idle

挂机无止境的辅助脚本

目前為 2018-09-15 提交的版本,檢視 最新版本

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