HeroWarsDungeon

Automation of actions for the game Hero Wars

目前为 2024-10-18 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name HeroWarsDungeon
  3. // @name:en HeroWarsDungeon
  4. // @name:ru HeroWarsDungeon
  5. // @namespace HeroWarsDungeon
  6. // @version 2.292
  7. // @description Automation of actions for the game Hero Wars
  8. // @description:en Automation of actions for the game Hero Wars
  9. // @description:ru Автоматизация действий для игры Хроники Хаоса
  10. // @author ZingerY, ApuoH, Gudwin
  11. // @license Copyright ZingerY
  12. // @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. // сделал ApuoH
  21. (function() {
  22. /**
  23. * Start script
  24. *
  25. * Стартуем скрипт
  26. */
  27. console.log('%cStart ' + GM_info.script.name + ', v' + GM_info.script.version + ' by ' + GM_info.script.author, 'color: red');
  28. /**
  29. * Script info
  30. *
  31. * Информация о скрипте
  32. */
  33. this.scriptInfo = (({name, version, author, homepage, lastModified}, updateUrl) =>
  34. ({name, version, author, homepage, lastModified, updateUrl}))
  35. (GM_info.script, GM_info.scriptUpdateURL);
  36. this.GM_info = GM_info;
  37. /**
  38. * Information for completing daily quests
  39. *
  40. * Информация для выполнения ежендевных квестов
  41. */
  42. const questsInfo = {};
  43. /**
  44. * Is the game data loaded
  45. *
  46. * Загружены ли данные игры
  47. */
  48. let isLoadGame = false;
  49. /**
  50. * Headers of the last request
  51. *
  52. * Заголовки последнего запроса
  53. */
  54. let lastHeaders = {};
  55. /**
  56. * Information about sent gifts
  57. *
  58. * Информация об отправленных подарках
  59. */
  60. let freebieCheckInfo = null;
  61. /**
  62. * missionTimer
  63. *
  64. * missionTimer
  65. */
  66. let missionBattle = null;
  67. /** Пачки для тестов в чате*/ //тест сохранка
  68. let repleyBattle = {
  69. defenders: {},
  70. attackers: {},
  71. effects: {},
  72. state: {},
  73. seed: undefined
  74. }
  75. /**
  76. * User data
  77. *
  78. * Данные пользователя
  79. */
  80. let userInfo;
  81. /**
  82. * Original methods for working with AJAX
  83. *
  84. * Оригинальные методы для работы с AJAX
  85. */
  86. const original = {
  87. open: XMLHttpRequest.prototype.open,
  88. send: XMLHttpRequest.prototype.send,
  89. setRequestHeader: XMLHttpRequest.prototype.setRequestHeader,
  90. SendWebSocket: WebSocket.prototype.send,
  91. };
  92. /**
  93. * Decoder for converting byte data to JSON string
  94. *
  95. * Декодер для перобразования байтовых данных в JSON строку
  96. */
  97. const decoder = new TextDecoder("utf-8");
  98. /**
  99. * Stores a history of requests
  100. *
  101. * Хранит историю запросов
  102. */
  103. let requestHistory = {};
  104. /**
  105. * URL for API requests
  106. *
  107. * URL для запросов к API
  108. */
  109. let apiUrl = '';
  110.  
  111. /**
  112. * Connecting to the game code
  113. *
  114. * Подключение к коду игры
  115. */
  116. this.cheats = new hackGame();
  117. /**
  118. * The function of calculating the results of the battle
  119. *
  120. * Функция расчета результатов боя
  121. */
  122. this.BattleCalc = cheats.BattleCalc;
  123. /**
  124. * Sending a request available through the console
  125. *
  126. * Отправка запроса доступная через консоль
  127. */
  128. this.SendRequest = send;
  129. /**
  130. * Simple combat calculation available through the console
  131. *
  132. * Простой расчет боя доступный через консоль
  133. */
  134. this.Calc = function (data) {
  135. const type = getBattleType(data?.type);
  136. return new Promise((resolve, reject) => {
  137. try {
  138. BattleCalc(data, type, resolve);
  139. } catch (e) {
  140. reject(e);
  141. }
  142. })
  143. }
  144. //тест остановка подземки
  145. let stopDung = false;
  146. /**
  147. * Short asynchronous request
  148. * Usage example (returns information about a character):
  149. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  150. *
  151. * Короткий асинхронный запрос
  152. * Пример использования (возвращает информацию о персонаже):
  153. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  154. */
  155. this.Send = function (json, pr) {
  156. return new Promise((resolve, reject) => {
  157. try {
  158. send(json, resolve, pr);
  159. } catch (e) {
  160. reject(e);
  161. }
  162. })
  163. }
  164.  
  165. this.xyz = (({ name, version, author }) => ({ name, version, author }))(GM_info.script);
  166. const i18nLangData = {
  167. /* English translation by BaBa */
  168. en: {
  169. /* Checkboxes */
  170. SKIP_FIGHTS: 'Skip battle',
  171. SKIP_FIGHTS_TITLE: 'Skip battle in Outland and the arena of the titans, auto-pass in the tower and campaign',
  172. ENDLESS_CARDS: 'Infinite cards',
  173. ENDLESS_CARDS_TITLE: 'Disable Divination Cards wasting',
  174. AUTO_EXPEDITION: 'Auto Expedition',
  175. AUTO_EXPEDITION_TITLE: 'Auto-sending expeditions',
  176. CANCEL_FIGHT: 'Cancel battle',
  177. CANCEL_FIGHT_TITLE: 'Ability to cancel manual combat on GW, CoW and Asgard',
  178. GIFTS: 'Gifts',
  179. GIFTS_TITLE: 'Collect gifts automatically',
  180. BATTLE_RECALCULATION: 'Battle recalculation',
  181. BATTLE_RECALCULATION_TITLE: 'Preliminary calculation of the battle',
  182. BATTLE_FISHING: 'Finishing',
  183. BATTLE_FISHING_TITLE: 'Finishing off the team from the last replay in the chat',
  184. BATTLE_TRENING: 'Workout',
  185. BATTLE_TRENING_TITLE: 'A training battle in the chat against the team from the last replay',
  186. QUANTITY_CONTROL: 'Quantity control',
  187. QUANTITY_CONTROL_TITLE: 'Ability to specify the number of opened "lootboxes"',
  188. REPEAT_CAMPAIGN: 'Repeat missions',
  189. REPEAT_CAMPAIGN_TITLE: 'Auto-repeat battles in the campaign',
  190. DISABLE_DONAT: 'Disable donation',
  191. DISABLE_DONAT_TITLE: 'Removes all donation offers',
  192. DAILY_QUESTS: 'Quests',
  193. DAILY_QUESTS_TITLE: 'Complete daily quests',
  194. AUTO_QUIZ: 'AutoQuiz',
  195. AUTO_QUIZ_TITLE: 'Automatically receive correct answers to quiz questions',
  196. SECRET_WEALTH_CHECKBOX: 'Automatic purchase in the store "Secret Wealth" when entering the game',
  197. HIDE_SERVERS: 'Collapse servers',
  198. HIDE_SERVERS_TITLE: 'Hide unused servers',
  199. /* Input fields */
  200. HOW_MUCH_TITANITE: 'How much titanite to farm',
  201. COMBAT_SPEED: 'Combat Speed Multiplier',
  202. HOW_REPEAT_CAMPAIGN: 'how many mission replays', //тест добавил
  203. NUMBER_OF_TEST: 'Number of test fights',
  204. NUMBER_OF_AUTO_BATTLE: 'Number of auto-battle attempts',
  205. USER_ID_TITLE: 'Enter the player ID',
  206. AMOUNT: 'Gift number, 1 - hero development, 2 - pets, 3 - light, 4 - darkness, 5 - ascension, 6 - appearance',
  207. GIFT_NUM: 'Number of gifts to be sent',
  208. /* Buttons */
  209. RUN_SCRIPT: 'Run the',
  210. STOP_SCRIPT: 'Stop the',
  211. TO_DO_EVERYTHING: 'Do All',
  212. TO_DO_EVERYTHING_TITLE: 'Perform multiple actions of your choice',
  213. OUTLAND: 'Outland',
  214. OUTLAND_TITLE: 'Collect Outland',
  215. TITAN_ARENA: 'ToE',
  216. TITAN_ARENA_TITLE: 'Complete the titan arena',
  217. DUNGEON: 'Dungeon',
  218. DUNGEON_TITLE: 'Go through the dungeon',
  219. DUNGEON2: 'Dungeon full',
  220. DUNGEON_FULL_TITLE: 'Dungeon for Full Titans',
  221. STOP_DUNGEON: 'Stop Dungeon',
  222. STOP_DUNGEON_TITLE: 'Stop digging the dungeon',
  223. SEER: 'Seer',
  224. SEER_TITLE: 'Roll the Seer',
  225. TOWER: 'Tower',
  226. TOWER_TITLE: 'Pass the tower',
  227. EXPEDITIONS: 'Expeditions',
  228. EXPEDITIONS_TITLE: 'Sending and collecting expeditions',
  229. SYNC: 'Sync',
  230. SYNC_TITLE: 'Partial synchronization of game data without reloading the page',
  231. ARCHDEMON: 'Archdemon',
  232. ARCHDEMON_TITLE: 'Hitting kills and collecting rewards',
  233. CRUCIBLE_SOULS: 'Crucible',
  234. CRUCIBLE_SOULS_TITLE: 'Fill the kilos in the crucible of souls',
  235. ESTER_EGGS: 'Easter eggs',
  236. ESTER_EGGS_TITLE: 'Collect all Easter eggs or rewards',
  237. REWARDS: 'Rewards',
  238. REWARDS_TITLE: 'Collect all quest rewards',
  239. MAIL: 'Mail',
  240. MAIL_TITLE: 'Collect all mail, except letters with energy and charges of the portal',
  241. MINIONS: 'Minions',
  242. MINIONS_TITLE: 'Attack minions with saved packs',
  243. ADVENTURE: 'Adventure',
  244. ADVENTURE_TITLE: 'Passes the adventure along the specified route',
  245. STORM: 'Storm',
  246. STORM_TITLE: 'Passes the Storm along the specified route',
  247. SANCTUARY: 'Sanctuary',
  248. SANCTUARY_TITLE: 'Fast travel to Sanctuary',
  249. GUILD_WAR: 'Guild War',
  250. GUILD_WAR_TITLE: 'Fast travel to Guild War',
  251. SECRET_WEALTH: 'Secret Wealth',
  252. SECRET_WEALTH_TITLE: 'Buy something in the store "Secret Wealth"',
  253. /* Misc */
  254. BOTTOM_URLS: '<a href="https://t.me/+0oMwICyV1aQ1MDAy" target="_blank" title="Telegram"><svg width="20" height="20" style="margin:2px" viewBox="0 0 1e3 1e3" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="a" x1="50%" x2="50%" y2="99.258%"><stop stop-color="#2AABEE" offset="0"/><stop stop-color="#229ED9" offset="1"/></linearGradient></defs><g fill-rule="evenodd"><circle cx="500" cy="500" r="500" fill="url(#a)"/><path d="m226.33 494.72c145.76-63.505 242.96-105.37 291.59-125.6 138.86-57.755 167.71-67.787 186.51-68.119 4.1362-0.072862 13.384 0.95221 19.375 5.8132 5.0584 4.1045 6.4501 9.6491 7.1161 13.541 0.666 3.8915 1.4953 12.756 0.83608 19.683-7.5246 79.062-40.084 270.92-56.648 359.47-7.0089 37.469-20.81 50.032-34.17 51.262-29.036 2.6719-51.085-19.189-79.207-37.624-44.007-28.847-68.867-46.804-111.58-74.953-49.366-32.531-17.364-50.411 10.769-79.631 7.3626-7.6471 135.3-124.01 137.77-134.57 0.30968-1.3202 0.59708-6.2414-2.3265-8.8399s-7.2385-1.7099-10.352-1.0032c-4.4137 1.0017-74.715 47.468-210.9 139.4-19.955 13.702-38.029 20.379-54.223 20.029-17.853-0.3857-52.194-10.094-77.723-18.393-31.313-10.178-56.199-15.56-54.032-32.846 1.1287-9.0037 13.528-18.212 37.197-27.624z" fill="#fff"/></g></svg></a><a href="https://www.patreon.com/HeroWarsUserScripts" target="_blank" title="Patreon"><svg width="20" height="20" viewBox="0 0 1080 1080" xmlns="http://www.w3.org/2000/svg"><g fill="#FFF" stroke="None"><path d="m1033 324.45c-0.19-137.9-107.59-250.92-233.6-291.7-156.48-50.64-362.86-43.3-512.28 27.2-181.1 85.46-237.99 272.66-240.11 459.36-1.74 153.5 13.58 557.79 241.62 560.67 169.44 2.15 194.67-216.18 273.07-321.33 55.78-74.81 127.6-95.94 216.01-117.82 151.95-37.61 255.51-157.53 255.29-316.38z"/></g></svg></a>',
  255. GIFTS_SENT: 'Gifts sent!',
  256. DO_YOU_WANT: 'Do you really want to do this?',
  257. BTN_RUN: 'Run',
  258. BTN_CANCEL: 'Cancel',
  259. BTN_OK: 'OK',
  260. MSG_HAVE_BEEN_DEFEATED: 'You have been defeated!',
  261. BTN_AUTO: 'Auto',
  262. MSG_YOU_APPLIED: 'You applied',
  263. MSG_DAMAGE: 'damage',
  264. MSG_CANCEL_AND_STAT: 'Auto (F5) and show statistic',
  265. MSG_REPEAT_MISSION: 'Repeat the mission?',
  266. BTN_REPEAT: 'Repeat',
  267. BTN_NO: 'No',
  268. MSG_SPECIFY_QUANT: 'Specify Quantity:',
  269. BTN_OPEN: 'Open',
  270. QUESTION_COPY: 'Question copied to clipboard',
  271. ANSWER_KNOWN: 'The answer is known',
  272. ANSWER_NOT_KNOWN: 'ATTENTION THE ANSWER IS NOT KNOWN',
  273. BEING_RECALC: 'The battle is being recalculated',
  274. THIS_TIME: 'This time',
  275. VICTORY: '<span style="color:green;">VICTORY</span>',
  276. DEFEAT: '<span style="color:red;">DEFEAT</span>',
  277. CHANCE_TO_WIN: 'Chance to win <span style="color: red;">based on pre-calculation</span>',
  278. OPEN_DOLLS: 'nesting dolls recursively',
  279. SENT_QUESTION: 'Question sent',
  280. SETTINGS: 'Settings',
  281. MSG_BAN_ATTENTION: '<p style="color:red;">Using this feature may result in a ban.</p> Continue?',
  282. BTN_YES_I_AGREE: 'Yes, I understand the risks!',
  283. BTN_NO_I_AM_AGAINST: 'No, I refuse it!',
  284. VALUES: 'Values',
  285. SAVING: 'Saving',
  286. USER_ID: 'User Id',
  287. SEND_GIFT: 'The gift has been sent',
  288. EXPEDITIONS_SENT: 'Expeditions:<br>Collected: {countGet}<br>Sent: {countSend}',
  289. EXPEDITIONS_NOTHING: 'Nothing to collect/send',
  290. TITANIT: 'Titanit',
  291. COMPLETED: 'completed',
  292. FLOOR: 'Floor',
  293. LEVEL: 'Level',
  294. BATTLES: 'battles',
  295. EVENT: 'Event',
  296. NOT_AVAILABLE: 'not available',
  297. NO_HEROES: 'No heroes',
  298. DAMAGE_AMOUNT: 'Damage amount',
  299. NOTHING_TO_COLLECT: 'Nothing to collect',
  300. COLLECTED: 'Collected',
  301. REWARD: 'rewards',
  302. REMAINING_ATTEMPTS: 'Remaining attempts',
  303. BATTLES_CANCELED: 'Battles canceled',
  304. MINION_RAID: 'Minion Raid',
  305. STOPPED: 'Stopped',
  306. REPETITIONS: 'Repetitions',
  307. MISSIONS_PASSED: 'Missions passed',
  308. STOP: 'stop',
  309. TOTAL_OPEN: 'Total open',
  310. OPEN: 'Open',
  311. ROUND_STAT: 'Damage statistics for ',
  312. BATTLE: 'battles',
  313. MINIMUM: 'Minimum',
  314. MAXIMUM: 'Maximum',
  315. AVERAGE: 'Average',
  316. NOT_THIS_TIME: 'Not this time',
  317. RETRY_LIMIT_EXCEEDED: 'Retry limit exceeded',
  318. SUCCESS: 'Success',
  319. RECEIVED: 'Received',
  320. LETTERS: 'letters',
  321. PORTALS: 'portals',
  322. ATTEMPTS: 'attempts',
  323. /* Quests */
  324. QUEST_10001: 'Upgrade the skills of heroes 3 times',
  325. QUEST_10002: 'Complete 10 missions',
  326. QUEST_10003: 'Complete 3 heroic missions',
  327. QUEST_10004: 'Fight 3 times in the Arena or Grand Arena',
  328. QUEST_10006: 'Use the exchange of emeralds 1 time',
  329. QUEST_10007: 'Perform 1 summon in the Solu Atrium',
  330. QUEST_10016: 'Send gifts to guildmates',
  331. QUEST_10018: 'Use an experience potion',
  332. QUEST_10019: 'Open 1 chest in the Tower',
  333. QUEST_10020: 'Open 3 chests in Outland',
  334. QUEST_10021: 'Collect 75 Titanite in the Guild Dungeon',
  335. QUEST_10021: 'Collect 150 Titanite in the Guild Dungeon',
  336. QUEST_10023: 'Upgrade Gift of the Elements by 1 level',
  337. QUEST_10024: 'Level up any artifact once',
  338. QUEST_10025: 'Start Expedition 1',
  339. QUEST_10026: 'Start 4 Expeditions',
  340. QUEST_10027: 'Win 1 battle of the Tournament of Elements',
  341. QUEST_10028: 'Level up any titan artifact',
  342. QUEST_10029: 'Unlock the Orb of Titan Artifacts',
  343. QUEST_10030: 'Upgrade any Skin of any hero 1 time',
  344. QUEST_10031: 'Win 6 battles of the Tournament of Elements',
  345. QUEST_10043: 'Start or Join an Adventure',
  346. QUEST_10044: 'Use Summon Pets 1 time',
  347. QUEST_10046: 'Open 3 chests in Adventure',
  348. QUEST_10047: 'Get 150 Guild Activity Points',
  349. NOTHING_TO_DO: 'Nothing to do',
  350. YOU_CAN_COMPLETE: 'You can complete quests',
  351. BTN_DO_IT: 'Do it',
  352. NOT_QUEST_COMPLETED: 'Not a single quest completed',
  353. COMPLETED_QUESTS: 'Completed quests',
  354. /* everything button */
  355. ASSEMBLE_OUTLAND: 'Assemble Outland',
  356. PASS_THE_TOWER: 'Pass the tower',
  357. CHECK_EXPEDITIONS: 'Check Expeditions',
  358. COMPLETE_TOE: 'Complete ToE',
  359. COMPLETE_DUNGEON: 'Complete the dungeon',
  360. COMPLETE_DUNGEON_FULL: 'Complete the dungeon for Full Titans',
  361. COLLECT_MAIL: 'Collect mail',
  362. COLLECT_MISC: 'Collect some bullshit',
  363. COLLECT_MISC_TITLE: 'Collect Easter Eggs, Skin Gems, Keys, Arena Coins and Soul Crystal',
  364. COLLECT_QUEST_REWARDS: 'Collect quest rewards',
  365. MAKE_A_SYNC: 'Make a sync',
  366.  
  367. RUN_FUNCTION: 'Run the following functions?',
  368. BTN_GO: 'Go!',
  369. PERFORMED: 'Performed',
  370. DONE: 'Done',
  371. ERRORS_OCCURRES: 'Errors occurred while executing',
  372. COPY_ERROR: 'Copy error information to clipboard',
  373. BTN_YES: 'Yes',
  374. ALL_TASK_COMPLETED: 'All tasks completed',
  375.  
  376. UNKNOWN: 'unknown',
  377. ENTER_THE_PATH: 'Enter the path of adventure using commas or dashes',
  378. START_ADVENTURE: 'Start your adventure along this path!',
  379. INCORRECT_WAY: 'Incorrect path in adventure: {from} -> {to}',
  380. BTN_CANCELED: 'Canceled',
  381. MUST_TWO_POINTS: 'The path must contain at least 2 points.',
  382. MUST_ONLY_NUMBERS: 'The path must contain only numbers and commas',
  383. NOT_ON_AN_ADVENTURE: 'You are not on an adventure',
  384. YOU_IN_NOT_ON_THE_WAY: 'Your location is not on the way',
  385. ATTEMPTS_NOT_ENOUGH: 'Your attempts are not enough to complete the path, continue?',
  386. YES_CONTINUE: 'Yes, continue!',
  387. NOT_ENOUGH_AP: 'Not enough action points',
  388. ATTEMPTS_ARE_OVER: 'The attempts are over',
  389. MOVES: 'Moves',
  390. BUFF_GET_ERROR: 'Buff getting error',
  391. BATTLE_END_ERROR: 'Battle end error',
  392. AUTOBOT: 'Autobot',
  393. FAILED_TO_WIN_AUTO: 'Failed to win the auto battle',
  394. ERROR_OF_THE_BATTLE_COPY: 'An error occurred during the passage of the battle<br>Copy the error to the clipboard?',
  395. ERROR_DURING_THE_BATTLE: 'Error during the battle',
  396. NO_CHANCE_WIN: 'No chance of winning this fight: 0/',
  397. LOST_HEROES: 'You have won, but you have lost one or several heroes',
  398. VICTORY_IMPOSSIBLE: 'Is victory impossible, should we focus on the result?',
  399. FIND_COEFF: 'Find the coefficient greater than',
  400. BTN_PASS: 'PASS',
  401. BRAWLS: 'Brawls',
  402. BRAWLS_TITLE: 'Activates the ability to auto-brawl',
  403. START_AUTO_BRAWLS: 'Start Auto Brawls?',
  404. LOSSES: 'Losses',
  405. WINS: 'Wins',
  406. FIGHTS: 'Fights',
  407. STAGE: 'Stage',
  408. DONT_HAVE_LIVES: "You don't have lives",
  409. LIVES: 'Lives',
  410. SECRET_WEALTH_ALREADY: 'Item for Pet Potions already purchased',
  411. SECRET_WEALTH_NOT_ENOUGH: 'Not Enough Pet Potion, You Have {available}, Need {need}',
  412. SECRET_WEALTH_UPGRADE_NEW_PET: 'After purchasing the Pet Potion, it will not be enough to upgrade a new pet',
  413. SECRET_WEALTH_PURCHASED: 'Purchased {count} {name}',
  414. SECRET_WEALTH_CANCELED: 'Secret Wealth: Purchase Canceled',
  415. SECRET_WEALTH_BUY: 'You have {available} Pet Potion.<br>Do you want to buy {countBuy} {name} for {price} Pet Potion?',
  416. DAILY_BONUS: 'Daily bonus',
  417. DO_DAILY_QUESTS: 'Do daily quests',
  418. ACTIONS: 'Actions',
  419. ACTIONS_TITLE: 'Dialog box with various actions',
  420. OTHERS: 'Others',
  421. OTHERS_TITLE: 'Others',
  422. CHOOSE_ACTION: 'Choose an action',
  423. OPEN_LOOTBOX: 'You have {lootBox} boxes, should we open them?',
  424. STAMINA: 'Energy',
  425. BOXES_OVER: 'The boxes are over',
  426. NO_BOXES: 'No boxes',
  427. NO_MORE_ACTIVITY: 'No more activity for items today',
  428. EXCHANGE_ITEMS: 'Exchange items for activity points (max {maxActive})?',
  429. GET_ACTIVITY: 'Get Activity',
  430. NOT_ENOUGH_ITEMS: 'Not enough items',
  431. ACTIVITY_RECEIVED: 'Activity received',
  432. NO_PURCHASABLE_HERO_SOULS: 'No purchasable Hero Souls',
  433. PURCHASED_HERO_SOULS: 'Purchased {countHeroSouls} Hero Souls',
  434. NOT_ENOUGH_EMERALDS_540: 'Not enough emeralds, you need {imgEmerald}540 you have {imgEmerald}{currentStarMoney}',
  435. BUY_OUTLAND_BTN: 'Buy {count} chests {imgEmerald}{countEmerald}',
  436. CHESTS_NOT_AVAILABLE: 'Chests not available',
  437. OUTLAND_CHESTS_RECEIVED: 'Outland chests received',
  438. RAID_NOT_AVAILABLE: 'The raid is not available or there are no spheres',
  439. RAID_ADVENTURE: 'Raid {adventureId} adventure!',
  440. SOMETHING_WENT_WRONG: 'Something went wrong',
  441. ADVENTURE_COMPLETED: 'Adventure {adventureId} completed {times} times',
  442. CLAN_STAT_COPY: 'Clan statistics copied to clipboard',
  443. GET_ENERGY: 'Get Energy',
  444. GET_ENERGY_TITLE: 'Opens platinum boxes one at a time until you get 250 energy',
  445. ITEM_EXCHANGE: 'Item Exchange',
  446. ITEM_EXCHANGE_TITLE: 'Exchanges items for the specified amount of activity',
  447. BUY_SOULS: 'Buy souls',
  448. BUY_SOULS_TITLE: 'Buy hero souls from all available shops',
  449. BUY_OUTLAND: 'Buy Outland',
  450. BUY_OUTLAND_TITLE: 'Buy 9 chests in Outland for 540 emeralds',
  451. RAID: 'Raid',
  452. AUTO_RAID_ADVENTURE: 'Raid adventure',
  453. AUTO_RAID_ADVENTURE_TITLE: 'Raid adventure set number of times',
  454. CLAN_STAT: 'Clan statistics',
  455. CLAN_STAT_TITLE: 'Copies clan statistics to the clipboard',
  456. BTN_AUTO_F5: 'Auto (F5)',
  457. BOSS_DAMAGE: 'Boss Damage: ',
  458. NOTHING_BUY: 'Nothing to buy',
  459. LOTS_BOUGHT: '{countBuy} lots bought for gold',
  460. BUY_FOR_GOLD: 'Buy for gold',
  461. BUY_FOR_GOLD_TITLE: 'Buy items for gold in the Town Shop and in the Pet Soul Stone Shop',
  462. REWARDS_AND_MAIL: 'Rewards and Mail',
  463. REWARDS_AND_MAIL_TITLE: 'Collects rewards and mail',
  464. New_Year_Clan: 'a gift for a friend',
  465. New_Year_Clan_TITLE: 'New Year gifts to friends',
  466. COLLECT_REWARDS_AND_MAIL: 'Collected {countQuests} rewards and {countMail} letters',
  467. TIMER_ALREADY: 'Timer already started {time}',
  468. NO_ATTEMPTS_TIMER_START: 'No attempts, timer started {time}',
  469. EPIC_BRAWL_RESULT: 'Wins: {wins}/{attempts}, Coins: {coins}, Streak: {progress}/{nextStage} [Close]{end}',
  470. ATTEMPT_ENDED: '<br>Attempts ended, timer started {time}',
  471. EPIC_BRAWL: 'Cosmic Battle',
  472. EPIC_BRAWL_TITLE: 'Spends attempts in the Cosmic Battle',
  473. RELOAD_GAME: 'Reload game',
  474. TIMER: 'Timer:',
  475. SHOW_ERRORS: 'Show errors',
  476. SHOW_ERRORS_TITLE: 'Show server request errors',
  477. ERROR_MSG: 'Error: {name}<br>{description}',
  478. EVENT_AUTO_BOSS: 'Maximum number of battles for calculation:</br>{length} ∗ {countTestBattle} = {maxCalcBattle}</br>If you have a weak computer, it may take a long time for this, click on the cross to cancel.</br>Should I search for the best pack from all or the first suitable one?',
  479. BEST_SLOW: 'Best (slower)',
  480. FIRST_FAST: 'First (faster)',
  481. FREEZE_INTERFACE: 'Calculating... <br>The interface may freeze.',
  482. ERROR_F12: 'Error, details in the console (F12)',
  483. FAILED_FIND_WIN_PACK: 'Failed to find a winning pack',
  484. BEST_PACK: 'Best pack:',
  485. BOSS_HAS_BEEN_DEF: 'Boss {bossLvl} has been defeated.',
  486. NOT_ENOUGH_ATTEMPTS_BOSS: 'Not enough attempts to defeat boss {bossLvl}, retry?',
  487. BOSS_VICTORY_IMPOSSIBLE: 'Based on the recalculation of {battles} battles, victory has not been achieved. Would you like to continue the search for a winning battle in real battles?',
  488. BOSS_HAS_BEEN_DEF_TEXT: 'Boss {bossLvl} defeated in<br>{countBattle}/{countMaxBattle} attempts<br>(Please synchronize or restart the game to update the data)',
  489. MAP: 'Map: ',
  490. PLAYER_POS: 'Player positions:',
  491. NY_GIFTS: 'Gifts',
  492. NY_GIFTS_TITLE: "Open all New Year's gifts",
  493. NY_NO_GIFTS: 'No gifts not received',
  494. NY_GIFTS_COLLECTED: '{count} gifts collected',
  495. CHANGE_MAP: 'Island map',
  496. CHANGE_MAP_TITLE: 'Change island map',
  497. SELECT_ISLAND_MAP: 'Select an island map:',
  498. MAP_NUM: 'Map {num}',
  499. SECRET_WEALTH_SHOP: 'Secret Wealth {name}: ',
  500. SHOPS: 'Shops',
  501. SHOPS_DEFAULT: 'Default',
  502. SHOPS_DEFAULT_TITLE: 'Default stores',
  503. SHOPS_LIST: 'Shops {number}',
  504. SHOPS_LIST_TITLE: 'List of shops {number}',
  505. SHOPS_WARNING: 'Stores<br><span style="color:red">If you buy brawl store coins for emeralds, you must use them immediately, otherwise they will disappear after restarting the game!</span>',
  506. MINIONS_WARNING: 'The hero packs for attacking minions are incomplete, should I continue?',
  507. FAST_SEASON: 'Fast season',
  508. FAST_SEASON_TITLE: 'Skip the map selection screen in a season',
  509. SET_NUMBER_LEVELS: 'Specify the number of levels:',
  510. POSSIBLE_IMPROVE_LEVELS: 'It is possible to improve only {count} levels.<br>Improving?',
  511. NOT_ENOUGH_RESOURECES: 'Not enough resources',
  512. IMPROVED_LEVELS: 'Improved levels: {count}',
  513. ARTIFACTS_UPGRADE: 'Artifacts Upgrade',
  514. ARTIFACTS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero artifacts',
  515. SKINS_UPGRADE: 'Skins Upgrade',
  516. SKINS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero skins',
  517. HINT: '<br>Hint: ',
  518. PICTURE: '<br>Picture: ',
  519. ANSWER: '<br>Answer: ',
  520. NO_HEROES_PACK: 'Fight at least one battle to save the attacking team',
  521. BRAWL_AUTO_PACK: 'Automatic selection of packs',
  522. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Automatic pack selection is not suitable for the current hero',
  523. BRAWL_DAILY_TASK_COMPLETED: 'Daily task completed, continue attacking?',
  524. CALC_STAT: 'Calculate statistics',
  525. ELEMENT_TOURNAMENT_REWARD: 'Unclaimed bonus for Elemental Tournament',
  526. BTN_TRY_FIX_IT: 'Fix it',
  527. BTN_TRY_FIX_IT_TITLE: 'Enable auto attack combat correction',
  528. DAMAGE_FIXED: 'Damage fixed from {lastDamage} to {maxDamage}!',
  529. DAMAGE_NO_FIXED: 'Failed to fix damage: {lastDamage}',
  530. LETS_FIX: "Let's fix",
  531. COUNT_FIXED: 'For {count} attempts',
  532. DEFEAT_TURN_TIMER: 'Defeat! Turn on the timer to complete the mission?',
  533. SEASON_REWARD: 'Season Rewards',
  534. SEASON_REWARD_TITLE: 'Collects available free rewards from all current seasons',
  535. SEASON_REWARD_COLLECTED: 'Collected {count} season rewards',
  536. SELL_HERO_SOULS: 'Sell ​​souls',
  537. SELL_HERO_SOULS_TITLE: 'Exchanges all absolute star hero souls for gold',
  538. GOLD_RECEIVED: 'Gold received: {gold}',
  539. OPEN_ALL_EQUIP_BOXES: 'Open all Equipment Fragment Box?',
  540. },
  541. ru: {
  542. /* Чекбоксы */
  543. SKIP_FIGHTS: 'Пропуск боев',
  544. SKIP_FIGHTS_TITLE: 'Пропуск боев в запределье и арене титанов, автопропуск в башне и кампании',
  545. ENDLESS_CARDS: 'Бесконечные карты',
  546. ENDLESS_CARDS_TITLE: 'Отключить трату карт предсказаний',
  547. AUTO_EXPEDITION: 'АвтоЭкспедиции',
  548. AUTO_EXPEDITION_TITLE: 'Автоотправка экспедиций',
  549. CANCEL_FIGHT: 'Отмена боя',
  550. CANCEL_FIGHT_TITLE: 'Возможность отмены ручного боя на ВГ, СМ и в Асгарде',
  551. GIFTS: 'Подарки',
  552. GIFTS_TITLE: 'Собирать подарки автоматически',
  553. BATTLE_RECALCULATION: 'Прерасчет боя',
  554. BATTLE_RECALCULATION_TITLE: 'Предварительный расчет боя',
  555. BATTLE_FISHING: 'Добивание',
  556. BATTLE_FISHING_TITLE: 'Добивание в чате команды из последнего реплея',
  557. BATTLE_TRENING: 'Тренировка',
  558. BATTLE_TRENING_TITLE: 'Тренировочный бой в чате против команды из последнего реплея',
  559. QUANTITY_CONTROL: 'Контроль кол-ва',
  560. QUANTITY_CONTROL_TITLE: 'Возможность указывать количество открываемых "лутбоксов"',
  561. REPEAT_CAMPAIGN: 'Повтор в компании',
  562. REPEAT_CAMPAIGN_TITLE: 'Автоповтор боев в кампании',
  563. DISABLE_DONAT: 'Отключить донат',
  564. DISABLE_DONAT_TITLE: 'Убирает все предложения доната',
  565. DAILY_QUESTS: 'Квесты',
  566. DAILY_QUESTS_TITLE: 'Выполнять ежедневные квесты',
  567. AUTO_QUIZ: 'АвтоВикторина',
  568. AUTO_QUIZ_TITLE: 'Автоматическое получение правильных ответов на вопросы викторины',
  569. SECRET_WEALTH_CHECKBOX: 'Автоматическая покупка в магазине "Тайное Богатство" при заходе в игру',
  570. HIDE_SERVERS: 'Свернуть сервера',
  571. HIDE_SERVERS_TITLE: 'Скрывать неиспользуемые сервера',
  572. /* Поля ввода */
  573. HOW_MUCH_TITANITE: 'Сколько фармим титанита',
  574. COMBAT_SPEED: 'Множитель ускорения боя',
  575. HOW_REPEAT_CAMPAIGN: 'Сколько повторов миссий', //тест добавил
  576. NUMBER_OF_TEST: 'Количество тестовых боев',
  577. NUMBER_OF_AUTO_BATTLE: 'Количество попыток автобоев',
  578. USER_ID_TITLE: 'Введите айди игрока',
  579. AMOUNT: 'Количество отправляемых подарков',
  580. GIFT_NUM: 'Номер подарка, 1 - развитие героев, 2 - питомцы, 3 - света, 4 - тьмы, 5 - вознесения, 6 - облик',
  581. /* Кнопки */
  582. RUN_SCRIPT: 'Запустить скрипт',
  583. STOP_SCRIPT: 'Остановить скрипт',
  584. TO_DO_EVERYTHING: 'Сделать все',
  585. TO_DO_EVERYTHING_TITLE: 'Выполнить несколько действий',
  586. OUTLAND: 'Запределье',
  587. OUTLAND_TITLE: 'Собрать Запределье',
  588. TITAN_ARENA: 'Турнир Стихий',
  589. TITAN_ARENA_TITLE: 'Автопрохождение Турнира Стихий',
  590. DUNGEON: 'Подземелье',
  591. DUNGEON_TITLE: 'Автопрохождение подземелья',
  592. DUNGEON2: 'Подземелье фулл',
  593. DUNGEON_FULL_TITLE: 'Подземелье для фуловых титанов',
  594. STOP_DUNGEON: 'Стоп подземка',
  595. STOP_DUNGEON_TITLE: 'Остановить копание подземелья',
  596. SEER: 'Провидец',
  597. SEER_TITLE: 'Покрутить Провидца',
  598. TOWER: 'Башня',
  599. TOWER_TITLE: 'Автопрохождение башни',
  600. EXPEDITIONS: 'Экспедиции',
  601. EXPEDITIONS_TITLE: 'Отправка и сбор экспедиций',
  602. SYNC: 'Синхронизация',
  603. SYNC_TITLE: 'Частичная синхронизация данных игры без перезагрузки сатраницы',
  604. ARCHDEMON: 'Архидемон',
  605. ARCHDEMON_TITLE: 'Набивает килы и собирает награду',
  606. CRUCIBLE_SOULS: 'Горнило душ',
  607. CRUCIBLE_SOULS_TITLE:'Набить килов в горниле душ',
  608. ESTER_EGGS: 'Пасхалки',
  609. ESTER_EGGS_TITLE: 'Собрать все пасхалки или награды',
  610. REWARDS: 'Награды',
  611. REWARDS_TITLE: 'Собрать все награды за задания',
  612. MAIL: 'Почта',
  613. MAIL_TITLE: 'Собрать всю почту, кроме писем с энергией и зарядами портала',
  614. MINIONS: 'Прислужники',
  615. MINIONS_TITLE: 'Атакует прислужников сохраннеными пачками',
  616. ADVENTURE: 'Приключение',
  617. ADVENTURE_TITLE: 'Проходит приключение по указанному маршруту',
  618. STORM: 'Буря',
  619. STORM_TITLE: 'Проходит бурю по указанному маршруту',
  620. SANCTUARY: 'Святилище',
  621. SANCTUARY_TITLE: 'Быстрый переход к Святилищу',
  622. GUILD_WAR: 'Война гильдий',
  623. GUILD_WAR_TITLE: 'Быстрый переход к Войне гильдий',
  624. SECRET_WEALTH: 'Тайное богатство',
  625. SECRET_WEALTH_TITLE: 'Купить что-то в магазине "Тайное богатство"',
  626. /* Разное */
  627. BOTTOM_URLS: '<a href="https://t.me/+q6gAGCRpwyFkNTYy" target="_blank" title="Telegram"><svg width="20" height="20" style="margin:2px" viewBox="0 0 1e3 1e3" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="a" x1="50%" x2="50%" y2="99.258%"><stop stop-color="#2AABEE" offset="0"/><stop stop-color="#229ED9" offset="1"/></linearGradient></defs><g fill-rule="evenodd"><circle cx="500" cy="500" r="500" fill="url(#a)"/><path d="m226.33 494.72c145.76-63.505 242.96-105.37 291.59-125.6 138.86-57.755 167.71-67.787 186.51-68.119 4.1362-0.072862 13.384 0.95221 19.375 5.8132 5.0584 4.1045 6.4501 9.6491 7.1161 13.541 0.666 3.8915 1.4953 12.756 0.83608 19.683-7.5246 79.062-40.084 270.92-56.648 359.47-7.0089 37.469-20.81 50.032-34.17 51.262-29.036 2.6719-51.085-19.189-79.207-37.624-44.007-28.847-68.867-46.804-111.58-74.953-49.366-32.531-17.364-50.411 10.769-79.631 7.3626-7.6471 135.3-124.01 137.77-134.57 0.30968-1.3202 0.59708-6.2414-2.3265-8.8399s-7.2385-1.7099-10.352-1.0032c-4.4137 1.0017-74.715 47.468-210.9 139.4-19.955 13.702-38.029 20.379-54.223 20.029-17.853-0.3857-52.194-10.094-77.723-18.393-31.313-10.178-56.199-15.56-54.032-32.846 1.1287-9.0037 13.528-18.212 37.197-27.624z" fill="#fff"/></g></svg></a><a href="https://vk.com/invite/YNPxKGX" target="_blank" title="Вконтакте"><svg width="20" height="20" style="margin:2px" viewBox="0 0 101 100" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path d="M0.5 48C0.5 25.3726 0.5 14.0589 7.52944 7.02944C14.5589 0 25.8726 0 48.5 0H52.5C75.1274 0 86.4411 0 93.4706 7.02944C100.5 14.0589 100.5 25.3726 100.5 48V52C100.5 74.6274 100.5 85.9411 93.4706 92.9706C86.4411 100 75.1274 100 52.5 100H48.5C25.8726 100 14.5589 100 7.52944 92.9706C0.5 85.9411 0.5 74.6274 0.5 52V48Z" fill="#07f"/><path d="m53.708 72.042c-22.792 0-35.792-15.625-36.333-41.625h11.417c0.375 19.083 8.7915 27.167 15.458 28.833v-28.833h10.75v16.458c6.5833-0.7083 13.499-8.2082 15.832-16.458h10.75c-1.7917 10.167-9.2917 17.667-14.625 20.75 5.3333 2.5 13.875 9.0417 17.125 20.875h-11.834c-2.5417-7.9167-8.8745-14.042-17.25-14.875v14.875h-1.2919z" fill="#fff"/></g><defs><clipPath id="a"><rect transform="translate(.5)" width="100" height="100" fill="#fff"/></clipPath></defs></svg></a>',
  628. GIFTS_SENT: 'Подарки отправлены!',
  629. DO_YOU_WANT: 'Вы действительно хотите это сделать?',
  630. BTN_RUN: 'Запускай',
  631. BTN_CANCEL: 'Отмена',
  632. BTN_OK: 'Ок',
  633. MSG_HAVE_BEEN_DEFEATED: 'Вы потерпели поражение!',
  634. BTN_AUTO: 'Авто',
  635. MSG_YOU_APPLIED: 'Вы нанесли',
  636. MSG_DAMAGE: 'урона',
  637. MSG_CANCEL_AND_STAT: 'Авто (F5) и показать Статистику',
  638. MSG_REPEAT_MISSION: 'Повторить миссию?',
  639. BTN_REPEAT: 'Повторить',
  640. BTN_NO: 'Нет',
  641. MSG_SPECIFY_QUANT: 'Указать количество:',
  642. BTN_OPEN: 'Открыть',
  643. QUESTION_COPY: 'Вопрос скопирован в буфер обмена',
  644. ANSWER_KNOWN: 'Ответ известен',
  645. ANSWER_NOT_KNOWN: 'ВНИМАНИЕ ОТВЕТ НЕ ИЗВЕСТЕН',
  646. BEING_RECALC: 'Идет прерасчет боя',
  647. THIS_TIME: 'На этот раз',
  648. VICTORY: '<span style="color:green;">ПОБЕДА</span>',
  649. DEFEAT: '<span style="color:red;">ПОРАЖЕНИЕ</span>',
  650. CHANCE_TO_WIN: 'Шансы на победу <span style="color:red;">на основе прерасчета</span>',
  651. OPEN_DOLLS: 'матрешек рекурсивно',
  652. SENT_QUESTION: 'Вопрос отправлен',
  653. SETTINGS: 'Настройки',
  654. MSG_BAN_ATTENTION: '<p style="color:red;">Использование этой функции может привести к бану.</p> Продолжить?',
  655. BTN_YES_I_AGREE: 'Да, я беру на себя все риски!',
  656. BTN_NO_I_AM_AGAINST: 'Нет, я отказываюсь от этого!',
  657. VALUES: 'Значения',
  658. SAVING: 'Сохранка',
  659. USER_ID: 'айди пользователя',
  660. SEND_GIFT: 'Подарок отправлен',
  661. EXPEDITIONS_SENT: 'Экспедиции:<br>Собрано: {countGet}<br>Отправлено: {countSend}',
  662. EXPEDITIONS_NOTHING: 'Нечего собирать/отправлять',
  663. TITANIT: 'Титанит',
  664. COMPLETED: 'завершено',
  665. FLOOR: 'Этаж',
  666. LEVEL: 'Уровень',
  667. BATTLES: 'бои',
  668. EVENT: 'Эвент',
  669. NOT_AVAILABLE: 'недоступен',
  670. NO_HEROES: 'Нет героев',
  671. DAMAGE_AMOUNT: 'Количество урона',
  672. NOTHING_TO_COLLECT: 'Нечего собирать',
  673. COLLECTED: 'Собрано',
  674. REWARD: 'наград',
  675. REMAINING_ATTEMPTS: 'Осталось попыток',
  676. BATTLES_CANCELED: 'Битв отменено',
  677. MINION_RAID: 'Рейд прислужников',
  678. STOPPED: 'Остановлено',
  679. REPETITIONS: 'Повторений',
  680. MISSIONS_PASSED: 'Миссий пройдено',
  681. STOP: 'остановить',
  682. TOTAL_OPEN: 'Всего открыто',
  683. OPEN: 'Открыто',
  684. ROUND_STAT: 'Статистика урона за',
  685. BATTLE: 'боев',
  686. MINIMUM: 'Минимальный',
  687. MAXIMUM: 'Максимальный',
  688. AVERAGE: 'Средний',
  689. NOT_THIS_TIME: 'Не в этот раз',
  690. RETRY_LIMIT_EXCEEDED: 'Превышен лимит попыток',
  691. SUCCESS: 'Успех',
  692. RECEIVED: 'Получено',
  693. LETTERS: 'писем',
  694. PORTALS: 'порталов',
  695. ATTEMPTS: 'попыток',
  696. QUEST_10001: 'Улучши умения героев 3 раза',
  697. QUEST_10002: 'Пройди 10 миссий',
  698. QUEST_10003: 'Пройди 3 героические миссии',
  699. QUEST_10004: 'Сразись 3 раза на Арене или Гранд Арене',
  700. QUEST_10006: 'Используй обмен изумрудов 1 раз',
  701. QUEST_10007: 'Соверши 1 призыв в Атриуме Душ',
  702. QUEST_10016: 'Отправь подарки согильдийцам',
  703. QUEST_10018: 'Используй зелье опыта',
  704. QUEST_10019: 'Открой 1 сундук в Башне',
  705. QUEST_10020: 'Открой 3 сундука в Запределье',
  706. QUEST_10021: 'Собери 75 Титанита в Подземелье Гильдии',
  707. QUEST_10021: 'Собери 150 Титанита в Подземелье Гильдии',
  708. QUEST_10023: 'Прокачай Дар Стихий на 1 уровень',
  709. QUEST_10024: 'Повысь уровень любого артефакта один раз',
  710. QUEST_10025: 'Начни 1 Экспедицию',
  711. QUEST_10026: 'Начни 4 Экспедиции',
  712. QUEST_10027: 'Победи в 1 бою Турнира Стихий',
  713. QUEST_10028: 'Повысь уровень любого артефакта титанов',
  714. QUEST_10029: 'Открой сферу артефактов титанов',
  715. QUEST_10030: 'Улучши облик любого героя 1 раз',
  716. QUEST_10031: 'Победи в 6 боях Турнира Стихий',
  717. QUEST_10043: 'Начни или присоеденись к Приключению',
  718. QUEST_10044: 'Воспользуйся призывом питомцев 1 раз',
  719. QUEST_10046: 'Открой 3 сундука в Приключениях',
  720. QUEST_10047: 'Набери 150 очков активности в Гильдии',
  721. NOTHING_TO_DO: 'Нечего выполнять',
  722. YOU_CAN_COMPLETE: 'Можно выполнить квесты',
  723. BTN_DO_IT: 'Выполняй',
  724. NOT_QUEST_COMPLETED: 'Ни одного квеста не выполенно',
  725. COMPLETED_QUESTS: 'Выполнено квестов',
  726. /* everything button */
  727. ASSEMBLE_OUTLAND: 'Собрать Запределье',
  728. PASS_THE_TOWER: 'Пройти башню',
  729. CHECK_EXPEDITIONS: 'Проверить экспедиции',
  730. COMPLETE_TOE: 'Пройти Турнир Стихий',
  731. COMPLETE_DUNGEON: 'Пройти подземелье',
  732. COMPLETE_DUNGEON_FULL: 'Пройти подземелье фулл',
  733. COLLECT_MAIL: 'Собрать почту',
  734. COLLECT_MISC: 'Собрать всякую херню',
  735. COLLECT_MISC_TITLE: 'Собрать пасхалки, камни облика, ключи, монеты арены и Хрусталь души',
  736. COLLECT_QUEST_REWARDS: 'Собрать награды за квесты',
  737. MAKE_A_SYNC: 'Сделать синхронизацию',
  738.  
  739. RUN_FUNCTION: 'Выполнить следующие функции?',
  740. BTN_GO: 'Погнали!',
  741. PERFORMED: 'Выполняется',
  742. DONE: 'Выполнено',
  743. ERRORS_OCCURRES: 'Призошли ошибки при выполнении',
  744. COPY_ERROR: 'Скопировать в буфер информацию об ошибке',
  745. BTN_YES: 'Да',
  746. ALL_TASK_COMPLETED: 'Все задачи выполнены',
  747.  
  748. UNKNOWN: 'Неизвестно',
  749. ENTER_THE_PATH: 'Введите путь приключения через запятые или дефисы',
  750. START_ADVENTURE: 'Начать приключение по этому пути!',
  751. INCORRECT_WAY: 'Неверный путь в приключении: {from} -> {to}',
  752. BTN_CANCELED: 'Отменено',
  753. MUST_TWO_POINTS: 'Путь должен состоять минимум из 2х точек',
  754. MUST_ONLY_NUMBERS: 'Путь должен содержать только цифры и запятые',
  755. NOT_ON_AN_ADVENTURE: 'Вы не в приключении',
  756. YOU_IN_NOT_ON_THE_WAY: 'Указанный путь должен включать точку вашего положения',
  757. ATTEMPTS_NOT_ENOUGH: 'Ваших попыток не достаточно для завершения пути, продолжить?',
  758. YES_CONTINUE: 'Да, продолжай!',
  759. NOT_ENOUGH_AP: 'Попыток не достаточно',
  760. ATTEMPTS_ARE_OVER: 'Попытки закончились',
  761. MOVES: 'Ходы',
  762. BUFF_GET_ERROR: 'Ошибка при получении бафа',
  763. BATTLE_END_ERROR: 'Ошибка завершения боя',
  764. AUTOBOT: 'АвтоБой',
  765. FAILED_TO_WIN_AUTO: 'Не удалось победить в автобою',
  766. ERROR_OF_THE_BATTLE_COPY: 'Призошли ошибка в процессе прохождения боя<br>Скопировать ошибку в буфер обмена?',
  767. ERROR_DURING_THE_BATTLE: 'Ошибка в процессе прохождения боя',
  768. NO_CHANCE_WIN: 'Нет шансов победить в этом бою: 0/',
  769. LOST_HEROES: 'Вы победили, но потеряли одного или несколько героев!',
  770. VICTORY_IMPOSSIBLE: 'Победа не возможна, бъем на результат?',
  771. FIND_COEFF: 'Поиск коэффициента больше чем',
  772. BTN_PASS: 'ПРОПУСК',
  773. BRAWLS: 'Потасовки',
  774. BRAWLS_TITLE: 'Включает возможность автопотасовок',
  775. START_AUTO_BRAWLS: 'Запустить Автопотасовки?',
  776. LOSSES: 'Поражений',
  777. WINS: 'Побед',
  778. FIGHTS: 'Боев',
  779. STAGE: 'Стадия',
  780. DONT_HAVE_LIVES: 'У Вас нет жизней',
  781. LIVES: 'Жизни',
  782. SECRET_WEALTH_ALREADY: 'товар за Зелья питомцев уже куплен',
  783. SECRET_WEALTH_NOT_ENOUGH: 'Не достаточно Зелье Питомца, у Вас {available}, нужно {need}',
  784. SECRET_WEALTH_UPGRADE_NEW_PET: 'После покупки Зелье Питомца будет не достаточно для прокачки нового питомца',
  785. SECRET_WEALTH_PURCHASED: 'Куплено {count} {name}',
  786. SECRET_WEALTH_CANCELED: 'Тайное богатство: покупка отменена',
  787. SECRET_WEALTH_BUY: 'У вас {available} Зелье Питомца.<br>Вы хотите купить {countBuy} {name} за {price} Зелье Питомца?',
  788. DAILY_BONUS: 'Ежедневная награда',
  789. DO_DAILY_QUESTS: 'Сделать ежедневные квесты',
  790. ACTIONS: 'Действия',
  791. ACTIONS_TITLE: 'Диалоговое окно с различными действиями',
  792. OTHERS: 'Разное',
  793. OTHERS_TITLE: 'Диалоговое окно с дополнительными различными действиями',
  794. CHOOSE_ACTION: 'Выберите действие',
  795. OPEN_LOOTBOX: 'У Вас {lootBox} ящиков, откываем?',
  796. STAMINA: 'Энергия',
  797. BOXES_OVER: 'Ящики закончились',
  798. NO_BOXES: 'Нет ящиков',
  799. NO_MORE_ACTIVITY: 'Больше активности за предметы сегодня не получить',
  800. EXCHANGE_ITEMS: 'Обменять предметы на очки активности (не более {maxActive})?',
  801. GET_ACTIVITY: 'Получить активность',
  802. NOT_ENOUGH_ITEMS: 'Предметов недостаточно',
  803. ACTIVITY_RECEIVED: 'Получено активности',
  804. NO_PURCHASABLE_HERO_SOULS: 'Нет доступных для покупки душ героев',
  805. PURCHASED_HERO_SOULS: 'Куплено {countHeroSouls} душ героев',
  806. NOT_ENOUGH_EMERALDS_540: 'Недостаточно изюма, нужно {imgEmerald}540 у Вас {imgEmerald}{currentStarMoney}',
  807. BUY_OUTLAND_BTN: 'Купить {count} сундуков {imgEmerald}{countEmerald}',
  808. CHESTS_NOT_AVAILABLE: 'Сундуки не доступны',
  809. OUTLAND_CHESTS_RECEIVED: 'Получено сундуков Запределья',
  810. RAID_NOT_AVAILABLE: 'Рейд не доступен или сфер нет',
  811. RAID_ADVENTURE: 'Рейд {adventureId} приключения!',
  812. SOMETHING_WENT_WRONG: 'Что-то пошло не так',
  813. ADVENTURE_COMPLETED: 'Приключение {adventureId} пройдено {times} раз',
  814. CLAN_STAT_COPY: 'Клановая статистика скопирована в буфер обмена',
  815. GET_ENERGY: 'Получить энергию',
  816. GET_ENERGY_TITLE: 'Открывает платиновые шкатулки по одной до получения 250 энергии',
  817. ITEM_EXCHANGE: 'Обмен предметов',
  818. ITEM_EXCHANGE_TITLE: 'Обменивает предметы на указанное количество активности',
  819. BUY_SOULS: 'Купить души',
  820. BUY_SOULS_TITLE: 'Купить души героев из всех доступных магазинов',
  821. BUY_OUTLAND: 'Купить Запределье',
  822. BUY_OUTLAND_TITLE: 'Купить 9 сундуков в Запределье за 540 изумрудов',
  823. RAID: 'Рейд',
  824. AUTO_RAID_ADVENTURE: 'Рейд приключения',
  825. AUTO_RAID_ADVENTURE_TITLE: 'Рейд приключения заданное количество раз',
  826. CLAN_STAT: 'Клановая статистика',
  827. CLAN_STAT_TITLE: 'Копирует клановую статистику в буфер обмена',
  828. BTN_AUTO_F5: 'Авто (F5)',
  829. BOSS_DAMAGE: 'Урон по боссу: ',
  830. NOTHING_BUY: 'Нечего покупать',
  831. LOTS_BOUGHT: 'За золото куплено {countBuy} лотов',
  832. BUY_FOR_GOLD: 'Скупить за золото',
  833. BUY_FOR_GOLD_TITLE: 'Скупить предметы за золото в Городской лавке и в магазине Камней Душ Питомцев',
  834. REWARDS_AND_MAIL: 'Награды и почта',
  835. REWARDS_AND_MAIL_TITLE: 'Собирает награды и почту',
  836. New_Year_Clan: 'подарок другу',
  837. New_Year_Clan_TITLE: 'Новогодние подарки друзьям',
  838. COLLECT_REWARDS_AND_MAIL: 'Собрано {countQuests} наград и {countMail} писем',
  839. TIMER_ALREADY: 'Таймер уже запущен {time}',
  840. NO_ATTEMPTS_TIMER_START: 'Попыток нет, запущен таймер {time}',
  841. EPIC_BRAWL_RESULT: '{i} Победы: {wins}/{attempts}, Монеты: {coins}, Серия: {progress}/{nextStage} [Закрыть]{end}',
  842. ATTEMPT_ENDED: '<br>Попытки закончились, запущен таймер {time}',
  843. EPIC_BRAWL: 'Вселенская битва',
  844. EPIC_BRAWL_TITLE: 'Тратит попытки во Вселенской битве',
  845. RELOAD_GAME: 'Перезагрузить игру',
  846. TIMER: 'Таймер:',
  847. SHOW_ERRORS: 'Отображать ошибки',
  848. SHOW_ERRORS_TITLE: 'Отображать ошибки запросов к серверу',
  849. ERROR_MSG: 'Ошибка: {name}<br>{description}',
  850. EVENT_AUTO_BOSS: 'Максимальное количество боев для расчета:</br>{length} * {countTestBattle} = {maxCalcBattle}</br>Если у Вас слабый компьютер на это может потребоваться много времени, нажмите крестик для отмены.</br>Искать лучший пак из всех или первый подходящий?',
  851. BEST_SLOW: 'Лучший (медленее)',
  852. FIRST_FAST: 'Первый (быстрее)',
  853. FREEZE_INTERFACE: 'Идет расчет... <br> Интерфейс может зависнуть.',
  854. ERROR_F12: 'Ошибка, подробности в консоли (F12)',
  855. FAILED_FIND_WIN_PACK: 'Победный пак найти не удалось',
  856. BEST_PACK: 'Наилучший пак: ',
  857. BOSS_HAS_BEEN_DEF: 'Босс {bossLvl} побежден',
  858. NOT_ENOUGH_ATTEMPTS_BOSS: 'Для победы босса ${bossLvl} не хватило попыток, повторить?',
  859. BOSS_VICTORY_IMPOSSIBLE: 'По результатам прерасчета {battles} боев победу получить не удалось. Вы хотите продолжить поиск победного боя на реальных боях?',
  860. BOSS_HAS_BEEN_DEF_TEXT: 'Босс {bossLvl} побежден за<br>{countBattle}/{countMaxBattle} попыток<br>(Сделайте синхронизацию или перезагрузите игру для обновления данных)',
  861. MAP: 'Карта: ',
  862. PLAYER_POS: 'Позиции игроков:',
  863. NY_GIFTS: 'Подарки',
  864. NY_GIFTS_TITLE: 'Открыть все новогодние подарки',
  865. NY_NO_GIFTS: 'Нет не полученных подарков',
  866. NY_GIFTS_COLLECTED: 'Собрано {count} подарков',
  867. CHANGE_MAP: 'Карта острова',
  868. CHANGE_MAP_TITLE: 'Сменить карту острова',
  869. SELECT_ISLAND_MAP: 'Выберите карту острова:',
  870. MAP_NUM: 'Карта {num}',
  871. SECRET_WEALTH_SHOP: 'Тайное богатство {name}: ',
  872. SHOPS: 'Магазины',
  873. SHOPS_DEFAULT: 'Стандартные',
  874. SHOPS_DEFAULT_TITLE: 'Стандартные магазины',
  875. SHOPS_LIST: 'Магазины {number}',
  876. SHOPS_LIST_TITLE: 'Список магазинов {number}',
  877. SHOPS_WARNING: 'Магазины<br><span style="color:red">Если Вы купите монеты магазинов потасовок за изумруды, то их надо использовать сразу, иначе после перезагрузки игры они пропадут!</span>',
  878. MINIONS_WARNING: 'Пачки героев для атаки приспешников неполные, продолжить?',
  879. FAST_SEASON: 'Быстрый сезон',
  880. FAST_SEASON_TITLE: 'Пропуск экрана с выбором карты в сезоне',
  881. SET_NUMBER_LEVELS: 'Указать колличество уровней:',
  882. POSSIBLE_IMPROVE_LEVELS: 'Возможно улучшить только {count} уровней.<br>Улучшаем?',
  883. NOT_ENOUGH_RESOURECES: 'Не хватает ресурсов',
  884. IMPROVED_LEVELS: 'Улучшено уровней: {count}',
  885. ARTIFACTS_UPGRADE: 'Улучшение артефактов',
  886. ARTIFACTS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых артефактов героев',
  887. SKINS_UPGRADE: 'Улучшение обликов',
  888. SKINS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых обликов героев',
  889. HINT: '<br>Подсказка: ',
  890. PICTURE: '<br>На картинке: ',
  891. ANSWER: '<br>Ответ: ',
  892. NO_HEROES_PACK: 'Проведите хотя бы один бой для сохранения атакующей команды',
  893. BRAWL_AUTO_PACK: 'Автоподбор пачки',
  894. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Автоматический подбор пачки не подходит для текущего героя',
  895. BRAWL_DAILY_TASK_COMPLETED: 'Ежедневное задание выполнено, продолжить атаку?',
  896. CALC_STAT: 'Посчитать статистику',
  897. ELEMENT_TOURNAMENT_REWARD: 'Несобранная награда за Турнир Стихий',
  898. BTN_TRY_FIX_IT: 'Исправить',
  899. BTN_TRY_FIX_IT_TITLE: 'Включить исправление боев при автоатаке',
  900. DAMAGE_FIXED: 'Урон исправлен с {lastDamage} до {maxDamage}!',
  901. DAMAGE_NO_FIXED: 'Не удалось исправить урон: {lastDamage}',
  902. LETS_FIX: 'Исправляем',
  903. COUNT_FIXED: 'За {count} попыток',
  904. DEFEAT_TURN_TIMER: 'Поражение! Включить таймер для завершения миссии?',
  905. SEASON_REWARD: 'Награды сезонов',
  906. SEASON_REWARD_TITLE: 'Собирает доступные бесплатные награды со всех текущих сезонов',
  907. SEASON_REWARD_COLLECTED: 'Собрано {count} наград сезонов',
  908. SELL_HERO_SOULS: 'Продать души',
  909. SELL_HERO_SOULS_TITLE: 'Обменивает все души героев с абсолютной звездой на золото',
  910. GOLD_RECEIVED: 'Получено золота: {gold}',
  911. OPEN_ALL_EQUIP_BOXES: 'Открыть все ящики фрагментов экипировки?',
  912. },
  913. };
  914.  
  915. function getLang() {
  916. let lang = '';
  917. if (typeof NXFlashVars !== 'undefined') {
  918. lang = NXFlashVars.interface_lang
  919. }
  920. if (!lang) {
  921. lang = (navigator.language || navigator.userLanguage).substr(0, 2);
  922. }
  923. if (lang == 'ru') {
  924. return lang;
  925. }
  926. return 'en';
  927. }
  928.  
  929. this.I18N = function (constant, replace) {
  930. const selectLang = getLang();
  931. if (constant && constant in i18nLangData[selectLang]) {
  932. const result = i18nLangData[selectLang][constant];
  933. if (replace) {
  934. return result.sprintf(replace);
  935. }
  936. return result;
  937. }
  938. return `% ${constant} %`;
  939. };
  940.  
  941. String.prototype.sprintf = String.prototype.sprintf ||
  942. function () {
  943. "use strict";
  944. var str = this.toString();
  945. if (arguments.length) {
  946. var t = typeof arguments[0];
  947. var key;
  948. var args = ("string" === t || "number" === t) ?
  949. Array.prototype.slice.call(arguments)
  950. : arguments[0];
  951.  
  952. for (key in args) {
  953. str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
  954. }
  955. }
  956.  
  957. return str;
  958. };
  959.  
  960. /**
  961. * Checkboxes
  962. *
  963. * Чекбоксы
  964. */
  965. const checkboxes = {
  966. passBattle: {
  967. label: I18N('SKIP_FIGHTS'),
  968. cbox: null,
  969. title: I18N('SKIP_FIGHTS_TITLE'),
  970. default: false,
  971. },
  972. /*sendExpedition: {
  973. label: I18N('AUTO_EXPEDITION'),
  974. cbox: null,
  975. title: I18N('AUTO_EXPEDITION_TITLE'),
  976. default: false,
  977. },*/ //тест сдедал экспедиции на авто в сделать все
  978. cancelBattle: {
  979. label: I18N('CANCEL_FIGHT'),
  980. cbox: null,
  981. title: I18N('CANCEL_FIGHT_TITLE'),
  982. default: false,
  983. },
  984. preCalcBattle: {
  985. label: I18N('BATTLE_RECALCULATION'),
  986. cbox: null,
  987. title: I18N('BATTLE_RECALCULATION_TITLE'),
  988. default: false,
  989. },
  990. finishingBattle: {
  991. label: I18N('BATTLE_FISHING'),
  992. cbox: null,
  993. title: I18N('BATTLE_FISHING_TITLE'),
  994. default: false,
  995. },
  996. treningBattle: {
  997. label: I18N('BATTLE_TRENING'),
  998. cbox: null,
  999. title: I18N('BATTLE_TRENING_TITLE'),
  1000. default: false,
  1001. },
  1002. countControl: {
  1003. label: I18N('QUANTITY_CONTROL'),
  1004. cbox: null,
  1005. title: I18N('QUANTITY_CONTROL_TITLE'),
  1006. default: true,
  1007. },
  1008. repeatMission: {
  1009. label: I18N('REPEAT_CAMPAIGN'),
  1010. cbox: null,
  1011. title: I18N('REPEAT_CAMPAIGN_TITLE'),
  1012. default: false,
  1013. },
  1014. noOfferDonat: {
  1015. label: I18N('DISABLE_DONAT'),
  1016. cbox: null,
  1017. title: I18N('DISABLE_DONAT_TITLE'),
  1018. /**
  1019. * A crutch to get the field before getting the character id
  1020. *
  1021. * Костыль чтоб получать поле до получения id персонажа
  1022. */
  1023. default: (() => {
  1024. $result = false;
  1025. try {
  1026. $result = JSON.parse(localStorage[GM_info.script.name + ':noOfferDonat']);
  1027. } catch (e) {
  1028. $result = false;
  1029. }
  1030. return $result || false;
  1031. })(),
  1032. },
  1033. dailyQuests: {
  1034. label: I18N('DAILY_QUESTS'),
  1035. cbox: null,
  1036. title: I18N('DAILY_QUESTS_TITLE'),
  1037. default: false,
  1038. },
  1039. // Потасовки
  1040. /*
  1041. autoBrawls: {
  1042. label: I18N('BRAWLS'),
  1043. cbox: null,
  1044. title: I18N('BRAWLS_TITLE'),
  1045. default: (() => {
  1046. $result = false;
  1047. try {
  1048. $result = JSON.parse(localStorage[GM_info.script.name + ':autoBrawls']);
  1049. } catch (e) {
  1050. $result = false;
  1051. }
  1052. return $result || false;
  1053. })(),
  1054. hide: false,
  1055. },
  1056. getAnswer: {
  1057. label: I18N('AUTO_QUIZ'),
  1058. cbox: null,
  1059. title: I18N('AUTO_QUIZ_TITLE'),
  1060. default: false,
  1061. hide: true,
  1062. },*/
  1063. tryFixIt: {
  1064. label: I18N('BTN_TRY_FIX_IT'),
  1065. cbox: null,
  1066. title: I18N('BTN_TRY_FIX_IT_TITLE'),
  1067. default: false,
  1068. hide: false,
  1069. },
  1070. showErrors: {
  1071. label: I18N('SHOW_ERRORS'),
  1072. cbox: null,
  1073. title: I18N('SHOW_ERRORS_TITLE'),
  1074. default: true,
  1075. },
  1076. buyForGold: {
  1077. label: I18N('BUY_FOR_GOLD'),
  1078. cbox: null,
  1079. title: I18N('BUY_FOR_GOLD_TITLE'),
  1080. default: false,
  1081. },
  1082. hideServers: {
  1083. label: I18N('HIDE_SERVERS'),
  1084. cbox: null,
  1085. title: I18N('HIDE_SERVERS_TITLE'),
  1086. default: false,
  1087. },
  1088. fastSeason: {
  1089. label: I18N('FAST_SEASON'),
  1090. cbox: null,
  1091. title: I18N('FAST_SEASON_TITLE'),
  1092. default: false,
  1093. },
  1094. };
  1095. /**
  1096. * Get checkbox state
  1097. *
  1098. * Получить состояние чекбокса
  1099. */
  1100. function isChecked(checkBox) {
  1101. if (!(checkBox in checkboxes)) {
  1102. return false;
  1103. }
  1104. return checkboxes[checkBox].cbox?.checked;
  1105. }
  1106. /**
  1107. * Input fields
  1108. *
  1109. * Поля ввода
  1110. */
  1111. const inputs = {
  1112. countTitanit: {
  1113. input: null,
  1114. title: I18N('HOW_MUCH_TITANITE'),
  1115. default: 150,
  1116. },
  1117. speedBattle: {
  1118. input: null,
  1119. title: I18N('COMBAT_SPEED'),
  1120. default: 5,
  1121. },
  1122. //тест повтор компании
  1123. countRaid: {
  1124. input: null,
  1125. title: I18N('HOW_REPEAT_CAMPAIGN'),
  1126. default: 5,
  1127. },
  1128. countTestBattle: {
  1129. input: null,
  1130. title: I18N('NUMBER_OF_TEST'),
  1131. default: 10,
  1132. },
  1133. countAutoBattle: {
  1134. input: null,
  1135. title: I18N('NUMBER_OF_AUTO_BATTLE'),
  1136. default: 10,
  1137. },
  1138. /*FPS: {
  1139. input: null,
  1140. title: 'FPS',
  1141. default: 60,
  1142. }*/
  1143. }
  1144. //сохранка тест
  1145. const inputs2 = {
  1146. countBattle: {
  1147. input: null,
  1148. title: '-1 сохраняет защиту, -2 атаку противника с Replay',
  1149. default: 1,
  1150. },
  1151. needResource: {
  1152. input: null,
  1153. title: 'Мощь противника мин.(тыс.)/урона(млн.)',
  1154. default: 300,
  1155. },
  1156. needResource2: {
  1157. input: null,
  1158. title: 'Мощь противника макс./тип бафа',
  1159. default: 1500,
  1160. },
  1161. }
  1162. //новогодние подарки игрокам других гильдий
  1163. const inputs3 = {
  1164. userID: { // айди игрока посмотреть открыв его инфо
  1165. input: null,
  1166. title: I18N('USER_ID_TITLE'),
  1167. default: 111111,
  1168. },
  1169. GiftNum: { // номер подарка считаем слева направо от 1 до 6, под 1 это за 750 новогодних игрушек
  1170. input: null,
  1171. title: I18N('GIFT_NUM'),
  1172. default: 10,
  1173. },
  1174. AmontID: { // количество ресурсов от 1 до бесконечности
  1175. input: null,
  1176. title: I18N('AMOUNT'),
  1177. default: 1,
  1178. },
  1179. }
  1180. /**
  1181. * Checks the checkbox
  1182. *
  1183. * Поплучить данные поля ввода
  1184. */
  1185. /*function getInput(inputName) {
  1186. return inputs[inputName]?.input?.value;
  1187. }*/
  1188. function getInput(inputName) {
  1189. if (inputName in inputs){return inputs[inputName]?.input?.value;}
  1190. else if (inputName in inputs2){return inputs2[inputName]?.input?.value;}
  1191. //else if (inputName in inputs3){return inputs3[inputName]?.input?.value;}
  1192. else return null
  1193. }
  1194.  
  1195. //тест рейд
  1196. /** Автоповтор миссии */
  1197. let isRepeatMission = false;
  1198. /** Вкл/Выкл автоповтор миссии */
  1199. this.switchRepeatMission = function() {
  1200. isRepeatMission = !isRepeatMission;
  1201. console.log(isRepeatMission);
  1202. }
  1203.  
  1204. /**
  1205. * Control FPS
  1206. *
  1207. * Контроль FPS
  1208. */
  1209. let nextAnimationFrame = Date.now();
  1210. const oldRequestAnimationFrame = this.requestAnimationFrame;
  1211. this.requestAnimationFrame = async function (e) {
  1212. const FPS = Number(getInput('FPS')) || -1;
  1213. const now = Date.now();
  1214. const delay = nextAnimationFrame - now;
  1215. nextAnimationFrame = Math.max(now, nextAnimationFrame) + Math.min(1e3 / FPS, 1e3);
  1216. if (delay > 0) {
  1217. await new Promise((e) => setTimeout(e, delay));
  1218. }
  1219. oldRequestAnimationFrame(e);
  1220. };
  1221.  
  1222. /**
  1223. * Button List
  1224. *
  1225. * Список кнопочек
  1226. */
  1227. const buttons = {
  1228. getOutland: {
  1229. name: I18N('TO_DO_EVERYTHING'),
  1230. title: I18N('TO_DO_EVERYTHING_TITLE'),
  1231. func: testDoYourBest,
  1232. },
  1233. /*
  1234. doActions: {
  1235. name: I18N('ACTIONS'),
  1236. title: I18N('ACTIONS_TITLE'),
  1237. func: async function () {
  1238. const popupButtons = [
  1239. {
  1240. msg: I18N('OUTLAND'),
  1241. result: function () {
  1242. confShow(`${I18N('RUN_SCRIPT')} ${I18N('OUTLAND')}?`, getOutland);
  1243. },
  1244. title: I18N('OUTLAND_TITLE'),
  1245. },
  1246. {
  1247. msg: I18N('TOWER'),
  1248. result: function () {
  1249. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TOWER')}?`, testTower);
  1250. },
  1251. title: I18N('TOWER_TITLE'),
  1252. },
  1253. {
  1254. msg: I18N('EXPEDITIONS'),
  1255. result: function () {
  1256. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EXPEDITIONS')}?`, checkExpedition);
  1257. },
  1258. title: I18N('EXPEDITIONS_TITLE'),
  1259. },
  1260. {
  1261. msg: I18N('MINIONS'),
  1262. result: function () {
  1263. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MINIONS')}?`, testRaidNodes);
  1264. },
  1265. title: I18N('MINIONS_TITLE'),
  1266. },
  1267. {
  1268. msg: I18N('ESTER_EGGS'),
  1269. result: function () {
  1270. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ESTER_EGGS')}?`, offerFarmAllReward);
  1271. },
  1272. title: I18N('ESTER_EGGS_TITLE'),
  1273. },
  1274. {
  1275. msg: I18N('STORM'),
  1276. result: function () {
  1277. testAdventure('solo');
  1278. },
  1279. title: I18N('STORM_TITLE'),
  1280. },
  1281. {
  1282. msg: I18N('REWARDS'),
  1283. result: function () {
  1284. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS')}?`, questAllFarm);
  1285. },
  1286. title: I18N('REWARDS_TITLE'),
  1287. },
  1288. {
  1289. msg: I18N('MAIL'),
  1290. result: function () {
  1291. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MAIL')}?`, mailGetAll);
  1292. },
  1293. title: I18N('MAIL_TITLE'),
  1294. },
  1295. {
  1296. msg: I18N('SEER'),
  1297. result: function () {
  1298. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SEER')}?`, rollAscension);
  1299. },
  1300. title: I18N('SEER_TITLE'),
  1301. },
  1302. {
  1303. msg: I18N('NY_GIFTS'),
  1304. result: getGiftNewYear,
  1305. title: I18N('NY_GIFTS_TITLE'),
  1306. },
  1307. ];
  1308. popupButtons.push({ result: false, isClose: true })
  1309. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1310. if (typeof answer === 'function') {
  1311. answer();
  1312. }
  1313. }
  1314. },*/
  1315. doOthers: {
  1316. name: I18N('OTHERS'),
  1317. title: I18N('OTHERS_TITLE'),
  1318. func: async function () {
  1319. const popupButtons = [
  1320. /*
  1321. {
  1322. msg: I18N('GET_ENERGY'),
  1323. result: farmStamina,
  1324. title: I18N('GET_ENERGY_TITLE'),
  1325. },
  1326. {
  1327. msg: I18N('ITEM_EXCHANGE'),
  1328. result: fillActive,
  1329. title: I18N('ITEM_EXCHANGE_TITLE'),
  1330. },
  1331. {
  1332. msg: I18N('BUY_SOULS'),
  1333. result: function () {
  1334. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_SOULS')}?`, buyHeroFragments);
  1335. },
  1336. title: I18N('BUY_SOULS_TITLE'),
  1337. },
  1338. {
  1339. msg: I18N('BUY_FOR_GOLD'),
  1340. result: function () {
  1341. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_FOR_GOLD')}?`, buyInStoreForGold);
  1342. },
  1343. title: I18N('BUY_FOR_GOLD_TITLE'),
  1344. },
  1345. {
  1346. msg: I18N('BUY_OUTLAND'),
  1347. result: bossOpenChestPay,
  1348. title: I18N('BUY_OUTLAND_TITLE'),
  1349. },
  1350. {
  1351. msg: I18N('AUTO_RAID_ADVENTURE'),
  1352. result: autoRaidAdventure,
  1353. title: I18N('AUTO_RAID_ADVENTURE_TITLE'),
  1354. },
  1355. {
  1356. msg: I18N('CLAN_STAT'),
  1357. result: clanStatistic,
  1358. title: I18N('CLAN_STAT_TITLE'),
  1359. },
  1360. {
  1361. msg: I18N('EPIC_BRAWL'),
  1362. result: async function () {
  1363. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EPIC_BRAWL')}?`, () => {
  1364. const brawl = new epicBrawl();
  1365. brawl.start();
  1366. });
  1367. },
  1368. title: I18N('EPIC_BRAWL_TITLE'),
  1369. },*/
  1370. {
  1371. msg: I18N('ARTIFACTS_UPGRADE'),
  1372. result: updateArtifacts,
  1373. title: I18N('ARTIFACTS_UPGRADE_TITLE'),
  1374. },
  1375. {
  1376. msg: I18N('SKINS_UPGRADE'),
  1377. result: updateSkins,
  1378. title: I18N('SKINS_UPGRADE_TITLE'),
  1379. },
  1380. {
  1381. msg: I18N('SEASON_REWARD'),
  1382. result: farmBattlePass,
  1383. title: I18N('SEASON_REWARD_TITLE'),
  1384. },
  1385. {
  1386. msg: I18N('SELL_HERO_SOULS'),
  1387. result: sellHeroSoulsForGold,
  1388. title: I18N('SELL_HERO_SOULS_TITLE'),
  1389. },
  1390. {
  1391. msg: I18N('CHANGE_MAP'),
  1392. result: async function () {
  1393. const maps = Object.values(lib.data.seasonAdventure.list)
  1394. .filter((e) => e.map.cells.length > 2)
  1395. .map((i) => ({
  1396. msg: I18N('MAP_NUM', { num: i.id }),
  1397. result: i.id,
  1398. }));
  1399.  
  1400. /*const result = await popup.confirm(I18N('SELECT_ISLAND_MAP'), [
  1401. ...maps,
  1402. { result: false, isClose: true },
  1403. ]);*/
  1404. //тест карта острова
  1405. const result = await popup.confirm(I18N('SELECT_ISLAND_MAP'), [...maps, { result: false, isClose: true }]);
  1406. if (result) {
  1407. cheats.changeIslandMap(result);
  1408. }
  1409. },
  1410. title: I18N('CHANGE_MAP_TITLE'),
  1411. },
  1412. {
  1413. msg: I18N('SHOPS'),
  1414. result: async function () {
  1415. const shopButtons = [{
  1416. msg: I18N('SHOPS_DEFAULT'),
  1417. result: function () {
  1418. cheats.goDefaultShops();
  1419. },
  1420. title: I18N('SHOPS_DEFAULT_TITLE'),
  1421. }, {
  1422. msg: I18N('SECRET_WEALTH'),
  1423. result: function () {
  1424. cheats.goSecretWealthShops();
  1425. },
  1426. title: I18N('SECRET_WEALTH'),
  1427. }];
  1428. for (let i = 0; i < 4; i++) {
  1429. const number = i + 1;
  1430. shopButtons.push({
  1431. msg: I18N('SHOPS_LIST', { number }),
  1432. result: function () {
  1433. cheats.goCustomShops(i);
  1434. },
  1435. title: I18N('SHOPS_LIST_TITLE', { number }),
  1436. })
  1437. }
  1438. shopButtons.push({ result: false, isClose: true })
  1439. const answer = await popup.confirm(I18N('SHOPS_WARNING'), shopButtons);
  1440. if (typeof answer === 'function') {
  1441. answer();
  1442. }
  1443. },
  1444. title: I18N('SHOPS'),
  1445. },
  1446. ];
  1447.  
  1448. popupButtons.push({ result: false, isClose: true })
  1449. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1450. if (typeof answer === 'function') {
  1451. answer();
  1452. }
  1453. }
  1454. },
  1455. testTitanArena: {
  1456. name: I18N('TITAN_ARENA'),
  1457. title: I18N('TITAN_ARENA_TITLE'),
  1458. func: function () {
  1459. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TITAN_ARENA')}?`, testTitanArena);
  1460. },
  1461. },
  1462. /* тест подземка есть в сделать все
  1463. testDungeon: {
  1464. name: I18N('DUNGEON'),
  1465. title: I18N('DUNGEON_TITLE'),
  1466. func: function () {
  1467. confShow(`${I18N('RUN_SCRIPT')} ${I18N('DUNGEON')}?`, testDungeon);
  1468. },
  1469. hide: true,
  1470. },*/
  1471. //тест подземка 2
  1472. DungeonFull: {
  1473. name: I18N('DUNGEON2'),
  1474. title: I18N('DUNGEON_FULL_TITLE'),
  1475. func: function () {
  1476. confShow(`${I18N('RUN_SCRIPT')} ${I18N('DUNGEON_FULL_TITLE')}?`, DungeonFull);
  1477. },
  1478. },
  1479. //остановить подземелье
  1480. stopDungeon: {
  1481. name: I18N('STOP_DUNGEON'),
  1482. title: I18N('STOP_DUNGEON_TITLE'),
  1483. func: function () {
  1484. confShow(`${I18N('STOP_SCRIPT')} ${I18N('STOP_DUNGEON_TITLE')}?`, stopDungeon);
  1485. },
  1486. },
  1487. // Архидемон
  1488. bossRatingEvent: {
  1489. name: I18N('ARCHDEMON'),
  1490. title: I18N('ARCHDEMON_TITLE'),
  1491. func: function () {
  1492. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ARCHDEMON')}?`, bossRatingEvent);
  1493. },
  1494. hide: true,
  1495. },
  1496. /*
  1497. // Горнило душ
  1498. bossRatingEvent: {
  1499. name: I18N('CRUCIBLE_SOULS'),
  1500. title: I18N('CRUCIBLE_SOULS_TITLE'),
  1501. func: function () {
  1502. confShow(`${I18N('RUN_SCRIPT')} ${I18N('CRUCIBLE_SOULS')}?`, bossRatingEventSouls);
  1503. },
  1504. },*/
  1505. // Буря
  1506. /*testAdventure2: {
  1507. name: I18N('STORM'),
  1508. title: I18N('STORM_TITLE'),
  1509. func: () => {
  1510. testAdventure2('solo');
  1511. },
  1512. },*/
  1513. rewardsAndMailFarm: {
  1514. name: I18N('REWARDS_AND_MAIL'),
  1515. title: I18N('REWARDS_AND_MAIL_TITLE'),
  1516. func: function () {
  1517. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS_AND_MAIL')}?`, rewardsAndMailFarm);
  1518. },
  1519. },
  1520. //тест прислужники
  1521. testRaidNodes: {
  1522. name: I18N('MINIONS'),
  1523. title: I18N('MINIONS_TITLE'),
  1524. func: function () {
  1525. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MINIONS')}?`, testRaidNodes);
  1526. },
  1527. },
  1528. testAdventure: {
  1529. name: I18N('ADVENTURE'),
  1530. title: I18N('ADVENTURE_TITLE'),
  1531. func: () => {
  1532. testAdventure();
  1533. },
  1534. },
  1535. goToSanctuary: {
  1536. name: I18N('SANCTUARY'),
  1537. title: I18N('SANCTUARY_TITLE'),
  1538. func: cheats.goSanctuary,
  1539. },
  1540. goToClanWar: {
  1541. name: I18N('GUILD_WAR'),
  1542. title: I18N('GUILD_WAR_TITLE'),
  1543. func: cheats.goClanWar,
  1544. },
  1545. dailyQuests: {
  1546. name: I18N('DAILY_QUESTS'),
  1547. title: I18N('DAILY_QUESTS_TITLE'),
  1548. func: async function () {
  1549. const quests = new dailyQuests(() => { }, () => { });
  1550. await quests.autoInit();
  1551. quests.start();
  1552. },
  1553. },
  1554. //подарок др
  1555. /*NewYearGift_Clan: {
  1556. name: I18N('New_Year_Clan'),
  1557. title: I18N('New_Year_Clan_TITLE'),
  1558. func: function () {
  1559. confShow(`${I18N('RUN_SCRIPT')} ${I18N('New_Year_Clan_TITLE')}?`, NewYearGift_Clan);
  1560. },
  1561. },*/
  1562. newDay: {
  1563. name: I18N('SYNC'),
  1564. title: I18N('SYNC_TITLE'),
  1565. func: function () {
  1566. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SYNC')}?`, cheats.refreshGame);
  1567. },
  1568. },
  1569. }
  1570. /**
  1571. * Display buttons
  1572. *
  1573. * Вывести кнопочки
  1574. */
  1575. function addControlButtons() {
  1576. for (let name in buttons) {
  1577. button = buttons[name];
  1578. if (button.hide) {
  1579. continue;
  1580. }
  1581. button['button'] = scriptMenu.addButton(button.name, button.func, button.title);
  1582. }
  1583. }
  1584. /**
  1585. * Adds links
  1586. *
  1587. * Добавляет ссылки
  1588. */
  1589. function addBottomUrls() {
  1590. scriptMenu.addHeader(I18N('BOTTOM_URLS'));
  1591. }
  1592. /**
  1593. * Stop repetition of the mission
  1594. *
  1595. * Остановить повтор миссии
  1596. */
  1597. let isStopSendMission = false;
  1598. /**
  1599. * There is a repetition of the mission
  1600. *
  1601. * Идет повтор миссии
  1602. */
  1603. let isSendsMission = false;
  1604. /**
  1605. * Data on the past mission
  1606. *
  1607. * Данные о прошедшей мисии
  1608. */
  1609. let lastMissionStart = {}
  1610. /**
  1611. * Start time of the last battle in the company
  1612. *
  1613. * Время начала последнего боя в кампании
  1614. */
  1615. let lastMissionBattleStart = 0;
  1616. /**
  1617. * Data for calculating the last battle with the boss
  1618. *
  1619. * Данные для расчете последнего боя с боссом
  1620. */
  1621. let lastBossBattle = null;
  1622. /**
  1623. * Information about the last battle
  1624. *
  1625. * Данные о прошедшей битве
  1626. */
  1627. let lastBattleArg = {}
  1628. let lastBossBattleStart = null;
  1629. this.addBattleTimer = 4;
  1630. this.invasionTimer = 2500;
  1631. /**
  1632. * The name of the function of the beginning of the battle
  1633. *
  1634. * Имя функции начала боя
  1635. */
  1636. let nameFuncStartBattle = '';
  1637. /**
  1638. * The name of the function of the end of the battle
  1639. *
  1640. * Имя функции конца боя
  1641. */
  1642. let nameFuncEndBattle = '';
  1643. /**
  1644. * Data for calculating the last battle
  1645. *
  1646. * Данные для расчета последнего боя
  1647. */
  1648. let lastBattleInfo = null;
  1649. /**
  1650. * The ability to cancel the battle
  1651. *
  1652. * Возможность отменить бой
  1653. */
  1654. let isCancalBattle = true;
  1655.  
  1656. /**
  1657. * Certificator of the last open nesting doll
  1658. *
  1659. * Идетификатор последней открытой матрешки
  1660. */
  1661. let lastRussianDollId = null;
  1662. /**
  1663. * Cancel the training guide
  1664. *
  1665. * Отменить обучающее руководство
  1666. */
  1667. this.isCanceledTutorial = false;
  1668.  
  1669. /**
  1670. * Data from the last question of the quiz
  1671. *
  1672. * Данные последнего вопроса викторины
  1673. */
  1674. let lastQuestion = null;
  1675. /**
  1676. * Answer to the last question of the quiz
  1677. *
  1678. * Ответ на последний вопрос викторины
  1679. */
  1680. let lastAnswer = null;
  1681. /**
  1682. * Flag for opening keys or titan artifact spheres
  1683. *
  1684. * Флаг открытия ключей или сфер артефактов титанов
  1685. */
  1686. let artifactChestOpen = false;
  1687. /**
  1688. * The name of the function to open keys or orbs of titan artifacts
  1689. *
  1690. * Имя функции открытия ключей или сфер артефактов титанов
  1691. */
  1692. let artifactChestOpenCallName = '';
  1693. let correctShowOpenArtifact = 0;
  1694. /**
  1695. * Data for the last battle in the dungeon
  1696. * (Fix endless cards)
  1697. *
  1698. * Данные для последнего боя в подземке
  1699. * (Исправление бесконечных карт)
  1700. */
  1701. let lastDungeonBattleData = null;
  1702. /**
  1703. * Start time of the last battle in the dungeon
  1704. *
  1705. * Время начала последнего боя в подземелье
  1706. */
  1707. let lastDungeonBattleStart = 0;
  1708. /**
  1709. * Subscription end time
  1710. *
  1711. * Время окончания подписки
  1712. */
  1713. let subEndTime = 0;
  1714. /**
  1715. * Number of prediction cards
  1716. *
  1717. * Количество карт предсказаний
  1718. */
  1719. let countPredictionCard = 0;
  1720.  
  1721. /**
  1722. * Brawl pack
  1723. *
  1724. * Пачка для потасовок
  1725. */
  1726. let brawlsPack = null;
  1727. /**
  1728. * Autobrawl started
  1729. *
  1730. * Автопотасовка запущена
  1731. */
  1732. let isBrawlsAutoStart = false;
  1733. let clanDominationGetInfo = null;
  1734. /**
  1735. * Copies the text to the clipboard
  1736. *
  1737. * Копирует тест в буфер обмена
  1738. * @param {*} text copied text // копируемый текст
  1739. */
  1740. function copyText(text) {
  1741. let copyTextarea = document.createElement("textarea");
  1742. copyTextarea.style.opacity = "0";
  1743. copyTextarea.textContent = text;
  1744. document.body.appendChild(copyTextarea);
  1745. copyTextarea.select();
  1746. document.execCommand("copy");
  1747. document.body.removeChild(copyTextarea);
  1748. delete copyTextarea;
  1749. }
  1750. /**
  1751. * Returns the history of requests
  1752. *
  1753. * Возвращает историю запросов
  1754. */
  1755. this.getRequestHistory = function() {
  1756. return requestHistory;
  1757. }
  1758. /**
  1759. * Generates a random integer from min to max
  1760. *
  1761. * Гененирует случайное целое число от min до max
  1762. */
  1763. const random = function (min, max) {
  1764. return Math.floor(Math.random() * (max - min + 1) + min);
  1765. }
  1766. const randf = function (min, max) {
  1767. return Math.random() * (max - min + 1) + min;
  1768. };
  1769. /**
  1770. * Clearing the request history
  1771. *
  1772. * Очистка истоии запросов
  1773. */
  1774. setInterval(function () {
  1775. let now = Date.now();
  1776. for (let i in requestHistory) {
  1777. const time = +i.split('_')[0];
  1778. if (now - time > 300000) {
  1779. delete requestHistory[i];
  1780. }
  1781. }
  1782. }, 300000);
  1783. /**
  1784. * Displays the dialog box
  1785. *
  1786. * Отображает диалоговое окно
  1787. */
  1788. function confShow(message, yesCallback, noCallback) {
  1789. let buts = [];
  1790. message = message || I18N('DO_YOU_WANT');
  1791. noCallback = noCallback || (() => {});
  1792. if (yesCallback) {
  1793. buts = [
  1794. { msg: I18N('BTN_RUN'), result: true},
  1795. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true},
  1796. ]
  1797. } else {
  1798. yesCallback = () => {};
  1799. buts = [
  1800. { msg: I18N('BTN_OK'), result: true},
  1801. ];
  1802. }
  1803. popup.confirm(message, buts).then((e) => {
  1804. // dialogPromice = null;
  1805. if (e) {
  1806. yesCallback();
  1807. } else {
  1808. noCallback();
  1809. }
  1810. });
  1811. }
  1812. /**
  1813. * Override/proxy the method for creating a WS package send
  1814. *
  1815. * Переопределяем/проксируем метод создания отправки WS пакета
  1816. */
  1817. WebSocket.prototype.send = function (data) {
  1818. if (!this.isSetOnMessage) {
  1819. const oldOnmessage = this.onmessage;
  1820. this.onmessage = function (event) {
  1821. try {
  1822. const data = JSON.parse(event.data);
  1823. if (!this.isWebSocketLogin && data.result.type == "iframeEvent.login") {
  1824. this.isWebSocketLogin = true;
  1825. } else if (data.result.type == "iframeEvent.login") {
  1826. return;
  1827. }
  1828. } catch (e) { }
  1829. return oldOnmessage.apply(this, arguments);
  1830. }
  1831. this.isSetOnMessage = true;
  1832. }
  1833. original.SendWebSocket.call(this, data);
  1834. }
  1835. /**
  1836. * Overriding/Proxying the Ajax Request Creation Method
  1837. *
  1838. * Переопределяем/проксируем метод создания Ajax запроса
  1839. */
  1840. XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
  1841. this.uniqid = Date.now() + '_' + random(1000000, 10000000);
  1842. this.errorRequest = false;
  1843. if (method == 'POST' && url.includes('.nextersglobal.com/api/') && /api\/$/.test(url)) {
  1844. if (!apiUrl) {
  1845. apiUrl = url;
  1846. const socialInfo = /heroes-(.+?)\./.exec(apiUrl);
  1847. console.log(socialInfo);
  1848. }
  1849. requestHistory[this.uniqid] = {
  1850. method,
  1851. url,
  1852. error: [],
  1853. headers: {},
  1854. request: null,
  1855. response: null,
  1856. signature: [],
  1857. calls: {},
  1858. };
  1859. } else if (method == 'POST' && url.includes('error.nextersglobal.com/client/')) {
  1860. this.errorRequest = true;
  1861. }
  1862. return original.open.call(this, method, url, async, user, password);
  1863. };
  1864. /**
  1865. * Overriding/Proxying the header setting method for the AJAX request
  1866. *
  1867. * Переопределяем/проксируем метод установки заголовков для AJAX запроса
  1868. */
  1869. XMLHttpRequest.prototype.setRequestHeader = function (name, value, check) {
  1870. if (this.uniqid in requestHistory) {
  1871. requestHistory[this.uniqid].headers[name] = value;
  1872. } else {
  1873. check = true;
  1874. }
  1875.  
  1876. if (name == 'X-Auth-Signature') {
  1877. requestHistory[this.uniqid].signature.push(value);
  1878. if (!check) {
  1879. return;
  1880. }
  1881. }
  1882.  
  1883. return original.setRequestHeader.call(this, name, value);
  1884. };
  1885. /**
  1886. * Overriding/Proxying the AJAX Request Sending Method
  1887. *
  1888. * Переопределяем/проксируем метод отправки AJAX запроса
  1889. */
  1890. XMLHttpRequest.prototype.send = async function (sourceData) {
  1891. if (this.uniqid in requestHistory) {
  1892. let tempData = null;
  1893. if (getClass(sourceData) == "ArrayBuffer") {
  1894. tempData = decoder.decode(sourceData);
  1895. } else {
  1896. tempData = sourceData;
  1897. }
  1898. requestHistory[this.uniqid].request = tempData;
  1899. let headers = requestHistory[this.uniqid].headers;
  1900. lastHeaders = Object.assign({}, headers);
  1901. /**
  1902. * Game loading event
  1903. *
  1904. * Событие загрузки игры
  1905. */
  1906. if (headers["X-Request-Id"] > 2 && !isLoadGame) {
  1907. isLoadGame = true;
  1908. await lib.load();
  1909. addControls();
  1910. addControlButtons();
  1911. addBottomUrls();
  1912.  
  1913. //if (isChecked('sendExpedition')) {
  1914. checkExpedition(); //экспедиции на авто при входе в игру
  1915. //}
  1916.  
  1917. getAutoGifts();
  1918.  
  1919. cheats.activateHacks();
  1920.  
  1921. justInfo();
  1922. if (isChecked('dailyQuests')) {
  1923. testDailyQuests();
  1924. }
  1925.  
  1926. if (isChecked('buyForGold')) {
  1927. buyInStoreForGold();
  1928. }
  1929. }
  1930. /**
  1931. * Outgoing request data processing
  1932. *
  1933. * Обработка данных исходящего запроса
  1934. */
  1935. sourceData = await checkChangeSend.call(this, sourceData, tempData);
  1936. /**
  1937. * Handling incoming request data
  1938. *
  1939. * Обработка данных входящего запроса
  1940. */
  1941. const oldReady = this.onreadystatechange;
  1942. this.onreadystatechange = async function (e) {
  1943. if (this.errorRequest) {
  1944. return oldReady.apply(this, arguments);
  1945. }
  1946. if(this.readyState == 4 && this.status == 200) {
  1947. isTextResponse = this.responseType === "text" || this.responseType === "";
  1948. let response = isTextResponse ? this.responseText : this.response;
  1949. requestHistory[this.uniqid].response = response;
  1950. /**
  1951. * Replacing incoming request data
  1952. *
  1953. * Заменна данных входящего запроса
  1954. */
  1955. if (isTextResponse) {
  1956. await checkChangeResponse.call(this, response);
  1957. }
  1958. /**
  1959. * A function to run after the request is executed
  1960. *
  1961. * Функция запускаемая после выполения запроса
  1962. */
  1963. if (typeof this.onReadySuccess == 'function') {
  1964. setTimeout(this.onReadySuccess, 500);
  1965. }
  1966. /** Удаляем из истории запросов битвы с боссом */
  1967. if ('invasion_bossStart' in requestHistory[this.uniqid].calls) delete requestHistory[this.uniqid];
  1968. }
  1969. if (oldReady) {
  1970. return oldReady.apply(this, arguments);
  1971. }
  1972. }
  1973. }
  1974. if (this.errorRequest) {
  1975. const oldReady = this.onreadystatechange;
  1976. this.onreadystatechange = function () {
  1977. Object.defineProperty(this, 'status', {
  1978. writable: true
  1979. });
  1980. this.status = 200;
  1981. Object.defineProperty(this, 'readyState', {
  1982. writable: true
  1983. });
  1984. this.readyState = 4;
  1985. Object.defineProperty(this, 'responseText', {
  1986. writable: true
  1987. });
  1988. this.responseText = JSON.stringify({
  1989. "result": true
  1990. });
  1991. if (typeof this.onReadySuccess == 'function') {
  1992. setTimeout(this.onReadySuccess, 200);
  1993. }
  1994. return oldReady.apply(this, arguments);
  1995. }
  1996. this.onreadystatechange();
  1997. } else {
  1998. try {
  1999. return original.send.call(this, sourceData);
  2000. } catch(e) {
  2001. debugger;
  2002. }
  2003.  
  2004. }
  2005. };
  2006. /**
  2007. * Processing and substitution of outgoing data
  2008. *
  2009. * Обработка и подмена исходящих данных
  2010. */
  2011. async function checkChangeSend(sourceData, tempData) {
  2012. try {
  2013. /**
  2014. * A function that replaces battle data with incorrect ones to cancel combatя
  2015. *
  2016. * Функция заменяющая данные боя на неверные для отмены боя
  2017. */
  2018. const fixBattle = function (heroes) {
  2019. for (const ids in heroes) {
  2020. hero = heroes[ids];
  2021. hero.energy = random(1, 999);
  2022. if (hero.hp > 0) {
  2023. hero.hp = random(1, hero.hp);
  2024. }
  2025. }
  2026. }
  2027. /**
  2028. * Dialog window 2
  2029. *
  2030. * Диалоговое окно 2
  2031. */
  2032. const showMsg = async function (msg, ansF, ansS) {
  2033. if (typeof popup == 'object') {
  2034. return await popup.confirm(msg, [
  2035. {msg: ansF, result: false},
  2036. {msg: ansS, result: true},
  2037. ]);
  2038. } else {
  2039. return !confirm(`${msg}\n ${ansF} (${I18N('BTN_OK')})\n ${ansS} (${I18N('BTN_CANCEL')})`);
  2040. }
  2041. }
  2042. /**
  2043. * Dialog window 3
  2044. *
  2045. * Диалоговое окно 3
  2046. */
  2047. const showMsgs = async function (msg, ansF, ansS, ansT) {
  2048. return await popup.confirm(msg, [
  2049. {msg: ansF, result: 0},
  2050. {msg: ansS, result: 1},
  2051. {msg: ansT, result: 2},
  2052. ]);
  2053. }
  2054.  
  2055. let changeRequest = false;
  2056. testData = JSON.parse(tempData);
  2057. for (const call of testData.calls) {
  2058. if (!artifactChestOpen) {
  2059. requestHistory[this.uniqid].calls[call.name] = call.ident;
  2060. }
  2061. /**
  2062. * Cancellation of the battle in adventures, on VG and with minions of Asgard
  2063. * Отмена боя в приключениях, на ВГ и с прислужниками Асгарда
  2064. */
  2065. if ((call.name == 'adventure_endBattle' ||
  2066. call.name == 'adventureSolo_endBattle' ||
  2067. call.name == 'clanWarEndBattle' &&
  2068. isChecked('cancelBattle') ||
  2069. call.name == 'crossClanWar_endBattle' &&
  2070. isChecked('cancelBattle') ||
  2071. call.name == 'brawl_endBattle' ||
  2072. call.name == 'towerEndBattle' ||
  2073. call.name == 'invasion_bossEnd' ||
  2074. call.name == 'bossEndBattle' ||
  2075. call.name == 'clanRaid_endNodeBattle') &&
  2076. isCancalBattle) {
  2077. nameFuncEndBattle = call.name;
  2078. if (!call.args.result.win) {
  2079. let resultPopup = false;
  2080. if (call.name == 'adventure_endBattle' ||
  2081. call.name == 'invasion_bossEnd' ||
  2082. call.name == 'bossEndBattle' ||
  2083. call.name == 'adventureSolo_endBattle') {
  2084. resultPopup = await showMsgs(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  2085. } else if (call.name == 'clanWarEndBattle' ||
  2086. call.name == 'crossClanWar_endBattle') {
  2087. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_AUTO_F5'));
  2088. } else {
  2089. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'));
  2090. }
  2091. if (resultPopup) {
  2092. if (call.name == 'invasion_bossEnd') {
  2093. this.errorRequest = true;
  2094. }
  2095. fixBattle(call.args.progress[0].attackers.heroes);
  2096. fixBattle(call.args.progress[0].defenders.heroes);
  2097. changeRequest = true;
  2098. if (resultPopup > 1) {
  2099. this.onReadySuccess = testAutoBattle;
  2100. // setTimeout(bossBattle, 1000);
  2101. }
  2102. }
  2103. } else if (call.args.result.stars < 3 && call.name == 'towerEndBattle') {
  2104. resultPopup = await showMsg(I18N('LOST_HEROES'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  2105. if (resultPopup) {
  2106. fixBattle(call.args.progress[0].attackers.heroes);
  2107. fixBattle(call.args.progress[0].defenders.heroes);
  2108. changeRequest = true;
  2109. if (resultPopup > 1) {
  2110. this.onReadySuccess = testAutoBattle;
  2111. }
  2112. }
  2113. }
  2114. // Потасовки
  2115. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_endBattle') {}
  2116. }
  2117. /**
  2118. * Save pack for Brawls
  2119. *
  2120. * Сохраняем пачку для потасовок
  2121. */
  2122. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_startBattle') {
  2123. console.log(JSON.stringify(call.args));
  2124. brawlsPack = call.args;
  2125. if (
  2126. await popup.confirm(
  2127. I18N('START_AUTO_BRAWLS'),
  2128. [
  2129. { msg: I18N('BTN_NO'), result: false },
  2130. { msg: I18N('BTN_YES'), result: true },
  2131. ],
  2132. [
  2133. {
  2134. name: 'isAuto',
  2135. label: I18N('BRAWL_AUTO_PACK'),
  2136. checked: false,
  2137. },
  2138. ]
  2139. )
  2140. ) {
  2141. isBrawlsAutoStart = true;
  2142. const isAuto = popup.getCheckBoxes().find((e) => e.name === 'isAuto');
  2143. this.errorRequest = true;
  2144. testBrawls(isAuto.checked);
  2145. }
  2146. }
  2147. /**
  2148. * Canceled fight in Asgard
  2149. * Отмена боя в Асгарде
  2150. */
  2151. if (call.name == 'clanRaid_endBossBattle' && isChecked('cancelBattle')) {
  2152. const bossDamage = call.args.progress[0].defenders.heroes[1].extra;
  2153. let maxDamage = bossDamage.damageTaken + bossDamage.damageTakenNextLevel;
  2154. const lastDamage = maxDamage;
  2155. const resultPopup = await popup.confirm(
  2156. `${I18N('MSG_YOU_APPLIED')} ${lastDamage.toLocaleString()} ${I18N('MSG_DAMAGE')}.`,
  2157. [
  2158. { msg: I18N('BTN_OK'), result: false },
  2159. { msg: I18N('BTN_AUTO_F5'), result: 1 },
  2160. { msg: I18N('BTN_TRY_FIX_IT'), result: 2 },
  2161. ],
  2162. [
  2163. {
  2164. name: 'isStat',
  2165. label: I18N('CALC_STAT'),
  2166. checked: false,
  2167. },
  2168. ]
  2169. );
  2170. if (resultPopup) {
  2171. if (resultPopup == 2) {
  2172. setProgress(I18N('LETS_FIX'), false);
  2173. await new Promise((e) => setTimeout(e, 0));
  2174. const cloneBattle = structuredClone(lastBossBattle);
  2175. const endTime = cloneBattle.endTime - 1e4;
  2176. console.log('fixBossBattleStart');
  2177. const COUNT = 300;
  2178. let maxCount = 0;
  2179. let duration = 0;
  2180. let avgTime = 0;
  2181. for (let count = 1; count <= COUNT; count++) {
  2182. maxCount = count;
  2183. const start = Date.now();
  2184. const timer = randf(1.3, 10.3);
  2185. if ((endTime + avgTime) < start) {
  2186. break;
  2187. }
  2188. await new Promise((e) =>
  2189. setTimeout(() => {
  2190. const maxDmg = maxDamage.toLocaleString();
  2191. const avg = avgTime.toFixed(2);
  2192. const msg = `${I18N('LETS_FIX')} ${maxCount}/${COUNT}<br/>${maxDmg}<br/>${avg}ms`;
  2193. setProgress(msg, false);
  2194. e();
  2195. }, 0)
  2196. );
  2197. try {
  2198. resultBattle = await Calc(cloneBattle);
  2199. } catch (e) {
  2200. continue;
  2201. }
  2202. duration += Date.now() - start;
  2203. avgTime = duration / count;
  2204. const extraDmg = resultBattle.progress[0].defenders.heroes[1].extra;
  2205. const bossDamage = extraDmg.damageTaken + extraDmg.damageTakenNextLevel;
  2206. console.log(count + '\t' + timer.toFixed(2) + '\t' + bossDamage.toLocaleString());
  2207. if (bossDamage > maxDamage) {
  2208. maxDamage = bossDamage;
  2209. call.args.result = resultBattle.result;
  2210. call.args.progress = resultBattle.progress;
  2211. }
  2212. cloneBattle.progress = [{ attackers: { input: ['auto', 0, 0, 'auto', 0, timer] } }];
  2213. }
  2214. let msgResult = I18N('DAMAGE_NO_FIXED', {
  2215. lastDamage: lastDamage.toLocaleString()
  2216. });
  2217. if (maxDamage > lastDamage) {
  2218. msgResult = I18N('DAMAGE_FIXED', {
  2219. lastDamage: lastDamage.toLocaleString(),
  2220. maxDamage: maxDamage.toLocaleString(),
  2221. });
  2222. }
  2223. console.log(lastDamage, '>' ,maxDamage);
  2224. setProgress(
  2225. msgResult + '<br/>' +
  2226. I18N('COUNT_FIXED', {
  2227. count: maxCount,
  2228. }),
  2229. false,
  2230. hideProgress
  2231. );
  2232. } else {
  2233. fixBattle(call.args.progress[0].attackers.heroes);
  2234. fixBattle(call.args.progress[0].defenders.heroes);
  2235. }
  2236. changeRequest = true;
  2237. }
  2238. const isStat = popup.getCheckBoxes().find((e) => e.name === 'isStat');
  2239. if (isStat.checked) {
  2240. this.onReadySuccess = testBossBattle;
  2241. }
  2242. }
  2243. /**
  2244. * Save the Asgard Boss Attack Pack
  2245. * Сохраняем пачку для атаки босса Асгарда
  2246. */
  2247. if (call.name == 'clanRaid_startBossBattle') {
  2248. console.log(JSON.stringify(call.args));
  2249. }
  2250. /**
  2251. * Saving the request to start the last battle
  2252. * Сохранение запроса начала последнего боя
  2253. */
  2254. if (call.name == 'clanWarAttack' ||
  2255. call.name == 'crossClanWar_startBattle' ||
  2256. call.name == 'adventure_turnStartBattle' ||
  2257. call.name == 'bossAttack' ||
  2258. call.name == 'invasion_bossStart' ||
  2259. call.name == 'towerStartBattle') {
  2260. nameFuncStartBattle = call.name;
  2261. lastBattleArg = call.args;
  2262.  
  2263. if (call.name == 'invasion_bossStart') {
  2264. const timePassed = Date.now() - lastBossBattleStart;
  2265. if (timePassed < invasionTimer) {
  2266. await new Promise((e) => setTimeout(e, invasionTimer - timePassed));
  2267. }
  2268. invasionTimer -= 1;
  2269. }
  2270. lastBossBattleStart = Date.now();
  2271. }
  2272. if (call.name == 'invasion_bossEnd') {
  2273. const lastBattle = lastBattleInfo;
  2274. if (lastBattle && call.args.result.win) {
  2275. lastBattle.progress = call.args.progress;
  2276. const result = await Calc(lastBattle);
  2277. let timer = getTimer(result.battleTime, 1) + addBattleTimer;
  2278. const period = Math.ceil((Date.now() - lastBossBattleStart) / 1000);
  2279. console.log(timer, period);
  2280. if (period < timer) {
  2281. timer = timer - period;
  2282. await countdownTimer(timer);
  2283. }
  2284. }
  2285. }
  2286. /**
  2287. * Disable spending divination cards
  2288. * Отключить трату карт предсказаний
  2289. */
  2290. if (call.name == 'dungeonEndBattle') {
  2291. if (call.args.isRaid) {
  2292. if (countPredictionCard <= 0) {
  2293. delete call.args.isRaid;
  2294. changeRequest = true;
  2295. } else if (countPredictionCard > 0) {
  2296. countPredictionCard--;
  2297. }
  2298. }
  2299. console.log(`Cards: ${countPredictionCard}`);
  2300. /**
  2301. * Fix endless cards
  2302. * Исправление бесконечных карт
  2303. */
  2304. const lastBattle = lastDungeonBattleData;
  2305. if (lastBattle && !call.args.isRaid) {
  2306. if (changeRequest) {
  2307. lastBattle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2308. } else {
  2309. lastBattle.progress = call.args.progress;
  2310. }
  2311. const result = await Calc(lastBattle);
  2312.  
  2313. if (changeRequest) {
  2314. call.args.progress = result.progress;
  2315. call.args.result = result.result;
  2316. }
  2317.  
  2318. let timer = result.battleTimer + addBattleTimer;
  2319. const period = Math.ceil((Date.now() - lastDungeonBattleStart) / 1000);
  2320. console.log(timer, period);
  2321. if (period < timer) {
  2322. timer = timer - period;
  2323. await countdownTimer(timer);
  2324. }
  2325. }
  2326. }
  2327. /**
  2328. * Quiz Answer
  2329. * Ответ на викторину
  2330. */
  2331. if (call.name == 'quizAnswer') {
  2332. /**
  2333. * Automatically changes the answer to the correct one if there is one.
  2334. * Автоматически меняет ответ на правильный если он есть
  2335. */
  2336. if (lastAnswer && isChecked('getAnswer')) {
  2337. call.args.answerId = lastAnswer;
  2338. lastAnswer = null;
  2339. changeRequest = true;
  2340. }
  2341. }
  2342. /**
  2343. * Present
  2344. * Подарки
  2345. */
  2346. if (call.name == 'freebieCheck') {
  2347. freebieCheckInfo = call;
  2348. }
  2349. /** missionTimer */
  2350. if (call.name == 'missionEnd' && missionBattle) {
  2351. let startTimer = false;
  2352. if (!call.args.result.win) {
  2353. startTimer = await popup.confirm(I18N('DEFEAT_TURN_TIMER'), [
  2354. { msg: I18N('BTN_NO'), result: false },
  2355. { msg: I18N('BTN_YES'), result: true },
  2356. ]);
  2357. }
  2358. if (call.args.result.win || startTimer) {
  2359. missionBattle.progress = call.args.progress;
  2360. missionBattle.result = call.args.result;
  2361. const result = await Calc(missionBattle);
  2362. let timer = result.battleTimer + addBattleTimer;
  2363. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  2364. if (period < timer) {
  2365. timer = timer - period;
  2366. await countdownTimer(timer);
  2367. }
  2368. missionBattle = null;
  2369. } else {
  2370. this.errorRequest = true;
  2371. }
  2372. }
  2373. /**
  2374. * Getting mission data for auto-repeat
  2375. * Получение данных миссии для автоповтора
  2376. */
  2377. if (isChecked('repeatMission') &&
  2378. call.name == 'missionEnd') {
  2379. let missionInfo = {
  2380. id: call.args.id,
  2381. result: call.args.result,
  2382. heroes: call.args.progress[0].attackers.heroes,
  2383. count: 0,
  2384. }
  2385. setTimeout(async () => {
  2386. if (!isSendsMission && await popup.confirm(I18N('MSG_REPEAT_MISSION'), [
  2387. { msg: I18N('BTN_REPEAT'), result: true},
  2388. { msg: I18N('BTN_NO'), result: false},
  2389. ])) {
  2390. isStopSendMission = false;
  2391. isSendsMission = true;
  2392. sendsMission(missionInfo);
  2393. }
  2394. }, 0);
  2395. }
  2396. /**
  2397. * Getting mission data
  2398. * Получение данных миссии
  2399. * missionTimer
  2400. */
  2401. if (call.name == 'missionStart') {
  2402. lastMissionStart = call.args;
  2403. lastMissionBattleStart = Date.now();
  2404. }
  2405.  
  2406. /**
  2407. * Specify the quantity for Titan Orbs and Pet Eggs
  2408. * Указать количество для сфер титанов и яиц петов
  2409. */
  2410. if (isChecked('countControl') &&
  2411. (call.name == 'pet_chestOpen' ||
  2412. call.name == 'titanUseSummonCircle') &&
  2413. call.args.amount > 1) {
  2414. const startAmount = call.args.amount;
  2415. call.args.amount = 1;
  2416. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2417. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2418. ]);
  2419. if (result) {
  2420. const item = call.name == 'pet_chestOpen' ? { id: 90, type: 'consumable' } : { id: 13, type: 'coin' };
  2421. cheats.updateInventory({
  2422. [item.type]: {
  2423. [item.id]: -(result - startAmount),
  2424. },
  2425. });
  2426. call.args.amount = result;
  2427. changeRequest = true;
  2428. }
  2429. }
  2430. /**
  2431. * Specify the amount for keys and spheres of titan artifacts
  2432. * Указать колличество для ключей и сфер артефактов титанов
  2433. */
  2434. if (isChecked('countControl') &&
  2435. (call.name == 'artifactChestOpen' ||
  2436. call.name == 'titanArtifactChestOpen') &&
  2437. call.args.amount > 1 &&
  2438. call.args.free &&
  2439. !changeRequest) {
  2440. artifactChestOpenCallName = call.name;
  2441. const startAmount = call.args.amount;
  2442. let result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2443. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount },
  2444. ]);
  2445. if (result) {
  2446. const openChests = result;
  2447. let sphere = result < 10 ? 1 : 10;
  2448.  
  2449. call.args.amount = sphere;
  2450. for (let count = openChests - sphere; count > 0; count -= sphere) {
  2451. if (count < 10) sphere = 1;
  2452. const ident = artifactChestOpenCallName + "_" + count;
  2453. testData.calls.push({
  2454. name: artifactChestOpenCallName,
  2455. args: {
  2456. amount: sphere,
  2457. free: true,
  2458. },
  2459. ident: ident
  2460. });
  2461. if (!Array.isArray(requestHistory[this.uniqid].calls[call.name])) {
  2462. requestHistory[this.uniqid].calls[call.name] = [requestHistory[this.uniqid].calls[call.name]];
  2463. }
  2464. requestHistory[this.uniqid].calls[call.name].push(ident);
  2465. }
  2466. const consumableId = call.name == 'artifactChestOpen' ? 45 : 55;
  2467. cheats.updateInventory({
  2468. consumable: {
  2469. [consumableId]: -(openChests - startAmount),
  2470. },
  2471. });
  2472.  
  2473. artifactChestOpen = true;
  2474. changeRequest = true;
  2475. }
  2476. }
  2477. if (call.name == 'consumableUseLootBox') {
  2478. lastRussianDollId = call.args.libId;
  2479. /**
  2480. * Specify quantity for gold caskets
  2481. * Указать количество для золотых шкатулок
  2482. */
  2483. if (isChecked('countControl') &&
  2484. call.args.libId == 148 &&
  2485. call.args.amount > 1) {
  2486. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2487. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2488. ]);
  2489. call.args.amount = result;
  2490. changeRequest = true;
  2491. }
  2492. if (isChecked('countControl') && call.args.libId >= 362 && call.args.libId <= 389) {
  2493. this.massOpen = call.args.libId;
  2494. }
  2495. }
  2496. /**
  2497. * Changing the maximum number of raids in the campaign
  2498. * Изменение максимального количества рейдов в кампании
  2499. */
  2500. // if (call.name == 'missionRaid') {
  2501. // if (isChecked('countControl') && call.args.times > 1) {
  2502. // const result = +(await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2503. // { msg: I18N('BTN_RUN'), isInput: true, default: call.args.times },
  2504. // ]));
  2505. // call.args.times = result > call.args.times ? call.args.times : result;
  2506. // changeRequest = true;
  2507. // }
  2508. // }
  2509. }
  2510.  
  2511. let headers = requestHistory[this.uniqid].headers;
  2512. if (changeRequest) {
  2513. sourceData = JSON.stringify(testData);
  2514. headers['X-Auth-Signature'] = getSignature(headers, sourceData);
  2515. }
  2516.  
  2517. let signature = headers['X-Auth-Signature'];
  2518. if (signature) {
  2519. original.setRequestHeader.call(this, 'X-Auth-Signature', signature);
  2520. }
  2521. } catch (err) {
  2522. console.log("Request(send, " + this.uniqid + "):\n", sourceData, "Error:\n", err);
  2523. }
  2524. return sourceData;
  2525. }
  2526. /**
  2527. * Processing and substitution of incoming data
  2528. *
  2529. * Обработка и подмена входящих данных
  2530. */
  2531. async function checkChangeResponse(response) {
  2532. try {
  2533. isChange = false;
  2534. let nowTime = Math.round(Date.now() / 1000);
  2535. callsIdent = requestHistory[this.uniqid].calls;
  2536. respond = JSON.parse(response);
  2537. /**
  2538. * If the request returned an error removes the error (removes synchronization errors)
  2539. * Если запрос вернул ошибку удаляет ошибку (убирает ошибки синхронизации)
  2540. */
  2541. if (respond.error) {
  2542. isChange = true;
  2543. console.error(respond.error);
  2544. if (isChecked('showErrors')) {
  2545. popup.confirm(I18N('ERROR_MSG', {
  2546. name: respond.error.name,
  2547. description: respond.error.description,
  2548. }));
  2549. }
  2550. delete respond.error;
  2551. respond.results = [];
  2552. }
  2553. let mainReward = null;
  2554. const allReward = {};
  2555. let countTypeReward = 0;
  2556. let readQuestInfo = false;
  2557. for (const call of respond.results) {
  2558. /**
  2559. * Obtaining initial data for completing quests
  2560. * Получение исходных данных для выполнения квестов
  2561. */
  2562. if (readQuestInfo) {
  2563. questsInfo[call.ident] = call.result.response;
  2564. }
  2565. /**
  2566. * Getting a user ID
  2567. * Получение идетификатора пользователя
  2568. */
  2569. if (call.ident == callsIdent['registration']) {
  2570. userId = call.result.response.userId;
  2571. if (localStorage['userId'] != userId) {
  2572. localStorage['newGiftSendIds'] = '';
  2573. localStorage['userId'] = userId;
  2574. }
  2575. await openOrMigrateDatabase(userId);
  2576. readQuestInfo = true;
  2577. }
  2578. /**
  2579. * Hiding donation offers 1
  2580. * Скрываем предложения доната 1
  2581. */
  2582. if (call.ident == callsIdent['billingGetAll'] && getSaveVal('noOfferDonat')) {
  2583. const billings = call.result.response?.billings;
  2584. const bundle = call.result.response?.bundle;
  2585. if (billings && bundle) {
  2586. call.result.response.billings = [];
  2587. call.result.response.bundle = [];
  2588. isChange = true;
  2589. }
  2590. }
  2591. /**
  2592. * Hiding donation offers 2
  2593. * Скрываем предложения доната 2
  2594. */
  2595. if (getSaveVal('noOfferDonat') &&
  2596. (call.ident == callsIdent['offerGetAll'] ||
  2597. call.ident == callsIdent['specialOffer_getAll'])) {
  2598. let offers = call.result.response;
  2599. if (offers) {
  2600. call.result.response = offers.filter(e => !['addBilling', 'bundleCarousel'].includes(e.type) || ['idleResource'].includes(e.offerType));
  2601. isChange = true;
  2602. }
  2603. }
  2604. /**
  2605. * Hiding donation offers 3
  2606. * Скрываем предложения доната 3
  2607. */
  2608. if (getSaveVal('noOfferDonat') && call.result?.bundleUpdate) {
  2609. delete call.result.bundleUpdate;
  2610. isChange = true;
  2611. }
  2612. /**
  2613. * Copies a quiz question to the clipboard
  2614. * Копирует вопрос викторины в буфер обмена и получает на него ответ если есть
  2615. */
  2616. if (call.ident == callsIdent['quizGetNewQuestion']) {
  2617. let quest = call.result.response;
  2618. console.log(quest.question);
  2619. copyText(quest.question);
  2620. setProgress(I18N('QUESTION_COPY'), true);
  2621. quest.lang = null;
  2622. if (typeof NXFlashVars !== 'undefined') {
  2623. quest.lang = NXFlashVars.interface_lang;
  2624. }
  2625. lastQuestion = quest;
  2626. if (isChecked('getAnswer')) {
  2627. const answer = await getAnswer(lastQuestion);
  2628. let showText = '';
  2629. if (answer) {
  2630. lastAnswer = answer;
  2631. console.log(answer);
  2632. showText = `${I18N('ANSWER_KNOWN')}: ${answer}`;
  2633. } else {
  2634. showText = I18N('ANSWER_NOT_KNOWN');
  2635. }
  2636.  
  2637. try {
  2638. const hint = hintQuest(quest);
  2639. if (hint) {
  2640. showText += I18N('HINT') + hint;
  2641. }
  2642. } catch(e) {}
  2643.  
  2644. setProgress(showText, true);
  2645. }
  2646. }
  2647. /**
  2648. * Submits a question with an answer to the database
  2649. * Отправляет вопрос с ответом в базу данных
  2650. */
  2651. if (call.ident == callsIdent['quizAnswer']) {
  2652. const answer = call.result.response;
  2653. if (lastQuestion) {
  2654. const answerInfo = {
  2655. answer,
  2656. question: lastQuestion,
  2657. lang: null,
  2658. }
  2659. if (typeof NXFlashVars !== 'undefined') {
  2660. answerInfo.lang = NXFlashVars.interface_lang;
  2661. }
  2662. lastQuestion = null;
  2663. setTimeout(sendAnswerInfo, 0, answerInfo);
  2664. }
  2665. }
  2666. /**
  2667. * Get user data
  2668. * Получить даныне пользователя
  2669. */
  2670. if (call.ident == callsIdent['userGetInfo']) {
  2671. let user = call.result.response;
  2672. document.title = user.name;
  2673. userInfo = Object.assign({}, user);
  2674. delete userInfo.refillable;
  2675. if (!questsInfo['userGetInfo']) {
  2676. questsInfo['userGetInfo'] = user;
  2677. }
  2678. }
  2679. /**
  2680. * Start of the battle for recalculation
  2681. * Начало боя для прерасчета
  2682. */
  2683. if (call.ident == callsIdent['clanWarAttack'] ||
  2684. call.ident == callsIdent['crossClanWar_startBattle'] ||
  2685. call.ident == callsIdent['bossAttack'] ||
  2686. call.ident == callsIdent['battleGetReplay'] ||
  2687. call.ident == callsIdent['brawl_startBattle'] ||
  2688. call.ident == callsIdent['adventureSolo_turnStartBattle'] ||
  2689. call.ident == callsIdent['invasion_bossStart'] ||
  2690. call.ident == callsIdent['towerStartBattle'] ||
  2691. call.ident == callsIdent['adventure_turnStartBattle']) {
  2692. let battle = call.result.response.battle || call.result.response.replay;
  2693. if (call.ident == callsIdent['brawl_startBattle'] ||
  2694. call.ident == callsIdent['bossAttack'] ||
  2695. call.ident == callsIdent['towerStartBattle'] ||
  2696. call.ident == callsIdent['invasion_bossStart']) {
  2697. battle = call.result.response;
  2698. }
  2699. lastBattleInfo = battle;
  2700. if (!isChecked('preCalcBattle')) {
  2701. continue;
  2702. }
  2703. setProgress(I18N('BEING_RECALC'));
  2704. let battleDuration = 120;
  2705. try {
  2706. const typeBattle = getBattleType(battle.type);
  2707. battleDuration = +lib.data.battleConfig[typeBattle.split('_')[1]].config.battleDuration;
  2708. } catch (e) { }
  2709. //console.log(battle.type);
  2710. function getBattleInfo(battle, isRandSeed) {
  2711. return new Promise(function (resolve) {
  2712. if (isRandSeed) {
  2713. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  2714. }
  2715. BattleCalc(battle, getBattleType(battle.type), e => resolve(e));
  2716. });
  2717. }
  2718. let actions = [getBattleInfo(battle, false)]
  2719. const countTestBattle = getInput('countTestBattle');
  2720. if (call.ident == callsIdent['battleGetReplay']) {
  2721. battle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2722. }
  2723. for (let i = 0; i < countTestBattle; i++) {
  2724. actions.push(getBattleInfo(battle, true));
  2725. }
  2726. Promise.all(actions)
  2727. .then(e => {
  2728. e = e.map(n => ({win: n.result.win, time: n.battleTime}));
  2729. let firstBattle = e.shift();
  2730. const timer = Math.floor(battleDuration - firstBattle.time);
  2731. const min = ('00' + Math.floor(timer / 60)).slice(-2);
  2732. const sec = ('00' + Math.floor(timer - min * 60)).slice(-2);
  2733. const countWin = e.reduce((w, s) => w + s.win, 0);
  2734. 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)
  2735. });
  2736. }
  2737. //тест сохранки
  2738. /** Запоминаем команды в реплее*/
  2739. if (call.ident == callsIdent['battleGetReplay']) {
  2740. let battle = call.result.response.replay;
  2741. repleyBattle.attackers = battle.attackers;
  2742. repleyBattle.defenders = battle.defenders[0];
  2743. repleyBattle.effects = battle.effects.defenders;
  2744. repleyBattle.state = battle.progress[0].defenders.heroes;
  2745. repleyBattle.seed = battle.seed;
  2746. }
  2747. /** Нападение в турнире*/
  2748. if (call.ident == callsIdent['titanArenaStartBattle']) {
  2749. let bestBattle = getInput('countBattle');
  2750. let unrandom = getInput('needResource');
  2751. let maxPower = getInput('needResource2');
  2752. if (bestBattle * unrandom * maxPower == 0) {
  2753. let battle = call.result.response.battle;
  2754. if (bestBattle == 0) {
  2755. battle.progress = bestLordBattle[battle.typeId]?.progress;
  2756. }
  2757. if (unrandom == 0 && !!repleyBattle.seed) {
  2758. battle.seed = repleyBattle.seed;
  2759. }
  2760. if (maxPower == 0) {
  2761. battle.attackers = getTitansPack(Object.keys(battle.attackers));
  2762. }
  2763. isChange = true;
  2764. }
  2765. }
  2766. /** Тест боев с усилениями команд защиты*/
  2767. if (call.ident == callsIdent['chatAcceptChallenge']) {
  2768. let battle = call.result.response.battle;
  2769. addBuff(battle);
  2770. let testType = getInput('countBattle');
  2771. if (testType.slice(0, 1) == "-") {
  2772. testType = parseInt(testType.slice(1), 10);
  2773. switch (testType) {
  2774. case 1:
  2775. battle.defenders[0] = repleyBattle.defenders;
  2776. break; //наша атака против защиты из реплея
  2777. case 2:
  2778. battle.defenders[0] = repleyBattle.attackers;
  2779. break; //наша атака против атаки из реплея
  2780. case 3:
  2781. battle.attackers = repleyBattle.attackers;
  2782. break; //атака из реплея против защиты в чате
  2783. case 4:
  2784. battle.attackers = repleyBattle.defenders;
  2785. break; //защита из реплея против защиты в чате
  2786. case 5:
  2787. battle.attackers = repleyBattle.attackers;
  2788. battle.defenders[0] = repleyBattle.defenders;
  2789. break; //атака из реплея против защиты из реплея
  2790. case 6:
  2791. battle.attackers = repleyBattle.defenders;
  2792. battle.defenders[0] = repleyBattle.attackers;
  2793. break; //защита из реплея против атаки из реплея
  2794. case 7:
  2795. battle.attackers = repleyBattle.attackers;
  2796. battle.defenders[0] = repleyBattle.attackers;
  2797. break; //атака из реплея против атаки из реплея
  2798. case 8:
  2799. battle.attackers = repleyBattle.defenders;
  2800. battle.defenders[0] = repleyBattle.defenders;
  2801. break; //защита из реплея против защиты из реплея
  2802. case 15:
  2803. battle.attackers = repleyBattle.defenders;
  2804. battle.defenders[0] = repleyBattle.defenders;
  2805. break; //защита из реплея против защиты из реплея
  2806. }
  2807. }
  2808.  
  2809. isChange = true;
  2810. }
  2811. /** Тест боев с усилениями команд защиты тренировках*/
  2812. if (call.ident == callsIdent['demoBattles_startBattle']) {
  2813. let battle = call.result.response.battle;
  2814. addBuff(battle);
  2815. let testType = getInput('countBattle');
  2816. if (testType.slice(0, 1) == "-") {
  2817. testType = parseInt(testType.slice(1), 10);
  2818. switch (testType) {
  2819. case 1:
  2820. battle.defenders[0] = repleyBattle.defenders;
  2821. break; //наша атака против защиты из реплея
  2822. case 2:
  2823. battle.defenders[0] = repleyBattle.attackers;
  2824. break; //наша атака против атаки из реплея
  2825. case 3:
  2826. battle.attackers = repleyBattle.attackers;
  2827. break; //атака из реплея против защиты в чате
  2828. case 4:
  2829. battle.attackers = repleyBattle.defenders;
  2830. break; //защита из реплея против защиты в чате
  2831. case 5:
  2832. battle.attackers = repleyBattle.attackers;
  2833. battle.defenders[0] = repleyBattle.defenders;
  2834. break; //атака из реплея против защиты из реплея
  2835. case 6:
  2836. battle.attackers = repleyBattle.defenders;
  2837. battle.defenders[0] = repleyBattle.attackers;
  2838. break; //защита из реплея против атаки из реплея
  2839. case 7:
  2840. battle.attackers = repleyBattle.attackers;
  2841. battle.defenders[0] = repleyBattle.attackers;
  2842. break; //атака из реплея против атаки из реплея
  2843. case 8:
  2844. battle.attackers = repleyBattle.defenders;
  2845. battle.defenders[0] = repleyBattle.defenders;
  2846. break; //защита из реплея против защиты из реплея
  2847. }
  2848. }
  2849.  
  2850. isChange = true;
  2851. }
  2852. //тест сохранки
  2853. /**
  2854. * Start of the Asgard boss fight
  2855. * Начало боя с боссом Асгарда
  2856. */
  2857. if (call.ident == callsIdent['clanRaid_startBossBattle']) {
  2858. lastBossBattle = call.result.response.battle;
  2859. lastBossBattle.endTime = Date.now() + 160 * 1000;
  2860. if (isChecked('preCalcBattle')) {
  2861. const result = await Calc(lastBossBattle).then(e => e.progress[0].defenders.heroes[1].extra);
  2862. const bossDamage = result.damageTaken + result.damageTakenNextLevel;
  2863. setProgress(I18N('BOSS_DAMAGE') + bossDamage.toLocaleString(), false, hideProgress);
  2864. }
  2865. }
  2866. /**
  2867. * Cancel tutorial
  2868. * Отмена туториала
  2869. */
  2870. if (isCanceledTutorial && call.ident == callsIdent['tutorialGetInfo']) {
  2871. let chains = call.result.response.chains;
  2872. for (let n in chains) {
  2873. chains[n] = 9999;
  2874. }
  2875. isChange = true;
  2876. }
  2877. /**
  2878. * Opening keys and spheres of titan artifacts
  2879. * Открытие ключей и сфер артефактов титанов
  2880. */
  2881. if (artifactChestOpen &&
  2882. (call.ident == callsIdent[artifactChestOpenCallName] ||
  2883. (callsIdent[artifactChestOpenCallName] && callsIdent[artifactChestOpenCallName].includes(call.ident)))) {
  2884. let reward = call.result.response[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'];
  2885.  
  2886. reward.forEach(e => {
  2887. for (let f in e) {
  2888. if (!allReward[f]) {
  2889. allReward[f] = {};
  2890. }
  2891. for (let o in e[f]) {
  2892. if (!allReward[f][o]) {
  2893. allReward[f][o] = e[f][o];
  2894. countTypeReward++;
  2895. } else {
  2896. allReward[f][o] += e[f][o];
  2897. }
  2898. }
  2899. }
  2900. });
  2901.  
  2902. if (!call.ident.includes(artifactChestOpenCallName)) {
  2903. mainReward = call.result.response;
  2904. }
  2905. }
  2906.  
  2907. if (countTypeReward > 20) {
  2908. correctShowOpenArtifact = 3;
  2909. } else {
  2910. correctShowOpenArtifact = 0;
  2911. }
  2912.  
  2913. /**
  2914. * Sum the result of opening Pet Eggs
  2915. * Суммирование результата открытия яиц питомцев
  2916. */
  2917. if (isChecked('countControl') && call.ident == callsIdent['pet_chestOpen']) {
  2918. const rewards = call.result.response.rewards;
  2919. if (rewards.length > 10) {
  2920. /**
  2921. * Removing pet cards
  2922. * Убираем карточки петов
  2923. */
  2924. for (const reward of rewards) {
  2925. if (reward.petCard) {
  2926. delete reward.petCard;
  2927. }
  2928. }
  2929. }
  2930. rewards.forEach(e => {
  2931. for (let f in e) {
  2932. if (!allReward[f]) {
  2933. allReward[f] = {};
  2934. }
  2935. for (let o in e[f]) {
  2936. if (!allReward[f][o]) {
  2937. allReward[f][o] = e[f][o];
  2938. } else {
  2939. allReward[f][o] += e[f][o];
  2940. }
  2941. }
  2942. }
  2943. });
  2944. call.result.response.rewards = [allReward];
  2945. isChange = true;
  2946. }
  2947. /**
  2948. * Removing titan cards
  2949. * Убираем карточки титанов
  2950. */
  2951. if (call.ident == callsIdent['titanUseSummonCircle']) {
  2952. if (call.result.response.rewards.length > 10) {
  2953. for (const reward of call.result.response.rewards) {
  2954. if (reward.titanCard) {
  2955. delete reward.titanCard;
  2956. }
  2957. }
  2958. isChange = true;
  2959. }
  2960. }
  2961. /**
  2962. * Auto-repeat opening matryoshkas
  2963. * АвтоПовтор открытия матрешек
  2964. */
  2965. if (isChecked('countControl') && call.ident == callsIdent['consumableUseLootBox']) {
  2966. let lootBox = call.result.response;
  2967. let newCount = 0;
  2968. for (let n of lootBox) {
  2969. if (n?.consumable && n.consumable[lastRussianDollId]) {
  2970. newCount += n.consumable[lastRussianDollId]
  2971. }
  2972. }
  2973. if (
  2974. newCount && (await popup.confirm(`${I18N('BTN_OPEN')} ${newCount} ${I18N('OPEN_DOLLS')}?`, [
  2975. { msg: I18N('BTN_OPEN'), result: true },
  2976. { msg: I18N('BTN_NO'), result: false, isClose: true },
  2977. ]))
  2978. ) {
  2979. const recursionResult = await openRussianDolls(lastRussianDollId, newCount);
  2980. lootBox = [...lootBox, ...recursionResult];
  2981. }
  2982.  
  2983. if (this.massOpen) {
  2984. if (
  2985. await popup.confirm(I18N('OPEN_ALL_EQUIP_BOXES'), [
  2986. { msg: I18N('BTN_OPEN'), result: true },
  2987. { msg: I18N('BTN_NO'), result: false, isClose: true },
  2988. ])
  2989. ) {
  2990. const consumable = await Send({ calls: [{ name: 'inventoryGet', args: {}, ident: 'inventoryGet' }] }).then((e) =>
  2991. Object.entries(e.results[0].result.response.consumable)
  2992. );
  2993. const calls = [];
  2994. const deleteItems = {};
  2995. for (const [libId, amount] of consumable) {
  2996. if (libId != this.massOpen && libId >= 362 && libId <= 389) {
  2997. calls.push({
  2998. name: 'consumableUseLootBox',
  2999. args: { libId, amount },
  3000. ident: 'consumableUseLootBox_' + libId,
  3001. });
  3002. deleteItems[libId] = -amount;
  3003. }
  3004. }
  3005. const result = await Send({ calls }).then((e) => e.results.map((r) => r.result.response).flat());
  3006. lootBox = [...lootBox, ...result];
  3007. this.onReadySuccess = () => {
  3008. cheats.updateInventory({ consumable: deleteItems });
  3009. cheats.refreshInventory();
  3010. };
  3011. }
  3012. }
  3013.  
  3014. /** Объединение результата лутбоксов */
  3015. const allLootBox = {};
  3016. lootBox.forEach(e => {
  3017. for (let f in e) {
  3018. if (!allLootBox[f]) {
  3019. if (typeof e[f] == 'object') {
  3020. allLootBox[f] = {};
  3021. } else {
  3022. allLootBox[f] = 0;
  3023. }
  3024. }
  3025. if (typeof e[f] == 'object') {
  3026. for (let o in e[f]) {
  3027. if (newCount && o == lastRussianDollId) {
  3028. continue;
  3029. }
  3030. if (!allLootBox[f][o]) {
  3031. allLootBox[f][o] = e[f][o];
  3032. } else {
  3033. allLootBox[f][o] += e[f][o];
  3034. }
  3035. }
  3036. } else {
  3037. allLootBox[f] += e[f];
  3038. }
  3039. }
  3040. });
  3041. /** Разбитие результата */
  3042. const output = [];
  3043. const maxCount = 5;
  3044. let currentObj = {};
  3045. let count = 0;
  3046. for (let f in allLootBox) {
  3047. if (!currentObj[f]) {
  3048. if (typeof allLootBox[f] == 'object') {
  3049. for (let o in allLootBox[f]) {
  3050. currentObj[f] ||= {}
  3051. if (!currentObj[f][o]) {
  3052. currentObj[f][o] = allLootBox[f][o];
  3053. count++;
  3054. if (count === maxCount) {
  3055. output.push(currentObj);
  3056. currentObj = {};
  3057. count = 0;
  3058. }
  3059. }
  3060. }
  3061. } else {
  3062. currentObj[f] = allLootBox[f];
  3063. count++;
  3064. if (count === maxCount) {
  3065. output.push(currentObj);
  3066. currentObj = {};
  3067. count = 0;
  3068. }
  3069. }
  3070. }
  3071. }
  3072. if (count > 0) {
  3073. output.push(currentObj);
  3074. }
  3075.  
  3076. console.log(output);
  3077. call.result.response = output;
  3078. isChange = true;
  3079. }
  3080. /**
  3081. * Dungeon recalculation (fix endless cards)
  3082. * Прерасчет подземки (исправление бесконечных карт)
  3083. */
  3084. if (call.ident == callsIdent['dungeonStartBattle']) {
  3085. lastDungeonBattleData = call.result.response;
  3086. lastDungeonBattleStart = Date.now();
  3087. }
  3088. /**
  3089. * Getting the number of prediction cards
  3090. * Получение количества карт предсказаний
  3091. */
  3092. if (call.ident == callsIdent['inventoryGet']) {
  3093. countPredictionCard = call.result.response.consumable[81] || 0;
  3094. }
  3095. /**
  3096. * Getting subscription status
  3097. * Получение состояния подписки
  3098. */
  3099. if (call.ident == callsIdent['subscriptionGetInfo']) {
  3100. const subscription = call.result.response.subscription;
  3101. if (subscription) {
  3102. subEndTime = subscription.endTime * 1000;
  3103. }
  3104. }
  3105. /**
  3106. * Getting prediction cards
  3107. * Получение карт предсказаний
  3108. */
  3109. if (call.ident == callsIdent['questFarm']) {
  3110. const consumable = call.result.response?.consumable;
  3111. if (consumable && consumable[81]) {
  3112. countPredictionCard += consumable[81];
  3113. console.log(`Cards: ${countPredictionCard}`);
  3114. }
  3115. }
  3116. /**
  3117. * Hiding extra servers
  3118. * Скрытие лишних серверов
  3119. */
  3120. if (call.ident == callsIdent['serverGetAll'] && isChecked('hideServers')) {
  3121. let servers = call.result.response.users.map(s => s.serverId)
  3122. call.result.response.servers = call.result.response.servers.filter(s => servers.includes(s.id));
  3123. isChange = true;
  3124. }
  3125. /**
  3126. * Displays player positions in the adventure
  3127. * Отображает позиции игроков в приключении
  3128. */
  3129. if (call.ident == callsIdent['adventure_getLobbyInfo']) {
  3130. const users = Object.values(call.result.response.users);
  3131. const mapIdent = call.result.response.mapIdent;
  3132. const adventureId = call.result.response.adventureId;
  3133. const maps = {
  3134. adv_strongford_3pl_hell: 9,
  3135. adv_valley_3pl_hell: 10,
  3136. adv_ghirwil_3pl_hell: 11,
  3137. adv_angels_3pl_hell: 12,
  3138. }
  3139. let msg = I18N('MAP') + (mapIdent in maps ? maps[mapIdent] : adventureId);
  3140. msg += '<br>' + I18N('PLAYER_POS');
  3141. for (const user of users) {
  3142. msg += `<br>${user.user.name} - ${user.currentNode}`;
  3143. }
  3144. setProgress(msg, false, hideProgress);
  3145. }
  3146. /**
  3147. * Automatic launch of a raid at the end of the adventure
  3148. * Автоматический запуск рейда при окончании приключения
  3149. */
  3150. if (call.ident == callsIdent['adventure_end']) {
  3151. autoRaidAdventure()
  3152. }
  3153. /** Удаление лавки редкостей */
  3154. if (call.ident == callsIdent['missionRaid']) {
  3155. if (call.result?.heroesMerchant) {
  3156. delete call.result.heroesMerchant;
  3157. isChange = true;
  3158. }
  3159. }
  3160. /** missionTimer */
  3161. if (call.ident == callsIdent['missionStart']) {
  3162. missionBattle = call.result.response;
  3163. }
  3164. /** Награды турнира стихий */
  3165. if (call.ident == callsIdent['hallOfFameGetTrophies']) {
  3166. const trophys = call.result.response;
  3167. const calls = [];
  3168. for (const week in trophys) {
  3169. const trophy = trophys[week];
  3170. if (!trophy.championRewardFarmed) {
  3171. calls.push({
  3172. name: 'hallOfFameFarmTrophyReward',
  3173. args: { trophyId: week, rewardType: 'champion' },
  3174. ident: 'body_champion_' + week,
  3175. });
  3176. }
  3177. if (Object.keys(trophy.clanReward).length && !trophy.clanRewardFarmed) {
  3178. calls.push({
  3179. name: 'hallOfFameFarmTrophyReward',
  3180. args: { trophyId: week, rewardType: 'clan' },
  3181. ident: 'body_clan_' + week,
  3182. });
  3183. }
  3184. }
  3185. if (calls.length) {
  3186. Send({ calls })
  3187. .then((e) => e.results.map((e) => e.result.response))
  3188. .then(async results => {
  3189. let coin18 = 0,
  3190. coin19 = 0,
  3191. gold = 0,
  3192. starmoney = 0;
  3193. for (const r of results) {
  3194. coin18 += r?.coin ? +r.coin[18] : 0;
  3195. coin19 += r?.coin ? +r.coin[19] : 0;
  3196. gold += r?.gold ? +r.gold : 0;
  3197. starmoney += r?.starmoney ? +r.starmoney : 0;
  3198. }
  3199. let msg = I18N('ELEMENT_TOURNAMENT_REWARD') + '<br>';
  3200. if (coin18) {
  3201. msg += cheats.translate('LIB_COIN_NAME_18') + `: ${coin18}<br>`;
  3202. }
  3203. if (coin19) {
  3204. msg += cheats.translate('LIB_COIN_NAME_19') + `: ${coin19}<br>`;
  3205. }
  3206. if (gold) {
  3207. msg += cheats.translate('LIB_PSEUDO_COIN') + `: ${gold}<br>`;
  3208. }
  3209. if (starmoney) {
  3210. msg += cheats.translate('LIB_PSEUDO_STARMONEY') + `: ${starmoney}<br>`;
  3211. }
  3212. await popup.confirm(msg, [{ msg: I18N('BTN_OK'), result: 0 }]);
  3213. });
  3214. }
  3215. }
  3216. if (call.ident == callsIdent['clanDomination_getInfo']) {
  3217. clanDominationGetInfo = call.result.response;
  3218. }
  3219. /*
  3220. if (call.ident == callsIdent['chatGetAll'] && call.args.chatType == 'clanDomination' && !callsIdent['clanDomination_mapState']) {
  3221. this.onReadySuccess = async function () {
  3222. const result = await Send({
  3223. calls: [
  3224. {
  3225. name: 'clanDomination_mapState',
  3226. args: {},
  3227. ident: 'clanDomination_mapState',
  3228. },
  3229. ],
  3230. }).then((e) => e.results[0].result.response);
  3231. let townPositions = result.townPositions;
  3232. let positions = {};
  3233. for (let pos in townPositions) {
  3234. let townPosition = townPositions[pos];
  3235. positions[townPosition.position] = townPosition;
  3236. }
  3237. Object.assign(clanDominationGetInfo, {
  3238. townPositions: positions,
  3239. });
  3240. let userPositions = result.userPositions;
  3241. for (let pos in clanDominationGetInfo.townPositions) {
  3242. let townPosition = clanDominationGetInfo.townPositions[pos];
  3243. if (townPosition.status) {
  3244. userPositions[townPosition.userId] = +pos;
  3245. }
  3246. }
  3247. cheats.updateMap(result);
  3248. };
  3249. }
  3250. if (call.ident == callsIdent['clanDomination_mapState']) {
  3251. const townPositions = call.result.response.townPositions;
  3252. const userPositions = call.result.response.userPositions;
  3253. for (let pos in townPositions) {
  3254. let townPos = townPositions[pos];
  3255. if (townPos.status) {
  3256. userPositions[townPos.userId] = townPos.position;
  3257. }
  3258. }
  3259. isChange = true;
  3260. }
  3261. */
  3262. }
  3263. if (mainReward && artifactChestOpen) {
  3264. console.log(allReward);
  3265. mainReward[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'] = [allReward];
  3266. artifactChestOpen = false;
  3267. artifactChestOpenCallName = '';
  3268. isChange = true;
  3269. }
  3270. } catch(err) {
  3271. console.log("Request(response, " + this.uniqid + "):\n", "Error:\n", response, err);
  3272. }
  3273.  
  3274. if (isChange) {
  3275. Object.defineProperty(this, 'responseText', {
  3276. writable: true
  3277. });
  3278. this.responseText = JSON.stringify(respond);
  3279. }
  3280. }
  3281.  
  3282. /** Добавляет в бой эффекты усиления*/
  3283. function addBuff(battle) {
  3284. let effects = battle.effects;
  3285. let buffType = getInput('needResource2');
  3286. if (-1 < buffType && buffType < 7) {
  3287. let percentBuff = getInput('needResource');
  3288. effects.defenders = {};
  3289. effects.defenders[buffs[buffType]] = percentBuff;
  3290. } else if (buffType.slice(0, 1) == "-" || isChecked('treningBattle')) {
  3291. buffType = parseInt(buffType.slice(1), 10);
  3292. effects.defenders = repleyBattle.effects;
  3293. battle.defenders[0] = repleyBattle.defenders;
  3294. let def = battle.defenders[0];
  3295. if (buffType == 1) {
  3296. for (let i in def) {
  3297. let state = def[i].state;
  3298. state.hp = state.maxHp;
  3299. state.energy = 0;
  3300. state.isDead = false;
  3301. }
  3302. } else if (buffType == 2 || isChecked('finishingBattle')) {
  3303. for (let i in def) {
  3304. let state2 = def[i].state;
  3305. let rState = repleyBattle.state[i];
  3306. if (!!rState) {
  3307. state2.hp = rState.hp;
  3308. state2.energy = rState.energy;
  3309. state2.isDead = rState.isDead;
  3310. } else {
  3311. state2.hp = 0;
  3312. state2.energy = 0;
  3313. state2.isDead = true;
  3314. }
  3315. }
  3316. }
  3317. }
  3318. }
  3319. const buffs = ['percentBuffAll_allAttacks', 'percentBuffAll_armor', 'percentBuffAll_magicResist', 'percentBuffAll_physicalAttack', 'percentBuffAll_magicPower', 'percentDamageBuff_dot', 'percentBuffAll_healing', 'percentBuffAllForFallenAllies', 'percentBuffAll_energyIncrease', 'percentIncomeDamageReduce_any', 'percentIncomeDamageReduce_physical', 'percentIncomeDamageReduce_magic', 'percentIncomeDamageReduce_dot', 'percentBuffHp', 'percentBuffByPerk_energyIncrease_8', 'percentBuffByPerk_energyIncrease_5', 'percentBuffByPerk_energyIncrease_4', 'percentBuffByPerk_allAttacks_5', 'percentBuffByPerk_allAttacks_4', 'percentBuffByPerk_allAttacks_9', 'percentBuffByPerk_castSpeed_7', 'percentBuffByPerk_castSpeed_6', 'percentBuffByPerk_castSpeed_10', 'percentBuffByPerk_armorPenetration_6', 'percentBuffByPerk_physicalAttack_6', 'percentBuffByPerk_armorPenetration_10', 'percentBuffByPerk_physicalAttack_10', 'percentBuffByPerk_magicPower_7', 'percentDamageBuff_any','percentDamageBuff_physical','percentDamageBuff_magic','corruptedBoss_25_80_1_100_10','tutorialPetUlt_1.2','tutorialBossPercentDamage_1','corruptedBoss_50_80_1_100_10','corruptedBoss_75_80_1_100_10','corruptedBoss_80_80_1_100_10','percentBuffByPerk_castSpeed_4','percentBuffByPerk_energyIncrease_7','percentBuffByPerk_castSpeed_9','percentBuffByPerk_castSpeed_8','bossStageBuff_1000000_20000','bossStageBuff_1500000_30000','bossStageBuff_2000000_40000','bossStageBuff_3000000_50000','bossStageBuff_4000000_60000','bossStageBuff_5000000_70000','bossStageBuff_7500000_80000','bossStageBuff_11000000_90000','bossStageBuff_15000000_100000','bossStageBuff_20000000_120000','bossStageBuff_30000000_150000','bossStageBuff_40000000_200000','bossStageBuff_50000000_250000','percentBuffPet_strength','percentBuffPet_castSpeed','percentBuffPet_petEnergyIncrease','stormPowerBuff_100_1000','stormPowerBuff_100','changeStarSphereIncomingDamage_any','changeBlackHoleDamage','buffSpeedWhenStarfall','changeTeamStartEnergy','decreaseStarSphereDamage','avoidAllBlackholeDamageOnce','groveKeeperAvoidBlackholeDamageChance_3','undeadPreventsNightmares_3','engeneerIncreaseStarMachineIncomingDamage_3','overloadHealDamageStarSphere','nightmareDeathGiveLifesteal_100','starfallIncreaseAllyHeal_9_100','decreaseStarSphereDamage_4','increaseNightmaresIncomingDamageByCount','debuffNightmareOnSpawnFrom_7_hp','damageNightmareGiveEnergy','ultEnergyCompensationOnPlanetParade_6','bestDamagerBeforeParadeGetsImprovedBuff_any','starSphereDeathGiveEnergy','bestDamagerOnParadeBecomesImmortal_any','preventNightmare','buffStatWithHealing_physicalAttack_magic_100','buffStatWithHealing_magicPower_physical_100','buffStatWithHealing_hp_dot_100','replaceHealingWithDamage_magic','critWithRetaliation_10_dot','posessionWithBuffStat_25_20_5_10','energyBurnDamageWithEffect_magic_Silence_5_5','percentBuffHp','percentBuffAll_energyIncrease','percentBuffAll_magicResist','percentBuffAll_armor','percentIncomeDamageReduce_any','percentBuffAll_healing','percentIncomeDamageReduce_any','percentBuffHp','percentBuffAll_energyIncrease','percentIncomeDamageReduce_any','percentBuffHp','percentBuffByPerk_castSpeed_All','percentBuffAll_castSpeed'];
  3320.  
  3321. /**
  3322. * Request an answer to a question
  3323. *
  3324. * Запрос ответа на вопрос
  3325. */
  3326. async function getAnswer(question) {
  3327. // c29tZSBzdHJhbmdlIHN5bWJvbHM=
  3328. const quizAPI = new ZingerYWebsiteAPI('getAnswer.php', arguments, { question });
  3329. return new Promise((resolve, reject) => {
  3330. quizAPI.request().then((data) => {
  3331. if (data.result) {
  3332. resolve(data.result);
  3333. } else {
  3334. resolve(false);
  3335. }
  3336. }).catch((error) => {
  3337. console.error(error);
  3338. resolve(false);
  3339. });
  3340. })
  3341. }
  3342.  
  3343. /**
  3344. * Submitting a question and answer to a database
  3345. *
  3346. * Отправка вопроса и ответа в базу данных
  3347. */
  3348. function sendAnswerInfo(answerInfo) {
  3349. // c29tZSBub25zZW5zZQ==
  3350. const quizAPI = new ZingerYWebsiteAPI('setAnswer.php', arguments, { answerInfo });
  3351. quizAPI.request().then((data) => {
  3352. if (data.result) {
  3353. console.log(I18N('SENT_QUESTION'));
  3354. }
  3355. });
  3356. }
  3357.  
  3358. /**
  3359. * Returns the battle type by preset type
  3360. *
  3361. * Возвращает тип боя по типу пресета
  3362. */
  3363. function getBattleType(strBattleType) {
  3364. if (!strBattleType) {
  3365. return null;
  3366. }
  3367. switch (strBattleType) {
  3368. case 'titan_pvp':
  3369. return 'get_titanPvp';
  3370. case 'titan_pvp_manual':
  3371. case 'titan_clan_pvp':
  3372. case 'clan_pvp_titan':
  3373. case 'clan_global_pvp_titan':
  3374. case 'brawl_titan':
  3375. case 'challenge_titan':
  3376. case 'titan_mission':
  3377. return 'get_titanPvpManual';
  3378. case 'clan_raid': // Asgard Boss // Босс асгарда
  3379. case 'adventure': // Adventures // Приключения
  3380. case 'clan_global_pvp':
  3381. case 'epic_brawl':
  3382. case 'clan_pvp':
  3383. return 'get_clanPvp';
  3384. case 'dungeon_titan':
  3385. case 'titan_tower':
  3386. return 'get_titan';
  3387. case 'tower':
  3388. return 'get_tower';
  3389. case 'clan_dungeon':
  3390. case 'pve':
  3391. case 'mission':
  3392. return 'get_pve';
  3393. case 'mission_boss':
  3394. return 'get_missionBoss';
  3395. case 'challenge':
  3396. case 'pvp_manual':
  3397. return 'get_pvpManual';
  3398. case 'grand':
  3399. case 'arena':
  3400. case 'pvp':
  3401. case 'clan_domination':
  3402. return 'get_pvp';
  3403. case 'core':
  3404. return 'get_core';
  3405. default: {
  3406. if (strBattleType.includes('invasion')) {
  3407. return 'get_invasion';
  3408. }
  3409. if (strBattleType.includes('boss')) {
  3410. return 'get_boss';
  3411. }
  3412. if (strBattleType.includes('titan_arena')) {
  3413. return 'get_titanPvpManual';
  3414. }
  3415. return 'get_clanPvp';
  3416. }
  3417. }
  3418. }
  3419. /**
  3420. * Returns the class name of the passed object
  3421. *
  3422. * Возвращает название класса переданного объекта
  3423. */
  3424. function getClass(obj) {
  3425. return {}.toString.call(obj).slice(8, -1);
  3426. }
  3427. /**
  3428. * Calculates the request signature
  3429. *
  3430. * Расчитывает сигнатуру запроса
  3431. */
  3432. this.getSignature = function(headers, data) {
  3433. const sign = {
  3434. signature: '',
  3435. length: 0,
  3436. add: function (text) {
  3437. this.signature += text;
  3438. if (this.length < this.signature.length) {
  3439. this.length = 3 * (this.signature.length + 1) >> 1;
  3440. }
  3441. },
  3442. }
  3443. sign.add(headers["X-Request-Id"]);
  3444. sign.add(':');
  3445. sign.add(headers["X-Auth-Token"]);
  3446. sign.add(':');
  3447. sign.add(headers["X-Auth-Session-Id"]);
  3448. sign.add(':');
  3449. sign.add(data);
  3450. sign.add(':');
  3451. sign.add('LIBRARY-VERSION=1');
  3452. sign.add('UNIQUE-SESSION-ID=' + headers["X-Env-Unique-Session-Id"]);
  3453.  
  3454. return md5(sign.signature);
  3455. }
  3456. /**
  3457. * Creates an interface
  3458. *
  3459. * Создает интерфейс
  3460. */
  3461. function createInterface() {
  3462. popup.init();
  3463. scriptMenu.init({
  3464. showMenu: true
  3465. });
  3466. scriptMenu.addHeader(GM_info.script.name, justInfo);
  3467. scriptMenu.addHeader('v' + GM_info.script.version);
  3468. }
  3469.  
  3470. function addControls() {
  3471. createInterface();
  3472. const checkboxDetails = scriptMenu.addDetails(I18N('SETTINGS'));
  3473. for (let name in checkboxes) {
  3474. if (checkboxes[name].hide) {
  3475. continue;
  3476. }
  3477. checkboxes[name].cbox = scriptMenu.addCheckbox(checkboxes[name].label, checkboxes[name].title, checkboxDetails);
  3478. /**
  3479. * Getting the state of checkboxes from storage
  3480. * Получаем состояние чекбоксов из storage
  3481. */
  3482. let val = storage.get(name, null);
  3483. if (val != null) {
  3484. checkboxes[name].cbox.checked = val;
  3485. } else {
  3486. storage.set(name, checkboxes[name].default);
  3487. checkboxes[name].cbox.checked = checkboxes[name].default;
  3488. }
  3489. /**
  3490. * Tracing the change event of the checkbox for writing to storage
  3491. * Отсеживание события изменения чекбокса для записи в storage
  3492. */
  3493. checkboxes[name].cbox.dataset['name'] = name;
  3494. checkboxes[name].cbox.addEventListener('change', async function (event) {
  3495. const nameCheckbox = this.dataset['name'];
  3496. /*
  3497. if (this.checked && nameCheckbox == 'cancelBattle') {
  3498. this.checked = false;
  3499. if (await popup.confirm(I18N('MSG_BAN_ATTENTION'), [
  3500. { msg: I18N('BTN_NO_I_AM_AGAINST'), result: true },
  3501. { msg: I18N('BTN_YES_I_AGREE'), result: false },
  3502. ])) {
  3503. return;
  3504. }
  3505. this.checked = true;
  3506. }
  3507. */
  3508. storage.set(nameCheckbox, this.checked);
  3509. })
  3510. }
  3511.  
  3512. const inputDetails = scriptMenu.addDetails(I18N('VALUES'));
  3513. for (let name in inputs) {
  3514. inputs[name].input = scriptMenu.addInputText(inputs[name].title, false, inputDetails);
  3515. /**
  3516. * Get inputText state from storage
  3517. * Получаем состояние inputText из storage
  3518. */
  3519. let val = storage.get(name, null);
  3520. if (val != null) {
  3521. inputs[name].input.value = val;
  3522. } else {
  3523. storage.set(name, inputs[name].default);
  3524. inputs[name].input.value = inputs[name].default;
  3525. }
  3526. /**
  3527. * Tracing a field change event for a record in storage
  3528. * Отсеживание события изменения поля для записи в storage
  3529. */
  3530. inputs[name].input.dataset['name'] = name;
  3531. inputs[name].input.addEventListener('input', function () {
  3532. const inputName = this.dataset['name'];
  3533. let value = +this.value;
  3534. if (!value || Number.isNaN(value)) {
  3535. value = storage.get(inputName, inputs[inputName].default);
  3536. inputs[name].input.value = value;
  3537. }
  3538. storage.set(inputName, value);
  3539. })
  3540. }
  3541. const inputDetails2 = scriptMenu.addDetails(I18N('SAVING'));
  3542. for (let name in inputs2) {
  3543. inputs2[name].input = scriptMenu.addInputText(inputs2[name].title, false, inputDetails2);
  3544. /**
  3545. * Get inputText state from storage
  3546. * Получаем состояние inputText из storage
  3547. */
  3548. let val = storage.get(name, null);
  3549. if (val != null) {
  3550. inputs2[name].input.value = val;
  3551. } else {
  3552. storage.set(name, inputs2[name].default);
  3553. inputs2[name].input.value = inputs2[name].default;
  3554. }
  3555. /**
  3556. * Tracing a field change event for a record in storage
  3557. * Отсеживание события изменения поля для записи в storage
  3558. */
  3559. inputs2[name].input.dataset['name'] = name;
  3560. inputs2[name].input.addEventListener('input', function () {
  3561. const inputName = this.dataset['name'];
  3562. let value = +this.value;
  3563. if (!value || Number.isNaN(value)) {
  3564. value = storage.get(inputName, inputs2[inputName].default);
  3565. inputs2[name].input.value = value;
  3566. }
  3567. storage.set(inputName, value);
  3568. })
  3569. }
  3570. /* const inputDetails3 = scriptMenu.addDetails(I18N('USER_ID'));
  3571. for (let name in inputs3) {
  3572. inputs3[name].input = scriptMenu.addInputText(inputs3[name].title, false, inputDetails3);
  3573. /**
  3574. * Get inputText state from storage
  3575. * Получаем состояние inputText из storage
  3576. *
  3577. let val = storage.get(name, null);
  3578. if (val != null) {
  3579. inputs3[name].input.value = val;
  3580. } else {
  3581. storage.set(name, inputs3[name].default);
  3582. inputs3[name].input.value = inputs3[name].default;
  3583. }
  3584. /**
  3585. * Tracing a field change event for a record in storage
  3586. * Отсеживание события изменения поля для записи в storage
  3587. *
  3588. inputs3[name].input.dataset['name'] = name;
  3589. inputs3[name].input.addEventListener('input', function () {
  3590. const inputName = this.dataset['name'];
  3591. let value = +this.value;
  3592. if (!value || Number.isNaN(value)) {
  3593. value = storage.get(inputName, inputs3[inputName].default);
  3594. inputs3[name].input.value = value;
  3595. }
  3596. storage.set(inputName, value);
  3597. })
  3598. }*/
  3599. }
  3600.  
  3601. /**
  3602. * Sending a request
  3603. *
  3604. * Отправка запроса
  3605. */
  3606. function send(json, callback, pr) {
  3607. if (typeof json == 'string') {
  3608. json = JSON.parse(json);
  3609. }
  3610. for (const call of json.calls) {
  3611. if (!call?.context?.actionTs) {
  3612. call.context = {
  3613. actionTs: Math.floor(performance.now())
  3614. }
  3615. }
  3616. }
  3617. json = JSON.stringify(json);
  3618. /**
  3619. * We get the headlines of the previous intercepted request
  3620. * Получаем заголовки предыдущего перехваченого запроса
  3621. */
  3622. let headers = lastHeaders;
  3623. /**
  3624. * We increase the header of the query Certifier by 1
  3625. * Увеличиваем заголовок идетификатора запроса на 1
  3626. */
  3627. headers["X-Request-Id"]++;
  3628. /**
  3629. * We calculate the title with the signature
  3630. * Расчитываем заголовок с сигнатурой
  3631. */
  3632. headers["X-Auth-Signature"] = getSignature(headers, json);
  3633. /**
  3634. * Create a new ajax request
  3635. * Создаем новый AJAX запрос
  3636. */
  3637. let xhr = new XMLHttpRequest;
  3638. /**
  3639. * Indicate the previously saved URL for API queries
  3640. * Указываем ранее сохраненный URL для API запросов
  3641. */
  3642. xhr.open('POST', apiUrl, true);
  3643. /**
  3644. * Add the function to the event change event
  3645. * Добавляем функцию к событию смены статуса запроса
  3646. */
  3647. xhr.onreadystatechange = function() {
  3648. /**
  3649. * If the result of the request is obtained, we call the flask function
  3650. * Если результат запроса получен вызываем колбек функцию
  3651. */
  3652. if(xhr.readyState == 4) {
  3653. callback(xhr.response, pr);
  3654. }
  3655. };
  3656. /**
  3657. * Indicate the type of request
  3658. * Указываем тип запроса
  3659. */
  3660. xhr.responseType = 'json';
  3661. /**
  3662. * We set the request headers
  3663. * Задаем заголовки запроса
  3664. */
  3665. for(let nameHeader in headers) {
  3666. let head = headers[nameHeader];
  3667. xhr.setRequestHeader(nameHeader, head);
  3668. }
  3669. /**
  3670. * Sending a request
  3671. * Отправляем запрос
  3672. */
  3673. xhr.send(json);
  3674. }
  3675.  
  3676. let hideTimeoutProgress = 0;
  3677. /**
  3678. * Hide progress
  3679. *
  3680. * Скрыть прогресс
  3681. */
  3682. function hideProgress(timeout) {
  3683. timeout = timeout || 0;
  3684. clearTimeout(hideTimeoutProgress);
  3685. hideTimeoutProgress = setTimeout(function () {
  3686. scriptMenu.setStatus('');
  3687. }, timeout);
  3688. }
  3689. /**
  3690. * Progress display
  3691. *
  3692. * Отображение прогресса
  3693. */
  3694. function setProgress(text, hide, onclick) {
  3695. scriptMenu.setStatus(text, onclick);
  3696. hide = hide || false;
  3697. if (hide) {
  3698. hideProgress(3000);
  3699. }
  3700. }
  3701.  
  3702. /**
  3703. * Returns the timer value depending on the subscription
  3704. *
  3705. * Возвращает значение таймера в зависимости от подписки
  3706. */
  3707. function getTimer(time, div) {
  3708. let speedDiv = 5;
  3709. if (subEndTime < Date.now()) {
  3710. speedDiv = div || 1.5;
  3711. }
  3712. return Math.max(Math.ceil(time / speedDiv + 1.5), 4);
  3713. }
  3714.  
  3715. /**
  3716. * Calculates HASH MD5 from string
  3717. *
  3718. * Расчитывает HASH MD5 из строки
  3719. *
  3720. * [js-md5]{@link https://github.com/emn178/js-md5}
  3721. *
  3722. * @namespace md5
  3723. * @version 0.7.3
  3724. * @author Chen, Yi-Cyuan [emn178@gmail.com]
  3725. * @copyright Chen, Yi-Cyuan 2014-2017
  3726. * @license MIT
  3727. */
  3728. !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 _}))}();
  3729.  
  3730. /**
  3731. * Script for beautiful dialog boxes
  3732. *
  3733. * Скрипт для красивых диалоговых окошек
  3734. */
  3735. const popup = new (function () {
  3736. this.popUp,
  3737. this.downer,
  3738. this.middle,
  3739. this.msgText,
  3740. this.buttons = [];
  3741. this.checkboxes = [];
  3742. this.dialogPromice = null;
  3743.  
  3744. this.init = function () {
  3745. addStyle();
  3746. addBlocks();
  3747. addEventListeners();
  3748. }
  3749.  
  3750. const addEventListeners = () => {
  3751. document.addEventListener('keyup', (e) => {
  3752. if (e.key == 'Escape') {
  3753. if (this.dialogPromice) {
  3754. const { func, result } = this.dialogPromice;
  3755. this.dialogPromice = null;
  3756. popup.hide();
  3757. func(result);
  3758. }
  3759. }
  3760. });
  3761. }
  3762.  
  3763. const addStyle = () => {
  3764. let style = document.createElement('style');
  3765. style.innerText = `
  3766. .PopUp_ {
  3767. position: absolute;
  3768. min-width: 300px;
  3769. max-width: 500px;
  3770. max-height: 600px;
  3771. background-color: #190e08e6;
  3772. z-index: 10001;
  3773. top: 169px;
  3774. left: 345px;
  3775. border: 3px #ce9767 solid;
  3776. border-radius: 10px;
  3777. display: flex;
  3778. flex-direction: column;
  3779. justify-content: space-around;
  3780. padding: 15px 9px;
  3781. box-sizing: border-box;
  3782. }
  3783.  
  3784. .PopUp_back {
  3785. position: absolute;
  3786. background-color: #00000066;
  3787. width: 100%;
  3788. height: 100%;
  3789. z-index: 10000;
  3790. top: 0;
  3791. left: 0;
  3792. }
  3793.  
  3794. .PopUp_close {
  3795. width: 40px;
  3796. height: 40px;
  3797. position: absolute;
  3798. right: -18px;
  3799. top: -18px;
  3800. border: 3px solid #c18550;
  3801. border-radius: 20px;
  3802. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  3803. background-position-y: 3px;
  3804. box-shadow: -1px 1px 3px black;
  3805. cursor: pointer;
  3806. box-sizing: border-box;
  3807. }
  3808.  
  3809. .PopUp_close:hover {
  3810. filter: brightness(1.2);
  3811. }
  3812.  
  3813. .PopUp_crossClose {
  3814. width: 100%;
  3815. height: 100%;
  3816. background-size: 65%;
  3817. background-position: center;
  3818. background-repeat: no-repeat;
  3819. 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")
  3820. }
  3821.  
  3822. .PopUp_blocks {
  3823. width: 100%;
  3824. height: 50%;
  3825. display: flex;
  3826. justify-content: space-evenly;
  3827. align-items: center;
  3828. flex-wrap: wrap;
  3829. justify-content: center;
  3830. }
  3831.  
  3832. .PopUp_blocks:last-child {
  3833. margin-top: 25px;
  3834. }
  3835.  
  3836. .PopUp_buttons {
  3837. display: flex;
  3838. margin: 7px 10px;
  3839. flex-direction: column;
  3840. }
  3841.  
  3842. .PopUp_button {
  3843. background-color: #52A81C;
  3844. border-radius: 5px;
  3845. box-shadow: inset 0px -4px 10px, inset 0px 3px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  3846. cursor: pointer;
  3847. padding: 4px 12px 6px;
  3848. }
  3849.  
  3850. .PopUp_input {
  3851. text-align: center;
  3852. font-size: 16px;
  3853. height: 27px;
  3854. border: 1px solid #cf9250;
  3855. border-radius: 9px 9px 0px 0px;
  3856. background: transparent;
  3857. color: #fce1ac;
  3858. padding: 1px 10px;
  3859. box-sizing: border-box;
  3860. box-shadow: 0px 0px 4px, 0px 0px 0px 3px #ce9767;
  3861. }
  3862.  
  3863. .PopUp_checkboxes {
  3864. display: flex;
  3865. flex-direction: column;
  3866. margin: 15px 15px -5px 15px;
  3867. align-items: flex-start;
  3868. }
  3869.  
  3870. .PopUp_ContCheckbox {
  3871. margin: 2px 0px;
  3872. }
  3873.  
  3874. .PopUp_checkbox {
  3875. position: absolute;
  3876. z-index: -1;
  3877. opacity: 0;
  3878. }
  3879. .PopUp_checkbox+label {
  3880. display: inline-flex;
  3881. align-items: center;
  3882. user-select: none;
  3883.  
  3884. font-size: 15px;
  3885. font-family: sans-serif;
  3886. font-weight: 600;
  3887. font-stretch: condensed;
  3888. letter-spacing: 1px;
  3889. color: #fce1ac;
  3890. text-shadow: 0px 0px 1px;
  3891. }
  3892. .PopUp_checkbox+label::before {
  3893. content: '';
  3894. display: inline-block;
  3895. width: 20px;
  3896. height: 20px;
  3897. border: 1px solid #cf9250;
  3898. border-radius: 7px;
  3899. margin-right: 7px;
  3900. }
  3901. .PopUp_checkbox:checked+label::before {
  3902. 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");
  3903. }
  3904.  
  3905. .PopUp_input::placeholder {
  3906. color: #fce1ac75;
  3907. }
  3908.  
  3909. .PopUp_input:focus {
  3910. outline: 0;
  3911. }
  3912.  
  3913. .PopUp_input + .PopUp_button {
  3914. border-radius: 0px 0px 5px 5px;
  3915. padding: 2px 18px 5px;
  3916. }
  3917.  
  3918. .PopUp_button:hover {
  3919. filter: brightness(1.2);
  3920. }
  3921.  
  3922. .PopUp_button:active {
  3923. box-shadow: inset 0px 5px 10px, inset 0px 1px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  3924. }
  3925.  
  3926. .PopUp_text {
  3927. font-size: 22px;
  3928. font-family: sans-serif;
  3929. font-weight: 600;
  3930. font-stretch: condensed;
  3931. white-space: pre-wrap;
  3932. letter-spacing: 1px;
  3933. text-align: center;
  3934. }
  3935.  
  3936. .PopUp_buttonText {
  3937. color: #E4FF4C;
  3938. text-shadow: 0px 1px 2px black;
  3939. }
  3940.  
  3941. .PopUp_msgText {
  3942. color: #FDE5B6;
  3943. text-shadow: 0px 0px 2px;
  3944. }
  3945.  
  3946. .PopUp_hideBlock {
  3947. display: none;
  3948. }
  3949. `;
  3950. document.head.appendChild(style);
  3951. }
  3952.  
  3953. const addBlocks = () => {
  3954. this.back = document.createElement('div');
  3955. this.back.classList.add('PopUp_back');
  3956. this.back.classList.add('PopUp_hideBlock');
  3957. document.body.append(this.back);
  3958.  
  3959. this.popUp = document.createElement('div');
  3960. this.popUp.classList.add('PopUp_');
  3961. this.back.append(this.popUp);
  3962.  
  3963. let upper = document.createElement('div')
  3964. upper.classList.add('PopUp_blocks');
  3965. this.popUp.append(upper);
  3966.  
  3967. this.middle = document.createElement('div')
  3968. this.middle.classList.add('PopUp_blocks');
  3969. this.middle.classList.add('PopUp_checkboxes');
  3970. this.popUp.append(this.middle);
  3971.  
  3972. this.downer = document.createElement('div')
  3973. this.downer.classList.add('PopUp_blocks');
  3974. this.popUp.append(this.downer);
  3975.  
  3976. this.msgText = document.createElement('div');
  3977. this.msgText.classList.add('PopUp_text', 'PopUp_msgText');
  3978. upper.append(this.msgText);
  3979. }
  3980.  
  3981. this.showBack = function () {
  3982. this.back.classList.remove('PopUp_hideBlock');
  3983. }
  3984.  
  3985. this.hideBack = function () {
  3986. this.back.classList.add('PopUp_hideBlock');
  3987. }
  3988.  
  3989. this.show = function () {
  3990. if (this.checkboxes.length) {
  3991. this.middle.classList.remove('PopUp_hideBlock');
  3992. }
  3993. this.showBack();
  3994. this.popUp.classList.remove('PopUp_hideBlock');
  3995. this.popUp.style.left = (window.innerWidth - this.popUp.offsetWidth) / 2 + 'px';
  3996. this.popUp.style.top = (window.innerHeight - this.popUp.offsetHeight) / 3 + 'px';
  3997. }
  3998.  
  3999. this.hide = function () {
  4000. this.hideBack();
  4001. this.popUp.classList.add('PopUp_hideBlock');
  4002. }
  4003.  
  4004. this.addAnyButton = (option) => {
  4005. const contButton = document.createElement('div');
  4006. contButton.classList.add('PopUp_buttons');
  4007. this.downer.append(contButton);
  4008.  
  4009. let inputField = {
  4010. value: option.result || option.default
  4011. }
  4012. if (option.isInput) {
  4013. inputField = document.createElement('input');
  4014. inputField.type = 'text';
  4015. if (option.placeholder) {
  4016. inputField.placeholder = option.placeholder;
  4017. }
  4018. if (option.default) {
  4019. inputField.value = option.default;
  4020. }
  4021. inputField.classList.add('PopUp_input');
  4022. contButton.append(inputField);
  4023. }
  4024.  
  4025. const button = document.createElement('div');
  4026. button.classList.add('PopUp_button');
  4027. button.title = option.title || '';
  4028. contButton.append(button);
  4029.  
  4030. const buttonText = document.createElement('div');
  4031. buttonText.classList.add('PopUp_text', 'PopUp_buttonText');
  4032. buttonText.innerHTML = option.msg;
  4033. button.append(buttonText);
  4034.  
  4035. return { button, contButton, inputField };
  4036. }
  4037.  
  4038. this.addCloseButton = () => {
  4039. let button = document.createElement('div')
  4040. button.classList.add('PopUp_close');
  4041. this.popUp.append(button);
  4042.  
  4043. let crossClose = document.createElement('div')
  4044. crossClose.classList.add('PopUp_crossClose');
  4045. button.append(crossClose);
  4046.  
  4047. return { button, contButton: button };
  4048. }
  4049.  
  4050. this.addButton = (option, buttonClick) => {
  4051.  
  4052. const { button, contButton, inputField } = option.isClose ? this.addCloseButton() : this.addAnyButton(option);
  4053. if (option.isClose) {
  4054. this.dialogPromice = {func: buttonClick, result: option.result};
  4055. }
  4056. button.addEventListener('click', () => {
  4057. let result = '';
  4058. if (option.isInput) {
  4059. result = inputField.value;
  4060. }
  4061. if (option.isClose || option.isCancel) {
  4062. this.dialogPromice = null;
  4063. }
  4064. buttonClick(result);
  4065. });
  4066.  
  4067. this.buttons.push(contButton);
  4068. }
  4069.  
  4070. this.clearButtons = () => {
  4071. while (this.buttons.length) {
  4072. this.buttons.pop().remove();
  4073. }
  4074. }
  4075.  
  4076. this.addCheckBox = (checkBox) => {
  4077. const contCheckbox = document.createElement('div');
  4078. contCheckbox.classList.add('PopUp_ContCheckbox');
  4079. this.middle.append(contCheckbox);
  4080.  
  4081. const checkbox = document.createElement('input');
  4082. checkbox.type = 'checkbox';
  4083. checkbox.id = 'PopUpCheckbox' + this.checkboxes.length;
  4084. checkbox.dataset.name = checkBox.name;
  4085. checkbox.checked = checkBox.checked;
  4086. checkbox.label = checkBox.label;
  4087. checkbox.title = checkBox.title || '';
  4088. checkbox.classList.add('PopUp_checkbox');
  4089. contCheckbox.appendChild(checkbox)
  4090.  
  4091. const checkboxLabel = document.createElement('label');
  4092. checkboxLabel.innerText = checkBox.label;
  4093. checkboxLabel.title = checkBox.title || '';
  4094. checkboxLabel.setAttribute('for', checkbox.id);
  4095. contCheckbox.appendChild(checkboxLabel);
  4096.  
  4097. this.checkboxes.push(checkbox);
  4098. }
  4099.  
  4100. this.clearCheckBox = () => {
  4101. this.middle.classList.add('PopUp_hideBlock');
  4102. while (this.checkboxes.length) {
  4103. this.checkboxes.pop().parentNode.remove();
  4104. }
  4105. }
  4106.  
  4107. this.setMsgText = (text) => {
  4108. this.msgText.innerHTML = text;
  4109. }
  4110.  
  4111. this.getCheckBoxes = () => {
  4112. const checkBoxes = [];
  4113.  
  4114. for (const checkBox of this.checkboxes) {
  4115. checkBoxes.push({
  4116. name: checkBox.dataset.name,
  4117. label: checkBox.label,
  4118. checked: checkBox.checked
  4119. });
  4120. }
  4121.  
  4122. return checkBoxes;
  4123. }
  4124.  
  4125. this.confirm = async (msg, buttOpt, checkBoxes = []) => {
  4126. this.clearButtons();
  4127. this.clearCheckBox();
  4128. return new Promise((complete, failed) => {
  4129. this.setMsgText(msg);
  4130. if (!buttOpt) {
  4131. buttOpt = [{ msg: 'Ok', result: true, isInput: false }];
  4132. }
  4133. for (const checkBox of checkBoxes) {
  4134. this.addCheckBox(checkBox);
  4135. }
  4136. for (let butt of buttOpt) {
  4137. this.addButton(butt, (result) => {
  4138. result = result || butt.result;
  4139. complete(result);
  4140. popup.hide();
  4141. });
  4142. if (butt.isCancel) {
  4143. this.dialogPromice = {func: complete, result: butt.result};
  4144. }
  4145. }
  4146. this.show();
  4147. });
  4148. }
  4149.  
  4150. });
  4151.  
  4152. /**
  4153. * Script control panel
  4154. *
  4155. * Панель управления скриптом
  4156. */
  4157. const scriptMenu = new (function () {
  4158.  
  4159. this.mainMenu,
  4160. this.buttons = [],
  4161. this.checkboxes = [];
  4162. this.option = {
  4163. showMenu: false,
  4164. showDetails: {}
  4165. };
  4166.  
  4167. this.init = function (option = {}) {
  4168. this.option = Object.assign(this.option, option);
  4169. this.option.showDetails = this.loadShowDetails();
  4170. addStyle();
  4171. addBlocks();
  4172. }
  4173.  
  4174. const addStyle = () => {
  4175. style = document.createElement('style');
  4176. style.innerText = `
  4177. .scriptMenu_status {
  4178. position: absolute;
  4179. z-index: 10001;
  4180. white-space: pre-wrap; //тест для выравнивания кнопок
  4181. /* max-height: 30px; */
  4182. top: -1px;
  4183. left: 30%;
  4184. cursor: pointer;
  4185. border-radius: 0px 0px 10px 10px;
  4186. background: #190e08e6;
  4187. border: 1px #ce9767 solid;
  4188. font-size: 18px;
  4189. font-family: sans-serif;
  4190. font-weight: 600;
  4191. font-stretch: condensed;
  4192. letter-spacing: 1px;
  4193. color: #fce1ac;
  4194. text-shadow: 0px 0px 1px;
  4195. transition: 0.5s;
  4196. padding: 2px 10px 3px;
  4197. }
  4198. .scriptMenu_statusHide {
  4199. top: -35px;
  4200. height: 30px;
  4201. overflow: hidden;
  4202. }
  4203. .scriptMenu_label {
  4204. position: absolute;
  4205. top: 30%;
  4206. left: -4px;
  4207. z-index: 9999;
  4208. cursor: pointer;
  4209. width: 30px;
  4210. height: 30px;
  4211. background: radial-gradient(circle, #47a41b 0%, #1a2f04 100%);
  4212. border: 1px solid #1a2f04;
  4213. border-radius: 5px;
  4214. box-shadow:
  4215. inset 0px 2px 4px #83ce26,
  4216. inset 0px -4px 6px #1a2f04,
  4217. 0px 0px 2px black,
  4218. 0px 0px 0px 2px #ce9767;
  4219. }
  4220. .scriptMenu_label:hover {
  4221. filter: brightness(1.2);
  4222. }
  4223. .scriptMenu_arrowLabel {
  4224. width: 100%;
  4225. height: 100%;
  4226. background-size: 75%;
  4227. background-position: center;
  4228. background-repeat: no-repeat;
  4229. 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");
  4230. box-shadow: 0px 1px 2px #000;
  4231. border-radius: 5px;
  4232. filter: drop-shadow(0px 1px 2px #000D);
  4233. }
  4234. .scriptMenu_main {
  4235. position: absolute;
  4236. max-width: 285px;
  4237. z-index: 9999;
  4238. top: 50%;
  4239. transform: translateY(-40%);
  4240. background: #190e08e6;
  4241. border: 1px #ce9767 solid;
  4242. border-radius: 0px 10px 10px 0px;
  4243. border-left: none;
  4244. padding: 5px 10px 5px 5px;
  4245. box-sizing: border-box;
  4246. font-size: 15px;
  4247. font-family: sans-serif;
  4248. font-weight: 600;
  4249. font-stretch: condensed;
  4250. letter-spacing: 1px;
  4251. color: #fce1ac;
  4252. text-shadow: 0px 0px 1px;
  4253. transition: 1s;
  4254. display: flex;
  4255. flex-direction: column;
  4256. flex-wrap: nowrap;
  4257. }
  4258. .scriptMenu_showMenu {
  4259. display: none;
  4260. }
  4261. .scriptMenu_showMenu:checked~.scriptMenu_main {
  4262. left: 0px;
  4263. }
  4264. .scriptMenu_showMenu:not(:checked)~.scriptMenu_main {
  4265. left: -300px;
  4266. }
  4267. .scriptMenu_divInput {
  4268. margin: 2px;
  4269. }
  4270. .scriptMenu_divInputText {
  4271. margin: 2px;
  4272. align-self: center;
  4273. display: flex;
  4274. }
  4275. .scriptMenu_checkbox {
  4276. position: absolute;
  4277. z-index: -1;
  4278. opacity: 0;
  4279. }
  4280. .scriptMenu_checkbox+label {
  4281. display: inline-flex;
  4282. align-items: center;
  4283. user-select: none;
  4284. }
  4285. .scriptMenu_checkbox+label::before {
  4286. content: '';
  4287. display: inline-block;
  4288. width: 20px;
  4289. height: 20px;
  4290. border: 1px solid #cf9250;
  4291. border-radius: 7px;
  4292. margin-right: 7px;
  4293. }
  4294. .scriptMenu_checkbox:checked+label::before {
  4295. 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");
  4296. }
  4297. .scriptMenu_close {
  4298. width: 40px;
  4299. height: 40px;
  4300. position: absolute;
  4301. right: -18px;
  4302. top: -18px;
  4303. border: 3px solid #c18550;
  4304. border-radius: 20px;
  4305. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  4306. background-position-y: 3px;
  4307. box-shadow: -1px 1px 3px black;
  4308. cursor: pointer;
  4309. box-sizing: border-box;
  4310. }
  4311. .scriptMenu_close:hover {
  4312. filter: brightness(1.2);
  4313. }
  4314. .scriptMenu_crossClose {
  4315. width: 100%;
  4316. height: 100%;
  4317. background-size: 65%;
  4318. background-position: center;
  4319. background-repeat: no-repeat;
  4320. 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")
  4321. }
  4322. .scriptMenu_button {
  4323. user-select: none;
  4324. border-radius: 5px;
  4325. cursor: pointer;
  4326. padding: 5px 14px 8px;
  4327. margin: 4px;
  4328. background: radial-gradient(circle, rgba(165,120,56,1) 80%, rgba(0,0,0,1) 110%);
  4329. box-shadow: inset 0px -4px 6px #442901, inset 0px 1px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  4330. }
  4331. .scriptMenu_button:hover {
  4332. filter: brightness(1.2);
  4333. }
  4334. .scriptMenu_button:active {
  4335. box-shadow: inset 0px 4px 6px #442901, inset 0px 4px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  4336. }
  4337. .scriptMenu_buttonText {
  4338. color: #fce5b7;
  4339. text-shadow: 0px 1px 2px black;
  4340. text-align: center;
  4341. }
  4342. .scriptMenu_header {
  4343. text-align: center;
  4344. align-self: center;
  4345. font-size: 15px;
  4346. margin: 0px 15px;
  4347. }
  4348. .scriptMenu_header a {
  4349. color: #fce5b7;
  4350. text-decoration: none;
  4351. }
  4352. .scriptMenu_InputText {
  4353. text-align: center;
  4354. width: 130px;
  4355. height: 24px;
  4356. border: 1px solid #cf9250;
  4357. border-radius: 9px;
  4358. background: transparent;
  4359. color: #fce1ac;
  4360. padding: 0px 10px;
  4361. box-sizing: border-box;
  4362. }
  4363. .scriptMenu_InputText:focus {
  4364. filter: brightness(1.2);
  4365. outline: 0;
  4366. }
  4367. .scriptMenu_InputText::placeholder {
  4368. color: #fce1ac75;
  4369. }
  4370. .scriptMenu_Summary {
  4371. cursor: pointer;
  4372. margin-left: 7px;
  4373. }
  4374. .scriptMenu_Details {
  4375. align-self: center;
  4376. }
  4377. `;
  4378. document.head.appendChild(style);
  4379. }
  4380.  
  4381. const addBlocks = () => {
  4382. const main = document.createElement('div');
  4383. document.body.appendChild(main);
  4384.  
  4385. this.status = document.createElement('div');
  4386. this.status.classList.add('scriptMenu_status');
  4387. this.setStatus('');
  4388. main.appendChild(this.status);
  4389.  
  4390. const label = document.createElement('label');
  4391. label.classList.add('scriptMenu_label');
  4392. label.setAttribute('for', 'checkbox_showMenu');
  4393. main.appendChild(label);
  4394.  
  4395. const arrowLabel = document.createElement('div');
  4396. arrowLabel.classList.add('scriptMenu_arrowLabel');
  4397. label.appendChild(arrowLabel);
  4398.  
  4399. const checkbox = document.createElement('input');
  4400. checkbox.type = 'checkbox';
  4401. checkbox.id = 'checkbox_showMenu';
  4402. checkbox.checked = this.option.showMenu;
  4403. checkbox.classList.add('scriptMenu_showMenu');
  4404. main.appendChild(checkbox);
  4405.  
  4406. this.mainMenu = document.createElement('div');
  4407. this.mainMenu.classList.add('scriptMenu_main');
  4408. main.appendChild(this.mainMenu);
  4409.  
  4410. const closeButton = document.createElement('label');
  4411. closeButton.classList.add('scriptMenu_close');
  4412. closeButton.setAttribute('for', 'checkbox_showMenu');
  4413. this.mainMenu.appendChild(closeButton);
  4414.  
  4415. const crossClose = document.createElement('div');
  4416. crossClose.classList.add('scriptMenu_crossClose');
  4417. closeButton.appendChild(crossClose);
  4418. }
  4419.  
  4420. this.setStatus = (text, onclick) => {
  4421. if (!text) {
  4422. this.status.classList.add('scriptMenu_statusHide');
  4423. } else {
  4424. this.status.classList.remove('scriptMenu_statusHide');
  4425. this.status.innerHTML = text;
  4426. }
  4427.  
  4428. if (typeof onclick == 'function') {
  4429. this.status.addEventListener("click", onclick, {
  4430. once: true
  4431. });
  4432. }
  4433. }
  4434.  
  4435. /**
  4436. * Adding a text element
  4437. *
  4438. * Добавление текстового элемента
  4439. * @param {String} text text // текст
  4440. * @param {Function} func Click function // функция по клику
  4441. * @param {HTMLDivElement} main parent // родитель
  4442. */
  4443. this.addHeader = (text, func, main) => {
  4444. main = main || this.mainMenu;
  4445. const header = document.createElement('div');
  4446. header.classList.add('scriptMenu_header');
  4447. header.innerHTML = text;
  4448. if (typeof func == 'function') {
  4449. header.addEventListener('click', func);
  4450. }
  4451. main.appendChild(header);
  4452. }
  4453.  
  4454. /**
  4455. * Adding a button
  4456. *
  4457. * Добавление кнопки
  4458. * @param {String} text
  4459. * @param {Function} func
  4460. * @param {String} title
  4461. * @param {HTMLDivElement} main parent // родитель
  4462. */
  4463. this.addButton = (text, func, title, main) => {
  4464. main = main || this.mainMenu;
  4465. const button = document.createElement('div');
  4466. button.classList.add('scriptMenu_button');
  4467. button.title = title;
  4468. button.addEventListener('click', func);
  4469. main.appendChild(button);
  4470.  
  4471. const buttonText = document.createElement('div');
  4472. buttonText.classList.add('scriptMenu_buttonText');
  4473. buttonText.innerText = text;
  4474. button.appendChild(buttonText);
  4475. this.buttons.push(button);
  4476.  
  4477. return button;
  4478. }
  4479.  
  4480. /**
  4481. * Adding checkbox
  4482. *
  4483. * Добавление чекбокса
  4484. * @param {String} label
  4485. * @param {String} title
  4486. * @param {HTMLDivElement} main parent // родитель
  4487. * @returns
  4488. */
  4489. this.addCheckbox = (label, title, main) => {
  4490. main = main || this.mainMenu;
  4491. const divCheckbox = document.createElement('div');
  4492. divCheckbox.classList.add('scriptMenu_divInput');
  4493. divCheckbox.title = title;
  4494. main.appendChild(divCheckbox);
  4495.  
  4496. const checkbox = document.createElement('input');
  4497. checkbox.type = 'checkbox';
  4498. checkbox.id = 'scriptMenuCheckbox' + this.checkboxes.length;
  4499. checkbox.classList.add('scriptMenu_checkbox');
  4500. divCheckbox.appendChild(checkbox)
  4501.  
  4502. const checkboxLabel = document.createElement('label');
  4503. checkboxLabel.innerText = label;
  4504. checkboxLabel.setAttribute('for', checkbox.id);
  4505. divCheckbox.appendChild(checkboxLabel);
  4506.  
  4507. this.checkboxes.push(checkbox);
  4508. return checkbox;
  4509. }
  4510.  
  4511. /**
  4512. * Adding input field
  4513. *
  4514. * Добавление поля ввода
  4515. * @param {String} title
  4516. * @param {String} placeholder
  4517. * @param {HTMLDivElement} main parent // родитель
  4518. * @returns
  4519. */
  4520. this.addInputText = (title, placeholder, main) => {
  4521. main = main || this.mainMenu;
  4522. const divInputText = document.createElement('div');
  4523. divInputText.classList.add('scriptMenu_divInputText');
  4524. divInputText.title = title;
  4525. main.appendChild(divInputText);
  4526.  
  4527. const newInputText = document.createElement('input');
  4528. newInputText.type = 'text';
  4529. if (placeholder) {
  4530. newInputText.placeholder = placeholder;
  4531. }
  4532. newInputText.classList.add('scriptMenu_InputText');
  4533. divInputText.appendChild(newInputText)
  4534. return newInputText;
  4535. }
  4536.  
  4537. /**
  4538. * Adds a dropdown block
  4539. *
  4540. * Добавляет раскрывающийся блок
  4541. * @param {String} summary
  4542. * @param {String} name
  4543. * @returns
  4544. */
  4545. this.addDetails = (summaryText, name = null) => {
  4546. const details = document.createElement('details');
  4547. details.classList.add('scriptMenu_Details');
  4548. this.mainMenu.appendChild(details);
  4549.  
  4550. const summary = document.createElement('summary');
  4551. summary.classList.add('scriptMenu_Summary');
  4552. summary.innerText = summaryText;
  4553. if (name) {
  4554. const self = this;
  4555. details.open = this.option.showDetails[name];
  4556. details.dataset.name = name;
  4557. summary.addEventListener('click', () => {
  4558. self.option.showDetails[details.dataset.name] = !details.open;
  4559. self.saveShowDetails(self.option.showDetails);
  4560. });
  4561. }
  4562. details.appendChild(summary);
  4563.  
  4564. return details;
  4565. }
  4566.  
  4567. /**
  4568. * Saving the expanded state of the details blocks
  4569. *
  4570. * Сохранение состояния развенутости блоков details
  4571. * @param {*} value
  4572. */
  4573. this.saveShowDetails = (value) => {
  4574. localStorage.setItem('scriptMenu_showDetails', JSON.stringify(value));
  4575. }
  4576.  
  4577. /**
  4578. * Loading the state of expanded blocks details
  4579. *
  4580. * Загрузка состояния развенутости блоков details
  4581. * @returns
  4582. */
  4583. this.loadShowDetails = () => {
  4584. let showDetails = localStorage.getItem('scriptMenu_showDetails');
  4585.  
  4586. if (!showDetails) {
  4587. return {};
  4588. }
  4589.  
  4590. try {
  4591. showDetails = JSON.parse(showDetails);
  4592. } catch (e) {
  4593. return {};
  4594. }
  4595.  
  4596. return showDetails;
  4597. }
  4598. });
  4599.  
  4600. /**
  4601. * Пример использования
  4602. scriptMenu.init();
  4603. scriptMenu.addHeader('v1.508');
  4604. scriptMenu.addCheckbox('testHack', 'Тестовый взлом игры!');
  4605. scriptMenu.addButton('Запуск!', () => console.log('click'), 'подсказака');
  4606. scriptMenu.addInputText('input подсказака');
  4607. */
  4608. /**
  4609. * Game Library
  4610. *
  4611. * Игровая библиотека
  4612. */
  4613. class Library {
  4614. defaultLibUrl = 'https://heroesru-a.akamaihd.net/vk/v1101/lib/lib.json';
  4615.  
  4616. constructor() {
  4617. if (!Library.instance) {
  4618. Library.instance = this;
  4619. }
  4620.  
  4621. return Library.instance;
  4622. }
  4623.  
  4624. async load() {
  4625. try {
  4626. await this.getUrlLib();
  4627. console.log(this.defaultLibUrl);
  4628. this.data = await fetch(this.defaultLibUrl).then(e => e.json())
  4629. } catch (error) {
  4630. console.error('Не удалось загрузить библиотеку', error)
  4631. }
  4632. }
  4633.  
  4634. async getUrlLib() {
  4635. try {
  4636. const db = new Database('hw_cache', 'cache');
  4637. await db.open();
  4638. const cacheLibFullUrl = await db.get('lib/lib.json.gz', false);
  4639. this.defaultLibUrl = cacheLibFullUrl.fullUrl.split('.gz').shift();
  4640. } catch(e) {}
  4641. }
  4642.  
  4643. getData(id) {
  4644. return this.data[id];
  4645. }
  4646. }
  4647.  
  4648. this.lib = new Library();
  4649. /**
  4650. * Database
  4651. *
  4652. * База данных
  4653. */
  4654. class Database {
  4655. constructor(dbName, storeName) {
  4656. this.dbName = dbName;
  4657. this.storeName = storeName;
  4658. this.db = null;
  4659. }
  4660.  
  4661. async open() {
  4662. return new Promise((resolve, reject) => {
  4663. const request = indexedDB.open(this.dbName);
  4664.  
  4665. request.onerror = () => {
  4666. reject(new Error(`Failed to open database ${this.dbName}`));
  4667. };
  4668.  
  4669. request.onsuccess = () => {
  4670. this.db = request.result;
  4671. resolve();
  4672. };
  4673.  
  4674. request.onupgradeneeded = (event) => {
  4675. const db = event.target.result;
  4676. if (!db.objectStoreNames.contains(this.storeName)) {
  4677. db.createObjectStore(this.storeName);
  4678. }
  4679. };
  4680. });
  4681. }
  4682.  
  4683. async set(key, value) {
  4684. return new Promise((resolve, reject) => {
  4685. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4686. const store = transaction.objectStore(this.storeName);
  4687. const request = store.put(value, key);
  4688.  
  4689. request.onerror = () => {
  4690. reject(new Error(`Failed to save value with key ${key}`));
  4691. };
  4692.  
  4693. request.onsuccess = () => {
  4694. resolve();
  4695. };
  4696. });
  4697. }
  4698.  
  4699. async get(key, def) {
  4700. return new Promise((resolve, reject) => {
  4701. const transaction = this.db.transaction([this.storeName], 'readonly');
  4702. const store = transaction.objectStore(this.storeName);
  4703. const request = store.get(key);
  4704.  
  4705. request.onerror = () => {
  4706. resolve(def);
  4707. };
  4708.  
  4709. request.onsuccess = () => {
  4710. resolve(request.result);
  4711. };
  4712. });
  4713. }
  4714.  
  4715. async delete(key) {
  4716. return new Promise((resolve, reject) => {
  4717. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4718. const store = transaction.objectStore(this.storeName);
  4719. const request = store.delete(key);
  4720.  
  4721. request.onerror = () => {
  4722. reject(new Error(`Failed to delete value with key ${key}`));
  4723. };
  4724.  
  4725. request.onsuccess = () => {
  4726. resolve();
  4727. };
  4728. });
  4729. }
  4730. }
  4731.  
  4732. /**
  4733. * Returns the stored value
  4734. *
  4735. * Возвращает сохраненное значение
  4736. */
  4737. function getSaveVal(saveName, def) {
  4738. const result = storage.get(saveName, def);
  4739. return result;
  4740. }
  4741.  
  4742. /**
  4743. * Stores value
  4744. *
  4745. * Сохраняет значение
  4746. */
  4747. function setSaveVal(saveName, value) {
  4748. storage.set(saveName, value);
  4749. }
  4750.  
  4751. /**
  4752. * Database initialization
  4753. *
  4754. * Инициализация базы данных
  4755. */
  4756. const db = new Database(GM_info.script.name, 'settings');
  4757.  
  4758. /**
  4759. * Data store
  4760. *
  4761. * Хранилище данных
  4762. */
  4763. const storage = {
  4764. userId: 0,
  4765. /**
  4766. * Default values
  4767. *
  4768. * Значения по умолчанию
  4769. */
  4770. values: [
  4771. ...Object.entries(checkboxes).map(e => ({ [e[0]]: e[1].default })),
  4772. ...Object.entries(inputs).map(e => ({ [e[0]]: e[1].default })),
  4773. ...Object.entries(inputs2).map(e => ({ [e[0]]: e[1].default })),
  4774. //...Object.entries(inputs3).map(e => ({ [e[0]]: e[1].default })),
  4775. ].reduce((acc, obj) => ({ ...acc, ...obj }), {}),
  4776. name: GM_info.script.name,
  4777. get: function (key, def) {
  4778. if (key in this.values) {
  4779. return this.values[key];
  4780. }
  4781. return def;
  4782. },
  4783. set: function (key, value) {
  4784. this.values[key] = value;
  4785. db.set(this.userId, this.values).catch(
  4786. e => null
  4787. );
  4788. localStorage[this.name + ':' + key] = value;
  4789. },
  4790. delete: function (key) {
  4791. delete this.values[key];
  4792. db.set(this.userId, this.values);
  4793. delete localStorage[this.name + ':' + key];
  4794. }
  4795. }
  4796.  
  4797. /**
  4798. * Returns all keys from localStorage that start with prefix (for migration)
  4799. *
  4800. * Возвращает все ключи из localStorage которые начинаются с prefix (для миграции)
  4801. */
  4802. function getAllValuesStartingWith(prefix) {
  4803. const values = [];
  4804. for (let i = 0; i < localStorage.length; i++) {
  4805. const key = localStorage.key(i);
  4806. if (key.startsWith(prefix)) {
  4807. const val = localStorage.getItem(key);
  4808. const keyValue = key.split(':')[1];
  4809. values.push({ key: keyValue, val });
  4810. }
  4811. }
  4812. return values;
  4813. }
  4814.  
  4815. /**
  4816. * Opens or migrates to a database
  4817. *
  4818. * Открывает или мигрирует в базу данных
  4819. */
  4820. async function openOrMigrateDatabase(userId) {
  4821. storage.userId = userId;
  4822. try {
  4823. await db.open();
  4824. } catch(e) {
  4825. return;
  4826. }
  4827. let settings = await db.get(userId, false);
  4828.  
  4829. if (settings) {
  4830. storage.values = settings;
  4831. return;
  4832. }
  4833.  
  4834. const values = getAllValuesStartingWith(GM_info.script.name);
  4835. for (const value of values) {
  4836. let val = null;
  4837. try {
  4838. val = JSON.parse(value.val);
  4839. } catch {
  4840. break;
  4841. }
  4842. storage.values[value.key] = val;
  4843. }
  4844. await db.set(userId, storage.values);
  4845. }
  4846.  
  4847. class ZingerYWebsiteAPI {
  4848. /**
  4849. * Class for interaction with the API of the zingery.ru website
  4850. * Intended only for use with the HeroWarsHelper script:
  4851. * https://greasyfork.org/ru/scripts/450693-herowarshelper
  4852. * Copyright ZingerY
  4853. */
  4854. url = 'https://zingery.ru/heroes/';
  4855. // YWJzb2x1dGVseSB1c2VsZXNzIGxpbmU=
  4856. constructor(urn, env, data = {}) {
  4857. this.urn = urn;
  4858. this.fd = {
  4859. now: Date.now(),
  4860. fp: this.constructor.toString().replaceAll(/\s/g, ''),
  4861. env: env.callee.toString().replaceAll(/\s/g, ''),
  4862. info: (({ name, version, author }) => [name, version, author])(GM_info.script),
  4863. ...data,
  4864. };
  4865. }
  4866. sign() {
  4867. return md5([...this.fd.info, ~(this.fd.now % 1e3), this.fd.fp].join('_'));
  4868. }
  4869. encode(data) {
  4870. return btoa(encodeURIComponent(JSON.stringify(data)));
  4871. }
  4872. decode(data) {
  4873. return JSON.parse(decodeURIComponent(atob(data)));
  4874. }
  4875. headers() {
  4876. return {
  4877. 'X-Request-Signature': this.sign(),
  4878. 'X-Script-Name': GM_info.script.name,
  4879. 'X-Script-Version': GM_info.script.version,
  4880. 'X-Script-Author': GM_info.script.author,
  4881. 'X-Script-ZingerY': 42,
  4882. };
  4883. }
  4884. async request() {
  4885. try {
  4886. const response = await fetch(this.url + this.urn, {
  4887. method: 'POST',
  4888. headers: this.headers(),
  4889. body: this.encode(this.fd),
  4890. });
  4891. const text = await response.text();
  4892. return this.decode(text);
  4893. } catch (e) {
  4894. console.error(e);
  4895. return [];
  4896. }
  4897. }
  4898. /**
  4899. * Класс для взаимодействия с API сайта zingery.ru
  4900. * Предназначен только для использования со скриптом HeroWarsHelper:
  4901. * https://greasyfork.org/ru/scripts/450693-herowarshelper
  4902. * Copyright ZingerY
  4903. */
  4904. }
  4905.  
  4906. /**
  4907. * Sending expeditions
  4908. *
  4909. * Отправка экспедиций
  4910. */
  4911. function checkExpedition() {
  4912. return new Promise((resolve, reject) => {
  4913. const expedition = new Expedition(resolve, reject);
  4914. expedition.start();
  4915. });
  4916. }
  4917.  
  4918. class Expedition {
  4919. checkExpedInfo = {
  4920. calls: [
  4921. {
  4922. name: 'expeditionGet',
  4923. args: {},
  4924. ident: 'expeditionGet',
  4925. },
  4926. {
  4927. name: 'heroGetAll',
  4928. args: {},
  4929. ident: 'heroGetAll',
  4930. },
  4931. ],
  4932. };
  4933.  
  4934. constructor(resolve, reject) {
  4935. this.resolve = resolve;
  4936. this.reject = reject;
  4937. }
  4938.  
  4939. async start() {
  4940. const data = await Send(JSON.stringify(this.checkExpedInfo));
  4941.  
  4942. const expedInfo = data.results[0].result.response;
  4943. const dataHeroes = data.results[1].result.response;
  4944. const dataExped = { useHeroes: [], exped: [] };
  4945. const calls = [];
  4946.  
  4947. /**
  4948. * Adding expeditions to collect
  4949. * Добавляем экспедиции для сбора
  4950. */
  4951. let countGet = 0;
  4952. for (var n in expedInfo) {
  4953. const exped = expedInfo[n];
  4954. const dateNow = Date.now() / 1000;
  4955. if (exped.status == 2 && exped.endTime != 0 && dateNow > exped.endTime) {
  4956. countGet++;
  4957. calls.push({
  4958. name: 'expeditionFarm',
  4959. args: { expeditionId: exped.id },
  4960. ident: 'expeditionFarm_' + exped.id,
  4961. });
  4962. } else {
  4963. dataExped.useHeroes = dataExped.useHeroes.concat(exped.heroes);
  4964. }
  4965. if (exped.status == 1) {
  4966. dataExped.exped.push({ id: exped.id, power: exped.power });
  4967. }
  4968. }
  4969. dataExped.exped = dataExped.exped.sort((a, b) => b.power - a.power);
  4970.  
  4971. /**
  4972. * Putting together a list of heroes
  4973. * Собираем список героев
  4974. */
  4975. const heroesArr = [];
  4976. for (let n in dataHeroes) {
  4977. const hero = dataHeroes[n];
  4978. if (hero.xp > 0 && !dataExped.useHeroes.includes(hero.id)) {
  4979. let heroPower = hero.power;
  4980. // Лара Крофт * 3
  4981. if (hero.id == 63 && hero.color >= 16) {
  4982. heroPower *= 3;
  4983. }
  4984. heroesArr.push({ id: hero.id, power: heroPower });
  4985. }
  4986. }
  4987.  
  4988. /**
  4989. * Adding expeditions to send
  4990. * Добавляем экспедиции для отправки
  4991. */
  4992. let countSend = 0;
  4993. heroesArr.sort((a, b) => a.power - b.power);
  4994. for (const exped of dataExped.exped) {
  4995. let heroesIds = this.selectionHeroes(heroesArr, exped.power);
  4996. if (heroesIds && heroesIds.length > 4) {
  4997. for (let q in heroesArr) {
  4998. if (heroesIds.includes(heroesArr[q].id)) {
  4999. delete heroesArr[q];
  5000. }
  5001. }
  5002. countSend++;
  5003. calls.push({
  5004. name: 'expeditionSendHeroes',
  5005. args: {
  5006. expeditionId: exped.id,
  5007. heroes: heroesIds,
  5008. },
  5009. ident: 'expeditionSendHeroes_' + exped.id,
  5010. });
  5011. }
  5012. }
  5013.  
  5014. if (calls.length) {
  5015. await Send({ calls });
  5016. this.end(I18N('EXPEDITIONS_SENT', {countGet, countSend}));
  5017. return;
  5018. }
  5019. this.end(I18N('EXPEDITIONS_NOTHING'));
  5020. }
  5021.  
  5022. /**
  5023. * Selection of heroes for expeditions
  5024. *
  5025. * Подбор героев для экспедиций
  5026. */
  5027. selectionHeroes(heroes, power) {
  5028. const resultHeroers = [];
  5029. const heroesIds = [];
  5030. for (let q = 0; q < 5; q++) {
  5031. for (let i in heroes) {
  5032. let hero = heroes[i];
  5033. if (heroesIds.includes(hero.id)) {
  5034. continue;
  5035. }
  5036.  
  5037. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  5038. const need = Math.round((power - summ) / (5 - resultHeroers.length));
  5039. if (hero.power > need) {
  5040. resultHeroers.push(hero);
  5041. heroesIds.push(hero.id);
  5042. break;
  5043. }
  5044. }
  5045. }
  5046.  
  5047. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  5048. if (summ < power) {
  5049. return false;
  5050. }
  5051. return heroesIds;
  5052. }
  5053.  
  5054. /**
  5055. * Ends expedition script
  5056. *
  5057. * Завершает скрипт экспедиции
  5058. */
  5059. end(msg) {
  5060. setProgress(msg, true);
  5061. this.resolve();
  5062. }
  5063. }
  5064.  
  5065. /**
  5066. * Walkthrough of the dungeon
  5067. *
  5068. * Прохождение подземелья
  5069. */
  5070. function testDungeon() {
  5071. return new Promise((resolve, reject) => {
  5072. const dung = new executeDungeon(resolve, reject);
  5073. const titanit = getInput('countTitanit');
  5074. dung.start(titanit);
  5075. });
  5076. }
  5077.  
  5078. /**
  5079. * Walkthrough of the dungeon
  5080. *
  5081. * Прохождение подземелья
  5082. */
  5083. function executeDungeon(resolve, reject) {
  5084. dungeonActivity = 0;
  5085. maxDungeonActivity = 150;
  5086.  
  5087. titanGetAll = [];
  5088.  
  5089. teams = {
  5090. heroes: [],
  5091. earth: [],
  5092. fire: [],
  5093. neutral: [],
  5094. water: [],
  5095. }
  5096.  
  5097. titanStats = [];
  5098.  
  5099. titansStates = {};
  5100.  
  5101. callsExecuteDungeon = {
  5102. calls: [{
  5103. name: "dungeonGetInfo",
  5104. args: {},
  5105. ident: "dungeonGetInfo"
  5106. }, {
  5107. name: "teamGetAll",
  5108. args: {},
  5109. ident: "teamGetAll"
  5110. }, {
  5111. name: "teamGetFavor",
  5112. args: {},
  5113. ident: "teamGetFavor"
  5114. }, {
  5115. name: "clanGetInfo",
  5116. args: {},
  5117. ident: "clanGetInfo"
  5118. }, {
  5119. name: "titanGetAll",
  5120. args: {},
  5121. ident: "titanGetAll"
  5122. }, {
  5123. name: "inventoryGet",
  5124. args: {},
  5125. ident: "inventoryGet"
  5126. }]
  5127. }
  5128.  
  5129. this.start = function(titanit) {
  5130. maxDungeonActivity = titanit || getInput('countTitanit');
  5131. send(JSON.stringify(callsExecuteDungeon), startDungeon);
  5132. }
  5133.  
  5134. /**
  5135. * Getting data on the dungeon
  5136. *
  5137. * Получаем данные по подземелью
  5138. */
  5139. function startDungeon(e) {
  5140. stopDung = false; // стоп подземка
  5141. res = e.results;
  5142. dungeonGetInfo = res[0].result.response;
  5143. if (!dungeonGetInfo) {
  5144. endDungeon('noDungeon', res);
  5145. return;
  5146. }
  5147. teamGetAll = res[1].result.response;
  5148. teamGetFavor = res[2].result.response;
  5149. dungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  5150. titanGetAll = Object.values(res[4].result.response);
  5151. countPredictionCard = res[5].result.response.consumable[81];
  5152.  
  5153. teams.hero = {
  5154. favor: teamGetFavor.dungeon_hero,
  5155. heroes: teamGetAll.dungeon_hero.filter(id => id < 6000),
  5156. teamNum: 0,
  5157. }
  5158. heroPet = teamGetAll.dungeon_hero.filter(id => id >= 6000).pop();
  5159. if (heroPet) {
  5160. teams.hero.pet = heroPet;
  5161. }
  5162.  
  5163. teams.neutral = {
  5164. favor: {},
  5165. heroes: getTitanTeam(titanGetAll, 'neutral'),
  5166. teamNum: 0,
  5167. };
  5168. teams.water = {
  5169. favor: {},
  5170. heroes: getTitanTeam(titanGetAll, 'water'),
  5171. teamNum: 0,
  5172. };
  5173. teams.fire = {
  5174. favor: {},
  5175. heroes: getTitanTeam(titanGetAll, 'fire'),
  5176. teamNum: 0,
  5177. };
  5178. teams.earth = {
  5179. favor: {},
  5180. heroes: getTitanTeam(titanGetAll, 'earth'),
  5181. teamNum: 0,
  5182. };
  5183.  
  5184.  
  5185. checkFloor(dungeonGetInfo);
  5186. }
  5187.  
  5188. function getTitanTeam(titans, type) {
  5189. switch (type) {
  5190. case 'neutral':
  5191. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5192. case 'water':
  5193. return titans.filter(e => e.id.toString().slice(2, 3) == '0').map(e => e.id);
  5194. case 'fire':
  5195. return titans.filter(e => e.id.toString().slice(2, 3) == '1').map(e => e.id);
  5196. case 'earth':
  5197. return titans.filter(e => e.id.toString().slice(2, 3) == '2').map(e => e.id);
  5198. }
  5199. }
  5200.  
  5201. function getNeutralTeam() {
  5202. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  5203. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5204. }
  5205.  
  5206. function fixTitanTeam(titans) {
  5207. titans.heroes = titans.heroes.filter(e => !titansStates[e]?.isDead);
  5208. return titans;
  5209. }
  5210.  
  5211. /**
  5212. * Checking the floor
  5213. *
  5214. * Проверяем этаж
  5215. */
  5216. async function checkFloor(dungeonInfo) {
  5217. if (!('floor' in dungeonInfo) || dungeonInfo.floor?.state == 2) {
  5218. saveProgress();
  5219. return;
  5220. }
  5221. // console.log(dungeonInfo, dungeonActivity);
  5222. setProgress(`${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  5223. if (dungeonActivity >= maxDungeonActivity) {
  5224. endDungeon('endDungeon', 'maxActive ' + dungeonActivity + '/' + maxDungeonActivity);
  5225. return;
  5226. }
  5227. titansStates = dungeonInfo.states.titans;
  5228. titanStats = titanObjToArray(titansStates);
  5229. if (stopDung){
  5230. endDungeon('Стоп подземка,', 'набрано титанита: ' + dungeonActivity + '/' + maxDungeonActivity);
  5231. return;
  5232. }
  5233. const floorChoices = dungeonInfo.floor.userData;
  5234. const floorType = dungeonInfo.floorType;
  5235. //const primeElement = dungeonInfo.elements.prime;
  5236. if (floorType == "battle") {
  5237. const calls = [];
  5238. for (let teamNum in floorChoices) {
  5239. attackerType = floorChoices[teamNum].attackerType;
  5240. const args = fixTitanTeam(teams[attackerType]);
  5241. if (attackerType == 'neutral') {
  5242. args.heroes = getNeutralTeam();
  5243. }
  5244. if (!args.heroes.length) {
  5245. continue;
  5246. }
  5247. args.teamNum = teamNum;
  5248. calls.push({
  5249. name: "dungeonStartBattle",
  5250. args,
  5251. ident: "body_" + teamNum
  5252. })
  5253. }
  5254. if (!calls.length) {
  5255. endDungeon('endDungeon', 'All Dead');
  5256. return;
  5257. }
  5258. const battleDatas = await Send(JSON.stringify({ calls }))
  5259. .then(e => e.results.map(n => n.result.response))
  5260. const battleResults = [];
  5261. for (n in battleDatas) {
  5262. battleData = battleDatas[n]
  5263. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  5264. battleResults.push(await Calc(battleData).then(result => {
  5265. result.teamNum = n;
  5266. result.attackerType = floorChoices[n].attackerType;
  5267. return result;
  5268. }));
  5269. }
  5270. processingPromises(battleResults)
  5271. }
  5272. }
  5273.  
  5274. function processingPromises(results) {
  5275. let selectBattle = results[0];
  5276. if (results.length < 2) {
  5277. // console.log(selectBattle);
  5278. if (!selectBattle.result.win) {
  5279. endDungeon('dungeonEndBattle\n', selectBattle);
  5280. return;
  5281. }
  5282. endBattle(selectBattle);
  5283. return;
  5284. }
  5285.  
  5286. selectBattle = false;
  5287. let bestState = -1000;
  5288. for (const result of results) {
  5289. const recovery = getState(result);
  5290. if (recovery > bestState) {
  5291. bestState = recovery;
  5292. selectBattle = result
  5293. }
  5294. }
  5295. // console.log(selectBattle.teamNum, results);
  5296. if (!selectBattle || bestState <= -1000) {
  5297. endDungeon('dungeonEndBattle\n', results);
  5298. return;
  5299. }
  5300.  
  5301. startBattle(selectBattle.teamNum, selectBattle.attackerType)
  5302. .then(endBattle);
  5303. }
  5304.  
  5305. /**
  5306. * Let's start the fight
  5307. *
  5308. * Начинаем бой
  5309. */
  5310. function startBattle(teamNum, attackerType) {
  5311. return new Promise(function (resolve, reject) {
  5312. args = fixTitanTeam(teams[attackerType]);
  5313. args.teamNum = teamNum;
  5314. if (attackerType == 'neutral') {
  5315. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  5316. args.heroes = titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5317. }
  5318. startBattleCall = {
  5319. calls: [{
  5320. name: "dungeonStartBattle",
  5321. args,
  5322. ident: "body"
  5323. }]
  5324. }
  5325. send(JSON.stringify(startBattleCall), resultBattle, {
  5326. resolve,
  5327. teamNum,
  5328. attackerType
  5329. });
  5330. });
  5331. }
  5332. /**
  5333. * Returns the result of the battle in a promise
  5334. *
  5335. * Возращает резульат боя в промис
  5336. */
  5337. function resultBattle(resultBattles, args) {
  5338. battleData = resultBattles.results[0].result.response;
  5339. battleType = "get_tower";
  5340. if (battleData.type == "dungeon_titan") {
  5341. battleType = "get_titan";
  5342. }
  5343. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  5344. BattleCalc(battleData, battleType, function (result) {
  5345. result.teamNum = args.teamNum;
  5346. result.attackerType = args.attackerType;
  5347. args.resolve(result);
  5348. });
  5349. }
  5350. /**
  5351. * Finishing the fight
  5352. *
  5353. * Заканчиваем бой
  5354. */
  5355. async function endBattle(battleInfo) {
  5356. if (battleInfo.result.win) {
  5357. const args = {
  5358. result: battleInfo.result,
  5359. progress: battleInfo.progress,
  5360. }
  5361. if (countPredictionCard > 0) {
  5362. args.isRaid = true;
  5363. } else {
  5364. const timer = getTimer(battleInfo.battleTime);
  5365. console.log(timer);
  5366. await countdownTimer(timer, `${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  5367. }
  5368. const calls = [{
  5369. name: "dungeonEndBattle",
  5370. args,
  5371. ident: "body"
  5372. }];
  5373. lastDungeonBattleData = null;
  5374. send(JSON.stringify({ calls }), resultEndBattle);
  5375. } else {
  5376. endDungeon('dungeonEndBattle win: false\n', battleInfo);
  5377. }
  5378. }
  5379.  
  5380. /**
  5381. * Getting and processing battle results
  5382. *
  5383. * Получаем и обрабатываем результаты боя
  5384. */
  5385. function resultEndBattle(e) {
  5386. if ('error' in e) {
  5387. popup.confirm(I18N('ERROR_MSG', {
  5388. name: e.error.name,
  5389. description: e.error.description,
  5390. }));
  5391. endDungeon('errorRequest', e);
  5392. return;
  5393. }
  5394. battleResult = e.results[0].result.response;
  5395. if ('error' in battleResult) {
  5396. endDungeon('errorBattleResult', battleResult);
  5397. return;
  5398. }
  5399. dungeonGetInfo = battleResult.dungeon ?? battleResult;
  5400. dungeonActivity += battleResult.reward.dungeonActivity ?? 0;
  5401. checkFloor(dungeonGetInfo);
  5402. }
  5403.  
  5404. /**
  5405. * Returns the coefficient of condition of the
  5406. * difference in titanium before and after the battle
  5407. *
  5408. * Возвращает коэффициент состояния титанов после боя
  5409. */
  5410. function getState(result) {
  5411. if (!result.result.win) {
  5412. return -1000;
  5413. }
  5414.  
  5415. let beforeSumFactor = 0;
  5416. const beforeTitans = result.battleData.attackers;
  5417. for (let titanId in beforeTitans) {
  5418. const titan = beforeTitans[titanId];
  5419. const state = titan.state;
  5420. let factor = 1;
  5421. if (state) {
  5422. const hp = state.hp / titan.hp;
  5423. const energy = state.energy / 1e3;
  5424. factor = hp + energy / 20
  5425. }
  5426. beforeSumFactor += factor;
  5427. }
  5428.  
  5429. let afterSumFactor = 0;
  5430. const afterTitans = result.progress[0].attackers.heroes;
  5431. for (let titanId in afterTitans) {
  5432. const titan = afterTitans[titanId];
  5433. const hp = titan.hp / beforeTitans[titanId].hp;
  5434. const energy = titan.energy / 1e3;
  5435. const factor = hp + energy / 20;
  5436. afterSumFactor += factor;
  5437. }
  5438. return afterSumFactor - beforeSumFactor;
  5439. }
  5440.  
  5441. /**
  5442. * Converts an object with IDs to an array with IDs
  5443. *
  5444. * Преобразует объект с идетификаторами в массив с идетификаторами
  5445. */
  5446. function titanObjToArray(obj) {
  5447. let titans = [];
  5448. for (let id in obj) {
  5449. obj[id].id = id;
  5450. titans.push(obj[id]);
  5451. }
  5452. return titans;
  5453. }
  5454.  
  5455. function saveProgress() {
  5456. let saveProgressCall = {
  5457. calls: [{
  5458. name: "dungeonSaveProgress",
  5459. args: {},
  5460. ident: "body"
  5461. }]
  5462. }
  5463. send(JSON.stringify(saveProgressCall), resultEndBattle);
  5464. }
  5465.  
  5466. function endDungeon(reason, info) {
  5467. console.warn(reason, info);
  5468. setProgress(`${I18N('DUNGEON')} ${I18N('COMPLETED')}`, true);
  5469. resolve();
  5470. }
  5471. }
  5472.  
  5473. /**
  5474. * Passing the tower
  5475. *
  5476. * Прохождение башни
  5477. */
  5478. function testTower() {
  5479. return new Promise((resolve, reject) => {
  5480. tower = new executeTower(resolve, reject);
  5481. tower.start();
  5482. });
  5483. }
  5484.  
  5485. /**
  5486. * Passing the tower
  5487. *
  5488. * Прохождение башни
  5489. */
  5490. function executeTower(resolve, reject) {
  5491. lastTowerInfo = {};
  5492.  
  5493. scullCoin = 0;
  5494.  
  5495. heroGetAll = [];
  5496.  
  5497. heroesStates = {};
  5498.  
  5499. argsBattle = {
  5500. heroes: [],
  5501. favor: {},
  5502. };
  5503.  
  5504. callsExecuteTower = {
  5505. calls: [{
  5506. name: "towerGetInfo",
  5507. args: {},
  5508. ident: "towerGetInfo"
  5509. }, {
  5510. name: "teamGetAll",
  5511. args: {},
  5512. ident: "teamGetAll"
  5513. }, {
  5514. name: "teamGetFavor",
  5515. args: {},
  5516. ident: "teamGetFavor"
  5517. }, {
  5518. name: "inventoryGet",
  5519. args: {},
  5520. ident: "inventoryGet"
  5521. }, {
  5522. name: "heroGetAll",
  5523. args: {},
  5524. ident: "heroGetAll"
  5525. }]
  5526. }
  5527.  
  5528. buffIds = [
  5529. {id: 0, cost: 0, isBuy: false}, // plug // заглушка
  5530. {id: 1, cost: 1, isBuy: true}, // 3% attack // 3% атака
  5531. {id: 2, cost: 6, isBuy: true}, // 2% attack // 2% атака
  5532. {id: 3, cost: 16, isBuy: true}, // 4% attack // 4% атака
  5533. {id: 4, cost: 40, isBuy: true}, // 8% attack // 8% атака
  5534. {id: 5, cost: 1, isBuy: true}, // 10% armor // 10% броня
  5535. {id: 6, cost: 6, isBuy: true}, // 5% armor // 5% броня
  5536. {id: 7, cost: 16, isBuy: true}, // 10% armor // 10% броня
  5537. {id: 8, cost: 40, isBuy: true}, // 20% armor // 20% броня
  5538. { id: 9, cost: 1, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5539. { id: 10, cost: 6, isBuy: true }, // 5% protection from magic // 5% защита от магии
  5540. { id: 11, cost: 16, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5541. { id: 12, cost: 40, isBuy: true }, // 20% protection from magic // 20% защита от магии
  5542. { id: 13, cost: 1, isBuy: false }, // 40% health hero // 40% здоровья герою
  5543. { id: 14, cost: 6, isBuy: false }, // 40% health hero // 40% здоровья герою
  5544. { id: 15, cost: 16, isBuy: false }, // 80% health hero // 80% здоровья герою
  5545. { id: 16, cost: 40, isBuy: false }, // 40% health to all heroes // 40% здоровья всем героям
  5546. { id: 17, cost: 1, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5547. { id: 18, cost: 3, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5548. { id: 19, cost: 8, isBuy: false }, // 80% energy to the hero // 80% энергии герою
  5549. { id: 20, cost: 20, isBuy: false }, // 40% energy to all heroes // 40% энергии всем героям
  5550. { id: 21, cost: 40, isBuy: false }, // Hero Resurrection // Воскрешение героя
  5551. ]
  5552.  
  5553. this.start = function () {
  5554. send(JSON.stringify(callsExecuteTower), startTower);
  5555. }
  5556.  
  5557. /**
  5558. * Getting data on the Tower
  5559. *
  5560. * Получаем данные по башне
  5561. */
  5562. function startTower(e) {
  5563. res = e.results;
  5564. towerGetInfo = res[0].result.response;
  5565. if (!towerGetInfo) {
  5566. endTower('noTower', res);
  5567. return;
  5568. }
  5569. teamGetAll = res[1].result.response;
  5570. teamGetFavor = res[2].result.response;
  5571. inventoryGet = res[3].result.response;
  5572. heroGetAll = Object.values(res[4].result.response);
  5573.  
  5574. scullCoin = inventoryGet.coin[7] ?? 0;
  5575.  
  5576. argsBattle.favor = teamGetFavor.tower;
  5577. argsBattle.heroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5578. pet = teamGetAll.tower.filter(id => id >= 6000).pop();
  5579. if (pet) {
  5580. argsBattle.pet = pet;
  5581. }
  5582.  
  5583. checkFloor(towerGetInfo);
  5584. }
  5585.  
  5586. function fixHeroesTeam(argsBattle) {
  5587. let fixHeroes = argsBattle.heroes.filter(e => !heroesStates[e]?.isDead);
  5588. if (fixHeroes.length < 5) {
  5589. heroGetAll = heroGetAll.filter(e => !heroesStates[e.id]?.isDead);
  5590. fixHeroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5591. Object.keys(argsBattle.favor).forEach(e => {
  5592. if (!fixHeroes.includes(+e)) {
  5593. delete argsBattle.favor[e];
  5594. }
  5595. })
  5596. }
  5597. argsBattle.heroes = fixHeroes;
  5598. return argsBattle;
  5599. }
  5600.  
  5601. /**
  5602. * Check the floor
  5603. *
  5604. * Проверяем этаж
  5605. */
  5606. function checkFloor(towerInfo) {
  5607. lastTowerInfo = towerInfo;
  5608. maySkipFloor = +towerInfo.maySkipFloor;
  5609. floorNumber = +towerInfo.floorNumber;
  5610. heroesStates = towerInfo.states.heroes;
  5611. floorInfo = towerInfo.floor;
  5612.  
  5613. /**
  5614. * Is there at least one chest open on the floor
  5615. * Открыт ли на этаже хоть один сундук
  5616. */
  5617. isOpenChest = false;
  5618. if (towerInfo.floorType == "chest") {
  5619. isOpenChest = towerInfo.floor.chests.reduce((n, e) => n + e.opened, 0);
  5620. }
  5621.  
  5622. setProgress(`${I18N('TOWER')}: ${I18N('FLOOR')} ${floorNumber}`);
  5623. if (floorNumber > 49) {
  5624. if (isOpenChest) {
  5625. endTower('alreadyOpenChest 50 floor', floorNumber);
  5626. return;
  5627. }
  5628. }
  5629. /**
  5630. * If the chest is open and you can skip floors, then move on
  5631. * Если сундук открыт и можно скипать этажи, то переходим дальше
  5632. */
  5633. if (towerInfo.mayFullSkip && +towerInfo.teamLevel == 130) {
  5634. if (isOpenChest) {
  5635. nextOpenChest(floorNumber);
  5636. } else {
  5637. nextChestOpen(floorNumber);
  5638. }
  5639. return;
  5640. }
  5641.  
  5642. // console.log(towerInfo, scullCoin);
  5643. switch (towerInfo.floorType) {
  5644. case "battle":
  5645. if (floorNumber <= maySkipFloor) {
  5646. skipFloor();
  5647. return;
  5648. }
  5649. if (floorInfo.state == 2) {
  5650. nextFloor();
  5651. return;
  5652. }
  5653. startBattle().then(endBattle);
  5654. return;
  5655. case "buff":
  5656. checkBuff(towerInfo);
  5657. return;
  5658. case "chest":
  5659. openChest(floorNumber);
  5660. return;
  5661. default:
  5662. console.log('!', towerInfo.floorType, towerInfo);
  5663. break;
  5664. }
  5665. }
  5666.  
  5667. /**
  5668. * Let's start the fight
  5669. *
  5670. * Начинаем бой
  5671. */
  5672. function startBattle() {
  5673. return new Promise(function (resolve, reject) {
  5674. towerStartBattle = {
  5675. calls: [{
  5676. name: "towerStartBattle",
  5677. args: fixHeroesTeam(argsBattle),
  5678. ident: "body"
  5679. }]
  5680. }
  5681. send(JSON.stringify(towerStartBattle), resultBattle, resolve);
  5682. });
  5683. }
  5684. /**
  5685. * Returns the result of the battle in a promise
  5686. *
  5687. * Возращает резульат боя в промис
  5688. */
  5689. function resultBattle(resultBattles, resolve) {
  5690. battleData = resultBattles.results[0].result.response;
  5691. battleType = "get_tower";
  5692. BattleCalc(battleData, battleType, function (result) {
  5693. resolve(result);
  5694. });
  5695. }
  5696. /**
  5697. * Finishing the fight
  5698. *
  5699. * Заканчиваем бой
  5700. */
  5701. function endBattle(battleInfo) {
  5702. if (battleInfo.result.stars >= 3) {
  5703. endBattleCall = {
  5704. calls: [{
  5705. name: "towerEndBattle",
  5706. args: {
  5707. result: battleInfo.result,
  5708. progress: battleInfo.progress,
  5709. },
  5710. ident: "body"
  5711. }]
  5712. }
  5713. send(JSON.stringify(endBattleCall), resultEndBattle);
  5714. } else {
  5715. endTower('towerEndBattle win: false\n', battleInfo);
  5716. }
  5717. }
  5718.  
  5719. /**
  5720. * Getting and processing battle results
  5721. *
  5722. * Получаем и обрабатываем результаты боя
  5723. */
  5724. function resultEndBattle(e) {
  5725. battleResult = e.results[0].result.response;
  5726. if ('error' in battleResult) {
  5727. endTower('errorBattleResult', battleResult);
  5728. return;
  5729. }
  5730. if ('reward' in battleResult) {
  5731. scullCoin += battleResult.reward?.coin[7] ?? 0;
  5732. }
  5733. nextFloor();
  5734. }
  5735.  
  5736. function nextFloor() {
  5737. nextFloorCall = {
  5738. calls: [{
  5739. name: "towerNextFloor",
  5740. args: {},
  5741. ident: "body"
  5742. }]
  5743. }
  5744. send(JSON.stringify(nextFloorCall), checkDataFloor);
  5745. }
  5746.  
  5747. function openChest(floorNumber) {
  5748. floorNumber = floorNumber || 0;
  5749. openChestCall = {
  5750. calls: [{
  5751. name: "towerOpenChest",
  5752. args: {
  5753. num: 2
  5754. },
  5755. ident: "body"
  5756. }]
  5757. }
  5758. send(JSON.stringify(openChestCall), floorNumber < 50 ? nextFloor : lastChest);
  5759. }
  5760.  
  5761. function lastChest() {
  5762. endTower('openChest 50 floor', floorNumber);
  5763. }
  5764.  
  5765. function skipFloor() {
  5766. skipFloorCall = {
  5767. calls: [{
  5768. name: "towerSkipFloor",
  5769. args: {},
  5770. ident: "body"
  5771. }]
  5772. }
  5773. send(JSON.stringify(skipFloorCall), checkDataFloor);
  5774. }
  5775.  
  5776. function checkBuff(towerInfo) {
  5777. buffArr = towerInfo.floor;
  5778. promises = [];
  5779. for (let buff of buffArr) {
  5780. buffInfo = buffIds[buff.id];
  5781. if (buffInfo.isBuy && buffInfo.cost <= scullCoin) {
  5782. scullCoin -= buffInfo.cost;
  5783. promises.push(buyBuff(buff.id));
  5784. }
  5785. }
  5786. Promise.all(promises).then(nextFloor);
  5787. }
  5788.  
  5789. function buyBuff(buffId) {
  5790. return new Promise(function (resolve, reject) {
  5791. buyBuffCall = {
  5792. calls: [{
  5793. name: "towerBuyBuff",
  5794. args: {
  5795. buffId
  5796. },
  5797. ident: "body"
  5798. }]
  5799. }
  5800. send(JSON.stringify(buyBuffCall), resolve);
  5801. });
  5802. }
  5803.  
  5804. function checkDataFloor(result) {
  5805. towerInfo = result.results[0].result.response;
  5806. if ('reward' in towerInfo && towerInfo.reward?.coin) {
  5807. scullCoin += towerInfo.reward?.coin[7] ?? 0;
  5808. }
  5809. if ('tower' in towerInfo) {
  5810. towerInfo = towerInfo.tower;
  5811. }
  5812. if ('skullReward' in towerInfo) {
  5813. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  5814. }
  5815. checkFloor(towerInfo);
  5816. }
  5817. /**
  5818. * Getting tower rewards
  5819. *
  5820. * Получаем награды башни
  5821. */
  5822. function farmTowerRewards(reason) {
  5823. let { pointRewards, points } = lastTowerInfo;
  5824. let pointsAll = Object.getOwnPropertyNames(pointRewards);
  5825. let farmPoints = pointsAll.filter(e => +e <= +points && !pointRewards[e]);
  5826. if (!farmPoints.length) {
  5827. return;
  5828. }
  5829. let farmTowerRewardsCall = {
  5830. calls: [{
  5831. name: "tower_farmPointRewards",
  5832. args: {
  5833. points: farmPoints
  5834. },
  5835. ident: "tower_farmPointRewards"
  5836. }]
  5837. }
  5838.  
  5839. if (scullCoin > 0 && reason == 'openChest 50 floor') {
  5840. farmTowerRewardsCall.calls.push({
  5841. name: "tower_farmSkullReward",
  5842. args: {},
  5843. ident: "tower_farmSkullReward"
  5844. });
  5845. }
  5846.  
  5847. send(JSON.stringify(farmTowerRewardsCall), () => { });
  5848. }
  5849.  
  5850. function fullSkipTower() {
  5851. /**
  5852. * Next chest
  5853. *
  5854. * Следующий сундук
  5855. */
  5856. function nextChest(n) {
  5857. return {
  5858. name: "towerNextChest",
  5859. args: {},
  5860. ident: "group_" + n + "_body"
  5861. }
  5862. }
  5863. /**
  5864. * Open chest
  5865. *
  5866. * Открыть сундук
  5867. */
  5868. function openChest(n) {
  5869. return {
  5870. name: "towerOpenChest",
  5871. args: {
  5872. "num": 2
  5873. },
  5874. ident: "group_" + n + "_body"
  5875. }
  5876. }
  5877.  
  5878. const fullSkipTowerCall = {
  5879. calls: []
  5880. }
  5881.  
  5882. let n = 0;
  5883. for (let i = 0; i < 15; i++) {
  5884. fullSkipTowerCall.calls.push(nextChest(++n));
  5885. fullSkipTowerCall.calls.push(openChest(++n));
  5886. }
  5887.  
  5888. send(JSON.stringify(fullSkipTowerCall), data => {
  5889. data.results[0] = data.results[28];
  5890. checkDataFloor(data);
  5891. });
  5892. }
  5893.  
  5894. function nextChestOpen(floorNumber) {
  5895. const calls = [{
  5896. name: "towerOpenChest",
  5897. args: {
  5898. num: 2
  5899. },
  5900. ident: "towerOpenChest"
  5901. }];
  5902.  
  5903. Send(JSON.stringify({ calls })).then(e => {
  5904. nextOpenChest(floorNumber);
  5905. });
  5906. }
  5907.  
  5908. function nextOpenChest(floorNumber) {
  5909. if (floorNumber > 49) {
  5910. endTower('openChest 50 floor', floorNumber);
  5911. return;
  5912. }
  5913. if (floorNumber == 1) {
  5914. fullSkipTower();
  5915. return;
  5916. }
  5917.  
  5918. let nextOpenChestCall = {
  5919. calls: [{
  5920. name: "towerNextChest",
  5921. args: {},
  5922. ident: "towerNextChest"
  5923. }, {
  5924. name: "towerOpenChest",
  5925. args: {
  5926. num: 2
  5927. },
  5928. ident: "towerOpenChest"
  5929. }]
  5930. }
  5931. send(JSON.stringify(nextOpenChestCall), checkDataFloor);
  5932. }
  5933.  
  5934. function endTower(reason, info) {
  5935. console.log(reason, info);
  5936. if (reason != 'noTower') {
  5937. farmTowerRewards(reason);
  5938. }
  5939. setProgress(`${I18N('TOWER')} ${I18N('COMPLETED')}!`, true);
  5940. resolve();
  5941. }
  5942. }
  5943.  
  5944. /**
  5945. * Passage of the arena of the titans
  5946. *
  5947. * Прохождение арены титанов
  5948. */
  5949. function testTitanArena() {
  5950. return new Promise((resolve, reject) => {
  5951. titAren = new executeTitanArena(resolve, reject);
  5952. titAren.start();
  5953. });
  5954. }
  5955.  
  5956. /**
  5957. * Passage of the arena of the titans
  5958. *
  5959. * Прохождение арены титанов
  5960. */
  5961. function executeTitanArena(resolve, reject) {
  5962. let titan_arena = [];
  5963. let finishListBattle = [];
  5964. /**
  5965. * ID of the current batch
  5966. *
  5967. * Идетификатор текущей пачки
  5968. */
  5969. let currentRival = 0;
  5970. /**
  5971. * Number of attempts to finish off the pack
  5972. *
  5973. * Количество попыток добития пачки
  5974. */
  5975. let attempts = 0;
  5976. /**
  5977. * Was there an attempt to finish off the current shooting range
  5978. *
  5979. * Была ли попытка добития текущего тира
  5980. */
  5981. let isCheckCurrentTier = false;
  5982. /**
  5983. * Current shooting range
  5984. *
  5985. * Текущий тир
  5986. */
  5987. let currTier = 0;
  5988. /**
  5989. * Number of battles on the current dash
  5990. *
  5991. * Количество битв на текущем тире
  5992. */
  5993. let countRivalsTier = 0;
  5994.  
  5995. let callsStart = {
  5996. calls: [{
  5997. name: "titanArenaGetStatus",
  5998. args: {},
  5999. ident: "titanArenaGetStatus"
  6000. }, {
  6001. name: "teamGetAll",
  6002. args: {},
  6003. ident: "teamGetAll"
  6004. }]
  6005. }
  6006.  
  6007. this.start = function () {
  6008. send(JSON.stringify(callsStart), startTitanArena);
  6009. }
  6010.  
  6011. function startTitanArena(data) {
  6012. let titanArena = data.results[0].result.response;
  6013. if (titanArena.status == 'disabled') {
  6014. endTitanArena('disabled', titanArena);
  6015. return;
  6016. }
  6017.  
  6018. let teamGetAll = data.results[1].result.response;
  6019. titan_arena = teamGetAll.titan_arena;
  6020.  
  6021. checkTier(titanArena)
  6022. }
  6023.  
  6024. function checkTier(titanArena) {
  6025. if (titanArena.status == "peace_time") {
  6026. endTitanArena('Peace_time', titanArena);
  6027. return;
  6028. }
  6029. currTier = titanArena.tier;
  6030. if (currTier) {
  6031. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier}`);
  6032. }
  6033.  
  6034. if (titanArena.status == "completed_tier") {
  6035. titanArenaCompleteTier();
  6036. return;
  6037. }
  6038. /**
  6039. * Checking for the possibility of a raid
  6040. * Проверка на возможность рейда
  6041. */
  6042. if (titanArena.canRaid) {
  6043. titanArenaStartRaid();
  6044. return;
  6045. }
  6046. /**
  6047. * Check was an attempt to achieve the current shooting range
  6048. * Проверка была ли попытка добития текущего тира
  6049. */
  6050. if (!isCheckCurrentTier) {
  6051. checkRivals(titanArena.rivals);
  6052. return;
  6053. }
  6054.  
  6055. endTitanArena('Done or not canRaid', titanArena);
  6056. }
  6057. /**
  6058. * Submit dash information for verification
  6059. *
  6060. * Отправка информации о тире на проверку
  6061. */
  6062. function checkResultInfo(data) {
  6063. let titanArena = data.results[0].result.response;
  6064. checkTier(titanArena);
  6065. }
  6066. /**
  6067. * Finish the current tier
  6068. *
  6069. * Завершить текущий тир
  6070. */
  6071. function titanArenaCompleteTier() {
  6072. isCheckCurrentTier = false;
  6073. let calls = [{
  6074. name: "titanArenaCompleteTier",
  6075. args: {},
  6076. ident: "body"
  6077. }];
  6078. send(JSON.stringify({calls}), checkResultInfo);
  6079. }
  6080. /**
  6081. * Gathering points to be completed
  6082. *
  6083. * Собираем точки которые нужно добить
  6084. */
  6085. function checkRivals(rivals) {
  6086. finishListBattle = [];
  6087. for (let n in rivals) {
  6088. if (rivals[n].attackScore < 250) {
  6089. finishListBattle.push(n);
  6090. }
  6091. }
  6092. console.log('checkRivals', finishListBattle);
  6093. countRivalsTier = finishListBattle.length;
  6094. roundRivals();
  6095. }
  6096. /**
  6097. * Selecting the next point to finish off
  6098. *
  6099. * Выбор следующей точки для добития
  6100. */
  6101. function roundRivals() {
  6102. let countRivals = finishListBattle.length;
  6103. if (!countRivals) {
  6104. /**
  6105. * Whole range checked
  6106. *
  6107. * Весь тир проверен
  6108. */
  6109. isCheckCurrentTier = true;
  6110. titanArenaGetStatus();
  6111. return;
  6112. }
  6113. // setProgress('TitanArena: Уровень ' + currTier + ' Бои: ' + (countRivalsTier - countRivals + 1) + '/' + countRivalsTier);
  6114. currentRival = finishListBattle.pop();
  6115. attempts = +currentRival;
  6116. // console.log('roundRivals', currentRival);
  6117. titanArenaStartBattle(currentRival);
  6118. }
  6119. /**
  6120. * The start of a solo battle
  6121. *
  6122. * Начало одиночной битвы
  6123. */
  6124. function titanArenaStartBattle(rivalId) {
  6125. let calls = [{
  6126. name: "titanArenaStartBattle",
  6127. args: {
  6128. rivalId: rivalId,
  6129. titans: titan_arena
  6130. },
  6131. ident: "body"
  6132. }];
  6133. send(JSON.stringify({calls}), calcResult);
  6134. }
  6135. /**
  6136. * Calculation of the results of the battle
  6137. *
  6138. * Расчет результатов боя
  6139. */
  6140. function calcResult(data) {
  6141. let battlesInfo = data.results[0].result.response.battle;
  6142. /**
  6143. * If attempts are equal to the current battle number we make
  6144. * Если попытки равны номеру текущего боя делаем прерасчет
  6145. */
  6146. if (attempts == currentRival) {
  6147. preCalcBattle(battlesInfo);
  6148. return;
  6149. }
  6150. /**
  6151. * If there are still attempts, we calculate a new battle
  6152. * Если попытки еще есть делаем расчет нового боя
  6153. */
  6154. if (attempts > 0) {
  6155. attempts--;
  6156. calcBattleResult(battlesInfo)
  6157. .then(resultCalcBattle);
  6158. return;
  6159. }
  6160. /**
  6161. * Otherwise, go to the next opponent
  6162. * Иначе переходим к следующему сопернику
  6163. */
  6164. roundRivals();
  6165. }
  6166. /**
  6167. * Processing the results of the battle calculation
  6168. *
  6169. * Обработка результатов расчета битвы
  6170. */
  6171. function resultCalcBattle(resultBattle) {
  6172. // console.log('resultCalcBattle', currentRival, attempts, resultBattle.result.win);
  6173. /**
  6174. * If the current calculation of victory is not a chance or the attempt ended with the finish the battle
  6175. * Если текущий расчет победа или шансов нет или попытки кончились завершаем бой
  6176. */
  6177. if (resultBattle.result.win || !attempts) {
  6178. titanArenaEndBattle({
  6179. progress: resultBattle.progress,
  6180. result: resultBattle.result,
  6181. rivalId: resultBattle.battleData.typeId
  6182. });
  6183. return;
  6184. }
  6185. /**
  6186. * If not victory and there are attempts we start a new battle
  6187. * Если не победа и есть попытки начинаем новый бой
  6188. */
  6189. titanArenaStartBattle(resultBattle.battleData.typeId);
  6190. }
  6191. /**
  6192. * Returns the promise of calculating the results of the battle
  6193. *
  6194. * Возращает промис расчета результатов битвы
  6195. */
  6196. function getBattleInfo(battle, isRandSeed) {
  6197. return new Promise(function (resolve) {
  6198. if (isRandSeed) {
  6199. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  6200. }
  6201. // console.log(battle.seed);
  6202. BattleCalc(battle, "get_titanClanPvp", e => resolve(e));
  6203. });
  6204. }
  6205. /**
  6206. * Recalculate battles
  6207. *
  6208. * Прерасчтет битвы
  6209. */
  6210. function preCalcBattle(battle) {
  6211. let actions = [getBattleInfo(battle, false)];
  6212. const countTestBattle = getInput('countTestBattle');
  6213. for (let i = 0; i < countTestBattle; i++) {
  6214. actions.push(getBattleInfo(battle, true));
  6215. }
  6216. Promise.all(actions)
  6217. .then(resultPreCalcBattle);
  6218. }
  6219. /**
  6220. * Processing the results of the battle recalculation
  6221. *
  6222. * Обработка результатов прерасчета битвы
  6223. */
  6224. function resultPreCalcBattle(e) {
  6225. let wins = e.map(n => n.result.win);
  6226. let firstBattle = e.shift();
  6227. let countWin = wins.reduce((w, s) => w + s);
  6228. const countTestBattle = getInput('countTestBattle');
  6229. console.log('resultPreCalcBattle', `${countWin}/${countTestBattle}`)
  6230. if (countWin > 0) {
  6231. attempts = getInput('countAutoBattle');
  6232. } else {
  6233. attempts = 0;
  6234. }
  6235. resultCalcBattle(firstBattle);
  6236. }
  6237.  
  6238. /**
  6239. * Complete an arena battle
  6240. *
  6241. * Завершить битву на арене
  6242. */
  6243. function titanArenaEndBattle(args) {
  6244. let calls = [{
  6245. name: "titanArenaEndBattle",
  6246. args,
  6247. ident: "body"
  6248. }];
  6249. send(JSON.stringify({calls}), resultTitanArenaEndBattle);
  6250. }
  6251.  
  6252. function resultTitanArenaEndBattle(e) {
  6253. let attackScore = e.results[0].result.response.attackScore;
  6254. let numReval = countRivalsTier - finishListBattle.length;
  6255. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier} </br>${I18N('BATTLES')}: ${numReval}/${countRivalsTier} - ${attackScore}`);
  6256. /**
  6257. * TODO: Might need to improve the results.
  6258. * TODO: Возможно стоит сделать улучшение результатов
  6259. */
  6260. // console.log('resultTitanArenaEndBattle', e)
  6261. console.log('resultTitanArenaEndBattle', numReval + '/' + countRivalsTier, attempts)
  6262. roundRivals();
  6263. }
  6264. /**
  6265. * Arena State
  6266. *
  6267. * Состояние арены
  6268. */
  6269. function titanArenaGetStatus() {
  6270. let calls = [{
  6271. name: "titanArenaGetStatus",
  6272. args: {},
  6273. ident: "body"
  6274. }];
  6275. send(JSON.stringify({calls}), checkResultInfo);
  6276. }
  6277. /**
  6278. * Arena Raid Request
  6279. *
  6280. * Запрос рейда арены
  6281. */
  6282. function titanArenaStartRaid() {
  6283. let calls = [{
  6284. name: "titanArenaStartRaid",
  6285. args: {
  6286. titans: titan_arena
  6287. },
  6288. ident: "body"
  6289. }];
  6290. send(JSON.stringify({calls}), calcResults);
  6291. }
  6292.  
  6293. function calcResults(data) {
  6294. let battlesInfo = data.results[0].result.response;
  6295. let {attackers, rivals} = battlesInfo;
  6296.  
  6297. let promises = [];
  6298. for (let n in rivals) {
  6299. rival = rivals[n];
  6300. promises.push(calcBattleResult({
  6301. attackers: attackers,
  6302. defenders: [rival.team],
  6303. seed: rival.seed,
  6304. typeId: n,
  6305. }));
  6306. }
  6307.  
  6308. Promise.all(promises)
  6309. .then(results => {
  6310. const endResults = {};
  6311. for (let info of results) {
  6312. let id = info.battleData.typeId;
  6313. endResults[id] = {
  6314. progress: info.progress,
  6315. result: info.result,
  6316. }
  6317. }
  6318. titanArenaEndRaid(endResults);
  6319. });
  6320. }
  6321.  
  6322. function calcBattleResult(battleData) {
  6323. return new Promise(function (resolve, reject) {
  6324. BattleCalc(battleData, "get_titanClanPvp", resolve);
  6325. });
  6326. }
  6327.  
  6328. /**
  6329. * Sending Raid Results
  6330. *
  6331. * Отправка результатов рейда
  6332. */
  6333. function titanArenaEndRaid(results) {
  6334. titanArenaEndRaidCall = {
  6335. calls: [{
  6336. name: "titanArenaEndRaid",
  6337. args: {
  6338. results
  6339. },
  6340. ident: "body"
  6341. }]
  6342. }
  6343. send(JSON.stringify(titanArenaEndRaidCall), checkRaidResults);
  6344. }
  6345.  
  6346. function checkRaidResults(data) {
  6347. results = data.results[0].result.response.results;
  6348. isSucsesRaid = true;
  6349. for (let i in results) {
  6350. isSucsesRaid &&= (results[i].attackScore >= 250);
  6351. }
  6352.  
  6353. if (isSucsesRaid) {
  6354. titanArenaCompleteTier();
  6355. } else {
  6356. titanArenaGetStatus();
  6357. }
  6358. }
  6359.  
  6360. function titanArenaFarmDailyReward() {
  6361. titanArenaFarmDailyRewardCall = {
  6362. calls: [{
  6363. name: "titanArenaFarmDailyReward",
  6364. args: {},
  6365. ident: "body"
  6366. }]
  6367. }
  6368. send(JSON.stringify(titanArenaFarmDailyRewardCall), () => {console.log('Done farm daily reward')});
  6369. }
  6370.  
  6371. function endTitanArena(reason, info) {
  6372. if (!['Peace_time', 'disabled'].includes(reason)) {
  6373. titanArenaFarmDailyReward();
  6374. }
  6375. console.log(reason, info);
  6376. setProgress(`${I18N('TITAN_ARENA')} ${I18N('COMPLETED')}!`, true);
  6377. resolve();
  6378. }
  6379. }
  6380.  
  6381. function hackGame() {
  6382. const self = this;
  6383. selfGame = null;
  6384. bindId = 1e9;
  6385. this.libGame = null;
  6386.  
  6387. /**
  6388. * List of correspondence of used classes to their names
  6389. *
  6390. * Список соответствия используемых классов их названиям
  6391. */
  6392. ObjectsList = [
  6393. { name: 'BattlePresets', prop: 'game.battle.controller.thread.BattlePresets' },
  6394. { name: 'DataStorage', prop: 'game.data.storage.DataStorage' },
  6395. { name: 'BattleConfigStorage', prop: 'game.data.storage.battle.BattleConfigStorage' },
  6396. { name: 'BattleInstantPlay', prop: 'game.battle.controller.instant.BattleInstantPlay' },
  6397. { name: 'MultiBattleInstantReplay', prop: 'game.battle.controller.instant.MultiBattleInstantReplay' },
  6398. { name: 'MultiBattleResult', prop: 'game.battle.controller.MultiBattleResult' },
  6399. { name: 'PlayerMissionData', prop: 'game.model.user.mission.PlayerMissionData' },
  6400. { name: 'PlayerMissionBattle', prop: 'game.model.user.mission.PlayerMissionBattle' },
  6401. { name: 'GameModel', prop: 'game.model.GameModel' },
  6402. { name: 'CommandManager', prop: 'game.command.CommandManager' },
  6403. { name: 'MissionCommandList', prop: 'game.command.rpc.mission.MissionCommandList' },
  6404. { name: 'RPCCommandBase', prop: 'game.command.rpc.RPCCommandBase' },
  6405. { name: 'PlayerTowerData', prop: 'game.model.user.tower.PlayerTowerData' },
  6406. { name: 'TowerCommandList', prop: 'game.command.tower.TowerCommandList' },
  6407. { name: 'PlayerHeroTeamResolver', prop: 'game.model.user.hero.PlayerHeroTeamResolver' },
  6408. { name: 'BattlePausePopup', prop: 'game.view.popup.battle.BattlePausePopup' },
  6409. { name: 'BattlePopup', prop: 'game.view.popup.battle.BattlePopup' },
  6410. { name: 'DisplayObjectContainer', prop: 'starling.display.DisplayObjectContainer' },
  6411. { name: 'GuiClipContainer', prop: 'engine.core.clipgui.GuiClipContainer' },
  6412. { name: 'BattlePausePopupClip', prop: 'game.view.popup.battle.BattlePausePopupClip' },
  6413. { name: 'ClipLabel', prop: 'game.view.gui.components.ClipLabel' },
  6414. { name: 'ClipLabelBase', prop: 'game.view.gui.components.ClipLabelBase' },
  6415. { name: 'Translate', prop: 'com.progrestar.common.lang.Translate' },
  6416. { name: 'ClipButtonLabeledCentered', prop: 'game.view.gui.components.ClipButtonLabeledCentered' },
  6417. { name: 'BattlePausePopupMediator', prop: 'game.mediator.gui.popup.battle.BattlePausePopupMediator' },
  6418. { name: 'SettingToggleButton', prop: 'game.mechanics.settings.popup.view.SettingToggleButton' },
  6419. { name: 'PlayerDungeonData', prop: 'game.mechanics.dungeon.model.PlayerDungeonData' },
  6420. { name: 'NextDayUpdatedManager', prop: 'game.model.user.NextDayUpdatedManager' },
  6421. { name: 'BattleController', prop: 'game.battle.controller.BattleController' },
  6422. { name: 'BattleSettingsModel', prop: 'game.battle.controller.BattleSettingsModel' },
  6423. { name: 'BooleanProperty', prop: 'engine.core.utils.property.BooleanProperty' },
  6424. { name: 'RuleStorage', prop: 'game.data.storage.rule.RuleStorage' },
  6425. { name: 'BattleConfig', prop: 'battle.BattleConfig' },
  6426. { name: 'BattleGuiMediator', prop: 'game.battle.gui.BattleGuiMediator' },
  6427. { name: 'BooleanPropertyWriteable', prop: 'engine.core.utils.property.BooleanPropertyWriteable' },
  6428. { name: 'BattleLogEncoder', prop: 'battle.log.BattleLogEncoder' },
  6429. { name: 'BattleLogReader', prop: 'battle.log.BattleLogReader' },
  6430. { name: 'PlayerSubscriptionInfoValueObject', prop: 'game.model.user.subscription.PlayerSubscriptionInfoValueObject' },
  6431. { name: 'AdventureMapCamera', prop: 'game.mechanics.adventure.popup.map.AdventureMapCamera' },
  6432. { name: 'SendReplayPopUp', prop: 'game.mediator.gui.popup.chat.sendreplay.SendReplayPopUp' }, //полное окно реплей на вг
  6433. ];
  6434.  
  6435. /**
  6436. * Contains the game classes needed to write and override game methods
  6437. *
  6438. * Содержит классы игры необходимые для написания и подмены методов игры
  6439. */
  6440. Game = {
  6441. /**
  6442. * Function 'e'
  6443. * Функция 'e'
  6444. */
  6445. bindFunc: function (a, b) {
  6446. if (null == b)
  6447. return null;
  6448. null == b.__id__ && (b.__id__ = bindId++);
  6449. var c;
  6450. null == a.hx__closures__ ? a.hx__closures__ = {} :
  6451. c = a.hx__closures__[b.__id__];
  6452. null == c && (c = b.bind(a), a.hx__closures__[b.__id__] = c);
  6453. return c
  6454. },
  6455. };
  6456.  
  6457. /**
  6458. * Connects to game objects via the object creation event
  6459. *
  6460. * Подключается к объектам игры через событие создания объекта
  6461. */
  6462. function connectGame() {
  6463. for (let obj of ObjectsList) {
  6464. /**
  6465. * https: //stackoverflow.com/questions/42611719/how-to-intercept-and-modify-a-specific-property-for-any-object
  6466. */
  6467. Object.defineProperty(Object.prototype, obj.prop, {
  6468. set: function (value) {
  6469. if (!selfGame) {
  6470. selfGame = this;
  6471. }
  6472. if (!Game[obj.name]) {
  6473. Game[obj.name] = value;
  6474. }
  6475. // console.log('set ' + obj.prop, this, value);
  6476. this[obj.prop + '_'] = value;
  6477. },
  6478. get: function () {
  6479. // console.log('get ' + obj.prop, this);
  6480. return this[obj.prop + '_'];
  6481. }
  6482. });
  6483. }
  6484. }
  6485.  
  6486. /**
  6487. * Game.BattlePresets
  6488. * @param {bool} a isReplay
  6489. * @param {bool} b autoToggleable
  6490. * @param {bool} c auto On Start
  6491. * @param {object} d config
  6492. * @param {bool} f showBothTeams
  6493. */
  6494. /**
  6495. * Returns the results of the battle to the callback function
  6496. * Возвращает в функцию callback результаты боя
  6497. * @param {*} battleData battle data данные боя
  6498. * @param {*} battleConfig combat configuration type options:
  6499. *
  6500. * тип конфигурации боя варианты:
  6501. *
  6502. * "get_invasion", "get_titanPvpManual", "get_titanPvp",
  6503. * "get_titanClanPvp","get_clanPvp","get_titan","get_boss",
  6504. * "get_tower","get_pve","get_pvpManual","get_pvp","get_core"
  6505. *
  6506. * You can specify the xYc function in the game.assets.storage.BattleAssetStorage class
  6507. *
  6508. * Можно уточнить в классе game.assets.storage.BattleAssetStorage функция xYc
  6509. * @param {*} callback функция в которую вернуться результаты боя
  6510. */
  6511. this.BattleCalc = function (battleData, battleConfig, callback) {
  6512. // battleConfig = battleConfig || getBattleType(battleData.type)
  6513. if (!Game.BattlePresets) throw Error('Use connectGame');
  6514. battlePresets = new Game.BattlePresets(battleData.progress, !1, !0, Game.DataStorage[getFn(Game.DataStorage, 24)][getF(Game.BattleConfigStorage, battleConfig)](), !1);
  6515. let battleInstantPlay;
  6516. if (battleData.progress?.length > 1) {
  6517. battleInstantPlay = new Game.MultiBattleInstantReplay(battleData, battlePresets);
  6518. } else {
  6519. battleInstantPlay = new Game.BattleInstantPlay(battleData, battlePresets);
  6520. }
  6521. battleInstantPlay[getProtoFn(Game.BattleInstantPlay, 9)].add((battleInstant) => {
  6522. const MBR_2 = getProtoFn(Game.MultiBattleResult, 2);
  6523. const battleResults = battleInstant[getF(Game.BattleInstantPlay, 'get_result')]();
  6524. const battleData = battleInstant[getF(Game.BattleInstantPlay, 'get_rawBattleInfo')]();
  6525. const battleLogs = [];
  6526. const timeLimit = battlePresets[getF(Game.BattlePresets, 'get_timeLimit')]();
  6527. let battleTime = 0;
  6528. let battleTimer = 0;
  6529. for (const battleResult of battleResults[MBR_2]) {
  6530. const battleLog = Game.BattleLogEncoder.read(new Game.BattleLogReader(battleResult));
  6531. battleLogs.push(battleLog);
  6532. const maxTime = Math.max(...battleLog.map((e) => (e.time < timeLimit && e.time !== 168.8 ? e.time : 0)));
  6533. battleTimer += getTimer(maxTime)
  6534. battleTime += maxTime;
  6535. }
  6536. callback({
  6537. battleLogs,
  6538. battleTime,
  6539. battleTimer,
  6540. battleData,
  6541. progress: battleResults[getF(Game.MultiBattleResult, 'get_progress')](),
  6542. result: battleResults[getF(Game.MultiBattleResult, 'get_result')](),
  6543. });
  6544. });
  6545. battleInstantPlay.start();
  6546. }
  6547.  
  6548. /**
  6549. * Returns a function with the specified name from the class
  6550. *
  6551. * Возвращает из класса функцию с указанным именем
  6552. * @param {Object} classF Class // класс
  6553. * @param {String} nameF function name // имя функции
  6554. * @param {String} pos name and alias order // порядок имени и псевдонима
  6555. * @returns
  6556. */
  6557. function getF(classF, nameF, pos) {
  6558. pos = pos || false;
  6559. let prop = Object.entries(classF.prototype.__properties__)
  6560. if (!pos) {
  6561. return prop.filter((e) => e[1] == nameF).pop()[0];
  6562. } else {
  6563. return prop.filter((e) => e[0] == nameF).pop()[1];
  6564. }
  6565. }
  6566.  
  6567. /**
  6568. * Returns a function with the specified name from the class
  6569. *
  6570. * Возвращает из класса функцию с указанным именем
  6571. * @param {Object} classF Class // класс
  6572. * @param {String} nameF function name // имя функции
  6573. * @returns
  6574. */
  6575. function getFnP(classF, nameF) {
  6576. let prop = Object.entries(classF.__properties__)
  6577. return prop.filter((e) => e[1] == nameF).pop()[0];
  6578. }
  6579.  
  6580. /**
  6581. * Returns the function name with the specified ordinal from the class
  6582. *
  6583. * Возвращает имя функции с указаным порядковым номером из класса
  6584. * @param {Object} classF Class // класс
  6585. * @param {Number} nF Order number of function // порядковый номер функции
  6586. * @returns
  6587. */
  6588. function getFn(classF, nF) {
  6589. let prop = Object.keys(classF);
  6590. return prop[nF];
  6591. }
  6592.  
  6593. /**
  6594. * Returns the name of the function with the specified serial number from the prototype of the class
  6595. *
  6596. * Возвращает имя функции с указаным порядковым номером из прототипа класса
  6597. * @param {Object} classF Class // класс
  6598. * @param {Number} nF Order number of function // порядковый номер функции
  6599. * @returns
  6600. */
  6601. function getProtoFn(classF, nF) {
  6602. let prop = Object.keys(classF.prototype);
  6603. return prop[nF];
  6604. }
  6605. /**
  6606. * Description of replaced functions
  6607. *
  6608. * Описание подменяемых функций
  6609. */
  6610. replaceFunction = {
  6611. company: function () {
  6612. let PMD_12 = getProtoFn(Game.PlayerMissionData, 12);
  6613. let oldSkipMisson = Game.PlayerMissionData.prototype[PMD_12];
  6614. Game.PlayerMissionData.prototype[PMD_12] = function (a, b, c) {
  6615. if (!isChecked('passBattle')) {
  6616. oldSkipMisson.call(this, a, b, c);
  6617. return;
  6618. }
  6619.  
  6620. try {
  6621. this[getProtoFn(Game.PlayerMissionData, 9)] = new Game.PlayerMissionBattle(a, b, c);
  6622.  
  6623. var a = new Game.BattlePresets(
  6624. !1,
  6625. !1,
  6626. !0,
  6627. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  6628. !1
  6629. );
  6630. a = new Game.BattleInstantPlay(c, a);
  6631. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6632. a.start();
  6633. } catch (error) {
  6634. console.error('company', error);
  6635. oldSkipMisson.call(this, a, b, c);
  6636. }
  6637. };
  6638.  
  6639. Game.PlayerMissionData.prototype.P$h = function (a) {
  6640. let GM_2 = getFn(Game.GameModel, 2);
  6641. let GM_P2 = getProtoFn(Game.GameModel, 2);
  6642. let CM_20 = getProtoFn(Game.CommandManager, 20);
  6643. let MCL_2 = getProtoFn(Game.MissionCommandList, 2);
  6644. let MBR_15 = getF(Game.MultiBattleResult, 'get_result');
  6645. let RPCCB_15 = getProtoFn(Game.RPCCommandBase, 16);
  6646. let PMD_32 = getProtoFn(Game.PlayerMissionData, 32);
  6647. Game.GameModel[GM_2]()[GM_P2][CM_20][MCL_2](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PMD_32]));
  6648. };
  6649. },
  6650. /*
  6651. tower: function () {
  6652. let PTD_67 = getProtoFn(Game.PlayerTowerData, 67);
  6653. let oldSkipTower = Game.PlayerTowerData.prototype[PTD_67];
  6654. Game.PlayerTowerData.prototype[PTD_67] = function (a) {
  6655. if (!isChecked('passBattle')) {
  6656. oldSkipTower.call(this, a);
  6657. return;
  6658. }
  6659. try {
  6660. var p = new Game.BattlePresets(
  6661. !1,
  6662. !1,
  6663. !0,
  6664. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  6665. !1
  6666. );
  6667. a = new Game.BattleInstantPlay(a, p);
  6668. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6669. a.start();
  6670. } catch (error) {
  6671. console.error('tower', error);
  6672. oldSkipMisson.call(this, a, b, c);
  6673. }
  6674. };
  6675.  
  6676. Game.PlayerTowerData.prototype.P$h = function (a) {
  6677. const GM_2 = getFnP(Game.GameModel, 'get_instance');
  6678. const GM_P2 = getProtoFn(Game.GameModel, 2);
  6679. const CM_29 = getProtoFn(Game.CommandManager, 29);
  6680. const TCL_5 = getProtoFn(Game.TowerCommandList, 5);
  6681. const MBR_15 = getF(Game.MultiBattleResult, 'get_result');
  6682. const RPCCB_15 = getProtoFn(Game.RPCCommandBase, 17);
  6683. const PTD_78 = getProtoFn(Game.PlayerTowerData, 78);
  6684. Game.GameModel[GM_2]()[GM_P2][CM_29][TCL_5](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PTD_78]));
  6685. };
  6686. },
  6687. */
  6688. // skipSelectHero: function() {
  6689. // if (!HOST) throw Error('Use connectGame');
  6690. // Game.PlayerHeroTeamResolver.prototype[getProtoFn(Game.PlayerHeroTeamResolver, 3)] = () => false;
  6691. // },
  6692. // кнопка пропустить
  6693. passBattle: function () {
  6694. let BPP_4 = getProtoFn(Game.BattlePausePopup, 4);
  6695. let oldPassBattle = Game.BattlePausePopup.prototype[BPP_4];
  6696. Game.BattlePausePopup.prototype[BPP_4] = function (a) {
  6697. if (!isChecked('passBattle')) {
  6698. oldPassBattle.call(this, a);
  6699. return;
  6700. }
  6701. try {
  6702. Game.BattlePopup.prototype[getProtoFn(Game.BattlePausePopup, 4)].call(this, a);
  6703. this[getProtoFn(Game.BattlePausePopup, 3)]();
  6704. this[getProtoFn(Game.DisplayObjectContainer, 3)](this.clip[getProtoFn(Game.GuiClipContainer, 2)]());
  6705. this.clip[getProtoFn(Game.BattlePausePopupClip, 1)][getProtoFn(Game.ClipLabelBase, 9)](
  6706. Game.Translate.translate('UI_POPUP_BATTLE_PAUSE')
  6707. );
  6708. this.clip[getProtoFn(Game.BattlePausePopupClip, 2)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  6709. Game.Translate.translate('UI_POPUP_BATTLE_RETREAT'),
  6710. ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 17)]))
  6711. );
  6712. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  6713. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 14)](),
  6714. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 13)]()
  6715. ? ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  6716. : ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  6717. );
  6718. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 0)][
  6719. getProtoFn(Game.ClipLabelBase, 24)
  6720. ]();
  6721. this.clip[getProtoFn(Game.BattlePausePopupClip, 3)][getProtoFn(Game.SettingToggleButton, 3)](
  6722. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 9)]()
  6723. );
  6724. this.clip[getProtoFn(Game.BattlePausePopupClip, 4)][getProtoFn(Game.SettingToggleButton, 3)](
  6725. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 10)]()
  6726. );
  6727. this.clip[getProtoFn(Game.BattlePausePopupClip, 6)][getProtoFn(Game.SettingToggleButton, 3)](
  6728. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 11)]()
  6729. );
  6730. } catch (error) {
  6731. console.error('passBattle', error);
  6732. oldPassBattle.call(this, a);
  6733. }
  6734. };
  6735. let retreatButtonLabel = getF(Game.BattlePausePopupMediator, 'get_retreatButtonLabel');
  6736. let oldFunc = Game.BattlePausePopupMediator.prototype[retreatButtonLabel];
  6737. Game.BattlePausePopupMediator.prototype[retreatButtonLabel] = function () {
  6738. if (isChecked('passBattle')) {
  6739. return I18N('BTN_PASS');
  6740. } else {
  6741. return oldFunc.call(this);
  6742. }
  6743. };
  6744. },
  6745. endlessCards: function () {
  6746. let PDD_21 = getProtoFn(Game.PlayerDungeonData, 21);
  6747. let oldEndlessCards = Game.PlayerDungeonData.prototype[PDD_21];
  6748. Game.PlayerDungeonData.prototype[PDD_21] = function () {
  6749. if (countPredictionCard <= 0) {
  6750. return true;
  6751. } else {
  6752. return oldEndlessCards.call(this);
  6753. }
  6754. };
  6755. },
  6756. speedBattle: function () {
  6757. const get_timeScale = getF(Game.BattleController, 'get_timeScale');
  6758. const oldSpeedBattle = Game.BattleController.prototype[get_timeScale];
  6759. Game.BattleController.prototype[get_timeScale] = function () {
  6760. const speedBattle = Number.parseFloat(getInput('speedBattle'));
  6761. if (!speedBattle) {
  6762. return oldSpeedBattle.call(this);
  6763. }
  6764. try {
  6765. const BC_12 = getProtoFn(Game.BattleController, 12);
  6766. const BSM_12 = getProtoFn(Game.BattleSettingsModel, 12);
  6767. const BP_get_value = getF(Game.BooleanProperty, 'get_value');
  6768. if (this[BC_12][BSM_12][BP_get_value]()) {
  6769. return 0;
  6770. }
  6771. const BSM_2 = getProtoFn(Game.BattleSettingsModel, 2);
  6772. const BC_49 = getProtoFn(Game.BattleController, 49);
  6773. const BSM_1 = getProtoFn(Game.BattleSettingsModel, 1);
  6774. const BC_14 = getProtoFn(Game.BattleController, 14);
  6775. const BC_3 = getFn(Game.BattleController, 3);
  6776. if (this[BC_12][BSM_2][BP_get_value]()) {
  6777. var a = speedBattle * this[BC_49]();
  6778. } else {
  6779. a = this[BC_12][BSM_1][BP_get_value]();
  6780. const maxSpeed = Math.max(...this[BC_14]);
  6781. const multiple = a == this[BC_14].indexOf(maxSpeed) ? (maxSpeed >= 4 ? speedBattle : this[BC_14][a]) : this[BC_14][a];
  6782. a = multiple * Game.BattleController[BC_3][BP_get_value]() * this[BC_49]();
  6783. }
  6784. const BSM_24 = getProtoFn(Game.BattleSettingsModel, 24);
  6785. a > this[BC_12][BSM_24][BP_get_value]() && (a = this[BC_12][BSM_24][BP_get_value]());
  6786. const DS_23 = getFn(Game.DataStorage, 23);
  6787. const get_battleSpeedMultiplier = getF(Game.RuleStorage, 'get_battleSpeedMultiplier', true);
  6788. var b = Game.DataStorage[DS_23][get_battleSpeedMultiplier]();
  6789. const R_1 = getFn(selfGame.Reflect, 1);
  6790. const BC_1 = getFn(Game.BattleController, 1);
  6791. const get_config = getF(Game.BattlePresets, 'get_config');
  6792. null != b &&
  6793. (a = selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  6794. ? a * selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  6795. : a * selfGame.Reflect[R_1](b, 'default'));
  6796. return a;
  6797. } catch (error) {
  6798. console.error('passBatspeedBattletle', error);
  6799. return oldSpeedBattle.call(this);
  6800. }
  6801. };
  6802. },
  6803.  
  6804. /**
  6805. * Acceleration button without Valkyries favor
  6806. *
  6807. * Кнопка ускорения без Покровительства Валькирий
  6808. */
  6809. battleFastKey: function () {
  6810. const PSIVO_9 = getProtoFn(Game.PlayerSubscriptionInfoValueObject, 9);
  6811. const oldBattleFastKey = Game.PlayerSubscriptionInfoValueObject.prototype[PSIVO_9];
  6812. Game.PlayerSubscriptionInfoValueObject.prototype[PSIVO_9] = function () {
  6813. //const BGM_44 = getProtoFn(Game.BattleGuiMediator, 44);
  6814. //const oldBattleFastKey = Game.BattleGuiMediator.prototype[BGM_44];
  6815. //Game.BattleGuiMediator.prototype[BGM_44] = function () {
  6816. let flag = true;
  6817. //console.log(flag)
  6818. if (flag) {
  6819. return true;
  6820. } else {
  6821. return oldBattleFastKey.call(this);
  6822. }
  6823. };
  6824. },
  6825. fastSeason: function () {
  6826. const GameNavigator = selfGame['game.screen.navigator.GameNavigator'];
  6827. const oldFuncName = getProtoFn(GameNavigator, 18);
  6828. const newFuncName = getProtoFn(GameNavigator, 16);
  6829. const oldFastSeason = GameNavigator.prototype[oldFuncName];
  6830. const newFastSeason = GameNavigator.prototype[newFuncName];
  6831. GameNavigator.prototype[oldFuncName] = function (a, b) {
  6832. if (isChecked('fastSeason')) {
  6833. return newFastSeason.apply(this, [a]);
  6834. } else {
  6835. return oldFastSeason.apply(this, [a, b]);
  6836. }
  6837. };
  6838. },
  6839. ShowChestReward: function () {
  6840. const TitanArtifactChest = selfGame['game.mechanics.titan_arena.mediator.chest.TitanArtifactChestRewardPopupMediator'];
  6841. const getOpenAmountTitan = getF(TitanArtifactChest, 'get_openAmount');
  6842. const oldGetOpenAmountTitan = TitanArtifactChest.prototype[getOpenAmountTitan];
  6843. TitanArtifactChest.prototype[getOpenAmountTitan] = function () {
  6844. if (correctShowOpenArtifact) {
  6845. correctShowOpenArtifact--;
  6846. return 100;
  6847. }
  6848. return oldGetOpenAmountTitan.call(this);
  6849. };
  6850.  
  6851. const ArtifactChest = selfGame['game.view.popup.artifactchest.rewardpopup.ArtifactChestRewardPopupMediator'];
  6852. const getOpenAmount = getF(ArtifactChest, 'get_openAmount');
  6853. const oldGetOpenAmount = ArtifactChest.prototype[getOpenAmount];
  6854. ArtifactChest.prototype[getOpenAmount] = function () {
  6855. if (correctShowOpenArtifact) {
  6856. correctShowOpenArtifact--;
  6857. return 100;
  6858. }
  6859. return oldGetOpenAmount.call(this);
  6860. };
  6861.  
  6862. },
  6863. fixCompany: function () {
  6864. const GameBattleView = selfGame['game.mediator.gui.popup.battle.GameBattleView'];
  6865. const BattleThread = selfGame['game.battle.controller.thread.BattleThread'];
  6866. const getOnViewDisposed = getF(BattleThread, 'get_onViewDisposed');
  6867. const getThread = getF(GameBattleView, 'get_thread');
  6868. const oldFunc = GameBattleView.prototype[getThread];
  6869. GameBattleView.prototype[getThread] = function () {
  6870. return (
  6871. oldFunc.call(this) || {
  6872. [getOnViewDisposed]: async () => {},
  6873. }
  6874. );
  6875. };
  6876. },
  6877. BuyTitanArtifact: function () {
  6878. const BIP_4 = getProtoFn(selfGame['game.view.popup.shop.buy.BuyItemPopup'], 4);
  6879. const BuyItemPopup = selfGame['game.view.popup.shop.buy.BuyItemPopup'];
  6880. const oldFunc = BuyItemPopup.prototype[BIP_4];
  6881. BuyItemPopup.prototype[BIP_4] = function () {
  6882. if (isChecked('countControl')) {
  6883. const BuyTitanArtifactItemPopup = selfGame['game.view.popup.shop.buy.BuyTitanArtifactItemPopup'];
  6884. const BTAP_0 = getProtoFn(BuyTitanArtifactItemPopup, 0);
  6885. if (this[BTAP_0]) {
  6886. const BuyTitanArtifactPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyTitanArtifactItemPopupMediator'];
  6887. const BTAM_1 = getProtoFn(BuyTitanArtifactPopupMediator, 1);
  6888. const BuyItemPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyItemPopupMediator'];
  6889. const BIPM_5 = getProtoFn(BuyItemPopupMediator, 5);
  6890. const BIPM_7 = getProtoFn(BuyItemPopupMediator, 7);
  6891. const BIPM_9 = getProtoFn(BuyItemPopupMediator, 9);
  6892.  
  6893. let need = Math.min(this[BTAP_0][BTAM_1](), this[BTAP_0][BIPM_7]);
  6894. need = need ? need : 60;
  6895. this[BTAP_0][BIPM_9] = need;
  6896. this[BTAP_0][BIPM_5] = 10;
  6897. }
  6898. }
  6899. oldFunc.call(this);
  6900. };
  6901. },
  6902. ClanQuestsFastFarm: function () {
  6903. const VipRuleValueObject = selfGame['game.data.storage.rule.VipRuleValueObject'];
  6904. const getClanQuestsFastFarm = getF(VipRuleValueObject, 'get_clanQuestsFastFarm', 1);
  6905. VipRuleValueObject.prototype[getClanQuestsFastFarm] = function () {
  6906. return 0;
  6907. };
  6908. },
  6909. adventureCamera: function () {
  6910. const AMC_40 = getProtoFn(Game.AdventureMapCamera, 40);
  6911. const AMC_5 = getProtoFn(Game.AdventureMapCamera, 5);
  6912. const oldFunc = Game.AdventureMapCamera.prototype[AMC_40];
  6913. Game.AdventureMapCamera.prototype[AMC_40] = function (a) {
  6914. this[AMC_5] = 0.4;
  6915. oldFunc.bind(this)(a);
  6916. };
  6917. },
  6918. unlockMission: function () {
  6919. const WorldMapStoryDrommerHelper = selfGame['game.mediator.gui.worldmap.WorldMapStoryDrommerHelper'];
  6920. const WMSDH_4 = getFn(WorldMapStoryDrommerHelper, 4);
  6921. const WMSDH_7 = getFn(WorldMapStoryDrommerHelper, 7);
  6922. WorldMapStoryDrommerHelper[WMSDH_4] = function () {
  6923. return true;
  6924. };
  6925. WorldMapStoryDrommerHelper[WMSDH_7] = function () {
  6926. return true;
  6927. };
  6928. },
  6929. SendReplayPopUp: function() {
  6930. game_view_popup_ClipBasedPopup.prototype.SendReplayPopUp.call(this);
  6931. //if(this.mediator.get_canShareChat()) {
  6932. var clipFull = new game_mediator_gui_popup_chat_sendreplay_SendReplayPopUpClip();
  6933. game_assets_storage_AssetStorage.rsx.popup_theme.get_factory().create(clipFull,game_assets_storage_AssetStorage.rsx.popup_theme.data.getClipByName("send_replay_popup"));
  6934. this.addChild(clipFull.get_graphics());
  6935. clipFull.tf_title.set_text(com_progrestar_common_lang_Translate.translate("UI_DIALOG_CHAT_SEND_REPLAY_TEXT"));
  6936. clipFull.replay_info.tf_label.set_text(com_progrestar_common_lang_Translate.translate("UI_DIALOG_CHAT_REPLAY_TEXT"));
  6937. clipFull.action_btn.set_label(com_progrestar_common_lang_Translate.translate("UI_POPUP_CHAT_SEND"));
  6938. clipFull.tf_message_input.set_prompt(com_progrestar_common_lang_Translate.translate("UI_DIALOG_CHAT_INPUT_MESSAGE_PROMPT"));
  6939. clipFull.tf_message_input.set_text(this.mediator.get_defauiltText());
  6940. clipFull.action_btn.get_signal_click().add($bind(this,this.handler_sendClick));
  6941. clipFull.replay_info.btn_option.get_signal_click().add($bind(this,this.handler_replayClick));
  6942. this.clip = clipFull;
  6943. /*} else {
  6944. var clipShort = new game_mediator_gui_popup_chat_sendreplay_SendReplayPopUpClipShort();
  6945. game_assets_storage_AssetStorage.rsx.popup_theme.get_factory().create(clipShort,game_assets_storage_AssetStorage.rsx.popup_theme.data.getClipByName("send_replay_popup_short"));
  6946. this.addChild(clipShort.get_graphics());
  6947. this.clip = clipShort;
  6948. }*/
  6949. this.clip.button_close.get_signal_click().add(($_=this.mediator,$bind($_,$_.close)));
  6950. this.clip.tf_replay.set_text(com_progrestar_common_lang_Translate.translate("UI_DIALOG_ARENA_REPLAY_URL"));
  6951. this.clip.replay_url_input.set_text(this.mediator.get_replayURL());
  6952. this.clip.replay_url_input.addEventListener("change",$bind(this,this.handler_replayUrlInputChange));
  6953. this.clip.copy_btn.set_label(com_progrestar_common_lang_Translate.translate("UI_DIALOG_BUTTON_COPY"));
  6954. },
  6955. };
  6956.  
  6957. /**
  6958. * Starts replacing recorded functions
  6959. *
  6960. * Запускает замену записанных функций
  6961. */
  6962. this.activateHacks = function () {
  6963. if (!selfGame) throw Error('Use connectGame');
  6964. for (let func in replaceFunction) {
  6965. try {
  6966. replaceFunction[func]();
  6967. } catch (error) {
  6968. console.error(error);
  6969. }
  6970. }
  6971. }
  6972.  
  6973. /**
  6974. * Returns the game object
  6975. *
  6976. * Возвращает объект игры
  6977. */
  6978. this.getSelfGame = function () {
  6979. return selfGame;
  6980. }
  6981.  
  6982. /**
  6983. * Updates game data
  6984. *
  6985. * Обновляет данные игры
  6986. */
  6987. this.refreshGame = function () {
  6988. (new Game.NextDayUpdatedManager)[getProtoFn(Game.NextDayUpdatedManager, 5)]();
  6989. try {
  6990. cheats.refreshInventory();
  6991. } catch (e) { }
  6992. }
  6993.  
  6994. /**
  6995. * Update inventory
  6996. *
  6997. * Обновляет инвентарь
  6998. */
  6999. this.refreshInventory = async function () {
  7000. const GM_INST = getFnP(Game.GameModel, "get_instance");
  7001. const GM_0 = getProtoFn(Game.GameModel, 0);
  7002. const P_24 = getProtoFn(selfGame["game.model.user.Player"], 24);
  7003. const Player = Game.GameModel[GM_INST]()[GM_0];
  7004. Player[P_24] = new selfGame["game.model.user.inventory.PlayerInventory"]
  7005. Player[P_24].init(await Send({calls:[{name:"inventoryGet",args:{},ident:"body"}]}).then(e => e.results[0].result.response))
  7006. }
  7007. this.updateInventory = function (reward) {
  7008. const GM_INST = getFnP(Game.GameModel, 'get_instance');
  7009. const GM_0 = getProtoFn(Game.GameModel, 0);
  7010. const P_24 = getProtoFn(selfGame['game.model.user.Player'], 24);
  7011. const Player = Game.GameModel[GM_INST]()[GM_0];
  7012. Player[P_24].init(reward);
  7013. };
  7014. this.updateMap = function (data) {
  7015. const PCDD_21 = getProtoFn(selfGame['game.mechanics.clanDomination.model.PlayerClanDominationData'], 21);
  7016. const P_60 = getProtoFn(selfGame['game.model.user.Player'], 60);
  7017. const GM_0 = getProtoFn(Game.GameModel, 0);
  7018. const getInstance = getFnP(selfGame['Game'], 'get_instance');
  7019. const PlayerClanDominationData = Game.GameModel[getInstance]()[GM_0];
  7020. PlayerClanDominationData[P_60][PCDD_21].update(data);
  7021. };
  7022.  
  7023. /**
  7024. * Change the play screen on windowName
  7025. *
  7026. * Сменить экран игры на windowName
  7027. *
  7028. * Possible options:
  7029. *
  7030. * Возможные варианты:
  7031. *
  7032. * 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
  7033. */
  7034. this.goNavigtor = function (windowName) {
  7035. let mechanicStorage = selfGame["game.data.storage.mechanic.MechanicStorage"];
  7036. let window = mechanicStorage[windowName];
  7037. let event = new selfGame["game.mediator.gui.popup.PopupStashEventParams"];
  7038. let Game = selfGame['Game'];
  7039. let navigator = getF(Game, "get_navigator")
  7040. let navigate = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 20)
  7041. let instance = getFnP(Game, 'get_instance');
  7042. Game[instance]()[navigator]()[navigate](window, event);
  7043. }
  7044.  
  7045. /**
  7046. * Move to the sanctuary cheats.goSanctuary()
  7047. *
  7048. * Переместиться в святилище cheats.goSanctuary()
  7049. */
  7050. this.goSanctuary = () => {
  7051. this.goNavigtor("SANCTUARY");
  7052. }
  7053.  
  7054. /**
  7055. * Go to Guild War
  7056. *
  7057. * Перейти к Войне Гильдий
  7058. */
  7059. this.goClanWar = function() {
  7060. let instance = getFnP(Game.GameModel, 'get_instance')
  7061. let player = Game.GameModel[instance]().A;
  7062. let clanWarSelect = selfGame["game.mechanics.cross_clan_war.popup.selectMode.CrossClanWarSelectModeMediator"];
  7063. new clanWarSelect(player).open();
  7064. }
  7065.  
  7066. /**
  7067. * Go to BrawlShop
  7068. *
  7069. * Переместиться в BrawlShop
  7070. */
  7071. this.goBrawlShop = () => {
  7072. const instance = getFnP(Game.GameModel, 'get_instance')
  7073. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  7074. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  7075. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  7076. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  7077.  
  7078. const player = Game.GameModel[instance]().A;
  7079. const shop = player[P_36][PSD_0][IM_0][1038][PSDE_4];
  7080. const shopPopup = new selfGame["game.mechanics.brawl.mediator.BrawlShopPopupMediator"](player, shop)
  7081. shopPopup.open(new selfGame["game.mediator.gui.popup.PopupStashEventParams"])
  7082. }
  7083.  
  7084. /**
  7085. * Returns all stores from game data
  7086. *
  7087. * Возвращает все магазины из данных игры
  7088. */
  7089. this.getShops = () => {
  7090. const instance = getFnP(Game.GameModel, 'get_instance')
  7091. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  7092. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  7093. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  7094.  
  7095. const player = Game.GameModel[instance]().A;
  7096. return player[P_36][PSD_0][IM_0];
  7097. }
  7098.  
  7099. /**
  7100. * Returns the store from the game data by ID
  7101. *
  7102. * Возвращает магазин из данных игры по идетификатору
  7103. */
  7104. this.getShop = (id) => {
  7105. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  7106. const shops = this.getShops();
  7107. const shop = shops[id]?.[PSDE_4];
  7108. return shop;
  7109. }
  7110. /**
  7111. * Moves to the store with the specified ID
  7112. *
  7113. * Перемещает к магазину с указанным идетификатором
  7114. */
  7115. this.goShopId = function (id) {
  7116. const shop = this.getShop(id);
  7117. if (!shop) {
  7118. return;
  7119. }
  7120. let event = new selfGame["game.mediator.gui.popup.PopupStashEventParams"];
  7121. let Game = selfGame['Game'];
  7122. let navigator = getF(Game, "get_navigator");
  7123. let navigate = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 21);
  7124. let instance = getFnP(Game, 'get_instance');
  7125. Game[instance]()[navigator]()[navigate](shop, event);
  7126. }
  7127. /**
  7128. * Opens a list of non-standard stores
  7129. *
  7130. * Открывает список не стандартных магазинов
  7131. */
  7132. this.goCustomShops = async (p = 0) => {
  7133. /** Запрос данных нужных магазинов */
  7134. const calls = [{ name: "shopGetAll", args: {}, ident: "shopGetAll" }];
  7135. const shops = lib.getData('shop');
  7136. for (const id in shops) {
  7137. const check = !shops[id].ident.includes('merchantPromo') &&
  7138. ![1, 4, 5, 6, 7, 8, 9, 10, 11, 1023, 1024].includes(+id);
  7139. if (check) {
  7140. calls.push({
  7141. name: "shopGet", args: { shopId: id }, ident: `shopGet_${id}`
  7142. })
  7143. }
  7144. }
  7145. const result = await Send({ calls }).then(e => e.results.map(n => n.result.response));
  7146. const shopAll = result.shift();
  7147. const DS_32 = getFn(Game.DataStorage, 32)
  7148. const SDS_5 = getProtoFn(selfGame["game.data.storage.shop.ShopDescriptionStorage"], 5)
  7149. const SD_21 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 21);
  7150. const SD_1 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 1);
  7151. const SD_9 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 9);
  7152. const ident = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 11);
  7153. for (let shop of result) {
  7154. shopAll[shop.id] = shop;
  7155. // Снимаем все ограничения с магазинов
  7156. const shopLibData = Game.DataStorage[DS_32][SDS_5](shop.id)
  7157. shopLibData[SD_21] = 1;
  7158. shopLibData[SD_1] = new selfGame["game.model.user.requirement.Requirement"]
  7159. shopLibData[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  7160. teamLevel: 10
  7161. });
  7162. }
  7163. /** Скрываем все остальные магазины */
  7164. for (let id in shops) {
  7165. const shopLibData = Game.DataStorage[DS_32][SDS_5](id)
  7166. if (shopLibData[ident].includes('merchantPromo')) {
  7167. shopLibData[SD_21] = 0;
  7168. shopLibData[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  7169. teamLevel: 999
  7170. });
  7171. }
  7172. }
  7173. const instance = getFnP(Game.GameModel, 'get_instance')
  7174. const GM_0 = getProtoFn(Game.GameModel, 0);
  7175. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  7176. const player = Game.GameModel[instance]()[GM_0];
  7177. /** Пересоздаем объект с магазинами */
  7178. player[P_36] = new selfGame["game.model.user.shop.PlayerShopData"](player);
  7179. player[P_36].init(shopAll);
  7180. /** Даем магазинам новые названия */
  7181. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  7182. const shopName = getFn(cheats.getShop(1), 14);
  7183. const currentShops = this.getShops();
  7184. let count = 0;
  7185. const start = 9 * p + 1;
  7186. const end = start + 8;
  7187. for (let id in currentShops) {
  7188. const shop = currentShops[id][PSDE_4];
  7189. if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  7190. /** Скрываем стандартные магазины */
  7191. shop[SD_21] = 0;
  7192. } else {
  7193. count++;
  7194. if (count < start || count > end) {
  7195. shop[SD_21] = 0;
  7196. continue;
  7197. }
  7198. shop[SD_21] = 1;
  7199. shop[shopName] = cheats.translate("LIB_SHOP_NAME_" + id) + ' ' + id;
  7200. shop[SD_1] = new selfGame["game.model.user.requirement.Requirement"]
  7201. shop[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  7202. teamLevel: 10
  7203. });
  7204. }
  7205. }
  7206. console.log(count, start, end)
  7207. /** Отправляемся в городскую лавку */
  7208. this.goShopId(1);
  7209. }
  7210. /**
  7211. * Opens a list of standard stores
  7212. *
  7213. * Открывает список стандартных магазинов
  7214. */
  7215. this.goDefaultShops = async () => {
  7216. const result = await Send({ calls: [{ name: "shopGetAll", args: {}, ident: "shopGetAll" }] })
  7217. .then(e => e.results.map(n => n.result.response));
  7218. const shopAll = result.shift();
  7219. const shops = lib.getData('shop');
  7220. const DS_8 = getFn(Game.DataStorage, 8)
  7221. const DSB_4 = getProtoFn(selfGame["game.data.storage.DescriptionStorageBase"], 4)
  7222. /** Получаем объект валюты магазина для оторажения */
  7223. const coins = Game.DataStorage[DS_8][DSB_4](85);
  7224. coins.__proto__ = selfGame["game.data.storage.resource.ConsumableDescription"].prototype;
  7225. const DS_32 = getFn(Game.DataStorage, 32)
  7226. const SDS_5 = getProtoFn(selfGame["game.data.storage.shop.ShopDescriptionStorage"], 5)
  7227. const SD_21 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 21);
  7228. for (const id in shops) {
  7229. const shopLibData = Game.DataStorage[DS_32][SDS_5](id)
  7230. if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  7231. shopLibData[SD_21] = 1;
  7232. } else {
  7233. shopLibData[SD_21] = 0;
  7234. }
  7235. }
  7236. const instance = getFnP(Game.GameModel, 'get_instance')
  7237. const GM_0 = getProtoFn(Game.GameModel, 0);
  7238. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  7239. const player = Game.GameModel[instance]()[GM_0];
  7240. /** Пересоздаем объект с магазинами */
  7241. player[P_36] = new selfGame["game.model.user.shop.PlayerShopData"](player);
  7242. player[P_36].init(shopAll);
  7243. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  7244. const currentShops = this.getShops();
  7245. for (let id in currentShops) {
  7246. const shop = currentShops[id][PSDE_4];
  7247. if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  7248. shop[SD_21] = 1;
  7249. } else {
  7250. shop[SD_21] = 0;
  7251. }
  7252. }
  7253. this.goShopId(1);
  7254. }
  7255. /**
  7256. * Opens a list of Secret Wealth stores
  7257. *
  7258. * Открывает список магазинов Тайное богатство
  7259. */
  7260. this.goSecretWealthShops = async () => {
  7261. /** Запрос данных нужных магазинов */
  7262. const calls = [{ name: "shopGetAll", args: {}, ident: "shopGetAll" }];
  7263. const shops = lib.getData('shop');
  7264. for (const id in shops) {
  7265. if (shops[id].ident.includes('merchantPromo') && shops[id].teamLevelToUnlock <= 130) {
  7266. calls.push({
  7267. name: "shopGet", args: { shopId: id }, ident: `shopGet_${id}`
  7268. })
  7269. }
  7270. }
  7271. const result = await Send({ calls }).then(e => e.results.map(n => n.result.response));
  7272. const shopAll = result.shift();
  7273. const DS_32 = getFn(Game.DataStorage, 32)
  7274. const SDS_5 = getProtoFn(selfGame["game.data.storage.shop.ShopDescriptionStorage"], 5)
  7275. const SD_21 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 21);
  7276. const SD_1 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 1);
  7277. const SD_9 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 9);
  7278. const ident = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 11);
  7279. const specialCurrency = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 15);
  7280. const DS_8 = getFn(Game.DataStorage, 8)
  7281. const DSB_4 = getProtoFn(selfGame["game.data.storage.DescriptionStorageBase"], 4)
  7282. /** Получаем объект валюты магазина для оторажения */
  7283. const coins = Game.DataStorage[DS_8][DSB_4](85);
  7284. coins.__proto__ = selfGame["game.data.storage.resource.CoinDescription"].prototype;
  7285. for (let shop of result) {
  7286. shopAll[shop.id] = shop;
  7287. /** Снимаем все ограничения с магазинов */
  7288. const shopLibData = Game.DataStorage[DS_32][SDS_5](shop.id)
  7289. if (shopLibData[ident].includes('merchantPromo')) {
  7290. shopLibData[SD_21] = 1;
  7291. shopLibData[SD_1] = new selfGame["game.model.user.requirement.Requirement"]
  7292. shopLibData[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  7293. teamLevel: 10
  7294. });
  7295. }
  7296. }
  7297. /** Скрываем все остальные магазины */
  7298. for (let id in shops) {
  7299. const shopLibData = Game.DataStorage[DS_32][SDS_5](id)
  7300. if (!shopLibData[ident].includes('merchantPromo')) {
  7301. shopLibData[SD_21] = 0;
  7302. }
  7303. }
  7304. const instance = getFnP(Game.GameModel, 'get_instance')
  7305. const GM_0 = getProtoFn(Game.GameModel, 0);
  7306. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  7307. const player = Game.GameModel[instance]()[GM_0];
  7308. /** Пересоздаем объект с магазинами */
  7309. player[P_36] = new selfGame["game.model.user.shop.PlayerShopData"](player);
  7310. player[P_36].init(shopAll);
  7311. /** Даем магазинам новые названия */
  7312. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  7313. const shopName = getFn(cheats.getShop(1), 14);
  7314. const currentShops = this.getShops();
  7315. for (let id in currentShops) {
  7316. const shop = currentShops[id][PSDE_4];
  7317. if (shop[ident].includes('merchantPromo')) {
  7318. shop[SD_21] = 1;
  7319. shop[specialCurrency] = coins;
  7320. shop[shopName] = cheats.translate("LIB_SHOP_NAME_" + id) + ' ' + id;
  7321. } else if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  7322. /** Скрываем стандартные магазины */
  7323. shop[SD_21] = 0;
  7324. }
  7325. }
  7326. /** Отправляемся в городскую лавку */
  7327. this.goShopId(1);
  7328. }
  7329. /**
  7330. * Change island map
  7331. *
  7332. * Сменить карту острова
  7333. */
  7334. this.changeIslandMap = (mapId = 2) => {
  7335. const GameInst = getFnP(selfGame['Game'], 'get_instance');
  7336. const GM_0 = getProtoFn(Game.GameModel, 0);
  7337. const P_59 = getProtoFn(selfGame["game.model.user.Player"], 60);
  7338. const PSAD_31 = getProtoFn(selfGame['game.mechanics.season_adventure.model.PlayerSeasonAdventureData'], 31);
  7339. const Player = Game.GameModel[GameInst]()[GM_0];
  7340. Player[P_59][PSAD_31]({ id: mapId, seasonAdventure: { id: mapId, startDate: 1701914400, endDate: 1709690400, closed: false } });
  7341.  
  7342. const GN_15 = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 17)
  7343. const navigator = getF(selfGame['Game'], "get_navigator");
  7344. selfGame['Game'][GameInst]()[navigator]()[GN_15](new selfGame["game.mediator.gui.popup.PopupStashEventParams"]);
  7345. }
  7346.  
  7347. /**
  7348. * Game library availability tracker
  7349. *
  7350. * Отслеживание доступности игровой библиотеки
  7351. */
  7352. function checkLibLoad() {
  7353. timeout = setTimeout(() => {
  7354. if (Game.GameModel) {
  7355. changeLib();
  7356. } else {
  7357. checkLibLoad();
  7358. }
  7359. }, 100)
  7360. }
  7361.  
  7362. /**
  7363. * Game library data spoofing
  7364. *
  7365. * Подмена данных игровой библиотеки
  7366. */
  7367. function changeLib() {
  7368. console.log('lib connect');
  7369. const originalStartFunc = Game.GameModel.prototype.start;
  7370. Game.GameModel.prototype.start = function (a, b, c) {
  7371. self.libGame = b.raw;
  7372. try {
  7373. const levels = b.raw.seasonAdventure.level;
  7374. for (const id in levels) {
  7375. const level = levels[id];
  7376. level.clientData.graphics.fogged = level.clientData.graphics.visible
  7377. }
  7378. const adv = b.raw.seasonAdventure.list[1];
  7379. adv.clientData.asset = 'dialog_season_adventure_tiles';
  7380. } catch (e) {
  7381. console.warn(e);
  7382. }
  7383. originalStartFunc.call(this, a, b, c);
  7384. }
  7385. }
  7386.  
  7387. /**
  7388. * Returns the value of a language constant
  7389. *
  7390. * Возвращает значение языковой константы
  7391. * @param {*} langConst language constant // языковая константа
  7392. * @returns
  7393. */
  7394. this.translate = function (langConst) {
  7395. return Game.Translate.translate(langConst);
  7396. }
  7397.  
  7398. connectGame();
  7399. checkLibLoad();
  7400. }
  7401.  
  7402. /**
  7403. * Auto collection of gifts
  7404. *
  7405. * Автосбор подарков
  7406. */
  7407. function getAutoGifts() {
  7408. // c3ltYm9scyB0aGF0IG1lYW4gbm90aGluZw==
  7409. let valName = 'giftSendIds_' + userInfo.id;
  7410.  
  7411. if (!localStorage['clearGift' + userInfo.id]) {
  7412. localStorage[valName] = '';
  7413. localStorage['clearGift' + userInfo.id] = '+';
  7414. }
  7415.  
  7416. if (!localStorage[valName]) {
  7417. localStorage[valName] = '';
  7418. }
  7419.  
  7420. const giftsAPI = new ZingerYWebsiteAPI('getGifts.php', arguments);
  7421. /**
  7422. * Submit a request to receive gift codes
  7423. *
  7424. * Отправка запроса для получения кодов подарков
  7425. */
  7426. giftsAPI.request().then((data) => {
  7427. let freebieCheckCalls = {
  7428. calls: [],
  7429. };
  7430. data.forEach((giftId, n) => {
  7431. if (localStorage[valName].includes(giftId)) return;
  7432. freebieCheckCalls.calls.push({
  7433. name: 'registration',
  7434. args: {
  7435. user: { referrer: {} },
  7436. giftId,
  7437. },
  7438. context: {
  7439. actionTs: Math.floor(performance.now()),
  7440. cookie: window?.NXAppInfo?.session_id || null,
  7441. },
  7442. ident: giftId,
  7443. });
  7444. });
  7445. if (!freebieCheckCalls.calls.length) {
  7446. return;
  7447. }
  7448. send(JSON.stringify(freebieCheckCalls), (e) => {
  7449. let countGetGifts = 0;
  7450. const gifts = [];
  7451. for (check of e.results) {
  7452. gifts.push(check.ident);
  7453. if (check.result.response != null) {
  7454. countGetGifts++;
  7455. }
  7456. }
  7457. const saveGifts = localStorage[valName].split(';');
  7458. localStorage[valName] = [...saveGifts, ...gifts].slice(-50).join(';');
  7459. console.log(`${I18N('GIFTS')}: ${countGetGifts}`);
  7460. });
  7461. });
  7462. }
  7463.  
  7464. /**
  7465. * To fill the kills in the Forge of Souls
  7466. *
  7467. * Набить килов в горниле душ
  7468. */
  7469. async function bossRatingEvent() {
  7470. const topGet = await Send(JSON.stringify({ calls: [{ name: "topGet", args: { type: "bossRatingTop", extraId: 0 }, ident: "body" }] }));
  7471. if (!topGet || !topGet.results[0].result.response[0]) {
  7472. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7473. return;
  7474. }
  7475. const replayId = topGet.results[0].result.response[0].userData.replayId;
  7476. const result = await Send(JSON.stringify({
  7477. calls: [
  7478. { name: "battleGetReplay", args: { id: replayId }, ident: "battleGetReplay" },
  7479. { name: "heroGetAll", args: {}, ident: "heroGetAll" },
  7480. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  7481. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  7482. ]
  7483. }));
  7484. const bossEventInfo = result.results[3].result.response.find(e => e.offerType == "bossEvent");
  7485. if (!bossEventInfo) {
  7486. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7487. return;
  7488. }
  7489. const usedHeroes = bossEventInfo.progress.usedHeroes;
  7490. const party = Object.values(result.results[0].result.response.replay.attackers);
  7491. const availableHeroes = Object.values(result.results[1].result.response).map(e => e.id);
  7492. const availablePets = Object.values(result.results[2].result.response).map(e => e.id);
  7493. const calls = [];
  7494. /**
  7495. * First pack
  7496. *
  7497. * Первая пачка
  7498. */
  7499. const args = {
  7500. heroes: [],
  7501. favor: {}
  7502. }
  7503. for (let hero of party) {
  7504. if (hero.id >= 6000 && availablePets.includes(hero.id)) {
  7505. args.pet = hero.id;
  7506. continue;
  7507. }
  7508. if (!availableHeroes.includes(hero.id) || usedHeroes.includes(hero.id)) {
  7509. continue;
  7510. }
  7511. args.heroes.push(hero.id);
  7512. if (hero.favorPetId) {
  7513. args.favor[hero.id] = hero.favorPetId;
  7514. }
  7515. }
  7516. if (args.heroes.length) {
  7517. calls.push({
  7518. name: "bossRatingEvent_startBattle",
  7519. args,
  7520. ident: "body_0"
  7521. });
  7522. }
  7523. /**
  7524. * Other packs
  7525. *
  7526. * Другие пачки
  7527. */
  7528. let heroes = [];
  7529. let count = 1;
  7530. while (heroId = availableHeroes.pop()) {
  7531. if (args.heroes.includes(heroId) || usedHeroes.includes(heroId)) {
  7532. continue;
  7533. }
  7534. heroes.push(heroId);
  7535. if (heroes.length == 5) {
  7536. calls.push({
  7537. name: "bossRatingEvent_startBattle",
  7538. args: {
  7539. heroes: [...heroes],
  7540. pet: availablePets[Math.floor(Math.random() * availablePets.length)]
  7541. },
  7542. ident: "body_" + count
  7543. });
  7544. heroes = [];
  7545. count++;
  7546. }
  7547. }
  7548.  
  7549. if (!calls.length) {
  7550. setProgress(`${I18N('NO_HEROES')}`, true);
  7551. return;
  7552. }
  7553.  
  7554. const resultBattles = await Send(JSON.stringify({ calls }));
  7555. console.log(resultBattles);
  7556. rewardBossRatingEvent();
  7557. }
  7558.  
  7559. /**
  7560. * Collecting Rewards from the Forge of Souls
  7561. *
  7562. * Сбор награды из Горнила Душ
  7563. */
  7564. function rewardBossRatingEvent() {
  7565. let rewardBossRatingCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  7566. send(rewardBossRatingCall, function (data) {
  7567. let bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  7568. if (!bossEventInfo) {
  7569. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7570. return;
  7571. }
  7572.  
  7573. let farmedChests = bossEventInfo.progress.farmedChests;
  7574. let score = bossEventInfo.progress.score;
  7575. setProgress(`${I18N('DAMAGE_AMOUNT')}: ${score}`);
  7576. let revard = bossEventInfo.reward;
  7577.  
  7578. let getRewardCall = {
  7579. calls: []
  7580. }
  7581.  
  7582. let count = 0;
  7583. for (let i = 1; i < 10; i++) {
  7584. if (farmedChests.includes(i)) {
  7585. continue;
  7586. }
  7587. if (score < revard[i].score) {
  7588. break;
  7589. }
  7590. getRewardCall.calls.push({
  7591. name: "bossRatingEvent_getReward",
  7592. args: {
  7593. rewardId: i
  7594. },
  7595. ident: "body_" + i
  7596. });
  7597. count++;
  7598. }
  7599. if (!count) {
  7600. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  7601. return;
  7602. }
  7603.  
  7604. send(JSON.stringify(getRewardCall), e => {
  7605. console.log(e);
  7606. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  7607. });
  7608. });
  7609. }
  7610.  
  7611. /**
  7612. * Collect Easter eggs and event rewards
  7613. *
  7614. * Собрать пасхалки и награды событий
  7615. */
  7616. function offerFarmAllReward() {
  7617. const offerGetAllCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  7618. return Send(offerGetAllCall).then((data) => {
  7619. const offerGetAll = data.results[0].result.response.filter(e => e.type == "reward" && !e?.freeRewardObtained && e.reward);
  7620. if (!offerGetAll.length) {
  7621. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  7622. return;
  7623. }
  7624.  
  7625. const calls = [];
  7626. for (let reward of offerGetAll) {
  7627. calls.push({
  7628. name: "offerFarmReward",
  7629. args: {
  7630. offerId: reward.id
  7631. },
  7632. ident: "offerFarmReward_" + reward.id
  7633. });
  7634. }
  7635.  
  7636. return Send(JSON.stringify({ calls })).then(e => {
  7637. console.log(e);
  7638. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  7639. });
  7640. });
  7641. }
  7642.  
  7643. /**
  7644. * Assemble Outland
  7645. *
  7646. * Собрать запределье
  7647. */
  7648. function getOutland() {
  7649. return new Promise(function (resolve, reject) {
  7650. send('{"calls":[{"name":"bossGetAll","args":{},"ident":"bossGetAll"}]}', e => {
  7651. let bosses = e.results[0].result.response;
  7652.  
  7653. let bossRaidOpenChestCall = {
  7654. calls: []
  7655. };
  7656.  
  7657. for (let boss of bosses) {
  7658. if (boss.mayRaid) {
  7659. bossRaidOpenChestCall.calls.push({
  7660. name: "bossRaid",
  7661. args: {
  7662. bossId: boss.id
  7663. },
  7664. ident: "bossRaid_" + boss.id
  7665. });
  7666. bossRaidOpenChestCall.calls.push({
  7667. name: "bossOpenChest",
  7668. args: {
  7669. bossId: boss.id,
  7670. amount: 1,
  7671. starmoney: 0
  7672. },
  7673. ident: "bossOpenChest_" + boss.id
  7674. });
  7675. } else if (boss.chestId == 1) {
  7676. bossRaidOpenChestCall.calls.push({
  7677. name: "bossOpenChest",
  7678. args: {
  7679. bossId: boss.id,
  7680. amount: 1,
  7681. starmoney: 0
  7682. },
  7683. ident: "bossOpenChest_" + boss.id
  7684. });
  7685. }
  7686. }
  7687.  
  7688. if (!bossRaidOpenChestCall.calls.length) {
  7689. setProgress(`${I18N('OUTLAND')} ${I18N('NOTHING_TO_COLLECT')}`, true);
  7690. resolve();
  7691. return;
  7692. }
  7693.  
  7694. send(JSON.stringify(bossRaidOpenChestCall), e => {
  7695. setProgress(`${I18N('OUTLAND')} ${I18N('COLLECTED')}`, true);
  7696. resolve();
  7697. });
  7698. });
  7699. });
  7700. }
  7701.  
  7702. /**
  7703. * Collect all rewards
  7704. *
  7705. * Собрать все награды
  7706. */
  7707. function questAllFarm() {
  7708. return new Promise(function (resolve, reject) {
  7709. let questGetAllCall = {
  7710. calls: [{
  7711. name: "questGetAll",
  7712. args: {},
  7713. ident: "body"
  7714. }]
  7715. }
  7716. send(JSON.stringify(questGetAllCall), function (data) {
  7717. let questGetAll = data.results[0].result.response;
  7718. const questAllFarmCall = {
  7719. calls: []
  7720. }
  7721. let number = 0;
  7722. for (let quest of questGetAll) {
  7723. if (quest.id < 1e6 && quest.state == 2) {
  7724. questAllFarmCall.calls.push({
  7725. name: "questFarm",
  7726. args: {
  7727. questId: quest.id
  7728. },
  7729. ident: `group_${number}_body`
  7730. });
  7731. number++;
  7732. }
  7733. }
  7734.  
  7735. if (!questAllFarmCall.calls.length) {
  7736. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  7737. resolve();
  7738. return;
  7739. }
  7740.  
  7741. send(JSON.stringify(questAllFarmCall), function (res) {
  7742. console.log(res);
  7743. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  7744. resolve();
  7745. });
  7746. });
  7747. })
  7748. }
  7749.  
  7750. /**
  7751. * Mission auto repeat
  7752. *
  7753. * Автоповтор миссии
  7754. * isStopSendMission = false;
  7755. * isSendsMission = true;
  7756. **/
  7757. this.sendsMission = async function (param) {
  7758. if (isStopSendMission) {
  7759. isSendsMission = false;
  7760. console.log(I18N('STOPPED'));
  7761. setProgress('');
  7762. await popup.confirm(`${I18N('STOPPED')}<br>${I18N('REPETITIONS')}: ${param.count}`, [{
  7763. msg: 'Ok',
  7764. result: true
  7765. }, ])
  7766. return;
  7767. }
  7768. lastMissionBattleStart = Date.now();
  7769. let missionStartCall = {
  7770. "calls": [{
  7771. "name": "missionStart",
  7772. "args": lastMissionStart,
  7773. "ident": "body"
  7774. }]
  7775. }
  7776. /**
  7777. * Mission Request
  7778. *
  7779. * Запрос на выполнение мисcии
  7780. */
  7781. SendRequest(JSON.stringify(missionStartCall), async e => {
  7782. if (e['error']) {
  7783. isSendsMission = false;
  7784. console.log(e['error']);
  7785. setProgress('');
  7786. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  7787. await popup.confirm(msg, [
  7788. {msg: 'Ok', result: true},
  7789. ])
  7790. return;
  7791. }
  7792. /**
  7793. * Mission data calculation
  7794. *
  7795. * Расчет данных мисcии
  7796. */
  7797. BattleCalc(e.results[0].result.response, 'get_tower', async r => {
  7798. /** missionTimer */
  7799. let timer = getTimer(r.battleTime) + 5;
  7800. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  7801. if (period < timer) {
  7802. timer = timer - period;
  7803. await countdownTimer(timer, `${I18N('MISSIONS_PASSED')}: ${param.count}`);
  7804. }
  7805.  
  7806. let missionEndCall = {
  7807. "calls": [{
  7808. "name": "missionEnd",
  7809. "args": {
  7810. "id": param.id,
  7811. "result": r.result,
  7812. "progress": r.progress
  7813. },
  7814. "ident": "body"
  7815. }]
  7816. }
  7817. /**
  7818. * Mission Completion Request
  7819. *
  7820. * Запрос на завершение миссии
  7821. */
  7822. SendRequest(JSON.stringify(missionEndCall), async (e) => {
  7823. if (e['error']) {
  7824. isSendsMission = false;
  7825. console.log(e['error']);
  7826. setProgress('');
  7827. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  7828. await popup.confirm(msg, [
  7829. {msg: 'Ok', result: true},
  7830. ])
  7831. return;
  7832. }
  7833. r = e.results[0].result.response;
  7834. if (r['error']) {
  7835. isSendsMission = false;
  7836. console.log(r['error']);
  7837. setProgress('');
  7838. await popup.confirm(`<br>${I18N('REPETITIONS')}: ${param.count}` + ' 3 ' + r['error'], [
  7839. {msg: 'Ok', result: true},
  7840. ])
  7841. return;
  7842. }
  7843.  
  7844. param.count++;
  7845. let RaidMission = getInput('countRaid');
  7846.  
  7847. if (RaidMission==param.count){
  7848. isStopSendMission = true;
  7849. console.log(RaidMission);
  7850. }
  7851. setProgress(`${I18N('MISSIONS_PASSED')}: ${param.count} (${I18N('STOP')})`, false, () => {
  7852. isStopSendMission = true;
  7853. });
  7854. setTimeout(sendsMission, 1, param);
  7855. });
  7856. })
  7857. });
  7858. }
  7859.  
  7860. /**
  7861. * Opening of russian dolls
  7862. *
  7863. * Открытие матрешек
  7864. */
  7865. async function openRussianDolls(libId, amount) {
  7866. let sum = 0;
  7867. let sumResult = [];
  7868.  
  7869. while (amount) {
  7870. sum += amount;
  7871. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`);
  7872. const calls = [{
  7873. name: "consumableUseLootBox",
  7874. args: { libId, amount },
  7875. ident: "body"
  7876. }];
  7877. const result = await Send(JSON.stringify({ calls })).then(e => e.results[0].result.response);
  7878. let newCount = 0;
  7879. for (let n of result) {
  7880. if (n?.consumable && n.consumable[libId]) {
  7881. newCount += n.consumable[libId]
  7882. }
  7883. }
  7884. sumResult = [...sumResult, ...result];
  7885. amount = newCount;
  7886. }
  7887.  
  7888. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`, 5000);
  7889. return sumResult;
  7890. }
  7891.  
  7892. /**
  7893. * Collect all mail, except letters with energy and charges of the portal
  7894. *
  7895. * Собрать всю почту, кроме писем с энергией и зарядами портала
  7896. */
  7897. function mailGetAll() {
  7898. const getMailInfo = '{"calls":[{"name":"mailGetAll","args":{},"ident":"body"}]}';
  7899.  
  7900. return Send(getMailInfo).then(dataMail => {
  7901. const letters = dataMail.results[0].result.response.letters;
  7902. const letterIds = lettersFilter(letters);
  7903. if (!letterIds.length) {
  7904. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  7905. return;
  7906. }
  7907.  
  7908. const calls = [
  7909. { name: "mailFarm", args: { letterIds }, ident: "body" }
  7910. ];
  7911.  
  7912. return Send(JSON.stringify({ calls })).then(res => {
  7913. const lettersIds = res.results[0].result.response;
  7914. if (lettersIds) {
  7915. const countLetters = Object.keys(lettersIds).length;
  7916. setProgress(`${I18N('RECEIVED')} ${countLetters} ${I18N('LETTERS')}`, true);
  7917. }
  7918. });
  7919. });
  7920. }
  7921.  
  7922. /**
  7923. * Filters received emails
  7924. *
  7925. * Фильтрует получаемые письма
  7926. */
  7927. function lettersFilter(letters) {
  7928. const lettersIds = [];
  7929. for (let l in letters) {
  7930. letter = letters[l];
  7931. const reward = letter.reward;
  7932. if (!reward) {
  7933. continue;
  7934. }
  7935. /**
  7936. * Mail Collection Exceptions
  7937. *
  7938. * Исключения на сбор писем
  7939. */
  7940. const isFarmLetter = !(
  7941. /** Portals // сферы портала */
  7942. (reward?.refillable ? reward.refillable[45] : false) ||
  7943. /** Energy // энергия */
  7944. (reward?.stamina ? reward.stamina : false) ||
  7945. /** accelerating energy gain // ускорение набора энергии */
  7946. (reward?.buff ? true : false) ||
  7947. /** VIP Points // вип очки */
  7948. (reward?.vipPoints ? reward.vipPoints : false) ||
  7949. /** souls of heroes // душы героев */
  7950. (reward?.fragmentHero ? true : false) ||
  7951. /** heroes // герои */
  7952. (reward?.bundleHeroReward ? true : false)
  7953. );
  7954. if (isFarmLetter) {
  7955. lettersIds.push(~~letter.id);
  7956. continue;
  7957. }
  7958. /**
  7959. * Если до окончания годности письма менее 24 часов,
  7960. * то оно собирается не смотря на исключения
  7961. */
  7962. const availableUntil = +letter?.availableUntil;
  7963. if (availableUntil) {
  7964. const maxTimeLeft = 24 * 60 * 60 * 1000;
  7965. const timeLeft = (new Date(availableUntil * 1000) - new Date())
  7966. console.log('Time left:', timeLeft)
  7967. if (timeLeft < maxTimeLeft) {
  7968. lettersIds.push(~~letter.id);
  7969. continue;
  7970. }
  7971. }
  7972. }
  7973. return lettersIds;
  7974. }
  7975.  
  7976. /**
  7977. * Displaying information about the areas of the portal and attempts on the VG
  7978. *
  7979. * Отображение информации о сферах портала и попытках на ВГ
  7980. */
  7981. async function justInfo() {
  7982. return new Promise(async (resolve, reject) => {
  7983. const calls = [{
  7984. name: "userGetInfo",
  7985. args: {},
  7986. ident: "userGetInfo"
  7987. },
  7988. {
  7989. name: "clanWarGetInfo",
  7990. args: {},
  7991. ident: "clanWarGetInfo"
  7992. },
  7993. {
  7994. name: "titanArenaGetStatus",
  7995. args: {},
  7996. ident: "titanArenaGetStatus"
  7997. }];
  7998. const result = await Send(JSON.stringify({ calls }));
  7999. const infos = result.results;
  8000. const portalSphere = infos[0].result.response.refillable.find(n => n.id == 45);
  8001. const clanWarMyTries = infos[1].result.response?.myTries ?? 0;
  8002. const arePointsMax = infos[1].result.response?.arePointsMax;
  8003. const titansLevel = +(infos[2].result.response?.tier ?? 0);
  8004. const titansStatus = infos[2].result.response?.status; //peace_time || battle
  8005.  
  8006. const sanctuaryButton = buttons['goToSanctuary'].button;
  8007. const clanWarButton = buttons['goToClanWar'].button;
  8008. const titansArenaButton = buttons['testTitanArena'].button;
  8009.  
  8010. /*if (portalSphere.amount) {
  8011. sanctuaryButton.style.color = portalSphere.amount >= 3 ? 'red' : 'brown';
  8012. sanctuaryButton.title = `${I18N('SANCTUARY_TITLE')}\n${portalSphere.amount} ${I18N('PORTALS')}`;
  8013. } else {*/
  8014. sanctuaryButton.style.color = '';
  8015. sanctuaryButton.title = I18N('SANCTUARY_TITLE');
  8016. //}
  8017. /*if (clanWarMyTries && !arePointsMax) {
  8018. clanWarButton.style.color = 'red';
  8019. clanWarButton.title = `${I18N('GUILD_WAR_TITLE')}\n${clanWarMyTries}${I18N('ATTEMPTS')}`;
  8020. } else {*/
  8021. clanWarButton.style.color = '';
  8022. clanWarButton.title = I18N('GUILD_WAR_TITLE');
  8023. //}
  8024.  
  8025. /*if (titansLevel < 7 && titansStatus == 'battle') {
  8026. const partColor = Math.floor(125 * titansLevel / 7);
  8027. titansArenaButton.style.color = `rgb(255,${partColor},${partColor})`;
  8028. titansArenaButton.title = `${I18N('TITAN_ARENA_TITLE')}\n${titansLevel} ${I18N('LEVEL')}`;
  8029. } else {*/
  8030. titansArenaButton.style.color = '';
  8031. titansArenaButton.title = I18N('TITAN_ARENA_TITLE');
  8032. //}
  8033. //тест убрал подсветку красным в меню
  8034. const imgPortal =
  8035. 'data:image/gif;base64,R0lGODlhLwAvAHAAACH5BAEAAP8ALAAAAAAvAC8AhwAAABkQWgjF3krO3ghSjAhSzinF3u+tGWvO3s5rGSmE5gha7+/OWghSrWvmnClShCmUlAiE5u+MGe/W3mvvWmspUmvvGSnOWinOnCnOGWsZjErvnAiUlErvWmsIUkrvGQjOWgjOnAjOGUoZjM6MGe/OIWvv5q1KGSnv5mulGe/vWs7v3ozv3kqEGYxKGWuEWmtSKUrv3mNaCEpKUs7OWiml5ggxWmMpEAgZpRlaCO/35q1rGRkxKWtarSkZrRljKSkZhAjv3msIGRk6CEparQhjWq3v3kql3ozOGe/vnM6tGYytWu9rGWuEGYzO3kqE3gil5s6MWq3vnGvFnM7vWoxrGc5KGYyMWs6tWq2MGYzOnO+tWmvFWkqlWoxrWgAZhEqEWq2tWoytnIyt3krFnGul3mulWmulnEIpUkqlGUqlnK3OnK2MWs7OnClSrSmUte+tnGvFGYytGYzvWs5rWowpGa3O3u/OnErFWoyMnGuE3muEnEqEnIyMGYzOWs7OGe9r3u9rWq3vWq1rWq1r3invWimlWu+t3q0pWq2t3u8pWu8p3q0p3invnCnvGe/vGa2tGa3vGa2tnK0pGe9rnK1rnCmlGe8pGe8pnK0pnGsZrSkp3msp3s7vGYzvnM7vnIzvGc6tnM5r3oxr3gilWs6t3owpWs4pWs4p3owp3s5rnIxrnAilGc4pGc4pnIwpnAgp3kop3s7O3u9KGe+MWoxKWoyM3kIIUgiUte+MnErFGc5KWowIGe9K3u9KWq3OWq1KWq1K3gjvWimEWu+M3q0IWq2M3u8IWu8I3q0I3gjvnAjvGa3OGa2MnK0IGe9KnK1KnCmEGe8IGe8InK0InEoZrSkI3msI3s6MnM5K3oxK3giEWs6M3owIWs4IWs4I3owI3s5KnIxKnAiEGc4IGc4InIwInAgI3koI3kJaCAgQKUIpEGtKUkJSKUIIECla7ylazmtahGta70pa70pahGtazkpazmtrWiExUkprUiljWikQKRkQCAAQCAAACAAAAAj/AP8JHEiwoMGDCBMqXMiwocODJlBIRBHDxMOLBmMEkSjAgICPE2Mw/OUH4z8TGz+agBIBCsuWUAQE0WLwzkAkKZZcnAilhk+fA1bUiEC0ZZABJOD8IyHhwJYDkpakafJQ4kooR5yw0LFihQ4WJhAMKCoARRYSTJgkUOInBZK2DiX2rGHEiI67eFcYATtAAVEoKEiQSFBFDs4UKbg0lGgAigIEeCNzrWvCxIChEcoy3dGiSoITTRQvnCLRrxOveI2McbKahevKJmooiKkFy4Gzg5tMMaMwitwIj/PqGPCugL0CT47ANhEjQg3Atg9IT5CiS4uEUcRIBH4EtREETuB9/xn/BUcBBbBXGGgpoPaBEid23EuXgvdBJhtQGFCwwA7eMgs0gEMDBJD3hR7KbRVbSwP8UcIWJNwjIRLXGZRAAhLVsIACR9y1whMNfNGAHgiUcUSBX8ADWwwKzCYADTSUcMA9ebwQmkFYMMFGhgu80x1XTxSAwxNdGWGCAiG6YQBzly3QkhYxlsDGP1cg4YBBaC0h1zsLPGHXCkfA00AZeu11hALl1VBZXwW0RAaMDGDxTxNdTGEQExJoiUINXCpwmhFOKJCcVmCdOR56MezXJhRvwFlCC2lcWVAUEjBxRobw9HhEXUYekWBlsoVoQEWyFbAAFPRIQQMDJcDQhRhYSv+QZ1kGcAnPYya4BhZYlb1TQ4iI+tVmBPpIQQWrMORxkKwSsEFrDaa+8xgCy1mmgLSHxtDXAhtGMIOxDKjgAkLM7iAAYD4VJ+0RAyAgVl++ikfAESxy62QB365awrjLyprAcxEY4FOmXEp7LbctjlfAAE1yGwEBYBirAgP8GtTUARIMM1QBPrVYQAHF9dgiml/Mexl/3DbAwxnHMqBExQVdLAEMjRXQgHOyydaibPCgqEDH3JrawDosUDExCTATZJuMJ0AAxRNXtLFFPD+P/DB58AC9wH4N4BMxDRPvkPRAbLx3AAlVMLBFCXeQgIaIKJKHQ9X8+forAetMsaoKB7j/MAhCL5j9VFNPJYBGiCGW18CtsvWIs5j7gLEGqyV81gxC6ZBQQgkSMEUCLQckMMLHNhcAD3B+8TdyA0PPACWrB8SH0BItyHAAAwdE4YILTSUww8cELwAyt7D4JSberkd5wA4neIFQE020sMPmJZBwAi0SJMBOA6WTXgAsDYDPOj7r3KNFy5WfkEBCKbTQBQzTM+By5wm4YAPr+LM+IIE27LPOFWswmgqqZ4UEXCEhLUjBGWbgAs3JD2OfWcc68GEDArCOAASwAfnWUYUwtIEKSVCBCiSgPuclpAlImMI9YNDAzeFuMEwQ2w3W4Q530PAGLthBFNqwghCKMAoF3MEB/xNihvr8Ix4sdCCrJja47CVAMFjAwid6eJcQWi8BO4jHQl6AGFjdwwUnOMF75CfCMpoxCTpAoxoZMBgs3qMh7ZODQFYYxgSMsQThCpcK0BiZJNxBCZ7zwhsbYqO3wCoe7AjjCaxAggNUcY94mcDa3qMECWSBHYN0CBfj0IQliEFCMFjkIulAAisUkBZYyB4USxAFCZnkH1xsgltSYCMYyACMpizghS7kOTZIKJMmeYEZzCCH6iCmBS1IRzpkcEsXVMGZMMgHJvfwyoLsYQ9nmMIUuDAFPIAhH8pUZjLbcY89rKKaC9nDFeLxy3vkYwbJTMcL0InOeOSjBVShJz2pqQvPfvrznwANKEMCAgA7';
  8036.  
  8037. setProgress('<img src="' + imgPortal + '" style="height: 25px;position: relative;top: 5px;"> ' + `${portalSphere.amount} </br> ${I18N('GUILD_WAR')}: ${clanWarMyTries}`, true);
  8038. resolve();
  8039. });
  8040. }
  8041. // тест сделать все
  8042. /** Отправить подарки мое*/
  8043. function testclanSendDailyGifts() {
  8044.  
  8045. send('{"calls":[{"name":"clanSendDailyGifts","args":{},"ident":"clanSendDailyGifts"}]}', e => {
  8046. setProgress('Награды собраны', true);});
  8047. }
  8048. /** Открой сферу артефактов титанов*/
  8049. function testtitanArtifactChestOpen() {
  8050. send('{"calls":[{"name":"titanArtifactChestOpen","args":{"amount":1,"free":true},"ident":"body"}]}',
  8051. isWeCanDo => {
  8052. return info['inventoryGet']?.consumable[55] > 0
  8053. //setProgress('Награды собраны', true);
  8054. });
  8055. }
  8056. /** Воспользуйся призывом питомцев 1 раз*/
  8057. function testpet_chestOpen() {
  8058. send('{"calls":[{"name":"pet_chestOpen","args":{"amount":1,"paid":false},"ident":"pet_chestOpen"}]}',
  8059. isWeCanDo => {
  8060. return info['inventoryGet']?.consumable[90] > 0
  8061. //setProgress('Награды собраны', true);
  8062. });
  8063. }
  8064.  
  8065. async function getDailyBonus() {
  8066. const dailyBonusInfo = await Send(JSON.stringify({
  8067. calls: [{
  8068. name: "dailyBonusGetInfo",
  8069. args: {},
  8070. ident: "body"
  8071. }]
  8072. })).then(e => e.results[0].result.response);
  8073. const { availableToday, availableVip, currentDay } = dailyBonusInfo;
  8074.  
  8075. if (!availableToday) {
  8076. console.log('Уже собрано');
  8077. return;
  8078. }
  8079.  
  8080. const currentVipPoints = +userInfo.vipPoints;
  8081. const dailyBonusStat = lib.getData('dailyBonusStatic');
  8082. const vipInfo = lib.getData('level').vip;
  8083. let currentVipLevel = 0;
  8084. for (let i in vipInfo) {
  8085. vipLvl = vipInfo[i];
  8086. if (currentVipPoints >= vipLvl.vipPoints) {
  8087. currentVipLevel = vipLvl.level;
  8088. }
  8089. }
  8090. const vipLevelDouble = dailyBonusStat[`${currentDay}_0_0`].vipLevelDouble;
  8091.  
  8092. const calls = [{
  8093. name: "dailyBonusFarm",
  8094. args: {
  8095. vip: availableVip && currentVipLevel >= vipLevelDouble ? 1 : 0
  8096. },
  8097. ident: "body"
  8098. }];
  8099.  
  8100. const result = await Send(JSON.stringify({ calls }));
  8101. if (result.error) {
  8102. console.error(result.error);
  8103. return;
  8104. }
  8105.  
  8106. const reward = result.results[0].result.response;
  8107. const type = Object.keys(reward).pop();
  8108. const itemId = Object.keys(reward[type]).pop();
  8109. const count = reward[type][itemId];
  8110. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  8111.  
  8112. console.log(`Ежедневная награда: Получено ${count} ${itemName}`, reward);
  8113. }
  8114.  
  8115. async function farmStamina(lootBoxId = 148) {
  8116. const lootBox = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"}]}')
  8117. .then(e => e.results[0].result.response.consumable[148]);
  8118.  
  8119. /** Добавить другие ящики */
  8120. /**
  8121. * 144 - медная шкатулка
  8122. * 145 - бронзовая шкатулка
  8123. * 148 - платиновая шкатулка
  8124. */
  8125. if (!lootBox) {
  8126. setProgress(I18N('NO_BOXES'), true);
  8127. return;
  8128. }
  8129.  
  8130. let maxFarmEnergy = getSaveVal('maxFarmEnergy', 100);
  8131. const result = await popup.confirm(I18N('OPEN_LOOTBOX', { lootBox }), [
  8132. { result: false, isClose: true },
  8133. { msg: I18N('BTN_YES'), result: true },
  8134. { msg: I18N('STAMINA'), isInput: true, default: maxFarmEnergy },
  8135. ]);
  8136.  
  8137. if (!+result) {
  8138. return;
  8139. }
  8140.  
  8141. if ((typeof result) !== 'boolean' && Number.parseInt(result)) {
  8142. maxFarmEnergy = +result;
  8143. setSaveVal('maxFarmEnergy', maxFarmEnergy);
  8144. } else {
  8145. maxFarmEnergy = 0;
  8146. }
  8147.  
  8148. let collectEnergy = 0;
  8149. for (let count = lootBox; count > 0; count--) {
  8150. const result = await Send('{"calls":[{"name":"consumableUseLootBox","args":{"libId":148,"amount":1},"ident":"body"}]}')
  8151. .then(e => e.results[0].result.response[0]);
  8152. if ('stamina' in result) {
  8153. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox} ${I18N('STAMINA')} +${result.stamina}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  8154. console.log(`${ I18N('STAMINA') } + ${ result.stamina }`);
  8155. if (!maxFarmEnergy) {
  8156. return;
  8157. }
  8158. collectEnergy += +result.stamina;
  8159. if (collectEnergy >= maxFarmEnergy) {
  8160. console.log(`${I18N('STAMINA')} + ${ collectEnergy }`);
  8161. setProgress(`${I18N('STAMINA')} + ${ collectEnergy }`, false);
  8162. return;
  8163. }
  8164. } else {
  8165. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  8166. console.log(result);
  8167. }
  8168. }
  8169.  
  8170. setProgress(I18N('BOXES_OVER'), true);
  8171. }
  8172.  
  8173. async function fillActive() {
  8174. const data = await Send(JSON.stringify({
  8175. calls: [{
  8176. name: "questGetAll",
  8177. args: {},
  8178. ident: "questGetAll"
  8179. }, {
  8180. name: "inventoryGet",
  8181. args: {},
  8182. ident: "inventoryGet"
  8183. }, {
  8184. name: "clanGetInfo",
  8185. args: {},
  8186. ident: "clanGetInfo"
  8187. }
  8188. ]
  8189. })).then(e => e.results.map(n => n.result.response));
  8190.  
  8191. const quests = data[0];
  8192. const inv = data[1];
  8193. const stat = data[2].stat;
  8194. const maxActive = 2000 - stat.todayItemsActivity;
  8195. if (maxActive <= 0) {
  8196. setProgress(I18N('NO_MORE_ACTIVITY'), true);
  8197. return;
  8198. }
  8199.  
  8200. let countGetActive = 0;
  8201. const quest = quests.find(e => e.id > 10046 && e.id < 10051);
  8202. if (quest) {
  8203. countGetActive = 1750 - quest.progress;
  8204. }
  8205.  
  8206. if (countGetActive <= 0) {
  8207. countGetActive = maxActive;
  8208. }
  8209. console.log(countGetActive);
  8210.  
  8211. countGetActive = +(await popup.confirm(I18N('EXCHANGE_ITEMS', { maxActive }), [
  8212. { result: false, isClose: true },
  8213. { msg: I18N('GET_ACTIVITY'), isInput: true, default: countGetActive.toString() },
  8214. ]));
  8215.  
  8216. if (!countGetActive) {
  8217. return;
  8218. }
  8219.  
  8220. if (countGetActive > maxActive) {
  8221. countGetActive = maxActive;
  8222. }
  8223.  
  8224. const items = lib.getData('inventoryItem');
  8225.  
  8226. let itemsInfo = [];
  8227. for (let type of ['gear', 'scroll']) {
  8228. for (let i in inv[type]) {
  8229. const v = items[type][i]?.enchantValue || 0;
  8230. itemsInfo.push({
  8231. id: i,
  8232. count: inv[type][i],
  8233. v,
  8234. type
  8235. })
  8236. }
  8237. const invType = 'fragment' + type.toLowerCase().charAt(0).toUpperCase() + type.slice(1);
  8238. for (let i in inv[invType]) {
  8239. const v = items[type][i]?.fragmentEnchantValue || 0;
  8240. itemsInfo.push({
  8241. id: i,
  8242. count: inv[invType][i],
  8243. v,
  8244. type: invType
  8245. })
  8246. }
  8247. }
  8248. itemsInfo = itemsInfo.filter(e => e.v < 4 && e.count > 200);
  8249. itemsInfo = itemsInfo.sort((a, b) => b.count - a.count);
  8250. console.log(itemsInfo);
  8251. const activeItem = itemsInfo.shift();
  8252. console.log(activeItem);
  8253. const countItem = Math.ceil(countGetActive / activeItem.v);
  8254. if (countItem > activeItem.count) {
  8255. setProgress(I18N('NOT_ENOUGH_ITEMS'), true);
  8256. console.log(activeItem);
  8257. return;
  8258. }
  8259.  
  8260. await Send(JSON.stringify({
  8261. calls: [{
  8262. name: "clanItemsForActivity",
  8263. args: {
  8264. items: {
  8265. [activeItem.type]: {
  8266. [activeItem.id]: countItem
  8267. }
  8268. }
  8269. },
  8270. ident: "body"
  8271. }]
  8272. })).then(e => {
  8273. /** TODO: Вывести потраченые предметы */
  8274. console.log(e);
  8275. setProgress(`${I18N('ACTIVITY_RECEIVED')}: ` + e.results[0].result.response, true);
  8276. });
  8277. }
  8278.  
  8279. async function buyHeroFragments() {
  8280. const result = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"},{"name":"shopGetAll","args":{},"ident":"shopGetAll"}]}')
  8281. .then(e => e.results.map(n => n.result.response));
  8282. const inv = result[0];
  8283. const shops = Object.values(result[1]).filter(shop => [4, 5, 6, 8, 9, 10, 17].includes(shop.id));
  8284. const calls = [];
  8285.  
  8286. for (let shop of shops) {
  8287. const slots = Object.values(shop.slots);
  8288. for (const slot of slots) {
  8289. /* Уже куплено */
  8290. if (slot.bought) {
  8291. continue;
  8292. }
  8293. /* Не душа героя */
  8294. if (!('fragmentHero' in slot.reward)) {
  8295. continue;
  8296. }
  8297. const coin = Object.keys(slot.cost).pop();
  8298. const coinId = Object.keys(slot.cost[coin]).pop();
  8299. const stock = inv[coin][coinId] || 0;
  8300. /* Не хватает на покупку */
  8301. if (slot.cost[coin][coinId] > stock) {
  8302. continue;
  8303. }
  8304. inv[coin][coinId] -= slot.cost[coin][coinId];
  8305. calls.push({
  8306. name: "shopBuy",
  8307. args: {
  8308. shopId: shop.id,
  8309. slot: slot.id,
  8310. cost: slot.cost,
  8311. reward: slot.reward,
  8312. },
  8313. ident: `shopBuy_${shop.id}_${slot.id}`,
  8314. })
  8315. }
  8316. }
  8317.  
  8318. if (!calls.length) {
  8319. setProgress(I18N('NO_PURCHASABLE_HERO_SOULS'), true);
  8320. return;
  8321. }
  8322.  
  8323. const bought = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  8324. if (!bought) {
  8325. console.log('что-то пошло не так')
  8326. return;
  8327. }
  8328.  
  8329. let countHeroSouls = 0;
  8330. for (const buy of bought) {
  8331. countHeroSouls += +Object.values(Object.values(buy).pop()).pop();
  8332. }
  8333. console.log(countHeroSouls, bought, calls);
  8334. setProgress(I18N('PURCHASED_HERO_SOULS', { countHeroSouls }), true);
  8335. }
  8336.  
  8337. /** Открыть платные сундуки в Запределье за 90 */
  8338. async function bossOpenChestPay() {
  8339. const callsNames = ['userGetInfo', 'bossGetAll', 'specialOffer_getAll', 'getTime'];
  8340. const info = await Send({ calls: callsNames.map((name) => ({ name, args: {}, ident: name })) }).then((e) =>
  8341. e.results.map((n) => n.result.response)
  8342. );
  8343. const user = info[0];
  8344. const boses = info[1];
  8345. const offers = info[2];
  8346. const time = info[3];
  8347. const discountOffer = offers.find((e) => e.offerType == 'costReplaceOutlandChest');
  8348. let discount = 1;
  8349. if (discountOffer && discountOffer.endTime > time) {
  8350. discount = 1 - discountOffer.offerData.outlandChest.discountPercent / 100;
  8351. }
  8352. cost9chests = 540 * discount;
  8353. cost18chests = 1740 * discount;
  8354. costFirstChest = 90 * discount;
  8355. costSecondChest = 200 * discount;
  8356. const currentStarMoney = user.starMoney;
  8357. if (currentStarMoney < cost9chests) {
  8358. setProgress('Недостаточно изюма, нужно ' + cost9chests + ' у Вас ' + currentStarMoney, true);
  8359. return;
  8360. }
  8361. const imgEmerald =
  8362. "<img style='position: relative;top: 3px;' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAXCAYAAAD+4+QTAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAY8SURBVEhLpVV5bFVlFv/d7a19W3tfN1pKabGFAm3Rlg4toAWRiH+AioiaqAkaE42NycRR0ZnomJnJYHAJERGNyx/GJYoboo2igKVSMUUKreW1pRvUvr7XvvXe9+7qeW1nGJaJycwvObnny/fl/L7zO+c7l8EV0LAKzA+H83lAFAC/BeDJN2gnc5yd/WaQ8Q0NCCnAANkU+ZfjIpKqJWBOd4EDbHagueBPb1tWuesi9Rqn86zJZDbAMTp4xoSFzMaa4FVe6fra3bbzQbYN6A8Cmrz0qoBx8gzMmaj/QfKHWyxs+4e1DiC78M9v5TTn1RtbVH+kMWlJCCad100VOmQiUWFnNLg4HW42QeYEl3KnIiP5Bzu/dr27o0UistD48k2d8rF9Sib9GZKaejAnOmrs2/6e3VR3q7idF41GWVA41uQQ1RMY00ZJrChcrAYvx8HHaSjil8LLilCY98BORylBKlWQHhjzfvfFnuTfPn1O+xFolzM7s5nMI80rSl7qib8ykRNcWyaUosBWgnN6BL3pHuRwucjmnBTUCjfHwElkNiaNPHYr0mYCKnMeE/r3OC2NQiZZheHsfQ9Vu1uAM+eBIX2W5Nqsh/ewtxlrhl75NtUviDpwq+s+NOXWwWFhKKCd6iCQVByV2qSb0wEo5PvhY9YikGrH3uAdiBtBDIdVVAvlyfjBOffuesTcDxySqD3mUxaOPLZ6aktAOS/kqHaYigN7gnsxMGnDAuEuiPw6ymIt3MwaZFFQB7MeTmYjPLSWjTTCioQ5XCOMJIPeoInD/SNOviy6heLmALkckRTyf3xLbtQ8k6sdOodcxoocMoXU9JoFdF8VESMMiWRJmykyedqXTInaQJnOTtYDcJtZ+DXkRSrOou1cCoHx4LptL0nLgYU8kWhwlFgrNV2wFnEmVAr+w9gUzkwQic2DoNmLYe0QgkYXIuYg4uYYosYQJs1fMGkEpqWzUVucDh9E37gCIWFgvY9FcbniEipii6hbwZVilP0kXB/jysrrPLqU3yDG0JzXhA3OjWgsXo8UG6XbR6AxScqJjJHo/gmY0+9FIOn80I0UkukQFohJNFZmwV/uhosX2j59KPuF8JgS5CI3wHB90RUdKL12pMs7Z3VvfH6WyOajPt+Deb7FRDCBmNmNpNmPhHEWCW0IMXUQaTVEtVPhseYTZRCBeB86h8+hY0yDodsHfny+4NETB7JOLN74TXqmu1Yu4ixHuj3ii0/eaatx7RgY/NYKtR2tm+6B7lbwTGg3bDQ06MLTcsoJettR4DqaC8+u/gfe6HwZOzuGQU8JDR5f1B2+6uHWp8RPSjfsj5/dDyMzfIAj3bqSK8bGW579ECPWXRViHTijDK2BPojcPCxkbXCZflh1H5ISkCCSWJxI8jcjmErhnaHh6fdzdbZTd0aKd7Q+5T/gqj6VyBBkwmfG0QySkkHDJq19dDrgvP3GQq/Pt6h/8mesLqqFz+6DRq0qWkR4uGzEYhrGJBktNdvQGfoJH490YwmNuwKt+LWvWubtAk6GlPHhfw/LCyQz0BXEZOaoLcDf1lAt2z1z5nIhlIsL0Csfo90sWDkHXDYXaq2VWFZShffOfoQc0qOIzT9wbGvpXxOYGgG6SdwLuJSE6mPT1ZNdUdM9fyi8YlnTEiHLc423GBPaFBSVQcrQqcMYrJrbjElVRUf8FIq57K4z/8x7rL9f7ymsb0vHz83GmsXlJJSlsXKhxn3w+YSyrC48vKB0zVbLYqHCUYEe5SekaRYznBuLvU1olwbBmvr4r/v4RzteN4761x+Wxg9dGPH/wkzhL8WRHkMvKo7j/sc/Swfir7ZT/WTYSapc6LwFhc4qSKwLEYHXoz/bnzv8dOw7+4ojyYkvLyfI4MokhNToSKZwYf+6u3e39P3y8XH6AeY5yxHiBcx11OA8rZO9qTdaNx9/n9KPyUdnOulKuFyui6GHAAkHpEDBptqauaKtcMySRBW3HH2Do1+9WbP9GXocVGj5okJfit8jATY06Dh+MBIyiwZrrylb4XXneO1BV9df7n/tMb0/0J17O9LJU7Nn/x+UrKvOyOq58dXtNz0Q2Luz+cUnrqe1q+qmyv8q9/+EypuXZrK2kdEwgW3R5pW/r8I0gN8AVk6uP7Y929oAAAAASUVORK5CYII='>";
  8363. if (currentStarMoney < cost9chests) {
  8364. setProgress(I18N('NOT_ENOUGH_EMERALDS_540', { currentStarMoney, imgEmerald }), true);
  8365. return;
  8366. }
  8367. const buttons = [{ result: false, isClose: true }];
  8368. if (currentStarMoney >= cost9chests) {
  8369. buttons.push({
  8370. msg: I18N('BUY_OUTLAND_BTN', { count: 9, countEmerald: cost9chests, imgEmerald }),
  8371. result: [costFirstChest, costFirstChest, 0],
  8372. });
  8373. }
  8374. if (currentStarMoney >= cost18chests) {
  8375. buttons.push({
  8376. msg: I18N('BUY_OUTLAND_BTN', { count: 18, countEmerald: cost18chests, imgEmerald }),
  8377. result: [costFirstChest, costFirstChest, 0, costSecondChest, costSecondChest, 0],
  8378. });
  8379. }
  8380. const answer = await popup.confirm(`<div style="margin-bottom: 15px;">${I18N('BUY_OUTLAND')}</div>`, buttons);
  8381. if (!answer) {
  8382. return;
  8383. }
  8384. const callBoss = [];
  8385. let n = 0;
  8386. for (let boss of boses) {
  8387. const bossId = boss.id;
  8388. if (boss.chestNum != 2) {
  8389. continue;
  8390. }
  8391. const calls = [];
  8392. for (const starmoney of answer) {
  8393. calls.push({
  8394. name: 'bossOpenChest',
  8395. args: {
  8396. amount: 1,
  8397. bossId,
  8398. starmoney,
  8399. },
  8400. ident: 'bossOpenChest_' + ++n,
  8401. });
  8402. }
  8403. callBoss.push(calls);
  8404. }
  8405. if (!callBoss.length) {
  8406. setProgress(I18N('CHESTS_NOT_AVAILABLE'), true);
  8407. return;
  8408. }
  8409. let count = 0;
  8410. let errors = 0;
  8411. for (const calls of callBoss) {
  8412. const result = await Send({ calls });
  8413. console.log(result);
  8414. if (result?.results) {
  8415. count += result.results.length;
  8416. } else {
  8417. errors++;
  8418. }
  8419. }
  8420. setProgress(`${I18N('OUTLAND_CHESTS_RECEIVED')}: ${count}`, true);
  8421. }
  8422.  
  8423. async function autoRaidAdventure() {
  8424. const calls = [
  8425. {
  8426. name: "userGetInfo",
  8427. args: {},
  8428. ident: "userGetInfo"
  8429. },
  8430. {
  8431. name: "adventure_raidGetInfo",
  8432. args: {},
  8433. ident: "adventure_raidGetInfo"
  8434. }
  8435. ];
  8436. const result = await Send(JSON.stringify({ calls }))
  8437. .then(e => e.results.map(n => n.result.response));
  8438.  
  8439. const portalSphere = result[0].refillable.find(n => n.id == 45);
  8440. const adventureRaid = Object.entries(result[1].raid).filter(e => e[1]).pop()
  8441. const adventureId = adventureRaid ? adventureRaid[0] : 0;
  8442.  
  8443. if (!portalSphere.amount || !adventureId) {
  8444. setProgress(I18N('RAID_NOT_AVAILABLE'), true);
  8445. return;
  8446. }
  8447.  
  8448. const countRaid = +(await popup.confirm(I18N('RAID_ADVENTURE', { adventureId }), [
  8449. { result: false, isClose: true },
  8450. { msg: I18N('RAID'), isInput: true, default: portalSphere.amount },
  8451. ]));
  8452.  
  8453. if (!countRaid) {
  8454. return;
  8455. }
  8456.  
  8457. if (countRaid > portalSphere.amount) {
  8458. countRaid = portalSphere.amount;
  8459. }
  8460.  
  8461. const resultRaid = await Send(JSON.stringify({
  8462. calls: [...Array(countRaid)].map((e, i) => ({
  8463. name: "adventure_raid",
  8464. args: {
  8465. adventureId
  8466. },
  8467. ident: `body_${i}`
  8468. }))
  8469. })).then(e => e.results.map(n => n.result.response));
  8470.  
  8471. if (!resultRaid.length) {
  8472. console.log(resultRaid);
  8473. setProgress(I18N('SOMETHING_WENT_WRONG'), true);
  8474. return;
  8475. }
  8476.  
  8477. console.log(resultRaid, adventureId, portalSphere.amount);
  8478. setProgress(I18N('ADVENTURE_COMPLETED', { adventureId, times: resultRaid.length }), true);
  8479. }
  8480.  
  8481. /** Вывести всю клановую статистику в консоль браузера */
  8482. async function clanStatistic() {
  8483. const copy = function (text) {
  8484. const copyTextarea = document.createElement("textarea");
  8485. copyTextarea.style.opacity = "0";
  8486. copyTextarea.textContent = text;
  8487. document.body.appendChild(copyTextarea);
  8488. copyTextarea.select();
  8489. document.execCommand("copy");
  8490. document.body.removeChild(copyTextarea);
  8491. delete copyTextarea;
  8492. }
  8493. const calls = [
  8494. { name: "clanGetInfo", args: {}, ident: "clanGetInfo" },
  8495. { name: "clanGetWeeklyStat", args: {}, ident: "clanGetWeeklyStat" },
  8496. { name: "clanGetLog", args: {}, ident: "clanGetLog" },
  8497. ];
  8498.  
  8499. const result = await Send(JSON.stringify({ calls }));
  8500.  
  8501. const dataClanInfo = result.results[0].result.response;
  8502. const dataClanStat = result.results[1].result.response;
  8503. const dataClanLog = result.results[2].result.response;
  8504.  
  8505. const membersStat = {};
  8506. for (let i = 0; i < dataClanStat.stat.length; i++) {
  8507. membersStat[dataClanStat.stat[i].id] = dataClanStat.stat[i];
  8508. }
  8509.  
  8510. const joinStat = {};
  8511. historyLog = dataClanLog.history;
  8512. for (let j in historyLog) {
  8513. his = historyLog[j];
  8514. if (his.event == 'join') {
  8515. joinStat[his.userId] = his.ctime;
  8516. }
  8517. }
  8518.  
  8519. const infoArr = [];
  8520. const members = dataClanInfo.clan.members;
  8521. for (let n in members) {
  8522. var member = [
  8523. n,
  8524. members[n].name,
  8525. members[n].level,
  8526. dataClanInfo.clan.warriors.includes(+n) ? 1 : 0,
  8527. (new Date(members[n].lastLoginTime * 1000)).toLocaleString().replace(',', ''),
  8528. joinStat[n] ? (new Date(joinStat[n] * 1000)).toLocaleString().replace(',', '') : '',
  8529. membersStat[n].activity.reverse().join('\t'),
  8530. membersStat[n].adventureStat.reverse().join('\t'),
  8531. membersStat[n].clanGifts.reverse().join('\t'),
  8532. membersStat[n].clanWarStat.reverse().join('\t'),
  8533. membersStat[n].dungeonActivity.reverse().join('\t'),
  8534. ];
  8535. infoArr.push(member);
  8536. }
  8537. const info = infoArr.sort((a, b) => (b[2] - a[2])).map((e) => e.join('\t')).join('\n');
  8538. console.log(info);
  8539. copy(info);
  8540. setProgress(I18N('CLAN_STAT_COPY'), true);
  8541. }
  8542.  
  8543. async function buyInStoreForGold() {
  8544. const result = await Send('{"calls":[{"name":"shopGetAll","args":{},"ident":"body"},{"name":"userGetInfo","args":{},"ident":"userGetInfo"}]}').then(e => e.results.map(n => n.result.response));
  8545. const shops = result[0];
  8546. const user = result[1];
  8547. let gold = user.gold;
  8548. const calls = [];
  8549. if (shops[17]) {
  8550. const slots = shops[17].slots;
  8551. for (let i = 1; i <= 2; i++) {
  8552. if (!slots[i].bought) {
  8553. const costGold = slots[i].cost.gold;
  8554. if ((gold - costGold) < 0) {
  8555. continue;
  8556. }
  8557. gold -= costGold;
  8558. calls.push({
  8559. name: "shopBuy",
  8560. args: {
  8561. shopId: 17,
  8562. slot: i,
  8563. cost: slots[i].cost,
  8564. reward: slots[i].reward,
  8565. },
  8566. ident: 'body_' + i,
  8567. })
  8568. }
  8569. }
  8570. }
  8571. const slots = shops[1].slots;
  8572. for (let i = 4; i <= 6; i++) {
  8573. if (!slots[i].bought && slots[i]?.cost?.gold) {
  8574. const costGold = slots[i].cost.gold;
  8575. if ((gold - costGold) < 0) {
  8576. continue;
  8577. }
  8578. gold -= costGold;
  8579. calls.push({
  8580. name: "shopBuy",
  8581. args: {
  8582. shopId: 1,
  8583. slot: i,
  8584. cost: slots[i].cost,
  8585. reward: slots[i].reward,
  8586. },
  8587. ident: 'body_' + i,
  8588. })
  8589. }
  8590. }
  8591.  
  8592. if (!calls.length) {
  8593. setProgress(I18N('NOTHING_BUY'), true);
  8594. return;
  8595. }
  8596.  
  8597. const resultBuy = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  8598. console.log(resultBuy);
  8599. const countBuy = resultBuy.length;
  8600. setProgress(I18N('LOTS_BOUGHT', { countBuy }), true);
  8601. }
  8602.  
  8603. function rewardsAndMailFarm() {
  8604. return new Promise(function (resolve, reject) {
  8605. let questGetAllCall = {
  8606. calls: [{
  8607. name: "questGetAll",
  8608. args: {},
  8609. ident: "questGetAll"
  8610. }, {
  8611. name: "mailGetAll",
  8612. args: {},
  8613. ident: "mailGetAll"
  8614. }]
  8615. }
  8616. send(JSON.stringify(questGetAllCall), function (data) {
  8617. if (!data) return;
  8618. const questGetAll = data.results[0].result.response.filter((e) => e.state == 2);
  8619. const questBattlePass = lib.getData('quest').battlePass;
  8620. const questChainBPass = lib.getData('battlePass').questChain;
  8621. const listBattlePass = lib.getData('battlePass').list;
  8622.  
  8623. const questAllFarmCall = {
  8624. calls: [],
  8625. };
  8626. const questIds = [];
  8627. for (let quest of questGetAll) {
  8628. if (quest.id >= 2001e4) {
  8629. continue;
  8630. }
  8631. if (quest.id > 1e6 && quest.id < 2e7) {
  8632. const questInfo = questBattlePass[quest.id];
  8633. const chain = questChainBPass[questInfo.chain];
  8634. if (chain.requirement?.battlePassTicket) {
  8635. continue;
  8636. }
  8637. const battlePass = listBattlePass[chain.battlePass];
  8638. const startTime = battlePass.startCondition.time.value * 1e3
  8639. const endTime = new Date(startTime + battlePass.duration * 1e3);
  8640. if (startTime > Date.now() || endTime < Date.now()) {
  8641. continue;
  8642. }
  8643. }
  8644. if (quest.id >= 2e7) {
  8645. questIds.push(quest.id);
  8646. continue;
  8647. }
  8648. questAllFarmCall.calls.push({
  8649. name: 'questFarm',
  8650. args: {
  8651. questId: quest.id,
  8652. },
  8653. ident: `questFarm_${quest.id}`,
  8654. });
  8655. }
  8656.  
  8657. if (questIds.length) {
  8658. questAllFarmCall.calls.push({
  8659. name: 'quest_questsFarm',
  8660. args: { questIds },
  8661. ident: 'quest_questsFarm',
  8662. });
  8663. }
  8664.  
  8665. let letters = data?.results[1]?.result?.response?.letters;
  8666. letterIds = lettersFilter(letters);
  8667.  
  8668. if (letterIds.length) {
  8669. questAllFarmCall.calls.push({
  8670. name: 'mailFarm',
  8671. args: { letterIds },
  8672. ident: 'mailFarm',
  8673. });
  8674. }
  8675.  
  8676. if (!questAllFarmCall.calls.length) {
  8677. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  8678. resolve();
  8679. return;
  8680. }
  8681.  
  8682. send(JSON.stringify(questAllFarmCall), async function (res) {
  8683. let countQuests = 0;
  8684. let countMail = 0;
  8685. let questsIds = [];
  8686. for (let call of res.results) {
  8687. if (call.ident.includes('questFarm')) {
  8688. countQuests++;
  8689. } else if (call.ident.includes('questsFarm')) {
  8690. countQuests += Object.keys(call.result.response).length;
  8691. } else if (call.ident.includes('mailFarm')) {
  8692. countMail = Object.keys(call.result.response).length;
  8693. }
  8694.  
  8695. const newQuests = call.result.newQuests;
  8696. if (newQuests) {
  8697. for (let quest of newQuests) {
  8698. if ((quest.id < 1e6 || (quest.id >= 2e7 && quest.id < 2001e4)) && quest.state == 2) {
  8699. questsIds.push(quest.id);
  8700. }
  8701. }
  8702. }
  8703. }
  8704. while (questsIds.length) {
  8705. const questIds = [];
  8706. const calls = [];
  8707. for (let questId of questsIds) {
  8708. if (questId < 1e6) {
  8709. calls.push({
  8710. name: 'questFarm',
  8711. args: {
  8712. questId,
  8713. },
  8714. ident: `questFarm_${questId}`,
  8715. });
  8716. countQuests++;
  8717. } else if (questId >= 2e7 && questId < 2001e4) {
  8718. questIds.push(questId);
  8719. countQuests++;
  8720. }
  8721. }
  8722. calls.push({
  8723. name: 'quest_questsFarm',
  8724. args: { questIds },
  8725. ident: 'body',
  8726. });
  8727. const results = await Send({ calls }).then((e) => e.results.map((e) => e.result));
  8728. questsIds = [];
  8729. for (const result of results) {
  8730. const newQuests = result.newQuests;
  8731. if (newQuests) {
  8732. for (let quest of newQuests) {
  8733. if (quest.state == 2) {
  8734. questsIds.push(quest.id);
  8735. }
  8736. }
  8737. }
  8738. }
  8739. }
  8740. setProgress(I18N('COLLECT_REWARDS_AND_MAIL', { countQuests, countMail }), true);
  8741. resolve();
  8742. });
  8743. });
  8744. })
  8745. }
  8746.  
  8747. class epicBrawl {
  8748. timeout = null;
  8749. time = null;
  8750.  
  8751. constructor() {
  8752. if (epicBrawl.inst) {
  8753. return epicBrawl.inst;
  8754. }
  8755. epicBrawl.inst = this;
  8756. return this;
  8757. }
  8758.  
  8759. runTimeout(func, timeDiff) {
  8760. const worker = new Worker(URL.createObjectURL(new Blob([`
  8761. self.onmessage = function(e) {
  8762. const timeDiff = e.data;
  8763.  
  8764. if (timeDiff > 0) {
  8765. setTimeout(() => {
  8766. self.postMessage(1);
  8767. self.close();
  8768. }, timeDiff);
  8769. }
  8770. };
  8771. `])));
  8772. worker.postMessage(timeDiff);
  8773. worker.onmessage = () => {
  8774. func();
  8775. };
  8776. return true;
  8777. }
  8778.  
  8779. timeDiff(date1, date2) {
  8780. const date1Obj = new Date(date1);
  8781. const date2Obj = new Date(date2);
  8782.  
  8783. const timeDiff = Math.abs(date2Obj - date1Obj);
  8784.  
  8785. const totalSeconds = timeDiff / 1000;
  8786. const minutes = Math.floor(totalSeconds / 60);
  8787. const seconds = Math.floor(totalSeconds % 60);
  8788.  
  8789. const formattedMinutes = String(minutes).padStart(2, '0');
  8790. const formattedSeconds = String(seconds).padStart(2, '0');
  8791.  
  8792. return `${formattedMinutes}:${formattedSeconds}`;
  8793. }
  8794.  
  8795. check() {
  8796. console.log(new Date(this.time))
  8797. if (Date.now() > this.time) {
  8798. this.timeout = null;
  8799. this.start()
  8800. return;
  8801. }
  8802. this.timeout = this.runTimeout(() => this.check(), 6e4);
  8803. return this.timeDiff(this.time, Date.now())
  8804. }
  8805.  
  8806. async start() {
  8807. if (this.timeout) {
  8808. const time = this.timeDiff(this.time, Date.now());
  8809. console.log(new Date(this.time))
  8810. setProgress(I18N('TIMER_ALREADY', { time }), false, hideProgress);
  8811. return;
  8812. }
  8813. setProgress(I18N('EPIC_BRAWL'), false, hideProgress);
  8814. 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));
  8815. const refill = teamInfo[2].refillable.find(n => n.id == 52)
  8816. this.time = (refill.lastRefill + 3600) * 1000
  8817. const attempts = refill.amount;
  8818. if (!attempts) {
  8819. console.log(new Date(this.time));
  8820. const time = this.check();
  8821. setProgress(I18N('NO_ATTEMPTS_TIMER_START', { time }), false, hideProgress);
  8822. return;
  8823. }
  8824.  
  8825. if (!teamInfo[0].epic_brawl) {
  8826. setProgress(I18N('NO_HEROES_PACK'), false, hideProgress);
  8827. return;
  8828. }
  8829.  
  8830. const args = {
  8831. heroes: teamInfo[0].epic_brawl.filter(e => e < 1000),
  8832. pet: teamInfo[0].epic_brawl.filter(e => e > 6000).pop(),
  8833. favor: teamInfo[1].epic_brawl,
  8834. }
  8835.  
  8836. let wins = 0;
  8837. let coins = 0;
  8838. let streak = { progress: 0, nextStage: 0 };
  8839. for (let i = attempts; i > 0; i--) {
  8840. const info = await Send(JSON.stringify({
  8841. calls: [
  8842. { name: "epicBrawl_getEnemy", args: {}, ident: "epicBrawl_getEnemy" }, { name: "epicBrawl_startBattle", args, ident: "epicBrawl_startBattle" }
  8843. ]
  8844. })).then(e => e.results.map(n => n.result.response));
  8845.  
  8846. const { progress, result } = await Calc(info[1].battle);
  8847. 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));
  8848.  
  8849. const resultInfo = endResult[0].result;
  8850. streak = endResult[1];
  8851.  
  8852. wins += resultInfo.win;
  8853. coins += resultInfo.reward ? resultInfo.reward.coin[39] : 0;
  8854.  
  8855. console.log(endResult[0].result)
  8856. if (endResult[1].progress == endResult[1].nextStage) {
  8857. const farm = await Send('{"calls":[{"name":"epicBrawl_farmWinStreak","args":{},"ident":"body"}]}').then(e => e.results[0].result.response);
  8858. coins += farm.coin[39];
  8859. }
  8860.  
  8861. setProgress(I18N('EPIC_BRAWL_RESULT', {
  8862. i, wins, attempts, coins,
  8863. progress: streak.progress,
  8864. nextStage: streak.nextStage,
  8865. end: '',
  8866. }), false, hideProgress);
  8867. }
  8868.  
  8869. console.log(new Date(this.time));
  8870. const time = this.check();
  8871. setProgress(I18N('EPIC_BRAWL_RESULT', {
  8872. wins, attempts, coins,
  8873. i: '',
  8874. progress: streak.progress,
  8875. nextStage: streak.nextStage,
  8876. end: I18N('ATTEMPT_ENDED', { time }),
  8877. }), false, hideProgress);
  8878. }
  8879. }
  8880. /* тест остановка подземки*/
  8881. function stopDungeon(e) {
  8882. stopDung = true;
  8883. }
  8884.  
  8885. function countdownTimer(seconds, message) {
  8886. message = message || I18N('TIMER');
  8887. const stopTimer = Date.now() + seconds * 1e3
  8888. return new Promise(resolve => {
  8889. const interval = setInterval(async () => {
  8890. const now = Date.now();
  8891. setProgress(`${message} ${((stopTimer - now) / 1000).toFixed(2)}`, false);
  8892. if (now > stopTimer) {
  8893. clearInterval(interval);
  8894. setProgress('', 1);
  8895. resolve();
  8896. }
  8897. }, 100);
  8898. });
  8899. }
  8900.  
  8901. /** Набить килов в горниле душк */
  8902. async function bossRatingEventSouls() {
  8903. const data = await Send({
  8904. calls: [
  8905. { name: "heroGetAll", args: {}, ident: "teamGetAll" },
  8906. { name: "offerGetAll", args: {}, ident: "offerGetAll" },
  8907. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  8908. ]
  8909. });
  8910. const bossEventInfo = data.results[1].result.response.find(e => e.offerType == "bossEvent");
  8911. if (!bossEventInfo) {
  8912. setProgress('Эвент завершен', true);
  8913. return;
  8914. }
  8915.  
  8916. if (bossEventInfo.progress.score > 250) {
  8917. setProgress('Уже убито больше 250 врагов');
  8918. rewardBossRatingEventSouls();
  8919. return;
  8920. }
  8921. const availablePets = Object.values(data.results[2].result.response).map(e => e.id);
  8922. const heroGetAllList = data.results[0].result.response;
  8923. const usedHeroes = bossEventInfo.progress.usedHeroes;
  8924. const heroList = [];
  8925.  
  8926. for (let heroId in heroGetAllList) {
  8927. let hero = heroGetAllList[heroId];
  8928. if (usedHeroes.includes(hero.id)) {
  8929. continue;
  8930. }
  8931. heroList.push(hero.id);
  8932. }
  8933.  
  8934. if (!heroList.length) {
  8935. setProgress('Нет героев', true);
  8936. return;
  8937. }
  8938.  
  8939. const pet = availablePets.includes(6005) ? 6005 : availablePets[Math.floor(Math.random() * availablePets.length)];
  8940. const petLib = lib.getData('pet');
  8941. let count = 1;
  8942.  
  8943. for (const heroId of heroList) {
  8944. const args = {
  8945. heroes: [heroId],
  8946. pet
  8947. }
  8948. /** Поиск питомца для героя */
  8949. for (const petId of availablePets) {
  8950. if (petLib[petId].favorHeroes.includes(heroId)) {
  8951. args.favor = {
  8952. [heroId]: petId
  8953. }
  8954. break;
  8955. }
  8956. }
  8957.  
  8958. const calls = [{
  8959. name: "bossRatingEvent_startBattle",
  8960. args,
  8961. ident: "body"
  8962. }, {
  8963. name: "offerGetAll",
  8964. args: {},
  8965. ident: "offerGetAll"
  8966. }];
  8967.  
  8968. const res = await Send({ calls });
  8969. count++;
  8970.  
  8971. if ('error' in res) {
  8972. console.error(res.error);
  8973. setProgress('Перезагрузите игру и попробуйте позже', true);
  8974. return;
  8975. }
  8976.  
  8977. const eventInfo = res.results[1].result.response.find(e => e.offerType == "bossEvent");
  8978. if (eventInfo.progress.score > 250) {
  8979. break;
  8980. }
  8981. setProgress('Количество убитых врагов: ' + eventInfo.progress.score + '<br>Использовано ' + count + ' героев');
  8982. }
  8983.  
  8984. rewardBossRatingEventSouls();
  8985. }
  8986. /** Сбор награды из Горнила Душ */
  8987. async function rewardBossRatingEventSouls() {
  8988. const data = await Send({
  8989. calls: [
  8990. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  8991. ]
  8992. });
  8993.  
  8994. const bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  8995. if (!bossEventInfo) {
  8996. setProgress('Эвент завершен', true);
  8997. return;
  8998. }
  8999.  
  9000. const farmedChests = bossEventInfo.progress.farmedChests;
  9001. const score = bossEventInfo.progress.score;
  9002. // setProgress('Количество убитых врагов: ' + score);
  9003. const revard = bossEventInfo.reward;
  9004. const calls = [];
  9005.  
  9006. let count = 0;
  9007. for (let i = 1; i < 10; i++) {
  9008. if (farmedChests.includes(i)) {
  9009. continue;
  9010. }
  9011. if (score < revard[i].score) {
  9012. break;
  9013. }
  9014. calls.push({
  9015. name: "bossRatingEvent_getReward",
  9016. args: {
  9017. rewardId: i
  9018. },
  9019. ident: "body_" + i
  9020. });
  9021. count++;
  9022. }
  9023. if (!count) {
  9024. setProgress('Нечего собирать', true);
  9025. return;
  9026. }
  9027.  
  9028. Send({ calls }).then(e => {
  9029. console.log(e);
  9030. setProgress('Собрано ' + e?.results?.length + ' наград', true);
  9031. })
  9032. }
  9033. /**
  9034. * Spin the Seer
  9035. *
  9036. * Покрутить провидца
  9037. */
  9038. async function rollAscension() {
  9039. const refillable = await Send({calls:[
  9040. {
  9041. name:"userGetInfo",
  9042. args:{},
  9043. ident:"userGetInfo"
  9044. }
  9045. ]}).then(e => e.results[0].result.response.refillable);
  9046. const i47 = refillable.find(i => i.id == 47);
  9047. if (i47?.amount) {
  9048. await Send({ calls: [{ name: "ascensionChest_open", args: { paid: false, amount: 1 }, ident: "body" }] });
  9049. setProgress(I18N('DONE'), true);
  9050. } else {
  9051. setProgress(I18N('NOT_ENOUGH_AP'), true);
  9052. }
  9053. }
  9054.  
  9055. /**
  9056. * Collect gifts for the New Year
  9057. *
  9058. * Собрать подарки на новый год
  9059. */
  9060. function getGiftNewYear() {
  9061. Send({ calls: [{ name: "newYearGiftGet", args: { type: 0 }, ident: "body" }] }).then(e => {
  9062. const gifts = e.results[0].result.response.gifts;
  9063. const calls = gifts.filter(e => e.opened == 0).map(e => ({
  9064. name: "newYearGiftOpen",
  9065. args: {
  9066. giftId: e.id
  9067. },
  9068. ident: `body_${e.id}`
  9069. }));
  9070. if (!calls.length) {
  9071. setProgress(I18N('NY_NO_GIFTS'), 5000);
  9072. return;
  9073. }
  9074. Send({ calls }).then(e => {
  9075. console.log(e.results)
  9076. const msg = I18N('NY_GIFTS_COLLECTED', { count: e.results.length });
  9077. console.log(msg);
  9078. setProgress(msg, 5000);
  9079. });
  9080. })
  9081. }
  9082.  
  9083. async function updateArtifacts() {
  9084. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  9085. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  9086. { result: false, isClose: true }
  9087. ]);
  9088. if (!count) {
  9089. return;
  9090. }
  9091. const quest = new questRun;
  9092. await quest.autoInit();
  9093. const heroes = Object.values(quest.questInfo['heroGetAll']);
  9094. const inventory = quest.questInfo['inventoryGet'];
  9095. const calls = [];
  9096. for (let i = count; i > 0; i--) {
  9097. const upArtifact = quest.getUpgradeArtifact();
  9098. if (!upArtifact.heroId) {
  9099. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  9100. { msg: I18N('YES'), result: true },
  9101. { result: false, isClose: true }
  9102. ])) {
  9103. break;
  9104. } else {
  9105. return;
  9106. }
  9107. }
  9108. const hero = heroes.find(e => e.id == upArtifact.heroId);
  9109. hero.artifacts[upArtifact.slotId].level++;
  9110. inventory[upArtifact.costCurrency][upArtifact.costId] -= upArtifact.costValue;
  9111. calls.push({
  9112. name: "heroArtifactLevelUp",
  9113. args: {
  9114. heroId: upArtifact.heroId,
  9115. slotId: upArtifact.slotId
  9116. },
  9117. ident: `heroArtifactLevelUp_${i}`
  9118. });
  9119. }
  9120.  
  9121. if (!calls.length) {
  9122. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9123. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9124. return;
  9125. }
  9126.  
  9127. await Send(JSON.stringify({ calls })).then(e => {
  9128. if ('error' in e) {
  9129. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9130. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9131. } else {
  9132. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  9133. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  9134. }
  9135. });
  9136. }
  9137.  
  9138. window.sign = a => {
  9139. const i = this['\x78\x79\x7a'];
  9140. 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'))
  9141. }
  9142.  
  9143. async function updateSkins() {
  9144. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  9145. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  9146. { result: false, isClose: true }
  9147. ]);
  9148. if (!count) {
  9149. return;
  9150. }
  9151.  
  9152. const quest = new questRun;
  9153. await quest.autoInit();
  9154. const heroes = Object.values(quest.questInfo['heroGetAll']);
  9155. const inventory = quest.questInfo['inventoryGet'];
  9156. const calls = [];
  9157. for (let i = count; i > 0; i--) {
  9158. const upSkin = quest.getUpgradeSkin();
  9159. if (!upSkin.heroId) {
  9160. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  9161. { msg: I18N('YES'), result: true },
  9162. { result: false, isClose: true }
  9163. ])) {
  9164. break;
  9165. } else {
  9166. return;
  9167. }
  9168. }
  9169. const hero = heroes.find(e => e.id == upSkin.heroId);
  9170. hero.skins[upSkin.skinId]++;
  9171. inventory[upSkin.costCurrency][upSkin.costCurrencyId] -= upSkin.cost;
  9172. calls.push({
  9173. name: "heroSkinUpgrade",
  9174. args: {
  9175. heroId: upSkin.heroId,
  9176. skinId: upSkin.skinId
  9177. },
  9178. ident: `heroSkinUpgrade_${i}`
  9179. })
  9180. }
  9181.  
  9182. if (!calls.length) {
  9183. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9184. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9185. return;
  9186. }
  9187.  
  9188. await Send(JSON.stringify({ calls })).then(e => {
  9189. if ('error' in e) {
  9190. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9191. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9192. } else {
  9193. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  9194. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  9195. }
  9196. });
  9197. }
  9198.  
  9199. function getQuestionInfo(img, nameOnly = false) {
  9200. const libHeroes = Object.values(lib.data.hero);
  9201. const parts = img.split(':');
  9202. const id = parts[1];
  9203. switch (parts[0]) {
  9204. case 'titanArtifact_id':
  9205. return cheats.translate("LIB_TITAN_ARTIFACT_NAME_" + id);
  9206. case 'titan':
  9207. return cheats.translate("LIB_HERO_NAME_" + id);
  9208. case 'skill':
  9209. return cheats.translate("LIB_SKILL_" + id);
  9210. case 'inventoryItem_gear':
  9211. return cheats.translate("LIB_GEAR_NAME_" + id);
  9212. case 'inventoryItem_coin':
  9213. return cheats.translate("LIB_COIN_NAME_" + id);
  9214. case 'artifact':
  9215. if (nameOnly) {
  9216. return cheats.translate("LIB_ARTIFACT_NAME_" + id);
  9217. }
  9218. heroes = libHeroes.filter(h => h.id < 100 && h.artifacts.includes(+id));
  9219. return {
  9220. /** Как называется этот артефакт? */
  9221. name: cheats.translate("LIB_ARTIFACT_NAME_" + id),
  9222. /** Какому герою принадлежит этот артефакт? */
  9223. heroes: heroes.map(h => cheats.translate("LIB_HERO_NAME_" + h.id))
  9224. };
  9225. case 'hero':
  9226. if (nameOnly) {
  9227. return cheats.translate("LIB_HERO_NAME_" + id);
  9228. }
  9229. artifacts = lib.data.hero[id].artifacts;
  9230. return {
  9231. /** Как зовут этого героя? */
  9232. name: cheats.translate("LIB_HERO_NAME_" + id),
  9233. /** Какой артефакт принадлежит этому герою? */
  9234. artifact: artifacts.map(a => cheats.translate("LIB_ARTIFACT_NAME_" + a))
  9235. };
  9236. }
  9237. }
  9238.  
  9239. function hintQuest(quest) {
  9240. const result = {};
  9241. if (quest?.questionIcon) {
  9242. const info = getQuestionInfo(quest.questionIcon);
  9243. if (info?.heroes) {
  9244. /** Какому герою принадлежит этот артефакт? */
  9245. result.answer = quest.answers.filter(e => info.heroes.includes(e.answerText.slice(1)));
  9246. }
  9247. if (info?.artifact) {
  9248. /** Какой артефакт принадлежит этому герою? */
  9249. result.answer = quest.answers.filter(e => info.artifact.includes(e.answerText.slice(1)));
  9250. }
  9251. if (typeof info == 'string') {
  9252. result.info = { name: info };
  9253. } else {
  9254. result.info = info;
  9255. }
  9256. }
  9257.  
  9258. if (quest.answers[0]?.answerIcon) {
  9259. result.answer = quest.answers.filter(e => quest.question.includes(getQuestionInfo(e.answerIcon, true)))
  9260. }
  9261.  
  9262. if ((!result?.answer || !result.answer.length) && !result.info?.name) {
  9263. return false;
  9264. }
  9265.  
  9266. let resultText = '';
  9267. if (result?.info) {
  9268. resultText += I18N('PICTURE') + result.info.name;
  9269. }
  9270. console.log(result);
  9271. if (result?.answer && result.answer.length) {
  9272. resultText += I18N('ANSWER') + result.answer[0].id + (!result.answer[0].answerIcon ? ' - ' + result.answer[0].answerText : '');
  9273. }
  9274.  
  9275. return resultText;
  9276. }
  9277.  
  9278. async function farmBattlePass() {
  9279. const battlePasses = await Send({
  9280. calls: [
  9281. { name: 'battlePass_getInfo', args: {}, ident: 'getInfo' },
  9282. { name: 'battlePass_getSpecial', args: {}, ident: 'getSpecial' },
  9283. ],
  9284. }).then((e) => [e.results[0].result.response.battlePass, ...Object.values(e.results[1].result.response)]);
  9285. const calls = [];
  9286. let first = true;
  9287. for (const battlePass of battlePasses) {
  9288. const id = battlePass.id;
  9289. const bPassExp = battlePass.exp;
  9290. const bPassRewardsLvls = Object.keys(battlePass.rewards);
  9291. const bPassLevels = Object.values(lib.data.battlePass.level).filter((e) => e.battlePass === id);
  9292. for (let lvl of bPassLevels) {
  9293. if (bPassExp < lvl.experience) {
  9294. continue;
  9295. }
  9296. if (bPassRewardsLvls.includes(lvl.level.toString())) {
  9297. continue;
  9298. }
  9299. const reward = lvl.freeReward;
  9300. /** Исключения на сбор наград */
  9301. const isFarmReward = !(
  9302. (
  9303. (reward?.buff ? true : false) || // ускорение набора энергии
  9304. (reward?.fragmentHero ? true : false) || // душы героев
  9305. (reward?.bundleHeroReward ? true : false) // герои
  9306. )
  9307. );
  9308. if (isFarmReward) {
  9309. const args = {
  9310. level: lvl.level,
  9311. free: true,
  9312. };
  9313. if (!first) {
  9314. args.id = id;
  9315. }
  9316. calls.push({
  9317. name: 'battlePass_farmReward',
  9318. args,
  9319. ident: 'battlePass_farmReward_' + lvl.level + '_' + id,
  9320. });
  9321. }
  9322. }
  9323. first = false;
  9324. }
  9325. const results = await Send(JSON.stringify({ calls })).then((e) => e.results);
  9326. setProgress(I18N('SEASON_REWARD_COLLECTED', {count: results.length}), true);
  9327. }
  9328. async function sellHeroSoulsForGold() {
  9329. let { fragmentHero, heroes } = await Send({
  9330. calls: [
  9331. { name: 'inventoryGet', args: {}, ident: 'inventoryGet' },
  9332. { name: 'heroGetAll', args: {}, ident: 'heroGetAll' },
  9333. ],
  9334. })
  9335. .then((e) => e.results.map((r) => r.result.response))
  9336. .then((e) => ({ fragmentHero: e[0].fragmentHero, heroes: e[1] }));
  9337. const calls = [];
  9338. for (let i in fragmentHero) {
  9339. if (heroes[i] && heroes[i].star == 6) {
  9340. calls.push({
  9341. name: 'inventorySell',
  9342. args: {
  9343. type: 'hero',
  9344. libId: i,
  9345. amount: fragmentHero[i],
  9346. fragment: true,
  9347. },
  9348. ident: 'inventorySell_' + i,
  9349. });
  9350. }
  9351. }
  9352. if (!calls.length) {
  9353. console.log(0);
  9354. return 0;
  9355. }
  9356. const rewards = await Send({ calls }).then((e) => e.results.map((r) => r.result?.response?.gold || 0));
  9357. const gold = rewards.reduce((e, a) => e + a, 0);
  9358. setProgress(I18N('GOLD_RECEIVED', { gold }), true);
  9359. }
  9360.  
  9361. /**
  9362. * Attack of the minions of Asgard
  9363. *
  9364. * Атака прислужников Асгарда
  9365. */
  9366. function testRaidNodes() {
  9367. return new Promise((resolve, reject) => {
  9368. const tower = new executeRaidNodes(resolve, reject);
  9369. tower.start();
  9370. });
  9371. }
  9372.  
  9373. /**
  9374. * Attack of the minions of Asgard
  9375. *
  9376. * Атака прислужников Асгарда
  9377. */
  9378. function executeRaidNodes(resolve, reject) {
  9379. let raidData = {
  9380. teams: [],
  9381. favor: {},
  9382. nodes: [],
  9383. attempts: 0,
  9384. countExecuteBattles: 0,
  9385. cancelBattle: 0,
  9386. }
  9387.  
  9388. callsExecuteRaidNodes = {
  9389. calls: [{
  9390. name: "clanRaid_getInfo",
  9391. args: {},
  9392. ident: "clanRaid_getInfo"
  9393. }, {
  9394. name: "teamGetAll",
  9395. args: {},
  9396. ident: "teamGetAll"
  9397. }, {
  9398. name: "teamGetFavor",
  9399. args: {},
  9400. ident: "teamGetFavor"
  9401. }]
  9402. }
  9403.  
  9404. this.start = function () {
  9405. send(JSON.stringify(callsExecuteRaidNodes), startRaidNodes);
  9406. }
  9407.  
  9408. async function startRaidNodes(data) {
  9409. res = data.results;
  9410. clanRaidInfo = res[0].result.response;
  9411. teamGetAll = res[1].result.response;
  9412. teamGetFavor = res[2].result.response;
  9413.  
  9414. let index = 0;
  9415. let isNotFullPack = false;
  9416. for (let team of teamGetAll.clanRaid_nodes) {
  9417. if (team.length < 6) {
  9418. isNotFullPack = true;
  9419. }
  9420. raidData.teams.push({
  9421. data: {},
  9422. heroes: team.filter(id => id < 6000),
  9423. pet: team.filter(id => id >= 6000).pop(),
  9424. battleIndex: index++
  9425. });
  9426. }
  9427. raidData.favor = teamGetFavor.clanRaid_nodes;
  9428.  
  9429. if (isNotFullPack) {
  9430. if (await popup.confirm(I18N('MINIONS_WARNING'), [
  9431. { msg: I18N('BTN_NO'), result: true },
  9432. { msg: I18N('BTN_YES'), result: false },
  9433. ])) {
  9434. endRaidNodes('isNotFullPack');
  9435. return;
  9436. }
  9437. }
  9438.  
  9439. raidData.nodes = clanRaidInfo.nodes;
  9440. raidData.attempts = clanRaidInfo.attempts;
  9441. isCancalBattle = false;
  9442.  
  9443. checkNodes();
  9444. }
  9445.  
  9446. function getAttackNode() {
  9447. for (let nodeId in raidData.nodes) {
  9448. let node = raidData.nodes[nodeId];
  9449. let points = 0
  9450. for (team of node.teams) {
  9451. points += team.points;
  9452. }
  9453. let now = Date.now() / 1000;
  9454. if (!points && now > node.timestamps.start && now < node.timestamps.end) {
  9455. let countTeam = node.teams.length;
  9456. delete raidData.nodes[nodeId];
  9457. return {
  9458. nodeId,
  9459. countTeam
  9460. };
  9461. }
  9462. }
  9463. return null;
  9464. }
  9465.  
  9466. function checkNodes() {
  9467. setProgress(`${I18N('REMAINING_ATTEMPTS')}: ${raidData.attempts}`);
  9468. let nodeInfo = getAttackNode();
  9469. if (nodeInfo && raidData.attempts) {
  9470. startNodeBattles(nodeInfo);
  9471. return;
  9472. }
  9473.  
  9474. endRaidNodes('EndRaidNodes');
  9475. }
  9476.  
  9477. function startNodeBattles(nodeInfo) {
  9478. let {nodeId, countTeam} = nodeInfo;
  9479. let teams = raidData.teams.slice(0, countTeam);
  9480. let heroes = raidData.teams.map(e => e.heroes).flat();
  9481. let favor = {...raidData.favor};
  9482. for (let heroId in favor) {
  9483. if (!heroes.includes(+heroId)) {
  9484. delete favor[heroId];
  9485. }
  9486. }
  9487.  
  9488. let calls = [{
  9489. name: "clanRaid_startNodeBattles",
  9490. args: {
  9491. nodeId,
  9492. teams,
  9493. favor
  9494. },
  9495. ident: "body"
  9496. }];
  9497.  
  9498. send(JSON.stringify({calls}), resultNodeBattles);
  9499. }
  9500.  
  9501. function resultNodeBattles(e) {
  9502. if (e['error']) {
  9503. endRaidNodes('nodeBattlesError', e['error']);
  9504. return;
  9505. }
  9506.  
  9507. console.log(e);
  9508. let battles = e.results[0].result.response.battles;
  9509. let promises = [];
  9510. let battleIndex = 0;
  9511. for (let battle of battles) {
  9512. battle.battleIndex = battleIndex++;
  9513. promises.push(calcBattleResult(battle));
  9514. }
  9515.  
  9516. Promise.all(promises)
  9517. .then(results => {
  9518. const endResults = {};
  9519. let isAllWin = true;
  9520. for (let r of results) {
  9521. isAllWin &&= r.result.win;
  9522. }
  9523. if (!isAllWin) {
  9524. cancelEndNodeBattle(results[0]);
  9525. return;
  9526. }
  9527. raidData.countExecuteBattles = results.length;
  9528. let timeout = 500;
  9529. for (let r of results) {
  9530. setTimeout(endNodeBattle, timeout, r);
  9531. timeout += 500;
  9532. }
  9533. });
  9534. }
  9535. /**
  9536. * Returns the battle calculation promise
  9537. *
  9538. * Возвращает промис расчета боя
  9539. */
  9540. function calcBattleResult(battleData) {
  9541. return new Promise(function (resolve, reject) {
  9542. BattleCalc(battleData, "get_clanPvp", resolve);
  9543. });
  9544. }
  9545. /**
  9546. * Cancels the fight
  9547. *
  9548. * Отменяет бой
  9549. */
  9550. function cancelEndNodeBattle(r) {
  9551. const fixBattle = function (heroes) {
  9552. for (const ids in heroes) {
  9553. hero = heroes[ids];
  9554. hero.energy = random(1, 999);
  9555. if (hero.hp > 0) {
  9556. hero.hp = random(1, hero.hp);
  9557. }
  9558. }
  9559. }
  9560. fixBattle(r.progress[0].attackers.heroes);
  9561. fixBattle(r.progress[0].defenders.heroes);
  9562. endNodeBattle(r);
  9563. }
  9564. /**
  9565. * Ends the fight
  9566. *
  9567. * Завершает бой
  9568. */
  9569. function endNodeBattle(r) {
  9570. let nodeId = r.battleData.result.nodeId;
  9571. let battleIndex = r.battleData.battleIndex;
  9572. let calls = [{
  9573. name: "clanRaid_endNodeBattle",
  9574. args: {
  9575. nodeId,
  9576. battleIndex,
  9577. result: r.result,
  9578. progress: r.progress
  9579. },
  9580. ident: "body"
  9581. }]
  9582.  
  9583. SendRequest(JSON.stringify({calls}), battleResult);
  9584. }
  9585. /**
  9586. * Processing the results of the battle
  9587. *
  9588. * Обработка результатов боя
  9589. */
  9590. function battleResult(e) {
  9591. if (e['error']) {
  9592. endRaidNodes('missionEndError', e['error']);
  9593. return;
  9594. }
  9595. r = e.results[0].result.response;
  9596. if (r['error']) {
  9597. if (r.reason == "invalidBattle") {
  9598. raidData.cancelBattle++;
  9599. checkNodes();
  9600. } else {
  9601. endRaidNodes('missionEndError', e['error']);
  9602. }
  9603. return;
  9604. }
  9605.  
  9606. if (!(--raidData.countExecuteBattles)) {
  9607. raidData.attempts--;
  9608. checkNodes();
  9609. }
  9610. }
  9611. /**
  9612. * Completing a task
  9613. *
  9614. * Завершение задачи
  9615. */
  9616. function endRaidNodes(reason, info) {
  9617. isCancalBattle = true;
  9618. let textCancel = raidData.cancelBattle ? ` ${I18N('BATTLES_CANCELED')}: ${raidData.cancelBattle}` : '';
  9619. setProgress(`${I18N('MINION_RAID')} ${I18N('COMPLETED')}! ${textCancel}`, true);
  9620. console.log(reason, info);
  9621. resolve();
  9622. }
  9623. }
  9624.  
  9625. /**
  9626. * Asgard Boss Attack Replay
  9627. *
  9628. * Повтор атаки босса Асгарда
  9629. */
  9630. function testBossBattle() {
  9631. return new Promise((resolve, reject) => {
  9632. const bossBattle = new executeBossBattle(resolve, reject);
  9633. bossBattle.start(lastBossBattle);
  9634. });
  9635. }
  9636.  
  9637. /**
  9638. * Asgard Boss Attack Replay
  9639. *
  9640. * Повтор атаки босса Асгарда
  9641. */
  9642. function executeBossBattle(resolve, reject) {
  9643. this.start = function (battleInfo) {
  9644. preCalcBattle(battleInfo);
  9645. }
  9646.  
  9647. function getBattleInfo(battle) {
  9648. return new Promise(function (resolve) {
  9649. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  9650. BattleCalc(battle, getBattleType(battle.type), e => {
  9651. let extra = e.progress[0].defenders.heroes[1].extra;
  9652. resolve(extra.damageTaken + extra.damageTakenNextLevel);
  9653. });
  9654. });
  9655. }
  9656.  
  9657. function preCalcBattle(battle) {
  9658. let actions = [];
  9659. const countTestBattle = getInput('countTestBattle');
  9660. for (let i = 0; i < countTestBattle; i++) {
  9661. actions.push(getBattleInfo(battle, true));
  9662. }
  9663. Promise.all(actions)
  9664. .then(resultPreCalcBattle);
  9665. }
  9666.  
  9667. async function resultPreCalcBattle(damages) {
  9668. let maxDamage = 0;
  9669. let minDamage = 1e10;
  9670. let avgDamage = 0;
  9671. for (let damage of damages) {
  9672. avgDamage += damage
  9673. if (damage > maxDamage) {
  9674. maxDamage = damage;
  9675. }
  9676. if (damage < minDamage) {
  9677. minDamage = damage;
  9678. }
  9679. }
  9680. avgDamage /= damages.length;
  9681. console.log(damages.map(e => e.toLocaleString()).join('\n'), avgDamage, maxDamage);
  9682.  
  9683. await popup.confirm(
  9684. `${I18N('ROUND_STAT')} ${damages.length} ${I18N('BATTLE')}:` +
  9685. `<br>${I18N('MINIMUM')}: ` + minDamage.toLocaleString() +
  9686. `<br>${I18N('MAXIMUM')}: ` + maxDamage.toLocaleString() +
  9687. `<br>${I18N('AVERAGE')}: ` + avgDamage.toLocaleString()
  9688. , [
  9689. { msg: I18N('BTN_OK'), result: 0},
  9690. ])
  9691. endBossBattle(I18N('BTN_CANCEL'));
  9692. }
  9693.  
  9694. /**
  9695. * Completing a task
  9696. *
  9697. * Завершение задачи
  9698. */
  9699. function endBossBattle(reason, info) {
  9700. console.log(reason, info);
  9701. resolve();
  9702. }
  9703. }
  9704.  
  9705. /**
  9706. * Auto-repeat attack
  9707. *
  9708. * Автоповтор атаки
  9709. */
  9710. function testAutoBattle() {
  9711. return new Promise((resolve, reject) => {
  9712. const bossBattle = new executeAutoBattle(resolve, reject);
  9713. bossBattle.start(lastBattleArg, lastBattleInfo);
  9714. });
  9715. }
  9716.  
  9717. /**
  9718. * Auto-repeat attack
  9719. *
  9720. * Автоповтор атаки
  9721. */
  9722. function executeAutoBattle(resolve, reject) {
  9723. let battleArg = {};
  9724. let countBattle = 0;
  9725. let countError = 0;
  9726. let findCoeff = 0;
  9727. let dataNotEeceived = 0;
  9728. let stopAutoBattle = false;
  9729. 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>';
  9730. 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>';
  9731. 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>';
  9732.  
  9733. this.start = function (battleArgs, battleInfo) {
  9734. battleArg = battleArgs;
  9735. preCalcBattle(battleInfo);
  9736. }
  9737. /**
  9738. * Returns a promise for combat recalculation
  9739. *
  9740. * Возвращает промис для прерасчета боя
  9741. */
  9742. function getBattleInfo(battle) {
  9743. return new Promise(function (resolve) {
  9744. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  9745. Calc(battle).then(e => {
  9746. e.coeff = calcCoeff(e, 'defenders');
  9747. resolve(e);
  9748. });
  9749. });
  9750. }
  9751. /**
  9752. * Battle recalculation
  9753. *
  9754. * Прерасчет боя
  9755. */
  9756. function preCalcBattle(battle) {
  9757. let actions = [];
  9758. const countTestBattle = getInput('countTestBattle');
  9759. for (let i = 0; i < countTestBattle; i++) {
  9760. actions.push(getBattleInfo(battle));
  9761. }
  9762. Promise.all(actions)
  9763. .then(resultPreCalcBattle);
  9764. }
  9765. /**
  9766. * Processing the results of the battle recalculation
  9767. *
  9768. * Обработка результатов прерасчета боя
  9769. */
  9770. async function resultPreCalcBattle(results) {
  9771. let countWin = results.reduce((s, w) => w.result.win + s, 0);
  9772. setProgress(`${I18N('CHANCE_TO_WIN')} ${Math.floor(countWin / results.length * 100)}% (${results.length})`, false, hideProgress);
  9773. if (countWin > 0) {
  9774. isCancalBattle = false;
  9775. startBattle();
  9776. return;
  9777. }
  9778.  
  9779. let minCoeff = 100;
  9780. let maxCoeff = -100;
  9781. let avgCoeff = 0;
  9782. results.forEach(e => {
  9783. if (e.coeff < minCoeff) minCoeff = e.coeff;
  9784. if (e.coeff > maxCoeff) maxCoeff = e.coeff;
  9785. avgCoeff += e.coeff;
  9786. });
  9787. avgCoeff /= results.length;
  9788.  
  9789. if (nameFuncStartBattle == 'invasion_bossStart' ||
  9790. nameFuncStartBattle == 'bossAttack') {
  9791. const result = await popup.confirm(
  9792. I18N('BOSS_VICTORY_IMPOSSIBLE', { battles: results.length }), [
  9793. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  9794. { msg: I18N('BTN_DO_IT'), result: true },
  9795. ])
  9796. if (result) {
  9797. isCancalBattle = false;
  9798. startBattle();
  9799. return;
  9800. }
  9801. setProgress(I18N('NOT_THIS_TIME'), true);
  9802. endAutoBattle('invasion_bossStart');
  9803. return;
  9804. }
  9805.  
  9806. const result = await popup.confirm(
  9807. I18N('VICTORY_IMPOSSIBLE') +
  9808. `<br>${I18N('ROUND_STAT')} ${results.length} ${I18N('BATTLE')}:` +
  9809. `<br>${I18N('MINIMUM')}: ` + minCoeff.toLocaleString() +
  9810. `<br>${I18N('MAXIMUM')}: ` + maxCoeff.toLocaleString() +
  9811. `<br>${I18N('AVERAGE')}: ` + avgCoeff.toLocaleString() +
  9812. `<br>${I18N('FIND_COEFF')} ` + avgCoeff.toLocaleString(), [
  9813. { msg: I18N('BTN_CANCEL'), result: 0, isCancel: true },
  9814. { msg: I18N('BTN_GO'), isInput: true, default: Math.round(avgCoeff * 1000) / 1000 },
  9815. ])
  9816. if (result) {
  9817. findCoeff = result;
  9818. isCancalBattle = false;
  9819. startBattle();
  9820. return;
  9821. }
  9822. setProgress(I18N('NOT_THIS_TIME'), true);
  9823. endAutoBattle(I18N('NOT_THIS_TIME'));
  9824. }
  9825.  
  9826. /**
  9827. * Calculation of the combat result coefficient
  9828. *
  9829. * Расчет коэфициента результата боя
  9830. */
  9831. function calcCoeff(result, packType) {
  9832. let beforeSumFactor = 0;
  9833. const beforePack = result.battleData[packType][0];
  9834. for (let heroId in beforePack) {
  9835. const hero = beforePack[heroId];
  9836. const state = hero.state;
  9837. let factor = 1;
  9838. if (state) {
  9839. const hp = state.hp / state.maxHp;
  9840. const energy = state.energy / 1e3;
  9841. factor = hp + energy / 20;
  9842. }
  9843. beforeSumFactor += factor;
  9844. }
  9845.  
  9846. let afterSumFactor = 0;
  9847. const afterPack = result.progress[0][packType].heroes;
  9848. for (let heroId in afterPack) {
  9849. const hero = afterPack[heroId];
  9850. const stateHp = beforePack[heroId]?.state?.hp || beforePack[heroId]?.stats?.hp;
  9851. const hp = hero.hp / stateHp;
  9852. const energy = hero.energy / 1e3;
  9853. const factor = hp + energy / 20;
  9854. afterSumFactor += factor;
  9855. }
  9856. const resultCoeff = -(afterSumFactor - beforeSumFactor);
  9857. return Math.round(resultCoeff * 1000) / 1000;
  9858. }
  9859. /**
  9860. * Start battle
  9861. *
  9862. * Начало боя
  9863. */
  9864. function startBattle() {
  9865. countBattle++;
  9866. const countMaxBattle = getInput('countAutoBattle');
  9867. // setProgress(countBattle + '/' + countMaxBattle);
  9868. if (countBattle > countMaxBattle) {
  9869. setProgress(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`, true);
  9870. endAutoBattle(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`)
  9871. return;
  9872. }
  9873. if (stopAutoBattle) {
  9874. setProgress(I18N('STOPPED'), true);
  9875. endAutoBattle('STOPPED');
  9876. return;
  9877. }
  9878. send({calls: [{
  9879. name: nameFuncStartBattle,
  9880. args: battleArg,
  9881. ident: "body"
  9882. }]}, calcResultBattle);
  9883. }
  9884. /**
  9885. * Battle calculation
  9886. *
  9887. * Расчет боя
  9888. */
  9889. async function calcResultBattle(e) {
  9890. if ('error' in e) {
  9891. if (e.error.description === 'too many tries') {
  9892. invasionTimer += 100;
  9893. countBattle--;
  9894. countError++;
  9895. console.log(`Errors: ${countError}`, e.error);
  9896. startBattle();
  9897. return;
  9898. }
  9899. const result = await popup.confirm(I18N('ERROR_DURING_THE_BATTLE') + '<br>' + e.error.description, [
  9900. { msg: I18N('BTN_OK'), result: false },
  9901. { msg: I18N('RELOAD_GAME'), result: true },
  9902. ]);
  9903. endAutoBattle('Error', e.error);
  9904. if (result) {
  9905. location.reload();
  9906. }
  9907. return;
  9908. }
  9909. let battle = e.results[0].result.response.battle
  9910. if (nameFuncStartBattle == 'towerStartBattle' ||
  9911. nameFuncStartBattle == 'bossAttack' ||
  9912. nameFuncStartBattle == 'invasion_bossStart') {
  9913. battle = e.results[0].result.response;
  9914. }
  9915. lastBattleInfo = battle;
  9916. BattleCalc(battle, getBattleType(battle.type), resultBattle);
  9917. }
  9918. /**
  9919. * Processing the results of the battle
  9920. *
  9921. * Обработка результатов боя
  9922. */
  9923. async function resultBattle(e) {
  9924. const isWin = e.result.win;
  9925. if (isWin) {
  9926. endBattle(e, false);
  9927. return;
  9928. } else if (isChecked('tryFixIt')) {
  9929. const cloneBattle = structuredClone(e.battleData);
  9930. const bFix = new WinFixBattle(cloneBattle);
  9931. const endTime = Date.now() + 6e4;
  9932. const result = await bFix.start(endTime, Infinity);
  9933. console.log(result);
  9934. if (result.value) {
  9935. endBattle(result, false);
  9936. return;
  9937. }
  9938. }
  9939. const countMaxBattle = getInput('countAutoBattle');
  9940. if (findCoeff) {
  9941. const coeff = calcCoeff(e, 'defenders');
  9942. setProgress(`${countBattle}/${countMaxBattle}, ${coeff}`);
  9943. if (coeff > findCoeff) {
  9944. endBattle(e, false);
  9945. return;
  9946. }
  9947. } else {
  9948. if (nameFuncStartBattle == 'invasion_bossStart') {
  9949. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  9950. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageMod_any_99_100_300_99_1000 || 0;
  9951. setProgress(`${svgBoss} ${bossLvl} ${svgJustice} ${justice} <br>${svgAttempt} ${countBattle}/${countMaxBattle}`, false, () => {
  9952. stopAutoBattle = true;
  9953. });
  9954. await new Promise((resolve) => setTimeout(resolve, 5000));
  9955. } else {
  9956. setProgress(`${countBattle}/${countMaxBattle}`);
  9957. }
  9958. }
  9959. if (nameFuncStartBattle == 'towerStartBattle' ||
  9960. nameFuncStartBattle == 'bossAttack' ||
  9961. nameFuncStartBattle == 'invasion_bossStart') {
  9962. startBattle();
  9963. return;
  9964. }
  9965. cancelEndBattle(e);
  9966. }
  9967. /**
  9968. * Cancel fight
  9969. *
  9970. * Отмена боя
  9971. */
  9972. function cancelEndBattle(r) {
  9973. const fixBattle = function (heroes) {
  9974. for (const ids in heroes) {
  9975. hero = heroes[ids];
  9976. hero.energy = random(1, 999);
  9977. if (hero.hp > 0) {
  9978. hero.hp = random(1, hero.hp);
  9979. }
  9980. }
  9981. }
  9982. fixBattle(r.progress[0].attackers.heroes);
  9983. fixBattle(r.progress[0].defenders.heroes);
  9984. endBattle(r, true);
  9985. }
  9986. /**
  9987. * End of the fight
  9988. *
  9989. * Завершение боя */
  9990. function endBattle(battleResult, isCancal) {
  9991. let calls = [{
  9992. name: nameFuncEndBattle,
  9993. args: {
  9994. result: battleResult.result,
  9995. progress: battleResult.progress
  9996. },
  9997. ident: "body"
  9998. }];
  9999.  
  10000. if (nameFuncStartBattle == 'invasion_bossStart') {
  10001. calls[0].args.id = lastBattleArg.id;
  10002. }
  10003.  
  10004. send(JSON.stringify({
  10005. calls
  10006. }), async e => {
  10007. console.log(e);
  10008. if (isCancal) {
  10009. startBattle();
  10010. return;
  10011. }
  10012.  
  10013. setProgress(`${I18N('SUCCESS')}!`, 5000)
  10014. if (nameFuncStartBattle == 'invasion_bossStart' ||
  10015. nameFuncStartBattle == 'bossAttack') {
  10016. const countMaxBattle = getInput('countAutoBattle');
  10017. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  10018. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageMod_any_99_100_300_99_1000 || 0;
  10019. const result = await popup.confirm(
  10020. I18N('BOSS_HAS_BEEN_DEF_TEXT', {
  10021. bossLvl: `${svgBoss} ${bossLvl} ${svgJustice} ${justice}`,
  10022. countBattle: svgAttempt + ' ' + countBattle,
  10023. countMaxBattle,}),
  10024. [
  10025. { msg: I18N('BTN_OK'), result: 0 },
  10026. { msg: I18N('MAKE_A_SYNC'), result: 1 },
  10027. { msg: I18N('RELOAD_GAME'), result: 2 },
  10028. ]);
  10029. if (result) {
  10030. if (result == 1) {
  10031. cheats.refreshGame();
  10032. }
  10033. if (result == 2) {
  10034. location.reload();
  10035. }
  10036. }
  10037.  
  10038. }
  10039. endAutoBattle(`${I18N('SUCCESS')}!`)
  10040. });
  10041. }
  10042. /**
  10043. * Completing a task
  10044. *
  10045. * Завершение задачи
  10046. */
  10047. function endAutoBattle(reason, info) {
  10048. isCancalBattle = true;
  10049. console.log(reason, info);
  10050. resolve();
  10051. }
  10052. }
  10053.  
  10054. class FixBattle {
  10055. constructor(battle, isTimeout = true) {
  10056. this.battle = structuredClone(battle);
  10057. this.isTimeout = isTimeout;
  10058. }
  10059. timeout(callback, timeout) {
  10060. if (this.isTimeout) {
  10061. this.worker.postMessage(timeout);
  10062. this.worker.onmessage = callback;
  10063. } else {
  10064. callback();
  10065. }
  10066. }
  10067. randTimer() {
  10068. const min = 1.3;
  10069. const max = 10.3;
  10070. return Math.random() * (max - min + 1) + min;
  10071. }
  10072. setAvgTime(startTime) {
  10073. this.fixTime += Date.now() - startTime;
  10074. this.avgTime = this.fixTime / this.count;
  10075. }
  10076. init() {
  10077. this.fixTime = 0;
  10078. this.lastTimer = 0;
  10079. this.index = 0;
  10080. this.lastBossDamage = 0;
  10081. this.bestResult = {
  10082. count: 0,
  10083. timer: 0,
  10084. value: 0,
  10085. result: null,
  10086. progress: null,
  10087. };
  10088. this.lastBattleResult = {
  10089. win: false,
  10090. };
  10091. this.worker = new Worker(
  10092. URL.createObjectURL(
  10093. new Blob([
  10094. `self.onmessage = function(e) {
  10095. const timeout = e.data;
  10096. setTimeout(() => {
  10097. self.postMessage(1);
  10098. }, timeout);
  10099. };`,
  10100. ])
  10101. )
  10102. );
  10103. }
  10104. async start(endTime = Date.now() + 6e4, maxCount = 100) {
  10105. this.endTime = endTime;
  10106. this.maxCount = maxCount;
  10107. this.init();
  10108. return await new Promise((resolve) => {
  10109. this.resolve = resolve;
  10110. this.count = 0;
  10111. this.loop();
  10112. });
  10113. }
  10114. endFix() {
  10115. this.bestResult.maxCount = this.count;
  10116. this.worker.terminate();
  10117. this.resolve(this.bestResult);
  10118. }
  10119. async loop() {
  10120. const start = Date.now();
  10121. if (this.isEndLoop()) {
  10122. this.endFix();
  10123. return;
  10124. }
  10125. this.count++;
  10126. try {
  10127. this.lastResult = await Calc(this.battle);
  10128. } catch (e) {
  10129. this.updateProgressTimer(this.index++);
  10130. this.timeout(this.loop.bind(this), 0);
  10131. return;
  10132. }
  10133. const { progress, result } = this.lastResult;
  10134. this.lastBattleResult = result;
  10135. this.lastBattleProgress = progress;
  10136. this.setAvgTime(start);
  10137. this.checkResult();
  10138. this.showResult();
  10139. this.updateProgressTimer();
  10140. this.timeout(this.loop.bind(this), 0);
  10141. }
  10142. isEndLoop() {
  10143. return this.count >= this.maxCount || this.endTime < Date.now();
  10144. }
  10145. updateProgressTimer(index = 0) {
  10146. this.lastTimer = this.randTimer();
  10147. this.battle.progress = [{ attackers: { input: ['auto', 0, 0, 'auto', index, this.lastTimer] } }];
  10148. }
  10149. showResult() {
  10150. console.log(
  10151. this.count,
  10152. this.avgTime.toFixed(2),
  10153. (this.endTime - Date.now()) / 1000,
  10154. this.lastTimer.toFixed(2),
  10155. this.lastBossDamage.toLocaleString(),
  10156. this.bestResult.value.toLocaleString()
  10157. );
  10158. }
  10159. checkResult() {
  10160. const { damageTaken, damageTakenNextLevel } = this.lastBattleProgress[0].defenders.heroes[1].extra;
  10161. this.lastBossDamage = damageTaken + damageTakenNextLevel;
  10162. if (this.lastBossDamage > this.bestResult.value) {
  10163. this.bestResult = {
  10164. count: this.count,
  10165. timer: this.lastTimer,
  10166. value: this.lastBossDamage,
  10167. result: structuredClone(this.lastBattleResult),
  10168. progress: structuredClone(this.lastBattleProgress),
  10169. };
  10170. }
  10171. }
  10172. }
  10173. class WinFixBattle extends FixBattle {
  10174. checkResult() {
  10175. if (this.lastBattleResult.win) {
  10176. this.bestResult = {
  10177. count: this.count,
  10178. timer: this.lastTimer,
  10179. value: this.lastBattleResult.stars,
  10180. result: structuredClone(this.lastBattleResult),
  10181. progress: structuredClone(this.lastBattleProgress),
  10182. battleTimer: this.lastResult.battleTimer,
  10183. };
  10184. }
  10185. }
  10186. isEndLoop() {
  10187. return super.isEndLoop() || this.lastBattleResult.win;
  10188. }
  10189. showResult() {
  10190. console.log(this.count, this.avgTime.toFixed(2), (this.endTime - Date.now()) / 1000, this.lastResult.battleTime, this.lastTimer);
  10191. const endTime = ((this.endTime - Date.now()) / 1000).toFixed(2);
  10192. const avgTime = this.avgTime.toFixed(2);
  10193. const msg = `${this.count}/${this.maxCount}<br/>${endTime}s<br/>${avgTime}ms`;
  10194. setProgress(msg, false, this.stopFix.bind(this));
  10195. }
  10196. stopFix() {
  10197. this.endTime = 0;
  10198. }
  10199. }
  10200.  
  10201. function testDailyQuests() {
  10202. return new Promise((resolve, reject) => {
  10203. const quests = new dailyQuests(resolve, reject);
  10204. quests.init(questsInfo);
  10205. quests.start();
  10206. });
  10207. }
  10208.  
  10209. /**
  10210. * Automatic completion of daily quests
  10211. *
  10212. * Автоматическое выполнение ежедневных квестов
  10213. */
  10214. class dailyQuests {
  10215. /**
  10216. * Send(' {"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}').then(e => console.log(e))
  10217. * Send(' {"calls":[{"name":"heroGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10218. * Send(' {"calls":[{"name":"titanGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10219. * Send(' {"calls":[{"name":"inventoryGet","args":{},"ident":"body"}]}').then(e => console.log(e))
  10220. * Send(' {"calls":[{"name":"questGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10221. * Send(' {"calls":[{"name":"bossGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10222. */
  10223. callsList = [
  10224. "userGetInfo",
  10225. "heroGetAll",
  10226. "titanGetAll",
  10227. "inventoryGet",
  10228. "questGetAll",
  10229. "bossGetAll",
  10230. ]
  10231.  
  10232. dataQuests = {
  10233. 10001: {
  10234. description: 'Улучши умения героев 3 раза', // ++++++++++++++++
  10235. doItCall: () => {
  10236. const upgradeSkills = this.getUpgradeSkills();
  10237. return upgradeSkills.map(({ heroId, skill }, index) => ({ name: "heroUpgradeSkill", args: { heroId, skill }, "ident": `heroUpgradeSkill_${index}` }));
  10238. },
  10239. isWeCanDo: () => {
  10240. const upgradeSkills = this.getUpgradeSkills();
  10241. let sumGold = 0;
  10242. for (const skill of upgradeSkills) {
  10243. sumGold += this.skillCost(skill.value);
  10244. if (!skill.heroId) {
  10245. return false;
  10246. }
  10247. }
  10248. return this.questInfo['userGetInfo'].gold > sumGold;
  10249. },
  10250. },
  10251. 10002: {
  10252. description: 'Пройди 10 миссий', // --------------
  10253. isWeCanDo: () => false,
  10254. },
  10255. 10003: {
  10256. description: 'Пройди 3 героические миссии', // --------------
  10257. isWeCanDo: () => false,
  10258. },
  10259. 10004: {
  10260. description: 'Сразись 3 раза на Арене или Гранд Арене', // --------------
  10261. isWeCanDo: () => false,
  10262. },
  10263. 10006: {
  10264. description: 'Используй обмен изумрудов 1 раз', // ++++++++++++++++
  10265. doItCall: () => [{
  10266. name: "refillableAlchemyUse",
  10267. args: { multi: false },
  10268. ident: "refillableAlchemyUse"
  10269. }],
  10270. isWeCanDo: () => {
  10271. const starMoney = this.questInfo['userGetInfo'].starMoney;
  10272. return starMoney >= 20;
  10273. },
  10274. },
  10275. 10007: {
  10276. description: 'Соверши 1 призыв в Атриуме Душ', // ++++++++++++++++
  10277. doItCall: () => [{ name: "gacha_open", args: { ident: "heroGacha", free: true, pack: false }, ident: "gacha_open" }],
  10278. isWeCanDo: () => {
  10279. const soulCrystal = this.questInfo['inventoryGet'].coin[38];
  10280. return soulCrystal > 0;
  10281. },
  10282. },
  10283. /*10016: {
  10284. description: 'Отправь подарки согильдийцам', // ++++++++++++++++
  10285. doItCall: () => [{ name: "clanSendDailyGifts", args: {}, ident: "clanSendDailyGifts" }],
  10286. isWeCanDo: () => true,
  10287. },*/
  10288. 10018: {
  10289. description: 'Используй зелье опыта', // ++++++++++++++++
  10290. doItCall: () => {
  10291. const expHero = this.getExpHero();
  10292. return [{
  10293. name: "consumableUseHeroXp",
  10294. args: {
  10295. heroId: expHero.heroId,
  10296. libId: expHero.libId,
  10297. amount: 1
  10298. },
  10299. ident: "consumableUseHeroXp"
  10300. }];
  10301. },
  10302. isWeCanDo: () => {
  10303. const expHero = this.getExpHero();
  10304. return expHero.heroId && expHero.libId;
  10305. },
  10306. },
  10307. 10019: {
  10308. description: 'Открой 1 сундук в Башне',
  10309. doItFunc: testTower,
  10310. isWeCanDo: () => false,
  10311. },
  10312. 10020: {
  10313. description: 'Открой 3 сундука в Запределье', // Готово
  10314. doItCall: () => {
  10315. return this.getOutlandChest();
  10316. },
  10317. isWeCanDo: () => {
  10318. const outlandChest = this.getOutlandChest();
  10319. return outlandChest.length > 0;
  10320. },
  10321. },
  10322. 10021: {
  10323. description: 'Собери 75 Титанита в Подземелье Гильдии',
  10324. isWeCanDo: () => false,
  10325. },
  10326. 10022: {
  10327. description: 'Собери 150 Титанита в Подземелье Гильдии',
  10328. doItFunc: testDungeon,
  10329. isWeCanDo: () => false,
  10330. },
  10331. 10023: {
  10332. description: 'Прокачай Дар Стихий на 1 уровень', // Готово
  10333. doItCall: () => {
  10334. const heroId = this.getHeroIdTitanGift();
  10335. return [
  10336. { name: "heroTitanGiftLevelUp", args: { heroId }, ident: "heroTitanGiftLevelUp" },
  10337. { name: "heroTitanGiftDrop", args: { heroId }, ident: "heroTitanGiftDrop" }
  10338. ]
  10339. },
  10340. isWeCanDo: () => {
  10341. const heroId = this.getHeroIdTitanGift();
  10342. return heroId;
  10343. },
  10344. },
  10345. 10024: {
  10346. description: 'Повысь уровень любого артефакта один раз', // Готово
  10347. doItCall: () => {
  10348. const upArtifact = this.getUpgradeArtifact();
  10349. return [
  10350. {
  10351. name: "heroArtifactLevelUp",
  10352. args: {
  10353. heroId: upArtifact.heroId,
  10354. slotId: upArtifact.slotId
  10355. },
  10356. ident: `heroArtifactLevelUp`
  10357. }
  10358. ];
  10359. },
  10360. isWeCanDo: () => {
  10361. const upgradeArtifact = this.getUpgradeArtifact();
  10362. return upgradeArtifact.heroId;
  10363. },
  10364. },
  10365. 10025: {
  10366. description: 'Начни 1 Экспедицию',
  10367. doItFunc: checkExpedition,
  10368. isWeCanDo: () => false,
  10369. },
  10370. 10026: {
  10371. description: 'Начни 4 Экспедиции', // --------------
  10372. doItFunc: checkExpedition,
  10373. isWeCanDo: () => false,
  10374. },
  10375. 10027: {
  10376. description: 'Победи в 1 бою Турнира Стихий',
  10377. doItFunc: testTitanArena,
  10378. isWeCanDo: () => false,
  10379. },
  10380. 10028: {
  10381. description: 'Повысь уровень любого артефакта титанов', // Готово
  10382. doItCall: () => {
  10383. const upTitanArtifact = this.getUpgradeTitanArtifact();
  10384. return [
  10385. {
  10386. name: "titanArtifactLevelUp",
  10387. args: {
  10388. titanId: upTitanArtifact.titanId,
  10389. slotId: upTitanArtifact.slotId
  10390. },
  10391. ident: `titanArtifactLevelUp`
  10392. }
  10393. ];
  10394. },
  10395. isWeCanDo: () => {
  10396. const upgradeTitanArtifact = this.getUpgradeTitanArtifact();
  10397. return upgradeTitanArtifact.titanId;
  10398. },
  10399. },
  10400. 10029: {
  10401. description: 'Открой сферу артефактов титанов', // ++++++++++++++++
  10402. doItCall: () => [{ name: "titanArtifactChestOpen", args: { amount: 1, free: true }, ident: "titanArtifactChestOpen" }],
  10403. isWeCanDo: () => {
  10404. return this.questInfo['inventoryGet']?.consumable[55] > 0
  10405. },
  10406. },
  10407. 10030: {
  10408. description: 'Улучши облик любого героя 1 раз', // Готово
  10409. doItCall: () => {
  10410. const upSkin = this.getUpgradeSkin();
  10411. return [
  10412. {
  10413. name: "heroSkinUpgrade",
  10414. args: {
  10415. heroId: upSkin.heroId,
  10416. skinId: upSkin.skinId
  10417. },
  10418. ident: `heroSkinUpgrade`
  10419. }
  10420. ];
  10421. },
  10422. isWeCanDo: () => {
  10423. const upgradeSkin = this.getUpgradeSkin();
  10424. return upgradeSkin.heroId;
  10425. },
  10426. },
  10427. 10031: {
  10428. description: 'Победи в 6 боях Турнира Стихий', // --------------
  10429. doItFunc: testTitanArena,
  10430. isWeCanDo: () => false,
  10431. },
  10432. 10043: {
  10433. description: 'Начни или присоеденись к Приключению', // --------------
  10434. isWeCanDo: () => false,
  10435. },
  10436. 10044: {
  10437. description: 'Воспользуйся призывом питомцев 1 раз', // ++++++++++++++++
  10438. doItCall: () => [{ name: "pet_chestOpen", args: { amount: 1, paid: false }, ident: "pet_chestOpen" }],
  10439. isWeCanDo: () => {
  10440. return this.questInfo['inventoryGet']?.consumable[90] > 0
  10441. },
  10442. },
  10443. 10046: {
  10444. /**
  10445. * TODO: Watch Adventure
  10446. * TODO: Смотреть приключение
  10447. */
  10448. description: 'Открой 3 сундука в Приключениях',
  10449. isWeCanDo: () => false,
  10450. },
  10451. 10047: {
  10452. description: 'Набери 150 очков активности в Гильдии', // Готово
  10453. doItCall: () => {
  10454. const enchantRune = this.getEnchantRune();
  10455. return [
  10456. {
  10457. name: "heroEnchantRune",
  10458. args: {
  10459. heroId: enchantRune.heroId,
  10460. tier: enchantRune.tier,
  10461. items: {
  10462. consumable: { [enchantRune.itemId]: 1 }
  10463. }
  10464. },
  10465. ident: `heroEnchantRune`
  10466. }
  10467. ];
  10468. },
  10469. isWeCanDo: () => {
  10470. const userInfo = this.questInfo['userGetInfo'];
  10471. const enchantRune = this.getEnchantRune();
  10472. return enchantRune.heroId && userInfo.gold > 1e3;
  10473. },
  10474. },
  10475. };
  10476.  
  10477. constructor(resolve, reject, questInfo) {
  10478. this.resolve = resolve;
  10479. this.reject = reject;
  10480. }
  10481.  
  10482. init(questInfo) {
  10483. this.questInfo = questInfo;
  10484. this.isAuto = false;
  10485. }
  10486.  
  10487. async autoInit(isAuto) {
  10488. this.isAuto = isAuto || false;
  10489. const quests = {};
  10490. const calls = this.callsList.map(name => ({
  10491. name, args: {}, ident: name
  10492. }))
  10493. const result = await Send(JSON.stringify({ calls })).then(e => e.results);
  10494. for (const call of result) {
  10495. quests[call.ident] = call.result.response;
  10496. }
  10497. this.questInfo = quests;
  10498. }
  10499.  
  10500. async start() {
  10501. const weCanDo = [];
  10502. const selectedActions = getSaveVal('selectedActions', {});
  10503. for (let quest of this.questInfo['questGetAll']) {
  10504. if (quest.id in this.dataQuests && quest.state == 1) {
  10505. if (!selectedActions[quest.id]) {
  10506. selectedActions[quest.id] = {
  10507. checked: false
  10508. }
  10509. }
  10510.  
  10511. const isWeCanDo = this.dataQuests[quest.id].isWeCanDo;
  10512. if (!isWeCanDo.call(this)) {
  10513. continue;
  10514. }
  10515.  
  10516. weCanDo.push({
  10517. name: quest.id,
  10518. label: I18N(`QUEST_${quest.id}`),
  10519. checked: selectedActions[quest.id].checked
  10520. });
  10521. }
  10522. }
  10523.  
  10524. if (!weCanDo.length) {
  10525. this.end(I18N('NOTHING_TO_DO'));
  10526. return;
  10527. }
  10528.  
  10529. console.log(weCanDo);
  10530. let taskList = [];
  10531. if (this.isAuto) {
  10532. taskList = weCanDo;
  10533. } else {
  10534. const answer = await popup.confirm(`${I18N('YOU_CAN_COMPLETE') }:`, [
  10535. { msg: I18N('BTN_DO_IT'), result: true },
  10536. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  10537. ], weCanDo);
  10538. if (!answer) {
  10539. this.end('');
  10540. return;
  10541. }
  10542. taskList = popup.getCheckBoxes();
  10543. taskList.forEach(e => {
  10544. selectedActions[e.name].checked = e.checked;
  10545. });
  10546. setSaveVal('selectedActions', selectedActions);
  10547. }
  10548.  
  10549. const calls = [];
  10550. let countChecked = 0;
  10551. for (const task of taskList) {
  10552. if (task.checked) {
  10553. countChecked++;
  10554. const quest = this.dataQuests[task.name]
  10555. console.log(quest.description);
  10556.  
  10557. if (quest.doItCall) {
  10558. const doItCall = quest.doItCall.call(this);
  10559. calls.push(...doItCall);
  10560. }
  10561. }
  10562. }
  10563.  
  10564. if (!countChecked) {
  10565. this.end(I18N('NOT_QUEST_COMPLETED'));
  10566. return;
  10567. }
  10568.  
  10569. const result = await Send(JSON.stringify({ calls }));
  10570. if (result.error) {
  10571. console.error(result.error, result.error.call)
  10572. }
  10573. this.end(`${I18N('COMPLETED_QUESTS')}: ${countChecked}`);
  10574. }
  10575.  
  10576. errorHandling(error) {
  10577. //console.error(error);
  10578. let errorInfo = error.toString() + '\n';
  10579. try {
  10580. const errorStack = error.stack.split('\n');
  10581. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  10582. errorInfo += errorStack.slice(0, endStack).join('\n');
  10583. } catch (e) {
  10584. errorInfo += error.stack;
  10585. }
  10586. copyText(errorInfo);
  10587. }
  10588.  
  10589. skillCost(lvl) {
  10590. return 573 * lvl ** 0.9 + lvl ** 2.379;
  10591. }
  10592.  
  10593. getUpgradeSkills() {
  10594. const heroes = Object.values(this.questInfo['heroGetAll']);
  10595. const upgradeSkills = [
  10596. { heroId: 0, slotId: 0, value: 130 },
  10597. { heroId: 0, slotId: 0, value: 130 },
  10598. { heroId: 0, slotId: 0, value: 130 },
  10599. ];
  10600. const skillLib = lib.getData('skill');
  10601. /**
  10602. * color - 1 (белый) открывает 1 навык
  10603. * color - 2 (зеленый) открывает 2 навык
  10604. * color - 4 (синий) открывает 3 навык
  10605. * color - 7 (фиолетовый) открывает 4 навык
  10606. */
  10607. const colors = [1, 2, 4, 7];
  10608. for (const hero of heroes) {
  10609. const level = hero.level;
  10610. const color = hero.color;
  10611. for (let skillId in hero.skills) {
  10612. const tier = skillLib[skillId].tier;
  10613. const sVal = hero.skills[skillId];
  10614. if (color < colors[tier] || tier < 1 || tier > 4) {
  10615. continue;
  10616. }
  10617. for (let upSkill of upgradeSkills) {
  10618. if (sVal < upSkill.value && sVal < level) {
  10619. upSkill.value = sVal;
  10620. upSkill.heroId = hero.id;
  10621. upSkill.skill = tier;
  10622. break;
  10623. }
  10624. }
  10625. }
  10626. }
  10627. return upgradeSkills;
  10628. }
  10629.  
  10630. getUpgradeArtifact() {
  10631. const heroes = Object.values(this.questInfo['heroGetAll']);
  10632. const inventory = this.questInfo['inventoryGet'];
  10633. const upArt = { heroId: 0, slotId: 0, level: 100 };
  10634.  
  10635. const heroLib = lib.getData('hero');
  10636. const artifactLib = lib.getData('artifact');
  10637.  
  10638. for (const hero of heroes) {
  10639. const heroInfo = heroLib[hero.id];
  10640. const level = hero.level
  10641. if (level < 20) {
  10642. continue;
  10643. }
  10644.  
  10645. for (let slotId in hero.artifacts) {
  10646. const art = hero.artifacts[slotId];
  10647. /* Текущая звезданость арта */
  10648. const star = art.star;
  10649. if (!star) {
  10650. continue;
  10651. }
  10652. /* Текущий уровень арта */
  10653. const level = art.level;
  10654. if (level >= 100) {
  10655. continue;
  10656. }
  10657. /* Идентификатор арта в библиотеке */
  10658. const artifactId = heroInfo.artifacts[slotId];
  10659. const artInfo = artifactLib.id[artifactId];
  10660. const costNextLevel = artifactLib.type[artInfo.type].levels[level + 1].cost;
  10661.  
  10662. const costCurrency = Object.keys(costNextLevel).pop();
  10663. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  10664. const costId = costValues[0];
  10665. const costValue = +costValues[1];
  10666.  
  10667. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10668. if (level < upArt.level && inventory[costCurrency][costId] >= costValue) {
  10669. upArt.level = level;
  10670. upArt.heroId = hero.id;
  10671. upArt.slotId = slotId;
  10672. upArt.costCurrency = costCurrency;
  10673. upArt.costId = costId;
  10674. upArt.costValue = costValue;
  10675. }
  10676. }
  10677. }
  10678. return upArt;
  10679. }
  10680.  
  10681. getUpgradeSkin() {
  10682. const heroes = Object.values(this.questInfo['heroGetAll']);
  10683. const inventory = this.questInfo['inventoryGet'];
  10684. const upSkin = { heroId: 0, skinId: 0, level: 60, cost: 1500 };
  10685.  
  10686. const skinLib = lib.getData('skin');
  10687.  
  10688. for (const hero of heroes) {
  10689. const level = hero.level
  10690. if (level < 20) {
  10691. continue;
  10692. }
  10693.  
  10694. for (let skinId in hero.skins) {
  10695. /* Текущий уровень скина */
  10696. const level = hero.skins[skinId];
  10697. if (level >= 60) {
  10698. continue;
  10699. }
  10700. /* Идентификатор скина в библиотеке */
  10701. const skinInfo = skinLib[skinId];
  10702. if (!skinInfo.statData.levels?.[level + 1]) {
  10703. continue;
  10704. }
  10705. const costNextLevel = skinInfo.statData.levels[level + 1].cost;
  10706.  
  10707. const costCurrency = Object.keys(costNextLevel).pop();
  10708. const costCurrencyId = Object.keys(costNextLevel[costCurrency]).pop();
  10709. const costValue = +costNextLevel[costCurrency][costCurrencyId];
  10710.  
  10711. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10712. if (level < upSkin.level &&
  10713. costValue < upSkin.cost &&
  10714. inventory[costCurrency][costCurrencyId] >= costValue) {
  10715. upSkin.cost = costValue;
  10716. upSkin.level = level;
  10717. upSkin.heroId = hero.id;
  10718. upSkin.skinId = skinId;
  10719. upSkin.costCurrency = costCurrency;
  10720. upSkin.costCurrencyId = costCurrencyId;
  10721. }
  10722. }
  10723. }
  10724. return upSkin;
  10725. }
  10726.  
  10727. getUpgradeTitanArtifact() {
  10728. const titans = Object.values(this.questInfo['titanGetAll']);
  10729. const inventory = this.questInfo['inventoryGet'];
  10730. const userInfo = this.questInfo['userGetInfo'];
  10731. const upArt = { titanId: 0, slotId: 0, level: 120 };
  10732.  
  10733. const titanLib = lib.getData('titan');
  10734. const artTitanLib = lib.getData('titanArtifact');
  10735.  
  10736. for (const titan of titans) {
  10737. const titanInfo = titanLib[titan.id];
  10738. // const level = titan.level
  10739. // if (level < 20) {
  10740. // continue;
  10741. // }
  10742.  
  10743. for (let slotId in titan.artifacts) {
  10744. const art = titan.artifacts[slotId];
  10745. /* Текущая звезданость арта */
  10746. const star = art.star;
  10747. if (!star) {
  10748. continue;
  10749. }
  10750. /* Текущий уровень арта */
  10751. const level = art.level;
  10752. if (level >= 120) {
  10753. continue;
  10754. }
  10755. /* Идентификатор арта в библиотеке */
  10756. const artifactId = titanInfo.artifacts[slotId];
  10757. const artInfo = artTitanLib.id[artifactId];
  10758. const costNextLevel = artTitanLib.type[artInfo.type].levels[level + 1].cost;
  10759.  
  10760. const costCurrency = Object.keys(costNextLevel).pop();
  10761. let costValue = 0;
  10762. let currentValue = 0;
  10763. if (costCurrency == 'gold') {
  10764. costValue = costNextLevel[costCurrency];
  10765. currentValue = userInfo.gold;
  10766. } else {
  10767. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  10768. const costId = costValues[0];
  10769. costValue = +costValues[1];
  10770. currentValue = inventory[costCurrency][costId];
  10771. }
  10772.  
  10773. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10774. if (level < upArt.level && currentValue >= costValue) {
  10775. upArt.level = level;
  10776. upArt.titanId = titan.id;
  10777. upArt.slotId = slotId;
  10778. break;
  10779. }
  10780. }
  10781. }
  10782. return upArt;
  10783. }
  10784.  
  10785. getEnchantRune() {
  10786. const heroes = Object.values(this.questInfo['heroGetAll']);
  10787. const inventory = this.questInfo['inventoryGet'];
  10788. const enchRune = { heroId: 0, tier: 0, exp: 43750, itemId: 0 };
  10789. for (let i = 1; i <= 4; i++) {
  10790. if (inventory.consumable[i] > 0) {
  10791. enchRune.itemId = i;
  10792. break;
  10793. }
  10794. return enchRune;
  10795. }
  10796.  
  10797. const runeLib = lib.getData('rune');
  10798. const runeLvls = Object.values(runeLib.level);
  10799. /**
  10800. * color - 4 (синий) открывает 1 и 2 символ
  10801. * color - 7 (фиолетовый) открывает 3 символ
  10802. * color - 8 (фиолетовый +1) открывает 4 символ
  10803. * color - 9 (фиолетовый +2) открывает 5 символ
  10804. */
  10805. // TODO: кажется надо учесть уровень команды
  10806. const colors = [4, 4, 7, 8, 9];
  10807. for (const hero of heroes) {
  10808. const color = hero.color;
  10809.  
  10810.  
  10811. for (let runeTier in hero.runes) {
  10812. /* Проверка на доступность руны */
  10813. if (color < colors[runeTier]) {
  10814. continue;
  10815. }
  10816. /* Текущий опыт руны */
  10817. const exp = hero.runes[runeTier];
  10818. if (exp >= 43750) {
  10819. continue;
  10820. }
  10821.  
  10822. let level = 0;
  10823. if (exp) {
  10824. for (let lvl of runeLvls) {
  10825. if (exp >= lvl.enchantValue) {
  10826. level = lvl.level;
  10827. } else {
  10828. break;
  10829. }
  10830. }
  10831. }
  10832. /** Уровень героя необходимый для уровня руны */
  10833. const heroLevel = runeLib.level[level].heroLevel;
  10834. if (hero.level < heroLevel) {
  10835. continue;
  10836. }
  10837.  
  10838. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10839. if (exp < enchRune.exp) {
  10840. enchRune.exp = exp;
  10841. enchRune.heroId = hero.id;
  10842. enchRune.tier = runeTier;
  10843. break;
  10844. }
  10845. }
  10846. }
  10847. return enchRune;
  10848. }
  10849.  
  10850. getOutlandChest() {
  10851. const bosses = this.questInfo['bossGetAll'];
  10852.  
  10853. const calls = [];
  10854.  
  10855. for (let boss of bosses) {
  10856. if (boss.mayRaid) {
  10857. calls.push({
  10858. name: "bossRaid",
  10859. args: {
  10860. bossId: boss.id
  10861. },
  10862. ident: "bossRaid_" + boss.id
  10863. });
  10864. calls.push({
  10865. name: "bossOpenChest",
  10866. args: {
  10867. bossId: boss.id,
  10868. amount: 1,
  10869. starmoney: 0
  10870. },
  10871. ident: "bossOpenChest_" + boss.id
  10872. });
  10873. } else if (boss.chestId == 1) {
  10874. calls.push({
  10875. name: "bossOpenChest",
  10876. args: {
  10877. bossId: boss.id,
  10878. amount: 1,
  10879. starmoney: 0
  10880. },
  10881. ident: "bossOpenChest_" + boss.id
  10882. });
  10883. }
  10884. }
  10885.  
  10886. return calls;
  10887. }
  10888.  
  10889. getExpHero() {
  10890. const heroes = Object.values(this.questInfo['heroGetAll']);
  10891. const inventory = this.questInfo['inventoryGet'];
  10892. const expHero = { heroId: 0, exp: 3625195, libId: 0 };
  10893. /** зелья опыта (consumable 9, 10, 11, 12) */
  10894. for (let i = 9; i <= 12; i++) {
  10895. if (inventory.consumable[i]) {
  10896. expHero.libId = i;
  10897. break;
  10898. }
  10899. }
  10900.  
  10901. for (const hero of heroes) {
  10902. const exp = hero.xp;
  10903. if (exp < expHero.exp) {
  10904. expHero.heroId = hero.id;
  10905. }
  10906. }
  10907. return expHero;
  10908. }
  10909.  
  10910. getHeroIdTitanGift() {
  10911. const heroes = Object.values(this.questInfo['heroGetAll']);
  10912. const inventory = this.questInfo['inventoryGet'];
  10913. const user = this.questInfo['userGetInfo'];
  10914. const titanGiftLib = lib.getData('titanGift');
  10915. /** Искры */
  10916. const titanGift = inventory.consumable[24];
  10917. let heroId = 0;
  10918. let minLevel = 30;
  10919.  
  10920. if (titanGift < 250 || user.gold < 7000) {
  10921. return 0;
  10922. }
  10923.  
  10924. for (const hero of heroes) {
  10925. if (hero.titanGiftLevel >= 30) {
  10926. continue;
  10927. }
  10928.  
  10929. if (!hero.titanGiftLevel) {
  10930. return hero.id;
  10931. }
  10932.  
  10933. const cost = titanGiftLib[hero.titanGiftLevel].cost;
  10934. if (minLevel > hero.titanGiftLevel &&
  10935. titanGift >= cost.consumable[24] &&
  10936. user.gold >= cost.gold
  10937. ) {
  10938. minLevel = hero.titanGiftLevel;
  10939. heroId = hero.id;
  10940. }
  10941. }
  10942.  
  10943. return heroId;
  10944. }
  10945.  
  10946. end(status) {
  10947. setProgress(status, true);
  10948. this.resolve();
  10949. }
  10950. }
  10951.  
  10952. this.questRun = dailyQuests;
  10953.  
  10954. function testDoYourBest() {
  10955. return new Promise((resolve, reject) => {
  10956. const doIt = new doYourBest(resolve, reject);
  10957. doIt.start();
  10958. });
  10959. }
  10960.  
  10961. /**
  10962. * Do everything button
  10963. *
  10964. * Кнопка сделать все
  10965. */
  10966. class doYourBest {
  10967.  
  10968. funcList = [
  10969. //собрать запределье
  10970. {
  10971. name: 'getOutland',
  10972. label: I18N('ASSEMBLE_OUTLAND'),
  10973. checked: false
  10974. },
  10975. //пройти башню
  10976. {
  10977. name: 'testTower',
  10978. label: I18N('PASS_THE_TOWER'),
  10979. checked: false
  10980. },
  10981. //экспедиции
  10982. {
  10983. name: 'checkExpedition',
  10984. label: I18N('CHECK_EXPEDITIONS'),
  10985. checked: false
  10986. },
  10987. //турнир стихий
  10988. {
  10989. name: 'testTitanArena',
  10990. label: I18N('COMPLETE_TOE'),
  10991. checked: false
  10992. },
  10993. //собрать почту
  10994. {
  10995. name: 'mailGetAll',
  10996. label: I18N('COLLECT_MAIL'),
  10997. checked: false
  10998. },
  10999. //Собрать всякую херню
  11000. {
  11001. name: 'collectAllStuff',
  11002. label: I18N('COLLECT_MISC'),
  11003. title: I18N('COLLECT_MISC_TITLE'),
  11004. checked: false
  11005. },
  11006. //ежедневная награда
  11007. {
  11008. name: 'getDailyBonus',
  11009. label: I18N('DAILY_BONUS'),
  11010. checked: false
  11011. },
  11012. //ежедневные квесты удалить наверно есть в настройках
  11013. {
  11014. name: 'dailyQuests',
  11015. label: I18N('DO_DAILY_QUESTS'),
  11016. checked: false
  11017. },
  11018. //Провидец
  11019. {
  11020. name: 'rollAscension',
  11021. label: I18N('SEER_TITLE'),
  11022. checked: false
  11023. },
  11024. //собрать награды за квесты
  11025. {
  11026. name: 'questAllFarm',
  11027. label: I18N('COLLECT_QUEST_REWARDS'),
  11028. checked: false
  11029. },
  11030. // тест отправь подарки согильдийцам
  11031. {
  11032. name: 'testclanSendDailyGifts',
  11033. label: I18N('QUEST_10016'),
  11034. checked: false
  11035. },
  11036. //собрать новогодние подарки
  11037. /*{
  11038. name: 'getGiftNewYear',
  11039. label: I18N('NY_GIFTS'),
  11040. checked: false
  11041. },*/
  11042. // тест сферу титанов
  11043. /*{
  11044. name: 'testtitanArtifactChestOpen',
  11045. label: I18N('QUEST_10029'),
  11046. checked: false
  11047. },
  11048. // тест призыв петов
  11049. {
  11050. name: 'testpet_chestOpen',
  11051. label: I18N('QUEST_10044'),
  11052. checked: false
  11053. },*/
  11054. //пройти подземелье обычное
  11055. {
  11056. name: 'testDungeon',
  11057. label: I18N('COMPLETE_DUNGEON'),
  11058. checked: false
  11059. },
  11060. //пройти подземелье для фуловых титанов
  11061. {
  11062. name: 'DungeonFull',
  11063. label: I18N('COMPLETE_DUNGEON_FULL'),
  11064. checked: false
  11065. },
  11066. //синхронизация
  11067. {
  11068. name: 'synchronization',
  11069. label: I18N('MAKE_A_SYNC'),
  11070. checked: false
  11071. },
  11072. //перезагрузка
  11073. {
  11074. name: 'reloadGame',
  11075. label: I18N('RELOAD_GAME'),
  11076. checked: false
  11077. },
  11078. ];
  11079.  
  11080. functions = {
  11081. getOutland,//собрать запределье
  11082. testTower,//прохождение башни
  11083. checkExpedition,//автоэкспедиции
  11084. testTitanArena,//Автопрохождение Турнира Стихий
  11085. mailGetAll,//Собрать всю почту, кроме писем с энергией и зарядами портала
  11086. //Собрать пасхалки, камни облика, ключи, монеты арены и Хрусталь души
  11087. collectAllStuff: async () => {
  11088. await offerFarmAllReward();
  11089. 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"}]}');
  11090. },
  11091. //Выполнять ежедневные квесты
  11092. dailyQuests: async function () {
  11093. const quests = new dailyQuests(() => { }, () => { });
  11094. await quests.autoInit(true);
  11095. await quests.start();
  11096. },
  11097. rollAscension,//провидец
  11098. getDailyBonus,//ежедневная награда
  11099. questAllFarm,//Собрать все награды за задания
  11100. testclanSendDailyGifts, //отправить подарки
  11101. getGiftNewYear,//собрать новогодние подарки
  11102. testtitanArtifactChestOpen, //открой сферу титанов
  11103. testpet_chestOpen, //Воспользуйся призывом питомцев 1 раз
  11104. testDungeon,//подземка обычная
  11105. DungeonFull,//подземка для фуловых титанов
  11106. synchronization: async () => {
  11107. cheats.refreshGame();
  11108. },
  11109. reloadGame: async () => {
  11110. location.reload();
  11111. },
  11112. }
  11113.  
  11114. constructor(resolve, reject, questInfo) {
  11115. this.resolve = resolve;
  11116. this.reject = reject;
  11117. this.questInfo = questInfo
  11118. }
  11119.  
  11120. async start() {
  11121. const selectedDoIt = getSaveVal('selectedDoIt', {});
  11122.  
  11123. this.funcList.forEach(task => {
  11124. if (!selectedDoIt[task.name]) {
  11125. selectedDoIt[task.name] = {
  11126. checked: task.checked
  11127. }
  11128. } else {
  11129. task.checked = selectedDoIt[task.name].checked
  11130. }
  11131. });
  11132.  
  11133. const answer = await popup.confirm(I18N('RUN_FUNCTION'), [
  11134. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  11135. { msg: I18N('BTN_GO'), result: true },
  11136. ], this.funcList);
  11137.  
  11138. if (!answer) {
  11139. this.end('');
  11140. return;
  11141. }
  11142.  
  11143. const taskList = popup.getCheckBoxes();
  11144. taskList.forEach(task => {
  11145. selectedDoIt[task.name].checked = task.checked;
  11146. });
  11147. setSaveVal('selectedDoIt', selectedDoIt);
  11148. for (const task of popup.getCheckBoxes()) {
  11149. if (task.checked) {
  11150. try {
  11151. setProgress(`${task.label} <br>${I18N('PERFORMED')}!`);
  11152. await this.functions[task.name]();
  11153. setProgress(`${task.label} <br>${I18N('DONE')}!`);
  11154. } catch (error) {
  11155. if (await popup.confirm(`${I18N('ERRORS_OCCURRES')}:<br> ${task.label} <br>${I18N('COPY_ERROR')}?`, [
  11156. { msg: I18N('BTN_NO'), result: false },
  11157. { msg: I18N('BTN_YES'), result: true },
  11158. ])) {
  11159. this.errorHandling(error);
  11160. }
  11161. }
  11162. }
  11163. }
  11164. setTimeout((msg) => {
  11165. this.end(msg);
  11166. }, 2000, I18N('ALL_TASK_COMPLETED'));
  11167. return;
  11168. }
  11169.  
  11170. errorHandling(error) {
  11171. //console.error(error);
  11172. let errorInfo = error.toString() + '\n';
  11173. try {
  11174. const errorStack = error.stack.split('\n');
  11175. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  11176. errorInfo += errorStack.slice(0, endStack).join('\n');
  11177. } catch (e) {
  11178. errorInfo += error.stack;
  11179. }
  11180. copyText(errorInfo);
  11181. }
  11182.  
  11183. end(status) {
  11184. setProgress(status, true);
  11185. this.resolve();
  11186. }
  11187. }
  11188.  
  11189. /**
  11190. * Passing the adventure along the specified route
  11191. *
  11192. * Прохождение приключения по указанному маршруту
  11193. */
  11194. function testAdventure(type) {
  11195. return new Promise((resolve, reject) => {
  11196. const bossBattle = new executeAdventure(resolve, reject);
  11197. bossBattle.start(type);
  11198. });
  11199. }
  11200.  
  11201. //Буря
  11202. function testAdventure2(solo) {
  11203. return new Promise((resolve, reject) => {
  11204. const bossBattle = new executeAdventure2(resolve, reject);
  11205. bossBattle.start(solo);
  11206. });
  11207. }
  11208.  
  11209. /**
  11210. * Passing the adventure along the specified route
  11211. *
  11212. * Прохождение приключения по указанному маршруту
  11213. */
  11214. class executeAdventure {
  11215.  
  11216. type = 'default';
  11217.  
  11218. actions = {
  11219. default: {
  11220. getInfo: "adventure_getInfo",
  11221. startBattle: 'adventure_turnStartBattle',
  11222. endBattle: 'adventure_endBattle',
  11223. collectBuff: 'adventure_turnCollectBuff'
  11224. },
  11225. solo: {
  11226. getInfo: "adventureSolo_getInfo",
  11227. startBattle: 'adventureSolo_turnStartBattle',
  11228. endBattle: 'adventureSolo_endBattle',
  11229. collectBuff: 'adventureSolo_turnCollectBuff'
  11230. }
  11231. }
  11232.  
  11233. terminatеReason = I18N('UNKNOWN');
  11234. callAdventureInfo = {
  11235. name: "adventure_getInfo",
  11236. args: {},
  11237. ident: "adventure_getInfo"
  11238. }
  11239. callTeamGetAll = {
  11240. name: "teamGetAll",
  11241. args: {},
  11242. ident: "teamGetAll"
  11243. }
  11244. callTeamGetFavor = {
  11245. name: "teamGetFavor",
  11246. args: {},
  11247. ident: "teamGetFavor"
  11248. }
  11249. //тест прикла
  11250. defaultWays = {
  11251. //Галахад, 1-я
  11252. "adv_strongford_2pl_easy": {
  11253. first: '1,2,3,5,6',
  11254. second: '1,2,4,7,6',
  11255. third: '1,2,3,5,6'
  11256. },
  11257. //Джинджер, 2-я
  11258. "adv_valley_3pl_easy": {
  11259. first: '1,2,5,8,9,11',
  11260. second: '1,3,6,9,11',
  11261. third: '1,4,7,10,9,11'
  11262. },
  11263. //Орион, 3-я
  11264. "adv_ghirwil_3pl_easy": {
  11265. first: '1,5,6,9,11',
  11266. second: '1,4,12,13,11',
  11267. third: '1,2,3,7,10,11'
  11268. },
  11269. //Тесак, 4-я
  11270. "adv_angels_3pl_easy_fire": {
  11271. first: '1,2,4,7,18,8,12,19,22,23',
  11272. second: '1,3,6,11,17,10,16,21,22,23',
  11273. third: '1,5,24,25,9,14,15,20,22,23'
  11274. },
  11275. //Галахад, 5-я
  11276. "adv_strongford_3pl_normal_2": {
  11277. first: '1,2,7,8,12,16,23,26,25,21,24',
  11278. second: '1,4,6,10,11,15,22,15,19,18,24',
  11279. third: '1,5,9,10,14,17,20,27,25,21,24'
  11280. },
  11281. //Джинджер, 6-я
  11282. "adv_valley_3pl_normal": {
  11283. first: '1,2,4,7,10,13,16,19,24,22,25',
  11284. second: '1,3,6,9,12,15,18,21,26,23,25',
  11285. third: '1,5,7,8,11,14,17,20,22,25'
  11286. },
  11287. //Орион, 7-я
  11288. "adv_ghirwil_3pl_normal_2": {
  11289. first: '1,11,10,11,12,15,12,11,21,25,27',
  11290. second: '1,7,3,4,3,6,13,19,20,24,27',
  11291. third: '1,8,5,9,16,23,22,26,27'
  11292. },
  11293. //Тесак, 8-я
  11294. "adv_angels_3pl_normal": {
  11295. first: '1,3,4,8,7,9,10,13,17,16,20,22,23,31,32',
  11296. second: '1,3,5,7,8,11,14,18,20,22,24,27,30,26,32',
  11297. third: '1,3,2,6,7,9,11,15,19,20,22,21,28,29,25'
  11298. },
  11299. //Галахад, 9-я
  11300. "adv_strongford_3pl_hard_2": {
  11301. first: '1,2,6,10,15,7,16,17,23,22,27,32,35,37,40,45',
  11302. second: '1,3,8,12,11,18,19,28,34,33,38,41,43,46,45',
  11303. third: '1,2,5,9,14,20,26,21,30,36,39,42,44,45'
  11304. },
  11305. //Джинджер, 10-я
  11306. "adv_valley_3pl_hard": {
  11307. first: '1,3,2,6,11,17,25,30,35,34,29,24,21,17,12,7',
  11308. second: '1,4,8,13,18,22,26,31,36,40,45,44,43,38,33,28',
  11309. third: '1,5,9,14,19,23,27,32,37,42,48,51,50,49,46,52'
  11310. },
  11311. //Орион, 11-я
  11312. "adv_ghirwil_3pl_hard": {
  11313. first: '1,2,3,6,8,12,11,15,21,27,36,34,33,35,37',
  11314. second: '1,2,4,6,9,13,18,17,16,22,28,29,30,31,25,19',
  11315. third: '1,2,5,6,10,13,14,20,26,32,38,41,40,39,37'
  11316. },
  11317. //Тесак, 12-я
  11318. "adv_angels_3pl_hard": {
  11319. first: '1,2,8,11,7,4,7,16,23,32,33,25,34,29,35,36',
  11320. second: '1,3,9,13,10,6,10,22,31,30,21,30,15,28,20,27',
  11321. third: '1,5,12,14,24,17,24,25,26,18,19,20,27'
  11322. },
  11323. //Тесак, 13-я
  11324. "adv_angels_3pl_hell": {
  11325. first: '1,2,4,6,16,23,33,34,25,32,29,28,20,27',
  11326. second: '1,7,11,17,24,14,26,18,19,20,27,20,12,8',
  11327. third: '1,9,3,5,10,22,31,36,31,30,15,28,29,30,21,13'
  11328. },
  11329. //Галахад, 13-я
  11330. "adv_strongford_3pl_hell": {
  11331. first: '1,2,5,11,14,20,26,21,30,35,38,41,43,44',
  11332. second: '1,2,6,12,15,7,16,17,23,22,27,42,34,36,39,44',
  11333. third: '1,3,8,9,13,18,19,28,0,33,37,40,32,45,44'
  11334. },
  11335. //Орион, 13-я
  11336. "adv_ghirwil_3pl_hell": {
  11337. first: '1,2,3,6,8,12,11,15,21,27,36,34,33,35,37',
  11338. second: '1,2,4,6,9,13,18,17,16,22,28,29,30,31,25,19',
  11339. third: '1,2,5,6,10,13,14,20,26,32,38,41,40,39,37'
  11340. },
  11341. //Джинджер, 13-я
  11342. "adv_valley_3pl_hell": {
  11343. first: '1,3,2,6,11,17,25,30,35,34,29,24,21,17,12,7',
  11344. second: '1,4,8,13,18,22,26,31,36,40,45,44,43,38,33,28',
  11345. third: '1,5,9,14,19,23,27,32,37,42,48,51,50,49,46,52'
  11346. }
  11347. }
  11348. callStartBattle = {
  11349. name: "adventure_turnStartBattle",
  11350. args: {},
  11351. ident: "body"
  11352. }
  11353. callEndBattle = {
  11354. name: "adventure_endBattle",
  11355. args: {
  11356. result: {},
  11357. progress: {},
  11358. },
  11359. ident: "body"
  11360. }
  11361. callCollectBuff = {
  11362. name: "adventure_turnCollectBuff",
  11363. args: {},
  11364. ident: "body"
  11365. }
  11366.  
  11367. constructor(resolve, reject) {
  11368. this.resolve = resolve;
  11369. this.reject = reject;
  11370. }
  11371.  
  11372. async start(type) {
  11373. //this.type = type || this.type;
  11374. //this.callAdventureInfo.name = this.actions[this.type].getInfo;
  11375. const data = await Send(JSON.stringify({
  11376. calls: [
  11377. this.callAdventureInfo,
  11378. this.callTeamGetAll,
  11379. this.callTeamGetFavor
  11380. ]
  11381. }));
  11382. //тест прикла1
  11383. this.path = await this.getPath(data.results[0].result.response.mapIdent);
  11384. if (!this.path) {
  11385. this.end();
  11386. return;
  11387. }
  11388. return this.checkAdventureInfo(data.results);
  11389. }
  11390.  
  11391. async getPath(mapId) {
  11392. //const oldVal = getSaveVal('adventurePath', '');
  11393. //const keyPath = `adventurePath:${this.mapIdent}`;
  11394. const answer = await popup.confirm(I18N('ENTER_THE_PATH'), [
  11395. {
  11396. msg: I18N('START_ADVENTURE'),
  11397. placeholder: '1,2,3,4,5,6',
  11398. isInput: true,
  11399. //default: getSaveVal(keyPath, oldVal)
  11400. default: getSaveVal('adventurePath', '')
  11401. },
  11402. {
  11403. msg: ' Начать по пути №1! ',
  11404. placeholder: '1,2,3',
  11405. isInput: true,
  11406. default: this.defaultWays[mapId]?.first
  11407. },
  11408. {
  11409. msg: ' Начать по пути №2! ',
  11410. placeholder: '1,2,3',
  11411. isInput: true,
  11412. default: this.defaultWays[mapId]?.second
  11413. },
  11414. {
  11415. msg: ' Начать по пути №3! ',
  11416. placeholder: '1,2,3',
  11417. isInput: true,
  11418. default: this.defaultWays[mapId]?.third
  11419. },
  11420. {
  11421. msg: I18N('BTN_CANCEL'),
  11422. result: false,
  11423. isCancel: true
  11424. },
  11425. ]);
  11426. if (!answer) {
  11427. this.terminatеReason = I18N('BTN_CANCELED');
  11428. return false;
  11429. }
  11430.  
  11431. let path = answer.split(',');
  11432. if (path.length < 2) {
  11433. path = answer.split('-');
  11434. }
  11435. if (path.length < 2) {
  11436. this.terminatеReason = I18N('MUST_TWO_POINTS');
  11437. return false;
  11438. }
  11439.  
  11440. for (let p in path) {
  11441. path[p] = +path[p].trim()
  11442. if (Number.isNaN(path[p])) {
  11443. this.terminatеReason = I18N('MUST_ONLY_NUMBERS');
  11444. return false;
  11445. }
  11446. }
  11447.  
  11448. /*if (!this.checkPath(path)) {
  11449. return false;
  11450. }*/
  11451. //setSaveVal(keyPath, answer);
  11452. setSaveVal('adventurePath', answer);
  11453. return path;
  11454. }
  11455. /*
  11456. checkPath(path) {
  11457. for (let i = 0; i < path.length - 1; i++) {
  11458. const currentPoint = path[i];
  11459. const nextPoint = path[i + 1];
  11460.  
  11461. const isValidPath = this.paths.some(p =>
  11462. (p.from_id === currentPoint && p.to_id === nextPoint) ||
  11463. (p.from_id === nextPoint && p.to_id === currentPoint)
  11464. );
  11465.  
  11466. if (!isValidPath) {
  11467. this.terminatеReason = I18N('INCORRECT_WAY', {
  11468. from: currentPoint,
  11469. to: nextPoint,
  11470. });
  11471. return false;
  11472. }
  11473. }
  11474.  
  11475. return true;
  11476. }
  11477. */
  11478. async checkAdventureInfo(data) {
  11479. this.advInfo = data[0].result.response;
  11480. if (!this.advInfo) {
  11481. this.terminatеReason = I18N('NOT_ON_AN_ADVENTURE') ;
  11482. return this.end();
  11483. }
  11484. const heroesTeam = data[1].result.response.adventure_hero;
  11485. const favor = data[2]?.result.response.adventure_hero;
  11486. const heroes = heroesTeam.slice(0, 5);
  11487. const pet = heroesTeam[5];
  11488. this.args = {
  11489. pet,
  11490. heroes,
  11491. favor,
  11492. path: [],
  11493. broadcast: false
  11494. }
  11495. const advUserInfo = this.advInfo.users[userInfo.id];
  11496. this.turnsLeft = advUserInfo.turnsLeft;
  11497. this.currentNode = advUserInfo.currentNode;
  11498. this.nodes = this.advInfo.nodes;
  11499. //this.paths = this.advInfo.paths;
  11500. //this.mapIdent = this.advInfo.mapIdent;
  11501.  
  11502. /*this.path = await this.getPath();
  11503. if (!this.path) {
  11504. return this.end();
  11505. }*/
  11506.  
  11507. if (this.currentNode == 1 && this.path[0] != 1) {
  11508. this.path.unshift(1);
  11509. }
  11510.  
  11511. return this.loop();
  11512. }
  11513.  
  11514. async loop() {
  11515. const position = this.path.indexOf(+this.currentNode);
  11516. if (!(~position)) {
  11517. this.terminatеReason = I18N('YOU_IN_NOT_ON_THE_WAY');
  11518. return this.end();
  11519. }
  11520. this.path = this.path.slice(position);
  11521. if ((this.path.length - 1) > this.turnsLeft &&
  11522. await popup.confirm(I18N('ATTEMPTS_NOT_ENOUGH'), [
  11523. { msg: I18N('YES_CONTINUE'), result: false },
  11524. { msg: I18N('BTN_NO'), result: true },
  11525. ])) {
  11526. this.terminatеReason = I18N('NOT_ENOUGH_AP');
  11527. return this.end();
  11528. }
  11529. const toPath = [];
  11530. for (const nodeId of this.path) {
  11531. if (!this.turnsLeft) {
  11532. this.terminatеReason = I18N('ATTEMPTS_ARE_OVER');
  11533. return this.end();
  11534. }
  11535. toPath.push(nodeId);
  11536. console.log(toPath);
  11537. if (toPath.length > 1) {
  11538. setProgress(toPath.join(' > ') + ` ${I18N('MOVES')}: ` + this.turnsLeft);
  11539. }
  11540. if (nodeId == this.currentNode) {
  11541. continue;
  11542. }
  11543.  
  11544. const nodeInfo = this.getNodeInfo(nodeId);
  11545. if (nodeInfo.type == 'TYPE_COMBAT') {
  11546. if (nodeInfo.state == 'empty') {
  11547. this.turnsLeft--;
  11548. continue;
  11549. }
  11550.  
  11551. /**
  11552. * Disable regular battle cancellation
  11553. *
  11554. * Отключаем штатную отменую боя
  11555. */
  11556. isCancalBattle = false;
  11557. if (await this.battle(toPath)) {
  11558. this.turnsLeft--;
  11559. toPath.splice(0, toPath.indexOf(nodeId));
  11560. nodeInfo.state = 'empty';
  11561. isCancalBattle = true;
  11562. continue;
  11563. }
  11564. isCancalBattle = true;
  11565. return this.end()
  11566. }
  11567.  
  11568. if (nodeInfo.type == 'TYPE_PLAYERBUFF') {
  11569. const buff = this.checkBuff(nodeInfo);
  11570. if (buff == null) {
  11571. continue;
  11572. }
  11573.  
  11574. if (await this.collectBuff(buff, toPath)) {
  11575. this.turnsLeft--;
  11576. toPath.splice(0, toPath.indexOf(nodeId));
  11577. continue;
  11578. }
  11579. this.terminatеReason = I18N('BUFF_GET_ERROR');
  11580. return this.end();
  11581. }
  11582. }
  11583. this.terminatеReason = I18N('SUCCESS');
  11584. return this.end();
  11585. }
  11586.  
  11587. /**
  11588. * Carrying out a fight
  11589. *
  11590. * Проведение боя
  11591. */
  11592. async battle(path, preCalc = true) {
  11593. const data = await this.startBattle(path);
  11594. try {
  11595. const battle = data.results[0].result.response.battle;
  11596. const result = await Calc(battle);
  11597. if (result.result.win) {
  11598. const info = await this.endBattle(result);
  11599. if (info.results[0].result.response?.error) {
  11600. this.terminatеReason = I18N('BATTLE_END_ERROR');
  11601. return false;
  11602. }
  11603. } else {
  11604. await this.cancelBattle(result);
  11605.  
  11606. if (preCalc && await this.preCalcBattle(battle)) {
  11607. path = path.slice(-2);
  11608. for (let i = 1; i <= getInput('countAutoBattle'); i++) {
  11609. setProgress(`${I18N('AUTOBOT')}: ${i}/${getInput('countAutoBattle')}`);
  11610. const result = await this.battle(path, false);
  11611. if (result) {
  11612. setProgress(I18N('VICTORY'));
  11613. return true;
  11614. }
  11615. }
  11616. this.terminatеReason = I18N('FAILED_TO_WIN_AUTO');
  11617. return false;
  11618. }
  11619. return false;
  11620. }
  11621. } catch (error) {
  11622. console.error(error);
  11623. if (await popup.confirm(I18N('ERROR_OF_THE_BATTLE_COPY'), [
  11624. { msg: I18N('BTN_NO'), result: false },
  11625. { msg: I18N('BTN_YES'), result: true },
  11626. ])) {
  11627. this.errorHandling(error, data);
  11628. }
  11629. this.terminatеReason = I18N('ERROR_DURING_THE_BATTLE');
  11630. return false;
  11631. }
  11632. return true;
  11633. }
  11634.  
  11635. /**
  11636. * Recalculate battles
  11637. *
  11638. * Прерасчтет битвы
  11639. */
  11640. async preCalcBattle(battle) {
  11641. const countTestBattle = getInput('countTestBattle');
  11642. for (let i = 0; i < countTestBattle; i++) {
  11643. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  11644. const result = await Calc(battle);
  11645. if (result.result.win) {
  11646. console.log(i, countTestBattle);
  11647. return true;
  11648. }
  11649. }
  11650. this.terminatеReason = I18N('NO_CHANCE_WIN') + countTestBattle;
  11651. return false;
  11652. }
  11653.  
  11654. /**
  11655. * Starts a fight
  11656. *
  11657. * Начинает бой
  11658. */
  11659. startBattle(path) {
  11660. this.args.path = path;
  11661. this.callStartBattle.name = this.actions[this.type].startBattle;
  11662. this.callStartBattle.args = this.args
  11663. const calls = [this.callStartBattle];
  11664. return Send(JSON.stringify({ calls }));
  11665. }
  11666.  
  11667. cancelBattle(battle) {
  11668. const fixBattle = function (heroes) {
  11669. for (const ids in heroes) {
  11670. const hero = heroes[ids];
  11671. hero.energy = random(1, 999);
  11672. if (hero.hp > 0) {
  11673. hero.hp = random(1, hero.hp);
  11674. }
  11675. }
  11676. }
  11677. fixBattle(battle.progress[0].attackers.heroes);
  11678. fixBattle(battle.progress[0].defenders.heroes);
  11679. return this.endBattle(battle);
  11680. }
  11681.  
  11682. /**
  11683. * Ends the fight
  11684. *
  11685. * Заканчивает бой
  11686. */
  11687. endBattle(battle) {
  11688. this.callEndBattle.name = this.actions[this.type].endBattle;
  11689. this.callEndBattle.args.result = battle.result
  11690. this.callEndBattle.args.progress = battle.progress
  11691. const calls = [this.callEndBattle];
  11692. return Send(JSON.stringify({ calls }));
  11693. }
  11694.  
  11695. /**
  11696. * Checks if you can get a buff
  11697. *
  11698. * Проверяет можно ли получить баф
  11699. */
  11700. checkBuff(nodeInfo) {
  11701. let id = null;
  11702. let value = 0;
  11703. for (const buffId in nodeInfo.buffs) {
  11704. const buff = nodeInfo.buffs[buffId];
  11705. if (buff.owner == null && buff.value > value) {
  11706. id = buffId;
  11707. value = buff.value;
  11708. }
  11709. }
  11710. nodeInfo.buffs[id].owner = 'Я';
  11711. return id;
  11712. }
  11713.  
  11714. /**
  11715. * Collects a buff
  11716. *
  11717. * Собирает баф
  11718. */
  11719. async collectBuff(buff, path) {
  11720. this.callCollectBuff.name = this.actions[this.type].collectBuff;
  11721. this.callCollectBuff.args = { buff, path };
  11722. const calls = [this.callCollectBuff];
  11723. return Send(JSON.stringify({ calls }));
  11724. }
  11725.  
  11726. getNodeInfo(nodeId) {
  11727. return this.nodes.find(node => node.id == nodeId);
  11728. }
  11729.  
  11730. errorHandling(error, data) {
  11731. //console.error(error);
  11732. let errorInfo = error.toString() + '\n';
  11733. try {
  11734. const errorStack = error.stack.split('\n');
  11735. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testAdventure");
  11736. errorInfo += errorStack.slice(0, endStack).join('\n');
  11737. } catch (e) {
  11738. errorInfo += error.stack;
  11739. }
  11740. if (data) {
  11741. errorInfo += '\nData: ' + JSON.stringify(data);
  11742. }
  11743. copyText(errorInfo);
  11744. }
  11745.  
  11746. end() {
  11747. isCancalBattle = true;
  11748. setProgress(this.terminatеReason, true);
  11749. console.log(this.terminatеReason);
  11750. this.resolve();
  11751. }
  11752. }
  11753. class executeAdventure2 {
  11754.  
  11755. type = 'default';
  11756.  
  11757. actions = {
  11758. default: {
  11759. getInfo: "adventure_getInfo",
  11760. startBattle: 'adventure_turnStartBattle',
  11761. endBattle: 'adventure_endBattle',
  11762. collectBuff: 'adventure_turnCollectBuff'
  11763. },
  11764. solo: {
  11765. getInfo: "adventureSolo_getInfo",
  11766. startBattle: 'adventureSolo_turnStartBattle',
  11767. endBattle: 'adventureSolo_endBattle',
  11768. collectBuff: 'adventureSolo_turnCollectBuff'
  11769. }
  11770. }
  11771.  
  11772. terminatеReason = I18N('UNKNOWN');
  11773. callAdventureInfo = {
  11774. name: "adventure_getInfo",
  11775. args: {},
  11776. ident: "adventure_getInfo"
  11777. }
  11778. callTeamGetAll = {
  11779. name: "teamGetAll",
  11780. args: {},
  11781. ident: "teamGetAll"
  11782. }
  11783. callTeamGetFavor = {
  11784. name: "teamGetFavor",
  11785. args: {},
  11786. ident: "teamGetFavor"
  11787. }
  11788. callStartBattle = {
  11789. name: "adventure_turnStartBattle",
  11790. args: {},
  11791. ident: "body"
  11792. }
  11793. callEndBattle = {
  11794. name: "adventure_endBattle",
  11795. args: {
  11796. result: {},
  11797. progress: {},
  11798. },
  11799. ident: "body"
  11800. }
  11801. callCollectBuff = {
  11802. name: "adventure_turnCollectBuff",
  11803. args: {},
  11804. ident: "body"
  11805. }
  11806.  
  11807. constructor(resolve, reject) {
  11808. this.resolve = resolve;
  11809. this.reject = reject;
  11810. }
  11811.  
  11812. async start(type) {
  11813. this.type = type || this.type;
  11814. this.callAdventureInfo.name = this.actions[this.type].getInfo;
  11815. const data = await Send(JSON.stringify({
  11816. calls: [
  11817. this.callAdventureInfo,
  11818. this.callTeamGetAll,
  11819. this.callTeamGetFavor
  11820. ]
  11821. }));
  11822. return this.checkAdventureInfo(data.results);
  11823. }
  11824.  
  11825. async getPath() {
  11826. const oldVal = getSaveVal('adventurePath', '');
  11827. const keyPath = `adventurePath:${this.mapIdent}`;
  11828. const answer = await popup.confirm(I18N('ENTER_THE_PATH'), [
  11829. {
  11830. msg: I18N('START_ADVENTURE'),
  11831. placeholder: '1,2,3,4,5,6',
  11832. isInput: true,
  11833. default: getSaveVal(keyPath, oldVal)
  11834. },
  11835. {
  11836. msg: I18N('BTN_CANCEL'),
  11837. result: false,
  11838. isCancel: true
  11839. },
  11840. ]);
  11841. if (!answer) {
  11842. this.terminatеReason = I18N('BTN_CANCELED');
  11843. return false;
  11844. }
  11845.  
  11846. let path = answer.split(',');
  11847. if (path.length < 2) {
  11848. path = answer.split('-');
  11849. }
  11850. if (path.length < 2) {
  11851. this.terminatеReason = I18N('MUST_TWO_POINTS');
  11852. return false;
  11853. }
  11854.  
  11855. for (let p in path) {
  11856. path[p] = +path[p].trim()
  11857. if (Number.isNaN(path[p])) {
  11858. this.terminatеReason = I18N('MUST_ONLY_NUMBERS');
  11859. return false;
  11860. }
  11861. }
  11862. if (!this.checkPath(path)) {
  11863. return false;
  11864. }
  11865. setSaveVal(keyPath, answer);
  11866. return path;
  11867. }
  11868.  
  11869. checkPath(path) {
  11870. for (let i = 0; i < path.length - 1; i++) {
  11871. const currentPoint = path[i];
  11872. const nextPoint = path[i + 1];
  11873.  
  11874. const isValidPath = this.paths.some(p =>
  11875. (p.from_id === currentPoint && p.to_id === nextPoint) ||
  11876. (p.from_id === nextPoint && p.to_id === currentPoint)
  11877. );
  11878.  
  11879. if (!isValidPath) {
  11880. this.terminatеReason = I18N('INCORRECT_WAY', {
  11881. from: currentPoint,
  11882. to: nextPoint,
  11883. });
  11884. return false;
  11885. }
  11886. }
  11887.  
  11888. return true;
  11889. }
  11890.  
  11891. async checkAdventureInfo(data) {
  11892. this.advInfo = data[0].result.response;
  11893. if (!this.advInfo) {
  11894. this.terminatеReason = I18N('NOT_ON_AN_ADVENTURE') ;
  11895. return this.end();
  11896. }
  11897. const heroesTeam = data[1].result.response.adventure_hero;
  11898. const favor = data[2]?.result.response.adventure_hero;
  11899. const heroes = heroesTeam.slice(0, 5);
  11900. const pet = heroesTeam[5];
  11901. this.args = {
  11902. pet,
  11903. heroes,
  11904. favor,
  11905. path: [],
  11906. broadcast: false
  11907. }
  11908. const advUserInfo = this.advInfo.users[userInfo.id];
  11909. this.turnsLeft = advUserInfo.turnsLeft;
  11910. this.currentNode = advUserInfo.currentNode;
  11911. this.nodes = this.advInfo.nodes;
  11912. this.paths = this.advInfo.paths;
  11913. this.mapIdent = this.advInfo.mapIdent;
  11914.  
  11915. this.path = await this.getPath();
  11916. if (!this.path) {
  11917. return this.end();
  11918. }
  11919.  
  11920. if (this.currentNode == 1 && this.path[0] != 1) {
  11921. this.path.unshift(1);
  11922. }
  11923.  
  11924. return this.loop();
  11925. }
  11926.  
  11927. async loop() {
  11928. const position = this.path.indexOf(+this.currentNode);
  11929. if (!(~position)) {
  11930. this.terminatеReason = I18N('YOU_IN_NOT_ON_THE_WAY');
  11931. return this.end();
  11932. }
  11933. this.path = this.path.slice(position);
  11934. if ((this.path.length - 1) > this.turnsLeft &&
  11935. await popup.confirm(I18N('ATTEMPTS_NOT_ENOUGH'), [
  11936. { msg: I18N('YES_CONTINUE'), result: false },
  11937. { msg: I18N('BTN_NO'), result: true },
  11938. ])) {
  11939. this.terminatеReason = I18N('NOT_ENOUGH_AP');
  11940. return this.end();
  11941. }
  11942. const toPath = [];
  11943. for (const nodeId of this.path) {
  11944. if (!this.turnsLeft) {
  11945. this.terminatеReason = I18N('ATTEMPTS_ARE_OVER');
  11946. return this.end();
  11947. }
  11948. toPath.push(nodeId);
  11949. console.log(toPath);
  11950. if (toPath.length > 1) {
  11951. setProgress(toPath.join(' > ') + ` ${I18N('MOVES')}: ` + this.turnsLeft);
  11952. }
  11953. if (nodeId == this.currentNode) {
  11954. continue;
  11955. }
  11956.  
  11957. const nodeInfo = this.getNodeInfo(nodeId);
  11958. if (nodeInfo.type == 'TYPE_COMBAT') {
  11959. if (nodeInfo.state == 'empty') {
  11960. this.turnsLeft--;
  11961. continue;
  11962. }
  11963.  
  11964. /**
  11965. * Disable regular battle cancellation
  11966. *
  11967. * Отключаем штатную отменую боя
  11968. */
  11969. isCancalBattle = false;
  11970. if (await this.battle(toPath)) {
  11971. this.turnsLeft--;
  11972. toPath.splice(0, toPath.indexOf(nodeId));
  11973. nodeInfo.state = 'empty';
  11974. isCancalBattle = true;
  11975. continue;
  11976. }
  11977. isCancalBattle = true;
  11978. return this.end()
  11979. }
  11980.  
  11981. if (nodeInfo.type == 'TYPE_PLAYERBUFF') {
  11982. const buff = this.checkBuff(nodeInfo);
  11983. if (buff == null) {
  11984. continue;
  11985. }
  11986.  
  11987. if (await this.collectBuff(buff, toPath)) {
  11988. this.turnsLeft--;
  11989. toPath.splice(0, toPath.indexOf(nodeId));
  11990. continue;
  11991. }
  11992. this.terminatеReason = I18N('BUFF_GET_ERROR');
  11993. return this.end();
  11994. }
  11995. }
  11996. this.terminatеReason = I18N('SUCCESS');
  11997. return this.end();
  11998. }
  11999.  
  12000. /**
  12001. * Carrying out a fight
  12002. *
  12003. * Проведение боя
  12004. */
  12005. async battle(path, preCalc = true) {
  12006. const data = await this.startBattle(path);
  12007. try {
  12008. const battle = data.results[0].result.response.battle;
  12009. const result = await Calc(battle);
  12010. if (result.result.win) {
  12011. const info = await this.endBattle(result);
  12012. if (info.results[0].result.response?.error) {
  12013. this.terminatеReason = I18N('BATTLE_END_ERROR');
  12014. return false;
  12015. }
  12016. } else {
  12017. await this.cancelBattle(result);
  12018.  
  12019. if (preCalc && await this.preCalcBattle(battle)) {
  12020. path = path.slice(-2);
  12021. for (let i = 1; i <= getInput('countAutoBattle'); i++) {
  12022. setProgress(`${I18N('AUTOBOT')}: ${i}/${getInput('countAutoBattle')}`);
  12023. const result = await this.battle(path, false);
  12024. if (result) {
  12025. setProgress(I18N('VICTORY'));
  12026. return true;
  12027. }
  12028. }
  12029. this.terminatеReason = I18N('FAILED_TO_WIN_AUTO');
  12030. return false;
  12031. }
  12032. return false;
  12033. }
  12034. } catch (error) {
  12035. console.error(error);
  12036. if (await popup.confirm(I18N('ERROR_OF_THE_BATTLE_COPY'), [
  12037. { msg: I18N('BTN_NO'), result: false },
  12038. { msg: I18N('BTN_YES'), result: true },
  12039. ])) {
  12040. this.errorHandling(error, data);
  12041. }
  12042. this.terminatеReason = I18N('ERROR_DURING_THE_BATTLE');
  12043. return false;
  12044. }
  12045. return true;
  12046. }
  12047.  
  12048. /**
  12049. * Recalculate battles
  12050. *
  12051. * Прерасчтет битвы
  12052. */
  12053. async preCalcBattle(battle) {
  12054. const countTestBattle = getInput('countTestBattle');
  12055. for (let i = 0; i < countTestBattle; i++) {
  12056. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  12057. const result = await Calc(battle);
  12058. if (result.result.win) {
  12059. console.log(i, countTestBattle);
  12060. return true;
  12061. }
  12062. }
  12063. this.terminatеReason = I18N('NO_CHANCE_WIN') + countTestBattle;
  12064. return false;
  12065. }
  12066.  
  12067. /**
  12068. * Starts a fight
  12069. *
  12070. * Начинает бой
  12071. */
  12072. startBattle(path) {
  12073. this.args.path = path;
  12074. this.callStartBattle.name = this.actions[this.type].startBattle;
  12075. this.callStartBattle.args = this.args
  12076. const calls = [this.callStartBattle];
  12077. return Send(JSON.stringify({ calls }));
  12078. }
  12079.  
  12080. cancelBattle(battle) {
  12081. const fixBattle = function (heroes) {
  12082. for (const ids in heroes) {
  12083. const hero = heroes[ids];
  12084. hero.energy = random(1, 999);
  12085. if (hero.hp > 0) {
  12086. hero.hp = random(1, hero.hp);
  12087. }
  12088. }
  12089. }
  12090. fixBattle(battle.progress[0].attackers.heroes);
  12091. fixBattle(battle.progress[0].defenders.heroes);
  12092. return this.endBattle(battle);
  12093. }
  12094.  
  12095. /**
  12096. * Ends the fight
  12097. *
  12098. * Заканчивает бой
  12099. */
  12100. endBattle(battle) {
  12101. this.callEndBattle.name = this.actions[this.type].endBattle;
  12102. this.callEndBattle.args.result = battle.result
  12103. this.callEndBattle.args.progress = battle.progress
  12104. const calls = [this.callEndBattle];
  12105. return Send(JSON.stringify({ calls }));
  12106. }
  12107.  
  12108. /**
  12109. * Checks if you can get a buff
  12110. *
  12111. * Проверяет можно ли получить баф
  12112. */
  12113. checkBuff(nodeInfo) {
  12114. let id = null;
  12115. let value = 0;
  12116. for (const buffId in nodeInfo.buffs) {
  12117. const buff = nodeInfo.buffs[buffId];
  12118. if (buff.owner == null && buff.value > value) {
  12119. id = buffId;
  12120. value = buff.value;
  12121. }
  12122. }
  12123. nodeInfo.buffs[id].owner = 'Я';
  12124. return id;
  12125. }
  12126.  
  12127. /**
  12128. * Collects a buff
  12129. *
  12130. * Собирает баф
  12131. */
  12132. async collectBuff(buff, path) {
  12133. this.callCollectBuff.name = this.actions[this.type].collectBuff;
  12134. this.callCollectBuff.args = { buff, path };
  12135. const calls = [this.callCollectBuff];
  12136. return Send(JSON.stringify({ calls }));
  12137. }
  12138.  
  12139. getNodeInfo(nodeId) {
  12140. return this.nodes.find(node => node.id == nodeId);
  12141. }
  12142.  
  12143. errorHandling(error, data) {
  12144. //console.error(error);
  12145. let errorInfo = error.toString() + '\n';
  12146. try {
  12147. const errorStack = error.stack.split('\n');
  12148. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testAdventure");
  12149. errorInfo += errorStack.slice(0, endStack).join('\n');
  12150. } catch (e) {
  12151. errorInfo += error.stack;
  12152. }
  12153. if (data) {
  12154. errorInfo += '\nData: ' + JSON.stringify(data);
  12155. }
  12156. copyText(errorInfo);
  12157. }
  12158.  
  12159. end() {
  12160. isCancalBattle = true;
  12161. setProgress(this.terminatеReason, true);
  12162. console.log(this.terminatеReason);
  12163. this.resolve();
  12164. }
  12165. }
  12166. /**
  12167. * Passage of brawls
  12168. *
  12169. * Прохождение потасовок
  12170. */
  12171. function testBrawls(isAuto) {
  12172. return new Promise((resolve, reject) => {
  12173. const brawls = new executeBrawls(resolve, reject);
  12174. brawls.start(brawlsPack, isAuto);
  12175. });
  12176. }
  12177. /**
  12178. * Passage of brawls
  12179. *
  12180. * Прохождение потасовок
  12181. */
  12182. class executeBrawls {
  12183. callBrawlQuestGetInfo = {
  12184. name: "brawl_questGetInfo",
  12185. args: {},
  12186. ident: "brawl_questGetInfo"
  12187. }
  12188. callBrawlFindEnemies = {
  12189. name: "brawl_findEnemies",
  12190. args: {},
  12191. ident: "brawl_findEnemies"
  12192. }
  12193. callBrawlQuestFarm = {
  12194. name: "brawl_questFarm",
  12195. args: {},
  12196. ident: "brawl_questFarm"
  12197. }
  12198. callUserGetInfo = {
  12199. name: "userGetInfo",
  12200. args: {},
  12201. ident: "userGetInfo"
  12202. }
  12203. callTeamGetMaxUpgrade = {
  12204. name: "teamGetMaxUpgrade",
  12205. args: {},
  12206. ident: "teamGetMaxUpgrade"
  12207. }
  12208. callBrawlGetInfo = {
  12209. name: "brawl_getInfo",
  12210. args: {},
  12211. ident: "brawl_getInfo"
  12212. }
  12213.  
  12214. stats = {
  12215. win: 0,
  12216. loss: 0,
  12217. count: 0,
  12218. }
  12219.  
  12220. stage = {
  12221. '3': 1,
  12222. '7': 2,
  12223. '12': 3,
  12224. }
  12225.  
  12226. attempts = 0;
  12227.  
  12228. constructor(resolve, reject) {
  12229. this.resolve = resolve;
  12230. this.reject = reject;
  12231. const allHeroIds = Object.keys(lib.getData('hero'));
  12232. this.callTeamGetMaxUpgrade.args.units = {
  12233. hero: allHeroIds.filter((id) => +id < 1000),
  12234. titan: allHeroIds.filter((id) => +id >= 4000 && +id < 4100),
  12235. pet: allHeroIds.filter((id) => +id >= 6000 && +id < 6100),
  12236. };
  12237. }
  12238.  
  12239. async start(args, isAuto) {
  12240. this.isAuto = isAuto;
  12241. this.args = args;
  12242. isCancalBattle = false;
  12243. this.brawlInfo = await this.getBrawlInfo();
  12244. this.attempts = this.brawlInfo.attempts;
  12245.  
  12246. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  12247. this.end(I18N('DONT_HAVE_LIVES'));
  12248. return;
  12249. }
  12250.  
  12251. while (1) {
  12252. if (!isBrawlsAutoStart) {
  12253. this.end(I18N('BTN_CANCELED'));
  12254. return;
  12255. }
  12256.  
  12257. const maxStage = this.brawlInfo.questInfo.stage;
  12258. const stage = this.stage[maxStage];
  12259. const progress = this.brawlInfo.questInfo.progress;
  12260.  
  12261. setProgress(
  12262. `${I18N('STAGE')} ${stage}: ${progress}/${maxStage}<br>${I18N('FIGHTS')}: ${this.stats.count}<br>${I18N('WINS')}: ${
  12263. this.stats.win
  12264. }<br>${I18N('LOSSES')}: ${this.stats.loss}<br>${I18N('LIVES')}: ${this.attempts}<br>${I18N('STOP')}`,
  12265. false,
  12266. function () {
  12267. isBrawlsAutoStart = false;
  12268. }
  12269. );
  12270.  
  12271. if (this.brawlInfo.questInfo.canFarm) {
  12272. const result = await this.questFarm();
  12273. console.log(result);
  12274. }
  12275.  
  12276. if (!this.continueAttack && this.brawlInfo.questInfo.stage == 12 && this.brawlInfo.questInfo.progress == 12) {
  12277. if (
  12278. await popup.confirm(I18N('BRAWL_DAILY_TASK_COMPLETED'), [
  12279. { msg: I18N('BTN_NO'), result: true },
  12280. { msg: I18N('BTN_YES'), result: false },
  12281. ])
  12282. ) {
  12283. this.end(I18N('SUCCESS'));
  12284. return;
  12285. } else {
  12286. this.continueAttack = true;
  12287. }
  12288. }
  12289.  
  12290. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  12291. this.end(I18N('DONT_HAVE_LIVES'))
  12292. return;
  12293. }
  12294.  
  12295. const enemie = Object.values(this.brawlInfo.findEnemies).shift();
  12296.  
  12297. // Автоматический подбор пачки
  12298. if (this.isAuto) {
  12299. if (this.mandatoryId <= 4000 && this.mandatoryId != 13) {
  12300. this.end(I18N('BRAWL_AUTO_PACK_NOT_CUR_HERO'));
  12301. return;
  12302. }
  12303. if (this.mandatoryId >= 4000 && this.mandatoryId < 4100) {
  12304. this.args = await this.updateTitanPack(enemie.heroes);
  12305. } else if (this.mandatoryId < 4000 && this.mandatoryId == 13) {
  12306. this.args = await this.updateHeroesPack(enemie.heroes);
  12307. }
  12308. }
  12309.  
  12310. const result = await this.battle(enemie.userId);
  12311. this.brawlInfo = {
  12312. questInfo: result[1].result.response,
  12313. findEnemies: result[2].result.response,
  12314. };
  12315. }
  12316. }
  12317.  
  12318. async updateTitanPack(enemieHeroes) {
  12319. const packs = [
  12320. [4033, 4040, 4041, 4042, 4043],
  12321. [4032, 4040, 4041, 4042, 4043],
  12322. [4031, 4040, 4041, 4042, 4043],
  12323. [4030, 4040, 4041, 4042, 4043],
  12324. [4032, 4033, 4040, 4042, 4043],
  12325. [4030, 4033, 4041, 4042, 4043],
  12326. [4031, 4033, 4040, 4042, 4043],
  12327. [4032, 4033, 4040, 4041, 4043],
  12328. [4023, 4040, 4041, 4042, 4043],
  12329. [4030, 4033, 4040, 4042, 4043],
  12330. [4031, 4033, 4040, 4041, 4043],
  12331. [4022, 4040, 4041, 4042, 4043],
  12332. [4030, 4033, 4040, 4041, 4043],
  12333. [4021, 4040, 4041, 4042, 4043],
  12334. [4020, 4040, 4041, 4042, 4043],
  12335. [4023, 4033, 4040, 4042, 4043],
  12336. [4030, 4032, 4033, 4042, 4043],
  12337. [4023, 4033, 4040, 4041, 4043],
  12338. [4031, 4032, 4033, 4040, 4043],
  12339. [4030, 4032, 4033, 4041, 4043],
  12340. [4030, 4031, 4033, 4042, 4043],
  12341. [4013, 4040, 4041, 4042, 4043],
  12342. [4030, 4032, 4033, 4040, 4043],
  12343. [4030, 4031, 4033, 4041, 4043],
  12344. [4012, 4040, 4041, 4042, 4043],
  12345. [4030, 4031, 4033, 4040, 4043],
  12346. [4011, 4040, 4041, 4042, 4043],
  12347. [4010, 4040, 4041, 4042, 4043],
  12348. [4023, 4032, 4033, 4042, 4043],
  12349. [4022, 4032, 4033, 4042, 4043],
  12350. [4023, 4032, 4033, 4041, 4043],
  12351. [4021, 4032, 4033, 4042, 4043],
  12352. [4022, 4032, 4033, 4041, 4043],
  12353. [4023, 4030, 4033, 4042, 4043],
  12354. [4023, 4032, 4033, 4040, 4043],
  12355. [4013, 4033, 4040, 4042, 4043],
  12356. [4020, 4032, 4033, 4042, 4043],
  12357. [4021, 4032, 4033, 4041, 4043],
  12358. [4022, 4030, 4033, 4042, 4043],
  12359. [4022, 4032, 4033, 4040, 4043],
  12360. [4023, 4030, 4033, 4041, 4043],
  12361. [4023, 4031, 4033, 4040, 4043],
  12362. [4013, 4033, 4040, 4041, 4043],
  12363. [4020, 4031, 4033, 4042, 4043],
  12364. [4020, 4032, 4033, 4041, 4043],
  12365. [4021, 4030, 4033, 4042, 4043],
  12366. [4021, 4032, 4033, 4040, 4043],
  12367. [4022, 4030, 4033, 4041, 4043],
  12368. [4022, 4031, 4033, 4040, 4043],
  12369. [4023, 4030, 4033, 4040, 4043],
  12370. [4030, 4031, 4032, 4033, 4043],
  12371. [4003, 4040, 4041, 4042, 4043],
  12372. [4020, 4030, 4033, 4042, 4043],
  12373. [4020, 4031, 4033, 4041, 4043],
  12374. [4020, 4032, 4033, 4040, 4043],
  12375. [4021, 4030, 4033, 4041, 4043],
  12376. [4021, 4031, 4033, 4040, 4043],
  12377. [4022, 4030, 4033, 4040, 4043],
  12378. [4030, 4031, 4032, 4033, 4042],
  12379. [4002, 4040, 4041, 4042, 4043],
  12380. [4020, 4030, 4033, 4041, 4043],
  12381. [4020, 4031, 4033, 4040, 4043],
  12382. [4021, 4030, 4033, 4040, 4043],
  12383. [4030, 4031, 4032, 4033, 4041],
  12384. [4001, 4040, 4041, 4042, 4043],
  12385. [4030, 4031, 4032, 4033, 4040],
  12386. [4000, 4040, 4041, 4042, 4043],
  12387. [4013, 4032, 4033, 4042, 4043],
  12388. [4012, 4032, 4033, 4042, 4043],
  12389. [4013, 4032, 4033, 4041, 4043],
  12390. [4023, 4031, 4032, 4033, 4043],
  12391. [4011, 4032, 4033, 4042, 4043],
  12392. [4012, 4032, 4033, 4041, 4043],
  12393. [4013, 4030, 4033, 4042, 4043],
  12394. [4013, 4032, 4033, 4040, 4043],
  12395. [4023, 4030, 4032, 4033, 4043],
  12396. [4003, 4033, 4040, 4042, 4043],
  12397. [4013, 4023, 4040, 4042, 4043],
  12398. [4010, 4032, 4033, 4042, 4043],
  12399. [4011, 4032, 4033, 4041, 4043],
  12400. [4012, 4030, 4033, 4042, 4043],
  12401. [4012, 4032, 4033, 4040, 4043],
  12402. [4013, 4030, 4033, 4041, 4043],
  12403. [4013, 4031, 4033, 4040, 4043],
  12404. [4023, 4030, 4031, 4033, 4043],
  12405. [4003, 4033, 4040, 4041, 4043],
  12406. [4013, 4023, 4040, 4041, 4043],
  12407. [4010, 4031, 4033, 4042, 4043],
  12408. [4010, 4032, 4033, 4041, 4043],
  12409. [4011, 4030, 4033, 4042, 4043],
  12410. [4011, 4032, 4033, 4040, 4043],
  12411. [4012, 4030, 4033, 4041, 4043],
  12412. [4012, 4031, 4033, 4040, 4043],
  12413. [4013, 4030, 4033, 4040, 4043],
  12414. [4010, 4030, 4033, 4042, 4043],
  12415. [4010, 4031, 4033, 4041, 4043],
  12416. [4010, 4032, 4033, 4040, 4043],
  12417. [4011, 4030, 4033, 4041, 4043],
  12418. [4011, 4031, 4033, 4040, 4043],
  12419. [4012, 4030, 4033, 4040, 4043],
  12420. [4010, 4030, 4033, 4041, 4043],
  12421. [4010, 4031, 4033, 4040, 4043],
  12422. [4011, 4030, 4033, 4040, 4043],
  12423. [4003, 4032, 4033, 4042, 4043],
  12424. [4002, 4032, 4033, 4042, 4043],
  12425. [4003, 4032, 4033, 4041, 4043],
  12426. [4013, 4031, 4032, 4033, 4043],
  12427. [4001, 4032, 4033, 4042, 4043],
  12428. [4002, 4032, 4033, 4041, 4043],
  12429. [4003, 4030, 4033, 4042, 4043],
  12430. [4003, 4032, 4033, 4040, 4043],
  12431. [4013, 4030, 4032, 4033, 4043],
  12432. [4003, 4023, 4040, 4042, 4043],
  12433. [4000, 4032, 4033, 4042, 4043],
  12434. [4001, 4032, 4033, 4041, 4043],
  12435. [4002, 4030, 4033, 4042, 4043],
  12436. [4002, 4032, 4033, 4040, 4043],
  12437. [4003, 4030, 4033, 4041, 4043],
  12438. [4003, 4031, 4033, 4040, 4043],
  12439. [4020, 4022, 4023, 4042, 4043],
  12440. [4013, 4030, 4031, 4033, 4043],
  12441. [4003, 4023, 4040, 4041, 4043],
  12442. [4000, 4031, 4033, 4042, 4043],
  12443. [4000, 4032, 4033, 4041, 4043],
  12444. [4001, 4030, 4033, 4042, 4043],
  12445. [4001, 4032, 4033, 4040, 4043],
  12446. [4002, 4030, 4033, 4041, 4043],
  12447. [4002, 4031, 4033, 4040, 4043],
  12448. [4003, 4030, 4033, 4040, 4043],
  12449. [4021, 4022, 4023, 4040, 4043],
  12450. [4020, 4022, 4023, 4041, 4043],
  12451. [4020, 4021, 4023, 4042, 4043],
  12452. [4023, 4030, 4031, 4032, 4033],
  12453. [4000, 4030, 4033, 4042, 4043],
  12454. [4000, 4031, 4033, 4041, 4043],
  12455. [4000, 4032, 4033, 4040, 4043],
  12456. [4001, 4030, 4033, 4041, 4043],
  12457. [4001, 4031, 4033, 4040, 4043],
  12458. [4002, 4030, 4033, 4040, 4043],
  12459. [4020, 4022, 4023, 4040, 4043],
  12460. [4020, 4021, 4023, 4041, 4043],
  12461. [4022, 4030, 4031, 4032, 4033],
  12462. [4000, 4030, 4033, 4041, 4043],
  12463. [4000, 4031, 4033, 4040, 4043],
  12464. [4001, 4030, 4033, 4040, 4043],
  12465. [4020, 4021, 4023, 4040, 4043],
  12466. [4021, 4030, 4031, 4032, 4033],
  12467. [4020, 4030, 4031, 4032, 4033],
  12468. [4003, 4031, 4032, 4033, 4043],
  12469. [4020, 4022, 4023, 4033, 4043],
  12470. [4003, 4030, 4032, 4033, 4043],
  12471. [4003, 4013, 4040, 4042, 4043],
  12472. [4020, 4021, 4023, 4033, 4043],
  12473. [4003, 4030, 4031, 4033, 4043],
  12474. [4003, 4013, 4040, 4041, 4043],
  12475. [4013, 4030, 4031, 4032, 4033],
  12476. [4012, 4030, 4031, 4032, 4033],
  12477. [4011, 4030, 4031, 4032, 4033],
  12478. [4010, 4030, 4031, 4032, 4033],
  12479. [4013, 4023, 4031, 4032, 4033],
  12480. [4013, 4023, 4030, 4032, 4033],
  12481. [4020, 4022, 4023, 4032, 4033],
  12482. [4013, 4023, 4030, 4031, 4033],
  12483. [4021, 4022, 4023, 4030, 4033],
  12484. [4020, 4022, 4023, 4031, 4033],
  12485. [4020, 4021, 4023, 4032, 4033],
  12486. [4020, 4021, 4022, 4023, 4043],
  12487. [4003, 4030, 4031, 4032, 4033],
  12488. [4020, 4022, 4023, 4030, 4033],
  12489. [4020, 4021, 4023, 4031, 4033],
  12490. [4020, 4021, 4022, 4023, 4042],
  12491. [4002, 4030, 4031, 4032, 4033],
  12492. [4020, 4021, 4023, 4030, 4033],
  12493. [4020, 4021, 4022, 4023, 4041],
  12494. [4001, 4030, 4031, 4032, 4033],
  12495. [4020, 4021, 4022, 4023, 4040],
  12496. [4000, 4030, 4031, 4032, 4033],
  12497. [4003, 4023, 4031, 4032, 4033],
  12498. [4013, 4020, 4022, 4023, 4043],
  12499. [4003, 4023, 4030, 4032, 4033],
  12500. [4010, 4012, 4013, 4042, 4043],
  12501. [4013, 4020, 4021, 4023, 4043],
  12502. [4003, 4023, 4030, 4031, 4033],
  12503. [4011, 4012, 4013, 4040, 4043],
  12504. [4010, 4012, 4013, 4041, 4043],
  12505. [4010, 4011, 4013, 4042, 4043],
  12506. [4020, 4021, 4022, 4023, 4033],
  12507. [4010, 4012, 4013, 4040, 4043],
  12508. [4010, 4011, 4013, 4041, 4043],
  12509. [4020, 4021, 4022, 4023, 4032],
  12510. [4010, 4011, 4013, 4040, 4043],
  12511. [4020, 4021, 4022, 4023, 4031],
  12512. [4020, 4021, 4022, 4023, 4030],
  12513. [4003, 4013, 4031, 4032, 4033],
  12514. [4010, 4012, 4013, 4033, 4043],
  12515. [4003, 4020, 4022, 4023, 4043],
  12516. [4013, 4020, 4022, 4023, 4033],
  12517. [4003, 4013, 4030, 4032, 4033],
  12518. [4010, 4011, 4013, 4033, 4043],
  12519. [4003, 4020, 4021, 4023, 4043],
  12520. [4013, 4020, 4021, 4023, 4033],
  12521. [4003, 4013, 4030, 4031, 4033],
  12522. [4010, 4012, 4013, 4023, 4043],
  12523. [4003, 4020, 4022, 4023, 4033],
  12524. [4010, 4012, 4013, 4032, 4033],
  12525. [4010, 4011, 4013, 4023, 4043],
  12526. [4003, 4020, 4021, 4023, 4033],
  12527. [4011, 4012, 4013, 4030, 4033],
  12528. [4010, 4012, 4013, 4031, 4033],
  12529. [4010, 4011, 4013, 4032, 4033],
  12530. [4013, 4020, 4021, 4022, 4023],
  12531. [4010, 4012, 4013, 4030, 4033],
  12532. [4010, 4011, 4013, 4031, 4033],
  12533. [4012, 4020, 4021, 4022, 4023],
  12534. [4010, 4011, 4013, 4030, 4033],
  12535. [4011, 4020, 4021, 4022, 4023],
  12536. [4010, 4020, 4021, 4022, 4023],
  12537. [4010, 4012, 4013, 4023, 4033],
  12538. [4000, 4002, 4003, 4042, 4043],
  12539. [4010, 4011, 4013, 4023, 4033],
  12540. [4001, 4002, 4003, 4040, 4043],
  12541. [4000, 4002, 4003, 4041, 4043],
  12542. [4000, 4001, 4003, 4042, 4043],
  12543. [4010, 4011, 4012, 4013, 4043],
  12544. [4003, 4020, 4021, 4022, 4023],
  12545. [4000, 4002, 4003, 4040, 4043],
  12546. [4000, 4001, 4003, 4041, 4043],
  12547. [4010, 4011, 4012, 4013, 4042],
  12548. [4002, 4020, 4021, 4022, 4023],
  12549. [4000, 4001, 4003, 4040, 4043],
  12550. [4010, 4011, 4012, 4013, 4041],
  12551. [4001, 4020, 4021, 4022, 4023],
  12552. [4010, 4011, 4012, 4013, 4040],
  12553. [4000, 4020, 4021, 4022, 4023],
  12554. [4001, 4002, 4003, 4033, 4043],
  12555. [4000, 4002, 4003, 4033, 4043],
  12556. [4003, 4010, 4012, 4013, 4043],
  12557. [4003, 4013, 4020, 4022, 4023],
  12558. [4000, 4001, 4003, 4033, 4043],
  12559. [4003, 4010, 4011, 4013, 4043],
  12560. [4003, 4013, 4020, 4021, 4023],
  12561. [4010, 4011, 4012, 4013, 4033],
  12562. [4010, 4011, 4012, 4013, 4032],
  12563. [4010, 4011, 4012, 4013, 4031],
  12564. [4010, 4011, 4012, 4013, 4030],
  12565. [4001, 4002, 4003, 4023, 4043],
  12566. [4000, 4002, 4003, 4023, 4043],
  12567. [4003, 4010, 4012, 4013, 4033],
  12568. [4000, 4002, 4003, 4032, 4033],
  12569. [4000, 4001, 4003, 4023, 4043],
  12570. [4003, 4010, 4011, 4013, 4033],
  12571. [4001, 4002, 4003, 4030, 4033],
  12572. [4000, 4002, 4003, 4031, 4033],
  12573. [4000, 4001, 4003, 4032, 4033],
  12574. [4010, 4011, 4012, 4013, 4023],
  12575. [4000, 4002, 4003, 4030, 4033],
  12576. [4000, 4001, 4003, 4031, 4033],
  12577. [4010, 4011, 4012, 4013, 4022],
  12578. [4000, 4001, 4003, 4030, 4033],
  12579. [4010, 4011, 4012, 4013, 4021],
  12580. [4010, 4011, 4012, 4013, 4020],
  12581. [4001, 4002, 4003, 4013, 4043],
  12582. [4001, 4002, 4003, 4023, 4033],
  12583. [4000, 4002, 4003, 4013, 4043],
  12584. [4000, 4002, 4003, 4023, 4033],
  12585. [4003, 4010, 4012, 4013, 4023],
  12586. [4000, 4001, 4003, 4013, 4043],
  12587. [4000, 4001, 4003, 4023, 4033],
  12588. [4003, 4010, 4011, 4013, 4023],
  12589. [4001, 4002, 4003, 4013, 4033],
  12590. [4000, 4002, 4003, 4013, 4033],
  12591. [4000, 4001, 4003, 4013, 4033],
  12592. [4000, 4001, 4002, 4003, 4043],
  12593. [4003, 4010, 4011, 4012, 4013],
  12594. [4000, 4001, 4002, 4003, 4042],
  12595. [4002, 4010, 4011, 4012, 4013],
  12596. [4000, 4001, 4002, 4003, 4041],
  12597. [4001, 4010, 4011, 4012, 4013],
  12598. [4000, 4001, 4002, 4003, 4040],
  12599. [4000, 4010, 4011, 4012, 4013],
  12600. [4001, 4002, 4003, 4013, 4023],
  12601. [4000, 4002, 4003, 4013, 4023],
  12602. [4000, 4001, 4003, 4013, 4023],
  12603. [4000, 4001, 4002, 4003, 4033],
  12604. [4000, 4001, 4002, 4003, 4032],
  12605. [4000, 4001, 4002, 4003, 4031],
  12606. [4000, 4001, 4002, 4003, 4030],
  12607. [4000, 4001, 4002, 4003, 4023],
  12608. [4000, 4001, 4002, 4003, 4022],
  12609. [4000, 4001, 4002, 4003, 4021],
  12610. [4000, 4001, 4002, 4003, 4020],
  12611. [4000, 4001, 4002, 4003, 4013],
  12612. [4000, 4001, 4002, 4003, 4012],
  12613. [4000, 4001, 4002, 4003, 4011],
  12614. [4000, 4001, 4002, 4003, 4010],
  12615. ].filter((p) => p.includes(this.mandatoryId));
  12616. const bestPack = {
  12617. pack: packs[0],
  12618. winRate: 0,
  12619. countBattle: 0,
  12620. id: 0,
  12621. };
  12622. for (const id in packs) {
  12623. const pack = packs[id];
  12624. const attackers = this.maxUpgrade.filter((e) => pack.includes(e.id)).reduce((obj, e) => ({ ...obj, [e.id]: e }), {});
  12625. const battle = {
  12626. attackers,
  12627. defenders: [enemieHeroes],
  12628. type: 'brawl_titan',
  12629. };
  12630. const isRandom = this.isRandomBattle(battle);
  12631. const stat = {
  12632. count: 0,
  12633. win: 0,
  12634. winRate: 0,
  12635. };
  12636. for (let i = 1; i <= 20; i++) {
  12637. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  12638. const result = await Calc(battle);
  12639. stat.win += result.result.win;
  12640. stat.count += 1;
  12641. stat.winRate = stat.win / stat.count;
  12642. if (!isRandom || (i >= 2 && stat.winRate < 0.65) || (i >= 10 && stat.winRate == 1)) {
  12643. break;
  12644. }
  12645. }
  12646. if (!isRandom && stat.win) {
  12647. return {
  12648. favor: {},
  12649. heroes: pack,
  12650. };
  12651. }
  12652. if (stat.winRate > 0.85) {
  12653. return {
  12654. favor: {},
  12655. heroes: pack,
  12656. };
  12657. }
  12658. if (stat.winRate > bestPack.winRate) {
  12659. bestPack.countBattle = stat.count;
  12660. bestPack.winRate = stat.winRate;
  12661. bestPack.pack = pack;
  12662. bestPack.id = id;
  12663. }
  12664. }
  12665. //console.log(bestPack.id, bestPack.pack, bestPack.winRate, bestPack.countBattle);
  12666. return {
  12667. favor: {},
  12668. heroes: bestPack.pack,
  12669. };
  12670. }
  12671. isRandomPack(pack) {
  12672. const ids = Object.keys(pack);
  12673. return ids.includes('4023') || ids.includes('4021');
  12674. }
  12675. isRandomBattle(battle) {
  12676. return this.isRandomPack(battle.attackers) || this.isRandomPack(battle.defenders[0]);
  12677. }
  12678. async updateHeroesPack(enemieHeroes) {
  12679. const packs = [{id:1,args:{userId:-830021,heroes:[63,13,9,48,1],pet:6006,favor:{1:6004,9:6005,13:6002,48:6e3,63:6009}},attackers:{1:{id:1,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{2:130,3:130,4:130,5:130,6022:130,8268:1,8269:1},power:198058,star:6,runes:[43750,43750,43750,43750,43750],skins:{1:60,54:60,95:60,154:60,250:60,325:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[4,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3093,hp:419649,intelligence:3644,physicalAttack:11481.6,strength:17049,armor:12720,dodge:17232.28,magicPenetration:22780,magicPower:55816,magicResist:1580,modifiedSkillTier:5,skin:0,favorPetId:6004,favorPower:11064},9:{id:9,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{335:130,336:130,337:130,338:130,6027:130,8270:1,8271:1},power:195886,star:6,runes:[43750,43750,43750,43750,43750],skins:{9:60,41:60,163:60,189:60,311:60,338:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6005,type:"hero",perks:[7,2,20],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3068,hp:227134,intelligence:19003,physicalAttack:7020.32,strength:3068,armor:19995,dodge:14644,magicPower:64780.6,magicResist:31597,modifiedSkillTier:5,skin:0,favorPetId:6005,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6012:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:19060,magicPenetration:58138.6,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6002,favorPower:11064},48:{id:48,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{240:130,241:130,242:130,243:130,6002:130},power:190584,star:6,runes:[43750,43750,43750,43750,43750],skins:{103:60,165:60,217:60,296:60,326:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6e3,type:"hero",perks:[5,2],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:17308,hp:397737,intelligence:2888,physicalAttack:40298.32,physicalCritChance:12280,strength:3169,armor:12185,armorPenetration:20137.6,magicResist:24816,skin:0,favorPetId:6e3,favorPower:11064},63:{id:63,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{442:130,443:130,444:130,445:130,6041:130,8272:1,8273:1},power:193520,star:6,runes:[43750,43750,43750,43750,43750],skins:{341:60,350:60,351:60,352:1},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6009,type:"hero",perks:[6,1,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:17931,hp:488832,intelligence:2737,physicalAttack:54213.6,strength:2877,armor:800,armorPenetration:32477.6,magicResist:8526,physicalCritChance:9545,modifiedSkillTier:3,skin:0,favorPetId:6009,favorPower:11064},6006:{id:6006,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6030:130,6031:130},power:181943,type:"pet",perks:[5,9],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}},{id:2,args:{userId:-830049,heroes:[46,13,52,49,4],pet:6006,favor:{4:6001,13:6002,46:6006,49:6004,52:6003}},attackers:{4:{id:4,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{255:130,256:130,257:130,258:130,6007:130},power:189782,star:6,runes:[43750,43750,43750,43750,43750],skins:{4:60,35:60,92:60,161:60,236:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6001,type:"hero",perks:[4,5,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:3065,hp:482631,intelligence:3402,physicalAttack:2800,strength:17488,armor:56262.6,magicPower:51021,magicResist:36971,skin:0,favorPetId:6001,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6012:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:19060,magicPenetration:58138.6,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6002,favorPower:11064},46:{id:46,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{230:130,231:130,232:130,233:130,6032:130},power:189653,star:6,runes:[43750,43750,43750,43750,43750],skins:{101:60,159:60,178:60,262:60,315:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[9,5,1,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2122,hp:637517,intelligence:16208,physicalAttack:50,strength:5151,armor:38507.6,magicPower:74495.6,magicResist:22237,skin:0,favorPetId:6006,favorPower:11064},49:{id:49,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{245:130,246:130,247:130,248:130,6022:130},power:193163,star:6,runes:[43750,43750,43750,43750,43750],skins:{104:60,191:60,252:60,305:60,329:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[10,1,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:17935,hp:250405,intelligence:2790,physicalAttack:40413.6,strength:2987,armor:11655,dodge:14844.28,magicResist:3175,physicalCritChance:14135,skin:0,favorPetId:6004,favorPower:11064},52:{id:52,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{310:130,311:130,312:130,313:130,6017:130},power:185075,star:6,runes:[43750,43750,43750,43750,43750],skins:{188:60,213:60,248:60,297:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6003,type:"hero",perks:[5,8,2,13,15,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:18270,hp:226207,intelligence:2620,physicalAttack:44206,strength:3260,armor:13150,armorPenetration:40301,magicPower:9957.6,magicResist:33892.6,skin:0,favorPetId:6003,favorPower:11064},6006:{id:6006,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6030:130,6031:130},power:181943,type:"pet",perks:[5,9],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}},{id:3,args:{userId:8263225,heroes:[29,63,13,48,1],pet:6006,favor:{1:6004,13:6002,29:6006,48:6e3,63:6003}},attackers:{1:{id:1,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{2:130,3:130,4:130,5:130,6022:130,8268:1,8269:1},power:198058,star:6,runes:[43750,43750,43750,43750,43750],skins:{1:60,54:60,95:60,154:60,250:60,325:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[4,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3093,hp:419649,intelligence:3644,physicalAttack:11481.6,strength:17049,armor:12720,dodge:17232.28,magicPenetration:22780,magicPower:55816,magicResist:1580,modifiedSkillTier:5,skin:0,favorPetId:6004,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6012:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:19060,magicPenetration:58138.6,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6002,favorPower:11064},29:{id:29,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{145:130,146:130,147:130,148:130,6032:130},power:189790,star:6,runes:[43750,43750,43750,43750,43750],skins:{29:60,72:60,88:60,147:60,242:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[9,5,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2885,hp:491431,intelligence:18331,physicalAttack:106,strength:3020,armor:37716.6,magicPower:76792.6,magicResist:31377,skin:0,favorPetId:6006,favorPower:11064},48:{id:48,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{240:130,241:130,242:130,243:130,6002:130},power:190584,star:6,runes:[43750,43750,43750,43750,43750],skins:{103:60,165:60,217:60,296:60,326:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6e3,type:"hero",perks:[5,2],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:17308,hp:397737,intelligence:2888,physicalAttack:40298.32,physicalCritChance:12280,strength:3169,armor:12185,armorPenetration:20137.6,magicResist:24816,skin:0,favorPetId:6e3,favorPower:11064},63:{id:63,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{442:130,443:130,444:130,445:130,6017:130,8272:1,8273:1},power:191031,star:6,runes:[43750,43750,43750,43750,43750],skins:{341:60,350:60,351:60,352:1},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6003,type:"hero",perks:[6,1,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:17931,hp:488832,intelligence:2737,physicalAttack:44256,strength:2877,armor:800,armorPenetration:22520,magicPower:9957.6,magicResist:18483.6,physicalCritChance:9545,modifiedSkillTier:3,skin:0,favorPetId:6003,favorPower:11064},6006:{id:6006,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6030:130,6031:130},power:181943,type:"pet",perks:[5,9],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}},{id:4,args:{userId:8263247,heroes:[55,13,40,51,1],pet:6006,favor:{1:6007,13:6002,40:6004,51:6006,55:6001}},attackers:{1:{id:1,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{2:130,3:130,4:130,5:130,6035:130,8268:1,8269:1},power:195170,star:6,runes:[43750,43750,43750,43750,43750],skins:{1:60,54:60,95:60,154:60,250:60,325:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6007,type:"hero",perks:[4,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3093,hp:419649,intelligence:3644,physicalAttack:1524,strength:17049,armor:22677.6,dodge:14245,magicPenetration:22780,magicPower:65773.6,magicResist:1580,modifiedSkillTier:5,skin:0,favorPetId:6007,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6012:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:19060,magicPenetration:58138.6,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6002,favorPower:11064},40:{id:40,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{200:130,201:130,202:130,203:130,6022:130,8244:1,8245:1},power:192541,star:6,runes:[43750,43750,43750,43750,43750],skins:{53:60,89:60,129:60,168:60,314:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[5,9,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:17540,hp:343191,intelligence:2805,physicalAttack:48430.6,strength:2976,armor:24410,dodge:15732.28,magicResist:17633,modifiedSkillTier:3,skin:0,favorPetId:6004,favorPower:11064},51:{id:51,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{305:130,306:130,307:130,308:130,6032:130},power:190005,star:6,runes:[43750,43750,43750,43750,43750],skins:{181:60,219:60,260:60,290:60,334:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[5,9,1,12],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2526,hp:438205,intelligence:18851,physicalAttack:50,strength:2921,armor:39442.6,magicPower:88978.6,magicResist:22960,skin:0,favorPetId:6006,favorPower:11064},55:{id:55,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{325:130,326:130,327:130,328:130,6007:130},power:190529,star:6,runes:[43750,43750,43750,43750,43750],skins:{239:60,278:60,309:60,327:60,346:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6001,type:"hero",perks:[7,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2631,hp:499591,intelligence:19438,physicalAttack:50,strength:3286,armor:32892.6,armorPenetration:36870,magicPower:60704,magicResist:10010,skin:0,favorPetId:6001,favorPower:11064},6006:{id:6006,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6030:130,6031:130},power:181943,type:"pet",perks:[5,9],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}},{id:5,args:{userId:8263303,heroes:[31,29,13,40,1],pet:6004,favor:{1:6001,13:6007,29:6002,31:6006,40:6004}},attackers:{1:{id:1,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{2:130,3:130,4:130,5:130,6007:130,8268:1,8269:1},power:195170,star:6,runes:[43750,43750,43750,43750,43750],skins:{1:60,54:60,95:60,154:60,250:60,325:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6001,type:"hero",perks:[4,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3093,hp:519225,intelligence:3644,physicalAttack:1524,strength:17049,armor:22677.6,dodge:14245,magicPenetration:22780,magicPower:55816,magicResist:1580,modifiedSkillTier:5,skin:0,favorPetId:6001,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6035:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6007,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:29017.6,magicPenetration:48181,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6007,favorPower:11064},29:{id:29,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{145:130,146:130,147:130,148:130,6012:130},power:189790,star:6,runes:[43750,43750,43750,43750,43750],skins:{29:60,72:60,88:60,147:60,242:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[9,5,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2885,hp:491431,intelligence:18331,physicalAttack:106,strength:3020,armor:27759,magicPenetration:9957.6,magicPower:76792.6,magicResist:31377,skin:0,favorPetId:6002,favorPower:11064},31:{id:31,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{155:130,156:130,157:130,158:130,6032:130},power:190305,star:6,runes:[43750,43750,43750,43750,43750],skins:{44:60,94:60,133:60,200:60,295:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[9,5,2,20],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2781,dodge:12620,hp:374484,intelligence:18945,physicalAttack:78,strength:2916,armor:28049.6,magicPower:67686.6,magicResist:15252,skin:0,favorPetId:6006,favorPower:11064},40:{id:40,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{200:130,201:130,202:130,203:130,6022:130,8244:1,8245:1},power:192541,star:6,runes:[43750,43750,43750,43750,43750],skins:{53:60,89:60,129:60,168:60,314:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[5,9,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:17540,hp:343191,intelligence:2805,physicalAttack:48430.6,strength:2976,armor:24410,dodge:15732.28,magicResist:17633,modifiedSkillTier:3,skin:0,favorPetId:6004,favorPower:11064},6004:{id:6004,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6020:130,6021:130},power:181943,type:"pet",perks:[5],name:null,armorPenetration:47911,intelligence:11064,strength:12360}}},{id:6,args:{userId:8263317,heroes:[62,13,9,56,61],pet:6003,favor:{9:6004,13:6002,56:6006,61:6001,62:6003}},attackers:{9:{id:9,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{335:130,336:130,337:130,338:130,6022:130,8270:1,8271:1},power:198525,star:6,runes:[43750,43750,43750,43750,43750],skins:{9:60,41:60,163:60,189:60,311:60,338:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[7,2,20],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3068,hp:227134,intelligence:19003,physicalAttack:10007.6,strength:3068,armor:19995,dodge:17631.28,magicPower:54823,magicResist:31597,modifiedSkillTier:5,skin:0,favorPetId:6004,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6012:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:19060,magicPenetration:58138.6,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6002,favorPower:11064},56:{id:56,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{376:130,377:130,378:130,379:130,6032:130},power:184420,star:6,runes:[43750,43750,43750,43750,43750],skins:{264:60,279:60,294:60,321:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[5,7,1,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2791,hp:235111,intelligence:18813,physicalAttack:50,strength:2656,armor:22982.6,magicPenetration:48159,magicPower:75598.6,magicResist:13990,skin:0,favorPetId:6006,favorPower:11064},61:{id:61,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{411:130,412:130,413:130,414:130,6007:130},power:184868,star:6,runes:[43750,43750,43750,43750,43750],skins:{302:60,306:60,323:60,340:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6001,type:"hero",perks:[4,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2545,hp:466176,intelligence:3320,physicalAttack:34305,strength:18309,armor:31077.6,magicResist:24101,physicalCritChance:9009,skin:0,favorPetId:6001,favorPower:11064},62:{id:62,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{437:130,438:130,439:130,440:130,6017:130},power:173991,star:6,runes:[43750,43750,43750,43750,43750],skins:{320:60,343:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6003,type:"hero",perks:[8,7,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2530,hp:276010,intelligence:19245,physicalAttack:50,strength:3543,armor:12890,magicPenetration:23658,magicPower:80966.6,magicResist:12447.6,skin:0,favorPetId:6003,favorPower:11064},6003:{id:6003,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6015:130,6016:130},power:181943,type:"pet",perks:[8],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}},{id:7,args:{userId:8263335,heroes:[32,29,13,43,1],pet:6006,favor:{1:6004,13:6008,29:6006,32:6002,43:6007}},attackers:{1:{id:1,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{2:130,3:130,4:130,5:130,6022:130,8268:1,8269:1},power:198058,star:6,runes:[43750,43750,43750,43750,43750],skins:{1:60,54:60,95:60,154:60,250:60,325:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[4,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3093,hp:419649,intelligence:3644,physicalAttack:11481.6,strength:17049,armor:12720,dodge:17232.28,magicPenetration:22780,magicPower:55816,magicResist:1580,modifiedSkillTier:5,skin:0,favorPetId:6004,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6038:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6008,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:29017.6,magicPenetration:48181,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6008,favorPower:11064},29:{id:29,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{145:130,146:130,147:130,148:130,6032:130},power:189790,star:6,runes:[43750,43750,43750,43750,43750],skins:{29:60,72:60,88:60,147:60,242:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[9,5,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2885,hp:491431,intelligence:18331,physicalAttack:106,strength:3020,armor:37716.6,magicPower:76792.6,magicResist:31377,skin:0,favorPetId:6006,favorPower:11064},32:{id:32,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{160:130,161:130,162:130,163:130,6012:130},power:189956,star:6,runes:[43750,43750,43750,43750,43750],skins:{45:60,73:60,81:60,135:60,212:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,5,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2815,hp:551066,intelligence:18800,physicalAttack:50,strength:2810,armor:19040,magicPenetration:9957.6,magicPower:89495.6,magicResist:20805,skin:0,favorPetId:6002,favorPower:11064},43:{id:43,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{215:130,216:130,217:130,218:130,6035:130},power:189593,star:6,runes:[43750,43750,43750,43750,43750],skins:{98:60,130:60,169:60,201:60,304:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6007,type:"hero",perks:[7,9,1,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2447,hp:265217,intelligence:18758,physicalAttack:50,strength:2842,armor:18637.6,magicPenetration:52439,magicPower:75465.6,magicResist:22695,skin:0,favorPetId:6007,favorPower:11064},6006:{id:6006,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6030:130,6031:130},power:181943,type:"pet",perks:[5,9],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}}];
  12680. const bestPack = {
  12681. pack: packs[0],
  12682. countWin: 0,
  12683. }
  12684. for (const pack of packs) {
  12685. const attackers = pack.attackers;
  12686. const battle = {
  12687. attackers,
  12688. defenders: [enemieHeroes],
  12689. type: 'brawl',
  12690. };
  12691. let countWinBattles = 0;
  12692. let countTestBattle = 10;
  12693. for (let i = 0; i < countTestBattle; i++) {
  12694. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  12695. const result = await Calc(battle);
  12696. if (result.result.win) {
  12697. countWinBattles++;
  12698. }
  12699. if (countWinBattles > 7) {
  12700. console.log(pack)
  12701. return pack.args;
  12702. }
  12703. }
  12704. if (countWinBattles > bestPack.countWin) {
  12705. bestPack.countWin = countWinBattles;
  12706. bestPack.pack = pack.args;
  12707. }
  12708. }
  12709. console.log(bestPack);
  12710. return bestPack.pack;
  12711. }
  12712. async questFarm() {
  12713. const calls = [this.callBrawlQuestFarm];
  12714. const result = await Send(JSON.stringify({ calls }));
  12715. return result.results[0].result.response;
  12716. }
  12717. async getBrawlInfo() {
  12718. const data = await Send(JSON.stringify({
  12719. calls: [
  12720. this.callUserGetInfo,
  12721. this.callBrawlQuestGetInfo,
  12722. this.callBrawlFindEnemies,
  12723. this.callTeamGetMaxUpgrade,
  12724. this.callBrawlGetInfo,
  12725. ]
  12726. }));
  12727. let attempts = data.results[0].result.response.refillable.find(n => n.id == 48);
  12728. const maxUpgrade = data.results[3].result.response;
  12729. const maxHero = Object.values(maxUpgrade.hero);
  12730. const maxTitan = Object.values(maxUpgrade.titan);
  12731. const maxPet = Object.values(maxUpgrade.pet);
  12732. this.maxUpgrade = [...maxHero, ...maxPet, ...maxTitan];
  12733. this.info = data.results[4].result.response;
  12734. this.mandatoryId = lib.data.brawl.promoHero[this.info.id].promoHero;
  12735. return {
  12736. attempts: attempts.amount,
  12737. questInfo: data.results[1].result.response,
  12738. findEnemies: data.results[2].result.response,
  12739. }
  12740. }
  12741.  
  12742. /**
  12743. * Carrying out a fight
  12744. *
  12745. * Проведение боя
  12746. */
  12747. async battle(userId) {
  12748. this.stats.count++;
  12749. const battle = await this.startBattle(userId, this.args);
  12750. const result = await Calc(battle);
  12751. console.log(result.result);
  12752. if (result.result.win) {
  12753. this.stats.win++;
  12754. } else {
  12755. this.stats.loss++;
  12756. if (!this.info.boughtEndlessLivesToday) {
  12757. this.attempts--;
  12758. }
  12759. }
  12760. return await this.endBattle(result);
  12761. // return await this.cancelBattle(result);
  12762. }
  12763.  
  12764. /**
  12765. * Starts a fight
  12766. *
  12767. * Начинает бой
  12768. */
  12769. async startBattle(userId, args) {
  12770. const call = {
  12771. name: "brawl_startBattle",
  12772. args,
  12773. ident: "brawl_startBattle"
  12774. }
  12775. call.args.userId = userId;
  12776. const calls = [call];
  12777. const result = await Send(JSON.stringify({ calls }));
  12778. return result.results[0].result.response;
  12779. }
  12780.  
  12781. cancelBattle(battle) {
  12782. const fixBattle = function (heroes) {
  12783. for (const ids in heroes) {
  12784. const hero = heroes[ids];
  12785. hero.energy = random(1, 999);
  12786. if (hero.hp > 0) {
  12787. hero.hp = random(1, hero.hp);
  12788. }
  12789. }
  12790. }
  12791. fixBattle(battle.progress[0].attackers.heroes);
  12792. fixBattle(battle.progress[0].defenders.heroes);
  12793. return this.endBattle(battle);
  12794. }
  12795.  
  12796. /**
  12797. * Ends the fight
  12798. *
  12799. * Заканчивает бой
  12800. */
  12801. async endBattle(battle) {
  12802. battle.progress[0].attackers.input = ['auto', 0, 0, 'auto', 0, 0];
  12803. const calls = [{
  12804. name: "brawl_endBattle",
  12805. args: {
  12806. result: battle.result,
  12807. progress: battle.progress
  12808. },
  12809. ident: "brawl_endBattle"
  12810. },
  12811. this.callBrawlQuestGetInfo,
  12812. this.callBrawlFindEnemies,
  12813. ];
  12814. const result = await Send(JSON.stringify({ calls }));
  12815. return result.results;
  12816. }
  12817.  
  12818. end(endReason) {
  12819. isCancalBattle = true;
  12820. isBrawlsAutoStart = false;
  12821. setProgress(endReason, true);
  12822. console.log(endReason);
  12823. this.resolve();
  12824. }
  12825. }
  12826.  
  12827. // подземку вконце впихнул
  12828. function DungeonFull() {
  12829. return new Promise((resolve, reject) => {
  12830. const dung = new executeDungeon2(resolve, reject);
  12831. const titanit = getInput('countTitanit');
  12832. dung.start(titanit);
  12833. });
  12834. }
  12835. /** Прохождение подземелья */
  12836. function executeDungeon2(resolve, reject) {
  12837. let dungeonActivity = 0;
  12838. let startDungeonActivity = 0;
  12839. let maxDungeonActivity = 150;
  12840. let limitDungeonActivity = 30180;
  12841. let countShowStats = 1;
  12842. //let fastMode = isChecked('fastMode');
  12843. let end = false;
  12844.  
  12845. let countTeam = [];
  12846. let timeDungeon = {
  12847. all: new Date().getTime(),
  12848. findAttack: 0,
  12849. attackNeutral: 0,
  12850. attackEarthOrFire: 0
  12851. }
  12852.  
  12853. let titansStates = {};
  12854. let bestBattle = {};
  12855.  
  12856. let teams = {
  12857. neutral: [],
  12858. water: [],
  12859. earth: [],
  12860. fire: [],
  12861. hero: []
  12862. }
  12863.  
  12864. let callsExecuteDungeon = {
  12865. calls: [{
  12866. name: "dungeonGetInfo",
  12867. args: {},
  12868. ident: "dungeonGetInfo"
  12869. }, {
  12870. name: "teamGetAll",
  12871. args: {},
  12872. ident: "teamGetAll"
  12873. }, {
  12874. name: "teamGetFavor",
  12875. args: {},
  12876. ident: "teamGetFavor"
  12877. }, {
  12878. name: "clanGetInfo",
  12879. args: {},
  12880. ident: "clanGetInfo"
  12881. }]
  12882. }
  12883.  
  12884. this.start = async function(titanit) {
  12885. //maxDungeonActivity = titanit > limitDungeonActivity ? limitDungeonActivity : titanit;
  12886. maxDungeonActivity = titanit || getInput('countTitanit');
  12887. send(JSON.stringify(callsExecuteDungeon), startDungeon);
  12888. }
  12889.  
  12890. /** Получаем данные по подземелью */
  12891. function startDungeon(e) {
  12892. stopDung = false; // стоп подземка
  12893. let res = e.results;
  12894. let dungeonGetInfo = res[0].result.response;
  12895. if (!dungeonGetInfo) {
  12896. endDungeon('noDungeon', res);
  12897. return;
  12898. }
  12899. console.log("Начинаем копать на фулл: ", new Date());
  12900. let teamGetAll = res[1].result.response;
  12901. let teamGetFavor = res[2].result.response;
  12902. dungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  12903. startDungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  12904. titansStates = dungeonGetInfo.states.titans;
  12905.  
  12906. teams.hero = {
  12907. favor: teamGetFavor.dungeon_hero,
  12908. heroes: teamGetAll.dungeon_hero.filter(id => id < 6000),
  12909. teamNum: 0,
  12910. }
  12911. let heroPet = teamGetAll.dungeon_hero.filter(id => id >= 6000).pop();
  12912. if (heroPet) {
  12913. teams.hero.pet = heroPet;
  12914. }
  12915. teams.neutral = getTitanTeam('neutral');
  12916. teams.water = {
  12917. favor: {},
  12918. heroes: getTitanTeam('water'),
  12919. teamNum: 0,
  12920. };
  12921. teams.earth = {
  12922. favor: {},
  12923. heroes: getTitanTeam('earth'),
  12924. teamNum: 0,
  12925. };
  12926. teams.fire = {
  12927. favor: {},
  12928. heroes: getTitanTeam('fire'),
  12929. teamNum: 0,
  12930. };
  12931.  
  12932. checkFloor(dungeonGetInfo);
  12933. }
  12934.  
  12935. function getTitanTeam(type) {
  12936. switch (type) {
  12937. case 'neutral':
  12938. return [4023, 4022, 4012, 4021, 4011, 4010, 4020];
  12939. case 'water':
  12940. return [4000, 4001, 4002, 4003]
  12941. .filter(e => !titansStates[e]?.isDead);
  12942. case 'earth':
  12943. return [4020, 4022, 4021, 4023]
  12944. .filter(e => !titansStates[e]?.isDead);
  12945. case 'fire':
  12946. return [4010, 4011, 4012, 4013]
  12947. .filter(e => !titansStates[e]?.isDead);
  12948. }
  12949. }
  12950.  
  12951. /** Создать копию объекта */
  12952. function clone(a) {
  12953. return JSON.parse(JSON.stringify(a));
  12954. }
  12955.  
  12956. /** Находит стихию на этаже */
  12957. function findElement(floor, element) {
  12958. for (let i in floor) {
  12959. if (floor[i].attackerType === element) {
  12960. return i;
  12961. }
  12962. }
  12963. return undefined;
  12964. }
  12965.  
  12966. /** Проверяем этаж */
  12967. async function checkFloor(dungeonInfo) {
  12968. if (!('floor' in dungeonInfo) || dungeonInfo.floor?.state == 2) {
  12969. saveProgress();
  12970. return;
  12971. }
  12972. // console.log(dungeonInfo, dungeonActivity);
  12973. setProgress(`${I18N('DUNGEON2')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  12974. //setProgress('Dungeon: Титанит ' + dungeonActivity + '/' + maxDungeonActivity);
  12975. if (dungeonActivity >= maxDungeonActivity) {
  12976. endDungeon('Стоп подземка,', 'набрано титанита: ' + dungeonActivity + '/' + maxDungeonActivity);
  12977. return;
  12978. }
  12979. let activity = dungeonActivity - startDungeonActivity;
  12980. titansStates = dungeonInfo.states.titans;
  12981. if (stopDung){
  12982. endDungeon('Стоп подземка,', 'набрано титанита: ' + dungeonActivity + '/' + maxDungeonActivity);
  12983. return;
  12984. }
  12985. /*if (activity / 1000 > countShowStats) {
  12986. countShowStats++;
  12987. showStats();
  12988. }*/
  12989. bestBattle = {};
  12990. let floorChoices = dungeonInfo.floor.userData;
  12991. if (floorChoices.length > 1) {
  12992. for (let element in teams) {
  12993. let teamNum = findElement(floorChoices, element);
  12994. if (!!teamNum) {
  12995. if (element == 'earth') {
  12996. teamNum = await chooseEarthOrFire(floorChoices);
  12997. if (teamNum < 0) {
  12998. endDungeon('Невозможно победить без потери Титана!', dungeonInfo);
  12999. return;
  13000. }
  13001. }
  13002. chooseElement(floorChoices[teamNum].attackerType, teamNum);
  13003. return;
  13004. }
  13005. }
  13006. } else {
  13007. chooseElement(floorChoices[0].attackerType, 0);
  13008. }
  13009. }
  13010.  
  13011. /** Выбираем огнем или землей атаковать */
  13012. async function chooseEarthOrFire(floorChoices) {
  13013. bestBattle.recovery = -11;
  13014. let selectedTeamNum = -1;
  13015. for (let attempt = 0; selectedTeamNum < 0 && attempt < 4; attempt++) {
  13016. for (let teamNum in floorChoices) {
  13017. let attackerType = floorChoices[teamNum].attackerType;
  13018. selectedTeamNum = await attemptAttackEarthOrFire(teamNum, attackerType, attempt);
  13019. }
  13020. }
  13021. console.log("Выбор команды огня или земли: ", selectedTeamNum < 0 ? "не сделан" : floorChoices[selectedTeamNum].attackerType);
  13022. return selectedTeamNum;
  13023. }
  13024.  
  13025. /** Попытка атаки землей и огнем */
  13026. async function attemptAttackEarthOrFire(teamNum, attackerType, attempt) {
  13027. let start = new Date();
  13028. let team = clone(teams[attackerType]);
  13029. let startIndex = team.heroes.length + attempt - 4;
  13030. if (startIndex >= 0) {
  13031. team.heroes = team.heroes.slice(startIndex);
  13032. let recovery = await getBestRecovery(teamNum, attackerType, team, 25);
  13033. if (recovery > bestBattle.recovery) {
  13034. bestBattle.recovery = recovery;
  13035. bestBattle.selectedTeamNum = teamNum;
  13036. bestBattle.team = team;
  13037. }
  13038. }
  13039. let workTime = new Date().getTime() - start.getTime();
  13040. timeDungeon.attackEarthOrFire += workTime;
  13041. if (bestBattle.recovery < -10) {
  13042. return -1;
  13043. }
  13044. return bestBattle.selectedTeamNum;
  13045. }
  13046.  
  13047. /** Выбираем стихию для атаки */
  13048. async function chooseElement(attackerType, teamNum) {
  13049. let result;
  13050. switch (attackerType) {
  13051. case 'hero':
  13052. case 'water':
  13053. result = await startBattle(teamNum, attackerType, teams[attackerType]);
  13054. break;
  13055. case 'earth':
  13056. case 'fire':
  13057. result = await attackEarthOrFire(teamNum, attackerType);
  13058. break;
  13059. case 'neutral':
  13060. result = await attackNeutral(teamNum, attackerType);
  13061. }
  13062. if (!!result && attackerType != 'hero') {
  13063. let recovery = (!!!bestBattle.recovery ? 10 * getRecovery(result) : bestBattle.recovery) * 100;
  13064. let titans = result.progress[0].attackers.heroes;
  13065. console.log("Проведен бой: " + attackerType +
  13066. ", recovery = " + (recovery > 0 ? "+" : "") + Math.round(recovery) + "% \r\n", titans);
  13067. }
  13068. endBattle(result);
  13069. }
  13070.  
  13071. /** Атакуем Землей или Огнем */
  13072. async function attackEarthOrFire(teamNum, attackerType) {
  13073. if (!!!bestBattle.recovery) {
  13074. bestBattle.recovery = -11;
  13075. let selectedTeamNum = -1;
  13076. for (let attempt = 0; selectedTeamNum < 0 && attempt < 4; attempt++) {
  13077. selectedTeamNum = await attemptAttackEarthOrFire(teamNum, attackerType, attempt);
  13078. }
  13079. if (selectedTeamNum < 0) {
  13080. endDungeon('Невозможно победить без потери Титана!', attackerType);
  13081. return;
  13082. }
  13083. }
  13084. return findAttack(teamNum, attackerType, bestBattle.team);
  13085. }
  13086.  
  13087. /** Находим подходящий результат для атаки */
  13088. async function findAttack(teamNum, attackerType, team) {
  13089. let start = new Date();
  13090. let recovery = -1000;
  13091. let iterations = 0;
  13092. let result;
  13093. let correction = 0.01;
  13094. for (let needRecovery = bestBattle.recovery; recovery < needRecovery; needRecovery -= correction, iterations++) {
  13095. result = await startBattle(teamNum, attackerType, team);
  13096. recovery = getRecovery(result);
  13097. }
  13098. bestBattle.recovery = recovery;
  13099. let workTime = new Date().getTime() - start.getTime();
  13100. timeDungeon.findAttack += workTime;
  13101. return result;
  13102. }
  13103.  
  13104. /** Атакуем Нейтральной командой */
  13105. async function attackNeutral(teamNum, attackerType) {
  13106. let start = new Date();
  13107. let factors = calcFactor();
  13108. bestBattle.recovery = -0.2;
  13109. await findBestBattleNeutral(teamNum, attackerType, factors, true)
  13110. if (bestBattle.recovery < 0 || (bestBattle.recovery < 0.2 && factors[0].value < 0.5)) {
  13111. let recovery = 100 * bestBattle.recovery;
  13112. console.log("Не удалось найти удачный бой в быстром режиме: " + attackerType +
  13113. ", recovery = " + (recovery > 0 ? "+" : "") + Math.round(recovery) + "% \r\n", bestBattle.attackers);
  13114. await findBestBattleNeutral(teamNum, attackerType, factors, false)
  13115. }
  13116. let workTime = new Date().getTime() - start.getTime();
  13117. timeDungeon.attackNeutral += workTime;
  13118. if (!!bestBattle.attackers) {
  13119. let team = getTeam(bestBattle.attackers);
  13120. return findAttack(teamNum, attackerType, team);
  13121. }
  13122. endDungeon('Не удалось найти удачный бой!', attackerType);
  13123. return undefined;
  13124. }
  13125.  
  13126. /** Находит лучшую нейтральную команду */
  13127. async function findBestBattleNeutral(teamNum, attackerType, factors, mode) {
  13128. let countFactors = factors.length < 4 ? factors.length : 4;
  13129. let aradgi = !titansStates['4013']?.isDead;
  13130. let edem = !titansStates['4023']?.isDead;
  13131. let dark = [4032, 4033].filter(e => !titansStates[e]?.isDead);
  13132. let light = [4042].filter(e => !titansStates[e]?.isDead);
  13133. let actions = [];
  13134. if (mode) {
  13135. for (let i = 0; i < countFactors; i++) {
  13136. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(factors[i].id)));
  13137. }
  13138. if (countFactors > 1) {
  13139. let firstId = factors[0].id;
  13140. let secondId = factors[1].id;
  13141. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, secondId)));
  13142. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, secondId)));
  13143. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4003, secondId)));
  13144. }
  13145. if (aradgi) {
  13146. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(4013)));
  13147. if (countFactors > 0) {
  13148. let firstId = factors[0].id;
  13149. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4000, 4013)));
  13150. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, 4013)));
  13151. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, 4013)));
  13152. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4003, 4013)));
  13153. }
  13154. if (edem) {
  13155. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(4023, 4000, 4013)));
  13156. }
  13157. }
  13158. } else {
  13159. if (mode) {
  13160. for (let i = 0; i < factors.length; i++) {
  13161. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(factors[i].id)));
  13162. }
  13163. } else {
  13164. countFactors = factors.length < 2 ? factors.length : 2;
  13165. }
  13166. for (let i = 0; i < countFactors; i++) {
  13167. let mainId = factors[i].id;
  13168. if (aradgi && (mode || i > 0)) {
  13169. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4000, 4013)));
  13170. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, 4013)));
  13171. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, 4013)));
  13172. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4003, 4013)));
  13173. }
  13174. for (let i = 0; i < dark.length; i++) {
  13175. let darkId = dark[i];
  13176. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, darkId)));
  13177. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, darkId)));
  13178. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4003, darkId)));
  13179. }
  13180. for (let i = 0; i < light.length; i++) {
  13181. let lightId = light[i];
  13182. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, lightId)));
  13183. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, lightId)));
  13184. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4003, lightId)));
  13185. }
  13186. let isFull = mode || i > 0;
  13187. for (let j = isFull ? i + 1 : 2; j < factors.length; j++) {
  13188. let extraId = factors[j].id;
  13189. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4000, extraId)));
  13190. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, extraId)));
  13191. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, extraId)));
  13192. }
  13193. }
  13194. if (aradgi) {
  13195. if (mode) {
  13196. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(4013)));
  13197. }
  13198. for (let i = 0; i < dark.length; i++) {
  13199. let darkId = dark[i];
  13200. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(darkId, 4001, 4013)));
  13201. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(darkId, 4002, 4013)));
  13202. }
  13203. for (let i = 0; i < light.length; i++) {
  13204. let lightId = light[i];
  13205. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(lightId, 4001, 4013)));
  13206. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(lightId, 4002, 4013)));
  13207. }
  13208. }
  13209. for (let i = 0; i < dark.length; i++) {
  13210. let firstId = dark[i];
  13211. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId)));
  13212. for (let j = i + 1; j < dark.length; j++) {
  13213. let secondId = dark[j];
  13214. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, secondId)));
  13215. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, secondId)));
  13216. }
  13217. }
  13218. for (let i = 0; i < light.length; i++) {
  13219. let firstId = light[i];
  13220. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId)));
  13221. for (let j = i + 1; j < light.length; j++) {
  13222. let secondId = light[j];
  13223. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, secondId)));
  13224. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, secondId)));
  13225. }
  13226. }
  13227. }
  13228. for (let result of await Promise.all(actions)) {
  13229. let recovery = getRecovery(result);
  13230. if (recovery > bestBattle.recovery) {
  13231. bestBattle.recovery = recovery;
  13232. bestBattle.attackers = result.progress[0].attackers.heroes;
  13233. }
  13234. }
  13235. }
  13236.  
  13237. /** Получаем нейтральную команду */
  13238. function getNeutralTeam(id, swapId, addId) {
  13239. let neutralTeam = clone(teams.water);
  13240. let neutral = neutralTeam.heroes;
  13241. if (neutral.length == 4) {
  13242. if (!!swapId) {
  13243. for (let i in neutral) {
  13244. if (neutral[i] == swapId) {
  13245. neutral[i] = addId;
  13246. }
  13247. }
  13248. }
  13249. } else if (!!addId) {
  13250. neutral.push(addId);
  13251. }
  13252. neutral.push(id);
  13253. return neutralTeam;
  13254. }
  13255.  
  13256. /** Получить команду титанов */
  13257. function getTeam(titans) {
  13258. return {
  13259. favor: {},
  13260. heroes: Object.keys(titans).map(id => parseInt(id)),
  13261. teamNum: 0,
  13262. };
  13263. }
  13264.  
  13265. /** Вычисляем фактор боеготовности титанов */
  13266. function calcFactor() {
  13267. let neutral = teams.neutral;
  13268. let factors = [];
  13269. for (let i in neutral) {
  13270. let titanId = neutral[i];
  13271. let titan = titansStates[titanId];
  13272. let factor = !!titan ? titan.hp / titan.maxHp + titan.energy / 10000.0 : 1;
  13273. if (factor > 0) {
  13274. factors.push({id: titanId, value: factor});
  13275. }
  13276. }
  13277. factors.sort(function(a, b) {
  13278. return a.value - b.value;
  13279. });
  13280. return factors;
  13281. }
  13282.  
  13283. /** Возвращает наилучший результат из нескольких боев */
  13284. async function getBestRecovery(teamNum, attackerType, team, countBattle) {
  13285. let bestRecovery = -1000;
  13286. let actions = [];
  13287. for (let i = 0; i < countBattle; i++) {
  13288. actions.push(startBattle(teamNum, attackerType, team));
  13289. }
  13290. for (let result of await Promise.all(actions)) {
  13291. let recovery = getRecovery(result);
  13292. if (recovery > bestRecovery) {
  13293. bestRecovery = recovery;
  13294. }
  13295. }
  13296. return bestRecovery;
  13297. }
  13298.  
  13299. /** Возвращает разницу в здоровье атакующей команды после и до битвы и проверяет здоровье титанов на необходимый минимум*/
  13300. function getRecovery(result) {
  13301. if (result.result.stars < 3) {
  13302. return -100;
  13303. }
  13304. let beforeSumFactor = 0;
  13305. let afterSumFactor = 0;
  13306. let beforeTitans = result.battleData.attackers;
  13307. let afterTitans = result.progress[0].attackers.heroes;
  13308. for (let i in afterTitans) {
  13309. let titan = afterTitans[i];
  13310. let percentHP = titan.hp / beforeTitans[i].hp;
  13311. let energy = titan.energy;
  13312. let factor = checkTitan(i, energy, percentHP) ? getFactor(i, energy, percentHP) : -100;
  13313. afterSumFactor += factor;
  13314. }
  13315. for (let i in beforeTitans) {
  13316. let titan = beforeTitans[i];
  13317. let state = titan.state;
  13318. beforeSumFactor += !!state ? getFactor(i, state.energy, state.hp / titan.hp) : 1;
  13319. }
  13320. return afterSumFactor - beforeSumFactor;
  13321. }
  13322.  
  13323. /** Возвращает состояние титана*/
  13324. function getFactor(id, energy, percentHP) {
  13325. let elemantId = id.slice(2, 3);
  13326. let isEarthOrFire = elemantId == '1' || elemantId == '2';
  13327. let energyBonus = id == '4020' && energy == 1000 ? 0.1 : energy / 20000.0;
  13328. let factor = percentHP + energyBonus;
  13329. return isEarthOrFire ? factor : factor / 10;
  13330. }
  13331.  
  13332. /** Проверяет состояние титана*/
  13333. function checkTitan(id, energy, percentHP) {
  13334. switch (id) {
  13335. case '4020':
  13336. return percentHP > 0.25 || (energy == 1000 && percentHP > 0.05);
  13337. break;
  13338. case '4010':
  13339. return percentHP + energy / 2000.0 > 0.63;
  13340. break;
  13341. case '4000':
  13342. return percentHP > 0.62 || (energy < 1000 && (
  13343. (percentHP > 0.45 && energy >= 400) ||
  13344. (percentHP > 0.3 && energy >= 670)));
  13345. }
  13346. return true;
  13347. }
  13348.  
  13349.  
  13350. /** Начинаем бой */
  13351. function startBattle(teamNum, attackerType, args) {
  13352. return new Promise(function (resolve, reject) {
  13353. args.teamNum = teamNum;
  13354. let startBattleCall = {
  13355. calls: [{
  13356. name: "dungeonStartBattle",
  13357. args,
  13358. ident: "body"
  13359. }]
  13360. }
  13361. send(JSON.stringify(startBattleCall), resultBattle, {
  13362. resolve,
  13363. teamNum,
  13364. attackerType
  13365. });
  13366. });
  13367. }
  13368.  
  13369. /** Возращает результат боя в промис */
  13370. /*function resultBattle(resultBattles, args) {
  13371. if (!!resultBattles && !!resultBattles.results) {
  13372. let battleData = resultBattles.results[0].result.response;
  13373. let battleType = "get_tower";
  13374. if (battleData.type == "dungeon_titan") {
  13375. battleType = "get_titan";
  13376. }
  13377. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];//тест подземка правки
  13378. BattleCalc(battleData, battleType, function (result) {
  13379. result.teamNum = args.teamNum;
  13380. result.attackerType = args.attackerType;
  13381. args.resolve(result);
  13382. });
  13383. } else {
  13384. endDungeon('Потеряна связь с сервером игры!', 'break');
  13385. }
  13386. }*/
  13387. function resultBattle(resultBattles, args) {
  13388. battleData = resultBattles.results[0].result.response;
  13389. battleType = "get_tower";
  13390. if (battleData.type == "dungeon_titan") {
  13391. battleType = "get_titan";
  13392. }
  13393. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  13394. BattleCalc(battleData, battleType, function (result) {
  13395. result.teamNum = args.teamNum;
  13396. result.attackerType = args.attackerType;
  13397. args.resolve(result);
  13398. });
  13399. }
  13400.  
  13401. /** Заканчиваем бой */
  13402.  
  13403. ////
  13404. async function endBattle(battleInfo) {
  13405. if (!!battleInfo) {
  13406. const args = {
  13407. result: battleInfo.result,
  13408. progress: battleInfo.progress,
  13409. }
  13410. if (battleInfo.result.stars < 3) {
  13411. endDungeon('Герой или Титан мог погибнуть в бою!', battleInfo);
  13412. return;
  13413. }
  13414. if (countPredictionCard > 0) {
  13415. args.isRaid = true;
  13416. } else {
  13417. const timer = getTimer(battleInfo.battleTime);
  13418. console.log(timer);
  13419. await countdownTimer(timer, `${I18N('DUNGEON2')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  13420. }
  13421. const calls = [{
  13422. name: "dungeonEndBattle",
  13423. args,
  13424. ident: "body"
  13425. }];
  13426. lastDungeonBattleData = null;
  13427. send(JSON.stringify({ calls }), resultEndBattle);
  13428. } else {
  13429. endDungeon('dungeonEndBattle win: false\n', battleInfo);
  13430. }
  13431. }
  13432. /** Получаем и обрабатываем результаты боя */
  13433. function resultEndBattle(e) {
  13434. if (!!e && !!e.results) {
  13435. let battleResult = e.results[0].result.response;
  13436. if ('error' in battleResult) {
  13437. endDungeon('errorBattleResult', battleResult);
  13438. return;
  13439. }
  13440. let dungeonGetInfo = battleResult.dungeon ?? battleResult;
  13441. dungeonActivity += battleResult.reward.dungeonActivity ?? 0;
  13442. checkFloor(dungeonGetInfo);
  13443. } else {
  13444. endDungeon('Потеряна связь с сервером игры!', 'break');
  13445. }
  13446. }
  13447.  
  13448. /** Добавить команду титанов в общий список команд */
  13449. function addTeam(team) {
  13450. for (let i in countTeam) {
  13451. if (equalsTeam(countTeam[i].team, team)) {
  13452. countTeam[i].count++;
  13453. return;
  13454. }
  13455. }
  13456. countTeam.push({team: team, count: 1});
  13457. }
  13458.  
  13459. /** Сравнить команды на равенство */
  13460. function equalsTeam(team1, team2) {
  13461. if (team1.length == team2.length) {
  13462. for (let i in team1) {
  13463. if (team1[i] != team2[i]) {
  13464. return false;
  13465. }
  13466. }
  13467. return true;
  13468. }
  13469. return false;
  13470. }
  13471.  
  13472. function saveProgress() {
  13473. let saveProgressCall = {
  13474. calls: [{
  13475. name: "dungeonSaveProgress",
  13476. args: {},
  13477. ident: "body"
  13478. }]
  13479. }
  13480. send(JSON.stringify(saveProgressCall), resultEndBattle);
  13481. }
  13482.  
  13483.  
  13484. /** Выводит статистику прохождения подземелья */
  13485. function showStats() {
  13486. let activity = dungeonActivity - startDungeonActivity;
  13487. let workTime = clone(timeDungeon);
  13488. workTime.all = new Date().getTime() - workTime.all;
  13489. for (let i in workTime) {
  13490. workTime[i] = (workTime[i] / 1000).round(0);
  13491. }
  13492. countTeam.sort(function(a, b) {
  13493. return b.count - a.count;
  13494. });
  13495. console.log(titansStates);
  13496. console.log("Собрано титанита: ", activity);
  13497. console.log("Скорость сбора: " + (3600 * activity / workTime.all).round(0) + " титанита/час");
  13498. console.log("Время раскопок: ");
  13499. for (let i in workTime) {
  13500. let timeNow = workTime[i];
  13501. console.log(i + ": ", (timeNow / 3600).round(0) + " ч. " + (timeNow % 3600 / 60).round(0) + " мин. " + timeNow % 60 + " сек.");
  13502. }
  13503. console.log("Частота использования команд: ");
  13504. for (let i in countTeam) {
  13505. let teams = countTeam[i];
  13506. console.log(teams.team + ": ", teams.count);
  13507. }
  13508. }
  13509.  
  13510. /** Заканчиваем копать подземелье */
  13511. function endDungeon(reason, info) {
  13512. if (!end) {
  13513. end = true;
  13514. console.log(reason, info);
  13515. showStats();
  13516. if (info == 'break') {
  13517. setProgress('Dungeon stoped: Титанит ' + dungeonActivity + '/' + maxDungeonActivity +
  13518. "\r\nПотеряна связь с сервером игры!", false, hideProgress);
  13519. } else {
  13520. setProgress('Dungeon completed: Титанит ' + dungeonActivity + '/' + maxDungeonActivity, false, hideProgress);
  13521. }
  13522. setTimeout(cheats.refreshGame, 1000);
  13523. resolve();
  13524. }
  13525. }
  13526. }
  13527.  
  13528. //дарим подарки участникам других гильдий не выходя из своей гильдии
  13529. function NewYearGift_Clan() {
  13530. console.log('NewYearGift_Clan called...');
  13531. const userID = getInput('userID');
  13532. const AmontID = getInput('AmontID');
  13533. const GiftNum = getInput('GiftNum');
  13534.  
  13535. const data = {
  13536. "calls": [{
  13537. "name": "newYearGiftSend",
  13538. "args": {
  13539. "userId": userID,
  13540. "amount": AmontID,
  13541. "giftNum": GiftNum,
  13542. "users": {
  13543. [userID]: AmontID
  13544. }
  13545. },
  13546. "ident": "body"
  13547. }
  13548. ]
  13549. }
  13550.  
  13551. const dataJson = JSON.stringify(data);
  13552.  
  13553. SendRequest(dataJson, e => {
  13554. let userInfo = e.results[0].result.response;
  13555. console.log(userInfo);
  13556. });
  13557. setProgress(I18N('SEND_GIFT'), true);
  13558. }
  13559. })();
  13560.  
  13561. /**
  13562. * TODO:
  13563. * Получение всех уровней при сборе всех наград (квест на титанит и на энку) +-
  13564. * Добивание на арене титанов
  13565. * Закрытие окошек по Esc +-
  13566. * Починить работу скрипта на уровне команды ниже 10 +-
  13567. * Написать номальную синхронизацию
  13568. * Добавить дополнительные настройки автопокупки в "Тайном богатстве"
  13569. */