HeroWarsHelper

Automation of actions for the game Hero Wars

目前為 2024-05-26 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name HeroWarsHelper
  3. // @name:en HeroWarsDungeon
  4. // @name:ru HeroWarsDungeon
  5. // @namespace HeroWarsDungeon
  6. // @version 2.245
  7. // @description Automation of actions for the game Hero Wars
  8. // @description:en Automation of actions for the game Hero Wars
  9. // @description:ru Автоматизация действий для игры Хроники Хаоса
  10. // @author ZingerY
  11. // @license Copyright ZingerY
  12. // @homepage https://zingery.ru/scripts/HeroWarsHelper.user.js
  13. // @icon http://ilovemycomp.narod.ru/VaultBoyIco16.ico
  14. // @icon64 http://ilovemycomp.narod.ru/VaultBoyIco64.png
  15. // @encoding utf-8
  16. // @include https://apps-1701433570146040.apps.fbsbx.com/*
  17. // @include https://*.nextersglobal.com/*
  18. // @include https://*.hero-wars*.com/*
  19. // @match https://www.solfors.com/
  20. // @match https://t.me/s/hw_ru
  21. // @run-at document-start
  22. // ==/UserScript==
  23.  
  24. // сделал ApuoH
  25. (function() {
  26. /**
  27. * Start script
  28. *
  29. * Стартуем скрипт
  30. */
  31. console.log('Start ' + GM_info.script.name + ', v' + GM_info.script.version);
  32. /**
  33. * Script info
  34. *
  35. * Информация о скрипте
  36. */
  37. const scriptInfo = (({name, version, author, homepage, lastModified}, updateUrl, source) =>
  38. ({name, version, author, homepage, lastModified, updateUrl, source}))
  39. (GM_info.script, GM_info.scriptUpdateURL, arguments.callee.toString());
  40. /**
  41. * If we are on the gifts page, then we collect and send them to the server
  42. *
  43. * Если находимся на странице подарков, то собираем и отправляем их на сервер
  44. */
  45. if (['www.solfors.com', 't.me'].includes(location.host)) {
  46. setTimeout(sendCodes, 2000);
  47. return;
  48. }
  49. /**
  50. * Information for completing daily quests
  51. *
  52. * Информация для выполнения ежендевных квестов
  53. */
  54. const questsInfo = {};
  55. /**
  56. * Is the game data loaded
  57. *
  58. * Загружены ли данные игры
  59. */
  60. let isLoadGame = false;
  61. /**
  62. * Headers of the last request
  63. *
  64. * Заголовки последнего запроса
  65. */
  66. let lastHeaders = {};
  67. /**
  68. * Information about sent gifts
  69. *
  70. * Информация об отправленных подарках
  71. */
  72. let freebieCheckInfo = null;
  73. /**
  74. * missionTimer
  75. *
  76. * missionTimer
  77. */
  78. let missionBattle = null;
  79. /** Пачки для тестов в чате*/ //тест сохранка
  80. let repleyBattle = {
  81. defenders: {},
  82. attackers: {},
  83. effects: {},
  84. state: {},
  85. seed: undefined
  86. }
  87. /**
  88. * User data
  89. *
  90. * Данные пользователя
  91. */
  92. let userInfo;
  93. /**
  94. * Original methods for working with AJAX
  95. *
  96. * Оригинальные методы для работы с AJAX
  97. */
  98. const original = {
  99. open: XMLHttpRequest.prototype.open,
  100. send: XMLHttpRequest.prototype.send,
  101. setRequestHeader: XMLHttpRequest.prototype.setRequestHeader,
  102. SendWebSocket: WebSocket.prototype.send,
  103. };
  104. /**
  105. * Decoder for converting byte data to JSON string
  106. *
  107. * Декодер для перобразования байтовых данных в JSON строку
  108. */
  109. const decoder = new TextDecoder("utf-8");
  110. /**
  111. * Stores a history of requests
  112. *
  113. * Хранит историю запросов
  114. */
  115. let requestHistory = {};
  116. /**
  117. * URL for API requests
  118. *
  119. * URL для запросов к API
  120. */
  121. let apiUrl = '';
  122.  
  123. /**
  124. * Connecting to the game code
  125. *
  126. * Подключение к коду игры
  127. */
  128. this.cheats = new hackGame();
  129. /**
  130. * The function of calculating the results of the battle
  131. *
  132. * Функция расчета результатов боя
  133. */
  134. this.BattleCalc = cheats.BattleCalc;
  135. /**
  136. * Sending a request available through the console
  137. *
  138. * Отправка запроса доступная через консоль
  139. */
  140. this.SendRequest = send;
  141. /**
  142. * Simple combat calculation available through the console
  143. *
  144. * Простой расчет боя доступный через консоль
  145. */
  146. this.Calc = function (data) {
  147. const type = getBattleType(data?.type);
  148. return new Promise((resolve, reject) => {
  149. try {
  150. BattleCalc(data, type, resolve);
  151. } catch (e) {
  152. reject(e);
  153. }
  154. })
  155. }
  156. //тест остановка подземки
  157. let stopDung = false;
  158. /**
  159. * Short asynchronous request
  160. * Usage example (returns information about a character):
  161. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  162. *
  163. * Короткий асинхронный запрос
  164. * Пример использования (возвращает информацию о персонаже):
  165. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  166. */
  167. this.Send = function (json, pr) {
  168. return new Promise((resolve, reject) => {
  169. try {
  170. send(json, resolve, pr);
  171. } catch (e) {
  172. reject(e);
  173. }
  174. })
  175. }
  176.  
  177. this.xyz = (({ name, version, author }) => ({ name, version, author }))(GM_info.script);
  178. const i18nLangData = {
  179. /* English translation by BaBa */
  180. en: {
  181. /* Checkboxes */
  182. SKIP_FIGHTS: 'Skip battle',
  183. SKIP_FIGHTS_TITLE: 'Skip battle in Outland and the arena of the titans, auto-pass in the tower and campaign',
  184. ENDLESS_CARDS: 'Infinite cards',
  185. ENDLESS_CARDS_TITLE: 'Disable Divination Cards wasting',
  186. AUTO_EXPEDITION: 'Auto Expedition',
  187. AUTO_EXPEDITION_TITLE: 'Auto-sending expeditions',
  188. CANCEL_FIGHT: 'Cancel battle',
  189. CANCEL_FIGHT_TITLE: 'The possibility of canceling the battle on VG',
  190. GIFTS: 'Gifts',
  191. GIFTS_TITLE: 'Collect gifts automatically',
  192. BATTLE_RECALCULATION: 'Battle recalculation',
  193. BATTLE_RECALCULATION_TITLE: 'Preliminary calculation of the battle',
  194. BATTLE_FISHING: 'Finishing',
  195. BATTLE_FISHING_TITLE: 'Finishing off the team from the last replay in the chat',
  196. BATTLE_TRENING: 'Workout',
  197. BATTLE_TRENING_TITLE: 'A training battle in the chat against the team from the last replay',
  198. QUANTITY_CONTROL: 'Quantity control',
  199. QUANTITY_CONTROL_TITLE: 'Ability to specify the number of opened "lootboxes"',
  200. REPEAT_CAMPAIGN: 'Repeat missions',
  201. REPEAT_CAMPAIGN_TITLE: 'Auto-repeat battles in the campaign',
  202. DISABLE_DONAT: 'Disable donation',
  203. DISABLE_DONAT_TITLE: 'Removes all donation offers',
  204. DAILY_QUESTS: 'Quests',
  205. DAILY_QUESTS_TITLE: 'Complete daily quests',
  206. AUTO_QUIZ: 'AutoQuiz',
  207. AUTO_QUIZ_TITLE: 'Automatically receive correct answers to quiz questions',
  208. SECRET_WEALTH_CHECKBOX: 'Automatic purchase in the store "Secret Wealth" when entering the game',
  209. HIDE_SERVERS: 'Collapse servers',
  210. HIDE_SERVERS_TITLE: 'Hide unused servers',
  211. /* Input fields */
  212. HOW_MUCH_TITANITE: 'How much titanite to farm',
  213. COMBAT_SPEED: 'Combat Speed Multiplier',
  214. HOW_REPEAT_CAMPAIGN: 'how many mission replays', //тест добавил
  215. NUMBER_OF_TEST: 'Number of test fights',
  216. NUMBER_OF_AUTO_BATTLE: 'Number of auto-battle attempts',
  217. USER_ID_TITLE: 'Enter the player ID',
  218. AMOUNT: 'Gift number, 1 - hero development, 2 - pets, 3 - light, 4 - darkness, 5 - ascension, 6 - appearance',
  219. GIFT_NUM: 'Number of gifts to be sent',
  220. /* Buttons */
  221. RUN_SCRIPT: 'Run the',
  222. STOP_SCRIPT: 'Stop the',
  223. TO_DO_EVERYTHING: 'Do All',
  224. TO_DO_EVERYTHING_TITLE: 'Perform multiple actions of your choice',
  225. OUTLAND: 'Outland',
  226. OUTLAND_TITLE: 'Collect Outland',
  227. TITAN_ARENA: 'ToE',
  228. TITAN_ARENA_TITLE: 'Complete the titan arena',
  229. DUNGEON: 'Dungeon',
  230. DUNGEON_TITLE: 'Go through the dungeon',
  231. DUNGEON2: 'Dungeon full',
  232. DUNGEON_FULL_TITLE: 'Dungeon for Full Titans',
  233. STOP_DUNGEON: 'Stop Dungeon',
  234. STOP_DUNGEON_TITLE: 'Stop digging the dungeon',
  235. SEER: 'Seer',
  236. SEER_TITLE: 'Roll the Seer',
  237. TOWER: 'Tower',
  238. TOWER_TITLE: 'Pass the tower',
  239. EXPEDITIONS: 'Expeditions',
  240. EXPEDITIONS_TITLE: 'Sending and collecting expeditions',
  241. SYNC: 'Sync',
  242. SYNC_TITLE: 'Partial synchronization of game data without reloading the page',
  243. ARCHDEMON: 'Archdemon',
  244. ARCHDEMON_TITLE: 'Hitting kills and collecting rewards',
  245. CRUCIBLE_SOULS: 'Crucible',
  246. CRUCIBLE_SOULS_TITLE: 'Fill the kilos in the crucible of souls',
  247. ESTER_EGGS: 'Easter eggs',
  248. ESTER_EGGS_TITLE: 'Collect all Easter eggs or rewards',
  249. REWARDS: 'Rewards',
  250. REWARDS_TITLE: 'Collect all quest rewards',
  251. MAIL: 'Mail',
  252. MAIL_TITLE: 'Collect all mail, except letters with energy and charges of the portal',
  253. MINIONS: 'Minions',
  254. MINIONS_TITLE: 'Attack minions with saved packs',
  255. ADVENTURE: 'Adventure',
  256. ADVENTURE_TITLE: 'Passes the adventure along the specified route',
  257. STORM: 'Storm',
  258. STORM_TITLE: 'Passes the Storm along the specified route',
  259. SANCTUARY: 'Sanctuary',
  260. SANCTUARY_TITLE: 'Fast travel to Sanctuary',
  261. GUILD_WAR: 'Guild War',
  262. GUILD_WAR_TITLE: 'Fast travel to Guild War',
  263. SECRET_WEALTH: 'Secret Wealth',
  264. SECRET_WEALTH_TITLE: 'Buy something in the store "Secret Wealth"',
  265. /* Misc */
  266. BOTTOM_URLS: '<a href="https://t.me/+q6gAGCRpwyFkNTYy" target="_blank" title="Telegram"><svg style="margin: 2px;" width="20" height="20" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient x1="50%" y1="0%" x2="50%" y2="99.2583404%" id="linearGradient-1"><stop stop-color="#2AABEE" offset="0%"></stop><stop stop-color="#229ED9" offset="100%"></stop></linearGradient></defs><g id="Artboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><circle id="Oval" fill="url(#linearGradient-1)" cx="500" cy="500" r="500"></circle><path d="M226.328419,494.722069 C372.088573,431.216685 469.284839,389.350049 517.917216,369.122161 C656.772535,311.36743 685.625481,301.334815 704.431427,301.003532 C708.567621,300.93067 717.815839,301.955743 723.806446,306.816707 C728.864797,310.92121 730.256552,316.46581 730.922551,320.357329 C731.588551,324.248848 732.417879,333.113828 731.758626,340.040666 C724.234007,419.102486 691.675104,610.964674 675.110982,699.515267 C668.10208,736.984342 654.301336,749.547532 640.940618,750.777006 C611.904684,753.448938 589.856115,731.588035 561.733393,713.153237 C517.726886,684.306416 492.866009,666.349181 450.150074,638.200013 C400.78442,605.66878 432.786119,587.789048 460.919462,558.568563 C468.282091,550.921423 596.21508,434.556479 598.691227,424.000355 C599.00091,422.680135 599.288312,417.758981 596.36474,415.160431 C593.441168,412.561881 589.126229,413.450484 586.012448,414.157198 C581.598758,415.158943 511.297793,461.625274 375.109553,553.556189 C355.154858,567.258623 337.080515,573.934908 320.886524,573.585046 C303.033948,573.199351 268.692754,563.490928 243.163606,555.192408 C211.851067,545.013936 186.964484,539.632504 189.131547,522.346309 C190.260287,513.342589 202.659244,504.134509 226.328419,494.722069 Z" id="Path-3" fill="#FFFFFF"></path></g></svg></a><a href="https://vk.com/invite/YNPxKGX" target="_blank" title="Вконтакте"><svg style="margin: 2px;" width="20" height="20" viewBox="0 0 101 100" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_2_40)"><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="#0077FF"/><path d="M53.7085 72.042C30.9168 72.042 17.9169 56.417 17.3752 30.417H28.7919C29.1669 49.5003 37.5834 57.5836 44.25 59.2503V30.417H55.0004V46.8752C61.5837 46.1669 68.4995 38.667 70.8329 30.417H81.5832C79.7915 40.5837 72.2915 48.0836 66.9582 51.1669C72.2915 53.6669 80.8336 60.2086 84.0836 72.042H72.2499C69.7082 64.1253 63.3754 58.0003 55.0004 57.1669V72.042H53.7085Z" fill="white"/></g><defs><clipPath id="clip0_2_40"><rect width="100" height="100" fill="white" transform="translate(0.5)"/></clipPath></defs></svg></a>',
  267. GIFTS_SENT: 'Gifts sent!',
  268. DO_YOU_WANT: 'Do you really want to do this?',
  269. BTN_RUN: 'Run',
  270. BTN_CANCEL: 'Cancel',
  271. BTN_OK: 'OK',
  272. MSG_HAVE_BEEN_DEFEATED: 'You have been defeated!',
  273. BTN_AUTO: 'Auto',
  274. MSG_YOU_APPLIED: 'You applied',
  275. MSG_DAMAGE: 'damage',
  276. MSG_CANCEL_AND_STAT: 'Auto (F5) and show statistic',
  277. MSG_REPEAT_MISSION: 'Repeat the mission?',
  278. BTN_REPEAT: 'Repeat',
  279. BTN_NO: 'No',
  280. MSG_SPECIFY_QUANT: 'Specify Quantity:',
  281. BTN_OPEN: 'Open',
  282. QUESTION_COPY: 'Question copied to clipboard',
  283. ANSWER_KNOWN: 'The answer is known',
  284. ANSWER_NOT_KNOWN: 'ATTENTION THE ANSWER IS NOT KNOWN',
  285. BEING_RECALC: 'The battle is being recalculated',
  286. THIS_TIME: 'This time',
  287. VICTORY: '<span style="color:green;">VICTORY</span>',
  288. DEFEAT: '<span style="color:red;">DEFEAT</span>',
  289. CHANCE_TO_WIN: 'Chance to win <span style="color: red;">based on pre-calculation</span>',
  290. OPEN_DOLLS: 'nesting dolls recursively',
  291. SENT_QUESTION: 'Question sent',
  292. SETTINGS: 'Settings',
  293. MSG_BAN_ATTENTION: '<p style="color:red;">Using this feature may result in a ban.</p> Continue?',
  294. BTN_YES_I_AGREE: 'Yes, I understand the risks!',
  295. BTN_NO_I_AM_AGAINST: 'No, I refuse it!',
  296. VALUES: 'Values',
  297. SAVING: 'Saving',
  298. USER_ID: 'User Id',
  299. SEND_GIFT: 'The gift has been sent',
  300. EXPEDITIONS_SENT: 'Expeditions sent',
  301. TITANIT: 'Titanit',
  302. COMPLETED: 'completed',
  303. FLOOR: 'Floor',
  304. LEVEL: 'Level',
  305. BATTLES: 'battles',
  306. EVENT: 'Event',
  307. NOT_AVAILABLE: 'not available',
  308. NO_HEROES: 'No heroes',
  309. DAMAGE_AMOUNT: 'Damage amount',
  310. NOTHING_TO_COLLECT: 'Nothing to collect',
  311. COLLECTED: 'Collected',
  312. REWARD: 'rewards',
  313. REMAINING_ATTEMPTS: 'Remaining attempts',
  314. BATTLES_CANCELED: 'Battles canceled',
  315. MINION_RAID: 'Minion Raid',
  316. STOPPED: 'Stopped',
  317. REPETITIONS: 'Repetitions',
  318. MISSIONS_PASSED: 'Missions passed',
  319. STOP: 'stop',
  320. TOTAL_OPEN: 'Total open',
  321. OPEN: 'Open',
  322. ROUND_STAT: 'Damage statistics for ',
  323. BATTLE: 'battles',
  324. MINIMUM: 'Minimum',
  325. MAXIMUM: 'Maximum',
  326. AVERAGE: 'Average',
  327. NOT_THIS_TIME: 'Not this time',
  328. RETRY_LIMIT_EXCEEDED: 'Retry limit exceeded',
  329. SUCCESS: 'Success',
  330. RECEIVED: 'Received',
  331. LETTERS: 'letters',
  332. PORTALS: 'portals',
  333. ATTEMPTS: 'attempts',
  334. /* Quests */
  335. QUEST_10001: 'Upgrade the skills of heroes 3 times',
  336. QUEST_10002: 'Complete 10 missions',
  337. QUEST_10003: 'Complete 3 heroic missions',
  338. QUEST_10004: 'Fight 3 times in the Arena or Grand Arena',
  339. QUEST_10006: 'Use the exchange of emeralds 1 time',
  340. QUEST_10007: 'Perform 1 summon in the Solu Atrium',
  341. QUEST_10016: 'Send gifts to guildmates',
  342. QUEST_10018: 'Use an experience potion',
  343. QUEST_10019: 'Open 1 chest in the Tower',
  344. QUEST_10020: 'Open 3 chests in Outland',
  345. QUEST_10021: 'Collect 75 Titanite in the Guild Dungeon',
  346. QUEST_10021: 'Collect 150 Titanite in the Guild Dungeon',
  347. QUEST_10023: 'Upgrade Gift of the Elements by 1 level',
  348. QUEST_10024: 'Level up any artifact once',
  349. QUEST_10025: 'Start Expedition 1',
  350. QUEST_10026: 'Start 4 Expeditions',
  351. QUEST_10027: 'Win 1 battle of the Tournament of Elements',
  352. QUEST_10028: 'Level up any titan artifact',
  353. QUEST_10029: 'Unlock the Orb of Titan Artifacts',
  354. QUEST_10030: 'Upgrade any Skin of any hero 1 time',
  355. QUEST_10031: 'Win 6 battles of the Tournament of Elements',
  356. QUEST_10043: 'Start or Join an Adventure',
  357. QUEST_10044: 'Use Summon Pets 1 time',
  358. QUEST_10046: 'Open 3 chests in Adventure',
  359. QUEST_10047: 'Get 150 Guild Activity Points',
  360. NOTHING_TO_DO: 'Nothing to do',
  361. YOU_CAN_COMPLETE: 'You can complete quests',
  362. BTN_DO_IT: 'Do it',
  363. NOT_QUEST_COMPLETED: 'Not a single quest completed',
  364. COMPLETED_QUESTS: 'Completed quests',
  365. /* everything button */
  366. ASSEMBLE_OUTLAND: 'Assemble Outland',
  367. PASS_THE_TOWER: 'Pass the tower',
  368. CHECK_EXPEDITIONS: 'Check Expeditions',
  369. COMPLETE_TOE: 'Complete ToE',
  370. COMPLETE_DUNGEON: 'Complete the dungeon',
  371. COMPLETE_DUNGEON_FULL: 'Complete the dungeon for Full Titans',
  372. COLLECT_MAIL: 'Collect mail',
  373. COLLECT_MISC: 'Collect some bullshit',
  374. COLLECT_MISC_TITLE: 'Collect Easter Eggs, Skin Gems, Keys, Arena Coins and Soul Crystal',
  375. COLLECT_QUEST_REWARDS: 'Collect quest rewards',
  376. MAKE_A_SYNC: 'Make a sync',
  377.  
  378. RUN_FUNCTION: 'Run the following functions?',
  379. BTN_GO: 'Go!',
  380. PERFORMED: 'Performed',
  381. DONE: 'Done',
  382. ERRORS_OCCURRES: 'Errors occurred while executing',
  383. COPY_ERROR: 'Copy error information to clipboard',
  384. BTN_YES: 'Yes',
  385. ALL_TASK_COMPLETED: 'All tasks completed',
  386.  
  387. UNKNOWN: 'unknown',
  388. ENTER_THE_PATH: 'Enter the path of adventure using commas or dashes',
  389. START_ADVENTURE: 'Start your adventure along this path!',
  390. INCORRECT_WAY: 'Incorrect path in adventure: {from} -> {to}',
  391. BTN_CANCELED: 'Canceled',
  392. MUST_TWO_POINTS: 'The path must contain at least 2 points.',
  393. MUST_ONLY_NUMBERS: 'The path must contain only numbers and commas',
  394. NOT_ON_AN_ADVENTURE: 'You are not on an adventure',
  395. YOU_IN_NOT_ON_THE_WAY: 'Your location is not on the way',
  396. ATTEMPTS_NOT_ENOUGH: 'Your attempts are not enough to complete the path, continue?',
  397. YES_CONTINUE: 'Yes, continue!',
  398. NOT_ENOUGH_AP: 'Not enough action points',
  399. ATTEMPTS_ARE_OVER: 'The attempts are over',
  400. MOVES: 'Moves',
  401. BUFF_GET_ERROR: 'Buff getting error',
  402. BATTLE_END_ERROR: 'Battle end error',
  403. AUTOBOT: 'Autobot',
  404. FAILED_TO_WIN_AUTO: 'Failed to win the auto battle',
  405. ERROR_OF_THE_BATTLE_COPY: 'An error occurred during the passage of the battle<br>Copy the error to the clipboard?',
  406. ERROR_DURING_THE_BATTLE: 'Error during the battle',
  407. NO_CHANCE_WIN: 'No chance of winning this fight: 0/',
  408. LOST_HEROES: 'You have won, but you have lost one or several heroes',
  409. VICTORY_IMPOSSIBLE: 'Is victory impossible, should we focus on the result?',
  410. FIND_COEFF: 'Find the coefficient greater than',
  411. BTN_PASS: 'PASS',
  412. BRAWLS: 'Brawls',
  413. BRAWLS_TITLE: 'Activates the ability to auto-brawl',
  414. START_AUTO_BRAWLS: 'Start Auto Brawls?',
  415. LOSSES: 'Losses',
  416. WINS: 'Wins',
  417. FIGHTS: 'Fights',
  418. STAGE: 'Stage',
  419. DONT_HAVE_LIVES: "You don't have lives",
  420. LIVES: 'Lives',
  421. SECRET_WEALTH_ALREADY: 'Item for Pet Potions already purchased',
  422. SECRET_WEALTH_NOT_ENOUGH: 'Not Enough Pet Potion, You Have {available}, Need {need}',
  423. SECRET_WEALTH_UPGRADE_NEW_PET: 'After purchasing the Pet Potion, it will not be enough to upgrade a new pet',
  424. SECRET_WEALTH_PURCHASED: 'Purchased {count} {name}',
  425. SECRET_WEALTH_CANCELED: 'Secret Wealth: Purchase Canceled',
  426. SECRET_WEALTH_BUY: 'You have {available} Pet Potion.<br>Do you want to buy {countBuy} {name} for {price} Pet Potion?',
  427. DAILY_BONUS: 'Daily bonus',
  428. DO_DAILY_QUESTS: 'Do daily quests',
  429. ACTIONS: 'Actions',
  430. ACTIONS_TITLE: 'Dialog box with various actions',
  431. OTHERS: 'Others',
  432. OTHERS_TITLE: 'Others',
  433. CHOOSE_ACTION: 'Choose an action',
  434. OPEN_LOOTBOX: 'You have {lootBox} boxes, should we open them?',
  435. STAMINA: 'Energy',
  436. BOXES_OVER: 'The boxes are over',
  437. NO_BOXES: 'No boxes',
  438. NO_MORE_ACTIVITY: 'No more activity for items today',
  439. EXCHANGE_ITEMS: 'Exchange items for activity points (max {maxActive})?',
  440. GET_ACTIVITY: 'Get Activity',
  441. NOT_ENOUGH_ITEMS: 'Not enough items',
  442. ACTIVITY_RECEIVED: 'Activity received',
  443. NO_PURCHASABLE_HERO_SOULS: 'No purchasable Hero Souls',
  444. PURCHASED_HERO_SOULS: 'Purchased {countHeroSouls} Hero Souls',
  445. NOT_ENOUGH_EMERALDS_540: 'Not enough emeralds, you need 540 you have {currentStarMoney}',
  446. CHESTS_NOT_AVAILABLE: 'Chests not available',
  447. OUTLAND_CHESTS_RECEIVED: 'Outland chests received',
  448. RAID_NOT_AVAILABLE: 'The raid is not available or there are no spheres',
  449. RAID_ADVENTURE: 'Raid {adventureId} adventure!',
  450. SOMETHING_WENT_WRONG: 'Something went wrong',
  451. ADVENTURE_COMPLETED: 'Adventure {adventureId} completed {times} times',
  452. CLAN_STAT_COPY: 'Clan statistics copied to clipboard',
  453. GET_ENERGY: 'Get Energy',
  454. GET_ENERGY_TITLE: 'Opens platinum boxes one at a time until you get 250 energy',
  455. ITEM_EXCHANGE: 'Item Exchange',
  456. ITEM_EXCHANGE_TITLE: 'Exchanges items for the specified amount of activity',
  457. BUY_SOULS: 'Buy souls',
  458. BUY_SOULS_TITLE: 'Buy hero souls from all available shops',
  459. BUY_OUTLAND: 'Buy Outland',
  460. BUY_OUTLAND_TITLE: 'Buy 9 chests in Outland for 540 emeralds',
  461. RAID: 'Raid',
  462. AUTO_RAID_ADVENTURE: 'Raid adventure',
  463. AUTO_RAID_ADVENTURE_TITLE: 'Raid adventure set number of times',
  464. CLAN_STAT: 'Clan statistics',
  465. CLAN_STAT_TITLE: 'Copies clan statistics to the clipboard',
  466. BTN_AUTO_F5: 'Auto (F5)',
  467. BOSS_DAMAGE: 'Boss Damage: ',
  468. NOTHING_BUY: 'Nothing to buy',
  469. LOTS_BOUGHT: '{countBuy} lots bought for gold',
  470. BUY_FOR_GOLD: 'Buy for gold',
  471. BUY_FOR_GOLD_TITLE: 'Buy items for gold in the Town Shop and in the Pet Soul Stone Shop',
  472. REWARDS_AND_MAIL: 'Rewars and Mail',
  473. REWARDS_AND_MAIL_TITLE: 'Collects rewards and mail',
  474. New_Year_Clan: 'a gift for a friend',
  475. New_Year_Clan_TITLE: 'New Year gifts to friends',
  476. COLLECT_REWARDS_AND_MAIL: 'Collected {countQuests} rewards and {countMail} letters',
  477. TIMER_ALREADY: 'Timer already started {time}',
  478. NO_ATTEMPTS_TIMER_START: 'No attempts, timer started {time}',
  479. EPIC_BRAWL_RESULT: 'Wins: {wins}/{attempts}, Coins: {coins}, Streak: {progress}/{nextStage} [Close]{end}',
  480. ATTEMPT_ENDED: '<br>Attempts ended, timer started {time}',
  481. EPIC_BRAWL: 'Cosmic Battle',
  482. EPIC_BRAWL_TITLE: 'Spends attempts in the Cosmic Battle',
  483. RELOAD_GAME: 'Reload game',
  484. TIMER: 'Timer:',
  485. SHOW_ERRORS: 'Show errors',
  486. SHOW_ERRORS_TITLE: 'Show server request errors',
  487. ERROR_MSG: 'Error: {name}<br>{description}',
  488. 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?',
  489. BEST_SLOW: 'Best (slower)',
  490. FIRST_FAST: 'First (faster)',
  491. FREEZE_INTERFACE: 'Calculating... <br>The interface may freeze.',
  492. ERROR_F12: 'Error, details in the console (F12)',
  493. FAILED_FIND_WIN_PACK: 'Failed to find a winning pack',
  494. BEST_PACK: 'Best pack:',
  495. BOSS_HAS_BEEN_DEF: 'Boss {bossLvl} has been defeated.',
  496. NOT_ENOUGH_ATTEMPTS_BOSS: 'Not enough attempts to defeat boss {bossLvl}, retry?',
  497. 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?',
  498. BOSS_HAS_BEEN_DEF_TEXT: 'Boss {bossLvl} defeated in<br>{countBattle}/{countMaxBattle} attempts<br>(Please synchronize or restart the game to update the data)',
  499. MAP: 'Map: ',
  500. PLAYER_POS: 'Player positions:',
  501. NY_GIFTS: 'Gifts',
  502. NY_GIFTS_TITLE: "Open all New Year's gifts",
  503. NY_NO_GIFTS: 'No gifts not received',
  504. NY_GIFTS_COLLECTED: '{count} gifts collected',
  505. CHANGE_MAP: 'Island map',
  506. CHANGE_MAP_TITLE: 'Change island map',
  507. SELECT_ISLAND_MAP: 'Select an island map:',
  508. FIRST_MAP: 'First map',
  509. SECOND_MAP: 'Second map',
  510. THIRD_MAP: 'Third card',
  511. SECRET_WEALTH_SHOP: 'Secret Wealth {name}: ',
  512. SHOPS: 'Shops',
  513. SHOPS_DEFAULT: 'Default',
  514. SHOPS_DEFAULT_TITLE: 'Default stores',
  515. SHOPS_LIST: 'Shops {number}',
  516. SHOPS_LIST_TITLE: 'List of shops {number}',
  517. 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>',
  518. MINIONS_WARNING: 'The hero packs for attacking minions are incomplete, should I continue?',
  519. FAST_SEASON: 'Fast season',
  520. FAST_SEASON_TITLE: 'Skip the map selection screen in a season',
  521. SET_NUMBER_LEVELS: 'Specify the number of levels:',
  522. POSSIBLE_IMPROVE_LEVELS: 'It is possible to improve only {count} levels.<br>Improving?',
  523. NOT_ENOUGH_RESOURECES: 'Not enough resources',
  524. IMPROVED_LEVELS: 'Improved levels: {count}',
  525. ARTIFACTS_UPGRADE: 'Artifacts Upgrade',
  526. ARTIFACTS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero artifacts',
  527. SKINS_UPGRADE: 'Skins Upgrade',
  528. SKINS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero skins',
  529. HINT: '<br>Hint: ',
  530. PICTURE: '<br>Picture: ',
  531. ANSWER: '<br>Answer: ',
  532. NO_HEROES_PACK: 'Fight at least one battle to save the attacking team',
  533. },
  534. ru: {
  535. /* Чекбоксы */
  536. SKIP_FIGHTS: 'Пропуск боев',
  537. SKIP_FIGHTS_TITLE: 'Пропуск боев в запределье и арене титанов, автопропуск в башне и кампании',
  538. ENDLESS_CARDS: 'Бесконечные карты',
  539. ENDLESS_CARDS_TITLE: 'Отключить трату карт предсказаний',
  540. AUTO_EXPEDITION: 'АвтоЭкспедиции',
  541. AUTO_EXPEDITION_TITLE: 'Автоотправка экспедиций',
  542. CANCEL_FIGHT: 'Отмена боя',
  543. CANCEL_FIGHT_TITLE: 'Возможность отмены боя на ВГ, СМ и в Асгарде',
  544. GIFTS: 'Подарки',
  545. GIFTS_TITLE: 'Собирать подарки автоматически',
  546. BATTLE_RECALCULATION: 'Прерасчет боя',
  547. BATTLE_RECALCULATION_TITLE: 'Предварительный расчет боя',
  548. BATTLE_FISHING: 'Добивание',
  549. BATTLE_FISHING_TITLE: 'Добивание в чате команды из последнего реплея',
  550. BATTLE_TRENING: 'Тренировка',
  551. BATTLE_TRENING_TITLE: 'Тренировочный бой в чате против команды из последнего реплея',
  552. QUANTITY_CONTROL: 'Контроль кол-ва',
  553. QUANTITY_CONTROL_TITLE: 'Возможность указывать количество открываемых "лутбоксов"',
  554. REPEAT_CAMPAIGN: 'Повтор в компании',
  555. REPEAT_CAMPAIGN_TITLE: 'Автоповтор боев в кампании',
  556. DISABLE_DONAT: 'Отключить донат',
  557. DISABLE_DONAT_TITLE: 'Убирает все предложения доната',
  558. DAILY_QUESTS: 'Квесты',
  559. DAILY_QUESTS_TITLE: 'Выполнять ежедневные квесты',
  560. AUTO_QUIZ: 'АвтоВикторина',
  561. AUTO_QUIZ_TITLE: 'Автоматическое получение правильных ответов на вопросы викторины',
  562. SECRET_WEALTH_CHECKBOX: 'Автоматическая покупка в магазине "Тайное Богатство" при заходе в игру',
  563. HIDE_SERVERS: 'Свернуть сервера',
  564. HIDE_SERVERS_TITLE: 'Скрывать неиспользуемые сервера',
  565. /* Поля ввода */
  566. HOW_MUCH_TITANITE: 'Сколько фармим титанита',
  567. COMBAT_SPEED: 'Множитель ускорения боя',
  568. HOW_REPEAT_CAMPAIGN: 'Сколько повторов миссий', //тест добавил
  569. NUMBER_OF_TEST: 'Количество тестовых боев',
  570. NUMBER_OF_AUTO_BATTLE: 'Количество попыток автобоев',
  571. USER_ID_TITLE: 'Введите айди игрока',
  572. AMOUNT: 'Количество отправляемых подарков',
  573. GIFT_NUM: 'Номер подарка, 1 - развитие героев, 2 - питомцы, 3 - света, 4 - тьмы, 5 - вознесения, 6 - облик',
  574. /* Кнопки */
  575. RUN_SCRIPT: 'Запустить скрипт',
  576. STOP_SCRIPT: 'Остановить скрипт',
  577. TO_DO_EVERYTHING: 'Сделать все',
  578. TO_DO_EVERYTHING_TITLE: 'Выполнить несколько действий',
  579. OUTLAND: 'Запределье',
  580. OUTLAND_TITLE: 'Собрать Запределье',
  581. TITAN_ARENA: 'Турнир Стихий',
  582. TITAN_ARENA_TITLE: 'Автопрохождение Турнира Стихий',
  583. DUNGEON: 'Подземелье',
  584. DUNGEON_TITLE: 'Автопрохождение подземелья',
  585. DUNGEON2: 'Подземелье фулл',
  586. DUNGEON_FULL_TITLE: 'Подземелье для фуловых титанов',
  587. STOP_DUNGEON: 'Стоп подземка',
  588. STOP_DUNGEON_TITLE: 'Остановить копание подземелья',
  589. SEER: 'Провидец',
  590. SEER_TITLE: 'Покрутить Провидца',
  591. TOWER: 'Башня',
  592. TOWER_TITLE: 'Автопрохождение башни',
  593. EXPEDITIONS: 'Экспедиции',
  594. EXPEDITIONS_TITLE: 'Отправка и сбор экспедиций',
  595. SYNC: 'Синхронизация',
  596. SYNC_TITLE: 'Частичная синхронизация данных игры без перезагрузки сатраницы',
  597. ARCHDEMON: 'Архидемон',
  598. ARCHDEMON_TITLE: 'Набивает килы и собирает награду',
  599. CRUCIBLE_SOULS: 'Горнило душ',
  600. CRUCIBLE_SOULS_TITLE:'Набить килов в горниле душ',
  601. ESTER_EGGS: 'Пасхалки',
  602. ESTER_EGGS_TITLE: 'Собрать все пасхалки или награды',
  603. REWARDS: 'Награды',
  604. REWARDS_TITLE: 'Собрать все награды за задания',
  605. MAIL: 'Почта',
  606. MAIL_TITLE: 'Собрать всю почту, кроме писем с энергией и зарядами портала',
  607. MINIONS: 'Прислужники',
  608. MINIONS_TITLE: 'Атакует прислужников сохраннеными пачками',
  609. ADVENTURE: 'Приключение',
  610. ADVENTURE_TITLE: 'Проходит приключение по указанному маршруту',
  611. STORM: 'Буря',
  612. STORM_TITLE: 'Проходит бурю по указанному маршруту',
  613. SANCTUARY: 'Святилище',
  614. SANCTUARY_TITLE: 'Быстрый переход к Святилищу',
  615. GUILD_WAR: 'Война гильдий',
  616. GUILD_WAR_TITLE: 'Быстрый переход к Войне гильдий',
  617. SECRET_WEALTH: 'Тайное богатство',
  618. SECRET_WEALTH_TITLE: 'Купить что-то в магазине "Тайное богатство"',
  619. /* Разное */
  620. BOTTOM_URLS: '<a href="https://t.me/+q6gAGCRpwyFkNTYy" target="_blank" title="Telegram"><svg style="margin: 2px;" width="20" height="20" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient x1="50%" y1="0%" x2="50%" y2="99.2583404%" id="linearGradient-1"><stop stop-color="#2AABEE" offset="0%"></stop><stop stop-color="#229ED9" offset="100%"></stop></linearGradient></defs><g id="Artboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><circle id="Oval" fill="url(#linearGradient-1)" cx="500" cy="500" r="500"></circle><path d="M226.328419,494.722069 C372.088573,431.216685 469.284839,389.350049 517.917216,369.122161 C656.772535,311.36743 685.625481,301.334815 704.431427,301.003532 C708.567621,300.93067 717.815839,301.955743 723.806446,306.816707 C728.864797,310.92121 730.256552,316.46581 730.922551,320.357329 C731.588551,324.248848 732.417879,333.113828 731.758626,340.040666 C724.234007,419.102486 691.675104,610.964674 675.110982,699.515267 C668.10208,736.984342 654.301336,749.547532 640.940618,750.777006 C611.904684,753.448938 589.856115,731.588035 561.733393,713.153237 C517.726886,684.306416 492.866009,666.349181 450.150074,638.200013 C400.78442,605.66878 432.786119,587.789048 460.919462,558.568563 C468.282091,550.921423 596.21508,434.556479 598.691227,424.000355 C599.00091,422.680135 599.288312,417.758981 596.36474,415.160431 C593.441168,412.561881 589.126229,413.450484 586.012448,414.157198 C581.598758,415.158943 511.297793,461.625274 375.109553,553.556189 C355.154858,567.258623 337.080515,573.934908 320.886524,573.585046 C303.033948,573.199351 268.692754,563.490928 243.163606,555.192408 C211.851067,545.013936 186.964484,539.632504 189.131547,522.346309 C190.260287,513.342589 202.659244,504.134509 226.328419,494.722069 Z" id="Path-3" fill="#FFFFFF"></path></g></svg></a><a href="https://vk.com/invite/YNPxKGX" target="_blank" title="Вконтакте"><svg style="margin: 2px;" width="20" height="20" viewBox="0 0 101 100" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_2_40)"><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="#0077FF"/><path d="M53.7085 72.042C30.9168 72.042 17.9169 56.417 17.3752 30.417H28.7919C29.1669 49.5003 37.5834 57.5836 44.25 59.2503V30.417H55.0004V46.8752C61.5837 46.1669 68.4995 38.667 70.8329 30.417H81.5832C79.7915 40.5837 72.2915 48.0836 66.9582 51.1669C72.2915 53.6669 80.8336 60.2086 84.0836 72.042H72.2499C69.7082 64.1253 63.3754 58.0003 55.0004 57.1669V72.042H53.7085Z" fill="white"/></g><defs><clipPath id="clip0_2_40"><rect width="100" height="100" fill="white" transform="translate(0.5)"/></clipPath></defs></svg></a>',
  621. GIFTS_SENT: 'Подарки отправлены!',
  622. DO_YOU_WANT: 'Вы действительно хотите это сделать?',
  623. BTN_RUN: 'Запускай',
  624. BTN_CANCEL: 'Отмена',
  625. BTN_OK: 'Ок',
  626. MSG_HAVE_BEEN_DEFEATED: 'Вы потерпели поражение!',
  627. BTN_AUTO: 'Авто',
  628. MSG_YOU_APPLIED: 'Вы нанесли',
  629. MSG_DAMAGE: 'урона',
  630. MSG_CANCEL_AND_STAT: 'Авто (F5) и показать Статистику',
  631. MSG_REPEAT_MISSION: 'Повторить миссию?',
  632. BTN_REPEAT: 'Повторить',
  633. BTN_NO: 'Нет',
  634. MSG_SPECIFY_QUANT: 'Указать количество:',
  635. BTN_OPEN: 'Открыть',
  636. QUESTION_COPY: 'Вопрос скопирован в буфер обмена',
  637. ANSWER_KNOWN: 'Ответ известен',
  638. ANSWER_NOT_KNOWN: 'ВНИМАНИЕ ОТВЕТ НЕ ИЗВЕСТЕН',
  639. BEING_RECALC: 'Идет прерасчет боя',
  640. THIS_TIME: 'На этот раз',
  641. VICTORY: '<span style="color:green;">ПОБЕДА</span>',
  642. DEFEAT: '<span style="color:red;">ПОРАЖЕНИЕ</span>',
  643. CHANCE_TO_WIN: 'Шансы на победу <span style="color:red;">на основе прерасчета</span>',
  644. OPEN_DOLLS: 'матрешек рекурсивно',
  645. SENT_QUESTION: 'Вопрос отправлен',
  646. SETTINGS: 'Настройки',
  647. MSG_BAN_ATTENTION: '<p style="color:red;">Использование этой функции может привести к бану.</p> Продолжить?',
  648. BTN_YES_I_AGREE: 'Да, я беру на себя все риски!',
  649. BTN_NO_I_AM_AGAINST: 'Нет, я отказываюсь от этого!',
  650. VALUES: 'Значения',
  651. SAVING: 'Сохранка',
  652. USER_ID: 'айди пользователя',
  653. SEND_GIFT: 'Подарок отправлен',
  654. EXPEDITIONS_SENT: 'Экспедиции отправлены',
  655. TITANIT: 'Титанит',
  656. COMPLETED: 'завершено',
  657. FLOOR: 'Этаж',
  658. LEVEL: 'Уровень',
  659. BATTLES: 'бои',
  660. EVENT: 'Эвент',
  661. NOT_AVAILABLE: 'недоступен',
  662. NO_HEROES: 'Нет героев',
  663. DAMAGE_AMOUNT: 'Количество урона',
  664. NOTHING_TO_COLLECT: 'Нечего собирать',
  665. COLLECTED: 'Собрано',
  666. REWARD: 'наград',
  667. REMAINING_ATTEMPTS: 'Осталось попыток',
  668. BATTLES_CANCELED: 'Битв отменено',
  669. MINION_RAID: 'Рейд прислужников',
  670. STOPPED: 'Остановлено',
  671. REPETITIONS: 'Повторений',
  672. MISSIONS_PASSED: 'Миссий пройдено',
  673. STOP: 'остановить',
  674. TOTAL_OPEN: 'Всего открыто',
  675. OPEN: 'Открыто',
  676. ROUND_STAT: 'Статистика урона за',
  677. BATTLE: 'боев',
  678. MINIMUM: 'Минимальный',
  679. MAXIMUM: 'Максимальный',
  680. AVERAGE: 'Средний',
  681. NOT_THIS_TIME: 'Не в этот раз',
  682. RETRY_LIMIT_EXCEEDED: 'Превышен лимит попыток',
  683. SUCCESS: 'Успех',
  684. RECEIVED: 'Получено',
  685. LETTERS: 'писем',
  686. PORTALS: 'порталов',
  687. ATTEMPTS: 'попыток',
  688. QUEST_10001: 'Улучши умения героев 3 раза',
  689. QUEST_10002: 'Пройди 10 миссий',
  690. QUEST_10003: 'Пройди 3 героические миссии',
  691. QUEST_10004: 'Сразись 3 раза на Арене или Гранд Арене',
  692. QUEST_10006: 'Используй обмен изумрудов 1 раз',
  693. QUEST_10007: 'Соверши 1 призыв в Атриуме Душ',
  694. QUEST_10016: 'Отправь подарки согильдийцам',
  695. QUEST_10018: 'Используй зелье опыта',
  696. QUEST_10019: 'Открой 1 сундук в Башне',
  697. QUEST_10020: 'Открой 3 сундука в Запределье',
  698. QUEST_10021: 'Собери 75 Титанита в Подземелье Гильдии',
  699. QUEST_10021: 'Собери 150 Титанита в Подземелье Гильдии',
  700. QUEST_10023: 'Прокачай Дар Стихий на 1 уровень',
  701. QUEST_10024: 'Повысь уровень любого артефакта один раз',
  702. QUEST_10025: 'Начни 1 Экспедицию',
  703. QUEST_10026: 'Начни 4 Экспедиции',
  704. QUEST_10027: 'Победи в 1 бою Турнира Стихий',
  705. QUEST_10028: 'Повысь уровень любого артефакта титанов',
  706. QUEST_10029: 'Открой сферу артефактов титанов',
  707. QUEST_10030: 'Улучши облик любого героя 1 раз',
  708. QUEST_10031: 'Победи в 6 боях Турнира Стихий',
  709. QUEST_10043: 'Начни или присоеденись к Приключению',
  710. QUEST_10044: 'Воспользуйся призывом питомцев 1 раз',
  711. QUEST_10046: 'Открой 3 сундука в Приключениях',
  712. QUEST_10047: 'Набери 150 очков активности в Гильдии',
  713. NOTHING_TO_DO: 'Нечего выполнять',
  714. YOU_CAN_COMPLETE: 'Можно выполнить квесты',
  715. BTN_DO_IT: 'Выполняй',
  716. NOT_QUEST_COMPLETED: 'Ни одного квеста не выполенно',
  717. COMPLETED_QUESTS: 'Выполнено квестов',
  718. /* everything button */
  719. ASSEMBLE_OUTLAND: 'Собрать Запределье',
  720. PASS_THE_TOWER: 'Пройти башню',
  721. CHECK_EXPEDITIONS: 'Проверить экспедиции',
  722. COMPLETE_TOE: 'Пройти Турнир Стихий',
  723. COMPLETE_DUNGEON: 'Пройти подземелье',
  724. COMPLETE_DUNGEON_FULL: 'Пройти подземелье фулл',
  725. COLLECT_MAIL: 'Собрать почту',
  726. COLLECT_MISC: 'Собрать всякую херню',
  727. COLLECT_MISC_TITLE: 'Собрать пасхалки, камни облика, ключи, монеты арены и Хрусталь души',
  728. COLLECT_QUEST_REWARDS: 'Собрать награды за квесты',
  729. MAKE_A_SYNC: 'Сделать синхронизацию',
  730.  
  731. RUN_FUNCTION: 'Выполнить следующие функции?',
  732. BTN_GO: 'Погнали!',
  733. PERFORMED: 'Выполняется',
  734. DONE: 'Выполнено',
  735. ERRORS_OCCURRES: 'Призошли ошибки при выполнении',
  736. COPY_ERROR: 'Скопировать в буфер информацию об ошибке',
  737. BTN_YES: 'Да',
  738. ALL_TASK_COMPLETED: 'Все задачи выполнены',
  739.  
  740. UNKNOWN: 'Неизвестно',
  741. ENTER_THE_PATH: 'Введите путь приключения через запятые или дефисы',
  742. START_ADVENTURE: 'Начать приключение по этому пути!',
  743. INCORRECT_WAY: 'Неверный путь в приключении: {from} -> {to}',
  744. BTN_CANCELED: 'Отменено',
  745. MUST_TWO_POINTS: 'Путь должен состоять минимум из 2х точек',
  746. MUST_ONLY_NUMBERS: 'Путь должен содержать только цифры и запятые',
  747. NOT_ON_AN_ADVENTURE: 'Вы не в приключении',
  748. YOU_IN_NOT_ON_THE_WAY: 'Указанный путь должен включать точку вашего положения',
  749. ATTEMPTS_NOT_ENOUGH: 'Ваших попыток не достаточно для завершения пути, продолжить?',
  750. YES_CONTINUE: 'Да, продолжай!',
  751. NOT_ENOUGH_AP: 'Попыток не достаточно',
  752. ATTEMPTS_ARE_OVER: 'Попытки закончились',
  753. MOVES: 'Ходы',
  754. BUFF_GET_ERROR: 'Ошибка при получении бафа',
  755. BATTLE_END_ERROR: 'Ошибка завершения боя',
  756. AUTOBOT: 'АвтоБой',
  757. FAILED_TO_WIN_AUTO: 'Не удалось победить в автобою',
  758. ERROR_OF_THE_BATTLE_COPY: 'Призошли ошибка в процессе прохождения боя<br>Скопировать ошибку в буфер обмена?',
  759. ERROR_DURING_THE_BATTLE: 'Ошибка в процессе прохождения боя',
  760. NO_CHANCE_WIN: 'Нет шансов победить в этом бою: 0/',
  761. LOST_HEROES: 'Вы победили, но потеряли одного или несколько героев!',
  762. VICTORY_IMPOSSIBLE: 'Победа не возможна, бъем на результат?',
  763. FIND_COEFF: 'Поиск коэффициента больше чем',
  764. BTN_PASS: 'ПРОПУСК',
  765. BRAWLS: 'Потасовки',
  766. BRAWLS_TITLE: 'Включает возможность автопотасовок',
  767. START_AUTO_BRAWLS: 'Запустить Автопотасовки?',
  768. LOSSES: 'Поражений',
  769. WINS: 'Побед',
  770. FIGHTS: 'Боев',
  771. STAGE: 'Стадия',
  772. DONT_HAVE_LIVES: 'У Вас нет жизней',
  773. LIVES: 'Жизни',
  774. SECRET_WEALTH_ALREADY: 'товар за Зелья питомцев уже куплен',
  775. SECRET_WEALTH_NOT_ENOUGH: 'Не достаточно Зелье Питомца, у Вас {available}, нужно {need}',
  776. SECRET_WEALTH_UPGRADE_NEW_PET: 'После покупки Зелье Питомца будет не достаточно для прокачки нового питомца',
  777. SECRET_WEALTH_PURCHASED: 'Куплено {count} {name}',
  778. SECRET_WEALTH_CANCELED: 'Тайное богатство: покупка отменена',
  779. SECRET_WEALTH_BUY: 'У вас {available} Зелье Питомца.<br>Вы хотите купить {countBuy} {name} за {price} Зелье Питомца?',
  780. DAILY_BONUS: 'Ежедневная награда',
  781. DO_DAILY_QUESTS: 'Сделать ежедневные квесты',
  782. ACTIONS: 'Действия',
  783. ACTIONS_TITLE: 'Диалоговое окно с различными действиями',
  784. OTHERS: 'Разное',
  785. OTHERS_TITLE: 'Диалоговое окно с дополнительными различными действиями',
  786. CHOOSE_ACTION: 'Выберите действие',
  787. OPEN_LOOTBOX: 'У Вас {lootBox} ящиков, откываем?',
  788. STAMINA: 'Энергия',
  789. BOXES_OVER: 'Ящики закончились',
  790. NO_BOXES: 'Нет ящиков',
  791. NO_MORE_ACTIVITY: 'Больше активности за предметы сегодня не получить',
  792. EXCHANGE_ITEMS: 'Обменять предметы на очки активности (не более {maxActive})?',
  793. GET_ACTIVITY: 'Получить активность',
  794. NOT_ENOUGH_ITEMS: 'Предметов недостаточно',
  795. ACTIVITY_RECEIVED: 'Получено активности',
  796. NO_PURCHASABLE_HERO_SOULS: 'Нет доступных для покупки душ героев',
  797. PURCHASED_HERO_SOULS: 'Куплено {countHeroSouls} душ героев',
  798. NOT_ENOUGH_EMERALDS_540: 'Недостаточно изюма, нужно 540 у Вас {currentStarMoney}',
  799. CHESTS_NOT_AVAILABLE: 'Сундуки не доступны',
  800. OUTLAND_CHESTS_RECEIVED: 'Получено сундуков Запределья',
  801. RAID_NOT_AVAILABLE: 'Рейд не доступен или сфер нет',
  802. RAID_ADVENTURE: 'Рейд {adventureId} приключения!',
  803. SOMETHING_WENT_WRONG: 'Что-то пошло не так',
  804. ADVENTURE_COMPLETED: 'Приключение {adventureId} пройдено {times} раз',
  805. CLAN_STAT_COPY: 'Клановая статистика скопирована в буфер обмена',
  806. GET_ENERGY: 'Получить энергию',
  807. GET_ENERGY_TITLE: 'Открывает платиновые шкатулки по одной до получения 250 энергии',
  808. ITEM_EXCHANGE: 'Обмен предметов',
  809. ITEM_EXCHANGE_TITLE: 'Обменивает предметы на указанное количество активности',
  810. BUY_SOULS: 'Купить души',
  811. BUY_SOULS_TITLE: 'Купить души героев из всех доступных магазинов',
  812. BUY_OUTLAND: 'Купить Запределье',
  813. BUY_OUTLAND_TITLE: 'Купить 9 сундуков в Запределье за 540 изумрудов',
  814. RAID: 'Рейд',
  815. AUTO_RAID_ADVENTURE: 'Рейд приключения',
  816. AUTO_RAID_ADVENTURE_TITLE: 'Рейд приключения заданное количество раз',
  817. CLAN_STAT: 'Клановая статистика',
  818. CLAN_STAT_TITLE: 'Копирует клановую статистику в буфер обмена',
  819. BTN_AUTO_F5: 'Авто (F5)',
  820. BOSS_DAMAGE: 'Урон по боссу: ',
  821. NOTHING_BUY: 'Нечего покупать',
  822. LOTS_BOUGHT: 'За золото куплено {countBuy} лотов',
  823. BUY_FOR_GOLD: 'Скупить за золото',
  824. BUY_FOR_GOLD_TITLE: 'Скупить предметы за золото в Городской лавке и в магазине Камней Душ Питомцев',
  825. REWARDS_AND_MAIL: 'Награды и почта',
  826. REWARDS_AND_MAIL_TITLE: 'Собирает награды и почту',
  827. New_Year_Clan: 'подарок другу',
  828. New_Year_Clan_TITLE: 'Новогодние подарки друзьям',
  829. COLLECT_REWARDS_AND_MAIL: 'Собрано {countQuests} наград и {countMail} писем',
  830. TIMER_ALREADY: 'Таймер уже запущен {time}',
  831. NO_ATTEMPTS_TIMER_START: 'Попыток нет, запущен таймер {time}',
  832. EPIC_BRAWL_RESULT: '{i} Победы: {wins}/{attempts}, Монеты: {coins}, Серия: {progress}/{nextStage} [Закрыть]{end}',
  833. ATTEMPT_ENDED: '<br>Попытки закончились, запущен таймер {time}',
  834. EPIC_BRAWL: 'Вселенская битва',
  835. EPIC_BRAWL_TITLE: 'Тратит попытки во Вселенской битве',
  836. RELOAD_GAME: 'Перезагрузить игру',
  837. TIMER: 'Таймер:',
  838. SHOW_ERRORS: 'Отображать ошибки',
  839. SHOW_ERRORS_TITLE: 'Отображать ошибки запросов к серверу',
  840. ERROR_MSG: 'Ошибка: {name}<br>{description}',
  841. EVENT_AUTO_BOSS: 'Максимальное количество боев для расчета:</br>{length} * {countTestBattle} = {maxCalcBattle}</br>Если у Вас слабый компьютер на это может потребоваться много времени, нажмите крестик для отмены.</br>Искать лучший пак из всех или первый подходящий?',
  842. BEST_SLOW: 'Лучший (медленее)',
  843. FIRST_FAST: 'Первый (быстрее)',
  844. FREEZE_INTERFACE: 'Идет расчет... <br> Интерфейс может зависнуть.',
  845. ERROR_F12: 'Ошибка, подробности в консоли (F12)',
  846. FAILED_FIND_WIN_PACK: 'Победный пак найти не удалось',
  847. BEST_PACK: 'Наилучший пак: ',
  848. BOSS_HAS_BEEN_DEF: 'Босс {bossLvl} побежден',
  849. NOT_ENOUGH_ATTEMPTS_BOSS: 'Для победы босса ${bossLvl} не хватило попыток, повторить?',
  850. BOSS_VICTORY_IMPOSSIBLE: 'По результатам прерасчета {battles} боев победу получить не удалось. Вы хотите продолжить поиск победного боя на реальных боях?',
  851. BOSS_HAS_BEEN_DEF_TEXT: 'Босс {bossLvl} побежден за<br>{countBattle}/{countMaxBattle} попыток<br>(Сделайте синхронизацию или перезагрузите игру для обновления данных)',
  852. MAP: 'Карта: ',
  853. PLAYER_POS: 'Позиции игроков:',
  854. NY_GIFTS: 'Подарки',
  855. NY_GIFTS_TITLE: 'Открыть все новогодние подарки',
  856. NY_NO_GIFTS: 'Нет не полученных подарков',
  857. NY_GIFTS_COLLECTED: 'Собрано {count} подарков',
  858. CHANGE_MAP: 'Карта острова',
  859. CHANGE_MAP_TITLE: 'Сменить карту острова',
  860. SELECT_ISLAND_MAP: 'Выберите карту острова:',
  861. FIRST_MAP: 'Первая карта',
  862. SECOND_MAP: 'Вторая карта',
  863. THIRD_MAP: 'Третья карта',
  864. SECRET_WEALTH_SHOP: 'Тайное богатство {name}: ',
  865. SHOPS: 'Магазины',
  866. SHOPS_DEFAULT: 'Стандартные',
  867. SHOPS_DEFAULT_TITLE: 'Стандартные магазины',
  868. SHOPS_LIST: 'Магазины {number}',
  869. SHOPS_LIST_TITLE: 'Список магазинов {number}',
  870. SHOPS_WARNING: 'Магазины<br><span style="color:red">Если Вы купите монеты магазинов потасовок за изумруды, то их надо использовать сразу, иначе после перезагрузки игры они пропадут!</span>',
  871. MINIONS_WARNING: 'Пачки героев для атаки приспешников неполные, продолжить?',
  872. FAST_SEASON: 'Быстрый сезон',
  873. FAST_SEASON_TITLE: 'Пропуск экрана с выбором карты в сезоне',
  874. SET_NUMBER_LEVELS: 'Указать колличество уровней:',
  875. POSSIBLE_IMPROVE_LEVELS: 'Возможно улучшить только {count} уровней.<br>Улучшаем?',
  876. NOT_ENOUGH_RESOURECES: 'Не хватает ресурсов',
  877. IMPROVED_LEVELS: 'Улучшено уровней: {count}',
  878. ARTIFACTS_UPGRADE: 'Улучшение артефактов',
  879. ARTIFACTS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых артефактов героев',
  880. SKINS_UPGRADE: 'Улучшение обликов',
  881. SKINS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых обликов героев',
  882. HINT: '<br>Подсказка: ',
  883. PICTURE: '<br>На картинке: ',
  884. ANSWER: '<br>Ответ: ',
  885. NO_HEROES_PACK: 'Проведите хотя бы один бой для сохранения атакующей команды',
  886. },
  887. };
  888.  
  889. function getLang() {
  890. let lang = '';
  891. if (typeof NXFlashVars !== 'undefined') {
  892. lang = NXFlashVars.interface_lang
  893. }
  894. if (!lang) {
  895. lang = (navigator.language || navigator.userLanguage).substr(0, 2);
  896. }
  897. if (lang == 'ru') {
  898. return lang;
  899. }
  900. return 'en';
  901. }
  902.  
  903. this.I18N = function (constant, replace) {
  904. const selectLang = getLang();
  905. if (constant && constant in i18nLangData[selectLang]) {
  906. const result = i18nLangData[selectLang][constant];
  907. if (replace) {
  908. return result.sprintf(replace);
  909. }
  910. return result;
  911. }
  912. return `% ${constant} %`;
  913. };
  914.  
  915. String.prototype.sprintf = String.prototype.sprintf ||
  916. function () {
  917. "use strict";
  918. var str = this.toString();
  919. if (arguments.length) {
  920. var t = typeof arguments[0];
  921. var key;
  922. var args = ("string" === t || "number" === t) ?
  923. Array.prototype.slice.call(arguments)
  924. : arguments[0];
  925.  
  926. for (key in args) {
  927. str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
  928. }
  929. }
  930.  
  931. return str;
  932. };
  933.  
  934. /**
  935. * Checkboxes
  936. *
  937. * Чекбоксы
  938. */
  939. const checkboxes = {
  940. passBattle: {
  941. label: I18N('SKIP_FIGHTS'),
  942. cbox: null,
  943. title: I18N('SKIP_FIGHTS_TITLE'),
  944. default: false
  945. },
  946. /*endlessCards: {
  947. label: I18N('ENDLESS_CARDS'),
  948. cbox: null,
  949. title: I18N('ENDLESS_CARDS_TITLE'),
  950. default: true
  951. },*/
  952. /*sendExpedition: {
  953. label: I18N('AUTO_EXPEDITION'),
  954. cbox: null,
  955. title: I18N('AUTO_EXPEDITION_TITLE'),
  956. default: false
  957. },*/ //тест сдедал экспедиции на авто в сделать все
  958. cancelBattle: {
  959. label: I18N('CANCEL_FIGHT'),
  960. cbox: null,
  961. title: I18N('CANCEL_FIGHT_TITLE'),
  962. default: false,
  963. },
  964. preCalcBattle: {
  965. label: I18N('BATTLE_RECALCULATION'),
  966. cbox: null,
  967. title: I18N('BATTLE_RECALCULATION_TITLE'),
  968. default: false
  969. },
  970. finishingBattle: {
  971. label: I18N('BATTLE_FISHING'),
  972. cbox: null,
  973. title: I18N('BATTLE_FISHING_TITLE'),
  974. default: false
  975. },
  976. treningBattle: {
  977. label: I18N('BATTLE_TRENING'),
  978. cbox: null,
  979. title: I18N('BATTLE_TRENING_TITLE'),
  980. default: false
  981. },
  982. countControl: {
  983. label: I18N('QUANTITY_CONTROL'),
  984. cbox: null,
  985. title: I18N('QUANTITY_CONTROL_TITLE'),
  986. default: true
  987. },
  988. repeatMission: {
  989. label: I18N('REPEAT_CAMPAIGN'),
  990. cbox: null,
  991. title: I18N('REPEAT_CAMPAIGN_TITLE'),
  992. default: false
  993. },
  994. noOfferDonat: {
  995. label: I18N('DISABLE_DONAT'),
  996. cbox: null,
  997. title: I18N('DISABLE_DONAT_TITLE'),
  998. /**
  999. * A crutch to get the field before getting the character id
  1000. *
  1001. * Костыль чтоб получать поле до получения id персонажа
  1002. */
  1003. default: (() => {
  1004. $result = false;
  1005. try {
  1006. $result = JSON.parse(localStorage[GM_info.script.name + ':noOfferDonat'])
  1007. } catch(e) {
  1008. $result = false;
  1009. }
  1010. return $result || false;
  1011. })(),
  1012. },
  1013. dailyQuests: {
  1014. label: I18N('DAILY_QUESTS'),
  1015. cbox: null,
  1016. title: I18N('DAILY_QUESTS_TITLE'),
  1017. default: false
  1018. },
  1019. // Потасовки
  1020. /*autoBrawls: {
  1021. label: I18N('BRAWLS'),
  1022. cbox: null,
  1023. title: I18N('BRAWLS_TITLE'),
  1024. default: (() => {
  1025. $result = false;
  1026. try {
  1027. $result = JSON.parse(localStorage[GM_info.script.name + ':autoBrawls'])
  1028. } catch (e) {
  1029. $result = false;
  1030. }
  1031. return $result || false;
  1032. })(),
  1033. hide: false,
  1034. },
  1035. getAnswer: {
  1036. label: I18N('AUTO_QUIZ'),
  1037. cbox: null,
  1038. title: I18N('AUTO_QUIZ_TITLE'),
  1039. default: false,
  1040. hide: true,
  1041. },
  1042. showErrors: {
  1043. label: I18N('SHOW_ERRORS'),
  1044. cbox: null,
  1045. title: I18N('SHOW_ERRORS_TITLE'),
  1046. default: true
  1047. },*/
  1048. buyForGold: {
  1049. label: I18N('BUY_FOR_GOLD'),
  1050. cbox: null,
  1051. title: I18N('BUY_FOR_GOLD_TITLE'),
  1052. default: false
  1053. },
  1054. hideServers: {
  1055. label: I18N('HIDE_SERVERS'),
  1056. cbox: null,
  1057. title: I18N('HIDE_SERVERS_TITLE'),
  1058. default: false
  1059. },
  1060. fastSeason: {
  1061. label: I18N('FAST_SEASON'),
  1062. cbox: null,
  1063. title: I18N('FAST_SEASON_TITLE'),
  1064. default: false
  1065. },
  1066. };
  1067. /**
  1068. * Get checkbox state
  1069. *
  1070. * Получить состояние чекбокса
  1071. */
  1072. function isChecked(checkBox) {
  1073. if (!(checkBox in checkboxes)) {
  1074. return false;
  1075. }
  1076. return checkboxes[checkBox].cbox?.checked;
  1077. }
  1078. /**
  1079. * Input fields
  1080. *
  1081. * Поля ввода
  1082. */
  1083. const inputs = {
  1084. countTitanit: {
  1085. input: null,
  1086. title: I18N('HOW_MUCH_TITANITE'),
  1087. default: 150,
  1088. },
  1089. speedBattle: {
  1090. input: null,
  1091. title: I18N('COMBAT_SPEED'),
  1092. default: 5,
  1093. },
  1094. //тест повтор компании
  1095. countRaid: {
  1096. input: null,
  1097. title: I18N('HOW_REPEAT_CAMPAIGN'),
  1098. default: 5,
  1099. },
  1100. countTestBattle: {
  1101. input: null,
  1102. title: I18N('NUMBER_OF_TEST'),
  1103. default: 10,
  1104. },
  1105. countAutoBattle: {
  1106. input: null,
  1107. title: I18N('NUMBER_OF_AUTO_BATTLE'),
  1108. default: 10,
  1109. },
  1110. /*FPS: {
  1111. input: null,
  1112. title: 'FPS',
  1113. default: 60,
  1114. }*/
  1115. }
  1116. //сохранка тест
  1117. const inputs2 = {
  1118. countBattle: {
  1119. input: null,
  1120. title: '-1 сохраняет защиту, -2 атаку противника с Replay',
  1121. default: 1,
  1122. },
  1123. needResource: {
  1124. input: null,
  1125. title: 'Мощь противника мин.(тыс.)/урона(млн.)',
  1126. default: 300,
  1127. },
  1128. needResource2: {
  1129. input: null,
  1130. title: 'Мощь противника макс./тип бафа',
  1131. default: 1500,
  1132. },
  1133. }
  1134. //новогодние подарки игрокам других гильдий
  1135. const inputs3 = {
  1136. userID: { // айди игрока посмотреть открыв его инфо
  1137. input: null,
  1138. title: I18N('USER_ID_TITLE'),
  1139. default: 111111,
  1140. },
  1141. GiftNum: { // номер подарка считаем слева направо от 1 до 6, под 1 это за 750 новогодних игрушек
  1142. input: null,
  1143. title: I18N('GIFT_NUM'),
  1144. default: 10,
  1145. },
  1146. AmontID: { // количество ресурсов от 1 до бесконечности
  1147. input: null,
  1148. title: I18N('AMOUNT'),
  1149. default: 1,
  1150. },
  1151. }
  1152. /**
  1153. * Checks the checkbox
  1154. *
  1155. * Поплучить данные поля ввода
  1156. */
  1157. /*function getInput(inputName) {
  1158. return inputs[inputName]?.input?.value;
  1159. }*/
  1160. function getInput(inputName) {
  1161. if (inputName in inputs){return inputs[inputName]?.input?.value;}
  1162. else if (inputName in inputs2){return inputs2[inputName]?.input?.value;}
  1163. //else if (inputName in inputs3){return inputs3[inputName]?.input?.value;}
  1164. else return null
  1165. }
  1166.  
  1167. //тест рейд
  1168. /** Автоповтор миссии */
  1169. let isRepeatMission = false;
  1170. /** Вкл/Выкл автоповтор миссии */
  1171. this.switchRepeatMission = function() {
  1172. isRepeatMission = !isRepeatMission;
  1173. console.log(isRepeatMission);
  1174. }
  1175.  
  1176. /**
  1177. * Control FPS
  1178. *
  1179. * Контроль FPS
  1180. */
  1181. let nextAnimationFrame = Date.now();
  1182. const oldRequestAnimationFrame = this.requestAnimationFrame;
  1183. this.requestAnimationFrame = async function (e) {
  1184. const FPS = Number(getInput('FPS')) || -1;
  1185. const now = Date.now();
  1186. const delay = nextAnimationFrame - now;
  1187. nextAnimationFrame = Math.max(now, nextAnimationFrame) + Math.min(1e3 / FPS, 1e3);
  1188. if (delay > 0) {
  1189. await new Promise((e) => setTimeout(e, delay));
  1190. }
  1191. oldRequestAnimationFrame(e);
  1192. };
  1193.  
  1194. /**
  1195. * Button List
  1196. *
  1197. * Список кнопочек
  1198. */
  1199. const buttons = {
  1200. getOutland: {
  1201. name: I18N('TO_DO_EVERYTHING'),
  1202. title: I18N('TO_DO_EVERYTHING_TITLE'),
  1203. func: testDoYourBest,
  1204. },
  1205. /*
  1206. doActions: {
  1207. name: I18N('ACTIONS'),
  1208. title: I18N('ACTIONS_TITLE'),
  1209. func: async function () {
  1210. const popupButtons = [
  1211. {
  1212. msg: I18N('OUTLAND'),
  1213. result: function () {
  1214. confShow(`${I18N('RUN_SCRIPT')} ${I18N('OUTLAND')}?`, getOutland);
  1215. },
  1216. title: I18N('OUTLAND_TITLE'),
  1217. },
  1218. {
  1219. msg: I18N('TOWER'),
  1220. result: function () {
  1221. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TOWER')}?`, testTower);
  1222. },
  1223. title: I18N('TOWER_TITLE'),
  1224. },
  1225. {
  1226. msg: I18N('EXPEDITIONS'),
  1227. result: function () {
  1228. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EXPEDITIONS')}?`, checkExpedition);
  1229. },
  1230. title: I18N('EXPEDITIONS_TITLE'),
  1231. },
  1232. {
  1233. msg: I18N('MINIONS'),
  1234. result: function () {
  1235. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MINIONS')}?`, testRaidNodes);
  1236. },
  1237. title: I18N('MINIONS_TITLE'),
  1238. },
  1239. {
  1240. msg: I18N('ESTER_EGGS'),
  1241. result: function () {
  1242. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ESTER_EGGS')}?`, offerFarmAllReward);
  1243. },
  1244. title: I18N('ESTER_EGGS_TITLE'),
  1245. },
  1246. {
  1247. msg: I18N('STORM'),
  1248. result: function () {
  1249. testAdventure('solo');
  1250. },
  1251. title: I18N('STORM_TITLE'),
  1252. },
  1253. {
  1254. msg: I18N('REWARDS'),
  1255. result: function () {
  1256. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS')}?`, questAllFarm);
  1257. },
  1258. title: I18N('REWARDS_TITLE'),
  1259. },
  1260. {
  1261. msg: I18N('MAIL'),
  1262. result: function () {
  1263. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MAIL')}?`, mailGetAll);
  1264. },
  1265. title: I18N('MAIL_TITLE'),
  1266. },
  1267. {
  1268. msg: I18N('SEER'),
  1269. result: function () {
  1270. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SEER')}?`, rollAscension);
  1271. },
  1272. title: I18N('SEER_TITLE'),
  1273. },
  1274. {
  1275. msg: I18N('NY_GIFTS'),
  1276. result: getGiftNewYear,
  1277. title: I18N('NY_GIFTS_TITLE'),
  1278. },
  1279. ];
  1280. popupButtons.push({ result: false, isClose: true })
  1281. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1282. if (typeof answer === 'function') {
  1283. answer();
  1284. }
  1285. }
  1286. },*/
  1287. doOthers: {
  1288. name: I18N('OTHERS'),
  1289. title: I18N('OTHERS_TITLE'),
  1290. func: async function () {
  1291. const popupButtons = [
  1292. /*
  1293. {
  1294. msg: I18N('GET_ENERGY'),
  1295. result: farmStamina,
  1296. title: I18N('GET_ENERGY_TITLE'),
  1297. },
  1298. {
  1299. msg: I18N('ITEM_EXCHANGE'),
  1300. result: fillActive,
  1301. title: I18N('ITEM_EXCHANGE_TITLE'),
  1302. },
  1303. {
  1304. msg: I18N('BUY_SOULS'),
  1305. result: function () {
  1306. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_SOULS')}?`, buyHeroFragments);
  1307. },
  1308. title: I18N('BUY_SOULS_TITLE'),
  1309. },
  1310. {
  1311. msg: I18N('BUY_FOR_GOLD'),
  1312. result: function () {
  1313. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_FOR_GOLD')}?`, buyInStoreForGold);
  1314. },
  1315. title: I18N('BUY_FOR_GOLD_TITLE'),
  1316. },
  1317. {
  1318. msg: I18N('BUY_OUTLAND'),
  1319. result: function () {
  1320. confShow(I18N('BUY_OUTLAND_TITLE') + '?', bossOpenChestPay);
  1321. },
  1322. title: I18N('BUY_OUTLAND_TITLE'),
  1323. },
  1324. {
  1325. msg: I18N('AUTO_RAID_ADVENTURE'),
  1326. result: autoRaidAdventure,
  1327. title: I18N('AUTO_RAID_ADVENTURE_TITLE'),
  1328. },
  1329. {
  1330. msg: I18N('CLAN_STAT'),
  1331. result: clanStatistic,
  1332. title: I18N('CLAN_STAT_TITLE'),
  1333. },
  1334. {
  1335. msg: I18N('EPIC_BRAWL'),
  1336. result: async function () {
  1337. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EPIC_BRAWL')}?`, () => {
  1338. const brawl = new epicBrawl;
  1339. brawl.start();
  1340. });
  1341. },
  1342. title: I18N('EPIC_BRAWL_TITLE'),
  1343. },*/
  1344. {
  1345. msg: I18N('ARTIFACTS_UPGRADE'),
  1346. result: updateArtifacts,
  1347. title: I18N('ARTIFACTS_UPGRADE_TITLE'),
  1348. },
  1349. {
  1350. msg: I18N('SKINS_UPGRADE'),
  1351. result: updateSkins,
  1352. title: I18N('SKINS_UPGRADE_TITLE'),
  1353. },
  1354. {
  1355. msg: I18N('CHANGE_MAP'),
  1356. result: async function () {
  1357. const result = await popup.confirm(I18N('SELECT_ISLAND_MAP'), [
  1358. { msg: I18N('FIRST_MAP'), result: 1 },
  1359. { msg: I18N('SECOND_MAP'), result: 2 },
  1360. { msg: I18N('THIRD_MAP'), result: 3 },
  1361. { result: false, isClose: true },
  1362. ]);
  1363. if (result) {
  1364. cheats.changeIslandMap(result);
  1365. }
  1366. },
  1367. title: I18N('CHANGE_MAP_TITLE'),
  1368. },
  1369. {
  1370. msg: I18N('SHOPS'),
  1371. result: async function () {
  1372. const shopButtons = [{
  1373. msg: I18N('SHOPS_DEFAULT'),
  1374. result: function () {
  1375. cheats.goDefaultShops();
  1376. },
  1377. title: I18N('SHOPS_DEFAULT_TITLE'),
  1378. }, {
  1379. msg: I18N('SECRET_WEALTH'),
  1380. result: function () {
  1381. cheats.goSecretWealthShops();
  1382. },
  1383. title: I18N('SECRET_WEALTH'),
  1384. }];
  1385. for (let i = 0; i < 4; i++) {
  1386. const number = i + 1;
  1387. shopButtons.push({
  1388. msg: I18N('SHOPS_LIST', { number }),
  1389. result: function () {
  1390. cheats.goCustomShops(i);
  1391. },
  1392. title: I18N('SHOPS_LIST_TITLE', { number }),
  1393. })
  1394. }
  1395. shopButtons.push({ result: false, isClose: true })
  1396. const answer = await popup.confirm(I18N('SHOPS_WARNING'), shopButtons);
  1397. if (typeof answer === 'function') {
  1398. answer();
  1399. }
  1400. },
  1401. title: I18N('SHOPS'),
  1402. },
  1403. ];
  1404.  
  1405. popupButtons.push({ result: false, isClose: true })
  1406. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1407. if (typeof answer === 'function') {
  1408. answer();
  1409. }
  1410. }
  1411. },
  1412. testTitanArena: {
  1413. name: I18N('TITAN_ARENA'),
  1414. title: I18N('TITAN_ARENA_TITLE'),
  1415. func: function () {
  1416. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TITAN_ARENA')}?`, testTitanArena);
  1417. },
  1418. },
  1419. /* тест подземка есть в сделать все
  1420. testDungeon: {
  1421. name: I18N('DUNGEON'),
  1422. title: I18N('DUNGEON_TITLE'),
  1423. func: function () {
  1424. confShow(`${I18N('RUN_SCRIPT')} ${I18N('DUNGEON')}?`, testDungeon);
  1425. },
  1426. hide: true,
  1427. },*/
  1428. //тест подземка 2
  1429. DungeonFull: {
  1430. name: I18N('DUNGEON2'),
  1431. title: I18N('DUNGEON_FULL_TITLE'),
  1432. func: function () {
  1433. confShow(`${I18N('RUN_SCRIPT')} ${I18N('DUNGEON_FULL_TITLE')}?`, DungeonFull);
  1434. },
  1435. },
  1436. //остановить подземелье
  1437. stopDungeon: {
  1438. name: I18N('STOP_DUNGEON'),
  1439. title: I18N('STOP_DUNGEON_TITLE'),
  1440. func: function () {
  1441. confShow(`${I18N('STOP_SCRIPT')} ${I18N('STOP_DUNGEON_TITLE')}?`, stopDungeon);
  1442. },
  1443. },
  1444. /*
  1445. autoBoss: {
  1446. name: 'autoBoss',
  1447. title: 'autoBoss',
  1448. func: function () {
  1449. (new executeEventAutoBoss()).start()
  1450. },
  1451. },
  1452. */
  1453. // Архидемон
  1454. bossRatingEvent: {
  1455. name: I18N('ARCHDEMON'),
  1456. title: I18N('ARCHDEMON_TITLE'),
  1457. func: function () {
  1458. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ARCHDEMON')}?`, bossRatingEvent);
  1459. },
  1460. hide: true,
  1461. },
  1462. /*
  1463. // Горнило душ
  1464. bossRatingEvent: {
  1465. name: I18N('CRUCIBLE_SOULS'),
  1466. title: I18N('CRUCIBLE_SOULS_TITLE'),
  1467. func: function () {
  1468. confShow(`${I18N('RUN_SCRIPT')} ${I18N('CRUCIBLE_SOULS')}?`, bossRatingEventSouls);
  1469. },
  1470. },*/
  1471. // Буря
  1472. /*testAdventure2: {
  1473. name: I18N('STORM'),
  1474. title: I18N('STORM_TITLE'),
  1475. func: () => {
  1476. testAdventure2('solo');
  1477. },
  1478. },*/
  1479. rewardsAndMailFarm: {
  1480. name: I18N('REWARDS_AND_MAIL'),
  1481. title: I18N('REWARDS_AND_MAIL_TITLE'),
  1482. func: function () {
  1483. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS_AND_MAIL')}?`, rewardsAndMailFarm);
  1484. },
  1485. },
  1486. //тест прислужники
  1487. testRaidNodes: {
  1488. name: I18N('MINIONS'),
  1489. title: I18N('MINIONS_TITLE'),
  1490. func: function () {
  1491. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MINIONS')}?`, testRaidNodes);
  1492. },
  1493. },
  1494. testAdventure: {
  1495. name: I18N('ADVENTURE'),
  1496. title: I18N('ADVENTURE_TITLE'),
  1497. func: () => {
  1498. testAdventure();
  1499. },
  1500. },
  1501. goToSanctuary: {
  1502. name: I18N('SANCTUARY'),
  1503. title: I18N('SANCTUARY_TITLE'),
  1504. func: cheats.goSanctuary,
  1505. },
  1506. goToClanWar: {
  1507. name: I18N('GUILD_WAR'),
  1508. title: I18N('GUILD_WAR_TITLE'),
  1509. func: cheats.goClanWar,
  1510. },
  1511. dailyQuests: {
  1512. name: I18N('DAILY_QUESTS'),
  1513. title: I18N('DAILY_QUESTS_TITLE'),
  1514. func: async function () {
  1515. const quests = new dailyQuests(() => { }, () => { });
  1516. await quests.autoInit();
  1517. quests.start();
  1518. },
  1519. },
  1520. //подарок др
  1521. /*NewYearGift_Clan: {
  1522. name: I18N('New_Year_Clan'),
  1523. title: I18N('New_Year_Clan_TITLE'),
  1524. func: function () {
  1525. confShow(`${I18N('RUN_SCRIPT')} ${I18N('New_Year_Clan_TITLE')}?`, NewYearGift_Clan);
  1526. },
  1527. },*/
  1528. newDay: {
  1529. name: I18N('SYNC'),
  1530. title: I18N('SYNC_TITLE'),
  1531. func: function () {
  1532. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SYNC')}?`, cheats.refreshGame);
  1533. },
  1534. },
  1535. }
  1536. /**
  1537. * Display buttons
  1538. *
  1539. * Вывести кнопочки
  1540. */
  1541. function addControlButtons() {
  1542. for (let name in buttons) {
  1543. button = buttons[name];
  1544. if (button.hide) {
  1545. continue;
  1546. }
  1547. button['button'] = scriptMenu.addButton(button.name, button.func, button.title);
  1548. }
  1549. }
  1550. /**
  1551. * Adds links
  1552. *
  1553. * Добавляет ссылки
  1554. */
  1555. function addBottomUrls() {
  1556. scriptMenu.addHeader(I18N('BOTTOM_URLS'));
  1557. }
  1558. /**
  1559. * Stop repetition of the mission
  1560. *
  1561. * Остановить повтор миссии
  1562. */
  1563. let isStopSendMission = false;
  1564. /**
  1565. * There is a repetition of the mission
  1566. *
  1567. * Идет повтор миссии
  1568. */
  1569. let isSendsMission = false;
  1570. /**
  1571. * Data on the past mission
  1572. *
  1573. * Данные о прошедшей мисии
  1574. */
  1575. let lastMissionStart = {}
  1576. /**
  1577. * Start time of the last battle in the company
  1578. *
  1579. * Время начала последнего боя в кампании
  1580. */
  1581. let lastMissionBattleStart = 0;
  1582. /**
  1583. * Data on the past attack on the boss
  1584. *
  1585. * Данные о прошедшей атаке на босса
  1586. */
  1587. let lastBossBattle = {}
  1588. /**
  1589. * Data for calculating the last battle with the boss
  1590. *
  1591. * Данные для расчете последнего боя с боссом
  1592. */
  1593. let lastBossBattleInfo = null;
  1594. /**
  1595. * Ability to cancel the battle in Asgard
  1596. *
  1597. * Возможность отменить бой в Астгарде
  1598. */
  1599. let isCancalBossBattle = true;
  1600. /**
  1601. * Information about the last battle
  1602. *
  1603. * Данные о прошедшей битве
  1604. */
  1605. let lastBattleArg = {}
  1606. let lastBossBattleStart = null;
  1607. this.addBattleTimer = 4;
  1608. this.invasionTimer = 2500;
  1609. /**
  1610. * The name of the function of the beginning of the battle
  1611. *
  1612. * Имя функции начала боя
  1613. */
  1614. let nameFuncStartBattle = '';
  1615. /**
  1616. * The name of the function of the end of the battle
  1617. *
  1618. * Имя функции конца боя
  1619. */
  1620. let nameFuncEndBattle = '';
  1621. /**
  1622. * Data for calculating the last battle
  1623. *
  1624. * Данные для расчета последнего боя
  1625. */
  1626. let lastBattleInfo = null;
  1627. /**
  1628. * The ability to cancel the battle
  1629. *
  1630. * Возможность отменить бой
  1631. */
  1632. let isCancalBattle = true;
  1633.  
  1634. /**
  1635. * Certificator of the last open nesting doll
  1636. *
  1637. * Идетификатор последней открытой матрешки
  1638. */
  1639. let lastRussianDollId = null;
  1640. /**
  1641. * Cancel the training guide
  1642. *
  1643. * Отменить обучающее руководство
  1644. */
  1645. this.isCanceledTutorial = false;
  1646.  
  1647. /**
  1648. * Data from the last question of the quiz
  1649. *
  1650. * Данные последнего вопроса викторины
  1651. */
  1652. let lastQuestion = null;
  1653. /**
  1654. * Answer to the last question of the quiz
  1655. *
  1656. * Ответ на последний вопрос викторины
  1657. */
  1658. let lastAnswer = null;
  1659. /**
  1660. * Flag for opening keys or titan artifact spheres
  1661. *
  1662. * Флаг открытия ключей или сфер артефактов титанов
  1663. */
  1664. let artifactChestOpen = false;
  1665. /**
  1666. * The name of the function to open keys or orbs of titan artifacts
  1667. *
  1668. * Имя функции открытия ключей или сфер артефактов титанов
  1669. */
  1670. let artifactChestOpenCallName = '';
  1671. let correctShowOpenArtifact = 0;
  1672. /**
  1673. * Data for the last battle in the dungeon
  1674. * (Fix endless cards)
  1675. *
  1676. * Данные для последнего боя в подземке
  1677. * (Исправление бесконечных карт)
  1678. */
  1679. let lastDungeonBattleData = null;
  1680. /**
  1681. * Start time of the last battle in the dungeon
  1682. *
  1683. * Время начала последнего боя в подземелье
  1684. */
  1685. let lastDungeonBattleStart = 0;
  1686. /**
  1687. * Subscription end time
  1688. *
  1689. * Время окончания подписки
  1690. */
  1691. let subEndTime = 0;
  1692. /**
  1693. * Number of prediction cards
  1694. *
  1695. * Количество карт предсказаний
  1696. */
  1697. let countPredictionCard = 0;
  1698.  
  1699. /**
  1700. * Brawl pack
  1701. *
  1702. * Пачка для потасовок
  1703. */
  1704. let brawlsPack = null;
  1705. /**
  1706. * Autobrawl started
  1707. *
  1708. * Автопотасовка запущена
  1709. */
  1710. let isBrawlsAutoStart = false;
  1711. /**
  1712. * Copies the text to the clipboard
  1713. *
  1714. * Копирует тест в буфер обмена
  1715. * @param {*} text copied text // копируемый текст
  1716. */
  1717. function copyText(text) {
  1718. let copyTextarea = document.createElement("textarea");
  1719. copyTextarea.style.opacity = "0";
  1720. copyTextarea.textContent = text;
  1721. document.body.appendChild(copyTextarea);
  1722. copyTextarea.select();
  1723. document.execCommand("copy");
  1724. document.body.removeChild(copyTextarea);
  1725. delete copyTextarea;
  1726. }
  1727. /**
  1728. * Returns the history of requests
  1729. *
  1730. * Возвращает историю запросов
  1731. */
  1732. this.getRequestHistory = function() {
  1733. return requestHistory;
  1734. }
  1735. /**
  1736. * Generates a random integer from min to max
  1737. *
  1738. * Гененирует случайное целое число от min до max
  1739. */
  1740. const random = function (min, max) {
  1741. return Math.floor(Math.random() * (max - min + 1) + min);
  1742. }
  1743. /**
  1744. * Clearing the request history
  1745. *
  1746. * Очистка истоии запросов
  1747. */
  1748. setInterval(function () {
  1749. let now = Date.now();
  1750. for (let i in requestHistory) {
  1751. const time = +i.split('_')[0];
  1752. if (now - time > 300000) {
  1753. delete requestHistory[i];
  1754. }
  1755. }
  1756. }, 300000);
  1757. /**
  1758. * DOM Loading Event page
  1759. *
  1760. * Событие загрузки DOM дерева страницы
  1761. */
  1762. document.addEventListener("DOMContentLoaded", () => {
  1763. /**
  1764. * Create the script interface
  1765. *
  1766. * Создание интерфеса скрипта
  1767. */
  1768. createInterface();
  1769. });
  1770. /**
  1771. * Gift codes collecting and sending codes
  1772. *
  1773. * Сбор и отправка кодов подарков
  1774. */
  1775. function sendCodes() {
  1776. return;
  1777. let codes = [], count = 0;
  1778. if (!localStorage['giftSendIds']) {
  1779. localStorage['giftSendIds'] = '';
  1780. }
  1781. document.querySelectorAll('a[target="_blank"]').forEach(e => {
  1782. let url = e?.href;
  1783. if (!url) return;
  1784. url = new URL(url);
  1785. let giftId = url.searchParams.get('gift_id');
  1786. if (!giftId || localStorage['giftSendIds'].includes(giftId)) return;
  1787. localStorage['giftSendIds'] += ';' + giftId;
  1788. codes.push(giftId);
  1789. count++;
  1790. });
  1791.  
  1792. if (codes.length) {
  1793. localStorage['giftSendIds'] = localStorage['giftSendIds'].split(';').splice(-50).join(';');
  1794. sendGiftsCodes(codes);
  1795. }
  1796.  
  1797. if (!count) {
  1798. setTimeout(sendCodes, 2000);
  1799. }
  1800. }
  1801. /**
  1802. * Checking sent codes
  1803. *
  1804. * Проверка отправленных кодов
  1805. */
  1806. function checkSendGifts() {
  1807. if (!freebieCheckInfo) {
  1808. return;
  1809. }
  1810.  
  1811. let giftId = freebieCheckInfo.args.giftId;
  1812. let valName = 'giftSendIds_' + userInfo.id;
  1813. localStorage[valName] = localStorage[valName] ?? '';
  1814. if (!localStorage[valName].includes(giftId)) {
  1815. localStorage[valName] += ';' + giftId;
  1816. sendGiftsCodes([giftId]);
  1817. }
  1818. }
  1819. /**
  1820. * Sending codes
  1821. *
  1822. * Отправка кодов
  1823. */
  1824. function sendGiftsCodes(codes) {
  1825. return;
  1826. fetch('https://zingery.ru/heroes/setGifts.php', {
  1827. method: 'POST',
  1828. body: JSON.stringify(codes)
  1829. }).then(
  1830. response => response.json()
  1831. ).then(
  1832. data => {
  1833. if (data.result) {
  1834. console.log(I18N('GIFTS_SENT'));
  1835. }
  1836. }
  1837. )
  1838. }
  1839. /**
  1840. * Displays the dialog box
  1841. *
  1842. * Отображает диалоговое окно
  1843. */
  1844. function confShow(message, yesCallback, noCallback) {
  1845. let buts = [];
  1846. message = message || I18N('DO_YOU_WANT');
  1847. noCallback = noCallback || (() => {});
  1848. if (yesCallback) {
  1849. buts = [
  1850. { msg: I18N('BTN_RUN'), result: true},
  1851. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true},
  1852. ]
  1853. } else {
  1854. yesCallback = () => {};
  1855. buts = [
  1856. { msg: I18N('BTN_OK'), result: true},
  1857. ];
  1858. }
  1859. popup.confirm(message, buts).then((e) => {
  1860. // dialogPromice = null;
  1861. if (e) {
  1862. yesCallback();
  1863. } else {
  1864. noCallback();
  1865. }
  1866. });
  1867. }
  1868. /**
  1869. * Override/proxy the method for creating a WS package send
  1870. *
  1871. * Переопределяем/проксируем метод создания отправки WS пакета
  1872. */
  1873. WebSocket.prototype.send = function (data) {
  1874. if (!this.isSetOnMessage) {
  1875. const oldOnmessage = this.onmessage;
  1876. this.onmessage = function (event) {
  1877. try {
  1878. const data = JSON.parse(event.data);
  1879. if (!this.isWebSocketLogin && data.result.type == "iframeEvent.login") {
  1880. this.isWebSocketLogin = true;
  1881. } else if (data.result.type == "iframeEvent.login") {
  1882. return;
  1883. }
  1884. } catch (e) { }
  1885. return oldOnmessage.apply(this, arguments);
  1886. }
  1887. this.isSetOnMessage = true;
  1888. }
  1889. original.SendWebSocket.call(this, data);
  1890. }
  1891. /**
  1892. * Overriding/Proxying the Ajax Request Creation Method
  1893. *
  1894. * Переопределяем/проксируем метод создания Ajax запроса
  1895. */
  1896. XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
  1897. this.uniqid = Date.now() + '_' + random(1000000, 10000000);
  1898. this.errorRequest = false;
  1899. if (method == 'POST' && url.includes('.nextersglobal.com/api/') && /api\/$/.test(url)) {
  1900. if (!apiUrl) {
  1901. apiUrl = url;
  1902. const socialInfo = /heroes-(.+?)\./.exec(apiUrl);
  1903. console.log(socialInfo);
  1904. }
  1905. requestHistory[this.uniqid] = {
  1906. method,
  1907. url,
  1908. error: [],
  1909. headers: {},
  1910. request: null,
  1911. response: null,
  1912. signature: [],
  1913. calls: {},
  1914. };
  1915. } else if (method == 'POST' && url.includes('error.nextersglobal.com/client/')) {
  1916. this.errorRequest = true;
  1917. }
  1918. return original.open.call(this, method, url, async, user, password);
  1919. };
  1920. /**
  1921. * Overriding/Proxying the header setting method for the AJAX request
  1922. *
  1923. * Переопределяем/проксируем метод установки заголовков для AJAX запроса
  1924. */
  1925. XMLHttpRequest.prototype.setRequestHeader = function (name, value, check) {
  1926. if (this.uniqid in requestHistory) {
  1927. requestHistory[this.uniqid].headers[name] = value;
  1928. } else {
  1929. check = true;
  1930. }
  1931.  
  1932. if (name == 'X-Auth-Signature') {
  1933. requestHistory[this.uniqid].signature.push(value);
  1934. if (!check) {
  1935. return;
  1936. }
  1937. }
  1938.  
  1939. return original.setRequestHeader.call(this, name, value);
  1940. };
  1941. /**
  1942. * Overriding/Proxying the AJAX Request Sending Method
  1943. *
  1944. * Переопределяем/проксируем метод отправки AJAX запроса
  1945. */
  1946. XMLHttpRequest.prototype.send = async function (sourceData) {
  1947. if (this.uniqid in requestHistory) {
  1948. let tempData = null;
  1949. if (getClass(sourceData) == "ArrayBuffer") {
  1950. tempData = decoder.decode(sourceData);
  1951. } else {
  1952. tempData = sourceData;
  1953. }
  1954. requestHistory[this.uniqid].request = tempData;
  1955. let headers = requestHistory[this.uniqid].headers;
  1956. lastHeaders = Object.assign({}, headers);
  1957. /**
  1958. * Game loading event
  1959. *
  1960. * Событие загрузки игры
  1961. */
  1962. if (headers["X-Request-Id"] > 2 && !isLoadGame) {
  1963. isLoadGame = true;
  1964. await lib.load();
  1965. addControls();
  1966. addControlButtons();
  1967. addBottomUrls();
  1968.  
  1969. //if (isChecked('sendExpedition')) {
  1970. checkExpedition(); //экспедиции на авто при входе в игру
  1971. //}
  1972.  
  1973. checkSendGifts();
  1974. getAutoGifts();
  1975.  
  1976. cheats.activateHacks();
  1977.  
  1978. justInfo();
  1979. if (isChecked('dailyQuests')) {
  1980. testDailyQuests();
  1981. }
  1982.  
  1983. if (isChecked('buyForGold')) {
  1984. buyInStoreForGold();
  1985. }
  1986. }
  1987. /**
  1988. * Outgoing request data processing
  1989. *
  1990. * Обработка данных исходящего запроса
  1991. */
  1992. sourceData = await checkChangeSend.call(this, sourceData, tempData);
  1993. /**
  1994. * Handling incoming request data
  1995. *
  1996. * Обработка данных входящего запроса
  1997. */
  1998. const oldReady = this.onreadystatechange;
  1999. this.onreadystatechange = async function (e) {
  2000. if (this.errorRequest) {
  2001. return oldReady.apply(this, arguments);
  2002. }
  2003. if(this.readyState == 4 && this.status == 200) {
  2004. isTextResponse = this.responseType === "text" || this.responseType === "";
  2005. let response = isTextResponse ? this.responseText : this.response;
  2006. requestHistory[this.uniqid].response = response;
  2007. /**
  2008. * Replacing incoming request data
  2009. *
  2010. * Заменна данных входящего запроса
  2011. */
  2012. if (isTextResponse) {
  2013. await checkChangeResponse.call(this, response);
  2014. }
  2015. /**
  2016. * A function to run after the request is executed
  2017. *
  2018. * Функция запускаемая после выполения запроса
  2019. */
  2020. if (typeof this.onReadySuccess == 'function') {
  2021. setTimeout(this.onReadySuccess, 500);
  2022. }
  2023. /** Удаляем из истории запросов битвы с боссом */
  2024. if ('invasion_bossStart' in requestHistory[this.uniqid].calls) delete requestHistory[this.uniqid];
  2025. }
  2026. if (oldReady) {
  2027. return oldReady.apply(this, arguments);
  2028. }
  2029. }
  2030. }
  2031. if (this.errorRequest) {
  2032. const oldReady = this.onreadystatechange;
  2033. this.onreadystatechange = function () {
  2034. Object.defineProperty(this, 'status', {
  2035. writable: true
  2036. });
  2037. this.status = 200;
  2038. Object.defineProperty(this, 'readyState', {
  2039. writable: true
  2040. });
  2041. this.readyState = 4;
  2042. Object.defineProperty(this, 'responseText', {
  2043. writable: true
  2044. });
  2045. this.responseText = JSON.stringify({
  2046. "result": true
  2047. });
  2048. if (typeof this.onReadySuccess == 'function') {
  2049. setTimeout(this.onReadySuccess, 500);
  2050. }
  2051. return oldReady.apply(this, arguments);
  2052. }
  2053. this.onreadystatechange();
  2054. } else {
  2055. try {
  2056. return original.send.call(this, sourceData);
  2057. } catch(e) {
  2058. debugger;
  2059. }
  2060.  
  2061. }
  2062. };
  2063. /**
  2064. * Processing and substitution of outgoing data
  2065. *
  2066. * Обработка и подмена исходящих данных
  2067. */
  2068. async function checkChangeSend(sourceData, tempData) {
  2069. try {
  2070. /**
  2071. * A function that replaces battle data with incorrect ones to cancel combatя
  2072. *
  2073. * Функция заменяющая данные боя на неверные для отмены боя
  2074. */
  2075. const fixBattle = function (heroes) {
  2076. for (const ids in heroes) {
  2077. hero = heroes[ids];
  2078. hero.energy = random(1, 999);
  2079. if (hero.hp > 0) {
  2080. hero.hp = random(1, hero.hp);
  2081. }
  2082. }
  2083. }
  2084. /**
  2085. * Dialog window 2
  2086. *
  2087. * Диалоговое окно 2
  2088. */
  2089. const showMsg = async function (msg, ansF, ansS) {
  2090. if (typeof popup == 'object') {
  2091. return await popup.confirm(msg, [
  2092. {msg: ansF, result: false},
  2093. {msg: ansS, result: true},
  2094. ]);
  2095. } else {
  2096. return !confirm(`${msg}\n ${ansF} (${I18N('BTN_OK')})\n ${ansS} (${I18N('BTN_CANCEL')})`);
  2097. }
  2098. }
  2099. /**
  2100. * Dialog window 3
  2101. *
  2102. * Диалоговое окно 3
  2103. */
  2104. const showMsgs = async function (msg, ansF, ansS, ansT) {
  2105. return await popup.confirm(msg, [
  2106. {msg: ansF, result: 0},
  2107. {msg: ansS, result: 1},
  2108. {msg: ansT, result: 2},
  2109. ]);
  2110. }
  2111.  
  2112. let changeRequest = false;
  2113. testData = JSON.parse(tempData);
  2114. for (const call of testData.calls) {
  2115. if (!artifactChestOpen) {
  2116. requestHistory[this.uniqid].calls[call.name] = call.ident;
  2117. }
  2118. /**
  2119. * Сбор подарка
  2120. */
  2121. /*
  2122. if (call.name == 'registration') {
  2123. if (!call.args?.giftId) {
  2124. const giftId = await getGiftCode();
  2125. if (giftId) {
  2126. call.args.giftId = giftId;
  2127. changeRequest = true;
  2128. }
  2129. } else {
  2130. sendGiftsCodes([call.args.giftId])
  2131. }
  2132. }
  2133. */
  2134. /**
  2135. * Cancellation of the battle in adventures, on VG and with minions of Asgard
  2136. * Отмена боя в приключениях, на ВГ и с прислужниками Асгарда
  2137. */
  2138. if ((call.name == 'adventure_endBattle' ||
  2139. call.name == 'adventureSolo_endBattle' ||
  2140. call.name == 'clanWarEndBattle' &&
  2141. isChecked('cancelBattle') ||
  2142. call.name == 'crossClanWar_endBattle' &&
  2143. isChecked('cancelBattle') ||
  2144. call.name == 'brawl_endBattle' ||
  2145. call.name == 'towerEndBattle' ||
  2146. call.name == 'invasion_bossEnd' ||
  2147. call.name == 'bossEndBattle' ||
  2148. call.name == 'clanRaid_endNodeBattle') &&
  2149. isCancalBattle) {
  2150. nameFuncEndBattle = call.name;
  2151. if (!call.args.result.win) {
  2152. let resultPopup = false;
  2153. if (call.name == 'adventure_endBattle' ||
  2154. call.name == 'invasion_bossEnd' ||
  2155. call.name == 'bossEndBattle' ||
  2156. call.name == 'adventureSolo_endBattle') {
  2157. resultPopup = await showMsgs(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  2158. } else if (call.name == 'clanWarEndBattle' ||
  2159. call.name == 'crossClanWar_endBattle') {
  2160. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_AUTO_F5'));
  2161. } else {
  2162. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'));
  2163. }
  2164. if (resultPopup) {
  2165. if (call.name == 'invasion_bossEnd') {
  2166. this.errorRequest = true;
  2167. }
  2168. fixBattle(call.args.progress[0].attackers.heroes);
  2169. fixBattle(call.args.progress[0].defenders.heroes);
  2170. changeRequest = true;
  2171. if (resultPopup > 1) {
  2172. this.onReadySuccess = testAutoBattle;
  2173. // setTimeout(bossBattle, 1000);
  2174. }
  2175. }
  2176. } else if (call.args.result.stars < 3 && call.name == 'towerEndBattle') {
  2177. resultPopup = await showMsg(I18N('LOST_HEROES'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  2178. if (resultPopup) {
  2179. fixBattle(call.args.progress[0].attackers.heroes);
  2180. fixBattle(call.args.progress[0].defenders.heroes);
  2181. changeRequest = true;
  2182. if (resultPopup > 1) {
  2183. this.onReadySuccess = testAutoBattle;
  2184. }
  2185. }
  2186. }
  2187. // Потасовки
  2188. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_endBattle') {
  2189. if (await popup.confirm(I18N('START_AUTO_BRAWLS'), [
  2190. { msg: I18N('BTN_NO'), result: false },
  2191. { msg: I18N('BTN_YES'), result: true },
  2192. ])) {
  2193. this.onReadySuccess = testBrawls;
  2194. isBrawlsAutoStart = true;
  2195. }
  2196. }
  2197. }
  2198. /**
  2199. * Save pack for Brawls
  2200. *
  2201. * Сохраняем пачку для потасовок
  2202. */
  2203. if (call.name == 'brawl_startBattle') {
  2204. console.log(JSON.stringify(call.args));
  2205. brawlsPack = call.args;
  2206. }
  2207. /**
  2208. * Canceled fight in Asgard
  2209. * Отмена боя в Асгарде
  2210. */
  2211. if (call.name == 'clanRaid_endBossBattle' &&
  2212. isCancalBossBattle &&
  2213. isChecked('cancelBattle')) {
  2214. bossDamage = call.args.progress[0].defenders.heroes[1].extra;
  2215. sumDamage = bossDamage.damageTaken + bossDamage.damageTakenNextLevel;
  2216. let resultPopup = await showMsgs(
  2217. `${I18N('MSG_YOU_APPLIED')} ${sumDamage.toLocaleString()} ${I18N('MSG_DAMAGE')}.`,
  2218. I18N('BTN_OK'), I18N('BTN_AUTO_F5'), I18N('MSG_CANCEL_AND_STAT'))
  2219. if (resultPopup) {
  2220. fixBattle(call.args.progress[0].attackers.heroes);
  2221. fixBattle(call.args.progress[0].defenders.heroes);
  2222. changeRequest = true;
  2223. if (resultPopup > 1) {
  2224. this.onReadySuccess = testBossBattle;
  2225. // setTimeout(bossBattle, 1000);
  2226. }
  2227. }
  2228. }
  2229. /**
  2230. * Save the Asgard Boss Attack Pack
  2231. * Сохраняем пачку для атаки босса Асгарда
  2232. */
  2233. if (call.name == 'clanRaid_startBossBattle') {
  2234. lastBossBattle = call.args;
  2235. }
  2236. /**
  2237. * Saving the request to start the last battle
  2238. * Сохранение запроса начала последнего боя
  2239. */
  2240. if (call.name == 'clanWarAttack' ||
  2241. call.name == 'crossClanWar_startBattle' ||
  2242. call.name == 'adventure_turnStartBattle' ||
  2243. call.name == 'bossAttack' ||
  2244. call.name == 'invasion_bossStart' ||
  2245. call.name == 'towerStartBattle') {
  2246. nameFuncStartBattle = call.name;
  2247. lastBattleArg = call.args;
  2248.  
  2249. if (call.name == 'invasion_bossStart') {
  2250. const timePassed = Date.now() - lastBossBattleStart;
  2251. if (timePassed < invasionTimer) {
  2252. await new Promise((e) => setTimeout(e, invasionTimer - timePassed));
  2253. }
  2254. invasionTimer -= 1;
  2255. }
  2256. lastBossBattleStart = Date.now();
  2257. }
  2258. if (call.name == 'invasion_bossEnd') {
  2259. const lastBattle = lastBattleInfo;
  2260. if (lastBattle && call.args.result.win) {
  2261. lastBattle.progress = call.args.progress;
  2262. const result = await Calc(lastBattle);
  2263. let timer = getTimer(result.battleTime, 1) + addBattleTimer;
  2264. const period = Math.ceil((Date.now() - lastBossBattleStart) / 1000);
  2265. console.log(timer, period);
  2266. if (period < timer) {
  2267. timer = timer - period;
  2268. await countdownTimer(timer);
  2269. }
  2270. }
  2271. }
  2272. /**
  2273. * Disable spending divination cards
  2274. * Отключить трату карт предсказаний
  2275. */
  2276. if (call.name == 'dungeonEndBattle') {
  2277. if (call.args.isRaid) {
  2278. if (countPredictionCard <= 0) {
  2279. delete call.args.isRaid;
  2280. changeRequest = true;
  2281. } else if (countPredictionCard > 0) {
  2282. countPredictionCard--;
  2283. }
  2284. }
  2285. console.log(`Cards: ${countPredictionCard}`);
  2286. /**
  2287. * Fix endless cards
  2288. * Исправление бесконечных карт
  2289. */
  2290. const lastBattle = lastDungeonBattleData;
  2291. if (lastBattle && !call.args.isRaid) {
  2292. if (changeRequest) {
  2293. lastBattle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2294. } else {
  2295. lastBattle.progress = call.args.progress;
  2296. }
  2297. const result = await Calc(lastBattle);
  2298.  
  2299. if (changeRequest) {
  2300. call.args.progress = result.progress;
  2301. call.args.result = result.result;
  2302. }
  2303.  
  2304. let timer = getTimer(result.battleTime) + addBattleTimer;
  2305. const period = Math.ceil((Date.now() - lastDungeonBattleStart) / 1000);
  2306. console.log(timer, period);
  2307. if (period < timer) {
  2308. timer = timer - period;
  2309. await countdownTimer(timer);
  2310. }
  2311. }
  2312. }
  2313. /**
  2314. * Quiz Answer
  2315. * Ответ на викторину
  2316. */
  2317. if (call.name == 'quizAnswer') {
  2318. /**
  2319. * Automatically changes the answer to the correct one if there is one.
  2320. * Автоматически меняет ответ на правильный если он есть
  2321. */
  2322. if (lastAnswer && isChecked('getAnswer')) {
  2323. call.args.answerId = lastAnswer;
  2324. lastAnswer = null;
  2325. changeRequest = true;
  2326. }
  2327. }
  2328. /**
  2329. * Present
  2330. * Подарки
  2331. */
  2332. if (call.name == 'freebieCheck') {
  2333. freebieCheckInfo = call;
  2334. }
  2335. /** missionTimer */
  2336. if (call.name == 'missionEnd' && missionBattle) {
  2337. missionBattle.progress = call.args.progress;
  2338. missionBattle.result = call.args.result;
  2339. const result = await Calc(missionBattle);
  2340.  
  2341. let timer = getTimer(result.battleTime) + addBattleTimer;
  2342. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  2343. if (period < timer) {
  2344. timer = timer - period;
  2345. await countdownTimer(timer);
  2346. }
  2347. missionBattle = null;
  2348. }
  2349. /**
  2350. * Getting mission data for auto-repeat
  2351. * Получение данных миссии для автоповтора
  2352. */
  2353. if (isChecked('repeatMission') &&
  2354. call.name == 'missionEnd') {
  2355. let missionInfo = {
  2356. id: call.args.id,
  2357. result: call.args.result,
  2358. heroes: call.args.progress[0].attackers.heroes,
  2359. count: 0,
  2360. }
  2361. setTimeout(async () => {
  2362. if (!isSendsMission && await popup.confirm(I18N('MSG_REPEAT_MISSION'), [
  2363. { msg: I18N('BTN_REPEAT'), result: true},
  2364. { msg: I18N('BTN_NO'), result: false},
  2365. ])) {
  2366. isStopSendMission = false;
  2367. isSendsMission = true;
  2368. sendsMission(missionInfo);
  2369. }
  2370. }, 0);
  2371. }
  2372. /**
  2373. * Getting mission data
  2374. * Получение данных миссии
  2375. * missionTimer
  2376. */
  2377. if (call.name == 'missionStart') {
  2378. lastMissionStart = call.args;
  2379. lastMissionBattleStart = Date.now();
  2380. }
  2381.  
  2382. /**
  2383. * Specify the quantity for Titan Orbs and Pet Eggs
  2384. * Указать количество для сфер титанов и яиц петов
  2385. */
  2386. if (isChecked('countControl') &&
  2387. (call.name == 'pet_chestOpen' ||
  2388. call.name == 'titanUseSummonCircle') &&
  2389. call.args.amount > 1) {
  2390. call.args.amount = 1;
  2391. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2392. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2393. ]);
  2394. if (result) {
  2395. call.args.amount = result;
  2396. changeRequest = true;
  2397. }
  2398. }
  2399. /**
  2400. * Specify the amount for keys and spheres of titan artifacts
  2401. * Указать колличество для ключей и сфер артефактов титанов
  2402. */
  2403. if (isChecked('countControl') &&
  2404. (call.name == 'artifactChestOpen' ||
  2405. call.name == 'titanArtifactChestOpen') &&
  2406. call.args.amount > 1 &&
  2407. call.args.free &&
  2408. !changeRequest) {
  2409. artifactChestOpenCallName = call.name;
  2410. let result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2411. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount },
  2412. ]);
  2413. if (result) {
  2414. let sphere = result < 10 ? 1 : 10;
  2415.  
  2416. call.args.amount = sphere;
  2417. result -= sphere;
  2418.  
  2419. for (let count = result; count > 0; count -= sphere) {
  2420. if (count < 10) sphere = 1;
  2421. const ident = artifactChestOpenCallName + "_" + count;
  2422. testData.calls.push({
  2423. name: artifactChestOpenCallName,
  2424. args: {
  2425. amount: sphere,
  2426. free: true,
  2427. },
  2428. ident: ident
  2429. });
  2430. if (!Array.isArray(requestHistory[this.uniqid].calls[call.name])) {
  2431. requestHistory[this.uniqid].calls[call.name] = [requestHistory[this.uniqid].calls[call.name]];
  2432. }
  2433. requestHistory[this.uniqid].calls[call.name].push(ident);
  2434. }
  2435.  
  2436. artifactChestOpen = true;
  2437. changeRequest = true;
  2438. }
  2439. }
  2440. if (call.name == 'consumableUseLootBox') {
  2441. lastRussianDollId = call.args.libId;
  2442. /**
  2443. * Specify quantity for gold caskets
  2444. * Указать количество для золотых шкатулок
  2445. */
  2446. if (isChecked('countControl') &&
  2447. call.args.libId == 148 &&
  2448. call.args.amount > 1) {
  2449. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2450. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2451. ]);
  2452. call.args.amount = result;
  2453. changeRequest = true;
  2454. }
  2455. }
  2456. /**
  2457. * Changing the maximum number of raids in the campaign
  2458. * Изменение максимального количества рейдов в кампании
  2459. */
  2460. // if (call.name == 'missionRaid') {
  2461. // if (isChecked('countControl') && call.args.times > 1) {
  2462. // const result = +(await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2463. // { msg: I18N('BTN_RUN'), isInput: true, default: call.args.times },
  2464. // ]));
  2465. // call.args.times = result > call.args.times ? call.args.times : result;
  2466. // changeRequest = true;
  2467. // }
  2468. // }
  2469. }
  2470.  
  2471. let headers = requestHistory[this.uniqid].headers;
  2472. if (changeRequest) {
  2473. sourceData = JSON.stringify(testData);
  2474. headers['X-Auth-Signature'] = getSignature(headers, sourceData);
  2475. }
  2476.  
  2477. let signature = headers['X-Auth-Signature'];
  2478. if (signature) {
  2479. original.setRequestHeader.call(this, 'X-Auth-Signature', signature);
  2480. }
  2481. } catch (err) {
  2482. console.log("Request(send, " + this.uniqid + "):\n", sourceData, "Error:\n", err);
  2483. }
  2484. return sourceData;
  2485. }
  2486. /**
  2487. * Processing and substitution of incoming data
  2488. *
  2489. * Обработка и подмена входящих данных
  2490. */
  2491. async function checkChangeResponse(response) {
  2492. try {
  2493. isChange = false;
  2494. let nowTime = Math.round(Date.now() / 1000);
  2495. callsIdent = requestHistory[this.uniqid].calls;
  2496. respond = JSON.parse(response);
  2497. /**
  2498. * If the request returned an error removes the error (removes synchronization errors)
  2499. * Если запрос вернул ошибку удаляет ошибку (убирает ошибки синхронизации)
  2500. */
  2501. if (respond.error) {
  2502. isChange = true;
  2503. console.error(respond.error);
  2504. if (isChecked('showErrors')) {
  2505. popup.confirm(I18N('ERROR_MSG', {
  2506. name: respond.error.name,
  2507. description: respond.error.description,
  2508. }));
  2509. }
  2510. delete respond.error;
  2511. respond.results = [];
  2512. }
  2513. let mainReward = null;
  2514. const allReward = {};
  2515. let countTypeReward = 0;
  2516. let readQuestInfo = false;
  2517. for (const call of respond.results) {
  2518. /**
  2519. * Obtaining initial data for completing quests
  2520. * Получение исходных данных для выполнения квестов
  2521. */
  2522. if (readQuestInfo) {
  2523. questsInfo[call.ident] = call.result.response;
  2524. }
  2525. /**
  2526. * Getting a user ID
  2527. * Получение идетификатора пользователя
  2528. */
  2529. if (call.ident == callsIdent['registration']) {
  2530. userId = call.result.response.userId;
  2531. if (localStorage['userId'] != userId) {
  2532. localStorage['newGiftSendIds'] = '';
  2533. localStorage['userId'] = userId;
  2534. }
  2535. await openOrMigrateDatabase(userId);
  2536. readQuestInfo = true;
  2537. }
  2538. /**
  2539. * Hiding donation offers 1
  2540. * Скрываем предложения доната 1
  2541. */
  2542. if (call.ident == callsIdent['billingGetAll'] && getSaveVal('noOfferDonat')) {
  2543. const billings = call.result.response?.billings;
  2544. const bundle = call.result.response?.bundle;
  2545. if (billings && bundle) {
  2546. call.result.response.billings = [];
  2547. call.result.response.bundle = [];
  2548. isChange = true;
  2549. }
  2550. }
  2551. /**
  2552. * Hiding donation offers 2
  2553. * Скрываем предложения доната 2
  2554. */
  2555. if (getSaveVal('noOfferDonat') &&
  2556. (call.ident == callsIdent['offerGetAll'] ||
  2557. call.ident == callsIdent['specialOffer_getAll'])) {
  2558. let offers = call.result.response;
  2559. if (offers) {
  2560. call.result.response = offers.filter(e => !['addBilling', 'bundleCarousel'].includes(e.type) || ['idleResource'].includes(e.offerType));
  2561. isChange = true;
  2562. }
  2563. }
  2564. /**
  2565. * Hiding donation offers 3
  2566. * Скрываем предложения доната 3
  2567. */
  2568. if (getSaveVal('noOfferDonat') && call.result?.bundleUpdate) {
  2569. delete call.result.bundleUpdate;
  2570. isChange = true;
  2571. }
  2572. /**
  2573. * Copies a quiz question to the clipboard
  2574. * Копирует вопрос викторины в буфер обмена и получает на него ответ если есть
  2575. */
  2576. if (call.ident == callsIdent['quizGetNewQuestion']) {
  2577. let quest = call.result.response;
  2578. console.log(quest.question);
  2579. copyText(quest.question);
  2580. setProgress(I18N('QUESTION_COPY'), true);
  2581. quest.lang = null;
  2582. if (typeof NXFlashVars !== 'undefined') {
  2583. quest.lang = NXFlashVars.interface_lang;
  2584. }
  2585. lastQuestion = quest;
  2586. if (isChecked('getAnswer')) {
  2587. const answer = await getAnswer(lastQuestion);
  2588. let showText = '';
  2589. if (answer) {
  2590. lastAnswer = answer;
  2591. console.log(answer);
  2592. showText = `${I18N('ANSWER_KNOWN')}: ${answer}`;
  2593. } else {
  2594. showText = I18N('ANSWER_NOT_KNOWN');
  2595. }
  2596.  
  2597. try {
  2598. const hint = hintQuest(quest);
  2599. if (hint) {
  2600. showText += I18N('HINT') + hint;
  2601. }
  2602. } catch(e) {}
  2603.  
  2604. setProgress(showText, true);
  2605. }
  2606. }
  2607. /**
  2608. * Submits a question with an answer to the database
  2609. * Отправляет вопрос с ответом в базу данных
  2610. */
  2611. if (call.ident == callsIdent['quizAnswer']) {
  2612. const answer = call.result.response;
  2613. if (lastQuestion) {
  2614. const answerInfo = {
  2615. answer,
  2616. question: lastQuestion,
  2617. lang: null,
  2618. }
  2619. if (typeof NXFlashVars !== 'undefined') {
  2620. answerInfo.lang = NXFlashVars.interface_lang;
  2621. }
  2622. lastQuestion = null;
  2623. setTimeout(sendAnswerInfo, 0, answerInfo);
  2624. }
  2625. }
  2626. /**
  2627. * Get user data
  2628. * Получить даныне пользователя
  2629. */
  2630. if (call.ident == callsIdent['userGetInfo']) {
  2631. let user = call.result.response;
  2632. userInfo = Object.assign({}, user);
  2633. delete userInfo.refillable;
  2634. if (!questsInfo['userGetInfo']) {
  2635. questsInfo['userGetInfo'] = user;
  2636. }
  2637. }
  2638. /**
  2639. * Start of the battle for recalculation
  2640. * Начало боя для прерасчета
  2641. */
  2642. if (call.ident == callsIdent['clanWarAttack'] ||
  2643. call.ident == callsIdent['crossClanWar_startBattle'] ||
  2644. call.ident == callsIdent['bossAttack'] ||
  2645. call.ident == callsIdent['battleGetReplay'] ||
  2646. call.ident == callsIdent['brawl_startBattle'] ||
  2647. call.ident == callsIdent['adventureSolo_turnStartBattle'] ||
  2648. call.ident == callsIdent['invasion_bossStart'] ||
  2649. call.ident == callsIdent['towerStartBattle'] ||
  2650. call.ident == callsIdent['adventure_turnStartBattle']) {
  2651. let battle = call.result.response.battle || call.result.response.replay;
  2652. if (call.ident == callsIdent['brawl_startBattle'] ||
  2653. call.ident == callsIdent['bossAttack'] ||
  2654. call.ident == callsIdent['towerStartBattle'] ||
  2655. call.ident == callsIdent['invasion_bossStart']) {
  2656. battle = call.result.response;
  2657. }
  2658. lastBattleInfo = battle;
  2659. if (!isChecked('preCalcBattle')) {
  2660. continue;
  2661. }
  2662. setProgress(I18N('BEING_RECALC'));
  2663. let battleDuration = 120;
  2664. try {
  2665. const typeBattle = getBattleType(battle.type);
  2666. battleDuration = +lib.data.battleConfig[typeBattle.split('_')[1]].config.battleDuration;
  2667. } catch (e) { }
  2668. //console.log(battle.type);
  2669. function getBattleInfo(battle, isRandSeed) {
  2670. return new Promise(function (resolve) {
  2671. if (isRandSeed) {
  2672. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  2673. }
  2674. BattleCalc(battle, getBattleType(battle.type), e => resolve(e));
  2675. });
  2676. }
  2677. let actions = [getBattleInfo(battle, false)]
  2678. const countTestBattle = getInput('countTestBattle');
  2679. if (call.ident == callsIdent['battleGetReplay']) {
  2680. battle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2681. }
  2682. for (let i = 0; i < countTestBattle; i++) {
  2683. actions.push(getBattleInfo(battle, true));
  2684. }
  2685. Promise.all(actions)
  2686. .then(e => {
  2687. e = e.map(n => ({win: n.result.win, time: n.battleTime}));
  2688. let firstBattle = e.shift();
  2689. const timer = Math.floor(battleDuration - firstBattle.time);
  2690. const min = ('00' + Math.floor(timer / 60)).slice(-2);
  2691. const sec = ('00' + Math.floor(timer - min * 60)).slice(-2);
  2692. const countWin = e.reduce((w, s) => w + s.win, 0);
  2693. 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)
  2694. });
  2695. }
  2696. //тест сохранки
  2697. /** Запоминаем команды в реплее*/
  2698. if (call.ident == callsIdent['battleGetReplay']) {
  2699. let battle = call.result.response.replay;
  2700. repleyBattle.attackers = battle.attackers;
  2701. repleyBattle.defenders = battle.defenders[0];
  2702. repleyBattle.effects = battle.effects.defenders;
  2703. repleyBattle.state = battle.progress[0].defenders.heroes;
  2704. repleyBattle.seed = battle.seed;
  2705. }
  2706. /** Нападение в турнире*/
  2707. if (call.ident == callsIdent['titanArenaStartBattle']) {
  2708. let bestBattle = getInput('countBattle');
  2709. let unrandom = getInput('needResource');
  2710. let maxPower = getInput('needResource2');
  2711. if (bestBattle * unrandom * maxPower == 0) {
  2712. let battle = call.result.response.battle;
  2713. if (bestBattle == 0) {
  2714. battle.progress = bestLordBattle[battle.typeId]?.progress;
  2715. }
  2716. if (unrandom == 0 && !!repleyBattle.seed) {
  2717. battle.seed = repleyBattle.seed;
  2718. }
  2719. if (maxPower == 0) {
  2720. battle.attackers = getTitansPack(Object.keys(battle.attackers));
  2721. }
  2722. isChange = true;
  2723. }
  2724. }
  2725. /** Тест боев с усилениями команд защиты*/
  2726. if (call.ident == callsIdent['chatAcceptChallenge']) {
  2727. let battle = call.result.response.battle;
  2728. addBuff(battle);
  2729. let testType = getInput('countBattle');
  2730. if (testType.slice(0, 1) == "-") {
  2731. testType = parseInt(testType.slice(1), 10);
  2732. switch (testType) {
  2733. case 1:
  2734. battle.defenders[0] = repleyBattle.defenders;
  2735. break; //наша атака против защиты из реплея
  2736. case 2:
  2737. battle.defenders[0] = repleyBattle.attackers;
  2738. break; //наша атака против атаки из реплея
  2739. case 3:
  2740. battle.attackers = repleyBattle.attackers;
  2741. break; //атака из реплея против защиты в чате
  2742. case 4:
  2743. battle.attackers = repleyBattle.defenders;
  2744. break; //защита из реплея против защиты в чате
  2745. case 5:
  2746. battle.attackers = repleyBattle.attackers;
  2747. battle.defenders[0] = repleyBattle.defenders;
  2748. break; //атака из реплея против защиты из реплея
  2749. case 6:
  2750. battle.attackers = repleyBattle.defenders;
  2751. battle.defenders[0] = repleyBattle.attackers;
  2752. break; //защита из реплея против атаки из реплея
  2753. case 7:
  2754. battle.attackers = repleyBattle.attackers;
  2755. battle.defenders[0] = repleyBattle.attackers;
  2756. break; //атака из реплея против атаки из реплея
  2757. case 8:
  2758. battle.attackers = repleyBattle.defenders;
  2759. battle.defenders[0] = repleyBattle.defenders;
  2760. break; //защита из реплея против защиты из реплея
  2761. }
  2762. }
  2763.  
  2764. isChange = true;
  2765. }
  2766. /** Тест боев с усилениями команд защиты тренировках*/
  2767. if (call.ident == callsIdent['demoBattles_startBattle']) {
  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. }
  2803. }
  2804.  
  2805. isChange = true;
  2806. }
  2807. //тест сохранки
  2808. /**
  2809. * Start of the Asgard boss fight
  2810. * Начало боя с боссом Асгарда
  2811. */
  2812. if (call.ident == callsIdent['clanRaid_startBossBattle']) {
  2813. lastBossBattleInfo = call.result.response.battle;
  2814. if (isChecked('preCalcBattle')) {
  2815. const result = await Calc(lastBossBattleInfo).then(e => e.progress[0].defenders.heroes[1].extra);
  2816. const bossDamage = result.damageTaken + result.damageTakenNextLevel;
  2817. setProgress(I18N('BOSS_DAMAGE') + bossDamage.toLocaleString(), false, hideProgress);
  2818. }
  2819. }
  2820. /**
  2821. * Cancel tutorial
  2822. * Отмена туториала
  2823. */
  2824. if (isCanceledTutorial && call.ident == callsIdent['tutorialGetInfo']) {
  2825. let chains = call.result.response.chains;
  2826. for (let n in chains) {
  2827. chains[n] = 9999;
  2828. }
  2829. isChange = true;
  2830. }
  2831. /**
  2832. * Opening keys and spheres of titan artifacts
  2833. * Открытие ключей и сфер артефактов титанов
  2834. */
  2835. if (artifactChestOpen &&
  2836. (call.ident == callsIdent[artifactChestOpenCallName] ||
  2837. (callsIdent[artifactChestOpenCallName] && callsIdent[artifactChestOpenCallName].includes(call.ident)))) {
  2838. let reward = call.result.response[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'];
  2839.  
  2840. reward.forEach(e => {
  2841. for (let f in e) {
  2842. if (!allReward[f]) {
  2843. allReward[f] = {};
  2844. }
  2845. for (let o in e[f]) {
  2846. if (!allReward[f][o]) {
  2847. allReward[f][o] = e[f][o];
  2848. countTypeReward++;
  2849. } else {
  2850. allReward[f][o] += e[f][o];
  2851. }
  2852. }
  2853. }
  2854. });
  2855.  
  2856. if (!call.ident.includes(artifactChestOpenCallName)) {
  2857. mainReward = call.result.response;
  2858. }
  2859. }
  2860.  
  2861. if (countTypeReward > 20) {
  2862. correctShowOpenArtifact = 3;
  2863. } else {
  2864. correctShowOpenArtifact = 0;
  2865. }
  2866.  
  2867. /**
  2868. * Sum the result of opening Pet Eggs
  2869. * Суммирование результата открытия яиц питомцев
  2870. */
  2871. if (isChecked('countControl') && call.ident == callsIdent['pet_chestOpen']) {
  2872. const rewards = call.result.response.rewards;
  2873. if (rewards.length > 10) {
  2874. /**
  2875. * Removing pet cards
  2876. * Убираем карточки петов
  2877. */
  2878. for (const reward of rewards) {
  2879. if (reward.petCard) {
  2880. delete reward.petCard;
  2881. }
  2882. }
  2883. }
  2884. rewards.forEach(e => {
  2885. for (let f in e) {
  2886. if (!allReward[f]) {
  2887. allReward[f] = {};
  2888. }
  2889. for (let o in e[f]) {
  2890. if (!allReward[f][o]) {
  2891. allReward[f][o] = e[f][o];
  2892. } else {
  2893. allReward[f][o] += e[f][o];
  2894. }
  2895. }
  2896. }
  2897. });
  2898. call.result.response.rewards = [allReward];
  2899. isChange = true;
  2900. }
  2901. /**
  2902. * Removing titan cards
  2903. * Убираем карточки титанов
  2904. */
  2905. if (call.ident == callsIdent['titanUseSummonCircle']) {
  2906. if (call.result.response.rewards.length > 10) {
  2907. for (const reward of call.result.response.rewards) {
  2908. if (reward.titanCard) {
  2909. delete reward.titanCard;
  2910. }
  2911. }
  2912. isChange = true;
  2913. }
  2914. }
  2915. /**
  2916. * Auto-repeat opening matryoshkas
  2917. * АвтоПовтор открытия матрешек
  2918. */
  2919. if (isChecked('countControl') && call.ident == callsIdent['consumableUseLootBox']) {
  2920. let lootBox = call.result.response;
  2921. let newCount = 0;
  2922. for (let n of lootBox) {
  2923. if (n?.consumable && n.consumable[lastRussianDollId]) {
  2924. newCount += n.consumable[lastRussianDollId]
  2925. }
  2926. }
  2927. if (newCount && await popup.confirm(`${I18N('BTN_OPEN')} ${newCount} ${I18N('OPEN_DOLLS')}?`, [
  2928. { msg: I18N('BTN_OPEN'), result: true},
  2929. { msg: I18N('BTN_NO'), result: false},
  2930. ])) {
  2931. const recursionResult = await openRussianDolls(lastRussianDollId, newCount);
  2932. lootBox = [...lootBox, ...recursionResult];
  2933. }
  2934.  
  2935. /** Объединение результата лутбоксов */
  2936. const allLootBox = {};
  2937. lootBox.forEach(e => {
  2938. for (let f in e) {
  2939. if (!allLootBox[f]) {
  2940. if (typeof e[f] == 'object') {
  2941. allLootBox[f] = {};
  2942. } else {
  2943. allLootBox[f] = 0;
  2944. }
  2945. }
  2946. if (typeof e[f] == 'object') {
  2947. for (let o in e[f]) {
  2948. if (newCount && o == lastRussianDollId) {
  2949. continue;
  2950. }
  2951. if (!allLootBox[f][o]) {
  2952. allLootBox[f][o] = e[f][o];
  2953. } else {
  2954. allLootBox[f][o] += e[f][o];
  2955. }
  2956. }
  2957. } else {
  2958. allLootBox[f] += e[f];
  2959. }
  2960. }
  2961. });
  2962. /** Разбитие результата */
  2963. const output = [];
  2964. const maxCount = 5;
  2965. let currentObj = {};
  2966. let count = 0;
  2967. for (let f in allLootBox) {
  2968. if (!currentObj[f]) {
  2969. if (typeof allLootBox[f] == 'object') {
  2970. for (let o in allLootBox[f]) {
  2971. currentObj[f] ||= {}
  2972. if (!currentObj[f][o]) {
  2973. currentObj[f][o] = allLootBox[f][o];
  2974. count++;
  2975. if (count === maxCount) {
  2976. output.push(currentObj);
  2977. currentObj = {};
  2978. count = 0;
  2979. }
  2980. }
  2981. }
  2982. } else {
  2983. currentObj[f] = allLootBox[f];
  2984. count++;
  2985. if (count === maxCount) {
  2986. output.push(currentObj);
  2987. currentObj = {};
  2988. count = 0;
  2989. }
  2990. }
  2991. }
  2992. }
  2993. if (count > 0) {
  2994. output.push(currentObj);
  2995. }
  2996.  
  2997. console.log(output);
  2998. call.result.response = output;
  2999. isChange = true;
  3000. }
  3001. /**
  3002. * Dungeon recalculation (fix endless cards)
  3003. * Прерасчет подземки (исправление бесконечных карт)
  3004. */
  3005. if (call.ident == callsIdent['dungeonStartBattle']) {
  3006. lastDungeonBattleData = call.result.response;
  3007. lastDungeonBattleStart = Date.now();
  3008. }
  3009. /**
  3010. * Getting the number of prediction cards
  3011. * Получение количества карт предсказаний
  3012. */
  3013. if (call.ident == callsIdent['inventoryGet']) {
  3014. countPredictionCard = call.result.response.consumable[81] || 0;
  3015. }
  3016. /**
  3017. * Getting subscription status
  3018. * Получение состояния подписки
  3019. */
  3020. if (call.ident == callsIdent['subscriptionGetInfo']) {
  3021. const subscription = call.result.response.subscription;
  3022. if (subscription) {
  3023. subEndTime = subscription.endTime * 1000;
  3024. }
  3025. }
  3026. /**
  3027. * Getting prediction cards
  3028. * Получение карт предсказаний
  3029. */
  3030. if (call.ident == callsIdent['questFarm']) {
  3031. const consumable = call.result.response?.consumable;
  3032. if (consumable && consumable[81]) {
  3033. countPredictionCard += consumable[81];
  3034. console.log(`Cards: ${countPredictionCard}`);
  3035. }
  3036. }
  3037. /**
  3038. * Hiding extra servers
  3039. * Скрытие лишних серверов
  3040. */
  3041. if (call.ident == callsIdent['serverGetAll'] && isChecked('hideServers')) {
  3042. let servers = call.result.response.users.map(s => s.serverId)
  3043. call.result.response.servers = call.result.response.servers.filter(s => servers.includes(s.id));
  3044. isChange = true;
  3045. }
  3046. /**
  3047. * Displays player positions in the adventure
  3048. * Отображает позиции игроков в приключении
  3049. */
  3050. if (call.ident == callsIdent['adventure_getLobbyInfo']) {
  3051. const users = Object.values(call.result.response.users);
  3052. const mapIdent = call.result.response.mapIdent;
  3053. const adventureId = call.result.response.adventureId;
  3054. const maps = {
  3055. adv_strongford_3pl_hell: 9,
  3056. adv_valley_3pl_hell: 10,
  3057. adv_ghirwil_3pl_hell: 11,
  3058. adv_angels_3pl_hell: 12,
  3059. }
  3060. let msg = I18N('MAP') + (mapIdent in maps ? maps[mapIdent] : adventureId);
  3061. msg += '<br>' + I18N('PLAYER_POS');
  3062. for (const user of users) {
  3063. msg += `<br>${user.user.name} - ${user.currentNode}`;
  3064. }
  3065. setProgress(msg, false, hideProgress);
  3066. }
  3067. /**
  3068. * Automatic launch of a raid at the end of the adventure
  3069. * Автоматический запуск рейда при окончании приключения
  3070. */
  3071. if (call.ident == callsIdent['adventure_end']) {
  3072. autoRaidAdventure()
  3073. }
  3074. /** Удаление лавки редкостей */
  3075. if (call.ident == callsIdent['missionRaid']) {
  3076. if (call.result?.heroesMerchant) {
  3077. delete call.result.heroesMerchant;
  3078. isChange = true;
  3079. }
  3080. }
  3081. /** missionTimer */
  3082. if (call.ident == callsIdent['missionStart']) {
  3083. missionBattle = call.result.response;
  3084. }
  3085. }
  3086.  
  3087. if (mainReward && artifactChestOpen) {
  3088. console.log(allReward);
  3089. mainReward[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'] = [allReward];
  3090. artifactChestOpen = false;
  3091. artifactChestOpenCallName = '';
  3092. isChange = true;
  3093. }
  3094. } catch(err) {
  3095. console.log("Request(response, " + this.uniqid + "):\n", "Error:\n", response, err);
  3096. }
  3097.  
  3098. if (isChange) {
  3099. Object.defineProperty(this, 'responseText', {
  3100. writable: true
  3101. });
  3102. this.responseText = JSON.stringify(respond);
  3103. }
  3104. }
  3105.  
  3106. /** Добавляет в бой эффекты усиления*/
  3107. function addBuff(battle) {
  3108. let effects = battle.effects;
  3109. let buffType = getInput('needResource2');
  3110. if (-1 < buffType && buffType < 7) {
  3111. let percentBuff = getInput('needResource');
  3112. effects.defenders = {};
  3113. effects.defenders[buffs[buffType]] = percentBuff;
  3114. } else if (buffType.slice(0, 1) == "-" || isChecked('treningBattle')) {
  3115. buffType = parseInt(buffType.slice(1), 10);
  3116. effects.defenders = repleyBattle.effects;
  3117. battle.defenders[0] = repleyBattle.defenders;
  3118. let def = battle.defenders[0];
  3119. if (buffType == 1) {
  3120. for (let i in def) {
  3121. let state = def[i].state;
  3122. state.hp = state.maxHp;
  3123. state.energy = 0;
  3124. state.isDead = false;
  3125. }
  3126. } else if (buffType == 2 || isChecked('finishingBattle')) {
  3127. for (let i in def) {
  3128. let state = def[i].state;
  3129. let rState = repleyBattle.state[i];
  3130. if (!!rState) {
  3131. state.hp = rState.hp;
  3132. state.energy = rState.energy;
  3133. state.isDead = rState.isDead;
  3134. } else {
  3135. state.hp = 0;
  3136. state.energy = 0;
  3137. state.isDead = true;
  3138. }
  3139. }
  3140. }
  3141. }
  3142. }
  3143. 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'];
  3144.  
  3145. /**
  3146. * Request an answer to a question
  3147. *
  3148. * Запрос ответа на вопрос
  3149. */
  3150. async function getAnswer(question) {
  3151. const now = Date.now();
  3152. const body = JSON.stringify({ ...question, now });
  3153. const signature = window['\x73\x69\x67\x6e'](now);
  3154. return new Promise((resolve, reject) => {
  3155. fetch('https://zingery.ru/heroes/getAnswer.php', {
  3156. method: 'POST',
  3157. headers: {
  3158. 'X-Request-Signature': signature,
  3159. 'X-Script-Name': GM_info.script.name,
  3160. 'X-Script-Version': GM_info.script.version,
  3161. 'X-Script-Author': GM_info.script.author,
  3162. },
  3163. body,
  3164. }).then(
  3165. response => response.json()
  3166. ).then(
  3167. data => {
  3168. if (data.result) {
  3169. resolve(data.result);
  3170. } else {
  3171. resolve(false);
  3172. }
  3173. }
  3174. ).catch((error) => {
  3175. console.error(error);
  3176. resolve(false);
  3177. });
  3178. })
  3179. }
  3180.  
  3181. /**
  3182. * Submitting a question and answer to a database
  3183. *
  3184. * Отправка вопроса и ответа в базу данных
  3185. */
  3186. function sendAnswerInfo(answerInfo) {
  3187. fetch('https://zingery.ru/heroes/setAnswer.php', {
  3188. method: 'POST',
  3189. body: JSON.stringify(answerInfo)
  3190. }).then(
  3191. response => response.json()
  3192. ).then(
  3193. data => {
  3194. if (data.result) {
  3195. console.log(I18N('SENT_QUESTION'));
  3196. }
  3197. }
  3198. )
  3199. }
  3200.  
  3201. /**
  3202. * Returns the battle type by preset type
  3203. *
  3204. * Возвращает тип боя по типу пресета
  3205. */
  3206. function getBattleType(strBattleType) {
  3207. if (strBattleType.includes("invasion")) {
  3208. return "get_invasion";
  3209. }
  3210. if (strBattleType.includes("boss")) {
  3211. return "get_boss";
  3212. }
  3213. switch (strBattleType) {
  3214. case "invasion":
  3215. return "get_invasion";
  3216. case "titan_pvp_manual":
  3217. return "get_titanPvpManual";
  3218. case "titan_pvp":
  3219. return "get_titanPvp";
  3220. case "titan_clan_pvp":
  3221. case "clan_pvp_titan":
  3222. case "clan_global_pvp_titan":
  3223. case "brawl_titan":
  3224. case "challenge_titan":
  3225. return "get_titanClanPvp";
  3226. case "clan_raid": // Asgard Boss // Босс асгарда
  3227. case "adventure": // Adventures // Приключения
  3228. case "clan_global_pvp":
  3229. case "clan_pvp":
  3230. return "get_clanPvp";
  3231. case "dungeon_titan":
  3232. case "titan_tower":
  3233. return "get_titan";
  3234. case "tower":
  3235. case "clan_dungeon":
  3236. return "get_tower";
  3237. case "pve":
  3238. return "get_pve";
  3239. case "pvp_manual":
  3240. return "get_pvpManual";
  3241. case "grand":
  3242. case "arena":
  3243. case "pvp":
  3244. case "challenge":
  3245. return "get_pvp";
  3246. case "core":
  3247. return "get_core";
  3248. case "boss_10":
  3249. case "boss_11":
  3250. case "boss_12":
  3251. return "get_boss";
  3252. default:
  3253. return "get_clanPvp";
  3254. }
  3255. }
  3256. /**
  3257. * Returns the class name of the passed object
  3258. *
  3259. * Возвращает название класса переданного объекта
  3260. */
  3261. function getClass(obj) {
  3262. return {}.toString.call(obj).slice(8, -1);
  3263. }
  3264. /**
  3265. * Calculates the request signature
  3266. *
  3267. * Расчитывает сигнатуру запроса
  3268. */
  3269. this.getSignature = function(headers, data) {
  3270. const sign = {
  3271. signature: '',
  3272. length: 0,
  3273. add: function (text) {
  3274. this.signature += text;
  3275. if (this.length < this.signature.length) {
  3276. this.length = 3 * (this.signature.length + 1) >> 1;
  3277. }
  3278. },
  3279. }
  3280. sign.add(headers["X-Request-Id"]);
  3281. sign.add(':');
  3282. sign.add(headers["X-Auth-Token"]);
  3283. sign.add(':');
  3284. sign.add(headers["X-Auth-Session-Id"]);
  3285. sign.add(':');
  3286. sign.add(data);
  3287. sign.add(':');
  3288. sign.add('LIBRARY-VERSION=1');
  3289. sign.add('UNIQUE-SESSION-ID=' + headers["X-Env-Unique-Session-Id"]);
  3290.  
  3291. return md5(sign.signature);
  3292. }
  3293. /**
  3294. * Creates an interface
  3295. *
  3296. * Создает интерфейс
  3297. */
  3298. function createInterface() {
  3299. scriptMenu.init({
  3300. showMenu: true
  3301. });
  3302. scriptMenu.addHeader(GM_info.script.name, justInfo);
  3303. scriptMenu.addHeader('v' + GM_info.script.version);
  3304. }
  3305.  
  3306. function addControls() {
  3307. const checkboxDetails = scriptMenu.addDetails(I18N('SETTINGS'));
  3308. for (let name in checkboxes) {
  3309. if (checkboxes[name].hide) {
  3310. continue;
  3311. }
  3312. checkboxes[name].cbox = scriptMenu.addCheckbox(checkboxes[name].label, checkboxes[name].title, checkboxDetails);
  3313. /**
  3314. * Getting the state of checkboxes from storage
  3315. * Получаем состояние чекбоксов из storage
  3316. */
  3317. let val = storage.get(name, null);
  3318. if (val != null) {
  3319. checkboxes[name].cbox.checked = val;
  3320. } else {
  3321. storage.set(name, checkboxes[name].default);
  3322. checkboxes[name].cbox.checked = checkboxes[name].default;
  3323. }
  3324. /**
  3325. * Tracing the change event of the checkbox for writing to storage
  3326. * Отсеживание события изменения чекбокса для записи в storage
  3327. */
  3328. checkboxes[name].cbox.dataset['name'] = name;
  3329. checkboxes[name].cbox.addEventListener('change', async function (event) {
  3330. const nameCheckbox = this.dataset['name'];
  3331. /*
  3332. if (this.checked && nameCheckbox == 'cancelBattle') {
  3333. this.checked = false;
  3334. if (await popup.confirm(I18N('MSG_BAN_ATTENTION'), [
  3335. { msg: I18N('BTN_NO_I_AM_AGAINST'), result: true },
  3336. { msg: I18N('BTN_YES_I_AGREE'), result: false },
  3337. ])) {
  3338. return;
  3339. }
  3340. this.checked = true;
  3341. }
  3342. */
  3343. storage.set(nameCheckbox, this.checked);
  3344. })
  3345. }
  3346.  
  3347. const inputDetails = scriptMenu.addDetails(I18N('VALUES'));
  3348. for (let name in inputs) {
  3349. inputs[name].input = scriptMenu.addInputText(inputs[name].title, false, inputDetails);
  3350. /**
  3351. * Get inputText state from storage
  3352. * Получаем состояние inputText из storage
  3353. */
  3354. let val = storage.get(name, null);
  3355. if (val != null) {
  3356. inputs[name].input.value = val;
  3357. } else {
  3358. storage.set(name, inputs[name].default);
  3359. inputs[name].input.value = inputs[name].default;
  3360. }
  3361. /**
  3362. * Tracing a field change event for a record in storage
  3363. * Отсеживание события изменения поля для записи в storage
  3364. */
  3365. inputs[name].input.dataset['name'] = name;
  3366. inputs[name].input.addEventListener('input', function () {
  3367. const inputName = this.dataset['name'];
  3368. let value = +this.value;
  3369. if (!value || Number.isNaN(value)) {
  3370. value = storage.get(inputName, inputs[inputName].default);
  3371. inputs[name].input.value = value;
  3372. }
  3373. storage.set(inputName, value);
  3374. })
  3375. }
  3376. const inputDetails2 = scriptMenu.addDetails(I18N('SAVING'));
  3377. for (let name in inputs2) {
  3378. inputs2[name].input = scriptMenu.addInputText(inputs2[name].title, false, inputDetails2);
  3379. /**
  3380. * Get inputText state from storage
  3381. * Получаем состояние inputText из storage
  3382. */
  3383. let val = storage.get(name, null);
  3384. if (val != null) {
  3385. inputs2[name].input.value = val;
  3386. } else {
  3387. storage.set(name, inputs2[name].default);
  3388. inputs2[name].input.value = inputs2[name].default;
  3389. }
  3390. /**
  3391. * Tracing a field change event for a record in storage
  3392. * Отсеживание события изменения поля для записи в storage
  3393. */
  3394. inputs2[name].input.dataset['name'] = name;
  3395. inputs2[name].input.addEventListener('input', function () {
  3396. const inputName = this.dataset['name'];
  3397. let value = +this.value;
  3398. if (!value || Number.isNaN(value)) {
  3399. value = storage.get(inputName, inputs2[inputName].default);
  3400. inputs2[name].input.value = value;
  3401. }
  3402. storage.set(inputName, value);
  3403. })
  3404. }
  3405. /* const inputDetails3 = scriptMenu.addDetails(I18N('USER_ID'));
  3406. for (let name in inputs3) {
  3407. inputs3[name].input = scriptMenu.addInputText(inputs3[name].title, false, inputDetails3);
  3408. /**
  3409. * Get inputText state from storage
  3410. * Получаем состояние inputText из storage
  3411. *
  3412. let val = storage.get(name, null);
  3413. if (val != null) {
  3414. inputs3[name].input.value = val;
  3415. } else {
  3416. storage.set(name, inputs3[name].default);
  3417. inputs3[name].input.value = inputs3[name].default;
  3418. }
  3419. /**
  3420. * Tracing a field change event for a record in storage
  3421. * Отсеживание события изменения поля для записи в storage
  3422. *
  3423. inputs3[name].input.dataset['name'] = name;
  3424. inputs3[name].input.addEventListener('input', function () {
  3425. const inputName = this.dataset['name'];
  3426. let value = +this.value;
  3427. if (!value || Number.isNaN(value)) {
  3428. value = storage.get(inputName, inputs3[inputName].default);
  3429. inputs3[name].input.value = value;
  3430. }
  3431. storage.set(inputName, value);
  3432. })
  3433. }*/
  3434. }
  3435.  
  3436. /**
  3437. * Sending a request
  3438. *
  3439. * Отправка запроса
  3440. */
  3441. function send(json, callback, pr) {
  3442. if (typeof json == 'string') {
  3443. json = JSON.parse(json);
  3444. }
  3445. for (const call of json.calls) {
  3446. if (!call?.context?.actionTs) {
  3447. call.context = {
  3448. actionTs: Math.floor(performance.now())
  3449. }
  3450. }
  3451. }
  3452. json = JSON.stringify(json);
  3453. /**
  3454. * We get the headlines of the previous intercepted request
  3455. * Получаем заголовки предыдущего перехваченого запроса
  3456. */
  3457. let headers = lastHeaders;
  3458. /**
  3459. * We increase the header of the query Certifier by 1
  3460. * Увеличиваем заголовок идетификатора запроса на 1
  3461. */
  3462. headers["X-Request-Id"]++;
  3463. /**
  3464. * We calculate the title with the signature
  3465. * Расчитываем заголовок с сигнатурой
  3466. */
  3467. headers["X-Auth-Signature"] = getSignature(headers, json);
  3468. /**
  3469. * Create a new ajax request
  3470. * Создаем новый AJAX запрос
  3471. */
  3472. let xhr = new XMLHttpRequest;
  3473. /**
  3474. * Indicate the previously saved URL for API queries
  3475. * Указываем ранее сохраненный URL для API запросов
  3476. */
  3477. xhr.open('POST', apiUrl, true);
  3478. /**
  3479. * Add the function to the event change event
  3480. * Добавляем функцию к событию смены статуса запроса
  3481. */
  3482. xhr.onreadystatechange = function() {
  3483. /**
  3484. * If the result of the request is obtained, we call the flask function
  3485. * Если результат запроса получен вызываем колбек функцию
  3486. */
  3487. if(xhr.readyState == 4) {
  3488. callback(xhr.response, pr);
  3489. }
  3490. };
  3491. /**
  3492. * Indicate the type of request
  3493. * Указываем тип запроса
  3494. */
  3495. xhr.responseType = 'json';
  3496. /**
  3497. * We set the request headers
  3498. * Задаем заголовки запроса
  3499. */
  3500. for(let nameHeader in headers) {
  3501. let head = headers[nameHeader];
  3502. xhr.setRequestHeader(nameHeader, head);
  3503. }
  3504. /**
  3505. * Sending a request
  3506. * Отправляем запрос
  3507. */
  3508. xhr.send(json);
  3509. }
  3510.  
  3511. let hideTimeoutProgress = 0;
  3512. /**
  3513. * Hide progress
  3514. *
  3515. * Скрыть прогресс
  3516. */
  3517. function hideProgress(timeout) {
  3518. timeout = timeout || 0;
  3519. clearTimeout(hideTimeoutProgress);
  3520. hideTimeoutProgress = setTimeout(function () {
  3521. scriptMenu.setStatus('');
  3522. }, timeout);
  3523. }
  3524. /**
  3525. * Progress display
  3526. *
  3527. * Отображение прогресса
  3528. */
  3529. function setProgress(text, hide, onclick) {
  3530. scriptMenu.setStatus(text, onclick);
  3531. hide = hide || false;
  3532. if (hide) {
  3533. hideProgress(3000);
  3534. }
  3535. }
  3536.  
  3537. /**
  3538. * Returns the timer value depending on the subscription
  3539. *
  3540. * Возвращает значение таймера в зависимости от подписки
  3541. */
  3542. function getTimer(time, div) {
  3543. let speedDiv = 5;
  3544. if (subEndTime < Date.now()) {
  3545. speedDiv = div || 1.5;
  3546. }
  3547. return Math.max(Math.ceil(time / speedDiv + 1.5), 4);
  3548. }
  3549.  
  3550. /**
  3551. * Calculates HASH MD5 from string
  3552. *
  3553. * Расчитывает HASH MD5 из строки
  3554. *
  3555. * [js-md5]{@link https://github.com/emn178/js-md5}
  3556. *
  3557. * @namespace md5
  3558. * @version 0.7.3
  3559. * @author Chen, Yi-Cyuan [emn178@gmail.com]
  3560. * @copyright Chen, Yi-Cyuan 2014-2017
  3561. * @license MIT
  3562. */
  3563. !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 _}))}();
  3564.  
  3565. /**
  3566. * Script for beautiful dialog boxes
  3567. *
  3568. * Скрипт для красивых диалоговых окошек
  3569. */
  3570. const popup = new (function () {
  3571. this.popUp,
  3572. this.downer,
  3573. this.middle,
  3574. this.msgText,
  3575. this.buttons = [];
  3576. this.checkboxes = [];
  3577. this.dialogPromice = null;
  3578.  
  3579. function init() {
  3580. addStyle();
  3581. addBlocks();
  3582. addEventListeners();
  3583. }
  3584.  
  3585. const addEventListeners = () => {
  3586. document.addEventListener('keyup', (e) => {
  3587. if (e.key == 'Escape') {
  3588. if (this.dialogPromice) {
  3589. const { func, result } = this.dialogPromice;
  3590. this.dialogPromice = null;
  3591. popup.hide();
  3592. func(result);
  3593. }
  3594. }
  3595. });
  3596. }
  3597.  
  3598. const addStyle = () => {
  3599. let style = document.createElement('style');
  3600. style.innerText = `
  3601. .PopUp_ {
  3602. position: absolute;
  3603. min-width: 300px;
  3604. max-width: 500px;
  3605. max-height: 600px;
  3606. background-color: #190e08e6;
  3607. z-index: 10001;
  3608. top: 169px;
  3609. left: 345px;
  3610. border: 3px #ce9767 solid;
  3611. border-radius: 10px;
  3612. display: flex;
  3613. flex-direction: column;
  3614. justify-content: space-around;
  3615. padding: 15px 9px;
  3616. box-sizing: border-box;
  3617. }
  3618.  
  3619. .PopUp_back {
  3620. position: absolute;
  3621. background-color: #00000066;
  3622. width: 100%;
  3623. height: 100%;
  3624. z-index: 10000;
  3625. top: 0;
  3626. left: 0;
  3627. }
  3628.  
  3629. .PopUp_close {
  3630. width: 40px;
  3631. height: 40px;
  3632. position: absolute;
  3633. right: -18px;
  3634. top: -18px;
  3635. border: 3px solid #c18550;
  3636. border-radius: 20px;
  3637. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  3638. background-position-y: 3px;
  3639. box-shadow: -1px 1px 3px black;
  3640. cursor: pointer;
  3641. box-sizing: border-box;
  3642. }
  3643.  
  3644. .PopUp_close:hover {
  3645. filter: brightness(1.2);
  3646. }
  3647.  
  3648. .PopUp_crossClose {
  3649. width: 100%;
  3650. height: 100%;
  3651. background-size: 65%;
  3652. background-position: center;
  3653. background-repeat: no-repeat;
  3654. 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")
  3655. }
  3656.  
  3657. .PopUp_blocks {
  3658. width: 100%;
  3659. height: 50%;
  3660. display: flex;
  3661. justify-content: space-evenly;
  3662. align-items: center;
  3663. flex-wrap: wrap;
  3664. justify-content: center;
  3665. }
  3666.  
  3667. .PopUp_blocks:last-child {
  3668. margin-top: 25px;
  3669. }
  3670.  
  3671. .PopUp_buttons {
  3672. display: flex;
  3673. margin: 7px 10px;
  3674. flex-direction: column;
  3675. }
  3676.  
  3677. .PopUp_button {
  3678. background-color: #52A81C;
  3679. border-radius: 5px;
  3680. box-shadow: inset 0px -4px 10px, inset 0px 3px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  3681. cursor: pointer;
  3682. padding: 4px 12px 6px;
  3683. }
  3684.  
  3685. .PopUp_input {
  3686. text-align: center;
  3687. font-size: 16px;
  3688. height: 27px;
  3689. border: 1px solid #cf9250;
  3690. border-radius: 9px 9px 0px 0px;
  3691. background: transparent;
  3692. color: #fce1ac;
  3693. padding: 1px 10px;
  3694. box-sizing: border-box;
  3695. box-shadow: 0px 0px 4px, 0px 0px 0px 3px #ce9767;
  3696. }
  3697.  
  3698. .PopUp_checkboxes {
  3699. display: flex;
  3700. flex-direction: column;
  3701. margin: 15px 15px -5px 15px;
  3702. align-items: flex-start;
  3703. }
  3704.  
  3705. .PopUp_ContCheckbox {
  3706. margin: 2px 0px;
  3707. }
  3708.  
  3709. .PopUp_checkbox {
  3710. position: absolute;
  3711. z-index: -1;
  3712. opacity: 0;
  3713. }
  3714. .PopUp_checkbox+label {
  3715. display: inline-flex;
  3716. align-items: center;
  3717. user-select: none;
  3718.  
  3719. font-size: 15px;
  3720. font-family: sans-serif;
  3721. font-weight: 600;
  3722. font-stretch: condensed;
  3723. letter-spacing: 1px;
  3724. color: #fce1ac;
  3725. text-shadow: 0px 0px 1px;
  3726. }
  3727. .PopUp_checkbox+label::before {
  3728. content: '';
  3729. display: inline-block;
  3730. width: 20px;
  3731. height: 20px;
  3732. border: 1px solid #cf9250;
  3733. border-radius: 7px;
  3734. margin-right: 7px;
  3735. }
  3736. .PopUp_checkbox:checked+label::before {
  3737. 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");
  3738. }
  3739.  
  3740. .PopUp_input::placeholder {
  3741. color: #fce1ac75;
  3742. }
  3743.  
  3744. .PopUp_input:focus {
  3745. outline: 0;
  3746. }
  3747.  
  3748. .PopUp_input + .PopUp_button {
  3749. border-radius: 0px 0px 5px 5px;
  3750. padding: 2px 18px 5px;
  3751. }
  3752.  
  3753. .PopUp_button:hover {
  3754. filter: brightness(1.2);
  3755. }
  3756.  
  3757. .PopUp_button:active {
  3758. box-shadow: inset 0px 5px 10px, inset 0px 1px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  3759. }
  3760.  
  3761. .PopUp_text {
  3762. font-size: 22px;
  3763. font-family: sans-serif;
  3764. font-weight: 600;
  3765. font-stretch: condensed;
  3766. white-space: pre-wrap;
  3767. letter-spacing: 1px;
  3768. text-align: center;
  3769. }
  3770.  
  3771. .PopUp_buttonText {
  3772. color: #E4FF4C;
  3773. text-shadow: 0px 1px 2px black;
  3774. }
  3775.  
  3776. .PopUp_msgText {
  3777. color: #FDE5B6;
  3778. text-shadow: 0px 0px 2px;
  3779. }
  3780.  
  3781. .PopUp_hideBlock {
  3782. display: none;
  3783. }
  3784. `;
  3785. document.head.appendChild(style);
  3786. }
  3787.  
  3788. const addBlocks = () => {
  3789. this.back = document.createElement('div');
  3790. this.back.classList.add('PopUp_back');
  3791. this.back.classList.add('PopUp_hideBlock');
  3792. document.body.append(this.back);
  3793.  
  3794. this.popUp = document.createElement('div');
  3795. this.popUp.classList.add('PopUp_');
  3796. this.back.append(this.popUp);
  3797.  
  3798. let upper = document.createElement('div')
  3799. upper.classList.add('PopUp_blocks');
  3800. this.popUp.append(upper);
  3801.  
  3802. this.middle = document.createElement('div')
  3803. this.middle.classList.add('PopUp_blocks');
  3804. this.middle.classList.add('PopUp_checkboxes');
  3805. this.popUp.append(this.middle);
  3806.  
  3807. this.downer = document.createElement('div')
  3808. this.downer.classList.add('PopUp_blocks');
  3809. this.popUp.append(this.downer);
  3810.  
  3811. this.msgText = document.createElement('div');
  3812. this.msgText.classList.add('PopUp_text', 'PopUp_msgText');
  3813. upper.append(this.msgText);
  3814. }
  3815.  
  3816. this.showBack = function () {
  3817. this.back.classList.remove('PopUp_hideBlock');
  3818. }
  3819.  
  3820. this.hideBack = function () {
  3821. this.back.classList.add('PopUp_hideBlock');
  3822. }
  3823.  
  3824. this.show = function () {
  3825. if (this.checkboxes.length) {
  3826. this.middle.classList.remove('PopUp_hideBlock');
  3827. }
  3828. this.showBack();
  3829. this.popUp.classList.remove('PopUp_hideBlock');
  3830. this.popUp.style.left = (window.innerWidth - this.popUp.offsetWidth) / 2 + 'px';
  3831. this.popUp.style.top = (window.innerHeight - this.popUp.offsetHeight) / 3 + 'px';
  3832. }
  3833.  
  3834. this.hide = function () {
  3835. this.hideBack();
  3836. this.popUp.classList.add('PopUp_hideBlock');
  3837. }
  3838.  
  3839. this.addAnyButton = (option) => {
  3840. const contButton = document.createElement('div');
  3841. contButton.classList.add('PopUp_buttons');
  3842. this.downer.append(contButton);
  3843.  
  3844. let inputField = {
  3845. value: option.result || option.default
  3846. }
  3847. if (option.isInput) {
  3848. inputField = document.createElement('input');
  3849. inputField.type = 'text';
  3850. if (option.placeholder) {
  3851. inputField.placeholder = option.placeholder;
  3852. }
  3853. if (option.default) {
  3854. inputField.value = option.default;
  3855. }
  3856. inputField.classList.add('PopUp_input');
  3857. contButton.append(inputField);
  3858. }
  3859.  
  3860. const button = document.createElement('div');
  3861. button.classList.add('PopUp_button');
  3862. button.title = option.title || '';
  3863. contButton.append(button);
  3864.  
  3865. const buttonText = document.createElement('div');
  3866. buttonText.classList.add('PopUp_text', 'PopUp_buttonText');
  3867. buttonText.innerText = option.msg;
  3868. button.append(buttonText);
  3869.  
  3870. return { button, contButton, inputField };
  3871. }
  3872.  
  3873. this.addCloseButton = () => {
  3874. let button = document.createElement('div')
  3875. button.classList.add('PopUp_close');
  3876. this.popUp.append(button);
  3877.  
  3878. let crossClose = document.createElement('div')
  3879. crossClose.classList.add('PopUp_crossClose');
  3880. button.append(crossClose);
  3881.  
  3882. return { button, contButton: button };
  3883. }
  3884.  
  3885. this.addButton = (option, buttonClick) => {
  3886.  
  3887. const { button, contButton, inputField } = option.isClose ? this.addCloseButton() : this.addAnyButton(option);
  3888. if (option.isClose) {
  3889. this.dialogPromice = {func: buttonClick, result: option.result};
  3890. }
  3891. button.addEventListener('click', () => {
  3892. let result = '';
  3893. if (option.isInput) {
  3894. result = inputField.value;
  3895. }
  3896. if (option.isClose || option.isCancel) {
  3897. this.dialogPromice = null;
  3898. }
  3899. buttonClick(result);
  3900. });
  3901.  
  3902. this.buttons.push(contButton);
  3903. }
  3904.  
  3905. this.clearButtons = () => {
  3906. while (this.buttons.length) {
  3907. this.buttons.pop().remove();
  3908. }
  3909. }
  3910.  
  3911. this.addCheckBox = (checkBox) => {
  3912. const contCheckbox = document.createElement('div');
  3913. contCheckbox.classList.add('PopUp_ContCheckbox');
  3914. this.middle.append(contCheckbox);
  3915.  
  3916. const checkbox = document.createElement('input');
  3917. checkbox.type = 'checkbox';
  3918. checkbox.id = 'PopUpCheckbox' + this.checkboxes.length;
  3919. checkbox.dataset.name = checkBox.name;
  3920. checkbox.checked = checkBox.checked;
  3921. checkbox.label = checkBox.label;
  3922. checkbox.title = checkBox.title || '';
  3923. checkbox.classList.add('PopUp_checkbox');
  3924. contCheckbox.appendChild(checkbox)
  3925.  
  3926. const checkboxLabel = document.createElement('label');
  3927. checkboxLabel.innerText = checkBox.label;
  3928. checkboxLabel.title = checkBox.title || '';
  3929. checkboxLabel.setAttribute('for', checkbox.id);
  3930. contCheckbox.appendChild(checkboxLabel);
  3931.  
  3932. this.checkboxes.push(checkbox);
  3933. }
  3934.  
  3935. this.clearCheckBox = () => {
  3936. this.middle.classList.add('PopUp_hideBlock');
  3937. while (this.checkboxes.length) {
  3938. this.checkboxes.pop().parentNode.remove();
  3939. }
  3940. }
  3941.  
  3942. this.setMsgText = (text) => {
  3943. this.msgText.innerHTML = text;
  3944. }
  3945.  
  3946. this.getCheckBoxes = () => {
  3947. const checkBoxes = [];
  3948.  
  3949. for (const checkBox of this.checkboxes) {
  3950. checkBoxes.push({
  3951. name: checkBox.dataset.name,
  3952. label: checkBox.label,
  3953. checked: checkBox.checked
  3954. });
  3955. }
  3956.  
  3957. return checkBoxes;
  3958. }
  3959.  
  3960. this.confirm = async (msg, buttOpt, checkBoxes = []) => {
  3961. this.clearButtons();
  3962. this.clearCheckBox();
  3963. return new Promise((complete, failed) => {
  3964. this.setMsgText(msg);
  3965. if (!buttOpt) {
  3966. buttOpt = [{ msg: 'Ok', result: true, isInput: false }];
  3967. }
  3968. for (const checkBox of checkBoxes) {
  3969. this.addCheckBox(checkBox);
  3970. }
  3971. for (let butt of buttOpt) {
  3972. this.addButton(butt, (result) => {
  3973. result = result || butt.result;
  3974. complete(result);
  3975. popup.hide();
  3976. });
  3977. if (butt.isCancel) {
  3978. this.dialogPromice = {func: complete, result: butt.result};
  3979. }
  3980. }
  3981. this.show();
  3982. });
  3983. }
  3984.  
  3985. document.addEventListener('DOMContentLoaded', init);
  3986. });
  3987.  
  3988. /**
  3989. * Script control panel
  3990. *
  3991. * Панель управления скриптом
  3992. */
  3993. const scriptMenu = new (function () {
  3994.  
  3995. this.mainMenu,
  3996. this.buttons = [],
  3997. this.checkboxes = [];
  3998. this.option = {
  3999. showMenu: false,
  4000. showDetails: {}
  4001. };
  4002.  
  4003. this.init = function (option = {}) {
  4004. this.option = Object.assign(this.option, option);
  4005. this.option.showDetails = this.loadShowDetails();
  4006. addStyle();
  4007. addBlocks();
  4008. }
  4009.  
  4010. const addStyle = () => {
  4011. style = document.createElement('style');
  4012. style.innerText = `
  4013. .scriptMenu_status {
  4014. position: absolute;
  4015. z-index: 10001;
  4016. white-space: pre-wrap; //тест для выравнивания кнопок
  4017. /* max-height: 30px; */
  4018. top: -1px;
  4019. left: 30%;
  4020. cursor: pointer;
  4021. border-radius: 0px 0px 10px 10px;
  4022. background: #190e08e6;
  4023. border: 1px #ce9767 solid;
  4024. font-size: 18px;
  4025. font-family: sans-serif;
  4026. font-weight: 600;
  4027. font-stretch: condensed;
  4028. letter-spacing: 1px;
  4029. color: #fce1ac;
  4030. text-shadow: 0px 0px 1px;
  4031. transition: 0.5s;
  4032. padding: 2px 10px 3px;
  4033. }
  4034. .scriptMenu_statusHide {
  4035. top: -35px;
  4036. height: 30px;
  4037. overflow: hidden;
  4038. }
  4039. .scriptMenu_label {
  4040. position: absolute;
  4041. top: 30%;
  4042. left: -4px;
  4043. z-index: 9999;
  4044. cursor: pointer;
  4045. width: 30px;
  4046. height: 30px;
  4047. background: radial-gradient(circle, #47a41b 0%, #1a2f04 100%);
  4048. border: 1px solid #1a2f04;
  4049. border-radius: 5px;
  4050. box-shadow:
  4051. inset 0px 2px 4px #83ce26,
  4052. inset 0px -4px 6px #1a2f04,
  4053. 0px 0px 2px black,
  4054. 0px 0px 0px 2px #ce9767;
  4055. }
  4056. .scriptMenu_label:hover {
  4057. filter: brightness(1.2);
  4058. }
  4059. .scriptMenu_arrowLabel {
  4060. width: 100%;
  4061. height: 100%;
  4062. background-size: 75%;
  4063. background-position: center;
  4064. background-repeat: no-repeat;
  4065. 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");
  4066. box-shadow: 0px 1px 2px #000;
  4067. border-radius: 5px;
  4068. filter: drop-shadow(0px 1px 2px #000D);
  4069. }
  4070. .scriptMenu_main {
  4071. position: absolute;
  4072. max-width: 285px;
  4073. z-index: 9999;
  4074. top: 50%;
  4075. transform: translateY(-40%);
  4076. background: #190e08e6;
  4077. border: 1px #ce9767 solid;
  4078. border-radius: 0px 10px 10px 0px;
  4079. border-left: none;
  4080. padding: 5px 10px 5px 5px;
  4081. box-sizing: border-box;
  4082. font-size: 15px;
  4083. font-family: sans-serif;
  4084. font-weight: 600;
  4085. font-stretch: condensed;
  4086. letter-spacing: 1px;
  4087. color: #fce1ac;
  4088. text-shadow: 0px 0px 1px;
  4089. transition: 1s;
  4090. display: flex;
  4091. flex-direction: column;
  4092. flex-wrap: nowrap;
  4093. }
  4094. .scriptMenu_showMenu {
  4095. display: none;
  4096. }
  4097. .scriptMenu_showMenu:checked~.scriptMenu_main {
  4098. left: 0px;
  4099. }
  4100. .scriptMenu_showMenu:not(:checked)~.scriptMenu_main {
  4101. left: -300px;
  4102. }
  4103. .scriptMenu_divInput {
  4104. margin: 2px;
  4105. }
  4106. .scriptMenu_divInputText {
  4107. margin: 2px;
  4108. align-self: center;
  4109. display: flex;
  4110. }
  4111. .scriptMenu_checkbox {
  4112. position: absolute;
  4113. z-index: -1;
  4114. opacity: 0;
  4115. }
  4116. .scriptMenu_checkbox+label {
  4117. display: inline-flex;
  4118. align-items: center;
  4119. user-select: none;
  4120. }
  4121. .scriptMenu_checkbox+label::before {
  4122. content: '';
  4123. display: inline-block;
  4124. width: 20px;
  4125. height: 20px;
  4126. border: 1px solid #cf9250;
  4127. border-radius: 7px;
  4128. margin-right: 7px;
  4129. }
  4130. .scriptMenu_checkbox:checked+label::before {
  4131. 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");
  4132. }
  4133. .scriptMenu_close {
  4134. width: 40px;
  4135. height: 40px;
  4136. position: absolute;
  4137. right: -18px;
  4138. top: -18px;
  4139. border: 3px solid #c18550;
  4140. border-radius: 20px;
  4141. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  4142. background-position-y: 3px;
  4143. box-shadow: -1px 1px 3px black;
  4144. cursor: pointer;
  4145. box-sizing: border-box;
  4146. }
  4147. .scriptMenu_close:hover {
  4148. filter: brightness(1.2);
  4149. }
  4150. .scriptMenu_crossClose {
  4151. width: 100%;
  4152. height: 100%;
  4153. background-size: 65%;
  4154. background-position: center;
  4155. background-repeat: no-repeat;
  4156. 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")
  4157. }
  4158. .scriptMenu_button {
  4159. user-select: none;
  4160. border-radius: 5px;
  4161. cursor: pointer;
  4162. padding: 5px 14px 8px;
  4163. margin: 4px;
  4164. background: radial-gradient(circle, rgba(165,120,56,1) 80%, rgba(0,0,0,1) 110%);
  4165. box-shadow: inset 0px -4px 6px #442901, inset 0px 1px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  4166. }
  4167. .scriptMenu_button:hover {
  4168. filter: brightness(1.2);
  4169. }
  4170. .scriptMenu_button:active {
  4171. box-shadow: inset 0px 4px 6px #442901, inset 0px 4px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 2px #ce9767;
  4172. }
  4173. .scriptMenu_buttonText {
  4174. color: #fce5b7;
  4175. text-shadow: 0px 1px 2px black;
  4176. text-align: center;
  4177. }
  4178. .scriptMenu_header {
  4179. text-align: center;
  4180. align-self: center;
  4181. font-size: 15px;
  4182. margin: 0px 15px;
  4183. }
  4184. .scriptMenu_header a {
  4185. color: #fce5b7;
  4186. text-decoration: none;
  4187. }
  4188. .scriptMenu_InputText {
  4189. text-align: center;
  4190. width: 130px;
  4191. height: 24px;
  4192. border: 1px solid #cf9250;
  4193. border-radius: 9px;
  4194. background: transparent;
  4195. color: #fce1ac;
  4196. padding: 0px 10px;
  4197. box-sizing: border-box;
  4198. }
  4199. .scriptMenu_InputText:focus {
  4200. filter: brightness(1.2);
  4201. outline: 0;
  4202. }
  4203. .scriptMenu_InputText::placeholder {
  4204. color: #fce1ac75;
  4205. }
  4206. .scriptMenu_Summary {
  4207. cursor: pointer;
  4208. margin-left: 7px;
  4209. }
  4210. .scriptMenu_Details {
  4211. align-self: center;
  4212. }
  4213. `;
  4214. document.head.appendChild(style);
  4215. }
  4216.  
  4217. const addBlocks = () => {
  4218. const main = document.createElement('div');
  4219. document.body.appendChild(main);
  4220.  
  4221. this.status = document.createElement('div');
  4222. this.status.classList.add('scriptMenu_status');
  4223. this.setStatus('');
  4224. main.appendChild(this.status);
  4225.  
  4226. const label = document.createElement('label');
  4227. label.classList.add('scriptMenu_label');
  4228. label.setAttribute('for', 'checkbox_showMenu');
  4229. main.appendChild(label);
  4230.  
  4231. const arrowLabel = document.createElement('div');
  4232. arrowLabel.classList.add('scriptMenu_arrowLabel');
  4233. label.appendChild(arrowLabel);
  4234.  
  4235. const checkbox = document.createElement('input');
  4236. checkbox.type = 'checkbox';
  4237. checkbox.id = 'checkbox_showMenu';
  4238. checkbox.checked = this.option.showMenu;
  4239. checkbox.classList.add('scriptMenu_showMenu');
  4240. main.appendChild(checkbox);
  4241.  
  4242. this.mainMenu = document.createElement('div');
  4243. this.mainMenu.classList.add('scriptMenu_main');
  4244. main.appendChild(this.mainMenu);
  4245.  
  4246. const closeButton = document.createElement('label');
  4247. closeButton.classList.add('scriptMenu_close');
  4248. closeButton.setAttribute('for', 'checkbox_showMenu');
  4249. this.mainMenu.appendChild(closeButton);
  4250.  
  4251. const crossClose = document.createElement('div');
  4252. crossClose.classList.add('scriptMenu_crossClose');
  4253. closeButton.appendChild(crossClose);
  4254. }
  4255.  
  4256. this.setStatus = (text, onclick) => {
  4257. if (!text) {
  4258. this.status.classList.add('scriptMenu_statusHide');
  4259. } else {
  4260. this.status.classList.remove('scriptMenu_statusHide');
  4261. this.status.innerHTML = text;
  4262. }
  4263.  
  4264. if (typeof onclick == 'function') {
  4265. this.status.addEventListener("click", onclick, {
  4266. once: true
  4267. });
  4268. }
  4269. }
  4270.  
  4271. /**
  4272. * Adding a text element
  4273. *
  4274. * Добавление текстового элемента
  4275. * @param {String} text text // текст
  4276. * @param {Function} func Click function // функция по клику
  4277. * @param {HTMLDivElement} main parent // родитель
  4278. */
  4279. this.addHeader = (text, func, main) => {
  4280. main = main || this.mainMenu;
  4281. const header = document.createElement('div');
  4282. header.classList.add('scriptMenu_header');
  4283. header.innerHTML = text;
  4284. if (typeof func == 'function') {
  4285. header.addEventListener('click', func);
  4286. }
  4287. main.appendChild(header);
  4288. }
  4289.  
  4290. /**
  4291. * Adding a button
  4292. *
  4293. * Добавление кнопки
  4294. * @param {String} text
  4295. * @param {Function} func
  4296. * @param {String} title
  4297. * @param {HTMLDivElement} main parent // родитель
  4298. */
  4299. this.addButton = (text, func, title, main) => {
  4300. main = main || this.mainMenu;
  4301. const button = document.createElement('div');
  4302. button.classList.add('scriptMenu_button');
  4303. button.title = title;
  4304. button.addEventListener('click', func);
  4305. main.appendChild(button);
  4306.  
  4307. const buttonText = document.createElement('div');
  4308. buttonText.classList.add('scriptMenu_buttonText');
  4309. buttonText.innerText = text;
  4310. button.appendChild(buttonText);
  4311. this.buttons.push(button);
  4312.  
  4313. return button;
  4314. }
  4315.  
  4316. /**
  4317. * Adding checkbox
  4318. *
  4319. * Добавление чекбокса
  4320. * @param {String} label
  4321. * @param {String} title
  4322. * @param {HTMLDivElement} main parent // родитель
  4323. * @returns
  4324. */
  4325. this.addCheckbox = (label, title, main) => {
  4326. main = main || this.mainMenu;
  4327. const divCheckbox = document.createElement('div');
  4328. divCheckbox.classList.add('scriptMenu_divInput');
  4329. divCheckbox.title = title;
  4330. main.appendChild(divCheckbox);
  4331.  
  4332. const checkbox = document.createElement('input');
  4333. checkbox.type = 'checkbox';
  4334. checkbox.id = 'scriptMenuCheckbox' + this.checkboxes.length;
  4335. checkbox.classList.add('scriptMenu_checkbox');
  4336. divCheckbox.appendChild(checkbox)
  4337.  
  4338. const checkboxLabel = document.createElement('label');
  4339. checkboxLabel.innerText = label;
  4340. checkboxLabel.setAttribute('for', checkbox.id);
  4341. divCheckbox.appendChild(checkboxLabel);
  4342.  
  4343. this.checkboxes.push(checkbox);
  4344. return checkbox;
  4345. }
  4346.  
  4347. /**
  4348. * Adding input field
  4349. *
  4350. * Добавление поля ввода
  4351. * @param {String} title
  4352. * @param {String} placeholder
  4353. * @param {HTMLDivElement} main parent // родитель
  4354. * @returns
  4355. */
  4356. this.addInputText = (title, placeholder, main) => {
  4357. main = main || this.mainMenu;
  4358. const divInputText = document.createElement('div');
  4359. divInputText.classList.add('scriptMenu_divInputText');
  4360. divInputText.title = title;
  4361. main.appendChild(divInputText);
  4362.  
  4363. const newInputText = document.createElement('input');
  4364. newInputText.type = 'text';
  4365. if (placeholder) {
  4366. newInputText.placeholder = placeholder;
  4367. }
  4368. newInputText.classList.add('scriptMenu_InputText');
  4369. divInputText.appendChild(newInputText)
  4370. return newInputText;
  4371. }
  4372.  
  4373. /**
  4374. * Adds a dropdown block
  4375. *
  4376. * Добавляет раскрывающийся блок
  4377. * @param {String} summary
  4378. * @param {String} name
  4379. * @returns
  4380. */
  4381. this.addDetails = (summaryText, name = null) => {
  4382. const details = document.createElement('details');
  4383. details.classList.add('scriptMenu_Details');
  4384. this.mainMenu.appendChild(details);
  4385.  
  4386. const summary = document.createElement('summary');
  4387. summary.classList.add('scriptMenu_Summary');
  4388. summary.innerText = summaryText;
  4389. if (name) {
  4390. const self = this;
  4391. details.open = this.option.showDetails[name];
  4392. details.dataset.name = name;
  4393. summary.addEventListener('click', () => {
  4394. self.option.showDetails[details.dataset.name] = !details.open;
  4395. self.saveShowDetails(self.option.showDetails);
  4396. });
  4397. }
  4398. details.appendChild(summary);
  4399.  
  4400. return details;
  4401. }
  4402.  
  4403. /**
  4404. * Saving the expanded state of the details blocks
  4405. *
  4406. * Сохранение состояния развенутости блоков details
  4407. * @param {*} value
  4408. */
  4409. this.saveShowDetails = (value) => {
  4410. localStorage.setItem('scriptMenu_showDetails', JSON.stringify(value));
  4411. }
  4412.  
  4413. /**
  4414. * Loading the state of expanded blocks details
  4415. *
  4416. * Загрузка состояния развенутости блоков details
  4417. * @returns
  4418. */
  4419. this.loadShowDetails = () => {
  4420. let showDetails = localStorage.getItem('scriptMenu_showDetails');
  4421.  
  4422. if (!showDetails) {
  4423. return {};
  4424. }
  4425.  
  4426. try {
  4427. showDetails = JSON.parse(showDetails);
  4428. } catch (e) {
  4429. return {};
  4430. }
  4431.  
  4432. return showDetails;
  4433. }
  4434. });
  4435.  
  4436. /**
  4437. * Пример использования
  4438. scriptMenu.init();
  4439. scriptMenu.addHeader('v1.508');
  4440. scriptMenu.addCheckbox('testHack', 'Тестовый взлом игры!');
  4441. scriptMenu.addButton('Запуск!', () => console.log('click'), 'подсказака');
  4442. scriptMenu.addInputText('input подсказака');
  4443. */
  4444. /**
  4445. * Game Library
  4446. *
  4447. * Игровая библиотека
  4448. */
  4449. class Library {
  4450. defaultLibUrl = 'https://heroesru-a.akamaihd.net/vk/v1101/lib/lib.json';
  4451.  
  4452. constructor() {
  4453. if (!Library.instance) {
  4454. Library.instance = this;
  4455. }
  4456.  
  4457. return Library.instance;
  4458. }
  4459.  
  4460. async load() {
  4461. try {
  4462. await this.getUrlLib();
  4463. console.log(this.defaultLibUrl);
  4464. this.data = await fetch(this.defaultLibUrl).then(e => e.json())
  4465. } catch (error) {
  4466. console.error('Не удалось загрузить библиотеку', error)
  4467. }
  4468. }
  4469.  
  4470. async getUrlLib() {
  4471. try {
  4472. const db = new Database('hw_cache', 'cache');
  4473. await db.open();
  4474. const cacheLibFullUrl = await db.get('lib/lib.json.gz', false);
  4475. this.defaultLibUrl = cacheLibFullUrl.fullUrl.split('.gz').shift();
  4476. } catch(e) {}
  4477. }
  4478.  
  4479. getData(id) {
  4480. return this.data[id];
  4481. }
  4482. }
  4483.  
  4484. this.lib = new Library();
  4485. /**
  4486. * Database
  4487. *
  4488. * База данных
  4489. */
  4490. class Database {
  4491. constructor(dbName, storeName) {
  4492. this.dbName = dbName;
  4493. this.storeName = storeName;
  4494. this.db = null;
  4495. }
  4496.  
  4497. async open() {
  4498. return new Promise((resolve, reject) => {
  4499. const request = indexedDB.open(this.dbName);
  4500.  
  4501. request.onerror = () => {
  4502. reject(new Error(`Failed to open database ${this.dbName}`));
  4503. };
  4504.  
  4505. request.onsuccess = () => {
  4506. this.db = request.result;
  4507. resolve();
  4508. };
  4509.  
  4510. request.onupgradeneeded = (event) => {
  4511. const db = event.target.result;
  4512. if (!db.objectStoreNames.contains(this.storeName)) {
  4513. db.createObjectStore(this.storeName);
  4514. }
  4515. };
  4516. });
  4517. }
  4518.  
  4519. async set(key, value) {
  4520. return new Promise((resolve, reject) => {
  4521. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4522. const store = transaction.objectStore(this.storeName);
  4523. const request = store.put(value, key);
  4524.  
  4525. request.onerror = () => {
  4526. reject(new Error(`Failed to save value with key ${key}`));
  4527. };
  4528.  
  4529. request.onsuccess = () => {
  4530. resolve();
  4531. };
  4532. });
  4533. }
  4534.  
  4535. async get(key, def) {
  4536. return new Promise((resolve, reject) => {
  4537. const transaction = this.db.transaction([this.storeName], 'readonly');
  4538. const store = transaction.objectStore(this.storeName);
  4539. const request = store.get(key);
  4540.  
  4541. request.onerror = () => {
  4542. resolve(def);
  4543. };
  4544.  
  4545. request.onsuccess = () => {
  4546. resolve(request.result);
  4547. };
  4548. });
  4549. }
  4550.  
  4551. async delete(key) {
  4552. return new Promise((resolve, reject) => {
  4553. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4554. const store = transaction.objectStore(this.storeName);
  4555. const request = store.delete(key);
  4556.  
  4557. request.onerror = () => {
  4558. reject(new Error(`Failed to delete value with key ${key}`));
  4559. };
  4560.  
  4561. request.onsuccess = () => {
  4562. resolve();
  4563. };
  4564. });
  4565. }
  4566. }
  4567.  
  4568. /**
  4569. * Returns the stored value
  4570. *
  4571. * Возвращает сохраненное значение
  4572. */
  4573. function getSaveVal(saveName, def) {
  4574. const result = storage.get(saveName, def);
  4575. return result;
  4576. }
  4577.  
  4578. /**
  4579. * Stores value
  4580. *
  4581. * Сохраняет значение
  4582. */
  4583. function setSaveVal(saveName, value) {
  4584. storage.set(saveName, value);
  4585. }
  4586.  
  4587. /**
  4588. * Database initialization
  4589. *
  4590. * Инициализация базы данных
  4591. */
  4592. const db = new Database(GM_info.script.name, 'settings');
  4593.  
  4594. /**
  4595. * Data store
  4596. *
  4597. * Хранилище данных
  4598. */
  4599. const storage = {
  4600. userId: 0,
  4601. /**
  4602. * Default values
  4603. *
  4604. * Значения по умолчанию
  4605. */
  4606. values: [
  4607. ...Object.entries(checkboxes).map(e => ({ [e[0]]: e[1].default })),
  4608. ...Object.entries(inputs).map(e => ({ [e[0]]: e[1].default })),
  4609. ...Object.entries(inputs2).map(e => ({ [e[0]]: e[1].default })),
  4610. //...Object.entries(inputs3).map(e => ({ [e[0]]: e[1].default })),
  4611. ].reduce((acc, obj) => ({ ...acc, ...obj }), {}),
  4612. name: GM_info.script.name,
  4613. get: function (key, def) {
  4614. if (key in this.values) {
  4615. return this.values[key];
  4616. }
  4617. return def;
  4618. },
  4619. set: function (key, value) {
  4620. this.values[key] = value;
  4621. db.set(this.userId, this.values).catch(
  4622. e => null
  4623. );
  4624. localStorage[this.name + ':' + key] = value;
  4625. },
  4626. delete: function (key) {
  4627. delete this.values[key];
  4628. db.set(this.userId, this.values);
  4629. delete localStorage[this.name + ':' + key];
  4630. }
  4631. }
  4632.  
  4633. /**
  4634. * Returns all keys from localStorage that start with prefix (for migration)
  4635. *
  4636. * Возвращает все ключи из localStorage которые начинаются с prefix (для миграции)
  4637. */
  4638. function getAllValuesStartingWith(prefix) {
  4639. const values = [];
  4640. for (let i = 0; i < localStorage.length; i++) {
  4641. const key = localStorage.key(i);
  4642. if (key.startsWith(prefix)) {
  4643. const val = localStorage.getItem(key);
  4644. const keyValue = key.split(':')[1];
  4645. values.push({ key: keyValue, val });
  4646. }
  4647. }
  4648. return values;
  4649. }
  4650.  
  4651. /**
  4652. * Opens or migrates to a database
  4653. *
  4654. * Открывает или мигрирует в базу данных
  4655. */
  4656. async function openOrMigrateDatabase(userId) {
  4657. storage.userId = userId;
  4658. try {
  4659. await db.open();
  4660. } catch(e) {
  4661. return;
  4662. }
  4663. let settings = await db.get(userId, false);
  4664.  
  4665. if (settings) {
  4666. storage.values = settings;
  4667. return;
  4668. }
  4669.  
  4670. const values = getAllValuesStartingWith(GM_info.script.name);
  4671. for (const value of values) {
  4672. let val = null;
  4673. try {
  4674. val = JSON.parse(value.val);
  4675. } catch {
  4676. break;
  4677. }
  4678. storage.values[value.key] = val;
  4679. }
  4680. await db.set(userId, storage.values);
  4681. }
  4682.  
  4683. /**
  4684. * Sending expeditions
  4685. *
  4686. * Отправка экспедиций
  4687. */
  4688. function checkExpedition() {
  4689. return new Promise((resolve, reject) => {
  4690. const expedition = new Expedition(resolve, reject);
  4691. expedition.start();
  4692. });
  4693. }
  4694.  
  4695. class Expedition {
  4696. checkExpedInfo = {
  4697. calls: [{
  4698. name: "expeditionGet",
  4699. args: {},
  4700. ident: "expeditionGet"
  4701. }, {
  4702. name: "heroGetAll",
  4703. args: {},
  4704. ident: "heroGetAll"
  4705. }]
  4706. }
  4707.  
  4708. constructor(resolve, reject) {
  4709. this.resolve = resolve;
  4710. this.reject = reject;
  4711. }
  4712.  
  4713. async start() {
  4714. const data = await Send(JSON.stringify(this.checkExpedInfo));
  4715.  
  4716. const expedInfo = data.results[0].result.response;
  4717. const dataHeroes = data.results[1].result.response;
  4718. const dataExped = { useHeroes: [], exped: [] };
  4719. const calls = [];
  4720.  
  4721. /**
  4722. * Adding expeditions to collect
  4723. * Добавляем экспедиции для сбора
  4724. */
  4725. for (var n in expedInfo) {
  4726. const exped = expedInfo[n];
  4727. const dateNow = (Date.now() / 1000);
  4728. if (exped.status == 2 && exped.endTime != 0 && dateNow > exped.endTime) {
  4729. calls.push({
  4730. name: "expeditionFarm",
  4731. args: { expeditionId: exped.id },
  4732. ident: "expeditionFarm_" + exped.id
  4733. });
  4734. } else {
  4735. dataExped.useHeroes = dataExped.useHeroes.concat(exped.heroes);
  4736. }
  4737. if (exped.status == 1) {
  4738. dataExped.exped.push({ id: exped.id, power: exped.power });
  4739. }
  4740. }
  4741. dataExped.exped = dataExped.exped.sort((a, b) => (b.power - a.power));
  4742.  
  4743. /**
  4744. * Putting together a list of heroes
  4745. * Собираем список героев
  4746. */
  4747. const heroesArr = [];
  4748. for (let n in dataHeroes) {
  4749. const hero = dataHeroes[n];
  4750. if (hero.xp > 0 && !dataExped.useHeroes.includes(hero.id)) {
  4751. let heroPower = hero.power;
  4752. // Лара Крофт * 3
  4753. if (hero.id == 63 && hero.color >= 16) {
  4754. heroPower *= 3;
  4755. }
  4756. heroesArr.push({ id: hero.id, power: heroPower });
  4757. }
  4758. }
  4759.  
  4760. /**
  4761. * Adding expeditions to send
  4762. * Добавляем экспедиции для отправки
  4763. */
  4764. heroesArr.sort((a, b) => (a.power - b.power));
  4765. for (const exped of dataExped.exped) {
  4766. let heroesIds = this.selectionHeroes(heroesArr, exped.power);
  4767. if (heroesIds && heroesIds.length > 4) {
  4768. for (let q in heroesArr) {
  4769. if (heroesIds.includes(heroesArr[q].id)) {
  4770. delete heroesArr[q];
  4771. }
  4772. }
  4773. calls.push({
  4774. name: "expeditionSendHeroes",
  4775. args: {
  4776. expeditionId: exped.id,
  4777. heroes: heroesIds
  4778. },
  4779. ident: "expeditionSendHeroes_" + exped.id
  4780. });
  4781. }
  4782. }
  4783.  
  4784. await Send(JSON.stringify({ calls }));
  4785. this.end();
  4786. }
  4787.  
  4788. /**
  4789. * Selection of heroes for expeditions
  4790. *
  4791. * Подбор героев для экспедиций
  4792. */
  4793. selectionHeroes(heroes, power) {
  4794. const resultHeroers = [];
  4795. const heroesIds = [];
  4796. for (let q = 0; q < 5; q++) {
  4797. for (let i in heroes) {
  4798. let hero = heroes[i];
  4799. if (heroesIds.includes(hero.id)) {
  4800. continue;
  4801. }
  4802.  
  4803. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  4804. const need = Math.round((power - summ) / (5 - resultHeroers.length));
  4805. if (hero.power > need) {
  4806. resultHeroers.push(hero);
  4807. heroesIds.push(hero.id);
  4808. break;
  4809. }
  4810. }
  4811. }
  4812.  
  4813. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  4814. if (summ < power) {
  4815. return false;
  4816. }
  4817. return heroesIds;
  4818. }
  4819.  
  4820. /**
  4821. * Ends expedition script
  4822. *
  4823. * Завершает скрипт экспедиции
  4824. */
  4825. end() {
  4826. setProgress(I18N('EXPEDITIONS_SENT'), true);
  4827. this.resolve()
  4828. }
  4829. }
  4830.  
  4831. /**
  4832. * Walkthrough of the dungeon
  4833. *
  4834. * Прохождение подземелья
  4835. */
  4836. function testDungeon() {
  4837. return new Promise((resolve, reject) => {
  4838. const dung = new executeDungeon(resolve, reject);
  4839. const titanit = getInput('countTitanit');
  4840. dung.start(titanit);
  4841. });
  4842. }
  4843.  
  4844. /**
  4845. * Walkthrough of the dungeon
  4846. *
  4847. * Прохождение подземелья
  4848. */
  4849. function executeDungeon(resolve, reject) {
  4850. dungeonActivity = 0;
  4851. maxDungeonActivity = 150;
  4852.  
  4853. titanGetAll = [];
  4854.  
  4855. teams = {
  4856. heroes: [],
  4857. earth: [],
  4858. fire: [],
  4859. neutral: [],
  4860. water: [],
  4861. }
  4862.  
  4863. titanStats = [];
  4864.  
  4865. titansStates = {};
  4866.  
  4867. callsExecuteDungeon = {
  4868. calls: [{
  4869. name: "dungeonGetInfo",
  4870. args: {},
  4871. ident: "dungeonGetInfo"
  4872. }, {
  4873. name: "teamGetAll",
  4874. args: {},
  4875. ident: "teamGetAll"
  4876. }, {
  4877. name: "teamGetFavor",
  4878. args: {},
  4879. ident: "teamGetFavor"
  4880. }, {
  4881. name: "clanGetInfo",
  4882. args: {},
  4883. ident: "clanGetInfo"
  4884. }, {
  4885. name: "titanGetAll",
  4886. args: {},
  4887. ident: "titanGetAll"
  4888. }, {
  4889. name: "inventoryGet",
  4890. args: {},
  4891. ident: "inventoryGet"
  4892. }]
  4893. }
  4894.  
  4895. this.start = function(titanit) {
  4896. maxDungeonActivity = titanit || getInput('countTitanit');
  4897. send(JSON.stringify(callsExecuteDungeon), startDungeon);
  4898. }
  4899.  
  4900. /**
  4901. * Getting data on the dungeon
  4902. *
  4903. * Получаем данные по подземелью
  4904. */
  4905. function startDungeon(e) {
  4906. stopDung = false; // стоп подземка
  4907. res = e.results;
  4908. dungeonGetInfo = res[0].result.response;
  4909. if (!dungeonGetInfo) {
  4910. endDungeon('noDungeon', res);
  4911. return;
  4912. }
  4913. teamGetAll = res[1].result.response;
  4914. teamGetFavor = res[2].result.response;
  4915. dungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  4916. titanGetAll = Object.values(res[4].result.response);
  4917. countPredictionCard = res[5].result.response.consumable[81];
  4918.  
  4919. teams.hero = {
  4920. favor: teamGetFavor.dungeon_hero,
  4921. heroes: teamGetAll.dungeon_hero.filter(id => id < 6000),
  4922. teamNum: 0,
  4923. }
  4924. heroPet = teamGetAll.dungeon_hero.filter(id => id >= 6000).pop();
  4925. if (heroPet) {
  4926. teams.hero.pet = heroPet;
  4927. }
  4928.  
  4929. teams.neutral = {
  4930. favor: {},
  4931. heroes: getTitanTeam(titanGetAll, 'neutral'),
  4932. teamNum: 0,
  4933. };
  4934. teams.water = {
  4935. favor: {},
  4936. heroes: getTitanTeam(titanGetAll, 'water'),
  4937. teamNum: 0,
  4938. };
  4939. teams.fire = {
  4940. favor: {},
  4941. heroes: getTitanTeam(titanGetAll, 'fire'),
  4942. teamNum: 0,
  4943. };
  4944. teams.earth = {
  4945. favor: {},
  4946. heroes: getTitanTeam(titanGetAll, 'earth'),
  4947. teamNum: 0,
  4948. };
  4949.  
  4950.  
  4951. checkFloor(dungeonGetInfo);
  4952. }
  4953.  
  4954. function getTitanTeam(titans, type) {
  4955. switch (type) {
  4956. case 'neutral':
  4957. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4958. case 'water':
  4959. return titans.filter(e => e.id.toString().slice(2, 3) == '0').map(e => e.id);
  4960. case 'fire':
  4961. return titans.filter(e => e.id.toString().slice(2, 3) == '1').map(e => e.id);
  4962. case 'earth':
  4963. return titans.filter(e => e.id.toString().slice(2, 3) == '2').map(e => e.id);
  4964. }
  4965. }
  4966.  
  4967. function getNeutralTeam() {
  4968. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  4969. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  4970. }
  4971.  
  4972. function fixTitanTeam(titans) {
  4973. titans.heroes = titans.heroes.filter(e => !titansStates[e]?.isDead);
  4974. return titans;
  4975. }
  4976.  
  4977. /**
  4978. * Checking the floor
  4979. *
  4980. * Проверяем этаж
  4981. */
  4982. async function checkFloor(dungeonInfo) {
  4983. if (!('floor' in dungeonInfo) || dungeonInfo.floor?.state == 2) {
  4984. saveProgress();
  4985. return;
  4986. }
  4987. // console.log(dungeonInfo, dungeonActivity);
  4988. setProgress(`${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  4989. if (dungeonActivity >= maxDungeonActivity) {
  4990. endDungeon('endDungeon', 'maxActive ' + dungeonActivity + '/' + maxDungeonActivity);
  4991. return;
  4992. }
  4993. titansStates = dungeonInfo.states.titans;
  4994. titanStats = titanObjToArray(titansStates);
  4995. if (stopDung){
  4996. endDungeon('Стоп подземка,', 'набрано титанита: ' + dungeonActivity + '/' + maxDungeonActivity);
  4997. return;
  4998. }
  4999. const floorChoices = dungeonInfo.floor.userData;
  5000. const floorType = dungeonInfo.floorType;
  5001. //const primeElement = dungeonInfo.elements.prime;
  5002. if (floorType == "battle") {
  5003. const calls = [];
  5004. for (let teamNum in floorChoices) {
  5005. attackerType = floorChoices[teamNum].attackerType;
  5006. const args = fixTitanTeam(teams[attackerType]);
  5007. if (attackerType == 'neutral') {
  5008. args.heroes = getNeutralTeam();
  5009. }
  5010. if (!args.heroes.length) {
  5011. continue;
  5012. }
  5013. args.teamNum = teamNum;
  5014. calls.push({
  5015. name: "dungeonStartBattle",
  5016. args,
  5017. ident: "body_" + teamNum
  5018. })
  5019. }
  5020. if (!calls.length) {
  5021. endDungeon('endDungeon', 'All Dead');
  5022. return;
  5023. }
  5024. const battleDatas = await Send(JSON.stringify({ calls }))
  5025. .then(e => e.results.map(n => n.result.response))
  5026. const battleResults = [];
  5027. for (n in battleDatas) {
  5028. battleData = battleDatas[n]
  5029. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  5030. battleResults.push(await Calc(battleData).then(result => {
  5031. result.teamNum = n;
  5032. result.attackerType = floorChoices[n].attackerType;
  5033. return result;
  5034. }));
  5035. }
  5036. processingPromises(battleResults)
  5037. }
  5038. }
  5039.  
  5040. function processingPromises(results) {
  5041. let selectBattle = results[0];
  5042. if (results.length < 2) {
  5043. // console.log(selectBattle);
  5044. if (!selectBattle.result.win) {
  5045. endDungeon('dungeonEndBattle\n', selectBattle);
  5046. return;
  5047. }
  5048. endBattle(selectBattle);
  5049. return;
  5050. }
  5051.  
  5052. selectBattle = false;
  5053. let bestState = -1000;
  5054. for (const result of results) {
  5055. const recovery = getState(result);
  5056. if (recovery > bestState) {
  5057. bestState = recovery;
  5058. selectBattle = result
  5059. }
  5060. }
  5061. // console.log(selectBattle.teamNum, results);
  5062. if (!selectBattle || bestState <= -1000) {
  5063. endDungeon('dungeonEndBattle\n', results);
  5064. return;
  5065. }
  5066.  
  5067. startBattle(selectBattle.teamNum, selectBattle.attackerType)
  5068. .then(endBattle);
  5069. }
  5070.  
  5071. /**
  5072. * Let's start the fight
  5073. *
  5074. * Начинаем бой
  5075. */
  5076. function startBattle(teamNum, attackerType) {
  5077. return new Promise(function (resolve, reject) {
  5078. args = fixTitanTeam(teams[attackerType]);
  5079. args.teamNum = teamNum;
  5080. if (attackerType == 'neutral') {
  5081. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  5082. args.heroes = titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5083. }
  5084. startBattleCall = {
  5085. calls: [{
  5086. name: "dungeonStartBattle",
  5087. args,
  5088. ident: "body"
  5089. }]
  5090. }
  5091. send(JSON.stringify(startBattleCall), resultBattle, {
  5092. resolve,
  5093. teamNum,
  5094. attackerType
  5095. });
  5096. });
  5097. }
  5098. /**
  5099. * Returns the result of the battle in a promise
  5100. *
  5101. * Возращает резульат боя в промис
  5102. */
  5103. function resultBattle(resultBattles, args) {
  5104. battleData = resultBattles.results[0].result.response;
  5105. battleType = "get_tower";
  5106. if (battleData.type == "dungeon_titan") {
  5107. battleType = "get_titan";
  5108. }
  5109. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  5110. BattleCalc(battleData, battleType, function (result) {
  5111. result.teamNum = args.teamNum;
  5112. result.attackerType = args.attackerType;
  5113. args.resolve(result);
  5114. });
  5115. }
  5116. /**
  5117. * Finishing the fight
  5118. *
  5119. * Заканчиваем бой
  5120. */
  5121. async function endBattle(battleInfo) {
  5122. if (battleInfo.result.win) {
  5123. const args = {
  5124. result: battleInfo.result,
  5125. progress: battleInfo.progress,
  5126. }
  5127. if (countPredictionCard > 0) {
  5128. args.isRaid = true;
  5129. } else {
  5130. const timer = getTimer(battleInfo.battleTime);
  5131. console.log(timer);
  5132. await countdownTimer(timer, `${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  5133. }
  5134. const calls = [{
  5135. name: "dungeonEndBattle",
  5136. args,
  5137. ident: "body"
  5138. }];
  5139. lastDungeonBattleData = null;
  5140. send(JSON.stringify({ calls }), resultEndBattle);
  5141. } else {
  5142. endDungeon('dungeonEndBattle win: false\n', battleInfo);
  5143. }
  5144. }
  5145.  
  5146. /**
  5147. * Getting and processing battle results
  5148. *
  5149. * Получаем и обрабатываем результаты боя
  5150. */
  5151. function resultEndBattle(e) {
  5152. if ('error' in e) {
  5153. popup.confirm(I18N('ERROR_MSG', {
  5154. name: e.error.name,
  5155. description: e.error.description,
  5156. }));
  5157. endDungeon('errorRequest', e);
  5158. return;
  5159. }
  5160. battleResult = e.results[0].result.response;
  5161. if ('error' in battleResult) {
  5162. endDungeon('errorBattleResult', battleResult);
  5163. return;
  5164. }
  5165. dungeonGetInfo = battleResult.dungeon ?? battleResult;
  5166. dungeonActivity += battleResult.reward.dungeonActivity ?? 0;
  5167. checkFloor(dungeonGetInfo);
  5168. }
  5169.  
  5170. /**
  5171. * Returns the coefficient of condition of the
  5172. * difference in titanium before and after the battle
  5173. *
  5174. * Возвращает коэффициент состояния титанов после боя
  5175. */
  5176. function getState(result) {
  5177. if (!result.result.win) {
  5178. return -1000;
  5179. }
  5180.  
  5181. let beforeSumFactor = 0;
  5182. const beforeTitans = result.battleData.attackers;
  5183. for (let titanId in beforeTitans) {
  5184. const titan = beforeTitans[titanId];
  5185. const state = titan.state;
  5186. let factor = 1;
  5187. if (state) {
  5188. const hp = state.hp / titan.hp;
  5189. const energy = state.energy / 1e3;
  5190. factor = hp + energy / 20
  5191. }
  5192. beforeSumFactor += factor;
  5193. }
  5194.  
  5195. let afterSumFactor = 0;
  5196. const afterTitans = result.progress[0].attackers.heroes;
  5197. for (let titanId in afterTitans) {
  5198. const titan = afterTitans[titanId];
  5199. const hp = titan.hp / beforeTitans[titanId].hp;
  5200. const energy = titan.energy / 1e3;
  5201. const factor = hp + energy / 20;
  5202. afterSumFactor += factor;
  5203. }
  5204. return afterSumFactor - beforeSumFactor;
  5205. }
  5206.  
  5207. /**
  5208. * Converts an object with IDs to an array with IDs
  5209. *
  5210. * Преобразует объект с идетификаторами в массив с идетификаторами
  5211. */
  5212. function titanObjToArray(obj) {
  5213. let titans = [];
  5214. for (let id in obj) {
  5215. obj[id].id = id;
  5216. titans.push(obj[id]);
  5217. }
  5218. return titans;
  5219. }
  5220.  
  5221. function saveProgress() {
  5222. let saveProgressCall = {
  5223. calls: [{
  5224. name: "dungeonSaveProgress",
  5225. args: {},
  5226. ident: "body"
  5227. }]
  5228. }
  5229. send(JSON.stringify(saveProgressCall), resultEndBattle);
  5230. }
  5231.  
  5232. function endDungeon(reason, info) {
  5233. console.warn(reason, info);
  5234. setProgress(`${I18N('DUNGEON')} ${I18N('COMPLETED')}`, true);
  5235. resolve();
  5236. }
  5237. }
  5238.  
  5239. /**
  5240. * Passing the tower
  5241. *
  5242. * Прохождение башни
  5243. */
  5244. function testTower() {
  5245. return new Promise((resolve, reject) => {
  5246. tower = new executeTower(resolve, reject);
  5247. tower.start();
  5248. });
  5249. }
  5250.  
  5251. /**
  5252. * Passing the tower
  5253. *
  5254. * Прохождение башни
  5255. */
  5256. function executeTower(resolve, reject) {
  5257. lastTowerInfo = {};
  5258.  
  5259. scullCoin = 0;
  5260.  
  5261. heroGetAll = [];
  5262.  
  5263. heroesStates = {};
  5264.  
  5265. argsBattle = {
  5266. heroes: [],
  5267. favor: {},
  5268. };
  5269.  
  5270. callsExecuteTower = {
  5271. calls: [{
  5272. name: "towerGetInfo",
  5273. args: {},
  5274. ident: "towerGetInfo"
  5275. }, {
  5276. name: "teamGetAll",
  5277. args: {},
  5278. ident: "teamGetAll"
  5279. }, {
  5280. name: "teamGetFavor",
  5281. args: {},
  5282. ident: "teamGetFavor"
  5283. }, {
  5284. name: "inventoryGet",
  5285. args: {},
  5286. ident: "inventoryGet"
  5287. }, {
  5288. name: "heroGetAll",
  5289. args: {},
  5290. ident: "heroGetAll"
  5291. }]
  5292. }
  5293.  
  5294. buffIds = [
  5295. {id: 0, cost: 0, isBuy: false}, // plug // заглушка
  5296. {id: 1, cost: 1, isBuy: true}, // 3% attack // 3% атака
  5297. {id: 2, cost: 6, isBuy: true}, // 2% attack // 2% атака
  5298. {id: 3, cost: 16, isBuy: true}, // 4% attack // 4% атака
  5299. {id: 4, cost: 40, isBuy: true}, // 8% attack // 8% атака
  5300. {id: 5, cost: 1, isBuy: true}, // 10% armor // 10% броня
  5301. {id: 6, cost: 6, isBuy: true}, // 5% armor // 5% броня
  5302. {id: 7, cost: 16, isBuy: true}, // 10% armor // 10% броня
  5303. {id: 8, cost: 40, isBuy: true}, // 20% armor // 20% броня
  5304. { id: 9, cost: 1, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5305. { id: 10, cost: 6, isBuy: true }, // 5% protection from magic // 5% защита от магии
  5306. { id: 11, cost: 16, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5307. { id: 12, cost: 40, isBuy: true }, // 20% protection from magic // 20% защита от магии
  5308. { id: 13, cost: 1, isBuy: false }, // 40% health hero // 40% здоровья герою
  5309. { id: 14, cost: 6, isBuy: false }, // 40% health hero // 40% здоровья герою
  5310. { id: 15, cost: 16, isBuy: false }, // 80% health hero // 80% здоровья герою
  5311. { id: 16, cost: 40, isBuy: false }, // 40% health to all heroes // 40% здоровья всем героям
  5312. { id: 17, cost: 1, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5313. { id: 18, cost: 3, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5314. { id: 19, cost: 8, isBuy: false }, // 80% energy to the hero // 80% энергии герою
  5315. { id: 20, cost: 20, isBuy: false }, // 40% energy to all heroes // 40% энергии всем героям
  5316. { id: 21, cost: 40, isBuy: false }, // Hero Resurrection // Воскрешение героя
  5317. ]
  5318.  
  5319. this.start = function () {
  5320. send(JSON.stringify(callsExecuteTower), startTower);
  5321. }
  5322.  
  5323. /**
  5324. * Getting data on the Tower
  5325. *
  5326. * Получаем данные по башне
  5327. */
  5328. function startTower(e) {
  5329. res = e.results;
  5330. towerGetInfo = res[0].result.response;
  5331. if (!towerGetInfo) {
  5332. endTower('noTower', res);
  5333. return;
  5334. }
  5335. teamGetAll = res[1].result.response;
  5336. teamGetFavor = res[2].result.response;
  5337. inventoryGet = res[3].result.response;
  5338. heroGetAll = Object.values(res[4].result.response);
  5339.  
  5340. scullCoin = inventoryGet.coin[7] ?? 0;
  5341.  
  5342. argsBattle.favor = teamGetFavor.tower;
  5343. argsBattle.heroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5344. pet = teamGetAll.tower.filter(id => id >= 6000).pop();
  5345. if (pet) {
  5346. argsBattle.pet = pet;
  5347. }
  5348.  
  5349. checkFloor(towerGetInfo);
  5350. }
  5351.  
  5352. function fixHeroesTeam(argsBattle) {
  5353. let fixHeroes = argsBattle.heroes.filter(e => !heroesStates[e]?.isDead);
  5354. if (fixHeroes.length < 5) {
  5355. heroGetAll = heroGetAll.filter(e => !heroesStates[e.id]?.isDead);
  5356. fixHeroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5357. Object.keys(argsBattle.favor).forEach(e => {
  5358. if (!fixHeroes.includes(+e)) {
  5359. delete argsBattle.favor[e];
  5360. }
  5361. })
  5362. }
  5363. argsBattle.heroes = fixHeroes;
  5364. return argsBattle;
  5365. }
  5366.  
  5367. /**
  5368. * Check the floor
  5369. *
  5370. * Проверяем этаж
  5371. */
  5372. function checkFloor(towerInfo) {
  5373. lastTowerInfo = towerInfo;
  5374. maySkipFloor = +towerInfo.maySkipFloor;
  5375. floorNumber = +towerInfo.floorNumber;
  5376. heroesStates = towerInfo.states.heroes;
  5377. floorInfo = towerInfo.floor;
  5378.  
  5379. /**
  5380. * Is there at least one chest open on the floor
  5381. * Открыт ли на этаже хоть один сундук
  5382. */
  5383. isOpenChest = false;
  5384. if (towerInfo.floorType == "chest") {
  5385. isOpenChest = towerInfo.floor.chests.reduce((n, e) => n + e.opened, 0);
  5386. }
  5387.  
  5388. setProgress(`${I18N('TOWER')}: ${I18N('FLOOR')} ${floorNumber}`);
  5389. if (floorNumber > 49) {
  5390. if (isOpenChest) {
  5391. endTower('alreadyOpenChest 50 floor', floorNumber);
  5392. return;
  5393. }
  5394. }
  5395. /**
  5396. * If the chest is open and you can skip floors, then move on
  5397. * Если сундук открыт и можно скипать этажи, то переходим дальше
  5398. */
  5399. if (towerInfo.mayFullSkip && +towerInfo.teamLevel == 130) {
  5400. if (isOpenChest) {
  5401. nextOpenChest(floorNumber);
  5402. } else {
  5403. nextChestOpen(floorNumber);
  5404. }
  5405. return;
  5406. }
  5407.  
  5408. // console.log(towerInfo, scullCoin);
  5409. switch (towerInfo.floorType) {
  5410. case "battle":
  5411. if (floorNumber <= maySkipFloor) {
  5412. skipFloor();
  5413. return;
  5414. }
  5415. if (floorInfo.state == 2) {
  5416. nextFloor();
  5417. return;
  5418. }
  5419. startBattle().then(endBattle);
  5420. return;
  5421. case "buff":
  5422. checkBuff(towerInfo);
  5423. return;
  5424. case "chest":
  5425. openChest(floorNumber);
  5426. return;
  5427. default:
  5428. console.log('!', towerInfo.floorType, towerInfo);
  5429. break;
  5430. }
  5431. }
  5432.  
  5433. /**
  5434. * Let's start the fight
  5435. *
  5436. * Начинаем бой
  5437. */
  5438. function startBattle() {
  5439. return new Promise(function (resolve, reject) {
  5440. towerStartBattle = {
  5441. calls: [{
  5442. name: "towerStartBattle",
  5443. args: fixHeroesTeam(argsBattle),
  5444. ident: "body"
  5445. }]
  5446. }
  5447. send(JSON.stringify(towerStartBattle), resultBattle, resolve);
  5448. });
  5449. }
  5450. /**
  5451. * Returns the result of the battle in a promise
  5452. *
  5453. * Возращает резульат боя в промис
  5454. */
  5455. function resultBattle(resultBattles, resolve) {
  5456. battleData = resultBattles.results[0].result.response;
  5457. battleType = "get_tower";
  5458. BattleCalc(battleData, battleType, function (result) {
  5459. resolve(result);
  5460. });
  5461. }
  5462. /**
  5463. * Finishing the fight
  5464. *
  5465. * Заканчиваем бой
  5466. */
  5467. function endBattle(battleInfo) {
  5468. if (battleInfo.result.stars >= 3) {
  5469. endBattleCall = {
  5470. calls: [{
  5471. name: "towerEndBattle",
  5472. args: {
  5473. result: battleInfo.result,
  5474. progress: battleInfo.progress,
  5475. },
  5476. ident: "body"
  5477. }]
  5478. }
  5479. send(JSON.stringify(endBattleCall), resultEndBattle);
  5480. } else {
  5481. endTower('towerEndBattle win: false\n', battleInfo);
  5482. }
  5483. }
  5484.  
  5485. /**
  5486. * Getting and processing battle results
  5487. *
  5488. * Получаем и обрабатываем результаты боя
  5489. */
  5490. function resultEndBattle(e) {
  5491. battleResult = e.results[0].result.response;
  5492. if ('error' in battleResult) {
  5493. endTower('errorBattleResult', battleResult);
  5494. return;
  5495. }
  5496. if ('reward' in battleResult) {
  5497. scullCoin += battleResult.reward?.coin[7] ?? 0;
  5498. }
  5499. nextFloor();
  5500. }
  5501.  
  5502. function nextFloor() {
  5503. nextFloorCall = {
  5504. calls: [{
  5505. name: "towerNextFloor",
  5506. args: {},
  5507. ident: "body"
  5508. }]
  5509. }
  5510. send(JSON.stringify(nextFloorCall), checkDataFloor);
  5511. }
  5512.  
  5513. function openChest(floorNumber) {
  5514. floorNumber = floorNumber || 0;
  5515. openChestCall = {
  5516. calls: [{
  5517. name: "towerOpenChest",
  5518. args: {
  5519. num: 2
  5520. },
  5521. ident: "body"
  5522. }]
  5523. }
  5524. send(JSON.stringify(openChestCall), floorNumber < 50 ? nextFloor : lastChest);
  5525. }
  5526.  
  5527. function lastChest() {
  5528. endTower('openChest 50 floor', floorNumber);
  5529. }
  5530.  
  5531. function skipFloor() {
  5532. skipFloorCall = {
  5533. calls: [{
  5534. name: "towerSkipFloor",
  5535. args: {},
  5536. ident: "body"
  5537. }]
  5538. }
  5539. send(JSON.stringify(skipFloorCall), checkDataFloor);
  5540. }
  5541.  
  5542. function checkBuff(towerInfo) {
  5543. buffArr = towerInfo.floor;
  5544. promises = [];
  5545. for (let buff of buffArr) {
  5546. buffInfo = buffIds[buff.id];
  5547. if (buffInfo.isBuy && buffInfo.cost <= scullCoin) {
  5548. scullCoin -= buffInfo.cost;
  5549. promises.push(buyBuff(buff.id));
  5550. }
  5551. }
  5552. Promise.all(promises).then(nextFloor);
  5553. }
  5554.  
  5555. function buyBuff(buffId) {
  5556. return new Promise(function (resolve, reject) {
  5557. buyBuffCall = {
  5558. calls: [{
  5559. name: "towerBuyBuff",
  5560. args: {
  5561. buffId
  5562. },
  5563. ident: "body"
  5564. }]
  5565. }
  5566. send(JSON.stringify(buyBuffCall), resolve);
  5567. });
  5568. }
  5569.  
  5570. function checkDataFloor(result) {
  5571. towerInfo = result.results[0].result.response;
  5572. if ('reward' in towerInfo && towerInfo.reward?.coin) {
  5573. scullCoin += towerInfo.reward?.coin[7] ?? 0;
  5574. }
  5575. if ('tower' in towerInfo) {
  5576. towerInfo = towerInfo.tower;
  5577. }
  5578. if ('skullReward' in towerInfo) {
  5579. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  5580. }
  5581. checkFloor(towerInfo);
  5582. }
  5583. /**
  5584. * Getting tower rewards
  5585. *
  5586. * Получаем награды башни
  5587. */
  5588. function farmTowerRewards(reason) {
  5589. let { pointRewards, points } = lastTowerInfo;
  5590. let pointsAll = Object.getOwnPropertyNames(pointRewards);
  5591. let farmPoints = pointsAll.filter(e => +e <= +points && !pointRewards[e]);
  5592. if (!farmPoints.length) {
  5593. return;
  5594. }
  5595. let farmTowerRewardsCall = {
  5596. calls: [{
  5597. name: "tower_farmPointRewards",
  5598. args: {
  5599. points: farmPoints
  5600. },
  5601. ident: "tower_farmPointRewards"
  5602. }]
  5603. }
  5604.  
  5605. if (scullCoin > 0 && reason == 'openChest 50 floor') {
  5606. farmTowerRewardsCall.calls.push({
  5607. name: "tower_farmSkullReward",
  5608. args: {},
  5609. ident: "tower_farmSkullReward"
  5610. });
  5611. }
  5612.  
  5613. send(JSON.stringify(farmTowerRewardsCall), () => { });
  5614. }
  5615.  
  5616. function fullSkipTower() {
  5617. /**
  5618. * Next chest
  5619. *
  5620. * Следующий сундук
  5621. */
  5622. function nextChest(n) {
  5623. return {
  5624. name: "towerNextChest",
  5625. args: {},
  5626. ident: "group_" + n + "_body"
  5627. }
  5628. }
  5629. /**
  5630. * Open chest
  5631. *
  5632. * Открыть сундук
  5633. */
  5634. function openChest(n) {
  5635. return {
  5636. name: "towerOpenChest",
  5637. args: {
  5638. "num": 2
  5639. },
  5640. ident: "group_" + n + "_body"
  5641. }
  5642. }
  5643.  
  5644. const fullSkipTowerCall = {
  5645. calls: []
  5646. }
  5647.  
  5648. let n = 0;
  5649. for (let i = 0; i < 15; i++) {
  5650. fullSkipTowerCall.calls.push(nextChest(++n));
  5651. fullSkipTowerCall.calls.push(openChest(++n));
  5652. }
  5653.  
  5654. send(JSON.stringify(fullSkipTowerCall), data => {
  5655. data.results[0] = data.results[28];
  5656. checkDataFloor(data);
  5657. });
  5658. }
  5659.  
  5660. function nextChestOpen(floorNumber) {
  5661. const calls = [{
  5662. name: "towerOpenChest",
  5663. args: {
  5664. num: 2
  5665. },
  5666. ident: "towerOpenChest"
  5667. }];
  5668.  
  5669. Send(JSON.stringify({ calls })).then(e => {
  5670. nextOpenChest(floorNumber);
  5671. });
  5672. }
  5673.  
  5674. function nextOpenChest(floorNumber) {
  5675. if (floorNumber > 49) {
  5676. endTower('openChest 50 floor', floorNumber);
  5677. return;
  5678. }
  5679. if (floorNumber == 1) {
  5680. fullSkipTower();
  5681. return;
  5682. }
  5683.  
  5684. let nextOpenChestCall = {
  5685. calls: [{
  5686. name: "towerNextChest",
  5687. args: {},
  5688. ident: "towerNextChest"
  5689. }, {
  5690. name: "towerOpenChest",
  5691. args: {
  5692. num: 2
  5693. },
  5694. ident: "towerOpenChest"
  5695. }]
  5696. }
  5697. send(JSON.stringify(nextOpenChestCall), checkDataFloor);
  5698. }
  5699.  
  5700. function endTower(reason, info) {
  5701. console.log(reason, info);
  5702. if (reason != 'noTower') {
  5703. farmTowerRewards(reason);
  5704. }
  5705. setProgress(`${I18N('TOWER')} ${I18N('COMPLETED')}!`, true);
  5706. resolve();
  5707. }
  5708. }
  5709.  
  5710. /**
  5711. * Passage of the arena of the titans
  5712. *
  5713. * Прохождение арены титанов
  5714. */
  5715. function testTitanArena() {
  5716. return new Promise((resolve, reject) => {
  5717. titAren = new executeTitanArena(resolve, reject);
  5718. titAren.start();
  5719. });
  5720. }
  5721.  
  5722. /**
  5723. * Passage of the arena of the titans
  5724. *
  5725. * Прохождение арены титанов
  5726. */
  5727. function executeTitanArena(resolve, reject) {
  5728. let titan_arena = [];
  5729. let finishListBattle = [];
  5730. /**
  5731. * ID of the current batch
  5732. *
  5733. * Идетификатор текущей пачки
  5734. */
  5735. let currentRival = 0;
  5736. /**
  5737. * Number of attempts to finish off the pack
  5738. *
  5739. * Количество попыток добития пачки
  5740. */
  5741. let attempts = 0;
  5742. /**
  5743. * Was there an attempt to finish off the current shooting range
  5744. *
  5745. * Была ли попытка добития текущего тира
  5746. */
  5747. let isCheckCurrentTier = false;
  5748. /**
  5749. * Current shooting range
  5750. *
  5751. * Текущий тир
  5752. */
  5753. let currTier = 0;
  5754. /**
  5755. * Number of battles on the current dash
  5756. *
  5757. * Количество битв на текущем тире
  5758. */
  5759. let countRivalsTier = 0;
  5760.  
  5761. let callsStart = {
  5762. calls: [{
  5763. name: "titanArenaGetStatus",
  5764. args: {},
  5765. ident: "titanArenaGetStatus"
  5766. }, {
  5767. name: "teamGetAll",
  5768. args: {},
  5769. ident: "teamGetAll"
  5770. }]
  5771. }
  5772.  
  5773. this.start = function () {
  5774. send(JSON.stringify(callsStart), startTitanArena);
  5775. }
  5776.  
  5777. function startTitanArena(data) {
  5778. let titanArena = data.results[0].result.response;
  5779. if (titanArena.status == 'disabled') {
  5780. endTitanArena('disabled', titanArena);
  5781. return;
  5782. }
  5783.  
  5784. let teamGetAll = data.results[1].result.response;
  5785. titan_arena = teamGetAll.titan_arena;
  5786.  
  5787. checkTier(titanArena)
  5788. }
  5789.  
  5790. function checkTier(titanArena) {
  5791. if (titanArena.status == "peace_time") {
  5792. endTitanArena('Peace_time', titanArena);
  5793. return;
  5794. }
  5795. currTier = titanArena.tier;
  5796. if (currTier) {
  5797. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier}`);
  5798. }
  5799.  
  5800. if (titanArena.status == "completed_tier") {
  5801. titanArenaCompleteTier();
  5802. return;
  5803. }
  5804. /**
  5805. * Checking for the possibility of a raid
  5806. * Проверка на возможность рейда
  5807. */
  5808. if (titanArena.canRaid) {
  5809. titanArenaStartRaid();
  5810. return;
  5811. }
  5812. /**
  5813. * Check was an attempt to achieve the current shooting range
  5814. * Проверка была ли попытка добития текущего тира
  5815. */
  5816. if (!isCheckCurrentTier) {
  5817. checkRivals(titanArena.rivals);
  5818. return;
  5819. }
  5820.  
  5821. endTitanArena('Done or not canRaid', titanArena);
  5822. }
  5823. /**
  5824. * Submit dash information for verification
  5825. *
  5826. * Отправка информации о тире на проверку
  5827. */
  5828. function checkResultInfo(data) {
  5829. let titanArena = data.results[0].result.response;
  5830. checkTier(titanArena);
  5831. }
  5832. /**
  5833. * Finish the current tier
  5834. *
  5835. * Завершить текущий тир
  5836. */
  5837. function titanArenaCompleteTier() {
  5838. isCheckCurrentTier = false;
  5839. let calls = [{
  5840. name: "titanArenaCompleteTier",
  5841. args: {},
  5842. ident: "body"
  5843. }];
  5844. send(JSON.stringify({calls}), checkResultInfo);
  5845. }
  5846. /**
  5847. * Gathering points to be completed
  5848. *
  5849. * Собираем точки которые нужно добить
  5850. */
  5851. function checkRivals(rivals) {
  5852. finishListBattle = [];
  5853. for (let n in rivals) {
  5854. if (rivals[n].attackScore < 250) {
  5855. finishListBattle.push(n);
  5856. }
  5857. }
  5858. console.log('checkRivals', finishListBattle);
  5859. countRivalsTier = finishListBattle.length;
  5860. roundRivals();
  5861. }
  5862. /**
  5863. * Selecting the next point to finish off
  5864. *
  5865. * Выбор следующей точки для добития
  5866. */
  5867. function roundRivals() {
  5868. let countRivals = finishListBattle.length;
  5869. if (!countRivals) {
  5870. /**
  5871. * Whole range checked
  5872. *
  5873. * Весь тир проверен
  5874. */
  5875. isCheckCurrentTier = true;
  5876. titanArenaGetStatus();
  5877. return;
  5878. }
  5879. // setProgress('TitanArena: Уровень ' + currTier + ' Бои: ' + (countRivalsTier - countRivals + 1) + '/' + countRivalsTier);
  5880. currentRival = finishListBattle.pop();
  5881. attempts = +currentRival;
  5882. // console.log('roundRivals', currentRival);
  5883. titanArenaStartBattle(currentRival);
  5884. }
  5885. /**
  5886. * The start of a solo battle
  5887. *
  5888. * Начало одиночной битвы
  5889. */
  5890. function titanArenaStartBattle(rivalId) {
  5891. let calls = [{
  5892. name: "titanArenaStartBattle",
  5893. args: {
  5894. rivalId: rivalId,
  5895. titans: titan_arena
  5896. },
  5897. ident: "body"
  5898. }];
  5899. send(JSON.stringify({calls}), calcResult);
  5900. }
  5901. /**
  5902. * Calculation of the results of the battle
  5903. *
  5904. * Расчет результатов боя
  5905. */
  5906. function calcResult(data) {
  5907. let battlesInfo = data.results[0].result.response.battle;
  5908. /**
  5909. * If attempts are equal to the current battle number we make
  5910. * Если попытки равны номеру текущего боя делаем прерасчет
  5911. */
  5912. if (attempts == currentRival) {
  5913. preCalcBattle(battlesInfo);
  5914. return;
  5915. }
  5916. /**
  5917. * If there are still attempts, we calculate a new battle
  5918. * Если попытки еще есть делаем расчет нового боя
  5919. */
  5920. if (attempts > 0) {
  5921. attempts--;
  5922. calcBattleResult(battlesInfo)
  5923. .then(resultCalcBattle);
  5924. return;
  5925. }
  5926. /**
  5927. * Otherwise, go to the next opponent
  5928. * Иначе переходим к следующему сопернику
  5929. */
  5930. roundRivals();
  5931. }
  5932. /**
  5933. * Processing the results of the battle calculation
  5934. *
  5935. * Обработка результатов расчета битвы
  5936. */
  5937. function resultCalcBattle(resultBattle) {
  5938. // console.log('resultCalcBattle', currentRival, attempts, resultBattle.result.win);
  5939. /**
  5940. * If the current calculation of victory is not a chance or the attempt ended with the finish the battle
  5941. * Если текущий расчет победа или шансов нет или попытки кончились завершаем бой
  5942. */
  5943. if (resultBattle.result.win || !attempts) {
  5944. titanArenaEndBattle({
  5945. progress: resultBattle.progress,
  5946. result: resultBattle.result,
  5947. rivalId: resultBattle.battleData.typeId
  5948. });
  5949. return;
  5950. }
  5951. /**
  5952. * If not victory and there are attempts we start a new battle
  5953. * Если не победа и есть попытки начинаем новый бой
  5954. */
  5955. titanArenaStartBattle(resultBattle.battleData.typeId);
  5956. }
  5957. /**
  5958. * Returns the promise of calculating the results of the battle
  5959. *
  5960. * Возращает промис расчета результатов битвы
  5961. */
  5962. function getBattleInfo(battle, isRandSeed) {
  5963. return new Promise(function (resolve) {
  5964. if (isRandSeed) {
  5965. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  5966. }
  5967. // console.log(battle.seed);
  5968. BattleCalc(battle, "get_titanClanPvp", e => resolve(e));
  5969. });
  5970. }
  5971. /**
  5972. * Recalculate battles
  5973. *
  5974. * Прерасчтет битвы
  5975. */
  5976. function preCalcBattle(battle) {
  5977. let actions = [getBattleInfo(battle, false)];
  5978. const countTestBattle = getInput('countTestBattle');
  5979. for (let i = 0; i < countTestBattle; i++) {
  5980. actions.push(getBattleInfo(battle, true));
  5981. }
  5982. Promise.all(actions)
  5983. .then(resultPreCalcBattle);
  5984. }
  5985. /**
  5986. * Processing the results of the battle recalculation
  5987. *
  5988. * Обработка результатов прерасчета битвы
  5989. */
  5990. function resultPreCalcBattle(e) {
  5991. let wins = e.map(n => n.result.win);
  5992. let firstBattle = e.shift();
  5993. let countWin = wins.reduce((w, s) => w + s);
  5994. const countTestBattle = getInput('countTestBattle');
  5995. console.log('resultPreCalcBattle', `${countWin}/${countTestBattle}`)
  5996. if (countWin > 0) {
  5997. attempts = getInput('countAutoBattle');
  5998. } else {
  5999. attempts = 0;
  6000. }
  6001. resultCalcBattle(firstBattle);
  6002. }
  6003.  
  6004. /**
  6005. * Complete an arena battle
  6006. *
  6007. * Завершить битву на арене
  6008. */
  6009. function titanArenaEndBattle(args) {
  6010. let calls = [{
  6011. name: "titanArenaEndBattle",
  6012. args,
  6013. ident: "body"
  6014. }];
  6015. send(JSON.stringify({calls}), resultTitanArenaEndBattle);
  6016. }
  6017.  
  6018. function resultTitanArenaEndBattle(e) {
  6019. let attackScore = e.results[0].result.response.attackScore;
  6020. let numReval = countRivalsTier - finishListBattle.length;
  6021. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier} </br>${I18N('BATTLES')}: ${numReval}/${countRivalsTier} - ${attackScore}`);
  6022. /**
  6023. * TODO: Might need to improve the results.
  6024. * TODO: Возможно стоит сделать улучшение результатов
  6025. */
  6026. // console.log('resultTitanArenaEndBattle', e)
  6027. console.log('resultTitanArenaEndBattle', numReval + '/' + countRivalsTier, attempts)
  6028. roundRivals();
  6029. }
  6030. /**
  6031. * Arena State
  6032. *
  6033. * Состояние арены
  6034. */
  6035. function titanArenaGetStatus() {
  6036. let calls = [{
  6037. name: "titanArenaGetStatus",
  6038. args: {},
  6039. ident: "body"
  6040. }];
  6041. send(JSON.stringify({calls}), checkResultInfo);
  6042. }
  6043. /**
  6044. * Arena Raid Request
  6045. *
  6046. * Запрос рейда арены
  6047. */
  6048. function titanArenaStartRaid() {
  6049. let calls = [{
  6050. name: "titanArenaStartRaid",
  6051. args: {
  6052. titans: titan_arena
  6053. },
  6054. ident: "body"
  6055. }];
  6056. send(JSON.stringify({calls}), calcResults);
  6057. }
  6058.  
  6059. function calcResults(data) {
  6060. let battlesInfo = data.results[0].result.response;
  6061. let {attackers, rivals} = battlesInfo;
  6062.  
  6063. let promises = [];
  6064. for (let n in rivals) {
  6065. rival = rivals[n];
  6066. promises.push(calcBattleResult({
  6067. attackers: attackers,
  6068. defenders: [rival.team],
  6069. seed: rival.seed,
  6070. typeId: n,
  6071. }));
  6072. }
  6073.  
  6074. Promise.all(promises)
  6075. .then(results => {
  6076. const endResults = {};
  6077. for (let info of results) {
  6078. let id = info.battleData.typeId;
  6079. endResults[id] = {
  6080. progress: info.progress,
  6081. result: info.result,
  6082. }
  6083. }
  6084. titanArenaEndRaid(endResults);
  6085. });
  6086. }
  6087.  
  6088. function calcBattleResult(battleData) {
  6089. return new Promise(function (resolve, reject) {
  6090. BattleCalc(battleData, "get_titanClanPvp", resolve);
  6091. });
  6092. }
  6093.  
  6094. /**
  6095. * Sending Raid Results
  6096. *
  6097. * Отправка результатов рейда
  6098. */
  6099. function titanArenaEndRaid(results) {
  6100. titanArenaEndRaidCall = {
  6101. calls: [{
  6102. name: "titanArenaEndRaid",
  6103. args: {
  6104. results
  6105. },
  6106. ident: "body"
  6107. }]
  6108. }
  6109. send(JSON.stringify(titanArenaEndRaidCall), checkRaidResults);
  6110. }
  6111.  
  6112. function checkRaidResults(data) {
  6113. results = data.results[0].result.response.results;
  6114. isSucsesRaid = true;
  6115. for (let i in results) {
  6116. isSucsesRaid &&= (results[i].attackScore >= 250);
  6117. }
  6118.  
  6119. if (isSucsesRaid) {
  6120. titanArenaCompleteTier();
  6121. } else {
  6122. titanArenaGetStatus();
  6123. }
  6124. }
  6125.  
  6126. function titanArenaFarmDailyReward() {
  6127. titanArenaFarmDailyRewardCall = {
  6128. calls: [{
  6129. name: "titanArenaFarmDailyReward",
  6130. args: {},
  6131. ident: "body"
  6132. }]
  6133. }
  6134. send(JSON.stringify(titanArenaFarmDailyRewardCall), () => {console.log('Done farm daily reward')});
  6135. }
  6136.  
  6137. function endTitanArena(reason, info) {
  6138. if (!['Peace_time', 'disabled'].includes(reason)) {
  6139. titanArenaFarmDailyReward();
  6140. }
  6141. console.log(reason, info);
  6142. setProgress(`${I18N('TITAN_ARENA')} ${I18N('COMPLETED')}!`, true);
  6143. resolve();
  6144. }
  6145. }
  6146.  
  6147. function hackGame() {
  6148. self = this;
  6149. selfGame = null;
  6150. bindId = 1e9;
  6151. this.libGame = null;
  6152.  
  6153. /**
  6154. * List of correspondence of used classes to their names
  6155. *
  6156. * Список соответствия используемых классов их названиям
  6157. */
  6158. ObjectsList = [
  6159. {name:"BattlePresets", prop:"game.battle.controller.thread.BattlePresets"},
  6160. {name:"DataStorage", prop:"game.data.storage.DataStorage"},
  6161. {name:"BattleConfigStorage", prop:"game.data.storage.battle.BattleConfigStorage"},
  6162. {name:"BattleInstantPlay", prop:"game.battle.controller.instant.BattleInstantPlay"},
  6163. {name:"MultiBattleResult", prop:"game.battle.controller.MultiBattleResult"},
  6164.  
  6165. {name:"PlayerMissionData", prop:"game.model.user.mission.PlayerMissionData"},
  6166. {name:"PlayerMissionBattle", prop:"game.model.user.mission.PlayerMissionBattle"},
  6167. {name:"GameModel", prop:"game.model.GameModel"},
  6168. {name:"CommandManager", prop:"game.command.CommandManager"},
  6169. {name:"MissionCommandList", prop:"game.command.rpc.mission.MissionCommandList"},
  6170. {name:"RPCCommandBase", prop:"game.command.rpc.RPCCommandBase"},
  6171. {name:"PlayerTowerData", prop:"game.model.user.tower.PlayerTowerData"},
  6172. {name:"TowerCommandList", prop:"game.command.tower.TowerCommandList"},
  6173. {name:"PlayerHeroTeamResolver", prop:"game.model.user.hero.PlayerHeroTeamResolver"},
  6174. {name:"BattlePausePopup", prop:"game.view.popup.battle.BattlePausePopup"},
  6175. {name:"BattlePopup", prop:"game.view.popup.battle.BattlePopup"},
  6176. {name:"DisplayObjectContainer", prop:"starling.display.DisplayObjectContainer"},
  6177. {name:"GuiClipContainer", prop:"engine.core.clipgui.GuiClipContainer"},
  6178. {name:"BattlePausePopupClip", prop:"game.view.popup.battle.BattlePausePopupClip"},
  6179. {name:"ClipLabel", prop:"game.view.gui.components.ClipLabel"},
  6180. {name:"ClipLabelBase", prop:"game.view.gui.components.ClipLabelBase"},
  6181. {name:"Translate", prop:"com.progrestar.common.lang.Translate"},
  6182. {name:"ClipButtonLabeledCentered", prop:"game.view.gui.components.ClipButtonLabeledCentered"},
  6183. {name:"BattlePausePopupMediator", prop:"game.mediator.gui.popup.battle.BattlePausePopupMediator"},
  6184. {name:"SettingToggleButton", prop:"game.mechanics.settings.popup.view.SettingToggleButton"},
  6185. {name:"PlayerDungeonData", prop:"game.mechanics.dungeon.model.PlayerDungeonData"},
  6186. {name:"NextDayUpdatedManager", prop:"game.model.user.NextDayUpdatedManager"},
  6187. {name:"BattleController", prop:"game.battle.controller.BattleController"},
  6188. {name:"BattleSettingsModel", prop:"game.battle.controller.BattleSettingsModel"},
  6189. {name:"BooleanProperty", prop:"engine.core.utils.property.BooleanProperty"},
  6190. {name:"RuleStorage", prop:"game.data.storage.rule.RuleStorage"},
  6191. {name:"BattleConfig", prop:"battle.BattleConfig"},
  6192. {name:"BattleGuiMediator", prop:"game.battle.gui.BattleGuiMediator"},
  6193. {name:"BooleanPropertyWriteable", prop:"engine.core.utils.property.BooleanPropertyWriteable"},
  6194. { name: "BattleLogEncoder", prop: "battle.log.BattleLogEncoder" },
  6195. { name: "BattleLogReader", prop: "battle.log.BattleLogReader" },
  6196. { name: "PlayerSubscriptionInfoValueObject", prop: "game.model.user.subscription.PlayerSubscriptionInfoValueObject" },
  6197. ];
  6198.  
  6199. /**
  6200. * Contains the game classes needed to write and override game methods
  6201. *
  6202. * Содержит классы игры необходимые для написания и подмены методов игры
  6203. */
  6204. Game = {
  6205. /**
  6206. * Function 'e'
  6207. * Функция 'e'
  6208. */
  6209. bindFunc: function (a, b) {
  6210. if (null == b)
  6211. return null;
  6212. null == b.__id__ && (b.__id__ = bindId++);
  6213. var c;
  6214. null == a.hx__closures__ ? a.hx__closures__ = {} :
  6215. c = a.hx__closures__[b.__id__];
  6216. null == c && (c = b.bind(a), a.hx__closures__[b.__id__] = c);
  6217. return c
  6218. },
  6219. };
  6220.  
  6221. /**
  6222. * Connects to game objects via the object creation event
  6223. *
  6224. * Подключается к объектам игры через событие создания объекта
  6225. */
  6226. function connectGame() {
  6227. for (let obj of ObjectsList) {
  6228. /**
  6229. * https: //stackoverflow.com/questions/42611719/how-to-intercept-and-modify-a-specific-property-for-any-object
  6230. */
  6231. Object.defineProperty(Object.prototype, obj.prop, {
  6232. set: function (value) {
  6233. if (!selfGame) {
  6234. selfGame = this;
  6235. }
  6236. if (!Game[obj.name]) {
  6237. Game[obj.name] = value;
  6238. }
  6239. // console.log('set ' + obj.prop, this, value);
  6240. this[obj.prop + '_'] = value;
  6241. },
  6242. get: function () {
  6243. // console.log('get ' + obj.prop, this);
  6244. return this[obj.prop + '_'];
  6245. }
  6246. });
  6247. }
  6248. }
  6249.  
  6250. /**
  6251. * Game.BattlePresets
  6252. * @param {bool} a isReplay
  6253. * @param {bool} b autoToggleable
  6254. * @param {bool} c auto On Start
  6255. * @param {object} d config
  6256. * @param {bool} f showBothTeams
  6257. */
  6258. /**
  6259. * Returns the results of the battle to the callback function
  6260. * Возвращает в функцию callback результаты боя
  6261. * @param {*} battleData battle data данные боя
  6262. * @param {*} battleConfig combat configuration type options:
  6263. *
  6264. * тип конфигурации боя варианты:
  6265. *
  6266. * "get_invasion", "get_titanPvpManual", "get_titanPvp",
  6267. * "get_titanClanPvp","get_clanPvp","get_titan","get_boss",
  6268. * "get_tower","get_pve","get_pvpManual","get_pvp","get_core"
  6269. *
  6270. * You can specify the xYc function in the game.assets.storage.BattleAssetStorage class
  6271. *
  6272. * Можно уточнить в классе game.assets.storage.BattleAssetStorage функция xYc
  6273. * @param {*} callback функция в которую вернуться результаты боя
  6274. */
  6275. this.BattleCalc = function (battleData, battleConfig, callback) {
  6276. // battleConfig = battleConfig || getBattleType(battleData.type)
  6277. if (!Game.BattlePresets) throw Error('Use connectGame');
  6278. battlePresets = new Game.BattlePresets(!!battleData.progress, !1, !0, Game.DataStorage[getFn(Game.DataStorage, 24)][getF(Game.BattleConfigStorage, battleConfig)](), !1);
  6279. battleInstantPlay = new Game.BattleInstantPlay(battleData, battlePresets);
  6280. battleInstantPlay[getProtoFn(Game.BattleInstantPlay, 9)].add((battleInstant) => {
  6281. const battleResult = battleInstant[getF(Game.BattleInstantPlay, 'get_result')]();
  6282. const battleData = battleInstant[getF(Game.BattleInstantPlay, 'get_rawBattleInfo')]();
  6283. const battleLog = Game.BattleLogEncoder.read(new Game.BattleLogReader(battleResult[getProtoFn(Game.MultiBattleResult, 2)][0]));
  6284. const timeLimit = battlePresets[getF(Game.BattlePresets, 'get_timeLimit')]();
  6285. const battleTime = Math.max(...battleLog.map((e) => (e.time < timeLimit && e.time !== 168.8 ? e.time : 0)));
  6286. callback({
  6287. battleTime,
  6288. battleData,
  6289. progress: battleResult[getF(Game.MultiBattleResult, 'get_progress')](),
  6290. result: battleResult[getF(Game.MultiBattleResult, 'get_result')]()
  6291. })
  6292. });
  6293. battleInstantPlay.start();
  6294. }
  6295.  
  6296. /**
  6297. * Returns a function with the specified name from the class
  6298. *
  6299. * Возвращает из класса функцию с указанным именем
  6300. * @param {Object} classF Class // класс
  6301. * @param {String} nameF function name // имя функции
  6302. * @param {String} pos name and alias order // порядок имени и псевдонима
  6303. * @returns
  6304. */
  6305. function getF(classF, nameF, pos) {
  6306. pos = pos || false;
  6307. let prop = Object.entries(classF.prototype.__properties__)
  6308. if (!pos) {
  6309. return prop.filter((e) => e[1] == nameF).pop()[0];
  6310. } else {
  6311. return prop.filter((e) => e[0] == nameF).pop()[1];
  6312. }
  6313. }
  6314.  
  6315. /**
  6316. * Returns a function with the specified name from the class
  6317. *
  6318. * Возвращает из класса функцию с указанным именем
  6319. * @param {Object} classF Class // класс
  6320. * @param {String} nameF function name // имя функции
  6321. * @returns
  6322. */
  6323. function getFnP(classF, nameF) {
  6324. let prop = Object.entries(classF.__properties__)
  6325. return prop.filter((e) => e[1] == nameF).pop()[0];
  6326. }
  6327.  
  6328. /**
  6329. * Returns the function name with the specified ordinal from the class
  6330. *
  6331. * Возвращает имя функции с указаным порядковым номером из класса
  6332. * @param {Object} classF Class // класс
  6333. * @param {Number} nF Order number of function // порядковый номер функции
  6334. * @returns
  6335. */
  6336. function getFn(classF, nF) {
  6337. let prop = Object.keys(classF);
  6338. return prop[nF];
  6339. }
  6340.  
  6341. /**
  6342. * Returns the name of the function with the specified serial number from the prototype of the class
  6343. *
  6344. * Возвращает имя функции с указаным порядковым номером из прототипа класса
  6345. * @param {Object} classF Class // класс
  6346. * @param {Number} nF Order number of function // порядковый номер функции
  6347. * @returns
  6348. */
  6349. function getProtoFn(classF, nF) {
  6350. let prop = Object.keys(classF.prototype);
  6351. return prop[nF];
  6352. }
  6353. /**
  6354. * Description of replaced functions
  6355. *
  6356. * Описание подменяемых функций
  6357. */
  6358. replaceFunction = {
  6359. company: function() {
  6360. let PMD_12 = getProtoFn(Game.PlayerMissionData, 12);
  6361. let oldSkipMisson = Game.PlayerMissionData.prototype[PMD_12];
  6362. Game.PlayerMissionData.prototype[PMD_12] = function (a, b, c) {
  6363. if (!isChecked('passBattle')) {
  6364. oldSkipMisson.call(this, a, b, c);
  6365. return;
  6366. }
  6367.  
  6368. try {
  6369. this[getProtoFn(Game.PlayerMissionData, 9)] = new Game.PlayerMissionBattle(a, b, c);
  6370.  
  6371. var a = new Game.BattlePresets(!1, !1, !0, Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](), !1);
  6372. a = new Game.BattleInstantPlay(c, a);
  6373. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6374. a.start()
  6375. } catch (error) {
  6376. console.error('company', error)
  6377. oldSkipMisson.call(this, a, b, c);
  6378. }
  6379. }
  6380.  
  6381. Game.PlayerMissionData.prototype.P$h = function (a) {
  6382. let GM_2 = getFn(Game.GameModel, 2);
  6383. let GM_P2 = getProtoFn(Game.GameModel, 2);
  6384. let CM_20 = getProtoFn(Game.CommandManager, 20);
  6385. let MCL_2 = getProtoFn(Game.MissionCommandList, 2);
  6386. let MBR_15 = getF(Game.MultiBattleResult, "get_result");
  6387. let RPCCB_15 = getProtoFn(Game.RPCCommandBase, 16);
  6388. let PMD_32 = getProtoFn(Game.PlayerMissionData, 32);
  6389. Game.GameModel[GM_2]()[GM_P2][CM_20][MCL_2](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PMD_32]))
  6390. }
  6391. },
  6392. tower: function() {
  6393. let PTD_67 = getProtoFn(Game.PlayerTowerData, 67);
  6394. let oldSkipTower = Game.PlayerTowerData.prototype[PTD_67];
  6395. Game.PlayerTowerData.prototype[PTD_67] = function (a) {
  6396. if (!isChecked('passBattle')) {
  6397. oldSkipTower.call(this, a);
  6398. return;
  6399. }
  6400. try {
  6401. var p = new Game.BattlePresets(!1, !1, !0, Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage,20)](), !1);
  6402. a = new Game.BattleInstantPlay(a, p);
  6403. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6404. a.start()
  6405. } catch (error) {
  6406. console.error('tower', error)
  6407. oldSkipMisson.call(this, a, b, c);
  6408. }
  6409. }
  6410.  
  6411. Game.PlayerTowerData.prototype.P$h = function (a) {
  6412. const GM_2 = getFnP(Game.GameModel, "get_instance");
  6413. const GM_P2 = getProtoFn(Game.GameModel, 2);
  6414. const CM_29 = getProtoFn(Game.CommandManager, 29);
  6415. const TCL_5 = getProtoFn(Game.TowerCommandList, 5);
  6416. const MBR_15 = getF(Game.MultiBattleResult, "get_result");
  6417. const RPCCB_15 = getProtoFn(Game.RPCCommandBase, 17);
  6418. const PTD_78 = getProtoFn(Game.PlayerTowerData, 78);
  6419. Game.GameModel[GM_2]()[GM_P2][CM_29][TCL_5](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PTD_78]));
  6420. }
  6421. },
  6422. // skipSelectHero: function() {
  6423. // if (!HOST) throw Error('Use connectGame');
  6424. // Game.PlayerHeroTeamResolver.prototype[getProtoFn(Game.PlayerHeroTeamResolver, 3)] = () => false;
  6425. // },
  6426. passBattle: function() {
  6427. let BPP_4 = getProtoFn(Game.BattlePausePopup, 4);
  6428. let oldPassBattle = Game.BattlePausePopup.prototype[BPP_4];
  6429. Game.BattlePausePopup.prototype[BPP_4] = function (a) {
  6430. if (!isChecked('passBattle')) {
  6431. oldPassBattle.call(this, a);
  6432. return;
  6433. }
  6434. try {
  6435. Game.BattlePopup.prototype[getProtoFn(Game.BattlePausePopup, 4)].call(this, a);
  6436. this[getProtoFn(Game.BattlePausePopup, 3)]();
  6437. this[getProtoFn(Game.DisplayObjectContainer, 3)](this.clip[getProtoFn(Game.GuiClipContainer, 2)]());
  6438. this.clip[getProtoFn(Game.BattlePausePopupClip, 1)][getProtoFn(Game.ClipLabelBase, 9)](Game.Translate.translate("UI_POPUP_BATTLE_PAUSE"));
  6439.  
  6440. this.clip[getProtoFn(Game.BattlePausePopupClip, 2)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](Game.Translate.translate("UI_POPUP_BATTLE_RETREAT"), (q = this[getProtoFn(Game.BattlePausePopup, 1)], Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 17)])));
  6441. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  6442. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 14)](),
  6443. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 13)]() ?
  6444. (q = this[getProtoFn(Game.BattlePausePopup, 1)], Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)])) :
  6445. (q = this[getProtoFn(Game.BattlePausePopup, 1)], Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  6446. );
  6447.  
  6448. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 0)][getProtoFn(Game.ClipLabelBase, 24)]();
  6449. this.clip[getProtoFn(Game.BattlePausePopupClip, 3)][getProtoFn(Game.SettingToggleButton, 3)](this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 9)]());
  6450. this.clip[getProtoFn(Game.BattlePausePopupClip, 4)][getProtoFn(Game.SettingToggleButton, 3)](this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 10)]());
  6451. this.clip[getProtoFn(Game.BattlePausePopupClip, 6)][getProtoFn(Game.SettingToggleButton, 3)](this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 11)]());
  6452. /*
  6453. Какая-то ненужная фигня
  6454. if (!HC.lSb()) {
  6455. this.clip.r6b.g().B(!1);
  6456. a = this.clip.r6b.g().X() + 7;
  6457. var b = this.clip.ba.g();
  6458. b.$(b.X() - a);
  6459. b = this.clip.IS.g();
  6460. b.sa(b.Fa() - a)
  6461. }
  6462. */
  6463. } catch(error) {
  6464. console.error('passBattle', error)
  6465. oldPassBattle.call(this, a);
  6466. }
  6467. }
  6468.  
  6469. let retreatButtonLabel = getF(Game.BattlePausePopupMediator, "get_retreatButtonLabel");
  6470. let oldFunc = Game.BattlePausePopupMediator.prototype[retreatButtonLabel];
  6471. Game.BattlePausePopupMediator.prototype[retreatButtonLabel] = function () {
  6472. if (isChecked('passBattle')) {
  6473. return I18N('BTN_PASS');
  6474. } else {
  6475. return oldFunc.call(this);
  6476. }
  6477. }
  6478. },
  6479. endlessCards: function() {
  6480. let PDD_20 = getProtoFn(Game.PlayerDungeonData, 20);
  6481. let oldEndlessCards = Game.PlayerDungeonData.prototype[PDD_20];
  6482. Game.PlayerDungeonData.prototype[PDD_20] = function () {
  6483. if (countPredictionCard <= 0) {
  6484. return true;
  6485. } else {
  6486. return oldEndlessCards.call(this);
  6487. }
  6488. }
  6489. },
  6490. speedBattle: function () {
  6491. const get_timeScale = getF(Game.BattleController, "get_timeScale");
  6492. const oldSpeedBattle = Game.BattleController.prototype[get_timeScale];
  6493. Game.BattleController.prototype[get_timeScale] = function () {
  6494. const speedBattle = Number.parseFloat(getInput('speedBattle'));
  6495. if (!speedBattle) {
  6496. return oldSpeedBattle.call(this);
  6497. }
  6498. try {
  6499. const BC_12 = getProtoFn(Game.BattleController, 12);
  6500. const BSM_12 = getProtoFn(Game.BattleSettingsModel, 12);
  6501. const BP_get_value = getF(Game.BooleanProperty, "get_value");
  6502. if (this[BC_12][BSM_12][BP_get_value]()) {
  6503. return 0;
  6504. }
  6505. const BSM_2 = getProtoFn(Game.BattleSettingsModel, 2);
  6506. const BC_49 = getProtoFn(Game.BattleController, 49);
  6507. const BSM_1 = getProtoFn(Game.BattleSettingsModel, 1);
  6508. const BC_14 = getProtoFn(Game.BattleController, 14);
  6509. const BC_3 = getFn(Game.BattleController, 3);
  6510. if (this[BC_12][BSM_2][BP_get_value]()) {
  6511. var a = speedBattle * this[BC_49]();
  6512. } else {
  6513. a = this[BC_12][BSM_1][BP_get_value]();
  6514. const maxSpeed = Math.max(...this[BC_14]);
  6515. const multiple = a == this[BC_14].indexOf(maxSpeed) ? (maxSpeed >= 4 ? speedBattle : this[BC_14][a]) : this[BC_14][a];
  6516. a = multiple * Game.BattleController[BC_3][BP_get_value]() * this[BC_49]();
  6517. }
  6518. const BSM_24 = getProtoFn(Game.BattleSettingsModel, 24);
  6519. a > this[BC_12][BSM_24][BP_get_value]() && (a = this[BC_12][BSM_24][BP_get_value]());
  6520. const DS_23 = getFn(Game.DataStorage, 23);
  6521. const get_battleSpeedMultiplier = getF(Game.RuleStorage, "get_battleSpeedMultiplier", true);
  6522. // const RS_167 = getProtoFn(Game.RuleStorage, 167); // get_battleSpeedMultiplier
  6523. var b = Game.DataStorage[DS_23][get_battleSpeedMultiplier]();
  6524. const R_1 = getFn(selfGame.Reflect, 1);
  6525. const BC_1 = getFn(Game.BattleController, 1);
  6526. const get_config = getF(Game.BattlePresets, "get_config");
  6527. // const BC_0 = getProtoFn(Game.BattleConfig, 0); // .ident
  6528. null != b && (a = selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident) ? a * selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident) : a * selfGame.Reflect[R_1](b, "default"));
  6529. return a
  6530. } catch(error) {
  6531. console.error('passBatspeedBattletle', error)
  6532. return oldSpeedBattle.call(this);
  6533. }
  6534. }
  6535. },
  6536.  
  6537. /**
  6538. * Acceleration button without Valkyries favor
  6539. *
  6540. * Кнопка ускорения без Покровительства Валькирий
  6541. */
  6542. battleFastKey: function () {
  6543. const PSIVO_9 = getProtoFn(Game.PlayerSubscriptionInfoValueObject, 9);
  6544. const oldBattleFastKey = Game.PlayerSubscriptionInfoValueObject.prototype[PSIVO_9];
  6545. Game.PlayerSubscriptionInfoValueObject.prototype[PSIVO_9] = function () {
  6546. //const BGM_42 = getProtoFn(Game.BattleGuiMediator, 42);
  6547. //const oldBattleFastKey = Game.BattleGuiMediator.prototype[BGM_42];
  6548. //Game.BattleGuiMediator.prototype[BGM_42] = function () {
  6549. let flag = true;
  6550. //console.log(flag)
  6551. if (flag) {
  6552. return true;
  6553. } else {
  6554. return oldBattleFastKey.call(this);
  6555. }
  6556. /*
  6557. if (!flag) {
  6558. return oldBattleFastKey.call(this);
  6559. }
  6560. try {
  6561. const BGM_9 = getProtoFn(Game.BattleGuiMediator, 9);
  6562. const BGM_10 = getProtoFn(Game.BattleGuiMediator, 10);
  6563. const BPW_0 = getProtoFn(Game.BooleanPropertyWriteable, 0);
  6564. this[BGM_9][BPW_0](true);
  6565. this[BGM_10][BPW_0](true);
  6566. } catch (error) {
  6567. console.error(error);
  6568. return oldBattleFastKey.call(this);
  6569. }*/
  6570. }
  6571. },
  6572. /* ТЕСТ 2.240
  6573. battleFastKey: function () {
  6574. const BGM_43 = getProtoFn(Game.BattleGuiMediator, 43);
  6575. const oldBattleFastKey = Game.BattleGuiMediator.prototype[BGM_43];
  6576. Game.BattleGuiMediator.prototype[BGM_43] = function () {
  6577. let flag = true;
  6578. //console.log(flag)
  6579. if (!flag) {
  6580. return oldBattleFastKey.call(this);
  6581. }
  6582. try {
  6583. const BGM_9 = getProtoFn(Game.BattleGuiMediator, 9);
  6584. const BGM_10 = getProtoFn(Game.BattleGuiMediator, 10);
  6585. const BPW_0 = getProtoFn(Game.BooleanPropertyWriteable, 0);
  6586. this[BGM_9][BPW_0](true);
  6587. this[BGM_10][BPW_0](true);
  6588. } catch (error) {
  6589. console.error(error);
  6590. return oldBattleFastKey.call(this);
  6591. }
  6592. }
  6593. },*/
  6594. fastSeason: function () {
  6595. const GameNavigator = selfGame["game.screen.navigator.GameNavigator"];
  6596. const oldFuncName = getProtoFn(GameNavigator, 16);
  6597. const newFuncName = getProtoFn(GameNavigator, 14);
  6598. const oldFastSeason = GameNavigator.prototype[oldFuncName];
  6599. const newFastSeason = GameNavigator.prototype[newFuncName];
  6600. GameNavigator.prototype[oldFuncName] = function (a, b) {
  6601. if (isChecked('fastSeason')) {
  6602. return newFastSeason.apply(this, [a]);
  6603. } else {
  6604. return oldFastSeason.apply(this, [a, b]);
  6605. }
  6606. }
  6607. },
  6608. ShowChestReward: function () {
  6609. const TitanArtifactChest = selfGame["game.mechanics.titan_arena.mediator.chest.TitanArtifactChestRewardPopupMediator"];
  6610. const getOpenAmountTitan = getF(TitanArtifactChest, "get_openAmount");
  6611. const oldGetOpenAmountTitan = TitanArtifactChest.prototype[getOpenAmountTitan];
  6612. TitanArtifactChest.prototype[getOpenAmountTitan] = function () {
  6613. if (correctShowOpenArtifact) {
  6614. correctShowOpenArtifact--;
  6615. return 100;
  6616. }
  6617. return oldGetOpenAmountTitan.call(this);
  6618. }
  6619.  
  6620. const ArtifactChest = selfGame["game.view.popup.artifactchest.rewardpopup.ArtifactChestRewardPopupMediator"];
  6621. const getOpenAmount = getF(ArtifactChest, "get_openAmount");
  6622. const oldGetOpenAmount = ArtifactChest.prototype[getOpenAmount];
  6623. ArtifactChest.prototype[getOpenAmount] = function () {
  6624. if (correctShowOpenArtifact) {
  6625. correctShowOpenArtifact--;
  6626. return 100;
  6627. }
  6628. return oldGetOpenAmount.call(this);
  6629. }
  6630.  
  6631. },
  6632. fixCompany: function () {
  6633. const GameBattleView = selfGame["game.mediator.gui.popup.battle.GameBattleView"];
  6634. const BattleThread = selfGame["game.battle.controller.thread.BattleThread"];
  6635. const getOnViewDisposed = getF(BattleThread, 'get_onViewDisposed');
  6636. const getThread = getF(GameBattleView, 'get_thread');
  6637. const oldFunc = GameBattleView.prototype[getThread];
  6638. GameBattleView.prototype[getThread] = function () {
  6639. return oldFunc.call(this) || {
  6640. [getOnViewDisposed]: async () => { }
  6641. }
  6642. }
  6643. }
  6644. }
  6645.  
  6646. /**
  6647. * Starts replacing recorded functions
  6648. *
  6649. * Запускает замену записанных функций
  6650. */
  6651. this.activateHacks = function () {
  6652. if (!selfGame) throw Error('Use connectGame');
  6653. for (let func in replaceFunction) {
  6654. replaceFunction[func]();
  6655. }
  6656. }
  6657.  
  6658. /**
  6659. * Returns the game object
  6660. *
  6661. * Возвращает объект игры
  6662. */
  6663. this.getSelfGame = function () {
  6664. return selfGame;
  6665. }
  6666.  
  6667. /**
  6668. * Updates game data
  6669. *
  6670. * Обновляет данные игры
  6671. */
  6672. this.refreshGame = function () {
  6673. (new Game.NextDayUpdatedManager)[getProtoFn(Game.NextDayUpdatedManager, 5)]();
  6674. try {
  6675. cheats.refreshInventory();
  6676. } catch (e) { }
  6677. }
  6678.  
  6679. /**
  6680. * Update inventory
  6681. *
  6682. * Обновляет инвентарь
  6683. */
  6684. this.refreshInventory = async function () {
  6685. const GM_INST = getFnP(Game.GameModel, "get_instance");
  6686. const GM_0 = getProtoFn(Game.GameModel, 0);
  6687. const P_24 = getProtoFn(selfGame["game.model.user.Player"], 24);
  6688. const Player = Game.GameModel[GM_INST]()[GM_0];
  6689. Player[P_24] = new selfGame["game.model.user.inventory.PlayerInventory"]
  6690. Player[P_24].init(await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"}]}').then(e => e.results[0].result.response))
  6691. }
  6692.  
  6693. /**
  6694. * Change the play screen on windowName
  6695. *
  6696. * Сменить экран игры на windowName
  6697. *
  6698. * Possible options:
  6699. *
  6700. * Возможные варианты:
  6701. *
  6702. * 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
  6703. */
  6704. this.goNavigtor = function (windowName) {
  6705. let mechanicStorage = selfGame["game.data.storage.mechanic.MechanicStorage"];
  6706. let window = mechanicStorage[windowName];
  6707. let event = new selfGame["game.mediator.gui.popup.PopupStashEventParams"];
  6708. let Game = selfGame['Game'];
  6709. let navigator = getF(Game, "get_navigator")
  6710. let navigate = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 18)
  6711. let instance = getFnP(Game, 'get_instance');
  6712. Game[instance]()[navigator]()[navigate](window, event);
  6713. }
  6714.  
  6715. /**
  6716. * Move to the sanctuary cheats.goSanctuary()
  6717. *
  6718. * Переместиться в святилище cheats.goSanctuary()
  6719. */
  6720. this.goSanctuary = () => {
  6721. this.goNavigtor("SANCTUARY");
  6722. }
  6723.  
  6724. /**
  6725. * Go to Guild War
  6726. *
  6727. * Перейти к Войне Гильдий
  6728. */
  6729. this.goClanWar = function() {
  6730. let instance = getFnP(Game.GameModel, 'get_instance')
  6731. let player = Game.GameModel[instance]().A;
  6732. let clanWarSelect = selfGame["game.mechanics.cross_clan_war.popup.selectMode.CrossClanWarSelectModeMediator"];
  6733. new clanWarSelect(player).open();
  6734. }
  6735.  
  6736. /**
  6737. * Go to BrawlShop
  6738. *
  6739. * Переместиться в BrawlShop
  6740. */
  6741. this.goBrawlShop = () => {
  6742. const instance = getFnP(Game.GameModel, 'get_instance')
  6743. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  6744. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  6745. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  6746. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  6747.  
  6748. const player = Game.GameModel[instance]().A;
  6749. const shop = player[P_36][PSD_0][IM_0][1038][PSDE_4];
  6750. const shopPopup = new selfGame["game.mechanics.brawl.mediator.BrawlShopPopupMediator"](player, shop)
  6751. shopPopup.open(new selfGame["game.mediator.gui.popup.PopupStashEventParams"])
  6752. }
  6753.  
  6754. /**
  6755. * Returns all stores from game data
  6756. *
  6757. * Возвращает все магазины из данных игры
  6758. */
  6759. this.getShops = () => {
  6760. const instance = getFnP(Game.GameModel, 'get_instance')
  6761. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  6762. const PSD_0 = getProtoFn(selfGame["game.model.user.shop.PlayerShopData"], 0);
  6763. const IM_0 = getProtoFn(selfGame["haxe.ds.IntMap"], 0);
  6764.  
  6765. const player = Game.GameModel[instance]().A;
  6766. return player[P_36][PSD_0][IM_0];
  6767. }
  6768.  
  6769. /**
  6770. * Returns the store from the game data by ID
  6771. *
  6772. * Возвращает магазин из данных игры по идетификатору
  6773. */
  6774. this.getShop = (id) => {
  6775. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  6776. const shops = this.getShops();
  6777. const shop = shops[id]?.[PSDE_4];
  6778. return shop;
  6779. }
  6780.  
  6781. /**
  6782. * Moves to the store with the specified ID
  6783. *
  6784. * Перемещает к магазину с указанным идетификатором
  6785. */
  6786. this.goShopId = function (id) {
  6787. const shop = this.getShop(id);
  6788. if (!shop) {
  6789. return;
  6790. }
  6791. let event = new selfGame["game.mediator.gui.popup.PopupStashEventParams"];
  6792. let Game = selfGame['Game'];
  6793. let navigator = getF(Game, "get_navigator");
  6794. let navigate = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 21);
  6795. let instance = getFnP(Game, 'get_instance');
  6796. Game[instance]()[navigator]()[navigate](shop, event);
  6797. }
  6798.  
  6799. /**
  6800. * Opens a list of non-standard stores
  6801. *
  6802. * Открывает список не стандартных магазинов
  6803. */
  6804. this.goCustomShops = async (p = 0) => {
  6805. /** Запрос данных нужных магазинов */
  6806. const calls = [{ name: "shopGetAll", args: {}, ident: "shopGetAll" }];
  6807. const shops = lib.getData('shop');
  6808. for (const id in shops) {
  6809. const check = !shops[id].ident.includes('merchantPromo') &&
  6810. ![1, 4, 5, 6, 7, 8, 9, 10, 11, 1023, 1024].includes(+id);
  6811. if (check) {
  6812. calls.push({
  6813. name: "shopGet", args: { shopId: id }, ident: `shopGet_${id}`
  6814. })
  6815. }
  6816. }
  6817. const result = await Send({ calls }).then(e => e.results.map(n => n.result.response));
  6818. const shopAll = result.shift();
  6819. const DS_32 = getFn(Game.DataStorage, 32)
  6820.  
  6821. const SDS_5 = getProtoFn(selfGame["game.data.storage.shop.ShopDescriptionStorage"], 5)
  6822.  
  6823. const SD_21 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 21);
  6824. const SD_1 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 1);
  6825. const SD_9 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 9);
  6826. const ident = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 11);
  6827.  
  6828. for (let shop of result) {
  6829. shopAll[shop.id] = shop;
  6830. // Снимаем все ограничения с магазинов
  6831. const shopLibData = Game.DataStorage[DS_32][SDS_5](shop.id)
  6832. shopLibData[SD_21] = 1;
  6833. shopLibData[SD_1] = new selfGame["game.model.user.requirement.Requirement"]
  6834. shopLibData[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  6835. teamLevel: 10
  6836. });
  6837. }
  6838. /** Скрываем все остальные магазины */
  6839. for (let id in shops) {
  6840. const shopLibData = Game.DataStorage[DS_32][SDS_5](id)
  6841. if (shopLibData[ident].includes('merchantPromo')) {
  6842. shopLibData[SD_21] = 0;
  6843. shopLibData[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  6844. teamLevel: 999
  6845. });
  6846. }
  6847. }
  6848.  
  6849. const instance = getFnP(Game.GameModel, 'get_instance')
  6850. const GM_0 = getProtoFn(Game.GameModel, 0);
  6851. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  6852. const player = Game.GameModel[instance]()[GM_0];
  6853. /** Пересоздаем объект с магазинами */
  6854. player[P_36] = new selfGame["game.model.user.shop.PlayerShopData"](player);
  6855. player[P_36].init(shopAll);
  6856. /** Даем магазинам новые названия */
  6857. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  6858.  
  6859. const shopName = getFn(cheats.getShop(1), 14);
  6860. const currentShops = this.getShops();
  6861. let count = 0;
  6862. const start = 9 * p + 1;
  6863. const end = start + 8;
  6864. for (let id in currentShops) {
  6865. const shop = currentShops[id][PSDE_4];
  6866. if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  6867. /** Скрываем стандартные магазины */
  6868. shop[SD_21] = 0;
  6869. } else {
  6870. count++;
  6871. if (count < start || count > end) {
  6872. shop[SD_21] = 0;
  6873. continue;
  6874. }
  6875. shop[SD_21] = 1;
  6876. shop[shopName] = cheats.translate("LIB_SHOP_NAME_" + id) + ' ' + id;
  6877. shop[SD_1] = new selfGame["game.model.user.requirement.Requirement"]
  6878. shop[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  6879. teamLevel: 10
  6880. });
  6881. }
  6882. }
  6883. console.log(count, start, end)
  6884. /** Отправляемся в городскую лавку */
  6885. this.goShopId(1);
  6886. }
  6887.  
  6888. /**
  6889. * Opens a list of standard stores
  6890. *
  6891. * Открывает список стандартных магазинов
  6892. */
  6893. this.goDefaultShops = async () => {
  6894. const result = await Send({ calls: [{ name: "shopGetAll", args: {}, ident: "shopGetAll" }] })
  6895. .then(e => e.results.map(n => n.result.response));
  6896. const shopAll = result.shift();
  6897. const shops = lib.getData('shop');
  6898.  
  6899. const DS_8 = getFn(Game.DataStorage, 8)
  6900. const DSB_4 = getProtoFn(selfGame["game.data.storage.DescriptionStorageBase"], 4)
  6901.  
  6902. /** Получаем объект валюты магазина для оторажения */
  6903. const coins = Game.DataStorage[DS_8][DSB_4](85);
  6904. coins.__proto__ = selfGame["game.data.storage.resource.ConsumableDescription"].prototype;
  6905.  
  6906. const DS_32 = getFn(Game.DataStorage, 32)
  6907. const SDS_5 = getProtoFn(selfGame["game.data.storage.shop.ShopDescriptionStorage"], 5)
  6908.  
  6909. const SD_21 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 21);
  6910. for (const id in shops) {
  6911. const shopLibData = Game.DataStorage[DS_32][SDS_5](id)
  6912. if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  6913. shopLibData[SD_21] = 1;
  6914. } else {
  6915. shopLibData[SD_21] = 0;
  6916. }
  6917. }
  6918.  
  6919. const instance = getFnP(Game.GameModel, 'get_instance')
  6920. const GM_0 = getProtoFn(Game.GameModel, 0);
  6921. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  6922. const player = Game.GameModel[instance]()[GM_0];
  6923. /** Пересоздаем объект с магазинами */
  6924. player[P_36] = new selfGame["game.model.user.shop.PlayerShopData"](player);
  6925. player[P_36].init(shopAll);
  6926.  
  6927. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  6928. const currentShops = this.getShops();
  6929. for (let id in currentShops) {
  6930. const shop = currentShops[id][PSDE_4];
  6931. if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  6932. shop[SD_21] = 1;
  6933. } else {
  6934. shop[SD_21] = 0;
  6935. }
  6936. }
  6937. this.goShopId(1);
  6938. }
  6939.  
  6940. /**
  6941. * Opens a list of Secret Wealth stores
  6942. *
  6943. * Открывает список магазинов Тайное богатство
  6944. */
  6945. this.goSecretWealthShops = async () => {
  6946. /** Запрос данных нужных магазинов */
  6947. const calls = [{ name: "shopGetAll", args: {}, ident: "shopGetAll" }];
  6948. const shops = lib.getData('shop');
  6949. for (const id in shops) {
  6950. if (shops[id].ident.includes('merchantPromo') && shops[id].teamLevelToUnlock <= 130) {
  6951. calls.push({
  6952. name: "shopGet", args: { shopId: id }, ident: `shopGet_${id}`
  6953. })
  6954. }
  6955. }
  6956. const result = await Send({ calls }).then(e => e.results.map(n => n.result.response));
  6957. const shopAll = result.shift();
  6958. const DS_32 = getFn(Game.DataStorage, 32)
  6959.  
  6960. const SDS_5 = getProtoFn(selfGame["game.data.storage.shop.ShopDescriptionStorage"], 5)
  6961.  
  6962. const SD_21 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 21);
  6963. const SD_1 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 1);
  6964. const SD_9 = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 9);
  6965. const ident = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 11);
  6966. const specialCurrency = getProtoFn(selfGame["game.data.storage.shop.ShopDescription"], 15);
  6967.  
  6968. const DS_8 = getFn(Game.DataStorage, 8)
  6969. const DSB_4 = getProtoFn(selfGame["game.data.storage.DescriptionStorageBase"], 4)
  6970.  
  6971. /** Получаем объект валюты магазина для оторажения */
  6972. const coins = Game.DataStorage[DS_8][DSB_4](85);
  6973. coins.__proto__ = selfGame["game.data.storage.resource.CoinDescription"].prototype;
  6974.  
  6975. for (let shop of result) {
  6976. shopAll[shop.id] = shop;
  6977. /** Снимаем все ограничения с магазинов */
  6978. const shopLibData = Game.DataStorage[DS_32][SDS_5](shop.id)
  6979. if (shopLibData[ident].includes('merchantPromo')) {
  6980. shopLibData[SD_21] = 1;
  6981. shopLibData[SD_1] = new selfGame["game.model.user.requirement.Requirement"]
  6982. shopLibData[SD_9] = new selfGame["game.data.storage.level.LevelRequirement"]({
  6983. teamLevel: 10
  6984. });
  6985. }
  6986. }
  6987.  
  6988. /** Скрываем все остальные магазины */
  6989. for (let id in shops) {
  6990. const shopLibData = Game.DataStorage[DS_32][SDS_5](id)
  6991. if (!shopLibData[ident].includes('merchantPromo')) {
  6992. shopLibData[SD_21] = 0;
  6993. }
  6994. }
  6995.  
  6996. const instance = getFnP(Game.GameModel, 'get_instance')
  6997. const GM_0 = getProtoFn(Game.GameModel, 0);
  6998. const P_36 = getProtoFn(selfGame["game.model.user.Player"], 36);
  6999. const player = Game.GameModel[instance]()[GM_0];
  7000. /** Пересоздаем объект с магазинами */
  7001. player[P_36] = new selfGame["game.model.user.shop.PlayerShopData"](player);
  7002. player[P_36].init(shopAll);
  7003. /** Даем магазинам новые названия */
  7004. const PSDE_4 = getProtoFn(selfGame["game.model.user.shop.PlayerShopDataEntry"], 4);
  7005.  
  7006. const shopName = getFn(cheats.getShop(1), 14);
  7007. const currentShops = this.getShops();
  7008. for (let id in currentShops) {
  7009. const shop = currentShops[id][PSDE_4];
  7010. if (shop[ident].includes('merchantPromo')) {
  7011. shop[SD_21] = 1;
  7012. shop[specialCurrency] = coins;
  7013. shop[shopName] = cheats.translate("LIB_SHOP_NAME_" + id) + ' ' + id;
  7014. } else if ([1, 4, 5, 6, 8, 9, 10, 11].includes(+id)) {
  7015. /** Скрываем стандартные магазины */
  7016. shop[SD_21] = 0;
  7017. }
  7018. }
  7019. /** Отправляемся в городскую лавку */
  7020. this.goShopId(1);
  7021. }
  7022.  
  7023. /**
  7024. * Change island map
  7025. *
  7026. * Сменить карту острова
  7027. */
  7028. this.changeIslandMap = (mapId = 2) => {
  7029. const GameInst = getFnP(selfGame['Game'], 'get_instance');
  7030. const GM_0 = getProtoFn(Game.GameModel, 0);
  7031. const P_59 = getProtoFn(selfGame["game.model.user.Player"], 59);
  7032. const Player = Game.GameModel[GameInst]()[GM_0];
  7033. Player[P_59].$({ id: mapId, seasonAdventure: { id: mapId, startDate: 1701914400, endDate: 1709690400, closed: false } });
  7034.  
  7035. const GN_15 = getProtoFn(selfGame["game.screen.navigator.GameNavigator"], 15)
  7036. const navigator = getF(selfGame['Game'], "get_navigator");
  7037. selfGame['Game'][GameInst]()[navigator]()[GN_15](new selfGame["game.mediator.gui.popup.PopupStashEventParams"]);
  7038. }
  7039.  
  7040. /**
  7041. * Game library availability tracker
  7042. *
  7043. * Отслеживание доступности игровой библиотеки
  7044. */
  7045. function checkLibLoad() {
  7046. timeout = setTimeout(() => {
  7047. if (Game.GameModel) {
  7048. changeLib();
  7049. } else {
  7050. checkLibLoad();
  7051. }
  7052. }, 100)
  7053. }
  7054.  
  7055. /**
  7056. * Game library data spoofing
  7057. *
  7058. * Подмена данных игровой библиотеки
  7059. */
  7060. function changeLib() {
  7061. console.log('lib connect');
  7062. const originalStartFunc = Game.GameModel.prototype.start;
  7063. Game.GameModel.prototype.start = function (a, b, c) {
  7064. self.libGame = b.raw;
  7065. try {
  7066. const levels = b.raw.seasonAdventure.level;
  7067. for (const id in levels) {
  7068. const level = levels[id];
  7069. level.clientData.graphics.fogged = level.clientData.graphics.visible
  7070. }
  7071. // b.raw.shop[26].requirements = null;
  7072. // b.raw.shop[28].requirements = null;
  7073. // b.raw.shop[29].requirements = null;
  7074. } catch (e) {
  7075. console.warn(e);
  7076. }
  7077. originalStartFunc.call(this, a, b, c);
  7078. }
  7079. }
  7080.  
  7081. /**
  7082. * Returns the value of a language constant
  7083. *
  7084. * Возвращает значение языковой константы
  7085. * @param {*} langConst language constant // языковая константа
  7086. * @returns
  7087. */
  7088. this.translate = function (langConst) {
  7089. return Game.Translate.translate(langConst);
  7090. }
  7091.  
  7092. connectGame();
  7093. checkLibLoad();
  7094. }
  7095.  
  7096. /**
  7097. * Auto collection of gifts
  7098. *
  7099. * Автосбор подарков
  7100. */
  7101. function getAutoGifts() {
  7102. let valName = 'giftSendIds_' + userInfo.id;
  7103.  
  7104. if (!localStorage['clearGift' + userInfo.id]) {
  7105. localStorage[valName] = '';
  7106. localStorage['clearGift' + userInfo.id] = '+';
  7107. }
  7108.  
  7109. if (!localStorage[valName]) {
  7110. localStorage[valName] = '';
  7111. }
  7112.  
  7113. const now = Date.now();
  7114. const body = JSON.stringify({ now });
  7115. const signature = window['\x73\x69\x67\x6e'](now);
  7116. /**
  7117. * Submit a request to receive gift codes
  7118. *
  7119. * Отправка запроса для получения кодов подарков
  7120. */
  7121. fetch('https://zingery.ru/heroes/getGifts.php', {
  7122. method: 'POST',
  7123. headers: {
  7124. 'X-Request-Signature': signature,
  7125. 'X-Script-Name': GM_info.script.name,
  7126. 'X-Script-Version': GM_info.script.version,
  7127. 'X-Script-Author': GM_info.script.author,
  7128. },
  7129. body
  7130. }).then(
  7131. response => response.json()
  7132. ).then(
  7133. data => {
  7134. let freebieCheckCalls = {
  7135. calls: []
  7136. }
  7137. data.forEach((giftId, n) => {
  7138. if (localStorage[valName].includes(giftId)) return;
  7139. //localStorage[valName] += ';' + giftId;
  7140. freebieCheckCalls.calls.push({
  7141. name: "registration",
  7142. args: {
  7143. user: { referrer: {} },
  7144. giftId
  7145. },
  7146. context: {
  7147. actionTs: Math.floor(performance.now()),
  7148. cookie: window?.NXAppInfo?.session_id || null
  7149. },
  7150. ident: giftId
  7151. });
  7152. });
  7153.  
  7154. if (!freebieCheckCalls.calls.length) {
  7155. return;
  7156. }
  7157.  
  7158. send(JSON.stringify(freebieCheckCalls), e => {
  7159. let countGetGifts = 0;
  7160. const gifts = [];
  7161. for (check of e.results) {
  7162. gifts.push(check.ident);
  7163. if (check.result.response != null) {
  7164. countGetGifts++;
  7165. }
  7166. }
  7167. const saveGifts = localStorage[valName].split(';');
  7168. localStorage[valName] = [...saveGifts, ...gifts].slice(-50).join(';');
  7169. console.log(`${I18N('GIFTS')}: ${countGetGifts}`);
  7170. });
  7171. }
  7172. )
  7173. }
  7174.  
  7175. async function getGiftCode() {
  7176. return null;
  7177. const isWrite = false;
  7178. let data = null;
  7179. try {
  7180. data = await fetch('https://zingery.ru/heroes/getGifts.php', {
  7181. method: 'POST',
  7182. body: JSON.stringify({ isWrite })
  7183. }).then(response => response.json());
  7184. } catch(e) {
  7185. return null;
  7186. }
  7187.  
  7188. const valName = 'newGiftSendIds';
  7189. if (!localStorage[valName]) {
  7190. localStorage[valName] = '';
  7191. }
  7192. const saveGifts = localStorage[valName].split(';');
  7193.  
  7194. while (data.length) {
  7195. let giftId = data.pop()
  7196. if (!localStorage[valName].includes(giftId)) {
  7197. saveGifts.push(giftId);
  7198. localStorage[valName] = saveGifts.slice(-50).join(';');
  7199. return giftId;
  7200. }
  7201. }
  7202. return null;
  7203. }
  7204.  
  7205. /**
  7206. * To fill the kills in the Forge of Souls
  7207. *
  7208. * Набить килов в горниле душ
  7209. */
  7210. async function bossRatingEvent() {
  7211. const topGet = await Send(JSON.stringify({ calls: [{ name: "topGet", args: { type: "bossRatingTop", extraId: 0 }, ident: "body" }] }));
  7212. if (!topGet || !topGet.results[0].result.response[0]) {
  7213. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7214. return;
  7215. }
  7216. const replayId = topGet.results[0].result.response[0].userData.replayId;
  7217. const result = await Send(JSON.stringify({
  7218. calls: [
  7219. { name: "battleGetReplay", args: { id: replayId }, ident: "battleGetReplay" },
  7220. { name: "heroGetAll", args: {}, ident: "heroGetAll" },
  7221. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  7222. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  7223. ]
  7224. }));
  7225. const bossEventInfo = result.results[3].result.response.find(e => e.offerType == "bossEvent");
  7226. if (!bossEventInfo) {
  7227. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7228. return;
  7229. }
  7230. const usedHeroes = bossEventInfo.progress.usedHeroes;
  7231. const party = Object.values(result.results[0].result.response.replay.attackers);
  7232. const availableHeroes = Object.values(result.results[1].result.response).map(e => e.id);
  7233. const availablePets = Object.values(result.results[2].result.response).map(e => e.id);
  7234. const calls = [];
  7235. /**
  7236. * First pack
  7237. *
  7238. * Первая пачка
  7239. */
  7240. const args = {
  7241. heroes: [],
  7242. favor: {}
  7243. }
  7244. for (let hero of party) {
  7245. if (hero.id >= 6000 && availablePets.includes(hero.id)) {
  7246. args.pet = hero.id;
  7247. continue;
  7248. }
  7249. if (!availableHeroes.includes(hero.id) || usedHeroes.includes(hero.id)) {
  7250. continue;
  7251. }
  7252. args.heroes.push(hero.id);
  7253. if (hero.favorPetId) {
  7254. args.favor[hero.id] = hero.favorPetId;
  7255. }
  7256. }
  7257. if (args.heroes.length) {
  7258. calls.push({
  7259. name: "bossRatingEvent_startBattle",
  7260. args,
  7261. ident: "body_0"
  7262. });
  7263. }
  7264. /**
  7265. * Other packs
  7266. *
  7267. * Другие пачки
  7268. */
  7269. let heroes = [];
  7270. let count = 1;
  7271. while (heroId = availableHeroes.pop()) {
  7272. if (args.heroes.includes(heroId) || usedHeroes.includes(heroId)) {
  7273. continue;
  7274. }
  7275. heroes.push(heroId);
  7276. if (heroes.length == 5) {
  7277. calls.push({
  7278. name: "bossRatingEvent_startBattle",
  7279. args: {
  7280. heroes: [...heroes],
  7281. pet: availablePets[Math.floor(Math.random() * availablePets.length)]
  7282. },
  7283. ident: "body_" + count
  7284. });
  7285. heroes = [];
  7286. count++;
  7287. }
  7288. }
  7289.  
  7290. if (!calls.length) {
  7291. setProgress(`${I18N('NO_HEROES')}`, true);
  7292. return;
  7293. }
  7294.  
  7295. const resultBattles = await Send(JSON.stringify({ calls }));
  7296. console.log(resultBattles);
  7297. rewardBossRatingEvent();
  7298. }
  7299.  
  7300. /**
  7301. * Collecting Rewards from the Forge of Souls
  7302. *
  7303. * Сбор награды из Горнила Душ
  7304. */
  7305. function rewardBossRatingEvent() {
  7306. let rewardBossRatingCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  7307. send(rewardBossRatingCall, function (data) {
  7308. let bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  7309. if (!bossEventInfo) {
  7310. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7311. return;
  7312. }
  7313.  
  7314. let farmedChests = bossEventInfo.progress.farmedChests;
  7315. let score = bossEventInfo.progress.score;
  7316. setProgress(`${I18N('DAMAGE_AMOUNT')}: ${score}`);
  7317. let revard = bossEventInfo.reward;
  7318.  
  7319. let getRewardCall = {
  7320. calls: []
  7321. }
  7322.  
  7323. let count = 0;
  7324. for (let i = 1; i < 10; i++) {
  7325. if (farmedChests.includes(i)) {
  7326. continue;
  7327. }
  7328. if (score < revard[i].score) {
  7329. break;
  7330. }
  7331. getRewardCall.calls.push({
  7332. name: "bossRatingEvent_getReward",
  7333. args: {
  7334. rewardId: i
  7335. },
  7336. ident: "body_" + i
  7337. });
  7338. count++;
  7339. }
  7340. if (!count) {
  7341. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  7342. return;
  7343. }
  7344.  
  7345. send(JSON.stringify(getRewardCall), e => {
  7346. console.log(e);
  7347. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  7348. });
  7349. });
  7350. }
  7351.  
  7352. /**
  7353. * Collect Easter eggs and event rewards
  7354. *
  7355. * Собрать пасхалки и награды событий
  7356. */
  7357. function offerFarmAllReward() {
  7358. const offerGetAllCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  7359. return Send(offerGetAllCall).then((data) => {
  7360. const offerGetAll = data.results[0].result.response.filter(e => e.type == "reward" && !e?.freeRewardObtained && e.reward);
  7361. if (!offerGetAll.length) {
  7362. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  7363. return;
  7364. }
  7365.  
  7366. const calls = [];
  7367. for (let reward of offerGetAll) {
  7368. calls.push({
  7369. name: "offerFarmReward",
  7370. args: {
  7371. offerId: reward.id
  7372. },
  7373. ident: "offerFarmReward_" + reward.id
  7374. });
  7375. }
  7376.  
  7377. return Send(JSON.stringify({ calls })).then(e => {
  7378. console.log(e);
  7379. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  7380. });
  7381. });
  7382. }
  7383.  
  7384. /**
  7385. * Assemble Outland
  7386. *
  7387. * Собрать запределье
  7388. */
  7389. function getOutland() {
  7390. return new Promise(function (resolve, reject) {
  7391. send('{"calls":[{"name":"bossGetAll","args":{},"ident":"bossGetAll"}]}', e => {
  7392. let bosses = e.results[0].result.response;
  7393.  
  7394. let bossRaidOpenChestCall = {
  7395. calls: []
  7396. };
  7397.  
  7398. for (let boss of bosses) {
  7399. if (boss.mayRaid) {
  7400. bossRaidOpenChestCall.calls.push({
  7401. name: "bossRaid",
  7402. args: {
  7403. bossId: boss.id
  7404. },
  7405. ident: "bossRaid_" + boss.id
  7406. });
  7407. bossRaidOpenChestCall.calls.push({
  7408. name: "bossOpenChest",
  7409. args: {
  7410. bossId: boss.id,
  7411. amount: 1,
  7412. starmoney: 0
  7413. },
  7414. ident: "bossOpenChest_" + boss.id
  7415. });
  7416. } else if (boss.chestId == 1) {
  7417. bossRaidOpenChestCall.calls.push({
  7418. name: "bossOpenChest",
  7419. args: {
  7420. bossId: boss.id,
  7421. amount: 1,
  7422. starmoney: 0
  7423. },
  7424. ident: "bossOpenChest_" + boss.id
  7425. });
  7426. }
  7427. }
  7428.  
  7429. if (!bossRaidOpenChestCall.calls.length) {
  7430. setProgress(`${I18N('OUTLAND')} ${I18N('NOTHING_TO_COLLECT')}`, true);
  7431. resolve();
  7432. return;
  7433. }
  7434.  
  7435. send(JSON.stringify(bossRaidOpenChestCall), e => {
  7436. setProgress(`${I18N('OUTLAND')} ${I18N('COLLECTED')}`, true);
  7437. resolve();
  7438. });
  7439. });
  7440. });
  7441. }
  7442.  
  7443. /**
  7444. * Collect all rewards
  7445. *
  7446. * Собрать все награды
  7447. */
  7448. function questAllFarm() {
  7449. return new Promise(function (resolve, reject) {
  7450. let questGetAllCall = {
  7451. calls: [{
  7452. name: "questGetAll",
  7453. args: {},
  7454. ident: "body"
  7455. }]
  7456. }
  7457. send(JSON.stringify(questGetAllCall), function (data) {
  7458. let questGetAll = data.results[0].result.response;
  7459. const questAllFarmCall = {
  7460. calls: []
  7461. }
  7462. let number = 0;
  7463. for (let quest of questGetAll) {
  7464. if (quest.id < 1e6 && quest.state == 2) {
  7465. questAllFarmCall.calls.push({
  7466. name: "questFarm",
  7467. args: {
  7468. questId: quest.id
  7469. },
  7470. ident: `group_${number}_body`
  7471. });
  7472. number++;
  7473. }
  7474. }
  7475.  
  7476. if (!questAllFarmCall.calls.length) {
  7477. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  7478. resolve();
  7479. return;
  7480. }
  7481.  
  7482. send(JSON.stringify(questAllFarmCall), function (res) {
  7483. console.log(res);
  7484. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  7485. resolve();
  7486. });
  7487. });
  7488. })
  7489. }
  7490.  
  7491. /**
  7492. * Mission auto repeat
  7493. *
  7494. * Автоповтор миссии
  7495. * isStopSendMission = false;
  7496. * isSendsMission = true;
  7497. **/
  7498. this.sendsMission = async function (param) {
  7499. if (isStopSendMission) {
  7500. isSendsMission = false;
  7501. console.log(I18N('STOPPED'));
  7502. setProgress('');
  7503. await popup.confirm(`${I18N('STOPPED')}<br>${I18N('REPETITIONS')}: ${param.count}`, [{
  7504. msg: 'Ok',
  7505. result: true
  7506. }, ])
  7507. return;
  7508. }
  7509. lastMissionBattleStart = Date.now();
  7510. let missionStartCall = {
  7511. "calls": [{
  7512. "name": "missionStart",
  7513. "args": lastMissionStart,
  7514. "ident": "body"
  7515. }]
  7516. }
  7517. /**
  7518. * Mission Request
  7519. *
  7520. * Запрос на выполнение мисcии
  7521. */
  7522. SendRequest(JSON.stringify(missionStartCall), async e => {
  7523. if (e['error']) {
  7524. isSendsMission = false;
  7525. console.log(e['error']);
  7526. setProgress('');
  7527. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  7528. await popup.confirm(msg, [
  7529. {msg: 'Ok', result: true},
  7530. ])
  7531. return;
  7532. }
  7533. /**
  7534. * Mission data calculation
  7535. *
  7536. * Расчет данных мисcии
  7537. */
  7538. BattleCalc(e.results[0].result.response, 'get_tower', async r => {
  7539. /** missionTimer */
  7540. let timer = getTimer(r.battleTime) + 5;
  7541. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  7542. if (period < timer) {
  7543. timer = timer - period;
  7544. await countdownTimer(timer, `${I18N('MISSIONS_PASSED')}: ${param.count}`);
  7545. }
  7546.  
  7547. let missionEndCall = {
  7548. "calls": [{
  7549. "name": "missionEnd",
  7550. "args": {
  7551. "id": param.id,
  7552. "result": r.result,
  7553. "progress": r.progress
  7554. },
  7555. "ident": "body"
  7556. }]
  7557. }
  7558. /**
  7559. * Mission Completion Request
  7560. *
  7561. * Запрос на завершение миссии
  7562. */
  7563. SendRequest(JSON.stringify(missionEndCall), async (e) => {
  7564. if (e['error']) {
  7565. isSendsMission = false;
  7566. console.log(e['error']);
  7567. setProgress('');
  7568. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  7569. await popup.confirm(msg, [
  7570. {msg: 'Ok', result: true},
  7571. ])
  7572. return;
  7573. }
  7574. r = e.results[0].result.response;
  7575. if (r['error']) {
  7576. isSendsMission = false;
  7577. console.log(r['error']);
  7578. setProgress('');
  7579. await popup.confirm(`<br>${I18N('REPETITIONS')}: ${param.count}` + ' 3 ' + r['error'], [
  7580. {msg: 'Ok', result: true},
  7581. ])
  7582. return;
  7583. }
  7584.  
  7585. param.count++;
  7586. let RaidMission = getInput('countRaid');
  7587.  
  7588. if (RaidMission==param.count){
  7589. isStopSendMission = true;
  7590. console.log(RaidMission);
  7591. }
  7592. setProgress(`${I18N('MISSIONS_PASSED')}: ${param.count} (${I18N('STOP')})`, false, () => {
  7593. isStopSendMission = true;
  7594. });
  7595. setTimeout(sendsMission, 1, param);
  7596. });
  7597. })
  7598. });
  7599. }
  7600.  
  7601. /**
  7602. * Recursive opening of russian dolls
  7603. *
  7604. * Рекурсивное открытие матрешек
  7605. */
  7606. function openRussianDoll(id, count, sum) {
  7607. sum = sum || 0;
  7608. sum += count;
  7609. send('{"calls":[{"name":"consumableUseLootBox","args":{"libId":'+id+',"amount":'+count+'},"ident":"body"}]}', e => {
  7610. setProgress(`${I18N('OPEN')} ${count}`, true);
  7611. let result = e.results[0].result.response;
  7612. let newCount = 0;
  7613. for(let n of result) {
  7614. if (n?.consumable && n.consumable[id]) {
  7615. newCount += n.consumable[id]
  7616. }
  7617. }
  7618. if (newCount) {
  7619. openRussianDoll(id, newCount, sum);
  7620. } else {
  7621. popup.confirm(`${I18N('TOTAL_OPEN')} ${sum}`);
  7622. }
  7623. })
  7624. }
  7625.  
  7626. /**
  7627. * Opening of russian dolls
  7628. *
  7629. * Открытие матрешек
  7630. */
  7631. async function openRussianDolls(libId, amount) {
  7632. let sum = 0;
  7633. let sumResult = [];
  7634.  
  7635. while (amount) {
  7636. sum += amount;
  7637. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`);
  7638. const calls = [{
  7639. name: "consumableUseLootBox",
  7640. args: { libId, amount },
  7641. ident: "body"
  7642. }];
  7643. const result = await Send(JSON.stringify({ calls })).then(e => e.results[0].result.response);
  7644. let newCount = 0;
  7645. for (let n of result) {
  7646. if (n?.consumable && n.consumable[libId]) {
  7647. newCount += n.consumable[libId]
  7648. }
  7649. }
  7650. sumResult = [...sumResult, ...result];
  7651. amount = newCount;
  7652. }
  7653.  
  7654. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`, 5000);
  7655. return sumResult;
  7656. }
  7657.  
  7658. /**
  7659. * Collect all mail, except letters with energy and charges of the portal
  7660. *
  7661. * Собрать всю почту, кроме писем с энергией и зарядами портала
  7662. */
  7663. function mailGetAll() {
  7664. const getMailInfo = '{"calls":[{"name":"mailGetAll","args":{},"ident":"body"}]}';
  7665.  
  7666. return Send(getMailInfo).then(dataMail => {
  7667. const letters = dataMail.results[0].result.response.letters;
  7668. const letterIds = lettersFilter(letters);
  7669. if (!letterIds.length) {
  7670. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  7671. return;
  7672. }
  7673.  
  7674. const calls = [
  7675. { name: "mailFarm", args: { letterIds }, ident: "body" }
  7676. ];
  7677.  
  7678. return Send(JSON.stringify({ calls })).then(res => {
  7679. const lettersIds = res.results[0].result.response;
  7680. if (lettersIds) {
  7681. const countLetters = Object.keys(lettersIds).length;
  7682. setProgress(`${I18N('RECEIVED')} ${countLetters} ${I18N('LETTERS')}`, true);
  7683. }
  7684. });
  7685. });
  7686. }
  7687.  
  7688. /**
  7689. * Filters received emails
  7690. *
  7691. * Фильтрует получаемые письма
  7692. */
  7693. function lettersFilter(letters) {
  7694. const lettersIds = [];
  7695. for (let l in letters) {
  7696. letter = letters[l];
  7697. const reward = letter.reward;
  7698. if (!reward) {
  7699. continue;
  7700. }
  7701. /**
  7702. * Mail Collection Exceptions
  7703. *
  7704. * Исключения на сбор писем
  7705. */
  7706. const isFarmLetter = !(
  7707. /** Portals // сферы портала */
  7708. (reward?.refillable ? reward.refillable[45] : false) ||
  7709. /** Energy // энергия */
  7710. (reward?.stamina ? reward.stamina : false) ||
  7711. /** accelerating energy gain // ускорение набора энергии */
  7712. (reward?.buff ? true : false) ||
  7713. /** VIP Points // вип очки */
  7714. (reward?.vipPoints ? reward.vipPoints : false) ||
  7715. /** souls of heroes // душы героев */
  7716. (reward?.fragmentHero ? true : false) ||
  7717. /** heroes // герои */
  7718. (reward?.bundleHeroReward ? true : false)
  7719. );
  7720. if (isFarmLetter) {
  7721. lettersIds.push(~~letter.id);
  7722. continue;
  7723. }
  7724. /**
  7725. * Если до окончания годности письма менее 24 часов,
  7726. * то оно собирается не смотря на исключения
  7727. */
  7728. const availableUntil = +letter?.availableUntil;
  7729. if (availableUntil) {
  7730. const maxTimeLeft = 24 * 60 * 60 * 1000;
  7731. const timeLeft = (new Date(availableUntil * 1000) - new Date())
  7732. console.log('Time left:', timeLeft)
  7733. if (timeLeft < maxTimeLeft) {
  7734. lettersIds.push(~~letter.id);
  7735. continue;
  7736. }
  7737. }
  7738. }
  7739. return lettersIds;
  7740. }
  7741.  
  7742. /**
  7743. * Displaying information about the areas of the portal and attempts on the VG
  7744. *
  7745. * Отображение информации о сферах портала и попытках на ВГ
  7746. */
  7747. async function justInfo() {
  7748. return new Promise(async (resolve, reject) => {
  7749. const calls = [{
  7750. name: "userGetInfo",
  7751. args: {},
  7752. ident: "userGetInfo"
  7753. },
  7754. {
  7755. name: "clanWarGetInfo",
  7756. args: {},
  7757. ident: "clanWarGetInfo"
  7758. },
  7759. {
  7760. name: "titanArenaGetStatus",
  7761. args: {},
  7762. ident: "titanArenaGetStatus"
  7763. }];
  7764. const result = await Send(JSON.stringify({ calls }));
  7765. const infos = result.results;
  7766. const portalSphere = infos[0].result.response.refillable.find(n => n.id == 45);
  7767. const clanWarMyTries = infos[1].result.response?.myTries ?? 0;
  7768. const arePointsMax = infos[1].result.response?.arePointsMax;
  7769. const titansLevel = +(infos[2].result.response?.tier ?? 0);
  7770. const titansStatus = infos[2].result.response?.status; //peace_time || battle
  7771.  
  7772. const sanctuaryButton = buttons['goToSanctuary'].button;
  7773. const clanWarButton = buttons['goToClanWar'].button;
  7774. const titansArenaButton = buttons['testTitanArena'].button;
  7775.  
  7776. /*if (portalSphere.amount) {
  7777. sanctuaryButton.style.color = portalSphere.amount >= 3 ? 'red' : 'brown';
  7778. sanctuaryButton.title = `${I18N('SANCTUARY_TITLE')}\n${portalSphere.amount} ${I18N('PORTALS')}`;
  7779. } else {*/
  7780. sanctuaryButton.style.color = '';
  7781. sanctuaryButton.title = I18N('SANCTUARY_TITLE');
  7782. //}
  7783. /*if (clanWarMyTries && !arePointsMax) {
  7784. clanWarButton.style.color = 'red';
  7785. clanWarButton.title = `${I18N('GUILD_WAR_TITLE')}\n${clanWarMyTries}${I18N('ATTEMPTS')}`;
  7786. } else {*/
  7787. clanWarButton.style.color = '';
  7788. clanWarButton.title = I18N('GUILD_WAR_TITLE');
  7789. //}
  7790.  
  7791. /*if (titansLevel < 7 && titansStatus == 'battle') {
  7792. const partColor = Math.floor(125 * titansLevel / 7);
  7793. titansArenaButton.style.color = `rgb(255,${partColor},${partColor})`;
  7794. titansArenaButton.title = `${I18N('TITAN_ARENA_TITLE')}\n${titansLevel} ${I18N('LEVEL')}`;
  7795. } else {*/
  7796. titansArenaButton.style.color = '';
  7797. titansArenaButton.title = I18N('TITAN_ARENA_TITLE');
  7798. //}
  7799. //тест убрал подсветку красным в меню
  7800. setProgress('<img src="https://zingery.ru/heroes/portal.png" style="height: 25px;position: relative;top: 5px;"> ' + `${portalSphere.amount} </br> ${I18N('GUILD_WAR')}: ${clanWarMyTries}`, true);
  7801. resolve();
  7802. });
  7803. }
  7804. // тест сделать все
  7805. /** Отправить подарки мое*/
  7806. function testclanSendDailyGifts() {
  7807.  
  7808. send('{"calls":[{"name":"clanSendDailyGifts","args":{},"ident":"clanSendDailyGifts"}]}', e => {
  7809. setProgress('Награды собраны', true);});
  7810. }
  7811. /** Открой сферу артефактов титанов*/
  7812. function testtitanArtifactChestOpen() {
  7813. send('{"calls":[{"name":"titanArtifactChestOpen","args":{"amount":1,"free":true},"ident":"body"}]}',
  7814. isWeCanDo => {
  7815. return info['inventoryGet']?.consumable[55] > 0
  7816. //setProgress('Награды собраны', true);
  7817. });
  7818. }
  7819. /** Воспользуйся призывом питомцев 1 раз*/
  7820. function testpet_chestOpen() {
  7821. send('{"calls":[{"name":"pet_chestOpen","args":{"amount":1,"paid":false},"ident":"pet_chestOpen"}]}',
  7822. isWeCanDo => {
  7823. return info['inventoryGet']?.consumable[90] > 0
  7824. //setProgress('Награды собраны', true);
  7825. });
  7826. }
  7827.  
  7828. async function getDailyBonus() {
  7829. const dailyBonusInfo = await Send(JSON.stringify({
  7830. calls: [{
  7831. name: "dailyBonusGetInfo",
  7832. args: {},
  7833. ident: "body"
  7834. }]
  7835. })).then(e => e.results[0].result.response);
  7836. const { availableToday, availableVip, currentDay } = dailyBonusInfo;
  7837.  
  7838. if (!availableToday) {
  7839. console.log('Уже собрано');
  7840. return;
  7841. }
  7842.  
  7843. const currentVipPoints = +userInfo.vipPoints;
  7844. const dailyBonusStat = lib.getData('dailyBonusStatic');
  7845. const vipInfo = lib.getData('level').vip;
  7846. let currentVipLevel = 0;
  7847. for (let i in vipInfo) {
  7848. vipLvl = vipInfo[i];
  7849. if (currentVipPoints >= vipLvl.vipPoints) {
  7850. currentVipLevel = vipLvl.level;
  7851. }
  7852. }
  7853. const vipLevelDouble = dailyBonusStat[`${currentDay}_0_0`].vipLevelDouble;
  7854.  
  7855. const calls = [{
  7856. name: "dailyBonusFarm",
  7857. args: {
  7858. vip: availableVip && currentVipLevel >= vipLevelDouble ? 1 : 0
  7859. },
  7860. ident: "body"
  7861. }];
  7862.  
  7863. const result = await Send(JSON.stringify({ calls }));
  7864. if (result.error) {
  7865. console.error(result.error);
  7866. return;
  7867. }
  7868.  
  7869. const reward = result.results[0].result.response;
  7870. const type = Object.keys(reward).pop();
  7871. const itemId = Object.keys(reward[type]).pop();
  7872. const count = reward[type][itemId];
  7873. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  7874.  
  7875. console.log(`Ежедневная награда: Получено ${count} ${itemName}`, reward);
  7876. }
  7877.  
  7878. async function farmStamina(lootBoxId = 148) {
  7879. const lootBox = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"}]}')
  7880. .then(e => e.results[0].result.response.consumable[148]);
  7881.  
  7882. /** Добавить другие ящики */
  7883. /**
  7884. * 144 - медная шкатулка
  7885. * 145 - бронзовая шкатулка
  7886. * 148 - платиновая шкатулка
  7887. */
  7888. if (!lootBox) {
  7889. setProgress(I18N('NO_BOXES'), true);
  7890. return;
  7891. }
  7892.  
  7893. let maxFarmEnergy = getSaveVal('maxFarmEnergy', 100);
  7894. const result = await popup.confirm(I18N('OPEN_LOOTBOX', { lootBox }), [
  7895. { result: false, isClose: true },
  7896. { msg: I18N('BTN_YES'), result: true },
  7897. { msg: I18N('STAMINA'), isInput: true, default: maxFarmEnergy },
  7898. ]);
  7899.  
  7900. if (!+result) {
  7901. return;
  7902. }
  7903.  
  7904. if ((typeof result) !== 'boolean' && Number.parseInt(result)) {
  7905. maxFarmEnergy = +result;
  7906. setSaveVal('maxFarmEnergy', maxFarmEnergy);
  7907. } else {
  7908. maxFarmEnergy = 0;
  7909. }
  7910.  
  7911. let collectEnergy = 0;
  7912. for (let count = lootBox; count > 0; count--) {
  7913. const result = await Send('{"calls":[{"name":"consumableUseLootBox","args":{"libId":148,"amount":1},"ident":"body"}]}')
  7914. .then(e => e.results[0].result.response[0]);
  7915. if ('stamina' in result) {
  7916. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox} ${I18N('STAMINA')} +${result.stamina}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  7917. console.log(`${ I18N('STAMINA') } + ${ result.stamina }`);
  7918. if (!maxFarmEnergy) {
  7919. return;
  7920. }
  7921. collectEnergy += +result.stamina;
  7922. if (collectEnergy >= maxFarmEnergy) {
  7923. console.log(`${I18N('STAMINA')} + ${ collectEnergy }`);
  7924. setProgress(`${I18N('STAMINA')} + ${ collectEnergy }`, false);
  7925. return;
  7926. }
  7927. } else {
  7928. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  7929. console.log(result);
  7930. }
  7931. }
  7932.  
  7933. setProgress(I18N('BOXES_OVER'), true);
  7934. }
  7935.  
  7936. async function fillActive() {
  7937. const data = await Send(JSON.stringify({
  7938. calls: [{
  7939. name: "questGetAll",
  7940. args: {},
  7941. ident: "questGetAll"
  7942. }, {
  7943. name: "inventoryGet",
  7944. args: {},
  7945. ident: "inventoryGet"
  7946. }, {
  7947. name: "clanGetInfo",
  7948. args: {},
  7949. ident: "clanGetInfo"
  7950. }
  7951. ]
  7952. })).then(e => e.results.map(n => n.result.response));
  7953.  
  7954. const quests = data[0];
  7955. const inv = data[1];
  7956. const stat = data[2].stat;
  7957. const maxActive = 2000 - stat.todayItemsActivity;
  7958. if (maxActive <= 0) {
  7959. setProgress(I18N('NO_MORE_ACTIVITY'), true);
  7960. return;
  7961. }
  7962.  
  7963. let countGetActive = 0;
  7964. const quest = quests.find(e => e.id > 10046 && e.id < 10051);
  7965. if (quest) {
  7966. countGetActive = 1750 - quest.progress;
  7967. }
  7968.  
  7969. if (countGetActive <= 0) {
  7970. countGetActive = maxActive;
  7971. }
  7972. console.log(countGetActive);
  7973.  
  7974. countGetActive = +(await popup.confirm(I18N('EXCHANGE_ITEMS', { maxActive }), [
  7975. { result: false, isClose: true },
  7976. { msg: I18N('GET_ACTIVITY'), isInput: true, default: countGetActive.toString() },
  7977. ]));
  7978.  
  7979. if (!countGetActive) {
  7980. return;
  7981. }
  7982.  
  7983. if (countGetActive > maxActive) {
  7984. countGetActive = maxActive;
  7985. }
  7986.  
  7987. const items = lib.getData('inventoryItem');
  7988.  
  7989. let itemsInfo = [];
  7990. for (let type of ['gear', 'scroll']) {
  7991. for (let i in inv[type]) {
  7992. const v = items[type][i]?.enchantValue || 0;
  7993. itemsInfo.push({
  7994. id: i,
  7995. count: inv[type][i],
  7996. v,
  7997. type
  7998. })
  7999. }
  8000. const invType = 'fragment' + type.toLowerCase().charAt(0).toUpperCase() + type.slice(1);
  8001. for (let i in inv[invType]) {
  8002. const v = items[type][i]?.fragmentEnchantValue || 0;
  8003. itemsInfo.push({
  8004. id: i,
  8005. count: inv[invType][i],
  8006. v,
  8007. type: invType
  8008. })
  8009. }
  8010. }
  8011. itemsInfo = itemsInfo.filter(e => e.v < 4 && e.count > 200);
  8012. itemsInfo = itemsInfo.sort((a, b) => b.count - a.count);
  8013. console.log(itemsInfo);
  8014. const activeItem = itemsInfo.shift();
  8015. console.log(activeItem);
  8016. const countItem = Math.ceil(countGetActive / activeItem.v);
  8017. if (countItem > activeItem.count) {
  8018. setProgress(I18N('NOT_ENOUGH_ITEMS'), true);
  8019. console.log(activeItem);
  8020. return;
  8021. }
  8022.  
  8023. await Send(JSON.stringify({
  8024. calls: [{
  8025. name: "clanItemsForActivity",
  8026. args: {
  8027. items: {
  8028. [activeItem.type]: {
  8029. [activeItem.id]: countItem
  8030. }
  8031. }
  8032. },
  8033. ident: "body"
  8034. }]
  8035. })).then(e => {
  8036. /** TODO: Вывести потраченые предметы */
  8037. console.log(e);
  8038. setProgress(`${I18N('ACTIVITY_RECEIVED')}: ` + e.results[0].result.response, true);
  8039. });
  8040. }
  8041.  
  8042. async function buyHeroFragments() {
  8043. const result = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"},{"name":"shopGetAll","args":{},"ident":"shopGetAll"}]}')
  8044. .then(e => e.results.map(n => n.result.response));
  8045. const inv = result[0];
  8046. const shops = Object.values(result[1]).filter(shop => [4, 5, 6, 8, 9, 10, 17].includes(shop.id));
  8047. const calls = [];
  8048.  
  8049. for (let shop of shops) {
  8050. const slots = Object.values(shop.slots);
  8051. for (const slot of slots) {
  8052. /* Уже куплено */
  8053. if (slot.bought) {
  8054. continue;
  8055. }
  8056. /* Не душа героя */
  8057. if (!('fragmentHero' in slot.reward)) {
  8058. continue;
  8059. }
  8060. const coin = Object.keys(slot.cost).pop();
  8061. const coinId = Object.keys(slot.cost[coin]).pop();
  8062. const stock = inv[coin][coinId] || 0;
  8063. /* Не хватает на покупку */
  8064. if (slot.cost[coin][coinId] > stock) {
  8065. continue;
  8066. }
  8067. inv[coin][coinId] -= slot.cost[coin][coinId];
  8068. calls.push({
  8069. name: "shopBuy",
  8070. args: {
  8071. shopId: shop.id,
  8072. slot: slot.id,
  8073. cost: slot.cost,
  8074. reward: slot.reward,
  8075. },
  8076. ident: `shopBuy_${shop.id}_${slot.id}`,
  8077. })
  8078. }
  8079. }
  8080.  
  8081. if (!calls.length) {
  8082. setProgress(I18N('NO_PURCHASABLE_HERO_SOULS'), true);
  8083. return;
  8084. }
  8085.  
  8086. const bought = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  8087. if (!bought) {
  8088. console.log('что-то пошло не так')
  8089. return;
  8090. }
  8091.  
  8092. let countHeroSouls = 0;
  8093. for (const buy of bought) {
  8094. countHeroSouls += +Object.values(Object.values(buy).pop()).pop();
  8095. }
  8096. console.log(countHeroSouls, bought, calls);
  8097. setProgress(I18N('PURCHASED_HERO_SOULS', { countHeroSouls }), true);
  8098. }
  8099.  
  8100. /** Открыть платные сундуки в Запределье за 90 */
  8101. async function bossOpenChestPay() {
  8102. const info = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"userGetInfo"},{"name":"bossGetAll","args":{},"ident":"bossGetAll"}]}')
  8103. .then(e => e.results.map(n => n.result.response));
  8104.  
  8105. const user = info[0];
  8106. const boses = info[1];
  8107.  
  8108. const currentStarMoney = user.starMoney;
  8109. if (currentStarMoney < 540) {
  8110. setProgress(I18N('NOT_ENOUGH_EMERALDS_540', { currentStarMoney }), true);
  8111. return;
  8112. }
  8113.  
  8114. const calls = [];
  8115.  
  8116. let n = 0;
  8117. const amount = 1;
  8118. for (let boss of boses) {
  8119. const bossId = boss.id;
  8120. if (boss.chestNum != 2) {
  8121. continue;
  8122. }
  8123. for (const starmoney of [90, 90, 0]) {
  8124. calls.push({
  8125. name: "bossOpenChest",
  8126. args: {
  8127. bossId,
  8128. amount,
  8129. starmoney
  8130. },
  8131. ident: "bossOpenChest_" + (++n)
  8132. });
  8133. }
  8134. }
  8135.  
  8136. if (!calls.length) {
  8137. setProgress(I18N('CHESTS_NOT_AVAILABLE'), true);
  8138. return;
  8139. }
  8140.  
  8141. const result = await Send(JSON.stringify({ calls }));
  8142. console.log(result);
  8143. if (result?.results) {
  8144. setProgress(`${I18N('OUTLAND_CHESTS_RECEIVED')}: ` + result.results.length, true);
  8145. } else {
  8146. setProgress(I18N('CHESTS_NOT_AVAILABLE'), true);
  8147. }
  8148. }
  8149.  
  8150. async function autoRaidAdventure() {
  8151. const calls = [
  8152. {
  8153. name: "userGetInfo",
  8154. args: {},
  8155. ident: "userGetInfo"
  8156. },
  8157. {
  8158. name: "adventure_raidGetInfo",
  8159. args: {},
  8160. ident: "adventure_raidGetInfo"
  8161. }
  8162. ];
  8163. const result = await Send(JSON.stringify({ calls }))
  8164. .then(e => e.results.map(n => n.result.response));
  8165.  
  8166. const portalSphere = result[0].refillable.find(n => n.id == 45);
  8167. const adventureRaid = Object.entries(result[1].raid).filter(e => e[1]).pop()
  8168. const adventureId = adventureRaid ? adventureRaid[0] : 0;
  8169.  
  8170. if (!portalSphere.amount || !adventureId) {
  8171. setProgress(I18N('RAID_NOT_AVAILABLE'), true);
  8172. return;
  8173. }
  8174.  
  8175. const countRaid = +(await popup.confirm(I18N('RAID_ADVENTURE', { adventureId }), [
  8176. { result: false, isClose: true },
  8177. { msg: I18N('RAID'), isInput: true, default: portalSphere.amount },
  8178. ]));
  8179.  
  8180. if (!countRaid) {
  8181. return;
  8182. }
  8183.  
  8184. if (countRaid > portalSphere.amount) {
  8185. countRaid = portalSphere.amount;
  8186. }
  8187.  
  8188. const resultRaid = await Send(JSON.stringify({
  8189. calls: [...Array(countRaid)].map((e, i) => ({
  8190. name: "adventure_raid",
  8191. args: {
  8192. adventureId
  8193. },
  8194. ident: `body_${i}`
  8195. }))
  8196. })).then(e => e.results.map(n => n.result.response));
  8197.  
  8198. if (!resultRaid.length) {
  8199. console.log(resultRaid);
  8200. setProgress(I18N('SOMETHING_WENT_WRONG'), true);
  8201. return;
  8202. }
  8203.  
  8204. console.log(resultRaid, adventureId, portalSphere.amount);
  8205. setProgress(I18N('ADVENTURE_COMPLETED', { adventureId, times: resultRaid.length }), true);
  8206. }
  8207.  
  8208. /** Вывести всю клановую статистику в консоль браузера */
  8209. async function clanStatistic() {
  8210. const copy = function (text) {
  8211. const copyTextarea = document.createElement("textarea");
  8212. copyTextarea.style.opacity = "0";
  8213. copyTextarea.textContent = text;
  8214. document.body.appendChild(copyTextarea);
  8215. copyTextarea.select();
  8216. document.execCommand("copy");
  8217. document.body.removeChild(copyTextarea);
  8218. delete copyTextarea;
  8219. }
  8220. const calls = [
  8221. { name: "clanGetInfo", args: {}, ident: "clanGetInfo" },
  8222. { name: "clanGetWeeklyStat", args: {}, ident: "clanGetWeeklyStat" },
  8223. { name: "clanGetLog", args: {}, ident: "clanGetLog" },
  8224. ];
  8225.  
  8226. const result = await Send(JSON.stringify({ calls }));
  8227.  
  8228. const dataClanInfo = result.results[0].result.response;
  8229. const dataClanStat = result.results[1].result.response;
  8230. const dataClanLog = result.results[2].result.response;
  8231.  
  8232. const membersStat = {};
  8233. for (let i = 0; i < dataClanStat.stat.length; i++) {
  8234. membersStat[dataClanStat.stat[i].id] = dataClanStat.stat[i];
  8235. }
  8236.  
  8237. const joinStat = {};
  8238. historyLog = dataClanLog.history;
  8239. for (let j in historyLog) {
  8240. his = historyLog[j];
  8241. if (his.event == 'join') {
  8242. joinStat[his.userId] = his.ctime;
  8243. }
  8244. }
  8245.  
  8246. const infoArr = [];
  8247. const members = dataClanInfo.clan.members;
  8248. for (let n in members) {
  8249. var member = [
  8250. n,
  8251. members[n].name,
  8252. members[n].level,
  8253. dataClanInfo.clan.warriors.includes(+n) ? 1 : 0,
  8254. (new Date(members[n].lastLoginTime * 1000)).toLocaleString().replace(',', ''),
  8255. joinStat[n] ? (new Date(joinStat[n] * 1000)).toLocaleString().replace(',', '') : '',
  8256. membersStat[n].activity.reverse().join('\t'),
  8257. membersStat[n].adventureStat.reverse().join('\t'),
  8258. membersStat[n].clanGifts.reverse().join('\t'),
  8259. membersStat[n].clanWarStat.reverse().join('\t'),
  8260. membersStat[n].dungeonActivity.reverse().join('\t'),
  8261. ];
  8262. infoArr.push(member);
  8263. }
  8264. const info = infoArr.sort((a, b) => (b[2] - a[2])).map((e) => e.join('\t')).join('\n');
  8265. console.log(info);
  8266. copy(info);
  8267. setProgress(I18N('CLAN_STAT_COPY'), true);
  8268. }
  8269.  
  8270. async function buyInStoreForGold() {
  8271. const result = await Send('{"calls":[{"name":"shopGetAll","args":{},"ident":"body"},{"name":"userGetInfo","args":{},"ident":"userGetInfo"}]}').then(e => e.results.map(n => n.result.response));
  8272. const shops = result[0];
  8273. const user = result[1];
  8274. let gold = user.gold;
  8275. const calls = [];
  8276. if (shops[17]) {
  8277. const slots = shops[17].slots;
  8278. for (let i = 1; i <= 2; i++) {
  8279. if (!slots[i].bought) {
  8280. const costGold = slots[i].cost.gold;
  8281. if ((gold - costGold) < 0) {
  8282. continue;
  8283. }
  8284. gold -= costGold;
  8285. calls.push({
  8286. name: "shopBuy",
  8287. args: {
  8288. shopId: 17,
  8289. slot: i,
  8290. cost: slots[i].cost,
  8291. reward: slots[i].reward,
  8292. },
  8293. ident: 'body_' + i,
  8294. })
  8295. }
  8296. }
  8297. }
  8298. const slots = shops[1].slots;
  8299. for (let i = 4; i <= 6; i++) {
  8300. if (!slots[i].bought && slots[i]?.cost?.gold) {
  8301. const costGold = slots[i].cost.gold;
  8302. if ((gold - costGold) < 0) {
  8303. continue;
  8304. }
  8305. gold -= costGold;
  8306. calls.push({
  8307. name: "shopBuy",
  8308. args: {
  8309. shopId: 1,
  8310. slot: i,
  8311. cost: slots[i].cost,
  8312. reward: slots[i].reward,
  8313. },
  8314. ident: 'body_' + i,
  8315. })
  8316. }
  8317. }
  8318.  
  8319. if (!calls.length) {
  8320. setProgress(I18N('NOTHING_BUY'), true);
  8321. return;
  8322. }
  8323.  
  8324. const resultBuy = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  8325. console.log(resultBuy);
  8326. const countBuy = resultBuy.length;
  8327. setProgress(I18N('LOTS_BOUGHT', { countBuy }), true);
  8328. }
  8329.  
  8330. function rewardsAndMailFarm() {
  8331. return new Promise(function (resolve, reject) {
  8332. let questGetAllCall = {
  8333. calls: [{
  8334. name: "questGetAll",
  8335. args: {},
  8336. ident: "questGetAll"
  8337. }, {
  8338. name: "mailGetAll",
  8339. args: {},
  8340. ident: "mailGetAll"
  8341. }]
  8342. }
  8343. send(JSON.stringify(questGetAllCall), function (data) {
  8344. if (!data) return;
  8345. let questGetAll = data.results[0].result.response.filter(e => e.state == 2);
  8346. const questBattlePass = lib.getData('quest').battlePass;
  8347. const questChainBPass = lib.getData('battlePass').questChain;
  8348.  
  8349. const questAllFarmCall = {
  8350. calls: []
  8351. }
  8352. let number = 0;
  8353. for (let quest of questGetAll) {
  8354. if (quest.id > 1e6) {
  8355. const questInfo = questBattlePass[quest.id];
  8356. const chain = questChainBPass[questInfo.chain];
  8357. if (chain.requirement?.battlePassTicket) {
  8358. continue;
  8359. }
  8360. }
  8361. questAllFarmCall.calls.push({
  8362. name: "questFarm",
  8363. args: {
  8364. questId: quest.id
  8365. },
  8366. ident: `questFarm_${number}`
  8367. });
  8368. number++;
  8369. }
  8370.  
  8371. let letters = data?.results[1]?.result?.response?.letters;
  8372. letterIds = lettersFilter(letters);
  8373.  
  8374. if (letterIds.length) {
  8375. questAllFarmCall.calls.push({
  8376. name: "mailFarm",
  8377. args: { letterIds },
  8378. ident: "mailFarm"
  8379. })
  8380. }
  8381.  
  8382. if (!questAllFarmCall.calls.length) {
  8383. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  8384. resolve();
  8385. return;
  8386. }
  8387.  
  8388. send(JSON.stringify(questAllFarmCall), function (res) {
  8389. let reSend = false;
  8390. let countQuests = 0;
  8391. let countMail = 0;
  8392. for (let call of res.results) {
  8393. if (call.ident.includes('questFarm')) {
  8394. countQuests++;
  8395. } else {
  8396. countMail = Object.keys(call.result.response).length;
  8397. }
  8398.  
  8399. /** TODO: Переписать чтоб не вызывать функцию дважды */
  8400. const newQuests = call.result.newQuests;
  8401. if (newQuests) {
  8402. for (let quest of newQuests) {
  8403. if (quest.id < 1e6 && quest.state == 2) {
  8404. reSend = true;
  8405. }
  8406. }
  8407. }
  8408. }
  8409. setProgress(I18N('COLLECT_REWARDS_AND_MAIL', { countQuests, countMail }), true);
  8410. if (reSend) {
  8411. rewardsAndMailFarm()
  8412. }
  8413. resolve();
  8414. });
  8415. });
  8416. })
  8417. }
  8418.  
  8419. class epicBrawl {
  8420. timeout = null;
  8421. time = null;
  8422.  
  8423. constructor() {
  8424. if (epicBrawl.inst) {
  8425. return epicBrawl.inst;
  8426. }
  8427. epicBrawl.inst = this;
  8428. return this;
  8429. }
  8430.  
  8431. runTimeout(func, timeDiff) {
  8432. const worker = new Worker(URL.createObjectURL(new Blob([`
  8433. self.onmessage = function(e) {
  8434. const timeDiff = e.data;
  8435.  
  8436. if (timeDiff > 0) {
  8437. setTimeout(() => {
  8438. self.postMessage(1);
  8439. self.close();
  8440. }, timeDiff);
  8441. }
  8442. };
  8443. `])));
  8444. worker.postMessage(timeDiff);
  8445. worker.onmessage = () => {
  8446. func();
  8447. };
  8448. return true;
  8449. }
  8450.  
  8451. timeDiff(date1, date2) {
  8452. const date1Obj = new Date(date1);
  8453. const date2Obj = new Date(date2);
  8454.  
  8455. const timeDiff = Math.abs(date2Obj - date1Obj);
  8456.  
  8457. const totalSeconds = timeDiff / 1000;
  8458. const minutes = Math.floor(totalSeconds / 60);
  8459. const seconds = Math.floor(totalSeconds % 60);
  8460.  
  8461. const formattedMinutes = String(minutes).padStart(2, '0');
  8462. const formattedSeconds = String(seconds).padStart(2, '0');
  8463.  
  8464. return `${formattedMinutes}:${formattedSeconds}`;
  8465. }
  8466.  
  8467. check() {
  8468. console.log(new Date(this.time))
  8469. if (Date.now() > this.time) {
  8470. this.timeout = null;
  8471. this.start()
  8472. return;
  8473. }
  8474. this.timeout = this.runTimeout(() => this.check(), 6e4);
  8475. return this.timeDiff(this.time, Date.now())
  8476. }
  8477.  
  8478. async start() {
  8479. if (this.timeout) {
  8480. const time = this.timeDiff(this.time, Date.now());
  8481. console.log(new Date(this.time))
  8482. setProgress(I18N('TIMER_ALREADY', { time }), false, hideProgress);
  8483. return;
  8484. }
  8485. setProgress(I18N('EPIC_BRAWL'), false, hideProgress);
  8486. 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));
  8487. const refill = teamInfo[2].refillable.find(n => n.id == 52)
  8488. this.time = (refill.lastRefill + 3600) * 1000
  8489. const attempts = refill.amount;
  8490. if (!attempts) {
  8491. console.log(new Date(this.time));
  8492. const time = this.check();
  8493. setProgress(I18N('NO_ATTEMPTS_TIMER_START', { time }), false, hideProgress);
  8494. return;
  8495. }
  8496.  
  8497. if (!teamInfo[0].epic_brawl) {
  8498. setProgress(I18N('NO_HEROES_PACK'), false, hideProgress);
  8499. return;
  8500. }
  8501.  
  8502. const args = {
  8503. heroes: teamInfo[0].epic_brawl.filter(e => e < 1000),
  8504. pet: teamInfo[0].epic_brawl.filter(e => e > 6000).pop(),
  8505. favor: teamInfo[1].epic_brawl,
  8506. }
  8507.  
  8508. let wins = 0;
  8509. let coins = 0;
  8510. let streak = { progress: 0, nextStage: 0 };
  8511. for (let i = attempts; i > 0; i--) {
  8512. const info = await Send(JSON.stringify({
  8513. calls: [
  8514. { name: "epicBrawl_getEnemy", args: {}, ident: "epicBrawl_getEnemy" }, { name: "epicBrawl_startBattle", args, ident: "epicBrawl_startBattle" }
  8515. ]
  8516. })).then(e => e.results.map(n => n.result.response));
  8517.  
  8518. const { progress, result } = await Calc(info[1].battle);
  8519. 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));
  8520.  
  8521. const resultInfo = endResult[0].result;
  8522. streak = endResult[1];
  8523.  
  8524. wins += resultInfo.win;
  8525. coins += resultInfo.reward ? resultInfo.reward.coin[39] : 0;
  8526.  
  8527. console.log(endResult[0].result)
  8528. if (endResult[1].progress == endResult[1].nextStage) {
  8529. const farm = await Send('{"calls":[{"name":"epicBrawl_farmWinStreak","args":{},"ident":"body"}]}').then(e => e.results[0].result.response);
  8530. coins += farm.coin[39];
  8531. }
  8532.  
  8533. setProgress(I18N('EPIC_BRAWL_RESULT', {
  8534. i, wins, attempts, coins,
  8535. progress: streak.progress,
  8536. nextStage: streak.nextStage,
  8537. end: '',
  8538. }), false, hideProgress);
  8539. }
  8540.  
  8541. console.log(new Date(this.time));
  8542. const time = this.check();
  8543. setProgress(I18N('EPIC_BRAWL_RESULT', {
  8544. wins, attempts, coins,
  8545. i: '',
  8546. progress: streak.progress,
  8547. nextStage: streak.nextStage,
  8548. end: I18N('ATTEMPT_ENDED', { time }),
  8549. }), false, hideProgress);
  8550. }
  8551. }
  8552. /* тест остановка подземки*/
  8553. function stopDungeon(e) {
  8554. stopDung = true;
  8555. }
  8556. function Sleep(ms) {
  8557. return new Promise(resolve => setTimeout(resolve, ms));
  8558. }
  8559. function countdownTimer(seconds, message) {
  8560. message = message || I18N('TIMER');
  8561. const stopTimer = Date.now() + seconds * 1e3
  8562. return new Promise(resolve => {
  8563. const interval = setInterval(async () => {
  8564. const now = Date.now();
  8565. setProgress(`${message} ${((stopTimer - now) / 1000).toFixed(2)}`, false);
  8566. if (now > stopTimer) {
  8567. clearInterval(interval);
  8568. setProgress('', 1);
  8569. resolve();
  8570. }
  8571. }, 100);
  8572. });
  8573. }
  8574.  
  8575. /** Набить килов в горниле душк */
  8576. async function bossRatingEventSouls() {
  8577. const data = await Send({
  8578. calls: [
  8579. { name: "heroGetAll", args: {}, ident: "teamGetAll" },
  8580. { name: "offerGetAll", args: {}, ident: "offerGetAll" },
  8581. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  8582. ]
  8583. });
  8584. const bossEventInfo = data.results[1].result.response.find(e => e.offerType == "bossEvent");
  8585. if (!bossEventInfo) {
  8586. setProgress('Эвент завершен', true);
  8587. return;
  8588. }
  8589.  
  8590. if (bossEventInfo.progress.score > 250) {
  8591. setProgress('Уже убито больше 250 врагов');
  8592. rewardBossRatingEventSouls();
  8593. return;
  8594. }
  8595. const availablePets = Object.values(data.results[2].result.response).map(e => e.id);
  8596. const heroGetAllList = data.results[0].result.response;
  8597. const usedHeroes = bossEventInfo.progress.usedHeroes;
  8598. const heroList = [];
  8599.  
  8600. for (let heroId in heroGetAllList) {
  8601. let hero = heroGetAllList[heroId];
  8602. if (usedHeroes.includes(hero.id)) {
  8603. continue;
  8604. }
  8605. heroList.push(hero.id);
  8606. }
  8607.  
  8608. if (!heroList.length) {
  8609. setProgress('Нет героев', true);
  8610. return;
  8611. }
  8612.  
  8613. const pet = availablePets.includes(6005) ? 6005 : availablePets[Math.floor(Math.random() * availablePets.length)];
  8614. const petLib = lib.getData('pet');
  8615. let count = 1;
  8616.  
  8617. for (const heroId of heroList) {
  8618. const args = {
  8619. heroes: [heroId],
  8620. pet
  8621. }
  8622. /** Поиск питомца для героя */
  8623. for (const petId of availablePets) {
  8624. if (petLib[petId].favorHeroes.includes(heroId)) {
  8625. args.favor = {
  8626. [heroId]: petId
  8627. }
  8628. break;
  8629. }
  8630. }
  8631.  
  8632. const calls = [{
  8633. name: "bossRatingEvent_startBattle",
  8634. args,
  8635. ident: "body"
  8636. }, {
  8637. name: "offerGetAll",
  8638. args: {},
  8639. ident: "offerGetAll"
  8640. }];
  8641.  
  8642. const res = await Send({ calls });
  8643. count++;
  8644.  
  8645. if ('error' in res) {
  8646. console.error(res.error);
  8647. setProgress('Перезагрузите игру и попробуйте позже', true);
  8648. return;
  8649. }
  8650.  
  8651. const eventInfo = res.results[1].result.response.find(e => e.offerType == "bossEvent");
  8652. if (eventInfo.progress.score > 250) {
  8653. break;
  8654. }
  8655. setProgress('Количество убитых врагов: ' + eventInfo.progress.score + '<br>Использовано ' + count + ' героев');
  8656. }
  8657.  
  8658. rewardBossRatingEventSouls();
  8659. }
  8660. /** Сбор награды из Горнила Душ */
  8661. async function rewardBossRatingEventSouls() {
  8662. const data = await Send({
  8663. calls: [
  8664. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  8665. ]
  8666. });
  8667.  
  8668. const bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  8669. if (!bossEventInfo) {
  8670. setProgress('Эвент завершен', true);
  8671. return;
  8672. }
  8673.  
  8674. const farmedChests = bossEventInfo.progress.farmedChests;
  8675. const score = bossEventInfo.progress.score;
  8676. // setProgress('Количество убитых врагов: ' + score);
  8677. const revard = bossEventInfo.reward;
  8678. const calls = [];
  8679.  
  8680. let count = 0;
  8681. for (let i = 1; i < 10; i++) {
  8682. if (farmedChests.includes(i)) {
  8683. continue;
  8684. }
  8685. if (score < revard[i].score) {
  8686. break;
  8687. }
  8688. calls.push({
  8689. name: "bossRatingEvent_getReward",
  8690. args: {
  8691. rewardId: i
  8692. },
  8693. ident: "body_" + i
  8694. });
  8695. count++;
  8696. }
  8697. if (!count) {
  8698. setProgress('Нечего собирать', true);
  8699. return;
  8700. }
  8701.  
  8702. Send({ calls }).then(e => {
  8703. console.log(e);
  8704. setProgress('Собрано ' + e?.results?.length + ' наград', true);
  8705. })
  8706. }
  8707. /**
  8708. * Spin the Seer
  8709. *
  8710. * Покрутить провидца
  8711. */
  8712. async function rollAscension() {
  8713. const refillable = await Send({calls:[
  8714. {
  8715. name:"userGetInfo",
  8716. args:{},
  8717. ident:"userGetInfo"
  8718. }
  8719. ]}).then(e => e.results[0].result.response.refillable);
  8720. const i47 = refillable.find(i => i.id == 47);
  8721. if (i47?.amount) {
  8722. await Send({ calls: [{ name: "ascensionChest_open", args: { paid: false, amount: 1 }, ident: "body" }] });
  8723. setProgress(I18N('DONE'), true);
  8724. } else {
  8725. setProgress(I18N('NOT_ENOUGH_AP'), true);
  8726. }
  8727. }
  8728.  
  8729. /**
  8730. * Collect gifts for the New Year
  8731. *
  8732. * Собрать подарки на новый год
  8733. */
  8734. function getGiftNewYear() {
  8735. Send({ calls: [{ name: "newYearGiftGet", args: { type: 0 }, ident: "body" }] }).then(e => {
  8736. const gifts = e.results[0].result.response.gifts;
  8737. const calls = gifts.filter(e => e.opened == 0).map(e => ({
  8738. name: "newYearGiftOpen",
  8739. args: {
  8740. giftId: e.id
  8741. },
  8742. ident: `body_${e.id}`
  8743. }));
  8744. if (!calls.length) {
  8745. setProgress(I18N('NY_NO_GIFTS'), 5000);
  8746. return;
  8747. }
  8748. Send({ calls }).then(e => {
  8749. console.log(e.results)
  8750. const msg = I18N('NY_GIFTS_COLLECTED', { count: e.results.length });
  8751. console.log(msg);
  8752. setProgress(msg, 5000);
  8753. });
  8754. })
  8755. }
  8756.  
  8757. async function updateArtifacts() {
  8758. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  8759. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  8760. { result: false, isClose: true }
  8761. ]);
  8762. if (!count) {
  8763. return;
  8764. }
  8765. const quest = new questRun;
  8766. await quest.autoInit();
  8767. const heroes = Object.values(quest.questInfo['heroGetAll']);
  8768. const inventory = quest.questInfo['inventoryGet'];
  8769. const calls = [];
  8770. for (let i = count; i > 0; i--) {
  8771. const upArtifact = quest.getUpgradeArtifact();
  8772. if (!upArtifact.heroId) {
  8773. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  8774. { msg: I18N('YES'), result: true },
  8775. { result: false, isClose: true }
  8776. ])) {
  8777. break;
  8778. } else {
  8779. return;
  8780. }
  8781. }
  8782. const hero = heroes.find(e => e.id == upArtifact.heroId);
  8783. hero.artifacts[upArtifact.slotId].level++;
  8784. inventory[upArtifact.costСurrency][upArtifact.costId] -= upArtifact.costValue;
  8785. calls.push({
  8786. name: "heroArtifactLevelUp",
  8787. args: {
  8788. heroId: upArtifact.heroId,
  8789. slotId: upArtifact.slotId
  8790. },
  8791. ident: `heroArtifactLevelUp_${i}`
  8792. });
  8793. }
  8794.  
  8795. if (!calls.length) {
  8796. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8797. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8798. return;
  8799. }
  8800.  
  8801. await Send(JSON.stringify({ calls })).then(e => {
  8802. if ('error' in e) {
  8803. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8804. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8805. } else {
  8806. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  8807. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  8808. }
  8809. });
  8810. }
  8811.  
  8812. window.sign = a => {
  8813. const i = this['\x78\x79\x7a'];
  8814. 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'))
  8815. }
  8816.  
  8817. async function updateSkins() {
  8818. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  8819. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  8820. { result: false, isClose: true }
  8821. ]);
  8822. if (!count) {
  8823. return;
  8824. }
  8825.  
  8826. const quest = new questRun;
  8827. await quest.autoInit();
  8828. const heroes = Object.values(quest.questInfo['heroGetAll']);
  8829. const inventory = quest.questInfo['inventoryGet'];
  8830. const calls = [];
  8831. for (let i = count; i > 0; i--) {
  8832. const upSkin = quest.getUpgradeSkin();
  8833. if (!upSkin.heroId) {
  8834. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  8835. { msg: I18N('YES'), result: true },
  8836. { result: false, isClose: true }
  8837. ])) {
  8838. break;
  8839. } else {
  8840. return;
  8841. }
  8842. }
  8843. const hero = heroes.find(e => e.id == upSkin.heroId);
  8844. hero.skins[upSkin.skinId]++;
  8845. inventory[upSkin.costСurrency][upSkin.costСurrencyId] -= upSkin.cost;
  8846. calls.push({
  8847. name: "heroSkinUpgrade",
  8848. args: {
  8849. heroId: upSkin.heroId,
  8850. skinId: upSkin.skinId
  8851. },
  8852. ident: `heroSkinUpgrade_${i}`
  8853. })
  8854. }
  8855.  
  8856. if (!calls.length) {
  8857. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8858. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8859. return;
  8860. }
  8861.  
  8862. await Send(JSON.stringify({ calls })).then(e => {
  8863. if ('error' in e) {
  8864. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8865. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8866. } else {
  8867. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  8868. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  8869. }
  8870. });
  8871. }
  8872.  
  8873. function getQuestionInfo(img, nameOnly = false) {
  8874. const libHeroes = Object.values(lib.data.hero);
  8875. const parts = img.split(':');
  8876. const id = parts[1];
  8877. switch (parts[0]) {
  8878. case 'titanArtifact_id':
  8879. return cheats.translate("LIB_TITAN_ARTIFACT_NAME_" + id);
  8880. case 'titan':
  8881. return cheats.translate("LIB_HERO_NAME_" + id);
  8882. case 'skill':
  8883. return cheats.translate("LIB_SKILL_" + id);
  8884. case 'inventoryItem_gear':
  8885. return cheats.translate("LIB_GEAR_NAME_" + id);
  8886. case 'inventoryItem_coin':
  8887. return cheats.translate("LIB_COIN_NAME_" + id);
  8888. case 'artifact':
  8889. if (nameOnly) {
  8890. return cheats.translate("LIB_ARTIFACT_NAME_" + id);
  8891. }
  8892. heroes = libHeroes.filter(h => h.id < 100 && h.artifacts.includes(+id));
  8893. return {
  8894. /** Как называется этот артефакт? */
  8895. name: cheats.translate("LIB_ARTIFACT_NAME_" + id),
  8896. /** Какому герою принадлежит этот артефакт? */
  8897. heroes: heroes.map(h => cheats.translate("LIB_HERO_NAME_" + h.id))
  8898. };
  8899. case 'hero':
  8900. if (nameOnly) {
  8901. return cheats.translate("LIB_HERO_NAME_" + id);
  8902. }
  8903. artifacts = lib.data.hero[id].artifacts;
  8904. return {
  8905. /** Как зовут этого героя? */
  8906. name: cheats.translate("LIB_HERO_NAME_" + id),
  8907. /** Какой артефакт принадлежит этому герою? */
  8908. artifact: artifacts.map(a => cheats.translate("LIB_ARTIFACT_NAME_" + a))
  8909. };
  8910. }
  8911. }
  8912.  
  8913. function hintQuest(quest) {
  8914. const result = {};
  8915. if (quest?.questionIcon) {
  8916. const info = getQuestionInfo(quest.questionIcon);
  8917. if (info?.heroes) {
  8918. /** Какому герою принадлежит этот артефакт? */
  8919. result.answer = quest.answers.filter(e => info.heroes.includes(e.answerText.slice(1)));
  8920. }
  8921. if (info?.artifact) {
  8922. /** Какой артефакт принадлежит этому герою? */
  8923. result.answer = quest.answers.filter(e => info.artifact.includes(e.answerText.slice(1)));
  8924. }
  8925. if (typeof info == 'string') {
  8926. result.info = { name: info };
  8927. } else {
  8928. result.info = info;
  8929. }
  8930. }
  8931.  
  8932. if (quest.answers[0]?.answerIcon) {
  8933. result.answer = quest.answers.filter(e => quest.question.includes(getQuestionInfo(e.answerIcon, true)))
  8934. }
  8935.  
  8936. if ((!result?.answer || !result.answer.length) && !result.info?.name) {
  8937. return false;
  8938. }
  8939.  
  8940. let resultText = '';
  8941. if (result?.info) {
  8942. resultText += I18N('PICTURE') + result.info.name;
  8943. }
  8944. console.log(result);
  8945. if (result?.answer && result.answer.length) {
  8946. resultText += I18N('ANSWER') + result.answer[0].id + (!result.answer[0].answerIcon ? ' - ' + result.answer[0].answerText : '');
  8947. }
  8948.  
  8949. return resultText;
  8950. }
  8951.  
  8952. /**
  8953. * Attack of the minions of Asgard
  8954. *
  8955. * Атака прислужников Асгарда
  8956. */
  8957. function testRaidNodes() {
  8958. return new Promise((resolve, reject) => {
  8959. const tower = new executeRaidNodes(resolve, reject);
  8960. tower.start();
  8961. });
  8962. }
  8963.  
  8964. /**
  8965. * Attack of the minions of Asgard
  8966. *
  8967. * Атака прислужников Асгарда
  8968. */
  8969. function executeRaidNodes(resolve, reject) {
  8970. let raidData = {
  8971. teams: [],
  8972. favor: {},
  8973. nodes: [],
  8974. attempts: 0,
  8975. countExecuteBattles: 0,
  8976. cancelBattle: 0,
  8977. }
  8978.  
  8979. callsExecuteRaidNodes = {
  8980. calls: [{
  8981. name: "clanRaid_getInfo",
  8982. args: {},
  8983. ident: "clanRaid_getInfo"
  8984. }, {
  8985. name: "teamGetAll",
  8986. args: {},
  8987. ident: "teamGetAll"
  8988. }, {
  8989. name: "teamGetFavor",
  8990. args: {},
  8991. ident: "teamGetFavor"
  8992. }]
  8993. }
  8994.  
  8995. this.start = function () {
  8996. send(JSON.stringify(callsExecuteRaidNodes), startRaidNodes);
  8997. }
  8998.  
  8999. async function startRaidNodes(data) {
  9000. res = data.results;
  9001. clanRaidInfo = res[0].result.response;
  9002. teamGetAll = res[1].result.response;
  9003. teamGetFavor = res[2].result.response;
  9004.  
  9005. let index = 0;
  9006. let isNotFullPack = false;
  9007. for (let team of teamGetAll.clanRaid_nodes) {
  9008. if (team.length < 6) {
  9009. isNotFullPack = true;
  9010. }
  9011. raidData.teams.push({
  9012. data: {},
  9013. heroes: team.filter(id => id < 6000),
  9014. pet: team.filter(id => id >= 6000).pop(),
  9015. battleIndex: index++
  9016. });
  9017. }
  9018. raidData.favor = teamGetFavor.clanRaid_nodes;
  9019.  
  9020. if (isNotFullPack) {
  9021. if (await popup.confirm(I18N('MINIONS_WARNING'), [
  9022. { msg: I18N('BTN_NO'), result: true },
  9023. { msg: I18N('BTN_YES'), result: false },
  9024. ])) {
  9025. endRaidNodes('isNotFullPack');
  9026. return;
  9027. }
  9028. }
  9029.  
  9030. raidData.nodes = clanRaidInfo.nodes;
  9031. raidData.attempts = clanRaidInfo.attempts;
  9032. isCancalBattle = false;
  9033.  
  9034. checkNodes();
  9035. }
  9036.  
  9037. function getAttackNode() {
  9038. for (let nodeId in raidData.nodes) {
  9039. let node = raidData.nodes[nodeId];
  9040. let points = 0
  9041. for (team of node.teams) {
  9042. points += team.points;
  9043. }
  9044. let now = Date.now() / 1000;
  9045. if (!points && now > node.timestamps.start && now < node.timestamps.end) {
  9046. let countTeam = node.teams.length;
  9047. delete raidData.nodes[nodeId];
  9048. return {
  9049. nodeId,
  9050. countTeam
  9051. };
  9052. }
  9053. }
  9054. return null;
  9055. }
  9056.  
  9057. function checkNodes() {
  9058. setProgress(`${I18N('REMAINING_ATTEMPTS')}: ${raidData.attempts}`);
  9059. let nodeInfo = getAttackNode();
  9060. if (nodeInfo && raidData.attempts) {
  9061. startNodeBattles(nodeInfo);
  9062. return;
  9063. }
  9064.  
  9065. endRaidNodes('EndRaidNodes');
  9066. }
  9067.  
  9068. function startNodeBattles(nodeInfo) {
  9069. let {nodeId, countTeam} = nodeInfo;
  9070. let teams = raidData.teams.slice(0, countTeam);
  9071. let heroes = raidData.teams.map(e => e.heroes).flat();
  9072. let favor = {...raidData.favor};
  9073. for (let heroId in favor) {
  9074. if (!heroes.includes(+heroId)) {
  9075. delete favor[heroId];
  9076. }
  9077. }
  9078.  
  9079. let calls = [{
  9080. name: "clanRaid_startNodeBattles",
  9081. args: {
  9082. nodeId,
  9083. teams,
  9084. favor
  9085. },
  9086. ident: "body"
  9087. }];
  9088.  
  9089. send(JSON.stringify({calls}), resultNodeBattles);
  9090. }
  9091.  
  9092. function resultNodeBattles(e) {
  9093. if (e['error']) {
  9094. endRaidNodes('nodeBattlesError', e['error']);
  9095. return;
  9096. }
  9097.  
  9098. console.log(e);
  9099. let battles = e.results[0].result.response.battles;
  9100. let promises = [];
  9101. let battleIndex = 0;
  9102. for (let battle of battles) {
  9103. battle.battleIndex = battleIndex++;
  9104. promises.push(calcBattleResult(battle));
  9105. }
  9106.  
  9107. Promise.all(promises)
  9108. .then(results => {
  9109. const endResults = {};
  9110. let isAllWin = true;
  9111. for (let r of results) {
  9112. isAllWin &&= r.result.win;
  9113. }
  9114. if (!isAllWin) {
  9115. cancelEndNodeBattle(results[0]);
  9116. return;
  9117. }
  9118. raidData.countExecuteBattles = results.length;
  9119. let timeout = 500;
  9120. for (let r of results) {
  9121. setTimeout(endNodeBattle, timeout, r);
  9122. timeout += 500;
  9123. }
  9124. });
  9125. }
  9126. /**
  9127. * Returns the battle calculation promise
  9128. *
  9129. * Возвращает промис расчета боя
  9130. */
  9131. function calcBattleResult(battleData) {
  9132. return new Promise(function (resolve, reject) {
  9133. BattleCalc(battleData, "get_clanPvp", resolve);
  9134. });
  9135. }
  9136. /**
  9137. * Cancels the fight
  9138. *
  9139. * Отменяет бой
  9140. */
  9141. function cancelEndNodeBattle(r) {
  9142. const fixBattle = function (heroes) {
  9143. for (const ids in heroes) {
  9144. hero = heroes[ids];
  9145. hero.energy = random(1, 999);
  9146. if (hero.hp > 0) {
  9147. hero.hp = random(1, hero.hp);
  9148. }
  9149. }
  9150. }
  9151. fixBattle(r.progress[0].attackers.heroes);
  9152. fixBattle(r.progress[0].defenders.heroes);
  9153. endNodeBattle(r);
  9154. }
  9155. /**
  9156. * Ends the fight
  9157. *
  9158. * Завершает бой
  9159. */
  9160. function endNodeBattle(r) {
  9161. let nodeId = r.battleData.result.nodeId;
  9162. let battleIndex = r.battleData.battleIndex;
  9163. let calls = [{
  9164. name: "clanRaid_endNodeBattle",
  9165. args: {
  9166. nodeId,
  9167. battleIndex,
  9168. result: r.result,
  9169. progress: r.progress
  9170. },
  9171. ident: "body"
  9172. }]
  9173.  
  9174. SendRequest(JSON.stringify({calls}), battleResult);
  9175. }
  9176. /**
  9177. * Processing the results of the battle
  9178. *
  9179. * Обработка результатов боя
  9180. */
  9181. function battleResult(e) {
  9182. if (e['error']) {
  9183. endRaidNodes('missionEndError', e['error']);
  9184. return;
  9185. }
  9186. r = e.results[0].result.response;
  9187. if (r['error']) {
  9188. if (r.reason == "invalidBattle") {
  9189. raidData.cancelBattle++;
  9190. checkNodes();
  9191. } else {
  9192. endRaidNodes('missionEndError', e['error']);
  9193. }
  9194. return;
  9195. }
  9196.  
  9197. if (!(--raidData.countExecuteBattles)) {
  9198. raidData.attempts--;
  9199. checkNodes();
  9200. }
  9201. }
  9202. /**
  9203. * Completing a task
  9204. *
  9205. * Завершение задачи
  9206. */
  9207. function endRaidNodes(reason, info) {
  9208. isCancalBattle = true;
  9209. let textCancel = raidData.cancelBattle ? ` ${I18N('BATTLES_CANCELED')}: ${raidData.cancelBattle}` : '';
  9210. setProgress(`${I18N('MINION_RAID')} ${I18N('COMPLETED')}! ${textCancel}`, true);
  9211. console.log(reason, info);
  9212. resolve();
  9213. }
  9214. }
  9215.  
  9216. /**
  9217. * Asgard Boss Attack Replay
  9218. *
  9219. * Повтор атаки босса Асгарда
  9220. */
  9221. function testBossBattle() {
  9222. return new Promise((resolve, reject) => {
  9223. const bossBattle = new executeBossBattle(resolve, reject);
  9224. bossBattle.start(lastBossBattle, lastBossBattleInfo);
  9225. });
  9226. }
  9227.  
  9228. /**
  9229. * Asgard Boss Attack Replay
  9230. *
  9231. * Повтор атаки босса Асгарда
  9232. */
  9233. function executeBossBattle(resolve, reject) {
  9234. let lastBossBattleArgs = {};
  9235. let reachDamage = 0;
  9236. let countBattle = 0;
  9237. let countMaxBattle = 10;
  9238. let lastDamage = 0;
  9239.  
  9240. this.start = function (battleArg, battleInfo) {
  9241. lastBossBattleArgs = battleArg;
  9242. preCalcBattle(battleInfo);
  9243. }
  9244.  
  9245. function getBattleInfo(battle) {
  9246. return new Promise(function (resolve) {
  9247. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  9248. BattleCalc(battle, getBattleType(battle.type), e => {
  9249. let extra = e.progress[0].defenders.heroes[1].extra;
  9250. resolve(extra.damageTaken + extra.damageTakenNextLevel);
  9251. });
  9252. });
  9253. }
  9254.  
  9255. function preCalcBattle(battle) {
  9256. let actions = [];
  9257. const countTestBattle = getInput('countTestBattle');
  9258. for (let i = 0; i < countTestBattle; i++) {
  9259. actions.push(getBattleInfo(battle, true));
  9260. }
  9261. Promise.all(actions)
  9262. .then(resultPreCalcBattle);
  9263. }
  9264.  
  9265. function fixDamage(damage) {
  9266. for (let i = 1e6; i > 1; i /= 10) {
  9267. if (damage > i) {
  9268. let n = i / 10;
  9269. damage = Math.ceil(damage / n) * n;
  9270. break;
  9271. }
  9272. }
  9273. return damage;
  9274. }
  9275.  
  9276. async function resultPreCalcBattle(damages) {
  9277. let maxDamage = 0;
  9278. let minDamage = 1e10;
  9279. let avgDamage = 0;
  9280. for (let damage of damages) {
  9281. avgDamage += damage
  9282. if (damage > maxDamage) {
  9283. maxDamage = damage;
  9284. }
  9285. if (damage < minDamage) {
  9286. minDamage = damage;
  9287. }
  9288. }
  9289. avgDamage /= damages.length;
  9290. console.log(damages.map(e => e.toLocaleString()).join('\n'), avgDamage, maxDamage);
  9291.  
  9292. reachDamage = fixDamage(avgDamage);
  9293. const result = await popup.confirm(
  9294. `${I18N('ROUND_STAT')} ${damages.length} ${I18N('BATTLE')}:` +
  9295. `<br>${I18N('MINIMUM')}: ` + minDamage.toLocaleString() +
  9296. `<br>${I18N('MAXIMUM')}: ` + maxDamage.toLocaleString() +
  9297. `<br>${I18N('AVERAGE')}: ` + avgDamage.toLocaleString()
  9298. /*+ '<br>Поиск урона больше чем ' + reachDamage.toLocaleString()*/
  9299. , [
  9300. { msg: I18N('BTN_OK'), result: 0},
  9301. /* {msg: 'Погнали', isInput: true, default: reachDamage}, */
  9302. ])
  9303. if (result) {
  9304. reachDamage = result;
  9305. isCancalBossBattle = false;
  9306. startBossBattle();
  9307. return;
  9308. }
  9309. endBossBattle(I18N('BTN_CANCEL'));
  9310. }
  9311.  
  9312. function startBossBattle() {
  9313. countBattle++;
  9314. countMaxBattle = getInput('countAutoBattle');
  9315. if (countBattle > countMaxBattle) {
  9316. setProgress('Превышен лимит попыток: ' + countMaxBattle, true);
  9317. endBossBattle('Превышен лимит попыток: ' + countMaxBattle);
  9318. return;
  9319. }
  9320. let calls = [{
  9321. name: "clanRaid_startBossBattle",
  9322. args: lastBossBattleArgs,
  9323. ident: "body"
  9324. }];
  9325. send(JSON.stringify({calls}), calcResultBattle);
  9326. }
  9327.  
  9328. function calcResultBattle(e) {
  9329. BattleCalc(e.results[0].result.response.battle, "get_clanPvp", resultBattle);
  9330. }
  9331.  
  9332. async function resultBattle(e) {
  9333. let extra = e.progress[0].defenders.heroes[1].extra
  9334. resultDamage = extra.damageTaken + extra.damageTakenNextLevel
  9335. console.log(resultDamage);
  9336. scriptMenu.setStatus(countBattle + ') ' + resultDamage.toLocaleString());
  9337. lastDamage = resultDamage;
  9338. if (resultDamage > reachDamage && await popup.confirm(countBattle + ') Урон ' + resultDamage.toLocaleString(), [
  9339. {msg: 'Ок', result: true},
  9340. {msg: 'Не пойдет', result: false},
  9341. ])) {
  9342. endBattle(e, false);
  9343. return;
  9344. }
  9345. cancelEndBattle(e);
  9346. }
  9347.  
  9348. function cancelEndBattle (r) {
  9349. const fixBattle = function (heroes) {
  9350. for (const ids in heroes) {
  9351. hero = heroes[ids];
  9352. hero.energy = random(1, 999);
  9353. if (hero.hp > 0) {
  9354. hero.hp = random(1, hero.hp);
  9355. }
  9356. }
  9357. }
  9358. fixBattle(r.progress[0].attackers.heroes);
  9359. fixBattle(r.progress[0].defenders.heroes);
  9360. endBattle(r, true);
  9361. }
  9362.  
  9363. function endBattle(battleResult, isCancal) {
  9364. let calls = [{
  9365. name: "clanRaid_endBossBattle",
  9366. args: {
  9367. result: battleResult.result,
  9368. progress: battleResult.progress
  9369. },
  9370. ident: "body"
  9371. }];
  9372.  
  9373. send(JSON.stringify({calls}), e => {
  9374. console.log(e);
  9375. if (isCancal) {
  9376. startBossBattle();
  9377. return;
  9378. }
  9379. scriptMenu.setStatus('Босс пробит нанесен урон: ' + lastDamage);
  9380. setTimeout(() => {
  9381. scriptMenu.setStatus('');
  9382. }, 5000);
  9383. endBossBattle('Узпех!');
  9384. });
  9385. }
  9386.  
  9387. /**
  9388. * Completing a task
  9389. *
  9390. * Завершение задачи
  9391. */
  9392. function endBossBattle(reason, info) {
  9393. isCancalBossBattle = true;
  9394. console.log(reason, info);
  9395. resolve();
  9396. }
  9397. }
  9398.  
  9399. /**
  9400. * Auto-repeat attack
  9401. *
  9402. * Автоповтор атаки
  9403. */
  9404. function testAutoBattle() {
  9405. return new Promise((resolve, reject) => {
  9406. const bossBattle = new executeAutoBattle(resolve, reject);
  9407. bossBattle.start(lastBattleArg, lastBattleInfo);
  9408. });
  9409. }
  9410.  
  9411. /**
  9412. * Auto-repeat attack
  9413. *
  9414. * Автоповтор атаки
  9415. */
  9416. function executeAutoBattle(resolve, reject) {
  9417. let battleArg = {};
  9418. let countBattle = 0;
  9419. let countError = 0;
  9420. let findCoeff = 0;
  9421. 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>';
  9422. 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>';
  9423. 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>';
  9424.  
  9425. this.start = function (battleArgs, battleInfo) {
  9426. battleArg = battleArgs;
  9427. preCalcBattle(battleInfo);
  9428. }
  9429. /**
  9430. * Returns a promise for combat recalculation
  9431. *
  9432. * Возвращает промис для прерасчета боя
  9433. */
  9434. function getBattleInfo(battle) {
  9435. return new Promise(function (resolve) {
  9436. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  9437. Calc(battle).then(e => {
  9438. e.coeff = calcCoeff(e, 'defenders');
  9439. resolve(e);
  9440. });
  9441. });
  9442. }
  9443. /**
  9444. * Battle recalculation
  9445. *
  9446. * Прерасчет боя
  9447. */
  9448. function preCalcBattle(battle) {
  9449. let actions = [];
  9450. const countTestBattle = getInput('countTestBattle');
  9451. for (let i = 0; i < countTestBattle; i++) {
  9452. actions.push(getBattleInfo(battle));
  9453. }
  9454. Promise.all(actions)
  9455. .then(resultPreCalcBattle);
  9456. }
  9457. /**
  9458. * Processing the results of the battle recalculation
  9459. *
  9460. * Обработка результатов прерасчета боя
  9461. */
  9462. async function resultPreCalcBattle(results) {
  9463. let countWin = results.reduce((s, w) => w.result.win + s, 0);
  9464. setProgress(`${I18N('CHANCE_TO_WIN')} ${Math.floor(countWin / results.length * 100)}% (${results.length})`, false, hideProgress);
  9465. if (countWin > 0) {
  9466. isCancalBattle = false;
  9467. startBattle();
  9468. return;
  9469. }
  9470.  
  9471. let minCoeff = 100;
  9472. let maxCoeff = -100;
  9473. let avgCoeff = 0;
  9474. results.forEach(e => {
  9475. if (e.coeff < minCoeff) minCoeff = e.coeff;
  9476. if (e.coeff > maxCoeff) maxCoeff = e.coeff;
  9477. avgCoeff += e.coeff;
  9478. });
  9479. avgCoeff /= results.length;
  9480.  
  9481. if (nameFuncStartBattle == 'invasion_bossStart' ||
  9482. nameFuncStartBattle == 'bossAttack') {
  9483. const result = await popup.confirm(
  9484. I18N('BOSS_VICTORY_IMPOSSIBLE', { battles: results.length }), [
  9485. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  9486. { msg: I18N('BTN_DO_IT'), result: true },
  9487. ])
  9488. if (result) {
  9489. isCancalBattle = false;
  9490. startBattle();
  9491. return;
  9492. }
  9493. setProgress(I18N('NOT_THIS_TIME'), true);
  9494. endAutoBattle('invasion_bossStart');
  9495. return;
  9496. }
  9497.  
  9498. const result = await popup.confirm(
  9499. I18N('VICTORY_IMPOSSIBLE') +
  9500. `<br>${I18N('ROUND_STAT')} ${results.length} ${I18N('BATTLE')}:` +
  9501. `<br>${I18N('MINIMUM')}: ` + minCoeff.toLocaleString() +
  9502. `<br>${I18N('MAXIMUM')}: ` + maxCoeff.toLocaleString() +
  9503. `<br>${I18N('AVERAGE')}: ` + avgCoeff.toLocaleString() +
  9504. `<br>${I18N('FIND_COEFF')} ` + avgCoeff.toLocaleString(), [
  9505. { msg: I18N('BTN_CANCEL'), result: 0, isCancel: true },
  9506. { msg: I18N('BTN_GO'), isInput: true, default: Math.round(avgCoeff * 1000) / 1000 },
  9507. ])
  9508. if (result) {
  9509. findCoeff = result;
  9510. isCancalBattle = false;
  9511. startBattle();
  9512. return;
  9513. }
  9514. setProgress(I18N('NOT_THIS_TIME'), true);
  9515. endAutoBattle(I18N('NOT_THIS_TIME'));
  9516. }
  9517.  
  9518. /**
  9519. * Calculation of the combat result coefficient
  9520. *
  9521. * Расчет коэфициента результата боя
  9522. */
  9523. function calcCoeff(result, packType) {
  9524. let beforeSumFactor = 0;
  9525. const beforePack = result.battleData[packType][0];
  9526. for (let heroId in beforePack) {
  9527. const hero = beforePack[heroId];
  9528. const state = hero.state;
  9529. let factor = 1;
  9530. if (state) {
  9531. const hp = state.hp / state.maxHp;
  9532. const energy = state.energy / 1e3;
  9533. factor = hp + energy / 20;
  9534. }
  9535. beforeSumFactor += factor;
  9536. }
  9537.  
  9538. let afterSumFactor = 0;
  9539. const afterPack = result.progress[0][packType].heroes;
  9540. for (let heroId in afterPack) {
  9541. const hero = afterPack[heroId];
  9542. const stateHp = beforePack[heroId]?.state?.hp || beforePack[heroId]?.stats?.hp;
  9543. const hp = hero.hp / stateHp;
  9544. const energy = hero.energy / 1e3;
  9545. const factor = hp + energy / 20;
  9546. afterSumFactor += factor;
  9547. }
  9548. const resultCoeff = -(afterSumFactor - beforeSumFactor);
  9549. return Math.round(resultCoeff * 1000) / 1000;
  9550. }
  9551. /**
  9552. * Start battle
  9553. *
  9554. * Начало боя
  9555. */
  9556. function startBattle() {
  9557. countBattle++;
  9558. const countMaxBattle = getInput('countAutoBattle');
  9559. // setProgress(countBattle + '/' + countMaxBattle);
  9560. if (countBattle > countMaxBattle) {
  9561. setProgress(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`, true);
  9562. endAutoBattle(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`)
  9563. return;
  9564. }
  9565. send({calls: [{
  9566. name: nameFuncStartBattle,
  9567. args: battleArg,
  9568. ident: "body"
  9569. }]}, calcResultBattle);
  9570. }
  9571. /**
  9572. * Battle calculation
  9573. *
  9574. * Расчет боя
  9575. */
  9576. async function calcResultBattle(e) {
  9577. if ('error' in e) {
  9578. if (e.error.description === 'too many tries') {
  9579. invasionTimer += 100;
  9580. countBattle--;
  9581. countError++;
  9582. console.log(`Errors: ${countError}`, e.error);
  9583. startBattle();
  9584. return;
  9585. }
  9586. const result = await popup.confirm(I18N('ERROR_DURING_THE_BATTLE') + '<br>' + e.error.description, [
  9587. { msg: I18N('BTN_OK'), result: false },
  9588. { msg: I18N('RELOAD_GAME'), result: true },
  9589. ]);
  9590. endAutoBattle('Error', e.error);
  9591. if (result) {
  9592. location.reload();
  9593. }
  9594. return;
  9595. }
  9596. let battle = e.results[0].result.response.battle
  9597. if (nameFuncStartBattle == 'towerStartBattle' ||
  9598. nameFuncStartBattle == 'bossAttack' ||
  9599. nameFuncStartBattle == 'invasion_bossStart') {
  9600. battle = e.results[0].result.response;
  9601. }
  9602. lastBattleInfo = battle;
  9603. BattleCalc(battle, getBattleType(battle.type), resultBattle);
  9604. }
  9605. /**
  9606. * Processing the results of the battle
  9607. *
  9608. * Обработка результатов боя
  9609. */
  9610. function resultBattle(e) {
  9611. const isWin = e.result.win;
  9612. if (isWin) {
  9613. endBattle(e, false);
  9614. return;
  9615. }
  9616. const countMaxBattle = getInput('countAutoBattle');
  9617. if (findCoeff) {
  9618. const coeff = calcCoeff(e, 'defenders');
  9619. setProgress(`${countBattle}/${countMaxBattle}, ${coeff}`);
  9620. if (coeff > findCoeff) {
  9621. endBattle(e, false);
  9622. return;
  9623. }
  9624. } else {
  9625. if (nameFuncStartBattle == 'invasion_bossStart') {
  9626. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  9627. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageMod_any_99_100_300_99_1000 || 0;
  9628. setProgress(`${svgBoss} ${bossLvl} ${svgJustice} ${justice} <br>${svgAttempt} ${countBattle}/${countMaxBattle}`);
  9629. } else {
  9630. setProgress(`${countBattle}/${countMaxBattle}`);
  9631. }
  9632. }
  9633. if (nameFuncStartBattle == 'towerStartBattle' ||
  9634. nameFuncStartBattle == 'bossAttack' ||
  9635. nameFuncStartBattle == 'invasion_bossStart') {
  9636. startBattle();
  9637. return;
  9638. }
  9639. cancelEndBattle(e);
  9640. }
  9641. /**
  9642. * Cancel fight
  9643. *
  9644. * Отмена боя
  9645. */
  9646. function cancelEndBattle(r) {
  9647. const fixBattle = function (heroes) {
  9648. for (const ids in heroes) {
  9649. hero = heroes[ids];
  9650. hero.energy = random(1, 999);
  9651. if (hero.hp > 0) {
  9652. hero.hp = random(1, hero.hp);
  9653. }
  9654. }
  9655. }
  9656. fixBattle(r.progress[0].attackers.heroes);
  9657. fixBattle(r.progress[0].defenders.heroes);
  9658. endBattle(r, true);
  9659. }
  9660. /**
  9661. * End of the fight
  9662. *
  9663. * Завершение боя */
  9664. function endBattle(battleResult, isCancal) {
  9665. let calls = [{
  9666. name: nameFuncEndBattle,
  9667. args: {
  9668. result: battleResult.result,
  9669. progress: battleResult.progress
  9670. },
  9671. ident: "body"
  9672. }];
  9673.  
  9674. if (nameFuncStartBattle == 'invasion_bossStart') {
  9675. calls[0].args.id = lastBattleArg.id;
  9676. }
  9677.  
  9678. send(JSON.stringify({
  9679. calls
  9680. }), async e => {
  9681. console.log(e);
  9682. if (isCancal) {
  9683. startBattle();
  9684. return;
  9685. }
  9686.  
  9687. setProgress(`${I18N('SUCCESS')}!`, 5000)
  9688. if (nameFuncStartBattle == 'invasion_bossStart' ||
  9689. nameFuncStartBattle == 'bossAttack') {
  9690. const countMaxBattle = getInput('countAutoBattle');
  9691. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  9692. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageMod_any_99_100_300_99_1000 || 0;
  9693. const result = await popup.confirm(
  9694. I18N('BOSS_HAS_BEEN_DEF_TEXT', {
  9695. bossLvl: `${svgBoss} ${bossLvl} ${svgJustice} ${justice}`,
  9696. countBattle: svgAttempt + ' ' + countBattle,
  9697. countMaxBattle,}),
  9698. [
  9699. { msg: I18N('BTN_OK'), result: 0 },
  9700. { msg: I18N('MAKE_A_SYNC'), result: 1 },
  9701. { msg: I18N('RELOAD_GAME'), result: 2 },
  9702. ]);
  9703. if (result) {
  9704. if (result == 1) {
  9705. cheats.refreshGame();
  9706. }
  9707. if (result == 2) {
  9708. location.reload();
  9709. }
  9710. }
  9711.  
  9712. }
  9713. endAutoBattle(`${I18N('SUCCESS')}!`)
  9714. });
  9715. }
  9716. /**
  9717. * Completing a task
  9718. *
  9719. * Завершение задачи
  9720. */
  9721. function endAutoBattle(reason, info) {
  9722. isCancalBattle = true;
  9723. console.log(reason, info);
  9724. resolve();
  9725. }
  9726. }
  9727.  
  9728. function testDailyQuests() {
  9729. return new Promise((resolve, reject) => {
  9730. const quests = new dailyQuests(resolve, reject);
  9731. quests.init(questsInfo);
  9732. quests.start();
  9733. });
  9734. }
  9735.  
  9736. /**
  9737. * Automatic completion of daily quests
  9738. *
  9739. * Автоматическое выполнение ежедневных квестов
  9740. */
  9741. class dailyQuests {
  9742. /**
  9743. * Send(' {"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}').then(e => console.log(e))
  9744. * Send(' {"calls":[{"name":"heroGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  9745. * Send(' {"calls":[{"name":"titanGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  9746. * Send(' {"calls":[{"name":"inventoryGet","args":{},"ident":"body"}]}').then(e => console.log(e))
  9747. * Send(' {"calls":[{"name":"questGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  9748. * Send(' {"calls":[{"name":"bossGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  9749. */
  9750. callsList = [
  9751. "userGetInfo",
  9752. "heroGetAll",
  9753. "titanGetAll",
  9754. "inventoryGet",
  9755. "questGetAll",
  9756. "bossGetAll",
  9757. ]
  9758.  
  9759. dataQuests = {
  9760. 10001: {
  9761. description: 'Улучши умения героев 3 раза', // ++++++++++++++++
  9762. doItCall: () => {
  9763. const upgradeSkills = this.getUpgradeSkills();
  9764. return upgradeSkills.map(({ heroId, skill }, index) => ({ name: "heroUpgradeSkill", args: { heroId, skill }, "ident": `heroUpgradeSkill_${index}` }));
  9765. },
  9766. isWeCanDo: () => {
  9767. const upgradeSkills = this.getUpgradeSkills();
  9768. let sumGold = 0;
  9769. for (const skill of upgradeSkills) {
  9770. sumGold += this.skillCost(skill.value);
  9771. if (!skill.heroId) {
  9772. return false;
  9773. }
  9774. }
  9775. return this.questInfo['userGetInfo'].gold > sumGold;
  9776. },
  9777. },
  9778. 10002: {
  9779. description: 'Пройди 10 миссий', // --------------
  9780. isWeCanDo: () => false,
  9781. },
  9782. 10003: {
  9783. description: 'Пройди 3 героические миссии', // --------------
  9784. isWeCanDo: () => false,
  9785. },
  9786. 10004: {
  9787. description: 'Сразись 3 раза на Арене или Гранд Арене', // --------------
  9788. isWeCanDo: () => false,
  9789. },
  9790. 10006: {
  9791. description: 'Используй обмен изумрудов 1 раз', // ++++++++++++++++
  9792. doItCall: () => [{
  9793. name: "refillableAlchemyUse",
  9794. args: { multi: false },
  9795. ident: "refillableAlchemyUse"
  9796. }],
  9797. isWeCanDo: () => {
  9798. const starMoney = this.questInfo['userGetInfo'].starMoney;
  9799. return starMoney >= 20;
  9800. },
  9801. },
  9802. 10007: {
  9803. description: 'Соверши 1 призыв в Атриуме Душ', // ++++++++++++++++
  9804. doItCall: () => [{ name: "gacha_open", args: { ident: "heroGacha", free: true, pack: false }, ident: "gacha_open" }],
  9805. isWeCanDo: () => {
  9806. const soulCrystal = this.questInfo['inventoryGet'].coin[38];
  9807. return soulCrystal > 0;
  9808. },
  9809. },
  9810. /*10016: {
  9811. description: 'Отправь подарки согильдийцам', // ++++++++++++++++
  9812. doItCall: () => [{ name: "clanSendDailyGifts", args: {}, ident: "clanSendDailyGifts" }],
  9813. isWeCanDo: () => true,
  9814. },*/
  9815. 10018: {
  9816. description: 'Используй зелье опыта', // ++++++++++++++++
  9817. doItCall: () => {
  9818. const expHero = this.getExpHero();
  9819. return [{
  9820. name: "consumableUseHeroXp",
  9821. args: {
  9822. heroId: expHero.heroId,
  9823. libId: expHero.libId,
  9824. amount: 1
  9825. },
  9826. ident: "consumableUseHeroXp"
  9827. }];
  9828. },
  9829. isWeCanDo: () => {
  9830. const expHero = this.getExpHero();
  9831. return expHero.heroId && expHero.libId;
  9832. },
  9833. },
  9834. 10019: {
  9835. description: 'Открой 1 сундук в Башне',
  9836. doItFunc: testTower,
  9837. isWeCanDo: () => false,
  9838. },
  9839. 10020: {
  9840. description: 'Открой 3 сундука в Запределье', // Готово
  9841. doItCall: () => {
  9842. return this.getOutlandChest();
  9843. },
  9844. isWeCanDo: () => {
  9845. const outlandChest = this.getOutlandChest();
  9846. return outlandChest.length > 0;
  9847. },
  9848. },
  9849. 10021: {
  9850. description: 'Собери 75 Титанита в Подземелье Гильдии',
  9851. isWeCanDo: () => false,
  9852. },
  9853. 10022: {
  9854. description: 'Собери 150 Титанита в Подземелье Гильдии',
  9855. doItFunc: testDungeon,
  9856. isWeCanDo: () => false,
  9857. },
  9858. 10023: {
  9859. description: 'Прокачай Дар Стихий на 1 уровень', // Готово
  9860. doItCall: () => {
  9861. const heroId = this.getHeroIdTitanGift();
  9862. return [
  9863. { name: "heroTitanGiftLevelUp", args: { heroId }, ident: "heroTitanGiftLevelUp" },
  9864. { name: "heroTitanGiftDrop", args: { heroId }, ident: "heroTitanGiftDrop" }
  9865. ]
  9866. },
  9867. isWeCanDo: () => {
  9868. const heroId = this.getHeroIdTitanGift();
  9869. return heroId;
  9870. },
  9871. },
  9872. 10024: {
  9873. description: 'Повысь уровень любого артефакта один раз', // Готово
  9874. doItCall: () => {
  9875. const upArtifact = this.getUpgradeArtifact();
  9876. return [
  9877. {
  9878. name: "heroArtifactLevelUp",
  9879. args: {
  9880. heroId: upArtifact.heroId,
  9881. slotId: upArtifact.slotId
  9882. },
  9883. ident: `heroArtifactLevelUp`
  9884. }
  9885. ];
  9886. },
  9887. isWeCanDo: () => {
  9888. const upgradeArtifact = this.getUpgradeArtifact();
  9889. return upgradeArtifact.heroId;
  9890. },
  9891. },
  9892. 10025: {
  9893. description: 'Начни 1 Экспедицию',
  9894. doItFunc: checkExpedition,
  9895. isWeCanDo: () => false,
  9896. },
  9897. 10026: {
  9898. description: 'Начни 4 Экспедиции', // --------------
  9899. doItFunc: checkExpedition,
  9900. isWeCanDo: () => false,
  9901. },
  9902. 10027: {
  9903. description: 'Победи в 1 бою Турнира Стихий',
  9904. doItFunc: testTitanArena,
  9905. isWeCanDo: () => false,
  9906. },
  9907. 10028: {
  9908. description: 'Повысь уровень любого артефакта титанов', // Готово
  9909. doItCall: () => {
  9910. const upTitanArtifact = this.getUpgradeTitanArtifact();
  9911. return [
  9912. {
  9913. name: "titanArtifactLevelUp",
  9914. args: {
  9915. titanId: upTitanArtifact.titanId,
  9916. slotId: upTitanArtifact.slotId
  9917. },
  9918. ident: `titanArtifactLevelUp`
  9919. }
  9920. ];
  9921. },
  9922. isWeCanDo: () => {
  9923. const upgradeTitanArtifact = this.getUpgradeTitanArtifact();
  9924. return upgradeTitanArtifact.titanId;
  9925. },
  9926. },
  9927. 10029: {
  9928. description: 'Открой сферу артефактов титанов', // ++++++++++++++++
  9929. doItCall: () => [{ name: "titanArtifactChestOpen", args: { amount: 1, free: true }, ident: "titanArtifactChestOpen" }],
  9930. isWeCanDo: () => {
  9931. return this.questInfo['inventoryGet']?.consumable[55] > 0
  9932. },
  9933. },
  9934. 10030: {
  9935. description: 'Улучши облик любого героя 1 раз', // Готово
  9936. doItCall: () => {
  9937. const upSkin = this.getUpgradeSkin();
  9938. return [
  9939. {
  9940. name: "heroSkinUpgrade",
  9941. args: {
  9942. heroId: upSkin.heroId,
  9943. skinId: upSkin.skinId
  9944. },
  9945. ident: `heroSkinUpgrade`
  9946. }
  9947. ];
  9948. },
  9949. isWeCanDo: () => {
  9950. const upgradeSkin = this.getUpgradeSkin();
  9951. return upgradeSkin.heroId;
  9952. },
  9953. },
  9954. 10031: {
  9955. description: 'Победи в 6 боях Турнира Стихий', // --------------
  9956. doItFunc: testTitanArena,
  9957. isWeCanDo: () => false,
  9958. },
  9959. 10043: {
  9960. description: 'Начни или присоеденись к Приключению', // --------------
  9961. isWeCanDo: () => false,
  9962. },
  9963. 10044: {
  9964. description: 'Воспользуйся призывом питомцев 1 раз', // ++++++++++++++++
  9965. doItCall: () => [{ name: "pet_chestOpen", args: { amount: 1, paid: false }, ident: "pet_chestOpen" }],
  9966. isWeCanDo: () => {
  9967. return this.questInfo['inventoryGet']?.consumable[90] > 0
  9968. },
  9969. },
  9970. 10046: {
  9971. /**
  9972. * TODO: Watch Adventure
  9973. * TODO: Смотреть приключение
  9974. */
  9975. description: 'Открой 3 сундука в Приключениях',
  9976. isWeCanDo: () => false,
  9977. },
  9978. 10047: {
  9979. description: 'Набери 150 очков активности в Гильдии', // Готово
  9980. doItCall: () => {
  9981. const enchantRune = this.getEnchantRune();
  9982. return [
  9983. {
  9984. name: "heroEnchantRune",
  9985. args: {
  9986. heroId: enchantRune.heroId,
  9987. tier: enchantRune.tier,
  9988. items: {
  9989. consumable: { [enchantRune.itemId]: 1 }
  9990. }
  9991. },
  9992. ident: `heroEnchantRune`
  9993. }
  9994. ];
  9995. },
  9996. isWeCanDo: () => {
  9997. const userInfo = this.questInfo['userGetInfo'];
  9998. const enchantRune = this.getEnchantRune();
  9999. return enchantRune.heroId && userInfo.gold > 1e3;
  10000. },
  10001. },
  10002. };
  10003.  
  10004. constructor(resolve, reject, questInfo) {
  10005. this.resolve = resolve;
  10006. this.reject = reject;
  10007. }
  10008.  
  10009. init(questInfo) {
  10010. this.questInfo = questInfo;
  10011. this.isAuto = false;
  10012. }
  10013.  
  10014. async autoInit(isAuto) {
  10015. this.isAuto = isAuto || false;
  10016. const quests = {};
  10017. const calls = this.callsList.map(name => ({
  10018. name, args: {}, ident: name
  10019. }))
  10020. const result = await Send(JSON.stringify({ calls })).then(e => e.results);
  10021. for (const call of result) {
  10022. quests[call.ident] = call.result.response;
  10023. }
  10024. this.questInfo = quests;
  10025. }
  10026.  
  10027. async start() {
  10028. /**
  10029. * TODO may not be needed
  10030. *
  10031. * TODO возожно не нужна
  10032. */
  10033. let countQuest = 0;
  10034. const weCanDo = [];
  10035. const selectedActions = getSaveVal('selectedActions', {});
  10036. for (let quest of this.questInfo['questGetAll']) {
  10037. if (quest.id in this.dataQuests && quest.state == 1) {
  10038. if (!selectedActions[quest.id]) {
  10039. selectedActions[quest.id] = {
  10040. checked: false
  10041. }
  10042. }
  10043.  
  10044. const isWeCanDo = this.dataQuests[quest.id].isWeCanDo;
  10045. if (!isWeCanDo.call(this)) {
  10046. continue;
  10047. }
  10048.  
  10049. weCanDo.push({
  10050. name: quest.id,
  10051. label: I18N(`QUEST_${quest.id}`),
  10052. checked: selectedActions[quest.id].checked
  10053. });
  10054. countQuest++;
  10055. }
  10056. }
  10057.  
  10058. if (!weCanDo.length) {
  10059. this.end(I18N('NOTHING_TO_DO'));
  10060. return;
  10061. }
  10062.  
  10063. console.log(weCanDo);
  10064. let taskList = [];
  10065. if (this.isAuto) {
  10066. taskList = weCanDo;
  10067. } else {
  10068. const answer = await popup.confirm(`${I18N('YOU_CAN_COMPLETE') }:`, [
  10069. { msg: I18N('BTN_DO_IT'), result: true },
  10070. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  10071. ], weCanDo);
  10072. if (!answer) {
  10073. this.end('');
  10074. return;
  10075. }
  10076. taskList = popup.getCheckBoxes();
  10077. taskList.forEach(e => {
  10078. selectedActions[e.name].checked = e.checked;
  10079. });
  10080. setSaveVal('selectedActions', selectedActions);
  10081. }
  10082.  
  10083. const calls = [];
  10084. let countChecked = 0;
  10085. for (const task of taskList) {
  10086. if (task.checked) {
  10087. countChecked++;
  10088. const quest = this.dataQuests[task.name]
  10089. console.log(quest.description);
  10090.  
  10091. if (quest.doItCall) {
  10092. const doItCall = quest.doItCall.call(this);
  10093. calls.push(...doItCall);
  10094. }
  10095. }
  10096. }
  10097.  
  10098. if (!countChecked) {
  10099. this.end(I18N('NOT_QUEST_COMPLETED'));
  10100. return;
  10101. }
  10102.  
  10103. const result = await Send(JSON.stringify({ calls }));
  10104. if (result.error) {
  10105. console.error(result.error, result.error.call)
  10106. }
  10107. this.end(`${I18N('COMPLETED_QUESTS')}: ${countChecked}`);
  10108. }
  10109.  
  10110. errorHandling(error) {
  10111. //console.error(error);
  10112. let errorInfo = error.toString() + '\n';
  10113. try {
  10114. const errorStack = error.stack.split('\n');
  10115. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  10116. errorInfo += errorStack.slice(0, endStack).join('\n');
  10117. } catch (e) {
  10118. errorInfo += error.stack;
  10119. }
  10120. copyText(errorInfo);
  10121. }
  10122.  
  10123. skillCost(lvl) {
  10124. return 573 * lvl ** 0.9 + lvl ** 2.379;
  10125. }
  10126.  
  10127. getUpgradeSkills() {
  10128. const heroes = Object.values(this.questInfo['heroGetAll']);
  10129. const upgradeSkills = [
  10130. { heroId: 0, slotId: 0, value: 130 },
  10131. { heroId: 0, slotId: 0, value: 130 },
  10132. { heroId: 0, slotId: 0, value: 130 },
  10133. ];
  10134. const skillLib = lib.getData('skill');
  10135. /**
  10136. * color - 1 (белый) открывает 1 навык
  10137. * color - 2 (зеленый) открывает 2 навык
  10138. * color - 4 (синий) открывает 3 навык
  10139. * color - 7 (фиолетовый) открывает 4 навык
  10140. */
  10141. const colors = [1, 2, 4, 7];
  10142. for (const hero of heroes) {
  10143. const level = hero.level;
  10144. const color = hero.color;
  10145. for (let skillId in hero.skills) {
  10146. const tier = skillLib[skillId].tier;
  10147. const sVal = hero.skills[skillId];
  10148. if (color < colors[tier] || tier < 1 || tier > 4) {
  10149. continue;
  10150. }
  10151. for (let upSkill of upgradeSkills) {
  10152. if (sVal < upSkill.value && sVal < level) {
  10153. upSkill.value = sVal;
  10154. upSkill.heroId = hero.id;
  10155. upSkill.skill = tier;
  10156. break;
  10157. }
  10158. }
  10159. }
  10160. }
  10161. return upgradeSkills;
  10162. }
  10163.  
  10164. getUpgradeArtifact() {
  10165. const heroes = Object.values(this.questInfo['heroGetAll']);
  10166. const inventory = this.questInfo['inventoryGet'];
  10167. const upArt = { heroId: 0, slotId: 0, level: 100 };
  10168.  
  10169. const heroLib = lib.getData('hero');
  10170. const artifactLib = lib.getData('artifact');
  10171.  
  10172. for (const hero of heroes) {
  10173. const heroInfo = heroLib[hero.id];
  10174. const level = hero.level
  10175. if (level < 20) {
  10176. continue;
  10177. }
  10178.  
  10179. for (let slotId in hero.artifacts) {
  10180. const art = hero.artifacts[slotId];
  10181. /* Текущая звезданость арта */
  10182. const star = art.star;
  10183. if (!star) {
  10184. continue;
  10185. }
  10186. /* Текущий уровень арта */
  10187. const level = art.level;
  10188. if (level >= 100) {
  10189. continue;
  10190. }
  10191. /* Идентификатор арта в библиотеке */
  10192. const artifactId = heroInfo.artifacts[slotId];
  10193. const artInfo = artifactLib.id[artifactId];
  10194. const costNextLevel = artifactLib.type[artInfo.type].levels[level + 1].cost;
  10195.  
  10196. const costСurrency = Object.keys(costNextLevel).pop();
  10197. const costValues = Object.entries(costNextLevel[costСurrency]).pop();
  10198. const costId = costValues[0];
  10199. const costValue = +costValues[1];
  10200.  
  10201. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10202. if (level < upArt.level && inventory[costСurrency][costId] >= costValue) {
  10203. upArt.level = level;
  10204. upArt.heroId = hero.id;
  10205. upArt.slotId = slotId;
  10206. upArt.costСurrency = costСurrency;
  10207. upArt.costId = costId;
  10208. upArt.costValue = costValue;
  10209. }
  10210. }
  10211. }
  10212. return upArt;
  10213. }
  10214.  
  10215. getUpgradeSkin() {
  10216. const heroes = Object.values(this.questInfo['heroGetAll']);
  10217. const inventory = this.questInfo['inventoryGet'];
  10218. const upSkin = { heroId: 0, skinId: 0, level: 60, cost: 1500 };
  10219.  
  10220. const skinLib = lib.getData('skin');
  10221.  
  10222. for (const hero of heroes) {
  10223. const level = hero.level
  10224. if (level < 20) {
  10225. continue;
  10226. }
  10227.  
  10228. for (let skinId in hero.skins) {
  10229. /* Текущий уровень скина */
  10230. const level = hero.skins[skinId];
  10231. if (level >= 60) {
  10232. continue;
  10233. }
  10234. /* Идентификатор скина в библиотеке */
  10235. const skinInfo = skinLib[skinId];
  10236. if (!skinInfo.statData.levels?.[level + 1]) {
  10237. continue;
  10238. }
  10239. const costNextLevel = skinInfo.statData.levels[level + 1].cost;
  10240.  
  10241. const costСurrency = Object.keys(costNextLevel).pop();
  10242. const costСurrencyId = Object.keys(costNextLevel[costСurrency]).pop();
  10243. const costValue = +costNextLevel[costСurrency][costСurrencyId];
  10244.  
  10245. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10246. if (level < upSkin.level &&
  10247. costValue < upSkin.cost &&
  10248. inventory[costСurrency][costСurrencyId] >= costValue) {
  10249. upSkin.cost = costValue;
  10250. upSkin.level = level;
  10251. upSkin.heroId = hero.id;
  10252. upSkin.skinId = skinId;
  10253. upSkin.costСurrency = costСurrency;
  10254. upSkin.costСurrencyId = costСurrencyId;
  10255. }
  10256. }
  10257. }
  10258. return upSkin;
  10259. }
  10260.  
  10261. getUpgradeTitanArtifact() {
  10262. const titans = Object.values(this.questInfo['titanGetAll']);
  10263. const inventory = this.questInfo['inventoryGet'];
  10264. const userInfo = this.questInfo['userGetInfo'];
  10265. const upArt = { titanId: 0, slotId: 0, level: 120 };
  10266.  
  10267. const titanLib = lib.getData('titan');
  10268. const artTitanLib = lib.getData('titanArtifact');
  10269.  
  10270. for (const titan of titans) {
  10271. const titanInfo = titanLib[titan.id];
  10272. // const level = titan.level
  10273. // if (level < 20) {
  10274. // continue;
  10275. // }
  10276.  
  10277. for (let slotId in titan.artifacts) {
  10278. const art = titan.artifacts[slotId];
  10279. /* Текущая звезданость арта */
  10280. const star = art.star;
  10281. if (!star) {
  10282. continue;
  10283. }
  10284. /* Текущий уровень арта */
  10285. const level = art.level;
  10286. if (level >= 120) {
  10287. continue;
  10288. }
  10289. /* Идентификатор арта в библиотеке */
  10290. const artifactId = titanInfo.artifacts[slotId];
  10291. const artInfo = artTitanLib.id[artifactId];
  10292. const costNextLevel = artTitanLib.type[artInfo.type].levels[level + 1].cost;
  10293.  
  10294. const costСurrency = Object.keys(costNextLevel).pop();
  10295. let costValue = 0;
  10296. let currentValue = 0;
  10297. if (costСurrency == 'gold') {
  10298. costValue = costNextLevel[costСurrency];
  10299. currentValue = userInfo.gold;
  10300. } else {
  10301. const costValues = Object.entries(costNextLevel[costСurrency]).pop();
  10302. const costId = costValues[0];
  10303. costValue = +costValues[1];
  10304. currentValue = inventory[costСurrency][costId];
  10305. }
  10306.  
  10307. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10308. if (level < upArt.level && currentValue >= costValue) {
  10309. upArt.level = level;
  10310. upArt.titanId = titan.id;
  10311. upArt.slotId = slotId;
  10312. break;
  10313. }
  10314. }
  10315. }
  10316. return upArt;
  10317. }
  10318.  
  10319. getEnchantRune() {
  10320. const heroes = Object.values(this.questInfo['heroGetAll']);
  10321. const inventory = this.questInfo['inventoryGet'];
  10322. const enchRune = { heroId: 0, tier: 0, exp: 43750, itemId: 0 };
  10323. for (let i = 1; i <= 4; i++) {
  10324. if (inventory.consumable[i] > 0) {
  10325. enchRune.itemId = i;
  10326. break;
  10327. }
  10328. return enchRune;
  10329. }
  10330.  
  10331. const runeLib = lib.getData('rune');
  10332. const runeLvls = Object.values(runeLib.level);
  10333. /**
  10334. * color - 4 (синий) открывает 1 и 2 символ
  10335. * color - 7 (фиолетовый) открывает 3 символ
  10336. * color - 8 (фиолетовый +1) открывает 4 символ
  10337. * color - 9 (фиолетовый +2) открывает 5 символ
  10338. */
  10339. // TODO: кажется надо учесть уровень команды
  10340. const colors = [4, 4, 7, 8, 9];
  10341. for (const hero of heroes) {
  10342. const color = hero.color;
  10343.  
  10344.  
  10345. for (let runeTier in hero.runes) {
  10346. /* Проверка на доступность руны */
  10347. if (color < colors[runeTier]) {
  10348. continue;
  10349. }
  10350. /* Текущий опыт руны */
  10351. const exp = hero.runes[runeTier];
  10352. if (exp >= 43750) {
  10353. continue;
  10354. }
  10355.  
  10356. let level = 0;
  10357. if (exp) {
  10358. for (let lvl of runeLvls) {
  10359. if (exp >= lvl.enchantValue) {
  10360. level = lvl.level;
  10361. } else {
  10362. break;
  10363. }
  10364. }
  10365. }
  10366. /** Уровень героя необходимый для уровня руны */
  10367. const heroLevel = runeLib.level[level].heroLevel;
  10368. if (hero.level < heroLevel) {
  10369. continue;
  10370. }
  10371.  
  10372. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10373. if (exp < enchRune.exp) {
  10374. enchRune.exp = exp;
  10375. enchRune.heroId = hero.id;
  10376. enchRune.tier = runeTier;
  10377. break;
  10378. }
  10379. }
  10380. }
  10381. return enchRune;
  10382. }
  10383.  
  10384. getOutlandChest() {
  10385. const bosses = this.questInfo['bossGetAll'];
  10386.  
  10387. const calls = [];
  10388.  
  10389. for (let boss of bosses) {
  10390. if (boss.mayRaid) {
  10391. calls.push({
  10392. name: "bossRaid",
  10393. args: {
  10394. bossId: boss.id
  10395. },
  10396. ident: "bossRaid_" + boss.id
  10397. });
  10398. calls.push({
  10399. name: "bossOpenChest",
  10400. args: {
  10401. bossId: boss.id,
  10402. amount: 1,
  10403. starmoney: 0
  10404. },
  10405. ident: "bossOpenChest_" + boss.id
  10406. });
  10407. } else if (boss.chestId == 1) {
  10408. calls.push({
  10409. name: "bossOpenChest",
  10410. args: {
  10411. bossId: boss.id,
  10412. amount: 1,
  10413. starmoney: 0
  10414. },
  10415. ident: "bossOpenChest_" + boss.id
  10416. });
  10417. }
  10418. }
  10419.  
  10420. return calls;
  10421. }
  10422.  
  10423. getExpHero() {
  10424. const heroes = Object.values(this.questInfo['heroGetAll']);
  10425. const inventory = this.questInfo['inventoryGet'];
  10426. const expHero = { heroId: 0, exp: 3625195, libId: 0 };
  10427. /** зелья опыта (consumable 9, 10, 11, 12) */
  10428. for (let i = 9; i <= 12; i++) {
  10429. if (inventory.consumable[i]) {
  10430. expHero.libId = i;
  10431. break;
  10432. }
  10433. }
  10434.  
  10435. for (const hero of heroes) {
  10436. const exp = hero.xp;
  10437. if (exp < expHero.exp) {
  10438. expHero.heroId = hero.id;
  10439. }
  10440. }
  10441. return expHero;
  10442. }
  10443.  
  10444. getHeroIdTitanGift() {
  10445. const heroes = Object.values(this.questInfo['heroGetAll']);
  10446. const inventory = this.questInfo['inventoryGet'];
  10447. const user = this.questInfo['userGetInfo'];
  10448. const titanGiftLib = lib.getData('titanGift');
  10449. /** Искры */
  10450. const titanGift = inventory.consumable[24];
  10451. let heroId = 0;
  10452. let minLevel = 30;
  10453.  
  10454. if (titanGift < 250 || user.gold < 7000) {
  10455. return 0;
  10456. }
  10457.  
  10458. for (const hero of heroes) {
  10459. if (hero.titanGiftLevel >= 30) {
  10460. continue;
  10461. }
  10462.  
  10463. if (!hero.titanGiftLevel) {
  10464. return hero.id;
  10465. }
  10466.  
  10467. const cost = titanGiftLib[hero.titanGiftLevel].cost;
  10468. if (minLevel > hero.titanGiftLevel &&
  10469. titanGift >= cost.consumable[24] &&
  10470. user.gold >= cost.gold
  10471. ) {
  10472. minLevel = hero.titanGiftLevel;
  10473. heroId = hero.id;
  10474. }
  10475. }
  10476.  
  10477. return heroId;
  10478. }
  10479.  
  10480. end(status) {
  10481. setProgress(status, true);
  10482. this.resolve();
  10483. }
  10484. }
  10485.  
  10486. this.questRun = dailyQuests;
  10487.  
  10488. function testDoYourBest() {
  10489. return new Promise((resolve, reject) => {
  10490. const doIt = new doYourBest(resolve, reject);
  10491. doIt.start();
  10492. });
  10493. }
  10494.  
  10495. /**
  10496. * Do everything button
  10497. *
  10498. * Кнопка сделать все
  10499. */
  10500. class doYourBest {
  10501.  
  10502. funcList = [
  10503. //собрать запределье
  10504. {
  10505. name: 'getOutland',
  10506. label: I18N('ASSEMBLE_OUTLAND'),
  10507. checked: false
  10508. },
  10509. //пройти башню
  10510. {
  10511. name: 'testTower',
  10512. label: I18N('PASS_THE_TOWER'),
  10513. checked: false
  10514. },
  10515. //экспедиции
  10516. {
  10517. name: 'checkExpedition',
  10518. label: I18N('CHECK_EXPEDITIONS'),
  10519. checked: false
  10520. },
  10521. //турнир стихий
  10522. {
  10523. name: 'testTitanArena',
  10524. label: I18N('COMPLETE_TOE'),
  10525. checked: false
  10526. },
  10527. //собрать почту
  10528. {
  10529. name: 'mailGetAll',
  10530. label: I18N('COLLECT_MAIL'),
  10531. checked: false
  10532. },
  10533. //Собрать всякую херню
  10534. {
  10535. name: 'collectAllStuff',
  10536. label: I18N('COLLECT_MISC'),
  10537. title: I18N('COLLECT_MISC_TITLE'),
  10538. checked: false
  10539. },
  10540. //ежедневная награда
  10541. {
  10542. name: 'getDailyBonus',
  10543. label: I18N('DAILY_BONUS'),
  10544. checked: false
  10545. },
  10546. //ежедневные квесты удалить наверно есть в настройках
  10547. {
  10548. name: 'dailyQuests',
  10549. label: I18N('DO_DAILY_QUESTS'),
  10550. checked: false
  10551. },
  10552. //Провидец
  10553. {
  10554. name: 'rollAscension',
  10555. label: I18N('SEER_TITLE'),
  10556. checked: false
  10557. },
  10558. //собрать награды за квесты
  10559. {
  10560. name: 'questAllFarm',
  10561. label: I18N('COLLECT_QUEST_REWARDS'),
  10562. checked: false
  10563. },
  10564. // тест отправь подарки согильдийцам
  10565. {
  10566. name: 'testclanSendDailyGifts',
  10567. label: I18N('QUEST_10016'),
  10568. checked: false
  10569. },
  10570. //собрать новогодние подарки
  10571. /*{
  10572. name: 'getGiftNewYear',
  10573. label: I18N('NY_GIFTS'),
  10574. checked: false
  10575. },*/
  10576. // тест сферу титанов
  10577. /*{
  10578. name: 'testtitanArtifactChestOpen',
  10579. label: I18N('QUEST_10029'),
  10580. checked: false
  10581. },
  10582. // тест призыв петов
  10583. {
  10584. name: 'testpet_chestOpen',
  10585. label: I18N('QUEST_10044'),
  10586. checked: false
  10587. },*/
  10588. //пройти подземелье обычное
  10589. {
  10590. name: 'testDungeon',
  10591. label: I18N('COMPLETE_DUNGEON'),
  10592. checked: false
  10593. },
  10594. //пройти подземелье для фуловых титанов
  10595. {
  10596. name: 'DungeonFull',
  10597. label: I18N('COMPLETE_DUNGEON_FULL'),
  10598. checked: false
  10599. },
  10600. //синхронизация
  10601. {
  10602. name: 'synchronization',
  10603. label: I18N('MAKE_A_SYNC'),
  10604. checked: false
  10605. },
  10606. //перезагрузка
  10607. {
  10608. name: 'reloadGame',
  10609. label: I18N('RELOAD_GAME'),
  10610. checked: false
  10611. },
  10612. ];
  10613.  
  10614. functions = {
  10615. getOutland,//собрать запределье
  10616. testTower,//прохождение башни
  10617. checkExpedition,//автоэкспедиции
  10618. testTitanArena,//Автопрохождение Турнира Стихий
  10619. mailGetAll,//Собрать всю почту, кроме писем с энергией и зарядами портала
  10620. //Собрать пасхалки, камни облика, ключи, монеты арены и Хрусталь души
  10621. collectAllStuff: async () => {
  10622. await offerFarmAllReward();
  10623. 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"}]}');
  10624. },
  10625. //Выполнять ежедневные квесты
  10626. dailyQuests: async function () {
  10627. const quests = new dailyQuests(() => { }, () => { });
  10628. await quests.autoInit(true);
  10629. await quests.start();
  10630. },
  10631. rollAscension,//провидец
  10632. getDailyBonus,//ежедневная награда
  10633. questAllFarm,//Собрать все награды за задания
  10634. testclanSendDailyGifts, //отправить подарки
  10635. getGiftNewYear,//собрать новогодние подарки
  10636. testtitanArtifactChestOpen, //открой сферу титанов
  10637. testpet_chestOpen, //Воспользуйся призывом питомцев 1 раз
  10638. testDungeon,//подземка обычная
  10639. DungeonFull,//подземка для фуловых титанов
  10640. synchronization: async () => {
  10641. cheats.refreshGame();
  10642. },
  10643. reloadGame: async () => {
  10644. location.reload();
  10645. },
  10646. }
  10647.  
  10648. constructor(resolve, reject, questInfo) {
  10649. this.resolve = resolve;
  10650. this.reject = reject;
  10651. this.questInfo = questInfo
  10652. }
  10653.  
  10654. async start() {
  10655. const selectedDoIt = getSaveVal('selectedDoIt', {});
  10656.  
  10657. this.funcList.forEach(task => {
  10658. if (!selectedDoIt[task.name]) {
  10659. selectedDoIt[task.name] = {
  10660. checked: task.checked
  10661. }
  10662. } else {
  10663. task.checked = selectedDoIt[task.name].checked
  10664. }
  10665. });
  10666.  
  10667. const answer = await popup.confirm(I18N('RUN_FUNCTION'), [
  10668. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  10669. { msg: I18N('BTN_GO'), result: true },
  10670. ], this.funcList);
  10671.  
  10672. if (!answer) {
  10673. this.end('');
  10674. return;
  10675. }
  10676.  
  10677. const taskList = popup.getCheckBoxes();
  10678. taskList.forEach(task => {
  10679. selectedDoIt[task.name].checked = task.checked;
  10680. });
  10681. setSaveVal('selectedDoIt', selectedDoIt);
  10682. for (const task of popup.getCheckBoxes()) {
  10683. if (task.checked) {
  10684. try {
  10685. setProgress(`${task.label} <br>${I18N('PERFORMED')}!`);
  10686. await this.functions[task.name]();
  10687. setProgress(`${task.label} <br>${I18N('DONE')}!`);
  10688. } catch (error) {
  10689. if (await popup.confirm(`${I18N('ERRORS_OCCURRES')}:<br> ${task.label} <br>${I18N('COPY_ERROR')}?`, [
  10690. { msg: I18N('BTN_NO'), result: false },
  10691. { msg: I18N('BTN_YES'), result: true },
  10692. ])) {
  10693. this.errorHandling(error);
  10694. }
  10695. }
  10696. }
  10697. }
  10698. setTimeout((msg) => {
  10699. this.end(msg);
  10700. }, 2000, I18N('ALL_TASK_COMPLETED'));
  10701. return;
  10702. }
  10703.  
  10704. errorHandling(error) {
  10705. //console.error(error);
  10706. let errorInfo = error.toString() + '\n';
  10707. try {
  10708. const errorStack = error.stack.split('\n');
  10709. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  10710. errorInfo += errorStack.slice(0, endStack).join('\n');
  10711. } catch (e) {
  10712. errorInfo += error.stack;
  10713. }
  10714. copyText(errorInfo);
  10715. }
  10716.  
  10717. end(status) {
  10718. setProgress(status, true);
  10719. this.resolve();
  10720. }
  10721. }
  10722.  
  10723. /**
  10724. * Passing the adventure along the specified route
  10725. *
  10726. * Прохождение приключения по указанному маршруту
  10727. */
  10728. function testAdventure(type) {
  10729. return new Promise((resolve, reject) => {
  10730. const bossBattle = new executeAdventure(resolve, reject);
  10731. bossBattle.start(type);
  10732. });
  10733. }
  10734.  
  10735. //Буря
  10736. function testAdventure2(solo) {
  10737. return new Promise((resolve, reject) => {
  10738. const bossBattle = new executeAdventure2(resolve, reject);
  10739. bossBattle.start(solo);
  10740. });
  10741. }
  10742.  
  10743. /**
  10744. * Passing the adventure along the specified route
  10745. *
  10746. * Прохождение приключения по указанному маршруту
  10747. */
  10748. class executeAdventure {
  10749.  
  10750. type = 'default';
  10751.  
  10752. actions = {
  10753. default: {
  10754. getInfo: "adventure_getInfo",
  10755. startBattle: 'adventure_turnStartBattle',
  10756. endBattle: 'adventure_endBattle',
  10757. collectBuff: 'adventure_turnCollectBuff'
  10758. },
  10759. solo: {
  10760. getInfo: "adventureSolo_getInfo",
  10761. startBattle: 'adventureSolo_turnStartBattle',
  10762. endBattle: 'adventureSolo_endBattle',
  10763. collectBuff: 'adventureSolo_turnCollectBuff'
  10764. }
  10765. }
  10766.  
  10767. terminatеReason = I18N('UNKNOWN');
  10768. callAdventureInfo = {
  10769. name: "adventure_getInfo",
  10770. args: {},
  10771. ident: "adventure_getInfo"
  10772. }
  10773. callTeamGetAll = {
  10774. name: "teamGetAll",
  10775. args: {},
  10776. ident: "teamGetAll"
  10777. }
  10778. callTeamGetFavor = {
  10779. name: "teamGetFavor",
  10780. args: {},
  10781. ident: "teamGetFavor"
  10782. }
  10783. //тест прикла
  10784. defaultWays = {
  10785. //Галахад, 1-я
  10786. "adv_strongford_2pl_easy": {
  10787. first: '1,2,3,5,6',
  10788. second: '1,2,4,7,6',
  10789. third: '1,2,3,5,6'
  10790. },
  10791. //Джинджер, 2-я
  10792. "adv_valley_3pl_easy": {
  10793. first: '1,2,5,8,9,11',
  10794. second: '1,3,6,9,11',
  10795. third: '1,4,7,10,9,11'
  10796. },
  10797. //Орион, 3-я
  10798. "adv_ghirwil_3pl_easy": {
  10799. first: '1,5,6,9,11',
  10800. second: '1,4,12,13,11',
  10801. third: '1,2,3,7,10,11'
  10802. },
  10803. //Тесак, 4-я
  10804. "adv_angels_3pl_easy_fire": {
  10805. first: '1,2,4,7,18,8,12,19,22,23',
  10806. second: '1,3,6,11,17,10,16,21,22,23',
  10807. third: '1,5,24,25,9,14,15,20,22,23'
  10808. },
  10809. //Галахад, 5-я
  10810. "adv_strongford_3pl_normal_2": {
  10811. first: '1,2,7,8,12,16,23,26,25,21,24',
  10812. second: '1,4,6,10,11,15,22,15,19,18,24',
  10813. third: '1,5,9,10,14,17,20,27,25,21,24'
  10814. },
  10815. //Джинджер, 6-я
  10816. "adv_valley_3pl_normal": {
  10817. first: '1,2,4,7,10,13,16,19,24,22,25',
  10818. second: '1,3,6,9,12,15,18,21,26,23,25',
  10819. third: '1,5,7,8,11,14,17,20,22,25'
  10820. },
  10821. //Орион, 7-я
  10822. "adv_ghirwil_3pl_normal_2": {
  10823. first: '1,11,10,11,12,15,12,11,21,25,27',
  10824. second: '1,7,3,4,3,6,13,19,20,24,27',
  10825. third: '1,8,5,9,16,23,22,26,27'
  10826. },
  10827. //Тесак, 8-я
  10828. "adv_angels_3pl_normal": {
  10829. first: '1,3,4,8,7,9,10,13,17,16,20,22,23,31,32',
  10830. second: '1,3,5,7,8,11,14,18,20,22,24,27,30,26,32',
  10831. third: '1,3,2,6,7,9,11,15,19,20,22,21,28,29,25'
  10832. },
  10833. //Галахад, 9-я
  10834. "adv_strongford_3pl_hard_2": {
  10835. first: '1,2,6,10,15,7,16,17,23,22,27,32,35,37,40,45',
  10836. second: '1,3,8,12,11,18,19,28,34,33,38,41,43,46,45',
  10837. third: '1,2,5,9,14,20,26,21,30,36,39,42,44,45'
  10838. },
  10839. //Джинджер, 10-я
  10840. "adv_valley_3pl_hard": {
  10841. first: '1,3,2,6,11,17,25,30,35,34,29,24,21,17,12,7',
  10842. second: '1,4,8,13,18,22,26,31,36,40,45,44,43,38,33,28',
  10843. third: '1,5,9,14,19,23,27,32,37,42,48,51,50,49,46,52'
  10844. },
  10845. //Орион, 11-я
  10846. "adv_ghirwil_3pl_hard": {
  10847. first: '1,2,3,6,8,12,11,15,21,27,36,34,33,35,37',
  10848. second: '1,2,4,6,9,13,18,17,16,22,28,29,30,31,25,19',
  10849. third: '1,2,5,6,10,13,14,20,26,32,38,41,40,39,37'
  10850. },
  10851. //Тесак, 12-я
  10852. "adv_angels_3pl_hard": {
  10853. first: '1,2,8,11,7,4,7,16,23,32,33,25,34,29,35,36',
  10854. second: '1,3,9,13,10,6,10,22,31,30,21,30,15,28,20,27',
  10855. third: '1,5,12,14,24,17,24,25,26,18,19,20,27'
  10856. },
  10857. //Тесак, 13-я
  10858. "adv_angels_3pl_hell": {
  10859. first: '1,2,4,6,16,23,33,34,25,32,29,28,20,27',
  10860. second: '1,7,11,17,24,14,26,18,19,20,27,20,12,8',
  10861. third: '1,9,3,5,10,22,31,36,31,30,15,28,29,30,21,13'
  10862. },
  10863. //Галахад, 13-я
  10864. "adv_strongford_3pl_hell": {
  10865. first: '1,2,5,11,14,20,26,21,30,35,38,41,43,44',
  10866. second: '1,2,6,12,15,7,16,17,23,22,27,42,34,36,39,44',
  10867. third: '1,3,8,9,13,18,19,28,0,33,37,40,32,45,44'
  10868. },
  10869. //Орион, 13-я
  10870. "adv_ghirwil_3pl_hell": {
  10871. first: '1,2,3,6,8,12,11,15,21,27,36,34,33,35,37',
  10872. second: '1,2,4,6,9,13,18,17,16,22,28,29,30,31,25,19',
  10873. third: '1,2,5,6,10,13,14,20,26,32,38,41,40,39,37'
  10874. },
  10875. //Джинджер, 13-я
  10876. "adv_valley_3pl_hell": {
  10877. first: '1,3,2,6,11,17,25,30,35,34,29,24,21,17,12,7',
  10878. second: '1,4,8,13,18,22,26,31,36,40,45,44,43,38,33,28',
  10879. third: '1,5,9,14,19,23,27,32,37,42,48,51,50,49,46,52'
  10880. }
  10881. }
  10882. callStartBattle = {
  10883. name: "adventure_turnStartBattle",
  10884. args: {},
  10885. ident: "body"
  10886. }
  10887. callEndBattle = {
  10888. name: "adventure_endBattle",
  10889. args: {
  10890. result: {},
  10891. progress: {},
  10892. },
  10893. ident: "body"
  10894. }
  10895. callCollectBuff = {
  10896. name: "adventure_turnCollectBuff",
  10897. args: {},
  10898. ident: "body"
  10899. }
  10900.  
  10901. constructor(resolve, reject) {
  10902. this.resolve = resolve;
  10903. this.reject = reject;
  10904. }
  10905.  
  10906. async start(type) {
  10907. //this.type = type || this.type;
  10908. //this.callAdventureInfo.name = this.actions[this.type].getInfo;
  10909. const data = await Send(JSON.stringify({
  10910. calls: [
  10911. this.callAdventureInfo,
  10912. this.callTeamGetAll,
  10913. this.callTeamGetFavor
  10914. ]
  10915. }));
  10916. //тест прикла1
  10917. this.path = await this.getPath(data.results[0].result.response.mapIdent);
  10918. if (!this.path) {
  10919. this.end();
  10920. return;
  10921. }
  10922. return this.checkAdventureInfo(data.results);
  10923. }
  10924.  
  10925. async getPath(mapId) {
  10926. //const oldVal = getSaveVal('adventurePath', '');
  10927. //const keyPath = `adventurePath:${this.mapIdent}`;
  10928. const answer = await popup.confirm(I18N('ENTER_THE_PATH'), [
  10929. {
  10930. msg: I18N('START_ADVENTURE'),
  10931. placeholder: '1,2,3,4,5,6',
  10932. isInput: true,
  10933. //default: getSaveVal(keyPath, oldVal)
  10934. default: getSaveVal('adventurePath', '')
  10935. },
  10936. {
  10937. msg: ' Начать по пути №1! ',
  10938. placeholder: '1,2,3',
  10939. isInput: true,
  10940. default: this.defaultWays[mapId]?.first
  10941. },
  10942. {
  10943. msg: ' Начать по пути №2! ',
  10944. placeholder: '1,2,3',
  10945. isInput: true,
  10946. default: this.defaultWays[mapId]?.second
  10947. },
  10948. {
  10949. msg: ' Начать по пути №3! ',
  10950. placeholder: '1,2,3',
  10951. isInput: true,
  10952. default: this.defaultWays[mapId]?.third
  10953. },
  10954. {
  10955. msg: I18N('BTN_CANCEL'),
  10956. result: false,
  10957. isCancel: true
  10958. },
  10959. ]);
  10960. if (!answer) {
  10961. this.terminatеReason = I18N('BTN_CANCELED');
  10962. return false;
  10963. }
  10964.  
  10965. let path = answer.split(',');
  10966. if (path.length < 2) {
  10967. path = answer.split('-');
  10968. }
  10969. if (path.length < 2) {
  10970. this.terminatеReason = I18N('MUST_TWO_POINTS');
  10971. return false;
  10972. }
  10973.  
  10974. for (let p in path) {
  10975. path[p] = +path[p].trim()
  10976. if (Number.isNaN(path[p])) {
  10977. this.terminatеReason = I18N('MUST_ONLY_NUMBERS');
  10978. return false;
  10979. }
  10980. }
  10981.  
  10982. /*if (!this.checkPath(path)) {
  10983. return false;
  10984. }*/
  10985. //setSaveVal(keyPath, answer);
  10986. setSaveVal('adventurePath', answer);
  10987. return path;
  10988. }
  10989. /*
  10990. checkPath(path) {
  10991. for (let i = 0; i < path.length - 1; i++) {
  10992. const currentPoint = path[i];
  10993. const nextPoint = path[i + 1];
  10994.  
  10995. const isValidPath = this.paths.some(p =>
  10996. (p.from_id === currentPoint && p.to_id === nextPoint) ||
  10997. (p.from_id === nextPoint && p.to_id === currentPoint)
  10998. );
  10999.  
  11000. if (!isValidPath) {
  11001. this.terminatеReason = I18N('INCORRECT_WAY', {
  11002. from: currentPoint,
  11003. to: nextPoint,
  11004. });
  11005. return false;
  11006. }
  11007. }
  11008.  
  11009. return true;
  11010. }
  11011. */
  11012. async checkAdventureInfo(data) {
  11013. this.advInfo = data[0].result.response;
  11014. if (!this.advInfo) {
  11015. this.terminatеReason = I18N('NOT_ON_AN_ADVENTURE') ;
  11016. return this.end();
  11017. }
  11018. const heroesTeam = data[1].result.response.adventure_hero;
  11019. const favor = data[2]?.result.response.adventure_hero;
  11020. const heroes = heroesTeam.slice(0, 5);
  11021. const pet = heroesTeam[5];
  11022. this.args = {
  11023. pet,
  11024. heroes,
  11025. favor,
  11026. path: [],
  11027. broadcast: false
  11028. }
  11029. const advUserInfo = this.advInfo.users[userInfo.id];
  11030. this.turnsLeft = advUserInfo.turnsLeft;
  11031. this.currentNode = advUserInfo.currentNode;
  11032. this.nodes = this.advInfo.nodes;
  11033. //this.paths = this.advInfo.paths;
  11034. //this.mapIdent = this.advInfo.mapIdent;
  11035.  
  11036. /*this.path = await this.getPath();
  11037. if (!this.path) {
  11038. return this.end();
  11039. }*/
  11040.  
  11041. if (this.currentNode == 1 && this.path[0] != 1) {
  11042. this.path.unshift(1);
  11043. }
  11044.  
  11045. return this.loop();
  11046. }
  11047.  
  11048. async loop() {
  11049. const position = this.path.indexOf(+this.currentNode);
  11050. if (!(~position)) {
  11051. this.terminatеReason = I18N('YOU_IN_NOT_ON_THE_WAY');
  11052. return this.end();
  11053. }
  11054. this.path = this.path.slice(position);
  11055. if ((this.path.length - 1) > this.turnsLeft &&
  11056. await popup.confirm(I18N('ATTEMPTS_NOT_ENOUGH'), [
  11057. { msg: I18N('YES_CONTINUE'), result: false },
  11058. { msg: I18N('BTN_NO'), result: true },
  11059. ])) {
  11060. this.terminatеReason = I18N('NOT_ENOUGH_AP');
  11061. return this.end();
  11062. }
  11063. const toPath = [];
  11064. for (const nodeId of this.path) {
  11065. if (!this.turnsLeft) {
  11066. this.terminatеReason = I18N('ATTEMPTS_ARE_OVER');
  11067. return this.end();
  11068. }
  11069. toPath.push(nodeId);
  11070. console.log(toPath);
  11071. if (toPath.length > 1) {
  11072. setProgress(toPath.join(' > ') + ` ${I18N('MOVES')}: ` + this.turnsLeft);
  11073. }
  11074. if (nodeId == this.currentNode) {
  11075. continue;
  11076. }
  11077.  
  11078. const nodeInfo = this.getNodeInfo(nodeId);
  11079. if (nodeInfo.type == 'TYPE_COMBAT') {
  11080. if (nodeInfo.state == 'empty') {
  11081. this.turnsLeft--;
  11082. continue;
  11083. }
  11084.  
  11085. /**
  11086. * Disable regular battle cancellation
  11087. *
  11088. * Отключаем штатную отменую боя
  11089. */
  11090. isCancalBattle = false;
  11091. if (await this.battle(toPath)) {
  11092. this.turnsLeft--;
  11093. toPath.splice(0, toPath.indexOf(nodeId));
  11094. nodeInfo.state = 'empty';
  11095. isCancalBattle = true;
  11096. continue;
  11097. }
  11098. isCancalBattle = true;
  11099. return this.end()
  11100. }
  11101.  
  11102. if (nodeInfo.type == 'TYPE_PLAYERBUFF') {
  11103. const buff = this.checkBuff(nodeInfo);
  11104. if (buff == null) {
  11105. continue;
  11106. }
  11107.  
  11108. if (await this.collectBuff(buff, toPath)) {
  11109. this.turnsLeft--;
  11110. toPath.splice(0, toPath.indexOf(nodeId));
  11111. continue;
  11112. }
  11113. this.terminatеReason = I18N('BUFF_GET_ERROR');
  11114. return this.end();
  11115. }
  11116. }
  11117. this.terminatеReason = I18N('SUCCESS');
  11118. return this.end();
  11119. }
  11120.  
  11121. /**
  11122. * Carrying out a fight
  11123. *
  11124. * Проведение боя
  11125. */
  11126. async battle(path, preCalc = true) {
  11127. const data = await this.startBattle(path);
  11128. try {
  11129. const battle = data.results[0].result.response.battle;
  11130. const result = await Calc(battle);
  11131. if (result.result.win) {
  11132. const info = await this.endBattle(result);
  11133. if (info.results[0].result.response?.error) {
  11134. this.terminatеReason = I18N('BATTLE_END_ERROR');
  11135. return false;
  11136. }
  11137. } else {
  11138. await this.cancelBattle(result);
  11139.  
  11140. if (preCalc && await this.preCalcBattle(battle)) {
  11141. path = path.slice(-2);
  11142. for (let i = 1; i <= getInput('countAutoBattle'); i++) {
  11143. setProgress(`${I18N('AUTOBOT')}: ${i}/${getInput('countAutoBattle')}`);
  11144. const result = await this.battle(path, false);
  11145. if (result) {
  11146. setProgress(I18N('VICTORY'));
  11147. return true;
  11148. }
  11149. }
  11150. this.terminatеReason = I18N('FAILED_TO_WIN_AUTO');
  11151. return false;
  11152. }
  11153. return false;
  11154. }
  11155. } catch (error) {
  11156. console.error(error);
  11157. if (await popup.confirm(I18N('ERROR_OF_THE_BATTLE_COPY'), [
  11158. { msg: I18N('BTN_NO'), result: false },
  11159. { msg: I18N('BTN_YES'), result: true },
  11160. ])) {
  11161. this.errorHandling(error, data);
  11162. }
  11163. this.terminatеReason = I18N('ERROR_DURING_THE_BATTLE');
  11164. return false;
  11165. }
  11166. return true;
  11167. }
  11168.  
  11169. /**
  11170. * Recalculate battles
  11171. *
  11172. * Прерасчтет битвы
  11173. */
  11174. async preCalcBattle(battle) {
  11175. const countTestBattle = getInput('countTestBattle');
  11176. for (let i = 0; i < countTestBattle; i++) {
  11177. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  11178. const result = await Calc(battle);
  11179. if (result.result.win) {
  11180. console.log(i, countTestBattle);
  11181. return true;
  11182. }
  11183. }
  11184. this.terminatеReason = I18N('NO_CHANCE_WIN') + countTestBattle;
  11185. return false;
  11186. }
  11187.  
  11188. /**
  11189. * Starts a fight
  11190. *
  11191. * Начинает бой
  11192. */
  11193. startBattle(path) {
  11194. this.args.path = path;
  11195. this.callStartBattle.name = this.actions[this.type].startBattle;
  11196. this.callStartBattle.args = this.args
  11197. const calls = [this.callStartBattle];
  11198. return Send(JSON.stringify({ calls }));
  11199. }
  11200.  
  11201. cancelBattle(battle) {
  11202. const fixBattle = function (heroes) {
  11203. for (const ids in heroes) {
  11204. const hero = heroes[ids];
  11205. hero.energy = random(1, 999);
  11206. if (hero.hp > 0) {
  11207. hero.hp = random(1, hero.hp);
  11208. }
  11209. }
  11210. }
  11211. fixBattle(battle.progress[0].attackers.heroes);
  11212. fixBattle(battle.progress[0].defenders.heroes);
  11213. return this.endBattle(battle);
  11214. }
  11215.  
  11216. /**
  11217. * Ends the fight
  11218. *
  11219. * Заканчивает бой
  11220. */
  11221. endBattle(battle) {
  11222. this.callEndBattle.name = this.actions[this.type].endBattle;
  11223. this.callEndBattle.args.result = battle.result
  11224. this.callEndBattle.args.progress = battle.progress
  11225. const calls = [this.callEndBattle];
  11226. return Send(JSON.stringify({ calls }));
  11227. }
  11228.  
  11229. /**
  11230. * Checks if you can get a buff
  11231. *
  11232. * Проверяет можно ли получить баф
  11233. */
  11234. checkBuff(nodeInfo) {
  11235. let id = null;
  11236. let value = 0;
  11237. for (const buffId in nodeInfo.buffs) {
  11238. const buff = nodeInfo.buffs[buffId];
  11239. if (buff.owner == null && buff.value > value) {
  11240. id = buffId;
  11241. value = buff.value;
  11242. }
  11243. }
  11244. nodeInfo.buffs[id].owner = 'Я';
  11245. return id;
  11246. }
  11247.  
  11248. /**
  11249. * Collects a buff
  11250. *
  11251. * Собирает баф
  11252. */
  11253. async collectBuff(buff, path) {
  11254. this.callCollectBuff.name = this.actions[this.type].collectBuff;
  11255. this.callCollectBuff.args = { buff, path };
  11256. const calls = [this.callCollectBuff];
  11257. return Send(JSON.stringify({ calls }));
  11258. }
  11259.  
  11260. getNodeInfo(nodeId) {
  11261. return this.nodes.find(node => node.id == nodeId);
  11262. }
  11263.  
  11264. errorHandling(error, data) {
  11265. //console.error(error);
  11266. let errorInfo = error.toString() + '\n';
  11267. try {
  11268. const errorStack = error.stack.split('\n');
  11269. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testAdventure");
  11270. errorInfo += errorStack.slice(0, endStack).join('\n');
  11271. } catch (e) {
  11272. errorInfo += error.stack;
  11273. }
  11274. if (data) {
  11275. errorInfo += '\nData: ' + JSON.stringify(data);
  11276. }
  11277. copyText(errorInfo);
  11278. }
  11279.  
  11280. end() {
  11281. isCancalBattle = true;
  11282. setProgress(this.terminatеReason, true);
  11283. console.log(this.terminatеReason);
  11284. this.resolve();
  11285. }
  11286. }
  11287. class executeAdventure2 {
  11288.  
  11289. type = 'default';
  11290.  
  11291. actions = {
  11292. default: {
  11293. getInfo: "adventure_getInfo",
  11294. startBattle: 'adventure_turnStartBattle',
  11295. endBattle: 'adventure_endBattle',
  11296. collectBuff: 'adventure_turnCollectBuff'
  11297. },
  11298. solo: {
  11299. getInfo: "adventureSolo_getInfo",
  11300. startBattle: 'adventureSolo_turnStartBattle',
  11301. endBattle: 'adventureSolo_endBattle',
  11302. collectBuff: 'adventureSolo_turnCollectBuff'
  11303. }
  11304. }
  11305.  
  11306. terminatеReason = I18N('UNKNOWN');
  11307. callAdventureInfo = {
  11308. name: "adventure_getInfo",
  11309. args: {},
  11310. ident: "adventure_getInfo"
  11311. }
  11312. callTeamGetAll = {
  11313. name: "teamGetAll",
  11314. args: {},
  11315. ident: "teamGetAll"
  11316. }
  11317. callTeamGetFavor = {
  11318. name: "teamGetFavor",
  11319. args: {},
  11320. ident: "teamGetFavor"
  11321. }
  11322. callStartBattle = {
  11323. name: "adventure_turnStartBattle",
  11324. args: {},
  11325. ident: "body"
  11326. }
  11327. callEndBattle = {
  11328. name: "adventure_endBattle",
  11329. args: {
  11330. result: {},
  11331. progress: {},
  11332. },
  11333. ident: "body"
  11334. }
  11335. callCollectBuff = {
  11336. name: "adventure_turnCollectBuff",
  11337. args: {},
  11338. ident: "body"
  11339. }
  11340.  
  11341. constructor(resolve, reject) {
  11342. this.resolve = resolve;
  11343. this.reject = reject;
  11344. }
  11345.  
  11346. async start(type) {
  11347. this.type = type || this.type;
  11348. this.callAdventureInfo.name = this.actions[this.type].getInfo;
  11349. const data = await Send(JSON.stringify({
  11350. calls: [
  11351. this.callAdventureInfo,
  11352. this.callTeamGetAll,
  11353. this.callTeamGetFavor
  11354. ]
  11355. }));
  11356. return this.checkAdventureInfo(data.results);
  11357. }
  11358.  
  11359. async getPath() {
  11360. const oldVal = getSaveVal('adventurePath', '');
  11361. const keyPath = `adventurePath:${this.mapIdent}`;
  11362. const answer = await popup.confirm(I18N('ENTER_THE_PATH'), [
  11363. {
  11364. msg: I18N('START_ADVENTURE'),
  11365. placeholder: '1,2,3,4,5,6',
  11366. isInput: true,
  11367. default: getSaveVal(keyPath, oldVal)
  11368. },
  11369. {
  11370. msg: I18N('BTN_CANCEL'),
  11371. result: false,
  11372. isCancel: true
  11373. },
  11374. ]);
  11375. if (!answer) {
  11376. this.terminatеReason = I18N('BTN_CANCELED');
  11377. return false;
  11378. }
  11379.  
  11380. let path = answer.split(',');
  11381. if (path.length < 2) {
  11382. path = answer.split('-');
  11383. }
  11384. if (path.length < 2) {
  11385. this.terminatеReason = I18N('MUST_TWO_POINTS');
  11386. return false;
  11387. }
  11388.  
  11389. for (let p in path) {
  11390. path[p] = +path[p].trim()
  11391. if (Number.isNaN(path[p])) {
  11392. this.terminatеReason = I18N('MUST_ONLY_NUMBERS');
  11393. return false;
  11394. }
  11395. }
  11396. if (!this.checkPath(path)) {
  11397. return false;
  11398. }
  11399. setSaveVal(keyPath, answer);
  11400. return path;
  11401. }
  11402.  
  11403. checkPath(path) {
  11404. for (let i = 0; i < path.length - 1; i++) {
  11405. const currentPoint = path[i];
  11406. const nextPoint = path[i + 1];
  11407.  
  11408. const isValidPath = this.paths.some(p =>
  11409. (p.from_id === currentPoint && p.to_id === nextPoint) ||
  11410. (p.from_id === nextPoint && p.to_id === currentPoint)
  11411. );
  11412.  
  11413. if (!isValidPath) {
  11414. this.terminatеReason = I18N('INCORRECT_WAY', {
  11415. from: currentPoint,
  11416. to: nextPoint,
  11417. });
  11418. return false;
  11419. }
  11420. }
  11421.  
  11422. return true;
  11423. }
  11424.  
  11425. async checkAdventureInfo(data) {
  11426. this.advInfo = data[0].result.response;
  11427. if (!this.advInfo) {
  11428. this.terminatеReason = I18N('NOT_ON_AN_ADVENTURE') ;
  11429. return this.end();
  11430. }
  11431. const heroesTeam = data[1].result.response.adventure_hero;
  11432. const favor = data[2]?.result.response.adventure_hero;
  11433. const heroes = heroesTeam.slice(0, 5);
  11434. const pet = heroesTeam[5];
  11435. this.args = {
  11436. pet,
  11437. heroes,
  11438. favor,
  11439. path: [],
  11440. broadcast: false
  11441. }
  11442. const advUserInfo = this.advInfo.users[userInfo.id];
  11443. this.turnsLeft = advUserInfo.turnsLeft;
  11444. this.currentNode = advUserInfo.currentNode;
  11445. this.nodes = this.advInfo.nodes;
  11446. this.paths = this.advInfo.paths;
  11447. this.mapIdent = this.advInfo.mapIdent;
  11448.  
  11449. this.path = await this.getPath();
  11450. if (!this.path) {
  11451. return this.end();
  11452. }
  11453.  
  11454. if (this.currentNode == 1 && this.path[0] != 1) {
  11455. this.path.unshift(1);
  11456. }
  11457.  
  11458. return this.loop();
  11459. }
  11460.  
  11461. async loop() {
  11462. const position = this.path.indexOf(+this.currentNode);
  11463. if (!(~position)) {
  11464. this.terminatеReason = I18N('YOU_IN_NOT_ON_THE_WAY');
  11465. return this.end();
  11466. }
  11467. this.path = this.path.slice(position);
  11468. if ((this.path.length - 1) > this.turnsLeft &&
  11469. await popup.confirm(I18N('ATTEMPTS_NOT_ENOUGH'), [
  11470. { msg: I18N('YES_CONTINUE'), result: false },
  11471. { msg: I18N('BTN_NO'), result: true },
  11472. ])) {
  11473. this.terminatеReason = I18N('NOT_ENOUGH_AP');
  11474. return this.end();
  11475. }
  11476. const toPath = [];
  11477. for (const nodeId of this.path) {
  11478. if (!this.turnsLeft) {
  11479. this.terminatеReason = I18N('ATTEMPTS_ARE_OVER');
  11480. return this.end();
  11481. }
  11482. toPath.push(nodeId);
  11483. console.log(toPath);
  11484. if (toPath.length > 1) {
  11485. setProgress(toPath.join(' > ') + ` ${I18N('MOVES')}: ` + this.turnsLeft);
  11486. }
  11487. if (nodeId == this.currentNode) {
  11488. continue;
  11489. }
  11490.  
  11491. const nodeInfo = this.getNodeInfo(nodeId);
  11492. if (nodeInfo.type == 'TYPE_COMBAT') {
  11493. if (nodeInfo.state == 'empty') {
  11494. this.turnsLeft--;
  11495. continue;
  11496. }
  11497.  
  11498. /**
  11499. * Disable regular battle cancellation
  11500. *
  11501. * Отключаем штатную отменую боя
  11502. */
  11503. isCancalBattle = false;
  11504. if (await this.battle(toPath)) {
  11505. this.turnsLeft--;
  11506. toPath.splice(0, toPath.indexOf(nodeId));
  11507. nodeInfo.state = 'empty';
  11508. isCancalBattle = true;
  11509. continue;
  11510. }
  11511. isCancalBattle = true;
  11512. return this.end()
  11513. }
  11514.  
  11515. if (nodeInfo.type == 'TYPE_PLAYERBUFF') {
  11516. const buff = this.checkBuff(nodeInfo);
  11517. if (buff == null) {
  11518. continue;
  11519. }
  11520.  
  11521. if (await this.collectBuff(buff, toPath)) {
  11522. this.turnsLeft--;
  11523. toPath.splice(0, toPath.indexOf(nodeId));
  11524. continue;
  11525. }
  11526. this.terminatеReason = I18N('BUFF_GET_ERROR');
  11527. return this.end();
  11528. }
  11529. }
  11530. this.terminatеReason = I18N('SUCCESS');
  11531. return this.end();
  11532. }
  11533.  
  11534. /**
  11535. * Carrying out a fight
  11536. *
  11537. * Проведение боя
  11538. */
  11539. async battle(path, preCalc = true) {
  11540. const data = await this.startBattle(path);
  11541. try {
  11542. const battle = data.results[0].result.response.battle;
  11543. const result = await Calc(battle);
  11544. if (result.result.win) {
  11545. const info = await this.endBattle(result);
  11546. if (info.results[0].result.response?.error) {
  11547. this.terminatеReason = I18N('BATTLE_END_ERROR');
  11548. return false;
  11549. }
  11550. } else {
  11551. await this.cancelBattle(result);
  11552.  
  11553. if (preCalc && await this.preCalcBattle(battle)) {
  11554. path = path.slice(-2);
  11555. for (let i = 1; i <= getInput('countAutoBattle'); i++) {
  11556. setProgress(`${I18N('AUTOBOT')}: ${i}/${getInput('countAutoBattle')}`);
  11557. const result = await this.battle(path, false);
  11558. if (result) {
  11559. setProgress(I18N('VICTORY'));
  11560. return true;
  11561. }
  11562. }
  11563. this.terminatеReason = I18N('FAILED_TO_WIN_AUTO');
  11564. return false;
  11565. }
  11566. return false;
  11567. }
  11568. } catch (error) {
  11569. console.error(error);
  11570. if (await popup.confirm(I18N('ERROR_OF_THE_BATTLE_COPY'), [
  11571. { msg: I18N('BTN_NO'), result: false },
  11572. { msg: I18N('BTN_YES'), result: true },
  11573. ])) {
  11574. this.errorHandling(error, data);
  11575. }
  11576. this.terminatеReason = I18N('ERROR_DURING_THE_BATTLE');
  11577. return false;
  11578. }
  11579. return true;
  11580. }
  11581.  
  11582. /**
  11583. * Recalculate battles
  11584. *
  11585. * Прерасчтет битвы
  11586. */
  11587. async preCalcBattle(battle) {
  11588. const countTestBattle = getInput('countTestBattle');
  11589. for (let i = 0; i < countTestBattle; i++) {
  11590. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  11591. const result = await Calc(battle);
  11592. if (result.result.win) {
  11593. console.log(i, countTestBattle);
  11594. return true;
  11595. }
  11596. }
  11597. this.terminatеReason = I18N('NO_CHANCE_WIN') + countTestBattle;
  11598. return false;
  11599. }
  11600.  
  11601. /**
  11602. * Starts a fight
  11603. *
  11604. * Начинает бой
  11605. */
  11606. startBattle(path) {
  11607. this.args.path = path;
  11608. this.callStartBattle.name = this.actions[this.type].startBattle;
  11609. this.callStartBattle.args = this.args
  11610. const calls = [this.callStartBattle];
  11611. return Send(JSON.stringify({ calls }));
  11612. }
  11613.  
  11614. cancelBattle(battle) {
  11615. const fixBattle = function (heroes) {
  11616. for (const ids in heroes) {
  11617. const hero = heroes[ids];
  11618. hero.energy = random(1, 999);
  11619. if (hero.hp > 0) {
  11620. hero.hp = random(1, hero.hp);
  11621. }
  11622. }
  11623. }
  11624. fixBattle(battle.progress[0].attackers.heroes);
  11625. fixBattle(battle.progress[0].defenders.heroes);
  11626. return this.endBattle(battle);
  11627. }
  11628.  
  11629. /**
  11630. * Ends the fight
  11631. *
  11632. * Заканчивает бой
  11633. */
  11634. endBattle(battle) {
  11635. this.callEndBattle.name = this.actions[this.type].endBattle;
  11636. this.callEndBattle.args.result = battle.result
  11637. this.callEndBattle.args.progress = battle.progress
  11638. const calls = [this.callEndBattle];
  11639. return Send(JSON.stringify({ calls }));
  11640. }
  11641.  
  11642. /**
  11643. * Checks if you can get a buff
  11644. *
  11645. * Проверяет можно ли получить баф
  11646. */
  11647. checkBuff(nodeInfo) {
  11648. let id = null;
  11649. let value = 0;
  11650. for (const buffId in nodeInfo.buffs) {
  11651. const buff = nodeInfo.buffs[buffId];
  11652. if (buff.owner == null && buff.value > value) {
  11653. id = buffId;
  11654. value = buff.value;
  11655. }
  11656. }
  11657. nodeInfo.buffs[id].owner = 'Я';
  11658. return id;
  11659. }
  11660.  
  11661. /**
  11662. * Collects a buff
  11663. *
  11664. * Собирает баф
  11665. */
  11666. async collectBuff(buff, path) {
  11667. this.callCollectBuff.name = this.actions[this.type].collectBuff;
  11668. this.callCollectBuff.args = { buff, path };
  11669. const calls = [this.callCollectBuff];
  11670. return Send(JSON.stringify({ calls }));
  11671. }
  11672.  
  11673. getNodeInfo(nodeId) {
  11674. return this.nodes.find(node => node.id == nodeId);
  11675. }
  11676.  
  11677. errorHandling(error, data) {
  11678. //console.error(error);
  11679. let errorInfo = error.toString() + '\n';
  11680. try {
  11681. const errorStack = error.stack.split('\n');
  11682. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testAdventure");
  11683. errorInfo += errorStack.slice(0, endStack).join('\n');
  11684. } catch (e) {
  11685. errorInfo += error.stack;
  11686. }
  11687. if (data) {
  11688. errorInfo += '\nData: ' + JSON.stringify(data);
  11689. }
  11690. copyText(errorInfo);
  11691. }
  11692.  
  11693. end() {
  11694. isCancalBattle = true;
  11695. setProgress(this.terminatеReason, true);
  11696. console.log(this.terminatеReason);
  11697. this.resolve();
  11698. }
  11699. }
  11700. /**
  11701. * Passage of brawls
  11702. *
  11703. * Прохождение потасовок
  11704. */
  11705. function testBrawls() {
  11706. return new Promise((resolve, reject) => {
  11707. const brawls = new executeBrawls(resolve, reject);
  11708. brawls.start(brawlsPack);
  11709. });
  11710. }
  11711. /**
  11712. * Passage of brawls
  11713. *
  11714. * Прохождение потасовок
  11715. */
  11716. class executeBrawls {
  11717. callBrawlQuestGetInfo = {
  11718. name: "brawl_questGetInfo",
  11719. args: {},
  11720. ident: "brawl_questGetInfo"
  11721. }
  11722. callBrawlFindEnemies = {
  11723. name: "brawl_findEnemies",
  11724. args: {},
  11725. ident: "brawl_findEnemies"
  11726. }
  11727. callBrawlQuestFarm = {
  11728. name: "brawl_questFarm",
  11729. args: {},
  11730. ident: "brawl_questFarm"
  11731. }
  11732. callUserGetInfo = {
  11733. name: "userGetInfo",
  11734. args: {},
  11735. ident: "userGetInfo"
  11736. }
  11737. callTeamGetMaxUpgrade = {
  11738. name: "teamGetMaxUpgrade",
  11739. args: {},
  11740. ident: "teamGetMaxUpgrade"
  11741. }
  11742. callBrawlGetInfo = {
  11743. name: "brawl_getInfo",
  11744. args: {},
  11745. ident: "brawl_getInfo"
  11746. }
  11747.  
  11748. stats = {
  11749. win: 0,
  11750. loss: 0,
  11751. count: 0,
  11752. }
  11753.  
  11754. stage = {
  11755. '3': 1,
  11756. '7': 2,
  11757. '12': 3,
  11758. }
  11759.  
  11760. attempts = 0;
  11761.  
  11762. constructor(resolve, reject) {
  11763. this.resolve = resolve;
  11764. this.reject = reject;
  11765. }
  11766.  
  11767. async start(args) {
  11768. this.args = args;
  11769. isCancalBattle = false;
  11770. this.brawlInfo = await this.getBrawlInfo();
  11771. this.attempts = this.brawlInfo.attempts;
  11772.  
  11773. if (!this.attempts) {
  11774. this.end(I18N('DONT_HAVE_LIVES'))
  11775. return;
  11776. }
  11777.  
  11778. while (1) {
  11779. if (!isBrawlsAutoStart) {
  11780. this.end(I18N('BTN_CANCELED'))
  11781. return;
  11782. }
  11783.  
  11784. const maxStage = this.brawlInfo.questInfo.stage;
  11785. const stage = this.stage[maxStage];
  11786. const progress = this.brawlInfo.questInfo.progress;
  11787.  
  11788. setProgress(`${I18N('STAGE')} ${stage}: ${progress}/${maxStage}<br>${I18N('FIGHTS')}: ${this.stats.count}<br>${I18N('WINS')}: ${this.stats.win}<br>${I18N('LOSSES')}: ${this.stats.loss}<br>${I18N('LIVES')}: ${this.attempts}<br>${I18N('STOP')}`, false, function () {
  11789. isBrawlsAutoStart = false;
  11790. });
  11791.  
  11792. if (this.brawlInfo.questInfo.canFarm) {
  11793. const result = await this.questFarm();
  11794. console.log(result);
  11795. }
  11796.  
  11797. if (this.brawlInfo.questInfo.stage == 12 && this.brawlInfo.questInfo.progress == 12) {
  11798. this.end(I18N('SUCCESS'))
  11799. return;
  11800. }
  11801.  
  11802. if (!this.attempts) {
  11803. this.end(I18N('DONT_HAVE_LIVES'))
  11804. return;
  11805. }
  11806.  
  11807. const enemie = Object.values(this.brawlInfo.findEnemies).shift();
  11808.  
  11809. // Для потасовок брустара
  11810. this.args.heroes = await this.updatePack(enemie.heroes);
  11811.  
  11812. const result = await this.battle(enemie.userId);
  11813. this.brawlInfo = {
  11814. questInfo: result[1].result.response,
  11815. findEnemies: result[2].result.response,
  11816. }
  11817. }
  11818. }
  11819.  
  11820. async updatePack(enemieHeroes) {
  11821. const packs = [
  11822. // 4023 Эдем
  11823. [4020, 4022, 4023, 4042, 4043],
  11824. [4023, 4030, 4033, 4042, 4043],
  11825. [4023, 4040, 4041, 4042, 4043],
  11826. // Разное
  11827. [4003, 4010, 4011, 4012, 4013],
  11828. [4030, 4032, 4033, 4040, 4043],
  11829. [4033, 4040, 4041, 4042, 4043],
  11830. [4030, 4031, 4033, 4040, 4043],
  11831. [4030, 4033, 4040, 4042, 4043],
  11832. [4001, 4032, 4033, 4040, 4043],
  11833. [4010, 4012, 4013, 4040, 4043],
  11834. [4001, 4002, 4003, 4040, 4043],
  11835. // 4003 Гиперион
  11836. [4000, 4001, 4003, 4033, 4043],
  11837. [4000, 4001, 4003, 4023, 4030],
  11838. [4000, 4001, 4003, 4023, 4033],
  11839. [4000, 4001, 4003, 4013, 4033],
  11840. [4003, 4010, 4012, 4013, 4043],
  11841. [4003, 4010, 4012, 4013, 4033],
  11842. [4003, 4030, 4032, 4042, 4043],
  11843. [4003, 4030, 4031, 4032, 4033],
  11844. [4003, 4040, 4041, 4042, 4043],
  11845. [4003, 4030, 4033, 4040, 4043],
  11846. // 4013 Араджи
  11847. [4010, 4011, 4012, 4013, 4033],
  11848. [4010, 4011, 4012, 4013, 4043],
  11849. [4010, 4011, 4013, 4042, 4043],
  11850. [4010, 4011, 4013, 4033, 4043],
  11851. [4001, 4010, 4011, 4013, 4033],
  11852. [4010, 4011, 4013, 4030, 4033],
  11853. [4010, 4011, 4013, 4040, 4043],
  11854. [4013, 4030, 4033, 4040, 4043],
  11855. [4013, 4030, 4033, 4042, 4043],
  11856. [4013, 4020, 4022, 4023, 4033],
  11857. ].filter(p => p.includes(this.mandatoryId))
  11858.  
  11859. const bestPack = {
  11860. pack: packs[0],
  11861. countWin: 0,
  11862. }
  11863.  
  11864. for (const pack of packs) {
  11865. const attackers = this.maxUpgrade
  11866. .filter(e => pack.includes(e.id))
  11867. .reduce((obj, e) => ({ ...obj, [e.id]: e }), {});
  11868. const battle = {
  11869. attackers,
  11870. defenders: [enemieHeroes],
  11871. type: "brawl_titan",
  11872. }
  11873.  
  11874. let countWinBattles = 0;
  11875. let countTestBattle = 10;
  11876. for (let i = 0; i < countTestBattle; i++) {
  11877. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  11878. const result = await Calc(battle);
  11879. if (result.result.win) {
  11880. countWinBattles++;
  11881. }
  11882. if (countWinBattles > 7) {
  11883. console.log(pack)
  11884. return pack;
  11885. }
  11886. }
  11887. if (countWinBattles > bestPack.countWin) {
  11888. bestPack.countWin = countWinBattles;
  11889. bestPack.pack = pack;
  11890. }
  11891. }
  11892.  
  11893. console.log(bestPack);
  11894. return bestPack.pack;
  11895. }
  11896.  
  11897. async questFarm() {
  11898. const calls = [this.callBrawlQuestFarm];
  11899. const result = await Send(JSON.stringify({ calls }));
  11900. return result.results[0].result.response;
  11901. }
  11902.  
  11903. async getBrawlInfo() {
  11904. const data = await Send(JSON.stringify({
  11905. calls: [
  11906. this.callUserGetInfo,
  11907. this.callBrawlQuestGetInfo,
  11908. this.callBrawlFindEnemies,
  11909. this.callTeamGetMaxUpgrade,
  11910. this.callBrawlGetInfo,
  11911. ]
  11912. }));
  11913.  
  11914. let attempts = data.results[0].result.response.refillable.find(n => n.id == 48);
  11915. this.maxUpgrade = Object.values(data.results[3].result.response.titan);
  11916. this.info = data.results[4].result.response;
  11917. this.mandatoryId = lib.data.brawl.promoHero[this.info.id].promoHero;
  11918. return {
  11919. attempts: attempts.amount,
  11920. questInfo: data.results[1].result.response,
  11921. findEnemies: data.results[2].result.response,
  11922. }
  11923. }
  11924.  
  11925. /**
  11926. * Carrying out a fight
  11927. *
  11928. * Проведение боя
  11929. */
  11930. async battle(userId) {
  11931. this.stats.count++;
  11932. const battle = await this.startBattle(userId, this.args);
  11933. const result = await Calc(battle);
  11934. console.log(result.result);
  11935. if (result.result.win) {
  11936. this.stats.win++;
  11937. } else {
  11938. this.stats.loss++;
  11939. this.attempts--;
  11940. }
  11941. return await this.endBattle(result);
  11942. // return await this.cancelBattle(result);
  11943. }
  11944.  
  11945. /**
  11946. * Starts a fight
  11947. *
  11948. * Начинает бой
  11949. */
  11950. async startBattle(userId, args) {
  11951. const call = {
  11952. name: "brawl_startBattle",
  11953. args,
  11954. ident: "brawl_startBattle"
  11955. }
  11956. call.args.userId = userId;
  11957. const calls = [call];
  11958. const result = await Send(JSON.stringify({ calls }));
  11959. return result.results[0].result.response;
  11960. }
  11961.  
  11962. cancelBattle(battle) {
  11963. const fixBattle = function (heroes) {
  11964. for (const ids in heroes) {
  11965. const hero = heroes[ids];
  11966. hero.energy = random(1, 999);
  11967. if (hero.hp > 0) {
  11968. hero.hp = random(1, hero.hp);
  11969. }
  11970. }
  11971. }
  11972. fixBattle(battle.progress[0].attackers.heroes);
  11973. fixBattle(battle.progress[0].defenders.heroes);
  11974. return this.endBattle(battle);
  11975. }
  11976.  
  11977. /**
  11978. * Ends the fight
  11979. *
  11980. * Заканчивает бой
  11981. */
  11982. async endBattle(battle) {
  11983. battle.progress[0].attackers.input = ['auto', 0, 0, 'auto', 0, 0];
  11984. const calls = [{
  11985. name: "brawl_endBattle",
  11986. args: {
  11987. result: battle.result,
  11988. progress: battle.progress
  11989. },
  11990. ident: "brawl_endBattle"
  11991. },
  11992. this.callBrawlQuestGetInfo,
  11993. this.callBrawlFindEnemies,
  11994. ];
  11995. const result = await Send(JSON.stringify({ calls }));
  11996. return result.results;
  11997. }
  11998.  
  11999. end(endReason) {
  12000. isCancalBattle = true;
  12001. isBrawlsAutoStart = false;
  12002. setProgress(endReason, true);
  12003. console.log(endReason);
  12004. this.resolve();
  12005. }
  12006. }
  12007.  
  12008. class executeEventAutoBoss {
  12009.  
  12010. async start() {
  12011. await this.loadInfo();
  12012. this.generateCombo();
  12013.  
  12014. const countTestBattle = +getInput('countTestBattle');
  12015. const maxCalcBattle = this.combo.length * countTestBattle;
  12016.  
  12017. const resultDialog = await popup.confirm(I18N('EVENT_AUTO_BOSS', {
  12018. length: this.combo.length,
  12019. countTestBattle,
  12020. maxCalcBattle
  12021. }), [
  12022. { msg: I18N('BEST_SLOW'), result: true },
  12023. { msg: I18N('FIRST_FAST'), result: false },
  12024. { isClose: true, result: 'exit' },
  12025. ]);
  12026.  
  12027. if (resultDialog == 'exit') {
  12028. this.end('Отменено');
  12029. return;
  12030. }
  12031.  
  12032. popup.confirm(I18N('FREEZE_INTERFACE'));
  12033.  
  12034. setTimeout(() => {
  12035. this.startFindPack(resultDialog)
  12036. }, 1000)
  12037. }
  12038.  
  12039. async loadInfo() {
  12040. const resultReq = await Send({ calls: [{ name: "teamGetMaxUpgrade", args: {}, ident: "group_1_body" }, { name: "invasion_bossStart", args: { id: 119, heroes: [3, 61], favor: { "61": 6001 } }, ident: "body" }] }).then(e => e.results);
  12041. this.heroes = resultReq[0].result.response;
  12042. this.battle = resultReq[1].result.response;
  12043.  
  12044. this.heroes.hero[61] = this.battle.attackers[1];
  12045. this.battle.attackers = [];
  12046. }
  12047.  
  12048. combinations(arr, n) {
  12049. if (n == 1) {
  12050. return arr.map(function (x) { return [x]; });
  12051. }
  12052. else if (n <= 0) {
  12053. return [];
  12054. }
  12055. var result = [];
  12056. for (var i = 0; i < arr.length; i++) {
  12057. var rest = arr.slice(i + 1);
  12058. var c = this.combinations(rest, n - 1);
  12059. for (var j = 0; j < c.length; j++) {
  12060. c[j].unshift(arr[i]);
  12061. result.push(c[j]);
  12062. }
  12063. }
  12064. return result;
  12065. }
  12066.  
  12067. generateCombo() {
  12068. // const heroesIds = [3, 7, 8, 9, 12, 16, 18, 22, 35, 40, 48, 57, 58, 59];
  12069. const heroesIds = [3, 7, 9, 12, 18, 22, 35, 40, 48, 57, 58, 59];
  12070. this.combo = this.combinations(heroesIds, 4);
  12071. }
  12072.  
  12073. async startFindPack(findBestOfAll) {
  12074. const promises = [];
  12075. let bestBattle = null;
  12076. for (const comb of this.combo) {
  12077. const copyBattle = structuredClone(this.battle);
  12078. const attackers = [];
  12079. for (const id of comb) {
  12080. if (this.heroes.hero[id]) {
  12081. attackers.push(this.heroes.hero[id]);
  12082. }
  12083. }
  12084. attackers.push(this.heroes.hero[61]);
  12085. attackers.push(this.heroes.pet[6001]);
  12086. copyBattle.attackers = attackers;
  12087. const countTestBattle = +getInput('countTestBattle');
  12088. if (findBestOfAll) {
  12089. promises.push(this.CalcBattle(copyBattle, countTestBattle));
  12090. } else {
  12091. try {
  12092. const checkBattle = await this.CalcBattle(copyBattle, countTestBattle);
  12093. if (checkBattle.result.win) {
  12094. bestBattle = checkBattle;
  12095. break;
  12096. }
  12097. } catch(e) {
  12098. console.log(e, copyBattle)
  12099. popup.confirm(I18N('ERROR_F12'));
  12100. this.end(I18N('ERROR_F12'), e, copyBattle)
  12101. return;
  12102. }
  12103. }
  12104. }
  12105.  
  12106. if (findBestOfAll) {
  12107. bestBattle = await Promise.all(promises)
  12108. .then(results => {
  12109. results = results.sort((a, b) => b.coeff - a.coeff).slice(0, 10);
  12110. let maxStars = 0;
  12111. let maxCoeff = -100;
  12112. let maxBattle = null;
  12113. results.forEach(e => {
  12114. if (e.stars > maxStars || e.coeff > maxCoeff) {
  12115. maxCoeff = e.coeff;
  12116. maxStars = e.stars;
  12117. maxBattle = e;
  12118. }
  12119. });
  12120. console.log(results);
  12121. console.log('better', maxCoeff, maxStars, maxBattle, maxBattle.battleData.attackers.map(e => e.id));
  12122. return maxBattle;
  12123. });
  12124. }
  12125.  
  12126. if (!bestBattle || !bestBattle.result.win) {
  12127. let msg = I18N('FAILED_FIND_WIN_PACK');
  12128. let msgc = msg;
  12129. if (bestBattle?.battleData) {
  12130. const heroes = bestBattle.battleData.attackers.map(e => e.id).filter(e => e < 61);
  12131. msg += `</br>${I18N('BEST_PACK')}</br>` + heroes.map(
  12132. id => `<img src="https://heroesweb-a.akamaihd.net/vk/v0952/assets/hero_icons/${('000' + id).slice(-4)}.png"/>`
  12133. ).join('');
  12134. msgc += I18N('BEST_PACK') + heroes.join(',')
  12135. }
  12136.  
  12137. await popup.confirm(msg);
  12138. this.end(msgc);
  12139. return;
  12140. }
  12141.  
  12142. this.heroesPack = bestBattle.battleData.attackers.map(e => e.id).filter(e => e < 6000);
  12143. this.battleLoop();
  12144. }
  12145.  
  12146. async battleLoop() {
  12147. let repeat = false;
  12148. do {
  12149. repeat = false;
  12150. const countAutoBattle = +getInput('countAutoBattle');
  12151. for (let i = 1; i <= countAutoBattle; i++) {
  12152. const startBattle = await Send({
  12153. calls: [{
  12154. name: "invasion_bossStart",
  12155. args: {
  12156. id: 119,
  12157. heroes: this.heroesPack,
  12158. favor: { "61": 6001 },
  12159. pet: 6001
  12160. }, ident: "body"
  12161. }]
  12162. }).then(e => e.results[0].result.response);
  12163. const calcBattle = await Calc(startBattle);
  12164.  
  12165. setProgress(`${i}) ${calcBattle.result.win ? I18N('VICTORY') : I18N('DEFEAT') } `)
  12166. console.log(i, calcBattle.result.win)
  12167. if (!calcBattle.result.win) {
  12168. continue;
  12169. }
  12170.  
  12171. const endBattle = await Send({
  12172. calls: [{
  12173. name: "invasion_bossEnd",
  12174. args: {
  12175. id: 119,
  12176. result: calcBattle.result,
  12177. progress: calcBattle.progress
  12178. }, ident: "body"
  12179. }]
  12180. }).then(e => e.results[0].result.response);
  12181. console.log(endBattle);
  12182. const msg = I18N('BOSS_HAS_BEEN_DEF', { bossLvl: this.battle.typeId });
  12183. await popup.confirm(msg);
  12184. this.end(msg);
  12185. return;
  12186. }
  12187.  
  12188. const msg = I18N('NOT_ENOUGH_ATTEMPTS_BOSS', { bossLvl: this.battle.typeId });
  12189. repeat = await popup.confirm(msg, [
  12190. { msg: 'Да', result: true },
  12191. { msg: 'Нет', result: false },
  12192. ]);
  12193. this.end(I18N('NOT_ENOUGH_ATTEMPTS_BOSS', { bossLvl: this.battle.typeId }));
  12194.  
  12195. } while (repeat)
  12196. }
  12197.  
  12198. calcCoeff(result, packType) {
  12199. let beforeSumFactor = 0;
  12200. const beforePack = result.battleData[packType][0];
  12201. for (let heroId in beforePack) {
  12202. const hero = beforePack[heroId];
  12203. const state = hero.state;
  12204. let factor = 1;
  12205. if (state) {
  12206. const hp = state.hp / state.maxHp;
  12207. factor = hp;
  12208. }
  12209. beforeSumFactor += factor;
  12210. }
  12211.  
  12212. let afterSumFactor = 0;
  12213. const afterPack = result.progress[0][packType].heroes;
  12214. for (let heroId in afterPack) {
  12215. const hero = afterPack[heroId];
  12216. const stateHp = beforePack[heroId]?.state?.hp || beforePack[heroId]?.stats?.hp;
  12217. const hp = hero.hp / stateHp;
  12218. afterSumFactor += hp;
  12219. }
  12220. const resultCoeff = beforeSumFactor / afterSumFactor;
  12221. return resultCoeff;
  12222. }
  12223.  
  12224. async CalcBattle(battle, count) {
  12225. const actions = [];
  12226. for (let i = 0; i < count; i++) {
  12227. battle.seed = Math.floor(Date.now() / 1000) + this.random(0, 1e3);
  12228. actions.push(Calc(battle).then(e => {
  12229. e.coeff = this.calcCoeff(e, 'defenders');
  12230. return e;
  12231. }));
  12232. }
  12233.  
  12234. return Promise.all(actions).then(results => {
  12235. let maxCoeff = -100;
  12236. let maxBattle = null;
  12237. results.forEach(e => {
  12238. if (e.coeff > maxCoeff) {
  12239. maxCoeff = e.coeff;
  12240. maxBattle = e;
  12241. }
  12242. });
  12243. maxBattle.stars = results.reduce((w, s) => w + s.result.stars, 0);
  12244. maxBattle.attempts = results;
  12245. return maxBattle;
  12246. });
  12247. }
  12248.  
  12249. random(min, max) {
  12250. return Math.floor(Math.random() * (max - min + 1) + min);
  12251. }
  12252.  
  12253. end(reason) {
  12254. setProgress('');
  12255. console.log('endEventAutoBoss', reason)
  12256. }
  12257. }
  12258.  
  12259. // подземку вконце впихнул
  12260. function DungeonFull() {
  12261. return new Promise((resolve, reject) => {
  12262. const dung = new executeDungeon2(resolve, reject);
  12263. const titanit = getInput('countTitanit');
  12264. dung.start(titanit);
  12265. });
  12266. }
  12267. /** Прохождение подземелья */
  12268. function executeDungeon2(resolve, reject) {
  12269. let dungeonActivity = 0;
  12270. let startDungeonActivity = 0;
  12271. let maxDungeonActivity = 150;
  12272. let limitDungeonActivity = 30180;
  12273. let countShowStats = 1;
  12274. //let fastMode = isChecked('fastMode');
  12275. let end = false;
  12276.  
  12277. let countTeam = [];
  12278. let timeDungeon = {
  12279. all: new Date().getTime(),
  12280. findAttack: 0,
  12281. attackNeutral: 0,
  12282. attackEarthOrFire: 0
  12283. }
  12284.  
  12285. let titansStates = {};
  12286. let bestBattle = {};
  12287.  
  12288. let teams = {
  12289. neutral: [],
  12290. water: [],
  12291. earth: [],
  12292. fire: [],
  12293. hero: []
  12294. }
  12295.  
  12296. let callsExecuteDungeon = {
  12297. calls: [{
  12298. name: "dungeonGetInfo",
  12299. args: {},
  12300. ident: "dungeonGetInfo"
  12301. }, {
  12302. name: "teamGetAll",
  12303. args: {},
  12304. ident: "teamGetAll"
  12305. }, {
  12306. name: "teamGetFavor",
  12307. args: {},
  12308. ident: "teamGetFavor"
  12309. }, {
  12310. name: "clanGetInfo",
  12311. args: {},
  12312. ident: "clanGetInfo"
  12313. }]
  12314. }
  12315.  
  12316. this.start = async function(titanit) {
  12317. //maxDungeonActivity = titanit > limitDungeonActivity ? limitDungeonActivity : titanit;
  12318. maxDungeonActivity = titanit || getInput('countTitanit');
  12319. send(JSON.stringify(callsExecuteDungeon), startDungeon);
  12320. }
  12321.  
  12322. /** Получаем данные по подземелью */
  12323. function startDungeon(e) {
  12324. stopDung = false; // стоп подземка
  12325. let res = e.results;
  12326. let dungeonGetInfo = res[0].result.response;
  12327. if (!dungeonGetInfo) {
  12328. endDungeon('noDungeon', res);
  12329. return;
  12330. }
  12331. console.log("Начинаем копать на фулл: ", new Date());
  12332. let teamGetAll = res[1].result.response;
  12333. let teamGetFavor = res[2].result.response;
  12334. dungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  12335. startDungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  12336. titansStates = dungeonGetInfo.states.titans;
  12337.  
  12338. teams.hero = {
  12339. favor: teamGetFavor.dungeon_hero,
  12340. heroes: teamGetAll.dungeon_hero.filter(id => id < 6000),
  12341. teamNum: 0,
  12342. }
  12343. let heroPet = teamGetAll.dungeon_hero.filter(id => id >= 6000).pop();
  12344. if (heroPet) {
  12345. teams.hero.pet = heroPet;
  12346. }
  12347. teams.neutral = getTitanTeam('neutral');
  12348. teams.water = {
  12349. favor: {},
  12350. heroes: getTitanTeam('water'),
  12351. teamNum: 0,
  12352. };
  12353. teams.earth = {
  12354. favor: {},
  12355. heroes: getTitanTeam('earth'),
  12356. teamNum: 0,
  12357. };
  12358. teams.fire = {
  12359. favor: {},
  12360. heroes: getTitanTeam('fire'),
  12361. teamNum: 0,
  12362. };
  12363.  
  12364. checkFloor(dungeonGetInfo);
  12365. }
  12366.  
  12367. function getTitanTeam(type) {
  12368. switch (type) {
  12369. case 'neutral':
  12370. return [4023, 4022, 4012, 4021, 4011, 4010, 4020];
  12371. case 'water':
  12372. return [4000, 4001, 4002, 4003]
  12373. .filter(e => !titansStates[e]?.isDead);
  12374. case 'earth':
  12375. return [4020, 4022, 4021, 4023]
  12376. .filter(e => !titansStates[e]?.isDead);
  12377. case 'fire':
  12378. return [4010, 4011, 4012, 4013]
  12379. .filter(e => !titansStates[e]?.isDead);
  12380. }
  12381. }
  12382.  
  12383. /** Создать копию объекта */
  12384. function clone(a) {
  12385. return JSON.parse(JSON.stringify(a));
  12386. }
  12387.  
  12388. /** Находит стихию на этаже */
  12389. function findElement(floor, element) {
  12390. for (let i in floor) {
  12391. if (floor[i].attackerType === element) {
  12392. return i;
  12393. }
  12394. }
  12395. return undefined;
  12396. }
  12397.  
  12398. /** Проверяем этаж */
  12399. async function checkFloor(dungeonInfo) {
  12400. if (!('floor' in dungeonInfo) || dungeonInfo.floor?.state == 2) {
  12401. saveProgress();
  12402. return;
  12403. }
  12404. // console.log(dungeonInfo, dungeonActivity);
  12405. setProgress(`${I18N('DUNGEON2')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  12406. //setProgress('Dungeon: Титанит ' + dungeonActivity + '/' + maxDungeonActivity);
  12407. if (dungeonActivity >= maxDungeonActivity) {
  12408. endDungeon('Стоп подземка,', 'набрано титанита: ' + dungeonActivity + '/' + maxDungeonActivity);
  12409. return;
  12410. }
  12411. let activity = dungeonActivity - startDungeonActivity;
  12412. titansStates = dungeonInfo.states.titans;
  12413. if (stopDung){
  12414. endDungeon('Стоп подземка,', 'набрано титанита: ' + dungeonActivity + '/' + maxDungeonActivity);
  12415. return;
  12416. }
  12417. /*if (activity / 1000 > countShowStats) {
  12418. countShowStats++;
  12419. showStats();
  12420. }*/
  12421. bestBattle = {};
  12422. let floorChoices = dungeonInfo.floor.userData;
  12423. if (floorChoices.length > 1) {
  12424. for (let element in teams) {
  12425. let teamNum = findElement(floorChoices, element);
  12426. if (!!teamNum) {
  12427. if (element == 'earth') {
  12428. teamNum = await chooseEarthOrFire(floorChoices);
  12429. if (teamNum < 0) {
  12430. endDungeon('Невозможно победить без потери Титана!', dungeonInfo);
  12431. return;
  12432. }
  12433. }
  12434. chooseElement(floorChoices[teamNum].attackerType, teamNum);
  12435. return;
  12436. }
  12437. }
  12438. } else {
  12439. chooseElement(floorChoices[0].attackerType, 0);
  12440. }
  12441. }
  12442.  
  12443. /** Выбираем огнем или землей атаковать */
  12444. async function chooseEarthOrFire(floorChoices) {
  12445. bestBattle.recovery = -11;
  12446. let selectedTeamNum = -1;
  12447. for (let attempt = 0; selectedTeamNum < 0 && attempt < 4; attempt++) {
  12448. for (let teamNum in floorChoices) {
  12449. let attackerType = floorChoices[teamNum].attackerType;
  12450. selectedTeamNum = await attemptAttackEarthOrFire(teamNum, attackerType, attempt);
  12451. }
  12452. }
  12453. console.log("Выбор команды огня или земли: ", selectedTeamNum < 0 ? "не сделан" : floorChoices[selectedTeamNum].attackerType);
  12454. return selectedTeamNum;
  12455. }
  12456.  
  12457. /** Попытка атаки землей и огнем */
  12458. async function attemptAttackEarthOrFire(teamNum, attackerType, attempt) {
  12459. let start = new Date();
  12460. let team = clone(teams[attackerType]);
  12461. let startIndex = team.heroes.length + attempt - 4;
  12462. if (startIndex >= 0) {
  12463. team.heroes = team.heroes.slice(startIndex);
  12464. let recovery = await getBestRecovery(teamNum, attackerType, team, 25);
  12465. if (recovery > bestBattle.recovery) {
  12466. bestBattle.recovery = recovery;
  12467. bestBattle.selectedTeamNum = teamNum;
  12468. bestBattle.team = team;
  12469. }
  12470. }
  12471. let workTime = new Date().getTime() - start.getTime();
  12472. timeDungeon.attackEarthOrFire += workTime;
  12473. if (bestBattle.recovery < -10) {
  12474. return -1;
  12475. }
  12476. return bestBattle.selectedTeamNum;
  12477. }
  12478.  
  12479. /** Выбираем стихию для атаки */
  12480. async function chooseElement(attackerType, teamNum) {
  12481. let result;
  12482. switch (attackerType) {
  12483. case 'hero':
  12484. case 'water':
  12485. result = await startBattle(teamNum, attackerType, teams[attackerType]);
  12486. break;
  12487. case 'earth':
  12488. case 'fire':
  12489. result = await attackEarthOrFire(teamNum, attackerType);
  12490. break;
  12491. case 'neutral':
  12492. result = await attackNeutral(teamNum, attackerType);
  12493. }
  12494. if (!!result && attackerType != 'hero') {
  12495. let recovery = (!!!bestBattle.recovery ? 10 * getRecovery(result) : bestBattle.recovery) * 100;
  12496. let titans = result.progress[0].attackers.heroes;
  12497. console.log("Проведен бой: " + attackerType +
  12498. ", recovery = " + (recovery > 0 ? "+" : "") + Math.round(recovery) + "% \r\n", titans);
  12499. }
  12500. endBattle(result);
  12501. }
  12502.  
  12503. /** Атакуем Землей или Огнем */
  12504. async function attackEarthOrFire(teamNum, attackerType) {
  12505. if (!!!bestBattle.recovery) {
  12506. bestBattle.recovery = -11;
  12507. let selectedTeamNum = -1;
  12508. for (let attempt = 0; selectedTeamNum < 0 && attempt < 4; attempt++) {
  12509. selectedTeamNum = await attemptAttackEarthOrFire(teamNum, attackerType, attempt);
  12510. }
  12511. if (selectedTeamNum < 0) {
  12512. endDungeon('Невозможно победить без потери Титана!', attackerType);
  12513. return;
  12514. }
  12515. }
  12516. return findAttack(teamNum, attackerType, bestBattle.team);
  12517. }
  12518.  
  12519. /** Находим подходящий результат для атаки */
  12520. async function findAttack(teamNum, attackerType, team) {
  12521. let start = new Date();
  12522. let recovery = -1000;
  12523. let iterations = 0;
  12524. let result;
  12525. let correction = 0.01;
  12526. for (let needRecovery = bestBattle.recovery; recovery < needRecovery; needRecovery -= correction, iterations++) {
  12527. result = await startBattle(teamNum, attackerType, team);
  12528. recovery = getRecovery(result);
  12529. }
  12530. bestBattle.recovery = recovery;
  12531. let workTime = new Date().getTime() - start.getTime();
  12532. timeDungeon.findAttack += workTime;
  12533. return result;
  12534. }
  12535.  
  12536. /** Атакуем Нейтральной командой */
  12537. async function attackNeutral(teamNum, attackerType) {
  12538. let start = new Date();
  12539. let factors = calcFactor();
  12540. bestBattle.recovery = -0.2;
  12541. await findBestBattleNeutral(teamNum, attackerType, factors, true)
  12542. if (bestBattle.recovery < 0 || (bestBattle.recovery < 0.2 && factors[0].value < 0.5)) {
  12543. let recovery = 100 * bestBattle.recovery;
  12544. console.log("Не удалось найти удачный бой в быстром режиме: " + attackerType +
  12545. ", recovery = " + (recovery > 0 ? "+" : "") + Math.round(recovery) + "% \r\n", bestBattle.attackers);
  12546. await findBestBattleNeutral(teamNum, attackerType, factors, false)
  12547. }
  12548. let workTime = new Date().getTime() - start.getTime();
  12549. timeDungeon.attackNeutral += workTime;
  12550. if (!!bestBattle.attackers) {
  12551. let team = getTeam(bestBattle.attackers);
  12552. return findAttack(teamNum, attackerType, team);
  12553. }
  12554. endDungeon('Не удалось найти удачный бой!', attackerType);
  12555. return undefined;
  12556. }
  12557.  
  12558. /** Находит лучшую нейтральную команду */
  12559. async function findBestBattleNeutral(teamNum, attackerType, factors, mode) {
  12560. let countFactors = factors.length < 4 ? factors.length : 4;
  12561. let aradgi = !titansStates['4013']?.isDead;
  12562. let edem = !titansStates['4023']?.isDead;
  12563. let dark = [4032, 4033].filter(e => !titansStates[e]?.isDead);
  12564. let light = [4042].filter(e => !titansStates[e]?.isDead);
  12565. let actions = [];
  12566. if (mode) {
  12567. for (let i = 0; i < countFactors; i++) {
  12568. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(factors[i].id)));
  12569. }
  12570. if (countFactors > 1) {
  12571. let firstId = factors[0].id;
  12572. let secondId = factors[1].id;
  12573. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, secondId)));
  12574. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, secondId)));
  12575. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4003, secondId)));
  12576. }
  12577. if (aradgi) {
  12578. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(4013)));
  12579. if (countFactors > 0) {
  12580. let firstId = factors[0].id;
  12581. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4000, 4013)));
  12582. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, 4013)));
  12583. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, 4013)));
  12584. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4003, 4013)));
  12585. }
  12586. if (edem) {
  12587. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(4023, 4000, 4013)));
  12588. }
  12589. }
  12590. } else {
  12591. if (mode) {
  12592. for (let i = 0; i < factors.length; i++) {
  12593. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(factors[i].id)));
  12594. }
  12595. } else {
  12596. countFactors = factors.length < 2 ? factors.length : 2;
  12597. }
  12598. for (let i = 0; i < countFactors; i++) {
  12599. let mainId = factors[i].id;
  12600. if (aradgi && (mode || i > 0)) {
  12601. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4000, 4013)));
  12602. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, 4013)));
  12603. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, 4013)));
  12604. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4003, 4013)));
  12605. }
  12606. for (let i = 0; i < dark.length; i++) {
  12607. let darkId = dark[i];
  12608. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, darkId)));
  12609. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, darkId)));
  12610. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4003, darkId)));
  12611. }
  12612. for (let i = 0; i < light.length; i++) {
  12613. let lightId = light[i];
  12614. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, lightId)));
  12615. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, lightId)));
  12616. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4003, lightId)));
  12617. }
  12618. let isFull = mode || i > 0;
  12619. for (let j = isFull ? i + 1 : 2; j < factors.length; j++) {
  12620. let extraId = factors[j].id;
  12621. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4000, extraId)));
  12622. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4001, extraId)));
  12623. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(mainId, 4002, extraId)));
  12624. }
  12625. }
  12626. if (aradgi) {
  12627. if (mode) {
  12628. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(4013)));
  12629. }
  12630. for (let i = 0; i < dark.length; i++) {
  12631. let darkId = dark[i];
  12632. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(darkId, 4001, 4013)));
  12633. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(darkId, 4002, 4013)));
  12634. }
  12635. for (let i = 0; i < light.length; i++) {
  12636. let lightId = light[i];
  12637. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(lightId, 4001, 4013)));
  12638. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(lightId, 4002, 4013)));
  12639. }
  12640. }
  12641. for (let i = 0; i < dark.length; i++) {
  12642. let firstId = dark[i];
  12643. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId)));
  12644. for (let j = i + 1; j < dark.length; j++) {
  12645. let secondId = dark[j];
  12646. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, secondId)));
  12647. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, secondId)));
  12648. }
  12649. }
  12650. for (let i = 0; i < light.length; i++) {
  12651. let firstId = light[i];
  12652. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId)));
  12653. for (let j = i + 1; j < light.length; j++) {
  12654. let secondId = light[j];
  12655. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4001, secondId)));
  12656. actions.push(startBattle(teamNum, attackerType, getNeutralTeam(firstId, 4002, secondId)));
  12657. }
  12658. }
  12659. }
  12660. for (let result of await Promise.all(actions)) {
  12661. let recovery = getRecovery(result);
  12662. if (recovery > bestBattle.recovery) {
  12663. bestBattle.recovery = recovery;
  12664. bestBattle.attackers = result.progress[0].attackers.heroes;
  12665. }
  12666. }
  12667. }
  12668.  
  12669. /** Получаем нейтральную команду */
  12670. function getNeutralTeam(id, swapId, addId) {
  12671. let neutralTeam = clone(teams.water);
  12672. let neutral = neutralTeam.heroes;
  12673. if (neutral.length == 4) {
  12674. if (!!swapId) {
  12675. for (let i in neutral) {
  12676. if (neutral[i] == swapId) {
  12677. neutral[i] = addId;
  12678. }
  12679. }
  12680. }
  12681. } else if (!!addId) {
  12682. neutral.push(addId);
  12683. }
  12684. neutral.push(id);
  12685. return neutralTeam;
  12686. }
  12687.  
  12688. /** Получить команду титанов */
  12689. function getTeam(titans) {
  12690. return {
  12691. favor: {},
  12692. heroes: Object.keys(titans).map(id => parseInt(id)),
  12693. teamNum: 0,
  12694. };
  12695. }
  12696.  
  12697. /** Вычисляем фактор боеготовности титанов */
  12698. function calcFactor() {
  12699. let neutral = teams.neutral;
  12700. let factors = [];
  12701. for (let i in neutral) {
  12702. let titanId = neutral[i];
  12703. let titan = titansStates[titanId];
  12704. let factor = !!titan ? titan.hp / titan.maxHp + titan.energy / 10000.0 : 1;
  12705. if (factor > 0) {
  12706. factors.push({id: titanId, value: factor});
  12707. }
  12708. }
  12709. factors.sort(function(a, b) {
  12710. return a.value - b.value;
  12711. });
  12712. return factors;
  12713. }
  12714.  
  12715. /** Возвращает наилучший результат из нескольких боев */
  12716. async function getBestRecovery(teamNum, attackerType, team, countBattle) {
  12717. let bestRecovery = -1000;
  12718. let actions = [];
  12719. for (let i = 0; i < countBattle; i++) {
  12720. actions.push(startBattle(teamNum, attackerType, team));
  12721. }
  12722. for (let result of await Promise.all(actions)) {
  12723. let recovery = getRecovery(result);
  12724. if (recovery > bestRecovery) {
  12725. bestRecovery = recovery;
  12726. }
  12727. }
  12728. return bestRecovery;
  12729. }
  12730.  
  12731. /** Возвращает разницу в здоровье атакующей команды после и до битвы и проверяет здоровье титанов на необходимый минимум*/
  12732. function getRecovery(result) {
  12733. if (result.result.stars < 3) {
  12734. return -100;
  12735. }
  12736. let beforeSumFactor = 0;
  12737. let afterSumFactor = 0;
  12738. let beforeTitans = result.battleData.attackers;
  12739. let afterTitans = result.progress[0].attackers.heroes;
  12740. for (let i in afterTitans) {
  12741. let titan = afterTitans[i];
  12742. let percentHP = titan.hp / beforeTitans[i].hp;
  12743. let energy = titan.energy;
  12744. let factor = checkTitan(i, energy, percentHP) ? getFactor(i, energy, percentHP) : -100;
  12745. afterSumFactor += factor;
  12746. }
  12747. for (let i in beforeTitans) {
  12748. let titan = beforeTitans[i];
  12749. let state = titan.state;
  12750. beforeSumFactor += !!state ? getFactor(i, state.energy, state.hp / titan.hp) : 1;
  12751. }
  12752. return afterSumFactor - beforeSumFactor;
  12753. }
  12754.  
  12755. /** Возвращает состояние титана*/
  12756. function getFactor(id, energy, percentHP) {
  12757. let elemantId = id.slice(2, 3);
  12758. let isEarthOrFire = elemantId == '1' || elemantId == '2';
  12759. let energyBonus = id == '4020' && energy == 1000 ? 0.1 : energy / 20000.0;
  12760. let factor = percentHP + energyBonus;
  12761. return isEarthOrFire ? factor : factor / 10;
  12762. }
  12763.  
  12764. /** Проверяет состояние титана*/
  12765. function checkTitan(id, energy, percentHP) {
  12766. switch (id) {
  12767. case '4020':
  12768. return percentHP > 0.25 || (energy == 1000 && percentHP > 0.05);
  12769. break;
  12770. case '4010':
  12771. return percentHP + energy / 2000.0 > 0.63;
  12772. break;
  12773. case '4000':
  12774. return percentHP > 0.62 || (energy < 1000 && (
  12775. (percentHP > 0.45 && energy >= 400) ||
  12776. (percentHP > 0.3 && energy >= 670)));
  12777. }
  12778. return true;
  12779. }
  12780.  
  12781.  
  12782. /** Начинаем бой */
  12783. function startBattle(teamNum, attackerType, args) {
  12784. return new Promise(function (resolve, reject) {
  12785. args.teamNum = teamNum;
  12786. let startBattleCall = {
  12787. calls: [{
  12788. name: "dungeonStartBattle",
  12789. args,
  12790. ident: "body"
  12791. }]
  12792. }
  12793. send(JSON.stringify(startBattleCall), resultBattle, {
  12794. resolve,
  12795. teamNum,
  12796. attackerType
  12797. });
  12798. });
  12799. }
  12800.  
  12801. /** Возращает результат боя в промис */
  12802. /*function resultBattle(resultBattles, args) {
  12803. if (!!resultBattles && !!resultBattles.results) {
  12804. let battleData = resultBattles.results[0].result.response;
  12805. let battleType = "get_tower";
  12806. if (battleData.type == "dungeon_titan") {
  12807. battleType = "get_titan";
  12808. }
  12809. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];//тест подземка правки
  12810. BattleCalc(battleData, battleType, function (result) {
  12811. result.teamNum = args.teamNum;
  12812. result.attackerType = args.attackerType;
  12813. args.resolve(result);
  12814. });
  12815. } else {
  12816. endDungeon('Потеряна связь с сервером игры!', 'break');
  12817. }
  12818. }*/
  12819. function resultBattle(resultBattles, args) {
  12820. battleData = resultBattles.results[0].result.response;
  12821. battleType = "get_tower";
  12822. if (battleData.type == "dungeon_titan") {
  12823. battleType = "get_titan";
  12824. }
  12825. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  12826. BattleCalc(battleData, battleType, function (result) {
  12827. result.teamNum = args.teamNum;
  12828. result.attackerType = args.attackerType;
  12829. args.resolve(result);
  12830. });
  12831. }
  12832.  
  12833. /** Заканчиваем бой */
  12834.  
  12835. ////
  12836. async function endBattle(battleInfo) {
  12837. if (!!battleInfo) {
  12838. const args = {
  12839. result: battleInfo.result,
  12840. progress: battleInfo.progress,
  12841. }
  12842. if (battleInfo.result.stars < 3) {
  12843. endDungeon('Герой или Титан мог погибнуть в бою!', battleInfo);
  12844. return;
  12845. }
  12846. if (countPredictionCard > 0) {
  12847. args.isRaid = true;
  12848. } else {
  12849. const timer = getTimer(battleInfo.battleTime);
  12850. console.log(timer);
  12851. await countdownTimer(timer, `${I18N('DUNGEON2')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity}`);
  12852. }
  12853. const calls = [{
  12854. name: "dungeonEndBattle",
  12855. args,
  12856. ident: "body"
  12857. }];
  12858. lastDungeonBattleData = null;
  12859. send(JSON.stringify({ calls }), resultEndBattle);
  12860. } else {
  12861. endDungeon('dungeonEndBattle win: false\n', battleInfo);
  12862. }
  12863. }
  12864. /** Получаем и обрабатываем результаты боя */
  12865. function resultEndBattle(e) {
  12866. if (!!e && !!e.results) {
  12867. let battleResult = e.results[0].result.response;
  12868. if ('error' in battleResult) {
  12869. endDungeon('errorBattleResult', battleResult);
  12870. return;
  12871. }
  12872. let dungeonGetInfo = battleResult.dungeon ?? battleResult;
  12873. dungeonActivity += battleResult.reward.dungeonActivity ?? 0;
  12874. checkFloor(dungeonGetInfo);
  12875. } else {
  12876. endDungeon('Потеряна связь с сервером игры!', 'break');
  12877. }
  12878. }
  12879.  
  12880. /** Добавить команду титанов в общий список команд */
  12881. function addTeam(team) {
  12882. for (let i in countTeam) {
  12883. if (equalsTeam(countTeam[i].team, team)) {
  12884. countTeam[i].count++;
  12885. return;
  12886. }
  12887. }
  12888. countTeam.push({team: team, count: 1});
  12889. }
  12890.  
  12891. /** Сравнить команды на равенство */
  12892. function equalsTeam(team1, team2) {
  12893. if (team1.length == team2.length) {
  12894. for (let i in team1) {
  12895. if (team1[i] != team2[i]) {
  12896. return false;
  12897. }
  12898. }
  12899. return true;
  12900. }
  12901. return false;
  12902. }
  12903.  
  12904. function saveProgress() {
  12905. let saveProgressCall = {
  12906. calls: [{
  12907. name: "dungeonSaveProgress",
  12908. args: {},
  12909. ident: "body"
  12910. }]
  12911. }
  12912. send(JSON.stringify(saveProgressCall), resultEndBattle);
  12913. }
  12914.  
  12915.  
  12916. /** Выводит статистику прохождения подземелья */
  12917. function showStats() {
  12918. let activity = dungeonActivity - startDungeonActivity;
  12919. let workTime = clone(timeDungeon);
  12920. workTime.all = new Date().getTime() - workTime.all;
  12921. for (let i in workTime) {
  12922. workTime[i] = (workTime[i] / 1000).round(0);
  12923. }
  12924. countTeam.sort(function(a, b) {
  12925. return b.count - a.count;
  12926. });
  12927. console.log(titansStates);
  12928. console.log("Собрано титанита: ", activity);
  12929. console.log("Скорость сбора: " + (3600 * activity / workTime.all).round(0) + " титанита/час");
  12930. console.log("Время раскопок: ");
  12931. for (let i in workTime) {
  12932. let timeNow = workTime[i];
  12933. console.log(i + ": ", (timeNow / 3600).round(0) + " ч. " + (timeNow % 3600 / 60).round(0) + " мин. " + timeNow % 60 + " сек.");
  12934. }
  12935. console.log("Частота использования команд: ");
  12936. for (let i in countTeam) {
  12937. let teams = countTeam[i];
  12938. console.log(teams.team + ": ", teams.count);
  12939. }
  12940. }
  12941.  
  12942. /** Заканчиваем копать подземелье */
  12943. function endDungeon(reason, info) {
  12944. if (!end) {
  12945. end = true;
  12946. console.log(reason, info);
  12947. showStats();
  12948. if (info == 'break') {
  12949. setProgress('Dungeon stoped: Титанит ' + dungeonActivity + '/' + maxDungeonActivity +
  12950. "\r\nПотеряна связь с сервером игры!", false, hideProgress);
  12951. } else {
  12952. setProgress('Dungeon completed: Титанит ' + dungeonActivity + '/' + maxDungeonActivity, false, hideProgress);
  12953. }
  12954. setTimeout(cheats.refreshGame, 1000);
  12955. resolve();
  12956. }
  12957. }
  12958. }
  12959.  
  12960. //дарим подарки участникам других гильдий не выходя из своей гильдии
  12961. function NewYearGift_Clan() {
  12962. console.log('NewYearGift_Clan called...');
  12963. const userID = getInput('userID');
  12964. const AmontID = getInput('AmontID');
  12965. const GiftNum = getInput('GiftNum');
  12966.  
  12967. const data = {
  12968. "calls": [{
  12969. "name": "newYearGiftSend",
  12970. "args": {
  12971. "userId": userID,
  12972. "amount": AmontID,
  12973. "giftNum": GiftNum,
  12974. "users": {
  12975. [userID]: AmontID
  12976. }
  12977. },
  12978. "ident": "body"
  12979. }
  12980. ]
  12981. }
  12982.  
  12983. const dataJson = JSON.stringify(data);
  12984.  
  12985. SendRequest(dataJson, e => {
  12986. let userInfo = e.results[0].result.response;
  12987. console.log(userInfo);
  12988. });
  12989. setProgress(I18N('SEND_GIFT'), true);
  12990. }
  12991. })();
  12992.  
  12993. /**
  12994. * TODO:
  12995. * Получение всех уровней при сборе всех наград (квест на титанит и на энку) +-
  12996. * Добивание на арене титанов
  12997. * Закрытие окошек по Esc +-
  12998. * Починить работу скрипта на уровне команды ниже 10 +-
  12999. * Написать номальную синхронизацию
  13000. * Добавить дополнительные настройки автопокупки в "Тайном богатстве"
  13001. */
  13002.