HeroWarsHelper

Automation of actions for the game Hero Wars

当前为 2024-11-24 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name HeroWarsHelper
  3. // @name:en HeroWarsHelper
  4. // @name:ru HeroWarsHelper
  5. // @namespace HeroWarsHelper
  6. // @version 2.299
  7. // @description Automation of actions for the game Hero Wars
  8. // @description:en Automation of actions for the game Hero Wars
  9. // @description:ru Автоматизация действий для игры Хроники Хаоса
  10. // @author ZingerY
  11. // @license Copyright ZingerY
  12. // @homepage https://zingery.ru/scripts/HeroWarsHelper.user.js
  13. // @icon https://zingery.ru/scripts/VaultBoyIco16.ico
  14. // @icon64 https://zingery.ru/scripts/VaultBoyIco64.png
  15. // @match https://www.hero-wars.com/*
  16. // @match https://apps-1701433570146040.apps.fbsbx.com/*
  17. // @run-at document-start
  18. // ==/UserScript==
  19.  
  20. (function() {
  21. /**
  22. * Start script
  23. *
  24. * Стартуем скрипт
  25. */
  26. console.log('%cStart ' + GM_info.script.name + ', v' + GM_info.script.version + ' by ' + GM_info.script.author, 'color: red');
  27. /**
  28. * Script info
  29. *
  30. * Информация о скрипте
  31. */
  32. this.scriptInfo = (({name, version, author, homepage, lastModified}, updateUrl) =>
  33. ({name, version, author, homepage, lastModified, updateUrl}))
  34. (GM_info.script, GM_info.scriptUpdateURL);
  35. this.GM_info = GM_info;
  36. /**
  37. * Information for completing daily quests
  38. *
  39. * Информация для выполнения ежендевных квестов
  40. */
  41. const questsInfo = {};
  42. /**
  43. * Is the game data loaded
  44. *
  45. * Загружены ли данные игры
  46. */
  47. let isLoadGame = false;
  48. /**
  49. * Headers of the last request
  50. *
  51. * Заголовки последнего запроса
  52. */
  53. let lastHeaders = {};
  54. /**
  55. * Information about sent gifts
  56. *
  57. * Информация об отправленных подарках
  58. */
  59. let freebieCheckInfo = null;
  60. /**
  61. * missionTimer
  62. *
  63. * missionTimer
  64. */
  65. let missionBattle = null;
  66. /**
  67. * User data
  68. *
  69. * Данные пользователя
  70. */
  71. let userInfo;
  72. /**
  73. * Original methods for working with AJAX
  74. *
  75. * Оригинальные методы для работы с AJAX
  76. */
  77. const original = {
  78. open: XMLHttpRequest.prototype.open,
  79. send: XMLHttpRequest.prototype.send,
  80. setRequestHeader: XMLHttpRequest.prototype.setRequestHeader,
  81. SendWebSocket: WebSocket.prototype.send,
  82. fetch: fetch,
  83. };
  84.  
  85. // Sentry blocking
  86. // Блокировка наблюдателя
  87. this.fetch = function (url, options) {
  88. /**
  89. * Checking URL for blocking
  90. * Проверяем URL на блокировку
  91. */
  92. if (url.includes('sentry.io')) {
  93. console.log('%cFetch blocked', 'color: red');
  94. console.log(url, options);
  95. const body = {
  96. id: md5(Date.now()),
  97. };
  98. let info = {};
  99. try {
  100. info = JSON.parse(options.body);
  101. } catch (e) {}
  102. if (info.event_id) {
  103. body.id = info.event_id;
  104. }
  105. /**
  106. * Mock response for blocked URL
  107. *
  108. * Мокаем ответ для заблокированного URL
  109. */
  110. const mockResponse = new Response('Custom blocked response', {
  111. status: 200,
  112. headers: { 'Content-Type': 'application/json' },
  113. body,
  114. });
  115. return Promise.resolve(mockResponse);
  116. } else {
  117. /**
  118. * Call the original fetch function for all other URLs
  119. * Вызываем оригинальную функцию fetch для всех других URL
  120. */
  121. return original.fetch.apply(this, arguments);
  122. }
  123. };
  124.  
  125. /**
  126. * Decoder for converting byte data to JSON string
  127. *
  128. * Декодер для перобразования байтовых данных в JSON строку
  129. */
  130. const decoder = new TextDecoder("utf-8");
  131. /**
  132. * Stores a history of requests
  133. *
  134. * Хранит историю запросов
  135. */
  136. let requestHistory = {};
  137. /**
  138. * URL for API requests
  139. *
  140. * URL для запросов к API
  141. */
  142. let apiUrl = '';
  143.  
  144. /**
  145. * Connecting to the game code
  146. *
  147. * Подключение к коду игры
  148. */
  149. this.cheats = new hackGame();
  150. /**
  151. * The function of calculating the results of the battle
  152. *
  153. * Функция расчета результатов боя
  154. */
  155. this.BattleCalc = cheats.BattleCalc;
  156. /**
  157. * Sending a request available through the console
  158. *
  159. * Отправка запроса доступная через консоль
  160. */
  161. this.SendRequest = send;
  162. /**
  163. * Simple combat calculation available through the console
  164. *
  165. * Простой расчет боя доступный через консоль
  166. */
  167. this.Calc = function (data) {
  168. const type = getBattleType(data?.type);
  169. return new Promise((resolve, reject) => {
  170. try {
  171. BattleCalc(data, type, resolve);
  172. } catch (e) {
  173. reject(e);
  174. }
  175. })
  176. }
  177. /**
  178. * Short asynchronous request
  179. * Usage example (returns information about a character):
  180. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  181. *
  182. * Короткий асинхронный запрос
  183. * Пример использования (возвращает информацию о персонаже):
  184. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  185. */
  186. this.Send = function (json, pr) {
  187. return new Promise((resolve, reject) => {
  188. try {
  189. send(json, resolve, pr);
  190. } catch (e) {
  191. reject(e);
  192. }
  193. })
  194. }
  195.  
  196. this.xyz = (({ name, version, author }) => ({ name, version, author }))(GM_info.script);
  197. const i18nLangData = {
  198. /* English translation by BaBa */
  199. en: {
  200. /* Checkboxes */
  201. SKIP_FIGHTS: 'Skip battle',
  202. SKIP_FIGHTS_TITLE: 'Skip battle in Outland and the arena of the titans, auto-pass in the tower and campaign',
  203. ENDLESS_CARDS: 'Infinite cards',
  204. ENDLESS_CARDS_TITLE: 'Disable Divination Cards wasting',
  205. AUTO_EXPEDITION: 'Auto Expedition',
  206. AUTO_EXPEDITION_TITLE: 'Auto-sending expeditions',
  207. CANCEL_FIGHT: 'Cancel battle',
  208. CANCEL_FIGHT_TITLE: 'Ability to cancel manual combat on GW, CoW and Asgard',
  209. GIFTS: 'Gifts',
  210. GIFTS_TITLE: 'Collect gifts automatically',
  211. BATTLE_RECALCULATION: 'Battle recalculation',
  212. BATTLE_RECALCULATION_TITLE: 'Preliminary calculation of the battle',
  213. QUANTITY_CONTROL: 'Quantity control',
  214. QUANTITY_CONTROL_TITLE: 'Ability to specify the number of opened "lootboxes"',
  215. REPEAT_CAMPAIGN: 'Repeat missions',
  216. REPEAT_CAMPAIGN_TITLE: 'Auto-repeat battles in the campaign',
  217. DISABLE_DONAT: 'Disable donation',
  218. DISABLE_DONAT_TITLE: 'Removes all donation offers',
  219. DAILY_QUESTS: 'Quests',
  220. DAILY_QUESTS_TITLE: 'Complete daily quests',
  221. AUTO_QUIZ: 'AutoQuiz',
  222. AUTO_QUIZ_TITLE: 'Automatically receive correct answers to quiz questions',
  223. SECRET_WEALTH_CHECKBOX: 'Automatic purchase in the store "Secret Wealth" when entering the game',
  224. HIDE_SERVERS: 'Collapse servers',
  225. HIDE_SERVERS_TITLE: 'Hide unused servers',
  226. /* Input fields */
  227. HOW_MUCH_TITANITE: 'How much titanite to farm',
  228. COMBAT_SPEED: 'Combat Speed Multiplier',
  229. NUMBER_OF_TEST: 'Number of test fights',
  230. NUMBER_OF_AUTO_BATTLE: 'Number of auto-battle attempts',
  231. /* Buttons */
  232. RUN_SCRIPT: 'Run the',
  233. TO_DO_EVERYTHING: 'Do All',
  234. TO_DO_EVERYTHING_TITLE: 'Perform multiple actions of your choice',
  235. OUTLAND: 'Outland',
  236. OUTLAND_TITLE: 'Collect Outland',
  237. TITAN_ARENA: 'ToE',
  238. TITAN_ARENA_TITLE: 'Complete the titan arena',
  239. DUNGEON: 'Dungeon',
  240. DUNGEON_TITLE: 'Go through the dungeon',
  241. SEER: 'Seer',
  242. SEER_TITLE: 'Roll the Seer',
  243. TOWER: 'Tower',
  244. TOWER_TITLE: 'Pass the tower',
  245. EXPEDITIONS: 'Expeditions',
  246. EXPEDITIONS_TITLE: 'Sending and collecting expeditions',
  247. SYNC: 'Sync',
  248. SYNC_TITLE: 'Partial synchronization of game data without reloading the page',
  249. ARCHDEMON: 'Archdemon',
  250. FURNACE_OF_SOULS: 'Furnace of souls',
  251. ARCHDEMON_TITLE: 'Hitting kills and collecting rewards',
  252. ESTER_EGGS: 'Easter eggs',
  253. ESTER_EGGS_TITLE: 'Collect all Easter eggs or rewards',
  254. REWARDS: 'Rewards',
  255. REWARDS_TITLE: 'Collect all quest rewards',
  256. MAIL: 'Mail',
  257. MAIL_TITLE: 'Collect all mail, except letters with energy and charges of the portal',
  258. MINIONS: 'Minions',
  259. MINIONS_TITLE: 'Attack minions with saved packs',
  260. ADVENTURE: 'Adventure',
  261. ADVENTURE_TITLE: 'Passes the adventure along the specified route',
  262. STORM: 'Storm',
  263. STORM_TITLE: 'Passes the Storm along the specified route',
  264. SANCTUARY: 'Sanctuary',
  265. SANCTUARY_TITLE: 'Fast travel to Sanctuary',
  266. GUILD_WAR: 'Guild War',
  267. GUILD_WAR_TITLE: 'Fast travel to Guild War',
  268. SECRET_WEALTH: 'Secret Wealth',
  269. SECRET_WEALTH_TITLE: 'Buy something in the store "Secret Wealth"',
  270. /* Misc */
  271. BOTTOM_URLS:
  272. '<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>',
  273. GIFTS_SENT: 'Gifts sent!',
  274. DO_YOU_WANT: 'Do you really want to do this?',
  275. BTN_RUN: 'Run',
  276. BTN_CANCEL: 'Cancel',
  277. BTN_OK: 'OK',
  278. MSG_HAVE_BEEN_DEFEATED: 'You have been defeated!',
  279. BTN_AUTO: 'Auto',
  280. MSG_YOU_APPLIED: 'You applied',
  281. MSG_DAMAGE: 'damage',
  282. MSG_CANCEL_AND_STAT: 'Auto (F5) and show statistic',
  283. MSG_REPEAT_MISSION: 'Repeat the mission?',
  284. BTN_REPEAT: 'Repeat',
  285. BTN_NO: 'No',
  286. MSG_SPECIFY_QUANT: 'Specify Quantity:',
  287. BTN_OPEN: 'Open',
  288. QUESTION_COPY: 'Question copied to clipboard',
  289. ANSWER_KNOWN: 'The answer is known',
  290. ANSWER_NOT_KNOWN: 'ATTENTION THE ANSWER IS NOT KNOWN',
  291. BEING_RECALC: 'The battle is being recalculated',
  292. THIS_TIME: 'This time',
  293. VICTORY: '<span style="color:green;">VICTORY</span>',
  294. DEFEAT: '<span style="color:red;">DEFEAT</span>',
  295. CHANCE_TO_WIN: 'Chance to win <span style="color: red;">based on pre-calculation</span>',
  296. OPEN_DOLLS: 'nesting dolls recursively',
  297. SENT_QUESTION: 'Question sent',
  298. SETTINGS: 'Settings',
  299. MSG_BAN_ATTENTION: '<p style="color:red;">Using this feature may result in a ban.</p> Continue?',
  300. BTN_YES_I_AGREE: 'Yes, I understand the risks!',
  301. BTN_NO_I_AM_AGAINST: 'No, I refuse it!',
  302. VALUES: 'Values',
  303. EXPEDITIONS_SENT: 'Expeditions:<br>Collected: {countGet}<br>Sent: {countSend}',
  304. EXPEDITIONS_NOTHING: 'Nothing to collect/send',
  305. TITANIT: 'Titanit',
  306. COMPLETED: 'completed',
  307. FLOOR: 'Floor',
  308. LEVEL: 'Level',
  309. BATTLES: 'battles',
  310. EVENT: 'Event',
  311. NOT_AVAILABLE: 'not available',
  312. NO_HEROES: 'No heroes',
  313. DAMAGE_AMOUNT: 'Damage amount',
  314. NOTHING_TO_COLLECT: 'Nothing to collect',
  315. COLLECTED: 'Collected',
  316. REWARD: 'rewards',
  317. REMAINING_ATTEMPTS: 'Remaining attempts',
  318. BATTLES_CANCELED: 'Battles canceled',
  319. MINION_RAID: 'Minion Raid',
  320. STOPPED: 'Stopped',
  321. REPETITIONS: 'Repetitions',
  322. MISSIONS_PASSED: 'Missions passed',
  323. STOP: 'stop',
  324. TOTAL_OPEN: 'Total open',
  325. OPEN: 'Open',
  326. ROUND_STAT: 'Damage statistics for ',
  327. BATTLE: 'battles',
  328. MINIMUM: 'Minimum',
  329. MAXIMUM: 'Maximum',
  330. AVERAGE: 'Average',
  331. NOT_THIS_TIME: 'Not this time',
  332. RETRY_LIMIT_EXCEEDED: 'Retry limit exceeded',
  333. SUCCESS: 'Success',
  334. RECEIVED: 'Received',
  335. LETTERS: 'letters',
  336. PORTALS: 'portals',
  337. ATTEMPTS: 'attempts',
  338. /* Quests */
  339. QUEST_10001: 'Upgrade the skills of heroes 3 times',
  340. QUEST_10002: 'Complete 10 missions',
  341. QUEST_10003: 'Complete 3 heroic missions',
  342. QUEST_10004: 'Fight 3 times in the Arena or Grand Arena',
  343. QUEST_10006: 'Use the exchange of emeralds 1 time',
  344. QUEST_10007: 'Perform 1 summon in the Solu Atrium',
  345. QUEST_10016: 'Send gifts to guildmates',
  346. QUEST_10018: 'Use an experience potion',
  347. QUEST_10019: 'Open 1 chest in the Tower',
  348. QUEST_10020: 'Open 3 chests in Outland',
  349. QUEST_10021: 'Collect 75 Titanite in the Guild Dungeon',
  350. QUEST_10021: 'Collect 150 Titanite in the Guild Dungeon',
  351. QUEST_10023: 'Upgrade Gift of the Elements by 1 level',
  352. QUEST_10024: 'Level up any artifact once',
  353. QUEST_10025: 'Start Expedition 1',
  354. QUEST_10026: 'Start 4 Expeditions',
  355. QUEST_10027: 'Win 1 battle of the Tournament of Elements',
  356. QUEST_10028: 'Level up any titan artifact',
  357. QUEST_10029: 'Unlock the Orb of Titan Artifacts',
  358. QUEST_10030: 'Upgrade any Skin of any hero 1 time',
  359. QUEST_10031: 'Win 6 battles of the Tournament of Elements',
  360. QUEST_10043: 'Start or Join an Adventure',
  361. QUEST_10044: 'Use Summon Pets 1 time',
  362. QUEST_10046: 'Open 3 chests in Adventure',
  363. QUEST_10047: 'Get 150 Guild Activity Points',
  364. NOTHING_TO_DO: 'Nothing to do',
  365. YOU_CAN_COMPLETE: 'You can complete quests',
  366. BTN_DO_IT: 'Do it',
  367. NOT_QUEST_COMPLETED: 'Not a single quest completed',
  368. COMPLETED_QUESTS: 'Completed quests',
  369. /* everything button */
  370. ASSEMBLE_OUTLAND: 'Assemble Outland',
  371. PASS_THE_TOWER: 'Pass the tower',
  372. CHECK_EXPEDITIONS: 'Check Expeditions',
  373. COMPLETE_TOE: 'Complete ToE',
  374. COMPLETE_DUNGEON: 'Complete the dungeon',
  375. COLLECT_MAIL: 'Collect mail',
  376. COLLECT_MISC: 'Collect some bullshit',
  377. COLLECT_MISC_TITLE: 'Collect Easter Eggs, Skin Gems, Keys, Arena Coins and Soul Crystal',
  378. COLLECT_QUEST_REWARDS: 'Collect quest rewards',
  379. MAKE_A_SYNC: 'Make a sync',
  380.  
  381. RUN_FUNCTION: 'Run the following functions?',
  382. BTN_GO: 'Go!',
  383. PERFORMED: 'Performed',
  384. DONE: 'Done',
  385. ERRORS_OCCURRES: 'Errors occurred while executing',
  386. COPY_ERROR: 'Copy error information to clipboard',
  387. BTN_YES: 'Yes',
  388. ALL_TASK_COMPLETED: 'All tasks completed',
  389.  
  390. UNKNOWN: 'unknown',
  391. ENTER_THE_PATH: 'Enter the path of adventure using commas or dashes',
  392. START_ADVENTURE: 'Start your adventure along this path!',
  393. INCORRECT_WAY: 'Incorrect path in adventure: {from} -> {to}',
  394. BTN_CANCELED: 'Canceled',
  395. MUST_TWO_POINTS: 'The path must contain at least 2 points.',
  396. MUST_ONLY_NUMBERS: 'The path must contain only numbers and commas',
  397. NOT_ON_AN_ADVENTURE: 'You are not on an adventure',
  398. YOU_IN_NOT_ON_THE_WAY: 'Your location is not on the way',
  399. ATTEMPTS_NOT_ENOUGH: 'Your attempts are not enough to complete the path, continue?',
  400. YES_CONTINUE: 'Yes, continue!',
  401. NOT_ENOUGH_AP: 'Not enough action points',
  402. ATTEMPTS_ARE_OVER: 'The attempts are over',
  403. MOVES: 'Moves',
  404. BUFF_GET_ERROR: 'Buff getting error',
  405. BATTLE_END_ERROR: 'Battle end error',
  406. AUTOBOT: 'Autobot',
  407. FAILED_TO_WIN_AUTO: 'Failed to win the auto battle',
  408. ERROR_OF_THE_BATTLE_COPY: 'An error occurred during the passage of the battle<br>Copy the error to the clipboard?',
  409. ERROR_DURING_THE_BATTLE: 'Error during the battle',
  410. NO_CHANCE_WIN: 'No chance of winning this fight: 0/',
  411. LOST_HEROES: 'You have won, but you have lost one or several heroes',
  412. VICTORY_IMPOSSIBLE: 'Is victory impossible, should we focus on the result?',
  413. FIND_COEFF: 'Find the coefficient greater than',
  414. BTN_PASS: 'PASS',
  415. BRAWLS: 'Brawls',
  416. BRAWLS_TITLE: 'Activates the ability to auto-brawl',
  417. START_AUTO_BRAWLS: 'Start Auto Brawls?',
  418. LOSSES: 'Losses',
  419. WINS: 'Wins',
  420. FIGHTS: 'Fights',
  421. STAGE: 'Stage',
  422. DONT_HAVE_LIVES: "You don't have lives",
  423. LIVES: 'Lives',
  424. SECRET_WEALTH_ALREADY: 'Item for Pet Potions already purchased',
  425. SECRET_WEALTH_NOT_ENOUGH: 'Not Enough Pet Potion, You Have {available}, Need {need}',
  426. SECRET_WEALTH_UPGRADE_NEW_PET: 'After purchasing the Pet Potion, it will not be enough to upgrade a new pet',
  427. SECRET_WEALTH_PURCHASED: 'Purchased {count} {name}',
  428. SECRET_WEALTH_CANCELED: 'Secret Wealth: Purchase Canceled',
  429. SECRET_WEALTH_BUY: 'You have {available} Pet Potion.<br>Do you want to buy {countBuy} {name} for {price} Pet Potion?',
  430. DAILY_BONUS: 'Daily bonus',
  431. DO_DAILY_QUESTS: 'Do daily quests',
  432. ACTIONS: 'Actions',
  433. ACTIONS_TITLE: 'Dialog box with various actions',
  434. OTHERS: 'Others',
  435. OTHERS_TITLE: 'Others',
  436. CHOOSE_ACTION: 'Choose an action',
  437. OPEN_LOOTBOX: 'You have {lootBox} boxes, should we open them?',
  438. STAMINA: 'Energy',
  439. BOXES_OVER: 'The boxes are over',
  440. NO_BOXES: 'No boxes',
  441. NO_MORE_ACTIVITY: 'No more activity for items today',
  442. EXCHANGE_ITEMS: 'Exchange items for activity points (max {maxActive})?',
  443. GET_ACTIVITY: 'Get Activity',
  444. NOT_ENOUGH_ITEMS: 'Not enough items',
  445. ACTIVITY_RECEIVED: 'Activity received',
  446. NO_PURCHASABLE_HERO_SOULS: 'No purchasable Hero Souls',
  447. PURCHASED_HERO_SOULS: 'Purchased {countHeroSouls} Hero Souls',
  448. NOT_ENOUGH_EMERALDS_540: 'Not enough emeralds, you need {imgEmerald}540 you have {imgEmerald}{currentStarMoney}',
  449. BUY_OUTLAND_BTN: 'Buy {count} chests {imgEmerald}{countEmerald}',
  450. CHESTS_NOT_AVAILABLE: 'Chests not available',
  451. OUTLAND_CHESTS_RECEIVED: 'Outland chests received',
  452. RAID_NOT_AVAILABLE: 'The raid is not available or there are no spheres',
  453. RAID_ADVENTURE: 'Raid {adventureId} adventure!',
  454. SOMETHING_WENT_WRONG: 'Something went wrong',
  455. ADVENTURE_COMPLETED: 'Adventure {adventureId} completed {times} times',
  456. CLAN_STAT_COPY: 'Clan statistics copied to clipboard',
  457. GET_ENERGY: 'Get Energy',
  458. GET_ENERGY_TITLE: 'Opens platinum boxes one at a time until you get 250 energy',
  459. ITEM_EXCHANGE: 'Item Exchange',
  460. ITEM_EXCHANGE_TITLE: 'Exchanges items for the specified amount of activity',
  461. BUY_SOULS: 'Buy souls',
  462. BUY_SOULS_TITLE: 'Buy hero souls from all available shops',
  463. BUY_OUTLAND: 'Buy Outland',
  464. BUY_OUTLAND_TITLE: 'Buy 9 chests in Outland for 540 emeralds',
  465. RAID: 'Raid',
  466. AUTO_RAID_ADVENTURE: 'Raid adventure',
  467. AUTO_RAID_ADVENTURE_TITLE: 'Raid adventure set number of times',
  468. CLAN_STAT: 'Clan statistics',
  469. CLAN_STAT_TITLE: 'Copies clan statistics to the clipboard',
  470. BTN_AUTO_F5: 'Auto (F5)',
  471. BOSS_DAMAGE: 'Boss Damage: ',
  472. NOTHING_BUY: 'Nothing to buy',
  473. LOTS_BOUGHT: '{countBuy} lots bought for gold',
  474. BUY_FOR_GOLD: 'Buy for gold',
  475. BUY_FOR_GOLD_TITLE: 'Buy items for gold in the Town Shop and in the Pet Soul Stone Shop',
  476. REWARDS_AND_MAIL: 'Rewards and Mail',
  477. REWARDS_AND_MAIL_TITLE: 'Collects rewards and mail',
  478. COLLECT_REWARDS_AND_MAIL: 'Collected {countQuests} rewards and {countMail} letters',
  479. TIMER_ALREADY: 'Timer already started {time}',
  480. NO_ATTEMPTS_TIMER_START: 'No attempts, timer started {time}',
  481. EPIC_BRAWL_RESULT: 'Wins: {wins}/{attempts}, Coins: {coins}, Streak: {progress}/{nextStage} [Close]{end}',
  482. ATTEMPT_ENDED: '<br>Attempts ended, timer started {time}',
  483. EPIC_BRAWL: 'Cosmic Battle',
  484. EPIC_BRAWL_TITLE: 'Spends attempts in the Cosmic Battle',
  485. RELOAD_GAME: 'Reload game',
  486. TIMER: 'Timer:',
  487. SHOW_ERRORS: 'Show errors',
  488. SHOW_ERRORS_TITLE: 'Show server request errors',
  489. ERROR_MSG: 'Error: {name}<br>{description}',
  490. EVENT_AUTO_BOSS:
  491. '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?',
  492. BEST_SLOW: 'Best (slower)',
  493. FIRST_FAST: 'First (faster)',
  494. FREEZE_INTERFACE: 'Calculating... <br>The interface may freeze.',
  495. ERROR_F12: 'Error, details in the console (F12)',
  496. FAILED_FIND_WIN_PACK: 'Failed to find a winning pack',
  497. BEST_PACK: 'Best pack:',
  498. BOSS_HAS_BEEN_DEF: 'Boss {bossLvl} has been defeated.',
  499. NOT_ENOUGH_ATTEMPTS_BOSS: 'Not enough attempts to defeat boss {bossLvl}, retry?',
  500. BOSS_VICTORY_IMPOSSIBLE:
  501. '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?',
  502. BOSS_HAS_BEEN_DEF_TEXT:
  503. 'Boss {bossLvl} defeated in<br>{countBattle}/{countMaxBattle} attempts<br>(Please synchronize or restart the game to update the data)',
  504. MAP: 'Map: ',
  505. PLAYER_POS: 'Player positions:',
  506. NY_GIFTS: 'Gifts',
  507. NY_GIFTS_TITLE: "Open all New Year's gifts",
  508. NY_NO_GIFTS: 'No gifts not received',
  509. NY_GIFTS_COLLECTED: '{count} gifts collected',
  510. CHANGE_MAP: 'Island map',
  511. CHANGE_MAP_TITLE: 'Change island map',
  512. SELECT_ISLAND_MAP: 'Select an island map:',
  513. MAP_NUM: 'Map {num}',
  514. SECRET_WEALTH_SHOP: 'Secret Wealth {name}: ',
  515. SHOPS: 'Shops',
  516. SHOPS_DEFAULT: 'Default',
  517. SHOPS_DEFAULT_TITLE: 'Default stores',
  518. SHOPS_LIST: 'Shops {number}',
  519. SHOPS_LIST_TITLE: 'List of shops {number}',
  520. SHOPS_WARNING:
  521. '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>',
  522. MINIONS_WARNING: 'The hero packs for attacking minions are incomplete, should I continue?',
  523. FAST_SEASON: 'Fast season',
  524. FAST_SEASON_TITLE: 'Skip the map selection screen in a season',
  525. SET_NUMBER_LEVELS: 'Specify the number of levels:',
  526. POSSIBLE_IMPROVE_LEVELS: 'It is possible to improve only {count} levels.<br>Improving?',
  527. NOT_ENOUGH_RESOURECES: 'Not enough resources',
  528. IMPROVED_LEVELS: 'Improved levels: {count}',
  529. ARTIFACTS_UPGRADE: 'Artifacts Upgrade',
  530. ARTIFACTS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero artifacts',
  531. SKINS_UPGRADE: 'Skins Upgrade',
  532. SKINS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero skins',
  533. HINT: '<br>Hint: ',
  534. PICTURE: '<br>Picture: ',
  535. ANSWER: '<br>Answer: ',
  536. NO_HEROES_PACK: 'Fight at least one battle to save the attacking team',
  537. BRAWL_AUTO_PACK: 'Automatic selection of packs',
  538. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Automatic pack selection is not suitable for the current hero',
  539. BRAWL_DAILY_TASK_COMPLETED: 'Daily task completed, continue attacking?',
  540. CALC_STAT: 'Calculate statistics',
  541. ELEMENT_TOURNAMENT_REWARD: 'Unclaimed bonus for Elemental Tournament',
  542. BTN_TRY_FIX_IT: 'Fix it',
  543. BTN_TRY_FIX_IT_TITLE: 'Enable auto attack combat correction',
  544. DAMAGE_FIXED: 'Damage fixed from {lastDamage} to {maxDamage}!',
  545. DAMAGE_NO_FIXED: 'Failed to fix damage: {lastDamage}',
  546. LETS_FIX: "Let's fix",
  547. COUNT_FIXED: 'For {count} attempts',
  548. DEFEAT_TURN_TIMER: 'Defeat! Turn on the timer to complete the mission?',
  549. SEASON_REWARD: 'Season Rewards',
  550. SEASON_REWARD_TITLE: 'Collects available free rewards from all current seasons',
  551. SEASON_REWARD_COLLECTED: 'Collected {count} season rewards',
  552. SELL_HERO_SOULS: 'Sell ​​souls',
  553. SELL_HERO_SOULS_TITLE: 'Exchanges all absolute star hero souls for gold',
  554. GOLD_RECEIVED: 'Gold received: {gold}',
  555. OPEN_ALL_EQUIP_BOXES: 'Open all Equipment Fragment Box?',
  556. SERVER_NOT_ACCEPT: 'The server did not accept the result',
  557. },
  558. ru: {
  559. /* Чекбоксы */
  560. SKIP_FIGHTS: 'Пропуск боев',
  561. SKIP_FIGHTS_TITLE: 'Пропуск боев в запределье и арене титанов, автопропуск в башне и кампании',
  562. ENDLESS_CARDS: 'Бесконечные карты',
  563. ENDLESS_CARDS_TITLE: 'Отключить трату карт предсказаний',
  564. AUTO_EXPEDITION: 'АвтоЭкспедиции',
  565. AUTO_EXPEDITION_TITLE: 'Автоотправка экспедиций',
  566. CANCEL_FIGHT: 'Отмена боя',
  567. CANCEL_FIGHT_TITLE: 'Возможность отмены ручного боя на ВГ, СМ и в Асгарде',
  568. GIFTS: 'Подарки',
  569. GIFTS_TITLE: 'Собирать подарки автоматически',
  570. BATTLE_RECALCULATION: 'Прерасчет боя',
  571. BATTLE_RECALCULATION_TITLE: 'Предварительный расчет боя',
  572. QUANTITY_CONTROL: 'Контроль кол-ва',
  573. QUANTITY_CONTROL_TITLE: 'Возможность указывать количество открываемых "лутбоксов"',
  574. REPEAT_CAMPAIGN: 'Повтор в кампании',
  575. REPEAT_CAMPAIGN_TITLE: 'Автоповтор боев в кампании',
  576. DISABLE_DONAT: 'Отключить донат',
  577. DISABLE_DONAT_TITLE: 'Убирает все предложения доната',
  578. DAILY_QUESTS: 'Квесты',
  579. DAILY_QUESTS_TITLE: 'Выполнять ежедневные квесты',
  580. AUTO_QUIZ: 'АвтоВикторина',
  581. AUTO_QUIZ_TITLE: 'Автоматическое получение правильных ответов на вопросы викторины',
  582. SECRET_WEALTH_CHECKBOX: 'Автоматическая покупка в магазине "Тайное Богатство" при заходе в игру',
  583. HIDE_SERVERS: 'Свернуть сервера',
  584. HIDE_SERVERS_TITLE: 'Скрывать неиспользуемые сервера',
  585. /* Поля ввода */
  586. HOW_MUCH_TITANITE: 'Сколько фармим титанита',
  587. COMBAT_SPEED: 'Множитель ускорения боя',
  588. NUMBER_OF_TEST: 'Количество тестовых боев',
  589. NUMBER_OF_AUTO_BATTLE: 'Количество попыток автобоев',
  590. /* Кнопки */
  591. RUN_SCRIPT: 'Запустить скрипт',
  592. TO_DO_EVERYTHING: 'Сделать все',
  593. TO_DO_EVERYTHING_TITLE: 'Выполнить несколько действий',
  594. OUTLAND: 'Запределье',
  595. OUTLAND_TITLE: 'Собрать Запределье',
  596. TITAN_ARENA: 'Турнир Стихий',
  597. TITAN_ARENA_TITLE: 'Автопрохождение Турнира Стихий',
  598. DUNGEON: 'Подземелье',
  599. DUNGEON_TITLE: 'Автопрохождение подземелья',
  600. SEER: 'Провидец',
  601. SEER_TITLE: 'Покрутить Провидца',
  602. TOWER: 'Башня',
  603. TOWER_TITLE: 'Автопрохождение башни',
  604. EXPEDITIONS: 'Экспедиции',
  605. EXPEDITIONS_TITLE: 'Отправка и сбор экспедиций',
  606. SYNC: 'Синхронизация',
  607. SYNC_TITLE: 'Частичная синхронизация данных игры без перезагрузки сатраницы',
  608. ARCHDEMON: 'Архидемон',
  609. FURNACE_OF_SOULS: 'Горнило душ',
  610. ARCHDEMON_TITLE: 'Набивает килы и собирает награду',
  611. ESTER_EGGS: 'Пасхалки',
  612. ESTER_EGGS_TITLE: 'Собрать все пасхалки или награды',
  613. REWARDS: 'Награды',
  614. REWARDS_TITLE: 'Собрать все награды за задания',
  615. MAIL: 'Почта',
  616. MAIL_TITLE: 'Собрать всю почту, кроме писем с энергией и зарядами портала',
  617. MINIONS: 'Прислужники',
  618. MINIONS_TITLE: 'Атакует прислужников сохраннеными пачками',
  619. ADVENTURE: 'Приключение',
  620. ADVENTURE_TITLE: 'Проходит приключение по указанному маршруту',
  621. STORM: 'Буря',
  622. STORM_TITLE: 'Проходит бурю по указанному маршруту',
  623. SANCTUARY: 'Святилище',
  624. SANCTUARY_TITLE: 'Быстрый переход к Святилищу',
  625. GUILD_WAR: 'Война гильдий',
  626. GUILD_WAR_TITLE: 'Быстрый переход к Войне гильдий',
  627. SECRET_WEALTH: 'Тайное богатство',
  628. SECRET_WEALTH_TITLE: 'Купить что-то в магазине "Тайное богатство"',
  629. /* Разное */
  630. BOTTOM_URLS:
  631. '<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>',
  632. GIFTS_SENT: 'Подарки отправлены!',
  633. DO_YOU_WANT: 'Вы действительно хотите это сделать?',
  634. BTN_RUN: 'Запускай',
  635. BTN_CANCEL: 'Отмена',
  636. BTN_OK: 'Ок',
  637. MSG_HAVE_BEEN_DEFEATED: 'Вы потерпели поражение!',
  638. BTN_AUTO: 'Авто',
  639. MSG_YOU_APPLIED: 'Вы нанесли',
  640. MSG_DAMAGE: 'урона',
  641. MSG_CANCEL_AND_STAT: 'Авто (F5) и показать Статистику',
  642. MSG_REPEAT_MISSION: 'Повторить миссию?',
  643. BTN_REPEAT: 'Повторить',
  644. BTN_NO: 'Нет',
  645. MSG_SPECIFY_QUANT: 'Указать количество:',
  646. BTN_OPEN: 'Открыть',
  647. QUESTION_COPY: 'Вопрос скопирован в буфер обмена',
  648. ANSWER_KNOWN: 'Ответ известен',
  649. ANSWER_NOT_KNOWN: 'ВНИМАНИЕ ОТВЕТ НЕ ИЗВЕСТЕН',
  650. BEING_RECALC: 'Идет прерасчет боя',
  651. THIS_TIME: 'На этот раз',
  652. VICTORY: '<span style="color:green;">ПОБЕДА</span>',
  653. DEFEAT: '<span style="color:red;">ПОРАЖЕНИЕ</span>',
  654. CHANCE_TO_WIN: 'Шансы на победу <span style="color:red;">на основе прерасчета</span>',
  655. OPEN_DOLLS: 'матрешек рекурсивно',
  656. SENT_QUESTION: 'Вопрос отправлен',
  657. SETTINGS: 'Настройки',
  658. MSG_BAN_ATTENTION: '<p style="color:red;">Использование этой функции может привести к бану.</p> Продолжить?',
  659. BTN_YES_I_AGREE: 'Да, я беру на себя все риски!',
  660. BTN_NO_I_AM_AGAINST: 'Нет, я отказываюсь от этого!',
  661. VALUES: 'Значения',
  662. EXPEDITIONS_SENT: 'Экспедиции:<br>Собрано: {countGet}<br>Отправлено: {countSend}',
  663. EXPEDITIONS_NOTHING: 'Нечего собирать/отправлять',
  664. TITANIT: 'Титанит',
  665. COMPLETED: 'завершено',
  666. FLOOR: 'Этаж',
  667. LEVEL: 'Уровень',
  668. BATTLES: 'бои',
  669. EVENT: 'Эвент',
  670. NOT_AVAILABLE: 'недоступен',
  671. NO_HEROES: 'Нет героев',
  672. DAMAGE_AMOUNT: 'Количество урона',
  673. NOTHING_TO_COLLECT: 'Нечего собирать',
  674. COLLECTED: 'Собрано',
  675. REWARD: 'наград',
  676. REMAINING_ATTEMPTS: 'Осталось попыток',
  677. BATTLES_CANCELED: 'Битв отменено',
  678. MINION_RAID: 'Рейд прислужников',
  679. STOPPED: 'Остановлено',
  680. REPETITIONS: 'Повторений',
  681. MISSIONS_PASSED: 'Миссий пройдено',
  682. STOP: 'остановить',
  683. TOTAL_OPEN: 'Всего открыто',
  684. OPEN: 'Открыто',
  685. ROUND_STAT: 'Статистика урона за',
  686. BATTLE: 'боев',
  687. MINIMUM: 'Минимальный',
  688. MAXIMUM: 'Максимальный',
  689. AVERAGE: 'Средний',
  690. NOT_THIS_TIME: 'Не в этот раз',
  691. RETRY_LIMIT_EXCEEDED: 'Превышен лимит попыток',
  692. SUCCESS: 'Успех',
  693. RECEIVED: 'Получено',
  694. LETTERS: 'писем',
  695. PORTALS: 'порталов',
  696. ATTEMPTS: 'попыток',
  697. QUEST_10001: 'Улучши умения героев 3 раза',
  698. QUEST_10002: 'Пройди 10 миссий',
  699. QUEST_10003: 'Пройди 3 героические миссии',
  700. QUEST_10004: 'Сразись 3 раза на Арене или Гранд Арене',
  701. QUEST_10006: 'Используй обмен изумрудов 1 раз',
  702. QUEST_10007: 'Соверши 1 призыв в Атриуме Душ',
  703. QUEST_10016: 'Отправь подарки согильдийцам',
  704. QUEST_10018: 'Используй зелье опыта',
  705. QUEST_10019: 'Открой 1 сундук в Башне',
  706. QUEST_10020: 'Открой 3 сундука в Запределье',
  707. QUEST_10021: 'Собери 75 Титанита в Подземелье Гильдии',
  708. QUEST_10021: 'Собери 150 Титанита в Подземелье Гильдии',
  709. QUEST_10023: 'Прокачай Дар Стихий на 1 уровень',
  710. QUEST_10024: 'Повысь уровень любого артефакта один раз',
  711. QUEST_10025: 'Начни 1 Экспедицию',
  712. QUEST_10026: 'Начни 4 Экспедиции',
  713. QUEST_10027: 'Победи в 1 бою Турнира Стихий',
  714. QUEST_10028: 'Повысь уровень любого артефакта титанов',
  715. QUEST_10029: 'Открой сферу артефактов титанов',
  716. QUEST_10030: 'Улучши облик любого героя 1 раз',
  717. QUEST_10031: 'Победи в 6 боях Турнира Стихий',
  718. QUEST_10043: 'Начни или присоеденись к Приключению',
  719. QUEST_10044: 'Воспользуйся призывом питомцев 1 раз',
  720. QUEST_10046: 'Открой 3 сундука в Приключениях',
  721. QUEST_10047: 'Набери 150 очков активности в Гильдии',
  722. NOTHING_TO_DO: 'Нечего выполнять',
  723. YOU_CAN_COMPLETE: 'Можно выполнить квесты',
  724. BTN_DO_IT: 'Выполняй',
  725. NOT_QUEST_COMPLETED: 'Ни одного квеста не выполенно',
  726. COMPLETED_QUESTS: 'Выполнено квестов',
  727. /* everything button */
  728. ASSEMBLE_OUTLAND: 'Собрать Запределье',
  729. PASS_THE_TOWER: 'Пройти башню',
  730. CHECK_EXPEDITIONS: 'Проверить экспедиции',
  731. COMPLETE_TOE: 'Пройти Турнир Стихий',
  732. COMPLETE_DUNGEON: 'Пройти подземелье',
  733. COLLECT_MAIL: 'Собрать почту',
  734. COLLECT_MISC: 'Собрать всякую херню',
  735. COLLECT_MISC_TITLE: 'Собрать пасхалки, камни облика, ключи, монеты арены и Хрусталь души',
  736. COLLECT_QUEST_REWARDS: 'Собрать награды за квесты',
  737. MAKE_A_SYNC: 'Сделать синхронизацию',
  738.  
  739. RUN_FUNCTION: 'Выполнить следующие функции?',
  740. BTN_GO: 'Погнали!',
  741. PERFORMED: 'Выполняется',
  742. DONE: 'Выполнено',
  743. ERRORS_OCCURRES: 'Призошли ошибки при выполнении',
  744. COPY_ERROR: 'Скопировать в буфер информацию об ошибке',
  745. BTN_YES: 'Да',
  746. ALL_TASK_COMPLETED: 'Все задачи выполнены',
  747.  
  748. UNKNOWN: 'Неизвестно',
  749. ENTER_THE_PATH: 'Введите путь приключения через запятые или дефисы',
  750. START_ADVENTURE: 'Начать приключение по этому пути!',
  751. INCORRECT_WAY: 'Неверный путь в приключении: {from} -> {to}',
  752. BTN_CANCELED: 'Отменено',
  753. MUST_TWO_POINTS: 'Путь должен состоять минимум из 2х точек',
  754. MUST_ONLY_NUMBERS: 'Путь должен содержать только цифры и запятые',
  755. NOT_ON_AN_ADVENTURE: 'Вы не в приключении',
  756. YOU_IN_NOT_ON_THE_WAY: 'Указанный путь должен включать точку вашего положения',
  757. ATTEMPTS_NOT_ENOUGH: 'Ваших попыток не достаточно для завершения пути, продолжить?',
  758. YES_CONTINUE: 'Да, продолжай!',
  759. NOT_ENOUGH_AP: 'Попыток не достаточно',
  760. ATTEMPTS_ARE_OVER: 'Попытки закончились',
  761. MOVES: 'Ходы',
  762. BUFF_GET_ERROR: 'Ошибка при получении бафа',
  763. BATTLE_END_ERROR: 'Ошибка завершения боя',
  764. AUTOBOT: 'АвтоБой',
  765. FAILED_TO_WIN_AUTO: 'Не удалось победить в автобою',
  766. ERROR_OF_THE_BATTLE_COPY: 'Призошли ошибка в процессе прохождения боя<br>Скопировать ошибку в буфер обмена?',
  767. ERROR_DURING_THE_BATTLE: 'Ошибка в процессе прохождения боя',
  768. NO_CHANCE_WIN: 'Нет шансов победить в этом бою: 0/',
  769. LOST_HEROES: 'Вы победили, но потеряли одного или несколько героев!',
  770. VICTORY_IMPOSSIBLE: 'Победа не возможна, бъем на результат?',
  771. FIND_COEFF: 'Поиск коэффициента больше чем',
  772. BTN_PASS: 'ПРОПУСК',
  773. BRAWLS: 'Потасовки',
  774. BRAWLS_TITLE: 'Включает возможность автопотасовок',
  775. START_AUTO_BRAWLS: 'Запустить Автопотасовки?',
  776. LOSSES: 'Поражений',
  777. WINS: 'Побед',
  778. FIGHTS: 'Боев',
  779. STAGE: 'Стадия',
  780. DONT_HAVE_LIVES: 'У Вас нет жизней',
  781. LIVES: 'Жизни',
  782. SECRET_WEALTH_ALREADY: 'товар за Зелья питомцев уже куплен',
  783. SECRET_WEALTH_NOT_ENOUGH: 'Не достаточно Зелье Питомца, у Вас {available}, нужно {need}',
  784. SECRET_WEALTH_UPGRADE_NEW_PET: 'После покупки Зелье Питомца будет не достаточно для прокачки нового питомца',
  785. SECRET_WEALTH_PURCHASED: 'Куплено {count} {name}',
  786. SECRET_WEALTH_CANCELED: 'Тайное богатство: покупка отменена',
  787. SECRET_WEALTH_BUY: 'У вас {available} Зелье Питомца.<br>Вы хотите купить {countBuy} {name} за {price} Зелье Питомца?',
  788. DAILY_BONUS: 'Ежедневная награда',
  789. DO_DAILY_QUESTS: 'Сделать ежедневные квесты',
  790. ACTIONS: 'Действия',
  791. ACTIONS_TITLE: 'Диалоговое окно с различными действиями',
  792. OTHERS: 'Разное',
  793. OTHERS_TITLE: 'Диалоговое окно с дополнительными различными действиями',
  794. CHOOSE_ACTION: 'Выберите действие',
  795. OPEN_LOOTBOX: 'У Вас {lootBox} ящиков, откываем?',
  796. STAMINA: 'Энергия',
  797. BOXES_OVER: 'Ящики закончились',
  798. NO_BOXES: 'Нет ящиков',
  799. NO_MORE_ACTIVITY: 'Больше активности за предметы сегодня не получить',
  800. EXCHANGE_ITEMS: 'Обменять предметы на очки активности (не более {maxActive})?',
  801. GET_ACTIVITY: 'Получить активность',
  802. NOT_ENOUGH_ITEMS: 'Предметов недостаточно',
  803. ACTIVITY_RECEIVED: 'Получено активности',
  804. NO_PURCHASABLE_HERO_SOULS: 'Нет доступных для покупки душ героев',
  805. PURCHASED_HERO_SOULS: 'Куплено {countHeroSouls} душ героев',
  806. NOT_ENOUGH_EMERALDS_540: 'Недостаточно изюма, нужно {imgEmerald}540 у Вас {imgEmerald}{currentStarMoney}',
  807. BUY_OUTLAND_BTN: 'Купить {count} сундуков {imgEmerald}{countEmerald}',
  808. CHESTS_NOT_AVAILABLE: 'Сундуки не доступны',
  809. OUTLAND_CHESTS_RECEIVED: 'Получено сундуков Запределья',
  810. RAID_NOT_AVAILABLE: 'Рейд не доступен или сфер нет',
  811. RAID_ADVENTURE: 'Рейд {adventureId} приключения!',
  812. SOMETHING_WENT_WRONG: 'Что-то пошло не так',
  813. ADVENTURE_COMPLETED: 'Приключение {adventureId} пройдено {times} раз',
  814. CLAN_STAT_COPY: 'Клановая статистика скопирована в буфер обмена',
  815. GET_ENERGY: 'Получить энергию',
  816. GET_ENERGY_TITLE: 'Открывает платиновые шкатулки по одной до получения 250 энергии',
  817. ITEM_EXCHANGE: 'Обмен предметов',
  818. ITEM_EXCHANGE_TITLE: 'Обменивает предметы на указанное количество активности',
  819. BUY_SOULS: 'Купить души',
  820. BUY_SOULS_TITLE: 'Купить души героев из всех доступных магазинов',
  821. BUY_OUTLAND: 'Купить Запределье',
  822. BUY_OUTLAND_TITLE: 'Купить 9 сундуков в Запределье за 540 изумрудов',
  823. RAID: 'Рейд',
  824. AUTO_RAID_ADVENTURE: 'Рейд приключения',
  825. AUTO_RAID_ADVENTURE_TITLE: 'Рейд приключения заданное количество раз',
  826. CLAN_STAT: 'Клановая статистика',
  827. CLAN_STAT_TITLE: 'Копирует клановую статистику в буфер обмена',
  828. BTN_AUTO_F5: 'Авто (F5)',
  829. BOSS_DAMAGE: 'Урон по боссу: ',
  830. NOTHING_BUY: 'Нечего покупать',
  831. LOTS_BOUGHT: 'За золото куплено {countBuy} лотов',
  832. BUY_FOR_GOLD: 'Скупить за золото',
  833. BUY_FOR_GOLD_TITLE: 'Скупить предметы за золото в Городской лавке и в магазине Камней Душ Питомцев',
  834. REWARDS_AND_MAIL: 'Награды и почта',
  835. REWARDS_AND_MAIL_TITLE: 'Собирает награды и почту',
  836. COLLECT_REWARDS_AND_MAIL: 'Собрано {countQuests} наград и {countMail} писем',
  837. TIMER_ALREADY: 'Таймер уже запущен {time}',
  838. NO_ATTEMPTS_TIMER_START: 'Попыток нет, запущен таймер {time}',
  839. EPIC_BRAWL_RESULT: '{i} Победы: {wins}/{attempts}, Монеты: {coins}, Серия: {progress}/{nextStage} [Закрыть]{end}',
  840. ATTEMPT_ENDED: '<br>Попытки закончились, запущен таймер {time}',
  841. EPIC_BRAWL: 'Вселенская битва',
  842. EPIC_BRAWL_TITLE: 'Тратит попытки во Вселенской битве',
  843. RELOAD_GAME: 'Перезагрузить игру',
  844. TIMER: 'Таймер:',
  845. SHOW_ERRORS: 'Отображать ошибки',
  846. SHOW_ERRORS_TITLE: 'Отображать ошибки запросов к серверу',
  847. ERROR_MSG: 'Ошибка: {name}<br>{description}',
  848. EVENT_AUTO_BOSS:
  849. 'Максимальное количество боев для расчета:</br>{length} * {countTestBattle} = {maxCalcBattle}</br>Если у Вас слабый компьютер на это может потребоваться много времени, нажмите крестик для отмены.</br>Искать лучший пак из всех или первый подходящий?',
  850. BEST_SLOW: 'Лучший (медленее)',
  851. FIRST_FAST: 'Первый (быстрее)',
  852. FREEZE_INTERFACE: 'Идет расчет... <br> Интерфейс может зависнуть.',
  853. ERROR_F12: 'Ошибка, подробности в консоли (F12)',
  854. FAILED_FIND_WIN_PACK: 'Победный пак найти не удалось',
  855. BEST_PACK: 'Наилучший пак: ',
  856. BOSS_HAS_BEEN_DEF: 'Босс {bossLvl} побежден',
  857. NOT_ENOUGH_ATTEMPTS_BOSS: 'Для победы босса ${bossLvl} не хватило попыток, повторить?',
  858. BOSS_VICTORY_IMPOSSIBLE:
  859. 'По результатам прерасчета {battles} боев победу получить не удалось. Вы хотите продолжить поиск победного боя на реальных боях?',
  860. BOSS_HAS_BEEN_DEF_TEXT:
  861. 'Босс {bossLvl} побежден за<br>{countBattle}/{countMaxBattle} попыток<br>(Сделайте синхронизацию или перезагрузите игру для обновления данных)',
  862. MAP: 'Карта: ',
  863. PLAYER_POS: 'Позиции игроков:',
  864. NY_GIFTS: 'Подарки',
  865. NY_GIFTS_TITLE: 'Открыть все новогодние подарки',
  866. NY_NO_GIFTS: 'Нет не полученных подарков',
  867. NY_GIFTS_COLLECTED: 'Собрано {count} подарков',
  868. CHANGE_MAP: 'Карта острова',
  869. CHANGE_MAP_TITLE: 'Сменить карту острова',
  870. SELECT_ISLAND_MAP: 'Выберите карту острова:',
  871. MAP_NUM: 'Карта {num}',
  872. SECRET_WEALTH_SHOP: 'Тайное богатство {name}: ',
  873. SHOPS: 'Магазины',
  874. SHOPS_DEFAULT: 'Стандартные',
  875. SHOPS_DEFAULT_TITLE: 'Стандартные магазины',
  876. SHOPS_LIST: 'Магазины {number}',
  877. SHOPS_LIST_TITLE: 'Список магазинов {number}',
  878. SHOPS_WARNING:
  879. 'Магазины<br><span style="color:red">Если Вы купите монеты магазинов потасовок за изумруды, то их надо использовать сразу, иначе после перезагрузки игры они пропадут!</span>',
  880. MINIONS_WARNING: 'Пачки героев для атаки приспешников неполные, продолжить?',
  881. FAST_SEASON: 'Быстрый сезон',
  882. FAST_SEASON_TITLE: 'Пропуск экрана с выбором карты в сезоне',
  883. SET_NUMBER_LEVELS: 'Указать колличество уровней:',
  884. POSSIBLE_IMPROVE_LEVELS: 'Возможно улучшить только {count} уровней.<br>Улучшаем?',
  885. NOT_ENOUGH_RESOURECES: 'Не хватает ресурсов',
  886. IMPROVED_LEVELS: 'Улучшено уровней: {count}',
  887. ARTIFACTS_UPGRADE: 'Улучшение артефактов',
  888. ARTIFACTS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых артефактов героев',
  889. SKINS_UPGRADE: 'Улучшение обликов',
  890. SKINS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых обликов героев',
  891. HINT: '<br>Подсказка: ',
  892. PICTURE: '<br>На картинке: ',
  893. ANSWER: '<br>Ответ: ',
  894. NO_HEROES_PACK: 'Проведите хотя бы один бой для сохранения атакующей команды',
  895. BRAWL_AUTO_PACK: 'Автоподбор пачки',
  896. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Автоматический подбор пачки не подходит для текущего героя',
  897. BRAWL_DAILY_TASK_COMPLETED: 'Ежедневное задание выполнено, продолжить атаку?',
  898. CALC_STAT: 'Посчитать статистику',
  899. ELEMENT_TOURNAMENT_REWARD: 'Несобранная награда за Турнир Стихий',
  900. BTN_TRY_FIX_IT: 'Исправить',
  901. BTN_TRY_FIX_IT_TITLE: 'Включить исправление боев при автоатаке',
  902. DAMAGE_FIXED: 'Урон исправлен с {lastDamage} до {maxDamage}!',
  903. DAMAGE_NO_FIXED: 'Не удалось исправить урон: {lastDamage}',
  904. LETS_FIX: 'Исправляем',
  905. COUNT_FIXED: 'За {count} попыток',
  906. DEFEAT_TURN_TIMER: 'Поражение! Включить таймер для завершения миссии?',
  907. SEASON_REWARD: 'Награды сезонов',
  908. SEASON_REWARD_TITLE: 'Собирает доступные бесплатные награды со всех текущих сезонов',
  909. SEASON_REWARD_COLLECTED: 'Собрано {count} наград сезонов',
  910. SELL_HERO_SOULS: 'Продать души',
  911. SELL_HERO_SOULS_TITLE: 'Обменивает все души героев с абсолютной звездой на золото',
  912. GOLD_RECEIVED: 'Получено золота: {gold}',
  913. OPEN_ALL_EQUIP_BOXES: 'Открыть все ящики фрагментов экипировки?',
  914. SERVER_NOT_ACCEPT: 'Сервер не принял результат',
  915. },
  916. };
  917.  
  918. function getLang() {
  919. let lang = '';
  920. if (typeof NXFlashVars !== 'undefined') {
  921. lang = NXFlashVars.interface_lang
  922. }
  923. if (!lang) {
  924. lang = (navigator.language || navigator.userLanguage).substr(0, 2);
  925. }
  926. if (lang == 'ru') {
  927. return lang;
  928. }
  929. return 'en';
  930. }
  931.  
  932. this.I18N = function (constant, replace) {
  933. const selectLang = getLang();
  934. if (constant && constant in i18nLangData[selectLang]) {
  935. const result = i18nLangData[selectLang][constant];
  936. if (replace) {
  937. return result.sprintf(replace);
  938. }
  939. return result;
  940. }
  941. return `% ${constant} %`;
  942. };
  943.  
  944. String.prototype.sprintf = String.prototype.sprintf ||
  945. function () {
  946. "use strict";
  947. var str = this.toString();
  948. if (arguments.length) {
  949. var t = typeof arguments[0];
  950. var key;
  951. var args = ("string" === t || "number" === t) ?
  952. Array.prototype.slice.call(arguments)
  953. : arguments[0];
  954.  
  955. for (key in args) {
  956. str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
  957. }
  958. }
  959.  
  960. return str;
  961. };
  962.  
  963. /**
  964. * Checkboxes
  965. *
  966. * Чекбоксы
  967. */
  968. const checkboxes = {
  969. passBattle: {
  970. label: I18N('SKIP_FIGHTS'),
  971. cbox: null,
  972. title: I18N('SKIP_FIGHTS_TITLE'),
  973. default: false,
  974. },
  975. sendExpedition: {
  976. label: I18N('AUTO_EXPEDITION'),
  977. cbox: null,
  978. title: I18N('AUTO_EXPEDITION_TITLE'),
  979. default: false,
  980. },
  981. cancelBattle: {
  982. label: I18N('CANCEL_FIGHT'),
  983. cbox: null,
  984. title: I18N('CANCEL_FIGHT_TITLE'),
  985. default: false,
  986. },
  987. preCalcBattle: {
  988. label: I18N('BATTLE_RECALCULATION'),
  989. cbox: null,
  990. title: I18N('BATTLE_RECALCULATION_TITLE'),
  991. default: false,
  992. },
  993. countControl: {
  994. label: I18N('QUANTITY_CONTROL'),
  995. cbox: null,
  996. title: I18N('QUANTITY_CONTROL_TITLE'),
  997. default: true,
  998. },
  999. repeatMission: {
  1000. label: I18N('REPEAT_CAMPAIGN'),
  1001. cbox: null,
  1002. title: I18N('REPEAT_CAMPAIGN_TITLE'),
  1003. default: false,
  1004. },
  1005. noOfferDonat: {
  1006. label: I18N('DISABLE_DONAT'),
  1007. cbox: null,
  1008. title: I18N('DISABLE_DONAT_TITLE'),
  1009. /**
  1010. * A crutch to get the field before getting the character id
  1011. *
  1012. * Костыль чтоб получать поле до получения id персонажа
  1013. */
  1014. default: (() => {
  1015. $result = false;
  1016. try {
  1017. $result = JSON.parse(localStorage[GM_info.script.name + ':noOfferDonat']);
  1018. } catch (e) {
  1019. $result = false;
  1020. }
  1021. return $result || false;
  1022. })(),
  1023. },
  1024. dailyQuests: {
  1025. label: I18N('DAILY_QUESTS'),
  1026. cbox: null,
  1027. title: I18N('DAILY_QUESTS_TITLE'),
  1028. default: false,
  1029. },
  1030. // Потасовки
  1031. autoBrawls: {
  1032. label: I18N('BRAWLS'),
  1033. cbox: null,
  1034. title: I18N('BRAWLS_TITLE'),
  1035. default: (() => {
  1036. $result = false;
  1037. try {
  1038. $result = JSON.parse(localStorage[GM_info.script.name + ':autoBrawls']);
  1039. } catch (e) {
  1040. $result = false;
  1041. }
  1042. return $result || false;
  1043. })(),
  1044. hide: false,
  1045. },
  1046. getAnswer: {
  1047. label: I18N('AUTO_QUIZ'),
  1048. cbox: null,
  1049. title: I18N('AUTO_QUIZ_TITLE'),
  1050. default: false,
  1051. hide: true,
  1052. },
  1053. tryFixIt: {
  1054. label: I18N('BTN_TRY_FIX_IT'),
  1055. cbox: null,
  1056. title: I18N('BTN_TRY_FIX_IT_TITLE'),
  1057. default: false,
  1058. hide: false,
  1059. },
  1060. showErrors: {
  1061. label: I18N('SHOW_ERRORS'),
  1062. cbox: null,
  1063. title: I18N('SHOW_ERRORS_TITLE'),
  1064. default: true,
  1065. },
  1066. buyForGold: {
  1067. label: I18N('BUY_FOR_GOLD'),
  1068. cbox: null,
  1069. title: I18N('BUY_FOR_GOLD_TITLE'),
  1070. default: false,
  1071. },
  1072. hideServers: {
  1073. label: I18N('HIDE_SERVERS'),
  1074. cbox: null,
  1075. title: I18N('HIDE_SERVERS_TITLE'),
  1076. default: false,
  1077. },
  1078. fastSeason: {
  1079. label: I18N('FAST_SEASON'),
  1080. cbox: null,
  1081. title: I18N('FAST_SEASON_TITLE'),
  1082. default: false,
  1083. },
  1084. };
  1085. /**
  1086. * Get checkbox state
  1087. *
  1088. * Получить состояние чекбокса
  1089. */
  1090. function isChecked(checkBox) {
  1091. if (!(checkBox in checkboxes)) {
  1092. return false;
  1093. }
  1094. return checkboxes[checkBox].cbox?.checked;
  1095. }
  1096. /**
  1097. * Input fields
  1098. *
  1099. * Поля ввода
  1100. */
  1101. const inputs = {
  1102. countTitanit: {
  1103. input: null,
  1104. title: I18N('HOW_MUCH_TITANITE'),
  1105. default: 150,
  1106. },
  1107. speedBattle: {
  1108. input: null,
  1109. title: I18N('COMBAT_SPEED'),
  1110. default: 5,
  1111. },
  1112. countTestBattle: {
  1113. input: null,
  1114. title: I18N('NUMBER_OF_TEST'),
  1115. default: 10,
  1116. },
  1117. countAutoBattle: {
  1118. input: null,
  1119. title: I18N('NUMBER_OF_AUTO_BATTLE'),
  1120. default: 10,
  1121. },
  1122. FPS: {
  1123. input: null,
  1124. title: 'FPS',
  1125. default: 60,
  1126. }
  1127. }
  1128. /**
  1129. * Checks the checkbox
  1130. *
  1131. * Поплучить данные поля ввода
  1132. */
  1133. function getInput(inputName) {
  1134. return inputs[inputName]?.input?.value;
  1135. }
  1136.  
  1137. /**
  1138. * Control FPS
  1139. *
  1140. * Контроль FPS
  1141. */
  1142. let nextAnimationFrame = Date.now();
  1143. const oldRequestAnimationFrame = this.requestAnimationFrame;
  1144. this.requestAnimationFrame = async function (e) {
  1145. const FPS = Number(getInput('FPS')) || -1;
  1146. const now = Date.now();
  1147. const delay = nextAnimationFrame - now;
  1148. nextAnimationFrame = Math.max(now, nextAnimationFrame) + Math.min(1e3 / FPS, 1e3);
  1149. if (delay > 0) {
  1150. await new Promise((e) => setTimeout(e, delay));
  1151. }
  1152. oldRequestAnimationFrame(e);
  1153. };
  1154. /**
  1155. * Button List
  1156. *
  1157. * Список кнопочек
  1158. */
  1159. const buttons = {
  1160. getOutland: {
  1161. name: I18N('TO_DO_EVERYTHING'),
  1162. title: I18N('TO_DO_EVERYTHING_TITLE'),
  1163. func: testDoYourBest,
  1164. },
  1165. doActions: {
  1166. name: I18N('ACTIONS'),
  1167. title: I18N('ACTIONS_TITLE'),
  1168. func: async function () {
  1169. const popupButtons = [
  1170. {
  1171. msg: I18N('OUTLAND'),
  1172. result: function () {
  1173. confShow(`${I18N('RUN_SCRIPT')} ${I18N('OUTLAND')}?`, getOutland);
  1174. },
  1175. title: I18N('OUTLAND_TITLE'),
  1176. },
  1177. {
  1178. msg: I18N('TOWER'),
  1179. result: function () {
  1180. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TOWER')}?`, testTower);
  1181. },
  1182. title: I18N('TOWER_TITLE'),
  1183. },
  1184. {
  1185. msg: I18N('EXPEDITIONS'),
  1186. result: function () {
  1187. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EXPEDITIONS')}?`, checkExpedition);
  1188. },
  1189. title: I18N('EXPEDITIONS_TITLE'),
  1190. },
  1191. {
  1192. msg: I18N('MINIONS'),
  1193. result: function () {
  1194. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MINIONS')}?`, testRaidNodes);
  1195. },
  1196. title: I18N('MINIONS_TITLE'),
  1197. },
  1198. {
  1199. msg: I18N('ESTER_EGGS'),
  1200. result: function () {
  1201. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ESTER_EGGS')}?`, offerFarmAllReward);
  1202. },
  1203. title: I18N('ESTER_EGGS_TITLE'),
  1204. },
  1205. {
  1206. msg: I18N('STORM'),
  1207. result: function () {
  1208. testAdventure('solo');
  1209. },
  1210. title: I18N('STORM_TITLE'),
  1211. },
  1212. {
  1213. msg: I18N('REWARDS'),
  1214. result: function () {
  1215. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS')}?`, questAllFarm);
  1216. },
  1217. title: I18N('REWARDS_TITLE'),
  1218. },
  1219. {
  1220. msg: I18N('MAIL'),
  1221. result: function () {
  1222. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MAIL')}?`, mailGetAll);
  1223. },
  1224. title: I18N('MAIL_TITLE'),
  1225. },
  1226. {
  1227. msg: I18N('SEER'),
  1228. result: function () {
  1229. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SEER')}?`, rollAscension);
  1230. },
  1231. title: I18N('SEER_TITLE'),
  1232. },
  1233. /*
  1234. {
  1235. msg: I18N('NY_GIFTS'),
  1236. result: getGiftNewYear,
  1237. title: I18N('NY_GIFTS_TITLE'),
  1238. },
  1239. */
  1240. ];
  1241. popupButtons.push({ result: false, isClose: true });
  1242. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1243. if (typeof answer === 'function') {
  1244. answer();
  1245. }
  1246. },
  1247. },
  1248. doOthers: {
  1249. name: I18N('OTHERS'),
  1250. title: I18N('OTHERS_TITLE'),
  1251. func: async function () {
  1252. const popupButtons = [
  1253. {
  1254. msg: I18N('GET_ENERGY'),
  1255. result: farmStamina,
  1256. title: I18N('GET_ENERGY_TITLE'),
  1257. },
  1258. {
  1259. msg: I18N('ITEM_EXCHANGE'),
  1260. result: fillActive,
  1261. title: I18N('ITEM_EXCHANGE_TITLE'),
  1262. },
  1263. {
  1264. msg: I18N('BUY_SOULS'),
  1265. result: function () {
  1266. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_SOULS')}?`, buyHeroFragments);
  1267. },
  1268. title: I18N('BUY_SOULS_TITLE'),
  1269. },
  1270. {
  1271. msg: I18N('BUY_FOR_GOLD'),
  1272. result: function () {
  1273. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_FOR_GOLD')}?`, buyInStoreForGold);
  1274. },
  1275. title: I18N('BUY_FOR_GOLD_TITLE'),
  1276. },
  1277. {
  1278. msg: I18N('BUY_OUTLAND'),
  1279. result: bossOpenChestPay,
  1280. title: I18N('BUY_OUTLAND_TITLE'),
  1281. },
  1282. {
  1283. msg: I18N('AUTO_RAID_ADVENTURE'),
  1284. result: autoRaidAdventure,
  1285. title: I18N('AUTO_RAID_ADVENTURE_TITLE'),
  1286. },
  1287. {
  1288. msg: I18N('CLAN_STAT'),
  1289. result: clanStatistic,
  1290. title: I18N('CLAN_STAT_TITLE'),
  1291. },
  1292. {
  1293. msg: I18N('EPIC_BRAWL'),
  1294. result: async function () {
  1295. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EPIC_BRAWL')}?`, () => {
  1296. const brawl = new epicBrawl();
  1297. brawl.start();
  1298. });
  1299. },
  1300. title: I18N('EPIC_BRAWL_TITLE'),
  1301. },
  1302. {
  1303. msg: I18N('ARTIFACTS_UPGRADE'),
  1304. result: updateArtifacts,
  1305. title: I18N('ARTIFACTS_UPGRADE_TITLE'),
  1306. },
  1307. {
  1308. msg: I18N('SKINS_UPGRADE'),
  1309. result: updateSkins,
  1310. title: I18N('SKINS_UPGRADE_TITLE'),
  1311. },
  1312. {
  1313. msg: I18N('SEASON_REWARD'),
  1314. result: farmBattlePass,
  1315. title: I18N('SEASON_REWARD_TITLE'),
  1316. },
  1317. {
  1318. msg: I18N('SELL_HERO_SOULS'),
  1319. result: sellHeroSoulsForGold,
  1320. title: I18N('SELL_HERO_SOULS_TITLE'),
  1321. },
  1322. {
  1323. msg: I18N('CHANGE_MAP'),
  1324. result: async function () {
  1325. const maps = Object.values(lib.data.seasonAdventure.list)
  1326. .filter((e) => e.map.cells.length > 2)
  1327. .map((i) => ({
  1328. msg: I18N('MAP_NUM', { num: i.id }),
  1329. result: i.id,
  1330. }));
  1331.  
  1332. const result = await popup.confirm(I18N('SELECT_ISLAND_MAP'), [...maps, { result: false, isClose: true }]);
  1333. if (result) {
  1334. cheats.changeIslandMap(result);
  1335. }
  1336. },
  1337. title: I18N('CHANGE_MAP_TITLE'),
  1338. },
  1339. ];
  1340. popupButtons.push({ result: false, isClose: true });
  1341. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1342. if (typeof answer === 'function') {
  1343. answer();
  1344. }
  1345. },
  1346. },
  1347. testTitanArena: {
  1348. name: I18N('TITAN_ARENA'),
  1349. title: I18N('TITAN_ARENA_TITLE'),
  1350. func: function () {
  1351. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TITAN_ARENA')}?`, testTitanArena);
  1352. },
  1353. },
  1354. testDungeon: {
  1355. name: I18N('DUNGEON'),
  1356. title: I18N('DUNGEON_TITLE'),
  1357. func: function () {
  1358. confShow(`${I18N('RUN_SCRIPT')} ${I18N('DUNGEON')}?`, testDungeon);
  1359. },
  1360. },
  1361. // Архидемон
  1362. bossRatingEvent: {
  1363. name: I18N('ARCHDEMON'),
  1364. title: I18N('ARCHDEMON_TITLE'),
  1365. func: function () {
  1366. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ARCHDEMON')}?`, bossRatingEvent);
  1367. },
  1368. hide: true,
  1369. },
  1370. // Горнило душ
  1371. bossRatingEvent: {
  1372. name: I18N('FURNACE_OF_SOULS'),
  1373. title: I18N('ARCHDEMON_TITLE'),
  1374. func: function () {
  1375. confShow(`${I18N('RUN_SCRIPT')} ${I18N('FURNACE_OF_SOULS')}?`, bossRatingEventSouls);
  1376. },
  1377. hide: true,
  1378. },
  1379. rewardsAndMailFarm: {
  1380. name: I18N('REWARDS_AND_MAIL'),
  1381. title: I18N('REWARDS_AND_MAIL_TITLE'),
  1382. func: function () {
  1383. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS_AND_MAIL')}?`, rewardsAndMailFarm);
  1384. },
  1385. },
  1386. testAdventure: {
  1387. name: I18N('ADVENTURE'),
  1388. title: I18N('ADVENTURE_TITLE'),
  1389. func: () => {
  1390. testAdventure();
  1391. },
  1392. },
  1393. goToSanctuary: {
  1394. name: I18N('SANCTUARY'),
  1395. title: I18N('SANCTUARY_TITLE'),
  1396. func: cheats.goSanctuary,
  1397. },
  1398. goToClanWar: {
  1399. name: I18N('GUILD_WAR'),
  1400. title: I18N('GUILD_WAR_TITLE'),
  1401. func: cheats.goClanWar,
  1402. },
  1403. dailyQuests: {
  1404. name: I18N('DAILY_QUESTS'),
  1405. title: I18N('DAILY_QUESTS_TITLE'),
  1406. func: async function () {
  1407. const quests = new dailyQuests(
  1408. () => {},
  1409. () => {}
  1410. );
  1411. await quests.autoInit();
  1412. quests.start();
  1413. },
  1414. },
  1415. newDay: {
  1416. name: I18N('SYNC'),
  1417. title: I18N('SYNC_TITLE'),
  1418. func: function () {
  1419. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SYNC')}?`, cheats.refreshGame);
  1420. },
  1421. },
  1422. };
  1423. /**
  1424. * Display buttons
  1425. *
  1426. * Вывести кнопочки
  1427. */
  1428. function addControlButtons() {
  1429. for (let name in buttons) {
  1430. button = buttons[name];
  1431. if (button.hide) {
  1432. continue;
  1433. }
  1434. button['button'] = scriptMenu.addButton(button.name, button.func, button.title);
  1435. }
  1436. }
  1437. /**
  1438. * Adds links
  1439. *
  1440. * Добавляет ссылки
  1441. */
  1442. function addBottomUrls() {
  1443. scriptMenu.addHeader(I18N('BOTTOM_URLS'));
  1444. }
  1445. /**
  1446. * Stop repetition of the mission
  1447. *
  1448. * Остановить повтор миссии
  1449. */
  1450. let isStopSendMission = false;
  1451. /**
  1452. * There is a repetition of the mission
  1453. *
  1454. * Идет повтор миссии
  1455. */
  1456. let isSendsMission = false;
  1457. /**
  1458. * Data on the past mission
  1459. *
  1460. * Данные о прошедшей мисии
  1461. */
  1462. let lastMissionStart = {}
  1463. /**
  1464. * Start time of the last battle in the company
  1465. *
  1466. * Время начала последнего боя в кампании
  1467. */
  1468. let lastMissionBattleStart = 0;
  1469. /**
  1470. * Data for calculating the last battle with the boss
  1471. *
  1472. * Данные для расчете последнего боя с боссом
  1473. */
  1474. let lastBossBattle = null;
  1475. /**
  1476. * Information about the last battle
  1477. *
  1478. * Данные о прошедшей битве
  1479. */
  1480. let lastBattleArg = {}
  1481. let lastBossBattleStart = null;
  1482. this.addBattleTimer = 4;
  1483. this.invasionTimer = 2500;
  1484. /**
  1485. * The name of the function of the beginning of the battle
  1486. *
  1487. * Имя функции начала боя
  1488. */
  1489. let nameFuncStartBattle = '';
  1490. /**
  1491. * The name of the function of the end of the battle
  1492. *
  1493. * Имя функции конца боя
  1494. */
  1495. let nameFuncEndBattle = '';
  1496. /**
  1497. * Data for calculating the last battle
  1498. *
  1499. * Данные для расчета последнего боя
  1500. */
  1501. let lastBattleInfo = null;
  1502. /**
  1503. * The ability to cancel the battle
  1504. *
  1505. * Возможность отменить бой
  1506. */
  1507. let isCancalBattle = true;
  1508.  
  1509. /**
  1510. * Certificator of the last open nesting doll
  1511. *
  1512. * Идетификатор последней открытой матрешки
  1513. */
  1514. let lastRussianDollId = null;
  1515. /**
  1516. * Cancel the training guide
  1517. *
  1518. * Отменить обучающее руководство
  1519. */
  1520. this.isCanceledTutorial = false;
  1521.  
  1522. /**
  1523. * Data from the last question of the quiz
  1524. *
  1525. * Данные последнего вопроса викторины
  1526. */
  1527. let lastQuestion = null;
  1528. /**
  1529. * Answer to the last question of the quiz
  1530. *
  1531. * Ответ на последний вопрос викторины
  1532. */
  1533. let lastAnswer = null;
  1534. /**
  1535. * Flag for opening keys or titan artifact spheres
  1536. *
  1537. * Флаг открытия ключей или сфер артефактов титанов
  1538. */
  1539. let artifactChestOpen = false;
  1540. /**
  1541. * The name of the function to open keys or orbs of titan artifacts
  1542. *
  1543. * Имя функции открытия ключей или сфер артефактов титанов
  1544. */
  1545. let artifactChestOpenCallName = '';
  1546. let correctShowOpenArtifact = 0;
  1547. /**
  1548. * Data for the last battle in the dungeon
  1549. * (Fix endless cards)
  1550. *
  1551. * Данные для последнего боя в подземке
  1552. * (Исправление бесконечных карт)
  1553. */
  1554. let lastDungeonBattleData = null;
  1555. /**
  1556. * Start time of the last battle in the dungeon
  1557. *
  1558. * Время начала последнего боя в подземелье
  1559. */
  1560. let lastDungeonBattleStart = 0;
  1561. /**
  1562. * Subscription end time
  1563. *
  1564. * Время окончания подписки
  1565. */
  1566. let subEndTime = 0;
  1567. /**
  1568. * Number of prediction cards
  1569. *
  1570. * Количество карт предсказаний
  1571. */
  1572. let countPredictionCard = 0;
  1573.  
  1574. /**
  1575. * Brawl pack
  1576. *
  1577. * Пачка для потасовок
  1578. */
  1579. let brawlsPack = null;
  1580. /**
  1581. * Autobrawl started
  1582. *
  1583. * Автопотасовка запущена
  1584. */
  1585. let isBrawlsAutoStart = false;
  1586. let clanDominationGetInfo = null;
  1587. /**
  1588. * Copies the text to the clipboard
  1589. *
  1590. * Копирует тест в буфер обмена
  1591. * @param {*} text copied text // копируемый текст
  1592. */
  1593. function copyText(text) {
  1594. let copyTextarea = document.createElement("textarea");
  1595. copyTextarea.style.opacity = "0";
  1596. copyTextarea.textContent = text;
  1597. document.body.appendChild(copyTextarea);
  1598. copyTextarea.select();
  1599. document.execCommand("copy");
  1600. document.body.removeChild(copyTextarea);
  1601. delete copyTextarea;
  1602. }
  1603. /**
  1604. * Returns the history of requests
  1605. *
  1606. * Возвращает историю запросов
  1607. */
  1608. this.getRequestHistory = function() {
  1609. return requestHistory;
  1610. }
  1611. /**
  1612. * Generates a random integer from min to max
  1613. *
  1614. * Гененирует случайное целое число от min до max
  1615. */
  1616. const random = function (min, max) {
  1617. return Math.floor(Math.random() * (max - min + 1) + min);
  1618. }
  1619. const randf = function (min, max) {
  1620. return Math.random() * (max - min + 1) + min;
  1621. };
  1622. /**
  1623. * Clearing the request history
  1624. *
  1625. * Очистка истоии запросов
  1626. */
  1627. setInterval(function () {
  1628. let now = Date.now();
  1629. for (let i in requestHistory) {
  1630. const time = +i.split('_')[0];
  1631. if (now - time > 300000) {
  1632. delete requestHistory[i];
  1633. }
  1634. }
  1635. }, 300000);
  1636. /**
  1637. * Displays the dialog box
  1638. *
  1639. * Отображает диалоговое окно
  1640. */
  1641. function confShow(message, yesCallback, noCallback) {
  1642. let buts = [];
  1643. message = message || I18N('DO_YOU_WANT');
  1644. noCallback = noCallback || (() => {});
  1645. if (yesCallback) {
  1646. buts = [
  1647. { msg: I18N('BTN_RUN'), result: true},
  1648. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true},
  1649. ]
  1650. } else {
  1651. yesCallback = () => {};
  1652. buts = [
  1653. { msg: I18N('BTN_OK'), result: true},
  1654. ];
  1655. }
  1656. popup.confirm(message, buts).then((e) => {
  1657. // dialogPromice = null;
  1658. if (e) {
  1659. yesCallback();
  1660. } else {
  1661. noCallback();
  1662. }
  1663. });
  1664. }
  1665. /**
  1666. * Override/proxy the method for creating a WS package send
  1667. *
  1668. * Переопределяем/проксируем метод создания отправки WS пакета
  1669. */
  1670. WebSocket.prototype.send = function (data) {
  1671. if (!this.isSetOnMessage) {
  1672. const oldOnmessage = this.onmessage;
  1673. this.onmessage = function (event) {
  1674. try {
  1675. const data = JSON.parse(event.data);
  1676. if (!this.isWebSocketLogin && data.result.type == "iframeEvent.login") {
  1677. this.isWebSocketLogin = true;
  1678. } else if (data.result.type == "iframeEvent.login") {
  1679. return;
  1680. }
  1681. } catch (e) { }
  1682. return oldOnmessage.apply(this, arguments);
  1683. }
  1684. this.isSetOnMessage = true;
  1685. }
  1686. original.SendWebSocket.call(this, data);
  1687. }
  1688. /**
  1689. * Overriding/Proxying the Ajax Request Creation Method
  1690. *
  1691. * Переопределяем/проксируем метод создания Ajax запроса
  1692. */
  1693. XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
  1694. this.uniqid = Date.now() + '_' + random(1000000, 10000000);
  1695. this.errorRequest = false;
  1696. if (method == 'POST' && url.includes('.nextersglobal.com/api/') && /api\/$/.test(url)) {
  1697. if (!apiUrl) {
  1698. apiUrl = url;
  1699. const socialInfo = /heroes-(.+?)\./.exec(apiUrl);
  1700. console.log(socialInfo);
  1701. }
  1702. requestHistory[this.uniqid] = {
  1703. method,
  1704. url,
  1705. error: [],
  1706. headers: {},
  1707. request: null,
  1708. response: null,
  1709. signature: [],
  1710. calls: {},
  1711. };
  1712. } else if (method == 'POST' && url.includes('error.nextersglobal.com/client/')) {
  1713. this.errorRequest = true;
  1714. }
  1715. return original.open.call(this, method, url, async, user, password);
  1716. };
  1717. /**
  1718. * Overriding/Proxying the header setting method for the AJAX request
  1719. *
  1720. * Переопределяем/проксируем метод установки заголовков для AJAX запроса
  1721. */
  1722. XMLHttpRequest.prototype.setRequestHeader = function (name, value, check) {
  1723. if (this.uniqid in requestHistory) {
  1724. requestHistory[this.uniqid].headers[name] = value;
  1725. } else {
  1726. check = true;
  1727. }
  1728.  
  1729. if (name == 'X-Auth-Signature') {
  1730. requestHistory[this.uniqid].signature.push(value);
  1731. if (!check) {
  1732. return;
  1733. }
  1734. }
  1735.  
  1736. return original.setRequestHeader.call(this, name, value);
  1737. };
  1738. /**
  1739. * Overriding/Proxying the AJAX Request Sending Method
  1740. *
  1741. * Переопределяем/проксируем метод отправки AJAX запроса
  1742. */
  1743. XMLHttpRequest.prototype.send = async function (sourceData) {
  1744. if (this.uniqid in requestHistory) {
  1745. let tempData = null;
  1746. if (getClass(sourceData) == "ArrayBuffer") {
  1747. tempData = decoder.decode(sourceData);
  1748. } else {
  1749. tempData = sourceData;
  1750. }
  1751. requestHistory[this.uniqid].request = tempData;
  1752. let headers = requestHistory[this.uniqid].headers;
  1753. lastHeaders = Object.assign({}, headers);
  1754. /**
  1755. * Game loading event
  1756. *
  1757. * Событие загрузки игры
  1758. */
  1759. if (headers["X-Request-Id"] > 2 && !isLoadGame) {
  1760. isLoadGame = true;
  1761. await lib.load();
  1762. addControls();
  1763. addControlButtons();
  1764. addBottomUrls();
  1765.  
  1766. if (isChecked('sendExpedition')) {
  1767. checkExpedition();
  1768. }
  1769.  
  1770. getAutoGifts();
  1771.  
  1772. cheats.activateHacks();
  1773. justInfo();
  1774. if (isChecked('dailyQuests')) {
  1775. testDailyQuests();
  1776. }
  1777.  
  1778. if (isChecked('buyForGold')) {
  1779. buyInStoreForGold();
  1780. }
  1781. }
  1782. /**
  1783. * Outgoing request data processing
  1784. *
  1785. * Обработка данных исходящего запроса
  1786. */
  1787. sourceData = await checkChangeSend.call(this, sourceData, tempData);
  1788. /**
  1789. * Handling incoming request data
  1790. *
  1791. * Обработка данных входящего запроса
  1792. */
  1793. const oldReady = this.onreadystatechange;
  1794. this.onreadystatechange = async function (e) {
  1795. if (this.errorRequest) {
  1796. return oldReady.apply(this, arguments);
  1797. }
  1798. if(this.readyState == 4 && this.status == 200) {
  1799. isTextResponse = this.responseType === "text" || this.responseType === "";
  1800. let response = isTextResponse ? this.responseText : this.response;
  1801. requestHistory[this.uniqid].response = response;
  1802. /**
  1803. * Replacing incoming request data
  1804. *
  1805. * Заменна данных входящего запроса
  1806. */
  1807. if (isTextResponse) {
  1808. await checkChangeResponse.call(this, response);
  1809. }
  1810. /**
  1811. * A function to run after the request is executed
  1812. *
  1813. * Функция запускаемая после выполения запроса
  1814. */
  1815. if (typeof this.onReadySuccess == 'function') {
  1816. setTimeout(this.onReadySuccess, 500);
  1817. }
  1818. /** Удаляем из истории запросов битвы с боссом */
  1819. if ('invasion_bossStart' in requestHistory[this.uniqid].calls) delete requestHistory[this.uniqid];
  1820. }
  1821. if (oldReady) {
  1822. return oldReady.apply(this, arguments);
  1823. }
  1824. }
  1825. }
  1826. if (this.errorRequest) {
  1827. const oldReady = this.onreadystatechange;
  1828. this.onreadystatechange = function () {
  1829. Object.defineProperty(this, 'status', {
  1830. writable: true
  1831. });
  1832. this.status = 200;
  1833. Object.defineProperty(this, 'readyState', {
  1834. writable: true
  1835. });
  1836. this.readyState = 4;
  1837. Object.defineProperty(this, 'responseText', {
  1838. writable: true
  1839. });
  1840. this.responseText = JSON.stringify({
  1841. "result": true
  1842. });
  1843. if (typeof this.onReadySuccess == 'function') {
  1844. setTimeout(this.onReadySuccess, 200);
  1845. }
  1846. return oldReady.apply(this, arguments);
  1847. }
  1848. this.onreadystatechange();
  1849. } else {
  1850. try {
  1851. return original.send.call(this, sourceData);
  1852. } catch(e) {
  1853. debugger;
  1854. }
  1855. }
  1856. };
  1857. /**
  1858. * Processing and substitution of outgoing data
  1859. *
  1860. * Обработка и подмена исходящих данных
  1861. */
  1862. async function checkChangeSend(sourceData, tempData) {
  1863. try {
  1864. /**
  1865. * A function that replaces battle data with incorrect ones to cancel combatя
  1866. *
  1867. * Функция заменяющая данные боя на неверные для отмены боя
  1868. */
  1869. const fixBattle = function (heroes) {
  1870. for (const ids in heroes) {
  1871. hero = heroes[ids];
  1872. hero.energy = random(1, 999);
  1873. if (hero.hp > 0) {
  1874. hero.hp = random(1, hero.hp);
  1875. }
  1876. }
  1877. }
  1878. /**
  1879. * Dialog window 2
  1880. *
  1881. * Диалоговое окно 2
  1882. */
  1883. const showMsg = async function (msg, ansF, ansS) {
  1884. if (typeof popup == 'object') {
  1885. return await popup.confirm(msg, [
  1886. {msg: ansF, result: false},
  1887. {msg: ansS, result: true},
  1888. ]);
  1889. } else {
  1890. return !confirm(`${msg}\n ${ansF} (${I18N('BTN_OK')})\n ${ansS} (${I18N('BTN_CANCEL')})`);
  1891. }
  1892. }
  1893. /**
  1894. * Dialog window 3
  1895. *
  1896. * Диалоговое окно 3
  1897. */
  1898. const showMsgs = async function (msg, ansF, ansS, ansT) {
  1899. return await popup.confirm(msg, [
  1900. {msg: ansF, result: 0},
  1901. {msg: ansS, result: 1},
  1902. {msg: ansT, result: 2},
  1903. ]);
  1904. }
  1905.  
  1906. let changeRequest = false;
  1907. testData = JSON.parse(tempData);
  1908. for (const call of testData.calls) {
  1909. if (!artifactChestOpen) {
  1910. requestHistory[this.uniqid].calls[call.name] = call.ident;
  1911. }
  1912. /**
  1913. * Cancellation of the battle in adventures, on VG and with minions of Asgard
  1914. * Отмена боя в приключениях, на ВГ и с прислужниками Асгарда
  1915. */
  1916. if ((call.name == 'adventure_endBattle' ||
  1917. call.name == 'adventureSolo_endBattle' ||
  1918. call.name == 'clanWarEndBattle' &&
  1919. isChecked('cancelBattle') ||
  1920. call.name == 'crossClanWar_endBattle' &&
  1921. isChecked('cancelBattle') ||
  1922. call.name == 'brawl_endBattle' ||
  1923. call.name == 'towerEndBattle' ||
  1924. call.name == 'invasion_bossEnd' ||
  1925. call.name == 'titanArenaEndBattle' ||
  1926. call.name == 'bossEndBattle' ||
  1927. call.name == 'clanRaid_endNodeBattle') &&
  1928. isCancalBattle) {
  1929. nameFuncEndBattle = call.name;
  1930.  
  1931. if (isChecked('tryFixIt') &&
  1932. !call.args.result.win &&
  1933. (call.name == 'brawl_endBattle' ||
  1934. //call.name == 'crossClanWar_endBattle' ||
  1935. call.name == 'epicBrawl_endBattle' ||
  1936. //call.name == 'clanWarEndBattle' ||
  1937. call.name == 'adventure_endBattle' ||
  1938. call.name == 'titanArenaEndBattle' ||
  1939. call.name == 'bossEndBattle' ||
  1940. call.name == 'adventureSolo_endBattle') &&
  1941. lastBattleInfo) {
  1942. const noFixWin = call.name == 'clanWarEndBattle' || call.name == 'crossClanWar_endBattle';
  1943. const cloneBattle = structuredClone(lastBattleInfo);
  1944. try {
  1945. const bFix = new BestOrWinFixBattle(cloneBattle);
  1946. bFix.setNoMakeWin(noFixWin);
  1947. let endTime = Date.now() + 3e4;
  1948. if (endTime < cloneBattle.endTime) {
  1949. endTime = cloneBattle.endTime;
  1950. }
  1951. const result = await bFix.start(cloneBattle.endTime, 150);
  1952.  
  1953. if (result.result.win) {
  1954. call.args.result = result.result;
  1955. call.args.progress = result.progress;
  1956. changeRequest = true;
  1957. } else if (result.value) {
  1958. if (
  1959. await popup.confirm('Поражение<br>Лучший результат: ' + result.value + '%', [
  1960. { msg: 'Отмена', result: 0 },
  1961. { msg: 'Принять', result: 1 },
  1962. ])
  1963. ) {
  1964. call.args.result = result.result;
  1965. call.args.progress = result.progress;
  1966. changeRequest = true;
  1967. }
  1968. }
  1969. } catch (error) {
  1970. console.error(error);
  1971. }
  1972. }
  1973.  
  1974. if (!call.args.result.win) {
  1975. let resultPopup = false;
  1976. if (call.name == 'adventure_endBattle' ||
  1977. call.name == 'invasion_bossEnd' ||
  1978. call.name == 'bossEndBattle' ||
  1979. call.name == 'adventureSolo_endBattle') {
  1980. resultPopup = await showMsgs(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  1981. } else if (call.name == 'clanWarEndBattle' ||
  1982. call.name == 'crossClanWar_endBattle') {
  1983. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_AUTO_F5'));
  1984. } else {
  1985. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'));
  1986. }
  1987. if (resultPopup) {
  1988. if (call.name == 'invasion_bossEnd') {
  1989. this.errorRequest = true;
  1990. }
  1991. fixBattle(call.args.progress[0].attackers.heroes);
  1992. fixBattle(call.args.progress[0].defenders.heroes);
  1993. changeRequest = true;
  1994. if (resultPopup > 1) {
  1995. this.onReadySuccess = testAutoBattle;
  1996. // setTimeout(bossBattle, 1000);
  1997. }
  1998. }
  1999. } else if (call.args.result.stars < 3 && call.name == 'towerEndBattle') {
  2000. resultPopup = await showMsg(I18N('LOST_HEROES'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  2001. if (resultPopup) {
  2002. fixBattle(call.args.progress[0].attackers.heroes);
  2003. fixBattle(call.args.progress[0].defenders.heroes);
  2004. changeRequest = true;
  2005. if (resultPopup > 1) {
  2006. this.onReadySuccess = testAutoBattle;
  2007. }
  2008. }
  2009. }
  2010. // Потасовки
  2011. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_endBattle') {}
  2012. }
  2013. /**
  2014. * Save pack for Brawls
  2015. *
  2016. * Сохраняем пачку для потасовок
  2017. */
  2018. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_startBattle') {
  2019. console.log(JSON.stringify(call.args));
  2020. brawlsPack = call.args;
  2021. if (
  2022. await popup.confirm(
  2023. I18N('START_AUTO_BRAWLS'),
  2024. [
  2025. { msg: I18N('BTN_NO'), result: false },
  2026. { msg: I18N('BTN_YES'), result: true },
  2027. ],
  2028. [
  2029. {
  2030. name: 'isAuto',
  2031. label: I18N('BRAWL_AUTO_PACK'),
  2032. checked: false,
  2033. },
  2034. ]
  2035. )
  2036. ) {
  2037. isBrawlsAutoStart = true;
  2038. const isAuto = popup.getCheckBoxes().find((e) => e.name === 'isAuto');
  2039. this.errorRequest = true;
  2040. testBrawls(isAuto.checked);
  2041. }
  2042. }
  2043. /**
  2044. * Canceled fight in Asgard
  2045. * Отмена боя в Асгарде
  2046. */
  2047. if (call.name == 'clanRaid_endBossBattle' && isChecked('cancelBattle')) {
  2048. const bossDamage = call.args.progress[0].defenders.heroes[1].extra;
  2049. let maxDamage = bossDamage.damageTaken + bossDamage.damageTakenNextLevel;
  2050. const lastDamage = maxDamage;
  2051.  
  2052. const testFunc = [];
  2053.  
  2054. if (testFuntions.masterFix) {
  2055. testFunc.push({ msg: 'masterFix', isInput: true, default: 100 });
  2056. }
  2057.  
  2058. const resultPopup = await popup.confirm(
  2059. `${I18N('MSG_YOU_APPLIED')} ${lastDamage.toLocaleString()} ${I18N('MSG_DAMAGE')}.`,
  2060. [
  2061. { msg: I18N('BTN_OK'), result: false },
  2062. { msg: I18N('BTN_AUTO_F5'), result: 1 },
  2063. { msg: I18N('BTN_TRY_FIX_IT'), result: 2 },
  2064. ...testFunc,
  2065. ],
  2066. [
  2067. {
  2068. name: 'isStat',
  2069. label: I18N('CALC_STAT'),
  2070. checked: false,
  2071. },
  2072. ]
  2073. );
  2074. if (resultPopup) {
  2075. if (resultPopup == 2) {
  2076. setProgress(I18N('LETS_FIX'), false);
  2077. await new Promise((e) => setTimeout(e, 0));
  2078. const cloneBattle = structuredClone(lastBossBattle);
  2079. const endTime = cloneBattle.endTime - 1e4;
  2080. console.log('fixBossBattleStart');
  2081.  
  2082. const bFix = new BossFixBattle(cloneBattle);
  2083. const result = await bFix.start(endTime, 300);
  2084. console.log(result);
  2085.  
  2086. let msgResult = I18N('DAMAGE_NO_FIXED', {
  2087. lastDamage: lastDamage.toLocaleString()
  2088. });
  2089. if (result.value > lastDamage) {
  2090. call.args.result = result.result;
  2091. call.args.progress = result.progress;
  2092. msgResult = I18N('DAMAGE_FIXED', {
  2093. lastDamage: lastDamage.toLocaleString(),
  2094. maxDamage: result.value.toLocaleString(),
  2095. });
  2096. }
  2097. console.log(lastDamage, '>', result.value);
  2098. setProgress(
  2099. msgResult +
  2100. '<br/>' +
  2101. I18N('COUNT_FIXED', {
  2102. count: result.maxCount,
  2103. }),
  2104. false,
  2105. hideProgress
  2106. );
  2107. } else if (resultPopup > 3) {
  2108. const cloneBattle = structuredClone(lastBossBattle);
  2109. const mFix = new masterFixBattle(cloneBattle);
  2110. const result = await mFix.start(cloneBattle.endTime, resultPopup);
  2111. console.log(result);
  2112. let msgResult = I18N('DAMAGE_NO_FIXED', {
  2113. lastDamage: lastDamage.toLocaleString(),
  2114. });
  2115. if (result.value > lastDamage) {
  2116. maxDamage = result.value;
  2117. call.args.result = result.result;
  2118. call.args.progress = result.progress;
  2119. msgResult = I18N('DAMAGE_FIXED', {
  2120. lastDamage: lastDamage.toLocaleString(),
  2121. maxDamage: maxDamage.toLocaleString(),
  2122. });
  2123. }
  2124. console.log('Урон:', lastDamage, maxDamage);
  2125. setProgress(msgResult, false, hideProgress);
  2126. } else {
  2127. fixBattle(call.args.progress[0].attackers.heroes);
  2128. fixBattle(call.args.progress[0].defenders.heroes);
  2129. }
  2130. changeRequest = true;
  2131. }
  2132. const isStat = popup.getCheckBoxes().find((e) => e.name === 'isStat');
  2133. if (isStat.checked) {
  2134. this.onReadySuccess = testBossBattle;
  2135. }
  2136. }
  2137. /**
  2138. * Save the Asgard Boss Attack Pack
  2139. * Сохраняем пачку для атаки босса Асгарда
  2140. */
  2141. if (call.name == 'clanRaid_startBossBattle') {
  2142. console.log(JSON.stringify(call.args));
  2143. }
  2144. /**
  2145. * Saving the request to start the last battle
  2146. * Сохранение запроса начала последнего боя
  2147. */
  2148. if (
  2149. call.name == 'clanWarAttack' ||
  2150. call.name == 'crossClanWar_startBattle' ||
  2151. call.name == 'adventure_turnStartBattle' ||
  2152. call.name == 'adventureSolo_turnStartBattle' ||
  2153. call.name == 'bossAttack' ||
  2154. call.name == 'invasion_bossStart' ||
  2155. call.name == 'towerStartBattle'
  2156. ) {
  2157. nameFuncStartBattle = call.name;
  2158. lastBattleArg = call.args;
  2159.  
  2160. if (call.name == 'invasion_bossStart') {
  2161. const timePassed = Date.now() - lastBossBattleStart;
  2162. if (timePassed < invasionTimer) {
  2163. await new Promise((e) => setTimeout(e, invasionTimer - timePassed));
  2164. }
  2165. invasionTimer -= 1;
  2166. }
  2167. lastBossBattleStart = Date.now();
  2168. }
  2169. if (call.name == 'invasion_bossEnd') {
  2170. const lastBattle = lastBattleInfo;
  2171. if (lastBattle && call.args.result.win) {
  2172. lastBattle.progress = call.args.progress;
  2173. const result = await Calc(lastBattle);
  2174. let timer = getTimer(result.battleTime, 1) + addBattleTimer;
  2175. const period = Math.ceil((Date.now() - lastBossBattleStart) / 1000);
  2176. console.log(timer, period);
  2177. if (period < timer) {
  2178. timer = timer - period;
  2179. await countdownTimer(timer);
  2180. }
  2181. }
  2182. }
  2183. /**
  2184. * Disable spending divination cards
  2185. * Отключить трату карт предсказаний
  2186. */
  2187. if (call.name == 'dungeonEndBattle') {
  2188. if (call.args.isRaid) {
  2189. if (countPredictionCard <= 0) {
  2190. delete call.args.isRaid;
  2191. changeRequest = true;
  2192. } else if (countPredictionCard > 0) {
  2193. countPredictionCard--;
  2194. }
  2195. }
  2196. console.log(`Cards: ${countPredictionCard}`);
  2197. /**
  2198. * Fix endless cards
  2199. * Исправление бесконечных карт
  2200. */
  2201. const lastBattle = lastDungeonBattleData;
  2202. if (lastBattle && !call.args.isRaid) {
  2203. if (changeRequest) {
  2204. lastBattle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2205. } else {
  2206. lastBattle.progress = call.args.progress;
  2207. }
  2208. const result = await Calc(lastBattle);
  2209.  
  2210. if (changeRequest) {
  2211. call.args.progress = result.progress;
  2212. call.args.result = result.result;
  2213. }
  2214. let timer = result.battleTimer + addBattleTimer;
  2215. const period = Math.ceil((Date.now() - lastDungeonBattleStart) / 1000);
  2216. console.log(timer, period);
  2217. if (period < timer) {
  2218. timer = timer - period;
  2219. await countdownTimer(timer);
  2220. }
  2221. }
  2222. }
  2223. /**
  2224. * Quiz Answer
  2225. * Ответ на викторину
  2226. */
  2227. if (call.name == 'quizAnswer') {
  2228. /**
  2229. * Automatically changes the answer to the correct one if there is one.
  2230. * Автоматически меняет ответ на правильный если он есть
  2231. */
  2232. if (lastAnswer && isChecked('getAnswer')) {
  2233. call.args.answerId = lastAnswer;
  2234. lastAnswer = null;
  2235. changeRequest = true;
  2236. }
  2237. }
  2238. /**
  2239. * Present
  2240. * Подарки
  2241. */
  2242. if (call.name == 'freebieCheck') {
  2243. freebieCheckInfo = call;
  2244. }
  2245. /** missionTimer */
  2246. if (call.name == 'missionEnd' && missionBattle) {
  2247. let startTimer = false;
  2248. if (!call.args.result.win) {
  2249. startTimer = await popup.confirm(I18N('DEFEAT_TURN_TIMER'), [
  2250. { msg: I18N('BTN_NO'), result: false },
  2251. { msg: I18N('BTN_YES'), result: true },
  2252. ]);
  2253. }
  2254.  
  2255. if (call.args.result.win || startTimer) {
  2256. missionBattle.progress = call.args.progress;
  2257. missionBattle.result = call.args.result;
  2258. const result = await Calc(missionBattle);
  2259.  
  2260. let timer = result.battleTimer + addBattleTimer;
  2261. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  2262. if (period < timer) {
  2263. timer = timer - period;
  2264. await countdownTimer(timer);
  2265. }
  2266. missionBattle = null;
  2267. } else {
  2268. this.errorRequest = true;
  2269. }
  2270. }
  2271. /**
  2272. * Getting mission data for auto-repeat
  2273. * Получение данных миссии для автоповтора
  2274. */
  2275. if (isChecked('repeatMission') &&
  2276. call.name == 'missionEnd') {
  2277. let missionInfo = {
  2278. id: call.args.id,
  2279. result: call.args.result,
  2280. heroes: call.args.progress[0].attackers.heroes,
  2281. count: 0,
  2282. }
  2283. setTimeout(async () => {
  2284. if (!isSendsMission && await popup.confirm(I18N('MSG_REPEAT_MISSION'), [
  2285. { msg: I18N('BTN_REPEAT'), result: true},
  2286. { msg: I18N('BTN_NO'), result: false},
  2287. ])) {
  2288. isStopSendMission = false;
  2289. isSendsMission = true;
  2290. sendsMission(missionInfo);
  2291. }
  2292. }, 0);
  2293. }
  2294. /**
  2295. * Getting mission data
  2296. * Получение данных миссии
  2297. * missionTimer
  2298. */
  2299. if (call.name == 'missionStart') {
  2300. lastMissionStart = call.args;
  2301. lastMissionBattleStart = Date.now();
  2302. }
  2303. /**
  2304. * Specify the quantity for Titan Orbs and Pet Eggs
  2305. * Указать количество для сфер титанов и яиц петов
  2306. */
  2307. if (isChecked('countControl') &&
  2308. (call.name == 'pet_chestOpen' ||
  2309. call.name == 'titanUseSummonCircle') &&
  2310. call.args.amount > 1) {
  2311. const startAmount = call.args.amount;
  2312. call.args.amount = 1;
  2313. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2314. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2315. ]);
  2316. if (result) {
  2317. const item = call.name == 'pet_chestOpen' ? { id: 90, type: 'consumable' } : { id: 13, type: 'coin' };
  2318. cheats.updateInventory({
  2319. [item.type]: {
  2320. [item.id]: -(result - startAmount),
  2321. },
  2322. });
  2323. call.args.amount = result;
  2324. changeRequest = true;
  2325. }
  2326. }
  2327. /**
  2328. * Specify the amount for keys and spheres of titan artifacts
  2329. * Указать колличество для ключей и сфер артефактов титанов
  2330. */
  2331. if (isChecked('countControl') &&
  2332. (call.name == 'artifactChestOpen' ||
  2333. call.name == 'titanArtifactChestOpen') &&
  2334. call.args.amount > 1 &&
  2335. call.args.free &&
  2336. !changeRequest) {
  2337. artifactChestOpenCallName = call.name;
  2338. const startAmount = call.args.amount;
  2339. let result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2340. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount },
  2341. ]);
  2342. if (result) {
  2343. const openChests = result;
  2344. let sphere = result < 10 ? 1 : 10;
  2345. call.args.amount = sphere;
  2346. for (let count = openChests - sphere; count > 0; count -= sphere) {
  2347. if (count < 10) sphere = 1;
  2348. const ident = artifactChestOpenCallName + "_" + count;
  2349. testData.calls.push({
  2350. name: artifactChestOpenCallName,
  2351. args: {
  2352. amount: sphere,
  2353. free: true,
  2354. },
  2355. ident: ident
  2356. });
  2357. if (!Array.isArray(requestHistory[this.uniqid].calls[call.name])) {
  2358. requestHistory[this.uniqid].calls[call.name] = [requestHistory[this.uniqid].calls[call.name]];
  2359. }
  2360. requestHistory[this.uniqid].calls[call.name].push(ident);
  2361. }
  2362.  
  2363. const consumableId = call.name == 'artifactChestOpen' ? 45 : 55;
  2364. cheats.updateInventory({
  2365. consumable: {
  2366. [consumableId]: -(openChests - startAmount),
  2367. },
  2368. });
  2369. artifactChestOpen = true;
  2370. changeRequest = true;
  2371. }
  2372. }
  2373. if (call.name == 'consumableUseLootBox') {
  2374. lastRussianDollId = call.args.libId;
  2375. /**
  2376. * Specify quantity for gold caskets
  2377. * Указать количество для золотых шкатулок
  2378. */
  2379. if (isChecked('countControl') &&
  2380. call.args.libId == 148 &&
  2381. call.args.amount > 1) {
  2382. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2383. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2384. ]);
  2385. call.args.amount = result;
  2386. changeRequest = true;
  2387. }
  2388. if (isChecked('countControl') && call.args.libId >= 362 && call.args.libId <= 389) {
  2389. this.massOpen = call.args.libId;
  2390. }
  2391. }
  2392. /**
  2393. * Changing the maximum number of raids in the campaign
  2394. * Изменение максимального количества рейдов в кампании
  2395. */
  2396. // if (call.name == 'missionRaid') {
  2397. // if (isChecked('countControl') && call.args.times > 1) {
  2398. // const result = +(await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2399. // { msg: I18N('BTN_RUN'), isInput: true, default: call.args.times },
  2400. // ]));
  2401. // call.args.times = result > call.args.times ? call.args.times : result;
  2402. // changeRequest = true;
  2403. // }
  2404. // }
  2405. }
  2406.  
  2407. let headers = requestHistory[this.uniqid].headers;
  2408. if (changeRequest) {
  2409. sourceData = JSON.stringify(testData);
  2410. headers['X-Auth-Signature'] = getSignature(headers, sourceData);
  2411. }
  2412.  
  2413. let signature = headers['X-Auth-Signature'];
  2414. if (signature) {
  2415. original.setRequestHeader.call(this, 'X-Auth-Signature', signature);
  2416. }
  2417. } catch (err) {
  2418. console.log("Request(send, " + this.uniqid + "):\n", sourceData, "Error:\n", err);
  2419. }
  2420. return sourceData;
  2421. }
  2422. /**
  2423. * Processing and substitution of incoming data
  2424. *
  2425. * Обработка и подмена входящих данных
  2426. */
  2427. async function checkChangeResponse(response) {
  2428. try {
  2429. isChange = false;
  2430. let nowTime = Math.round(Date.now() / 1000);
  2431. callsIdent = requestHistory[this.uniqid].calls;
  2432. respond = JSON.parse(response);
  2433. /**
  2434. * If the request returned an error removes the error (removes synchronization errors)
  2435. * Если запрос вернул ошибку удаляет ошибку (убирает ошибки синхронизации)
  2436. */
  2437. if (respond.error) {
  2438. isChange = true;
  2439. console.error(respond.error);
  2440. if (isChecked('showErrors')) {
  2441. popup.confirm(I18N('ERROR_MSG', {
  2442. name: respond.error.name,
  2443. description: respond.error.description,
  2444. }));
  2445. }
  2446. if (respond.error.name != 'AccountBan') {
  2447. delete respond.error;
  2448. respond.results = [];
  2449. }
  2450. }
  2451. let mainReward = null;
  2452. const allReward = {};
  2453. let countTypeReward = 0;
  2454. let readQuestInfo = false;
  2455. for (const call of respond.results) {
  2456. /**
  2457. * Obtaining initial data for completing quests
  2458. * Получение исходных данных для выполнения квестов
  2459. */
  2460. if (readQuestInfo) {
  2461. questsInfo[call.ident] = call.result.response;
  2462. }
  2463. /**
  2464. * Getting a user ID
  2465. * Получение идетификатора пользователя
  2466. */
  2467. if (call.ident == callsIdent['registration']) {
  2468. userId = call.result.response.userId;
  2469. if (localStorage['userId'] != userId) {
  2470. localStorage['newGiftSendIds'] = '';
  2471. localStorage['userId'] = userId;
  2472. }
  2473. await openOrMigrateDatabase(userId);
  2474. readQuestInfo = true;
  2475. }
  2476. /**
  2477. * Hiding donation offers 1
  2478. * Скрываем предложения доната 1
  2479. */
  2480. if (call.ident == callsIdent['billingGetAll'] && getSaveVal('noOfferDonat')) {
  2481. const billings = call.result.response?.billings;
  2482. const bundle = call.result.response?.bundle;
  2483. if (billings && bundle) {
  2484. call.result.response.billings = [];
  2485. call.result.response.bundle = [];
  2486. isChange = true;
  2487. }
  2488. }
  2489. /**
  2490. * Hiding donation offers 2
  2491. * Скрываем предложения доната 2
  2492. */
  2493. if (getSaveVal('noOfferDonat') &&
  2494. (call.ident == callsIdent['offerGetAll'] ||
  2495. call.ident == callsIdent['specialOffer_getAll'])) {
  2496. let offers = call.result.response;
  2497. if (offers) {
  2498. call.result.response = offers.filter(e => !['addBilling', 'bundleCarousel'].includes(e.type) || ['idleResource'].includes(e.offerType));
  2499. isChange = true;
  2500. }
  2501. }
  2502. /**
  2503. * Hiding donation offers 3
  2504. * Скрываем предложения доната 3
  2505. */
  2506. if (getSaveVal('noOfferDonat') && call.result?.bundleUpdate) {
  2507. delete call.result.bundleUpdate;
  2508. isChange = true;
  2509. }
  2510. /**
  2511. * Copies a quiz question to the clipboard
  2512. * Копирует вопрос викторины в буфер обмена и получает на него ответ если есть
  2513. */
  2514. if (call.ident == callsIdent['quizGetNewQuestion']) {
  2515. let quest = call.result.response;
  2516. console.log(quest.question);
  2517. copyText(quest.question);
  2518. setProgress(I18N('QUESTION_COPY'), true);
  2519. quest.lang = null;
  2520. if (typeof NXFlashVars !== 'undefined') {
  2521. quest.lang = NXFlashVars.interface_lang;
  2522. }
  2523. lastQuestion = quest;
  2524. if (isChecked('getAnswer')) {
  2525. const answer = await getAnswer(lastQuestion);
  2526. let showText = '';
  2527. if (answer) {
  2528. lastAnswer = answer;
  2529. console.log(answer);
  2530. showText = `${I18N('ANSWER_KNOWN')}: ${answer}`;
  2531. } else {
  2532. showText = I18N('ANSWER_NOT_KNOWN');
  2533. }
  2534.  
  2535. try {
  2536. const hint = hintQuest(quest);
  2537. if (hint) {
  2538. showText += I18N('HINT') + hint;
  2539. }
  2540. } catch(e) {}
  2541.  
  2542. setProgress(showText, true);
  2543. }
  2544. }
  2545. /**
  2546. * Submits a question with an answer to the database
  2547. * Отправляет вопрос с ответом в базу данных
  2548. */
  2549. if (call.ident == callsIdent['quizAnswer']) {
  2550. const answer = call.result.response;
  2551. if (lastQuestion) {
  2552. const answerInfo = {
  2553. answer,
  2554. question: lastQuestion,
  2555. lang: null,
  2556. }
  2557. if (typeof NXFlashVars !== 'undefined') {
  2558. answerInfo.lang = NXFlashVars.interface_lang;
  2559. }
  2560. lastQuestion = null;
  2561. setTimeout(sendAnswerInfo, 0, answerInfo);
  2562. }
  2563. }
  2564. /**
  2565. * Get user data
  2566. * Получить даныне пользователя
  2567. */
  2568. if (call.ident == callsIdent['userGetInfo']) {
  2569. let user = call.result.response;
  2570. document.title = user.name;
  2571. userInfo = Object.assign({}, user);
  2572. delete userInfo.refillable;
  2573. if (!questsInfo['userGetInfo']) {
  2574. questsInfo['userGetInfo'] = user;
  2575. }
  2576. }
  2577. /**
  2578. * Start of the battle for recalculation
  2579. * Начало боя для прерасчета
  2580. */
  2581. if (call.ident == callsIdent['clanWarAttack'] ||
  2582. call.ident == callsIdent['crossClanWar_startBattle'] ||
  2583. call.ident == callsIdent['bossAttack'] ||
  2584. call.ident == callsIdent['battleGetReplay'] ||
  2585. call.ident == callsIdent['brawl_startBattle'] ||
  2586. call.ident == callsIdent['adventureSolo_turnStartBattle'] ||
  2587. call.ident == callsIdent['invasion_bossStart'] ||
  2588. call.ident == callsIdent['titanArenaStartBattle'] ||
  2589. call.ident == callsIdent['towerStartBattle'] ||
  2590. call.ident == callsIdent['adventure_turnStartBattle']) {
  2591. let battle = call.result.response.battle || call.result.response.replay;
  2592. if (call.ident == callsIdent['brawl_startBattle'] ||
  2593. call.ident == callsIdent['bossAttack'] ||
  2594. call.ident == callsIdent['towerStartBattle'] ||
  2595. call.ident == callsIdent['invasion_bossStart']) {
  2596. battle = call.result.response;
  2597. }
  2598. lastBattleInfo = battle;
  2599. if (!isChecked('preCalcBattle')) {
  2600. continue;
  2601. }
  2602. setProgress(I18N('BEING_RECALC'));
  2603. let battleDuration = 120;
  2604. try {
  2605. const typeBattle = getBattleType(battle.type);
  2606. battleDuration = +lib.data.battleConfig[typeBattle.split('_')[1]].config.battleDuration;
  2607. } catch (e) { }
  2608. //console.log(battle.type);
  2609. function getBattleInfo(battle, isRandSeed) {
  2610. return new Promise(function (resolve) {
  2611. if (isRandSeed) {
  2612. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  2613. }
  2614. BattleCalc(battle, getBattleType(battle.type), e => resolve(e));
  2615. });
  2616. }
  2617. let actions = [getBattleInfo(battle, false)]
  2618. const countTestBattle = getInput('countTestBattle');
  2619. if (call.ident == callsIdent['battleGetReplay']) {
  2620. battle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2621. }
  2622. for (let i = 0; i < countTestBattle; i++) {
  2623. actions.push(getBattleInfo(battle, true));
  2624. }
  2625. Promise.all(actions)
  2626. .then(e => {
  2627. e = e.map(n => ({win: n.result.win, time: n.battleTime}));
  2628. let firstBattle = e.shift();
  2629. const timer = Math.floor(battleDuration - firstBattle.time);
  2630. const min = ('00' + Math.floor(timer / 60)).slice(-2);
  2631. const sec = ('00' + Math.floor(timer - min * 60)).slice(-2);
  2632. const countWin = e.reduce((w, s) => w + s.win, 0);
  2633. setProgress(`${I18N('THIS_TIME')} ${(firstBattle.win ? I18N('VICTORY') : I18N('DEFEAT'))} ${I18N('CHANCE_TO_WIN')}: ${Math.floor(countWin / e.length * 100)}% (${e.length}), ${min}:${sec}`, false, hideProgress)
  2634. });
  2635. }
  2636. /**
  2637. * Start of the Asgard boss fight
  2638. * Начало боя с боссом Асгарда
  2639. */
  2640. if (call.ident == callsIdent['clanRaid_startBossBattle']) {
  2641. lastBossBattle = call.result.response.battle;
  2642. lastBossBattle.endTime = Date.now() + 160 * 1000;
  2643. if (isChecked('preCalcBattle')) {
  2644. const result = await Calc(lastBossBattle).then(e => e.progress[0].defenders.heroes[1].extra);
  2645. const bossDamage = result.damageTaken + result.damageTakenNextLevel;
  2646. setProgress(I18N('BOSS_DAMAGE') + bossDamage.toLocaleString(), false, hideProgress);
  2647. }
  2648. }
  2649. /**
  2650. * Cancel tutorial
  2651. * Отмена туториала
  2652. */
  2653. if (isCanceledTutorial && call.ident == callsIdent['tutorialGetInfo']) {
  2654. let chains = call.result.response.chains;
  2655. for (let n in chains) {
  2656. chains[n] = 9999;
  2657. }
  2658. isChange = true;
  2659. }
  2660. /**
  2661. * Opening keys and spheres of titan artifacts
  2662. * Открытие ключей и сфер артефактов титанов
  2663. */
  2664. if (artifactChestOpen &&
  2665. (call.ident == callsIdent[artifactChestOpenCallName] ||
  2666. (callsIdent[artifactChestOpenCallName] && callsIdent[artifactChestOpenCallName].includes(call.ident)))) {
  2667. let reward = call.result.response[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'];
  2668.  
  2669. reward.forEach(e => {
  2670. for (let f in e) {
  2671. if (!allReward[f]) {
  2672. allReward[f] = {};
  2673. }
  2674. for (let o in e[f]) {
  2675. if (!allReward[f][o]) {
  2676. allReward[f][o] = e[f][o];
  2677. countTypeReward++;
  2678. } else {
  2679. allReward[f][o] += e[f][o];
  2680. }
  2681. }
  2682. }
  2683. });
  2684.  
  2685. if (!call.ident.includes(artifactChestOpenCallName)) {
  2686. mainReward = call.result.response;
  2687. }
  2688. }
  2689.  
  2690. if (countTypeReward > 20) {
  2691. correctShowOpenArtifact = 3;
  2692. } else {
  2693. correctShowOpenArtifact = 0;
  2694. }
  2695. /**
  2696. * Sum the result of opening Pet Eggs
  2697. * Суммирование результата открытия яиц питомцев
  2698. */
  2699. if (isChecked('countControl') && call.ident == callsIdent['pet_chestOpen']) {
  2700. const rewards = call.result.response.rewards;
  2701. if (rewards.length > 10) {
  2702. /**
  2703. * Removing pet cards
  2704. * Убираем карточки петов
  2705. */
  2706. for (const reward of rewards) {
  2707. if (reward.petCard) {
  2708. delete reward.petCard;
  2709. }
  2710. }
  2711. }
  2712. rewards.forEach(e => {
  2713. for (let f in e) {
  2714. if (!allReward[f]) {
  2715. allReward[f] = {};
  2716. }
  2717. for (let o in e[f]) {
  2718. if (!allReward[f][o]) {
  2719. allReward[f][o] = e[f][o];
  2720. } else {
  2721. allReward[f][o] += e[f][o];
  2722. }
  2723. }
  2724. }
  2725. });
  2726. call.result.response.rewards = [allReward];
  2727. isChange = true;
  2728. }
  2729. /**
  2730. * Removing titan cards
  2731. * Убираем карточки титанов
  2732. */
  2733. if (call.ident == callsIdent['titanUseSummonCircle']) {
  2734. if (call.result.response.rewards.length > 10) {
  2735. for (const reward of call.result.response.rewards) {
  2736. if (reward.titanCard) {
  2737. delete reward.titanCard;
  2738. }
  2739. }
  2740. isChange = true;
  2741. }
  2742. }
  2743. /**
  2744. * Auto-repeat opening matryoshkas
  2745. * АвтоПовтор открытия матрешек
  2746. */
  2747. if (isChecked('countControl') && call.ident == callsIdent['consumableUseLootBox']) {
  2748. let lootBox = call.result.response;
  2749. let newCount = 0;
  2750. for (let n of lootBox) {
  2751. if (n?.consumable && n.consumable[lastRussianDollId]) {
  2752. newCount += n.consumable[lastRussianDollId]
  2753. }
  2754. }
  2755. if (
  2756. newCount &&
  2757. (await popup.confirm(`${I18N('BTN_OPEN')} ${newCount} ${I18N('OPEN_DOLLS')}?`, [
  2758. { msg: I18N('BTN_OPEN'), result: true },
  2759. { msg: I18N('BTN_NO'), result: false, isClose: true },
  2760. ]))
  2761. ) {
  2762. const recursionResult = await openRussianDolls(lastRussianDollId, newCount);
  2763. lootBox = [...lootBox, ...recursionResult];
  2764. }
  2765.  
  2766. if (this.massOpen) {
  2767. if (
  2768. await popup.confirm(I18N('OPEN_ALL_EQUIP_BOXES'), [
  2769. { msg: I18N('BTN_OPEN'), result: true },
  2770. { msg: I18N('BTN_NO'), result: false, isClose: true },
  2771. ])
  2772. ) {
  2773. const consumable = await Send({ calls: [{ name: 'inventoryGet', args: {}, ident: 'inventoryGet' }] }).then((e) =>
  2774. Object.entries(e.results[0].result.response.consumable)
  2775. );
  2776. const calls = [];
  2777. const deleteItems = {};
  2778. for (const [libId, amount] of consumable) {
  2779. if (libId != this.massOpen && libId >= 362 && libId <= 389) {
  2780. calls.push({
  2781. name: 'consumableUseLootBox',
  2782. args: { libId, amount },
  2783. ident: 'consumableUseLootBox_' + libId,
  2784. });
  2785. deleteItems[libId] = -amount;
  2786. }
  2787. }
  2788. const result = await Send({ calls }).then((e) => e.results.map((r) => r.result.response).flat());
  2789. lootBox = [...lootBox, ...result];
  2790. this.onReadySuccess = () => {
  2791. cheats.updateInventory({ consumable: deleteItems });
  2792. cheats.refreshInventory();
  2793. };
  2794. }
  2795. }
  2796.  
  2797. /** Объединение результата лутбоксов */
  2798. const allLootBox = {};
  2799. lootBox.forEach(e => {
  2800. for (let f in e) {
  2801. if (!allLootBox[f]) {
  2802. if (typeof e[f] == 'object') {
  2803. allLootBox[f] = {};
  2804. } else {
  2805. allLootBox[f] = 0;
  2806. }
  2807. }
  2808. if (typeof e[f] == 'object') {
  2809. for (let o in e[f]) {
  2810. if (newCount && o == lastRussianDollId) {
  2811. continue;
  2812. }
  2813. if (!allLootBox[f][o]) {
  2814. allLootBox[f][o] = e[f][o];
  2815. } else {
  2816. allLootBox[f][o] += e[f][o];
  2817. }
  2818. }
  2819. } else {
  2820. allLootBox[f] += e[f];
  2821. }
  2822. }
  2823. });
  2824. /** Разбитие результата */
  2825. const output = [];
  2826. const maxCount = 5;
  2827. let currentObj = {};
  2828. let count = 0;
  2829. for (let f in allLootBox) {
  2830. if (!currentObj[f]) {
  2831. if (typeof allLootBox[f] == 'object') {
  2832. for (let o in allLootBox[f]) {
  2833. currentObj[f] ||= {}
  2834. if (!currentObj[f][o]) {
  2835. currentObj[f][o] = allLootBox[f][o];
  2836. count++;
  2837. if (count === maxCount) {
  2838. output.push(currentObj);
  2839. currentObj = {};
  2840. count = 0;
  2841. }
  2842. }
  2843. }
  2844. } else {
  2845. currentObj[f] = allLootBox[f];
  2846. count++;
  2847. if (count === maxCount) {
  2848. output.push(currentObj);
  2849. currentObj = {};
  2850. count = 0;
  2851. }
  2852. }
  2853. }
  2854. }
  2855. if (count > 0) {
  2856. output.push(currentObj);
  2857. }
  2858.  
  2859. console.log(output);
  2860. call.result.response = output;
  2861. isChange = true;
  2862. }
  2863. /**
  2864. * Dungeon recalculation (fix endless cards)
  2865. * Прерасчет подземки (исправление бесконечных карт)
  2866. */
  2867. if (call.ident == callsIdent['dungeonStartBattle']) {
  2868. lastDungeonBattleData = call.result.response;
  2869. lastDungeonBattleStart = Date.now();
  2870. }
  2871. /**
  2872. * Getting the number of prediction cards
  2873. * Получение количества карт предсказаний
  2874. */
  2875. if (call.ident == callsIdent['inventoryGet']) {
  2876. countPredictionCard = call.result.response.consumable[81] || 0;
  2877. }
  2878. /**
  2879. * Getting subscription status
  2880. * Получение состояния подписки
  2881. */
  2882. if (call.ident == callsIdent['subscriptionGetInfo']) {
  2883. const subscription = call.result.response.subscription;
  2884. if (subscription) {
  2885. subEndTime = subscription.endTime * 1000;
  2886. }
  2887. }
  2888. /**
  2889. * Getting prediction cards
  2890. * Получение карт предсказаний
  2891. */
  2892. if (call.ident == callsIdent['questFarm']) {
  2893. const consumable = call.result.response?.consumable;
  2894. if (consumable && consumable[81]) {
  2895. countPredictionCard += consumable[81];
  2896. console.log(`Cards: ${countPredictionCard}`);
  2897. }
  2898. }
  2899. /**
  2900. * Hiding extra servers
  2901. * Скрытие лишних серверов
  2902. */
  2903. if (call.ident == callsIdent['serverGetAll'] && isChecked('hideServers')) {
  2904. let servers = call.result.response.users.map(s => s.serverId)
  2905. call.result.response.servers = call.result.response.servers.filter(s => servers.includes(s.id));
  2906. isChange = true;
  2907. }
  2908. /**
  2909. * Displays player positions in the adventure
  2910. * Отображает позиции игроков в приключении
  2911. */
  2912. if (call.ident == callsIdent['adventure_getLobbyInfo']) {
  2913. const users = Object.values(call.result.response.users);
  2914. const mapIdent = call.result.response.mapIdent;
  2915. const adventureId = call.result.response.adventureId;
  2916. const maps = {
  2917. adv_strongford_3pl_hell: 9,
  2918. adv_valley_3pl_hell: 10,
  2919. adv_ghirwil_3pl_hell: 11,
  2920. adv_angels_3pl_hell: 12,
  2921. }
  2922. let msg = I18N('MAP') + (mapIdent in maps ? maps[mapIdent] : adventureId);
  2923. msg += '<br>' + I18N('PLAYER_POS');
  2924. for (const user of users) {
  2925. msg += `<br>${user.user.name} - ${user.currentNode}`;
  2926. }
  2927. setProgress(msg, false, hideProgress);
  2928. }
  2929. /**
  2930. * Automatic launch of a raid at the end of the adventure
  2931. * Автоматический запуск рейда при окончании приключения
  2932. */
  2933. if (call.ident == callsIdent['adventure_end']) {
  2934. autoRaidAdventure()
  2935. }
  2936. /** Удаление лавки редкостей */
  2937. if (call.ident == callsIdent['missionRaid']) {
  2938. if (call.result?.heroesMerchant) {
  2939. delete call.result.heroesMerchant;
  2940. isChange = true;
  2941. }
  2942. }
  2943. /** missionTimer */
  2944. if (call.ident == callsIdent['missionStart']) {
  2945. missionBattle = call.result.response;
  2946. }
  2947. /** Награды турнира стихий */
  2948. if (call.ident == callsIdent['hallOfFameGetTrophies']) {
  2949. const trophys = call.result.response;
  2950. const calls = [];
  2951. for (const week in trophys) {
  2952. const trophy = trophys[week];
  2953. if (!trophy.championRewardFarmed) {
  2954. calls.push({
  2955. name: 'hallOfFameFarmTrophyReward',
  2956. args: { trophyId: week, rewardType: 'champion' },
  2957. ident: 'body_champion_' + week,
  2958. });
  2959. }
  2960. if (Object.keys(trophy.clanReward).length && !trophy.clanRewardFarmed) {
  2961. calls.push({
  2962. name: 'hallOfFameFarmTrophyReward',
  2963. args: { trophyId: week, rewardType: 'clan' },
  2964. ident: 'body_clan_' + week,
  2965. });
  2966. }
  2967. }
  2968. if (calls.length) {
  2969. Send({ calls })
  2970. .then((e) => e.results.map((e) => e.result.response))
  2971. .then(async results => {
  2972. let coin18 = 0,
  2973. coin19 = 0,
  2974. gold = 0,
  2975. starmoney = 0;
  2976. for (const r of results) {
  2977. coin18 += r?.coin ? +r.coin[18] : 0;
  2978. coin19 += r?.coin ? +r.coin[19] : 0;
  2979. gold += r?.gold ? +r.gold : 0;
  2980. starmoney += r?.starmoney ? +r.starmoney : 0;
  2981. }
  2982.  
  2983. let msg = I18N('ELEMENT_TOURNAMENT_REWARD') + '<br>';
  2984. if (coin18) {
  2985. msg += cheats.translate('LIB_COIN_NAME_18') + `: ${coin18}<br>`;
  2986. }
  2987. if (coin19) {
  2988. msg += cheats.translate('LIB_COIN_NAME_19') + `: ${coin19}<br>`;
  2989. }
  2990. if (gold) {
  2991. msg += cheats.translate('LIB_PSEUDO_COIN') + `: ${gold}<br>`;
  2992. }
  2993. if (starmoney) {
  2994. msg += cheats.translate('LIB_PSEUDO_STARMONEY') + `: ${starmoney}<br>`;
  2995. }
  2996.  
  2997. await popup.confirm(msg, [{ msg: I18N('BTN_OK'), result: 0 }]);
  2998. });
  2999. }
  3000. }
  3001. if (call.ident == callsIdent['clanDomination_getInfo']) {
  3002. clanDominationGetInfo = call.result.response;
  3003. }
  3004. if (call.ident == callsIdent['clanRaid_endBossBattle']) {
  3005. console.log(call.result.response);
  3006. const damage = Object.values(call.result.response.damage).reduce((a, e) => a + e);
  3007. if (call.result.response.result.afterInvalid) {
  3008. addProgress('<br>' + I18N('SERVER_NOT_ACCEPT'));
  3009. }
  3010. addProgress('<br>Server > ' + I18N('BOSS_DAMAGE') + damage.toLocaleString());
  3011. }
  3012. /*
  3013. if (call.ident == callsIdent['chatGetAll'] && call.args.chatType == 'clanDomination' && !callsIdent['clanDomination_mapState']) {
  3014. this.onReadySuccess = async function () {
  3015. const result = await Send({
  3016. calls: [
  3017. {
  3018. name: 'clanDomination_mapState',
  3019. args: {},
  3020. ident: 'clanDomination_mapState',
  3021. },
  3022. ],
  3023. }).then((e) => e.results[0].result.response);
  3024. let townPositions = result.townPositions;
  3025. let positions = {};
  3026. for (let pos in townPositions) {
  3027. let townPosition = townPositions[pos];
  3028. positions[townPosition.position] = townPosition;
  3029. }
  3030. Object.assign(clanDominationGetInfo, {
  3031. townPositions: positions,
  3032. });
  3033. let userPositions = result.userPositions;
  3034. for (let pos in clanDominationGetInfo.townPositions) {
  3035. let townPosition = clanDominationGetInfo.townPositions[pos];
  3036. if (townPosition.status) {
  3037. userPositions[townPosition.userId] = +pos;
  3038. }
  3039. }
  3040. cheats.updateMap(result);
  3041. };
  3042. }
  3043. if (call.ident == callsIdent['clanDomination_mapState']) {
  3044. const townPositions = call.result.response.townPositions;
  3045. const userPositions = call.result.response.userPositions;
  3046. for (let pos in townPositions) {
  3047. let townPos = townPositions[pos];
  3048. if (townPos.status) {
  3049. userPositions[townPos.userId] = townPos.position;
  3050. }
  3051. }
  3052. isChange = true;
  3053. }
  3054. */
  3055. }
  3056.  
  3057. if (mainReward && artifactChestOpen) {
  3058. console.log(allReward);
  3059. mainReward[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'] = [allReward];
  3060. artifactChestOpen = false;
  3061. artifactChestOpenCallName = '';
  3062. isChange = true;
  3063. }
  3064. } catch(err) {
  3065. console.log("Request(response, " + this.uniqid + "):\n", "Error:\n", response, err);
  3066. }
  3067.  
  3068. if (isChange) {
  3069. Object.defineProperty(this, 'responseText', {
  3070. writable: true
  3071. });
  3072. this.responseText = JSON.stringify(respond);
  3073. }
  3074. }
  3075.  
  3076. /**
  3077. * Request an answer to a question
  3078. *
  3079. * Запрос ответа на вопрос
  3080. */
  3081. async function getAnswer(question) {
  3082. // c29tZSBzdHJhbmdlIHN5bWJvbHM=
  3083. const quizAPI = new ZingerYWebsiteAPI('getAnswer.php', arguments, { question });
  3084. return new Promise((resolve, reject) => {
  3085. quizAPI.request().then((data) => {
  3086. if (data.result) {
  3087. resolve(data.result);
  3088. } else {
  3089. resolve(false);
  3090. }
  3091. }).catch((error) => {
  3092. console.error(error);
  3093. resolve(false);
  3094. });
  3095. })
  3096. }
  3097.  
  3098. /**
  3099. * Submitting a question and answer to a database
  3100. *
  3101. * Отправка вопроса и ответа в базу данных
  3102. */
  3103. function sendAnswerInfo(answerInfo) {
  3104. // c29tZSBub25zZW5zZQ==
  3105. const quizAPI = new ZingerYWebsiteAPI('setAnswer.php', arguments, { answerInfo });
  3106. quizAPI.request().then((data) => {
  3107. if (data.result) {
  3108. console.log(I18N('SENT_QUESTION'));
  3109. }
  3110. });
  3111. }
  3112.  
  3113. /**
  3114. * Returns the battle type by preset type
  3115. *
  3116. * Возвращает тип боя по типу пресета
  3117. */
  3118. function getBattleType(strBattleType) {
  3119. if (!strBattleType) {
  3120. return null;
  3121. }
  3122. switch (strBattleType) {
  3123. case 'titan_pvp':
  3124. return 'get_titanPvp';
  3125. case 'titan_pvp_manual':
  3126. case 'titan_clan_pvp':
  3127. case 'clan_pvp_titan':
  3128. case 'clan_global_pvp_titan':
  3129. case 'brawl_titan':
  3130. case 'challenge_titan':
  3131. case 'titan_mission':
  3132. return 'get_titanPvpManual';
  3133. case 'clan_raid': // Asgard Boss // Босс асгарда
  3134. case 'adventure': // Adventures // Приключения
  3135. case 'clan_global_pvp':
  3136. case 'epic_brawl':
  3137. case 'clan_pvp':
  3138. return 'get_clanPvp';
  3139. case 'dungeon_titan':
  3140. case 'titan_tower':
  3141. return 'get_titan';
  3142. case 'tower':
  3143. return 'get_tower';
  3144. case 'clan_dungeon':
  3145. case 'pve':
  3146. case 'mission':
  3147. return 'get_pve';
  3148. case 'mission_boss':
  3149. return 'get_missionBoss';
  3150. case 'challenge':
  3151. case 'pvp_manual':
  3152. return 'get_pvpManual';
  3153. case 'grand':
  3154. case 'arena':
  3155. case 'pvp':
  3156. case 'clan_domination':
  3157. return 'get_pvp';
  3158. case 'core':
  3159. return 'get_core';
  3160. default: {
  3161. if (strBattleType.includes('invasion')) {
  3162. return 'get_invasion';
  3163. }
  3164. if (strBattleType.includes('boss')) {
  3165. return 'get_boss';
  3166. }
  3167. if (strBattleType.includes('titan_arena')) {
  3168. return 'get_titanPvpManual';
  3169. }
  3170. return 'get_clanPvp';
  3171. }
  3172. }
  3173. }
  3174. /**
  3175. * Returns the class name of the passed object
  3176. *
  3177. * Возвращает название класса переданного объекта
  3178. */
  3179. function getClass(obj) {
  3180. return {}.toString.call(obj).slice(8, -1);
  3181. }
  3182. /**
  3183. * Calculates the request signature
  3184. *
  3185. * Расчитывает сигнатуру запроса
  3186. */
  3187. this.getSignature = function(headers, data) {
  3188. const sign = {
  3189. signature: '',
  3190. length: 0,
  3191. add: function (text) {
  3192. this.signature += text;
  3193. if (this.length < this.signature.length) {
  3194. this.length = 3 * (this.signature.length + 1) >> 1;
  3195. }
  3196. },
  3197. }
  3198. sign.add(headers["X-Request-Id"]);
  3199. sign.add(':');
  3200. sign.add(headers["X-Auth-Token"]);
  3201. sign.add(':');
  3202. sign.add(headers["X-Auth-Session-Id"]);
  3203. sign.add(':');
  3204. sign.add(data);
  3205. sign.add(':');
  3206. sign.add('LIBRARY-VERSION=1');
  3207. sign.add('UNIQUE-SESSION-ID=' + headers["X-Env-Unique-Session-Id"]);
  3208.  
  3209. return md5(sign.signature);
  3210. }
  3211. /**
  3212. * Creates an interface
  3213. *
  3214. * Создает интерфейс
  3215. */
  3216. function createInterface() {
  3217. popup.init();
  3218. scriptMenu.init({
  3219. showMenu: true
  3220. });
  3221. scriptMenu.addHeader(GM_info.script.name, justInfo);
  3222. scriptMenu.addHeader('v' + GM_info.script.version);
  3223. }
  3224.  
  3225. function addControls() {
  3226. createInterface();
  3227. const checkboxDetails = scriptMenu.addDetails(I18N('SETTINGS'));
  3228. for (let name in checkboxes) {
  3229. if (checkboxes[name].hide) {
  3230. continue;
  3231. }
  3232. checkboxes[name].cbox = scriptMenu.addCheckbox(checkboxes[name].label, checkboxes[name].title, checkboxDetails);
  3233. /**
  3234. * Getting the state of checkboxes from storage
  3235. * Получаем состояние чекбоксов из storage
  3236. */
  3237. let val = storage.get(name, null);
  3238. if (val != null) {
  3239. checkboxes[name].cbox.checked = val;
  3240. } else {
  3241. storage.set(name, checkboxes[name].default);
  3242. checkboxes[name].cbox.checked = checkboxes[name].default;
  3243. }
  3244. /**
  3245. * Tracing the change event of the checkbox for writing to storage
  3246. * Отсеживание события изменения чекбокса для записи в storage
  3247. */
  3248. checkboxes[name].cbox.dataset['name'] = name;
  3249. checkboxes[name].cbox.addEventListener('change', async function (event) {
  3250. const nameCheckbox = this.dataset['name'];
  3251. /*
  3252. if (this.checked && nameCheckbox == 'cancelBattle') {
  3253. this.checked = false;
  3254. if (await popup.confirm(I18N('MSG_BAN_ATTENTION'), [
  3255. { msg: I18N('BTN_NO_I_AM_AGAINST'), result: true },
  3256. { msg: I18N('BTN_YES_I_AGREE'), result: false },
  3257. ])) {
  3258. return;
  3259. }
  3260. this.checked = true;
  3261. }
  3262. */
  3263. storage.set(nameCheckbox, this.checked);
  3264. })
  3265. }
  3266.  
  3267. const inputDetails = scriptMenu.addDetails(I18N('VALUES'));
  3268. for (let name in inputs) {
  3269. inputs[name].input = scriptMenu.addInputText(inputs[name].title, false, inputDetails);
  3270. /**
  3271. * Get inputText state from storage
  3272. * Получаем состояние inputText из storage
  3273. */
  3274. let val = storage.get(name, null);
  3275. if (val != null) {
  3276. inputs[name].input.value = val;
  3277. } else {
  3278. storage.set(name, inputs[name].default);
  3279. inputs[name].input.value = inputs[name].default;
  3280. }
  3281. /**
  3282. * Tracing a field change event for a record in storage
  3283. * Отсеживание события изменения поля для записи в storage
  3284. */
  3285. inputs[name].input.dataset['name'] = name;
  3286. inputs[name].input.addEventListener('input', function () {
  3287. const inputName = this.dataset['name'];
  3288. let value = +this.value;
  3289. if (!value || Number.isNaN(value)) {
  3290. value = storage.get(inputName, inputs[inputName].default);
  3291. inputs[name].input.value = value;
  3292. }
  3293. storage.set(inputName, value);
  3294. })
  3295. }
  3296. }
  3297.  
  3298. /**
  3299. * Sending a request
  3300. *
  3301. * Отправка запроса
  3302. */
  3303. function send(json, callback, pr) {
  3304. if (typeof json == 'string') {
  3305. json = JSON.parse(json);
  3306. }
  3307. for (const call of json.calls) {
  3308. if (!call?.context?.actionTs) {
  3309. call.context = {
  3310. actionTs: Math.floor(performance.now())
  3311. }
  3312. }
  3313. }
  3314. json = JSON.stringify(json);
  3315. /**
  3316. * We get the headlines of the previous intercepted request
  3317. * Получаем заголовки предыдущего перехваченого запроса
  3318. */
  3319. let headers = lastHeaders;
  3320. /**
  3321. * We increase the header of the query Certifier by 1
  3322. * Увеличиваем заголовок идетификатора запроса на 1
  3323. */
  3324. headers["X-Request-Id"]++;
  3325. /**
  3326. * We calculate the title with the signature
  3327. * Расчитываем заголовок с сигнатурой
  3328. */
  3329. headers["X-Auth-Signature"] = getSignature(headers, json);
  3330. /**
  3331. * Create a new ajax request
  3332. * Создаем новый AJAX запрос
  3333. */
  3334. let xhr = new XMLHttpRequest;
  3335. /**
  3336. * Indicate the previously saved URL for API queries
  3337. * Указываем ранее сохраненный URL для API запросов
  3338. */
  3339. xhr.open('POST', apiUrl, true);
  3340. /**
  3341. * Add the function to the event change event
  3342. * Добавляем функцию к событию смены статуса запроса
  3343. */
  3344. xhr.onreadystatechange = function() {
  3345. /**
  3346. * If the result of the request is obtained, we call the flask function
  3347. * Если результат запроса получен вызываем колбек функцию
  3348. */
  3349. if(xhr.readyState == 4) {
  3350. callback(xhr.response, pr);
  3351. }
  3352. };
  3353. /**
  3354. * Indicate the type of request
  3355. * Указываем тип запроса
  3356. */
  3357. xhr.responseType = 'json';
  3358. /**
  3359. * We set the request headers
  3360. * Задаем заголовки запроса
  3361. */
  3362. for(let nameHeader in headers) {
  3363. let head = headers[nameHeader];
  3364. xhr.setRequestHeader(nameHeader, head);
  3365. }
  3366. /**
  3367. * Sending a request
  3368. * Отправляем запрос
  3369. */
  3370. xhr.send(json);
  3371. }
  3372.  
  3373. let hideTimeoutProgress = 0;
  3374. /**
  3375. * Hide progress
  3376. *
  3377. * Скрыть прогресс
  3378. */
  3379. function hideProgress(timeout) {
  3380. timeout = timeout || 0;
  3381. clearTimeout(hideTimeoutProgress);
  3382. hideTimeoutProgress = setTimeout(function () {
  3383. scriptMenu.setStatus('');
  3384. }, timeout);
  3385. }
  3386. /**
  3387. * Progress display
  3388. *
  3389. * Отображение прогресса
  3390. */
  3391. function setProgress(text, hide, onclick) {
  3392. scriptMenu.setStatus(text, onclick);
  3393. hide = hide || false;
  3394. if (hide) {
  3395. hideProgress(3000);
  3396. }
  3397. }
  3398.  
  3399. /**
  3400. * Progress added
  3401. *
  3402. * Дополнение прогресса
  3403. */
  3404. function addProgress(text) {
  3405. scriptMenu.addStatus(text);
  3406. }
  3407.  
  3408. /**
  3409. * Returns the timer value depending on the subscription
  3410. *
  3411. * Возвращает значение таймера в зависимости от подписки
  3412. */
  3413. function getTimer(time, div) {
  3414. let speedDiv = 5;
  3415. if (subEndTime < Date.now()) {
  3416. speedDiv = div || 1.5;
  3417. }
  3418. return Math.max(Math.ceil(time / speedDiv + 1.5), 4);
  3419. }
  3420.  
  3421. function startSlave() {
  3422. const sFix = new slaveFixBattle();
  3423. sFix.wsStart();
  3424. }
  3425.  
  3426. this.testFuntions = {
  3427. hideProgress,
  3428. setProgress,
  3429. addProgress,
  3430. masterFix: false,
  3431. startSlave,
  3432. };
  3433.  
  3434. /**
  3435. * Calculates HASH MD5 from string
  3436. *
  3437. * Расчитывает HASH MD5 из строки
  3438. *
  3439. * [js-md5]{@link https://github.com/emn178/js-md5}
  3440. *
  3441. * @namespace md5
  3442. * @version 0.7.3
  3443. * @author Chen, Yi-Cyuan [emn178@gmail.com]
  3444. * @copyright Chen, Yi-Cyuan 2014-2017
  3445. * @license MIT
  3446. */
  3447. !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 _}))}();
  3448.  
  3449. /**
  3450. * Script for beautiful dialog boxes
  3451. *
  3452. * Скрипт для красивых диалоговых окошек
  3453. */
  3454. const popup = new (function () {
  3455. this.popUp,
  3456. this.downer,
  3457. this.middle,
  3458. this.msgText,
  3459. this.buttons = [];
  3460. this.checkboxes = [];
  3461. this.dialogPromice = null;
  3462. this.isInit = false;
  3463.  
  3464. this.init = function () {
  3465. if (this.isInit) {
  3466. return;
  3467. }
  3468. addStyle();
  3469. addBlocks();
  3470. addEventListeners();
  3471. this.isInit = true;
  3472. }
  3473.  
  3474. const addEventListeners = () => {
  3475. document.addEventListener('keyup', (e) => {
  3476. if (e.key == 'Escape') {
  3477. if (this.dialogPromice) {
  3478. const { func, result } = this.dialogPromice;
  3479. this.dialogPromice = null;
  3480. popup.hide();
  3481. func(result);
  3482. }
  3483. }
  3484. });
  3485. }
  3486.  
  3487. const addStyle = () => {
  3488. let style = document.createElement('style');
  3489. style.innerText = `
  3490. .PopUp_ {
  3491. position: absolute;
  3492. min-width: 300px;
  3493. max-width: 500px;
  3494. max-height: 600px;
  3495. background-color: #190e08e6;
  3496. z-index: 10001;
  3497. top: 169px;
  3498. left: 345px;
  3499. border: 3px #ce9767 solid;
  3500. border-radius: 10px;
  3501. display: flex;
  3502. flex-direction: column;
  3503. justify-content: space-around;
  3504. padding: 15px 9px;
  3505. box-sizing: border-box;
  3506. }
  3507.  
  3508. .PopUp_back {
  3509. position: absolute;
  3510. background-color: #00000066;
  3511. width: 100%;
  3512. height: 100%;
  3513. z-index: 10000;
  3514. top: 0;
  3515. left: 0;
  3516. }
  3517.  
  3518. .PopUp_close {
  3519. width: 40px;
  3520. height: 40px;
  3521. position: absolute;
  3522. right: -18px;
  3523. top: -18px;
  3524. border: 3px solid #c18550;
  3525. border-radius: 20px;
  3526. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  3527. background-position-y: 3px;
  3528. box-shadow: -1px 1px 3px black;
  3529. cursor: pointer;
  3530. box-sizing: border-box;
  3531. }
  3532.  
  3533. .PopUp_close:hover {
  3534. filter: brightness(1.2);
  3535. }
  3536.  
  3537. .PopUp_crossClose {
  3538. width: 100%;
  3539. height: 100%;
  3540. background-size: 65%;
  3541. background-position: center;
  3542. background-repeat: no-repeat;
  3543. 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")
  3544. }
  3545.  
  3546. .PopUp_blocks {
  3547. width: 100%;
  3548. height: 50%;
  3549. display: flex;
  3550. justify-content: space-evenly;
  3551. align-items: center;
  3552. flex-wrap: wrap;
  3553. justify-content: center;
  3554. }
  3555.  
  3556. .PopUp_blocks:last-child {
  3557. margin-top: 25px;
  3558. }
  3559.  
  3560. .PopUp_buttons {
  3561. display: flex;
  3562. margin: 7px 10px;
  3563. flex-direction: column;
  3564. }
  3565.  
  3566. .PopUp_button {
  3567. background-color: #52A81C;
  3568. border-radius: 5px;
  3569. box-shadow: inset 0px -4px 10px, inset 0px 3px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  3570. cursor: pointer;
  3571. padding: 4px 12px 6px;
  3572. }
  3573.  
  3574. .PopUp_input {
  3575. text-align: center;
  3576. font-size: 16px;
  3577. height: 27px;
  3578. border: 1px solid #cf9250;
  3579. border-radius: 9px 9px 0px 0px;
  3580. background: transparent;
  3581. color: #fce1ac;
  3582. padding: 1px 10px;
  3583. box-sizing: border-box;
  3584. box-shadow: 0px 0px 4px, 0px 0px 0px 3px #ce9767;
  3585. }
  3586.  
  3587. .PopUp_checkboxes {
  3588. display: flex;
  3589. flex-direction: column;
  3590. margin: 15px 15px -5px 15px;
  3591. align-items: flex-start;
  3592. }
  3593.  
  3594. .PopUp_ContCheckbox {
  3595. margin: 2px 0px;
  3596. }
  3597.  
  3598. .PopUp_checkbox {
  3599. position: absolute;
  3600. z-index: -1;
  3601. opacity: 0;
  3602. }
  3603. .PopUp_checkbox+label {
  3604. display: inline-flex;
  3605. align-items: center;
  3606. user-select: none;
  3607.  
  3608. font-size: 15px;
  3609. font-family: sans-serif;
  3610. font-weight: 600;
  3611. font-stretch: condensed;
  3612. letter-spacing: 1px;
  3613. color: #fce1ac;
  3614. text-shadow: 0px 0px 1px;
  3615. }
  3616. .PopUp_checkbox+label::before {
  3617. content: '';
  3618. display: inline-block;
  3619. width: 20px;
  3620. height: 20px;
  3621. border: 1px solid #cf9250;
  3622. border-radius: 7px;
  3623. margin-right: 7px;
  3624. }
  3625. .PopUp_checkbox:checked+label::before {
  3626. 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");
  3627. }
  3628.  
  3629. .PopUp_input::placeholder {
  3630. color: #fce1ac75;
  3631. }
  3632.  
  3633. .PopUp_input:focus {
  3634. outline: 0;
  3635. }
  3636.  
  3637. .PopUp_input + .PopUp_button {
  3638. border-radius: 0px 0px 5px 5px;
  3639. padding: 2px 18px 5px;
  3640. }
  3641.  
  3642. .PopUp_button:hover {
  3643. filter: brightness(1.2);
  3644. }
  3645.  
  3646. .PopUp_button:active {
  3647. box-shadow: inset 0px 5px 10px, inset 0px 1px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  3648. }
  3649.  
  3650. .PopUp_text {
  3651. font-size: 22px;
  3652. font-family: sans-serif;
  3653. font-weight: 600;
  3654. font-stretch: condensed;
  3655. letter-spacing: 1px;
  3656. text-align: center;
  3657. }
  3658.  
  3659. .PopUp_buttonText {
  3660. color: #E4FF4C;
  3661. text-shadow: 0px 1px 2px black;
  3662. }
  3663.  
  3664. .PopUp_msgText {
  3665. color: #FDE5B6;
  3666. text-shadow: 0px 0px 2px;
  3667. }
  3668.  
  3669. .PopUp_hideBlock {
  3670. display: none;
  3671. }
  3672. `;
  3673. document.head.appendChild(style);
  3674. }
  3675.  
  3676. const addBlocks = () => {
  3677. this.back = document.createElement('div');
  3678. this.back.classList.add('PopUp_back');
  3679. this.back.classList.add('PopUp_hideBlock');
  3680. document.body.append(this.back);
  3681.  
  3682. this.popUp = document.createElement('div');
  3683. this.popUp.classList.add('PopUp_');
  3684. this.back.append(this.popUp);
  3685.  
  3686. let upper = document.createElement('div')
  3687. upper.classList.add('PopUp_blocks');
  3688. this.popUp.append(upper);
  3689.  
  3690. this.middle = document.createElement('div')
  3691. this.middle.classList.add('PopUp_blocks');
  3692. this.middle.classList.add('PopUp_checkboxes');
  3693. this.popUp.append(this.middle);
  3694.  
  3695. this.downer = document.createElement('div')
  3696. this.downer.classList.add('PopUp_blocks');
  3697. this.popUp.append(this.downer);
  3698.  
  3699. this.msgText = document.createElement('div');
  3700. this.msgText.classList.add('PopUp_text', 'PopUp_msgText');
  3701. upper.append(this.msgText);
  3702. }
  3703.  
  3704. this.showBack = function () {
  3705. this.back.classList.remove('PopUp_hideBlock');
  3706. }
  3707.  
  3708. this.hideBack = function () {
  3709. this.back.classList.add('PopUp_hideBlock');
  3710. }
  3711.  
  3712. this.show = function () {
  3713. if (this.checkboxes.length) {
  3714. this.middle.classList.remove('PopUp_hideBlock');
  3715. }
  3716. this.showBack();
  3717. this.popUp.classList.remove('PopUp_hideBlock');
  3718. this.popUp.style.left = (window.innerWidth - this.popUp.offsetWidth) / 2 + 'px';
  3719. this.popUp.style.top = (window.innerHeight - this.popUp.offsetHeight) / 3 + 'px';
  3720. }
  3721.  
  3722. this.hide = function () {
  3723. this.hideBack();
  3724. this.popUp.classList.add('PopUp_hideBlock');
  3725. }
  3726.  
  3727. this.addAnyButton = (option) => {
  3728. const contButton = document.createElement('div');
  3729. contButton.classList.add('PopUp_buttons');
  3730. this.downer.append(contButton);
  3731.  
  3732. let inputField = {
  3733. value: option.result || option.default
  3734. }
  3735. if (option.isInput) {
  3736. inputField = document.createElement('input');
  3737. inputField.type = 'text';
  3738. if (option.placeholder) {
  3739. inputField.placeholder = option.placeholder;
  3740. }
  3741. if (option.default) {
  3742. inputField.value = option.default;
  3743. }
  3744. inputField.classList.add('PopUp_input');
  3745. contButton.append(inputField);
  3746. }
  3747.  
  3748. const button = document.createElement('div');
  3749. button.classList.add('PopUp_button');
  3750. button.title = option.title || '';
  3751. contButton.append(button);
  3752.  
  3753. const buttonText = document.createElement('div');
  3754. buttonText.classList.add('PopUp_text', 'PopUp_buttonText');
  3755. buttonText.innerHTML = option.msg;
  3756. button.append(buttonText);
  3757.  
  3758. return { button, contButton, inputField };
  3759. }
  3760.  
  3761. this.addCloseButton = () => {
  3762. let button = document.createElement('div')
  3763. button.classList.add('PopUp_close');
  3764. this.popUp.append(button);
  3765.  
  3766. let crossClose = document.createElement('div')
  3767. crossClose.classList.add('PopUp_crossClose');
  3768. button.append(crossClose);
  3769.  
  3770. return { button, contButton: button };
  3771. }
  3772.  
  3773. this.addButton = (option, buttonClick) => {
  3774.  
  3775. const { button, contButton, inputField } = option.isClose ? this.addCloseButton() : this.addAnyButton(option);
  3776. if (option.isClose) {
  3777. this.dialogPromice = { func: buttonClick, result: option.result };
  3778. }
  3779. button.addEventListener('click', () => {
  3780. let result = '';
  3781. if (option.isInput) {
  3782. result = inputField.value;
  3783. }
  3784. if (option.isClose || option.isCancel) {
  3785. this.dialogPromice = null;
  3786. }
  3787. buttonClick(result);
  3788. });
  3789.  
  3790. this.buttons.push(contButton);
  3791. }
  3792.  
  3793. this.clearButtons = () => {
  3794. while (this.buttons.length) {
  3795. this.buttons.pop().remove();
  3796. }
  3797. }
  3798.  
  3799. this.addCheckBox = (checkBox) => {
  3800. const contCheckbox = document.createElement('div');
  3801. contCheckbox.classList.add('PopUp_ContCheckbox');
  3802. this.middle.append(contCheckbox);
  3803.  
  3804. const checkbox = document.createElement('input');
  3805. checkbox.type = 'checkbox';
  3806. checkbox.id = 'PopUpCheckbox' + this.checkboxes.length;
  3807. checkbox.dataset.name = checkBox.name;
  3808. checkbox.checked = checkBox.checked;
  3809. checkbox.label = checkBox.label;
  3810. checkbox.title = checkBox.title || '';
  3811. checkbox.classList.add('PopUp_checkbox');
  3812. contCheckbox.appendChild(checkbox)
  3813.  
  3814. const checkboxLabel = document.createElement('label');
  3815. checkboxLabel.innerText = checkBox.label;
  3816. checkboxLabel.title = checkBox.title || '';
  3817. checkboxLabel.setAttribute('for', checkbox.id);
  3818. contCheckbox.appendChild(checkboxLabel);
  3819.  
  3820. this.checkboxes.push(checkbox);
  3821. }
  3822.  
  3823. this.clearCheckBox = () => {
  3824. this.middle.classList.add('PopUp_hideBlock');
  3825. while (this.checkboxes.length) {
  3826. this.checkboxes.pop().parentNode.remove();
  3827. }
  3828. }
  3829.  
  3830. this.setMsgText = (text) => {
  3831. this.msgText.innerHTML = text;
  3832. }
  3833.  
  3834. this.getCheckBoxes = () => {
  3835. const checkBoxes = [];
  3836.  
  3837. for (const checkBox of this.checkboxes) {
  3838. checkBoxes.push({
  3839. name: checkBox.dataset.name,
  3840. label: checkBox.label,
  3841. checked: checkBox.checked
  3842. });
  3843. }
  3844.  
  3845. return checkBoxes;
  3846. }
  3847.  
  3848. this.confirm = async (msg, buttOpt, checkBoxes = []) => {
  3849. if (!this.isInit) {
  3850. this.init();
  3851. }
  3852. this.clearButtons();
  3853. this.clearCheckBox();
  3854. return new Promise((complete, failed) => {
  3855. this.setMsgText(msg);
  3856. if (!buttOpt) {
  3857. buttOpt = [{ msg: 'Ok', result: true, isInput: false }];
  3858. }
  3859. for (const checkBox of checkBoxes) {
  3860. this.addCheckBox(checkBox);
  3861. }
  3862. for (let butt of buttOpt) {
  3863. this.addButton(butt, (result) => {
  3864. result = result || butt.result;
  3865. complete(result);
  3866. popup.hide();
  3867. });
  3868. if (butt.isCancel) {
  3869. this.dialogPromice = { func: complete, result: butt.result };
  3870. }
  3871. }
  3872. this.show();
  3873. });
  3874. }
  3875. });
  3876.  
  3877. /**
  3878. * Script control panel
  3879. *
  3880. * Панель управления скриптом
  3881. */
  3882. const scriptMenu = new (function () {
  3883.  
  3884. this.mainMenu,
  3885. this.buttons = [],
  3886. this.checkboxes = [];
  3887. this.option = {
  3888. showMenu: false,
  3889. showDetails: {}
  3890. };
  3891.  
  3892. this.init = function (option = {}) {
  3893. this.option = Object.assign(this.option, option);
  3894. this.option.showDetails = this.loadShowDetails();
  3895. addStyle();
  3896. addBlocks();
  3897. }
  3898.  
  3899. const addStyle = () => {
  3900. style = document.createElement('style');
  3901. style.innerText = `
  3902. .scriptMenu_status {
  3903. position: absolute;
  3904. z-index: 10001;
  3905. /* max-height: 30px; */
  3906. top: -1px;
  3907. left: 30%;
  3908. cursor: pointer;
  3909. border-radius: 0px 0px 10px 10px;
  3910. background: #190e08e6;
  3911. border: 1px #ce9767 solid;
  3912. font-size: 18px;
  3913. font-family: sans-serif;
  3914. font-weight: 600;
  3915. font-stretch: condensed;
  3916. letter-spacing: 1px;
  3917. color: #fce1ac;
  3918. text-shadow: 0px 0px 1px;
  3919. transition: 0.5s;
  3920. padding: 2px 10px 3px;
  3921. }
  3922. .scriptMenu_statusHide {
  3923. top: -35px;
  3924. height: 30px;
  3925. overflow: hidden;
  3926. }
  3927. .scriptMenu_label {
  3928. position: absolute;
  3929. top: 30%;
  3930. left: -4px;
  3931. z-index: 9999;
  3932. cursor: pointer;
  3933. width: 30px;
  3934. height: 30px;
  3935. background: radial-gradient(circle, #47a41b 0%, #1a2f04 100%);
  3936. border: 1px solid #1a2f04;
  3937. border-radius: 5px;
  3938. box-shadow:
  3939. inset 0px 2px 4px #83ce26,
  3940. inset 0px -4px 6px #1a2f04,
  3941. 0px 0px 2px black,
  3942. 0px 0px 0px 2px #ce9767;
  3943. }
  3944. .scriptMenu_label:hover {
  3945. filter: brightness(1.2);
  3946. }
  3947. .scriptMenu_arrowLabel {
  3948. width: 100%;
  3949. height: 100%;
  3950. background-size: 75%;
  3951. background-position: center;
  3952. background-repeat: no-repeat;
  3953. 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");
  3954. box-shadow: 0px 1px 2px #000;
  3955. border-radius: 5px;
  3956. filter: drop-shadow(0px 1px 2px #000D);
  3957. }
  3958. .scriptMenu_main {
  3959. position: absolute;
  3960. max-width: 285px;
  3961. z-index: 9999;
  3962. top: 50%;
  3963. transform: translateY(-40%);
  3964. background: #190e08e6;
  3965. border: 1px #ce9767 solid;
  3966. border-radius: 0px 10px 10px 0px;
  3967. border-left: none;
  3968. padding: 5px 10px 5px 5px;
  3969. box-sizing: border-box;
  3970. font-size: 15px;
  3971. font-family: sans-serif;
  3972. font-weight: 600;
  3973. font-stretch: condensed;
  3974. letter-spacing: 1px;
  3975. color: #fce1ac;
  3976. text-shadow: 0px 0px 1px;
  3977. transition: 1s;
  3978. display: flex;
  3979. flex-direction: column;
  3980. flex-wrap: nowrap;
  3981. }
  3982. .scriptMenu_showMenu {
  3983. display: none;
  3984. }
  3985. .scriptMenu_showMenu:checked~.scriptMenu_main {
  3986. left: 0px;
  3987. }
  3988. .scriptMenu_showMenu:not(:checked)~.scriptMenu_main {
  3989. left: -300px;
  3990. }
  3991. .scriptMenu_divInput {
  3992. margin: 2px;
  3993. }
  3994. .scriptMenu_divInputText {
  3995. margin: 2px;
  3996. align-self: center;
  3997. display: flex;
  3998. }
  3999. .scriptMenu_checkbox {
  4000. position: absolute;
  4001. z-index: -1;
  4002. opacity: 0;
  4003. }
  4004. .scriptMenu_checkbox+label {
  4005. display: inline-flex;
  4006. align-items: center;
  4007. user-select: none;
  4008. }
  4009. .scriptMenu_checkbox+label::before {
  4010. content: '';
  4011. display: inline-block;
  4012. width: 20px;
  4013. height: 20px;
  4014. border: 1px solid #cf9250;
  4015. border-radius: 7px;
  4016. margin-right: 7px;
  4017. }
  4018. .scriptMenu_checkbox:checked+label::before {
  4019. 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");
  4020. }
  4021. .scriptMenu_close {
  4022. width: 40px;
  4023. height: 40px;
  4024. position: absolute;
  4025. right: -18px;
  4026. top: -18px;
  4027. border: 3px solid #c18550;
  4028. border-radius: 20px;
  4029. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  4030. background-position-y: 3px;
  4031. box-shadow: -1px 1px 3px black;
  4032. cursor: pointer;
  4033. box-sizing: border-box;
  4034. }
  4035. .scriptMenu_close:hover {
  4036. filter: brightness(1.2);
  4037. }
  4038. .scriptMenu_crossClose {
  4039. width: 100%;
  4040. height: 100%;
  4041. background-size: 65%;
  4042. background-position: center;
  4043. background-repeat: no-repeat;
  4044. 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")
  4045. }
  4046. .scriptMenu_button {
  4047. user-select: none;
  4048. border-radius: 5px;
  4049. cursor: pointer;
  4050. padding: 5px 14px 8px;
  4051. margin: 4px;
  4052. background: radial-gradient(circle, rgba(165,120,56,1) 80%, rgba(0,0,0,1) 110%);
  4053. box-shadow: inset 0px -4px 6px #442901, inset 0px 1px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  4054. }
  4055. .scriptMenu_button:hover {
  4056. filter: brightness(1.2);
  4057. }
  4058. .scriptMenu_button:active {
  4059. box-shadow: inset 0px 4px 6px #442901, inset 0px 4px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  4060. }
  4061. .scriptMenu_buttonText {
  4062. color: #fce5b7;
  4063. text-shadow: 0px 1px 2px black;
  4064. text-align: center;
  4065. }
  4066. .scriptMenu_header {
  4067. text-align: center;
  4068. align-self: center;
  4069. font-size: 15px;
  4070. margin: 0px 15px;
  4071. }
  4072. .scriptMenu_header a {
  4073. color: #fce5b7;
  4074. text-decoration: none;
  4075. }
  4076. .scriptMenu_InputText {
  4077. text-align: center;
  4078. width: 130px;
  4079. height: 24px;
  4080. border: 1px solid #cf9250;
  4081. border-radius: 9px;
  4082. background: transparent;
  4083. color: #fce1ac;
  4084. padding: 0px 10px;
  4085. box-sizing: border-box;
  4086. }
  4087. .scriptMenu_InputText:focus {
  4088. filter: brightness(1.2);
  4089. outline: 0;
  4090. }
  4091. .scriptMenu_InputText::placeholder {
  4092. color: #fce1ac75;
  4093. }
  4094. .scriptMenu_Summary {
  4095. cursor: pointer;
  4096. margin-left: 7px;
  4097. }
  4098. .scriptMenu_Details {
  4099. align-self: center;
  4100. }
  4101. `;
  4102. document.head.appendChild(style);
  4103. }
  4104.  
  4105. const addBlocks = () => {
  4106. const main = document.createElement('div');
  4107. document.body.appendChild(main);
  4108.  
  4109. this.status = document.createElement('div');
  4110. this.status.classList.add('scriptMenu_status');
  4111. this.setStatus('');
  4112. main.appendChild(this.status);
  4113.  
  4114. const label = document.createElement('label');
  4115. label.classList.add('scriptMenu_label');
  4116. label.setAttribute('for', 'checkbox_showMenu');
  4117. main.appendChild(label);
  4118.  
  4119. const arrowLabel = document.createElement('div');
  4120. arrowLabel.classList.add('scriptMenu_arrowLabel');
  4121. label.appendChild(arrowLabel);
  4122.  
  4123. const checkbox = document.createElement('input');
  4124. checkbox.type = 'checkbox';
  4125. checkbox.id = 'checkbox_showMenu';
  4126. checkbox.checked = this.option.showMenu;
  4127. checkbox.classList.add('scriptMenu_showMenu');
  4128. main.appendChild(checkbox);
  4129.  
  4130. this.mainMenu = document.createElement('div');
  4131. this.mainMenu.classList.add('scriptMenu_main');
  4132. main.appendChild(this.mainMenu);
  4133.  
  4134. const closeButton = document.createElement('label');
  4135. closeButton.classList.add('scriptMenu_close');
  4136. closeButton.setAttribute('for', 'checkbox_showMenu');
  4137. this.mainMenu.appendChild(closeButton);
  4138.  
  4139. const crossClose = document.createElement('div');
  4140. crossClose.classList.add('scriptMenu_crossClose');
  4141. closeButton.appendChild(crossClose);
  4142. }
  4143.  
  4144. this.setStatus = (text, onclick) => {
  4145. if (!text) {
  4146. this.status.classList.add('scriptMenu_statusHide');
  4147. this.status.innerHTML = '';
  4148. } else {
  4149. this.status.classList.remove('scriptMenu_statusHide');
  4150. this.status.innerHTML = text;
  4151. }
  4152.  
  4153. if (typeof onclick == 'function') {
  4154. this.status.addEventListener("click", onclick, {
  4155. once: true
  4156. });
  4157. }
  4158. }
  4159.  
  4160. this.addStatus = (text) => {
  4161. if (!this.status.innerHTML) {
  4162. this.status.classList.remove('scriptMenu_statusHide');
  4163. }
  4164. this.status.innerHTML += text;
  4165. }
  4166.  
  4167. /**
  4168. * Adding a text element
  4169. *
  4170. * Добавление текстового элемента
  4171. * @param {String} text text // текст
  4172. * @param {Function} func Click function // функция по клику
  4173. * @param {HTMLDivElement} main parent // родитель
  4174. */
  4175. this.addHeader = (text, func, main) => {
  4176. main = main || this.mainMenu;
  4177. const header = document.createElement('div');
  4178. header.classList.add('scriptMenu_header');
  4179. header.innerHTML = text;
  4180. if (typeof func == 'function') {
  4181. header.addEventListener('click', func);
  4182. }
  4183. main.appendChild(header);
  4184. }
  4185.  
  4186. /**
  4187. * Adding a button
  4188. *
  4189. * Добавление кнопки
  4190. * @param {String} text
  4191. * @param {Function} func
  4192. * @param {String} title
  4193. * @param {HTMLDivElement} main parent // родитель
  4194. */
  4195. this.addButton = (text, func, title, main) => {
  4196. main = main || this.mainMenu;
  4197. const button = document.createElement('div');
  4198. button.classList.add('scriptMenu_button');
  4199. button.title = title;
  4200. button.addEventListener('click', func);
  4201. main.appendChild(button);
  4202.  
  4203. const buttonText = document.createElement('div');
  4204. buttonText.classList.add('scriptMenu_buttonText');
  4205. buttonText.innerText = text;
  4206. button.appendChild(buttonText);
  4207. this.buttons.push(button);
  4208.  
  4209. return button;
  4210. }
  4211.  
  4212. /**
  4213. * Adding checkbox
  4214. *
  4215. * Добавление чекбокса
  4216. * @param {String} label
  4217. * @param {String} title
  4218. * @param {HTMLDivElement} main parent // родитель
  4219. * @returns
  4220. */
  4221. this.addCheckbox = (label, title, main) => {
  4222. main = main || this.mainMenu;
  4223. const divCheckbox = document.createElement('div');
  4224. divCheckbox.classList.add('scriptMenu_divInput');
  4225. divCheckbox.title = title;
  4226. main.appendChild(divCheckbox);
  4227.  
  4228. const checkbox = document.createElement('input');
  4229. checkbox.type = 'checkbox';
  4230. checkbox.id = 'scriptMenuCheckbox' + this.checkboxes.length;
  4231. checkbox.classList.add('scriptMenu_checkbox');
  4232. divCheckbox.appendChild(checkbox)
  4233.  
  4234. const checkboxLabel = document.createElement('label');
  4235. checkboxLabel.innerText = label;
  4236. checkboxLabel.setAttribute('for', checkbox.id);
  4237. divCheckbox.appendChild(checkboxLabel);
  4238.  
  4239. this.checkboxes.push(checkbox);
  4240. return checkbox;
  4241. }
  4242.  
  4243. /**
  4244. * Adding input field
  4245. *
  4246. * Добавление поля ввода
  4247. * @param {String} title
  4248. * @param {String} placeholder
  4249. * @param {HTMLDivElement} main parent // родитель
  4250. * @returns
  4251. */
  4252. this.addInputText = (title, placeholder, main) => {
  4253. main = main || this.mainMenu;
  4254. const divInputText = document.createElement('div');
  4255. divInputText.classList.add('scriptMenu_divInputText');
  4256. divInputText.title = title;
  4257. main.appendChild(divInputText);
  4258.  
  4259. const newInputText = document.createElement('input');
  4260. newInputText.type = 'text';
  4261. if (placeholder) {
  4262. newInputText.placeholder = placeholder;
  4263. }
  4264. newInputText.classList.add('scriptMenu_InputText');
  4265. divInputText.appendChild(newInputText)
  4266. return newInputText;
  4267. }
  4268.  
  4269. /**
  4270. * Adds a dropdown block
  4271. *
  4272. * Добавляет раскрывающийся блок
  4273. * @param {String} summary
  4274. * @param {String} name
  4275. * @returns
  4276. */
  4277. this.addDetails = (summaryText, name = null) => {
  4278. const details = document.createElement('details');
  4279. details.classList.add('scriptMenu_Details');
  4280. this.mainMenu.appendChild(details);
  4281.  
  4282. const summary = document.createElement('summary');
  4283. summary.classList.add('scriptMenu_Summary');
  4284. summary.innerText = summaryText;
  4285. if (name) {
  4286. const self = this;
  4287. details.open = this.option.showDetails[name];
  4288. details.dataset.name = name;
  4289. summary.addEventListener('click', () => {
  4290. self.option.showDetails[details.dataset.name] = !details.open;
  4291. self.saveShowDetails(self.option.showDetails);
  4292. });
  4293. }
  4294. details.appendChild(summary);
  4295.  
  4296. return details;
  4297. }
  4298.  
  4299. /**
  4300. * Saving the expanded state of the details blocks
  4301. *
  4302. * Сохранение состояния развенутости блоков details
  4303. * @param {*} value
  4304. */
  4305. this.saveShowDetails = (value) => {
  4306. localStorage.setItem('scriptMenu_showDetails', JSON.stringify(value));
  4307. }
  4308.  
  4309. /**
  4310. * Loading the state of expanded blocks details
  4311. *
  4312. * Загрузка состояния развенутости блоков details
  4313. * @returns
  4314. */
  4315. this.loadShowDetails = () => {
  4316. let showDetails = localStorage.getItem('scriptMenu_showDetails');
  4317.  
  4318. if (!showDetails) {
  4319. return {};
  4320. }
  4321.  
  4322. try {
  4323. showDetails = JSON.parse(showDetails);
  4324. } catch (e) {
  4325. return {};
  4326. }
  4327.  
  4328. return showDetails;
  4329. }
  4330. });
  4331.  
  4332. /**
  4333. * Пример использования
  4334. scriptMenu.init();
  4335. scriptMenu.addHeader('v1.508');
  4336. scriptMenu.addCheckbox('testHack', 'Тестовый взлом игры!');
  4337. scriptMenu.addButton('Запуск!', () => console.log('click'), 'подсказака');
  4338. scriptMenu.addInputText('input подсказака');
  4339. */
  4340. /**
  4341. * Game Library
  4342. *
  4343. * Игровая библиотека
  4344. */
  4345. class Library {
  4346. defaultLibUrl = 'https://heroesru-a.akamaihd.net/vk/v1101/lib/lib.json';
  4347.  
  4348. constructor() {
  4349. if (!Library.instance) {
  4350. Library.instance = this;
  4351. }
  4352.  
  4353. return Library.instance;
  4354. }
  4355.  
  4356. async load() {
  4357. try {
  4358. await this.getUrlLib();
  4359. console.log(this.defaultLibUrl);
  4360. this.data = await fetch(this.defaultLibUrl).then(e => e.json())
  4361. } catch (error) {
  4362. console.error('Не удалось загрузить библиотеку', error)
  4363. }
  4364. }
  4365.  
  4366. async getUrlLib() {
  4367. try {
  4368. const db = new Database('hw_cache', 'cache');
  4369. await db.open();
  4370. const cacheLibFullUrl = await db.get('lib/lib.json.gz', false);
  4371. this.defaultLibUrl = cacheLibFullUrl.fullUrl.split('.gz').shift();
  4372. } catch(e) {}
  4373. }
  4374.  
  4375. getData(id) {
  4376. return this.data[id];
  4377. }
  4378. }
  4379.  
  4380. this.lib = new Library();
  4381. /**
  4382. * Database
  4383. *
  4384. * База данных
  4385. */
  4386. class Database {
  4387. constructor(dbName, storeName) {
  4388. this.dbName = dbName;
  4389. this.storeName = storeName;
  4390. this.db = null;
  4391. }
  4392.  
  4393. async open() {
  4394. return new Promise((resolve, reject) => {
  4395. const request = indexedDB.open(this.dbName);
  4396.  
  4397. request.onerror = () => {
  4398. reject(new Error(`Failed to open database ${this.dbName}`));
  4399. };
  4400.  
  4401. request.onsuccess = () => {
  4402. this.db = request.result;
  4403. resolve();
  4404. };
  4405.  
  4406. request.onupgradeneeded = (event) => {
  4407. const db = event.target.result;
  4408. if (!db.objectStoreNames.contains(this.storeName)) {
  4409. db.createObjectStore(this.storeName);
  4410. }
  4411. };
  4412. });
  4413. }
  4414.  
  4415. async set(key, value) {
  4416. return new Promise((resolve, reject) => {
  4417. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4418. const store = transaction.objectStore(this.storeName);
  4419. const request = store.put(value, key);
  4420.  
  4421. request.onerror = () => {
  4422. reject(new Error(`Failed to save value with key ${key}`));
  4423. };
  4424.  
  4425. request.onsuccess = () => {
  4426. resolve();
  4427. };
  4428. });
  4429. }
  4430.  
  4431. async get(key, def) {
  4432. return new Promise((resolve, reject) => {
  4433. const transaction = this.db.transaction([this.storeName], 'readonly');
  4434. const store = transaction.objectStore(this.storeName);
  4435. const request = store.get(key);
  4436.  
  4437. request.onerror = () => {
  4438. resolve(def);
  4439. };
  4440.  
  4441. request.onsuccess = () => {
  4442. resolve(request.result);
  4443. };
  4444. });
  4445. }
  4446.  
  4447. async delete(key) {
  4448. return new Promise((resolve, reject) => {
  4449. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4450. const store = transaction.objectStore(this.storeName);
  4451. const request = store.delete(key);
  4452.  
  4453. request.onerror = () => {
  4454. reject(new Error(`Failed to delete value with key ${key}`));
  4455. };
  4456.  
  4457. request.onsuccess = () => {
  4458. resolve();
  4459. };
  4460. });
  4461. }
  4462. }
  4463.  
  4464. /**
  4465. * Returns the stored value
  4466. *
  4467. * Возвращает сохраненное значение
  4468. */
  4469. function getSaveVal(saveName, def) {
  4470. const result = storage.get(saveName, def);
  4471. return result;
  4472. }
  4473.  
  4474. /**
  4475. * Stores value
  4476. *
  4477. * Сохраняет значение
  4478. */
  4479. function setSaveVal(saveName, value) {
  4480. storage.set(saveName, value);
  4481. }
  4482.  
  4483. /**
  4484. * Database initialization
  4485. *
  4486. * Инициализация базы данных
  4487. */
  4488. const db = new Database(GM_info.script.name, 'settings');
  4489.  
  4490. /**
  4491. * Data store
  4492. *
  4493. * Хранилище данных
  4494. */
  4495. const storage = {
  4496. userId: 0,
  4497. /**
  4498. * Default values
  4499. *
  4500. * Значения по умолчанию
  4501. */
  4502. values: [
  4503. ...Object.entries(checkboxes).map(e => ({ [e[0]]: e[1].default })),
  4504. ...Object.entries(inputs).map(e => ({ [e[0]]: e[1].default })),
  4505. ].reduce((acc, obj) => ({ ...acc, ...obj }), {}),
  4506. name: GM_info.script.name,
  4507. get: function (key, def) {
  4508. if (key in this.values) {
  4509. return this.values[key];
  4510. }
  4511. return def;
  4512. },
  4513. set: function (key, value) {
  4514. this.values[key] = value;
  4515. db.set(this.userId, this.values).catch(
  4516. e => null
  4517. );
  4518. localStorage[this.name + ':' + key] = value;
  4519. },
  4520. delete: function (key) {
  4521. delete this.values[key];
  4522. db.set(this.userId, this.values);
  4523. delete localStorage[this.name + ':' + key];
  4524. }
  4525. }
  4526.  
  4527. /**
  4528. * Returns all keys from localStorage that start with prefix (for migration)
  4529. *
  4530. * Возвращает все ключи из localStorage которые начинаются с prefix (для миграции)
  4531. */
  4532. function getAllValuesStartingWith(prefix) {
  4533. const values = [];
  4534. for (let i = 0; i < localStorage.length; i++) {
  4535. const key = localStorage.key(i);
  4536. if (key.startsWith(prefix)) {
  4537. const val = localStorage.getItem(key);
  4538. const keyValue = key.split(':')[1];
  4539. values.push({ key: keyValue, val });
  4540. }
  4541. }
  4542. return values;
  4543. }
  4544.  
  4545. /**
  4546. * Opens or migrates to a database
  4547. *
  4548. * Открывает или мигрирует в базу данных
  4549. */
  4550. async function openOrMigrateDatabase(userId) {
  4551. storage.userId = userId;
  4552. try {
  4553. await db.open();
  4554. } catch(e) {
  4555. return;
  4556. }
  4557. let settings = await db.get(userId, false);
  4558.  
  4559. if (settings) {
  4560. storage.values = settings;
  4561. return;
  4562. }
  4563.  
  4564. const values = getAllValuesStartingWith(GM_info.script.name);
  4565. for (const value of values) {
  4566. let val = null;
  4567. try {
  4568. val = JSON.parse(value.val);
  4569. } catch {
  4570. break;
  4571. }
  4572. storage.values[value.key] = val;
  4573. }
  4574. await db.set(userId, storage.values);
  4575. }
  4576.  
  4577. class ZingerYWebsiteAPI {
  4578. /**
  4579. * Class for interaction with the API of the zingery.ru website
  4580. * Intended only for use with the HeroWarsHelper script:
  4581. * https://greasyfork.org/ru/scripts/450693-herowarshelper
  4582. * Copyright ZingerY
  4583. */
  4584. url = 'https://zingery.ru/heroes/';
  4585. // YWJzb2x1dGVseSB1c2VsZXNzIGxpbmU=
  4586. constructor(urn, env, data = {}) {
  4587. this.urn = urn;
  4588. this.fd = {
  4589. now: Date.now(),
  4590. fp: this.constructor.toString().replaceAll(/\s/g, ''),
  4591. env: env.callee.toString().replaceAll(/\s/g, ''),
  4592. info: (({ name, version, author }) => [name, version, author])(GM_info.script),
  4593. ...data,
  4594. };
  4595. }
  4596.  
  4597. sign() {
  4598. return md5([...this.fd.info, ~(this.fd.now % 1e3), this.fd.fp].join('_'));
  4599. }
  4600.  
  4601. encode(data) {
  4602. return btoa(encodeURIComponent(JSON.stringify(data)));
  4603. }
  4604.  
  4605. decode(data) {
  4606. return JSON.parse(decodeURIComponent(atob(data)));
  4607. }
  4608.  
  4609. headers() {
  4610. return {
  4611. 'X-Request-Signature': this.sign(),
  4612. 'X-Script-Name': GM_info.script.name,
  4613. 'X-Script-Version': GM_info.script.version,
  4614. 'X-Script-Author': GM_info.script.author,
  4615. 'X-Script-ZingerY': 42,
  4616. };
  4617. }
  4618.  
  4619. async request() {
  4620. try {
  4621. const response = await fetch(this.url + this.urn, {
  4622. method: 'POST',
  4623. headers: this.headers(),
  4624. body: this.encode(this.fd),
  4625. });
  4626. const text = await response.text();
  4627. return this.decode(text);
  4628. } catch (e) {
  4629. console.error(e);
  4630. return [];
  4631. }
  4632. }
  4633. /**
  4634. * Класс для взаимодействия с API сайта zingery.ru
  4635. * Предназначен только для использования со скриптом HeroWarsHelper:
  4636. * https://greasyfork.org/ru/scripts/450693-herowarshelper
  4637. * Copyright ZingerY
  4638. */
  4639. }
  4640.  
  4641. /**
  4642. * Sending expeditions
  4643. *
  4644. * Отправка экспедиций
  4645. */
  4646. function checkExpedition() {
  4647. return new Promise((resolve, reject) => {
  4648. const expedition = new Expedition(resolve, reject);
  4649. expedition.start();
  4650. });
  4651. }
  4652.  
  4653. class Expedition {
  4654. checkExpedInfo = {
  4655. calls: [
  4656. {
  4657. name: 'expeditionGet',
  4658. args: {},
  4659. ident: 'expeditionGet',
  4660. },
  4661. {
  4662. name: 'heroGetAll',
  4663. args: {},
  4664. ident: 'heroGetAll',
  4665. },
  4666. ],
  4667. };
  4668.  
  4669. constructor(resolve, reject) {
  4670. this.resolve = resolve;
  4671. this.reject = reject;
  4672. }
  4673.  
  4674. async start() {
  4675. const data = await Send(JSON.stringify(this.checkExpedInfo));
  4676.  
  4677. const expedInfo = data.results[0].result.response;
  4678. const dataHeroes = data.results[1].result.response;
  4679. const dataExped = { useHeroes: [], exped: [] };
  4680. const calls = [];
  4681.  
  4682. /**
  4683. * Adding expeditions to collect
  4684. * Добавляем экспедиции для сбора
  4685. */
  4686. let countGet = 0;
  4687. for (var n in expedInfo) {
  4688. const exped = expedInfo[n];
  4689. const dateNow = Date.now() / 1000;
  4690. if (exped.status == 2 && exped.endTime != 0 && dateNow > exped.endTime) {
  4691. countGet++;
  4692. calls.push({
  4693. name: 'expeditionFarm',
  4694. args: { expeditionId: exped.id },
  4695. ident: 'expeditionFarm_' + exped.id,
  4696. });
  4697. } else {
  4698. dataExped.useHeroes = dataExped.useHeroes.concat(exped.heroes);
  4699. }
  4700. if (exped.status == 1) {
  4701. dataExped.exped.push({ id: exped.id, power: exped.power });
  4702. }
  4703. }
  4704. dataExped.exped = dataExped.exped.sort((a, b) => b.power - a.power);
  4705.  
  4706. /**
  4707. * Putting together a list of heroes
  4708. * Собираем список героев
  4709. */
  4710. const heroesArr = [];
  4711. for (let n in dataHeroes) {
  4712. const hero = dataHeroes[n];
  4713. if (hero.xp > 0 && !dataExped.useHeroes.includes(hero.id)) {
  4714. let heroPower = hero.power;
  4715. // Лара Крофт * 3
  4716. if (hero.id == 63 && hero.color >= 16) {
  4717. heroPower *= 3;
  4718. }
  4719. heroesArr.push({ id: hero.id, power: heroPower });
  4720. }
  4721. }
  4722.  
  4723. /**
  4724. * Adding expeditions to send
  4725. * Добавляем экспедиции для отправки
  4726. */
  4727. let countSend = 0;
  4728. heroesArr.sort((a, b) => a.power - b.power);
  4729. for (const exped of dataExped.exped) {
  4730. let heroesIds = this.selectionHeroes(heroesArr, exped.power);
  4731. if (heroesIds && heroesIds.length > 4) {
  4732. for (let q in heroesArr) {
  4733. if (heroesIds.includes(heroesArr[q].id)) {
  4734. delete heroesArr[q];
  4735. }
  4736. }
  4737. countSend++;
  4738. calls.push({
  4739. name: 'expeditionSendHeroes',
  4740. args: {
  4741. expeditionId: exped.id,
  4742. heroes: heroesIds,
  4743. },
  4744. ident: 'expeditionSendHeroes_' + exped.id,
  4745. });
  4746. }
  4747. }
  4748.  
  4749. if (calls.length) {
  4750. await Send({ calls });
  4751. this.end(I18N('EXPEDITIONS_SENT', {countGet, countSend}));
  4752. return;
  4753. }
  4754.  
  4755. this.end(I18N('EXPEDITIONS_NOTHING'));
  4756. }
  4757.  
  4758. /**
  4759. * Selection of heroes for expeditions
  4760. *
  4761. * Подбор героев для экспедиций
  4762. */
  4763. selectionHeroes(heroes, power) {
  4764. const resultHeroers = [];
  4765. const heroesIds = [];
  4766. for (let q = 0; q < 5; q++) {
  4767. for (let i in heroes) {
  4768. let hero = heroes[i];
  4769. if (heroesIds.includes(hero.id)) {
  4770. continue;
  4771. }
  4772.  
  4773. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  4774. const need = Math.round((power - summ) / (5 - resultHeroers.length));
  4775. if (hero.power > need) {
  4776. resultHeroers.push(hero);
  4777. heroesIds.push(hero.id);
  4778. break;
  4779. }
  4780. }
  4781. }
  4782.  
  4783. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  4784. if (summ < power) {
  4785. return false;
  4786. }
  4787. return heroesIds;
  4788. }
  4789.  
  4790. /**
  4791. * Ends expedition script
  4792. *
  4793. * Завершает скрипт экспедиции
  4794. */
  4795. end(msg) {
  4796. setProgress(msg, true);
  4797. this.resolve();
  4798. }
  4799. }
  4800.  
  4801. /**
  4802. * Walkthrough of the dungeon
  4803. *
  4804. * Прохождение подземелья
  4805. */
  4806. function testDungeon() {
  4807. return new Promise((resolve, reject) => {
  4808. const dung = new executeDungeon(resolve, reject);
  4809. const titanit = getInput('countTitanit');
  4810. dung.start(titanit);
  4811. });
  4812. }
  4813.  
  4814. /**
  4815. * Walkthrough of the dungeon
  4816. *
  4817. * Прохождение подземелья
  4818. */
  4819. function executeDungeon(resolve, reject) {
  4820. dungeonActivity = 0;
  4821. maxDungeonActivity = 150;
  4822.  
  4823. titanGetAll = [];
  4824.  
  4825. teams = {
  4826. heroes: [],
  4827. earth: [],
  4828. fire: [],
  4829. neutral: [],
  4830. water: [],
  4831. }
  4832.  
  4833. titanStats = [];
  4834.  
  4835. titansStates = {};
  4836.  
  4837. callsExecuteDungeon = {
  4838. calls: [{
  4839. name: "dungeonGetInfo",
  4840. args: {},
  4841. ident: "dungeonGetInfo"
  4842. }, {
  4843. name: "teamGetAll",
  4844. args: {},
  4845. ident: "teamGetAll"
  4846. }, {
  4847. name: "teamGetFavor",
  4848. args: {},
  4849. ident: "teamGetFavor"
  4850. }, {
  4851. name: "clanGetInfo",
  4852. args: {},
  4853. ident: "clanGetInfo"
  4854. }, {
  4855. name: "titanGetAll",
  4856. args: {},
  4857. ident: "titanGetAll"
  4858. }, {
  4859. name: "inventoryGet",
  4860. args: {},
  4861. ident: "inventoryGet"
  4862. }]
  4863. }
  4864.  
  4865. this.start = function(titanit) {
  4866. maxDungeonActivity = titanit || getInput('countTitanit');
  4867. send(JSON.stringify(callsExecuteDungeon), startDungeon);
  4868. }
  4869.  
  4870. /**
  4871. * Getting data on the dungeon
  4872. *
  4873. * Получаем данные по подземелью
  4874. */
  4875. function startDungeon(e) {
  4876. res = e.results;
  4877. dungeonGetInfo = res[0].result.response;
  4878. if (!dungeonGetInfo) {
  4879. endDungeon('noDungeon', res);
  4880. return;
  4881. }
  4882. teamGetAll = res[1].result.response;
  4883. teamGetFavor = res[2].result.response;
  4884. dungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  4885. titanGetAll = Object.values(res[4].result.response);
  4886. countPredictionCard = res[5].result.response.consumable[81];
  4887.  
  4888. teams.hero = {
  4889. favor: teamGetFavor.dungeon_hero,
  4890. heroes: teamGetAll.dungeon_hero.filter(id => id < 6000),
  4891. teamNum: 0,
  4892. }
  4893. heroPet = teamGetAll.dungeon_hero.filter(id => id >= 6000).pop();
  4894. if (heroPet) {
  4895. teams.hero.pet = heroPet;
  4896. }
  4897.  
  4898. teams.neutral = {
  4899. favor: {},
  4900. heroes: getTitanTeam(titanGetAll, 'neutral'),
  4901. teamNum: 0,
  4902. };
  4903. teams.water = {
  4904. favor: {},
  4905. heroes: getTitanTeam(titanGetAll, 'water'),
  4906. teamNum: 0,
  4907. };
  4908. teams.fire = {
  4909. favor: {},
  4910. heroes: getTitanTeam(titanGetAll, 'fire'),
  4911. teamNum: 0,
  4912. };
  4913. teams.earth = {
  4914. favor: {},
  4915. heroes: getTitanTeam(titanGetAll, 'earth'),
  4916. teamNum: 0,
  4917. };
  4918.  
  4919.  
  4920. checkFloor(dungeonGetInfo);
  4921. }
  4922.  
  4923. function getTitanTeam(titans, type) {
  4924. switch (type) {
  4925. case 'neutral':
  4926. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4927. case 'water':
  4928. return titans.filter(e => e.id.toString().slice(2, 3) == '0').map(e => e.id);
  4929. case 'fire':
  4930. return titans.filter(e => e.id.toString().slice(2, 3) == '1').map(e => e.id);
  4931. case 'earth':
  4932. return titans.filter(e => e.id.toString().slice(2, 3) == '2').map(e => e.id);
  4933. }
  4934. }
  4935.  
  4936. function getNeutralTeam() {
  4937. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  4938. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4939. }
  4940.  
  4941. function fixTitanTeam(titans) {
  4942. titans.heroes = titans.heroes.filter(e => !titansStates[e]?.isDead);
  4943. return titans;
  4944. }
  4945.  
  4946. /**
  4947. * Checking the floor
  4948. *
  4949. * Проверяем этаж
  4950. */
  4951. async function checkFloor(dungeonInfo) {
  4952. if (!('floor' in dungeonInfo) || dungeonInfo.floor?.state == 2) {
  4953. saveProgress();
  4954. return;
  4955. }
  4956. // console.log(dungeonInfo, dungeonActivity);
  4957. setProgress(`${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  4958. if (dungeonActivity >= maxDungeonActivity) {
  4959. endDungeon('endDungeon', 'maxActive ' + dungeonActivity + '/' + maxDungeonActivity);
  4960. return;
  4961. }
  4962. titansStates = dungeonInfo.states.titans;
  4963. titanStats = titanObjToArray(titansStates);
  4964. const floorChoices = dungeonInfo.floor.userData;
  4965. const floorType = dungeonInfo.floorType;
  4966. //const primeElement = dungeonInfo.elements.prime;
  4967. if (floorType == "battle") {
  4968. const calls = [];
  4969. for (let teamNum in floorChoices) {
  4970. attackerType = floorChoices[teamNum].attackerType;
  4971. const args = fixTitanTeam(teams[attackerType]);
  4972. if (attackerType == 'neutral') {
  4973. args.heroes = getNeutralTeam();
  4974. }
  4975. if (!args.heroes.length) {
  4976. continue;
  4977. }
  4978. args.teamNum = teamNum;
  4979. calls.push({
  4980. name: "dungeonStartBattle",
  4981. args,
  4982. ident: "body_" + teamNum
  4983. })
  4984. }
  4985. if (!calls.length) {
  4986. endDungeon('endDungeon', 'All Dead');
  4987. return;
  4988. }
  4989. const battleDatas = await Send(JSON.stringify({ calls }))
  4990. .then(e => e.results.map(n => n.result.response))
  4991. const battleResults = [];
  4992. for (n in battleDatas) {
  4993. battleData = battleDatas[n]
  4994. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  4995. battleResults.push(await Calc(battleData).then(result => {
  4996. result.teamNum = n;
  4997. result.attackerType = floorChoices[n].attackerType;
  4998. return result;
  4999. }));
  5000. }
  5001. processingPromises(battleResults)
  5002. }
  5003. }
  5004.  
  5005. function processingPromises(results) {
  5006. let selectBattle = results[0];
  5007. if (results.length < 2) {
  5008. // console.log(selectBattle);
  5009. if (!selectBattle.result.win) {
  5010. endDungeon('dungeonEndBattle\n', selectBattle);
  5011. return;
  5012. }
  5013. endBattle(selectBattle);
  5014. return;
  5015. }
  5016.  
  5017. selectBattle = false;
  5018. let bestState = -1000;
  5019. for (const result of results) {
  5020. const recovery = getState(result);
  5021. if (recovery > bestState) {
  5022. bestState = recovery;
  5023. selectBattle = result
  5024. }
  5025. }
  5026. // console.log(selectBattle.teamNum, results);
  5027. if (!selectBattle || bestState <= -1000) {
  5028. endDungeon('dungeonEndBattle\n', results);
  5029. return;
  5030. }
  5031.  
  5032. startBattle(selectBattle.teamNum, selectBattle.attackerType)
  5033. .then(endBattle);
  5034. }
  5035.  
  5036. /**
  5037. * Let's start the fight
  5038. *
  5039. * Начинаем бой
  5040. */
  5041. function startBattle(teamNum, attackerType) {
  5042. return new Promise(function (resolve, reject) {
  5043. args = fixTitanTeam(teams[attackerType]);
  5044. args.teamNum = teamNum;
  5045. if (attackerType == 'neutral') {
  5046. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  5047. args.heroes = titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5048. }
  5049. startBattleCall = {
  5050. calls: [{
  5051. name: "dungeonStartBattle",
  5052. args,
  5053. ident: "body"
  5054. }]
  5055. }
  5056. send(JSON.stringify(startBattleCall), resultBattle, {
  5057. resolve,
  5058. teamNum,
  5059. attackerType
  5060. });
  5061. });
  5062. }
  5063. /**
  5064. * Returns the result of the battle in a promise
  5065. *
  5066. * Возращает резульат боя в промис
  5067. */
  5068. function resultBattle(resultBattles, args) {
  5069. battleData = resultBattles.results[0].result.response;
  5070. battleType = "get_tower";
  5071. if (battleData.type == "dungeon_titan") {
  5072. battleType = "get_titan";
  5073. }
  5074. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  5075. BattleCalc(battleData, battleType, function (result) {
  5076. result.teamNum = args.teamNum;
  5077. result.attackerType = args.attackerType;
  5078. args.resolve(result);
  5079. });
  5080. }
  5081. /**
  5082. * Finishing the fight
  5083. *
  5084. * Заканчиваем бой
  5085. */
  5086. async function endBattle(battleInfo) {
  5087. if (battleInfo.result.win) {
  5088. const args = {
  5089. result: battleInfo.result,
  5090. progress: battleInfo.progress,
  5091. }
  5092. if (countPredictionCard > 0) {
  5093. args.isRaid = true;
  5094. } else {
  5095. const timer = getTimer(battleInfo.battleTime);
  5096. console.log(timer);
  5097. await countdownTimer(timer, `${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  5098. }
  5099. const calls = [{
  5100. name: "dungeonEndBattle",
  5101. args,
  5102. ident: "body"
  5103. }];
  5104. lastDungeonBattleData = null;
  5105. send(JSON.stringify({ calls }), resultEndBattle);
  5106. } else {
  5107. endDungeon('dungeonEndBattle win: false\n', battleInfo);
  5108. }
  5109. }
  5110.  
  5111. /**
  5112. * Getting and processing battle results
  5113. *
  5114. * Получаем и обрабатываем результаты боя
  5115. */
  5116. function resultEndBattle(e) {
  5117. if ('error' in e) {
  5118. popup.confirm(I18N('ERROR_MSG', {
  5119. name: e.error.name,
  5120. description: e.error.description,
  5121. }));
  5122. endDungeon('errorRequest', e);
  5123. return;
  5124. }
  5125. battleResult = e.results[0].result.response;
  5126. if ('error' in battleResult) {
  5127. endDungeon('errorBattleResult', battleResult);
  5128. return;
  5129. }
  5130. dungeonGetInfo = battleResult.dungeon ?? battleResult;
  5131. dungeonActivity += battleResult.reward.dungeonActivity ?? 0;
  5132. checkFloor(dungeonGetInfo);
  5133. }
  5134.  
  5135. /**
  5136. * Returns the coefficient of condition of the
  5137. * difference in titanium before and after the battle
  5138. *
  5139. * Возвращает коэффициент состояния титанов после боя
  5140. */
  5141. function getState(result) {
  5142. if (!result.result.win) {
  5143. return -1000;
  5144. }
  5145.  
  5146. let beforeSumFactor = 0;
  5147. const beforeTitans = result.battleData.attackers;
  5148. for (let titanId in beforeTitans) {
  5149. const titan = beforeTitans[titanId];
  5150. const state = titan.state;
  5151. let factor = 1;
  5152. if (state) {
  5153. const hp = state.hp / titan.hp;
  5154. const energy = state.energy / 1e3;
  5155. factor = hp + energy / 20
  5156. }
  5157. beforeSumFactor += factor;
  5158. }
  5159.  
  5160. let afterSumFactor = 0;
  5161. const afterTitans = result.progress[0].attackers.heroes;
  5162. for (let titanId in afterTitans) {
  5163. const titan = afterTitans[titanId];
  5164. const hp = titan.hp / beforeTitans[titanId].hp;
  5165. const energy = titan.energy / 1e3;
  5166. const factor = hp + energy / 20;
  5167. afterSumFactor += factor;
  5168. }
  5169. return afterSumFactor - beforeSumFactor;
  5170. }
  5171.  
  5172. /**
  5173. * Converts an object with IDs to an array with IDs
  5174. *
  5175. * Преобразует объект с идетификаторами в массив с идетификаторами
  5176. */
  5177. function titanObjToArray(obj) {
  5178. let titans = [];
  5179. for (let id in obj) {
  5180. obj[id].id = id;
  5181. titans.push(obj[id]);
  5182. }
  5183. return titans;
  5184. }
  5185.  
  5186. function saveProgress() {
  5187. let saveProgressCall = {
  5188. calls: [{
  5189. name: "dungeonSaveProgress",
  5190. args: {},
  5191. ident: "body"
  5192. }]
  5193. }
  5194. send(JSON.stringify(saveProgressCall), resultEndBattle);
  5195. }
  5196.  
  5197. function endDungeon(reason, info) {
  5198. console.warn(reason, info);
  5199. setProgress(`${I18N('DUNGEON')} ${I18N('COMPLETED')}`, true);
  5200. resolve();
  5201. }
  5202. }
  5203.  
  5204. /**
  5205. * Passing the tower
  5206. *
  5207. * Прохождение башни
  5208. */
  5209. function testTower() {
  5210. return new Promise((resolve, reject) => {
  5211. tower = new executeTower(resolve, reject);
  5212. tower.start();
  5213. });
  5214. }
  5215.  
  5216. /**
  5217. * Passing the tower
  5218. *
  5219. * Прохождение башни
  5220. */
  5221. function executeTower(resolve, reject) {
  5222. lastTowerInfo = {};
  5223.  
  5224. scullCoin = 0;
  5225.  
  5226. heroGetAll = [];
  5227.  
  5228. heroesStates = {};
  5229.  
  5230. argsBattle = {
  5231. heroes: [],
  5232. favor: {},
  5233. };
  5234.  
  5235. callsExecuteTower = {
  5236. calls: [{
  5237. name: "towerGetInfo",
  5238. args: {},
  5239. ident: "towerGetInfo"
  5240. }, {
  5241. name: "teamGetAll",
  5242. args: {},
  5243. ident: "teamGetAll"
  5244. }, {
  5245. name: "teamGetFavor",
  5246. args: {},
  5247. ident: "teamGetFavor"
  5248. }, {
  5249. name: "inventoryGet",
  5250. args: {},
  5251. ident: "inventoryGet"
  5252. }, {
  5253. name: "heroGetAll",
  5254. args: {},
  5255. ident: "heroGetAll"
  5256. }]
  5257. }
  5258.  
  5259. buffIds = [
  5260. {id: 0, cost: 0, isBuy: false}, // plug // заглушка
  5261. {id: 1, cost: 1, isBuy: true}, // 3% attack // 3% атака
  5262. {id: 2, cost: 6, isBuy: true}, // 2% attack // 2% атака
  5263. {id: 3, cost: 16, isBuy: true}, // 4% attack // 4% атака
  5264. {id: 4, cost: 40, isBuy: true}, // 8% attack // 8% атака
  5265. {id: 5, cost: 1, isBuy: true}, // 10% armor // 10% броня
  5266. {id: 6, cost: 6, isBuy: true}, // 5% armor // 5% броня
  5267. {id: 7, cost: 16, isBuy: true}, // 10% armor // 10% броня
  5268. {id: 8, cost: 40, isBuy: true}, // 20% armor // 20% броня
  5269. { id: 9, cost: 1, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5270. { id: 10, cost: 6, isBuy: true }, // 5% protection from magic // 5% защита от магии
  5271. { id: 11, cost: 16, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5272. { id: 12, cost: 40, isBuy: true }, // 20% protection from magic // 20% защита от магии
  5273. { id: 13, cost: 1, isBuy: false }, // 40% health hero // 40% здоровья герою
  5274. { id: 14, cost: 6, isBuy: false }, // 40% health hero // 40% здоровья герою
  5275. { id: 15, cost: 16, isBuy: false }, // 80% health hero // 80% здоровья герою
  5276. { id: 16, cost: 40, isBuy: false }, // 40% health to all heroes // 40% здоровья всем героям
  5277. { id: 17, cost: 1, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5278. { id: 18, cost: 3, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5279. { id: 19, cost: 8, isBuy: false }, // 80% energy to the hero // 80% энергии герою
  5280. { id: 20, cost: 20, isBuy: false }, // 40% energy to all heroes // 40% энергии всем героям
  5281. { id: 21, cost: 40, isBuy: false }, // Hero Resurrection // Воскрешение героя
  5282. ]
  5283.  
  5284. this.start = function () {
  5285. send(JSON.stringify(callsExecuteTower), startTower);
  5286. }
  5287.  
  5288. /**
  5289. * Getting data on the Tower
  5290. *
  5291. * Получаем данные по башне
  5292. */
  5293. function startTower(e) {
  5294. res = e.results;
  5295. towerGetInfo = res[0].result.response;
  5296. if (!towerGetInfo) {
  5297. endTower('noTower', res);
  5298. return;
  5299. }
  5300. teamGetAll = res[1].result.response;
  5301. teamGetFavor = res[2].result.response;
  5302. inventoryGet = res[3].result.response;
  5303. heroGetAll = Object.values(res[4].result.response);
  5304.  
  5305. scullCoin = inventoryGet.coin[7] ?? 0;
  5306.  
  5307. argsBattle.favor = teamGetFavor.tower;
  5308. argsBattle.heroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5309. pet = teamGetAll.tower.filter(id => id >= 6000).pop();
  5310. if (pet) {
  5311. argsBattle.pet = pet;
  5312. }
  5313.  
  5314. checkFloor(towerGetInfo);
  5315. }
  5316.  
  5317. function fixHeroesTeam(argsBattle) {
  5318. let fixHeroes = argsBattle.heroes.filter(e => !heroesStates[e]?.isDead);
  5319. if (fixHeroes.length < 5) {
  5320. heroGetAll = heroGetAll.filter(e => !heroesStates[e.id]?.isDead);
  5321. fixHeroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5322. Object.keys(argsBattle.favor).forEach(e => {
  5323. if (!fixHeroes.includes(+e)) {
  5324. delete argsBattle.favor[e];
  5325. }
  5326. })
  5327. }
  5328. argsBattle.heroes = fixHeroes;
  5329. return argsBattle;
  5330. }
  5331.  
  5332. /**
  5333. * Check the floor
  5334. *
  5335. * Проверяем этаж
  5336. */
  5337. function checkFloor(towerInfo) {
  5338. lastTowerInfo = towerInfo;
  5339. maySkipFloor = +towerInfo.maySkipFloor;
  5340. floorNumber = +towerInfo.floorNumber;
  5341. heroesStates = towerInfo.states.heroes;
  5342. floorInfo = towerInfo.floor;
  5343.  
  5344. /**
  5345. * Is there at least one chest open on the floor
  5346. * Открыт ли на этаже хоть один сундук
  5347. */
  5348. isOpenChest = false;
  5349. if (towerInfo.floorType == "chest") {
  5350. isOpenChest = towerInfo.floor.chests.reduce((n, e) => n + e.opened, 0);
  5351. }
  5352.  
  5353. setProgress(`${I18N('TOWER')}: ${I18N('FLOOR')} ${floorNumber}`);
  5354. if (floorNumber > 49) {
  5355. if (isOpenChest) {
  5356. endTower('alreadyOpenChest 50 floor', floorNumber);
  5357. return;
  5358. }
  5359. }
  5360. /**
  5361. * If the chest is open and you can skip floors, then move on
  5362. * Если сундук открыт и можно скипать этажи, то переходим дальше
  5363. */
  5364. if (towerInfo.mayFullSkip && +towerInfo.teamLevel == 130) {
  5365. if (floorNumber == 1) {
  5366. fullSkipTower();
  5367. return;
  5368. }
  5369. if (isOpenChest) {
  5370. nextOpenChest(floorNumber);
  5371. } else {
  5372. nextChestOpen(floorNumber);
  5373. }
  5374. return;
  5375. }
  5376.  
  5377. // console.log(towerInfo, scullCoin);
  5378. switch (towerInfo.floorType) {
  5379. case "battle":
  5380. if (floorNumber <= maySkipFloor) {
  5381. skipFloor();
  5382. return;
  5383. }
  5384. if (floorInfo.state == 2) {
  5385. nextFloor();
  5386. return;
  5387. }
  5388. startBattle().then(endBattle);
  5389. return;
  5390. case "buff":
  5391. checkBuff(towerInfo);
  5392. return;
  5393. case "chest":
  5394. openChest(floorNumber);
  5395. return;
  5396. default:
  5397. console.log('!', towerInfo.floorType, towerInfo);
  5398. break;
  5399. }
  5400. }
  5401.  
  5402. /**
  5403. * Let's start the fight
  5404. *
  5405. * Начинаем бой
  5406. */
  5407. function startBattle() {
  5408. return new Promise(function (resolve, reject) {
  5409. towerStartBattle = {
  5410. calls: [{
  5411. name: "towerStartBattle",
  5412. args: fixHeroesTeam(argsBattle),
  5413. ident: "body"
  5414. }]
  5415. }
  5416. send(JSON.stringify(towerStartBattle), resultBattle, resolve);
  5417. });
  5418. }
  5419. /**
  5420. * Returns the result of the battle in a promise
  5421. *
  5422. * Возращает резульат боя в промис
  5423. */
  5424. function resultBattle(resultBattles, resolve) {
  5425. battleData = resultBattles.results[0].result.response;
  5426. battleType = "get_tower";
  5427. BattleCalc(battleData, battleType, function (result) {
  5428. resolve(result);
  5429. });
  5430. }
  5431. /**
  5432. * Finishing the fight
  5433. *
  5434. * Заканчиваем бой
  5435. */
  5436. function endBattle(battleInfo) {
  5437. if (battleInfo.result.stars >= 3) {
  5438. endBattleCall = {
  5439. calls: [{
  5440. name: "towerEndBattle",
  5441. args: {
  5442. result: battleInfo.result,
  5443. progress: battleInfo.progress,
  5444. },
  5445. ident: "body"
  5446. }]
  5447. }
  5448. send(JSON.stringify(endBattleCall), resultEndBattle);
  5449. } else {
  5450. endTower('towerEndBattle win: false\n', battleInfo);
  5451. }
  5452. }
  5453.  
  5454. /**
  5455. * Getting and processing battle results
  5456. *
  5457. * Получаем и обрабатываем результаты боя
  5458. */
  5459. function resultEndBattle(e) {
  5460. battleResult = e.results[0].result.response;
  5461. if ('error' in battleResult) {
  5462. endTower('errorBattleResult', battleResult);
  5463. return;
  5464. }
  5465. if ('reward' in battleResult) {
  5466. scullCoin += battleResult.reward?.coin[7] ?? 0;
  5467. }
  5468. nextFloor();
  5469. }
  5470.  
  5471. function nextFloor() {
  5472. nextFloorCall = {
  5473. calls: [{
  5474. name: "towerNextFloor",
  5475. args: {},
  5476. ident: "body"
  5477. }]
  5478. }
  5479. send(JSON.stringify(nextFloorCall), checkDataFloor);
  5480. }
  5481.  
  5482. function openChest(floorNumber) {
  5483. floorNumber = floorNumber || 0;
  5484. openChestCall = {
  5485. calls: [{
  5486. name: "towerOpenChest",
  5487. args: {
  5488. num: 2
  5489. },
  5490. ident: "body"
  5491. }]
  5492. }
  5493. send(JSON.stringify(openChestCall), floorNumber < 50 ? nextFloor : lastChest);
  5494. }
  5495.  
  5496. function lastChest() {
  5497. endTower('openChest 50 floor', floorNumber);
  5498. }
  5499.  
  5500. function skipFloor() {
  5501. skipFloorCall = {
  5502. calls: [{
  5503. name: "towerSkipFloor",
  5504. args: {},
  5505. ident: "body"
  5506. }]
  5507. }
  5508. send(JSON.stringify(skipFloorCall), checkDataFloor);
  5509. }
  5510.  
  5511. function checkBuff(towerInfo) {
  5512. buffArr = towerInfo.floor;
  5513. promises = [];
  5514. for (let buff of buffArr) {
  5515. buffInfo = buffIds[buff.id];
  5516. if (buffInfo.isBuy && buffInfo.cost <= scullCoin) {
  5517. scullCoin -= buffInfo.cost;
  5518. promises.push(buyBuff(buff.id));
  5519. }
  5520. }
  5521. Promise.all(promises).then(nextFloor);
  5522. }
  5523.  
  5524. function buyBuff(buffId) {
  5525. return new Promise(function (resolve, reject) {
  5526. buyBuffCall = {
  5527. calls: [{
  5528. name: "towerBuyBuff",
  5529. args: {
  5530. buffId
  5531. },
  5532. ident: "body"
  5533. }]
  5534. }
  5535. send(JSON.stringify(buyBuffCall), resolve);
  5536. });
  5537. }
  5538.  
  5539. function checkDataFloor(result) {
  5540. towerInfo = result.results[0].result.response;
  5541. if ('reward' in towerInfo && towerInfo.reward?.coin) {
  5542. scullCoin += towerInfo.reward?.coin[7] ?? 0;
  5543. }
  5544. if ('tower' in towerInfo) {
  5545. towerInfo = towerInfo.tower;
  5546. }
  5547. if ('skullReward' in towerInfo) {
  5548. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  5549. }
  5550. checkFloor(towerInfo);
  5551. }
  5552. /**
  5553. * Getting tower rewards
  5554. *
  5555. * Получаем награды башни
  5556. */
  5557. function farmTowerRewards(reason) {
  5558. let { pointRewards, points } = lastTowerInfo;
  5559. let pointsAll = Object.getOwnPropertyNames(pointRewards);
  5560. let farmPoints = pointsAll.filter(e => +e <= +points && !pointRewards[e]);
  5561. if (!farmPoints.length) {
  5562. return;
  5563. }
  5564. let farmTowerRewardsCall = {
  5565. calls: [{
  5566. name: "tower_farmPointRewards",
  5567. args: {
  5568. points: farmPoints
  5569. },
  5570. ident: "tower_farmPointRewards"
  5571. }]
  5572. }
  5573.  
  5574. if (scullCoin > 0) {
  5575. farmTowerRewardsCall.calls.push({
  5576. name: "tower_farmSkullReward",
  5577. args: {},
  5578. ident: "tower_farmSkullReward"
  5579. });
  5580. }
  5581.  
  5582. send(JSON.stringify(farmTowerRewardsCall), () => { });
  5583. }
  5584.  
  5585. function fullSkipTower() {
  5586. /**
  5587. * Next chest
  5588. *
  5589. * Следующий сундук
  5590. */
  5591. function nextChest(n) {
  5592. return {
  5593. name: "towerNextChest",
  5594. args: {},
  5595. ident: "group_" + n + "_body"
  5596. }
  5597. }
  5598. /**
  5599. * Open chest
  5600. *
  5601. * Открыть сундук
  5602. */
  5603. function openChest(n) {
  5604. return {
  5605. name: "towerOpenChest",
  5606. args: {
  5607. "num": 2
  5608. },
  5609. ident: "group_" + n + "_body"
  5610. }
  5611. }
  5612.  
  5613. const fullSkipTowerCall = {
  5614. calls: []
  5615. }
  5616.  
  5617. let n = 0;
  5618. for (let i = 0; i < 15; i++) {
  5619. // 15 сундуков
  5620. fullSkipTowerCall.calls.push(nextChest(++n));
  5621. fullSkipTowerCall.calls.push(openChest(++n));
  5622. // +5 сундуков, 250 изюма // towerOpenChest
  5623. // if (i < 5) {
  5624. // fullSkipTowerCall.calls.push(openChest(++n, 2));
  5625. // }
  5626. }
  5627.  
  5628. fullSkipTowerCall.calls.push({
  5629. name: 'towerGetInfo',
  5630. args: {},
  5631. ident: 'group_' + ++n + '_body',
  5632. });
  5633.  
  5634. send(JSON.stringify(fullSkipTowerCall), data => {
  5635. for (const r of data.results) {
  5636. const towerInfo = r?.result?.response;
  5637. if (towerInfo && 'skullReward' in towerInfo) {
  5638. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  5639. }
  5640. }
  5641. data.results[0] = data.results[data.results.length - 1];
  5642. checkDataFloor(data);
  5643. });
  5644. }
  5645.  
  5646. function nextChestOpen(floorNumber) {
  5647. const calls = [{
  5648. name: "towerOpenChest",
  5649. args: {
  5650. num: 2
  5651. },
  5652. ident: "towerOpenChest"
  5653. }];
  5654.  
  5655. Send(JSON.stringify({ calls })).then(e => {
  5656. nextOpenChest(floorNumber);
  5657. });
  5658. }
  5659.  
  5660. function nextOpenChest(floorNumber) {
  5661. if (floorNumber > 49) {
  5662. endTower('openChest 50 floor', floorNumber);
  5663. return;
  5664. }
  5665.  
  5666. let nextOpenChestCall = {
  5667. calls: [{
  5668. name: "towerNextChest",
  5669. args: {},
  5670. ident: "towerNextChest"
  5671. }, {
  5672. name: "towerOpenChest",
  5673. args: {
  5674. num: 2
  5675. },
  5676. ident: "towerOpenChest"
  5677. }]
  5678. }
  5679. send(JSON.stringify(nextOpenChestCall), checkDataFloor);
  5680. }
  5681.  
  5682. function endTower(reason, info) {
  5683. console.log(reason, info);
  5684. if (reason != 'noTower') {
  5685. farmTowerRewards(reason);
  5686. }
  5687. setProgress(`${I18N('TOWER')} ${I18N('COMPLETED')}!`, true);
  5688. resolve();
  5689. }
  5690. }
  5691.  
  5692. /**
  5693. * Passage of the arena of the titans
  5694. *
  5695. * Прохождение арены титанов
  5696. */
  5697. function testTitanArena() {
  5698. return new Promise((resolve, reject) => {
  5699. titAren = new executeTitanArena(resolve, reject);
  5700. titAren.start();
  5701. });
  5702. }
  5703.  
  5704. /**
  5705. * Passage of the arena of the titans
  5706. *
  5707. * Прохождение арены титанов
  5708. */
  5709. function executeTitanArena(resolve, reject) {
  5710. let titan_arena = [];
  5711. let finishListBattle = [];
  5712. /**
  5713. * ID of the current batch
  5714. *
  5715. * Идетификатор текущей пачки
  5716. */
  5717. let currentRival = 0;
  5718. /**
  5719. * Number of attempts to finish off the pack
  5720. *
  5721. * Количество попыток добития пачки
  5722. */
  5723. let attempts = 0;
  5724. /**
  5725. * Was there an attempt to finish off the current shooting range
  5726. *
  5727. * Была ли попытка добития текущего тира
  5728. */
  5729. let isCheckCurrentTier = false;
  5730. /**
  5731. * Current shooting range
  5732. *
  5733. * Текущий тир
  5734. */
  5735. let currTier = 0;
  5736. /**
  5737. * Number of battles on the current dash
  5738. *
  5739. * Количество битв на текущем тире
  5740. */
  5741. let countRivalsTier = 0;
  5742.  
  5743. let callsStart = {
  5744. calls: [{
  5745. name: "titanArenaGetStatus",
  5746. args: {},
  5747. ident: "titanArenaGetStatus"
  5748. }, {
  5749. name: "teamGetAll",
  5750. args: {},
  5751. ident: "teamGetAll"
  5752. }]
  5753. }
  5754.  
  5755. this.start = function () {
  5756. send(JSON.stringify(callsStart), startTitanArena);
  5757. }
  5758.  
  5759. function startTitanArena(data) {
  5760. let titanArena = data.results[0].result.response;
  5761. if (titanArena.status == 'disabled') {
  5762. endTitanArena('disabled', titanArena);
  5763. return;
  5764. }
  5765.  
  5766. let teamGetAll = data.results[1].result.response;
  5767. titan_arena = teamGetAll.titan_arena;
  5768.  
  5769. checkTier(titanArena)
  5770. }
  5771.  
  5772. function checkTier(titanArena) {
  5773. if (titanArena.status == "peace_time") {
  5774. endTitanArena('Peace_time', titanArena);
  5775. return;
  5776. }
  5777. currTier = titanArena.tier;
  5778. if (currTier) {
  5779. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier}`);
  5780. }
  5781.  
  5782. if (titanArena.status == "completed_tier") {
  5783. titanArenaCompleteTier();
  5784. return;
  5785. }
  5786. /**
  5787. * Checking for the possibility of a raid
  5788. * Проверка на возможность рейда
  5789. */
  5790. if (titanArena.canRaid) {
  5791. titanArenaStartRaid();
  5792. return;
  5793. }
  5794. /**
  5795. * Check was an attempt to achieve the current shooting range
  5796. * Проверка была ли попытка добития текущего тира
  5797. */
  5798. if (!isCheckCurrentTier) {
  5799. checkRivals(titanArena.rivals);
  5800. return;
  5801. }
  5802.  
  5803. endTitanArena('Done or not canRaid', titanArena);
  5804. }
  5805. /**
  5806. * Submit dash information for verification
  5807. *
  5808. * Отправка информации о тире на проверку
  5809. */
  5810. function checkResultInfo(data) {
  5811. let titanArena = data.results[0].result.response;
  5812. checkTier(titanArena);
  5813. }
  5814. /**
  5815. * Finish the current tier
  5816. *
  5817. * Завершить текущий тир
  5818. */
  5819. function titanArenaCompleteTier() {
  5820. isCheckCurrentTier = false;
  5821. let calls = [{
  5822. name: "titanArenaCompleteTier",
  5823. args: {},
  5824. ident: "body"
  5825. }];
  5826. send(JSON.stringify({calls}), checkResultInfo);
  5827. }
  5828. /**
  5829. * Gathering points to be completed
  5830. *
  5831. * Собираем точки которые нужно добить
  5832. */
  5833. function checkRivals(rivals) {
  5834. finishListBattle = [];
  5835. for (let n in rivals) {
  5836. if (rivals[n].attackScore < 250) {
  5837. finishListBattle.push(n);
  5838. }
  5839. }
  5840. console.log('checkRivals', finishListBattle);
  5841. countRivalsTier = finishListBattle.length;
  5842. roundRivals();
  5843. }
  5844. /**
  5845. * Selecting the next point to finish off
  5846. *
  5847. * Выбор следующей точки для добития
  5848. */
  5849. function roundRivals() {
  5850. let countRivals = finishListBattle.length;
  5851. if (!countRivals) {
  5852. /**
  5853. * Whole range checked
  5854. *
  5855. * Весь тир проверен
  5856. */
  5857. isCheckCurrentTier = true;
  5858. titanArenaGetStatus();
  5859. return;
  5860. }
  5861. // setProgress('TitanArena: Уровень ' + currTier + ' Бои: ' + (countRivalsTier - countRivals + 1) + '/' + countRivalsTier);
  5862. currentRival = finishListBattle.pop();
  5863. attempts = +currentRival;
  5864. // console.log('roundRivals', currentRival);
  5865. titanArenaStartBattle(currentRival);
  5866. }
  5867. /**
  5868. * The start of a solo battle
  5869. *
  5870. * Начало одиночной битвы
  5871. */
  5872. function titanArenaStartBattle(rivalId) {
  5873. let calls = [{
  5874. name: "titanArenaStartBattle",
  5875. args: {
  5876. rivalId: rivalId,
  5877. titans: titan_arena
  5878. },
  5879. ident: "body"
  5880. }];
  5881. send(JSON.stringify({calls}), calcResult);
  5882. }
  5883. /**
  5884. * Calculation of the results of the battle
  5885. *
  5886. * Расчет результатов боя
  5887. */
  5888. function calcResult(data) {
  5889. let battlesInfo = data.results[0].result.response.battle;
  5890. /**
  5891. * If attempts are equal to the current battle number we make
  5892. * Если попытки равны номеру текущего боя делаем прерасчет
  5893. */
  5894. if (attempts == currentRival) {
  5895. preCalcBattle(battlesInfo);
  5896. return;
  5897. }
  5898. /**
  5899. * If there are still attempts, we calculate a new battle
  5900. * Если попытки еще есть делаем расчет нового боя
  5901. */
  5902. if (attempts > 0) {
  5903. attempts--;
  5904. calcBattleResult(battlesInfo)
  5905. .then(resultCalcBattle);
  5906. return;
  5907. }
  5908. /**
  5909. * Otherwise, go to the next opponent
  5910. * Иначе переходим к следующему сопернику
  5911. */
  5912. roundRivals();
  5913. }
  5914. /**
  5915. * Processing the results of the battle calculation
  5916. *
  5917. * Обработка результатов расчета битвы
  5918. */
  5919. function resultCalcBattle(resultBattle) {
  5920. // console.log('resultCalcBattle', currentRival, attempts, resultBattle.result.win);
  5921. /**
  5922. * If the current calculation of victory is not a chance or the attempt ended with the finish the battle
  5923. * Если текущий расчет победа или шансов нет или попытки кончились завершаем бой
  5924. */
  5925. if (resultBattle.result.win || !attempts) {
  5926. titanArenaEndBattle({
  5927. progress: resultBattle.progress,
  5928. result: resultBattle.result,
  5929. rivalId: resultBattle.battleData.typeId
  5930. });
  5931. return;
  5932. }
  5933. /**
  5934. * If not victory and there are attempts we start a new battle
  5935. * Если не победа и есть попытки начинаем новый бой
  5936. */
  5937. titanArenaStartBattle(resultBattle.battleData.typeId);
  5938. }
  5939. /**
  5940. * Returns the promise of calculating the results of the battle
  5941. *
  5942. * Возращает промис расчета результатов битвы
  5943. */
  5944. function getBattleInfo(battle, isRandSeed) {
  5945. return new Promise(function (resolve) {
  5946. if (isRandSeed) {
  5947. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  5948. }
  5949. // console.log(battle.seed);
  5950. BattleCalc(battle, "get_titanClanPvp", e => resolve(e));
  5951. });
  5952. }
  5953. /**
  5954. * Recalculate battles
  5955. *
  5956. * Прерасчтет битвы
  5957. */
  5958. function preCalcBattle(battle) {
  5959. let actions = [getBattleInfo(battle, false)];
  5960. const countTestBattle = getInput('countTestBattle');
  5961. for (let i = 0; i < countTestBattle; i++) {
  5962. actions.push(getBattleInfo(battle, true));
  5963. }
  5964. Promise.all(actions)
  5965. .then(resultPreCalcBattle);
  5966. }
  5967. /**
  5968. * Processing the results of the battle recalculation
  5969. *
  5970. * Обработка результатов прерасчета битвы
  5971. */
  5972. function resultPreCalcBattle(e) {
  5973. let wins = e.map(n => n.result.win);
  5974. let firstBattle = e.shift();
  5975. let countWin = wins.reduce((w, s) => w + s);
  5976. const countTestBattle = getInput('countTestBattle');
  5977. console.log('resultPreCalcBattle', `${countWin}/${countTestBattle}`)
  5978. if (countWin > 0) {
  5979. attempts = getInput('countAutoBattle');
  5980. } else {
  5981. attempts = 0;
  5982. }
  5983. resultCalcBattle(firstBattle);
  5984. }
  5985.  
  5986. /**
  5987. * Complete an arena battle
  5988. *
  5989. * Завершить битву на арене
  5990. */
  5991. function titanArenaEndBattle(args) {
  5992. let calls = [{
  5993. name: "titanArenaEndBattle",
  5994. args,
  5995. ident: "body"
  5996. }];
  5997. send(JSON.stringify({calls}), resultTitanArenaEndBattle);
  5998. }
  5999.  
  6000. function resultTitanArenaEndBattle(e) {
  6001. let attackScore = e.results[0].result.response.attackScore;
  6002. let numReval = countRivalsTier - finishListBattle.length;
  6003. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier} </br>${I18N('BATTLES')}: ${numReval}/${countRivalsTier} - ${attackScore}`);
  6004. /**
  6005. * TODO: Might need to improve the results.
  6006. * TODO: Возможно стоит сделать улучшение результатов
  6007. */
  6008. // console.log('resultTitanArenaEndBattle', e)
  6009. console.log('resultTitanArenaEndBattle', numReval + '/' + countRivalsTier, attempts)
  6010. roundRivals();
  6011. }
  6012. /**
  6013. * Arena State
  6014. *
  6015. * Состояние арены
  6016. */
  6017. function titanArenaGetStatus() {
  6018. let calls = [{
  6019. name: "titanArenaGetStatus",
  6020. args: {},
  6021. ident: "body"
  6022. }];
  6023. send(JSON.stringify({calls}), checkResultInfo);
  6024. }
  6025. /**
  6026. * Arena Raid Request
  6027. *
  6028. * Запрос рейда арены
  6029. */
  6030. function titanArenaStartRaid() {
  6031. let calls = [{
  6032. name: "titanArenaStartRaid",
  6033. args: {
  6034. titans: titan_arena
  6035. },
  6036. ident: "body"
  6037. }];
  6038. send(JSON.stringify({calls}), calcResults);
  6039. }
  6040.  
  6041. function calcResults(data) {
  6042. let battlesInfo = data.results[0].result.response;
  6043. let {attackers, rivals} = battlesInfo;
  6044.  
  6045. let promises = [];
  6046. for (let n in rivals) {
  6047. rival = rivals[n];
  6048. promises.push(calcBattleResult({
  6049. attackers: attackers,
  6050. defenders: [rival.team],
  6051. seed: rival.seed,
  6052. typeId: n,
  6053. }));
  6054. }
  6055.  
  6056. Promise.all(promises)
  6057. .then(results => {
  6058. const endResults = {};
  6059. for (let info of results) {
  6060. let id = info.battleData.typeId;
  6061. endResults[id] = {
  6062. progress: info.progress,
  6063. result: info.result,
  6064. }
  6065. }
  6066. titanArenaEndRaid(endResults);
  6067. });
  6068. }
  6069.  
  6070. function calcBattleResult(battleData) {
  6071. return new Promise(function (resolve, reject) {
  6072. BattleCalc(battleData, "get_titanClanPvp", resolve);
  6073. });
  6074. }
  6075.  
  6076. /**
  6077. * Sending Raid Results
  6078. *
  6079. * Отправка результатов рейда
  6080. */
  6081. function titanArenaEndRaid(results) {
  6082. titanArenaEndRaidCall = {
  6083. calls: [{
  6084. name: "titanArenaEndRaid",
  6085. args: {
  6086. results
  6087. },
  6088. ident: "body"
  6089. }]
  6090. }
  6091. send(JSON.stringify(titanArenaEndRaidCall), checkRaidResults);
  6092. }
  6093.  
  6094. function checkRaidResults(data) {
  6095. results = data.results[0].result.response.results;
  6096. isSucsesRaid = true;
  6097. for (let i in results) {
  6098. isSucsesRaid &&= (results[i].attackScore >= 250);
  6099. }
  6100.  
  6101. if (isSucsesRaid) {
  6102. titanArenaCompleteTier();
  6103. } else {
  6104. titanArenaGetStatus();
  6105. }
  6106. }
  6107.  
  6108. function titanArenaFarmDailyReward() {
  6109. titanArenaFarmDailyRewardCall = {
  6110. calls: [{
  6111. name: "titanArenaFarmDailyReward",
  6112. args: {},
  6113. ident: "body"
  6114. }]
  6115. }
  6116. send(JSON.stringify(titanArenaFarmDailyRewardCall), () => {console.log('Done farm daily reward')});
  6117. }
  6118.  
  6119. function endTitanArena(reason, info) {
  6120. if (!['Peace_time', 'disabled'].includes(reason)) {
  6121. titanArenaFarmDailyReward();
  6122. }
  6123. console.log(reason, info);
  6124. setProgress(`${I18N('TITAN_ARENA')} ${I18N('COMPLETED')}!`, true);
  6125. resolve();
  6126. }
  6127. }
  6128.  
  6129. function hackGame() {
  6130. const self = this;
  6131. selfGame = null;
  6132. bindId = 1e9;
  6133. this.libGame = null;
  6134.  
  6135. /**
  6136. * List of correspondence of used classes to their names
  6137. *
  6138. * Список соответствия используемых классов их названиям
  6139. */
  6140. ObjectsList = [
  6141. { name: 'BattlePresets', prop: 'game.battle.controller.thread.BattlePresets' },
  6142. { name: 'DataStorage', prop: 'game.data.storage.DataStorage' },
  6143. { name: 'BattleConfigStorage', prop: 'game.data.storage.battle.BattleConfigStorage' },
  6144. { name: 'BattleInstantPlay', prop: 'game.battle.controller.instant.BattleInstantPlay' },
  6145. { name: 'MultiBattleInstantReplay', prop: 'game.battle.controller.instant.MultiBattleInstantReplay' },
  6146. { name: 'MultiBattleResult', prop: 'game.battle.controller.MultiBattleResult' },
  6147.  
  6148. { name: 'PlayerMissionData', prop: 'game.model.user.mission.PlayerMissionData' },
  6149. { name: 'PlayerMissionBattle', prop: 'game.model.user.mission.PlayerMissionBattle' },
  6150. { name: 'GameModel', prop: 'game.model.GameModel' },
  6151. { name: 'CommandManager', prop: 'game.command.CommandManager' },
  6152. { name: 'MissionCommandList', prop: 'game.command.rpc.mission.MissionCommandList' },
  6153. { name: 'RPCCommandBase', prop: 'game.command.rpc.RPCCommandBase' },
  6154. { name: 'PlayerTowerData', prop: 'game.model.user.tower.PlayerTowerData' },
  6155. { name: 'TowerCommandList', prop: 'game.command.tower.TowerCommandList' },
  6156. { name: 'PlayerHeroTeamResolver', prop: 'game.model.user.hero.PlayerHeroTeamResolver' },
  6157. { name: 'BattlePausePopup', prop: 'game.view.popup.battle.BattlePausePopup' },
  6158. { name: 'BattlePopup', prop: 'game.view.popup.battle.BattlePopup' },
  6159. { name: 'DisplayObjectContainer', prop: 'starling.display.DisplayObjectContainer' },
  6160. { name: 'GuiClipContainer', prop: 'engine.core.clipgui.GuiClipContainer' },
  6161. { name: 'BattlePausePopupClip', prop: 'game.view.popup.battle.BattlePausePopupClip' },
  6162. { name: 'ClipLabel', prop: 'game.view.gui.components.ClipLabel' },
  6163. { name: 'ClipLabelBase', prop: 'game.view.gui.components.ClipLabelBase' },
  6164. { name: 'Translate', prop: 'com.progrestar.common.lang.Translate' },
  6165. { name: 'ClipButtonLabeledCentered', prop: 'game.view.gui.components.ClipButtonLabeledCentered' },
  6166. { name: 'BattlePausePopupMediator', prop: 'game.mediator.gui.popup.battle.BattlePausePopupMediator' },
  6167. { name: 'SettingToggleButton', prop: 'game.mechanics.settings.popup.view.SettingToggleButton' },
  6168. { name: 'PlayerDungeonData', prop: 'game.mechanics.dungeon.model.PlayerDungeonData' },
  6169. { name: 'NextDayUpdatedManager', prop: 'game.model.user.NextDayUpdatedManager' },
  6170. { name: 'BattleController', prop: 'game.battle.controller.BattleController' },
  6171. { name: 'BattleSettingsModel', prop: 'game.battle.controller.BattleSettingsModel' },
  6172. { name: 'BooleanProperty', prop: 'engine.core.utils.property.BooleanProperty' },
  6173. { name: 'RuleStorage', prop: 'game.data.storage.rule.RuleStorage' },
  6174. { name: 'BattleConfig', prop: 'battle.BattleConfig' },
  6175. { name: 'BattleGuiMediator', prop: 'game.battle.gui.BattleGuiMediator' },
  6176. { name: 'BooleanPropertyWriteable', prop: 'engine.core.utils.property.BooleanPropertyWriteable' },
  6177. { name: 'BattleLogEncoder', prop: 'battle.log.BattleLogEncoder' },
  6178. { name: 'BattleLogReader', prop: 'battle.log.BattleLogReader' },
  6179. { name: 'PlayerSubscriptionInfoValueObject', prop: 'game.model.user.subscription.PlayerSubscriptionInfoValueObject' },
  6180. { name: 'AdventureMapCamera', prop: 'game.mechanics.adventure.popup.map.AdventureMapCamera' },
  6181. ];
  6182.  
  6183. /**
  6184. * Contains the game classes needed to write and override game methods
  6185. *
  6186. * Содержит классы игры необходимые для написания и подмены методов игры
  6187. */
  6188. Game = {
  6189. /**
  6190. * Function 'e'
  6191. * Функция 'e'
  6192. */
  6193. bindFunc: function (a, b) {
  6194. if (null == b)
  6195. return null;
  6196. null == b.__id__ && (b.__id__ = bindId++);
  6197. var c;
  6198. null == a.hx__closures__ ? a.hx__closures__ = {} :
  6199. c = a.hx__closures__[b.__id__];
  6200. null == c && (c = b.bind(a), a.hx__closures__[b.__id__] = c);
  6201. return c
  6202. },
  6203. };
  6204.  
  6205. /**
  6206. * Connects to game objects via the object creation event
  6207. *
  6208. * Подключается к объектам игры через событие создания объекта
  6209. */
  6210. function connectGame() {
  6211. for (let obj of ObjectsList) {
  6212. /**
  6213. * https: //stackoverflow.com/questions/42611719/how-to-intercept-and-modify-a-specific-property-for-any-object
  6214. */
  6215. Object.defineProperty(Object.prototype, obj.prop, {
  6216. set: function (value) {
  6217. if (!selfGame) {
  6218. selfGame = this;
  6219. }
  6220. if (!Game[obj.name]) {
  6221. Game[obj.name] = value;
  6222. }
  6223. // console.log('set ' + obj.prop, this, value);
  6224. this[obj.prop + '_'] = value;
  6225. },
  6226. get: function () {
  6227. // console.log('get ' + obj.prop, this);
  6228. return this[obj.prop + '_'];
  6229. }
  6230. });
  6231. }
  6232. }
  6233.  
  6234. /**
  6235. * Game.BattlePresets
  6236. * @param {bool} a isReplay
  6237. * @param {bool} b autoToggleable
  6238. * @param {bool} c auto On Start
  6239. * @param {object} d config
  6240. * @param {bool} f showBothTeams
  6241. */
  6242. /**
  6243. * Returns the results of the battle to the callback function
  6244. * Возвращает в функцию callback результаты боя
  6245. * @param {*} battleData battle data данные боя
  6246. * @param {*} battleConfig combat configuration type options:
  6247. *
  6248. * тип конфигурации боя варианты:
  6249. *
  6250. * "get_invasion", "get_titanPvpManual", "get_titanPvp",
  6251. * "get_titanClanPvp","get_clanPvp","get_titan","get_boss",
  6252. * "get_tower","get_pve","get_pvpManual","get_pvp","get_core"
  6253. *
  6254. * You can specify the xYc function in the game.assets.storage.BattleAssetStorage class
  6255. *
  6256. * Можно уточнить в классе game.assets.storage.BattleAssetStorage функция xYc
  6257. * @param {*} callback функция в которую вернуться результаты боя
  6258. */
  6259. this.BattleCalc = function (battleData, battleConfig, callback) {
  6260. // battleConfig = battleConfig || getBattleType(battleData.type)
  6261. if (!Game.BattlePresets) throw Error('Use connectGame');
  6262. battlePresets = new Game.BattlePresets(battleData.progress, !1, !0, Game.DataStorage[getFn(Game.DataStorage, 24)][getF(Game.BattleConfigStorage, battleConfig)](), !1);
  6263. let battleInstantPlay;
  6264. if (battleData.progress?.length > 1) {
  6265. battleInstantPlay = new Game.MultiBattleInstantReplay(battleData, battlePresets);
  6266. } else {
  6267. battleInstantPlay = new Game.BattleInstantPlay(battleData, battlePresets);
  6268. }
  6269. battleInstantPlay[getProtoFn(Game.BattleInstantPlay, 9)].add((battleInstant) => {
  6270. const MBR_2 = getProtoFn(Game.MultiBattleResult, 2);
  6271. const battleResults = battleInstant[getF(Game.BattleInstantPlay, 'get_result')]();
  6272. const battleData = battleInstant[getF(Game.BattleInstantPlay, 'get_rawBattleInfo')]();
  6273. const battleLogs = [];
  6274. const timeLimit = battlePresets[getF(Game.BattlePresets, 'get_timeLimit')]();
  6275. let battleTime = 0;
  6276. let battleTimer = 0;
  6277. for (const battleResult of battleResults[MBR_2]) {
  6278. const battleLog = Game.BattleLogEncoder.read(new Game.BattleLogReader(battleResult));
  6279. battleLogs.push(battleLog);
  6280. const maxTime = Math.max(...battleLog.map((e) => (e.time < timeLimit && e.time !== 168.8 ? e.time : 0)));
  6281. battleTimer += getTimer(maxTime)
  6282. battleTime += maxTime;
  6283. }
  6284. callback({
  6285. battleLogs,
  6286. battleTime,
  6287. battleTimer,
  6288. battleData,
  6289. progress: battleResults[getF(Game.MultiBattleResult, 'get_progress')](),
  6290. result: battleResults[getF(Game.MultiBattleResult, 'get_result')](),
  6291. });
  6292. });
  6293. battleInstantPlay.start();
  6294. }
  6295.  
  6296. /**
  6297. * Returns a function with the specified name from the class
  6298. *
  6299. * Возвращает из класса функцию с указанным именем
  6300. * @param {Object} classF Class // класс
  6301. * @param {String} nameF function name // имя функции
  6302. * @param {String} pos name and alias order // порядок имени и псевдонима
  6303. * @returns
  6304. */
  6305. function getF(classF, nameF, pos) {
  6306. pos = pos || false;
  6307. let prop = Object.entries(classF.prototype.__properties__)
  6308. if (!pos) {
  6309. return prop.filter((e) => e[1] == nameF).pop()[0];
  6310. } else {
  6311. return prop.filter((e) => e[0] == nameF).pop()[1];
  6312. }
  6313. }
  6314.  
  6315. /**
  6316. * Returns a function with the specified name from the class
  6317. *
  6318. * Возвращает из класса функцию с указанным именем
  6319. * @param {Object} classF Class // класс
  6320. * @param {String} nameF function name // имя функции
  6321. * @returns
  6322. */
  6323. function getFnP(classF, nameF) {
  6324. let prop = Object.entries(classF.__properties__)
  6325. return prop.filter((e) => e[1] == nameF).pop()[0];
  6326. }
  6327.  
  6328. /**
  6329. * Returns the function name with the specified ordinal from the class
  6330. *
  6331. * Возвращает имя функции с указаным порядковым номером из класса
  6332. * @param {Object} classF Class // класс
  6333. * @param {Number} nF Order number of function // порядковый номер функции
  6334. * @returns
  6335. */
  6336. function getFn(classF, nF) {
  6337. let prop = Object.keys(classF);
  6338. return prop[nF];
  6339. }
  6340.  
  6341. /**
  6342. * Returns the name of the function with the specified serial number from the prototype of the class
  6343. *
  6344. * Возвращает имя функции с указаным порядковым номером из прототипа класса
  6345. * @param {Object} classF Class // класс
  6346. * @param {Number} nF Order number of function // порядковый номер функции
  6347. * @returns
  6348. */
  6349. function getProtoFn(classF, nF) {
  6350. let prop = Object.keys(classF.prototype);
  6351. return prop[nF];
  6352. }
  6353. /**
  6354. * Description of replaced functions
  6355. *
  6356. * Описание подменяемых функций
  6357. */
  6358. replaceFunction = {
  6359. company: function () {
  6360. let PMD_12 = getProtoFn(Game.PlayerMissionData, 12);
  6361. let oldSkipMisson = Game.PlayerMissionData.prototype[PMD_12];
  6362. Game.PlayerMissionData.prototype[PMD_12] = function (a, b, c) {
  6363. if (!isChecked('passBattle')) {
  6364. oldSkipMisson.call(this, a, b, c);
  6365. return;
  6366. }
  6367.  
  6368. try {
  6369. this[getProtoFn(Game.PlayerMissionData, 9)] = new Game.PlayerMissionBattle(a, b, c);
  6370.  
  6371. var a = new Game.BattlePresets(
  6372. !1,
  6373. !1,
  6374. !0,
  6375. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  6376. !1
  6377. );
  6378. a = new Game.BattleInstantPlay(c, a);
  6379. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6380. a.start();
  6381. } catch (error) {
  6382. console.error('company', error);
  6383. oldSkipMisson.call(this, a, b, c);
  6384. }
  6385. };
  6386.  
  6387. Game.PlayerMissionData.prototype.P$h = function (a) {
  6388. let GM_2 = getFn(Game.GameModel, 2);
  6389. let GM_P2 = getProtoFn(Game.GameModel, 2);
  6390. let CM_20 = getProtoFn(Game.CommandManager, 20);
  6391. let MCL_2 = getProtoFn(Game.MissionCommandList, 2);
  6392. let MBR_15 = getF(Game.MultiBattleResult, 'get_result');
  6393. let RPCCB_15 = getProtoFn(Game.RPCCommandBase, 16);
  6394. let PMD_32 = getProtoFn(Game.PlayerMissionData, 32);
  6395. Game.GameModel[GM_2]()[GM_P2][CM_20][MCL_2](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PMD_32]));
  6396. };
  6397. },
  6398. /*
  6399. tower: function () {
  6400. let PTD_67 = getProtoFn(Game.PlayerTowerData, 67);
  6401. let oldSkipTower = Game.PlayerTowerData.prototype[PTD_67];
  6402. Game.PlayerTowerData.prototype[PTD_67] = function (a) {
  6403. if (!isChecked('passBattle')) {
  6404. oldSkipTower.call(this, a);
  6405. return;
  6406. }
  6407. try {
  6408. var p = new Game.BattlePresets(
  6409. !1,
  6410. !1,
  6411. !0,
  6412. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  6413. !1
  6414. );
  6415. a = new Game.BattleInstantPlay(a, p);
  6416. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6417. a.start();
  6418. } catch (error) {
  6419. console.error('tower', error);
  6420. oldSkipMisson.call(this, a, b, c);
  6421. }
  6422. };
  6423.  
  6424. Game.PlayerTowerData.prototype.P$h = function (a) {
  6425. const GM_2 = getFnP(Game.GameModel, 'get_instance');
  6426. const GM_P2 = getProtoFn(Game.GameModel, 2);
  6427. const CM_29 = getProtoFn(Game.CommandManager, 29);
  6428. const TCL_5 = getProtoFn(Game.TowerCommandList, 5);
  6429. const MBR_15 = getF(Game.MultiBattleResult, 'get_result');
  6430. const RPCCB_15 = getProtoFn(Game.RPCCommandBase, 17);
  6431. const PTD_78 = getProtoFn(Game.PlayerTowerData, 78);
  6432. Game.GameModel[GM_2]()[GM_P2][CM_29][TCL_5](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PTD_78]));
  6433. };
  6434. },
  6435. */
  6436. // skipSelectHero: function() {
  6437. // if (!HOST) throw Error('Use connectGame');
  6438. // Game.PlayerHeroTeamResolver.prototype[getProtoFn(Game.PlayerHeroTeamResolver, 3)] = () => false;
  6439. // },
  6440. passBattle: function () {
  6441. let BPP_4 = getProtoFn(Game.BattlePausePopup, 4);
  6442. let oldPassBattle = Game.BattlePausePopup.prototype[BPP_4];
  6443. Game.BattlePausePopup.prototype[BPP_4] = function (a) {
  6444. if (!isChecked('passBattle')) {
  6445. oldPassBattle.call(this, a);
  6446. return;
  6447. }
  6448. try {
  6449. Game.BattlePopup.prototype[getProtoFn(Game.BattlePausePopup, 4)].call(this, a);
  6450. this[getProtoFn(Game.BattlePausePopup, 3)]();
  6451. this[getProtoFn(Game.DisplayObjectContainer, 3)](this.clip[getProtoFn(Game.GuiClipContainer, 2)]());
  6452. this.clip[getProtoFn(Game.BattlePausePopupClip, 1)][getProtoFn(Game.ClipLabelBase, 9)](
  6453. Game.Translate.translate('UI_POPUP_BATTLE_PAUSE')
  6454. );
  6455.  
  6456. this.clip[getProtoFn(Game.BattlePausePopupClip, 2)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  6457. Game.Translate.translate('UI_POPUP_BATTLE_RETREAT'),
  6458. ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 17)]))
  6459. );
  6460. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  6461. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 14)](),
  6462. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 13)]()
  6463. ? ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  6464. : ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  6465. );
  6466.  
  6467. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 0)][
  6468. getProtoFn(Game.ClipLabelBase, 24)
  6469. ]();
  6470. this.clip[getProtoFn(Game.BattlePausePopupClip, 3)][getProtoFn(Game.SettingToggleButton, 3)](
  6471. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 9)]()
  6472. );
  6473. this.clip[getProtoFn(Game.BattlePausePopupClip, 4)][getProtoFn(Game.SettingToggleButton, 3)](
  6474. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 10)]()
  6475. );
  6476. this.clip[getProtoFn(Game.BattlePausePopupClip, 6)][getProtoFn(Game.SettingToggleButton, 3)](
  6477. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 11)]()
  6478. );
  6479. } catch (error) {
  6480. console.error('passBattle', error);
  6481. oldPassBattle.call(this, a);
  6482. }
  6483. };
  6484.  
  6485. let retreatButtonLabel = getF(Game.BattlePausePopupMediator, 'get_retreatButtonLabel');
  6486. let oldFunc = Game.BattlePausePopupMediator.prototype[retreatButtonLabel];
  6487. Game.BattlePausePopupMediator.prototype[retreatButtonLabel] = function () {
  6488. if (isChecked('passBattle')) {
  6489. return I18N('BTN_PASS');
  6490. } else {
  6491. return oldFunc.call(this);
  6492. }
  6493. };
  6494. },
  6495. endlessCards: function () {
  6496. let PDD_21 = getProtoFn(Game.PlayerDungeonData, 21);
  6497. let oldEndlessCards = Game.PlayerDungeonData.prototype[PDD_21];
  6498. Game.PlayerDungeonData.prototype[PDD_21] = function () {
  6499. if (countPredictionCard <= 0) {
  6500. return true;
  6501. } else {
  6502. return oldEndlessCards.call(this);
  6503. }
  6504. };
  6505. },
  6506. speedBattle: function () {
  6507. const get_timeScale = getF(Game.BattleController, 'get_timeScale');
  6508. const oldSpeedBattle = Game.BattleController.prototype[get_timeScale];
  6509. Game.BattleController.prototype[get_timeScale] = function () {
  6510. const speedBattle = Number.parseFloat(getInput('speedBattle'));
  6511. if (!speedBattle) {
  6512. return oldSpeedBattle.call(this);
  6513. }
  6514. try {
  6515. const BC_12 = getProtoFn(Game.BattleController, 12);
  6516. const BSM_12 = getProtoFn(Game.BattleSettingsModel, 12);
  6517. const BP_get_value = getF(Game.BooleanProperty, 'get_value');
  6518. if (this[BC_12][BSM_12][BP_get_value]()) {
  6519. return 0;
  6520. }
  6521. const BSM_2 = getProtoFn(Game.BattleSettingsModel, 2);
  6522. const BC_49 = getProtoFn(Game.BattleController, 49);
  6523. const BSM_1 = getProtoFn(Game.BattleSettingsModel, 1);
  6524. const BC_14 = getProtoFn(Game.BattleController, 14);
  6525. const BC_3 = getFn(Game.BattleController, 3);
  6526. if (this[BC_12][BSM_2][BP_get_value]()) {
  6527. var a = speedBattle * this[BC_49]();
  6528. } else {
  6529. a = this[BC_12][BSM_1][BP_get_value]();
  6530. const maxSpeed = Math.max(...this[BC_14]);
  6531. const multiple = a == this[BC_14].indexOf(maxSpeed) ? (maxSpeed >= 4 ? speedBattle : this[BC_14][a]) : this[BC_14][a];
  6532. a = multiple * Game.BattleController[BC_3][BP_get_value]() * this[BC_49]();
  6533. }
  6534. const BSM_24 = getProtoFn(Game.BattleSettingsModel, 24);
  6535. a > this[BC_12][BSM_24][BP_get_value]() && (a = this[BC_12][BSM_24][BP_get_value]());
  6536. const DS_23 = getFn(Game.DataStorage, 23);
  6537. const get_battleSpeedMultiplier = getF(Game.RuleStorage, 'get_battleSpeedMultiplier', true);
  6538. var b = Game.DataStorage[DS_23][get_battleSpeedMultiplier]();
  6539. const R_1 = getFn(selfGame.Reflect, 1);
  6540. const BC_1 = getFn(Game.BattleController, 1);
  6541. const get_config = getF(Game.BattlePresets, 'get_config');
  6542. null != b &&
  6543. (a = selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  6544. ? a * selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  6545. : a * selfGame.Reflect[R_1](b, 'default'));
  6546. return a;
  6547. } catch (error) {
  6548. console.error('passBatspeedBattletle', error);
  6549. return oldSpeedBattle.call(this);
  6550. }
  6551. };
  6552. },
  6553.  
  6554. /**
  6555. * Acceleration button without Valkyries favor
  6556. *
  6557. * Кнопка ускорения без Покровительства Валькирий
  6558. */
  6559. battleFastKey: function () {
  6560. const BGM_44 = getProtoFn(Game.BattleGuiMediator, 44);
  6561. const oldBattleFastKey = Game.BattleGuiMediator.prototype[BGM_44];
  6562. Game.BattleGuiMediator.prototype[BGM_44] = function () {
  6563. let flag = true;
  6564. //console.log(flag)
  6565. if (!flag) {
  6566. return oldBattleFastKey.call(this);
  6567. }
  6568. try {
  6569. const BGM_9 = getProtoFn(Game.BattleGuiMediator, 9);
  6570. const BGM_10 = getProtoFn(Game.BattleGuiMediator, 10);
  6571. const BPW_0 = getProtoFn(Game.BooleanPropertyWriteable, 0);
  6572. this[BGM_9][BPW_0](true);
  6573. this[BGM_10][BPW_0](true);
  6574. } catch (error) {
  6575. console.error(error);
  6576. return oldBattleFastKey.call(this);
  6577. }
  6578. };
  6579. },
  6580. fastSeason: function () {
  6581. const GameNavigator = selfGame['game.screen.navigator.GameNavigator'];
  6582. const oldFuncName = getProtoFn(GameNavigator, 18);
  6583. const newFuncName = getProtoFn(GameNavigator, 16);
  6584. const oldFastSeason = GameNavigator.prototype[oldFuncName];
  6585. const newFastSeason = GameNavigator.prototype[newFuncName];
  6586. GameNavigator.prototype[oldFuncName] = function (a, b) {
  6587. if (isChecked('fastSeason')) {
  6588. return newFastSeason.apply(this, [a]);
  6589. } else {
  6590. return oldFastSeason.apply(this, [a, b]);
  6591. }
  6592. };
  6593. },
  6594. ShowChestReward: function () {
  6595. const TitanArtifactChest = selfGame['game.mechanics.titan_arena.mediator.chest.TitanArtifactChestRewardPopupMediator'];
  6596. const getOpenAmountTitan = getF(TitanArtifactChest, 'get_openAmount');
  6597. const oldGetOpenAmountTitan = TitanArtifactChest.prototype[getOpenAmountTitan];
  6598. TitanArtifactChest.prototype[getOpenAmountTitan] = function () {
  6599. if (correctShowOpenArtifact) {
  6600. correctShowOpenArtifact--;
  6601. return 100;
  6602. }
  6603. return oldGetOpenAmountTitan.call(this);
  6604. };
  6605.  
  6606. const ArtifactChest = selfGame['game.view.popup.artifactchest.rewardpopup.ArtifactChestRewardPopupMediator'];
  6607. const getOpenAmount = getF(ArtifactChest, 'get_openAmount');
  6608. const oldGetOpenAmount = ArtifactChest.prototype[getOpenAmount];
  6609. ArtifactChest.prototype[getOpenAmount] = function () {
  6610. if (correctShowOpenArtifact) {
  6611. correctShowOpenArtifact--;
  6612. return 100;
  6613. }
  6614. return oldGetOpenAmount.call(this);
  6615. };
  6616. },
  6617. fixCompany: function () {
  6618. const GameBattleView = selfGame['game.mediator.gui.popup.battle.GameBattleView'];
  6619. const BattleThread = selfGame['game.battle.controller.thread.BattleThread'];
  6620. const getOnViewDisposed = getF(BattleThread, 'get_onViewDisposed');
  6621. const getThread = getF(GameBattleView, 'get_thread');
  6622. const oldFunc = GameBattleView.prototype[getThread];
  6623. GameBattleView.prototype[getThread] = function () {
  6624. return (
  6625. oldFunc.call(this) || {
  6626. [getOnViewDisposed]: async () => {},
  6627. }
  6628. );
  6629. };
  6630. },
  6631. BuyTitanArtifact: function () {
  6632. const BIP_4 = getProtoFn(selfGame['game.view.popup.shop.buy.BuyItemPopup'], 4);
  6633. const BuyItemPopup = selfGame['game.view.popup.shop.buy.BuyItemPopup'];
  6634. const oldFunc = BuyItemPopup.prototype[BIP_4];
  6635. BuyItemPopup.prototype[BIP_4] = function () {
  6636. if (isChecked('countControl')) {
  6637. const BuyTitanArtifactItemPopup = selfGame['game.view.popup.shop.buy.BuyTitanArtifactItemPopup'];
  6638. const BTAP_0 = getProtoFn(BuyTitanArtifactItemPopup, 0);
  6639. if (this[BTAP_0]) {
  6640. const BuyTitanArtifactPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyTitanArtifactItemPopupMediator'];
  6641. const BTAM_1 = getProtoFn(BuyTitanArtifactPopupMediator, 1);
  6642. const BuyItemPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyItemPopupMediator'];
  6643. const BIPM_5 = getProtoFn(BuyItemPopupMediator, 5);
  6644. const BIPM_7 = getProtoFn(BuyItemPopupMediator, 7);
  6645. const BIPM_9 = getProtoFn(BuyItemPopupMediator, 9);
  6646.  
  6647. let need = Math.min(this[BTAP_0][BTAM_1](), this[BTAP_0][BIPM_7]);
  6648. need = need ? need : 60;
  6649. this[BTAP_0][BIPM_9] = need;
  6650. this[BTAP_0][BIPM_5] = 10;
  6651. }
  6652. }
  6653. oldFunc.call(this);
  6654. };
  6655. },
  6656. ClanQuestsFastFarm: function () {
  6657. const VipRuleValueObject = selfGame['game.data.storage.rule.VipRuleValueObject'];
  6658. const getClanQuestsFastFarm = getF(VipRuleValueObject, 'get_clanQuestsFastFarm', 1);
  6659. VipRuleValueObject.prototype[getClanQuestsFastFarm] = function () {
  6660. return 0;
  6661. };
  6662. },
  6663. adventureCamera: function () {
  6664. const AMC_40 = getProtoFn(Game.AdventureMapCamera, 40);
  6665. const AMC_5 = getProtoFn(Game.AdventureMapCamera, 5);
  6666. const oldFunc = Game.AdventureMapCamera.prototype[AMC_40];
  6667. Game.AdventureMapCamera.prototype[AMC_40] = function (a) {
  6668. this[AMC_5] = 0.4;
  6669. oldFunc.bind(this)(a);
  6670. };
  6671. },
  6672. unlockMission: function () {
  6673. const WorldMapStoryDrommerHelper = selfGame['game.mediator.gui.worldmap.WorldMapStoryDrommerHelper'];
  6674. const WMSDH_4 = getFn(WorldMapStoryDrommerHelper, 4);
  6675. const WMSDH_7 = getFn(WorldMapStoryDrommerHelper, 7);
  6676. WorldMapStoryDrommerHelper[WMSDH_4] = function () {
  6677. return true;
  6678. };
  6679. WorldMapStoryDrommerHelper[WMSDH_7] = function () {
  6680. return true;
  6681. };
  6682. },
  6683. };
  6684.  
  6685. /**
  6686. * Starts replacing recorded functions
  6687. *
  6688. * Запускает замену записанных функций
  6689. */
  6690. this.activateHacks = function () {
  6691. if (!selfGame) throw Error('Use connectGame');
  6692. for (let func in replaceFunction) {
  6693. try {
  6694. replaceFunction[func]();
  6695. } catch (error) {
  6696. console.error(error);
  6697. }
  6698. }
  6699. }
  6700.  
  6701. /**
  6702. * Returns the game object
  6703. *
  6704. * Возвращает объект игры
  6705. */
  6706. this.getSelfGame = function () {
  6707. return selfGame;
  6708. }
  6709.  
  6710. /**
  6711. * Updates game data
  6712. *
  6713. * Обновляет данные игры
  6714. */
  6715. this.refreshGame = function () {
  6716. (new Game.NextDayUpdatedManager)[getProtoFn(Game.NextDayUpdatedManager, 5)]();
  6717. try {
  6718. cheats.refreshInventory();
  6719. } catch (e) { }
  6720. }
  6721.  
  6722. /**
  6723. * Update inventory
  6724. *
  6725. * Обновляет инвентарь
  6726. */
  6727. this.refreshInventory = async function () {
  6728. const GM_INST = getFnP(Game.GameModel, "get_instance");
  6729. const GM_0 = getProtoFn(Game.GameModel, 0);
  6730. const P_24 = getProtoFn(selfGame["game.model.user.Player"], 24);
  6731. const Player = Game.GameModel[GM_INST]()[GM_0];
  6732. Player[P_24] = new selfGame["game.model.user.inventory.PlayerInventory"]
  6733. Player[P_24].init(await Send({calls:[{name:"inventoryGet",args:{},ident:"body"}]}).then(e => e.results[0].result.response))
  6734. }
  6735. this.updateInventory = function (reward) {
  6736. const GM_INST = getFnP(Game.GameModel, 'get_instance');
  6737. const GM_0 = getProtoFn(Game.GameModel, 0);
  6738. const P_24 = getProtoFn(selfGame['game.model.user.Player'], 24);
  6739. const Player = Game.GameModel[GM_INST]()[GM_0];
  6740. Player[P_24].init(reward);
  6741. };
  6742.  
  6743. this.updateMap = function (data) {
  6744. const PCDD_21 = getProtoFn(selfGame['game.mechanics.clanDomination.model.PlayerClanDominationData'], 21);
  6745. const P_60 = getProtoFn(selfGame['game.model.user.Player'], 60);
  6746. const GM_0 = getProtoFn(Game.GameModel, 0);
  6747. const getInstance = getFnP(selfGame['Game'], 'get_instance');
  6748. const PlayerClanDominationData = Game.GameModel[getInstance]()[GM_0];
  6749. PlayerClanDominationData[P_60][PCDD_21].update(data);
  6750. };
  6751.  
  6752. /**
  6753. * Change the play screen on windowName
  6754. *
  6755. * Сменить экран игры на windowName
  6756. *
  6757. * Possible options:
  6758. *
  6759. * Возможные варианты:
  6760. *
  6761. * 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
  6762. */
  6763. this.goNavigtor = function (windowName) {
  6764. let mechanicStorage = selfGame["game.data.storage.mechanic.MechanicStorage"];
  6765. let window = mechanicStorage[windowName];
  6766. let event = new selfGame["game.mediator.gui.popup.PopupStashEventParams"];
  6767. let Game = selfGame['Game'];
  6768. let navigator = getF(Game, "get_navigator")
  6769. let navigate = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 20)
  6770. let instance = getFnP(Game, 'get_instance');
  6771. Game[instance]()[navigator]()[navigate](window, event);
  6772. }
  6773.  
  6774. /**
  6775. * Move to the sanctuary cheats.goSanctuary()
  6776. *
  6777. * Переместиться в святилище cheats.goSanctuary()
  6778. */
  6779. this.goSanctuary = () => {
  6780. this.goNavigtor("SANCTUARY");
  6781. }
  6782.  
  6783. /**
  6784. * Go to Guild War
  6785. *
  6786. * Перейти к Войне Гильдий
  6787. */
  6788. this.goClanWar = function() {
  6789. let instance = getFnP(Game.GameModel, 'get_instance')
  6790. let player = Game.GameModel[instance]().A;
  6791. let clanWarSelect = selfGame["game.mechanics.cross_clan_war.popup.selectMode.CrossClanWarSelectModeMediator"];
  6792. new clanWarSelect(player).open();
  6793. }
  6794.  
  6795. /**
  6796. * Go to BrawlShop
  6797. *
  6798. * Переместиться в BrawlShop
  6799. */
  6800. this.goBrawlShop = () => {
  6801. const instance = getFnP(Game.GameModel, 'get_instance')
  6802. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  6803. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  6804. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  6805. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  6806.  
  6807. const player = Game.GameModel[instance]().A;
  6808. const shop = player[P_36][PSD_0][IM_0][1038][PSDE_4];
  6809. const shopPopup = new selfGame["game.mechanics.brawl.mediator.BrawlShopPopupMediator"](player, shop)
  6810. shopPopup.open(new selfGame["game.mediator.gui.popup.PopupStashEventParams"])
  6811. }
  6812.  
  6813. /**
  6814. * Returns all stores from game data
  6815. *
  6816. * Возвращает все магазины из данных игры
  6817. */
  6818. this.getShops = () => {
  6819. const instance = getFnP(Game.GameModel, 'get_instance')
  6820. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  6821. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  6822. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  6823.  
  6824. const player = Game.GameModel[instance]().A;
  6825. return player[P_36][PSD_0][IM_0];
  6826. }
  6827.  
  6828. /**
  6829. * Returns the store from the game data by ID
  6830. *
  6831. * Возвращает магазин из данных игры по идетификатору
  6832. */
  6833. this.getShop = (id) => {
  6834. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  6835. const shops = this.getShops();
  6836. const shop = shops[id]?.[PSDE_4];
  6837. return shop;
  6838. }
  6839.  
  6840. /**
  6841. * Change island map
  6842. *
  6843. * Сменить карту острова
  6844. */
  6845. this.changeIslandMap = (mapId = 2) => {
  6846. const GameInst = getFnP(selfGame['Game'], 'get_instance');
  6847. const GM_0 = getProtoFn(Game.GameModel, 0);
  6848. const P_59 = getProtoFn(selfGame["game.model.user.Player"], 60);
  6849. const PSAD_31 = getProtoFn(selfGame['game.mechanics.season_adventure.model.PlayerSeasonAdventureData'], 31);
  6850. const Player = Game.GameModel[GameInst]()[GM_0];
  6851. Player[P_59][PSAD_31]({ id: mapId, seasonAdventure: { id: mapId, startDate: 1701914400, endDate: 1709690400, closed: false } });
  6852.  
  6853. const GN_15 = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 17)
  6854. const navigator = getF(selfGame['Game'], "get_navigator");
  6855. selfGame['Game'][GameInst]()[navigator]()[GN_15](new selfGame["game.mediator.gui.popup.PopupStashEventParams"]);
  6856. }
  6857.  
  6858. /**
  6859. * Game library availability tracker
  6860. *
  6861. * Отслеживание доступности игровой библиотеки
  6862. */
  6863. function checkLibLoad() {
  6864. timeout = setTimeout(() => {
  6865. if (Game.GameModel) {
  6866. changeLib();
  6867. } else {
  6868. checkLibLoad();
  6869. }
  6870. }, 100)
  6871. }
  6872.  
  6873. /**
  6874. * Game library data spoofing
  6875. *
  6876. * Подмена данных игровой библиотеки
  6877. */
  6878. function changeLib() {
  6879. console.log('lib connect');
  6880. const originalStartFunc = Game.GameModel.prototype.start;
  6881. Game.GameModel.prototype.start = function (a, b, c) {
  6882. self.libGame = b.raw;
  6883. try {
  6884. const levels = b.raw.seasonAdventure.level;
  6885. for (const id in levels) {
  6886. const level = levels[id];
  6887. level.clientData.graphics.fogged = level.clientData.graphics.visible
  6888. }
  6889. const adv = b.raw.seasonAdventure.list[1];
  6890. adv.clientData.asset = 'dialog_season_adventure_tiles';
  6891. } catch (e) {
  6892. console.warn(e);
  6893. }
  6894. originalStartFunc.call(this, a, b, c);
  6895. }
  6896. }
  6897.  
  6898. /**
  6899. * Returns the value of a language constant
  6900. *
  6901. * Возвращает значение языковой константы
  6902. * @param {*} langConst language constant // языковая константа
  6903. * @returns
  6904. */
  6905. this.translate = function (langConst) {
  6906. return Game.Translate.translate(langConst);
  6907. }
  6908.  
  6909. connectGame();
  6910. checkLibLoad();
  6911. }
  6912.  
  6913. /**
  6914. * Auto collection of gifts
  6915. *
  6916. * Автосбор подарков
  6917. */
  6918. function getAutoGifts() {
  6919. // c3ltYm9scyB0aGF0IG1lYW4gbm90aGluZw==
  6920. let valName = 'giftSendIds_' + userInfo.id;
  6921.  
  6922. if (!localStorage['clearGift' + userInfo.id]) {
  6923. localStorage[valName] = '';
  6924. localStorage['clearGift' + userInfo.id] = '+';
  6925. }
  6926.  
  6927. if (!localStorage[valName]) {
  6928. localStorage[valName] = '';
  6929. }
  6930.  
  6931. const giftsAPI = new ZingerYWebsiteAPI('getGifts.php', arguments);
  6932. /**
  6933. * Submit a request to receive gift codes
  6934. *
  6935. * Отправка запроса для получения кодов подарков
  6936. */
  6937. giftsAPI.request().then((data) => {
  6938. let freebieCheckCalls = {
  6939. calls: [],
  6940. };
  6941. data.forEach((giftId, n) => {
  6942. if (localStorage[valName].includes(giftId)) return;
  6943. freebieCheckCalls.calls.push({
  6944. name: 'registration',
  6945. args: {
  6946. user: { referrer: {} },
  6947. giftId,
  6948. },
  6949. context: {
  6950. actionTs: Math.floor(performance.now()),
  6951. cookie: window?.NXAppInfo?.session_id || null,
  6952. },
  6953. ident: giftId,
  6954. });
  6955. });
  6956.  
  6957. if (!freebieCheckCalls.calls.length) {
  6958. return;
  6959. }
  6960.  
  6961. send(JSON.stringify(freebieCheckCalls), (e) => {
  6962. let countGetGifts = 0;
  6963. const gifts = [];
  6964. for (check of e.results) {
  6965. gifts.push(check.ident);
  6966. if (check.result.response != null) {
  6967. countGetGifts++;
  6968. }
  6969. }
  6970. const saveGifts = localStorage[valName].split(';');
  6971. localStorage[valName] = [...saveGifts, ...gifts].slice(-50).join(';');
  6972. console.log(`${I18N('GIFTS')}: ${countGetGifts}`);
  6973. });
  6974. });
  6975. }
  6976.  
  6977. /**
  6978. * To fill the kills in the Forge of Souls
  6979. *
  6980. * Набить килов в горниле душ
  6981. */
  6982. async function bossRatingEvent() {
  6983. const topGet = await Send(JSON.stringify({ calls: [{ name: "topGet", args: { type: "bossRatingTop", extraId: 0 }, ident: "body" }] }));
  6984. if (!topGet || !topGet.results[0].result.response[0]) {
  6985. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  6986. return;
  6987. }
  6988. const replayId = topGet.results[0].result.response[0].userData.replayId;
  6989. const result = await Send(JSON.stringify({
  6990. calls: [
  6991. { name: "battleGetReplay", args: { id: replayId }, ident: "battleGetReplay" },
  6992. { name: "heroGetAll", args: {}, ident: "heroGetAll" },
  6993. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  6994. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  6995. ]
  6996. }));
  6997. const bossEventInfo = result.results[3].result.response.find(e => e.offerType == "bossEvent");
  6998. if (!bossEventInfo) {
  6999. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7000. return;
  7001. }
  7002. const usedHeroes = bossEventInfo.progress.usedHeroes;
  7003. const party = Object.values(result.results[0].result.response.replay.attackers);
  7004. const availableHeroes = Object.values(result.results[1].result.response).map(e => e.id);
  7005. const availablePets = Object.values(result.results[2].result.response).map(e => e.id);
  7006. const calls = [];
  7007. /**
  7008. * First pack
  7009. *
  7010. * Первая пачка
  7011. */
  7012. const args = {
  7013. heroes: [],
  7014. favor: {}
  7015. }
  7016. for (let hero of party) {
  7017. if (hero.id >= 6000 && availablePets.includes(hero.id)) {
  7018. args.pet = hero.id;
  7019. continue;
  7020. }
  7021. if (!availableHeroes.includes(hero.id) || usedHeroes.includes(hero.id)) {
  7022. continue;
  7023. }
  7024. args.heroes.push(hero.id);
  7025. if (hero.favorPetId) {
  7026. args.favor[hero.id] = hero.favorPetId;
  7027. }
  7028. }
  7029. if (args.heroes.length) {
  7030. calls.push({
  7031. name: "bossRatingEvent_startBattle",
  7032. args,
  7033. ident: "body_0"
  7034. });
  7035. }
  7036. /**
  7037. * Other packs
  7038. *
  7039. * Другие пачки
  7040. */
  7041. let heroes = [];
  7042. let count = 1;
  7043. while (heroId = availableHeroes.pop()) {
  7044. if (args.heroes.includes(heroId) || usedHeroes.includes(heroId)) {
  7045. continue;
  7046. }
  7047. heroes.push(heroId);
  7048. if (heroes.length == 5) {
  7049. calls.push({
  7050. name: "bossRatingEvent_startBattle",
  7051. args: {
  7052. heroes: [...heroes],
  7053. pet: availablePets[Math.floor(Math.random() * availablePets.length)]
  7054. },
  7055. ident: "body_" + count
  7056. });
  7057. heroes = [];
  7058. count++;
  7059. }
  7060. }
  7061.  
  7062. if (!calls.length) {
  7063. setProgress(`${I18N('NO_HEROES')}`, true);
  7064. return;
  7065. }
  7066.  
  7067. const resultBattles = await Send(JSON.stringify({ calls }));
  7068. console.log(resultBattles);
  7069. rewardBossRatingEvent();
  7070. }
  7071.  
  7072. /**
  7073. * Collecting Rewards from the Forge of Souls
  7074. *
  7075. * Сбор награды из Горнила Душ
  7076. */
  7077. function rewardBossRatingEvent() {
  7078. let rewardBossRatingCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  7079. send(rewardBossRatingCall, function (data) {
  7080. let bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  7081. if (!bossEventInfo) {
  7082. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7083. return;
  7084. }
  7085.  
  7086. let farmedChests = bossEventInfo.progress.farmedChests;
  7087. let score = bossEventInfo.progress.score;
  7088. setProgress(`${I18N('DAMAGE_AMOUNT')}: ${score}`);
  7089. let revard = bossEventInfo.reward;
  7090.  
  7091. let getRewardCall = {
  7092. calls: []
  7093. }
  7094.  
  7095. let count = 0;
  7096. for (let i = 1; i < 10; i++) {
  7097. if (farmedChests.includes(i)) {
  7098. continue;
  7099. }
  7100. if (score < revard[i].score) {
  7101. break;
  7102. }
  7103. getRewardCall.calls.push({
  7104. name: "bossRatingEvent_getReward",
  7105. args: {
  7106. rewardId: i
  7107. },
  7108. ident: "body_" + i
  7109. });
  7110. count++;
  7111. }
  7112. if (!count) {
  7113. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  7114. return;
  7115. }
  7116.  
  7117. send(JSON.stringify(getRewardCall), e => {
  7118. console.log(e);
  7119. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  7120. });
  7121. });
  7122. }
  7123.  
  7124. /**
  7125. * Collect Easter eggs and event rewards
  7126. *
  7127. * Собрать пасхалки и награды событий
  7128. */
  7129. function offerFarmAllReward() {
  7130. const offerGetAllCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  7131. return Send(offerGetAllCall).then((data) => {
  7132. const offerGetAll = data.results[0].result.response.filter(e => e.type == "reward" && !e?.freeRewardObtained && e.reward);
  7133. if (!offerGetAll.length) {
  7134. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  7135. return;
  7136. }
  7137.  
  7138. const calls = [];
  7139. for (let reward of offerGetAll) {
  7140. calls.push({
  7141. name: "offerFarmReward",
  7142. args: {
  7143. offerId: reward.id
  7144. },
  7145. ident: "offerFarmReward_" + reward.id
  7146. });
  7147. }
  7148.  
  7149. return Send(JSON.stringify({ calls })).then(e => {
  7150. console.log(e);
  7151. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  7152. });
  7153. });
  7154. }
  7155.  
  7156. /**
  7157. * Assemble Outland
  7158. *
  7159. * Собрать запределье
  7160. */
  7161. function getOutland() {
  7162. return new Promise(function (resolve, reject) {
  7163. send('{"calls":[{"name":"bossGetAll","args":{},"ident":"bossGetAll"}]}', e => {
  7164. let bosses = e.results[0].result.response;
  7165.  
  7166. let bossRaidOpenChestCall = {
  7167. calls: []
  7168. };
  7169.  
  7170. for (let boss of bosses) {
  7171. if (boss.mayRaid) {
  7172. bossRaidOpenChestCall.calls.push({
  7173. name: "bossRaid",
  7174. args: {
  7175. bossId: boss.id
  7176. },
  7177. ident: "bossRaid_" + boss.id
  7178. });
  7179. bossRaidOpenChestCall.calls.push({
  7180. name: "bossOpenChest",
  7181. args: {
  7182. bossId: boss.id,
  7183. amount: 1,
  7184. starmoney: 0
  7185. },
  7186. ident: "bossOpenChest_" + boss.id
  7187. });
  7188. } else if (boss.chestId == 1) {
  7189. bossRaidOpenChestCall.calls.push({
  7190. name: "bossOpenChest",
  7191. args: {
  7192. bossId: boss.id,
  7193. amount: 1,
  7194. starmoney: 0
  7195. },
  7196. ident: "bossOpenChest_" + boss.id
  7197. });
  7198. }
  7199. }
  7200.  
  7201. if (!bossRaidOpenChestCall.calls.length) {
  7202. setProgress(`${I18N('OUTLAND')} ${I18N('NOTHING_TO_COLLECT')}`, true);
  7203. resolve();
  7204. return;
  7205. }
  7206.  
  7207. send(JSON.stringify(bossRaidOpenChestCall), e => {
  7208. setProgress(`${I18N('OUTLAND')} ${I18N('COLLECTED')}`, true);
  7209. resolve();
  7210. });
  7211. });
  7212. });
  7213. }
  7214.  
  7215. /**
  7216. * Collect all rewards
  7217. *
  7218. * Собрать все награды
  7219. */
  7220. function questAllFarm() {
  7221. return new Promise(function (resolve, reject) {
  7222. let questGetAllCall = {
  7223. calls: [{
  7224. name: "questGetAll",
  7225. args: {},
  7226. ident: "body"
  7227. }]
  7228. }
  7229. send(JSON.stringify(questGetAllCall), function (data) {
  7230. let questGetAll = data.results[0].result.response;
  7231. const questAllFarmCall = {
  7232. calls: []
  7233. }
  7234. let number = 0;
  7235. for (let quest of questGetAll) {
  7236. if (quest.id < 1e6 && quest.state == 2) {
  7237. questAllFarmCall.calls.push({
  7238. name: "questFarm",
  7239. args: {
  7240. questId: quest.id
  7241. },
  7242. ident: `group_${number}_body`
  7243. });
  7244. number++;
  7245. }
  7246. }
  7247.  
  7248. if (!questAllFarmCall.calls.length) {
  7249. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  7250. resolve();
  7251. return;
  7252. }
  7253.  
  7254. send(JSON.stringify(questAllFarmCall), function (res) {
  7255. console.log(res);
  7256. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  7257. resolve();
  7258. });
  7259. });
  7260. })
  7261. }
  7262.  
  7263. /**
  7264. * Mission auto repeat
  7265. *
  7266. * Автоповтор миссии
  7267. * isStopSendMission = false;
  7268. * isSendsMission = true;
  7269. **/
  7270. this.sendsMission = async function (param) {
  7271. if (isStopSendMission) {
  7272. isSendsMission = false;
  7273. console.log(I18N('STOPPED'));
  7274. setProgress('');
  7275. await popup.confirm(`${I18N('STOPPED')}<br>${I18N('REPETITIONS')}: ${param.count}`, [{
  7276. msg: 'Ok',
  7277. result: true
  7278. }, ])
  7279. return;
  7280. }
  7281. lastMissionBattleStart = Date.now();
  7282. let missionStartCall = {
  7283. "calls": [{
  7284. "name": "missionStart",
  7285. "args": lastMissionStart,
  7286. "ident": "body"
  7287. }]
  7288. }
  7289. /**
  7290. * Mission Request
  7291. *
  7292. * Запрос на выполнение мисии
  7293. */
  7294. SendRequest(JSON.stringify(missionStartCall), async e => {
  7295. if (e['error']) {
  7296. isSendsMission = false;
  7297. console.log(e['error']);
  7298. setProgress('');
  7299. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  7300. await popup.confirm(msg, [
  7301. {msg: 'Ok', result: true},
  7302. ])
  7303. return;
  7304. }
  7305. /**
  7306. * Mission data calculation
  7307. *
  7308. * Расчет данных мисии
  7309. */
  7310. BattleCalc(e.results[0].result.response, 'get_tower', async r => {
  7311. /** missionTimer */
  7312. let timer = getTimer(r.battleTime) + 5;
  7313. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  7314. if (period < timer) {
  7315. timer = timer - period;
  7316. await countdownTimer(timer, `${I18N('MISSIONS_PASSED')}: ${param.count}`);
  7317. }
  7318.  
  7319. let missionEndCall = {
  7320. "calls": [{
  7321. "name": "missionEnd",
  7322. "args": {
  7323. "id": param.id,
  7324. "result": r.result,
  7325. "progress": r.progress
  7326. },
  7327. "ident": "body"
  7328. }]
  7329. }
  7330. /**
  7331. * Mission Completion Request
  7332. *
  7333. * Запрос на завершение миссии
  7334. */
  7335. SendRequest(JSON.stringify(missionEndCall), async (e) => {
  7336. if (e['error']) {
  7337. isSendsMission = false;
  7338. console.log(e['error']);
  7339. setProgress('');
  7340. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  7341. await popup.confirm(msg, [
  7342. {msg: 'Ok', result: true},
  7343. ])
  7344. return;
  7345. }
  7346. r = e.results[0].result.response;
  7347. if (r['error']) {
  7348. isSendsMission = false;
  7349. console.log(r['error']);
  7350. setProgress('');
  7351. await popup.confirm(`<br>${I18N('REPETITIONS')}: ${param.count}` + ' 3 ' + r['error'], [
  7352. {msg: 'Ok', result: true},
  7353. ])
  7354. return;
  7355. }
  7356.  
  7357. param.count++;
  7358. setProgress(`${I18N('MISSIONS_PASSED')}: ${param.count} (${I18N('STOP')})`, false, () => {
  7359. isStopSendMission = true;
  7360. });
  7361. setTimeout(sendsMission, 1, param);
  7362. });
  7363. })
  7364. });
  7365. }
  7366.  
  7367. /**
  7368. * Opening of russian dolls
  7369. *
  7370. * Открытие матрешек
  7371. */
  7372. async function openRussianDolls(libId, amount) {
  7373. let sum = 0;
  7374. let sumResult = [];
  7375.  
  7376. while (amount) {
  7377. sum += amount;
  7378. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`);
  7379. const calls = [{
  7380. name: "consumableUseLootBox",
  7381. args: { libId, amount },
  7382. ident: "body"
  7383. }];
  7384. const result = await Send(JSON.stringify({ calls })).then(e => e.results[0].result.response);
  7385. let newCount = 0;
  7386. for (let n of result) {
  7387. if (n?.consumable && n.consumable[libId]) {
  7388. newCount += n.consumable[libId]
  7389. }
  7390. }
  7391. sumResult = [...sumResult, ...result];
  7392. amount = newCount;
  7393. }
  7394.  
  7395. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`, 5000);
  7396. return sumResult;
  7397. }
  7398.  
  7399. /**
  7400. * Collect all mail, except letters with energy and charges of the portal
  7401. *
  7402. * Собрать всю почту, кроме писем с энергией и зарядами портала
  7403. */
  7404. function mailGetAll() {
  7405. const getMailInfo = '{"calls":[{"name":"mailGetAll","args":{},"ident":"body"}]}';
  7406.  
  7407. return Send(getMailInfo).then(dataMail => {
  7408. const letters = dataMail.results[0].result.response.letters;
  7409. const letterIds = lettersFilter(letters);
  7410. if (!letterIds.length) {
  7411. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  7412. return;
  7413. }
  7414.  
  7415. const calls = [
  7416. { name: "mailFarm", args: { letterIds }, ident: "body" }
  7417. ];
  7418.  
  7419. return Send(JSON.stringify({ calls })).then(res => {
  7420. const lettersIds = res.results[0].result.response;
  7421. if (lettersIds) {
  7422. const countLetters = Object.keys(lettersIds).length;
  7423. setProgress(`${I18N('RECEIVED')} ${countLetters} ${I18N('LETTERS')}`, true);
  7424. }
  7425. });
  7426. });
  7427. }
  7428.  
  7429. /**
  7430. * Filters received emails
  7431. *
  7432. * Фильтрует получаемые письма
  7433. */
  7434. function lettersFilter(letters) {
  7435. const lettersIds = [];
  7436. for (let l in letters) {
  7437. letter = letters[l];
  7438. const reward = letter?.reward;
  7439. if (!reward || !Object.keys(reward).length) {
  7440. continue;
  7441. }
  7442. /**
  7443. * Mail Collection Exceptions
  7444. *
  7445. * Исключения на сбор писем
  7446. */
  7447. const isFarmLetter = !(
  7448. /** Portals // сферы портала */
  7449. (reward?.refillable ? reward.refillable[45] : false) ||
  7450. /** Energy // энергия */
  7451. (reward?.stamina ? reward.stamina : false) ||
  7452. /** accelerating energy gain // ускорение набора энергии */
  7453. (reward?.buff ? true : false) ||
  7454. /** VIP Points // вип очки */
  7455. (reward?.vipPoints ? reward.vipPoints : false) ||
  7456. /** souls of heroes // душы героев */
  7457. (reward?.fragmentHero ? true : false) ||
  7458. /** heroes // герои */
  7459. (reward?.bundleHeroReward ? true : false)
  7460. );
  7461. if (isFarmLetter) {
  7462. lettersIds.push(~~letter.id);
  7463. continue;
  7464. }
  7465. /**
  7466. * Если до окончания годности письма менее 24 часов,
  7467. * то оно собирается не смотря на исключения
  7468. */
  7469. const availableUntil = +letter?.availableUntil;
  7470. if (availableUntil) {
  7471. const maxTimeLeft = 24 * 60 * 60 * 1000;
  7472. const timeLeft = (new Date(availableUntil * 1000) - new Date())
  7473. console.log('Time left:', timeLeft)
  7474. if (timeLeft < maxTimeLeft) {
  7475. lettersIds.push(~~letter.id);
  7476. continue;
  7477. }
  7478. }
  7479. }
  7480. return lettersIds;
  7481. }
  7482.  
  7483. /**
  7484. * Displaying information about the areas of the portal and attempts on the VG
  7485. *
  7486. * Отображение информации о сферах портала и попытках на ВГ
  7487. */
  7488. async function justInfo() {
  7489. return new Promise(async (resolve, reject) => {
  7490. const calls = [{
  7491. name: "userGetInfo",
  7492. args: {},
  7493. ident: "userGetInfo"
  7494. },
  7495. {
  7496. name: "clanWarGetInfo",
  7497. args: {},
  7498. ident: "clanWarGetInfo"
  7499. },
  7500. {
  7501. name: "titanArenaGetStatus",
  7502. args: {},
  7503. ident: "titanArenaGetStatus"
  7504. }];
  7505. const result = await Send(JSON.stringify({ calls }));
  7506. const infos = result.results;
  7507. const portalSphere = infos[0].result.response.refillable.find(n => n.id == 45);
  7508. const clanWarMyTries = infos[1].result.response?.myTries ?? 0;
  7509. const arePointsMax = infos[1].result.response?.arePointsMax;
  7510. const titansLevel = +(infos[2].result.response?.tier ?? 0);
  7511. const titansStatus = infos[2].result.response?.status; //peace_time || battle
  7512.  
  7513. const sanctuaryButton = buttons['goToSanctuary'].button;
  7514. const clanWarButton = buttons['goToClanWar'].button;
  7515. const titansArenaButton = buttons['testTitanArena'].button;
  7516.  
  7517. if (portalSphere.amount) {
  7518. sanctuaryButton.style.color = portalSphere.amount >= 3 ? 'red' : 'brown';
  7519. sanctuaryButton.title = `${I18N('SANCTUARY_TITLE')}\n${portalSphere.amount} ${I18N('PORTALS')}`;
  7520. } else {
  7521. sanctuaryButton.style.color = '';
  7522. sanctuaryButton.title = I18N('SANCTUARY_TITLE');
  7523. }
  7524. if (clanWarMyTries && !arePointsMax) {
  7525. clanWarButton.style.color = 'red';
  7526. clanWarButton.title = `${I18N('GUILD_WAR_TITLE')}\n${clanWarMyTries}${I18N('ATTEMPTS')}`;
  7527. } else {
  7528. clanWarButton.style.color = '';
  7529. clanWarButton.title = I18N('GUILD_WAR_TITLE');
  7530. }
  7531.  
  7532. if (titansLevel < 7 && titansStatus == 'battle') {
  7533. const partColor = Math.floor(125 * titansLevel / 7);
  7534. titansArenaButton.style.color = `rgb(255,${partColor},${partColor})`;
  7535. titansArenaButton.title = `${I18N('TITAN_ARENA_TITLE')}\n${titansLevel} ${I18N('LEVEL')}`;
  7536. } else {
  7537. titansArenaButton.style.color = '';
  7538. titansArenaButton.title = I18N('TITAN_ARENA_TITLE');
  7539. }
  7540.  
  7541. const imgPortal =
  7542. 'data:image/gif;base64,R0lGODlhLwAvAHAAACH5BAEAAP8ALAAAAAAvAC8AhwAAABkQWgjF3krO3ghSjAhSzinF3u+tGWvO3s5rGSmE5gha7+/OWghSrWvmnClShCmUlAiE5u+MGe/W3mvvWmspUmvvGSnOWinOnCnOGWsZjErvnAiUlErvWmsIUkrvGQjOWgjOnAjOGUoZjM6MGe/OIWvv5q1KGSnv5mulGe/vWs7v3ozv3kqEGYxKGWuEWmtSKUrv3mNaCEpKUs7OWiml5ggxWmMpEAgZpRlaCO/35q1rGRkxKWtarSkZrRljKSkZhAjv3msIGRk6CEparQhjWq3v3kql3ozOGe/vnM6tGYytWu9rGWuEGYzO3kqE3gil5s6MWq3vnGvFnM7vWoxrGc5KGYyMWs6tWq2MGYzOnO+tWmvFWkqlWoxrWgAZhEqEWq2tWoytnIyt3krFnGul3mulWmulnEIpUkqlGUqlnK3OnK2MWs7OnClSrSmUte+tnGvFGYytGYzvWs5rWowpGa3O3u/OnErFWoyMnGuE3muEnEqEnIyMGYzOWs7OGe9r3u9rWq3vWq1rWq1r3invWimlWu+t3q0pWq2t3u8pWu8p3q0p3invnCnvGe/vGa2tGa3vGa2tnK0pGe9rnK1rnCmlGe8pGe8pnK0pnGsZrSkp3msp3s7vGYzvnM7vnIzvGc6tnM5r3oxr3gilWs6t3owpWs4pWs4p3owp3s5rnIxrnAilGc4pGc4pnIwpnAgp3kop3s7O3u9KGe+MWoxKWoyM3kIIUgiUte+MnErFGc5KWowIGe9K3u9KWq3OWq1KWq1K3gjvWimEWu+M3q0IWq2M3u8IWu8I3q0I3gjvnAjvGa3OGa2MnK0IGe9KnK1KnCmEGe8IGe8InK0InEoZrSkI3msI3s6MnM5K3oxK3giEWs6M3owIWs4IWs4I3owI3s5KnIxKnAiEGc4IGc4InIwInAgI3koI3kJaCAgQKUIpEGtKUkJSKUIIECla7ylazmtahGta70pa70pahGtazkpazmtrWiExUkprUiljWikQKRkQCAAQCAAACAAAAAj/AP8JHEiwoMGDCBMqXMiwocODJlBIRBHDxMOLBmMEkSjAgICPE2Mw/OUH4z8TGz+agBIBCsuWUAQE0WLwzkAkKZZcnAilhk+fA1bUiEC0ZZABJOD8IyHhwJYDkpakafJQ4kooR5yw0LFihQ4WJhAMKCoARRYSTJgkUOInBZK2DiX2rGHEiI67eFcYATtAAVEoKEiQSFBFDs4UKbg0lGgAigIEeCNzrWvCxIChEcoy3dGiSoITTRQvnCLRrxOveI2McbKahevKJmooiKkFy4Gzg5tMMaMwitwIj/PqGPCugL0CT47ANhEjQg3Atg9IT5CiS4uEUcRIBH4EtREETuB9/xn/BUcBBbBXGGgpoPaBEid23EuXgvdBJhtQGFCwwA7eMgs0gEMDBJD3hR7KbRVbSwP8UcIWJNwjIRLXGZRAAhLVsIACR9y1whMNfNGAHgiUcUSBX8ADWwwKzCYADTSUcMA9ebwQmkFYMMFGhgu80x1XTxSAwxNdGWGCAiG6YQBzly3QkhYxlsDGP1cg4YBBaC0h1zsLPGHXCkfA00AZeu11hALl1VBZXwW0RAaMDGDxTxNdTGEQExJoiUINXCpwmhFOKJCcVmCdOR56MezXJhRvwFlCC2lcWVAUEjBxRobw9HhEXUYekWBlsoVoQEWyFbAAFPRIQQMDJcDQhRhYSv+QZ1kGcAnPYya4BhZYlb1TQ4iI+tVmBPpIQQWrMORxkKwSsEFrDaa+8xgCy1mmgLSHxtDXAhtGMIOxDKjgAkLM7iAAYD4VJ+0RAyAgVl++ikfAESxy62QB365awrjLyprAcxEY4FOmXEp7LbctjlfAAE1yGwEBYBirAgP8GtTUARIMM1QBPrVYQAHF9dgiml/Mexl/3DbAwxnHMqBExQVdLAEMjRXQgHOyydaibPCgqEDH3JrawDosUDExCTATZJuMJ0AAxRNXtLFFPD+P/DB58AC9wH4N4BMxDRPvkPRAbLx3AAlVMLBFCXeQgIaIKJKHQ9X8+forAetMsaoKB7j/MAhCL5j9VFNPJYBGiCGW18CtsvWIs5j7gLEGqyV81gxC6ZBQQgkSMEUCLQckMMLHNhcAD3B+8TdyA0PPACWrB8SH0BItyHAAAwdE4YILTSUww8cELwAyt7D4JSberkd5wA4neIFQE020sMPmJZBwAi0SJMBOA6WTXgAsDYDPOj7r3KNFy5WfkEBCKbTQBQzTM+By5wm4YAPr+LM+IIE27LPOFWswmgqqZ4UEXCEhLUjBGWbgAs3JD2OfWcc68GEDArCOAASwAfnWUYUwtIEKSVCBCiSgPuclpAlImMI9YNDAzeFuMEwQ2w3W4Q530PAGLthBFNqwghCKMAoF3MEB/xNihvr8Ix4sdCCrJja47CVAMFjAwid6eJcQWi8BO4jHQl6AGFjdwwUnOMF75CfCMpoxCTpAoxoZMBgs3qMh7ZODQFYYxgSMsQThCpcK0BiZJNxBCZ7zwhsbYqO3wCoe7AjjCaxAggNUcY94mcDa3qMECWSBHYN0CBfj0IQliEFCMFjkIulAAisUkBZYyB4USxAFCZnkH1xsgltSYCMYyACMpizghS7kOTZIKJMmeYEZzCCH6iCmBS1IRzpkcEsXVMGZMMgHJvfwyoLsYQ9nmMIUuDAFPIAhH8pUZjLbcY89rKKaC9nDFeLxy3vkYwbJTMcL0InOeOSjBVShJz2pqQvPfvrznwANKEMCAgA7';
  7543.  
  7544. setProgress('<img src="' + imgPortal + '" style="height: 25px;position: relative;top: 5px;"> ' + `${portalSphere.amount} </br> ${I18N('GUILD_WAR')}: ${clanWarMyTries}`, true);
  7545. resolve();
  7546. });
  7547. }
  7548.  
  7549. async function getDailyBonus() {
  7550. const dailyBonusInfo = await Send(JSON.stringify({
  7551. calls: [{
  7552. name: "dailyBonusGetInfo",
  7553. args: {},
  7554. ident: "body"
  7555. }]
  7556. })).then(e => e.results[0].result.response);
  7557. const { availableToday, availableVip, currentDay } = dailyBonusInfo;
  7558.  
  7559. if (!availableToday) {
  7560. console.log('Уже собрано');
  7561. return;
  7562. }
  7563.  
  7564. const currentVipPoints = +userInfo.vipPoints;
  7565. const dailyBonusStat = lib.getData('dailyBonusStatic');
  7566. const vipInfo = lib.getData('level').vip;
  7567. let currentVipLevel = 0;
  7568. for (let i in vipInfo) {
  7569. vipLvl = vipInfo[i];
  7570. if (currentVipPoints >= vipLvl.vipPoints) {
  7571. currentVipLevel = vipLvl.level;
  7572. }
  7573. }
  7574. const vipLevelDouble = dailyBonusStat[`${currentDay}_0_0`].vipLevelDouble;
  7575.  
  7576. const calls = [{
  7577. name: "dailyBonusFarm",
  7578. args: {
  7579. vip: availableVip && currentVipLevel >= vipLevelDouble ? 1 : 0
  7580. },
  7581. ident: "body"
  7582. }];
  7583.  
  7584. const result = await Send(JSON.stringify({ calls }));
  7585. if (result.error) {
  7586. console.error(result.error);
  7587. return;
  7588. }
  7589.  
  7590. const reward = result.results[0].result.response;
  7591. const type = Object.keys(reward).pop();
  7592. const itemId = Object.keys(reward[type]).pop();
  7593. const count = reward[type][itemId];
  7594. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  7595.  
  7596. console.log(`Ежедневная награда: Получено ${count} ${itemName}`, reward);
  7597. }
  7598.  
  7599. async function farmStamina(lootBoxId = 148) {
  7600. const lootBox = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"}]}')
  7601. .then(e => e.results[0].result.response.consumable[148]);
  7602.  
  7603. /** Добавить другие ящики */
  7604. /**
  7605. * 144 - медная шкатулка
  7606. * 145 - бронзовая шкатулка
  7607. * 148 - платиновая шкатулка
  7608. */
  7609. if (!lootBox) {
  7610. setProgress(I18N('NO_BOXES'), true);
  7611. return;
  7612. }
  7613.  
  7614. let maxFarmEnergy = getSaveVal('maxFarmEnergy', 100);
  7615. const result = await popup.confirm(I18N('OPEN_LOOTBOX', { lootBox }), [
  7616. { result: false, isClose: true },
  7617. { msg: I18N('BTN_YES'), result: true },
  7618. { msg: I18N('STAMINA'), isInput: true, default: maxFarmEnergy },
  7619. ]);
  7620. if (!+result) {
  7621. return;
  7622. }
  7623.  
  7624. if ((typeof result) !== 'boolean' && Number.parseInt(result)) {
  7625. maxFarmEnergy = +result;
  7626. setSaveVal('maxFarmEnergy', maxFarmEnergy);
  7627. } else {
  7628. maxFarmEnergy = 0;
  7629. }
  7630.  
  7631. let collectEnergy = 0;
  7632. for (let count = lootBox; count > 0; count--) {
  7633. const result = await Send('{"calls":[{"name":"consumableUseLootBox","args":{"libId":148,"amount":1},"ident":"body"}]}')
  7634. .then(e => e.results[0].result.response[0]);
  7635. if ('stamina' in result) {
  7636. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox} ${I18N('STAMINA')} +${result.stamina}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  7637. console.log(`${ I18N('STAMINA') } + ${ result.stamina }`);
  7638. if (!maxFarmEnergy) {
  7639. return;
  7640. }
  7641. collectEnergy += +result.stamina;
  7642. if (collectEnergy >= maxFarmEnergy) {
  7643. console.log(`${I18N('STAMINA')} + ${ collectEnergy }`);
  7644. setProgress(`${I18N('STAMINA')} + ${ collectEnergy }`, false);
  7645. return;
  7646. }
  7647. } else {
  7648. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  7649. console.log(result);
  7650. }
  7651. }
  7652.  
  7653. setProgress(I18N('BOXES_OVER'), true);
  7654. }
  7655.  
  7656. async function fillActive() {
  7657. const data = await Send(JSON.stringify({
  7658. calls: [{
  7659. name: "questGetAll",
  7660. args: {},
  7661. ident: "questGetAll"
  7662. }, {
  7663. name: "inventoryGet",
  7664. args: {},
  7665. ident: "inventoryGet"
  7666. }, {
  7667. name: "clanGetInfo",
  7668. args: {},
  7669. ident: "clanGetInfo"
  7670. }
  7671. ]
  7672. })).then(e => e.results.map(n => n.result.response));
  7673.  
  7674. const quests = data[0];
  7675. const inv = data[1];
  7676. const stat = data[2].stat;
  7677. const maxActive = 2000 - stat.todayItemsActivity;
  7678. if (maxActive <= 0) {
  7679. setProgress(I18N('NO_MORE_ACTIVITY'), true);
  7680. return;
  7681. }
  7682. let countGetActive = 0;
  7683. const quest = quests.find(e => e.id > 10046 && e.id < 10051);
  7684. if (quest) {
  7685. countGetActive = 1750 - quest.progress;
  7686. }
  7687. if (countGetActive <= 0) {
  7688. countGetActive = maxActive;
  7689. }
  7690. console.log(countGetActive);
  7691.  
  7692. countGetActive = +(await popup.confirm(I18N('EXCHANGE_ITEMS', { maxActive }), [
  7693. { result: false, isClose: true },
  7694. { msg: I18N('GET_ACTIVITY'), isInput: true, default: countGetActive.toString() },
  7695. ]));
  7696.  
  7697. if (!countGetActive) {
  7698. return;
  7699. }
  7700.  
  7701. if (countGetActive > maxActive) {
  7702. countGetActive = maxActive;
  7703. }
  7704.  
  7705. const items = lib.getData('inventoryItem');
  7706.  
  7707. let itemsInfo = [];
  7708. for (let type of ['gear', 'scroll']) {
  7709. for (let i in inv[type]) {
  7710. const v = items[type][i]?.enchantValue || 0;
  7711. itemsInfo.push({
  7712. id: i,
  7713. count: inv[type][i],
  7714. v,
  7715. type
  7716. })
  7717. }
  7718. const invType = 'fragment' + type.toLowerCase().charAt(0).toUpperCase() + type.slice(1);
  7719. for (let i in inv[invType]) {
  7720. const v = items[type][i]?.fragmentEnchantValue || 0;
  7721. itemsInfo.push({
  7722. id: i,
  7723. count: inv[invType][i],
  7724. v,
  7725. type: invType
  7726. })
  7727. }
  7728. }
  7729. itemsInfo = itemsInfo.filter(e => e.v < 4 && e.count > 200);
  7730. itemsInfo = itemsInfo.sort((a, b) => b.count - a.count);
  7731. console.log(itemsInfo);
  7732. const activeItem = itemsInfo.shift();
  7733. console.log(activeItem);
  7734. const countItem = Math.ceil(countGetActive / activeItem.v);
  7735. if (countItem > activeItem.count) {
  7736. setProgress(I18N('NOT_ENOUGH_ITEMS'), true);
  7737. console.log(activeItem);
  7738. return;
  7739. }
  7740.  
  7741. await Send(JSON.stringify({
  7742. calls: [{
  7743. name: "clanItemsForActivity",
  7744. args: {
  7745. items: {
  7746. [activeItem.type]: {
  7747. [activeItem.id]: countItem
  7748. }
  7749. }
  7750. },
  7751. ident: "body"
  7752. }]
  7753. })).then(e => {
  7754. /** TODO: Вывести потраченые предметы */
  7755. console.log(e);
  7756. setProgress(`${I18N('ACTIVITY_RECEIVED')}: ` + e.results[0].result.response, true);
  7757. });
  7758. }
  7759.  
  7760. async function buyHeroFragments() {
  7761. const result = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"},{"name":"shopGetAll","args":{},"ident":"shopGetAll"}]}')
  7762. .then(e => e.results.map(n => n.result.response));
  7763. const inv = result[0];
  7764. const shops = Object.values(result[1]).filter(shop => [4, 5, 6, 8, 9, 10, 17].includes(shop.id));
  7765. const calls = [];
  7766.  
  7767. for (let shop of shops) {
  7768. const slots = Object.values(shop.slots);
  7769. for (const slot of slots) {
  7770. /* Уже куплено */
  7771. if (slot.bought) {
  7772. continue;
  7773. }
  7774. /* Не душа героя */
  7775. if (!('fragmentHero' in slot.reward)) {
  7776. continue;
  7777. }
  7778. const coin = Object.keys(slot.cost).pop();
  7779. const coinId = Object.keys(slot.cost[coin]).pop();
  7780. const stock = inv[coin][coinId] || 0;
  7781. /* Не хватает на покупку */
  7782. if (slot.cost[coin][coinId] > stock) {
  7783. continue;
  7784. }
  7785. inv[coin][coinId] -= slot.cost[coin][coinId];
  7786. calls.push({
  7787. name: "shopBuy",
  7788. args: {
  7789. shopId: shop.id,
  7790. slot: slot.id,
  7791. cost: slot.cost,
  7792. reward: slot.reward,
  7793. },
  7794. ident: `shopBuy_${shop.id}_${slot.id}`,
  7795. })
  7796. }
  7797. }
  7798.  
  7799. if (!calls.length) {
  7800. setProgress(I18N('NO_PURCHASABLE_HERO_SOULS'), true);
  7801. return;
  7802. }
  7803.  
  7804. const bought = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  7805. if (!bought) {
  7806. console.log('что-то пошло не так')
  7807. return;
  7808. }
  7809.  
  7810. let countHeroSouls = 0;
  7811. for (const buy of bought) {
  7812. countHeroSouls += +Object.values(Object.values(buy).pop()).pop();
  7813. }
  7814. console.log(countHeroSouls, bought, calls);
  7815. setProgress(I18N('PURCHASED_HERO_SOULS', { countHeroSouls }), true);
  7816. }
  7817.  
  7818. /** Открыть платные сундуки в Запределье за 90 */
  7819. async function bossOpenChestPay() {
  7820. const callsNames = ['userGetInfo', 'bossGetAll', 'specialOffer_getAll', 'getTime'];
  7821. const info = await Send({ calls: callsNames.map((name) => ({ name, args: {}, ident: name })) }).then((e) =>
  7822. e.results.map((n) => n.result.response)
  7823. );
  7824.  
  7825. const user = info[0];
  7826. const boses = info[1];
  7827. const offers = info[2];
  7828. const time = info[3];
  7829.  
  7830. const discountOffer = offers.find((e) => e.offerType == 'costReplaceOutlandChest');
  7831.  
  7832. let discount = 1;
  7833. if (discountOffer && discountOffer.endTime > time) {
  7834. discount = 1 - discountOffer.offerData.outlandChest.discountPercent / 100;
  7835. }
  7836.  
  7837. cost9chests = 540 * discount;
  7838. cost18chests = 1740 * discount;
  7839. costFirstChest = 90 * discount;
  7840. costSecondChest = 200 * discount;
  7841.  
  7842. const currentStarMoney = user.starMoney;
  7843. if (currentStarMoney < cost9chests) {
  7844. setProgress('Недостаточно изюма, нужно ' + cost9chests + ' у Вас ' + currentStarMoney, true);
  7845. return;
  7846. }
  7847.  
  7848. const imgEmerald =
  7849. "<img style='position: relative;top: 3px;' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAXCAYAAAD+4+QTAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAY8SURBVEhLpVV5bFVlFv/d7a19W3tfN1pKabGFAm3Rlg4toAWRiH+AioiaqAkaE42NycRR0ZnomJnJYHAJERGNyx/GJYoboo2igKVSMUUKreW1pRvUvr7XvvXe9+7qeW1nGJaJycwvObnny/fl/L7zO+c7l8EV0LAKzA+H83lAFAC/BeDJN2gnc5yd/WaQ8Q0NCCnAANkU+ZfjIpKqJWBOd4EDbHagueBPb1tWuesi9Rqn86zJZDbAMTp4xoSFzMaa4FVe6fra3bbzQbYN6A8Cmrz0qoBx8gzMmaj/QfKHWyxs+4e1DiC78M9v5TTn1RtbVH+kMWlJCCad100VOmQiUWFnNLg4HW42QeYEl3KnIiP5Bzu/dr27o0UistD48k2d8rF9Sib9GZKaejAnOmrs2/6e3VR3q7idF41GWVA41uQQ1RMY00ZJrChcrAYvx8HHaSjil8LLilCY98BORylBKlWQHhjzfvfFnuTfPn1O+xFolzM7s5nMI80rSl7qib8ykRNcWyaUosBWgnN6BL3pHuRwucjmnBTUCjfHwElkNiaNPHYr0mYCKnMeE/r3OC2NQiZZheHsfQ9Vu1uAM+eBIX2W5Nqsh/ewtxlrhl75NtUviDpwq+s+NOXWwWFhKKCd6iCQVByV2qSb0wEo5PvhY9YikGrH3uAdiBtBDIdVVAvlyfjBOffuesTcDxySqD3mUxaOPLZ6aktAOS/kqHaYigN7gnsxMGnDAuEuiPw6ymIt3MwaZFFQB7MeTmYjPLSWjTTCioQ5XCOMJIPeoInD/SNOviy6heLmALkckRTyf3xLbtQ8k6sdOodcxoocMoXU9JoFdF8VESMMiWRJmykyedqXTInaQJnOTtYDcJtZ+DXkRSrOou1cCoHx4LptL0nLgYU8kWhwlFgrNV2wFnEmVAr+w9gUzkwQic2DoNmLYe0QgkYXIuYg4uYYosYQJs1fMGkEpqWzUVucDh9E37gCIWFgvY9FcbniEipii6hbwZVilP0kXB/jysrrPLqU3yDG0JzXhA3OjWgsXo8UG6XbR6AxScqJjJHo/gmY0+9FIOn80I0UkukQFohJNFZmwV/uhosX2j59KPuF8JgS5CI3wHB90RUdKL12pMs7Z3VvfH6WyOajPt+Deb7FRDCBmNmNpNmPhHEWCW0IMXUQaTVEtVPhseYTZRCBeB86h8+hY0yDodsHfny+4NETB7JOLN74TXqmu1Yu4ixHuj3ii0/eaatx7RgY/NYKtR2tm+6B7lbwTGg3bDQ06MLTcsoJettR4DqaC8+u/gfe6HwZOzuGQU8JDR5f1B2+6uHWp8RPSjfsj5/dDyMzfIAj3bqSK8bGW579ECPWXRViHTijDK2BPojcPCxkbXCZflh1H5ISkCCSWJxI8jcjmErhnaHh6fdzdbZTd0aKd7Q+5T/gqj6VyBBkwmfG0QySkkHDJq19dDrgvP3GQq/Pt6h/8mesLqqFz+6DRq0qWkR4uGzEYhrGJBktNdvQGfoJH490YwmNuwKt+LWvWubtAk6GlPHhfw/LCyQz0BXEZOaoLcDf1lAt2z1z5nIhlIsL0Csfo90sWDkHXDYXaq2VWFZShffOfoQc0qOIzT9wbGvpXxOYGgG6SdwLuJSE6mPT1ZNdUdM9fyi8YlnTEiHLc423GBPaFBSVQcrQqcMYrJrbjElVRUf8FIq57K4z/8x7rL9f7ymsb0vHz83GmsXlJJSlsXKhxn3w+YSyrC48vKB0zVbLYqHCUYEe5SekaRYznBuLvU1olwbBmvr4r/v4RzteN4761x+Wxg9dGPH/wkzhL8WRHkMvKo7j/sc/Swfir7ZT/WTYSapc6LwFhc4qSKwLEYHXoz/bnzv8dOw7+4ojyYkvLyfI4MokhNToSKZwYf+6u3e39P3y8XH6AeY5yxHiBcx11OA8rZO9qTdaNx9/n9KPyUdnOulKuFyui6GHAAkHpEDBptqauaKtcMySRBW3HH2Do1+9WbP9GXocVGj5okJfit8jATY06Dh+MBIyiwZrrylb4XXneO1BV9df7n/tMb0/0J17O9LJU7Nn/x+UrKvOyOq58dXtNz0Q2Luz+cUnrqe1q+qmyv8q9/+EypuXZrK2kdEwgW3R5pW/r8I0gN8AVk6uP7Y929oAAAAASUVORK5CYII='>";
  7850.  
  7851. if (currentStarMoney < cost9chests) {
  7852. setProgress(I18N('NOT_ENOUGH_EMERALDS_540', { currentStarMoney, imgEmerald }), true);
  7853. return;
  7854. }
  7855.  
  7856. const buttons = [{ result: false, isClose: true }];
  7857.  
  7858. if (currentStarMoney >= cost9chests) {
  7859. buttons.push({
  7860. msg: I18N('BUY_OUTLAND_BTN', { count: 9, countEmerald: cost9chests, imgEmerald }),
  7861. result: [costFirstChest, costFirstChest, 0],
  7862. });
  7863. }
  7864.  
  7865. if (currentStarMoney >= cost18chests) {
  7866. buttons.push({
  7867. msg: I18N('BUY_OUTLAND_BTN', { count: 18, countEmerald: cost18chests, imgEmerald }),
  7868. result: [costFirstChest, costFirstChest, 0, costSecondChest, costSecondChest, 0],
  7869. });
  7870. }
  7871.  
  7872. const answer = await popup.confirm(`<div style="margin-bottom: 15px;">${I18N('BUY_OUTLAND')}</div>`, buttons);
  7873.  
  7874. if (!answer) {
  7875. return;
  7876. }
  7877.  
  7878. const callBoss = [];
  7879. let n = 0;
  7880. for (let boss of boses) {
  7881. const bossId = boss.id;
  7882. if (boss.chestNum != 2) {
  7883. continue;
  7884. }
  7885. const calls = [];
  7886. for (const starmoney of answer) {
  7887. calls.push({
  7888. name: 'bossOpenChest',
  7889. args: {
  7890. amount: 1,
  7891. bossId,
  7892. starmoney,
  7893. },
  7894. ident: 'bossOpenChest_' + ++n,
  7895. });
  7896. }
  7897. callBoss.push(calls);
  7898. }
  7899.  
  7900. if (!callBoss.length) {
  7901. setProgress(I18N('CHESTS_NOT_AVAILABLE'), true);
  7902. return;
  7903. }
  7904.  
  7905. let count = 0;
  7906. let errors = 0;
  7907. for (const calls of callBoss) {
  7908. const result = await Send({ calls });
  7909. console.log(result);
  7910. if (result?.results) {
  7911. count += result.results.length;
  7912. } else {
  7913. errors++;
  7914. }
  7915. }
  7916.  
  7917. setProgress(`${I18N('OUTLAND_CHESTS_RECEIVED')}: ${count}`, true);
  7918. }
  7919.  
  7920. async function autoRaidAdventure() {
  7921. const calls = [
  7922. {
  7923. name: "userGetInfo",
  7924. args: {},
  7925. ident: "userGetInfo"
  7926. },
  7927. {
  7928. name: "adventure_raidGetInfo",
  7929. args: {},
  7930. ident: "adventure_raidGetInfo"
  7931. }
  7932. ];
  7933. const result = await Send(JSON.stringify({ calls }))
  7934. .then(e => e.results.map(n => n.result.response));
  7935.  
  7936. const portalSphere = result[0].refillable.find(n => n.id == 45);
  7937. const adventureRaid = Object.entries(result[1].raid).filter(e => e[1]).pop()
  7938. const adventureId = adventureRaid ? adventureRaid[0] : 0;
  7939.  
  7940. if (!portalSphere.amount || !adventureId) {
  7941. setProgress(I18N('RAID_NOT_AVAILABLE'), true);
  7942. return;
  7943. }
  7944.  
  7945. const countRaid = +(await popup.confirm(I18N('RAID_ADVENTURE', { adventureId }), [
  7946. { result: false, isClose: true },
  7947. { msg: I18N('RAID'), isInput: true, default: portalSphere.amount },
  7948. ]));
  7949.  
  7950. if (!countRaid) {
  7951. return;
  7952. }
  7953.  
  7954. if (countRaid > portalSphere.amount) {
  7955. countRaid = portalSphere.amount;
  7956. }
  7957.  
  7958. const resultRaid = await Send(JSON.stringify({
  7959. calls: [...Array(countRaid)].map((e, i) => ({
  7960. name: "adventure_raid",
  7961. args: {
  7962. adventureId
  7963. },
  7964. ident: `body_${i}`
  7965. }))
  7966. })).then(e => e.results.map(n => n.result.response));
  7967.  
  7968. if (!resultRaid.length) {
  7969. console.log(resultRaid);
  7970. setProgress(I18N('SOMETHING_WENT_WRONG'), true);
  7971. return;
  7972. }
  7973.  
  7974. console.log(resultRaid, adventureId, portalSphere.amount);
  7975. setProgress(I18N('ADVENTURE_COMPLETED', { adventureId, times: resultRaid.length }), true);
  7976. }
  7977.  
  7978. /** Вывести всю клановую статистику в консоль браузера */
  7979. async function clanStatistic() {
  7980. const copy = function (text) {
  7981. const copyTextarea = document.createElement("textarea");
  7982. copyTextarea.style.opacity = "0";
  7983. copyTextarea.textContent = text;
  7984. document.body.appendChild(copyTextarea);
  7985. copyTextarea.select();
  7986. document.execCommand("copy");
  7987. document.body.removeChild(copyTextarea);
  7988. delete copyTextarea;
  7989. }
  7990. const calls = [
  7991. { name: "clanGetInfo", args: {}, ident: "clanGetInfo" },
  7992. { name: "clanGetWeeklyStat", args: {}, ident: "clanGetWeeklyStat" },
  7993. { name: "clanGetLog", args: {}, ident: "clanGetLog" },
  7994. ];
  7995.  
  7996. const result = await Send(JSON.stringify({ calls }));
  7997.  
  7998. const dataClanInfo = result.results[0].result.response;
  7999. const dataClanStat = result.results[1].result.response;
  8000. const dataClanLog = result.results[2].result.response;
  8001.  
  8002. const membersStat = {};
  8003. for (let i = 0; i < dataClanStat.stat.length; i++) {
  8004. membersStat[dataClanStat.stat[i].id] = dataClanStat.stat[i];
  8005. }
  8006.  
  8007. const joinStat = {};
  8008. historyLog = dataClanLog.history;
  8009. for (let j in historyLog) {
  8010. his = historyLog[j];
  8011. if (his.event == 'join') {
  8012. joinStat[his.userId] = his.ctime;
  8013. }
  8014. }
  8015.  
  8016. const infoArr = [];
  8017. const members = dataClanInfo.clan.members;
  8018. for (let n in members) {
  8019. var member = [
  8020. n,
  8021. members[n].name,
  8022. members[n].level,
  8023. dataClanInfo.clan.warriors.includes(+n) ? 1 : 0,
  8024. (new Date(members[n].lastLoginTime * 1000)).toLocaleString().replace(',', ''),
  8025. joinStat[n] ? (new Date(joinStat[n] * 1000)).toLocaleString().replace(',', '') : '',
  8026. membersStat[n].activity.reverse().join('\t'),
  8027. membersStat[n].adventureStat.reverse().join('\t'),
  8028. membersStat[n].clanGifts.reverse().join('\t'),
  8029. membersStat[n].clanWarStat.reverse().join('\t'),
  8030. membersStat[n].dungeonActivity.reverse().join('\t'),
  8031. ];
  8032. infoArr.push(member);
  8033. }
  8034. const info = infoArr.sort((a, b) => (b[2] - a[2])).map((e) => e.join('\t')).join('\n');
  8035. console.log(info);
  8036. copy(info);
  8037. setProgress(I18N('CLAN_STAT_COPY'), true);
  8038. }
  8039.  
  8040. async function buyInStoreForGold() {
  8041. const result = await Send('{"calls":[{"name":"shopGetAll","args":{},"ident":"body"},{"name":"userGetInfo","args":{},"ident":"userGetInfo"}]}').then(e => e.results.map(n => n.result.response));
  8042. const shops = result[0];
  8043. const user = result[1];
  8044. let gold = user.gold;
  8045. const calls = [];
  8046. if (shops[17]) {
  8047. const slots = shops[17].slots;
  8048. for (let i = 1; i <= 2; i++) {
  8049. if (!slots[i].bought) {
  8050. const costGold = slots[i].cost.gold;
  8051. if ((gold - costGold) < 0) {
  8052. continue;
  8053. }
  8054. gold -= costGold;
  8055. calls.push({
  8056. name: "shopBuy",
  8057. args: {
  8058. shopId: 17,
  8059. slot: i,
  8060. cost: slots[i].cost,
  8061. reward: slots[i].reward,
  8062. },
  8063. ident: 'body_' + i,
  8064. })
  8065. }
  8066. }
  8067. }
  8068. const slots = shops[1].slots;
  8069. for (let i = 4; i <= 6; i++) {
  8070. if (!slots[i].bought && slots[i]?.cost?.gold) {
  8071. const costGold = slots[i].cost.gold;
  8072. if ((gold - costGold) < 0) {
  8073. continue;
  8074. }
  8075. gold -= costGold;
  8076. calls.push({
  8077. name: "shopBuy",
  8078. args: {
  8079. shopId: 1,
  8080. slot: i,
  8081. cost: slots[i].cost,
  8082. reward: slots[i].reward,
  8083. },
  8084. ident: 'body_' + i,
  8085. })
  8086. }
  8087. }
  8088.  
  8089. if (!calls.length) {
  8090. setProgress(I18N('NOTHING_BUY'), true);
  8091. return;
  8092. }
  8093.  
  8094. const resultBuy = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  8095. console.log(resultBuy);
  8096. const countBuy = resultBuy.length;
  8097. setProgress(I18N('LOTS_BOUGHT', { countBuy }), true);
  8098. }
  8099.  
  8100. function rewardsAndMailFarm() {
  8101. return new Promise(function (resolve, reject) {
  8102. let questGetAllCall = {
  8103. calls: [{
  8104. name: "questGetAll",
  8105. args: {},
  8106. ident: "questGetAll"
  8107. }, {
  8108. name: "mailGetAll",
  8109. args: {},
  8110. ident: "mailGetAll"
  8111. }]
  8112. }
  8113. send(JSON.stringify(questGetAllCall), function (data) {
  8114. if (!data) return;
  8115. const questGetAll = data.results[0].result.response.filter((e) => e.state == 2);
  8116. const questBattlePass = lib.getData('quest').battlePass;
  8117. const questChainBPass = lib.getData('battlePass').questChain;
  8118. const listBattlePass = lib.getData('battlePass').list;
  8119.  
  8120. const questAllFarmCall = {
  8121. calls: [],
  8122. };
  8123. const questIds = [];
  8124. for (let quest of questGetAll) {
  8125. if (quest.id >= 2001e4) {
  8126. continue;
  8127. }
  8128. if (quest.id > 1e6 && quest.id < 2e7) {
  8129. const questInfo = questBattlePass[quest.id];
  8130. const chain = questChainBPass[questInfo.chain];
  8131. if (chain.requirement?.battlePassTicket) {
  8132. continue;
  8133. }
  8134. const battlePass = listBattlePass[chain.battlePass];
  8135. const startTime = battlePass.startCondition.time.value * 1e3
  8136. const endTime = new Date(startTime + battlePass.duration * 1e3);
  8137. if (startTime > Date.now() || endTime < Date.now()) {
  8138. continue;
  8139. }
  8140. }
  8141. if (quest.id >= 2e7) {
  8142. questIds.push(quest.id);
  8143. continue;
  8144. }
  8145. questAllFarmCall.calls.push({
  8146. name: 'questFarm',
  8147. args: {
  8148. questId: quest.id,
  8149. },
  8150. ident: `questFarm_${quest.id}`,
  8151. });
  8152. }
  8153.  
  8154. if (questIds.length) {
  8155. questAllFarmCall.calls.push({
  8156. name: 'quest_questsFarm',
  8157. args: { questIds },
  8158. ident: 'quest_questsFarm',
  8159. });
  8160. }
  8161.  
  8162. let letters = data?.results[1]?.result?.response?.letters;
  8163. letterIds = lettersFilter(letters);
  8164.  
  8165. if (letterIds.length) {
  8166. questAllFarmCall.calls.push({
  8167. name: 'mailFarm',
  8168. args: { letterIds },
  8169. ident: 'mailFarm',
  8170. });
  8171. }
  8172.  
  8173. if (!questAllFarmCall.calls.length) {
  8174. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  8175. resolve();
  8176. return;
  8177. }
  8178.  
  8179. send(JSON.stringify(questAllFarmCall), async function (res) {
  8180. let countQuests = 0;
  8181. let countMail = 0;
  8182. let questsIds = [];
  8183. for (let call of res.results) {
  8184. if (call.ident.includes('questFarm')) {
  8185. countQuests++;
  8186. } else if (call.ident.includes('questsFarm')) {
  8187. countQuests += Object.keys(call.result.response).length;
  8188. } else if (call.ident.includes('mailFarm')) {
  8189. countMail = Object.keys(call.result.response).length;
  8190. }
  8191.  
  8192. const newQuests = call.result.newQuests;
  8193. if (newQuests) {
  8194. for (let quest of newQuests) {
  8195. if ((quest.id < 1e6 || (quest.id >= 2e7 && quest.id < 2001e4)) && quest.state == 2) {
  8196. questsIds.push(quest.id);
  8197. }
  8198. }
  8199. }
  8200. }
  8201.  
  8202. while (questsIds.length) {
  8203. const questIds = [];
  8204. const calls = [];
  8205. for (let questId of questsIds) {
  8206. if (questId < 1e6) {
  8207. calls.push({
  8208. name: 'questFarm',
  8209. args: {
  8210. questId,
  8211. },
  8212. ident: `questFarm_${questId}`,
  8213. });
  8214. countQuests++;
  8215. } else if (questId >= 2e7 && questId < 2001e4) {
  8216. questIds.push(questId);
  8217. countQuests++;
  8218. }
  8219. }
  8220. calls.push({
  8221. name: 'quest_questsFarm',
  8222. args: { questIds },
  8223. ident: 'body',
  8224. });
  8225. const results = await Send({ calls }).then((e) => e.results.map((e) => e.result));
  8226. questsIds = [];
  8227. for (const result of results) {
  8228. const newQuests = result.newQuests;
  8229. if (newQuests) {
  8230. for (let quest of newQuests) {
  8231. if (quest.state == 2) {
  8232. questsIds.push(quest.id);
  8233. }
  8234. }
  8235. }
  8236. }
  8237. }
  8238.  
  8239. setProgress(I18N('COLLECT_REWARDS_AND_MAIL', { countQuests, countMail }), true);
  8240. resolve();
  8241. });
  8242. });
  8243. })
  8244. }
  8245.  
  8246. class epicBrawl {
  8247. timeout = null;
  8248. time = null;
  8249.  
  8250. constructor() {
  8251. if (epicBrawl.inst) {
  8252. return epicBrawl.inst;
  8253. }
  8254. epicBrawl.inst = this;
  8255. return this;
  8256. }
  8257.  
  8258. runTimeout(func, timeDiff) {
  8259. const worker = new Worker(URL.createObjectURL(new Blob([`
  8260. self.onmessage = function(e) {
  8261. const timeDiff = e.data;
  8262.  
  8263. if (timeDiff > 0) {
  8264. setTimeout(() => {
  8265. self.postMessage(1);
  8266. self.close();
  8267. }, timeDiff);
  8268. }
  8269. };
  8270. `])));
  8271. worker.postMessage(timeDiff);
  8272. worker.onmessage = () => {
  8273. func();
  8274. };
  8275. return true;
  8276. }
  8277.  
  8278. timeDiff(date1, date2) {
  8279. const date1Obj = new Date(date1);
  8280. const date2Obj = new Date(date2);
  8281.  
  8282. const timeDiff = Math.abs(date2Obj - date1Obj);
  8283.  
  8284. const totalSeconds = timeDiff / 1000;
  8285. const minutes = Math.floor(totalSeconds / 60);
  8286. const seconds = Math.floor(totalSeconds % 60);
  8287.  
  8288. const formattedMinutes = String(minutes).padStart(2, '0');
  8289. const formattedSeconds = String(seconds).padStart(2, '0');
  8290.  
  8291. return `${formattedMinutes}:${formattedSeconds}`;
  8292. }
  8293.  
  8294. check() {
  8295. console.log(new Date(this.time))
  8296. if (Date.now() > this.time) {
  8297. this.timeout = null;
  8298. this.start()
  8299. return;
  8300. }
  8301. this.timeout = this.runTimeout(() => this.check(), 6e4);
  8302. return this.timeDiff(this.time, Date.now())
  8303. }
  8304.  
  8305. async start() {
  8306. if (this.timeout) {
  8307. const time = this.timeDiff(this.time, Date.now());
  8308. console.log(new Date(this.time))
  8309. setProgress(I18N('TIMER_ALREADY', { time }), false, hideProgress);
  8310. return;
  8311. }
  8312. setProgress(I18N('EPIC_BRAWL'), false, hideProgress);
  8313. const teamInfo = await Send('{"calls":[{"name":"teamGetAll","args":{},"ident":"teamGetAll"},{"name":"teamGetFavor","args":{},"ident":"teamGetFavor"},{"name":"userGetInfo","args":{},"ident":"userGetInfo"}]}').then(e => e.results.map(n => n.result.response));
  8314. const refill = teamInfo[2].refillable.find(n => n.id == 52)
  8315. this.time = (refill.lastRefill + 3600) * 1000
  8316. const attempts = refill.amount;
  8317. if (!attempts) {
  8318. console.log(new Date(this.time));
  8319. const time = this.check();
  8320. setProgress(I18N('NO_ATTEMPTS_TIMER_START', { time }), false, hideProgress);
  8321. return;
  8322. }
  8323.  
  8324. if (!teamInfo[0].epic_brawl) {
  8325. setProgress(I18N('NO_HEROES_PACK'), false, hideProgress);
  8326. return;
  8327. }
  8328.  
  8329. const args = {
  8330. heroes: teamInfo[0].epic_brawl.filter(e => e < 1000),
  8331. pet: teamInfo[0].epic_brawl.filter(e => e > 6000).pop(),
  8332. favor: teamInfo[1].epic_brawl,
  8333. }
  8334.  
  8335. let wins = 0;
  8336. let coins = 0;
  8337. let streak = { progress: 0, nextStage: 0 };
  8338. for (let i = attempts; i > 0; i--) {
  8339. const info = await Send(JSON.stringify({
  8340. calls: [
  8341. { name: "epicBrawl_getEnemy", args: {}, ident: "epicBrawl_getEnemy" }, { name: "epicBrawl_startBattle", args, ident: "epicBrawl_startBattle" }
  8342. ]
  8343. })).then(e => e.results.map(n => n.result.response));
  8344.  
  8345. const { progress, result } = await Calc(info[1].battle);
  8346. const endResult = await Send(JSON.stringify({ calls: [{ name: "epicBrawl_endBattle", args: { progress, result }, ident: "epicBrawl_endBattle" }, { name: "epicBrawl_getWinStreak", args: {}, ident: "epicBrawl_getWinStreak" }] })).then(e => e.results.map(n => n.result.response));
  8347.  
  8348. const resultInfo = endResult[0].result;
  8349. streak = endResult[1];
  8350.  
  8351. wins += resultInfo.win;
  8352. coins += resultInfo.reward ? resultInfo.reward.coin[39] : 0;
  8353.  
  8354. console.log(endResult[0].result)
  8355. if (endResult[1].progress == endResult[1].nextStage) {
  8356. const farm = await Send('{"calls":[{"name":"epicBrawl_farmWinStreak","args":{},"ident":"body"}]}').then(e => e.results[0].result.response);
  8357. coins += farm.coin[39];
  8358. }
  8359.  
  8360. setProgress(I18N('EPIC_BRAWL_RESULT', {
  8361. i, wins, attempts, coins,
  8362. progress: streak.progress,
  8363. nextStage: streak.nextStage,
  8364. end: '',
  8365. }), false, hideProgress);
  8366. }
  8367.  
  8368. console.log(new Date(this.time));
  8369. const time = this.check();
  8370. setProgress(I18N('EPIC_BRAWL_RESULT', {
  8371. wins, attempts, coins,
  8372. i: '',
  8373. progress: streak.progress,
  8374. nextStage: streak.nextStage,
  8375. end: I18N('ATTEMPT_ENDED', { time }),
  8376. }), false, hideProgress);
  8377. }
  8378. }
  8379.  
  8380. function countdownTimer(seconds, message) {
  8381. message = message || I18N('TIMER');
  8382. const stopTimer = Date.now() + seconds * 1e3
  8383. return new Promise(resolve => {
  8384. const interval = setInterval(async () => {
  8385. const now = Date.now();
  8386. setProgress(`${message} ${((stopTimer - now) / 1000).toFixed(2)}`, false);
  8387. if (now > stopTimer) {
  8388. clearInterval(interval);
  8389. setProgress('', 1);
  8390. resolve();
  8391. }
  8392. }, 100);
  8393. });
  8394. }
  8395.  
  8396. /** Набить килов в горниле душк */
  8397. async function bossRatingEventSouls() {
  8398. const data = await Send({
  8399. calls: [
  8400. { name: "heroGetAll", args: {}, ident: "teamGetAll" },
  8401. { name: "offerGetAll", args: {}, ident: "offerGetAll" },
  8402. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  8403. ]
  8404. });
  8405. const bossEventInfo = data.results[1].result.response.find(e => e.offerType == "bossEvent");
  8406. if (!bossEventInfo) {
  8407. setProgress('Эвент завершен', true);
  8408. return;
  8409. }
  8410.  
  8411. if (bossEventInfo.progress.score > 250) {
  8412. setProgress('Уже убито больше 250 врагов');
  8413. rewardBossRatingEventSouls();
  8414. return;
  8415. }
  8416. const availablePets = Object.values(data.results[2].result.response).map(e => e.id);
  8417. const heroGetAllList = data.results[0].result.response;
  8418. const usedHeroes = bossEventInfo.progress.usedHeroes;
  8419. const heroList = [];
  8420.  
  8421. for (let heroId in heroGetAllList) {
  8422. let hero = heroGetAllList[heroId];
  8423. if (usedHeroes.includes(hero.id)) {
  8424. continue;
  8425. }
  8426. heroList.push(hero.id);
  8427. }
  8428.  
  8429. if (!heroList.length) {
  8430. setProgress('Нет героев', true);
  8431. return;
  8432. }
  8433.  
  8434. const pet = availablePets.includes(6005) ? 6005 : availablePets[Math.floor(Math.random() * availablePets.length)];
  8435. const petLib = lib.getData('pet');
  8436. let count = 1;
  8437.  
  8438. for (const heroId of heroList) {
  8439. const args = {
  8440. heroes: [heroId],
  8441. pet
  8442. }
  8443. /** Поиск питомца для героя */
  8444. for (const petId of availablePets) {
  8445. if (petLib[petId].favorHeroes.includes(heroId)) {
  8446. args.favor = {
  8447. [heroId]: petId
  8448. }
  8449. break;
  8450. }
  8451. }
  8452.  
  8453. const calls = [{
  8454. name: "bossRatingEvent_startBattle",
  8455. args,
  8456. ident: "body"
  8457. }, {
  8458. name: "offerGetAll",
  8459. args: {},
  8460. ident: "offerGetAll"
  8461. }];
  8462.  
  8463. const res = await Send({ calls });
  8464. count++;
  8465.  
  8466. if ('error' in res) {
  8467. console.error(res.error);
  8468. setProgress('Перезагрузите игру и попробуйте позже', true);
  8469. return;
  8470. }
  8471.  
  8472. const eventInfo = res.results[1].result.response.find(e => e.offerType == "bossEvent");
  8473. if (eventInfo.progress.score > 250) {
  8474. break;
  8475. }
  8476. setProgress('Количество убитых врагов: ' + eventInfo.progress.score + '<br>Использовано ' + count + ' героев');
  8477. }
  8478.  
  8479. rewardBossRatingEventSouls();
  8480. }
  8481. /** Сбор награды из Горнила Душ */
  8482. async function rewardBossRatingEventSouls() {
  8483. const data = await Send({
  8484. calls: [
  8485. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  8486. ]
  8487. });
  8488.  
  8489. const bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  8490. if (!bossEventInfo) {
  8491. setProgress('Эвент завершен', true);
  8492. return;
  8493. }
  8494.  
  8495. const farmedChests = bossEventInfo.progress.farmedChests;
  8496. const score = bossEventInfo.progress.score;
  8497. // setProgress('Количество убитых врагов: ' + score);
  8498. const revard = bossEventInfo.reward;
  8499. const calls = [];
  8500.  
  8501. let count = 0;
  8502. for (let i = 1; i < 10; i++) {
  8503. if (farmedChests.includes(i)) {
  8504. continue;
  8505. }
  8506. if (score < revard[i].score) {
  8507. break;
  8508. }
  8509. calls.push({
  8510. name: "bossRatingEvent_getReward",
  8511. args: {
  8512. rewardId: i
  8513. },
  8514. ident: "body_" + i
  8515. });
  8516. count++;
  8517. }
  8518. if (!count) {
  8519. setProgress('Нечего собирать', true);
  8520. return;
  8521. }
  8522.  
  8523. Send({ calls }).then(e => {
  8524. console.log(e);
  8525. setProgress('Собрано ' + e?.results?.length + ' наград', true);
  8526. })
  8527. }
  8528. /**
  8529. * Spin the Seer
  8530. *
  8531. * Покрутить провидца
  8532. */
  8533. async function rollAscension() {
  8534. const refillable = await Send({calls:[
  8535. {
  8536. name:"userGetInfo",
  8537. args:{},
  8538. ident:"userGetInfo"
  8539. }
  8540. ]}).then(e => e.results[0].result.response.refillable);
  8541. const i47 = refillable.find(i => i.id == 47);
  8542. if (i47?.amount) {
  8543. await Send({ calls: [{ name: "ascensionChest_open", args: { paid: false, amount: 1 }, ident: "body" }] });
  8544. setProgress(I18N('DONE'), true);
  8545. } else {
  8546. setProgress(I18N('NOT_ENOUGH_AP'), true);
  8547. }
  8548. }
  8549.  
  8550. /**
  8551. * Collect gifts for the New Year
  8552. *
  8553. * Собрать подарки на новый год
  8554. */
  8555. function getGiftNewYear() {
  8556. Send({ calls: [{ name: "newYearGiftGet", args: { type: 0 }, ident: "body" }] }).then(e => {
  8557. const gifts = e.results[0].result.response.gifts;
  8558. const calls = gifts.filter(e => e.opened == 0).map(e => ({
  8559. name: "newYearGiftOpen",
  8560. args: {
  8561. giftId: e.id
  8562. },
  8563. ident: `body_${e.id}`
  8564. }));
  8565. if (!calls.length) {
  8566. setProgress(I18N('NY_NO_GIFTS'), 5000);
  8567. return;
  8568. }
  8569. Send({ calls }).then(e => {
  8570. console.log(e.results)
  8571. const msg = I18N('NY_GIFTS_COLLECTED', { count: e.results.length });
  8572. console.log(msg);
  8573. setProgress(msg, 5000);
  8574. });
  8575. })
  8576. }
  8577.  
  8578. async function updateArtifacts() {
  8579. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  8580. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  8581. { result: false, isClose: true }
  8582. ]);
  8583. if (!count) {
  8584. return;
  8585. }
  8586. const quest = new questRun;
  8587. await quest.autoInit();
  8588. const heroes = Object.values(quest.questInfo['heroGetAll']);
  8589. const inventory = quest.questInfo['inventoryGet'];
  8590. const calls = [];
  8591. for (let i = count; i > 0; i--) {
  8592. const upArtifact = quest.getUpgradeArtifact();
  8593. if (!upArtifact.heroId) {
  8594. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  8595. { msg: I18N('YES'), result: true },
  8596. { result: false, isClose: true }
  8597. ])) {
  8598. break;
  8599. } else {
  8600. return;
  8601. }
  8602. }
  8603. const hero = heroes.find(e => e.id == upArtifact.heroId);
  8604. hero.artifacts[upArtifact.slotId].level++;
  8605. inventory[upArtifact.costCurrency][upArtifact.costId] -= upArtifact.costValue;
  8606. calls.push({
  8607. name: "heroArtifactLevelUp",
  8608. args: {
  8609. heroId: upArtifact.heroId,
  8610. slotId: upArtifact.slotId
  8611. },
  8612. ident: `heroArtifactLevelUp_${i}`
  8613. });
  8614. }
  8615.  
  8616. if (!calls.length) {
  8617. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8618. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8619. return;
  8620. }
  8621.  
  8622. await Send(JSON.stringify({ calls })).then(e => {
  8623. if ('error' in e) {
  8624. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8625. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8626. } else {
  8627. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  8628. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  8629. }
  8630. });
  8631. }
  8632.  
  8633. window.sign = a => {
  8634. const i = this['\x78\x79\x7a'];
  8635. 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'))
  8636. }
  8637.  
  8638. async function updateSkins() {
  8639. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  8640. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  8641. { result: false, isClose: true }
  8642. ]);
  8643. if (!count) {
  8644. return;
  8645. }
  8646.  
  8647. const quest = new questRun;
  8648. await quest.autoInit();
  8649. const heroes = Object.values(quest.questInfo['heroGetAll']);
  8650. const inventory = quest.questInfo['inventoryGet'];
  8651. const calls = [];
  8652. for (let i = count; i > 0; i--) {
  8653. const upSkin = quest.getUpgradeSkin();
  8654. if (!upSkin.heroId) {
  8655. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  8656. { msg: I18N('YES'), result: true },
  8657. { result: false, isClose: true }
  8658. ])) {
  8659. break;
  8660. } else {
  8661. return;
  8662. }
  8663. }
  8664. const hero = heroes.find(e => e.id == upSkin.heroId);
  8665. hero.skins[upSkin.skinId]++;
  8666. inventory[upSkin.costCurrency][upSkin.costCurrencyId] -= upSkin.cost;
  8667. calls.push({
  8668. name: "heroSkinUpgrade",
  8669. args: {
  8670. heroId: upSkin.heroId,
  8671. skinId: upSkin.skinId
  8672. },
  8673. ident: `heroSkinUpgrade_${i}`
  8674. })
  8675. }
  8676.  
  8677. if (!calls.length) {
  8678. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8679. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8680. return;
  8681. }
  8682.  
  8683. await Send(JSON.stringify({ calls })).then(e => {
  8684. if ('error' in e) {
  8685. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8686. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8687. } else {
  8688. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  8689. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  8690. }
  8691. });
  8692. }
  8693.  
  8694. function getQuestionInfo(img, nameOnly = false) {
  8695. const libHeroes = Object.values(lib.data.hero);
  8696. const parts = img.split(':');
  8697. const id = parts[1];
  8698. switch (parts[0]) {
  8699. case 'titanArtifact_id':
  8700. return cheats.translate("LIB_TITAN_ARTIFACT_NAME_" + id);
  8701. case 'titan':
  8702. return cheats.translate("LIB_HERO_NAME_" + id);
  8703. case 'skill':
  8704. return cheats.translate("LIB_SKILL_" + id);
  8705. case 'inventoryItem_gear':
  8706. return cheats.translate("LIB_GEAR_NAME_" + id);
  8707. case 'inventoryItem_coin':
  8708. return cheats.translate("LIB_COIN_NAME_" + id);
  8709. case 'artifact':
  8710. if (nameOnly) {
  8711. return cheats.translate("LIB_ARTIFACT_NAME_" + id);
  8712. }
  8713. heroes = libHeroes.filter(h => h.id < 100 && h.artifacts.includes(+id));
  8714. return {
  8715. /** Как называется этот артефакт? */
  8716. name: cheats.translate("LIB_ARTIFACT_NAME_" + id),
  8717. /** Какому герою принадлежит этот артефакт? */
  8718. heroes: heroes.map(h => cheats.translate("LIB_HERO_NAME_" + h.id))
  8719. };
  8720. case 'hero':
  8721. if (nameOnly) {
  8722. return cheats.translate("LIB_HERO_NAME_" + id);
  8723. }
  8724. artifacts = lib.data.hero[id].artifacts;
  8725. return {
  8726. /** Как зовут этого героя? */
  8727. name: cheats.translate("LIB_HERO_NAME_" + id),
  8728. /** Какой артефакт принадлежит этому герою? */
  8729. artifact: artifacts.map(a => cheats.translate("LIB_ARTIFACT_NAME_" + a))
  8730. };
  8731. }
  8732. }
  8733.  
  8734. function hintQuest(quest) {
  8735. const result = {};
  8736. if (quest?.questionIcon) {
  8737. const info = getQuestionInfo(quest.questionIcon);
  8738. if (info?.heroes) {
  8739. /** Какому герою принадлежит этот артефакт? */
  8740. result.answer = quest.answers.filter(e => info.heroes.includes(e.answerText.slice(1)));
  8741. }
  8742. if (info?.artifact) {
  8743. /** Какой артефакт принадлежит этому герою? */
  8744. result.answer = quest.answers.filter(e => info.artifact.includes(e.answerText.slice(1)));
  8745. }
  8746. if (typeof info == 'string') {
  8747. result.info = { name: info };
  8748. } else {
  8749. result.info = info;
  8750. }
  8751. }
  8752.  
  8753. if (quest.answers[0]?.answerIcon) {
  8754. result.answer = quest.answers.filter(e => quest.question.includes(getQuestionInfo(e.answerIcon, true)))
  8755. }
  8756.  
  8757. if ((!result?.answer || !result.answer.length) && !result.info?.name) {
  8758. return false;
  8759. }
  8760.  
  8761. let resultText = '';
  8762. if (result?.info) {
  8763. resultText += I18N('PICTURE') + result.info.name;
  8764. }
  8765. console.log(result);
  8766. if (result?.answer && result.answer.length) {
  8767. resultText += I18N('ANSWER') + result.answer[0].id + (!result.answer[0].answerIcon ? ' - ' + result.answer[0].answerText : '');
  8768. }
  8769.  
  8770. return resultText;
  8771. }
  8772.  
  8773. async function farmBattlePass() {
  8774. const isFarmReward = (reward) => {
  8775. return !(reward?.buff || reward?.fragmentHero || reward?.bundleHeroReward);
  8776. };
  8777.  
  8778. const battlePassProcess = (pass) => {
  8779. if (!pass.id) {return []}
  8780. const levels = Object.values(lib.data.battlePass.level).filter(x => x.battlePass == pass.id)
  8781. const last_level = levels[levels.length - 1];
  8782. let actual = Math.max(...levels.filter(p => pass.exp >= p.experience).map(p => p.level))
  8783.  
  8784. if (pass.exp > last_level.experience) {
  8785. actual = last_level.level + (pass.exp - last_level.experience) / last_level.experienceByLevel;
  8786. }
  8787. const calls = [];
  8788. for(let i = 1; i <= actual; i++) {
  8789. const level = i >= last_level.level ? last_level : levels.find(l => l.level === i);
  8790. const reward = {free: level?.freeReward, paid:level?.paidReward};
  8791.  
  8792. if (!pass.rewards[i]?.free && isFarmReward(reward.free)) {
  8793. const args = {level: i, free:true};
  8794. if (!pass.gold) { args.id = pass.id }
  8795. calls.push({ name: 'battlePass_farmReward', args, ident: `${pass.gold ? 'body' : 'spesial'}_free_${args.id}_${i}` });
  8796. }
  8797. if (pass.ticket && !pass.rewards[i]?.paid && isFarmReward(reward.paid)) {
  8798. const args = {level: i, free:false};
  8799. if (!pass.gold) { args.id = pass.id}
  8800. calls.push({ name: 'battlePass_farmReward', args, ident: `${pass.gold ? 'body' : 'spesial'}_paid_${args.id}_${i}` });
  8801. }
  8802. }
  8803. return calls;
  8804. }
  8805.  
  8806. const passes = await Send({
  8807. calls: [
  8808. { name: 'battlePass_getInfo', args: {}, ident: 'getInfo' },
  8809. { name: 'battlePass_getSpecial', args: {}, ident: 'getSpecial' },
  8810. ],
  8811. }).then((e) => [{...e.results[0].result.response?.battlePass, gold: true}, ...Object.values(e.results[1].result.response)]);
  8812.  
  8813. const calls = passes.map(p => battlePassProcess(p)).flat()
  8814.  
  8815. let results = await Send({calls});
  8816. if (results.error) {
  8817. console.log(results.error);
  8818. setProgress(I18N('SOMETHING_WENT_WRONG'));
  8819. } else {
  8820. setProgress(I18N('SEASON_REWARD_COLLECTED', {count: results.results.length}), true);
  8821. }
  8822. }
  8823.  
  8824. async function sellHeroSoulsForGold() {
  8825. let { fragmentHero, heroes } = await Send({
  8826. calls: [
  8827. { name: 'inventoryGet', args: {}, ident: 'inventoryGet' },
  8828. { name: 'heroGetAll', args: {}, ident: 'heroGetAll' },
  8829. ],
  8830. })
  8831. .then((e) => e.results.map((r) => r.result.response))
  8832. .then((e) => ({ fragmentHero: e[0].fragmentHero, heroes: e[1] }));
  8833.  
  8834. const calls = [];
  8835. for (let i in fragmentHero) {
  8836. if (heroes[i] && heroes[i].star == 6) {
  8837. calls.push({
  8838. name: 'inventorySell',
  8839. args: {
  8840. type: 'hero',
  8841. libId: i,
  8842. amount: fragmentHero[i],
  8843. fragment: true,
  8844. },
  8845. ident: 'inventorySell_' + i,
  8846. });
  8847. }
  8848. }
  8849. if (!calls.length) {
  8850. console.log(0);
  8851. return 0;
  8852. }
  8853. const rewards = await Send({ calls }).then((e) => e.results.map((r) => r.result?.response?.gold || 0));
  8854. const gold = rewards.reduce((e, a) => e + a, 0);
  8855. setProgress(I18N('GOLD_RECEIVED', { gold }), true);
  8856. }
  8857.  
  8858. /**
  8859. * Attack of the minions of Asgard
  8860. *
  8861. * Атака прислужников Асгарда
  8862. */
  8863. function testRaidNodes() {
  8864. return new Promise((resolve, reject) => {
  8865. const tower = new executeRaidNodes(resolve, reject);
  8866. tower.start();
  8867. });
  8868. }
  8869.  
  8870. /**
  8871. * Attack of the minions of Asgard
  8872. *
  8873. * Атака прислужников Асгарда
  8874. */
  8875. function executeRaidNodes(resolve, reject) {
  8876. let raidData = {
  8877. teams: [],
  8878. favor: {},
  8879. nodes: [],
  8880. attempts: 0,
  8881. countExecuteBattles: 0,
  8882. cancelBattle: 0,
  8883. }
  8884.  
  8885. callsExecuteRaidNodes = {
  8886. calls: [{
  8887. name: "clanRaid_getInfo",
  8888. args: {},
  8889. ident: "clanRaid_getInfo"
  8890. }, {
  8891. name: "teamGetAll",
  8892. args: {},
  8893. ident: "teamGetAll"
  8894. }, {
  8895. name: "teamGetFavor",
  8896. args: {},
  8897. ident: "teamGetFavor"
  8898. }]
  8899. }
  8900.  
  8901. this.start = function () {
  8902. send(JSON.stringify(callsExecuteRaidNodes), startRaidNodes);
  8903. }
  8904.  
  8905. async function startRaidNodes(data) {
  8906. res = data.results;
  8907. clanRaidInfo = res[0].result.response;
  8908. teamGetAll = res[1].result.response;
  8909. teamGetFavor = res[2].result.response;
  8910.  
  8911. let index = 0;
  8912. let isNotFullPack = false;
  8913. for (let team of teamGetAll.clanRaid_nodes) {
  8914. if (team.length < 6) {
  8915. isNotFullPack = true;
  8916. }
  8917. raidData.teams.push({
  8918. data: {},
  8919. heroes: team.filter(id => id < 6000),
  8920. pet: team.filter(id => id >= 6000).pop(),
  8921. battleIndex: index++
  8922. });
  8923. }
  8924. raidData.favor = teamGetFavor.clanRaid_nodes;
  8925.  
  8926. if (isNotFullPack) {
  8927. if (await popup.confirm(I18N('MINIONS_WARNING'), [
  8928. { msg: I18N('BTN_NO'), result: true },
  8929. { msg: I18N('BTN_YES'), result: false },
  8930. ])) {
  8931. endRaidNodes('isNotFullPack');
  8932. return;
  8933. }
  8934. }
  8935.  
  8936. raidData.nodes = clanRaidInfo.nodes;
  8937. raidData.attempts = clanRaidInfo.attempts;
  8938. isCancalBattle = false;
  8939.  
  8940. checkNodes();
  8941. }
  8942.  
  8943. function getAttackNode() {
  8944. for (let nodeId in raidData.nodes) {
  8945. let node = raidData.nodes[nodeId];
  8946. let points = 0
  8947. for (team of node.teams) {
  8948. points += team.points;
  8949. }
  8950. let now = Date.now() / 1000;
  8951. if (!points && now > node.timestamps.start && now < node.timestamps.end) {
  8952. let countTeam = node.teams.length;
  8953. delete raidData.nodes[nodeId];
  8954. return {
  8955. nodeId,
  8956. countTeam
  8957. };
  8958. }
  8959. }
  8960. return null;
  8961. }
  8962.  
  8963. function checkNodes() {
  8964. setProgress(`${I18N('REMAINING_ATTEMPTS')}: ${raidData.attempts}`);
  8965. let nodeInfo = getAttackNode();
  8966. if (nodeInfo && raidData.attempts) {
  8967. startNodeBattles(nodeInfo);
  8968. return;
  8969. }
  8970.  
  8971. endRaidNodes('EndRaidNodes');
  8972. }
  8973.  
  8974. function startNodeBattles(nodeInfo) {
  8975. let {nodeId, countTeam} = nodeInfo;
  8976. let teams = raidData.teams.slice(0, countTeam);
  8977. let heroes = raidData.teams.map(e => e.heroes).flat();
  8978. let favor = {...raidData.favor};
  8979. for (let heroId in favor) {
  8980. if (!heroes.includes(+heroId)) {
  8981. delete favor[heroId];
  8982. }
  8983. }
  8984.  
  8985. let calls = [{
  8986. name: "clanRaid_startNodeBattles",
  8987. args: {
  8988. nodeId,
  8989. teams,
  8990. favor
  8991. },
  8992. ident: "body"
  8993. }];
  8994.  
  8995. send(JSON.stringify({calls}), resultNodeBattles);
  8996. }
  8997.  
  8998. function resultNodeBattles(e) {
  8999. if (e['error']) {
  9000. endRaidNodes('nodeBattlesError', e['error']);
  9001. return;
  9002. }
  9003.  
  9004. console.log(e);
  9005. let battles = e.results[0].result.response.battles;
  9006. let promises = [];
  9007. let battleIndex = 0;
  9008. for (let battle of battles) {
  9009. battle.battleIndex = battleIndex++;
  9010. promises.push(calcBattleResult(battle));
  9011. }
  9012.  
  9013. Promise.all(promises)
  9014. .then(results => {
  9015. const endResults = {};
  9016. let isAllWin = true;
  9017. for (let r of results) {
  9018. isAllWin &&= r.result.win;
  9019. }
  9020. if (!isAllWin) {
  9021. cancelEndNodeBattle(results[0]);
  9022. return;
  9023. }
  9024. raidData.countExecuteBattles = results.length;
  9025. let timeout = 500;
  9026. for (let r of results) {
  9027. setTimeout(endNodeBattle, timeout, r);
  9028. timeout += 500;
  9029. }
  9030. });
  9031. }
  9032. /**
  9033. * Returns the battle calculation promise
  9034. *
  9035. * Возвращает промис расчета боя
  9036. */
  9037. function calcBattleResult(battleData) {
  9038. return new Promise(function (resolve, reject) {
  9039. BattleCalc(battleData, "get_clanPvp", resolve);
  9040. });
  9041. }
  9042. /**
  9043. * Cancels the fight
  9044. *
  9045. * Отменяет бой
  9046. */
  9047. function cancelEndNodeBattle(r) {
  9048. const fixBattle = function (heroes) {
  9049. for (const ids in heroes) {
  9050. hero = heroes[ids];
  9051. hero.energy = random(1, 999);
  9052. if (hero.hp > 0) {
  9053. hero.hp = random(1, hero.hp);
  9054. }
  9055. }
  9056. }
  9057. fixBattle(r.progress[0].attackers.heroes);
  9058. fixBattle(r.progress[0].defenders.heroes);
  9059. endNodeBattle(r);
  9060. }
  9061. /**
  9062. * Ends the fight
  9063. *
  9064. * Завершает бой
  9065. */
  9066. function endNodeBattle(r) {
  9067. let nodeId = r.battleData.result.nodeId;
  9068. let battleIndex = r.battleData.battleIndex;
  9069. let calls = [{
  9070. name: "clanRaid_endNodeBattle",
  9071. args: {
  9072. nodeId,
  9073. battleIndex,
  9074. result: r.result,
  9075. progress: r.progress
  9076. },
  9077. ident: "body"
  9078. }]
  9079.  
  9080. SendRequest(JSON.stringify({calls}), battleResult);
  9081. }
  9082. /**
  9083. * Processing the results of the battle
  9084. *
  9085. * Обработка результатов боя
  9086. */
  9087. function battleResult(e) {
  9088. if (e['error']) {
  9089. endRaidNodes('missionEndError', e['error']);
  9090. return;
  9091. }
  9092. r = e.results[0].result.response;
  9093. if (r['error']) {
  9094. if (r.reason == "invalidBattle") {
  9095. raidData.cancelBattle++;
  9096. checkNodes();
  9097. } else {
  9098. endRaidNodes('missionEndError', e['error']);
  9099. }
  9100. return;
  9101. }
  9102.  
  9103. if (!(--raidData.countExecuteBattles)) {
  9104. raidData.attempts--;
  9105. checkNodes();
  9106. }
  9107. }
  9108. /**
  9109. * Completing a task
  9110. *
  9111. * Завершение задачи
  9112. */
  9113. function endRaidNodes(reason, info) {
  9114. isCancalBattle = true;
  9115. let textCancel = raidData.cancelBattle ? ` ${I18N('BATTLES_CANCELED')}: ${raidData.cancelBattle}` : '';
  9116. setProgress(`${I18N('MINION_RAID')} ${I18N('COMPLETED')}! ${textCancel}`, true);
  9117. console.log(reason, info);
  9118. resolve();
  9119. }
  9120. }
  9121.  
  9122. /**
  9123. * Asgard Boss Attack Replay
  9124. *
  9125. * Повтор атаки босса Асгарда
  9126. */
  9127. function testBossBattle() {
  9128. return new Promise((resolve, reject) => {
  9129. const bossBattle = new executeBossBattle(resolve, reject);
  9130. bossBattle.start(lastBossBattle);
  9131. });
  9132. }
  9133.  
  9134. /**
  9135. * Asgard Boss Attack Replay
  9136. *
  9137. * Повтор атаки босса Асгарда
  9138. */
  9139. function executeBossBattle(resolve, reject) {
  9140.  
  9141. this.start = function (battleInfo) {
  9142. preCalcBattle(battleInfo);
  9143. }
  9144.  
  9145. function getBattleInfo(battle) {
  9146. return new Promise(function (resolve) {
  9147. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  9148. BattleCalc(battle, getBattleType(battle.type), e => {
  9149. let extra = e.progress[0].defenders.heroes[1].extra;
  9150. resolve(extra.damageTaken + extra.damageTakenNextLevel);
  9151. });
  9152. });
  9153. }
  9154.  
  9155. function preCalcBattle(battle) {
  9156. let actions = [];
  9157. const countTestBattle = getInput('countTestBattle');
  9158. for (let i = 0; i < countTestBattle; i++) {
  9159. actions.push(getBattleInfo(battle, true));
  9160. }
  9161. Promise.all(actions)
  9162. .then(resultPreCalcBattle);
  9163. }
  9164.  
  9165. async function resultPreCalcBattle(damages) {
  9166. let maxDamage = 0;
  9167. let minDamage = 1e10;
  9168. let avgDamage = 0;
  9169. for (let damage of damages) {
  9170. avgDamage += damage
  9171. if (damage > maxDamage) {
  9172. maxDamage = damage;
  9173. }
  9174. if (damage < minDamage) {
  9175. minDamage = damage;
  9176. }
  9177. }
  9178. avgDamage /= damages.length;
  9179. console.log(damages.map(e => e.toLocaleString()).join('\n'), avgDamage, maxDamage);
  9180.  
  9181. await popup.confirm(
  9182. `${I18N('ROUND_STAT')} ${damages.length} ${I18N('BATTLE')}:` +
  9183. `<br>${I18N('MINIMUM')}: ` + minDamage.toLocaleString() +
  9184. `<br>${I18N('MAXIMUM')}: ` + maxDamage.toLocaleString() +
  9185. `<br>${I18N('AVERAGE')}: ` + avgDamage.toLocaleString()
  9186. , [
  9187. { msg: I18N('BTN_OK'), result: 0},
  9188. ])
  9189. endBossBattle(I18N('BTN_CANCEL'));
  9190. }
  9191.  
  9192. /**
  9193. * Completing a task
  9194. *
  9195. * Завершение задачи
  9196. */
  9197. function endBossBattle(reason, info) {
  9198. console.log(reason, info);
  9199. resolve();
  9200. }
  9201. }
  9202.  
  9203. class FixBattle {
  9204. constructor(battle, isTimeout = true) {
  9205. this.battle = structuredClone(battle);
  9206. this.isTimeout = isTimeout;
  9207. }
  9208.  
  9209. timeout(callback, timeout) {
  9210. if (this.isTimeout) {
  9211. this.worker.postMessage(timeout);
  9212. this.worker.onmessage = callback;
  9213. } else {
  9214. callback();
  9215. }
  9216. }
  9217.  
  9218. randTimer() {
  9219. const min = 1.3;
  9220. const max = 15.3;
  9221. return Math.random() * (max - min + 1) + min;
  9222. }
  9223.  
  9224. setAvgTime(startTime) {
  9225. this.fixTime += Date.now() - startTime;
  9226. this.avgTime = this.fixTime / this.count;
  9227. }
  9228.  
  9229. init() {
  9230. this.fixTime = 0;
  9231. this.lastTimer = 0;
  9232. this.index = 0;
  9233. this.lastBossDamage = 0;
  9234. this.bestResult = {
  9235. count: 0,
  9236. timer: 0,
  9237. value: 0,
  9238. result: null,
  9239. progress: null,
  9240. };
  9241. this.lastBattleResult = {
  9242. win: false,
  9243. };
  9244. this.worker = new Worker(
  9245. URL.createObjectURL(
  9246. new Blob([
  9247. `self.onmessage = function(e) {
  9248. const timeout = e.data;
  9249. setTimeout(() => {
  9250. self.postMessage(1);
  9251. }, timeout);
  9252. };`,
  9253. ])
  9254. )
  9255. );
  9256. }
  9257.  
  9258. async start(endTime = Date.now() + 6e4, maxCount = 100) {
  9259. this.endTime = endTime;
  9260. this.maxCount = maxCount;
  9261. this.init();
  9262. return await new Promise((resolve) => {
  9263. this.resolve = resolve;
  9264. this.count = 0;
  9265. this.loop();
  9266. });
  9267. }
  9268.  
  9269. endFix() {
  9270. this.bestResult.maxCount = this.count;
  9271. this.worker.terminate();
  9272. this.resolve(this.bestResult);
  9273. }
  9274.  
  9275. async loop() {
  9276. const start = Date.now();
  9277. if (this.isEndLoop()) {
  9278. this.endFix();
  9279. return;
  9280. }
  9281. this.count++;
  9282. try {
  9283. this.lastResult = await Calc(this.battle);
  9284. } catch (e) {
  9285. this.updateProgressTimer(this.index++);
  9286. this.timeout(this.loop.bind(this), 0);
  9287. return;
  9288. }
  9289. const { progress, result } = this.lastResult;
  9290. this.lastBattleResult = result;
  9291. this.lastBattleProgress = progress;
  9292. this.setAvgTime(start);
  9293. this.checkResult();
  9294. this.showResult();
  9295. this.updateProgressTimer();
  9296. this.timeout(this.loop.bind(this), 0);
  9297. }
  9298.  
  9299. isEndLoop() {
  9300. return this.count >= this.maxCount || this.endTime < Date.now();
  9301. }
  9302.  
  9303. updateProgressTimer(index = 0) {
  9304. this.lastTimer = this.randTimer();
  9305. this.battle.progress = [{ attackers: { input: ['auto', 0, 0, 'auto', index, this.lastTimer] } }];
  9306. }
  9307.  
  9308. showResult() {
  9309. console.log(
  9310. this.count,
  9311. this.avgTime.toFixed(2),
  9312. (this.endTime - Date.now()) / 1000,
  9313. this.lastTimer.toFixed(2),
  9314. this.lastBossDamage.toLocaleString(),
  9315. this.bestResult.value.toLocaleString()
  9316. );
  9317. }
  9318.  
  9319. checkResult() {
  9320. const { damageTaken, damageTakenNextLevel } = this.lastBattleProgress[0].defenders.heroes[1].extra;
  9321. this.lastBossDamage = damageTaken + damageTakenNextLevel;
  9322. if (this.lastBossDamage > this.bestResult.value) {
  9323. this.bestResult = {
  9324. count: this.count,
  9325. timer: this.lastTimer,
  9326. value: this.lastBossDamage,
  9327. result: structuredClone(this.lastBattleResult),
  9328. progress: structuredClone(this.lastBattleProgress),
  9329. };
  9330. }
  9331. }
  9332.  
  9333. stopFix() {
  9334. this.endTime = 0;
  9335. }
  9336. }
  9337.  
  9338. class WinFixBattle extends FixBattle {
  9339. checkResult() {
  9340. if (this.lastBattleResult.win) {
  9341. this.bestResult = {
  9342. count: this.count,
  9343. timer: this.lastTimer,
  9344. value: this.lastBattleResult.stars,
  9345. result: structuredClone(this.lastBattleResult),
  9346. progress: structuredClone(this.lastBattleProgress),
  9347. battleTimer: this.lastResult.battleTimer,
  9348. };
  9349. }
  9350. }
  9351.  
  9352. randTimer() {
  9353. const min = 1.3;
  9354. const max = 30.3;
  9355. return Math.random() * (max - min + 1) + min;
  9356. }
  9357.  
  9358. isEndLoop() {
  9359. return super.isEndLoop() || this.bestResult.result?.win;
  9360. }
  9361.  
  9362. showResult() {
  9363. console.log(
  9364. this.count,
  9365. this.avgTime.toFixed(2),
  9366. (this.endTime - Date.now()) / 1000,
  9367. this.lastResult.battleTime,
  9368. this.lastTimer,
  9369. this.bestResult.value
  9370. );
  9371. const endTime = ((this.endTime - Date.now()) / 1000).toFixed(2);
  9372. const avgTime = this.avgTime.toFixed(2);
  9373. const msg = `${I18N('LETS_FIX')} ${this.count}/${this.maxCount}<br/>${endTime}s<br/>${avgTime}ms`;
  9374. setProgress(msg, false, this.stopFix.bind(this));
  9375. }
  9376. }
  9377.  
  9378. class BestOrWinFixBattle extends WinFixBattle {
  9379. isNoMakeWin = false;
  9380.  
  9381. getState(result) {
  9382. let beforeSumFactor = 0;
  9383. const beforeHeroes = result.battleData.defenders[0];
  9384. for (let heroId in beforeHeroes) {
  9385. const hero = beforeHeroes[heroId];
  9386. const state = hero.state;
  9387. let factor = 1;
  9388. if (state) {
  9389. const hp = state.hp / (hero?.hp || 1);
  9390. const energy = state.energy / 1e3;
  9391. factor = hp + energy / 20;
  9392. }
  9393. beforeSumFactor += factor;
  9394. }
  9395.  
  9396. let afterSumFactor = 0;
  9397. const afterHeroes = result.progress[0].defenders.heroes;
  9398. for (let heroId in afterHeroes) {
  9399. const hero = afterHeroes[heroId];
  9400. const hp = hero.hp / (beforeHeroes[heroId]?.hp || 1);
  9401. const energy = hero.energy / 1e3;
  9402. const factor = hp + energy / 20;
  9403. afterSumFactor += factor;
  9404. }
  9405. return 100 - Math.floor((afterSumFactor / beforeSumFactor) * 1e4) / 100;
  9406. }
  9407.  
  9408. setNoMakeWin(value) {
  9409. this.isNoMakeWin = value;
  9410. }
  9411.  
  9412. checkResult() {
  9413. const state = this.getState(this.lastResult);
  9414. console.log(state);
  9415.  
  9416. if (state > this.bestResult.value) {
  9417. if (!(this.isNoMakeWin && this.lastBattleResult.win)) {
  9418. this.bestResult = {
  9419. count: this.count,
  9420. timer: this.lastTimer,
  9421. value: state,
  9422. result: structuredClone(this.lastBattleResult),
  9423. progress: structuredClone(this.lastBattleProgress),
  9424. battleTimer: this.lastResult.battleTimer,
  9425. };
  9426. }
  9427. }
  9428. }
  9429. }
  9430.  
  9431. class BossFixBattle extends FixBattle {
  9432. showResult() {
  9433. super.showResult();
  9434. //setTimeout(() => {
  9435. const best = this.bestResult;
  9436. const maxDmg = best.value.toLocaleString();
  9437. const avgTime = this.avgTime.toLocaleString();
  9438. const msg = `${I18N('LETS_FIX')} ${this.count}/${this.maxCount}<br/>${maxDmg}<br/>${avgTime}ms`;
  9439. setProgress(msg, false, this.stopFix.bind(this));
  9440. //}, 0);
  9441. }
  9442. }
  9443.  
  9444. class DungeonFixBattle extends FixBattle {
  9445. init() {
  9446. super.init();
  9447. this.isTimeout = false;
  9448. }
  9449.  
  9450. setState() {
  9451. const result = this.lastResult;
  9452. let beforeSumFactor = 0;
  9453. const beforeHeroes = result.battleData.attackers;
  9454. for (let heroId in beforeHeroes) {
  9455. const hero = beforeHeroes[heroId];
  9456. const state = hero.state;
  9457. let factor = 1;
  9458. if (state) {
  9459. const hp = state.hp / (hero?.hp || 1);
  9460. const energy = state.energy / 1e3;
  9461. factor = hp + energy / 20;
  9462. }
  9463. beforeSumFactor += factor;
  9464. }
  9465.  
  9466. let afterSumFactor = 0;
  9467. const afterHeroes = result.progress[0].attackers.heroes;
  9468. for (let heroId in afterHeroes) {
  9469. const hero = afterHeroes[heroId];
  9470. const hp = hero.hp / (beforeHeroes[heroId]?.hp || 1);
  9471. const energy = hero.energy / 1e3;
  9472. const factor = hp + energy / 20;
  9473. afterSumFactor += factor;
  9474. }
  9475. this.lastState = Math.floor((afterSumFactor / beforeSumFactor) * 1e4) / 100;
  9476. }
  9477.  
  9478. checkResult() {
  9479. this.setState();
  9480. if (this.lastResult.result.win && this.lastState > this.bestResult.value) {
  9481. this.bestResult = {
  9482. count: this.count,
  9483. timer: this.lastTimer,
  9484. value: this.lastState,
  9485. result: this.lastResult.result,
  9486. progress: this.lastResult.progress,
  9487. };
  9488. }
  9489. }
  9490.  
  9491. showResult() {
  9492. console.log(
  9493. this.count,
  9494. this.avgTime.toFixed(2),
  9495. (this.endTime - Date.now()) / 1000,
  9496. this.lastTimer.toFixed(2),
  9497. this.lastState.toLocaleString(),
  9498. this.bestResult.value.toLocaleString()
  9499. );
  9500. }
  9501. }
  9502.  
  9503. const masterWsMixin = {
  9504. wsStart() {
  9505. const socket = new WebSocket(this.url);
  9506.  
  9507. socket.onopen = () => {
  9508. console.log('Connected to server');
  9509.  
  9510. // Пример создания новой задачи
  9511. const newTask = {
  9512. type: 'newTask',
  9513. battle: this.battle,
  9514. endTime: this.endTime - 1e4,
  9515. maxCount: this.maxCount,
  9516. };
  9517. socket.send(JSON.stringify(newTask));
  9518. };
  9519.  
  9520. socket.onmessage = this.onmessage.bind(this);
  9521.  
  9522. socket.onclose = () => {
  9523. console.log('Disconnected from server');
  9524. };
  9525.  
  9526. this.ws = socket;
  9527. },
  9528.  
  9529. onmessage(event) {
  9530. const data = JSON.parse(event.data);
  9531. switch (data.type) {
  9532. case 'newTask': {
  9533. console.log('newTask:', data);
  9534. this.id = data.id;
  9535. this.countExecutor = data.count;
  9536. break;
  9537. }
  9538. case 'getSolTask': {
  9539. console.log('getSolTask:', data);
  9540. this.endFix(data.solutions);
  9541. break;
  9542. }
  9543. case 'resolveTask': {
  9544. console.log('resolveTask:', data);
  9545. if (data.id === this.id && data.solutions.length === this.countExecutor) {
  9546. this.worker.terminate();
  9547. this.endFix(data.solutions);
  9548. }
  9549. break;
  9550. }
  9551. default:
  9552. console.log('Unknown message type:', data.type);
  9553. }
  9554. },
  9555.  
  9556. getTask() {
  9557. this.ws.send(
  9558. JSON.stringify({
  9559. type: 'getSolTask',
  9560. id: this.id,
  9561. })
  9562. );
  9563. },
  9564. };
  9565.  
  9566. /*
  9567. mFix = new action.masterFixBattle(battle)
  9568. await mFix.start(Date.now() + 6e4, 1);
  9569. */
  9570. class masterFixBattle extends FixBattle {
  9571. constructor(battle, url = 'wss://localho.st:3000') {
  9572. super(battle, true);
  9573. this.url = url;
  9574. }
  9575.  
  9576. async start(endTime, maxCount) {
  9577. this.endTime = endTime;
  9578. this.maxCount = maxCount;
  9579. this.init();
  9580. this.wsStart();
  9581. return await new Promise((resolve) => {
  9582. this.resolve = resolve;
  9583. const timeout = this.endTime - Date.now();
  9584. this.timeout(this.getTask.bind(this), timeout);
  9585. });
  9586. }
  9587.  
  9588. async endFix(solutions) {
  9589. this.ws.close();
  9590. let maxCount = 0;
  9591. for (const solution of solutions) {
  9592. maxCount += solution.maxCount;
  9593. if (solution.value > this.bestResult.value) {
  9594. this.bestResult = solution;
  9595. }
  9596. }
  9597. this.count = maxCount;
  9598. super.endFix();
  9599. }
  9600. }
  9601.  
  9602. Object.assign(masterFixBattle.prototype, masterWsMixin);
  9603.  
  9604. class masterWinFixBattle extends WinFixBattle {
  9605. constructor(battle, url = 'wss://localho.st:3000') {
  9606. super(battle, true);
  9607. this.url = url;
  9608. }
  9609.  
  9610. async start(endTime, maxCount) {
  9611. this.endTime = endTime;
  9612. this.maxCount = maxCount;
  9613. this.init();
  9614. this.wsStart();
  9615. return await new Promise((resolve) => {
  9616. this.resolve = resolve;
  9617. const timeout = this.endTime - Date.now();
  9618. this.timeout(this.getTask.bind(this), timeout);
  9619. });
  9620. }
  9621.  
  9622. async endFix(solutions) {
  9623. this.ws.close();
  9624. let maxCount = 0;
  9625. for (const solution of solutions) {
  9626. maxCount += solution.maxCount;
  9627. if (solution.value > this.bestResult.value) {
  9628. this.bestResult = solution;
  9629. }
  9630. }
  9631. this.count = maxCount;
  9632. super.endFix();
  9633. }
  9634. }
  9635.  
  9636. Object.assign(masterWinFixBattle.prototype, masterWsMixin);
  9637.  
  9638. const slaveWsMixin = {
  9639. wsStop() {
  9640. this.ws.close();
  9641. },
  9642.  
  9643. wsStart() {
  9644. const socket = new WebSocket(this.url);
  9645.  
  9646. socket.onopen = () => {
  9647. console.log('Connected to server');
  9648. };
  9649. socket.onmessage = this.onmessage.bind(this);
  9650. socket.onclose = () => {
  9651. console.log('Disconnected from server');
  9652. };
  9653.  
  9654. this.ws = socket;
  9655. },
  9656.  
  9657. async onmessage(event) {
  9658. const data = JSON.parse(event.data);
  9659. switch (data.type) {
  9660. case 'newTask': {
  9661. console.log('newTask:', data.task);
  9662. const { battle, endTime, maxCount } = data.task;
  9663. this.battle = battle;
  9664. const id = data.task.id;
  9665. const solution = await this.start(endTime, maxCount);
  9666. this.ws.send(
  9667. JSON.stringify({
  9668. type: 'resolveTask',
  9669. id,
  9670. solution,
  9671. })
  9672. );
  9673. break;
  9674. }
  9675. default:
  9676. console.log('Unknown message type:', data.type);
  9677. }
  9678. },
  9679. };
  9680. /*
  9681. sFix = new action.slaveFixBattle();
  9682. sFix.wsStart()
  9683. */
  9684. class slaveFixBattle extends FixBattle {
  9685. constructor(url = 'wss://localho.st:3000') {
  9686. super(null, false);
  9687. this.isTimeout = false;
  9688. this.url = url;
  9689. }
  9690. }
  9691.  
  9692. Object.assign(slaveFixBattle.prototype, slaveWsMixin);
  9693.  
  9694. class slaveWinFixBattle extends WinFixBattle {
  9695. constructor(url = 'wss://localho.st:3000') {
  9696. super(null, false);
  9697. this.isTimeout = false;
  9698. this.url = url;
  9699. }
  9700. }
  9701.  
  9702. Object.assign(slaveWinFixBattle.prototype, slaveWsMixin);
  9703. /**
  9704. * Auto-repeat attack
  9705. *
  9706. * Автоповтор атаки
  9707. */
  9708. function testAutoBattle() {
  9709. return new Promise((resolve, reject) => {
  9710. const bossBattle = new executeAutoBattle(resolve, reject);
  9711. bossBattle.start(lastBattleArg, lastBattleInfo);
  9712. });
  9713. }
  9714.  
  9715. /**
  9716. * Auto-repeat attack
  9717. *
  9718. * Автоповтор атаки
  9719. */
  9720. function executeAutoBattle(resolve, reject) {
  9721. let battleArg = {};
  9722. let countBattle = 0;
  9723. let countError = 0;
  9724. let findCoeff = 0;
  9725. let dataNotEeceived = 0;
  9726. let stopAutoBattle = false;
  9727. 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>';
  9728. 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>';
  9729. 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>';
  9730.  
  9731. this.start = function (battleArgs, battleInfo) {
  9732. battleArg = battleArgs;
  9733. preCalcBattle(battleInfo);
  9734. }
  9735. /**
  9736. * Returns a promise for combat recalculation
  9737. *
  9738. * Возвращает промис для прерасчета боя
  9739. */
  9740. function getBattleInfo(battle) {
  9741. return new Promise(function (resolve) {
  9742. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  9743. Calc(battle).then(e => {
  9744. e.coeff = calcCoeff(e, 'defenders');
  9745. resolve(e);
  9746. });
  9747. });
  9748. }
  9749. /**
  9750. * Battle recalculation
  9751. *
  9752. * Прерасчет боя
  9753. */
  9754. function preCalcBattle(battle) {
  9755. let actions = [];
  9756. const countTestBattle = getInput('countTestBattle');
  9757. for (let i = 0; i < countTestBattle; i++) {
  9758. actions.push(getBattleInfo(battle));
  9759. }
  9760. Promise.all(actions)
  9761. .then(resultPreCalcBattle);
  9762. }
  9763. /**
  9764. * Processing the results of the battle recalculation
  9765. *
  9766. * Обработка результатов прерасчета боя
  9767. */
  9768. async function resultPreCalcBattle(results) {
  9769. let countWin = results.reduce((s, w) => w.result.win + s, 0);
  9770. setProgress(`${I18N('CHANCE_TO_WIN')} ${Math.floor(countWin / results.length * 100)}% (${results.length})`, false, hideProgress);
  9771. if (countWin > 0) {
  9772. isCancalBattle = false;
  9773. startBattle();
  9774. return;
  9775. }
  9776.  
  9777. let minCoeff = 100;
  9778. let maxCoeff = -100;
  9779. let avgCoeff = 0;
  9780. results.forEach(e => {
  9781. if (e.coeff < minCoeff) minCoeff = e.coeff;
  9782. if (e.coeff > maxCoeff) maxCoeff = e.coeff;
  9783. avgCoeff += e.coeff;
  9784. });
  9785. avgCoeff /= results.length;
  9786.  
  9787. if (nameFuncStartBattle == 'invasion_bossStart' ||
  9788. nameFuncStartBattle == 'bossAttack') {
  9789. const result = await popup.confirm(
  9790. I18N('BOSS_VICTORY_IMPOSSIBLE', { battles: results.length }), [
  9791. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  9792. { msg: I18N('BTN_DO_IT'), result: true },
  9793. ])
  9794. if (result) {
  9795. isCancalBattle = false;
  9796. startBattle();
  9797. return;
  9798. }
  9799. setProgress(I18N('NOT_THIS_TIME'), true);
  9800. endAutoBattle('invasion_bossStart');
  9801. return;
  9802. }
  9803.  
  9804. const result = await popup.confirm(
  9805. I18N('VICTORY_IMPOSSIBLE') +
  9806. `<br>${I18N('ROUND_STAT')} ${results.length} ${I18N('BATTLE')}:` +
  9807. `<br>${I18N('MINIMUM')}: ` + minCoeff.toLocaleString() +
  9808. `<br>${I18N('MAXIMUM')}: ` + maxCoeff.toLocaleString() +
  9809. `<br>${I18N('AVERAGE')}: ` + avgCoeff.toLocaleString() +
  9810. `<br>${I18N('FIND_COEFF')} ` + avgCoeff.toLocaleString(), [
  9811. { msg: I18N('BTN_CANCEL'), result: 0, isCancel: true },
  9812. { msg: I18N('BTN_GO'), isInput: true, default: Math.round(avgCoeff * 1000) / 1000 },
  9813. ])
  9814. if (result) {
  9815. findCoeff = result;
  9816. isCancalBattle = false;
  9817. startBattle();
  9818. return;
  9819. }
  9820. setProgress(I18N('NOT_THIS_TIME'), true);
  9821. endAutoBattle(I18N('NOT_THIS_TIME'));
  9822. }
  9823.  
  9824. /**
  9825. * Calculation of the combat result coefficient
  9826. *
  9827. * Расчет коэфициента результата боя
  9828. */
  9829. function calcCoeff(result, packType) {
  9830. let beforeSumFactor = 0;
  9831. const beforePack = result.battleData[packType][0];
  9832. for (let heroId in beforePack) {
  9833. const hero = beforePack[heroId];
  9834. const state = hero.state;
  9835. let factor = 1;
  9836. if (state) {
  9837. const hp = state.hp / state.maxHp;
  9838. const energy = state.energy / 1e3;
  9839. factor = hp + energy / 20;
  9840. }
  9841. beforeSumFactor += factor;
  9842. }
  9843.  
  9844. let afterSumFactor = 0;
  9845. const afterPack = result.progress[0][packType].heroes;
  9846. for (let heroId in afterPack) {
  9847. const hero = afterPack[heroId];
  9848. const stateHp = beforePack[heroId]?.state?.hp || beforePack[heroId]?.stats?.hp;
  9849. const hp = hero.hp / stateHp;
  9850. const energy = hero.energy / 1e3;
  9851. const factor = hp + energy / 20;
  9852. afterSumFactor += factor;
  9853. }
  9854. const resultCoeff = -(afterSumFactor - beforeSumFactor);
  9855. return Math.round(resultCoeff * 1000) / 1000;
  9856. }
  9857. /**
  9858. * Start battle
  9859. *
  9860. * Начало боя
  9861. */
  9862. function startBattle() {
  9863. countBattle++;
  9864. const countMaxBattle = getInput('countAutoBattle');
  9865. // setProgress(countBattle + '/' + countMaxBattle);
  9866. if (countBattle > countMaxBattle) {
  9867. setProgress(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`, true);
  9868. endAutoBattle(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`)
  9869. return;
  9870. }
  9871. if (stopAutoBattle) {
  9872. setProgress(I18N('STOPPED'), true);
  9873. endAutoBattle('STOPPED');
  9874. return;
  9875. }
  9876. send({calls: [{
  9877. name: nameFuncStartBattle,
  9878. args: battleArg,
  9879. ident: "body"
  9880. }]}, calcResultBattle);
  9881. }
  9882. /**
  9883. * Battle calculation
  9884. *
  9885. * Расчет боя
  9886. */
  9887. async function calcResultBattle(e) {
  9888. if (!e) {
  9889. console.log('данные не были получены');
  9890. if (dataNotEeceived < 10) {
  9891. dataNotEeceived++;
  9892. startBattle();
  9893. return;
  9894. }
  9895. endAutoBattle('Error', 'данные не были получены ' + dataNotEeceived + ' раз');
  9896. return;
  9897. }
  9898. if ('error' in e) {
  9899. if (e.error.description === 'too many tries') {
  9900. invasionTimer += 100;
  9901. countBattle--;
  9902. countError++;
  9903. console.log(`Errors: ${countError}`, e.error);
  9904. startBattle();
  9905. return;
  9906. }
  9907. const result = await popup.confirm(I18N('ERROR_DURING_THE_BATTLE') + '<br>' + e.error.description, [
  9908. { msg: I18N('BTN_OK'), result: false },
  9909. { msg: I18N('RELOAD_GAME'), result: true },
  9910. ]);
  9911. endAutoBattle('Error', e.error);
  9912. if (result) {
  9913. location.reload();
  9914. }
  9915. return;
  9916. }
  9917. let battle = e.results[0].result.response.battle
  9918. if (nameFuncStartBattle == 'towerStartBattle' ||
  9919. nameFuncStartBattle == 'bossAttack' ||
  9920. nameFuncStartBattle == 'invasion_bossStart') {
  9921. battle = e.results[0].result.response;
  9922. }
  9923. lastBattleInfo = battle;
  9924. BattleCalc(battle, getBattleType(battle.type), resultBattle);
  9925. }
  9926. /**
  9927. * Processing the results of the battle
  9928. *
  9929. * Обработка результатов боя
  9930. */
  9931. async function resultBattle(e) {
  9932. const isWin = e.result.win;
  9933. if (isWin) {
  9934. endBattle(e, false);
  9935. return;
  9936. } else if (isChecked('tryFixIt')) {
  9937. const cloneBattle = structuredClone(e.battleData);
  9938. const bFix = new WinFixBattle(cloneBattle);
  9939. const endTime = Date.now() + 6e4;
  9940. const result = await bFix.start(endTime, Infinity);
  9941. console.log(result);
  9942. if (result.value) {
  9943. endBattle(result, false);
  9944. return;
  9945. }
  9946. }
  9947. const countMaxBattle = getInput('countAutoBattle');
  9948. if (findCoeff) {
  9949. const coeff = calcCoeff(e, 'defenders');
  9950. setProgress(`${countBattle}/${countMaxBattle}, ${coeff}`);
  9951. if (coeff > findCoeff) {
  9952. endBattle(e, false);
  9953. return;
  9954. }
  9955. } else {
  9956. if (nameFuncStartBattle == 'invasion_bossStart') {
  9957. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  9958. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageMod_any_99_100_300_99_1000 || 0;
  9959. setProgress(`${svgBoss} ${bossLvl} ${svgJustice} ${justice} <br>${svgAttempt} ${countBattle}/${countMaxBattle}`, false, () => {
  9960. stopAutoBattle = true;
  9961. });
  9962. await new Promise((resolve) => setTimeout(resolve, 5000));
  9963. } else {
  9964. setProgress(`${countBattle}/${countMaxBattle}`);
  9965. }
  9966. }
  9967. if (nameFuncStartBattle == 'towerStartBattle' ||
  9968. nameFuncStartBattle == 'bossAttack' ||
  9969. nameFuncStartBattle == 'invasion_bossStart') {
  9970. startBattle();
  9971. return;
  9972. }
  9973. cancelEndBattle(e);
  9974. }
  9975. /**
  9976. * Cancel fight
  9977. *
  9978. * Отмена боя
  9979. */
  9980. function cancelEndBattle(r) {
  9981. const fixBattle = function (heroes) {
  9982. for (const ids in heroes) {
  9983. hero = heroes[ids];
  9984. hero.energy = random(1, 999);
  9985. if (hero.hp > 0) {
  9986. hero.hp = random(1, hero.hp);
  9987. }
  9988. }
  9989. }
  9990. fixBattle(r.progress[0].attackers.heroes);
  9991. fixBattle(r.progress[0].defenders.heroes);
  9992. endBattle(r, true);
  9993. }
  9994. /**
  9995. * End of the fight
  9996. *
  9997. * Завершение боя */
  9998. function endBattle(battleResult, isCancal) {
  9999. let calls = [{
  10000. name: nameFuncEndBattle,
  10001. args: {
  10002. result: battleResult.result,
  10003. progress: battleResult.progress
  10004. },
  10005. ident: "body"
  10006. }];
  10007.  
  10008. if (nameFuncStartBattle == 'invasion_bossStart') {
  10009. calls[0].args.id = lastBattleArg.id;
  10010. }
  10011.  
  10012. send(JSON.stringify({
  10013. calls
  10014. }), async e => {
  10015. console.log(e);
  10016. if (isCancal) {
  10017. startBattle();
  10018. return;
  10019. }
  10020.  
  10021. setProgress(`${I18N('SUCCESS')}!`, 5000)
  10022. if (nameFuncStartBattle == 'invasion_bossStart' ||
  10023. nameFuncStartBattle == 'bossAttack') {
  10024. const countMaxBattle = getInput('countAutoBattle');
  10025. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  10026. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageMod_any_99_100_300_99_1000 || 0;
  10027. const result = await popup.confirm(
  10028. I18N('BOSS_HAS_BEEN_DEF_TEXT', {
  10029. bossLvl: `${svgBoss} ${bossLvl} ${svgJustice} ${justice}`,
  10030. countBattle: svgAttempt + ' ' + countBattle,
  10031. countMaxBattle,
  10032. }),
  10033. [
  10034. { msg: I18N('BTN_OK'), result: 0 },
  10035. { msg: I18N('MAKE_A_SYNC'), result: 1 },
  10036. { msg: I18N('RELOAD_GAME'), result: 2 },
  10037. ]
  10038. );
  10039. if (result) {
  10040. if (result == 1) {
  10041. cheats.refreshGame();
  10042. }
  10043. if (result == 2) {
  10044. location.reload();
  10045. }
  10046. }
  10047.  
  10048. }
  10049. endAutoBattle(`${I18N('SUCCESS')}!`)
  10050. });
  10051. }
  10052. /**
  10053. * Completing a task
  10054. *
  10055. * Завершение задачи
  10056. */
  10057. function endAutoBattle(reason, info) {
  10058. isCancalBattle = true;
  10059. console.log(reason, info);
  10060. resolve();
  10061. }
  10062. }
  10063.  
  10064. function testDailyQuests() {
  10065. return new Promise((resolve, reject) => {
  10066. const quests = new dailyQuests(resolve, reject);
  10067. quests.init(questsInfo);
  10068. quests.start();
  10069. });
  10070. }
  10071.  
  10072. /**
  10073. * Automatic completion of daily quests
  10074. *
  10075. * Автоматическое выполнение ежедневных квестов
  10076. */
  10077. class dailyQuests {
  10078. /**
  10079. * Send(' {"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}').then(e => console.log(e))
  10080. * Send(' {"calls":[{"name":"heroGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10081. * Send(' {"calls":[{"name":"titanGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10082. * Send(' {"calls":[{"name":"inventoryGet","args":{},"ident":"body"}]}').then(e => console.log(e))
  10083. * Send(' {"calls":[{"name":"questGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10084. * Send(' {"calls":[{"name":"bossGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10085. */
  10086. callsList = ['userGetInfo', 'heroGetAll', 'titanGetAll', 'inventoryGet', 'questGetAll', 'bossGetAll', 'missionGetAll'];
  10087.  
  10088. dataQuests = {
  10089. 10001: {
  10090. description: 'Улучши умения героев 3 раза', // ++++++++++++++++
  10091. doItCall: () => {
  10092. const upgradeSkills = this.getUpgradeSkills();
  10093. return upgradeSkills.map(({ heroId, skill }, index) => ({
  10094. name: 'heroUpgradeSkill',
  10095. args: { heroId, skill },
  10096. ident: `heroUpgradeSkill_${index}`,
  10097. }));
  10098. },
  10099. isWeCanDo: () => {
  10100. const upgradeSkills = this.getUpgradeSkills();
  10101. let sumGold = 0;
  10102. for (const skill of upgradeSkills) {
  10103. sumGold += this.skillCost(skill.value);
  10104. if (!skill.heroId) {
  10105. return false;
  10106. }
  10107. }
  10108. return this.questInfo['userGetInfo'].gold > sumGold;
  10109. },
  10110. },
  10111. 10002: {
  10112. description: 'Пройди 10 миссий', // --------------
  10113. isWeCanDo: () => false,
  10114. },
  10115. 10003: {
  10116. description: 'Пройди 3 героические миссии', // ++++++++++++++++
  10117. isWeCanDo: () => {
  10118. const vipPoints = +this.questInfo.userGetInfo.vipPoints;
  10119. const goldTicket = !!this.questInfo.inventoryGet.consumable[151];
  10120. return (vipPoints > 100 || goldTicket) && this.getHeroicMissionId();
  10121. },
  10122. doItCall: () => {
  10123. const selectedMissionId = this.getHeroicMissionId();
  10124. const goldTicket = !!this.questInfo.inventoryGet.consumable[151];
  10125. const vipPoints = +this.questInfo.userGetInfo.vipPoints;
  10126. // Возвращаем массив команд для рейда
  10127. if (vipPoints > 500 || goldTicket) {
  10128. return [{ name: 'missionRaid', args: { id: selectedMissionId, times: 3 }, ident: 'missionRaid_1' }];
  10129. } else {
  10130. return [
  10131. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_1' },
  10132. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_2' },
  10133. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_3' },
  10134. ];
  10135. }
  10136. },
  10137. },
  10138. 10004: {
  10139. description: 'Сразись 3 раза на Арене или Гранд Арене', // --------------
  10140. isWeCanDo: () => false,
  10141. },
  10142. 10006: {
  10143. description: 'Используй обмен изумрудов 1 раз', // ++++++++++++++++
  10144. doItCall: () => [
  10145. {
  10146. name: 'refillableAlchemyUse',
  10147. args: { multi: false },
  10148. ident: 'refillableAlchemyUse',
  10149. },
  10150. ],
  10151. isWeCanDo: () => {
  10152. const starMoney = this.questInfo['userGetInfo'].starMoney;
  10153. return starMoney >= 20;
  10154. },
  10155. },
  10156. 10007: {
  10157. description: 'Соверши 1 призыв в Атриуме Душ', // ++++++++++++++++
  10158. doItCall: () => [{ name: 'gacha_open', args: { ident: 'heroGacha', free: true, pack: false }, ident: 'gacha_open' }],
  10159. isWeCanDo: () => {
  10160. const soulCrystal = this.questInfo['inventoryGet'].coin[38];
  10161. return soulCrystal > 0;
  10162. },
  10163. },
  10164. 10016: {
  10165. description: 'Отправь подарки согильдийцам', // ++++++++++++++++
  10166. doItCall: () => [{ name: 'clanSendDailyGifts', args: {}, ident: 'clanSendDailyGifts' }],
  10167. isWeCanDo: () => true,
  10168. },
  10169. 10018: {
  10170. description: 'Используй зелье опыта', // ++++++++++++++++
  10171. doItCall: () => {
  10172. const expHero = this.getExpHero();
  10173. return [
  10174. {
  10175. name: 'consumableUseHeroXp',
  10176. args: {
  10177. heroId: expHero.heroId,
  10178. libId: expHero.libId,
  10179. amount: 1,
  10180. },
  10181. ident: 'consumableUseHeroXp',
  10182. },
  10183. ];
  10184. },
  10185. isWeCanDo: () => {
  10186. const expHero = this.getExpHero();
  10187. return expHero.heroId && expHero.libId;
  10188. },
  10189. },
  10190. 10019: {
  10191. description: 'Открой 1 сундук в Башне',
  10192. doItFunc: testTower,
  10193. isWeCanDo: () => false,
  10194. },
  10195. 10020: {
  10196. description: 'Открой 3 сундука в Запределье', // Готово
  10197. doItCall: () => {
  10198. return this.getOutlandChest();
  10199. },
  10200. isWeCanDo: () => {
  10201. const outlandChest = this.getOutlandChest();
  10202. return outlandChest.length > 0;
  10203. },
  10204. },
  10205. 10021: {
  10206. description: 'Собери 75 Титанита в Подземелье Гильдии',
  10207. isWeCanDo: () => false,
  10208. },
  10209. 10022: {
  10210. description: 'Собери 150 Титанита в Подземелье Гильдии',
  10211. doItFunc: testDungeon,
  10212. isWeCanDo: () => false,
  10213. },
  10214. 10023: {
  10215. description: 'Прокачай Дар Стихий на 1 уровень', // Готово
  10216. doItCall: () => {
  10217. const heroId = this.getHeroIdTitanGift();
  10218. return [
  10219. { name: 'heroTitanGiftLevelUp', args: { heroId }, ident: 'heroTitanGiftLevelUp' },
  10220. { name: 'heroTitanGiftDrop', args: { heroId }, ident: 'heroTitanGiftDrop' },
  10221. ];
  10222. },
  10223. isWeCanDo: () => {
  10224. const heroId = this.getHeroIdTitanGift();
  10225. return heroId;
  10226. },
  10227. },
  10228. 10024: {
  10229. description: 'Повысь уровень любого артефакта один раз', // Готово
  10230. doItCall: () => {
  10231. const upArtifact = this.getUpgradeArtifact();
  10232. return [
  10233. {
  10234. name: 'heroArtifactLevelUp',
  10235. args: {
  10236. heroId: upArtifact.heroId,
  10237. slotId: upArtifact.slotId,
  10238. },
  10239. ident: `heroArtifactLevelUp`,
  10240. },
  10241. ];
  10242. },
  10243. isWeCanDo: () => {
  10244. const upgradeArtifact = this.getUpgradeArtifact();
  10245. return upgradeArtifact.heroId;
  10246. },
  10247. },
  10248. 10025: {
  10249. description: 'Начни 1 Экспедицию',
  10250. doItFunc: checkExpedition,
  10251. isWeCanDo: () => false,
  10252. },
  10253. 10026: {
  10254. description: 'Начни 4 Экспедиции', // --------------
  10255. doItFunc: checkExpedition,
  10256. isWeCanDo: () => false,
  10257. },
  10258. 10027: {
  10259. description: 'Победи в 1 бою Турнира Стихий',
  10260. doItFunc: testTitanArena,
  10261. isWeCanDo: () => false,
  10262. },
  10263. 10028: {
  10264. description: 'Повысь уровень любого артефакта титанов', // Готово
  10265. doItCall: () => {
  10266. const upTitanArtifact = this.getUpgradeTitanArtifact();
  10267. return [
  10268. {
  10269. name: 'titanArtifactLevelUp',
  10270. args: {
  10271. titanId: upTitanArtifact.titanId,
  10272. slotId: upTitanArtifact.slotId,
  10273. },
  10274. ident: `titanArtifactLevelUp`,
  10275. },
  10276. ];
  10277. },
  10278. isWeCanDo: () => {
  10279. const upgradeTitanArtifact = this.getUpgradeTitanArtifact();
  10280. return upgradeTitanArtifact.titanId;
  10281. },
  10282. },
  10283. 10029: {
  10284. description: 'Открой сферу артефактов титанов', // ++++++++++++++++
  10285. doItCall: () => [{ name: 'titanArtifactChestOpen', args: { amount: 1, free: true }, ident: 'titanArtifactChestOpen' }],
  10286. isWeCanDo: () => {
  10287. return this.questInfo['inventoryGet']?.consumable[55] > 0;
  10288. },
  10289. },
  10290. 10030: {
  10291. description: 'Улучши облик любого героя 1 раз', // Готово
  10292. doItCall: () => {
  10293. const upSkin = this.getUpgradeSkin();
  10294. return [
  10295. {
  10296. name: 'heroSkinUpgrade',
  10297. args: {
  10298. heroId: upSkin.heroId,
  10299. skinId: upSkin.skinId,
  10300. },
  10301. ident: `heroSkinUpgrade`,
  10302. },
  10303. ];
  10304. },
  10305. isWeCanDo: () => {
  10306. const upgradeSkin = this.getUpgradeSkin();
  10307. return upgradeSkin.heroId;
  10308. },
  10309. },
  10310. 10031: {
  10311. description: 'Победи в 6 боях Турнира Стихий', // --------------
  10312. doItFunc: testTitanArena,
  10313. isWeCanDo: () => false,
  10314. },
  10315. 10043: {
  10316. description: 'Начни или присоеденись к Приключению', // --------------
  10317. isWeCanDo: () => false,
  10318. },
  10319. 10044: {
  10320. description: 'Воспользуйся призывом питомцев 1 раз', // ++++++++++++++++
  10321. doItCall: () => [{ name: 'pet_chestOpen', args: { amount: 1, paid: false }, ident: 'pet_chestOpen' }],
  10322. isWeCanDo: () => {
  10323. return this.questInfo['inventoryGet']?.consumable[90] > 0;
  10324. },
  10325. },
  10326. 10046: {
  10327. /**
  10328. * TODO: Watch Adventure
  10329. * TODO: Смотреть приключение
  10330. */
  10331. description: 'Открой 3 сундука в Приключениях',
  10332. isWeCanDo: () => false,
  10333. },
  10334. 10047: {
  10335. description: 'Набери 150 очков активности в Гильдии', // Готово
  10336. doItCall: () => {
  10337. const enchantRune = this.getEnchantRune();
  10338. return [
  10339. {
  10340. name: 'heroEnchantRune',
  10341. args: {
  10342. heroId: enchantRune.heroId,
  10343. tier: enchantRune.tier,
  10344. items: {
  10345. consumable: { [enchantRune.itemId]: 1 },
  10346. },
  10347. },
  10348. ident: `heroEnchantRune`,
  10349. },
  10350. ];
  10351. },
  10352. isWeCanDo: () => {
  10353. const userInfo = this.questInfo['userGetInfo'];
  10354. const enchantRune = this.getEnchantRune();
  10355. return enchantRune.heroId && userInfo.gold > 1e3;
  10356. },
  10357. },
  10358. };
  10359.  
  10360. constructor(resolve, reject, questInfo) {
  10361. this.resolve = resolve;
  10362. this.reject = reject;
  10363. }
  10364.  
  10365. init(questInfo) {
  10366. this.questInfo = questInfo;
  10367. this.isAuto = false;
  10368. }
  10369.  
  10370. async autoInit(isAuto) {
  10371. this.isAuto = isAuto || false;
  10372. const quests = {};
  10373. const calls = this.callsList.map((name) => ({
  10374. name,
  10375. args: {},
  10376. ident: name,
  10377. }));
  10378. const result = await Send(JSON.stringify({ calls })).then((e) => e.results);
  10379. for (const call of result) {
  10380. quests[call.ident] = call.result.response;
  10381. }
  10382. this.questInfo = quests;
  10383. }
  10384.  
  10385. async start() {
  10386. const weCanDo = [];
  10387. const selectedActions = getSaveVal('selectedActions', {});
  10388. for (let quest of this.questInfo['questGetAll']) {
  10389. if (quest.id in this.dataQuests && quest.state == 1) {
  10390. if (!selectedActions[quest.id]) {
  10391. selectedActions[quest.id] = {
  10392. checked: false,
  10393. };
  10394. }
  10395.  
  10396. const isWeCanDo = this.dataQuests[quest.id].isWeCanDo;
  10397. if (!isWeCanDo.call(this)) {
  10398. continue;
  10399. }
  10400.  
  10401. weCanDo.push({
  10402. name: quest.id,
  10403. label: I18N(`QUEST_${quest.id}`),
  10404. checked: selectedActions[quest.id].checked,
  10405. });
  10406. }
  10407. }
  10408.  
  10409. if (!weCanDo.length) {
  10410. this.end(I18N('NOTHING_TO_DO'));
  10411. return;
  10412. }
  10413.  
  10414. console.log(weCanDo);
  10415. let taskList = [];
  10416. if (this.isAuto) {
  10417. taskList = weCanDo;
  10418. } else {
  10419. const answer = await popup.confirm(
  10420. `${I18N('YOU_CAN_COMPLETE')}:`,
  10421. [
  10422. { msg: I18N('BTN_DO_IT'), result: true },
  10423. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  10424. ],
  10425. weCanDo
  10426. );
  10427. if (!answer) {
  10428. this.end('');
  10429. return;
  10430. }
  10431. taskList = popup.getCheckBoxes();
  10432. taskList.forEach((e) => {
  10433. selectedActions[e.name].checked = e.checked;
  10434. });
  10435. setSaveVal('selectedActions', selectedActions);
  10436. }
  10437.  
  10438. const calls = [];
  10439. let countChecked = 0;
  10440. for (const task of taskList) {
  10441. if (task.checked) {
  10442. countChecked++;
  10443. const quest = this.dataQuests[task.name];
  10444. console.log(quest.description);
  10445.  
  10446. if (quest.doItCall) {
  10447. const doItCall = quest.doItCall.call(this);
  10448. calls.push(...doItCall);
  10449. }
  10450. }
  10451. }
  10452.  
  10453. if (!countChecked) {
  10454. this.end(I18N('NOT_QUEST_COMPLETED'));
  10455. return;
  10456. }
  10457.  
  10458. const result = await Send(JSON.stringify({ calls }));
  10459. if (result.error) {
  10460. console.error(result.error, result.error.call);
  10461. }
  10462. this.end(`${I18N('COMPLETED_QUESTS')}: ${countChecked}`);
  10463. }
  10464.  
  10465. errorHandling(error) {
  10466. //console.error(error);
  10467. let errorInfo = error.toString() + '\n';
  10468. try {
  10469. const errorStack = error.stack.split('\n');
  10470. const endStack = errorStack.map((e) => e.split('@')[0]).indexOf('testDoYourBest');
  10471. errorInfo += errorStack.slice(0, endStack).join('\n');
  10472. } catch (e) {
  10473. errorInfo += error.stack;
  10474. }
  10475. copyText(errorInfo);
  10476. }
  10477.  
  10478. skillCost(lvl) {
  10479. return 573 * lvl ** 0.9 + lvl ** 2.379;
  10480. }
  10481.  
  10482. getUpgradeSkills() {
  10483. const heroes = Object.values(this.questInfo['heroGetAll']);
  10484. const upgradeSkills = [
  10485. { heroId: 0, slotId: 0, value: 130 },
  10486. { heroId: 0, slotId: 0, value: 130 },
  10487. { heroId: 0, slotId: 0, value: 130 },
  10488. ];
  10489. const skillLib = lib.getData('skill');
  10490. /**
  10491. * color - 1 (белый) открывает 1 навык
  10492. * color - 2 (зеленый) открывает 2 навык
  10493. * color - 4 (синий) открывает 3 навык
  10494. * color - 7 (фиолетовый) открывает 4 навык
  10495. */
  10496. const colors = [1, 2, 4, 7];
  10497. for (const hero of heroes) {
  10498. const level = hero.level;
  10499. const color = hero.color;
  10500. for (let skillId in hero.skills) {
  10501. const tier = skillLib[skillId].tier;
  10502. const sVal = hero.skills[skillId];
  10503. if (color < colors[tier] || tier < 1 || tier > 4) {
  10504. continue;
  10505. }
  10506. for (let upSkill of upgradeSkills) {
  10507. if (sVal < upSkill.value && sVal < level) {
  10508. upSkill.value = sVal;
  10509. upSkill.heroId = hero.id;
  10510. upSkill.skill = tier;
  10511. break;
  10512. }
  10513. }
  10514. }
  10515. }
  10516. return upgradeSkills;
  10517. }
  10518.  
  10519. getUpgradeArtifact() {
  10520. const heroes = Object.values(this.questInfo['heroGetAll']);
  10521. const inventory = this.questInfo['inventoryGet'];
  10522. const upArt = { heroId: 0, slotId: 0, level: 100 };
  10523.  
  10524. const heroLib = lib.getData('hero');
  10525. const artifactLib = lib.getData('artifact');
  10526.  
  10527. for (const hero of heroes) {
  10528. const heroInfo = heroLib[hero.id];
  10529. const level = hero.level;
  10530. if (level < 20) {
  10531. continue;
  10532. }
  10533.  
  10534. for (let slotId in hero.artifacts) {
  10535. const art = hero.artifacts[slotId];
  10536. /* Текущая звезданость арта */
  10537. const star = art.star;
  10538. if (!star) {
  10539. continue;
  10540. }
  10541. /* Текущий уровень арта */
  10542. const level = art.level;
  10543. if (level >= 100) {
  10544. continue;
  10545. }
  10546. /* Идентификатор арта в библиотеке */
  10547. const artifactId = heroInfo.artifacts[slotId];
  10548. const artInfo = artifactLib.id[artifactId];
  10549. const costNextLevel = artifactLib.type[artInfo.type].levels[level + 1].cost;
  10550.  
  10551. const costCurrency = Object.keys(costNextLevel).pop();
  10552. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  10553. const costId = costValues[0];
  10554. const costValue = +costValues[1];
  10555.  
  10556. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10557. if (level < upArt.level && inventory[costCurrency][costId] >= costValue) {
  10558. upArt.level = level;
  10559. upArt.heroId = hero.id;
  10560. upArt.slotId = slotId;
  10561. upArt.costCurrency = costCurrency;
  10562. upArt.costId = costId;
  10563. upArt.costValue = costValue;
  10564. }
  10565. }
  10566. }
  10567. return upArt;
  10568. }
  10569.  
  10570. getUpgradeSkin() {
  10571. const heroes = Object.values(this.questInfo['heroGetAll']);
  10572. const inventory = this.questInfo['inventoryGet'];
  10573. const upSkin = { heroId: 0, skinId: 0, level: 60, cost: 1500 };
  10574.  
  10575. const skinLib = lib.getData('skin');
  10576.  
  10577. for (const hero of heroes) {
  10578. const level = hero.level;
  10579. if (level < 20) {
  10580. continue;
  10581. }
  10582.  
  10583. for (let skinId in hero.skins) {
  10584. /* Текущий уровень скина */
  10585. const level = hero.skins[skinId];
  10586. if (level >= 60) {
  10587. continue;
  10588. }
  10589. /* Идентификатор скина в библиотеке */
  10590. const skinInfo = skinLib[skinId];
  10591. if (!skinInfo.statData.levels?.[level + 1]) {
  10592. continue;
  10593. }
  10594. const costNextLevel = skinInfo.statData.levels[level + 1].cost;
  10595.  
  10596. const costCurrency = Object.keys(costNextLevel).pop();
  10597. const costCurrencyId = Object.keys(costNextLevel[costCurrency]).pop();
  10598. const costValue = +costNextLevel[costCurrency][costCurrencyId];
  10599.  
  10600. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10601. if (level < upSkin.level && costValue < upSkin.cost && inventory[costCurrency][costCurrencyId] >= costValue) {
  10602. upSkin.cost = costValue;
  10603. upSkin.level = level;
  10604. upSkin.heroId = hero.id;
  10605. upSkin.skinId = skinId;
  10606. upSkin.costCurrency = costCurrency;
  10607. upSkin.costCurrencyId = costCurrencyId;
  10608. }
  10609. }
  10610. }
  10611. return upSkin;
  10612. }
  10613.  
  10614. getUpgradeTitanArtifact() {
  10615. const titans = Object.values(this.questInfo['titanGetAll']);
  10616. const inventory = this.questInfo['inventoryGet'];
  10617. const userInfo = this.questInfo['userGetInfo'];
  10618. const upArt = { titanId: 0, slotId: 0, level: 120 };
  10619.  
  10620. const titanLib = lib.getData('titan');
  10621. const artTitanLib = lib.getData('titanArtifact');
  10622.  
  10623. for (const titan of titans) {
  10624. const titanInfo = titanLib[titan.id];
  10625. // const level = titan.level
  10626. // if (level < 20) {
  10627. // continue;
  10628. // }
  10629.  
  10630. for (let slotId in titan.artifacts) {
  10631. const art = titan.artifacts[slotId];
  10632. /* Текущая звезданость арта */
  10633. const star = art.star;
  10634. if (!star) {
  10635. continue;
  10636. }
  10637. /* Текущий уровень арта */
  10638. const level = art.level;
  10639. if (level >= 120) {
  10640. continue;
  10641. }
  10642. /* Идентификатор арта в библиотеке */
  10643. const artifactId = titanInfo.artifacts[slotId];
  10644. const artInfo = artTitanLib.id[artifactId];
  10645. const costNextLevel = artTitanLib.type[artInfo.type].levels[level + 1].cost;
  10646.  
  10647. const costCurrency = Object.keys(costNextLevel).pop();
  10648. let costValue = 0;
  10649. let currentValue = 0;
  10650. if (costCurrency == 'gold') {
  10651. costValue = costNextLevel[costCurrency];
  10652. currentValue = userInfo.gold;
  10653. } else {
  10654. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  10655. const costId = costValues[0];
  10656. costValue = +costValues[1];
  10657. currentValue = inventory[costCurrency][costId];
  10658. }
  10659.  
  10660. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10661. if (level < upArt.level && currentValue >= costValue) {
  10662. upArt.level = level;
  10663. upArt.titanId = titan.id;
  10664. upArt.slotId = slotId;
  10665. break;
  10666. }
  10667. }
  10668. }
  10669. return upArt;
  10670. }
  10671.  
  10672. getEnchantRune() {
  10673. const heroes = Object.values(this.questInfo['heroGetAll']);
  10674. const inventory = this.questInfo['inventoryGet'];
  10675. const enchRune = { heroId: 0, tier: 0, exp: 43750, itemId: 0 };
  10676. for (let i = 1; i <= 4; i++) {
  10677. if (inventory.consumable[i] > 0) {
  10678. enchRune.itemId = i;
  10679. break;
  10680. }
  10681. return enchRune;
  10682. }
  10683.  
  10684. const runeLib = lib.getData('rune');
  10685. const runeLvls = Object.values(runeLib.level);
  10686. /**
  10687. * color - 4 (синий) открывает 1 и 2 символ
  10688. * color - 7 (фиолетовый) открывает 3 символ
  10689. * color - 8 (фиолетовый +1) открывает 4 символ
  10690. * color - 9 (фиолетовый +2) открывает 5 символ
  10691. */
  10692. // TODO: кажется надо учесть уровень команды
  10693. const colors = [4, 4, 7, 8, 9];
  10694. for (const hero of heroes) {
  10695. const color = hero.color;
  10696.  
  10697. for (let runeTier in hero.runes) {
  10698. /* Проверка на доступность руны */
  10699. if (color < colors[runeTier]) {
  10700. continue;
  10701. }
  10702. /* Текущий опыт руны */
  10703. const exp = hero.runes[runeTier];
  10704. if (exp >= 43750) {
  10705. continue;
  10706. }
  10707.  
  10708. let level = 0;
  10709. if (exp) {
  10710. for (let lvl of runeLvls) {
  10711. if (exp >= lvl.enchantValue) {
  10712. level = lvl.level;
  10713. } else {
  10714. break;
  10715. }
  10716. }
  10717. }
  10718. /** Уровень героя необходимый для уровня руны */
  10719. const heroLevel = runeLib.level[level].heroLevel;
  10720. if (hero.level < heroLevel) {
  10721. continue;
  10722. }
  10723.  
  10724. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10725. if (exp < enchRune.exp) {
  10726. enchRune.exp = exp;
  10727. enchRune.heroId = hero.id;
  10728. enchRune.tier = runeTier;
  10729. break;
  10730. }
  10731. }
  10732. }
  10733. return enchRune;
  10734. }
  10735.  
  10736. getOutlandChest() {
  10737. const bosses = this.questInfo['bossGetAll'];
  10738.  
  10739. const calls = [];
  10740.  
  10741. for (let boss of bosses) {
  10742. if (boss.mayRaid) {
  10743. calls.push({
  10744. name: 'bossRaid',
  10745. args: {
  10746. bossId: boss.id,
  10747. },
  10748. ident: 'bossRaid_' + boss.id,
  10749. });
  10750. calls.push({
  10751. name: 'bossOpenChest',
  10752. args: {
  10753. bossId: boss.id,
  10754. amount: 1,
  10755. starmoney: 0,
  10756. },
  10757. ident: 'bossOpenChest_' + boss.id,
  10758. });
  10759. } else if (boss.chestId == 1) {
  10760. calls.push({
  10761. name: 'bossOpenChest',
  10762. args: {
  10763. bossId: boss.id,
  10764. amount: 1,
  10765. starmoney: 0,
  10766. },
  10767. ident: 'bossOpenChest_' + boss.id,
  10768. });
  10769. }
  10770. }
  10771.  
  10772. return calls;
  10773. }
  10774.  
  10775. getExpHero() {
  10776. const heroes = Object.values(this.questInfo['heroGetAll']);
  10777. const inventory = this.questInfo['inventoryGet'];
  10778. const expHero = { heroId: 0, exp: 3625195, libId: 0 };
  10779. /** зелья опыта (consumable 9, 10, 11, 12) */
  10780. for (let i = 9; i <= 12; i++) {
  10781. if (inventory.consumable[i]) {
  10782. expHero.libId = i;
  10783. break;
  10784. }
  10785. }
  10786.  
  10787. for (const hero of heroes) {
  10788. const exp = hero.xp;
  10789. if (exp < expHero.exp) {
  10790. expHero.heroId = hero.id;
  10791. }
  10792. }
  10793. return expHero;
  10794. }
  10795.  
  10796. getHeroIdTitanGift() {
  10797. const heroes = Object.values(this.questInfo['heroGetAll']);
  10798. const inventory = this.questInfo['inventoryGet'];
  10799. const user = this.questInfo['userGetInfo'];
  10800. const titanGiftLib = lib.getData('titanGift');
  10801. /** Искры */
  10802. const titanGift = inventory.consumable[24];
  10803. let heroId = 0;
  10804. let minLevel = 30;
  10805.  
  10806. if (titanGift < 250 || user.gold < 7000) {
  10807. return 0;
  10808. }
  10809.  
  10810. for (const hero of heroes) {
  10811. if (hero.titanGiftLevel >= 30) {
  10812. continue;
  10813. }
  10814.  
  10815. if (!hero.titanGiftLevel) {
  10816. return hero.id;
  10817. }
  10818.  
  10819. const cost = titanGiftLib[hero.titanGiftLevel].cost;
  10820. if (minLevel > hero.titanGiftLevel && titanGift >= cost.consumable[24] && user.gold >= cost.gold) {
  10821. minLevel = hero.titanGiftLevel;
  10822. heroId = hero.id;
  10823. }
  10824. }
  10825.  
  10826. return heroId;
  10827. }
  10828.  
  10829. getHeroicMissionId() {
  10830. // Получаем доступные миссии с 3 звездами
  10831. const availableMissionsToRaid = Object.values(this.questInfo.missionGetAll)
  10832. .filter((mission) => mission.stars === 3)
  10833. .map((mission) => mission.id);
  10834.  
  10835. // Получаем героев для улучшения, у которых меньше 6 звезд
  10836. const heroesToUpgrade = Object.values(this.questInfo.heroGetAll)
  10837. .filter((hero) => hero.star < 6)
  10838. .sort((a, b) => b.power - a.power)
  10839. .map((hero) => hero.id);
  10840.  
  10841. // Получаем героические миссии, которые доступны для рейдов
  10842. const heroicMissions = Object.values(lib.data.mission).filter((mission) => mission.isHeroic && availableMissionsToRaid.includes(mission.id));
  10843.  
  10844. // Собираем дропы из героических миссий
  10845. const drops = heroicMissions.map((mission) => {
  10846. const lastWave = mission.normalMode.waves[mission.normalMode.waves.length - 1];
  10847. const allRewards = lastWave.enemies[lastWave.enemies.length - 1]
  10848. .drop.map((drop) => drop.reward);
  10849.  
  10850. const heroId = +Object.keys(allRewards.find((reward) => reward.fragmentHero).fragmentHero).pop();
  10851.  
  10852. return { id: mission.id, heroId };
  10853. });
  10854.  
  10855. // Определяем, какие дропы подходят для героев, которых нужно улучшить
  10856. const heroDrops = heroesToUpgrade.map((heroId) => drops.find((drop) => drop.heroId == heroId)).filter((drop) => drop);
  10857. const firstMission = heroDrops[0];
  10858. // Выбираем миссию для рейда
  10859. const selectedMissionId = firstMission ? firstMission.id : 1;
  10860.  
  10861. const stamina = this.questInfo.userGetInfo.refillable.find((x) => x.id == 1).amount;
  10862. const costMissions = 3 * lib.data.mission[selectedMissionId].normalMode.teamExp;
  10863. if (stamina < costMissions) {
  10864. console.log('Энергии не достаточно');
  10865. return 0;
  10866. }
  10867. return selectedMissionId;
  10868. }
  10869.  
  10870. end(status) {
  10871. setProgress(status, true);
  10872. this.resolve();
  10873. }
  10874. }
  10875.  
  10876. this.questRun = dailyQuests;
  10877.  
  10878. function testDoYourBest() {
  10879. return new Promise((resolve, reject) => {
  10880. const doIt = new doYourBest(resolve, reject);
  10881. doIt.start();
  10882. });
  10883. }
  10884.  
  10885. /**
  10886. * Do everything button
  10887. *
  10888. * Кнопка сделать все
  10889. */
  10890. class doYourBest {
  10891.  
  10892. funcList = [
  10893. {
  10894. name: 'getOutland',
  10895. label: I18N('ASSEMBLE_OUTLAND'),
  10896. checked: false
  10897. },
  10898. {
  10899. name: 'testTower',
  10900. label: I18N('PASS_THE_TOWER'),
  10901. checked: false
  10902. },
  10903. {
  10904. name: 'checkExpedition',
  10905. label: I18N('CHECK_EXPEDITIONS'),
  10906. checked: false
  10907. },
  10908. {
  10909. name: 'testTitanArena',
  10910. label: I18N('COMPLETE_TOE'),
  10911. checked: false
  10912. },
  10913. {
  10914. name: 'mailGetAll',
  10915. label: I18N('COLLECT_MAIL'),
  10916. checked: false
  10917. },
  10918. {
  10919. name: 'collectAllStuff',
  10920. label: I18N('COLLECT_MISC'),
  10921. title: I18N('COLLECT_MISC_TITLE'),
  10922. checked: false
  10923. },
  10924. {
  10925. name: 'getDailyBonus',
  10926. label: I18N('DAILY_BONUS'),
  10927. checked: false
  10928. },
  10929. {
  10930. name: 'dailyQuests',
  10931. label: I18N('DO_DAILY_QUESTS'),
  10932. checked: false
  10933. },
  10934. {
  10935. name: 'rollAscension',
  10936. label: I18N('SEER_TITLE'),
  10937. checked: false
  10938. },
  10939. {
  10940. name: 'questAllFarm',
  10941. label: I18N('COLLECT_QUEST_REWARDS'),
  10942. checked: false
  10943. },
  10944. {
  10945. name: 'testDungeon',
  10946. label: I18N('COMPLETE_DUNGEON'),
  10947. checked: false
  10948. },
  10949. {
  10950. name: 'synchronization',
  10951. label: I18N('MAKE_A_SYNC'),
  10952. checked: false
  10953. },
  10954. {
  10955. name: 'reloadGame',
  10956. label: I18N('RELOAD_GAME'),
  10957. checked: false
  10958. },
  10959. ];
  10960.  
  10961. functions = {
  10962. getOutland,
  10963. testTower,
  10964. checkExpedition,
  10965. testTitanArena,
  10966. mailGetAll,
  10967. collectAllStuff: async () => {
  10968. await offerFarmAllReward();
  10969. 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"}]}');
  10970. },
  10971. dailyQuests: async function () {
  10972. const quests = new dailyQuests(() => { }, () => { });
  10973. await quests.autoInit(true);
  10974. await quests.start();
  10975. },
  10976. rollAscension,
  10977. getDailyBonus,
  10978. questAllFarm,
  10979. testDungeon,
  10980. synchronization: async () => {
  10981. cheats.refreshGame();
  10982. },
  10983. reloadGame: async () => {
  10984. location.reload();
  10985. },
  10986. }
  10987.  
  10988. constructor(resolve, reject, questInfo) {
  10989. this.resolve = resolve;
  10990. this.reject = reject;
  10991. this.questInfo = questInfo
  10992. }
  10993.  
  10994. async start() {
  10995. const selectedDoIt = getSaveVal('selectedDoIt', {});
  10996.  
  10997. this.funcList.forEach(task => {
  10998. if (!selectedDoIt[task.name]) {
  10999. selectedDoIt[task.name] = {
  11000. checked: task.checked
  11001. }
  11002. } else {
  11003. task.checked = selectedDoIt[task.name].checked
  11004. }
  11005. });
  11006.  
  11007. const answer = await popup.confirm(I18N('RUN_FUNCTION'), [
  11008. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  11009. { msg: I18N('BTN_GO'), result: true },
  11010. ], this.funcList);
  11011.  
  11012. if (!answer) {
  11013. this.end('');
  11014. return;
  11015. }
  11016.  
  11017. const taskList = popup.getCheckBoxes();
  11018. taskList.forEach(task => {
  11019. selectedDoIt[task.name].checked = task.checked;
  11020. });
  11021. setSaveVal('selectedDoIt', selectedDoIt);
  11022. for (const task of popup.getCheckBoxes()) {
  11023. if (task.checked) {
  11024. try {
  11025. setProgress(`${task.label} <br>${I18N('PERFORMED')}!`);
  11026. await this.functions[task.name]();
  11027. setProgress(`${task.label} <br>${I18N('DONE')}!`);
  11028. } catch (error) {
  11029. if (await popup.confirm(`${I18N('ERRORS_OCCURRES')}:<br> ${task.label} <br>${I18N('COPY_ERROR')}?`, [
  11030. { msg: I18N('BTN_NO'), result: false },
  11031. { msg: I18N('BTN_YES'), result: true },
  11032. ])) {
  11033. this.errorHandling(error);
  11034. }
  11035. }
  11036. }
  11037. }
  11038. setTimeout((msg) => {
  11039. this.end(msg);
  11040. }, 2000, I18N('ALL_TASK_COMPLETED'));
  11041. return;
  11042. }
  11043.  
  11044. errorHandling(error) {
  11045. //console.error(error);
  11046. let errorInfo = error.toString() + '\n';
  11047. try {
  11048. const errorStack = error.stack.split('\n');
  11049. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  11050. errorInfo += errorStack.slice(0, endStack).join('\n');
  11051. } catch (e) {
  11052. errorInfo += error.stack;
  11053. }
  11054. copyText(errorInfo);
  11055. }
  11056.  
  11057. end(status) {
  11058. setProgress(status, true);
  11059. this.resolve();
  11060. }
  11061. }
  11062.  
  11063. /**
  11064. * Passing the adventure along the specified route
  11065. *
  11066. * Прохождение приключения по указанному маршруту
  11067. */
  11068. function testAdventure(type) {
  11069. return new Promise((resolve, reject) => {
  11070. const bossBattle = new executeAdventure(resolve, reject);
  11071. bossBattle.start(type);
  11072. });
  11073. }
  11074.  
  11075. /**
  11076. * Passing the adventure along the specified route
  11077. *
  11078. * Прохождение приключения по указанному маршруту
  11079. */
  11080. class executeAdventure {
  11081.  
  11082. type = 'default';
  11083.  
  11084. actions = {
  11085. default: {
  11086. getInfo: "adventure_getInfo",
  11087. startBattle: 'adventure_turnStartBattle',
  11088. endBattle: 'adventure_endBattle',
  11089. collectBuff: 'adventure_turnCollectBuff'
  11090. },
  11091. solo: {
  11092. getInfo: "adventureSolo_getInfo",
  11093. startBattle: 'adventureSolo_turnStartBattle',
  11094. endBattle: 'adventureSolo_endBattle',
  11095. collectBuff: 'adventureSolo_turnCollectBuff'
  11096. }
  11097. }
  11098.  
  11099. terminatеReason = I18N('UNKNOWN');
  11100. callAdventureInfo = {
  11101. name: "adventure_getInfo",
  11102. args: {},
  11103. ident: "adventure_getInfo"
  11104. }
  11105. callTeamGetAll = {
  11106. name: "teamGetAll",
  11107. args: {},
  11108. ident: "teamGetAll"
  11109. }
  11110. callTeamGetFavor = {
  11111. name: "teamGetFavor",
  11112. args: {},
  11113. ident: "teamGetFavor"
  11114. }
  11115. callStartBattle = {
  11116. name: "adventure_turnStartBattle",
  11117. args: {},
  11118. ident: "body"
  11119. }
  11120. callEndBattle = {
  11121. name: "adventure_endBattle",
  11122. args: {
  11123. result: {},
  11124. progress: {},
  11125. },
  11126. ident: "body"
  11127. }
  11128. callCollectBuff = {
  11129. name: "adventure_turnCollectBuff",
  11130. args: {},
  11131. ident: "body"
  11132. }
  11133.  
  11134. constructor(resolve, reject) {
  11135. this.resolve = resolve;
  11136. this.reject = reject;
  11137. }
  11138.  
  11139. async start(type) {
  11140. this.type = type || this.type;
  11141. this.callAdventureInfo.name = this.actions[this.type].getInfo;
  11142. const data = await Send(JSON.stringify({
  11143. calls: [
  11144. this.callAdventureInfo,
  11145. this.callTeamGetAll,
  11146. this.callTeamGetFavor
  11147. ]
  11148. }));
  11149. return this.checkAdventureInfo(data.results);
  11150. }
  11151.  
  11152. async getPath() {
  11153. const oldVal = getSaveVal('adventurePath', '');
  11154. const keyPath = `adventurePath:${this.mapIdent}`;
  11155. const answer = await popup.confirm(I18N('ENTER_THE_PATH'), [
  11156. {
  11157. msg: I18N('START_ADVENTURE'),
  11158. placeholder: '1,2,3,4,5,6',
  11159. isInput: true,
  11160. default: getSaveVal(keyPath, oldVal)
  11161. },
  11162. {
  11163. msg: I18N('BTN_CANCEL'),
  11164. result: false,
  11165. isCancel: true
  11166. },
  11167. ]);
  11168. if (!answer) {
  11169. this.terminatеReason = I18N('BTN_CANCELED');
  11170. return false;
  11171. }
  11172.  
  11173. let path = answer.split(',');
  11174. if (path.length < 2) {
  11175. path = answer.split('-');
  11176. }
  11177. if (path.length < 2) {
  11178. this.terminatеReason = I18N('MUST_TWO_POINTS');
  11179. return false;
  11180. }
  11181.  
  11182. for (let p in path) {
  11183. path[p] = +path[p].trim()
  11184. if (Number.isNaN(path[p])) {
  11185. this.terminatеReason = I18N('MUST_ONLY_NUMBERS');
  11186. return false;
  11187. }
  11188. }
  11189.  
  11190. if (!this.checkPath(path)) {
  11191. return false;
  11192. }
  11193. setSaveVal(keyPath, answer);
  11194. return path;
  11195. }
  11196.  
  11197. checkPath(path) {
  11198. for (let i = 0; i < path.length - 1; i++) {
  11199. const currentPoint = path[i];
  11200. const nextPoint = path[i + 1];
  11201.  
  11202. const isValidPath = this.paths.some(p =>
  11203. (p.from_id === currentPoint && p.to_id === nextPoint) ||
  11204. (p.from_id === nextPoint && p.to_id === currentPoint)
  11205. );
  11206.  
  11207. if (!isValidPath) {
  11208. this.terminatеReason = I18N('INCORRECT_WAY', {
  11209. from: currentPoint,
  11210. to: nextPoint,
  11211. });
  11212. return false;
  11213. }
  11214. }
  11215.  
  11216. return true;
  11217. }
  11218.  
  11219. async checkAdventureInfo(data) {
  11220. this.advInfo = data[0].result.response;
  11221. if (!this.advInfo) {
  11222. this.terminatеReason = I18N('NOT_ON_AN_ADVENTURE') ;
  11223. return this.end();
  11224. }
  11225. const heroesTeam = data[1].result.response.adventure_hero;
  11226. const favor = data[2]?.result.response.adventure_hero;
  11227. const heroes = heroesTeam.slice(0, 5);
  11228. const pet = heroesTeam[5];
  11229. this.args = {
  11230. pet,
  11231. heroes,
  11232. favor,
  11233. path: [],
  11234. broadcast: false
  11235. }
  11236. const advUserInfo = this.advInfo.users[userInfo.id];
  11237. this.turnsLeft = advUserInfo.turnsLeft;
  11238. this.currentNode = advUserInfo.currentNode;
  11239. this.nodes = this.advInfo.nodes;
  11240. this.paths = this.advInfo.paths;
  11241. this.mapIdent = this.advInfo.mapIdent;
  11242.  
  11243. this.path = await this.getPath();
  11244. if (!this.path) {
  11245. return this.end();
  11246. }
  11247.  
  11248. if (this.currentNode == 1 && this.path[0] != 1) {
  11249. this.path.unshift(1);
  11250. }
  11251.  
  11252. return this.loop();
  11253. }
  11254.  
  11255. async loop() {
  11256. const position = this.path.indexOf(+this.currentNode);
  11257. if (!(~position)) {
  11258. this.terminatеReason = I18N('YOU_IN_NOT_ON_THE_WAY');
  11259. return this.end();
  11260. }
  11261. this.path = this.path.slice(position);
  11262. if ((this.path.length - 1) > this.turnsLeft &&
  11263. await popup.confirm(I18N('ATTEMPTS_NOT_ENOUGH'), [
  11264. { msg: I18N('YES_CONTINUE'), result: false },
  11265. { msg: I18N('BTN_NO'), result: true },
  11266. ])) {
  11267. this.terminatеReason = I18N('NOT_ENOUGH_AP');
  11268. return this.end();
  11269. }
  11270. const toPath = [];
  11271. for (const nodeId of this.path) {
  11272. if (!this.turnsLeft) {
  11273. this.terminatеReason = I18N('ATTEMPTS_ARE_OVER');
  11274. return this.end();
  11275. }
  11276. toPath.push(nodeId);
  11277. console.log(toPath);
  11278. if (toPath.length > 1) {
  11279. setProgress(toPath.join(' > ') + ` ${I18N('MOVES')}: ` + this.turnsLeft);
  11280. }
  11281. if (nodeId == this.currentNode) {
  11282. continue;
  11283. }
  11284.  
  11285. const nodeInfo = this.getNodeInfo(nodeId);
  11286. if (nodeInfo.type == 'TYPE_COMBAT') {
  11287. if (nodeInfo.state == 'empty') {
  11288. this.turnsLeft--;
  11289. continue;
  11290. }
  11291.  
  11292. /**
  11293. * Disable regular battle cancellation
  11294. *
  11295. * Отключаем штатную отменую боя
  11296. */
  11297. isCancalBattle = false;
  11298. if (await this.battle(toPath)) {
  11299. this.turnsLeft--;
  11300. toPath.splice(0, toPath.indexOf(nodeId));
  11301. nodeInfo.state = 'empty';
  11302. isCancalBattle = true;
  11303. continue;
  11304. }
  11305. isCancalBattle = true;
  11306. return this.end()
  11307. }
  11308.  
  11309. if (nodeInfo.type == 'TYPE_PLAYERBUFF') {
  11310. const buff = this.checkBuff(nodeInfo);
  11311. if (buff == null) {
  11312. continue;
  11313. }
  11314.  
  11315. if (await this.collectBuff(buff, toPath)) {
  11316. this.turnsLeft--;
  11317. toPath.splice(0, toPath.indexOf(nodeId));
  11318. continue;
  11319. }
  11320. this.terminatеReason = I18N('BUFF_GET_ERROR');
  11321. return this.end();
  11322. }
  11323. }
  11324. this.terminatеReason = I18N('SUCCESS');
  11325. return this.end();
  11326. }
  11327.  
  11328. /**
  11329. * Carrying out a fight
  11330. *
  11331. * Проведение боя
  11332. */
  11333. async battle(path, preCalc = true) {
  11334. const data = await this.startBattle(path);
  11335. try {
  11336. const battle = data.results[0].result.response.battle;
  11337. const result = await Calc(battle);
  11338. if (result.result.win) {
  11339. const info = await this.endBattle(result);
  11340. if (info.results[0].result.response?.error) {
  11341. this.terminatеReason = I18N('BATTLE_END_ERROR');
  11342. return false;
  11343. }
  11344. } else {
  11345. await this.cancelBattle(result);
  11346.  
  11347. if (preCalc && await this.preCalcBattle(battle)) {
  11348. path = path.slice(-2);
  11349. for (let i = 1; i <= getInput('countAutoBattle'); i++) {
  11350. setProgress(`${I18N('AUTOBOT')}: ${i}/${getInput('countAutoBattle')}`);
  11351. const result = await this.battle(path, false);
  11352. if (result) {
  11353. setProgress(I18N('VICTORY'));
  11354. return true;
  11355. }
  11356. }
  11357. this.terminatеReason = I18N('FAILED_TO_WIN_AUTO');
  11358. return false;
  11359. }
  11360. return false;
  11361. }
  11362. } catch (error) {
  11363. console.error(error);
  11364. if (await popup.confirm(I18N('ERROR_OF_THE_BATTLE_COPY'), [
  11365. { msg: I18N('BTN_NO'), result: false },
  11366. { msg: I18N('BTN_YES'), result: true },
  11367. ])) {
  11368. this.errorHandling(error, data);
  11369. }
  11370. this.terminatеReason = I18N('ERROR_DURING_THE_BATTLE');
  11371. return false;
  11372. }
  11373. return true;
  11374. }
  11375.  
  11376. /**
  11377. * Recalculate battles
  11378. *
  11379. * Прерасчтет битвы
  11380. */
  11381. async preCalcBattle(battle) {
  11382. const countTestBattle = getInput('countTestBattle');
  11383. for (let i = 0; i < countTestBattle; i++) {
  11384. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  11385. const result = await Calc(battle);
  11386. if (result.result.win) {
  11387. console.log(i, countTestBattle);
  11388. return true;
  11389. }
  11390. }
  11391. this.terminatеReason = I18N('NO_CHANCE_WIN') + countTestBattle;
  11392. return false;
  11393. }
  11394.  
  11395. /**
  11396. * Starts a fight
  11397. *
  11398. * Начинает бой
  11399. */
  11400. startBattle(path) {
  11401. this.args.path = path;
  11402. this.callStartBattle.name = this.actions[this.type].startBattle;
  11403. this.callStartBattle.args = this.args
  11404. const calls = [this.callStartBattle];
  11405. return Send(JSON.stringify({ calls }));
  11406. }
  11407.  
  11408. cancelBattle(battle) {
  11409. const fixBattle = function (heroes) {
  11410. for (const ids in heroes) {
  11411. const hero = heroes[ids];
  11412. hero.energy = random(1, 999);
  11413. if (hero.hp > 0) {
  11414. hero.hp = random(1, hero.hp);
  11415. }
  11416. }
  11417. }
  11418. fixBattle(battle.progress[0].attackers.heroes);
  11419. fixBattle(battle.progress[0].defenders.heroes);
  11420. return this.endBattle(battle);
  11421. }
  11422.  
  11423. /**
  11424. * Ends the fight
  11425. *
  11426. * Заканчивает бой
  11427. */
  11428. endBattle(battle) {
  11429. this.callEndBattle.name = this.actions[this.type].endBattle;
  11430. this.callEndBattle.args.result = battle.result
  11431. this.callEndBattle.args.progress = battle.progress
  11432. const calls = [this.callEndBattle];
  11433. return Send(JSON.stringify({ calls }));
  11434. }
  11435.  
  11436. /**
  11437. * Checks if you can get a buff
  11438. *
  11439. * Проверяет можно ли получить баф
  11440. */
  11441. checkBuff(nodeInfo) {
  11442. let id = null;
  11443. let value = 0;
  11444. for (const buffId in nodeInfo.buffs) {
  11445. const buff = nodeInfo.buffs[buffId];
  11446. if (buff.owner == null && buff.value > value) {
  11447. id = buffId;
  11448. value = buff.value;
  11449. }
  11450. }
  11451. nodeInfo.buffs[id].owner = 'Я';
  11452. return id;
  11453. }
  11454.  
  11455. /**
  11456. * Collects a buff
  11457. *
  11458. * Собирает баф
  11459. */
  11460. async collectBuff(buff, path) {
  11461. this.callCollectBuff.name = this.actions[this.type].collectBuff;
  11462. this.callCollectBuff.args = { buff, path };
  11463. const calls = [this.callCollectBuff];
  11464. return Send(JSON.stringify({ calls }));
  11465. }
  11466.  
  11467. getNodeInfo(nodeId) {
  11468. return this.nodes.find(node => node.id == nodeId);
  11469. }
  11470.  
  11471. errorHandling(error, data) {
  11472. //console.error(error);
  11473. let errorInfo = error.toString() + '\n';
  11474. try {
  11475. const errorStack = error.stack.split('\n');
  11476. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testAdventure");
  11477. errorInfo += errorStack.slice(0, endStack).join('\n');
  11478. } catch (e) {
  11479. errorInfo += error.stack;
  11480. }
  11481. if (data) {
  11482. errorInfo += '\nData: ' + JSON.stringify(data);
  11483. }
  11484. copyText(errorInfo);
  11485. }
  11486.  
  11487. end() {
  11488. isCancalBattle = true;
  11489. setProgress(this.terminatеReason, true);
  11490. console.log(this.terminatеReason);
  11491. this.resolve();
  11492. }
  11493. }
  11494.  
  11495. /**
  11496. * Passage of brawls
  11497. *
  11498. * Прохождение потасовок
  11499. */
  11500. function testBrawls(isAuto) {
  11501. return new Promise((resolve, reject) => {
  11502. const brawls = new executeBrawls(resolve, reject);
  11503. brawls.start(brawlsPack, isAuto);
  11504. });
  11505. }
  11506. /**
  11507. * Passage of brawls
  11508. *
  11509. * Прохождение потасовок
  11510. */
  11511. class executeBrawls {
  11512. callBrawlQuestGetInfo = {
  11513. name: "brawl_questGetInfo",
  11514. args: {},
  11515. ident: "brawl_questGetInfo"
  11516. }
  11517. callBrawlFindEnemies = {
  11518. name: "brawl_findEnemies",
  11519. args: {},
  11520. ident: "brawl_findEnemies"
  11521. }
  11522. callBrawlQuestFarm = {
  11523. name: "brawl_questFarm",
  11524. args: {},
  11525. ident: "brawl_questFarm"
  11526. }
  11527. callUserGetInfo = {
  11528. name: "userGetInfo",
  11529. args: {},
  11530. ident: "userGetInfo"
  11531. }
  11532. callTeamGetMaxUpgrade = {
  11533. name: "teamGetMaxUpgrade",
  11534. args: {},
  11535. ident: "teamGetMaxUpgrade"
  11536. }
  11537. callBrawlGetInfo = {
  11538. name: "brawl_getInfo",
  11539. args: {},
  11540. ident: "brawl_getInfo"
  11541. }
  11542.  
  11543. stats = {
  11544. win: 0,
  11545. loss: 0,
  11546. count: 0,
  11547. }
  11548.  
  11549. stage = {
  11550. '3': 1,
  11551. '7': 2,
  11552. '12': 3,
  11553. }
  11554.  
  11555. attempts = 0;
  11556.  
  11557. constructor(resolve, reject) {
  11558. this.resolve = resolve;
  11559. this.reject = reject;
  11560.  
  11561. const allHeroIds = Object.keys(lib.getData('hero'));
  11562. this.callTeamGetMaxUpgrade.args.units = {
  11563. hero: allHeroIds.filter((id) => +id < 1000),
  11564. titan: allHeroIds.filter((id) => +id >= 4000 && +id < 4100),
  11565. pet: allHeroIds.filter((id) => +id >= 6000 && +id < 6100),
  11566. };
  11567. }
  11568.  
  11569. async start(args, isAuto) {
  11570. this.isAuto = isAuto;
  11571. this.args = args;
  11572. isCancalBattle = false;
  11573. this.brawlInfo = await this.getBrawlInfo();
  11574. this.attempts = this.brawlInfo.attempts;
  11575.  
  11576. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  11577. this.end(I18N('DONT_HAVE_LIVES'));
  11578. return;
  11579. }
  11580.  
  11581. while (1) {
  11582. if (!isBrawlsAutoStart) {
  11583. this.end(I18N('BTN_CANCELED'));
  11584. return;
  11585. }
  11586.  
  11587. const maxStage = this.brawlInfo.questInfo.stage;
  11588. const stage = this.stage[maxStage];
  11589. const progress = this.brawlInfo.questInfo.progress;
  11590.  
  11591. setProgress(
  11592. `${I18N('STAGE')} ${stage}: ${progress}/${maxStage}<br>${I18N('FIGHTS')}: ${this.stats.count}<br>${I18N('WINS')}: ${
  11593. this.stats.win
  11594. }<br>${I18N('LOSSES')}: ${this.stats.loss}<br>${I18N('LIVES')}: ${this.attempts}<br>${I18N('STOP')}`,
  11595. false,
  11596. function () {
  11597. isBrawlsAutoStart = false;
  11598. }
  11599. );
  11600.  
  11601. if (this.brawlInfo.questInfo.canFarm) {
  11602. const result = await this.questFarm();
  11603. console.log(result);
  11604. }
  11605.  
  11606. if (!this.continueAttack && this.brawlInfo.questInfo.stage == 12 && this.brawlInfo.questInfo.progress == 12) {
  11607. if (
  11608. await popup.confirm(I18N('BRAWL_DAILY_TASK_COMPLETED'), [
  11609. { msg: I18N('BTN_NO'), result: true },
  11610. { msg: I18N('BTN_YES'), result: false },
  11611. ])
  11612. ) {
  11613. this.end(I18N('SUCCESS'));
  11614. return;
  11615. } else {
  11616. this.continueAttack = true;
  11617. }
  11618. }
  11619.  
  11620. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  11621. this.end(I18N('DONT_HAVE_LIVES'));
  11622. return;
  11623. }
  11624.  
  11625. const enemie = Object.values(this.brawlInfo.findEnemies).shift();
  11626.  
  11627. // Автоматический подбор пачки
  11628. if (this.isAuto) {
  11629. if (this.mandatoryId <= 4000 && this.mandatoryId != 13) {
  11630. this.end(I18N('BRAWL_AUTO_PACK_NOT_CUR_HERO'));
  11631. return;
  11632. }
  11633. if (this.mandatoryId >= 4000 && this.mandatoryId < 4100) {
  11634. this.args = await this.updateTitanPack(enemie.heroes);
  11635. } else if (this.mandatoryId < 4000 && this.mandatoryId == 13) {
  11636. this.args = await this.updateHeroesPack(enemie.heroes);
  11637. }
  11638. }
  11639.  
  11640. const result = await this.battle(enemie.userId);
  11641. this.brawlInfo = {
  11642. questInfo: result[1].result.response,
  11643. findEnemies: result[2].result.response,
  11644. };
  11645. }
  11646. }
  11647.  
  11648. async updateTitanPack(enemieHeroes) {
  11649. const packs = [
  11650. [4033, 4040, 4041, 4042, 4043],
  11651. [4032, 4040, 4041, 4042, 4043],
  11652. [4031, 4040, 4041, 4042, 4043],
  11653. [4030, 4040, 4041, 4042, 4043],
  11654. [4032, 4033, 4040, 4042, 4043],
  11655. [4030, 4033, 4041, 4042, 4043],
  11656. [4031, 4033, 4040, 4042, 4043],
  11657. [4032, 4033, 4040, 4041, 4043],
  11658. [4023, 4040, 4041, 4042, 4043],
  11659. [4030, 4033, 4040, 4042, 4043],
  11660. [4031, 4033, 4040, 4041, 4043],
  11661. [4022, 4040, 4041, 4042, 4043],
  11662. [4030, 4033, 4040, 4041, 4043],
  11663. [4021, 4040, 4041, 4042, 4043],
  11664. [4020, 4040, 4041, 4042, 4043],
  11665. [4023, 4033, 4040, 4042, 4043],
  11666. [4030, 4032, 4033, 4042, 4043],
  11667. [4023, 4033, 4040, 4041, 4043],
  11668. [4031, 4032, 4033, 4040, 4043],
  11669. [4030, 4032, 4033, 4041, 4043],
  11670. [4030, 4031, 4033, 4042, 4043],
  11671. [4013, 4040, 4041, 4042, 4043],
  11672. [4030, 4032, 4033, 4040, 4043],
  11673. [4030, 4031, 4033, 4041, 4043],
  11674. [4012, 4040, 4041, 4042, 4043],
  11675. [4030, 4031, 4033, 4040, 4043],
  11676. [4011, 4040, 4041, 4042, 4043],
  11677. [4010, 4040, 4041, 4042, 4043],
  11678. [4023, 4032, 4033, 4042, 4043],
  11679. [4022, 4032, 4033, 4042, 4043],
  11680. [4023, 4032, 4033, 4041, 4043],
  11681. [4021, 4032, 4033, 4042, 4043],
  11682. [4022, 4032, 4033, 4041, 4043],
  11683. [4023, 4030, 4033, 4042, 4043],
  11684. [4023, 4032, 4033, 4040, 4043],
  11685. [4013, 4033, 4040, 4042, 4043],
  11686. [4020, 4032, 4033, 4042, 4043],
  11687. [4021, 4032, 4033, 4041, 4043],
  11688. [4022, 4030, 4033, 4042, 4043],
  11689. [4022, 4032, 4033, 4040, 4043],
  11690. [4023, 4030, 4033, 4041, 4043],
  11691. [4023, 4031, 4033, 4040, 4043],
  11692. [4013, 4033, 4040, 4041, 4043],
  11693. [4020, 4031, 4033, 4042, 4043],
  11694. [4020, 4032, 4033, 4041, 4043],
  11695. [4021, 4030, 4033, 4042, 4043],
  11696. [4021, 4032, 4033, 4040, 4043],
  11697. [4022, 4030, 4033, 4041, 4043],
  11698. [4022, 4031, 4033, 4040, 4043],
  11699. [4023, 4030, 4033, 4040, 4043],
  11700. [4030, 4031, 4032, 4033, 4043],
  11701. [4003, 4040, 4041, 4042, 4043],
  11702. [4020, 4030, 4033, 4042, 4043],
  11703. [4020, 4031, 4033, 4041, 4043],
  11704. [4020, 4032, 4033, 4040, 4043],
  11705. [4021, 4030, 4033, 4041, 4043],
  11706. [4021, 4031, 4033, 4040, 4043],
  11707. [4022, 4030, 4033, 4040, 4043],
  11708. [4030, 4031, 4032, 4033, 4042],
  11709. [4002, 4040, 4041, 4042, 4043],
  11710. [4020, 4030, 4033, 4041, 4043],
  11711. [4020, 4031, 4033, 4040, 4043],
  11712. [4021, 4030, 4033, 4040, 4043],
  11713. [4030, 4031, 4032, 4033, 4041],
  11714. [4001, 4040, 4041, 4042, 4043],
  11715. [4030, 4031, 4032, 4033, 4040],
  11716. [4000, 4040, 4041, 4042, 4043],
  11717. [4013, 4032, 4033, 4042, 4043],
  11718. [4012, 4032, 4033, 4042, 4043],
  11719. [4013, 4032, 4033, 4041, 4043],
  11720. [4023, 4031, 4032, 4033, 4043],
  11721. [4011, 4032, 4033, 4042, 4043],
  11722. [4012, 4032, 4033, 4041, 4043],
  11723. [4013, 4030, 4033, 4042, 4043],
  11724. [4013, 4032, 4033, 4040, 4043],
  11725. [4023, 4030, 4032, 4033, 4043],
  11726. [4003, 4033, 4040, 4042, 4043],
  11727. [4013, 4023, 4040, 4042, 4043],
  11728. [4010, 4032, 4033, 4042, 4043],
  11729. [4011, 4032, 4033, 4041, 4043],
  11730. [4012, 4030, 4033, 4042, 4043],
  11731. [4012, 4032, 4033, 4040, 4043],
  11732. [4013, 4030, 4033, 4041, 4043],
  11733. [4013, 4031, 4033, 4040, 4043],
  11734. [4023, 4030, 4031, 4033, 4043],
  11735. [4003, 4033, 4040, 4041, 4043],
  11736. [4013, 4023, 4040, 4041, 4043],
  11737. [4010, 4031, 4033, 4042, 4043],
  11738. [4010, 4032, 4033, 4041, 4043],
  11739. [4011, 4030, 4033, 4042, 4043],
  11740. [4011, 4032, 4033, 4040, 4043],
  11741. [4012, 4030, 4033, 4041, 4043],
  11742. [4012, 4031, 4033, 4040, 4043],
  11743. [4013, 4030, 4033, 4040, 4043],
  11744. [4010, 4030, 4033, 4042, 4043],
  11745. [4010, 4031, 4033, 4041, 4043],
  11746. [4010, 4032, 4033, 4040, 4043],
  11747. [4011, 4030, 4033, 4041, 4043],
  11748. [4011, 4031, 4033, 4040, 4043],
  11749. [4012, 4030, 4033, 4040, 4043],
  11750. [4010, 4030, 4033, 4041, 4043],
  11751. [4010, 4031, 4033, 4040, 4043],
  11752. [4011, 4030, 4033, 4040, 4043],
  11753. [4003, 4032, 4033, 4042, 4043],
  11754. [4002, 4032, 4033, 4042, 4043],
  11755. [4003, 4032, 4033, 4041, 4043],
  11756. [4013, 4031, 4032, 4033, 4043],
  11757. [4001, 4032, 4033, 4042, 4043],
  11758. [4002, 4032, 4033, 4041, 4043],
  11759. [4003, 4030, 4033, 4042, 4043],
  11760. [4003, 4032, 4033, 4040, 4043],
  11761. [4013, 4030, 4032, 4033, 4043],
  11762. [4003, 4023, 4040, 4042, 4043],
  11763. [4000, 4032, 4033, 4042, 4043],
  11764. [4001, 4032, 4033, 4041, 4043],
  11765. [4002, 4030, 4033, 4042, 4043],
  11766. [4002, 4032, 4033, 4040, 4043],
  11767. [4003, 4030, 4033, 4041, 4043],
  11768. [4003, 4031, 4033, 4040, 4043],
  11769. [4020, 4022, 4023, 4042, 4043],
  11770. [4013, 4030, 4031, 4033, 4043],
  11771. [4003, 4023, 4040, 4041, 4043],
  11772. [4000, 4031, 4033, 4042, 4043],
  11773. [4000, 4032, 4033, 4041, 4043],
  11774. [4001, 4030, 4033, 4042, 4043],
  11775. [4001, 4032, 4033, 4040, 4043],
  11776. [4002, 4030, 4033, 4041, 4043],
  11777. [4002, 4031, 4033, 4040, 4043],
  11778. [4003, 4030, 4033, 4040, 4043],
  11779. [4021, 4022, 4023, 4040, 4043],
  11780. [4020, 4022, 4023, 4041, 4043],
  11781. [4020, 4021, 4023, 4042, 4043],
  11782. [4023, 4030, 4031, 4032, 4033],
  11783. [4000, 4030, 4033, 4042, 4043],
  11784. [4000, 4031, 4033, 4041, 4043],
  11785. [4000, 4032, 4033, 4040, 4043],
  11786. [4001, 4030, 4033, 4041, 4043],
  11787. [4001, 4031, 4033, 4040, 4043],
  11788. [4002, 4030, 4033, 4040, 4043],
  11789. [4020, 4022, 4023, 4040, 4043],
  11790. [4020, 4021, 4023, 4041, 4043],
  11791. [4022, 4030, 4031, 4032, 4033],
  11792. [4000, 4030, 4033, 4041, 4043],
  11793. [4000, 4031, 4033, 4040, 4043],
  11794. [4001, 4030, 4033, 4040, 4043],
  11795. [4020, 4021, 4023, 4040, 4043],
  11796. [4021, 4030, 4031, 4032, 4033],
  11797. [4020, 4030, 4031, 4032, 4033],
  11798. [4003, 4031, 4032, 4033, 4043],
  11799. [4020, 4022, 4023, 4033, 4043],
  11800. [4003, 4030, 4032, 4033, 4043],
  11801. [4003, 4013, 4040, 4042, 4043],
  11802. [4020, 4021, 4023, 4033, 4043],
  11803. [4003, 4030, 4031, 4033, 4043],
  11804. [4003, 4013, 4040, 4041, 4043],
  11805. [4013, 4030, 4031, 4032, 4033],
  11806. [4012, 4030, 4031, 4032, 4033],
  11807. [4011, 4030, 4031, 4032, 4033],
  11808. [4010, 4030, 4031, 4032, 4033],
  11809. [4013, 4023, 4031, 4032, 4033],
  11810. [4013, 4023, 4030, 4032, 4033],
  11811. [4020, 4022, 4023, 4032, 4033],
  11812. [4013, 4023, 4030, 4031, 4033],
  11813. [4021, 4022, 4023, 4030, 4033],
  11814. [4020, 4022, 4023, 4031, 4033],
  11815. [4020, 4021, 4023, 4032, 4033],
  11816. [4020, 4021, 4022, 4023, 4043],
  11817. [4003, 4030, 4031, 4032, 4033],
  11818. [4020, 4022, 4023, 4030, 4033],
  11819. [4020, 4021, 4023, 4031, 4033],
  11820. [4020, 4021, 4022, 4023, 4042],
  11821. [4002, 4030, 4031, 4032, 4033],
  11822. [4020, 4021, 4023, 4030, 4033],
  11823. [4020, 4021, 4022, 4023, 4041],
  11824. [4001, 4030, 4031, 4032, 4033],
  11825. [4020, 4021, 4022, 4023, 4040],
  11826. [4000, 4030, 4031, 4032, 4033],
  11827. [4003, 4023, 4031, 4032, 4033],
  11828. [4013, 4020, 4022, 4023, 4043],
  11829. [4003, 4023, 4030, 4032, 4033],
  11830. [4010, 4012, 4013, 4042, 4043],
  11831. [4013, 4020, 4021, 4023, 4043],
  11832. [4003, 4023, 4030, 4031, 4033],
  11833. [4011, 4012, 4013, 4040, 4043],
  11834. [4010, 4012, 4013, 4041, 4043],
  11835. [4010, 4011, 4013, 4042, 4043],
  11836. [4020, 4021, 4022, 4023, 4033],
  11837. [4010, 4012, 4013, 4040, 4043],
  11838. [4010, 4011, 4013, 4041, 4043],
  11839. [4020, 4021, 4022, 4023, 4032],
  11840. [4010, 4011, 4013, 4040, 4043],
  11841. [4020, 4021, 4022, 4023, 4031],
  11842. [4020, 4021, 4022, 4023, 4030],
  11843. [4003, 4013, 4031, 4032, 4033],
  11844. [4010, 4012, 4013, 4033, 4043],
  11845. [4003, 4020, 4022, 4023, 4043],
  11846. [4013, 4020, 4022, 4023, 4033],
  11847. [4003, 4013, 4030, 4032, 4033],
  11848. [4010, 4011, 4013, 4033, 4043],
  11849. [4003, 4020, 4021, 4023, 4043],
  11850. [4013, 4020, 4021, 4023, 4033],
  11851. [4003, 4013, 4030, 4031, 4033],
  11852. [4010, 4012, 4013, 4023, 4043],
  11853. [4003, 4020, 4022, 4023, 4033],
  11854. [4010, 4012, 4013, 4032, 4033],
  11855. [4010, 4011, 4013, 4023, 4043],
  11856. [4003, 4020, 4021, 4023, 4033],
  11857. [4011, 4012, 4013, 4030, 4033],
  11858. [4010, 4012, 4013, 4031, 4033],
  11859. [4010, 4011, 4013, 4032, 4033],
  11860. [4013, 4020, 4021, 4022, 4023],
  11861. [4010, 4012, 4013, 4030, 4033],
  11862. [4010, 4011, 4013, 4031, 4033],
  11863. [4012, 4020, 4021, 4022, 4023],
  11864. [4010, 4011, 4013, 4030, 4033],
  11865. [4011, 4020, 4021, 4022, 4023],
  11866. [4010, 4020, 4021, 4022, 4023],
  11867. [4010, 4012, 4013, 4023, 4033],
  11868. [4000, 4002, 4003, 4042, 4043],
  11869. [4010, 4011, 4013, 4023, 4033],
  11870. [4001, 4002, 4003, 4040, 4043],
  11871. [4000, 4002, 4003, 4041, 4043],
  11872. [4000, 4001, 4003, 4042, 4043],
  11873. [4010, 4011, 4012, 4013, 4043],
  11874. [4003, 4020, 4021, 4022, 4023],
  11875. [4000, 4002, 4003, 4040, 4043],
  11876. [4000, 4001, 4003, 4041, 4043],
  11877. [4010, 4011, 4012, 4013, 4042],
  11878. [4002, 4020, 4021, 4022, 4023],
  11879. [4000, 4001, 4003, 4040, 4043],
  11880. [4010, 4011, 4012, 4013, 4041],
  11881. [4001, 4020, 4021, 4022, 4023],
  11882. [4010, 4011, 4012, 4013, 4040],
  11883. [4000, 4020, 4021, 4022, 4023],
  11884. [4001, 4002, 4003, 4033, 4043],
  11885. [4000, 4002, 4003, 4033, 4043],
  11886. [4003, 4010, 4012, 4013, 4043],
  11887. [4003, 4013, 4020, 4022, 4023],
  11888. [4000, 4001, 4003, 4033, 4043],
  11889. [4003, 4010, 4011, 4013, 4043],
  11890. [4003, 4013, 4020, 4021, 4023],
  11891. [4010, 4011, 4012, 4013, 4033],
  11892. [4010, 4011, 4012, 4013, 4032],
  11893. [4010, 4011, 4012, 4013, 4031],
  11894. [4010, 4011, 4012, 4013, 4030],
  11895. [4001, 4002, 4003, 4023, 4043],
  11896. [4000, 4002, 4003, 4023, 4043],
  11897. [4003, 4010, 4012, 4013, 4033],
  11898. [4000, 4002, 4003, 4032, 4033],
  11899. [4000, 4001, 4003, 4023, 4043],
  11900. [4003, 4010, 4011, 4013, 4033],
  11901. [4001, 4002, 4003, 4030, 4033],
  11902. [4000, 4002, 4003, 4031, 4033],
  11903. [4000, 4001, 4003, 4032, 4033],
  11904. [4010, 4011, 4012, 4013, 4023],
  11905. [4000, 4002, 4003, 4030, 4033],
  11906. [4000, 4001, 4003, 4031, 4033],
  11907. [4010, 4011, 4012, 4013, 4022],
  11908. [4000, 4001, 4003, 4030, 4033],
  11909. [4010, 4011, 4012, 4013, 4021],
  11910. [4010, 4011, 4012, 4013, 4020],
  11911. [4001, 4002, 4003, 4013, 4043],
  11912. [4001, 4002, 4003, 4023, 4033],
  11913. [4000, 4002, 4003, 4013, 4043],
  11914. [4000, 4002, 4003, 4023, 4033],
  11915. [4003, 4010, 4012, 4013, 4023],
  11916. [4000, 4001, 4003, 4013, 4043],
  11917. [4000, 4001, 4003, 4023, 4033],
  11918. [4003, 4010, 4011, 4013, 4023],
  11919. [4001, 4002, 4003, 4013, 4033],
  11920. [4000, 4002, 4003, 4013, 4033],
  11921. [4000, 4001, 4003, 4013, 4033],
  11922. [4000, 4001, 4002, 4003, 4043],
  11923. [4003, 4010, 4011, 4012, 4013],
  11924. [4000, 4001, 4002, 4003, 4042],
  11925. [4002, 4010, 4011, 4012, 4013],
  11926. [4000, 4001, 4002, 4003, 4041],
  11927. [4001, 4010, 4011, 4012, 4013],
  11928. [4000, 4001, 4002, 4003, 4040],
  11929. [4000, 4010, 4011, 4012, 4013],
  11930. [4001, 4002, 4003, 4013, 4023],
  11931. [4000, 4002, 4003, 4013, 4023],
  11932. [4000, 4001, 4003, 4013, 4023],
  11933. [4000, 4001, 4002, 4003, 4033],
  11934. [4000, 4001, 4002, 4003, 4032],
  11935. [4000, 4001, 4002, 4003, 4031],
  11936. [4000, 4001, 4002, 4003, 4030],
  11937. [4000, 4001, 4002, 4003, 4023],
  11938. [4000, 4001, 4002, 4003, 4022],
  11939. [4000, 4001, 4002, 4003, 4021],
  11940. [4000, 4001, 4002, 4003, 4020],
  11941. [4000, 4001, 4002, 4003, 4013],
  11942. [4000, 4001, 4002, 4003, 4012],
  11943. [4000, 4001, 4002, 4003, 4011],
  11944. [4000, 4001, 4002, 4003, 4010],
  11945. ].filter((p) => p.includes(this.mandatoryId));
  11946.  
  11947. const bestPack = {
  11948. pack: packs[0],
  11949. winRate: 0,
  11950. countBattle: 0,
  11951. id: 0,
  11952. };
  11953.  
  11954. for (const id in packs) {
  11955. const pack = packs[id];
  11956. const attackers = this.maxUpgrade.filter((e) => pack.includes(e.id)).reduce((obj, e) => ({ ...obj, [e.id]: e }), {});
  11957. const battle = {
  11958. attackers,
  11959. defenders: [enemieHeroes],
  11960. type: 'brawl_titan',
  11961. };
  11962. const isRandom = this.isRandomBattle(battle);
  11963. const stat = {
  11964. count: 0,
  11965. win: 0,
  11966. winRate: 0,
  11967. };
  11968. for (let i = 1; i <= 20; i++) {
  11969. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  11970. const result = await Calc(battle);
  11971. stat.win += result.result.win;
  11972. stat.count += 1;
  11973. stat.winRate = stat.win / stat.count;
  11974. if (!isRandom || (i >= 2 && stat.winRate < 0.65) || (i >= 10 && stat.winRate == 1)) {
  11975. break;
  11976. }
  11977. }
  11978.  
  11979. if (!isRandom && stat.win) {
  11980. return {
  11981. favor: {},
  11982. heroes: pack,
  11983. };
  11984. }
  11985. if (stat.winRate > 0.85) {
  11986. return {
  11987. favor: {},
  11988. heroes: pack,
  11989. };
  11990. }
  11991. if (stat.winRate > bestPack.winRate) {
  11992. bestPack.countBattle = stat.count;
  11993. bestPack.winRate = stat.winRate;
  11994. bestPack.pack = pack;
  11995. bestPack.id = id;
  11996. }
  11997. }
  11998.  
  11999. //console.log(bestPack.id, bestPack.pack, bestPack.winRate, bestPack.countBattle);
  12000. return {
  12001. favor: {},
  12002. heroes: bestPack.pack,
  12003. };
  12004. }
  12005.  
  12006. isRandomPack(pack) {
  12007. const ids = Object.keys(pack);
  12008. return ids.includes('4023') || ids.includes('4021');
  12009. }
  12010.  
  12011. isRandomBattle(battle) {
  12012. return this.isRandomPack(battle.attackers) || this.isRandomPack(battle.defenders[0]);
  12013. }
  12014.  
  12015. async updateHeroesPack(enemieHeroes) {
  12016. 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}}}];
  12017.  
  12018. const bestPack = {
  12019. pack: packs[0],
  12020. countWin: 0,
  12021. }
  12022.  
  12023. for (const pack of packs) {
  12024. const attackers = pack.attackers;
  12025. const battle = {
  12026. attackers,
  12027. defenders: [enemieHeroes],
  12028. type: 'brawl',
  12029. };
  12030.  
  12031. let countWinBattles = 0;
  12032. let countTestBattle = 10;
  12033. for (let i = 0; i < countTestBattle; i++) {
  12034. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  12035. const result = await Calc(battle);
  12036. if (result.result.win) {
  12037. countWinBattles++;
  12038. }
  12039. if (countWinBattles > 7) {
  12040. console.log(pack)
  12041. return pack.args;
  12042. }
  12043. }
  12044. if (countWinBattles > bestPack.countWin) {
  12045. bestPack.countWin = countWinBattles;
  12046. bestPack.pack = pack.args;
  12047. }
  12048. }
  12049.  
  12050. console.log(bestPack);
  12051. return bestPack.pack;
  12052. }
  12053.  
  12054. async questFarm() {
  12055. const calls = [this.callBrawlQuestFarm];
  12056. const result = await Send(JSON.stringify({ calls }));
  12057. return result.results[0].result.response;
  12058. }
  12059.  
  12060. async getBrawlInfo() {
  12061. const data = await Send(JSON.stringify({
  12062. calls: [
  12063. this.callUserGetInfo,
  12064. this.callBrawlQuestGetInfo,
  12065. this.callBrawlFindEnemies,
  12066. this.callTeamGetMaxUpgrade,
  12067. this.callBrawlGetInfo,
  12068. ]
  12069. }));
  12070.  
  12071. let attempts = data.results[0].result.response.refillable.find(n => n.id == 48);
  12072.  
  12073. const maxUpgrade = data.results[3].result.response;
  12074. const maxHero = Object.values(maxUpgrade.hero);
  12075. const maxTitan = Object.values(maxUpgrade.titan);
  12076. const maxPet = Object.values(maxUpgrade.pet);
  12077. this.maxUpgrade = [...maxHero, ...maxPet, ...maxTitan];
  12078.  
  12079. this.info = data.results[4].result.response;
  12080. this.mandatoryId = lib.data.brawl.promoHero[this.info.id].promoHero;
  12081. return {
  12082. attempts: attempts.amount,
  12083. questInfo: data.results[1].result.response,
  12084. findEnemies: data.results[2].result.response,
  12085. }
  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 result = await Calc(battle);
  12097. console.log(result.result);
  12098. if (result.result.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(result);
  12107. // return await this.cancelBattle(result);
  12108. }
  12109.  
  12110. /**
  12111. * Starts a fight
  12112. *
  12113. * Начинает бой
  12114. */
  12115. async startBattle(userId, args) {
  12116. const call = {
  12117. name: "brawl_startBattle",
  12118. args,
  12119. ident: "brawl_startBattle"
  12120. }
  12121. call.args.userId = userId;
  12122. const calls = [call];
  12123. const result = await Send(JSON.stringify({ calls }));
  12124. return result.results[0].result.response;
  12125. }
  12126.  
  12127. cancelBattle(battle) {
  12128. const fixBattle = function (heroes) {
  12129. for (const ids in heroes) {
  12130. const hero = heroes[ids];
  12131. hero.energy = random(1, 999);
  12132. if (hero.hp > 0) {
  12133. hero.hp = random(1, hero.hp);
  12134. }
  12135. }
  12136. }
  12137. fixBattle(battle.progress[0].attackers.heroes);
  12138. fixBattle(battle.progress[0].defenders.heroes);
  12139. return this.endBattle(battle);
  12140. }
  12141.  
  12142. /**
  12143. * Ends the fight
  12144. *
  12145. * Заканчивает бой
  12146. */
  12147. async endBattle(battle) {
  12148. battle.progress[0].attackers.input = ['auto', 0, 0, 'auto', 0, 0];
  12149. const calls = [{
  12150. name: "brawl_endBattle",
  12151. args: {
  12152. result: battle.result,
  12153. progress: battle.progress
  12154. },
  12155. ident: "brawl_endBattle"
  12156. },
  12157. this.callBrawlQuestGetInfo,
  12158. this.callBrawlFindEnemies,
  12159. ];
  12160. const result = await Send(JSON.stringify({ calls }));
  12161. return result.results;
  12162. }
  12163.  
  12164. end(endReason) {
  12165. isCancalBattle = true;
  12166. isBrawlsAutoStart = false;
  12167. setProgress(endReason, true);
  12168. console.log(endReason);
  12169. this.resolve();
  12170. }
  12171. }
  12172.  
  12173. })();
  12174.  
  12175. /**
  12176. * TODO:
  12177. * Получение всех уровней при сборе всех наград (квест на титанит и на энку) +-
  12178. * Добивание на арене титанов
  12179. * Закрытие окошек по Esc +-
  12180. * Починить работу скрипта на уровне команды ниже 10 +-
  12181. * Написать номальную синхронизацию
  12182. * Запрет сбора квестов и отправки экспеиций в промежуток между локальным обновлением и глобальным обновлением дня
  12183. * Улучшение боев
  12184. */