idle

挂机无止境的辅助脚本

目前为 2019-04-11 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name idle
  3. // @version 1.35
  4. // @namespace ErQi
  5. // @description 挂机无止境的辅助脚本
  6. // @author beside4ever@outlook.com
  7. // @grant GM_addStyle
  8. // @run-at document-start
  9. // @match https://www.idleinfinity.cn/*
  10. // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js
  11. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery-url-parser/2.3.1/purl.min.js
  12. // ==/UserScript==
  13.  
  14. const defaultFilterOptions = ['技能', '凹槽(0/2)', '凹槽(0/4)', '取得魔法装备', '攻击速度', '施法速度', '+20 毒素', '+25 毒素'];
  15.  
  16. let config = {
  17. userNumber: 1,
  18. showRequire: true,
  19. fastFilter: true,
  20. fastOptions: defaultFilterOptions.slice(0), // 快速过滤器配置,可自行增删
  21. showSpellColor: true,
  22. showSpeedLevel: true,
  23. showCharDmg: true,
  24. showAccuracy: true,
  25. dropNotification: true,
  26. itemStats: true,
  27. showBattle: true,
  28. mapHack: true,
  29. mapHackType: 'all',
  30. infiniteMap: false,
  31. showSetAttr: true,
  32. showAuctionNote: true,
  33. auctionWatch: true,
  34. oneKeyEquip: true,
  35. oneKeyAgree: true,
  36. oneKeyRune: true,
  37. showRuneTip: true,
  38. showBattleDetail: true,
  39. d3theme: true,
  40. minLevel: null,
  41. // 秘境的石头等级 0 表示普通 1表示魔法 2表示稀有,以此类推 按照下拉列表的排序
  42. level: '',
  43. moveTime: 5000,
  44. failure: 10,
  45. };
  46.  
  47. const configLabel = {
  48. showRequire: '职业专属显示',
  49. fastFilter: '快速过滤选项',
  50. showSpellColor: '法术技能高亮',
  51. showSpeedLevel: '显示速度档位',
  52. showCharDmg: '角色均伤显示',
  53. showAccuracy: '角色命中显示',
  54. dropNotification: '欧皇暗金通知',
  55. itemStats: '欧皇收获统计',
  56. showBattle: '快速秘境战斗',
  57. mapHack: '秘境自动战斗',
  58. infiniteMap: '无限秘境模式',
  59. showSetAttr: '显示套装属性',
  60. showAuctionNote: '显示拍卖备注',
  61. auctionWatch: '拍卖特别关注',
  62. oneKeyEquip: '一键换装功能',
  63. oneKeyAgree: '一键同意功能',
  64. oneKeyRune: '一键转移符文',
  65. showRuneTip: '符文之语提示',
  66. showBattleDetail: '战斗详细分析',
  67. d3theme: '暗黑界面皮肤',
  68. minLevel: '符文序号',
  69. failure: '失败重置次数'
  70. };
  71.  
  72. const userConfig = ['dropNotification', 'd3theme'];
  73.  
  74. let localConfig = localStorage.getItem('idle-ui-config');
  75. if (localConfig) {
  76. localConfig = JSON.parse(localConfig);
  77. Object.keys(localConfig).map(key => {
  78. if (config[key] !== undefined) config[key] = localConfig[key];
  79. });
  80. }
  81.  
  82. if (config.d3theme) {
  83. const htmlElement = document.getElementsByTagName('html')[0];
  84. htmlElement.setAttribute('class', 'd3');
  85. }
  86.  
  87. function idleInit() {
  88. // 秘境的石头等级 ''空表示所有秘境 0 表示普通 1表示魔法 2表示稀有,以此类推 按照下拉列表的排序
  89. config.level = '';
  90. // 转移物品间隔时间,单位毫秒,最低不能低于300,会被制裁
  91. config.moveTime = 500;
  92. // 战斗失败重置次数,当同一组怪物失败到达此次数,自动重置当前秘境
  93. config.failure = 10;
  94. var style = document.createElement('style');
  95. style.type = 'text/css';
  96. style.innerHTML = `.eq-weapon { background-color: #700;} .eq-armor {background-color: #007;} .eq-amulet {background-color: #0b0;} .eq-delete {background-color: gray;}
  97. .eq-jewel {background-color: #808a87;} .selected-b {border: 1px solid #66ccff!important;} .selected-r {border: 1px solid #f00!important;} .selected-d {border: 1px solid #fff!important;}`;
  98. document.getElementsByTagName('head')[0].appendChild(style);
  99.  
  100. // Extend page width
  101. // $('.container:nth(1)').css('width', '70%');
  102. $('body').css('height', $('body').height() + 500);
  103.  
  104. var equips = $(".panel-filter").parent().prev().find(".equip-content");
  105. var on_gears = $('.equip-container .equip-content');
  106. var i, gear, ps, hits, key, n_name, eqn;
  107. for (i = 0; i < on_gears.length; i++) {
  108. gear = on_gears[i];
  109. ps = gear.getElementsByTagName('p');
  110. if (ps.length > 0) {
  111. hits = gear.innerHTML.match(/彩虹刻面/);
  112. if (hits != null) {
  113. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  114. hits = gear.innerHTML.match(/(\d+)陨石/);
  115. if (hits != null) {
  116. eqn[eqn.length - 1].innerHTML += ' <span style="color:red; background-color: black;">火刻 ' + hits[1] + 'slv</span>';
  117. }
  118. hits = gear.innerHTML.match(/(\d+)暴风雪/);
  119. if (hits != null) {
  120. eqn[eqn.length - 1].innerHTML += ' <span style="color:#3ff; background-color: black;">冰刻 ' + hits[1] + 'slv</span>';
  121. }
  122. hits = gear.innerHTML.match(/(\d+)连锁闪电/);
  123. if (hits != null) {
  124. eqn[eqn.length - 1].innerHTML += ' <span style="color:yellow; background-color: black;">电刻 ' + hits[1] + 'slv</span>';
  125. }
  126. hits = gear.innerHTML.match(/(\d+)剧毒新星/);
  127. if (hits != null) {
  128. eqn[eqn.length - 1].innerHTML += ' <span style="color:#00c400; background-color: black;">毒刻 ' + hits[1] + 'slv</span>';
  129. }
  130. hits = gear.innerHTML.match(/(\d+)虚化/);
  131. if (hits != null) {
  132. eqn[eqn.length - 1].innerHTML += ' <span style="color:#B659F5; background-color: black;">魔刻 ' + hits[1] + 'slv</span>';
  133. }
  134. hits = gear.innerHTML.match(/(\d+)伤害加深/);
  135. if (hits != null) {
  136. eqn[eqn.length - 1].innerHTML += ' <span style="color:white; background-color: black;">物刻</span>';
  137. }
  138. hits = gear.innerHTML.match(/(\d+)\% 火焰伤害/);
  139. if (hits != null) {
  140. eqn[eqn.length - 1].innerHTML += ' <span style="color:red; background-color: black;">+' + hits[1] + '</span>';
  141. }
  142. hits = gear.innerHTML.match(/(\d+)\% 冰冷伤害/);
  143. if (hits != null) {
  144. eqn[eqn.length - 1].innerHTML += ' <span style="color:#3ff; background-color: black;">+' + hits[1] + '</span>';
  145. }
  146. hits = gear.innerHTML.match(/(\d+)\% 闪电伤害/);
  147. if (hits != null) {
  148. eqn[eqn.length - 1].innerHTML += ' <span style="color:yellow; background-color: black;">+' + hits[1] + '</span>';
  149. }
  150. hits = gear.innerHTML.match(/(\d+)\% 毒素伤害/);
  151. if (hits != null) {
  152. eqn[eqn.length - 1].innerHTML += ' <span style="color:#00c400; background-color: black;">+' + hits[1] + '</span>';
  153. }
  154. hits = gear.innerHTML.match(/(\d+)\% 魔法伤害/);
  155. if (hits != null) {
  156. eqn[eqn.length - 1].innerHTML += ' <span style="color:#B659F5; background-color: black;">+' + hits[1] + '</span>';
  157. }
  158. hits = gear.innerHTML.match(/(\d+)\% 物理伤害/);
  159. if (hits != null) {
  160. eqn[eqn.length - 1].innerHTML += ' <span style="color:white; background-color: black;">+' + hits[1] + '</span>';
  161. }
  162. hits = gear.innerHTML.match(/(\d+)\% 目标火焰抗性/);
  163. if (hits != null) {
  164. eqn[eqn.length - 1].innerHTML += ' <span style="color:red; background-color: black;">-' + hits[1] + '</span>';
  165. }
  166. hits = gear.innerHTML.match(/(\d+)\% 目标冰冷抗性/);
  167. if (hits != null) {
  168. eqn[eqn.length - 1].innerHTML += ' <span style="color:#3ff; background-color: black;">-' + hits[1] + '</span>';
  169. }
  170. hits = gear.innerHTML.match(/(\d+)\% 目标闪电抗性/);
  171. if (hits != null) {
  172. eqn[eqn.length - 1].innerHTML += ' <span style="color:yellow; background-color: black;">-' + hits[1] + '</span>';
  173. }
  174. hits = gear.innerHTML.match(/(\d+)\% 目标毒素抗性/);
  175. if (hits != null) {
  176. eqn[eqn.length - 1].innerHTML += ' <span style="color:#00c400; background-color: black;">-' + hits[1] + '</span>';
  177. }
  178. }
  179. hits = gear.innerHTML.match(/攻击速度提升 (\d+)\%/);
  180. if (hits != null) {
  181. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  182. eqn[eqn.length - 1].innerHTML += ' <span style="color:#ffd700; background-color: black;">' + hits[1] + 'ias </span>';
  183. }
  184. hits = gear.innerHTML.match(/施法速度提升 (\d+)\%/);
  185. if (hits != null) {
  186. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  187. eqn[eqn.length - 1].innerHTML += ' <span style="color:#ff8000; background-color: black;">' + hits[1] + 'fcr </span>';
  188. }
  189. hits = gear.innerHTML.match(/\+(\d+)\% 增强伤害/);
  190. if (hits != null) {
  191. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  192. eqn[eqn.length - 1].innerHTML += ' <span style="color:#66ccff; background-color: black;">' + hits[1] + 'ed </span>';
  193. }
  194. hits = gear.innerHTML.match(/\+(\d+)\% 暴击几率/);
  195. if (hits != null) {
  196. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  197. eqn[eqn.length - 1].innerHTML += ' <span style="color:#CCCC00; background-color: black;">' + hits[1] + 'cri </span>';
  198. }
  199. hits = ps[ps.length - 1].textContent.match(/凹槽(\(\d+\/\d+\))/);
  200. if (hits != null) {
  201. eqn = gear.previousElementSibling.getElementsByClassName('equip-name')
  202. eqn[eqn.length - 1].innerHTML += ' <span>' + hits[1] + ' </span>';
  203. }
  204. hits = gear.innerHTML.match(/\+(\d+)\% 更佳的机会取得魔法装备/);
  205. if (hits != null) {
  206. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  207. eqn[eqn.length - 1].innerHTML += ' <span style="color:white; background-color: black;"> ' + hits[1] + 'mf </span>';
  208. }
  209. hits = gear.innerHTML.match(/\+(\d+)\% 额外金币从怪物身上取得/);
  210. if (hits != null) {
  211. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  212. eqn[eqn.length - 1].innerHTML += ' <span style="color:gold; background-color: black;"> ' + hits[1] + 'gf </span>';
  213. }
  214. hits = gear.innerHTML.match(/元素抗性 \+(\d+)\%/);
  215. if (hits != null) {
  216. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  217. eqn[eqn.length - 1].innerHTML += ' <span style="color:#f90; background-color: black;">' + hits[1] + 'ar </span>';
  218. }
  219. hits = gear.innerHTML.match(/抗火 \+(\d+)\%/);
  220. if (hits != null) {
  221. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  222. eqn[eqn.length - 1].innerHTML += ' <span style="color:red; background-color: black;">' + hits[1] + 'f </span>';
  223. }
  224. hits = gear.innerHTML.match(/抗寒 \+(\d+)\%/);
  225. if (hits != null) {
  226. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  227. eqn[eqn.length - 1].innerHTML += ' <span style="color:#3ff; background-color: black;">' + hits[1] + 'c </span>';
  228. }
  229. hits = gear.innerHTML.match(/抗闪电 \+(\d+)\%/);
  230. if (hits != null) {
  231. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  232. eqn[eqn.length - 1].innerHTML += ' <span style="color:yellow; background-color: black;">' + hits[1] + 'l </span>';
  233. }
  234. hits = gear.innerHTML.match(/抗毒 \+(\d+)\%/);
  235. if (hits != null) {
  236. eqn = gear.previousElementSibling.getElementsByClassName('equip-name');
  237. eqn[eqn.length - 1].innerHTML += ' <span style="color:#00c400; background-color: black;">' + hits[1] + 'p </span>';
  238. }
  239. }
  240. }
  241.  
  242. addConfig();
  243. // 显示限定字符
  244. switchSkin(config.showRequire);
  245. Notification.requestPermission();
  246.  
  247. $('.navbar-nav > li > a').each(function () {
  248. if ($(this).text().indexOf('帮助') >= 0) {
  249. const links = [
  250. {text: '暗金列表', link: '/Help/Content?url=Unique'},
  251. {text: '套装列表', link: '/Help/Content?url=Set'},
  252. {text: '秘境圣衣', link: '/Help/Content?url=Sacred'},
  253. {text: '神器列表', link: '/Help/Content?url=Artifact'},
  254. {text: '普通物品', link: '/Help/Content?url=BaseEquip'},
  255. {text: '前缀属性', link: '/Help/Content?url=Prefix'},
  256. {text: '后缀属性', link: '/Help/Content?url=Suffix'},
  257. {text: '固定词缀', link: '/Help/Content?url=SpecialAffix'},
  258. ].map(item => {
  259. return `<li><a class="base" href="${item.link}" target="_blank">${item.text}</a></li>`;
  260. }).join('');
  261. $(this).next().append(links);
  262. }
  263. });
  264.  
  265. function fetchItem(name, callback) {
  266. if (!name) return;
  267. if (quickSearchType === 'Set' || quickSearchType === 'Unique') {
  268. $.get(`/Help/${quickSearchType}`, function (html) {
  269. const dom = $.parseHTML(html);
  270. const type = quickSearchType.toLowerCase();
  271. $(dom).find(`.equip > .${type}`).each(function () {
  272. if ($(this).text().indexOf(name) >= 0) {
  273. callback($(this).parent());
  274. return;
  275. }
  276. });
  277. });
  278. } else {
  279. $.get('/Help/Artifact', function (html) {
  280. const dom = $.parseHTML(html);
  281. $(dom).find('tr').each(function (i) {
  282. if (i > 0) {
  283. const nameLabel = $(this).children().last().find('.artifact');
  284. if (nameLabel.text().indexOf(name) >= 0) {
  285. const ret = [];
  286. ret.push(`<p class="artifact">${nameLabel.text()}</p>`);
  287. $(this).children().first().children('div').each(function () {
  288. ret.push(`<p class="physical">${$(this).text()}</p>`);
  289. });
  290. ret.push('<p class="artifact">神器</p>');
  291. nameLabel.parent().children().each(function (index) {
  292. if (index > 0) ret.push(`<p>${$(this).text()}</p>`);
  293. });
  294. const recipe = [];
  295. $(this).children().eq(1).find('.artifact.equip-name').each(function () {
  296. const id = $(this).text().match(/\d+/g)[0];
  297. recipe.push(`<span class="artifact">${id}#</span>`);
  298. });
  299. ret.push(`<p class="physical">${recipe.join(' + ')}</p>`);
  300. callback($(`<div class="equip">${ret.join('')}</div>`));
  301. return;
  302. }
  303. }
  304. });
  305. });
  306. }
  307. }
  308.  
  309. let quickSearchType = 'Unique';
  310. const itemTypes = `
  311. <div class="btn-group">
  312. <button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown">
  313. <span id="idle-quick-type">暗金</span><span class="caret" style="margin-left: 5px;"></span>
  314. </button>
  315. <ul class="dropdown-menu">
  316. <li><a class="quick-option unique" data-type="Unique" href="javascript: void(0);">暗金</a></li>
  317. <li><a class="quick-option set" data-type="Set" href="javascript: void(0);">套装</a></li>
  318. <li><a class="quick-option artifact" data-type="Artifact" href="javascript: void(0);">神器</a></li>
  319. </ul>
  320. </div>
  321. `;
  322. const input = `<div id="idle-ui-quicksearch">${itemTypes}<input placeholder="搜索..." class="form-control"/><div class="popover" style="display: none; left: 60px; top: 28px;"><div class="popover-content"></div></div></div>`;
  323. $('.navbar-header').append(input);
  324.  
  325. $('.quick-option').click(function (e) {
  326. e.preventDefault();
  327. quickSearchType = $(this).data('type');
  328. $('#idle-quick-type').text($(this).text());
  329. const val = $('#idle-ui-quicksearch > input').val();
  330. if (val) {
  331. const popover = $('#idle-ui-quicksearch > input').next();
  332. popover.hide();
  333. fetchItem(val, function (html) {
  334. popover.children().first().html(html);
  335. popover.show();
  336. });
  337. }
  338. });
  339.  
  340. let quickTimer = null;
  341. $('#idle-ui-quicksearch > input').keyup(function () {
  342. if (quickTimer) {
  343. clearTimeout(quickTimer);
  344. quickTimer = null;
  345. }
  346. const val = $(this).val();
  347. if (!val) $(this).next().hide();
  348. quickTimer = setTimeout(() => {
  349. const popover = $(this).next();
  350. popover.hide();
  351. fetchItem(val, function (html) {
  352. popover.children().first().html(html);
  353. popover.show();
  354. });
  355. }, 500);
  356. });
  357.  
  358. if (config.fastFilter) {
  359. const fastOptions = (['无'].concat(config.fastOptions)).map(function (item) {
  360. return `<li><a href="javascript: void(0);" class="filter-text" style="color: white">${item}</a></li>`;
  361. }).join('');
  362.  
  363. const fastFilter = '<div class="fast-filter btn-group">' +
  364. '<button type="button" class="btn btn-default btn-xs dropdown-toggle" style="margin-left: 10px;" data-toggle="dropdown">快速过滤<span class="caret"/></button>'
  365. + `<ul class="dropdown-menu">${fastOptions}</ul></div>`;
  366. $(fastFilter).insertAfter('.panel-filter');
  367.  
  368. $('.filter-text').click(function () {
  369. const text = $(this).text() === '无' ? '' : $(this).text();
  370. const filter = $(this).parent().parent().parent().prev();
  371. filter.val(text);
  372. filter.trigger('input');
  373. });
  374. }
  375.  
  376. if (config.showSpellColor) {
  377. $('.skill-name').each(function () {
  378. let desc = '';
  379. let label = '';
  380. if ($(this).children().length === 2) {
  381. desc = $(this).next().text();
  382. label = $(this).children().last();
  383. } else {
  384. desc = $(this).parent().next().text();
  385. label = $(this);
  386. }
  387. if (desc.indexOf('法术技能') >= 0) {
  388. label.addClass('skill');
  389. }
  390. });
  391. }
  392.  
  393. function getSpeedLevel(speed, isAttack) {
  394. const levels = isAttack ? [0, -25, -50, -80, -120, -160, -200] : [0, -20, -45, -75, -110, -145, -180];
  395. for (let i = 0; i < levels.length; i++) {
  396. if (speed > levels[i]) {
  397. const next = levels[i];
  398. return [i, next];
  399. }
  400. }
  401. return [levels.length, '已最高'];
  402. }
  403.  
  404. function getAvgDmg(dmgStr) {
  405. const dmgArray = dmgStr.split('~');
  406. const avg = (((dmgArray[0] - 0) + (dmgArray[1] - 0)) / 2);
  407. return avg;
  408. }
  409.  
  410. function getKeySkill() {
  411. let ret = {name: '', accRate: 0, dmgRate: 0};
  412. $('span.label.label-danger').each(function () {
  413. if (!$(this).hasClass('sr-only') && $(this).text().indexOf('K') >= 0) {
  414. ret.name = $(this).prev().text();
  415. const skill = $(this).parent().next().text();
  416. ret.isAttack = skill.indexOf('攻击技能') >= 0;
  417. if (ret.isAttack) {
  418. const accMatch = skill.match(/提升(\d+)%准确率/);
  419. const dmgMatch = skill.match(/(\d+)%基础伤害/);
  420. if (accMatch) ret.accRate = (accMatch[1] - 0) / 100;
  421. if (dmgMatch) ret.dmgRate = (dmgMatch[1] - 0) / 100;
  422. }
  423. }
  424. });
  425. return ret;
  426. }
  427.  
  428. function renderCharLabel(name, value, id) {
  429. const idStr = id ? `id="${id}"` : '';
  430. return `<p><span>${name}:</span><span ${idStr} class="state">${value}</span></p>`;
  431. }
  432.  
  433. if (location.href.indexOf('Character/Detail') >= 0) {
  434. const keySkill = getKeySkill();
  435. let level = 0;
  436. $('.label.label-default').each(function () {
  437. const label = $(this).text();
  438. if (label.indexOf('Lv') >= 0 && level === 0) {
  439. level = label.replace('Lv', '') - 0;
  440. }
  441. if (config.showSpeedLevel) {
  442. if (label === '攻击') {
  443. const attackSpeed = $(this).parent().next().next().next().next().children().last();
  444. const level = getSpeedLevel(attackSpeed.text(), true);
  445. const levelElement = renderCharLabel('攻速档位', level[0]) + renderCharLabel('下档攻速', level[1]);
  446. $(levelElement).insertAfter(attackSpeed.parent());
  447. } else if (label === '法术') {
  448. const spellSpeed = $(this).parent().next().children().last();
  449. const level = getSpeedLevel(spellSpeed.text(), false);
  450. const levelElement = renderCharLabel('速度档位', level[0]) + renderCharLabel('下档速度', level[1]);
  451. $(levelElement).insertAfter(spellSpeed.parent());
  452. }
  453. }
  454. if (config.showCharDmg) {
  455. if (label === '攻击') {
  456. const baseDmg = $(this).parent().next().children().last().text();
  457. const critElement = $(this).parent().next().next().next();
  458. const crit = critElement.children().last().text().replace('%', '') / 100;
  459. const avgDmg = getAvgDmg(baseDmg);
  460. const finalDmg = (avgDmg * (1 + (crit - 0))).toFixed(2) - 0;
  461. let dmgElement = renderCharLabel('普攻均伤', finalDmg);
  462. if (keySkill.isAttack) {
  463. const keyDmg = (keySkill.dmgRate * finalDmg).toFixed(2) - 0;
  464. dmgElement += renderCharLabel(`${keySkill.name}均伤`, keyDmg);
  465. }
  466. $(dmgElement).insertAfter(critElement);
  467. }
  468. }
  469. if (config.showAccuracy) {
  470. if (label === '攻击') {
  471. const accuracy = $(this).parent().next().next().children().last().text() - 0;
  472. const accuracyElement = $(this).parent().next().next();
  473. const accRate = getAccRate(level, level, accuracy);
  474. let accElement = `<p><span>命中怪物等级:</span><span><input type="number" class="form-control hit-input" value="${level}"/></span></p>`;
  475. accElement += renderCharLabel('普攻命中率', `${accRate}%`, 'idle-ui-acc');
  476. if (keySkill.isAttack) {
  477. const keyAcc = accuracy * keySkill.accRate;
  478. const keyAccRate = getAccRate(level, level, keyAcc);
  479. accElement += renderCharLabel(`${keySkill.name}命中率`, `${keyAccRate}%`, 'idle-ui-key-acc');
  480. }
  481. $(accElement).insertAfter(accuracyElement);
  482.  
  483. $('.hit-input').change(function () {
  484. const mlvl = $(this).val();
  485. const def = (mlvl - 0 + 1) * 10;
  486. const curAccRate = getAccRate(level, mlvl, accuracy);
  487. $('#idle-ui-acc').text(`${curAccRate}%`);
  488. if (keySkill.isAttack) {
  489. const curKeyAccRate = getAccRate(level, mlvl, accuracy * keySkill.accRate);
  490. $('#idle-ui-key-acc').text(`${curKeyAccRate}%`);
  491. }
  492. });
  493. }
  494. }
  495. if (config.itemStats) {
  496. if (label == '综合') {
  497. const uniqueNum = $(this).parent().next().next().next().next().children().last().text();
  498. const setNum = $(this).parent().next().next().next().next().next().children().last().text();
  499. const statsData = {uniqueNum: uniqueNum, setNum: setNum};
  500. saveStats({uniqueNum: uniqueNum, setNum: setNum});
  501. }
  502. }
  503. });
  504. }
  505.  
  506. function getAccRate(clvl, mlvl, acc) {
  507. clvl = clvl - 0;
  508. mlvl = mlvl - 0;
  509. acc = acc - 0;
  510. const def = (mlvl - 0 + 1) * 10;
  511. return (2 * (clvl / (clvl + mlvl)) * (acc / (acc + def)) * 100).toFixed(2) - 0;
  512. }
  513.  
  514. function saveStats(statsData) {
  515. const idMatch = location.href.match(/Character\/Detail\?Id=(\d+)/i);
  516. if (!idMatch) return;
  517. const id = idMatch[1];
  518. let stats = localStorage.getItem('idle-ui-stats');
  519. stats = stats ? JSON.parse(stats) : {uniqueNum: 0, setNum: 0};
  520. const lastStatsData = stats[id];
  521. const time = +new Date();
  522. if (lastStatsData && lastStatsData.time) {
  523. const duration = moment.duration(moment(time).diff(moment(lastStatsData.time)));
  524. const timeSpan = duration.asMinutes() > 60 ? (duration.asHours().toFixed(1) - 0) + '小时前' : Math.round(duration.asMinutes()) + '分钟前';
  525. const uniqueChange = statsData.uniqueNum - lastStatsData.uniqueNum;
  526. const setChange = statsData.setNum - lastStatsData.setNum;
  527. displayStats(id, timeSpan, uniqueChange, setChange);
  528. }
  529. statsData.time = time;
  530. stats[id] = statsData;
  531. localStorage.setItem('idle-ui-stats', JSON.stringify(stats));
  532. }
  533.  
  534. function displayStats(id, timeSpan, uniqueChange, setChange) {
  535. const message = `<div class="panel panel-inverse panel-top"><div class="panel-body">上次访问是${timeSpan},这段时间内你获得了 <span class="unique">${uniqueChange}</span> 件暗金,<span class="set">${setChange}</span> 件套装。<a href="javascript: void(0);" id="open-ui-modal" class="btn btn-xs btn-default ml-10">插件设置</a></div></div>`;
  536.  
  537. $('.navbar.navbar-inverse.navbar-fixed-top').next().next().prepend(message);
  538. $('#open-ui-modal').click(function () {
  539. $('#modalUI').modal('show');
  540. });
  541. }
  542.  
  543. // 离线挂机统计记录
  544. if (config.dropNotification && location.href.indexOf('Map/Dungeon') === -1) {
  545. $(document).ready(function () {
  546. // 找到数据添加下拉框
  547. // $("div.panel-heading")
  548.  
  549. // 添加获得焦点事件,在获得焦点时更新下拉列表数据
  550.  
  551. // 处理下拉选中,显示数据
  552.  
  553. // 初始化记载经验数据列表
  554. const userCont = new Map();
  555.  
  556. const dropTypes = {unique: '暗金', set: '套装'};
  557. const oldLog = $.connection.userManagerHub.client.battleLog;
  558. $.connection.userManagerHub.client.battleLog = function (data) {
  559. const ret = JSON.parse(data);
  560. const keys = Object.keys(ret.EquipmentNameList);
  561. if (keys.length > 0) {
  562. keys.forEach(function (type) {
  563. const items = ret.EquipmentNameList[type].join(',');
  564. if (dropTypes[type]) {
  565. const notice = new Notification(
  566. `${ret.CharName} 获得${dropTypes[type]}`,
  567. {
  568. body: items,
  569. icon: 'https://cdn3.iconfinder.com/data/icons/game-play/512/gaming-game-play-multimedia-console-09-512.png'
  570. }
  571. );
  572. }
  573. });
  574. }
  575. if (ret.RuneNameList.length) {
  576. let s = ret.RuneNameList.join(',');
  577. if (parseInt(s.replace(/[^0-9]/ig, "")) >= parseInt(config.minLevel)) {
  578. new Notification(
  579. `${ret.CharName} 获得符文`,
  580. {
  581. body: s,
  582. icon: 'https://cdn0.iconfinder.com/data/icons/geek-4/24/Mortal_Instruments_movie_symbol_logo_rune-512.png'
  583. }
  584. );
  585. }
  586. }
  587.  
  588. if (!userCont.get(ret.CharName)) {
  589. const user = {};
  590. user.name = ret.CharName;
  591. user.time = 0;
  592. user.count = 0;
  593. user.exp = 0;
  594. user.gold = 0;
  595. user.equipment = 0;
  596. userCont.set(ret.CharName, user);
  597. }
  598. let user = userCont.get(ret.CharName);
  599. user.time += Number(ret.CostTime);
  600. user.count += 1;
  601. let exp = Number(ret.Exp);
  602. user.exp += isNaN(exp) ? 0 : exp;
  603. let gold = Number(ret.Gold);
  604. user.gold += isNaN(gold) ? 0 : gold;
  605. userCont.set(ret.CharName, user);
  606. user.equipment += keys.length;
  607. console.log(user.name + "\t" + (user.time / user.count).toFixed(2) + "\t" + ((user.exp / user.time) * 60).toFixed(2) + "\t" + ((user.equipment / user.time * 3600)).toFixed(0));
  608.  
  609. if (oldLog) oldLog(data);
  610. };
  611. $.connection.hub.stop();
  612. $.connection.hub.start();
  613. });
  614. }
  615.  
  616. if (config.showBattle && inBattlePage() && !$('.error').length) {
  617. let waitTime = $('#time');
  618. if (waitTime.length) {
  619. waitTime = waitTime.val();
  620. } else {
  621. $(document).ready(function () {
  622. $(".turn").battle({
  623. interval: 0,
  624. guaji: 0
  625. });
  626. });
  627. }
  628. }
  629.  
  630. function renderConigHtml() {
  631. return Object.keys(config)
  632. .filter(item => userConfig.indexOf(item) >= 0)
  633. .map(key => {
  634. const cfg = config[key];
  635. return `<div class="col-sm-4"><div class="checkbox" style="margin: 2px 0;"><label><input class=" idle-ui-config" type="checkbox" data-key="${key}"> ${configLabel[key]}</label></div></div>`
  636. })
  637. .join('');
  638. }
  639.  
  640. function addConfig() {
  641. $("[name='gold'][id='gold'][type='number']").attr('value', 50000);
  642. const configHtml = renderConigHtml();
  643. const html = `
  644. <div class="modal fade" id="modalUI" style="display: none;">
  645. <div class="modal-dialog modal-large" role="">
  646. <div class="modal-content model-inverse">
  647. <div class="modal-header">
  648. <span class="modal-title">插件设置</span>
  649. </div>
  650. <div class="modal-body">
  651. <div class="idle-ui-title">Idle Infinity UI 增强插件 by 班登</div>
  652. <div class="panel-header state">配置项开关(配置具体含义请参考<a href="https://greasyfork.org/zh-CN/scripts/370841-fight-beibei-everyday" target="_blank">脚本介绍</a>,点击即可启用/禁用,变更后请刷新)</div>
  653. <div class="form row">${configHtml}</div>
  654. <p>按 Alt+T 可快速切换主题皮肤</p>
  655. <div class="panel-header state">自动秘境模式</div>
  656. <div>
  657. <label class="radio-inline">
  658. <input type="radio" class="idle-ui-hack-type" name="maphack-type" id="hack-boss" value="boss"> 只打BOSS
  659. </label>
  660. <label class="radio-inline">
  661. <input type="radio" class="idle-ui-hack-type" name="maphack-type" id="hack-all" value="all"> 小怪全清
  662. </label>
  663. <label class="radio-inline">
  664. <input type="radio" class="idle-ui-hack-type" name="maphack-type" id="hack-mystery" value="mystery"> 秘境扫荡
  665. </label>
  666. </div>
  667. <div class="panel-header state">符文提示过滤</div>
  668. <div>
  669. <input id="idle-ui-rune-filter" type="number" name="points" min="1" max="33" step="1" style="padding: 0 0 0 10px; width: 20%;" placeholder=${configLabel.minLevel} value=${config.minLevel}>
  670. </div>
  671. <div class="panel-header state"></div>
  672. <div class="panel-header state">快速过滤下拉选项(每行一个)</div>
  673. <textarea id="idle-ui-filters" class="form-control panel-textarea" rows="5"></textarea>
  674. <div class="textarea-actions">
  675. <button type="button" class="btn btn-xs btn-success" id="idle-ui-save-filters">保存选项</button>
  676. <button type="button" class="btn btn-xs btn-default" id="idle-ui-reset-filters">恢复默认</button>
  677. </div>
  678. </div>
  679. <div class="modal-footer">
  680. <button type="button" class="btn btn-default btn-xs" data-dismiss="modal">关闭</button>
  681. </div>
  682. </div>
  683. </div>
  684. </div>
  685. `;
  686. $(document.body).append(html);
  687. loadLocalConfig();
  688. }
  689.  
  690. function loadLocalConfig() {
  691. $('.idle-ui-config').each(function () {
  692. const key = $(this).data('key');
  693. $(this).prop('checked', config[key]);
  694. });
  695. $('#idle-ui-filters').val(config.fastOptions.join('\n'));
  696. $(`#hack-${config.mapHackType}`).prop('checked', true);
  697.  
  698. $('#idle-ui-reset-filters').click(function () {
  699. config.fastOptions = defaultFilterOptions;
  700. saveLocalConfig();
  701. loadLocalConfig();
  702. });
  703.  
  704. $('#idle-ui-save-filters').click(function () {
  705. config.fastOptions = $('#idle-ui-filters').val().split('\n');
  706. config.minLevel = $('#idle-ui-rune-filter').val();
  707. saveLocalConfig();
  708. });
  709.  
  710. $('.idle-ui-config').change(function () {
  711. const key = $(this).data('key');
  712. config[key] = $(this).prop('checked');
  713. if (config.d3theme) {
  714. $('html').addClass('d3');
  715. } else {
  716. $('html').removeClass('d3');
  717. }
  718. saveLocalConfig();
  719. });
  720.  
  721. $('.idle-ui-hack-type').change(function () {
  722. if ($(this).prop('checked')) config.mapHackType = $(this).val();
  723. saveLocalConfig();
  724. });
  725.  
  726. // 监听alt+t按键,切换界面
  727. $(document).bind('keyup', function (event) {
  728. if (event.which === 84 && event.altKey) {
  729. $('html').toggleClass('d3');
  730. switchSkin(document.getElementsByClassName('d3').length > 0)
  731. }
  732. });
  733. }
  734.  
  735. function saveLocalConfig() {
  736. localStorage.setItem('idle-ui-config', JSON.stringify(config));
  737. }
  738.  
  739. // 监听过滤条件输入框的改变
  740. $(".panel-filter").on("input propertychange", function () {
  741. $(".equip-container .selected").removeClass("selected")
  742.  
  743. // 输入的值
  744. var value = $(this).val();
  745. // 保存到缓存,方便下次使用
  746. window.localStorage.setItem($(this).attr("id"), value);
  747. if (value.length > 0) {
  748. var values = value.split(",");
  749. var equips = $(this).parent().prev().find(".equip-content");
  750.  
  751. // 正则判断是否是数字
  752. const min = /^<[0-9]+.?[0-9]*$/;
  753. const max = /^>[0-9]+.?[0-9]*$/;
  754.  
  755. // 提取装备等级的正则表达式
  756. const level = /\([0-9]*\)/;
  757.  
  758. // 去的当页数据
  759. equips.each(function (i, e) {
  760. var match = 0;
  761. $.each(values, function (j, p) {
  762. let text = $(e).text();
  763. if (min.test(p)) {
  764. // 纯数字,作为掉落等级来判断
  765. let exec = String(level.exec(text));
  766. exec = exec.substring(1, exec.length - 1);
  767. p = p.substring(1, p.length);
  768. if (parseInt(exec) <= parseInt(p)) match++;
  769. } else if (max.test(p)) {
  770. let exec = String(level.exec(text));
  771. exec = exec.substring(1, exec.length - 1);
  772. p = p.substring(1, p.length);
  773. if (parseInt(exec) >= parseInt(p)) match++;
  774. } else if (text.indexOf(p) >= 0) {
  775. // 其他属性
  776. match++;
  777. }
  778. });
  779. if (match == values.length) {
  780. $(e).prev().addClass("selected");
  781. }
  782. });
  783. }
  784. });
  785.  
  786. $(document).ready(function () {
  787. $(".panel-filter").each(function (i, input) {
  788. var value = window.localStorage.getItem($(this).attr("id"));
  789. if (value != null && value.length > 0) {
  790. $(this).val(value);
  791. $(this).trigger("propertychange");
  792. }
  793. });
  794. });
  795.  
  796.  
  797. // 当前是秘境界面
  798. if (config.mapHack && location.href.indexOf('Map/Dungeon') >= 0) {
  799.  
  800. // 爱液的原始点击
  801. $.connection.userManagerHub.client.startDungeon = function (d) {
  802. localStorage.setItem("t", d);
  803. $(".dungeon-container").on("mousedown", ".public", null, function (a, g) {
  804. var f = $(this);
  805. var c = f.parent();
  806. g = f.attr("id");
  807. var k = $("#cid").val();
  808. if (f.hasClass("monster")) window.location.replace("/Battle/InDungeon?id=" + k + "&bid=" + g); else {
  809. $(".dungeon-layer").show();
  810. var e = [];
  811. if (0 < a.pageX && 0 < a.pageY && a.hasOwnProperty("originalEvent") && (a.originalEvent.isTrusted || 1 == a.originalEvent.detail)) {
  812. e = $(c).offset();
  813. var h = $(c).width();
  814. c = $(c).height();
  815. var l = Math.floor(Math.random() * h);
  816. e = [a.pageX, l, a.pageY, e.left, h - l, e.top, h, Math.floor(Math.random() * c), c]
  817. }
  818. a = {
  819. id: k,
  820. bid: g,
  821. m: e,
  822. t: d,
  823. __RequestVerificationToken: $("[name='__RequestVerificationToken']").val()
  824. };
  825. $.ajax({
  826. url: "MoveTo",
  827. type: "post",
  828. data: a,
  829. dataType: "json",
  830. success: function (a) {
  831. $.each(a, function (a, b) {
  832. void 0 == b.id && (b.id = 0);
  833. a = "";
  834. 0 == b.d[0] && (a += " top");
  835. 0 == b.d[1] && (a += " left");
  836. if (1 == b.m)
  837. $("#" + b.id).addClass(a);
  838. else {
  839. a += " public";
  840. var c = "";
  841. 0 < b.mlvl && (c += "Lv" + b.mlvl + " " + b.mname, a = a + " monster " + b.mtype);
  842. $("#" + b.id).removeClass("mask").addClass(a);
  843. "" != c && $("#" + b.id).attr("title", c)
  844. }
  845. });
  846. 0 < a.length && ($("#explore").text(parseInt($("#explore").text()) + a.length),
  847. $("#not-explore").text(parseInt($("#not-explore").text()) - a.length));
  848. $(".current").removeClass("current");
  849. f.addClass("current");
  850. $(".dungeon-layer").hide()
  851. }, error: function (a, c, b) {
  852. alert(a.responseText);
  853. $(".dungeon-layer").hide()
  854. }
  855. })
  856. }
  857. })
  858. };
  859.  
  860. let hacking = false;
  861. const idMatch = location.href.match(/id=(\d+)/i);
  862. if (!idMatch) return;
  863. const id = idMatch[1];
  864. const btns = '<button class="btn btn-xs btn-success mr-10" id="start-hack">开始自动秘境</button><label class="mr-10"><input id="auto-reset" type="checkbox"/> 自动重置</label>';
  865. $('.dungeon-container').prev().children().last().prepend(btns);
  866.  
  867. if (config.infiniteMap) $('#auto-reset').prop('checked', true);
  868. $('#auto-reset').change(function () {
  869. config.infiniteMap = $(this).prop('checked');
  870. saveLocalConfig();
  871. });
  872.  
  873. let failedBlocks = localStorage.getItem('idle-ui-fail-blocks');
  874. failedBlocks = failedBlocks ? JSON.parse(failedBlocks) : [];
  875.  
  876. let map = localStorage.getItem('idle-ui-maphack');
  877.  
  878. // 是否出现验证码提示
  879. if ($("[role='dialog'][data-code='True']").length) {
  880. // 提示验证码 停止自动秘境
  881. endMove("验证码出现");
  882. return;
  883. }
  884.  
  885. if (map) {
  886. map = JSON.parse(map);
  887.  
  888. if (map[id] && map[id] === 'start') {
  889. const bossLeft = $('.boss-left').text() - 0;
  890. const monster = $('.monster-left').text() - 0;
  891. if (bossLeft === 0 && config.mapHackType === 'boss') {
  892. if (config.infiniteMap) {
  893. setTimeout(() => {
  894. tryReset();
  895. }, 500);
  896. } else {
  897. map = {};
  898. map[id] = 'end';
  899. }
  900. } else if (monster === 0 && config.mapHackType === 'mystery') {
  901. // 秘境扫荡完毕,跳转到装备界面开始继续打石头
  902. // 获得用户的ID
  903. // 秘境的石头等级 0 表示普通 1表示魔法 2表示稀有,以此类推 按照下拉列表的排序
  904. // https://www.idleinfinity.cn/Equipment/Query?id=5671&pt2=2&et2=2147483648&pi=0&pt=1&et=2147483648
  905. // https://www.idleinfinity.cn/Equipment/Query?id=5671&et2=2147483648&pt2=1&pi=0&pt=1&et=2147483648
  906. // https://www.idleinfinity.cn/Equipment/Query?id=5671&pt=2&et=2147483648&pi2=0&pt2=2&et2=2147483648
  907. localStorage.setItem('failure', "0");
  908. const level = config.level;
  909. const userId = $("#cid").val();
  910. location.href = `/Equipment/Query?id=${userId}&pt=5&et=2147483648&pi2=0&pt2=&et2=2147483648`;
  911. // 定位到装备界面
  912. } else {
  913. $('.dungeon-container').prev().children().last().prepend('<button class="btn btn-xs btn-default" style="margin-right: 5px;" id="end-hack">停止自动秘境</button>');
  914. setTimeout(() => {
  915. startHack();
  916. }, 500);
  917. }
  918. }
  919. } else {
  920. map = {};
  921. map[id] = 'end';
  922. }
  923.  
  924. function tryReset() {
  925. const stoneLeft = $('.panel-heading .state').text() - 0;
  926. if (stoneLeft > 0) {
  927. localStorage.setItem('idle-ui-fail-blocks', '[]');
  928. localStorage.setItem('failure', "0");
  929. $("form").attr("action", "DungeonRefresh");
  930. $("form").trigger("submit");
  931. } else {
  932. endMove('秘境之石已用完');
  933. }
  934. }
  935.  
  936. $('#start-hack').click(function (params) {
  937. startHack(true);
  938. });
  939.  
  940. $('#end-hack').click(function (params) {
  941. alert('自动秘境已停止');
  942. endMove();
  943. });
  944.  
  945. function startHack(fromClick) {
  946. if (hacking) return;
  947. hacking = true;
  948. if (!map[id] && typeof map == 'string') {
  949. map = JSON.parse(map);
  950. }
  951. map[id] = 'start';
  952. localStorage.setItem('idle-ui-maphack', JSON.stringify(map));
  953. if (fromClick) {
  954. localStorage.setItem('idle-ui-fail-blocks', '[]');
  955. localStorage.setItem('failure', "0");
  956. }
  957. mapMove();
  958. }
  959.  
  960. function mapMove() {
  961. // if (blockData.num >= 9) {
  962. // endMove('封号打击次数过多,禁止自动秘境');
  963. // return;
  964. // }
  965. if (map[id] !== 'start') return;
  966. // 有boss先打boss
  967. const bossBlock = $('.boss').eq(0);
  968. if (bossBlock.length && !bossBlock.hasClass('mask')) {
  969. clickBlock(bossBlock);
  970. return;
  971. }
  972.  
  973. const bossId = bossBlock.attr("id");
  974. const asc = Number(bossId) <= 200;
  975. // Boss在地图上X轴坐标
  976. const boosX = bossId % 20;
  977. // Boss在地图上Y轴坐标
  978. const boosY = bossId / 20;
  979. const blocks = []; // 无敌人的可行区块
  980. const enemyBlocks = []; // 有敌人的可行区块
  981. for (let i = asc ? 0 : 399; asc ? i <= 399 : i >= 0; asc ? i++ : i--) {
  982. const block = $(`#${i}`);
  983. if (canExplore(i)) {
  984. if (block.hasClass('monster')) {
  985. enemyBlocks.push(i);
  986. } else {
  987. blocks.push(i);
  988. }
  989. }
  990. }
  991. let nextBlockIndex = null;
  992. if (blocks.length) {
  993. nextBlockIndex = blocks[0];
  994. } else if (enemyBlocks.length) {
  995. // 和Boss的距离的值,等于X+Y.
  996. let distance = 39;
  997. // 计算距离Boss最近的怪
  998. for (let i = 0; i < enemyBlocks.length; i++) {
  999. const itemX = enemyBlocks[i] % 20;
  1000. const itemY = enemyBlocks[i] / 20;
  1001. const itemDistance = Math.abs(itemX - boosX) + Math.abs(itemY - boosY);
  1002. // 判断是否有打不过的怪
  1003. if (((config.mapHackType === 'boss') ? (itemDistance < distance) : true) && failedBlocks.indexOf(enemyBlocks[i]) === -1) {
  1004. distance = itemDistance;
  1005. nextBlockIndex = enemyBlocks[i];
  1006. }
  1007. }
  1008. if (nextBlockIndex === null) {
  1009. nextBlockIndex = enemyBlocks[0];
  1010. localStorage.setItem('idle-ui-fail-blocks', '[]');
  1011. let number = parseInt(localStorage.getItem("failure"));
  1012. let failure = (isNaN(number) ? 0 : number) + 1;
  1013. localStorage.setItem('failure', failure);
  1014. if ((failure % 3) === 0) {
  1015. if (failure > 1) new Notification('第' + failure + '轮战斗失败');
  1016. }
  1017. if (failure > config.failure) {
  1018. if (config.mapHackType === 'mystery') {
  1019. const level = config.level;
  1020. const userId = $("#cid").val();
  1021. location.href = `/Equipment/Query?id=${userId}&pt=5&et=2147483648&pi2=0&pt2=${level}&et2=2147483648`;
  1022. return;
  1023. } else if (config.infiniteMap) {
  1024. tryReset();
  1025. return
  1026. }
  1027. }
  1028. }
  1029. } else {
  1030. endMove('', false, config.infiniteMap);
  1031. }
  1032. if (nextBlockIndex !== null) {
  1033. clickBlock($(`#${nextBlockIndex}`));
  1034. }
  1035. }
  1036.  
  1037. function clickBlock(block) {
  1038. const width = block.width();
  1039. const height = block.height();
  1040. const rect = document.getElementById(block.attr('id')).getBoundingClientRect();
  1041. const x = Math.round(rect.left + width / 3 + (width / 4 * Math.random(id))) + $(window).scrollLeft();
  1042. const y = Math.round(rect.top + height / 3 + (height / 4 * Math.random(id))) + $(window).scrollTop();
  1043. ajaxMove(block, {pageX: x, pageY: y, originalEvent: {isTrusted: true}});
  1044. }
  1045.  
  1046. function ajaxMove(block, a) {
  1047. const f = block;
  1048. var c = f.parent();
  1049. const g = f.attr("id");
  1050. const k = $("#cid").val();
  1051. const td = localStorage.getItem("t");
  1052. if (f.hasClass("monster")) {
  1053. location.href = "/Battle/InDungeon?id=" + k + "&bid=" + g;
  1054. } else {
  1055. $(".dungeon-layer").show();
  1056. var e = [];
  1057. if (0 < a.pageX && 0 < a.pageY && a.hasOwnProperty("originalEvent") && (a.originalEvent.isTrusted || 1 == a.originalEvent.detail)) {
  1058. e = $(c).offset();
  1059. const h = $(c).width();
  1060. c = $(c).height();
  1061. const l = Math.floor(Math.random() * h);
  1062. e = [a.pageX, l, a.pageY, e.left, h - l, e.top, h, Math.floor(Math.random() * c), c]
  1063. }
  1064. a = {
  1065. id: k,
  1066. bid: g,
  1067. m: e,
  1068. t: td,
  1069. __RequestVerificationToken: $("[name='__RequestVerificationToken']").val()
  1070. };
  1071. $.ajax({
  1072. url: "MoveTo",
  1073. type: "post",
  1074. data: a,
  1075. dataType: "json",
  1076. success: function (a) {
  1077. $.each(a, function (a, b) {
  1078. void 0 == b.id && (b.id = 0);
  1079. a = "";
  1080. 0 == b.d[0] && (a += " top");
  1081. 0 == b.d[1] && (a += " left");
  1082. if (1 == b.m)
  1083. $("#" + b.id).addClass(a);
  1084. else {
  1085. a += " public";
  1086. var c = "";
  1087. 0 < b.mlvl && (c += "Lv" + b.mlvl + " " + b.mname, a = a + " monster " + b.mtype);
  1088. $("#" + b.id).removeClass("mask").addClass(a);
  1089. "" != c && $("#" + b.id).attr("title", c)
  1090. }
  1091. });
  1092. 0 < a.length && ($("#explore").text(parseInt($("#explore").text()) + a.length),
  1093. $("#not-explore").text(parseInt($("#not-explore").text()) - a.length));
  1094. $(".current").removeClass("current");
  1095. f.addClass("current");
  1096. $(".dungeon-layer").hide();
  1097. setTimeout(() => {
  1098. mapMove();
  1099. }, Math.round(config.userNumber * 300));
  1100. },
  1101. error: function (XMLHttpRequest) {
  1102. const responseText = XMLHttpRequest.responseText;
  1103. if (responseText.indexOf('封号') >= 0) {
  1104. addBlockNum();
  1105. }
  1106. endMove(null, true, true);
  1107. $(".dungeon-layer").hide();
  1108. }
  1109. });
  1110. }
  1111. }
  1112.  
  1113. function endMove(notice, retry, reset) {
  1114. if (!reset) {
  1115. map[id] = 'end';
  1116. localStorage.setItem('idle-ui-maphack', JSON.stringify(map));
  1117. }
  1118.  
  1119. if (notice) new Notification(notice);
  1120.  
  1121. if (retry) {
  1122. // 请求异常情况直接刷新界面,暂时注释原来逻辑
  1123. $('#modalAlert').modal('hide');
  1124. setTimeout(function () {
  1125. const userId = $("#cid").val();
  1126. location.href = `../Map/DungeonForEquip?id=${userId}`
  1127. }, Math.round(300));
  1128. } else if (reset) {
  1129. tryReset();
  1130. }
  1131. }
  1132.  
  1133. // 判断是否可以点击
  1134. function canExplore(i) {
  1135. const size = 20;
  1136. const block = $(`#${i}`);
  1137. if (block.hasClass('mask')) return false;
  1138. if ((config.mapHackType === 'all' || config.mapHackType === 'mystery') && block.hasClass('monster')) return true;
  1139. const left = i % size === 0 ? null : $(`#${i - 1}`);
  1140. const right = i % size === (size - 1) ? null : $(`#${i + 1}`);
  1141. const up = i < size ? null : $(`#${i - size}`);
  1142. const down = i >= ((size * size) - size) ? null : $(`#${i + size}`);
  1143. const canMoveLeft = left && left.hasClass('mask') && !block.hasClass('left');
  1144. const canMoveRight = right && right.hasClass('mask') && !right.hasClass('left');
  1145. const canMoveUp = up && up.hasClass('mask') && !block.hasClass('top');
  1146. const canMoveDown = down && down.hasClass('mask') && !down.hasClass('top');
  1147. return canMoveLeft || canMoveRight || canMoveUp || canMoveDown;
  1148. }
  1149. }
  1150.  
  1151. if (location.href.indexOf('Map/Dungeon') === -1) {
  1152. $.ajaxSetup({
  1153. complete: function (XMLHttpRequest) {
  1154. if (!XMLHttpRequest.responseText) return;
  1155. if (XMLHttpRequest.responseText.indexOf('封号') >= 0) {
  1156. addBlockNum();
  1157. location.reload();
  1158. }
  1159. }
  1160. });
  1161. }
  1162.  
  1163. // 战斗界面
  1164. if (config.mapHack && location.href.indexOf('Battle/InDungeon') >= 0) {
  1165.  
  1166. const id = purl().param().id;
  1167. const bid = purl().param().bid - 0;
  1168. if (!id) return;
  1169. let map = localStorage.getItem('idle-ui-maphack');
  1170. if (map) {
  1171. map = JSON.parse(map);
  1172. if (map[id] && map[id] === 'start') {
  1173. const exception = $('.error').length;
  1174. if (exception) {
  1175. setTimeout(() => {
  1176. location.href = `/Map/Dungeon?id=${id}`;
  1177. }, Math.round(Math.random() * 3000));
  1178. return;
  1179. }
  1180.  
  1181. const stopBtn = renderButton('end-hack', '停止自动秘境', 'default');
  1182. $('.btn.btn-xs').eq(1).before(stopBtn);
  1183. $('#end-hack').click(function () {
  1184. map[id] = 'end';
  1185. localStorage.setItem('idle-ui-maphack', JSON.stringify(map));
  1186. alert('自动秘境已停止');
  1187. });
  1188.  
  1189. let waitTime = $('head').text().match(/waitTime:(\d+)/);
  1190. if (waitTime) {
  1191. waitTime = waitTime[1];
  1192. }
  1193. if (waitTime) {
  1194. setTimeout(() => {
  1195. endFight(id);
  1196. }, (waitTime + 1) * 1000);
  1197. } else {
  1198. endFight(id);
  1199. }
  1200. }
  1201. }
  1202.  
  1203. function endFight(dungeonId) {
  1204. const win = $('.turn').first().text().indexOf('战斗胜利') > 0;
  1205. const turns = $('.turn').length - 1;
  1206. let enemys = {};
  1207. $('.battle-char').each(function () {
  1208. const id = $(this).prop('id').split('_')[1];
  1209. if (id < 0) {
  1210. const type = $(this).children().first().children().last().prop('class');
  1211. if (enemys[type]) {
  1212. enemys[type] += 1;
  1213. } else {
  1214. enemys[type] = 1;
  1215. }
  1216. }
  1217. });
  1218. let drops = [];
  1219. $('.turn').first().find('.equip-name').each(function () {
  1220. const type = $(this).clone().prop('class').replace('equip-name', '').trim();
  1221. const name = $(this).text();
  1222. drops.push({type: type, name: name});
  1223. });
  1224. const isBoss = $('.boss').length > 0;
  1225. const battleLog = {time: +new Date(), win, boss: isBoss, turns, enemys, drops};
  1226. addBattleLog(battleLog);
  1227.  
  1228. const bossWin = isBoss && win;
  1229. if (!win) {
  1230. let failedBlocks = localStorage.getItem('idle-ui-fail-blocks');
  1231. failedBlocks = failedBlocks ? JSON.parse(failedBlocks) : [];
  1232. if (failedBlocks.indexOf(bid) === -1) failedBlocks.push(bid);
  1233. localStorage.setItem('idle-ui-fail-blocks', JSON.stringify(failedBlocks));
  1234. } else {
  1235. localStorage.setItem('failure', '0');
  1236. localStorage.setItem('idle-ui-fail-blocks', '[]');
  1237. }
  1238. let timeout = 5;
  1239. if (turns < 50) {
  1240. timeout = 3
  1241. } else if (turns < 100) {
  1242. timeout = 7;
  1243. } else if (turns < 200) {
  1244. timeout = 10;
  1245. }
  1246. setTimeout(() => {
  1247. location.href = `/Map/Dungeon?id=${dungeonId}`;
  1248. }, timeout * 1000);
  1249. }
  1250.  
  1251. function addBattleLog(battleLog) {
  1252. let log = localStorage.getItem('idle-ui-maplog');
  1253. log = log ? JSON.parse(log) : {};
  1254. if (!log[id]) log[id] = [];
  1255. log[id].unshift(battleLog);
  1256. log[id] = log[id].slice(0, 500);
  1257. localStorage.setItem('idle-ui-maplog', JSON.stringify(log));
  1258. }
  1259. }
  1260.  
  1261. if (config.mapHack && location.href.indexOf('Map/Detail') >= 0) {
  1262. const btn = renderButton('idle-ui-maplog', '自动秘境日志');
  1263. $('.btn.btn-xs').eq(1).before(btn);
  1264. let page = 1;
  1265. let log = {};
  1266. let dataSource = [];
  1267. const id = purl().param().id;
  1268. const pageSize = 10;
  1269. let maxPage = 0;
  1270. const modal = `
  1271. <div class="modal fade" id="modalMapLog" tabindex="-1" role="dialog">
  1272. <div class="modal-dialog modal-lg" role="document">
  1273. <div class="modal-content model-inverse">
  1274. <div class="modal-header">
  1275. <span class="modal-title">自动秘境日志</span>
  1276. </div>
  1277. <div class="modal-body">
  1278. <div class="row">
  1279. <div class="col-md-6 col-xs-12">
  1280. <div class="panel-header state">小怪战斗统计</div>
  1281. <p>
  1282. <span>战斗次数:</span><span class="state mr-10" id="idle-ui-creepnum"></span>
  1283. <span>平均回合:</span><span class="state mr-10" id="idle-ui-avgcreepturns"></span>
  1284. <span>胜率:</span><span class="state" id="idle-ui-creepwinrate"></span>
  1285. </p>
  1286. </div>
  1287. <div class="col-md-6 col-xs-12">
  1288. <div class="panel-header state">Boss战斗统计</div>
  1289. <p>
  1290. <span>战斗次数:</span><span class="state mr-10" id="idle-ui-bossnum"></span>
  1291. <span>平均回合:</span><span class="state mr-10" id="idle-ui-avgbossturns"></span>
  1292. <span>胜率:</span><span class="state" id="idle-ui-bosswinrate"></span>
  1293. </p>
  1294. </div>
  1295. </div>
  1296. <div class="panel-header state">
  1297. <span class="mr-10">战斗日志</span>
  1298. <label class="normal" style="font-weight: normal; cursor: pointer;"><input type="checkbox" id="idle-ui-only-boss"/> 只看Boss</label>
  1299. </div>
  1300. <table class="table table-condensed" style="margin-bottom: 10px;">
  1301. <thead><tr><td width="120">时间</td><td width="50">结果</td><td width="60">回合数</td><td width="200">敌人</td><td>掉落</td></tr></thead>
  1302. <tbody id="idle-ui-log-table" class="table-body"></tbody>
  1303. </table>
  1304. <div class="row">
  1305. <div class="col-md-6 col-xs-12" style="text-align: left;">
  1306. <span>共 <span id="idle-ui-log-length">0</span> 条记录</span>
  1307. </div>
  1308. <div class="col-md-6 col-xs-12" style="text-align: right;">
  1309. <span class="mr-10">第 <span id="idle-ui-page">0</span> 页,共 <span id="idle-ui-max-page">0</span> 页</span>
  1310. </div>
  1311. </div>
  1312. </div>
  1313. <div class="modal-footer">
  1314. <div class="row">
  1315. <div class="col-md-6 col-xs-12" style="text-align: left;">
  1316. <button type="button" id="clear-log" class="btn btn-danger btn-xs" style="float: left;">清空日志</button>
  1317. <button type="button" id="idle-ui-reload" class="btn btn-success btn-xs">刷新数据</button>
  1318. </div>
  1319. <div class="col-md-6 col-xs-12" style="text-align: right;">
  1320. <button type="button" id="page-prev" class="btn btn-default btn-xs">上一页</button>
  1321. <button type="button" id="page-next" class="btn btn-default btn-xs">下一页</button>
  1322. <button type="button" class="btn btn-default btn-xs" data-dismiss="modal">关闭</button>
  1323. </div>
  1324. </div>
  1325. </div>
  1326. </div>
  1327. </div>
  1328. </div>
  1329. `;
  1330. $(document.body).append(modal);
  1331.  
  1332. function getBattleLogStats(battleLog) {
  1333. let creepNum = 0;
  1334. let bossNum = 0;
  1335. let creepWin = 0;
  1336. let bossWin = 0;
  1337. let creepTurns = 0;
  1338. let bossTurns = 0;
  1339. battleLog.forEach(item => {
  1340. if (item.boss) {
  1341. bossNum += 1;
  1342. if (item.win) bossWin += 1;
  1343. bossTurns += item.turns;
  1344. } else {
  1345. creepNum += 1;
  1346. if (item.win) creepWin += 1;
  1347. creepTurns += item.turns;
  1348. }
  1349. });
  1350. const avgCreepTurns = creepNum > 0 ? Math.round(creepTurns / creepNum) : 0;
  1351. const avgBossTurns = bossNum > 0 ? Math.round(bossTurns / bossNum) : 0;
  1352. const creepWinRate = creepNum > 0 ? Math.round(creepWin / creepNum * 100) : 0;
  1353. const bossWinRate = bossNum > 0 ? Math.round(bossWin / bossNum * 100) : 0;
  1354. return {creepNum, bossNum, avgCreepTurns, avgBossTurns, creepWinRate, bossWinRate}
  1355. }
  1356.  
  1357. const enemyTypes = {'normal': '普通', 'rare': '稀有', 'super': '精英', 'boss': 'Boss'};
  1358.  
  1359. function renderRows() {
  1360. const start = (page - 1) * pageSize;
  1361. let data = [];
  1362. if ($('#idle-ui-only-boss').prop('checked')) {
  1363. data = dataSource.filter(item => item.boss).slice(start, start + pageSize);
  1364. } else {
  1365. data = dataSource.slice(start, start + pageSize);
  1366. }
  1367. const rows = data.map(item => {
  1368. const date = moment(item.time).format('MM-DD HH:mm:ss');
  1369. const result = item.win ? '<span class="poison">胜利</span>' : '<span class="fire">失败</span>';
  1370. const enemys = Object.keys(item.enemys).map(type => {
  1371. const count = item.enemys[type];
  1372. return `<span class="${type}">${enemyTypes[type]}</span><span class="normal mr-10"> x ${count}</span>`;
  1373. }).join('');
  1374. const drops = item.drops.map(item => {
  1375. return `<span class="${item.type}">${item.name}</span>`;
  1376. }).join('');
  1377. return `<tr><td>${date}</td><td>${result}</td><td>${item.turns}</td><td>${enemys}</td><td>${drops}</td></tr>`;
  1378. }).join('');
  1379. $('#idle-ui-log-table').html(rows);
  1380. if (page === 1) {
  1381. $('#page-prev').prop('disabled', true);
  1382. } else {
  1383. $('#page-prev').prop('disabled', false);
  1384. }
  1385. if (page === maxPage) {
  1386. $('#page-next').prop('disabled', true);
  1387. } else {
  1388. $('#page-next').prop('disabled', false);
  1389. }
  1390. $('#idle-ui-log-length').text(logLength);
  1391. $('#idle-ui-max-page').text(maxPage);
  1392. $('#idle-ui-page').text(page);
  1393. }
  1394.  
  1395. $('#page-prev').click(function () {
  1396. page = page - 1;
  1397. renderRows();
  1398. });
  1399.  
  1400. $('#page-next').click(function () {
  1401. page = page + 1;
  1402. renderRows();
  1403. });
  1404.  
  1405. $('#idle-ui-only-boss').change(function () {
  1406. page = 1;
  1407. getLengthAndMaxPage();
  1408. renderRows();
  1409. });
  1410.  
  1411. $('#clear-log').click(function () {
  1412. log[id] = [];
  1413. localStorage.setItem('idle-ui-maplog', JSON.stringify(log));
  1414. location.reload();
  1415. });
  1416.  
  1417. function getLengthAndMaxPage() {
  1418. const checked = $('#idle-ui-only-boss').prop('checked');
  1419. logLength = checked ? dataSource.filter(item => item.boss).length : dataSource.length;
  1420. maxPage = Math.ceil(logLength / pageSize);
  1421. }
  1422.  
  1423. function reloadLog() {
  1424. log = localStorage.getItem('idle-ui-maplog');
  1425. log = log ? JSON.parse(log) : {};
  1426. dataSource = log[id] || [];
  1427. getLengthAndMaxPage();
  1428. const stats = getBattleLogStats(dataSource);
  1429. $('#idle-ui-creepnum').text(stats.creepNum);
  1430. $('#idle-ui-avgcreepturns').text(stats.avgCreepTurns);
  1431. $('#idle-ui-creepwinrate').text(`${stats.creepWinRate}%`);
  1432. $('#idle-ui-bossnum').text(stats.bossNum);
  1433. $('#idle-ui-avgbossturns').text(stats.avgBossTurns);
  1434. $('#idle-ui-bosswinrate').text(`${stats.bossWinRate}%`);
  1435. page = 1;
  1436. renderRows();
  1437. }
  1438.  
  1439. $('#idle-ui-reload').click(function () {
  1440. reloadLog();
  1441. });
  1442.  
  1443. $('#idle-ui-maplog').click(function () {
  1444. reloadLog();
  1445. $('#modalMapLog').modal('show');
  1446. });
  1447. }
  1448.  
  1449. if (config.showSetAttr) {
  1450. loadSetAttr();
  1451.  
  1452. function loadSetAttr() {
  1453. if (!$('.equip-content > .equip > .set').length) return;
  1454. const setDB = localStorage.getItem('idle-ui-set-db');
  1455. const newSetDB = localStorage.getItem('idle-ui-set-db-new');
  1456. if (setDB && newSetDB) {
  1457. const JSONSetDB = JSON.parse(setDB);
  1458. const JSONNewSetDB = JSON.parse(newSetDB);
  1459. $('.equip-content > .equip > .set').each(function () {
  1460. const content = $(this).parent();
  1461. const itemName = content.children().first().text().replace(/\(\d+\)/g, '');
  1462. const singleData = JSONSetDB.singleData[itemName];
  1463. const existSingLeNum = content.children('.set').length - 1;
  1464. if (singleData && singleData.length > existSingLeNum) {
  1465. const singleContent = singleData.slice(existSingLeNum).map(item => {
  1466. return `<p class="set idle-ui-set-single">${item}</p>`;
  1467. }).join('');
  1468. content.children('.unique').before(singleContent);
  1469. }
  1470. const fullContent = content.children('.unique');
  1471. const existFullNum = fullContent.children('p[class!="set"][class!="require"]').length - 1;
  1472. const setName = fullContent.children('br').last().next().text().replace(/\(\d+\)/g, '');
  1473. var fullData = JSONSetDB.setData[setName];
  1474. if (!fullData) {
  1475. fullData = JSONNewSetDB.setData[setName];
  1476. }
  1477. let setContent = fullData.slice(existFullNum).map(item => {
  1478. return `<p class="idle-ui-set-full">${item}</p>`;
  1479. }).join('');
  1480. if (fullContent.children('br').length === 1) setContent = '<br>' + setContent;
  1481. fullContent.children('br').last().before(setContent);
  1482. });
  1483. } else {
  1484. $.get('/Help/Set', function (html) {
  1485. const parsedsetDB = parseSetHtml(html);
  1486. localStorage.setItem('idle-ui-set-db', JSON.stringify(parsedsetDB));
  1487. loadSetAttr();
  1488. });
  1489. $.get('/Help/Sacred', function (html) {
  1490. const parsedsetDB = parseSetHtml(html);
  1491. localStorage.setItem('idle-ui-set-db-new', JSON.stringify(parsedsetDB));
  1492. loadSetAttr();
  1493. });
  1494. }
  1495. }
  1496.  
  1497. function parseSetHtml(html) {
  1498. $(".footer").before(`<div style="display: none;" id="set-data">${html}</div>`);
  1499. const singleData = {};
  1500. const setData = {};
  1501. $('#set-data .masonry-item .panel-body .equip').each(function () {
  1502. const lines = $(this).children();
  1503. const itemName = lines.first().text().replace(/\(\d+\)/, '');
  1504. const singleLines = [];
  1505. lines.each(function (index) {
  1506. const line = $(this);
  1507. if (index > 0 && line.hasClass('set')) {
  1508. singleLines.push(line.text().replace(/\n/g, ''));
  1509. }
  1510. if (line.hasClass('unique')) {
  1511. const setItems = line.children();
  1512. let stop = false;
  1513. const setLines = [];
  1514. let setName = '';
  1515. setItems.each(function (index) {
  1516. if (index > 0) {
  1517. if ($(this).prop('tagName').toLowerCase() === 'br') {
  1518. stop = true;
  1519. setName = $(this).next().text();
  1520. }
  1521. if (!stop) setLines.push($(this).text().replace(/\n/g, ''));
  1522. }
  1523. });
  1524. if (!setData[setName]) setData[setName] = setLines;
  1525. }
  1526. });
  1527. if (singleLines.length) singleData[itemName] = singleLines;
  1528. });
  1529. return {singleData, setData};
  1530. }
  1531. }
  1532.  
  1533. if (location.href.indexOf('Auction/Query') >= 0 && location.href.indexOf('Auction/QueryBid') === -1) {
  1534. if (config.showAuctionNote) {
  1535. $('.physical.equip-des').each(function () {
  1536. const note = $(this).text();
  1537. const label = $(this).parent().parent().prev().children('.equip-name').last();
  1538. label.after(`<span style="color: #fff;"> ${note}</span>`);
  1539. });
  1540. }
  1541.  
  1542. // if (config.auctionWatch) {
  1543. // let watchList = [];
  1544. //
  1545. // function renderTable(params) {
  1546. // const list = localStorage.getItem('idle-ui-auction');
  1547. // watchList = (list ? JSON.parse(list) : []) || [];
  1548. // const rows = watchList.map((item, index) => {
  1549. // return `<tr><td>${item.category}</td><td>${item.name}</td><td><a href="Query?id=&${item.link}" class="btn btn-xs btn-default" style="margin-right: 12px;">查看</a><button data-index="${index}" type="button" class="delete-auction btn btn-xs btn-danger">取消关注</button></td></tr>`;
  1550. // });
  1551. // $('#modalAuction .table-body').html(rows);
  1552. // $('.delete-auction').click(function () {
  1553. // const index = $(this).data('index');
  1554. // watchList.splice(index, 1);
  1555. // localStorage.setItem('idle-ui-auction', JSON.stringify(watchList));
  1556. // renderTable();
  1557. // });
  1558. // renderNewItems();
  1559. // }
  1560. //
  1561. // function renderNewItems() {
  1562. // const ids = purl().param().items;
  1563. // if (!ids) return;
  1564. // ids.split(',').map(id => {
  1565. // $(`span[data-id="${id}"`).parent().addClass('idle-ui-new-item');
  1566. // });
  1567. // }
  1568. //
  1569. // const link = '<button id="open-auction-modal" type="button" class="btn btn-xs btn-success" style="margin-right: 10px;">特别关注</button>';
  1570. // $('.btn-group').eq(1).before(link);
  1571. // const categorys = [];
  1572. // $('.panel-heading .btn-group button.dropdown-toggle').each(function () {
  1573. // categorys.push($(this).text().replace('<span class="caret"></span>', '').replace(/\s/g, ''));
  1574. // });
  1575. // const category = categorys.join(' - ');
  1576. //
  1577. // const modal = `
  1578. // <div class="modal fade" id="modalAuction" style="display: none;">
  1579. // <div class="modal-dialog modal-large" role="">
  1580. // <div class="modal-content model-inverse">
  1581. // <div class="modal-header">
  1582. // <span class="modal-title">拍卖行特别关注</span>
  1583. // </div>
  1584. // <div class="modal-body">
  1585. // <div class="panel-header state">已有关注项目</div>
  1586. // <table class="table table-condensed">
  1587. // <thead><tr><td>筛选条件</td><td>装备名称</td><td>操作</td></tr></thead>
  1588. // <tbody class="table-body"></tbody>
  1589. // </table>
  1590. // <div class="panel-header state">添加新项目</div>
  1591. // <div class="form">
  1592. // <div class="form-group">
  1593. // <label>筛选条件</label>
  1594. // <p class="form-control-static" style="color: #fff;">${category}</p>
  1595. // </div>
  1596. // <div class="form-group">
  1597. // <label>装备名称</label>
  1598. // <input type="text" id="auction-name" class="form-control hit-input" style="width: 100%;">
  1599. // </div>
  1600. // <button type="button" class="btn btn-success btn-xs" id="add-auction">新增</button>
  1601. // </div>
  1602. // </div>
  1603. // <div class="modal-footer">
  1604. // <button type="button" class="btn btn-default btn-xs" data-dismiss="modal">关闭</button>
  1605. // </div>
  1606. // </div>
  1607. // </div>
  1608. // </div>
  1609. // `;
  1610. // $(document.body).append(modal);
  1611. // renderTable();
  1612. // $('#open-auction-modal').click(function () {
  1613. // if ($('.equip-name').length) {
  1614. // $('#auction-name').val($('.equip-name').eq(0).text().replace('【', '').replace('】', ''));
  1615. // }
  1616. // $('#modalAuction').modal('show');
  1617. // });
  1618. //
  1619. // $('#add-auction').click(function () {
  1620. // if (watchList.length >= 10) {
  1621. // alert('最多关注10条');
  1622. // return;
  1623. // }
  1624. // const params = purl().param();
  1625. // const et = params.et || '';
  1626. // const pt = params.pt || '';
  1627. // const ei = params.ei || '';
  1628. // const link = `et=${et}&pt=${pt}&ei=${ei}`;
  1629. // const name = $('#auction-name').val();
  1630. // const items = [];
  1631. // $('.equip-name').each(function () {
  1632. // const curName = $(this).text().replace('【', '').replace('】', '');
  1633. // if (curName === name) {
  1634. // const id = $(this).parent().children().last().data('id');
  1635. // items.push(id);
  1636. // }
  1637. // });
  1638. // const data = {
  1639. // category: category,
  1640. // name: $('#auction-name').val(),
  1641. // link: link,
  1642. // items: items
  1643. // };
  1644. // watchList.push(data);
  1645. // localStorage.setItem('idle-ui-auction', JSON.stringify(watchList));
  1646. // renderTable();
  1647. // });
  1648. // }1
  1649. }
  1650.  
  1651. if (config.oneKeyEquip && location.href.indexOf('Equipment/Query') >= 0) {
  1652. const btn = '<button type="button" class="btn btn-xs btn-success mr-10" id="show-one-key-equip">一键换装</button>';
  1653. const cname = '<input style="height: 22px;background: black; border: solid 1px #322a20; width: 180px; text-indent: 3px" class="move-name" placeholder="转移ID"/>';
  1654. const startMetastasis = '<button class="btn btn-xs btn-default" id="start-metastasis">一键转移</button>';
  1655. const stopMetastasis = '<button class="btn btn-xs btn-default" id="end-metastasis">停止转移</button>';
  1656.  
  1657. const start = '<button class="btn btn-xs btn-default" id="start-mystery">开始扫荡秘境</button>';
  1658. const end = '<button class="btn btn-xs btn-default" id="end-mystery">停止扫荡</button>';
  1659. $('.panel-heading .btn').eq(0).before(btn);
  1660. $('.panel-heading .btn').eq(0).before(cname);
  1661. let map = localStorage.getItem('idle-ui-maphack');
  1662. if (map) {
  1663. map = JSON.parse(map);
  1664. }
  1665. const cid = $("#cid").val();
  1666. var mysteryIndex = 5;
  1667.  
  1668. // 是否一键转移
  1669. const metastasis = map[`metastasis${cid}`];
  1670. // 要转移人的姓名
  1671. const name = map[`cname${cid}`];
  1672.  
  1673. if (name) {
  1674. $('.move-name').val(name);
  1675. }
  1676. if ((metastasis) && metastasis === 'start') {
  1677. $('.panel-heading .btn').eq(0).before(stopMetastasis);
  1678. mysteryIndex = 6;
  1679. }
  1680.  
  1681. $('#end-metastasis').click(function (params) {
  1682. map[`metastasis${cid}`] = 'end';
  1683. map[`cname${cid}`] = "";
  1684. localStorage.setItem('idle-ui-maphack', JSON.stringify(map));
  1685. location.reload();
  1686. });
  1687.  
  1688. $('.panel-heading .btn').eq(0).before(startMetastasis);
  1689. $('#start-metastasis').click(function (params) {
  1690. map[`metastasis${cid}`] = 'start';
  1691. map[`cname${cid}`] = $('.move-name').val();
  1692. localStorage.setItem('idle-ui-maphack', JSON.stringify(map));
  1693. moveMystery();
  1694. });
  1695.  
  1696. function moveMystery() {
  1697. const mysteryId = $(".selected").children(":first").next().next().next().data('id');
  1698. if (!mysteryId) {
  1699. map[`metastasis${cid}`] = 'end';
  1700. localStorage.setItem('idle-ui-maphack', JSON.stringify(map));
  1701. location.reload();
  1702. return;
  1703. }
  1704. a = {
  1705. cid: cid,
  1706. eid: mysteryId,
  1707. cname: map[`cname${cid}`],
  1708. __RequestVerificationToken: $("[name='__RequestVerificationToken']").val(),
  1709. };
  1710.  
  1711. $.ajax({
  1712. //几个参数需要注意一下
  1713. type: "POST",//方法类型
  1714. dataType: "html",//预期服务器返回的数据类型
  1715. url: 'EquipTrade',//url
  1716. data: a,
  1717. success: function (result) {
  1718. location.reload()
  1719. },
  1720. error: function (result) {
  1721. alert(result)
  1722. }
  1723. });
  1724. }
  1725.  
  1726. if (metastasis && metastasis === 'start') {
  1727. setTimeout(() => {
  1728. if ((metastasis) && metastasis === 'start') {
  1729. moveMystery()
  1730. }
  1731. },config.moveTime);
  1732. }
  1733.  
  1734.  
  1735. // 开始扫荡秘境了,就显示停止扫荡按钮
  1736. const mystery = map[`mystery${cid}`];
  1737. if ((mystery) && mystery === 'start') {
  1738. $('.panel-heading .btn').eq(mysteryIndex).before(end);
  1739. $('#end-mystery').click(function (params) {
  1740. alert('已停止扫荡秘境');
  1741. map[`mystery${cid}`] = 'end';
  1742. localStorage.setItem('idle-ui-maphack', JSON.stringify(map));
  1743. });
  1744. }
  1745. $('.panel-heading .btn').eq(mysteryIndex).before(start);
  1746.  
  1747. $('#start-mystery').click(function (params) {
  1748. map[`mystery${cid}`] = 'start';
  1749. localStorage.setItem('idle-ui-maphack', JSON.stringify(map));
  1750. startMystery();
  1751. });
  1752.  
  1753. function startMystery() {
  1754. const mysteryId = $(".selected").children(":first").next().next().next().data('id');
  1755.  
  1756. map[cid] = 'start';
  1757. a = {
  1758. id: cid,
  1759. cid: cid,
  1760. eid: mysteryId,
  1761. __RequestVerificationToken: $("[name='__RequestVerificationToken']").val(),
  1762. };
  1763.  
  1764. $.ajax({
  1765. //几个参数需要注意一下
  1766. type: "POST",//方法类型
  1767. dataType: "html",//预期服务器返回的数据类型
  1768. url: "EquipDungeon",//url
  1769. data: a,
  1770. success: function (result) {
  1771. // 请求成功,返回网页,自动跳转到秘境界面
  1772. location.href = `../Map/DungeonForEquip?id=${userId}`
  1773. },
  1774. error: function (XMLHttpRequest, textStatus) {
  1775. alert(XMLHttpRequest)
  1776. }
  1777. });
  1778. }
  1779.  
  1780. if (mystery && mystery === 'start') {
  1781. setTimeout(() => {
  1782. if ((mystery) && mystery === 'start') {
  1783. startMystery()
  1784. }
  1785. }, 15000);
  1786. }
  1787.  
  1788. // 设置点击对应的点击事件
  1789.  
  1790. const equipList = ['主手', '副手', '头盔', '护符', '项链', '戒指', '戒指', '衣服', '腰带', '手套', '靴子'];
  1791. let buildMap = {};
  1792. let buildData = [];
  1793. const userId = purl().param().id;
  1794. const equipItems = getEquipItems();
  1795.  
  1796. function loadEquipBuild() {
  1797. buildMap = JSON.parse(localStorage.getItem('idle-ui-equip-build') || '{}');
  1798. buildData = buildMap[userId] || [];
  1799. }
  1800.  
  1801. function saveEquipBuild(data) {
  1802. localStorage.setItem('idle-ui-equip-build', JSON.stringify(data));
  1803. loadEquipBuild();
  1804. renderEquip();
  1805. }
  1806.  
  1807. function renderEquip(buildIndex) {
  1808. if (!buildIndex && buildData.length) buildIndex = 0;
  1809. const data = buildData[buildIndex] || {};
  1810. const equipContent = equipList.map((item, index) => {
  1811. const equipItem = data.items ? data.items[index] : {};
  1812. return `<p><span>${item}</span><span class="${equipItem.type || ''}">${equipItem.name || ''}</span></p>`;
  1813. });
  1814. const firstCol = equipContent.slice(0, 4).join('');
  1815. const secondCol = equipContent.slice(4, 7).join('');
  1816. const thirdCol = equipContent.slice(7).join('');
  1817. const content = `<div class="col-sm-6 col-md-4">${firstCol}</div><div class="col-sm-6 col-md-4">${secondCol}</div><div class="col-sm-6 col-md-4">${thirdCol}</div>`;
  1818. $('#equip-build-content').html(content);
  1819.  
  1820. // 一键换装
  1821. const buildTags = buildData.map((item, index) => {
  1822. return `<li><a class="physical equip-build-option" href="#" data-index="${index}">${item.name}</a></li>`;
  1823. }).join('');
  1824. $('#equip-build-tags').html(buildTags);
  1825. $('#selected-build-name').text(data.name || '选择方案');
  1826. if (buildIndex !== undefined) {
  1827. $('#use-equip-build').data('index', buildIndex);
  1828. $('#del-equip-build').data('index', buildIndex);
  1829. } else {
  1830. $('#use-equip-build').data('index', -1);
  1831. $('#del-equip-build').data('index', -1);
  1832. }
  1833. $('.equip-build-option').click(function (e) {
  1834. e.preventDefault();
  1835. const index = $(this).data('index');
  1836. renderEquip(index);
  1837. });
  1838. }
  1839.  
  1840. const modal = `
  1841. <div class="modal fade" id="modalEquipBuild" style="display: none;">
  1842. <div class="modal-dialog modal-large" role="" style="width: 800px;">
  1843. <div class="modal-content model-inverse">
  1844. <div class="modal-header">
  1845. <span class="modal-title">一键换装</span>
  1846. </div>
  1847. <div class="modal-body">
  1848. <div class="panel-header state">
  1849. <span>已有装备方案:</span>
  1850. <div class="btn-group"><button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown"><span id="selected-build-name">选择方案</span><span class="caret" style="margin-left: 5px;"></span></button><ul class="dropdown-menu" id="equip-build-tags"></ul></div>
  1851. </div>
  1852. <div class="row" id="equip-build-content"></div>
  1853. <button type="button" class="btn btn-success btn-xs mr-10" id="use-equip-build">使用本方案</button>
  1854. <button type="button" class="btn btn-danger btn-xs" id="del-equip-build">删除本方案</button>
  1855. <div id="processing" style="display:none; margin-top: 10px;"><i class="glyphicon glyphicon-refresh"></i> 处理中...</div>
  1856. <div class="panel-header state" style="margin-top: 10px;">保存当前装备到新方案</div>
  1857. <div class="form">
  1858. <div class="form-group">
  1859. <label>方案名称</label>
  1860. <input type="text" id="equip-build-name" class="form-control hit-input" style="width: 100%;">
  1861. </div>
  1862. <button type="button" class="btn btn-success btn-xs" id="add-equip-build">保存</button>
  1863. </div>
  1864. </div>
  1865. <div class="modal-footer">
  1866. <button type="button" class="btn btn-default btn-xs" data-dismiss="modal">关闭</button>
  1867. </div>
  1868. </div>
  1869. </div>
  1870. </div>
  1871. `;
  1872. $(document.body).append(modal);
  1873. loadEquipBuild();
  1874. renderEquip();
  1875. $('#show-one-key-equip').click(function () {
  1876. $('#modalEquipBuild').modal('show');
  1877. });
  1878.  
  1879. let processing = false;
  1880.  
  1881. function doEquip(buildIndex, itemIndex) {
  1882. if (blockData.num >= 9) {
  1883. alert('封号打击次数过多,禁止一键换装');
  1884. location.reload();
  1885. }
  1886. if (itemIndex > equipItems.length - 1) {
  1887. setTimeout(() => {
  1888. processing = false;
  1889. $('#processing').hide();
  1890. location.reload();
  1891. }, 500);
  1892. return;
  1893. }
  1894. const list = $('#form').serializeArray();
  1895. const params = {};
  1896. list.forEach(item => {
  1897. params[item.name] = item.value;
  1898. });
  1899. params.eid = buildData[buildIndex].items[itemIndex].id;
  1900. params.cid = userId;
  1901. // 判断当前要替换的装备是否已经装备
  1902. const itemAlreadyEquiped = equipItems.some(item => item.id === params.eid);
  1903. if (!params.eid || !params.cid) return;
  1904. const name = buildData[buildIndex].items[itemIndex].name;
  1905.  
  1906. if (itemAlreadyEquiped) {
  1907. // 已经装备,进入下一件装备
  1908. doEquip(buildIndex, itemIndex + 1);
  1909. } else {
  1910. // 没有装备,还是进行替换
  1911. $.post('/Equipment/EquipOn', params, function (data) {
  1912. setTimeout(function () {
  1913. doEquip(buildIndex, itemIndex + 1);
  1914. }, 1000);
  1915. }).fail(function (data) {
  1916. setTimeout(function () {
  1917. doEquip(buildIndex, itemIndex + 1);
  1918. }, 1000);
  1919. });
  1920. }
  1921. }
  1922.  
  1923. $('#use-equip-build').click(function () {
  1924. if (processing) return;
  1925. const index = $(this).data('index');
  1926. if (index >= 0) {
  1927. processing = true;
  1928. $('#processing').show();
  1929. doEquip(index, 0);
  1930. } else {
  1931. alert('请先选择一个方案');
  1932. }
  1933. });
  1934.  
  1935. $('#del-equip-build').click(function () {
  1936. const index = $(this).data('index');
  1937. if (index >= 0) {
  1938. buildData.splice(index, 1);
  1939. buildMap[userId] = buildData;
  1940. saveEquipBuild(buildMap);
  1941. } else {
  1942. alert('请先选择一个方案');
  1943. }
  1944. });
  1945.  
  1946. function getEquipItems() {
  1947. const items = [];
  1948. $('.panel-body').eq(0).find('.equip-content').each(function () {
  1949. const label = $(this).prev().children('.equip-name').eq(0);
  1950. if (label.length) {
  1951. const name = label.text();
  1952. const type = label.prop('class').replace('equip-name', '').trim();
  1953. const id = label.parent().children().last().data('id');
  1954. items.push({name: name, type: type, id: id});
  1955. } else {
  1956. items.push({name: '', type: '', id: 0});
  1957. }
  1958. });
  1959. return items;
  1960. }
  1961.  
  1962. $('#add-equip-build').click(function () {
  1963. if (buildData.length >= 5) {
  1964. alert('同一角色最多保存5套方案');
  1965. return;
  1966. }
  1967. const name = $('#equip-build-name').val();
  1968. if (!name) {
  1969. alert('方案必须有一个名称');
  1970. return;
  1971. }
  1972. const newBuild = {
  1973. name: name,
  1974. items: equipItems
  1975. };
  1976. buildData.push(newBuild);
  1977. buildMap[userId] = buildData;
  1978. saveEquipBuild(buildMap);
  1979. });
  1980. }
  1981.  
  1982. if (config.oneKeyAgree && location.href.indexOf('Notice/Query') >= 0) {
  1983. let processing = false;
  1984. const agreeList = [];
  1985. $('.notice-yes').each(function () {
  1986. agreeList.push($(this).data('id'));
  1987. });
  1988.  
  1989. function doAgree(index) {
  1990. if (blockData.num >= 9) {
  1991. alert('封号打击次数过多,禁止一键同意');
  1992. location.reload();
  1993. }
  1994. if (index > agreeList.length - 1) {
  1995. $('#processing').hide();
  1996. processing = false;
  1997. location.reload();
  1998. return;
  1999. }
  2000. const id = agreeList[index];
  2001. const list = $('#form').serializeArray();
  2002. const params = {};
  2003. list.forEach(item => {
  2004. params[item.name] = item.value;
  2005. });
  2006. params.nid = id;
  2007. $.post('/Notice/NoticeYes', params, function () {
  2008. setTimeout(function () {
  2009. doAgree(index + 1);
  2010. }, 300);
  2011. }).fail(function (data) {
  2012. alert("发生异常");
  2013. location.reload();
  2014. });
  2015. }
  2016.  
  2017. let action = renderProcessing();
  2018. action += renderButton('idle-ui-agree', '全部同意');
  2019. $('a.btn.btn-xs.btn-default').eq(0).before(action);
  2020. $('#idle-ui-agree').click(function () {
  2021. if (processing) return;
  2022. if (agreeList.length) {
  2023. $('#processing').show();
  2024. processing = true;
  2025. doAgree(0);
  2026. } else {
  2027. alert('没有可处理的消息');
  2028. }
  2029. });
  2030. }
  2031.  
  2032. if (config.oneKeyRune && location.href.indexOf('Equipment/Material') >= 0) {
  2033. let processing = false;
  2034. const runeList = [];
  2035. $('.artifact.equip-name').each(function () {
  2036. const count = $(this).next().next().text() - 0;
  2037. if (count > 0) {
  2038. const rune = {
  2039. id: $(this).next().next().next().data('id') - 0,
  2040. count: count
  2041. };
  2042. runeList.push(rune);
  2043. }
  2044. });
  2045.  
  2046. $('.equip-name').each(function () {
  2047. const count = $(this).next().next().text() - 0;
  2048. if (count > 0) {
  2049. const rune = {
  2050. id: $(this).next().next().next().data('id') - 0,
  2051. count: count
  2052. };
  2053. runeList.push(rune);
  2054. }
  2055. });
  2056.  
  2057. function doMoveRune(index, cname) {
  2058. if (blockData.num >= 9) {
  2059. alert('封号打击次数过多,禁止一键符文转移');
  2060. location.reload();
  2061. }
  2062. if (index > runeList.length - 1) {
  2063. $('#processing').hide();
  2064. processing = false;
  2065. location.reload();
  2066. return;
  2067. }
  2068. const rune = runeList[index];
  2069. const list = $('#form').serializeArray();
  2070. const params = {};
  2071. list.forEach(item => {
  2072. params[item.name] = item.value;
  2073. });
  2074. params.cname = cname;
  2075. params.count = rune.count;
  2076. params.rune = rune.id;
  2077. $.post('/Equipment/RuneTrade', params, function () {
  2078. setTimeout(function () {
  2079. doMoveRune(index + 1, cname);
  2080. }, 300);
  2081. }).fail(function (data) {
  2082. alert("发生异常,请检查角色名是否正确");
  2083. location.reload();
  2084. });
  2085. }
  2086.  
  2087. $('.btn.btn-xs.btn-default').eq(1).before(renderButton('idle-ui-show-rune', '转移全部符文'));
  2088. $('#idle-ui-show-rune').click(function () {
  2089. $('#modalMoveRune').modal('show');
  2090. });
  2091. const spinner = renderProcessing();
  2092. const modal = `
  2093. <div class="modal fade" id="modalMoveRune" tabindex="-1" role="dialog">
  2094. <div class="modal-dialog modal-sm" role="document">
  2095. <div class="modal-content model-inverse">
  2096. <div class="modal-header">
  2097. <span class="modal-title">转移全部符文</span>
  2098. </div>
  2099. <div class="modal-body">
  2100. <div class="form-group">
  2101. <label for="charName" class="control-label">交易角色:</label>
  2102. <input type="text" class="form-control" id="idle-ui-cname" name="charName" placeholder="请输入角色名称">
  2103. </div>
  2104. </div>
  2105. <div class="modal-footer">
  2106. ${spinner}
  2107. <button type="button" class="btn btn-primary btn-xs" id="idle-ui-move-rune">提交</button>
  2108. <button type="button" class="btn btn-default btn-xs" data-dismiss="modal">关闭</button>
  2109. </div>
  2110. </div>
  2111. </div>
  2112. </div>
  2113. `;
  2114. $(document.body).append(modal);
  2115. $('#idle-ui-move-rune').click(function () {
  2116. if (processing) return;
  2117. if (runeList.length) {
  2118. const cname = $('#idle-ui-cname').val();
  2119. if (!cname) {
  2120. alert('请输入角色名称');
  2121. } else {
  2122. processing = true;
  2123. $('#processing').show();
  2124. doMoveRune(0, cname);
  2125. }
  2126. } else {
  2127. alert('没有转移的符文');
  2128. }
  2129. });
  2130. }
  2131.  
  2132. if (config.showRuneTip) {
  2133. let runeList = [];
  2134. const runeData = localStorage.getItem('idle-ui-rune-db');
  2135. if (runeData) {
  2136. runeList = JSON.parse(runeData);
  2137. } else {
  2138. fetchRuneTip();
  2139. }
  2140.  
  2141. if (location.href.indexOf('Equipment/Inlay') >= 0) {
  2142. const footer = `
  2143. <div class="panel-footer">
  2144. <input class="panel-filter hidden-xs filter-input" id="panel-filter-runeword" placeholder="搜索符文之语">
  2145. <span id="runeword-content"></span>
  2146. </div>
  2147. `;
  2148. $('.panel').eq(0).append(footer);
  2149. let timer = null;
  2150. $('#panel-filter-runeword').keyup(function () {
  2151. if (timer) {
  2152. clearTimeout(timer);
  2153. timer = null;
  2154. }
  2155. timer = setTimeout(() => {
  2156. const name = $(this).val();
  2157. const filtered = name ? runeList.filter(item => item.name.indexOf(name) >= 0) : [];
  2158. let ret = '';
  2159. if (filtered.length) {
  2160. const item = filtered[0];
  2161. const recipe = item.recipe.map(item => {
  2162. return `<span class="artifact">${item}</span>`
  2163. }).join(' + ');
  2164. ret = `<span><span class="artifact equip-name">【${item.name}】</span>:<span>${recipe}</span></span>`;
  2165. const requireContent = item.require.map(item => {
  2166. return `<p><span class="equip-label">${item}</span></p>`;
  2167. }).join('');
  2168. const attrContent = item.attr.map(item => {
  2169. return `<p>${item}</p>`;
  2170. }).join('');
  2171. const tip = `<div class="equip-content"><div class="equip"><p class="artifact">${item.name}</p>${requireContent}${attrContent}</div></div>`;
  2172. ret += tip;
  2173. }
  2174. $('#runeword-content').html(ret);
  2175. $.initPopup();
  2176. }, 300);
  2177. });
  2178.  
  2179. $('.equip').eq(0).children().last().prop('id', 'big-slot');
  2180.  
  2181. const link = '<a href="/Help/Content?url=Artifact" target="_blank" class="btn btn-xs btn-success mr-10">神器列表</a>';
  2182. $('.btn.btn-xs').eq(0).before(link);
  2183. }
  2184.  
  2185. if (location.href.indexOf('Help/Content?url=Artifact') >= 0) {
  2186. const filter = '<div class="container" style="margin-bottom: 20px;"><input class="form-control" id="panel-filter" placeholder="输入神器名称或符文序号" /></div>';
  2187. $('.navbar').next().after(filter);
  2188. let timer = null;
  2189. $('#panel-filter').keyup(function () {
  2190. if (timer) {
  2191. clearTimeout(timer);
  2192. timer = null;
  2193. }
  2194. timer = setTimeout(() => {
  2195. const val = $(this).val();
  2196. if (val) {
  2197. if (/^\d+$/.test(val)) {
  2198. $('tbody tr').each(function (i) {
  2199. const recipe = [];
  2200. $(this).children().eq(1).find('.artifact.equip-name').each(function () {
  2201. recipe.push($(this).text().match(/\d+/g)[0]);
  2202. });
  2203. if (recipe.indexOf(val) >= 0) {
  2204. $(this).show();
  2205. } else {
  2206. $(this).hide();
  2207. }
  2208. });
  2209. } else {
  2210. $('tbody tr').each(function (i) {
  2211. const name = $(this).children().last().find('.artifact').text();
  2212. if (name.indexOf(val) >= 0) {
  2213. $(this).show();
  2214. } else {
  2215. $(this).hide();
  2216. }
  2217. });
  2218. }
  2219. } else {
  2220. $('tbody tr').show();
  2221. }
  2222. }, 300);
  2223. });
  2224. }
  2225.  
  2226. function fetchRuneTip() {
  2227. $.get('/Help/Artifact', function (html) {
  2228. const dom = $.parseHTML(html);
  2229. $(dom).find('tr').each(function (i) {
  2230. if (i > 0) {
  2231. const nameLabel = $(this).children().last().find('.artifact');
  2232. const rune = {name: nameLabel.text(), attr: [], recipe: [], require: []};
  2233. nameLabel.parent().children().each(function (index) {
  2234. if (index > 0) rune.attr.push($(this).text());
  2235. });
  2236. $(this).children().eq(1).find('.artifact.equip-name').each(function () {
  2237. rune.recipe.push($(this).text());
  2238. });
  2239. $(this).children().eq(0).find('.equip-label').each(function () {
  2240. rune.require.push($(this).text());
  2241. });
  2242. runeList.push(rune);
  2243. }
  2244. });
  2245. localStorage.setItem('idle-ui-rune-db', JSON.stringify(runeList));
  2246. });
  2247. }
  2248. }
  2249.  
  2250. if (config.showBattleDetail && inBattlePage()) {
  2251. const battleResult = {};
  2252. const addedDamageTypes = ['溅射', '触发了技能', '对方受到'];
  2253.  
  2254. function getDamageType(plainText) {
  2255. let ret = -1;
  2256. addedDamageTypes.forEach((item, i) => {
  2257. if (plainText.indexOf(item) >= 0) ret = i;
  2258. });
  2259. return ret;
  2260. }
  2261.  
  2262. $('.turn').each(function (index) {
  2263. if (index > 0) {
  2264. const line = $(this).children().eq(1);
  2265. const hpData = $(this).children().first().data('hp');
  2266. const id = line.children()[0].innerHTML;
  2267. if (!hpData[1]) return;
  2268. const firstTargetId = hpData[1].id;
  2269. const skillLabel = line.children('.skill-name');
  2270. const skill = skillLabel.length ? skillLabel.eq(0).text() : '普通攻击';
  2271. const damageLabel = line.children('.damage');
  2272.  
  2273. let damage = 0;
  2274. let damageDetail = {base: 0};
  2275. if (firstTargetId < 0) {
  2276. damage = damageLabel.length ? damageLabel.eq(0).text() - 0 : 0;
  2277. damageDetail = {base: damage};
  2278. $(this).children().each(function (i) {
  2279. if (i > 1) {
  2280. const plainText = getPlainText($(this));
  2281. if (getDamageType(plainText) >= 0) {
  2282. const addedDamage = $(this).children('.damage').eq(0).text() - 0;
  2283. const damageType = getDamageType(plainText);
  2284. damage += addedDamage;
  2285. const lastDamage = damageDetail[damageType];
  2286. damageDetail[damageType] = lastDamage ? lastDamage + addedDamage : addedDamage;
  2287. }
  2288. }
  2289. });
  2290. }
  2291. if (!battleResult[id]) battleResult[id] = {};
  2292. if (!battleResult[id][skill]) battleResult[id][skill] = {
  2293. turn: 0,
  2294. damage: 0,
  2295. damageDetail: {}
  2296. };
  2297.  
  2298. const skillData = battleResult[id][skill];
  2299. skillData.turn += 1;
  2300. skillData.damage += damage;
  2301. Object.keys(damageDetail).forEach(type => {
  2302. if (skillData.damageDetail[type]) {
  2303. skillData.damageDetail[type] += damageDetail[type];
  2304. } else {
  2305. skillData.damageDetail[type] = damageDetail[type];
  2306. }
  2307. });
  2308. }
  2309. });
  2310.  
  2311. const totalTurns = $('.turn').length - 1;
  2312. let partyTotalDamage = 0;
  2313. $('.battle-data tbody tr').each(function (index) {
  2314. if (getCharId(index) > 0) {
  2315. const dmg = $(this).children().eq(2).text() - 0;
  2316. partyTotalDamage += dmg;
  2317. }
  2318. });
  2319.  
  2320. $('.battle-data thead td').eq(2).after('<td class="text-center">友方伤害占比</td><td class="text-center">详情</td><td class="text-center">出手次数</td><td class="text-center">出手占比</td><td class="text-center">每回合伤害</td>');
  2321. $('.battle-data tbody tr').each(function (index) {
  2322. const id = getCharId(index);
  2323. const actor = $(this).children().first().text();
  2324. const turns = getActorTurns(actor);
  2325. const turnsPercent = (turns / totalTurns * 100).toFixed(1) - 0;
  2326. const damage = $(this).children().eq(2).text() - 0;
  2327. const damagePercent = id > 0 ? `${(damage / partyTotalDamage * 100).toFixed(1) - 0}%` : '-';
  2328. const avgDamage = turns > 0 ? Math.round(damage / turns) : '-';
  2329. const link = battleResult[actor] ? `<a href="javascript: void(0);" class="link-detail" data-id="${actor}" data-actor="${actor}">查看</a>` : '-';
  2330. const content = `<td class="text-center poison">${damagePercent}</td><td class="text-center">${link}</td><td class="text-center physical ddd">${turns}</td><td class="text-center poison">${turnsPercent}%</td><td class="text-center fire ee">${avgDamage}</td>`;
  2331. $(this).children().eq(2).after(content);
  2332. });
  2333.  
  2334. $('.battle-data').css('overflow', 'auto');
  2335.  
  2336. const modal = `
  2337. <div class="modal fade" id="modalBattleDetail" tabindex="-1" role="dialog">
  2338. <div class="modal-dialog modal-lg" role="document">
  2339. <div class="modal-content model-inverse">
  2340. <div class="modal-header">
  2341. <span class="modal-title"><span id="idle-ui-char"></span> - 伤害详情</span>
  2342. </div>
  2343. <div class="modal-body">
  2344. <table class="table table-condensed">
  2345. <thead><tr><th class="text-center">技能</th><th class="text-center">总伤害</th><th class="text-center">伤害占比</th><th class="text-center">出手次数</th><th class="text-center">出手占比</th><th class="text-center">每回合伤害</th><th class="text-center">直接伤害</th><th class="text-center">溅射</th><th class="text-center">触发技能</th><th class="text-center">持续伤害及其他</th></tr></thead>
  2346. <tbody id="idle-ui-battle-rows"></tbody>
  2347. </table>
  2348. <ul>
  2349. <li>直接伤害:技能造成的实际直接伤害</li>
  2350. <li>溅射:因溅射,对非主目标造成的溅射伤害之和</li>
  2351. <li>触发技能:【装备自带技能】或【被击中触发】的技能等被触发后造成的伤害</li>
  2352. <li>持续伤害及其他:技能造成的持续伤害,以及其他伤害 </li>
  2353. </ul>
  2354. </div>
  2355. <div class="modal-footer">
  2356. <button type="button" class="btn btn-default btn-xs" data-dismiss="modal">关闭</button>
  2357. </div>
  2358. </div>
  2359. </div>
  2360. </div>
  2361. `;
  2362.  
  2363. $(document.body).append(modal);
  2364.  
  2365. $('.link-detail').click(function () {
  2366. const id = $(this).data('id');
  2367. const data = battleResult[id];
  2368. const actor = $(this).data('actor');
  2369. $('#idle-ui-char').text(actor);
  2370. let actorTotalTurns = 0;
  2371. let actorTotalDamage = 0;
  2372. Object.keys(data).forEach(skill => {
  2373. actorTotalTurns += data[skill].turn;
  2374. actorTotalDamage += data[skill].damage;
  2375. });
  2376.  
  2377. const content = Object.keys(data).map(skill => {
  2378. const skillData = data[skill];
  2379. const percent = (skillData.turn / actorTotalTurns * 100).toFixed(1) - 0;
  2380. const damagePercent = (skillData.damage / actorTotalDamage * 100).toFixed(1) - 0;
  2381. const avgDamage = skillData.turn > 0 ? Math.round(skillData.damage / skillData.turn) : '-';
  2382. return `<tr><td class="text-center skill">${skill}</td><td class="text-center fire">${skillData.damage}</td><td class="text-center poison">${damagePercent}%</td><td class="text-center physical">${skillData.turn}</td><td class="text-center poison">${percent}%</td><td class="text-center fire">${avgDamage}</td><td class="text-center fire">${skillData.damageDetail.base}</td><td class="text-center fire">${skillData.damageDetail['0'] || 0}</td><td class="text-center fire">${skillData.damageDetail['1'] || 0}</td><td class="text-center fire">${skillData.damageDetail['2'] || 0}</td></tr>`;
  2383. }).join('');
  2384. $('#idle-ui-battle-rows').html(content);
  2385. $('#modalBattleDetail').modal('show');
  2386. });
  2387.  
  2388. function getCharId(index) {
  2389. const ary = $('.battle-char').eq(index).prop('id').split('_');
  2390. return ary[ary.length - 1];
  2391. }
  2392.  
  2393. function getActorTurns(id) {
  2394. let ret = 0;
  2395. if (battleResult[id]) {
  2396. Object.keys(battleResult[id]).forEach(skill => {
  2397. ret += battleResult[id][skill].turn;
  2398. });
  2399. }
  2400. return ret;
  2401. }
  2402.  
  2403. function getPlainText(element) {
  2404. return element.clone() //clone the element
  2405. .children() //select all the children
  2406. .remove() //remove all the children
  2407. .end() //again go back to selected element
  2408. .text();
  2409. }
  2410. }
  2411.  
  2412. function switchSkin(showRequire) {
  2413. $('.equip-content > .equip').each(function (item) {
  2414. const type = $(this).children().first().attr('class');
  2415.  
  2416. let classLabel = '';
  2417. const requireIndex = $(this).text().indexOf('限');
  2418. if (requireIndex >= 0) {
  2419. const requireClass = $(this).text().substring(requireIndex + 1, requireIndex + 2);
  2420. classLabel = '<span style="color: #a99877" class="mr-10">' + requireClass + '</span>';
  2421. }
  2422.  
  2423. const label = location.href.indexOf('Auction/QueryBid') >= 0 ? $(this).parent().prev().find('.equip-name').first() : $(this).parent().prev().find('.equip-name').last();
  2424. if (classLabel) {
  2425. showRequire ? label.after(classLabel) : label.next().remove();
  2426. }
  2427. });
  2428. }
  2429.  
  2430. function inBattlePage() {
  2431. const battePages = ['Battle/Simulate', 'Battle/InDungeon', 'Battle/WithChar'];
  2432. return battePages.some(path => location.href.indexOf(path) >= 0);
  2433. }
  2434.  
  2435. function renderProcessing() {
  2436. return '<span id="processing" class="mr-10" style="display:none;"><i class="glyphicon glyphicon-refresh"></i> 处理中...</span>';
  2437. }
  2438.  
  2439. function renderButton(id, text, type) {
  2440. if (!type) type = 'success';
  2441. return `<button type="button" class="btn btn-xs btn-${type} mr-10" id="${id}">${text}</button>`;
  2442. }
  2443.  
  2444. let uid = purl().param().id || purl().param().Id;
  2445.  
  2446. let blockMap = localStorage.getItem('idle-ui-block');
  2447. if (blockMap) {
  2448. blockMap = JSON.parse(blockMap);
  2449. } else {
  2450. blockMap = {};
  2451. }
  2452. if (!blockMap[uid]) blockMap[uid] = {num: 0, time: +new Date()};
  2453. let blockData = blockMap[uid];
  2454.  
  2455. if (location.href.indexOf('Character/Detail') >= 0) {
  2456. checkBlockNum();
  2457. $('.col-sm-6 .panel-body').eq(0).children().last().append(`<p>封号打击次数(仅供参考):<span class="physical">${blockData.num}</span></p>`);
  2458. }
  2459.  
  2460. function addBlockNum() {
  2461. checkBlockNum();
  2462. if (!blockData.num) blockData.num = 0;
  2463. blockData.num += 1;
  2464. blockData.time = +new Date();
  2465. localStorage.setItem('idle-ui-block', JSON.stringify(blockMap));
  2466. new Notification(`当前封号打击为${blockData.num}次,请注意`);
  2467. }
  2468.  
  2469. function checkBlockNum() {
  2470. const curTime = +new Date();
  2471. const hours = Math.floor((curTime - blockData.time) / (3600 * 1000));
  2472. if (hours > 0) {
  2473. blockData.num = blockData.num > hours ? blockData.num - hours : 0;
  2474. blockData.time = blockData.time + (hours * 3600 * 1000);
  2475. localStorage.setItem('idle-ui-block', JSON.stringify(blockMap));
  2476. }
  2477. }
  2478. };
  2479.  
  2480. window.addEventListener('load', idleInit, false);
  2481.  
  2482. const borderColor = '#6f5a40';
  2483. GM_addStyle(`
  2484. .panel-top {
  2485. margin-bottom: 20px;
  2486. text-align: center;
  2487. }
  2488. .idle-ui-title {
  2489. font-size: 18px;
  2490. color: #fff;
  2491. margin-bottom: 6px;
  2492. }
  2493. .panel-header {
  2494. margin: 8px 0;
  2495. }
  2496. .panel-textarea {
  2497. background-color: rgba(255,255,255,0.1);
  2498. color: #a99877;
  2499. margin-bottom: 8px;
  2500. }
  2501. .block-visited {
  2502. background-color: #3f51b5 !important;
  2503. }
  2504. .hit-input {
  2505. display: inline-block;
  2506. color: #fff;
  2507. width: 60px;
  2508. padding: 0 8px;
  2509. border-radius: 0;
  2510. background-color: transparent;
  2511. }
  2512. .idle-ui-set-single, .idle-ui-set-full {
  2513. opacity: 0.5;
  2514. }
  2515. .idle-ui-new-item {
  2516. border: 1px dashed #888 !important;
  2517. }
  2518. .mr-10 {
  2519. margin-right: 10px;
  2520. }
  2521. .ml-10 {
  2522. margin-left: 10px;
  2523. }
  2524. @-webkit-keyframes rotate {
  2525. from {
  2526. -webkit-transform: rotate(0deg);
  2527. -o-transform: rotate(0deg);
  2528. transform: rotate(0deg);
  2529. }
  2530. to {
  2531. -webkit-transform: rotate(360deg);
  2532. -o-transform: rotate(360deg);
  2533. transform: rotate(360deg);
  2534. }
  2535. }
  2536. #processing i {
  2537. animation: rotate 1s ease-in-out infinite;
  2538. }
  2539. .filter-input {
  2540. width: 150px !important;
  2541. }
  2542. #big-slot {
  2543. font-size: 24px;
  2544. margin-top: 10px !important;
  2545. color: #fff;
  2546. }
  2547. #idle-ui-quicksearch {
  2548. position: relative;
  2549. float: left;
  2550. margin-top: 14px;
  2551. }
  2552. #idle-ui-quicksearch > input {
  2553. width: 150px;
  2554. display: inline-block;
  2555. height: 24px;
  2556. line-height: 24px;
  2557. border-radius: 3px;
  2558. }
  2559. .equip-container > p:hover {
  2560. white-space: nowrap;
  2561. }
  2562. .equip-container > p:hover .sr-only {
  2563. z-index: 1;
  2564. position: relative;
  2565. }
  2566. html.d3 body {
  2567. color: #a99877;
  2568. font-family: "Consolas", Arial, sans-serif;
  2569. }
  2570. html.d3 .panel {
  2571. background-color: #171614;
  2572. border-color: ${borderColor};
  2573. }
  2574. html.d3 .panel-inverse > .panel-heading {
  2575. background-color: #101010;
  2576. border-color: ${borderColor};
  2577. font: normal 16px "Exocet Blizzard Light","Palatino Linotype", "Times", serif;
  2578. color: #F3E6D0;
  2579. line-height: 26px;
  2580. }
  2581. html.d3 .panel-inverse > .panel-heading .label {
  2582. font-size: 12px;
  2583. font-family: "Consolas", Arial, sans-serif;
  2584. }
  2585. html.d3 .btn {
  2586. background-color: transparent;
  2587. border: 1px solid ${borderColor};
  2588. vertical-align: top;
  2589. color: #ad835a;
  2590. font: normal 14px/1.5 Arial, sans-serif;
  2591. line-height: normal;
  2592. }
  2593. html.d3 .btn:hover {
  2594. color: #fff !important;
  2595. }
  2596. html.d3 .btn:active {
  2597. background-color: transparent;
  2598. }
  2599. html.d3 .label {
  2600. line-height: normal;
  2601. font-weight: normal;
  2602. border-radius: 2px;
  2603. padding: 3px 4px 1px;
  2604. border: 1px solid #5f3d11;
  2605. box-shadow: 0 0 2px #000;
  2606. background-color: #000;
  2607. color: #ad835a;
  2608. }
  2609. html.d3 .label.label-info {
  2610. color: #6969ff;
  2611. }
  2612. html.d3 .label.label-warning {
  2613. color: #ffff00;
  2614. }
  2615. html.d3 .label.label-danger {
  2616. color: #e60101;
  2617. }
  2618. html.d3 .label.label-success {
  2619. color: #00c400;
  2620. }
  2621. html.d3 .physical {
  2622. color: #f3e6d0 !important;
  2623. }
  2624. html.d3 .navbar-inverse.navbar-fixed-top {
  2625. border-bottom: 1px solid #322a20;
  2626. background-color: #171614;
  2627. }
  2628. html.d3 .navbar-inverse .navbar-brand {
  2629. color: #f3e6d0;
  2630. font-family: "Exocet Blizzard Light","Palatino Linotype", "Times", serif;
  2631. }
  2632. html.d3 a, html.d3 .navbar-inverse .navbar-nav>li>a {
  2633. color: #ad835a;
  2634. }
  2635. html.d3 .magical, html.d3 .skill, html.d3 .cold {
  2636. color: #6969ff !important;
  2637. }
  2638. html.d3 .hit-input {
  2639. border-color: ${borderColor};
  2640. }
  2641. html.d3 .progress {
  2642. border: 1px solid #513f2e;
  2643. border-radius: 0;
  2644. box-shadow: 0 0 5px #000;
  2645. background-color: #101010;
  2646. color: #f3e6d0;
  2647. height: 22px;
  2648. }
  2649. html.d3 .progress-bar {
  2650. border: 1px solid #101010;
  2651. line-height: 20px;
  2652. }
  2653. html.d3 .progress-bar-exp {
  2654. background-color: rgb(251,131,44);
  2655. }
  2656. html.d3 .progress-bar-life {
  2657. background: rgb(235,21,28);
  2658. }
  2659. html.d3 .footer {
  2660. border-top: 1px solid #322a20;
  2661. background-color: #171614;
  2662. }
  2663. html.d3 .btn.btn-success {
  2664. color: #00c400;
  2665. }
  2666. html.d3 .btn.btn-danger {
  2667. color: #e60101;
  2668. }
  2669. html.d3 .img-thumbnail {
  2670. border-color: #d59c52;
  2671. }
  2672. html.d3 .popover {
  2673. background: #1d180e;
  2674. padding: 1px;
  2675. border: 1px solid #322a20;
  2676. border-radius: 2px;
  2677. box-shadow: 0 0 10px #000;
  2678. max-width: 271px;
  2679. font-family: "Consolas", Arial, sans-serif;
  2680. }
  2681. html.d3 .popover-content .equip p:first-child {
  2682. height: 30px;
  2683. width: 263px;
  2684. padding: 0;
  2685. margin: 0 -10px 10px -10px !important;
  2686. background: url(http://images.targetedu.cn/d3/tooltip-title.jpg) no-repeat;
  2687. text-align: center;
  2688. line-height: 28px;
  2689. font-size: 16px;
  2690. font-family: "Exocet Blizzard Light","Palatino Linotype", "Times", serif;
  2691. }
  2692. html.d3 .popover-content .equip p.unique:first-child {
  2693. background-position: 0 -120px;
  2694. }
  2695. html.d3 .popover-content .equip p.set:first-child {
  2696. background-position: 0 -180px;
  2697. }
  2698. html.d3 .popover-content .equip p.rare:first-child {
  2699. background-position: 0 -90px;
  2700. }
  2701. html.d3 .popover-content .equip p.artifact:first-child {
  2702. background-position: 0 -150px;
  2703. }
  2704. html.d3 .popover-content .equip p.magical:first-child {
  2705. background-position: 0 -60px;
  2706. }
  2707. html.d3 .popover-content .equip p.base:first-child {
  2708. background-position: 0 -30px;
  2709. }
  2710. html.d3 .popover-content .equip p.slot:first-child {
  2711. background-position: 0 -30px;
  2712. }
  2713. html.d3 .popover-content {
  2714. background-color: #000;
  2715. padding: 2px 12px;
  2716. }
  2717. html.d3 hr {
  2718. border-color: ${borderColor};
  2719. }
  2720. html.d3 .panel-inverse > .panel-footer {
  2721. background-color: #101010;
  2722. border-color: ${borderColor};
  2723. }
  2724. html.d3 .modal-dialog {
  2725. box-shadow: 0 0 10px #000;
  2726. }
  2727. html.d3 .modal-content {
  2728. background-color: #171614;
  2729. border-color: ${borderColor};
  2730. }
  2731. html.d3 .model-inverse > .modal-header, html.d3 .model-inverse > .modal-footer {
  2732. background-color: #101010;
  2733. border-color: ${borderColor};
  2734. }
  2735. html.d3 .model-inverse > .modal-header span {
  2736. line-height: normal;
  2737. }
  2738. html.d3 .panel-textarea {
  2739. border-color: ${borderColor};
  2740. }
  2741. html.d3 .panel-footer .panel-filter {
  2742. border-color: #2a241c;
  2743. }
  2744. html.d3 .btn-default:active:focus,
  2745. html.d3 .open>.dropdown-toggle.btn-default:focus,
  2746. html.d3 .btn-default.active, .btn-default:active,
  2747. html.d3 .open>.dropdown-toggle.btn-default {
  2748. background-color: transparent;
  2749. color: #a99877;
  2750. }
  2751. html.d3 .dropdown-menu {
  2752. background-color: #101010;
  2753. border-color: ${borderColor};
  2754. box-shadow: 0 0 10px #000;
  2755. font-family: "Consolas", Arial, sans-serif;
  2756. }
  2757. html.d3 .equip-container .selected {
  2758. border: 1px solid ${borderColor};
  2759. background-color: transparent;
  2760. }
  2761. html.d3 .table > tbody > tr > td,
  2762. html.d3 .table > tbody > tr > th,
  2763. html.d3 .table > tfoot > tr > td,
  2764. html.d3 .table > tfoot > tr > th,
  2765. html.d3 .table > thead > tr > td,
  2766. html.d3 .table > thead > tr > th {
  2767. border-color: ${borderColor};
  2768. }
  2769. html.d3 .equip .divider {
  2770. background-color: ${borderColor};
  2771. }
  2772. html.d3 .panel-heading .btn-group, html.d3 .panel-heading .btn {
  2773. vertical-align: top;
  2774. }
  2775. html.d3 .form-control{
  2776. border-color: ${borderColor};
  2777. background-color: #101010;
  2778. color: #a99877;
  2779. }
  2780. html.d3 .form-validation .form-control {
  2781. width: 198px;
  2782. }
  2783. html.d3 .popover.bottom>.arrow:after {
  2784. border-bottom-color: #322a20;
  2785. }
  2786. html.d3 .super, html.d3 .unique {
  2787. color: rgb(255,128,0) !important;
  2788. }
  2789. html.d3 .artifact {
  2790. color: rgb(182,89,245) !important;
  2791. }
  2792. html.d3 .equip > p {
  2793. color: #6969ff;
  2794. }
  2795. `);