HeroWarsHelper

Automation of actions for the game Hero Wars

当前为 2024-05-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name HeroWarsHelper
  3. // @name:en HeroWarsHelper
  4. // @name:ru HeroWarsHelper
  5. // @namespace HeroWarsHelper
  6. // @version 2.252
  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 540 you have {currentStarMoney}',
  405. CHESTS_NOT_AVAILABLE: 'Chests not available',
  406. OUTLAND_CHESTS_RECEIVED: 'Outland chests received',
  407. RAID_NOT_AVAILABLE: 'The raid is not available or there are no spheres',
  408. RAID_ADVENTURE: 'Raid {adventureId} adventure!',
  409. SOMETHING_WENT_WRONG: 'Something went wrong',
  410. ADVENTURE_COMPLETED: 'Adventure {adventureId} completed {times} times',
  411. CLAN_STAT_COPY: 'Clan statistics copied to clipboard',
  412. GET_ENERGY: 'Get Energy',
  413. GET_ENERGY_TITLE: 'Opens platinum boxes one at a time until you get 250 energy',
  414. ITEM_EXCHANGE: 'Item Exchange',
  415. ITEM_EXCHANGE_TITLE: 'Exchanges items for the specified amount of activity',
  416. BUY_SOULS: 'Buy souls',
  417. BUY_SOULS_TITLE: 'Buy hero souls from all available shops',
  418. BUY_OUTLAND: 'Buy Outland',
  419. BUY_OUTLAND_TITLE: 'Buy 9 chests in Outland for 540 emeralds',
  420. RAID: 'Raid',
  421. AUTO_RAID_ADVENTURE: 'Raid adventure',
  422. AUTO_RAID_ADVENTURE_TITLE: 'Raid adventure set number of times',
  423. CLAN_STAT: 'Clan statistics',
  424. CLAN_STAT_TITLE: 'Copies clan statistics to the clipboard',
  425. BTN_AUTO_F5: 'Auto (F5)',
  426. BOSS_DAMAGE: 'Boss Damage: ',
  427. NOTHING_BUY: 'Nothing to buy',
  428. LOTS_BOUGHT: '{countBuy} lots bought for gold',
  429. BUY_FOR_GOLD: 'Buy for gold',
  430. BUY_FOR_GOLD_TITLE: 'Buy items for gold in the Town Shop and in the Pet Soul Stone Shop',
  431. REWARDS_AND_MAIL: 'Rewars and Mail',
  432. REWARDS_AND_MAIL_TITLE: 'Collects rewards and mail',
  433. COLLECT_REWARDS_AND_MAIL: 'Collected {countQuests} rewards and {countMail} letters',
  434. TIMER_ALREADY: 'Timer already started {time}',
  435. NO_ATTEMPTS_TIMER_START: 'No attempts, timer started {time}',
  436. EPIC_BRAWL_RESULT: 'Wins: {wins}/{attempts}, Coins: {coins}, Streak: {progress}/{nextStage} [Close]{end}',
  437. ATTEMPT_ENDED: '<br>Attempts ended, timer started {time}',
  438. EPIC_BRAWL: 'Cosmic Battle',
  439. EPIC_BRAWL_TITLE: 'Spends attempts in the Cosmic Battle',
  440. RELOAD_GAME: 'Reload game',
  441. TIMER: 'Timer:',
  442. SHOW_ERRORS: 'Show errors',
  443. SHOW_ERRORS_TITLE: 'Show server request errors',
  444. ERROR_MSG: 'Error: {name}<br>{description}',
  445. EVENT_AUTO_BOSS:
  446. '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?',
  447. BEST_SLOW: 'Best (slower)',
  448. FIRST_FAST: 'First (faster)',
  449. FREEZE_INTERFACE: 'Calculating... <br>The interface may freeze.',
  450. ERROR_F12: 'Error, details in the console (F12)',
  451. FAILED_FIND_WIN_PACK: 'Failed to find a winning pack',
  452. BEST_PACK: 'Best pack:',
  453. BOSS_HAS_BEEN_DEF: 'Boss {bossLvl} has been defeated.',
  454. NOT_ENOUGH_ATTEMPTS_BOSS: 'Not enough attempts to defeat boss {bossLvl}, retry?',
  455. BOSS_VICTORY_IMPOSSIBLE:
  456. '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?',
  457. BOSS_HAS_BEEN_DEF_TEXT:
  458. 'Boss {bossLvl} defeated in<br>{countBattle}/{countMaxBattle} attempts<br>(Please synchronize or restart the game to update the data)',
  459. MAP: 'Map: ',
  460. PLAYER_POS: 'Player positions:',
  461. NY_GIFTS: 'Gifts',
  462. NY_GIFTS_TITLE: "Open all New Year's gifts",
  463. NY_NO_GIFTS: 'No gifts not received',
  464. NY_GIFTS_COLLECTED: '{count} gifts collected',
  465. CHANGE_MAP: 'Island map',
  466. CHANGE_MAP_TITLE: 'Change island map',
  467. SELECT_ISLAND_MAP: 'Select an island map:',
  468. MAP_NUM: 'Map {num}',
  469. SECRET_WEALTH_SHOP: 'Secret Wealth {name}: ',
  470. SHOPS: 'Shops',
  471. SHOPS_DEFAULT: 'Default',
  472. SHOPS_DEFAULT_TITLE: 'Default stores',
  473. SHOPS_LIST: 'Shops {number}',
  474. SHOPS_LIST_TITLE: 'List of shops {number}',
  475. SHOPS_WARNING:
  476. '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>',
  477. MINIONS_WARNING: 'The hero packs for attacking minions are incomplete, should I continue?',
  478. FAST_SEASON: 'Fast season',
  479. FAST_SEASON_TITLE: 'Skip the map selection screen in a season',
  480. SET_NUMBER_LEVELS: 'Specify the number of levels:',
  481. POSSIBLE_IMPROVE_LEVELS: 'It is possible to improve only {count} levels.<br>Improving?',
  482. NOT_ENOUGH_RESOURECES: 'Not enough resources',
  483. IMPROVED_LEVELS: 'Improved levels: {count}',
  484. ARTIFACTS_UPGRADE: 'Artifacts Upgrade',
  485. ARTIFACTS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero artifacts',
  486. SKINS_UPGRADE: 'Skins Upgrade',
  487. SKINS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero skins',
  488. HINT: '<br>Hint: ',
  489. PICTURE: '<br>Picture: ',
  490. ANSWER: '<br>Answer: ',
  491. NO_HEROES_PACK: 'Fight at least one battle to save the attacking team',
  492. BRAWL_AUTO_PACK: 'Automatic selection of packs',
  493. },
  494. ru: {
  495. /* Чекбоксы */
  496. SKIP_FIGHTS: 'Пропуск боев',
  497. SKIP_FIGHTS_TITLE: 'Пропуск боев в запределье и арене титанов, автопропуск в башне и кампании',
  498. ENDLESS_CARDS: 'Бесконечные карты',
  499. ENDLESS_CARDS_TITLE: 'Отключить трату карт предсказаний',
  500. AUTO_EXPEDITION: 'АвтоЭкспедиции',
  501. AUTO_EXPEDITION_TITLE: 'Автоотправка экспедиций',
  502. CANCEL_FIGHT: 'Отмена боя',
  503. CANCEL_FIGHT_TITLE: 'Возможность отмены ручного боя на ВГ, СМ и в Асгарде',
  504. GIFTS: 'Подарки',
  505. GIFTS_TITLE: 'Собирать подарки автоматически',
  506. BATTLE_RECALCULATION: 'Прерасчет боя',
  507. BATTLE_RECALCULATION_TITLE: 'Предварительный расчет боя',
  508. QUANTITY_CONTROL: 'Контроль кол-ва',
  509. QUANTITY_CONTROL_TITLE: 'Возможность указывать количество открываемых "лутбоксов"',
  510. REPEAT_CAMPAIGN: 'Повтор в кампании',
  511. REPEAT_CAMPAIGN_TITLE: 'Автоповтор боев в кампании',
  512. DISABLE_DONAT: 'Отключить донат',
  513. DISABLE_DONAT_TITLE: 'Убирает все предложения доната',
  514. DAILY_QUESTS: 'Квесты',
  515. DAILY_QUESTS_TITLE: 'Выполнять ежедневные квесты',
  516. AUTO_QUIZ: 'АвтоВикторина',
  517. AUTO_QUIZ_TITLE: 'Автоматическое получение правильных ответов на вопросы викторины',
  518. SECRET_WEALTH_CHECKBOX: 'Автоматическая покупка в магазине "Тайное Богатство" при заходе в игру',
  519. HIDE_SERVERS: 'Свернуть сервера',
  520. HIDE_SERVERS_TITLE: 'Скрывать неиспользуемые сервера',
  521. /* Поля ввода */
  522. HOW_MUCH_TITANITE: 'Сколько фармим титанита',
  523. COMBAT_SPEED: 'Множитель ускорения боя',
  524. NUMBER_OF_TEST: 'Количество тестовых боев',
  525. NUMBER_OF_AUTO_BATTLE: 'Количество попыток автобоев',
  526. /* Кнопки */
  527. RUN_SCRIPT: 'Запустить скрипт',
  528. TO_DO_EVERYTHING: 'Сделать все',
  529. TO_DO_EVERYTHING_TITLE: 'Выполнить несколько действий',
  530. OUTLAND: 'Запределье',
  531. OUTLAND_TITLE: 'Собрать Запределье',
  532. TITAN_ARENA: 'Турнир Стихий',
  533. TITAN_ARENA_TITLE: 'Автопрохождение Турнира Стихий',
  534. DUNGEON: 'Подземелье',
  535. DUNGEON_TITLE: 'Автопрохождение подземелья',
  536. SEER: 'Провидец',
  537. SEER_TITLE: 'Покрутить Провидца',
  538. TOWER: 'Башня',
  539. TOWER_TITLE: 'Автопрохождение башни',
  540. EXPEDITIONS: 'Экспедиции',
  541. EXPEDITIONS_TITLE: 'Отправка и сбор экспедиций',
  542. SYNC: 'Синхронизация',
  543. SYNC_TITLE: 'Частичная синхронизация данных игры без перезагрузки сатраницы',
  544. ARCHDEMON: 'Архидемон',
  545. ARCHDEMON_TITLE: 'Набивает килы и собирает награду',
  546. ESTER_EGGS: 'Пасхалки',
  547. ESTER_EGGS_TITLE: 'Собрать все пасхалки или награды',
  548. REWARDS: 'Награды',
  549. REWARDS_TITLE: 'Собрать все награды за задания',
  550. MAIL: 'Почта',
  551. MAIL_TITLE: 'Собрать всю почту, кроме писем с энергией и зарядами портала',
  552. MINIONS: 'Прислужники',
  553. MINIONS_TITLE: 'Атакует прислужников сохраннеными пачками',
  554. ADVENTURE: 'Приключение',
  555. ADVENTURE_TITLE: 'Проходит приключение по указанному маршруту',
  556. STORM: 'Буря',
  557. STORM_TITLE: 'Проходит бурю по указанному маршруту',
  558. SANCTUARY: 'Святилище',
  559. SANCTUARY_TITLE: 'Быстрый переход к Святилищу',
  560. GUILD_WAR: 'Война гильдий',
  561. GUILD_WAR_TITLE: 'Быстрый переход к Войне гильдий',
  562. SECRET_WEALTH: 'Тайное богатство',
  563. SECRET_WEALTH_TITLE: 'Купить что-то в магазине "Тайное богатство"',
  564. /* Разное */
  565. BOTTOM_URLS:
  566. '<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>',
  567. GIFTS_SENT: 'Подарки отправлены!',
  568. DO_YOU_WANT: 'Вы действительно хотите это сделать?',
  569. BTN_RUN: 'Запускай',
  570. BTN_CANCEL: 'Отмена',
  571. BTN_OK: 'Ок',
  572. MSG_HAVE_BEEN_DEFEATED: 'Вы потерпели поражение!',
  573. BTN_AUTO: 'Авто',
  574. MSG_YOU_APPLIED: 'Вы нанесли',
  575. MSG_DAMAGE: 'урона',
  576. MSG_CANCEL_AND_STAT: 'Авто (F5) и показать Статистику',
  577. MSG_REPEAT_MISSION: 'Повторить миссию?',
  578. BTN_REPEAT: 'Повторить',
  579. BTN_NO: 'Нет',
  580. MSG_SPECIFY_QUANT: 'Указать количество:',
  581. BTN_OPEN: 'Открыть',
  582. QUESTION_COPY: 'Вопрос скопирован в буфер обмена',
  583. ANSWER_KNOWN: 'Ответ известен',
  584. ANSWER_NOT_KNOWN: 'ВНИМАНИЕ ОТВЕТ НЕ ИЗВЕСТЕН',
  585. BEING_RECALC: 'Идет прерасчет боя',
  586. THIS_TIME: 'На этот раз',
  587. VICTORY: '<span style="color:green;">ПОБЕДА</span>',
  588. DEFEAT: '<span style="color:red;">ПОРАЖЕНИЕ</span>',
  589. CHANCE_TO_WIN: 'Шансы на победу <span style="color:red;">на основе прерасчета</span>',
  590. OPEN_DOLLS: 'матрешек рекурсивно',
  591. SENT_QUESTION: 'Вопрос отправлен',
  592. SETTINGS: 'Настройки',
  593. MSG_BAN_ATTENTION: '<p style="color:red;">Использование этой функции может привести к бану.</p> Продолжить?',
  594. BTN_YES_I_AGREE: 'Да, я беру на себя все риски!',
  595. BTN_NO_I_AM_AGAINST: 'Нет, я отказываюсь от этого!',
  596. VALUES: 'Значения',
  597. EXPEDITIONS_SENT: 'Экспедиции:<br>Собрано: {countGet}<br>Отправлено: {countSend}',
  598. EXPEDITIONS_NOTHING: 'Нечего собирать/отправлять',
  599. TITANIT: 'Титанит',
  600. COMPLETED: 'завершено',
  601. FLOOR: 'Этаж',
  602. LEVEL: 'Уровень',
  603. BATTLES: 'бои',
  604. EVENT: 'Эвент',
  605. NOT_AVAILABLE: 'недоступен',
  606. NO_HEROES: 'Нет героев',
  607. DAMAGE_AMOUNT: 'Количество урона',
  608. NOTHING_TO_COLLECT: 'Нечего собирать',
  609. COLLECTED: 'Собрано',
  610. REWARD: 'наград',
  611. REMAINING_ATTEMPTS: 'Осталось попыток',
  612. BATTLES_CANCELED: 'Битв отменено',
  613. MINION_RAID: 'Рейд прислужников',
  614. STOPPED: 'Остановлено',
  615. REPETITIONS: 'Повторений',
  616. MISSIONS_PASSED: 'Миссий пройдено',
  617. STOP: 'остановить',
  618. TOTAL_OPEN: 'Всего открыто',
  619. OPEN: 'Открыто',
  620. ROUND_STAT: 'Статистика урона за',
  621. BATTLE: 'боев',
  622. MINIMUM: 'Минимальный',
  623. MAXIMUM: 'Максимальный',
  624. AVERAGE: 'Средний',
  625. NOT_THIS_TIME: 'Не в этот раз',
  626. RETRY_LIMIT_EXCEEDED: 'Превышен лимит попыток',
  627. SUCCESS: 'Успех',
  628. RECEIVED: 'Получено',
  629. LETTERS: 'писем',
  630. PORTALS: 'порталов',
  631. ATTEMPTS: 'попыток',
  632. QUEST_10001: 'Улучши умения героев 3 раза',
  633. QUEST_10002: 'Пройди 10 миссий',
  634. QUEST_10003: 'Пройди 3 героические миссии',
  635. QUEST_10004: 'Сразись 3 раза на Арене или Гранд Арене',
  636. QUEST_10006: 'Используй обмен изумрудов 1 раз',
  637. QUEST_10007: 'Соверши 1 призыв в Атриуме Душ',
  638. QUEST_10016: 'Отправь подарки согильдийцам',
  639. QUEST_10018: 'Используй зелье опыта',
  640. QUEST_10019: 'Открой 1 сундук в Башне',
  641. QUEST_10020: 'Открой 3 сундука в Запределье',
  642. QUEST_10021: 'Собери 75 Титанита в Подземелье Гильдии',
  643. QUEST_10021: 'Собери 150 Титанита в Подземелье Гильдии',
  644. QUEST_10023: 'Прокачай Дар Стихий на 1 уровень',
  645. QUEST_10024: 'Повысь уровень любого артефакта один раз',
  646. QUEST_10025: 'Начни 1 Экспедицию',
  647. QUEST_10026: 'Начни 4 Экспедиции',
  648. QUEST_10027: 'Победи в 1 бою Турнира Стихий',
  649. QUEST_10028: 'Повысь уровень любого артефакта титанов',
  650. QUEST_10029: 'Открой сферу артефактов титанов',
  651. QUEST_10030: 'Улучши облик любого героя 1 раз',
  652. QUEST_10031: 'Победи в 6 боях Турнира Стихий',
  653. QUEST_10043: 'Начни или присоеденись к Приключению',
  654. QUEST_10044: 'Воспользуйся призывом питомцев 1 раз',
  655. QUEST_10046: 'Открой 3 сундука в Приключениях',
  656. QUEST_10047: 'Набери 150 очков активности в Гильдии',
  657. NOTHING_TO_DO: 'Нечего выполнять',
  658. YOU_CAN_COMPLETE: 'Можно выполнить квесты',
  659. BTN_DO_IT: 'Выполняй',
  660. NOT_QUEST_COMPLETED: 'Ни одного квеста не выполенно',
  661. COMPLETED_QUESTS: 'Выполнено квестов',
  662. /* everything button */
  663. ASSEMBLE_OUTLAND: 'Собрать Запределье',
  664. PASS_THE_TOWER: 'Пройти башню',
  665. CHECK_EXPEDITIONS: 'Проверить экспедиции',
  666. COMPLETE_TOE: 'Пройти Турнир Стихий',
  667. COMPLETE_DUNGEON: 'Пройти подземелье',
  668. COLLECT_MAIL: 'Собрать почту',
  669. COLLECT_MISC: 'Собрать всякую херню',
  670. COLLECT_MISC_TITLE: 'Собрать пасхалки, камни облика, ключи, монеты арены и Хрусталь души',
  671. COLLECT_QUEST_REWARDS: 'Собрать награды за квесты',
  672. MAKE_A_SYNC: 'Сделать синхронизацию',
  673.  
  674. RUN_FUNCTION: 'Выполнить следующие функции?',
  675. BTN_GO: 'Погнали!',
  676. PERFORMED: 'Выполняется',
  677. DONE: 'Выполнено',
  678. ERRORS_OCCURRES: 'Призошли ошибки при выполнении',
  679. COPY_ERROR: 'Скопировать в буфер информацию об ошибке',
  680. BTN_YES: 'Да',
  681. ALL_TASK_COMPLETED: 'Все задачи выполнены',
  682.  
  683. UNKNOWN: 'Неизвестно',
  684. ENTER_THE_PATH: 'Введите путь приключения через запятые или дефисы',
  685. START_ADVENTURE: 'Начать приключение по этому пути!',
  686. INCORRECT_WAY: 'Неверный путь в приключении: {from} -> {to}',
  687. BTN_CANCELED: 'Отменено',
  688. MUST_TWO_POINTS: 'Путь должен состоять минимум из 2х точек',
  689. MUST_ONLY_NUMBERS: 'Путь должен содержать только цифры и запятые',
  690. NOT_ON_AN_ADVENTURE: 'Вы не в приключении',
  691. YOU_IN_NOT_ON_THE_WAY: 'Указанный путь должен включать точку вашего положения',
  692. ATTEMPTS_NOT_ENOUGH: 'Ваших попыток не достаточно для завершения пути, продолжить?',
  693. YES_CONTINUE: 'Да, продолжай!',
  694. NOT_ENOUGH_AP: 'Попыток не достаточно',
  695. ATTEMPTS_ARE_OVER: 'Попытки закончились',
  696. MOVES: 'Ходы',
  697. BUFF_GET_ERROR: 'Ошибка при получении бафа',
  698. BATTLE_END_ERROR: 'Ошибка завершения боя',
  699. AUTOBOT: 'АвтоБой',
  700. FAILED_TO_WIN_AUTO: 'Не удалось победить в автобою',
  701. ERROR_OF_THE_BATTLE_COPY: 'Призошли ошибка в процессе прохождения боя<br>Скопировать ошибку в буфер обмена?',
  702. ERROR_DURING_THE_BATTLE: 'Ошибка в процессе прохождения боя',
  703. NO_CHANCE_WIN: 'Нет шансов победить в этом бою: 0/',
  704. LOST_HEROES: 'Вы победили, но потеряли одного или несколько героев!',
  705. VICTORY_IMPOSSIBLE: 'Победа не возможна, бъем на результат?',
  706. FIND_COEFF: 'Поиск коэффициента больше чем',
  707. BTN_PASS: 'ПРОПУСК',
  708. BRAWLS: 'Потасовки',
  709. BRAWLS_TITLE: 'Включает возможность автопотасовок',
  710. START_AUTO_BRAWLS: 'Запустить Автопотасовки?',
  711. LOSSES: 'Поражений',
  712. WINS: 'Побед',
  713. FIGHTS: 'Боев',
  714. STAGE: 'Стадия',
  715. DONT_HAVE_LIVES: 'У Вас нет жизней',
  716. LIVES: 'Жизни',
  717. SECRET_WEALTH_ALREADY: 'товар за Зелья питомцев уже куплен',
  718. SECRET_WEALTH_NOT_ENOUGH: 'Не достаточно Зелье Питомца, у Вас {available}, нужно {need}',
  719. SECRET_WEALTH_UPGRADE_NEW_PET: 'После покупки Зелье Питомца будет не достаточно для прокачки нового питомца',
  720. SECRET_WEALTH_PURCHASED: 'Куплено {count} {name}',
  721. SECRET_WEALTH_CANCELED: 'Тайное богатство: покупка отменена',
  722. SECRET_WEALTH_BUY: 'У вас {available} Зелье Питомца.<br>Вы хотите купить {countBuy} {name} за {price} Зелье Питомца?',
  723. DAILY_BONUS: 'Ежедневная награда',
  724. DO_DAILY_QUESTS: 'Сделать ежедневные квесты',
  725. ACTIONS: 'Действия',
  726. ACTIONS_TITLE: 'Диалоговое окно с различными действиями',
  727. OTHERS: 'Разное',
  728. OTHERS_TITLE: 'Диалоговое окно с дополнительными различными действиями',
  729. CHOOSE_ACTION: 'Выберите действие',
  730. OPEN_LOOTBOX: 'У Вас {lootBox} ящиков, откываем?',
  731. STAMINA: 'Энергия',
  732. BOXES_OVER: 'Ящики закончились',
  733. NO_BOXES: 'Нет ящиков',
  734. NO_MORE_ACTIVITY: 'Больше активности за предметы сегодня не получить',
  735. EXCHANGE_ITEMS: 'Обменять предметы на очки активности (не более {maxActive})?',
  736. GET_ACTIVITY: 'Получить активность',
  737. NOT_ENOUGH_ITEMS: 'Предметов недостаточно',
  738. ACTIVITY_RECEIVED: 'Получено активности',
  739. NO_PURCHASABLE_HERO_SOULS: 'Нет доступных для покупки душ героев',
  740. PURCHASED_HERO_SOULS: 'Куплено {countHeroSouls} душ героев',
  741. NOT_ENOUGH_EMERALDS_540: 'Недостаточно изюма, нужно 540 у Вас {currentStarMoney}',
  742. CHESTS_NOT_AVAILABLE: 'Сундуки не доступны',
  743. OUTLAND_CHESTS_RECEIVED: 'Получено сундуков Запределья',
  744. RAID_NOT_AVAILABLE: 'Рейд не доступен или сфер нет',
  745. RAID_ADVENTURE: 'Рейд {adventureId} приключения!',
  746. SOMETHING_WENT_WRONG: 'Что-то пошло не так',
  747. ADVENTURE_COMPLETED: 'Приключение {adventureId} пройдено {times} раз',
  748. CLAN_STAT_COPY: 'Клановая статистика скопирована в буфер обмена',
  749. GET_ENERGY: 'Получить энергию',
  750. GET_ENERGY_TITLE: 'Открывает платиновые шкатулки по одной до получения 250 энергии',
  751. ITEM_EXCHANGE: 'Обмен предметов',
  752. ITEM_EXCHANGE_TITLE: 'Обменивает предметы на указанное количество активности',
  753. BUY_SOULS: 'Купить души',
  754. BUY_SOULS_TITLE: 'Купить души героев из всех доступных магазинов',
  755. BUY_OUTLAND: 'Купить Запределье',
  756. BUY_OUTLAND_TITLE: 'Купить 9 сундуков в Запределье за 540 изумрудов',
  757. RAID: 'Рейд',
  758. AUTO_RAID_ADVENTURE: 'Рейд приключения',
  759. AUTO_RAID_ADVENTURE_TITLE: 'Рейд приключения заданное количество раз',
  760. CLAN_STAT: 'Клановая статистика',
  761. CLAN_STAT_TITLE: 'Копирует клановую статистику в буфер обмена',
  762. BTN_AUTO_F5: 'Авто (F5)',
  763. BOSS_DAMAGE: 'Урон по боссу: ',
  764. NOTHING_BUY: 'Нечего покупать',
  765. LOTS_BOUGHT: 'За золото куплено {countBuy} лотов',
  766. BUY_FOR_GOLD: 'Скупить за золото',
  767. BUY_FOR_GOLD_TITLE: 'Скупить предметы за золото в Городской лавке и в магазине Камней Душ Питомцев',
  768. REWARDS_AND_MAIL: 'Награды и почта',
  769. REWARDS_AND_MAIL_TITLE: 'Собирает награды и почту',
  770. COLLECT_REWARDS_AND_MAIL: 'Собрано {countQuests} наград и {countMail} писем',
  771. TIMER_ALREADY: 'Таймер уже запущен {time}',
  772. NO_ATTEMPTS_TIMER_START: 'Попыток нет, запущен таймер {time}',
  773. EPIC_BRAWL_RESULT: '{i} Победы: {wins}/{attempts}, Монеты: {coins}, Серия: {progress}/{nextStage} [Закрыть]{end}',
  774. ATTEMPT_ENDED: '<br>Попытки закончились, запущен таймер {time}',
  775. EPIC_BRAWL: 'Вселенская битва',
  776. EPIC_BRAWL_TITLE: 'Тратит попытки во Вселенской битве',
  777. RELOAD_GAME: 'Перезагрузить игру',
  778. TIMER: 'Таймер:',
  779. SHOW_ERRORS: 'Отображать ошибки',
  780. SHOW_ERRORS_TITLE: 'Отображать ошибки запросов к серверу',
  781. ERROR_MSG: 'Ошибка: {name}<br>{description}',
  782. EVENT_AUTO_BOSS:
  783. 'Максимальное количество боев для расчета:</br>{length} * {countTestBattle} = {maxCalcBattle}</br>Если у Вас слабый компьютер на это может потребоваться много времени, нажмите крестик для отмены.</br>Искать лучший пак из всех или первый подходящий?',
  784. BEST_SLOW: 'Лучший (медленее)',
  785. FIRST_FAST: 'Первый (быстрее)',
  786. FREEZE_INTERFACE: 'Идет расчет... <br> Интерфейс может зависнуть.',
  787. ERROR_F12: 'Ошибка, подробности в консоли (F12)',
  788. FAILED_FIND_WIN_PACK: 'Победный пак найти не удалось',
  789. BEST_PACK: 'Наилучший пак: ',
  790. BOSS_HAS_BEEN_DEF: 'Босс {bossLvl} побежден',
  791. NOT_ENOUGH_ATTEMPTS_BOSS: 'Для победы босса ${bossLvl} не хватило попыток, повторить?',
  792. BOSS_VICTORY_IMPOSSIBLE:
  793. 'По результатам прерасчета {battles} боев победу получить не удалось. Вы хотите продолжить поиск победного боя на реальных боях?',
  794. BOSS_HAS_BEEN_DEF_TEXT:
  795. 'Босс {bossLvl} побежден за<br>{countBattle}/{countMaxBattle} попыток<br>(Сделайте синхронизацию или перезагрузите игру для обновления данных)',
  796. MAP: 'Карта: ',
  797. PLAYER_POS: 'Позиции игроков:',
  798. NY_GIFTS: 'Подарки',
  799. NY_GIFTS_TITLE: 'Открыть все новогодние подарки',
  800. NY_NO_GIFTS: 'Нет не полученных подарков',
  801. NY_GIFTS_COLLECTED: 'Собрано {count} подарков',
  802. CHANGE_MAP: 'Карта острова',
  803. CHANGE_MAP_TITLE: 'Сменить карту острова',
  804. SELECT_ISLAND_MAP: 'Выберите карту острова:',
  805. MAP_NUM: 'Карта {num}',
  806. SECRET_WEALTH_SHOP: 'Тайное богатство {name}: ',
  807. SHOPS: 'Магазины',
  808. SHOPS_DEFAULT: 'Стандартные',
  809. SHOPS_DEFAULT_TITLE: 'Стандартные магазины',
  810. SHOPS_LIST: 'Магазины {number}',
  811. SHOPS_LIST_TITLE: 'Список магазинов {number}',
  812. SHOPS_WARNING:
  813. 'Магазины<br><span style="color:red">Если Вы купите монеты магазинов потасовок за изумруды, то их надо использовать сразу, иначе после перезагрузки игры они пропадут!</span>',
  814. MINIONS_WARNING: 'Пачки героев для атаки приспешников неполные, продолжить?',
  815. FAST_SEASON: 'Быстрый сезон',
  816. FAST_SEASON_TITLE: 'Пропуск экрана с выбором карты в сезоне',
  817. SET_NUMBER_LEVELS: 'Указать колличество уровней:',
  818. POSSIBLE_IMPROVE_LEVELS: 'Возможно улучшить только {count} уровней.<br>Улучшаем?',
  819. NOT_ENOUGH_RESOURECES: 'Не хватает ресурсов',
  820. IMPROVED_LEVELS: 'Улучшено уровней: {count}',
  821. ARTIFACTS_UPGRADE: 'Улучшение артефактов',
  822. ARTIFACTS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых артефактов героев',
  823. SKINS_UPGRADE: 'Улучшение обликов',
  824. SKINS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых обликов героев',
  825. HINT: '<br>Подсказка: ',
  826. PICTURE: '<br>На картинке: ',
  827. ANSWER: '<br>Ответ: ',
  828. NO_HEROES_PACK: 'Проведите хотя бы один бой для сохранения атакующей команды',
  829. BRAWL_AUTO_PACK: 'Автоподбор пачки',
  830. },
  831. };
  832.  
  833. function getLang() {
  834. let lang = '';
  835. if (typeof NXFlashVars !== 'undefined') {
  836. lang = NXFlashVars.interface_lang
  837. }
  838. if (!lang) {
  839. lang = (navigator.language || navigator.userLanguage).substr(0, 2);
  840. }
  841. if (lang == 'ru') {
  842. return lang;
  843. }
  844. return 'en';
  845. }
  846.  
  847. this.I18N = function (constant, replace) {
  848. const selectLang = getLang();
  849. if (constant && constant in i18nLangData[selectLang]) {
  850. const result = i18nLangData[selectLang][constant];
  851. if (replace) {
  852. return result.sprintf(replace);
  853. }
  854. return result;
  855. }
  856. return `% ${constant} %`;
  857. };
  858.  
  859. String.prototype.sprintf = String.prototype.sprintf ||
  860. function () {
  861. "use strict";
  862. var str = this.toString();
  863. if (arguments.length) {
  864. var t = typeof arguments[0];
  865. var key;
  866. var args = ("string" === t || "number" === t) ?
  867. Array.prototype.slice.call(arguments)
  868. : arguments[0];
  869.  
  870. for (key in args) {
  871. str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
  872. }
  873. }
  874.  
  875. return str;
  876. };
  877.  
  878. /**
  879. * Checkboxes
  880. *
  881. * Чекбоксы
  882. */
  883. const checkboxes = {
  884. passBattle: {
  885. label: I18N('SKIP_FIGHTS'),
  886. cbox: null,
  887. title: I18N('SKIP_FIGHTS_TITLE'),
  888. default: false
  889. },
  890. sendExpedition: {
  891. label: I18N('AUTO_EXPEDITION'),
  892. cbox: null,
  893. title: I18N('AUTO_EXPEDITION_TITLE'),
  894. default: false
  895. },
  896. cancelBattle: {
  897. label: I18N('CANCEL_FIGHT'),
  898. cbox: null,
  899. title: I18N('CANCEL_FIGHT_TITLE'),
  900. default: false,
  901. },
  902. preCalcBattle: {
  903. label: I18N('BATTLE_RECALCULATION'),
  904. cbox: null,
  905. title: I18N('BATTLE_RECALCULATION_TITLE'),
  906. default: false
  907. },
  908. countControl: {
  909. label: I18N('QUANTITY_CONTROL'),
  910. cbox: null,
  911. title: I18N('QUANTITY_CONTROL_TITLE'),
  912. default: true
  913. },
  914. repeatMission: {
  915. label: I18N('REPEAT_CAMPAIGN'),
  916. cbox: null,
  917. title: I18N('REPEAT_CAMPAIGN_TITLE'),
  918. default: false
  919. },
  920. noOfferDonat: {
  921. label: I18N('DISABLE_DONAT'),
  922. cbox: null,
  923. title: I18N('DISABLE_DONAT_TITLE'),
  924. /**
  925. * A crutch to get the field before getting the character id
  926. *
  927. * Костыль чтоб получать поле до получения id персонажа
  928. */
  929. default: (() => {
  930. $result = false;
  931. try {
  932. $result = JSON.parse(localStorage[GM_info.script.name + ':noOfferDonat'])
  933. } catch(e) {
  934. $result = false;
  935. }
  936. return $result || false;
  937. })(),
  938. },
  939. dailyQuests: {
  940. label: I18N('DAILY_QUESTS'),
  941. cbox: null,
  942. title: I18N('DAILY_QUESTS_TITLE'),
  943. default: false
  944. },
  945. // Потасовки
  946. autoBrawls: {
  947. label: I18N('BRAWLS'),
  948. cbox: null,
  949. title: I18N('BRAWLS_TITLE'),
  950. default: (() => {
  951. $result = false;
  952. try {
  953. $result = JSON.parse(localStorage[GM_info.script.name + ':autoBrawls'])
  954. } catch (e) {
  955. $result = false;
  956. }
  957. return $result || false;
  958. })(),
  959. hide: false,
  960. },
  961. getAnswer: {
  962. label: I18N('AUTO_QUIZ'),
  963. cbox: null,
  964. title: I18N('AUTO_QUIZ_TITLE'),
  965. default: false,
  966. hide: true,
  967. },
  968. showErrors: {
  969. label: I18N('SHOW_ERRORS'),
  970. cbox: null,
  971. title: I18N('SHOW_ERRORS_TITLE'),
  972. default: true
  973. },
  974. buyForGold: {
  975. label: I18N('BUY_FOR_GOLD'),
  976. cbox: null,
  977. title: I18N('BUY_FOR_GOLD_TITLE'),
  978. default: false
  979. },
  980. hideServers: {
  981. label: I18N('HIDE_SERVERS'),
  982. cbox: null,
  983. title: I18N('HIDE_SERVERS_TITLE'),
  984. default: false
  985. },
  986. fastSeason: {
  987. label: I18N('FAST_SEASON'),
  988. cbox: null,
  989. title: I18N('FAST_SEASON_TITLE'),
  990. default: false
  991. },
  992. };
  993. /**
  994. * Get checkbox state
  995. *
  996. * Получить состояние чекбокса
  997. */
  998. function isChecked(checkBox) {
  999. if (!(checkBox in checkboxes)) {
  1000. return false;
  1001. }
  1002. return checkboxes[checkBox].cbox?.checked;
  1003. }
  1004. /**
  1005. * Input fields
  1006. *
  1007. * Поля ввода
  1008. */
  1009. const inputs = {
  1010. countTitanit: {
  1011. input: null,
  1012. title: I18N('HOW_MUCH_TITANITE'),
  1013. default: 150,
  1014. },
  1015. speedBattle: {
  1016. input: null,
  1017. title: I18N('COMBAT_SPEED'),
  1018. default: 5,
  1019. },
  1020. countTestBattle: {
  1021. input: null,
  1022. title: I18N('NUMBER_OF_TEST'),
  1023. default: 10,
  1024. },
  1025. countAutoBattle: {
  1026. input: null,
  1027. title: I18N('NUMBER_OF_AUTO_BATTLE'),
  1028. default: 10,
  1029. },
  1030. FPS: {
  1031. input: null,
  1032. title: 'FPS',
  1033. default: 60,
  1034. }
  1035. }
  1036. /**
  1037. * Checks the checkbox
  1038. *
  1039. * Поплучить данные поля ввода
  1040. */
  1041. function getInput(inputName) {
  1042. return inputs[inputName]?.input?.value;
  1043. }
  1044.  
  1045. /**
  1046. * Control FPS
  1047. *
  1048. * Контроль FPS
  1049. */
  1050. let nextAnimationFrame = Date.now();
  1051. const oldRequestAnimationFrame = this.requestAnimationFrame;
  1052. this.requestAnimationFrame = async function (e) {
  1053. const FPS = Number(getInput('FPS')) || -1;
  1054. const now = Date.now();
  1055. const delay = nextAnimationFrame - now;
  1056. nextAnimationFrame = Math.max(now, nextAnimationFrame) + Math.min(1e3 / FPS, 1e3);
  1057. if (delay > 0) {
  1058. await new Promise((e) => setTimeout(e, delay));
  1059. }
  1060. oldRequestAnimationFrame(e);
  1061. };
  1062. /**
  1063. * Button List
  1064. *
  1065. * Список кнопочек
  1066. */
  1067. const buttons = {
  1068. getOutland: {
  1069. name: I18N('TO_DO_EVERYTHING'),
  1070. title: I18N('TO_DO_EVERYTHING_TITLE'),
  1071. func: testDoYourBest,
  1072. },
  1073. doActions: {
  1074. name: I18N('ACTIONS'),
  1075. title: I18N('ACTIONS_TITLE'),
  1076. func: async function () {
  1077. const popupButtons = [
  1078. {
  1079. msg: I18N('OUTLAND'),
  1080. result: function () {
  1081. confShow(`${I18N('RUN_SCRIPT')} ${I18N('OUTLAND')}?`, getOutland);
  1082. },
  1083. title: I18N('OUTLAND_TITLE'),
  1084. },
  1085. {
  1086. msg: I18N('TOWER'),
  1087. result: function () {
  1088. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TOWER')}?`, testTower);
  1089. },
  1090. title: I18N('TOWER_TITLE'),
  1091. },
  1092. {
  1093. msg: I18N('EXPEDITIONS'),
  1094. result: function () {
  1095. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EXPEDITIONS')}?`, checkExpedition);
  1096. },
  1097. title: I18N('EXPEDITIONS_TITLE'),
  1098. },
  1099. {
  1100. msg: I18N('MINIONS'),
  1101. result: function () {
  1102. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MINIONS')}?`, testRaidNodes);
  1103. },
  1104. title: I18N('MINIONS_TITLE'),
  1105. },
  1106. {
  1107. msg: I18N('ESTER_EGGS'),
  1108. result: function () {
  1109. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ESTER_EGGS')}?`, offerFarmAllReward);
  1110. },
  1111. title: I18N('ESTER_EGGS_TITLE'),
  1112. },
  1113. {
  1114. msg: I18N('STORM'),
  1115. result: function () {
  1116. testAdventure('solo');
  1117. },
  1118. title: I18N('STORM_TITLE'),
  1119. },
  1120. {
  1121. msg: I18N('REWARDS'),
  1122. result: function () {
  1123. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS')}?`, questAllFarm);
  1124. },
  1125. title: I18N('REWARDS_TITLE'),
  1126. },
  1127. {
  1128. msg: I18N('MAIL'),
  1129. result: function () {
  1130. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MAIL')}?`, mailGetAll);
  1131. },
  1132. title: I18N('MAIL_TITLE'),
  1133. },
  1134. {
  1135. msg: I18N('SEER'),
  1136. result: function () {
  1137. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SEER')}?`, rollAscension);
  1138. },
  1139. title: I18N('SEER_TITLE'),
  1140. },
  1141. /*
  1142. {
  1143. msg: I18N('NY_GIFTS'),
  1144. result: getGiftNewYear,
  1145. title: I18N('NY_GIFTS_TITLE'),
  1146. },
  1147. */
  1148. ];
  1149. popupButtons.push({ result: false, isClose: true })
  1150. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1151. if (typeof answer === 'function') {
  1152. answer();
  1153. }
  1154. }
  1155. },
  1156. doOthers: {
  1157. name: I18N('OTHERS'),
  1158. title: I18N('OTHERS_TITLE'),
  1159. func: async function () {
  1160. const popupButtons = [
  1161. {
  1162. msg: I18N('GET_ENERGY'),
  1163. result: farmStamina,
  1164. title: I18N('GET_ENERGY_TITLE'),
  1165. },
  1166. {
  1167. msg: I18N('ITEM_EXCHANGE'),
  1168. result: fillActive,
  1169. title: I18N('ITEM_EXCHANGE_TITLE'),
  1170. },
  1171. {
  1172. msg: I18N('BUY_SOULS'),
  1173. result: function () {
  1174. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_SOULS')}?`, buyHeroFragments);
  1175. },
  1176. title: I18N('BUY_SOULS_TITLE'),
  1177. },
  1178. {
  1179. msg: I18N('BUY_FOR_GOLD'),
  1180. result: function () {
  1181. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_FOR_GOLD')}?`, buyInStoreForGold);
  1182. },
  1183. title: I18N('BUY_FOR_GOLD_TITLE'),
  1184. },
  1185. {
  1186. msg: I18N('BUY_OUTLAND'),
  1187. result: function () {
  1188. confShow(I18N('BUY_OUTLAND_TITLE') + '?', bossOpenChestPay);
  1189. },
  1190. title: I18N('BUY_OUTLAND_TITLE'),
  1191. },
  1192. {
  1193. msg: I18N('AUTO_RAID_ADVENTURE'),
  1194. result: autoRaidAdventure,
  1195. title: I18N('AUTO_RAID_ADVENTURE_TITLE'),
  1196. },
  1197. {
  1198. msg: I18N('CLAN_STAT'),
  1199. result: clanStatistic,
  1200. title: I18N('CLAN_STAT_TITLE'),
  1201. },
  1202. {
  1203. msg: I18N('EPIC_BRAWL'),
  1204. result: async function () {
  1205. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EPIC_BRAWL')}?`, () => {
  1206. const brawl = new epicBrawl;
  1207. brawl.start();
  1208. });
  1209. },
  1210. title: I18N('EPIC_BRAWL_TITLE'),
  1211. },
  1212. {
  1213. msg: I18N('ARTIFACTS_UPGRADE'),
  1214. result: updateArtifacts,
  1215. title: I18N('ARTIFACTS_UPGRADE_TITLE'),
  1216. },
  1217. {
  1218. msg: I18N('SKINS_UPGRADE'),
  1219. result: updateSkins,
  1220. title: I18N('SKINS_UPGRADE_TITLE'),
  1221. },
  1222. {
  1223. msg: I18N('CHANGE_MAP'),
  1224. result: async function () {
  1225. const maps = [];
  1226. for (let num = 1; num < 5; num++) {
  1227. maps.push({
  1228. msg: I18N('MAP_NUM', { num }),
  1229. result: num,
  1230. });
  1231. }
  1232.  
  1233. const result = await popup.confirm(I18N('SELECT_ISLAND_MAP'), [
  1234. ...maps,
  1235. { result: false, isClose: true },
  1236. ]);
  1237. if (result) {
  1238. cheats.changeIslandMap(result);
  1239. }
  1240. },
  1241. title: I18N('CHANGE_MAP_TITLE'),
  1242. },
  1243. ];
  1244. popupButtons.push({ result: false, isClose: true })
  1245. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1246. if (typeof answer === 'function') {
  1247. answer();
  1248. }
  1249. }
  1250. },
  1251. testTitanArena: {
  1252. name: I18N('TITAN_ARENA'),
  1253. title: I18N('TITAN_ARENA_TITLE'),
  1254. func: function () {
  1255. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TITAN_ARENA')}?`, testTitanArena);
  1256. },
  1257. },
  1258. testDungeon: {
  1259. name: I18N('DUNGEON'),
  1260. title: I18N('DUNGEON_TITLE'),
  1261. func: function () {
  1262. confShow(`${I18N('RUN_SCRIPT')} ${I18N('DUNGEON')}?`, testDungeon);
  1263. },
  1264. },
  1265. // Архидемон
  1266. bossRatingEvent: {
  1267. name: I18N('ARCHDEMON'),
  1268. title: I18N('ARCHDEMON_TITLE'),
  1269. func: function () {
  1270. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ARCHDEMON')}?`, bossRatingEvent);
  1271. },
  1272. hide: true,
  1273. },
  1274. /*
  1275. // Горнило душ
  1276. bossRatingEvent: {
  1277. name: I18N('ARCHDEMON'),
  1278. title: I18N('ARCHDEMON_TITLE'),
  1279. func: function () {
  1280. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ARCHDEMON')}?`, bossRatingEventSouls);
  1281. },
  1282. },
  1283. */
  1284. rewardsAndMailFarm: {
  1285. name: I18N('REWARDS_AND_MAIL'),
  1286. title: I18N('REWARDS_AND_MAIL_TITLE'),
  1287. func: function () {
  1288. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS_AND_MAIL')}?`, rewardsAndMailFarm);
  1289. },
  1290. },
  1291. testAdventure: {
  1292. name: I18N('ADVENTURE'),
  1293. title: I18N('ADVENTURE_TITLE'),
  1294. func: () => {
  1295. testAdventure();
  1296. },
  1297. },
  1298. goToSanctuary: {
  1299. name: I18N('SANCTUARY'),
  1300. title: I18N('SANCTUARY_TITLE'),
  1301. func: cheats.goSanctuary,
  1302. },
  1303. goToClanWar: {
  1304. name: I18N('GUILD_WAR'),
  1305. title: I18N('GUILD_WAR_TITLE'),
  1306. func: cheats.goClanWar,
  1307. },
  1308. dailyQuests: {
  1309. name: I18N('DAILY_QUESTS'),
  1310. title: I18N('DAILY_QUESTS_TITLE'),
  1311. func: async function () {
  1312. const quests = new dailyQuests(() => { }, () => { });
  1313. await quests.autoInit();
  1314. quests.start();
  1315. },
  1316. },
  1317. newDay: {
  1318. name: I18N('SYNC'),
  1319. title: I18N('SYNC_TITLE'),
  1320. func: function () {
  1321. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SYNC')}?`, cheats.refreshGame);
  1322. },
  1323. },
  1324. }
  1325. /**
  1326. * Display buttons
  1327. *
  1328. * Вывести кнопочки
  1329. */
  1330. function addControlButtons() {
  1331. for (let name in buttons) {
  1332. button = buttons[name];
  1333. if (button.hide) {
  1334. continue;
  1335. }
  1336. button['button'] = scriptMenu.addButton(button.name, button.func, button.title);
  1337. }
  1338. }
  1339. /**
  1340. * Adds links
  1341. *
  1342. * Добавляет ссылки
  1343. */
  1344. function addBottomUrls() {
  1345. scriptMenu.addHeader(I18N('BOTTOM_URLS'));
  1346. }
  1347. /**
  1348. * Stop repetition of the mission
  1349. *
  1350. * Остановить повтор миссии
  1351. */
  1352. let isStopSendMission = false;
  1353. /**
  1354. * There is a repetition of the mission
  1355. *
  1356. * Идет повтор миссии
  1357. */
  1358. let isSendsMission = false;
  1359. /**
  1360. * Data on the past mission
  1361. *
  1362. * Данные о прошедшей мисии
  1363. */
  1364. let lastMissionStart = {}
  1365. /**
  1366. * Start time of the last battle in the company
  1367. *
  1368. * Время начала последнего боя в кампании
  1369. */
  1370. let lastMissionBattleStart = 0;
  1371. /**
  1372. * Data on the past attack on the boss
  1373. *
  1374. * Данные о прошедшей атаке на босса
  1375. */
  1376. let lastBossBattle = {}
  1377. /**
  1378. * Data for calculating the last battle with the boss
  1379. *
  1380. * Данные для расчете последнего боя с боссом
  1381. */
  1382. let lastBossBattleInfo = null;
  1383. /**
  1384. * Ability to cancel the battle in Asgard
  1385. *
  1386. * Возможность отменить бой в Астгарде
  1387. */
  1388. let isCancalBossBattle = true;
  1389. /**
  1390. * Information about the last battle
  1391. *
  1392. * Данные о прошедшей битве
  1393. */
  1394. let lastBattleArg = {}
  1395. let lastBossBattleStart = null;
  1396. this.addBattleTimer = 4;
  1397. this.invasionTimer = 2500;
  1398. /**
  1399. * The name of the function of the beginning of the battle
  1400. *
  1401. * Имя функции начала боя
  1402. */
  1403. let nameFuncStartBattle = '';
  1404. /**
  1405. * The name of the function of the end of the battle
  1406. *
  1407. * Имя функции конца боя
  1408. */
  1409. let nameFuncEndBattle = '';
  1410. /**
  1411. * Data for calculating the last battle
  1412. *
  1413. * Данные для расчета последнего боя
  1414. */
  1415. let lastBattleInfo = null;
  1416. /**
  1417. * The ability to cancel the battle
  1418. *
  1419. * Возможность отменить бой
  1420. */
  1421. let isCancalBattle = true;
  1422.  
  1423. /**
  1424. * Certificator of the last open nesting doll
  1425. *
  1426. * Идетификатор последней открытой матрешки
  1427. */
  1428. let lastRussianDollId = null;
  1429. /**
  1430. * Cancel the training guide
  1431. *
  1432. * Отменить обучающее руководство
  1433. */
  1434. this.isCanceledTutorial = false;
  1435.  
  1436. /**
  1437. * Data from the last question of the quiz
  1438. *
  1439. * Данные последнего вопроса викторины
  1440. */
  1441. let lastQuestion = null;
  1442. /**
  1443. * Answer to the last question of the quiz
  1444. *
  1445. * Ответ на последний вопрос викторины
  1446. */
  1447. let lastAnswer = null;
  1448. /**
  1449. * Flag for opening keys or titan artifact spheres
  1450. *
  1451. * Флаг открытия ключей или сфер артефактов титанов
  1452. */
  1453. let artifactChestOpen = false;
  1454. /**
  1455. * The name of the function to open keys or orbs of titan artifacts
  1456. *
  1457. * Имя функции открытия ключей или сфер артефактов титанов
  1458. */
  1459. let artifactChestOpenCallName = '';
  1460. let correctShowOpenArtifact = 0;
  1461. /**
  1462. * Data for the last battle in the dungeon
  1463. * (Fix endless cards)
  1464. *
  1465. * Данные для последнего боя в подземке
  1466. * (Исправление бесконечных карт)
  1467. */
  1468. let lastDungeonBattleData = null;
  1469. /**
  1470. * Start time of the last battle in the dungeon
  1471. *
  1472. * Время начала последнего боя в подземелье
  1473. */
  1474. let lastDungeonBattleStart = 0;
  1475. /**
  1476. * Subscription end time
  1477. *
  1478. * Время окончания подписки
  1479. */
  1480. let subEndTime = 0;
  1481. /**
  1482. * Number of prediction cards
  1483. *
  1484. * Количество карт предсказаний
  1485. */
  1486. let countPredictionCard = 0;
  1487.  
  1488. /**
  1489. * Brawl pack
  1490. *
  1491. * Пачка для потасовок
  1492. */
  1493. let brawlsPack = null;
  1494. /**
  1495. * Autobrawl started
  1496. *
  1497. * Автопотасовка запущена
  1498. */
  1499. let isBrawlsAutoStart = false;
  1500. /**
  1501. * Copies the text to the clipboard
  1502. *
  1503. * Копирует тест в буфер обмена
  1504. * @param {*} text copied text // копируемый текст
  1505. */
  1506. function copyText(text) {
  1507. let copyTextarea = document.createElement("textarea");
  1508. copyTextarea.style.opacity = "0";
  1509. copyTextarea.textContent = text;
  1510. document.body.appendChild(copyTextarea);
  1511. copyTextarea.select();
  1512. document.execCommand("copy");
  1513. document.body.removeChild(copyTextarea);
  1514. delete copyTextarea;
  1515. }
  1516. /**
  1517. * Returns the history of requests
  1518. *
  1519. * Возвращает историю запросов
  1520. */
  1521. this.getRequestHistory = function() {
  1522. return requestHistory;
  1523. }
  1524. /**
  1525. * Generates a random integer from min to max
  1526. *
  1527. * Гененирует случайное целое число от min до max
  1528. */
  1529. const random = function (min, max) {
  1530. return Math.floor(Math.random() * (max - min + 1) + min);
  1531. }
  1532. /**
  1533. * Clearing the request history
  1534. *
  1535. * Очистка истоии запросов
  1536. */
  1537. setInterval(function () {
  1538. let now = Date.now();
  1539. for (let i in requestHistory) {
  1540. const time = +i.split('_')[0];
  1541. if (now - time > 300000) {
  1542. delete requestHistory[i];
  1543. }
  1544. }
  1545. }, 300000);
  1546. /**
  1547. * Displays the dialog box
  1548. *
  1549. * Отображает диалоговое окно
  1550. */
  1551. function confShow(message, yesCallback, noCallback) {
  1552. let buts = [];
  1553. message = message || I18N('DO_YOU_WANT');
  1554. noCallback = noCallback || (() => {});
  1555. if (yesCallback) {
  1556. buts = [
  1557. { msg: I18N('BTN_RUN'), result: true},
  1558. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true},
  1559. ]
  1560. } else {
  1561. yesCallback = () => {};
  1562. buts = [
  1563. { msg: I18N('BTN_OK'), result: true},
  1564. ];
  1565. }
  1566. popup.confirm(message, buts).then((e) => {
  1567. // dialogPromice = null;
  1568. if (e) {
  1569. yesCallback();
  1570. } else {
  1571. noCallback();
  1572. }
  1573. });
  1574. }
  1575. /**
  1576. * Override/proxy the method for creating a WS package send
  1577. *
  1578. * Переопределяем/проксируем метод создания отправки WS пакета
  1579. */
  1580. WebSocket.prototype.send = function (data) {
  1581. if (!this.isSetOnMessage) {
  1582. const oldOnmessage = this.onmessage;
  1583. this.onmessage = function (event) {
  1584. try {
  1585. const data = JSON.parse(event.data);
  1586. if (!this.isWebSocketLogin && data.result.type == "iframeEvent.login") {
  1587. this.isWebSocketLogin = true;
  1588. } else if (data.result.type == "iframeEvent.login") {
  1589. return;
  1590. }
  1591. } catch (e) { }
  1592. return oldOnmessage.apply(this, arguments);
  1593. }
  1594. this.isSetOnMessage = true;
  1595. }
  1596. original.SendWebSocket.call(this, data);
  1597. }
  1598. /**
  1599. * Overriding/Proxying the Ajax Request Creation Method
  1600. *
  1601. * Переопределяем/проксируем метод создания Ajax запроса
  1602. */
  1603. XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
  1604. this.uniqid = Date.now() + '_' + random(1000000, 10000000);
  1605. this.errorRequest = false;
  1606. if (method == 'POST' && url.includes('.nextersglobal.com/api/') && /api\/$/.test(url)) {
  1607. if (!apiUrl) {
  1608. apiUrl = url;
  1609. const socialInfo = /heroes-(.+?)\./.exec(apiUrl);
  1610. console.log(socialInfo);
  1611. }
  1612. requestHistory[this.uniqid] = {
  1613. method,
  1614. url,
  1615. error: [],
  1616. headers: {},
  1617. request: null,
  1618. response: null,
  1619. signature: [],
  1620. calls: {},
  1621. };
  1622. } else if (method == 'POST' && url.includes('error.nextersglobal.com/client/')) {
  1623. this.errorRequest = true;
  1624. }
  1625. return original.open.call(this, method, url, async, user, password);
  1626. };
  1627. /**
  1628. * Overriding/Proxying the header setting method for the AJAX request
  1629. *
  1630. * Переопределяем/проксируем метод установки заголовков для AJAX запроса
  1631. */
  1632. XMLHttpRequest.prototype.setRequestHeader = function (name, value, check) {
  1633. if (this.uniqid in requestHistory) {
  1634. requestHistory[this.uniqid].headers[name] = value;
  1635. } else {
  1636. check = true;
  1637. }
  1638.  
  1639. if (name == 'X-Auth-Signature') {
  1640. requestHistory[this.uniqid].signature.push(value);
  1641. if (!check) {
  1642. return;
  1643. }
  1644. }
  1645.  
  1646. return original.setRequestHeader.call(this, name, value);
  1647. };
  1648. /**
  1649. * Overriding/Proxying the AJAX Request Sending Method
  1650. *
  1651. * Переопределяем/проксируем метод отправки AJAX запроса
  1652. */
  1653. XMLHttpRequest.prototype.send = async function (sourceData) {
  1654. if (this.uniqid in requestHistory) {
  1655. let tempData = null;
  1656. if (getClass(sourceData) == "ArrayBuffer") {
  1657. tempData = decoder.decode(sourceData);
  1658. } else {
  1659. tempData = sourceData;
  1660. }
  1661. requestHistory[this.uniqid].request = tempData;
  1662. let headers = requestHistory[this.uniqid].headers;
  1663. lastHeaders = Object.assign({}, headers);
  1664. /**
  1665. * Game loading event
  1666. *
  1667. * Событие загрузки игры
  1668. */
  1669. if (headers["X-Request-Id"] > 2 && !isLoadGame) {
  1670. isLoadGame = true;
  1671. await lib.load();
  1672. addControls();
  1673. addControlButtons();
  1674. addBottomUrls();
  1675.  
  1676. if (isChecked('sendExpedition')) {
  1677. checkExpedition();
  1678. }
  1679.  
  1680. getAutoGifts();
  1681.  
  1682. cheats.activateHacks();
  1683. justInfo();
  1684. if (isChecked('dailyQuests')) {
  1685. testDailyQuests();
  1686. }
  1687.  
  1688. if (isChecked('buyForGold')) {
  1689. buyInStoreForGold();
  1690. }
  1691. }
  1692. /**
  1693. * Outgoing request data processing
  1694. *
  1695. * Обработка данных исходящего запроса
  1696. */
  1697. sourceData = await checkChangeSend.call(this, sourceData, tempData);
  1698. /**
  1699. * Handling incoming request data
  1700. *
  1701. * Обработка данных входящего запроса
  1702. */
  1703. const oldReady = this.onreadystatechange;
  1704. this.onreadystatechange = async function (e) {
  1705. if (this.errorRequest) {
  1706. return oldReady.apply(this, arguments);
  1707. }
  1708. if(this.readyState == 4 && this.status == 200) {
  1709. isTextResponse = this.responseType === "text" || this.responseType === "";
  1710. let response = isTextResponse ? this.responseText : this.response;
  1711. requestHistory[this.uniqid].response = response;
  1712. /**
  1713. * Replacing incoming request data
  1714. *
  1715. * Заменна данных входящего запроса
  1716. */
  1717. if (isTextResponse) {
  1718. await checkChangeResponse.call(this, response);
  1719. }
  1720. /**
  1721. * A function to run after the request is executed
  1722. *
  1723. * Функция запускаемая после выполения запроса
  1724. */
  1725. if (typeof this.onReadySuccess == 'function') {
  1726. setTimeout(this.onReadySuccess, 500);
  1727. }
  1728. /** Удаляем из истории запросов битвы с боссом */
  1729. if ('invasion_bossStart' in requestHistory[this.uniqid].calls) delete requestHistory[this.uniqid];
  1730. }
  1731. if (oldReady) {
  1732. return oldReady.apply(this, arguments);
  1733. }
  1734. }
  1735. }
  1736. if (this.errorRequest) {
  1737. const oldReady = this.onreadystatechange;
  1738. this.onreadystatechange = function () {
  1739. Object.defineProperty(this, 'status', {
  1740. writable: true
  1741. });
  1742. this.status = 200;
  1743. Object.defineProperty(this, 'readyState', {
  1744. writable: true
  1745. });
  1746. this.readyState = 4;
  1747. Object.defineProperty(this, 'responseText', {
  1748. writable: true
  1749. });
  1750. this.responseText = JSON.stringify({
  1751. "result": true
  1752. });
  1753. if (typeof this.onReadySuccess == 'function') {
  1754. setTimeout(this.onReadySuccess, 500);
  1755. }
  1756. return oldReady.apply(this, arguments);
  1757. }
  1758. this.onreadystatechange();
  1759. } else {
  1760. try {
  1761. return original.send.call(this, sourceData);
  1762. } catch(e) {
  1763. debugger;
  1764. }
  1765. }
  1766. };
  1767. /**
  1768. * Processing and substitution of outgoing data
  1769. *
  1770. * Обработка и подмена исходящих данных
  1771. */
  1772. async function checkChangeSend(sourceData, tempData) {
  1773. try {
  1774. /**
  1775. * A function that replaces battle data with incorrect ones to cancel combatя
  1776. *
  1777. * Функция заменяющая данные боя на неверные для отмены боя
  1778. */
  1779. const fixBattle = function (heroes) {
  1780. for (const ids in heroes) {
  1781. hero = heroes[ids];
  1782. hero.energy = random(1, 999);
  1783. if (hero.hp > 0) {
  1784. hero.hp = random(1, hero.hp);
  1785. }
  1786. }
  1787. }
  1788. /**
  1789. * Dialog window 2
  1790. *
  1791. * Диалоговое окно 2
  1792. */
  1793. const showMsg = async function (msg, ansF, ansS) {
  1794. if (typeof popup == 'object') {
  1795. return await popup.confirm(msg, [
  1796. {msg: ansF, result: false},
  1797. {msg: ansS, result: true},
  1798. ]);
  1799. } else {
  1800. return !confirm(`${msg}\n ${ansF} (${I18N('BTN_OK')})\n ${ansS} (${I18N('BTN_CANCEL')})`);
  1801. }
  1802. }
  1803. /**
  1804. * Dialog window 3
  1805. *
  1806. * Диалоговое окно 3
  1807. */
  1808. const showMsgs = async function (msg, ansF, ansS, ansT) {
  1809. return await popup.confirm(msg, [
  1810. {msg: ansF, result: 0},
  1811. {msg: ansS, result: 1},
  1812. {msg: ansT, result: 2},
  1813. ]);
  1814. }
  1815.  
  1816. let changeRequest = false;
  1817. testData = JSON.parse(tempData);
  1818. for (const call of testData.calls) {
  1819. if (!artifactChestOpen) {
  1820. requestHistory[this.uniqid].calls[call.name] = call.ident;
  1821. }
  1822. /**
  1823. * Cancellation of the battle in adventures, on VG and with minions of Asgard
  1824. * Отмена боя в приключениях, на ВГ и с прислужниками Асгарда
  1825. */
  1826. if ((call.name == 'adventure_endBattle' ||
  1827. call.name == 'adventureSolo_endBattle' ||
  1828. call.name == 'clanWarEndBattle' &&
  1829. isChecked('cancelBattle') ||
  1830. call.name == 'crossClanWar_endBattle' &&
  1831. isChecked('cancelBattle') ||
  1832. call.name == 'brawl_endBattle' ||
  1833. call.name == 'towerEndBattle' ||
  1834. call.name == 'invasion_bossEnd' ||
  1835. call.name == 'bossEndBattle' ||
  1836. call.name == 'clanRaid_endNodeBattle') &&
  1837. isCancalBattle) {
  1838. nameFuncEndBattle = call.name;
  1839. if (!call.args.result.win) {
  1840. let resultPopup = false;
  1841. if (call.name == 'adventure_endBattle' ||
  1842. call.name == 'invasion_bossEnd' ||
  1843. call.name == 'bossEndBattle' ||
  1844. call.name == 'adventureSolo_endBattle') {
  1845. resultPopup = await showMsgs(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  1846. } else if (call.name == 'clanWarEndBattle' ||
  1847. call.name == 'crossClanWar_endBattle') {
  1848. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_AUTO_F5'));
  1849. } else {
  1850. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'));
  1851. }
  1852. if (resultPopup) {
  1853. if (call.name == 'invasion_bossEnd') {
  1854. this.errorRequest = true;
  1855. }
  1856. fixBattle(call.args.progress[0].attackers.heroes);
  1857. fixBattle(call.args.progress[0].defenders.heroes);
  1858. changeRequest = true;
  1859. if (resultPopup > 1) {
  1860. this.onReadySuccess = testAutoBattle;
  1861. // setTimeout(bossBattle, 1000);
  1862. }
  1863. }
  1864. } else if (call.args.result.stars < 3 && call.name == 'towerEndBattle') {
  1865. resultPopup = await showMsg(I18N('LOST_HEROES'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  1866. if (resultPopup) {
  1867. fixBattle(call.args.progress[0].attackers.heroes);
  1868. fixBattle(call.args.progress[0].defenders.heroes);
  1869. changeRequest = true;
  1870. if (resultPopup > 1) {
  1871. this.onReadySuccess = testAutoBattle;
  1872. }
  1873. }
  1874. }
  1875. // Потасовки
  1876. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_endBattle') {}
  1877. }
  1878. /**
  1879. * Save pack for Brawls
  1880. *
  1881. * Сохраняем пачку для потасовок
  1882. */
  1883. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_startBattle') {
  1884. console.log(JSON.stringify(call.args));
  1885. brawlsPack = call.args;
  1886. if (
  1887. await popup.confirm(
  1888. I18N('START_AUTO_BRAWLS'),
  1889. [
  1890. { msg: I18N('BTN_NO'), result: false },
  1891. { msg: I18N('BTN_YES'), result: true },
  1892. ],
  1893. [
  1894. {
  1895. name: 'isAuto',
  1896. label: I18N('BRAWL_AUTO_PACK'),
  1897. checked: false,
  1898. },
  1899. ]
  1900. )
  1901. ) {
  1902. isBrawlsAutoStart = true;
  1903. const isAuto = popup.getCheckBoxes().find((e) => e.name === 'isAuto');
  1904. this.errorRequest = true;
  1905. testBrawls(isAuto);
  1906. }
  1907. }
  1908. /**
  1909. * Canceled fight in Asgard
  1910. * Отмена боя в Асгарде
  1911. */
  1912. if (call.name == 'clanRaid_endBossBattle' &&
  1913. isCancalBossBattle &&
  1914. isChecked('cancelBattle')) {
  1915. bossDamage = call.args.progress[0].defenders.heroes[1].extra;
  1916. sumDamage = bossDamage.damageTaken + bossDamage.damageTakenNextLevel;
  1917. let resultPopup = await showMsgs(
  1918. `${I18N('MSG_YOU_APPLIED')} ${sumDamage.toLocaleString()} ${I18N('MSG_DAMAGE')}.`,
  1919. I18N('BTN_OK'), I18N('BTN_AUTO_F5'), I18N('MSG_CANCEL_AND_STAT'))
  1920. if (resultPopup) {
  1921. fixBattle(call.args.progress[0].attackers.heroes);
  1922. fixBattle(call.args.progress[0].defenders.heroes);
  1923. changeRequest = true;
  1924. if (resultPopup > 1) {
  1925. this.onReadySuccess = testBossBattle;
  1926. // setTimeout(bossBattle, 1000);
  1927. }
  1928. }
  1929. }
  1930. /**
  1931. * Save the Asgard Boss Attack Pack
  1932. * Сохраняем пачку для атаки босса Асгарда
  1933. */
  1934. if (call.name == 'clanRaid_startBossBattle') {
  1935. lastBossBattle = call.args;
  1936. }
  1937. /**
  1938. * Saving the request to start the last battle
  1939. * Сохранение запроса начала последнего боя
  1940. */
  1941. if (call.name == 'clanWarAttack' ||
  1942. call.name == 'crossClanWar_startBattle' ||
  1943. call.name == 'adventure_turnStartBattle' ||
  1944. call.name == 'bossAttack' ||
  1945. call.name == 'invasion_bossStart' ||
  1946. call.name == 'towerStartBattle') {
  1947. nameFuncStartBattle = call.name;
  1948. lastBattleArg = call.args;
  1949.  
  1950. if (call.name == 'invasion_bossStart') {
  1951. const timePassed = Date.now() - lastBossBattleStart;
  1952. if (timePassed < invasionTimer) {
  1953. await new Promise((e) => setTimeout(e, invasionTimer - timePassed));
  1954. }
  1955. invasionTimer -= 1;
  1956. }
  1957. lastBossBattleStart = Date.now();
  1958. }
  1959. if (call.name == 'invasion_bossEnd') {
  1960. const lastBattle = lastBattleInfo;
  1961. if (lastBattle && call.args.result.win) {
  1962. lastBattle.progress = call.args.progress;
  1963. const result = await Calc(lastBattle);
  1964. let timer = getTimer(result.battleTime, 1) + addBattleTimer;
  1965. const period = Math.ceil((Date.now() - lastBossBattleStart) / 1000);
  1966. console.log(timer, period);
  1967. if (period < timer) {
  1968. timer = timer - period;
  1969. await countdownTimer(timer);
  1970. }
  1971. }
  1972. }
  1973. /**
  1974. * Disable spending divination cards
  1975. * Отключить трату карт предсказаний
  1976. */
  1977. if (call.name == 'dungeonEndBattle') {
  1978. if (call.args.isRaid) {
  1979. if (countPredictionCard <= 0) {
  1980. delete call.args.isRaid;
  1981. changeRequest = true;
  1982. } else if (countPredictionCard > 0) {
  1983. countPredictionCard--;
  1984. }
  1985. }
  1986. console.log(`Cards: ${countPredictionCard}`);
  1987. /**
  1988. * Fix endless cards
  1989. * Исправление бесконечных карт
  1990. */
  1991. const lastBattle = lastDungeonBattleData;
  1992. if (lastBattle && !call.args.isRaid) {
  1993. if (changeRequest) {
  1994. lastBattle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  1995. } else {
  1996. lastBattle.progress = call.args.progress;
  1997. }
  1998. const result = await Calc(lastBattle);
  1999.  
  2000. if (changeRequest) {
  2001. call.args.progress = result.progress;
  2002. call.args.result = result.result;
  2003. }
  2004. let timer = getTimer(result.battleTime) + addBattleTimer;
  2005. const period = Math.ceil((Date.now() - lastDungeonBattleStart) / 1000);
  2006. console.log(timer, period);
  2007. if (period < timer) {
  2008. timer = timer - period;
  2009. await countdownTimer(timer);
  2010. }
  2011. }
  2012. }
  2013. /**
  2014. * Quiz Answer
  2015. * Ответ на викторину
  2016. */
  2017. if (call.name == 'quizAnswer') {
  2018. /**
  2019. * Automatically changes the answer to the correct one if there is one.
  2020. * Автоматически меняет ответ на правильный если он есть
  2021. */
  2022. if (lastAnswer && isChecked('getAnswer')) {
  2023. call.args.answerId = lastAnswer;
  2024. lastAnswer = null;
  2025. changeRequest = true;
  2026. }
  2027. }
  2028. /**
  2029. * Present
  2030. * Подарки
  2031. */
  2032. if (call.name == 'freebieCheck') {
  2033. freebieCheckInfo = call;
  2034. }
  2035. /** missionTimer */
  2036. if (call.name == 'missionEnd' && missionBattle) {
  2037. missionBattle.progress = call.args.progress;
  2038. missionBattle.result = call.args.result;
  2039. const result = await Calc(missionBattle);
  2040.  
  2041. let timer = getTimer(result.battleTime) + addBattleTimer;
  2042. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  2043. if (period < timer) {
  2044. timer = timer - period;
  2045. await countdownTimer(timer);
  2046. }
  2047. missionBattle = null;
  2048. }
  2049. /**
  2050. * Getting mission data for auto-repeat
  2051. * Получение данных миссии для автоповтора
  2052. */
  2053. if (isChecked('repeatMission') &&
  2054. call.name == 'missionEnd') {
  2055. let missionInfo = {
  2056. id: call.args.id,
  2057. result: call.args.result,
  2058. heroes: call.args.progress[0].attackers.heroes,
  2059. count: 0,
  2060. }
  2061. setTimeout(async () => {
  2062. if (!isSendsMission && await popup.confirm(I18N('MSG_REPEAT_MISSION'), [
  2063. { msg: I18N('BTN_REPEAT'), result: true},
  2064. { msg: I18N('BTN_NO'), result: false},
  2065. ])) {
  2066. isStopSendMission = false;
  2067. isSendsMission = true;
  2068. sendsMission(missionInfo);
  2069. }
  2070. }, 0);
  2071. }
  2072. /**
  2073. * Getting mission data
  2074. * Получение данных миссии
  2075. * missionTimer
  2076. */
  2077. if (call.name == 'missionStart') {
  2078. lastMissionStart = call.args;
  2079. lastMissionBattleStart = Date.now();
  2080. }
  2081. /**
  2082. * Specify the quantity for Titan Orbs and Pet Eggs
  2083. * Указать количество для сфер титанов и яиц петов
  2084. */
  2085. if (isChecked('countControl') &&
  2086. (call.name == 'pet_chestOpen' ||
  2087. call.name == 'titanUseSummonCircle') &&
  2088. call.args.amount > 1) {
  2089. call.args.amount = 1;
  2090. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2091. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2092. ]);
  2093. if (result) {
  2094. call.args.amount = result;
  2095. changeRequest = true;
  2096. }
  2097. }
  2098. /**
  2099. * Specify the amount for keys and spheres of titan artifacts
  2100. * Указать колличество для ключей и сфер артефактов титанов
  2101. */
  2102. if (isChecked('countControl') &&
  2103. (call.name == 'artifactChestOpen' ||
  2104. call.name == 'titanArtifactChestOpen') &&
  2105. call.args.amount > 1 &&
  2106. call.args.free &&
  2107. !changeRequest) {
  2108. artifactChestOpenCallName = call.name;
  2109. let result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2110. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount },
  2111. ]);
  2112. if (result) {
  2113. let sphere = result < 10 ? 1 : 10;
  2114.  
  2115. call.args.amount = sphere;
  2116. result -= sphere;
  2117.  
  2118. for (let count = result; count > 0; count -= sphere) {
  2119. if (count < 10) sphere = 1;
  2120. const ident = artifactChestOpenCallName + "_" + count;
  2121. testData.calls.push({
  2122. name: artifactChestOpenCallName,
  2123. args: {
  2124. amount: sphere,
  2125. free: true,
  2126. },
  2127. ident: ident
  2128. });
  2129. if (!Array.isArray(requestHistory[this.uniqid].calls[call.name])) {
  2130. requestHistory[this.uniqid].calls[call.name] = [requestHistory[this.uniqid].calls[call.name]];
  2131. }
  2132. requestHistory[this.uniqid].calls[call.name].push(ident);
  2133. }
  2134.  
  2135. artifactChestOpen = true;
  2136. changeRequest = true;
  2137. }
  2138. }
  2139. if (call.name == 'consumableUseLootBox') {
  2140. lastRussianDollId = call.args.libId;
  2141. /**
  2142. * Specify quantity for gold caskets
  2143. * Указать количество для золотых шкатулок
  2144. */
  2145. if (isChecked('countControl') &&
  2146. call.args.libId == 148 &&
  2147. call.args.amount > 1) {
  2148. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2149. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2150. ]);
  2151. call.args.amount = result;
  2152. changeRequest = true;
  2153. }
  2154. }
  2155. /**
  2156. * Changing the maximum number of raids in the campaign
  2157. * Изменение максимального количества рейдов в кампании
  2158. */
  2159. // if (call.name == 'missionRaid') {
  2160. // if (isChecked('countControl') && call.args.times > 1) {
  2161. // const result = +(await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2162. // { msg: I18N('BTN_RUN'), isInput: true, default: call.args.times },
  2163. // ]));
  2164. // call.args.times = result > call.args.times ? call.args.times : result;
  2165. // changeRequest = true;
  2166. // }
  2167. // }
  2168. }
  2169.  
  2170. let headers = requestHistory[this.uniqid].headers;
  2171. if (changeRequest) {
  2172. sourceData = JSON.stringify(testData);
  2173. headers['X-Auth-Signature'] = getSignature(headers, sourceData);
  2174. }
  2175.  
  2176. let signature = headers['X-Auth-Signature'];
  2177. if (signature) {
  2178. original.setRequestHeader.call(this, 'X-Auth-Signature', signature);
  2179. }
  2180. } catch (err) {
  2181. console.log("Request(send, " + this.uniqid + "):\n", sourceData, "Error:\n", err);
  2182. }
  2183. return sourceData;
  2184. }
  2185. /**
  2186. * Processing and substitution of incoming data
  2187. *
  2188. * Обработка и подмена входящих данных
  2189. */
  2190. async function checkChangeResponse(response) {
  2191. try {
  2192. isChange = false;
  2193. let nowTime = Math.round(Date.now() / 1000);
  2194. callsIdent = requestHistory[this.uniqid].calls;
  2195. respond = JSON.parse(response);
  2196. /**
  2197. * If the request returned an error removes the error (removes synchronization errors)
  2198. * Если запрос вернул ошибку удаляет ошибку (убирает ошибки синхронизации)
  2199. */
  2200. if (respond.error) {
  2201. isChange = true;
  2202. console.error(respond.error);
  2203. if (isChecked('showErrors')) {
  2204. popup.confirm(I18N('ERROR_MSG', {
  2205. name: respond.error.name,
  2206. description: respond.error.description,
  2207. }));
  2208. }
  2209. delete respond.error;
  2210. respond.results = [];
  2211. }
  2212. let mainReward = null;
  2213. const allReward = {};
  2214. let countTypeReward = 0;
  2215. let readQuestInfo = false;
  2216. for (const call of respond.results) {
  2217. /**
  2218. * Obtaining initial data for completing quests
  2219. * Получение исходных данных для выполнения квестов
  2220. */
  2221. if (readQuestInfo) {
  2222. questsInfo[call.ident] = call.result.response;
  2223. }
  2224. /**
  2225. * Getting a user ID
  2226. * Получение идетификатора пользователя
  2227. */
  2228. if (call.ident == callsIdent['registration']) {
  2229. userId = call.result.response.userId;
  2230. if (localStorage['userId'] != userId) {
  2231. localStorage['newGiftSendIds'] = '';
  2232. localStorage['userId'] = userId;
  2233. }
  2234. await openOrMigrateDatabase(userId);
  2235. readQuestInfo = true;
  2236. }
  2237. /**
  2238. * Hiding donation offers 1
  2239. * Скрываем предложения доната 1
  2240. */
  2241. if (call.ident == callsIdent['billingGetAll'] && getSaveVal('noOfferDonat')) {
  2242. const billings = call.result.response?.billings;
  2243. const bundle = call.result.response?.bundle;
  2244. if (billings && bundle) {
  2245. call.result.response.billings = [];
  2246. call.result.response.bundle = [];
  2247. isChange = true;
  2248. }
  2249. }
  2250. /**
  2251. * Hiding donation offers 2
  2252. * Скрываем предложения доната 2
  2253. */
  2254. if (getSaveVal('noOfferDonat') &&
  2255. (call.ident == callsIdent['offerGetAll'] ||
  2256. call.ident == callsIdent['specialOffer_getAll'])) {
  2257. let offers = call.result.response;
  2258. if (offers) {
  2259. call.result.response = offers.filter(e => !['addBilling', 'bundleCarousel'].includes(e.type) || ['idleResource'].includes(e.offerType));
  2260. isChange = true;
  2261. }
  2262. }
  2263. /**
  2264. * Hiding donation offers 3
  2265. * Скрываем предложения доната 3
  2266. */
  2267. if (getSaveVal('noOfferDonat') && call.result?.bundleUpdate) {
  2268. delete call.result.bundleUpdate;
  2269. isChange = true;
  2270. }
  2271. /**
  2272. * Copies a quiz question to the clipboard
  2273. * Копирует вопрос викторины в буфер обмена и получает на него ответ если есть
  2274. */
  2275. if (call.ident == callsIdent['quizGetNewQuestion']) {
  2276. let quest = call.result.response;
  2277. console.log(quest.question);
  2278. copyText(quest.question);
  2279. setProgress(I18N('QUESTION_COPY'), true);
  2280. quest.lang = null;
  2281. if (typeof NXFlashVars !== 'undefined') {
  2282. quest.lang = NXFlashVars.interface_lang;
  2283. }
  2284. lastQuestion = quest;
  2285. if (isChecked('getAnswer')) {
  2286. const answer = await getAnswer(lastQuestion);
  2287. let showText = '';
  2288. if (answer) {
  2289. lastAnswer = answer;
  2290. console.log(answer);
  2291. showText = `${I18N('ANSWER_KNOWN')}: ${answer}`;
  2292. } else {
  2293. showText = I18N('ANSWER_NOT_KNOWN');
  2294. }
  2295.  
  2296. try {
  2297. const hint = hintQuest(quest);
  2298. if (hint) {
  2299. showText += I18N('HINT') + hint;
  2300. }
  2301. } catch(e) {}
  2302.  
  2303. setProgress(showText, true);
  2304. }
  2305. }
  2306. /**
  2307. * Submits a question with an answer to the database
  2308. * Отправляет вопрос с ответом в базу данных
  2309. */
  2310. if (call.ident == callsIdent['quizAnswer']) {
  2311. const answer = call.result.response;
  2312. if (lastQuestion) {
  2313. const answerInfo = {
  2314. answer,
  2315. question: lastQuestion,
  2316. lang: null,
  2317. }
  2318. if (typeof NXFlashVars !== 'undefined') {
  2319. answerInfo.lang = NXFlashVars.interface_lang;
  2320. }
  2321. lastQuestion = null;
  2322. setTimeout(sendAnswerInfo, 0, answerInfo);
  2323. }
  2324. }
  2325. /**
  2326. * Get user data
  2327. * Получить даныне пользователя
  2328. */
  2329. if (call.ident == callsIdent['userGetInfo']) {
  2330. let user = call.result.response;
  2331. userInfo = Object.assign({}, user);
  2332. delete userInfo.refillable;
  2333. if (!questsInfo['userGetInfo']) {
  2334. questsInfo['userGetInfo'] = user;
  2335. }
  2336. }
  2337. /**
  2338. * Start of the battle for recalculation
  2339. * Начало боя для прерасчета
  2340. */
  2341. if (call.ident == callsIdent['clanWarAttack'] ||
  2342. call.ident == callsIdent['crossClanWar_startBattle'] ||
  2343. call.ident == callsIdent['bossAttack'] ||
  2344. call.ident == callsIdent['battleGetReplay'] ||
  2345. call.ident == callsIdent['brawl_startBattle'] ||
  2346. call.ident == callsIdent['adventureSolo_turnStartBattle'] ||
  2347. call.ident == callsIdent['invasion_bossStart'] ||
  2348. call.ident == callsIdent['towerStartBattle'] ||
  2349. call.ident == callsIdent['adventure_turnStartBattle']) {
  2350. let battle = call.result.response.battle || call.result.response.replay;
  2351. if (call.ident == callsIdent['brawl_startBattle'] ||
  2352. call.ident == callsIdent['bossAttack'] ||
  2353. call.ident == callsIdent['towerStartBattle'] ||
  2354. call.ident == callsIdent['invasion_bossStart']) {
  2355. battle = call.result.response;
  2356. }
  2357. lastBattleInfo = battle;
  2358. if (!isChecked('preCalcBattle')) {
  2359. continue;
  2360. }
  2361. setProgress(I18N('BEING_RECALC'));
  2362. let battleDuration = 120;
  2363. try {
  2364. const typeBattle = getBattleType(battle.type);
  2365. battleDuration = +lib.data.battleConfig[typeBattle.split('_')[1]].config.battleDuration;
  2366. } catch (e) { }
  2367. //console.log(battle.type);
  2368. function getBattleInfo(battle, isRandSeed) {
  2369. return new Promise(function (resolve) {
  2370. if (isRandSeed) {
  2371. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  2372. }
  2373. BattleCalc(battle, getBattleType(battle.type), e => resolve(e));
  2374. });
  2375. }
  2376. let actions = [getBattleInfo(battle, false)]
  2377. const countTestBattle = getInput('countTestBattle');
  2378. if (call.ident == callsIdent['battleGetReplay']) {
  2379. battle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2380. }
  2381. for (let i = 0; i < countTestBattle; i++) {
  2382. actions.push(getBattleInfo(battle, true));
  2383. }
  2384. Promise.all(actions)
  2385. .then(e => {
  2386. e = e.map(n => ({win: n.result.win, time: n.battleTime}));
  2387. let firstBattle = e.shift();
  2388. const timer = Math.floor(battleDuration - firstBattle.time);
  2389. const min = ('00' + Math.floor(timer / 60)).slice(-2);
  2390. const sec = ('00' + Math.floor(timer - min * 60)).slice(-2);
  2391. const countWin = e.reduce((w, s) => w + s.win, 0);
  2392. 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)
  2393. });
  2394. }
  2395. /**
  2396. * Start of the Asgard boss fight
  2397. * Начало боя с боссом Асгарда
  2398. */
  2399. if (call.ident == callsIdent['clanRaid_startBossBattle']) {
  2400. lastBossBattleInfo = call.result.response.battle;
  2401. if (isChecked('preCalcBattle')) {
  2402. const result = await Calc(lastBossBattleInfo).then(e => e.progress[0].defenders.heroes[1].extra);
  2403. const bossDamage = result.damageTaken + result.damageTakenNextLevel;
  2404. setProgress(I18N('BOSS_DAMAGE') + bossDamage.toLocaleString(), false, hideProgress);
  2405. }
  2406. }
  2407. /**
  2408. * Cancel tutorial
  2409. * Отмена туториала
  2410. */
  2411. if (isCanceledTutorial && call.ident == callsIdent['tutorialGetInfo']) {
  2412. let chains = call.result.response.chains;
  2413. for (let n in chains) {
  2414. chains[n] = 9999;
  2415. }
  2416. isChange = true;
  2417. }
  2418. /**
  2419. * Opening keys and spheres of titan artifacts
  2420. * Открытие ключей и сфер артефактов титанов
  2421. */
  2422. if (artifactChestOpen &&
  2423. (call.ident == callsIdent[artifactChestOpenCallName] ||
  2424. (callsIdent[artifactChestOpenCallName] && callsIdent[artifactChestOpenCallName].includes(call.ident)))) {
  2425. let reward = call.result.response[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'];
  2426.  
  2427. reward.forEach(e => {
  2428. for (let f in e) {
  2429. if (!allReward[f]) {
  2430. allReward[f] = {};
  2431. }
  2432. for (let o in e[f]) {
  2433. if (!allReward[f][o]) {
  2434. allReward[f][o] = e[f][o];
  2435. countTypeReward++;
  2436. } else {
  2437. allReward[f][o] += e[f][o];
  2438. }
  2439. }
  2440. }
  2441. });
  2442.  
  2443. if (!call.ident.includes(artifactChestOpenCallName)) {
  2444. mainReward = call.result.response;
  2445. }
  2446. }
  2447.  
  2448. if (countTypeReward > 20) {
  2449. correctShowOpenArtifact = 3;
  2450. } else {
  2451. correctShowOpenArtifact = 0;
  2452. }
  2453. /**
  2454. * Sum the result of opening Pet Eggs
  2455. * Суммирование результата открытия яиц питомцев
  2456. */
  2457. if (isChecked('countControl') && call.ident == callsIdent['pet_chestOpen']) {
  2458. const rewards = call.result.response.rewards;
  2459. if (rewards.length > 10) {
  2460. /**
  2461. * Removing pet cards
  2462. * Убираем карточки петов
  2463. */
  2464. for (const reward of rewards) {
  2465. if (reward.petCard) {
  2466. delete reward.petCard;
  2467. }
  2468. }
  2469. }
  2470. rewards.forEach(e => {
  2471. for (let f in e) {
  2472. if (!allReward[f]) {
  2473. allReward[f] = {};
  2474. }
  2475. for (let o in e[f]) {
  2476. if (!allReward[f][o]) {
  2477. allReward[f][o] = e[f][o];
  2478. } else {
  2479. allReward[f][o] += e[f][o];
  2480. }
  2481. }
  2482. }
  2483. });
  2484. call.result.response.rewards = [allReward];
  2485. isChange = true;
  2486. }
  2487. /**
  2488. * Removing titan cards
  2489. * Убираем карточки титанов
  2490. */
  2491. if (call.ident == callsIdent['titanUseSummonCircle']) {
  2492. if (call.result.response.rewards.length > 10) {
  2493. for (const reward of call.result.response.rewards) {
  2494. if (reward.titanCard) {
  2495. delete reward.titanCard;
  2496. }
  2497. }
  2498. isChange = true;
  2499. }
  2500. }
  2501. /**
  2502. * Auto-repeat opening matryoshkas
  2503. * АвтоПовтор открытия матрешек
  2504. */
  2505. if (isChecked('countControl') && call.ident == callsIdent['consumableUseLootBox']) {
  2506. let lootBox = call.result.response;
  2507. let newCount = 0;
  2508. for (let n of lootBox) {
  2509. if (n?.consumable && n.consumable[lastRussianDollId]) {
  2510. newCount += n.consumable[lastRussianDollId]
  2511. }
  2512. }
  2513. if (newCount && await popup.confirm(`${I18N('BTN_OPEN')} ${newCount} ${I18N('OPEN_DOLLS')}?`, [
  2514. { msg: I18N('BTN_OPEN'), result: true},
  2515. { msg: I18N('BTN_NO'), result: false},
  2516. ])) {
  2517. const recursionResult = await openRussianDolls(lastRussianDollId, newCount);
  2518. lootBox = [...lootBox, ...recursionResult];
  2519. }
  2520.  
  2521. /** Объединение результата лутбоксов */
  2522. const allLootBox = {};
  2523. lootBox.forEach(e => {
  2524. for (let f in e) {
  2525. if (!allLootBox[f]) {
  2526. if (typeof e[f] == 'object') {
  2527. allLootBox[f] = {};
  2528. } else {
  2529. allLootBox[f] = 0;
  2530. }
  2531. }
  2532. if (typeof e[f] == 'object') {
  2533. for (let o in e[f]) {
  2534. if (newCount && o == lastRussianDollId) {
  2535. continue;
  2536. }
  2537. if (!allLootBox[f][o]) {
  2538. allLootBox[f][o] = e[f][o];
  2539. } else {
  2540. allLootBox[f][o] += e[f][o];
  2541. }
  2542. }
  2543. } else {
  2544. allLootBox[f] += e[f];
  2545. }
  2546. }
  2547. });
  2548. /** Разбитие результата */
  2549. const output = [];
  2550. const maxCount = 5;
  2551. let currentObj = {};
  2552. let count = 0;
  2553. for (let f in allLootBox) {
  2554. if (!currentObj[f]) {
  2555. if (typeof allLootBox[f] == 'object') {
  2556. for (let o in allLootBox[f]) {
  2557. currentObj[f] ||= {}
  2558. if (!currentObj[f][o]) {
  2559. currentObj[f][o] = allLootBox[f][o];
  2560. count++;
  2561. if (count === maxCount) {
  2562. output.push(currentObj);
  2563. currentObj = {};
  2564. count = 0;
  2565. }
  2566. }
  2567. }
  2568. } else {
  2569. currentObj[f] = allLootBox[f];
  2570. count++;
  2571. if (count === maxCount) {
  2572. output.push(currentObj);
  2573. currentObj = {};
  2574. count = 0;
  2575. }
  2576. }
  2577. }
  2578. }
  2579. if (count > 0) {
  2580. output.push(currentObj);
  2581. }
  2582.  
  2583. console.log(output);
  2584. call.result.response = output;
  2585. isChange = true;
  2586. }
  2587. /**
  2588. * Dungeon recalculation (fix endless cards)
  2589. * Прерасчет подземки (исправление бесконечных карт)
  2590. */
  2591. if (call.ident == callsIdent['dungeonStartBattle']) {
  2592. lastDungeonBattleData = call.result.response;
  2593. lastDungeonBattleStart = Date.now();
  2594. }
  2595. /**
  2596. * Getting the number of prediction cards
  2597. * Получение количества карт предсказаний
  2598. */
  2599. if (call.ident == callsIdent['inventoryGet']) {
  2600. countPredictionCard = call.result.response.consumable[81] || 0;
  2601. }
  2602. /**
  2603. * Getting subscription status
  2604. * Получение состояния подписки
  2605. */
  2606. if (call.ident == callsIdent['subscriptionGetInfo']) {
  2607. const subscription = call.result.response.subscription;
  2608. if (subscription) {
  2609. subEndTime = subscription.endTime * 1000;
  2610. }
  2611. }
  2612. /**
  2613. * Getting prediction cards
  2614. * Получение карт предсказаний
  2615. */
  2616. if (call.ident == callsIdent['questFarm']) {
  2617. const consumable = call.result.response?.consumable;
  2618. if (consumable && consumable[81]) {
  2619. countPredictionCard += consumable[81];
  2620. console.log(`Cards: ${countPredictionCard}`);
  2621. }
  2622. }
  2623. /**
  2624. * Hiding extra servers
  2625. * Скрытие лишних серверов
  2626. */
  2627. if (call.ident == callsIdent['serverGetAll'] && isChecked('hideServers')) {
  2628. let servers = call.result.response.users.map(s => s.serverId)
  2629. call.result.response.servers = call.result.response.servers.filter(s => servers.includes(s.id));
  2630. isChange = true;
  2631. }
  2632. /**
  2633. * Displays player positions in the adventure
  2634. * Отображает позиции игроков в приключении
  2635. */
  2636. if (call.ident == callsIdent['adventure_getLobbyInfo']) {
  2637. const users = Object.values(call.result.response.users);
  2638. const mapIdent = call.result.response.mapIdent;
  2639. const adventureId = call.result.response.adventureId;
  2640. const maps = {
  2641. adv_strongford_3pl_hell: 9,
  2642. adv_valley_3pl_hell: 10,
  2643. adv_ghirwil_3pl_hell: 11,
  2644. adv_angels_3pl_hell: 12,
  2645. }
  2646. let msg = I18N('MAP') + (mapIdent in maps ? maps[mapIdent] : adventureId);
  2647. msg += '<br>' + I18N('PLAYER_POS');
  2648. for (const user of users) {
  2649. msg += `<br>${user.user.name} - ${user.currentNode}`;
  2650. }
  2651. setProgress(msg, false, hideProgress);
  2652. }
  2653. /**
  2654. * Automatic launch of a raid at the end of the adventure
  2655. * Автоматический запуск рейда при окончании приключения
  2656. */
  2657. if (call.ident == callsIdent['adventure_end']) {
  2658. autoRaidAdventure()
  2659. }
  2660. /** Удаление лавки редкостей */
  2661. if (call.ident == callsIdent['missionRaid']) {
  2662. if (call.result?.heroesMerchant) {
  2663. delete call.result.heroesMerchant;
  2664. isChange = true;
  2665. }
  2666. }
  2667. /** missionTimer */
  2668. if (call.ident == callsIdent['missionStart']) {
  2669. missionBattle = call.result.response;
  2670. }
  2671. }
  2672.  
  2673. if (mainReward && artifactChestOpen) {
  2674. console.log(allReward);
  2675. mainReward[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'] = [allReward];
  2676. artifactChestOpen = false;
  2677. artifactChestOpenCallName = '';
  2678. isChange = true;
  2679. }
  2680. } catch(err) {
  2681. console.log("Request(response, " + this.uniqid + "):\n", "Error:\n", response, err);
  2682. }
  2683.  
  2684. if (isChange) {
  2685. Object.defineProperty(this, 'responseText', {
  2686. writable: true
  2687. });
  2688. this.responseText = JSON.stringify(respond);
  2689. }
  2690. }
  2691.  
  2692. /**
  2693. * Request an answer to a question
  2694. *
  2695. * Запрос ответа на вопрос
  2696. */
  2697. async function getAnswer(question) {
  2698. const now = Date.now();
  2699. const body = JSON.stringify({ ...question, now });
  2700. const signature = window['\x73\x69\x67\x6e'](now);
  2701. return new Promise(resolve => {
  2702. fetch('https://zingery.ru/heroes/getAnswer.php', {
  2703. method: 'POST',
  2704. headers: {
  2705. 'X-Request-Signature': signature,
  2706. 'X-Script-Name': GM_info.script.name,
  2707. 'X-Script-Version': GM_info.script.version,
  2708. 'X-Script-Author': GM_info.script.author,
  2709. },
  2710. body,
  2711. }).then(
  2712. response => response.json()
  2713. ).then(
  2714. data => {
  2715. if (data.result) {
  2716. resolve(data.result);
  2717. } else {
  2718. resolve(false);
  2719. }
  2720. }
  2721. ).catch((error) => {
  2722. console.error(error);
  2723. resolve(false);
  2724. });
  2725. })
  2726. }
  2727.  
  2728. /**
  2729. * Submitting a question and answer to a database
  2730. *
  2731. * Отправка вопроса и ответа в базу данных
  2732. */
  2733. function sendAnswerInfo(answerInfo) {
  2734. fetch('https://zingery.ru/heroes/setAnswer.php', {
  2735. method: 'POST',
  2736. body: JSON.stringify(answerInfo)
  2737. }).then(
  2738. response => response.json()
  2739. ).then(
  2740. data => {
  2741. if (data.result) {
  2742. console.log(I18N('SENT_QUESTION'));
  2743. }
  2744. }
  2745. )
  2746. }
  2747.  
  2748. /**
  2749. * Returns the battle type by preset type
  2750. *
  2751. * Возвращает тип боя по типу пресета
  2752. */
  2753. function getBattleType(strBattleType) {
  2754. if (strBattleType.includes("invasion")) {
  2755. return "get_invasion";
  2756. }
  2757. if (strBattleType.includes("boss")) {
  2758. return "get_boss";
  2759. }
  2760. switch (strBattleType) {
  2761. case "invasion":
  2762. return "get_invasion";
  2763. case "titan_pvp_manual":
  2764. return "get_titanPvpManual";
  2765. case "titan_pvp":
  2766. return "get_titanPvp";
  2767. case "titan_clan_pvp":
  2768. case "clan_pvp_titan":
  2769. case "clan_global_pvp_titan":
  2770. case "brawl_titan":
  2771. case "challenge_titan":
  2772. return "get_titanClanPvp";
  2773. case "clan_raid": // Asgard Boss // Босс асгарда
  2774. case "adventure": // Adventures // Приключения
  2775. case "clan_global_pvp":
  2776. case "clan_pvp":
  2777. return "get_clanPvp";
  2778. case "dungeon_titan":
  2779. case "titan_tower":
  2780. return "get_titan";
  2781. case "tower":
  2782. case "clan_dungeon":
  2783. return "get_tower";
  2784. case "pve":
  2785. return "get_pve";
  2786. case "pvp_manual":
  2787. return "get_pvpManual";
  2788. case "grand":
  2789. case "arena":
  2790. case "pvp":
  2791. case "challenge":
  2792. return "get_pvp";
  2793. case "core":
  2794. return "get_core";
  2795. case "boss_10":
  2796. case "boss_11":
  2797. case "boss_12":
  2798. return "get_boss";
  2799. default:
  2800. return "get_clanPvp";
  2801. }
  2802. }
  2803. /**
  2804. * Returns the class name of the passed object
  2805. *
  2806. * Возвращает название класса переданного объекта
  2807. */
  2808. function getClass(obj) {
  2809. return {}.toString.call(obj).slice(8, -1);
  2810. }
  2811. /**
  2812. * Calculates the request signature
  2813. *
  2814. * Расчитывает сигнатуру запроса
  2815. */
  2816. this.getSignature = function(headers, data) {
  2817. const sign = {
  2818. signature: '',
  2819. length: 0,
  2820. add: function (text) {
  2821. this.signature += text;
  2822. if (this.length < this.signature.length) {
  2823. this.length = 3 * (this.signature.length + 1) >> 1;
  2824. }
  2825. },
  2826. }
  2827. sign.add(headers["X-Request-Id"]);
  2828. sign.add(':');
  2829. sign.add(headers["X-Auth-Token"]);
  2830. sign.add(':');
  2831. sign.add(headers["X-Auth-Session-Id"]);
  2832. sign.add(':');
  2833. sign.add(data);
  2834. sign.add(':');
  2835. sign.add('LIBRARY-VERSION=1');
  2836. sign.add('UNIQUE-SESSION-ID=' + headers["X-Env-Unique-Session-Id"]);
  2837.  
  2838. return md5(sign.signature);
  2839. }
  2840. /**
  2841. * Creates an interface
  2842. *
  2843. * Создает интерфейс
  2844. */
  2845. function createInterface() {
  2846. scriptMenu.init({
  2847. showMenu: true
  2848. });
  2849. scriptMenu.addHeader(GM_info.script.name, justInfo);
  2850. scriptMenu.addHeader('v' + GM_info.script.version);
  2851. }
  2852.  
  2853. function addControls() {
  2854. createInterface();
  2855. const checkboxDetails = scriptMenu.addDetails(I18N('SETTINGS'));
  2856. for (let name in checkboxes) {
  2857. if (checkboxes[name].hide) {
  2858. continue;
  2859. }
  2860. checkboxes[name].cbox = scriptMenu.addCheckbox(checkboxes[name].label, checkboxes[name].title, checkboxDetails);
  2861. /**
  2862. * Getting the state of checkboxes from storage
  2863. * Получаем состояние чекбоксов из storage
  2864. */
  2865. let val = storage.get(name, null);
  2866. if (val != null) {
  2867. checkboxes[name].cbox.checked = val;
  2868. } else {
  2869. storage.set(name, checkboxes[name].default);
  2870. checkboxes[name].cbox.checked = checkboxes[name].default;
  2871. }
  2872. /**
  2873. * Tracing the change event of the checkbox for writing to storage
  2874. * Отсеживание события изменения чекбокса для записи в storage
  2875. */
  2876. checkboxes[name].cbox.dataset['name'] = name;
  2877. checkboxes[name].cbox.addEventListener('change', async function (event) {
  2878. const nameCheckbox = this.dataset['name'];
  2879. /*
  2880. if (this.checked && nameCheckbox == 'cancelBattle') {
  2881. this.checked = false;
  2882. if (await popup.confirm(I18N('MSG_BAN_ATTENTION'), [
  2883. { msg: I18N('BTN_NO_I_AM_AGAINST'), result: true },
  2884. { msg: I18N('BTN_YES_I_AGREE'), result: false },
  2885. ])) {
  2886. return;
  2887. }
  2888. this.checked = true;
  2889. }
  2890. */
  2891. storage.set(nameCheckbox, this.checked);
  2892. })
  2893. }
  2894.  
  2895. const inputDetails = scriptMenu.addDetails(I18N('VALUES'));
  2896. for (let name in inputs) {
  2897. inputs[name].input = scriptMenu.addInputText(inputs[name].title, false, inputDetails);
  2898. /**
  2899. * Get inputText state from storage
  2900. * Получаем состояние inputText из storage
  2901. */
  2902. let val = storage.get(name, null);
  2903. if (val != null) {
  2904. inputs[name].input.value = val;
  2905. } else {
  2906. storage.set(name, inputs[name].default);
  2907. inputs[name].input.value = inputs[name].default;
  2908. }
  2909. /**
  2910. * Tracing a field change event for a record in storage
  2911. * Отсеживание события изменения поля для записи в storage
  2912. */
  2913. inputs[name].input.dataset['name'] = name;
  2914. inputs[name].input.addEventListener('input', function () {
  2915. const inputName = this.dataset['name'];
  2916. let value = +this.value;
  2917. if (!value || Number.isNaN(value)) {
  2918. value = storage.get(inputName, inputs[inputName].default);
  2919. inputs[name].input.value = value;
  2920. }
  2921. storage.set(inputName, value);
  2922. })
  2923. }
  2924. }
  2925.  
  2926. /**
  2927. * Sending a request
  2928. *
  2929. * Отправка запроса
  2930. */
  2931. function send(json, callback, pr) {
  2932. if (typeof json == 'string') {
  2933. json = JSON.parse(json);
  2934. }
  2935. for (const call of json.calls) {
  2936. if (!call?.context?.actionTs) {
  2937. call.context = {
  2938. actionTs: Math.floor(performance.now())
  2939. }
  2940. }
  2941. }
  2942. json = JSON.stringify(json);
  2943. /**
  2944. * We get the headlines of the previous intercepted request
  2945. * Получаем заголовки предыдущего перехваченого запроса
  2946. */
  2947. let headers = lastHeaders;
  2948. /**
  2949. * We increase the header of the query Certifier by 1
  2950. * Увеличиваем заголовок идетификатора запроса на 1
  2951. */
  2952. headers["X-Request-Id"]++;
  2953. /**
  2954. * We calculate the title with the signature
  2955. * Расчитываем заголовок с сигнатурой
  2956. */
  2957. headers["X-Auth-Signature"] = getSignature(headers, json);
  2958. /**
  2959. * Create a new ajax request
  2960. * Создаем новый AJAX запрос
  2961. */
  2962. let xhr = new XMLHttpRequest;
  2963. /**
  2964. * Indicate the previously saved URL for API queries
  2965. * Указываем ранее сохраненный URL для API запросов
  2966. */
  2967. xhr.open('POST', apiUrl, true);
  2968. /**
  2969. * Add the function to the event change event
  2970. * Добавляем функцию к событию смены статуса запроса
  2971. */
  2972. xhr.onreadystatechange = function() {
  2973. /**
  2974. * If the result of the request is obtained, we call the flask function
  2975. * Если результат запроса получен вызываем колбек функцию
  2976. */
  2977. if(xhr.readyState == 4) {
  2978. callback(xhr.response, pr);
  2979. }
  2980. };
  2981. /**
  2982. * Indicate the type of request
  2983. * Указываем тип запроса
  2984. */
  2985. xhr.responseType = 'json';
  2986. /**
  2987. * We set the request headers
  2988. * Задаем заголовки запроса
  2989. */
  2990. for(let nameHeader in headers) {
  2991. let head = headers[nameHeader];
  2992. xhr.setRequestHeader(nameHeader, head);
  2993. }
  2994. /**
  2995. * Sending a request
  2996. * Отправляем запрос
  2997. */
  2998. xhr.send(json);
  2999. }
  3000.  
  3001. let hideTimeoutProgress = 0;
  3002. /**
  3003. * Hide progress
  3004. *
  3005. * Скрыть прогресс
  3006. */
  3007. function hideProgress(timeout) {
  3008. timeout = timeout || 0;
  3009. clearTimeout(hideTimeoutProgress);
  3010. hideTimeoutProgress = setTimeout(function () {
  3011. scriptMenu.setStatus('');
  3012. }, timeout);
  3013. }
  3014. /**
  3015. * Progress display
  3016. *
  3017. * Отображение прогресса
  3018. */
  3019. function setProgress(text, hide, onclick) {
  3020. scriptMenu.setStatus(text, onclick);
  3021. hide = hide || false;
  3022. if (hide) {
  3023. hideProgress(3000);
  3024. }
  3025. }
  3026.  
  3027. /**
  3028. * Returns the timer value depending on the subscription
  3029. *
  3030. * Возвращает значение таймера в зависимости от подписки
  3031. */
  3032. function getTimer(time, div) {
  3033. let speedDiv = 5;
  3034. if (subEndTime < Date.now()) {
  3035. speedDiv = div || 1.5;
  3036. }
  3037. return Math.max(Math.ceil(time / speedDiv + 1.5), 4);
  3038. }
  3039.  
  3040. /**
  3041. * Calculates HASH MD5 from string
  3042. *
  3043. * Расчитывает HASH MD5 из строки
  3044. *
  3045. * [js-md5]{@link https://github.com/emn178/js-md5}
  3046. *
  3047. * @namespace md5
  3048. * @version 0.7.3
  3049. * @author Chen, Yi-Cyuan [emn178@gmail.com]
  3050. * @copyright Chen, Yi-Cyuan 2014-2017
  3051. * @license MIT
  3052. */
  3053. !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 _}))}();
  3054.  
  3055. /**
  3056. * Script for beautiful dialog boxes
  3057. *
  3058. * Скрипт для красивых диалоговых окошек
  3059. */
  3060. const popup = new (function () {
  3061. this.popUp,
  3062. this.downer,
  3063. this.middle,
  3064. this.msgText,
  3065. this.buttons = [];
  3066. this.checkboxes = [];
  3067. this.dialogPromice = null;
  3068.  
  3069. function init() {
  3070. addStyle();
  3071. addBlocks();
  3072. addEventListeners();
  3073. }
  3074.  
  3075. const addEventListeners = () => {
  3076. document.addEventListener('keyup', (e) => {
  3077. if (e.key == 'Escape') {
  3078. if (this.dialogPromice) {
  3079. const { func, result } = this.dialogPromice;
  3080. this.dialogPromice = null;
  3081. popup.hide();
  3082. func(result);
  3083. }
  3084. }
  3085. });
  3086. }
  3087.  
  3088. const addStyle = () => {
  3089. let style = document.createElement('style');
  3090. style.innerText = `
  3091. .PopUp_ {
  3092. position: absolute;
  3093. min-width: 300px;
  3094. max-width: 500px;
  3095. max-height: 600px;
  3096. background-color: #190e08e6;
  3097. z-index: 10001;
  3098. top: 169px;
  3099. left: 345px;
  3100. border: 3px #ce9767 solid;
  3101. border-radius: 10px;
  3102. display: flex;
  3103. flex-direction: column;
  3104. justify-content: space-around;
  3105. padding: 15px 9px;
  3106. box-sizing: border-box;
  3107. }
  3108.  
  3109. .PopUp_back {
  3110. position: absolute;
  3111. background-color: #00000066;
  3112. width: 100%;
  3113. height: 100%;
  3114. z-index: 10000;
  3115. top: 0;
  3116. left: 0;
  3117. }
  3118.  
  3119. .PopUp_close {
  3120. width: 40px;
  3121. height: 40px;
  3122. position: absolute;
  3123. right: -18px;
  3124. top: -18px;
  3125. border: 3px solid #c18550;
  3126. border-radius: 20px;
  3127. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  3128. background-position-y: 3px;
  3129. box-shadow: -1px 1px 3px black;
  3130. cursor: pointer;
  3131. box-sizing: border-box;
  3132. }
  3133.  
  3134. .PopUp_close:hover {
  3135. filter: brightness(1.2);
  3136. }
  3137.  
  3138. .PopUp_crossClose {
  3139. width: 100%;
  3140. height: 100%;
  3141. background-size: 65%;
  3142. background-position: center;
  3143. background-repeat: no-repeat;
  3144. 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")
  3145. }
  3146.  
  3147. .PopUp_blocks {
  3148. width: 100%;
  3149. height: 50%;
  3150. display: flex;
  3151. justify-content: space-evenly;
  3152. align-items: center;
  3153. flex-wrap: wrap;
  3154. justify-content: center;
  3155. }
  3156.  
  3157. .PopUp_blocks:last-child {
  3158. margin-top: 25px;
  3159. }
  3160.  
  3161. .PopUp_buttons {
  3162. display: flex;
  3163. margin: 7px 10px;
  3164. flex-direction: column;
  3165. }
  3166.  
  3167. .PopUp_button {
  3168. background-color: #52A81C;
  3169. border-radius: 5px;
  3170. box-shadow: inset 0px -4px 10px, inset 0px 3px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  3171. cursor: pointer;
  3172. padding: 4px 12px 6px;
  3173. }
  3174.  
  3175. .PopUp_input {
  3176. text-align: center;
  3177. font-size: 16px;
  3178. height: 27px;
  3179. border: 1px solid #cf9250;
  3180. border-radius: 9px 9px 0px 0px;
  3181. background: transparent;
  3182. color: #fce1ac;
  3183. padding: 1px 10px;
  3184. box-sizing: border-box;
  3185. box-shadow: 0px 0px 4px, 0px 0px 0px 3px #ce9767;
  3186. }
  3187.  
  3188. .PopUp_checkboxes {
  3189. display: flex;
  3190. flex-direction: column;
  3191. margin: 15px 15px -5px 15px;
  3192. align-items: flex-start;
  3193. }
  3194.  
  3195. .PopUp_ContCheckbox {
  3196. margin: 2px 0px;
  3197. }
  3198.  
  3199. .PopUp_checkbox {
  3200. position: absolute;
  3201. z-index: -1;
  3202. opacity: 0;
  3203. }
  3204. .PopUp_checkbox+label {
  3205. display: inline-flex;
  3206. align-items: center;
  3207. user-select: none;
  3208.  
  3209. font-size: 15px;
  3210. font-family: sans-serif;
  3211. font-weight: 600;
  3212. font-stretch: condensed;
  3213. letter-spacing: 1px;
  3214. color: #fce1ac;
  3215. text-shadow: 0px 0px 1px;
  3216. }
  3217. .PopUp_checkbox+label::before {
  3218. content: '';
  3219. display: inline-block;
  3220. width: 20px;
  3221. height: 20px;
  3222. border: 1px solid #cf9250;
  3223. border-radius: 7px;
  3224. margin-right: 7px;
  3225. }
  3226. .PopUp_checkbox:checked+label::before {
  3227. 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");
  3228. }
  3229.  
  3230. .PopUp_input::placeholder {
  3231. color: #fce1ac75;
  3232. }
  3233.  
  3234. .PopUp_input:focus {
  3235. outline: 0;
  3236. }
  3237.  
  3238. .PopUp_input + .PopUp_button {
  3239. border-radius: 0px 0px 5px 5px;
  3240. padding: 2px 18px 5px;
  3241. }
  3242.  
  3243. .PopUp_button:hover {
  3244. filter: brightness(1.2);
  3245. }
  3246.  
  3247. .PopUp_button:active {
  3248. box-shadow: inset 0px 5px 10px, inset 0px 1px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  3249. }
  3250.  
  3251. .PopUp_text {
  3252. font-size: 22px;
  3253. font-family: sans-serif;
  3254. font-weight: 600;
  3255. font-stretch: condensed;
  3256. letter-spacing: 1px;
  3257. text-align: center;
  3258. }
  3259.  
  3260. .PopUp_buttonText {
  3261. color: #E4FF4C;
  3262. text-shadow: 0px 1px 2px black;
  3263. }
  3264.  
  3265. .PopUp_msgText {
  3266. color: #FDE5B6;
  3267. text-shadow: 0px 0px 2px;
  3268. }
  3269.  
  3270. .PopUp_hideBlock {
  3271. display: none;
  3272. }
  3273. `;
  3274. document.head.appendChild(style);
  3275. }
  3276.  
  3277. const addBlocks = () => {
  3278. this.back = document.createElement('div');
  3279. this.back.classList.add('PopUp_back');
  3280. this.back.classList.add('PopUp_hideBlock');
  3281. document.body.append(this.back);
  3282.  
  3283. this.popUp = document.createElement('div');
  3284. this.popUp.classList.add('PopUp_');
  3285. this.back.append(this.popUp);
  3286.  
  3287. let upper = document.createElement('div')
  3288. upper.classList.add('PopUp_blocks');
  3289. this.popUp.append(upper);
  3290.  
  3291. this.middle = document.createElement('div')
  3292. this.middle.classList.add('PopUp_blocks');
  3293. this.middle.classList.add('PopUp_checkboxes');
  3294. this.popUp.append(this.middle);
  3295.  
  3296. this.downer = document.createElement('div')
  3297. this.downer.classList.add('PopUp_blocks');
  3298. this.popUp.append(this.downer);
  3299.  
  3300. this.msgText = document.createElement('div');
  3301. this.msgText.classList.add('PopUp_text', 'PopUp_msgText');
  3302. upper.append(this.msgText);
  3303. }
  3304.  
  3305. this.showBack = function () {
  3306. this.back.classList.remove('PopUp_hideBlock');
  3307. }
  3308.  
  3309. this.hideBack = function () {
  3310. this.back.classList.add('PopUp_hideBlock');
  3311. }
  3312.  
  3313. this.show = function () {
  3314. if (this.checkboxes.length) {
  3315. this.middle.classList.remove('PopUp_hideBlock');
  3316. }
  3317. this.showBack();
  3318. this.popUp.classList.remove('PopUp_hideBlock');
  3319. this.popUp.style.left = (window.innerWidth - this.popUp.offsetWidth) / 2 + 'px';
  3320. this.popUp.style.top = (window.innerHeight - this.popUp.offsetHeight) / 3 + 'px';
  3321. }
  3322.  
  3323. this.hide = function () {
  3324. this.hideBack();
  3325. this.popUp.classList.add('PopUp_hideBlock');
  3326. }
  3327.  
  3328. this.addAnyButton = (option) => {
  3329. const contButton = document.createElement('div');
  3330. contButton.classList.add('PopUp_buttons');
  3331. this.downer.append(contButton);
  3332.  
  3333. let inputField = {
  3334. value: option.result || option.default
  3335. }
  3336. if (option.isInput) {
  3337. inputField = document.createElement('input');
  3338. inputField.type = 'text';
  3339. if (option.placeholder) {
  3340. inputField.placeholder = option.placeholder;
  3341. }
  3342. if (option.default) {
  3343. inputField.value = option.default;
  3344. }
  3345. inputField.classList.add('PopUp_input');
  3346. contButton.append(inputField);
  3347. }
  3348.  
  3349. const button = document.createElement('div');
  3350. button.classList.add('PopUp_button');
  3351. button.title = option.title || '';
  3352. contButton.append(button);
  3353.  
  3354. const buttonText = document.createElement('div');
  3355. buttonText.classList.add('PopUp_text', 'PopUp_buttonText');
  3356. buttonText.innerText = option.msg;
  3357. button.append(buttonText);
  3358.  
  3359. return { button, contButton, inputField };
  3360. }
  3361.  
  3362. this.addCloseButton = () => {
  3363. let button = document.createElement('div')
  3364. button.classList.add('PopUp_close');
  3365. this.popUp.append(button);
  3366.  
  3367. let crossClose = document.createElement('div')
  3368. crossClose.classList.add('PopUp_crossClose');
  3369. button.append(crossClose);
  3370.  
  3371. return { button, contButton: button };
  3372. }
  3373.  
  3374. this.addButton = (option, buttonClick) => {
  3375.  
  3376. const { button, contButton, inputField } = option.isClose ? this.addCloseButton() : this.addAnyButton(option);
  3377. if (option.isClose) {
  3378. this.dialogPromice = {func: buttonClick, result: option.result};
  3379. }
  3380. button.addEventListener('click', () => {
  3381. let result = '';
  3382. if (option.isInput) {
  3383. result = inputField.value;
  3384. }
  3385. if (option.isClose || option.isCancel) {
  3386. this.dialogPromice = null;
  3387. }
  3388. buttonClick(result);
  3389. });
  3390.  
  3391. this.buttons.push(contButton);
  3392. }
  3393.  
  3394. this.clearButtons = () => {
  3395. while (this.buttons.length) {
  3396. this.buttons.pop().remove();
  3397. }
  3398. }
  3399.  
  3400. this.addCheckBox = (checkBox) => {
  3401. const contCheckbox = document.createElement('div');
  3402. contCheckbox.classList.add('PopUp_ContCheckbox');
  3403. this.middle.append(contCheckbox);
  3404.  
  3405. const checkbox = document.createElement('input');
  3406. checkbox.type = 'checkbox';
  3407. checkbox.id = 'PopUpCheckbox' + this.checkboxes.length;
  3408. checkbox.dataset.name = checkBox.name;
  3409. checkbox.checked = checkBox.checked;
  3410. checkbox.label = checkBox.label;
  3411. checkbox.title = checkBox.title || '';
  3412. checkbox.classList.add('PopUp_checkbox');
  3413. contCheckbox.appendChild(checkbox)
  3414.  
  3415. const checkboxLabel = document.createElement('label');
  3416. checkboxLabel.innerText = checkBox.label;
  3417. checkboxLabel.title = checkBox.title || '';
  3418. checkboxLabel.setAttribute('for', checkbox.id);
  3419. contCheckbox.appendChild(checkboxLabel);
  3420.  
  3421. this.checkboxes.push(checkbox);
  3422. }
  3423.  
  3424. this.clearCheckBox = () => {
  3425. this.middle.classList.add('PopUp_hideBlock');
  3426. while (this.checkboxes.length) {
  3427. this.checkboxes.pop().parentNode.remove();
  3428. }
  3429. }
  3430.  
  3431. this.setMsgText = (text) => {
  3432. this.msgText.innerHTML = text;
  3433. }
  3434.  
  3435. this.getCheckBoxes = () => {
  3436. const checkBoxes = [];
  3437.  
  3438. for (const checkBox of this.checkboxes) {
  3439. checkBoxes.push({
  3440. name: checkBox.dataset.name,
  3441. label: checkBox.label,
  3442. checked: checkBox.checked
  3443. });
  3444. }
  3445.  
  3446. return checkBoxes;
  3447. }
  3448.  
  3449. this.confirm = async (msg, buttOpt, checkBoxes = []) => {
  3450. this.clearButtons();
  3451. this.clearCheckBox();
  3452. return new Promise((complete, failed) => {
  3453. this.setMsgText(msg);
  3454. if (!buttOpt) {
  3455. buttOpt = [{ msg: 'Ok', result: true, isInput: false }];
  3456. }
  3457. for (const checkBox of checkBoxes) {
  3458. this.addCheckBox(checkBox);
  3459. }
  3460. for (let butt of buttOpt) {
  3461. this.addButton(butt, (result) => {
  3462. result = result || butt.result;
  3463. complete(result);
  3464. popup.hide();
  3465. });
  3466. if (butt.isCancel) {
  3467. this.dialogPromice = {func: complete, result: butt.result};
  3468. }
  3469. }
  3470. this.show();
  3471. });
  3472. }
  3473.  
  3474. document.addEventListener('DOMContentLoaded', init);
  3475. });
  3476.  
  3477. /**
  3478. * Script control panel
  3479. *
  3480. * Панель управления скриптом
  3481. */
  3482. const scriptMenu = new (function () {
  3483.  
  3484. this.mainMenu,
  3485. this.buttons = [],
  3486. this.checkboxes = [];
  3487. this.option = {
  3488. showMenu: false,
  3489. showDetails: {}
  3490. };
  3491.  
  3492. this.init = function (option = {}) {
  3493. this.option = Object.assign(this.option, option);
  3494. this.option.showDetails = this.loadShowDetails();
  3495. addStyle();
  3496. addBlocks();
  3497. }
  3498.  
  3499. const addStyle = () => {
  3500. style = document.createElement('style');
  3501. style.innerText = `
  3502. .scriptMenu_status {
  3503. position: absolute;
  3504. z-index: 10001;
  3505. /* max-height: 30px; */
  3506. top: -1px;
  3507. left: 30%;
  3508. cursor: pointer;
  3509. border-radius: 0px 0px 10px 10px;
  3510. background: #190e08e6;
  3511. border: 1px #ce9767 solid;
  3512. font-size: 18px;
  3513. font-family: sans-serif;
  3514. font-weight: 600;
  3515. font-stretch: condensed;
  3516. letter-spacing: 1px;
  3517. color: #fce1ac;
  3518. text-shadow: 0px 0px 1px;
  3519. transition: 0.5s;
  3520. padding: 2px 10px 3px;
  3521. }
  3522. .scriptMenu_statusHide {
  3523. top: -35px;
  3524. height: 30px;
  3525. overflow: hidden;
  3526. }
  3527. .scriptMenu_label {
  3528. position: absolute;
  3529. top: 30%;
  3530. left: -4px;
  3531. z-index: 9999;
  3532. cursor: pointer;
  3533. width: 30px;
  3534. height: 30px;
  3535. background: radial-gradient(circle, #47a41b 0%, #1a2f04 100%);
  3536. border: 1px solid #1a2f04;
  3537. border-radius: 5px;
  3538. box-shadow:
  3539. inset 0px 2px 4px #83ce26,
  3540. inset 0px -4px 6px #1a2f04,
  3541. 0px 0px 2px black,
  3542. 0px 0px 0px 2px #ce9767;
  3543. }
  3544. .scriptMenu_label:hover {
  3545. filter: brightness(1.2);
  3546. }
  3547. .scriptMenu_arrowLabel {
  3548. width: 100%;
  3549. height: 100%;
  3550. background-size: 75%;
  3551. background-position: center;
  3552. background-repeat: no-repeat;
  3553. 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");
  3554. box-shadow: 0px 1px 2px #000;
  3555. border-radius: 5px;
  3556. filter: drop-shadow(0px 1px 2px #000D);
  3557. }
  3558. .scriptMenu_main {
  3559. position: absolute;
  3560. max-width: 285px;
  3561. z-index: 9999;
  3562. top: 50%;
  3563. transform: translateY(-40%);
  3564. background: #190e08e6;
  3565. border: 1px #ce9767 solid;
  3566. border-radius: 0px 10px 10px 0px;
  3567. border-left: none;
  3568. padding: 5px 10px 5px 5px;
  3569. box-sizing: border-box;
  3570. font-size: 15px;
  3571. font-family: sans-serif;
  3572. font-weight: 600;
  3573. font-stretch: condensed;
  3574. letter-spacing: 1px;
  3575. color: #fce1ac;
  3576. text-shadow: 0px 0px 1px;
  3577. transition: 1s;
  3578. display: flex;
  3579. flex-direction: column;
  3580. flex-wrap: nowrap;
  3581. }
  3582. .scriptMenu_showMenu {
  3583. display: none;
  3584. }
  3585. .scriptMenu_showMenu:checked~.scriptMenu_main {
  3586. left: 0px;
  3587. }
  3588. .scriptMenu_showMenu:not(:checked)~.scriptMenu_main {
  3589. left: -300px;
  3590. }
  3591. .scriptMenu_divInput {
  3592. margin: 2px;
  3593. }
  3594. .scriptMenu_divInputText {
  3595. margin: 2px;
  3596. align-self: center;
  3597. display: flex;
  3598. }
  3599. .scriptMenu_checkbox {
  3600. position: absolute;
  3601. z-index: -1;
  3602. opacity: 0;
  3603. }
  3604. .scriptMenu_checkbox+label {
  3605. display: inline-flex;
  3606. align-items: center;
  3607. user-select: none;
  3608. }
  3609. .scriptMenu_checkbox+label::before {
  3610. content: '';
  3611. display: inline-block;
  3612. width: 20px;
  3613. height: 20px;
  3614. border: 1px solid #cf9250;
  3615. border-radius: 7px;
  3616. margin-right: 7px;
  3617. }
  3618. .scriptMenu_checkbox:checked+label::before {
  3619. 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");
  3620. }
  3621. .scriptMenu_close {
  3622. width: 40px;
  3623. height: 40px;
  3624. position: absolute;
  3625. right: -18px;
  3626. top: -18px;
  3627. border: 3px solid #c18550;
  3628. border-radius: 20px;
  3629. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  3630. background-position-y: 3px;
  3631. box-shadow: -1px 1px 3px black;
  3632. cursor: pointer;
  3633. box-sizing: border-box;
  3634. }
  3635. .scriptMenu_close:hover {
  3636. filter: brightness(1.2);
  3637. }
  3638. .scriptMenu_crossClose {
  3639. width: 100%;
  3640. height: 100%;
  3641. background-size: 65%;
  3642. background-position: center;
  3643. background-repeat: no-repeat;
  3644. 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")
  3645. }
  3646. .scriptMenu_button {
  3647. user-select: none;
  3648. border-radius: 5px;
  3649. cursor: pointer;
  3650. padding: 5px 14px 8px;
  3651. margin: 4px;
  3652. background: radial-gradient(circle, rgba(165,120,56,1) 80%, rgba(0,0,0,1) 110%);
  3653. box-shadow: inset 0px -4px 6px #442901, inset 0px 1px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  3654. }
  3655. .scriptMenu_button:hover {
  3656. filter: brightness(1.2);
  3657. }
  3658. .scriptMenu_button:active {
  3659. box-shadow: inset 0px 4px 6px #442901, inset 0px 4px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  3660. }
  3661. .scriptMenu_buttonText {
  3662. color: #fce5b7;
  3663. text-shadow: 0px 1px 2px black;
  3664. text-align: center;
  3665. }
  3666. .scriptMenu_header {
  3667. text-align: center;
  3668. align-self: center;
  3669. font-size: 15px;
  3670. margin: 0px 15px;
  3671. }
  3672. .scriptMenu_header a {
  3673. color: #fce5b7;
  3674. text-decoration: none;
  3675. }
  3676. .scriptMenu_InputText {
  3677. text-align: center;
  3678. width: 130px;
  3679. height: 24px;
  3680. border: 1px solid #cf9250;
  3681. border-radius: 9px;
  3682. background: transparent;
  3683. color: #fce1ac;
  3684. padding: 0px 10px;
  3685. box-sizing: border-box;
  3686. }
  3687. .scriptMenu_InputText:focus {
  3688. filter: brightness(1.2);
  3689. outline: 0;
  3690. }
  3691. .scriptMenu_InputText::placeholder {
  3692. color: #fce1ac75;
  3693. }
  3694. .scriptMenu_Summary {
  3695. cursor: pointer;
  3696. margin-left: 7px;
  3697. }
  3698. .scriptMenu_Details {
  3699. align-self: center;
  3700. }
  3701. `;
  3702. document.head.appendChild(style);
  3703. }
  3704.  
  3705. const addBlocks = () => {
  3706. const main = document.createElement('div');
  3707. document.body.appendChild(main);
  3708.  
  3709. this.status = document.createElement('div');
  3710. this.status.classList.add('scriptMenu_status');
  3711. this.setStatus('');
  3712. main.appendChild(this.status);
  3713.  
  3714. const label = document.createElement('label');
  3715. label.classList.add('scriptMenu_label');
  3716. label.setAttribute('for', 'checkbox_showMenu');
  3717. main.appendChild(label);
  3718.  
  3719. const arrowLabel = document.createElement('div');
  3720. arrowLabel.classList.add('scriptMenu_arrowLabel');
  3721. label.appendChild(arrowLabel);
  3722.  
  3723. const checkbox = document.createElement('input');
  3724. checkbox.type = 'checkbox';
  3725. checkbox.id = 'checkbox_showMenu';
  3726. checkbox.checked = this.option.showMenu;
  3727. checkbox.classList.add('scriptMenu_showMenu');
  3728. main.appendChild(checkbox);
  3729.  
  3730. this.mainMenu = document.createElement('div');
  3731. this.mainMenu.classList.add('scriptMenu_main');
  3732. main.appendChild(this.mainMenu);
  3733.  
  3734. const closeButton = document.createElement('label');
  3735. closeButton.classList.add('scriptMenu_close');
  3736. closeButton.setAttribute('for', 'checkbox_showMenu');
  3737. this.mainMenu.appendChild(closeButton);
  3738.  
  3739. const crossClose = document.createElement('div');
  3740. crossClose.classList.add('scriptMenu_crossClose');
  3741. closeButton.appendChild(crossClose);
  3742. }
  3743.  
  3744. this.setStatus = (text, onclick) => {
  3745. if (!text) {
  3746. this.status.classList.add('scriptMenu_statusHide');
  3747. } else {
  3748. this.status.classList.remove('scriptMenu_statusHide');
  3749. this.status.innerHTML = text;
  3750. }
  3751.  
  3752. if (typeof onclick == 'function') {
  3753. this.status.addEventListener("click", onclick, {
  3754. once: true
  3755. });
  3756. }
  3757. }
  3758.  
  3759. /**
  3760. * Adding a text element
  3761. *
  3762. * Добавление текстового элемента
  3763. * @param {String} text text // текст
  3764. * @param {Function} func Click function // функция по клику
  3765. * @param {HTMLDivElement} main parent // родитель
  3766. */
  3767. this.addHeader = (text, func, main) => {
  3768. main = main || this.mainMenu;
  3769. const header = document.createElement('div');
  3770. header.classList.add('scriptMenu_header');
  3771. header.innerHTML = text;
  3772. if (typeof func == 'function') {
  3773. header.addEventListener('click', func);
  3774. }
  3775. main.appendChild(header);
  3776. }
  3777.  
  3778. /**
  3779. * Adding a button
  3780. *
  3781. * Добавление кнопки
  3782. * @param {String} text
  3783. * @param {Function} func
  3784. * @param {String} title
  3785. * @param {HTMLDivElement} main parent // родитель
  3786. */
  3787. this.addButton = (text, func, title, main) => {
  3788. main = main || this.mainMenu;
  3789. const button = document.createElement('div');
  3790. button.classList.add('scriptMenu_button');
  3791. button.title = title;
  3792. button.addEventListener('click', func);
  3793. main.appendChild(button);
  3794.  
  3795. const buttonText = document.createElement('div');
  3796. buttonText.classList.add('scriptMenu_buttonText');
  3797. buttonText.innerText = text;
  3798. button.appendChild(buttonText);
  3799. this.buttons.push(button);
  3800.  
  3801. return button;
  3802. }
  3803.  
  3804. /**
  3805. * Adding checkbox
  3806. *
  3807. * Добавление чекбокса
  3808. * @param {String} label
  3809. * @param {String} title
  3810. * @param {HTMLDivElement} main parent // родитель
  3811. * @returns
  3812. */
  3813. this.addCheckbox = (label, title, main) => {
  3814. main = main || this.mainMenu;
  3815. const divCheckbox = document.createElement('div');
  3816. divCheckbox.classList.add('scriptMenu_divInput');
  3817. divCheckbox.title = title;
  3818. main.appendChild(divCheckbox);
  3819.  
  3820. const checkbox = document.createElement('input');
  3821. checkbox.type = 'checkbox';
  3822. checkbox.id = 'scriptMenuCheckbox' + this.checkboxes.length;
  3823. checkbox.classList.add('scriptMenu_checkbox');
  3824. divCheckbox.appendChild(checkbox)
  3825.  
  3826. const checkboxLabel = document.createElement('label');
  3827. checkboxLabel.innerText = label;
  3828. checkboxLabel.setAttribute('for', checkbox.id);
  3829. divCheckbox.appendChild(checkboxLabel);
  3830.  
  3831. this.checkboxes.push(checkbox);
  3832. return checkbox;
  3833. }
  3834.  
  3835. /**
  3836. * Adding input field
  3837. *
  3838. * Добавление поля ввода
  3839. * @param {String} title
  3840. * @param {String} placeholder
  3841. * @param {HTMLDivElement} main parent // родитель
  3842. * @returns
  3843. */
  3844. this.addInputText = (title, placeholder, main) => {
  3845. main = main || this.mainMenu;
  3846. const divInputText = document.createElement('div');
  3847. divInputText.classList.add('scriptMenu_divInputText');
  3848. divInputText.title = title;
  3849. main.appendChild(divInputText);
  3850.  
  3851. const newInputText = document.createElement('input');
  3852. newInputText.type = 'text';
  3853. if (placeholder) {
  3854. newInputText.placeholder = placeholder;
  3855. }
  3856. newInputText.classList.add('scriptMenu_InputText');
  3857. divInputText.appendChild(newInputText)
  3858. return newInputText;
  3859. }
  3860.  
  3861. /**
  3862. * Adds a dropdown block
  3863. *
  3864. * Добавляет раскрывающийся блок
  3865. * @param {String} summary
  3866. * @param {String} name
  3867. * @returns
  3868. */
  3869. this.addDetails = (summaryText, name = null) => {
  3870. const details = document.createElement('details');
  3871. details.classList.add('scriptMenu_Details');
  3872. this.mainMenu.appendChild(details);
  3873.  
  3874. const summary = document.createElement('summary');
  3875. summary.classList.add('scriptMenu_Summary');
  3876. summary.innerText = summaryText;
  3877. if (name) {
  3878. const self = this;
  3879. details.open = this.option.showDetails[name];
  3880. details.dataset.name = name;
  3881. summary.addEventListener('click', () => {
  3882. self.option.showDetails[details.dataset.name] = !details.open;
  3883. self.saveShowDetails(self.option.showDetails);
  3884. });
  3885. }
  3886. details.appendChild(summary);
  3887.  
  3888. return details;
  3889. }
  3890.  
  3891. /**
  3892. * Saving the expanded state of the details blocks
  3893. *
  3894. * Сохранение состояния развенутости блоков details
  3895. * @param {*} value
  3896. */
  3897. this.saveShowDetails = (value) => {
  3898. localStorage.setItem('scriptMenu_showDetails', JSON.stringify(value));
  3899. }
  3900.  
  3901. /**
  3902. * Loading the state of expanded blocks details
  3903. *
  3904. * Загрузка состояния развенутости блоков details
  3905. * @returns
  3906. */
  3907. this.loadShowDetails = () => {
  3908. let showDetails = localStorage.getItem('scriptMenu_showDetails');
  3909.  
  3910. if (!showDetails) {
  3911. return {};
  3912. }
  3913.  
  3914. try {
  3915. showDetails = JSON.parse(showDetails);
  3916. } catch (e) {
  3917. return {};
  3918. }
  3919.  
  3920. return showDetails;
  3921. }
  3922. });
  3923.  
  3924. /**
  3925. * Пример использования
  3926. scriptMenu.init();
  3927. scriptMenu.addHeader('v1.508');
  3928. scriptMenu.addCheckbox('testHack', 'Тестовый взлом игры!');
  3929. scriptMenu.addButton('Запуск!', () => console.log('click'), 'подсказака');
  3930. scriptMenu.addInputText('input подсказака');
  3931. */
  3932. /**
  3933. * Game Library
  3934. *
  3935. * Игровая библиотека
  3936. */
  3937. class Library {
  3938. defaultLibUrl = 'https://heroesru-a.akamaihd.net/vk/v1101/lib/lib.json';
  3939.  
  3940. constructor() {
  3941. if (!Library.instance) {
  3942. Library.instance = this;
  3943. }
  3944.  
  3945. return Library.instance;
  3946. }
  3947.  
  3948. async load() {
  3949. try {
  3950. await this.getUrlLib();
  3951. console.log(this.defaultLibUrl);
  3952. this.data = await fetch(this.defaultLibUrl).then(e => e.json())
  3953. } catch (error) {
  3954. console.error('Не удалось загрузить библиотеку', error)
  3955. }
  3956. }
  3957.  
  3958. async getUrlLib() {
  3959. try {
  3960. const db = new Database('hw_cache', 'cache');
  3961. await db.open();
  3962. const cacheLibFullUrl = await db.get('lib/lib.json.gz', false);
  3963. this.defaultLibUrl = cacheLibFullUrl.fullUrl.split('.gz').shift();
  3964. } catch(e) {}
  3965. }
  3966.  
  3967. getData(id) {
  3968. return this.data[id];
  3969. }
  3970. }
  3971.  
  3972. this.lib = new Library();
  3973. /**
  3974. * Database
  3975. *
  3976. * База данных
  3977. */
  3978. class Database {
  3979. constructor(dbName, storeName) {
  3980. this.dbName = dbName;
  3981. this.storeName = storeName;
  3982. this.db = null;
  3983. }
  3984.  
  3985. async open() {
  3986. return new Promise((resolve, reject) => {
  3987. const request = indexedDB.open(this.dbName);
  3988.  
  3989. request.onerror = () => {
  3990. reject(new Error(`Failed to open database ${this.dbName}`));
  3991. };
  3992.  
  3993. request.onsuccess = () => {
  3994. this.db = request.result;
  3995. resolve();
  3996. };
  3997.  
  3998. request.onupgradeneeded = (event) => {
  3999. const db = event.target.result;
  4000. if (!db.objectStoreNames.contains(this.storeName)) {
  4001. db.createObjectStore(this.storeName);
  4002. }
  4003. };
  4004. });
  4005. }
  4006.  
  4007. async set(key, value) {
  4008. return new Promise((resolve, reject) => {
  4009. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4010. const store = transaction.objectStore(this.storeName);
  4011. const request = store.put(value, key);
  4012.  
  4013. request.onerror = () => {
  4014. reject(new Error(`Failed to save value with key ${key}`));
  4015. };
  4016.  
  4017. request.onsuccess = () => {
  4018. resolve();
  4019. };
  4020. });
  4021. }
  4022.  
  4023. async get(key, def) {
  4024. return new Promise((resolve, reject) => {
  4025. const transaction = this.db.transaction([this.storeName], 'readonly');
  4026. const store = transaction.objectStore(this.storeName);
  4027. const request = store.get(key);
  4028.  
  4029. request.onerror = () => {
  4030. resolve(def);
  4031. };
  4032.  
  4033. request.onsuccess = () => {
  4034. resolve(request.result);
  4035. };
  4036. });
  4037. }
  4038.  
  4039. async delete(key) {
  4040. return new Promise((resolve, reject) => {
  4041. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4042. const store = transaction.objectStore(this.storeName);
  4043. const request = store.delete(key);
  4044.  
  4045. request.onerror = () => {
  4046. reject(new Error(`Failed to delete value with key ${key}`));
  4047. };
  4048.  
  4049. request.onsuccess = () => {
  4050. resolve();
  4051. };
  4052. });
  4053. }
  4054. }
  4055.  
  4056. /**
  4057. * Returns the stored value
  4058. *
  4059. * Возвращает сохраненное значение
  4060. */
  4061. function getSaveVal(saveName, def) {
  4062. const result = storage.get(saveName, def);
  4063. return result;
  4064. }
  4065.  
  4066. /**
  4067. * Stores value
  4068. *
  4069. * Сохраняет значение
  4070. */
  4071. function setSaveVal(saveName, value) {
  4072. storage.set(saveName, value);
  4073. }
  4074.  
  4075. /**
  4076. * Database initialization
  4077. *
  4078. * Инициализация базы данных
  4079. */
  4080. const db = new Database(GM_info.script.name, 'settings');
  4081.  
  4082. /**
  4083. * Data store
  4084. *
  4085. * Хранилище данных
  4086. */
  4087. const storage = {
  4088. userId: 0,
  4089. /**
  4090. * Default values
  4091. *
  4092. * Значения по умолчанию
  4093. */
  4094. values: [
  4095. ...Object.entries(checkboxes).map(e => ({ [e[0]]: e[1].default })),
  4096. ...Object.entries(inputs).map(e => ({ [e[0]]: e[1].default })),
  4097. ].reduce((acc, obj) => ({ ...acc, ...obj }), {}),
  4098. name: GM_info.script.name,
  4099. get: function (key, def) {
  4100. if (key in this.values) {
  4101. return this.values[key];
  4102. }
  4103. return def;
  4104. },
  4105. set: function (key, value) {
  4106. this.values[key] = value;
  4107. db.set(this.userId, this.values).catch(
  4108. e => null
  4109. );
  4110. localStorage[this.name + ':' + key] = value;
  4111. },
  4112. delete: function (key) {
  4113. delete this.values[key];
  4114. db.set(this.userId, this.values);
  4115. delete localStorage[this.name + ':' + key];
  4116. }
  4117. }
  4118.  
  4119. /**
  4120. * Returns all keys from localStorage that start with prefix (for migration)
  4121. *
  4122. * Возвращает все ключи из localStorage которые начинаются с prefix (для миграции)
  4123. */
  4124. function getAllValuesStartingWith(prefix) {
  4125. const values = [];
  4126. for (let i = 0; i < localStorage.length; i++) {
  4127. const key = localStorage.key(i);
  4128. if (key.startsWith(prefix)) {
  4129. const val = localStorage.getItem(key);
  4130. const keyValue = key.split(':')[1];
  4131. values.push({ key: keyValue, val });
  4132. }
  4133. }
  4134. return values;
  4135. }
  4136.  
  4137. /**
  4138. * Opens or migrates to a database
  4139. *
  4140. * Открывает или мигрирует в базу данных
  4141. */
  4142. async function openOrMigrateDatabase(userId) {
  4143. storage.userId = userId;
  4144. try {
  4145. await db.open();
  4146. } catch(e) {
  4147. return;
  4148. }
  4149. let settings = await db.get(userId, false);
  4150.  
  4151. if (settings) {
  4152. storage.values = settings;
  4153. return;
  4154. }
  4155.  
  4156. const values = getAllValuesStartingWith(GM_info.script.name);
  4157. for (const value of values) {
  4158. let val = null;
  4159. try {
  4160. val = JSON.parse(value.val);
  4161. } catch {
  4162. break;
  4163. }
  4164. storage.values[value.key] = val;
  4165. }
  4166. await db.set(userId, storage.values);
  4167. }
  4168.  
  4169. /**
  4170. * Sending expeditions
  4171. *
  4172. * Отправка экспедиций
  4173. */
  4174. function checkExpedition() {
  4175. return new Promise((resolve, reject) => {
  4176. const expedition = new Expedition(resolve, reject);
  4177. expedition.start();
  4178. });
  4179. }
  4180.  
  4181. class Expedition {
  4182. checkExpedInfo = {
  4183. calls: [
  4184. {
  4185. name: 'expeditionGet',
  4186. args: {},
  4187. ident: 'expeditionGet',
  4188. },
  4189. {
  4190. name: 'heroGetAll',
  4191. args: {},
  4192. ident: 'heroGetAll',
  4193. },
  4194. ],
  4195. };
  4196.  
  4197. constructor(resolve, reject) {
  4198. this.resolve = resolve;
  4199. this.reject = reject;
  4200. }
  4201.  
  4202. async start() {
  4203. const data = await Send(JSON.stringify(this.checkExpedInfo));
  4204.  
  4205. const expedInfo = data.results[0].result.response;
  4206. const dataHeroes = data.results[1].result.response;
  4207. const dataExped = { useHeroes: [], exped: [] };
  4208. const calls = [];
  4209.  
  4210. /**
  4211. * Adding expeditions to collect
  4212. * Добавляем экспедиции для сбора
  4213. */
  4214. let countGet = 0;
  4215. for (var n in expedInfo) {
  4216. const exped = expedInfo[n];
  4217. const dateNow = Date.now() / 1000;
  4218. if (exped.status == 2 && exped.endTime != 0 && dateNow > exped.endTime) {
  4219. countGet++;
  4220. calls.push({
  4221. name: 'expeditionFarm',
  4222. args: { expeditionId: exped.id },
  4223. ident: 'expeditionFarm_' + exped.id,
  4224. });
  4225. } else {
  4226. dataExped.useHeroes = dataExped.useHeroes.concat(exped.heroes);
  4227. }
  4228. if (exped.status == 1) {
  4229. dataExped.exped.push({ id: exped.id, power: exped.power });
  4230. }
  4231. }
  4232. dataExped.exped = dataExped.exped.sort((a, b) => b.power - a.power);
  4233.  
  4234. /**
  4235. * Putting together a list of heroes
  4236. * Собираем список героев
  4237. */
  4238. const heroesArr = [];
  4239. for (let n in dataHeroes) {
  4240. const hero = dataHeroes[n];
  4241. if (hero.xp > 0 && !dataExped.useHeroes.includes(hero.id)) {
  4242. let heroPower = hero.power;
  4243. // Лара Крофт * 3
  4244. if (hero.id == 63 && hero.color >= 16) {
  4245. heroPower *= 3;
  4246. }
  4247. heroesArr.push({ id: hero.id, power: heroPower });
  4248. }
  4249. }
  4250.  
  4251. /**
  4252. * Adding expeditions to send
  4253. * Добавляем экспедиции для отправки
  4254. */
  4255. let countSend = 0;
  4256. heroesArr.sort((a, b) => a.power - b.power);
  4257. for (const exped of dataExped.exped) {
  4258. let heroesIds = this.selectionHeroes(heroesArr, exped.power);
  4259. if (heroesIds && heroesIds.length > 4) {
  4260. for (let q in heroesArr) {
  4261. if (heroesIds.includes(heroesArr[q].id)) {
  4262. delete heroesArr[q];
  4263. }
  4264. }
  4265. countSend++;
  4266. calls.push({
  4267. name: 'expeditionSendHeroes',
  4268. args: {
  4269. expeditionId: exped.id,
  4270. heroes: heroesIds,
  4271. },
  4272. ident: 'expeditionSendHeroes_' + exped.id,
  4273. });
  4274. }
  4275. }
  4276.  
  4277. if (calls.length) {
  4278. await Send({ calls });
  4279. this.end(I18N('EXPEDITIONS_SENT', {countGet, countSend}));
  4280. return;
  4281. }
  4282.  
  4283. this.end(I18N('EXPEDITIONS_NOTHING'));
  4284. }
  4285.  
  4286. /**
  4287. * Selection of heroes for expeditions
  4288. *
  4289. * Подбор героев для экспедиций
  4290. */
  4291. selectionHeroes(heroes, power) {
  4292. const resultHeroers = [];
  4293. const heroesIds = [];
  4294. for (let q = 0; q < 5; q++) {
  4295. for (let i in heroes) {
  4296. let hero = heroes[i];
  4297. if (heroesIds.includes(hero.id)) {
  4298. continue;
  4299. }
  4300.  
  4301. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  4302. const need = Math.round((power - summ) / (5 - resultHeroers.length));
  4303. if (hero.power > need) {
  4304. resultHeroers.push(hero);
  4305. heroesIds.push(hero.id);
  4306. break;
  4307. }
  4308. }
  4309. }
  4310.  
  4311. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  4312. if (summ < power) {
  4313. return false;
  4314. }
  4315. return heroesIds;
  4316. }
  4317.  
  4318. /**
  4319. * Ends expedition script
  4320. *
  4321. * Завершает скрипт экспедиции
  4322. */
  4323. end(msg) {
  4324. setProgress(msg, true);
  4325. this.resolve();
  4326. }
  4327. }
  4328.  
  4329. /**
  4330. * Walkthrough of the dungeon
  4331. *
  4332. * Прохождение подземелья
  4333. */
  4334. function testDungeon() {
  4335. return new Promise((resolve, reject) => {
  4336. const dung = new executeDungeon(resolve, reject);
  4337. const titanit = getInput('countTitanit');
  4338. dung.start(titanit);
  4339. });
  4340. }
  4341.  
  4342. /**
  4343. * Walkthrough of the dungeon
  4344. *
  4345. * Прохождение подземелья
  4346. */
  4347. function executeDungeon(resolve, reject) {
  4348. dungeonActivity = 0;
  4349. maxDungeonActivity = 150;
  4350.  
  4351. titanGetAll = [];
  4352.  
  4353. teams = {
  4354. heroes: [],
  4355. earth: [],
  4356. fire: [],
  4357. neutral: [],
  4358. water: [],
  4359. }
  4360.  
  4361. titanStats = [];
  4362.  
  4363. titansStates = {};
  4364.  
  4365. callsExecuteDungeon = {
  4366. calls: [{
  4367. name: "dungeonGetInfo",
  4368. args: {},
  4369. ident: "dungeonGetInfo"
  4370. }, {
  4371. name: "teamGetAll",
  4372. args: {},
  4373. ident: "teamGetAll"
  4374. }, {
  4375. name: "teamGetFavor",
  4376. args: {},
  4377. ident: "teamGetFavor"
  4378. }, {
  4379. name: "clanGetInfo",
  4380. args: {},
  4381. ident: "clanGetInfo"
  4382. }, {
  4383. name: "titanGetAll",
  4384. args: {},
  4385. ident: "titanGetAll"
  4386. }, {
  4387. name: "inventoryGet",
  4388. args: {},
  4389. ident: "inventoryGet"
  4390. }]
  4391. }
  4392.  
  4393. this.start = function(titanit) {
  4394. maxDungeonActivity = titanit || getInput('countTitanit');
  4395. send(JSON.stringify(callsExecuteDungeon), startDungeon);
  4396. }
  4397.  
  4398. /**
  4399. * Getting data on the dungeon
  4400. *
  4401. * Получаем данные по подземелью
  4402. */
  4403. function startDungeon(e) {
  4404. res = e.results;
  4405. dungeonGetInfo = res[0].result.response;
  4406. if (!dungeonGetInfo) {
  4407. endDungeon('noDungeon', res);
  4408. return;
  4409. }
  4410. teamGetAll = res[1].result.response;
  4411. teamGetFavor = res[2].result.response;
  4412. dungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  4413. titanGetAll = Object.values(res[4].result.response);
  4414. countPredictionCard = res[5].result.response.consumable[81];
  4415.  
  4416. teams.hero = {
  4417. favor: teamGetFavor.dungeon_hero,
  4418. heroes: teamGetAll.dungeon_hero.filter(id => id < 6000),
  4419. teamNum: 0,
  4420. }
  4421. heroPet = teamGetAll.dungeon_hero.filter(id => id >= 6000).pop();
  4422. if (heroPet) {
  4423. teams.hero.pet = heroPet;
  4424. }
  4425.  
  4426. teams.neutral = {
  4427. favor: {},
  4428. heroes: getTitanTeam(titanGetAll, 'neutral'),
  4429. teamNum: 0,
  4430. };
  4431. teams.water = {
  4432. favor: {},
  4433. heroes: getTitanTeam(titanGetAll, 'water'),
  4434. teamNum: 0,
  4435. };
  4436. teams.fire = {
  4437. favor: {},
  4438. heroes: getTitanTeam(titanGetAll, 'fire'),
  4439. teamNum: 0,
  4440. };
  4441. teams.earth = {
  4442. favor: {},
  4443. heroes: getTitanTeam(titanGetAll, 'earth'),
  4444. teamNum: 0,
  4445. };
  4446.  
  4447.  
  4448. checkFloor(dungeonGetInfo);
  4449. }
  4450.  
  4451. function getTitanTeam(titans, type) {
  4452. switch (type) {
  4453. case 'neutral':
  4454. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4455. case 'water':
  4456. return titans.filter(e => e.id.toString().slice(2, 3) == '0').map(e => e.id);
  4457. case 'fire':
  4458. return titans.filter(e => e.id.toString().slice(2, 3) == '1').map(e => e.id);
  4459. case 'earth':
  4460. return titans.filter(e => e.id.toString().slice(2, 3) == '2').map(e => e.id);
  4461. }
  4462. }
  4463.  
  4464. function getNeutralTeam() {
  4465. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  4466. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4467. }
  4468.  
  4469. function fixTitanTeam(titans) {
  4470. titans.heroes = titans.heroes.filter(e => !titansStates[e]?.isDead);
  4471. return titans;
  4472. }
  4473.  
  4474. /**
  4475. * Checking the floor
  4476. *
  4477. * Проверяем этаж
  4478. */
  4479. async function checkFloor(dungeonInfo) {
  4480. if (!('floor' in dungeonInfo) || dungeonInfo.floor?.state == 2) {
  4481. saveProgress();
  4482. return;
  4483. }
  4484. // console.log(dungeonInfo, dungeonActivity);
  4485. setProgress(`${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  4486. if (dungeonActivity >= maxDungeonActivity) {
  4487. endDungeon('endDungeon', 'maxActive ' + dungeonActivity + '/' + maxDungeonActivity);
  4488. return;
  4489. }
  4490. titansStates = dungeonInfo.states.titans;
  4491. titanStats = titanObjToArray(titansStates);
  4492. const floorChoices = dungeonInfo.floor.userData;
  4493. const floorType = dungeonInfo.floorType;
  4494. //const primeElement = dungeonInfo.elements.prime;
  4495. if (floorType == "battle") {
  4496. const calls = [];
  4497. for (let teamNum in floorChoices) {
  4498. attackerType = floorChoices[teamNum].attackerType;
  4499. const args = fixTitanTeam(teams[attackerType]);
  4500. if (attackerType == 'neutral') {
  4501. args.heroes = getNeutralTeam();
  4502. }
  4503. if (!args.heroes.length) {
  4504. continue;
  4505. }
  4506. args.teamNum = teamNum;
  4507. calls.push({
  4508. name: "dungeonStartBattle",
  4509. args,
  4510. ident: "body_" + teamNum
  4511. })
  4512. }
  4513. if (!calls.length) {
  4514. endDungeon('endDungeon', 'All Dead');
  4515. return;
  4516. }
  4517. const battleDatas = await Send(JSON.stringify({ calls }))
  4518. .then(e => e.results.map(n => n.result.response))
  4519. const battleResults = [];
  4520. for (n in battleDatas) {
  4521. battleData = battleDatas[n]
  4522. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  4523. battleResults.push(await Calc(battleData).then(result => {
  4524. result.teamNum = n;
  4525. result.attackerType = floorChoices[n].attackerType;
  4526. return result;
  4527. }));
  4528. }
  4529. processingPromises(battleResults)
  4530. }
  4531. }
  4532.  
  4533. function processingPromises(results) {
  4534. let selectBattle = results[0];
  4535. if (results.length < 2) {
  4536. // console.log(selectBattle);
  4537. if (!selectBattle.result.win) {
  4538. endDungeon('dungeonEndBattle\n', selectBattle);
  4539. return;
  4540. }
  4541. endBattle(selectBattle);
  4542. return;
  4543. }
  4544.  
  4545. selectBattle = false;
  4546. let bestState = -1000;
  4547. for (const result of results) {
  4548. const recovery = getState(result);
  4549. if (recovery > bestState) {
  4550. bestState = recovery;
  4551. selectBattle = result
  4552. }
  4553. }
  4554. // console.log(selectBattle.teamNum, results);
  4555. if (!selectBattle || bestState <= -1000) {
  4556. endDungeon('dungeonEndBattle\n', results);
  4557. return;
  4558. }
  4559.  
  4560. startBattle(selectBattle.teamNum, selectBattle.attackerType)
  4561. .then(endBattle);
  4562. }
  4563.  
  4564. /**
  4565. * Let's start the fight
  4566. *
  4567. * Начинаем бой
  4568. */
  4569. function startBattle(teamNum, attackerType) {
  4570. return new Promise(function (resolve, reject) {
  4571. args = fixTitanTeam(teams[attackerType]);
  4572. args.teamNum = teamNum;
  4573. if (attackerType == 'neutral') {
  4574. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  4575. args.heroes = titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4576. }
  4577. startBattleCall = {
  4578. calls: [{
  4579. name: "dungeonStartBattle",
  4580. args,
  4581. ident: "body"
  4582. }]
  4583. }
  4584. send(JSON.stringify(startBattleCall), resultBattle, {
  4585. resolve,
  4586. teamNum,
  4587. attackerType
  4588. });
  4589. });
  4590. }
  4591. /**
  4592. * Returns the result of the battle in a promise
  4593. *
  4594. * Возращает резульат боя в промис
  4595. */
  4596. function resultBattle(resultBattles, args) {
  4597. battleData = resultBattles.results[0].result.response;
  4598. battleType = "get_tower";
  4599. if (battleData.type == "dungeon_titan") {
  4600. battleType = "get_titan";
  4601. }
  4602. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  4603. BattleCalc(battleData, battleType, function (result) {
  4604. result.teamNum = args.teamNum;
  4605. result.attackerType = args.attackerType;
  4606. args.resolve(result);
  4607. });
  4608. }
  4609. /**
  4610. * Finishing the fight
  4611. *
  4612. * Заканчиваем бой
  4613. */
  4614. async function endBattle(battleInfo) {
  4615. if (battleInfo.result.win) {
  4616. const args = {
  4617. result: battleInfo.result,
  4618. progress: battleInfo.progress,
  4619. }
  4620. if (countPredictionCard > 0) {
  4621. args.isRaid = true;
  4622. } else {
  4623. const timer = getTimer(battleInfo.battleTime);
  4624. console.log(timer);
  4625. await countdownTimer(timer, `${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  4626. }
  4627. const calls = [{
  4628. name: "dungeonEndBattle",
  4629. args,
  4630. ident: "body"
  4631. }];
  4632. lastDungeonBattleData = null;
  4633. send(JSON.stringify({ calls }), resultEndBattle);
  4634. } else {
  4635. endDungeon('dungeonEndBattle win: false\n', battleInfo);
  4636. }
  4637. }
  4638.  
  4639. /**
  4640. * Getting and processing battle results
  4641. *
  4642. * Получаем и обрабатываем результаты боя
  4643. */
  4644. function resultEndBattle(e) {
  4645. if ('error' in e) {
  4646. popup.confirm(I18N('ERROR_MSG', {
  4647. name: e.error.name,
  4648. description: e.error.description,
  4649. }));
  4650. endDungeon('errorRequest', e);
  4651. return;
  4652. }
  4653. battleResult = e.results[0].result.response;
  4654. if ('error' in battleResult) {
  4655. endDungeon('errorBattleResult', battleResult);
  4656. return;
  4657. }
  4658. dungeonGetInfo = battleResult.dungeon ?? battleResult;
  4659. dungeonActivity += battleResult.reward.dungeonActivity ?? 0;
  4660. checkFloor(dungeonGetInfo);
  4661. }
  4662.  
  4663. /**
  4664. * Returns the coefficient of condition of the
  4665. * difference in titanium before and after the battle
  4666. *
  4667. * Возвращает коэффициент состояния титанов после боя
  4668. */
  4669. function getState(result) {
  4670. if (!result.result.win) {
  4671. return -1000;
  4672. }
  4673.  
  4674. let beforeSumFactor = 0;
  4675. const beforeTitans = result.battleData.attackers;
  4676. for (let titanId in beforeTitans) {
  4677. const titan = beforeTitans[titanId];
  4678. const state = titan.state;
  4679. let factor = 1;
  4680. if (state) {
  4681. const hp = state.hp / titan.hp;
  4682. const energy = state.energy / 1e3;
  4683. factor = hp + energy / 20
  4684. }
  4685. beforeSumFactor += factor;
  4686. }
  4687.  
  4688. let afterSumFactor = 0;
  4689. const afterTitans = result.progress[0].attackers.heroes;
  4690. for (let titanId in afterTitans) {
  4691. const titan = afterTitans[titanId];
  4692. const hp = titan.hp / beforeTitans[titanId].hp;
  4693. const energy = titan.energy / 1e3;
  4694. const factor = hp + energy / 20;
  4695. afterSumFactor += factor;
  4696. }
  4697. return afterSumFactor - beforeSumFactor;
  4698. }
  4699.  
  4700. /**
  4701. * Converts an object with IDs to an array with IDs
  4702. *
  4703. * Преобразует объект с идетификаторами в массив с идетификаторами
  4704. */
  4705. function titanObjToArray(obj) {
  4706. let titans = [];
  4707. for (let id in obj) {
  4708. obj[id].id = id;
  4709. titans.push(obj[id]);
  4710. }
  4711. return titans;
  4712. }
  4713.  
  4714. function saveProgress() {
  4715. let saveProgressCall = {
  4716. calls: [{
  4717. name: "dungeonSaveProgress",
  4718. args: {},
  4719. ident: "body"
  4720. }]
  4721. }
  4722. send(JSON.stringify(saveProgressCall), resultEndBattle);
  4723. }
  4724.  
  4725. function endDungeon(reason, info) {
  4726. console.warn(reason, info);
  4727. setProgress(`${I18N('DUNGEON')} ${I18N('COMPLETED')}`, true);
  4728. resolve();
  4729. }
  4730. }
  4731.  
  4732. /**
  4733. * Passing the tower
  4734. *
  4735. * Прохождение башни
  4736. */
  4737. function testTower() {
  4738. return new Promise((resolve, reject) => {
  4739. tower = new executeTower(resolve, reject);
  4740. tower.start();
  4741. });
  4742. }
  4743.  
  4744. /**
  4745. * Passing the tower
  4746. *
  4747. * Прохождение башни
  4748. */
  4749. function executeTower(resolve, reject) {
  4750. lastTowerInfo = {};
  4751.  
  4752. scullCoin = 0;
  4753.  
  4754. heroGetAll = [];
  4755.  
  4756. heroesStates = {};
  4757.  
  4758. argsBattle = {
  4759. heroes: [],
  4760. favor: {},
  4761. };
  4762.  
  4763. callsExecuteTower = {
  4764. calls: [{
  4765. name: "towerGetInfo",
  4766. args: {},
  4767. ident: "towerGetInfo"
  4768. }, {
  4769. name: "teamGetAll",
  4770. args: {},
  4771. ident: "teamGetAll"
  4772. }, {
  4773. name: "teamGetFavor",
  4774. args: {},
  4775. ident: "teamGetFavor"
  4776. }, {
  4777. name: "inventoryGet",
  4778. args: {},
  4779. ident: "inventoryGet"
  4780. }, {
  4781. name: "heroGetAll",
  4782. args: {},
  4783. ident: "heroGetAll"
  4784. }]
  4785. }
  4786.  
  4787. buffIds = [
  4788. {id: 0, cost: 0, isBuy: false}, // plug // заглушка
  4789. {id: 1, cost: 1, isBuy: true}, // 3% attack // 3% атака
  4790. {id: 2, cost: 6, isBuy: true}, // 2% attack // 2% атака
  4791. {id: 3, cost: 16, isBuy: true}, // 4% attack // 4% атака
  4792. {id: 4, cost: 40, isBuy: true}, // 8% attack // 8% атака
  4793. {id: 5, cost: 1, isBuy: true}, // 10% armor // 10% броня
  4794. {id: 6, cost: 6, isBuy: true}, // 5% armor // 5% броня
  4795. {id: 7, cost: 16, isBuy: true}, // 10% armor // 10% броня
  4796. {id: 8, cost: 40, isBuy: true}, // 20% armor // 20% броня
  4797. { id: 9, cost: 1, isBuy: true }, // 10% protection from magic // 10% защита от магии
  4798. { id: 10, cost: 6, isBuy: true }, // 5% protection from magic // 5% защита от магии
  4799. { id: 11, cost: 16, isBuy: true }, // 10% protection from magic // 10% защита от магии
  4800. { id: 12, cost: 40, isBuy: true }, // 20% protection from magic // 20% защита от магии
  4801. { id: 13, cost: 1, isBuy: false }, // 40% health hero // 40% здоровья герою
  4802. { id: 14, cost: 6, isBuy: false }, // 40% health hero // 40% здоровья герою
  4803. { id: 15, cost: 16, isBuy: false }, // 80% health hero // 80% здоровья герою
  4804. { id: 16, cost: 40, isBuy: false }, // 40% health to all heroes // 40% здоровья всем героям
  4805. { id: 17, cost: 1, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  4806. { id: 18, cost: 3, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  4807. { id: 19, cost: 8, isBuy: false }, // 80% energy to the hero // 80% энергии герою
  4808. { id: 20, cost: 20, isBuy: false }, // 40% energy to all heroes // 40% энергии всем героям
  4809. { id: 21, cost: 40, isBuy: false }, // Hero Resurrection // Воскрешение героя
  4810. ]
  4811.  
  4812. this.start = function () {
  4813. send(JSON.stringify(callsExecuteTower), startTower);
  4814. }
  4815.  
  4816. /**
  4817. * Getting data on the Tower
  4818. *
  4819. * Получаем данные по башне
  4820. */
  4821. function startTower(e) {
  4822. res = e.results;
  4823. towerGetInfo = res[0].result.response;
  4824. if (!towerGetInfo) {
  4825. endTower('noTower', res);
  4826. return;
  4827. }
  4828. teamGetAll = res[1].result.response;
  4829. teamGetFavor = res[2].result.response;
  4830. inventoryGet = res[3].result.response;
  4831. heroGetAll = Object.values(res[4].result.response);
  4832.  
  4833. scullCoin = inventoryGet.coin[7] ?? 0;
  4834.  
  4835. argsBattle.favor = teamGetFavor.tower;
  4836. argsBattle.heroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4837. pet = teamGetAll.tower.filter(id => id >= 6000).pop();
  4838. if (pet) {
  4839. argsBattle.pet = pet;
  4840. }
  4841.  
  4842. checkFloor(towerGetInfo);
  4843. }
  4844.  
  4845. function fixHeroesTeam(argsBattle) {
  4846. let fixHeroes = argsBattle.heroes.filter(e => !heroesStates[e]?.isDead);
  4847. if (fixHeroes.length < 5) {
  4848. heroGetAll = heroGetAll.filter(e => !heroesStates[e.id]?.isDead);
  4849. fixHeroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4850. Object.keys(argsBattle.favor).forEach(e => {
  4851. if (!fixHeroes.includes(+e)) {
  4852. delete argsBattle.favor[e];
  4853. }
  4854. })
  4855. }
  4856. argsBattle.heroes = fixHeroes;
  4857. return argsBattle;
  4858. }
  4859.  
  4860. /**
  4861. * Check the floor
  4862. *
  4863. * Проверяем этаж
  4864. */
  4865. function checkFloor(towerInfo) {
  4866. lastTowerInfo = towerInfo;
  4867. maySkipFloor = +towerInfo.maySkipFloor;
  4868. floorNumber = +towerInfo.floorNumber;
  4869. heroesStates = towerInfo.states.heroes;
  4870. floorInfo = towerInfo.floor;
  4871.  
  4872. /**
  4873. * Is there at least one chest open on the floor
  4874. * Открыт ли на этаже хоть один сундук
  4875. */
  4876. isOpenChest = false;
  4877. if (towerInfo.floorType == "chest") {
  4878. isOpenChest = towerInfo.floor.chests.reduce((n, e) => n + e.opened, 0);
  4879. }
  4880.  
  4881. setProgress(`${I18N('TOWER')}: ${I18N('FLOOR')} ${floorNumber}`);
  4882. if (floorNumber > 49) {
  4883. if (isOpenChest) {
  4884. endTower('alreadyOpenChest 50 floor', floorNumber);
  4885. return;
  4886. }
  4887. }
  4888. /**
  4889. * If the chest is open and you can skip floors, then move on
  4890. * Если сундук открыт и можно скипать этажи, то переходим дальше
  4891. */
  4892. if (towerInfo.mayFullSkip && +towerInfo.teamLevel == 130) {
  4893. if (isOpenChest) {
  4894. nextOpenChest(floorNumber);
  4895. } else {
  4896. nextChestOpen(floorNumber);
  4897. }
  4898. return;
  4899. }
  4900.  
  4901. // console.log(towerInfo, scullCoin);
  4902. switch (towerInfo.floorType) {
  4903. case "battle":
  4904. if (floorNumber <= maySkipFloor) {
  4905. skipFloor();
  4906. return;
  4907. }
  4908. if (floorInfo.state == 2) {
  4909. nextFloor();
  4910. return;
  4911. }
  4912. startBattle().then(endBattle);
  4913. return;
  4914. case "buff":
  4915. checkBuff(towerInfo);
  4916. return;
  4917. case "chest":
  4918. openChest(floorNumber);
  4919. return;
  4920. default:
  4921. console.log('!', towerInfo.floorType, towerInfo);
  4922. break;
  4923. }
  4924. }
  4925.  
  4926. /**
  4927. * Let's start the fight
  4928. *
  4929. * Начинаем бой
  4930. */
  4931. function startBattle() {
  4932. return new Promise(function (resolve, reject) {
  4933. towerStartBattle = {
  4934. calls: [{
  4935. name: "towerStartBattle",
  4936. args: fixHeroesTeam(argsBattle),
  4937. ident: "body"
  4938. }]
  4939. }
  4940. send(JSON.stringify(towerStartBattle), resultBattle, resolve);
  4941. });
  4942. }
  4943. /**
  4944. * Returns the result of the battle in a promise
  4945. *
  4946. * Возращает резульат боя в промис
  4947. */
  4948. function resultBattle(resultBattles, resolve) {
  4949. battleData = resultBattles.results[0].result.response;
  4950. battleType = "get_tower";
  4951. BattleCalc(battleData, battleType, function (result) {
  4952. resolve(result);
  4953. });
  4954. }
  4955. /**
  4956. * Finishing the fight
  4957. *
  4958. * Заканчиваем бой
  4959. */
  4960. function endBattle(battleInfo) {
  4961. if (battleInfo.result.stars >= 3) {
  4962. endBattleCall = {
  4963. calls: [{
  4964. name: "towerEndBattle",
  4965. args: {
  4966. result: battleInfo.result,
  4967. progress: battleInfo.progress,
  4968. },
  4969. ident: "body"
  4970. }]
  4971. }
  4972. send(JSON.stringify(endBattleCall), resultEndBattle);
  4973. } else {
  4974. endTower('towerEndBattle win: false\n', battleInfo);
  4975. }
  4976. }
  4977.  
  4978. /**
  4979. * Getting and processing battle results
  4980. *
  4981. * Получаем и обрабатываем результаты боя
  4982. */
  4983. function resultEndBattle(e) {
  4984. battleResult = e.results[0].result.response;
  4985. if ('error' in battleResult) {
  4986. endTower('errorBattleResult', battleResult);
  4987. return;
  4988. }
  4989. if ('reward' in battleResult) {
  4990. scullCoin += battleResult.reward?.coin[7] ?? 0;
  4991. }
  4992. nextFloor();
  4993. }
  4994.  
  4995. function nextFloor() {
  4996. nextFloorCall = {
  4997. calls: [{
  4998. name: "towerNextFloor",
  4999. args: {},
  5000. ident: "body"
  5001. }]
  5002. }
  5003. send(JSON.stringify(nextFloorCall), checkDataFloor);
  5004. }
  5005.  
  5006. function openChest(floorNumber) {
  5007. floorNumber = floorNumber || 0;
  5008. openChestCall = {
  5009. calls: [{
  5010. name: "towerOpenChest",
  5011. args: {
  5012. num: 2
  5013. },
  5014. ident: "body"
  5015. }]
  5016. }
  5017. send(JSON.stringify(openChestCall), floorNumber < 50 ? nextFloor : lastChest);
  5018. }
  5019.  
  5020. function lastChest() {
  5021. endTower('openChest 50 floor', floorNumber);
  5022. }
  5023.  
  5024. function skipFloor() {
  5025. skipFloorCall = {
  5026. calls: [{
  5027. name: "towerSkipFloor",
  5028. args: {},
  5029. ident: "body"
  5030. }]
  5031. }
  5032. send(JSON.stringify(skipFloorCall), checkDataFloor);
  5033. }
  5034.  
  5035. function checkBuff(towerInfo) {
  5036. buffArr = towerInfo.floor;
  5037. promises = [];
  5038. for (let buff of buffArr) {
  5039. buffInfo = buffIds[buff.id];
  5040. if (buffInfo.isBuy && buffInfo.cost <= scullCoin) {
  5041. scullCoin -= buffInfo.cost;
  5042. promises.push(buyBuff(buff.id));
  5043. }
  5044. }
  5045. Promise.all(promises).then(nextFloor);
  5046. }
  5047.  
  5048. function buyBuff(buffId) {
  5049. return new Promise(function (resolve, reject) {
  5050. buyBuffCall = {
  5051. calls: [{
  5052. name: "towerBuyBuff",
  5053. args: {
  5054. buffId
  5055. },
  5056. ident: "body"
  5057. }]
  5058. }
  5059. send(JSON.stringify(buyBuffCall), resolve);
  5060. });
  5061. }
  5062.  
  5063. function checkDataFloor(result) {
  5064. towerInfo = result.results[0].result.response;
  5065. if ('reward' in towerInfo && towerInfo.reward?.coin) {
  5066. scullCoin += towerInfo.reward?.coin[7] ?? 0;
  5067. }
  5068. if ('tower' in towerInfo) {
  5069. towerInfo = towerInfo.tower;
  5070. }
  5071. if ('skullReward' in towerInfo) {
  5072. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  5073. }
  5074. checkFloor(towerInfo);
  5075. }
  5076. /**
  5077. * Getting tower rewards
  5078. *
  5079. * Получаем награды башни
  5080. */
  5081. function farmTowerRewards(reason) {
  5082. let { pointRewards, points } = lastTowerInfo;
  5083. let pointsAll = Object.getOwnPropertyNames(pointRewards);
  5084. let farmPoints = pointsAll.filter(e => +e <= +points && !pointRewards[e]);
  5085. if (!farmPoints.length) {
  5086. return;
  5087. }
  5088. let farmTowerRewardsCall = {
  5089. calls: [{
  5090. name: "tower_farmPointRewards",
  5091. args: {
  5092. points: farmPoints
  5093. },
  5094. ident: "tower_farmPointRewards"
  5095. }]
  5096. }
  5097.  
  5098. if (scullCoin > 0 && reason == 'openChest 50 floor') {
  5099. farmTowerRewardsCall.calls.push({
  5100. name: "tower_farmSkullReward",
  5101. args: {},
  5102. ident: "tower_farmSkullReward"
  5103. });
  5104. }
  5105.  
  5106. send(JSON.stringify(farmTowerRewardsCall), () => { });
  5107. }
  5108.  
  5109. function fullSkipTower() {
  5110. /**
  5111. * Next chest
  5112. *
  5113. * Следующий сундук
  5114. */
  5115. function nextChest(n) {
  5116. return {
  5117. name: "towerNextChest",
  5118. args: {},
  5119. ident: "group_" + n + "_body"
  5120. }
  5121. }
  5122. /**
  5123. * Open chest
  5124. *
  5125. * Открыть сундук
  5126. */
  5127. function openChest(n) {
  5128. return {
  5129. name: "towerOpenChest",
  5130. args: {
  5131. "num": 2
  5132. },
  5133. ident: "group_" + n + "_body"
  5134. }
  5135. }
  5136.  
  5137. const fullSkipTowerCall = {
  5138. calls: []
  5139. }
  5140.  
  5141. let n = 0;
  5142. for (let i = 0; i < 15; i++) {
  5143. fullSkipTowerCall.calls.push(nextChest(++n));
  5144. fullSkipTowerCall.calls.push(openChest(++n));
  5145. }
  5146.  
  5147. send(JSON.stringify(fullSkipTowerCall), data => {
  5148. data.results[0] = data.results[28];
  5149. checkDataFloor(data);
  5150. });
  5151. }
  5152.  
  5153. function nextChestOpen(floorNumber) {
  5154. const calls = [{
  5155. name: "towerOpenChest",
  5156. args: {
  5157. num: 2
  5158. },
  5159. ident: "towerOpenChest"
  5160. }];
  5161.  
  5162. Send(JSON.stringify({ calls })).then(e => {
  5163. nextOpenChest(floorNumber);
  5164. });
  5165. }
  5166.  
  5167. function nextOpenChest(floorNumber) {
  5168. if (floorNumber > 49) {
  5169. endTower('openChest 50 floor', floorNumber);
  5170. return;
  5171. }
  5172. if (floorNumber == 1) {
  5173. fullSkipTower();
  5174. return;
  5175. }
  5176.  
  5177. let nextOpenChestCall = {
  5178. calls: [{
  5179. name: "towerNextChest",
  5180. args: {},
  5181. ident: "towerNextChest"
  5182. }, {
  5183. name: "towerOpenChest",
  5184. args: {
  5185. num: 2
  5186. },
  5187. ident: "towerOpenChest"
  5188. }]
  5189. }
  5190. send(JSON.stringify(nextOpenChestCall), checkDataFloor);
  5191. }
  5192.  
  5193. function endTower(reason, info) {
  5194. console.log(reason, info);
  5195. if (reason != 'noTower') {
  5196. farmTowerRewards(reason);
  5197. }
  5198. setProgress(`${I18N('TOWER')} ${I18N('COMPLETED')}!`, true);
  5199. resolve();
  5200. }
  5201. }
  5202.  
  5203. /**
  5204. * Passage of the arena of the titans
  5205. *
  5206. * Прохождение арены титанов
  5207. */
  5208. function testTitanArena() {
  5209. return new Promise((resolve, reject) => {
  5210. titAren = new executeTitanArena(resolve, reject);
  5211. titAren.start();
  5212. });
  5213. }
  5214.  
  5215. /**
  5216. * Passage of the arena of the titans
  5217. *
  5218. * Прохождение арены титанов
  5219. */
  5220. function executeTitanArena(resolve, reject) {
  5221. let titan_arena = [];
  5222. let finishListBattle = [];
  5223. /**
  5224. * ID of the current batch
  5225. *
  5226. * Идетификатор текущей пачки
  5227. */
  5228. let currentRival = 0;
  5229. /**
  5230. * Number of attempts to finish off the pack
  5231. *
  5232. * Количество попыток добития пачки
  5233. */
  5234. let attempts = 0;
  5235. /**
  5236. * Was there an attempt to finish off the current shooting range
  5237. *
  5238. * Была ли попытка добития текущего тира
  5239. */
  5240. let isCheckCurrentTier = false;
  5241. /**
  5242. * Current shooting range
  5243. *
  5244. * Текущий тир
  5245. */
  5246. let currTier = 0;
  5247. /**
  5248. * Number of battles on the current dash
  5249. *
  5250. * Количество битв на текущем тире
  5251. */
  5252. let countRivalsTier = 0;
  5253.  
  5254. let callsStart = {
  5255. calls: [{
  5256. name: "titanArenaGetStatus",
  5257. args: {},
  5258. ident: "titanArenaGetStatus"
  5259. }, {
  5260. name: "teamGetAll",
  5261. args: {},
  5262. ident: "teamGetAll"
  5263. }]
  5264. }
  5265.  
  5266. this.start = function () {
  5267. send(JSON.stringify(callsStart), startTitanArena);
  5268. }
  5269.  
  5270. function startTitanArena(data) {
  5271. let titanArena = data.results[0].result.response;
  5272. if (titanArena.status == 'disabled') {
  5273. endTitanArena('disabled', titanArena);
  5274. return;
  5275. }
  5276.  
  5277. let teamGetAll = data.results[1].result.response;
  5278. titan_arena = teamGetAll.titan_arena;
  5279.  
  5280. checkTier(titanArena)
  5281. }
  5282.  
  5283. function checkTier(titanArena) {
  5284. if (titanArena.status == "peace_time") {
  5285. endTitanArena('Peace_time', titanArena);
  5286. return;
  5287. }
  5288. currTier = titanArena.tier;
  5289. if (currTier) {
  5290. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier}`);
  5291. }
  5292.  
  5293. if (titanArena.status == "completed_tier") {
  5294. titanArenaCompleteTier();
  5295. return;
  5296. }
  5297. /**
  5298. * Checking for the possibility of a raid
  5299. * Проверка на возможность рейда
  5300. */
  5301. if (titanArena.canRaid) {
  5302. titanArenaStartRaid();
  5303. return;
  5304. }
  5305. /**
  5306. * Check was an attempt to achieve the current shooting range
  5307. * Проверка была ли попытка добития текущего тира
  5308. */
  5309. if (!isCheckCurrentTier) {
  5310. checkRivals(titanArena.rivals);
  5311. return;
  5312. }
  5313.  
  5314. endTitanArena('Done or not canRaid', titanArena);
  5315. }
  5316. /**
  5317. * Submit dash information for verification
  5318. *
  5319. * Отправка информации о тире на проверку
  5320. */
  5321. function checkResultInfo(data) {
  5322. let titanArena = data.results[0].result.response;
  5323. checkTier(titanArena);
  5324. }
  5325. /**
  5326. * Finish the current tier
  5327. *
  5328. * Завершить текущий тир
  5329. */
  5330. function titanArenaCompleteTier() {
  5331. isCheckCurrentTier = false;
  5332. let calls = [{
  5333. name: "titanArenaCompleteTier",
  5334. args: {},
  5335. ident: "body"
  5336. }];
  5337. send(JSON.stringify({calls}), checkResultInfo);
  5338. }
  5339. /**
  5340. * Gathering points to be completed
  5341. *
  5342. * Собираем точки которые нужно добить
  5343. */
  5344. function checkRivals(rivals) {
  5345. finishListBattle = [];
  5346. for (let n in rivals) {
  5347. if (rivals[n].attackScore < 250) {
  5348. finishListBattle.push(n);
  5349. }
  5350. }
  5351. console.log('checkRivals', finishListBattle);
  5352. countRivalsTier = finishListBattle.length;
  5353. roundRivals();
  5354. }
  5355. /**
  5356. * Selecting the next point to finish off
  5357. *
  5358. * Выбор следующей точки для добития
  5359. */
  5360. function roundRivals() {
  5361. let countRivals = finishListBattle.length;
  5362. if (!countRivals) {
  5363. /**
  5364. * Whole range checked
  5365. *
  5366. * Весь тир проверен
  5367. */
  5368. isCheckCurrentTier = true;
  5369. titanArenaGetStatus();
  5370. return;
  5371. }
  5372. // setProgress('TitanArena: Уровень ' + currTier + ' Бои: ' + (countRivalsTier - countRivals + 1) + '/' + countRivalsTier);
  5373. currentRival = finishListBattle.pop();
  5374. attempts = +currentRival;
  5375. // console.log('roundRivals', currentRival);
  5376. titanArenaStartBattle(currentRival);
  5377. }
  5378. /**
  5379. * The start of a solo battle
  5380. *
  5381. * Начало одиночной битвы
  5382. */
  5383. function titanArenaStartBattle(rivalId) {
  5384. let calls = [{
  5385. name: "titanArenaStartBattle",
  5386. args: {
  5387. rivalId: rivalId,
  5388. titans: titan_arena
  5389. },
  5390. ident: "body"
  5391. }];
  5392. send(JSON.stringify({calls}), calcResult);
  5393. }
  5394. /**
  5395. * Calculation of the results of the battle
  5396. *
  5397. * Расчет результатов боя
  5398. */
  5399. function calcResult(data) {
  5400. let battlesInfo = data.results[0].result.response.battle;
  5401. /**
  5402. * If attempts are equal to the current battle number we make
  5403. * Если попытки равны номеру текущего боя делаем прерасчет
  5404. */
  5405. if (attempts == currentRival) {
  5406. preCalcBattle(battlesInfo);
  5407. return;
  5408. }
  5409. /**
  5410. * If there are still attempts, we calculate a new battle
  5411. * Если попытки еще есть делаем расчет нового боя
  5412. */
  5413. if (attempts > 0) {
  5414. attempts--;
  5415. calcBattleResult(battlesInfo)
  5416. .then(resultCalcBattle);
  5417. return;
  5418. }
  5419. /**
  5420. * Otherwise, go to the next opponent
  5421. * Иначе переходим к следующему сопернику
  5422. */
  5423. roundRivals();
  5424. }
  5425. /**
  5426. * Processing the results of the battle calculation
  5427. *
  5428. * Обработка результатов расчета битвы
  5429. */
  5430. function resultCalcBattle(resultBattle) {
  5431. // console.log('resultCalcBattle', currentRival, attempts, resultBattle.result.win);
  5432. /**
  5433. * If the current calculation of victory is not a chance or the attempt ended with the finish the battle
  5434. * Если текущий расчет победа или шансов нет или попытки кончились завершаем бой
  5435. */
  5436. if (resultBattle.result.win || !attempts) {
  5437. titanArenaEndBattle({
  5438. progress: resultBattle.progress,
  5439. result: resultBattle.result,
  5440. rivalId: resultBattle.battleData.typeId
  5441. });
  5442. return;
  5443. }
  5444. /**
  5445. * If not victory and there are attempts we start a new battle
  5446. * Если не победа и есть попытки начинаем новый бой
  5447. */
  5448. titanArenaStartBattle(resultBattle.battleData.typeId);
  5449. }
  5450. /**
  5451. * Returns the promise of calculating the results of the battle
  5452. *
  5453. * Возращает промис расчета результатов битвы
  5454. */
  5455. function getBattleInfo(battle, isRandSeed) {
  5456. return new Promise(function (resolve) {
  5457. if (isRandSeed) {
  5458. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  5459. }
  5460. // console.log(battle.seed);
  5461. BattleCalc(battle, "get_titanClanPvp", e => resolve(e));
  5462. });
  5463. }
  5464. /**
  5465. * Recalculate battles
  5466. *
  5467. * Прерасчтет битвы
  5468. */
  5469. function preCalcBattle(battle) {
  5470. let actions = [getBattleInfo(battle, false)];
  5471. const countTestBattle = getInput('countTestBattle');
  5472. for (let i = 0; i < countTestBattle; i++) {
  5473. actions.push(getBattleInfo(battle, true));
  5474. }
  5475. Promise.all(actions)
  5476. .then(resultPreCalcBattle);
  5477. }
  5478. /**
  5479. * Processing the results of the battle recalculation
  5480. *
  5481. * Обработка результатов прерасчета битвы
  5482. */
  5483. function resultPreCalcBattle(e) {
  5484. let wins = e.map(n => n.result.win);
  5485. let firstBattle = e.shift();
  5486. let countWin = wins.reduce((w, s) => w + s);
  5487. const countTestBattle = getInput('countTestBattle');
  5488. console.log('resultPreCalcBattle', `${countWin}/${countTestBattle}`)
  5489. if (countWin > 0) {
  5490. attempts = getInput('countAutoBattle');
  5491. } else {
  5492. attempts = 0;
  5493. }
  5494. resultCalcBattle(firstBattle);
  5495. }
  5496.  
  5497. /**
  5498. * Complete an arena battle
  5499. *
  5500. * Завершить битву на арене
  5501. */
  5502. function titanArenaEndBattle(args) {
  5503. let calls = [{
  5504. name: "titanArenaEndBattle",
  5505. args,
  5506. ident: "body"
  5507. }];
  5508. send(JSON.stringify({calls}), resultTitanArenaEndBattle);
  5509. }
  5510.  
  5511. function resultTitanArenaEndBattle(e) {
  5512. let attackScore = e.results[0].result.response.attackScore;
  5513. let numReval = countRivalsTier - finishListBattle.length;
  5514. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier} </br>${I18N('BATTLES')}: ${numReval}/${countRivalsTier} - ${attackScore}`);
  5515. /**
  5516. * TODO: Might need to improve the results.
  5517. * TODO: Возможно стоит сделать улучшение результатов
  5518. */
  5519. // console.log('resultTitanArenaEndBattle', e)
  5520. console.log('resultTitanArenaEndBattle', numReval + '/' + countRivalsTier, attempts)
  5521. roundRivals();
  5522. }
  5523. /**
  5524. * Arena State
  5525. *
  5526. * Состояние арены
  5527. */
  5528. function titanArenaGetStatus() {
  5529. let calls = [{
  5530. name: "titanArenaGetStatus",
  5531. args: {},
  5532. ident: "body"
  5533. }];
  5534. send(JSON.stringify({calls}), checkResultInfo);
  5535. }
  5536. /**
  5537. * Arena Raid Request
  5538. *
  5539. * Запрос рейда арены
  5540. */
  5541. function titanArenaStartRaid() {
  5542. let calls = [{
  5543. name: "titanArenaStartRaid",
  5544. args: {
  5545. titans: titan_arena
  5546. },
  5547. ident: "body"
  5548. }];
  5549. send(JSON.stringify({calls}), calcResults);
  5550. }
  5551.  
  5552. function calcResults(data) {
  5553. let battlesInfo = data.results[0].result.response;
  5554. let {attackers, rivals} = battlesInfo;
  5555.  
  5556. let promises = [];
  5557. for (let n in rivals) {
  5558. rival = rivals[n];
  5559. promises.push(calcBattleResult({
  5560. attackers: attackers,
  5561. defenders: [rival.team],
  5562. seed: rival.seed,
  5563. typeId: n,
  5564. }));
  5565. }
  5566.  
  5567. Promise.all(promises)
  5568. .then(results => {
  5569. const endResults = {};
  5570. for (let info of results) {
  5571. let id = info.battleData.typeId;
  5572. endResults[id] = {
  5573. progress: info.progress,
  5574. result: info.result,
  5575. }
  5576. }
  5577. titanArenaEndRaid(endResults);
  5578. });
  5579. }
  5580.  
  5581. function calcBattleResult(battleData) {
  5582. return new Promise(function (resolve, reject) {
  5583. BattleCalc(battleData, "get_titanClanPvp", resolve);
  5584. });
  5585. }
  5586.  
  5587. /**
  5588. * Sending Raid Results
  5589. *
  5590. * Отправка результатов рейда
  5591. */
  5592. function titanArenaEndRaid(results) {
  5593. titanArenaEndRaidCall = {
  5594. calls: [{
  5595. name: "titanArenaEndRaid",
  5596. args: {
  5597. results
  5598. },
  5599. ident: "body"
  5600. }]
  5601. }
  5602. send(JSON.stringify(titanArenaEndRaidCall), checkRaidResults);
  5603. }
  5604.  
  5605. function checkRaidResults(data) {
  5606. results = data.results[0].result.response.results;
  5607. isSucsesRaid = true;
  5608. for (let i in results) {
  5609. isSucsesRaid &&= (results[i].attackScore >= 250);
  5610. }
  5611.  
  5612. if (isSucsesRaid) {
  5613. titanArenaCompleteTier();
  5614. } else {
  5615. titanArenaGetStatus();
  5616. }
  5617. }
  5618.  
  5619. function titanArenaFarmDailyReward() {
  5620. titanArenaFarmDailyRewardCall = {
  5621. calls: [{
  5622. name: "titanArenaFarmDailyReward",
  5623. args: {},
  5624. ident: "body"
  5625. }]
  5626. }
  5627. send(JSON.stringify(titanArenaFarmDailyRewardCall), () => {console.log('Done farm daily reward')});
  5628. }
  5629.  
  5630. function endTitanArena(reason, info) {
  5631. if (!['Peace_time', 'disabled'].includes(reason)) {
  5632. titanArenaFarmDailyReward();
  5633. }
  5634. console.log(reason, info);
  5635. setProgress(`${I18N('TITAN_ARENA')} ${I18N('COMPLETED')}!`, true);
  5636. resolve();
  5637. }
  5638. }
  5639.  
  5640. function hackGame() {
  5641. self = this;
  5642. selfGame = null;
  5643. bindId = 1e9;
  5644. this.libGame = null;
  5645.  
  5646. /**
  5647. * List of correspondence of used classes to their names
  5648. *
  5649. * Список соответствия используемых классов их названиям
  5650. */
  5651. ObjectsList = [
  5652. {name:"BattlePresets", prop:"game.battle.controller.thread.BattlePresets"},
  5653. {name:"DataStorage", prop:"game.data.storage.DataStorage"},
  5654. {name:"BattleConfigStorage", prop:"game.data.storage.battle.BattleConfigStorage"},
  5655. {name:"BattleInstantPlay", prop:"game.battle.controller.instant.BattleInstantPlay"},
  5656. {name:"MultiBattleResult", prop:"game.battle.controller.MultiBattleResult"},
  5657.  
  5658. {name:"PlayerMissionData", prop:"game.model.user.mission.PlayerMissionData"},
  5659. {name:"PlayerMissionBattle", prop:"game.model.user.mission.PlayerMissionBattle"},
  5660. {name:"GameModel", prop:"game.model.GameModel"},
  5661. {name:"CommandManager", prop:"game.command.CommandManager"},
  5662. {name:"MissionCommandList", prop:"game.command.rpc.mission.MissionCommandList"},
  5663. {name:"RPCCommandBase", prop:"game.command.rpc.RPCCommandBase"},
  5664. {name:"PlayerTowerData", prop:"game.model.user.tower.PlayerTowerData"},
  5665. {name:"TowerCommandList", prop:"game.command.tower.TowerCommandList"},
  5666. {name:"PlayerHeroTeamResolver", prop:"game.model.user.hero.PlayerHeroTeamResolver"},
  5667. {name:"BattlePausePopup", prop:"game.view.popup.battle.BattlePausePopup"},
  5668. {name:"BattlePopup", prop:"game.view.popup.battle.BattlePopup"},
  5669. {name:"DisplayObjectContainer", prop:"starling.display.DisplayObjectContainer"},
  5670. {name:"GuiClipContainer", prop:"engine.core.clipgui.GuiClipContainer"},
  5671. {name:"BattlePausePopupClip", prop:"game.view.popup.battle.BattlePausePopupClip"},
  5672. {name:"ClipLabel", prop:"game.view.gui.components.ClipLabel"},
  5673. {name:"ClipLabelBase", prop:"game.view.gui.components.ClipLabelBase"},
  5674. {name:"Translate", prop:"com.progrestar.common.lang.Translate"},
  5675. {name:"ClipButtonLabeledCentered", prop:"game.view.gui.components.ClipButtonLabeledCentered"},
  5676. {name:"BattlePausePopupMediator", prop:"game.mediator.gui.popup.battle.BattlePausePopupMediator"},
  5677. {name:"SettingToggleButton", prop:"game.mechanics.settings.popup.view.SettingToggleButton"},
  5678. {name:"PlayerDungeonData", prop:"game.mechanics.dungeon.model.PlayerDungeonData"},
  5679. {name:"NextDayUpdatedManager", prop:"game.model.user.NextDayUpdatedManager"},
  5680. {name:"BattleController", prop:"game.battle.controller.BattleController"},
  5681. {name:"BattleSettingsModel", prop:"game.battle.controller.BattleSettingsModel"},
  5682. {name:"BooleanProperty", prop:"engine.core.utils.property.BooleanProperty"},
  5683. {name:"RuleStorage", prop:"game.data.storage.rule.RuleStorage"},
  5684. {name:"BattleConfig", prop:"battle.BattleConfig"},
  5685. {name:"BattleGuiMediator", prop:"game.battle.gui.BattleGuiMediator"},
  5686. {name:"BooleanPropertyWriteable", prop:"engine.core.utils.property.BooleanPropertyWriteable"},
  5687. { name: "BattleLogEncoder", prop: "battle.log.BattleLogEncoder" },
  5688. { name: "BattleLogReader", prop: "battle.log.BattleLogReader" },
  5689. { name: "PlayerSubscriptionInfoValueObject", prop: "game.model.user.subscription.PlayerSubscriptionInfoValueObject" },
  5690. ];
  5691.  
  5692. /**
  5693. * Contains the game classes needed to write and override game methods
  5694. *
  5695. * Содержит классы игры необходимые для написания и подмены методов игры
  5696. */
  5697. Game = {
  5698. /**
  5699. * Function 'e'
  5700. * Функция 'e'
  5701. */
  5702. bindFunc: function (a, b) {
  5703. if (null == b)
  5704. return null;
  5705. null == b.__id__ && (b.__id__ = bindId++);
  5706. var c;
  5707. null == a.hx__closures__ ? a.hx__closures__ = {} :
  5708. c = a.hx__closures__[b.__id__];
  5709. null == c && (c = b.bind(a), a.hx__closures__[b.__id__] = c);
  5710. return c
  5711. },
  5712. };
  5713.  
  5714. /**
  5715. * Connects to game objects via the object creation event
  5716. *
  5717. * Подключается к объектам игры через событие создания объекта
  5718. */
  5719. function connectGame() {
  5720. for (let obj of ObjectsList) {
  5721. /**
  5722. * https: //stackoverflow.com/questions/42611719/how-to-intercept-and-modify-a-specific-property-for-any-object
  5723. */
  5724. Object.defineProperty(Object.prototype, obj.prop, {
  5725. set: function (value) {
  5726. if (!selfGame) {
  5727. selfGame = this;
  5728. }
  5729. if (!Game[obj.name]) {
  5730. Game[obj.name] = value;
  5731. }
  5732. // console.log('set ' + obj.prop, this, value);
  5733. this[obj.prop + '_'] = value;
  5734. },
  5735. get: function () {
  5736. // console.log('get ' + obj.prop, this);
  5737. return this[obj.prop + '_'];
  5738. }
  5739. });
  5740. }
  5741. }
  5742.  
  5743. /**
  5744. * Game.BattlePresets
  5745. * @param {bool} a isReplay
  5746. * @param {bool} b autoToggleable
  5747. * @param {bool} c auto On Start
  5748. * @param {object} d config
  5749. * @param {bool} f showBothTeams
  5750. */
  5751. /**
  5752. * Returns the results of the battle to the callback function
  5753. * Возвращает в функцию callback результаты боя
  5754. * @param {*} battleData battle data данные боя
  5755. * @param {*} battleConfig combat configuration type options:
  5756. *
  5757. * тип конфигурации боя варианты:
  5758. *
  5759. * "get_invasion", "get_titanPvpManual", "get_titanPvp",
  5760. * "get_titanClanPvp","get_clanPvp","get_titan","get_boss",
  5761. * "get_tower","get_pve","get_pvpManual","get_pvp","get_core"
  5762. *
  5763. * You can specify the xYc function in the game.assets.storage.BattleAssetStorage class
  5764. *
  5765. * Можно уточнить в классе game.assets.storage.BattleAssetStorage функция xYc
  5766. * @param {*} callback функция в которую вернуться результаты боя
  5767. */
  5768. this.BattleCalc = function (battleData, battleConfig, callback) {
  5769. // battleConfig = battleConfig || getBattleType(battleData.type)
  5770. if (!Game.BattlePresets) throw Error('Use connectGame');
  5771. battlePresets = new Game.BattlePresets(!!battleData.progress, !1, !0, Game.DataStorage[getFn(Game.DataStorage, 24)][getF(Game.BattleConfigStorage, battleConfig)](), !1);
  5772. battleInstantPlay = new Game.BattleInstantPlay(battleData, battlePresets);
  5773. battleInstantPlay[getProtoFn(Game.BattleInstantPlay, 9)].add((battleInstant) => {
  5774. const battleResult = battleInstant[getF(Game.BattleInstantPlay, 'get_result')]();
  5775. const battleData = battleInstant[getF(Game.BattleInstantPlay, 'get_rawBattleInfo')]();
  5776. const battleLog = Game.BattleLogEncoder.read(new Game.BattleLogReader(battleResult[getProtoFn(Game.MultiBattleResult, 2)][0]));
  5777. const timeLimit = battlePresets[getF(Game.BattlePresets, 'get_timeLimit')]();
  5778. const battleTime = Math.max(...battleLog.map((e) => (e.time < timeLimit && e.time !== 168.8 ? e.time : 0)));
  5779. callback({
  5780. battleTime,
  5781. battleData,
  5782. progress: battleResult[getF(Game.MultiBattleResult, 'get_progress')](),
  5783. result: battleResult[getF(Game.MultiBattleResult, 'get_result')]()
  5784. })
  5785. });
  5786. battleInstantPlay.start();
  5787. }
  5788.  
  5789. /**
  5790. * Returns a function with the specified name from the class
  5791. *
  5792. * Возвращает из класса функцию с указанным именем
  5793. * @param {Object} classF Class // класс
  5794. * @param {String} nameF function name // имя функции
  5795. * @param {String} pos name and alias order // порядок имени и псевдонима
  5796. * @returns
  5797. */
  5798. function getF(classF, nameF, pos) {
  5799. pos = pos || false;
  5800. let prop = Object.entries(classF.prototype.__properties__)
  5801. if (!pos) {
  5802. return prop.filter((e) => e[1] == nameF).pop()[0];
  5803. } else {
  5804. return prop.filter((e) => e[0] == nameF).pop()[1];
  5805. }
  5806. }
  5807.  
  5808. /**
  5809. * Returns a function with the specified name from the class
  5810. *
  5811. * Возвращает из класса функцию с указанным именем
  5812. * @param {Object} classF Class // класс
  5813. * @param {String} nameF function name // имя функции
  5814. * @returns
  5815. */
  5816. function getFnP(classF, nameF) {
  5817. let prop = Object.entries(classF.__properties__)
  5818. return prop.filter((e) => e[1] == nameF).pop()[0];
  5819. }
  5820.  
  5821. /**
  5822. * Returns the function name with the specified ordinal from the class
  5823. *
  5824. * Возвращает имя функции с указаным порядковым номером из класса
  5825. * @param {Object} classF Class // класс
  5826. * @param {Number} nF Order number of function // порядковый номер функции
  5827. * @returns
  5828. */
  5829. function getFn(classF, nF) {
  5830. let prop = Object.keys(classF);
  5831. return prop[nF];
  5832. }
  5833.  
  5834. /**
  5835. * Returns the name of the function with the specified serial number from the prototype of the class
  5836. *
  5837. * Возвращает имя функции с указаным порядковым номером из прототипа класса
  5838. * @param {Object} classF Class // класс
  5839. * @param {Number} nF Order number of function // порядковый номер функции
  5840. * @returns
  5841. */
  5842. function getProtoFn(classF, nF) {
  5843. let prop = Object.keys(classF.prototype);
  5844. return prop[nF];
  5845. }
  5846. /**
  5847. * Description of replaced functions
  5848. *
  5849. * Описание подменяемых функций
  5850. */
  5851. replaceFunction = {
  5852. company: function() {
  5853. let PMD_12 = getProtoFn(Game.PlayerMissionData, 12);
  5854. let oldSkipMisson = Game.PlayerMissionData.prototype[PMD_12];
  5855. Game.PlayerMissionData.prototype[PMD_12] = function (a, b, c) {
  5856. if (!isChecked('passBattle')) {
  5857. oldSkipMisson.call(this, a, b, c);
  5858. return;
  5859. }
  5860.  
  5861. try {
  5862. this[getProtoFn(Game.PlayerMissionData, 9)] = new Game.PlayerMissionBattle(a, b, c);
  5863.  
  5864. var a = new Game.BattlePresets(!1, !1, !0, Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](), !1);
  5865. a = new Game.BattleInstantPlay(c, a);
  5866. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  5867. a.start()
  5868. } catch (error) {
  5869. console.error('company', error)
  5870. oldSkipMisson.call(this, a, b, c);
  5871. }
  5872. }
  5873.  
  5874. Game.PlayerMissionData.prototype.P$h = function (a) {
  5875. let GM_2 = getFn(Game.GameModel, 2);
  5876. let GM_P2 = getProtoFn(Game.GameModel, 2);
  5877. let CM_20 = getProtoFn(Game.CommandManager, 20);
  5878. let MCL_2 = getProtoFn(Game.MissionCommandList, 2);
  5879. let MBR_15 = getF(Game.MultiBattleResult, "get_result");
  5880. let RPCCB_15 = getProtoFn(Game.RPCCommandBase, 16);
  5881. let PMD_32 = getProtoFn(Game.PlayerMissionData, 32);
  5882. Game.GameModel[GM_2]()[GM_P2][CM_20][MCL_2](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PMD_32]))
  5883. }
  5884. },
  5885. tower: function() {
  5886. let PTD_67 = getProtoFn(Game.PlayerTowerData, 67);
  5887. let oldSkipTower = Game.PlayerTowerData.prototype[PTD_67];
  5888. Game.PlayerTowerData.prototype[PTD_67] = function (a) {
  5889. if (!isChecked('passBattle')) {
  5890. oldSkipTower.call(this, a);
  5891. return;
  5892. }
  5893. try {
  5894. var p = new Game.BattlePresets(!1, !1, !0, Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage,20)](), !1);
  5895. a = new Game.BattleInstantPlay(a, p);
  5896. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  5897. a.start()
  5898. } catch (error) {
  5899. console.error('tower', error)
  5900. oldSkipMisson.call(this, a, b, c);
  5901. }
  5902. }
  5903.  
  5904. Game.PlayerTowerData.prototype.P$h = function (a) {
  5905. const GM_2 = getFnP(Game.GameModel, "get_instance");
  5906. const GM_P2 = getProtoFn(Game.GameModel, 2);
  5907. const CM_29 = getProtoFn(Game.CommandManager, 29);
  5908. const TCL_5 = getProtoFn(Game.TowerCommandList, 5);
  5909. const MBR_15 = getF(Game.MultiBattleResult, "get_result");
  5910. const RPCCB_15 = getProtoFn(Game.RPCCommandBase, 17);
  5911. const PTD_78 = getProtoFn(Game.PlayerTowerData, 78);
  5912. Game.GameModel[GM_2]()[GM_P2][CM_29][TCL_5](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PTD_78]));
  5913. }
  5914. },
  5915. // skipSelectHero: function() {
  5916. // if (!HOST) throw Error('Use connectGame');
  5917. // Game.PlayerHeroTeamResolver.prototype[getProtoFn(Game.PlayerHeroTeamResolver, 3)] = () => false;
  5918. // },
  5919. passBattle: function() {
  5920. let BPP_4 = getProtoFn(Game.BattlePausePopup, 4);
  5921. let oldPassBattle = Game.BattlePausePopup.prototype[BPP_4];
  5922. Game.BattlePausePopup.prototype[BPP_4] = function (a) {
  5923. if (!isChecked('passBattle')) {
  5924. oldPassBattle.call(this, a);
  5925. return;
  5926. }
  5927. try {
  5928. Game.BattlePopup.prototype[getProtoFn(Game.BattlePausePopup, 4)].call(this, a);
  5929. this[getProtoFn(Game.BattlePausePopup, 3)]();
  5930. this[getProtoFn(Game.DisplayObjectContainer, 3)](this.clip[getProtoFn(Game.GuiClipContainer, 2)]());
  5931. this.clip[getProtoFn(Game.BattlePausePopupClip, 1)][getProtoFn(Game.ClipLabelBase, 9)](Game.Translate.translate("UI_POPUP_BATTLE_PAUSE"));
  5932.  
  5933. this.clip[getProtoFn(Game.BattlePausePopupClip, 2)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](Game.Translate.translate("UI_POPUP_BATTLE_RETREAT"), (q = this[getProtoFn(Game.BattlePausePopup, 1)], Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 17)])));
  5934. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  5935. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 14)](),
  5936. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 13)]() ?
  5937. (q = this[getProtoFn(Game.BattlePausePopup, 1)], Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)])) :
  5938. (q = this[getProtoFn(Game.BattlePausePopup, 1)], Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  5939. );
  5940.  
  5941. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 0)][getProtoFn(Game.ClipLabelBase, 24)]();
  5942. this.clip[getProtoFn(Game.BattlePausePopupClip, 3)][getProtoFn(Game.SettingToggleButton, 3)](this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 9)]());
  5943. this.clip[getProtoFn(Game.BattlePausePopupClip, 4)][getProtoFn(Game.SettingToggleButton, 3)](this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 10)]());
  5944. this.clip[getProtoFn(Game.BattlePausePopupClip, 6)][getProtoFn(Game.SettingToggleButton, 3)](this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 11)]());
  5945. } catch(error) {
  5946. console.error('passBattle', error)
  5947. oldPassBattle.call(this, a);
  5948. }
  5949. }
  5950.  
  5951. let retreatButtonLabel = getF(Game.BattlePausePopupMediator, "get_retreatButtonLabel");
  5952. let oldFunc = Game.BattlePausePopupMediator.prototype[retreatButtonLabel];
  5953. Game.BattlePausePopupMediator.prototype[retreatButtonLabel] = function () {
  5954. if (isChecked('passBattle')) {
  5955. return I18N('BTN_PASS');
  5956. } else {
  5957. return oldFunc.call(this);
  5958. }
  5959. }
  5960. },
  5961. endlessCards: function() {
  5962. let PDD_20 = getProtoFn(Game.PlayerDungeonData, 20);
  5963. let oldEndlessCards = Game.PlayerDungeonData.prototype[PDD_20];
  5964. Game.PlayerDungeonData.prototype[PDD_20] = function () {
  5965. if (countPredictionCard <= 0) {
  5966. return true;
  5967. } else {
  5968. return oldEndlessCards.call(this);
  5969. }
  5970. }
  5971. },
  5972. speedBattle: function () {
  5973. const get_timeScale = getF(Game.BattleController, "get_timeScale");
  5974. const oldSpeedBattle = Game.BattleController.prototype[get_timeScale];
  5975. Game.BattleController.prototype[get_timeScale] = function () {
  5976. const speedBattle = Number.parseFloat(getInput('speedBattle'));
  5977. if (!speedBattle) {
  5978. return oldSpeedBattle.call(this);
  5979. }
  5980. try {
  5981. const BC_12 = getProtoFn(Game.BattleController, 12);
  5982. const BSM_12 = getProtoFn(Game.BattleSettingsModel, 12);
  5983. const BP_get_value = getF(Game.BooleanProperty, "get_value");
  5984. if (this[BC_12][BSM_12][BP_get_value]()) {
  5985. return 0;
  5986. }
  5987. const BSM_2 = getProtoFn(Game.BattleSettingsModel, 2);
  5988. const BC_49 = getProtoFn(Game.BattleController, 49);
  5989. const BSM_1 = getProtoFn(Game.BattleSettingsModel, 1);
  5990. const BC_14 = getProtoFn(Game.BattleController, 14);
  5991. const BC_3 = getFn(Game.BattleController, 3);
  5992. if (this[BC_12][BSM_2][BP_get_value]()) {
  5993. var a = speedBattle * this[BC_49]();
  5994. } else {
  5995. a = this[BC_12][BSM_1][BP_get_value]();
  5996. const maxSpeed = Math.max(...this[BC_14]);
  5997. const multiple = a == this[BC_14].indexOf(maxSpeed) ? (maxSpeed >= 4 ? speedBattle : this[BC_14][a]) : this[BC_14][a];
  5998. a = multiple * Game.BattleController[BC_3][BP_get_value]() * this[BC_49]();
  5999. }
  6000. const BSM_24 = getProtoFn(Game.BattleSettingsModel, 24);
  6001. a > this[BC_12][BSM_24][BP_get_value]() && (a = this[BC_12][BSM_24][BP_get_value]());
  6002. const DS_23 = getFn(Game.DataStorage, 23);
  6003. const get_battleSpeedMultiplier = getF(Game.RuleStorage, "get_battleSpeedMultiplier", true);
  6004. var b = Game.DataStorage[DS_23][get_battleSpeedMultiplier]();
  6005. const R_1 = getFn(selfGame.Reflect, 1);
  6006. const BC_1 = getFn(Game.BattleController, 1);
  6007. const get_config = getF(Game.BattlePresets, "get_config");
  6008. null != b && (a = selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident) ? a * selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident) : a * selfGame.Reflect[R_1](b, "default"));
  6009. return a
  6010. } catch(error) {
  6011. console.error('passBatspeedBattletle', error)
  6012. return oldSpeedBattle.call(this);
  6013. }
  6014. }
  6015. },
  6016.  
  6017. /**
  6018. * Acceleration button without Valkyries favor
  6019. *
  6020. * Кнопка ускорения без Покровительства Валькирий
  6021. */
  6022. battleFastKey: function () {
  6023. const BGM_43 = getProtoFn(Game.BattleGuiMediator, 43);
  6024. const oldBattleFastKey = Game.BattleGuiMediator.prototype[BGM_43];
  6025. Game.BattleGuiMediator.prototype[BGM_43] = function () {
  6026. let flag = true;
  6027. //console.log(flag)
  6028. if (!flag) {
  6029. return oldBattleFastKey.call(this);
  6030. }
  6031. try {
  6032. const BGM_9 = getProtoFn(Game.BattleGuiMediator, 9);
  6033. const BGM_10 = getProtoFn(Game.BattleGuiMediator, 10);
  6034. const BPW_0 = getProtoFn(Game.BooleanPropertyWriteable, 0);
  6035. this[BGM_9][BPW_0](true);
  6036. this[BGM_10][BPW_0](true);
  6037. } catch (error) {
  6038. console.error(error);
  6039. return oldBattleFastKey.call(this);
  6040. }
  6041. }
  6042. },
  6043. fastSeason: function () {
  6044. const GameNavigator = selfGame["game.screen.navigator.GameNavigator"];
  6045. const oldFuncName = getProtoFn(GameNavigator, 16);
  6046. const newFuncName = getProtoFn(GameNavigator, 14);
  6047. const oldFastSeason = GameNavigator.prototype[oldFuncName];
  6048. const newFastSeason = GameNavigator.prototype[newFuncName];
  6049. GameNavigator.prototype[oldFuncName] = function (a, b) {
  6050. if (isChecked('fastSeason')) {
  6051. return newFastSeason.apply(this, [a]);
  6052. } else {
  6053. return oldFastSeason.apply(this, [a, b]);
  6054. }
  6055. }
  6056. },
  6057. ShowChestReward: function () {
  6058. const TitanArtifactChest = selfGame["game.mechanics.titan_arena.mediator.chest.TitanArtifactChestRewardPopupMediator"];
  6059. const getOpenAmountTitan = getF(TitanArtifactChest, "get_openAmount");
  6060. const oldGetOpenAmountTitan = TitanArtifactChest.prototype[getOpenAmountTitan];
  6061. TitanArtifactChest.prototype[getOpenAmountTitan] = function () {
  6062. if (correctShowOpenArtifact) {
  6063. correctShowOpenArtifact--;
  6064. return 100;
  6065. }
  6066. return oldGetOpenAmountTitan.call(this);
  6067. }
  6068.  
  6069. const ArtifactChest = selfGame["game.view.popup.artifactchest.rewardpopup.ArtifactChestRewardPopupMediator"];
  6070. const getOpenAmount = getF(ArtifactChest, "get_openAmount");
  6071. const oldGetOpenAmount = ArtifactChest.prototype[getOpenAmount];
  6072. ArtifactChest.prototype[getOpenAmount] = function () {
  6073. if (correctShowOpenArtifact) {
  6074. correctShowOpenArtifact--;
  6075. return 100;
  6076. }
  6077. return oldGetOpenAmount.call(this);
  6078. }
  6079.  
  6080. },
  6081. fixCompany: function () {
  6082. const GameBattleView = selfGame["game.mediator.gui.popup.battle.GameBattleView"];
  6083. const BattleThread = selfGame["game.battle.controller.thread.BattleThread"];
  6084. const getOnViewDisposed = getF(BattleThread, 'get_onViewDisposed');
  6085. const getThread = getF(GameBattleView, 'get_thread');
  6086. const oldFunc = GameBattleView.prototype[getThread];
  6087. GameBattleView.prototype[getThread] = function () {
  6088. return oldFunc.call(this) || {
  6089. [getOnViewDisposed]: async () => { }
  6090. }
  6091. }
  6092. }
  6093. }
  6094.  
  6095. /**
  6096. * Starts replacing recorded functions
  6097. *
  6098. * Запускает замену записанных функций
  6099. */
  6100. this.activateHacks = function () {
  6101. if (!selfGame) throw Error('Use connectGame');
  6102. for (let func in replaceFunction) {
  6103. replaceFunction[func]();
  6104. }
  6105. }
  6106.  
  6107. /**
  6108. * Returns the game object
  6109. *
  6110. * Возвращает объект игры
  6111. */
  6112. this.getSelfGame = function () {
  6113. return selfGame;
  6114. }
  6115.  
  6116. /**
  6117. * Updates game data
  6118. *
  6119. * Обновляет данные игры
  6120. */
  6121. this.refreshGame = function () {
  6122. (new Game.NextDayUpdatedManager)[getProtoFn(Game.NextDayUpdatedManager, 5)]();
  6123. try {
  6124. cheats.refreshInventory();
  6125. } catch (e) { }
  6126. }
  6127.  
  6128. /**
  6129. * Update inventory
  6130. *
  6131. * Обновляет инвентарь
  6132. */
  6133. this.refreshInventory = async function () {
  6134. const GM_INST = getFnP(Game.GameModel, "get_instance");
  6135. const GM_0 = getProtoFn(Game.GameModel, 0);
  6136. const P_24 = getProtoFn(selfGame["game.model.user.Player"], 24);
  6137. const Player = Game.GameModel[GM_INST]()[GM_0];
  6138. Player[P_24] = new selfGame["game.model.user.inventory.PlayerInventory"]
  6139. Player[P_24].init(await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"}]}').then(e => e.results[0].result.response))
  6140. }
  6141.  
  6142. /**
  6143. * Change the play screen on windowName
  6144. *
  6145. * Сменить экран игры на windowName
  6146. *
  6147. * Possible options:
  6148. *
  6149. * Возможные варианты:
  6150. *
  6151. * 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
  6152. */
  6153. this.goNavigtor = function (windowName) {
  6154. let mechanicStorage = selfGame["game.data.storage.mechanic.MechanicStorage"];
  6155. let window = mechanicStorage[windowName];
  6156. let event = new selfGame["game.mediator.gui.popup.PopupStashEventParams"];
  6157. let Game = selfGame['Game'];
  6158. let navigator = getF(Game, "get_navigator")
  6159. let navigate = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 18)
  6160. let instance = getFnP(Game, 'get_instance');
  6161. Game[instance]()[navigator]()[navigate](window, event);
  6162. }
  6163.  
  6164. /**
  6165. * Move to the sanctuary cheats.goSanctuary()
  6166. *
  6167. * Переместиться в святилище cheats.goSanctuary()
  6168. */
  6169. this.goSanctuary = () => {
  6170. this.goNavigtor("SANCTUARY");
  6171. }
  6172.  
  6173. /**
  6174. * Go to Guild War
  6175. *
  6176. * Перейти к Войне Гильдий
  6177. */
  6178. this.goClanWar = function() {
  6179. let instance = getFnP(Game.GameModel, 'get_instance')
  6180. let player = Game.GameModel[instance]().A;
  6181. let clanWarSelect = selfGame["game.mechanics.cross_clan_war.popup.selectMode.CrossClanWarSelectModeMediator"];
  6182. new clanWarSelect(player).open();
  6183. }
  6184.  
  6185. /**
  6186. * Go to BrawlShop
  6187. *
  6188. * Переместиться в BrawlShop
  6189. */
  6190. this.goBrawlShop = () => {
  6191. const instance = getFnP(Game.GameModel, 'get_instance')
  6192. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  6193. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  6194. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  6195. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  6196.  
  6197. const player = Game.GameModel[instance]().A;
  6198. const shop = player[P_36][PSD_0][IM_0][1038][PSDE_4];
  6199. const shopPopup = new selfGame["game.mechanics.brawl.mediator.BrawlShopPopupMediator"](player, shop)
  6200. shopPopup.open(new selfGame["game.mediator.gui.popup.PopupStashEventParams"])
  6201. }
  6202.  
  6203. /**
  6204. * Returns all stores from game data
  6205. *
  6206. * Возвращает все магазины из данных игры
  6207. */
  6208. this.getShops = () => {
  6209. const instance = getFnP(Game.GameModel, 'get_instance')
  6210. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  6211. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  6212. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  6213.  
  6214. const player = Game.GameModel[instance]().A;
  6215. return player[P_36][PSD_0][IM_0];
  6216. }
  6217.  
  6218. /**
  6219. * Returns the store from the game data by ID
  6220. *
  6221. * Возвращает магазин из данных игры по идетификатору
  6222. */
  6223. this.getShop = (id) => {
  6224. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  6225. const shops = this.getShops();
  6226. const shop = shops[id]?.[PSDE_4];
  6227. return shop;
  6228. }
  6229.  
  6230. /**
  6231. * Change island map
  6232. *
  6233. * Сменить карту острова
  6234. */
  6235. this.changeIslandMap = (mapId = 2) => {
  6236. const GameInst = getFnP(selfGame['Game'], 'get_instance');
  6237. const GM_0 = getProtoFn(Game.GameModel, 0);
  6238. const P_59 = getProtoFn(selfGame["game.model.user.Player"], 59);
  6239. const Player = Game.GameModel[GameInst]()[GM_0];
  6240. Player[P_59].$({ id: mapId, seasonAdventure: { id: mapId, startDate: 1701914400, endDate: 1709690400, closed: false } });
  6241.  
  6242. const GN_15 = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 15)
  6243. const navigator = getF(selfGame['Game'], "get_navigator");
  6244. selfGame['Game'][GameInst]()[navigator]()[GN_15](new selfGame["game.mediator.gui.popup.PopupStashEventParams"]);
  6245. }
  6246.  
  6247. /**
  6248. * Game library availability tracker
  6249. *
  6250. * Отслеживание доступности игровой библиотеки
  6251. */
  6252. function checkLibLoad() {
  6253. timeout = setTimeout(() => {
  6254. if (Game.GameModel) {
  6255. changeLib();
  6256. } else {
  6257. checkLibLoad();
  6258. }
  6259. }, 100)
  6260. }
  6261.  
  6262. /**
  6263. * Game library data spoofing
  6264. *
  6265. * Подмена данных игровой библиотеки
  6266. */
  6267. function changeLib() {
  6268. console.log('lib connect');
  6269. const originalStartFunc = Game.GameModel.prototype.start;
  6270. Game.GameModel.prototype.start = function (a, b, c) {
  6271. self.libGame = b.raw;
  6272. try {
  6273. const levels = b.raw.seasonAdventure.level;
  6274. for (const id in levels) {
  6275. const level = levels[id];
  6276. level.clientData.graphics.fogged = level.clientData.graphics.visible
  6277. }
  6278. } catch (e) {
  6279. console.warn(e);
  6280. }
  6281. originalStartFunc.call(this, a, b, c);
  6282. }
  6283. }
  6284.  
  6285. /**
  6286. * Returns the value of a language constant
  6287. *
  6288. * Возвращает значение языковой константы
  6289. * @param {*} langConst language constant // языковая константа
  6290. * @returns
  6291. */
  6292. this.translate = function (langConst) {
  6293. return Game.Translate.translate(langConst);
  6294. }
  6295.  
  6296. connectGame();
  6297. checkLibLoad();
  6298. }
  6299.  
  6300. /**
  6301. * Auto collection of gifts
  6302. *
  6303. * Автосбор подарков
  6304. */
  6305. function getAutoGifts() {
  6306. let valName = 'giftSendIds_' + userInfo.id;
  6307.  
  6308. if (!localStorage['clearGift' + userInfo.id]) {
  6309. localStorage[valName] = '';
  6310. localStorage['clearGift' + userInfo.id] = '+';
  6311. }
  6312.  
  6313. if (!localStorage[valName]) {
  6314. localStorage[valName] = '';
  6315. }
  6316.  
  6317. const now = Date.now();
  6318. const body = JSON.stringify({ now });
  6319. const signature = window['\x73\x69\x67\x6e'](now);
  6320. /**
  6321. * Submit a request to receive gift codes
  6322. *
  6323. * Отправка запроса для получения кодов подарков
  6324. */
  6325. fetch('https://zingery.ru/heroes/getGifts.php', {
  6326. method: 'POST',
  6327. headers: {
  6328. 'X-Request-Signature': signature,
  6329. 'X-Script-Name': GM_info.script.name,
  6330. 'X-Script-Version': GM_info.script.version,
  6331. 'X-Script-Author': GM_info.script.author,
  6332. },
  6333. body
  6334. }).then(
  6335. response => response.json()
  6336. ).then(
  6337. data => {
  6338. let freebieCheckCalls = {
  6339. calls: []
  6340. }
  6341. data.forEach((giftId, n) => {
  6342. if (localStorage[valName].includes(giftId)) return;
  6343. freebieCheckCalls.calls.push({
  6344. name: "registration",
  6345. args: {
  6346. user: { referrer: {} },
  6347. giftId
  6348. },
  6349. context: {
  6350. actionTs: Math.floor(performance.now()),
  6351. cookie: window?.NXAppInfo?.session_id || null
  6352. },
  6353. ident: giftId
  6354. });
  6355. });
  6356.  
  6357. if (!freebieCheckCalls.calls.length) {
  6358. return;
  6359. }
  6360.  
  6361. send(JSON.stringify(freebieCheckCalls), e => {
  6362. let countGetGifts = 0;
  6363. const gifts = [];
  6364. for (check of e.results) {
  6365. gifts.push(check.ident);
  6366. if (check.result.response != null) {
  6367. countGetGifts++;
  6368. }
  6369. }
  6370. const saveGifts = localStorage[valName].split(';');
  6371. localStorage[valName] = [...saveGifts, ...gifts].slice(-50).join(';');
  6372. console.log(`${I18N('GIFTS')}: ${countGetGifts}`);
  6373. });
  6374. }
  6375. )
  6376. }
  6377.  
  6378. /**
  6379. * To fill the kills in the Forge of Souls
  6380. *
  6381. * Набить килов в горниле душ
  6382. */
  6383. async function bossRatingEvent() {
  6384. const topGet = await Send(JSON.stringify({ calls: [{ name: "topGet", args: { type: "bossRatingTop", extraId: 0 }, ident: "body" }] }));
  6385. if (!topGet || !topGet.results[0].result.response[0]) {
  6386. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  6387. return;
  6388. }
  6389. const replayId = topGet.results[0].result.response[0].userData.replayId;
  6390. const result = await Send(JSON.stringify({
  6391. calls: [
  6392. { name: "battleGetReplay", args: { id: replayId }, ident: "battleGetReplay" },
  6393. { name: "heroGetAll", args: {}, ident: "heroGetAll" },
  6394. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  6395. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  6396. ]
  6397. }));
  6398. const bossEventInfo = result.results[3].result.response.find(e => e.offerType == "bossEvent");
  6399. if (!bossEventInfo) {
  6400. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  6401. return;
  6402. }
  6403. const usedHeroes = bossEventInfo.progress.usedHeroes;
  6404. const party = Object.values(result.results[0].result.response.replay.attackers);
  6405. const availableHeroes = Object.values(result.results[1].result.response).map(e => e.id);
  6406. const availablePets = Object.values(result.results[2].result.response).map(e => e.id);
  6407. const calls = [];
  6408. /**
  6409. * First pack
  6410. *
  6411. * Первая пачка
  6412. */
  6413. const args = {
  6414. heroes: [],
  6415. favor: {}
  6416. }
  6417. for (let hero of party) {
  6418. if (hero.id >= 6000 && availablePets.includes(hero.id)) {
  6419. args.pet = hero.id;
  6420. continue;
  6421. }
  6422. if (!availableHeroes.includes(hero.id) || usedHeroes.includes(hero.id)) {
  6423. continue;
  6424. }
  6425. args.heroes.push(hero.id);
  6426. if (hero.favorPetId) {
  6427. args.favor[hero.id] = hero.favorPetId;
  6428. }
  6429. }
  6430. if (args.heroes.length) {
  6431. calls.push({
  6432. name: "bossRatingEvent_startBattle",
  6433. args,
  6434. ident: "body_0"
  6435. });
  6436. }
  6437. /**
  6438. * Other packs
  6439. *
  6440. * Другие пачки
  6441. */
  6442. let heroes = [];
  6443. let count = 1;
  6444. while (heroId = availableHeroes.pop()) {
  6445. if (args.heroes.includes(heroId) || usedHeroes.includes(heroId)) {
  6446. continue;
  6447. }
  6448. heroes.push(heroId);
  6449. if (heroes.length == 5) {
  6450. calls.push({
  6451. name: "bossRatingEvent_startBattle",
  6452. args: {
  6453. heroes: [...heroes],
  6454. pet: availablePets[Math.floor(Math.random() * availablePets.length)]
  6455. },
  6456. ident: "body_" + count
  6457. });
  6458. heroes = [];
  6459. count++;
  6460. }
  6461. }
  6462.  
  6463. if (!calls.length) {
  6464. setProgress(`${I18N('NO_HEROES')}`, true);
  6465. return;
  6466. }
  6467.  
  6468. const resultBattles = await Send(JSON.stringify({ calls }));
  6469. console.log(resultBattles);
  6470. rewardBossRatingEvent();
  6471. }
  6472.  
  6473. /**
  6474. * Collecting Rewards from the Forge of Souls
  6475. *
  6476. * Сбор награды из Горнила Душ
  6477. */
  6478. function rewardBossRatingEvent() {
  6479. let rewardBossRatingCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  6480. send(rewardBossRatingCall, function (data) {
  6481. let bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  6482. if (!bossEventInfo) {
  6483. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  6484. return;
  6485. }
  6486.  
  6487. let farmedChests = bossEventInfo.progress.farmedChests;
  6488. let score = bossEventInfo.progress.score;
  6489. setProgress(`${I18N('DAMAGE_AMOUNT')}: ${score}`);
  6490. let revard = bossEventInfo.reward;
  6491.  
  6492. let getRewardCall = {
  6493. calls: []
  6494. }
  6495.  
  6496. let count = 0;
  6497. for (let i = 1; i < 10; i++) {
  6498. if (farmedChests.includes(i)) {
  6499. continue;
  6500. }
  6501. if (score < revard[i].score) {
  6502. break;
  6503. }
  6504. getRewardCall.calls.push({
  6505. name: "bossRatingEvent_getReward",
  6506. args: {
  6507. rewardId: i
  6508. },
  6509. ident: "body_" + i
  6510. });
  6511. count++;
  6512. }
  6513. if (!count) {
  6514. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  6515. return;
  6516. }
  6517.  
  6518. send(JSON.stringify(getRewardCall), e => {
  6519. console.log(e);
  6520. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  6521. });
  6522. });
  6523. }
  6524.  
  6525. /**
  6526. * Collect Easter eggs and event rewards
  6527. *
  6528. * Собрать пасхалки и награды событий
  6529. */
  6530. function offerFarmAllReward() {
  6531. const offerGetAllCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  6532. return Send(offerGetAllCall).then((data) => {
  6533. const offerGetAll = data.results[0].result.response.filter(e => e.type == "reward" && !e?.freeRewardObtained && e.reward);
  6534. if (!offerGetAll.length) {
  6535. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  6536. return;
  6537. }
  6538.  
  6539. const calls = [];
  6540. for (let reward of offerGetAll) {
  6541. calls.push({
  6542. name: "offerFarmReward",
  6543. args: {
  6544. offerId: reward.id
  6545. },
  6546. ident: "offerFarmReward_" + reward.id
  6547. });
  6548. }
  6549.  
  6550. return Send(JSON.stringify({ calls })).then(e => {
  6551. console.log(e);
  6552. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  6553. });
  6554. });
  6555. }
  6556.  
  6557. /**
  6558. * Assemble Outland
  6559. *
  6560. * Собрать запределье
  6561. */
  6562. function getOutland() {
  6563. return new Promise(function (resolve, reject) {
  6564. send('{"calls":[{"name":"bossGetAll","args":{},"ident":"bossGetAll"}]}', e => {
  6565. let bosses = e.results[0].result.response;
  6566.  
  6567. let bossRaidOpenChestCall = {
  6568. calls: []
  6569. };
  6570.  
  6571. for (let boss of bosses) {
  6572. if (boss.mayRaid) {
  6573. bossRaidOpenChestCall.calls.push({
  6574. name: "bossRaid",
  6575. args: {
  6576. bossId: boss.id
  6577. },
  6578. ident: "bossRaid_" + boss.id
  6579. });
  6580. bossRaidOpenChestCall.calls.push({
  6581. name: "bossOpenChest",
  6582. args: {
  6583. bossId: boss.id,
  6584. amount: 1,
  6585. starmoney: 0
  6586. },
  6587. ident: "bossOpenChest_" + boss.id
  6588. });
  6589. } else if (boss.chestId == 1) {
  6590. bossRaidOpenChestCall.calls.push({
  6591. name: "bossOpenChest",
  6592. args: {
  6593. bossId: boss.id,
  6594. amount: 1,
  6595. starmoney: 0
  6596. },
  6597. ident: "bossOpenChest_" + boss.id
  6598. });
  6599. }
  6600. }
  6601.  
  6602. if (!bossRaidOpenChestCall.calls.length) {
  6603. setProgress(`${I18N('OUTLAND')} ${I18N('NOTHING_TO_COLLECT')}`, true);
  6604. resolve();
  6605. return;
  6606. }
  6607.  
  6608. send(JSON.stringify(bossRaidOpenChestCall), e => {
  6609. setProgress(`${I18N('OUTLAND')} ${I18N('COLLECTED')}`, true);
  6610. resolve();
  6611. });
  6612. });
  6613. });
  6614. }
  6615.  
  6616. /**
  6617. * Collect all rewards
  6618. *
  6619. * Собрать все награды
  6620. */
  6621. function questAllFarm() {
  6622. return new Promise(function (resolve, reject) {
  6623. let questGetAllCall = {
  6624. calls: [{
  6625. name: "questGetAll",
  6626. args: {},
  6627. ident: "body"
  6628. }]
  6629. }
  6630. send(JSON.stringify(questGetAllCall), function (data) {
  6631. let questGetAll = data.results[0].result.response;
  6632. const questAllFarmCall = {
  6633. calls: []
  6634. }
  6635. let number = 0;
  6636. for (let quest of questGetAll) {
  6637. if (quest.id < 1e6 && quest.state == 2) {
  6638. questAllFarmCall.calls.push({
  6639. name: "questFarm",
  6640. args: {
  6641. questId: quest.id
  6642. },
  6643. ident: `group_${number}_body`
  6644. });
  6645. number++;
  6646. }
  6647. }
  6648.  
  6649. if (!questAllFarmCall.calls.length) {
  6650. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  6651. resolve();
  6652. return;
  6653. }
  6654.  
  6655. send(JSON.stringify(questAllFarmCall), function (res) {
  6656. console.log(res);
  6657. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  6658. resolve();
  6659. });
  6660. });
  6661. })
  6662. }
  6663.  
  6664. /**
  6665. * Mission auto repeat
  6666. *
  6667. * Автоповтор миссии
  6668. * isStopSendMission = false;
  6669. * isSendsMission = true;
  6670. **/
  6671. this.sendsMission = async function (param) {
  6672. if (isStopSendMission) {
  6673. isSendsMission = false;
  6674. console.log(I18N('STOPPED'));
  6675. setProgress('');
  6676. await popup.confirm(`${I18N('STOPPED')}<br>${I18N('REPETITIONS')}: ${param.count}`, [{
  6677. msg: 'Ok',
  6678. result: true
  6679. }, ])
  6680. return;
  6681. }
  6682. lastMissionBattleStart = Date.now();
  6683. let missionStartCall = {
  6684. "calls": [{
  6685. "name": "missionStart",
  6686. "args": lastMissionStart,
  6687. "ident": "body"
  6688. }]
  6689. }
  6690. /**
  6691. * Mission Request
  6692. *
  6693. * Запрос на выполнение мисии
  6694. */
  6695. SendRequest(JSON.stringify(missionStartCall), async e => {
  6696. if (e['error']) {
  6697. isSendsMission = false;
  6698. console.log(e['error']);
  6699. setProgress('');
  6700. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  6701. await popup.confirm(msg, [
  6702. {msg: 'Ok', result: true},
  6703. ])
  6704. return;
  6705. }
  6706. /**
  6707. * Mission data calculation
  6708. *
  6709. * Расчет данных мисии
  6710. */
  6711. BattleCalc(e.results[0].result.response, 'get_tower', async r => {
  6712. /** missionTimer */
  6713. let timer = getTimer(r.battleTime) + 5;
  6714. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  6715. if (period < timer) {
  6716. timer = timer - period;
  6717. await countdownTimer(timer, `${I18N('MISSIONS_PASSED')}: ${param.count}`);
  6718. }
  6719.  
  6720. let missionEndCall = {
  6721. "calls": [{
  6722. "name": "missionEnd",
  6723. "args": {
  6724. "id": param.id,
  6725. "result": r.result,
  6726. "progress": r.progress
  6727. },
  6728. "ident": "body"
  6729. }]
  6730. }
  6731. /**
  6732. * Mission Completion Request
  6733. *
  6734. * Запрос на завершение миссии
  6735. */
  6736. SendRequest(JSON.stringify(missionEndCall), async (e) => {
  6737. if (e['error']) {
  6738. isSendsMission = false;
  6739. console.log(e['error']);
  6740. setProgress('');
  6741. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  6742. await popup.confirm(msg, [
  6743. {msg: 'Ok', result: true},
  6744. ])
  6745. return;
  6746. }
  6747. r = e.results[0].result.response;
  6748. if (r['error']) {
  6749. isSendsMission = false;
  6750. console.log(r['error']);
  6751. setProgress('');
  6752. await popup.confirm(`<br>${I18N('REPETITIONS')}: ${param.count}` + ' 3 ' + r['error'], [
  6753. {msg: 'Ok', result: true},
  6754. ])
  6755. return;
  6756. }
  6757.  
  6758. param.count++;
  6759. setProgress(`${I18N('MISSIONS_PASSED')}: ${param.count} (${I18N('STOP')})`, false, () => {
  6760. isStopSendMission = true;
  6761. });
  6762. setTimeout(sendsMission, 1, param);
  6763. });
  6764. })
  6765. });
  6766. }
  6767.  
  6768. /**
  6769. * Opening of russian dolls
  6770. *
  6771. * Открытие матрешек
  6772. */
  6773. async function openRussianDolls(libId, amount) {
  6774. let sum = 0;
  6775. let sumResult = [];
  6776.  
  6777. while (amount) {
  6778. sum += amount;
  6779. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`);
  6780. const calls = [{
  6781. name: "consumableUseLootBox",
  6782. args: { libId, amount },
  6783. ident: "body"
  6784. }];
  6785. const result = await Send(JSON.stringify({ calls })).then(e => e.results[0].result.response);
  6786. let newCount = 0;
  6787. for (let n of result) {
  6788. if (n?.consumable && n.consumable[libId]) {
  6789. newCount += n.consumable[libId]
  6790. }
  6791. }
  6792. sumResult = [...sumResult, ...result];
  6793. amount = newCount;
  6794. }
  6795.  
  6796. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`, 5000);
  6797. return sumResult;
  6798. }
  6799.  
  6800. /**
  6801. * Collect all mail, except letters with energy and charges of the portal
  6802. *
  6803. * Собрать всю почту, кроме писем с энергией и зарядами портала
  6804. */
  6805. function mailGetAll() {
  6806. const getMailInfo = '{"calls":[{"name":"mailGetAll","args":{},"ident":"body"}]}';
  6807.  
  6808. return Send(getMailInfo).then(dataMail => {
  6809. const letters = dataMail.results[0].result.response.letters;
  6810. const letterIds = lettersFilter(letters);
  6811. if (!letterIds.length) {
  6812. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  6813. return;
  6814. }
  6815.  
  6816. const calls = [
  6817. { name: "mailFarm", args: { letterIds }, ident: "body" }
  6818. ];
  6819.  
  6820. return Send(JSON.stringify({ calls })).then(res => {
  6821. const lettersIds = res.results[0].result.response;
  6822. if (lettersIds) {
  6823. const countLetters = Object.keys(lettersIds).length;
  6824. setProgress(`${I18N('RECEIVED')} ${countLetters} ${I18N('LETTERS')}`, true);
  6825. }
  6826. });
  6827. });
  6828. }
  6829.  
  6830. /**
  6831. * Filters received emails
  6832. *
  6833. * Фильтрует получаемые письма
  6834. */
  6835. function lettersFilter(letters) {
  6836. const lettersIds = [];
  6837. for (let l in letters) {
  6838. letter = letters[l];
  6839. const reward = letter.reward;
  6840. if (!reward) {
  6841. continue;
  6842. }
  6843. /**
  6844. * Mail Collection Exceptions
  6845. *
  6846. * Исключения на сбор писем
  6847. */
  6848. const isFarmLetter = !(
  6849. /** Portals // сферы портала */
  6850. (reward?.refillable ? reward.refillable[45] : false) ||
  6851. /** Energy // энергия */
  6852. (reward?.stamina ? reward.stamina : false) ||
  6853. /** accelerating energy gain // ускорение набора энергии */
  6854. (reward?.buff ? true : false) ||
  6855. /** VIP Points // вип очки */
  6856. (reward?.vipPoints ? reward.vipPoints : false) ||
  6857. /** souls of heroes // душы героев */
  6858. (reward?.fragmentHero ? true : false) ||
  6859. /** heroes // герои */
  6860. (reward?.bundleHeroReward ? true : false)
  6861. );
  6862. if (isFarmLetter) {
  6863. lettersIds.push(~~letter.id);
  6864. continue;
  6865. }
  6866. /**
  6867. * Если до окончания годности письма менее 24 часов,
  6868. * то оно собирается не смотря на исключения
  6869. */
  6870. const availableUntil = +letter?.availableUntil;
  6871. if (availableUntil) {
  6872. const maxTimeLeft = 24 * 60 * 60 * 1000;
  6873. const timeLeft = (new Date(availableUntil * 1000) - new Date())
  6874. console.log('Time left:', timeLeft)
  6875. if (timeLeft < maxTimeLeft) {
  6876. lettersIds.push(~~letter.id);
  6877. continue;
  6878. }
  6879. }
  6880. }
  6881. return lettersIds;
  6882. }
  6883.  
  6884. /**
  6885. * Displaying information about the areas of the portal and attempts on the VG
  6886. *
  6887. * Отображение информации о сферах портала и попытках на ВГ
  6888. */
  6889. async function justInfo() {
  6890. return new Promise(async (resolve, reject) => {
  6891. const calls = [{
  6892. name: "userGetInfo",
  6893. args: {},
  6894. ident: "userGetInfo"
  6895. },
  6896. {
  6897. name: "clanWarGetInfo",
  6898. args: {},
  6899. ident: "clanWarGetInfo"
  6900. },
  6901. {
  6902. name: "titanArenaGetStatus",
  6903. args: {},
  6904. ident: "titanArenaGetStatus"
  6905. }];
  6906. const result = await Send(JSON.stringify({ calls }));
  6907. const infos = result.results;
  6908. const portalSphere = infos[0].result.response.refillable.find(n => n.id == 45);
  6909. const clanWarMyTries = infos[1].result.response?.myTries ?? 0;
  6910. const arePointsMax = infos[1].result.response?.arePointsMax;
  6911. const titansLevel = +(infos[2].result.response?.tier ?? 0);
  6912. const titansStatus = infos[2].result.response?.status; //peace_time || battle
  6913.  
  6914. const sanctuaryButton = buttons['goToSanctuary'].button;
  6915. const clanWarButton = buttons['goToClanWar'].button;
  6916. const titansArenaButton = buttons['testTitanArena'].button;
  6917.  
  6918. if (portalSphere.amount) {
  6919. sanctuaryButton.style.color = portalSphere.amount >= 3 ? 'red' : 'brown';
  6920. sanctuaryButton.title = `${I18N('SANCTUARY_TITLE')}\n${portalSphere.amount} ${I18N('PORTALS')}`;
  6921. } else {
  6922. sanctuaryButton.style.color = '';
  6923. sanctuaryButton.title = I18N('SANCTUARY_TITLE');
  6924. }
  6925. if (clanWarMyTries && !arePointsMax) {
  6926. clanWarButton.style.color = 'red';
  6927. clanWarButton.title = `${I18N('GUILD_WAR_TITLE')}\n${clanWarMyTries}${I18N('ATTEMPTS')}`;
  6928. } else {
  6929. clanWarButton.style.color = '';
  6930. clanWarButton.title = I18N('GUILD_WAR_TITLE');
  6931. }
  6932.  
  6933. if (titansLevel < 7 && titansStatus == 'battle') {
  6934. const partColor = Math.floor(125 * titansLevel / 7);
  6935. titansArenaButton.style.color = `rgb(255,${partColor},${partColor})`;
  6936. titansArenaButton.title = `${I18N('TITAN_ARENA_TITLE')}\n${titansLevel} ${I18N('LEVEL')}`;
  6937. } else {
  6938. titansArenaButton.style.color = '';
  6939. titansArenaButton.title = I18N('TITAN_ARENA_TITLE');
  6940. }
  6941.  
  6942. setProgress('<img src="https://zingery.ru/heroes/portal.png" style="height: 25px;position: relative;top: 5px;"> ' + `${portalSphere.amount} </br> ${I18N('GUILD_WAR')}: ${clanWarMyTries}`, true);
  6943. resolve();
  6944. });
  6945. }
  6946.  
  6947. async function getDailyBonus() {
  6948. const dailyBonusInfo = await Send(JSON.stringify({
  6949. calls: [{
  6950. name: "dailyBonusGetInfo",
  6951. args: {},
  6952. ident: "body"
  6953. }]
  6954. })).then(e => e.results[0].result.response);
  6955. const { availableToday, availableVip, currentDay } = dailyBonusInfo;
  6956.  
  6957. if (!availableToday) {
  6958. console.log('Уже собрано');
  6959. return;
  6960. }
  6961.  
  6962. const currentVipPoints = +userInfo.vipPoints;
  6963. const dailyBonusStat = lib.getData('dailyBonusStatic');
  6964. const vipInfo = lib.getData('level').vip;
  6965. let currentVipLevel = 0;
  6966. for (let i in vipInfo) {
  6967. vipLvl = vipInfo[i];
  6968. if (currentVipPoints >= vipLvl.vipPoints) {
  6969. currentVipLevel = vipLvl.level;
  6970. }
  6971. }
  6972. const vipLevelDouble = dailyBonusStat[`${currentDay}_0_0`].vipLevelDouble;
  6973.  
  6974. const calls = [{
  6975. name: "dailyBonusFarm",
  6976. args: {
  6977. vip: availableVip && currentVipLevel >= vipLevelDouble ? 1 : 0
  6978. },
  6979. ident: "body"
  6980. }];
  6981.  
  6982. const result = await Send(JSON.stringify({ calls }));
  6983. if (result.error) {
  6984. console.error(result.error);
  6985. return;
  6986. }
  6987.  
  6988. const reward = result.results[0].result.response;
  6989. const type = Object.keys(reward).pop();
  6990. const itemId = Object.keys(reward[type]).pop();
  6991. const count = reward[type][itemId];
  6992. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  6993.  
  6994. console.log(`Ежедневная награда: Получено ${count} ${itemName}`, reward);
  6995. }
  6996.  
  6997. async function farmStamina(lootBoxId = 148) {
  6998. const lootBox = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"}]}')
  6999. .then(e => e.results[0].result.response.consumable[148]);
  7000.  
  7001. /** Добавить другие ящики */
  7002. /**
  7003. * 144 - медная шкатулка
  7004. * 145 - бронзовая шкатулка
  7005. * 148 - платиновая шкатулка
  7006. */
  7007. if (!lootBox) {
  7008. setProgress(I18N('NO_BOXES'), true);
  7009. return;
  7010. }
  7011.  
  7012. let maxFarmEnergy = getSaveVal('maxFarmEnergy', 100);
  7013. const result = await popup.confirm(I18N('OPEN_LOOTBOX', { lootBox }), [
  7014. { result: false, isClose: true },
  7015. { msg: I18N('BTN_YES'), result: true },
  7016. { msg: I18N('STAMINA'), isInput: true, default: maxFarmEnergy },
  7017. ]);
  7018. if (!+result) {
  7019. return;
  7020. }
  7021.  
  7022. if ((typeof result) !== 'boolean' && Number.parseInt(result)) {
  7023. maxFarmEnergy = +result;
  7024. setSaveVal('maxFarmEnergy', maxFarmEnergy);
  7025. } else {
  7026. maxFarmEnergy = 0;
  7027. }
  7028.  
  7029. let collectEnergy = 0;
  7030. for (let count = lootBox; count > 0; count--) {
  7031. const result = await Send('{"calls":[{"name":"consumableUseLootBox","args":{"libId":148,"amount":1},"ident":"body"}]}')
  7032. .then(e => e.results[0].result.response[0]);
  7033. if ('stamina' in result) {
  7034. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox} ${I18N('STAMINA')} +${result.stamina}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  7035. console.log(`${ I18N('STAMINA') } + ${ result.stamina }`);
  7036. if (!maxFarmEnergy) {
  7037. return;
  7038. }
  7039. collectEnergy += +result.stamina;
  7040. if (collectEnergy >= maxFarmEnergy) {
  7041. console.log(`${I18N('STAMINA')} + ${ collectEnergy }`);
  7042. setProgress(`${I18N('STAMINA')} + ${ collectEnergy }`, false);
  7043. return;
  7044. }
  7045. } else {
  7046. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  7047. console.log(result);
  7048. }
  7049. }
  7050.  
  7051. setProgress(I18N('BOXES_OVER'), true);
  7052. }
  7053.  
  7054. async function fillActive() {
  7055. const data = await Send(JSON.stringify({
  7056. calls: [{
  7057. name: "questGetAll",
  7058. args: {},
  7059. ident: "questGetAll"
  7060. }, {
  7061. name: "inventoryGet",
  7062. args: {},
  7063. ident: "inventoryGet"
  7064. }, {
  7065. name: "clanGetInfo",
  7066. args: {},
  7067. ident: "clanGetInfo"
  7068. }
  7069. ]
  7070. })).then(e => e.results.map(n => n.result.response));
  7071.  
  7072. const quests = data[0];
  7073. const inv = data[1];
  7074. const stat = data[2].stat;
  7075. const maxActive = 2000 - stat.todayItemsActivity;
  7076. if (maxActive <= 0) {
  7077. setProgress(I18N('NO_MORE_ACTIVITY'), true);
  7078. return;
  7079. }
  7080. let countGetActive = 0;
  7081. const quest = quests.find(e => e.id > 10046 && e.id < 10051);
  7082. if (quest) {
  7083. countGetActive = 1750 - quest.progress;
  7084. }
  7085. if (countGetActive <= 0) {
  7086. countGetActive = maxActive;
  7087. }
  7088. console.log(countGetActive);
  7089.  
  7090. countGetActive = +(await popup.confirm(I18N('EXCHANGE_ITEMS', { maxActive }), [
  7091. { result: false, isClose: true },
  7092. { msg: I18N('GET_ACTIVITY'), isInput: true, default: countGetActive.toString() },
  7093. ]));
  7094.  
  7095. if (!countGetActive) {
  7096. return;
  7097. }
  7098.  
  7099. if (countGetActive > maxActive) {
  7100. countGetActive = maxActive;
  7101. }
  7102.  
  7103. const items = lib.getData('inventoryItem');
  7104.  
  7105. let itemsInfo = [];
  7106. for (let type of ['gear', 'scroll']) {
  7107. for (let i in inv[type]) {
  7108. const v = items[type][i]?.enchantValue || 0;
  7109. itemsInfo.push({
  7110. id: i,
  7111. count: inv[type][i],
  7112. v,
  7113. type
  7114. })
  7115. }
  7116. const invType = 'fragment' + type.toLowerCase().charAt(0).toUpperCase() + type.slice(1);
  7117. for (let i in inv[invType]) {
  7118. const v = items[type][i]?.fragmentEnchantValue || 0;
  7119. itemsInfo.push({
  7120. id: i,
  7121. count: inv[invType][i],
  7122. v,
  7123. type: invType
  7124. })
  7125. }
  7126. }
  7127. itemsInfo = itemsInfo.filter(e => e.v < 4 && e.count > 200);
  7128. itemsInfo = itemsInfo.sort((a, b) => b.count - a.count);
  7129. console.log(itemsInfo);
  7130. const activeItem = itemsInfo.shift();
  7131. console.log(activeItem);
  7132. const countItem = Math.ceil(countGetActive / activeItem.v);
  7133. if (countItem > activeItem.count) {
  7134. setProgress(I18N('NOT_ENOUGH_ITEMS'), true);
  7135. console.log(activeItem);
  7136. return;
  7137. }
  7138.  
  7139. await Send(JSON.stringify({
  7140. calls: [{
  7141. name: "clanItemsForActivity",
  7142. args: {
  7143. items: {
  7144. [activeItem.type]: {
  7145. [activeItem.id]: countItem
  7146. }
  7147. }
  7148. },
  7149. ident: "body"
  7150. }]
  7151. })).then(e => {
  7152. /** TODO: Вывести потраченые предметы */
  7153. console.log(e);
  7154. setProgress(`${I18N('ACTIVITY_RECEIVED')}: ` + e.results[0].result.response, true);
  7155. });
  7156. }
  7157.  
  7158. async function buyHeroFragments() {
  7159. const result = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"},{"name":"shopGetAll","args":{},"ident":"shopGetAll"}]}')
  7160. .then(e => e.results.map(n => n.result.response));
  7161. const inv = result[0];
  7162. const shops = Object.values(result[1]).filter(shop => [4, 5, 6, 8, 9, 10, 17].includes(shop.id));
  7163. const calls = [];
  7164.  
  7165. for (let shop of shops) {
  7166. const slots = Object.values(shop.slots);
  7167. for (const slot of slots) {
  7168. /* Уже куплено */
  7169. if (slot.bought) {
  7170. continue;
  7171. }
  7172. /* Не душа героя */
  7173. if (!('fragmentHero' in slot.reward)) {
  7174. continue;
  7175. }
  7176. const coin = Object.keys(slot.cost).pop();
  7177. const coinId = Object.keys(slot.cost[coin]).pop();
  7178. const stock = inv[coin][coinId] || 0;
  7179. /* Не хватает на покупку */
  7180. if (slot.cost[coin][coinId] > stock) {
  7181. continue;
  7182. }
  7183. inv[coin][coinId] -= slot.cost[coin][coinId];
  7184. calls.push({
  7185. name: "shopBuy",
  7186. args: {
  7187. shopId: shop.id,
  7188. slot: slot.id,
  7189. cost: slot.cost,
  7190. reward: slot.reward,
  7191. },
  7192. ident: `shopBuy_${shop.id}_${slot.id}`,
  7193. })
  7194. }
  7195. }
  7196.  
  7197. if (!calls.length) {
  7198. setProgress(I18N('NO_PURCHASABLE_HERO_SOULS'), true);
  7199. return;
  7200. }
  7201.  
  7202. const bought = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  7203. if (!bought) {
  7204. console.log('что-то пошло не так')
  7205. return;
  7206. }
  7207.  
  7208. let countHeroSouls = 0;
  7209. for (const buy of bought) {
  7210. countHeroSouls += +Object.values(Object.values(buy).pop()).pop();
  7211. }
  7212. console.log(countHeroSouls, bought, calls);
  7213. setProgress(I18N('PURCHASED_HERO_SOULS', { countHeroSouls }), true);
  7214. }
  7215.  
  7216. /** Открыть платные сундуки в Запределье за 90 */
  7217. async function bossOpenChestPay() {
  7218. const info = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"userGetInfo"},{"name":"bossGetAll","args":{},"ident":"bossGetAll"}]}')
  7219. .then(e => e.results.map(n => n.result.response));
  7220.  
  7221. const user = info[0];
  7222. const boses = info[1];
  7223.  
  7224. const currentStarMoney = user.starMoney;
  7225. if (currentStarMoney < 540) {
  7226. setProgress(I18N('NOT_ENOUGH_EMERALDS_540', { currentStarMoney }), true);
  7227. return;
  7228. }
  7229.  
  7230. const calls = [];
  7231.  
  7232. let n = 0;
  7233. const amount = 1;
  7234. for (let boss of boses) {
  7235. const bossId = boss.id;
  7236. if (boss.chestNum != 2) {
  7237. continue;
  7238. }
  7239. for (const starmoney of [90, 90, 0]) {
  7240. calls.push({
  7241. name: "bossOpenChest",
  7242. args: {
  7243. bossId,
  7244. amount,
  7245. starmoney
  7246. },
  7247. ident: "bossOpenChest_" + (++n)
  7248. });
  7249. }
  7250. }
  7251.  
  7252. if (!calls.length) {
  7253. setProgress(I18N('CHESTS_NOT_AVAILABLE'), true);
  7254. return;
  7255. }
  7256.  
  7257. const result = await Send(JSON.stringify({ calls }));
  7258. console.log(result);
  7259. if (result?.results) {
  7260. setProgress(`${I18N('OUTLAND_CHESTS_RECEIVED')}: ` + result.results.length, true);
  7261. } else {
  7262. setProgress(I18N('CHESTS_NOT_AVAILABLE'), true);
  7263. }
  7264. }
  7265.  
  7266. async function autoRaidAdventure() {
  7267. const calls = [
  7268. {
  7269. name: "userGetInfo",
  7270. args: {},
  7271. ident: "userGetInfo"
  7272. },
  7273. {
  7274. name: "adventure_raidGetInfo",
  7275. args: {},
  7276. ident: "adventure_raidGetInfo"
  7277. }
  7278. ];
  7279. const result = await Send(JSON.stringify({ calls }))
  7280. .then(e => e.results.map(n => n.result.response));
  7281.  
  7282. const portalSphere = result[0].refillable.find(n => n.id == 45);
  7283. const adventureRaid = Object.entries(result[1].raid).filter(e => e[1]).pop()
  7284. const adventureId = adventureRaid ? adventureRaid[0] : 0;
  7285.  
  7286. if (!portalSphere.amount || !adventureId) {
  7287. setProgress(I18N('RAID_NOT_AVAILABLE'), true);
  7288. return;
  7289. }
  7290.  
  7291. const countRaid = +(await popup.confirm(I18N('RAID_ADVENTURE', { adventureId }), [
  7292. { result: false, isClose: true },
  7293. { msg: I18N('RAID'), isInput: true, default: portalSphere.amount },
  7294. ]));
  7295.  
  7296. if (!countRaid) {
  7297. return;
  7298. }
  7299.  
  7300. if (countRaid > portalSphere.amount) {
  7301. countRaid = portalSphere.amount;
  7302. }
  7303.  
  7304. const resultRaid = await Send(JSON.stringify({
  7305. calls: [...Array(countRaid)].map((e, i) => ({
  7306. name: "adventure_raid",
  7307. args: {
  7308. adventureId
  7309. },
  7310. ident: `body_${i}`
  7311. }))
  7312. })).then(e => e.results.map(n => n.result.response));
  7313.  
  7314. if (!resultRaid.length) {
  7315. console.log(resultRaid);
  7316. setProgress(I18N('SOMETHING_WENT_WRONG'), true);
  7317. return;
  7318. }
  7319.  
  7320. console.log(resultRaid, adventureId, portalSphere.amount);
  7321. setProgress(I18N('ADVENTURE_COMPLETED', { adventureId, times: resultRaid.length }), true);
  7322. }
  7323.  
  7324. /** Вывести всю клановую статистику в консоль браузера */
  7325. async function clanStatistic() {
  7326. const copy = function (text) {
  7327. const copyTextarea = document.createElement("textarea");
  7328. copyTextarea.style.opacity = "0";
  7329. copyTextarea.textContent = text;
  7330. document.body.appendChild(copyTextarea);
  7331. copyTextarea.select();
  7332. document.execCommand("copy");
  7333. document.body.removeChild(copyTextarea);
  7334. delete copyTextarea;
  7335. }
  7336. const calls = [
  7337. { name: "clanGetInfo", args: {}, ident: "clanGetInfo" },
  7338. { name: "clanGetWeeklyStat", args: {}, ident: "clanGetWeeklyStat" },
  7339. { name: "clanGetLog", args: {}, ident: "clanGetLog" },
  7340. ];
  7341.  
  7342. const result = await Send(JSON.stringify({ calls }));
  7343.  
  7344. const dataClanInfo = result.results[0].result.response;
  7345. const dataClanStat = result.results[1].result.response;
  7346. const dataClanLog = result.results[2].result.response;
  7347.  
  7348. const membersStat = {};
  7349. for (let i = 0; i < dataClanStat.stat.length; i++) {
  7350. membersStat[dataClanStat.stat[i].id] = dataClanStat.stat[i];
  7351. }
  7352.  
  7353. const joinStat = {};
  7354. historyLog = dataClanLog.history;
  7355. for (let j in historyLog) {
  7356. his = historyLog[j];
  7357. if (his.event == 'join') {
  7358. joinStat[his.userId] = his.ctime;
  7359. }
  7360. }
  7361.  
  7362. const infoArr = [];
  7363. const members = dataClanInfo.clan.members;
  7364. for (let n in members) {
  7365. var member = [
  7366. n,
  7367. members[n].name,
  7368. members[n].level,
  7369. dataClanInfo.clan.warriors.includes(+n) ? 1 : 0,
  7370. (new Date(members[n].lastLoginTime * 1000)).toLocaleString().replace(',', ''),
  7371. joinStat[n] ? (new Date(joinStat[n] * 1000)).toLocaleString().replace(',', '') : '',
  7372. membersStat[n].activity.reverse().join('\t'),
  7373. membersStat[n].adventureStat.reverse().join('\t'),
  7374. membersStat[n].clanGifts.reverse().join('\t'),
  7375. membersStat[n].clanWarStat.reverse().join('\t'),
  7376. membersStat[n].dungeonActivity.reverse().join('\t'),
  7377. ];
  7378. infoArr.push(member);
  7379. }
  7380. const info = infoArr.sort((a, b) => (b[2] - a[2])).map((e) => e.join('\t')).join('\n');
  7381. console.log(info);
  7382. copy(info);
  7383. setProgress(I18N('CLAN_STAT_COPY'), true);
  7384. }
  7385.  
  7386. async function buyInStoreForGold() {
  7387. const result = await Send('{"calls":[{"name":"shopGetAll","args":{},"ident":"body"},{"name":"userGetInfo","args":{},"ident":"userGetInfo"}]}').then(e => e.results.map(n => n.result.response));
  7388. const shops = result[0];
  7389. const user = result[1];
  7390. let gold = user.gold;
  7391. const calls = [];
  7392. if (shops[17]) {
  7393. const slots = shops[17].slots;
  7394. for (let i = 1; i <= 2; i++) {
  7395. if (!slots[i].bought) {
  7396. const costGold = slots[i].cost.gold;
  7397. if ((gold - costGold) < 0) {
  7398. continue;
  7399. }
  7400. gold -= costGold;
  7401. calls.push({
  7402. name: "shopBuy",
  7403. args: {
  7404. shopId: 17,
  7405. slot: i,
  7406. cost: slots[i].cost,
  7407. reward: slots[i].reward,
  7408. },
  7409. ident: 'body_' + i,
  7410. })
  7411. }
  7412. }
  7413. }
  7414. const slots = shops[1].slots;
  7415. for (let i = 4; i <= 6; i++) {
  7416. if (!slots[i].bought && slots[i]?.cost?.gold) {
  7417. const costGold = slots[i].cost.gold;
  7418. if ((gold - costGold) < 0) {
  7419. continue;
  7420. }
  7421. gold -= costGold;
  7422. calls.push({
  7423. name: "shopBuy",
  7424. args: {
  7425. shopId: 1,
  7426. slot: i,
  7427. cost: slots[i].cost,
  7428. reward: slots[i].reward,
  7429. },
  7430. ident: 'body_' + i,
  7431. })
  7432. }
  7433. }
  7434.  
  7435. if (!calls.length) {
  7436. setProgress(I18N('NOTHING_BUY'), true);
  7437. return;
  7438. }
  7439.  
  7440. const resultBuy = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  7441. console.log(resultBuy);
  7442. const countBuy = resultBuy.length;
  7443. setProgress(I18N('LOTS_BOUGHT', { countBuy }), true);
  7444. }
  7445.  
  7446. function rewardsAndMailFarm() {
  7447. return new Promise(function (resolve, reject) {
  7448. let questGetAllCall = {
  7449. calls: [{
  7450. name: "questGetAll",
  7451. args: {},
  7452. ident: "questGetAll"
  7453. }, {
  7454. name: "mailGetAll",
  7455. args: {},
  7456. ident: "mailGetAll"
  7457. }]
  7458. }
  7459. send(JSON.stringify(questGetAllCall), function (data) {
  7460. if (!data) return;
  7461. let questGetAll = data.results[0].result.response.filter(e => e.state == 2);
  7462. const questBattlePass = lib.getData('quest').battlePass;
  7463. const questChainBPass = lib.getData('battlePass').questChain;
  7464.  
  7465. const questAllFarmCall = {
  7466. calls: []
  7467. }
  7468. let number = 0;
  7469. for (let quest of questGetAll) {
  7470. if (quest.id > 1e6) {
  7471. const questInfo = questBattlePass[quest.id];
  7472. const chain = questChainBPass[questInfo.chain];
  7473. if (chain.requirement?.battlePassTicket) {
  7474. continue;
  7475. }
  7476. }
  7477. questAllFarmCall.calls.push({
  7478. name: "questFarm",
  7479. args: {
  7480. questId: quest.id
  7481. },
  7482. ident: `questFarm_${number}`
  7483. });
  7484. number++;
  7485. }
  7486.  
  7487. let letters = data?.results[1]?.result?.response?.letters;
  7488. letterIds = lettersFilter(letters);
  7489.  
  7490. if (letterIds.length) {
  7491. questAllFarmCall.calls.push({
  7492. name: "mailFarm",
  7493. args: { letterIds },
  7494. ident: "mailFarm"
  7495. })
  7496. }
  7497.  
  7498. if (!questAllFarmCall.calls.length) {
  7499. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  7500. resolve();
  7501. return;
  7502. }
  7503.  
  7504. send(JSON.stringify(questAllFarmCall), function (res) {
  7505. let reSend = false;
  7506. let countQuests = 0;
  7507. let countMail = 0;
  7508. for (let call of res.results) {
  7509. if (call.ident.includes('questFarm')) {
  7510. countQuests++;
  7511. } else {
  7512. countMail = Object.keys(call.result.response).length;
  7513. }
  7514.  
  7515. /** TODO: Переписать чтоб не вызывать функцию дважды */
  7516. const newQuests = call.result.newQuests;
  7517. if (newQuests) {
  7518. for (let quest of newQuests) {
  7519. if (quest.id < 1e6 && quest.state == 2) {
  7520. reSend = true;
  7521. }
  7522. }
  7523. }
  7524. }
  7525. setProgress(I18N('COLLECT_REWARDS_AND_MAIL', { countQuests, countMail }), true);
  7526. if (reSend) {
  7527. rewardsAndMailFarm()
  7528. }
  7529. resolve();
  7530. });
  7531. });
  7532. })
  7533. }
  7534.  
  7535. class epicBrawl {
  7536. timeout = null;
  7537. time = null;
  7538.  
  7539. constructor() {
  7540. if (epicBrawl.inst) {
  7541. return epicBrawl.inst;
  7542. }
  7543. epicBrawl.inst = this;
  7544. return this;
  7545. }
  7546.  
  7547. runTimeout(func, timeDiff) {
  7548. const worker = new Worker(URL.createObjectURL(new Blob([`
  7549. self.onmessage = function(e) {
  7550. const timeDiff = e.data;
  7551.  
  7552. if (timeDiff > 0) {
  7553. setTimeout(() => {
  7554. self.postMessage(1);
  7555. self.close();
  7556. }, timeDiff);
  7557. }
  7558. };
  7559. `])));
  7560. worker.postMessage(timeDiff);
  7561. worker.onmessage = () => {
  7562. func();
  7563. };
  7564. return true;
  7565. }
  7566.  
  7567. timeDiff(date1, date2) {
  7568. const date1Obj = new Date(date1);
  7569. const date2Obj = new Date(date2);
  7570.  
  7571. const timeDiff = Math.abs(date2Obj - date1Obj);
  7572.  
  7573. const totalSeconds = timeDiff / 1000;
  7574. const minutes = Math.floor(totalSeconds / 60);
  7575. const seconds = Math.floor(totalSeconds % 60);
  7576.  
  7577. const formattedMinutes = String(minutes).padStart(2, '0');
  7578. const formattedSeconds = String(seconds).padStart(2, '0');
  7579.  
  7580. return `${formattedMinutes}:${formattedSeconds}`;
  7581. }
  7582.  
  7583. check() {
  7584. console.log(new Date(this.time))
  7585. if (Date.now() > this.time) {
  7586. this.timeout = null;
  7587. this.start()
  7588. return;
  7589. }
  7590. this.timeout = this.runTimeout(() => this.check(), 6e4);
  7591. return this.timeDiff(this.time, Date.now())
  7592. }
  7593.  
  7594. async start() {
  7595. if (this.timeout) {
  7596. const time = this.timeDiff(this.time, Date.now());
  7597. console.log(new Date(this.time))
  7598. setProgress(I18N('TIMER_ALREADY', { time }), false, hideProgress);
  7599. return;
  7600. }
  7601. setProgress(I18N('EPIC_BRAWL'), false, hideProgress);
  7602. 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));
  7603. const refill = teamInfo[2].refillable.find(n => n.id == 52)
  7604. this.time = (refill.lastRefill + 3600) * 1000
  7605. const attempts = refill.amount;
  7606. if (!attempts) {
  7607. console.log(new Date(this.time));
  7608. const time = this.check();
  7609. setProgress(I18N('NO_ATTEMPTS_TIMER_START', { time }), false, hideProgress);
  7610. return;
  7611. }
  7612.  
  7613. if (!teamInfo[0].epic_brawl) {
  7614. setProgress(I18N('NO_HEROES_PACK'), false, hideProgress);
  7615. return;
  7616. }
  7617.  
  7618. const args = {
  7619. heroes: teamInfo[0].epic_brawl.filter(e => e < 1000),
  7620. pet: teamInfo[0].epic_brawl.filter(e => e > 6000).pop(),
  7621. favor: teamInfo[1].epic_brawl,
  7622. }
  7623.  
  7624. let wins = 0;
  7625. let coins = 0;
  7626. let streak = { progress: 0, nextStage: 0 };
  7627. for (let i = attempts; i > 0; i--) {
  7628. const info = await Send(JSON.stringify({
  7629. calls: [
  7630. { name: "epicBrawl_getEnemy", args: {}, ident: "epicBrawl_getEnemy" }, { name: "epicBrawl_startBattle", args, ident: "epicBrawl_startBattle" }
  7631. ]
  7632. })).then(e => e.results.map(n => n.result.response));
  7633.  
  7634. const { progress, result } = await Calc(info[1].battle);
  7635. 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));
  7636.  
  7637. const resultInfo = endResult[0].result;
  7638. streak = endResult[1];
  7639.  
  7640. wins += resultInfo.win;
  7641. coins += resultInfo.reward ? resultInfo.reward.coin[39] : 0;
  7642.  
  7643. console.log(endResult[0].result)
  7644. if (endResult[1].progress == endResult[1].nextStage) {
  7645. const farm = await Send('{"calls":[{"name":"epicBrawl_farmWinStreak","args":{},"ident":"body"}]}').then(e => e.results[0].result.response);
  7646. coins += farm.coin[39];
  7647. }
  7648.  
  7649. setProgress(I18N('EPIC_BRAWL_RESULT', {
  7650. i, wins, attempts, coins,
  7651. progress: streak.progress,
  7652. nextStage: streak.nextStage,
  7653. end: '',
  7654. }), false, hideProgress);
  7655. }
  7656.  
  7657. console.log(new Date(this.time));
  7658. const time = this.check();
  7659. setProgress(I18N('EPIC_BRAWL_RESULT', {
  7660. wins, attempts, coins,
  7661. i: '',
  7662. progress: streak.progress,
  7663. nextStage: streak.nextStage,
  7664. end: I18N('ATTEMPT_ENDED', { time }),
  7665. }), false, hideProgress);
  7666. }
  7667. }
  7668.  
  7669. function countdownTimer(seconds, message) {
  7670. message = message || I18N('TIMER');
  7671. const stopTimer = Date.now() + seconds * 1e3
  7672. return new Promise(resolve => {
  7673. const interval = setInterval(async () => {
  7674. const now = Date.now();
  7675. setProgress(`${message} ${((stopTimer - now) / 1000).toFixed(2)}`, false);
  7676. if (now > stopTimer) {
  7677. clearInterval(interval);
  7678. setProgress('', 1);
  7679. resolve();
  7680. }
  7681. }, 100);
  7682. });
  7683. }
  7684.  
  7685. /** Набить килов в горниле душк */
  7686. async function bossRatingEventSouls() {
  7687. const data = await Send({
  7688. calls: [
  7689. { name: "heroGetAll", args: {}, ident: "teamGetAll" },
  7690. { name: "offerGetAll", args: {}, ident: "offerGetAll" },
  7691. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  7692. ]
  7693. });
  7694. const bossEventInfo = data.results[1].result.response.find(e => e.offerType == "bossEvent");
  7695. if (!bossEventInfo) {
  7696. setProgress('Эвент завершен', true);
  7697. return;
  7698. }
  7699.  
  7700. if (bossEventInfo.progress.score > 250) {
  7701. setProgress('Уже убито больше 250 врагов');
  7702. rewardBossRatingEventSouls();
  7703. return;
  7704. }
  7705. const availablePets = Object.values(data.results[2].result.response).map(e => e.id);
  7706. const heroGetAllList = data.results[0].result.response;
  7707. const usedHeroes = bossEventInfo.progress.usedHeroes;
  7708. const heroList = [];
  7709.  
  7710. for (let heroId in heroGetAllList) {
  7711. let hero = heroGetAllList[heroId];
  7712. if (usedHeroes.includes(hero.id)) {
  7713. continue;
  7714. }
  7715. heroList.push(hero.id);
  7716. }
  7717.  
  7718. if (!heroList.length) {
  7719. setProgress('Нет героев', true);
  7720. return;
  7721. }
  7722.  
  7723. const pet = availablePets.includes(6005) ? 6005 : availablePets[Math.floor(Math.random() * availablePets.length)];
  7724. const petLib = lib.getData('pet');
  7725. let count = 1;
  7726.  
  7727. for (const heroId of heroList) {
  7728. const args = {
  7729. heroes: [heroId],
  7730. pet
  7731. }
  7732. /** Поиск питомца для героя */
  7733. for (const petId of availablePets) {
  7734. if (petLib[petId].favorHeroes.includes(heroId)) {
  7735. args.favor = {
  7736. [heroId]: petId
  7737. }
  7738. break;
  7739. }
  7740. }
  7741.  
  7742. const calls = [{
  7743. name: "bossRatingEvent_startBattle",
  7744. args,
  7745. ident: "body"
  7746. }, {
  7747. name: "offerGetAll",
  7748. args: {},
  7749. ident: "offerGetAll"
  7750. }];
  7751.  
  7752. const res = await Send({ calls });
  7753. count++;
  7754.  
  7755. if ('error' in res) {
  7756. console.error(res.error);
  7757. setProgress('Перезагрузите игру и попробуйте позже', true);
  7758. return;
  7759. }
  7760.  
  7761. const eventInfo = res.results[1].result.response.find(e => e.offerType == "bossEvent");
  7762. if (eventInfo.progress.score > 250) {
  7763. break;
  7764. }
  7765. setProgress('Количество убитых врагов: ' + eventInfo.progress.score + '<br>Использовано ' + count + ' героев');
  7766. }
  7767.  
  7768. rewardBossRatingEventSouls();
  7769. }
  7770. /** Сбор награды из Горнила Душ */
  7771. async function rewardBossRatingEventSouls() {
  7772. const data = await Send({
  7773. calls: [
  7774. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  7775. ]
  7776. });
  7777.  
  7778. const bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  7779. if (!bossEventInfo) {
  7780. setProgress('Эвент завершен', true);
  7781. return;
  7782. }
  7783.  
  7784. const farmedChests = bossEventInfo.progress.farmedChests;
  7785. const score = bossEventInfo.progress.score;
  7786. // setProgress('Количество убитых врагов: ' + score);
  7787. const revard = bossEventInfo.reward;
  7788. const calls = [];
  7789.  
  7790. let count = 0;
  7791. for (let i = 1; i < 10; i++) {
  7792. if (farmedChests.includes(i)) {
  7793. continue;
  7794. }
  7795. if (score < revard[i].score) {
  7796. break;
  7797. }
  7798. calls.push({
  7799. name: "bossRatingEvent_getReward",
  7800. args: {
  7801. rewardId: i
  7802. },
  7803. ident: "body_" + i
  7804. });
  7805. count++;
  7806. }
  7807. if (!count) {
  7808. setProgress('Нечего собирать', true);
  7809. return;
  7810. }
  7811.  
  7812. Send({ calls }).then(e => {
  7813. console.log(e);
  7814. setProgress('Собрано ' + e?.results?.length + ' наград', true);
  7815. })
  7816. }
  7817. /**
  7818. * Spin the Seer
  7819. *
  7820. * Покрутить провидца
  7821. */
  7822. async function rollAscension() {
  7823. const refillable = await Send({calls:[
  7824. {
  7825. name:"userGetInfo",
  7826. args:{},
  7827. ident:"userGetInfo"
  7828. }
  7829. ]}).then(e => e.results[0].result.response.refillable);
  7830. const i47 = refillable.find(i => i.id == 47);
  7831. if (i47?.amount) {
  7832. await Send({ calls: [{ name: "ascensionChest_open", args: { paid: false, amount: 1 }, ident: "body" }] });
  7833. setProgress(I18N('DONE'), true);
  7834. } else {
  7835. setProgress(I18N('NOT_ENOUGH_AP'), true);
  7836. }
  7837. }
  7838.  
  7839. /**
  7840. * Collect gifts for the New Year
  7841. *
  7842. * Собрать подарки на новый год
  7843. */
  7844. function getGiftNewYear() {
  7845. Send({ calls: [{ name: "newYearGiftGet", args: { type: 0 }, ident: "body" }] }).then(e => {
  7846. const gifts = e.results[0].result.response.gifts;
  7847. const calls = gifts.filter(e => e.opened == 0).map(e => ({
  7848. name: "newYearGiftOpen",
  7849. args: {
  7850. giftId: e.id
  7851. },
  7852. ident: `body_${e.id}`
  7853. }));
  7854. if (!calls.length) {
  7855. setProgress(I18N('NY_NO_GIFTS'), 5000);
  7856. return;
  7857. }
  7858. Send({ calls }).then(e => {
  7859. console.log(e.results)
  7860. const msg = I18N('NY_GIFTS_COLLECTED', { count: e.results.length });
  7861. console.log(msg);
  7862. setProgress(msg, 5000);
  7863. });
  7864. })
  7865. }
  7866.  
  7867. async function updateArtifacts() {
  7868. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  7869. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  7870. { result: false, isClose: true }
  7871. ]);
  7872. if (!count) {
  7873. return;
  7874. }
  7875. const quest = new questRun;
  7876. await quest.autoInit();
  7877. const heroes = Object.values(quest.questInfo['heroGetAll']);
  7878. const inventory = quest.questInfo['inventoryGet'];
  7879. const calls = [];
  7880. for (let i = count; i > 0; i--) {
  7881. const upArtifact = quest.getUpgradeArtifact();
  7882. if (!upArtifact.heroId) {
  7883. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  7884. { msg: I18N('YES'), result: true },
  7885. { result: false, isClose: true }
  7886. ])) {
  7887. break;
  7888. } else {
  7889. return;
  7890. }
  7891. }
  7892. const hero = heroes.find(e => e.id == upArtifact.heroId);
  7893. hero.artifacts[upArtifact.slotId].level++;
  7894. inventory[upArtifact.costСurrency][upArtifact.costId] -= upArtifact.costValue;
  7895. calls.push({
  7896. name: "heroArtifactLevelUp",
  7897. args: {
  7898. heroId: upArtifact.heroId,
  7899. slotId: upArtifact.slotId
  7900. },
  7901. ident: `heroArtifactLevelUp_${i}`
  7902. });
  7903. }
  7904.  
  7905. if (!calls.length) {
  7906. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  7907. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  7908. return;
  7909. }
  7910.  
  7911. await Send(JSON.stringify({ calls })).then(e => {
  7912. if ('error' in e) {
  7913. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  7914. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  7915. } else {
  7916. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  7917. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  7918. }
  7919. });
  7920. }
  7921.  
  7922. window.sign = a => {
  7923. const i = this['\x78\x79\x7a'];
  7924. 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'))
  7925. }
  7926.  
  7927. async function updateSkins() {
  7928. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  7929. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  7930. { result: false, isClose: true }
  7931. ]);
  7932. if (!count) {
  7933. return;
  7934. }
  7935.  
  7936. const quest = new questRun;
  7937. await quest.autoInit();
  7938. const heroes = Object.values(quest.questInfo['heroGetAll']);
  7939. const inventory = quest.questInfo['inventoryGet'];
  7940. const calls = [];
  7941. for (let i = count; i > 0; i--) {
  7942. const upSkin = quest.getUpgradeSkin();
  7943. if (!upSkin.heroId) {
  7944. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  7945. { msg: I18N('YES'), result: true },
  7946. { result: false, isClose: true }
  7947. ])) {
  7948. break;
  7949. } else {
  7950. return;
  7951. }
  7952. }
  7953. const hero = heroes.find(e => e.id == upSkin.heroId);
  7954. hero.skins[upSkin.skinId]++;
  7955. inventory[upSkin.costСurrency][upSkin.costСurrencyId] -= upSkin.cost;
  7956. calls.push({
  7957. name: "heroSkinUpgrade",
  7958. args: {
  7959. heroId: upSkin.heroId,
  7960. skinId: upSkin.skinId
  7961. },
  7962. ident: `heroSkinUpgrade_${i}`
  7963. })
  7964. }
  7965.  
  7966. if (!calls.length) {
  7967. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  7968. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  7969. return;
  7970. }
  7971.  
  7972. await Send(JSON.stringify({ calls })).then(e => {
  7973. if ('error' in e) {
  7974. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  7975. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  7976. } else {
  7977. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  7978. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  7979. }
  7980. });
  7981. }
  7982.  
  7983. function getQuestionInfo(img, nameOnly = false) {
  7984. const libHeroes = Object.values(lib.data.hero);
  7985. const parts = img.split(':');
  7986. const id = parts[1];
  7987. switch (parts[0]) {
  7988. case 'titanArtifact_id':
  7989. return cheats.translate("LIB_TITAN_ARTIFACT_NAME_" + id);
  7990. case 'titan':
  7991. return cheats.translate("LIB_HERO_NAME_" + id);
  7992. case 'skill':
  7993. return cheats.translate("LIB_SKILL_" + id);
  7994. case 'inventoryItem_gear':
  7995. return cheats.translate("LIB_GEAR_NAME_" + id);
  7996. case 'inventoryItem_coin':
  7997. return cheats.translate("LIB_COIN_NAME_" + id);
  7998. case 'artifact':
  7999. if (nameOnly) {
  8000. return cheats.translate("LIB_ARTIFACT_NAME_" + id);
  8001. }
  8002. heroes = libHeroes.filter(h => h.id < 100 && h.artifacts.includes(+id));
  8003. return {
  8004. /** Как называется этот артефакт? */
  8005. name: cheats.translate("LIB_ARTIFACT_NAME_" + id),
  8006. /** Какому герою принадлежит этот артефакт? */
  8007. heroes: heroes.map(h => cheats.translate("LIB_HERO_NAME_" + h.id))
  8008. };
  8009. case 'hero':
  8010. if (nameOnly) {
  8011. return cheats.translate("LIB_HERO_NAME_" + id);
  8012. }
  8013. artifacts = lib.data.hero[id].artifacts;
  8014. return {
  8015. /** Как зовут этого героя? */
  8016. name: cheats.translate("LIB_HERO_NAME_" + id),
  8017. /** Какой артефакт принадлежит этому герою? */
  8018. artifact: artifacts.map(a => cheats.translate("LIB_ARTIFACT_NAME_" + a))
  8019. };
  8020. }
  8021. }
  8022.  
  8023. function hintQuest(quest) {
  8024. const result = {};
  8025. if (quest?.questionIcon) {
  8026. const info = getQuestionInfo(quest.questionIcon);
  8027. if (info?.heroes) {
  8028. /** Какому герою принадлежит этот артефакт? */
  8029. result.answer = quest.answers.filter(e => info.heroes.includes(e.answerText.slice(1)));
  8030. }
  8031. if (info?.artifact) {
  8032. /** Какой артефакт принадлежит этому герою? */
  8033. result.answer = quest.answers.filter(e => info.artifact.includes(e.answerText.slice(1)));
  8034. }
  8035. if (typeof info == 'string') {
  8036. result.info = { name: info };
  8037. } else {
  8038. result.info = info;
  8039. }
  8040. }
  8041.  
  8042. if (quest.answers[0]?.answerIcon) {
  8043. result.answer = quest.answers.filter(e => quest.question.includes(getQuestionInfo(e.answerIcon, true)))
  8044. }
  8045.  
  8046. if ((!result?.answer || !result.answer.length) && !result.info?.name) {
  8047. return false;
  8048. }
  8049.  
  8050. let resultText = '';
  8051. if (result?.info) {
  8052. resultText += I18N('PICTURE') + result.info.name;
  8053. }
  8054. console.log(result);
  8055. if (result?.answer && result.answer.length) {
  8056. resultText += I18N('ANSWER') + result.answer[0].id + (!result.answer[0].answerIcon ? ' - ' + result.answer[0].answerText : '');
  8057. }
  8058.  
  8059. return resultText;
  8060. }
  8061.  
  8062. /**
  8063. * Attack of the minions of Asgard
  8064. *
  8065. * Атака прислужников Асгарда
  8066. */
  8067. function testRaidNodes() {
  8068. return new Promise((resolve, reject) => {
  8069. const tower = new executeRaidNodes(resolve, reject);
  8070. tower.start();
  8071. });
  8072. }
  8073.  
  8074. /**
  8075. * Attack of the minions of Asgard
  8076. *
  8077. * Атака прислужников Асгарда
  8078. */
  8079. function executeRaidNodes(resolve, reject) {
  8080. let raidData = {
  8081. teams: [],
  8082. favor: {},
  8083. nodes: [],
  8084. attempts: 0,
  8085. countExecuteBattles: 0,
  8086. cancelBattle: 0,
  8087. }
  8088.  
  8089. callsExecuteRaidNodes = {
  8090. calls: [{
  8091. name: "clanRaid_getInfo",
  8092. args: {},
  8093. ident: "clanRaid_getInfo"
  8094. }, {
  8095. name: "teamGetAll",
  8096. args: {},
  8097. ident: "teamGetAll"
  8098. }, {
  8099. name: "teamGetFavor",
  8100. args: {},
  8101. ident: "teamGetFavor"
  8102. }]
  8103. }
  8104.  
  8105. this.start = function () {
  8106. send(JSON.stringify(callsExecuteRaidNodes), startRaidNodes);
  8107. }
  8108.  
  8109. async function startRaidNodes(data) {
  8110. res = data.results;
  8111. clanRaidInfo = res[0].result.response;
  8112. teamGetAll = res[1].result.response;
  8113. teamGetFavor = res[2].result.response;
  8114.  
  8115. let index = 0;
  8116. let isNotFullPack = false;
  8117. for (let team of teamGetAll.clanRaid_nodes) {
  8118. if (team.length < 6) {
  8119. isNotFullPack = true;
  8120. }
  8121. raidData.teams.push({
  8122. data: {},
  8123. heroes: team.filter(id => id < 6000),
  8124. pet: team.filter(id => id >= 6000).pop(),
  8125. battleIndex: index++
  8126. });
  8127. }
  8128. raidData.favor = teamGetFavor.clanRaid_nodes;
  8129.  
  8130. if (isNotFullPack) {
  8131. if (await popup.confirm(I18N('MINIONS_WARNING'), [
  8132. { msg: I18N('BTN_NO'), result: true },
  8133. { msg: I18N('BTN_YES'), result: false },
  8134. ])) {
  8135. endRaidNodes('isNotFullPack');
  8136. return;
  8137. }
  8138. }
  8139.  
  8140. raidData.nodes = clanRaidInfo.nodes;
  8141. raidData.attempts = clanRaidInfo.attempts;
  8142. isCancalBattle = false;
  8143.  
  8144. checkNodes();
  8145. }
  8146.  
  8147. function getAttackNode() {
  8148. for (let nodeId in raidData.nodes) {
  8149. let node = raidData.nodes[nodeId];
  8150. let points = 0
  8151. for (team of node.teams) {
  8152. points += team.points;
  8153. }
  8154. let now = Date.now() / 1000;
  8155. if (!points && now > node.timestamps.start && now < node.timestamps.end) {
  8156. let countTeam = node.teams.length;
  8157. delete raidData.nodes[nodeId];
  8158. return {
  8159. nodeId,
  8160. countTeam
  8161. };
  8162. }
  8163. }
  8164. return null;
  8165. }
  8166.  
  8167. function checkNodes() {
  8168. setProgress(`${I18N('REMAINING_ATTEMPTS')}: ${raidData.attempts}`);
  8169. let nodeInfo = getAttackNode();
  8170. if (nodeInfo && raidData.attempts) {
  8171. startNodeBattles(nodeInfo);
  8172. return;
  8173. }
  8174.  
  8175. endRaidNodes('EndRaidNodes');
  8176. }
  8177.  
  8178. function startNodeBattles(nodeInfo) {
  8179. let {nodeId, countTeam} = nodeInfo;
  8180. let teams = raidData.teams.slice(0, countTeam);
  8181. let heroes = raidData.teams.map(e => e.heroes).flat();
  8182. let favor = {...raidData.favor};
  8183. for (let heroId in favor) {
  8184. if (!heroes.includes(+heroId)) {
  8185. delete favor[heroId];
  8186. }
  8187. }
  8188.  
  8189. let calls = [{
  8190. name: "clanRaid_startNodeBattles",
  8191. args: {
  8192. nodeId,
  8193. teams,
  8194. favor
  8195. },
  8196. ident: "body"
  8197. }];
  8198.  
  8199. send(JSON.stringify({calls}), resultNodeBattles);
  8200. }
  8201.  
  8202. function resultNodeBattles(e) {
  8203. if (e['error']) {
  8204. endRaidNodes('nodeBattlesError', e['error']);
  8205. return;
  8206. }
  8207.  
  8208. console.log(e);
  8209. let battles = e.results[0].result.response.battles;
  8210. let promises = [];
  8211. let battleIndex = 0;
  8212. for (let battle of battles) {
  8213. battle.battleIndex = battleIndex++;
  8214. promises.push(calcBattleResult(battle));
  8215. }
  8216.  
  8217. Promise.all(promises)
  8218. .then(results => {
  8219. const endResults = {};
  8220. let isAllWin = true;
  8221. for (let r of results) {
  8222. isAllWin &&= r.result.win;
  8223. }
  8224. if (!isAllWin) {
  8225. cancelEndNodeBattle(results[0]);
  8226. return;
  8227. }
  8228. raidData.countExecuteBattles = results.length;
  8229. let timeout = 500;
  8230. for (let r of results) {
  8231. setTimeout(endNodeBattle, timeout, r);
  8232. timeout += 500;
  8233. }
  8234. });
  8235. }
  8236. /**
  8237. * Returns the battle calculation promise
  8238. *
  8239. * Возвращает промис расчета боя
  8240. */
  8241. function calcBattleResult(battleData) {
  8242. return new Promise(function (resolve, reject) {
  8243. BattleCalc(battleData, "get_clanPvp", resolve);
  8244. });
  8245. }
  8246. /**
  8247. * Cancels the fight
  8248. *
  8249. * Отменяет бой
  8250. */
  8251. function cancelEndNodeBattle(r) {
  8252. const fixBattle = function (heroes) {
  8253. for (const ids in heroes) {
  8254. hero = heroes[ids];
  8255. hero.energy = random(1, 999);
  8256. if (hero.hp > 0) {
  8257. hero.hp = random(1, hero.hp);
  8258. }
  8259. }
  8260. }
  8261. fixBattle(r.progress[0].attackers.heroes);
  8262. fixBattle(r.progress[0].defenders.heroes);
  8263. endNodeBattle(r);
  8264. }
  8265. /**
  8266. * Ends the fight
  8267. *
  8268. * Завершает бой
  8269. */
  8270. function endNodeBattle(r) {
  8271. let nodeId = r.battleData.result.nodeId;
  8272. let battleIndex = r.battleData.battleIndex;
  8273. let calls = [{
  8274. name: "clanRaid_endNodeBattle",
  8275. args: {
  8276. nodeId,
  8277. battleIndex,
  8278. result: r.result,
  8279. progress: r.progress
  8280. },
  8281. ident: "body"
  8282. }]
  8283.  
  8284. SendRequest(JSON.stringify({calls}), battleResult);
  8285. }
  8286. /**
  8287. * Processing the results of the battle
  8288. *
  8289. * Обработка результатов боя
  8290. */
  8291. function battleResult(e) {
  8292. if (e['error']) {
  8293. endRaidNodes('missionEndError', e['error']);
  8294. return;
  8295. }
  8296. r = e.results[0].result.response;
  8297. if (r['error']) {
  8298. if (r.reason == "invalidBattle") {
  8299. raidData.cancelBattle++;
  8300. checkNodes();
  8301. } else {
  8302. endRaidNodes('missionEndError', e['error']);
  8303. }
  8304. return;
  8305. }
  8306.  
  8307. if (!(--raidData.countExecuteBattles)) {
  8308. raidData.attempts--;
  8309. checkNodes();
  8310. }
  8311. }
  8312. /**
  8313. * Completing a task
  8314. *
  8315. * Завершение задачи
  8316. */
  8317. function endRaidNodes(reason, info) {
  8318. isCancalBattle = true;
  8319. let textCancel = raidData.cancelBattle ? ` ${I18N('BATTLES_CANCELED')}: ${raidData.cancelBattle}` : '';
  8320. setProgress(`${I18N('MINION_RAID')} ${I18N('COMPLETED')}! ${textCancel}`, true);
  8321. console.log(reason, info);
  8322. resolve();
  8323. }
  8324. }
  8325.  
  8326. /**
  8327. * Asgard Boss Attack Replay
  8328. *
  8329. * Повтор атаки босса Асгарда
  8330. */
  8331. function testBossBattle() {
  8332. return new Promise((resolve, reject) => {
  8333. const bossBattle = new executeBossBattle(resolve, reject);
  8334. bossBattle.start(lastBossBattle, lastBossBattleInfo);
  8335. });
  8336. }
  8337.  
  8338. /**
  8339. * Asgard Boss Attack Replay
  8340. *
  8341. * Повтор атаки босса Асгарда
  8342. */
  8343. function executeBossBattle(resolve, reject) {
  8344. let lastBossBattleArgs = {};
  8345. let reachDamage = 0;
  8346. let countBattle = 0;
  8347. let countMaxBattle = 10;
  8348. let lastDamage = 0;
  8349.  
  8350. this.start = function (battleArg, battleInfo) {
  8351. lastBossBattleArgs = battleArg;
  8352. preCalcBattle(battleInfo);
  8353. }
  8354.  
  8355. function getBattleInfo(battle) {
  8356. return new Promise(function (resolve) {
  8357. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  8358. BattleCalc(battle, getBattleType(battle.type), e => {
  8359. let extra = e.progress[0].defenders.heroes[1].extra;
  8360. resolve(extra.damageTaken + extra.damageTakenNextLevel);
  8361. });
  8362. });
  8363. }
  8364.  
  8365. function preCalcBattle(battle) {
  8366. let actions = [];
  8367. const countTestBattle = getInput('countTestBattle');
  8368. for (let i = 0; i < countTestBattle; i++) {
  8369. actions.push(getBattleInfo(battle, true));
  8370. }
  8371. Promise.all(actions)
  8372. .then(resultPreCalcBattle);
  8373. }
  8374.  
  8375. function fixDamage(damage) {
  8376. for (let i = 1e6; i > 1; i /= 10) {
  8377. if (damage > i) {
  8378. let n = i / 10;
  8379. damage = Math.ceil(damage / n) * n;
  8380. break;
  8381. }
  8382. }
  8383. return damage;
  8384. }
  8385.  
  8386. async function resultPreCalcBattle(damages) {
  8387. let maxDamage = 0;
  8388. let minDamage = 1e10;
  8389. let avgDamage = 0;
  8390. for (let damage of damages) {
  8391. avgDamage += damage
  8392. if (damage > maxDamage) {
  8393. maxDamage = damage;
  8394. }
  8395. if (damage < minDamage) {
  8396. minDamage = damage;
  8397. }
  8398. }
  8399. avgDamage /= damages.length;
  8400. console.log(damages.map(e => e.toLocaleString()).join('\n'), avgDamage, maxDamage);
  8401.  
  8402. reachDamage = fixDamage(avgDamage);
  8403. const result = await popup.confirm(
  8404. `${I18N('ROUND_STAT')} ${damages.length} ${I18N('BATTLE')}:` +
  8405. `<br>${I18N('MINIMUM')}: ` + minDamage.toLocaleString() +
  8406. `<br>${I18N('MAXIMUM')}: ` + maxDamage.toLocaleString() +
  8407. `<br>${I18N('AVERAGE')}: ` + avgDamage.toLocaleString()
  8408. /*+ '<br>Поиск урона больше чем ' + reachDamage.toLocaleString()*/
  8409. , [
  8410. { msg: I18N('BTN_OK'), result: 0},
  8411. /* {msg: 'Погнали', isInput: true, default: reachDamage}, */
  8412. ])
  8413. if (result) {
  8414. reachDamage = result;
  8415. isCancalBossBattle = false;
  8416. startBossBattle();
  8417. return;
  8418. }
  8419. endBossBattle(I18N('BTN_CANCEL'));
  8420. }
  8421.  
  8422. function startBossBattle() {
  8423. countBattle++;
  8424. countMaxBattle = getInput('countAutoBattle');
  8425. if (countBattle > countMaxBattle) {
  8426. setProgress('Превышен лимит попыток: ' + countMaxBattle, true);
  8427. endBossBattle('Превышен лимит попыток: ' + countMaxBattle);
  8428. return;
  8429. }
  8430. let calls = [{
  8431. name: "clanRaid_startBossBattle",
  8432. args: lastBossBattleArgs,
  8433. ident: "body"
  8434. }];
  8435. send(JSON.stringify({calls}), calcResultBattle);
  8436. }
  8437.  
  8438. function calcResultBattle(e) {
  8439. BattleCalc(e.results[0].result.response.battle, "get_clanPvp", resultBattle);
  8440. }
  8441.  
  8442. async function resultBattle(e) {
  8443. let extra = e.progress[0].defenders.heroes[1].extra
  8444. resultDamage = extra.damageTaken + extra.damageTakenNextLevel
  8445. console.log(resultDamage);
  8446. scriptMenu.setStatus(countBattle + ') ' + resultDamage.toLocaleString());
  8447. lastDamage = resultDamage;
  8448. if (resultDamage > reachDamage && await popup.confirm(countBattle + ') Урон ' + resultDamage.toLocaleString(), [
  8449. {msg: 'Ок', result: true},
  8450. {msg: 'Не пойдет', result: false},
  8451. ])) {
  8452. endBattle(e, false);
  8453. return;
  8454. }
  8455. cancelEndBattle(e);
  8456. }
  8457.  
  8458. function cancelEndBattle (r) {
  8459. const fixBattle = function (heroes) {
  8460. for (const ids in heroes) {
  8461. hero = heroes[ids];
  8462. hero.energy = random(1, 999);
  8463. if (hero.hp > 0) {
  8464. hero.hp = random(1, hero.hp);
  8465. }
  8466. }
  8467. }
  8468. fixBattle(r.progress[0].attackers.heroes);
  8469. fixBattle(r.progress[0].defenders.heroes);
  8470. endBattle(r, true);
  8471. }
  8472.  
  8473. function endBattle(battleResult, isCancal) {
  8474. let calls = [{
  8475. name: "clanRaid_endBossBattle",
  8476. args: {
  8477. result: battleResult.result,
  8478. progress: battleResult.progress
  8479. },
  8480. ident: "body"
  8481. }];
  8482.  
  8483. send(JSON.stringify({calls}), e => {
  8484. console.log(e);
  8485. if (isCancal) {
  8486. startBossBattle();
  8487. return;
  8488. }
  8489. scriptMenu.setStatus('Босс пробит нанесен урон: ' + lastDamage);
  8490. setTimeout(() => {
  8491. scriptMenu.setStatus('');
  8492. }, 5000);
  8493. endBossBattle('Узпех!');
  8494. });
  8495. }
  8496.  
  8497. /**
  8498. * Completing a task
  8499. *
  8500. * Завершение задачи
  8501. */
  8502. function endBossBattle(reason, info) {
  8503. isCancalBossBattle = true;
  8504. console.log(reason, info);
  8505. resolve();
  8506. }
  8507. }
  8508.  
  8509. /**
  8510. * Auto-repeat attack
  8511. *
  8512. * Автоповтор атаки
  8513. */
  8514. function testAutoBattle() {
  8515. return new Promise((resolve, reject) => {
  8516. const bossBattle = new executeAutoBattle(resolve, reject);
  8517. bossBattle.start(lastBattleArg, lastBattleInfo);
  8518. });
  8519. }
  8520.  
  8521. /**
  8522. * Auto-repeat attack
  8523. *
  8524. * Автоповтор атаки
  8525. */
  8526. function executeAutoBattle(resolve, reject) {
  8527. let battleArg = {};
  8528. let countBattle = 0;
  8529. let countError = 0;
  8530. let findCoeff = 0;
  8531. let dataNotEeceived = 0;
  8532. 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>';
  8533. 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>';
  8534. 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>';
  8535.  
  8536. this.start = function (battleArgs, battleInfo) {
  8537. battleArg = battleArgs;
  8538. preCalcBattle(battleInfo);
  8539. }
  8540. /**
  8541. * Returns a promise for combat recalculation
  8542. *
  8543. * Возвращает промис для прерасчета боя
  8544. */
  8545. function getBattleInfo(battle) {
  8546. return new Promise(function (resolve) {
  8547. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  8548. Calc(battle).then(e => {
  8549. e.coeff = calcCoeff(e, 'defenders');
  8550. resolve(e);
  8551. });
  8552. });
  8553. }
  8554. /**
  8555. * Battle recalculation
  8556. *
  8557. * Прерасчет боя
  8558. */
  8559. function preCalcBattle(battle) {
  8560. let actions = [];
  8561. const countTestBattle = getInput('countTestBattle');
  8562. for (let i = 0; i < countTestBattle; i++) {
  8563. actions.push(getBattleInfo(battle));
  8564. }
  8565. Promise.all(actions)
  8566. .then(resultPreCalcBattle);
  8567. }
  8568. /**
  8569. * Processing the results of the battle recalculation
  8570. *
  8571. * Обработка результатов прерасчета боя
  8572. */
  8573. async function resultPreCalcBattle(results) {
  8574. let countWin = results.reduce((s, w) => w.result.win + s, 0);
  8575. setProgress(`${I18N('CHANCE_TO_WIN')} ${Math.floor(countWin / results.length * 100)}% (${results.length})`, false, hideProgress);
  8576. if (countWin > 0) {
  8577. isCancalBattle = false;
  8578. startBattle();
  8579. return;
  8580. }
  8581.  
  8582. let minCoeff = 100;
  8583. let maxCoeff = -100;
  8584. let avgCoeff = 0;
  8585. results.forEach(e => {
  8586. if (e.coeff < minCoeff) minCoeff = e.coeff;
  8587. if (e.coeff > maxCoeff) maxCoeff = e.coeff;
  8588. avgCoeff += e.coeff;
  8589. });
  8590. avgCoeff /= results.length;
  8591.  
  8592. if (nameFuncStartBattle == 'invasion_bossStart' ||
  8593. nameFuncStartBattle == 'bossAttack') {
  8594. const result = await popup.confirm(
  8595. I18N('BOSS_VICTORY_IMPOSSIBLE', { battles: results.length }), [
  8596. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  8597. { msg: I18N('BTN_DO_IT'), result: true },
  8598. ])
  8599. if (result) {
  8600. isCancalBattle = false;
  8601. startBattle();
  8602. return;
  8603. }
  8604. setProgress(I18N('NOT_THIS_TIME'), true);
  8605. endAutoBattle('invasion_bossStart');
  8606. return;
  8607. }
  8608.  
  8609. const result = await popup.confirm(
  8610. I18N('VICTORY_IMPOSSIBLE') +
  8611. `<br>${I18N('ROUND_STAT')} ${results.length} ${I18N('BATTLE')}:` +
  8612. `<br>${I18N('MINIMUM')}: ` + minCoeff.toLocaleString() +
  8613. `<br>${I18N('MAXIMUM')}: ` + maxCoeff.toLocaleString() +
  8614. `<br>${I18N('AVERAGE')}: ` + avgCoeff.toLocaleString() +
  8615. `<br>${I18N('FIND_COEFF')} ` + avgCoeff.toLocaleString(), [
  8616. { msg: I18N('BTN_CANCEL'), result: 0, isCancel: true },
  8617. { msg: I18N('BTN_GO'), isInput: true, default: Math.round(avgCoeff * 1000) / 1000 },
  8618. ])
  8619. if (result) {
  8620. findCoeff = result;
  8621. isCancalBattle = false;
  8622. startBattle();
  8623. return;
  8624. }
  8625. setProgress(I18N('NOT_THIS_TIME'), true);
  8626. endAutoBattle(I18N('NOT_THIS_TIME'));
  8627. }
  8628.  
  8629. /**
  8630. * Calculation of the combat result coefficient
  8631. *
  8632. * Расчет коэфициента результата боя
  8633. */
  8634. function calcCoeff(result, packType) {
  8635. let beforeSumFactor = 0;
  8636. const beforePack = result.battleData[packType][0];
  8637. for (let heroId in beforePack) {
  8638. const hero = beforePack[heroId];
  8639. const state = hero.state;
  8640. let factor = 1;
  8641. if (state) {
  8642. const hp = state.hp / state.maxHp;
  8643. const energy = state.energy / 1e3;
  8644. factor = hp + energy / 20;
  8645. }
  8646. beforeSumFactor += factor;
  8647. }
  8648.  
  8649. let afterSumFactor = 0;
  8650. const afterPack = result.progress[0][packType].heroes;
  8651. for (let heroId in afterPack) {
  8652. const hero = afterPack[heroId];
  8653. const stateHp = beforePack[heroId]?.state?.hp || beforePack[heroId]?.stats?.hp;
  8654. const hp = hero.hp / stateHp;
  8655. const energy = hero.energy / 1e3;
  8656. const factor = hp + energy / 20;
  8657. afterSumFactor += factor;
  8658. }
  8659. const resultCoeff = -(afterSumFactor - beforeSumFactor);
  8660. return Math.round(resultCoeff * 1000) / 1000;
  8661. }
  8662. /**
  8663. * Start battle
  8664. *
  8665. * Начало боя
  8666. */
  8667. function startBattle() {
  8668. countBattle++;
  8669. const countMaxBattle = getInput('countAutoBattle');
  8670. // setProgress(countBattle + '/' + countMaxBattle);
  8671. if (countBattle > countMaxBattle) {
  8672. setProgress(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`, true);
  8673. endAutoBattle(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`)
  8674. return;
  8675. }
  8676. send({calls: [{
  8677. name: nameFuncStartBattle,
  8678. args: battleArg,
  8679. ident: "body"
  8680. }]}, calcResultBattle);
  8681. }
  8682. /**
  8683. * Battle calculation
  8684. *
  8685. * Расчет боя
  8686. */
  8687. async function calcResultBattle(e) {
  8688. if (!e) {
  8689. console.log('данные не были получены');
  8690. if (dataNotEeceived < 10) {
  8691. dataNotEeceived++;
  8692. startBattle();
  8693. return;
  8694. }
  8695. endAutoBattle('Error', 'данные не были получены ' + dataNotEeceived + ' раз');
  8696. return;
  8697. }
  8698. if ('error' in e) {
  8699. if (e.error.description === 'too many tries') {
  8700. invasionTimer += 100;
  8701. countBattle--;
  8702. countError++;
  8703. console.log(`Errors: ${countError}`, e.error);
  8704. startBattle();
  8705. return;
  8706. }
  8707. const result = await popup.confirm(I18N('ERROR_DURING_THE_BATTLE') + '<br>' + e.error.description, [
  8708. { msg: I18N('BTN_OK'), result: false },
  8709. { msg: I18N('RELOAD_GAME'), result: true },
  8710. ]);
  8711. endAutoBattle('Error', e.error);
  8712. if (result) {
  8713. location.reload();
  8714. }
  8715. return;
  8716. }
  8717. let battle = e.results[0].result.response.battle
  8718. if (nameFuncStartBattle == 'towerStartBattle' ||
  8719. nameFuncStartBattle == 'bossAttack' ||
  8720. nameFuncStartBattle == 'invasion_bossStart') {
  8721. battle = e.results[0].result.response;
  8722. }
  8723. lastBattleInfo = battle;
  8724. BattleCalc(battle, getBattleType(battle.type), resultBattle);
  8725. }
  8726. /**
  8727. * Processing the results of the battle
  8728. *
  8729. * Обработка результатов боя
  8730. */
  8731. function resultBattle(e) {
  8732. const isWin = e.result.win;
  8733. if (isWin) {
  8734. endBattle(e, false);
  8735. return;
  8736. }
  8737. const countMaxBattle = getInput('countAutoBattle');
  8738. if (findCoeff) {
  8739. const coeff = calcCoeff(e, 'defenders');
  8740. setProgress(`${countBattle}/${countMaxBattle}, ${coeff}`);
  8741. if (coeff > findCoeff) {
  8742. endBattle(e, false);
  8743. return;
  8744. }
  8745. } else {
  8746. if (nameFuncStartBattle == 'invasion_bossStart') {
  8747. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  8748. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageMod_any_99_100_300_99_1000 || 0;
  8749. setProgress(`${svgBoss} ${bossLvl} ${svgJustice} ${justice} <br>${svgAttempt} ${countBattle}/${countMaxBattle}`);
  8750. } else {
  8751. setProgress(`${countBattle}/${countMaxBattle}`);
  8752. }
  8753. }
  8754. if (nameFuncStartBattle == 'towerStartBattle' ||
  8755. nameFuncStartBattle == 'bossAttack' ||
  8756. nameFuncStartBattle == 'invasion_bossStart') {
  8757. startBattle();
  8758. return;
  8759. }
  8760. cancelEndBattle(e);
  8761. }
  8762. /**
  8763. * Cancel fight
  8764. *
  8765. * Отмена боя
  8766. */
  8767. function cancelEndBattle(r) {
  8768. const fixBattle = function (heroes) {
  8769. for (const ids in heroes) {
  8770. hero = heroes[ids];
  8771. hero.energy = random(1, 999);
  8772. if (hero.hp > 0) {
  8773. hero.hp = random(1, hero.hp);
  8774. }
  8775. }
  8776. }
  8777. fixBattle(r.progress[0].attackers.heroes);
  8778. fixBattle(r.progress[0].defenders.heroes);
  8779. endBattle(r, true);
  8780. }
  8781. /**
  8782. * End of the fight
  8783. *
  8784. * Завершение боя */
  8785. function endBattle(battleResult, isCancal) {
  8786. let calls = [{
  8787. name: nameFuncEndBattle,
  8788. args: {
  8789. result: battleResult.result,
  8790. progress: battleResult.progress
  8791. },
  8792. ident: "body"
  8793. }];
  8794.  
  8795. if (nameFuncStartBattle == 'invasion_bossStart') {
  8796. calls[0].args.id = lastBattleArg.id;
  8797. }
  8798.  
  8799. send(JSON.stringify({
  8800. calls
  8801. }), async e => {
  8802. console.log(e);
  8803. if (isCancal) {
  8804. startBattle();
  8805. return;
  8806. }
  8807.  
  8808. setProgress(`${I18N('SUCCESS')}!`, 5000)
  8809. if (nameFuncStartBattle == 'invasion_bossStart' ||
  8810. nameFuncStartBattle == 'bossAttack') {
  8811. const countMaxBattle = getInput('countAutoBattle');
  8812. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  8813. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageMod_any_99_100_300_99_1000 || 0;
  8814. const result = await popup.confirm(
  8815. I18N('BOSS_HAS_BEEN_DEF_TEXT', {
  8816. bossLvl: `${svgBoss} ${bossLvl} ${svgJustice} ${justice}`,
  8817. countBattle: svgAttempt + ' ' + countBattle,
  8818. countMaxBattle,
  8819. }),
  8820. [
  8821. { msg: I18N('BTN_OK'), result: 0 },
  8822. { msg: I18N('MAKE_A_SYNC'), result: 1 },
  8823. { msg: I18N('RELOAD_GAME'), result: 2 },
  8824. ]
  8825. );
  8826. if (result) {
  8827. if (result == 1) {
  8828. cheats.refreshGame();
  8829. }
  8830. if (result == 2) {
  8831. location.reload();
  8832. }
  8833. }
  8834.  
  8835. }
  8836. endAutoBattle(`${I18N('SUCCESS')}!`)
  8837. });
  8838. }
  8839. /**
  8840. * Completing a task
  8841. *
  8842. * Завершение задачи
  8843. */
  8844. function endAutoBattle(reason, info) {
  8845. isCancalBattle = true;
  8846. console.log(reason, info);
  8847. resolve();
  8848. }
  8849. }
  8850.  
  8851. function testDailyQuests() {
  8852. return new Promise((resolve, reject) => {
  8853. const quests = new dailyQuests(resolve, reject);
  8854. quests.init(questsInfo);
  8855. quests.start();
  8856. });
  8857. }
  8858.  
  8859. /**
  8860. * Automatic completion of daily quests
  8861. *
  8862. * Автоматическое выполнение ежедневных квестов
  8863. */
  8864. class dailyQuests {
  8865. /**
  8866. * Send(' {"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}').then(e => console.log(e))
  8867. * Send(' {"calls":[{"name":"heroGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  8868. * Send(' {"calls":[{"name":"titanGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  8869. * Send(' {"calls":[{"name":"inventoryGet","args":{},"ident":"body"}]}').then(e => console.log(e))
  8870. * Send(' {"calls":[{"name":"questGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  8871. * Send(' {"calls":[{"name":"bossGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  8872. */
  8873. callsList = [
  8874. "userGetInfo",
  8875. "heroGetAll",
  8876. "titanGetAll",
  8877. "inventoryGet",
  8878. "questGetAll",
  8879. "bossGetAll",
  8880. ]
  8881.  
  8882. dataQuests = {
  8883. 10001: {
  8884. description: 'Улучши умения героев 3 раза', // ++++++++++++++++
  8885. doItCall: () => {
  8886. const upgradeSkills = this.getUpgradeSkills();
  8887. return upgradeSkills.map(({ heroId, skill }, index) => ({ name: "heroUpgradeSkill", args: { heroId, skill }, "ident": `heroUpgradeSkill_${index}` }));
  8888. },
  8889. isWeCanDo: () => {
  8890. const upgradeSkills = this.getUpgradeSkills();
  8891. let sumGold = 0;
  8892. for (const skill of upgradeSkills) {
  8893. sumGold += this.skillCost(skill.value);
  8894. if (!skill.heroId) {
  8895. return false;
  8896. }
  8897. }
  8898. return this.questInfo['userGetInfo'].gold > sumGold;
  8899. },
  8900. },
  8901. 10002: {
  8902. description: 'Пройди 10 миссий', // --------------
  8903. isWeCanDo: () => false,
  8904. },
  8905. 10003: {
  8906. description: 'Пройди 3 героические миссии', // --------------
  8907. isWeCanDo: () => false,
  8908. },
  8909. 10004: {
  8910. description: 'Сразись 3 раза на Арене или Гранд Арене', // --------------
  8911. isWeCanDo: () => false,
  8912. },
  8913. 10006: {
  8914. description: 'Используй обмен изумрудов 1 раз', // ++++++++++++++++
  8915. doItCall: () => [{
  8916. name: "refillableAlchemyUse",
  8917. args: { multi: false },
  8918. ident: "refillableAlchemyUse"
  8919. }],
  8920. isWeCanDo: () => {
  8921. const starMoney = this.questInfo['userGetInfo'].starMoney;
  8922. return starMoney >= 20;
  8923. },
  8924. },
  8925. 10007: {
  8926. description: 'Соверши 1 призыв в Атриуме Душ', // ++++++++++++++++
  8927. doItCall: () => [{ name: "gacha_open", args: { ident: "heroGacha", free: true, pack: false }, ident: "gacha_open" }],
  8928. isWeCanDo: () => {
  8929. const soulCrystal = this.questInfo['inventoryGet'].coin[38];
  8930. return soulCrystal > 0;
  8931. },
  8932. },
  8933. 10016: {
  8934. description: 'Отправь подарки согильдийцам', // ++++++++++++++++
  8935. doItCall: () => [{ name: "clanSendDailyGifts", args: {}, ident: "clanSendDailyGifts" }],
  8936. isWeCanDo: () => true,
  8937. },
  8938. 10018: {
  8939. description: 'Используй зелье опыта', // ++++++++++++++++
  8940. doItCall: () => {
  8941. const expHero = this.getExpHero();
  8942. return [{
  8943. name: "consumableUseHeroXp",
  8944. args: {
  8945. heroId: expHero.heroId,
  8946. libId: expHero.libId,
  8947. amount: 1
  8948. },
  8949. ident: "consumableUseHeroXp"
  8950. }];
  8951. },
  8952. isWeCanDo: () => {
  8953. const expHero = this.getExpHero();
  8954. return expHero.heroId && expHero.libId;
  8955. },
  8956. },
  8957. 10019: {
  8958. description: 'Открой 1 сундук в Башне',
  8959. doItFunc: testTower,
  8960. isWeCanDo: () => false,
  8961. },
  8962. 10020: {
  8963. description: 'Открой 3 сундука в Запределье', // Готово
  8964. doItCall: () => {
  8965. return this.getOutlandChest();
  8966. },
  8967. isWeCanDo: () => {
  8968. const outlandChest = this.getOutlandChest();
  8969. return outlandChest.length > 0;
  8970. },
  8971. },
  8972. 10021: {
  8973. description: 'Собери 75 Титанита в Подземелье Гильдии',
  8974. isWeCanDo: () => false,
  8975. },
  8976. 10022: {
  8977. description: 'Собери 150 Титанита в Подземелье Гильдии',
  8978. doItFunc: testDungeon,
  8979. isWeCanDo: () => false,
  8980. },
  8981. 10023: {
  8982. description: 'Прокачай Дар Стихий на 1 уровень', // Готово
  8983. doItCall: () => {
  8984. const heroId = this.getHeroIdTitanGift();
  8985. return [
  8986. { name: "heroTitanGiftLevelUp", args: { heroId }, ident: "heroTitanGiftLevelUp" },
  8987. { name: "heroTitanGiftDrop", args: { heroId }, ident: "heroTitanGiftDrop" }
  8988. ]
  8989. },
  8990. isWeCanDo: () => {
  8991. const heroId = this.getHeroIdTitanGift();
  8992. return heroId;
  8993. },
  8994. },
  8995. 10024: {
  8996. description: 'Повысь уровень любого артефакта один раз', // Готово
  8997. doItCall: () => {
  8998. const upArtifact = this.getUpgradeArtifact();
  8999. return [
  9000. {
  9001. name: "heroArtifactLevelUp",
  9002. args: {
  9003. heroId: upArtifact.heroId,
  9004. slotId: upArtifact.slotId
  9005. },
  9006. ident: `heroArtifactLevelUp`
  9007. }
  9008. ];
  9009. },
  9010. isWeCanDo: () => {
  9011. const upgradeArtifact = this.getUpgradeArtifact();
  9012. return upgradeArtifact.heroId;
  9013. },
  9014. },
  9015. 10025: {
  9016. description: 'Начни 1 Экспедицию',
  9017. doItFunc: checkExpedition,
  9018. isWeCanDo: () => false,
  9019. },
  9020. 10026: {
  9021. description: 'Начни 4 Экспедиции', // --------------
  9022. doItFunc: checkExpedition,
  9023. isWeCanDo: () => false,
  9024. },
  9025. 10027: {
  9026. description: 'Победи в 1 бою Турнира Стихий',
  9027. doItFunc: testTitanArena,
  9028. isWeCanDo: () => false,
  9029. },
  9030. 10028: {
  9031. description: 'Повысь уровень любого артефакта титанов', // Готово
  9032. doItCall: () => {
  9033. const upTitanArtifact = this.getUpgradeTitanArtifact();
  9034. return [
  9035. {
  9036. name: "titanArtifactLevelUp",
  9037. args: {
  9038. titanId: upTitanArtifact.titanId,
  9039. slotId: upTitanArtifact.slotId
  9040. },
  9041. ident: `titanArtifactLevelUp`
  9042. }
  9043. ];
  9044. },
  9045. isWeCanDo: () => {
  9046. const upgradeTitanArtifact = this.getUpgradeTitanArtifact();
  9047. return upgradeTitanArtifact.titanId;
  9048. },
  9049. },
  9050. 10029: {
  9051. description: 'Открой сферу артефактов титанов', // ++++++++++++++++
  9052. doItCall: () => [{ name: "titanArtifactChestOpen", args: { amount: 1, free: true }, ident: "titanArtifactChestOpen" }],
  9053. isWeCanDo: () => {
  9054. return this.questInfo['inventoryGet']?.consumable[55] > 0
  9055. },
  9056. },
  9057. 10030: {
  9058. description: 'Улучши облик любого героя 1 раз', // Готово
  9059. doItCall: () => {
  9060. const upSkin = this.getUpgradeSkin();
  9061. return [
  9062. {
  9063. name: "heroSkinUpgrade",
  9064. args: {
  9065. heroId: upSkin.heroId,
  9066. skinId: upSkin.skinId
  9067. },
  9068. ident: `heroSkinUpgrade`
  9069. }
  9070. ];
  9071. },
  9072. isWeCanDo: () => {
  9073. const upgradeSkin = this.getUpgradeSkin();
  9074. return upgradeSkin.heroId;
  9075. },
  9076. },
  9077. 10031: {
  9078. description: 'Победи в 6 боях Турнира Стихий', // --------------
  9079. doItFunc: testTitanArena,
  9080. isWeCanDo: () => false,
  9081. },
  9082. 10043: {
  9083. description: 'Начни или присоеденись к Приключению', // --------------
  9084. isWeCanDo: () => false,
  9085. },
  9086. 10044: {
  9087. description: 'Воспользуйся призывом питомцев 1 раз', // ++++++++++++++++
  9088. doItCall: () => [{ name: "pet_chestOpen", args: { amount: 1, paid: false }, ident: "pet_chestOpen" }],
  9089. isWeCanDo: () => {
  9090. return this.questInfo['inventoryGet']?.consumable[90] > 0
  9091. },
  9092. },
  9093. 10046: {
  9094. /**
  9095. * TODO: Watch Adventure
  9096. * TODO: Смотреть приключение
  9097. */
  9098. description: 'Открой 3 сундука в Приключениях',
  9099. isWeCanDo: () => false,
  9100. },
  9101. 10047: {
  9102. description: 'Набери 150 очков активности в Гильдии', // Готово
  9103. doItCall: () => {
  9104. const enchantRune = this.getEnchantRune();
  9105. return [
  9106. {
  9107. name: "heroEnchantRune",
  9108. args: {
  9109. heroId: enchantRune.heroId,
  9110. tier: enchantRune.tier,
  9111. items: {
  9112. consumable: { [enchantRune.itemId]: 1 }
  9113. }
  9114. },
  9115. ident: `heroEnchantRune`
  9116. }
  9117. ];
  9118. },
  9119. isWeCanDo: () => {
  9120. const userInfo = this.questInfo['userGetInfo'];
  9121. const enchantRune = this.getEnchantRune();
  9122. return enchantRune.heroId && userInfo.gold > 1e3;
  9123. },
  9124. },
  9125. };
  9126.  
  9127. constructor(resolve, reject, questInfo) {
  9128. this.resolve = resolve;
  9129. this.reject = reject;
  9130. }
  9131.  
  9132. init(questInfo) {
  9133. this.questInfo = questInfo;
  9134. this.isAuto = false;
  9135. }
  9136.  
  9137. async autoInit(isAuto) {
  9138. this.isAuto = isAuto || false;
  9139. const quests = {};
  9140. const calls = this.callsList.map(name => ({
  9141. name, args: {}, ident: name
  9142. }))
  9143. const result = await Send(JSON.stringify({ calls })).then(e => e.results);
  9144. for (const call of result) {
  9145. quests[call.ident] = call.result.response;
  9146. }
  9147. this.questInfo = quests;
  9148. }
  9149.  
  9150. async start() {
  9151. const weCanDo = [];
  9152. const selectedActions = getSaveVal('selectedActions', {});
  9153. for (let quest of this.questInfo['questGetAll']) {
  9154. if (quest.id in this.dataQuests && quest.state == 1) {
  9155. if (!selectedActions[quest.id]) {
  9156. selectedActions[quest.id] = {
  9157. checked: false
  9158. }
  9159. }
  9160.  
  9161. const isWeCanDo = this.dataQuests[quest.id].isWeCanDo;
  9162. if (!isWeCanDo.call(this)) {
  9163. continue;
  9164. }
  9165.  
  9166. weCanDo.push({
  9167. name: quest.id,
  9168. label: I18N(`QUEST_${quest.id}`),
  9169. checked: selectedActions[quest.id].checked
  9170. });
  9171. }
  9172. }
  9173.  
  9174. if (!weCanDo.length) {
  9175. this.end(I18N('NOTHING_TO_DO'));
  9176. return;
  9177. }
  9178.  
  9179. console.log(weCanDo);
  9180. let taskList = [];
  9181. if (this.isAuto) {
  9182. taskList = weCanDo;
  9183. } else {
  9184. const answer = await popup.confirm(`${I18N('YOU_CAN_COMPLETE') }:`, [
  9185. { msg: I18N('BTN_DO_IT'), result: true },
  9186. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  9187. ], weCanDo);
  9188. if (!answer) {
  9189. this.end('');
  9190. return;
  9191. }
  9192. taskList = popup.getCheckBoxes();
  9193. taskList.forEach(e => {
  9194. selectedActions[e.name].checked = e.checked;
  9195. });
  9196. setSaveVal('selectedActions', selectedActions);
  9197. }
  9198.  
  9199. const calls = [];
  9200. let countChecked = 0;
  9201. for (const task of taskList) {
  9202. if (task.checked) {
  9203. countChecked++;
  9204. const quest = this.dataQuests[task.name]
  9205. console.log(quest.description);
  9206.  
  9207. if (quest.doItCall) {
  9208. const doItCall = quest.doItCall.call(this);
  9209. calls.push(...doItCall);
  9210. }
  9211. }
  9212. }
  9213.  
  9214. if (!countChecked) {
  9215. this.end(I18N('NOT_QUEST_COMPLETED'));
  9216. return;
  9217. }
  9218.  
  9219. const result = await Send(JSON.stringify({ calls }));
  9220. if (result.error) {
  9221. console.error(result.error, result.error.call)
  9222. }
  9223. this.end(`${I18N('COMPLETED_QUESTS')}: ${countChecked}`);
  9224. }
  9225.  
  9226. errorHandling(error) {
  9227. //console.error(error);
  9228. let errorInfo = error.toString() + '\n';
  9229. try {
  9230. const errorStack = error.stack.split('\n');
  9231. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  9232. errorInfo += errorStack.slice(0, endStack).join('\n');
  9233. } catch (e) {
  9234. errorInfo += error.stack;
  9235. }
  9236. copyText(errorInfo);
  9237. }
  9238.  
  9239. skillCost(lvl) {
  9240. return 573 * lvl ** 0.9 + lvl ** 2.379;
  9241. }
  9242.  
  9243. getUpgradeSkills() {
  9244. const heroes = Object.values(this.questInfo['heroGetAll']);
  9245. const upgradeSkills = [
  9246. { heroId: 0, slotId: 0, value: 130 },
  9247. { heroId: 0, slotId: 0, value: 130 },
  9248. { heroId: 0, slotId: 0, value: 130 },
  9249. ];
  9250. const skillLib = lib.getData('skill');
  9251. /**
  9252. * color - 1 (белый) открывает 1 навык
  9253. * color - 2 (зеленый) открывает 2 навык
  9254. * color - 4 (синий) открывает 3 навык
  9255. * color - 7 (фиолетовый) открывает 4 навык
  9256. */
  9257. const colors = [1, 2, 4, 7];
  9258. for (const hero of heroes) {
  9259. const level = hero.level;
  9260. const color = hero.color;
  9261. for (let skillId in hero.skills) {
  9262. const tier = skillLib[skillId].tier;
  9263. const sVal = hero.skills[skillId];
  9264. if (color < colors[tier] || tier < 1 || tier > 4) {
  9265. continue;
  9266. }
  9267. for (let upSkill of upgradeSkills) {
  9268. if (sVal < upSkill.value && sVal < level) {
  9269. upSkill.value = sVal;
  9270. upSkill.heroId = hero.id;
  9271. upSkill.skill = tier;
  9272. break;
  9273. }
  9274. }
  9275. }
  9276. }
  9277. return upgradeSkills;
  9278. }
  9279.  
  9280. getUpgradeArtifact() {
  9281. const heroes = Object.values(this.questInfo['heroGetAll']);
  9282. const inventory = this.questInfo['inventoryGet'];
  9283. const upArt = { heroId: 0, slotId: 0, level: 100 };
  9284.  
  9285. const heroLib = lib.getData('hero');
  9286. const artifactLib = lib.getData('artifact');
  9287.  
  9288. for (const hero of heroes) {
  9289. const heroInfo = heroLib[hero.id];
  9290. const level = hero.level
  9291. if (level < 20) {
  9292. continue;
  9293. }
  9294.  
  9295. for (let slotId in hero.artifacts) {
  9296. const art = hero.artifacts[slotId];
  9297. /* Текущая звезданость арта */
  9298. const star = art.star;
  9299. if (!star) {
  9300. continue;
  9301. }
  9302. /* Текущий уровень арта */
  9303. const level = art.level;
  9304. if (level >= 100) {
  9305. continue;
  9306. }
  9307. /* Идентификатор арта в библиотеке */
  9308. const artifactId = heroInfo.artifacts[slotId];
  9309. const artInfo = artifactLib.id[artifactId];
  9310. const costNextLevel = artifactLib.type[artInfo.type].levels[level + 1].cost;
  9311.  
  9312. const costСurrency = Object.keys(costNextLevel).pop();
  9313. const costValues = Object.entries(costNextLevel[costСurrency]).pop();
  9314. const costId = costValues[0];
  9315. const costValue = +costValues[1];
  9316.  
  9317. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  9318. if (level < upArt.level && inventory[costСurrency][costId] >= costValue) {
  9319. upArt.level = level;
  9320. upArt.heroId = hero.id;
  9321. upArt.slotId = slotId;
  9322. upArt.costСurrency = costСurrency;
  9323. upArt.costId = costId;
  9324. upArt.costValue = costValue;
  9325. }
  9326. }
  9327. }
  9328. return upArt;
  9329. }
  9330.  
  9331. getUpgradeSkin() {
  9332. const heroes = Object.values(this.questInfo['heroGetAll']);
  9333. const inventory = this.questInfo['inventoryGet'];
  9334. const upSkin = { heroId: 0, skinId: 0, level: 60, cost: 1500 };
  9335.  
  9336. const skinLib = lib.getData('skin');
  9337.  
  9338. for (const hero of heroes) {
  9339. const level = hero.level
  9340. if (level < 20) {
  9341. continue;
  9342. }
  9343.  
  9344. for (let skinId in hero.skins) {
  9345. /* Текущий уровень скина */
  9346. const level = hero.skins[skinId];
  9347. if (level >= 60) {
  9348. continue;
  9349. }
  9350. /* Идентификатор скина в библиотеке */
  9351. const skinInfo = skinLib[skinId];
  9352. if (!skinInfo.statData.levels?.[level + 1]) {
  9353. continue;
  9354. }
  9355. const costNextLevel = skinInfo.statData.levels[level + 1].cost;
  9356.  
  9357. const costСurrency = Object.keys(costNextLevel).pop();
  9358. const costСurrencyId = Object.keys(costNextLevel[costСurrency]).pop();
  9359. const costValue = +costNextLevel[costСurrency][costСurrencyId];
  9360.  
  9361. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  9362. if (level < upSkin.level &&
  9363. costValue < upSkin.cost &&
  9364. inventory[costСurrency][costСurrencyId] >= costValue) {
  9365. upSkin.cost = costValue;
  9366. upSkin.level = level;
  9367. upSkin.heroId = hero.id;
  9368. upSkin.skinId = skinId;
  9369. upSkin.costСurrency = costСurrency;
  9370. upSkin.costСurrencyId = costСurrencyId;
  9371. }
  9372. }
  9373. }
  9374. return upSkin;
  9375. }
  9376.  
  9377. getUpgradeTitanArtifact() {
  9378. const titans = Object.values(this.questInfo['titanGetAll']);
  9379. const inventory = this.questInfo['inventoryGet'];
  9380. const userInfo = this.questInfo['userGetInfo'];
  9381. const upArt = { titanId: 0, slotId: 0, level: 120 };
  9382.  
  9383. const titanLib = lib.getData('titan');
  9384. const artTitanLib = lib.getData('titanArtifact');
  9385.  
  9386. for (const titan of titans) {
  9387. const titanInfo = titanLib[titan.id];
  9388. // const level = titan.level
  9389. // if (level < 20) {
  9390. // continue;
  9391. // }
  9392.  
  9393. for (let slotId in titan.artifacts) {
  9394. const art = titan.artifacts[slotId];
  9395. /* Текущая звезданость арта */
  9396. const star = art.star;
  9397. if (!star) {
  9398. continue;
  9399. }
  9400. /* Текущий уровень арта */
  9401. const level = art.level;
  9402. if (level >= 120) {
  9403. continue;
  9404. }
  9405. /* Идентификатор арта в библиотеке */
  9406. const artifactId = titanInfo.artifacts[slotId];
  9407. const artInfo = artTitanLib.id[artifactId];
  9408. const costNextLevel = artTitanLib.type[artInfo.type].levels[level + 1].cost;
  9409.  
  9410. const costСurrency = Object.keys(costNextLevel).pop();
  9411. let costValue = 0;
  9412. let currentValue = 0;
  9413. if (costСurrency == 'gold') {
  9414. costValue = costNextLevel[costСurrency];
  9415. currentValue = userInfo.gold;
  9416. } else {
  9417. const costValues = Object.entries(costNextLevel[costСurrency]).pop();
  9418. const costId = costValues[0];
  9419. costValue = +costValues[1];
  9420. currentValue = inventory[costСurrency][costId];
  9421. }
  9422.  
  9423. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  9424. if (level < upArt.level && currentValue >= costValue) {
  9425. upArt.level = level;
  9426. upArt.titanId = titan.id;
  9427. upArt.slotId = slotId;
  9428. break;
  9429. }
  9430. }
  9431. }
  9432. return upArt;
  9433. }
  9434.  
  9435. getEnchantRune() {
  9436. const heroes = Object.values(this.questInfo['heroGetAll']);
  9437. const inventory = this.questInfo['inventoryGet'];
  9438. const enchRune = { heroId: 0, tier: 0, exp: 43750, itemId: 0 };
  9439. for (let i = 1; i <= 4; i++) {
  9440. if (inventory.consumable[i] > 0) {
  9441. enchRune.itemId = i;
  9442. break;
  9443. }
  9444. return enchRune;
  9445. }
  9446.  
  9447. const runeLib = lib.getData('rune');
  9448. const runeLvls = Object.values(runeLib.level);
  9449. /**
  9450. * color - 4 (синий) открывает 1 и 2 символ
  9451. * color - 7 (фиолетовый) открывает 3 символ
  9452. * color - 8 (фиолетовый +1) открывает 4 символ
  9453. * color - 9 (фиолетовый +2) открывает 5 символ
  9454. */
  9455. // TODO: кажется надо учесть уровень команды
  9456. const colors = [4, 4, 7, 8, 9];
  9457. for (const hero of heroes) {
  9458. const color = hero.color;
  9459.  
  9460.  
  9461. for (let runeTier in hero.runes) {
  9462. /* Проверка на доступность руны */
  9463. if (color < colors[runeTier]) {
  9464. continue;
  9465. }
  9466. /* Текущий опыт руны */
  9467. const exp = hero.runes[runeTier];
  9468. if (exp >= 43750) {
  9469. continue;
  9470. }
  9471.  
  9472. let level = 0;
  9473. if (exp) {
  9474. for (let lvl of runeLvls) {
  9475. if (exp >= lvl.enchantValue) {
  9476. level = lvl.level;
  9477. } else {
  9478. break;
  9479. }
  9480. }
  9481. }
  9482. /** Уровень героя необходимый для уровня руны */
  9483. const heroLevel = runeLib.level[level].heroLevel;
  9484. if (hero.level < heroLevel) {
  9485. continue;
  9486. }
  9487.  
  9488. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  9489. if (exp < enchRune.exp) {
  9490. enchRune.exp = exp;
  9491. enchRune.heroId = hero.id;
  9492. enchRune.tier = runeTier;
  9493. break;
  9494. }
  9495. }
  9496. }
  9497. return enchRune;
  9498. }
  9499.  
  9500. getOutlandChest() {
  9501. const bosses = this.questInfo['bossGetAll'];
  9502.  
  9503. const calls = [];
  9504.  
  9505. for (let boss of bosses) {
  9506. if (boss.mayRaid) {
  9507. calls.push({
  9508. name: "bossRaid",
  9509. args: {
  9510. bossId: boss.id
  9511. },
  9512. ident: "bossRaid_" + boss.id
  9513. });
  9514. calls.push({
  9515. name: "bossOpenChest",
  9516. args: {
  9517. bossId: boss.id,
  9518. amount: 1,
  9519. starmoney: 0
  9520. },
  9521. ident: "bossOpenChest_" + boss.id
  9522. });
  9523. } else if (boss.chestId == 1) {
  9524. calls.push({
  9525. name: "bossOpenChest",
  9526. args: {
  9527. bossId: boss.id,
  9528. amount: 1,
  9529. starmoney: 0
  9530. },
  9531. ident: "bossOpenChest_" + boss.id
  9532. });
  9533. }
  9534. }
  9535.  
  9536. return calls;
  9537. }
  9538.  
  9539. getExpHero() {
  9540. const heroes = Object.values(this.questInfo['heroGetAll']);
  9541. const inventory = this.questInfo['inventoryGet'];
  9542. const expHero = { heroId: 0, exp: 3625195, libId: 0 };
  9543. /** зелья опыта (consumable 9, 10, 11, 12) */
  9544. for (let i = 9; i <= 12; i++) {
  9545. if (inventory.consumable[i]) {
  9546. expHero.libId = i;
  9547. break;
  9548. }
  9549. }
  9550.  
  9551. for (const hero of heroes) {
  9552. const exp = hero.xp;
  9553. if (exp < expHero.exp) {
  9554. expHero.heroId = hero.id;
  9555. }
  9556. }
  9557. return expHero;
  9558. }
  9559.  
  9560. getHeroIdTitanGift() {
  9561. const heroes = Object.values(this.questInfo['heroGetAll']);
  9562. const inventory = this.questInfo['inventoryGet'];
  9563. const user = this.questInfo['userGetInfo'];
  9564. const titanGiftLib = lib.getData('titanGift');
  9565. /** Искры */
  9566. const titanGift = inventory.consumable[24];
  9567. let heroId = 0;
  9568. let minLevel = 30;
  9569.  
  9570. if (titanGift < 250 || user.gold < 7000) {
  9571. return 0;
  9572. }
  9573.  
  9574. for (const hero of heroes) {
  9575. if (hero.titanGiftLevel >= 30) {
  9576. continue;
  9577. }
  9578.  
  9579. if (!hero.titanGiftLevel) {
  9580. return hero.id;
  9581. }
  9582.  
  9583. const cost = titanGiftLib[hero.titanGiftLevel].cost;
  9584. if (minLevel > hero.titanGiftLevel &&
  9585. titanGift >= cost.consumable[24] &&
  9586. user.gold >= cost.gold
  9587. ) {
  9588. minLevel = hero.titanGiftLevel;
  9589. heroId = hero.id;
  9590. }
  9591. }
  9592.  
  9593. return heroId;
  9594. }
  9595.  
  9596. end(status) {
  9597. setProgress(status, true);
  9598. this.resolve();
  9599. }
  9600. }
  9601.  
  9602. this.questRun = dailyQuests;
  9603.  
  9604. function testDoYourBest() {
  9605. return new Promise((resolve, reject) => {
  9606. const doIt = new doYourBest(resolve, reject);
  9607. doIt.start();
  9608. });
  9609. }
  9610.  
  9611. /**
  9612. * Do everything button
  9613. *
  9614. * Кнопка сделать все
  9615. */
  9616. class doYourBest {
  9617.  
  9618. funcList = [
  9619. {
  9620. name: 'getOutland',
  9621. label: I18N('ASSEMBLE_OUTLAND'),
  9622. checked: false
  9623. },
  9624. {
  9625. name: 'testTower',
  9626. label: I18N('PASS_THE_TOWER'),
  9627. checked: false
  9628. },
  9629. {
  9630. name: 'checkExpedition',
  9631. label: I18N('CHECK_EXPEDITIONS'),
  9632. checked: false
  9633. },
  9634. {
  9635. name: 'testTitanArena',
  9636. label: I18N('COMPLETE_TOE'),
  9637. checked: false
  9638. },
  9639. {
  9640. name: 'mailGetAll',
  9641. label: I18N('COLLECT_MAIL'),
  9642. checked: false
  9643. },
  9644. {
  9645. name: 'collectAllStuff',
  9646. label: I18N('COLLECT_MISC'),
  9647. title: I18N('COLLECT_MISC_TITLE'),
  9648. checked: false
  9649. },
  9650. {
  9651. name: 'getDailyBonus',
  9652. label: I18N('DAILY_BONUS'),
  9653. checked: false
  9654. },
  9655. {
  9656. name: 'dailyQuests',
  9657. label: I18N('DO_DAILY_QUESTS'),
  9658. checked: false
  9659. },
  9660. {
  9661. name: 'rollAscension',
  9662. label: I18N('SEER_TITLE'),
  9663. checked: false
  9664. },
  9665. {
  9666. name: 'questAllFarm',
  9667. label: I18N('COLLECT_QUEST_REWARDS'),
  9668. checked: false
  9669. },
  9670. {
  9671. name: 'testDungeon',
  9672. label: I18N('COMPLETE_DUNGEON'),
  9673. checked: false
  9674. },
  9675. {
  9676. name: 'synchronization',
  9677. label: I18N('MAKE_A_SYNC'),
  9678. checked: false
  9679. },
  9680. {
  9681. name: 'reloadGame',
  9682. label: I18N('RELOAD_GAME'),
  9683. checked: false
  9684. },
  9685. ];
  9686.  
  9687. functions = {
  9688. getOutland,
  9689. testTower,
  9690. checkExpedition,
  9691. testTitanArena,
  9692. mailGetAll,
  9693. collectAllStuff: async () => {
  9694. await offerFarmAllReward();
  9695. 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"}]}');
  9696. },
  9697. dailyQuests: async function () {
  9698. const quests = new dailyQuests(() => { }, () => { });
  9699. await quests.autoInit(true);
  9700. await quests.start();
  9701. },
  9702. rollAscension,
  9703. getDailyBonus,
  9704. questAllFarm,
  9705. testDungeon,
  9706. synchronization: async () => {
  9707. cheats.refreshGame();
  9708. },
  9709. reloadGame: async () => {
  9710. location.reload();
  9711. },
  9712. }
  9713.  
  9714. constructor(resolve, reject, questInfo) {
  9715. this.resolve = resolve;
  9716. this.reject = reject;
  9717. this.questInfo = questInfo
  9718. }
  9719.  
  9720. async start() {
  9721. const selectedDoIt = getSaveVal('selectedDoIt', {});
  9722.  
  9723. this.funcList.forEach(task => {
  9724. if (!selectedDoIt[task.name]) {
  9725. selectedDoIt[task.name] = {
  9726. checked: task.checked
  9727. }
  9728. } else {
  9729. task.checked = selectedDoIt[task.name].checked
  9730. }
  9731. });
  9732.  
  9733. const answer = await popup.confirm(I18N('RUN_FUNCTION'), [
  9734. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  9735. { msg: I18N('BTN_GO'), result: true },
  9736. ], this.funcList);
  9737.  
  9738. if (!answer) {
  9739. this.end('');
  9740. return;
  9741. }
  9742.  
  9743. const taskList = popup.getCheckBoxes();
  9744. taskList.forEach(task => {
  9745. selectedDoIt[task.name].checked = task.checked;
  9746. });
  9747. setSaveVal('selectedDoIt', selectedDoIt);
  9748. for (const task of popup.getCheckBoxes()) {
  9749. if (task.checked) {
  9750. try {
  9751. setProgress(`${task.label} <br>${I18N('PERFORMED')}!`);
  9752. await this.functions[task.name]();
  9753. setProgress(`${task.label} <br>${I18N('DONE')}!`);
  9754. } catch (error) {
  9755. if (await popup.confirm(`${I18N('ERRORS_OCCURRES')}:<br> ${task.label} <br>${I18N('COPY_ERROR')}?`, [
  9756. { msg: I18N('BTN_NO'), result: false },
  9757. { msg: I18N('BTN_YES'), result: true },
  9758. ])) {
  9759. this.errorHandling(error);
  9760. }
  9761. }
  9762. }
  9763. }
  9764. setTimeout((msg) => {
  9765. this.end(msg);
  9766. }, 2000, I18N('ALL_TASK_COMPLETED'));
  9767. return;
  9768. }
  9769.  
  9770. errorHandling(error) {
  9771. //console.error(error);
  9772. let errorInfo = error.toString() + '\n';
  9773. try {
  9774. const errorStack = error.stack.split('\n');
  9775. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  9776. errorInfo += errorStack.slice(0, endStack).join('\n');
  9777. } catch (e) {
  9778. errorInfo += error.stack;
  9779. }
  9780. copyText(errorInfo);
  9781. }
  9782.  
  9783. end(status) {
  9784. setProgress(status, true);
  9785. this.resolve();
  9786. }
  9787. }
  9788.  
  9789. /**
  9790. * Passing the adventure along the specified route
  9791. *
  9792. * Прохождение приключения по указанному маршруту
  9793. */
  9794. function testAdventure(type) {
  9795. return new Promise((resolve, reject) => {
  9796. const bossBattle = new executeAdventure(resolve, reject);
  9797. bossBattle.start(type);
  9798. });
  9799. }
  9800.  
  9801. /**
  9802. * Passing the adventure along the specified route
  9803. *
  9804. * Прохождение приключения по указанному маршруту
  9805. */
  9806. class executeAdventure {
  9807.  
  9808. type = 'default';
  9809.  
  9810. actions = {
  9811. default: {
  9812. getInfo: "adventure_getInfo",
  9813. startBattle: 'adventure_turnStartBattle',
  9814. endBattle: 'adventure_endBattle',
  9815. collectBuff: 'adventure_turnCollectBuff'
  9816. },
  9817. solo: {
  9818. getInfo: "adventureSolo_getInfo",
  9819. startBattle: 'adventureSolo_turnStartBattle',
  9820. endBattle: 'adventureSolo_endBattle',
  9821. collectBuff: 'adventureSolo_turnCollectBuff'
  9822. }
  9823. }
  9824.  
  9825. terminatеReason = I18N('UNKNOWN');
  9826. callAdventureInfo = {
  9827. name: "adventure_getInfo",
  9828. args: {},
  9829. ident: "adventure_getInfo"
  9830. }
  9831. callTeamGetAll = {
  9832. name: "teamGetAll",
  9833. args: {},
  9834. ident: "teamGetAll"
  9835. }
  9836. callTeamGetFavor = {
  9837. name: "teamGetFavor",
  9838. args: {},
  9839. ident: "teamGetFavor"
  9840. }
  9841. callStartBattle = {
  9842. name: "adventure_turnStartBattle",
  9843. args: {},
  9844. ident: "body"
  9845. }
  9846. callEndBattle = {
  9847. name: "adventure_endBattle",
  9848. args: {
  9849. result: {},
  9850. progress: {},
  9851. },
  9852. ident: "body"
  9853. }
  9854. callCollectBuff = {
  9855. name: "adventure_turnCollectBuff",
  9856. args: {},
  9857. ident: "body"
  9858. }
  9859.  
  9860. constructor(resolve, reject) {
  9861. this.resolve = resolve;
  9862. this.reject = reject;
  9863. }
  9864.  
  9865. async start(type) {
  9866. this.type = type || this.type;
  9867. this.callAdventureInfo.name = this.actions[this.type].getInfo;
  9868. const data = await Send(JSON.stringify({
  9869. calls: [
  9870. this.callAdventureInfo,
  9871. this.callTeamGetAll,
  9872. this.callTeamGetFavor
  9873. ]
  9874. }));
  9875. return this.checkAdventureInfo(data.results);
  9876. }
  9877.  
  9878. async getPath() {
  9879. const oldVal = getSaveVal('adventurePath', '');
  9880. const keyPath = `adventurePath:${this.mapIdent}`;
  9881. const answer = await popup.confirm(I18N('ENTER_THE_PATH'), [
  9882. {
  9883. msg: I18N('START_ADVENTURE'),
  9884. placeholder: '1,2,3,4,5,6',
  9885. isInput: true,
  9886. default: getSaveVal(keyPath, oldVal)
  9887. },
  9888. {
  9889. msg: I18N('BTN_CANCEL'),
  9890. result: false,
  9891. isCancel: true
  9892. },
  9893. ]);
  9894. if (!answer) {
  9895. this.terminatеReason = I18N('BTN_CANCELED');
  9896. return false;
  9897. }
  9898.  
  9899. let path = answer.split(',');
  9900. if (path.length < 2) {
  9901. path = answer.split('-');
  9902. }
  9903. if (path.length < 2) {
  9904. this.terminatеReason = I18N('MUST_TWO_POINTS');
  9905. return false;
  9906. }
  9907.  
  9908. for (let p in path) {
  9909. path[p] = +path[p].trim()
  9910. if (Number.isNaN(path[p])) {
  9911. this.terminatеReason = I18N('MUST_ONLY_NUMBERS');
  9912. return false;
  9913. }
  9914. }
  9915.  
  9916. if (!this.checkPath(path)) {
  9917. return false;
  9918. }
  9919. setSaveVal(keyPath, answer);
  9920. return path;
  9921. }
  9922.  
  9923. checkPath(path) {
  9924. for (let i = 0; i < path.length - 1; i++) {
  9925. const currentPoint = path[i];
  9926. const nextPoint = path[i + 1];
  9927.  
  9928. const isValidPath = this.paths.some(p =>
  9929. (p.from_id === currentPoint && p.to_id === nextPoint) ||
  9930. (p.from_id === nextPoint && p.to_id === currentPoint)
  9931. );
  9932.  
  9933. if (!isValidPath) {
  9934. this.terminatеReason = I18N('INCORRECT_WAY', {
  9935. from: currentPoint,
  9936. to: nextPoint,
  9937. });
  9938. return false;
  9939. }
  9940. }
  9941.  
  9942. return true;
  9943. }
  9944.  
  9945. async checkAdventureInfo(data) {
  9946. this.advInfo = data[0].result.response;
  9947. if (!this.advInfo) {
  9948. this.terminatеReason = I18N('NOT_ON_AN_ADVENTURE') ;
  9949. return this.end();
  9950. }
  9951. const heroesTeam = data[1].result.response.adventure_hero;
  9952. const favor = data[2]?.result.response.adventure_hero;
  9953. const heroes = heroesTeam.slice(0, 5);
  9954. const pet = heroesTeam[5];
  9955. this.args = {
  9956. pet,
  9957. heroes,
  9958. favor,
  9959. path: [],
  9960. broadcast: false
  9961. }
  9962. const advUserInfo = this.advInfo.users[userInfo.id];
  9963. this.turnsLeft = advUserInfo.turnsLeft;
  9964. this.currentNode = advUserInfo.currentNode;
  9965. this.nodes = this.advInfo.nodes;
  9966. this.paths = this.advInfo.paths;
  9967. this.mapIdent = this.advInfo.mapIdent;
  9968.  
  9969. this.path = await this.getPath();
  9970. if (!this.path) {
  9971. return this.end();
  9972. }
  9973.  
  9974. if (this.currentNode == 1 && this.path[0] != 1) {
  9975. this.path.unshift(1);
  9976. }
  9977.  
  9978. return this.loop();
  9979. }
  9980.  
  9981. async loop() {
  9982. const position = this.path.indexOf(+this.currentNode);
  9983. if (!(~position)) {
  9984. this.terminatеReason = I18N('YOU_IN_NOT_ON_THE_WAY');
  9985. return this.end();
  9986. }
  9987. this.path = this.path.slice(position);
  9988. if ((this.path.length - 1) > this.turnsLeft &&
  9989. await popup.confirm(I18N('ATTEMPTS_NOT_ENOUGH'), [
  9990. { msg: I18N('YES_CONTINUE'), result: false },
  9991. { msg: I18N('BTN_NO'), result: true },
  9992. ])) {
  9993. this.terminatеReason = I18N('NOT_ENOUGH_AP');
  9994. return this.end();
  9995. }
  9996. const toPath = [];
  9997. for (const nodeId of this.path) {
  9998. if (!this.turnsLeft) {
  9999. this.terminatеReason = I18N('ATTEMPTS_ARE_OVER');
  10000. return this.end();
  10001. }
  10002. toPath.push(nodeId);
  10003. console.log(toPath);
  10004. if (toPath.length > 1) {
  10005. setProgress(toPath.join(' > ') + ` ${I18N('MOVES')}: ` + this.turnsLeft);
  10006. }
  10007. if (nodeId == this.currentNode) {
  10008. continue;
  10009. }
  10010.  
  10011. const nodeInfo = this.getNodeInfo(nodeId);
  10012. if (nodeInfo.type == 'TYPE_COMBAT') {
  10013. if (nodeInfo.state == 'empty') {
  10014. this.turnsLeft--;
  10015. continue;
  10016. }
  10017.  
  10018. /**
  10019. * Disable regular battle cancellation
  10020. *
  10021. * Отключаем штатную отменую боя
  10022. */
  10023. isCancalBattle = false;
  10024. if (await this.battle(toPath)) {
  10025. this.turnsLeft--;
  10026. toPath.splice(0, toPath.indexOf(nodeId));
  10027. nodeInfo.state = 'empty';
  10028. isCancalBattle = true;
  10029. continue;
  10030. }
  10031. isCancalBattle = true;
  10032. return this.end()
  10033. }
  10034.  
  10035. if (nodeInfo.type == 'TYPE_PLAYERBUFF') {
  10036. const buff = this.checkBuff(nodeInfo);
  10037. if (buff == null) {
  10038. continue;
  10039. }
  10040.  
  10041. if (await this.collectBuff(buff, toPath)) {
  10042. this.turnsLeft--;
  10043. toPath.splice(0, toPath.indexOf(nodeId));
  10044. continue;
  10045. }
  10046. this.terminatеReason = I18N('BUFF_GET_ERROR');
  10047. return this.end();
  10048. }
  10049. }
  10050. this.terminatеReason = I18N('SUCCESS');
  10051. return this.end();
  10052. }
  10053.  
  10054. /**
  10055. * Carrying out a fight
  10056. *
  10057. * Проведение боя
  10058. */
  10059. async battle(path, preCalc = true) {
  10060. const data = await this.startBattle(path);
  10061. try {
  10062. const battle = data.results[0].result.response.battle;
  10063. const result = await Calc(battle);
  10064. if (result.result.win) {
  10065. const info = await this.endBattle(result);
  10066. if (info.results[0].result.response?.error) {
  10067. this.terminatеReason = I18N('BATTLE_END_ERROR');
  10068. return false;
  10069. }
  10070. } else {
  10071. await this.cancelBattle(result);
  10072.  
  10073. if (preCalc && await this.preCalcBattle(battle)) {
  10074. path = path.slice(-2);
  10075. for (let i = 1; i <= getInput('countAutoBattle'); i++) {
  10076. setProgress(`${I18N('AUTOBOT')}: ${i}/${getInput('countAutoBattle')}`);
  10077. const result = await this.battle(path, false);
  10078. if (result) {
  10079. setProgress(I18N('VICTORY'));
  10080. return true;
  10081. }
  10082. }
  10083. this.terminatеReason = I18N('FAILED_TO_WIN_AUTO');
  10084. return false;
  10085. }
  10086. return false;
  10087. }
  10088. } catch (error) {
  10089. console.error(error);
  10090. if (await popup.confirm(I18N('ERROR_OF_THE_BATTLE_COPY'), [
  10091. { msg: I18N('BTN_NO'), result: false },
  10092. { msg: I18N('BTN_YES'), result: true },
  10093. ])) {
  10094. this.errorHandling(error, data);
  10095. }
  10096. this.terminatеReason = I18N('ERROR_DURING_THE_BATTLE');
  10097. return false;
  10098. }
  10099. return true;
  10100. }
  10101.  
  10102. /**
  10103. * Recalculate battles
  10104. *
  10105. * Прерасчтет битвы
  10106. */
  10107. async preCalcBattle(battle) {
  10108. const countTestBattle = getInput('countTestBattle');
  10109. for (let i = 0; i < countTestBattle; i++) {
  10110. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  10111. const result = await Calc(battle);
  10112. if (result.result.win) {
  10113. console.log(i, countTestBattle);
  10114. return true;
  10115. }
  10116. }
  10117. this.terminatеReason = I18N('NO_CHANCE_WIN') + countTestBattle;
  10118. return false;
  10119. }
  10120.  
  10121. /**
  10122. * Starts a fight
  10123. *
  10124. * Начинает бой
  10125. */
  10126. startBattle(path) {
  10127. this.args.path = path;
  10128. this.callStartBattle.name = this.actions[this.type].startBattle;
  10129. this.callStartBattle.args = this.args
  10130. const calls = [this.callStartBattle];
  10131. return Send(JSON.stringify({ calls }));
  10132. }
  10133.  
  10134. cancelBattle(battle) {
  10135. const fixBattle = function (heroes) {
  10136. for (const ids in heroes) {
  10137. const hero = heroes[ids];
  10138. hero.energy = random(1, 999);
  10139. if (hero.hp > 0) {
  10140. hero.hp = random(1, hero.hp);
  10141. }
  10142. }
  10143. }
  10144. fixBattle(battle.progress[0].attackers.heroes);
  10145. fixBattle(battle.progress[0].defenders.heroes);
  10146. return this.endBattle(battle);
  10147. }
  10148.  
  10149. /**
  10150. * Ends the fight
  10151. *
  10152. * Заканчивает бой
  10153. */
  10154. endBattle(battle) {
  10155. this.callEndBattle.name = this.actions[this.type].endBattle;
  10156. this.callEndBattle.args.result = battle.result
  10157. this.callEndBattle.args.progress = battle.progress
  10158. const calls = [this.callEndBattle];
  10159. return Send(JSON.stringify({ calls }));
  10160. }
  10161.  
  10162. /**
  10163. * Checks if you can get a buff
  10164. *
  10165. * Проверяет можно ли получить баф
  10166. */
  10167. checkBuff(nodeInfo) {
  10168. let id = null;
  10169. let value = 0;
  10170. for (const buffId in nodeInfo.buffs) {
  10171. const buff = nodeInfo.buffs[buffId];
  10172. if (buff.owner == null && buff.value > value) {
  10173. id = buffId;
  10174. value = buff.value;
  10175. }
  10176. }
  10177. nodeInfo.buffs[id].owner = 'Я';
  10178. return id;
  10179. }
  10180.  
  10181. /**
  10182. * Collects a buff
  10183. *
  10184. * Собирает баф
  10185. */
  10186. async collectBuff(buff, path) {
  10187. this.callCollectBuff.name = this.actions[this.type].collectBuff;
  10188. this.callCollectBuff.args = { buff, path };
  10189. const calls = [this.callCollectBuff];
  10190. return Send(JSON.stringify({ calls }));
  10191. }
  10192.  
  10193. getNodeInfo(nodeId) {
  10194. return this.nodes.find(node => node.id == nodeId);
  10195. }
  10196.  
  10197. errorHandling(error, data) {
  10198. //console.error(error);
  10199. let errorInfo = error.toString() + '\n';
  10200. try {
  10201. const errorStack = error.stack.split('\n');
  10202. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testAdventure");
  10203. errorInfo += errorStack.slice(0, endStack).join('\n');
  10204. } catch (e) {
  10205. errorInfo += error.stack;
  10206. }
  10207. if (data) {
  10208. errorInfo += '\nData: ' + JSON.stringify(data);
  10209. }
  10210. copyText(errorInfo);
  10211. }
  10212.  
  10213. end() {
  10214. isCancalBattle = true;
  10215. setProgress(this.terminatеReason, true);
  10216. console.log(this.terminatеReason);
  10217. this.resolve();
  10218. }
  10219. }
  10220.  
  10221. /**
  10222. * Passage of brawls
  10223. *
  10224. * Прохождение потасовок
  10225. */
  10226. function testBrawls(isAuto) {
  10227. return new Promise((resolve, reject) => {
  10228. const brawls = new executeBrawls(resolve, reject);
  10229. brawls.start(brawlsPack, isAuto);
  10230. });
  10231. }
  10232. /**
  10233. * Passage of brawls
  10234. *
  10235. * Прохождение потасовок
  10236. */
  10237. class executeBrawls {
  10238. callBrawlQuestGetInfo = {
  10239. name: "brawl_questGetInfo",
  10240. args: {},
  10241. ident: "brawl_questGetInfo"
  10242. }
  10243. callBrawlFindEnemies = {
  10244. name: "brawl_findEnemies",
  10245. args: {},
  10246. ident: "brawl_findEnemies"
  10247. }
  10248. callBrawlQuestFarm = {
  10249. name: "brawl_questFarm",
  10250. args: {},
  10251. ident: "brawl_questFarm"
  10252. }
  10253. callUserGetInfo = {
  10254. name: "userGetInfo",
  10255. args: {},
  10256. ident: "userGetInfo"
  10257. }
  10258. callTeamGetMaxUpgrade = {
  10259. name: "teamGetMaxUpgrade",
  10260. args: {},
  10261. ident: "teamGetMaxUpgrade"
  10262. }
  10263. callBrawlGetInfo = {
  10264. name: "brawl_getInfo",
  10265. args: {},
  10266. ident: "brawl_getInfo"
  10267. }
  10268.  
  10269. stats = {
  10270. win: 0,
  10271. loss: 0,
  10272. count: 0,
  10273. }
  10274.  
  10275. stage = {
  10276. '3': 1,
  10277. '7': 2,
  10278. '12': 3,
  10279. }
  10280.  
  10281. attempts = 0;
  10282.  
  10283. constructor(resolve, reject) {
  10284. this.resolve = resolve;
  10285. this.reject = reject;
  10286. }
  10287.  
  10288. async start(args, isAuto) {
  10289. this.isAuto = isAuto;
  10290. this.args = args;
  10291. isCancalBattle = false;
  10292. this.brawlInfo = await this.getBrawlInfo();
  10293. this.attempts = this.brawlInfo.attempts;
  10294.  
  10295. if (!this.attempts) {
  10296. this.end(I18N('DONT_HAVE_LIVES'))
  10297. return;
  10298. }
  10299.  
  10300. while (1) {
  10301. if (!isBrawlsAutoStart) {
  10302. this.end(I18N('BTN_CANCELED'));
  10303. return;
  10304. }
  10305.  
  10306. const maxStage = this.brawlInfo.questInfo.stage;
  10307. const stage = this.stage[maxStage];
  10308. const progress = this.brawlInfo.questInfo.progress;
  10309.  
  10310. setProgress(
  10311. `${I18N('STAGE')} ${stage}: ${progress}/${maxStage}<br>${I18N('FIGHTS')}: ${this.stats.count}<br>${I18N('WINS')}: ${
  10312. this.stats.win
  10313. }<br>${I18N('LOSSES')}: ${this.stats.loss}<br>${I18N('LIVES')}: ${this.attempts}<br>${I18N('STOP')}`,
  10314. false,
  10315. function () {
  10316. isBrawlsAutoStart = false;
  10317. }
  10318. );
  10319.  
  10320. if (this.brawlInfo.questInfo.canFarm) {
  10321. const result = await this.questFarm();
  10322. console.log(result);
  10323. }
  10324.  
  10325. if (this.brawlInfo.questInfo.stage == 12 && this.brawlInfo.questInfo.progress == 12) {
  10326. this.end(I18N('SUCCESS'));
  10327. return;
  10328. }
  10329.  
  10330. if (!this.attempts) {
  10331. this.end(I18N('DONT_HAVE_LIVES'));
  10332. return;
  10333. }
  10334.  
  10335. const enemie = Object.values(this.brawlInfo.findEnemies).shift();
  10336.  
  10337. // Автоматический подбор пачки
  10338. if (this.isAuto) {
  10339. this.args = await this.updatePack(enemie.heroes);
  10340. }
  10341.  
  10342. const result = await this.battle(enemie.userId);
  10343. this.brawlInfo = {
  10344. questInfo: result[1].result.response,
  10345. findEnemies: result[2].result.response,
  10346. };
  10347. }
  10348. }
  10349.  
  10350. async updatePack(enemieHeroes) {
  10351. const packs= [
  10352. {args:{favor:{9:6004,16:6e3,29:6002,42:6001,55:6005},heroes:[29,55,9,16,42],pet:6006},attackers:{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},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,6027:130},power:190778,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:6005,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:400015,intelligence:19438,physicalAttack:7020.32,strength:3286,armor:22935,armorPenetration:36870,magicPower:70661.6,magicResist:10010,skin:0,favorPetId:6005,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,6022:130,8271:1,8270: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},16:{id:"16",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{350:130,301:130,302:130,303:130,6002:130},power:191091,star:6,runes:[43750,43750,43750,43750,43750],skins:{16:60,58:60,177:60,192:60,258:60},currentSkin:192,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6e3,type:"hero",perks:[6,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:17007,hp:286172,intelligence:3196,physicalAttack:37367.32,strength:3207,armor:16985,armorPenetration:43317.6,dodge:14027,magicResist:6866,skin:192,favorPetId:6e3,favorPower:11064},42:{id:42,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{210:130,211:130,212:130,213:130,6007:130},power:189864,star:6,runes:[43750,43750,43750,43750,43750],skins:{91:60,115:60,121:60,195:60,307: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:2442,hp:617785,intelligence:3476,physicalAttack:50,strength:18155,armor:37797.6,magicPower:66606,magicResist:29975,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}}},{args:{favor:{1:6001,9:6004,16:6e3,29:6002,55:6005},heroes:[29,55,9,16,1],pet:6006},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},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},16:{id:"16",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{301:130,302:130,303:130,350:130,6002:130},power:191091,star:6,runes:[43750,43750,43750,43750,43750],skins:{16:60,58:60,177:60,192:60,258:60},currentSkin:192,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6e3,type:"hero",perks:[6,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:17007,hp:286172,intelligence:3196,physicalAttack:37367.32,strength:3207,armor:16985,armorPenetration:43317.6,dodge:14027,magicResist:6866,skin:192,favorPetId:6e3,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},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,6027:130},power:190778,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:6005,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:400015,intelligence:19438,physicalAttack:7020.32,strength:3286,armor:22935,armorPenetration:36870,magicPower:70661.6,magicResist:10010,skin:0,favorPetId:6005,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}}},{args:{favor:{9:6005,16:6004,35:6001,56:6006,62:6007},heroes:[62,35,9,56,16],pet:6006},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,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},16:{id:"16",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{301:130,302:130,303:130,350:130,6022:130},power:193730,star:6,runes:[43750,43750,43750,43750,43750],skins:{16:60,58:60,177:60,192:60,258:60},currentSkin:192,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[6,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:17007,hp:286172,intelligence:3196,physicalAttack:40354.6,strength:3207,armor:16985,armorPenetration:33360,dodge:17014.28,magicResist:6866,skin:192,favorPetId:6004,favorPower:11064},35:{id:35,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{175:130,176:130,177:130,178:130,6007:130},power:189498,star:6,runes:[43750,43750,43750,43750,43750],skins:{48:60,74:60,79:60,194:60,293: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:[8,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:2647,hp:524339,intelligence:3554,physicalAttack:50,strength:17676,armor:41168.6,magicPower:59842,magicResist:43058,skin:0,favorPetId:6001,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},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,6035: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:6007,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:22847.6,magicPenetration:23658,magicPower:80966.6,magicResist:2490,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}}},{args:{favor:{1:6004,9:6005,16:6e3,46:6001,62:6003},heroes:[46,62,9,16,1],pet:6008},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},16:{id:"16",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{301:130,302:130,303:130,350:130,6002:130},power:191091,star:6,runes:[43750,43750,43750,43750,43750],skins:{16:60,58:60,177:60,192:60,258:60},currentSkin:192,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6e3,type:"hero",perks:[6,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:17007,hp:286172,intelligence:3196,physicalAttack:37367.32,strength:3207,armor:16985,armorPenetration:43317.6,dodge:14027,magicResist:6866,skin:192,favorPetId:6e3,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,6007: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:6001,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:737093,intelligence:16208,physicalAttack:50,strength:5151,armor:38507.6,magicPower:64538,magicResist:22237,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},6008:{id:6008,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6036:130,6037:130},power:181943,type:"pet",perks:[5],name:null,armorPenetration:47911,intelligence:11064,strength:12360}}},{args:{favor:{9:6005,13:6002,16:6004,31:6006},heroes:[31,13,9,40,16],pet:6008},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,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:{62:130,63:130,64:130,65:130,6012:130},power:194793,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,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:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:19060,magicPenetration:58138.6,magicPower:70100.6,magicResist:27227,skin:0,favorPetId:6002,favorPower:11064},16:{id:"16",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{301:130,302:130,303:130,350:130,6022:130},power:193730,star:6,runes:[43750,43750,43750,43750,43750],skins:{16:60,58:60,177:60,192:60,258:60},currentSkin:192,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[6,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:17007,hp:286172,intelligence:3196,physicalAttack:40354.6,strength:3207,armor:16985,armorPenetration:33360,dodge:17014.28,magicResist:6866,skin:192,favorPetId:6004,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,8244:1,8245:1},power:177096,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:0,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:38473,strength:2976,armor:24410,dodge:12745,magicResist:17633,modifiedSkillTier:3,skin:0,favorPetId:0,favorPower:0},6008:{id:6008,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6036:130,6037:130},power:181943,type:"pet",perks:[5],name:null,armorPenetration:47911,intelligence:11064,strength:12360}}},{args:{favor:{12:6003,16:6e3,31:6006,40:6004,48:6001},heroes:[31,48,40,16,12],pet:6006},attackers:{12:{id:12,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{346:130,347:130,348:130,349:130,6017:130},power:190108,star:6,runes:[43750,43750,43750,43750,43750],skins:{12:60,37:60,87:60,157:60,207: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,10,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:17241,hp:359857,intelligence:3432,physicalAttack:17632,strength:2887,armor:25126,lifesteal:80,magicPenetration:19650,magicPower:60919.6,magicResist:29092.6,skin:0,favorPetId:6003,favorPower:11064},16:{id:"16",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{301:130,302:130,303:130,350:130,6002:130},power:191091,star:6,runes:[43750,43750,43750,43750,43750],skins:{16:60,58:60,177:60,192:60,258:60},currentSkin:192,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6e3,type:"hero",perks:[6,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:17007,hp:286172,intelligence:3196,physicalAttack:37367.32,strength:3207,armor:16985,armorPenetration:43317.6,dodge:14027,magicResist:6866,skin:192,favorPetId:6e3,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},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,6007:130},power:190335,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:6001,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:497313,intelligence:2888,physicalAttack:33328,physicalCritChance:12280,strength:3169,armor:22142.6,armorPenetration:10180,magicResist:24816,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}}},{args:{favor:{1:6004,12:6003,16:6e3,51:6001,56:6006},heroes:[56,51,16,12,1],pet:6006},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},12:{id:12,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{346:130,347:130,348:130,349:130,6017:130},power:190108,star:6,runes:[43750,43750,43750,43750,43750],skins:{12:60,37:60,87:60,157:60,207: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,10,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:17241,hp:359857,intelligence:3432,physicalAttack:17632,strength:2887,armor:25126,lifesteal:80,magicPenetration:19650,magicPower:60919.6,magicResist:29092.6,skin:0,favorPetId:6003,favorPower:11064},16:{id:"16",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{301:130,302:130,303:130,350:130,6002:130},power:191091,star:6,runes:[43750,43750,43750,43750,43750],skins:{16:60,58:60,177:60,192:60,258:60},currentSkin:192,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6e3,type:"hero",perks:[6,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:17007,hp:286172,intelligence:3196,physicalAttack:37367.32,strength:3207,armor:16985,armorPenetration:43317.6,dodge:14027,magicResist:6866,skin:192,favorPetId:6e3,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,6007: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:6001,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:537781,intelligence:18851,physicalAttack:50,strength:2921,armor:39442.6,magicPower:79021,magicResist:22960,skin:0,favorPetId:6001,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},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}}},{args:{favor:{9:6004,16:6e3,46:6001,48:6005,63:6003},heroes:[46,63,9,48,16],pet:6006},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},16:{id:"16",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{301:130,302:130,303:130,350:130,6002:130},power:191091,star:6,runes:[43750,43750,43750,43750,43750],skins:{16:60,58:60,177:60,192:60,258:60},currentSkin:192,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6e3,type:"hero",perks:[6,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:17007,hp:286172,intelligence:3196,physicalAttack:37367.32,strength:3207,armor:16985,armorPenetration:43317.6,dodge:14027,magicResist:6866,skin:192,favorPetId:6e3,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,6007: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:6001,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:737093,intelligence:16208,physicalAttack:50,strength:5151,armor:38507.6,magicPower:64538,magicResist:22237,skin:0,favorPetId:6001,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,6027: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:6005,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:10180,magicPower:9957.6,magicResist:24816,skin:0,favorPetId:6005,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}}},{args:{favor:{16:6e3,48:6001,51:6006,55:6007,63:6009},heroes:[55,63,48,51,16],pet:6006},attackers:{16:{id:"16",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{301:130,302:130,303:130,350:130,6002:130},power:191091,star:6,runes:[43750,43750,43750,43750,43750],skins:{16:60,58:60,177:60,192:60,258:60},currentSkin:192,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6e3,type:"hero",perks:[6,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:17007,hp:286172,intelligence:3196,physicalAttack:37367.32,strength:3207,armor:16985,armorPenetration:43317.6,dodge:14027,magicResist:6866,skin:192,favorPetId:6e3,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,6007:130},power:190335,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:6001,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:497313,intelligence:2888,physicalAttack:33328,physicalCritChance:12280,strength:3169,armor:22142.6,armorPenetration:10180,magicResist:24816,skin:0,favorPetId:6001,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,6035: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:6007,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:400015,intelligence:19438,physicalAttack:50,strength:3286,armor:32892.6,armorPenetration:36870,magicPower:70661.6,magicResist:10010,skin:0,favorPetId:6007,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}}},{args:{favor:{16:6004,31:6001,32:6002,55:6005},heroes:[32,31,55,40,16],pet:6006},attackers:{16:{id:"16",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{301:130,302:130,303:130,350:130,6022:130},power:193730,star:6,runes:[43750,43750,43750,43750,43750],skins:{16:60,58:60,177:60,192:60,258:60},currentSkin:192,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[6,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:17007,hp:286172,intelligence:3196,physicalAttack:40354.6,strength:3207,armor:16985,armorPenetration:33360,dodge:17014.28,magicResist:6866,skin:192,favorPetId:6004,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,6007: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:6001,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:474060,intelligence:18945,physicalAttack:78,strength:2916,armor:28049.6,magicPower:57729,magicResist:15252,skin:0,favorPetId:6001,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},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,8244:1,8245:1},power:177096,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:0,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:38473,strength:2976,armor:24410,dodge:12745,magicResist:17633,modifiedSkillTier:3,skin:0,favorPetId:0,favorPower:0},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,6027:130},power:190778,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:6005,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:400015,intelligence:19438,physicalAttack:7020.32,strength:3286,armor:22935,armorPenetration:36870,magicPower:70661.6,magicResist:10010,skin:0,favorPetId:6005,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}}}
  10353. ];
  10354.  
  10355. const bestPack = {
  10356. pack: packs[0],
  10357. countWin: 0,
  10358. }
  10359.  
  10360. for (const pack of packs) {
  10361. /*
  10362. const attackers = this.maxUpgrade
  10363. .filter(e => pack.includes(e.id))
  10364. .reduce((obj, e) => ({ ...obj, [e.id]: e }), {});
  10365. */
  10366. const attackers = pack.attackers;
  10367. const battle = {
  10368. attackers,
  10369. defenders: [enemieHeroes],
  10370. type: 'brawl',
  10371. };
  10372.  
  10373. let countWinBattles = 0;
  10374. let countTestBattle = 10;
  10375. for (let i = 0; i < countTestBattle; i++) {
  10376. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  10377. const result = await Calc(battle);
  10378. if (result.result.win) {
  10379. countWinBattles++;
  10380. }
  10381. if (countWinBattles > 7) {
  10382. console.log(pack)
  10383. return pack.args;
  10384. }
  10385. }
  10386. if (countWinBattles > bestPack.countWin) {
  10387. bestPack.countWin = countWinBattles;
  10388. bestPack.pack = pack.args;
  10389. }
  10390. }
  10391.  
  10392. console.log(bestPack);
  10393. return bestPack.pack;
  10394. }
  10395.  
  10396. async questFarm() {
  10397. const calls = [this.callBrawlQuestFarm];
  10398. const result = await Send(JSON.stringify({ calls }));
  10399. return result.results[0].result.response;
  10400. }
  10401.  
  10402. async getBrawlInfo() {
  10403. const data = await Send(JSON.stringify({
  10404. calls: [
  10405. this.callUserGetInfo,
  10406. this.callBrawlQuestGetInfo,
  10407. this.callBrawlFindEnemies,
  10408. this.callTeamGetMaxUpgrade,
  10409. this.callBrawlGetInfo,
  10410. ]
  10411. }));
  10412.  
  10413. let attempts = data.results[0].result.response.refillable.find(n => n.id == 48);
  10414.  
  10415. const maxUpgrade = data.results[3].result.response;
  10416. const maxHero = Object.values(maxUpgrade.hero);
  10417. const maxTitan = Object.values(maxUpgrade.titan);
  10418. const maxPet = Object.values(maxUpgrade.pet);
  10419. this.maxUpgrade = [...maxHero, ...maxPet];
  10420.  
  10421. this.info = data.results[4].result.response;
  10422. this.mandatoryId = lib.data.brawl.promoHero[this.info.id].promoHero;
  10423. return {
  10424. attempts: attempts.amount,
  10425. questInfo: data.results[1].result.response,
  10426. findEnemies: data.results[2].result.response,
  10427. }
  10428. }
  10429.  
  10430. /**
  10431. * Carrying out a fight
  10432. *
  10433. * Проведение боя
  10434. */
  10435. async battle(userId) {
  10436. this.stats.count++;
  10437. const battle = await this.startBattle(userId, this.args);
  10438. const result = await Calc(battle);
  10439. console.log(result.result);
  10440. if (result.result.win) {
  10441. this.stats.win++;
  10442. } else {
  10443. this.stats.loss++;
  10444. this.attempts--;
  10445. }
  10446. return await this.endBattle(result);
  10447. // return await this.cancelBattle(result);
  10448. }
  10449.  
  10450. /**
  10451. * Starts a fight
  10452. *
  10453. * Начинает бой
  10454. */
  10455. async startBattle(userId, args) {
  10456. const call = {
  10457. name: "brawl_startBattle",
  10458. args,
  10459. ident: "brawl_startBattle"
  10460. }
  10461. call.args.userId = userId;
  10462. const calls = [call];
  10463. const result = await Send(JSON.stringify({ calls }));
  10464. return result.results[0].result.response;
  10465. }
  10466.  
  10467. cancelBattle(battle) {
  10468. const fixBattle = function (heroes) {
  10469. for (const ids in heroes) {
  10470. const hero = heroes[ids];
  10471. hero.energy = random(1, 999);
  10472. if (hero.hp > 0) {
  10473. hero.hp = random(1, hero.hp);
  10474. }
  10475. }
  10476. }
  10477. fixBattle(battle.progress[0].attackers.heroes);
  10478. fixBattle(battle.progress[0].defenders.heroes);
  10479. return this.endBattle(battle);
  10480. }
  10481.  
  10482. /**
  10483. * Ends the fight
  10484. *
  10485. * Заканчивает бой
  10486. */
  10487. async endBattle(battle) {
  10488. battle.progress[0].attackers.input = ['auto', 0, 0, 'auto', 0, 0];
  10489. const calls = [{
  10490. name: "brawl_endBattle",
  10491. args: {
  10492. result: battle.result,
  10493. progress: battle.progress
  10494. },
  10495. ident: "brawl_endBattle"
  10496. },
  10497. this.callBrawlQuestGetInfo,
  10498. this.callBrawlFindEnemies,
  10499. ];
  10500. const result = await Send(JSON.stringify({ calls }));
  10501. return result.results;
  10502. }
  10503.  
  10504. end(endReason) {
  10505. isCancalBattle = true;
  10506. isBrawlsAutoStart = false;
  10507. setProgress(endReason, true);
  10508. console.log(endReason);
  10509. this.resolve();
  10510. }
  10511. }
  10512.  
  10513. })();
  10514.  
  10515. /**
  10516. * TODO:
  10517. * Получение всех уровней при сборе всех наград (квест на титанит и на энку) +-
  10518. * Добивание на арене титанов
  10519. * Закрытие окошек по Esc +-
  10520. * Починить работу скрипта на уровне команды ниже 10 +-
  10521. * Написать номальную синхронизацию
  10522. * Добавить дополнительные настройки автопокупки в "Тайном богатстве"
  10523. */