HeroWarsDungeon

Automation of actions for the game Hero Wars

  1. // ==UserScript==
  2. // @name HeroWarsDungeon
  3. // @name:en HeroWarsDungeon
  4. // @name:ru HeroWarsDungeon
  5. // @namespace HeroWarsDungeon
  6. // @version 2.312.1
  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, ApuoH, Gudwin
  11. // @license Copyright ZingerY
  12. // @icon http://ilovemycomp.narod.ru/VaultBoyIco16.ico
  13. // @icon64 http://ilovemycomp.narod.ru/VaultBoyIco64.png
  14. // @match https://www.hero-wars.com/*
  15. // @match https://apps-1701433570146040.apps.fbsbx.com/*
  16. // @run-at document-start
  17. // ==/UserScript==
  18.  
  19. // сделал ApuoH
  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. let repleyBattle = {
  68. defenders: {},
  69. attackers: {},
  70. effects: {},
  71. state: {},
  72. seed: undefined
  73. }
  74. /**
  75. * User data
  76. *
  77. * Данные пользователя
  78. */
  79. let userInfo;
  80. this.isTimeBetweenNewDays = function () {
  81. if (userInfo.timeZone <= 3) {
  82. return false;
  83. }
  84. const nextDayTs = new Date(userInfo.nextDayTs * 1e3);
  85. const nextServerDayTs = new Date(userInfo.nextServerDayTs * 1e3);
  86. if (nextDayTs > nextServerDayTs) {
  87. nextDayTs.setDate(nextDayTs.getDate() - 1);
  88. }
  89. const now = Date.now();
  90. if (now > nextDayTs && now < nextServerDayTs) {
  91. return true;
  92. }
  93. return false;
  94. };
  95. /**
  96. * Original methods for working with AJAX
  97. *
  98. * Оригинальные методы для работы с AJAX
  99. */
  100. const original = {
  101. open: XMLHttpRequest.prototype.open,
  102. send: XMLHttpRequest.prototype.send,
  103. setRequestHeader: XMLHttpRequest.prototype.setRequestHeader,
  104. SendWebSocket: WebSocket.prototype.send,
  105. fetch: fetch,
  106. };
  107.  
  108. // Sentry blocking
  109. // Блокировка наблюдателя
  110. this.fetch = function (url, options) {
  111. /**
  112. * Checking URL for blocking
  113. * Проверяем URL на блокировку
  114. */
  115. if (url.includes('sentry.io')) {
  116. console.log('%cFetch blocked', 'color: red');
  117. console.log(url, options);
  118. const body = {
  119. id: md5(Date.now()),
  120. };
  121. let info = {};
  122. try {
  123. info = JSON.parse(options.body);
  124. } catch (e) {}
  125. if (info.event_id) {
  126. body.id = info.event_id;
  127. }
  128. /**
  129. * Mock response for blocked URL
  130. *
  131. * Мокаем ответ для заблокированного URL
  132. */
  133. const mockResponse = new Response('Custom blocked response', {
  134. status: 200,
  135. headers: { 'Content-Type': 'application/json' },
  136. body,
  137. });
  138. return Promise.resolve(mockResponse);
  139. } else {
  140. /**
  141. * Call the original fetch function for all other URLs
  142. * Вызываем оригинальную функцию fetch для всех других URL
  143. */
  144. return original.fetch.apply(this, arguments);
  145. }
  146. };
  147.  
  148. /**
  149. * Decoder for converting byte data to JSON string
  150. *
  151. * Декодер для перобразования байтовых данных в JSON строку
  152. */
  153. const decoder = new TextDecoder("utf-8");
  154. /**
  155. * Stores a history of requests
  156. *
  157. * Хранит историю запросов
  158. */
  159. let requestHistory = {};
  160. /**
  161. * URL for API requests
  162. *
  163. * URL для запросов к API
  164. */
  165. let apiUrl = '';
  166.  
  167. /**
  168. * Connecting to the game code
  169. *
  170. * Подключение к коду игры
  171. */
  172. this.cheats = new hackGame();
  173. /**
  174. * The function of calculating the results of the battle
  175. *
  176. * Функция расчета результатов боя
  177. */
  178. this.BattleCalc = cheats.BattleCalc;
  179. /**
  180. * Sending a request available through the console
  181. *
  182. * Отправка запроса доступная через консоль
  183. */
  184. this.SendRequest = send;
  185. /**
  186. * Simple combat calculation available through the console
  187. *
  188. * Простой расчет боя доступный через консоль
  189. */
  190. this.Calc = function (data) {
  191. const type = getBattleType(data?.type);
  192. return new Promise((resolve, reject) => {
  193. try {
  194. BattleCalc(data, type, resolve);
  195. } catch (e) {
  196. reject(e);
  197. }
  198. })
  199. }
  200. //тест остановка подземки
  201. let stopDung = false;
  202. /**
  203. * Short asynchronous request
  204. * Usage example (returns information about a character):
  205. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  206. *
  207. * Короткий асинхронный запрос
  208. * Пример использования (возвращает информацию о персонаже):
  209. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  210. */
  211. this.Send = function (json, pr) {
  212. return new Promise((resolve, reject) => {
  213. try {
  214. send(json, resolve, pr);
  215. } catch (e) {
  216. reject(e);
  217. }
  218. })
  219. }
  220.  
  221. this.xyz = (({ name, version, author }) => ({ name, version, author }))(GM_info.script);
  222. const i18nLangData = {
  223. /* English translation by BaBa */
  224. en: {
  225. /* Checkboxes */
  226. SKIP_FIGHTS: 'Skip battle',
  227. SKIP_FIGHTS_TITLE: 'Skip battle in Outland and the arena of the titans, auto-pass in the tower and campaign',
  228. ENDLESS_CARDS: 'Infinite cards',
  229. ENDLESS_CARDS_TITLE: 'Disable Divination Cards wasting',
  230. AUTO_EXPEDITION: 'Auto Expedition',
  231. AUTO_EXPEDITION_TITLE: 'Auto-sending expeditions',
  232. CANCEL_FIGHT: 'Cancel battle',
  233. CANCEL_FIGHT_TITLE: 'Ability to cancel manual combat on GW, CoW and Asgard',
  234. GIFTS: 'Gifts',
  235. GIFTS_TITLE: 'Collect gifts automatically',
  236. BATTLE_RECALCULATION: 'Battle recalculation',
  237. BATTLE_RECALCULATION_TITLE: 'Preliminary calculation of the battle',
  238. BATTLE_FISHING: 'Finishing',
  239. BATTLE_FISHING_TITLE: 'Finishing off the team from the last replay in the chat',
  240. BATTLE_TRENING: 'Workout',
  241. BATTLE_TRENING_TITLE: 'A training battle in the chat against the team from the last replay',
  242. QUANTITY_CONTROL: 'Quantity control',
  243. QUANTITY_CONTROL_TITLE: 'Ability to specify the number of opened "lootboxes"',
  244. REPEAT_CAMPAIGN: 'Repeat missions',
  245. REPEAT_CAMPAIGN_TITLE: 'Auto-repeat battles in the campaign',
  246. DISABLE_DONAT: 'Disable donation',
  247. DISABLE_DONAT_TITLE: 'Removes all donation offers',
  248. DAILY_QUESTS: 'Quests',
  249. DAILY_QUESTS_TITLE: 'Complete daily quests',
  250. AUTO_QUIZ: 'AutoQuiz',
  251. AUTO_QUIZ_TITLE: 'Automatically receive correct answers to quiz questions',
  252. SECRET_WEALTH_CHECKBOX: 'Automatic purchase in the store "Secret Wealth" when entering the game',
  253. HIDE_SERVERS: 'Collapse servers',
  254. HIDE_SERVERS_TITLE: 'Hide unused servers',
  255. /* Input fields */
  256. HOW_MUCH_TITANITE: 'How much titanite to farm',
  257. COMBAT_SPEED: 'Combat Speed Multiplier',
  258. HOW_REPEAT_CAMPAIGN: 'how many mission replays', //тест добавил
  259. NUMBER_OF_TEST: 'Number of test fights',
  260. NUMBER_OF_AUTO_BATTLE: 'Number of auto-battle attempts',
  261. USER_ID_TITLE: 'Enter the player ID',
  262. AMOUNT: 'Gift number, 1 - hero development, 2 - pets, 3 - light, 4 - darkness, 5 - ascension, 6 - appearance',
  263. GIFT_NUM: 'Number of gifts to be sent',
  264. /* Buttons */
  265. RUN_SCRIPT: 'Run the',
  266. STOP_SCRIPT: 'Stop the',
  267. TO_DO_EVERYTHING: 'Do All',
  268. TO_DO_EVERYTHING_TITLE: 'Perform multiple actions of your choice',
  269. OUTLAND: 'Outland',
  270. OUTLAND_TITLE: 'Collect Outland',
  271. TITAN_ARENA: 'ToE',
  272. TITAN_ARENA_TITLE: 'Complete the titan arena',
  273. DUNGEON: 'Dungeon',
  274. DUNGEON_TITLE: 'Go through the dungeon',
  275. DUNGEON2: 'Dungeon full',
  276. DUNGEON_FULL_TITLE: 'Dungeon for Full Titans',
  277. STOP_DUNGEON: 'Stop Dungeon',
  278. STOP_DUNGEON_TITLE: 'Stop digging the dungeon',
  279. SEER: 'Seer',
  280. SEER_TITLE: 'Roll the Seer',
  281. TOWER: 'Tower',
  282. TOWER_TITLE: 'Pass the tower',
  283. EXPEDITIONS: 'Expeditions',
  284. EXPEDITIONS_TITLE: 'Sending and collecting expeditions',
  285. SYNC: 'Sync',
  286. SYNC_TITLE: 'Partial synchronization of game data without reloading the page',
  287. ARCHDEMON: 'Archdemon',
  288. FURNACE_OF_SOULS: 'Furnace of souls',
  289. ARCHDEMON_TITLE: 'Hitting kills and collecting rewards',
  290. ESTER_EGGS: 'Easter eggs',
  291. ESTER_EGGS_TITLE: 'Collect all Easter eggs or rewards',
  292. REWARDS: 'Rewards',
  293. REWARDS_TITLE: 'Collect all quest rewards',
  294. MAIL: 'Mail',
  295. MAIL_TITLE: 'Collect all mail, except letters with energy and charges of the portal',
  296. MINIONS: 'Minions',
  297. MINIONS_TITLE: 'Attack minions with saved packs',
  298. ADVENTURE: 'Adventure',
  299. ADVENTURE_TITLE: 'Passes the adventure along the specified route',
  300. STORM: 'Storm',
  301. STORM_TITLE: 'Passes the Storm along the specified route',
  302. SANCTUARY: 'Sanctuary',
  303. SANCTUARY_TITLE: 'Fast travel to Sanctuary',
  304. GUILD_WAR: 'Guild War',
  305. GUILD_WAR_TITLE: 'Fast travel to Guild War',
  306. SECRET_WEALTH: 'Secret Wealth',
  307. SECRET_WEALTH_TITLE: 'Buy something in the store "Secret Wealth"',
  308. /* Misc */
  309. BOTTOM_URLS: '<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>',
  310. GIFTS_SENT: 'Gifts sent!',
  311. DO_YOU_WANT: 'Do you really want to do this?',
  312. BTN_RUN: 'Run',
  313. BTN_CANCEL: 'Cancel',
  314. BTN_OK: 'OK',
  315. MSG_HAVE_BEEN_DEFEATED: 'You have been defeated!',
  316. BTN_AUTO: 'Auto',
  317. MSG_YOU_APPLIED: 'You applied',
  318. MSG_DAMAGE: 'damage',
  319. MSG_CANCEL_AND_STAT: 'Auto (F5) and show statistic',
  320. MSG_REPEAT_MISSION: 'Repeat the mission?',
  321. BTN_REPEAT: 'Repeat',
  322. BTN_NO: 'No',
  323. MSG_SPECIFY_QUANT: 'Specify Quantity:',
  324. BTN_OPEN: 'Open',
  325. QUESTION_COPY: 'Question copied to clipboard',
  326. ANSWER_KNOWN: 'The answer is known',
  327. ANSWER_NOT_KNOWN: 'ATTENTION THE ANSWER IS NOT KNOWN',
  328. BEING_RECALC: 'The battle is being recalculated',
  329. THIS_TIME: 'This time',
  330. VICTORY: '<span style="color:green;">VICTORY</span>',
  331. DEFEAT: '<span style="color:red;">DEFEAT</span>',
  332. CHANCE_TO_WIN: 'Chance to win <span style="color: red;">based on pre-calculation</span>',
  333. OPEN_DOLLS: 'nesting dolls recursively',
  334. SENT_QUESTION: 'Question sent',
  335. SETTINGS: 'Settings',
  336. MSG_BAN_ATTENTION: '<p style="color:red;">Using this feature may result in a ban.</p> Continue?',
  337. BTN_YES_I_AGREE: 'Yes, I understand the risks!',
  338. BTN_NO_I_AM_AGAINST: 'No, I refuse it!',
  339. VALUES: 'Values',
  340. SAVING: 'Saving',
  341. USER_ID: 'User Id',
  342. SEND_GIFT: 'The gift has been sent',
  343. EXPEDITIONS_SENT: 'Expeditions:<br>Collected: {countGet}<br>Sent: {countSend}',
  344. EXPEDITIONS_NOTHING: 'Nothing to collect/send',
  345. TITANIT: 'Titanit',
  346. COMPLETED: 'completed',
  347. FLOOR: 'Floor',
  348. LEVEL: 'Level',
  349. BATTLES: 'battles',
  350. EVENT: 'Event',
  351. NOT_AVAILABLE: 'not available',
  352. NO_HEROES: 'No heroes',
  353. DAMAGE_AMOUNT: 'Damage amount',
  354. NOTHING_TO_COLLECT: 'Nothing to collect',
  355. COLLECTED: 'Collected',
  356. REWARD: 'rewards',
  357. REMAINING_ATTEMPTS: 'Remaining attempts',
  358. BATTLES_CANCELED: 'Battles canceled',
  359. MINION_RAID: 'Minion Raid',
  360. STOPPED: 'Stopped',
  361. REPETITIONS: 'Repetitions',
  362. MISSIONS_PASSED: 'Missions passed',
  363. STOP: 'stop',
  364. TOTAL_OPEN: 'Total open',
  365. OPEN: 'Open',
  366. ROUND_STAT: 'Damage statistics for ',
  367. BATTLE: 'battles',
  368. MINIMUM: 'Minimum',
  369. MAXIMUM: 'Maximum',
  370. AVERAGE: 'Average',
  371. NOT_THIS_TIME: 'Not this time',
  372. RETRY_LIMIT_EXCEEDED: 'Retry limit exceeded',
  373. SUCCESS: 'Success',
  374. RECEIVED: 'Received',
  375. LETTERS: 'letters',
  376. PORTALS: 'portals',
  377. ATTEMPTS: 'attempts',
  378. /* Quests */
  379. QUEST_10001: 'Upgrade the skills of heroes 3 times',
  380. QUEST_10002: 'Complete 10 missions',
  381. QUEST_10003: 'Complete 3 heroic missions',
  382. QUEST_10004: 'Fight 3 times in the Arena or Grand Arena',
  383. QUEST_10006: 'Use the exchange of emeralds 1 time',
  384. QUEST_10007: 'Perform 1 summon in the Solu Atrium',
  385. QUEST_10016: 'Send gifts to guildmates',
  386. QUEST_10018: 'Use an experience potion',
  387. QUEST_10019: 'Open 1 chest in the Tower',
  388. QUEST_10020: 'Open 3 chests in Outland',
  389. QUEST_10021: 'Collect 75 Titanite in the Guild Dungeon',
  390. QUEST_10021: 'Collect 150 Titanite in the Guild Dungeon',
  391. QUEST_10023: 'Upgrade Gift of the Elements by 1 level',
  392. QUEST_10024: 'Level up any artifact once',
  393. QUEST_10025: 'Start Expedition 1',
  394. QUEST_10026: 'Start 4 Expeditions',
  395. QUEST_10027: 'Win 1 battle of the Tournament of Elements',
  396. QUEST_10028: 'Level up any titan artifact',
  397. QUEST_10029: 'Unlock the Orb of Titan Artifacts',
  398. QUEST_10030: 'Upgrade any Skin of any hero 1 time',
  399. QUEST_10031: 'Win 6 battles of the Tournament of Elements',
  400. QUEST_10043: 'Start or Join an Adventure',
  401. QUEST_10044: 'Use Summon Pets 1 time',
  402. QUEST_10046: 'Open 3 chests in Adventure',
  403. QUEST_10047: 'Get 150 Guild Activity Points',
  404. NOTHING_TO_DO: 'Nothing to do',
  405. YOU_CAN_COMPLETE: 'You can complete quests',
  406. BTN_DO_IT: 'Do it',
  407. NOT_QUEST_COMPLETED: 'Not a single quest completed',
  408. COMPLETED_QUESTS: 'Completed quests',
  409. /* everything button */
  410. ASSEMBLE_OUTLAND: 'Assemble Outland',
  411. PASS_THE_TOWER: 'Pass the tower',
  412. CHECK_EXPEDITIONS: 'Check Expeditions',
  413. COMPLETE_TOE: 'Complete ToE',
  414. COMPLETE_DUNGEON: 'Complete the dungeon',
  415. COMPLETE_DUNGEON_FULL: 'Complete the dungeon for Full Titans',
  416. COLLECT_MAIL: 'Collect mail',
  417. COLLECT_MISC: 'Collect some bullshit',
  418. COLLECT_MISC_TITLE: 'Collect Easter Eggs, Skin Gems, Keys, Arena Coins and Soul Crystal',
  419. COLLECT_QUEST_REWARDS: 'Collect quest rewards',
  420. MAKE_A_SYNC: 'Make a sync',
  421.  
  422. RUN_FUNCTION: 'Run the following functions?',
  423. BTN_GO: 'Go!',
  424. PERFORMED: 'Performed',
  425. DONE: 'Done',
  426. ERRORS_OCCURRES: 'Errors occurred while executing',
  427. COPY_ERROR: 'Copy error information to clipboard',
  428. BTN_YES: 'Yes',
  429. ALL_TASK_COMPLETED: 'All tasks completed',
  430.  
  431. UNKNOWN: 'unknown',
  432. ENTER_THE_PATH: 'Enter the path of adventure using commas or dashes',
  433. START_ADVENTURE: 'Start your adventure along this path!',
  434. INCORRECT_WAY: 'Incorrect path in adventure: {from} -> {to}',
  435. BTN_CANCELED: 'Canceled',
  436. MUST_TWO_POINTS: 'The path must contain at least 2 points.',
  437. MUST_ONLY_NUMBERS: 'The path must contain only numbers and commas',
  438. NOT_ON_AN_ADVENTURE: 'You are not on an adventure',
  439. YOU_IN_NOT_ON_THE_WAY: 'Your location is not on the way',
  440. ATTEMPTS_NOT_ENOUGH: 'Your attempts are not enough to complete the path, continue?',
  441. YES_CONTINUE: 'Yes, continue!',
  442. NOT_ENOUGH_AP: 'Not enough action points',
  443. ATTEMPTS_ARE_OVER: 'The attempts are over',
  444. MOVES: 'Moves',
  445. BUFF_GET_ERROR: 'Buff getting error',
  446. BATTLE_END_ERROR: 'Battle end error',
  447. AUTOBOT: 'Autobot',
  448. FAILED_TO_WIN_AUTO: 'Failed to win the auto battle',
  449. ERROR_OF_THE_BATTLE_COPY: 'An error occurred during the passage of the battle<br>Copy the error to the clipboard?',
  450. ERROR_DURING_THE_BATTLE: 'Error during the battle',
  451. NO_CHANCE_WIN: 'No chance of winning this fight: 0/',
  452. LOST_HEROES: 'You have won, but you have lost one or several heroes',
  453. VICTORY_IMPOSSIBLE: 'Is victory impossible, should we focus on the result?',
  454. FIND_COEFF: 'Find the coefficient greater than',
  455. BTN_PASS: 'PASS',
  456. BRAWLS: 'Brawls',
  457. BRAWLS_TITLE: 'Activates the ability to auto-brawl',
  458. START_AUTO_BRAWLS: 'Start Auto Brawls?',
  459. LOSSES: 'Losses',
  460. WINS: 'Wins',
  461. FIGHTS: 'Fights',
  462. STAGE: 'Stage',
  463. DONT_HAVE_LIVES: "You don't have lives",
  464. LIVES: 'Lives',
  465. SECRET_WEALTH_ALREADY: 'Item for Pet Potions already purchased',
  466. SECRET_WEALTH_NOT_ENOUGH: 'Not Enough Pet Potion, You Have {available}, Need {need}',
  467. SECRET_WEALTH_UPGRADE_NEW_PET: 'After purchasing the Pet Potion, it will not be enough to upgrade a new pet',
  468. SECRET_WEALTH_PURCHASED: 'Purchased {count} {name}',
  469. SECRET_WEALTH_CANCELED: 'Secret Wealth: Purchase Canceled',
  470. SECRET_WEALTH_BUY: 'You have {available} Pet Potion.<br>Do you want to buy {countBuy} {name} for {price} Pet Potion?',
  471. DAILY_BONUS: 'Daily bonus',
  472. DO_DAILY_QUESTS: 'Do daily quests',
  473. ACTIONS: 'Actions',
  474. ACTIONS_TITLE: 'Dialog box with various actions',
  475. OTHERS: 'Others',
  476. OTHERS_TITLE: 'Others',
  477. CHOOSE_ACTION: 'Choose an action',
  478. OPEN_LOOTBOX: 'You have {lootBox} boxes, should we open them?',
  479. STAMINA: 'Energy',
  480. BOXES_OVER: 'The boxes are over',
  481. NO_BOXES: 'No boxes',
  482. NO_MORE_ACTIVITY: 'No more activity for items today',
  483. EXCHANGE_ITEMS: 'Exchange items for activity points (max {maxActive})?',
  484. GET_ACTIVITY: 'Get Activity',
  485. NOT_ENOUGH_ITEMS: 'Not enough items',
  486. ACTIVITY_RECEIVED: 'Activity received',
  487. NO_PURCHASABLE_HERO_SOULS: 'No purchasable Hero Souls',
  488. PURCHASED_HERO_SOULS: 'Purchased {countHeroSouls} Hero Souls',
  489. NOT_ENOUGH_EMERALDS_540: 'Not enough emeralds, you need {imgEmerald}540 you have {imgEmerald}{currentStarMoney}',
  490. BUY_OUTLAND_BTN: 'Buy {count} chests {imgEmerald}{countEmerald}',
  491. CHESTS_NOT_AVAILABLE: 'Chests not available',
  492. OUTLAND_CHESTS_RECEIVED: 'Outland chests received',
  493. RAID_NOT_AVAILABLE: 'The raid is not available or there are no spheres',
  494. RAID_ADVENTURE: 'Raid {adventureId} adventure!',
  495. SOMETHING_WENT_WRONG: 'Something went wrong',
  496. ADVENTURE_COMPLETED: 'Adventure {adventureId} completed {times} times',
  497. CLAN_STAT_COPY: 'Clan statistics copied to clipboard',
  498. GET_ENERGY: 'Get Energy',
  499. GET_ENERGY_TITLE: 'Opens platinum boxes one at a time until you get 250 energy',
  500. ITEM_EXCHANGE: 'Item Exchange',
  501. ITEM_EXCHANGE_TITLE: 'Exchanges items for the specified amount of activity',
  502. BUY_SOULS: 'Buy souls',
  503. BUY_SOULS_TITLE: 'Buy hero souls from all available shops',
  504. BUY_OUTLAND: 'Buy Outland',
  505. BUY_OUTLAND_TITLE: 'Buy 9 chests in Outland for 540 emeralds',
  506. RAID: 'Raid',
  507. AUTO_RAID_ADVENTURE: 'Raid adventure',
  508. AUTO_RAID_ADVENTURE_TITLE: 'Raid adventure set number of times',
  509. CLAN_STAT: 'Clan statistics',
  510. CLAN_STAT_TITLE: 'Copies clan statistics to the clipboard',
  511. BTN_AUTO_F5: 'Auto (F5)',
  512. BOSS_DAMAGE: 'Boss Damage: ',
  513. NOTHING_BUY: 'Nothing to buy',
  514. LOTS_BOUGHT: '{countBuy} lots bought for gold',
  515. BUY_FOR_GOLD: 'Buy for gold',
  516. BUY_FOR_GOLD_TITLE: 'Buy items for gold in the Town Shop and in the Pet Soul Stone Shop',
  517. REWARDS_AND_MAIL: 'Rewards and Mail',
  518. REWARDS_AND_MAIL_TITLE: 'Collects rewards and mail',
  519. New_Year_Clan: 'a gift for a friend',
  520. New_Year_Clan_TITLE: 'New Year gifts to friends',
  521. COLLECT_REWARDS_AND_MAIL: 'Collected {countQuests} rewards and {countMail} letters',
  522. TIMER_ALREADY: 'Timer already started {time}',
  523. NO_ATTEMPTS_TIMER_START: 'No attempts, timer started {time}',
  524. EPIC_BRAWL_RESULT: 'Wins: {wins}/{attempts}, Coins: {coins}, Streak: {progress}/{nextStage} [Close]{end}',
  525. ATTEMPT_ENDED: '<br>Attempts ended, timer started {time}',
  526. EPIC_BRAWL: 'Cosmic Battle',
  527. EPIC_BRAWL_TITLE: 'Spends attempts in the Cosmic Battle',
  528. RELOAD_GAME: 'Reload game',
  529. TIMER: 'Timer:',
  530. SHOW_ERRORS: 'Show errors',
  531. SHOW_ERRORS_TITLE: 'Show server request errors',
  532. ERROR_MSG: 'Error: {name}<br>{description}',
  533. EVENT_AUTO_BOSS: '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?',
  534. BEST_SLOW: 'Best (slower)',
  535. FIRST_FAST: 'First (faster)',
  536. FREEZE_INTERFACE: 'Calculating... <br>The interface may freeze.',
  537. ERROR_F12: 'Error, details in the console (F12)',
  538. FAILED_FIND_WIN_PACK: 'Failed to find a winning pack',
  539. BEST_PACK: 'Best pack:',
  540. BOSS_HAS_BEEN_DEF: 'Boss {bossLvl} has been defeated.',
  541. NOT_ENOUGH_ATTEMPTS_BOSS: 'Not enough attempts to defeat boss {bossLvl}, retry?',
  542. BOSS_VICTORY_IMPOSSIBLE: '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?',
  543. BOSS_HAS_BEEN_DEF_TEXT: 'Boss {bossLvl} defeated in<br>{countBattle}/{countMaxBattle} attempts{winTimer}<br>(Please synchronize or restart the game to update the data)',
  544. MAP: 'Map: ',
  545. PLAYER_POS: 'Player positions:',
  546. NY_GIFTS: 'Gifts',
  547. NY_GIFTS_TITLE: "Open all New Year's gifts",
  548. NY_NO_GIFTS: 'No gifts not received',
  549. NY_GIFTS_COLLECTED: '{count} gifts collected',
  550. CHANGE_MAP: 'Island map',
  551. CHANGE_MAP_TITLE: 'Change island map',
  552. SELECT_ISLAND_MAP: 'Select an island map:',
  553. MAP_NUM: 'Map {num}',
  554. SECRET_WEALTH_SHOP: 'Secret Wealth {name}: ',
  555. SHOPS: 'Shops',
  556. SHOPS_DEFAULT: 'Default',
  557. SHOPS_DEFAULT_TITLE: 'Default stores',
  558. SHOPS_LIST: 'Shops {number}',
  559. SHOPS_LIST_TITLE: 'List of shops {number}',
  560. SHOPS_WARNING: '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>',
  561. MINIONS_WARNING: 'The hero packs for attacking minions are incomplete, should I continue?',
  562. FAST_SEASON: 'Fast season',
  563. FAST_SEASON_TITLE: 'Skip the map selection screen in a season',
  564. SET_NUMBER_LEVELS: 'Specify the number of levels:',
  565. POSSIBLE_IMPROVE_LEVELS: 'It is possible to improve only {count} levels.<br>Improving?',
  566. NOT_ENOUGH_RESOURECES: 'Not enough resources',
  567. IMPROVED_LEVELS: 'Improved levels: {count}',
  568. ARTIFACTS_UPGRADE: 'Artifacts Upgrade',
  569. ARTIFACTS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero artifacts',
  570. SKINS_UPGRADE: 'Skins Upgrade',
  571. SKINS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero skins',
  572. HINT: '<br>Hint: ',
  573. PICTURE: '<br>Picture: ',
  574. ANSWER: '<br>Answer: ',
  575. NO_HEROES_PACK: 'Fight at least one battle to save the attacking team',
  576. BRAWL_AUTO_PACK: 'Automatic selection of packs',
  577. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Automatic pack selection is not suitable for the current hero',
  578. BRAWL_DAILY_TASK_COMPLETED: 'Daily task completed, continue attacking?',
  579. CALC_STAT: 'Calculate statistics',
  580. ELEMENT_TOURNAMENT_REWARD: 'Unclaimed bonus for Elemental Tournament',
  581. BTN_TRY_FIX_IT: 'Fix it',
  582. BTN_TRY_FIX_IT_TITLE: 'Enable auto attack combat correction',
  583. DAMAGE_FIXED: 'Damage fixed from {lastDamage} to {maxDamage}!',
  584. DAMAGE_NO_FIXED: 'Failed to fix damage: {lastDamage}',
  585. LETS_FIX: "Let's fix",
  586. COUNT_FIXED: 'For {count} attempts',
  587. DEFEAT_TURN_TIMER: 'Defeat! Turn on the timer to complete the mission?',
  588. SEASON_REWARD: 'Season Rewards',
  589. SEASON_REWARD_TITLE: 'Collects available free rewards from all current seasons',
  590. SEASON_REWARD_COLLECTED: 'Collected {count} season rewards',
  591. SELL_HERO_SOULS: 'Sell ​​souls',
  592. SELL_HERO_SOULS_TITLE: 'Exchanges all absolute star hero souls for gold',
  593. GOLD_RECEIVED: 'Gold received: {gold}',
  594. OPEN_ALL_EQUIP_BOXES: 'Open all Equipment Fragment Box?',
  595. SERVER_NOT_ACCEPT: 'The server did not accept the result',
  596. INVASION_BOSS_BUFF: 'For {bossLvl} boss need buff {needBuff} you have {haveBuff}}',
  597. },
  598. ru: {
  599. /* Чекбоксы */
  600. SKIP_FIGHTS: 'Пропуск боев',
  601. SKIP_FIGHTS_TITLE: 'Пропуск боев в запределье и арене титанов, автопропуск в башне и кампании',
  602. ENDLESS_CARDS: 'Бесконечные карты',
  603. ENDLESS_CARDS_TITLE: 'Отключить трату карт предсказаний',
  604. AUTO_EXPEDITION: 'АвтоЭкспедиции',
  605. AUTO_EXPEDITION_TITLE: 'Автоотправка экспедиций',
  606. CANCEL_FIGHT: 'Отмена боя',
  607. CANCEL_FIGHT_TITLE: 'Возможность отмены ручного боя на ВГ, СМ и в Асгарде',
  608. GIFTS: 'Подарки',
  609. GIFTS_TITLE: 'Собирать подарки автоматически',
  610. BATTLE_RECALCULATION: 'Прерасчет боя',
  611. BATTLE_RECALCULATION_TITLE: 'Предварительный расчет боя',
  612. BATTLE_FISHING: 'Добивание',
  613. BATTLE_FISHING_TITLE: 'Добивание в чате команды из последнего реплея',
  614. BATTLE_TRENING: 'Тренировка',
  615. BATTLE_TRENING_TITLE: 'Тренировочный бой в чате против команды из последнего реплея',
  616. QUANTITY_CONTROL: 'Контроль кол-ва',
  617. QUANTITY_CONTROL_TITLE: 'Возможность указывать количество открываемых "лутбоксов"',
  618. REPEAT_CAMPAIGN: 'Повтор в компании',
  619. REPEAT_CAMPAIGN_TITLE: 'Автоповтор боев в кампании',
  620. DISABLE_DONAT: 'Отключить донат',
  621. DISABLE_DONAT_TITLE: 'Убирает все предложения доната',
  622. DAILY_QUESTS: 'Квесты',
  623. DAILY_QUESTS_TITLE: 'Выполнять ежедневные квесты',
  624. AUTO_QUIZ: 'АвтоВикторина',
  625. AUTO_QUIZ_TITLE: 'Автоматическое получение правильных ответов на вопросы викторины',
  626. SECRET_WEALTH_CHECKBOX: 'Автоматическая покупка в магазине "Тайное Богатство" при заходе в игру',
  627. HIDE_SERVERS: 'Свернуть сервера',
  628. HIDE_SERVERS_TITLE: 'Скрывать неиспользуемые сервера',
  629. /* Поля ввода */
  630. HOW_MUCH_TITANITE: 'Сколько фармим титанита',
  631. COMBAT_SPEED: 'Множитель ускорения боя',
  632. HOW_REPEAT_CAMPAIGN: 'Сколько повторов миссий', //тест добавил
  633. NUMBER_OF_TEST: 'Количество тестовых боев',
  634. NUMBER_OF_AUTO_BATTLE: 'Количество попыток автобоев',
  635. USER_ID_TITLE: 'Введите айди игрока',
  636. AMOUNT: 'Количество отправляемых подарков',
  637. GIFT_NUM: 'Номер подарка, 1 - развитие героев, 2 - питомцы, 3 - света, 4 - тьмы, 5 - вознесения, 6 - облик',
  638. /* Кнопки */
  639. RUN_SCRIPT: 'Запустить скрипт',
  640. STOP_SCRIPT: 'Остановить скрипт',
  641. TO_DO_EVERYTHING: 'Сделать все',
  642. TO_DO_EVERYTHING_TITLE: 'Выполнить несколько действий',
  643. OUTLAND: 'Запределье',
  644. OUTLAND_TITLE: 'Собрать Запределье',
  645. TITAN_ARENA: 'Турнир Стихий',
  646. TITAN_ARENA_TITLE: 'Автопрохождение Турнира Стихий',
  647. DUNGEON: 'Подземелье',
  648. DUNGEON_TITLE: 'Автопрохождение подземелья',
  649. DUNGEON2: 'Подземелье фулл',
  650. DUNGEON_FULL_TITLE: 'Подземелье для фуловых титанов',
  651. STOP_DUNGEON: 'Стоп подземка',
  652. STOP_DUNGEON_TITLE: 'Остановить копание подземелья',
  653. SEER: 'Провидец',
  654. SEER_TITLE: 'Покрутить Провидца',
  655. TOWER: 'Башня',
  656. TOWER_TITLE: 'Автопрохождение башни',
  657. EXPEDITIONS: 'Экспедиции',
  658. EXPEDITIONS_TITLE: 'Отправка и сбор экспедиций',
  659. SYNC: 'Синхронизация',
  660. SYNC_TITLE: 'Частичная синхронизация данных игры без перезагрузки сатраницы',
  661. ARCHDEMON: 'Архидемон',
  662. FURNACE_OF_SOULS: 'Горнило душ',
  663. ARCHDEMON_TITLE: 'Набивает килы и собирает награду',
  664. ESTER_EGGS: 'Пасхалки',
  665. ESTER_EGGS_TITLE: 'Собрать все пасхалки или награды',
  666. REWARDS: 'Награды',
  667. REWARDS_TITLE: 'Собрать все награды за задания',
  668. MAIL: 'Почта',
  669. MAIL_TITLE: 'Собрать всю почту, кроме писем с энергией и зарядами портала',
  670. MINIONS: 'Прислужники',
  671. MINIONS_TITLE: 'Атакует прислужников сохраннеными пачками',
  672. ADVENTURE: 'Приключение',
  673. ADVENTURE_TITLE: 'Проходит приключение по указанному маршруту',
  674. STORM: 'Буря',
  675. STORM_TITLE: 'Проходит бурю по указанному маршруту',
  676. SANCTUARY: 'Святилище',
  677. SANCTUARY_TITLE: 'Быстрый переход к Святилищу',
  678. GUILD_WAR: 'Война гильдий',
  679. GUILD_WAR_TITLE: 'Быстрый переход к Войне гильдий',
  680. SECRET_WEALTH: 'Тайное богатство',
  681. SECRET_WEALTH_TITLE: 'Купить что-то в магазине "Тайное богатство"',
  682. /* Разное */
  683. BOTTOM_URLS: '<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>',
  684. GIFTS_SENT: 'Подарки отправлены!',
  685. DO_YOU_WANT: 'Вы действительно хотите это сделать?',
  686. BTN_RUN: 'Запускай',
  687. BTN_CANCEL: 'Отмена',
  688. BTN_OK: 'Ок',
  689. MSG_HAVE_BEEN_DEFEATED: 'Вы потерпели поражение!',
  690. BTN_AUTO: 'Авто',
  691. MSG_YOU_APPLIED: 'Вы нанесли',
  692. MSG_DAMAGE: 'урона',
  693. MSG_CANCEL_AND_STAT: 'Авто (F5) и показать Статистику',
  694. MSG_REPEAT_MISSION: 'Повторить миссию?',
  695. BTN_REPEAT: 'Повторить',
  696. BTN_NO: 'Нет',
  697. MSG_SPECIFY_QUANT: 'Указать количество:',
  698. BTN_OPEN: 'Открыть',
  699. QUESTION_COPY: 'Вопрос скопирован в буфер обмена',
  700. ANSWER_KNOWN: 'Ответ известен',
  701. ANSWER_NOT_KNOWN: 'ВНИМАНИЕ ОТВЕТ НЕ ИЗВЕСТЕН',
  702. BEING_RECALC: 'Идет прерасчет боя',
  703. THIS_TIME: 'На этот раз',
  704. VICTORY: '<span style="color:green;">ПОБЕДА</span>',
  705. DEFEAT: '<span style="color:red;">ПОРАЖЕНИЕ</span>',
  706. CHANCE_TO_WIN: 'Шансы на победу <span style="color:red;">на основе прерасчета</span>',
  707. OPEN_DOLLS: 'матрешек рекурсивно',
  708. SENT_QUESTION: 'Вопрос отправлен',
  709. SETTINGS: 'Настройки',
  710. MSG_BAN_ATTENTION: '<p style="color:red;">Использование этой функции может привести к бану.</p> Продолжить?',
  711. BTN_YES_I_AGREE: 'Да, я беру на себя все риски!',
  712. BTN_NO_I_AM_AGAINST: 'Нет, я отказываюсь от этого!',
  713. VALUES: 'Значения',
  714. SAVING: 'Сохранка',
  715. USER_ID: 'айди пользователя',
  716. SEND_GIFT: 'Подарок отправлен',
  717. EXPEDITIONS_SENT: 'Экспедиции:<br>Собрано: {countGet}<br>Отправлено: {countSend}',
  718. EXPEDITIONS_NOTHING: 'Нечего собирать/отправлять',
  719. TITANIT: 'Титанит',
  720. COMPLETED: 'завершено',
  721. FLOOR: 'Этаж',
  722. LEVEL: 'Уровень',
  723. BATTLES: 'бои',
  724. EVENT: 'Эвент',
  725. NOT_AVAILABLE: 'недоступен',
  726. NO_HEROES: 'Нет героев',
  727. DAMAGE_AMOUNT: 'Количество урона',
  728. NOTHING_TO_COLLECT: 'Нечего собирать',
  729. COLLECTED: 'Собрано',
  730. REWARD: 'наград',
  731. REMAINING_ATTEMPTS: 'Осталось попыток',
  732. BATTLES_CANCELED: 'Битв отменено',
  733. MINION_RAID: 'Рейд прислужников',
  734. STOPPED: 'Остановлено',
  735. REPETITIONS: 'Повторений',
  736. MISSIONS_PASSED: 'Миссий пройдено',
  737. STOP: 'остановить',
  738. TOTAL_OPEN: 'Всего открыто',
  739. OPEN: 'Открыто',
  740. ROUND_STAT: 'Статистика урона за',
  741. BATTLE: 'боев',
  742. MINIMUM: 'Минимальный',
  743. MAXIMUM: 'Максимальный',
  744. AVERAGE: 'Средний',
  745. NOT_THIS_TIME: 'Не в этот раз',
  746. RETRY_LIMIT_EXCEEDED: 'Превышен лимит попыток',
  747. SUCCESS: 'Успех',
  748. RECEIVED: 'Получено',
  749. LETTERS: 'писем',
  750. PORTALS: 'порталов',
  751. ATTEMPTS: 'попыток',
  752. QUEST_10001: 'Улучши умения героев 3 раза',
  753. QUEST_10002: 'Пройди 10 миссий',
  754. QUEST_10003: 'Пройди 3 героические миссии',
  755. QUEST_10004: 'Сразись 3 раза на Арене или Гранд Арене',
  756. QUEST_10006: 'Используй обмен изумрудов 1 раз',
  757. QUEST_10007: 'Соверши 1 призыв в Атриуме Душ',
  758. QUEST_10016: 'Отправь подарки согильдийцам',
  759. QUEST_10018: 'Используй зелье опыта',
  760. QUEST_10019: 'Открой 1 сундук в Башне',
  761. QUEST_10020: 'Открой 3 сундука в Запределье',
  762. QUEST_10021: 'Собери 75 Титанита в Подземелье Гильдии',
  763. QUEST_10021: 'Собери 150 Титанита в Подземелье Гильдии',
  764. QUEST_10023: 'Прокачай Дар Стихий на 1 уровень',
  765. QUEST_10024: 'Повысь уровень любого артефакта один раз',
  766. QUEST_10025: 'Начни 1 Экспедицию',
  767. QUEST_10026: 'Начни 4 Экспедиции',
  768. QUEST_10027: 'Победи в 1 бою Турнира Стихий',
  769. QUEST_10028: 'Повысь уровень любого артефакта титанов',
  770. QUEST_10029: 'Открой сферу артефактов титанов',
  771. QUEST_10030: 'Улучши облик любого героя 1 раз',
  772. QUEST_10031: 'Победи в 6 боях Турнира Стихий',
  773. QUEST_10043: 'Начни или присоеденись к Приключению',
  774. QUEST_10044: 'Воспользуйся призывом питомцев 1 раз',
  775. QUEST_10046: 'Открой 3 сундука в Приключениях',
  776. QUEST_10047: 'Набери 150 очков активности в Гильдии',
  777. NOTHING_TO_DO: 'Нечего выполнять',
  778. YOU_CAN_COMPLETE: 'Можно выполнить квесты',
  779. BTN_DO_IT: 'Выполняй',
  780. NOT_QUEST_COMPLETED: 'Ни одного квеста не выполенно',
  781. COMPLETED_QUESTS: 'Выполнено квестов',
  782. /* everything button */
  783. ASSEMBLE_OUTLAND: 'Собрать Запределье',
  784. PASS_THE_TOWER: 'Пройти башню',
  785. CHECK_EXPEDITIONS: 'Проверить экспедиции',
  786. COMPLETE_TOE: 'Пройти Турнир Стихий',
  787. COMPLETE_DUNGEON: 'Пройти подземелье',
  788. COMPLETE_DUNGEON_FULL: 'Пройти подземелье фулл',
  789. COLLECT_MAIL: 'Собрать почту',
  790. COLLECT_MISC: 'Собрать всякую херню',
  791. COLLECT_MISC_TITLE: 'Собрать пасхалки, камни облика, ключи, монеты арены и Хрусталь души',
  792. COLLECT_QUEST_REWARDS: 'Собрать награды за квесты',
  793. MAKE_A_SYNC: 'Сделать синхронизацию',
  794.  
  795. RUN_FUNCTION: 'Выполнить следующие функции?',
  796. BTN_GO: 'Погнали!',
  797. PERFORMED: 'Выполняется',
  798. DONE: 'Выполнено',
  799. ERRORS_OCCURRES: 'Призошли ошибки при выполнении',
  800. COPY_ERROR: 'Скопировать в буфер информацию об ошибке',
  801. BTN_YES: 'Да',
  802. ALL_TASK_COMPLETED: 'Все задачи выполнены',
  803.  
  804. UNKNOWN: 'Неизвестно',
  805. ENTER_THE_PATH: 'Введите путь приключения через запятые или дефисы',
  806. START_ADVENTURE: 'Начать приключение по этому пути!',
  807. INCORRECT_WAY: 'Неверный путь в приключении: {from} -> {to}',
  808. BTN_CANCELED: 'Отменено',
  809. MUST_TWO_POINTS: 'Путь должен состоять минимум из 2х точек',
  810. MUST_ONLY_NUMBERS: 'Путь должен содержать только цифры и запятые',
  811. NOT_ON_AN_ADVENTURE: 'Вы не в приключении',
  812. YOU_IN_NOT_ON_THE_WAY: 'Указанный путь должен включать точку вашего положения',
  813. ATTEMPTS_NOT_ENOUGH: 'Ваших попыток не достаточно для завершения пути, продолжить?',
  814. YES_CONTINUE: 'Да, продолжай!',
  815. NOT_ENOUGH_AP: 'Попыток не достаточно',
  816. ATTEMPTS_ARE_OVER: 'Попытки закончились',
  817. MOVES: 'Ходы',
  818. BUFF_GET_ERROR: 'Ошибка при получении бафа',
  819. BATTLE_END_ERROR: 'Ошибка завершения боя',
  820. AUTOBOT: 'АвтоБой',
  821. FAILED_TO_WIN_AUTO: 'Не удалось победить в автобою',
  822. ERROR_OF_THE_BATTLE_COPY: 'Призошли ошибка в процессе прохождения боя<br>Скопировать ошибку в буфер обмена?',
  823. ERROR_DURING_THE_BATTLE: 'Ошибка в процессе прохождения боя',
  824. NO_CHANCE_WIN: 'Нет шансов победить в этом бою: 0/',
  825. LOST_HEROES: 'Вы победили, но потеряли одного или несколько героев!',
  826. VICTORY_IMPOSSIBLE: 'Победа не возможна, бъем на результат?',
  827. FIND_COEFF: 'Поиск коэффициента больше чем',
  828. BTN_PASS: 'ПРОПУСК',
  829. BRAWLS: 'Потасовки',
  830. BRAWLS_TITLE: 'Включает возможность автопотасовок',
  831. START_AUTO_BRAWLS: 'Запустить Автопотасовки?',
  832. LOSSES: 'Поражений',
  833. WINS: 'Побед',
  834. FIGHTS: 'Боев',
  835. STAGE: 'Стадия',
  836. DONT_HAVE_LIVES: 'У Вас нет жизней',
  837. LIVES: 'Жизни',
  838. SECRET_WEALTH_ALREADY: 'товар за Зелья питомцев уже куплен',
  839. SECRET_WEALTH_NOT_ENOUGH: 'Не достаточно Зелье Питомца, у Вас {available}, нужно {need}',
  840. SECRET_WEALTH_UPGRADE_NEW_PET: 'После покупки Зелье Питомца будет не достаточно для прокачки нового питомца',
  841. SECRET_WEALTH_PURCHASED: 'Куплено {count} {name}',
  842. SECRET_WEALTH_CANCELED: 'Тайное богатство: покупка отменена',
  843. SECRET_WEALTH_BUY: 'У вас {available} Зелье Питомца.<br>Вы хотите купить {countBuy} {name} за {price} Зелье Питомца?',
  844. DAILY_BONUS: 'Ежедневная награда',
  845. DO_DAILY_QUESTS: 'Сделать ежедневные квесты',
  846. ACTIONS: 'Действия',
  847. ACTIONS_TITLE: 'Диалоговое окно с различными действиями',
  848. OTHERS: 'Разное',
  849. OTHERS_TITLE: 'Диалоговое окно с дополнительными различными действиями',
  850. CHOOSE_ACTION: 'Выберите действие',
  851. OPEN_LOOTBOX: 'У Вас {lootBox} ящиков, откываем?',
  852. STAMINA: 'Энергия',
  853. BOXES_OVER: 'Ящики закончились',
  854. NO_BOXES: 'Нет ящиков',
  855. NO_MORE_ACTIVITY: 'Больше активности за предметы сегодня не получить',
  856. EXCHANGE_ITEMS: 'Обменять предметы на очки активности (не более {maxActive})?',
  857. GET_ACTIVITY: 'Получить активность',
  858. NOT_ENOUGH_ITEMS: 'Предметов недостаточно',
  859. ACTIVITY_RECEIVED: 'Получено активности',
  860. NO_PURCHASABLE_HERO_SOULS: 'Нет доступных для покупки душ героев',
  861. PURCHASED_HERO_SOULS: 'Куплено {countHeroSouls} душ героев',
  862. NOT_ENOUGH_EMERALDS_540: 'Недостаточно изюма, нужно {imgEmerald}540 у Вас {imgEmerald}{currentStarMoney}',
  863. BUY_OUTLAND_BTN: 'Купить {count} сундуков {imgEmerald}{countEmerald}',
  864. CHESTS_NOT_AVAILABLE: 'Сундуки не доступны',
  865. OUTLAND_CHESTS_RECEIVED: 'Получено сундуков Запределья',
  866. RAID_NOT_AVAILABLE: 'Рейд не доступен или сфер нет',
  867. RAID_ADVENTURE: 'Рейд {adventureId} приключения!',
  868. SOMETHING_WENT_WRONG: 'Что-то пошло не так',
  869. ADVENTURE_COMPLETED: 'Приключение {adventureId} пройдено {times} раз',
  870. CLAN_STAT_COPY: 'Клановая статистика скопирована в буфер обмена',
  871. GET_ENERGY: 'Получить энергию',
  872. GET_ENERGY_TITLE: 'Открывает платиновые шкатулки по одной до получения 250 энергии',
  873. ITEM_EXCHANGE: 'Обмен предметов',
  874. ITEM_EXCHANGE_TITLE: 'Обменивает предметы на указанное количество активности',
  875. BUY_SOULS: 'Купить души',
  876. BUY_SOULS_TITLE: 'Купить души героев из всех доступных магазинов',
  877. BUY_OUTLAND: 'Купить Запределье',
  878. BUY_OUTLAND_TITLE: 'Купить 9 сундуков в Запределье за 540 изумрудов',
  879. RAID: 'Рейд',
  880. AUTO_RAID_ADVENTURE: 'Рейд приключения',
  881. AUTO_RAID_ADVENTURE_TITLE: 'Рейд приключения заданное количество раз',
  882. CLAN_STAT: 'Клановая статистика',
  883. CLAN_STAT_TITLE: 'Копирует клановую статистику в буфер обмена',
  884. BTN_AUTO_F5: 'Авто (F5)',
  885. BOSS_DAMAGE: 'Урон по боссу: ',
  886. NOTHING_BUY: 'Нечего покупать',
  887. LOTS_BOUGHT: 'За золото куплено {countBuy} лотов',
  888. BUY_FOR_GOLD: 'Скупить за золото',
  889. BUY_FOR_GOLD_TITLE: 'Скупить предметы за золото в Городской лавке и в магазине Камней Душ Питомцев',
  890. REWARDS_AND_MAIL: 'Награды и почта',
  891. REWARDS_AND_MAIL_TITLE: 'Собирает награды и почту',
  892. New_Year_Clan: 'подарок другу',
  893. New_Year_Clan_TITLE: 'Новогодние подарки друзьям',
  894. COLLECT_REWARDS_AND_MAIL: 'Собрано {countQuests} наград и {countMail} писем',
  895. TIMER_ALREADY: 'Таймер уже запущен {time}',
  896. NO_ATTEMPTS_TIMER_START: 'Попыток нет, запущен таймер {time}',
  897. EPIC_BRAWL_RESULT: '{i} Победы: {wins}/{attempts}, Монеты: {coins}, Серия: {progress}/{nextStage} [Закрыть]{end}',
  898. ATTEMPT_ENDED: '<br>Попытки закончились, запущен таймер {time}',
  899. EPIC_BRAWL: 'Вселенская битва',
  900. EPIC_BRAWL_TITLE: 'Тратит попытки во Вселенской битве',
  901. RELOAD_GAME: 'Перезагрузить игру',
  902. TIMER: 'Таймер:',
  903. SHOW_ERRORS: 'Отображать ошибки',
  904. SHOW_ERRORS_TITLE: 'Отображать ошибки запросов к серверу',
  905. ERROR_MSG: 'Ошибка: {name}<br>{description}',
  906. EVENT_AUTO_BOSS: 'Максимальное количество боев для расчета:</br>{length} * {countTestBattle} = {maxCalcBattle}</br>Если у Вас слабый компьютер на это может потребоваться много времени, нажмите крестик для отмены.</br>Искать лучший пак из всех или первый подходящий?',
  907. BEST_SLOW: 'Лучший (медленее)',
  908. FIRST_FAST: 'Первый (быстрее)',
  909. FREEZE_INTERFACE: 'Идет расчет... <br> Интерфейс может зависнуть.',
  910. ERROR_F12: 'Ошибка, подробности в консоли (F12)',
  911. FAILED_FIND_WIN_PACK: 'Победный пак найти не удалось',
  912. BEST_PACK: 'Наилучший пак: ',
  913. BOSS_HAS_BEEN_DEF: 'Босс {bossLvl} побежден',
  914. NOT_ENOUGH_ATTEMPTS_BOSS: 'Для победы босса ${bossLvl} не хватило попыток, повторить?',
  915. BOSS_VICTORY_IMPOSSIBLE: 'По результатам прерасчета {battles} боев победу получить не удалось. Вы хотите продолжить поиск победного боя на реальных боях?',
  916. BOSS_HAS_BEEN_DEF_TEXT: 'Босс {bossLvl} побежден за<br>{countBattle}/{countMaxBattle} попыток{winTimer}<br>(Сделайте синхронизацию или перезагрузите игру для обновления данных)',
  917. MAP: 'Карта: ',
  918. PLAYER_POS: 'Позиции игроков:',
  919. NY_GIFTS: 'Подарки',
  920. NY_GIFTS_TITLE: 'Открыть все новогодние подарки',
  921. NY_NO_GIFTS: 'Нет не полученных подарков',
  922. NY_GIFTS_COLLECTED: 'Собрано {count} подарков',
  923. CHANGE_MAP: 'Карта острова',
  924. CHANGE_MAP_TITLE: 'Сменить карту острова',
  925. SELECT_ISLAND_MAP: 'Выберите карту острова:',
  926. MAP_NUM: 'Карта {num}',
  927. SECRET_WEALTH_SHOP: 'Тайное богатство {name}: ',
  928. SHOPS: 'Магазины',
  929. SHOPS_DEFAULT: 'Стандартные',
  930. SHOPS_DEFAULT_TITLE: 'Стандартные магазины',
  931. SHOPS_LIST: 'Магазины {number}',
  932. SHOPS_LIST_TITLE: 'Список магазинов {number}',
  933. SHOPS_WARNING: 'Магазины<br><span style="color:red">Если Вы купите монеты магазинов потасовок за изумруды, то их надо использовать сразу, иначе после перезагрузки игры они пропадут!</span>',
  934. MINIONS_WARNING: 'Пачки героев для атаки приспешников неполные, продолжить?',
  935. FAST_SEASON: 'Быстрый сезон',
  936. FAST_SEASON_TITLE: 'Пропуск экрана с выбором карты в сезоне',
  937. SET_NUMBER_LEVELS: 'Указать колличество уровней:',
  938. POSSIBLE_IMPROVE_LEVELS: 'Возможно улучшить только {count} уровней.<br>Улучшаем?',
  939. NOT_ENOUGH_RESOURECES: 'Не хватает ресурсов',
  940. IMPROVED_LEVELS: 'Улучшено уровней: {count}',
  941. ARTIFACTS_UPGRADE: 'Улучшение артефактов',
  942. ARTIFACTS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых артефактов героев',
  943. SKINS_UPGRADE: 'Улучшение обликов',
  944. SKINS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых обликов героев',
  945. HINT: '<br>Подсказка: ',
  946. PICTURE: '<br>На картинке: ',
  947. ANSWER: '<br>Ответ: ',
  948. NO_HEROES_PACK: 'Проведите хотя бы один бой для сохранения атакующей команды',
  949. BRAWL_AUTO_PACK: 'Автоподбор пачки',
  950. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Автоматический подбор пачки не подходит для текущего героя',
  951. BRAWL_DAILY_TASK_COMPLETED: 'Ежедневное задание выполнено, продолжить атаку?',
  952. CALC_STAT: 'Посчитать статистику',
  953. ELEMENT_TOURNAMENT_REWARD: 'Несобранная награда за Турнир Стихий',
  954. BTN_TRY_FIX_IT: 'Исправить',
  955. BTN_TRY_FIX_IT_TITLE: 'Включить исправление боев при автоатаке',
  956. DAMAGE_FIXED: 'Урон исправлен с {lastDamage} до {maxDamage}!',
  957. DAMAGE_NO_FIXED: 'Не удалось исправить урон: {lastDamage}',
  958. LETS_FIX: 'Исправляем',
  959. COUNT_FIXED: 'За {count} попыток',
  960. DEFEAT_TURN_TIMER: 'Поражение! Включить таймер для завершения миссии?',
  961. SEASON_REWARD: 'Награды сезонов',
  962. SEASON_REWARD_TITLE: 'Собирает доступные бесплатные награды со всех текущих сезонов',
  963. SEASON_REWARD_COLLECTED: 'Собрано {count} наград сезонов',
  964. SELL_HERO_SOULS: 'Продать души',
  965. SELL_HERO_SOULS_TITLE: 'Обменивает все души героев с абсолютной звездой на золото',
  966. GOLD_RECEIVED: 'Получено золота: {gold}',
  967. OPEN_ALL_EQUIP_BOXES: 'Открыть все ящики фрагментов экипировки?',
  968. SERVER_NOT_ACCEPT: 'Сервер не принял результат',
  969. INVASION_BOSS_BUFF: 'Для {bossLvl} босса нужен баф {needBuff} у вас {haveBuff}',
  970. },
  971. };
  972.  
  973. function getLang() {
  974. let lang = '';
  975. if (typeof NXFlashVars !== 'undefined') {
  976. lang = NXFlashVars.interface_lang
  977. }
  978. if (!lang) {
  979. lang = (navigator.language || navigator.userLanguage).substr(0, 2);
  980. }
  981. if (lang == 'ru') {
  982. return lang;
  983. }
  984. return 'en';
  985. }
  986.  
  987. this.I18N = function (constant, replace) {
  988. const selectLang = getLang();
  989. if (constant && constant in i18nLangData[selectLang]) {
  990. const result = i18nLangData[selectLang][constant];
  991. if (replace) {
  992. return result.sprintf(replace);
  993. }
  994. return result;
  995. }
  996. return `% ${constant} %`;
  997. };
  998.  
  999. String.prototype.sprintf = String.prototype.sprintf ||
  1000. function () {
  1001. "use strict";
  1002. var str = this.toString();
  1003. if (arguments.length) {
  1004. var t = typeof arguments[0];
  1005. var key;
  1006. var args = ("string" === t || "number" === t) ?
  1007. Array.prototype.slice.call(arguments)
  1008. : arguments[0];
  1009.  
  1010. for (key in args) {
  1011. str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
  1012. }
  1013. }
  1014.  
  1015. return str;
  1016. };
  1017.  
  1018. /**
  1019. * Checkboxes
  1020. *
  1021. * Чекбоксы
  1022. */
  1023. const checkboxes = {
  1024. passBattle: {
  1025. label: I18N('SKIP_FIGHTS'),
  1026. cbox: null,
  1027. title: I18N('SKIP_FIGHTS_TITLE'),
  1028. default: false,
  1029. },
  1030. /*sendExpedition: {
  1031. label: I18N('AUTO_EXPEDITION'),
  1032. cbox: null,
  1033. title: I18N('AUTO_EXPEDITION_TITLE'),
  1034. default: false,
  1035. },*/ //тест сдедал экспедиции на авто в сделать все
  1036. cancelBattle: {
  1037. label: I18N('CANCEL_FIGHT'),
  1038. cbox: null,
  1039. title: I18N('CANCEL_FIGHT_TITLE'),
  1040. default: false,
  1041. },
  1042. preCalcBattle: {
  1043. label: I18N('BATTLE_RECALCULATION'),
  1044. cbox: null,
  1045. title: I18N('BATTLE_RECALCULATION_TITLE'),
  1046. default: false,
  1047. },
  1048. finishingBattle: {
  1049. label: I18N('BATTLE_FISHING'),
  1050. cbox: null,
  1051. title: I18N('BATTLE_FISHING_TITLE'),
  1052. default: false,
  1053. },
  1054. treningBattle: {
  1055. label: I18N('BATTLE_TRENING'),
  1056. cbox: null,
  1057. title: I18N('BATTLE_TRENING_TITLE'),
  1058. default: false,
  1059. },
  1060. countControl: {
  1061. label: I18N('QUANTITY_CONTROL'),
  1062. cbox: null,
  1063. title: I18N('QUANTITY_CONTROL_TITLE'),
  1064. default: true,
  1065. },
  1066. repeatMission: {
  1067. label: I18N('REPEAT_CAMPAIGN'),
  1068. cbox: null,
  1069. title: I18N('REPEAT_CAMPAIGN_TITLE'),
  1070. default: false,
  1071. },
  1072. noOfferDonat: {
  1073. label: I18N('DISABLE_DONAT'),
  1074. cbox: null,
  1075. title: I18N('DISABLE_DONAT_TITLE'),
  1076. /**
  1077. * A crutch to get the field before getting the character id
  1078. *
  1079. * Костыль чтоб получать поле до получения id персонажа
  1080. */
  1081. default: (() => {
  1082. $result = false;
  1083. try {
  1084. $result = JSON.parse(localStorage[GM_info.script.name + ':noOfferDonat']);
  1085. } catch (e) {
  1086. $result = false;
  1087. }
  1088. return $result || false;
  1089. })(),
  1090. },
  1091. dailyQuests: {
  1092. label: I18N('DAILY_QUESTS'),
  1093. cbox: null,
  1094. title: I18N('DAILY_QUESTS_TITLE'),
  1095. default: false,
  1096. },
  1097. // Потасовки
  1098. /*
  1099. autoBrawls: {
  1100. label: I18N('BRAWLS'),
  1101. cbox: null,
  1102. title: I18N('BRAWLS_TITLE'),
  1103. default: (() => {
  1104. $result = false;
  1105. try {
  1106. $result = JSON.parse(localStorage[GM_info.script.name + ':autoBrawls']);
  1107. } catch (e) {
  1108. $result = false;
  1109. }
  1110. return $result || false;
  1111. })(),
  1112. hide: false,
  1113. },
  1114. getAnswer: {
  1115. label: I18N('AUTO_QUIZ'),
  1116. cbox: null,
  1117. title: I18N('AUTO_QUIZ_TITLE'),
  1118. default: false,
  1119. hide: true,
  1120. },*/
  1121. tryFixIt_v2: {
  1122. label: I18N('BTN_TRY_FIX_IT'),
  1123. cbox: null,
  1124. title: I18N('BTN_TRY_FIX_IT_TITLE'),
  1125. default: false,
  1126. hide: false,
  1127. },
  1128. showErrors: {
  1129. label: I18N('SHOW_ERRORS'),
  1130. cbox: null,
  1131. title: I18N('SHOW_ERRORS_TITLE'),
  1132. default: true,
  1133. },
  1134. buyForGold: {
  1135. label: I18N('BUY_FOR_GOLD'),
  1136. cbox: null,
  1137. title: I18N('BUY_FOR_GOLD_TITLE'),
  1138. default: false,
  1139. },
  1140. hideServers: {
  1141. label: I18N('HIDE_SERVERS'),
  1142. cbox: null,
  1143. title: I18N('HIDE_SERVERS_TITLE'),
  1144. default: false,
  1145. },
  1146. fastSeason: {
  1147. label: I18N('FAST_SEASON'),
  1148. cbox: null,
  1149. title: I18N('FAST_SEASON_TITLE'),
  1150. default: false,
  1151. },
  1152. };
  1153. /**
  1154. * Get checkbox state
  1155. *
  1156. * Получить состояние чекбокса
  1157. */
  1158. function isChecked(checkBox) {
  1159. if (!(checkBox in checkboxes)) {
  1160. return false;
  1161. }
  1162. return checkboxes[checkBox].cbox?.checked;
  1163. }
  1164. /**
  1165. * Input fields
  1166. *
  1167. * Поля ввода
  1168. */
  1169. const inputs = {
  1170. countTitanit: {
  1171. input: null,
  1172. title: I18N('HOW_MUCH_TITANITE'),
  1173. default: 150,
  1174. },
  1175. speedBattle: {
  1176. input: null,
  1177. title: I18N('COMBAT_SPEED'),
  1178. default: 5,
  1179. },
  1180. //тест повтор компании
  1181. countRaid: {
  1182. input: null,
  1183. title: I18N('HOW_REPEAT_CAMPAIGN'),
  1184. default: 5,
  1185. },
  1186. countTestBattle: {
  1187. input: null,
  1188. title: I18N('NUMBER_OF_TEST'),
  1189. default: 10,
  1190. },
  1191. countAutoBattle: {
  1192. input: null,
  1193. title: I18N('NUMBER_OF_AUTO_BATTLE'),
  1194. default: 10,
  1195. },
  1196. /*FPS: {
  1197. input: null,
  1198. title: 'FPS',
  1199. default: 60,
  1200. }*/
  1201. }
  1202. //сохранка тест
  1203. const inputs2 = {
  1204. countBattle: {
  1205. input: null,
  1206. title: '-1 сохраняет защиту, -2 атаку противника с Replay',
  1207. default: 1,
  1208. },
  1209. needResource: {
  1210. input: null,
  1211. title: 'Мощь противника мин.(тыс.)/урона(млн.)',
  1212. default: 300,
  1213. },
  1214. needResource2: {
  1215. input: null,
  1216. title: 'Мощь противника макс./тип бафа',
  1217. default: 1500,
  1218. },
  1219. }
  1220. //новогодние подарки игрокам других гильдий
  1221. const inputs3 = {
  1222. userID: { // айди игрока посмотреть открыв его инфо
  1223. input: null,
  1224. title: I18N('USER_ID_TITLE'),
  1225. default: 111111,
  1226. },
  1227. GiftNum: { // номер подарка считаем слева направо от 1 до 6, под 1 это за 750 новогодних игрушек
  1228. input: null,
  1229. title: I18N('GIFT_NUM'),
  1230. default: 10,
  1231. },
  1232. AmontID: { // количество ресурсов от 1 до бесконечности
  1233. input: null,
  1234. title: I18N('AMOUNT'),
  1235. default: 1,
  1236. },
  1237. }
  1238. /**
  1239. * Checks the checkbox
  1240. *
  1241. * Поплучить данные поля ввода
  1242. */
  1243. /*function getInput(inputName) {
  1244. return inputs[inputName]?.input?.value;
  1245. }*/
  1246. function getInput(inputName) {
  1247. if (inputName in inputs){return inputs[inputName]?.input?.value;}
  1248. else if (inputName in inputs2){return inputs2[inputName]?.input?.value;}
  1249. //else if (inputName in inputs3){return inputs3[inputName]?.input?.value;}
  1250. else return null
  1251. }
  1252.  
  1253. //тест рейд
  1254. /** Автоповтор миссии */
  1255. let isRepeatMission = false;
  1256. /** Вкл/Выкл автоповтор миссии */
  1257. this.switchRepeatMission = function() {
  1258. isRepeatMission = !isRepeatMission;
  1259. console.log(isRepeatMission);
  1260. }
  1261.  
  1262. /**
  1263. * Control FPS
  1264. *
  1265. * Контроль FPS
  1266. */
  1267. let nextAnimationFrame = Date.now();
  1268. const oldRequestAnimationFrame = this.requestAnimationFrame;
  1269. this.requestAnimationFrame = async function (e) {
  1270. const FPS = Number(getInput('FPS')) || -1;
  1271. const now = Date.now();
  1272. const delay = nextAnimationFrame - now;
  1273. nextAnimationFrame = Math.max(now, nextAnimationFrame) + Math.min(1e3 / FPS, 1e3);
  1274. if (delay > 0) {
  1275. await new Promise((e) => setTimeout(e, delay));
  1276. }
  1277. oldRequestAnimationFrame(e);
  1278. };
  1279.  
  1280. /**
  1281. * Button List
  1282. *
  1283. * Список кнопочек
  1284. */
  1285. const buttons = {
  1286. getOutland: {
  1287. name: I18N('TO_DO_EVERYTHING'),
  1288. title: I18N('TO_DO_EVERYTHING_TITLE'),
  1289. func: testDoYourBest,
  1290. },
  1291. /*
  1292. doActions: {
  1293. name: I18N('ACTIONS'),
  1294. title: I18N('ACTIONS_TITLE'),
  1295. func: async function () {
  1296. const popupButtons = [
  1297. {
  1298. msg: I18N('OUTLAND'),
  1299. result: function () {
  1300. confShow(`${I18N('RUN_SCRIPT')} ${I18N('OUTLAND')}?`, getOutland);
  1301. },
  1302. title: I18N('OUTLAND_TITLE'),
  1303. },
  1304. {
  1305. msg: I18N('TOWER'),
  1306. result: function () {
  1307. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TOWER')}?`, testTower);
  1308. },
  1309. title: I18N('TOWER_TITLE'),
  1310. },
  1311. {
  1312. msg: I18N('EXPEDITIONS'),
  1313. result: function () {
  1314. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EXPEDITIONS')}?`, checkExpedition);
  1315. },
  1316. title: I18N('EXPEDITIONS_TITLE'),
  1317. },
  1318. {
  1319. msg: I18N('MINIONS'),
  1320. result: function () {
  1321. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MINIONS')}?`, testRaidNodes);
  1322. },
  1323. title: I18N('MINIONS_TITLE'),
  1324. },
  1325. {
  1326. msg: I18N('ESTER_EGGS'),
  1327. result: function () {
  1328. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ESTER_EGGS')}?`, offerFarmAllReward);
  1329. },
  1330. title: I18N('ESTER_EGGS_TITLE'),
  1331. },
  1332. {
  1333. msg: I18N('STORM'),
  1334. result: function () {
  1335. testAdventure('solo');
  1336. },
  1337. title: I18N('STORM_TITLE'),
  1338. },
  1339. {
  1340. msg: I18N('REWARDS'),
  1341. result: function () {
  1342. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS')}?`, questAllFarm);
  1343. },
  1344. title: I18N('REWARDS_TITLE'),
  1345. },
  1346. {
  1347. msg: I18N('MAIL'),
  1348. result: function () {
  1349. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MAIL')}?`, mailGetAll);
  1350. },
  1351. title: I18N('MAIL_TITLE'),
  1352. },
  1353. {
  1354. msg: I18N('SEER'),
  1355. result: function () {
  1356. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SEER')}?`, rollAscension);
  1357. },
  1358. title: I18N('SEER_TITLE'),
  1359. },
  1360. {
  1361. msg: I18N('NY_GIFTS'),
  1362. result: getGiftNewYear,
  1363. title: I18N('NY_GIFTS_TITLE'),
  1364. },
  1365. ];
  1366. popupButtons.push({ result: false, isClose: true });
  1367. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1368. if (typeof answer === 'function') {
  1369. answer();
  1370. },
  1371. }
  1372. },*/
  1373. doOthers: {
  1374. name: I18N('OTHERS'),
  1375. title: I18N('OTHERS_TITLE'),
  1376. func: async function () {
  1377. const popupButtons = [
  1378. /*
  1379. {
  1380. msg: I18N('GET_ENERGY'),
  1381. result: farmStamina,
  1382. title: I18N('GET_ENERGY_TITLE'),
  1383. },
  1384. {
  1385. msg: I18N('ITEM_EXCHANGE'),
  1386. result: fillActive,
  1387. title: I18N('ITEM_EXCHANGE_TITLE'),
  1388. },
  1389. {
  1390. msg: I18N('BUY_SOULS'),
  1391. result: function () {
  1392. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_SOULS')}?`, buyHeroFragments);
  1393. },
  1394. title: I18N('BUY_SOULS_TITLE'),
  1395. },
  1396. {
  1397. msg: I18N('BUY_FOR_GOLD'),
  1398. result: function () {
  1399. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_FOR_GOLD')}?`, buyInStoreForGold);
  1400. },
  1401. title: I18N('BUY_FOR_GOLD_TITLE'),
  1402. },
  1403. {
  1404. msg: I18N('BUY_OUTLAND'),
  1405. result: bossOpenChestPay,
  1406. title: I18N('BUY_OUTLAND_TITLE'),
  1407. },
  1408. {
  1409. msg: I18N('AUTO_RAID_ADVENTURE'),
  1410. result: autoRaidAdventure,
  1411. title: I18N('AUTO_RAID_ADVENTURE_TITLE'),
  1412. },
  1413. {
  1414. msg: I18N('CLAN_STAT'),
  1415. result: clanStatistic,
  1416. title: I18N('CLAN_STAT_TITLE'),
  1417. },
  1418. {
  1419. msg: I18N('EPIC_BRAWL'),
  1420. result: async function () {
  1421. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EPIC_BRAWL')}?`, () => {
  1422. const brawl = new epicBrawl();
  1423. brawl.start();
  1424. });
  1425. },
  1426. title: I18N('EPIC_BRAWL_TITLE'),
  1427. },*/
  1428. {
  1429. msg: I18N('ARTIFACTS_UPGRADE'),
  1430. result: updateArtifacts,
  1431. title: I18N('ARTIFACTS_UPGRADE_TITLE'),
  1432. },
  1433. {
  1434. msg: I18N('SKINS_UPGRADE'),
  1435. result: updateSkins,
  1436. title: I18N('SKINS_UPGRADE_TITLE'),
  1437. },
  1438. {
  1439. msg: I18N('SEASON_REWARD'),
  1440. result: farmBattlePass,
  1441. title: I18N('SEASON_REWARD_TITLE'),
  1442. },
  1443. {
  1444. msg: I18N('SELL_HERO_SOULS'),
  1445. result: sellHeroSoulsForGold,
  1446. title: I18N('SELL_HERO_SOULS_TITLE'),
  1447. },
  1448. {
  1449. msg: I18N('CHANGE_MAP'),
  1450. result: async function () {
  1451. const maps = Object.values(lib.data.seasonAdventure.list)
  1452. .filter((e) => e.map.cells.length > 2)
  1453. .map((i) => ({
  1454. msg: I18N('MAP_NUM', { num: i.id }),
  1455. result: i.id,
  1456. }));
  1457.  
  1458. /*const result = await popup.confirm(I18N('SELECT_ISLAND_MAP'), [
  1459. ...maps,
  1460. { result: false, isClose: true },
  1461. ]);*/
  1462. //тест карта острова
  1463. const result = await popup.confirm(I18N('SELECT_ISLAND_MAP'), [...maps, { result: false, isClose: true }]);
  1464. if (result) {
  1465. cheats.changeIslandMap(result);
  1466. }
  1467. },
  1468. title: I18N('CHANGE_MAP_TITLE'),
  1469. },
  1470. {
  1471. msg: I18N('SHOPS'),
  1472. result: async function () {
  1473. const shopButtons = [{
  1474. msg: I18N('SHOPS_DEFAULT'),
  1475. result: function () {
  1476. cheats.goDefaultShops();
  1477. },
  1478. title: I18N('SHOPS_DEFAULT_TITLE'),
  1479. }, {
  1480. msg: I18N('SECRET_WEALTH'),
  1481. result: function () {
  1482. cheats.goSecretWealthShops();
  1483. },
  1484. title: I18N('SECRET_WEALTH'),
  1485. }];
  1486. for (let i = 0; i < 4; i++) {
  1487. const number = i + 1;
  1488. shopButtons.push({
  1489. msg: I18N('SHOPS_LIST', { number }),
  1490. result: function () {
  1491. cheats.goCustomShops(i);
  1492. },
  1493. title: I18N('SHOPS_LIST_TITLE', { number }),
  1494. })
  1495. }
  1496. shopButtons.push({ result: false, isClose: true })
  1497. const answer = await popup.confirm(I18N('SHOPS_WARNING'), shopButtons);
  1498. if (typeof answer === 'function') {
  1499. answer();
  1500. }
  1501. },
  1502. title: I18N('SHOPS'),
  1503. },
  1504. ];
  1505.  
  1506. popupButtons.push({ result: false, isClose: true });
  1507. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1508. if (typeof answer === 'function') {
  1509. answer();
  1510. }
  1511. },
  1512. },
  1513. testTitanArena: {
  1514. name: I18N('TITAN_ARENA'),
  1515. title: I18N('TITAN_ARENA_TITLE'),
  1516. func: function () {
  1517. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TITAN_ARENA')}?`, testTitanArena);
  1518. },
  1519. },
  1520. /* тест подземка есть в сделать все
  1521. testDungeon: {
  1522. name: I18N('DUNGEON'),
  1523. title: I18N('DUNGEON_TITLE'),
  1524. func: function () {
  1525. confShow(`${I18N('RUN_SCRIPT')} ${I18N('DUNGEON')}?`, testDungeon);
  1526. },
  1527. hide: true,
  1528. },*/
  1529. //тест подземка 2
  1530. DungeonFull: {
  1531. name: I18N('DUNGEON2'),
  1532. title: I18N('DUNGEON_FULL_TITLE'),
  1533. func: function () {
  1534. confShow(`${I18N('RUN_SCRIPT')} ${I18N('DUNGEON_FULL_TITLE')}?`, DungeonFull);
  1535. },
  1536. },
  1537. //остановить подземелье
  1538. stopDungeon: {
  1539. name: I18N('STOP_DUNGEON'),
  1540. title: I18N('STOP_DUNGEON_TITLE'),
  1541. func: function () {
  1542. confShow(`${I18N('STOP_SCRIPT')} ${I18N('STOP_DUNGEON_TITLE')}?`, stopDungeon);
  1543. },
  1544. },
  1545. // Архидемон
  1546. bossRatingEvent: {
  1547. name: I18N('ARCHDEMON'),
  1548. title: I18N('ARCHDEMON_TITLE'),
  1549. func: function () {
  1550. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ARCHDEMON')}?`, bossRatingEvent);
  1551. },
  1552. hide: true,
  1553. },
  1554. // Горнило душ
  1555. bossRatingEvent: {
  1556. name: I18N('FURNACE_OF_SOULS'),
  1557. title: I18N('ARCHDEMON_TITLE'),
  1558. func: function () {
  1559. confShow(`${I18N('RUN_SCRIPT')} ${I18N('FURNACE_OF_SOULS')}?`, bossRatingEventSouls);
  1560. },
  1561. hide: true,
  1562. },
  1563. // Буря
  1564. /*testAdventure2: {
  1565. name: I18N('STORM'),
  1566. title: I18N('STORM_TITLE'),
  1567. func: () => {
  1568. testAdventure2('solo');
  1569. },
  1570. },*/
  1571. rewardsAndMailFarm: {
  1572. name: I18N('REWARDS_AND_MAIL'),
  1573. title: I18N('REWARDS_AND_MAIL_TITLE'),
  1574. func: function () {
  1575. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS_AND_MAIL')}?`, rewardsAndMailFarm);
  1576. },
  1577. },
  1578. //тест прислужники
  1579. testRaidNodes: {
  1580. name: I18N('MINIONS'),
  1581. title: I18N('MINIONS_TITLE'),
  1582. func: function () {
  1583. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MINIONS')}?`, testRaidNodes);
  1584. },
  1585. },
  1586. testAdventure: {
  1587. name: I18N('ADVENTURE'),
  1588. title: I18N('ADVENTURE_TITLE'),
  1589. func: () => {
  1590. testAdventure();
  1591. },
  1592. },
  1593. goToSanctuary: {
  1594. name: I18N('SANCTUARY'),
  1595. title: I18N('SANCTUARY_TITLE'),
  1596. func: cheats.goSanctuary,
  1597. },
  1598. goToClanWar: {
  1599. name: I18N('GUILD_WAR'),
  1600. title: I18N('GUILD_WAR_TITLE'),
  1601. func: cheats.goClanWar,
  1602. },
  1603. dailyQuests: {
  1604. name: I18N('DAILY_QUESTS'),
  1605. title: I18N('DAILY_QUESTS_TITLE'),
  1606. func: async function () {
  1607. const quests = new dailyQuests(
  1608. () => {},
  1609. () => {}
  1610. );
  1611. await quests.autoInit();
  1612. quests.start();
  1613. },
  1614. },
  1615. //подарок др
  1616. /*NewYearGift_Clan: {
  1617. name: I18N('New_Year_Clan'),
  1618. title: I18N('New_Year_Clan_TITLE'),
  1619. func: function () {
  1620. confShow(`${I18N('RUN_SCRIPT')} ${I18N('New_Year_Clan_TITLE')}?`, NewYearGift_Clan);
  1621. },
  1622. },*/
  1623. newDay: {
  1624. name: I18N('SYNC'),
  1625. title: I18N('SYNC_TITLE'),
  1626. func: function () {
  1627. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SYNC')}?`, cheats.refreshGame);
  1628. },
  1629. },
  1630. };
  1631. /**
  1632. * Display buttons
  1633. *
  1634. * Вывести кнопочки
  1635. */
  1636. function addControlButtons() {
  1637. for (let name in buttons) {
  1638. button = buttons[name];
  1639. if (button.hide) {
  1640. continue;
  1641. }
  1642. button['button'] = scriptMenu.addButton(button.name, button.func, button.title);
  1643. }
  1644. }
  1645. /**
  1646. * Adds links
  1647. *
  1648. * Добавляет ссылки
  1649. */
  1650. function addBottomUrls() {
  1651. scriptMenu.addHeader(I18N('BOTTOM_URLS'));
  1652. }
  1653. /**
  1654. * Stop repetition of the mission
  1655. *
  1656. * Остановить повтор миссии
  1657. */
  1658. let isStopSendMission = false;
  1659. /**
  1660. * There is a repetition of the mission
  1661. *
  1662. * Идет повтор миссии
  1663. */
  1664. let isSendsMission = false;
  1665. /**
  1666. * Data on the past mission
  1667. *
  1668. * Данные о прошедшей мисии
  1669. */
  1670. let lastMissionStart = {}
  1671. /**
  1672. * Start time of the last battle in the company
  1673. *
  1674. * Время начала последнего боя в кампании
  1675. */
  1676. let lastMissionBattleStart = 0;
  1677. /**
  1678. * Data for calculating the last battle with the boss
  1679. *
  1680. * Данные для расчете последнего боя с боссом
  1681. */
  1682. let lastBossBattle = null;
  1683. /**
  1684. * Information about the last battle
  1685. *
  1686. * Данные о прошедшей битве
  1687. */
  1688. let lastBattleArg = {}
  1689. let lastBossBattleStart = null;
  1690. this.addBattleTimer = 4;
  1691. this.invasionTimer = 2500;
  1692. const invasionInfo = {
  1693. buff: 0,
  1694. bossLvl: 130,
  1695. };
  1696. const invasionDataPacks = {
  1697. 130: { buff: 0, pet: 6004, heroes: [58, 48, 16, 65, 59], favor: { 16: 6004, 48: 6001, 58: 6002, 59: 6005, 65: 6000 } },
  1698. 140: { buff: 0, pet: 6006, heroes: [1, 4, 13, 58, 65], favor: { 1: 6001, 4: 6006, 13: 6002, 58: 6005, 65: 6000 } },
  1699. 150: { buff: 0, pet: 6006, heroes: [1, 12, 17, 21, 65], favor: { 1: 6001, 12: 6003, 17: 6006, 21: 6002, 65: 6000 } },
  1700. 160: { buff: 0, pet: 6008, heroes: [12, 21, 34, 58, 65], favor: { 12: 6003, 21: 6006, 34: 6008, 58: 6002, 65: 6001 } },
  1701. 170: { buff: 0, pet: 6005, heroes: [33, 12, 65, 21, 4], favor: { 4: 6001, 12: 6003, 21: 6006, 33: 6008, 65: 6000 } },
  1702. 180: { buff: 20, pet: 6009, heroes: [58, 13, 5, 17, 65], favor: { 5: 6006, 13: 6003, 58: 6005 } },
  1703. 190: { buff: 0, pet: 6006, heroes: [1, 12, 21, 36, 65], favor: { 1: 6004, 12: 6003, 21: 6006, 36: 6005, 65: 6000 } },
  1704. 200: { buff: 0, pet: 6006, heroes: [12, 1, 13, 2, 65], favor: { 2: 6001, 12: 6003, 13: 6006, 65: 6000 } },
  1705. 210: { buff: 15, pet: 6005, heroes: [12, 21, 33, 58, 65], favor: { 12: 6003, 21: 6006, 33: 6008, 58: 6005, 65: 6001 } },
  1706. 220: { buff: 5, pet: 6006, heroes: [58, 13, 7, 34, 65], favor: { 7: 6002, 13: 6008, 34: 6006, 58: 6005, 65: 6001 } },
  1707. 230: { buff: 35, pet: 6005, heroes: [5, 7, 13, 58, 65], favor: { 5: 6006, 7: 6003, 13: 6002, 58: 6005, 65: 6000 } },
  1708. 240: { buff: 0, pet: 6005, heroes: [12, 58, 1, 36, 65], favor: { 1: 6006, 12: 6003, 36: 6005, 65: 6001 } },
  1709. 250: { buff: 15, pet: 6005, heroes: [12, 36, 4, 16, 65], favor: { 12: 6003, 16: 6004, 36: 6005, 65: 6001 } },
  1710. 260: { buff: 15, pet: 6005, heroes: [48, 12, 36, 65, 4], favor: { 4: 6006, 12: 6003, 36: 6005, 48: 6000, 65: 6007 } },
  1711. 270: { buff: 35, pet: 6005, heroes: [12, 58, 36, 4, 65], favor: { 4: 6006, 12: 6003, 36: 6005 } },
  1712. 280: { buff: 80, pet: 6005, heroes: [21, 36, 48, 7, 65], favor: { 7: 6003, 21: 6006, 36: 6005, 48: 6001, 65: 6000 } },
  1713. 290: { buff: 95, pet: 6008, heroes: [12, 21, 36, 35, 65], favor: { 12: 6003, 21: 6006, 36: 6005, 65: 6007 } },
  1714. 300: { buff: 25, pet: 6005, heroes: [12, 13, 4, 34, 65], favor: { 4: 6006, 12: 6003, 13: 6007, 34: 6002 } },
  1715. 310: { buff: 45, pet: 6005, heroes: [12, 21, 58, 33, 65], favor: { 12: 6003, 21: 6006, 33: 6002, 58: 6005, 65: 6007 } },
  1716. 320: { buff: 70, pet: 6005, heroes: [12, 48, 2, 6, 65], favor: { 6: 6005, 12: 6003 } },
  1717. 330: { buff: 70, pet: 6005, heroes: [12, 21, 36, 5, 65], favor: { 5: 6002, 12: 6003, 21: 6006, 36: 6005, 65: 6000 } },
  1718. 340: { buff: 55, pet: 6009, heroes: [12, 36, 13, 6, 65], favor: { 6: 6005, 12: 6003, 13: 6002, 36: 6006, 65: 6000 } },
  1719. 350: { buff: 100, pet: 6005, heroes: [12, 21, 58, 34, 65], favor: { 12: 6003, 21: 6006, 58: 6005 } },
  1720. 360: { buff: 85, pet: 6007, heroes: [12, 21, 36, 4, 65], favor: { 4: 6006, 12: 6003, 21: 6002, 36: 6005 } },
  1721. 370: { buff: 90, pet: 6008, heroes: [12, 21, 36, 13, 65], favor: { 12: 6003, 13: 6007, 21: 6006, 36: 6005, 65: 6001 } },
  1722. 380: { buff: 165, pet: 6005, heroes: [12, 33, 36, 4, 65], favor: { 4: 6001, 12: 6003, 33: 6006 } },
  1723. 390: { buff: 235, pet: 6005, heroes: [21, 58, 48, 2, 65], favor: { 2: 6005, 21: 6002 } },
  1724. 400: { buff: 125, pet: 6006, heroes: [12, 21, 36, 48, 65], favor: { 12: 6003, 21: 6006, 36: 6005, 48: 6001, 65: 6007 } },
  1725. };
  1726. /**
  1727. * The name of the function of the beginning of the battle
  1728. *
  1729. * Имя функции начала боя
  1730. */
  1731. let nameFuncStartBattle = '';
  1732. /**
  1733. * The name of the function of the end of the battle
  1734. *
  1735. * Имя функции конца боя
  1736. */
  1737. let nameFuncEndBattle = '';
  1738. /**
  1739. * Data for calculating the last battle
  1740. *
  1741. * Данные для расчета последнего боя
  1742. */
  1743. let lastBattleInfo = null;
  1744. /**
  1745. * The ability to cancel the battle
  1746. *
  1747. * Возможность отменить бой
  1748. */
  1749. let isCancalBattle = true;
  1750.  
  1751. /**
  1752. * Certificator of the last open nesting doll
  1753. *
  1754. * Идетификатор последней открытой матрешки
  1755. */
  1756. let lastRussianDollId = null;
  1757. /**
  1758. * Cancel the training guide
  1759. *
  1760. * Отменить обучающее руководство
  1761. */
  1762. this.isCanceledTutorial = false;
  1763.  
  1764. /**
  1765. * Data from the last question of the quiz
  1766. *
  1767. * Данные последнего вопроса викторины
  1768. */
  1769. let lastQuestion = null;
  1770. /**
  1771. * Answer to the last question of the quiz
  1772. *
  1773. * Ответ на последний вопрос викторины
  1774. */
  1775. let lastAnswer = null;
  1776. /**
  1777. * Flag for opening keys or titan artifact spheres
  1778. *
  1779. * Флаг открытия ключей или сфер артефактов титанов
  1780. */
  1781. let artifactChestOpen = false;
  1782. /**
  1783. * The name of the function to open keys or orbs of titan artifacts
  1784. *
  1785. * Имя функции открытия ключей или сфер артефактов титанов
  1786. */
  1787. let artifactChestOpenCallName = '';
  1788. let correctShowOpenArtifact = 0;
  1789. /**
  1790. * Data for the last battle in the dungeon
  1791. * (Fix endless cards)
  1792. *
  1793. * Данные для последнего боя в подземке
  1794. * (Исправление бесконечных карт)
  1795. */
  1796. let lastDungeonBattleData = null;
  1797. /**
  1798. * Start time of the last battle in the dungeon
  1799. *
  1800. * Время начала последнего боя в подземелье
  1801. */
  1802. let lastDungeonBattleStart = 0;
  1803. /**
  1804. * Subscription end time
  1805. *
  1806. * Время окончания подписки
  1807. */
  1808. let subEndTime = 0;
  1809. /**
  1810. * Number of prediction cards
  1811. *
  1812. * Количество карт предсказаний
  1813. */
  1814. let countPredictionCard = 0;
  1815.  
  1816. /**
  1817. * Brawl pack
  1818. *
  1819. * Пачка для потасовок
  1820. */
  1821. let brawlsPack = null;
  1822. /**
  1823. * Autobrawl started
  1824. *
  1825. * Автопотасовка запущена
  1826. */
  1827. let isBrawlsAutoStart = false;
  1828. let clanDominationGetInfo = null;
  1829. /**
  1830. * Copies the text to the clipboard
  1831. *
  1832. * Копирует тест в буфер обмена
  1833. * @param {*} text copied text // копируемый текст
  1834. */
  1835. function copyText(text) {
  1836. let copyTextarea = document.createElement("textarea");
  1837. copyTextarea.style.opacity = "0";
  1838. copyTextarea.textContent = text;
  1839. document.body.appendChild(copyTextarea);
  1840. copyTextarea.select();
  1841. document.execCommand("copy");
  1842. document.body.removeChild(copyTextarea);
  1843. delete copyTextarea;
  1844. }
  1845. /**
  1846. * Returns the history of requests
  1847. *
  1848. * Возвращает историю запросов
  1849. */
  1850. this.getRequestHistory = function() {
  1851. return requestHistory;
  1852. }
  1853. /**
  1854. * Generates a random integer from min to max
  1855. *
  1856. * Гененирует случайное целое число от min до max
  1857. */
  1858. const random = function (min, max) {
  1859. return Math.floor(Math.random() * (max - min + 1) + min);
  1860. }
  1861. const randf = function (min, max) {
  1862. return Math.random() * (max - min + 1) + min;
  1863. };
  1864. /**
  1865. * Clearing the request history
  1866. *
  1867. * Очистка истоии запросов
  1868. */
  1869. setInterval(function () {
  1870. let now = Date.now();
  1871. for (let i in requestHistory) {
  1872. const time = +i.split('_')[0];
  1873. if (now - time > 300000) {
  1874. delete requestHistory[i];
  1875. }
  1876. }
  1877. }, 300000);
  1878. /**
  1879. * Displays the dialog box
  1880. *
  1881. * Отображает диалоговое окно
  1882. */
  1883. function confShow(message, yesCallback, noCallback) {
  1884. let buts = [];
  1885. message = message || I18N('DO_YOU_WANT');
  1886. noCallback = noCallback || (() => {});
  1887. if (yesCallback) {
  1888. buts = [
  1889. { msg: I18N('BTN_RUN'), result: true},
  1890. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true},
  1891. ]
  1892. } else {
  1893. yesCallback = () => {};
  1894. buts = [
  1895. { msg: I18N('BTN_OK'), result: true},
  1896. ];
  1897. }
  1898. popup.confirm(message, buts).then((e) => {
  1899. // dialogPromice = null;
  1900. if (e) {
  1901. yesCallback();
  1902. } else {
  1903. noCallback();
  1904. }
  1905. });
  1906. }
  1907. /**
  1908. * Override/proxy the method for creating a WS package send
  1909. *
  1910. * Переопределяем/проксируем метод создания отправки WS пакета
  1911. */
  1912. WebSocket.prototype.send = function (data) {
  1913. if (!this.isSetOnMessage) {
  1914. const oldOnmessage = this.onmessage;
  1915. this.onmessage = function (event) {
  1916. try {
  1917. const data = JSON.parse(event.data);
  1918. if (!this.isWebSocketLogin && data.result.type == "iframeEvent.login") {
  1919. this.isWebSocketLogin = true;
  1920. } else if (data.result.type == "iframeEvent.login") {
  1921. return;
  1922. }
  1923. } catch (e) { }
  1924. return oldOnmessage.apply(this, arguments);
  1925. }
  1926. this.isSetOnMessage = true;
  1927. }
  1928. original.SendWebSocket.call(this, data);
  1929. }
  1930. /**
  1931. * Overriding/Proxying the Ajax Request Creation Method
  1932. *
  1933. * Переопределяем/проксируем метод создания Ajax запроса
  1934. */
  1935. XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
  1936. this.uniqid = Date.now() + '_' + random(1000000, 10000000);
  1937. this.errorRequest = false;
  1938. if (method == 'POST' && url.includes('.nextersglobal.com/api/') && /api\/$/.test(url)) {
  1939. if (!apiUrl) {
  1940. apiUrl = url;
  1941. const socialInfo = /heroes-(.+?)\./.exec(apiUrl);
  1942. console.log(socialInfo);
  1943. }
  1944. requestHistory[this.uniqid] = {
  1945. method,
  1946. url,
  1947. error: [],
  1948. headers: {},
  1949. request: null,
  1950. response: null,
  1951. signature: [],
  1952. calls: {},
  1953. };
  1954. } else if (method == 'POST' && url.includes('error.nextersglobal.com/client/')) {
  1955. this.errorRequest = true;
  1956. }
  1957. return original.open.call(this, method, url, async, user, password);
  1958. };
  1959. /**
  1960. * Overriding/Proxying the header setting method for the AJAX request
  1961. *
  1962. * Переопределяем/проксируем метод установки заголовков для AJAX запроса
  1963. */
  1964. XMLHttpRequest.prototype.setRequestHeader = function (name, value, check) {
  1965. if (this.uniqid in requestHistory) {
  1966. requestHistory[this.uniqid].headers[name] = value;
  1967. if (name == 'X-Auth-Signature') {
  1968. requestHistory[this.uniqid].signature.push(value);
  1969. if (!check) {
  1970. return;
  1971. }
  1972. }
  1973. } else {
  1974. check = true;
  1975. }
  1976.  
  1977. return original.setRequestHeader.call(this, name, value);
  1978. };
  1979. /**
  1980. * Overriding/Proxying the AJAX Request Sending Method
  1981. *
  1982. * Переопределяем/проксируем метод отправки AJAX запроса
  1983. */
  1984. XMLHttpRequest.prototype.send = async function (sourceData) {
  1985. if (this.uniqid in requestHistory) {
  1986. let tempData = null;
  1987. if (getClass(sourceData) == "ArrayBuffer") {
  1988. tempData = decoder.decode(sourceData);
  1989. } else {
  1990. tempData = sourceData;
  1991. }
  1992. requestHistory[this.uniqid].request = tempData;
  1993. let headers = requestHistory[this.uniqid].headers;
  1994. lastHeaders = Object.assign({}, headers);
  1995. /**
  1996. * Game loading event
  1997. *
  1998. * Событие загрузки игры
  1999. */
  2000. if (headers["X-Request-Id"] > 2 && !isLoadGame) {
  2001. isLoadGame = true;
  2002.  
  2003. if (cheats.libGame) {
  2004. lib.setData(cheats.libGame);
  2005. } else {
  2006. lib.setData(await cheats.LibLoad());
  2007. }
  2008.  
  2009. addControls();
  2010. addControlButtons();
  2011. addBottomUrls();
  2012.  
  2013. //if (isChecked('sendExpedition')) {
  2014. // checkExpedition(); //экспедиции на авто при входе в игру
  2015. //}
  2016.  
  2017. //if (isChecked('sendExpedition')) {
  2018. const isTimeBetweenDays = isTimeBetweenNewDays();
  2019. if (!isTimeBetweenDays) {
  2020. checkExpedition(); //экспедиции на авто при входе в игру
  2021. } else {
  2022. setProgress(I18N('EXPEDITIONS_NOTTIME'), true);
  2023. }
  2024. //}
  2025.  
  2026. getAutoGifts(); // автосбор подарков
  2027.  
  2028. cheats.activateHacks();
  2029.  
  2030. justInfo();
  2031. if (isChecked('dailyQuests')) {
  2032. testDailyQuests();
  2033. }
  2034.  
  2035. if (isChecked('buyForGold')) {
  2036. buyInStoreForGold();
  2037. }
  2038. }
  2039. /**
  2040. * Outgoing request data processing
  2041. *
  2042. * Обработка данных исходящего запроса
  2043. */
  2044. sourceData = await checkChangeSend.call(this, sourceData, tempData);
  2045. /**
  2046. * Handling incoming request data
  2047. *
  2048. * Обработка данных входящего запроса
  2049. */
  2050. const oldReady = this.onreadystatechange;
  2051. this.onreadystatechange = async function (e) {
  2052. if (this.errorRequest) {
  2053. return oldReady.apply(this, arguments);
  2054. }
  2055. if(this.readyState == 4 && this.status == 200) {
  2056. isTextResponse = this.responseType === "text" || this.responseType === "";
  2057. let response = isTextResponse ? this.responseText : this.response;
  2058. requestHistory[this.uniqid].response = response;
  2059. /**
  2060. * Replacing incoming request data
  2061. *
  2062. * Заменна данных входящего запроса
  2063. */
  2064. if (isTextResponse) {
  2065. await checkChangeResponse.call(this, response);
  2066. }
  2067. /**
  2068. * A function to run after the request is executed
  2069. *
  2070. * Функция запускаемая после выполения запроса
  2071. */
  2072. if (typeof this.onReadySuccess == 'function') {
  2073. setTimeout(this.onReadySuccess, 500);
  2074. }
  2075. /** Удаляем из истории запросов битвы с боссом */
  2076. if ('invasion_bossStart' in requestHistory[this.uniqid].calls) delete requestHistory[this.uniqid];
  2077. }
  2078. if (oldReady) {
  2079. return oldReady.apply(this, arguments);
  2080. }
  2081. }
  2082. }
  2083. if (this.errorRequest) {
  2084. const oldReady = this.onreadystatechange;
  2085. this.onreadystatechange = function () {
  2086. Object.defineProperty(this, 'status', {
  2087. writable: true
  2088. });
  2089. this.status = 200;
  2090. Object.defineProperty(this, 'readyState', {
  2091. writable: true
  2092. });
  2093. this.readyState = 4;
  2094. Object.defineProperty(this, 'responseText', {
  2095. writable: true
  2096. });
  2097. this.responseText = JSON.stringify({
  2098. "result": true
  2099. });
  2100. if (typeof this.onReadySuccess == 'function') {
  2101. setTimeout(this.onReadySuccess, 200);
  2102. }
  2103. return oldReady.apply(this, arguments);
  2104. }
  2105. this.onreadystatechange();
  2106. } else {
  2107. try {
  2108. return original.send.call(this, sourceData);
  2109. } catch(e) {
  2110. debugger;
  2111. }
  2112.  
  2113. }
  2114. };
  2115. /**
  2116. * Processing and substitution of outgoing data
  2117. *
  2118. * Обработка и подмена исходящих данных
  2119. */
  2120. async function checkChangeSend(sourceData, tempData) {
  2121. try {
  2122. /**
  2123. * A function that replaces battle data with incorrect ones to cancel combatя
  2124. *
  2125. * Функция заменяющая данные боя на неверные для отмены боя
  2126. */
  2127. const fixBattle = function (heroes) {
  2128. for (const ids in heroes) {
  2129. hero = heroes[ids];
  2130. hero.energy = random(1, 999);
  2131. if (hero.hp > 0) {
  2132. hero.hp = random(1, hero.hp);
  2133. }
  2134. }
  2135. }
  2136. /**
  2137. * Dialog window 2
  2138. *
  2139. * Диалоговое окно 2
  2140. */
  2141. const showMsg = async function (msg, ansF, ansS) {
  2142. if (typeof popup == 'object') {
  2143. return await popup.confirm(msg, [
  2144. {msg: ansF, result: false},
  2145. {msg: ansS, result: true},
  2146. ]);
  2147. } else {
  2148. return !confirm(`${msg}\n ${ansF} (${I18N('BTN_OK')})\n ${ansS} (${I18N('BTN_CANCEL')})`);
  2149. }
  2150. }
  2151. /**
  2152. * Dialog window 3
  2153. *
  2154. * Диалоговое окно 3
  2155. */
  2156. const showMsgs = async function (msg, ansF, ansS, ansT) {
  2157. return await popup.confirm(msg, [
  2158. {msg: ansF, result: 0},
  2159. {msg: ansS, result: 1},
  2160. {msg: ansT, result: 2},
  2161. ]);
  2162. }
  2163.  
  2164. let changeRequest = false;
  2165. testData = JSON.parse(tempData);
  2166. for (const call of testData.calls) {
  2167. if (!artifactChestOpen) {
  2168. requestHistory[this.uniqid].calls[call.name] = call.ident;
  2169. }
  2170. /**
  2171. * Cancellation of the battle in adventures, on VG and with minions of Asgard
  2172. * Отмена боя в приключениях, на ВГ и с прислужниками Асгарда
  2173. */
  2174. if ((call.name == 'adventure_endBattle' ||
  2175. call.name == 'adventureSolo_endBattle' ||
  2176. call.name == 'clanWarEndBattle' &&
  2177. isChecked('cancelBattle') ||
  2178. call.name == 'crossClanWar_endBattle' &&
  2179. isChecked('cancelBattle') ||
  2180. call.name == 'brawl_endBattle' ||
  2181. call.name == 'towerEndBattle' ||
  2182. call.name == 'invasion_bossEnd' ||
  2183. call.name == 'titanArenaEndBattle' ||
  2184. call.name == 'bossEndBattle' ||
  2185. call.name == 'clanRaid_endNodeBattle') &&
  2186. isCancalBattle) {
  2187. nameFuncEndBattle = call.name;
  2188.  
  2189. if (isChecked('tryFixIt_v2') &&
  2190. !call.args.result.win &&
  2191. (call.name == 'brawl_endBattle' ||
  2192. //call.name == 'crossClanWar_endBattle' ||
  2193. call.name == 'epicBrawl_endBattle' ||
  2194. //call.name == 'clanWarEndBattle' ||
  2195. call.name == 'adventure_endBattle' ||
  2196. call.name == 'titanArenaEndBattle' ||
  2197. call.name == 'bossEndBattle' ||
  2198. call.name == 'adventureSolo_endBattle') &&
  2199. lastBattleInfo) {
  2200. const noFixWin = call.name == 'clanWarEndBattle' || call.name == 'crossClanWar_endBattle';
  2201. const cloneBattle = structuredClone(lastBattleInfo);
  2202. lastBattleInfo = null;
  2203. try {
  2204. const bFix = new BestOrWinFixBattle(cloneBattle);
  2205. bFix.setNoMakeWin(noFixWin);
  2206. let endTime = Date.now() + 3e4;
  2207. if (endTime < cloneBattle.endTime) {
  2208. endTime = cloneBattle.endTime;
  2209. }
  2210. const result = await bFix.start(cloneBattle.endTime, 150);
  2211.  
  2212. if (result.result.win) {
  2213. call.args.result = result.result;
  2214. call.args.progress = result.progress;
  2215. changeRequest = true;
  2216. } else if (result.value) {
  2217. if (
  2218. await popup.confirm('Поражение<br>Лучший результат: ' + result.value + '%', [
  2219. { msg: 'Отмена', result: 0 },
  2220. { msg: 'Принять', result: 1 },
  2221. ])
  2222. ) {
  2223. call.args.result = result.result;
  2224. call.args.progress = result.progress;
  2225. changeRequest = true;
  2226. }
  2227. }
  2228. } catch (error) {
  2229. console.error(error);
  2230. }
  2231. }
  2232.  
  2233. if (!call.args.result.win) {
  2234. let resultPopup = false;
  2235. if (call.name == 'adventure_endBattle' ||
  2236. //call.name == 'invasion_bossEnd' ||
  2237. call.name == 'bossEndBattle' ||
  2238. call.name == 'adventureSolo_endBattle') {
  2239. resultPopup = await showMsgs(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  2240. } else if (call.name == 'clanWarEndBattle' ||
  2241. call.name == 'crossClanWar_endBattle') {
  2242. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_AUTO_F5'));
  2243. } else if (call.name !== 'epicBrawl_endBattle' && call.name !== 'titanArenaEndBattle') {
  2244. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'));
  2245. }
  2246. if (resultPopup) {
  2247. if (call.name == 'invasion_bossEnd') {
  2248. this.errorRequest = true;
  2249. }
  2250. fixBattle(call.args.progress[0].attackers.heroes);
  2251. fixBattle(call.args.progress[0].defenders.heroes);
  2252. changeRequest = true;
  2253. if (resultPopup > 1) {
  2254. this.onReadySuccess = testAutoBattle;
  2255. // setTimeout(bossBattle, 1000);
  2256. }
  2257. }
  2258. } else if (call.args.result.stars < 3 && call.name == 'towerEndBattle') {
  2259. resultPopup = await showMsg(I18N('LOST_HEROES'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  2260. if (resultPopup) {
  2261. fixBattle(call.args.progress[0].attackers.heroes);
  2262. fixBattle(call.args.progress[0].defenders.heroes);
  2263. changeRequest = true;
  2264. if (resultPopup > 1) {
  2265. this.onReadySuccess = testAutoBattle;
  2266. }
  2267. }
  2268. }
  2269. // Потасовки
  2270. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_endBattle') {}
  2271. }
  2272. /**
  2273. * Save pack for Brawls
  2274. *
  2275. * Сохраняем пачку для потасовок
  2276. */
  2277. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_startBattle') {
  2278. console.log(JSON.stringify(call.args));
  2279. brawlsPack = call.args;
  2280. if (
  2281. await popup.confirm(
  2282. I18N('START_AUTO_BRAWLS'),
  2283. [
  2284. { msg: I18N('BTN_NO'), result: false },
  2285. { msg: I18N('BTN_YES'), result: true },
  2286. ],
  2287. [
  2288. {
  2289. name: 'isAuto',
  2290. label: I18N('BRAWL_AUTO_PACK'),
  2291. checked: false,
  2292. },
  2293. ]
  2294. )
  2295. ) {
  2296. isBrawlsAutoStart = true;
  2297. const isAuto = popup.getCheckBoxes().find((e) => e.name === 'isAuto');
  2298. this.errorRequest = true;
  2299. testBrawls(isAuto.checked);
  2300. }
  2301. }
  2302. /**
  2303. * Canceled fight in Asgard
  2304. * Отмена боя в Асгарде
  2305. */
  2306. if (call.name == 'clanRaid_endBossBattle' && isChecked('cancelBattle')) {
  2307. const bossDamage = call.args.progress[0].defenders.heroes[1].extra;
  2308. let maxDamage = bossDamage.damageTaken + bossDamage.damageTakenNextLevel;
  2309. const lastDamage = maxDamage;
  2310.  
  2311. const testFunc = [];
  2312.  
  2313. if (testFuntions.masterFix) {
  2314. testFunc.push({ msg: 'masterFix', isInput: true, default: 100 });
  2315. }
  2316.  
  2317. const resultPopup = await popup.confirm(
  2318. `${I18N('MSG_YOU_APPLIED')} ${lastDamage.toLocaleString()} ${I18N('MSG_DAMAGE')}.`,
  2319. [
  2320. { msg: I18N('BTN_OK'), result: false },
  2321. { msg: I18N('BTN_AUTO_F5'), result: 1 },
  2322. { msg: I18N('BTN_TRY_FIX_IT'), result: 2 },
  2323. ...testFunc,
  2324. ],
  2325. [
  2326. {
  2327. name: 'isStat',
  2328. label: I18N('CALC_STAT'),
  2329. checked: false,
  2330. },
  2331. ]
  2332. );
  2333. if (resultPopup) {
  2334. if (resultPopup == 2) {
  2335. setProgress(I18N('LETS_FIX'), false);
  2336. await new Promise((e) => setTimeout(e, 0));
  2337. const cloneBattle = structuredClone(lastBossBattle);
  2338. const endTime = cloneBattle.endTime - 1e4;
  2339. console.log('fixBossBattleStart');
  2340.  
  2341. const bFix = new BossFixBattle(cloneBattle);
  2342. const result = await bFix.start(endTime, 300);
  2343. console.log(result);
  2344.  
  2345. let msgResult = I18N('DAMAGE_NO_FIXED', {
  2346. lastDamage: lastDamage.toLocaleString()
  2347. });
  2348. if (result.value > lastDamage) {
  2349. call.args.result = result.result;
  2350. call.args.progress = result.progress;
  2351. msgResult = I18N('DAMAGE_FIXED', {
  2352. lastDamage: lastDamage.toLocaleString(),
  2353. maxDamage: result.value.toLocaleString(),
  2354. });
  2355. }
  2356. console.log(lastDamage, '>', result.value);
  2357. setProgress(
  2358. msgResult +
  2359. '<br/>' +
  2360. I18N('COUNT_FIXED', {
  2361. count: result.maxCount,
  2362. }),
  2363. false,
  2364. hideProgress
  2365. );
  2366. } else if (resultPopup > 3) {
  2367. const cloneBattle = structuredClone(lastBossBattle);
  2368. const mFix = new masterFixBattle(cloneBattle);
  2369. const result = await mFix.start(cloneBattle.endTime, resultPopup);
  2370. console.log(result);
  2371. let msgResult = I18N('DAMAGE_NO_FIXED', {
  2372. lastDamage: lastDamage.toLocaleString(),
  2373. });
  2374. if (result.value > lastDamage) {
  2375. maxDamage = result.value;
  2376. call.args.result = result.result;
  2377. call.args.progress = result.progress;
  2378. msgResult = I18N('DAMAGE_FIXED', {
  2379. lastDamage: lastDamage.toLocaleString(),
  2380. maxDamage: maxDamage.toLocaleString(),
  2381. });
  2382. }
  2383. console.log('Урон:', lastDamage, maxDamage);
  2384. setProgress(msgResult, false, hideProgress);
  2385. } else {
  2386. fixBattle(call.args.progress[0].attackers.heroes);
  2387. fixBattle(call.args.progress[0].defenders.heroes);
  2388. }
  2389. changeRequest = true;
  2390. }
  2391. const isStat = popup.getCheckBoxes().find((e) => e.name === 'isStat');
  2392. if (isStat.checked) {
  2393. this.onReadySuccess = testBossBattle;
  2394. }
  2395. }
  2396. /**
  2397. * Save the Asgard Boss Attack Pack
  2398. * Сохраняем пачку для атаки босса Асгарда
  2399. */
  2400. if (call.name == 'clanRaid_startBossBattle') {
  2401. console.log(JSON.stringify(call.args));
  2402. }
  2403. /**
  2404. * Saving the request to start the last battle
  2405. * Сохранение запроса начала последнего боя
  2406. */
  2407. if (
  2408. call.name == 'clanWarAttack' ||
  2409. call.name == 'crossClanWar_startBattle' ||
  2410. call.name == 'adventure_turnStartBattle' ||
  2411. call.name == 'adventureSolo_turnStartBattle' ||
  2412. call.name == 'bossAttack' ||
  2413. call.name == 'invasion_bossStart' ||
  2414. call.name == 'towerStartBattle'
  2415. ) {
  2416. nameFuncStartBattle = call.name;
  2417. lastBattleArg = call.args;
  2418.  
  2419. if (call.name == 'invasion_bossStart') {
  2420. const timePassed = Date.now() - lastBossBattleStart;
  2421. if (timePassed < invasionTimer) {
  2422. await new Promise((e) => setTimeout(e, invasionTimer - timePassed));
  2423. }
  2424. invasionTimer -= 1;
  2425. }
  2426. lastBossBattleStart = Date.now();
  2427. }
  2428. if (call.name == 'invasion_bossEnd') {
  2429. const lastBattle = lastBattleInfo;
  2430. if (lastBattle && call.args.result.win) {
  2431. lastBattle.progress = call.args.progress;
  2432. const result = await Calc(lastBattle);
  2433. let timer = getTimer(result.battleTime, 1) + addBattleTimer;
  2434. const period = Math.ceil((Date.now() - lastBossBattleStart) / 1000);
  2435. console.log(timer, period);
  2436. if (period < timer) {
  2437. timer = timer - period;
  2438. await countdownTimer(timer);
  2439. }
  2440. }
  2441. }
  2442. /**
  2443. * Disable spending divination cards
  2444. * Отключить трату карт предсказаний
  2445. */
  2446. if (call.name == 'dungeonEndBattle') {
  2447. if (call.args.isRaid) {
  2448. if (countPredictionCard <= 0) {
  2449. delete call.args.isRaid;
  2450. changeRequest = true;
  2451. } else if (countPredictionCard > 0) {
  2452. countPredictionCard--;
  2453. }
  2454. }
  2455. console.log(`Cards: ${countPredictionCard}`);
  2456. /**
  2457. * Fix endless cards
  2458. * Исправление бесконечных карт
  2459. */
  2460. const lastBattle = lastDungeonBattleData;
  2461. if (lastBattle && !call.args.isRaid) {
  2462. if (changeRequest) {
  2463. lastBattle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2464. } else {
  2465. lastBattle.progress = call.args.progress;
  2466. }
  2467. const result = await Calc(lastBattle);
  2468.  
  2469. if (changeRequest) {
  2470. call.args.progress = result.progress;
  2471. call.args.result = result.result;
  2472. }
  2473.  
  2474. let timer = result.battleTimer + addBattleTimer;
  2475. const period = Math.ceil((Date.now() - lastDungeonBattleStart) / 1000);
  2476. console.log(timer, period);
  2477. if (period < timer) {
  2478. timer = timer - period;
  2479. await countdownTimer(timer);
  2480. }
  2481. }
  2482. }
  2483. /**
  2484. * Quiz Answer
  2485. * Ответ на викторину
  2486. */
  2487. if (call.name == 'quizAnswer') {
  2488. /**
  2489. * Automatically changes the answer to the correct one if there is one.
  2490. * Автоматически меняет ответ на правильный если он есть
  2491. */
  2492. if (lastAnswer && isChecked('getAnswer')) {
  2493. call.args.answerId = lastAnswer;
  2494. lastAnswer = null;
  2495. changeRequest = true;
  2496. }
  2497. }
  2498. /**
  2499. * Present
  2500. * Подарки
  2501. */
  2502. if (call.name == 'freebieCheck') {
  2503. freebieCheckInfo = call;
  2504. }
  2505. /** missionTimer */
  2506. if (call.name == 'missionEnd' && missionBattle) {
  2507. let startTimer = false;
  2508. if (!call.args.result.win) {
  2509. startTimer = await popup.confirm(I18N('DEFEAT_TURN_TIMER'), [
  2510. { msg: I18N('BTN_NO'), result: false },
  2511. { msg: I18N('BTN_YES'), result: true },
  2512. ]);
  2513. }
  2514.  
  2515. if (call.args.result.win || startTimer) {
  2516. missionBattle.progress = call.args.progress;
  2517. missionBattle.result = call.args.result;
  2518. const result = await Calc(missionBattle);
  2519.  
  2520. let timer = result.battleTimer + addBattleTimer;
  2521. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  2522. if (period < timer) {
  2523. timer = timer - period;
  2524. await countdownTimer(timer);
  2525. }
  2526. missionBattle = null;
  2527. } else {
  2528. this.errorRequest = true;
  2529. }
  2530. }
  2531. /**
  2532. * Getting mission data for auto-repeat
  2533. * Получение данных миссии для автоповтора
  2534. */
  2535. if (isChecked('repeatMission') &&
  2536. call.name == 'missionEnd') {
  2537. let missionInfo = {
  2538. id: call.args.id,
  2539. result: call.args.result,
  2540. heroes: call.args.progress[0].attackers.heroes,
  2541. count: 0,
  2542. }
  2543. setTimeout(async () => {
  2544. if (!isSendsMission && await popup.confirm(I18N('MSG_REPEAT_MISSION'), [
  2545. { msg: I18N('BTN_REPEAT'), result: true},
  2546. { msg: I18N('BTN_NO'), result: false},
  2547. ])) {
  2548. isStopSendMission = false;
  2549. isSendsMission = true;
  2550. sendsMission(missionInfo);
  2551. }
  2552. }, 0);
  2553. }
  2554. /**
  2555. * Getting mission data
  2556. * Получение данных миссии
  2557. * missionTimer
  2558. */
  2559. if (call.name == 'missionStart') {
  2560. lastMissionStart = call.args;
  2561. lastMissionBattleStart = Date.now();
  2562. }
  2563.  
  2564. /**
  2565. * Specify the quantity for Titan Orbs and Pet Eggs
  2566. * Указать количество для сфер титанов и яиц петов
  2567. */
  2568. if (isChecked('countControl') &&
  2569. (call.name == 'pet_chestOpen' ||
  2570. call.name == 'titanUseSummonCircle') &&
  2571. call.args.amount > 1) {
  2572. const startAmount = call.args.amount;
  2573. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2574. { msg: I18N('BTN_OPEN'), isInput: true, default: 1},
  2575. ]);
  2576. if (result) {
  2577. const item = call.name == 'pet_chestOpen' ? { id: 90, type: 'consumable' } : { id: 13, type: 'coin' };
  2578. cheats.updateInventory({
  2579. [item.type]: {
  2580. [item.id]: -(result - startAmount),
  2581. },
  2582. });
  2583. call.args.amount = result;
  2584. changeRequest = true;
  2585. }
  2586. }
  2587. /**
  2588. * Specify the amount for keys and spheres of titan artifacts
  2589. * Указать колличество для ключей и сфер артефактов титанов
  2590. */
  2591. if (isChecked('countControl') &&
  2592. (call.name == 'artifactChestOpen' ||
  2593. call.name == 'titanArtifactChestOpen') &&
  2594. call.args.amount > 1 &&
  2595. call.args.free &&
  2596. !changeRequest) {
  2597. artifactChestOpenCallName = call.name;
  2598. const startAmount = call.args.amount;
  2599. let result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2600. { msg: I18N('BTN_OPEN'), isInput: true, default: 1 },
  2601. ]);
  2602. if (result) {
  2603. const openChests = result;
  2604. let sphere = result < 10 ? 1 : 10;
  2605.  
  2606. call.args.amount = sphere;
  2607.  
  2608. for (let count = openChests - sphere; count > 0; count -= sphere) {
  2609. if (count < 10) sphere = 1;
  2610. const ident = artifactChestOpenCallName + "_" + count;
  2611. testData.calls.push({
  2612. name: artifactChestOpenCallName,
  2613. args: {
  2614. amount: sphere,
  2615. free: true,
  2616. },
  2617. ident: ident
  2618. });
  2619. if (!Array.isArray(requestHistory[this.uniqid].calls[call.name])) {
  2620. requestHistory[this.uniqid].calls[call.name] = [requestHistory[this.uniqid].calls[call.name]];
  2621. }
  2622. requestHistory[this.uniqid].calls[call.name].push(ident);
  2623. }
  2624.  
  2625. const consumableId = call.name == 'artifactChestOpen' ? 45 : 55;
  2626. cheats.updateInventory({
  2627. consumable: {
  2628. [consumableId]: -(openChests - startAmount),
  2629. },
  2630. });
  2631.  
  2632. artifactChestOpen = true;
  2633. changeRequest = true;
  2634. }
  2635. }
  2636. if (call.name == 'consumableUseLootBox') {
  2637. lastRussianDollId = call.args.libId;
  2638. /**
  2639. * Specify quantity for gold caskets
  2640. * Указать количество для золотых шкатулок
  2641. */
  2642. if (isChecked('countControl') &&
  2643. call.args.libId == 148 &&
  2644. call.args.amount > 1) {
  2645. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2646. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2647. ]);
  2648. call.args.amount = result;
  2649. changeRequest = true;
  2650. }
  2651. if (isChecked('countControl') && call.args.libId >= 362 && call.args.libId <= 389) {
  2652. this.massOpen = call.args.libId;
  2653. }
  2654. }
  2655. if (call.name == 'invasion_bossStart' && isChecked('tryFixIt_v2') && call.args.id == 217) {
  2656. const pack = invasionDataPacks[invasionInfo.bossLvl];
  2657. if (pack.buff != invasionInfo.buff) {
  2658. setProgress(
  2659. I18N('INVASION_BOSS_BUFF', {
  2660. bossLvl: invasionInfo.bossLvl,
  2661. needBuff: pack.buff,
  2662. haveBuff: invasionInfo.buff,
  2663. }),
  2664. false
  2665. );
  2666. } else {
  2667. call.args.pet = pack.pet;
  2668. call.args.heroes = pack.heroes;
  2669. call.args.favor = pack.favor;
  2670. changeRequest = true;
  2671. }
  2672. }
  2673. /**
  2674. * Changing the maximum number of raids in the campaign
  2675. * Изменение максимального количества рейдов в кампании
  2676. */
  2677. // if (call.name == 'missionRaid') {
  2678. // if (isChecked('countControl') && call.args.times > 1) {
  2679. // const result = +(await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2680. // { msg: I18N('BTN_RUN'), isInput: true, default: call.args.times },
  2681. // ]));
  2682. // call.args.times = result > call.args.times ? call.args.times : result;
  2683. // changeRequest = true;
  2684. // }
  2685. // }
  2686. }
  2687.  
  2688. let headers = requestHistory[this.uniqid].headers;
  2689. if (changeRequest) {
  2690. sourceData = JSON.stringify(testData);
  2691. headers['X-Auth-Signature'] = getSignature(headers, sourceData);
  2692. }
  2693.  
  2694. let signature = headers['X-Auth-Signature'];
  2695. if (signature) {
  2696. original.setRequestHeader.call(this, 'X-Auth-Signature', signature);
  2697. }
  2698. } catch (err) {
  2699. console.log("Request(send, " + this.uniqid + "):\n", sourceData, "Error:\n", err);
  2700. }
  2701. return sourceData;
  2702. }
  2703. /**
  2704. * Processing and substitution of incoming data
  2705. *
  2706. * Обработка и подмена входящих данных
  2707. */
  2708. async function checkChangeResponse(response) {
  2709. try {
  2710. isChange = false;
  2711. let nowTime = Math.round(Date.now() / 1000);
  2712. callsIdent = requestHistory[this.uniqid].calls;
  2713. respond = JSON.parse(response);
  2714. /**
  2715. * If the request returned an error removes the error (removes synchronization errors)
  2716. * Если запрос вернул ошибку удаляет ошибку (убирает ошибки синхронизации)
  2717. */
  2718. if (respond.error) {
  2719. isChange = true;
  2720. console.error(respond.error);
  2721. if (isChecked('showErrors')) {
  2722. popup.confirm(I18N('ERROR_MSG', {
  2723. name: respond.error.name,
  2724. description: respond.error.description,
  2725. }));
  2726. }
  2727. if (respond.error.name != 'AccountBan') {
  2728. delete respond.error;
  2729. respond.results = [];
  2730. }
  2731. }
  2732. let mainReward = null;
  2733. const allReward = {};
  2734. let countTypeReward = 0;
  2735. let readQuestInfo = false;
  2736. for (const call of respond.results) {
  2737. /**
  2738. * Obtaining initial data for completing quests
  2739. * Получение исходных данных для выполнения квестов
  2740. */
  2741. if (readQuestInfo) {
  2742. questsInfo[call.ident] = call.result.response;
  2743. }
  2744. /**
  2745. * Getting a user ID
  2746. * Получение идетификатора пользователя
  2747. */
  2748. if (call.ident == callsIdent['registration']) {
  2749. userId = call.result.response.userId;
  2750. if (localStorage['userId'] != userId) {
  2751. localStorage['newGiftSendIds'] = '';
  2752. localStorage['userId'] = userId;
  2753. }
  2754. await openOrMigrateDatabase(userId);
  2755. readQuestInfo = true;
  2756. }
  2757. /**
  2758. * Hiding donation offers 1
  2759. * Скрываем предложения доната 1
  2760. */
  2761. if (call.ident == callsIdent['billingGetAll'] && getSaveVal('noOfferDonat')) {
  2762. const billings = call.result.response?.billings;
  2763. const bundle = call.result.response?.bundle;
  2764. if (billings && bundle) {
  2765. call.result.response.billings = call.result.response.billings.filter((e) => ['repeatableOffer'].includes(e.type));
  2766. call.result.response.bundle = [];
  2767. isChange = true;
  2768. }
  2769. }
  2770. /**
  2771. * Hiding donation offers 2
  2772. * Скрываем предложения доната 2
  2773. */
  2774. if (getSaveVal('noOfferDonat') &&
  2775. (call.ident == callsIdent['offerGetAll'] ||
  2776. call.ident == callsIdent['specialOffer_getAll'])) {
  2777. let offers = call.result.response;
  2778. if (offers) {
  2779. call.result.response = offers.filter(
  2780. (e) => !['addBilling', 'bundleCarousel'].includes(e.type) || ['idleResource', 'stagesOffer'].includes(e.offerType)
  2781. );
  2782. isChange = true;
  2783. }
  2784. }
  2785. /**
  2786. * Hiding donation offers 3
  2787. * Скрываем предложения доната 3
  2788. */
  2789. if (getSaveVal('noOfferDonat') && call.result?.bundleUpdate) {
  2790. delete call.result.bundleUpdate;
  2791. isChange = true;
  2792. }
  2793. /**
  2794. * Hiding donation offers 4
  2795. * Скрываем предложения доната 4
  2796. */
  2797. if (call.result?.specialOffers) {
  2798. const offers = call.result.specialOffers;
  2799. call.result.specialOffers = offers.filter(
  2800. (e) => !['addBilling', 'bundleCarousel'].includes(e.type) || ['idleResource', 'stagesOffer'].includes(e.offerType)
  2801. );
  2802. isChange = true;
  2803. }
  2804. /**
  2805. * Copies a quiz question to the clipboard
  2806. * Копирует вопрос викторины в буфер обмена и получает на него ответ если есть
  2807. */
  2808. if (call.ident == callsIdent['quizGetNewQuestion']) {
  2809. let quest = call.result.response;
  2810. console.log(quest.question);
  2811. copyText(quest.question);
  2812. setProgress(I18N('QUESTION_COPY'), true);
  2813. quest.lang = null;
  2814. if (typeof NXFlashVars !== 'undefined') {
  2815. quest.lang = NXFlashVars.interface_lang;
  2816. }
  2817. lastQuestion = quest;
  2818. if (isChecked('getAnswer')) {
  2819. const answer = await getAnswer(lastQuestion);
  2820. let showText = '';
  2821. if (answer) {
  2822. lastAnswer = answer;
  2823. console.log(answer);
  2824. showText = `${I18N('ANSWER_KNOWN')}: ${answer}`;
  2825. } else {
  2826. showText = I18N('ANSWER_NOT_KNOWN');
  2827. }
  2828.  
  2829. try {
  2830. const hint = hintQuest(quest);
  2831. if (hint) {
  2832. showText += I18N('HINT') + hint;
  2833. }
  2834. } catch(e) {}
  2835.  
  2836. setProgress(showText, true);
  2837. }
  2838. }
  2839. /**
  2840. * Submits a question with an answer to the database
  2841. * Отправляет вопрос с ответом в базу данных
  2842. */
  2843. if (call.ident == callsIdent['quizAnswer']) {
  2844. const answer = call.result.response;
  2845. if (lastQuestion) {
  2846. const answerInfo = {
  2847. answer,
  2848. question: lastQuestion,
  2849. lang: null,
  2850. }
  2851. if (typeof NXFlashVars !== 'undefined') {
  2852. answerInfo.lang = NXFlashVars.interface_lang;
  2853. }
  2854. lastQuestion = null;
  2855. setTimeout(sendAnswerInfo, 0, answerInfo);
  2856. }
  2857. }
  2858. /**
  2859. * Get user data
  2860. * Получить даныне пользователя
  2861. */
  2862. if (call.ident == callsIdent['userGetInfo']) {
  2863. let user = call.result.response;
  2864. document.title = user.name;
  2865. userInfo = Object.assign({}, user);
  2866. delete userInfo.refillable;
  2867. if (!questsInfo['userGetInfo']) {
  2868. questsInfo['userGetInfo'] = user;
  2869. }
  2870. }
  2871. /**
  2872. * Start of the battle for recalculation
  2873. * Начало боя для прерасчета
  2874. */
  2875. if (call.ident == callsIdent['clanWarAttack'] ||
  2876. call.ident == callsIdent['crossClanWar_startBattle'] ||
  2877. call.ident == callsIdent['bossAttack'] ||
  2878. call.ident == callsIdent['battleGetReplay'] ||
  2879. call.ident == callsIdent['brawl_startBattle'] ||
  2880. call.ident == callsIdent['adventureSolo_turnStartBattle'] ||
  2881. call.ident == callsIdent['invasion_bossStart'] ||
  2882. call.ident == callsIdent['titanArenaStartBattle'] ||
  2883. call.ident == callsIdent['towerStartBattle'] ||
  2884. call.ident == callsIdent['adventure_turnStartBattle']) {
  2885. let battle = call.result.response.battle || call.result.response.replay;
  2886. if (call.ident == callsIdent['brawl_startBattle'] ||
  2887. call.ident == callsIdent['bossAttack'] ||
  2888. call.ident == callsIdent['towerStartBattle'] ||
  2889. call.ident == callsIdent['invasion_bossStart']) {
  2890. battle = call.result.response;
  2891. }
  2892. lastBattleInfo = battle;
  2893. if (call.ident == callsIdent['battleGetReplay'] && call.result.response.replay.type === "clan_raid") {
  2894. if (call?.result?.response?.replay?.result?.damage) {
  2895. const damages = Object.values(call.result.response.replay.result.damage);
  2896. const bossDamage = damages.reduce((a, v) => a + v, 0);
  2897. setProgress(I18N('BOSS_DAMAGE') + bossDamage.toLocaleString(), false, hideProgress);
  2898. continue;
  2899. }
  2900. }
  2901. if (!isChecked('preCalcBattle')) {
  2902. continue;
  2903. }
  2904. setProgress(I18N('BEING_RECALC'));
  2905. let battleDuration = 120;
  2906. try {
  2907. const typeBattle = getBattleType(battle.type);
  2908. battleDuration = +lib.data.battleConfig[typeBattle.split('_')[1]].config.battleDuration;
  2909. } catch (e) { }
  2910. //console.log(battle.type);
  2911. function getBattleInfo(battle, isRandSeed) {
  2912. return new Promise(function (resolve) {
  2913. if (isRandSeed) {
  2914. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  2915. }
  2916. BattleCalc(battle, getBattleType(battle.type), e => resolve(e));
  2917. });
  2918. }
  2919. let actions = [getBattleInfo(battle, false)]
  2920. let countTestBattle = getInput('countTestBattle');
  2921. if (call.ident == callsIdent['invasion_bossStart'] ) {
  2922. countTestBattle = 0;
  2923. }
  2924. if (call.ident == callsIdent['battleGetReplay']) {
  2925. battle.progress = [{ attackers: { input: ['auto', 0, 0, 'auto', 0, 0] } }];
  2926. }
  2927. for (let i = 0; i < countTestBattle; i++) {
  2928. actions.push(getBattleInfo(battle, true));
  2929. }
  2930. Promise.all(actions)
  2931. .then(e => {
  2932. e = e.map(n => ({win: n.result.win, time: n.battleTime}));
  2933. let firstBattle = e.shift();
  2934. const timer = Math.floor(battleDuration - firstBattle.time);
  2935. const min = ('00' + Math.floor(timer / 60)).slice(-2);
  2936. const sec = ('00' + Math.floor(timer - min * 60)).slice(-2);
  2937. let msg = `${I18N('THIS_TIME')} ${firstBattle.win ? I18N('VICTORY') : I18N('DEFEAT')}`;
  2938. if (e.length) {
  2939. const countWin = e.reduce((w, s) => w + s.win, 0);
  2940. msg += ` ${I18N('CHANCE_TO_WIN')}: ${Math.floor((countWin / e.length) * 100)}% (${e.length})`;
  2941. }
  2942. msg += `, ${min}:${sec}`
  2943. setProgress(msg, false, hideProgress)
  2944. });
  2945. }
  2946. //тест сохранки
  2947. /** Запоминаем команды в реплее*/
  2948. if (call.ident == callsIdent['battleGetReplay']) {
  2949. let battle = call.result.response.replay;
  2950. repleyBattle.attackers = battle.attackers;
  2951. repleyBattle.defenders = battle.defenders[0];
  2952. repleyBattle.effects = battle.effects.defenders;
  2953. repleyBattle.state = battle.progress[0].defenders.heroes;
  2954. repleyBattle.seed = battle.seed;
  2955. }
  2956. /** Нападение в турнире*/
  2957. if (call.ident == callsIdent['titanArenaStartBattle']) {
  2958. let bestBattle = getInput('countBattle');
  2959. let unrandom = getInput('needResource');
  2960. let maxPower = getInput('needResource2');
  2961. if (bestBattle * unrandom * maxPower == 0) {
  2962. let battle = call.result.response.battle;
  2963. if (bestBattle == 0) {
  2964. battle.progress = bestLordBattle[battle.typeId]?.progress;
  2965. }
  2966. if (unrandom == 0 && !!repleyBattle.seed) {
  2967. battle.seed = repleyBattle.seed;
  2968. }
  2969. if (maxPower == 0) {
  2970. battle.attackers = getTitansPack(Object.keys(battle.attackers));
  2971. }
  2972. isChange = true;
  2973. }
  2974. }
  2975. /** Тест боев с усилениями команд защиты*/
  2976. if (call.ident == callsIdent['chatAcceptChallenge']) {
  2977. let battle = call.result.response.battle;
  2978. addBuff(battle);
  2979. let testType = getInput('countBattle');
  2980. if (testType.slice(0, 1) == "-") {
  2981. testType = parseInt(testType.slice(1), 10);
  2982. switch (testType) {
  2983. case 1:
  2984. battle.defenders[0] = repleyBattle.defenders;
  2985. break; //наша атака против защиты из реплея
  2986. case 2:
  2987. battle.defenders[0] = repleyBattle.attackers;
  2988. break; //наша атака против атаки из реплея
  2989. case 3:
  2990. battle.attackers = repleyBattle.attackers;
  2991. break; //атака из реплея против защиты в чате
  2992. case 4:
  2993. battle.attackers = repleyBattle.defenders;
  2994. break; //защита из реплея против защиты в чате
  2995. case 5:
  2996. battle.attackers = repleyBattle.attackers;
  2997. battle.defenders[0] = repleyBattle.defenders;
  2998. break; //атака из реплея против защиты из реплея
  2999. case 6:
  3000. battle.attackers = repleyBattle.defenders;
  3001. battle.defenders[0] = repleyBattle.attackers;
  3002. break; //защита из реплея против атаки из реплея
  3003. case 7:
  3004. battle.attackers = repleyBattle.attackers;
  3005. battle.defenders[0] = repleyBattle.attackers;
  3006. break; //атака из реплея против атаки из реплея
  3007. case 8:
  3008. battle.attackers = repleyBattle.defenders;
  3009. battle.defenders[0] = repleyBattle.defenders;
  3010. break; //защита из реплея против защиты из реплея
  3011. case 15:
  3012. battle.attackers = repleyBattle.defenders;
  3013. battle.defenders[0] = repleyBattle.defenders;
  3014. break; //защита из реплея против защиты из реплея
  3015. }
  3016. }
  3017.  
  3018. isChange = true;
  3019. }
  3020. /** Тест боев с усилениями команд защиты тренировках*/
  3021. if (call.ident == callsIdent['demoBattles_startBattle']) {
  3022. let battle = call.result.response.battle;
  3023. addBuff(battle);
  3024. let testType = getInput('countBattle');
  3025. if (testType.slice(0, 1) == "-") {
  3026. testType = parseInt(testType.slice(1), 10);
  3027. switch (testType) {
  3028. case 1:
  3029. battle.defenders[0] = repleyBattle.defenders;
  3030. break; //наша атака против защиты из реплея
  3031. case 2:
  3032. battle.defenders[0] = repleyBattle.attackers;
  3033. break; //наша атака против атаки из реплея
  3034. case 3:
  3035. battle.attackers = repleyBattle.attackers;
  3036. break; //атака из реплея против защиты в чате
  3037. case 4:
  3038. battle.attackers = repleyBattle.defenders;
  3039. break; //защита из реплея против защиты в чате
  3040. case 5:
  3041. battle.attackers = repleyBattle.attackers;
  3042. battle.defenders[0] = repleyBattle.defenders;
  3043. break; //атака из реплея против защиты из реплея
  3044. case 6:
  3045. battle.attackers = repleyBattle.defenders;
  3046. battle.defenders[0] = repleyBattle.attackers;
  3047. break; //защита из реплея против атаки из реплея
  3048. case 7:
  3049. battle.attackers = repleyBattle.attackers;
  3050. battle.defenders[0] = repleyBattle.attackers;
  3051. break; //атака из реплея против атаки из реплея
  3052. case 8:
  3053. battle.attackers = repleyBattle.defenders;
  3054. battle.defenders[0] = repleyBattle.defenders;
  3055. break; //защита из реплея против защиты из реплея
  3056. }
  3057. }
  3058.  
  3059. isChange = true;
  3060. }
  3061. //тест сохранки
  3062. /**
  3063. * Start of the Asgard boss fight
  3064. * Начало боя с боссом Асгарда
  3065. */
  3066. if (call.ident == callsIdent['clanRaid_startBossBattle']) {
  3067. lastBossBattle = call.result.response.battle;
  3068. lastBossBattle.endTime = Date.now() + 160 * 1000;
  3069. if (isChecked('preCalcBattle')) {
  3070. const result = await Calc(lastBossBattle).then(e => e.progress[0].defenders.heroes[1].extra);
  3071. const bossDamage = result.damageTaken + result.damageTakenNextLevel;
  3072. setProgress(I18N('BOSS_DAMAGE') + bossDamage.toLocaleString(), false, hideProgress);
  3073. }
  3074. }
  3075. /**
  3076. * Cancel tutorial
  3077. * Отмена туториала
  3078. */
  3079. if (isCanceledTutorial && call.ident == callsIdent['tutorialGetInfo']) {
  3080. let chains = call.result.response.chains;
  3081. for (let n in chains) {
  3082. chains[n] = 9999;
  3083. }
  3084. isChange = true;
  3085. }
  3086. /**
  3087. * Opening keys and spheres of titan artifacts
  3088. * Открытие ключей и сфер артефактов титанов
  3089. */
  3090. if (artifactChestOpen &&
  3091. (call.ident == callsIdent[artifactChestOpenCallName] ||
  3092. (callsIdent[artifactChestOpenCallName] && callsIdent[artifactChestOpenCallName].includes(call.ident)))) {
  3093. let reward = call.result.response[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'];
  3094.  
  3095. reward.forEach(e => {
  3096. for (let f in e) {
  3097. if (!allReward[f]) {
  3098. allReward[f] = {};
  3099. }
  3100. for (let o in e[f]) {
  3101. if (!allReward[f][o]) {
  3102. allReward[f][o] = e[f][o];
  3103. countTypeReward++;
  3104. } else {
  3105. allReward[f][o] += e[f][o];
  3106. }
  3107. }
  3108. }
  3109. });
  3110.  
  3111. if (!call.ident.includes(artifactChestOpenCallName)) {
  3112. mainReward = call.result.response;
  3113. }
  3114. }
  3115.  
  3116. if (countTypeReward > 20) {
  3117. correctShowOpenArtifact = 3;
  3118. } else {
  3119. correctShowOpenArtifact = 0;
  3120. }
  3121.  
  3122. /**
  3123. * Sum the result of opening Pet Eggs
  3124. * Суммирование результата открытия яиц питомцев
  3125. */
  3126. if (isChecked('countControl') && call.ident == callsIdent['pet_chestOpen']) {
  3127. const rewards = call.result.response.rewards;
  3128. if (rewards.length > 10) {
  3129. /**
  3130. * Removing pet cards
  3131. * Убираем карточки петов
  3132. */
  3133. for (const reward of rewards) {
  3134. if (reward.petCard) {
  3135. delete reward.petCard;
  3136. }
  3137. }
  3138. }
  3139. rewards.forEach(e => {
  3140. for (let f in e) {
  3141. if (!allReward[f]) {
  3142. allReward[f] = {};
  3143. }
  3144. for (let o in e[f]) {
  3145. if (!allReward[f][o]) {
  3146. allReward[f][o] = e[f][o];
  3147. } else {
  3148. allReward[f][o] += e[f][o];
  3149. }
  3150. }
  3151. }
  3152. });
  3153. call.result.response.rewards = [allReward];
  3154. isChange = true;
  3155. }
  3156. /**
  3157. * Removing titan cards
  3158. * Убираем карточки титанов
  3159. */
  3160. if (call.ident == callsIdent['titanUseSummonCircle']) {
  3161. if (call.result.response.rewards.length > 10) {
  3162. for (const reward of call.result.response.rewards) {
  3163. if (reward.titanCard) {
  3164. delete reward.titanCard;
  3165. }
  3166. }
  3167. isChange = true;
  3168. }
  3169. }
  3170. /**
  3171. * Auto-repeat opening matryoshkas
  3172. * АвтоПовтор открытия матрешек
  3173. */
  3174. if (isChecked('countControl') && call.ident == callsIdent['consumableUseLootBox']) {
  3175. let [countLootBox, lootBox] = Object.entries(call.result.response).pop();
  3176. countLootBox = +countLootBox;
  3177. let newCount = 0;
  3178. if (lootBox?.consumable && lootBox.consumable[lastRussianDollId]) {
  3179. newCount += lootBox.consumable[lastRussianDollId];
  3180. delete lootBox.consumable[lastRussianDollId];
  3181. }
  3182. if (
  3183. newCount && (await popup.confirm(`${I18N('BTN_OPEN')} ${newCount} ${I18N('OPEN_DOLLS')}?`, [
  3184. { msg: I18N('BTN_OPEN'), result: true },
  3185. { msg: I18N('BTN_NO'), result: false, isClose: true },
  3186. ]))
  3187. ) {
  3188. const [count, recursionResult] = await openRussianDolls(lastRussianDollId, newCount);
  3189. countLootBox += +count;
  3190. mergeItemsObj(lootBox, recursionResult);
  3191. isChange = true;
  3192. }
  3193.  
  3194. if (this.massOpen) {
  3195. if (
  3196. await popup.confirm(I18N('OPEN_ALL_EQUIP_BOXES'), [
  3197. { msg: I18N('BTN_OPEN'), result: true },
  3198. { msg: I18N('BTN_NO'), result: false, isClose: true },
  3199. ])
  3200. ) {
  3201. const consumable = await Send({ calls: [{ name: 'inventoryGet', args: {}, ident: 'inventoryGet' }] }).then((e) =>
  3202. Object.entries(e.results[0].result.response.consumable)
  3203. );
  3204. const calls = [];
  3205. const deleteItems = {};
  3206. for (const [libId, amount] of consumable) {
  3207. if (libId != this.massOpen && libId >= 362 && libId <= 389) {
  3208. calls.push({
  3209. name: 'consumableUseLootBox',
  3210. args: { libId, amount },
  3211. ident: 'consumableUseLootBox_' + libId,
  3212. });
  3213. deleteItems[libId] = -amount;
  3214. }
  3215. }
  3216. const responses = await Send({ calls }).then((e) => e.results.map((r) => r.result.response).flat());
  3217.  
  3218. for (const loot of responses) {
  3219. const [count, result] = Object.entries(loot).pop();
  3220. countLootBox += +count;
  3221.  
  3222. mergeItemsObj(lootBox, result);
  3223. }
  3224. isChange = true;
  3225.  
  3226. this.onReadySuccess = () => {
  3227. cheats.updateInventory({ consumable: deleteItems });
  3228. cheats.refreshInventory();
  3229. };
  3230. }
  3231. }
  3232.  
  3233. if (isChange) {
  3234. call.result.response = {
  3235. [countLootBox]: lootBox,
  3236. };
  3237. }
  3238.  
  3239. }
  3240. /**
  3241. * Dungeon recalculation (fix endless cards)
  3242. * Прерасчет подземки (исправление бесконечных карт)
  3243. */
  3244. if (call.ident == callsIdent['dungeonStartBattle']) {
  3245. lastDungeonBattleData = call.result.response;
  3246. lastDungeonBattleStart = Date.now();
  3247. }
  3248. /**
  3249. * Getting the number of prediction cards
  3250. * Получение количества карт предсказаний
  3251. */
  3252. if (call.ident == callsIdent['inventoryGet']) {
  3253. countPredictionCard = call.result.response.consumable[81] || 0;
  3254. }
  3255. /**
  3256. * Getting subscription status
  3257. * Получение состояния подписки
  3258. */
  3259. if (call.ident == callsIdent['subscriptionGetInfo']) {
  3260. const subscription = call.result.response.subscription;
  3261. if (subscription) {
  3262. subEndTime = subscription.endTime * 1000;
  3263. }
  3264. }
  3265. /**
  3266. * Getting prediction cards
  3267. * Получение карт предсказаний
  3268. */
  3269. if (call.ident == callsIdent['questFarm']) {
  3270. const consumable = call.result.response?.consumable;
  3271. if (consumable && consumable[81]) {
  3272. countPredictionCard += consumable[81];
  3273. console.log(`Cards: ${countPredictionCard}`);
  3274. }
  3275. }
  3276. /**
  3277. * Hiding extra servers
  3278. * Скрытие лишних серверов
  3279. */
  3280. if (call.ident == callsIdent['serverGetAll'] && isChecked('hideServers')) {
  3281. let servers = call.result.response.users.map(s => s.serverId)
  3282. call.result.response.servers = call.result.response.servers.filter(s => servers.includes(s.id));
  3283. isChange = true;
  3284. }
  3285. /**
  3286. * Displays player positions in the adventure
  3287. * Отображает позиции игроков в приключении
  3288. */
  3289. if (call.ident == callsIdent['adventure_getLobbyInfo']) {
  3290. const users = Object.values(call.result.response.users);
  3291. const mapIdent = call.result.response.mapIdent;
  3292. const adventureId = call.result.response.adventureId;
  3293. const maps = {
  3294. adv_strongford_3pl_hell: 9,
  3295. adv_valley_3pl_hell: 10,
  3296. adv_ghirwil_3pl_hell: 11,
  3297. adv_angels_3pl_hell: 12,
  3298. }
  3299. let msg = I18N('MAP') + (mapIdent in maps ? maps[mapIdent] : adventureId);
  3300. msg += '<br>' + I18N('PLAYER_POS');
  3301. for (const user of users) {
  3302. msg += `<br>${user.user.name} - ${user.currentNode}`;
  3303. }
  3304. setProgress(msg, false, hideProgress);
  3305. }
  3306. /**
  3307. * Automatic launch of a raid at the end of the adventure
  3308. * Автоматический запуск рейда при окончании приключения
  3309. */
  3310. if (call.ident == callsIdent['adventure_end']) {
  3311. autoRaidAdventure()
  3312. }
  3313. /** Удаление лавки редкостей */
  3314. if (call.ident == callsIdent['missionRaid']) {
  3315. if (call.result?.heroesMerchant) {
  3316. delete call.result.heroesMerchant;
  3317. isChange = true;
  3318. }
  3319. }
  3320. /** missionTimer */
  3321. if (call.ident == callsIdent['missionStart']) {
  3322. missionBattle = call.result.response;
  3323. }
  3324. /** Награды турнира стихий */
  3325. if (call.ident == callsIdent['hallOfFameGetTrophies']) {
  3326. const trophys = call.result.response;
  3327. const calls = [];
  3328. for (const week in trophys) {
  3329. const trophy = trophys[week];
  3330. if (!trophy.championRewardFarmed) {
  3331. calls.push({
  3332. name: 'hallOfFameFarmTrophyReward',
  3333. args: { trophyId: week, rewardType: 'champion' },
  3334. ident: 'body_champion_' + week,
  3335. });
  3336. }
  3337. if (Object.keys(trophy.clanReward).length && !trophy.clanRewardFarmed) {
  3338. calls.push({
  3339. name: 'hallOfFameFarmTrophyReward',
  3340. args: { trophyId: week, rewardType: 'clan' },
  3341. ident: 'body_clan_' + week,
  3342. });
  3343. }
  3344. }
  3345. if (calls.length) {
  3346. Send({ calls })
  3347. .then((e) => e.results.map((e) => e.result.response))
  3348. .then(async results => {
  3349. let coin18 = 0,
  3350. coin19 = 0,
  3351. gold = 0,
  3352. starmoney = 0;
  3353. for (const r of results) {
  3354. coin18 += r?.coin ? +r.coin[18] : 0;
  3355. coin19 += r?.coin ? +r.coin[19] : 0;
  3356. gold += r?.gold ? +r.gold : 0;
  3357. starmoney += r?.starmoney ? +r.starmoney : 0;
  3358. }
  3359.  
  3360. let msg = I18N('ELEMENT_TOURNAMENT_REWARD') + '<br>';
  3361. if (coin18) {
  3362. msg += cheats.translate('LIB_COIN_NAME_18') + `: ${coin18}<br>`;
  3363. }
  3364. if (coin19) {
  3365. msg += cheats.translate('LIB_COIN_NAME_19') + `: ${coin19}<br>`;
  3366. }
  3367. if (gold) {
  3368. msg += cheats.translate('LIB_PSEUDO_COIN') + `: ${gold}<br>`;
  3369. }
  3370. if (starmoney) {
  3371. msg += cheats.translate('LIB_PSEUDO_STARMONEY') + `: ${starmoney}<br>`;
  3372. }
  3373.  
  3374. await popup.confirm(msg, [{ msg: I18N('BTN_OK'), result: 0 }]);
  3375. });
  3376. }
  3377. }
  3378. if (call.ident == callsIdent['clanDomination_getInfo']) {
  3379. clanDominationGetInfo = call.result.response;
  3380. }
  3381. if (call.ident == callsIdent['clanRaid_endBossBattle']) {
  3382. console.log(call.result.response);
  3383. const damage = Object.values(call.result.response.damage).reduce((a, e) => a + e);
  3384. if (call.result.response.result.afterInvalid) {
  3385. addProgress('<br>' + I18N('SERVER_NOT_ACCEPT'));
  3386. }
  3387. addProgress('<br>Server > ' + I18N('BOSS_DAMAGE') + damage.toLocaleString());
  3388. }
  3389. if (call.ident == callsIdent['invasion_getInfo']) {
  3390. const r = call.result.response;
  3391. if (r?.actions?.length) {
  3392. const boss = r.actions.find((e) => e.payload.id === 217);
  3393. invasionInfo.buff = r.buffAmount;
  3394. invasionInfo.bossLvl = boss.payload.level;
  3395. if (isChecked('tryFixIt_v2')) {
  3396. const pack = invasionDataPacks[invasionInfo.bossLvl];
  3397. setProgress(
  3398. I18N('INVASION_BOSS_BUFF', {
  3399. bossLvl: invasionInfo.bossLvl,
  3400. needBuff: pack.buff,
  3401. haveBuff: invasionInfo.buff
  3402. }),
  3403. false
  3404. );
  3405. }
  3406. }
  3407. }
  3408. if (call.ident == callsIdent['workshopBuff_create']) {
  3409. const r = call.result.response;
  3410. if (r.id == 1) {
  3411. invasionInfo.buff = r.amount;
  3412. if (isChecked('tryFixIt_v2')) {
  3413. const pack = invasionDataPacks[invasionInfo.bossLvl];
  3414. setProgress(
  3415. I18N('INVASION_BOSS_BUFF', {
  3416. bossLvl: invasionInfo.bossLvl,
  3417. needBuff: pack.buff,
  3418. haveBuff: invasionInfo.buff,
  3419. }),
  3420. false
  3421. );
  3422. }
  3423. }
  3424. }
  3425. /*
  3426. if (call.ident == callsIdent['chatGetAll'] && call.args.chatType == 'clanDomination' && !callsIdent['clanDomination_mapState']) {
  3427. this.onReadySuccess = async function () {
  3428. const result = await Send({
  3429. calls: [
  3430. {
  3431. name: 'clanDomination_mapState',
  3432. args: {},
  3433. ident: 'clanDomination_mapState',
  3434. },
  3435. ],
  3436. }).then((e) => e.results[0].result.response);
  3437. let townPositions = result.townPositions;
  3438. let positions = {};
  3439. for (let pos in townPositions) {
  3440. let townPosition = townPositions[pos];
  3441. positions[townPosition.position] = townPosition;
  3442. }
  3443. Object.assign(clanDominationGetInfo, {
  3444. townPositions: positions,
  3445. });
  3446. let userPositions = result.userPositions;
  3447. for (let pos in clanDominationGetInfo.townPositions) {
  3448. let townPosition = clanDominationGetInfo.townPositions[pos];
  3449. if (townPosition.status) {
  3450. userPositions[townPosition.userId] = +pos;
  3451. }
  3452. }
  3453. cheats.updateMap(result);
  3454. };
  3455. }
  3456. if (call.ident == callsIdent['clanDomination_mapState']) {
  3457. const townPositions = call.result.response.townPositions;
  3458. const userPositions = call.result.response.userPositions;
  3459. for (let pos in townPositions) {
  3460. let townPos = townPositions[pos];
  3461. if (townPos.status) {
  3462. userPositions[townPos.userId] = townPos.position;
  3463. }
  3464. }
  3465. isChange = true;
  3466. }
  3467. */
  3468. }
  3469.  
  3470. if (mainReward && artifactChestOpen) {
  3471. console.log(allReward);
  3472. mainReward[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'] = [allReward];
  3473. artifactChestOpen = false;
  3474. artifactChestOpenCallName = '';
  3475. isChange = true;
  3476. }
  3477. } catch(err) {
  3478. console.log("Request(response, " + this.uniqid + "):\n", "Error:\n", response, err);
  3479. }
  3480.  
  3481. if (isChange) {
  3482. Object.defineProperty(this, 'responseText', {
  3483. writable: true
  3484. });
  3485. this.responseText = JSON.stringify(respond);
  3486. }
  3487. }
  3488.  
  3489. /** Добавляет в бой эффекты усиления*/
  3490. function addBuff(battle) {
  3491. let effects = battle.effects;
  3492. let buffType = getInput('needResource2');
  3493. if (-1 < buffType && buffType < 7) {
  3494. let percentBuff = getInput('needResource');
  3495. effects.defenders = {};
  3496. effects.defenders[buffs[buffType]] = percentBuff;
  3497. } else if (buffType.slice(0, 1) == "-" || isChecked('treningBattle')) {
  3498. buffType = parseInt(buffType.slice(1), 10);
  3499. effects.defenders = repleyBattle.effects;
  3500. battle.defenders[0] = repleyBattle.defenders;
  3501. let def = battle.defenders[0];
  3502. if (buffType == 1) {
  3503. for (let i in def) {
  3504. let state = def[i].state;
  3505. state.hp = state.maxHp;
  3506. state.energy = 0;
  3507. state.isDead = false;
  3508. }
  3509. } else if (buffType == 2 || isChecked('finishingBattle')) {
  3510. for (let i in def) {
  3511. let state2 = def[i].state;
  3512. let rState = repleyBattle.state[i];
  3513. if (!!rState) {
  3514. state2.hp = rState.hp;
  3515. state2.energy = rState.energy;
  3516. state2.isDead = rState.isDead;
  3517. } else {
  3518. state2.hp = 0;
  3519. state2.energy = 0;
  3520. state2.isDead = true;
  3521. }
  3522. }
  3523. }
  3524. }
  3525. }
  3526. const buffs = ['percentBuffAll_allAttacks', 'percentBuffAll_armor', 'percentBuffAll_magicResist', 'percentBuffAll_physicalAttack', 'percentBuffAll_magicPower', 'percentDamageBuff_dot', 'percentBuffAll_healing', 'percentBuffAllForFallenAllies', 'percentBuffAll_energyIncrease', 'percentIncomeDamageReduce_any', 'percentIncomeDamageReduce_physical', 'percentIncomeDamageReduce_magic', 'percentIncomeDamageReduce_dot', 'percentBuffHp', 'percentBuffByPerk_energyIncrease_8', 'percentBuffByPerk_energyIncrease_5', 'percentBuffByPerk_energyIncrease_4', 'percentBuffByPerk_allAttacks_5', 'percentBuffByPerk_allAttacks_4', 'percentBuffByPerk_allAttacks_9', 'percentBuffByPerk_castSpeed_7', 'percentBuffByPerk_castSpeed_6', 'percentBuffByPerk_castSpeed_10', 'percentBuffByPerk_armorPenetration_6', 'percentBuffByPerk_physicalAttack_6', 'percentBuffByPerk_armorPenetration_10', 'percentBuffByPerk_physicalAttack_10', 'percentBuffByPerk_magicPower_7', 'percentDamageBuff_any','percentDamageBuff_physical','percentDamageBuff_magic','corruptedBoss_25_80_1_100_10','tutorialPetUlt_1.2','tutorialBossPercentDamage_1','corruptedBoss_50_80_1_100_10','corruptedBoss_75_80_1_100_10','corruptedBoss_80_80_1_100_10','percentBuffByPerk_castSpeed_4','percentBuffByPerk_energyIncrease_7','percentBuffByPerk_castSpeed_9','percentBuffByPerk_castSpeed_8','bossStageBuff_1000000_20000','bossStageBuff_1500000_30000','bossStageBuff_2000000_40000','bossStageBuff_3000000_50000','bossStageBuff_4000000_60000','bossStageBuff_5000000_70000','bossStageBuff_7500000_80000','bossStageBuff_11000000_90000','bossStageBuff_15000000_100000','bossStageBuff_20000000_120000','bossStageBuff_30000000_150000','bossStageBuff_40000000_200000','bossStageBuff_50000000_250000','percentBuffPet_strength','percentBuffPet_castSpeed','percentBuffPet_petEnergyIncrease','stormPowerBuff_100_1000','stormPowerBuff_100','changeStarSphereIncomingDamage_any','changeBlackHoleDamage','buffSpeedWhenStarfall','changeTeamStartEnergy','decreaseStarSphereDamage','avoidAllBlackholeDamageOnce','groveKeeperAvoidBlackholeDamageChance_3','undeadPreventsNightmares_3','engeneerIncreaseStarMachineIncomingDamage_3','overloadHealDamageStarSphere','nightmareDeathGiveLifesteal_100','starfallIncreaseAllyHeal_9_100','decreaseStarSphereDamage_4','increaseNightmaresIncomingDamageByCount','debuffNightmareOnSpawnFrom_7_hp','damageNightmareGiveEnergy','ultEnergyCompensationOnPlanetParade_6','bestDamagerBeforeParadeGetsImprovedBuff_any','starSphereDeathGiveEnergy','bestDamagerOnParadeBecomesImmortal_any','preventNightmare','buffStatWithHealing_physicalAttack_magic_100','buffStatWithHealing_magicPower_physical_100','buffStatWithHealing_hp_dot_100','replaceHealingWithDamage_magic','critWithRetaliation_10_dot','posessionWithBuffStat_25_20_5_10','energyBurnDamageWithEffect_magic_Silence_5_5','percentBuffHp','percentBuffAll_energyIncrease','percentBuffAll_magicResist','percentBuffAll_armor','percentIncomeDamageReduce_any','percentBuffAll_healing','percentIncomeDamageReduce_any','percentBuffHp','percentBuffAll_energyIncrease','percentIncomeDamageReduce_any','percentBuffHp','percentBuffByPerk_castSpeed_All','percentBuffAll_castSpeed'];
  3527.  
  3528. /**
  3529. * Request an answer to a question
  3530. *
  3531. * Запрос ответа на вопрос
  3532. */
  3533. async function getAnswer(question) {
  3534. // c29tZSBzdHJhbmdlIHN5bWJvbHM=
  3535. /*const quizAPI = new ZingerYWebsiteAPI('getAnswer.php', arguments, { question });
  3536. return new Promise((resolve, reject) => {
  3537. quizAPI.request().then((data) => {
  3538. if (data.result) {
  3539. resolve(data.result);
  3540. } else {
  3541. resolve(false);
  3542. }
  3543. }).catch((error) => {
  3544. console.error(error);
  3545. resolve(false);
  3546. });
  3547. })*/
  3548. }
  3549.  
  3550. /**
  3551. * Submitting a question and answer to a database
  3552. *
  3553. * Отправка вопроса и ответа в базу данных
  3554. */
  3555. function sendAnswerInfo(answerInfo) {
  3556. // c29tZSBub25zZW5zZQ==
  3557. /*const quizAPI = new ZingerYWebsiteAPI('setAnswer.php', arguments, { answerInfo });
  3558. quizAPI.request().then((data) => {
  3559. if (data.result) {
  3560. console.log(I18N('SENT_QUESTION'));
  3561. }
  3562. });*/
  3563. }
  3564.  
  3565. /**
  3566. * Returns the battle type by preset type
  3567. *
  3568. * Возвращает тип боя по типу пресета
  3569. */
  3570. function getBattleType(strBattleType) {
  3571. if (!strBattleType) {
  3572. return null;
  3573. }
  3574. switch (strBattleType) {
  3575. case 'titan_pvp':
  3576. return 'get_titanPvp';
  3577. case 'titan_pvp_manual':
  3578. case 'titan_clan_pvp':
  3579. case 'clan_pvp_titan':
  3580. case 'clan_global_pvp_titan':
  3581. case 'brawl_titan':
  3582. case 'challenge_titan':
  3583. case 'titan_mission':
  3584. return 'get_titanPvpManual';
  3585. case 'clan_raid': // Asgard Boss // Босс асгарда
  3586. case 'adventure': // Adventures // Приключения
  3587. case 'clan_global_pvp':
  3588. case 'epic_brawl':
  3589. case 'clan_pvp':
  3590. return 'get_clanPvp';
  3591. case 'dungeon_titan':
  3592. case 'titan_tower':
  3593. return 'get_titan';
  3594. case 'tower':
  3595. case 'clan_dungeon':
  3596. return 'get_tower';
  3597. case 'pve':
  3598. case 'mission':
  3599. return 'get_pve';
  3600. case 'mission_boss':
  3601. return 'get_missionBoss';
  3602. case 'challenge':
  3603. case 'pvp_manual':
  3604. return 'get_pvpManual';
  3605. case 'grand':
  3606. case 'arena':
  3607. case 'pvp':
  3608. case 'clan_domination':
  3609. return 'get_pvp';
  3610. case 'core':
  3611. return 'get_core';
  3612. default: {
  3613. if (strBattleType.includes('invasion')) {
  3614. return 'get_invasion';
  3615. }
  3616. if (strBattleType.includes('boss')) {
  3617. return 'get_boss';
  3618. }
  3619. if (strBattleType.includes('titan_arena')) {
  3620. return 'get_titanPvpManual';
  3621. }
  3622. return 'get_clanPvp';
  3623. }
  3624. }
  3625. }
  3626. /**
  3627. * Returns the class name of the passed object
  3628. *
  3629. * Возвращает название класса переданного объекта
  3630. */
  3631. function getClass(obj) {
  3632. return {}.toString.call(obj).slice(8, -1);
  3633. }
  3634. /**
  3635. * Calculates the request signature
  3636. *
  3637. * Расчитывает сигнатуру запроса
  3638. */
  3639. this.getSignature = function(headers, data) {
  3640. const sign = {
  3641. signature: '',
  3642. length: 0,
  3643. add: function (text) {
  3644. this.signature += text;
  3645. if (this.length < this.signature.length) {
  3646. this.length = 3 * (this.signature.length + 1) >> 1;
  3647. }
  3648. },
  3649. }
  3650. sign.add(headers["X-Request-Id"]);
  3651. sign.add(':');
  3652. sign.add(headers["X-Auth-Token"]);
  3653. sign.add(':');
  3654. sign.add(headers["X-Auth-Session-Id"]);
  3655. sign.add(':');
  3656. sign.add(data);
  3657. sign.add(':');
  3658. sign.add('LIBRARY-VERSION=1');
  3659. sign.add('UNIQUE-SESSION-ID=' + headers["X-Env-Unique-Session-Id"]);
  3660.  
  3661. return md5(sign.signature);
  3662. }
  3663. /**
  3664. * Creates an interface
  3665. *
  3666. * Создает интерфейс
  3667. */
  3668. function createInterface() {
  3669. popup.init();
  3670. scriptMenu.init({
  3671. showMenu: true
  3672. });
  3673. scriptMenu.addHeader(GM_info.script.name, justInfo);
  3674. scriptMenu.addHeader('v' + GM_info.script.version);
  3675. }
  3676.  
  3677. function addControls() {
  3678. createInterface();
  3679. const checkboxDetails = scriptMenu.addDetails(I18N('SETTINGS'));
  3680. for (let name in checkboxes) {
  3681. if (checkboxes[name].hide) {
  3682. continue;
  3683. }
  3684. checkboxes[name].cbox = scriptMenu.addCheckbox(checkboxes[name].label, checkboxes[name].title, checkboxDetails);
  3685. /**
  3686. * Getting the state of checkboxes from storage
  3687. * Получаем состояние чекбоксов из storage
  3688. */
  3689. let val = storage.get(name, null);
  3690. if (val != null) {
  3691. checkboxes[name].cbox.checked = val;
  3692. } else {
  3693. storage.set(name, checkboxes[name].default);
  3694. checkboxes[name].cbox.checked = checkboxes[name].default;
  3695. }
  3696. /**
  3697. * Tracing the change event of the checkbox for writing to storage
  3698. * Отсеживание события изменения чекбокса для записи в storage
  3699. */
  3700. checkboxes[name].cbox.dataset['name'] = name;
  3701. checkboxes[name].cbox.addEventListener('change', async function (event) {
  3702. const nameCheckbox = this.dataset['name'];
  3703. /*
  3704. if (this.checked && nameCheckbox == 'cancelBattle') {
  3705. this.checked = false;
  3706. if (await popup.confirm(I18N('MSG_BAN_ATTENTION'), [
  3707. { msg: I18N('BTN_NO_I_AM_AGAINST'), result: true },
  3708. { msg: I18N('BTN_YES_I_AGREE'), result: false },
  3709. ])) {
  3710. return;
  3711. }
  3712. this.checked = true;
  3713. }
  3714. */
  3715. storage.set(nameCheckbox, this.checked);
  3716. })
  3717. }
  3718.  
  3719. const inputDetails = scriptMenu.addDetails(I18N('VALUES'));
  3720. for (let name in inputs) {
  3721. inputs[name].input = scriptMenu.addInputText(inputs[name].title, false, inputDetails);
  3722. /**
  3723. * Get inputText state from storage
  3724. * Получаем состояние inputText из storage
  3725. */
  3726. let val = storage.get(name, null);
  3727. if (val != null) {
  3728. inputs[name].input.value = val;
  3729. } else {
  3730. storage.set(name, inputs[name].default);
  3731. inputs[name].input.value = inputs[name].default;
  3732. }
  3733. /**
  3734. * Tracing a field change event for a record in storage
  3735. * Отсеживание события изменения поля для записи в storage
  3736. */
  3737. inputs[name].input.dataset['name'] = name;
  3738. inputs[name].input.addEventListener('input', function () {
  3739. const inputName = this.dataset['name'];
  3740. let value = +this.value;
  3741. if (!value || Number.isNaN(value)) {
  3742. value = storage.get(inputName, inputs[inputName].default);
  3743. inputs[name].input.value = value;
  3744. }
  3745. storage.set(inputName, value);
  3746. })
  3747. }
  3748. const inputDetails2 = scriptMenu.addDetails(I18N('SAVING'));
  3749. for (let name in inputs2) {
  3750. inputs2[name].input = scriptMenu.addInputText(inputs2[name].title, false, inputDetails2);
  3751. /**
  3752. * Get inputText state from storage
  3753. * Получаем состояние inputText из storage
  3754. */
  3755. let val = storage.get(name, null);
  3756. if (val != null) {
  3757. inputs2[name].input.value = val;
  3758. } else {
  3759. storage.set(name, inputs2[name].default);
  3760. inputs2[name].input.value = inputs2[name].default;
  3761. }
  3762. /**
  3763. * Tracing a field change event for a record in storage
  3764. * Отсеживание события изменения поля для записи в storage
  3765. */
  3766. inputs2[name].input.dataset['name'] = name;
  3767. inputs2[name].input.addEventListener('input', function () {
  3768. const inputName = this.dataset['name'];
  3769. let value = +this.value;
  3770. if (!value || Number.isNaN(value)) {
  3771. value = storage.get(inputName, inputs2[inputName].default);
  3772. inputs2[name].input.value = value;
  3773. }
  3774. storage.set(inputName, value);
  3775. })
  3776. }
  3777. /* const inputDetails3 = scriptMenu.addDetails(I18N('USER_ID'));
  3778. for (let name in inputs3) {
  3779. inputs3[name].input = scriptMenu.addInputText(inputs3[name].title, false, inputDetails3);
  3780. /**
  3781. * Get inputText state from storage
  3782. * Получаем состояние inputText из storage
  3783. *
  3784. let val = storage.get(name, null);
  3785. if (val != null) {
  3786. inputs3[name].input.value = val;
  3787. } else {
  3788. storage.set(name, inputs3[name].default);
  3789. inputs3[name].input.value = inputs3[name].default;
  3790. }
  3791. /**
  3792. * Tracing a field change event for a record in storage
  3793. * Отсеживание события изменения поля для записи в storage
  3794. *
  3795. inputs3[name].input.dataset['name'] = name;
  3796. inputs3[name].input.addEventListener('input', function () {
  3797. const inputName = this.dataset['name'];
  3798. let value = +this.value;
  3799. if (!value || Number.isNaN(value)) {
  3800. value = storage.get(inputName, inputs3[inputName].default);
  3801. inputs3[name].input.value = value;
  3802. }
  3803. storage.set(inputName, value);
  3804. })
  3805. }*/
  3806. }
  3807.  
  3808. /**
  3809. * Sending a request
  3810. *
  3811. * Отправка запроса
  3812. */
  3813. function send(json, callback, pr) {
  3814. if (typeof json == 'string') {
  3815. json = JSON.parse(json);
  3816. }
  3817. for (const call of json.calls) {
  3818. if (!call?.context?.actionTs) {
  3819. call.context = {
  3820. actionTs: Math.floor(performance.now())
  3821. }
  3822. }
  3823. }
  3824. json = JSON.stringify(json);
  3825. /**
  3826. * We get the headlines of the previous intercepted request
  3827. * Получаем заголовки предыдущего перехваченого запроса
  3828. */
  3829. let headers = lastHeaders;
  3830. /**
  3831. * We increase the header of the query Certifier by 1
  3832. * Увеличиваем заголовок идетификатора запроса на 1
  3833. */
  3834. headers["X-Request-Id"]++;
  3835. /**
  3836. * We calculate the title with the signature
  3837. * Расчитываем заголовок с сигнатурой
  3838. */
  3839. headers["X-Auth-Signature"] = getSignature(headers, json);
  3840. /**
  3841. * Create a new ajax request
  3842. * Создаем новый AJAX запрос
  3843. */
  3844. let xhr = new XMLHttpRequest;
  3845. /**
  3846. * Indicate the previously saved URL for API queries
  3847. * Указываем ранее сохраненный URL для API запросов
  3848. */
  3849. xhr.open('POST', apiUrl, true);
  3850. /**
  3851. * Add the function to the event change event
  3852. * Добавляем функцию к событию смены статуса запроса
  3853. */
  3854. xhr.onreadystatechange = function() {
  3855. /**
  3856. * If the result of the request is obtained, we call the flask function
  3857. * Если результат запроса получен вызываем колбек функцию
  3858. */
  3859. if(xhr.readyState == 4) {
  3860. callback(xhr.response, pr);
  3861. }
  3862. };
  3863. /**
  3864. * Indicate the type of request
  3865. * Указываем тип запроса
  3866. */
  3867. xhr.responseType = 'json';
  3868. /**
  3869. * We set the request headers
  3870. * Задаем заголовки запроса
  3871. */
  3872. for(let nameHeader in headers) {
  3873. let head = headers[nameHeader];
  3874. xhr.setRequestHeader(nameHeader, head);
  3875. }
  3876. /**
  3877. * Sending a request
  3878. * Отправляем запрос
  3879. */
  3880. xhr.send(json);
  3881. }
  3882.  
  3883. let hideTimeoutProgress = 0;
  3884. /**
  3885. * Hide progress
  3886. *
  3887. * Скрыть прогресс
  3888. */
  3889. function hideProgress(timeout) {
  3890. timeout = timeout || 0;
  3891. clearTimeout(hideTimeoutProgress);
  3892. hideTimeoutProgress = setTimeout(function () {
  3893. scriptMenu.setStatus('');
  3894. }, timeout);
  3895. }
  3896. /**
  3897. * Progress display
  3898. *
  3899. * Отображение прогресса
  3900. */
  3901. function setProgress(text, hide, onclick) {
  3902. scriptMenu.setStatus(text, onclick);
  3903. hide = hide || false;
  3904. if (hide) {
  3905. hideProgress(3000);
  3906. }
  3907. }
  3908.  
  3909. /**
  3910. * Progress added
  3911. *
  3912. * Дополнение прогресса
  3913. */
  3914. function addProgress(text) {
  3915. scriptMenu.addStatus(text);
  3916. }
  3917.  
  3918. /**
  3919. * Returns the timer value depending on the subscription
  3920. *
  3921. * Возвращает значение таймера в зависимости от подписки
  3922. */
  3923. function getTimer(time, div) {
  3924. let speedDiv = 5;
  3925. if (subEndTime < Date.now()) {
  3926. speedDiv = div || 1.5;
  3927. }
  3928. return Math.max(Math.ceil(time / speedDiv + 1.5), 4);
  3929. }
  3930.  
  3931. function startSlave() {
  3932. const sFix = new slaveFixBattle();
  3933. sFix.wsStart();
  3934. }
  3935.  
  3936. this.testFuntions = {
  3937. hideProgress,
  3938. setProgress,
  3939. addProgress,
  3940. masterFix: false,
  3941. startSlave,
  3942. };
  3943.  
  3944. /**
  3945. * Calculates HASH MD5 from string
  3946. *
  3947. * Расчитывает HASH MD5 из строки
  3948. *
  3949. * [js-md5]{@link https://github.com/emn178/js-md5}
  3950. *
  3951. * @namespace md5
  3952. * @version 0.7.3
  3953. * @author Chen, Yi-Cyuan [emn178@gmail.com]
  3954. * @copyright Chen, Yi-Cyuan 2014-2017
  3955. * @license MIT
  3956. */
  3957. !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 _}))}();
  3958.  
  3959. /**
  3960. * Script for beautiful dialog boxes
  3961. *
  3962. * Скрипт для красивых диалоговых окошек
  3963. */
  3964. const popup = new (function () {
  3965. this.popUp,
  3966. this.downer,
  3967. this.middle,
  3968. this.msgText,
  3969. this.buttons = [];
  3970. this.checkboxes = [];
  3971. this.dialogPromice = null;
  3972. this.isInit = false;
  3973.  
  3974. this.init = function () {
  3975. if (this.isInit) {
  3976. return;
  3977. }
  3978. addStyle();
  3979. addBlocks();
  3980. addEventListeners();
  3981. this.isInit = true;
  3982. }
  3983.  
  3984. const addEventListeners = () => {
  3985. document.addEventListener('keyup', (e) => {
  3986. if (e.key == 'Escape') {
  3987. if (this.dialogPromice) {
  3988. const { func, result } = this.dialogPromice;
  3989. this.dialogPromice = null;
  3990. popup.hide();
  3991. func(result);
  3992. }
  3993. }
  3994. });
  3995. }
  3996.  
  3997. const addStyle = () => {
  3998. let style = document.createElement('style');
  3999. style.innerText = `
  4000. .PopUp_ {
  4001. position: absolute;
  4002. min-width: 300px;
  4003. max-width: 500px;
  4004. max-height: 600px;
  4005. background-color: #190e08e6;
  4006. z-index: 10001;
  4007. top: 169px;
  4008. left: 345px;
  4009. border: 3px #ce9767 solid;
  4010. border-radius: 10px;
  4011. display: flex;
  4012. flex-direction: column;
  4013. justify-content: space-around;
  4014. padding: 15px 9px;
  4015. box-sizing: border-box;
  4016. }
  4017.  
  4018. .PopUp_back {
  4019. position: absolute;
  4020. background-color: #00000066;
  4021. width: 100%;
  4022. height: 100%;
  4023. z-index: 10000;
  4024. top: 0;
  4025. left: 0;
  4026. }
  4027.  
  4028. .PopUp_close {
  4029. width: 40px;
  4030. height: 40px;
  4031. position: absolute;
  4032. right: -18px;
  4033. top: -18px;
  4034. border: 3px solid #c18550;
  4035. border-radius: 20px;
  4036. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  4037. background-position-y: 3px;
  4038. box-shadow: -1px 1px 3px black;
  4039. cursor: pointer;
  4040. box-sizing: border-box;
  4041. }
  4042.  
  4043. .PopUp_close:hover {
  4044. filter: brightness(1.2);
  4045. }
  4046.  
  4047. .PopUp_crossClose {
  4048. width: 100%;
  4049. height: 100%;
  4050. background-size: 65%;
  4051. background-position: center;
  4052. background-repeat: no-repeat;
  4053. 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")
  4054. }
  4055.  
  4056. .PopUp_blocks {
  4057. width: 100%;
  4058. height: 50%;
  4059. display: flex;
  4060. justify-content: space-evenly;
  4061. align-items: center;
  4062. flex-wrap: wrap;
  4063. justify-content: center;
  4064. }
  4065.  
  4066. .PopUp_blocks:last-child {
  4067. margin-top: 25px;
  4068. }
  4069.  
  4070. .PopUp_buttons {
  4071. display: flex;
  4072. margin: 7px 10px;
  4073. flex-direction: column;
  4074. }
  4075.  
  4076. .PopUp_button {
  4077. background-color: #52A81C;
  4078. border-radius: 5px;
  4079. box-shadow: inset 0px -4px 10px, inset 0px 3px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  4080. cursor: pointer;
  4081. padding: 4px 12px 6px;
  4082. }
  4083.  
  4084. .PopUp_input {
  4085. text-align: center;
  4086. font-size: 16px;
  4087. height: 27px;
  4088. border: 1px solid #cf9250;
  4089. border-radius: 9px 9px 0px 0px;
  4090. background: transparent;
  4091. color: #fce1ac;
  4092. padding: 1px 10px;
  4093. box-sizing: border-box;
  4094. box-shadow: 0px 0px 4px, 0px 0px 0px 3px #ce9767;
  4095. }
  4096.  
  4097. .PopUp_checkboxes {
  4098. display: flex;
  4099. flex-direction: column;
  4100. margin: 15px 15px -5px 15px;
  4101. align-items: flex-start;
  4102. }
  4103.  
  4104. .PopUp_ContCheckbox {
  4105. margin: 2px 0px;
  4106. }
  4107.  
  4108. .PopUp_checkbox {
  4109. position: absolute;
  4110. z-index: -1;
  4111. opacity: 0;
  4112. }
  4113. .PopUp_checkbox+label {
  4114. display: inline-flex;
  4115. align-items: center;
  4116. user-select: none;
  4117.  
  4118. font-size: 15px;
  4119. font-family: sans-serif;
  4120. font-weight: 600;
  4121. font-stretch: condensed;
  4122. letter-spacing: 1px;
  4123. color: #fce1ac;
  4124. text-shadow: 0px 0px 1px;
  4125. }
  4126. .PopUp_checkbox+label::before {
  4127. content: '';
  4128. display: inline-block;
  4129. width: 20px;
  4130. height: 20px;
  4131. border: 1px solid #cf9250;
  4132. border-radius: 7px;
  4133. margin-right: 7px;
  4134. }
  4135. .PopUp_checkbox:checked+label::before {
  4136. 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");
  4137. }
  4138.  
  4139. .PopUp_input::placeholder {
  4140. color: #fce1ac75;
  4141. }
  4142.  
  4143. .PopUp_input:focus {
  4144. outline: 0;
  4145. }
  4146.  
  4147. .PopUp_input + .PopUp_button {
  4148. border-radius: 0px 0px 5px 5px;
  4149. padding: 2px 18px 5px;
  4150. }
  4151.  
  4152. .PopUp_button:hover {
  4153. filter: brightness(1.2);
  4154. }
  4155.  
  4156. .PopUp_button:active {
  4157. box-shadow: inset 0px 5px 10px, inset 0px 1px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  4158. }
  4159.  
  4160. .PopUp_text {
  4161. font-size: 22px;
  4162. font-family: sans-serif;
  4163. font-weight: 600;
  4164. font-stretch: condensed;
  4165. white-space: pre-wrap;
  4166. letter-spacing: 1px;
  4167. text-align: center;
  4168. }
  4169.  
  4170. .PopUp_buttonText {
  4171. color: #E4FF4C;
  4172. text-shadow: 0px 1px 2px black;
  4173. }
  4174.  
  4175. .PopUp_msgText {
  4176. color: #FDE5B6;
  4177. text-shadow: 0px 0px 2px;
  4178. }
  4179.  
  4180. .PopUp_hideBlock {
  4181. display: none;
  4182. }
  4183. `;
  4184. document.head.appendChild(style);
  4185. }
  4186.  
  4187. const addBlocks = () => {
  4188. this.back = document.createElement('div');
  4189. this.back.classList.add('PopUp_back');
  4190. this.back.classList.add('PopUp_hideBlock');
  4191. document.body.append(this.back);
  4192.  
  4193. this.popUp = document.createElement('div');
  4194. this.popUp.classList.add('PopUp_');
  4195. this.back.append(this.popUp);
  4196.  
  4197. let upper = document.createElement('div')
  4198. upper.classList.add('PopUp_blocks');
  4199. this.popUp.append(upper);
  4200.  
  4201. this.middle = document.createElement('div')
  4202. this.middle.classList.add('PopUp_blocks');
  4203. this.middle.classList.add('PopUp_checkboxes');
  4204. this.popUp.append(this.middle);
  4205.  
  4206. this.downer = document.createElement('div')
  4207. this.downer.classList.add('PopUp_blocks');
  4208. this.popUp.append(this.downer);
  4209.  
  4210. this.msgText = document.createElement('div');
  4211. this.msgText.classList.add('PopUp_text', 'PopUp_msgText');
  4212. upper.append(this.msgText);
  4213. }
  4214.  
  4215. this.showBack = function () {
  4216. this.back.classList.remove('PopUp_hideBlock');
  4217. }
  4218.  
  4219. this.hideBack = function () {
  4220. this.back.classList.add('PopUp_hideBlock');
  4221. }
  4222.  
  4223. this.show = function () {
  4224. if (this.checkboxes.length) {
  4225. this.middle.classList.remove('PopUp_hideBlock');
  4226. }
  4227. this.showBack();
  4228. this.popUp.classList.remove('PopUp_hideBlock');
  4229. this.popUp.style.left = (window.innerWidth - this.popUp.offsetWidth) / 2 + 'px';
  4230. this.popUp.style.top = (window.innerHeight - this.popUp.offsetHeight) / 3 + 'px';
  4231. }
  4232.  
  4233. this.hide = function () {
  4234. this.hideBack();
  4235. this.popUp.classList.add('PopUp_hideBlock');
  4236. }
  4237.  
  4238. this.addAnyButton = (option) => {
  4239. const contButton = document.createElement('div');
  4240. contButton.classList.add('PopUp_buttons');
  4241. this.downer.append(contButton);
  4242.  
  4243. let inputField = {
  4244. value: option.result || option.default
  4245. }
  4246. if (option.isInput) {
  4247. inputField = document.createElement('input');
  4248. inputField.type = 'text';
  4249. if (option.placeholder) {
  4250. inputField.placeholder = option.placeholder;
  4251. }
  4252. if (option.default) {
  4253. inputField.value = option.default;
  4254. }
  4255. inputField.classList.add('PopUp_input');
  4256. contButton.append(inputField);
  4257. }
  4258.  
  4259. const button = document.createElement('div');
  4260. button.classList.add('PopUp_button');
  4261. button.title = option.title || '';
  4262. contButton.append(button);
  4263.  
  4264. const buttonText = document.createElement('div');
  4265. buttonText.classList.add('PopUp_text', 'PopUp_buttonText');
  4266. buttonText.innerHTML = option.msg;
  4267. button.append(buttonText);
  4268.  
  4269. return { button, contButton, inputField };
  4270. }
  4271.  
  4272. this.addCloseButton = () => {
  4273. let button = document.createElement('div')
  4274. button.classList.add('PopUp_close');
  4275. this.popUp.append(button);
  4276.  
  4277. let crossClose = document.createElement('div')
  4278. crossClose.classList.add('PopUp_crossClose');
  4279. button.append(crossClose);
  4280.  
  4281. return { button, contButton: button };
  4282. }
  4283.  
  4284. this.addButton = (option, buttonClick) => {
  4285.  
  4286. const { button, contButton, inputField } = option.isClose ? this.addCloseButton() : this.addAnyButton(option);
  4287. if (option.isClose) {
  4288. this.dialogPromice = { func: buttonClick, result: option.result };
  4289. }
  4290. button.addEventListener('click', () => {
  4291. let result = '';
  4292. if (option.isInput) {
  4293. result = inputField.value;
  4294. }
  4295. if (option.isClose || option.isCancel) {
  4296. this.dialogPromice = null;
  4297. }
  4298. buttonClick(result);
  4299. });
  4300.  
  4301. this.buttons.push(contButton);
  4302. }
  4303.  
  4304. this.clearButtons = () => {
  4305. while (this.buttons.length) {
  4306. this.buttons.pop().remove();
  4307. }
  4308. }
  4309.  
  4310. this.addCheckBox = (checkBox) => {
  4311. const contCheckbox = document.createElement('div');
  4312. contCheckbox.classList.add('PopUp_ContCheckbox');
  4313. this.middle.append(contCheckbox);
  4314.  
  4315. const checkbox = document.createElement('input');
  4316. checkbox.type = 'checkbox';
  4317. checkbox.id = 'PopUpCheckbox' + this.checkboxes.length;
  4318. checkbox.dataset.name = checkBox.name;
  4319. checkbox.checked = checkBox.checked;
  4320. checkbox.label = checkBox.label;
  4321. checkbox.title = checkBox.title || '';
  4322. checkbox.classList.add('PopUp_checkbox');
  4323. contCheckbox.appendChild(checkbox)
  4324.  
  4325. const checkboxLabel = document.createElement('label');
  4326. checkboxLabel.innerText = checkBox.label;
  4327. checkboxLabel.title = checkBox.title || '';
  4328. checkboxLabel.setAttribute('for', checkbox.id);
  4329. contCheckbox.appendChild(checkboxLabel);
  4330.  
  4331. this.checkboxes.push(checkbox);
  4332. }
  4333.  
  4334. this.clearCheckBox = () => {
  4335. this.middle.classList.add('PopUp_hideBlock');
  4336. while (this.checkboxes.length) {
  4337. this.checkboxes.pop().parentNode.remove();
  4338. }
  4339. }
  4340.  
  4341. this.setMsgText = (text) => {
  4342. this.msgText.innerHTML = text;
  4343. }
  4344.  
  4345. this.getCheckBoxes = () => {
  4346. const checkBoxes = [];
  4347.  
  4348. for (const checkBox of this.checkboxes) {
  4349. checkBoxes.push({
  4350. name: checkBox.dataset.name,
  4351. label: checkBox.label,
  4352. checked: checkBox.checked
  4353. });
  4354. }
  4355.  
  4356. return checkBoxes;
  4357. }
  4358.  
  4359. this.confirm = async (msg, buttOpt, checkBoxes = []) => {
  4360. if (!this.isInit) {
  4361. this.init();
  4362. }
  4363. this.clearButtons();
  4364. this.clearCheckBox();
  4365. return new Promise((complete, failed) => {
  4366. this.setMsgText(msg);
  4367. if (!buttOpt) {
  4368. buttOpt = [{ msg: 'Ok', result: true, isInput: false }];
  4369. }
  4370. for (const checkBox of checkBoxes) {
  4371. this.addCheckBox(checkBox);
  4372. }
  4373. for (let butt of buttOpt) {
  4374. this.addButton(butt, (result) => {
  4375. result = result || butt.result;
  4376. complete(result);
  4377. popup.hide();
  4378. });
  4379. if (butt.isCancel) {
  4380. this.dialogPromice = { func: complete, result: butt.result };
  4381. }
  4382. }
  4383. this.show();
  4384. });
  4385. }
  4386.  
  4387. });
  4388.  
  4389. /**
  4390. * Script control panel
  4391. *
  4392. * Панель управления скриптом
  4393. */
  4394. const scriptMenu = new (function () {
  4395.  
  4396. this.mainMenu,
  4397. this.buttons = [],
  4398. this.checkboxes = [];
  4399. this.option = {
  4400. showMenu: false,
  4401. showDetails: {}
  4402. };
  4403.  
  4404. this.init = function (option = {}) {
  4405. this.option = Object.assign(this.option, option);
  4406. this.option.showDetails = this.loadShowDetails();
  4407. addStyle();
  4408. addBlocks();
  4409. }
  4410.  
  4411. const addStyle = () => {
  4412. style = document.createElement('style');
  4413. style.innerText = `
  4414. .scriptMenu_status {
  4415. position: absolute;
  4416. z-index: 10001;
  4417. white-space: pre-wrap; //тест для выравнивания кнопок
  4418. /* max-height: 30px; */
  4419. top: -1px;
  4420. left: 30%;
  4421. cursor: pointer;
  4422. border-radius: 0px 0px 10px 10px;
  4423. background: #190e08e6;
  4424. border: 1px #ce9767 solid;
  4425. font-size: 18px;
  4426. font-family: sans-serif;
  4427. font-weight: 600;
  4428. font-stretch: condensed;
  4429. letter-spacing: 1px;
  4430. color: #fce1ac;
  4431. text-shadow: 0px 0px 1px;
  4432. transition: 0.5s;
  4433. padding: 2px 10px 3px;
  4434. }
  4435. .scriptMenu_statusHide {
  4436. top: -35px;
  4437. height: 30px;
  4438. overflow: hidden;
  4439. }
  4440. .scriptMenu_label {
  4441. position: absolute;
  4442. top: 30%;
  4443. left: -4px;
  4444. z-index: 9999;
  4445. cursor: pointer;
  4446. width: 30px;
  4447. height: 30px;
  4448. background: radial-gradient(circle, #47a41b 0%, #1a2f04 100%);
  4449. border: 1px solid #1a2f04;
  4450. border-radius: 5px;
  4451. box-shadow:
  4452. inset 0px 2px 4px #83ce26,
  4453. inset 0px -4px 6px #1a2f04,
  4454. 0px 0px 2px black,
  4455. 0px 0px 0px 2px #ce9767;
  4456. }
  4457. .scriptMenu_label:hover {
  4458. filter: brightness(1.2);
  4459. }
  4460. .scriptMenu_arrowLabel {
  4461. width: 100%;
  4462. height: 100%;
  4463. background-size: 75%;
  4464. background-position: center;
  4465. background-repeat: no-repeat;
  4466. 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");
  4467. box-shadow: 0px 1px 2px #000;
  4468. border-radius: 5px;
  4469. filter: drop-shadow(0px 1px 2px #000D);
  4470. }
  4471. .scriptMenu_main {
  4472. position: absolute;
  4473. max-width: 285px;
  4474. z-index: 9999;
  4475. top: 50%;
  4476. transform: translateY(-40%);
  4477. background: #190e08e6;
  4478. border: 1px #ce9767 solid;
  4479. border-radius: 0px 10px 10px 0px;
  4480. border-left: none;
  4481. padding: 5px 10px 5px 5px;
  4482. box-sizing: border-box;
  4483. font-size: 15px;
  4484. font-family: sans-serif;
  4485. font-weight: 600;
  4486. font-stretch: condensed;
  4487. letter-spacing: 1px;
  4488. color: #fce1ac;
  4489. text-shadow: 0px 0px 1px;
  4490. transition: 1s;
  4491. display: flex;
  4492. flex-direction: column;
  4493. flex-wrap: nowrap;
  4494. }
  4495. .scriptMenu_showMenu {
  4496. display: none;
  4497. }
  4498. .scriptMenu_showMenu:checked~.scriptMenu_main {
  4499. left: 0px;
  4500. }
  4501. .scriptMenu_showMenu:not(:checked)~.scriptMenu_main {
  4502. left: -300px;
  4503. }
  4504. .scriptMenu_divInput {
  4505. margin: 2px;
  4506. }
  4507. .scriptMenu_divInputText {
  4508. margin: 2px;
  4509. align-self: center;
  4510. display: flex;
  4511. }
  4512. .scriptMenu_checkbox {
  4513. position: absolute;
  4514. z-index: -1;
  4515. opacity: 0;
  4516. }
  4517. .scriptMenu_checkbox+label {
  4518. display: inline-flex;
  4519. align-items: center;
  4520. user-select: none;
  4521. }
  4522. .scriptMenu_checkbox+label::before {
  4523. content: '';
  4524. display: inline-block;
  4525. width: 20px;
  4526. height: 20px;
  4527. border: 1px solid #cf9250;
  4528. border-radius: 7px;
  4529. margin-right: 7px;
  4530. }
  4531. .scriptMenu_checkbox:checked+label::before {
  4532. 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");
  4533. }
  4534. .scriptMenu_close {
  4535. width: 40px;
  4536. height: 40px;
  4537. position: absolute;
  4538. right: -18px;
  4539. top: -18px;
  4540. border: 3px solid #c18550;
  4541. border-radius: 20px;
  4542. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  4543. background-position-y: 3px;
  4544. box-shadow: -1px 1px 3px black;
  4545. cursor: pointer;
  4546. box-sizing: border-box;
  4547. }
  4548. .scriptMenu_close:hover {
  4549. filter: brightness(1.2);
  4550. }
  4551. .scriptMenu_crossClose {
  4552. width: 100%;
  4553. height: 100%;
  4554. background-size: 65%;
  4555. background-position: center;
  4556. background-repeat: no-repeat;
  4557. 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")
  4558. }
  4559. .scriptMenu_button {
  4560. user-select: none;
  4561. border-radius: 5px;
  4562. cursor: pointer;
  4563. padding: 5px 14px 8px;
  4564. margin: 4px;
  4565. background: radial-gradient(circle, rgba(165,120,56,1) 80%, rgba(0,0,0,1) 110%);
  4566. box-shadow: inset 0px -4px 6px #442901, inset 0px 1px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  4567. }
  4568. .scriptMenu_button:hover {
  4569. filter: brightness(1.2);
  4570. }
  4571. .scriptMenu_button:active {
  4572. box-shadow: inset 0px 4px 6px #442901, inset 0px 4px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  4573. }
  4574. .scriptMenu_buttonText {
  4575. color: #fce5b7;
  4576. text-shadow: 0px 1px 2px black;
  4577. text-align: center;
  4578. }
  4579. .scriptMenu_header {
  4580. text-align: center;
  4581. align-self: center;
  4582. font-size: 15px;
  4583. margin: 0px 15px;
  4584. }
  4585. .scriptMenu_header a {
  4586. color: #fce5b7;
  4587. text-decoration: none;
  4588. }
  4589. .scriptMenu_InputText {
  4590. text-align: center;
  4591. width: 130px;
  4592. height: 24px;
  4593. border: 1px solid #cf9250;
  4594. border-radius: 9px;
  4595. background: transparent;
  4596. color: #fce1ac;
  4597. padding: 0px 10px;
  4598. box-sizing: border-box;
  4599. }
  4600. .scriptMenu_InputText:focus {
  4601. filter: brightness(1.2);
  4602. outline: 0;
  4603. }
  4604. .scriptMenu_InputText::placeholder {
  4605. color: #fce1ac75;
  4606. }
  4607. .scriptMenu_Summary {
  4608. cursor: pointer;
  4609. margin-left: 7px;
  4610. }
  4611. .scriptMenu_Details {
  4612. align-self: center;
  4613. }
  4614. `;
  4615. document.head.appendChild(style);
  4616. }
  4617.  
  4618. const addBlocks = () => {
  4619. const main = document.createElement('div');
  4620. document.body.appendChild(main);
  4621.  
  4622. this.status = document.createElement('div');
  4623. this.status.classList.add('scriptMenu_status');
  4624. this.setStatus('');
  4625. main.appendChild(this.status);
  4626.  
  4627. const label = document.createElement('label');
  4628. label.classList.add('scriptMenu_label');
  4629. label.setAttribute('for', 'checkbox_showMenu');
  4630. main.appendChild(label);
  4631.  
  4632. const arrowLabel = document.createElement('div');
  4633. arrowLabel.classList.add('scriptMenu_arrowLabel');
  4634. label.appendChild(arrowLabel);
  4635.  
  4636. const checkbox = document.createElement('input');
  4637. checkbox.type = 'checkbox';
  4638. checkbox.id = 'checkbox_showMenu';
  4639. checkbox.checked = this.option.showMenu;
  4640. checkbox.classList.add('scriptMenu_showMenu');
  4641. main.appendChild(checkbox);
  4642.  
  4643. this.mainMenu = document.createElement('div');
  4644. this.mainMenu.classList.add('scriptMenu_main');
  4645. main.appendChild(this.mainMenu);
  4646.  
  4647. const closeButton = document.createElement('label');
  4648. closeButton.classList.add('scriptMenu_close');
  4649. closeButton.setAttribute('for', 'checkbox_showMenu');
  4650. this.mainMenu.appendChild(closeButton);
  4651.  
  4652. const crossClose = document.createElement('div');
  4653. crossClose.classList.add('scriptMenu_crossClose');
  4654. closeButton.appendChild(crossClose);
  4655. }
  4656.  
  4657. this.setStatus = (text, onclick) => {
  4658. if (!text) {
  4659. this.status.classList.add('scriptMenu_statusHide');
  4660. this.status.innerHTML = '';
  4661. } else {
  4662. this.status.classList.remove('scriptMenu_statusHide');
  4663. this.status.innerHTML = text;
  4664. }
  4665.  
  4666. if (typeof onclick == 'function') {
  4667. this.status.addEventListener("click", onclick, {
  4668. once: true
  4669. });
  4670. }
  4671. }
  4672.  
  4673. this.addStatus = (text) => {
  4674. if (!this.status.innerHTML) {
  4675. this.status.classList.remove('scriptMenu_statusHide');
  4676. }
  4677. this.status.innerHTML += text;
  4678. }
  4679.  
  4680. /**
  4681. * Adding a text element
  4682. *
  4683. * Добавление текстового элемента
  4684. * @param {String} text text // текст
  4685. * @param {Function} func Click function // функция по клику
  4686. * @param {HTMLDivElement} main parent // родитель
  4687. */
  4688. this.addHeader = (text, func, main) => {
  4689. main = main || this.mainMenu;
  4690. const header = document.createElement('div');
  4691. header.classList.add('scriptMenu_header');
  4692. header.innerHTML = text;
  4693. if (typeof func == 'function') {
  4694. header.addEventListener('click', func);
  4695. }
  4696. main.appendChild(header);
  4697. }
  4698.  
  4699. /**
  4700. * Adding a button
  4701. *
  4702. * Добавление кнопки
  4703. * @param {String} text
  4704. * @param {Function} func
  4705. * @param {String} title
  4706. * @param {HTMLDivElement} main parent // родитель
  4707. */
  4708. this.addButton = (text, func, title, main) => {
  4709. main = main || this.mainMenu;
  4710. const button = document.createElement('div');
  4711. button.classList.add('scriptMenu_button');
  4712. button.title = title;
  4713. button.addEventListener('click', func);
  4714. main.appendChild(button);
  4715.  
  4716. const buttonText = document.createElement('div');
  4717. buttonText.classList.add('scriptMenu_buttonText');
  4718. buttonText.innerText = text;
  4719. button.appendChild(buttonText);
  4720. this.buttons.push(button);
  4721.  
  4722. return button;
  4723. }
  4724.  
  4725. /**
  4726. * Adding checkbox
  4727. *
  4728. * Добавление чекбокса
  4729. * @param {String} label
  4730. * @param {String} title
  4731. * @param {HTMLDivElement} main parent // родитель
  4732. * @returns
  4733. */
  4734. this.addCheckbox = (label, title, main) => {
  4735. main = main || this.mainMenu;
  4736. const divCheckbox = document.createElement('div');
  4737. divCheckbox.classList.add('scriptMenu_divInput');
  4738. divCheckbox.title = title;
  4739. main.appendChild(divCheckbox);
  4740.  
  4741. const checkbox = document.createElement('input');
  4742. checkbox.type = 'checkbox';
  4743. checkbox.id = 'scriptMenuCheckbox' + this.checkboxes.length;
  4744. checkbox.classList.add('scriptMenu_checkbox');
  4745. divCheckbox.appendChild(checkbox)
  4746.  
  4747. const checkboxLabel = document.createElement('label');
  4748. checkboxLabel.innerText = label;
  4749. checkboxLabel.setAttribute('for', checkbox.id);
  4750. divCheckbox.appendChild(checkboxLabel);
  4751.  
  4752. this.checkboxes.push(checkbox);
  4753. return checkbox;
  4754. }
  4755.  
  4756. /**
  4757. * Adding input field
  4758. *
  4759. * Добавление поля ввода
  4760. * @param {String} title
  4761. * @param {String} placeholder
  4762. * @param {HTMLDivElement} main parent // родитель
  4763. * @returns
  4764. */
  4765. this.addInputText = (title, placeholder, main) => {
  4766. main = main || this.mainMenu;
  4767. const divInputText = document.createElement('div');
  4768. divInputText.classList.add('scriptMenu_divInputText');
  4769. divInputText.title = title;
  4770. main.appendChild(divInputText);
  4771.  
  4772. const newInputText = document.createElement('input');
  4773. newInputText.type = 'text';
  4774. if (placeholder) {
  4775. newInputText.placeholder = placeholder;
  4776. }
  4777. newInputText.classList.add('scriptMenu_InputText');
  4778. divInputText.appendChild(newInputText)
  4779. return newInputText;
  4780. }
  4781.  
  4782. /**
  4783. * Adds a dropdown block
  4784. *
  4785. * Добавляет раскрывающийся блок
  4786. * @param {String} summary
  4787. * @param {String} name
  4788. * @returns
  4789. */
  4790. this.addDetails = (summaryText, name = null) => {
  4791. const details = document.createElement('details');
  4792. details.classList.add('scriptMenu_Details');
  4793. this.mainMenu.appendChild(details);
  4794.  
  4795. const summary = document.createElement('summary');
  4796. summary.classList.add('scriptMenu_Summary');
  4797. summary.innerText = summaryText;
  4798. if (name) {
  4799. const self = this;
  4800. details.open = this.option.showDetails[name];
  4801. details.dataset.name = name;
  4802. summary.addEventListener('click', () => {
  4803. self.option.showDetails[details.dataset.name] = !details.open;
  4804. self.saveShowDetails(self.option.showDetails);
  4805. });
  4806. }
  4807. details.appendChild(summary);
  4808.  
  4809. return details;
  4810. }
  4811.  
  4812. /**
  4813. * Saving the expanded state of the details blocks
  4814. *
  4815. * Сохранение состояния развенутости блоков details
  4816. * @param {*} value
  4817. */
  4818. this.saveShowDetails = (value) => {
  4819. localStorage.setItem('scriptMenu_showDetails', JSON.stringify(value));
  4820. }
  4821.  
  4822. /**
  4823. * Loading the state of expanded blocks details
  4824. *
  4825. * Загрузка состояния развенутости блоков details
  4826. * @returns
  4827. */
  4828. this.loadShowDetails = () => {
  4829. let showDetails = localStorage.getItem('scriptMenu_showDetails');
  4830.  
  4831. if (!showDetails) {
  4832. return {};
  4833. }
  4834.  
  4835. try {
  4836. showDetails = JSON.parse(showDetails);
  4837. } catch (e) {
  4838. return {};
  4839. }
  4840.  
  4841. return showDetails;
  4842. }
  4843. });
  4844.  
  4845. /**
  4846. * Пример использования
  4847. scriptMenu.init();
  4848. scriptMenu.addHeader('v1.508');
  4849. scriptMenu.addCheckbox('testHack', 'Тестовый взлом игры!');
  4850. scriptMenu.addButton('Запуск!', () => console.log('click'), 'подсказака');
  4851. scriptMenu.addInputText('input подсказака');
  4852. */
  4853. /**
  4854. * Game Library
  4855. *
  4856. * Игровая библиотека
  4857. */
  4858. class Library {
  4859. defaultLibUrl = 'https://heroesru-a.akamaihd.net/vk/v1101/lib/lib.json';
  4860.  
  4861. constructor() {
  4862. if (!Library.instance) {
  4863. Library.instance = this;
  4864. }
  4865.  
  4866. return Library.instance;
  4867. }
  4868.  
  4869. async load() {
  4870. try {
  4871. await this.getUrlLib();
  4872. console.log(this.defaultLibUrl);
  4873. this.data = await fetch(this.defaultLibUrl).then(e => e.json())
  4874. } catch (error) {
  4875. console.error('Не удалось загрузить библиотеку', error)
  4876. }
  4877. }
  4878.  
  4879. async getUrlLib() {
  4880. try {
  4881. const db = new Database('hw_cache', 'cache');
  4882. await db.open();
  4883. const cacheLibFullUrl = await db.get('lib/lib.json.gz', false);
  4884. this.defaultLibUrl = cacheLibFullUrl.fullUrl.split('.gz').shift();
  4885. } catch(e) {}
  4886. }
  4887.  
  4888. getData(id) {
  4889. return this.data[id];
  4890. }
  4891.  
  4892. setData(data) {
  4893. this.data = data;
  4894. }
  4895. }
  4896.  
  4897. this.lib = new Library();
  4898. /**
  4899. * Database
  4900. *
  4901. * База данных
  4902. */
  4903. class Database {
  4904. constructor(dbName, storeName) {
  4905. this.dbName = dbName;
  4906. this.storeName = storeName;
  4907. this.db = null;
  4908. }
  4909.  
  4910. async open() {
  4911. return new Promise((resolve, reject) => {
  4912. const request = indexedDB.open(this.dbName);
  4913.  
  4914. request.onerror = () => {
  4915. reject(new Error(`Failed to open database ${this.dbName}`));
  4916. };
  4917.  
  4918. request.onsuccess = () => {
  4919. this.db = request.result;
  4920. resolve();
  4921. };
  4922.  
  4923. request.onupgradeneeded = (event) => {
  4924. const db = event.target.result;
  4925. if (!db.objectStoreNames.contains(this.storeName)) {
  4926. db.createObjectStore(this.storeName);
  4927. }
  4928. };
  4929. });
  4930. }
  4931.  
  4932. async set(key, value) {
  4933. return new Promise((resolve, reject) => {
  4934. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4935. const store = transaction.objectStore(this.storeName);
  4936. const request = store.put(value, key);
  4937.  
  4938. request.onerror = () => {
  4939. reject(new Error(`Failed to save value with key ${key}`));
  4940. };
  4941.  
  4942. request.onsuccess = () => {
  4943. resolve();
  4944. };
  4945. });
  4946. }
  4947.  
  4948. async get(key, def) {
  4949. return new Promise((resolve, reject) => {
  4950. const transaction = this.db.transaction([this.storeName], 'readonly');
  4951. const store = transaction.objectStore(this.storeName);
  4952. const request = store.get(key);
  4953.  
  4954. request.onerror = () => {
  4955. resolve(def);
  4956. };
  4957.  
  4958. request.onsuccess = () => {
  4959. resolve(request.result);
  4960. };
  4961. });
  4962. }
  4963.  
  4964. async delete(key) {
  4965. return new Promise((resolve, reject) => {
  4966. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4967. const store = transaction.objectStore(this.storeName);
  4968. const request = store.delete(key);
  4969.  
  4970. request.onerror = () => {
  4971. reject(new Error(`Failed to delete value with key ${key}`));
  4972. };
  4973.  
  4974. request.onsuccess = () => {
  4975. resolve();
  4976. };
  4977. });
  4978. }
  4979. }
  4980.  
  4981. /**
  4982. * Returns the stored value
  4983. *
  4984. * Возвращает сохраненное значение
  4985. */
  4986. function getSaveVal(saveName, def) {
  4987. const result = storage.get(saveName, def);
  4988. return result;
  4989. }
  4990.  
  4991. /**
  4992. * Stores value
  4993. *
  4994. * Сохраняет значение
  4995. */
  4996. function setSaveVal(saveName, value) {
  4997. storage.set(saveName, value);
  4998. }
  4999.  
  5000. /**
  5001. * Database initialization
  5002. *
  5003. * Инициализация базы данных
  5004. */
  5005. const db = new Database(GM_info.script.name, 'settings');
  5006.  
  5007. /**
  5008. * Data store
  5009. *
  5010. * Хранилище данных
  5011. */
  5012. const storage = {
  5013. userId: 0,
  5014. /**
  5015. * Default values
  5016. *
  5017. * Значения по умолчанию
  5018. */
  5019. values: [
  5020. ...Object.entries(checkboxes).map(e => ({ [e[0]]: e[1].default })),
  5021. ...Object.entries(inputs).map(e => ({ [e[0]]: e[1].default })),
  5022. ...Object.entries(inputs2).map(e => ({ [e[0]]: e[1].default })),
  5023. //...Object.entries(inputs3).map(e => ({ [e[0]]: e[1].default })),
  5024. ].reduce((acc, obj) => ({ ...acc, ...obj }), {}),
  5025. name: GM_info.script.name,
  5026. get: function (key, def) {
  5027. if (key in this.values) {
  5028. return this.values[key];
  5029. }
  5030. return def;
  5031. },
  5032. set: function (key, value) {
  5033. this.values[key] = value;
  5034. db.set(this.userId, this.values).catch(
  5035. e => null
  5036. );
  5037. localStorage[this.name + ':' + key] = value;
  5038. },
  5039. delete: function (key) {
  5040. delete this.values[key];
  5041. db.set(this.userId, this.values);
  5042. delete localStorage[this.name + ':' + key];
  5043. }
  5044. }
  5045.  
  5046. /**
  5047. * Returns all keys from localStorage that start with prefix (for migration)
  5048. *
  5049. * Возвращает все ключи из localStorage которые начинаются с prefix (для миграции)
  5050. */
  5051. function getAllValuesStartingWith(prefix) {
  5052. const values = [];
  5053. for (let i = 0; i < localStorage.length; i++) {
  5054. const key = localStorage.key(i);
  5055. if (key.startsWith(prefix)) {
  5056. const val = localStorage.getItem(key);
  5057. const keyValue = key.split(':')[1];
  5058. values.push({ key: keyValue, val });
  5059. }
  5060. }
  5061. return values;
  5062. }
  5063.  
  5064. /**
  5065. * Opens or migrates to a database
  5066. *
  5067. * Открывает или мигрирует в базу данных
  5068. */
  5069. async function openOrMigrateDatabase(userId) {
  5070. storage.userId = userId;
  5071. try {
  5072. await db.open();
  5073. } catch(e) {
  5074. return;
  5075. }
  5076. let settings = await db.get(userId, false);
  5077.  
  5078. if (settings) {
  5079. storage.values = settings;
  5080. return;
  5081. }
  5082.  
  5083. const values = getAllValuesStartingWith(GM_info.script.name);
  5084. for (const value of values) {
  5085. let val = null;
  5086. try {
  5087. val = JSON.parse(value.val);
  5088. } catch {
  5089. break;
  5090. }
  5091. storage.values[value.key] = val;
  5092. }
  5093. await db.set(userId, storage.values);
  5094. }
  5095.  
  5096. class ZingerYWebsiteAPI {
  5097.  
  5098. }
  5099.  
  5100. //тест парсер подарков
  5101. class GiftCodeCollector {
  5102. constructor(filterCodes = []) {
  5103. /** Массив кодов которые возвращать не нужно */
  5104. this.collectedGiftCodes = filterCodes;
  5105. this.codes = [];
  5106. }
  5107.  
  5108. async fetchData() {
  5109. const response = await fetch('https://community-api.hero-wars.com/api/posts/limit/10');
  5110. const data = await response.json();
  5111. return data.data;
  5112. }
  5113.  
  5114. async getGiftCodes() {
  5115. const data = await this.fetchData();
  5116. data.forEach((post) => {
  5117. let code = '';
  5118. post.attributes.body.forEach((body) => {
  5119. if (body.type !== 'paragraph') {
  5120. return;
  5121. }
  5122.  
  5123. const bodyText = body.data.text;
  5124. const giftUrl = this.getGiftUrl(bodyText);
  5125. const urlText = giftUrl || bodyText;
  5126.  
  5127. const findCode = this.getCodeFromText(urlText);
  5128. if (findCode) {
  5129. code = findCode;
  5130. }
  5131. });
  5132. if (!code || this.collectedGiftCodes.includes(code)) {
  5133. return;
  5134. }
  5135. this.codes.push(code);
  5136. });
  5137. return this.codes;
  5138. }
  5139.  
  5140. getGiftUrl(text) {
  5141. const regex = /href=([\"\'])(.*?bit\.ly.*?)\1/;
  5142. const matches = text.match(regex);
  5143. return matches ? matches[2] : null;
  5144. }
  5145.  
  5146. getCodeFromText(text) {
  5147. const regex = /gift_id=(\w{10,32})/;
  5148. const matches = text.match(regex);
  5149. return matches ? matches[1] : null;
  5150. }
  5151. }
  5152.  
  5153. /**
  5154. * Sending expeditions
  5155. *
  5156. * Отправка экспедиций
  5157. */
  5158. function checkExpedition() {
  5159. return new Promise((resolve, reject) => {
  5160. const expedition = new Expedition(resolve, reject);
  5161. expedition.start();
  5162. });
  5163. }
  5164.  
  5165. class Expedition {
  5166. checkExpedInfo = {
  5167. calls: [
  5168. {
  5169. name: 'expeditionGet',
  5170. args: {},
  5171. ident: 'expeditionGet',
  5172. },
  5173. {
  5174. name: 'heroGetAll',
  5175. args: {},
  5176. ident: 'heroGetAll',
  5177. },
  5178. ],
  5179. };
  5180.  
  5181. constructor(resolve, reject) {
  5182. this.resolve = resolve;
  5183. this.reject = reject;
  5184. }
  5185.  
  5186. async start() {
  5187. const data = await Send(JSON.stringify(this.checkExpedInfo));
  5188.  
  5189. const expedInfo = data.results[0].result.response;
  5190. const dataHeroes = data.results[1].result.response;
  5191. const dataExped = { useHeroes: [], exped: [] };
  5192. const calls = [];
  5193.  
  5194. /**
  5195. * Adding expeditions to collect
  5196. * Добавляем экспедиции для сбора
  5197. */
  5198. let countGet = 0;
  5199. for (var n in expedInfo) {
  5200. const exped = expedInfo[n];
  5201. const dateNow = Date.now() / 1000;
  5202. if (exped.status == 2 && exped.endTime != 0 && dateNow > exped.endTime) {
  5203. countGet++;
  5204. calls.push({
  5205. name: 'expeditionFarm',
  5206. args: { expeditionId: exped.id },
  5207. ident: 'expeditionFarm_' + exped.id,
  5208. });
  5209. } else {
  5210. dataExped.useHeroes = dataExped.useHeroes.concat(exped.heroes);
  5211. }
  5212. if (exped.status == 1) {
  5213. dataExped.exped.push({ id: exped.id, power: exped.power });
  5214. }
  5215. }
  5216. dataExped.exped = dataExped.exped.sort((a, b) => b.power - a.power);
  5217.  
  5218. /**
  5219. * Putting together a list of heroes
  5220. * Собираем список героев
  5221. */
  5222. const heroesArr = [];
  5223. for (let n in dataHeroes) {
  5224. const hero = dataHeroes[n];
  5225. if (hero.xp > 0 && !dataExped.useHeroes.includes(hero.id)) {
  5226. let heroPower = hero.power;
  5227. // Лара Крофт * 3
  5228. if (hero.id == 63 && hero.color >= 16) {
  5229. heroPower *= 3;
  5230. }
  5231. heroesArr.push({ id: hero.id, power: heroPower });
  5232. }
  5233. }
  5234.  
  5235. /**
  5236. * Adding expeditions to send
  5237. * Добавляем экспедиции для отправки
  5238. */
  5239. let countSend = 0;
  5240. heroesArr.sort((a, b) => a.power - b.power);
  5241. for (const exped of dataExped.exped) {
  5242. let heroesIds = this.selectionHeroes(heroesArr, exped.power);
  5243. if (heroesIds && heroesIds.length > 4) {
  5244. for (let q in heroesArr) {
  5245. if (heroesIds.includes(heroesArr[q].id)) {
  5246. delete heroesArr[q];
  5247. }
  5248. }
  5249. countSend++;
  5250. calls.push({
  5251. name: 'expeditionSendHeroes',
  5252. args: {
  5253. expeditionId: exped.id,
  5254. heroes: heroesIds,
  5255. },
  5256. ident: 'expeditionSendHeroes_' + exped.id,
  5257. });
  5258. }
  5259. }
  5260.  
  5261. if (calls.length) {
  5262. await Send({ calls });
  5263. this.end(I18N('EXPEDITIONS_SENT', {countGet, countSend}));
  5264. return;
  5265. }
  5266.  
  5267. this.end(I18N('EXPEDITIONS_NOTHING'));
  5268. }
  5269.  
  5270. /**
  5271. * Selection of heroes for expeditions
  5272. *
  5273. * Подбор героев для экспедиций
  5274. */
  5275. selectionHeroes(heroes, power) {
  5276. const resultHeroers = [];
  5277. const heroesIds = [];
  5278. for (let q = 0; q < 5; q++) {
  5279. for (let i in heroes) {
  5280. let hero = heroes[i];
  5281. if (heroesIds.includes(hero.id)) {
  5282. continue;
  5283. }
  5284.  
  5285. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  5286. const need = Math.round((power - summ) / (5 - resultHeroers.length));
  5287. if (hero.power > need) {
  5288. resultHeroers.push(hero);
  5289. heroesIds.push(hero.id);
  5290. break;
  5291. }
  5292. }
  5293. }
  5294.  
  5295. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  5296. if (summ < power) {
  5297. return false;
  5298. }
  5299. return heroesIds;
  5300. }
  5301.  
  5302. /**
  5303. * Ends expedition script
  5304. *
  5305. * Завершает скрипт экспедиции
  5306. */
  5307. end(msg) {
  5308. setProgress(msg, true);
  5309. this.resolve();
  5310. }
  5311. }
  5312.  
  5313. /**
  5314. * Walkthrough of the dungeon
  5315. *
  5316. * Прохождение подземелья
  5317. */
  5318. function testDungeon() {
  5319. return new Promise((resolve, reject) => {
  5320. const dung = new executeDungeon(resolve, reject);
  5321. const titanit = getInput('countTitanit');
  5322. dung.start(titanit);
  5323. });
  5324. }
  5325.  
  5326. /**
  5327. * Walkthrough of the dungeon
  5328. *
  5329. * Прохождение подземелья
  5330. */
  5331. function executeDungeon(resolve, reject) {
  5332. dungeonActivity = 0;
  5333. maxDungeonActivity = 150;
  5334.  
  5335. titanGetAll = [];
  5336.  
  5337. teams = {
  5338. heroes: [],
  5339. earth: [],
  5340. fire: [],
  5341. neutral: [],
  5342. water: [],
  5343. }
  5344.  
  5345. titanStats = [];
  5346.  
  5347. titansStates = {};
  5348.  
  5349. let talentMsg = '';
  5350. let talentMsgReward = '';
  5351.  
  5352. callsExecuteDungeon = {
  5353. calls: [{
  5354. name: "dungeonGetInfo",
  5355. args: {},
  5356. ident: "dungeonGetInfo"
  5357. }, {
  5358. name: "teamGetAll",
  5359. args: {},
  5360. ident: "teamGetAll"
  5361. }, {
  5362. name: "teamGetFavor",
  5363. args: {},
  5364. ident: "teamGetFavor"
  5365. }, {
  5366. name: "clanGetInfo",
  5367. args: {},
  5368. ident: "clanGetInfo"
  5369. }, {
  5370. name: "titanGetAll",
  5371. args: {},
  5372. ident: "titanGetAll"
  5373. }, {
  5374. name: "inventoryGet",
  5375. args: {},
  5376. ident: "inventoryGet"
  5377. }]
  5378. }
  5379.  
  5380. this.start = function(titanit) {
  5381. maxDungeonActivity = titanit || getInput('countTitanit');
  5382. send(JSON.stringify(callsExecuteDungeon), startDungeon);
  5383. }
  5384.  
  5385. /**
  5386. * Getting data on the dungeon
  5387. *
  5388. * Получаем данные по подземелью
  5389. */
  5390. function startDungeon(e) {
  5391. stopDung = false; // стоп подземка
  5392. res = e.results;
  5393. dungeonGetInfo = res[0].result.response;
  5394. if (!dungeonGetInfo) {
  5395. endDungeon('noDungeon', res);
  5396. return;
  5397. }
  5398. teamGetAll = res[1].result.response;
  5399. teamGetFavor = res[2].result.response;
  5400. dungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  5401. titanGetAll = Object.values(res[4].result.response);
  5402. countPredictionCard = res[5].result.response.consumable[81];
  5403.  
  5404. teams.hero = {
  5405. favor: teamGetFavor.dungeon_hero,
  5406. heroes: teamGetAll.dungeon_hero.filter(id => id < 6000),
  5407. teamNum: 0,
  5408. }
  5409. heroPet = teamGetAll.dungeon_hero.filter(id => id >= 6000).pop();
  5410. if (heroPet) {
  5411. teams.hero.pet = heroPet;
  5412. }
  5413.  
  5414. teams.neutral = {
  5415. favor: {},
  5416. heroes: getTitanTeam(titanGetAll, 'neutral'),
  5417. teamNum: 0,
  5418. };
  5419. teams.water = {
  5420. favor: {},
  5421. heroes: getTitanTeam(titanGetAll, 'water'),
  5422. teamNum: 0,
  5423. };
  5424. teams.fire = {
  5425. favor: {},
  5426. heroes: getTitanTeam(titanGetAll, 'fire'),
  5427. teamNum: 0,
  5428. };
  5429. teams.earth = {
  5430. favor: {},
  5431. heroes: getTitanTeam(titanGetAll, 'earth'),
  5432. teamNum: 0,
  5433. };
  5434.  
  5435.  
  5436. checkFloor(dungeonGetInfo);
  5437. }
  5438.  
  5439. function getTitanTeam(titans, type) {
  5440. switch (type) {
  5441. case 'neutral':
  5442. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5443. case 'water':
  5444. return titans.filter(e => e.id.toString().slice(2, 3) == '0').map(e => e.id);
  5445. case 'fire':
  5446. return titans.filter(e => e.id.toString().slice(2, 3) == '1').map(e => e.id);
  5447. case 'earth':
  5448. return titans.filter(e => e.id.toString().slice(2, 3) == '2').map(e => e.id);
  5449. }
  5450. }
  5451.  
  5452. function getNeutralTeam() {
  5453. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  5454. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5455. }
  5456.  
  5457. function fixTitanTeam(titans) {
  5458. titans.heroes = titans.heroes.filter(e => !titansStates[e]?.isDead);
  5459. return titans;
  5460. }
  5461.  
  5462. /**
  5463. * Checking the floor
  5464. *
  5465. * Проверяем этаж
  5466. */
  5467. async function checkFloor(dungeonInfo) {
  5468. if (!('floor' in dungeonInfo) || dungeonInfo.floor?.state == 2) {
  5469. saveProgress();
  5470. return;
  5471. }
  5472. checkTalent(dungeonInfo);
  5473. // console.log(dungeonInfo, dungeonActivity);
  5474. setProgress(`${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity} ${talentMsg}`);
  5475. if (dungeonActivity >= maxDungeonActivity) {
  5476. endDungeon('endDungeon', 'maxActive ' + dungeonActivity + '/' + maxDungeonActivity);
  5477. return;
  5478. }
  5479. titansStates = dungeonInfo.states.titans;
  5480. titanStats = titanObjToArray(titansStates);
  5481. if (stopDung){
  5482. endDungeon('Стоп подземка,', 'набрано титанита: ' + dungeonActivity + '/' + maxDungeonActivity);
  5483. return;
  5484. }
  5485. const floorChoices = dungeonInfo.floor.userData;
  5486. const floorType = dungeonInfo.floorType;
  5487. //const primeElement = dungeonInfo.elements.prime;
  5488. if (floorType == "battle") {
  5489. const calls = [];
  5490. for (let teamNum in floorChoices) {
  5491. attackerType = floorChoices[teamNum].attackerType;
  5492. const args = fixTitanTeam(teams[attackerType]);
  5493. if (attackerType == 'neutral') {
  5494. args.heroes = getNeutralTeam();
  5495. }
  5496. if (!args.heroes.length) {
  5497. continue;
  5498. }
  5499. args.teamNum = teamNum;
  5500. calls.push({
  5501. name: "dungeonStartBattle",
  5502. args,
  5503. ident: "body_" + teamNum
  5504. })
  5505. }
  5506. if (!calls.length) {
  5507. endDungeon('endDungeon', 'All Dead');
  5508. return;
  5509. }
  5510. const battleDatas = await Send(JSON.stringify({ calls }))
  5511. .then(e => e.results.map(n => n.result.response))
  5512. const battleResults = [];
  5513. for (n in battleDatas) {
  5514. battleData = battleDatas[n]
  5515. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  5516. battleResults.push(await Calc(battleData).then(result => {
  5517. result.teamNum = n;
  5518. result.attackerType = floorChoices[n].attackerType;
  5519. return result;
  5520. }));
  5521. }
  5522. processingPromises(battleResults)
  5523. }
  5524. }
  5525.  
  5526. async function checkTalent(dungeonInfo) {
  5527. const talent = dungeonInfo.talent;
  5528. if (!talent) {
  5529. return;
  5530. }
  5531. const dungeonFloor = +dungeonInfo.floorNumber;
  5532. const talentFloor = +talent.floorRandValue;
  5533. let doorsAmount = 3 - talent.conditions.doorsAmount;
  5534.  
  5535. if (dungeonFloor === talentFloor && (!doorsAmount || !talent.conditions?.farmedDoors[dungeonFloor])) {
  5536. const reward = await Send({
  5537. calls: [
  5538. { name: 'heroTalent_getReward', args: { talentType: 'tmntDungeonTalent', reroll: false }, ident: 'group_0_body' },
  5539. { name: 'heroTalent_farmReward', args: { talentType: 'tmntDungeonTalent' }, ident: 'group_1_body' },
  5540. ],
  5541. }).then((e) => e.results[0].result.response);
  5542. const type = Object.keys(reward).pop();
  5543. const itemId = Object.keys(reward[type]).pop();
  5544. const count = reward[type][itemId];
  5545. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  5546. talentMsgReward += `<br> ${count} ${itemName}`;
  5547. doorsAmount++;
  5548. }
  5549. talentMsg = `<br>TMNT Talent: ${doorsAmount}/3 ${talentMsgReward}<br>`;
  5550. }
  5551.  
  5552. function processingPromises(results) {
  5553. let selectBattle = results[0];
  5554. if (results.length < 2) {
  5555. // console.log(selectBattle);
  5556. if (!selectBattle.result.win) {
  5557. endDungeon('dungeonEndBattle\n', selectBattle);
  5558. return;
  5559. }
  5560. endBattle(selectBattle);
  5561. return;
  5562. }
  5563.  
  5564. selectBattle = false;
  5565. let bestState = -1000;
  5566. for (const result of results) {
  5567. const recovery = getState(result);
  5568. if (recovery > bestState) {
  5569. bestState = recovery;
  5570. selectBattle = result
  5571. }
  5572. }
  5573. // console.log(selectBattle.teamNum, results);
  5574. if (!selectBattle || bestState <= -1000) {
  5575. endDungeon('dungeonEndBattle\n', results);
  5576. return;
  5577. }
  5578.  
  5579. startBattle(selectBattle.teamNum, selectBattle.attackerType)
  5580. .then(endBattle);
  5581. }
  5582.  
  5583. /**
  5584. * Let's start the fight
  5585. *
  5586. * Начинаем бой
  5587. */
  5588. function startBattle(teamNum, attackerType) {
  5589. return new Promise(function (resolve, reject) {
  5590. args = fixTitanTeam(teams[attackerType]);
  5591. args.teamNum = teamNum;
  5592. if (attackerType == 'neutral') {
  5593. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  5594. args.heroes = titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5595. }
  5596. startBattleCall = {
  5597. calls: [{
  5598. name: "dungeonStartBattle",
  5599. args,
  5600. ident: "body"
  5601. }]
  5602. }
  5603. send(JSON.stringify(startBattleCall), resultBattle, {
  5604. resolve,
  5605. teamNum,
  5606. attackerType
  5607. });
  5608. });
  5609. }
  5610. /**
  5611. * Returns the result of the battle in a promise
  5612. *
  5613. * Возращает резульат боя в промис
  5614. */
  5615. function resultBattle(resultBattles, args) {
  5616. battleData = resultBattles.results[0].result.response;
  5617. battleType = "get_tower";
  5618. if (battleData.type == "dungeon_titan") {
  5619. battleType = "get_titan";
  5620. }
  5621. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  5622. BattleCalc(battleData, battleType, function (result) {
  5623. result.teamNum = args.teamNum;
  5624. result.attackerType = args.attackerType;
  5625. args.resolve(result);
  5626. });
  5627. }
  5628. /**
  5629. * Finishing the fight
  5630. *
  5631. * Заканчиваем бой
  5632. */
  5633. async function endBattle(battleInfo) {
  5634. if (battleInfo.result.win) {
  5635. const args = {
  5636. result: battleInfo.result,
  5637. progress: battleInfo.progress,
  5638. }
  5639. if (countPredictionCard > 0) {
  5640. args.isRaid = true;
  5641. } else {
  5642. const timer = getTimer(battleInfo.battleTime);
  5643. console.log(timer);
  5644. await countdownTimer(timer, `${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity} ${talentMsg}`);
  5645. }
  5646. const calls = [{
  5647. name: "dungeonEndBattle",
  5648. args,
  5649. ident: "body"
  5650. }];
  5651. lastDungeonBattleData = null;
  5652. send(JSON.stringify({ calls }), resultEndBattle);
  5653. } else {
  5654. endDungeon('dungeonEndBattle win: false\n', battleInfo);
  5655. }
  5656. }
  5657.  
  5658. /**
  5659. * Getting and processing battle results
  5660. *
  5661. * Получаем и обрабатываем результаты боя
  5662. */
  5663. function resultEndBattle(e) {
  5664. if ('error' in e) {
  5665. popup.confirm(I18N('ERROR_MSG', {
  5666. name: e.error.name,
  5667. description: e.error.description,
  5668. }));
  5669. endDungeon('errorRequest', e);
  5670. return;
  5671. }
  5672. battleResult = e.results[0].result.response;
  5673. if ('error' in battleResult) {
  5674. endDungeon('errorBattleResult', battleResult);
  5675. return;
  5676. }
  5677. dungeonGetInfo = battleResult.dungeon ?? battleResult;
  5678. dungeonActivity += battleResult.reward.dungeonActivity ?? 0;
  5679. checkFloor(dungeonGetInfo);
  5680. }
  5681.  
  5682. /**
  5683. * Returns the coefficient of condition of the
  5684. * difference in titanium before and after the battle
  5685. *
  5686. * Возвращает коэффициент состояния титанов после боя
  5687. */
  5688. function getState(result) {
  5689. if (!result.result.win) {
  5690. return -1000;
  5691. }
  5692.  
  5693. let beforeSumFactor = 0;
  5694. const beforeTitans = result.battleData.attackers;
  5695. for (let titanId in beforeTitans) {
  5696. const titan = beforeTitans[titanId];
  5697. const state = titan.state;
  5698. let factor = 1;
  5699. if (state) {
  5700. const hp = state.hp / titan.hp;
  5701. const energy = state.energy / 1e3;
  5702. factor = hp + energy / 20
  5703. }
  5704. beforeSumFactor += factor;
  5705. }
  5706.  
  5707. let afterSumFactor = 0;
  5708. const afterTitans = result.progress[0].attackers.heroes;
  5709. for (let titanId in afterTitans) {
  5710. const titan = afterTitans[titanId];
  5711. const hp = titan.hp / beforeTitans[titanId].hp;
  5712. const energy = titan.energy / 1e3;
  5713. const factor = hp + energy / 20;
  5714. afterSumFactor += factor;
  5715. }
  5716. return afterSumFactor - beforeSumFactor;
  5717. }
  5718.  
  5719. /**
  5720. * Converts an object with IDs to an array with IDs
  5721. *
  5722. * Преобразует объект с идетификаторами в массив с идетификаторами
  5723. */
  5724. function titanObjToArray(obj) {
  5725. let titans = [];
  5726. for (let id in obj) {
  5727. obj[id].id = id;
  5728. titans.push(obj[id]);
  5729. }
  5730. return titans;
  5731. }
  5732.  
  5733. function saveProgress() {
  5734. let saveProgressCall = {
  5735. calls: [{
  5736. name: "dungeonSaveProgress",
  5737. args: {},
  5738. ident: "body"
  5739. }]
  5740. }
  5741. send(JSON.stringify(saveProgressCall), resultEndBattle);
  5742. }
  5743.  
  5744. function endDungeon(reason, info) {
  5745. console.warn(reason, info);
  5746. setProgress(`${I18N('DUNGEON')} ${I18N('COMPLETED')}`, true);
  5747. resolve();
  5748. }
  5749. }
  5750.  
  5751. /**
  5752. * Passing the tower
  5753. *
  5754. * Прохождение башни
  5755. */
  5756. function testTower() {
  5757. return new Promise((resolve, reject) => {
  5758. tower = new executeTower(resolve, reject);
  5759. tower.start();
  5760. });
  5761. }
  5762.  
  5763. /**
  5764. * Passing the tower
  5765. *
  5766. * Прохождение башни
  5767. */
  5768. function executeTower(resolve, reject) {
  5769. lastTowerInfo = {};
  5770.  
  5771. scullCoin = 0;
  5772.  
  5773. heroGetAll = [];
  5774.  
  5775. heroesStates = {};
  5776.  
  5777. argsBattle = {
  5778. heroes: [],
  5779. favor: {},
  5780. };
  5781.  
  5782. callsExecuteTower = {
  5783. calls: [{
  5784. name: "towerGetInfo",
  5785. args: {},
  5786. ident: "towerGetInfo"
  5787. }, {
  5788. name: "teamGetAll",
  5789. args: {},
  5790. ident: "teamGetAll"
  5791. }, {
  5792. name: "teamGetFavor",
  5793. args: {},
  5794. ident: "teamGetFavor"
  5795. }, {
  5796. name: "inventoryGet",
  5797. args: {},
  5798. ident: "inventoryGet"
  5799. }, {
  5800. name: "heroGetAll",
  5801. args: {},
  5802. ident: "heroGetAll"
  5803. }]
  5804. }
  5805.  
  5806. buffIds = [
  5807. {id: 0, cost: 0, isBuy: false}, // plug // заглушка
  5808. {id: 1, cost: 1, isBuy: true}, // 3% attack // 3% атака
  5809. {id: 2, cost: 6, isBuy: true}, // 2% attack // 2% атака
  5810. {id: 3, cost: 16, isBuy: true}, // 4% attack // 4% атака
  5811. {id: 4, cost: 40, isBuy: true}, // 8% attack // 8% атака
  5812. {id: 5, cost: 1, isBuy: true}, // 10% armor // 10% броня
  5813. {id: 6, cost: 6, isBuy: true}, // 5% armor // 5% броня
  5814. {id: 7, cost: 16, isBuy: true}, // 10% armor // 10% броня
  5815. {id: 8, cost: 40, isBuy: true}, // 20% armor // 20% броня
  5816. { id: 9, cost: 1, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5817. { id: 10, cost: 6, isBuy: true }, // 5% protection from magic // 5% защита от магии
  5818. { id: 11, cost: 16, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5819. { id: 12, cost: 40, isBuy: true }, // 20% protection from magic // 20% защита от магии
  5820. { id: 13, cost: 1, isBuy: false }, // 40% health hero // 40% здоровья герою
  5821. { id: 14, cost: 6, isBuy: false }, // 40% health hero // 40% здоровья герою
  5822. { id: 15, cost: 16, isBuy: false }, // 80% health hero // 80% здоровья герою
  5823. { id: 16, cost: 40, isBuy: false }, // 40% health to all heroes // 40% здоровья всем героям
  5824. { id: 17, cost: 1, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5825. { id: 18, cost: 3, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5826. { id: 19, cost: 8, isBuy: false }, // 80% energy to the hero // 80% энергии герою
  5827. { id: 20, cost: 20, isBuy: false }, // 40% energy to all heroes // 40% энергии всем героям
  5828. { id: 21, cost: 40, isBuy: false }, // Hero Resurrection // Воскрешение героя
  5829. ]
  5830.  
  5831. this.start = function () {
  5832. send(JSON.stringify(callsExecuteTower), startTower);
  5833. }
  5834.  
  5835. /**
  5836. * Getting data on the Tower
  5837. *
  5838. * Получаем данные по башне
  5839. */
  5840. function startTower(e) {
  5841. res = e.results;
  5842. towerGetInfo = res[0].result.response;
  5843. if (!towerGetInfo) {
  5844. endTower('noTower', res);
  5845. return;
  5846. }
  5847. teamGetAll = res[1].result.response;
  5848. teamGetFavor = res[2].result.response;
  5849. inventoryGet = res[3].result.response;
  5850. heroGetAll = Object.values(res[4].result.response);
  5851.  
  5852. scullCoin = inventoryGet.coin[7] ?? 0;
  5853.  
  5854. argsBattle.favor = teamGetFavor.tower;
  5855. argsBattle.heroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5856. pet = teamGetAll.tower.filter(id => id >= 6000).pop();
  5857. if (pet) {
  5858. argsBattle.pet = pet;
  5859. }
  5860.  
  5861. checkFloor(towerGetInfo);
  5862. }
  5863.  
  5864. function fixHeroesTeam(argsBattle) {
  5865. let fixHeroes = argsBattle.heroes.filter(e => !heroesStates[e]?.isDead);
  5866. if (fixHeroes.length < 5) {
  5867. heroGetAll = heroGetAll.filter(e => !heroesStates[e.id]?.isDead);
  5868. fixHeroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5869. Object.keys(argsBattle.favor).forEach(e => {
  5870. if (!fixHeroes.includes(+e)) {
  5871. delete argsBattle.favor[e];
  5872. }
  5873. })
  5874. }
  5875. argsBattle.heroes = fixHeroes;
  5876. return argsBattle;
  5877. }
  5878.  
  5879. /**
  5880. * Check the floor
  5881. *
  5882. * Проверяем этаж
  5883. */
  5884. function checkFloor(towerInfo) {
  5885. lastTowerInfo = towerInfo;
  5886. maySkipFloor = +towerInfo.maySkipFloor;
  5887. floorNumber = +towerInfo.floorNumber;
  5888. heroesStates = towerInfo.states.heroes;
  5889. floorInfo = towerInfo.floor;
  5890.  
  5891. /**
  5892. * Is there at least one chest open on the floor
  5893. * Открыт ли на этаже хоть один сундук
  5894. */
  5895. isOpenChest = false;
  5896. if (towerInfo.floorType == "chest") {
  5897. isOpenChest = towerInfo.floor.chests.reduce((n, e) => n + e.opened, 0);
  5898. }
  5899.  
  5900. setProgress(`${I18N('TOWER')}: ${I18N('FLOOR')} ${floorNumber}`);
  5901. if (floorNumber > 49) {
  5902. if (isOpenChest) {
  5903. endTower('alreadyOpenChest 50 floor', floorNumber);
  5904. return;
  5905. }
  5906. }
  5907. /**
  5908. * If the chest is open and you can skip floors, then move on
  5909. * Если сундук открыт и можно скипать этажи, то переходим дальше
  5910. */
  5911. if (towerInfo.mayFullSkip && +towerInfo.teamLevel == 130) {
  5912. if (floorNumber == 1) {
  5913. fullSkipTower();
  5914. return;
  5915. }
  5916. if (isOpenChest) {
  5917. nextOpenChest(floorNumber);
  5918. } else {
  5919. nextChestOpen(floorNumber);
  5920. }
  5921. return;
  5922. }
  5923.  
  5924. // console.log(towerInfo, scullCoin);
  5925. switch (towerInfo.floorType) {
  5926. case "battle":
  5927. if (floorNumber <= maySkipFloor) {
  5928. skipFloor();
  5929. return;
  5930. }
  5931. if (floorInfo.state == 2) {
  5932. nextFloor();
  5933. return;
  5934. }
  5935. startBattle().then(endBattle);
  5936. return;
  5937. case "buff":
  5938. checkBuff(towerInfo);
  5939. return;
  5940. case "chest":
  5941. openChest(floorNumber);
  5942. return;
  5943. default:
  5944. console.log('!', towerInfo.floorType, towerInfo);
  5945. break;
  5946. }
  5947. }
  5948.  
  5949. /**
  5950. * Let's start the fight
  5951. *
  5952. * Начинаем бой
  5953. */
  5954. function startBattle() {
  5955. return new Promise(function (resolve, reject) {
  5956. towerStartBattle = {
  5957. calls: [{
  5958. name: "towerStartBattle",
  5959. args: fixHeroesTeam(argsBattle),
  5960. ident: "body"
  5961. }]
  5962. }
  5963. send(JSON.stringify(towerStartBattle), resultBattle, resolve);
  5964. });
  5965. }
  5966. /**
  5967. * Returns the result of the battle in a promise
  5968. *
  5969. * Возращает резульат боя в промис
  5970. */
  5971. function resultBattle(resultBattles, resolve) {
  5972. battleData = resultBattles.results[0].result.response;
  5973. battleType = "get_tower";
  5974. BattleCalc(battleData, battleType, function (result) {
  5975. resolve(result);
  5976. });
  5977. }
  5978. /**
  5979. * Finishing the fight
  5980. *
  5981. * Заканчиваем бой
  5982. */
  5983. function endBattle(battleInfo) {
  5984. if (battleInfo.result.stars >= 3) {
  5985. endBattleCall = {
  5986. calls: [{
  5987. name: "towerEndBattle",
  5988. args: {
  5989. result: battleInfo.result,
  5990. progress: battleInfo.progress,
  5991. },
  5992. ident: "body"
  5993. }]
  5994. }
  5995. send(JSON.stringify(endBattleCall), resultEndBattle);
  5996. } else {
  5997. endTower('towerEndBattle win: false\n', battleInfo);
  5998. }
  5999. }
  6000.  
  6001. /**
  6002. * Getting and processing battle results
  6003. *
  6004. * Получаем и обрабатываем результаты боя
  6005. */
  6006. function resultEndBattle(e) {
  6007. battleResult = e.results[0].result.response;
  6008. if ('error' in battleResult) {
  6009. endTower('errorBattleResult', battleResult);
  6010. return;
  6011. }
  6012. if ('reward' in battleResult) {
  6013. scullCoin += battleResult.reward?.coin[7] ?? 0;
  6014. }
  6015. nextFloor();
  6016. }
  6017.  
  6018. function nextFloor() {
  6019. nextFloorCall = {
  6020. calls: [{
  6021. name: "towerNextFloor",
  6022. args: {},
  6023. ident: "body"
  6024. }]
  6025. }
  6026. send(JSON.stringify(nextFloorCall), checkDataFloor);
  6027. }
  6028.  
  6029. function openChest(floorNumber) {
  6030. floorNumber = floorNumber || 0;
  6031. openChestCall = {
  6032. calls: [{
  6033. name: "towerOpenChest",
  6034. args: {
  6035. num: 2
  6036. },
  6037. ident: "body"
  6038. }]
  6039. }
  6040. send(JSON.stringify(openChestCall), floorNumber < 50 ? nextFloor : lastChest);
  6041. }
  6042.  
  6043. function lastChest() {
  6044. endTower('openChest 50 floor', floorNumber);
  6045. }
  6046.  
  6047. function skipFloor() {
  6048. skipFloorCall = {
  6049. calls: [{
  6050. name: "towerSkipFloor",
  6051. args: {},
  6052. ident: "body"
  6053. }]
  6054. }
  6055. send(JSON.stringify(skipFloorCall), checkDataFloor);
  6056. }
  6057.  
  6058. function checkBuff(towerInfo) {
  6059. buffArr = towerInfo.floor;
  6060. promises = [];
  6061. for (let buff of buffArr) {
  6062. buffInfo = buffIds[buff.id];
  6063. if (buffInfo.isBuy && buffInfo.cost <= scullCoin) {
  6064. scullCoin -= buffInfo.cost;
  6065. promises.push(buyBuff(buff.id));
  6066. }
  6067. }
  6068. Promise.all(promises).then(nextFloor);
  6069. }
  6070.  
  6071. function buyBuff(buffId) {
  6072. return new Promise(function (resolve, reject) {
  6073. buyBuffCall = {
  6074. calls: [{
  6075. name: "towerBuyBuff",
  6076. args: {
  6077. buffId
  6078. },
  6079. ident: "body"
  6080. }]
  6081. }
  6082. send(JSON.stringify(buyBuffCall), resolve);
  6083. });
  6084. }
  6085.  
  6086. function checkDataFloor(result) {
  6087. towerInfo = result.results[0].result.response;
  6088. if ('reward' in towerInfo && towerInfo.reward?.coin) {
  6089. scullCoin += towerInfo.reward?.coin[7] ?? 0;
  6090. }
  6091. if ('tower' in towerInfo) {
  6092. towerInfo = towerInfo.tower;
  6093. }
  6094. if ('skullReward' in towerInfo) {
  6095. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  6096. }
  6097. checkFloor(towerInfo);
  6098. }
  6099. /**
  6100. * Getting tower rewards
  6101. *
  6102. * Получаем награды башни
  6103. */
  6104. function farmTowerRewards(reason) {
  6105. let { pointRewards, points } = lastTowerInfo;
  6106. let pointsAll = Object.getOwnPropertyNames(pointRewards);
  6107. let farmPoints = pointsAll.filter(e => +e <= +points && !pointRewards[e]);
  6108. if (!farmPoints.length) {
  6109. return;
  6110. }
  6111. let farmTowerRewardsCall = {
  6112. calls: [{
  6113. name: "tower_farmPointRewards",
  6114. args: {
  6115. points: farmPoints
  6116. },
  6117. ident: "tower_farmPointRewards"
  6118. }]
  6119. }
  6120.  
  6121. if (scullCoin > 0) {
  6122. farmTowerRewardsCall.calls.push({
  6123. name: "tower_farmSkullReward",
  6124. args: {},
  6125. ident: "tower_farmSkullReward"
  6126. });
  6127. }
  6128.  
  6129. send(JSON.stringify(farmTowerRewardsCall), () => { });
  6130. }
  6131.  
  6132. function fullSkipTower() {
  6133. /**
  6134. * Next chest
  6135. *
  6136. * Следующий сундук
  6137. */
  6138. function nextChest(n) {
  6139. return {
  6140. name: "towerNextChest",
  6141. args: {},
  6142. ident: "group_" + n + "_body"
  6143. }
  6144. }
  6145. /**
  6146. * Open chest
  6147. *
  6148. * Открыть сундук
  6149. */
  6150. function openChest(n) {
  6151. return {
  6152. name: "towerOpenChest",
  6153. args: {
  6154. "num": 2
  6155. },
  6156. ident: "group_" + n + "_body"
  6157. }
  6158. }
  6159.  
  6160. const fullSkipTowerCall = {
  6161. calls: []
  6162. }
  6163.  
  6164. let n = 0;
  6165. for (let i = 0; i < 15; i++) {
  6166. // 15 сундуков
  6167. fullSkipTowerCall.calls.push(nextChest(++n));
  6168. fullSkipTowerCall.calls.push(openChest(++n));
  6169. // +5 сундуков, 250 изюма // towerOpenChest
  6170. // if (i < 5) {
  6171. // fullSkipTowerCall.calls.push(openChest(++n, 2));
  6172. // }
  6173. }
  6174.  
  6175. fullSkipTowerCall.calls.push({
  6176. name: 'towerGetInfo',
  6177. args: {},
  6178. ident: 'group_' + ++n + '_body',
  6179. });
  6180.  
  6181. send(JSON.stringify(fullSkipTowerCall), data => {
  6182. for (const r of data.results) {
  6183. const towerInfo = r?.result?.response;
  6184. if (towerInfo && 'skullReward' in towerInfo) {
  6185. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  6186. }
  6187. }
  6188. data.results[0] = data.results[data.results.length - 1];
  6189. checkDataFloor(data);
  6190. });
  6191. }
  6192.  
  6193. function nextChestOpen(floorNumber) {
  6194. const calls = [{
  6195. name: "towerOpenChest",
  6196. args: {
  6197. num: 2
  6198. },
  6199. ident: "towerOpenChest"
  6200. }];
  6201.  
  6202. Send(JSON.stringify({ calls })).then(e => {
  6203. nextOpenChest(floorNumber);
  6204. });
  6205. }
  6206.  
  6207. function nextOpenChest(floorNumber) {
  6208. if (floorNumber > 49) {
  6209. endTower('openChest 50 floor', floorNumber);
  6210. return;
  6211. }
  6212.  
  6213. let nextOpenChestCall = {
  6214. calls: [{
  6215. name: "towerNextChest",
  6216. args: {},
  6217. ident: "towerNextChest"
  6218. }, {
  6219. name: "towerOpenChest",
  6220. args: {
  6221. num: 2
  6222. },
  6223. ident: "towerOpenChest"
  6224. }]
  6225. }
  6226. send(JSON.stringify(nextOpenChestCall), checkDataFloor);
  6227. }
  6228.  
  6229. function endTower(reason, info) {
  6230. console.log(reason, info);
  6231. if (reason != 'noTower') {
  6232. farmTowerRewards(reason);
  6233. }
  6234. setProgress(`${I18N('TOWER')} ${I18N('COMPLETED')}!`, true);
  6235. resolve();
  6236. }
  6237. }
  6238.  
  6239. /**
  6240. * Passage of the arena of the titans
  6241. *
  6242. * Прохождение арены титанов
  6243. */
  6244. function testTitanArena() {
  6245. return new Promise((resolve, reject) => {
  6246. titAren = new executeTitanArena(resolve, reject);
  6247. titAren.start();
  6248. });
  6249. }
  6250.  
  6251. /**
  6252. * Passage of the arena of the titans
  6253. *
  6254. * Прохождение арены титанов
  6255. */
  6256. function executeTitanArena(resolve, reject) {
  6257. let titan_arena = [];
  6258. let finishListBattle = [];
  6259. /**
  6260. * ID of the current batch
  6261. *
  6262. * Идетификатор текущей пачки
  6263. */
  6264. let currentRival = 0;
  6265. /**
  6266. * Number of attempts to finish off the pack
  6267. *
  6268. * Количество попыток добития пачки
  6269. */
  6270. let attempts = 0;
  6271. /**
  6272. * Was there an attempt to finish off the current shooting range
  6273. *
  6274. * Была ли попытка добития текущего тира
  6275. */
  6276. let isCheckCurrentTier = false;
  6277. /**
  6278. * Current shooting range
  6279. *
  6280. * Текущий тир
  6281. */
  6282. let currTier = 0;
  6283. /**
  6284. * Number of battles on the current dash
  6285. *
  6286. * Количество битв на текущем тире
  6287. */
  6288. let countRivalsTier = 0;
  6289.  
  6290. let callsStart = {
  6291. calls: [{
  6292. name: "titanArenaGetStatus",
  6293. args: {},
  6294. ident: "titanArenaGetStatus"
  6295. }, {
  6296. name: "teamGetAll",
  6297. args: {},
  6298. ident: "teamGetAll"
  6299. }]
  6300. }
  6301.  
  6302. this.start = function () {
  6303. send(JSON.stringify(callsStart), startTitanArena);
  6304. }
  6305.  
  6306. function startTitanArena(data) {
  6307. let titanArena = data.results[0].result.response;
  6308. if (titanArena.status == 'disabled') {
  6309. endTitanArena('disabled', titanArena);
  6310. return;
  6311. }
  6312.  
  6313. let teamGetAll = data.results[1].result.response;
  6314. titan_arena = teamGetAll.titan_arena;
  6315.  
  6316. checkTier(titanArena)
  6317. }
  6318.  
  6319. function checkTier(titanArena) {
  6320. if (titanArena.status == "peace_time") {
  6321. endTitanArena('Peace_time', titanArena);
  6322. return;
  6323. }
  6324. currTier = titanArena.tier;
  6325. if (currTier) {
  6326. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier}`);
  6327. }
  6328.  
  6329. if (titanArena.status == "completed_tier") {
  6330. titanArenaCompleteTier();
  6331. return;
  6332. }
  6333. /**
  6334. * Checking for the possibility of a raid
  6335. * Проверка на возможность рейда
  6336. */
  6337. if (titanArena.canRaid) {
  6338. titanArenaStartRaid();
  6339. return;
  6340. }
  6341. /**
  6342. * Check was an attempt to achieve the current shooting range
  6343. * Проверка была ли попытка добития текущего тира
  6344. */
  6345. if (!isCheckCurrentTier) {
  6346. checkRivals(titanArena.rivals);
  6347. return;
  6348. }
  6349.  
  6350. endTitanArena('Done or not canRaid', titanArena);
  6351. }
  6352. /**
  6353. * Submit dash information for verification
  6354. *
  6355. * Отправка информации о тире на проверку
  6356. */
  6357. function checkResultInfo(data) {
  6358. let titanArena = data.results[0].result.response;
  6359. checkTier(titanArena);
  6360. }
  6361. /**
  6362. * Finish the current tier
  6363. *
  6364. * Завершить текущий тир
  6365. */
  6366. function titanArenaCompleteTier() {
  6367. isCheckCurrentTier = false;
  6368. let calls = [{
  6369. name: "titanArenaCompleteTier",
  6370. args: {},
  6371. ident: "body"
  6372. }];
  6373. send(JSON.stringify({calls}), checkResultInfo);
  6374. }
  6375. /**
  6376. * Gathering points to be completed
  6377. *
  6378. * Собираем точки которые нужно добить
  6379. */
  6380. function checkRivals(rivals) {
  6381. finishListBattle = [];
  6382. for (let n in rivals) {
  6383. if (rivals[n].attackScore < 250) {
  6384. finishListBattle.push(n);
  6385. }
  6386. }
  6387. console.log('checkRivals', finishListBattle);
  6388. countRivalsTier = finishListBattle.length;
  6389. roundRivals();
  6390. }
  6391. /**
  6392. * Selecting the next point to finish off
  6393. *
  6394. * Выбор следующей точки для добития
  6395. */
  6396. function roundRivals() {
  6397. let countRivals = finishListBattle.length;
  6398. if (!countRivals) {
  6399. /**
  6400. * Whole range checked
  6401. *
  6402. * Весь тир проверен
  6403. */
  6404. isCheckCurrentTier = true;
  6405. titanArenaGetStatus();
  6406. return;
  6407. }
  6408. // setProgress('TitanArena: Уровень ' + currTier + ' Бои: ' + (countRivalsTier - countRivals + 1) + '/' + countRivalsTier);
  6409. currentRival = finishListBattle.pop();
  6410. attempts = +currentRival;
  6411. // console.log('roundRivals', currentRival);
  6412. titanArenaStartBattle(currentRival);
  6413. }
  6414. /**
  6415. * The start of a solo battle
  6416. *
  6417. * Начало одиночной битвы
  6418. */
  6419. function titanArenaStartBattle(rivalId) {
  6420. let calls = [{
  6421. name: "titanArenaStartBattle",
  6422. args: {
  6423. rivalId: rivalId,
  6424. titans: titan_arena
  6425. },
  6426. ident: "body"
  6427. }];
  6428. send(JSON.stringify({calls}), calcResult);
  6429. }
  6430. /**
  6431. * Calculation of the results of the battle
  6432. *
  6433. * Расчет результатов боя
  6434. */
  6435. function calcResult(data) {
  6436. let battlesInfo = data.results[0].result.response.battle;
  6437. /**
  6438. * If attempts are equal to the current battle number we make
  6439. * Если попытки равны номеру текущего боя делаем прерасчет
  6440. */
  6441. if (attempts == currentRival) {
  6442. preCalcBattle(battlesInfo);
  6443. return;
  6444. }
  6445. /**
  6446. * If there are still attempts, we calculate a new battle
  6447. * Если попытки еще есть делаем расчет нового боя
  6448. */
  6449. if (attempts > 0) {
  6450. attempts--;
  6451. calcBattleResult(battlesInfo)
  6452. .then(resultCalcBattle);
  6453. return;
  6454. }
  6455. /**
  6456. * Otherwise, go to the next opponent
  6457. * Иначе переходим к следующему сопернику
  6458. */
  6459. roundRivals();
  6460. }
  6461. /**
  6462. * Processing the results of the battle calculation
  6463. *
  6464. * Обработка результатов расчета битвы
  6465. */
  6466. function resultCalcBattle(resultBattle) {
  6467. // console.log('resultCalcBattle', currentRival, attempts, resultBattle.result.win);
  6468. /**
  6469. * If the current calculation of victory is not a chance or the attempt ended with the finish the battle
  6470. * Если текущий расчет победа или шансов нет или попытки кончились завершаем бой
  6471. */
  6472. if (resultBattle.result.win || !attempts) {
  6473. titanArenaEndBattle({
  6474. progress: resultBattle.progress,
  6475. result: resultBattle.result,
  6476. rivalId: resultBattle.battleData.typeId
  6477. });
  6478. return;
  6479. }
  6480. /**
  6481. * If not victory and there are attempts we start a new battle
  6482. * Если не победа и есть попытки начинаем новый бой
  6483. */
  6484. titanArenaStartBattle(resultBattle.battleData.typeId);
  6485. }
  6486. /**
  6487. * Returns the promise of calculating the results of the battle
  6488. *
  6489. * Возращает промис расчета результатов битвы
  6490. */
  6491. function getBattleInfo(battle, isRandSeed) {
  6492. return new Promise(function (resolve) {
  6493. if (isRandSeed) {
  6494. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  6495. }
  6496. // console.log(battle.seed);
  6497. BattleCalc(battle, "get_titanClanPvp", e => resolve(e));
  6498. });
  6499. }
  6500. /**
  6501. * Recalculate battles
  6502. *
  6503. * Прерасчтет битвы
  6504. */
  6505. function preCalcBattle(battle) {
  6506. let actions = [getBattleInfo(battle, false)];
  6507. const countTestBattle = getInput('countTestBattle');
  6508. for (let i = 0; i < countTestBattle; i++) {
  6509. actions.push(getBattleInfo(battle, true));
  6510. }
  6511. Promise.all(actions)
  6512. .then(resultPreCalcBattle);
  6513. }
  6514. /**
  6515. * Processing the results of the battle recalculation
  6516. *
  6517. * Обработка результатов прерасчета битвы
  6518. */
  6519. function resultPreCalcBattle(e) {
  6520. let wins = e.map(n => n.result.win);
  6521. let firstBattle = e.shift();
  6522. let countWin = wins.reduce((w, s) => w + s);
  6523. const countTestBattle = getInput('countTestBattle');
  6524. console.log('resultPreCalcBattle', `${countWin}/${countTestBattle}`)
  6525. if (countWin > 0) {
  6526. attempts = getInput('countAutoBattle');
  6527. } else {
  6528. attempts = 0;
  6529. }
  6530. resultCalcBattle(firstBattle);
  6531. }
  6532.  
  6533. /**
  6534. * Complete an arena battle
  6535. *
  6536. * Завершить битву на арене
  6537. */
  6538. function titanArenaEndBattle(args) {
  6539. let calls = [{
  6540. name: "titanArenaEndBattle",
  6541. args,
  6542. ident: "body"
  6543. }];
  6544. send(JSON.stringify({calls}), resultTitanArenaEndBattle);
  6545. }
  6546.  
  6547. function resultTitanArenaEndBattle(e) {
  6548. let attackScore = e.results[0].result.response.attackScore;
  6549. let numReval = countRivalsTier - finishListBattle.length;
  6550. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier} </br>${I18N('BATTLES')}: ${numReval}/${countRivalsTier} - ${attackScore}`);
  6551. /**
  6552. * TODO: Might need to improve the results.
  6553. * TODO: Возможно стоит сделать улучшение результатов
  6554. */
  6555. // console.log('resultTitanArenaEndBattle', e)
  6556. console.log('resultTitanArenaEndBattle', numReval + '/' + countRivalsTier, attempts)
  6557. roundRivals();
  6558. }
  6559. /**
  6560. * Arena State
  6561. *
  6562. * Состояние арены
  6563. */
  6564. function titanArenaGetStatus() {
  6565. let calls = [{
  6566. name: "titanArenaGetStatus",
  6567. args: {},
  6568. ident: "body"
  6569. }];
  6570. send(JSON.stringify({calls}), checkResultInfo);
  6571. }
  6572. /**
  6573. * Arena Raid Request
  6574. *
  6575. * Запрос рейда арены
  6576. */
  6577. function titanArenaStartRaid() {
  6578. let calls = [{
  6579. name: "titanArenaStartRaid",
  6580. args: {
  6581. titans: titan_arena
  6582. },
  6583. ident: "body"
  6584. }];
  6585. send(JSON.stringify({calls}), calcResults);
  6586. }
  6587.  
  6588. function calcResults(data) {
  6589. let battlesInfo = data.results[0].result.response;
  6590. let {attackers, rivals} = battlesInfo;
  6591.  
  6592. let promises = [];
  6593. for (let n in rivals) {
  6594. rival = rivals[n];
  6595. promises.push(calcBattleResult({
  6596. attackers: attackers,
  6597. defenders: [rival.team],
  6598. seed: rival.seed,
  6599. typeId: n,
  6600. }));
  6601. }
  6602.  
  6603. Promise.all(promises)
  6604. .then(results => {
  6605. const endResults = {};
  6606. for (let info of results) {
  6607. let id = info.battleData.typeId;
  6608. endResults[id] = {
  6609. progress: info.progress,
  6610. result: info.result,
  6611. }
  6612. }
  6613. titanArenaEndRaid(endResults);
  6614. });
  6615. }
  6616.  
  6617. function calcBattleResult(battleData) {
  6618. return new Promise(function (resolve, reject) {
  6619. BattleCalc(battleData, "get_titanClanPvp", resolve);
  6620. });
  6621. }
  6622.  
  6623. /**
  6624. * Sending Raid Results
  6625. *
  6626. * Отправка результатов рейда
  6627. */
  6628. function titanArenaEndRaid(results) {
  6629. titanArenaEndRaidCall = {
  6630. calls: [{
  6631. name: "titanArenaEndRaid",
  6632. args: {
  6633. results
  6634. },
  6635. ident: "body"
  6636. }]
  6637. }
  6638. send(JSON.stringify(titanArenaEndRaidCall), checkRaidResults);
  6639. }
  6640.  
  6641. function checkRaidResults(data) {
  6642. results = data.results[0].result.response.results;
  6643. isSucsesRaid = true;
  6644. for (let i in results) {
  6645. isSucsesRaid &&= (results[i].attackScore >= 250);
  6646. }
  6647.  
  6648. if (isSucsesRaid) {
  6649. titanArenaCompleteTier();
  6650. } else {
  6651. titanArenaGetStatus();
  6652. }
  6653. }
  6654.  
  6655. function titanArenaFarmDailyReward() {
  6656. titanArenaFarmDailyRewardCall = {
  6657. calls: [{
  6658. name: "titanArenaFarmDailyReward",
  6659. args: {},
  6660. ident: "body"
  6661. }]
  6662. }
  6663. send(JSON.stringify(titanArenaFarmDailyRewardCall), () => {console.log('Done farm daily reward')});
  6664. }
  6665.  
  6666. function endTitanArena(reason, info) {
  6667. if (!['Peace_time', 'disabled'].includes(reason)) {
  6668. titanArenaFarmDailyReward();
  6669. }
  6670. console.log(reason, info);
  6671. setProgress(`${I18N('TITAN_ARENA')} ${I18N('COMPLETED')}!`, true);
  6672. resolve();
  6673. }
  6674. }
  6675.  
  6676. function hackGame() {
  6677. const self = this;
  6678. selfGame = null;
  6679. bindId = 1e9;
  6680. this.libGame = null;
  6681. this.doneLibLoad = () => {}
  6682.  
  6683. /**
  6684. * List of correspondence of used classes to their names
  6685. *
  6686. * Список соответствия используемых классов их названиям
  6687. */
  6688. ObjectsList = [
  6689. { name: 'BattlePresets', prop: 'game.battle.controller.thread.BattlePresets' },
  6690. { name: 'DataStorage', prop: 'game.data.storage.DataStorage' },
  6691. { name: 'BattleConfigStorage', prop: 'game.data.storage.battle.BattleConfigStorage' },
  6692. { name: 'BattleInstantPlay', prop: 'game.battle.controller.instant.BattleInstantPlay' },
  6693. { name: 'MultiBattleInstantReplay', prop: 'game.battle.controller.instant.MultiBattleInstantReplay' },
  6694. { name: 'MultiBattleResult', prop: 'game.battle.controller.MultiBattleResult' },
  6695.  
  6696. { name: 'PlayerMissionData', prop: 'game.model.user.mission.PlayerMissionData' },
  6697. { name: 'PlayerMissionBattle', prop: 'game.model.user.mission.PlayerMissionBattle' },
  6698. { name: 'GameModel', prop: 'game.model.GameModel' },
  6699. { name: 'CommandManager', prop: 'game.command.CommandManager' },
  6700. { name: 'MissionCommandList', prop: 'game.command.rpc.mission.MissionCommandList' },
  6701. { name: 'RPCCommandBase', prop: 'game.command.rpc.RPCCommandBase' },
  6702. { name: 'PlayerTowerData', prop: 'game.model.user.tower.PlayerTowerData' },
  6703. { name: 'TowerCommandList', prop: 'game.command.tower.TowerCommandList' },
  6704. { name: 'PlayerHeroTeamResolver', prop: 'game.model.user.hero.PlayerHeroTeamResolver' },
  6705. { name: 'BattlePausePopup', prop: 'game.view.popup.battle.BattlePausePopup' },
  6706. { name: 'BattlePopup', prop: 'game.view.popup.battle.BattlePopup' },
  6707. { name: 'DisplayObjectContainer', prop: 'starling.display.DisplayObjectContainer' },
  6708. { name: 'GuiClipContainer', prop: 'engine.core.clipgui.GuiClipContainer' },
  6709. { name: 'BattlePausePopupClip', prop: 'game.view.popup.battle.BattlePausePopupClip' },
  6710. { name: 'ClipLabel', prop: 'game.view.gui.components.ClipLabel' },
  6711. { name: 'ClipLabelBase', prop: 'game.view.gui.components.ClipLabelBase' },
  6712. { name: 'Translate', prop: 'com.progrestar.common.lang.Translate' },
  6713. { name: 'ClipButtonLabeledCentered', prop: 'game.view.gui.components.ClipButtonLabeledCentered' },
  6714. { name: 'BattlePausePopupMediator', prop: 'game.mediator.gui.popup.battle.BattlePausePopupMediator' },
  6715. { name: 'SettingToggleButton', prop: 'game.mechanics.settings.popup.view.SettingToggleButton' },
  6716. { name: 'PlayerDungeonData', prop: 'game.mechanics.dungeon.model.PlayerDungeonData' },
  6717. { name: 'NextDayUpdatedManager', prop: 'game.model.user.NextDayUpdatedManager' },
  6718. { name: 'BattleController', prop: 'game.battle.controller.BattleController' },
  6719. { name: 'BattleSettingsModel', prop: 'game.battle.controller.BattleSettingsModel' },
  6720. { name: 'BooleanProperty', prop: 'engine.core.utils.property.BooleanProperty' },
  6721. { name: 'RuleStorage', prop: 'game.data.storage.rule.RuleStorage' },
  6722. { name: 'BattleConfig', prop: 'battle.BattleConfig' },
  6723. { name: 'BattleGuiMediator', prop: 'game.battle.gui.BattleGuiMediator' },
  6724. { name: 'BooleanPropertyWriteable', prop: 'engine.core.utils.property.BooleanPropertyWriteable' },
  6725. { name: 'BattleLogEncoder', prop: 'battle.log.BattleLogEncoder' },
  6726. { name: 'BattleLogReader', prop: 'battle.log.BattleLogReader' },
  6727. { name: 'PlayerSubscriptionInfoValueObject', prop: 'game.model.user.subscription.PlayerSubscriptionInfoValueObject' },
  6728. { name: 'AdventureMapCamera', prop: 'game.mechanics.adventure.popup.map.AdventureMapCamera' },
  6729. { name: 'SendReplayPopUp', prop: 'game.mediator.gui.popup.chat.sendreplay.SendReplayPopUp' }, //полное окно реплей на вг
  6730. ];
  6731.  
  6732. /**
  6733. * Contains the game classes needed to write and override game methods
  6734. *
  6735. * Содержит классы игры необходимые для написания и подмены методов игры
  6736. */
  6737. Game = {
  6738. /**
  6739. * Function 'e'
  6740. * Функция 'e'
  6741. */
  6742. bindFunc: function (a, b) {
  6743. if (null == b)
  6744. return null;
  6745. null == b.__id__ && (b.__id__ = bindId++);
  6746. var c;
  6747. null == a.hx__closures__ ? a.hx__closures__ = {} :
  6748. c = a.hx__closures__[b.__id__];
  6749. null == c && (c = b.bind(a), a.hx__closures__[b.__id__] = c);
  6750. return c
  6751. },
  6752. };
  6753.  
  6754. /**
  6755. * Connects to game objects via the object creation event
  6756. *
  6757. * Подключается к объектам игры через событие создания объекта
  6758. */
  6759. function connectGame() {
  6760. for (let obj of ObjectsList) {
  6761. /**
  6762. * https: //stackoverflow.com/questions/42611719/how-to-intercept-and-modify-a-specific-property-for-any-object
  6763. */
  6764. Object.defineProperty(Object.prototype, obj.prop, {
  6765. set: function (value) {
  6766. if (!selfGame) {
  6767. selfGame = this;
  6768. }
  6769. if (!Game[obj.name]) {
  6770. Game[obj.name] = value;
  6771. }
  6772. // console.log('set ' + obj.prop, this, value);
  6773. this[obj.prop + '_'] = value;
  6774. },
  6775. get: function () {
  6776. // console.log('get ' + obj.prop, this);
  6777. return this[obj.prop + '_'];
  6778. }
  6779. });
  6780. }
  6781. }
  6782.  
  6783. /**
  6784. * Game.BattlePresets
  6785. * @param {bool} a isReplay
  6786. * @param {bool} b autoToggleable
  6787. * @param {bool} c auto On Start
  6788. * @param {object} d config
  6789. * @param {bool} f showBothTeams
  6790. */
  6791. /**
  6792. * Returns the results of the battle to the callback function
  6793. * Возвращает в функцию callback результаты боя
  6794. * @param {*} battleData battle data данные боя
  6795. * @param {*} battleConfig combat configuration type options:
  6796. *
  6797. * тип конфигурации боя варианты:
  6798. *
  6799. * "get_invasion", "get_titanPvpManual", "get_titanPvp",
  6800. * "get_titanClanPvp","get_clanPvp","get_titan","get_boss",
  6801. * "get_tower","get_pve","get_pvpManual","get_pvp","get_core"
  6802. *
  6803. * You can specify the xYc function in the game.assets.storage.BattleAssetStorage class
  6804. *
  6805. * Можно уточнить в классе game.assets.storage.BattleAssetStorage функция xYc
  6806. * @param {*} callback функция в которую вернуться результаты боя
  6807. */
  6808. this.BattleCalc = function (battleData, battleConfig, callback) {
  6809. // battleConfig = battleConfig || getBattleType(battleData.type)
  6810. if (!Game.BattlePresets) throw Error('Use connectGame');
  6811. battlePresets = new Game.BattlePresets(battleData.progress, !1, !0, Game.DataStorage[getFn(Game.DataStorage, 24)][getF(Game.BattleConfigStorage, battleConfig)](), !1);
  6812. let battleInstantPlay;
  6813. if (battleData.progress?.length > 1) {
  6814. battleInstantPlay = new Game.MultiBattleInstantReplay(battleData, battlePresets);
  6815. } else {
  6816. battleInstantPlay = new Game.BattleInstantPlay(battleData, battlePresets);
  6817. }
  6818. battleInstantPlay[getProtoFn(Game.BattleInstantPlay, 9)].add((battleInstant) => {
  6819. const MBR_2 = getProtoFn(Game.MultiBattleResult, 2);
  6820. const battleResults = battleInstant[getF(Game.BattleInstantPlay, 'get_result')]();
  6821. const battleData = battleInstant[getF(Game.BattleInstantPlay, 'get_rawBattleInfo')]();
  6822. const battleLogs = [];
  6823. const timeLimit = battlePresets[getF(Game.BattlePresets, 'get_timeLimit')]();
  6824. let battleTime = 0;
  6825. let battleTimer = 0;
  6826. for (const battleResult of battleResults[MBR_2]) {
  6827. const battleLog = Game.BattleLogEncoder.read(new Game.BattleLogReader(battleResult));
  6828. battleLogs.push(battleLog);
  6829. const maxTime = Math.max(...battleLog.map((e) => (e.time < timeLimit && e.time !== 168.8 ? e.time : 0)));
  6830. battleTimer += getTimer(maxTime)
  6831. battleTime += maxTime;
  6832. }
  6833. callback({
  6834. battleLogs,
  6835. battleTime,
  6836. battleTimer,
  6837. battleData,
  6838. progress: battleResults[getF(Game.MultiBattleResult, 'get_progress')](),
  6839. result: battleResults[getF(Game.MultiBattleResult, 'get_result')](),
  6840. });
  6841. });
  6842. battleInstantPlay.start();
  6843. }
  6844.  
  6845. /**
  6846. * Returns a function with the specified name from the class
  6847. *
  6848. * Возвращает из класса функцию с указанным именем
  6849. * @param {Object} classF Class // класс
  6850. * @param {String} nameF function name // имя функции
  6851. * @param {String} pos name and alias order // порядок имени и псевдонима
  6852. * @returns
  6853. */
  6854. function getF(classF, nameF, pos) {
  6855. pos = pos || false;
  6856. let prop = Object.entries(classF.prototype.__properties__)
  6857. if (!pos) {
  6858. return prop.filter((e) => e[1] == nameF).pop()[0];
  6859. } else {
  6860. return prop.filter((e) => e[0] == nameF).pop()[1];
  6861. }
  6862. }
  6863.  
  6864. /**
  6865. * Returns a function with the specified name from the class
  6866. *
  6867. * Возвращает из класса функцию с указанным именем
  6868. * @param {Object} classF Class // класс
  6869. * @param {String} nameF function name // имя функции
  6870. * @returns
  6871. */
  6872. function getFnP(classF, nameF) {
  6873. let prop = Object.entries(classF.__properties__)
  6874. return prop.filter((e) => e[1] == nameF).pop()[0];
  6875. }
  6876.  
  6877. /**
  6878. * Returns the function name with the specified ordinal from the class
  6879. *
  6880. * Возвращает имя функции с указаным порядковым номером из класса
  6881. * @param {Object} classF Class // класс
  6882. * @param {Number} nF Order number of function // порядковый номер функции
  6883. * @returns
  6884. */
  6885. function getFn(classF, nF) {
  6886. let prop = Object.keys(classF);
  6887. return prop[nF];
  6888. }
  6889.  
  6890. /**
  6891. * Returns the name of the function with the specified serial number from the prototype of the class
  6892. *
  6893. * Возвращает имя функции с указаным порядковым номером из прототипа класса
  6894. * @param {Object} classF Class // класс
  6895. * @param {Number} nF Order number of function // порядковый номер функции
  6896. * @returns
  6897. */
  6898. function getProtoFn(classF, nF) {
  6899. let prop = Object.keys(classF.prototype);
  6900. return prop[nF];
  6901. }
  6902. /**
  6903. * Description of replaced functions
  6904. *
  6905. * Описание подменяемых функций
  6906. */
  6907. replaceFunction = {
  6908. company: function () {
  6909. let PMD_12 = getProtoFn(Game.PlayerMissionData, 12);
  6910. let oldSkipMisson = Game.PlayerMissionData.prototype[PMD_12];
  6911. Game.PlayerMissionData.prototype[PMD_12] = function (a, b, c) {
  6912. if (!isChecked('passBattle')) {
  6913. oldSkipMisson.call(this, a, b, c);
  6914. return;
  6915. }
  6916.  
  6917. try {
  6918. this[getProtoFn(Game.PlayerMissionData, 9)] = new Game.PlayerMissionBattle(a, b, c);
  6919.  
  6920. var a = new Game.BattlePresets(
  6921. !1,
  6922. !1,
  6923. !0,
  6924. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  6925. !1
  6926. );
  6927. a = new Game.BattleInstantPlay(c, a);
  6928. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6929. a.start();
  6930. } catch (error) {
  6931. console.error('company', error);
  6932. oldSkipMisson.call(this, a, b, c);
  6933. }
  6934. };
  6935.  
  6936. Game.PlayerMissionData.prototype.P$h = function (a) {
  6937. let GM_2 = getFn(Game.GameModel, 2);
  6938. let GM_P2 = getProtoFn(Game.GameModel, 2);
  6939. let CM_20 = getProtoFn(Game.CommandManager, 20);
  6940. let MCL_2 = getProtoFn(Game.MissionCommandList, 2);
  6941. let MBR_15 = getF(Game.MultiBattleResult, 'get_result');
  6942. let RPCCB_15 = getProtoFn(Game.RPCCommandBase, 16);
  6943. let PMD_32 = getProtoFn(Game.PlayerMissionData, 32);
  6944. Game.GameModel[GM_2]()[GM_P2][CM_20][MCL_2](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PMD_32]));
  6945. };
  6946. },
  6947. /*
  6948. tower: function () {
  6949. let PTD_67 = getProtoFn(Game.PlayerTowerData, 67);
  6950. let oldSkipTower = Game.PlayerTowerData.prototype[PTD_67];
  6951. Game.PlayerTowerData.prototype[PTD_67] = function (a) {
  6952. if (!isChecked('passBattle')) {
  6953. oldSkipTower.call(this, a);
  6954. return;
  6955. }
  6956. try {
  6957. var p = new Game.BattlePresets(
  6958. !1,
  6959. !1,
  6960. !0,
  6961. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  6962. !1
  6963. );
  6964. a = new Game.BattleInstantPlay(a, p);
  6965. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6966. a.start();
  6967. } catch (error) {
  6968. console.error('tower', error);
  6969. oldSkipMisson.call(this, a, b, c);
  6970. }
  6971. };
  6972.  
  6973. Game.PlayerTowerData.prototype.P$h = function (a) {
  6974. const GM_2 = getFnP(Game.GameModel, 'get_instance');
  6975. const GM_P2 = getProtoFn(Game.GameModel, 2);
  6976. const CM_29 = getProtoFn(Game.CommandManager, 29);
  6977. const TCL_5 = getProtoFn(Game.TowerCommandList, 5);
  6978. const MBR_15 = getF(Game.MultiBattleResult, 'get_result');
  6979. const RPCCB_15 = getProtoFn(Game.RPCCommandBase, 17);
  6980. const PTD_78 = getProtoFn(Game.PlayerTowerData, 78);
  6981. Game.GameModel[GM_2]()[GM_P2][CM_29][TCL_5](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PTD_78]));
  6982. };
  6983. },
  6984. */
  6985. // skipSelectHero: function() {
  6986. // if (!HOST) throw Error('Use connectGame');
  6987. // Game.PlayerHeroTeamResolver.prototype[getProtoFn(Game.PlayerHeroTeamResolver, 3)] = () => false;
  6988. // },
  6989.  
  6990. // кнопка пропустить
  6991. passBattle: function () {
  6992. let BPP_4 = getProtoFn(Game.BattlePausePopup, 4);
  6993. let oldPassBattle = Game.BattlePausePopup.prototype[BPP_4];
  6994. Game.BattlePausePopup.prototype[BPP_4] = function (a) {
  6995. if (!isChecked('passBattle')) {
  6996. oldPassBattle.call(this, a);
  6997. return;
  6998. }
  6999. try {
  7000. Game.BattlePopup.prototype[getProtoFn(Game.BattlePausePopup, 4)].call(this, a);
  7001. this[getProtoFn(Game.BattlePausePopup, 3)]();
  7002. this[getProtoFn(Game.DisplayObjectContainer, 3)](this.clip[getProtoFn(Game.GuiClipContainer, 2)]());
  7003. this.clip[getProtoFn(Game.BattlePausePopupClip, 1)][getProtoFn(Game.ClipLabelBase, 9)](
  7004. Game.Translate.translate('UI_POPUP_BATTLE_PAUSE')
  7005. );
  7006.  
  7007. this.clip[getProtoFn(Game.BattlePausePopupClip, 2)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  7008. Game.Translate.translate('UI_POPUP_BATTLE_RETREAT'),
  7009. ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 17)]))
  7010. );
  7011. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  7012. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 14)](),
  7013. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 13)]()
  7014. ? ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  7015. : ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  7016. );
  7017.  
  7018. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 0)][
  7019. getProtoFn(Game.ClipLabelBase, 24)
  7020. ]();
  7021. this.clip[getProtoFn(Game.BattlePausePopupClip, 3)][getProtoFn(Game.SettingToggleButton, 3)](
  7022. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 9)]()
  7023. );
  7024. this.clip[getProtoFn(Game.BattlePausePopupClip, 4)][getProtoFn(Game.SettingToggleButton, 3)](
  7025. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 10)]()
  7026. );
  7027. this.clip[getProtoFn(Game.BattlePausePopupClip, 6)][getProtoFn(Game.SettingToggleButton, 3)](
  7028. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 11)]()
  7029. );
  7030. } catch (error) {
  7031. console.error('passBattle', error);
  7032. oldPassBattle.call(this, a);
  7033. }
  7034. };
  7035.  
  7036. let retreatButtonLabel = getF(Game.BattlePausePopupMediator, 'get_retreatButtonLabel');
  7037. let oldFunc = Game.BattlePausePopupMediator.prototype[retreatButtonLabel];
  7038. Game.BattlePausePopupMediator.prototype[retreatButtonLabel] = function () {
  7039. if (isChecked('passBattle')) {
  7040. return I18N('BTN_PASS');
  7041. } else {
  7042. return oldFunc.call(this);
  7043. }
  7044. };
  7045. },
  7046. endlessCards: function () {
  7047. let PDD_21 = getProtoFn(Game.PlayerDungeonData, 21);
  7048. let oldEndlessCards = Game.PlayerDungeonData.prototype[PDD_21];
  7049. Game.PlayerDungeonData.prototype[PDD_21] = function () {
  7050. if (countPredictionCard <= 0) {
  7051. return true;
  7052. } else {
  7053. return oldEndlessCards.call(this);
  7054. }
  7055. };
  7056. },
  7057. speedBattle: function () {
  7058. const get_timeScale = getF(Game.BattleController, 'get_timeScale');
  7059. const oldSpeedBattle = Game.BattleController.prototype[get_timeScale];
  7060. Game.BattleController.prototype[get_timeScale] = function () {
  7061. const speedBattle = Number.parseFloat(getInput('speedBattle'));
  7062. if (!speedBattle) {
  7063. return oldSpeedBattle.call(this);
  7064. }
  7065. try {
  7066. const BC_12 = getProtoFn(Game.BattleController, 12);
  7067. const BSM_12 = getProtoFn(Game.BattleSettingsModel, 12);
  7068. const BP_get_value = getF(Game.BooleanProperty, 'get_value');
  7069. if (this[BC_12][BSM_12][BP_get_value]()) {
  7070. return 0;
  7071. }
  7072. const BSM_2 = getProtoFn(Game.BattleSettingsModel, 2);
  7073. const BC_49 = getProtoFn(Game.BattleController, 49);
  7074. const BSM_1 = getProtoFn(Game.BattleSettingsModel, 1);
  7075. const BC_14 = getProtoFn(Game.BattleController, 14);
  7076. const BC_3 = getFn(Game.BattleController, 3);
  7077. if (this[BC_12][BSM_2][BP_get_value]()) {
  7078. var a = speedBattle * this[BC_49]();
  7079. } else {
  7080. a = this[BC_12][BSM_1][BP_get_value]();
  7081. const maxSpeed = Math.max(...this[BC_14]);
  7082. const multiple = a == this[BC_14].indexOf(maxSpeed) ? (maxSpeed >= 4 ? speedBattle : this[BC_14][a]) : this[BC_14][a];
  7083. a = multiple * Game.BattleController[BC_3][BP_get_value]() * this[BC_49]();
  7084. }
  7085. const BSM_24 = getProtoFn(Game.BattleSettingsModel, 24);
  7086. a > this[BC_12][BSM_24][BP_get_value]() && (a = this[BC_12][BSM_24][BP_get_value]());
  7087. const DS_23 = getFn(Game.DataStorage, 23);
  7088. const get_battleSpeedMultiplier = getF(Game.RuleStorage, 'get_battleSpeedMultiplier', true);
  7089. var b = Game.DataStorage[DS_23][get_battleSpeedMultiplier]();
  7090. const R_1 = getFn(selfGame.Reflect, 1);
  7091. const BC_1 = getFn(Game.BattleController, 1);
  7092. const get_config = getF(Game.BattlePresets, 'get_config');
  7093. null != b &&
  7094. (a = selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  7095. ? a * selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  7096. : a * selfGame.Reflect[R_1](b, 'default'));
  7097. return a;
  7098. } catch (error) {
  7099. console.error('passBatspeedBattletle', error);
  7100. return oldSpeedBattle.call(this);
  7101. }
  7102. };
  7103. },
  7104.  
  7105. /**
  7106. * Acceleration button without Valkyries favor
  7107. *
  7108. * Кнопка ускорения без Покровительства Валькирий
  7109. */
  7110. battleFastKey: function () {
  7111. const PSIVO_9 = getProtoFn(Game.PlayerSubscriptionInfoValueObject, 9);
  7112. const oldBattleFastKey = Game.PlayerSubscriptionInfoValueObject.prototype[PSIVO_9];
  7113. Game.PlayerSubscriptionInfoValueObject.prototype[PSIVO_9] = function () {
  7114. //const BGM_44 = getProtoFn(Game.BattleGuiMediator, 44);
  7115. //const oldBattleFastKey = Game.BattleGuiMediator.prototype[BGM_44];
  7116. //Game.BattleGuiMediator.prototype[BGM_44] = function () {
  7117. let flag = true;
  7118. //console.log(flag)
  7119. if (flag) {
  7120. return true;
  7121. } else {
  7122. return oldBattleFastKey.call(this);
  7123. }
  7124. };
  7125. },
  7126. fastSeason: function () {
  7127. const GameNavigator = selfGame['game.screen.navigator.GameNavigator'];
  7128. const oldFuncName = getProtoFn(GameNavigator, 18);
  7129. const newFuncName = getProtoFn(GameNavigator, 16);
  7130. const oldFastSeason = GameNavigator.prototype[oldFuncName];
  7131. const newFastSeason = GameNavigator.prototype[newFuncName];
  7132. GameNavigator.prototype[oldFuncName] = function (a, b) {
  7133. if (isChecked('fastSeason')) {
  7134. return newFastSeason.apply(this, [a]);
  7135. } else {
  7136. return oldFastSeason.apply(this, [a, b]);
  7137. }
  7138. };
  7139. },
  7140. ShowChestReward: function () {
  7141. const TitanArtifactChest = selfGame['game.mechanics.titan_arena.mediator.chest.TitanArtifactChestRewardPopupMediator'];
  7142. const getOpenAmountTitan = getF(TitanArtifactChest, 'get_openAmount');
  7143. const oldGetOpenAmountTitan = TitanArtifactChest.prototype[getOpenAmountTitan];
  7144. TitanArtifactChest.prototype[getOpenAmountTitan] = function () {
  7145. if (correctShowOpenArtifact) {
  7146. correctShowOpenArtifact--;
  7147. return 100;
  7148. }
  7149. return oldGetOpenAmountTitan.call(this);
  7150. };
  7151.  
  7152. const ArtifactChest = selfGame['game.view.popup.artifactchest.rewardpopup.ArtifactChestRewardPopupMediator'];
  7153. const getOpenAmount = getF(ArtifactChest, 'get_openAmount');
  7154. const oldGetOpenAmount = ArtifactChest.prototype[getOpenAmount];
  7155. ArtifactChest.prototype[getOpenAmount] = function () {
  7156. if (correctShowOpenArtifact) {
  7157. correctShowOpenArtifact--;
  7158. return 100;
  7159. }
  7160. return oldGetOpenAmount.call(this);
  7161. };
  7162.  
  7163. },
  7164. fixCompany: function () {
  7165. const GameBattleView = selfGame['game.mediator.gui.popup.battle.GameBattleView'];
  7166. const BattleThread = selfGame['game.battle.controller.thread.BattleThread'];
  7167. const getOnViewDisposed = getF(BattleThread, 'get_onViewDisposed');
  7168. const getThread = getF(GameBattleView, 'get_thread');
  7169. const oldFunc = GameBattleView.prototype[getThread];
  7170. GameBattleView.prototype[getThread] = function () {
  7171. return (
  7172. oldFunc.call(this) || {
  7173. [getOnViewDisposed]: async () => {},
  7174. }
  7175. );
  7176. };
  7177. },
  7178. BuyTitanArtifact: function () {
  7179. const BIP_4 = getProtoFn(selfGame['game.view.popup.shop.buy.BuyItemPopup'], 4);
  7180. const BuyItemPopup = selfGame['game.view.popup.shop.buy.BuyItemPopup'];
  7181. const oldFunc = BuyItemPopup.prototype[BIP_4];
  7182. BuyItemPopup.prototype[BIP_4] = function () {
  7183. if (isChecked('countControl')) {
  7184. const BuyTitanArtifactItemPopup = selfGame['game.view.popup.shop.buy.BuyTitanArtifactItemPopup'];
  7185. const BTAP_0 = getProtoFn(BuyTitanArtifactItemPopup, 0);
  7186. if (this[BTAP_0]) {
  7187. const BuyTitanArtifactPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyTitanArtifactItemPopupMediator'];
  7188. const BTAM_1 = getProtoFn(BuyTitanArtifactPopupMediator, 1);
  7189. const BuyItemPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyItemPopupMediator'];
  7190. const BIPM_5 = getProtoFn(BuyItemPopupMediator, 5);
  7191. const BIPM_7 = getProtoFn(BuyItemPopupMediator, 7);
  7192. const BIPM_9 = getProtoFn(BuyItemPopupMediator, 9);
  7193.  
  7194. let need = Math.min(this[BTAP_0][BTAM_1](), this[BTAP_0][BIPM_7]);
  7195. need = need ? need : 60;
  7196. this[BTAP_0][BIPM_9] = need;
  7197. this[BTAP_0][BIPM_5] = 10;
  7198. }
  7199. }
  7200. oldFunc.call(this);
  7201. };
  7202. },
  7203. ClanQuestsFastFarm: function () {
  7204. const VipRuleValueObject = selfGame['game.data.storage.rule.VipRuleValueObject'];
  7205. const getClanQuestsFastFarm = getF(VipRuleValueObject, 'get_clanQuestsFastFarm', 1);
  7206. VipRuleValueObject.prototype[getClanQuestsFastFarm] = function () {
  7207. return 0;
  7208. };
  7209. },
  7210. adventureCamera: function () {
  7211. const AMC_40 = getProtoFn(Game.AdventureMapCamera, 40);
  7212. const AMC_5 = getProtoFn(Game.AdventureMapCamera, 5);
  7213. const oldFunc = Game.AdventureMapCamera.prototype[AMC_40];
  7214. Game.AdventureMapCamera.prototype[AMC_40] = function (a) {
  7215. this[AMC_5] = 0.4;
  7216. oldFunc.bind(this)(a);
  7217. };
  7218. },
  7219. unlockMission: function () {
  7220. const WorldMapStoryDrommerHelper = selfGame['game.mediator.gui.worldmap.WorldMapStoryDrommerHelper'];
  7221. const WMSDH_4 = getFn(WorldMapStoryDrommerHelper, 4);
  7222. const WMSDH_7 = getFn(WorldMapStoryDrommerHelper, 7);
  7223. WorldMapStoryDrommerHelper[WMSDH_4] = function () {
  7224. return true;
  7225. };
  7226. WorldMapStoryDrommerHelper[WMSDH_7] = function () {
  7227. return true;
  7228. };
  7229. },
  7230. SendReplayPopUp: function() {
  7231. game_view_popup_ClipBasedPopup.prototype.SendReplayPopUp.call(this);
  7232. //if(this.mediator.get_canShareChat()) {
  7233. var clipFull = new game_mediator_gui_popup_chat_sendreplay_SendReplayPopUpClip();
  7234. game_assets_storage_AssetStorage.rsx.popup_theme.get_factory().create(clipFull,game_assets_storage_AssetStorage.rsx.popup_theme.data.getClipByName("send_replay_popup"));
  7235. this.addChild(clipFull.get_graphics());
  7236. clipFull.tf_title.set_text(com_progrestar_common_lang_Translate.translate("UI_DIALOG_CHAT_SEND_REPLAY_TEXT"));
  7237. clipFull.replay_info.tf_label.set_text(com_progrestar_common_lang_Translate.translate("UI_DIALOG_CHAT_REPLAY_TEXT"));
  7238. clipFull.action_btn.set_label(com_progrestar_common_lang_Translate.translate("UI_POPUP_CHAT_SEND"));
  7239. clipFull.tf_message_input.set_prompt(com_progrestar_common_lang_Translate.translate("UI_DIALOG_CHAT_INPUT_MESSAGE_PROMPT"));
  7240. clipFull.tf_message_input.set_text(this.mediator.get_defauiltText());
  7241. clipFull.action_btn.get_signal_click().add($bind(this,this.handler_sendClick));
  7242. clipFull.replay_info.btn_option.get_signal_click().add($bind(this,this.handler_replayClick));
  7243. this.clip = clipFull;
  7244. /*} else {
  7245. var clipShort = new game_mediator_gui_popup_chat_sendreplay_SendReplayPopUpClipShort();
  7246. game_assets_storage_AssetStorage.rsx.popup_theme.get_factory().create(clipShort,game_assets_storage_AssetStorage.rsx.popup_theme.data.getClipByName("send_replay_popup_short"));
  7247. this.addChild(clipShort.get_graphics());
  7248. this.clip = clipShort;
  7249. }*/
  7250. this.clip.button_close.get_signal_click().add(($_=this.mediator,$bind($_,$_.close)));
  7251. this.clip.tf_replay.set_text(com_progrestar_common_lang_Translate.translate("UI_DIALOG_ARENA_REPLAY_URL"));
  7252. this.clip.replay_url_input.set_text(this.mediator.get_replayURL());
  7253. this.clip.replay_url_input.addEventListener("change",$bind(this,this.handler_replayUrlInputChange));
  7254. this.clip.copy_btn.set_label(com_progrestar_common_lang_Translate.translate("UI_DIALOG_BUTTON_COPY"));
  7255. },
  7256.  
  7257. };
  7258.  
  7259. /**
  7260. * Starts replacing recorded functions
  7261. *
  7262. * Запускает замену записанных функций
  7263. */
  7264. this.activateHacks = function () {
  7265. if (!selfGame) throw Error('Use connectGame');
  7266. for (let func in replaceFunction) {
  7267. try {
  7268. replaceFunction[func]();
  7269. } catch (error) {
  7270. console.error(error);
  7271. }
  7272. }
  7273. }
  7274.  
  7275. /**
  7276. * Returns the game object
  7277. *
  7278. * Возвращает объект игры
  7279. */
  7280. this.getSelfGame = function () {
  7281. return selfGame;
  7282. }
  7283.  
  7284. /**
  7285. * Updates game data
  7286. *
  7287. * Обновляет данные игры
  7288. */
  7289. this.refreshGame = function () {
  7290. (new Game.NextDayUpdatedManager)[getProtoFn(Game.NextDayUpdatedManager, 5)]();
  7291. try {
  7292. cheats.refreshInventory();
  7293. } catch (e) { }
  7294. }
  7295.  
  7296. /**
  7297. * Update inventory
  7298. *
  7299. * Обновляет инвентарь
  7300. */
  7301. this.refreshInventory = async function () {
  7302. const GM_INST = getFnP(Game.GameModel, "get_instance");
  7303. const GM_0 = getProtoFn(Game.GameModel, 0);
  7304. const P_24 = getProtoFn(selfGame["game.model.user.Player"], 24);
  7305. const Player = Game.GameModel[GM_INST]()[GM_0];
  7306. Player[P_24] = new selfGame["game.model.user.inventory.PlayerInventory"]
  7307. Player[P_24].init(await Send({calls:[{name:"inventoryGet",args:{},ident:"body"}]}).then(e => e.results[0].result.response))
  7308. }
  7309. this.updateInventory = function (reward) {
  7310. const GM_INST = getFnP(Game.GameModel, 'get_instance');
  7311. const GM_0 = getProtoFn(Game.GameModel, 0);
  7312. const P_24 = getProtoFn(selfGame['game.model.user.Player'], 24);
  7313. const Player = Game.GameModel[GM_INST]()[GM_0];
  7314. Player[P_24].init(reward);
  7315. };
  7316.  
  7317. this.updateMap = function (data) {
  7318. const PCDD_21 = getProtoFn(selfGame['game.mechanics.clanDomination.model.PlayerClanDominationData'], 21);
  7319. const P_60 = getProtoFn(selfGame['game.model.user.Player'], 60);
  7320. const GM_0 = getProtoFn(Game.GameModel, 0);
  7321. const getInstance = getFnP(selfGame['Game'], 'get_instance');
  7322. const PlayerClanDominationData = Game.GameModel[getInstance]()[GM_0];
  7323. PlayerClanDominationData[P_60][PCDD_21].update(data);
  7324. };
  7325.  
  7326. /**
  7327. * Change the play screen on windowName
  7328. *
  7329. * Сменить экран игры на windowName
  7330. *
  7331. * Possible options:
  7332. *
  7333. * Возможные варианты:
  7334. *
  7335. * 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
  7336. */
  7337. this.goNavigtor = function (windowName) {
  7338. let mechanicStorage = selfGame["game.data.storage.mechanic.MechanicStorage"];
  7339. let window = mechanicStorage[windowName];
  7340. let event = new selfGame["game.mediator.gui.popup.PopupStashEventParams"];
  7341. let Game = selfGame['Game'];
  7342. let navigator = getF(Game, "get_navigator")
  7343. let navigate = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 20)
  7344. let instance = getFnP(Game, 'get_instance');
  7345. Game[instance]()[navigator]()[navigate](window, event);
  7346. }
  7347.  
  7348. /**
  7349. * Move to the sanctuary cheats.goSanctuary()
  7350. *
  7351. * Переместиться в святилище cheats.goSanctuary()
  7352. */
  7353. this.goSanctuary = () => {
  7354. this.goNavigtor("SANCTUARY");
  7355. }
  7356.  
  7357. /**
  7358. * Go to Guild War
  7359. *
  7360. * Перейти к Войне Гильдий
  7361. */
  7362. this.goClanWar = function() {
  7363. let instance = getFnP(Game.GameModel, 'get_instance')
  7364. let player = Game.GameModel[instance]().A;
  7365. let clanWarSelect = selfGame["game.mechanics.cross_clan_war.popup.selectMode.CrossClanWarSelectModeMediator"];
  7366. new clanWarSelect(player).open();
  7367. }
  7368.  
  7369. /**
  7370. * Go to BrawlShop
  7371. *
  7372. * Переместиться в BrawlShop
  7373. */
  7374. this.goBrawlShop = () => {
  7375. const instance = getFnP(Game.GameModel, 'get_instance')
  7376. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  7377. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  7378. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  7379. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  7380.  
  7381. const player = Game.GameModel[instance]().A;
  7382. const shop = player[P_36][PSD_0][IM_0][1038][PSDE_4];
  7383. const shopPopup = new selfGame["game.mechanics.brawl.mediator.BrawlShopPopupMediator"](player, shop)
  7384. shopPopup.open(new selfGame["game.mediator.gui.popup.PopupStashEventParams"])
  7385. }
  7386.  
  7387. /**
  7388. * Returns all stores from game data
  7389. *
  7390. * Возвращает все магазины из данных игры
  7391. */
  7392. this.getShops = () => {
  7393. const instance = getFnP(Game.GameModel, 'get_instance')
  7394. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  7395. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  7396. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  7397.  
  7398. const player = Game.GameModel[instance]().A;
  7399. return player[P_36][PSD_0][IM_0];
  7400. }
  7401.  
  7402. /**
  7403. * Returns the store from the game data by ID
  7404. *
  7405. * Возвращает магазин из данных игры по идетификатору
  7406. */
  7407. this.getShop = (id) => {
  7408. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  7409. const shops = this.getShops();
  7410. const shop = shops[id]?.[PSDE_4];
  7411. return shop;
  7412. }
  7413.  
  7414. /**
  7415. * Moves to the store with the specified ID
  7416. *
  7417. * Перемещает к магазину с указанным идетификатором
  7418. */
  7419. this.goShopId = function (id) {
  7420. const shop = this.getShop(id);
  7421. if (!shop) {
  7422. return;
  7423. }
  7424. let event = new selfGame["game.mediator.gui.popup.PopupStashEventParams"];
  7425. let Game = selfGame['Game'];
  7426. let navigator = getF(Game, "get_navigator");
  7427. let navigate = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 21);
  7428. let instance = getFnP(Game, 'get_instance');
  7429. Game[instance]()[navigator]()[navigate](shop, event);
  7430. }
  7431.  
  7432. /**
  7433. * Opens a list of non-standard stores
  7434. *
  7435. * Открывает список не стандартных магазинов
  7436. */
  7437. this.goCustomShops = async (p = 0) => {
  7438. /** Запрос данных нужных магазинов */
  7439. const calls = [{ name: "shopGetAll", args: {}, ident: "shopGetAll" }];
  7440. const shops = lib.getData('shop');
  7441. for (const id in shops) {
  7442. const check = !shops[id].ident.includes('merchantPromo') &&
  7443. ![1, 4, 5, 6, 7, 8, 9, 10, 11, 1023, 1024].includes(+id);
  7444. if (check) {
  7445. calls.push({
  7446. name: "shopGet", args: { shopId: id }, ident: `shopGet_${id}`
  7447. })
  7448. }
  7449. }
  7450. const result = await Send({ calls }).then(e => e.results.map(n => n.result.response));
  7451. const shopAll = result.shift();
  7452. const DS_32 = getFn(Game.DataStorage, 32)
  7453.  
  7454. const SDS_5 = getProtoFn(selfGame["game.data.storage.shop.ShopDescriptionStorage"], 5)
  7455.  
  7456. const SD_21 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 21);
  7457. const SD_1 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 1);
  7458. const SD_9 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 9);
  7459. const ident = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 11);
  7460.  
  7461. for (let shop of result) {
  7462. shopAll[shop.id] = shop;
  7463. // Снимаем все ограничения с магазинов
  7464. const shopLibData = Game.DataStorage[DS_32][SDS_5](shop.id)
  7465. shopLibData[SD_21] = 1;
  7466. shopLibData[SD_1] = new selfGame["game.model.user.requirement.Requirement"]
  7467. shopLibData[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  7468. teamLevel: 10
  7469. });
  7470. }
  7471. /** Скрываем все остальные магазины */
  7472. for (let id in shops) {
  7473. const shopLibData = Game.DataStorage[DS_32][SDS_5](id)
  7474. if (shopLibData[ident].includes('merchantPromo')) {
  7475. shopLibData[SD_21] = 0;
  7476. shopLibData[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  7477. teamLevel: 999
  7478. });
  7479. }
  7480. }
  7481.  
  7482. const instance = getFnP(Game.GameModel, 'get_instance')
  7483. const GM_0 = getProtoFn(Game.GameModel, 0);
  7484. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  7485. const player = Game.GameModel[instance]()[GM_0];
  7486. /** Пересоздаем объект с магазинами */
  7487. player[P_36] = new selfGame["game.model.user.shop.PlayerShopData"](player);
  7488. player[P_36].init(shopAll);
  7489. /** Даем магазинам новые названия */
  7490. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  7491.  
  7492. const shopName = getFn(cheats.getShop(1), 14);
  7493. const currentShops = this.getShops();
  7494. let count = 0;
  7495. const start = 9 * p + 1;
  7496. const end = start + 8;
  7497. for (let id in currentShops) {
  7498. const shop = currentShops[id][PSDE_4];
  7499. if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  7500. /** Скрываем стандартные магазины */
  7501. shop[SD_21] = 0;
  7502. } else {
  7503. count++;
  7504. if (count < start || count > end) {
  7505. shop[SD_21] = 0;
  7506. continue;
  7507. }
  7508. shop[SD_21] = 1;
  7509. shop[shopName] = cheats.translate("LIB_SHOP_NAME_" + id) + ' ' + id;
  7510. shop[SD_1] = new selfGame["game.model.user.requirement.Requirement"]
  7511. shop[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  7512. teamLevel: 10
  7513. });
  7514. }
  7515. }
  7516. console.log(count, start, end)
  7517. /** Отправляемся в городскую лавку */
  7518. this.goShopId(1);
  7519. }
  7520.  
  7521. /**
  7522. * Opens a list of standard stores
  7523. *
  7524. * Открывает список стандартных магазинов
  7525. */
  7526. this.goDefaultShops = async () => {
  7527. const result = await Send({ calls: [{ name: "shopGetAll", args: {}, ident: "shopGetAll" }] })
  7528. .then(e => e.results.map(n => n.result.response));
  7529. const shopAll = result.shift();
  7530. const shops = lib.getData('shop');
  7531.  
  7532. const DS_8 = getFn(Game.DataStorage, 8)
  7533. const DSB_4 = getProtoFn(selfGame["game.data.storage.DescriptionStorageBase"], 4)
  7534.  
  7535. /** Получаем объект валюты магазина для оторажения */
  7536. const coins = Game.DataStorage[DS_8][DSB_4](85);
  7537. coins.__proto__ = selfGame["game.data.storage.resource.ConsumableDescription"].prototype;
  7538.  
  7539. const DS_32 = getFn(Game.DataStorage, 32)
  7540. const SDS_5 = getProtoFn(selfGame["game.data.storage.shop.ShopDescriptionStorage"], 5)
  7541.  
  7542. const SD_21 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 21);
  7543. for (const id in shops) {
  7544. const shopLibData = Game.DataStorage[DS_32][SDS_5](id)
  7545. if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  7546. shopLibData[SD_21] = 1;
  7547. } else {
  7548. shopLibData[SD_21] = 0;
  7549. }
  7550. }
  7551.  
  7552. const instance = getFnP(Game.GameModel, 'get_instance')
  7553. const GM_0 = getProtoFn(Game.GameModel, 0);
  7554. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  7555. const player = Game.GameModel[instance]()[GM_0];
  7556. /** Пересоздаем объект с магазинами */
  7557. player[P_36] = new selfGame["game.model.user.shop.PlayerShopData"](player);
  7558. player[P_36].init(shopAll);
  7559.  
  7560. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  7561. const currentShops = this.getShops();
  7562. for (let id in currentShops) {
  7563. const shop = currentShops[id][PSDE_4];
  7564. if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  7565. shop[SD_21] = 1;
  7566. } else {
  7567. shop[SD_21] = 0;
  7568. }
  7569. }
  7570. this.goShopId(1);
  7571. }
  7572.  
  7573. /**
  7574. * Opens a list of Secret Wealth stores
  7575. *
  7576. * Открывает список магазинов Тайное богатство
  7577. */
  7578. this.goSecretWealthShops = async () => {
  7579. /** Запрос данных нужных магазинов */
  7580. const calls = [{ name: "shopGetAll", args: {}, ident: "shopGetAll" }];
  7581. const shops = lib.getData('shop');
  7582. for (const id in shops) {
  7583. if (shops[id].ident.includes('merchantPromo') && shops[id].teamLevelToUnlock <= 130) {
  7584. calls.push({
  7585. name: "shopGet", args: { shopId: id }, ident: `shopGet_${id}`
  7586. })
  7587. }
  7588. }
  7589. const result = await Send({ calls }).then(e => e.results.map(n => n.result.response));
  7590. const shopAll = result.shift();
  7591. const DS_32 = getFn(Game.DataStorage, 32)
  7592.  
  7593. const SDS_5 = getProtoFn(selfGame["game.data.storage.shop.ShopDescriptionStorage"], 5)
  7594.  
  7595. const SD_21 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 21);
  7596. const SD_1 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 1);
  7597. const SD_9 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 9);
  7598. const ident = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 11);
  7599. const specialCurrency = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 15);
  7600.  
  7601. const DS_8 = getFn(Game.DataStorage, 8)
  7602. const DSB_4 = getProtoFn(selfGame["game.data.storage.DescriptionStorageBase"], 4)
  7603.  
  7604. /** Получаем объект валюты магазина для оторажения */
  7605. const coins = Game.DataStorage[DS_8][DSB_4](85);
  7606. coins.__proto__ = selfGame["game.data.storage.resource.CoinDescription"].prototype;
  7607.  
  7608. for (let shop of result) {
  7609. shopAll[shop.id] = shop;
  7610. /** Снимаем все ограничения с магазинов */
  7611. const shopLibData = Game.DataStorage[DS_32][SDS_5](shop.id)
  7612. if (shopLibData[ident].includes('merchantPromo')) {
  7613. shopLibData[SD_21] = 1;
  7614. shopLibData[SD_1] = new selfGame["game.model.user.requirement.Requirement"]
  7615. shopLibData[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  7616. teamLevel: 10
  7617. });
  7618. }
  7619. }
  7620.  
  7621. /** Скрываем все остальные магазины */
  7622. for (let id in shops) {
  7623. const shopLibData = Game.DataStorage[DS_32][SDS_5](id)
  7624. if (!shopLibData[ident].includes('merchantPromo')) {
  7625. shopLibData[SD_21] = 0;
  7626. }
  7627. }
  7628.  
  7629. const instance = getFnP(Game.GameModel, 'get_instance')
  7630. const GM_0 = getProtoFn(Game.GameModel, 0);
  7631. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  7632. const player = Game.GameModel[instance]()[GM_0];
  7633. /** Пересоздаем объект с магазинами */
  7634. player[P_36] = new selfGame["game.model.user.shop.PlayerShopData"](player);
  7635. player[P_36].init(shopAll);
  7636. /** Даем магазинам новые названия */
  7637. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  7638.  
  7639. const shopName = getFn(cheats.getShop(1), 14);
  7640. const currentShops = this.getShops();
  7641. for (let id in currentShops) {
  7642. const shop = currentShops[id][PSDE_4];
  7643. if (shop[ident].includes('merchantPromo')) {
  7644. shop[SD_21] = 1;
  7645. shop[specialCurrency] = coins;
  7646. shop[shopName] = cheats.translate("LIB_SHOP_NAME_" + id) + ' ' + id;
  7647. } else if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  7648. /** Скрываем стандартные магазины */
  7649. shop[SD_21] = 0;
  7650. }
  7651. }
  7652. /** Отправляемся в городскую лавку */
  7653. this.goShopId(1);
  7654. }
  7655.  
  7656. /**
  7657. * Change island map
  7658. *
  7659. * Сменить карту острова
  7660. */
  7661. this.changeIslandMap = (mapId = 2) => {
  7662. const GameInst = getFnP(selfGame['Game'], 'get_instance');
  7663. const GM_0 = getProtoFn(Game.GameModel, 0);
  7664. const P_59 = getProtoFn(selfGame["game.model.user.Player"], 60);
  7665. const PSAD_31 = getProtoFn(selfGame['game.mechanics.season_adventure.model.PlayerSeasonAdventureData'], 31);
  7666. const Player = Game.GameModel[GameInst]()[GM_0];
  7667. Player[P_59][PSAD_31]({ id: mapId, seasonAdventure: { id: mapId, startDate: 1701914400, endDate: 1709690400, closed: false } });
  7668.  
  7669. const GN_15 = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 17)
  7670. const navigator = getF(selfGame['Game'], "get_navigator");
  7671. selfGame['Game'][GameInst]()[navigator]()[GN_15](new selfGame["game.mediator.gui.popup.PopupStashEventParams"]);
  7672. }
  7673.  
  7674. /**
  7675. * Game library availability tracker
  7676. *
  7677. * Отслеживание доступности игровой библиотеки
  7678. */
  7679. function checkLibLoad() {
  7680. timeout = setTimeout(() => {
  7681. if (Game.GameModel) {
  7682. changeLib();
  7683. } else {
  7684. checkLibLoad();
  7685. }
  7686. }, 100)
  7687. }
  7688.  
  7689. /**
  7690. * Game library data spoofing
  7691. *
  7692. * Подмена данных игровой библиотеки
  7693. */
  7694. function changeLib() {
  7695. console.log('lib connect');
  7696. const originalStartFunc = Game.GameModel.prototype.start;
  7697. Game.GameModel.prototype.start = function (a, b, c) {
  7698. self.libGame = b.raw;
  7699. self.doneLibLoad(self.libGame);
  7700. try {
  7701. const levels = b.raw.seasonAdventure.level;
  7702. for (const id in levels) {
  7703. const level = levels[id];
  7704. level.clientData.graphics.fogged = level.clientData.graphics.visible
  7705. }
  7706. const adv = b.raw.seasonAdventure.list[1];
  7707. adv.clientData.asset = 'dialog_season_adventure_tiles';
  7708. } catch (e) {
  7709. console.warn(e);
  7710. }
  7711. originalStartFunc.call(this, a, b, c);
  7712. }
  7713. }
  7714.  
  7715. this.LibLoad = function() {
  7716. return new Promise((e) => {
  7717. this.doneLibLoad = e;
  7718. });
  7719. }
  7720.  
  7721. /**
  7722. * Returns the value of a language constant
  7723. *
  7724. * Возвращает значение языковой константы
  7725. * @param {*} langConst language constant // языковая константа
  7726. * @returns
  7727. */
  7728. this.translate = function (langConst) {
  7729. return Game.Translate.translate(langConst);
  7730. }
  7731.  
  7732. connectGame();
  7733. checkLibLoad();
  7734. }
  7735.  
  7736. /**
  7737. * Auto collection of gifts
  7738. *
  7739. * Автосбор подарков
  7740. */
  7741. async function getAutoGifts() {
  7742. const collector = new GiftCodeCollector();
  7743. const giftCodes = await collector.getGiftCodes();
  7744. console.log(giftCodes);
  7745.  
  7746. for (const key of giftCodes)
  7747. send({ calls: [{ name: "registration", args: { giftId:key, user: { referrer: {} } },
  7748. context: { actionTs: Math.floor(performance.now()), cookie: window?.NXAppInfo?.session_id || null }, ident: "body" }] });
  7749. }
  7750.  
  7751. /**
  7752. * To fill the kills in the Forge of Souls
  7753. *
  7754. * Набить килов в горниле душ
  7755. */
  7756. async function bossRatingEvent() {
  7757. const topGet = await Send(JSON.stringify({ calls: [{ name: "topGet", args: { type: "bossRatingTop", extraId: 0 }, ident: "body" }] }));
  7758. if (!topGet || !topGet.results[0].result.response[0]) {
  7759. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7760. return;
  7761. }
  7762. const replayId = topGet.results[0].result.response[0].userData.replayId;
  7763. const result = await Send(JSON.stringify({
  7764. calls: [
  7765. { name: "battleGetReplay", args: { id: replayId }, ident: "battleGetReplay" },
  7766. { name: "heroGetAll", args: {}, ident: "heroGetAll" },
  7767. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  7768. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  7769. ]
  7770. }));
  7771. const bossEventInfo = result.results[3].result.response.find(e => e.offerType == "bossEvent");
  7772. if (!bossEventInfo) {
  7773. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7774. return;
  7775. }
  7776. const usedHeroes = bossEventInfo.progress.usedHeroes;
  7777. const party = Object.values(result.results[0].result.response.replay.attackers);
  7778. const availableHeroes = Object.values(result.results[1].result.response).map(e => e.id);
  7779. const availablePets = Object.values(result.results[2].result.response).map(e => e.id);
  7780. const calls = [];
  7781. /**
  7782. * First pack
  7783. *
  7784. * Первая пачка
  7785. */
  7786. const args = {
  7787. heroes: [],
  7788. favor: {}
  7789. }
  7790. for (let hero of party) {
  7791. if (hero.id >= 6000 && availablePets.includes(hero.id)) {
  7792. args.pet = hero.id;
  7793. continue;
  7794. }
  7795. if (!availableHeroes.includes(hero.id) || usedHeroes.includes(hero.id)) {
  7796. continue;
  7797. }
  7798. args.heroes.push(hero.id);
  7799. if (hero.favorPetId) {
  7800. args.favor[hero.id] = hero.favorPetId;
  7801. }
  7802. }
  7803. if (args.heroes.length) {
  7804. calls.push({
  7805. name: "bossRatingEvent_startBattle",
  7806. args,
  7807. ident: "body_0"
  7808. });
  7809. }
  7810. /**
  7811. * Other packs
  7812. *
  7813. * Другие пачки
  7814. */
  7815. let heroes = [];
  7816. let count = 1;
  7817. while (heroId = availableHeroes.pop()) {
  7818. if (args.heroes.includes(heroId) || usedHeroes.includes(heroId)) {
  7819. continue;
  7820. }
  7821. heroes.push(heroId);
  7822. if (heroes.length == 5) {
  7823. calls.push({
  7824. name: "bossRatingEvent_startBattle",
  7825. args: {
  7826. heroes: [...heroes],
  7827. pet: availablePets[Math.floor(Math.random() * availablePets.length)]
  7828. },
  7829. ident: "body_" + count
  7830. });
  7831. heroes = [];
  7832. count++;
  7833. }
  7834. }
  7835.  
  7836. if (!calls.length) {
  7837. setProgress(`${I18N('NO_HEROES')}`, true);
  7838. return;
  7839. }
  7840.  
  7841. const resultBattles = await Send(JSON.stringify({ calls }));
  7842. console.log(resultBattles);
  7843. rewardBossRatingEvent();
  7844. }
  7845.  
  7846. /**
  7847. * Collecting Rewards from the Forge of Souls
  7848. *
  7849. * Сбор награды из Горнила Душ
  7850. */
  7851. function rewardBossRatingEvent() {
  7852. let rewardBossRatingCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  7853. send(rewardBossRatingCall, function (data) {
  7854. let bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  7855. if (!bossEventInfo) {
  7856. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7857. return;
  7858. }
  7859.  
  7860. let farmedChests = bossEventInfo.progress.farmedChests;
  7861. let score = bossEventInfo.progress.score;
  7862. setProgress(`${I18N('DAMAGE_AMOUNT')}: ${score}`);
  7863. let revard = bossEventInfo.reward;
  7864.  
  7865. let getRewardCall = {
  7866. calls: []
  7867. }
  7868.  
  7869. let count = 0;
  7870. for (let i = 1; i < 10; i++) {
  7871. if (farmedChests.includes(i)) {
  7872. continue;
  7873. }
  7874. if (score < revard[i].score) {
  7875. break;
  7876. }
  7877. getRewardCall.calls.push({
  7878. name: "bossRatingEvent_getReward",
  7879. args: {
  7880. rewardId: i
  7881. },
  7882. ident: "body_" + i
  7883. });
  7884. count++;
  7885. }
  7886. if (!count) {
  7887. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  7888. return;
  7889. }
  7890.  
  7891. send(JSON.stringify(getRewardCall), e => {
  7892. console.log(e);
  7893. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  7894. });
  7895. });
  7896. }
  7897.  
  7898. /**
  7899. * Collect Easter eggs and event rewards
  7900. *
  7901. * Собрать пасхалки и награды событий
  7902. */
  7903. function offerFarmAllReward() {
  7904. const offerGetAllCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  7905. return Send(offerGetAllCall).then((data) => {
  7906. const offerGetAll = data.results[0].result.response.filter(e => e.type == "reward" && !e?.freeRewardObtained && e.reward);
  7907. if (!offerGetAll.length) {
  7908. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  7909. return;
  7910. }
  7911.  
  7912. const calls = [];
  7913. for (let reward of offerGetAll) {
  7914. calls.push({
  7915. name: "offerFarmReward",
  7916. args: {
  7917. offerId: reward.id
  7918. },
  7919. ident: "offerFarmReward_" + reward.id
  7920. });
  7921. }
  7922.  
  7923. return Send(JSON.stringify({ calls })).then(e => {
  7924. console.log(e);
  7925. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  7926. });
  7927. });
  7928. }
  7929.  
  7930. /**
  7931. * Assemble Outland
  7932. *
  7933. * Собрать запределье
  7934. */
  7935. function getOutland() {
  7936. return new Promise(function (resolve, reject) {
  7937. send('{"calls":[{"name":"bossGetAll","args":{},"ident":"bossGetAll"}]}', e => {
  7938. let bosses = e.results[0].result.response;
  7939.  
  7940. let bossRaidOpenChestCall = {
  7941. calls: []
  7942. };
  7943.  
  7944. for (let boss of bosses) {
  7945. if (boss.mayRaid) {
  7946. bossRaidOpenChestCall.calls.push({
  7947. name: "bossRaid",
  7948. args: {
  7949. bossId: boss.id
  7950. },
  7951. ident: "bossRaid_" + boss.id
  7952. });
  7953. bossRaidOpenChestCall.calls.push({
  7954. name: "bossOpenChest",
  7955. args: {
  7956. bossId: boss.id,
  7957. amount: 1,
  7958. starmoney: 0
  7959. },
  7960. ident: "bossOpenChest_" + boss.id
  7961. });
  7962. } else if (boss.chestId == 1) {
  7963. bossRaidOpenChestCall.calls.push({
  7964. name: "bossOpenChest",
  7965. args: {
  7966. bossId: boss.id,
  7967. amount: 1,
  7968. starmoney: 0
  7969. },
  7970. ident: "bossOpenChest_" + boss.id
  7971. });
  7972. }
  7973. }
  7974.  
  7975. if (!bossRaidOpenChestCall.calls.length) {
  7976. setProgress(`${I18N('OUTLAND')} ${I18N('NOTHING_TO_COLLECT')}`, true);
  7977. resolve();
  7978. return;
  7979. }
  7980.  
  7981. send(JSON.stringify(bossRaidOpenChestCall), e => {
  7982. setProgress(`${I18N('OUTLAND')} ${I18N('COLLECTED')}`, true);
  7983. resolve();
  7984. });
  7985. });
  7986. });
  7987. }
  7988.  
  7989. /**
  7990. * Collect all rewards
  7991. *
  7992. * Собрать все награды
  7993. */
  7994. function questAllFarm() {
  7995. return new Promise(function (resolve, reject) {
  7996. let questGetAllCall = {
  7997. calls: [{
  7998. name: "questGetAll",
  7999. args: {},
  8000. ident: "body"
  8001. }]
  8002. }
  8003. send(JSON.stringify(questGetAllCall), function (data) {
  8004. let questGetAll = data.results[0].result.response;
  8005. const questAllFarmCall = {
  8006. calls: []
  8007. }
  8008. let number = 0;
  8009. for (let quest of questGetAll) {
  8010. if (quest.id < 1e6 && quest.state == 2) {
  8011. questAllFarmCall.calls.push({
  8012. name: "questFarm",
  8013. args: {
  8014. questId: quest.id
  8015. },
  8016. ident: `group_${number}_body`
  8017. });
  8018. number++;
  8019. }
  8020. }
  8021.  
  8022. if (!questAllFarmCall.calls.length) {
  8023. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  8024. resolve();
  8025. return;
  8026. }
  8027.  
  8028. send(JSON.stringify(questAllFarmCall), function (res) {
  8029. console.log(res);
  8030. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  8031. resolve();
  8032. });
  8033. });
  8034. })
  8035. }
  8036.  
  8037. /**
  8038. * Mission auto repeat
  8039. *
  8040. * Автоповтор миссии
  8041. * isStopSendMission = false;
  8042. * isSendsMission = true;
  8043. **/
  8044. this.sendsMission = async function (param) {
  8045. if (isStopSendMission) {
  8046. isSendsMission = false;
  8047. console.log(I18N('STOPPED'));
  8048. setProgress('');
  8049. await popup.confirm(`${I18N('STOPPED')}<br>${I18N('REPETITIONS')}: ${param.count}`, [{
  8050. msg: 'Ok',
  8051. result: true
  8052. }, ])
  8053. return;
  8054. }
  8055. lastMissionBattleStart = Date.now();
  8056. let missionStartCall = {
  8057. "calls": [{
  8058. "name": "missionStart",
  8059. "args": lastMissionStart,
  8060. "ident": "body"
  8061. }]
  8062. }
  8063. /**
  8064. * Mission Request
  8065. *
  8066. * Запрос на выполнение мисcии
  8067. */
  8068. SendRequest(JSON.stringify(missionStartCall), async e => {
  8069. if (e['error']) {
  8070. isSendsMission = false;
  8071. console.log(e['error']);
  8072. setProgress('');
  8073. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  8074. await popup.confirm(msg, [
  8075. {msg: 'Ok', result: true},
  8076. ])
  8077. return;
  8078. }
  8079. /**
  8080. * Mission data calculation
  8081. *
  8082. * Расчет данных мисcии
  8083. */
  8084. BattleCalc(e.results[0].result.response, 'get_tower', async r => {
  8085. /** missionTimer */
  8086. let timer = getTimer(r.battleTime) + 5;
  8087. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  8088. if (period < timer) {
  8089. timer = timer - period;
  8090. await countdownTimer(timer, `${I18N('MISSIONS_PASSED')}: ${param.count}`);
  8091. }
  8092.  
  8093. let missionEndCall = {
  8094. "calls": [{
  8095. "name": "missionEnd",
  8096. "args": {
  8097. "id": param.id,
  8098. "result": r.result,
  8099. "progress": r.progress
  8100. },
  8101. "ident": "body"
  8102. }]
  8103. }
  8104. /**
  8105. * Mission Completion Request
  8106. *
  8107. * Запрос на завершение миссии
  8108. */
  8109. SendRequest(JSON.stringify(missionEndCall), async (e) => {
  8110. if (e['error']) {
  8111. isSendsMission = false;
  8112. console.log(e['error']);
  8113. setProgress('');
  8114. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  8115. await popup.confirm(msg, [
  8116. {msg: 'Ok', result: true},
  8117. ])
  8118. return;
  8119. }
  8120. r = e.results[0].result.response;
  8121. if (r['error']) {
  8122. isSendsMission = false;
  8123. console.log(r['error']);
  8124. setProgress('');
  8125. await popup.confirm(`<br>${I18N('REPETITIONS')}: ${param.count}` + ' 3 ' + r['error'], [
  8126. {msg: 'Ok', result: true},
  8127. ])
  8128. return;
  8129. }
  8130.  
  8131. param.count++;
  8132. let RaidMission = getInput('countRaid');
  8133.  
  8134. if (RaidMission==param.count){
  8135. isStopSendMission = true;
  8136. console.log(RaidMission);
  8137. }
  8138. setProgress(`${I18N('MISSIONS_PASSED')}: ${param.count} (${I18N('STOP')})`, false, () => {
  8139. isStopSendMission = true;
  8140. });
  8141. setTimeout(sendsMission, 1, param);
  8142. });
  8143. })
  8144. });
  8145. }
  8146.  
  8147. /**
  8148. * Opening of russian dolls
  8149. *
  8150. * Открытие матрешек
  8151. */
  8152. async function openRussianDolls(libId, amount) {
  8153. let sum = 0;
  8154. const sumResult = {};
  8155. let count = 0;
  8156.  
  8157. while (amount) {
  8158. sum += amount;
  8159. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`);
  8160. const calls = [
  8161. {
  8162. name: 'consumableUseLootBox',
  8163. args: { libId, amount },
  8164. ident: 'body',
  8165. },
  8166. ];
  8167. const response = await Send(JSON.stringify({ calls })).then((e) => e.results[0].result.response);
  8168. let [countLootBox, result] = Object.entries(response).pop();
  8169. count += +countLootBox;
  8170. let newCount = 0;
  8171.  
  8172. if (result?.consumable && result.consumable[libId]) {
  8173. newCount = result.consumable[libId];
  8174. delete result.consumable[libId];
  8175. }
  8176.  
  8177. mergeItemsObj(sumResult, result);
  8178. amount = newCount;
  8179. }
  8180.  
  8181. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`, 5000);
  8182. return [count, sumResult];
  8183. }
  8184.  
  8185. function mergeItemsObj(obj1, obj2) {
  8186. for (const key in obj2) {
  8187. if (obj1[key]) {
  8188. if (typeof obj1[key] == 'object') {
  8189. for (const innerKey in obj2[key]) {
  8190. obj1[key][innerKey] = (obj1[key][innerKey] || 0) + obj2[key][innerKey];
  8191. }
  8192. } else {
  8193. obj1[key] += obj2[key] || 0;
  8194. }
  8195. } else {
  8196. obj1[key] = obj2[key];
  8197. }
  8198. }
  8199.  
  8200. return obj1;
  8201. }
  8202.  
  8203. /**
  8204. * Collect all mail, except letters with energy and charges of the portal
  8205. *
  8206. * Собрать всю почту, кроме писем с энергией и зарядами портала
  8207. */
  8208. function mailGetAll() {
  8209. const getMailInfo = '{"calls":[{"name":"mailGetAll","args":{},"ident":"body"}]}';
  8210.  
  8211. return Send(getMailInfo).then(dataMail => {
  8212. const letters = dataMail.results[0].result.response.letters;
  8213. const letterIds = lettersFilter(letters);
  8214. if (!letterIds.length) {
  8215. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  8216. return;
  8217. }
  8218.  
  8219. const calls = [
  8220. { name: "mailFarm", args: { letterIds }, ident: "body" }
  8221. ];
  8222.  
  8223. return Send(JSON.stringify({ calls })).then(res => {
  8224. const lettersIds = res.results[0].result.response;
  8225. if (lettersIds) {
  8226. const countLetters = Object.keys(lettersIds).length;
  8227. setProgress(`${I18N('RECEIVED')} ${countLetters} ${I18N('LETTERS')}`, true);
  8228. }
  8229. });
  8230. });
  8231. }
  8232.  
  8233. /**
  8234. * Filters received emails
  8235. *
  8236. * Фильтрует получаемые письма
  8237. */
  8238. function lettersFilter(letters) {
  8239. const lettersIds = [];
  8240. for (let l in letters) {
  8241. letter = letters[l];
  8242. const reward = letter?.reward;
  8243. if (!reward || !Object.keys(reward).length) {
  8244. continue;
  8245. }
  8246. /**
  8247. * Mail Collection Exceptions
  8248. *
  8249. * Исключения на сбор писем
  8250. */
  8251. const isFarmLetter = !(
  8252. /** Portals // сферы портала */
  8253. (reward?.refillable ? reward.refillable[45] : false) ||
  8254. /** Energy // энергия */
  8255. (reward?.stamina ? reward.stamina : false) ||
  8256. /** accelerating energy gain // ускорение набора энергии */
  8257. (reward?.buff ? true : false) ||
  8258. /** VIP Points // вип очки */
  8259. (reward?.vipPoints ? reward.vipPoints : false) ||
  8260. /** souls of heroes // душы героев */
  8261. (reward?.fragmentHero ? true : false) ||
  8262. /** heroes // герои */
  8263. (reward?.bundleHeroReward ? true : false)
  8264. );
  8265. if (isFarmLetter) {
  8266. lettersIds.push(~~letter.id);
  8267. continue;
  8268. }
  8269. /**
  8270. * Если до окончания годности письма менее 24 часов,
  8271. * то оно собирается не смотря на исключения
  8272. */
  8273. const availableUntil = +letter?.availableUntil;
  8274. if (availableUntil) {
  8275. const maxTimeLeft = 24 * 60 * 60 * 1000;
  8276. const timeLeft = (new Date(availableUntil * 1000) - new Date())
  8277. console.log('Time left:', timeLeft)
  8278. if (timeLeft < maxTimeLeft) {
  8279. lettersIds.push(~~letter.id);
  8280. continue;
  8281. }
  8282. }
  8283. }
  8284. return lettersIds;
  8285. }
  8286.  
  8287. /**
  8288. * Displaying information about the areas of the portal and attempts on the VG
  8289. *
  8290. * Отображение информации о сферах портала и попытках на ВГ
  8291. */
  8292. async function justInfo() {
  8293. return new Promise(async (resolve, reject) => {
  8294. const calls = [{
  8295. name: "userGetInfo",
  8296. args: {},
  8297. ident: "userGetInfo"
  8298. },
  8299. {
  8300. name: "clanWarGetInfo",
  8301. args: {},
  8302. ident: "clanWarGetInfo"
  8303. },
  8304. {
  8305. name: "titanArenaGetStatus",
  8306. args: {},
  8307. ident: "titanArenaGetStatus"
  8308. }];
  8309. const result = await Send(JSON.stringify({ calls }));
  8310. const infos = result.results;
  8311. const portalSphere = infos[0].result.response.refillable.find(n => n.id == 45);
  8312. const clanWarMyTries = infos[1].result.response?.myTries ?? 0;
  8313. const arePointsMax = infos[1].result.response?.arePointsMax;
  8314. const titansLevel = +(infos[2].result.response?.tier ?? 0);
  8315. const titansStatus = infos[2].result.response?.status; //peace_time || battle
  8316.  
  8317. const sanctuaryButton = buttons['goToSanctuary'].button;
  8318. const clanWarButton = buttons['goToClanWar'].button;
  8319. const titansArenaButton = buttons['testTitanArena'].button;
  8320.  
  8321. /*if (portalSphere.amount) {
  8322. sanctuaryButton.style.color = portalSphere.amount >= 3 ? 'red' : 'brown';
  8323. sanctuaryButton.title = `${I18N('SANCTUARY_TITLE')}\n${portalSphere.amount} ${I18N('PORTALS')}`;
  8324. } else {*/
  8325. sanctuaryButton.style.color = '';
  8326. sanctuaryButton.title = I18N('SANCTUARY_TITLE');
  8327. //}
  8328. /*if (clanWarMyTries && !arePointsMax) {
  8329. clanWarButton.style.color = 'red';
  8330. clanWarButton.title = `${I18N('GUILD_WAR_TITLE')}\n${clanWarMyTries}${I18N('ATTEMPTS')}`;
  8331. } else {*/
  8332. clanWarButton.style.color = '';
  8333. clanWarButton.title = I18N('GUILD_WAR_TITLE');
  8334. //}
  8335.  
  8336. /*if (titansLevel < 7 && titansStatus == 'battle') {
  8337. const partColor = Math.floor(125 * titansLevel / 7);
  8338. titansArenaButton.style.color = `rgb(255,${partColor},${partColor})`;
  8339. titansArenaButton.title = `${I18N('TITAN_ARENA_TITLE')}\n${titansLevel} ${I18N('LEVEL')}`;
  8340. } else {*/
  8341. titansArenaButton.style.color = '';
  8342. titansArenaButton.title = I18N('TITAN_ARENA_TITLE');
  8343. //}
  8344. //тест убрал подсветку красным в меню
  8345. const imgPortal =
  8346. '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';
  8347.  
  8348. setProgress('<img src="' + imgPortal + '" style="height: 25px;position: relative;top: 5px;"> ' + `${portalSphere.amount} </br> ${I18N('GUILD_WAR')}: ${clanWarMyTries}`, true);
  8349. resolve();
  8350. });
  8351. }
  8352. // тест сделать все
  8353. /** Отправить подарки мое*/
  8354. function testclanSendDailyGifts() {
  8355.  
  8356. send('{"calls":[{"name":"clanSendDailyGifts","args":{},"ident":"clanSendDailyGifts"}]}', e => {
  8357. setProgress('Награды собраны', true);});
  8358. }
  8359. /** Открой сферу артефактов титанов*/
  8360. function testtitanArtifactChestOpen() {
  8361. send('{"calls":[{"name":"titanArtifactChestOpen","args":{"amount":1,"free":true},"ident":"body"}]}',
  8362. isWeCanDo => {
  8363. return info['inventoryGet']?.consumable[55] > 0
  8364. //setProgress('Награды собраны', true);
  8365. });
  8366. }
  8367. /** Воспользуйся призывом питомцев 1 раз*/
  8368. function testpet_chestOpen() {
  8369. send('{"calls":[{"name":"pet_chestOpen","args":{"amount":1,"paid":false},"ident":"pet_chestOpen"}]}',
  8370. isWeCanDo => {
  8371. return info['inventoryGet']?.consumable[90] > 0
  8372. //setProgress('Награды собраны', true);
  8373. });
  8374. }
  8375.  
  8376. async function getDailyBonus() {
  8377. const dailyBonusInfo = await Send(JSON.stringify({
  8378. calls: [{
  8379. name: "dailyBonusGetInfo",
  8380. args: {},
  8381. ident: "body"
  8382. }]
  8383. })).then(e => e.results[0].result.response);
  8384. const { availableToday, availableVip, currentDay } = dailyBonusInfo;
  8385.  
  8386. if (!availableToday) {
  8387. console.log('Уже собрано');
  8388. return;
  8389. }
  8390.  
  8391. const currentVipPoints = +userInfo.vipPoints;
  8392. const dailyBonusStat = lib.getData('dailyBonusStatic');
  8393. const vipInfo = lib.getData('level').vip;
  8394. let currentVipLevel = 0;
  8395. for (let i in vipInfo) {
  8396. vipLvl = vipInfo[i];
  8397. if (currentVipPoints >= vipLvl.vipPoints) {
  8398. currentVipLevel = vipLvl.level;
  8399. }
  8400. }
  8401. const vipLevelDouble = dailyBonusStat[`${currentDay}_0_0`].vipLevelDouble;
  8402.  
  8403. const calls = [{
  8404. name: "dailyBonusFarm",
  8405. args: {
  8406. vip: availableVip && currentVipLevel >= vipLevelDouble ? 1 : 0
  8407. },
  8408. ident: "body"
  8409. }];
  8410.  
  8411. const result = await Send(JSON.stringify({ calls }));
  8412. if (result.error) {
  8413. console.error(result.error);
  8414. return;
  8415. }
  8416.  
  8417. const reward = result.results[0].result.response;
  8418. const type = Object.keys(reward).pop();
  8419. const itemId = Object.keys(reward[type]).pop();
  8420. const count = reward[type][itemId];
  8421. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  8422.  
  8423. console.log(`Ежедневная награда: Получено ${count} ${itemName}`, reward);
  8424. }
  8425.  
  8426. async function farmStamina(lootBoxId = 148) {
  8427. const lootBox = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"}]}')
  8428. .then(e => e.results[0].result.response.consumable[148]);
  8429.  
  8430. /** Добавить другие ящики */
  8431. /**
  8432. * 144 - медная шкатулка
  8433. * 145 - бронзовая шкатулка
  8434. * 148 - платиновая шкатулка
  8435. */
  8436. if (!lootBox) {
  8437. setProgress(I18N('NO_BOXES'), true);
  8438. return;
  8439. }
  8440.  
  8441. let maxFarmEnergy = getSaveVal('maxFarmEnergy', 100);
  8442. const result = await popup.confirm(I18N('OPEN_LOOTBOX', { lootBox }), [
  8443. { result: false, isClose: true },
  8444. { msg: I18N('BTN_YES'), result: true },
  8445. { msg: I18N('STAMINA'), isInput: true, default: maxFarmEnergy },
  8446. ]);
  8447.  
  8448. if (!+result) {
  8449. return;
  8450. }
  8451.  
  8452. if ((typeof result) !== 'boolean' && Number.parseInt(result)) {
  8453. maxFarmEnergy = +result;
  8454. setSaveVal('maxFarmEnergy', maxFarmEnergy);
  8455. } else {
  8456. maxFarmEnergy = 0;
  8457. }
  8458.  
  8459. let collectEnergy = 0;
  8460. for (let count = lootBox; count > 0; count--) {
  8461. const response = await Send('{"calls":[{"name":"consumableUseLootBox","args":{"libId":148,"amount":1},"ident":"body"}]}').then(
  8462. (e) => e.results[0].result.response
  8463. );
  8464. const result = Object.values(response).pop();
  8465. if ('stamina' in result) {
  8466. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox} ${I18N('STAMINA')} +${result.stamina}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  8467. console.log(`${ I18N('STAMINA') } + ${ result.stamina }`);
  8468. if (!maxFarmEnergy) {
  8469. return;
  8470. }
  8471. collectEnergy += +result.stamina;
  8472. if (collectEnergy >= maxFarmEnergy) {
  8473. console.log(`${I18N('STAMINA')} + ${ collectEnergy }`);
  8474. setProgress(`${I18N('STAMINA')} + ${ collectEnergy }`, false);
  8475. return;
  8476. }
  8477. } else {
  8478. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  8479. console.log(result);
  8480. }
  8481. }
  8482.  
  8483. setProgress(I18N('BOXES_OVER'), true);
  8484. }
  8485.  
  8486. async function fillActive() {
  8487. const data = await Send(JSON.stringify({
  8488. calls: [{
  8489. name: "questGetAll",
  8490. args: {},
  8491. ident: "questGetAll"
  8492. }, {
  8493. name: "inventoryGet",
  8494. args: {},
  8495. ident: "inventoryGet"
  8496. }, {
  8497. name: "clanGetInfo",
  8498. args: {},
  8499. ident: "clanGetInfo"
  8500. }
  8501. ]
  8502. })).then(e => e.results.map(n => n.result.response));
  8503.  
  8504. const quests = data[0];
  8505. const inv = data[1];
  8506. const stat = data[2].stat;
  8507. const maxActive = 2000 - stat.todayItemsActivity;
  8508. if (maxActive <= 0) {
  8509. setProgress(I18N('NO_MORE_ACTIVITY'), true);
  8510. return;
  8511. }
  8512.  
  8513. let countGetActive = 0;
  8514. const quest = quests.find(e => e.id > 10046 && e.id < 10051);
  8515. if (quest) {
  8516. countGetActive = 1750 - quest.progress;
  8517. }
  8518.  
  8519. if (countGetActive <= 0) {
  8520. countGetActive = maxActive;
  8521. }
  8522. console.log(countGetActive);
  8523.  
  8524. countGetActive = +(await popup.confirm(I18N('EXCHANGE_ITEMS', { maxActive }), [
  8525. { result: false, isClose: true },
  8526. { msg: I18N('GET_ACTIVITY'), isInput: true, default: countGetActive.toString() },
  8527. ]));
  8528.  
  8529. if (!countGetActive) {
  8530. return;
  8531. }
  8532.  
  8533. if (countGetActive > maxActive) {
  8534. countGetActive = maxActive;
  8535. }
  8536.  
  8537. const items = lib.getData('inventoryItem');
  8538.  
  8539. let itemsInfo = [];
  8540. for (let type of ['gear', 'scroll']) {
  8541. for (let i in inv[type]) {
  8542. const v = items[type][i]?.enchantValue || 0;
  8543. itemsInfo.push({
  8544. id: i,
  8545. count: inv[type][i],
  8546. v,
  8547. type
  8548. })
  8549. }
  8550. const invType = 'fragment' + type.toLowerCase().charAt(0).toUpperCase() + type.slice(1);
  8551. for (let i in inv[invType]) {
  8552. const v = items[type][i]?.fragmentEnchantValue || 0;
  8553. itemsInfo.push({
  8554. id: i,
  8555. count: inv[invType][i],
  8556. v,
  8557. type: invType
  8558. })
  8559. }
  8560. }
  8561. itemsInfo = itemsInfo.filter(e => e.v < 4 && e.count > 200);
  8562. itemsInfo = itemsInfo.sort((a, b) => b.count - a.count);
  8563. console.log(itemsInfo);
  8564. const activeItem = itemsInfo.shift();
  8565. console.log(activeItem);
  8566. const countItem = Math.ceil(countGetActive / activeItem.v);
  8567. if (countItem > activeItem.count) {
  8568. setProgress(I18N('NOT_ENOUGH_ITEMS'), true);
  8569. console.log(activeItem);
  8570. return;
  8571. }
  8572.  
  8573. await Send(JSON.stringify({
  8574. calls: [{
  8575. name: "clanItemsForActivity",
  8576. args: {
  8577. items: {
  8578. [activeItem.type]: {
  8579. [activeItem.id]: countItem
  8580. }
  8581. }
  8582. },
  8583. ident: "body"
  8584. }]
  8585. })).then(e => {
  8586. /** TODO: Вывести потраченые предметы */
  8587. console.log(e);
  8588. setProgress(`${I18N('ACTIVITY_RECEIVED')}: ` + e.results[0].result.response, true);
  8589. });
  8590. }
  8591.  
  8592. async function buyHeroFragments() {
  8593. const result = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"},{"name":"shopGetAll","args":{},"ident":"shopGetAll"}]}')
  8594. .then(e => e.results.map(n => n.result.response));
  8595. const inv = result[0];
  8596. const shops = Object.values(result[1]).filter(shop => [4, 5, 6, 8, 9, 10, 17].includes(shop.id));
  8597. const calls = [];
  8598.  
  8599. for (let shop of shops) {
  8600. const slots = Object.values(shop.slots);
  8601. for (const slot of slots) {
  8602. /* Уже куплено */
  8603. if (slot.bought) {
  8604. continue;
  8605. }
  8606. /* Не душа героя */
  8607. if (!('fragmentHero' in slot.reward)) {
  8608. continue;
  8609. }
  8610. const coin = Object.keys(slot.cost).pop();
  8611. const coinId = Object.keys(slot.cost[coin]).pop();
  8612. const stock = inv[coin][coinId] || 0;
  8613. /* Не хватает на покупку */
  8614. if (slot.cost[coin][coinId] > stock) {
  8615. continue;
  8616. }
  8617. inv[coin][coinId] -= slot.cost[coin][coinId];
  8618. calls.push({
  8619. name: "shopBuy",
  8620. args: {
  8621. shopId: shop.id,
  8622. slot: slot.id,
  8623. cost: slot.cost,
  8624. reward: slot.reward,
  8625. },
  8626. ident: `shopBuy_${shop.id}_${slot.id}`,
  8627. })
  8628. }
  8629. }
  8630.  
  8631. if (!calls.length) {
  8632. setProgress(I18N('NO_PURCHASABLE_HERO_SOULS'), true);
  8633. return;
  8634. }
  8635.  
  8636. const bought = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  8637. if (!bought) {
  8638. console.log('что-то пошло не так')
  8639. return;
  8640. }
  8641.  
  8642. let countHeroSouls = 0;
  8643. for (const buy of bought) {
  8644. countHeroSouls += +Object.values(Object.values(buy).pop()).pop();
  8645. }
  8646. console.log(countHeroSouls, bought, calls);
  8647. setProgress(I18N('PURCHASED_HERO_SOULS', { countHeroSouls }), true);
  8648. }
  8649.  
  8650. /** Открыть платные сундуки в Запределье за 90 */
  8651. async function bossOpenChestPay() {
  8652. const callsNames = ['userGetInfo', 'bossGetAll', 'specialOffer_getAll', 'getTime'];
  8653. const info = await Send({ calls: callsNames.map((name) => ({ name, args: {}, ident: name })) }).then((e) =>
  8654. e.results.map((n) => n.result.response)
  8655. );
  8656.  
  8657. const user = info[0];
  8658. const boses = info[1];
  8659. const offers = info[2];
  8660. const time = info[3];
  8661.  
  8662. const discountOffer = offers.find((e) => e.offerType == 'costReplaceOutlandChest');
  8663.  
  8664. let discount = 1;
  8665. if (discountOffer && discountOffer.endTime > time) {
  8666. discount = 1 - discountOffer.offerData.outlandChest.discountPercent / 100;
  8667. }
  8668.  
  8669. cost9chests = 540 * discount;
  8670. cost18chests = 1740 * discount;
  8671. costFirstChest = 90 * discount;
  8672. costSecondChest = 200 * discount;
  8673.  
  8674. const currentStarMoney = user.starMoney;
  8675. if (currentStarMoney < cost9chests) {
  8676. setProgress('Недостаточно изюма, нужно ' + cost9chests + ' у Вас ' + currentStarMoney, true);
  8677. return;
  8678. }
  8679.  
  8680. const imgEmerald =
  8681. "<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='>";
  8682.  
  8683. if (currentStarMoney < cost9chests) {
  8684. setProgress(I18N('NOT_ENOUGH_EMERALDS_540', { currentStarMoney, imgEmerald }), true);
  8685. return;
  8686. }
  8687.  
  8688. const buttons = [{ result: false, isClose: true }];
  8689.  
  8690. if (currentStarMoney >= cost9chests) {
  8691. buttons.push({
  8692. msg: I18N('BUY_OUTLAND_BTN', { count: 9, countEmerald: cost9chests, imgEmerald }),
  8693. result: [costFirstChest, costFirstChest, 0],
  8694. });
  8695. }
  8696.  
  8697. if (currentStarMoney >= cost18chests) {
  8698. buttons.push({
  8699. msg: I18N('BUY_OUTLAND_BTN', { count: 18, countEmerald: cost18chests, imgEmerald }),
  8700. result: [costFirstChest, costFirstChest, 0, costSecondChest, costSecondChest, 0],
  8701. });
  8702. }
  8703.  
  8704. const answer = await popup.confirm(`<div style="margin-bottom: 15px;">${I18N('BUY_OUTLAND')}</div>`, buttons);
  8705.  
  8706. if (!answer) {
  8707. return;
  8708. }
  8709.  
  8710. const callBoss = [];
  8711. let n = 0;
  8712. for (let boss of boses) {
  8713. const bossId = boss.id;
  8714. if (boss.chestNum != 2) {
  8715. continue;
  8716. }
  8717. const calls = [];
  8718. for (const starmoney of answer) {
  8719. calls.push({
  8720. name: 'bossOpenChest',
  8721. args: {
  8722. amount: 1,
  8723. bossId,
  8724. starmoney,
  8725. },
  8726. ident: 'bossOpenChest_' + ++n,
  8727. });
  8728. }
  8729. callBoss.push(calls);
  8730. }
  8731.  
  8732. if (!callBoss.length) {
  8733. setProgress(I18N('CHESTS_NOT_AVAILABLE'), true);
  8734. return;
  8735. }
  8736.  
  8737. let count = 0;
  8738. let errors = 0;
  8739. for (const calls of callBoss) {
  8740. const result = await Send({ calls });
  8741. console.log(result);
  8742. if (result?.results) {
  8743. count += result.results.length;
  8744. } else {
  8745. errors++;
  8746. }
  8747. }
  8748.  
  8749. setProgress(`${I18N('OUTLAND_CHESTS_RECEIVED')}: ${count}`, true);
  8750. }
  8751.  
  8752. async function autoRaidAdventure() {
  8753. const calls = [
  8754. {
  8755. name: "userGetInfo",
  8756. args: {},
  8757. ident: "userGetInfo"
  8758. },
  8759. {
  8760. name: "adventure_raidGetInfo",
  8761. args: {},
  8762. ident: "adventure_raidGetInfo"
  8763. }
  8764. ];
  8765. const result = await Send(JSON.stringify({ calls }))
  8766. .then(e => e.results.map(n => n.result.response));
  8767.  
  8768. const portalSphere = result[0].refillable.find(n => n.id == 45);
  8769. const adventureRaid = Object.entries(result[1].raid).filter(e => e[1]).pop()
  8770. const adventureId = adventureRaid ? adventureRaid[0] : 0;
  8771.  
  8772. if (!portalSphere.amount || !adventureId) {
  8773. setProgress(I18N('RAID_NOT_AVAILABLE'), true);
  8774. return;
  8775. }
  8776.  
  8777. const countRaid = +(await popup.confirm(I18N('RAID_ADVENTURE', { adventureId }), [
  8778. { result: false, isClose: true },
  8779. { msg: I18N('RAID'), isInput: true, default: portalSphere.amount },
  8780. ]));
  8781.  
  8782. if (!countRaid) {
  8783. return;
  8784. }
  8785.  
  8786. if (countRaid > portalSphere.amount) {
  8787. countRaid = portalSphere.amount;
  8788. }
  8789.  
  8790. const resultRaid = await Send(JSON.stringify({
  8791. calls: [...Array(countRaid)].map((e, i) => ({
  8792. name: "adventure_raid",
  8793. args: {
  8794. adventureId
  8795. },
  8796. ident: `body_${i}`
  8797. }))
  8798. })).then(e => e.results.map(n => n.result.response));
  8799.  
  8800. if (!resultRaid.length) {
  8801. console.log(resultRaid);
  8802. setProgress(I18N('SOMETHING_WENT_WRONG'), true);
  8803. return;
  8804. }
  8805.  
  8806. console.log(resultRaid, adventureId, portalSphere.amount);
  8807. setProgress(I18N('ADVENTURE_COMPLETED', { adventureId, times: resultRaid.length }), true);
  8808. }
  8809.  
  8810. /** Вывести всю клановую статистику в консоль браузера */
  8811. async function clanStatistic() {
  8812. const copy = function (text) {
  8813. const copyTextarea = document.createElement("textarea");
  8814. copyTextarea.style.opacity = "0";
  8815. copyTextarea.textContent = text;
  8816. document.body.appendChild(copyTextarea);
  8817. copyTextarea.select();
  8818. document.execCommand("copy");
  8819. document.body.removeChild(copyTextarea);
  8820. delete copyTextarea;
  8821. }
  8822. const calls = [
  8823. { name: "clanGetInfo", args: {}, ident: "clanGetInfo" },
  8824. { name: "clanGetWeeklyStat", args: {}, ident: "clanGetWeeklyStat" },
  8825. { name: "clanGetLog", args: {}, ident: "clanGetLog" },
  8826. ];
  8827.  
  8828. const result = await Send(JSON.stringify({ calls }));
  8829.  
  8830. const dataClanInfo = result.results[0].result.response;
  8831. const dataClanStat = result.results[1].result.response;
  8832. const dataClanLog = result.results[2].result.response;
  8833.  
  8834. const membersStat = {};
  8835. for (let i = 0; i < dataClanStat.stat.length; i++) {
  8836. membersStat[dataClanStat.stat[i].id] = dataClanStat.stat[i];
  8837. }
  8838.  
  8839. const joinStat = {};
  8840. historyLog = dataClanLog.history;
  8841. for (let j in historyLog) {
  8842. his = historyLog[j];
  8843. if (his.event == 'join') {
  8844. joinStat[his.userId] = his.ctime;
  8845. }
  8846. }
  8847.  
  8848. const infoArr = [];
  8849. const members = dataClanInfo.clan.members;
  8850. for (let n in members) {
  8851. var member = [
  8852. n,
  8853. members[n].name,
  8854. members[n].level,
  8855. dataClanInfo.clan.warriors.includes(+n) ? 1 : 0,
  8856. (new Date(members[n].lastLoginTime * 1000)).toLocaleString().replace(',', ''),
  8857. joinStat[n] ? (new Date(joinStat[n] * 1000)).toLocaleString().replace(',', '') : '',
  8858. membersStat[n].activity.reverse().join('\t'),
  8859. membersStat[n].adventureStat.reverse().join('\t'),
  8860. membersStat[n].clanGifts.reverse().join('\t'),
  8861. membersStat[n].clanWarStat.reverse().join('\t'),
  8862. membersStat[n].dungeonActivity.reverse().join('\t'),
  8863. ];
  8864. infoArr.push(member);
  8865. }
  8866. const info = infoArr.sort((a, b) => (b[2] - a[2])).map((e) => e.join('\t')).join('\n');
  8867. console.log(info);
  8868. copy(info);
  8869. setProgress(I18N('CLAN_STAT_COPY'), true);
  8870. }
  8871.  
  8872. async function buyInStoreForGold() {
  8873. const result = await Send('{"calls":[{"name":"shopGetAll","args":{},"ident":"body"},{"name":"userGetInfo","args":{},"ident":"userGetInfo"}]}').then(e => e.results.map(n => n.result.response));
  8874. const shops = result[0];
  8875. const user = result[1];
  8876. let gold = user.gold;
  8877. const calls = [];
  8878. if (shops[17]) {
  8879. const slots = shops[17].slots;
  8880. for (let i = 1; i <= 2; i++) {
  8881. if (!slots[i].bought) {
  8882. const costGold = slots[i].cost.gold;
  8883. if ((gold - costGold) < 0) {
  8884. continue;
  8885. }
  8886. gold -= costGold;
  8887. calls.push({
  8888. name: "shopBuy",
  8889. args: {
  8890. shopId: 17,
  8891. slot: i,
  8892. cost: slots[i].cost,
  8893. reward: slots[i].reward,
  8894. },
  8895. ident: 'body_' + i,
  8896. })
  8897. }
  8898. }
  8899. }
  8900. const slots = shops[1].slots;
  8901. for (let i = 4; i <= 6; i++) {
  8902. if (!slots[i].bought && slots[i]?.cost?.gold) {
  8903. const costGold = slots[i].cost.gold;
  8904. if ((gold - costGold) < 0) {
  8905. continue;
  8906. }
  8907. gold -= costGold;
  8908. calls.push({
  8909. name: "shopBuy",
  8910. args: {
  8911. shopId: 1,
  8912. slot: i,
  8913. cost: slots[i].cost,
  8914. reward: slots[i].reward,
  8915. },
  8916. ident: 'body_' + i,
  8917. })
  8918. }
  8919. }
  8920.  
  8921. if (!calls.length) {
  8922. setProgress(I18N('NOTHING_BUY'), true);
  8923. return;
  8924. }
  8925.  
  8926. const resultBuy = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  8927. console.log(resultBuy);
  8928. const countBuy = resultBuy.length;
  8929. setProgress(I18N('LOTS_BOUGHT', { countBuy }), true);
  8930. }
  8931.  
  8932. function rewardsAndMailFarm() {
  8933. return new Promise(function (resolve, reject) {
  8934. let questGetAllCall = {
  8935. calls: [{
  8936. name: "questGetAll",
  8937. args: {},
  8938. ident: "questGetAll"
  8939. }, {
  8940. name: "mailGetAll",
  8941. args: {},
  8942. ident: "mailGetAll"
  8943. }]
  8944. }
  8945. send(JSON.stringify(questGetAllCall), function (data) {
  8946. if (!data) return;
  8947. const questGetAll = data.results[0].result.response.filter((e) => e.state == 2);
  8948. const questBattlePass = lib.getData('quest').battlePass;
  8949. const questChainBPass = lib.getData('battlePass').questChain;
  8950. const listBattlePass = lib.getData('battlePass').list;
  8951.  
  8952. const questAllFarmCall = {
  8953. calls: [],
  8954. };
  8955. const questIds = [];
  8956. for (let quest of questGetAll) {
  8957. if (quest.id >= 2001e4) {
  8958. continue;
  8959. }
  8960. if (quest.id > 1e6 && quest.id < 2e7) {
  8961. const questInfo = questBattlePass[quest.id];
  8962. const chain = questChainBPass[questInfo.chain];
  8963. if (chain.requirement?.battlePassTicket) {
  8964. continue;
  8965. }
  8966. const battlePass = listBattlePass[chain.battlePass];
  8967. const startTime = battlePass.startCondition.time.value * 1e3
  8968. const endTime = new Date(startTime + battlePass.duration * 1e3);
  8969. if (startTime > Date.now() || endTime < Date.now()) {
  8970. continue;
  8971. }
  8972. }
  8973. if (quest.id >= 2e7) {
  8974. questIds.push(quest.id);
  8975. continue;
  8976. }
  8977. questAllFarmCall.calls.push({
  8978. name: 'questFarm',
  8979. args: {
  8980. questId: quest.id,
  8981. },
  8982. ident: `questFarm_${quest.id}`,
  8983. });
  8984. }
  8985.  
  8986. if (questIds.length) {
  8987. questAllFarmCall.calls.push({
  8988. name: 'quest_questsFarm',
  8989. args: { questIds },
  8990. ident: 'quest_questsFarm',
  8991. });
  8992. }
  8993.  
  8994. let letters = data?.results[1]?.result?.response?.letters;
  8995. letterIds = lettersFilter(letters);
  8996.  
  8997. if (letterIds.length) {
  8998. questAllFarmCall.calls.push({
  8999. name: 'mailFarm',
  9000. args: { letterIds },
  9001. ident: 'mailFarm',
  9002. });
  9003. }
  9004.  
  9005. if (!questAllFarmCall.calls.length) {
  9006. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  9007. resolve();
  9008. return;
  9009. }
  9010.  
  9011. send(JSON.stringify(questAllFarmCall), async function (res) {
  9012. let countQuests = 0;
  9013. let countMail = 0;
  9014. let questsIds = [];
  9015. for (let call of res.results) {
  9016. if (call.ident.includes('questFarm')) {
  9017. countQuests++;
  9018. } else if (call.ident.includes('questsFarm')) {
  9019. countQuests += Object.keys(call.result.response).length;
  9020. } else if (call.ident.includes('mailFarm')) {
  9021. countMail = Object.keys(call.result.response).length;
  9022. }
  9023.  
  9024. const newQuests = call.result.newQuests;
  9025. if (newQuests) {
  9026. for (let quest of newQuests) {
  9027. if ((quest.id < 1e6 || (quest.id >= 2e7 && quest.id < 2001e4)) && quest.state == 2) {
  9028. questsIds.push(quest.id);
  9029. }
  9030. }
  9031. }
  9032. }
  9033. while (questsIds.length) {
  9034. const questIds = [];
  9035. const calls = [];
  9036. for (let questId of questsIds) {
  9037. if (questId < 1e6) {
  9038. calls.push({
  9039. name: 'questFarm',
  9040. args: {
  9041. questId,
  9042. },
  9043. ident: `questFarm_${questId}`,
  9044. });
  9045. countQuests++;
  9046. } else if (questId >= 2e7 && questId < 2001e4) {
  9047. questIds.push(questId);
  9048. countQuests++;
  9049. }
  9050. }
  9051. calls.push({
  9052. name: 'quest_questsFarm',
  9053. args: { questIds },
  9054. ident: 'body',
  9055. });
  9056. const results = await Send({ calls }).then((e) => e.results.map((e) => e.result));
  9057. questsIds = [];
  9058. for (const result of results) {
  9059. const newQuests = result.newQuests;
  9060. if (newQuests) {
  9061. for (let quest of newQuests) {
  9062. if (quest.state == 2) {
  9063. questsIds.push(quest.id);
  9064. }
  9065. }
  9066. }
  9067. }
  9068. }
  9069. setProgress(I18N('COLLECT_REWARDS_AND_MAIL', { countQuests, countMail }), true);
  9070. resolve();
  9071. });
  9072. });
  9073. })
  9074. }
  9075.  
  9076. class epicBrawl {
  9077. timeout = null;
  9078. time = null;
  9079.  
  9080. constructor() {
  9081. if (epicBrawl.inst) {
  9082. return epicBrawl.inst;
  9083. }
  9084. epicBrawl.inst = this;
  9085. return this;
  9086. }
  9087.  
  9088. runTimeout(func, timeDiff) {
  9089. const worker = new Worker(URL.createObjectURL(new Blob([`
  9090. self.onmessage = function(e) {
  9091. const timeDiff = e.data;
  9092.  
  9093. if (timeDiff > 0) {
  9094. setTimeout(() => {
  9095. self.postMessage(1);
  9096. self.close();
  9097. }, timeDiff);
  9098. }
  9099. };
  9100. `])));
  9101. worker.postMessage(timeDiff);
  9102. worker.onmessage = () => {
  9103. func();
  9104. };
  9105. return true;
  9106. }
  9107.  
  9108. timeDiff(date1, date2) {
  9109. const date1Obj = new Date(date1);
  9110. const date2Obj = new Date(date2);
  9111.  
  9112. const timeDiff = Math.abs(date2Obj - date1Obj);
  9113.  
  9114. const totalSeconds = timeDiff / 1000;
  9115. const minutes = Math.floor(totalSeconds / 60);
  9116. const seconds = Math.floor(totalSeconds % 60);
  9117.  
  9118. const formattedMinutes = String(minutes).padStart(2, '0');
  9119. const formattedSeconds = String(seconds).padStart(2, '0');
  9120.  
  9121. return `${formattedMinutes}:${formattedSeconds}`;
  9122. }
  9123.  
  9124. check() {
  9125. console.log(new Date(this.time))
  9126. if (Date.now() > this.time) {
  9127. this.timeout = null;
  9128. this.start()
  9129. return;
  9130. }
  9131. this.timeout = this.runTimeout(() => this.check(), 6e4);
  9132. return this.timeDiff(this.time, Date.now())
  9133. }
  9134.  
  9135. async start() {
  9136. if (this.timeout) {
  9137. const time = this.timeDiff(this.time, Date.now());
  9138. console.log(new Date(this.time))
  9139. setProgress(I18N('TIMER_ALREADY', { time }), false, hideProgress);
  9140. return;
  9141. }
  9142. setProgress(I18N('EPIC_BRAWL'), false, hideProgress);
  9143. 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));
  9144. const refill = teamInfo[2].refillable.find(n => n.id == 52)
  9145. this.time = (refill.lastRefill + 3600) * 1000
  9146. const attempts = refill.amount;
  9147. if (!attempts) {
  9148. console.log(new Date(this.time));
  9149. const time = this.check();
  9150. setProgress(I18N('NO_ATTEMPTS_TIMER_START', { time }), false, hideProgress);
  9151. return;
  9152. }
  9153.  
  9154. if (!teamInfo[0].epic_brawl) {
  9155. setProgress(I18N('NO_HEROES_PACK'), false, hideProgress);
  9156. return;
  9157. }
  9158.  
  9159. const args = {
  9160. heroes: teamInfo[0].epic_brawl.filter(e => e < 1000),
  9161. pet: teamInfo[0].epic_brawl.filter(e => e > 6000).pop(),
  9162. favor: teamInfo[1].epic_brawl,
  9163. }
  9164.  
  9165. let wins = 0;
  9166. let coins = 0;
  9167. let streak = { progress: 0, nextStage: 0 };
  9168. for (let i = attempts; i > 0; i--) {
  9169. const info = await Send(JSON.stringify({
  9170. calls: [
  9171. { name: "epicBrawl_getEnemy", args: {}, ident: "epicBrawl_getEnemy" }, { name: "epicBrawl_startBattle", args, ident: "epicBrawl_startBattle" }
  9172. ]
  9173. })).then(e => e.results.map(n => n.result.response));
  9174.  
  9175. const { progress, result } = await Calc(info[1].battle);
  9176. 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));
  9177.  
  9178. const resultInfo = endResult[0].result;
  9179. streak = endResult[1];
  9180.  
  9181. wins += resultInfo.win;
  9182. coins += resultInfo.reward ? resultInfo.reward.coin[39] : 0;
  9183.  
  9184. console.log(endResult[0].result)
  9185. if (endResult[1].progress == endResult[1].nextStage) {
  9186. const farm = await Send('{"calls":[{"name":"epicBrawl_farmWinStreak","args":{},"ident":"body"}]}').then(e => e.results[0].result.response);
  9187. coins += farm.coin[39];
  9188. }
  9189.  
  9190. setProgress(I18N('EPIC_BRAWL_RESULT', {
  9191. i, wins, attempts, coins,
  9192. progress: streak.progress,
  9193. nextStage: streak.nextStage,
  9194. end: '',
  9195. }), false, hideProgress);
  9196. }
  9197.  
  9198. console.log(new Date(this.time));
  9199. const time = this.check();
  9200. setProgress(I18N('EPIC_BRAWL_RESULT', {
  9201. wins, attempts, coins,
  9202. i: '',
  9203. progress: streak.progress,
  9204. nextStage: streak.nextStage,
  9205. end: I18N('ATTEMPT_ENDED', { time }),
  9206. }), false, hideProgress);
  9207. }
  9208. }
  9209. /* тест остановка подземки*/
  9210. function stopDungeon(e) {
  9211. stopDung = true;
  9212. }
  9213.  
  9214. function countdownTimer(seconds, message) {
  9215. message = message || I18N('TIMER');
  9216. const stopTimer = Date.now() + seconds * 1e3
  9217. return new Promise(resolve => {
  9218. const interval = setInterval(async () => {
  9219. const now = Date.now();
  9220. setProgress(`${message} ${((stopTimer - now) / 1000).toFixed(2)}`, false);
  9221. if (now > stopTimer) {
  9222. clearInterval(interval);
  9223. setProgress('', 1);
  9224. resolve();
  9225. }
  9226. }, 100);
  9227. });
  9228. }
  9229.  
  9230. /** Набить килов в горниле душк */
  9231. async function bossRatingEventSouls() {
  9232. const data = await Send({
  9233. calls: [
  9234. { name: "heroGetAll", args: {}, ident: "teamGetAll" },
  9235. { name: "offerGetAll", args: {}, ident: "offerGetAll" },
  9236. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  9237. ]
  9238. });
  9239. const bossEventInfo = data.results[1].result.response.find(e => e.offerType == "bossEvent");
  9240. if (!bossEventInfo) {
  9241. setProgress('Эвент завершен', true);
  9242. return;
  9243. }
  9244.  
  9245. if (bossEventInfo.progress.score > 250) {
  9246. setProgress('Уже убито больше 250 врагов');
  9247. rewardBossRatingEventSouls();
  9248. return;
  9249. }
  9250. const availablePets = Object.values(data.results[2].result.response).map(e => e.id);
  9251. const heroGetAllList = data.results[0].result.response;
  9252. const usedHeroes = bossEventInfo.progress.usedHeroes;
  9253. const heroList = [];
  9254.  
  9255. for (let heroId in heroGetAllList) {
  9256. let hero = heroGetAllList[heroId];
  9257. if (usedHeroes.includes(hero.id)) {
  9258. continue;
  9259. }
  9260. heroList.push(hero.id);
  9261. }
  9262.  
  9263. if (!heroList.length) {
  9264. setProgress('Нет героев', true);
  9265. return;
  9266. }
  9267.  
  9268. const pet = availablePets.includes(6005) ? 6005 : availablePets[Math.floor(Math.random() * availablePets.length)];
  9269. const petLib = lib.getData('pet');
  9270. let count = 1;
  9271.  
  9272. for (const heroId of heroList) {
  9273. const args = {
  9274. heroes: [heroId],
  9275. pet
  9276. }
  9277. /** Поиск питомца для героя */
  9278. for (const petId of availablePets) {
  9279. if (petLib[petId].favorHeroes.includes(heroId)) {
  9280. args.favor = {
  9281. [heroId]: petId
  9282. }
  9283. break;
  9284. }
  9285. }
  9286.  
  9287. const calls = [{
  9288. name: "bossRatingEvent_startBattle",
  9289. args,
  9290. ident: "body"
  9291. }, {
  9292. name: "offerGetAll",
  9293. args: {},
  9294. ident: "offerGetAll"
  9295. }];
  9296.  
  9297. const res = await Send({ calls });
  9298. count++;
  9299.  
  9300. if ('error' in res) {
  9301. console.error(res.error);
  9302. setProgress('Перезагрузите игру и попробуйте позже', true);
  9303. return;
  9304. }
  9305.  
  9306. const eventInfo = res.results[1].result.response.find(e => e.offerType == "bossEvent");
  9307. if (eventInfo.progress.score > 250) {
  9308. break;
  9309. }
  9310. setProgress('Количество убитых врагов: ' + eventInfo.progress.score + '<br>Использовано ' + count + ' героев');
  9311. }
  9312.  
  9313. rewardBossRatingEventSouls();
  9314. }
  9315. /** Сбор награды из Горнила Душ */
  9316. async function rewardBossRatingEventSouls() {
  9317. const data = await Send({
  9318. calls: [
  9319. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  9320. ]
  9321. });
  9322.  
  9323. const bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  9324. if (!bossEventInfo) {
  9325. setProgress('Эвент завершен', true);
  9326. return;
  9327. }
  9328.  
  9329. const farmedChests = bossEventInfo.progress.farmedChests;
  9330. const score = bossEventInfo.progress.score;
  9331. // setProgress('Количество убитых врагов: ' + score);
  9332. const revard = bossEventInfo.reward;
  9333. const calls = [];
  9334.  
  9335. let count = 0;
  9336. for (let i = 1; i < 10; i++) {
  9337. if (farmedChests.includes(i)) {
  9338. continue;
  9339. }
  9340. if (score < revard[i].score) {
  9341. break;
  9342. }
  9343. calls.push({
  9344. name: "bossRatingEvent_getReward",
  9345. args: {
  9346. rewardId: i
  9347. },
  9348. ident: "body_" + i
  9349. });
  9350. count++;
  9351. }
  9352. if (!count) {
  9353. setProgress('Нечего собирать', true);
  9354. return;
  9355. }
  9356.  
  9357. Send({ calls }).then(e => {
  9358. console.log(e);
  9359. setProgress('Собрано ' + e?.results?.length + ' наград', true);
  9360. })
  9361. }
  9362. /**
  9363. * Spin the Seer
  9364. *
  9365. * Покрутить провидца
  9366. */
  9367. async function rollAscension() {
  9368. const refillable = await Send({calls:[
  9369. {
  9370. name:"userGetInfo",
  9371. args:{},
  9372. ident:"userGetInfo"
  9373. }
  9374. ]}).then(e => e.results[0].result.response.refillable);
  9375. const i47 = refillable.find(i => i.id == 47);
  9376. if (i47?.amount) {
  9377. await Send({ calls: [{ name: "ascensionChest_open", args: { paid: false, amount: 1 }, ident: "body" }] });
  9378. setProgress(I18N('DONE'), true);
  9379. } else {
  9380. setProgress(I18N('NOT_ENOUGH_AP'), true);
  9381. }
  9382. }
  9383.  
  9384. /**
  9385. * Collect gifts for the New Year
  9386. *
  9387. * Собрать подарки на новый год
  9388. */
  9389. function getGiftNewYear() {
  9390. Send({ calls: [{ name: "newYearGiftGet", args: { type: 0 }, ident: "body" }] }).then(e => {
  9391. const gifts = e.results[0].result.response.gifts;
  9392. const calls = gifts.filter(e => e.opened == 0).map(e => ({
  9393. name: "newYearGiftOpen",
  9394. args: {
  9395. giftId: e.id
  9396. },
  9397. ident: `body_${e.id}`
  9398. }));
  9399. if (!calls.length) {
  9400. setProgress(I18N('NY_NO_GIFTS'), 5000);
  9401. return;
  9402. }
  9403. Send({ calls }).then(e => {
  9404. console.log(e.results)
  9405. const msg = I18N('NY_GIFTS_COLLECTED', { count: e.results.length });
  9406. console.log(msg);
  9407. setProgress(msg, 5000);
  9408. });
  9409. })
  9410. }
  9411.  
  9412. async function updateArtifacts() {
  9413. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  9414. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  9415. { result: false, isClose: true }
  9416. ]);
  9417. if (!count) {
  9418. return;
  9419. }
  9420. const quest = new questRun;
  9421. await quest.autoInit();
  9422. const heroes = Object.values(quest.questInfo['heroGetAll']);
  9423. const inventory = quest.questInfo['inventoryGet'];
  9424. const calls = [];
  9425. for (let i = count; i > 0; i--) {
  9426. const upArtifact = quest.getUpgradeArtifact();
  9427. if (!upArtifact.heroId) {
  9428. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  9429. { msg: I18N('YES'), result: true },
  9430. { result: false, isClose: true }
  9431. ])) {
  9432. break;
  9433. } else {
  9434. return;
  9435. }
  9436. }
  9437. const hero = heroes.find(e => e.id == upArtifact.heroId);
  9438. hero.artifacts[upArtifact.slotId].level++;
  9439. inventory[upArtifact.costCurrency][upArtifact.costId] -= upArtifact.costValue;
  9440. calls.push({
  9441. name: "heroArtifactLevelUp",
  9442. args: {
  9443. heroId: upArtifact.heroId,
  9444. slotId: upArtifact.slotId
  9445. },
  9446. ident: `heroArtifactLevelUp_${i}`
  9447. });
  9448. }
  9449.  
  9450. if (!calls.length) {
  9451. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9452. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9453. return;
  9454. }
  9455.  
  9456. await Send(JSON.stringify({ calls })).then(e => {
  9457. if ('error' in e) {
  9458. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9459. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9460. } else {
  9461. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  9462. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  9463. }
  9464. });
  9465. }
  9466.  
  9467. window.sign = a => {
  9468. const i = this['\x78\x79\x7a'];
  9469. 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'))
  9470. }
  9471.  
  9472. async function updateSkins() {
  9473. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  9474. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  9475. { result: false, isClose: true }
  9476. ]);
  9477. if (!count) {
  9478. return;
  9479. }
  9480.  
  9481. const quest = new questRun;
  9482. await quest.autoInit();
  9483. const heroes = Object.values(quest.questInfo['heroGetAll']);
  9484. const inventory = quest.questInfo['inventoryGet'];
  9485. const calls = [];
  9486. for (let i = count; i > 0; i--) {
  9487. const upSkin = quest.getUpgradeSkin();
  9488. if (!upSkin.heroId) {
  9489. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  9490. { msg: I18N('YES'), result: true },
  9491. { result: false, isClose: true }
  9492. ])) {
  9493. break;
  9494. } else {
  9495. return;
  9496. }
  9497. }
  9498. const hero = heroes.find(e => e.id == upSkin.heroId);
  9499. hero.skins[upSkin.skinId]++;
  9500. inventory[upSkin.costCurrency][upSkin.costCurrencyId] -= upSkin.cost;
  9501. calls.push({
  9502. name: "heroSkinUpgrade",
  9503. args: {
  9504. heroId: upSkin.heroId,
  9505. skinId: upSkin.skinId
  9506. },
  9507. ident: `heroSkinUpgrade_${i}`
  9508. })
  9509. }
  9510.  
  9511. if (!calls.length) {
  9512. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9513. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9514. return;
  9515. }
  9516.  
  9517. await Send(JSON.stringify({ calls })).then(e => {
  9518. if ('error' in e) {
  9519. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9520. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9521. } else {
  9522. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  9523. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  9524. }
  9525. });
  9526. }
  9527.  
  9528. function getQuestionInfo(img, nameOnly = false) {
  9529. const libHeroes = Object.values(lib.data.hero);
  9530. const parts = img.split(':');
  9531. const id = parts[1];
  9532. switch (parts[0]) {
  9533. case 'titanArtifact_id':
  9534. return cheats.translate("LIB_TITAN_ARTIFACT_NAME_" + id);
  9535. case 'titan':
  9536. return cheats.translate("LIB_HERO_NAME_" + id);
  9537. case 'skill':
  9538. return cheats.translate("LIB_SKILL_" + id);
  9539. case 'inventoryItem_gear':
  9540. return cheats.translate("LIB_GEAR_NAME_" + id);
  9541. case 'inventoryItem_coin':
  9542. return cheats.translate("LIB_COIN_NAME_" + id);
  9543. case 'artifact':
  9544. if (nameOnly) {
  9545. return cheats.translate("LIB_ARTIFACT_NAME_" + id);
  9546. }
  9547. heroes = libHeroes.filter(h => h.id < 100 && h.artifacts.includes(+id));
  9548. return {
  9549. /** Как называется этот артефакт? */
  9550. name: cheats.translate("LIB_ARTIFACT_NAME_" + id),
  9551. /** Какому герою принадлежит этот артефакт? */
  9552. heroes: heroes.map(h => cheats.translate("LIB_HERO_NAME_" + h.id))
  9553. };
  9554. case 'hero':
  9555. if (nameOnly) {
  9556. return cheats.translate("LIB_HERO_NAME_" + id);
  9557. }
  9558. artifacts = lib.data.hero[id].artifacts;
  9559. return {
  9560. /** Как зовут этого героя? */
  9561. name: cheats.translate("LIB_HERO_NAME_" + id),
  9562. /** Какой артефакт принадлежит этому герою? */
  9563. artifact: artifacts.map(a => cheats.translate("LIB_ARTIFACT_NAME_" + a))
  9564. };
  9565. }
  9566. }
  9567.  
  9568. function hintQuest(quest) {
  9569. const result = {};
  9570. if (quest?.questionIcon) {
  9571. const info = getQuestionInfo(quest.questionIcon);
  9572. if (info?.heroes) {
  9573. /** Какому герою принадлежит этот артефакт? */
  9574. result.answer = quest.answers.filter(e => info.heroes.includes(e.answerText.slice(1)));
  9575. }
  9576. if (info?.artifact) {
  9577. /** Какой артефакт принадлежит этому герою? */
  9578. result.answer = quest.answers.filter(e => info.artifact.includes(e.answerText.slice(1)));
  9579. }
  9580. if (typeof info == 'string') {
  9581. result.info = { name: info };
  9582. } else {
  9583. result.info = info;
  9584. }
  9585. }
  9586.  
  9587. if (quest.answers[0]?.answerIcon) {
  9588. result.answer = quest.answers.filter(e => quest.question.includes(getQuestionInfo(e.answerIcon, true)))
  9589. }
  9590.  
  9591. if ((!result?.answer || !result.answer.length) && !result.info?.name) {
  9592. return false;
  9593. }
  9594.  
  9595. let resultText = '';
  9596. if (result?.info) {
  9597. resultText += I18N('PICTURE') + result.info.name;
  9598. }
  9599. console.log(result);
  9600. if (result?.answer && result.answer.length) {
  9601. resultText += I18N('ANSWER') + result.answer[0].id + (!result.answer[0].answerIcon ? ' - ' + result.answer[0].answerText : '');
  9602. }
  9603.  
  9604. return resultText;
  9605. }
  9606.  
  9607. async function farmBattlePass() {
  9608. const isFarmReward = (reward) => {
  9609. return !(reward?.buff || reward?.fragmentHero || reward?.bundleHeroReward);
  9610. };
  9611.  
  9612. const battlePassProcess = (pass) => {
  9613. if (!pass.id) {return []}
  9614. const levels = Object.values(lib.data.battlePass.level).filter(x => x.battlePass == pass.id)
  9615. const last_level = levels[levels.length - 1];
  9616. let actual = Math.max(...levels.filter(p => pass.exp >= p.experience).map(p => p.level))
  9617.  
  9618. if (pass.exp > last_level.experience) {
  9619. actual = last_level.level + (pass.exp - last_level.experience) / last_level.experienceByLevel;
  9620. }
  9621. const calls = [];
  9622. for(let i = 1; i <= actual; i++) {
  9623. const level = i >= last_level.level ? last_level : levels.find(l => l.level === i);
  9624. const reward = {free: level?.freeReward, paid:level?.paidReward};
  9625.  
  9626. if (!pass.rewards[i]?.free && isFarmReward(reward.free)) {
  9627. const args = {level: i, free:true};
  9628. if (!pass.gold) { args.id = pass.id }
  9629. calls.push({ name: 'battlePass_farmReward', args, ident: `${pass.gold ? 'body' : 'spesial'}_free_${args.id}_${i}` });
  9630. }
  9631. if (pass.ticket && !pass.rewards[i]?.paid && isFarmReward(reward.paid)) {
  9632. const args = {level: i, free:false};
  9633. if (!pass.gold) { args.id = pass.id}
  9634. calls.push({ name: 'battlePass_farmReward', args, ident: `${pass.gold ? 'body' : 'spesial'}_paid_${args.id}_${i}` });
  9635. }
  9636. }
  9637. return calls;
  9638. }
  9639.  
  9640. const passes = await Send({
  9641. calls: [
  9642. { name: 'battlePass_getInfo', args: {}, ident: 'getInfo' },
  9643. { name: 'battlePass_getSpecial', args: {}, ident: 'getSpecial' },
  9644. ],
  9645. }).then((e) => [{...e.results[0].result.response?.battlePass, gold: true}, ...Object.values(e.results[1].result.response)]);
  9646.  
  9647. const calls = passes.map(p => battlePassProcess(p)).flat()
  9648.  
  9649. if (!calls.length) {
  9650. setProgress(I18N('NOTHING_TO_COLLECT'));
  9651. return;
  9652. }
  9653.  
  9654. let results = await Send({calls});
  9655. if (results.error) {
  9656. console.log(results.error);
  9657. setProgress(I18N('SOMETHING_WENT_WRONG'));
  9658. } else {
  9659. setProgress(I18N('SEASON_REWARD_COLLECTED', {count: results.results.length}), true);
  9660. }
  9661. }
  9662.  
  9663. async function sellHeroSoulsForGold() {
  9664. let { fragmentHero, heroes } = await Send({
  9665. calls: [
  9666. { name: 'inventoryGet', args: {}, ident: 'inventoryGet' },
  9667. { name: 'heroGetAll', args: {}, ident: 'heroGetAll' },
  9668. ],
  9669. })
  9670. .then((e) => e.results.map((r) => r.result.response))
  9671. .then((e) => ({ fragmentHero: e[0].fragmentHero, heroes: e[1] }));
  9672.  
  9673. const calls = [];
  9674. for (let i in fragmentHero) {
  9675. if (heroes[i] && heroes[i].star == 6) {
  9676. calls.push({
  9677. name: 'inventorySell',
  9678. args: {
  9679. type: 'hero',
  9680. libId: i,
  9681. amount: fragmentHero[i],
  9682. fragment: true,
  9683. },
  9684. ident: 'inventorySell_' + i,
  9685. });
  9686. }
  9687. }
  9688. if (!calls.length) {
  9689. console.log(0);
  9690. return 0;
  9691. }
  9692. const rewards = await Send({ calls }).then((e) => e.results.map((r) => r.result?.response?.gold || 0));
  9693. const gold = rewards.reduce((e, a) => e + a, 0);
  9694. setProgress(I18N('GOLD_RECEIVED', { gold }), true);
  9695. }
  9696.  
  9697. /**
  9698. * Attack of the minions of Asgard
  9699. *
  9700. * Атака прислужников Асгарда
  9701. */
  9702. function testRaidNodes() {
  9703. return new Promise((resolve, reject) => {
  9704. const tower = new executeRaidNodes(resolve, reject);
  9705. tower.start();
  9706. });
  9707. }
  9708.  
  9709. /**
  9710. * Attack of the minions of Asgard
  9711. *
  9712. * Атака прислужников Асгарда
  9713. */
  9714. function executeRaidNodes(resolve, reject) {
  9715. let raidData = {
  9716. teams: [],
  9717. favor: {},
  9718. nodes: [],
  9719. attempts: 0,
  9720. countExecuteBattles: 0,
  9721. cancelBattle: 0,
  9722. }
  9723.  
  9724. callsExecuteRaidNodes = {
  9725. calls: [{
  9726. name: "clanRaid_getInfo",
  9727. args: {},
  9728. ident: "clanRaid_getInfo"
  9729. }, {
  9730. name: "teamGetAll",
  9731. args: {},
  9732. ident: "teamGetAll"
  9733. }, {
  9734. name: "teamGetFavor",
  9735. args: {},
  9736. ident: "teamGetFavor"
  9737. }]
  9738. }
  9739.  
  9740. this.start = function () {
  9741. send(JSON.stringify(callsExecuteRaidNodes), startRaidNodes);
  9742. }
  9743.  
  9744. async function startRaidNodes(data) {
  9745. res = data.results;
  9746. clanRaidInfo = res[0].result.response;
  9747. teamGetAll = res[1].result.response;
  9748. teamGetFavor = res[2].result.response;
  9749.  
  9750. let index = 0;
  9751. let isNotFullPack = false;
  9752. for (let team of teamGetAll.clanRaid_nodes) {
  9753. if (team.length < 6) {
  9754. isNotFullPack = true;
  9755. }
  9756. raidData.teams.push({
  9757. data: {},
  9758. heroes: team.filter(id => id < 6000),
  9759. pet: team.filter(id => id >= 6000).pop(),
  9760. battleIndex: index++
  9761. });
  9762. }
  9763. raidData.favor = teamGetFavor.clanRaid_nodes;
  9764.  
  9765. if (isNotFullPack) {
  9766. if (await popup.confirm(I18N('MINIONS_WARNING'), [
  9767. { msg: I18N('BTN_NO'), result: true },
  9768. { msg: I18N('BTN_YES'), result: false },
  9769. ])) {
  9770. endRaidNodes('isNotFullPack');
  9771. return;
  9772. }
  9773. }
  9774.  
  9775. raidData.nodes = clanRaidInfo.nodes;
  9776. raidData.attempts = clanRaidInfo.attempts;
  9777. isCancalBattle = false;
  9778.  
  9779. checkNodes();
  9780. }
  9781.  
  9782. function getAttackNode() {
  9783. for (let nodeId in raidData.nodes) {
  9784. let node = raidData.nodes[nodeId];
  9785. let points = 0
  9786. for (team of node.teams) {
  9787. points += team.points;
  9788. }
  9789. let now = Date.now() / 1000;
  9790. if (!points && now > node.timestamps.start && now < node.timestamps.end) {
  9791. let countTeam = node.teams.length;
  9792. delete raidData.nodes[nodeId];
  9793. return {
  9794. nodeId,
  9795. countTeam
  9796. };
  9797. }
  9798. }
  9799. return null;
  9800. }
  9801.  
  9802. function checkNodes() {
  9803. setProgress(`${I18N('REMAINING_ATTEMPTS')}: ${raidData.attempts}`);
  9804. let nodeInfo = getAttackNode();
  9805. if (nodeInfo && raidData.attempts) {
  9806. startNodeBattles(nodeInfo);
  9807. return;
  9808. }
  9809.  
  9810. endRaidNodes('EndRaidNodes');
  9811. }
  9812.  
  9813. function startNodeBattles(nodeInfo) {
  9814. let {nodeId, countTeam} = nodeInfo;
  9815. let teams = raidData.teams.slice(0, countTeam);
  9816. let heroes = raidData.teams.map(e => e.heroes).flat();
  9817. let favor = {...raidData.favor};
  9818. for (let heroId in favor) {
  9819. if (!heroes.includes(+heroId)) {
  9820. delete favor[heroId];
  9821. }
  9822. }
  9823.  
  9824. let calls = [{
  9825. name: "clanRaid_startNodeBattles",
  9826. args: {
  9827. nodeId,
  9828. teams,
  9829. favor
  9830. },
  9831. ident: "body"
  9832. }];
  9833.  
  9834. send(JSON.stringify({calls}), resultNodeBattles);
  9835. }
  9836.  
  9837. function resultNodeBattles(e) {
  9838. if (e['error']) {
  9839. endRaidNodes('nodeBattlesError', e['error']);
  9840. return;
  9841. }
  9842.  
  9843. console.log(e);
  9844. let battles = e.results[0].result.response.battles;
  9845. let promises = [];
  9846. let battleIndex = 0;
  9847. for (let battle of battles) {
  9848. battle.battleIndex = battleIndex++;
  9849. promises.push(calcBattleResult(battle));
  9850. }
  9851.  
  9852. Promise.all(promises)
  9853. .then(results => {
  9854. const endResults = {};
  9855. let isAllWin = true;
  9856. for (let r of results) {
  9857. isAllWin &&= r.result.win;
  9858. }
  9859. if (!isAllWin) {
  9860. cancelEndNodeBattle(results[0]);
  9861. return;
  9862. }
  9863. raidData.countExecuteBattles = results.length;
  9864. let timeout = 500;
  9865. for (let r of results) {
  9866. setTimeout(endNodeBattle, timeout, r);
  9867. timeout += 500;
  9868. }
  9869. });
  9870. }
  9871. /**
  9872. * Returns the battle calculation promise
  9873. *
  9874. * Возвращает промис расчета боя
  9875. */
  9876. function calcBattleResult(battleData) {
  9877. return new Promise(function (resolve, reject) {
  9878. BattleCalc(battleData, "get_clanPvp", resolve);
  9879. });
  9880. }
  9881. /**
  9882. * Cancels the fight
  9883. *
  9884. * Отменяет бой
  9885. */
  9886. function cancelEndNodeBattle(r) {
  9887. const fixBattle = function (heroes) {
  9888. for (const ids in heroes) {
  9889. hero = heroes[ids];
  9890. hero.energy = random(1, 999);
  9891. if (hero.hp > 0) {
  9892. hero.hp = random(1, hero.hp);
  9893. }
  9894. }
  9895. }
  9896. fixBattle(r.progress[0].attackers.heroes);
  9897. fixBattle(r.progress[0].defenders.heroes);
  9898. endNodeBattle(r);
  9899. }
  9900. /**
  9901. * Ends the fight
  9902. *
  9903. * Завершает бой
  9904. */
  9905. function endNodeBattle(r) {
  9906. let nodeId = r.battleData.result.nodeId;
  9907. let battleIndex = r.battleData.battleIndex;
  9908. let calls = [{
  9909. name: "clanRaid_endNodeBattle",
  9910. args: {
  9911. nodeId,
  9912. battleIndex,
  9913. result: r.result,
  9914. progress: r.progress
  9915. },
  9916. ident: "body"
  9917. }]
  9918.  
  9919. SendRequest(JSON.stringify({calls}), battleResult);
  9920. }
  9921. /**
  9922. * Processing the results of the battle
  9923. *
  9924. * Обработка результатов боя
  9925. */
  9926. function battleResult(e) {
  9927. if (e['error']) {
  9928. endRaidNodes('missionEndError', e['error']);
  9929. return;
  9930. }
  9931. r = e.results[0].result.response;
  9932. if (r['error']) {
  9933. if (r.reason == "invalidBattle") {
  9934. raidData.cancelBattle++;
  9935. checkNodes();
  9936. } else {
  9937. endRaidNodes('missionEndError', e['error']);
  9938. }
  9939. return;
  9940. }
  9941.  
  9942. if (!(--raidData.countExecuteBattles)) {
  9943. raidData.attempts--;
  9944. checkNodes();
  9945. }
  9946. }
  9947. /**
  9948. * Completing a task
  9949. *
  9950. * Завершение задачи
  9951. */
  9952. function endRaidNodes(reason, info) {
  9953. isCancalBattle = true;
  9954. let textCancel = raidData.cancelBattle ? ` ${I18N('BATTLES_CANCELED')}: ${raidData.cancelBattle}` : '';
  9955. setProgress(`${I18N('MINION_RAID')} ${I18N('COMPLETED')}! ${textCancel}`, true);
  9956. console.log(reason, info);
  9957. resolve();
  9958. }
  9959. }
  9960.  
  9961. /**
  9962. * Asgard Boss Attack Replay
  9963. *
  9964. * Повтор атаки босса Асгарда
  9965. */
  9966. function testBossBattle() {
  9967. return new Promise((resolve, reject) => {
  9968. const bossBattle = new executeBossBattle(resolve, reject);
  9969. bossBattle.start(lastBossBattle);
  9970. });
  9971. }
  9972.  
  9973. /**
  9974. * Asgard Boss Attack Replay
  9975. *
  9976. * Повтор атаки босса Асгарда
  9977. */
  9978. function executeBossBattle(resolve, reject) {
  9979. this.start = function (battleInfo) {
  9980. preCalcBattle(battleInfo);
  9981. }
  9982.  
  9983. function getBattleInfo(battle) {
  9984. return new Promise(function (resolve) {
  9985. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  9986. BattleCalc(battle, getBattleType(battle.type), e => {
  9987. let extra = e.progress[0].defenders.heroes[1].extra;
  9988. resolve(extra.damageTaken + extra.damageTakenNextLevel);
  9989. });
  9990. });
  9991. }
  9992.  
  9993. function preCalcBattle(battle) {
  9994. let actions = [];
  9995. const countTestBattle = getInput('countTestBattle');
  9996. for (let i = 0; i < countTestBattle; i++) {
  9997. actions.push(getBattleInfo(battle, true));
  9998. }
  9999. Promise.all(actions)
  10000. .then(resultPreCalcBattle);
  10001. }
  10002.  
  10003. async function resultPreCalcBattle(damages) {
  10004. let maxDamage = 0;
  10005. let minDamage = 1e10;
  10006. let avgDamage = 0;
  10007. for (let damage of damages) {
  10008. avgDamage += damage
  10009. if (damage > maxDamage) {
  10010. maxDamage = damage;
  10011. }
  10012. if (damage < minDamage) {
  10013. minDamage = damage;
  10014. }
  10015. }
  10016. avgDamage /= damages.length;
  10017. console.log(damages.map(e => e.toLocaleString()).join('\n'), avgDamage, maxDamage);
  10018.  
  10019. await popup.confirm(
  10020. `${I18N('ROUND_STAT')} ${damages.length} ${I18N('BATTLE')}:` +
  10021. `<br>${I18N('MINIMUM')}: ` + minDamage.toLocaleString() +
  10022. `<br>${I18N('MAXIMUM')}: ` + maxDamage.toLocaleString() +
  10023. `<br>${I18N('AVERAGE')}: ` + avgDamage.toLocaleString()
  10024. , [
  10025. { msg: I18N('BTN_OK'), result: 0},
  10026. ])
  10027. endBossBattle(I18N('BTN_CANCEL'));
  10028. }
  10029.  
  10030. /**
  10031. * Completing a task
  10032. *
  10033. * Завершение задачи
  10034. */
  10035. function endBossBattle(reason, info) {
  10036. console.log(reason, info);
  10037. resolve();
  10038. }
  10039. }
  10040.  
  10041. class FixBattle {
  10042. minTimer = 1.3;
  10043. maxTimer = 15.3;
  10044. constructor(battle, isTimeout = true) {
  10045. this.battle = structuredClone(battle);
  10046. this.isTimeout = isTimeout;
  10047. }
  10048.  
  10049. timeout(callback, timeout) {
  10050. if (this.isTimeout) {
  10051. this.worker.postMessage(timeout);
  10052. this.worker.onmessage = callback;
  10053. } else {
  10054. callback();
  10055. }
  10056. }
  10057.  
  10058. randTimer() {
  10059. return Math.random() * (this.maxTimer - this.minTimer + 1) + this.minTimer;
  10060. }
  10061.  
  10062. setAvgTime(startTime) {
  10063. this.fixTime += Date.now() - startTime;
  10064. this.avgTime = this.fixTime / this.count;
  10065. }
  10066.  
  10067. init() {
  10068. this.fixTime = 0;
  10069. this.lastTimer = 0;
  10070. this.index = 0;
  10071. this.lastBossDamage = 0;
  10072. this.bestResult = {
  10073. count: 0,
  10074. timer: 0,
  10075. value: 0,
  10076. result: null,
  10077. progress: null,
  10078. };
  10079. this.lastBattleResult = {
  10080. win: false,
  10081. };
  10082. this.worker = new Worker(
  10083. URL.createObjectURL(
  10084. new Blob([
  10085. `self.onmessage = function(e) {
  10086. const timeout = e.data;
  10087. setTimeout(() => {
  10088. self.postMessage(1);
  10089. }, timeout);
  10090. };`,
  10091. ])
  10092. )
  10093. );
  10094. }
  10095.  
  10096. async start(endTime = Date.now() + 6e4, maxCount = 100) {
  10097. this.endTime = endTime;
  10098. this.maxCount = maxCount;
  10099. this.init();
  10100. return await new Promise((resolve) => {
  10101. this.resolve = resolve;
  10102. this.count = 0;
  10103. this.loop();
  10104. });
  10105. }
  10106.  
  10107. endFix() {
  10108. this.bestResult.maxCount = this.count;
  10109. this.worker.terminate();
  10110. this.resolve(this.bestResult);
  10111. }
  10112.  
  10113. async loop() {
  10114. const start = Date.now();
  10115. if (this.isEndLoop()) {
  10116. this.endFix();
  10117. return;
  10118. }
  10119. this.count++;
  10120. try {
  10121. this.lastResult = await Calc(this.battle);
  10122. } catch (e) {
  10123. this.updateProgressTimer(this.index++);
  10124. this.timeout(this.loop.bind(this), 0);
  10125. return;
  10126. }
  10127. const { progress, result } = this.lastResult;
  10128. this.lastBattleResult = result;
  10129. this.lastBattleProgress = progress;
  10130. this.setAvgTime(start);
  10131. this.checkResult();
  10132. this.showResult();
  10133. this.updateProgressTimer();
  10134. this.timeout(this.loop.bind(this), 0);
  10135. }
  10136.  
  10137. isEndLoop() {
  10138. return this.count >= this.maxCount || this.endTime < Date.now();
  10139. }
  10140.  
  10141. updateProgressTimer(index = 0) {
  10142. this.lastTimer = this.randTimer();
  10143. this.battle.progress = [{ attackers: { input: ['auto', 0, 0, 'auto', index, this.lastTimer] } }];
  10144. }
  10145.  
  10146. showResult() {
  10147. console.log(
  10148. this.count,
  10149. this.avgTime.toFixed(2),
  10150. (this.endTime - Date.now()) / 1000,
  10151. this.lastTimer.toFixed(2),
  10152. this.lastBossDamage.toLocaleString(),
  10153. this.bestResult.value.toLocaleString()
  10154. );
  10155. }
  10156.  
  10157. checkResult() {
  10158. const { damageTaken, damageTakenNextLevel } = this.lastBattleProgress[0].defenders.heroes[1].extra;
  10159. this.lastBossDamage = damageTaken + damageTakenNextLevel;
  10160. if (this.lastBossDamage > this.bestResult.value) {
  10161. this.bestResult = {
  10162. count: this.count,
  10163. timer: this.lastTimer,
  10164. value: this.lastBossDamage,
  10165. result: structuredClone(this.lastBattleResult),
  10166. progress: structuredClone(this.lastBattleProgress),
  10167. };
  10168. }
  10169. }
  10170.  
  10171. stopFix() {
  10172. this.endTime = 0;
  10173. }
  10174. }
  10175.  
  10176. class WinFixBattle extends FixBattle {
  10177. checkResult() {
  10178. if (this.lastBattleResult.win) {
  10179. this.bestResult = {
  10180. count: this.count,
  10181. timer: this.lastTimer,
  10182. value: this.lastBattleResult.stars,
  10183. result: structuredClone(this.lastBattleResult),
  10184. progress: structuredClone(this.lastBattleProgress),
  10185. battleTimer: this.lastResult.battleTimer,
  10186. };
  10187. }
  10188. }
  10189.  
  10190. setWinTimer(value) {
  10191. this.winTimer = value;
  10192. }
  10193.  
  10194. setMaxTimer(value) {
  10195. this.maxTimer = value;
  10196. }
  10197.  
  10198. randTimer() {
  10199. const min = 1.3;
  10200. const max = 30.3;
  10201. return Math.random() * (max - min + 1) + min;
  10202. }
  10203.  
  10204. isEndLoop() {
  10205. return super.isEndLoop() || this.bestResult.result?.win;
  10206. }
  10207.  
  10208. showResult() {
  10209. console.log(
  10210. this.count,
  10211. this.avgTime.toFixed(2),
  10212. (this.endTime - Date.now()) / 1000,
  10213. this.lastResult.battleTime,
  10214. this.lastTimer,
  10215. this.bestResult.value
  10216. );
  10217. const endTime = ((this.endTime - Date.now()) / 1000).toFixed(2);
  10218. const avgTime = this.avgTime.toFixed(2);
  10219. const msg = `${I18N('LETS_FIX')} ${this.count}/${this.maxCount}<br/>${endTime}s<br/>${avgTime}ms`;
  10220. setProgress(msg, false, this.stopFix.bind(this));
  10221. }
  10222. }
  10223.  
  10224. class BestOrWinFixBattle extends WinFixBattle {
  10225. isNoMakeWin = false;
  10226.  
  10227. getState(result) {
  10228. let beforeSumFactor = 0;
  10229. const beforeHeroes = result.battleData.defenders[0];
  10230. for (let heroId in beforeHeroes) {
  10231. const hero = beforeHeroes[heroId];
  10232. const state = hero.state;
  10233. let factor = 1;
  10234. if (state) {
  10235. const hp = state.hp / (hero?.hp || 1);
  10236. const energy = state.energy / 1e3;
  10237. factor = hp + energy / 20;
  10238. }
  10239. beforeSumFactor += factor;
  10240. }
  10241.  
  10242. let afterSumFactor = 0;
  10243. const afterHeroes = result.progress[0].defenders.heroes;
  10244. for (let heroId in afterHeroes) {
  10245. const hero = afterHeroes[heroId];
  10246. const hp = hero.hp / (beforeHeroes[heroId]?.hp || 1);
  10247. const energy = hero.energy / 1e3;
  10248. const factor = hp + energy / 20;
  10249. afterSumFactor += factor;
  10250. }
  10251. return 100 - Math.floor((afterSumFactor / beforeSumFactor) * 1e4) / 100;
  10252. }
  10253.  
  10254. setNoMakeWin(value) {
  10255. this.isNoMakeWin = value;
  10256. }
  10257.  
  10258. checkResult() {
  10259. const state = this.getState(this.lastResult);
  10260. console.log(state);
  10261.  
  10262. if (state > this.bestResult.value) {
  10263. if (!(this.isNoMakeWin && this.lastBattleResult.win)) {
  10264. this.bestResult = {
  10265. count: this.count,
  10266. timer: this.lastTimer,
  10267. value: state,
  10268. result: structuredClone(this.lastBattleResult),
  10269. progress: structuredClone(this.lastBattleProgress),
  10270. battleTimer: this.lastResult.battleTimer,
  10271. };
  10272. }
  10273. }
  10274. }
  10275. }
  10276.  
  10277. class BossFixBattle extends FixBattle {
  10278. showResult() {
  10279. super.showResult();
  10280. //setTimeout(() => {
  10281. const best = this.bestResult;
  10282. const maxDmg = best.value.toLocaleString();
  10283. const avgTime = this.avgTime.toLocaleString();
  10284. const msg = `${I18N('LETS_FIX')} ${this.count}/${this.maxCount}<br/>${maxDmg}<br/>${avgTime}ms`;
  10285. setProgress(msg, false, this.stopFix.bind(this));
  10286. //}, 0);
  10287. }
  10288. }
  10289.  
  10290. class DungeonFixBattle extends FixBattle {
  10291. init() {
  10292. super.init();
  10293. this.isTimeout = false;
  10294. }
  10295.  
  10296. setState() {
  10297. const result = this.lastResult;
  10298. let beforeSumFactor = 0;
  10299. const beforeHeroes = result.battleData.attackers;
  10300. for (let heroId in beforeHeroes) {
  10301. const hero = beforeHeroes[heroId];
  10302. const state = hero.state;
  10303. let factor = 1;
  10304. if (state) {
  10305. const hp = state.hp / (hero?.hp || 1);
  10306. const energy = state.energy / 1e3;
  10307. factor = hp + energy / 20;
  10308. }
  10309. beforeSumFactor += factor;
  10310. }
  10311.  
  10312. let afterSumFactor = 0;
  10313. const afterHeroes = result.progress[0].attackers.heroes;
  10314. for (let heroId in afterHeroes) {
  10315. const hero = afterHeroes[heroId];
  10316. const hp = hero.hp / (beforeHeroes[heroId]?.hp || 1);
  10317. const energy = hero.energy / 1e3;
  10318. const factor = hp + energy / 20;
  10319. afterSumFactor += factor;
  10320. }
  10321. this.lastState = Math.floor((afterSumFactor / beforeSumFactor) * 1e4) / 100;
  10322. }
  10323.  
  10324. checkResult() {
  10325. this.setState();
  10326. if (this.lastResult.result.win && this.lastState > this.bestResult.value) {
  10327. this.bestResult = {
  10328. count: this.count,
  10329. timer: this.lastTimer,
  10330. value: this.lastState,
  10331. result: this.lastResult.result,
  10332. progress: this.lastResult.progress,
  10333. };
  10334. }
  10335. }
  10336.  
  10337. showResult() {
  10338. console.log(
  10339. this.count,
  10340. this.avgTime.toFixed(2),
  10341. (this.endTime - Date.now()) / 1000,
  10342. this.lastTimer.toFixed(2),
  10343. this.lastState.toLocaleString(),
  10344. this.bestResult.value.toLocaleString()
  10345. );
  10346. }
  10347. }
  10348.  
  10349. const masterWsMixin = {
  10350. wsStart() {
  10351. const socket = new WebSocket(this.url);
  10352.  
  10353. socket.onopen = () => {
  10354. console.log('Connected to server');
  10355.  
  10356. // Пример создания новой задачи
  10357. const newTask = {
  10358. type: 'newTask',
  10359. battle: this.battle,
  10360. endTime: this.endTime - 1e4,
  10361. maxCount: this.maxCount,
  10362. };
  10363. socket.send(JSON.stringify(newTask));
  10364. };
  10365.  
  10366. socket.onmessage = this.onmessage.bind(this);
  10367.  
  10368. socket.onclose = () => {
  10369. console.log('Disconnected from server');
  10370. };
  10371.  
  10372. this.ws = socket;
  10373. },
  10374.  
  10375. onmessage(event) {
  10376. const data = JSON.parse(event.data);
  10377. switch (data.type) {
  10378. case 'newTask': {
  10379. console.log('newTask:', data);
  10380. this.id = data.id;
  10381. this.countExecutor = data.count;
  10382. break;
  10383. }
  10384. case 'getSolTask': {
  10385. console.log('getSolTask:', data);
  10386. this.endFix(data.solutions);
  10387. break;
  10388. }
  10389. case 'resolveTask': {
  10390. console.log('resolveTask:', data);
  10391. if (data.id === this.id && data.solutions.length === this.countExecutor) {
  10392. this.worker.terminate();
  10393. this.endFix(data.solutions);
  10394. }
  10395. break;
  10396. }
  10397. default:
  10398. console.log('Unknown message type:', data.type);
  10399. }
  10400. },
  10401.  
  10402. getTask() {
  10403. this.ws.send(
  10404. JSON.stringify({
  10405. type: 'getSolTask',
  10406. id: this.id,
  10407. })
  10408. );
  10409. },
  10410. };
  10411.  
  10412. /*
  10413. mFix = new action.masterFixBattle(battle)
  10414. await mFix.start(Date.now() + 6e4, 1);
  10415. */
  10416. class masterFixBattle extends FixBattle {
  10417. constructor(battle, url = 'wss://localho.st:3000') {
  10418. super(battle, true);
  10419. this.url = url;
  10420. }
  10421.  
  10422. async start(endTime, maxCount) {
  10423. this.endTime = endTime;
  10424. this.maxCount = maxCount;
  10425. this.init();
  10426. this.wsStart();
  10427. return await new Promise((resolve) => {
  10428. this.resolve = resolve;
  10429. const timeout = this.endTime - Date.now();
  10430. this.timeout(this.getTask.bind(this), timeout);
  10431. });
  10432. }
  10433.  
  10434. async endFix(solutions) {
  10435. this.ws.close();
  10436. let maxCount = 0;
  10437. for (const solution of solutions) {
  10438. maxCount += solution.maxCount;
  10439. if (solution.value > this.bestResult.value) {
  10440. this.bestResult = solution;
  10441. }
  10442. }
  10443. this.count = maxCount;
  10444. super.endFix();
  10445. }
  10446. }
  10447.  
  10448. Object.assign(masterFixBattle.prototype, masterWsMixin);
  10449. class masterWinFixBattle extends WinFixBattle {
  10450. constructor(battle, url = 'wss://localho.st:3000') {
  10451. super(battle, true);
  10452. this.url = url;
  10453. }
  10454.  
  10455. async start(endTime, maxCount) {
  10456. this.endTime = endTime;
  10457. this.maxCount = maxCount;
  10458. this.init();
  10459. this.wsStart();
  10460. return await new Promise((resolve) => {
  10461. this.resolve = resolve;
  10462. const timeout = this.endTime - Date.now();
  10463. this.timeout(this.getTask.bind(this), timeout);
  10464. });
  10465. }
  10466.  
  10467. async endFix(solutions) {
  10468. this.ws.close();
  10469. let maxCount = 0;
  10470. for (const solution of solutions) {
  10471. maxCount += solution.maxCount;
  10472. if (solution.value > this.bestResult.value) {
  10473. this.bestResult = solution;
  10474. }
  10475. }
  10476. this.count = maxCount;
  10477. super.endFix();
  10478. }
  10479. }
  10480.  
  10481. Object.assign(masterWinFixBattle.prototype, masterWsMixin);
  10482.  
  10483. const slaveWsMixin = {
  10484. wsStop() {
  10485. this.ws.close();
  10486. },
  10487.  
  10488. wsStart() {
  10489. const socket = new WebSocket(this.url);
  10490.  
  10491. socket.onopen = () => {
  10492. console.log('Connected to server');
  10493. };
  10494. socket.onmessage = this.onmessage.bind(this);
  10495. socket.onclose = () => {
  10496. console.log('Disconnected from server');
  10497. };
  10498.  
  10499. this.ws = socket;
  10500. },
  10501.  
  10502. async onmessage(event) {
  10503. const data = JSON.parse(event.data);
  10504. switch (data.type) {
  10505. case 'newTask': {
  10506. console.log('newTask:', data.task);
  10507. const { battle, endTime, maxCount } = data.task;
  10508. this.battle = battle;
  10509. const id = data.task.id;
  10510. const solution = await this.start(endTime, maxCount);
  10511. this.ws.send(
  10512. JSON.stringify({
  10513. type: 'resolveTask',
  10514. id,
  10515. solution,
  10516. })
  10517. );
  10518. break;
  10519. }
  10520. default:
  10521. console.log('Unknown message type:', data.type);
  10522. }
  10523. },
  10524. };
  10525. /*
  10526. sFix = new action.slaveFixBattle();
  10527. sFix.wsStart()
  10528. */
  10529. class slaveFixBattle extends FixBattle {
  10530. constructor(url = 'wss://localho.st:3000') {
  10531. super(null, false);
  10532. this.isTimeout = false;
  10533. this.url = url;
  10534. }
  10535. }
  10536.  
  10537. Object.assign(slaveFixBattle.prototype, slaveWsMixin);
  10538.  
  10539. class slaveWinFixBattle extends WinFixBattle {
  10540. constructor(url = 'wss://localho.st:3000') {
  10541. super(null, false);
  10542. this.isTimeout = false;
  10543. this.url = url;
  10544. }
  10545. }
  10546.  
  10547. Object.assign(slaveWinFixBattle.prototype, slaveWsMixin);
  10548. /**
  10549. * Auto-repeat attack
  10550. *
  10551. * Автоповтор атаки
  10552. */
  10553. function testAutoBattle() {
  10554. return new Promise((resolve, reject) => {
  10555. const bossBattle = new executeAutoBattle(resolve, reject);
  10556. bossBattle.start(lastBattleArg, lastBattleInfo);
  10557. });
  10558. }
  10559.  
  10560. /**
  10561. * Auto-repeat attack
  10562. *
  10563. * Автоповтор атаки
  10564. */
  10565. function executeAutoBattle(resolve, reject) {
  10566. let battleArg = {};
  10567. let countBattle = 0;
  10568. let countError = 0;
  10569. let findCoeff = 0;
  10570. let dataNotEeceived = 0;
  10571. let stopAutoBattle = false;
  10572.  
  10573. let isSetWinTimer = false;
  10574. 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>';
  10575. 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>';
  10576. 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>';
  10577.  
  10578. this.start = function (battleArgs, battleInfo) {
  10579. battleArg = battleArgs;
  10580. if (nameFuncStartBattle == 'invasion_bossStart') {
  10581. startBattle();
  10582. return;
  10583. }
  10584. preCalcBattle(battleInfo);
  10585. }
  10586. /**
  10587. * Returns a promise for combat recalculation
  10588. *
  10589. * Возвращает промис для прерасчета боя
  10590. */
  10591. function getBattleInfo(battle) {
  10592. return new Promise(function (resolve) {
  10593. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  10594. Calc(battle).then(e => {
  10595. e.coeff = calcCoeff(e, 'defenders');
  10596. resolve(e);
  10597. });
  10598. });
  10599. }
  10600. /**
  10601. * Battle recalculation
  10602. *
  10603. * Прерасчет боя
  10604. */
  10605. function preCalcBattle(battle) {
  10606. let actions = [];
  10607. const countTestBattle = getInput('countTestBattle');
  10608. for (let i = 0; i < countTestBattle; i++) {
  10609. actions.push(getBattleInfo(battle));
  10610. }
  10611. Promise.all(actions)
  10612. .then(resultPreCalcBattle);
  10613. }
  10614. /**
  10615. * Processing the results of the battle recalculation
  10616. *
  10617. * Обработка результатов прерасчета боя
  10618. */
  10619. async function resultPreCalcBattle(results) {
  10620. let countWin = results.reduce((s, w) => w.result.win + s, 0);
  10621. setProgress(`${I18N('CHANCE_TO_WIN')} ${Math.floor(countWin / results.length * 100)}% (${results.length})`, false, hideProgress);
  10622. if (countWin > 0) {
  10623. isCancalBattle = false;
  10624. startBattle();
  10625. return;
  10626. }
  10627.  
  10628. let minCoeff = 100;
  10629. let maxCoeff = -100;
  10630. let avgCoeff = 0;
  10631. results.forEach(e => {
  10632. if (e.coeff < minCoeff) minCoeff = e.coeff;
  10633. if (e.coeff > maxCoeff) maxCoeff = e.coeff;
  10634. avgCoeff += e.coeff;
  10635. });
  10636. avgCoeff /= results.length;
  10637.  
  10638. if (nameFuncStartBattle == 'invasion_bossStart' ||
  10639. nameFuncStartBattle == 'bossAttack') {
  10640. const result = await popup.confirm(
  10641. I18N('BOSS_VICTORY_IMPOSSIBLE', { battles: results.length }), [
  10642. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  10643. { msg: I18N('BTN_DO_IT'), result: true },
  10644. ])
  10645. if (result) {
  10646. isCancalBattle = false;
  10647. startBattle();
  10648. return;
  10649. }
  10650. setProgress(I18N('NOT_THIS_TIME'), true);
  10651. endAutoBattle('invasion_bossStart');
  10652. return;
  10653. }
  10654.  
  10655. const result = await popup.confirm(
  10656. I18N('VICTORY_IMPOSSIBLE') +
  10657. `<br>${I18N('ROUND_STAT')} ${results.length} ${I18N('BATTLE')}:` +
  10658. `<br>${I18N('MINIMUM')}: ` + minCoeff.toLocaleString() +
  10659. `<br>${I18N('MAXIMUM')}: ` + maxCoeff.toLocaleString() +
  10660. `<br>${I18N('AVERAGE')}: ` + avgCoeff.toLocaleString() +
  10661. `<br>${I18N('FIND_COEFF')} ` + avgCoeff.toLocaleString(), [
  10662. { msg: I18N('BTN_CANCEL'), result: 0, isCancel: true },
  10663. { msg: I18N('BTN_GO'), isInput: true, default: Math.round(avgCoeff * 1000) / 1000 },
  10664. ])
  10665. if (result) {
  10666. findCoeff = result;
  10667. isCancalBattle = false;
  10668. startBattle();
  10669. return;
  10670. }
  10671. setProgress(I18N('NOT_THIS_TIME'), true);
  10672. endAutoBattle(I18N('NOT_THIS_TIME'));
  10673. }
  10674.  
  10675. /**
  10676. * Calculation of the combat result coefficient
  10677. *
  10678. * Расчет коэфициента результата боя
  10679. */
  10680. function calcCoeff(result, packType) {
  10681. let beforeSumFactor = 0;
  10682. const beforePack = result.battleData[packType][0];
  10683. for (let heroId in beforePack) {
  10684. const hero = beforePack[heroId];
  10685. const state = hero.state;
  10686. let factor = 1;
  10687. if (state) {
  10688. const hp = state.hp / state.maxHp;
  10689. const energy = state.energy / 1e3;
  10690. factor = hp + energy / 20;
  10691. }
  10692. beforeSumFactor += factor;
  10693. }
  10694.  
  10695. let afterSumFactor = 0;
  10696. const afterPack = result.progress[0][packType].heroes;
  10697. for (let heroId in afterPack) {
  10698. const hero = afterPack[heroId];
  10699. const stateHp = beforePack[heroId]?.state?.hp || beforePack[heroId]?.stats?.hp;
  10700. const hp = hero.hp / stateHp;
  10701. const energy = hero.energy / 1e3;
  10702. const factor = hp + energy / 20;
  10703. afterSumFactor += factor;
  10704. }
  10705. const resultCoeff = -(afterSumFactor - beforeSumFactor);
  10706. return Math.round(resultCoeff * 1000) / 1000;
  10707. }
  10708. /**
  10709. * Start battle
  10710. *
  10711. * Начало боя
  10712. */
  10713. function startBattle() {
  10714. countBattle++;
  10715. const countMaxBattle = getInput('countAutoBattle');
  10716. // setProgress(countBattle + '/' + countMaxBattle);
  10717. if (countBattle > countMaxBattle) {
  10718. setProgress(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`, true);
  10719. endAutoBattle(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`)
  10720. return;
  10721. }
  10722. if (stopAutoBattle) {
  10723. setProgress(I18N('STOPPED'), true);
  10724. endAutoBattle('STOPPED');
  10725. return;
  10726. }
  10727. send({calls: [{
  10728. name: nameFuncStartBattle,
  10729. args: battleArg,
  10730. ident: "body"
  10731. }]}, calcResultBattle);
  10732. }
  10733. /**
  10734. * Battle calculation
  10735. *
  10736. * Расчет боя
  10737. */
  10738. async function calcResultBattle(e) {
  10739. if ('error' in e) {
  10740. if (e.error.description === 'too many tries') {
  10741. invasionTimer += 100;
  10742. countBattle--;
  10743. countError++;
  10744. console.log(`Errors: ${countError}`, e.error);
  10745. startBattle();
  10746. return;
  10747. }
  10748. const result = await popup.confirm(I18N('ERROR_DURING_THE_BATTLE') + '<br>' + e.error.description, [
  10749. { msg: I18N('BTN_OK'), result: false },
  10750. { msg: I18N('RELOAD_GAME'), result: true },
  10751. ]);
  10752. endAutoBattle('Error', e.error);
  10753. if (result) {
  10754. location.reload();
  10755. }
  10756. return;
  10757. }
  10758. let battle = e.results[0].result.response.battle
  10759. if (nameFuncStartBattle == 'towerStartBattle' ||
  10760. nameFuncStartBattle == 'bossAttack' ||
  10761. nameFuncStartBattle == 'invasion_bossStart') {
  10762. battle = e.results[0].result.response;
  10763. }
  10764. lastBattleInfo = battle;
  10765. BattleCalc(battle, getBattleType(battle.type), resultBattle);
  10766. }
  10767. /**
  10768. * Processing the results of the battle
  10769. *
  10770. * Обработка результатов боя
  10771. */
  10772. async function resultBattle(e) {
  10773. const isWin = e.result.win;
  10774. if (isWin) {
  10775. endBattle(e, false);
  10776. return;
  10777. } else if (isChecked('tryFixIt_v2')) {
  10778. const cloneBattle = structuredClone(e.battleData);
  10779. const bFix = new WinFixBattle(cloneBattle);
  10780. let attempts = Infinity;
  10781. if (nameFuncStartBattle == 'invasion_bossStart' && !isSetWinTimer) {
  10782. let winTimer = await popup.confirm(`Secret number:`, [
  10783. { result: false, isClose: true },
  10784. { msg: 'Go', isInput: true, default: '0' },
  10785. ]);
  10786. winTimer = Number.parseFloat(winTimer);
  10787. if (winTimer) {
  10788. attempts = 5;
  10789. bFix.setWinTimer(winTimer);
  10790. }
  10791. isSetWinTimer = true;
  10792. }
  10793. let endTime = Date.now() + 6e4;
  10794. if (nameFuncStartBattle == 'invasion_bossStart') {
  10795. endTime = Date.now() + 6e4 * 4;
  10796. bFix.setMaxTimer(120.3);
  10797. }
  10798. const result = await bFix.start(endTime, attempts);
  10799. console.log(result);
  10800. if (result.value) {
  10801. endBattle(result, false);
  10802. return;
  10803. }
  10804. }
  10805. const countMaxBattle = getInput('countAutoBattle');
  10806. if (findCoeff) {
  10807. const coeff = calcCoeff(e, 'defenders');
  10808. setProgress(`${countBattle}/${countMaxBattle}, ${coeff}`);
  10809. if (coeff > findCoeff) {
  10810. endBattle(e, false);
  10811. return;
  10812. }
  10813. } else {
  10814. if (nameFuncStartBattle == 'invasion_bossStart') {
  10815. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  10816. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageModAndEnergyIncrease_any_99_100_300_99_1000_300 || 0;
  10817. setProgress(`${svgBoss} ${bossLvl} ${svgJustice} ${justice} <br>${svgAttempt} ${countBattle}/${countMaxBattle}`, false, () => {
  10818. stopAutoBattle = true;
  10819. });
  10820. await new Promise((resolve) => setTimeout(resolve, 5000));
  10821. } else {
  10822. setProgress(`${countBattle}/${countMaxBattle}`);
  10823. }
  10824. }
  10825. if (nameFuncStartBattle == 'towerStartBattle' ||
  10826. nameFuncStartBattle == 'bossAttack' ||
  10827. nameFuncStartBattle == 'invasion_bossStart') {
  10828. startBattle();
  10829. return;
  10830. }
  10831. cancelEndBattle(e);
  10832. }
  10833. /**
  10834. * Cancel fight
  10835. *
  10836. * Отмена боя
  10837. */
  10838. function cancelEndBattle(r) {
  10839. const fixBattle = function (heroes) {
  10840. for (const ids in heroes) {
  10841. hero = heroes[ids];
  10842. hero.energy = random(1, 999);
  10843. if (hero.hp > 0) {
  10844. hero.hp = random(1, hero.hp);
  10845. }
  10846. }
  10847. }
  10848. fixBattle(r.progress[0].attackers.heroes);
  10849. fixBattle(r.progress[0].defenders.heroes);
  10850. endBattle(r, true);
  10851. }
  10852. /**
  10853. * End of the fight
  10854. *
  10855. * Завершение боя */
  10856. function endBattle(battleResult, isCancal) {
  10857. let calls = [{
  10858. name: nameFuncEndBattle,
  10859. args: {
  10860. result: battleResult.result,
  10861. progress: battleResult.progress
  10862. },
  10863. ident: "body"
  10864. }];
  10865.  
  10866. if (nameFuncStartBattle == 'invasion_bossStart') {
  10867. calls[0].args.id = lastBattleArg.id;
  10868. }
  10869.  
  10870. send(JSON.stringify({
  10871. calls
  10872. }), async e => {
  10873. console.log(e);
  10874. if (isCancal) {
  10875. startBattle();
  10876. return;
  10877. }
  10878.  
  10879. setProgress(`${I18N('SUCCESS')}!`, 5000)
  10880. if (nameFuncStartBattle == 'invasion_bossStart' ||
  10881. nameFuncStartBattle == 'bossAttack') {
  10882. const countMaxBattle = getInput('countAutoBattle');
  10883. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  10884. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageModAndEnergyIncrease_any_99_100_300_99_1000_300 || 0;
  10885. let winTimer = '';
  10886. if (nameFuncStartBattle == 'invasion_bossStart') {
  10887. winTimer = '<br>Secret number: ' + battleResult.progress[0].attackers.input[5];
  10888. }
  10889.  
  10890. const result = await popup.confirm(
  10891. I18N('BOSS_HAS_BEEN_DEF_TEXT', {
  10892. bossLvl: `${svgBoss} ${bossLvl} ${svgJustice} ${justice}`,
  10893. countBattle: svgAttempt + ' ' + countBattle,
  10894. countMaxBattle,}),
  10895. winTimer,
  10896. [
  10897. { msg: I18N('BTN_OK'), result: 0 },
  10898. { msg: I18N('MAKE_A_SYNC'), result: 1 },
  10899. { msg: I18N('RELOAD_GAME'), result: 2 },
  10900. ]);
  10901. if (result) {
  10902. if (result == 1) {
  10903. cheats.refreshGame();
  10904. }
  10905. if (result == 2) {
  10906. location.reload();
  10907. }
  10908. }
  10909.  
  10910. }
  10911. endAutoBattle(`${I18N('SUCCESS')}!`)
  10912. });
  10913. }
  10914. /**
  10915. * Completing a task
  10916. *
  10917. * Завершение задачи
  10918. */
  10919. function endAutoBattle(reason, info) {
  10920. isCancalBattle = true;
  10921. console.log(reason, info);
  10922. resolve();
  10923. }
  10924. }
  10925.  
  10926. function testDailyQuests() {
  10927. return new Promise((resolve, reject) => {
  10928. const quests = new dailyQuests(resolve, reject);
  10929. quests.init(questsInfo);
  10930. quests.start();
  10931. });
  10932. }
  10933.  
  10934. /**
  10935. * Automatic completion of daily quests
  10936. *
  10937. * Автоматическое выполнение ежедневных квестов
  10938. */
  10939. class dailyQuests {
  10940. /**
  10941. * Send(' {"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}').then(e => console.log(e))
  10942. * Send(' {"calls":[{"name":"heroGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10943. * Send(' {"calls":[{"name":"titanGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10944. * Send(' {"calls":[{"name":"inventoryGet","args":{},"ident":"body"}]}').then(e => console.log(e))
  10945. * Send(' {"calls":[{"name":"questGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10946. * Send(' {"calls":[{"name":"bossGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10947. */
  10948. callsList = ['userGetInfo', 'heroGetAll', 'titanGetAll', 'inventoryGet', 'questGetAll', 'bossGetAll', 'missionGetAll'];
  10949.  
  10950. dataQuests = {
  10951. 10001: {
  10952. description: 'Улучши умения героев 3 раза', // ++++++++++++++++
  10953. doItCall: () => {
  10954. const upgradeSkills = this.getUpgradeSkills();
  10955. return upgradeSkills.map(({ heroId, skill }, index) => ({
  10956. name: 'heroUpgradeSkill',
  10957. args: { heroId, skill },
  10958. ident: `heroUpgradeSkill_${index}`,
  10959. }));
  10960. },
  10961. isWeCanDo: () => {
  10962. const upgradeSkills = this.getUpgradeSkills();
  10963. let sumGold = 0;
  10964. for (const skill of upgradeSkills) {
  10965. sumGold += this.skillCost(skill.value);
  10966. if (!skill.heroId) {
  10967. return false;
  10968. }
  10969. }
  10970. return this.questInfo['userGetInfo'].gold > sumGold;
  10971. },
  10972. },
  10973. 10002: {
  10974. description: 'Пройди 10 миссий', // --------------
  10975. isWeCanDo: () => false,
  10976. },
  10977. 10003: {
  10978. description: 'Пройди 3 героические миссии', // ++++++++++++++++
  10979. isWeCanDo: () => {
  10980. const vipPoints = +this.questInfo.userGetInfo.vipPoints;
  10981. const goldTicket = !!this.questInfo.inventoryGet.consumable[151];
  10982. return (vipPoints > 100 || goldTicket) && this.getHeroicMissionId();
  10983. },
  10984. doItCall: () => {
  10985. const selectedMissionId = this.getHeroicMissionId();
  10986. const goldTicket = !!this.questInfo.inventoryGet.consumable[151];
  10987. const vipLevel = Math.max(...lib.data.level.vip.filter(l => l.vipPoints <= +this.questInfo.userGetInfo.vipPoints).map(l => l.level));
  10988. // Возвращаем массив команд для рейда
  10989. if (vipLevel >= 5 || goldTicket) {
  10990. return [{ name: 'missionRaid', args: { id: selectedMissionId, times: 3 }, ident: 'missionRaid_1' }];
  10991. } else {
  10992. return [
  10993. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_1' },
  10994. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_2' },
  10995. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_3' },
  10996. ];
  10997. }
  10998. },
  10999. },
  11000. 10004: {
  11001. description: 'Сразись 3 раза на Арене или Гранд Арене', // --------------
  11002. isWeCanDo: () => false,
  11003. },
  11004. 10006: {
  11005. description: 'Используй обмен изумрудов 1 раз', // ++++++++++++++++
  11006. doItCall: () => [
  11007. {
  11008. name: 'refillableAlchemyUse',
  11009. args: { multi: false },
  11010. ident: 'refillableAlchemyUse',
  11011. },
  11012. ],
  11013. isWeCanDo: () => {
  11014. const starMoney = this.questInfo['userGetInfo'].starMoney;
  11015. return starMoney >= 20;
  11016. },
  11017. },
  11018. 10007: {
  11019. description: 'Соверши 1 призыв в Атриуме Душ', // ++++++++++++++++
  11020. doItCall: () => [{ name: 'gacha_open', args: { ident: 'heroGacha', free: true, pack: false }, ident: 'gacha_open' }],
  11021. isWeCanDo: () => {
  11022. const soulCrystal = this.questInfo['inventoryGet'].coin[38];
  11023. return soulCrystal > 0;
  11024. },
  11025. },
  11026. /*10016: {
  11027. description: 'Отправь подарки согильдийцам', // ++++++++++++++++
  11028. doItCall: () => [{ name: 'clanSendDailyGifts', args: {}, ident: 'clanSendDailyGifts' }],
  11029. isWeCanDo: () => true,
  11030. },*/
  11031. 10018: {
  11032. description: 'Используй зелье опыта', // ++++++++++++++++
  11033. doItCall: () => {
  11034. const expHero = this.getExpHero();
  11035. return [
  11036. {
  11037. name: 'consumableUseHeroXp',
  11038. args: {
  11039. heroId: expHero.heroId,
  11040. libId: expHero.libId,
  11041. amount: 1,
  11042. },
  11043. ident: 'consumableUseHeroXp',
  11044. },
  11045. ];
  11046. },
  11047. isWeCanDo: () => {
  11048. const expHero = this.getExpHero();
  11049. return expHero.heroId && expHero.libId;
  11050. },
  11051. },
  11052. 10019: {
  11053. description: 'Открой 1 сундук в Башне',
  11054. doItFunc: testTower,
  11055. isWeCanDo: () => false,
  11056. },
  11057. 10020: {
  11058. description: 'Открой 3 сундука в Запределье', // Готово
  11059. doItCall: () => {
  11060. return this.getOutlandChest();
  11061. },
  11062. isWeCanDo: () => {
  11063. const outlandChest = this.getOutlandChest();
  11064. return outlandChest.length > 0;
  11065. },
  11066. },
  11067. 10021: {
  11068. description: 'Собери 75 Титанита в Подземелье Гильдии',
  11069. isWeCanDo: () => false,
  11070. },
  11071. 10022: {
  11072. description: 'Собери 150 Титанита в Подземелье Гильдии',
  11073. doItFunc: testDungeon,
  11074. isWeCanDo: () => false,
  11075. },
  11076. 10023: {
  11077. description: 'Прокачай Дар Стихий на 1 уровень', // Готово
  11078. doItCall: () => {
  11079. const heroId = this.getHeroIdTitanGift();
  11080. return [
  11081. { name: 'heroTitanGiftLevelUp', args: { heroId }, ident: 'heroTitanGiftLevelUp' },
  11082. { name: 'heroTitanGiftDrop', args: { heroId }, ident: 'heroTitanGiftDrop' },
  11083. ];
  11084. },
  11085. isWeCanDo: () => {
  11086. const heroId = this.getHeroIdTitanGift();
  11087. return heroId;
  11088. },
  11089. },
  11090. 10024: {
  11091. description: 'Повысь уровень любого артефакта один раз', // Готово
  11092. doItCall: () => {
  11093. const upArtifact = this.getUpgradeArtifact();
  11094. return [
  11095. {
  11096. name: 'heroArtifactLevelUp',
  11097. args: {
  11098. heroId: upArtifact.heroId,
  11099. slotId: upArtifact.slotId,
  11100. },
  11101. ident: `heroArtifactLevelUp`,
  11102. },
  11103. ];
  11104. },
  11105. isWeCanDo: () => {
  11106. const upgradeArtifact = this.getUpgradeArtifact();
  11107. return upgradeArtifact.heroId;
  11108. },
  11109. },
  11110. 10025: {
  11111. description: 'Начни 1 Экспедицию',
  11112. doItFunc: checkExpedition,
  11113. isWeCanDo: () => false,
  11114. },
  11115. 10026: {
  11116. description: 'Начни 4 Экспедиции', // --------------
  11117. doItFunc: checkExpedition,
  11118. isWeCanDo: () => false,
  11119. },
  11120. 10027: {
  11121. description: 'Победи в 1 бою Турнира Стихий',
  11122. doItFunc: testTitanArena,
  11123. isWeCanDo: () => false,
  11124. },
  11125. 10028: {
  11126. description: 'Повысь уровень любого артефакта титанов', // Готово
  11127. doItCall: () => {
  11128. const upTitanArtifact = this.getUpgradeTitanArtifact();
  11129. return [
  11130. {
  11131. name: 'titanArtifactLevelUp',
  11132. args: {
  11133. titanId: upTitanArtifact.titanId,
  11134. slotId: upTitanArtifact.slotId,
  11135. },
  11136. ident: `titanArtifactLevelUp`,
  11137. },
  11138. ];
  11139. },
  11140. isWeCanDo: () => {
  11141. const upgradeTitanArtifact = this.getUpgradeTitanArtifact();
  11142. return upgradeTitanArtifact.titanId;
  11143. },
  11144. },
  11145. 10029: {
  11146. description: 'Открой сферу артефактов титанов', // ++++++++++++++++
  11147. doItCall: () => [{ name: 'titanArtifactChestOpen', args: { amount: 1, free: true }, ident: 'titanArtifactChestOpen' }],
  11148. isWeCanDo: () => {
  11149. return this.questInfo['inventoryGet']?.consumable[55] > 0;
  11150. },
  11151. },
  11152. 10030: {
  11153. description: 'Улучши облик любого героя 1 раз', // Готово
  11154. doItCall: () => {
  11155. const upSkin = this.getUpgradeSkin();
  11156. return [
  11157. {
  11158. name: 'heroSkinUpgrade',
  11159. args: {
  11160. heroId: upSkin.heroId,
  11161. skinId: upSkin.skinId,
  11162. },
  11163. ident: `heroSkinUpgrade`,
  11164. },
  11165. ];
  11166. },
  11167. isWeCanDo: () => {
  11168. const upgradeSkin = this.getUpgradeSkin();
  11169. return upgradeSkin.heroId;
  11170. },
  11171. },
  11172. 10031: {
  11173. description: 'Победи в 6 боях Турнира Стихий', // --------------
  11174. doItFunc: testTitanArena,
  11175. isWeCanDo: () => false,
  11176. },
  11177. 10043: {
  11178. description: 'Начни или присоеденись к Приключению', // --------------
  11179. isWeCanDo: () => false,
  11180. },
  11181. 10044: {
  11182. description: 'Воспользуйся призывом питомцев 1 раз', // ++++++++++++++++
  11183. doItCall: () => [{ name: 'pet_chestOpen', args: { amount: 1, paid: false }, ident: 'pet_chestOpen' }],
  11184. isWeCanDo: () => {
  11185. return this.questInfo['inventoryGet']?.consumable[90] > 0;
  11186. },
  11187. },
  11188. 10046: {
  11189. /**
  11190. * TODO: Watch Adventure
  11191. * TODO: Смотреть приключение
  11192. */
  11193. description: 'Открой 3 сундука в Приключениях',
  11194. isWeCanDo: () => false,
  11195. },
  11196. 10047: {
  11197. description: 'Набери 150 очков активности в Гильдии', // Готово
  11198. doItCall: () => {
  11199. const enchantRune = this.getEnchantRune();
  11200. return [
  11201. {
  11202. name: 'heroEnchantRune',
  11203. args: {
  11204. heroId: enchantRune.heroId,
  11205. tier: enchantRune.tier,
  11206. items: {
  11207. consumable: { [enchantRune.itemId]: 1 },
  11208. },
  11209. },
  11210. ident: `heroEnchantRune`,
  11211. },
  11212. ];
  11213. },
  11214. isWeCanDo: () => {
  11215. const userInfo = this.questInfo['userGetInfo'];
  11216. const enchantRune = this.getEnchantRune();
  11217. return enchantRune.heroId && userInfo.gold > 1e3;
  11218. },
  11219. },
  11220. };
  11221.  
  11222. constructor(resolve, reject, questInfo) {
  11223. this.resolve = resolve;
  11224. this.reject = reject;
  11225. }
  11226.  
  11227. init(questInfo) {
  11228. this.questInfo = questInfo;
  11229. this.isAuto = false;
  11230. }
  11231.  
  11232. async autoInit(isAuto) {
  11233. this.isAuto = isAuto || false;
  11234. const quests = {};
  11235. const calls = this.callsList.map((name) => ({
  11236. name,
  11237. args: {},
  11238. ident: name,
  11239. }));
  11240. const result = await Send(JSON.stringify({ calls })).then((e) => e.results);
  11241. for (const call of result) {
  11242. quests[call.ident] = call.result.response;
  11243. }
  11244. this.questInfo = quests;
  11245. }
  11246.  
  11247. async start() {
  11248. const weCanDo = [];
  11249. const selectedActions = getSaveVal('selectedActions', {});
  11250. for (let quest of this.questInfo['questGetAll']) {
  11251. if (quest.id in this.dataQuests && quest.state == 1) {
  11252. if (!selectedActions[quest.id]) {
  11253. selectedActions[quest.id] = {
  11254. checked: false,
  11255. };
  11256. }
  11257.  
  11258. const isWeCanDo = this.dataQuests[quest.id].isWeCanDo;
  11259. if (!isWeCanDo.call(this)) {
  11260. continue;
  11261. }
  11262.  
  11263. weCanDo.push({
  11264. name: quest.id,
  11265. label: I18N(`QUEST_${quest.id}`),
  11266. checked: selectedActions[quest.id].checked,
  11267. });
  11268. }
  11269. }
  11270.  
  11271. if (!weCanDo.length) {
  11272. this.end(I18N('NOTHING_TO_DO'));
  11273. return;
  11274. }
  11275.  
  11276. console.log(weCanDo);
  11277. let taskList = [];
  11278. if (this.isAuto) {
  11279. taskList = weCanDo;
  11280. } else {
  11281. const answer = await popup.confirm(
  11282. `${I18N('YOU_CAN_COMPLETE')}:`,
  11283. [
  11284. { msg: I18N('BTN_DO_IT'), result: true },
  11285. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  11286. ],
  11287. weCanDo
  11288. );
  11289. if (!answer) {
  11290. this.end('');
  11291. return;
  11292. }
  11293. taskList = popup.getCheckBoxes();
  11294. taskList.forEach((e) => {
  11295. selectedActions[e.name].checked = e.checked;
  11296. });
  11297. setSaveVal('selectedActions', selectedActions);
  11298. }
  11299.  
  11300. const calls = [];
  11301. let countChecked = 0;
  11302. for (const task of taskList) {
  11303. if (task.checked) {
  11304. countChecked++;
  11305. const quest = this.dataQuests[task.name];
  11306. console.log(quest.description);
  11307.  
  11308. if (quest.doItCall) {
  11309. const doItCall = quest.doItCall.call(this);
  11310. calls.push(...doItCall);
  11311. }
  11312. }
  11313. }
  11314.  
  11315. if (!countChecked) {
  11316. this.end(I18N('NOT_QUEST_COMPLETED'));
  11317. return;
  11318. }
  11319.  
  11320. const result = await Send(JSON.stringify({ calls }));
  11321. if (result.error) {
  11322. console.error(result.error, result.error.call);
  11323. }
  11324. this.end(`${I18N('COMPLETED_QUESTS')}: ${countChecked}`);
  11325. }
  11326.  
  11327. errorHandling(error) {
  11328. //console.error(error);
  11329. let errorInfo = error.toString() + '\n';
  11330. try {
  11331. const errorStack = error.stack.split('\n');
  11332. const endStack = errorStack.map((e) => e.split('@')[0]).indexOf('testDoYourBest');
  11333. errorInfo += errorStack.slice(0, endStack).join('\n');
  11334. } catch (e) {
  11335. errorInfo += error.stack;
  11336. }
  11337. copyText(errorInfo);
  11338. }
  11339.  
  11340. skillCost(lvl) {
  11341. return 573 * lvl ** 0.9 + lvl ** 2.379;
  11342. }
  11343.  
  11344. getUpgradeSkills() {
  11345. const heroes = Object.values(this.questInfo['heroGetAll']);
  11346. const upgradeSkills = [
  11347. { heroId: 0, slotId: 0, value: 130 },
  11348. { heroId: 0, slotId: 0, value: 130 },
  11349. { heroId: 0, slotId: 0, value: 130 },
  11350. ];
  11351. const skillLib = lib.getData('skill');
  11352. /**
  11353. * color - 1 (белый) открывает 1 навык
  11354. * color - 2 (зеленый) открывает 2 навык
  11355. * color - 4 (синий) открывает 3 навык
  11356. * color - 7 (фиолетовый) открывает 4 навык
  11357. */
  11358. const colors = [1, 2, 4, 7];
  11359. for (const hero of heroes) {
  11360. const level = hero.level;
  11361. const color = hero.color;
  11362. for (let skillId in hero.skills) {
  11363. const tier = skillLib[skillId].tier;
  11364. const sVal = hero.skills[skillId];
  11365. if (color < colors[tier] || tier < 1 || tier > 4) {
  11366. continue;
  11367. }
  11368. for (let upSkill of upgradeSkills) {
  11369. if (sVal < upSkill.value && sVal < level) {
  11370. upSkill.value = sVal;
  11371. upSkill.heroId = hero.id;
  11372. upSkill.skill = tier;
  11373. break;
  11374. }
  11375. }
  11376. }
  11377. }
  11378. return upgradeSkills;
  11379. }
  11380.  
  11381. getUpgradeArtifact() {
  11382. const heroes = Object.values(this.questInfo['heroGetAll']);
  11383. const inventory = this.questInfo['inventoryGet'];
  11384. const upArt = { heroId: 0, slotId: 0, level: 100 };
  11385.  
  11386. const heroLib = lib.getData('hero');
  11387. const artifactLib = lib.getData('artifact');
  11388.  
  11389. for (const hero of heroes) {
  11390. const heroInfo = heroLib[hero.id];
  11391. const level = hero.level;
  11392. if (level < 20) {
  11393. continue;
  11394. }
  11395.  
  11396. for (let slotId in hero.artifacts) {
  11397. const art = hero.artifacts[slotId];
  11398. /* Текущая звезданость арта */
  11399. const star = art.star;
  11400. if (!star) {
  11401. continue;
  11402. }
  11403. /* Текущий уровень арта */
  11404. const level = art.level;
  11405. if (level >= 100) {
  11406. continue;
  11407. }
  11408. /* Идентификатор арта в библиотеке */
  11409. const artifactId = heroInfo.artifacts[slotId];
  11410. const artInfo = artifactLib.id[artifactId];
  11411. const costNextLevel = artifactLib.type[artInfo.type].levels[level + 1].cost;
  11412.  
  11413. const costCurrency = Object.keys(costNextLevel).pop();
  11414. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  11415. const costId = costValues[0];
  11416. const costValue = +costValues[1];
  11417.  
  11418. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  11419. if (level < upArt.level && inventory[costCurrency][costId] >= costValue) {
  11420. upArt.level = level;
  11421. upArt.heroId = hero.id;
  11422. upArt.slotId = slotId;
  11423. upArt.costCurrency = costCurrency;
  11424. upArt.costId = costId;
  11425. upArt.costValue = costValue;
  11426. }
  11427. }
  11428. }
  11429. return upArt;
  11430. }
  11431.  
  11432. getUpgradeSkin() {
  11433. const heroes = Object.values(this.questInfo['heroGetAll']);
  11434. const inventory = this.questInfo['inventoryGet'];
  11435. const upSkin = { heroId: 0, skinId: 0, level: 60, cost: 1500 };
  11436.  
  11437. const skinLib = lib.getData('skin');
  11438.  
  11439. for (const hero of heroes) {
  11440. const level = hero.level;
  11441. if (level < 20) {
  11442. continue;
  11443. }
  11444.  
  11445. for (let skinId in hero.skins) {
  11446. /* Текущий уровень скина */
  11447. const level = hero.skins[skinId];
  11448. if (level >= 60) {
  11449. continue;
  11450. }
  11451. /* Идентификатор скина в библиотеке */
  11452. const skinInfo = skinLib[skinId];
  11453. if (!skinInfo.statData.levels?.[level + 1]) {
  11454. continue;
  11455. }
  11456. const costNextLevel = skinInfo.statData.levels[level + 1].cost;
  11457.  
  11458. const costCurrency = Object.keys(costNextLevel).pop();
  11459. const costCurrencyId = Object.keys(costNextLevel[costCurrency]).pop();
  11460. const costValue = +costNextLevel[costCurrency][costCurrencyId];
  11461.  
  11462. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  11463. if (level < upSkin.level && costValue < upSkin.cost && inventory[costCurrency][costCurrencyId] >= costValue) {
  11464. upSkin.cost = costValue;
  11465. upSkin.level = level;
  11466. upSkin.heroId = hero.id;
  11467. upSkin.skinId = skinId;
  11468. upSkin.costCurrency = costCurrency;
  11469. upSkin.costCurrencyId = costCurrencyId;
  11470. }
  11471. }
  11472. }
  11473. return upSkin;
  11474. }
  11475.  
  11476. getUpgradeTitanArtifact() {
  11477. const titans = Object.values(this.questInfo['titanGetAll']);
  11478. const inventory = this.questInfo['inventoryGet'];
  11479. const userInfo = this.questInfo['userGetInfo'];
  11480. const upArt = { titanId: 0, slotId: 0, level: 120 };
  11481.  
  11482. const titanLib = lib.getData('titan');
  11483. const artTitanLib = lib.getData('titanArtifact');
  11484.  
  11485. for (const titan of titans) {
  11486. const titanInfo = titanLib[titan.id];
  11487. // const level = titan.level
  11488. // if (level < 20) {
  11489. // continue;
  11490. // }
  11491.  
  11492. for (let slotId in titan.artifacts) {
  11493. const art = titan.artifacts[slotId];
  11494. /* Текущая звезданость арта */
  11495. const star = art.star;
  11496. if (!star) {
  11497. continue;
  11498. }
  11499. /* Текущий уровень арта */
  11500. const level = art.level;
  11501. if (level >= 120) {
  11502. continue;
  11503. }
  11504. /* Идентификатор арта в библиотеке */
  11505. const artifactId = titanInfo.artifacts[slotId];
  11506. const artInfo = artTitanLib.id[artifactId];
  11507. const costNextLevel = artTitanLib.type[artInfo.type].levels[level + 1].cost;
  11508.  
  11509. const costCurrency = Object.keys(costNextLevel).pop();
  11510. let costValue = 0;
  11511. let currentValue = 0;
  11512. if (costCurrency == 'gold') {
  11513. costValue = costNextLevel[costCurrency];
  11514. currentValue = userInfo.gold;
  11515. } else {
  11516. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  11517. const costId = costValues[0];
  11518. costValue = +costValues[1];
  11519. currentValue = inventory[costCurrency][costId];
  11520. }
  11521.  
  11522. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  11523. if (level < upArt.level && currentValue >= costValue) {
  11524. upArt.level = level;
  11525. upArt.titanId = titan.id;
  11526. upArt.slotId = slotId;
  11527. break;
  11528. }
  11529. }
  11530. }
  11531. return upArt;
  11532. }
  11533.  
  11534. getEnchantRune() {
  11535. const heroes = Object.values(this.questInfo['heroGetAll']);
  11536. const inventory = this.questInfo['inventoryGet'];
  11537. const enchRune = { heroId: 0, tier: 0, exp: 43750, itemId: 0 };
  11538. for (let i = 1; i <= 4; i++) {
  11539. if (inventory.consumable[i] > 0) {
  11540. enchRune.itemId = i;
  11541. break;
  11542. }
  11543. return enchRune;
  11544. }
  11545.  
  11546. const runeLib = lib.getData('rune');
  11547. const runeLvls = Object.values(runeLib.level);
  11548. /**
  11549. * color - 4 (синий) открывает 1 и 2 символ
  11550. * color - 7 (фиолетовый) открывает 3 символ
  11551. * color - 8 (фиолетовый +1) открывает 4 символ
  11552. * color - 9 (фиолетовый +2) открывает 5 символ
  11553. */
  11554. // TODO: кажется надо учесть уровень команды
  11555. const colors = [4, 4, 7, 8, 9];
  11556. for (const hero of heroes) {
  11557. const color = hero.color;
  11558.  
  11559.  
  11560. for (let runeTier in hero.runes) {
  11561. /* Проверка на доступность руны */
  11562. if (color < colors[runeTier]) {
  11563. continue;
  11564. }
  11565. /* Текущий опыт руны */
  11566. const exp = hero.runes[runeTier];
  11567. if (exp >= 43750) {
  11568. continue;
  11569. }
  11570.  
  11571. let level = 0;
  11572. if (exp) {
  11573. for (let lvl of runeLvls) {
  11574. if (exp >= lvl.enchantValue) {
  11575. level = lvl.level;
  11576. } else {
  11577. break;
  11578. }
  11579. }
  11580. }
  11581. /** Уровень героя необходимый для уровня руны */
  11582. const heroLevel = runeLib.level[level].heroLevel;
  11583. if (hero.level < heroLevel) {
  11584. continue;
  11585. }
  11586.  
  11587. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  11588. if (exp < enchRune.exp) {
  11589. enchRune.exp = exp;
  11590. enchRune.heroId = hero.id;
  11591. enchRune.tier = runeTier;
  11592. break;
  11593. }
  11594. }
  11595. }
  11596. return enchRune;
  11597. }
  11598.  
  11599. getOutlandChest() {
  11600. const bosses = this.questInfo['bossGetAll'];
  11601.  
  11602. const calls = [];
  11603.  
  11604. for (let boss of bosses) {
  11605. if (boss.mayRaid) {
  11606. calls.push({
  11607. name: 'bossRaid',
  11608. args: {
  11609. bossId: boss.id,
  11610. },
  11611. ident: 'bossRaid_' + boss.id,
  11612. });
  11613. calls.push({
  11614. name: 'bossOpenChest',
  11615. args: {
  11616. bossId: boss.id,
  11617. amount: 1,
  11618. starmoney: 0,
  11619. },
  11620. ident: 'bossOpenChest_' + boss.id,
  11621. });
  11622. } else if (boss.chestId == 1) {
  11623. calls.push({
  11624. name: 'bossOpenChest',
  11625. args: {
  11626. bossId: boss.id,
  11627. amount: 1,
  11628. starmoney: 0,
  11629. },
  11630. ident: 'bossOpenChest_' + boss.id,
  11631. });
  11632. }
  11633. }
  11634.  
  11635. return calls;
  11636. }
  11637.  
  11638. getExpHero() {
  11639. const heroes = Object.values(this.questInfo['heroGetAll']);
  11640. const inventory = this.questInfo['inventoryGet'];
  11641. const expHero = { heroId: 0, exp: 3625195, libId: 0 };
  11642. /** зелья опыта (consumable 9, 10, 11, 12) */
  11643. for (let i = 9; i <= 12; i++) {
  11644. if (inventory.consumable[i]) {
  11645. expHero.libId = i;
  11646. break;
  11647. }
  11648. }
  11649.  
  11650. for (const hero of heroes) {
  11651. const exp = hero.xp;
  11652. if (exp < expHero.exp) {
  11653. expHero.heroId = hero.id;
  11654. }
  11655. }
  11656. return expHero;
  11657. }
  11658.  
  11659. getHeroIdTitanGift() {
  11660. const heroes = Object.values(this.questInfo['heroGetAll']);
  11661. const inventory = this.questInfo['inventoryGet'];
  11662. const user = this.questInfo['userGetInfo'];
  11663. const titanGiftLib = lib.getData('titanGift');
  11664. /** Искры */
  11665. const titanGift = inventory.consumable[24];
  11666. let heroId = 0;
  11667. let minLevel = 30;
  11668.  
  11669. if (titanGift < 250 || user.gold < 7000) {
  11670. return 0;
  11671. }
  11672.  
  11673. for (const hero of heroes) {
  11674. if (hero.titanGiftLevel >= 30) {
  11675. continue;
  11676. }
  11677.  
  11678. if (!hero.titanGiftLevel) {
  11679. return hero.id;
  11680. }
  11681.  
  11682. const cost = titanGiftLib[hero.titanGiftLevel].cost;
  11683. if (minLevel > hero.titanGiftLevel && titanGift >= cost.consumable[24] && user.gold >= cost.gold) {
  11684. minLevel = hero.titanGiftLevel;
  11685. heroId = hero.id;
  11686. }
  11687. }
  11688.  
  11689. return heroId;
  11690. }
  11691.  
  11692. getHeroicMissionId() {
  11693. // Получаем доступные миссии с 3 звездами
  11694. const availableMissionsToRaid = Object.values(this.questInfo.missionGetAll)
  11695. .filter((mission) => mission.stars === 3)
  11696. .map((mission) => mission.id);
  11697.  
  11698. // Получаем героев для улучшения, у которых меньше 6 звезд
  11699. const heroesToUpgrade = Object.values(this.questInfo.heroGetAll)
  11700. .filter((hero) => hero.star < 6)
  11701. .sort((a, b) => b.power - a.power)
  11702. .map((hero) => hero.id);
  11703.  
  11704. // Получаем героические миссии, которые доступны для рейдов
  11705. const heroicMissions = Object.values(lib.data.mission).filter((mission) => mission.isHeroic && availableMissionsToRaid.includes(mission.id));
  11706.  
  11707. // Собираем дропы из героических миссий
  11708. const drops = heroicMissions.map((mission) => {
  11709. const lastWave = mission.normalMode.waves[mission.normalMode.waves.length - 1];
  11710. const allRewards = lastWave.enemies[lastWave.enemies.length - 1]
  11711. .drop.map((drop) => drop.reward);
  11712.  
  11713. const heroId = +Object.keys(allRewards.find((reward) => reward.fragmentHero).fragmentHero).pop();
  11714.  
  11715. return { id: mission.id, heroId };
  11716. });
  11717.  
  11718. // Определяем, какие дропы подходят для героев, которых нужно улучшить
  11719. const heroDrops = heroesToUpgrade.map((heroId) => drops.find((drop) => drop.heroId == heroId)).filter((drop) => drop);
  11720. const firstMission = heroDrops[0];
  11721. // Выбираем миссию для рейда
  11722. const selectedMissionId = firstMission ? firstMission.id : 1;
  11723.  
  11724. const stamina = this.questInfo.userGetInfo.refillable.find((x) => x.id == 1).amount;
  11725. const costMissions = 3 * lib.data.mission[selectedMissionId].normalMode.teamExp;
  11726. if (stamina < costMissions) {
  11727. console.log('Энергии не достаточно');
  11728. return 0;
  11729. }
  11730. return selectedMissionId;
  11731. }
  11732.  
  11733. end(status) {
  11734. setProgress(status, true);
  11735. this.resolve();
  11736. }
  11737. }
  11738.  
  11739. this.questRun = dailyQuests;
  11740.  
  11741. function testDoYourBest() {
  11742. return new Promise((resolve, reject) => {
  11743. const doIt = new doYourBest(resolve, reject);
  11744. doIt.start();
  11745. });
  11746. }
  11747.  
  11748. /**
  11749. * Do everything button
  11750. *
  11751. * Кнопка сделать все
  11752. */
  11753. class doYourBest {
  11754.  
  11755. funcList = [
  11756. //собрать запределье
  11757. {
  11758. name: 'getOutland',
  11759. label: I18N('ASSEMBLE_OUTLAND'),
  11760. checked: false
  11761. },
  11762. //пройти башню
  11763. {
  11764. name: 'testTower',
  11765. label: I18N('PASS_THE_TOWER'),
  11766. checked: false
  11767. },
  11768. //экспедиции
  11769. {
  11770. name: 'checkExpedition',
  11771. label: I18N('CHECK_EXPEDITIONS'),
  11772. checked: false
  11773. },
  11774. //турнир стихий
  11775. {
  11776. name: 'testTitanArena',
  11777. label: I18N('COMPLETE_TOE'),
  11778. checked: false
  11779. },
  11780. //собрать почту
  11781. {
  11782. name: 'mailGetAll',
  11783. label: I18N('COLLECT_MAIL'),
  11784. checked: false
  11785. },
  11786. //Собрать всякую херню
  11787. {
  11788. name: 'collectAllStuff',
  11789. label: I18N('COLLECT_MISC'),
  11790. title: I18N('COLLECT_MISC_TITLE'),
  11791. checked: false
  11792. },
  11793. //ежедневная награда
  11794. {
  11795. name: 'getDailyBonus',
  11796. label: I18N('DAILY_BONUS'),
  11797. checked: false
  11798. },
  11799. //ежедневные квесты удалить наверно есть в настройках
  11800. {
  11801. name: 'dailyQuests',
  11802. label: I18N('DO_DAILY_QUESTS'),
  11803. checked: false
  11804. },
  11805. //Провидец
  11806. {
  11807. name: 'rollAscension',
  11808. label: I18N('SEER_TITLE'),
  11809. checked: false
  11810. },
  11811. //собрать награды за квесты
  11812. {
  11813. name: 'questAllFarm',
  11814. label: I18N('COLLECT_QUEST_REWARDS'),
  11815. checked: false
  11816. },
  11817. // тест отправь подарки согильдийцам
  11818. {
  11819. name: 'testclanSendDailyGifts',
  11820. label: I18N('QUEST_10016'),
  11821. checked: false
  11822. },
  11823. //получить подарки
  11824. /*{
  11825. name: 'getGift',
  11826. label: I18N('NY_GIFTS'),
  11827. checked: false
  11828. },*/
  11829. //собрать новогодние подарки
  11830. /*{
  11831. name: 'getGiftNewYear',
  11832. label: I18N('NY_GIFTS'),
  11833. checked: false
  11834. },*/
  11835. // тест сферу титанов
  11836. /*{
  11837. name: 'testtitanArtifactChestOpen',
  11838. label: I18N('QUEST_10029'),
  11839. checked: false
  11840. },
  11841. // тест призыв петов
  11842. {
  11843. name: 'testpet_chestOpen',
  11844. label: I18N('QUEST_10044'),
  11845. checked: false
  11846. },*/
  11847. //пройти подземелье обычное
  11848. {
  11849. name: 'testDungeon',
  11850. label: I18N('COMPLETE_DUNGEON'),
  11851. checked: false
  11852. },
  11853. //пройти подземелье для фуловых титанов
  11854. {
  11855. name: 'DungeonFull',
  11856. label: I18N('COMPLETE_DUNGEON_FULL'),
  11857. checked: false
  11858. },
  11859. //синхронизация
  11860. {
  11861. name: 'synchronization',
  11862. label: I18N('MAKE_A_SYNC'),
  11863. checked: false
  11864. },
  11865. //перезагрузка
  11866. {
  11867. name: 'reloadGame',
  11868. label: I18N('RELOAD_GAME'),
  11869. checked: false
  11870. },
  11871. ];
  11872.  
  11873. functions = {
  11874. getOutland,//собрать запределье
  11875. testTower,//прохождение башни
  11876. checkExpedition,//автоэкспедиции
  11877. testTitanArena,//Автопрохождение Турнира Стихий
  11878. mailGetAll,//Собрать всю почту, кроме писем с энергией и зарядами портала
  11879. //Собрать пасхалки, камни облика, ключи, монеты арены и Хрусталь души
  11880. collectAllStuff: async () => {
  11881. await offerFarmAllReward();
  11882. 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"}]}');
  11883. },
  11884. //Выполнять ежедневные квесты
  11885. dailyQuests: async function () {
  11886. const quests = new dailyQuests(() => { }, () => { });
  11887. await quests.autoInit(true);
  11888. await quests.start();
  11889. },
  11890. rollAscension,//провидец
  11891. getDailyBonus,//ежедневная награда
  11892. questAllFarm,//Собрать все награды за задания
  11893. testclanSendDailyGifts, //отправить подарки
  11894. /*getGift: async () => {
  11895. const collector = new GiftCodeCollector();
  11896. const giftCodes = await collector.getGiftCodes();
  11897. console.log(giftCodes);
  11898.  
  11899. for (const key of giftCodes)
  11900. send({ calls: [{ name: "registration", args: { giftId:key, user: { referrer: {} } },
  11901. context: { actionTs: Math.floor(performance.now()), cookie: window?.NXAppInfo?.session_id || null }, ident: "body" }] });
  11902. },*/
  11903. getGiftNewYear,//собрать новогодние подарки
  11904. testtitanArtifactChestOpen, //открой сферу титанов
  11905. testpet_chestOpen, //Воспользуйся призывом питомцев 1 раз
  11906. testDungeon,//подземка обычная
  11907. DungeonFull,//подземка для фуловых титанов
  11908. synchronization: async () => {
  11909. cheats.refreshGame();
  11910. },
  11911. reloadGame: async () => {
  11912. location.reload();
  11913. },
  11914. }
  11915.  
  11916. constructor(resolve, reject, questInfo) {
  11917. this.resolve = resolve;
  11918. this.reject = reject;
  11919. this.questInfo = questInfo
  11920. }
  11921.  
  11922. async start() {
  11923. const selectedDoIt = getSaveVal('selectedDoIt', {});
  11924.  
  11925. this.funcList.forEach(task => {
  11926. if (!selectedDoIt[task.name]) {
  11927. selectedDoIt[task.name] = {
  11928. checked: task.checked
  11929. }
  11930. } else {
  11931. task.checked = selectedDoIt[task.name].checked
  11932. }
  11933. });
  11934.  
  11935. const answer = await popup.confirm(I18N('RUN_FUNCTION'), [
  11936. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  11937. { msg: I18N('BTN_GO'), result: true },
  11938. ], this.funcList);
  11939.  
  11940. if (!answer) {
  11941. this.end('');
  11942. return;
  11943. }
  11944.  
  11945. const taskList = popup.getCheckBoxes();
  11946. taskList.forEach(task => {
  11947. selectedDoIt[task.name].checked = task.checked;
  11948. });
  11949. setSaveVal('selectedDoIt', selectedDoIt);
  11950. for (const task of popup.getCheckBoxes()) {
  11951. if (task.checked) {
  11952. try {
  11953. setProgress(`${task.label} <br>${I18N('PERFORMED')}!`);
  11954. await this.functions[task.name]();
  11955. setProgress(`${task.label} <br>${I18N('DONE')}!`);
  11956. } catch (error) {
  11957. if (await popup.confirm(`${I18N('ERRORS_OCCURRES')}:<br> ${task.label} <br>${I18N('COPY_ERROR')}?`, [
  11958. { msg: I18N('BTN_NO'), result: false },
  11959. { msg: I18N('BTN_YES'), result: true },
  11960. ])) {
  11961. this.errorHandling(error);
  11962. }
  11963. }
  11964. }
  11965. }
  11966. setTimeout((msg) => {
  11967. this.end(msg);
  11968. }, 2000, I18N('ALL_TASK_COMPLETED'));
  11969. return;
  11970. }
  11971.  
  11972. errorHandling(error) {
  11973. //console.error(error);
  11974. let errorInfo = error.toString() + '\n';
  11975. try {
  11976. const errorStack = error.stack.split('\n');
  11977. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  11978. errorInfo += errorStack.slice(0, endStack).join('\n');
  11979. } catch (e) {
  11980. errorInfo += error.stack;
  11981. }
  11982. copyText(errorInfo);
  11983. }
  11984.  
  11985. end(status) {
  11986. setProgress(status, true);
  11987. this.resolve();
  11988. }
  11989. }
  11990.  
  11991. /**
  11992. * Passing the adventure along the specified route
  11993. *
  11994. * Прохождение приключения по указанному маршруту
  11995. */
  11996. function testAdventure(type) {
  11997. return new Promise((resolve, reject) => {
  11998. const bossBattle = new executeAdventure(resolve, reject);
  11999. bossBattle.start(type);
  12000. });
  12001. }
  12002.  
  12003. //Буря
  12004. function testAdventure2(solo) {
  12005. return new Promise((resolve, reject) => {
  12006. const bossBattle = new executeAdventure2(resolve, reject);
  12007. bossBattle.start(solo);
  12008. });
  12009. }
  12010.  
  12011. /**
  12012. * Passing the adventure along the specified route
  12013. *
  12014. * Прохождение приключения по указанному маршруту
  12015. */
  12016. class executeAdventure {
  12017.  
  12018. type = 'default';
  12019.  
  12020. actions = {
  12021. default: {
  12022. getInfo: "adventure_getInfo",
  12023. startBattle: 'adventure_turnStartBattle',
  12024. endBattle: 'adventure_endBattle',
  12025. collectBuff: 'adventure_turnCollectBuff'
  12026. },
  12027. solo: {
  12028. getInfo: "adventureSolo_getInfo",
  12029. startBattle: 'adventureSolo_turnStartBattle',
  12030. endBattle: 'adventureSolo_endBattle',
  12031. collectBuff: 'adventureSolo_turnCollectBuff'
  12032. }
  12033. }
  12034.  
  12035. terminatеReason = I18N('UNKNOWN');
  12036. callAdventureInfo = {
  12037. name: "adventure_getInfo",
  12038. args: {},
  12039. ident: "adventure_getInfo"
  12040. }
  12041. callTeamGetAll = {
  12042. name: "teamGetAll",
  12043. args: {},
  12044. ident: "teamGetAll"
  12045. }
  12046. callTeamGetFavor = {
  12047. name: "teamGetFavor",
  12048. args: {},
  12049. ident: "teamGetFavor"
  12050. }
  12051. //тест прикла
  12052. defaultWays = {
  12053. //Галахад, 1-я
  12054. "adv_strongford_2pl_easy": {
  12055. first: '1,2,3,5,6',
  12056. second: '1,2,4,7,6',
  12057. third: '1,2,3,5,6'
  12058. },
  12059. //Джинджер, 2-я
  12060. "adv_valley_3pl_easy": {
  12061. first: '1,2,5,8,9,11',
  12062. second: '1,3,6,9,11',
  12063. third: '1,4,7,10,9,11'
  12064. },
  12065. //Орион, 3-я
  12066. "adv_ghirwil_3pl_easy": {
  12067. first: '1,5,6,9,11',
  12068. second: '1,4,12,13,11',
  12069. third: '1,2,3,7,10,11'
  12070. },
  12071. //Тесак, 4-я
  12072. "adv_angels_3pl_easy_fire": {
  12073. first: '1,2,4,7,18,8,12,19,22,23',
  12074. second: '1,3,6,11,17,10,16,21,22,23',
  12075. third: '1,5,24,25,9,14,15,20,22,23'
  12076. },
  12077. //Галахад, 5-я
  12078. "adv_strongford_3pl_normal_2": {
  12079. first: '1,2,7,8,12,16,23,26,25,21,24',
  12080. second: '1,4,6,10,11,15,22,15,19,18,24',
  12081. third: '1,5,9,10,14,17,20,27,25,21,24'
  12082. },
  12083. //Джинджер, 6-я
  12084. "adv_valley_3pl_normal": {
  12085. first: '1,2,4,7,10,13,16,19,24,22,25',
  12086. second: '1,3,6,9,12,15,18,21,26,23,25',
  12087. third: '1,5,7,8,11,14,17,20,22,25'
  12088. },
  12089. //Орион, 7-я
  12090. "adv_ghirwil_3pl_normal_2": {
  12091. first: '1,11,10,11,12,15,12,11,21,25,27',
  12092. second: '1,7,3,4,3,6,13,19,20,24,27',
  12093. third: '1,8,5,9,16,23,22,26,27'
  12094. },
  12095. //Тесак, 8-я
  12096. "adv_angels_3pl_normal": {
  12097. first: '1,3,4,8,7,9,10,13,17,16,20,22,23,31,32',
  12098. second: '1,3,5,7,8,11,14,18,20,22,24,27,30,26,32',
  12099. third: '1,3,2,6,7,9,11,15,19,20,22,21,28,29,25'
  12100. },
  12101. //Галахад, 9-я
  12102. "adv_strongford_3pl_hard_2": {
  12103. first: '1,2,6,10,15,7,16,17,23,22,27,32,35,37,40,45',
  12104. second: '1,3,8,12,11,18,19,28,34,33,38,41,43,46,45',
  12105. third: '1,2,5,9,14,20,26,21,30,36,39,42,44,45'
  12106. },
  12107. //Джинджер, 10-я
  12108. "adv_valley_3pl_hard": {
  12109. first: '1,3,2,6,11,17,25,30,35,34,29,24,21,17,12,7',
  12110. second: '1,4,8,13,18,22,26,31,36,40,45,44,43,38,33,28',
  12111. third: '1,5,9,14,19,23,27,32,37,42,48,51,50,49,46,52'
  12112. },
  12113. //Орион, 11-я
  12114. "adv_ghirwil_3pl_hard": {
  12115. first: '1,2,3,6,8,12,11,15,21,27,36,34,33,35,37',
  12116. second: '1,2,4,6,9,13,18,17,16,22,28,29,30,31,25,19',
  12117. third: '1,2,5,6,10,13,14,20,26,32,38,41,40,39,37'
  12118. },
  12119. //Тесак, 12-я
  12120. "adv_angels_3pl_hard": {
  12121. first: '1,2,8,11,7,4,7,16,23,32,33,25,34,29,35,36',
  12122. second: '1,3,9,13,10,6,10,22,31,30,21,30,15,28,20,27',
  12123. third: '1,5,12,14,24,17,24,25,26,18,19,20,27'
  12124. },
  12125. //Тесак, 13-я
  12126. "adv_angels_3pl_hell": {
  12127. first: '1,2,4,6,16,23,33,34,25,32,29,28,20,27',
  12128. second: '1,7,11,17,24,14,26,18,19,20,27,20,12,8',
  12129. third: '1,9,3,5,10,22,31,36,31,30,15,28,29,30,21,13'
  12130. },
  12131. //Галахад, 13-я
  12132. "adv_strongford_3pl_hell": {
  12133. first: '1,2,5,11,14,20,26,21,30,35,38,41,43,44',
  12134. second: '1,2,6,12,15,7,16,17,23,22,27,42,34,36,39,44',
  12135. third: '1,3,8,9,13,18,19,28,0,33,37,40,32,45,44'
  12136. },
  12137. //Орион, 13-я
  12138. "adv_ghirwil_3pl_hell": {
  12139. first: '1,2,3,6,8,12,11,15,21,27,36,34,33,35,37',
  12140. second: '1,2,4,6,9,13,18,17,16,22,28,29,30,31,25,19',
  12141. third: '1,2,5,6,10,13,14,20,26,32,38,41,40,39,37'
  12142. },
  12143. //Джинджер, 13-я
  12144. "adv_valley_3pl_hell": {
  12145. first: '1,3,2,6,11,17,25,30,35,34,29,24,21,17,12,7',
  12146. second: '1,4,8,13,18,22,26,31,36,40,45,44,43,38,33,28',
  12147. third: '1,5,9,14,19,23,27,32,37,42,48,51,50,49,46,52'
  12148. }
  12149. }
  12150. callStartBattle = {
  12151. name: "adventure_turnStartBattle",
  12152. args: {},
  12153. ident: "body"
  12154. }
  12155. callEndBattle = {
  12156. name: "adventure_endBattle",
  12157. args: {
  12158. result: {},
  12159. progress: {},
  12160. },
  12161. ident: "body"
  12162. }
  12163. callCollectBuff = {
  12164. name: "adventure_turnCollectBuff",
  12165. args: {},
  12166. ident: "body"
  12167. }
  12168.  
  12169. constructor(resolve, reject) {
  12170. this.resolve = resolve;
  12171. this.reject = reject;
  12172. }
  12173.  
  12174. async start(type) {
  12175. //this.type = type || this.type;
  12176. //this.callAdventureInfo.name = this.actions[this.type].getInfo;
  12177. const data = await Send(JSON.stringify({
  12178. calls: [
  12179. this.callAdventureInfo,
  12180. this.callTeamGetAll,
  12181. this.callTeamGetFavor
  12182. ]
  12183. }));
  12184. //тест прикла1
  12185. this.path = await this.getPath(data.results[0].result.response.mapIdent);
  12186. if (!this.path) {
  12187. this.end();
  12188. return;
  12189. }
  12190. return this.checkAdventureInfo(data.results);
  12191. }
  12192.  
  12193. async getPath(mapId) {
  12194. //const oldVal = getSaveVal('adventurePath', '');
  12195. //const keyPath = `adventurePath:${this.mapIdent}`;
  12196. const answer = await popup.confirm(I18N('ENTER_THE_PATH'), [
  12197. {
  12198. msg: I18N('START_ADVENTURE'),
  12199. placeholder: '1,2,3,4,5,6',
  12200. isInput: true,
  12201. //default: getSaveVal(keyPath, oldVal)
  12202. default: getSaveVal('adventurePath', '')
  12203. },
  12204. {
  12205. msg: ' Начать по пути №1! ',
  12206. placeholder: '1,2,3',
  12207. isInput: true,
  12208. default: this.defaultWays[mapId]?.first
  12209. },
  12210. {
  12211. msg: ' Начать по пути №2! ',
  12212. placeholder: '1,2,3',
  12213. isInput: true,
  12214. default: this.defaultWays[mapId]?.second
  12215. },
  12216. {
  12217. msg: ' Начать по пути №3! ',
  12218. placeholder: '1,2,3',
  12219. isInput: true,
  12220. default: this.defaultWays[mapId]?.third
  12221. },
  12222. {
  12223. msg: I18N('BTN_CANCEL'),
  12224. result: false,
  12225. isCancel: true
  12226. },
  12227. ]);
  12228. if (!answer) {
  12229. this.terminatеReason = I18N('BTN_CANCELED');
  12230. return false;
  12231. }
  12232.  
  12233. let path = answer.split(',');
  12234. if (path.length < 2) {
  12235. path = answer.split('-');
  12236. }
  12237. if (path.length < 2) {
  12238. this.terminatеReason = I18N('MUST_TWO_POINTS');
  12239. return false;
  12240. }
  12241.  
  12242. for (let p in path) {
  12243. path[p] = +path[p].trim()
  12244. if (Number.isNaN(path[p])) {
  12245. this.terminatеReason = I18N('MUST_ONLY_NUMBERS');
  12246. return false;
  12247. }
  12248. }
  12249.  
  12250. /*if (!this.checkPath(path)) {
  12251. return false;
  12252. }*/
  12253. //setSaveVal(keyPath, answer);
  12254. setSaveVal('adventurePath', answer);
  12255. return path;
  12256. }
  12257. /*
  12258. checkPath(path) {
  12259. for (let i = 0; i < path.length - 1; i++) {
  12260. const currentPoint = path[i];
  12261. const nextPoint = path[i + 1];
  12262.  
  12263. const isValidPath = this.paths.some(p =>
  12264. (p.from_id === currentPoint && p.to_id === nextPoint) ||
  12265. (p.from_id === nextPoint && p.to_id === currentPoint)
  12266. );
  12267.  
  12268. if (!isValidPath) {
  12269. this.terminatеReason = I18N('INCORRECT_WAY', {
  12270. from: currentPoint,
  12271. to: nextPoint,
  12272. });
  12273. return false;
  12274. }
  12275. }
  12276.  
  12277. return true;
  12278. }
  12279. */
  12280. async checkAdventureInfo(data) {
  12281. this.advInfo = data[0].result.response;
  12282. if (!this.advInfo) {
  12283. this.terminatеReason = I18N('NOT_ON_AN_ADVENTURE') ;
  12284. return this.end();
  12285. }
  12286. const heroesTeam = data[1].result.response.adventure_hero;
  12287. const favor = data[2]?.result.response.adventure_hero;
  12288. const heroes = heroesTeam.slice(0, 5);
  12289. const pet = heroesTeam[5];
  12290. this.args = {
  12291. pet,
  12292. heroes,
  12293. favor,
  12294. path: [],
  12295. broadcast: false
  12296. }
  12297. const advUserInfo = this.advInfo.users[userInfo.id];
  12298. this.turnsLeft = advUserInfo.turnsLeft;
  12299. this.currentNode = advUserInfo.currentNode;
  12300. this.nodes = this.advInfo.nodes;
  12301. //this.paths = this.advInfo.paths;
  12302. //this.mapIdent = this.advInfo.mapIdent;
  12303.  
  12304. /*this.path = await this.getPath();
  12305. if (!this.path) {
  12306. return this.end();
  12307. }*/
  12308.  
  12309. if (this.currentNode == 1 && this.path[0] != 1) {
  12310. this.path.unshift(1);
  12311. }
  12312.  
  12313. return this.loop();
  12314. }
  12315.  
  12316. async loop() {
  12317. const position = this.path.indexOf(+this.currentNode);
  12318. if (!(~position)) {
  12319. this.terminatеReason = I18N('YOU_IN_NOT_ON_THE_WAY');
  12320. return this.end();
  12321. }
  12322. this.path = this.path.slice(position);
  12323. if ((this.path.length - 1) > this.turnsLeft &&
  12324. await popup.confirm(I18N('ATTEMPTS_NOT_ENOUGH'), [
  12325. { msg: I18N('YES_CONTINUE'), result: false },
  12326. { msg: I18N('BTN_NO'), result: true },
  12327. ])) {
  12328. this.terminatеReason = I18N('NOT_ENOUGH_AP');
  12329. return this.end();
  12330. }
  12331. const toPath = [];
  12332. for (const nodeId of this.path) {
  12333. if (!this.turnsLeft) {
  12334. this.terminatеReason = I18N('ATTEMPTS_ARE_OVER');
  12335. return this.end();
  12336. }
  12337. toPath.push(nodeId);
  12338. console.log(toPath);
  12339. if (toPath.length > 1) {
  12340. setProgress(toPath.join(' > ') + ` ${I18N('MOVES')}: ` + this.turnsLeft);
  12341. }
  12342. if (nodeId == this.currentNode) {
  12343. continue;
  12344. }
  12345.  
  12346. const nodeInfo = this.getNodeInfo(nodeId);
  12347. if (nodeInfo.type == 'TYPE_COMBAT') {
  12348. if (nodeInfo.state == 'empty') {
  12349. this.turnsLeft--;
  12350. continue;
  12351. }
  12352.  
  12353. /**
  12354. * Disable regular battle cancellation
  12355. *
  12356. * Отключаем штатную отменую боя
  12357. */
  12358. isCancalBattle = false;
  12359. if (await this.battle(toPath)) {
  12360. this.turnsLeft--;
  12361. toPath.splice(0, toPath.indexOf(nodeId));
  12362. nodeInfo.state = 'empty';
  12363. isCancalBattle = true;
  12364. continue;
  12365. }
  12366. isCancalBattle = true;
  12367. return this.end()
  12368. }
  12369.  
  12370. if (nodeInfo.type == 'TYPE_PLAYERBUFF') {
  12371. const buff = this.checkBuff(nodeInfo);
  12372. if (buff == null) {
  12373. continue;
  12374. }
  12375.  
  12376. if (await this.collectBuff(buff, toPath)) {
  12377. this.turnsLeft--;
  12378. toPath.splice(0, toPath.indexOf(nodeId));
  12379. continue;
  12380. }
  12381. this.terminatеReason = I18N('BUFF_GET_ERROR');
  12382. return this.end();
  12383. }
  12384. }
  12385. this.terminatеReason = I18N('SUCCESS');
  12386. return this.end();
  12387. }
  12388.  
  12389. /**
  12390. * Carrying out a fight
  12391. *
  12392. * Проведение боя
  12393. */
  12394. async battle(path, preCalc = true) {
  12395. const data = await this.startBattle(path);
  12396. try {
  12397. const battle = data.results[0].result.response.battle;
  12398. const result = await Calc(battle);
  12399. if (result.result.win) {
  12400. const info = await this.endBattle(result);
  12401. if (info.results[0].result.response?.error) {
  12402. this.terminatеReason = I18N('BATTLE_END_ERROR');
  12403. return false;
  12404. }
  12405. } else {
  12406. await this.cancelBattle(result);
  12407.  
  12408. if (preCalc && await this.preCalcBattle(battle)) {
  12409. path = path.slice(-2);
  12410. for (let i = 1; i <= getInput('countAutoBattle'); i++) {
  12411. setProgress(`${I18N('AUTOBOT')}: ${i}/${getInput('countAutoBattle')}`);
  12412. const result = await this.battle(path, false);
  12413. if (result) {
  12414. setProgress(I18N('VICTORY'));
  12415. return true;
  12416. }
  12417. }
  12418. this.terminatеReason = I18N('FAILED_TO_WIN_AUTO');
  12419. return false;
  12420. }
  12421. return false;
  12422. }
  12423. } catch (error) {
  12424. console.error(error);
  12425. if (await popup.confirm(I18N('ERROR_OF_THE_BATTLE_COPY'), [
  12426. { msg: I18N('BTN_NO'), result: false },
  12427. { msg: I18N('BTN_YES'), result: true },
  12428. ])) {
  12429. this.errorHandling(error, data);
  12430. }
  12431. this.terminatеReason = I18N('ERROR_DURING_THE_BATTLE');
  12432. return false;
  12433. }
  12434. return true;
  12435. }
  12436.  
  12437. /**
  12438. * Recalculate battles
  12439. *
  12440. * Прерасчтет битвы
  12441. */
  12442. async preCalcBattle(battle) {
  12443. const countTestBattle = getInput('countTestBattle');
  12444. for (let i = 0; i < countTestBattle; i++) {
  12445. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  12446. const result = await Calc(battle);
  12447. if (result.result.win) {
  12448. console.log(i, countTestBattle);
  12449. return true;
  12450. }
  12451. }
  12452. this.terminatеReason = I18N('NO_CHANCE_WIN') + countTestBattle;
  12453. return false;
  12454. }
  12455.  
  12456. /**
  12457. * Starts a fight
  12458. *
  12459. * Начинает бой
  12460. */
  12461. startBattle(path) {
  12462. this.args.path = path;
  12463. this.callStartBattle.name = this.actions[this.type].startBattle;
  12464. this.callStartBattle.args = this.args
  12465. const calls = [this.callStartBattle];
  12466. return Send(JSON.stringify({ calls }));
  12467. }
  12468.  
  12469. cancelBattle(battle) {
  12470. const fixBattle = function (heroes) {
  12471. for (const ids in heroes) {
  12472. const hero = heroes[ids];
  12473. hero.energy = random(1, 999);
  12474. if (hero.hp > 0) {
  12475. hero.hp = random(1, hero.hp);
  12476. }
  12477. }
  12478. }
  12479. fixBattle(battle.progress[0].attackers.heroes);
  12480. fixBattle(battle.progress[0].defenders.heroes);
  12481. return this.endBattle(battle);
  12482. }
  12483.  
  12484. /**
  12485. * Ends the fight
  12486. *
  12487. * Заканчивает бой
  12488. */
  12489. endBattle(battle) {
  12490. this.callEndBattle.name = this.actions[this.type].endBattle;
  12491. this.callEndBattle.args.result = battle.result
  12492. this.callEndBattle.args.progress = battle.progress
  12493. const calls = [this.callEndBattle];
  12494. return Send(JSON.stringify({ calls }));
  12495. }
  12496.  
  12497. /**
  12498. * Checks if you can get a buff
  12499. *
  12500. * Проверяет можно ли получить баф
  12501. */
  12502. checkBuff(nodeInfo) {
  12503. let id = null;
  12504. let value = 0;
  12505. for (const buffId in nodeInfo.buffs) {
  12506. const buff = nodeInfo.buffs[buffId];
  12507. if (buff.owner == null && buff.value > value) {
  12508. id = buffId;
  12509. value = buff.value;
  12510. }
  12511. }
  12512. nodeInfo.buffs[id].owner = 'Я';
  12513. return id;
  12514. }
  12515.  
  12516. /**
  12517. * Collects a buff
  12518. *
  12519. * Собирает баф
  12520. */
  12521. async collectBuff(buff, path) {
  12522. this.callCollectBuff.name = this.actions[this.type].collectBuff;
  12523. this.callCollectBuff.args = { buff, path };
  12524. const calls = [this.callCollectBuff];
  12525. return Send(JSON.stringify({ calls }));
  12526. }
  12527.  
  12528. getNodeInfo(nodeId) {
  12529. return this.nodes.find(node => node.id == nodeId);
  12530. }
  12531.  
  12532. errorHandling(error, data) {
  12533. //console.error(error);
  12534. let errorInfo = error.toString() + '\n';
  12535. try {
  12536. const errorStack = error.stack.split('\n');
  12537. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testAdventure");
  12538. errorInfo += errorStack.slice(0, endStack).join('\n');
  12539. } catch (e) {
  12540. errorInfo += error.stack;
  12541. }
  12542. if (data) {
  12543. errorInfo += '\nData: ' + JSON.stringify(data);
  12544. }
  12545. copyText(errorInfo);
  12546. }
  12547.  
  12548. end() {
  12549. isCancalBattle = true;
  12550. setProgress(this.terminatеReason, true);
  12551. console.log(this.terminatеReason);
  12552. this.resolve();
  12553. }
  12554. }
  12555. class executeAdventure2 {
  12556.  
  12557. type = 'default';
  12558.  
  12559. actions = {
  12560. default: {
  12561. getInfo: "adventure_getInfo",
  12562. startBattle: 'adventure_turnStartBattle',
  12563. endBattle: 'adventure_endBattle',
  12564. collectBuff: 'adventure_turnCollectBuff'
  12565. },
  12566. solo: {
  12567. getInfo: "adventureSolo_getInfo",
  12568. startBattle: 'adventureSolo_turnStartBattle',
  12569. endBattle: 'adventureSolo_endBattle',
  12570. collectBuff: 'adventureSolo_turnCollectBuff'
  12571. }
  12572. }
  12573.  
  12574. terminatеReason = I18N('UNKNOWN');
  12575. callAdventureInfo = {
  12576. name: "adventure_getInfo",
  12577. args: {},
  12578. ident: "adventure_getInfo"
  12579. }
  12580. callTeamGetAll = {
  12581. name: "teamGetAll",
  12582. args: {},
  12583. ident: "teamGetAll"
  12584. }
  12585. callTeamGetFavor = {
  12586. name: "teamGetFavor",
  12587. args: {},
  12588. ident: "teamGetFavor"
  12589. }
  12590. callStartBattle = {
  12591. name: "adventure_turnStartBattle",
  12592. args: {},
  12593. ident: "body"
  12594. }
  12595. callEndBattle = {
  12596. name: "adventure_endBattle",
  12597. args: {
  12598. result: {},
  12599. progress: {},
  12600. },
  12601. ident: "body"
  12602. }
  12603. callCollectBuff = {
  12604. name: "adventure_turnCollectBuff",
  12605. args: {},
  12606. ident: "body"
  12607. }
  12608.  
  12609. constructor(resolve, reject) {
  12610. this.resolve = resolve;
  12611. this.reject = reject;
  12612. }
  12613.  
  12614. async start(type) {
  12615. this.type = type || this.type;
  12616. this.callAdventureInfo.name = this.actions[this.type].getInfo;
  12617. const data = await Send(JSON.stringify({
  12618. calls: [
  12619. this.callAdventureInfo,
  12620. this.callTeamGetAll,
  12621. this.callTeamGetFavor
  12622. ]
  12623. }));
  12624. return this.checkAdventureInfo(data.results);
  12625. }
  12626.  
  12627. async getPath() {
  12628. const oldVal = getSaveVal('adventurePath', '');
  12629. const keyPath = `adventurePath:${this.mapIdent}`;
  12630. const answer = await popup.confirm(I18N('ENTER_THE_PATH'), [
  12631. {
  12632. msg: I18N('START_ADVENTURE'),
  12633. placeholder: '1,2,3,4,5,6',
  12634. isInput: true,
  12635. default: getSaveVal(keyPath, oldVal)
  12636. },
  12637. {
  12638. msg: I18N('BTN_CANCEL'),
  12639. result: false,
  12640. isCancel: true
  12641. },
  12642. ]);
  12643. if (!answer) {
  12644. this.terminatеReason = I18N('BTN_CANCELED');
  12645. return false;
  12646. }
  12647.  
  12648. let path = answer.split(',');
  12649. if (path.length < 2) {
  12650. path = answer.split('-');
  12651. }
  12652. if (path.length < 2) {
  12653. this.terminatеReason = I18N('MUST_TWO_POINTS');
  12654. return false;
  12655. }
  12656.  
  12657. for (let p in path) {
  12658. path[p] = +path[p].trim()
  12659. if (Number.isNaN(path[p])) {
  12660. this.terminatеReason = I18N('MUST_ONLY_NUMBERS');
  12661. return false;
  12662. }
  12663. }
  12664. if (!this.checkPath(path)) {
  12665. return false;
  12666. }
  12667. setSaveVal(keyPath, answer);
  12668. return path;
  12669. }
  12670.  
  12671. checkPath(path) {
  12672. for (let i = 0; i < path.length - 1; i++) {
  12673. const currentPoint = path[i];
  12674. const nextPoint = path[i + 1];
  12675.  
  12676. const isValidPath = this.paths.some(p =>
  12677. (p.from_id === currentPoint && p.to_id === nextPoint) ||
  12678. (p.from_id === nextPoint && p.to_id === currentPoint)
  12679. );
  12680.  
  12681. if (!isValidPath) {
  12682. this.terminatеReason = I18N('INCORRECT_WAY', {
  12683. from: currentPoint,
  12684. to: nextPoint,
  12685. });
  12686. return false;
  12687. }
  12688. }
  12689.  
  12690. return true;
  12691. }
  12692.  
  12693. async checkAdventureInfo(data) {
  12694. this.advInfo = data[0].result.response;
  12695. if (!this.advInfo) {
  12696. this.terminatеReason = I18N('NOT_ON_AN_ADVENTURE') ;
  12697. return this.end();
  12698. }
  12699. const heroesTeam = data[1].result.response.adventure_hero;
  12700. const favor = data[2]?.result.response.adventure_hero;
  12701. const heroes = heroesTeam.slice(0, 5);
  12702. const pet = heroesTeam[5];
  12703. this.args = {
  12704. pet,
  12705. heroes,
  12706. favor,
  12707. path: [],
  12708. broadcast: false
  12709. }
  12710. const advUserInfo = this.advInfo.users[userInfo.id];
  12711. this.turnsLeft = advUserInfo.turnsLeft;
  12712. this.currentNode = advUserInfo.currentNode;
  12713. this.nodes = this.advInfo.nodes;
  12714. this.paths = this.advInfo.paths;
  12715. this.mapIdent = this.advInfo.mapIdent;
  12716.  
  12717. this.path = await this.getPath();
  12718. if (!this.path) {
  12719. return this.end();
  12720. }
  12721.  
  12722. if (this.currentNode == 1 && this.path[0] != 1) {
  12723. this.path.unshift(1);
  12724. }
  12725.  
  12726. return this.loop();
  12727. }
  12728.  
  12729. async loop() {
  12730. const position = this.path.indexOf(+this.currentNode);
  12731. if (!(~position)) {
  12732. this.terminatеReason = I18N('YOU_IN_NOT_ON_THE_WAY');
  12733. return this.end();
  12734. }
  12735. this.path = this.path.slice(position);
  12736. if ((this.path.length - 1) > this.turnsLeft &&
  12737. await popup.confirm(I18N('ATTEMPTS_NOT_ENOUGH'), [
  12738. { msg: I18N('YES_CONTINUE'), result: false },
  12739. { msg: I18N('BTN_NO'), result: true },
  12740. ])) {
  12741. this.terminatеReason = I18N('NOT_ENOUGH_AP');
  12742. return this.end();
  12743. }
  12744. const toPath = [];
  12745. for (const nodeId of this.path) {
  12746. if (!this.turnsLeft) {
  12747. this.terminatеReason = I18N('ATTEMPTS_ARE_OVER');
  12748. return this.end();
  12749. }
  12750. toPath.push(nodeId);
  12751. console.log(toPath);
  12752. if (toPath.length > 1) {
  12753. setProgress(toPath.join(' > ') + ` ${I18N('MOVES')}: ` + this.turnsLeft);
  12754. }
  12755. if (nodeId == this.currentNode) {
  12756. continue;
  12757. }
  12758.  
  12759. const nodeInfo = this.getNodeInfo(nodeId);
  12760. if (nodeInfo.type == 'TYPE_COMBAT') {
  12761. if (nodeInfo.state == 'empty') {
  12762. this.turnsLeft--;
  12763. continue;
  12764. }
  12765.  
  12766. /**
  12767. * Disable regular battle cancellation
  12768. *
  12769. * Отключаем штатную отменую боя
  12770. */
  12771. isCancalBattle = false;
  12772. if (await this.battle(toPath)) {
  12773. this.turnsLeft--;
  12774. toPath.splice(0, toPath.indexOf(nodeId));
  12775. nodeInfo.state = 'empty';
  12776. isCancalBattle = true;
  12777. continue;
  12778. }
  12779. isCancalBattle = true;
  12780. return this.end()
  12781. }
  12782.  
  12783. if (nodeInfo.type == 'TYPE_PLAYERBUFF') {
  12784. const buff = this.checkBuff(nodeInfo);
  12785. if (buff == null) {
  12786. continue;
  12787. }
  12788.  
  12789. if (await this.collectBuff(buff, toPath)) {
  12790. this.turnsLeft--;
  12791. toPath.splice(0, toPath.indexOf(nodeId));
  12792. continue;
  12793. }
  12794. this.terminatеReason = I18N('BUFF_GET_ERROR');
  12795. return this.end();
  12796. }
  12797. }
  12798. this.terminatеReason = I18N('SUCCESS');
  12799. return this.end();
  12800. }
  12801.  
  12802. /**
  12803. * Carrying out a fight
  12804. *
  12805. * Проведение боя
  12806. */
  12807. async battle(path, preCalc = true) {
  12808. const data = await this.startBattle(path);
  12809. try {
  12810. const battle = data.results[0].result.response.battle;
  12811. const result = await Calc(battle);
  12812. if (result.result.win) {
  12813. const info = await this.endBattle(result);
  12814. if (info.results[0].result.response?.error) {
  12815. this.terminatеReason = I18N('BATTLE_END_ERROR');
  12816. return false;
  12817. }
  12818. } else {
  12819. await this.cancelBattle(result);
  12820.  
  12821. if (preCalc && await this.preCalcBattle(battle)) {
  12822. path = path.slice(-2);
  12823. for (let i = 1; i <= getInput('countAutoBattle'); i++) {
  12824. setProgress(`${I18N('AUTOBOT')}: ${i}/${getInput('countAutoBattle')}`);
  12825. const result = await this.battle(path, false);
  12826. if (result) {
  12827. setProgress(I18N('VICTORY'));
  12828. return true;
  12829. }
  12830. }
  12831. this.terminatеReason = I18N('FAILED_TO_WIN_AUTO');
  12832. return false;
  12833. }
  12834. return false;
  12835. }
  12836. } catch (error) {
  12837. console.error(error);
  12838. if (await popup.confirm(I18N('ERROR_OF_THE_BATTLE_COPY'), [
  12839. { msg: I18N('BTN_NO'), result: false },
  12840. { msg: I18N('BTN_YES'), result: true },
  12841. ])) {
  12842. this.errorHandling(error, data);
  12843. }
  12844. this.terminatеReason = I18N('ERROR_DURING_THE_BATTLE');
  12845. return false;
  12846. }
  12847. return true;
  12848. }
  12849.  
  12850. /**
  12851. * Recalculate battles
  12852. *
  12853. * Прерасчтет битвы
  12854. */
  12855. async preCalcBattle(battle) {
  12856. const countTestBattle = getInput('countTestBattle');
  12857. for (let i = 0; i < countTestBattle; i++) {
  12858. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  12859. const result = await Calc(battle);
  12860. if (result.result.win) {
  12861. console.log(i, countTestBattle);
  12862. return true;
  12863. }
  12864. }
  12865. this.terminatеReason = I18N('NO_CHANCE_WIN') + countTestBattle;
  12866. return false;
  12867. }
  12868.  
  12869. /**
  12870. * Starts a fight
  12871. *
  12872. * Начинает бой
  12873. */
  12874. startBattle(path) {
  12875. this.args.path = path;
  12876. this.callStartBattle.name = this.actions[this.type].startBattle;
  12877. this.callStartBattle.args = this.args
  12878. const calls = [this.callStartBattle];
  12879. return Send(JSON.stringify({ calls }));
  12880. }
  12881.  
  12882. cancelBattle(battle) {
  12883. const fixBattle = function (heroes) {
  12884. for (const ids in heroes) {
  12885. const hero = heroes[ids];
  12886. hero.energy = random(1, 999);
  12887. if (hero.hp > 0) {
  12888. hero.hp = random(1, hero.hp);
  12889. }
  12890. }
  12891. }
  12892. fixBattle(battle.progress[0].attackers.heroes);
  12893. fixBattle(battle.progress[0].defenders.heroes);
  12894. return this.endBattle(battle);
  12895. }
  12896.  
  12897. /**
  12898. * Ends the fight
  12899. *
  12900. * Заканчивает бой
  12901. */
  12902. endBattle(battle) {
  12903. this.callEndBattle.name = this.actions[this.type].endBattle;
  12904. this.callEndBattle.args.result = battle.result
  12905. this.callEndBattle.args.progress = battle.progress
  12906. const calls = [this.callEndBattle];
  12907. return Send(JSON.stringify({ calls }));
  12908. }
  12909.  
  12910. /**
  12911. * Checks if you can get a buff
  12912. *
  12913. * Проверяет можно ли получить баф
  12914. */
  12915. checkBuff(nodeInfo) {
  12916. let id = null;
  12917. let value = 0;
  12918. for (const buffId in nodeInfo.buffs) {
  12919. const buff = nodeInfo.buffs[buffId];
  12920. if (buff.owner == null && buff.value > value) {
  12921. id = buffId;
  12922. value = buff.value;
  12923. }
  12924. }
  12925. nodeInfo.buffs[id].owner = 'Я';
  12926. return id;
  12927. }
  12928.  
  12929. /**
  12930. * Collects a buff
  12931. *
  12932. * Собирает баф
  12933. */
  12934. async collectBuff(buff, path) {
  12935. this.callCollectBuff.name = this.actions[this.type].collectBuff;
  12936. this.callCollectBuff.args = { buff, path };
  12937. const calls = [this.callCollectBuff];
  12938. return Send(JSON.stringify({ calls }));
  12939. }
  12940.  
  12941. getNodeInfo(nodeId) {
  12942. return this.nodes.find(node => node.id == nodeId);
  12943. }
  12944.  
  12945. errorHandling(error, data) {
  12946. //console.error(error);
  12947. let errorInfo = error.toString() + '\n';
  12948. try {
  12949. const errorStack = error.stack.split('\n');
  12950. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testAdventure");
  12951. errorInfo += errorStack.slice(0, endStack).join('\n');
  12952. } catch (e) {
  12953. errorInfo += error.stack;
  12954. }
  12955. if (data) {
  12956. errorInfo += '\nData: ' + JSON.stringify(data);
  12957. }
  12958. copyText(errorInfo);
  12959. }
  12960.  
  12961. end() {
  12962. isCancalBattle = true;
  12963. setProgress(this.terminatеReason, true);
  12964. console.log(this.terminatеReason);
  12965. this.resolve();
  12966. }
  12967. }
  12968. /**
  12969. * Passage of brawls
  12970. *
  12971. * Прохождение потасовок
  12972. */
  12973. function testBrawls(isAuto) {
  12974. return new Promise((resolve, reject) => {
  12975. const brawls = new executeBrawls(resolve, reject);
  12976. brawls.start(brawlsPack, isAuto);
  12977. });
  12978. }
  12979. /**
  12980. * Passage of brawls
  12981. *
  12982. * Прохождение потасовок
  12983. */
  12984. class executeBrawls {
  12985. callBrawlQuestGetInfo = {
  12986. name: "brawl_questGetInfo",
  12987. args: {},
  12988. ident: "brawl_questGetInfo"
  12989. }
  12990. callBrawlFindEnemies = {
  12991. name: "brawl_findEnemies",
  12992. args: {},
  12993. ident: "brawl_findEnemies"
  12994. }
  12995. callBrawlQuestFarm = {
  12996. name: "brawl_questFarm",
  12997. args: {},
  12998. ident: "brawl_questFarm"
  12999. }
  13000. callUserGetInfo = {
  13001. name: "userGetInfo",
  13002. args: {},
  13003. ident: "userGetInfo"
  13004. }
  13005. callTeamGetMaxUpgrade = {
  13006. name: "teamGetMaxUpgrade",
  13007. args: {},
  13008. ident: "teamGetMaxUpgrade"
  13009. }
  13010. callBrawlGetInfo = {
  13011. name: "brawl_getInfo",
  13012. args: {},
  13013. ident: "brawl_getInfo"
  13014. }
  13015.  
  13016. stats = {
  13017. win: 0,
  13018. loss: 0,
  13019. count: 0,
  13020. }
  13021.  
  13022. stage = {
  13023. '3': 1,
  13024. '7': 2,
  13025. '12': 3,
  13026. }
  13027.  
  13028. attempts = 0;
  13029.  
  13030. constructor(resolve, reject) {
  13031. this.resolve = resolve;
  13032. this.reject = reject;
  13033.  
  13034. const allHeroIds = Object.keys(lib.getData('hero'));
  13035. this.callTeamGetMaxUpgrade.args.units = {
  13036. hero: allHeroIds.filter((id) => +id < 1000),
  13037. titan: allHeroIds.filter((id) => +id >= 4000 && +id < 4100),
  13038. pet: allHeroIds.filter((id) => +id >= 6000 && +id < 6100),
  13039. };
  13040. }
  13041.  
  13042. async start(args, isAuto) {
  13043. this.isAuto = isAuto;
  13044. this.args = args;
  13045. isCancalBattle = false;
  13046. this.brawlInfo = await this.getBrawlInfo();
  13047. this.attempts = this.brawlInfo.attempts;
  13048.  
  13049. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  13050. this.end(I18N('DONT_HAVE_LIVES'));
  13051. return;
  13052. }
  13053.  
  13054. while (1) {
  13055. if (!isBrawlsAutoStart) {
  13056. this.end(I18N('BTN_CANCELED'));
  13057. return;
  13058. }
  13059.  
  13060. const maxStage = this.brawlInfo.questInfo.stage;
  13061. const stage = this.stage[maxStage];
  13062. const progress = this.brawlInfo.questInfo.progress;
  13063.  
  13064. setProgress(
  13065. `${I18N('STAGE')} ${stage}: ${progress}/${maxStage}<br>${I18N('FIGHTS')}: ${this.stats.count}<br>${I18N('WINS')}: ${
  13066. this.stats.win
  13067. }<br>${I18N('LOSSES')}: ${this.stats.loss}<br>${I18N('LIVES')}: ${this.attempts}<br>${I18N('STOP')}`,
  13068. false,
  13069. function () {
  13070. isBrawlsAutoStart = false;
  13071. }
  13072. );
  13073.  
  13074. if (this.brawlInfo.questInfo.canFarm) {
  13075. const result = await this.questFarm();
  13076. console.log(result);
  13077. }
  13078.  
  13079. if (!this.continueAttack && this.brawlInfo.questInfo.stage == 12 && this.brawlInfo.questInfo.progress == 12) {
  13080. if (
  13081. await popup.confirm(I18N('BRAWL_DAILY_TASK_COMPLETED'), [
  13082. { msg: I18N('BTN_NO'), result: true },
  13083. { msg: I18N('BTN_YES'), result: false },
  13084. ])
  13085. ) {
  13086. this.end(I18N('SUCCESS'));
  13087. return;
  13088. } else {
  13089. this.continueAttack = true;
  13090. }
  13091. }
  13092.  
  13093. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  13094. this.end(I18N('DONT_HAVE_LIVES'))
  13095. return;
  13096. }
  13097.  
  13098. const enemie = Object.values(this.brawlInfo.findEnemies).shift();
  13099.  
  13100. // Автоматический подбор пачки
  13101. if (this.isAuto) {
  13102. if (this.mandatoryId <= 4000 && this.mandatoryId != 13) {
  13103. this.end(I18N('BRAWL_AUTO_PACK_NOT_CUR_HERO'));
  13104. return;
  13105. }
  13106. if (this.mandatoryId >= 4000 && this.mandatoryId < 4100) {
  13107. this.args = await this.updateTitanPack(enemie.heroes);
  13108. } else if (this.mandatoryId < 4000 && this.mandatoryId == 13) {
  13109. this.args = await this.updateHeroesPack(enemie.heroes);
  13110. }
  13111. }
  13112.  
  13113. const result = await this.battle(enemie.userId);
  13114. this.brawlInfo = {
  13115. questInfo: result[1].result.response,
  13116. findEnemies: result[2].result.response,
  13117. };
  13118. }
  13119. }
  13120.  
  13121. async updateTitanPack(enemieHeroes) {
  13122. const packs = [
  13123. [4033, 4040, 4041, 4042, 4043],
  13124. [4032, 4040, 4041, 4042, 4043],
  13125. [4031, 4040, 4041, 4042, 4043],
  13126. [4030, 4040, 4041, 4042, 4043],
  13127. [4032, 4033, 4040, 4042, 4043],
  13128. [4030, 4033, 4041, 4042, 4043],
  13129. [4031, 4033, 4040, 4042, 4043],
  13130. [4032, 4033, 4040, 4041, 4043],
  13131. [4023, 4040, 4041, 4042, 4043],
  13132. [4030, 4033, 4040, 4042, 4043],
  13133. [4031, 4033, 4040, 4041, 4043],
  13134. [4022, 4040, 4041, 4042, 4043],
  13135. [4030, 4033, 4040, 4041, 4043],
  13136. [4021, 4040, 4041, 4042, 4043],
  13137. [4020, 4040, 4041, 4042, 4043],
  13138. [4023, 4033, 4040, 4042, 4043],
  13139. [4030, 4032, 4033, 4042, 4043],
  13140. [4023, 4033, 4040, 4041, 4043],
  13141. [4031, 4032, 4033, 4040, 4043],
  13142. [4030, 4032, 4033, 4041, 4043],
  13143. [4030, 4031, 4033, 4042, 4043],
  13144. [4013, 4040, 4041, 4042, 4043],
  13145. [4030, 4032, 4033, 4040, 4043],
  13146. [4030, 4031, 4033, 4041, 4043],
  13147. [4012, 4040, 4041, 4042, 4043],
  13148. [4030, 4031, 4033, 4040, 4043],
  13149. [4011, 4040, 4041, 4042, 4043],
  13150. [4010, 4040, 4041, 4042, 4043],
  13151. [4023, 4032, 4033, 4042, 4043],
  13152. [4022, 4032, 4033, 4042, 4043],
  13153. [4023, 4032, 4033, 4041, 4043],
  13154. [4021, 4032, 4033, 4042, 4043],
  13155. [4022, 4032, 4033, 4041, 4043],
  13156. [4023, 4030, 4033, 4042, 4043],
  13157. [4023, 4032, 4033, 4040, 4043],
  13158. [4013, 4033, 4040, 4042, 4043],
  13159. [4020, 4032, 4033, 4042, 4043],
  13160. [4021, 4032, 4033, 4041, 4043],
  13161. [4022, 4030, 4033, 4042, 4043],
  13162. [4022, 4032, 4033, 4040, 4043],
  13163. [4023, 4030, 4033, 4041, 4043],
  13164. [4023, 4031, 4033, 4040, 4043],
  13165. [4013, 4033, 4040, 4041, 4043],
  13166. [4020, 4031, 4033, 4042, 4043],
  13167. [4020, 4032, 4033, 4041, 4043],
  13168. [4021, 4030, 4033, 4042, 4043],
  13169. [4021, 4032, 4033, 4040, 4043],
  13170. [4022, 4030, 4033, 4041, 4043],
  13171. [4022, 4031, 4033, 4040, 4043],
  13172. [4023, 4030, 4033, 4040, 4043],
  13173. [4030, 4031, 4032, 4033, 4043],
  13174. [4003, 4040, 4041, 4042, 4043],
  13175. [4020, 4030, 4033, 4042, 4043],
  13176. [4020, 4031, 4033, 4041, 4043],
  13177. [4020, 4032, 4033, 4040, 4043],
  13178. [4021, 4030, 4033, 4041, 4043],
  13179. [4021, 4031, 4033, 4040, 4043],
  13180. [4022, 4030, 4033, 4040, 4043],
  13181. [4030, 4031, 4032, 4033, 4042],
  13182. [4002, 4040, 4041, 4042, 4043],
  13183. [4020, 4030, 4033, 4041, 4043],
  13184. [4020, 4031, 4033, 4040, 4043],
  13185. [4021, 4030, 4033, 4040, 4043],
  13186. [4030, 4031, 4032, 4033, 4041],
  13187. [4001, 4040, 4041, 4042, 4043],
  13188. [4030, 4031, 4032, 4033, 4040],
  13189. [4000, 4040, 4041, 4042, 4043],
  13190. [4013, 4032, 4033, 4042, 4043],
  13191. [4012, 4032, 4033, 4042, 4043],
  13192. [4013, 4032, 4033, 4041, 4043],
  13193. [4023, 4031, 4032, 4033, 4043],
  13194. [4011, 4032, 4033, 4042, 4043],
  13195. [4012, 4032, 4033, 4041, 4043],
  13196. [4013, 4030, 4033, 4042, 4043],
  13197. [4013, 4032, 4033, 4040, 4043],
  13198. [4023, 4030, 4032, 4033, 4043],
  13199. [4003, 4033, 4040, 4042, 4043],
  13200. [4013, 4023, 4040, 4042, 4043],
  13201. [4010, 4032, 4033, 4042, 4043],
  13202. [4011, 4032, 4033, 4041, 4043],
  13203. [4012, 4030, 4033, 4042, 4043],
  13204. [4012, 4032, 4033, 4040, 4043],
  13205. [4013, 4030, 4033, 4041, 4043],
  13206. [4013, 4031, 4033, 4040, 4043],
  13207. [4023, 4030, 4031, 4033, 4043],
  13208. [4003, 4033, 4040, 4041, 4043],
  13209. [4013, 4023, 4040, 4041, 4043],
  13210. [4010, 4031, 4033, 4042, 4043],
  13211. [4010, 4032, 4033, 4041, 4043],
  13212. [4011, 4030, 4033, 4042, 4043],
  13213. [4011, 4032, 4033, 4040, 4043],
  13214. [4012, 4030, 4033, 4041, 4043],
  13215. [4012, 4031, 4033, 4040, 4043],
  13216. [4013, 4030, 4033, 4040, 4043],
  13217. [4010, 4030, 4033, 4042, 4043],
  13218. [4010, 4031, 4033, 4041, 4043],
  13219. [4010, 4032, 4033, 4040, 4043],
  13220. [4011, 4030, 4033, 4041, 4043],
  13221. [4011, 4031, 4033, 4040, 4043],
  13222. [4012, 4030, 4033, 4040, 4043],
  13223. [4010, 4030, 4033, 4041, 4043],
  13224. [4010, 4031, 4033, 4040, 4043],
  13225. [4011, 4030, 4033, 4040, 4043],
  13226. [4003, 4032, 4033, 4042, 4043],
  13227. [4002, 4032, 4033, 4042, 4043],
  13228. [4003, 4032, 4033, 4041, 4043],
  13229. [4013, 4031, 4032, 4033, 4043],
  13230. [4001, 4032, 4033, 4042, 4043],
  13231. [4002, 4032, 4033, 4041, 4043],
  13232. [4003, 4030, 4033, 4042, 4043],
  13233. [4003, 4032, 4033, 4040, 4043],
  13234. [4013, 4030, 4032, 4033, 4043],
  13235. [4003, 4023, 4040, 4042, 4043],
  13236. [4000, 4032, 4033, 4042, 4043],
  13237. [4001, 4032, 4033, 4041, 4043],
  13238. [4002, 4030, 4033, 4042, 4043],
  13239. [4002, 4032, 4033, 4040, 4043],
  13240. [4003, 4030, 4033, 4041, 4043],
  13241. [4003, 4031, 4033, 4040, 4043],
  13242. [4020, 4022, 4023, 4042, 4043],
  13243. [4013, 4030, 4031, 4033, 4043],
  13244. [4003, 4023, 4040, 4041, 4043],
  13245. [4000, 4031, 4033, 4042, 4043],
  13246. [4000, 4032, 4033, 4041, 4043],
  13247. [4001, 4030, 4033, 4042, 4043],
  13248. [4001, 4032, 4033, 4040, 4043],
  13249. [4002, 4030, 4033, 4041, 4043],
  13250. [4002, 4031, 4033, 4040, 4043],
  13251. [4003, 4030, 4033, 4040, 4043],
  13252. [4021, 4022, 4023, 4040, 4043],
  13253. [4020, 4022, 4023, 4041, 4043],
  13254. [4020, 4021, 4023, 4042, 4043],
  13255. [4023, 4030, 4031, 4032, 4033],
  13256. [4000, 4030, 4033, 4042, 4043],
  13257. [4000, 4031, 4033, 4041, 4043],
  13258. [4000, 4032, 4033, 4040, 4043],
  13259. [4001, 4030, 4033, 4041, 4043],
  13260. [4001, 4031, 4033, 4040, 4043],
  13261. [4002, 4030, 4033, 4040, 4043],
  13262. [4020, 4022, 4023, 4040, 4043],
  13263. [4020, 4021, 4023, 4041, 4043],
  13264. [4022, 4030, 4031, 4032, 4033],
  13265. [4000, 4030, 4033, 4041, 4043],
  13266. [4000, 4031, 4033, 4040, 4043],
  13267. [4001, 4030, 4033, 4040, 4043],
  13268. [4020, 4021, 4023, 4040, 4043],
  13269. [4021, 4030, 4031, 4032, 4033],
  13270. [4020, 4030, 4031, 4032, 4033],
  13271. [4003, 4031, 4032, 4033, 4043],
  13272. [4020, 4022, 4023, 4033, 4043],
  13273. [4003, 4030, 4032, 4033, 4043],
  13274. [4003, 4013, 4040, 4042, 4043],
  13275. [4020, 4021, 4023, 4033, 4043],
  13276. [4003, 4030, 4031, 4033, 4043],
  13277. [4003, 4013, 4040, 4041, 4043],
  13278. [4013, 4030, 4031, 4032, 4033],
  13279. [4012, 4030, 4031, 4032, 4033],
  13280. [4011, 4030, 4031, 4032, 4033],
  13281. [4010, 4030, 4031, 4032, 4033],
  13282. [4013, 4023, 4031, 4032, 4033],
  13283. [4013, 4023, 4030, 4032, 4033],
  13284. [4020, 4022, 4023, 4032, 4033],
  13285. [4013, 4023, 4030, 4031, 4033],
  13286. [4021, 4022, 4023, 4030, 4033],
  13287. [4020, 4022, 4023, 4031, 4033],
  13288. [4020, 4021, 4023, 4032, 4033],
  13289. [4020, 4021, 4022, 4023, 4043],
  13290. [4003, 4030, 4031, 4032, 4033],
  13291. [4020, 4022, 4023, 4030, 4033],
  13292. [4020, 4021, 4023, 4031, 4033],
  13293. [4020, 4021, 4022, 4023, 4042],
  13294. [4002, 4030, 4031, 4032, 4033],
  13295. [4020, 4021, 4023, 4030, 4033],
  13296. [4020, 4021, 4022, 4023, 4041],
  13297. [4001, 4030, 4031, 4032, 4033],
  13298. [4020, 4021, 4022, 4023, 4040],
  13299. [4000, 4030, 4031, 4032, 4033],
  13300. [4003, 4023, 4031, 4032, 4033],
  13301. [4013, 4020, 4022, 4023, 4043],
  13302. [4003, 4023, 4030, 4032, 4033],
  13303. [4010, 4012, 4013, 4042, 4043],
  13304. [4013, 4020, 4021, 4023, 4043],
  13305. [4003, 4023, 4030, 4031, 4033],
  13306. [4011, 4012, 4013, 4040, 4043],
  13307. [4010, 4012, 4013, 4041, 4043],
  13308. [4010, 4011, 4013, 4042, 4043],
  13309. [4020, 4021, 4022, 4023, 4033],
  13310. [4010, 4012, 4013, 4040, 4043],
  13311. [4010, 4011, 4013, 4041, 4043],
  13312. [4020, 4021, 4022, 4023, 4032],
  13313. [4010, 4011, 4013, 4040, 4043],
  13314. [4020, 4021, 4022, 4023, 4031],
  13315. [4020, 4021, 4022, 4023, 4030],
  13316. [4003, 4013, 4031, 4032, 4033],
  13317. [4010, 4012, 4013, 4033, 4043],
  13318. [4003, 4020, 4022, 4023, 4043],
  13319. [4013, 4020, 4022, 4023, 4033],
  13320. [4003, 4013, 4030, 4032, 4033],
  13321. [4010, 4011, 4013, 4033, 4043],
  13322. [4003, 4020, 4021, 4023, 4043],
  13323. [4013, 4020, 4021, 4023, 4033],
  13324. [4003, 4013, 4030, 4031, 4033],
  13325. [4010, 4012, 4013, 4023, 4043],
  13326. [4003, 4020, 4022, 4023, 4033],
  13327. [4010, 4012, 4013, 4032, 4033],
  13328. [4010, 4011, 4013, 4023, 4043],
  13329. [4003, 4020, 4021, 4023, 4033],
  13330. [4011, 4012, 4013, 4030, 4033],
  13331. [4010, 4012, 4013, 4031, 4033],
  13332. [4010, 4011, 4013, 4032, 4033],
  13333. [4013, 4020, 4021, 4022, 4023],
  13334. [4010, 4012, 4013, 4030, 4033],
  13335. [4010, 4011, 4013, 4031, 4033],
  13336. [4012, 4020, 4021, 4022, 4023],
  13337. [4010, 4011, 4013, 4030, 4033],
  13338. [4011, 4020, 4021, 4022, 4023],
  13339. [4010, 4020, 4021, 4022, 4023],
  13340. [4010, 4012, 4013, 4023, 4033],
  13341. [4000, 4002, 4003, 4042, 4043],
  13342. [4010, 4011, 4013, 4023, 4033],
  13343. [4001, 4002, 4003, 4040, 4043],
  13344. [4000, 4002, 4003, 4041, 4043],
  13345. [4000, 4001, 4003, 4042, 4043],
  13346. [4010, 4011, 4012, 4013, 4043],
  13347. [4003, 4020, 4021, 4022, 4023],
  13348. [4000, 4002, 4003, 4040, 4043],
  13349. [4000, 4001, 4003, 4041, 4043],
  13350. [4010, 4011, 4012, 4013, 4042],
  13351. [4002, 4020, 4021, 4022, 4023],
  13352. [4000, 4001, 4003, 4040, 4043],
  13353. [4010, 4011, 4012, 4013, 4041],
  13354. [4001, 4020, 4021, 4022, 4023],
  13355. [4010, 4011, 4012, 4013, 4040],
  13356. [4000, 4020, 4021, 4022, 4023],
  13357. [4001, 4002, 4003, 4033, 4043],
  13358. [4000, 4002, 4003, 4033, 4043],
  13359. [4003, 4010, 4012, 4013, 4043],
  13360. [4003, 4013, 4020, 4022, 4023],
  13361. [4000, 4001, 4003, 4033, 4043],
  13362. [4003, 4010, 4011, 4013, 4043],
  13363. [4003, 4013, 4020, 4021, 4023],
  13364. [4010, 4011, 4012, 4013, 4033],
  13365. [4010, 4011, 4012, 4013, 4032],
  13366. [4010, 4011, 4012, 4013, 4031],
  13367. [4010, 4011, 4012, 4013, 4030],
  13368. [4001, 4002, 4003, 4023, 4043],
  13369. [4000, 4002, 4003, 4023, 4043],
  13370. [4003, 4010, 4012, 4013, 4033],
  13371. [4000, 4002, 4003, 4032, 4033],
  13372. [4000, 4001, 4003, 4023, 4043],
  13373. [4003, 4010, 4011, 4013, 4033],
  13374. [4001, 4002, 4003, 4030, 4033],
  13375. [4000, 4002, 4003, 4031, 4033],
  13376. [4000, 4001, 4003, 4032, 4033],
  13377. [4010, 4011, 4012, 4013, 4023],
  13378. [4000, 4002, 4003, 4030, 4033],
  13379. [4000, 4001, 4003, 4031, 4033],
  13380. [4010, 4011, 4012, 4013, 4022],
  13381. [4000, 4001, 4003, 4030, 4033],
  13382. [4010, 4011, 4012, 4013, 4021],
  13383. [4010, 4011, 4012, 4013, 4020],
  13384. [4001, 4002, 4003, 4013, 4043],
  13385. [4001, 4002, 4003, 4023, 4033],
  13386. [4000, 4002, 4003, 4013, 4043],
  13387. [4000, 4002, 4003, 4023, 4033],
  13388. [4003, 4010, 4012, 4013, 4023],
  13389. [4000, 4001, 4003, 4013, 4043],
  13390. [4000, 4001, 4003, 4023, 4033],
  13391. [4003, 4010, 4011, 4013, 4023],
  13392. [4001, 4002, 4003, 4013, 4033],
  13393. [4000, 4002, 4003, 4013, 4033],
  13394. [4000, 4001, 4003, 4013, 4033],
  13395. [4000, 4001, 4002, 4003, 4043],
  13396. [4003, 4010, 4011, 4012, 4013],
  13397. [4000, 4001, 4002, 4003, 4042],
  13398. [4002, 4010, 4011, 4012, 4013],
  13399. [4000, 4001, 4002, 4003, 4041],
  13400. [4001, 4010, 4011, 4012, 4013],
  13401. [4000, 4001, 4002, 4003, 4040],
  13402. [4000, 4010, 4011, 4012, 4013],
  13403. [4001, 4002, 4003, 4013, 4023],
  13404. [4000, 4002, 4003, 4013, 4023],
  13405. [4000, 4001, 4003, 4013, 4023],
  13406. [4000, 4001, 4002, 4003, 4033],
  13407. [4000, 4001, 4002, 4003, 4032],
  13408. [4000, 4001, 4002, 4003, 4031],
  13409. [4000, 4001, 4002, 4003, 4030],
  13410. [4000, 4001, 4002, 4003, 4023],
  13411. [4000, 4001, 4002, 4003, 4022],
  13412. [4000, 4001, 4002, 4003, 4021],
  13413. [4000, 4001, 4002, 4003, 4020],
  13414. [4000, 4001, 4002, 4003, 4013],
  13415. [4000, 4001, 4002, 4003, 4012],
  13416. [4000, 4001, 4002, 4003, 4011],
  13417. [4000, 4001, 4002, 4003, 4010],
  13418. ].filter((p) => p.includes(this.mandatoryId));
  13419.  
  13420. const bestPack = {
  13421. pack: packs[0],
  13422. winRate: 0,
  13423. countBattle: 0,
  13424. id: 0,
  13425. };
  13426.  
  13427. for (const id in packs) {
  13428. const pack = packs[id];
  13429. const attackers = this.maxUpgrade.filter((e) => pack.includes(e.id)).reduce((obj, e) => ({ ...obj, [e.id]: e }), {});
  13430. const battle = {
  13431. attackers,
  13432. defenders: [enemieHeroes],
  13433. type: 'brawl_titan',
  13434. };
  13435. const isRandom = this.isRandomBattle(battle);
  13436. const stat = {
  13437. count: 0,
  13438. win: 0,
  13439. winRate: 0,
  13440. };
  13441. for (let i = 1; i <= 20; i++) {
  13442. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  13443. const result = await Calc(battle);
  13444. stat.win += result.result.win;
  13445. stat.count += 1;
  13446. stat.winRate = stat.win / stat.count;
  13447. if (!isRandom || (i >= 2 && stat.winRate < 0.65) || (i >= 10 && stat.winRate == 1)) {
  13448. break;
  13449. }
  13450. }
  13451. if (!isRandom && stat.win) {
  13452. return {
  13453. favor: {},
  13454. heroes: pack,
  13455. };
  13456. }
  13457. if (stat.winRate > 0.85) {
  13458. return {
  13459. favor: {},
  13460. heroes: pack,
  13461. };
  13462. }
  13463. if (stat.winRate > bestPack.winRate) {
  13464. bestPack.countBattle = stat.count;
  13465. bestPack.winRate = stat.winRate;
  13466. bestPack.pack = pack;
  13467. bestPack.id = id;
  13468. }
  13469. }
  13470.  
  13471. //console.log(bestPack.id, bestPack.pack, bestPack.winRate, bestPack.countBattle);
  13472. return {
  13473. favor: {},
  13474. heroes: bestPack.pack,
  13475. };
  13476. }
  13477.  
  13478. isRandomPack(pack) {
  13479. const ids = Object.keys(pack);
  13480. return ids.includes('4023') || ids.includes('4021');
  13481. }
  13482.  
  13483. isRandomBattle(battle) {
  13484. return this.isRandomPack(battle.attackers) || this.isRandomPack(battle.defenders[0]);
  13485. }
  13486.  
  13487. async updateHeroesPack(enemieHeroes) {
  13488. 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}}}];
  13489.  
  13490. const bestPack = {
  13491. pack: packs[0],
  13492. countWin: 0,
  13493. }
  13494.  
  13495. for (const pack of packs) {
  13496. const attackers = pack.attackers;
  13497. const battle = {
  13498. attackers,
  13499. defenders: [enemieHeroes],
  13500. type: 'brawl',
  13501. };
  13502.  
  13503. let countWinBattles = 0;
  13504. let countTestBattle = 10;
  13505. for (let i = 0; i < countTestBattle; i++) {
  13506. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  13507. const result = await Calc(battle);
  13508. if (result.result.win) {
  13509. countWinBattles++;
  13510. }
  13511. if (countWinBattles > 7) {
  13512. console.log(pack)
  13513. return pack.args;
  13514. }
  13515. }
  13516. if (countWinBattles > bestPack.countWin) {
  13517. bestPack.countWin = countWinBattles;
  13518. bestPack.pack = pack.args;
  13519. }
  13520. }
  13521.  
  13522. console.log(bestPack);
  13523. return bestPack.pack;
  13524. }
  13525.  
  13526. async questFarm() {
  13527. const calls = [this.callBrawlQuestFarm];
  13528. const result = await Send(JSON.stringify({ calls }));
  13529. return result.results[0].result.response;
  13530. }
  13531.  
  13532. async getBrawlInfo() {
  13533. const data = await Send(JSON.stringify({
  13534. calls: [
  13535. this.callUserGetInfo,
  13536. this.callBrawlQuestGetInfo,
  13537. this.callBrawlFindEnemies,
  13538. this.callTeamGetMaxUpgrade,
  13539. this.callBrawlGetInfo,
  13540. ]
  13541. }));
  13542.  
  13543. let attempts = data.results[0].result.response.refillable.find(n => n.id == 48);
  13544.  
  13545. const maxUpgrade = data.results[3].result.response;
  13546. const maxHero = Object.values(maxUpgrade.hero);
  13547. const maxTitan = Object.values(maxUpgrade.titan);
  13548. const maxPet = Object.values(maxUpgrade.pet);
  13549. this.maxUpgrade = [...maxHero, ...maxPet, ...maxTitan];
  13550.  
  13551. this.info = data.results[4].result.response;
  13552. this.mandatoryId = lib.data.brawl.promoHero[this.info.id].promoHero;
  13553. return {
  13554. attempts: attempts.amount,
  13555. questInfo: data.results[1].result.response,
  13556. findEnemies: data.results[2].result.response,
  13557. }
  13558. }
  13559.  
  13560. /**
  13561. * Carrying out a fight
  13562. *
  13563. * Проведение боя
  13564. */
  13565. async battle(userId) {
  13566. this.stats.count++;
  13567. const battle = await this.startBattle(userId, this.args);
  13568. const result = await Calc(battle);
  13569. console.log(result.result);
  13570. if (result.result.win) {
  13571. this.stats.win++;
  13572. } else {
  13573. this.stats.loss++;
  13574. if (!this.info.boughtEndlessLivesToday) {
  13575. this.attempts--;
  13576. }
  13577. }
  13578. return await this.endBattle(result);
  13579. // return await this.cancelBattle(result);
  13580. }
  13581.  
  13582. /**
  13583. * Starts a fight
  13584. *
  13585. * Начинает бой
  13586. */
  13587. async startBattle(userId, args) {
  13588. const call = {
  13589. name: "brawl_startBattle",
  13590. args,
  13591. ident: "brawl_startBattle"
  13592. }
  13593. call.args.userId = userId;
  13594. const calls = [call];
  13595. const result = await Send(JSON.stringify({ calls }));
  13596. return result.results[0].result.response;
  13597. }
  13598.  
  13599. cancelBattle(battle) {
  13600. const fixBattle = function (heroes) {
  13601. for (const ids in heroes) {
  13602. const hero = heroes[ids];
  13603. hero.energy = random(1, 999);
  13604. if (hero.hp > 0) {
  13605. hero.hp = random(1, hero.hp);
  13606. }
  13607. }
  13608. }
  13609. fixBattle(battle.progress[0].attackers.heroes);
  13610. fixBattle(battle.progress[0].defenders.heroes);
  13611. return this.endBattle(battle);
  13612. }
  13613.  
  13614. /**
  13615. * Ends the fight
  13616. *
  13617. * Заканчивает бой
  13618. */
  13619. async endBattle(battle) {
  13620. battle.progress[0].attackers.input = ['auto', 0, 0, 'auto', 0, 0];
  13621. const calls = [{
  13622. name: "brawl_endBattle",
  13623. args: {
  13624. result: battle.result,
  13625. progress: battle.progress
  13626. },
  13627. ident: "brawl_endBattle"
  13628. },
  13629. this.callBrawlQuestGetInfo,
  13630. this.callBrawlFindEnemies,
  13631. ];
  13632. const result = await Send(JSON.stringify({ calls }));
  13633. return result.results;
  13634. }
  13635.  
  13636. end(endReason) {
  13637. isCancalBattle = true;
  13638. isBrawlsAutoStart = false;
  13639. setProgress(endReason, true);
  13640. console.log(endReason);
  13641. this.resolve();
  13642. }
  13643. }
  13644.  
  13645. // подземку вконце впихнул
  13646. function DungeonFull() {
  13647. return new Promise((resolve, reject) => {
  13648. const dung = new executeDungeon2(resolve, reject);
  13649. const titanit = getInput('countTitanit');
  13650. dung.start(titanit);
  13651. });
  13652. }
  13653. /** Прохождение подземелья */
  13654. function executeDungeon2(resolve, reject) {
  13655. let dungeonActivity = 0;
  13656. let startDungeonActivity = 0;
  13657. let maxDungeonActivity = 150;
  13658. let limitDungeonActivity = 30180;
  13659. let countShowStats = 1;
  13660. //let fastMode = isChecked('fastMode');
  13661. let end = false;
  13662.  
  13663. let countTeam = [];
  13664. let timeDungeon = {
  13665. all: new Date().getTime(),
  13666. findAttack: 0,
  13667. attackNeutral: 0,
  13668. attackEarthOrFire: 0
  13669. }
  13670.  
  13671. let titansStates = {};
  13672. let bestBattle = {};
  13673.  
  13674. let teams = {
  13675. neutral: [],
  13676. water: [],
  13677. earth: [],
  13678. fire: [],
  13679. hero: []
  13680. }
  13681.  
  13682. //тест
  13683. let talentMsg = '';
  13684. let talentMsgReward = ''
  13685.  
  13686. let callsExecuteDungeon = {
  13687. calls: [{
  13688. name: "dungeonGetInfo",
  13689. args: {},
  13690. ident: "dungeonGetInfo"
  13691. }, {
  13692. name: "teamGetAll",
  13693. args: {},
  13694. ident: "teamGetAll"
  13695. }, {
  13696. name: "teamGetFavor",
  13697. args: {},
  13698. ident: "teamGetFavor"
  13699. }, {
  13700. name: "clanGetInfo",
  13701. args: {},
  13702. ident: "clanGetInfo"
  13703. }]
  13704. }
  13705.  
  13706. this.start = async function(titanit) {
  13707. //maxDungeonActivity = titanit > limitDungeonActivity ? limitDungeonActivity : titanit;
  13708. maxDungeonActivity = titanit || getInput('countTitanit');
  13709. send(JSON.stringify(callsExecuteDungeon), startDungeon);
  13710. }
  13711.  
  13712. /** Получаем данные по подземелью */
  13713. function startDungeon(e) {
  13714. stopDung = false; // стоп подземка
  13715. let res = e.results;
  13716. let dungeonGetInfo = res[0].result.response;
  13717. if (!dungeonGetInfo) {
  13718. endDungeon('noDungeon', res);
  13719. return;
  13720. }
  13721. console.log("Начинаем копать на фулл: ", new Date());
  13722. let teamGetAll = res[1].result.response;
  13723. let teamGetFavor = res[2].result.response;
  13724. dungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  13725. startDungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  13726. titansStates = dungeonGetInfo.states.titans;
  13727.  
  13728. teams.hero = {
  13729. favor: teamGetFavor.dungeon_hero,
  13730. heroes: teamGetAll.dungeon_hero.filter(id => id < 6000),
  13731. teamNum: 0,
  13732. }
  13733. let heroPet = teamGetAll.dungeon_hero.filter(id => id >= 6000).pop();
  13734. if (heroPet) {
  13735. teams.hero.pet = heroPet;
  13736. }
  13737. teams.neutral = getTitanTeam('neutral');
  13738. teams.water = {
  13739. favor: {},
  13740. heroes: getTitanTeam('water'),
  13741. teamNum: 0,
  13742. };
  13743. teams.earth = {
  13744. favor: {},
  13745. heroes: getTitanTeam('earth'),
  13746. teamNum: 0,
  13747. };
  13748. teams.fire = {
  13749. favor: {},
  13750. heroes: getTitanTeam('fire'),
  13751. teamNum: 0,
  13752. };
  13753.  
  13754. checkFloor(dungeonGetInfo);
  13755. }
  13756.  
  13757. function getTitanTeam(type) {
  13758. switch (type) {
  13759. case 'neutral':
  13760. return [4023, 4022, 4012, 4021, 4011, 4010, 4020];
  13761. case 'water':
  13762. return [4000, 4001, 4002, 4003]
  13763. .filter(e => !titansStates[e]?.isDead);
  13764. case 'earth':
  13765. return [4020, 4022, 4021, 4023]
  13766. .filter(e => !titansStates[e]?.isDead);
  13767. case 'fire':
  13768. return [4010, 4011, 4012, 4013]
  13769. .filter(e => !titansStates[e]?.isDead);
  13770. }
  13771. }
  13772.  
  13773. /** Создать копию объекта */
  13774. function clone(a) {
  13775. return JSON.parse(JSON.stringify(a));
  13776. }
  13777.  
  13778. /** Находит стихию на этаже */
  13779. function findElement(floor, element) {
  13780. for (let i in floor) {
  13781. if (floor[i].attackerType === element) {
  13782. return i;
  13783. }
  13784. }
  13785. return undefined;
  13786. }
  13787.  
  13788. /** Проверяем этаж */
  13789. async function checkFloor(dungeonInfo) {
  13790. if (!('floor' in dungeonInfo) || dungeonInfo.floor?.state == 2) {
  13791. saveProgress();
  13792. return;
  13793. }
  13794. checkTalent(dungeonInfo);
  13795. // console.log(dungeonInfo, dungeonActivity);
  13796. setProgress(`${I18N('DUNGEON2')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity} ${talentMsg}`);
  13797. //setProgress('Dungeon: Титанит ' + dungeonActivity + '/' + maxDungeonActivity);
  13798. if (dungeonActivity >= maxDungeonActivity) {
  13799. endDungeon('Стоп подземка,', 'набрано титанита: ' + dungeonActivity + '/' + maxDungeonActivity);
  13800. return;
  13801. }
  13802. let activity = dungeonActivity - startDungeonActivity;
  13803. titansStates = dungeonInfo.states.titans;
  13804. if (stopDung){
  13805. endDungeon('Стоп подземка,', 'набрано титанита: ' + dungeonActivity + '/' + maxDungeonActivity);
  13806. return;
  13807. }
  13808. /*if (activity / 1000 > countShowStats) {
  13809. countShowStats++;
  13810. showStats();
  13811. }*/
  13812. bestBattle = {};
  13813. let floorChoices = dungeonInfo.floor.userData;
  13814. if (floorChoices.length > 1) {
  13815. for (let element in teams) {
  13816. let teamNum = findElement(floorChoices, element);
  13817. if (!!teamNum) {
  13818. if (element == 'earth') {
  13819. teamNum = await chooseEarthOrFire(floorChoices);
  13820. if (teamNum < 0) {
  13821. endDungeon('Невозможно победить без потери Титана!', dungeonInfo);
  13822. return;
  13823. }
  13824. }
  13825. chooseElement(floorChoices[teamNum].attackerType, teamNum);
  13826. return;
  13827. }
  13828. }
  13829. } else {
  13830. chooseElement(floorChoices[0].attackerType, 0);
  13831. }
  13832. }
  13833. //тест черепахи
  13834. async function checkTalent(dungeonInfo) {
  13835. const talent = dungeonInfo.talent;
  13836. if (!talent) {
  13837. return;
  13838. }
  13839. const dungeonFloor = +dungeonInfo.floorNumber;
  13840. const talentFloor = +talent.floorRandValue;
  13841. let doorsAmount = 3 - talent.conditions.doorsAmount;
  13842.  
  13843. if (dungeonFloor === talentFloor && (!doorsAmount || !talent.conditions?.farmedDoors[dungeonFloor])) {
  13844. const reward = await Send({
  13845. calls: [
  13846. { name: 'heroTalent_getReward', args: { talentType: 'tmntDungeonTalent', reroll: false }, ident: 'group_0_body' },
  13847. { name: 'heroTalent_farmReward', args: { talentType: 'tmntDungeonTalent' }, ident: 'group_1_body' },
  13848. ],
  13849. }).then((e) => e.results[0].result.response);
  13850. const type = Object.keys(reward).pop();
  13851. const itemId = Object.keys(reward[type]).pop();
  13852. const count = reward[type][itemId];
  13853. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  13854. talentMsgReward += `<br> ${count} ${itemName}`;
  13855. doorsAmount++;
  13856. }
  13857. talentMsg = `<br>TMNT Talent: ${doorsAmount}/3 ${talentMsgReward}<br>`;
  13858. }
  13859.  
  13860. /** Выбираем огнем или землей атаковать */
  13861. async function chooseEarthOrFire(floorChoices) {
  13862. bestBattle.recovery = -11;
  13863. let selectedTeamNum = -1;
  13864. for (let attempt = 0; selectedTeamNum < 0 && attempt < 4; attempt++) {
  13865. for (let teamNum in floorChoices) {
  13866. let attackerType = floorChoices[teamNum].attackerType;
  13867. selectedTeamNum = await attemptAttackEarthOrFire(teamNum, attackerType, attempt);
  13868. }
  13869. }
  13870. console.log("Выбор команды огня или земли: ", selectedTeamNum < 0 ? "не сделан" : floorChoices[selectedTeamNum].attackerType);
  13871. return selectedTeamNum;
  13872. }
  13873.  
  13874. /** Попытка атаки землей и огнем */
  13875. async function attemptAttackEarthOrFire(teamNum, attackerType, attempt) {
  13876. let start = new Date();
  13877. let team = clone(teams[attackerType]);
  13878. let startIndex = team.heroes.length + attempt - 4;
  13879. if (startIndex >= 0) {
  13880. team.heroes = team.heroes.slice(startIndex);
  13881. let recovery = await getBestRecovery(teamNum, attackerType, team, 25);
  13882. if (recovery > bestBattle.recovery) {
  13883. bestBattle.recovery = recovery;
  13884. bestBattle.selectedTeamNum = teamNum;
  13885. bestBattle.team = team;
  13886. }
  13887. }
  13888. let workTime = new Date().getTime() - start.getTime();
  13889. timeDungeon.attackEarthOrFire += workTime;
  13890. if (bestBattle.recovery < -10) {
  13891. return -1;
  13892. }
  13893. return bestBattle.selectedTeamNum;
  13894. }
  13895.  
  13896. /** Выбираем стихию для атаки */
  13897. async function chooseElement(attackerType, teamNum) {
  13898. let result;
  13899. switch (attackerType) {
  13900. case 'hero':
  13901. case 'water':
  13902. result = await startBattle(teamNum, attackerType, teams[attackerType]);
  13903. break;
  13904. case 'earth':
  13905. case 'fire':
  13906. result = await attackEarthOrFire(teamNum, attackerType);
  13907. break;
  13908. case 'neutral':
  13909. result = await attackNeutral(teamNum, attackerType);
  13910. }
  13911. if (!!result && attackerType != 'hero') {
  13912. let recovery = (!!!bestBattle.recovery ? 10 * getRecovery(result) : bestBattle.recovery) * 100;
  13913. let titans = result.progress[0].attackers.heroes;
  13914. console.log("Проведен бой: " + attackerType +
  13915. ", recovery = " + (recovery > 0 ? "+" : "") + Math.round(recovery) + "% \r\n", titans);
  13916. }
  13917. endBattle(result);
  13918. }
  13919.  
  13920. /** Атакуем Землей или Огнем */
  13921. async function attackEarthOrFire(teamNum, attackerType) {
  13922. if (!!!bestBattle.recovery) {
  13923. bestBattle.recovery = -11;
  13924. let selectedTeamNum = -1;
  13925. for (let attempt = 0; selectedTeamNum < 0 && attempt < 4; attempt++) {
  13926. selectedTeamNum = await attemptAttackEarthOrFire(teamNum, attackerType, attempt);
  13927. }
  13928. if (selectedTeamNum < 0) {
  13929. endDungeon('Невозможно победить без потери Титана!', attackerType);
  13930. return;
  13931. }
  13932. }
  13933. return findAttack(teamNum, attackerType, bestBattle.team);
  13934. }
  13935.  
  13936. /** Находим подходящий результат для атаки */
  13937. async function findAttack(teamNum, attackerType, team) {
  13938. let start = new Date();
  13939. let recovery = -1000;
  13940. let iterations = 0;
  13941. let result;
  13942. let correction = 0.01;
  13943. for (let needRecovery = bestBattle.recovery; recovery < needRecovery; needRecovery -= correction, iterations++) {
  13944. result = await startBattle(teamNum, attackerType, team);
  13945. recovery = getRecovery(result);
  13946. }
  13947. bestBattle.recovery = recovery;
  13948. let workTime = new Date().getTime() - start.getTime();
  13949. timeDungeon.findAttack += workTime;
  13950. return result;
  13951. }
  13952.  
  13953. /** Атакуем Нейтральной командой */
  13954. async function attackNeutral(teamNum, attackerType) {
  13955. let start = new Date();
  13956. let factors = calcFactor();
  13957. bestBattle.recovery = -0.2;
  13958. await findBestBattleNeutral(teamNum, attackerType, factors, true)
  13959. if (bestBattle.recovery < 0 || (bestBattle.recovery < 0.2 && factors[0].value < 0.5)) {
  13960. let recovery = 100 * bestBattle.recovery;
  13961. console.log("Не удалось найти удачный бой в быстром режиме: " + attackerType +
  13962. ", recovery = " + (recovery > 0 ? "+" : "") + Math.round(recovery) + "% \r\n", bestBattle.attackers);
  13963. await findBestBattleNeutral(teamNum, attackerType, factors, false)
  13964. }
  13965. let workTime = new Date().getTime() - start.getTime();
  13966. timeDungeon.attackNeutral += workTime;
  13967. if (!!bestBattle.attackers) {
  13968. let team = getTeam(bestBattle.attackers);
  13969. return findAttack(teamNum, attackerType, team);
  13970. }
  13971. endDungeon('Не удалось найти удачный бой!', attackerType);
  13972. return undefined;
  13973. }
  13974.  
  13975. /** Находит лучшую нейтральную команду */
  13976. async function findBestBattleNeutral(teamNum, attackerType, factors, mode) {
  13977. let countFactors = factors.length < 4 ? factors.length : 4;
  13978. let aradgi = !titansStates['4013']?.isDead;
  13979. let edem = !titansStates['4023']?.isDead;
  13980. let dark = [4032, 4033].filter(e => !titansStates[e]?.isDead);
  13981. let light = [4042].filter(e => !titansStates[e]?.isDead);
  13982. let actions = [];
  13983. if (mode) {
  13984. for (let i = 0; i < countFactors; i++) {
  13985. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(factors[i].id)));
  13986. }
  13987. if (countFactors > 1) {
  13988. let firstId = factors[0].id;
  13989. let secondId = factors[1].id;
  13990. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, secondId)));
  13991. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, secondId)));
  13992. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4003, secondId)));
  13993. }
  13994. if (aradgi) {
  13995. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(4013)));
  13996. if (countFactors > 0) {
  13997. let firstId = factors[0].id;
  13998. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4000, 4013)));
  13999. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, 4013)));
  14000. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, 4013)));
  14001. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4003, 4013)));
  14002. }
  14003. if (edem) {
  14004. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(4023, 4000, 4013)));
  14005. }
  14006. }
  14007. } else {
  14008. if (mode) {
  14009. for (let i = 0; i < factors.length; i++) {
  14010. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(factors[i].id)));
  14011. }
  14012. } else {
  14013. countFactors = factors.length < 2 ? factors.length : 2;
  14014. }
  14015. for (let i = 0; i < countFactors; i++) {
  14016. let mainId = factors[i].id;
  14017. if (aradgi && (mode || i > 0)) {
  14018. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4000, 4013)));
  14019. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, 4013)));
  14020. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, 4013)));
  14021. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4003, 4013)));
  14022. }
  14023. for (let i = 0; i < dark.length; i++) {
  14024. let darkId = dark[i];
  14025. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, darkId)));
  14026. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, darkId)));
  14027. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4003, darkId)));
  14028. }
  14029. for (let i = 0; i < light.length; i++) {
  14030. let lightId = light[i];
  14031. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, lightId)));
  14032. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, lightId)));
  14033. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4003, lightId)));
  14034. }
  14035. let isFull = mode || i > 0;
  14036. for (let j = isFull ? i + 1 : 2; j < factors.length; j++) {
  14037. let extraId = factors[j].id;
  14038. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4000, extraId)));
  14039. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, extraId)));
  14040. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, extraId)));
  14041. }
  14042. }
  14043. if (aradgi) {
  14044. if (mode) {
  14045. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(4013)));
  14046. }
  14047. for (let i = 0; i < dark.length; i++) {
  14048. let darkId = dark[i];
  14049. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(darkId, 4001, 4013)));
  14050. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(darkId, 4002, 4013)));
  14051. }
  14052. for (let i = 0; i < light.length; i++) {
  14053. let lightId = light[i];
  14054. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(lightId, 4001, 4013)));
  14055. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(lightId, 4002, 4013)));
  14056. }
  14057. }
  14058. for (let i = 0; i < dark.length; i++) {
  14059. let firstId = dark[i];
  14060. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId)));
  14061. for (let j = i + 1; j < dark.length; j++) {
  14062. let secondId = dark[j];
  14063. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, secondId)));
  14064. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, secondId)));
  14065. }
  14066. }
  14067. for (let i = 0; i < light.length; i++) {
  14068. let firstId = light[i];
  14069. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId)));
  14070. for (let j = i + 1; j < light.length; j++) {
  14071. let secondId = light[j];
  14072. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, secondId)));
  14073. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, secondId)));
  14074. }
  14075. }
  14076. }
  14077. for (let result of await Promise.all(actions)) {
  14078. let recovery = getRecovery(result);
  14079. if (recovery > bestBattle.recovery) {
  14080. bestBattle.recovery = recovery;
  14081. bestBattle.attackers = result.progress[0].attackers.heroes;
  14082. }
  14083. }
  14084. }
  14085.  
  14086. /** Получаем нейтральную команду */
  14087. function getNeutralTeam(id, swapId, addId) {
  14088. let neutralTeam = clone(teams.water);
  14089. let neutral = neutralTeam.heroes;
  14090. if (neutral.length == 4) {
  14091. if (!!swapId) {
  14092. for (let i in neutral) {
  14093. if (neutral[i] == swapId) {
  14094. neutral[i] = addId;
  14095. }
  14096. }
  14097. }
  14098. } else if (!!addId) {
  14099. neutral.push(addId);
  14100. }
  14101. neutral.push(id);
  14102. return neutralTeam;
  14103. }
  14104.  
  14105. /** Получить команду титанов */
  14106. function getTeam(titans) {
  14107. return {
  14108. favor: {},
  14109. heroes: Object.keys(titans).map(id => parseInt(id)),
  14110. teamNum: 0,
  14111. };
  14112. }
  14113.  
  14114. /** Вычисляем фактор боеготовности титанов */
  14115. function calcFactor() {
  14116. let neutral = teams.neutral;
  14117. let factors = [];
  14118. for (let i in neutral) {
  14119. let titanId = neutral[i];
  14120. let titan = titansStates[titanId];
  14121. let factor = !!titan ? titan.hp / titan.maxHp + titan.energy / 10000.0 : 1;
  14122. if (factor > 0) {
  14123. factors.push({id: titanId, value: factor});
  14124. }
  14125. }
  14126. factors.sort(function(a, b) {
  14127. return a.value - b.value;
  14128. });
  14129. return factors;
  14130. }
  14131.  
  14132. /** Возвращает наилучший результат из нескольких боев */
  14133. async function getBestRecovery(teamNum, attackerType, team, countBattle) {
  14134. let bestRecovery = -1000;
  14135. let actions = [];
  14136. for (let i = 0; i < countBattle; i++) {
  14137. actions.push(startBattle(teamNum, attackerType, team));
  14138. }
  14139. for (let result of await Promise.all(actions)) {
  14140. let recovery = getRecovery(result);
  14141. if (recovery > bestRecovery) {
  14142. bestRecovery = recovery;
  14143. }
  14144. }
  14145. return bestRecovery;
  14146. }
  14147.  
  14148. /** Возвращает разницу в здоровье атакующей команды после и до битвы и проверяет здоровье титанов на необходимый минимум*/
  14149. function getRecovery(result) {
  14150. if (result.result.stars < 3) {
  14151. return -100;
  14152. }
  14153. let beforeSumFactor = 0;
  14154. let afterSumFactor = 0;
  14155. let beforeTitans = result.battleData.attackers;
  14156. let afterTitans = result.progress[0].attackers.heroes;
  14157. for (let i in afterTitans) {
  14158. let titan = afterTitans[i];
  14159. let percentHP = titan.hp / beforeTitans[i].hp;
  14160. let energy = titan.energy;
  14161. let factor = checkTitan(i, energy, percentHP) ? getFactor(i, energy, percentHP) : -100;
  14162. afterSumFactor += factor;
  14163. }
  14164. for (let i in beforeTitans) {
  14165. let titan = beforeTitans[i];
  14166. let state = titan.state;
  14167. beforeSumFactor += !!state ? getFactor(i, state.energy, state.hp / titan.hp) : 1;
  14168. }
  14169. return afterSumFactor - beforeSumFactor;
  14170. }
  14171.  
  14172. /** Возвращает состояние титана*/
  14173. function getFactor(id, energy, percentHP) {
  14174. let elemantId = id.slice(2, 3);
  14175. let isEarthOrFire = elemantId == '1' || elemantId == '2';
  14176. let energyBonus = id == '4020' && energy == 1000 ? 0.1 : energy / 20000.0;
  14177. let factor = percentHP + energyBonus;
  14178. return isEarthOrFire ? factor : factor / 10;
  14179. }
  14180.  
  14181. /** Проверяет состояние титана*/
  14182. function checkTitan(id, energy, percentHP) {
  14183. switch (id) {
  14184. case '4020':
  14185. return percentHP > 0.25 || (energy == 1000 && percentHP > 0.05);
  14186. break;
  14187. case '4010':
  14188. return percentHP + energy / 2000.0 > 0.63;
  14189. break;
  14190. case '4000':
  14191. return percentHP > 0.62 || (energy < 1000 && (
  14192. (percentHP > 0.45 && energy >= 400) ||
  14193. (percentHP > 0.3 && energy >= 670)));
  14194. }
  14195. return true;
  14196. }
  14197.  
  14198.  
  14199. /** Начинаем бой */
  14200. function startBattle(teamNum, attackerType, args) {
  14201. return new Promise(function (resolve, reject) {
  14202. args.teamNum = teamNum;
  14203. let startBattleCall = {
  14204. calls: [{
  14205. name: "dungeonStartBattle",
  14206. args,
  14207. ident: "body"
  14208. }]
  14209. }
  14210. send(JSON.stringify(startBattleCall), resultBattle, {
  14211. resolve,
  14212. teamNum,
  14213. attackerType
  14214. });
  14215. });
  14216. }
  14217.  
  14218. /** Возращает результат боя в промис */
  14219. /*function resultBattle(resultBattles, args) {
  14220. if (!!resultBattles && !!resultBattles.results) {
  14221. let battleData = resultBattles.results[0].result.response;
  14222. let battleType = "get_tower";
  14223. if (battleData.type == "dungeon_titan") {
  14224. battleType = "get_titan";
  14225. }
  14226. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];//тест подземка правки
  14227. BattleCalc(battleData, battleType, function (result) {
  14228. result.teamNum = args.teamNum;
  14229. result.attackerType = args.attackerType;
  14230. args.resolve(result);
  14231. });
  14232. } else {
  14233. endDungeon('Потеряна связь с сервером игры!', 'break');
  14234. }
  14235. }*/
  14236. function resultBattle(resultBattles, args) {
  14237. battleData = resultBattles.results[0].result.response;
  14238. battleType = "get_tower";
  14239. if (battleData.type == "dungeon_titan") {
  14240. battleType = "get_titan";
  14241. }
  14242. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  14243. BattleCalc(battleData, battleType, function (result) {
  14244. result.teamNum = args.teamNum;
  14245. result.attackerType = args.attackerType;
  14246. args.resolve(result);
  14247. });
  14248. }
  14249.  
  14250. /** Заканчиваем бой */
  14251.  
  14252. ////
  14253. async function endBattle(battleInfo) {
  14254. if (!!battleInfo) {
  14255. const args = {
  14256. result: battleInfo.result,
  14257. progress: battleInfo.progress,
  14258. }
  14259. if (battleInfo.result.stars < 3) {
  14260. endDungeon('Герой или Титан мог погибнуть в бою!', battleInfo);
  14261. return;
  14262. }
  14263. if (countPredictionCard > 0) {
  14264. args.isRaid = true;
  14265. } else {
  14266. const timer = getTimer(battleInfo.battleTime);
  14267. console.log(timer);
  14268. await countdownTimer(timer, `${I18N('DUNGEON2')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity} ${talentMsg}`);
  14269. }
  14270. const calls = [{
  14271. name: "dungeonEndBattle",
  14272. args,
  14273. ident: "body"
  14274. }];
  14275. lastDungeonBattleData = null;
  14276. send(JSON.stringify({ calls }), resultEndBattle);
  14277. } else {
  14278. endDungeon('dungeonEndBattle win: false\n', battleInfo);
  14279. }
  14280. }
  14281. /** Получаем и обрабатываем результаты боя */
  14282. function resultEndBattle(e) {
  14283. if (!!e && !!e.results) {
  14284. let battleResult = e.results[0].result.response;
  14285. if ('error' in battleResult) {
  14286. endDungeon('errorBattleResult', battleResult);
  14287. return;
  14288. }
  14289. let dungeonGetInfo = battleResult.dungeon ?? battleResult;
  14290. dungeonActivity += battleResult.reward.dungeonActivity ?? 0;
  14291. checkFloor(dungeonGetInfo);
  14292. } else {
  14293. endDungeon('Потеряна связь с сервером игры!', 'break');
  14294. }
  14295. }
  14296.  
  14297. /** Добавить команду титанов в общий список команд */
  14298. function addTeam(team) {
  14299. for (let i in countTeam) {
  14300. if (equalsTeam(countTeam[i].team, team)) {
  14301. countTeam[i].count++;
  14302. return;
  14303. }
  14304. }
  14305. countTeam.push({team: team, count: 1});
  14306. }
  14307.  
  14308. /** Сравнить команды на равенство */
  14309. function equalsTeam(team1, team2) {
  14310. if (team1.length == team2.length) {
  14311. for (let i in team1) {
  14312. if (team1[i] != team2[i]) {
  14313. return false;
  14314. }
  14315. }
  14316. return true;
  14317. }
  14318. return false;
  14319. }
  14320.  
  14321. function saveProgress() {
  14322. let saveProgressCall = {
  14323. calls: [{
  14324. name: "dungeonSaveProgress",
  14325. args: {},
  14326. ident: "body"
  14327. }]
  14328. }
  14329. send(JSON.stringify(saveProgressCall), resultEndBattle);
  14330. }
  14331.  
  14332.  
  14333. /** Выводит статистику прохождения подземелья */
  14334. function showStats() {
  14335. let activity = dungeonActivity - startDungeonActivity;
  14336. let workTime = clone(timeDungeon);
  14337. workTime.all = new Date().getTime() - workTime.all;
  14338. for (let i in workTime) {
  14339. workTime[i] = (workTime[i] / 1000).round(0);
  14340. }
  14341. countTeam.sort(function(a, b) {
  14342. return b.count - a.count;
  14343. });
  14344. console.log(titansStates);
  14345. console.log("Собрано титанита: ", activity);
  14346. console.log("Скорость сбора: " + (3600 * activity / workTime.all).round(0) + " титанита/час");
  14347. console.log("Время раскопок: ");
  14348. for (let i in workTime) {
  14349. let timeNow = workTime[i];
  14350. console.log(i + ": ", (timeNow / 3600).round(0) + " ч. " + (timeNow % 3600 / 60).round(0) + " мин. " + timeNow % 60 + " сек.");
  14351. }
  14352. console.log("Частота использования команд: ");
  14353. for (let i in countTeam) {
  14354. let teams = countTeam[i];
  14355. console.log(teams.team + ": ", teams.count);
  14356. }
  14357. }
  14358.  
  14359. /** Заканчиваем копать подземелье */
  14360. function endDungeon(reason, info) {
  14361. if (!end) {
  14362. end = true;
  14363. console.log(reason, info);
  14364. showStats();
  14365. if (info == 'break') {
  14366. setProgress('Dungeon stoped: Титанит ' + dungeonActivity + '/' + maxDungeonActivity +
  14367. "\r\nПотеряна связь с сервером игры!", false, hideProgress);
  14368. } else {
  14369. setProgress('Dungeon completed: Титанит ' + dungeonActivity + '/' + maxDungeonActivity, false, hideProgress);
  14370. }
  14371. setTimeout(cheats.refreshGame, 1000);
  14372. resolve();
  14373. }
  14374. }
  14375. }
  14376.  
  14377. //дарим подарки участникам других гильдий не выходя из своей гильдии
  14378. function NewYearGift_Clan() {
  14379. console.log('NewYearGift_Clan called...');
  14380. const userID = getInput('userID');
  14381. const AmontID = getInput('AmontID');
  14382. const GiftNum = getInput('GiftNum');
  14383.  
  14384. const data = {
  14385. "calls": [{
  14386. "name": "newYearGiftSend",
  14387. "args": {
  14388. "userId": userID,
  14389. "amount": AmontID,
  14390. "giftNum": GiftNum,
  14391. "users": {
  14392. [userID]: AmontID
  14393. }
  14394. },
  14395. "ident": "body"
  14396. }
  14397. ]
  14398. }
  14399.  
  14400. const dataJson = JSON.stringify(data);
  14401.  
  14402. SendRequest(dataJson, e => {
  14403. let userInfo = e.results[0].result.response;
  14404. console.log(userInfo);
  14405. });
  14406. setProgress(I18N('SEND_GIFT'), true);
  14407. }
  14408. })();
  14409.  
  14410. /**
  14411. * TODO:
  14412. * Получение всех уровней при сборе всех наград (квест на титанит и на энку) +-
  14413. * Добивание на арене титанов
  14414. * Закрытие окошек по Esc +-
  14415. * Починить работу скрипта на уровне команды ниже 10 +-
  14416. * Написать нормальную синхронизацию
  14417. * Запрет сбора квестов и отправки экспеиций в промежуток между локальным обновлением и глобальным обновлением дня
  14418. * Улучшение боев
  14419. */

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址