Greasy Fork 支持简体中文。

idle

挂机无止境的辅助脚本

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

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