pad.skyozora.com-Multiplay-Helper

show stamina and fast add stage

当前为 2017-10-14 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name pad.skyozora.com-Multiplay-Helper
  3. // @name:zh-CN 智龙迷城战友系统及资讯网协力页面辅助器
  4. // @namespace http://www.mapaler.com/
  5. // @description show stamina and fast add stage
  6. // @description:zh-CN 智龙迷城战友系统及资讯网,协力页面,显示体力,登陆页面可快速添加今日地图
  7. // @include http://pad.skyozora.com/multiplay/register/
  8. // @include http://pad.skyozora.com/multiplay/
  9. // @resource style https://raw.githubusercontent.com/Mapaler/pad.skyozora.com-Multiplay-Helper/master/style.css?v6
  10. // @version 1.1.15
  11. // @copyright 2017+, Mapaler <mapaler@163.com>
  12. // @grant GM_getResourceText
  13. // ==/UserScript==
  14.  
  15.  
  16. //仿GM_xmlhttpRequest函数v1.3
  17. if (typeof(GM_xmlhttpRequest) == "undefined")
  18. {
  19. var GM_xmlhttpRequest = function(GM_param) {
  20.  
  21. var xhr = new XMLHttpRequest(); //创建XMLHttpRequest对象
  22. xhr.open(GM_param.method, GM_param.url, true);
  23. if (GM_param.responseType) xhr.responseType = GM_param.responseType;
  24. if (GM_param.overrideMimeType) xhr.overrideMimeType(GM_param.overrideMimeType);
  25. xhr.onreadystatechange = function() //设置回调函数
  26. {
  27. if (xhr.readyState === xhr.DONE) {
  28. if (xhr.status === 200 && GM_param.onload)
  29. GM_param.onload(xhr);
  30. if (xhr.status !== 200 && GM_param.onerror)
  31. GM_param.onerror(xhr);
  32. }
  33. }
  34.  
  35. for (var header in GM_param.headers) {
  36. xhr.setRequestHeader(header, GM_param.headers[header]);
  37. }
  38.  
  39. xhr.send(GM_param.data ? GM_param.data : null);
  40. }
  41. }
  42. //仿GM_getValue函数v1.0
  43. if(typeof(GM_getValue) == "undefined")
  44. {
  45. var GM_getValue = function(name, type){
  46. var value = localStorage.getItem(name);
  47. if (value == undefined) return value;
  48. if ((/^(?:true|false)$/i.test(value) && type == undefined) || type == "boolean")
  49. {
  50. if (/^true$/i.test(value))
  51. return true;
  52. else if (/^false$/i.test(value))
  53. return false;
  54. else
  55. return Boolean(value);
  56. }
  57. else if((/^\-?[\d\.]+$/i.test(value) && type == undefined) || type == "number")
  58. return Number(value);
  59. else
  60. return value;
  61. }
  62. }
  63. //仿GM_setValue函数v1.0
  64. if(typeof(GM_setValue) == "undefined")
  65. {
  66. var GM_setValue = function(name, value){
  67. localStorage.setItem(name, value);
  68. }
  69. }
  70. //仿GM_deleteValue函数v1.0
  71. if(typeof(GM_deleteValue) == "undefined")
  72. {
  73. var GM_deleteValue = function(name){
  74. localStorage.removeItem(name);
  75. }
  76. }
  77. //仿GM_listValues函数v1.0
  78. if(typeof(GM_listValues) == "undefined")
  79. {
  80. var GM_listValues = function(){
  81. var keys = [];
  82. for (var ki=0, kilen=localStorage.length; ki<kilen; ki++)
  83. {
  84. keys.push(localStorage.key(ki));
  85. }
  86. return keys;
  87. }
  88. }
  89. var formatJson = function (json, options) {
  90. var reg = null,
  91. formatted = '',
  92. pad = 0,
  93. PADDING = ' ';
  94. options = options || {};
  95. options.newlineAfterColonIfBeforeBraceOrBracket = (options.newlineAfterColonIfBeforeBraceOrBracket === true) ? true : false;
  96. options.spaceAfterColon = (options.spaceAfterColon === false) ? false : true;
  97. if (typeof json !== 'string') {
  98. json = JSON.stringify(json);
  99. } else {
  100. json = JSON.parse(json);
  101. json = JSON.stringify(json);
  102. }
  103. reg = /([\{\}])/g;
  104. json = json.replace(reg, '\r\n$1\r\n');
  105. reg = /([\[\]])/g;
  106. json = json.replace(reg, '\r\n$1\r\n');
  107. reg = /(\,)/g;
  108. json = json.replace(reg, '$1\r\n');
  109. reg = /(\r\n\r\n)/g;
  110. json = json.replace(reg, '\r\n');
  111. reg = /\r\n\,/g;
  112. json = json.replace(reg, ',');
  113. if (!options.newlineAfterColonIfBeforeBraceOrBracket) {
  114. reg = /\:\r\n\{/g;
  115. json = json.replace(reg, ':{');
  116. reg = /\:\r\n\[/g;
  117. json = json.replace(reg, ':[');
  118. }
  119. if (options.spaceAfterColon) {
  120. reg = /\:/g;
  121. json = json.replace(reg, ':');
  122. }
  123. (json.split('\r\n')).forEach(function (node, index) {
  124. var i = 0,
  125. indent = 0,
  126. padding = '';
  127.  
  128. if (node.match(/\{$/) || node.match(/\[$/)) {
  129. indent = 1;
  130. } else if (node.match(/\}/) || node.match(/\]/)) {
  131. if (pad !== 0) {
  132. pad -= 1;
  133. }
  134. } else {
  135. indent = 0;
  136. }
  137.  
  138. for (i = 0; i < pad; i++) {
  139. padding += PADDING;
  140. }
  141.  
  142. formatted += padding + node + '\r\n';
  143. pad += indent;
  144. }
  145. );
  146. formatted = formatted.replace(/^\s*|\s*$/g,""); //去掉首尾空格
  147. return formatted;
  148. };
  149. //创建带Label的Input类
  150. var LabelInput = function(text, classname, name, type, value, title = "", beforeText = true) {
  151. var label = document.createElement("label");
  152. if (text != undefined) label.appendChild(document.createTextNode(text));
  153. label.className = classname;
  154. if (typeof(title) != "undefined")
  155. label.title = title;
  156.  
  157. var ipt = document.createElement("input");
  158. ipt.name = name;
  159. ipt.id = ipt.name;
  160. ipt.type = type;
  161. ipt.value = value;
  162.  
  163. label.input = ipt;
  164. if (beforeText)
  165. label.insertBefore(ipt, label.firstChild);
  166. else
  167. label.appendChild(ipt);
  168. return label;
  169. };
  170. function log(str) //在信息框显示内容的
  171. {
  172. var infoBox = document.querySelector("#info-box");
  173. for (var ci = infoBox.childNodes.length-1;ci>=0;ci--) //清空主图列表
  174. {
  175. infoBox.childNodes[ci].remove();
  176. }
  177. infoBox.appendChild(document.createTextNode(str));
  178. }
  179. //得到标准时区的时间的函数
  180. function getLocalTime(i)
  181. {
  182. //参数i为时区值数字,比如北京为东八区则输进8,西5输入-5
  183. if (typeof i !== 'number') return;
  184. var d = new Date();
  185. //得到1970年一月一日到现在的秒数
  186. var len = d.getTime();
  187. //本地时间与GMT时间的时间偏移差
  188. var offset = d.getTimezoneOffset() * 60000;
  189. //得到现在的格林尼治时间
  190. var utcTime = len + offset;
  191. return new Date(utcTime + 3600000 * i);
  192. }
  193.  
  194. var config={
  195. version:1, //储存当前设置结构版本
  196. updateDate:0, //储存今日开放地图上次更新时间
  197. todayStage:[
  198. {name:"每日降临",detail:"每天都会更换一次的降临神,保持24小时。",stages:[]},
  199. {name:"紧急降临",detail:"每天分组出现的紧急本,每个组一小时。",stages:[]},
  200. {name:"耀日本",detail:"每周分星期几固定出现的本",stages:[]},
  201. {name:"活动本",detail:"各种活动的本",stages:[]}
  202. ], //储存当前开放的地图
  203. starStage:[], //储存收藏的地图
  204. message:[],
  205. };
  206. var stageList=[]; //储存全部地图的数据
  207. var mobile = false; //是否为手机版
  208. var stageTestReg = "^/?s(?:tage)?/"; //用来测试href是不是地下城的
  209.  
  210. if(typeof(GM_getResourceText) != "undefined") //用了GM插件
  211. {
  212. var styleDom = document.createElement("style");
  213. styleDom.type = "text/css";
  214. styleDom.appendChild(document.createTextNode(GM_getResourceText('style')));
  215. document.head.appendChild(styleDom);
  216. }
  217.  
  218. if (GM_getValue("helper-config") == undefined && location.pathname == "/multiplay/register/")
  219. {
  220. saveConfig();
  221. alert("?欢迎使用!\n请先导入地下城列表数据\n然后检查今日开放地下城。");
  222. console.log("配置不存在,储存默认配置");
  223. }else
  224. {
  225. loadConfig(GM_getValue("helper-config"),GM_getValue("helper-stage-list"));
  226. //console.log("配置存在",config);
  227.  
  228. var now = getLocalTime(9);var last = new Date(config.updateDate);
  229. if (now > last && now.getDate() != last.getDate())
  230. {
  231. console.log("今天的开放地图还没检查");
  232. if(location.pathname == "/multiplay/register/") alert("?又是新的一天了!\n请检查今天开放的地下城。");
  233. config.todayStage.length = 0; //清空昨天的
  234. }else
  235. {
  236. console.log("已经是今天的开放地图");
  237. }
  238. }
  239. function loadConfig(configStr,stageListStr,reset = false)
  240. {
  241. var bk = [true,true];
  242. var saConfig = JSON.parse(configStr);
  243. console.log("设置",saConfig)
  244. var saStageList = JSON.parse(stageListStr);
  245. console.log("地图数据",saStageList)
  246.  
  247. if (saConfig != null && typeof(saConfig) == "object")
  248. {
  249. if (reset)
  250. {
  251. config = saConfig;
  252. }
  253. else
  254. config = Object.assign(config, saConfig);
  255. }
  256. else
  257. {
  258. console.error("配置损坏,使用默认配置");
  259. bk[0] = false;
  260. }
  261. if (saStageList != null && typeof(saStageList) == "object")
  262. stageList = saStageList.concat();
  263. else
  264. {
  265. console.error("完整地下城数据丢失,使用空配置");
  266. bk[1] = false;
  267. }
  268. return bk;
  269. }
  270. function saveConfig(type)
  271. {
  272. if (type == undefined) type = 255;
  273. if (1 == (type & 1))
  274. {
  275. var configStr = JSON.stringify(config);
  276. GM_setValue("helper-config", configStr);
  277. }
  278. if (2 == (type & 2))
  279. {
  280. var stageListStr = JSON.stringify(stageList);
  281. GM_setValue("helper-stage-list", stageListStr);
  282. }
  283. }
  284.  
  285.  
  286. if(location.pathname == "/multiplay/register/") //注册页面
  287. {
  288. registerPage();
  289. }else if(location.pathname == "/multiplay/") //列表页面
  290. {
  291. multiplayPage();
  292. }
  293.  
  294. function registerPage()
  295. {
  296. var form = document.querySelector("#wrapper>table:nth-of-type(3) form"); //主要版面的表单
  297. if (form == undefined) //如果没找到,试试手机版
  298. {
  299. form = document.querySelector(".content>form");
  300. if (form!=undefined)
  301. {
  302. mobile = true;
  303. }else
  304. {
  305. alert("?未找到协力登陆窗口");
  306. }
  307. }
  308. if (!mobile) form.querySelector("p:nth-last-of-type(1)").remove() //去除最后面那个无用的东西
  309. var box = document.createElement("div");form.parentElement.appendChild(box);
  310. box.id = box.className = "mlt-helper";
  311.  
  312.  
  313. function typeClick(){refreshStageList1(this.value)};
  314.  
  315. var stgBox = document.createElement("div");box.appendChild(stgBox);
  316. stgBox.className = "main-stg-box";
  317.  
  318. var stg1Box = document.createElement("div");stgBox.appendChild(stg1Box);
  319. stg1Box.className = "stg-box stg-box-1";
  320. var stg1Ul = document.createElement("ul");stg1Box.appendChild(stg1Ul);
  321. function refresTypeList()
  322. {
  323. for (var ci = stg1Ul.childNodes.length-1;ci>=0;ci--) //清空主图列表
  324. {
  325. stg1Ul.childNodes[ci].remove();
  326. }
  327. //添加每日类型
  328. config.todayStage.forEach(function(stgs,index){
  329. var stg1UlLi1 = document.createElement("li");stg1Ul.appendChild(stg1UlLi1);
  330. if (typeof(stgs) != "object") return;
  331. var stgType1 = new LabelInput(stgs.name, "stg-type","stg-type","radio",index,stgs.name.detail);
  332. //if (index == 0) stgType1.input.checked = true;
  333. stgType1.input.onclick = typeClick;
  334. stg1UlLi1.appendChild(stgType1);
  335. })
  336.  
  337. //添加收藏类型
  338. var stg1UlLi2 = document.createElement("li");stg1Ul.appendChild(stg1UlLi2);
  339. var stgType2 = new LabelInput("我的收藏", "stg-type","stg-type","radio",100,"我收藏的地下城");
  340. stgType2.input.onclick = typeClick;
  341. stg1UlLi2.appendChild(stgType2);
  342. }
  343.  
  344.  
  345. var stg2Box = document.createElement("div");stgBox.appendChild(stg2Box);
  346. stg2Box.className = "stg-box stg-box-2";
  347. var stg2Ul = document.createElement("ul");stg2Box.appendChild(stg2Ul);
  348.  
  349. //征求文本信息
  350. var req = form.querySelector("[name=req]");
  351. var msgBox = document.createElement("select");stgBox.appendChild(msgBox);
  352. msgBox.size = 5;
  353. msgBox.className = "stg-box msg-box";
  354. msgBox.onclick = function(){
  355. var msg = config.message[this.value];
  356. if (msg !== undefined)
  357. insertText(req,msg);
  358. //req.value += msg;
  359. }
  360.  
  361. function refreshMessageList()
  362. {
  363. while(msgBox.options.length>0) //清空原来的短语列表
  364. {
  365. msgBox.remove(0);
  366. }
  367. config.message.forEach(function(item,index){
  368. var opt = new Option(item, index);
  369. msgBox.add(opt);
  370. })
  371. }
  372. function insertText(obj,str) {
  373. if (document.selection) {
  374. var sel = document.selection.createRange();
  375. sel.text = str;
  376. } else if (typeof obj.selectionStart === 'number' && typeof obj.selectionEnd === 'number') {
  377. var startPos = obj.selectionStart,
  378. endPos = obj.selectionEnd,
  379. cursorPos = startPos,
  380. tmpStr = obj.value;
  381. obj.value = tmpStr.substring(0, startPos) + str + tmpStr.substring(endPos, tmpStr.length);
  382. cursorPos += str.length;
  383. obj.selectionStart = obj.selectionEnd = cursorPos;
  384. } else {
  385. obj.value += str;
  386. }
  387. }
  388.  
  389. var msgBoxCtl = document.createElement("div");stgBox.appendChild(msgBoxCtl);
  390. msgBoxCtl.className = "msg-box-control";
  391. var msgAdd = document.createElement("input");msgBoxCtl.appendChild(msgAdd);
  392. msgAdd.type = "button";
  393. msgAdd.id = msgAdd.className = "message-add";
  394. msgAdd.value = "+";
  395. msgAdd.onclick = function(){
  396. var str = prompt("请输入需要保存的短语");
  397. if (str == null) return;
  398. config.message.push(str);
  399. saveConfig(1);
  400. refreshMessageList();
  401. };
  402. var msgRmv = document.createElement("input");msgBoxCtl.appendChild(msgRmv);
  403. msgRmv.type = "button";
  404. msgRmv.id = msgRmv.className = "message-remove";
  405. msgRmv.value = "-";
  406. msgRmv.onclick = function(){
  407. config.message.splice(msgBox.selectedIndex,1);
  408. saveConfig(1);
  409. refreshMessageList();
  410. };
  411.  
  412. //刷新地下城列表类型
  413. function refreshStageList1(type)
  414. {
  415. if (type == undefined)type = 0;
  416. for (var ci = stg2Ul.childNodes.length-1;ci>=0;ci--) //清空主图列表
  417. {
  418. stg2Ul.childNodes[ci].remove();
  419. }
  420. var stages; //需要处理的数组
  421. if (type == 100)
  422. {
  423. stages = config.starStage;
  424. }else if (type >=0 )
  425. {
  426. if (config.todayStage[type] == undefined) return;
  427. stages = config.todayStage[type].stages;
  428. }else
  429. {
  430. console.error("未知的地下城类型",type,stages);
  431. return;
  432. }
  433.  
  434. if (typeof(stages) != "object") return;
  435. stages.forEach(function(stgName)
  436. {
  437. var _stgName = stgName;
  438. var li = document.createElement("li");stg2Ul.appendChild(li);
  439. var stgLbl = new LabelInput(null, "stg-list","stg-list","radio",_stgName,"地下城大关卡:" + _stgName);
  440. li.appendChild(stgLbl);
  441. stgLbl.input.onclick = refreshStageList2;
  442.  
  443. var icon = document.createElement("div"); stgLbl.appendChild(icon);
  444. icon.className = "stage-icon";
  445. var thisStage = stageList.filter(function(stg){return stg.name == _stgName;})[0]
  446. if (thisStage) icon.style.backgroundImage = "url(" + thisStage.iconUrl + ")";
  447. var detail = document.createElement("div"); stgLbl.appendChild(detail);
  448. detail.className = "stage-detail";
  449. detail.appendChild(document.createTextNode(_stgName));
  450. })
  451. }
  452.  
  453. function refreshStageList2()
  454. {
  455. if (!this.checked) return; //如果并不是自身被选中,那么就没反应
  456. var _stgName = this.value;
  457. var thisStage = stageList.filter(function(stg){return stg.name == _stgName;})[0]
  458. if (thisStage == undefined)
  459. {
  460. alert("?数据库里没有这个地下城");
  461. return;
  462. }
  463.  
  464. stage0.selectedIndex = stage0.options.length - 1; //选中“上次登录的关卡”
  465.  
  466. while(stage1.options.length>0) //清空原来的主地下城列表
  467. {
  468. stage1.remove(0);
  469. }
  470. while(stage2.options.length>0) //清空原来的子地下城列表
  471. {
  472. stage2.remove(0);
  473. }
  474.  
  475. var opt = new Option(thisStage.name, thisStage.name);
  476. stage1.add(opt);
  477. stage1.selectedIndex = stage1.options.length - 1;
  478.  
  479. thisStage.subStage.forEach(function(stg){
  480. var opt = new Option(stg.name, stg.name);
  481. stage2.add(opt);
  482. })
  483. stage2.selectedIndex = 0;
  484. }
  485.  
  486. function addStarStage(name)
  487. {
  488. if (config.starStage.indexOf(name)<0)
  489. {
  490. if (!stageList.some(function(item){ //查找以前有没有这个地图
  491. return item.name == name;
  492. }))
  493. alert("?数据库里没有这个地下城");
  494. else{
  495. config.starStage.push(name);
  496. saveConfig(1);
  497. stg1Ul.querySelector("input[value='100']").click(); //点击刷新
  498. //alert("?“"+ name +"”收藏成功");
  499. }
  500. }else
  501. {
  502. alert("?“"+ name +"”已经收藏过了");
  503. }
  504. }
  505. function removeStarStage(name)
  506. {
  507. if (name == undefined)
  508. {
  509. config.starStage.length = 0; //如果没有输入,直接清空
  510. saveConfig(1);
  511. stg1Ul.querySelector("input[value='100']").click(); //点击刷新
  512. //alert("收藏清空了");
  513. return;
  514. }
  515. var index = config.starStage.indexOf(name);
  516. if (index<0)
  517. {
  518. alert("?你并没有收藏过“"+ name +"”");
  519. }else
  520. {
  521. config.starStage.splice(index,1)
  522. saveConfig(1);
  523. stg1Ul.querySelector("input[value='100']").click(); //点击刷新
  524. //alert("“"+ name +"”被删掉了");
  525. }
  526. }
  527. var btnBox1 = document.createElement("div");box.appendChild(btnBox1);
  528. var btnAddStg = document.createElement("input");btnBox1.appendChild(btnAddStg);
  529. btnAddStg.type = "button";
  530. btnAddStg.id = btnAddStg.className = "add-stage-string";
  531. btnAddStg.value = "输入地下城收藏";
  532. btnAddStg.onclick = function(){
  533. addStarStage(prompt("请输入地下城名称"));
  534. };
  535. var btnRemoveStg = document.createElement("input");btnBox1.appendChild(btnRemoveStg);
  536. btnRemoveStg.type = "button";
  537. btnRemoveStg.id = btnRemoveStg.className = "remove-stage";
  538. btnRemoveStg.value = "删除选中地下城收藏";
  539. btnRemoveStg.onclick = function(){
  540. var radios = document.getElementsByName("stg-list");
  541. for (var ri=0;ri<radios.length;ri++)
  542. {
  543. if (radios[ri].checked)
  544. {
  545. removeStarStage(radios[ri].value);
  546. }
  547. }
  548. };
  549. var btnRemoveAllStg = document.createElement("input");btnBox1.appendChild(btnRemoveAllStg);
  550. btnRemoveAllStg.type = "button";
  551. btnRemoveAllStg.id = btnRemoveAllStg.className = "remove-stage";
  552. btnRemoveAllStg.value = "清空我的收藏";
  553. btnRemoveAllStg.onclick = function(){
  554. removeStarStage();
  555. };
  556.  
  557. var btnBox2 = document.createElement("div");box.appendChild(btnBox2);
  558. var chkUpt = document.createElement("input");btnBox2.appendChild(chkUpt);
  559. chkUpt.type = "button";
  560. chkUpt.id = chkUpt.className = "checkUpdate";
  561. chkUpt.value = "检查今日开放地下城";
  562. chkUpt.onclick = function(){
  563. checkTodayUpdate(function(){
  564. refresTypeList();
  565. saveConfig(1);
  566. refreshStageList1(0);
  567. })
  568. }
  569.  
  570. var chkStgLst = document.createElement("input");btnBox2.appendChild(chkStgLst);
  571. chkStgLst.type = "button";
  572. chkStgLst.id = chkUpt.className = "check-stage-list";
  573. chkStgLst.value = "获取完整地下城数据";
  574. chkStgLst.onclick = function(){
  575. checkAllStageList();
  576. }
  577.  
  578. var ioCfg = document.createElement("input");btnBox2.appendChild(ioCfg);
  579. ioCfg.type = "button";
  580. ioCfg.id = chkUpt.className = "input-output-config";
  581. ioCfg.value = "导入/导出设置&地下城列表";
  582. ioCfg.onclick = function(){
  583. var dlg = ioConfigDialog();
  584. form.parentElement.appendChild(dlg);
  585. dlg.classList.remove("display-none");
  586. dlg.configText.value = formatJson(config);
  587. dlg.stageListText.value = formatJson(stageList);
  588. };
  589.  
  590. //收藏按钮
  591. var stage0 = form.querySelector("[name=column1]");
  592. var stage1 = form.querySelector("#stage");
  593. var stage2 = form.querySelector("#stage2"); stage2.onchange = null;
  594. var starStg = document.createElement("input");form.insertBefore(starStg,stage2.nextSibling);
  595. starStg.type = "button";
  596. starStg.id = starStg.className = "star-stage";
  597. starStg.value = "⭐️";
  598. starStg.onclick = function(){
  599. addStarStage(stage1.value);
  600. };
  601.  
  602. var infoBox = document.createElement("div");box.appendChild(infoBox);
  603. infoBox.id = infoBox.className = "info-box";
  604. refresTypeList();
  605. refreshStageList1(0); //先刷新地下城吧
  606. refreshMessageList(); //刷新文本列表
  607. }
  608. function checkTodayUpdate(callback)
  609. {
  610. log("开始检查今日地下城");
  611. GM_xmlhttpRequest({
  612. method: "GET",
  613. url: "desktop/", //主页
  614. onload: dealMainPage,
  615. onerror: function(response) {
  616. log("获取主页地下城活动失败");
  617. console.error("获取主页地下城活动失败",response);
  618. }
  619. });
  620.  
  621. function dealMainPage(response)
  622. {
  623. var PageDOM = new DOMParser().parseFromString(response.responseText, "text/html");
  624. //紧急活动地下城表格
  625. var JinJiEvent = PageDOM.querySelector("#container>.item:nth-of-type(1)>table:nth-of-type(2)");
  626. //今天的降临
  627. if (JinJiEvent.rows[2] == undefined || JinJiEvent.rows[2].cells[1] == undefined) {alert("?未发现今日数据,是不是主页格式有问题?"); return;}
  628. config.todayStage.length = 0; //先清空
  629.  
  630. var JiangLin = JinJiEvent.rows[2].cells[1].getElementsByTagName("a");
  631. var stgs1 = {name:"每日降临",detail:"每天都会更换一次的降临神,保持24小时。",stages:[]};
  632. for (var ai=0;ai<JiangLin.length;ai++)
  633. {
  634. var link = JiangLin[ai];
  635. if (new RegExp(stageTestReg,"igm").test(link.getAttribute("href")) && stgs1.stages.indexOf(link.title)<0)
  636. {
  637. stgs1.stages.push(link.title);
  638. }
  639. }
  640. config.todayStage.push(stgs1);
  641. //今天的紧急
  642. var stgs2 = {name:"紧急降临",detail:"每天分组出现的紧急本,每个组一小时。",stages:[]};
  643. for (var ri=1;ri<JinJiEvent.rows[2].cells[0].rowSpan;ri++)
  644. {
  645. var link = JinJiEvent.rows[2+ri].cells[0].querySelector("a");
  646. if (new RegExp(stageTestReg,"igm").test(link.getAttribute("href")) && stgs2.stages.indexOf(link.title)<0)
  647. {
  648. stgs2.stages.push(link.title);
  649. }
  650. }
  651. config.todayStage.push(stgs2);
  652. //长期活动地下城表格
  653. //第一行周回本
  654. var ChangQiEvent = PageDOM.querySelector("#container>.item:nth-of-type(2)>table:nth-of-type(2)");
  655. var stgs3 = {name:"耀日本",detail:"每周分星期几固定出现的本",stages:[]};
  656. var imgs = ChangQiEvent.rows[1].getElementsByTagName("img");
  657. for (var ii=0;ii<imgs.length;ii++)
  658. {
  659. var link = imgs[ii].parentElement;
  660. if (new RegExp(stageTestReg,"igm").test(link.getAttribute("href")) //是场景
  661. && stgs3.stages.indexOf(link.title)<0
  662. )
  663. {
  664. stgs3.stages.push(link.title);
  665. }
  666. }
  667. config.todayStage.push(stgs3);
  668.  
  669. //后面的活动
  670. var stgs4 = {name:"长期活动",detail:"各种活动的本",stages:[]};
  671. for (var ri=4;ri<ChangQiEvent.rows.length;ri++)
  672. {
  673. var imgs = ChangQiEvent.rows[ri].getElementsByTagName("img");
  674. var typeStr = ""; //储存地下城类型说明
  675. var typeSpan = ChangQiEvent.rows[ri].cells[2].querySelector("span");
  676. if (typeSpan != undefined)
  677. {
  678. typeStr = typeSpan.textContent;
  679. }
  680. var endTime = "";
  681. var endTimeTd = ChangQiEvent.rows[ri].cells[3];
  682. if (endTimeTd != undefined)
  683. {
  684. endTime = endTimeTd.childNodes[1].nodeValue;
  685. }
  686. for (var ii=0;ii<imgs.length;ii++)
  687. {
  688. var link = imgs[ii].parentElement;
  689. if (new RegExp(stageTestReg,"igm").test(link.getAttribute("href")) //是场景
  690. && !/coin\.png/igm.test(imgs[ii].getAttribute("src")) //不是金币地下城
  691. && !/一次通關限定/igm.test(typeStr) //不是一次通关限定
  692. && !/排名地下城/igm.test(typeStr) //不是排名地下城
  693. && !/每天一場/igm.test(typeStr) //不是每天一场限定
  694. && !/後開始/igm.test(endTime) //不是还没有开始的
  695. && stgs4.stages.indexOf(link.title)<0
  696. )
  697. {
  698. var realName = link.title.replace(/【.*】/igm,"");
  699. console.log(link.title,realName);
  700. stgs4.stages.push(realName);
  701. }
  702. }
  703. }
  704. config.todayStage.push(stgs4);
  705.  
  706. config.updateDate = getLocalTime(9).getTime();
  707. log("今日有" + config.todayStage.reduce(function(previous, current){return previous + current.stages.length},0) + "个地下城");
  708. //console.log("今日地下城获取完毕",config);
  709. callback();
  710. }
  711. }
  712. //关卡大家都有的部分,类
  713. function minStage(name,iconUrl)
  714. {
  715. this.name = name;
  716. this.iconUrl = iconUrl;
  717. }
  718. //单个难度地下城关卡,类
  719. function Stage(name,iconUrl,stamina,battles)
  720. {
  721. var obj = new minStage(name,iconUrl);
  722. obj.stamina = stamina; //体力
  723. obj.battles = battles; //层数
  724. return obj;
  725. }
  726. //多个难度的地下城关卡,类
  727. function mainStage(name,iconUrl)
  728. {
  729. var obj = new minStage(name,iconUrl);
  730. obj.name = name;
  731. obj.iconUrl = iconUrl;
  732. obj.subStage = [];
  733. obj.checkSubStage = function(callback)
  734. {
  735. GM_xmlhttpRequest({
  736. method: "GET",
  737. url: "stage/" + this.name,
  738. onload: function(response){ //获取成功
  739. var PageDOM = new DOMParser().parseFromString(response.responseText, "text/html");
  740. var subStageList = PageDOM.querySelector("#wrapper>table:nth-of-type(3) ul"); //子关卡的列表ul
  741. if (subStageList == undefined) //如果没找到,试试手机版
  742. {
  743. subStageList = document.querySelector(".content>ul");
  744. if (subStageList!=undefined)
  745. {
  746. mobile = true;
  747. }else
  748. {
  749. alert("? " + name + " 页面未找到關卡資料");
  750. }
  751. }
  752.  
  753. var subStage = subStageList.getElementsByTagName("li"); //所有的li
  754.  
  755. obj.subStage.length = 0; //去掉所有的旧数据
  756. for (var si=0;si<subStage.length;si++)
  757. {
  758. var link = subStage[si].querySelector("div a"); //图标链接
  759. var iconUrl = link.querySelector("img").getAttribute("data-original");
  760. var detailTd = subStage[si].querySelector("div:nth-of-type(2)"); //介绍格
  761. if (detailTd == undefined)
  762. { //目前不知道到底是谁错了
  763. console.error("没有介绍格",subStage[si]);
  764. }
  765. var name = detailTd.querySelector("a").textContent.replace(/\s*關卡資料.*$/igm,"");
  766. var stamina = 0;var battles = 0;
  767. for (var ci=0;ci<detailTd.childNodes.length;ci++)
  768. {
  769. var cld = detailTd.childNodes[ci];
  770. if (cld.nodeName == "SPAN" && /體力/igm.test(cld.previousSibling.nodeValue))
  771. var stamina = parseInt(cld.textContent);
  772. if (cld.nodeName == "SPAN" && /層數/igm.test(cld.previousSibling.nodeValue))
  773. var battles = parseInt(cld.textContent);
  774. }
  775. var stage = new Stage(name,iconUrl,stamina,battles);
  776. obj.subStage.push(stage);
  777. }
  778. callback();
  779. },
  780. onerror: function(response) {
  781. log("获取 " + obj.name + " 详情失败");
  782. console.error("获取 " + obj.name + " 详情失败",response);
  783. },
  784. });
  785. }
  786. return obj;
  787. }
  788. function checkAllStageList(resetAll = false)
  789. {
  790. GM_xmlhttpRequest({
  791. method: "GET",
  792. url: "stage",
  793. onload: dealStageList,
  794. onerror: function(response) {
  795. log("获取全部地下城列表失败");
  796. console.error("获取全部地下城列表失败",response);
  797. },
  798. });
  799.  
  800. function dealStageList(response)
  801. {
  802. var PageDOM = new DOMParser().parseFromString(response.responseText, "text/html");
  803. if (resetAll) stageList.length = 0; //先清空
  804. //所有地下城表格
  805. var stageTd = PageDOM.querySelector("#wrapper>table:nth-of-type(3) td");
  806. if (stageTd == undefined) //如果没找到,试试手机版
  807. {
  808. stageTd = document.querySelector(".content");
  809. if (stageTd!=undefined)
  810. {
  811. mobile = true;
  812. }else
  813. {
  814. alert("?未找到地下城列表");
  815. }
  816. }
  817. var stages = stageTd.getElementsByClassName("tooltip"); //获取所有的链接
  818. if(mobile)
  819. {
  820. stages = stageTd.getElementsByTagName("a"); //获取所有的链接
  821. }
  822.  
  823.  
  824. //检查是否已经存在,否则添加新的
  825. function checkExistAdd(newStage,resetAll = false)
  826. {
  827. var oldStage = stageList.filter(function(item){ //查找以前有没有这个地图
  828. return item.name == newStage.name;
  829. })[0];
  830. if (resetAll || oldStage == undefined)
  831. { //没有就添加新的
  832. newStages.push(newStage);
  833. }else
  834. { //有的话就什么也不改变
  835. //oldStage.name = newStage.name;
  836. //oldStage.iconUrl = newStage.iconUrl;
  837. }
  838. }
  839.  
  840. var newStages = [];
  841. //所有地下城
  842. for (var si=1,si_l=stages.length;si<si_l;si++)
  843. {
  844. var link = stages[si];
  845. if (new RegExp(stageTestReg,"igm").test(link.getAttribute("href")))
  846. {
  847. var img= link.querySelector("img");
  848. imgUrl = img.getAttribute("data-original");
  849. checkExistAdd(new mainStage(mobile?img.alt:link.title,imgUrl),resetAll);
  850. }
  851. }
  852. //▼添加暂时没有的特殊图
  853. //checkExistAdd(new mainStage("闇の戦武龍","http://i1296.photobucket.com/albums/ag18/skyozora/pets_icon/3839_zpsinupxf0j.png"),resetAll);
  854. //▲添加暂时没有的特殊图
  855.  
  856. //var stageArr = stageList.slice(398,400); //debug用
  857. getStageDetail(newStages,newStages.length,function(){
  858. stageList = stageList.concat(newStages);
  859. log("所有地下城获取完毕");
  860. //console.log("所有地下城获取完毕",config);
  861. saveConfig(2);
  862. });
  863. }
  864. function getStageDetail(stgArr,max,callback)
  865. {
  866. if (stgArr.length < 1)
  867. {
  868. callback();
  869. return;
  870. }
  871. var newStgArr = stgArr.concat();
  872. var thisStg = newStgArr.shift(); //删除新数组的第一个元素
  873.  
  874. thisStg.checkSubStage(function(){
  875. log("已获取" + (max-newStgArr.length) + "/" + max);
  876. console.log("已获取" + (max-newStgArr.length) + "/" + max);
  877. getStageDetail(newStgArr,max,callback);
  878. });
  879. }
  880. }
  881.  
  882. /*
  883. * 协力列表页面
  884. *
  885. */
  886. function multiplayPage()
  887. {
  888. var table = document.querySelector("#wrapper>table:nth-of-type(3) table"); //协力请求表格
  889. if (table == undefined) //如果没找到,试试手机版
  890. {
  891. table = document.querySelector(".content>table");
  892. if (table!=undefined)
  893. {
  894. mobile = true;
  895. }else
  896. {
  897. alert("?未找到协力列表");
  898. }
  899. }
  900. var cellMaxLength = 0;
  901. for (var ci=0;ci<table.rows[0].cells.length;ci++)
  902. {
  903. cellMaxLength += table.rows[0].cells[ci].colSpan; //计算宽度
  904. }
  905. for (var ri=table.rows.length-1;ri>0;ri--)
  906. {
  907. if (table.rows[ri].cells[0].colSpan >= cellMaxLength)
  908. {
  909. table.rows[ri].remove(); //去除广告
  910. }
  911. }
  912. if (!mobile) table.rows[0].cells[0].colSpan += 1; //标题添加一格合并
  913. for (var ri=(mobile?0:1);ri<table.rows.length;(mobile?ri+=nextRow+1:ri++))
  914. {
  915. var stageNameCell = table.rows[ri].cells[1]; //获取名字的格
  916. if (mobile)
  917. {
  918. var nextRow = table.rows[ri].cells[0].rowSpan++; //增加一跨行
  919. var newRow = table.insertRow(ri+nextRow);
  920. newRow.bgColor = table.rows[ri].bgColor;
  921. var newCell = newRow.insertCell(0); //添加新格
  922. }else
  923. {
  924. var newCell = table.rows[ri].insertCell(2); //添加新格
  925. }
  926.  
  927. var link1 = stageNameCell.querySelector("a");
  928. var link2 = stageNameCell.querySelector("a:nth-of-type(2)");
  929. var stage1 = stageList.filter(function(item){
  930. return item.name == link1.textContent;
  931. })[0];
  932. if (stage1 == undefined) //如果发现没有数据的图,跳过
  933. {
  934. console.error("没有主关卡数据",link1.textContent)
  935. continue;
  936. }
  937. var stage2 = stage1.subStage.filter(function(item){
  938. return item.name == link2.textContent;
  939. })[0];
  940. if (stage2 == undefined) //如果发现没有数据的图,跳过
  941. {
  942. console.error("没有子关卡数据",link2.textContent)
  943. continue;
  944. }
  945. //newCell.appendChild(document.createTextNode(stage2.stamina + "体"));
  946. //newCell.appendChild(document.createElement("br"));
  947. newCell.appendChild(document.createTextNode("协力" + Math.round(stage2.stamina/2) + "体"));
  948. if (!mobile) newCell.appendChild(document.createElement("br")); else newCell.appendChild(document.createTextNode(","));
  949. newCell.appendChild(document.createTextNode(stage2.battles + "层"));
  950. }
  951. }
  952.  
  953.  
  954. function ioConfigDialog()
  955. {
  956. var box = document.querySelector("#io-config-dialog");
  957. if (box != undefined) return box;
  958.  
  959. var box = document.createElement("div");
  960. box.id = box.className = "io-config-dialog";
  961. box.className = "display-none";
  962.  
  963. var txtBox = document.createElement("div");box.appendChild(txtBox);
  964. txtBox.className = "text-box";
  965. var divConfig = document.createElement("div");txtBox.appendChild(divConfig);
  966. divConfig.className = "text-lbl-box";
  967. var lblConfig = document.createElement("label");divConfig.appendChild(lblConfig);
  968. lblConfig.appendChild(document.createTextNode("设置:"));
  969. lblConfig.appendChild(document.createElement("br"));
  970. var txtConfig = document.createElement("textarea");lblConfig.appendChild(txtConfig);
  971. txtConfig.id = txtConfig.className = "text-config";
  972. txtConfig.value = "";
  973. box.configText = txtConfig;
  974.  
  975. var divStageList = document.createElement("div");txtBox.appendChild(divStageList);
  976. divStageList.className = "text-lbl-box";
  977. var lblStageList = document.createElement("label");divStageList.appendChild(lblStageList);
  978. lblStageList.appendChild(document.createTextNode("地下城列表:"));
  979. lblStageList.appendChild(document.createElement("br"));
  980. var txtStageList = document.createElement("textarea");lblStageList.appendChild(txtStageList);
  981. txtStageList.id = txtStageList.className = "text-stage-list";
  982. txtStageList.value = "";
  983. box.stageListText = txtStageList;
  984.  
  985. var btnBox = document.createElement("div");box.appendChild(btnBox);
  986. btnBox.className = "botton-box";
  987. var btnIpt = document.createElement("input");btnBox.appendChild(btnIpt);
  988. btnIpt.type = "button";
  989. btnIpt.id = btnIpt.className = "input-config";
  990. btnIpt.value = "导入设置";
  991. btnIpt.onclick = function(){
  992. var bk = loadConfig(txtConfig.value,txtStageList.value,true);
  993. if (bk[0] && bk[1])
  994. {
  995. saveConfig();
  996. alert("?导入成功");
  997. }else
  998. {
  999. if(!bk[0])alert("?该设置信息格式不正确");
  1000. if(!bk[1])alert("?该地下城列表信息格式不正确");
  1001. }
  1002. }
  1003.  
  1004. var btnCls = document.createElement("input");btnBox.appendChild(btnCls);
  1005. btnCls.type = "button";
  1006. btnCls.id = btnCls.className = "close-dialog";
  1007. btnCls.value = "关闭";
  1008. btnCls.onclick = function(){box.classList.add("display-none");}
  1009.  
  1010. return box;
  1011. }