// ==UserScript== // @name 咕咕镇数据采集 // @namespace https://greasyfork.org/users/448113 // @version 1.4.14 // @description 咕咕镇数据采集,目前采集已关闭,兼作助手 // @author paraii // @match https://www.guguzhen.com/* // @grant GM_xmlhttpRequest // @connect www.guguzhen.com // @run-at document-body // @license MIT License // @downloadURL none // ==/UserScript== // @connect notes.orga.cat // @require https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js // @require https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/js/tooltip.js // @require https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/js/popover.js (function() { 'use strict' //////////////////////////////////////////////////////////////////////////////////////////////////// // // common utilities // //////////////////////////////////////////////////////////////////////////////////////////////////// const g_modificationVersion = '2022-06-03 02:00:00'; const g_kfUser = document.getElementsByClassName('icon-user')[0].parentNode.innerText.split(' ')[1]; const g_autoTaskEnabledStorageKey = g_kfUser + '_autoTaskEnabled'; const g_keepPkRecordStorageKey = g_kfUser + '_keepPkRecord'; const g_amuletGroupsStorageKey = g_kfUser + '_amulet_groups'; const g_equipmentExpandStorageKey = g_kfUser + '_equipment_Expand'; const g_equipmentBGStorageKey = g_kfUser + '_equipment_BG'; const g_beachIgnoreStoreMysEquipStorageKey = g_kfUser + '_beach_ignoreStoreMysEquip'; const g_beachForceExpandStorageKey = g_kfUser + '_beach_forceExpand'; const g_beachBGStorageKey = g_kfUser + '_beach_BG'; const g_userDataStorageKeyConfig = [ g_kfUser, g_autoTaskEnabledStorageKey, g_keepPkRecordStorageKey, g_amuletGroupsStorageKey, g_equipmentExpandStorageKey, g_equipmentBGStorageKey, g_beachIgnoreStoreMysEquipStorageKey, g_beachForceExpandStorageKey, g_beachBGStorageKey ]; const g_userDataStorageKeyExtra = [ 'attribute', 'cardName', 'title', 'over', 'halo_max', 'beachcheck', 'dataReward', 'keepcheck' ]; const USER_STORAGE_RESERVED_SEPARATORS = /[:;,|=+*%!#$&?<>{}^`"\\\/\[\]\r\n\t\v\s]/; const USER_STORAGE_KEY_VALUE_SEPARATOR = ':'; console.log(g_kfUser) // perform a binary search. array must be sorted, but no matter in ascending or descending order. // in this manner, you must pass in a proper comparer function for it works properly, aka, if the // array was sorted in ascending order, then the comparer(a, b) should return a negative value // while a < b or a positive value while a > b; otherwise, if the array was sorted in descending // order, then the comparer(a, b) should return a positive value while a < b or a negative value // while a > b, and in both, if a equals b, the comparer(a, b) should return 0. if you pass nothing // or null / undefined value as comparer, then you must make sure about that the array was sorted // in ascending order. // // in this particular case, we just want to check whether the array contains the value or not, we // don't even need to point out the first place where the value appears (if the array actually // contains the value), so we perform a simplest binary search and return an index (may not the // first place where the value appears) or a negative value (means value not found) to indicate // the search result. function searchElement(array, value, fnComparer) { if (array?.length > 0) { fnComparer ??= ((a, b) => a < b ? -1 : (a > b ? 1 : 0)); let li = 0; let hi = array.length - 1; while (li <= hi) { let mi = ((li + hi) >> 1); let cr = fnComparer(value, array[mi]); if (cr == 0) { return mi; } else if (cr > 0) { li = mi + 1; } else { hi = mi - 1; } } } return -1; } // perform a binary insertion. the array and comparer must exactly satisfy as it in the searchElement // function. this operation behaves sort-stable, aka, the newer inserting element will be inserted // into the position after any existed equivalent elements. function insertElement(array, value, fnComparer) { if (array != null) { fnComparer ??= ((a, b) => a < b ? -1 : (a > b ? 1 : 0)); let li = 0; let hi = array.length - 1; while (li <= hi) { let mi = ((li + hi) >> 1); let cr = fnComparer(value, array[mi]); if (cr >= 0) { li = mi + 1; } else { hi = mi - 1; } } array.splice(li, 0, value); return li; } return -1; } // it's not necessary to have newArray been sorted, but the oldArray must be sorted since we are calling // searchElement. if there are some values should be ignored in newArray, the comparer(a, b) should be // implemented as return 0 whenever parameter a equals any of values that should be ignored. function findNewObjects(newArray, oldArray, fnComparer, findIndices) { // just in case, i discovered that sometimes if we use array.length directly in for(...) statement // (either some other statements too), the statement get chances to be executed incorrectly (or just // console.log can be effected?), don't know why, but we can use a temporary variable to handle this. let newObjects = []; let nl = (newArray?.length ?? 0); for (let i = 0; i < nl; i++) { if (searchElement(oldArray, newArray[i], fnComparer) < 0) { newObjects.push(findIndices ? i : newArray[i]); } } return newObjects; } // HTTP requests var g_httpRequests = []; function httpRequestRegister(request) { if (request != null) { g_httpRequests.push(request); } } function httpRequestAbortAll() { while (g_httpRequests.length > 0) { g_httpRequests.pop().abort(); } g_httpRequests = []; } function httpRequestClearAll() { g_httpRequests = []; } function objectIdParseNodes(nodes, ids, ignoreEmptyCell) { for (let node of nodes) { if (node.className?.endsWith("fyg_mp3")) { let id = node.getAttribute('onclick')?.match(/\d+/)[0]; if (id != undefined) { ids.push(id); } else if (!ignoreEmptyCell) { ids.push(-1); } } } } const g_postMethod = 'POST' const g_readUrl = 'https://www.guguzhen.com/fyg_read.php' const g_postUrl = 'https://www.guguzhen.com/fyg_click.php' const g_postHeader = { 'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8' , 'Cookie' : document.cookie }; const g_networkTimeoutMS = 120 * 1000; function beginReadObjects(bagIds, storeIds, ignoreEmptyCell, fnFurtherProcess, fnParams) { if (bagIds != null || storeIds != null) { let request = GM_xmlhttpRequest({ method: g_postMethod, url: g_readUrl, headers: g_postHeader, data: 'f=7', onload: response => { let div = document.createElement('div'); div.innerHTML = response.responseText; if (bagIds != null) { objectIdParseNodes(div.children[0].children[1].children, bagIds, ignoreEmptyCell); } if (storeIds != null) { objectIdParseNodes(div.children[1].children[1].children, storeIds, ignoreEmptyCell); } if (fnFurtherProcess != null) { fnFurtherProcess(fnParams); } } }); httpRequestRegister(request); } else if (fnFurtherProcess != null) { fnFurtherProcess(fnParams); } } // we wait the response(s) of the previous batch of request(s) to send another batch of request(s) // rather than simply send them all within an inside foreach - which could cause too many requests // to server simultaneously, that can be easily treated as D.D.O.S attack and therefor leads server // to returns http status 503: Service Temporarily Unavailable // * caution * the parameter 'objects' is required been sorted by their indices in ascending order const g_defaultConcurrentRequestsCount = { min : 1 , max : 8 , default : 4 }; var g_maxConcurrentRequestsCount = g_defaultConcurrentRequestsCount.default; var g_objectMoveRequestsCount = 0; var g_objectMoveTargetSiteFull = false; var g_func_puti_data = null; var g_func_puto_data = null; function beginMoveObjects(objects, bagToStore, fnFurtherProcess, fnParams) { if (!g_objectMoveTargetSiteFull && objects?.length > 0) { g_func_puti_data ??= getPostData(/puti\(id\)\{[\s\S]*\}/m, /data: ".*\+id\+.*"/).slice(7, -1); g_func_puto_data ??= getPostData(/puto\(id\)\{[\s\S]*\}/m, /data: ".*\+id\+.*"/).slice(7, -1); let ids = []; while (ids.length < g_maxConcurrentRequestsCount && objects.length > 0) { let id = objects.pop(); if (id >= 0) { ids.push(id); } } if ((g_objectMoveRequestsCount = ids.length) > 0) { while (ids.length > 0) { let request = GM_xmlhttpRequest({ method: g_postMethod, url: g_postUrl, headers: g_postHeader, data: (bagToStore ? g_func_puti_data : g_func_puto_data).replace('"+id+"', ids.shift()), onload: response => { if (response.responseText != 'ok') { g_objectMoveTargetSiteFull = true; console.log(response.responseText); } if (--g_objectMoveRequestsCount == 0) { beginMoveObjects(objects, bagToStore, fnFurtherProcess, fnParams); } } }); httpRequestRegister(request); } return; } } g_objectMoveTargetSiteFull = false; if (fnFurtherProcess != null) { fnFurtherProcess(fnParams); } } // read currently mounted role card and halo informations // roleInfo = [ roleId, roleName ] // haloInfo = [ haloPoints, haloSlots, [ haloItem1, haloItem2, … ] ] function beginReadRoleAndHalo(roleInfo, haloInfo, fnFurtherProcess, fnParams) { let asyncOperations = 0; let error = 0; let requestRole; let requestHalo; if (roleInfo != null) { asyncOperations++; requestRole = GM_xmlhttpRequest({ method: g_postMethod, url: g_readUrl, headers: g_postHeader, data: 'f=9', onload: response => { let div = document.createElement('div'); div.innerHTML = response.responseText; let role = g_roleMap.get(div.querySelector('div.text-info.fyg_f24.fyg_lh60')?.children[0]?.innerText); if (role != undefined) { roleInfo.push(role.id); roleInfo.push(role.name); } asyncOperations--; }, onerror : err => { error++; asyncOperations--; }, ontimeout : err => { error++; asyncOperations--; } }); } if (haloInfo != null) { asyncOperations++; requestHalo = GM_xmlhttpRequest({ method: g_postMethod, url: g_readUrl, headers: g_postHeader, data: 'f=5', onload: response => { let haloPS = response.responseText.match(/
]*>([^<]+)<[^>]*>\+(\d+)[^<]*<\/span><\/p>/g; while ((attr = regex.exec(content))?.length == 3) { this.buffCode += ((100 ** (g_amuletBuffTypeOrders.get(attr[1]) % 6)) * attr[2]); this.text += `${this.text.length > 0 ? ', ' : ''}${attr[1]} +${attr[2]} ${g_amuletBuffUnits[this.type]}`; } if (this.isValid()) { return this; } } } this.reset(); return null; }); this.fromAmulet = ((amulet) => { if (amulet?.isValid()) { this.id = amulet.id; this.type = amulet.type; this.level = amulet.level; this.enhancement = amulet.enhancement; this.buffCode = amulet.buffCode; this.text = amulet.text; } else { this.reset(); } return (this.isValid() ? this : null); }); this.getCode = (() => { if (this.isValid()) { return (this.type * AMULET_TYPE_ID_FACTOR + this.level * AMULET_LEVEL_ID_FACTOR + this.enhancement * AMULET_ENHANCEMENT_FACTOR + this.buffCode); } return -1; }); this.getBuff = (() => { let buffs = {}; if (this.isValid()) { let type = this.type * 6; for (let buff of g_amuletBuffTypeNames.slice(type, type + 6)) { let v = Math.trunc(this.buffCode / (100 ** (g_amuletBuffTypeOrders.get(buff) % 6))) % 100; if (v > 0) { buffs[buff] = v; } } } return buffs; }); this.formatName = (() => { if (this.isValid()) { return `${g_amuletLevelNames[this.level]}${g_amuletTypeNames[this.type]} (+${this.enhancement})`; } return null; }); this.formatBuff = (() => { if (this.isValid()) { if (this.text?.length > 0) { return this.text; } this.text = ''; let buffs = this.getBuff(); for (let buff in buffs) { this.text += `${this.text.length > 0 ? ', ' : ''}${buff} +${buffs[buff]} ${g_amuletBuffUnits[this.type]}`; } } return this.text; }); this.formatBuffText = (() => { if (this.isValid()) { return this.formatName() + ' = ' + this.formatBuff(); } return null; }); this.formatShortMark = (() => { let text = this.formatBuff()?.replaceAll(/(\+)|( 点)|( %)/g, ''); if (text?.length > 0) { for (let buff in this.getBuff()) { text = text.replaceAll(buff, g_amuletBuffShortMarks[g_amuletBuffTypeOrders.get(buff)]); } return this.formatName() + ' = ' + text; } return null; }); this.compareTo = ((other, ascType) => { if (!this.isValid()) { return 1; } else if (!other?.isValid()) { return -1; } else if (this.id >= 0 && this.id == other.id) { return 0; } let delta = other.type - this.type; if (delta != 0) { return (ascType ? -delta : delta); } let tbuffs = this.formatBuffText().split(' = ')[1].replaceAll(/(\+)|( 点)|( %)/g, '').split(', '); let obuffs = other.formatBuffText().split(' = ')[1].replaceAll(/(\+)|( 点)|( %)/g, '').split(', '); let bl = Math.min(tbuffs.length, obuffs.length); for (let i = 0; i < bl; i++) { let tbuff = tbuffs[i].split(' '); let obuff = obuffs[i].split(' '); if ((delta = g_amuletBuffTypeOrders.get(tbuff[0]) - g_amuletBuffTypeOrders.get(obuff[0])) != 0 || (delta = parseInt(obuff[1]) - parseInt(tbuff[1])) != 0) { return delta; } } if ((delta = obuffs.length - tbuffs.length) != 0 || (delta = other.level - this.level) != 0 || (delta = other.enhancement - this.enhancement) != 0) { return delta; } return 0; }); } function AmuletGroup(persistenceString) { this.buffSummary = { 力量 : 0, 敏捷 : 0, 智力 : 0, 体魄 : 0, 精神 : 0, 意志 : 0, 物理攻击 : 0, 魔法攻击 : 0, 速度 : 0, 生命护盾回复效果 : 0, 最大生命值 : 0, 最大护盾值 : 0, 固定生命偷取 : 0, 固定反伤 : 0, 固定暴击几率 : 0, 固定技能几率 : 0, 物理防御效果 : 0, 魔法防御效果 : 0 }; this.name = null; this.items = []; this.isValid = (() => { return (this.items.length > 0 && amuletIsValidGroupName(this.name)); }); this.count = (() => { return this.items.length; }); this.clear = (() => { this.items = []; for (let buff in this.buffSummary) { this.buffSummary[buff] = 0; } }); this.add = ((amulet) => { if (amulet?.isValid()) { let buffs = amulet.getBuff(); for (let buff in buffs) { this.buffSummary[buff] += buffs[buff]; } return insertElement(this.items, amulet, (a, b) => a.compareTo(b, true)); } return -1; }); this.remove = ((amulet) => { if (this.isValid() && amulet?.isValid()) { let i = searchElement(this.items, amulet, (a, b) => a.compareTo(b, true)); if (i >= 0) { let buffs = amulet.getBuff(); for (let buff in buffs) { this.buffSummary[buff] -= buffs[buff]; } this.items.splice(i, 1); return true; } } return false; }); this.removeId = ((id) => { if (this.isValid()) { let i = this.items.findIndex((a) => a.id == id); if (i >= 0) { let amulet = this.items[i]; let buffs = amulet.getBuff(); for (let buff in buffs) { this.buffSummary[buff] -= buffs[buff]; } this.items.splice(i, 1); return amulet; } } return null; }); this.validate = ((amulets) => { if (this.isValid()) { let mismatch = 0; let al = this.items.length; let i = 0; if (amulets?.length > 0) { amulets = amulets.slice().sort((a, b) => a.type != b.type ? a.type - b.type : a.buffCode - b.buffCode); for ( ; amulets.length > 0 && i < al; i++) { let mi = searchElement(amulets, this.items[i], (a, b) => a.type != b.type ? a.type - b.type : a.buffCode - b.buffCode); if (mi >= 0) { // remove a matched amulet from the amulet pool can avoid one single amulet matches all // the equivalent objects in the group. // let's say two (or even more) AGI +5 apples in one group is fairly normal, if we just // have only one equivalent apple in the amulet pool and we don't remove it when the // first match happens, then the 2nd apple will get matched later, the consequence would // be we can never find the mismatch which should be encountered at the 2nd apple this.items[i].fromAmulet(amulets[mi]); amulets.splice(mi, 1); } else { mismatch++; } } } if (i > mismatch) { this.items.sort((a, b) => a.compareTo(b, true)); } if (i < al) { mismatch += (al - i); } return (mismatch == 0); } return false; }); this.findIndices = ((amulets) => { let indices; let al; if (this.isValid() && (al = (amulets?.length ?? 0)) > 0) { let items = this.items.slice().sort((a, b) => a.type != b.type ? a.type - b.type : a.buffCode - b.buffCode); for (let i = 0; items.length > 0 && i < al; i++) { let mi; if (amulets[i]?.id >= 0 && (mi = searchElement(items, amulets[i], (a, b) => a.type != b.type ? a.type - b.type : a.buffCode - b.buffCode)) >= 0) { // similar to the 'validate', remove the amulet from the search list when we found // a match item in first time to avoid the duplicate founding, e.g. say we need only // one AGI +5 apple in current group and we actually have 10 of AGI +5 apples in store, // if we found the first matched itme in store and record it's index but not remove it // from the temporary searching list, then we will continuously reach this kind of // founding and recording until all those 10 AGI +5 apples are matched and processed, // this obviously ain't the result what we expected (indices ??= []).push(i); items.splice(mi, 1); } } } return indices; }); this.parse = ((persistenceString) => { this.clear(); if (persistenceString?.length > 0) { let elements = persistenceString.split(AMULET_STORAGE_GROUPNAME_SEPARATOR); if (elements.length == 2) { let name = elements[0].trim(); if (amuletIsValidGroupName(name)) { let items = elements[1].split(AMULET_STORAGE_AMULET_SEPARATOR); let il = items.length; for (let i = 0; i < il; i++) { if (this.add((new Amulet()).fromCode(parseInt(items[i]))) < 0) { this.clear(); break; } } if (this.count() > 0) { this.name = name; } } } } return (this.count() > 0); }); this.formatBuffSummary = ((linePrefix, lineSuffix, lineSeparator) => { if (this.isValid()) { let str = ''; let nl = ''; for (let buff of g_amuletBuffTypeNames) { let v = this.buffSummary[buff]; if (v > 0) { str += `${nl}${linePrefix}${buff} +${v} ${g_amuletBuffUnits[Math.trunc(g_amuletBuffTypeOrders.get(buff) / 6)]}${lineSuffix}`; nl = lineSeparator; } } return str; } return ''; }); this.formatItems = ((linePrefix, erroeLinePrefix, lineSuffix, errorLineSuffix, lineSeparator) => { if (this.isValid()) { let str = ''; let nl = ''; for (let amulet of this.items) { str += `${nl}${amulet.id < 0 ? erroeLinePrefix : linePrefix}${amulet.formatBuffText()}` + `${amulet.id < 0 ? errorLineSuffix : lineSuffix}`; nl = lineSeparator; } return str; } return ''; }); this.getDisplayStringLineCount = (() => { if (this.isValid()) { let lines = 0; for (let buff of g_amuletBuffTypeNames) { if (this.buffSummary[buff] > 0) { lines++; } } return lines + this.items.length; } return 0; }); this.formatPersistenceString = (() => { if (this.isValid()) { let codes = []; for (let amulet of this.items) { codes.push(amulet.getCode()); } return `${this.name}${AMULET_STORAGE_GROUPNAME_SEPARATOR}${codes.join(AMULET_STORAGE_AMULET_SEPARATOR)}`; } return ''; }); this.parse(persistenceString); } function AmuletGroupCollection(persistenceString) { this.items = {}; this.itemCount = 0; this.count = (() => { return this.itemCount; }); this.contains = ((name) => { return (this.items[name] != undefined); }); this.add = ((item) => { if (item?.isValid()) { if (!this.contains(item.name)) { this.itemCount++; } this.items[item.name] = item; return true; } return false; }); this.remove = ((name) => { if (this.contains(name)) { delete this.items[name]; this.itemCount--; return true; } return false; }); this.clear = (() => { for (let name in this.items) { delete this.items[name]; } this.itemCount = 0; }); this.get = ((name) => { return this.items[name]; }); this.rename = ((oldName, newName) => { if (amuletIsValidGroupName(newName)) { let group = this.items[oldName]; if (this.remove(oldName)) { group.name = newName; return this.add(group); } } return false; }); this.toArray = (() => { let groups = []; for (let name in this.items) { groups.push(this.items[name]); } return groups; }); this.parse = ((persistenceString) => { this.clear(); if (persistenceString?.length > 0) { let groupStrings = persistenceString.split(AMULET_STORAGE_GROUP_SEPARATOR); let gl = groupStrings.length; for (let i = 0; i < gl; i++) { if (!this.add(new AmuletGroup(groupStrings[i]))) { this.clear(); break; } } } return (this.count() > 0); }); this.formatPersistenceString = (() => { let str = ''; let ns = ''; for (let name in this.items) { str += (ns + this.items[name].formatPersistenceString()); ns = AMULET_STORAGE_GROUP_SEPARATOR; } return str; }); this.parse(persistenceString); } function amuletIsValidGroupName(groupName) { return (groupName?.length > 0 && groupName.length < 32 && groupName.search(USER_STORAGE_RESERVED_SEPARATORS) < 0); } function amuletSaveGroups(groups) { if (groups?.count() > 0) { localStorage.setItem(g_amuletGroupsStorageKey, groups.formatPersistenceString()); } else { localStorage.removeItem(g_amuletGroupsStorageKey); } } function amuletLoadGroups() { return new AmuletGroupCollection(localStorage.getItem(g_amuletGroupsStorageKey)); } function amuletClearGroups() { localStorage.removeItem(g_amuletGroupsStorageKey); } function amuletSaveGroup(group) { if (group?.isValid()) { let groups = amuletLoadGroups(); if (groups.add(group)) { amuletSaveGroups(groups); } } } function amuletLoadGroup(groupName) { return amuletLoadGroups().get(groupName); } function amuletDeleteGroup(groupName) { let groups = amuletLoadGroups(); if (groups.remove(groupName)) { amuletSaveGroups(groups); } } function amuletCreateGroupFromArray(groupName, amulets) { if (amulets?.length > 0 && amuletIsValidGroupName(groupName)) { let group = new AmuletGroup(null); for (let amulet of amulets) { if (group.add(amulet) < 0) { group.clear(); break; } } if (group.count() > 0) { group.name = groupName; return group; } } return null; } function amuletNodesToArray(nodes, array) { let amulet; for (let node of nodes) { if ((amulet ??= new Amulet()).fromNode(node)?.isValid()) { array.push(amulet); amulet = null; } } } function beginReadAmulets(bagAmulets, storeAmulets, fnFurtherProcess, fnParams) { if (bagAmulets != null || storeAmulets != null) { let request = GM_xmlhttpRequest({ method: g_postMethod, url: g_readUrl, headers: g_postHeader, data: 'f=7', onload: response => { let div = document.createElement('div'); div.innerHTML = response.responseText; if (bagAmulets != null) { amuletNodesToArray(div.children[0].children[1].children, bagAmulets); } if (storeAmulets != null) { amuletNodesToArray(div.children[1].children[1].children, storeAmulets); } if (fnFurtherProcess != null) { fnFurtherProcess(fnParams); } } }); httpRequestRegister(request); } else if (fnFurtherProcess != null) { fnFurtherProcess(fnParams); } } function beginMoveAmulets({ groupName, amulets, unload, proc, params }) { let indices = amuletLoadGroup(groupName)?.findIndices(amulets)?.sort((a, b) => b - a); let ids; while (indices?.length > 0) { (ids ??= []).push(amulets[indices.pop()].id); } beginMoveObjects(ids, unload, proc, params); } function beginLoadAmuletGroupFromStore(groupName, fnFurtherProcess, fnParams) { let amulets = []; beginReadAmulets(null, amulets, beginMoveAmulets, { groupName : groupName, amulets : amulets, unload : false, proc : fnFurtherProcess, params : fnParams }); } function beginUnloadAmuletGroupFromBag(groupName, fnFurtherProcess, fnParams) { let amulets = []; beginReadAmulets(amulets, null, beginMoveAmulets, { groupName : groupName, amulets : amulets, unload : true, proc : fnFurtherProcess, params : fnParams }); } function beginClearBag(fnFurtherProcess, fnParams) { function beginClearBagObjects({ objects, proc, params }) { beginMoveObjects(objects, true, proc, params); } let objects = []; beginReadObjects(objects, null, true, beginClearBagObjects, { objects : objects, proc : fnFurtherProcess, params : fnParams }); } //////////////////////////////////////////////////////////////////////////////////////////////////// // // generic popups // //////////////////////////////////////////////////////////////////////////////////////////////////// const g_genericPopupContainerId = 'generic-popup-container'; const g_genericPopupClass = 'generic-popup'; const g_genericPopupId = g_genericPopupClass; const g_genericPopupContentContainerId = 'generic-popup-content-container'; const g_genericPopupContentClass = 'generic-popup-content'; const g_genericPopupContentId = g_genericPopupContentClass; const g_genericPopupFixedContentId = 'generic-popup-content-fixed'; const g_genericPopupProgressClass = g_genericPopupClass; const g_genericPopupProgressId = 'generic-popup-progress'; const g_genericPopupProgressContentClass = 'generic-popup-content-progress'; const g_genericPopupProgressContentId = g_genericPopupProgressContentClass; const g_genericPopupTopLineDivClass = 'generic-popup-top-line-container'; const g_genericPopupTitleTextClass = 'generic-popup-title-text'; const g_genericPopupTitleTextId = g_genericPopupTitleTextClass; const g_genericPopupTitleButtonContainerId = 'generic-popup-title-button-container'; const g_genericPopupFootButtonContainerId = 'generic-popup-foot-button-container'; const g_genericPopupBackgroundColor = '#ebf2f9'; const g_genericPopupBackgroundColorAlt = '#dbe2e9'; const g_genericPopupBorderColor = '#3280fc'; const g_genericPopupTitleTextColor = '#ffffff'; const g_genericPopupStyle = ``; const g_genericPopupHTML = `${g_genericPopupStyle}
配置项 | 值 |
---|
装备名称 | 装备属性 |
---|
获得了
')) { let gain; let sp = '获得'; let regex = /x\s*(\d+)\s*([^<]+)<\/span>/g; while ((gain = regex.exec(response))?.length == 3) { gainText += `${sp}${gain[2].trim()}:${gain[1]}`; sp = ', '; } let lvlUp = response.match(/角色 \[ [^\s]+ \] 卡片等级提升!/g); if (lvlUp?.length > 0) { lvlUp.forEach((e) => { gainText += `${sp}${e}`; sp = ', '; }); } } return gainText; } function func0(time) { if (time == 0) { if (times[0] != 0) { GM_xmlhttpRequest({ method: g_postMethod, url: g_readUrl, headers: g_postHeader, data: 'f=12', onload: response => { let ap = response.responseText.match(/class="fyg_colpz03" style="font-size:32px;font-weight:900;">\d+)[0].match(/>\d+)[0].slice(1, -1); document.getElementsByClassName('fyg_colpz03')[0].innerText = ap; let rankp = response.responseText.match(/class="fyg_colpz02" style="font-size:32px;font-weight:900;">\d+%)[0].match(/\d+%/)[0]; document.getElementsByClassName('fyg_colpz02')[0].innerText = rankp; let div_sum = document.createElement('div'); div_sum.innerText = `贝壳总次数:经验总次数=${sum0}:${sum1}=${(sum0 == 0 || sum1 == 0) ? 'undefined' : (sum0 / sum1).toFixed(4)}`; dataReward.sumShell = sum0; dataReward.sumExp = sum1; localStorage.setItem('dataReward', JSON.stringify(dataReward)); document.getElementsByClassName('btn-outline-secondary')[0].parentNode.appendChild(div_sum); times[0] = 0; } }); } return; } GM_xmlhttpRequest({ method: g_postMethod, url: g_postUrl, headers: g_postHeader, data: gox_data, onload: response => { let gainText = parseGainResponse(response.responseText); if (gainText.length > 0) { let div_info = document.createElement('div'); div_info.innerText = gainText; document.getElementsByClassName('btn-outline-secondary')[0].parentNode.appendChild(div_info); if (gainText.indexOf('贝壳') != -1) { sum0 += 1; } if (gainText.indexOf('经验') != -1) { sum1 += 1; } func0(time - 1); } else { let div_info = document.createElement('div'); div_info.innerText = '段位进度不足或无法识别的应答信息'; document.getElementsByClassName('btn-outline-secondary')[0].parentNode.appendChild(div_info); func0(0); } } }); } function func1(time) { if (time == 0) { times[1] = 0; return; } let observerPk = new MutationObserver((mutationsList, observer) => { let isPk = 0; for (let mutation of mutationsList) { if (mutation.type == 'childList') { isPk = 1; } } if (isPk) { observerPk.disconnect(); func1(time - 1); } }); observerPk.observe(document.querySelector("#pk_text"), { characterData : true , childList : true }); jgjg(1); } function func2(time) { if (time == 0) { times[2] = 0; return; } let observerPk = new MutationObserver((mutationsList, observer) => { let isPk = 0; for (let mutation of mutationsList) { if (mutation.type == 'childList') { isPk = 1; } } if (isPk) { observerPk.disconnect(); func2(time - 1); } }); observerPk.observe(document.querySelector("#pk_text"), { characterData : true , childList : true }); jgjg(2); } func0(times[0]); let waitFor0 = setInterval(() => { if (times[0] == 0) { clearInterval(waitFor0); func1(times[1]); } }, 1000); let waitFor1 = setInterval(() => { if (times[0] == 0 && times[1] == 0) { clearInterval(waitFor1); func2(times[2]); } }, 1000); } else { alert('体力不足'); } } document.getElementsByClassName('btn-outline-secondary')[0].addEventListener('click', gobattle, false); } function selector_act() { var btnNum = $(".btn-group .btn-secondary").index(this); $(".btn-group .btn-secondary") .eq(btnNum) .css("background-color", "rgb(135, 206, 250)") .siblings(".btn-group .btn-secondary") .css("background-color", "rgb(255, 255, 255)"); } let btnselector = document.getElementsByClassName('btn-secondary'); for (let i = 0; i < btnselector.length; i++) { btnselector[i].addEventListener('click', selector_act, false); } } }, 1000); } }); taskObserver.observe(document.getElementsByClassName('panel panel-primary')[0], { childList : true, subtree : true, }); } } else if (window.location.pathname == '/fyg_wish.php') { let timer = setInterval(() => { let wishPoints = parseInt(document.getElementById('xys_dsn')?.innerText); if (!isNaN(wishPoints)) { clearInterval(timer); function getWishPoints() { let text = 'WISH'; for (let i = 7; i <= 13; i++) { text += (' ' + (document.getElementById('xyx_' + ('0' + i).slice(-2))?.innerText ?? '0')); } return text; } function copyWishPoints(a) { a = a.target; let acolor = a.style.color; let astring = a.innerText; a.style.color = '#c00000'; calcWishPoints.select(); if (document.execCommand('copy')) { a.innerText = '许愿点设置已复制到剪贴板'; } else { a.innerText = '复制失败,这可能是因为浏览器没有剪贴板访问权限,请进行手工复制'; } setTimeout((() => { a.style.color = acolor; a.innerText = astring; }), 3000); } let div = document.createElement('div'); div.className = 'row'; div.innerHTML = '