HeroWarsHelper

Automation of actions for the game Hero Wars

目前为 2024-08-27 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name HeroWarsHelper
  3. // @name:en HeroWarsHelper
  4. // @name:ru HeroWarsHelper
  5. // @namespace HeroWarsHelper
  6. // @version 2.281
  7. // @description Automation of actions for the game Hero Wars
  8. // @description:en Automation of actions for the game Hero Wars
  9. // @description:ru Автоматизация действий для игры Хроники Хаоса
  10. // @author ZingerY
  11. // @license Copyright ZingerY
  12. // @homepage https://zingery.ru/scripts/HeroWarsHelper.user.js
  13. // @icon http://ilovemycomp.narod.ru/VaultBoyIco16.ico
  14. // @icon64 http://ilovemycomp.narod.ru/VaultBoyIco64.png
  15. // @match https://www.hero-wars.com/*
  16. // @match https://apps-1701433570146040.apps.fbsbx.com/*
  17. // @run-at document-start
  18. // ==/UserScript==
  19.  
  20. (function() {
  21. /**
  22. * Start script
  23. *
  24. * Стартуем скрипт
  25. */
  26. console.log('%cStart ' + GM_info.script.name + ', v' + GM_info.script.version, 'color: red');
  27. /**
  28. * Script info
  29. *
  30. * Информация о скрипте
  31. */
  32. const scriptInfo = (({name, version, author, homepage, lastModified}, updateUrl, source) =>
  33. ({name, version, author, homepage, lastModified, updateUrl, source}))
  34. (GM_info.script, GM_info.scriptUpdateURL, arguments.callee.toString());
  35. /**
  36. * Information for completing daily quests
  37. *
  38. * Информация для выполнения ежендевных квестов
  39. */
  40. const questsInfo = {};
  41. /**
  42. * Is the game data loaded
  43. *
  44. * Загружены ли данные игры
  45. */
  46. let isLoadGame = false;
  47. /**
  48. * Headers of the last request
  49. *
  50. * Заголовки последнего запроса
  51. */
  52. let lastHeaders = {};
  53. /**
  54. * Information about sent gifts
  55. *
  56. * Информация об отправленных подарках
  57. */
  58. let freebieCheckInfo = null;
  59. /**
  60. * missionTimer
  61. *
  62. * missionTimer
  63. */
  64. let missionBattle = null;
  65. /**
  66. * User data
  67. *
  68. * Данные пользователя
  69. */
  70. let userInfo;
  71. /**
  72. * Original methods for working with AJAX
  73. *
  74. * Оригинальные методы для работы с AJAX
  75. */
  76. const original = {
  77. open: XMLHttpRequest.prototype.open,
  78. send: XMLHttpRequest.prototype.send,
  79. setRequestHeader: XMLHttpRequest.prototype.setRequestHeader,
  80. SendWebSocket: WebSocket.prototype.send,
  81. };
  82. /**
  83. * Decoder for converting byte data to JSON string
  84. *
  85. * Декодер для перобразования байтовых данных в JSON строку
  86. */
  87. const decoder = new TextDecoder("utf-8");
  88. /**
  89. * Stores a history of requests
  90. *
  91. * Хранит историю запросов
  92. */
  93. let requestHistory = {};
  94. /**
  95. * URL for API requests
  96. *
  97. * URL для запросов к API
  98. */
  99. let apiUrl = '';
  100.  
  101. /**
  102. * Connecting to the game code
  103. *
  104. * Подключение к коду игры
  105. */
  106. this.cheats = new hackGame();
  107. /**
  108. * The function of calculating the results of the battle
  109. *
  110. * Функция расчета результатов боя
  111. */
  112. this.BattleCalc = cheats.BattleCalc;
  113. /**
  114. * Sending a request available through the console
  115. *
  116. * Отправка запроса доступная через консоль
  117. */
  118. this.SendRequest = send;
  119. /**
  120. * Simple combat calculation available through the console
  121. *
  122. * Простой расчет боя доступный через консоль
  123. */
  124. this.Calc = function (data) {
  125. const type = getBattleType(data?.type);
  126. return new Promise((resolve, reject) => {
  127. try {
  128. BattleCalc(data, type, resolve);
  129. } catch (e) {
  130. reject(e);
  131. }
  132. })
  133. }
  134. /**
  135. * Short asynchronous request
  136. * Usage example (returns information about a character):
  137. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  138. *
  139. * Короткий асинхронный запрос
  140. * Пример использования (возвращает информацию о персонаже):
  141. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  142. */
  143. this.Send = function (json, pr) {
  144. return new Promise((resolve, reject) => {
  145. try {
  146. send(json, resolve, pr);
  147. } catch (e) {
  148. reject(e);
  149. }
  150. })
  151. }
  152.  
  153. this.xyz = (({ name, version, author }) => ({ name, version, author }))(GM_info.script);
  154. const i18nLangData = {
  155. /* English translation by BaBa */
  156. en: {
  157. /* Checkboxes */
  158. SKIP_FIGHTS: 'Skip battle',
  159. SKIP_FIGHTS_TITLE: 'Skip battle in Outland and the arena of the titans, auto-pass in the tower and campaign',
  160. ENDLESS_CARDS: 'Infinite cards',
  161. ENDLESS_CARDS_TITLE: 'Disable Divination Cards wasting',
  162. AUTO_EXPEDITION: 'Auto Expedition',
  163. AUTO_EXPEDITION_TITLE: 'Auto-sending expeditions',
  164. CANCEL_FIGHT: 'Cancel battle',
  165. CANCEL_FIGHT_TITLE: 'Ability to cancel manual combat on GW, CoW and Asgard',
  166. GIFTS: 'Gifts',
  167. GIFTS_TITLE: 'Collect gifts automatically',
  168. BATTLE_RECALCULATION: 'Battle recalculation',
  169. BATTLE_RECALCULATION_TITLE: 'Preliminary calculation of the battle',
  170. QUANTITY_CONTROL: 'Quantity control',
  171. QUANTITY_CONTROL_TITLE: 'Ability to specify the number of opened "lootboxes"',
  172. REPEAT_CAMPAIGN: 'Repeat missions',
  173. REPEAT_CAMPAIGN_TITLE: 'Auto-repeat battles in the campaign',
  174. DISABLE_DONAT: 'Disable donation',
  175. DISABLE_DONAT_TITLE: 'Removes all donation offers',
  176. DAILY_QUESTS: 'Quests',
  177. DAILY_QUESTS_TITLE: 'Complete daily quests',
  178. AUTO_QUIZ: 'AutoQuiz',
  179. AUTO_QUIZ_TITLE: 'Automatically receive correct answers to quiz questions',
  180. SECRET_WEALTH_CHECKBOX: 'Automatic purchase in the store "Secret Wealth" when entering the game',
  181. HIDE_SERVERS: 'Collapse servers',
  182. HIDE_SERVERS_TITLE: 'Hide unused servers',
  183. /* Input fields */
  184. HOW_MUCH_TITANITE: 'How much titanite to farm',
  185. COMBAT_SPEED: 'Combat Speed Multiplier',
  186. NUMBER_OF_TEST: 'Number of test fights',
  187. NUMBER_OF_AUTO_BATTLE: 'Number of auto-battle attempts',
  188. /* Buttons */
  189. RUN_SCRIPT: 'Run the',
  190. TO_DO_EVERYTHING: 'Do All',
  191. TO_DO_EVERYTHING_TITLE: 'Perform multiple actions of your choice',
  192. OUTLAND: 'Outland',
  193. OUTLAND_TITLE: 'Collect Outland',
  194. TITAN_ARENA: 'ToE',
  195. TITAN_ARENA_TITLE: 'Complete the titan arena',
  196. DUNGEON: 'Dungeon',
  197. DUNGEON_TITLE: 'Go through the dungeon',
  198. SEER: 'Seer',
  199. SEER_TITLE: 'Roll the Seer',
  200. TOWER: 'Tower',
  201. TOWER_TITLE: 'Pass the tower',
  202. EXPEDITIONS: 'Expeditions',
  203. EXPEDITIONS_TITLE: 'Sending and collecting expeditions',
  204. SYNC: 'Sync',
  205. SYNC_TITLE: 'Partial synchronization of game data without reloading the page',
  206. ARCHDEMON: 'Archdemon',
  207. ARCHDEMON_TITLE: 'Hitting kills and collecting rewards',
  208. ESTER_EGGS: 'Easter eggs',
  209. ESTER_EGGS_TITLE: 'Collect all Easter eggs or rewards',
  210. REWARDS: 'Rewards',
  211. REWARDS_TITLE: 'Collect all quest rewards',
  212. MAIL: 'Mail',
  213. MAIL_TITLE: 'Collect all mail, except letters with energy and charges of the portal',
  214. MINIONS: 'Minions',
  215. MINIONS_TITLE: 'Attack minions with saved packs',
  216. ADVENTURE: 'Adventure',
  217. ADVENTURE_TITLE: 'Passes the adventure along the specified route',
  218. STORM: 'Storm',
  219. STORM_TITLE: 'Passes the Storm along the specified route',
  220. SANCTUARY: 'Sanctuary',
  221. SANCTUARY_TITLE: 'Fast travel to Sanctuary',
  222. GUILD_WAR: 'Guild War',
  223. GUILD_WAR_TITLE: 'Fast travel to Guild War',
  224. SECRET_WEALTH: 'Secret Wealth',
  225. SECRET_WEALTH_TITLE: 'Buy something in the store "Secret Wealth"',
  226. /* Misc */
  227. BOTTOM_URLS:
  228. '<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>',
  229. GIFTS_SENT: 'Gifts sent!',
  230. DO_YOU_WANT: 'Do you really want to do this?',
  231. BTN_RUN: 'Run',
  232. BTN_CANCEL: 'Cancel',
  233. BTN_OK: 'OK',
  234. MSG_HAVE_BEEN_DEFEATED: 'You have been defeated!',
  235. BTN_AUTO: 'Auto',
  236. MSG_YOU_APPLIED: 'You applied',
  237. MSG_DAMAGE: 'damage',
  238. MSG_CANCEL_AND_STAT: 'Auto (F5) and show statistic',
  239. MSG_REPEAT_MISSION: 'Repeat the mission?',
  240. BTN_REPEAT: 'Repeat',
  241. BTN_NO: 'No',
  242. MSG_SPECIFY_QUANT: 'Specify Quantity:',
  243. BTN_OPEN: 'Open',
  244. QUESTION_COPY: 'Question copied to clipboard',
  245. ANSWER_KNOWN: 'The answer is known',
  246. ANSWER_NOT_KNOWN: 'ATTENTION THE ANSWER IS NOT KNOWN',
  247. BEING_RECALC: 'The battle is being recalculated',
  248. THIS_TIME: 'This time',
  249. VICTORY: '<span style="color:green;">VICTORY</span>',
  250. DEFEAT: '<span style="color:red;">DEFEAT</span>',
  251. CHANCE_TO_WIN: 'Chance to win <span style="color: red;">based on pre-calculation</span>',
  252. OPEN_DOLLS: 'nesting dolls recursively',
  253. SENT_QUESTION: 'Question sent',
  254. SETTINGS: 'Settings',
  255. MSG_BAN_ATTENTION: '<p style="color:red;">Using this feature may result in a ban.</p> Continue?',
  256. BTN_YES_I_AGREE: 'Yes, I understand the risks!',
  257. BTN_NO_I_AM_AGAINST: 'No, I refuse it!',
  258. VALUES: 'Values',
  259. EXPEDITIONS_SENT: 'Expeditions:<br>Collected: {countGet}<br>Sent: {countSend}',
  260. EXPEDITIONS_NOTHING: 'Nothing to collect/send',
  261. TITANIT: 'Titanit',
  262. COMPLETED: 'completed',
  263. FLOOR: 'Floor',
  264. LEVEL: 'Level',
  265. BATTLES: 'battles',
  266. EVENT: 'Event',
  267. NOT_AVAILABLE: 'not available',
  268. NO_HEROES: 'No heroes',
  269. DAMAGE_AMOUNT: 'Damage amount',
  270. NOTHING_TO_COLLECT: 'Nothing to collect',
  271. COLLECTED: 'Collected',
  272. REWARD: 'rewards',
  273. REMAINING_ATTEMPTS: 'Remaining attempts',
  274. BATTLES_CANCELED: 'Battles canceled',
  275. MINION_RAID: 'Minion Raid',
  276. STOPPED: 'Stopped',
  277. REPETITIONS: 'Repetitions',
  278. MISSIONS_PASSED: 'Missions passed',
  279. STOP: 'stop',
  280. TOTAL_OPEN: 'Total open',
  281. OPEN: 'Open',
  282. ROUND_STAT: 'Damage statistics for ',
  283. BATTLE: 'battles',
  284. MINIMUM: 'Minimum',
  285. MAXIMUM: 'Maximum',
  286. AVERAGE: 'Average',
  287. NOT_THIS_TIME: 'Not this time',
  288. RETRY_LIMIT_EXCEEDED: 'Retry limit exceeded',
  289. SUCCESS: 'Success',
  290. RECEIVED: 'Received',
  291. LETTERS: 'letters',
  292. PORTALS: 'portals',
  293. ATTEMPTS: 'attempts',
  294. /* Quests */
  295. QUEST_10001: 'Upgrade the skills of heroes 3 times',
  296. QUEST_10002: 'Complete 10 missions',
  297. QUEST_10003: 'Complete 3 heroic missions',
  298. QUEST_10004: 'Fight 3 times in the Arena or Grand Arena',
  299. QUEST_10006: 'Use the exchange of emeralds 1 time',
  300. QUEST_10007: 'Perform 1 summon in the Solu Atrium',
  301. QUEST_10016: 'Send gifts to guildmates',
  302. QUEST_10018: 'Use an experience potion',
  303. QUEST_10019: 'Open 1 chest in the Tower',
  304. QUEST_10020: 'Open 3 chests in Outland',
  305. QUEST_10021: 'Collect 75 Titanite in the Guild Dungeon',
  306. QUEST_10021: 'Collect 150 Titanite in the Guild Dungeon',
  307. QUEST_10023: 'Upgrade Gift of the Elements by 1 level',
  308. QUEST_10024: 'Level up any artifact once',
  309. QUEST_10025: 'Start Expedition 1',
  310. QUEST_10026: 'Start 4 Expeditions',
  311. QUEST_10027: 'Win 1 battle of the Tournament of Elements',
  312. QUEST_10028: 'Level up any titan artifact',
  313. QUEST_10029: 'Unlock the Orb of Titan Artifacts',
  314. QUEST_10030: 'Upgrade any Skin of any hero 1 time',
  315. QUEST_10031: 'Win 6 battles of the Tournament of Elements',
  316. QUEST_10043: 'Start or Join an Adventure',
  317. QUEST_10044: 'Use Summon Pets 1 time',
  318. QUEST_10046: 'Open 3 chests in Adventure',
  319. QUEST_10047: 'Get 150 Guild Activity Points',
  320. NOTHING_TO_DO: 'Nothing to do',
  321. YOU_CAN_COMPLETE: 'You can complete quests',
  322. BTN_DO_IT: 'Do it',
  323. NOT_QUEST_COMPLETED: 'Not a single quest completed',
  324. COMPLETED_QUESTS: 'Completed quests',
  325. /* everything button */
  326. ASSEMBLE_OUTLAND: 'Assemble Outland',
  327. PASS_THE_TOWER: 'Pass the tower',
  328. CHECK_EXPEDITIONS: 'Check Expeditions',
  329. COMPLETE_TOE: 'Complete ToE',
  330. COMPLETE_DUNGEON: 'Complete the dungeon',
  331. COLLECT_MAIL: 'Collect mail',
  332. COLLECT_MISC: 'Collect some bullshit',
  333. COLLECT_MISC_TITLE: 'Collect Easter Eggs, Skin Gems, Keys, Arena Coins and Soul Crystal',
  334. COLLECT_QUEST_REWARDS: 'Collect quest rewards',
  335. MAKE_A_SYNC: 'Make a sync',
  336.  
  337. RUN_FUNCTION: 'Run the following functions?',
  338. BTN_GO: 'Go!',
  339. PERFORMED: 'Performed',
  340. DONE: 'Done',
  341. ERRORS_OCCURRES: 'Errors occurred while executing',
  342. COPY_ERROR: 'Copy error information to clipboard',
  343. BTN_YES: 'Yes',
  344. ALL_TASK_COMPLETED: 'All tasks completed',
  345.  
  346. UNKNOWN: 'unknown',
  347. ENTER_THE_PATH: 'Enter the path of adventure using commas or dashes',
  348. START_ADVENTURE: 'Start your adventure along this path!',
  349. INCORRECT_WAY: 'Incorrect path in adventure: {from} -> {to}',
  350. BTN_CANCELED: 'Canceled',
  351. MUST_TWO_POINTS: 'The path must contain at least 2 points.',
  352. MUST_ONLY_NUMBERS: 'The path must contain only numbers and commas',
  353. NOT_ON_AN_ADVENTURE: 'You are not on an adventure',
  354. YOU_IN_NOT_ON_THE_WAY: 'Your location is not on the way',
  355. ATTEMPTS_NOT_ENOUGH: 'Your attempts are not enough to complete the path, continue?',
  356. YES_CONTINUE: 'Yes, continue!',
  357. NOT_ENOUGH_AP: 'Not enough action points',
  358. ATTEMPTS_ARE_OVER: 'The attempts are over',
  359. MOVES: 'Moves',
  360. BUFF_GET_ERROR: 'Buff getting error',
  361. BATTLE_END_ERROR: 'Battle end error',
  362. AUTOBOT: 'Autobot',
  363. FAILED_TO_WIN_AUTO: 'Failed to win the auto battle',
  364. ERROR_OF_THE_BATTLE_COPY: 'An error occurred during the passage of the battle<br>Copy the error to the clipboard?',
  365. ERROR_DURING_THE_BATTLE: 'Error during the battle',
  366. NO_CHANCE_WIN: 'No chance of winning this fight: 0/',
  367. LOST_HEROES: 'You have won, but you have lost one or several heroes',
  368. VICTORY_IMPOSSIBLE: 'Is victory impossible, should we focus on the result?',
  369. FIND_COEFF: 'Find the coefficient greater than',
  370. BTN_PASS: 'PASS',
  371. BRAWLS: 'Brawls',
  372. BRAWLS_TITLE: 'Activates the ability to auto-brawl',
  373. START_AUTO_BRAWLS: 'Start Auto Brawls?',
  374. LOSSES: 'Losses',
  375. WINS: 'Wins',
  376. FIGHTS: 'Fights',
  377. STAGE: 'Stage',
  378. DONT_HAVE_LIVES: "You don't have lives",
  379. LIVES: 'Lives',
  380. SECRET_WEALTH_ALREADY: 'Item for Pet Potions already purchased',
  381. SECRET_WEALTH_NOT_ENOUGH: 'Not Enough Pet Potion, You Have {available}, Need {need}',
  382. SECRET_WEALTH_UPGRADE_NEW_PET: 'After purchasing the Pet Potion, it will not be enough to upgrade a new pet',
  383. SECRET_WEALTH_PURCHASED: 'Purchased {count} {name}',
  384. SECRET_WEALTH_CANCELED: 'Secret Wealth: Purchase Canceled',
  385. SECRET_WEALTH_BUY: 'You have {available} Pet Potion.<br>Do you want to buy {countBuy} {name} for {price} Pet Potion?',
  386. DAILY_BONUS: 'Daily bonus',
  387. DO_DAILY_QUESTS: 'Do daily quests',
  388. ACTIONS: 'Actions',
  389. ACTIONS_TITLE: 'Dialog box with various actions',
  390. OTHERS: 'Others',
  391. OTHERS_TITLE: 'Others',
  392. CHOOSE_ACTION: 'Choose an action',
  393. OPEN_LOOTBOX: 'You have {lootBox} boxes, should we open them?',
  394. STAMINA: 'Energy',
  395. BOXES_OVER: 'The boxes are over',
  396. NO_BOXES: 'No boxes',
  397. NO_MORE_ACTIVITY: 'No more activity for items today',
  398. EXCHANGE_ITEMS: 'Exchange items for activity points (max {maxActive})?',
  399. GET_ACTIVITY: 'Get Activity',
  400. NOT_ENOUGH_ITEMS: 'Not enough items',
  401. ACTIVITY_RECEIVED: 'Activity received',
  402. NO_PURCHASABLE_HERO_SOULS: 'No purchasable Hero Souls',
  403. PURCHASED_HERO_SOULS: 'Purchased {countHeroSouls} Hero Souls',
  404. NOT_ENOUGH_EMERALDS_540: 'Not enough emeralds, you need {imgEmerald}540 you have {imgEmerald}{currentStarMoney}',
  405. BUY_OUTLAND_BTN: 'Buy {count} chests {imgEmerald}{countEmerald}',
  406. CHESTS_NOT_AVAILABLE: 'Chests not available',
  407. OUTLAND_CHESTS_RECEIVED: 'Outland chests received',
  408. RAID_NOT_AVAILABLE: 'The raid is not available or there are no spheres',
  409. RAID_ADVENTURE: 'Raid {adventureId} adventure!',
  410. SOMETHING_WENT_WRONG: 'Something went wrong',
  411. ADVENTURE_COMPLETED: 'Adventure {adventureId} completed {times} times',
  412. CLAN_STAT_COPY: 'Clan statistics copied to clipboard',
  413. GET_ENERGY: 'Get Energy',
  414. GET_ENERGY_TITLE: 'Opens platinum boxes one at a time until you get 250 energy',
  415. ITEM_EXCHANGE: 'Item Exchange',
  416. ITEM_EXCHANGE_TITLE: 'Exchanges items for the specified amount of activity',
  417. BUY_SOULS: 'Buy souls',
  418. BUY_SOULS_TITLE: 'Buy hero souls from all available shops',
  419. BUY_OUTLAND: 'Buy Outland',
  420. BUY_OUTLAND_TITLE: 'Buy 9 chests in Outland for 540 emeralds',
  421. RAID: 'Raid',
  422. AUTO_RAID_ADVENTURE: 'Raid adventure',
  423. AUTO_RAID_ADVENTURE_TITLE: 'Raid adventure set number of times',
  424. CLAN_STAT: 'Clan statistics',
  425. CLAN_STAT_TITLE: 'Copies clan statistics to the clipboard',
  426. BTN_AUTO_F5: 'Auto (F5)',
  427. BOSS_DAMAGE: 'Boss Damage: ',
  428. NOTHING_BUY: 'Nothing to buy',
  429. LOTS_BOUGHT: '{countBuy} lots bought for gold',
  430. BUY_FOR_GOLD: 'Buy for gold',
  431. BUY_FOR_GOLD_TITLE: 'Buy items for gold in the Town Shop and in the Pet Soul Stone Shop',
  432. REWARDS_AND_MAIL: 'Rewards and Mail',
  433. REWARDS_AND_MAIL_TITLE: 'Collects rewards and mail',
  434. COLLECT_REWARDS_AND_MAIL: 'Collected {countQuests} rewards and {countMail} letters',
  435. TIMER_ALREADY: 'Timer already started {time}',
  436. NO_ATTEMPTS_TIMER_START: 'No attempts, timer started {time}',
  437. EPIC_BRAWL_RESULT: 'Wins: {wins}/{attempts}, Coins: {coins}, Streak: {progress}/{nextStage} [Close]{end}',
  438. ATTEMPT_ENDED: '<br>Attempts ended, timer started {time}',
  439. EPIC_BRAWL: 'Cosmic Battle',
  440. EPIC_BRAWL_TITLE: 'Spends attempts in the Cosmic Battle',
  441. RELOAD_GAME: 'Reload game',
  442. TIMER: 'Timer:',
  443. SHOW_ERRORS: 'Show errors',
  444. SHOW_ERRORS_TITLE: 'Show server request errors',
  445. ERROR_MSG: 'Error: {name}<br>{description}',
  446. EVENT_AUTO_BOSS:
  447. '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?',
  448. BEST_SLOW: 'Best (slower)',
  449. FIRST_FAST: 'First (faster)',
  450. FREEZE_INTERFACE: 'Calculating... <br>The interface may freeze.',
  451. ERROR_F12: 'Error, details in the console (F12)',
  452. FAILED_FIND_WIN_PACK: 'Failed to find a winning pack',
  453. BEST_PACK: 'Best pack:',
  454. BOSS_HAS_BEEN_DEF: 'Boss {bossLvl} has been defeated.',
  455. NOT_ENOUGH_ATTEMPTS_BOSS: 'Not enough attempts to defeat boss {bossLvl}, retry?',
  456. BOSS_VICTORY_IMPOSSIBLE:
  457. '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?',
  458. BOSS_HAS_BEEN_DEF_TEXT:
  459. 'Boss {bossLvl} defeated in<br>{countBattle}/{countMaxBattle} attempts<br>(Please synchronize or restart the game to update the data)',
  460. MAP: 'Map: ',
  461. PLAYER_POS: 'Player positions:',
  462. NY_GIFTS: 'Gifts',
  463. NY_GIFTS_TITLE: "Open all New Year's gifts",
  464. NY_NO_GIFTS: 'No gifts not received',
  465. NY_GIFTS_COLLECTED: '{count} gifts collected',
  466. CHANGE_MAP: 'Island map',
  467. CHANGE_MAP_TITLE: 'Change island map',
  468. SELECT_ISLAND_MAP: 'Select an island map:',
  469. MAP_NUM: 'Map {num}',
  470. SECRET_WEALTH_SHOP: 'Secret Wealth {name}: ',
  471. SHOPS: 'Shops',
  472. SHOPS_DEFAULT: 'Default',
  473. SHOPS_DEFAULT_TITLE: 'Default stores',
  474. SHOPS_LIST: 'Shops {number}',
  475. SHOPS_LIST_TITLE: 'List of shops {number}',
  476. SHOPS_WARNING:
  477. '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>',
  478. MINIONS_WARNING: 'The hero packs for attacking minions are incomplete, should I continue?',
  479. FAST_SEASON: 'Fast season',
  480. FAST_SEASON_TITLE: 'Skip the map selection screen in a season',
  481. SET_NUMBER_LEVELS: 'Specify the number of levels:',
  482. POSSIBLE_IMPROVE_LEVELS: 'It is possible to improve only {count} levels.<br>Improving?',
  483. NOT_ENOUGH_RESOURECES: 'Not enough resources',
  484. IMPROVED_LEVELS: 'Improved levels: {count}',
  485. ARTIFACTS_UPGRADE: 'Artifacts Upgrade',
  486. ARTIFACTS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero artifacts',
  487. SKINS_UPGRADE: 'Skins Upgrade',
  488. SKINS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero skins',
  489. HINT: '<br>Hint: ',
  490. PICTURE: '<br>Picture: ',
  491. ANSWER: '<br>Answer: ',
  492. NO_HEROES_PACK: 'Fight at least one battle to save the attacking team',
  493. BRAWL_AUTO_PACK: 'Automatic selection of packs',
  494. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Automatic pack selection is not suitable for the current hero',
  495. BRAWL_DAILY_TASK_COMPLETED: 'Daily task completed, continue attacking?',
  496. CALC_STAT: 'Calculate statistics',
  497. ELEMENT_TOURNAMENT_REWARD: 'Unclaimed bonus for Elemental Tournament',
  498. BTN_TRY_FIX_IT: 'Fix it (test)',
  499. DAMAGE_FIXED: 'Damage fixed from {lastDamage} to {maxDamage}!',
  500. DAMAGE_NO_FIXED: 'Failed to fix damage: {lastDamage}',
  501. LETS_FIX: "Let's fix...",
  502. DEFEAT_TURN_TIMER: 'Defeat! Turn on the timer to complete the mission?',
  503. },
  504. ru: {
  505. /* Чекбоксы */
  506. SKIP_FIGHTS: 'Пропуск боев',
  507. SKIP_FIGHTS_TITLE: 'Пропуск боев в запределье и арене титанов, автопропуск в башне и кампании',
  508. ENDLESS_CARDS: 'Бесконечные карты',
  509. ENDLESS_CARDS_TITLE: 'Отключить трату карт предсказаний',
  510. AUTO_EXPEDITION: 'АвтоЭкспедиции',
  511. AUTO_EXPEDITION_TITLE: 'Автоотправка экспедиций',
  512. CANCEL_FIGHT: 'Отмена боя',
  513. CANCEL_FIGHT_TITLE: 'Возможность отмены ручного боя на ВГ, СМ и в Асгарде',
  514. GIFTS: 'Подарки',
  515. GIFTS_TITLE: 'Собирать подарки автоматически',
  516. BATTLE_RECALCULATION: 'Прерасчет боя',
  517. BATTLE_RECALCULATION_TITLE: 'Предварительный расчет боя',
  518. QUANTITY_CONTROL: 'Контроль кол-ва',
  519. QUANTITY_CONTROL_TITLE: 'Возможность указывать количество открываемых "лутбоксов"',
  520. REPEAT_CAMPAIGN: 'Повтор в кампании',
  521. REPEAT_CAMPAIGN_TITLE: 'Автоповтор боев в кампании',
  522. DISABLE_DONAT: 'Отключить донат',
  523. DISABLE_DONAT_TITLE: 'Убирает все предложения доната',
  524. DAILY_QUESTS: 'Квесты',
  525. DAILY_QUESTS_TITLE: 'Выполнять ежедневные квесты',
  526. AUTO_QUIZ: 'АвтоВикторина',
  527. AUTO_QUIZ_TITLE: 'Автоматическое получение правильных ответов на вопросы викторины',
  528. SECRET_WEALTH_CHECKBOX: 'Автоматическая покупка в магазине "Тайное Богатство" при заходе в игру',
  529. HIDE_SERVERS: 'Свернуть сервера',
  530. HIDE_SERVERS_TITLE: 'Скрывать неиспользуемые сервера',
  531. /* Поля ввода */
  532. HOW_MUCH_TITANITE: 'Сколько фармим титанита',
  533. COMBAT_SPEED: 'Множитель ускорения боя',
  534. NUMBER_OF_TEST: 'Количество тестовых боев',
  535. NUMBER_OF_AUTO_BATTLE: 'Количество попыток автобоев',
  536. /* Кнопки */
  537. RUN_SCRIPT: 'Запустить скрипт',
  538. TO_DO_EVERYTHING: 'Сделать все',
  539. TO_DO_EVERYTHING_TITLE: 'Выполнить несколько действий',
  540. OUTLAND: 'Запределье',
  541. OUTLAND_TITLE: 'Собрать Запределье',
  542. TITAN_ARENA: 'Турнир Стихий',
  543. TITAN_ARENA_TITLE: 'Автопрохождение Турнира Стихий',
  544. DUNGEON: 'Подземелье',
  545. DUNGEON_TITLE: 'Автопрохождение подземелья',
  546. SEER: 'Провидец',
  547. SEER_TITLE: 'Покрутить Провидца',
  548. TOWER: 'Башня',
  549. TOWER_TITLE: 'Автопрохождение башни',
  550. EXPEDITIONS: 'Экспедиции',
  551. EXPEDITIONS_TITLE: 'Отправка и сбор экспедиций',
  552. SYNC: 'Синхронизация',
  553. SYNC_TITLE: 'Частичная синхронизация данных игры без перезагрузки сатраницы',
  554. ARCHDEMON: 'Архидемон',
  555. ARCHDEMON_TITLE: 'Набивает килы и собирает награду',
  556. ESTER_EGGS: 'Пасхалки',
  557. ESTER_EGGS_TITLE: 'Собрать все пасхалки или награды',
  558. REWARDS: 'Награды',
  559. REWARDS_TITLE: 'Собрать все награды за задания',
  560. MAIL: 'Почта',
  561. MAIL_TITLE: 'Собрать всю почту, кроме писем с энергией и зарядами портала',
  562. MINIONS: 'Прислужники',
  563. MINIONS_TITLE: 'Атакует прислужников сохраннеными пачками',
  564. ADVENTURE: 'Приключение',
  565. ADVENTURE_TITLE: 'Проходит приключение по указанному маршруту',
  566. STORM: 'Буря',
  567. STORM_TITLE: 'Проходит бурю по указанному маршруту',
  568. SANCTUARY: 'Святилище',
  569. SANCTUARY_TITLE: 'Быстрый переход к Святилищу',
  570. GUILD_WAR: 'Война гильдий',
  571. GUILD_WAR_TITLE: 'Быстрый переход к Войне гильдий',
  572. SECRET_WEALTH: 'Тайное богатство',
  573. SECRET_WEALTH_TITLE: 'Купить что-то в магазине "Тайное богатство"',
  574. /* Разное */
  575. BOTTOM_URLS:
  576. '<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>',
  577. GIFTS_SENT: 'Подарки отправлены!',
  578. DO_YOU_WANT: 'Вы действительно хотите это сделать?',
  579. BTN_RUN: 'Запускай',
  580. BTN_CANCEL: 'Отмена',
  581. BTN_OK: 'Ок',
  582. MSG_HAVE_BEEN_DEFEATED: 'Вы потерпели поражение!',
  583. BTN_AUTO: 'Авто',
  584. MSG_YOU_APPLIED: 'Вы нанесли',
  585. MSG_DAMAGE: 'урона',
  586. MSG_CANCEL_AND_STAT: 'Авто (F5) и показать Статистику',
  587. MSG_REPEAT_MISSION: 'Повторить миссию?',
  588. BTN_REPEAT: 'Повторить',
  589. BTN_NO: 'Нет',
  590. MSG_SPECIFY_QUANT: 'Указать количество:',
  591. BTN_OPEN: 'Открыть',
  592. QUESTION_COPY: 'Вопрос скопирован в буфер обмена',
  593. ANSWER_KNOWN: 'Ответ известен',
  594. ANSWER_NOT_KNOWN: 'ВНИМАНИЕ ОТВЕТ НЕ ИЗВЕСТЕН',
  595. BEING_RECALC: 'Идет прерасчет боя',
  596. THIS_TIME: 'На этот раз',
  597. VICTORY: '<span style="color:green;">ПОБЕДА</span>',
  598. DEFEAT: '<span style="color:red;">ПОРАЖЕНИЕ</span>',
  599. CHANCE_TO_WIN: 'Шансы на победу <span style="color:red;">на основе прерасчета</span>',
  600. OPEN_DOLLS: 'матрешек рекурсивно',
  601. SENT_QUESTION: 'Вопрос отправлен',
  602. SETTINGS: 'Настройки',
  603. MSG_BAN_ATTENTION: '<p style="color:red;">Использование этой функции может привести к бану.</p> Продолжить?',
  604. BTN_YES_I_AGREE: 'Да, я беру на себя все риски!',
  605. BTN_NO_I_AM_AGAINST: 'Нет, я отказываюсь от этого!',
  606. VALUES: 'Значения',
  607. EXPEDITIONS_SENT: 'Экспедиции:<br>Собрано: {countGet}<br>Отправлено: {countSend}',
  608. EXPEDITIONS_NOTHING: 'Нечего собирать/отправлять',
  609. TITANIT: 'Титанит',
  610. COMPLETED: 'завершено',
  611. FLOOR: 'Этаж',
  612. LEVEL: 'Уровень',
  613. BATTLES: 'бои',
  614. EVENT: 'Эвент',
  615. NOT_AVAILABLE: 'недоступен',
  616. NO_HEROES: 'Нет героев',
  617. DAMAGE_AMOUNT: 'Количество урона',
  618. NOTHING_TO_COLLECT: 'Нечего собирать',
  619. COLLECTED: 'Собрано',
  620. REWARD: 'наград',
  621. REMAINING_ATTEMPTS: 'Осталось попыток',
  622. BATTLES_CANCELED: 'Битв отменено',
  623. MINION_RAID: 'Рейд прислужников',
  624. STOPPED: 'Остановлено',
  625. REPETITIONS: 'Повторений',
  626. MISSIONS_PASSED: 'Миссий пройдено',
  627. STOP: 'остановить',
  628. TOTAL_OPEN: 'Всего открыто',
  629. OPEN: 'Открыто',
  630. ROUND_STAT: 'Статистика урона за',
  631. BATTLE: 'боев',
  632. MINIMUM: 'Минимальный',
  633. MAXIMUM: 'Максимальный',
  634. AVERAGE: 'Средний',
  635. NOT_THIS_TIME: 'Не в этот раз',
  636. RETRY_LIMIT_EXCEEDED: 'Превышен лимит попыток',
  637. SUCCESS: 'Успех',
  638. RECEIVED: 'Получено',
  639. LETTERS: 'писем',
  640. PORTALS: 'порталов',
  641. ATTEMPTS: 'попыток',
  642. QUEST_10001: 'Улучши умения героев 3 раза',
  643. QUEST_10002: 'Пройди 10 миссий',
  644. QUEST_10003: 'Пройди 3 героические миссии',
  645. QUEST_10004: 'Сразись 3 раза на Арене или Гранд Арене',
  646. QUEST_10006: 'Используй обмен изумрудов 1 раз',
  647. QUEST_10007: 'Соверши 1 призыв в Атриуме Душ',
  648. QUEST_10016: 'Отправь подарки согильдийцам',
  649. QUEST_10018: 'Используй зелье опыта',
  650. QUEST_10019: 'Открой 1 сундук в Башне',
  651. QUEST_10020: 'Открой 3 сундука в Запределье',
  652. QUEST_10021: 'Собери 75 Титанита в Подземелье Гильдии',
  653. QUEST_10021: 'Собери 150 Титанита в Подземелье Гильдии',
  654. QUEST_10023: 'Прокачай Дар Стихий на 1 уровень',
  655. QUEST_10024: 'Повысь уровень любого артефакта один раз',
  656. QUEST_10025: 'Начни 1 Экспедицию',
  657. QUEST_10026: 'Начни 4 Экспедиции',
  658. QUEST_10027: 'Победи в 1 бою Турнира Стихий',
  659. QUEST_10028: 'Повысь уровень любого артефакта титанов',
  660. QUEST_10029: 'Открой сферу артефактов титанов',
  661. QUEST_10030: 'Улучши облик любого героя 1 раз',
  662. QUEST_10031: 'Победи в 6 боях Турнира Стихий',
  663. QUEST_10043: 'Начни или присоеденись к Приключению',
  664. QUEST_10044: 'Воспользуйся призывом питомцев 1 раз',
  665. QUEST_10046: 'Открой 3 сундука в Приключениях',
  666. QUEST_10047: 'Набери 150 очков активности в Гильдии',
  667. NOTHING_TO_DO: 'Нечего выполнять',
  668. YOU_CAN_COMPLETE: 'Можно выполнить квесты',
  669. BTN_DO_IT: 'Выполняй',
  670. NOT_QUEST_COMPLETED: 'Ни одного квеста не выполенно',
  671. COMPLETED_QUESTS: 'Выполнено квестов',
  672. /* everything button */
  673. ASSEMBLE_OUTLAND: 'Собрать Запределье',
  674. PASS_THE_TOWER: 'Пройти башню',
  675. CHECK_EXPEDITIONS: 'Проверить экспедиции',
  676. COMPLETE_TOE: 'Пройти Турнир Стихий',
  677. COMPLETE_DUNGEON: 'Пройти подземелье',
  678. COLLECT_MAIL: 'Собрать почту',
  679. COLLECT_MISC: 'Собрать всякую херню',
  680. COLLECT_MISC_TITLE: 'Собрать пасхалки, камни облика, ключи, монеты арены и Хрусталь души',
  681. COLLECT_QUEST_REWARDS: 'Собрать награды за квесты',
  682. MAKE_A_SYNC: 'Сделать синхронизацию',
  683.  
  684. RUN_FUNCTION: 'Выполнить следующие функции?',
  685. BTN_GO: 'Погнали!',
  686. PERFORMED: 'Выполняется',
  687. DONE: 'Выполнено',
  688. ERRORS_OCCURRES: 'Призошли ошибки при выполнении',
  689. COPY_ERROR: 'Скопировать в буфер информацию об ошибке',
  690. BTN_YES: 'Да',
  691. ALL_TASK_COMPLETED: 'Все задачи выполнены',
  692.  
  693. UNKNOWN: 'Неизвестно',
  694. ENTER_THE_PATH: 'Введите путь приключения через запятые или дефисы',
  695. START_ADVENTURE: 'Начать приключение по этому пути!',
  696. INCORRECT_WAY: 'Неверный путь в приключении: {from} -> {to}',
  697. BTN_CANCELED: 'Отменено',
  698. MUST_TWO_POINTS: 'Путь должен состоять минимум из 2х точек',
  699. MUST_ONLY_NUMBERS: 'Путь должен содержать только цифры и запятые',
  700. NOT_ON_AN_ADVENTURE: 'Вы не в приключении',
  701. YOU_IN_NOT_ON_THE_WAY: 'Указанный путь должен включать точку вашего положения',
  702. ATTEMPTS_NOT_ENOUGH: 'Ваших попыток не достаточно для завершения пути, продолжить?',
  703. YES_CONTINUE: 'Да, продолжай!',
  704. NOT_ENOUGH_AP: 'Попыток не достаточно',
  705. ATTEMPTS_ARE_OVER: 'Попытки закончились',
  706. MOVES: 'Ходы',
  707. BUFF_GET_ERROR: 'Ошибка при получении бафа',
  708. BATTLE_END_ERROR: 'Ошибка завершения боя',
  709. AUTOBOT: 'АвтоБой',
  710. FAILED_TO_WIN_AUTO: 'Не удалось победить в автобою',
  711. ERROR_OF_THE_BATTLE_COPY: 'Призошли ошибка в процессе прохождения боя<br>Скопировать ошибку в буфер обмена?',
  712. ERROR_DURING_THE_BATTLE: 'Ошибка в процессе прохождения боя',
  713. NO_CHANCE_WIN: 'Нет шансов победить в этом бою: 0/',
  714. LOST_HEROES: 'Вы победили, но потеряли одного или несколько героев!',
  715. VICTORY_IMPOSSIBLE: 'Победа не возможна, бъем на результат?',
  716. FIND_COEFF: 'Поиск коэффициента больше чем',
  717. BTN_PASS: 'ПРОПУСК',
  718. BRAWLS: 'Потасовки',
  719. BRAWLS_TITLE: 'Включает возможность автопотасовок',
  720. START_AUTO_BRAWLS: 'Запустить Автопотасовки?',
  721. LOSSES: 'Поражений',
  722. WINS: 'Побед',
  723. FIGHTS: 'Боев',
  724. STAGE: 'Стадия',
  725. DONT_HAVE_LIVES: 'У Вас нет жизней',
  726. LIVES: 'Жизни',
  727. SECRET_WEALTH_ALREADY: 'товар за Зелья питомцев уже куплен',
  728. SECRET_WEALTH_NOT_ENOUGH: 'Не достаточно Зелье Питомца, у Вас {available}, нужно {need}',
  729. SECRET_WEALTH_UPGRADE_NEW_PET: 'После покупки Зелье Питомца будет не достаточно для прокачки нового питомца',
  730. SECRET_WEALTH_PURCHASED: 'Куплено {count} {name}',
  731. SECRET_WEALTH_CANCELED: 'Тайное богатство: покупка отменена',
  732. SECRET_WEALTH_BUY: 'У вас {available} Зелье Питомца.<br>Вы хотите купить {countBuy} {name} за {price} Зелье Питомца?',
  733. DAILY_BONUS: 'Ежедневная награда',
  734. DO_DAILY_QUESTS: 'Сделать ежедневные квесты',
  735. ACTIONS: 'Действия',
  736. ACTIONS_TITLE: 'Диалоговое окно с различными действиями',
  737. OTHERS: 'Разное',
  738. OTHERS_TITLE: 'Диалоговое окно с дополнительными различными действиями',
  739. CHOOSE_ACTION: 'Выберите действие',
  740. OPEN_LOOTBOX: 'У Вас {lootBox} ящиков, откываем?',
  741. STAMINA: 'Энергия',
  742. BOXES_OVER: 'Ящики закончились',
  743. NO_BOXES: 'Нет ящиков',
  744. NO_MORE_ACTIVITY: 'Больше активности за предметы сегодня не получить',
  745. EXCHANGE_ITEMS: 'Обменять предметы на очки активности (не более {maxActive})?',
  746. GET_ACTIVITY: 'Получить активность',
  747. NOT_ENOUGH_ITEMS: 'Предметов недостаточно',
  748. ACTIVITY_RECEIVED: 'Получено активности',
  749. NO_PURCHASABLE_HERO_SOULS: 'Нет доступных для покупки душ героев',
  750. PURCHASED_HERO_SOULS: 'Куплено {countHeroSouls} душ героев',
  751. NOT_ENOUGH_EMERALDS_540: 'Недостаточно изюма, нужно {imgEmerald}540 у Вас {imgEmerald}{currentStarMoney}',
  752. BUY_OUTLAND_BTN: 'Купить {count} сундуков {imgEmerald}{countEmerald}',
  753. CHESTS_NOT_AVAILABLE: 'Сундуки не доступны',
  754. OUTLAND_CHESTS_RECEIVED: 'Получено сундуков Запределья',
  755. RAID_NOT_AVAILABLE: 'Рейд не доступен или сфер нет',
  756. RAID_ADVENTURE: 'Рейд {adventureId} приключения!',
  757. SOMETHING_WENT_WRONG: 'Что-то пошло не так',
  758. ADVENTURE_COMPLETED: 'Приключение {adventureId} пройдено {times} раз',
  759. CLAN_STAT_COPY: 'Клановая статистика скопирована в буфер обмена',
  760. GET_ENERGY: 'Получить энергию',
  761. GET_ENERGY_TITLE: 'Открывает платиновые шкатулки по одной до получения 250 энергии',
  762. ITEM_EXCHANGE: 'Обмен предметов',
  763. ITEM_EXCHANGE_TITLE: 'Обменивает предметы на указанное количество активности',
  764. BUY_SOULS: 'Купить души',
  765. BUY_SOULS_TITLE: 'Купить души героев из всех доступных магазинов',
  766. BUY_OUTLAND: 'Купить Запределье',
  767. BUY_OUTLAND_TITLE: 'Купить 9 сундуков в Запределье за 540 изумрудов',
  768. RAID: 'Рейд',
  769. AUTO_RAID_ADVENTURE: 'Рейд приключения',
  770. AUTO_RAID_ADVENTURE_TITLE: 'Рейд приключения заданное количество раз',
  771. CLAN_STAT: 'Клановая статистика',
  772. CLAN_STAT_TITLE: 'Копирует клановую статистику в буфер обмена',
  773. BTN_AUTO_F5: 'Авто (F5)',
  774. BOSS_DAMAGE: 'Урон по боссу: ',
  775. NOTHING_BUY: 'Нечего покупать',
  776. LOTS_BOUGHT: 'За золото куплено {countBuy} лотов',
  777. BUY_FOR_GOLD: 'Скупить за золото',
  778. BUY_FOR_GOLD_TITLE: 'Скупить предметы за золото в Городской лавке и в магазине Камней Душ Питомцев',
  779. REWARDS_AND_MAIL: 'Награды и почта',
  780. REWARDS_AND_MAIL_TITLE: 'Собирает награды и почту',
  781. COLLECT_REWARDS_AND_MAIL: 'Собрано {countQuests} наград и {countMail} писем',
  782. TIMER_ALREADY: 'Таймер уже запущен {time}',
  783. NO_ATTEMPTS_TIMER_START: 'Попыток нет, запущен таймер {time}',
  784. EPIC_BRAWL_RESULT: '{i} Победы: {wins}/{attempts}, Монеты: {coins}, Серия: {progress}/{nextStage} [Закрыть]{end}',
  785. ATTEMPT_ENDED: '<br>Попытки закончились, запущен таймер {time}',
  786. EPIC_BRAWL: 'Вселенская битва',
  787. EPIC_BRAWL_TITLE: 'Тратит попытки во Вселенской битве',
  788. RELOAD_GAME: 'Перезагрузить игру',
  789. TIMER: 'Таймер:',
  790. SHOW_ERRORS: 'Отображать ошибки',
  791. SHOW_ERRORS_TITLE: 'Отображать ошибки запросов к серверу',
  792. ERROR_MSG: 'Ошибка: {name}<br>{description}',
  793. EVENT_AUTO_BOSS:
  794. 'Максимальное количество боев для расчета:</br>{length} * {countTestBattle} = {maxCalcBattle}</br>Если у Вас слабый компьютер на это может потребоваться много времени, нажмите крестик для отмены.</br>Искать лучший пак из всех или первый подходящий?',
  795. BEST_SLOW: 'Лучший (медленее)',
  796. FIRST_FAST: 'Первый (быстрее)',
  797. FREEZE_INTERFACE: 'Идет расчет... <br> Интерфейс может зависнуть.',
  798. ERROR_F12: 'Ошибка, подробности в консоли (F12)',
  799. FAILED_FIND_WIN_PACK: 'Победный пак найти не удалось',
  800. BEST_PACK: 'Наилучший пак: ',
  801. BOSS_HAS_BEEN_DEF: 'Босс {bossLvl} побежден',
  802. NOT_ENOUGH_ATTEMPTS_BOSS: 'Для победы босса ${bossLvl} не хватило попыток, повторить?',
  803. BOSS_VICTORY_IMPOSSIBLE:
  804. 'По результатам прерасчета {battles} боев победу получить не удалось. Вы хотите продолжить поиск победного боя на реальных боях?',
  805. BOSS_HAS_BEEN_DEF_TEXT:
  806. 'Босс {bossLvl} побежден за<br>{countBattle}/{countMaxBattle} попыток<br>(Сделайте синхронизацию или перезагрузите игру для обновления данных)',
  807. MAP: 'Карта: ',
  808. PLAYER_POS: 'Позиции игроков:',
  809. NY_GIFTS: 'Подарки',
  810. NY_GIFTS_TITLE: 'Открыть все новогодние подарки',
  811. NY_NO_GIFTS: 'Нет не полученных подарков',
  812. NY_GIFTS_COLLECTED: 'Собрано {count} подарков',
  813. CHANGE_MAP: 'Карта острова',
  814. CHANGE_MAP_TITLE: 'Сменить карту острова',
  815. SELECT_ISLAND_MAP: 'Выберите карту острова:',
  816. MAP_NUM: 'Карта {num}',
  817. SECRET_WEALTH_SHOP: 'Тайное богатство {name}: ',
  818. SHOPS: 'Магазины',
  819. SHOPS_DEFAULT: 'Стандартные',
  820. SHOPS_DEFAULT_TITLE: 'Стандартные магазины',
  821. SHOPS_LIST: 'Магазины {number}',
  822. SHOPS_LIST_TITLE: 'Список магазинов {number}',
  823. SHOPS_WARNING:
  824. 'Магазины<br><span style="color:red">Если Вы купите монеты магазинов потасовок за изумруды, то их надо использовать сразу, иначе после перезагрузки игры они пропадут!</span>',
  825. MINIONS_WARNING: 'Пачки героев для атаки приспешников неполные, продолжить?',
  826. FAST_SEASON: 'Быстрый сезон',
  827. FAST_SEASON_TITLE: 'Пропуск экрана с выбором карты в сезоне',
  828. SET_NUMBER_LEVELS: 'Указать колличество уровней:',
  829. POSSIBLE_IMPROVE_LEVELS: 'Возможно улучшить только {count} уровней.<br>Улучшаем?',
  830. NOT_ENOUGH_RESOURECES: 'Не хватает ресурсов',
  831. IMPROVED_LEVELS: 'Улучшено уровней: {count}',
  832. ARTIFACTS_UPGRADE: 'Улучшение артефактов',
  833. ARTIFACTS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых артефактов героев',
  834. SKINS_UPGRADE: 'Улучшение обликов',
  835. SKINS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых обликов героев',
  836. HINT: '<br>Подсказка: ',
  837. PICTURE: '<br>На картинке: ',
  838. ANSWER: '<br>Ответ: ',
  839. NO_HEROES_PACK: 'Проведите хотя бы один бой для сохранения атакующей команды',
  840. BRAWL_AUTO_PACK: 'Автоподбор пачки',
  841. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Автоматический подбор пачки не подходит для текущего героя',
  842. BRAWL_DAILY_TASK_COMPLETED: 'Ежедневное задание выполнено, продолжить атаку?',
  843. CALC_STAT: 'Посчитать статистику',
  844. ELEMENT_TOURNAMENT_REWARD: 'Несобранная награда за Турнир Стихий',
  845. BTN_TRY_FIX_IT: 'Исправить (тест)',
  846. DAMAGE_FIXED: 'Урон исправлен с {lastDamage} до {maxDamage}!',
  847. DAMAGE_NO_FIXED: 'Не удалось исправить урон: {lastDamage}',
  848. LETS_FIX: 'Исправляем...',
  849. DEFEAT_TURN_TIMER: 'Поражение! Включить таймер для завершения миссии?',
  850. },
  851. };
  852.  
  853. function getLang() {
  854. let lang = '';
  855. if (typeof NXFlashVars !== 'undefined') {
  856. lang = NXFlashVars.interface_lang
  857. }
  858. if (!lang) {
  859. lang = (navigator.language || navigator.userLanguage).substr(0, 2);
  860. }
  861. if (lang == 'ru') {
  862. return lang;
  863. }
  864. return 'en';
  865. }
  866.  
  867. this.I18N = function (constant, replace) {
  868. const selectLang = getLang();
  869. if (constant && constant in i18nLangData[selectLang]) {
  870. const result = i18nLangData[selectLang][constant];
  871. if (replace) {
  872. return result.sprintf(replace);
  873. }
  874. return result;
  875. }
  876. return `% ${constant} %`;
  877. };
  878.  
  879. String.prototype.sprintf = String.prototype.sprintf ||
  880. function () {
  881. "use strict";
  882. var str = this.toString();
  883. if (arguments.length) {
  884. var t = typeof arguments[0];
  885. var key;
  886. var args = ("string" === t || "number" === t) ?
  887. Array.prototype.slice.call(arguments)
  888. : arguments[0];
  889.  
  890. for (key in args) {
  891. str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
  892. }
  893. }
  894.  
  895. return str;
  896. };
  897.  
  898. /**
  899. * Checkboxes
  900. *
  901. * Чекбоксы
  902. */
  903. const checkboxes = {
  904. passBattle: {
  905. label: I18N('SKIP_FIGHTS'),
  906. cbox: null,
  907. title: I18N('SKIP_FIGHTS_TITLE'),
  908. default: false,
  909. },
  910. sendExpedition: {
  911. label: I18N('AUTO_EXPEDITION'),
  912. cbox: null,
  913. title: I18N('AUTO_EXPEDITION_TITLE'),
  914. default: false,
  915. },
  916. cancelBattle: {
  917. label: I18N('CANCEL_FIGHT'),
  918. cbox: null,
  919. title: I18N('CANCEL_FIGHT_TITLE'),
  920. default: false,
  921. },
  922. preCalcBattle: {
  923. label: I18N('BATTLE_RECALCULATION'),
  924. cbox: null,
  925. title: I18N('BATTLE_RECALCULATION_TITLE'),
  926. default: false,
  927. },
  928. countControl: {
  929. label: I18N('QUANTITY_CONTROL'),
  930. cbox: null,
  931. title: I18N('QUANTITY_CONTROL_TITLE'),
  932. default: true,
  933. },
  934. repeatMission: {
  935. label: I18N('REPEAT_CAMPAIGN'),
  936. cbox: null,
  937. title: I18N('REPEAT_CAMPAIGN_TITLE'),
  938. default: false,
  939. },
  940. noOfferDonat: {
  941. label: I18N('DISABLE_DONAT'),
  942. cbox: null,
  943. title: I18N('DISABLE_DONAT_TITLE'),
  944. /**
  945. * A crutch to get the field before getting the character id
  946. *
  947. * Костыль чтоб получать поле до получения id персонажа
  948. */
  949. default: (() => {
  950. $result = false;
  951. try {
  952. $result = JSON.parse(localStorage[GM_info.script.name + ':noOfferDonat']);
  953. } catch (e) {
  954. $result = false;
  955. }
  956. return $result || false;
  957. })(),
  958. },
  959. dailyQuests: {
  960. label: I18N('DAILY_QUESTS'),
  961. cbox: null,
  962. title: I18N('DAILY_QUESTS_TITLE'),
  963. default: false,
  964. },
  965. // Потасовки
  966. autoBrawls: {
  967. label: I18N('BRAWLS'),
  968. cbox: null,
  969. title: I18N('BRAWLS_TITLE'),
  970. default: (() => {
  971. $result = false;
  972. try {
  973. $result = JSON.parse(localStorage[GM_info.script.name + ':autoBrawls']);
  974. } catch (e) {
  975. $result = false;
  976. }
  977. return $result || false;
  978. })(),
  979. hide: false,
  980. },
  981. getAnswer: {
  982. label: I18N('AUTO_QUIZ'),
  983. cbox: null,
  984. title: I18N('AUTO_QUIZ_TITLE'),
  985. default: false,
  986. hide: false,
  987. },
  988. showErrors: {
  989. label: I18N('SHOW_ERRORS'),
  990. cbox: null,
  991. title: I18N('SHOW_ERRORS_TITLE'),
  992. default: true,
  993. },
  994. buyForGold: {
  995. label: I18N('BUY_FOR_GOLD'),
  996. cbox: null,
  997. title: I18N('BUY_FOR_GOLD_TITLE'),
  998. default: false,
  999. },
  1000. hideServers: {
  1001. label: I18N('HIDE_SERVERS'),
  1002. cbox: null,
  1003. title: I18N('HIDE_SERVERS_TITLE'),
  1004. default: false,
  1005. },
  1006. fastSeason: {
  1007. label: I18N('FAST_SEASON'),
  1008. cbox: null,
  1009. title: I18N('FAST_SEASON_TITLE'),
  1010. default: false,
  1011. },
  1012. };
  1013. /**
  1014. * Get checkbox state
  1015. *
  1016. * Получить состояние чекбокса
  1017. */
  1018. function isChecked(checkBox) {
  1019. if (!(checkBox in checkboxes)) {
  1020. return false;
  1021. }
  1022. return checkboxes[checkBox].cbox?.checked;
  1023. }
  1024. /**
  1025. * Input fields
  1026. *
  1027. * Поля ввода
  1028. */
  1029. const inputs = {
  1030. countTitanit: {
  1031. input: null,
  1032. title: I18N('HOW_MUCH_TITANITE'),
  1033. default: 150,
  1034. },
  1035. speedBattle: {
  1036. input: null,
  1037. title: I18N('COMBAT_SPEED'),
  1038. default: 5,
  1039. },
  1040. countTestBattle: {
  1041. input: null,
  1042. title: I18N('NUMBER_OF_TEST'),
  1043. default: 10,
  1044. },
  1045. countAutoBattle: {
  1046. input: null,
  1047. title: I18N('NUMBER_OF_AUTO_BATTLE'),
  1048. default: 10,
  1049. },
  1050. FPS: {
  1051. input: null,
  1052. title: 'FPS',
  1053. default: 60,
  1054. }
  1055. }
  1056. /**
  1057. * Checks the checkbox
  1058. *
  1059. * Поплучить данные поля ввода
  1060. */
  1061. function getInput(inputName) {
  1062. return inputs[inputName]?.input?.value;
  1063. }
  1064.  
  1065. /**
  1066. * Control FPS
  1067. *
  1068. * Контроль FPS
  1069. */
  1070. let nextAnimationFrame = Date.now();
  1071. const oldRequestAnimationFrame = this.requestAnimationFrame;
  1072. this.requestAnimationFrame = async function (e) {
  1073. const FPS = Number(getInput('FPS')) || -1;
  1074. const now = Date.now();
  1075. const delay = nextAnimationFrame - now;
  1076. nextAnimationFrame = Math.max(now, nextAnimationFrame) + Math.min(1e3 / FPS, 1e3);
  1077. if (delay > 0) {
  1078. await new Promise((e) => setTimeout(e, delay));
  1079. }
  1080. oldRequestAnimationFrame(e);
  1081. };
  1082. /**
  1083. * Button List
  1084. *
  1085. * Список кнопочек
  1086. */
  1087. const buttons = {
  1088. getOutland: {
  1089. name: I18N('TO_DO_EVERYTHING'),
  1090. title: I18N('TO_DO_EVERYTHING_TITLE'),
  1091. func: testDoYourBest,
  1092. },
  1093. doActions: {
  1094. name: I18N('ACTIONS'),
  1095. title: I18N('ACTIONS_TITLE'),
  1096. func: async function () {
  1097. const popupButtons = [
  1098. {
  1099. msg: I18N('OUTLAND'),
  1100. result: function () {
  1101. confShow(`${I18N('RUN_SCRIPT')} ${I18N('OUTLAND')}?`, getOutland);
  1102. },
  1103. title: I18N('OUTLAND_TITLE'),
  1104. },
  1105. {
  1106. msg: I18N('TOWER'),
  1107. result: function () {
  1108. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TOWER')}?`, testTower);
  1109. },
  1110. title: I18N('TOWER_TITLE'),
  1111. },
  1112. {
  1113. msg: I18N('EXPEDITIONS'),
  1114. result: function () {
  1115. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EXPEDITIONS')}?`, checkExpedition);
  1116. },
  1117. title: I18N('EXPEDITIONS_TITLE'),
  1118. },
  1119. {
  1120. msg: I18N('MINIONS'),
  1121. result: function () {
  1122. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MINIONS')}?`, testRaidNodes);
  1123. },
  1124. title: I18N('MINIONS_TITLE'),
  1125. },
  1126. {
  1127. msg: I18N('ESTER_EGGS'),
  1128. result: function () {
  1129. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ESTER_EGGS')}?`, offerFarmAllReward);
  1130. },
  1131. title: I18N('ESTER_EGGS_TITLE'),
  1132. },
  1133. {
  1134. msg: I18N('STORM'),
  1135. result: function () {
  1136. testAdventure('solo');
  1137. },
  1138. title: I18N('STORM_TITLE'),
  1139. },
  1140. {
  1141. msg: I18N('REWARDS'),
  1142. result: function () {
  1143. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS')}?`, questAllFarm);
  1144. },
  1145. title: I18N('REWARDS_TITLE'),
  1146. },
  1147. {
  1148. msg: I18N('MAIL'),
  1149. result: function () {
  1150. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MAIL')}?`, mailGetAll);
  1151. },
  1152. title: I18N('MAIL_TITLE'),
  1153. },
  1154. {
  1155. msg: I18N('SEER'),
  1156. result: function () {
  1157. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SEER')}?`, rollAscension);
  1158. },
  1159. title: I18N('SEER_TITLE'),
  1160. },
  1161. /*
  1162. {
  1163. msg: I18N('NY_GIFTS'),
  1164. result: getGiftNewYear,
  1165. title: I18N('NY_GIFTS_TITLE'),
  1166. },
  1167. */
  1168. ];
  1169. popupButtons.push({ result: false, isClose: true })
  1170. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1171. if (typeof answer === 'function') {
  1172. answer();
  1173. }
  1174. }
  1175. },
  1176. doOthers: {
  1177. name: I18N('OTHERS'),
  1178. title: I18N('OTHERS_TITLE'),
  1179. func: async function () {
  1180. const popupButtons = [
  1181. {
  1182. msg: I18N('GET_ENERGY'),
  1183. result: farmStamina,
  1184. title: I18N('GET_ENERGY_TITLE'),
  1185. },
  1186. {
  1187. msg: I18N('ITEM_EXCHANGE'),
  1188. result: fillActive,
  1189. title: I18N('ITEM_EXCHANGE_TITLE'),
  1190. },
  1191. {
  1192. msg: I18N('BUY_SOULS'),
  1193. result: function () {
  1194. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_SOULS')}?`, buyHeroFragments);
  1195. },
  1196. title: I18N('BUY_SOULS_TITLE'),
  1197. },
  1198. {
  1199. msg: I18N('BUY_FOR_GOLD'),
  1200. result: function () {
  1201. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_FOR_GOLD')}?`, buyInStoreForGold);
  1202. },
  1203. title: I18N('BUY_FOR_GOLD_TITLE'),
  1204. },
  1205. {
  1206. msg: I18N('BUY_OUTLAND'),
  1207. result: bossOpenChestPay,
  1208. title: I18N('BUY_OUTLAND_TITLE'),
  1209. },
  1210. {
  1211. msg: I18N('AUTO_RAID_ADVENTURE'),
  1212. result: autoRaidAdventure,
  1213. title: I18N('AUTO_RAID_ADVENTURE_TITLE'),
  1214. },
  1215. {
  1216. msg: I18N('CLAN_STAT'),
  1217. result: clanStatistic,
  1218. title: I18N('CLAN_STAT_TITLE'),
  1219. },
  1220. {
  1221. msg: I18N('EPIC_BRAWL'),
  1222. result: async function () {
  1223. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EPIC_BRAWL')}?`, () => {
  1224. const brawl = new epicBrawl();
  1225. brawl.start();
  1226. });
  1227. },
  1228. title: I18N('EPIC_BRAWL_TITLE'),
  1229. },
  1230. {
  1231. msg: I18N('ARTIFACTS_UPGRADE'),
  1232. result: updateArtifacts,
  1233. title: I18N('ARTIFACTS_UPGRADE_TITLE'),
  1234. },
  1235. {
  1236. msg: I18N('SKINS_UPGRADE'),
  1237. result: updateSkins,
  1238. title: I18N('SKINS_UPGRADE_TITLE'),
  1239. },
  1240. {
  1241. msg: I18N('CHANGE_MAP'),
  1242. result: async function () {
  1243. const maps = Object.values(lib.data.seasonAdventure.list).map(i => (
  1244. {
  1245. msg: I18N('MAP_NUM', { num: i.id }),
  1246. result: i.id
  1247. }));
  1248.  
  1249. const result = await popup.confirm(I18N('SELECT_ISLAND_MAP'), [...maps, { result: false, isClose: true }]);
  1250. if (result) {
  1251. cheats.changeIslandMap(result);
  1252. }
  1253. },
  1254. title: I18N('CHANGE_MAP_TITLE'),
  1255. },
  1256. ];
  1257. popupButtons.push({ result: false, isClose: true })
  1258. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1259. if (typeof answer === 'function') {
  1260. answer();
  1261. }
  1262. }
  1263. },
  1264. testTitanArena: {
  1265. name: I18N('TITAN_ARENA'),
  1266. title: I18N('TITAN_ARENA_TITLE'),
  1267. func: function () {
  1268. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TITAN_ARENA')}?`, testTitanArena);
  1269. },
  1270. },
  1271. testDungeon: {
  1272. name: I18N('DUNGEON'),
  1273. title: I18N('DUNGEON_TITLE'),
  1274. func: function () {
  1275. confShow(`${I18N('RUN_SCRIPT')} ${I18N('DUNGEON')}?`, testDungeon);
  1276. },
  1277. },
  1278. // Архидемон
  1279. bossRatingEvent: {
  1280. name: I18N('ARCHDEMON'),
  1281. title: I18N('ARCHDEMON_TITLE'),
  1282. func: function () {
  1283. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ARCHDEMON')}?`, bossRatingEvent);
  1284. },
  1285. hide: true,
  1286. },
  1287. /*
  1288. // Горнило душ
  1289. bossRatingEvent: {
  1290. name: I18N('ARCHDEMON'),
  1291. title: I18N('ARCHDEMON_TITLE'),
  1292. func: function () {
  1293. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ARCHDEMON')}?`, bossRatingEventSouls);
  1294. },
  1295. },
  1296. */
  1297. rewardsAndMailFarm: {
  1298. name: I18N('REWARDS_AND_MAIL'),
  1299. title: I18N('REWARDS_AND_MAIL_TITLE'),
  1300. func: function () {
  1301. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS_AND_MAIL')}?`, rewardsAndMailFarm);
  1302. },
  1303. },
  1304. testAdventure: {
  1305. name: I18N('ADVENTURE'),
  1306. title: I18N('ADVENTURE_TITLE'),
  1307. func: () => {
  1308. testAdventure();
  1309. },
  1310. },
  1311. goToSanctuary: {
  1312. name: I18N('SANCTUARY'),
  1313. title: I18N('SANCTUARY_TITLE'),
  1314. func: cheats.goSanctuary,
  1315. },
  1316. goToClanWar: {
  1317. name: I18N('GUILD_WAR'),
  1318. title: I18N('GUILD_WAR_TITLE'),
  1319. func: cheats.goClanWar,
  1320. },
  1321. dailyQuests: {
  1322. name: I18N('DAILY_QUESTS'),
  1323. title: I18N('DAILY_QUESTS_TITLE'),
  1324. func: async function () {
  1325. const quests = new dailyQuests(() => { }, () => { });
  1326. await quests.autoInit();
  1327. quests.start();
  1328. },
  1329. },
  1330. newDay: {
  1331. name: I18N('SYNC'),
  1332. title: I18N('SYNC_TITLE'),
  1333. func: function () {
  1334. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SYNC')}?`, cheats.refreshGame);
  1335. },
  1336. },
  1337. }
  1338. /**
  1339. * Display buttons
  1340. *
  1341. * Вывести кнопочки
  1342. */
  1343. function addControlButtons() {
  1344. for (let name in buttons) {
  1345. button = buttons[name];
  1346. if (button.hide) {
  1347. continue;
  1348. }
  1349. button['button'] = scriptMenu.addButton(button.name, button.func, button.title);
  1350. }
  1351. }
  1352. /**
  1353. * Adds links
  1354. *
  1355. * Добавляет ссылки
  1356. */
  1357. function addBottomUrls() {
  1358. scriptMenu.addHeader(I18N('BOTTOM_URLS'));
  1359. }
  1360. /**
  1361. * Stop repetition of the mission
  1362. *
  1363. * Остановить повтор миссии
  1364. */
  1365. let isStopSendMission = false;
  1366. /**
  1367. * There is a repetition of the mission
  1368. *
  1369. * Идет повтор миссии
  1370. */
  1371. let isSendsMission = false;
  1372. /**
  1373. * Data on the past mission
  1374. *
  1375. * Данные о прошедшей мисии
  1376. */
  1377. let lastMissionStart = {}
  1378. /**
  1379. * Start time of the last battle in the company
  1380. *
  1381. * Время начала последнего боя в кампании
  1382. */
  1383. let lastMissionBattleStart = 0;
  1384. /**
  1385. * Data for calculating the last battle with the boss
  1386. *
  1387. * Данные для расчете последнего боя с боссом
  1388. */
  1389. let lastBossBattle = null;
  1390. /**
  1391. * Information about the last battle
  1392. *
  1393. * Данные о прошедшей битве
  1394. */
  1395. let lastBattleArg = {}
  1396. let lastBossBattleStart = null;
  1397. this.addBattleTimer = 4;
  1398. this.invasionTimer = 2500;
  1399. /**
  1400. * The name of the function of the beginning of the battle
  1401. *
  1402. * Имя функции начала боя
  1403. */
  1404. let nameFuncStartBattle = '';
  1405. /**
  1406. * The name of the function of the end of the battle
  1407. *
  1408. * Имя функции конца боя
  1409. */
  1410. let nameFuncEndBattle = '';
  1411. /**
  1412. * Data for calculating the last battle
  1413. *
  1414. * Данные для расчета последнего боя
  1415. */
  1416. let lastBattleInfo = null;
  1417. /**
  1418. * The ability to cancel the battle
  1419. *
  1420. * Возможность отменить бой
  1421. */
  1422. let isCancalBattle = true;
  1423.  
  1424. /**
  1425. * Certificator of the last open nesting doll
  1426. *
  1427. * Идетификатор последней открытой матрешки
  1428. */
  1429. let lastRussianDollId = null;
  1430. /**
  1431. * Cancel the training guide
  1432. *
  1433. * Отменить обучающее руководство
  1434. */
  1435. this.isCanceledTutorial = false;
  1436.  
  1437. /**
  1438. * Data from the last question of the quiz
  1439. *
  1440. * Данные последнего вопроса викторины
  1441. */
  1442. let lastQuestion = null;
  1443. /**
  1444. * Answer to the last question of the quiz
  1445. *
  1446. * Ответ на последний вопрос викторины
  1447. */
  1448. let lastAnswer = null;
  1449. /**
  1450. * Flag for opening keys or titan artifact spheres
  1451. *
  1452. * Флаг открытия ключей или сфер артефактов титанов
  1453. */
  1454. let artifactChestOpen = false;
  1455. /**
  1456. * The name of the function to open keys or orbs of titan artifacts
  1457. *
  1458. * Имя функции открытия ключей или сфер артефактов титанов
  1459. */
  1460. let artifactChestOpenCallName = '';
  1461. let correctShowOpenArtifact = 0;
  1462. /**
  1463. * Data for the last battle in the dungeon
  1464. * (Fix endless cards)
  1465. *
  1466. * Данные для последнего боя в подземке
  1467. * (Исправление бесконечных карт)
  1468. */
  1469. let lastDungeonBattleData = null;
  1470. /**
  1471. * Start time of the last battle in the dungeon
  1472. *
  1473. * Время начала последнего боя в подземелье
  1474. */
  1475. let lastDungeonBattleStart = 0;
  1476. /**
  1477. * Subscription end time
  1478. *
  1479. * Время окончания подписки
  1480. */
  1481. let subEndTime = 0;
  1482. /**
  1483. * Number of prediction cards
  1484. *
  1485. * Количество карт предсказаний
  1486. */
  1487. let countPredictionCard = 0;
  1488.  
  1489. /**
  1490. * Brawl pack
  1491. *
  1492. * Пачка для потасовок
  1493. */
  1494. let brawlsPack = null;
  1495. /**
  1496. * Autobrawl started
  1497. *
  1498. * Автопотасовка запущена
  1499. */
  1500. let isBrawlsAutoStart = false;
  1501. let clanDominationGetInfo = null;
  1502. /**
  1503. * Copies the text to the clipboard
  1504. *
  1505. * Копирует тест в буфер обмена
  1506. * @param {*} text copied text // копируемый текст
  1507. */
  1508. function copyText(text) {
  1509. let copyTextarea = document.createElement("textarea");
  1510. copyTextarea.style.opacity = "0";
  1511. copyTextarea.textContent = text;
  1512. document.body.appendChild(copyTextarea);
  1513. copyTextarea.select();
  1514. document.execCommand("copy");
  1515. document.body.removeChild(copyTextarea);
  1516. delete copyTextarea;
  1517. }
  1518. /**
  1519. * Returns the history of requests
  1520. *
  1521. * Возвращает историю запросов
  1522. */
  1523. this.getRequestHistory = function() {
  1524. return requestHistory;
  1525. }
  1526. /**
  1527. * Generates a random integer from min to max
  1528. *
  1529. * Гененирует случайное целое число от min до max
  1530. */
  1531. const random = function (min, max) {
  1532. return Math.floor(Math.random() * (max - min + 1) + min);
  1533. }
  1534. /**
  1535. * Clearing the request history
  1536. *
  1537. * Очистка истоии запросов
  1538. */
  1539. setInterval(function () {
  1540. let now = Date.now();
  1541. for (let i in requestHistory) {
  1542. const time = +i.split('_')[0];
  1543. if (now - time > 300000) {
  1544. delete requestHistory[i];
  1545. }
  1546. }
  1547. }, 300000);
  1548. /**
  1549. * Displays the dialog box
  1550. *
  1551. * Отображает диалоговое окно
  1552. */
  1553. function confShow(message, yesCallback, noCallback) {
  1554. let buts = [];
  1555. message = message || I18N('DO_YOU_WANT');
  1556. noCallback = noCallback || (() => {});
  1557. if (yesCallback) {
  1558. buts = [
  1559. { msg: I18N('BTN_RUN'), result: true},
  1560. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true},
  1561. ]
  1562. } else {
  1563. yesCallback = () => {};
  1564. buts = [
  1565. { msg: I18N('BTN_OK'), result: true},
  1566. ];
  1567. }
  1568. popup.confirm(message, buts).then((e) => {
  1569. // dialogPromice = null;
  1570. if (e) {
  1571. yesCallback();
  1572. } else {
  1573. noCallback();
  1574. }
  1575. });
  1576. }
  1577. /**
  1578. * Override/proxy the method for creating a WS package send
  1579. *
  1580. * Переопределяем/проксируем метод создания отправки WS пакета
  1581. */
  1582. WebSocket.prototype.send = function (data) {
  1583. if (!this.isSetOnMessage) {
  1584. const oldOnmessage = this.onmessage;
  1585. this.onmessage = function (event) {
  1586. try {
  1587. const data = JSON.parse(event.data);
  1588. if (!this.isWebSocketLogin && data.result.type == "iframeEvent.login") {
  1589. this.isWebSocketLogin = true;
  1590. } else if (data.result.type == "iframeEvent.login") {
  1591. return;
  1592. }
  1593. } catch (e) { }
  1594. return oldOnmessage.apply(this, arguments);
  1595. }
  1596. this.isSetOnMessage = true;
  1597. }
  1598. original.SendWebSocket.call(this, data);
  1599. }
  1600. /**
  1601. * Overriding/Proxying the Ajax Request Creation Method
  1602. *
  1603. * Переопределяем/проксируем метод создания Ajax запроса
  1604. */
  1605. XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
  1606. this.uniqid = Date.now() + '_' + random(1000000, 10000000);
  1607. this.errorRequest = false;
  1608. if (method == 'POST' && url.includes('.nextersglobal.com/api/') && /api\/$/.test(url)) {
  1609. if (!apiUrl) {
  1610. apiUrl = url;
  1611. const socialInfo = /heroes-(.+?)\./.exec(apiUrl);
  1612. console.log(socialInfo);
  1613. }
  1614. requestHistory[this.uniqid] = {
  1615. method,
  1616. url,
  1617. error: [],
  1618. headers: {},
  1619. request: null,
  1620. response: null,
  1621. signature: [],
  1622. calls: {},
  1623. };
  1624. } else if (method == 'POST' && url.includes('error.nextersglobal.com/client/')) {
  1625. this.errorRequest = true;
  1626. }
  1627. return original.open.call(this, method, url, async, user, password);
  1628. };
  1629. /**
  1630. * Overriding/Proxying the header setting method for the AJAX request
  1631. *
  1632. * Переопределяем/проксируем метод установки заголовков для AJAX запроса
  1633. */
  1634. XMLHttpRequest.prototype.setRequestHeader = function (name, value, check) {
  1635. if (this.uniqid in requestHistory) {
  1636. requestHistory[this.uniqid].headers[name] = value;
  1637. } else {
  1638. check = true;
  1639. }
  1640.  
  1641. if (name == 'X-Auth-Signature') {
  1642. requestHistory[this.uniqid].signature.push(value);
  1643. if (!check) {
  1644. return;
  1645. }
  1646. }
  1647.  
  1648. return original.setRequestHeader.call(this, name, value);
  1649. };
  1650. /**
  1651. * Overriding/Proxying the AJAX Request Sending Method
  1652. *
  1653. * Переопределяем/проксируем метод отправки AJAX запроса
  1654. */
  1655. XMLHttpRequest.prototype.send = async function (sourceData) {
  1656. if (this.uniqid in requestHistory) {
  1657. let tempData = null;
  1658. if (getClass(sourceData) == "ArrayBuffer") {
  1659. tempData = decoder.decode(sourceData);
  1660. } else {
  1661. tempData = sourceData;
  1662. }
  1663. requestHistory[this.uniqid].request = tempData;
  1664. let headers = requestHistory[this.uniqid].headers;
  1665. lastHeaders = Object.assign({}, headers);
  1666. /**
  1667. * Game loading event
  1668. *
  1669. * Событие загрузки игры
  1670. */
  1671. if (headers["X-Request-Id"] > 2 && !isLoadGame) {
  1672. isLoadGame = true;
  1673. await lib.load();
  1674. addControls();
  1675. addControlButtons();
  1676. addBottomUrls();
  1677.  
  1678. if (isChecked('sendExpedition')) {
  1679. checkExpedition();
  1680. }
  1681.  
  1682. getAutoGifts();
  1683.  
  1684. cheats.activateHacks();
  1685. justInfo();
  1686. if (isChecked('dailyQuests')) {
  1687. testDailyQuests();
  1688. }
  1689.  
  1690. if (isChecked('buyForGold')) {
  1691. buyInStoreForGold();
  1692. }
  1693. }
  1694. /**
  1695. * Outgoing request data processing
  1696. *
  1697. * Обработка данных исходящего запроса
  1698. */
  1699. sourceData = await checkChangeSend.call(this, sourceData, tempData);
  1700. /**
  1701. * Handling incoming request data
  1702. *
  1703. * Обработка данных входящего запроса
  1704. */
  1705. const oldReady = this.onreadystatechange;
  1706. this.onreadystatechange = async function (e) {
  1707. if (this.errorRequest) {
  1708. return oldReady.apply(this, arguments);
  1709. }
  1710. if(this.readyState == 4 && this.status == 200) {
  1711. isTextResponse = this.responseType === "text" || this.responseType === "";
  1712. let response = isTextResponse ? this.responseText : this.response;
  1713. requestHistory[this.uniqid].response = response;
  1714. /**
  1715. * Replacing incoming request data
  1716. *
  1717. * Заменна данных входящего запроса
  1718. */
  1719. if (isTextResponse) {
  1720. await checkChangeResponse.call(this, response);
  1721. }
  1722. /**
  1723. * A function to run after the request is executed
  1724. *
  1725. * Функция запускаемая после выполения запроса
  1726. */
  1727. if (typeof this.onReadySuccess == 'function') {
  1728. setTimeout(this.onReadySuccess, 500);
  1729. }
  1730. /** Удаляем из истории запросов битвы с боссом */
  1731. if ('invasion_bossStart' in requestHistory[this.uniqid].calls) delete requestHistory[this.uniqid];
  1732. }
  1733. if (oldReady) {
  1734. return oldReady.apply(this, arguments);
  1735. }
  1736. }
  1737. }
  1738. if (this.errorRequest) {
  1739. const oldReady = this.onreadystatechange;
  1740. this.onreadystatechange = function () {
  1741. Object.defineProperty(this, 'status', {
  1742. writable: true
  1743. });
  1744. this.status = 200;
  1745. Object.defineProperty(this, 'readyState', {
  1746. writable: true
  1747. });
  1748. this.readyState = 4;
  1749. Object.defineProperty(this, 'responseText', {
  1750. writable: true
  1751. });
  1752. this.responseText = JSON.stringify({
  1753. "result": true
  1754. });
  1755. if (typeof this.onReadySuccess == 'function') {
  1756. setTimeout(this.onReadySuccess, 200);
  1757. }
  1758. return oldReady.apply(this, arguments);
  1759. }
  1760. this.onreadystatechange();
  1761. } else {
  1762. try {
  1763. return original.send.call(this, sourceData);
  1764. } catch(e) {
  1765. debugger;
  1766. }
  1767. }
  1768. };
  1769. /**
  1770. * Processing and substitution of outgoing data
  1771. *
  1772. * Обработка и подмена исходящих данных
  1773. */
  1774. async function checkChangeSend(sourceData, tempData) {
  1775. try {
  1776. /**
  1777. * A function that replaces battle data with incorrect ones to cancel combatя
  1778. *
  1779. * Функция заменяющая данные боя на неверные для отмены боя
  1780. */
  1781. const fixBattle = function (heroes) {
  1782. for (const ids in heroes) {
  1783. hero = heroes[ids];
  1784. hero.energy = random(1, 999);
  1785. if (hero.hp > 0) {
  1786. hero.hp = random(1, hero.hp);
  1787. }
  1788. }
  1789. }
  1790. /**
  1791. * Dialog window 2
  1792. *
  1793. * Диалоговое окно 2
  1794. */
  1795. const showMsg = async function (msg, ansF, ansS) {
  1796. if (typeof popup == 'object') {
  1797. return await popup.confirm(msg, [
  1798. {msg: ansF, result: false},
  1799. {msg: ansS, result: true},
  1800. ]);
  1801. } else {
  1802. return !confirm(`${msg}\n ${ansF} (${I18N('BTN_OK')})\n ${ansS} (${I18N('BTN_CANCEL')})`);
  1803. }
  1804. }
  1805. /**
  1806. * Dialog window 3
  1807. *
  1808. * Диалоговое окно 3
  1809. */
  1810. const showMsgs = async function (msg, ansF, ansS, ansT) {
  1811. return await popup.confirm(msg, [
  1812. {msg: ansF, result: 0},
  1813. {msg: ansS, result: 1},
  1814. {msg: ansT, result: 2},
  1815. ]);
  1816. }
  1817.  
  1818. let changeRequest = false;
  1819. testData = JSON.parse(tempData);
  1820. for (const call of testData.calls) {
  1821. if (!artifactChestOpen) {
  1822. requestHistory[this.uniqid].calls[call.name] = call.ident;
  1823. }
  1824. /**
  1825. * Cancellation of the battle in adventures, on VG and with minions of Asgard
  1826. * Отмена боя в приключениях, на ВГ и с прислужниками Асгарда
  1827. */
  1828. if ((call.name == 'adventure_endBattle' ||
  1829. call.name == 'adventureSolo_endBattle' ||
  1830. call.name == 'clanWarEndBattle' &&
  1831. isChecked('cancelBattle') ||
  1832. call.name == 'crossClanWar_endBattle' &&
  1833. isChecked('cancelBattle') ||
  1834. call.name == 'brawl_endBattle' ||
  1835. call.name == 'towerEndBattle' ||
  1836. call.name == 'invasion_bossEnd' ||
  1837. call.name == 'bossEndBattle' ||
  1838. call.name == 'clanRaid_endNodeBattle') &&
  1839. isCancalBattle) {
  1840. nameFuncEndBattle = call.name;
  1841. if (!call.args.result.win) {
  1842. let resultPopup = false;
  1843. if (call.name == 'adventure_endBattle' ||
  1844. call.name == 'invasion_bossEnd' ||
  1845. call.name == 'bossEndBattle' ||
  1846. call.name == 'adventureSolo_endBattle') {
  1847. resultPopup = await showMsgs(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  1848. } else if (call.name == 'clanWarEndBattle' ||
  1849. call.name == 'crossClanWar_endBattle') {
  1850. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_AUTO_F5'));
  1851. } else {
  1852. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'));
  1853. }
  1854. if (resultPopup) {
  1855. if (call.name == 'invasion_bossEnd') {
  1856. this.errorRequest = true;
  1857. }
  1858. fixBattle(call.args.progress[0].attackers.heroes);
  1859. fixBattle(call.args.progress[0].defenders.heroes);
  1860. changeRequest = true;
  1861. if (resultPopup > 1) {
  1862. this.onReadySuccess = testAutoBattle;
  1863. // setTimeout(bossBattle, 1000);
  1864. }
  1865. }
  1866. } else if (call.args.result.stars < 3 && call.name == 'towerEndBattle') {
  1867. resultPopup = await showMsg(I18N('LOST_HEROES'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  1868. if (resultPopup) {
  1869. fixBattle(call.args.progress[0].attackers.heroes);
  1870. fixBattle(call.args.progress[0].defenders.heroes);
  1871. changeRequest = true;
  1872. if (resultPopup > 1) {
  1873. this.onReadySuccess = testAutoBattle;
  1874. }
  1875. }
  1876. }
  1877. // Потасовки
  1878. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_endBattle') {}
  1879. }
  1880. /**
  1881. * Save pack for Brawls
  1882. *
  1883. * Сохраняем пачку для потасовок
  1884. */
  1885. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_startBattle') {
  1886. console.log(JSON.stringify(call.args));
  1887. brawlsPack = call.args;
  1888. if (
  1889. await popup.confirm(
  1890. I18N('START_AUTO_BRAWLS'),
  1891. [
  1892. { msg: I18N('BTN_NO'), result: false },
  1893. { msg: I18N('BTN_YES'), result: true },
  1894. ],
  1895. [
  1896. {
  1897. name: 'isAuto',
  1898. label: I18N('BRAWL_AUTO_PACK'),
  1899. checked: false,
  1900. },
  1901. ]
  1902. )
  1903. ) {
  1904. isBrawlsAutoStart = true;
  1905. const isAuto = popup.getCheckBoxes().find((e) => e.name === 'isAuto');
  1906. this.errorRequest = true;
  1907. testBrawls(isAuto.checked);
  1908. }
  1909. }
  1910. /**
  1911. * Canceled fight in Asgard
  1912. * Отмена боя в Асгарде
  1913. */
  1914. if (call.name == 'clanRaid_endBossBattle' && isChecked('cancelBattle')) {
  1915. const bossDamage = call.args.progress[0].defenders.heroes[1].extra;
  1916. let maxDamage = bossDamage.damageTaken + bossDamage.damageTakenNextLevel;
  1917. const lastDamage = maxDamage;
  1918. const resultPopup = await popup.confirm(
  1919. `${I18N('MSG_YOU_APPLIED')} ${lastDamage.toLocaleString()} ${I18N('MSG_DAMAGE')}.`,
  1920. [
  1921. { msg: I18N('BTN_OK'), result: false },
  1922. { msg: I18N('BTN_AUTO_F5'), result: 1 },
  1923. { msg: I18N('BTN_TRY_FIX_IT'), result: 2 },
  1924. ],
  1925. [
  1926. {
  1927. name: 'isStat',
  1928. label: I18N('CALC_STAT'),
  1929. checked: false,
  1930. },
  1931. ]
  1932. );
  1933. if (resultPopup) {
  1934. if (resultPopup == 2) {
  1935. setProgress(I18N('LETS_FIX'), false);
  1936. await new Promise((e) => setTimeout(e, 1));
  1937. const cloneBattle = structuredClone(lastBossBattle);
  1938. const endTime = cloneBattle.endTime;
  1939. console.log('fixBossBattleStart');
  1940. const step = 9 / 300;
  1941. let index = 0;
  1942. let count = 0;
  1943. for (let timer = 1.3; timer < 10.3; timer += step) {
  1944. await new Promise((e) => setTimeout(() => {
  1945. setProgress('Исправляем: ' + Math.floor(count / 300 * 100) + '%', false);
  1946. e();
  1947. }, 1));
  1948. if (endTime < Date.now()) {
  1949. break;
  1950. }
  1951. try {
  1952. resultBattle = await Calc(cloneBattle);
  1953. } catch (e) {
  1954. continue;
  1955. }
  1956. count++;
  1957.  
  1958. const extraDmg = resultBattle.progress[0].defenders.heroes[1].extra;
  1959. const bossDamage = extraDmg.damageTaken + extraDmg.damageTakenNextLevel;
  1960. console.log(count + '\t' + timer.toFixed(2) + '\t' + bossDamage.toLocaleString());
  1961. if (bossDamage > maxDamage) {
  1962. maxDamage = bossDamage;
  1963. call.args.result = resultBattle.result;
  1964. call.args.progress = resultBattle.progress;
  1965. }
  1966. cloneBattle.progress = [{ attackers: { input: ['auto', 0, 0, 'auto', index, timer] } }];
  1967. }
  1968. let msgResult = I18N('DAMAGE_NO_FIXED', {
  1969. lastDamage: lastDamage.toLocaleString()
  1970. });
  1971. if (maxDamage > lastDamage) {
  1972. msgResult = I18N('DAMAGE_FIXED', {
  1973. lastDamage: lastDamage.toLocaleString(),
  1974. maxDamage: maxDamage.toLocaleString(),
  1975. });
  1976. }
  1977. console.log(lastDamage, '>' ,maxDamage);
  1978. setProgress(msgResult, false, hideProgress);
  1979. } else {
  1980. fixBattle(call.args.progress[0].attackers.heroes);
  1981. fixBattle(call.args.progress[0].defenders.heroes);
  1982. }
  1983. changeRequest = true;
  1984. }
  1985. const isStat = popup.getCheckBoxes().find((e) => e.name === 'isStat');
  1986. if (isStat.checked) {
  1987. this.onReadySuccess = testBossBattle;
  1988. }
  1989. }
  1990. /**
  1991. * Save the Asgard Boss Attack Pack
  1992. * Сохраняем пачку для атаки босса Асгарда
  1993. */
  1994. if (call.name == 'clanRaid_startBossBattle') {
  1995. console.log(JSON.stringify(call.args));
  1996. }
  1997. /**
  1998. * Saving the request to start the last battle
  1999. * Сохранение запроса начала последнего боя
  2000. */
  2001. if (call.name == 'clanWarAttack' ||
  2002. call.name == 'crossClanWar_startBattle' ||
  2003. call.name == 'adventure_turnStartBattle' ||
  2004. call.name == 'bossAttack' ||
  2005. call.name == 'invasion_bossStart' ||
  2006. call.name == 'towerStartBattle') {
  2007. nameFuncStartBattle = call.name;
  2008. lastBattleArg = call.args;
  2009.  
  2010. if (call.name == 'invasion_bossStart') {
  2011. const timePassed = Date.now() - lastBossBattleStart;
  2012. if (timePassed < invasionTimer) {
  2013. await new Promise((e) => setTimeout(e, invasionTimer - timePassed));
  2014. }
  2015. invasionTimer -= 1;
  2016. }
  2017. lastBossBattleStart = Date.now();
  2018. }
  2019. if (call.name == 'invasion_bossEnd') {
  2020. const lastBattle = lastBattleInfo;
  2021. if (lastBattle && call.args.result.win) {
  2022. lastBattle.progress = call.args.progress;
  2023. const result = await Calc(lastBattle);
  2024. let timer = getTimer(result.battleTime, 1) + addBattleTimer;
  2025. const period = Math.ceil((Date.now() - lastBossBattleStart) / 1000);
  2026. console.log(timer, period);
  2027. if (period < timer) {
  2028. timer = timer - period;
  2029. await countdownTimer(timer);
  2030. }
  2031. }
  2032. }
  2033. /**
  2034. * Disable spending divination cards
  2035. * Отключить трату карт предсказаний
  2036. */
  2037. if (call.name == 'dungeonEndBattle') {
  2038. if (call.args.isRaid) {
  2039. if (countPredictionCard <= 0) {
  2040. delete call.args.isRaid;
  2041. changeRequest = true;
  2042. } else if (countPredictionCard > 0) {
  2043. countPredictionCard--;
  2044. }
  2045. }
  2046. console.log(`Cards: ${countPredictionCard}`);
  2047. /**
  2048. * Fix endless cards
  2049. * Исправление бесконечных карт
  2050. */
  2051. const lastBattle = lastDungeonBattleData;
  2052. if (lastBattle && !call.args.isRaid) {
  2053. if (changeRequest) {
  2054. lastBattle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2055. } else {
  2056. lastBattle.progress = call.args.progress;
  2057. }
  2058. const result = await Calc(lastBattle);
  2059.  
  2060. if (changeRequest) {
  2061. call.args.progress = result.progress;
  2062. call.args.result = result.result;
  2063. }
  2064. let timer = result.battleTimer + addBattleTimer;
  2065. const period = Math.ceil((Date.now() - lastDungeonBattleStart) / 1000);
  2066. console.log(timer, period);
  2067. if (period < timer) {
  2068. timer = timer - period;
  2069. await countdownTimer(timer);
  2070. }
  2071. }
  2072. }
  2073. /**
  2074. * Quiz Answer
  2075. * Ответ на викторину
  2076. */
  2077. if (call.name == 'quizAnswer') {
  2078. /**
  2079. * Automatically changes the answer to the correct one if there is one.
  2080. * Автоматически меняет ответ на правильный если он есть
  2081. */
  2082. if (lastAnswer && isChecked('getAnswer')) {
  2083. call.args.answerId = lastAnswer;
  2084. lastAnswer = null;
  2085. changeRequest = true;
  2086. }
  2087. }
  2088. /**
  2089. * Present
  2090. * Подарки
  2091. */
  2092. if (call.name == 'freebieCheck') {
  2093. freebieCheckInfo = call;
  2094. }
  2095. /** missionTimer */
  2096. if (call.name == 'missionEnd' && missionBattle) {
  2097. let startTimer = false;
  2098. if (!call.args.result.win) {
  2099. startTimer = await popup.confirm(I18N('DEFEAT_TURN_TIMER'), [
  2100. { msg: I18N('BTN_NO'), result: false },
  2101. { msg: I18N('BTN_YES'), result: true },
  2102. ]);
  2103. }
  2104.  
  2105. if (call.args.result.win || startTimer) {
  2106. missionBattle.progress = call.args.progress;
  2107. missionBattle.result = call.args.result;
  2108. const result = await Calc(missionBattle);
  2109.  
  2110. let timer = result.battleTimer + addBattleTimer;
  2111. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  2112. if (period < timer) {
  2113. timer = timer - period;
  2114. await countdownTimer(timer);
  2115. }
  2116. missionBattle = null;
  2117. } else {
  2118. this.errorRequest = true;
  2119. }
  2120. }
  2121. /**
  2122. * Getting mission data for auto-repeat
  2123. * Получение данных миссии для автоповтора
  2124. */
  2125. if (isChecked('repeatMission') &&
  2126. call.name == 'missionEnd') {
  2127. let missionInfo = {
  2128. id: call.args.id,
  2129. result: call.args.result,
  2130. heroes: call.args.progress[0].attackers.heroes,
  2131. count: 0,
  2132. }
  2133. setTimeout(async () => {
  2134. if (!isSendsMission && await popup.confirm(I18N('MSG_REPEAT_MISSION'), [
  2135. { msg: I18N('BTN_REPEAT'), result: true},
  2136. { msg: I18N('BTN_NO'), result: false},
  2137. ])) {
  2138. isStopSendMission = false;
  2139. isSendsMission = true;
  2140. sendsMission(missionInfo);
  2141. }
  2142. }, 0);
  2143. }
  2144. /**
  2145. * Getting mission data
  2146. * Получение данных миссии
  2147. * missionTimer
  2148. */
  2149. if (call.name == 'missionStart') {
  2150. lastMissionStart = call.args;
  2151. lastMissionBattleStart = Date.now();
  2152. }
  2153. /**
  2154. * Specify the quantity for Titan Orbs and Pet Eggs
  2155. * Указать количество для сфер титанов и яиц петов
  2156. */
  2157. if (isChecked('countControl') &&
  2158. (call.name == 'pet_chestOpen' ||
  2159. call.name == 'titanUseSummonCircle') &&
  2160. call.args.amount > 1) {
  2161. const startAmount = call.args.amount;
  2162. call.args.amount = 1;
  2163. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2164. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2165. ]);
  2166. if (result) {
  2167. const item = call.name == 'pet_chestOpen' ? { id: 90, type: 'consumable' } : { id: 13, type: 'coin' };
  2168. cheats.updateInventory({
  2169. [item.type]: {
  2170. [item.id]: -(result - startAmount),
  2171. },
  2172. });
  2173. call.args.amount = result;
  2174. changeRequest = true;
  2175. }
  2176. }
  2177. /**
  2178. * Specify the amount for keys and spheres of titan artifacts
  2179. * Указать колличество для ключей и сфер артефактов титанов
  2180. */
  2181. if (isChecked('countControl') &&
  2182. (call.name == 'artifactChestOpen' ||
  2183. call.name == 'titanArtifactChestOpen') &&
  2184. call.args.amount > 1 &&
  2185. call.args.free &&
  2186. !changeRequest) {
  2187. artifactChestOpenCallName = call.name;
  2188. const startAmount = call.args.amount;
  2189. let result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2190. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount },
  2191. ]);
  2192. if (result) {
  2193. const openChests = result;
  2194. let sphere = result < 10 ? 1 : 10;
  2195. call.args.amount = sphere;
  2196. for (let count = openChests - sphere; count > 0; count -= sphere) {
  2197. if (count < 10) sphere = 1;
  2198. const ident = artifactChestOpenCallName + "_" + count;
  2199. testData.calls.push({
  2200. name: artifactChestOpenCallName,
  2201. args: {
  2202. amount: sphere,
  2203. free: true,
  2204. },
  2205. ident: ident
  2206. });
  2207. if (!Array.isArray(requestHistory[this.uniqid].calls[call.name])) {
  2208. requestHistory[this.uniqid].calls[call.name] = [requestHistory[this.uniqid].calls[call.name]];
  2209. }
  2210. requestHistory[this.uniqid].calls[call.name].push(ident);
  2211. }
  2212.  
  2213. const consumableId = call.name == 'artifactChestOpen' ? 45 : 55;
  2214. cheats.updateInventory({
  2215. consumable: {
  2216. [consumableId]: -(openChests - startAmount),
  2217. },
  2218. });
  2219. artifactChestOpen = true;
  2220. changeRequest = true;
  2221. }
  2222. }
  2223. if (call.name == 'consumableUseLootBox') {
  2224. lastRussianDollId = call.args.libId;
  2225. /**
  2226. * Specify quantity for gold caskets
  2227. * Указать количество для золотых шкатулок
  2228. */
  2229. if (isChecked('countControl') &&
  2230. call.args.libId == 148 &&
  2231. call.args.amount > 1) {
  2232. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2233. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2234. ]);
  2235. call.args.amount = result;
  2236. changeRequest = true;
  2237. }
  2238. }
  2239. /**
  2240. * Changing the maximum number of raids in the campaign
  2241. * Изменение максимального количества рейдов в кампании
  2242. */
  2243. // if (call.name == 'missionRaid') {
  2244. // if (isChecked('countControl') && call.args.times > 1) {
  2245. // const result = +(await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2246. // { msg: I18N('BTN_RUN'), isInput: true, default: call.args.times },
  2247. // ]));
  2248. // call.args.times = result > call.args.times ? call.args.times : result;
  2249. // changeRequest = true;
  2250. // }
  2251. // }
  2252. }
  2253.  
  2254. let headers = requestHistory[this.uniqid].headers;
  2255. if (changeRequest) {
  2256. sourceData = JSON.stringify(testData);
  2257. headers['X-Auth-Signature'] = getSignature(headers, sourceData);
  2258. }
  2259.  
  2260. let signature = headers['X-Auth-Signature'];
  2261. if (signature) {
  2262. original.setRequestHeader.call(this, 'X-Auth-Signature', signature);
  2263. }
  2264. } catch (err) {
  2265. console.log("Request(send, " + this.uniqid + "):\n", sourceData, "Error:\n", err);
  2266. }
  2267. return sourceData;
  2268. }
  2269. /**
  2270. * Processing and substitution of incoming data
  2271. *
  2272. * Обработка и подмена входящих данных
  2273. */
  2274. async function checkChangeResponse(response) {
  2275. try {
  2276. isChange = false;
  2277. let nowTime = Math.round(Date.now() / 1000);
  2278. callsIdent = requestHistory[this.uniqid].calls;
  2279. respond = JSON.parse(response);
  2280. /**
  2281. * If the request returned an error removes the error (removes synchronization errors)
  2282. * Если запрос вернул ошибку удаляет ошибку (убирает ошибки синхронизации)
  2283. */
  2284. if (respond.error) {
  2285. isChange = true;
  2286. console.error(respond.error);
  2287. if (isChecked('showErrors')) {
  2288. popup.confirm(I18N('ERROR_MSG', {
  2289. name: respond.error.name,
  2290. description: respond.error.description,
  2291. }));
  2292. }
  2293. delete respond.error;
  2294. respond.results = [];
  2295. }
  2296. let mainReward = null;
  2297. const allReward = {};
  2298. let countTypeReward = 0;
  2299. let readQuestInfo = false;
  2300. for (const call of respond.results) {
  2301. /**
  2302. * Obtaining initial data for completing quests
  2303. * Получение исходных данных для выполнения квестов
  2304. */
  2305. if (readQuestInfo) {
  2306. questsInfo[call.ident] = call.result.response;
  2307. }
  2308. /**
  2309. * Getting a user ID
  2310. * Получение идетификатора пользователя
  2311. */
  2312. if (call.ident == callsIdent['registration']) {
  2313. userId = call.result.response.userId;
  2314. if (localStorage['userId'] != userId) {
  2315. localStorage['newGiftSendIds'] = '';
  2316. localStorage['userId'] = userId;
  2317. }
  2318. await openOrMigrateDatabase(userId);
  2319. readQuestInfo = true;
  2320. }
  2321. /**
  2322. * Hiding donation offers 1
  2323. * Скрываем предложения доната 1
  2324. */
  2325. if (call.ident == callsIdent['billingGetAll'] && getSaveVal('noOfferDonat')) {
  2326. const billings = call.result.response?.billings;
  2327. const bundle = call.result.response?.bundle;
  2328. if (billings && bundle) {
  2329. call.result.response.billings = [];
  2330. call.result.response.bundle = [];
  2331. isChange = true;
  2332. }
  2333. }
  2334. /**
  2335. * Hiding donation offers 2
  2336. * Скрываем предложения доната 2
  2337. */
  2338. if (getSaveVal('noOfferDonat') &&
  2339. (call.ident == callsIdent['offerGetAll'] ||
  2340. call.ident == callsIdent['specialOffer_getAll'])) {
  2341. let offers = call.result.response;
  2342. if (offers) {
  2343. call.result.response = offers.filter(e => !['addBilling', 'bundleCarousel'].includes(e.type) || ['idleResource'].includes(e.offerType));
  2344. isChange = true;
  2345. }
  2346. }
  2347. /**
  2348. * Hiding donation offers 3
  2349. * Скрываем предложения доната 3
  2350. */
  2351. if (getSaveVal('noOfferDonat') && call.result?.bundleUpdate) {
  2352. delete call.result.bundleUpdate;
  2353. isChange = true;
  2354. }
  2355. /**
  2356. * Copies a quiz question to the clipboard
  2357. * Копирует вопрос викторины в буфер обмена и получает на него ответ если есть
  2358. */
  2359. if (call.ident == callsIdent['quizGetNewQuestion']) {
  2360. let quest = call.result.response;
  2361. console.log(quest.question);
  2362. copyText(quest.question);
  2363. setProgress(I18N('QUESTION_COPY'), true);
  2364. quest.lang = null;
  2365. if (typeof NXFlashVars !== 'undefined') {
  2366. quest.lang = NXFlashVars.interface_lang;
  2367. }
  2368. lastQuestion = quest;
  2369. if (isChecked('getAnswer')) {
  2370. const answer = await getAnswer(lastQuestion);
  2371. let showText = '';
  2372. if (answer) {
  2373. lastAnswer = answer;
  2374. console.log(answer);
  2375. showText = `${I18N('ANSWER_KNOWN')}: ${answer}`;
  2376. } else {
  2377. showText = I18N('ANSWER_NOT_KNOWN');
  2378. }
  2379.  
  2380. try {
  2381. const hint = hintQuest(quest);
  2382. if (hint) {
  2383. showText += I18N('HINT') + hint;
  2384. }
  2385. } catch(e) {}
  2386.  
  2387. setProgress(showText, true);
  2388. }
  2389. }
  2390. /**
  2391. * Submits a question with an answer to the database
  2392. * Отправляет вопрос с ответом в базу данных
  2393. */
  2394. if (call.ident == callsIdent['quizAnswer']) {
  2395. const answer = call.result.response;
  2396. if (lastQuestion) {
  2397. const answerInfo = {
  2398. answer,
  2399. question: lastQuestion,
  2400. lang: null,
  2401. }
  2402. if (typeof NXFlashVars !== 'undefined') {
  2403. answerInfo.lang = NXFlashVars.interface_lang;
  2404. }
  2405. lastQuestion = null;
  2406. setTimeout(sendAnswerInfo, 0, answerInfo);
  2407. }
  2408. }
  2409. /**
  2410. * Get user data
  2411. * Получить даныне пользователя
  2412. */
  2413. if (call.ident == callsIdent['userGetInfo']) {
  2414. let user = call.result.response;
  2415. userInfo = Object.assign({}, user);
  2416. delete userInfo.refillable;
  2417. if (!questsInfo['userGetInfo']) {
  2418. questsInfo['userGetInfo'] = user;
  2419. }
  2420. }
  2421. /**
  2422. * Start of the battle for recalculation
  2423. * Начало боя для прерасчета
  2424. */
  2425. if (call.ident == callsIdent['clanWarAttack'] ||
  2426. call.ident == callsIdent['crossClanWar_startBattle'] ||
  2427. call.ident == callsIdent['bossAttack'] ||
  2428. call.ident == callsIdent['battleGetReplay'] ||
  2429. call.ident == callsIdent['brawl_startBattle'] ||
  2430. call.ident == callsIdent['adventureSolo_turnStartBattle'] ||
  2431. call.ident == callsIdent['invasion_bossStart'] ||
  2432. call.ident == callsIdent['towerStartBattle'] ||
  2433. call.ident == callsIdent['adventure_turnStartBattle']) {
  2434. let battle = call.result.response.battle || call.result.response.replay;
  2435. if (call.ident == callsIdent['brawl_startBattle'] ||
  2436. call.ident == callsIdent['bossAttack'] ||
  2437. call.ident == callsIdent['towerStartBattle'] ||
  2438. call.ident == callsIdent['invasion_bossStart']) {
  2439. battle = call.result.response;
  2440. }
  2441. lastBattleInfo = battle;
  2442. if (!isChecked('preCalcBattle')) {
  2443. continue;
  2444. }
  2445. setProgress(I18N('BEING_RECALC'));
  2446. let battleDuration = 120;
  2447. try {
  2448. const typeBattle = getBattleType(battle.type);
  2449. battleDuration = +lib.data.battleConfig[typeBattle.split('_')[1]].config.battleDuration;
  2450. } catch (e) { }
  2451. //console.log(battle.type);
  2452. function getBattleInfo(battle, isRandSeed) {
  2453. return new Promise(function (resolve) {
  2454. if (isRandSeed) {
  2455. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  2456. }
  2457. BattleCalc(battle, getBattleType(battle.type), e => resolve(e));
  2458. });
  2459. }
  2460. let actions = [getBattleInfo(battle, false)]
  2461. const countTestBattle = getInput('countTestBattle');
  2462. if (call.ident == callsIdent['battleGetReplay']) {
  2463. battle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2464. }
  2465. for (let i = 0; i < countTestBattle; i++) {
  2466. actions.push(getBattleInfo(battle, true));
  2467. }
  2468. Promise.all(actions)
  2469. .then(e => {
  2470. e = e.map(n => ({win: n.result.win, time: n.battleTime}));
  2471. let firstBattle = e.shift();
  2472. const timer = Math.floor(battleDuration - firstBattle.time);
  2473. const min = ('00' + Math.floor(timer / 60)).slice(-2);
  2474. const sec = ('00' + Math.floor(timer - min * 60)).slice(-2);
  2475. const countWin = e.reduce((w, s) => w + s.win, 0);
  2476. setProgress(`${I18N('THIS_TIME')} ${(firstBattle.win ? I18N('VICTORY') : I18N('DEFEAT'))} ${I18N('CHANCE_TO_WIN')}: ${Math.floor(countWin / e.length * 100)}% (${e.length}), ${min}:${sec}`, false, hideProgress)
  2477. });
  2478. }
  2479. /**
  2480. * Start of the Asgard boss fight
  2481. * Начало боя с боссом Асгарда
  2482. */
  2483. if (call.ident == callsIdent['clanRaid_startBossBattle']) {
  2484. lastBossBattle = call.result.response.battle;
  2485. lastBossBattle.endTime = Date.now() + 160 * 1000;
  2486. if (isChecked('preCalcBattle')) {
  2487. const result = await Calc(lastBossBattle).then(e => e.progress[0].defenders.heroes[1].extra);
  2488. const bossDamage = result.damageTaken + result.damageTakenNextLevel;
  2489. setProgress(I18N('BOSS_DAMAGE') + bossDamage.toLocaleString(), false, hideProgress);
  2490. }
  2491. }
  2492. /**
  2493. * Cancel tutorial
  2494. * Отмена туториала
  2495. */
  2496. if (isCanceledTutorial && call.ident == callsIdent['tutorialGetInfo']) {
  2497. let chains = call.result.response.chains;
  2498. for (let n in chains) {
  2499. chains[n] = 9999;
  2500. }
  2501. isChange = true;
  2502. }
  2503. /**
  2504. * Opening keys and spheres of titan artifacts
  2505. * Открытие ключей и сфер артефактов титанов
  2506. */
  2507. if (artifactChestOpen &&
  2508. (call.ident == callsIdent[artifactChestOpenCallName] ||
  2509. (callsIdent[artifactChestOpenCallName] && callsIdent[artifactChestOpenCallName].includes(call.ident)))) {
  2510. let reward = call.result.response[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'];
  2511.  
  2512. reward.forEach(e => {
  2513. for (let f in e) {
  2514. if (!allReward[f]) {
  2515. allReward[f] = {};
  2516. }
  2517. for (let o in e[f]) {
  2518. if (!allReward[f][o]) {
  2519. allReward[f][o] = e[f][o];
  2520. countTypeReward++;
  2521. } else {
  2522. allReward[f][o] += e[f][o];
  2523. }
  2524. }
  2525. }
  2526. });
  2527.  
  2528. if (!call.ident.includes(artifactChestOpenCallName)) {
  2529. mainReward = call.result.response;
  2530. }
  2531. }
  2532.  
  2533. if (countTypeReward > 20) {
  2534. correctShowOpenArtifact = 3;
  2535. } else {
  2536. correctShowOpenArtifact = 0;
  2537. }
  2538. /**
  2539. * Sum the result of opening Pet Eggs
  2540. * Суммирование результата открытия яиц питомцев
  2541. */
  2542. if (isChecked('countControl') && call.ident == callsIdent['pet_chestOpen']) {
  2543. const rewards = call.result.response.rewards;
  2544. if (rewards.length > 10) {
  2545. /**
  2546. * Removing pet cards
  2547. * Убираем карточки петов
  2548. */
  2549. for (const reward of rewards) {
  2550. if (reward.petCard) {
  2551. delete reward.petCard;
  2552. }
  2553. }
  2554. }
  2555. rewards.forEach(e => {
  2556. for (let f in e) {
  2557. if (!allReward[f]) {
  2558. allReward[f] = {};
  2559. }
  2560. for (let o in e[f]) {
  2561. if (!allReward[f][o]) {
  2562. allReward[f][o] = e[f][o];
  2563. } else {
  2564. allReward[f][o] += e[f][o];
  2565. }
  2566. }
  2567. }
  2568. });
  2569. call.result.response.rewards = [allReward];
  2570. isChange = true;
  2571. }
  2572. /**
  2573. * Removing titan cards
  2574. * Убираем карточки титанов
  2575. */
  2576. if (call.ident == callsIdent['titanUseSummonCircle']) {
  2577. if (call.result.response.rewards.length > 10) {
  2578. for (const reward of call.result.response.rewards) {
  2579. if (reward.titanCard) {
  2580. delete reward.titanCard;
  2581. }
  2582. }
  2583. isChange = true;
  2584. }
  2585. }
  2586. /**
  2587. * Auto-repeat opening matryoshkas
  2588. * АвтоПовтор открытия матрешек
  2589. */
  2590. if (isChecked('countControl') && call.ident == callsIdent['consumableUseLootBox']) {
  2591. let lootBox = call.result.response;
  2592. let newCount = 0;
  2593. for (let n of lootBox) {
  2594. if (n?.consumable && n.consumable[lastRussianDollId]) {
  2595. newCount += n.consumable[lastRussianDollId]
  2596. }
  2597. }
  2598. if (newCount && await popup.confirm(`${I18N('BTN_OPEN')} ${newCount} ${I18N('OPEN_DOLLS')}?`, [
  2599. { msg: I18N('BTN_OPEN'), result: true},
  2600. { msg: I18N('BTN_NO'), result: false},
  2601. ])) {
  2602. const recursionResult = await openRussianDolls(lastRussianDollId, newCount);
  2603. lootBox = [...lootBox, ...recursionResult];
  2604. }
  2605.  
  2606. /** Объединение результата лутбоксов */
  2607. const allLootBox = {};
  2608. lootBox.forEach(e => {
  2609. for (let f in e) {
  2610. if (!allLootBox[f]) {
  2611. if (typeof e[f] == 'object') {
  2612. allLootBox[f] = {};
  2613. } else {
  2614. allLootBox[f] = 0;
  2615. }
  2616. }
  2617. if (typeof e[f] == 'object') {
  2618. for (let o in e[f]) {
  2619. if (newCount && o == lastRussianDollId) {
  2620. continue;
  2621. }
  2622. if (!allLootBox[f][o]) {
  2623. allLootBox[f][o] = e[f][o];
  2624. } else {
  2625. allLootBox[f][o] += e[f][o];
  2626. }
  2627. }
  2628. } else {
  2629. allLootBox[f] += e[f];
  2630. }
  2631. }
  2632. });
  2633. /** Разбитие результата */
  2634. const output = [];
  2635. const maxCount = 5;
  2636. let currentObj = {};
  2637. let count = 0;
  2638. for (let f in allLootBox) {
  2639. if (!currentObj[f]) {
  2640. if (typeof allLootBox[f] == 'object') {
  2641. for (let o in allLootBox[f]) {
  2642. currentObj[f] ||= {}
  2643. if (!currentObj[f][o]) {
  2644. currentObj[f][o] = allLootBox[f][o];
  2645. count++;
  2646. if (count === maxCount) {
  2647. output.push(currentObj);
  2648. currentObj = {};
  2649. count = 0;
  2650. }
  2651. }
  2652. }
  2653. } else {
  2654. currentObj[f] = allLootBox[f];
  2655. count++;
  2656. if (count === maxCount) {
  2657. output.push(currentObj);
  2658. currentObj = {};
  2659. count = 0;
  2660. }
  2661. }
  2662. }
  2663. }
  2664. if (count > 0) {
  2665. output.push(currentObj);
  2666. }
  2667.  
  2668. console.log(output);
  2669. call.result.response = output;
  2670. isChange = true;
  2671. }
  2672. /**
  2673. * Dungeon recalculation (fix endless cards)
  2674. * Прерасчет подземки (исправление бесконечных карт)
  2675. */
  2676. if (call.ident == callsIdent['dungeonStartBattle']) {
  2677. lastDungeonBattleData = call.result.response;
  2678. lastDungeonBattleStart = Date.now();
  2679. }
  2680. /**
  2681. * Getting the number of prediction cards
  2682. * Получение количества карт предсказаний
  2683. */
  2684. if (call.ident == callsIdent['inventoryGet']) {
  2685. countPredictionCard = call.result.response.consumable[81] || 0;
  2686. }
  2687. /**
  2688. * Getting subscription status
  2689. * Получение состояния подписки
  2690. */
  2691. if (call.ident == callsIdent['subscriptionGetInfo']) {
  2692. const subscription = call.result.response.subscription;
  2693. if (subscription) {
  2694. subEndTime = subscription.endTime * 1000;
  2695. }
  2696. }
  2697. /**
  2698. * Getting prediction cards
  2699. * Получение карт предсказаний
  2700. */
  2701. if (call.ident == callsIdent['questFarm']) {
  2702. const consumable = call.result.response?.consumable;
  2703. if (consumable && consumable[81]) {
  2704. countPredictionCard += consumable[81];
  2705. console.log(`Cards: ${countPredictionCard}`);
  2706. }
  2707. }
  2708. /**
  2709. * Hiding extra servers
  2710. * Скрытие лишних серверов
  2711. */
  2712. if (call.ident == callsIdent['serverGetAll'] && isChecked('hideServers')) {
  2713. let servers = call.result.response.users.map(s => s.serverId)
  2714. call.result.response.servers = call.result.response.servers.filter(s => servers.includes(s.id));
  2715. isChange = true;
  2716. }
  2717. /**
  2718. * Displays player positions in the adventure
  2719. * Отображает позиции игроков в приключении
  2720. */
  2721. if (call.ident == callsIdent['adventure_getLobbyInfo']) {
  2722. const users = Object.values(call.result.response.users);
  2723. const mapIdent = call.result.response.mapIdent;
  2724. const adventureId = call.result.response.adventureId;
  2725. const maps = {
  2726. adv_strongford_3pl_hell: 9,
  2727. adv_valley_3pl_hell: 10,
  2728. adv_ghirwil_3pl_hell: 11,
  2729. adv_angels_3pl_hell: 12,
  2730. }
  2731. let msg = I18N('MAP') + (mapIdent in maps ? maps[mapIdent] : adventureId);
  2732. msg += '<br>' + I18N('PLAYER_POS');
  2733. for (const user of users) {
  2734. msg += `<br>${user.user.name} - ${user.currentNode}`;
  2735. }
  2736. setProgress(msg, false, hideProgress);
  2737. }
  2738. /**
  2739. * Automatic launch of a raid at the end of the adventure
  2740. * Автоматический запуск рейда при окончании приключения
  2741. */
  2742. if (call.ident == callsIdent['adventure_end']) {
  2743. autoRaidAdventure()
  2744. }
  2745. /** Удаление лавки редкостей */
  2746. if (call.ident == callsIdent['missionRaid']) {
  2747. if (call.result?.heroesMerchant) {
  2748. delete call.result.heroesMerchant;
  2749. isChange = true;
  2750. }
  2751. }
  2752. /** missionTimer */
  2753. if (call.ident == callsIdent['missionStart']) {
  2754. missionBattle = call.result.response;
  2755. }
  2756. /** Награды турнира стихий */
  2757. if (call.ident == callsIdent['hallOfFameGetTrophies']) {
  2758. const trophys = call.result.response;
  2759. const calls = [];
  2760. for (const week in trophys) {
  2761. const trophy = trophys[week];
  2762. if (!trophy.championRewardFarmed) {
  2763. calls.push({
  2764. name: 'hallOfFameFarmTrophyReward',
  2765. args: { trophyId: week, rewardType: 'champion' },
  2766. ident: 'body_champion_' + week,
  2767. });
  2768. }
  2769. if (Object.keys(trophy.clanReward).length && !trophy.clanRewardFarmed) {
  2770. calls.push({
  2771. name: 'hallOfFameFarmTrophyReward',
  2772. args: { trophyId: week, rewardType: 'clan' },
  2773. ident: 'body_clan_' + week,
  2774. });
  2775. }
  2776. }
  2777. if (calls.length) {
  2778. Send({ calls })
  2779. .then((e) => e.results.map((e) => e.result.response))
  2780. .then(async results => {
  2781. let coin18 = 0,
  2782. coin19 = 0,
  2783. gold = 0,
  2784. starmoney = 0;
  2785. for (const r of results) {
  2786. coin18 += r?.coin ? +r.coin[18] : 0;
  2787. coin19 += r?.coin ? +r.coin[19] : 0;
  2788. gold += r?.gold ? +r.gold : 0;
  2789. starmoney += r?.starmoney ? +r.starmoney : 0;
  2790. }
  2791.  
  2792. let msg = I18N('ELEMENT_TOURNAMENT_REWARD') + '<br>';
  2793. if (coin18) {
  2794. msg += cheats.translate('LIB_COIN_NAME_18') + `: ${coin18}<br>`;
  2795. }
  2796. if (coin19) {
  2797. msg += cheats.translate('LIB_COIN_NAME_19') + `: ${coin19}<br>`;
  2798. }
  2799. if (gold) {
  2800. msg += cheats.translate('LIB_PSEUDO_COIN') + `: ${gold}<br>`;
  2801. }
  2802. if (starmoney) {
  2803. msg += cheats.translate('LIB_PSEUDO_STARMONEY') + `: ${starmoney}<br>`;
  2804. }
  2805.  
  2806. await popup.confirm(msg, [{ msg: I18N('BTN_OK'), result: 0 }]);
  2807. });
  2808. }
  2809. }
  2810. if (call.ident == callsIdent['clanDomination_getInfo']) {
  2811. clanDominationGetInfo = call.result.response;
  2812. }
  2813. if (call.ident == callsIdent['chatGetAll'] && call.args.chatType == 'clanDomination' && !callsIdent['clanDomination_mapState']) {
  2814. this.onReadySuccess = async function () {
  2815. const result = await Send({
  2816. calls: [
  2817. {
  2818. name: 'clanDomination_mapState',
  2819. args: {},
  2820. ident: 'clanDomination_mapState',
  2821. },
  2822. ],
  2823. }).then((e) => e.results[0].result.response);
  2824. let townPositions = result.townPositions;
  2825. let positions = {};
  2826. for (let pos in townPositions) {
  2827. let townPosition = townPositions[pos];
  2828. positions[townPosition.position] = townPosition;
  2829. }
  2830. Object.assign(clanDominationGetInfo, {
  2831. townPositions: positions,
  2832. });
  2833. let userPositions = result.userPositions;
  2834. for (let pos in clanDominationGetInfo.townPositions) {
  2835. let townPosition = clanDominationGetInfo.townPositions[pos];
  2836. if (townPosition.status) {
  2837. userPositions[townPosition.userId] = +pos;
  2838. }
  2839. }
  2840. cheats.updateMap(result);
  2841. };
  2842. }
  2843. if (call.ident == callsIdent['clanDomination_mapState']) {
  2844. const townPositions = call.result.response.townPositions;
  2845. const userPositions = call.result.response.userPositions;
  2846. for (let pos in townPositions) {
  2847. let townPos = townPositions[pos];
  2848. if (townPos.status) {
  2849. userPositions[townPos.userId] = townPos.position;
  2850. }
  2851. }
  2852. isChange = true;
  2853. }
  2854. }
  2855.  
  2856. if (mainReward && artifactChestOpen) {
  2857. console.log(allReward);
  2858. mainReward[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'] = [allReward];
  2859. artifactChestOpen = false;
  2860. artifactChestOpenCallName = '';
  2861. isChange = true;
  2862. }
  2863. } catch(err) {
  2864. console.log("Request(response, " + this.uniqid + "):\n", "Error:\n", response, err);
  2865. }
  2866.  
  2867. if (isChange) {
  2868. Object.defineProperty(this, 'responseText', {
  2869. writable: true
  2870. });
  2871. this.responseText = JSON.stringify(respond);
  2872. }
  2873. }
  2874.  
  2875. /**
  2876. * Request an answer to a question
  2877. *
  2878. * Запрос ответа на вопрос
  2879. */
  2880. async function getAnswer(question) {
  2881. // c29tZSBzdHJhbmdlIHN5bWJvbHM=
  2882. const quizAPI = new ZingerYWebsiteAPI('getAnswer.php', arguments, { question });
  2883. return new Promise((resolve, reject) => {
  2884. quizAPI.request().then((data) => {
  2885. if (data.result) {
  2886. resolve(data.result);
  2887. } else {
  2888. resolve(false);
  2889. }
  2890. }).catch((error) => {
  2891. console.error(error);
  2892. resolve(false);
  2893. });
  2894. })
  2895. }
  2896.  
  2897. /**
  2898. * Submitting a question and answer to a database
  2899. *
  2900. * Отправка вопроса и ответа в базу данных
  2901. */
  2902. function sendAnswerInfo(answerInfo) {
  2903. // c29tZSBub25zZW5zZQ==
  2904. const quizAPI = new ZingerYWebsiteAPI('setAnswer.php', arguments, { answerInfo });
  2905. quizAPI.request().then((data) => {
  2906. if (data.result) {
  2907. console.log(I18N('SENT_QUESTION'));
  2908. }
  2909. });
  2910. }
  2911.  
  2912. /**
  2913. * Returns the battle type by preset type
  2914. *
  2915. * Возвращает тип боя по типу пресета
  2916. */
  2917. function getBattleType(strBattleType) {
  2918. if (!strBattleType) {
  2919. return null;
  2920. }
  2921. switch (strBattleType) {
  2922. case 'titan_pvp':
  2923. return 'get_titanPvp';
  2924. case 'titan_pvp_manual':
  2925. case 'titan_clan_pvp':
  2926. case 'clan_pvp_titan':
  2927. case 'clan_global_pvp_titan':
  2928. case 'brawl_titan':
  2929. case 'challenge_titan':
  2930. case 'titan_mission':
  2931. return 'get_titanPvpManual';
  2932. case 'clan_raid': // Asgard Boss // Босс асгарда
  2933. case 'adventure': // Adventures // Приключения
  2934. case 'clan_global_pvp':
  2935. case 'epic_brawl':
  2936. case 'clan_pvp':
  2937. return 'get_clanPvp';
  2938. case 'dungeon_titan':
  2939. case 'titan_tower':
  2940. return 'get_titan';
  2941. case 'tower':
  2942. return 'get_tower';
  2943. case 'clan_dungeon':
  2944. case 'pve':
  2945. case 'mission':
  2946. return 'get_pve';
  2947. case 'mission_boss':
  2948. return 'get_missionBoss';
  2949. case 'challenge':
  2950. case 'pvp_manual':
  2951. return 'get_pvpManual';
  2952. case 'grand':
  2953. case 'arena':
  2954. case 'pvp':
  2955. case 'clan_domination':
  2956. return 'get_pvp';
  2957. case 'core':
  2958. return 'get_core';
  2959. default: {
  2960. if (strBattleType.includes('invasion')) {
  2961. return 'get_invasion';
  2962. }
  2963. if (strBattleType.includes('boss')) {
  2964. return 'get_boss';
  2965. }
  2966. if (strBattleType.includes('titan_arena')) {
  2967. return 'get_titanPvpManual';
  2968. }
  2969. return 'get_clanPvp';
  2970. }
  2971. }
  2972. }
  2973. /**
  2974. * Returns the class name of the passed object
  2975. *
  2976. * Возвращает название класса переданного объекта
  2977. */
  2978. function getClass(obj) {
  2979. return {}.toString.call(obj).slice(8, -1);
  2980. }
  2981. /**
  2982. * Calculates the request signature
  2983. *
  2984. * Расчитывает сигнатуру запроса
  2985. */
  2986. this.getSignature = function(headers, data) {
  2987. const sign = {
  2988. signature: '',
  2989. length: 0,
  2990. add: function (text) {
  2991. this.signature += text;
  2992. if (this.length < this.signature.length) {
  2993. this.length = 3 * (this.signature.length + 1) >> 1;
  2994. }
  2995. },
  2996. }
  2997. sign.add(headers["X-Request-Id"]);
  2998. sign.add(':');
  2999. sign.add(headers["X-Auth-Token"]);
  3000. sign.add(':');
  3001. sign.add(headers["X-Auth-Session-Id"]);
  3002. sign.add(':');
  3003. sign.add(data);
  3004. sign.add(':');
  3005. sign.add('LIBRARY-VERSION=1');
  3006. sign.add('UNIQUE-SESSION-ID=' + headers["X-Env-Unique-Session-Id"]);
  3007.  
  3008. return md5(sign.signature);
  3009. }
  3010. /**
  3011. * Creates an interface
  3012. *
  3013. * Создает интерфейс
  3014. */
  3015. function createInterface() {
  3016. popup.init();
  3017. scriptMenu.init({
  3018. showMenu: true
  3019. });
  3020. scriptMenu.addHeader(GM_info.script.name, justInfo);
  3021. scriptMenu.addHeader('v' + GM_info.script.version);
  3022. }
  3023.  
  3024. function addControls() {
  3025. createInterface();
  3026. const checkboxDetails = scriptMenu.addDetails(I18N('SETTINGS'));
  3027. for (let name in checkboxes) {
  3028. if (checkboxes[name].hide) {
  3029. continue;
  3030. }
  3031. checkboxes[name].cbox = scriptMenu.addCheckbox(checkboxes[name].label, checkboxes[name].title, checkboxDetails);
  3032. /**
  3033. * Getting the state of checkboxes from storage
  3034. * Получаем состояние чекбоксов из storage
  3035. */
  3036. let val = storage.get(name, null);
  3037. if (val != null) {
  3038. checkboxes[name].cbox.checked = val;
  3039. } else {
  3040. storage.set(name, checkboxes[name].default);
  3041. checkboxes[name].cbox.checked = checkboxes[name].default;
  3042. }
  3043. /**
  3044. * Tracing the change event of the checkbox for writing to storage
  3045. * Отсеживание события изменения чекбокса для записи в storage
  3046. */
  3047. checkboxes[name].cbox.dataset['name'] = name;
  3048. checkboxes[name].cbox.addEventListener('change', async function (event) {
  3049. const nameCheckbox = this.dataset['name'];
  3050. /*
  3051. if (this.checked && nameCheckbox == 'cancelBattle') {
  3052. this.checked = false;
  3053. if (await popup.confirm(I18N('MSG_BAN_ATTENTION'), [
  3054. { msg: I18N('BTN_NO_I_AM_AGAINST'), result: true },
  3055. { msg: I18N('BTN_YES_I_AGREE'), result: false },
  3056. ])) {
  3057. return;
  3058. }
  3059. this.checked = true;
  3060. }
  3061. */
  3062. storage.set(nameCheckbox, this.checked);
  3063. })
  3064. }
  3065.  
  3066. const inputDetails = scriptMenu.addDetails(I18N('VALUES'));
  3067. for (let name in inputs) {
  3068. inputs[name].input = scriptMenu.addInputText(inputs[name].title, false, inputDetails);
  3069. /**
  3070. * Get inputText state from storage
  3071. * Получаем состояние inputText из storage
  3072. */
  3073. let val = storage.get(name, null);
  3074. if (val != null) {
  3075. inputs[name].input.value = val;
  3076. } else {
  3077. storage.set(name, inputs[name].default);
  3078. inputs[name].input.value = inputs[name].default;
  3079. }
  3080. /**
  3081. * Tracing a field change event for a record in storage
  3082. * Отсеживание события изменения поля для записи в storage
  3083. */
  3084. inputs[name].input.dataset['name'] = name;
  3085. inputs[name].input.addEventListener('input', function () {
  3086. const inputName = this.dataset['name'];
  3087. let value = +this.value;
  3088. if (!value || Number.isNaN(value)) {
  3089. value = storage.get(inputName, inputs[inputName].default);
  3090. inputs[name].input.value = value;
  3091. }
  3092. storage.set(inputName, value);
  3093. })
  3094. }
  3095. }
  3096.  
  3097. /**
  3098. * Sending a request
  3099. *
  3100. * Отправка запроса
  3101. */
  3102. function send(json, callback, pr) {
  3103. if (typeof json == 'string') {
  3104. json = JSON.parse(json);
  3105. }
  3106. for (const call of json.calls) {
  3107. if (!call?.context?.actionTs) {
  3108. call.context = {
  3109. actionTs: Math.floor(performance.now())
  3110. }
  3111. }
  3112. }
  3113. json = JSON.stringify(json);
  3114. /**
  3115. * We get the headlines of the previous intercepted request
  3116. * Получаем заголовки предыдущего перехваченого запроса
  3117. */
  3118. let headers = lastHeaders;
  3119. /**
  3120. * We increase the header of the query Certifier by 1
  3121. * Увеличиваем заголовок идетификатора запроса на 1
  3122. */
  3123. headers["X-Request-Id"]++;
  3124. /**
  3125. * We calculate the title with the signature
  3126. * Расчитываем заголовок с сигнатурой
  3127. */
  3128. headers["X-Auth-Signature"] = getSignature(headers, json);
  3129. /**
  3130. * Create a new ajax request
  3131. * Создаем новый AJAX запрос
  3132. */
  3133. let xhr = new XMLHttpRequest;
  3134. /**
  3135. * Indicate the previously saved URL for API queries
  3136. * Указываем ранее сохраненный URL для API запросов
  3137. */
  3138. xhr.open('POST', apiUrl, true);
  3139. /**
  3140. * Add the function to the event change event
  3141. * Добавляем функцию к событию смены статуса запроса
  3142. */
  3143. xhr.onreadystatechange = function() {
  3144. /**
  3145. * If the result of the request is obtained, we call the flask function
  3146. * Если результат запроса получен вызываем колбек функцию
  3147. */
  3148. if(xhr.readyState == 4) {
  3149. callback(xhr.response, pr);
  3150. }
  3151. };
  3152. /**
  3153. * Indicate the type of request
  3154. * Указываем тип запроса
  3155. */
  3156. xhr.responseType = 'json';
  3157. /**
  3158. * We set the request headers
  3159. * Задаем заголовки запроса
  3160. */
  3161. for(let nameHeader in headers) {
  3162. let head = headers[nameHeader];
  3163. xhr.setRequestHeader(nameHeader, head);
  3164. }
  3165. /**
  3166. * Sending a request
  3167. * Отправляем запрос
  3168. */
  3169. xhr.send(json);
  3170. }
  3171.  
  3172. let hideTimeoutProgress = 0;
  3173. /**
  3174. * Hide progress
  3175. *
  3176. * Скрыть прогресс
  3177. */
  3178. function hideProgress(timeout) {
  3179. timeout = timeout || 0;
  3180. clearTimeout(hideTimeoutProgress);
  3181. hideTimeoutProgress = setTimeout(function () {
  3182. scriptMenu.setStatus('');
  3183. }, timeout);
  3184. }
  3185. /**
  3186. * Progress display
  3187. *
  3188. * Отображение прогресса
  3189. */
  3190. function setProgress(text, hide, onclick) {
  3191. scriptMenu.setStatus(text, onclick);
  3192. hide = hide || false;
  3193. if (hide) {
  3194. hideProgress(3000);
  3195. }
  3196. }
  3197.  
  3198. /**
  3199. * Returns the timer value depending on the subscription
  3200. *
  3201. * Возвращает значение таймера в зависимости от подписки
  3202. */
  3203. function getTimer(time, div) {
  3204. let speedDiv = 5;
  3205. if (subEndTime < Date.now()) {
  3206. speedDiv = div || 1.5;
  3207. }
  3208. return Math.max(Math.ceil(time / speedDiv + 1.5), 4);
  3209. }
  3210.  
  3211. /**
  3212. * Calculates HASH MD5 from string
  3213. *
  3214. * Расчитывает HASH MD5 из строки
  3215. *
  3216. * [js-md5]{@link https://github.com/emn178/js-md5}
  3217. *
  3218. * @namespace md5
  3219. * @version 0.7.3
  3220. * @author Chen, Yi-Cyuan [emn178@gmail.com]
  3221. * @copyright Chen, Yi-Cyuan 2014-2017
  3222. * @license MIT
  3223. */
  3224. !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 _}))}();
  3225.  
  3226. /**
  3227. * Script for beautiful dialog boxes
  3228. *
  3229. * Скрипт для красивых диалоговых окошек
  3230. */
  3231. const popup = new (function () {
  3232. this.popUp,
  3233. this.downer,
  3234. this.middle,
  3235. this.msgText,
  3236. this.buttons = [];
  3237. this.checkboxes = [];
  3238. this.dialogPromice = null;
  3239.  
  3240. this.init = function () {
  3241. addStyle();
  3242. addBlocks();
  3243. addEventListeners();
  3244. }
  3245.  
  3246. const addEventListeners = () => {
  3247. document.addEventListener('keyup', (e) => {
  3248. if (e.key == 'Escape') {
  3249. if (this.dialogPromice) {
  3250. const { func, result } = this.dialogPromice;
  3251. this.dialogPromice = null;
  3252. popup.hide();
  3253. func(result);
  3254. }
  3255. }
  3256. });
  3257. }
  3258.  
  3259. const addStyle = () => {
  3260. let style = document.createElement('style');
  3261. style.innerText = `
  3262. .PopUp_ {
  3263. position: absolute;
  3264. min-width: 300px;
  3265. max-width: 500px;
  3266. max-height: 600px;
  3267. background-color: #190e08e6;
  3268. z-index: 10001;
  3269. top: 169px;
  3270. left: 345px;
  3271. border: 3px #ce9767 solid;
  3272. border-radius: 10px;
  3273. display: flex;
  3274. flex-direction: column;
  3275. justify-content: space-around;
  3276. padding: 15px 9px;
  3277. box-sizing: border-box;
  3278. }
  3279.  
  3280. .PopUp_back {
  3281. position: absolute;
  3282. background-color: #00000066;
  3283. width: 100%;
  3284. height: 100%;
  3285. z-index: 10000;
  3286. top: 0;
  3287. left: 0;
  3288. }
  3289.  
  3290. .PopUp_close {
  3291. width: 40px;
  3292. height: 40px;
  3293. position: absolute;
  3294. right: -18px;
  3295. top: -18px;
  3296. border: 3px solid #c18550;
  3297. border-radius: 20px;
  3298. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  3299. background-position-y: 3px;
  3300. box-shadow: -1px 1px 3px black;
  3301. cursor: pointer;
  3302. box-sizing: border-box;
  3303. }
  3304.  
  3305. .PopUp_close:hover {
  3306. filter: brightness(1.2);
  3307. }
  3308.  
  3309. .PopUp_crossClose {
  3310. width: 100%;
  3311. height: 100%;
  3312. background-size: 65%;
  3313. background-position: center;
  3314. background-repeat: no-repeat;
  3315. 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")
  3316. }
  3317.  
  3318. .PopUp_blocks {
  3319. width: 100%;
  3320. height: 50%;
  3321. display: flex;
  3322. justify-content: space-evenly;
  3323. align-items: center;
  3324. flex-wrap: wrap;
  3325. justify-content: center;
  3326. }
  3327.  
  3328. .PopUp_blocks:last-child {
  3329. margin-top: 25px;
  3330. }
  3331.  
  3332. .PopUp_buttons {
  3333. display: flex;
  3334. margin: 7px 10px;
  3335. flex-direction: column;
  3336. }
  3337.  
  3338. .PopUp_button {
  3339. background-color: #52A81C;
  3340. border-radius: 5px;
  3341. box-shadow: inset 0px -4px 10px, inset 0px 3px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  3342. cursor: pointer;
  3343. padding: 4px 12px 6px;
  3344. }
  3345.  
  3346. .PopUp_input {
  3347. text-align: center;
  3348. font-size: 16px;
  3349. height: 27px;
  3350. border: 1px solid #cf9250;
  3351. border-radius: 9px 9px 0px 0px;
  3352. background: transparent;
  3353. color: #fce1ac;
  3354. padding: 1px 10px;
  3355. box-sizing: border-box;
  3356. box-shadow: 0px 0px 4px, 0px 0px 0px 3px #ce9767;
  3357. }
  3358.  
  3359. .PopUp_checkboxes {
  3360. display: flex;
  3361. flex-direction: column;
  3362. margin: 15px 15px -5px 15px;
  3363. align-items: flex-start;
  3364. }
  3365.  
  3366. .PopUp_ContCheckbox {
  3367. margin: 2px 0px;
  3368. }
  3369.  
  3370. .PopUp_checkbox {
  3371. position: absolute;
  3372. z-index: -1;
  3373. opacity: 0;
  3374. }
  3375. .PopUp_checkbox+label {
  3376. display: inline-flex;
  3377. align-items: center;
  3378. user-select: none;
  3379.  
  3380. font-size: 15px;
  3381. font-family: sans-serif;
  3382. font-weight: 600;
  3383. font-stretch: condensed;
  3384. letter-spacing: 1px;
  3385. color: #fce1ac;
  3386. text-shadow: 0px 0px 1px;
  3387. }
  3388. .PopUp_checkbox+label::before {
  3389. content: '';
  3390. display: inline-block;
  3391. width: 20px;
  3392. height: 20px;
  3393. border: 1px solid #cf9250;
  3394. border-radius: 7px;
  3395. margin-right: 7px;
  3396. }
  3397. .PopUp_checkbox:checked+label::before {
  3398. 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");
  3399. }
  3400.  
  3401. .PopUp_input::placeholder {
  3402. color: #fce1ac75;
  3403. }
  3404.  
  3405. .PopUp_input:focus {
  3406. outline: 0;
  3407. }
  3408.  
  3409. .PopUp_input + .PopUp_button {
  3410. border-radius: 0px 0px 5px 5px;
  3411. padding: 2px 18px 5px;
  3412. }
  3413.  
  3414. .PopUp_button:hover {
  3415. filter: brightness(1.2);
  3416. }
  3417.  
  3418. .PopUp_button:active {
  3419. box-shadow: inset 0px 5px 10px, inset 0px 1px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  3420. }
  3421.  
  3422. .PopUp_text {
  3423. font-size: 22px;
  3424. font-family: sans-serif;
  3425. font-weight: 600;
  3426. font-stretch: condensed;
  3427. letter-spacing: 1px;
  3428. text-align: center;
  3429. }
  3430.  
  3431. .PopUp_buttonText {
  3432. color: #E4FF4C;
  3433. text-shadow: 0px 1px 2px black;
  3434. }
  3435.  
  3436. .PopUp_msgText {
  3437. color: #FDE5B6;
  3438. text-shadow: 0px 0px 2px;
  3439. }
  3440.  
  3441. .PopUp_hideBlock {
  3442. display: none;
  3443. }
  3444. `;
  3445. document.head.appendChild(style);
  3446. }
  3447.  
  3448. const addBlocks = () => {
  3449. this.back = document.createElement('div');
  3450. this.back.classList.add('PopUp_back');
  3451. this.back.classList.add('PopUp_hideBlock');
  3452. document.body.append(this.back);
  3453.  
  3454. this.popUp = document.createElement('div');
  3455. this.popUp.classList.add('PopUp_');
  3456. this.back.append(this.popUp);
  3457.  
  3458. let upper = document.createElement('div')
  3459. upper.classList.add('PopUp_blocks');
  3460. this.popUp.append(upper);
  3461.  
  3462. this.middle = document.createElement('div')
  3463. this.middle.classList.add('PopUp_blocks');
  3464. this.middle.classList.add('PopUp_checkboxes');
  3465. this.popUp.append(this.middle);
  3466.  
  3467. this.downer = document.createElement('div')
  3468. this.downer.classList.add('PopUp_blocks');
  3469. this.popUp.append(this.downer);
  3470.  
  3471. this.msgText = document.createElement('div');
  3472. this.msgText.classList.add('PopUp_text', 'PopUp_msgText');
  3473. upper.append(this.msgText);
  3474. }
  3475.  
  3476. this.showBack = function () {
  3477. this.back.classList.remove('PopUp_hideBlock');
  3478. }
  3479.  
  3480. this.hideBack = function () {
  3481. this.back.classList.add('PopUp_hideBlock');
  3482. }
  3483.  
  3484. this.show = function () {
  3485. if (this.checkboxes.length) {
  3486. this.middle.classList.remove('PopUp_hideBlock');
  3487. }
  3488. this.showBack();
  3489. this.popUp.classList.remove('PopUp_hideBlock');
  3490. this.popUp.style.left = (window.innerWidth - this.popUp.offsetWidth) / 2 + 'px';
  3491. this.popUp.style.top = (window.innerHeight - this.popUp.offsetHeight) / 3 + 'px';
  3492. }
  3493.  
  3494. this.hide = function () {
  3495. this.hideBack();
  3496. this.popUp.classList.add('PopUp_hideBlock');
  3497. }
  3498.  
  3499. this.addAnyButton = (option) => {
  3500. const contButton = document.createElement('div');
  3501. contButton.classList.add('PopUp_buttons');
  3502. this.downer.append(contButton);
  3503.  
  3504. let inputField = {
  3505. value: option.result || option.default
  3506. }
  3507. if (option.isInput) {
  3508. inputField = document.createElement('input');
  3509. inputField.type = 'text';
  3510. if (option.placeholder) {
  3511. inputField.placeholder = option.placeholder;
  3512. }
  3513. if (option.default) {
  3514. inputField.value = option.default;
  3515. }
  3516. inputField.classList.add('PopUp_input');
  3517. contButton.append(inputField);
  3518. }
  3519.  
  3520. const button = document.createElement('div');
  3521. button.classList.add('PopUp_button');
  3522. button.title = option.title || '';
  3523. contButton.append(button);
  3524.  
  3525. const buttonText = document.createElement('div');
  3526. buttonText.classList.add('PopUp_text', 'PopUp_buttonText');
  3527. buttonText.innerHTML = option.msg;
  3528. button.append(buttonText);
  3529.  
  3530. return { button, contButton, inputField };
  3531. }
  3532.  
  3533. this.addCloseButton = () => {
  3534. let button = document.createElement('div')
  3535. button.classList.add('PopUp_close');
  3536. this.popUp.append(button);
  3537.  
  3538. let crossClose = document.createElement('div')
  3539. crossClose.classList.add('PopUp_crossClose');
  3540. button.append(crossClose);
  3541.  
  3542. return { button, contButton: button };
  3543. }
  3544.  
  3545. this.addButton = (option, buttonClick) => {
  3546.  
  3547. const { button, contButton, inputField } = option.isClose ? this.addCloseButton() : this.addAnyButton(option);
  3548. if (option.isClose) {
  3549. this.dialogPromice = {func: buttonClick, result: option.result};
  3550. }
  3551. button.addEventListener('click', () => {
  3552. let result = '';
  3553. if (option.isInput) {
  3554. result = inputField.value;
  3555. }
  3556. if (option.isClose || option.isCancel) {
  3557. this.dialogPromice = null;
  3558. }
  3559. buttonClick(result);
  3560. });
  3561.  
  3562. this.buttons.push(contButton);
  3563. }
  3564.  
  3565. this.clearButtons = () => {
  3566. while (this.buttons.length) {
  3567. this.buttons.pop().remove();
  3568. }
  3569. }
  3570.  
  3571. this.addCheckBox = (checkBox) => {
  3572. const contCheckbox = document.createElement('div');
  3573. contCheckbox.classList.add('PopUp_ContCheckbox');
  3574. this.middle.append(contCheckbox);
  3575.  
  3576. const checkbox = document.createElement('input');
  3577. checkbox.type = 'checkbox';
  3578. checkbox.id = 'PopUpCheckbox' + this.checkboxes.length;
  3579. checkbox.dataset.name = checkBox.name;
  3580. checkbox.checked = checkBox.checked;
  3581. checkbox.label = checkBox.label;
  3582. checkbox.title = checkBox.title || '';
  3583. checkbox.classList.add('PopUp_checkbox');
  3584. contCheckbox.appendChild(checkbox)
  3585.  
  3586. const checkboxLabel = document.createElement('label');
  3587. checkboxLabel.innerText = checkBox.label;
  3588. checkboxLabel.title = checkBox.title || '';
  3589. checkboxLabel.setAttribute('for', checkbox.id);
  3590. contCheckbox.appendChild(checkboxLabel);
  3591.  
  3592. this.checkboxes.push(checkbox);
  3593. }
  3594.  
  3595. this.clearCheckBox = () => {
  3596. this.middle.classList.add('PopUp_hideBlock');
  3597. while (this.checkboxes.length) {
  3598. this.checkboxes.pop().parentNode.remove();
  3599. }
  3600. }
  3601.  
  3602. this.setMsgText = (text) => {
  3603. this.msgText.innerHTML = text;
  3604. }
  3605.  
  3606. this.getCheckBoxes = () => {
  3607. const checkBoxes = [];
  3608.  
  3609. for (const checkBox of this.checkboxes) {
  3610. checkBoxes.push({
  3611. name: checkBox.dataset.name,
  3612. label: checkBox.label,
  3613. checked: checkBox.checked
  3614. });
  3615. }
  3616.  
  3617. return checkBoxes;
  3618. }
  3619.  
  3620. this.confirm = async (msg, buttOpt, checkBoxes = []) => {
  3621. this.clearButtons();
  3622. this.clearCheckBox();
  3623. return new Promise((complete, failed) => {
  3624. this.setMsgText(msg);
  3625. if (!buttOpt) {
  3626. buttOpt = [{ msg: 'Ok', result: true, isInput: false }];
  3627. }
  3628. for (const checkBox of checkBoxes) {
  3629. this.addCheckBox(checkBox);
  3630. }
  3631. for (let butt of buttOpt) {
  3632. this.addButton(butt, (result) => {
  3633. result = result || butt.result;
  3634. complete(result);
  3635. popup.hide();
  3636. });
  3637. if (butt.isCancel) {
  3638. this.dialogPromice = {func: complete, result: butt.result};
  3639. }
  3640. }
  3641. this.show();
  3642. });
  3643. }
  3644. });
  3645.  
  3646. /**
  3647. * Script control panel
  3648. *
  3649. * Панель управления скриптом
  3650. */
  3651. const scriptMenu = new (function () {
  3652.  
  3653. this.mainMenu,
  3654. this.buttons = [],
  3655. this.checkboxes = [];
  3656. this.option = {
  3657. showMenu: false,
  3658. showDetails: {}
  3659. };
  3660.  
  3661. this.init = function (option = {}) {
  3662. this.option = Object.assign(this.option, option);
  3663. this.option.showDetails = this.loadShowDetails();
  3664. addStyle();
  3665. addBlocks();
  3666. }
  3667.  
  3668. const addStyle = () => {
  3669. style = document.createElement('style');
  3670. style.innerText = `
  3671. .scriptMenu_status {
  3672. position: absolute;
  3673. z-index: 10001;
  3674. /* max-height: 30px; */
  3675. top: -1px;
  3676. left: 30%;
  3677. cursor: pointer;
  3678. border-radius: 0px 0px 10px 10px;
  3679. background: #190e08e6;
  3680. border: 1px #ce9767 solid;
  3681. font-size: 18px;
  3682. font-family: sans-serif;
  3683. font-weight: 600;
  3684. font-stretch: condensed;
  3685. letter-spacing: 1px;
  3686. color: #fce1ac;
  3687. text-shadow: 0px 0px 1px;
  3688. transition: 0.5s;
  3689. padding: 2px 10px 3px;
  3690. }
  3691. .scriptMenu_statusHide {
  3692. top: -35px;
  3693. height: 30px;
  3694. overflow: hidden;
  3695. }
  3696. .scriptMenu_label {
  3697. position: absolute;
  3698. top: 30%;
  3699. left: -4px;
  3700. z-index: 9999;
  3701. cursor: pointer;
  3702. width: 30px;
  3703. height: 30px;
  3704. background: radial-gradient(circle, #47a41b 0%, #1a2f04 100%);
  3705. border: 1px solid #1a2f04;
  3706. border-radius: 5px;
  3707. box-shadow:
  3708. inset 0px 2px 4px #83ce26,
  3709. inset 0px -4px 6px #1a2f04,
  3710. 0px 0px 2px black,
  3711. 0px 0px 0px 2px #ce9767;
  3712. }
  3713. .scriptMenu_label:hover {
  3714. filter: brightness(1.2);
  3715. }
  3716. .scriptMenu_arrowLabel {
  3717. width: 100%;
  3718. height: 100%;
  3719. background-size: 75%;
  3720. background-position: center;
  3721. background-repeat: no-repeat;
  3722. 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");
  3723. box-shadow: 0px 1px 2px #000;
  3724. border-radius: 5px;
  3725. filter: drop-shadow(0px 1px 2px #000D);
  3726. }
  3727. .scriptMenu_main {
  3728. position: absolute;
  3729. max-width: 285px;
  3730. z-index: 9999;
  3731. top: 50%;
  3732. transform: translateY(-40%);
  3733. background: #190e08e6;
  3734. border: 1px #ce9767 solid;
  3735. border-radius: 0px 10px 10px 0px;
  3736. border-left: none;
  3737. padding: 5px 10px 5px 5px;
  3738. box-sizing: border-box;
  3739. font-size: 15px;
  3740. font-family: sans-serif;
  3741. font-weight: 600;
  3742. font-stretch: condensed;
  3743. letter-spacing: 1px;
  3744. color: #fce1ac;
  3745. text-shadow: 0px 0px 1px;
  3746. transition: 1s;
  3747. display: flex;
  3748. flex-direction: column;
  3749. flex-wrap: nowrap;
  3750. }
  3751. .scriptMenu_showMenu {
  3752. display: none;
  3753. }
  3754. .scriptMenu_showMenu:checked~.scriptMenu_main {
  3755. left: 0px;
  3756. }
  3757. .scriptMenu_showMenu:not(:checked)~.scriptMenu_main {
  3758. left: -300px;
  3759. }
  3760. .scriptMenu_divInput {
  3761. margin: 2px;
  3762. }
  3763. .scriptMenu_divInputText {
  3764. margin: 2px;
  3765. align-self: center;
  3766. display: flex;
  3767. }
  3768. .scriptMenu_checkbox {
  3769. position: absolute;
  3770. z-index: -1;
  3771. opacity: 0;
  3772. }
  3773. .scriptMenu_checkbox+label {
  3774. display: inline-flex;
  3775. align-items: center;
  3776. user-select: none;
  3777. }
  3778. .scriptMenu_checkbox+label::before {
  3779. content: '';
  3780. display: inline-block;
  3781. width: 20px;
  3782. height: 20px;
  3783. border: 1px solid #cf9250;
  3784. border-radius: 7px;
  3785. margin-right: 7px;
  3786. }
  3787. .scriptMenu_checkbox:checked+label::before {
  3788. 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");
  3789. }
  3790. .scriptMenu_close {
  3791. width: 40px;
  3792. height: 40px;
  3793. position: absolute;
  3794. right: -18px;
  3795. top: -18px;
  3796. border: 3px solid #c18550;
  3797. border-radius: 20px;
  3798. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  3799. background-position-y: 3px;
  3800. box-shadow: -1px 1px 3px black;
  3801. cursor: pointer;
  3802. box-sizing: border-box;
  3803. }
  3804. .scriptMenu_close:hover {
  3805. filter: brightness(1.2);
  3806. }
  3807. .scriptMenu_crossClose {
  3808. width: 100%;
  3809. height: 100%;
  3810. background-size: 65%;
  3811. background-position: center;
  3812. background-repeat: no-repeat;
  3813. 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")
  3814. }
  3815. .scriptMenu_button {
  3816. user-select: none;
  3817. border-radius: 5px;
  3818. cursor: pointer;
  3819. padding: 5px 14px 8px;
  3820. margin: 4px;
  3821. background: radial-gradient(circle, rgba(165,120,56,1) 80%, rgba(0,0,0,1) 110%);
  3822. box-shadow: inset 0px -4px 6px #442901, inset 0px 1px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  3823. }
  3824. .scriptMenu_button:hover {
  3825. filter: brightness(1.2);
  3826. }
  3827. .scriptMenu_button:active {
  3828. box-shadow: inset 0px 4px 6px #442901, inset 0px 4px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  3829. }
  3830. .scriptMenu_buttonText {
  3831. color: #fce5b7;
  3832. text-shadow: 0px 1px 2px black;
  3833. text-align: center;
  3834. }
  3835. .scriptMenu_header {
  3836. text-align: center;
  3837. align-self: center;
  3838. font-size: 15px;
  3839. margin: 0px 15px;
  3840. }
  3841. .scriptMenu_header a {
  3842. color: #fce5b7;
  3843. text-decoration: none;
  3844. }
  3845. .scriptMenu_InputText {
  3846. text-align: center;
  3847. width: 130px;
  3848. height: 24px;
  3849. border: 1px solid #cf9250;
  3850. border-radius: 9px;
  3851. background: transparent;
  3852. color: #fce1ac;
  3853. padding: 0px 10px;
  3854. box-sizing: border-box;
  3855. }
  3856. .scriptMenu_InputText:focus {
  3857. filter: brightness(1.2);
  3858. outline: 0;
  3859. }
  3860. .scriptMenu_InputText::placeholder {
  3861. color: #fce1ac75;
  3862. }
  3863. .scriptMenu_Summary {
  3864. cursor: pointer;
  3865. margin-left: 7px;
  3866. }
  3867. .scriptMenu_Details {
  3868. align-self: center;
  3869. }
  3870. `;
  3871. document.head.appendChild(style);
  3872. }
  3873.  
  3874. const addBlocks = () => {
  3875. const main = document.createElement('div');
  3876. document.body.appendChild(main);
  3877.  
  3878. this.status = document.createElement('div');
  3879. this.status.classList.add('scriptMenu_status');
  3880. this.setStatus('');
  3881. main.appendChild(this.status);
  3882.  
  3883. const label = document.createElement('label');
  3884. label.classList.add('scriptMenu_label');
  3885. label.setAttribute('for', 'checkbox_showMenu');
  3886. main.appendChild(label);
  3887.  
  3888. const arrowLabel = document.createElement('div');
  3889. arrowLabel.classList.add('scriptMenu_arrowLabel');
  3890. label.appendChild(arrowLabel);
  3891.  
  3892. const checkbox = document.createElement('input');
  3893. checkbox.type = 'checkbox';
  3894. checkbox.id = 'checkbox_showMenu';
  3895. checkbox.checked = this.option.showMenu;
  3896. checkbox.classList.add('scriptMenu_showMenu');
  3897. main.appendChild(checkbox);
  3898.  
  3899. this.mainMenu = document.createElement('div');
  3900. this.mainMenu.classList.add('scriptMenu_main');
  3901. main.appendChild(this.mainMenu);
  3902.  
  3903. const closeButton = document.createElement('label');
  3904. closeButton.classList.add('scriptMenu_close');
  3905. closeButton.setAttribute('for', 'checkbox_showMenu');
  3906. this.mainMenu.appendChild(closeButton);
  3907.  
  3908. const crossClose = document.createElement('div');
  3909. crossClose.classList.add('scriptMenu_crossClose');
  3910. closeButton.appendChild(crossClose);
  3911. }
  3912.  
  3913. this.setStatus = (text, onclick) => {
  3914. if (!text) {
  3915. this.status.classList.add('scriptMenu_statusHide');
  3916. } else {
  3917. this.status.classList.remove('scriptMenu_statusHide');
  3918. this.status.innerHTML = text;
  3919. }
  3920.  
  3921. if (typeof onclick == 'function') {
  3922. this.status.addEventListener("click", onclick, {
  3923. once: true
  3924. });
  3925. }
  3926. }
  3927.  
  3928. /**
  3929. * Adding a text element
  3930. *
  3931. * Добавление текстового элемента
  3932. * @param {String} text text // текст
  3933. * @param {Function} func Click function // функция по клику
  3934. * @param {HTMLDivElement} main parent // родитель
  3935. */
  3936. this.addHeader = (text, func, main) => {
  3937. main = main || this.mainMenu;
  3938. const header = document.createElement('div');
  3939. header.classList.add('scriptMenu_header');
  3940. header.innerHTML = text;
  3941. if (typeof func == 'function') {
  3942. header.addEventListener('click', func);
  3943. }
  3944. main.appendChild(header);
  3945. }
  3946.  
  3947. /**
  3948. * Adding a button
  3949. *
  3950. * Добавление кнопки
  3951. * @param {String} text
  3952. * @param {Function} func
  3953. * @param {String} title
  3954. * @param {HTMLDivElement} main parent // родитель
  3955. */
  3956. this.addButton = (text, func, title, main) => {
  3957. main = main || this.mainMenu;
  3958. const button = document.createElement('div');
  3959. button.classList.add('scriptMenu_button');
  3960. button.title = title;
  3961. button.addEventListener('click', func);
  3962. main.appendChild(button);
  3963.  
  3964. const buttonText = document.createElement('div');
  3965. buttonText.classList.add('scriptMenu_buttonText');
  3966. buttonText.innerText = text;
  3967. button.appendChild(buttonText);
  3968. this.buttons.push(button);
  3969.  
  3970. return button;
  3971. }
  3972.  
  3973. /**
  3974. * Adding checkbox
  3975. *
  3976. * Добавление чекбокса
  3977. * @param {String} label
  3978. * @param {String} title
  3979. * @param {HTMLDivElement} main parent // родитель
  3980. * @returns
  3981. */
  3982. this.addCheckbox = (label, title, main) => {
  3983. main = main || this.mainMenu;
  3984. const divCheckbox = document.createElement('div');
  3985. divCheckbox.classList.add('scriptMenu_divInput');
  3986. divCheckbox.title = title;
  3987. main.appendChild(divCheckbox);
  3988.  
  3989. const checkbox = document.createElement('input');
  3990. checkbox.type = 'checkbox';
  3991. checkbox.id = 'scriptMenuCheckbox' + this.checkboxes.length;
  3992. checkbox.classList.add('scriptMenu_checkbox');
  3993. divCheckbox.appendChild(checkbox)
  3994.  
  3995. const checkboxLabel = document.createElement('label');
  3996. checkboxLabel.innerText = label;
  3997. checkboxLabel.setAttribute('for', checkbox.id);
  3998. divCheckbox.appendChild(checkboxLabel);
  3999.  
  4000. this.checkboxes.push(checkbox);
  4001. return checkbox;
  4002. }
  4003.  
  4004. /**
  4005. * Adding input field
  4006. *
  4007. * Добавление поля ввода
  4008. * @param {String} title
  4009. * @param {String} placeholder
  4010. * @param {HTMLDivElement} main parent // родитель
  4011. * @returns
  4012. */
  4013. this.addInputText = (title, placeholder, main) => {
  4014. main = main || this.mainMenu;
  4015. const divInputText = document.createElement('div');
  4016. divInputText.classList.add('scriptMenu_divInputText');
  4017. divInputText.title = title;
  4018. main.appendChild(divInputText);
  4019.  
  4020. const newInputText = document.createElement('input');
  4021. newInputText.type = 'text';
  4022. if (placeholder) {
  4023. newInputText.placeholder = placeholder;
  4024. }
  4025. newInputText.classList.add('scriptMenu_InputText');
  4026. divInputText.appendChild(newInputText)
  4027. return newInputText;
  4028. }
  4029.  
  4030. /**
  4031. * Adds a dropdown block
  4032. *
  4033. * Добавляет раскрывающийся блок
  4034. * @param {String} summary
  4035. * @param {String} name
  4036. * @returns
  4037. */
  4038. this.addDetails = (summaryText, name = null) => {
  4039. const details = document.createElement('details');
  4040. details.classList.add('scriptMenu_Details');
  4041. this.mainMenu.appendChild(details);
  4042.  
  4043. const summary = document.createElement('summary');
  4044. summary.classList.add('scriptMenu_Summary');
  4045. summary.innerText = summaryText;
  4046. if (name) {
  4047. const self = this;
  4048. details.open = this.option.showDetails[name];
  4049. details.dataset.name = name;
  4050. summary.addEventListener('click', () => {
  4051. self.option.showDetails[details.dataset.name] = !details.open;
  4052. self.saveShowDetails(self.option.showDetails);
  4053. });
  4054. }
  4055. details.appendChild(summary);
  4056.  
  4057. return details;
  4058. }
  4059.  
  4060. /**
  4061. * Saving the expanded state of the details blocks
  4062. *
  4063. * Сохранение состояния развенутости блоков details
  4064. * @param {*} value
  4065. */
  4066. this.saveShowDetails = (value) => {
  4067. localStorage.setItem('scriptMenu_showDetails', JSON.stringify(value));
  4068. }
  4069.  
  4070. /**
  4071. * Loading the state of expanded blocks details
  4072. *
  4073. * Загрузка состояния развенутости блоков details
  4074. * @returns
  4075. */
  4076. this.loadShowDetails = () => {
  4077. let showDetails = localStorage.getItem('scriptMenu_showDetails');
  4078.  
  4079. if (!showDetails) {
  4080. return {};
  4081. }
  4082.  
  4083. try {
  4084. showDetails = JSON.parse(showDetails);
  4085. } catch (e) {
  4086. return {};
  4087. }
  4088.  
  4089. return showDetails;
  4090. }
  4091. });
  4092.  
  4093. /**
  4094. * Пример использования
  4095. scriptMenu.init();
  4096. scriptMenu.addHeader('v1.508');
  4097. scriptMenu.addCheckbox('testHack', 'Тестовый взлом игры!');
  4098. scriptMenu.addButton('Запуск!', () => console.log('click'), 'подсказака');
  4099. scriptMenu.addInputText('input подсказака');
  4100. */
  4101. /**
  4102. * Game Library
  4103. *
  4104. * Игровая библиотека
  4105. */
  4106. class Library {
  4107. defaultLibUrl = 'https://heroesru-a.akamaihd.net/vk/v1101/lib/lib.json';
  4108.  
  4109. constructor() {
  4110. if (!Library.instance) {
  4111. Library.instance = this;
  4112. }
  4113.  
  4114. return Library.instance;
  4115. }
  4116.  
  4117. async load() {
  4118. try {
  4119. await this.getUrlLib();
  4120. console.log(this.defaultLibUrl);
  4121. this.data = await fetch(this.defaultLibUrl).then(e => e.json())
  4122. } catch (error) {
  4123. console.error('Не удалось загрузить библиотеку', error)
  4124. }
  4125. }
  4126.  
  4127. async getUrlLib() {
  4128. try {
  4129. const db = new Database('hw_cache', 'cache');
  4130. await db.open();
  4131. const cacheLibFullUrl = await db.get('lib/lib.json.gz', false);
  4132. this.defaultLibUrl = cacheLibFullUrl.fullUrl.split('.gz').shift();
  4133. } catch(e) {}
  4134. }
  4135.  
  4136. getData(id) {
  4137. return this.data[id];
  4138. }
  4139. }
  4140.  
  4141. this.lib = new Library();
  4142. /**
  4143. * Database
  4144. *
  4145. * База данных
  4146. */
  4147. class Database {
  4148. constructor(dbName, storeName) {
  4149. this.dbName = dbName;
  4150. this.storeName = storeName;
  4151. this.db = null;
  4152. }
  4153.  
  4154. async open() {
  4155. return new Promise((resolve, reject) => {
  4156. const request = indexedDB.open(this.dbName);
  4157.  
  4158. request.onerror = () => {
  4159. reject(new Error(`Failed to open database ${this.dbName}`));
  4160. };
  4161.  
  4162. request.onsuccess = () => {
  4163. this.db = request.result;
  4164. resolve();
  4165. };
  4166.  
  4167. request.onupgradeneeded = (event) => {
  4168. const db = event.target.result;
  4169. if (!db.objectStoreNames.contains(this.storeName)) {
  4170. db.createObjectStore(this.storeName);
  4171. }
  4172. };
  4173. });
  4174. }
  4175.  
  4176. async set(key, value) {
  4177. return new Promise((resolve, reject) => {
  4178. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4179. const store = transaction.objectStore(this.storeName);
  4180. const request = store.put(value, key);
  4181.  
  4182. request.onerror = () => {
  4183. reject(new Error(`Failed to save value with key ${key}`));
  4184. };
  4185.  
  4186. request.onsuccess = () => {
  4187. resolve();
  4188. };
  4189. });
  4190. }
  4191.  
  4192. async get(key, def) {
  4193. return new Promise((resolve, reject) => {
  4194. const transaction = this.db.transaction([this.storeName], 'readonly');
  4195. const store = transaction.objectStore(this.storeName);
  4196. const request = store.get(key);
  4197.  
  4198. request.onerror = () => {
  4199. resolve(def);
  4200. };
  4201.  
  4202. request.onsuccess = () => {
  4203. resolve(request.result);
  4204. };
  4205. });
  4206. }
  4207.  
  4208. async delete(key) {
  4209. return new Promise((resolve, reject) => {
  4210. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4211. const store = transaction.objectStore(this.storeName);
  4212. const request = store.delete(key);
  4213.  
  4214. request.onerror = () => {
  4215. reject(new Error(`Failed to delete value with key ${key}`));
  4216. };
  4217.  
  4218. request.onsuccess = () => {
  4219. resolve();
  4220. };
  4221. });
  4222. }
  4223. }
  4224.  
  4225. /**
  4226. * Returns the stored value
  4227. *
  4228. * Возвращает сохраненное значение
  4229. */
  4230. function getSaveVal(saveName, def) {
  4231. const result = storage.get(saveName, def);
  4232. return result;
  4233. }
  4234.  
  4235. /**
  4236. * Stores value
  4237. *
  4238. * Сохраняет значение
  4239. */
  4240. function setSaveVal(saveName, value) {
  4241. storage.set(saveName, value);
  4242. }
  4243.  
  4244. /**
  4245. * Database initialization
  4246. *
  4247. * Инициализация базы данных
  4248. */
  4249. const db = new Database(GM_info.script.name, 'settings');
  4250.  
  4251. /**
  4252. * Data store
  4253. *
  4254. * Хранилище данных
  4255. */
  4256. const storage = {
  4257. userId: 0,
  4258. /**
  4259. * Default values
  4260. *
  4261. * Значения по умолчанию
  4262. */
  4263. values: [
  4264. ...Object.entries(checkboxes).map(e => ({ [e[0]]: e[1].default })),
  4265. ...Object.entries(inputs).map(e => ({ [e[0]]: e[1].default })),
  4266. ].reduce((acc, obj) => ({ ...acc, ...obj }), {}),
  4267. name: GM_info.script.name,
  4268. get: function (key, def) {
  4269. if (key in this.values) {
  4270. return this.values[key];
  4271. }
  4272. return def;
  4273. },
  4274. set: function (key, value) {
  4275. this.values[key] = value;
  4276. db.set(this.userId, this.values).catch(
  4277. e => null
  4278. );
  4279. localStorage[this.name + ':' + key] = value;
  4280. },
  4281. delete: function (key) {
  4282. delete this.values[key];
  4283. db.set(this.userId, this.values);
  4284. delete localStorage[this.name + ':' + key];
  4285. }
  4286. }
  4287.  
  4288. /**
  4289. * Returns all keys from localStorage that start with prefix (for migration)
  4290. *
  4291. * Возвращает все ключи из localStorage которые начинаются с prefix (для миграции)
  4292. */
  4293. function getAllValuesStartingWith(prefix) {
  4294. const values = [];
  4295. for (let i = 0; i < localStorage.length; i++) {
  4296. const key = localStorage.key(i);
  4297. if (key.startsWith(prefix)) {
  4298. const val = localStorage.getItem(key);
  4299. const keyValue = key.split(':')[1];
  4300. values.push({ key: keyValue, val });
  4301. }
  4302. }
  4303. return values;
  4304. }
  4305.  
  4306. /**
  4307. * Opens or migrates to a database
  4308. *
  4309. * Открывает или мигрирует в базу данных
  4310. */
  4311. async function openOrMigrateDatabase(userId) {
  4312. storage.userId = userId;
  4313. try {
  4314. await db.open();
  4315. } catch(e) {
  4316. return;
  4317. }
  4318. let settings = await db.get(userId, false);
  4319.  
  4320. if (settings) {
  4321. storage.values = settings;
  4322. return;
  4323. }
  4324.  
  4325. const values = getAllValuesStartingWith(GM_info.script.name);
  4326. for (const value of values) {
  4327. let val = null;
  4328. try {
  4329. val = JSON.parse(value.val);
  4330. } catch {
  4331. break;
  4332. }
  4333. storage.values[value.key] = val;
  4334. }
  4335. await db.set(userId, storage.values);
  4336. }
  4337.  
  4338. class ZingerYWebsiteAPI {
  4339. /**
  4340. * Class for interaction with the API of the zingery.ru website
  4341. * Intended only for use with the HeroWarsHelper script:
  4342. * https://greasyfork.org/ru/scripts/450693-herowarshelper
  4343. * Copyright ZingerY
  4344. */
  4345. url = 'https://zingery.ru/heroes/';
  4346. // YWJzb2x1dGVseSB1c2VsZXNzIGxpbmU=
  4347. constructor(urn, env, data = {}) {
  4348. this.urn = urn;
  4349. this.fd = {
  4350. now: Date.now(),
  4351. fp: this.constructor.toString().replaceAll(/\s/g, ''),
  4352. env: env.callee.toString().replaceAll(/\s/g, ''),
  4353. info: (({ name, version, author }) => [name, version, author])(GM_info.script),
  4354. ...data,
  4355. };
  4356. }
  4357.  
  4358. sign() {
  4359. return md5([...this.fd.info, ~(this.fd.now % 1e3), this.fd.fp].join('_'));
  4360. }
  4361.  
  4362. encode(data) {
  4363. return btoa(encodeURIComponent(JSON.stringify(data)));
  4364. }
  4365.  
  4366. decode(data) {
  4367. return JSON.parse(decodeURIComponent(atob(data)));
  4368. }
  4369.  
  4370. headers() {
  4371. return {
  4372. 'X-Request-Signature': this.sign(),
  4373. 'X-Script-Name': GM_info.script.name,
  4374. 'X-Script-Version': GM_info.script.version,
  4375. 'X-Script-Author': GM_info.script.author,
  4376. 'X-Script-ZingerY': 42,
  4377. };
  4378. }
  4379.  
  4380. async request() {
  4381. try {
  4382. const response = await fetch(this.url + this.urn, {
  4383. method: 'POST',
  4384. headers: this.headers(),
  4385. body: this.encode(this.fd),
  4386. });
  4387. const text = await response.text();
  4388. return this.decode(text);
  4389. } catch (e) {
  4390. console.error(e);
  4391. return [];
  4392. }
  4393. }
  4394. /**
  4395. * Класс для взаимодействия с API сайта zingery.ru
  4396. * Предназначен только для использования со скриптом HeroWarsHelper:
  4397. * https://greasyfork.org/ru/scripts/450693-herowarshelper
  4398. * Copyright ZingerY
  4399. */
  4400. }
  4401.  
  4402. /**
  4403. * Sending expeditions
  4404. *
  4405. * Отправка экспедиций
  4406. */
  4407. function checkExpedition() {
  4408. return new Promise((resolve, reject) => {
  4409. const expedition = new Expedition(resolve, reject);
  4410. expedition.start();
  4411. });
  4412. }
  4413.  
  4414. class Expedition {
  4415. checkExpedInfo = {
  4416. calls: [
  4417. {
  4418. name: 'expeditionGet',
  4419. args: {},
  4420. ident: 'expeditionGet',
  4421. },
  4422. {
  4423. name: 'heroGetAll',
  4424. args: {},
  4425. ident: 'heroGetAll',
  4426. },
  4427. ],
  4428. };
  4429.  
  4430. constructor(resolve, reject) {
  4431. this.resolve = resolve;
  4432. this.reject = reject;
  4433. }
  4434.  
  4435. async start() {
  4436. const data = await Send(JSON.stringify(this.checkExpedInfo));
  4437.  
  4438. const expedInfo = data.results[0].result.response;
  4439. const dataHeroes = data.results[1].result.response;
  4440. const dataExped = { useHeroes: [], exped: [] };
  4441. const calls = [];
  4442.  
  4443. /**
  4444. * Adding expeditions to collect
  4445. * Добавляем экспедиции для сбора
  4446. */
  4447. let countGet = 0;
  4448. for (var n in expedInfo) {
  4449. const exped = expedInfo[n];
  4450. const dateNow = Date.now() / 1000;
  4451. if (exped.status == 2 && exped.endTime != 0 && dateNow > exped.endTime) {
  4452. countGet++;
  4453. calls.push({
  4454. name: 'expeditionFarm',
  4455. args: { expeditionId: exped.id },
  4456. ident: 'expeditionFarm_' + exped.id,
  4457. });
  4458. } else {
  4459. dataExped.useHeroes = dataExped.useHeroes.concat(exped.heroes);
  4460. }
  4461. if (exped.status == 1) {
  4462. dataExped.exped.push({ id: exped.id, power: exped.power });
  4463. }
  4464. }
  4465. dataExped.exped = dataExped.exped.sort((a, b) => b.power - a.power);
  4466.  
  4467. /**
  4468. * Putting together a list of heroes
  4469. * Собираем список героев
  4470. */
  4471. const heroesArr = [];
  4472. for (let n in dataHeroes) {
  4473. const hero = dataHeroes[n];
  4474. if (hero.xp > 0 && !dataExped.useHeroes.includes(hero.id)) {
  4475. let heroPower = hero.power;
  4476. // Лара Крофт * 3
  4477. if (hero.id == 63 && hero.color >= 16) {
  4478. heroPower *= 3;
  4479. }
  4480. heroesArr.push({ id: hero.id, power: heroPower });
  4481. }
  4482. }
  4483.  
  4484. /**
  4485. * Adding expeditions to send
  4486. * Добавляем экспедиции для отправки
  4487. */
  4488. let countSend = 0;
  4489. heroesArr.sort((a, b) => a.power - b.power);
  4490. for (const exped of dataExped.exped) {
  4491. let heroesIds = this.selectionHeroes(heroesArr, exped.power);
  4492. if (heroesIds && heroesIds.length > 4) {
  4493. for (let q in heroesArr) {
  4494. if (heroesIds.includes(heroesArr[q].id)) {
  4495. delete heroesArr[q];
  4496. }
  4497. }
  4498. countSend++;
  4499. calls.push({
  4500. name: 'expeditionSendHeroes',
  4501. args: {
  4502. expeditionId: exped.id,
  4503. heroes: heroesIds,
  4504. },
  4505. ident: 'expeditionSendHeroes_' + exped.id,
  4506. });
  4507. }
  4508. }
  4509.  
  4510. if (calls.length) {
  4511. await Send({ calls });
  4512. this.end(I18N('EXPEDITIONS_SENT', {countGet, countSend}));
  4513. return;
  4514. }
  4515.  
  4516. this.end(I18N('EXPEDITIONS_NOTHING'));
  4517. }
  4518.  
  4519. /**
  4520. * Selection of heroes for expeditions
  4521. *
  4522. * Подбор героев для экспедиций
  4523. */
  4524. selectionHeroes(heroes, power) {
  4525. const resultHeroers = [];
  4526. const heroesIds = [];
  4527. for (let q = 0; q < 5; q++) {
  4528. for (let i in heroes) {
  4529. let hero = heroes[i];
  4530. if (heroesIds.includes(hero.id)) {
  4531. continue;
  4532. }
  4533.  
  4534. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  4535. const need = Math.round((power - summ) / (5 - resultHeroers.length));
  4536. if (hero.power > need) {
  4537. resultHeroers.push(hero);
  4538. heroesIds.push(hero.id);
  4539. break;
  4540. }
  4541. }
  4542. }
  4543.  
  4544. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  4545. if (summ < power) {
  4546. return false;
  4547. }
  4548. return heroesIds;
  4549. }
  4550.  
  4551. /**
  4552. * Ends expedition script
  4553. *
  4554. * Завершает скрипт экспедиции
  4555. */
  4556. end(msg) {
  4557. setProgress(msg, true);
  4558. this.resolve();
  4559. }
  4560. }
  4561.  
  4562. /**
  4563. * Walkthrough of the dungeon
  4564. *
  4565. * Прохождение подземелья
  4566. */
  4567. function testDungeon() {
  4568. return new Promise((resolve, reject) => {
  4569. const dung = new executeDungeon(resolve, reject);
  4570. const titanit = getInput('countTitanit');
  4571. dung.start(titanit);
  4572. });
  4573. }
  4574.  
  4575. /**
  4576. * Walkthrough of the dungeon
  4577. *
  4578. * Прохождение подземелья
  4579. */
  4580. function executeDungeon(resolve, reject) {
  4581. dungeonActivity = 0;
  4582. maxDungeonActivity = 150;
  4583.  
  4584. titanGetAll = [];
  4585.  
  4586. teams = {
  4587. heroes: [],
  4588. earth: [],
  4589. fire: [],
  4590. neutral: [],
  4591. water: [],
  4592. }
  4593.  
  4594. titanStats = [];
  4595.  
  4596. titansStates = {};
  4597.  
  4598. callsExecuteDungeon = {
  4599. calls: [{
  4600. name: "dungeonGetInfo",
  4601. args: {},
  4602. ident: "dungeonGetInfo"
  4603. }, {
  4604. name: "teamGetAll",
  4605. args: {},
  4606. ident: "teamGetAll"
  4607. }, {
  4608. name: "teamGetFavor",
  4609. args: {},
  4610. ident: "teamGetFavor"
  4611. }, {
  4612. name: "clanGetInfo",
  4613. args: {},
  4614. ident: "clanGetInfo"
  4615. }, {
  4616. name: "titanGetAll",
  4617. args: {},
  4618. ident: "titanGetAll"
  4619. }, {
  4620. name: "inventoryGet",
  4621. args: {},
  4622. ident: "inventoryGet"
  4623. }]
  4624. }
  4625.  
  4626. this.start = function(titanit) {
  4627. maxDungeonActivity = titanit || getInput('countTitanit');
  4628. send(JSON.stringify(callsExecuteDungeon), startDungeon);
  4629. }
  4630.  
  4631. /**
  4632. * Getting data on the dungeon
  4633. *
  4634. * Получаем данные по подземелью
  4635. */
  4636. function startDungeon(e) {
  4637. res = e.results;
  4638. dungeonGetInfo = res[0].result.response;
  4639. if (!dungeonGetInfo) {
  4640. endDungeon('noDungeon', res);
  4641. return;
  4642. }
  4643. teamGetAll = res[1].result.response;
  4644. teamGetFavor = res[2].result.response;
  4645. dungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  4646. titanGetAll = Object.values(res[4].result.response);
  4647. countPredictionCard = res[5].result.response.consumable[81];
  4648.  
  4649. teams.hero = {
  4650. favor: teamGetFavor.dungeon_hero,
  4651. heroes: teamGetAll.dungeon_hero.filter(id => id < 6000),
  4652. teamNum: 0,
  4653. }
  4654. heroPet = teamGetAll.dungeon_hero.filter(id => id >= 6000).pop();
  4655. if (heroPet) {
  4656. teams.hero.pet = heroPet;
  4657. }
  4658.  
  4659. teams.neutral = {
  4660. favor: {},
  4661. heroes: getTitanTeam(titanGetAll, 'neutral'),
  4662. teamNum: 0,
  4663. };
  4664. teams.water = {
  4665. favor: {},
  4666. heroes: getTitanTeam(titanGetAll, 'water'),
  4667. teamNum: 0,
  4668. };
  4669. teams.fire = {
  4670. favor: {},
  4671. heroes: getTitanTeam(titanGetAll, 'fire'),
  4672. teamNum: 0,
  4673. };
  4674. teams.earth = {
  4675. favor: {},
  4676. heroes: getTitanTeam(titanGetAll, 'earth'),
  4677. teamNum: 0,
  4678. };
  4679.  
  4680.  
  4681. checkFloor(dungeonGetInfo);
  4682. }
  4683.  
  4684. function getTitanTeam(titans, type) {
  4685. switch (type) {
  4686. case 'neutral':
  4687. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4688. case 'water':
  4689. return titans.filter(e => e.id.toString().slice(2, 3) == '0').map(e => e.id);
  4690. case 'fire':
  4691. return titans.filter(e => e.id.toString().slice(2, 3) == '1').map(e => e.id);
  4692. case 'earth':
  4693. return titans.filter(e => e.id.toString().slice(2, 3) == '2').map(e => e.id);
  4694. }
  4695. }
  4696.  
  4697. function getNeutralTeam() {
  4698. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  4699. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4700. }
  4701.  
  4702. function fixTitanTeam(titans) {
  4703. titans.heroes = titans.heroes.filter(e => !titansStates[e]?.isDead);
  4704. return titans;
  4705. }
  4706.  
  4707. /**
  4708. * Checking the floor
  4709. *
  4710. * Проверяем этаж
  4711. */
  4712. async function checkFloor(dungeonInfo) {
  4713. if (!('floor' in dungeonInfo) || dungeonInfo.floor?.state == 2) {
  4714. saveProgress();
  4715. return;
  4716. }
  4717. // console.log(dungeonInfo, dungeonActivity);
  4718. setProgress(`${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  4719. if (dungeonActivity >= maxDungeonActivity) {
  4720. endDungeon('endDungeon', 'maxActive ' + dungeonActivity + '/' + maxDungeonActivity);
  4721. return;
  4722. }
  4723. titansStates = dungeonInfo.states.titans;
  4724. titanStats = titanObjToArray(titansStates);
  4725. const floorChoices = dungeonInfo.floor.userData;
  4726. const floorType = dungeonInfo.floorType;
  4727. //const primeElement = dungeonInfo.elements.prime;
  4728. if (floorType == "battle") {
  4729. const calls = [];
  4730. for (let teamNum in floorChoices) {
  4731. attackerType = floorChoices[teamNum].attackerType;
  4732. const args = fixTitanTeam(teams[attackerType]);
  4733. if (attackerType == 'neutral') {
  4734. args.heroes = getNeutralTeam();
  4735. }
  4736. if (!args.heroes.length) {
  4737. continue;
  4738. }
  4739. args.teamNum = teamNum;
  4740. calls.push({
  4741. name: "dungeonStartBattle",
  4742. args,
  4743. ident: "body_" + teamNum
  4744. })
  4745. }
  4746. if (!calls.length) {
  4747. endDungeon('endDungeon', 'All Dead');
  4748. return;
  4749. }
  4750. const battleDatas = await Send(JSON.stringify({ calls }))
  4751. .then(e => e.results.map(n => n.result.response))
  4752. const battleResults = [];
  4753. for (n in battleDatas) {
  4754. battleData = battleDatas[n]
  4755. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  4756. battleResults.push(await Calc(battleData).then(result => {
  4757. result.teamNum = n;
  4758. result.attackerType = floorChoices[n].attackerType;
  4759. return result;
  4760. }));
  4761. }
  4762. processingPromises(battleResults)
  4763. }
  4764. }
  4765.  
  4766. function processingPromises(results) {
  4767. let selectBattle = results[0];
  4768. if (results.length < 2) {
  4769. // console.log(selectBattle);
  4770. if (!selectBattle.result.win) {
  4771. endDungeon('dungeonEndBattle\n', selectBattle);
  4772. return;
  4773. }
  4774. endBattle(selectBattle);
  4775. return;
  4776. }
  4777.  
  4778. selectBattle = false;
  4779. let bestState = -1000;
  4780. for (const result of results) {
  4781. const recovery = getState(result);
  4782. if (recovery > bestState) {
  4783. bestState = recovery;
  4784. selectBattle = result
  4785. }
  4786. }
  4787. // console.log(selectBattle.teamNum, results);
  4788. if (!selectBattle || bestState <= -1000) {
  4789. endDungeon('dungeonEndBattle\n', results);
  4790. return;
  4791. }
  4792.  
  4793. startBattle(selectBattle.teamNum, selectBattle.attackerType)
  4794. .then(endBattle);
  4795. }
  4796.  
  4797. /**
  4798. * Let's start the fight
  4799. *
  4800. * Начинаем бой
  4801. */
  4802. function startBattle(teamNum, attackerType) {
  4803. return new Promise(function (resolve, reject) {
  4804. args = fixTitanTeam(teams[attackerType]);
  4805. args.teamNum = teamNum;
  4806. if (attackerType == 'neutral') {
  4807. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  4808. args.heroes = titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4809. }
  4810. startBattleCall = {
  4811. calls: [{
  4812. name: "dungeonStartBattle",
  4813. args,
  4814. ident: "body"
  4815. }]
  4816. }
  4817. send(JSON.stringify(startBattleCall), resultBattle, {
  4818. resolve,
  4819. teamNum,
  4820. attackerType
  4821. });
  4822. });
  4823. }
  4824. /**
  4825. * Returns the result of the battle in a promise
  4826. *
  4827. * Возращает резульат боя в промис
  4828. */
  4829. function resultBattle(resultBattles, args) {
  4830. battleData = resultBattles.results[0].result.response;
  4831. battleType = "get_tower";
  4832. if (battleData.type == "dungeon_titan") {
  4833. battleType = "get_titan";
  4834. }
  4835. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  4836. BattleCalc(battleData, battleType, function (result) {
  4837. result.teamNum = args.teamNum;
  4838. result.attackerType = args.attackerType;
  4839. args.resolve(result);
  4840. });
  4841. }
  4842. /**
  4843. * Finishing the fight
  4844. *
  4845. * Заканчиваем бой
  4846. */
  4847. async function endBattle(battleInfo) {
  4848. if (battleInfo.result.win) {
  4849. const args = {
  4850. result: battleInfo.result,
  4851. progress: battleInfo.progress,
  4852. }
  4853. if (countPredictionCard > 0) {
  4854. args.isRaid = true;
  4855. } else {
  4856. const timer = getTimer(battleInfo.battleTime);
  4857. console.log(timer);
  4858. await countdownTimer(timer, `${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  4859. }
  4860. const calls = [{
  4861. name: "dungeonEndBattle",
  4862. args,
  4863. ident: "body"
  4864. }];
  4865. lastDungeonBattleData = null;
  4866. send(JSON.stringify({ calls }), resultEndBattle);
  4867. } else {
  4868. endDungeon('dungeonEndBattle win: false\n', battleInfo);
  4869. }
  4870. }
  4871.  
  4872. /**
  4873. * Getting and processing battle results
  4874. *
  4875. * Получаем и обрабатываем результаты боя
  4876. */
  4877. function resultEndBattle(e) {
  4878. if ('error' in e) {
  4879. popup.confirm(I18N('ERROR_MSG', {
  4880. name: e.error.name,
  4881. description: e.error.description,
  4882. }));
  4883. endDungeon('errorRequest', e);
  4884. return;
  4885. }
  4886. battleResult = e.results[0].result.response;
  4887. if ('error' in battleResult) {
  4888. endDungeon('errorBattleResult', battleResult);
  4889. return;
  4890. }
  4891. dungeonGetInfo = battleResult.dungeon ?? battleResult;
  4892. dungeonActivity += battleResult.reward.dungeonActivity ?? 0;
  4893. checkFloor(dungeonGetInfo);
  4894. }
  4895.  
  4896. /**
  4897. * Returns the coefficient of condition of the
  4898. * difference in titanium before and after the battle
  4899. *
  4900. * Возвращает коэффициент состояния титанов после боя
  4901. */
  4902. function getState(result) {
  4903. if (!result.result.win) {
  4904. return -1000;
  4905. }
  4906.  
  4907. let beforeSumFactor = 0;
  4908. const beforeTitans = result.battleData.attackers;
  4909. for (let titanId in beforeTitans) {
  4910. const titan = beforeTitans[titanId];
  4911. const state = titan.state;
  4912. let factor = 1;
  4913. if (state) {
  4914. const hp = state.hp / titan.hp;
  4915. const energy = state.energy / 1e3;
  4916. factor = hp + energy / 20
  4917. }
  4918. beforeSumFactor += factor;
  4919. }
  4920.  
  4921. let afterSumFactor = 0;
  4922. const afterTitans = result.progress[0].attackers.heroes;
  4923. for (let titanId in afterTitans) {
  4924. const titan = afterTitans[titanId];
  4925. const hp = titan.hp / beforeTitans[titanId].hp;
  4926. const energy = titan.energy / 1e3;
  4927. const factor = hp + energy / 20;
  4928. afterSumFactor += factor;
  4929. }
  4930. return afterSumFactor - beforeSumFactor;
  4931. }
  4932.  
  4933. /**
  4934. * Converts an object with IDs to an array with IDs
  4935. *
  4936. * Преобразует объект с идетификаторами в массив с идетификаторами
  4937. */
  4938. function titanObjToArray(obj) {
  4939. let titans = [];
  4940. for (let id in obj) {
  4941. obj[id].id = id;
  4942. titans.push(obj[id]);
  4943. }
  4944. return titans;
  4945. }
  4946.  
  4947. function saveProgress() {
  4948. let saveProgressCall = {
  4949. calls: [{
  4950. name: "dungeonSaveProgress",
  4951. args: {},
  4952. ident: "body"
  4953. }]
  4954. }
  4955. send(JSON.stringify(saveProgressCall), resultEndBattle);
  4956. }
  4957.  
  4958. function endDungeon(reason, info) {
  4959. console.warn(reason, info);
  4960. setProgress(`${I18N('DUNGEON')} ${I18N('COMPLETED')}`, true);
  4961. resolve();
  4962. }
  4963. }
  4964.  
  4965. /**
  4966. * Passing the tower
  4967. *
  4968. * Прохождение башни
  4969. */
  4970. function testTower() {
  4971. return new Promise((resolve, reject) => {
  4972. tower = new executeTower(resolve, reject);
  4973. tower.start();
  4974. });
  4975. }
  4976.  
  4977. /**
  4978. * Passing the tower
  4979. *
  4980. * Прохождение башни
  4981. */
  4982. function executeTower(resolve, reject) {
  4983. lastTowerInfo = {};
  4984.  
  4985. scullCoin = 0;
  4986.  
  4987. heroGetAll = [];
  4988.  
  4989. heroesStates = {};
  4990.  
  4991. argsBattle = {
  4992. heroes: [],
  4993. favor: {},
  4994. };
  4995.  
  4996. callsExecuteTower = {
  4997. calls: [{
  4998. name: "towerGetInfo",
  4999. args: {},
  5000. ident: "towerGetInfo"
  5001. }, {
  5002. name: "teamGetAll",
  5003. args: {},
  5004. ident: "teamGetAll"
  5005. }, {
  5006. name: "teamGetFavor",
  5007. args: {},
  5008. ident: "teamGetFavor"
  5009. }, {
  5010. name: "inventoryGet",
  5011. args: {},
  5012. ident: "inventoryGet"
  5013. }, {
  5014. name: "heroGetAll",
  5015. args: {},
  5016. ident: "heroGetAll"
  5017. }]
  5018. }
  5019.  
  5020. buffIds = [
  5021. {id: 0, cost: 0, isBuy: false}, // plug // заглушка
  5022. {id: 1, cost: 1, isBuy: true}, // 3% attack // 3% атака
  5023. {id: 2, cost: 6, isBuy: true}, // 2% attack // 2% атака
  5024. {id: 3, cost: 16, isBuy: true}, // 4% attack // 4% атака
  5025. {id: 4, cost: 40, isBuy: true}, // 8% attack // 8% атака
  5026. {id: 5, cost: 1, isBuy: true}, // 10% armor // 10% броня
  5027. {id: 6, cost: 6, isBuy: true}, // 5% armor // 5% броня
  5028. {id: 7, cost: 16, isBuy: true}, // 10% armor // 10% броня
  5029. {id: 8, cost: 40, isBuy: true}, // 20% armor // 20% броня
  5030. { id: 9, cost: 1, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5031. { id: 10, cost: 6, isBuy: true }, // 5% protection from magic // 5% защита от магии
  5032. { id: 11, cost: 16, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5033. { id: 12, cost: 40, isBuy: true }, // 20% protection from magic // 20% защита от магии
  5034. { id: 13, cost: 1, isBuy: false }, // 40% health hero // 40% здоровья герою
  5035. { id: 14, cost: 6, isBuy: false }, // 40% health hero // 40% здоровья герою
  5036. { id: 15, cost: 16, isBuy: false }, // 80% health hero // 80% здоровья герою
  5037. { id: 16, cost: 40, isBuy: false }, // 40% health to all heroes // 40% здоровья всем героям
  5038. { id: 17, cost: 1, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5039. { id: 18, cost: 3, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5040. { id: 19, cost: 8, isBuy: false }, // 80% energy to the hero // 80% энергии герою
  5041. { id: 20, cost: 20, isBuy: false }, // 40% energy to all heroes // 40% энергии всем героям
  5042. { id: 21, cost: 40, isBuy: false }, // Hero Resurrection // Воскрешение героя
  5043. ]
  5044.  
  5045. this.start = function () {
  5046. send(JSON.stringify(callsExecuteTower), startTower);
  5047. }
  5048.  
  5049. /**
  5050. * Getting data on the Tower
  5051. *
  5052. * Получаем данные по башне
  5053. */
  5054. function startTower(e) {
  5055. res = e.results;
  5056. towerGetInfo = res[0].result.response;
  5057. if (!towerGetInfo) {
  5058. endTower('noTower', res);
  5059. return;
  5060. }
  5061. teamGetAll = res[1].result.response;
  5062. teamGetFavor = res[2].result.response;
  5063. inventoryGet = res[3].result.response;
  5064. heroGetAll = Object.values(res[4].result.response);
  5065.  
  5066. scullCoin = inventoryGet.coin[7] ?? 0;
  5067.  
  5068. argsBattle.favor = teamGetFavor.tower;
  5069. argsBattle.heroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5070. pet = teamGetAll.tower.filter(id => id >= 6000).pop();
  5071. if (pet) {
  5072. argsBattle.pet = pet;
  5073. }
  5074.  
  5075. checkFloor(towerGetInfo);
  5076. }
  5077.  
  5078. function fixHeroesTeam(argsBattle) {
  5079. let fixHeroes = argsBattle.heroes.filter(e => !heroesStates[e]?.isDead);
  5080. if (fixHeroes.length < 5) {
  5081. heroGetAll = heroGetAll.filter(e => !heroesStates[e.id]?.isDead);
  5082. fixHeroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5083. Object.keys(argsBattle.favor).forEach(e => {
  5084. if (!fixHeroes.includes(+e)) {
  5085. delete argsBattle.favor[e];
  5086. }
  5087. })
  5088. }
  5089. argsBattle.heroes = fixHeroes;
  5090. return argsBattle;
  5091. }
  5092.  
  5093. /**
  5094. * Check the floor
  5095. *
  5096. * Проверяем этаж
  5097. */
  5098. function checkFloor(towerInfo) {
  5099. lastTowerInfo = towerInfo;
  5100. maySkipFloor = +towerInfo.maySkipFloor;
  5101. floorNumber = +towerInfo.floorNumber;
  5102. heroesStates = towerInfo.states.heroes;
  5103. floorInfo = towerInfo.floor;
  5104.  
  5105. /**
  5106. * Is there at least one chest open on the floor
  5107. * Открыт ли на этаже хоть один сундук
  5108. */
  5109. isOpenChest = false;
  5110. if (towerInfo.floorType == "chest") {
  5111. isOpenChest = towerInfo.floor.chests.reduce((n, e) => n + e.opened, 0);
  5112. }
  5113.  
  5114. setProgress(`${I18N('TOWER')}: ${I18N('FLOOR')} ${floorNumber}`);
  5115. if (floorNumber > 49) {
  5116. if (isOpenChest) {
  5117. endTower('alreadyOpenChest 50 floor', floorNumber);
  5118. return;
  5119. }
  5120. }
  5121. /**
  5122. * If the chest is open and you can skip floors, then move on
  5123. * Если сундук открыт и можно скипать этажи, то переходим дальше
  5124. */
  5125. if (towerInfo.mayFullSkip && +towerInfo.teamLevel == 130) {
  5126. if (isOpenChest) {
  5127. nextOpenChest(floorNumber);
  5128. } else {
  5129. nextChestOpen(floorNumber);
  5130. }
  5131. return;
  5132. }
  5133.  
  5134. // console.log(towerInfo, scullCoin);
  5135. switch (towerInfo.floorType) {
  5136. case "battle":
  5137. if (floorNumber <= maySkipFloor) {
  5138. skipFloor();
  5139. return;
  5140. }
  5141. if (floorInfo.state == 2) {
  5142. nextFloor();
  5143. return;
  5144. }
  5145. startBattle().then(endBattle);
  5146. return;
  5147. case "buff":
  5148. checkBuff(towerInfo);
  5149. return;
  5150. case "chest":
  5151. openChest(floorNumber);
  5152. return;
  5153. default:
  5154. console.log('!', towerInfo.floorType, towerInfo);
  5155. break;
  5156. }
  5157. }
  5158.  
  5159. /**
  5160. * Let's start the fight
  5161. *
  5162. * Начинаем бой
  5163. */
  5164. function startBattle() {
  5165. return new Promise(function (resolve, reject) {
  5166. towerStartBattle = {
  5167. calls: [{
  5168. name: "towerStartBattle",
  5169. args: fixHeroesTeam(argsBattle),
  5170. ident: "body"
  5171. }]
  5172. }
  5173. send(JSON.stringify(towerStartBattle), resultBattle, resolve);
  5174. });
  5175. }
  5176. /**
  5177. * Returns the result of the battle in a promise
  5178. *
  5179. * Возращает резульат боя в промис
  5180. */
  5181. function resultBattle(resultBattles, resolve) {
  5182. battleData = resultBattles.results[0].result.response;
  5183. battleType = "get_tower";
  5184. BattleCalc(battleData, battleType, function (result) {
  5185. resolve(result);
  5186. });
  5187. }
  5188. /**
  5189. * Finishing the fight
  5190. *
  5191. * Заканчиваем бой
  5192. */
  5193. function endBattle(battleInfo) {
  5194. if (battleInfo.result.stars >= 3) {
  5195. endBattleCall = {
  5196. calls: [{
  5197. name: "towerEndBattle",
  5198. args: {
  5199. result: battleInfo.result,
  5200. progress: battleInfo.progress,
  5201. },
  5202. ident: "body"
  5203. }]
  5204. }
  5205. send(JSON.stringify(endBattleCall), resultEndBattle);
  5206. } else {
  5207. endTower('towerEndBattle win: false\n', battleInfo);
  5208. }
  5209. }
  5210.  
  5211. /**
  5212. * Getting and processing battle results
  5213. *
  5214. * Получаем и обрабатываем результаты боя
  5215. */
  5216. function resultEndBattle(e) {
  5217. battleResult = e.results[0].result.response;
  5218. if ('error' in battleResult) {
  5219. endTower('errorBattleResult', battleResult);
  5220. return;
  5221. }
  5222. if ('reward' in battleResult) {
  5223. scullCoin += battleResult.reward?.coin[7] ?? 0;
  5224. }
  5225. nextFloor();
  5226. }
  5227.  
  5228. function nextFloor() {
  5229. nextFloorCall = {
  5230. calls: [{
  5231. name: "towerNextFloor",
  5232. args: {},
  5233. ident: "body"
  5234. }]
  5235. }
  5236. send(JSON.stringify(nextFloorCall), checkDataFloor);
  5237. }
  5238.  
  5239. function openChest(floorNumber) {
  5240. floorNumber = floorNumber || 0;
  5241. openChestCall = {
  5242. calls: [{
  5243. name: "towerOpenChest",
  5244. args: {
  5245. num: 2
  5246. },
  5247. ident: "body"
  5248. }]
  5249. }
  5250. send(JSON.stringify(openChestCall), floorNumber < 50 ? nextFloor : lastChest);
  5251. }
  5252.  
  5253. function lastChest() {
  5254. endTower('openChest 50 floor', floorNumber);
  5255. }
  5256.  
  5257. function skipFloor() {
  5258. skipFloorCall = {
  5259. calls: [{
  5260. name: "towerSkipFloor",
  5261. args: {},
  5262. ident: "body"
  5263. }]
  5264. }
  5265. send(JSON.stringify(skipFloorCall), checkDataFloor);
  5266. }
  5267.  
  5268. function checkBuff(towerInfo) {
  5269. buffArr = towerInfo.floor;
  5270. promises = [];
  5271. for (let buff of buffArr) {
  5272. buffInfo = buffIds[buff.id];
  5273. if (buffInfo.isBuy && buffInfo.cost <= scullCoin) {
  5274. scullCoin -= buffInfo.cost;
  5275. promises.push(buyBuff(buff.id));
  5276. }
  5277. }
  5278. Promise.all(promises).then(nextFloor);
  5279. }
  5280.  
  5281. function buyBuff(buffId) {
  5282. return new Promise(function (resolve, reject) {
  5283. buyBuffCall = {
  5284. calls: [{
  5285. name: "towerBuyBuff",
  5286. args: {
  5287. buffId
  5288. },
  5289. ident: "body"
  5290. }]
  5291. }
  5292. send(JSON.stringify(buyBuffCall), resolve);
  5293. });
  5294. }
  5295.  
  5296. function checkDataFloor(result) {
  5297. towerInfo = result.results[0].result.response;
  5298. if ('reward' in towerInfo && towerInfo.reward?.coin) {
  5299. scullCoin += towerInfo.reward?.coin[7] ?? 0;
  5300. }
  5301. if ('tower' in towerInfo) {
  5302. towerInfo = towerInfo.tower;
  5303. }
  5304. if ('skullReward' in towerInfo) {
  5305. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  5306. }
  5307. checkFloor(towerInfo);
  5308. }
  5309. /**
  5310. * Getting tower rewards
  5311. *
  5312. * Получаем награды башни
  5313. */
  5314. function farmTowerRewards(reason) {
  5315. let { pointRewards, points } = lastTowerInfo;
  5316. let pointsAll = Object.getOwnPropertyNames(pointRewards);
  5317. let farmPoints = pointsAll.filter(e => +e <= +points && !pointRewards[e]);
  5318. if (!farmPoints.length) {
  5319. return;
  5320. }
  5321. let farmTowerRewardsCall = {
  5322. calls: [{
  5323. name: "tower_farmPointRewards",
  5324. args: {
  5325. points: farmPoints
  5326. },
  5327. ident: "tower_farmPointRewards"
  5328. }]
  5329. }
  5330.  
  5331. if (scullCoin > 0 && reason == 'openChest 50 floor') {
  5332. farmTowerRewardsCall.calls.push({
  5333. name: "tower_farmSkullReward",
  5334. args: {},
  5335. ident: "tower_farmSkullReward"
  5336. });
  5337. }
  5338.  
  5339. send(JSON.stringify(farmTowerRewardsCall), () => { });
  5340. }
  5341.  
  5342. function fullSkipTower() {
  5343. /**
  5344. * Next chest
  5345. *
  5346. * Следующий сундук
  5347. */
  5348. function nextChest(n) {
  5349. return {
  5350. name: "towerNextChest",
  5351. args: {},
  5352. ident: "group_" + n + "_body"
  5353. }
  5354. }
  5355. /**
  5356. * Open chest
  5357. *
  5358. * Открыть сундук
  5359. */
  5360. function openChest(n) {
  5361. return {
  5362. name: "towerOpenChest",
  5363. args: {
  5364. "num": 2
  5365. },
  5366. ident: "group_" + n + "_body"
  5367. }
  5368. }
  5369.  
  5370. const fullSkipTowerCall = {
  5371. calls: []
  5372. }
  5373.  
  5374. let n = 0;
  5375. for (let i = 0; i < 15; i++) {
  5376. fullSkipTowerCall.calls.push(nextChest(++n));
  5377. fullSkipTowerCall.calls.push(openChest(++n));
  5378. }
  5379.  
  5380. send(JSON.stringify(fullSkipTowerCall), data => {
  5381. data.results[0] = data.results[28];
  5382. checkDataFloor(data);
  5383. });
  5384. }
  5385.  
  5386. function nextChestOpen(floorNumber) {
  5387. const calls = [{
  5388. name: "towerOpenChest",
  5389. args: {
  5390. num: 2
  5391. },
  5392. ident: "towerOpenChest"
  5393. }];
  5394.  
  5395. Send(JSON.stringify({ calls })).then(e => {
  5396. nextOpenChest(floorNumber);
  5397. });
  5398. }
  5399.  
  5400. function nextOpenChest(floorNumber) {
  5401. if (floorNumber > 49) {
  5402. endTower('openChest 50 floor', floorNumber);
  5403. return;
  5404. }
  5405. if (floorNumber == 1) {
  5406. fullSkipTower();
  5407. return;
  5408. }
  5409.  
  5410. let nextOpenChestCall = {
  5411. calls: [{
  5412. name: "towerNextChest",
  5413. args: {},
  5414. ident: "towerNextChest"
  5415. }, {
  5416. name: "towerOpenChest",
  5417. args: {
  5418. num: 2
  5419. },
  5420. ident: "towerOpenChest"
  5421. }]
  5422. }
  5423. send(JSON.stringify(nextOpenChestCall), checkDataFloor);
  5424. }
  5425.  
  5426. function endTower(reason, info) {
  5427. console.log(reason, info);
  5428. if (reason != 'noTower') {
  5429. farmTowerRewards(reason);
  5430. }
  5431. setProgress(`${I18N('TOWER')} ${I18N('COMPLETED')}!`, true);
  5432. resolve();
  5433. }
  5434. }
  5435.  
  5436. /**
  5437. * Passage of the arena of the titans
  5438. *
  5439. * Прохождение арены титанов
  5440. */
  5441. function testTitanArena() {
  5442. return new Promise((resolve, reject) => {
  5443. titAren = new executeTitanArena(resolve, reject);
  5444. titAren.start();
  5445. });
  5446. }
  5447.  
  5448. /**
  5449. * Passage of the arena of the titans
  5450. *
  5451. * Прохождение арены титанов
  5452. */
  5453. function executeTitanArena(resolve, reject) {
  5454. let titan_arena = [];
  5455. let finishListBattle = [];
  5456. /**
  5457. * ID of the current batch
  5458. *
  5459. * Идетификатор текущей пачки
  5460. */
  5461. let currentRival = 0;
  5462. /**
  5463. * Number of attempts to finish off the pack
  5464. *
  5465. * Количество попыток добития пачки
  5466. */
  5467. let attempts = 0;
  5468. /**
  5469. * Was there an attempt to finish off the current shooting range
  5470. *
  5471. * Была ли попытка добития текущего тира
  5472. */
  5473. let isCheckCurrentTier = false;
  5474. /**
  5475. * Current shooting range
  5476. *
  5477. * Текущий тир
  5478. */
  5479. let currTier = 0;
  5480. /**
  5481. * Number of battles on the current dash
  5482. *
  5483. * Количество битв на текущем тире
  5484. */
  5485. let countRivalsTier = 0;
  5486.  
  5487. let callsStart = {
  5488. calls: [{
  5489. name: "titanArenaGetStatus",
  5490. args: {},
  5491. ident: "titanArenaGetStatus"
  5492. }, {
  5493. name: "teamGetAll",
  5494. args: {},
  5495. ident: "teamGetAll"
  5496. }]
  5497. }
  5498.  
  5499. this.start = function () {
  5500. send(JSON.stringify(callsStart), startTitanArena);
  5501. }
  5502.  
  5503. function startTitanArena(data) {
  5504. let titanArena = data.results[0].result.response;
  5505. if (titanArena.status == 'disabled') {
  5506. endTitanArena('disabled', titanArena);
  5507. return;
  5508. }
  5509.  
  5510. let teamGetAll = data.results[1].result.response;
  5511. titan_arena = teamGetAll.titan_arena;
  5512.  
  5513. checkTier(titanArena)
  5514. }
  5515.  
  5516. function checkTier(titanArena) {
  5517. if (titanArena.status == "peace_time") {
  5518. endTitanArena('Peace_time', titanArena);
  5519. return;
  5520. }
  5521. currTier = titanArena.tier;
  5522. if (currTier) {
  5523. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier}`);
  5524. }
  5525.  
  5526. if (titanArena.status == "completed_tier") {
  5527. titanArenaCompleteTier();
  5528. return;
  5529. }
  5530. /**
  5531. * Checking for the possibility of a raid
  5532. * Проверка на возможность рейда
  5533. */
  5534. if (titanArena.canRaid) {
  5535. titanArenaStartRaid();
  5536. return;
  5537. }
  5538. /**
  5539. * Check was an attempt to achieve the current shooting range
  5540. * Проверка была ли попытка добития текущего тира
  5541. */
  5542. if (!isCheckCurrentTier) {
  5543. checkRivals(titanArena.rivals);
  5544. return;
  5545. }
  5546.  
  5547. endTitanArena('Done or not canRaid', titanArena);
  5548. }
  5549. /**
  5550. * Submit dash information for verification
  5551. *
  5552. * Отправка информации о тире на проверку
  5553. */
  5554. function checkResultInfo(data) {
  5555. let titanArena = data.results[0].result.response;
  5556. checkTier(titanArena);
  5557. }
  5558. /**
  5559. * Finish the current tier
  5560. *
  5561. * Завершить текущий тир
  5562. */
  5563. function titanArenaCompleteTier() {
  5564. isCheckCurrentTier = false;
  5565. let calls = [{
  5566. name: "titanArenaCompleteTier",
  5567. args: {},
  5568. ident: "body"
  5569. }];
  5570. send(JSON.stringify({calls}), checkResultInfo);
  5571. }
  5572. /**
  5573. * Gathering points to be completed
  5574. *
  5575. * Собираем точки которые нужно добить
  5576. */
  5577. function checkRivals(rivals) {
  5578. finishListBattle = [];
  5579. for (let n in rivals) {
  5580. if (rivals[n].attackScore < 250) {
  5581. finishListBattle.push(n);
  5582. }
  5583. }
  5584. console.log('checkRivals', finishListBattle);
  5585. countRivalsTier = finishListBattle.length;
  5586. roundRivals();
  5587. }
  5588. /**
  5589. * Selecting the next point to finish off
  5590. *
  5591. * Выбор следующей точки для добития
  5592. */
  5593. function roundRivals() {
  5594. let countRivals = finishListBattle.length;
  5595. if (!countRivals) {
  5596. /**
  5597. * Whole range checked
  5598. *
  5599. * Весь тир проверен
  5600. */
  5601. isCheckCurrentTier = true;
  5602. titanArenaGetStatus();
  5603. return;
  5604. }
  5605. // setProgress('TitanArena: Уровень ' + currTier + ' Бои: ' + (countRivalsTier - countRivals + 1) + '/' + countRivalsTier);
  5606. currentRival = finishListBattle.pop();
  5607. attempts = +currentRival;
  5608. // console.log('roundRivals', currentRival);
  5609. titanArenaStartBattle(currentRival);
  5610. }
  5611. /**
  5612. * The start of a solo battle
  5613. *
  5614. * Начало одиночной битвы
  5615. */
  5616. function titanArenaStartBattle(rivalId) {
  5617. let calls = [{
  5618. name: "titanArenaStartBattle",
  5619. args: {
  5620. rivalId: rivalId,
  5621. titans: titan_arena
  5622. },
  5623. ident: "body"
  5624. }];
  5625. send(JSON.stringify({calls}), calcResult);
  5626. }
  5627. /**
  5628. * Calculation of the results of the battle
  5629. *
  5630. * Расчет результатов боя
  5631. */
  5632. function calcResult(data) {
  5633. let battlesInfo = data.results[0].result.response.battle;
  5634. /**
  5635. * If attempts are equal to the current battle number we make
  5636. * Если попытки равны номеру текущего боя делаем прерасчет
  5637. */
  5638. if (attempts == currentRival) {
  5639. preCalcBattle(battlesInfo);
  5640. return;
  5641. }
  5642. /**
  5643. * If there are still attempts, we calculate a new battle
  5644. * Если попытки еще есть делаем расчет нового боя
  5645. */
  5646. if (attempts > 0) {
  5647. attempts--;
  5648. calcBattleResult(battlesInfo)
  5649. .then(resultCalcBattle);
  5650. return;
  5651. }
  5652. /**
  5653. * Otherwise, go to the next opponent
  5654. * Иначе переходим к следующему сопернику
  5655. */
  5656. roundRivals();
  5657. }
  5658. /**
  5659. * Processing the results of the battle calculation
  5660. *
  5661. * Обработка результатов расчета битвы
  5662. */
  5663. function resultCalcBattle(resultBattle) {
  5664. // console.log('resultCalcBattle', currentRival, attempts, resultBattle.result.win);
  5665. /**
  5666. * If the current calculation of victory is not a chance or the attempt ended with the finish the battle
  5667. * Если текущий расчет победа или шансов нет или попытки кончились завершаем бой
  5668. */
  5669. if (resultBattle.result.win || !attempts) {
  5670. titanArenaEndBattle({
  5671. progress: resultBattle.progress,
  5672. result: resultBattle.result,
  5673. rivalId: resultBattle.battleData.typeId
  5674. });
  5675. return;
  5676. }
  5677. /**
  5678. * If not victory and there are attempts we start a new battle
  5679. * Если не победа и есть попытки начинаем новый бой
  5680. */
  5681. titanArenaStartBattle(resultBattle.battleData.typeId);
  5682. }
  5683. /**
  5684. * Returns the promise of calculating the results of the battle
  5685. *
  5686. * Возращает промис расчета результатов битвы
  5687. */
  5688. function getBattleInfo(battle, isRandSeed) {
  5689. return new Promise(function (resolve) {
  5690. if (isRandSeed) {
  5691. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  5692. }
  5693. // console.log(battle.seed);
  5694. BattleCalc(battle, "get_titanClanPvp", e => resolve(e));
  5695. });
  5696. }
  5697. /**
  5698. * Recalculate battles
  5699. *
  5700. * Прерасчтет битвы
  5701. */
  5702. function preCalcBattle(battle) {
  5703. let actions = [getBattleInfo(battle, false)];
  5704. const countTestBattle = getInput('countTestBattle');
  5705. for (let i = 0; i < countTestBattle; i++) {
  5706. actions.push(getBattleInfo(battle, true));
  5707. }
  5708. Promise.all(actions)
  5709. .then(resultPreCalcBattle);
  5710. }
  5711. /**
  5712. * Processing the results of the battle recalculation
  5713. *
  5714. * Обработка результатов прерасчета битвы
  5715. */
  5716. function resultPreCalcBattle(e) {
  5717. let wins = e.map(n => n.result.win);
  5718. let firstBattle = e.shift();
  5719. let countWin = wins.reduce((w, s) => w + s);
  5720. const countTestBattle = getInput('countTestBattle');
  5721. console.log('resultPreCalcBattle', `${countWin}/${countTestBattle}`)
  5722. if (countWin > 0) {
  5723. attempts = getInput('countAutoBattle');
  5724. } else {
  5725. attempts = 0;
  5726. }
  5727. resultCalcBattle(firstBattle);
  5728. }
  5729.  
  5730. /**
  5731. * Complete an arena battle
  5732. *
  5733. * Завершить битву на арене
  5734. */
  5735. function titanArenaEndBattle(args) {
  5736. let calls = [{
  5737. name: "titanArenaEndBattle",
  5738. args,
  5739. ident: "body"
  5740. }];
  5741. send(JSON.stringify({calls}), resultTitanArenaEndBattle);
  5742. }
  5743.  
  5744. function resultTitanArenaEndBattle(e) {
  5745. let attackScore = e.results[0].result.response.attackScore;
  5746. let numReval = countRivalsTier - finishListBattle.length;
  5747. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier} </br>${I18N('BATTLES')}: ${numReval}/${countRivalsTier} - ${attackScore}`);
  5748. /**
  5749. * TODO: Might need to improve the results.
  5750. * TODO: Возможно стоит сделать улучшение результатов
  5751. */
  5752. // console.log('resultTitanArenaEndBattle', e)
  5753. console.log('resultTitanArenaEndBattle', numReval + '/' + countRivalsTier, attempts)
  5754. roundRivals();
  5755. }
  5756. /**
  5757. * Arena State
  5758. *
  5759. * Состояние арены
  5760. */
  5761. function titanArenaGetStatus() {
  5762. let calls = [{
  5763. name: "titanArenaGetStatus",
  5764. args: {},
  5765. ident: "body"
  5766. }];
  5767. send(JSON.stringify({calls}), checkResultInfo);
  5768. }
  5769. /**
  5770. * Arena Raid Request
  5771. *
  5772. * Запрос рейда арены
  5773. */
  5774. function titanArenaStartRaid() {
  5775. let calls = [{
  5776. name: "titanArenaStartRaid",
  5777. args: {
  5778. titans: titan_arena
  5779. },
  5780. ident: "body"
  5781. }];
  5782. send(JSON.stringify({calls}), calcResults);
  5783. }
  5784.  
  5785. function calcResults(data) {
  5786. let battlesInfo = data.results[0].result.response;
  5787. let {attackers, rivals} = battlesInfo;
  5788.  
  5789. let promises = [];
  5790. for (let n in rivals) {
  5791. rival = rivals[n];
  5792. promises.push(calcBattleResult({
  5793. attackers: attackers,
  5794. defenders: [rival.team],
  5795. seed: rival.seed,
  5796. typeId: n,
  5797. }));
  5798. }
  5799.  
  5800. Promise.all(promises)
  5801. .then(results => {
  5802. const endResults = {};
  5803. for (let info of results) {
  5804. let id = info.battleData.typeId;
  5805. endResults[id] = {
  5806. progress: info.progress,
  5807. result: info.result,
  5808. }
  5809. }
  5810. titanArenaEndRaid(endResults);
  5811. });
  5812. }
  5813.  
  5814. function calcBattleResult(battleData) {
  5815. return new Promise(function (resolve, reject) {
  5816. BattleCalc(battleData, "get_titanClanPvp", resolve);
  5817. });
  5818. }
  5819.  
  5820. /**
  5821. * Sending Raid Results
  5822. *
  5823. * Отправка результатов рейда
  5824. */
  5825. function titanArenaEndRaid(results) {
  5826. titanArenaEndRaidCall = {
  5827. calls: [{
  5828. name: "titanArenaEndRaid",
  5829. args: {
  5830. results
  5831. },
  5832. ident: "body"
  5833. }]
  5834. }
  5835. send(JSON.stringify(titanArenaEndRaidCall), checkRaidResults);
  5836. }
  5837.  
  5838. function checkRaidResults(data) {
  5839. results = data.results[0].result.response.results;
  5840. isSucsesRaid = true;
  5841. for (let i in results) {
  5842. isSucsesRaid &&= (results[i].attackScore >= 250);
  5843. }
  5844.  
  5845. if (isSucsesRaid) {
  5846. titanArenaCompleteTier();
  5847. } else {
  5848. titanArenaGetStatus();
  5849. }
  5850. }
  5851.  
  5852. function titanArenaFarmDailyReward() {
  5853. titanArenaFarmDailyRewardCall = {
  5854. calls: [{
  5855. name: "titanArenaFarmDailyReward",
  5856. args: {},
  5857. ident: "body"
  5858. }]
  5859. }
  5860. send(JSON.stringify(titanArenaFarmDailyRewardCall), () => {console.log('Done farm daily reward')});
  5861. }
  5862.  
  5863. function endTitanArena(reason, info) {
  5864. if (!['Peace_time', 'disabled'].includes(reason)) {
  5865. titanArenaFarmDailyReward();
  5866. }
  5867. console.log(reason, info);
  5868. setProgress(`${I18N('TITAN_ARENA')} ${I18N('COMPLETED')}!`, true);
  5869. resolve();
  5870. }
  5871. }
  5872.  
  5873. function hackGame() {
  5874. self = this;
  5875. selfGame = null;
  5876. bindId = 1e9;
  5877. this.libGame = null;
  5878.  
  5879. /**
  5880. * List of correspondence of used classes to their names
  5881. *
  5882. * Список соответствия используемых классов их названиям
  5883. */
  5884. ObjectsList = [
  5885. { name: 'BattlePresets', prop: 'game.battle.controller.thread.BattlePresets' },
  5886. { name: 'DataStorage', prop: 'game.data.storage.DataStorage' },
  5887. { name: 'BattleConfigStorage', prop: 'game.data.storage.battle.BattleConfigStorage' },
  5888. { name: 'BattleInstantPlay', prop: 'game.battle.controller.instant.BattleInstantPlay' },
  5889. { name: 'MultiBattleInstantReplay', prop: 'game.battle.controller.instant.MultiBattleInstantReplay' },
  5890. { name: 'MultiBattleResult', prop: 'game.battle.controller.MultiBattleResult' },
  5891.  
  5892. { name: 'PlayerMissionData', prop: 'game.model.user.mission.PlayerMissionData' },
  5893. { name: 'PlayerMissionBattle', prop: 'game.model.user.mission.PlayerMissionBattle' },
  5894. { name: 'GameModel', prop: 'game.model.GameModel' },
  5895. { name: 'CommandManager', prop: 'game.command.CommandManager' },
  5896. { name: 'MissionCommandList', prop: 'game.command.rpc.mission.MissionCommandList' },
  5897. { name: 'RPCCommandBase', prop: 'game.command.rpc.RPCCommandBase' },
  5898. { name: 'PlayerTowerData', prop: 'game.model.user.tower.PlayerTowerData' },
  5899. { name: 'TowerCommandList', prop: 'game.command.tower.TowerCommandList' },
  5900. { name: 'PlayerHeroTeamResolver', prop: 'game.model.user.hero.PlayerHeroTeamResolver' },
  5901. { name: 'BattlePausePopup', prop: 'game.view.popup.battle.BattlePausePopup' },
  5902. { name: 'BattlePopup', prop: 'game.view.popup.battle.BattlePopup' },
  5903. { name: 'DisplayObjectContainer', prop: 'starling.display.DisplayObjectContainer' },
  5904. { name: 'GuiClipContainer', prop: 'engine.core.clipgui.GuiClipContainer' },
  5905. { name: 'BattlePausePopupClip', prop: 'game.view.popup.battle.BattlePausePopupClip' },
  5906. { name: 'ClipLabel', prop: 'game.view.gui.components.ClipLabel' },
  5907. { name: 'ClipLabelBase', prop: 'game.view.gui.components.ClipLabelBase' },
  5908. { name: 'Translate', prop: 'com.progrestar.common.lang.Translate' },
  5909. { name: 'ClipButtonLabeledCentered', prop: 'game.view.gui.components.ClipButtonLabeledCentered' },
  5910. { name: 'BattlePausePopupMediator', prop: 'game.mediator.gui.popup.battle.BattlePausePopupMediator' },
  5911. { name: 'SettingToggleButton', prop: 'game.mechanics.settings.popup.view.SettingToggleButton' },
  5912. { name: 'PlayerDungeonData', prop: 'game.mechanics.dungeon.model.PlayerDungeonData' },
  5913. { name: 'NextDayUpdatedManager', prop: 'game.model.user.NextDayUpdatedManager' },
  5914. { name: 'BattleController', prop: 'game.battle.controller.BattleController' },
  5915. { name: 'BattleSettingsModel', prop: 'game.battle.controller.BattleSettingsModel' },
  5916. { name: 'BooleanProperty', prop: 'engine.core.utils.property.BooleanProperty' },
  5917. { name: 'RuleStorage', prop: 'game.data.storage.rule.RuleStorage' },
  5918. { name: 'BattleConfig', prop: 'battle.BattleConfig' },
  5919. { name: 'BattleGuiMediator', prop: 'game.battle.gui.BattleGuiMediator' },
  5920. { name: 'BooleanPropertyWriteable', prop: 'engine.core.utils.property.BooleanPropertyWriteable' },
  5921. { name: 'BattleLogEncoder', prop: 'battle.log.BattleLogEncoder' },
  5922. { name: 'BattleLogReader', prop: 'battle.log.BattleLogReader' },
  5923. { name: 'PlayerSubscriptionInfoValueObject', prop: 'game.model.user.subscription.PlayerSubscriptionInfoValueObject' },
  5924. { name: 'AdventureMapCamera', prop: 'game.mechanics.adventure.popup.map.AdventureMapCamera' },
  5925. ];
  5926.  
  5927. /**
  5928. * Contains the game classes needed to write and override game methods
  5929. *
  5930. * Содержит классы игры необходимые для написания и подмены методов игры
  5931. */
  5932. Game = {
  5933. /**
  5934. * Function 'e'
  5935. * Функция 'e'
  5936. */
  5937. bindFunc: function (a, b) {
  5938. if (null == b)
  5939. return null;
  5940. null == b.__id__ && (b.__id__ = bindId++);
  5941. var c;
  5942. null == a.hx__closures__ ? a.hx__closures__ = {} :
  5943. c = a.hx__closures__[b.__id__];
  5944. null == c && (c = b.bind(a), a.hx__closures__[b.__id__] = c);
  5945. return c
  5946. },
  5947. };
  5948.  
  5949. /**
  5950. * Connects to game objects via the object creation event
  5951. *
  5952. * Подключается к объектам игры через событие создания объекта
  5953. */
  5954. function connectGame() {
  5955. for (let obj of ObjectsList) {
  5956. /**
  5957. * https: //stackoverflow.com/questions/42611719/how-to-intercept-and-modify-a-specific-property-for-any-object
  5958. */
  5959. Object.defineProperty(Object.prototype, obj.prop, {
  5960. set: function (value) {
  5961. if (!selfGame) {
  5962. selfGame = this;
  5963. }
  5964. if (!Game[obj.name]) {
  5965. Game[obj.name] = value;
  5966. }
  5967. // console.log('set ' + obj.prop, this, value);
  5968. this[obj.prop + '_'] = value;
  5969. },
  5970. get: function () {
  5971. // console.log('get ' + obj.prop, this);
  5972. return this[obj.prop + '_'];
  5973. }
  5974. });
  5975. }
  5976. }
  5977.  
  5978. /**
  5979. * Game.BattlePresets
  5980. * @param {bool} a isReplay
  5981. * @param {bool} b autoToggleable
  5982. * @param {bool} c auto On Start
  5983. * @param {object} d config
  5984. * @param {bool} f showBothTeams
  5985. */
  5986. /**
  5987. * Returns the results of the battle to the callback function
  5988. * Возвращает в функцию callback результаты боя
  5989. * @param {*} battleData battle data данные боя
  5990. * @param {*} battleConfig combat configuration type options:
  5991. *
  5992. * тип конфигурации боя варианты:
  5993. *
  5994. * "get_invasion", "get_titanPvpManual", "get_titanPvp",
  5995. * "get_titanClanPvp","get_clanPvp","get_titan","get_boss",
  5996. * "get_tower","get_pve","get_pvpManual","get_pvp","get_core"
  5997. *
  5998. * You can specify the xYc function in the game.assets.storage.BattleAssetStorage class
  5999. *
  6000. * Можно уточнить в классе game.assets.storage.BattleAssetStorage функция xYc
  6001. * @param {*} callback функция в которую вернуться результаты боя
  6002. */
  6003. this.BattleCalc = function (battleData, battleConfig, callback) {
  6004. // battleConfig = battleConfig || getBattleType(battleData.type)
  6005. if (!Game.BattlePresets) throw Error('Use connectGame');
  6006. battlePresets = new Game.BattlePresets(battleData.progress, !1, !0, Game.DataStorage[getFn(Game.DataStorage, 24)][getF(Game.BattleConfigStorage, battleConfig)](), !1);
  6007. let battleInstantPlay;
  6008. if (battleData.progress?.length > 1) {
  6009. battleInstantPlay = new Game.MultiBattleInstantReplay(battleData, battlePresets);
  6010. } else {
  6011. battleInstantPlay = new Game.BattleInstantPlay(battleData, battlePresets);
  6012. }
  6013. battleInstantPlay[getProtoFn(Game.BattleInstantPlay, 9)].add((battleInstant) => {
  6014. const MBR_2 = getProtoFn(Game.MultiBattleResult, 2);
  6015. const battleResults = battleInstant[getF(Game.BattleInstantPlay, 'get_result')]();
  6016. const battleData = battleInstant[getF(Game.BattleInstantPlay, 'get_rawBattleInfo')]();
  6017. const battleLogs = [];
  6018. const timeLimit = battlePresets[getF(Game.BattlePresets, 'get_timeLimit')]();
  6019. let battleTime = 0;
  6020. let battleTimer = 0;
  6021. for (const battleResult of battleResults[MBR_2]) {
  6022. const battleLog = Game.BattleLogEncoder.read(new Game.BattleLogReader(battleResult));
  6023. battleLogs.push(battleLog);
  6024. const maxTime = Math.max(...battleLog.map((e) => (e.time < timeLimit && e.time !== 168.8 ? e.time : 0)));
  6025. battleTimer += getTimer(maxTime)
  6026. battleTime += maxTime;
  6027. }
  6028. callback({
  6029. battleLogs,
  6030. battleTime,
  6031. battleTimer,
  6032. battleData,
  6033. progress: battleResults[getF(Game.MultiBattleResult, 'get_progress')](),
  6034. result: battleResults[getF(Game.MultiBattleResult, 'get_result')](),
  6035. });
  6036. });
  6037. battleInstantPlay.start();
  6038. }
  6039.  
  6040. /**
  6041. * Returns a function with the specified name from the class
  6042. *
  6043. * Возвращает из класса функцию с указанным именем
  6044. * @param {Object} classF Class // класс
  6045. * @param {String} nameF function name // имя функции
  6046. * @param {String} pos name and alias order // порядок имени и псевдонима
  6047. * @returns
  6048. */
  6049. function getF(classF, nameF, pos) {
  6050. pos = pos || false;
  6051. let prop = Object.entries(classF.prototype.__properties__)
  6052. if (!pos) {
  6053. return prop.filter((e) => e[1] == nameF).pop()[0];
  6054. } else {
  6055. return prop.filter((e) => e[0] == nameF).pop()[1];
  6056. }
  6057. }
  6058.  
  6059. /**
  6060. * Returns a function with the specified name from the class
  6061. *
  6062. * Возвращает из класса функцию с указанным именем
  6063. * @param {Object} classF Class // класс
  6064. * @param {String} nameF function name // имя функции
  6065. * @returns
  6066. */
  6067. function getFnP(classF, nameF) {
  6068. let prop = Object.entries(classF.__properties__)
  6069. return prop.filter((e) => e[1] == nameF).pop()[0];
  6070. }
  6071.  
  6072. /**
  6073. * Returns the function name with the specified ordinal from the class
  6074. *
  6075. * Возвращает имя функции с указаным порядковым номером из класса
  6076. * @param {Object} classF Class // класс
  6077. * @param {Number} nF Order number of function // порядковый номер функции
  6078. * @returns
  6079. */
  6080. function getFn(classF, nF) {
  6081. let prop = Object.keys(classF);
  6082. return prop[nF];
  6083. }
  6084.  
  6085. /**
  6086. * Returns the name of the function with the specified serial number from the prototype of the class
  6087. *
  6088. * Возвращает имя функции с указаным порядковым номером из прототипа класса
  6089. * @param {Object} classF Class // класс
  6090. * @param {Number} nF Order number of function // порядковый номер функции
  6091. * @returns
  6092. */
  6093. function getProtoFn(classF, nF) {
  6094. let prop = Object.keys(classF.prototype);
  6095. return prop[nF];
  6096. }
  6097. /**
  6098. * Description of replaced functions
  6099. *
  6100. * Описание подменяемых функций
  6101. */
  6102. replaceFunction = {
  6103. company: function () {
  6104. let PMD_12 = getProtoFn(Game.PlayerMissionData, 12);
  6105. let oldSkipMisson = Game.PlayerMissionData.prototype[PMD_12];
  6106. Game.PlayerMissionData.prototype[PMD_12] = function (a, b, c) {
  6107. if (!isChecked('passBattle')) {
  6108. oldSkipMisson.call(this, a, b, c);
  6109. return;
  6110. }
  6111.  
  6112. try {
  6113. this[getProtoFn(Game.PlayerMissionData, 9)] = new Game.PlayerMissionBattle(a, b, c);
  6114.  
  6115. var a = new Game.BattlePresets(
  6116. !1,
  6117. !1,
  6118. !0,
  6119. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  6120. !1
  6121. );
  6122. a = new Game.BattleInstantPlay(c, a);
  6123. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6124. a.start();
  6125. } catch (error) {
  6126. console.error('company', error);
  6127. oldSkipMisson.call(this, a, b, c);
  6128. }
  6129. };
  6130.  
  6131. Game.PlayerMissionData.prototype.P$h = function (a) {
  6132. let GM_2 = getFn(Game.GameModel, 2);
  6133. let GM_P2 = getProtoFn(Game.GameModel, 2);
  6134. let CM_20 = getProtoFn(Game.CommandManager, 20);
  6135. let MCL_2 = getProtoFn(Game.MissionCommandList, 2);
  6136. let MBR_15 = getF(Game.MultiBattleResult, 'get_result');
  6137. let RPCCB_15 = getProtoFn(Game.RPCCommandBase, 16);
  6138. let PMD_32 = getProtoFn(Game.PlayerMissionData, 32);
  6139. Game.GameModel[GM_2]()[GM_P2][CM_20][MCL_2](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PMD_32]));
  6140. };
  6141. },
  6142. tower: function () {
  6143. let PTD_67 = getProtoFn(Game.PlayerTowerData, 67);
  6144. let oldSkipTower = Game.PlayerTowerData.prototype[PTD_67];
  6145. Game.PlayerTowerData.prototype[PTD_67] = function (a) {
  6146. if (!isChecked('passBattle')) {
  6147. oldSkipTower.call(this, a);
  6148. return;
  6149. }
  6150. try {
  6151. var p = new Game.BattlePresets(
  6152. !1,
  6153. !1,
  6154. !0,
  6155. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  6156. !1
  6157. );
  6158. a = new Game.BattleInstantPlay(a, p);
  6159. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6160. a.start();
  6161. } catch (error) {
  6162. console.error('tower', error);
  6163. oldSkipMisson.call(this, a, b, c);
  6164. }
  6165. };
  6166.  
  6167. Game.PlayerTowerData.prototype.P$h = function (a) {
  6168. const GM_2 = getFnP(Game.GameModel, 'get_instance');
  6169. const GM_P2 = getProtoFn(Game.GameModel, 2);
  6170. const CM_29 = getProtoFn(Game.CommandManager, 29);
  6171. const TCL_5 = getProtoFn(Game.TowerCommandList, 5);
  6172. const MBR_15 = getF(Game.MultiBattleResult, 'get_result');
  6173. const RPCCB_15 = getProtoFn(Game.RPCCommandBase, 17);
  6174. const PTD_78 = getProtoFn(Game.PlayerTowerData, 78);
  6175. Game.GameModel[GM_2]()[GM_P2][CM_29][TCL_5](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PTD_78]));
  6176. };
  6177. },
  6178. // skipSelectHero: function() {
  6179. // if (!HOST) throw Error('Use connectGame');
  6180. // Game.PlayerHeroTeamResolver.prototype[getProtoFn(Game.PlayerHeroTeamResolver, 3)] = () => false;
  6181. // },
  6182. passBattle: function () {
  6183. let BPP_4 = getProtoFn(Game.BattlePausePopup, 4);
  6184. let oldPassBattle = Game.BattlePausePopup.prototype[BPP_4];
  6185. Game.BattlePausePopup.prototype[BPP_4] = function (a) {
  6186. if (!isChecked('passBattle')) {
  6187. oldPassBattle.call(this, a);
  6188. return;
  6189. }
  6190. try {
  6191. Game.BattlePopup.prototype[getProtoFn(Game.BattlePausePopup, 4)].call(this, a);
  6192. this[getProtoFn(Game.BattlePausePopup, 3)]();
  6193. this[getProtoFn(Game.DisplayObjectContainer, 3)](this.clip[getProtoFn(Game.GuiClipContainer, 2)]());
  6194. this.clip[getProtoFn(Game.BattlePausePopupClip, 1)][getProtoFn(Game.ClipLabelBase, 9)](
  6195. Game.Translate.translate('UI_POPUP_BATTLE_PAUSE')
  6196. );
  6197.  
  6198. this.clip[getProtoFn(Game.BattlePausePopupClip, 2)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  6199. Game.Translate.translate('UI_POPUP_BATTLE_RETREAT'),
  6200. ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 17)]))
  6201. );
  6202. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  6203. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 14)](),
  6204. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 13)]()
  6205. ? ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  6206. : ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  6207. );
  6208.  
  6209. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 0)][
  6210. getProtoFn(Game.ClipLabelBase, 24)
  6211. ]();
  6212. this.clip[getProtoFn(Game.BattlePausePopupClip, 3)][getProtoFn(Game.SettingToggleButton, 3)](
  6213. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 9)]()
  6214. );
  6215. this.clip[getProtoFn(Game.BattlePausePopupClip, 4)][getProtoFn(Game.SettingToggleButton, 3)](
  6216. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 10)]()
  6217. );
  6218. this.clip[getProtoFn(Game.BattlePausePopupClip, 6)][getProtoFn(Game.SettingToggleButton, 3)](
  6219. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 11)]()
  6220. );
  6221. } catch (error) {
  6222. console.error('passBattle', error);
  6223. oldPassBattle.call(this, a);
  6224. }
  6225. };
  6226.  
  6227. let retreatButtonLabel = getF(Game.BattlePausePopupMediator, 'get_retreatButtonLabel');
  6228. let oldFunc = Game.BattlePausePopupMediator.prototype[retreatButtonLabel];
  6229. Game.BattlePausePopupMediator.prototype[retreatButtonLabel] = function () {
  6230. if (isChecked('passBattle')) {
  6231. return I18N('BTN_PASS');
  6232. } else {
  6233. return oldFunc.call(this);
  6234. }
  6235. };
  6236. },
  6237. endlessCards: function () {
  6238. let PDD_21 = getProtoFn(Game.PlayerDungeonData, 21);
  6239. let oldEndlessCards = Game.PlayerDungeonData.prototype[PDD_21];
  6240. Game.PlayerDungeonData.prototype[PDD_21] = function () {
  6241. if (countPredictionCard <= 0) {
  6242. return true;
  6243. } else {
  6244. return oldEndlessCards.call(this);
  6245. }
  6246. };
  6247. },
  6248. speedBattle: function () {
  6249. const get_timeScale = getF(Game.BattleController, 'get_timeScale');
  6250. const oldSpeedBattle = Game.BattleController.prototype[get_timeScale];
  6251. Game.BattleController.prototype[get_timeScale] = function () {
  6252. const speedBattle = Number.parseFloat(getInput('speedBattle'));
  6253. if (!speedBattle) {
  6254. return oldSpeedBattle.call(this);
  6255. }
  6256. try {
  6257. const BC_12 = getProtoFn(Game.BattleController, 12);
  6258. const BSM_12 = getProtoFn(Game.BattleSettingsModel, 12);
  6259. const BP_get_value = getF(Game.BooleanProperty, 'get_value');
  6260. if (this[BC_12][BSM_12][BP_get_value]()) {
  6261. return 0;
  6262. }
  6263. const BSM_2 = getProtoFn(Game.BattleSettingsModel, 2);
  6264. const BC_49 = getProtoFn(Game.BattleController, 49);
  6265. const BSM_1 = getProtoFn(Game.BattleSettingsModel, 1);
  6266. const BC_14 = getProtoFn(Game.BattleController, 14);
  6267. const BC_3 = getFn(Game.BattleController, 3);
  6268. if (this[BC_12][BSM_2][BP_get_value]()) {
  6269. var a = speedBattle * this[BC_49]();
  6270. } else {
  6271. a = this[BC_12][BSM_1][BP_get_value]();
  6272. const maxSpeed = Math.max(...this[BC_14]);
  6273. const multiple = a == this[BC_14].indexOf(maxSpeed) ? (maxSpeed >= 4 ? speedBattle : this[BC_14][a]) : this[BC_14][a];
  6274. a = multiple * Game.BattleController[BC_3][BP_get_value]() * this[BC_49]();
  6275. }
  6276. const BSM_24 = getProtoFn(Game.BattleSettingsModel, 24);
  6277. a > this[BC_12][BSM_24][BP_get_value]() && (a = this[BC_12][BSM_24][BP_get_value]());
  6278. const DS_23 = getFn(Game.DataStorage, 23);
  6279. const get_battleSpeedMultiplier = getF(Game.RuleStorage, 'get_battleSpeedMultiplier', true);
  6280. var b = Game.DataStorage[DS_23][get_battleSpeedMultiplier]();
  6281. const R_1 = getFn(selfGame.Reflect, 1);
  6282. const BC_1 = getFn(Game.BattleController, 1);
  6283. const get_config = getF(Game.BattlePresets, 'get_config');
  6284. null != b &&
  6285. (a = selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  6286. ? a * selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  6287. : a * selfGame.Reflect[R_1](b, 'default'));
  6288. return a;
  6289. } catch (error) {
  6290. console.error('passBatspeedBattletle', error);
  6291. return oldSpeedBattle.call(this);
  6292. }
  6293. };
  6294. },
  6295.  
  6296. /**
  6297. * Acceleration button without Valkyries favor
  6298. *
  6299. * Кнопка ускорения без Покровительства Валькирий
  6300. */
  6301. battleFastKey: function () {
  6302. const BGM_43 = getProtoFn(Game.BattleGuiMediator, 43);
  6303. const oldBattleFastKey = Game.BattleGuiMediator.prototype[BGM_43];
  6304. Game.BattleGuiMediator.prototype[BGM_43] = function () {
  6305. let flag = true;
  6306. //console.log(flag)
  6307. if (!flag) {
  6308. return oldBattleFastKey.call(this);
  6309. }
  6310. try {
  6311. const BGM_9 = getProtoFn(Game.BattleGuiMediator, 9);
  6312. const BGM_10 = getProtoFn(Game.BattleGuiMediator, 10);
  6313. const BPW_0 = getProtoFn(Game.BooleanPropertyWriteable, 0);
  6314. this[BGM_9][BPW_0](true);
  6315. this[BGM_10][BPW_0](true);
  6316. } catch (error) {
  6317. console.error(error);
  6318. return oldBattleFastKey.call(this);
  6319. }
  6320. };
  6321. },
  6322. fastSeason: function () {
  6323. const GameNavigator = selfGame['game.screen.navigator.GameNavigator'];
  6324. const oldFuncName = getProtoFn(GameNavigator, 16);
  6325. const newFuncName = getProtoFn(GameNavigator, 14);
  6326. const oldFastSeason = GameNavigator.prototype[oldFuncName];
  6327. const newFastSeason = GameNavigator.prototype[newFuncName];
  6328. GameNavigator.prototype[oldFuncName] = function (a, b) {
  6329. if (isChecked('fastSeason')) {
  6330. return newFastSeason.apply(this, [a]);
  6331. } else {
  6332. return oldFastSeason.apply(this, [a, b]);
  6333. }
  6334. };
  6335. },
  6336. ShowChestReward: function () {
  6337. const TitanArtifactChest = selfGame['game.mechanics.titan_arena.mediator.chest.TitanArtifactChestRewardPopupMediator'];
  6338. const getOpenAmountTitan = getF(TitanArtifactChest, 'get_openAmount');
  6339. const oldGetOpenAmountTitan = TitanArtifactChest.prototype[getOpenAmountTitan];
  6340. TitanArtifactChest.prototype[getOpenAmountTitan] = function () {
  6341. if (correctShowOpenArtifact) {
  6342. correctShowOpenArtifact--;
  6343. return 100;
  6344. }
  6345. return oldGetOpenAmountTitan.call(this);
  6346. };
  6347.  
  6348. const ArtifactChest = selfGame['game.view.popup.artifactchest.rewardpopup.ArtifactChestRewardPopupMediator'];
  6349. const getOpenAmount = getF(ArtifactChest, 'get_openAmount');
  6350. const oldGetOpenAmount = ArtifactChest.prototype[getOpenAmount];
  6351. ArtifactChest.prototype[getOpenAmount] = function () {
  6352. if (correctShowOpenArtifact) {
  6353. correctShowOpenArtifact--;
  6354. return 100;
  6355. }
  6356. return oldGetOpenAmount.call(this);
  6357. };
  6358. },
  6359. fixCompany: function () {
  6360. const GameBattleView = selfGame['game.mediator.gui.popup.battle.GameBattleView'];
  6361. const BattleThread = selfGame['game.battle.controller.thread.BattleThread'];
  6362. const getOnViewDisposed = getF(BattleThread, 'get_onViewDisposed');
  6363. const getThread = getF(GameBattleView, 'get_thread');
  6364. const oldFunc = GameBattleView.prototype[getThread];
  6365. GameBattleView.prototype[getThread] = function () {
  6366. return (
  6367. oldFunc.call(this) || {
  6368. [getOnViewDisposed]: async () => {},
  6369. }
  6370. );
  6371. };
  6372. },
  6373. BuyTitanArtifact: function () {
  6374. const BIP_4 = getProtoFn(selfGame['game.view.popup.shop.buy.BuyItemPopup'], 4);
  6375. const BuyItemPopup = selfGame['game.view.popup.shop.buy.BuyItemPopup'];
  6376. const oldFunc = BuyItemPopup.prototype[BIP_4];
  6377. BuyItemPopup.prototype[BIP_4] = function () {
  6378. if (isChecked('countControl')) {
  6379. const BuyTitanArtifactItemPopup = selfGame['game.view.popup.shop.buy.BuyTitanArtifactItemPopup'];
  6380. const BTAP_0 = getProtoFn(BuyTitanArtifactItemPopup, 0);
  6381. if (this[BTAP_0]) {
  6382. const BuyTitanArtifactPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyTitanArtifactItemPopupMediator'];
  6383. const BTAM_1 = getProtoFn(BuyTitanArtifactPopupMediator, 1);
  6384. const BuyItemPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyItemPopupMediator'];
  6385. const BIPM_5 = getProtoFn(BuyItemPopupMediator, 5);
  6386. const BIPM_7 = getProtoFn(BuyItemPopupMediator, 7);
  6387. const BIPM_9 = getProtoFn(BuyItemPopupMediator, 9);
  6388.  
  6389. let need = Math.min(this[BTAP_0][BTAM_1](), this[BTAP_0][BIPM_7]);
  6390. need = need ? need : 60;
  6391. this[BTAP_0][BIPM_9] = need;
  6392. this[BTAP_0][BIPM_5] = 10;
  6393. }
  6394. }
  6395. oldFunc.call(this);
  6396. };
  6397. },
  6398. ClanQuestsFastFarm: function () {
  6399. const VipRuleValueObject = selfGame['game.data.storage.rule.VipRuleValueObject'];
  6400. const getClanQuestsFastFarm = getF(VipRuleValueObject, 'get_clanQuestsFastFarm', 1);
  6401. VipRuleValueObject.prototype[getClanQuestsFastFarm] = function () {
  6402. return 0;
  6403. };
  6404. },
  6405. adventureCamera: function () {
  6406. const AMC_40 = getProtoFn(Game.AdventureMapCamera, 40);
  6407. const AMC_5 = getProtoFn(Game.AdventureMapCamera, 5);
  6408. const oldFunc = Game.AdventureMapCamera.prototype[AMC_40];
  6409. Game.AdventureMapCamera.prototype[AMC_40] = function (a) {
  6410. this[AMC_5] = 0.4;
  6411. oldFunc.bind(this)(a);
  6412. };
  6413. },
  6414. unlockMission: function () {
  6415. const WorldMapStoryDrommerHelper = selfGame['game.mediator.gui.worldmap.WorldMapStoryDrommerHelper'];
  6416. const WMSDH_4 = getFn(WorldMapStoryDrommerHelper, 4);
  6417. const WMSDH_7 = getFn(WorldMapStoryDrommerHelper, 7);
  6418. WorldMapStoryDrommerHelper[WMSDH_4] = function () {
  6419. return true;
  6420. };
  6421. WorldMapStoryDrommerHelper[WMSDH_7] = function () {
  6422. return true;
  6423. };
  6424. },
  6425. };
  6426.  
  6427. /**
  6428. * Starts replacing recorded functions
  6429. *
  6430. * Запускает замену записанных функций
  6431. */
  6432. this.activateHacks = function () {
  6433. if (!selfGame) throw Error('Use connectGame');
  6434. for (let func in replaceFunction) {
  6435. replaceFunction[func]();
  6436. }
  6437. }
  6438.  
  6439. /**
  6440. * Returns the game object
  6441. *
  6442. * Возвращает объект игры
  6443. */
  6444. this.getSelfGame = function () {
  6445. return selfGame;
  6446. }
  6447.  
  6448. /**
  6449. * Updates game data
  6450. *
  6451. * Обновляет данные игры
  6452. */
  6453. this.refreshGame = function () {
  6454. (new Game.NextDayUpdatedManager)[getProtoFn(Game.NextDayUpdatedManager, 5)]();
  6455. try {
  6456. cheats.refreshInventory();
  6457. } catch (e) { }
  6458. }
  6459.  
  6460. /**
  6461. * Update inventory
  6462. *
  6463. * Обновляет инвентарь
  6464. */
  6465. this.refreshInventory = async function () {
  6466. const GM_INST = getFnP(Game.GameModel, "get_instance");
  6467. const GM_0 = getProtoFn(Game.GameModel, 0);
  6468. const P_24 = getProtoFn(selfGame["game.model.user.Player"], 24);
  6469. const Player = Game.GameModel[GM_INST]()[GM_0];
  6470. Player[P_24] = new selfGame["game.model.user.inventory.PlayerInventory"]
  6471. Player[P_24].init(await Send({calls:[{name:"inventoryGet",args:{},ident:"body"}]}).then(e => e.results[0].result.response))
  6472. }
  6473. this.updateInventory = function (reward) {
  6474. const GM_INST = getFnP(Game.GameModel, 'get_instance');
  6475. const GM_0 = getProtoFn(Game.GameModel, 0);
  6476. const P_24 = getProtoFn(selfGame['game.model.user.Player'], 24);
  6477. const Player = Game.GameModel[GM_INST]()[GM_0];
  6478. Player[P_24].init(reward);
  6479. };
  6480.  
  6481. this.updateMap = function (data) {
  6482. const PCDD_21 = getProtoFn(selfGame['game.mechanics.clanDomination.model.PlayerClanDominationData'], 21);
  6483. const P_60 = getProtoFn(selfGame['game.model.user.Player'], 60);
  6484. const GM_0 = getProtoFn(Game.GameModel, 0);
  6485. const getInstance = getFnP(selfGame['Game'], 'get_instance');
  6486. const PlayerClanDominationData = Game.GameModel[getInstance]()[GM_0];
  6487. PlayerClanDominationData[P_60][PCDD_21].update(data);
  6488. };
  6489.  
  6490. /**
  6491. * Change the play screen on windowName
  6492. *
  6493. * Сменить экран игры на windowName
  6494. *
  6495. * Possible options:
  6496. *
  6497. * Возможные варианты:
  6498. *
  6499. * 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
  6500. */
  6501. this.goNavigtor = function (windowName) {
  6502. let mechanicStorage = selfGame["game.data.storage.mechanic.MechanicStorage"];
  6503. let window = mechanicStorage[windowName];
  6504. let event = new selfGame["game.mediator.gui.popup.PopupStashEventParams"];
  6505. let Game = selfGame['Game'];
  6506. let navigator = getF(Game, "get_navigator")
  6507. let navigate = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 18)
  6508. let instance = getFnP(Game, 'get_instance');
  6509. Game[instance]()[navigator]()[navigate](window, event);
  6510. }
  6511.  
  6512. /**
  6513. * Move to the sanctuary cheats.goSanctuary()
  6514. *
  6515. * Переместиться в святилище cheats.goSanctuary()
  6516. */
  6517. this.goSanctuary = () => {
  6518. this.goNavigtor("SANCTUARY");
  6519. }
  6520.  
  6521. /**
  6522. * Go to Guild War
  6523. *
  6524. * Перейти к Войне Гильдий
  6525. */
  6526. this.goClanWar = function() {
  6527. let instance = getFnP(Game.GameModel, 'get_instance')
  6528. let player = Game.GameModel[instance]().A;
  6529. let clanWarSelect = selfGame["game.mechanics.cross_clan_war.popup.selectMode.CrossClanWarSelectModeMediator"];
  6530. new clanWarSelect(player).open();
  6531. }
  6532.  
  6533. /**
  6534. * Go to BrawlShop
  6535. *
  6536. * Переместиться в BrawlShop
  6537. */
  6538. this.goBrawlShop = () => {
  6539. const instance = getFnP(Game.GameModel, 'get_instance')
  6540. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  6541. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  6542. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  6543. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  6544.  
  6545. const player = Game.GameModel[instance]().A;
  6546. const shop = player[P_36][PSD_0][IM_0][1038][PSDE_4];
  6547. const shopPopup = new selfGame["game.mechanics.brawl.mediator.BrawlShopPopupMediator"](player, shop)
  6548. shopPopup.open(new selfGame["game.mediator.gui.popup.PopupStashEventParams"])
  6549. }
  6550.  
  6551. /**
  6552. * Returns all stores from game data
  6553. *
  6554. * Возвращает все магазины из данных игры
  6555. */
  6556. this.getShops = () => {
  6557. const instance = getFnP(Game.GameModel, 'get_instance')
  6558. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  6559. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  6560. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  6561.  
  6562. const player = Game.GameModel[instance]().A;
  6563. return player[P_36][PSD_0][IM_0];
  6564. }
  6565.  
  6566. /**
  6567. * Returns the store from the game data by ID
  6568. *
  6569. * Возвращает магазин из данных игры по идетификатору
  6570. */
  6571. this.getShop = (id) => {
  6572. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  6573. const shops = this.getShops();
  6574. const shop = shops[id]?.[PSDE_4];
  6575. return shop;
  6576. }
  6577.  
  6578. /**
  6579. * Change island map
  6580. *
  6581. * Сменить карту острова
  6582. */
  6583. this.changeIslandMap = (mapId = 2) => {
  6584. const GameInst = getFnP(selfGame['Game'], 'get_instance');
  6585. const GM_0 = getProtoFn(Game.GameModel, 0);
  6586. const P_59 = getProtoFn(selfGame["game.model.user.Player"], 59);
  6587. const PSAD_31 = getProtoFn(selfGame['game.mechanics.season_adventure.model.PlayerSeasonAdventureData'], 31);
  6588. const Player = Game.GameModel[GameInst]()[GM_0];
  6589. Player[P_59][PSAD_31]({ id: mapId, seasonAdventure: { id: mapId, startDate: 1701914400, endDate: 1709690400, closed: false } });
  6590.  
  6591. const GN_15 = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 15)
  6592. const navigator = getF(selfGame['Game'], "get_navigator");
  6593. selfGame['Game'][GameInst]()[navigator]()[GN_15](new selfGame["game.mediator.gui.popup.PopupStashEventParams"]);
  6594. }
  6595.  
  6596. /**
  6597. * Game library availability tracker
  6598. *
  6599. * Отслеживание доступности игровой библиотеки
  6600. */
  6601. function checkLibLoad() {
  6602. timeout = setTimeout(() => {
  6603. if (Game.GameModel) {
  6604. changeLib();
  6605. } else {
  6606. checkLibLoad();
  6607. }
  6608. }, 100)
  6609. }
  6610.  
  6611. /**
  6612. * Game library data spoofing
  6613. *
  6614. * Подмена данных игровой библиотеки
  6615. */
  6616. function changeLib() {
  6617. console.log('lib connect');
  6618. const originalStartFunc = Game.GameModel.prototype.start;
  6619. Game.GameModel.prototype.start = function (a, b, c) {
  6620. self.libGame = b.raw;
  6621. try {
  6622. const levels = b.raw.seasonAdventure.level;
  6623. for (const id in levels) {
  6624. const level = levels[id];
  6625. level.clientData.graphics.fogged = level.clientData.graphics.visible
  6626. }
  6627. const adv = b.raw.seasonAdventure.list[1];
  6628. adv.clientData.asset = 'dialog_season_adventure_tiles';
  6629. } catch (e) {
  6630. console.warn(e);
  6631. }
  6632. originalStartFunc.call(this, a, b, c);
  6633. }
  6634. }
  6635.  
  6636. /**
  6637. * Returns the value of a language constant
  6638. *
  6639. * Возвращает значение языковой константы
  6640. * @param {*} langConst language constant // языковая константа
  6641. * @returns
  6642. */
  6643. this.translate = function (langConst) {
  6644. return Game.Translate.translate(langConst);
  6645. }
  6646.  
  6647. connectGame();
  6648. checkLibLoad();
  6649. }
  6650.  
  6651. /**
  6652. * Auto collection of gifts
  6653. *
  6654. * Автосбор подарков
  6655. */
  6656. function getAutoGifts() {
  6657. // c3ltYm9scyB0aGF0IG1lYW4gbm90aGluZw==
  6658. let valName = 'giftSendIds_' + userInfo.id;
  6659.  
  6660. if (!localStorage['clearGift' + userInfo.id]) {
  6661. localStorage[valName] = '';
  6662. localStorage['clearGift' + userInfo.id] = '+';
  6663. }
  6664.  
  6665. if (!localStorage[valName]) {
  6666. localStorage[valName] = '';
  6667. }
  6668.  
  6669. const giftsAPI = new ZingerYWebsiteAPI('getGifts.php', arguments);
  6670. /**
  6671. * Submit a request to receive gift codes
  6672. *
  6673. * Отправка запроса для получения кодов подарков
  6674. */
  6675. giftsAPI.request().then((data) => {
  6676. let freebieCheckCalls = {
  6677. calls: [],
  6678. };
  6679. data.forEach((giftId, n) => {
  6680. if (localStorage[valName].includes(giftId)) return;
  6681. freebieCheckCalls.calls.push({
  6682. name: 'registration',
  6683. args: {
  6684. user: { referrer: {} },
  6685. giftId,
  6686. },
  6687. context: {
  6688. actionTs: Math.floor(performance.now()),
  6689. cookie: window?.NXAppInfo?.session_id || null,
  6690. },
  6691. ident: giftId,
  6692. });
  6693. });
  6694.  
  6695. if (!freebieCheckCalls.calls.length) {
  6696. return;
  6697. }
  6698.  
  6699. send(JSON.stringify(freebieCheckCalls), (e) => {
  6700. let countGetGifts = 0;
  6701. const gifts = [];
  6702. for (check of e.results) {
  6703. gifts.push(check.ident);
  6704. if (check.result.response != null) {
  6705. countGetGifts++;
  6706. }
  6707. }
  6708. const saveGifts = localStorage[valName].split(';');
  6709. localStorage[valName] = [...saveGifts, ...gifts].slice(-50).join(';');
  6710. console.log(`${I18N('GIFTS')}: ${countGetGifts}`);
  6711. });
  6712. });
  6713. }
  6714.  
  6715. /**
  6716. * To fill the kills in the Forge of Souls
  6717. *
  6718. * Набить килов в горниле душ
  6719. */
  6720. async function bossRatingEvent() {
  6721. const topGet = await Send(JSON.stringify({ calls: [{ name: "topGet", args: { type: "bossRatingTop", extraId: 0 }, ident: "body" }] }));
  6722. if (!topGet || !topGet.results[0].result.response[0]) {
  6723. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  6724. return;
  6725. }
  6726. const replayId = topGet.results[0].result.response[0].userData.replayId;
  6727. const result = await Send(JSON.stringify({
  6728. calls: [
  6729. { name: "battleGetReplay", args: { id: replayId }, ident: "battleGetReplay" },
  6730. { name: "heroGetAll", args: {}, ident: "heroGetAll" },
  6731. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  6732. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  6733. ]
  6734. }));
  6735. const bossEventInfo = result.results[3].result.response.find(e => e.offerType == "bossEvent");
  6736. if (!bossEventInfo) {
  6737. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  6738. return;
  6739. }
  6740. const usedHeroes = bossEventInfo.progress.usedHeroes;
  6741. const party = Object.values(result.results[0].result.response.replay.attackers);
  6742. const availableHeroes = Object.values(result.results[1].result.response).map(e => e.id);
  6743. const availablePets = Object.values(result.results[2].result.response).map(e => e.id);
  6744. const calls = [];
  6745. /**
  6746. * First pack
  6747. *
  6748. * Первая пачка
  6749. */
  6750. const args = {
  6751. heroes: [],
  6752. favor: {}
  6753. }
  6754. for (let hero of party) {
  6755. if (hero.id >= 6000 && availablePets.includes(hero.id)) {
  6756. args.pet = hero.id;
  6757. continue;
  6758. }
  6759. if (!availableHeroes.includes(hero.id) || usedHeroes.includes(hero.id)) {
  6760. continue;
  6761. }
  6762. args.heroes.push(hero.id);
  6763. if (hero.favorPetId) {
  6764. args.favor[hero.id] = hero.favorPetId;
  6765. }
  6766. }
  6767. if (args.heroes.length) {
  6768. calls.push({
  6769. name: "bossRatingEvent_startBattle",
  6770. args,
  6771. ident: "body_0"
  6772. });
  6773. }
  6774. /**
  6775. * Other packs
  6776. *
  6777. * Другие пачки
  6778. */
  6779. let heroes = [];
  6780. let count = 1;
  6781. while (heroId = availableHeroes.pop()) {
  6782. if (args.heroes.includes(heroId) || usedHeroes.includes(heroId)) {
  6783. continue;
  6784. }
  6785. heroes.push(heroId);
  6786. if (heroes.length == 5) {
  6787. calls.push({
  6788. name: "bossRatingEvent_startBattle",
  6789. args: {
  6790. heroes: [...heroes],
  6791. pet: availablePets[Math.floor(Math.random() * availablePets.length)]
  6792. },
  6793. ident: "body_" + count
  6794. });
  6795. heroes = [];
  6796. count++;
  6797. }
  6798. }
  6799.  
  6800. if (!calls.length) {
  6801. setProgress(`${I18N('NO_HEROES')}`, true);
  6802. return;
  6803. }
  6804.  
  6805. const resultBattles = await Send(JSON.stringify({ calls }));
  6806. console.log(resultBattles);
  6807. rewardBossRatingEvent();
  6808. }
  6809.  
  6810. /**
  6811. * Collecting Rewards from the Forge of Souls
  6812. *
  6813. * Сбор награды из Горнила Душ
  6814. */
  6815. function rewardBossRatingEvent() {
  6816. let rewardBossRatingCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  6817. send(rewardBossRatingCall, function (data) {
  6818. let bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  6819. if (!bossEventInfo) {
  6820. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  6821. return;
  6822. }
  6823.  
  6824. let farmedChests = bossEventInfo.progress.farmedChests;
  6825. let score = bossEventInfo.progress.score;
  6826. setProgress(`${I18N('DAMAGE_AMOUNT')}: ${score}`);
  6827. let revard = bossEventInfo.reward;
  6828.  
  6829. let getRewardCall = {
  6830. calls: []
  6831. }
  6832.  
  6833. let count = 0;
  6834. for (let i = 1; i < 10; i++) {
  6835. if (farmedChests.includes(i)) {
  6836. continue;
  6837. }
  6838. if (score < revard[i].score) {
  6839. break;
  6840. }
  6841. getRewardCall.calls.push({
  6842. name: "bossRatingEvent_getReward",
  6843. args: {
  6844. rewardId: i
  6845. },
  6846. ident: "body_" + i
  6847. });
  6848. count++;
  6849. }
  6850. if (!count) {
  6851. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  6852. return;
  6853. }
  6854.  
  6855. send(JSON.stringify(getRewardCall), e => {
  6856. console.log(e);
  6857. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  6858. });
  6859. });
  6860. }
  6861.  
  6862. /**
  6863. * Collect Easter eggs and event rewards
  6864. *
  6865. * Собрать пасхалки и награды событий
  6866. */
  6867. function offerFarmAllReward() {
  6868. const offerGetAllCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  6869. return Send(offerGetAllCall).then((data) => {
  6870. const offerGetAll = data.results[0].result.response.filter(e => e.type == "reward" && !e?.freeRewardObtained && e.reward);
  6871. if (!offerGetAll.length) {
  6872. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  6873. return;
  6874. }
  6875.  
  6876. const calls = [];
  6877. for (let reward of offerGetAll) {
  6878. calls.push({
  6879. name: "offerFarmReward",
  6880. args: {
  6881. offerId: reward.id
  6882. },
  6883. ident: "offerFarmReward_" + reward.id
  6884. });
  6885. }
  6886.  
  6887. return Send(JSON.stringify({ calls })).then(e => {
  6888. console.log(e);
  6889. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  6890. });
  6891. });
  6892. }
  6893.  
  6894. /**
  6895. * Assemble Outland
  6896. *
  6897. * Собрать запределье
  6898. */
  6899. function getOutland() {
  6900. return new Promise(function (resolve, reject) {
  6901. send('{"calls":[{"name":"bossGetAll","args":{},"ident":"bossGetAll"}]}', e => {
  6902. let bosses = e.results[0].result.response;
  6903.  
  6904. let bossRaidOpenChestCall = {
  6905. calls: []
  6906. };
  6907.  
  6908. for (let boss of bosses) {
  6909. if (boss.mayRaid) {
  6910. bossRaidOpenChestCall.calls.push({
  6911. name: "bossRaid",
  6912. args: {
  6913. bossId: boss.id
  6914. },
  6915. ident: "bossRaid_" + boss.id
  6916. });
  6917. bossRaidOpenChestCall.calls.push({
  6918. name: "bossOpenChest",
  6919. args: {
  6920. bossId: boss.id,
  6921. amount: 1,
  6922. starmoney: 0
  6923. },
  6924. ident: "bossOpenChest_" + boss.id
  6925. });
  6926. } else if (boss.chestId == 1) {
  6927. bossRaidOpenChestCall.calls.push({
  6928. name: "bossOpenChest",
  6929. args: {
  6930. bossId: boss.id,
  6931. amount: 1,
  6932. starmoney: 0
  6933. },
  6934. ident: "bossOpenChest_" + boss.id
  6935. });
  6936. }
  6937. }
  6938.  
  6939. if (!bossRaidOpenChestCall.calls.length) {
  6940. setProgress(`${I18N('OUTLAND')} ${I18N('NOTHING_TO_COLLECT')}`, true);
  6941. resolve();
  6942. return;
  6943. }
  6944.  
  6945. send(JSON.stringify(bossRaidOpenChestCall), e => {
  6946. setProgress(`${I18N('OUTLAND')} ${I18N('COLLECTED')}`, true);
  6947. resolve();
  6948. });
  6949. });
  6950. });
  6951. }
  6952.  
  6953. /**
  6954. * Collect all rewards
  6955. *
  6956. * Собрать все награды
  6957. */
  6958. function questAllFarm() {
  6959. return new Promise(function (resolve, reject) {
  6960. let questGetAllCall = {
  6961. calls: [{
  6962. name: "questGetAll",
  6963. args: {},
  6964. ident: "body"
  6965. }]
  6966. }
  6967. send(JSON.stringify(questGetAllCall), function (data) {
  6968. let questGetAll = data.results[0].result.response;
  6969. const questAllFarmCall = {
  6970. calls: []
  6971. }
  6972. let number = 0;
  6973. for (let quest of questGetAll) {
  6974. if (quest.id < 1e6 && quest.state == 2) {
  6975. questAllFarmCall.calls.push({
  6976. name: "questFarm",
  6977. args: {
  6978. questId: quest.id
  6979. },
  6980. ident: `group_${number}_body`
  6981. });
  6982. number++;
  6983. }
  6984. }
  6985.  
  6986. if (!questAllFarmCall.calls.length) {
  6987. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  6988. resolve();
  6989. return;
  6990. }
  6991.  
  6992. send(JSON.stringify(questAllFarmCall), function (res) {
  6993. console.log(res);
  6994. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  6995. resolve();
  6996. });
  6997. });
  6998. })
  6999. }
  7000.  
  7001. /**
  7002. * Mission auto repeat
  7003. *
  7004. * Автоповтор миссии
  7005. * isStopSendMission = false;
  7006. * isSendsMission = true;
  7007. **/
  7008. this.sendsMission = async function (param) {
  7009. if (isStopSendMission) {
  7010. isSendsMission = false;
  7011. console.log(I18N('STOPPED'));
  7012. setProgress('');
  7013. await popup.confirm(`${I18N('STOPPED')}<br>${I18N('REPETITIONS')}: ${param.count}`, [{
  7014. msg: 'Ok',
  7015. result: true
  7016. }, ])
  7017. return;
  7018. }
  7019. lastMissionBattleStart = Date.now();
  7020. let missionStartCall = {
  7021. "calls": [{
  7022. "name": "missionStart",
  7023. "args": lastMissionStart,
  7024. "ident": "body"
  7025. }]
  7026. }
  7027. /**
  7028. * Mission Request
  7029. *
  7030. * Запрос на выполнение мисии
  7031. */
  7032. SendRequest(JSON.stringify(missionStartCall), async e => {
  7033. if (e['error']) {
  7034. isSendsMission = false;
  7035. console.log(e['error']);
  7036. setProgress('');
  7037. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  7038. await popup.confirm(msg, [
  7039. {msg: 'Ok', result: true},
  7040. ])
  7041. return;
  7042. }
  7043. /**
  7044. * Mission data calculation
  7045. *
  7046. * Расчет данных мисии
  7047. */
  7048. BattleCalc(e.results[0].result.response, 'get_tower', async r => {
  7049. /** missionTimer */
  7050. let timer = getTimer(r.battleTime) + 5;
  7051. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  7052. if (period < timer) {
  7053. timer = timer - period;
  7054. await countdownTimer(timer, `${I18N('MISSIONS_PASSED')}: ${param.count}`);
  7055. }
  7056.  
  7057. let missionEndCall = {
  7058. "calls": [{
  7059. "name": "missionEnd",
  7060. "args": {
  7061. "id": param.id,
  7062. "result": r.result,
  7063. "progress": r.progress
  7064. },
  7065. "ident": "body"
  7066. }]
  7067. }
  7068. /**
  7069. * Mission Completion Request
  7070. *
  7071. * Запрос на завершение миссии
  7072. */
  7073. SendRequest(JSON.stringify(missionEndCall), async (e) => {
  7074. if (e['error']) {
  7075. isSendsMission = false;
  7076. console.log(e['error']);
  7077. setProgress('');
  7078. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  7079. await popup.confirm(msg, [
  7080. {msg: 'Ok', result: true},
  7081. ])
  7082. return;
  7083. }
  7084. r = e.results[0].result.response;
  7085. if (r['error']) {
  7086. isSendsMission = false;
  7087. console.log(r['error']);
  7088. setProgress('');
  7089. await popup.confirm(`<br>${I18N('REPETITIONS')}: ${param.count}` + ' 3 ' + r['error'], [
  7090. {msg: 'Ok', result: true},
  7091. ])
  7092. return;
  7093. }
  7094.  
  7095. param.count++;
  7096. setProgress(`${I18N('MISSIONS_PASSED')}: ${param.count} (${I18N('STOP')})`, false, () => {
  7097. isStopSendMission = true;
  7098. });
  7099. setTimeout(sendsMission, 1, param);
  7100. });
  7101. })
  7102. });
  7103. }
  7104.  
  7105. /**
  7106. * Opening of russian dolls
  7107. *
  7108. * Открытие матрешек
  7109. */
  7110. async function openRussianDolls(libId, amount) {
  7111. let sum = 0;
  7112. let sumResult = [];
  7113.  
  7114. while (amount) {
  7115. sum += amount;
  7116. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`);
  7117. const calls = [{
  7118. name: "consumableUseLootBox",
  7119. args: { libId, amount },
  7120. ident: "body"
  7121. }];
  7122. const result = await Send(JSON.stringify({ calls })).then(e => e.results[0].result.response);
  7123. let newCount = 0;
  7124. for (let n of result) {
  7125. if (n?.consumable && n.consumable[libId]) {
  7126. newCount += n.consumable[libId]
  7127. }
  7128. }
  7129. sumResult = [...sumResult, ...result];
  7130. amount = newCount;
  7131. }
  7132.  
  7133. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`, 5000);
  7134. return sumResult;
  7135. }
  7136.  
  7137. /**
  7138. * Collect all mail, except letters with energy and charges of the portal
  7139. *
  7140. * Собрать всю почту, кроме писем с энергией и зарядами портала
  7141. */
  7142. function mailGetAll() {
  7143. const getMailInfo = '{"calls":[{"name":"mailGetAll","args":{},"ident":"body"}]}';
  7144.  
  7145. return Send(getMailInfo).then(dataMail => {
  7146. const letters = dataMail.results[0].result.response.letters;
  7147. const letterIds = lettersFilter(letters);
  7148. if (!letterIds.length) {
  7149. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  7150. return;
  7151. }
  7152.  
  7153. const calls = [
  7154. { name: "mailFarm", args: { letterIds }, ident: "body" }
  7155. ];
  7156.  
  7157. return Send(JSON.stringify({ calls })).then(res => {
  7158. const lettersIds = res.results[0].result.response;
  7159. if (lettersIds) {
  7160. const countLetters = Object.keys(lettersIds).length;
  7161. setProgress(`${I18N('RECEIVED')} ${countLetters} ${I18N('LETTERS')}`, true);
  7162. }
  7163. });
  7164. });
  7165. }
  7166.  
  7167. /**
  7168. * Filters received emails
  7169. *
  7170. * Фильтрует получаемые письма
  7171. */
  7172. function lettersFilter(letters) {
  7173. const lettersIds = [];
  7174. for (let l in letters) {
  7175. letter = letters[l];
  7176. const reward = letter.reward;
  7177. if (!reward) {
  7178. continue;
  7179. }
  7180. /**
  7181. * Mail Collection Exceptions
  7182. *
  7183. * Исключения на сбор писем
  7184. */
  7185. const isFarmLetter = !(
  7186. /** Portals // сферы портала */
  7187. (reward?.refillable ? reward.refillable[45] : false) ||
  7188. /** Energy // энергия */
  7189. (reward?.stamina ? reward.stamina : false) ||
  7190. /** accelerating energy gain // ускорение набора энергии */
  7191. (reward?.buff ? true : false) ||
  7192. /** VIP Points // вип очки */
  7193. (reward?.vipPoints ? reward.vipPoints : false) ||
  7194. /** souls of heroes // душы героев */
  7195. (reward?.fragmentHero ? true : false) ||
  7196. /** heroes // герои */
  7197. (reward?.bundleHeroReward ? true : false)
  7198. );
  7199. if (isFarmLetter) {
  7200. lettersIds.push(~~letter.id);
  7201. continue;
  7202. }
  7203. /**
  7204. * Если до окончания годности письма менее 24 часов,
  7205. * то оно собирается не смотря на исключения
  7206. */
  7207. const availableUntil = +letter?.availableUntil;
  7208. if (availableUntil) {
  7209. const maxTimeLeft = 24 * 60 * 60 * 1000;
  7210. const timeLeft = (new Date(availableUntil * 1000) - new Date())
  7211. console.log('Time left:', timeLeft)
  7212. if (timeLeft < maxTimeLeft) {
  7213. lettersIds.push(~~letter.id);
  7214. continue;
  7215. }
  7216. }
  7217. }
  7218. return lettersIds;
  7219. }
  7220.  
  7221. /**
  7222. * Displaying information about the areas of the portal and attempts on the VG
  7223. *
  7224. * Отображение информации о сферах портала и попытках на ВГ
  7225. */
  7226. async function justInfo() {
  7227. return new Promise(async (resolve, reject) => {
  7228. const calls = [{
  7229. name: "userGetInfo",
  7230. args: {},
  7231. ident: "userGetInfo"
  7232. },
  7233. {
  7234. name: "clanWarGetInfo",
  7235. args: {},
  7236. ident: "clanWarGetInfo"
  7237. },
  7238. {
  7239. name: "titanArenaGetStatus",
  7240. args: {},
  7241. ident: "titanArenaGetStatus"
  7242. }];
  7243. const result = await Send(JSON.stringify({ calls }));
  7244. const infos = result.results;
  7245. const portalSphere = infos[0].result.response.refillable.find(n => n.id == 45);
  7246. const clanWarMyTries = infos[1].result.response?.myTries ?? 0;
  7247. const arePointsMax = infos[1].result.response?.arePointsMax;
  7248. const titansLevel = +(infos[2].result.response?.tier ?? 0);
  7249. const titansStatus = infos[2].result.response?.status; //peace_time || battle
  7250.  
  7251. const sanctuaryButton = buttons['goToSanctuary'].button;
  7252. const clanWarButton = buttons['goToClanWar'].button;
  7253. const titansArenaButton = buttons['testTitanArena'].button;
  7254.  
  7255. if (portalSphere.amount) {
  7256. sanctuaryButton.style.color = portalSphere.amount >= 3 ? 'red' : 'brown';
  7257. sanctuaryButton.title = `${I18N('SANCTUARY_TITLE')}\n${portalSphere.amount} ${I18N('PORTALS')}`;
  7258. } else {
  7259. sanctuaryButton.style.color = '';
  7260. sanctuaryButton.title = I18N('SANCTUARY_TITLE');
  7261. }
  7262. if (clanWarMyTries && !arePointsMax) {
  7263. clanWarButton.style.color = 'red';
  7264. clanWarButton.title = `${I18N('GUILD_WAR_TITLE')}\n${clanWarMyTries}${I18N('ATTEMPTS')}`;
  7265. } else {
  7266. clanWarButton.style.color = '';
  7267. clanWarButton.title = I18N('GUILD_WAR_TITLE');
  7268. }
  7269.  
  7270. if (titansLevel < 7 && titansStatus == 'battle') {
  7271. const partColor = Math.floor(125 * titansLevel / 7);
  7272. titansArenaButton.style.color = `rgb(255,${partColor},${partColor})`;
  7273. titansArenaButton.title = `${I18N('TITAN_ARENA_TITLE')}\n${titansLevel} ${I18N('LEVEL')}`;
  7274. } else {
  7275. titansArenaButton.style.color = '';
  7276. titansArenaButton.title = I18N('TITAN_ARENA_TITLE');
  7277. }
  7278.  
  7279. const imgPortal =
  7280. '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';
  7281.  
  7282. setProgress('<img src="' + imgPortal + '" style="height: 25px;position: relative;top: 5px;"> ' + `${portalSphere.amount} </br> ${I18N('GUILD_WAR')}: ${clanWarMyTries}`, true);
  7283. resolve();
  7284. });
  7285. }
  7286.  
  7287. async function getDailyBonus() {
  7288. const dailyBonusInfo = await Send(JSON.stringify({
  7289. calls: [{
  7290. name: "dailyBonusGetInfo",
  7291. args: {},
  7292. ident: "body"
  7293. }]
  7294. })).then(e => e.results[0].result.response);
  7295. const { availableToday, availableVip, currentDay } = dailyBonusInfo;
  7296.  
  7297. if (!availableToday) {
  7298. console.log('Уже собрано');
  7299. return;
  7300. }
  7301.  
  7302. const currentVipPoints = +userInfo.vipPoints;
  7303. const dailyBonusStat = lib.getData('dailyBonusStatic');
  7304. const vipInfo = lib.getData('level').vip;
  7305. let currentVipLevel = 0;
  7306. for (let i in vipInfo) {
  7307. vipLvl = vipInfo[i];
  7308. if (currentVipPoints >= vipLvl.vipPoints) {
  7309. currentVipLevel = vipLvl.level;
  7310. }
  7311. }
  7312. const vipLevelDouble = dailyBonusStat[`${currentDay}_0_0`].vipLevelDouble;
  7313.  
  7314. const calls = [{
  7315. name: "dailyBonusFarm",
  7316. args: {
  7317. vip: availableVip && currentVipLevel >= vipLevelDouble ? 1 : 0
  7318. },
  7319. ident: "body"
  7320. }];
  7321.  
  7322. const result = await Send(JSON.stringify({ calls }));
  7323. if (result.error) {
  7324. console.error(result.error);
  7325. return;
  7326. }
  7327.  
  7328. const reward = result.results[0].result.response;
  7329. const type = Object.keys(reward).pop();
  7330. const itemId = Object.keys(reward[type]).pop();
  7331. const count = reward[type][itemId];
  7332. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  7333.  
  7334. console.log(`Ежедневная награда: Получено ${count} ${itemName}`, reward);
  7335. }
  7336.  
  7337. async function farmStamina(lootBoxId = 148) {
  7338. const lootBox = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"}]}')
  7339. .then(e => e.results[0].result.response.consumable[148]);
  7340.  
  7341. /** Добавить другие ящики */
  7342. /**
  7343. * 144 - медная шкатулка
  7344. * 145 - бронзовая шкатулка
  7345. * 148 - платиновая шкатулка
  7346. */
  7347. if (!lootBox) {
  7348. setProgress(I18N('NO_BOXES'), true);
  7349. return;
  7350. }
  7351.  
  7352. let maxFarmEnergy = getSaveVal('maxFarmEnergy', 100);
  7353. const result = await popup.confirm(I18N('OPEN_LOOTBOX', { lootBox }), [
  7354. { result: false, isClose: true },
  7355. { msg: I18N('BTN_YES'), result: true },
  7356. { msg: I18N('STAMINA'), isInput: true, default: maxFarmEnergy },
  7357. ]);
  7358. if (!+result) {
  7359. return;
  7360. }
  7361.  
  7362. if ((typeof result) !== 'boolean' && Number.parseInt(result)) {
  7363. maxFarmEnergy = +result;
  7364. setSaveVal('maxFarmEnergy', maxFarmEnergy);
  7365. } else {
  7366. maxFarmEnergy = 0;
  7367. }
  7368.  
  7369. let collectEnergy = 0;
  7370. for (let count = lootBox; count > 0; count--) {
  7371. const result = await Send('{"calls":[{"name":"consumableUseLootBox","args":{"libId":148,"amount":1},"ident":"body"}]}')
  7372. .then(e => e.results[0].result.response[0]);
  7373. if ('stamina' in result) {
  7374. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox} ${I18N('STAMINA')} +${result.stamina}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  7375. console.log(`${ I18N('STAMINA') } + ${ result.stamina }`);
  7376. if (!maxFarmEnergy) {
  7377. return;
  7378. }
  7379. collectEnergy += +result.stamina;
  7380. if (collectEnergy >= maxFarmEnergy) {
  7381. console.log(`${I18N('STAMINA')} + ${ collectEnergy }`);
  7382. setProgress(`${I18N('STAMINA')} + ${ collectEnergy }`, false);
  7383. return;
  7384. }
  7385. } else {
  7386. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  7387. console.log(result);
  7388. }
  7389. }
  7390.  
  7391. setProgress(I18N('BOXES_OVER'), true);
  7392. }
  7393.  
  7394. async function fillActive() {
  7395. const data = await Send(JSON.stringify({
  7396. calls: [{
  7397. name: "questGetAll",
  7398. args: {},
  7399. ident: "questGetAll"
  7400. }, {
  7401. name: "inventoryGet",
  7402. args: {},
  7403. ident: "inventoryGet"
  7404. }, {
  7405. name: "clanGetInfo",
  7406. args: {},
  7407. ident: "clanGetInfo"
  7408. }
  7409. ]
  7410. })).then(e => e.results.map(n => n.result.response));
  7411.  
  7412. const quests = data[0];
  7413. const inv = data[1];
  7414. const stat = data[2].stat;
  7415. const maxActive = 2000 - stat.todayItemsActivity;
  7416. if (maxActive <= 0) {
  7417. setProgress(I18N('NO_MORE_ACTIVITY'), true);
  7418. return;
  7419. }
  7420. let countGetActive = 0;
  7421. const quest = quests.find(e => e.id > 10046 && e.id < 10051);
  7422. if (quest) {
  7423. countGetActive = 1750 - quest.progress;
  7424. }
  7425. if (countGetActive <= 0) {
  7426. countGetActive = maxActive;
  7427. }
  7428. console.log(countGetActive);
  7429.  
  7430. countGetActive = +(await popup.confirm(I18N('EXCHANGE_ITEMS', { maxActive }), [
  7431. { result: false, isClose: true },
  7432. { msg: I18N('GET_ACTIVITY'), isInput: true, default: countGetActive.toString() },
  7433. ]));
  7434.  
  7435. if (!countGetActive) {
  7436. return;
  7437. }
  7438.  
  7439. if (countGetActive > maxActive) {
  7440. countGetActive = maxActive;
  7441. }
  7442.  
  7443. const items = lib.getData('inventoryItem');
  7444.  
  7445. let itemsInfo = [];
  7446. for (let type of ['gear', 'scroll']) {
  7447. for (let i in inv[type]) {
  7448. const v = items[type][i]?.enchantValue || 0;
  7449. itemsInfo.push({
  7450. id: i,
  7451. count: inv[type][i],
  7452. v,
  7453. type
  7454. })
  7455. }
  7456. const invType = 'fragment' + type.toLowerCase().charAt(0).toUpperCase() + type.slice(1);
  7457. for (let i in inv[invType]) {
  7458. const v = items[type][i]?.fragmentEnchantValue || 0;
  7459. itemsInfo.push({
  7460. id: i,
  7461. count: inv[invType][i],
  7462. v,
  7463. type: invType
  7464. })
  7465. }
  7466. }
  7467. itemsInfo = itemsInfo.filter(e => e.v < 4 && e.count > 200);
  7468. itemsInfo = itemsInfo.sort((a, b) => b.count - a.count);
  7469. console.log(itemsInfo);
  7470. const activeItem = itemsInfo.shift();
  7471. console.log(activeItem);
  7472. const countItem = Math.ceil(countGetActive / activeItem.v);
  7473. if (countItem > activeItem.count) {
  7474. setProgress(I18N('NOT_ENOUGH_ITEMS'), true);
  7475. console.log(activeItem);
  7476. return;
  7477. }
  7478.  
  7479. await Send(JSON.stringify({
  7480. calls: [{
  7481. name: "clanItemsForActivity",
  7482. args: {
  7483. items: {
  7484. [activeItem.type]: {
  7485. [activeItem.id]: countItem
  7486. }
  7487. }
  7488. },
  7489. ident: "body"
  7490. }]
  7491. })).then(e => {
  7492. /** TODO: Вывести потраченые предметы */
  7493. console.log(e);
  7494. setProgress(`${I18N('ACTIVITY_RECEIVED')}: ` + e.results[0].result.response, true);
  7495. });
  7496. }
  7497.  
  7498. async function buyHeroFragments() {
  7499. const result = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"},{"name":"shopGetAll","args":{},"ident":"shopGetAll"}]}')
  7500. .then(e => e.results.map(n => n.result.response));
  7501. const inv = result[0];
  7502. const shops = Object.values(result[1]).filter(shop => [4, 5, 6, 8, 9, 10, 17].includes(shop.id));
  7503. const calls = [];
  7504.  
  7505. for (let shop of shops) {
  7506. const slots = Object.values(shop.slots);
  7507. for (const slot of slots) {
  7508. /* Уже куплено */
  7509. if (slot.bought) {
  7510. continue;
  7511. }
  7512. /* Не душа героя */
  7513. if (!('fragmentHero' in slot.reward)) {
  7514. continue;
  7515. }
  7516. const coin = Object.keys(slot.cost).pop();
  7517. const coinId = Object.keys(slot.cost[coin]).pop();
  7518. const stock = inv[coin][coinId] || 0;
  7519. /* Не хватает на покупку */
  7520. if (slot.cost[coin][coinId] > stock) {
  7521. continue;
  7522. }
  7523. inv[coin][coinId] -= slot.cost[coin][coinId];
  7524. calls.push({
  7525. name: "shopBuy",
  7526. args: {
  7527. shopId: shop.id,
  7528. slot: slot.id,
  7529. cost: slot.cost,
  7530. reward: slot.reward,
  7531. },
  7532. ident: `shopBuy_${shop.id}_${slot.id}`,
  7533. })
  7534. }
  7535. }
  7536.  
  7537. if (!calls.length) {
  7538. setProgress(I18N('NO_PURCHASABLE_HERO_SOULS'), true);
  7539. return;
  7540. }
  7541.  
  7542. const bought = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  7543. if (!bought) {
  7544. console.log('что-то пошло не так')
  7545. return;
  7546. }
  7547.  
  7548. let countHeroSouls = 0;
  7549. for (const buy of bought) {
  7550. countHeroSouls += +Object.values(Object.values(buy).pop()).pop();
  7551. }
  7552. console.log(countHeroSouls, bought, calls);
  7553. setProgress(I18N('PURCHASED_HERO_SOULS', { countHeroSouls }), true);
  7554. }
  7555.  
  7556. /** Открыть платные сундуки в Запределье за 90 */
  7557. async function bossOpenChestPay() {
  7558. const info = await Send(
  7559. '{"calls":[{"name":"userGetInfo","args":{},"ident":"userGetInfo"},{"name":"bossGetAll","args":{},"ident":"bossGetAll"}]}'
  7560. ).then((e) => e.results.map((n) => n.result.response));
  7561.  
  7562. const user = info[0];
  7563. const boses = info[1];
  7564.  
  7565. const imgEmerald =
  7566. "<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='>";
  7567. const currentStarMoney = user.starMoney;
  7568. if (currentStarMoney < 540) {
  7569. setProgress(I18N('NOT_ENOUGH_EMERALDS_540', { currentStarMoney, imgEmerald }), true);
  7570. return;
  7571. }
  7572. //
  7573. const buttons = [{ result: false, isClose: true }];
  7574.  
  7575. if (currentStarMoney >= 540) {
  7576. buttons.push({
  7577. msg: I18N('BUY_OUTLAND_BTN', { count: 9, countEmerald: 540, imgEmerald }),
  7578. result: [90, 90, 0]
  7579. });
  7580. }
  7581.  
  7582. if (currentStarMoney >= 1740) {
  7583. buttons.push({
  7584. msg: I18N('BUY_OUTLAND_BTN', { count: 18, countEmerald: 1740, imgEmerald }),
  7585. result: [90, 90, 0, 200, 200, 0]
  7586. });
  7587. }
  7588.  
  7589. const answer = await popup.confirm(`<div style="margin-bottom: 15px;">${I18N('BUY_OUTLAND')}</div>`, buttons);
  7590.  
  7591. if (!answer) {
  7592. return;
  7593. }
  7594.  
  7595. const calls = [];
  7596.  
  7597. let n = 0;
  7598. const amount = 1;
  7599. for (let boss of boses) {
  7600. const bossId = boss.id;
  7601. if (boss.chestNum != 2) {
  7602. continue;
  7603. }
  7604. for (const starmoney of answer) {
  7605. calls.push({
  7606. name: 'bossOpenChest',
  7607. args: {
  7608. bossId,
  7609. amount,
  7610. starmoney,
  7611. },
  7612. ident: 'bossOpenChest_' + ++n,
  7613. });
  7614. }
  7615. }
  7616.  
  7617. if (!calls.length) {
  7618. setProgress(I18N('CHESTS_NOT_AVAILABLE'), true);
  7619. return;
  7620. }
  7621.  
  7622. const result = await Send(JSON.stringify({ calls }));
  7623. console.log(result);
  7624. if (result?.results) {
  7625. setProgress(`${I18N('OUTLAND_CHESTS_RECEIVED')}: ` + result.results.length, true);
  7626. } else {
  7627. setProgress(I18N('CHESTS_NOT_AVAILABLE'), true);
  7628. }
  7629. }
  7630.  
  7631. async function autoRaidAdventure() {
  7632. const calls = [
  7633. {
  7634. name: "userGetInfo",
  7635. args: {},
  7636. ident: "userGetInfo"
  7637. },
  7638. {
  7639. name: "adventure_raidGetInfo",
  7640. args: {},
  7641. ident: "adventure_raidGetInfo"
  7642. }
  7643. ];
  7644. const result = await Send(JSON.stringify({ calls }))
  7645. .then(e => e.results.map(n => n.result.response));
  7646.  
  7647. const portalSphere = result[0].refillable.find(n => n.id == 45);
  7648. const adventureRaid = Object.entries(result[1].raid).filter(e => e[1]).pop()
  7649. const adventureId = adventureRaid ? adventureRaid[0] : 0;
  7650.  
  7651. if (!portalSphere.amount || !adventureId) {
  7652. setProgress(I18N('RAID_NOT_AVAILABLE'), true);
  7653. return;
  7654. }
  7655.  
  7656. const countRaid = +(await popup.confirm(I18N('RAID_ADVENTURE', { adventureId }), [
  7657. { result: false, isClose: true },
  7658. { msg: I18N('RAID'), isInput: true, default: portalSphere.amount },
  7659. ]));
  7660.  
  7661. if (!countRaid) {
  7662. return;
  7663. }
  7664.  
  7665. if (countRaid > portalSphere.amount) {
  7666. countRaid = portalSphere.amount;
  7667. }
  7668.  
  7669. const resultRaid = await Send(JSON.stringify({
  7670. calls: [...Array(countRaid)].map((e, i) => ({
  7671. name: "adventure_raid",
  7672. args: {
  7673. adventureId
  7674. },
  7675. ident: `body_${i}`
  7676. }))
  7677. })).then(e => e.results.map(n => n.result.response));
  7678.  
  7679. if (!resultRaid.length) {
  7680. console.log(resultRaid);
  7681. setProgress(I18N('SOMETHING_WENT_WRONG'), true);
  7682. return;
  7683. }
  7684.  
  7685. console.log(resultRaid, adventureId, portalSphere.amount);
  7686. setProgress(I18N('ADVENTURE_COMPLETED', { adventureId, times: resultRaid.length }), true);
  7687. }
  7688.  
  7689. /** Вывести всю клановую статистику в консоль браузера */
  7690. async function clanStatistic() {
  7691. const copy = function (text) {
  7692. const copyTextarea = document.createElement("textarea");
  7693. copyTextarea.style.opacity = "0";
  7694. copyTextarea.textContent = text;
  7695. document.body.appendChild(copyTextarea);
  7696. copyTextarea.select();
  7697. document.execCommand("copy");
  7698. document.body.removeChild(copyTextarea);
  7699. delete copyTextarea;
  7700. }
  7701. const calls = [
  7702. { name: "clanGetInfo", args: {}, ident: "clanGetInfo" },
  7703. { name: "clanGetWeeklyStat", args: {}, ident: "clanGetWeeklyStat" },
  7704. { name: "clanGetLog", args: {}, ident: "clanGetLog" },
  7705. ];
  7706.  
  7707. const result = await Send(JSON.stringify({ calls }));
  7708.  
  7709. const dataClanInfo = result.results[0].result.response;
  7710. const dataClanStat = result.results[1].result.response;
  7711. const dataClanLog = result.results[2].result.response;
  7712.  
  7713. const membersStat = {};
  7714. for (let i = 0; i < dataClanStat.stat.length; i++) {
  7715. membersStat[dataClanStat.stat[i].id] = dataClanStat.stat[i];
  7716. }
  7717.  
  7718. const joinStat = {};
  7719. historyLog = dataClanLog.history;
  7720. for (let j in historyLog) {
  7721. his = historyLog[j];
  7722. if (his.event == 'join') {
  7723. joinStat[his.userId] = his.ctime;
  7724. }
  7725. }
  7726.  
  7727. const infoArr = [];
  7728. const members = dataClanInfo.clan.members;
  7729. for (let n in members) {
  7730. var member = [
  7731. n,
  7732. members[n].name,
  7733. members[n].level,
  7734. dataClanInfo.clan.warriors.includes(+n) ? 1 : 0,
  7735. (new Date(members[n].lastLoginTime * 1000)).toLocaleString().replace(',', ''),
  7736. joinStat[n] ? (new Date(joinStat[n] * 1000)).toLocaleString().replace(',', '') : '',
  7737. membersStat[n].activity.reverse().join('\t'),
  7738. membersStat[n].adventureStat.reverse().join('\t'),
  7739. membersStat[n].clanGifts.reverse().join('\t'),
  7740. membersStat[n].clanWarStat.reverse().join('\t'),
  7741. membersStat[n].dungeonActivity.reverse().join('\t'),
  7742. ];
  7743. infoArr.push(member);
  7744. }
  7745. const info = infoArr.sort((a, b) => (b[2] - a[2])).map((e) => e.join('\t')).join('\n');
  7746. console.log(info);
  7747. copy(info);
  7748. setProgress(I18N('CLAN_STAT_COPY'), true);
  7749. }
  7750.  
  7751. async function buyInStoreForGold() {
  7752. const result = await Send('{"calls":[{"name":"shopGetAll","args":{},"ident":"body"},{"name":"userGetInfo","args":{},"ident":"userGetInfo"}]}').then(e => e.results.map(n => n.result.response));
  7753. const shops = result[0];
  7754. const user = result[1];
  7755. let gold = user.gold;
  7756. const calls = [];
  7757. if (shops[17]) {
  7758. const slots = shops[17].slots;
  7759. for (let i = 1; i <= 2; i++) {
  7760. if (!slots[i].bought) {
  7761. const costGold = slots[i].cost.gold;
  7762. if ((gold - costGold) < 0) {
  7763. continue;
  7764. }
  7765. gold -= costGold;
  7766. calls.push({
  7767. name: "shopBuy",
  7768. args: {
  7769. shopId: 17,
  7770. slot: i,
  7771. cost: slots[i].cost,
  7772. reward: slots[i].reward,
  7773. },
  7774. ident: 'body_' + i,
  7775. })
  7776. }
  7777. }
  7778. }
  7779. const slots = shops[1].slots;
  7780. for (let i = 4; i <= 6; i++) {
  7781. if (!slots[i].bought && slots[i]?.cost?.gold) {
  7782. const costGold = slots[i].cost.gold;
  7783. if ((gold - costGold) < 0) {
  7784. continue;
  7785. }
  7786. gold -= costGold;
  7787. calls.push({
  7788. name: "shopBuy",
  7789. args: {
  7790. shopId: 1,
  7791. slot: i,
  7792. cost: slots[i].cost,
  7793. reward: slots[i].reward,
  7794. },
  7795. ident: 'body_' + i,
  7796. })
  7797. }
  7798. }
  7799.  
  7800. if (!calls.length) {
  7801. setProgress(I18N('NOTHING_BUY'), true);
  7802. return;
  7803. }
  7804.  
  7805. const resultBuy = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  7806. console.log(resultBuy);
  7807. const countBuy = resultBuy.length;
  7808. setProgress(I18N('LOTS_BOUGHT', { countBuy }), true);
  7809. }
  7810.  
  7811. function rewardsAndMailFarm() {
  7812. return new Promise(function (resolve, reject) {
  7813. let questGetAllCall = {
  7814. calls: [{
  7815. name: "questGetAll",
  7816. args: {},
  7817. ident: "questGetAll"
  7818. }, {
  7819. name: "mailGetAll",
  7820. args: {},
  7821. ident: "mailGetAll"
  7822. }]
  7823. }
  7824. send(JSON.stringify(questGetAllCall), function (data) {
  7825. if (!data) return;
  7826. const questGetAll = data.results[0].result.response.filter((e) => e.state == 2);
  7827. const questBattlePass = lib.getData('quest').battlePass;
  7828. const questChainBPass = lib.getData('battlePass').questChain;
  7829.  
  7830. const questAllFarmCall = {
  7831. calls: [],
  7832. };
  7833. const questIds = [];
  7834. for (let quest of questGetAll) {
  7835. if (quest.id >= 2001e4) {
  7836. continue;
  7837. }
  7838. if (quest.id > 1e6 && quest.id < 2e7) {
  7839. const questInfo = questBattlePass[quest.id];
  7840. const chain = questChainBPass[questInfo.chain];
  7841. if (chain.requirement?.battlePassTicket) {
  7842. continue;
  7843. }
  7844. }
  7845. if (quest.id >= 2e7) {
  7846. questIds.push(quest.id);
  7847. continue;
  7848. }
  7849. questAllFarmCall.calls.push({
  7850. name: 'questFarm',
  7851. args: {
  7852. questId: quest.id,
  7853. },
  7854. ident: `questFarm_${quest.id}`,
  7855. });
  7856. }
  7857.  
  7858. if (questIds.length) {
  7859. questAllFarmCall.calls.push({
  7860. name: 'quest_questsFarm',
  7861. args: { questIds },
  7862. ident: 'quest_questsFarm',
  7863. });
  7864. }
  7865.  
  7866. let letters = data?.results[1]?.result?.response?.letters;
  7867. letterIds = lettersFilter(letters);
  7868.  
  7869. if (letterIds.length) {
  7870. questAllFarmCall.calls.push({
  7871. name: 'mailFarm',
  7872. args: { letterIds },
  7873. ident: 'mailFarm',
  7874. });
  7875. }
  7876.  
  7877. if (!questAllFarmCall.calls.length) {
  7878. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  7879. resolve();
  7880. return;
  7881. }
  7882.  
  7883. send(JSON.stringify(questAllFarmCall), async function (res) {
  7884. let countQuests = 0;
  7885. let countMail = 0;
  7886. let questsIds = [];
  7887. for (let call of res.results) {
  7888. if (call.ident.includes('questFarm')) {
  7889. countQuests++;
  7890. } else if (call.ident.includes('questsFarm')) {
  7891. countQuests += Object.keys(call.result.response).length;
  7892. } else if (call.ident.includes('mailFarm')) {
  7893. countMail = Object.keys(call.result.response).length;
  7894. }
  7895.  
  7896. const newQuests = call.result.newQuests;
  7897. if (newQuests) {
  7898. for (let quest of newQuests) {
  7899. if ((quest.id < 1e6 || (quest.id >= 2e7 && quest.id < 2001e4)) && quest.state == 2) {
  7900. questsIds.push(quest.id);
  7901. }
  7902. }
  7903. }
  7904. }
  7905.  
  7906. while (questsIds.length) {
  7907. const questIds = [];
  7908. const calls = [];
  7909. for (let questId of questsIds) {
  7910. if (questId < 1e6) {
  7911. calls.push({
  7912. name: 'questFarm',
  7913. args: {
  7914. questId,
  7915. },
  7916. ident: `questFarm_${questId}`,
  7917. });
  7918. countQuests++;
  7919. } else if (questId >= 2e7 && questId < 2001e4) {
  7920. questIds.push(questId);
  7921. countQuests++;
  7922. }
  7923. }
  7924. calls.push({
  7925. name: 'quest_questsFarm',
  7926. args: { questIds },
  7927. ident: 'body',
  7928. });
  7929. const results = await Send({ calls }).then((e) => e.results.map((e) => e.result));
  7930. questsIds = [];
  7931. for (const result of results) {
  7932. const newQuests = result.newQuests;
  7933. if (newQuests) {
  7934. for (let quest of newQuests) {
  7935. if (quest.state == 2) {
  7936. questsIds.push(quest.id);
  7937. }
  7938. }
  7939. }
  7940. }
  7941. }
  7942.  
  7943. setProgress(I18N('COLLECT_REWARDS_AND_MAIL', { countQuests, countMail }), true);
  7944. resolve();
  7945. });
  7946. });
  7947. })
  7948. }
  7949.  
  7950. class epicBrawl {
  7951. timeout = null;
  7952. time = null;
  7953.  
  7954. constructor() {
  7955. if (epicBrawl.inst) {
  7956. return epicBrawl.inst;
  7957. }
  7958. epicBrawl.inst = this;
  7959. return this;
  7960. }
  7961.  
  7962. runTimeout(func, timeDiff) {
  7963. const worker = new Worker(URL.createObjectURL(new Blob([`
  7964. self.onmessage = function(e) {
  7965. const timeDiff = e.data;
  7966.  
  7967. if (timeDiff > 0) {
  7968. setTimeout(() => {
  7969. self.postMessage(1);
  7970. self.close();
  7971. }, timeDiff);
  7972. }
  7973. };
  7974. `])));
  7975. worker.postMessage(timeDiff);
  7976. worker.onmessage = () => {
  7977. func();
  7978. };
  7979. return true;
  7980. }
  7981.  
  7982. timeDiff(date1, date2) {
  7983. const date1Obj = new Date(date1);
  7984. const date2Obj = new Date(date2);
  7985.  
  7986. const timeDiff = Math.abs(date2Obj - date1Obj);
  7987.  
  7988. const totalSeconds = timeDiff / 1000;
  7989. const minutes = Math.floor(totalSeconds / 60);
  7990. const seconds = Math.floor(totalSeconds % 60);
  7991.  
  7992. const formattedMinutes = String(minutes).padStart(2, '0');
  7993. const formattedSeconds = String(seconds).padStart(2, '0');
  7994.  
  7995. return `${formattedMinutes}:${formattedSeconds}`;
  7996. }
  7997.  
  7998. check() {
  7999. console.log(new Date(this.time))
  8000. if (Date.now() > this.time) {
  8001. this.timeout = null;
  8002. this.start()
  8003. return;
  8004. }
  8005. this.timeout = this.runTimeout(() => this.check(), 6e4);
  8006. return this.timeDiff(this.time, Date.now())
  8007. }
  8008.  
  8009. async start() {
  8010. if (this.timeout) {
  8011. const time = this.timeDiff(this.time, Date.now());
  8012. console.log(new Date(this.time))
  8013. setProgress(I18N('TIMER_ALREADY', { time }), false, hideProgress);
  8014. return;
  8015. }
  8016. setProgress(I18N('EPIC_BRAWL'), false, hideProgress);
  8017. 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));
  8018. const refill = teamInfo[2].refillable.find(n => n.id == 52)
  8019. this.time = (refill.lastRefill + 3600) * 1000
  8020. const attempts = refill.amount;
  8021. if (!attempts) {
  8022. console.log(new Date(this.time));
  8023. const time = this.check();
  8024. setProgress(I18N('NO_ATTEMPTS_TIMER_START', { time }), false, hideProgress);
  8025. return;
  8026. }
  8027.  
  8028. if (!teamInfo[0].epic_brawl) {
  8029. setProgress(I18N('NO_HEROES_PACK'), false, hideProgress);
  8030. return;
  8031. }
  8032.  
  8033. const args = {
  8034. heroes: teamInfo[0].epic_brawl.filter(e => e < 1000),
  8035. pet: teamInfo[0].epic_brawl.filter(e => e > 6000).pop(),
  8036. favor: teamInfo[1].epic_brawl,
  8037. }
  8038.  
  8039. let wins = 0;
  8040. let coins = 0;
  8041. let streak = { progress: 0, nextStage: 0 };
  8042. for (let i = attempts; i > 0; i--) {
  8043. const info = await Send(JSON.stringify({
  8044. calls: [
  8045. { name: "epicBrawl_getEnemy", args: {}, ident: "epicBrawl_getEnemy" }, { name: "epicBrawl_startBattle", args, ident: "epicBrawl_startBattle" }
  8046. ]
  8047. })).then(e => e.results.map(n => n.result.response));
  8048.  
  8049. const { progress, result } = await Calc(info[1].battle);
  8050. 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));
  8051.  
  8052. const resultInfo = endResult[0].result;
  8053. streak = endResult[1];
  8054.  
  8055. wins += resultInfo.win;
  8056. coins += resultInfo.reward ? resultInfo.reward.coin[39] : 0;
  8057.  
  8058. console.log(endResult[0].result)
  8059. if (endResult[1].progress == endResult[1].nextStage) {
  8060. const farm = await Send('{"calls":[{"name":"epicBrawl_farmWinStreak","args":{},"ident":"body"}]}').then(e => e.results[0].result.response);
  8061. coins += farm.coin[39];
  8062. }
  8063.  
  8064. setProgress(I18N('EPIC_BRAWL_RESULT', {
  8065. i, wins, attempts, coins,
  8066. progress: streak.progress,
  8067. nextStage: streak.nextStage,
  8068. end: '',
  8069. }), false, hideProgress);
  8070. }
  8071.  
  8072. console.log(new Date(this.time));
  8073. const time = this.check();
  8074. setProgress(I18N('EPIC_BRAWL_RESULT', {
  8075. wins, attempts, coins,
  8076. i: '',
  8077. progress: streak.progress,
  8078. nextStage: streak.nextStage,
  8079. end: I18N('ATTEMPT_ENDED', { time }),
  8080. }), false, hideProgress);
  8081. }
  8082. }
  8083.  
  8084. function countdownTimer(seconds, message) {
  8085. message = message || I18N('TIMER');
  8086. const stopTimer = Date.now() + seconds * 1e3
  8087. return new Promise(resolve => {
  8088. const interval = setInterval(async () => {
  8089. const now = Date.now();
  8090. setProgress(`${message} ${((stopTimer - now) / 1000).toFixed(2)}`, false);
  8091. if (now > stopTimer) {
  8092. clearInterval(interval);
  8093. setProgress('', 1);
  8094. resolve();
  8095. }
  8096. }, 100);
  8097. });
  8098. }
  8099.  
  8100. /** Набить килов в горниле душк */
  8101. async function bossRatingEventSouls() {
  8102. const data = await Send({
  8103. calls: [
  8104. { name: "heroGetAll", args: {}, ident: "teamGetAll" },
  8105. { name: "offerGetAll", args: {}, ident: "offerGetAll" },
  8106. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  8107. ]
  8108. });
  8109. const bossEventInfo = data.results[1].result.response.find(e => e.offerType == "bossEvent");
  8110. if (!bossEventInfo) {
  8111. setProgress('Эвент завершен', true);
  8112. return;
  8113. }
  8114.  
  8115. if (bossEventInfo.progress.score > 250) {
  8116. setProgress('Уже убито больше 250 врагов');
  8117. rewardBossRatingEventSouls();
  8118. return;
  8119. }
  8120. const availablePets = Object.values(data.results[2].result.response).map(e => e.id);
  8121. const heroGetAllList = data.results[0].result.response;
  8122. const usedHeroes = bossEventInfo.progress.usedHeroes;
  8123. const heroList = [];
  8124.  
  8125. for (let heroId in heroGetAllList) {
  8126. let hero = heroGetAllList[heroId];
  8127. if (usedHeroes.includes(hero.id)) {
  8128. continue;
  8129. }
  8130. heroList.push(hero.id);
  8131. }
  8132.  
  8133. if (!heroList.length) {
  8134. setProgress('Нет героев', true);
  8135. return;
  8136. }
  8137.  
  8138. const pet = availablePets.includes(6005) ? 6005 : availablePets[Math.floor(Math.random() * availablePets.length)];
  8139. const petLib = lib.getData('pet');
  8140. let count = 1;
  8141.  
  8142. for (const heroId of heroList) {
  8143. const args = {
  8144. heroes: [heroId],
  8145. pet
  8146. }
  8147. /** Поиск питомца для героя */
  8148. for (const petId of availablePets) {
  8149. if (petLib[petId].favorHeroes.includes(heroId)) {
  8150. args.favor = {
  8151. [heroId]: petId
  8152. }
  8153. break;
  8154. }
  8155. }
  8156.  
  8157. const calls = [{
  8158. name: "bossRatingEvent_startBattle",
  8159. args,
  8160. ident: "body"
  8161. }, {
  8162. name: "offerGetAll",
  8163. args: {},
  8164. ident: "offerGetAll"
  8165. }];
  8166.  
  8167. const res = await Send({ calls });
  8168. count++;
  8169.  
  8170. if ('error' in res) {
  8171. console.error(res.error);
  8172. setProgress('Перезагрузите игру и попробуйте позже', true);
  8173. return;
  8174. }
  8175.  
  8176. const eventInfo = res.results[1].result.response.find(e => e.offerType == "bossEvent");
  8177. if (eventInfo.progress.score > 250) {
  8178. break;
  8179. }
  8180. setProgress('Количество убитых врагов: ' + eventInfo.progress.score + '<br>Использовано ' + count + ' героев');
  8181. }
  8182.  
  8183. rewardBossRatingEventSouls();
  8184. }
  8185. /** Сбор награды из Горнила Душ */
  8186. async function rewardBossRatingEventSouls() {
  8187. const data = await Send({
  8188. calls: [
  8189. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  8190. ]
  8191. });
  8192.  
  8193. const bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  8194. if (!bossEventInfo) {
  8195. setProgress('Эвент завершен', true);
  8196. return;
  8197. }
  8198.  
  8199. const farmedChests = bossEventInfo.progress.farmedChests;
  8200. const score = bossEventInfo.progress.score;
  8201. // setProgress('Количество убитых врагов: ' + score);
  8202. const revard = bossEventInfo.reward;
  8203. const calls = [];
  8204.  
  8205. let count = 0;
  8206. for (let i = 1; i < 10; i++) {
  8207. if (farmedChests.includes(i)) {
  8208. continue;
  8209. }
  8210. if (score < revard[i].score) {
  8211. break;
  8212. }
  8213. calls.push({
  8214. name: "bossRatingEvent_getReward",
  8215. args: {
  8216. rewardId: i
  8217. },
  8218. ident: "body_" + i
  8219. });
  8220. count++;
  8221. }
  8222. if (!count) {
  8223. setProgress('Нечего собирать', true);
  8224. return;
  8225. }
  8226.  
  8227. Send({ calls }).then(e => {
  8228. console.log(e);
  8229. setProgress('Собрано ' + e?.results?.length + ' наград', true);
  8230. })
  8231. }
  8232. /**
  8233. * Spin the Seer
  8234. *
  8235. * Покрутить провидца
  8236. */
  8237. async function rollAscension() {
  8238. const refillable = await Send({calls:[
  8239. {
  8240. name:"userGetInfo",
  8241. args:{},
  8242. ident:"userGetInfo"
  8243. }
  8244. ]}).then(e => e.results[0].result.response.refillable);
  8245. const i47 = refillable.find(i => i.id == 47);
  8246. if (i47?.amount) {
  8247. await Send({ calls: [{ name: "ascensionChest_open", args: { paid: false, amount: 1 }, ident: "body" }] });
  8248. setProgress(I18N('DONE'), true);
  8249. } else {
  8250. setProgress(I18N('NOT_ENOUGH_AP'), true);
  8251. }
  8252. }
  8253.  
  8254. /**
  8255. * Collect gifts for the New Year
  8256. *
  8257. * Собрать подарки на новый год
  8258. */
  8259. function getGiftNewYear() {
  8260. Send({ calls: [{ name: "newYearGiftGet", args: { type: 0 }, ident: "body" }] }).then(e => {
  8261. const gifts = e.results[0].result.response.gifts;
  8262. const calls = gifts.filter(e => e.opened == 0).map(e => ({
  8263. name: "newYearGiftOpen",
  8264. args: {
  8265. giftId: e.id
  8266. },
  8267. ident: `body_${e.id}`
  8268. }));
  8269. if (!calls.length) {
  8270. setProgress(I18N('NY_NO_GIFTS'), 5000);
  8271. return;
  8272. }
  8273. Send({ calls }).then(e => {
  8274. console.log(e.results)
  8275. const msg = I18N('NY_GIFTS_COLLECTED', { count: e.results.length });
  8276. console.log(msg);
  8277. setProgress(msg, 5000);
  8278. });
  8279. })
  8280. }
  8281.  
  8282. async function updateArtifacts() {
  8283. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  8284. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  8285. { result: false, isClose: true }
  8286. ]);
  8287. if (!count) {
  8288. return;
  8289. }
  8290. const quest = new questRun;
  8291. await quest.autoInit();
  8292. const heroes = Object.values(quest.questInfo['heroGetAll']);
  8293. const inventory = quest.questInfo['inventoryGet'];
  8294. const calls = [];
  8295. for (let i = count; i > 0; i--) {
  8296. const upArtifact = quest.getUpgradeArtifact();
  8297. if (!upArtifact.heroId) {
  8298. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  8299. { msg: I18N('YES'), result: true },
  8300. { result: false, isClose: true }
  8301. ])) {
  8302. break;
  8303. } else {
  8304. return;
  8305. }
  8306. }
  8307. const hero = heroes.find(e => e.id == upArtifact.heroId);
  8308. hero.artifacts[upArtifact.slotId].level++;
  8309. inventory[upArtifact.costCurrency][upArtifact.costId] -= upArtifact.costValue;
  8310. calls.push({
  8311. name: "heroArtifactLevelUp",
  8312. args: {
  8313. heroId: upArtifact.heroId,
  8314. slotId: upArtifact.slotId
  8315. },
  8316. ident: `heroArtifactLevelUp_${i}`
  8317. });
  8318. }
  8319.  
  8320. if (!calls.length) {
  8321. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8322. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8323. return;
  8324. }
  8325.  
  8326. await Send(JSON.stringify({ calls })).then(e => {
  8327. if ('error' in e) {
  8328. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8329. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8330. } else {
  8331. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  8332. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  8333. }
  8334. });
  8335. }
  8336.  
  8337. window.sign = a => {
  8338. const i = this['\x78\x79\x7a'];
  8339. 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'))
  8340. }
  8341.  
  8342. async function updateSkins() {
  8343. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  8344. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  8345. { result: false, isClose: true }
  8346. ]);
  8347. if (!count) {
  8348. return;
  8349. }
  8350.  
  8351. const quest = new questRun;
  8352. await quest.autoInit();
  8353. const heroes = Object.values(quest.questInfo['heroGetAll']);
  8354. const inventory = quest.questInfo['inventoryGet'];
  8355. const calls = [];
  8356. for (let i = count; i > 0; i--) {
  8357. const upSkin = quest.getUpgradeSkin();
  8358. if (!upSkin.heroId) {
  8359. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  8360. { msg: I18N('YES'), result: true },
  8361. { result: false, isClose: true }
  8362. ])) {
  8363. break;
  8364. } else {
  8365. return;
  8366. }
  8367. }
  8368. const hero = heroes.find(e => e.id == upSkin.heroId);
  8369. hero.skins[upSkin.skinId]++;
  8370. inventory[upSkin.costCurrency][upSkin.costCurrencyId] -= upSkin.cost;
  8371. calls.push({
  8372. name: "heroSkinUpgrade",
  8373. args: {
  8374. heroId: upSkin.heroId,
  8375. skinId: upSkin.skinId
  8376. },
  8377. ident: `heroSkinUpgrade_${i}`
  8378. })
  8379. }
  8380.  
  8381. if (!calls.length) {
  8382. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8383. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8384. return;
  8385. }
  8386.  
  8387. await Send(JSON.stringify({ calls })).then(e => {
  8388. if ('error' in e) {
  8389. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8390. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8391. } else {
  8392. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  8393. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  8394. }
  8395. });
  8396. }
  8397.  
  8398. function getQuestionInfo(img, nameOnly = false) {
  8399. const libHeroes = Object.values(lib.data.hero);
  8400. const parts = img.split(':');
  8401. const id = parts[1];
  8402. switch (parts[0]) {
  8403. case 'titanArtifact_id':
  8404. return cheats.translate("LIB_TITAN_ARTIFACT_NAME_" + id);
  8405. case 'titan':
  8406. return cheats.translate("LIB_HERO_NAME_" + id);
  8407. case 'skill':
  8408. return cheats.translate("LIB_SKILL_" + id);
  8409. case 'inventoryItem_gear':
  8410. return cheats.translate("LIB_GEAR_NAME_" + id);
  8411. case 'inventoryItem_coin':
  8412. return cheats.translate("LIB_COIN_NAME_" + id);
  8413. case 'artifact':
  8414. if (nameOnly) {
  8415. return cheats.translate("LIB_ARTIFACT_NAME_" + id);
  8416. }
  8417. heroes = libHeroes.filter(h => h.id < 100 && h.artifacts.includes(+id));
  8418. return {
  8419. /** Как называется этот артефакт? */
  8420. name: cheats.translate("LIB_ARTIFACT_NAME_" + id),
  8421. /** Какому герою принадлежит этот артефакт? */
  8422. heroes: heroes.map(h => cheats.translate("LIB_HERO_NAME_" + h.id))
  8423. };
  8424. case 'hero':
  8425. if (nameOnly) {
  8426. return cheats.translate("LIB_HERO_NAME_" + id);
  8427. }
  8428. artifacts = lib.data.hero[id].artifacts;
  8429. return {
  8430. /** Как зовут этого героя? */
  8431. name: cheats.translate("LIB_HERO_NAME_" + id),
  8432. /** Какой артефакт принадлежит этому герою? */
  8433. artifact: artifacts.map(a => cheats.translate("LIB_ARTIFACT_NAME_" + a))
  8434. };
  8435. }
  8436. }
  8437.  
  8438. function hintQuest(quest) {
  8439. const result = {};
  8440. if (quest?.questionIcon) {
  8441. const info = getQuestionInfo(quest.questionIcon);
  8442. if (info?.heroes) {
  8443. /** Какому герою принадлежит этот артефакт? */
  8444. result.answer = quest.answers.filter(e => info.heroes.includes(e.answerText.slice(1)));
  8445. }
  8446. if (info?.artifact) {
  8447. /** Какой артефакт принадлежит этому герою? */
  8448. result.answer = quest.answers.filter(e => info.artifact.includes(e.answerText.slice(1)));
  8449. }
  8450. if (typeof info == 'string') {
  8451. result.info = { name: info };
  8452. } else {
  8453. result.info = info;
  8454. }
  8455. }
  8456.  
  8457. if (quest.answers[0]?.answerIcon) {
  8458. result.answer = quest.answers.filter(e => quest.question.includes(getQuestionInfo(e.answerIcon, true)))
  8459. }
  8460.  
  8461. if ((!result?.answer || !result.answer.length) && !result.info?.name) {
  8462. return false;
  8463. }
  8464.  
  8465. let resultText = '';
  8466. if (result?.info) {
  8467. resultText += I18N('PICTURE') + result.info.name;
  8468. }
  8469. console.log(result);
  8470. if (result?.answer && result.answer.length) {
  8471. resultText += I18N('ANSWER') + result.answer[0].id + (!result.answer[0].answerIcon ? ' - ' + result.answer[0].answerText : '');
  8472. }
  8473.  
  8474. return resultText;
  8475. }
  8476.  
  8477. /**
  8478. * Attack of the minions of Asgard
  8479. *
  8480. * Атака прислужников Асгарда
  8481. */
  8482. function testRaidNodes() {
  8483. return new Promise((resolve, reject) => {
  8484. const tower = new executeRaidNodes(resolve, reject);
  8485. tower.start();
  8486. });
  8487. }
  8488.  
  8489. /**
  8490. * Attack of the minions of Asgard
  8491. *
  8492. * Атака прислужников Асгарда
  8493. */
  8494. function executeRaidNodes(resolve, reject) {
  8495. let raidData = {
  8496. teams: [],
  8497. favor: {},
  8498. nodes: [],
  8499. attempts: 0,
  8500. countExecuteBattles: 0,
  8501. cancelBattle: 0,
  8502. }
  8503.  
  8504. callsExecuteRaidNodes = {
  8505. calls: [{
  8506. name: "clanRaid_getInfo",
  8507. args: {},
  8508. ident: "clanRaid_getInfo"
  8509. }, {
  8510. name: "teamGetAll",
  8511. args: {},
  8512. ident: "teamGetAll"
  8513. }, {
  8514. name: "teamGetFavor",
  8515. args: {},
  8516. ident: "teamGetFavor"
  8517. }]
  8518. }
  8519.  
  8520. this.start = function () {
  8521. send(JSON.stringify(callsExecuteRaidNodes), startRaidNodes);
  8522. }
  8523.  
  8524. async function startRaidNodes(data) {
  8525. res = data.results;
  8526. clanRaidInfo = res[0].result.response;
  8527. teamGetAll = res[1].result.response;
  8528. teamGetFavor = res[2].result.response;
  8529.  
  8530. let index = 0;
  8531. let isNotFullPack = false;
  8532. for (let team of teamGetAll.clanRaid_nodes) {
  8533. if (team.length < 6) {
  8534. isNotFullPack = true;
  8535. }
  8536. raidData.teams.push({
  8537. data: {},
  8538. heroes: team.filter(id => id < 6000),
  8539. pet: team.filter(id => id >= 6000).pop(),
  8540. battleIndex: index++
  8541. });
  8542. }
  8543. raidData.favor = teamGetFavor.clanRaid_nodes;
  8544.  
  8545. if (isNotFullPack) {
  8546. if (await popup.confirm(I18N('MINIONS_WARNING'), [
  8547. { msg: I18N('BTN_NO'), result: true },
  8548. { msg: I18N('BTN_YES'), result: false },
  8549. ])) {
  8550. endRaidNodes('isNotFullPack');
  8551. return;
  8552. }
  8553. }
  8554.  
  8555. raidData.nodes = clanRaidInfo.nodes;
  8556. raidData.attempts = clanRaidInfo.attempts;
  8557. isCancalBattle = false;
  8558.  
  8559. checkNodes();
  8560. }
  8561.  
  8562. function getAttackNode() {
  8563. for (let nodeId in raidData.nodes) {
  8564. let node = raidData.nodes[nodeId];
  8565. let points = 0
  8566. for (team of node.teams) {
  8567. points += team.points;
  8568. }
  8569. let now = Date.now() / 1000;
  8570. if (!points && now > node.timestamps.start && now < node.timestamps.end) {
  8571. let countTeam = node.teams.length;
  8572. delete raidData.nodes[nodeId];
  8573. return {
  8574. nodeId,
  8575. countTeam
  8576. };
  8577. }
  8578. }
  8579. return null;
  8580. }
  8581.  
  8582. function checkNodes() {
  8583. setProgress(`${I18N('REMAINING_ATTEMPTS')}: ${raidData.attempts}`);
  8584. let nodeInfo = getAttackNode();
  8585. if (nodeInfo && raidData.attempts) {
  8586. startNodeBattles(nodeInfo);
  8587. return;
  8588. }
  8589.  
  8590. endRaidNodes('EndRaidNodes');
  8591. }
  8592.  
  8593. function startNodeBattles(nodeInfo) {
  8594. let {nodeId, countTeam} = nodeInfo;
  8595. let teams = raidData.teams.slice(0, countTeam);
  8596. let heroes = raidData.teams.map(e => e.heroes).flat();
  8597. let favor = {...raidData.favor};
  8598. for (let heroId in favor) {
  8599. if (!heroes.includes(+heroId)) {
  8600. delete favor[heroId];
  8601. }
  8602. }
  8603.  
  8604. let calls = [{
  8605. name: "clanRaid_startNodeBattles",
  8606. args: {
  8607. nodeId,
  8608. teams,
  8609. favor
  8610. },
  8611. ident: "body"
  8612. }];
  8613.  
  8614. send(JSON.stringify({calls}), resultNodeBattles);
  8615. }
  8616.  
  8617. function resultNodeBattles(e) {
  8618. if (e['error']) {
  8619. endRaidNodes('nodeBattlesError', e['error']);
  8620. return;
  8621. }
  8622.  
  8623. console.log(e);
  8624. let battles = e.results[0].result.response.battles;
  8625. let promises = [];
  8626. let battleIndex = 0;
  8627. for (let battle of battles) {
  8628. battle.battleIndex = battleIndex++;
  8629. promises.push(calcBattleResult(battle));
  8630. }
  8631.  
  8632. Promise.all(promises)
  8633. .then(results => {
  8634. const endResults = {};
  8635. let isAllWin = true;
  8636. for (let r of results) {
  8637. isAllWin &&= r.result.win;
  8638. }
  8639. if (!isAllWin) {
  8640. cancelEndNodeBattle(results[0]);
  8641. return;
  8642. }
  8643. raidData.countExecuteBattles = results.length;
  8644. let timeout = 500;
  8645. for (let r of results) {
  8646. setTimeout(endNodeBattle, timeout, r);
  8647. timeout += 500;
  8648. }
  8649. });
  8650. }
  8651. /**
  8652. * Returns the battle calculation promise
  8653. *
  8654. * Возвращает промис расчета боя
  8655. */
  8656. function calcBattleResult(battleData) {
  8657. return new Promise(function (resolve, reject) {
  8658. BattleCalc(battleData, "get_clanPvp", resolve);
  8659. });
  8660. }
  8661. /**
  8662. * Cancels the fight
  8663. *
  8664. * Отменяет бой
  8665. */
  8666. function cancelEndNodeBattle(r) {
  8667. const fixBattle = function (heroes) {
  8668. for (const ids in heroes) {
  8669. hero = heroes[ids];
  8670. hero.energy = random(1, 999);
  8671. if (hero.hp > 0) {
  8672. hero.hp = random(1, hero.hp);
  8673. }
  8674. }
  8675. }
  8676. fixBattle(r.progress[0].attackers.heroes);
  8677. fixBattle(r.progress[0].defenders.heroes);
  8678. endNodeBattle(r);
  8679. }
  8680. /**
  8681. * Ends the fight
  8682. *
  8683. * Завершает бой
  8684. */
  8685. function endNodeBattle(r) {
  8686. let nodeId = r.battleData.result.nodeId;
  8687. let battleIndex = r.battleData.battleIndex;
  8688. let calls = [{
  8689. name: "clanRaid_endNodeBattle",
  8690. args: {
  8691. nodeId,
  8692. battleIndex,
  8693. result: r.result,
  8694. progress: r.progress
  8695. },
  8696. ident: "body"
  8697. }]
  8698.  
  8699. SendRequest(JSON.stringify({calls}), battleResult);
  8700. }
  8701. /**
  8702. * Processing the results of the battle
  8703. *
  8704. * Обработка результатов боя
  8705. */
  8706. function battleResult(e) {
  8707. if (e['error']) {
  8708. endRaidNodes('missionEndError', e['error']);
  8709. return;
  8710. }
  8711. r = e.results[0].result.response;
  8712. if (r['error']) {
  8713. if (r.reason == "invalidBattle") {
  8714. raidData.cancelBattle++;
  8715. checkNodes();
  8716. } else {
  8717. endRaidNodes('missionEndError', e['error']);
  8718. }
  8719. return;
  8720. }
  8721.  
  8722. if (!(--raidData.countExecuteBattles)) {
  8723. raidData.attempts--;
  8724. checkNodes();
  8725. }
  8726. }
  8727. /**
  8728. * Completing a task
  8729. *
  8730. * Завершение задачи
  8731. */
  8732. function endRaidNodes(reason, info) {
  8733. isCancalBattle = true;
  8734. let textCancel = raidData.cancelBattle ? ` ${I18N('BATTLES_CANCELED')}: ${raidData.cancelBattle}` : '';
  8735. setProgress(`${I18N('MINION_RAID')} ${I18N('COMPLETED')}! ${textCancel}`, true);
  8736. console.log(reason, info);
  8737. resolve();
  8738. }
  8739. }
  8740.  
  8741. /**
  8742. * Asgard Boss Attack Replay
  8743. *
  8744. * Повтор атаки босса Асгарда
  8745. */
  8746. function testBossBattle() {
  8747. return new Promise((resolve, reject) => {
  8748. const bossBattle = new executeBossBattle(resolve, reject);
  8749. bossBattle.start(lastBossBattleInfo);
  8750. });
  8751. }
  8752.  
  8753. /**
  8754. * Asgard Boss Attack Replay
  8755. *
  8756. * Повтор атаки босса Асгарда
  8757. */
  8758. function executeBossBattle(resolve, reject) {
  8759.  
  8760. this.start = function (battleInfo) {
  8761. preCalcBattle(battleInfo);
  8762. }
  8763.  
  8764. function getBattleInfo(battle) {
  8765. return new Promise(function (resolve) {
  8766. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  8767. BattleCalc(battle, getBattleType(battle.type), e => {
  8768. let extra = e.progress[0].defenders.heroes[1].extra;
  8769. resolve(extra.damageTaken + extra.damageTakenNextLevel);
  8770. });
  8771. });
  8772. }
  8773.  
  8774. function preCalcBattle(battle) {
  8775. let actions = [];
  8776. const countTestBattle = getInput('countTestBattle');
  8777. for (let i = 0; i < countTestBattle; i++) {
  8778. actions.push(getBattleInfo(battle, true));
  8779. }
  8780. Promise.all(actions)
  8781. .then(resultPreCalcBattle);
  8782. }
  8783.  
  8784. async function resultPreCalcBattle(damages) {
  8785. let maxDamage = 0;
  8786. let minDamage = 1e10;
  8787. let avgDamage = 0;
  8788. for (let damage of damages) {
  8789. avgDamage += damage
  8790. if (damage > maxDamage) {
  8791. maxDamage = damage;
  8792. }
  8793. if (damage < minDamage) {
  8794. minDamage = damage;
  8795. }
  8796. }
  8797. avgDamage /= damages.length;
  8798. console.log(damages.map(e => e.toLocaleString()).join('\n'), avgDamage, maxDamage);
  8799.  
  8800. await popup.confirm(
  8801. `${I18N('ROUND_STAT')} ${damages.length} ${I18N('BATTLE')}:` +
  8802. `<br>${I18N('MINIMUM')}: ` + minDamage.toLocaleString() +
  8803. `<br>${I18N('MAXIMUM')}: ` + maxDamage.toLocaleString() +
  8804. `<br>${I18N('AVERAGE')}: ` + avgDamage.toLocaleString()
  8805. , [
  8806. { msg: I18N('BTN_OK'), result: 0},
  8807. ])
  8808. endBossBattle(I18N('BTN_CANCEL'));
  8809. }
  8810.  
  8811. /**
  8812. * Completing a task
  8813. *
  8814. * Завершение задачи
  8815. */
  8816. function endBossBattle(reason, info) {
  8817. console.log(reason, info);
  8818. resolve();
  8819. }
  8820. }
  8821.  
  8822. /**
  8823. * Auto-repeat attack
  8824. *
  8825. * Автоповтор атаки
  8826. */
  8827. function testAutoBattle() {
  8828. return new Promise((resolve, reject) => {
  8829. const bossBattle = new executeAutoBattle(resolve, reject);
  8830. bossBattle.start(lastBattleArg, lastBattleInfo);
  8831. });
  8832. }
  8833.  
  8834. /**
  8835. * Auto-repeat attack
  8836. *
  8837. * Автоповтор атаки
  8838. */
  8839. function executeAutoBattle(resolve, reject) {
  8840. let battleArg = {};
  8841. let countBattle = 0;
  8842. let countError = 0;
  8843. let findCoeff = 0;
  8844. let dataNotEeceived = 0;
  8845. 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>';
  8846. 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>';
  8847. 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>';
  8848.  
  8849. this.start = function (battleArgs, battleInfo) {
  8850. battleArg = battleArgs;
  8851. preCalcBattle(battleInfo);
  8852. }
  8853. /**
  8854. * Returns a promise for combat recalculation
  8855. *
  8856. * Возвращает промис для прерасчета боя
  8857. */
  8858. function getBattleInfo(battle) {
  8859. return new Promise(function (resolve) {
  8860. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  8861. Calc(battle).then(e => {
  8862. e.coeff = calcCoeff(e, 'defenders');
  8863. resolve(e);
  8864. });
  8865. });
  8866. }
  8867. /**
  8868. * Battle recalculation
  8869. *
  8870. * Прерасчет боя
  8871. */
  8872. function preCalcBattle(battle) {
  8873. let actions = [];
  8874. const countTestBattle = getInput('countTestBattle');
  8875. for (let i = 0; i < countTestBattle; i++) {
  8876. actions.push(getBattleInfo(battle));
  8877. }
  8878. Promise.all(actions)
  8879. .then(resultPreCalcBattle);
  8880. }
  8881. /**
  8882. * Processing the results of the battle recalculation
  8883. *
  8884. * Обработка результатов прерасчета боя
  8885. */
  8886. async function resultPreCalcBattle(results) {
  8887. let countWin = results.reduce((s, w) => w.result.win + s, 0);
  8888. setProgress(`${I18N('CHANCE_TO_WIN')} ${Math.floor(countWin / results.length * 100)}% (${results.length})`, false, hideProgress);
  8889. if (countWin > 0) {
  8890. isCancalBattle = false;
  8891. startBattle();
  8892. return;
  8893. }
  8894.  
  8895. let minCoeff = 100;
  8896. let maxCoeff = -100;
  8897. let avgCoeff = 0;
  8898. results.forEach(e => {
  8899. if (e.coeff < minCoeff) minCoeff = e.coeff;
  8900. if (e.coeff > maxCoeff) maxCoeff = e.coeff;
  8901. avgCoeff += e.coeff;
  8902. });
  8903. avgCoeff /= results.length;
  8904.  
  8905. if (nameFuncStartBattle == 'invasion_bossStart' ||
  8906. nameFuncStartBattle == 'bossAttack') {
  8907. const result = await popup.confirm(
  8908. I18N('BOSS_VICTORY_IMPOSSIBLE', { battles: results.length }), [
  8909. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  8910. { msg: I18N('BTN_DO_IT'), result: true },
  8911. ])
  8912. if (result) {
  8913. isCancalBattle = false;
  8914. startBattle();
  8915. return;
  8916. }
  8917. setProgress(I18N('NOT_THIS_TIME'), true);
  8918. endAutoBattle('invasion_bossStart');
  8919. return;
  8920. }
  8921.  
  8922. const result = await popup.confirm(
  8923. I18N('VICTORY_IMPOSSIBLE') +
  8924. `<br>${I18N('ROUND_STAT')} ${results.length} ${I18N('BATTLE')}:` +
  8925. `<br>${I18N('MINIMUM')}: ` + minCoeff.toLocaleString() +
  8926. `<br>${I18N('MAXIMUM')}: ` + maxCoeff.toLocaleString() +
  8927. `<br>${I18N('AVERAGE')}: ` + avgCoeff.toLocaleString() +
  8928. `<br>${I18N('FIND_COEFF')} ` + avgCoeff.toLocaleString(), [
  8929. { msg: I18N('BTN_CANCEL'), result: 0, isCancel: true },
  8930. { msg: I18N('BTN_GO'), isInput: true, default: Math.round(avgCoeff * 1000) / 1000 },
  8931. ])
  8932. if (result) {
  8933. findCoeff = result;
  8934. isCancalBattle = false;
  8935. startBattle();
  8936. return;
  8937. }
  8938. setProgress(I18N('NOT_THIS_TIME'), true);
  8939. endAutoBattle(I18N('NOT_THIS_TIME'));
  8940. }
  8941.  
  8942. /**
  8943. * Calculation of the combat result coefficient
  8944. *
  8945. * Расчет коэфициента результата боя
  8946. */
  8947. function calcCoeff(result, packType) {
  8948. let beforeSumFactor = 0;
  8949. const beforePack = result.battleData[packType][0];
  8950. for (let heroId in beforePack) {
  8951. const hero = beforePack[heroId];
  8952. const state = hero.state;
  8953. let factor = 1;
  8954. if (state) {
  8955. const hp = state.hp / state.maxHp;
  8956. const energy = state.energy / 1e3;
  8957. factor = hp + energy / 20;
  8958. }
  8959. beforeSumFactor += factor;
  8960. }
  8961.  
  8962. let afterSumFactor = 0;
  8963. const afterPack = result.progress[0][packType].heroes;
  8964. for (let heroId in afterPack) {
  8965. const hero = afterPack[heroId];
  8966. const stateHp = beforePack[heroId]?.state?.hp || beforePack[heroId]?.stats?.hp;
  8967. const hp = hero.hp / stateHp;
  8968. const energy = hero.energy / 1e3;
  8969. const factor = hp + energy / 20;
  8970. afterSumFactor += factor;
  8971. }
  8972. const resultCoeff = -(afterSumFactor - beforeSumFactor);
  8973. return Math.round(resultCoeff * 1000) / 1000;
  8974. }
  8975. /**
  8976. * Start battle
  8977. *
  8978. * Начало боя
  8979. */
  8980. function startBattle() {
  8981. countBattle++;
  8982. const countMaxBattle = getInput('countAutoBattle');
  8983. // setProgress(countBattle + '/' + countMaxBattle);
  8984. if (countBattle > countMaxBattle) {
  8985. setProgress(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`, true);
  8986. endAutoBattle(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`)
  8987. return;
  8988. }
  8989. send({calls: [{
  8990. name: nameFuncStartBattle,
  8991. args: battleArg,
  8992. ident: "body"
  8993. }]}, calcResultBattle);
  8994. }
  8995. /**
  8996. * Battle calculation
  8997. *
  8998. * Расчет боя
  8999. */
  9000. async function calcResultBattle(e) {
  9001. if (!e) {
  9002. console.log('данные не были получены');
  9003. if (dataNotEeceived < 10) {
  9004. dataNotEeceived++;
  9005. startBattle();
  9006. return;
  9007. }
  9008. endAutoBattle('Error', 'данные не были получены ' + dataNotEeceived + ' раз');
  9009. return;
  9010. }
  9011. if ('error' in e) {
  9012. if (e.error.description === 'too many tries') {
  9013. invasionTimer += 100;
  9014. countBattle--;
  9015. countError++;
  9016. console.log(`Errors: ${countError}`, e.error);
  9017. startBattle();
  9018. return;
  9019. }
  9020. const result = await popup.confirm(I18N('ERROR_DURING_THE_BATTLE') + '<br>' + e.error.description, [
  9021. { msg: I18N('BTN_OK'), result: false },
  9022. { msg: I18N('RELOAD_GAME'), result: true },
  9023. ]);
  9024. endAutoBattle('Error', e.error);
  9025. if (result) {
  9026. location.reload();
  9027. }
  9028. return;
  9029. }
  9030. let battle = e.results[0].result.response.battle
  9031. if (nameFuncStartBattle == 'towerStartBattle' ||
  9032. nameFuncStartBattle == 'bossAttack' ||
  9033. nameFuncStartBattle == 'invasion_bossStart') {
  9034. battle = e.results[0].result.response;
  9035. }
  9036. lastBattleInfo = battle;
  9037. BattleCalc(battle, getBattleType(battle.type), resultBattle);
  9038. }
  9039. /**
  9040. * Processing the results of the battle
  9041. *
  9042. * Обработка результатов боя
  9043. */
  9044. function resultBattle(e) {
  9045. const isWin = e.result.win;
  9046. if (isWin) {
  9047. endBattle(e, false);
  9048. return;
  9049. }
  9050. const countMaxBattle = getInput('countAutoBattle');
  9051. if (findCoeff) {
  9052. const coeff = calcCoeff(e, 'defenders');
  9053. setProgress(`${countBattle}/${countMaxBattle}, ${coeff}`);
  9054. if (coeff > findCoeff) {
  9055. endBattle(e, false);
  9056. return;
  9057. }
  9058. } else {
  9059. if (nameFuncStartBattle == 'invasion_bossStart') {
  9060. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  9061. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageMod_any_99_100_300_99_1000 || 0;
  9062. setProgress(`${svgBoss} ${bossLvl} ${svgJustice} ${justice} <br>${svgAttempt} ${countBattle}/${countMaxBattle}`);
  9063. } else {
  9064. setProgress(`${countBattle}/${countMaxBattle}`);
  9065. }
  9066. }
  9067. if (nameFuncStartBattle == 'towerStartBattle' ||
  9068. nameFuncStartBattle == 'bossAttack' ||
  9069. nameFuncStartBattle == 'invasion_bossStart') {
  9070. startBattle();
  9071. return;
  9072. }
  9073. cancelEndBattle(e);
  9074. }
  9075. /**
  9076. * Cancel fight
  9077. *
  9078. * Отмена боя
  9079. */
  9080. function cancelEndBattle(r) {
  9081. const fixBattle = function (heroes) {
  9082. for (const ids in heroes) {
  9083. hero = heroes[ids];
  9084. hero.energy = random(1, 999);
  9085. if (hero.hp > 0) {
  9086. hero.hp = random(1, hero.hp);
  9087. }
  9088. }
  9089. }
  9090. fixBattle(r.progress[0].attackers.heroes);
  9091. fixBattle(r.progress[0].defenders.heroes);
  9092. endBattle(r, true);
  9093. }
  9094. /**
  9095. * End of the fight
  9096. *
  9097. * Завершение боя */
  9098. function endBattle(battleResult, isCancal) {
  9099. let calls = [{
  9100. name: nameFuncEndBattle,
  9101. args: {
  9102. result: battleResult.result,
  9103. progress: battleResult.progress
  9104. },
  9105. ident: "body"
  9106. }];
  9107.  
  9108. if (nameFuncStartBattle == 'invasion_bossStart') {
  9109. calls[0].args.id = lastBattleArg.id;
  9110. }
  9111.  
  9112. send(JSON.stringify({
  9113. calls
  9114. }), async e => {
  9115. console.log(e);
  9116. if (isCancal) {
  9117. startBattle();
  9118. return;
  9119. }
  9120.  
  9121. setProgress(`${I18N('SUCCESS')}!`, 5000)
  9122. if (nameFuncStartBattle == 'invasion_bossStart' ||
  9123. nameFuncStartBattle == 'bossAttack') {
  9124. const countMaxBattle = getInput('countAutoBattle');
  9125. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  9126. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageMod_any_99_100_300_99_1000 || 0;
  9127. const result = await popup.confirm(
  9128. I18N('BOSS_HAS_BEEN_DEF_TEXT', {
  9129. bossLvl: `${svgBoss} ${bossLvl} ${svgJustice} ${justice}`,
  9130. countBattle: svgAttempt + ' ' + countBattle,
  9131. countMaxBattle,
  9132. }),
  9133. [
  9134. { msg: I18N('BTN_OK'), result: 0 },
  9135. { msg: I18N('MAKE_A_SYNC'), result: 1 },
  9136. { msg: I18N('RELOAD_GAME'), result: 2 },
  9137. ]
  9138. );
  9139. if (result) {
  9140. if (result == 1) {
  9141. cheats.refreshGame();
  9142. }
  9143. if (result == 2) {
  9144. location.reload();
  9145. }
  9146. }
  9147.  
  9148. }
  9149. endAutoBattle(`${I18N('SUCCESS')}!`)
  9150. });
  9151. }
  9152. /**
  9153. * Completing a task
  9154. *
  9155. * Завершение задачи
  9156. */
  9157. function endAutoBattle(reason, info) {
  9158. isCancalBattle = true;
  9159. console.log(reason, info);
  9160. resolve();
  9161. }
  9162. }
  9163.  
  9164. function testDailyQuests() {
  9165. return new Promise((resolve, reject) => {
  9166. const quests = new dailyQuests(resolve, reject);
  9167. quests.init(questsInfo);
  9168. quests.start();
  9169. });
  9170. }
  9171.  
  9172. /**
  9173. * Automatic completion of daily quests
  9174. *
  9175. * Автоматическое выполнение ежедневных квестов
  9176. */
  9177. class dailyQuests {
  9178. /**
  9179. * Send(' {"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}').then(e => console.log(e))
  9180. * Send(' {"calls":[{"name":"heroGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  9181. * Send(' {"calls":[{"name":"titanGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  9182. * Send(' {"calls":[{"name":"inventoryGet","args":{},"ident":"body"}]}').then(e => console.log(e))
  9183. * Send(' {"calls":[{"name":"questGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  9184. * Send(' {"calls":[{"name":"bossGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  9185. */
  9186. callsList = [
  9187. "userGetInfo",
  9188. "heroGetAll",
  9189. "titanGetAll",
  9190. "inventoryGet",
  9191. "questGetAll",
  9192. "bossGetAll",
  9193. ]
  9194.  
  9195. dataQuests = {
  9196. 10001: {
  9197. description: 'Улучши умения героев 3 раза', // ++++++++++++++++
  9198. doItCall: () => {
  9199. const upgradeSkills = this.getUpgradeSkills();
  9200. return upgradeSkills.map(({ heroId, skill }, index) => ({ name: "heroUpgradeSkill", args: { heroId, skill }, "ident": `heroUpgradeSkill_${index}` }));
  9201. },
  9202. isWeCanDo: () => {
  9203. const upgradeSkills = this.getUpgradeSkills();
  9204. let sumGold = 0;
  9205. for (const skill of upgradeSkills) {
  9206. sumGold += this.skillCost(skill.value);
  9207. if (!skill.heroId) {
  9208. return false;
  9209. }
  9210. }
  9211. return this.questInfo['userGetInfo'].gold > sumGold;
  9212. },
  9213. },
  9214. 10002: {
  9215. description: 'Пройди 10 миссий', // --------------
  9216. isWeCanDo: () => false,
  9217. },
  9218. 10003: {
  9219. description: 'Пройди 3 героические миссии', // --------------
  9220. isWeCanDo: () => false,
  9221. },
  9222. 10004: {
  9223. description: 'Сразись 3 раза на Арене или Гранд Арене', // --------------
  9224. isWeCanDo: () => false,
  9225. },
  9226. 10006: {
  9227. description: 'Используй обмен изумрудов 1 раз', // ++++++++++++++++
  9228. doItCall: () => [{
  9229. name: "refillableAlchemyUse",
  9230. args: { multi: false },
  9231. ident: "refillableAlchemyUse"
  9232. }],
  9233. isWeCanDo: () => {
  9234. const starMoney = this.questInfo['userGetInfo'].starMoney;
  9235. return starMoney >= 20;
  9236. },
  9237. },
  9238. 10007: {
  9239. description: 'Соверши 1 призыв в Атриуме Душ', // ++++++++++++++++
  9240. doItCall: () => [{ name: "gacha_open", args: { ident: "heroGacha", free: true, pack: false }, ident: "gacha_open" }],
  9241. isWeCanDo: () => {
  9242. const soulCrystal = this.questInfo['inventoryGet'].coin[38];
  9243. return soulCrystal > 0;
  9244. },
  9245. },
  9246. 10016: {
  9247. description: 'Отправь подарки согильдийцам', // ++++++++++++++++
  9248. doItCall: () => [{ name: "clanSendDailyGifts", args: {}, ident: "clanSendDailyGifts" }],
  9249. isWeCanDo: () => true,
  9250. },
  9251. 10018: {
  9252. description: 'Используй зелье опыта', // ++++++++++++++++
  9253. doItCall: () => {
  9254. const expHero = this.getExpHero();
  9255. return [{
  9256. name: "consumableUseHeroXp",
  9257. args: {
  9258. heroId: expHero.heroId,
  9259. libId: expHero.libId,
  9260. amount: 1
  9261. },
  9262. ident: "consumableUseHeroXp"
  9263. }];
  9264. },
  9265. isWeCanDo: () => {
  9266. const expHero = this.getExpHero();
  9267. return expHero.heroId && expHero.libId;
  9268. },
  9269. },
  9270. 10019: {
  9271. description: 'Открой 1 сундук в Башне',
  9272. doItFunc: testTower,
  9273. isWeCanDo: () => false,
  9274. },
  9275. 10020: {
  9276. description: 'Открой 3 сундука в Запределье', // Готово
  9277. doItCall: () => {
  9278. return this.getOutlandChest();
  9279. },
  9280. isWeCanDo: () => {
  9281. const outlandChest = this.getOutlandChest();
  9282. return outlandChest.length > 0;
  9283. },
  9284. },
  9285. 10021: {
  9286. description: 'Собери 75 Титанита в Подземелье Гильдии',
  9287. isWeCanDo: () => false,
  9288. },
  9289. 10022: {
  9290. description: 'Собери 150 Титанита в Подземелье Гильдии',
  9291. doItFunc: testDungeon,
  9292. isWeCanDo: () => false,
  9293. },
  9294. 10023: {
  9295. description: 'Прокачай Дар Стихий на 1 уровень', // Готово
  9296. doItCall: () => {
  9297. const heroId = this.getHeroIdTitanGift();
  9298. return [
  9299. { name: "heroTitanGiftLevelUp", args: { heroId }, ident: "heroTitanGiftLevelUp" },
  9300. { name: "heroTitanGiftDrop", args: { heroId }, ident: "heroTitanGiftDrop" }
  9301. ]
  9302. },
  9303. isWeCanDo: () => {
  9304. const heroId = this.getHeroIdTitanGift();
  9305. return heroId;
  9306. },
  9307. },
  9308. 10024: {
  9309. description: 'Повысь уровень любого артефакта один раз', // Готово
  9310. doItCall: () => {
  9311. const upArtifact = this.getUpgradeArtifact();
  9312. return [
  9313. {
  9314. name: "heroArtifactLevelUp",
  9315. args: {
  9316. heroId: upArtifact.heroId,
  9317. slotId: upArtifact.slotId
  9318. },
  9319. ident: `heroArtifactLevelUp`
  9320. }
  9321. ];
  9322. },
  9323. isWeCanDo: () => {
  9324. const upgradeArtifact = this.getUpgradeArtifact();
  9325. return upgradeArtifact.heroId;
  9326. },
  9327. },
  9328. 10025: {
  9329. description: 'Начни 1 Экспедицию',
  9330. doItFunc: checkExpedition,
  9331. isWeCanDo: () => false,
  9332. },
  9333. 10026: {
  9334. description: 'Начни 4 Экспедиции', // --------------
  9335. doItFunc: checkExpedition,
  9336. isWeCanDo: () => false,
  9337. },
  9338. 10027: {
  9339. description: 'Победи в 1 бою Турнира Стихий',
  9340. doItFunc: testTitanArena,
  9341. isWeCanDo: () => false,
  9342. },
  9343. 10028: {
  9344. description: 'Повысь уровень любого артефакта титанов', // Готово
  9345. doItCall: () => {
  9346. const upTitanArtifact = this.getUpgradeTitanArtifact();
  9347. return [
  9348. {
  9349. name: "titanArtifactLevelUp",
  9350. args: {
  9351. titanId: upTitanArtifact.titanId,
  9352. slotId: upTitanArtifact.slotId
  9353. },
  9354. ident: `titanArtifactLevelUp`
  9355. }
  9356. ];
  9357. },
  9358. isWeCanDo: () => {
  9359. const upgradeTitanArtifact = this.getUpgradeTitanArtifact();
  9360. return upgradeTitanArtifact.titanId;
  9361. },
  9362. },
  9363. 10029: {
  9364. description: 'Открой сферу артефактов титанов', // ++++++++++++++++
  9365. doItCall: () => [{ name: "titanArtifactChestOpen", args: { amount: 1, free: true }, ident: "titanArtifactChestOpen" }],
  9366. isWeCanDo: () => {
  9367. return this.questInfo['inventoryGet']?.consumable[55] > 0
  9368. },
  9369. },
  9370. 10030: {
  9371. description: 'Улучши облик любого героя 1 раз', // Готово
  9372. doItCall: () => {
  9373. const upSkin = this.getUpgradeSkin();
  9374. return [
  9375. {
  9376. name: "heroSkinUpgrade",
  9377. args: {
  9378. heroId: upSkin.heroId,
  9379. skinId: upSkin.skinId
  9380. },
  9381. ident: `heroSkinUpgrade`
  9382. }
  9383. ];
  9384. },
  9385. isWeCanDo: () => {
  9386. const upgradeSkin = this.getUpgradeSkin();
  9387. return upgradeSkin.heroId;
  9388. },
  9389. },
  9390. 10031: {
  9391. description: 'Победи в 6 боях Турнира Стихий', // --------------
  9392. doItFunc: testTitanArena,
  9393. isWeCanDo: () => false,
  9394. },
  9395. 10043: {
  9396. description: 'Начни или присоеденись к Приключению', // --------------
  9397. isWeCanDo: () => false,
  9398. },
  9399. 10044: {
  9400. description: 'Воспользуйся призывом питомцев 1 раз', // ++++++++++++++++
  9401. doItCall: () => [{ name: "pet_chestOpen", args: { amount: 1, paid: false }, ident: "pet_chestOpen" }],
  9402. isWeCanDo: () => {
  9403. return this.questInfo['inventoryGet']?.consumable[90] > 0
  9404. },
  9405. },
  9406. 10046: {
  9407. /**
  9408. * TODO: Watch Adventure
  9409. * TODO: Смотреть приключение
  9410. */
  9411. description: 'Открой 3 сундука в Приключениях',
  9412. isWeCanDo: () => false,
  9413. },
  9414. 10047: {
  9415. description: 'Набери 150 очков активности в Гильдии', // Готово
  9416. doItCall: () => {
  9417. const enchantRune = this.getEnchantRune();
  9418. return [
  9419. {
  9420. name: "heroEnchantRune",
  9421. args: {
  9422. heroId: enchantRune.heroId,
  9423. tier: enchantRune.tier,
  9424. items: {
  9425. consumable: { [enchantRune.itemId]: 1 }
  9426. }
  9427. },
  9428. ident: `heroEnchantRune`
  9429. }
  9430. ];
  9431. },
  9432. isWeCanDo: () => {
  9433. const userInfo = this.questInfo['userGetInfo'];
  9434. const enchantRune = this.getEnchantRune();
  9435. return enchantRune.heroId && userInfo.gold > 1e3;
  9436. },
  9437. },
  9438. };
  9439.  
  9440. constructor(resolve, reject, questInfo) {
  9441. this.resolve = resolve;
  9442. this.reject = reject;
  9443. }
  9444.  
  9445. init(questInfo) {
  9446. this.questInfo = questInfo;
  9447. this.isAuto = false;
  9448. }
  9449.  
  9450. async autoInit(isAuto) {
  9451. this.isAuto = isAuto || false;
  9452. const quests = {};
  9453. const calls = this.callsList.map(name => ({
  9454. name, args: {}, ident: name
  9455. }))
  9456. const result = await Send(JSON.stringify({ calls })).then(e => e.results);
  9457. for (const call of result) {
  9458. quests[call.ident] = call.result.response;
  9459. }
  9460. this.questInfo = quests;
  9461. }
  9462.  
  9463. async start() {
  9464. const weCanDo = [];
  9465. const selectedActions = getSaveVal('selectedActions', {});
  9466. for (let quest of this.questInfo['questGetAll']) {
  9467. if (quest.id in this.dataQuests && quest.state == 1) {
  9468. if (!selectedActions[quest.id]) {
  9469. selectedActions[quest.id] = {
  9470. checked: false
  9471. }
  9472. }
  9473.  
  9474. const isWeCanDo = this.dataQuests[quest.id].isWeCanDo;
  9475. if (!isWeCanDo.call(this)) {
  9476. continue;
  9477. }
  9478.  
  9479. weCanDo.push({
  9480. name: quest.id,
  9481. label: I18N(`QUEST_${quest.id}`),
  9482. checked: selectedActions[quest.id].checked
  9483. });
  9484. }
  9485. }
  9486.  
  9487. if (!weCanDo.length) {
  9488. this.end(I18N('NOTHING_TO_DO'));
  9489. return;
  9490. }
  9491.  
  9492. console.log(weCanDo);
  9493. let taskList = [];
  9494. if (this.isAuto) {
  9495. taskList = weCanDo;
  9496. } else {
  9497. const answer = await popup.confirm(`${I18N('YOU_CAN_COMPLETE') }:`, [
  9498. { msg: I18N('BTN_DO_IT'), result: true },
  9499. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  9500. ], weCanDo);
  9501. if (!answer) {
  9502. this.end('');
  9503. return;
  9504. }
  9505. taskList = popup.getCheckBoxes();
  9506. taskList.forEach(e => {
  9507. selectedActions[e.name].checked = e.checked;
  9508. });
  9509. setSaveVal('selectedActions', selectedActions);
  9510. }
  9511.  
  9512. const calls = [];
  9513. let countChecked = 0;
  9514. for (const task of taskList) {
  9515. if (task.checked) {
  9516. countChecked++;
  9517. const quest = this.dataQuests[task.name]
  9518. console.log(quest.description);
  9519.  
  9520. if (quest.doItCall) {
  9521. const doItCall = quest.doItCall.call(this);
  9522. calls.push(...doItCall);
  9523. }
  9524. }
  9525. }
  9526.  
  9527. if (!countChecked) {
  9528. this.end(I18N('NOT_QUEST_COMPLETED'));
  9529. return;
  9530. }
  9531.  
  9532. const result = await Send(JSON.stringify({ calls }));
  9533. if (result.error) {
  9534. console.error(result.error, result.error.call)
  9535. }
  9536. this.end(`${I18N('COMPLETED_QUESTS')}: ${countChecked}`);
  9537. }
  9538.  
  9539. errorHandling(error) {
  9540. //console.error(error);
  9541. let errorInfo = error.toString() + '\n';
  9542. try {
  9543. const errorStack = error.stack.split('\n');
  9544. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  9545. errorInfo += errorStack.slice(0, endStack).join('\n');
  9546. } catch (e) {
  9547. errorInfo += error.stack;
  9548. }
  9549. copyText(errorInfo);
  9550. }
  9551.  
  9552. skillCost(lvl) {
  9553. return 573 * lvl ** 0.9 + lvl ** 2.379;
  9554. }
  9555.  
  9556. getUpgradeSkills() {
  9557. const heroes = Object.values(this.questInfo['heroGetAll']);
  9558. const upgradeSkills = [
  9559. { heroId: 0, slotId: 0, value: 130 },
  9560. { heroId: 0, slotId: 0, value: 130 },
  9561. { heroId: 0, slotId: 0, value: 130 },
  9562. ];
  9563. const skillLib = lib.getData('skill');
  9564. /**
  9565. * color - 1 (белый) открывает 1 навык
  9566. * color - 2 (зеленый) открывает 2 навык
  9567. * color - 4 (синий) открывает 3 навык
  9568. * color - 7 (фиолетовый) открывает 4 навык
  9569. */
  9570. const colors = [1, 2, 4, 7];
  9571. for (const hero of heroes) {
  9572. const level = hero.level;
  9573. const color = hero.color;
  9574. for (let skillId in hero.skills) {
  9575. const tier = skillLib[skillId].tier;
  9576. const sVal = hero.skills[skillId];
  9577. if (color < colors[tier] || tier < 1 || tier > 4) {
  9578. continue;
  9579. }
  9580. for (let upSkill of upgradeSkills) {
  9581. if (sVal < upSkill.value && sVal < level) {
  9582. upSkill.value = sVal;
  9583. upSkill.heroId = hero.id;
  9584. upSkill.skill = tier;
  9585. break;
  9586. }
  9587. }
  9588. }
  9589. }
  9590. return upgradeSkills;
  9591. }
  9592.  
  9593. getUpgradeArtifact() {
  9594. const heroes = Object.values(this.questInfo['heroGetAll']);
  9595. const inventory = this.questInfo['inventoryGet'];
  9596. const upArt = { heroId: 0, slotId: 0, level: 100 };
  9597.  
  9598. const heroLib = lib.getData('hero');
  9599. const artifactLib = lib.getData('artifact');
  9600.  
  9601. for (const hero of heroes) {
  9602. const heroInfo = heroLib[hero.id];
  9603. const level = hero.level
  9604. if (level < 20) {
  9605. continue;
  9606. }
  9607.  
  9608. for (let slotId in hero.artifacts) {
  9609. const art = hero.artifacts[slotId];
  9610. /* Текущая звезданость арта */
  9611. const star = art.star;
  9612. if (!star) {
  9613. continue;
  9614. }
  9615. /* Текущий уровень арта */
  9616. const level = art.level;
  9617. if (level >= 100) {
  9618. continue;
  9619. }
  9620. /* Идентификатор арта в библиотеке */
  9621. const artifactId = heroInfo.artifacts[slotId];
  9622. const artInfo = artifactLib.id[artifactId];
  9623. const costNextLevel = artifactLib.type[artInfo.type].levels[level + 1].cost;
  9624.  
  9625. const costCurrency = Object.keys(costNextLevel).pop();
  9626. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  9627. const costId = costValues[0];
  9628. const costValue = +costValues[1];
  9629.  
  9630. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  9631. if (level < upArt.level && inventory[costCurrency][costId] >= costValue) {
  9632. upArt.level = level;
  9633. upArt.heroId = hero.id;
  9634. upArt.slotId = slotId;
  9635. upArt.costCurrency = costCurrency;
  9636. upArt.costId = costId;
  9637. upArt.costValue = costValue;
  9638. }
  9639. }
  9640. }
  9641. return upArt;
  9642. }
  9643.  
  9644. getUpgradeSkin() {
  9645. const heroes = Object.values(this.questInfo['heroGetAll']);
  9646. const inventory = this.questInfo['inventoryGet'];
  9647. const upSkin = { heroId: 0, skinId: 0, level: 60, cost: 1500 };
  9648.  
  9649. const skinLib = lib.getData('skin');
  9650.  
  9651. for (const hero of heroes) {
  9652. const level = hero.level
  9653. if (level < 20) {
  9654. continue;
  9655. }
  9656.  
  9657. for (let skinId in hero.skins) {
  9658. /* Текущий уровень скина */
  9659. const level = hero.skins[skinId];
  9660. if (level >= 60) {
  9661. continue;
  9662. }
  9663. /* Идентификатор скина в библиотеке */
  9664. const skinInfo = skinLib[skinId];
  9665. if (!skinInfo.statData.levels?.[level + 1]) {
  9666. continue;
  9667. }
  9668. const costNextLevel = skinInfo.statData.levels[level + 1].cost;
  9669.  
  9670. const costCurrency = Object.keys(costNextLevel).pop();
  9671. const costCurrencyId = Object.keys(costNextLevel[costCurrency]).pop();
  9672. const costValue = +costNextLevel[costCurrency][costCurrencyId];
  9673.  
  9674. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  9675. if (level < upSkin.level &&
  9676. costValue < upSkin.cost &&
  9677. inventory[costCurrency][costCurrencyId] >= costValue) {
  9678. upSkin.cost = costValue;
  9679. upSkin.level = level;
  9680. upSkin.heroId = hero.id;
  9681. upSkin.skinId = skinId;
  9682. upSkin.costCurrency = costCurrency;
  9683. upSkin.costCurrencyId = costCurrencyId;
  9684. }
  9685. }
  9686. }
  9687. return upSkin;
  9688. }
  9689.  
  9690. getUpgradeTitanArtifact() {
  9691. const titans = Object.values(this.questInfo['titanGetAll']);
  9692. const inventory = this.questInfo['inventoryGet'];
  9693. const userInfo = this.questInfo['userGetInfo'];
  9694. const upArt = { titanId: 0, slotId: 0, level: 120 };
  9695.  
  9696. const titanLib = lib.getData('titan');
  9697. const artTitanLib = lib.getData('titanArtifact');
  9698.  
  9699. for (const titan of titans) {
  9700. const titanInfo = titanLib[titan.id];
  9701. // const level = titan.level
  9702. // if (level < 20) {
  9703. // continue;
  9704. // }
  9705.  
  9706. for (let slotId in titan.artifacts) {
  9707. const art = titan.artifacts[slotId];
  9708. /* Текущая звезданость арта */
  9709. const star = art.star;
  9710. if (!star) {
  9711. continue;
  9712. }
  9713. /* Текущий уровень арта */
  9714. const level = art.level;
  9715. if (level >= 120) {
  9716. continue;
  9717. }
  9718. /* Идентификатор арта в библиотеке */
  9719. const artifactId = titanInfo.artifacts[slotId];
  9720. const artInfo = artTitanLib.id[artifactId];
  9721. const costNextLevel = artTitanLib.type[artInfo.type].levels[level + 1].cost;
  9722.  
  9723. const costCurrency = Object.keys(costNextLevel).pop();
  9724. let costValue = 0;
  9725. let currentValue = 0;
  9726. if (costCurrency == 'gold') {
  9727. costValue = costNextLevel[costCurrency];
  9728. currentValue = userInfo.gold;
  9729. } else {
  9730. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  9731. const costId = costValues[0];
  9732. costValue = +costValues[1];
  9733. currentValue = inventory[costCurrency][costId];
  9734. }
  9735.  
  9736. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  9737. if (level < upArt.level && currentValue >= costValue) {
  9738. upArt.level = level;
  9739. upArt.titanId = titan.id;
  9740. upArt.slotId = slotId;
  9741. break;
  9742. }
  9743. }
  9744. }
  9745. return upArt;
  9746. }
  9747.  
  9748. getEnchantRune() {
  9749. const heroes = Object.values(this.questInfo['heroGetAll']);
  9750. const inventory = this.questInfo['inventoryGet'];
  9751. const enchRune = { heroId: 0, tier: 0, exp: 43750, itemId: 0 };
  9752. for (let i = 1; i <= 4; i++) {
  9753. if (inventory.consumable[i] > 0) {
  9754. enchRune.itemId = i;
  9755. break;
  9756. }
  9757. return enchRune;
  9758. }
  9759.  
  9760. const runeLib = lib.getData('rune');
  9761. const runeLvls = Object.values(runeLib.level);
  9762. /**
  9763. * color - 4 (синий) открывает 1 и 2 символ
  9764. * color - 7 (фиолетовый) открывает 3 символ
  9765. * color - 8 (фиолетовый +1) открывает 4 символ
  9766. * color - 9 (фиолетовый +2) открывает 5 символ
  9767. */
  9768. // TODO: кажется надо учесть уровень команды
  9769. const colors = [4, 4, 7, 8, 9];
  9770. for (const hero of heroes) {
  9771. const color = hero.color;
  9772.  
  9773.  
  9774. for (let runeTier in hero.runes) {
  9775. /* Проверка на доступность руны */
  9776. if (color < colors[runeTier]) {
  9777. continue;
  9778. }
  9779. /* Текущий опыт руны */
  9780. const exp = hero.runes[runeTier];
  9781. if (exp >= 43750) {
  9782. continue;
  9783. }
  9784.  
  9785. let level = 0;
  9786. if (exp) {
  9787. for (let lvl of runeLvls) {
  9788. if (exp >= lvl.enchantValue) {
  9789. level = lvl.level;
  9790. } else {
  9791. break;
  9792. }
  9793. }
  9794. }
  9795. /** Уровень героя необходимый для уровня руны */
  9796. const heroLevel = runeLib.level[level].heroLevel;
  9797. if (hero.level < heroLevel) {
  9798. continue;
  9799. }
  9800.  
  9801. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  9802. if (exp < enchRune.exp) {
  9803. enchRune.exp = exp;
  9804. enchRune.heroId = hero.id;
  9805. enchRune.tier = runeTier;
  9806. break;
  9807. }
  9808. }
  9809. }
  9810. return enchRune;
  9811. }
  9812.  
  9813. getOutlandChest() {
  9814. const bosses = this.questInfo['bossGetAll'];
  9815.  
  9816. const calls = [];
  9817.  
  9818. for (let boss of bosses) {
  9819. if (boss.mayRaid) {
  9820. calls.push({
  9821. name: "bossRaid",
  9822. args: {
  9823. bossId: boss.id
  9824. },
  9825. ident: "bossRaid_" + boss.id
  9826. });
  9827. calls.push({
  9828. name: "bossOpenChest",
  9829. args: {
  9830. bossId: boss.id,
  9831. amount: 1,
  9832. starmoney: 0
  9833. },
  9834. ident: "bossOpenChest_" + boss.id
  9835. });
  9836. } else if (boss.chestId == 1) {
  9837. calls.push({
  9838. name: "bossOpenChest",
  9839. args: {
  9840. bossId: boss.id,
  9841. amount: 1,
  9842. starmoney: 0
  9843. },
  9844. ident: "bossOpenChest_" + boss.id
  9845. });
  9846. }
  9847. }
  9848.  
  9849. return calls;
  9850. }
  9851.  
  9852. getExpHero() {
  9853. const heroes = Object.values(this.questInfo['heroGetAll']);
  9854. const inventory = this.questInfo['inventoryGet'];
  9855. const expHero = { heroId: 0, exp: 3625195, libId: 0 };
  9856. /** зелья опыта (consumable 9, 10, 11, 12) */
  9857. for (let i = 9; i <= 12; i++) {
  9858. if (inventory.consumable[i]) {
  9859. expHero.libId = i;
  9860. break;
  9861. }
  9862. }
  9863.  
  9864. for (const hero of heroes) {
  9865. const exp = hero.xp;
  9866. if (exp < expHero.exp) {
  9867. expHero.heroId = hero.id;
  9868. }
  9869. }
  9870. return expHero;
  9871. }
  9872.  
  9873. getHeroIdTitanGift() {
  9874. const heroes = Object.values(this.questInfo['heroGetAll']);
  9875. const inventory = this.questInfo['inventoryGet'];
  9876. const user = this.questInfo['userGetInfo'];
  9877. const titanGiftLib = lib.getData('titanGift');
  9878. /** Искры */
  9879. const titanGift = inventory.consumable[24];
  9880. let heroId = 0;
  9881. let minLevel = 30;
  9882.  
  9883. if (titanGift < 250 || user.gold < 7000) {
  9884. return 0;
  9885. }
  9886.  
  9887. for (const hero of heroes) {
  9888. if (hero.titanGiftLevel >= 30) {
  9889. continue;
  9890. }
  9891.  
  9892. if (!hero.titanGiftLevel) {
  9893. return hero.id;
  9894. }
  9895.  
  9896. const cost = titanGiftLib[hero.titanGiftLevel].cost;
  9897. if (minLevel > hero.titanGiftLevel &&
  9898. titanGift >= cost.consumable[24] &&
  9899. user.gold >= cost.gold
  9900. ) {
  9901. minLevel = hero.titanGiftLevel;
  9902. heroId = hero.id;
  9903. }
  9904. }
  9905.  
  9906. return heroId;
  9907. }
  9908.  
  9909. end(status) {
  9910. setProgress(status, true);
  9911. this.resolve();
  9912. }
  9913. }
  9914.  
  9915. this.questRun = dailyQuests;
  9916.  
  9917. function testDoYourBest() {
  9918. return new Promise((resolve, reject) => {
  9919. const doIt = new doYourBest(resolve, reject);
  9920. doIt.start();
  9921. });
  9922. }
  9923.  
  9924. /**
  9925. * Do everything button
  9926. *
  9927. * Кнопка сделать все
  9928. */
  9929. class doYourBest {
  9930.  
  9931. funcList = [
  9932. {
  9933. name: 'getOutland',
  9934. label: I18N('ASSEMBLE_OUTLAND'),
  9935. checked: false
  9936. },
  9937. {
  9938. name: 'testTower',
  9939. label: I18N('PASS_THE_TOWER'),
  9940. checked: false
  9941. },
  9942. {
  9943. name: 'checkExpedition',
  9944. label: I18N('CHECK_EXPEDITIONS'),
  9945. checked: false
  9946. },
  9947. {
  9948. name: 'testTitanArena',
  9949. label: I18N('COMPLETE_TOE'),
  9950. checked: false
  9951. },
  9952. {
  9953. name: 'mailGetAll',
  9954. label: I18N('COLLECT_MAIL'),
  9955. checked: false
  9956. },
  9957. {
  9958. name: 'collectAllStuff',
  9959. label: I18N('COLLECT_MISC'),
  9960. title: I18N('COLLECT_MISC_TITLE'),
  9961. checked: false
  9962. },
  9963. {
  9964. name: 'getDailyBonus',
  9965. label: I18N('DAILY_BONUS'),
  9966. checked: false
  9967. },
  9968. {
  9969. name: 'dailyQuests',
  9970. label: I18N('DO_DAILY_QUESTS'),
  9971. checked: false
  9972. },
  9973. {
  9974. name: 'rollAscension',
  9975. label: I18N('SEER_TITLE'),
  9976. checked: false
  9977. },
  9978. {
  9979. name: 'questAllFarm',
  9980. label: I18N('COLLECT_QUEST_REWARDS'),
  9981. checked: false
  9982. },
  9983. {
  9984. name: 'testDungeon',
  9985. label: I18N('COMPLETE_DUNGEON'),
  9986. checked: false
  9987. },
  9988. {
  9989. name: 'synchronization',
  9990. label: I18N('MAKE_A_SYNC'),
  9991. checked: false
  9992. },
  9993. {
  9994. name: 'reloadGame',
  9995. label: I18N('RELOAD_GAME'),
  9996. checked: false
  9997. },
  9998. ];
  9999.  
  10000. functions = {
  10001. getOutland,
  10002. testTower,
  10003. checkExpedition,
  10004. testTitanArena,
  10005. mailGetAll,
  10006. collectAllStuff: async () => {
  10007. await offerFarmAllReward();
  10008. 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"}]}');
  10009. },
  10010. dailyQuests: async function () {
  10011. const quests = new dailyQuests(() => { }, () => { });
  10012. await quests.autoInit(true);
  10013. await quests.start();
  10014. },
  10015. rollAscension,
  10016. getDailyBonus,
  10017. questAllFarm,
  10018. testDungeon,
  10019. synchronization: async () => {
  10020. cheats.refreshGame();
  10021. },
  10022. reloadGame: async () => {
  10023. location.reload();
  10024. },
  10025. }
  10026.  
  10027. constructor(resolve, reject, questInfo) {
  10028. this.resolve = resolve;
  10029. this.reject = reject;
  10030. this.questInfo = questInfo
  10031. }
  10032.  
  10033. async start() {
  10034. const selectedDoIt = getSaveVal('selectedDoIt', {});
  10035.  
  10036. this.funcList.forEach(task => {
  10037. if (!selectedDoIt[task.name]) {
  10038. selectedDoIt[task.name] = {
  10039. checked: task.checked
  10040. }
  10041. } else {
  10042. task.checked = selectedDoIt[task.name].checked
  10043. }
  10044. });
  10045.  
  10046. const answer = await popup.confirm(I18N('RUN_FUNCTION'), [
  10047. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  10048. { msg: I18N('BTN_GO'), result: true },
  10049. ], this.funcList);
  10050.  
  10051. if (!answer) {
  10052. this.end('');
  10053. return;
  10054. }
  10055.  
  10056. const taskList = popup.getCheckBoxes();
  10057. taskList.forEach(task => {
  10058. selectedDoIt[task.name].checked = task.checked;
  10059. });
  10060. setSaveVal('selectedDoIt', selectedDoIt);
  10061. for (const task of popup.getCheckBoxes()) {
  10062. if (task.checked) {
  10063. try {
  10064. setProgress(`${task.label} <br>${I18N('PERFORMED')}!`);
  10065. await this.functions[task.name]();
  10066. setProgress(`${task.label} <br>${I18N('DONE')}!`);
  10067. } catch (error) {
  10068. if (await popup.confirm(`${I18N('ERRORS_OCCURRES')}:<br> ${task.label} <br>${I18N('COPY_ERROR')}?`, [
  10069. { msg: I18N('BTN_NO'), result: false },
  10070. { msg: I18N('BTN_YES'), result: true },
  10071. ])) {
  10072. this.errorHandling(error);
  10073. }
  10074. }
  10075. }
  10076. }
  10077. setTimeout((msg) => {
  10078. this.end(msg);
  10079. }, 2000, I18N('ALL_TASK_COMPLETED'));
  10080. return;
  10081. }
  10082.  
  10083. errorHandling(error) {
  10084. //console.error(error);
  10085. let errorInfo = error.toString() + '\n';
  10086. try {
  10087. const errorStack = error.stack.split('\n');
  10088. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  10089. errorInfo += errorStack.slice(0, endStack).join('\n');
  10090. } catch (e) {
  10091. errorInfo += error.stack;
  10092. }
  10093. copyText(errorInfo);
  10094. }
  10095.  
  10096. end(status) {
  10097. setProgress(status, true);
  10098. this.resolve();
  10099. }
  10100. }
  10101.  
  10102. /**
  10103. * Passing the adventure along the specified route
  10104. *
  10105. * Прохождение приключения по указанному маршруту
  10106. */
  10107. function testAdventure(type) {
  10108. return new Promise((resolve, reject) => {
  10109. const bossBattle = new executeAdventure(resolve, reject);
  10110. bossBattle.start(type);
  10111. });
  10112. }
  10113.  
  10114. /**
  10115. * Passing the adventure along the specified route
  10116. *
  10117. * Прохождение приключения по указанному маршруту
  10118. */
  10119. class executeAdventure {
  10120.  
  10121. type = 'default';
  10122.  
  10123. actions = {
  10124. default: {
  10125. getInfo: "adventure_getInfo",
  10126. startBattle: 'adventure_turnStartBattle',
  10127. endBattle: 'adventure_endBattle',
  10128. collectBuff: 'adventure_turnCollectBuff'
  10129. },
  10130. solo: {
  10131. getInfo: "adventureSolo_getInfo",
  10132. startBattle: 'adventureSolo_turnStartBattle',
  10133. endBattle: 'adventureSolo_endBattle',
  10134. collectBuff: 'adventureSolo_turnCollectBuff'
  10135. }
  10136. }
  10137.  
  10138. terminatеReason = I18N('UNKNOWN');
  10139. callAdventureInfo = {
  10140. name: "adventure_getInfo",
  10141. args: {},
  10142. ident: "adventure_getInfo"
  10143. }
  10144. callTeamGetAll = {
  10145. name: "teamGetAll",
  10146. args: {},
  10147. ident: "teamGetAll"
  10148. }
  10149. callTeamGetFavor = {
  10150. name: "teamGetFavor",
  10151. args: {},
  10152. ident: "teamGetFavor"
  10153. }
  10154. callStartBattle = {
  10155. name: "adventure_turnStartBattle",
  10156. args: {},
  10157. ident: "body"
  10158. }
  10159. callEndBattle = {
  10160. name: "adventure_endBattle",
  10161. args: {
  10162. result: {},
  10163. progress: {},
  10164. },
  10165. ident: "body"
  10166. }
  10167. callCollectBuff = {
  10168. name: "adventure_turnCollectBuff",
  10169. args: {},
  10170. ident: "body"
  10171. }
  10172.  
  10173. constructor(resolve, reject) {
  10174. this.resolve = resolve;
  10175. this.reject = reject;
  10176. }
  10177.  
  10178. async start(type) {
  10179. this.type = type || this.type;
  10180. this.callAdventureInfo.name = this.actions[this.type].getInfo;
  10181. const data = await Send(JSON.stringify({
  10182. calls: [
  10183. this.callAdventureInfo,
  10184. this.callTeamGetAll,
  10185. this.callTeamGetFavor
  10186. ]
  10187. }));
  10188. return this.checkAdventureInfo(data.results);
  10189. }
  10190.  
  10191. async getPath() {
  10192. const oldVal = getSaveVal('adventurePath', '');
  10193. const keyPath = `adventurePath:${this.mapIdent}`;
  10194. const answer = await popup.confirm(I18N('ENTER_THE_PATH'), [
  10195. {
  10196. msg: I18N('START_ADVENTURE'),
  10197. placeholder: '1,2,3,4,5,6',
  10198. isInput: true,
  10199. default: getSaveVal(keyPath, oldVal)
  10200. },
  10201. {
  10202. msg: I18N('BTN_CANCEL'),
  10203. result: false,
  10204. isCancel: true
  10205. },
  10206. ]);
  10207. if (!answer) {
  10208. this.terminatеReason = I18N('BTN_CANCELED');
  10209. return false;
  10210. }
  10211.  
  10212. let path = answer.split(',');
  10213. if (path.length < 2) {
  10214. path = answer.split('-');
  10215. }
  10216. if (path.length < 2) {
  10217. this.terminatеReason = I18N('MUST_TWO_POINTS');
  10218. return false;
  10219. }
  10220.  
  10221. for (let p in path) {
  10222. path[p] = +path[p].trim()
  10223. if (Number.isNaN(path[p])) {
  10224. this.terminatеReason = I18N('MUST_ONLY_NUMBERS');
  10225. return false;
  10226. }
  10227. }
  10228.  
  10229. if (!this.checkPath(path)) {
  10230. return false;
  10231. }
  10232. setSaveVal(keyPath, answer);
  10233. return path;
  10234. }
  10235.  
  10236. checkPath(path) {
  10237. for (let i = 0; i < path.length - 1; i++) {
  10238. const currentPoint = path[i];
  10239. const nextPoint = path[i + 1];
  10240.  
  10241. const isValidPath = this.paths.some(p =>
  10242. (p.from_id === currentPoint && p.to_id === nextPoint) ||
  10243. (p.from_id === nextPoint && p.to_id === currentPoint)
  10244. );
  10245.  
  10246. if (!isValidPath) {
  10247. this.terminatеReason = I18N('INCORRECT_WAY', {
  10248. from: currentPoint,
  10249. to: nextPoint,
  10250. });
  10251. return false;
  10252. }
  10253. }
  10254.  
  10255. return true;
  10256. }
  10257.  
  10258. async checkAdventureInfo(data) {
  10259. this.advInfo = data[0].result.response;
  10260. if (!this.advInfo) {
  10261. this.terminatеReason = I18N('NOT_ON_AN_ADVENTURE') ;
  10262. return this.end();
  10263. }
  10264. const heroesTeam = data[1].result.response.adventure_hero;
  10265. const favor = data[2]?.result.response.adventure_hero;
  10266. const heroes = heroesTeam.slice(0, 5);
  10267. const pet = heroesTeam[5];
  10268. this.args = {
  10269. pet,
  10270. heroes,
  10271. favor,
  10272. path: [],
  10273. broadcast: false
  10274. }
  10275. const advUserInfo = this.advInfo.users[userInfo.id];
  10276. this.turnsLeft = advUserInfo.turnsLeft;
  10277. this.currentNode = advUserInfo.currentNode;
  10278. this.nodes = this.advInfo.nodes;
  10279. this.paths = this.advInfo.paths;
  10280. this.mapIdent = this.advInfo.mapIdent;
  10281.  
  10282. this.path = await this.getPath();
  10283. if (!this.path) {
  10284. return this.end();
  10285. }
  10286.  
  10287. if (this.currentNode == 1 && this.path[0] != 1) {
  10288. this.path.unshift(1);
  10289. }
  10290.  
  10291. return this.loop();
  10292. }
  10293.  
  10294. async loop() {
  10295. const position = this.path.indexOf(+this.currentNode);
  10296. if (!(~position)) {
  10297. this.terminatеReason = I18N('YOU_IN_NOT_ON_THE_WAY');
  10298. return this.end();
  10299. }
  10300. this.path = this.path.slice(position);
  10301. if ((this.path.length - 1) > this.turnsLeft &&
  10302. await popup.confirm(I18N('ATTEMPTS_NOT_ENOUGH'), [
  10303. { msg: I18N('YES_CONTINUE'), result: false },
  10304. { msg: I18N('BTN_NO'), result: true },
  10305. ])) {
  10306. this.terminatеReason = I18N('NOT_ENOUGH_AP');
  10307. return this.end();
  10308. }
  10309. const toPath = [];
  10310. for (const nodeId of this.path) {
  10311. if (!this.turnsLeft) {
  10312. this.terminatеReason = I18N('ATTEMPTS_ARE_OVER');
  10313. return this.end();
  10314. }
  10315. toPath.push(nodeId);
  10316. console.log(toPath);
  10317. if (toPath.length > 1) {
  10318. setProgress(toPath.join(' > ') + ` ${I18N('MOVES')}: ` + this.turnsLeft);
  10319. }
  10320. if (nodeId == this.currentNode) {
  10321. continue;
  10322. }
  10323.  
  10324. const nodeInfo = this.getNodeInfo(nodeId);
  10325. if (nodeInfo.type == 'TYPE_COMBAT') {
  10326. if (nodeInfo.state == 'empty') {
  10327. this.turnsLeft--;
  10328. continue;
  10329. }
  10330.  
  10331. /**
  10332. * Disable regular battle cancellation
  10333. *
  10334. * Отключаем штатную отменую боя
  10335. */
  10336. isCancalBattle = false;
  10337. if (await this.battle(toPath)) {
  10338. this.turnsLeft--;
  10339. toPath.splice(0, toPath.indexOf(nodeId));
  10340. nodeInfo.state = 'empty';
  10341. isCancalBattle = true;
  10342. continue;
  10343. }
  10344. isCancalBattle = true;
  10345. return this.end()
  10346. }
  10347.  
  10348. if (nodeInfo.type == 'TYPE_PLAYERBUFF') {
  10349. const buff = this.checkBuff(nodeInfo);
  10350. if (buff == null) {
  10351. continue;
  10352. }
  10353.  
  10354. if (await this.collectBuff(buff, toPath)) {
  10355. this.turnsLeft--;
  10356. toPath.splice(0, toPath.indexOf(nodeId));
  10357. continue;
  10358. }
  10359. this.terminatеReason = I18N('BUFF_GET_ERROR');
  10360. return this.end();
  10361. }
  10362. }
  10363. this.terminatеReason = I18N('SUCCESS');
  10364. return this.end();
  10365. }
  10366.  
  10367. /**
  10368. * Carrying out a fight
  10369. *
  10370. * Проведение боя
  10371. */
  10372. async battle(path, preCalc = true) {
  10373. const data = await this.startBattle(path);
  10374. try {
  10375. const battle = data.results[0].result.response.battle;
  10376. const result = await Calc(battle);
  10377. if (result.result.win) {
  10378. const info = await this.endBattle(result);
  10379. if (info.results[0].result.response?.error) {
  10380. this.terminatеReason = I18N('BATTLE_END_ERROR');
  10381. return false;
  10382. }
  10383. } else {
  10384. await this.cancelBattle(result);
  10385.  
  10386. if (preCalc && await this.preCalcBattle(battle)) {
  10387. path = path.slice(-2);
  10388. for (let i = 1; i <= getInput('countAutoBattle'); i++) {
  10389. setProgress(`${I18N('AUTOBOT')}: ${i}/${getInput('countAutoBattle')}`);
  10390. const result = await this.battle(path, false);
  10391. if (result) {
  10392. setProgress(I18N('VICTORY'));
  10393. return true;
  10394. }
  10395. }
  10396. this.terminatеReason = I18N('FAILED_TO_WIN_AUTO');
  10397. return false;
  10398. }
  10399. return false;
  10400. }
  10401. } catch (error) {
  10402. console.error(error);
  10403. if (await popup.confirm(I18N('ERROR_OF_THE_BATTLE_COPY'), [
  10404. { msg: I18N('BTN_NO'), result: false },
  10405. { msg: I18N('BTN_YES'), result: true },
  10406. ])) {
  10407. this.errorHandling(error, data);
  10408. }
  10409. this.terminatеReason = I18N('ERROR_DURING_THE_BATTLE');
  10410. return false;
  10411. }
  10412. return true;
  10413. }
  10414.  
  10415. /**
  10416. * Recalculate battles
  10417. *
  10418. * Прерасчтет битвы
  10419. */
  10420. async preCalcBattle(battle) {
  10421. const countTestBattle = getInput('countTestBattle');
  10422. for (let i = 0; i < countTestBattle; i++) {
  10423. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  10424. const result = await Calc(battle);
  10425. if (result.result.win) {
  10426. console.log(i, countTestBattle);
  10427. return true;
  10428. }
  10429. }
  10430. this.terminatеReason = I18N('NO_CHANCE_WIN') + countTestBattle;
  10431. return false;
  10432. }
  10433.  
  10434. /**
  10435. * Starts a fight
  10436. *
  10437. * Начинает бой
  10438. */
  10439. startBattle(path) {
  10440. this.args.path = path;
  10441. this.callStartBattle.name = this.actions[this.type].startBattle;
  10442. this.callStartBattle.args = this.args
  10443. const calls = [this.callStartBattle];
  10444. return Send(JSON.stringify({ calls }));
  10445. }
  10446.  
  10447. cancelBattle(battle) {
  10448. const fixBattle = function (heroes) {
  10449. for (const ids in heroes) {
  10450. const hero = heroes[ids];
  10451. hero.energy = random(1, 999);
  10452. if (hero.hp > 0) {
  10453. hero.hp = random(1, hero.hp);
  10454. }
  10455. }
  10456. }
  10457. fixBattle(battle.progress[0].attackers.heroes);
  10458. fixBattle(battle.progress[0].defenders.heroes);
  10459. return this.endBattle(battle);
  10460. }
  10461.  
  10462. /**
  10463. * Ends the fight
  10464. *
  10465. * Заканчивает бой
  10466. */
  10467. endBattle(battle) {
  10468. this.callEndBattle.name = this.actions[this.type].endBattle;
  10469. this.callEndBattle.args.result = battle.result
  10470. this.callEndBattle.args.progress = battle.progress
  10471. const calls = [this.callEndBattle];
  10472. return Send(JSON.stringify({ calls }));
  10473. }
  10474.  
  10475. /**
  10476. * Checks if you can get a buff
  10477. *
  10478. * Проверяет можно ли получить баф
  10479. */
  10480. checkBuff(nodeInfo) {
  10481. let id = null;
  10482. let value = 0;
  10483. for (const buffId in nodeInfo.buffs) {
  10484. const buff = nodeInfo.buffs[buffId];
  10485. if (buff.owner == null && buff.value > value) {
  10486. id = buffId;
  10487. value = buff.value;
  10488. }
  10489. }
  10490. nodeInfo.buffs[id].owner = 'Я';
  10491. return id;
  10492. }
  10493.  
  10494. /**
  10495. * Collects a buff
  10496. *
  10497. * Собирает баф
  10498. */
  10499. async collectBuff(buff, path) {
  10500. this.callCollectBuff.name = this.actions[this.type].collectBuff;
  10501. this.callCollectBuff.args = { buff, path };
  10502. const calls = [this.callCollectBuff];
  10503. return Send(JSON.stringify({ calls }));
  10504. }
  10505.  
  10506. getNodeInfo(nodeId) {
  10507. return this.nodes.find(node => node.id == nodeId);
  10508. }
  10509.  
  10510. errorHandling(error, data) {
  10511. //console.error(error);
  10512. let errorInfo = error.toString() + '\n';
  10513. try {
  10514. const errorStack = error.stack.split('\n');
  10515. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testAdventure");
  10516. errorInfo += errorStack.slice(0, endStack).join('\n');
  10517. } catch (e) {
  10518. errorInfo += error.stack;
  10519. }
  10520. if (data) {
  10521. errorInfo += '\nData: ' + JSON.stringify(data);
  10522. }
  10523. copyText(errorInfo);
  10524. }
  10525.  
  10526. end() {
  10527. isCancalBattle = true;
  10528. setProgress(this.terminatеReason, true);
  10529. console.log(this.terminatеReason);
  10530. this.resolve();
  10531. }
  10532. }
  10533.  
  10534. /**
  10535. * Passage of brawls
  10536. *
  10537. * Прохождение потасовок
  10538. */
  10539. function testBrawls(isAuto) {
  10540. return new Promise((resolve, reject) => {
  10541. const brawls = new executeBrawls(resolve, reject);
  10542. brawls.start(brawlsPack, isAuto);
  10543. });
  10544. }
  10545. /**
  10546. * Passage of brawls
  10547. *
  10548. * Прохождение потасовок
  10549. */
  10550. class executeBrawls {
  10551. callBrawlQuestGetInfo = {
  10552. name: "brawl_questGetInfo",
  10553. args: {},
  10554. ident: "brawl_questGetInfo"
  10555. }
  10556. callBrawlFindEnemies = {
  10557. name: "brawl_findEnemies",
  10558. args: {},
  10559. ident: "brawl_findEnemies"
  10560. }
  10561. callBrawlQuestFarm = {
  10562. name: "brawl_questFarm",
  10563. args: {},
  10564. ident: "brawl_questFarm"
  10565. }
  10566. callUserGetInfo = {
  10567. name: "userGetInfo",
  10568. args: {},
  10569. ident: "userGetInfo"
  10570. }
  10571. callTeamGetMaxUpgrade = {
  10572. name: "teamGetMaxUpgrade",
  10573. args: {},
  10574. ident: "teamGetMaxUpgrade"
  10575. }
  10576. callBrawlGetInfo = {
  10577. name: "brawl_getInfo",
  10578. args: {},
  10579. ident: "brawl_getInfo"
  10580. }
  10581.  
  10582. stats = {
  10583. win: 0,
  10584. loss: 0,
  10585. count: 0,
  10586. }
  10587.  
  10588. stage = {
  10589. '3': 1,
  10590. '7': 2,
  10591. '12': 3,
  10592. }
  10593.  
  10594. attempts = 0;
  10595.  
  10596. constructor(resolve, reject) {
  10597. this.resolve = resolve;
  10598. this.reject = reject;
  10599.  
  10600. const allHeroIds = Object.keys(lib.getData('hero'));
  10601. this.callTeamGetMaxUpgrade.args.units = {
  10602. hero: allHeroIds.filter((id) => +id < 1000),
  10603. titan: allHeroIds.filter((id) => +id >= 4000 && +id < 4100),
  10604. pet: allHeroIds.filter((id) => +id >= 6000 && +id < 6100),
  10605. };
  10606. }
  10607.  
  10608. async start(args, isAuto) {
  10609. this.isAuto = isAuto;
  10610. this.args = args;
  10611. isCancalBattle = false;
  10612. this.brawlInfo = await this.getBrawlInfo();
  10613. this.attempts = this.brawlInfo.attempts;
  10614.  
  10615. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  10616. this.end(I18N('DONT_HAVE_LIVES'));
  10617. return;
  10618. }
  10619.  
  10620. while (1) {
  10621. if (!isBrawlsAutoStart) {
  10622. this.end(I18N('BTN_CANCELED'));
  10623. return;
  10624. }
  10625.  
  10626. const maxStage = this.brawlInfo.questInfo.stage;
  10627. const stage = this.stage[maxStage];
  10628. const progress = this.brawlInfo.questInfo.progress;
  10629.  
  10630. setProgress(
  10631. `${I18N('STAGE')} ${stage}: ${progress}/${maxStage}<br>${I18N('FIGHTS')}: ${this.stats.count}<br>${I18N('WINS')}: ${
  10632. this.stats.win
  10633. }<br>${I18N('LOSSES')}: ${this.stats.loss}<br>${I18N('LIVES')}: ${this.attempts}<br>${I18N('STOP')}`,
  10634. false,
  10635. function () {
  10636. isBrawlsAutoStart = false;
  10637. }
  10638. );
  10639.  
  10640. if (this.brawlInfo.questInfo.canFarm) {
  10641. const result = await this.questFarm();
  10642. console.log(result);
  10643. }
  10644.  
  10645. if (!this.continueAttack && this.brawlInfo.questInfo.stage == 12 && this.brawlInfo.questInfo.progress == 12) {
  10646. if (
  10647. await popup.confirm(I18N('BRAWL_DAILY_TASK_COMPLETED'), [
  10648. { msg: I18N('BTN_NO'), result: true },
  10649. { msg: I18N('BTN_YES'), result: false },
  10650. ])
  10651. ) {
  10652. this.end(I18N('SUCCESS'));
  10653. return;
  10654. } else {
  10655. this.continueAttack = true;
  10656. }
  10657. }
  10658.  
  10659. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  10660. this.end(I18N('DONT_HAVE_LIVES'));
  10661. return;
  10662. }
  10663.  
  10664. const enemie = Object.values(this.brawlInfo.findEnemies).shift();
  10665.  
  10666. // Автоматический подбор пачки
  10667. if (this.isAuto) {
  10668. if (this.mandatoryId <= 4000 && this.mandatoryId != 13) {
  10669. this.end(I18N('BRAWL_AUTO_PACK_NOT_CUR_HERO'));
  10670. return;
  10671. }
  10672. if (this.mandatoryId >= 4000 && this.mandatoryId < 4100) {
  10673. this.args = await this.updateTitanPack(enemie.heroes);
  10674. } else if (this.mandatoryId < 4000 && this.mandatoryId == 13) {
  10675. this.args = await this.updateHeroesPack(enemie.heroes);
  10676. }
  10677. }
  10678.  
  10679. const result = await this.battle(enemie.userId);
  10680. this.brawlInfo = {
  10681. questInfo: result[1].result.response,
  10682. findEnemies: result[2].result.response,
  10683. };
  10684. }
  10685. }
  10686.  
  10687. async updateTitanPack(enemieHeroes) {
  10688. const packs = [
  10689. [4033, 4040, 4041, 4042, 4043],
  10690. [4032, 4040, 4041, 4042, 4043],
  10691. [4031, 4040, 4041, 4042, 4043],
  10692. [4030, 4040, 4041, 4042, 4043],
  10693. [4032, 4033, 4040, 4042, 4043],
  10694. [4030, 4033, 4041, 4042, 4043],
  10695. [4031, 4033, 4040, 4042, 4043],
  10696. [4032, 4033, 4040, 4041, 4043],
  10697. [4023, 4040, 4041, 4042, 4043],
  10698. [4030, 4033, 4040, 4042, 4043],
  10699. [4031, 4033, 4040, 4041, 4043],
  10700. [4022, 4040, 4041, 4042, 4043],
  10701. [4030, 4033, 4040, 4041, 4043],
  10702. [4021, 4040, 4041, 4042, 4043],
  10703. [4020, 4040, 4041, 4042, 4043],
  10704. [4023, 4033, 4040, 4042, 4043],
  10705. [4030, 4032, 4033, 4042, 4043],
  10706. [4023, 4033, 4040, 4041, 4043],
  10707. [4031, 4032, 4033, 4040, 4043],
  10708. [4030, 4032, 4033, 4041, 4043],
  10709. [4030, 4031, 4033, 4042, 4043],
  10710. [4013, 4040, 4041, 4042, 4043],
  10711. [4030, 4032, 4033, 4040, 4043],
  10712. [4030, 4031, 4033, 4041, 4043],
  10713. [4012, 4040, 4041, 4042, 4043],
  10714. [4030, 4031, 4033, 4040, 4043],
  10715. [4011, 4040, 4041, 4042, 4043],
  10716. [4010, 4040, 4041, 4042, 4043],
  10717. [4023, 4032, 4033, 4042, 4043],
  10718. [4022, 4032, 4033, 4042, 4043],
  10719. [4023, 4032, 4033, 4041, 4043],
  10720. [4021, 4032, 4033, 4042, 4043],
  10721. [4022, 4032, 4033, 4041, 4043],
  10722. [4023, 4030, 4033, 4042, 4043],
  10723. [4023, 4032, 4033, 4040, 4043],
  10724. [4013, 4033, 4040, 4042, 4043],
  10725. [4020, 4032, 4033, 4042, 4043],
  10726. [4021, 4032, 4033, 4041, 4043],
  10727. [4022, 4030, 4033, 4042, 4043],
  10728. [4022, 4032, 4033, 4040, 4043],
  10729. [4023, 4030, 4033, 4041, 4043],
  10730. [4023, 4031, 4033, 4040, 4043],
  10731. [4013, 4033, 4040, 4041, 4043],
  10732. [4020, 4031, 4033, 4042, 4043],
  10733. [4020, 4032, 4033, 4041, 4043],
  10734. [4021, 4030, 4033, 4042, 4043],
  10735. [4021, 4032, 4033, 4040, 4043],
  10736. [4022, 4030, 4033, 4041, 4043],
  10737. [4022, 4031, 4033, 4040, 4043],
  10738. [4023, 4030, 4033, 4040, 4043],
  10739. [4030, 4031, 4032, 4033, 4043],
  10740. [4003, 4040, 4041, 4042, 4043],
  10741. [4020, 4030, 4033, 4042, 4043],
  10742. [4020, 4031, 4033, 4041, 4043],
  10743. [4020, 4032, 4033, 4040, 4043],
  10744. [4021, 4030, 4033, 4041, 4043],
  10745. [4021, 4031, 4033, 4040, 4043],
  10746. [4022, 4030, 4033, 4040, 4043],
  10747. [4030, 4031, 4032, 4033, 4042],
  10748. [4002, 4040, 4041, 4042, 4043],
  10749. [4020, 4030, 4033, 4041, 4043],
  10750. [4020, 4031, 4033, 4040, 4043],
  10751. [4021, 4030, 4033, 4040, 4043],
  10752. [4030, 4031, 4032, 4033, 4041],
  10753. [4001, 4040, 4041, 4042, 4043],
  10754. [4030, 4031, 4032, 4033, 4040],
  10755. [4000, 4040, 4041, 4042, 4043],
  10756. [4013, 4032, 4033, 4042, 4043],
  10757. [4012, 4032, 4033, 4042, 4043],
  10758. [4013, 4032, 4033, 4041, 4043],
  10759. [4023, 4031, 4032, 4033, 4043],
  10760. [4011, 4032, 4033, 4042, 4043],
  10761. [4012, 4032, 4033, 4041, 4043],
  10762. [4013, 4030, 4033, 4042, 4043],
  10763. [4013, 4032, 4033, 4040, 4043],
  10764. [4023, 4030, 4032, 4033, 4043],
  10765. [4003, 4033, 4040, 4042, 4043],
  10766. [4013, 4023, 4040, 4042, 4043],
  10767. [4010, 4032, 4033, 4042, 4043],
  10768. [4011, 4032, 4033, 4041, 4043],
  10769. [4012, 4030, 4033, 4042, 4043],
  10770. [4012, 4032, 4033, 4040, 4043],
  10771. [4013, 4030, 4033, 4041, 4043],
  10772. [4013, 4031, 4033, 4040, 4043],
  10773. [4023, 4030, 4031, 4033, 4043],
  10774. [4003, 4033, 4040, 4041, 4043],
  10775. [4013, 4023, 4040, 4041, 4043],
  10776. [4010, 4031, 4033, 4042, 4043],
  10777. [4010, 4032, 4033, 4041, 4043],
  10778. [4011, 4030, 4033, 4042, 4043],
  10779. [4011, 4032, 4033, 4040, 4043],
  10780. [4012, 4030, 4033, 4041, 4043],
  10781. [4012, 4031, 4033, 4040, 4043],
  10782. [4013, 4030, 4033, 4040, 4043],
  10783. [4010, 4030, 4033, 4042, 4043],
  10784. [4010, 4031, 4033, 4041, 4043],
  10785. [4010, 4032, 4033, 4040, 4043],
  10786. [4011, 4030, 4033, 4041, 4043],
  10787. [4011, 4031, 4033, 4040, 4043],
  10788. [4012, 4030, 4033, 4040, 4043],
  10789. [4010, 4030, 4033, 4041, 4043],
  10790. [4010, 4031, 4033, 4040, 4043],
  10791. [4011, 4030, 4033, 4040, 4043],
  10792. [4003, 4032, 4033, 4042, 4043],
  10793. [4002, 4032, 4033, 4042, 4043],
  10794. [4003, 4032, 4033, 4041, 4043],
  10795. [4013, 4031, 4032, 4033, 4043],
  10796. [4001, 4032, 4033, 4042, 4043],
  10797. [4002, 4032, 4033, 4041, 4043],
  10798. [4003, 4030, 4033, 4042, 4043],
  10799. [4003, 4032, 4033, 4040, 4043],
  10800. [4013, 4030, 4032, 4033, 4043],
  10801. [4003, 4023, 4040, 4042, 4043],
  10802. [4000, 4032, 4033, 4042, 4043],
  10803. [4001, 4032, 4033, 4041, 4043],
  10804. [4002, 4030, 4033, 4042, 4043],
  10805. [4002, 4032, 4033, 4040, 4043],
  10806. [4003, 4030, 4033, 4041, 4043],
  10807. [4003, 4031, 4033, 4040, 4043],
  10808. [4020, 4022, 4023, 4042, 4043],
  10809. [4013, 4030, 4031, 4033, 4043],
  10810. [4003, 4023, 4040, 4041, 4043],
  10811. [4000, 4031, 4033, 4042, 4043],
  10812. [4000, 4032, 4033, 4041, 4043],
  10813. [4001, 4030, 4033, 4042, 4043],
  10814. [4001, 4032, 4033, 4040, 4043],
  10815. [4002, 4030, 4033, 4041, 4043],
  10816. [4002, 4031, 4033, 4040, 4043],
  10817. [4003, 4030, 4033, 4040, 4043],
  10818. [4021, 4022, 4023, 4040, 4043],
  10819. [4020, 4022, 4023, 4041, 4043],
  10820. [4020, 4021, 4023, 4042, 4043],
  10821. [4023, 4030, 4031, 4032, 4033],
  10822. [4000, 4030, 4033, 4042, 4043],
  10823. [4000, 4031, 4033, 4041, 4043],
  10824. [4000, 4032, 4033, 4040, 4043],
  10825. [4001, 4030, 4033, 4041, 4043],
  10826. [4001, 4031, 4033, 4040, 4043],
  10827. [4002, 4030, 4033, 4040, 4043],
  10828. [4020, 4022, 4023, 4040, 4043],
  10829. [4020, 4021, 4023, 4041, 4043],
  10830. [4022, 4030, 4031, 4032, 4033],
  10831. [4000, 4030, 4033, 4041, 4043],
  10832. [4000, 4031, 4033, 4040, 4043],
  10833. [4001, 4030, 4033, 4040, 4043],
  10834. [4020, 4021, 4023, 4040, 4043],
  10835. [4021, 4030, 4031, 4032, 4033],
  10836. [4020, 4030, 4031, 4032, 4033],
  10837. [4003, 4031, 4032, 4033, 4043],
  10838. [4020, 4022, 4023, 4033, 4043],
  10839. [4003, 4030, 4032, 4033, 4043],
  10840. [4003, 4013, 4040, 4042, 4043],
  10841. [4020, 4021, 4023, 4033, 4043],
  10842. [4003, 4030, 4031, 4033, 4043],
  10843. [4003, 4013, 4040, 4041, 4043],
  10844. [4013, 4030, 4031, 4032, 4033],
  10845. [4012, 4030, 4031, 4032, 4033],
  10846. [4011, 4030, 4031, 4032, 4033],
  10847. [4010, 4030, 4031, 4032, 4033],
  10848. [4013, 4023, 4031, 4032, 4033],
  10849. [4013, 4023, 4030, 4032, 4033],
  10850. [4020, 4022, 4023, 4032, 4033],
  10851. [4013, 4023, 4030, 4031, 4033],
  10852. [4021, 4022, 4023, 4030, 4033],
  10853. [4020, 4022, 4023, 4031, 4033],
  10854. [4020, 4021, 4023, 4032, 4033],
  10855. [4020, 4021, 4022, 4023, 4043],
  10856. [4003, 4030, 4031, 4032, 4033],
  10857. [4020, 4022, 4023, 4030, 4033],
  10858. [4020, 4021, 4023, 4031, 4033],
  10859. [4020, 4021, 4022, 4023, 4042],
  10860. [4002, 4030, 4031, 4032, 4033],
  10861. [4020, 4021, 4023, 4030, 4033],
  10862. [4020, 4021, 4022, 4023, 4041],
  10863. [4001, 4030, 4031, 4032, 4033],
  10864. [4020, 4021, 4022, 4023, 4040],
  10865. [4000, 4030, 4031, 4032, 4033],
  10866. [4003, 4023, 4031, 4032, 4033],
  10867. [4013, 4020, 4022, 4023, 4043],
  10868. [4003, 4023, 4030, 4032, 4033],
  10869. [4010, 4012, 4013, 4042, 4043],
  10870. [4013, 4020, 4021, 4023, 4043],
  10871. [4003, 4023, 4030, 4031, 4033],
  10872. [4011, 4012, 4013, 4040, 4043],
  10873. [4010, 4012, 4013, 4041, 4043],
  10874. [4010, 4011, 4013, 4042, 4043],
  10875. [4020, 4021, 4022, 4023, 4033],
  10876. [4010, 4012, 4013, 4040, 4043],
  10877. [4010, 4011, 4013, 4041, 4043],
  10878. [4020, 4021, 4022, 4023, 4032],
  10879. [4010, 4011, 4013, 4040, 4043],
  10880. [4020, 4021, 4022, 4023, 4031],
  10881. [4020, 4021, 4022, 4023, 4030],
  10882. [4003, 4013, 4031, 4032, 4033],
  10883. [4010, 4012, 4013, 4033, 4043],
  10884. [4003, 4020, 4022, 4023, 4043],
  10885. [4013, 4020, 4022, 4023, 4033],
  10886. [4003, 4013, 4030, 4032, 4033],
  10887. [4010, 4011, 4013, 4033, 4043],
  10888. [4003, 4020, 4021, 4023, 4043],
  10889. [4013, 4020, 4021, 4023, 4033],
  10890. [4003, 4013, 4030, 4031, 4033],
  10891. [4010, 4012, 4013, 4023, 4043],
  10892. [4003, 4020, 4022, 4023, 4033],
  10893. [4010, 4012, 4013, 4032, 4033],
  10894. [4010, 4011, 4013, 4023, 4043],
  10895. [4003, 4020, 4021, 4023, 4033],
  10896. [4011, 4012, 4013, 4030, 4033],
  10897. [4010, 4012, 4013, 4031, 4033],
  10898. [4010, 4011, 4013, 4032, 4033],
  10899. [4013, 4020, 4021, 4022, 4023],
  10900. [4010, 4012, 4013, 4030, 4033],
  10901. [4010, 4011, 4013, 4031, 4033],
  10902. [4012, 4020, 4021, 4022, 4023],
  10903. [4010, 4011, 4013, 4030, 4033],
  10904. [4011, 4020, 4021, 4022, 4023],
  10905. [4010, 4020, 4021, 4022, 4023],
  10906. [4010, 4012, 4013, 4023, 4033],
  10907. [4000, 4002, 4003, 4042, 4043],
  10908. [4010, 4011, 4013, 4023, 4033],
  10909. [4001, 4002, 4003, 4040, 4043],
  10910. [4000, 4002, 4003, 4041, 4043],
  10911. [4000, 4001, 4003, 4042, 4043],
  10912. [4010, 4011, 4012, 4013, 4043],
  10913. [4003, 4020, 4021, 4022, 4023],
  10914. [4000, 4002, 4003, 4040, 4043],
  10915. [4000, 4001, 4003, 4041, 4043],
  10916. [4010, 4011, 4012, 4013, 4042],
  10917. [4002, 4020, 4021, 4022, 4023],
  10918. [4000, 4001, 4003, 4040, 4043],
  10919. [4010, 4011, 4012, 4013, 4041],
  10920. [4001, 4020, 4021, 4022, 4023],
  10921. [4010, 4011, 4012, 4013, 4040],
  10922. [4000, 4020, 4021, 4022, 4023],
  10923. [4001, 4002, 4003, 4033, 4043],
  10924. [4000, 4002, 4003, 4033, 4043],
  10925. [4003, 4010, 4012, 4013, 4043],
  10926. [4003, 4013, 4020, 4022, 4023],
  10927. [4000, 4001, 4003, 4033, 4043],
  10928. [4003, 4010, 4011, 4013, 4043],
  10929. [4003, 4013, 4020, 4021, 4023],
  10930. [4010, 4011, 4012, 4013, 4033],
  10931. [4010, 4011, 4012, 4013, 4032],
  10932. [4010, 4011, 4012, 4013, 4031],
  10933. [4010, 4011, 4012, 4013, 4030],
  10934. [4001, 4002, 4003, 4023, 4043],
  10935. [4000, 4002, 4003, 4023, 4043],
  10936. [4003, 4010, 4012, 4013, 4033],
  10937. [4000, 4002, 4003, 4032, 4033],
  10938. [4000, 4001, 4003, 4023, 4043],
  10939. [4003, 4010, 4011, 4013, 4033],
  10940. [4001, 4002, 4003, 4030, 4033],
  10941. [4000, 4002, 4003, 4031, 4033],
  10942. [4000, 4001, 4003, 4032, 4033],
  10943. [4010, 4011, 4012, 4013, 4023],
  10944. [4000, 4002, 4003, 4030, 4033],
  10945. [4000, 4001, 4003, 4031, 4033],
  10946. [4010, 4011, 4012, 4013, 4022],
  10947. [4000, 4001, 4003, 4030, 4033],
  10948. [4010, 4011, 4012, 4013, 4021],
  10949. [4010, 4011, 4012, 4013, 4020],
  10950. [4001, 4002, 4003, 4013, 4043],
  10951. [4001, 4002, 4003, 4023, 4033],
  10952. [4000, 4002, 4003, 4013, 4043],
  10953. [4000, 4002, 4003, 4023, 4033],
  10954. [4003, 4010, 4012, 4013, 4023],
  10955. [4000, 4001, 4003, 4013, 4043],
  10956. [4000, 4001, 4003, 4023, 4033],
  10957. [4003, 4010, 4011, 4013, 4023],
  10958. [4001, 4002, 4003, 4013, 4033],
  10959. [4000, 4002, 4003, 4013, 4033],
  10960. [4000, 4001, 4003, 4013, 4033],
  10961. [4000, 4001, 4002, 4003, 4043],
  10962. [4003, 4010, 4011, 4012, 4013],
  10963. [4000, 4001, 4002, 4003, 4042],
  10964. [4002, 4010, 4011, 4012, 4013],
  10965. [4000, 4001, 4002, 4003, 4041],
  10966. [4001, 4010, 4011, 4012, 4013],
  10967. [4000, 4001, 4002, 4003, 4040],
  10968. [4000, 4010, 4011, 4012, 4013],
  10969. [4001, 4002, 4003, 4013, 4023],
  10970. [4000, 4002, 4003, 4013, 4023],
  10971. [4000, 4001, 4003, 4013, 4023],
  10972. [4000, 4001, 4002, 4003, 4033],
  10973. [4000, 4001, 4002, 4003, 4032],
  10974. [4000, 4001, 4002, 4003, 4031],
  10975. [4000, 4001, 4002, 4003, 4030],
  10976. [4000, 4001, 4002, 4003, 4023],
  10977. [4000, 4001, 4002, 4003, 4022],
  10978. [4000, 4001, 4002, 4003, 4021],
  10979. [4000, 4001, 4002, 4003, 4020],
  10980. [4000, 4001, 4002, 4003, 4013],
  10981. [4000, 4001, 4002, 4003, 4012],
  10982. [4000, 4001, 4002, 4003, 4011],
  10983. [4000, 4001, 4002, 4003, 4010],
  10984. ].filter((p) => p.includes(this.mandatoryId));
  10985.  
  10986. const bestPack = {
  10987. pack: packs[0],
  10988. winRate: 0,
  10989. countBattle: 0,
  10990. id: 0,
  10991. };
  10992.  
  10993. for (const id in packs) {
  10994. const pack = packs[id];
  10995. const attackers = this.maxUpgrade.filter((e) => pack.includes(e.id)).reduce((obj, e) => ({ ...obj, [e.id]: e }), {});
  10996. const battle = {
  10997. attackers,
  10998. defenders: [enemieHeroes],
  10999. type: 'brawl_titan',
  11000. };
  11001. const isRandom = this.isRandomBattle(battle);
  11002. const stat = {
  11003. count: 0,
  11004. win: 0,
  11005. winRate: 0,
  11006. };
  11007. for (let i = 1; i <= 20; i++) {
  11008. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  11009. const result = await Calc(battle);
  11010. stat.win += result.result.win;
  11011. stat.count += 1;
  11012. stat.winRate = stat.win / stat.count;
  11013. if (!isRandom || (i >= 2 && stat.winRate < 0.65) || (i >= 10 && stat.winRate == 1)) {
  11014. break;
  11015. }
  11016. }
  11017.  
  11018. if (!isRandom && stat.win) {
  11019. return {
  11020. favor: {},
  11021. heroes: pack,
  11022. };
  11023. }
  11024. if (stat.winRate > 0.85) {
  11025. return {
  11026. favor: {},
  11027. heroes: pack,
  11028. };
  11029. }
  11030. if (stat.winRate > bestPack.winRate) {
  11031. bestPack.countBattle = stat.count;
  11032. bestPack.winRate = stat.winRate;
  11033. bestPack.pack = pack;
  11034. bestPack.id = id;
  11035. }
  11036. }
  11037.  
  11038. //console.log(bestPack.id, bestPack.pack, bestPack.winRate, bestPack.countBattle);
  11039. return {
  11040. favor: {},
  11041. heroes: bestPack.pack,
  11042. };
  11043. }
  11044.  
  11045. isRandomPack(pack) {
  11046. const ids = Object.keys(pack);
  11047. return ids.includes('4023') || ids.includes('4021');
  11048. }
  11049.  
  11050. isRandomBattle(battle) {
  11051. return this.isRandomPack(battle.attackers) || this.isRandomPack(battle.defenders[0]);
  11052. }
  11053.  
  11054. async updateHeroesPack(enemieHeroes) {
  11055. 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}}}];
  11056.  
  11057. const bestPack = {
  11058. pack: packs[0],
  11059. countWin: 0,
  11060. }
  11061.  
  11062. for (const pack of packs) {
  11063. const attackers = pack.attackers;
  11064. const battle = {
  11065. attackers,
  11066. defenders: [enemieHeroes],
  11067. type: 'brawl',
  11068. };
  11069.  
  11070. let countWinBattles = 0;
  11071. let countTestBattle = 10;
  11072. for (let i = 0; i < countTestBattle; i++) {
  11073. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  11074. const result = await Calc(battle);
  11075. if (result.result.win) {
  11076. countWinBattles++;
  11077. }
  11078. if (countWinBattles > 7) {
  11079. console.log(pack)
  11080. return pack.args;
  11081. }
  11082. }
  11083. if (countWinBattles > bestPack.countWin) {
  11084. bestPack.countWin = countWinBattles;
  11085. bestPack.pack = pack.args;
  11086. }
  11087. }
  11088.  
  11089. console.log(bestPack);
  11090. return bestPack.pack;
  11091. }
  11092.  
  11093. async questFarm() {
  11094. const calls = [this.callBrawlQuestFarm];
  11095. const result = await Send(JSON.stringify({ calls }));
  11096. return result.results[0].result.response;
  11097. }
  11098.  
  11099. async getBrawlInfo() {
  11100. const data = await Send(JSON.stringify({
  11101. calls: [
  11102. this.callUserGetInfo,
  11103. this.callBrawlQuestGetInfo,
  11104. this.callBrawlFindEnemies,
  11105. this.callTeamGetMaxUpgrade,
  11106. this.callBrawlGetInfo,
  11107. ]
  11108. }));
  11109.  
  11110. let attempts = data.results[0].result.response.refillable.find(n => n.id == 48);
  11111.  
  11112. const maxUpgrade = data.results[3].result.response;
  11113. const maxHero = Object.values(maxUpgrade.hero);
  11114. const maxTitan = Object.values(maxUpgrade.titan);
  11115. const maxPet = Object.values(maxUpgrade.pet);
  11116. this.maxUpgrade = [...maxHero, ...maxPet, ...maxTitan];
  11117.  
  11118. this.info = data.results[4].result.response;
  11119. this.mandatoryId = lib.data.brawl.promoHero[this.info.id].promoHero;
  11120. return {
  11121. attempts: attempts.amount,
  11122. questInfo: data.results[1].result.response,
  11123. findEnemies: data.results[2].result.response,
  11124. }
  11125. }
  11126.  
  11127. /**
  11128. * Carrying out a fight
  11129. *
  11130. * Проведение боя
  11131. */
  11132. async battle(userId) {
  11133. this.stats.count++;
  11134. const battle = await this.startBattle(userId, this.args);
  11135. const result = await Calc(battle);
  11136. console.log(result.result);
  11137. if (result.result.win) {
  11138. this.stats.win++;
  11139. } else {
  11140. this.stats.loss++;
  11141. if (!this.info.boughtEndlessLivesToday) {
  11142. this.attempts--;
  11143. }
  11144. }
  11145. return await this.endBattle(result);
  11146. // return await this.cancelBattle(result);
  11147. }
  11148.  
  11149. /**
  11150. * Starts a fight
  11151. *
  11152. * Начинает бой
  11153. */
  11154. async startBattle(userId, args) {
  11155. const call = {
  11156. name: "brawl_startBattle",
  11157. args,
  11158. ident: "brawl_startBattle"
  11159. }
  11160. call.args.userId = userId;
  11161. const calls = [call];
  11162. const result = await Send(JSON.stringify({ calls }));
  11163. return result.results[0].result.response;
  11164. }
  11165.  
  11166. cancelBattle(battle) {
  11167. const fixBattle = function (heroes) {
  11168. for (const ids in heroes) {
  11169. const hero = heroes[ids];
  11170. hero.energy = random(1, 999);
  11171. if (hero.hp > 0) {
  11172. hero.hp = random(1, hero.hp);
  11173. }
  11174. }
  11175. }
  11176. fixBattle(battle.progress[0].attackers.heroes);
  11177. fixBattle(battle.progress[0].defenders.heroes);
  11178. return this.endBattle(battle);
  11179. }
  11180.  
  11181. /**
  11182. * Ends the fight
  11183. *
  11184. * Заканчивает бой
  11185. */
  11186. async endBattle(battle) {
  11187. battle.progress[0].attackers.input = ['auto', 0, 0, 'auto', 0, 0];
  11188. const calls = [{
  11189. name: "brawl_endBattle",
  11190. args: {
  11191. result: battle.result,
  11192. progress: battle.progress
  11193. },
  11194. ident: "brawl_endBattle"
  11195. },
  11196. this.callBrawlQuestGetInfo,
  11197. this.callBrawlFindEnemies,
  11198. ];
  11199. const result = await Send(JSON.stringify({ calls }));
  11200. return result.results;
  11201. }
  11202.  
  11203. end(endReason) {
  11204. isCancalBattle = true;
  11205. isBrawlsAutoStart = false;
  11206. setProgress(endReason, true);
  11207. console.log(endReason);
  11208. this.resolve();
  11209. }
  11210. }
  11211.  
  11212. })();
  11213.  
  11214. /**
  11215. * TODO:
  11216. * Получение всех уровней при сборе всех наград (квест на титанит и на энку) +-
  11217. * Добивание на арене титанов
  11218. * Закрытие окошек по Esc +-
  11219. * Починить работу скрипта на уровне команды ниже 10 +-
  11220. * Написать номальную синхронизацию
  11221. * Добавить дополнительные настройки автопокупки в "Тайном богатстве"
  11222. */