安装油猴后请安装 脚本核心模块
// ==UserScript==
// @name 安装油猴后请安装 脚本核心模块
// @namespace PokeClickerHelper
// @version 0.1.2
// @description 核心模块作为基础依赖框架/【必须安装】,否则功能模块无法生效。
// @author
// @match https://pokemon.ccox.cc/
// @icon data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/319hf99fYX/fX2F/319hf8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////99fYX/fX2F/319hf8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////////wAAAP8AAAD/fX2F/319hf99fYX/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////8AAAD/AAAA/wAAAP99fYX/fX2F/wAAAP8AAAD/AAAA/319hf8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/HBT//xwU//8AAAD//////319hf8AAAD/Dgim/w4Ipv8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAD/HBT//xwU//8cFP//HBT//wAAAP8AAAD/Dgim/w4Ipv8OCKb/Dgim/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/xwU//8cFP//HBT//xwU/44cFP//HBT//xwU//8cFP//Dgim/w4Ipv8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/HBT//xwU/47/////HBT/jhwU//8cFP//HBT//w4Ipv8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/xwU//8cFP//HBT/jhwU//8OCKb/Dgim/w4Ipv8OCKb/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/xwU//8OCKb/Dgim/w4Ipv8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAPw/AADwDwAA4AcAAOAHAADAAwAAwAMAAMADAADAAwAA4AcAAOAHAADwDwAA/D8AAP//AAD//wAA//8AAA==
// @grant none
// @license MIT
// @run-at document-body
// ==/UserScript==
/* eslint-env jquery */
/* global Preload,NotificationConstants */
/* eslint no-implicit-globals:0, no-eval:0*/
const { scriptHandler, version } = GM_info;
const [V, v] = version.split('.');
if (scriptHandler == "Tampermonkey") {
if (V < 4 || (V == 4 && v < 16)) alert(`Tampermonkey版本过低 可能无法正常运行脚本\n建议更新至4.16+版本\n当前版本:${scriptHandler} ${version}`)
}
////////////////////
// 脚本公共Object //
////////////////////
//所有方法均挂载在PokeClickerHelper对象下便于调用(简写PCH)
let PokeClickerHelper = {};
let PCH = PokeClickerHelper;
window.PCH = PokeClickerHelper;
window.PokeClickerHelper = PokeClickerHelper;
//存储或读取变量至localStorage 自动补全前缀PokeClickerHelper_,防止命名冲突
PokeClickerHelper.get = function (key, defaultValue) {
let value = JSON.parse(localStorage.getItem('PokeClickerHelper_' + key))
return value ?? defaultValue
}
PokeClickerHelper.set = function (key, value) {
localStorage.setItem('PokeClickerHelper_' + key, JSON.stringify(value))
}
//通知函数
//默认设置 标题:'宝可梦点击(Poke Clicker)辅助脚本';样式:Danger;持续:10秒;默认不进行浏览器通知
PokeClickerHelper.Notify = function ({ title = '宝可梦点击(Poke Clicker)辅助脚本', message, timeout = 10000, type = NotificationConstants.NotificationOption.danger, ...args }, alert = false) {
//节流 相同通知10秒内最多通知一次
const now = Date.now()
if (now - PokeClickerHelper.NotifyThrottle[message] < 10000) return
PokeClickerHelper.NotifyThrottle[message] = now
//桌面通知
alert && new Notification(message)
//游戏内通知
window.Notifier.notify({ title, message, timeout, type, ...args })
}
PokeClickerHelper.NotifyThrottle = {}
//委托初始化前函数:PokeClickerHelper.initBeforeList.add(fuc)
//{fuc}自定义函数
PokeClickerHelper.initBeforeList = new Set()
//读取存档前初始化函数
initBefore()
function initBefore() {
initHook()
initGameTickHook()
PokeClickerHelper.addHook('Game', forceWebWorker)
initWebWorker()
initUI()
//PokeClickerHelper.hookGameTickList.add(() => console.log('tick测试'))
initAfterHook()
PokeClickerHelper.initBeforeList.forEach(i => i())
PokeClickerHelper.Notify({ title: '宝可梦点击(Poke Clicker)辅助脚本', message: "加载成功" });
PokeClickerHelper.addHook('Game', initAfterStartHook)
}
//委托初始化后函数:PokeClickerHelper.initAfterList.add(fuc)
//{fuc}自定义函数
PokeClickerHelper.initAfterList = new Set()
//读取存档后初始化函数
function initAfter() {
appendUI()
PokeClickerHelper.initAfterList.forEach(i => i())
}
function initAfterHook() {
const realHideSplashScreen = Preload.hideSplashScreen
Preload.hideSplashScreen = function (fast = false) {
initAfter()
realHideSplashScreen(fast)
}
}
//强制游戏使用Web Worker计时器,减少延迟
//暂不支持自定义 TODO:Script Setting
function forceWebWorker(Game) {
const replacement = [["let pageHidden = document.hidden;", "/*let pageHidden = document.hidden;"],
["// Try start our webworker so we can process stuff while the page isn't focused", "*/"],
["let pageHidden = false;\n self.onmessage = function(e) {\n if (e.data.pageHidden != undefined) {\n pageHidden = e.data.pageHidden;\n }\n };", ""],
["if (!pageHidden) return;", ""],
["Settings.getSetting('useWebWorkerForGameTicks').value ? this.gameTick() : null", "this.gameTick()"],
["document.addEventListener('visibilitychange', () => {", "/*document.addEventListener('visibilitychange', () => {"],
["this.worker.postMessage({ 'pageHidden': pageHidden });\n if (this.worker) {", "this.worker.postMessage({ 'pageHidden': pageHidden });*/\n if (this.worker) {"]];
PokeClickerHelper.HookFuc(Game, 'start', replacement, '');
}
PokeClickerHelper.initAfterStartList = new Set()
//游戏完全加载后初始化函数
function initAfterStartHook(Game) {
const realStart = Game.start.bind(Game)
Game.start = function () {
realStart()
PokeClickerHelper.initAfterStartList.forEach(i => i())
}
}
//////////////////
// 劫持对象方法 //
//////////////////
//通过function.toString().replace劫持替换原有函数
//会自动在hook object对象下挂载3个属性{real_prop}原生函数、{hook_prop}劫持函数、{hookStorage}存储prop名方便还原或再次劫持
//调用后直接劫持并应用,如只想劫持不应用,需要额外调用PokeClickerHelper.restoreHook({obj})
//注:暂不支持多模块同时劫持同一个对象并分别还原
//(目前理念是各模块功能明确,互不干涉,暂不存在多模块需要劫持同一个对象情况)
//调用方法
//劫持对象属性 PokeClickerHelper.HookFuc({object}, {prop}, {replacement}, {argName})
//{object}劫持对象 {prop}劫持属性 {replacement}替换函数体内容(二维数组) {argName}替换函数传入参数名(字符串 以,分隔)
//
//还原已劫持对象所有劫持函数 PokeClickerHelper.restoreHook({object})
//{object}已劫持对象
//
//重新劫持已还原劫持对象所有劫持函数 PokeClickerHelper.applyHook({object})
//{object}已还原劫持对象
//
//额外功能:(通常用于脚本内自定义函数格式化,其结果通常用于与网页劫持函数拼接)
//不劫持只返回格式化函数体 PokeClickerHelper.HookFucBody({fucntion})
//{fucntion}需要格式化的函数
PokeClickerHelper.HookFuc = function (obj, prop, replacement, arg) {
const fuc = obj[prop]
let text = fuc.toString()
text = text.slice(text.indexOf('{') + 1, -1)
for (let item of replacement) {
if (typeof item[0] == 'string') { //string则includes;RegExp则test
if (!text.includes(item[0])) { //先检测是否存在 不存在代表脚本过时 停止注入
alert('替换失败 脚本可能需要更新' + item[0])
return false
}
} else {
if (!item[0].test(text)) {
alert('替换失败 脚本可能需要更新' + item[0])
return false
}
}
text = text.replace(item[0], item[1])
}
const newFuc = new Function(arg, text)
obj['real_' + prop] = obj[prop]
obj[prop] = newFuc
obj['hook_' + prop] = newFuc
obj.hookStorage = obj.hookStorage || []
obj.hookStorage.push(prop)
}
//还原替换hook函数
//prop为指定还原,无prop则为全部还原
PokeClickerHelper.restoreHook = function (obj, prop) {
if (prop != void 0) {
if (!obj['real_' + prop]) return
obj[prop] = obj['real_' + prop]
} else {
Object.values(obj.hookStorage).forEach(i => {
obj[i] = obj['real_' + i]
})
}
}
//重新劫持hook函数
//prop为指定劫持,无prop则为全部劫持
PokeClickerHelper.applyHook = function (obj, prop) {
if (prop != void 0) {
if (!obj['hook_' + prop]) return
obj[prop] = obj['hook_' + prop]
} else {
Object.values(obj.hookStorage).forEach(i => {
obj[i] = obj['hook_' + i]
})
}
}
//格式化函数体
PokeClickerHelper.HookFucBody = function (fuc) {
let text = fuc.toString()
return text.slice(text.indexOf('{') + 1, -1)
}
////////////////////
// 委托Web Worker //
////////////////////
//Web Worker 用于执行tick间隔低于100ms函数
//每种tick各生成一个Web Worker,相同tick函数共用同一Web Worker
//不建议生成过多Web Worker影响效率
//(暂不支持传参,如要传参可以改为读写全局变量/对象上的属性)
//调用方法
//创建一个setInterval循环线程 PokeClickerHelper.Worker.setInterval(callback,delay)
//创建一个setTimeout循环线程 PokeClickerHelper.Worker.setTimeout(callback,delay)
//注:setTimeout循环线程同样不断循环执行,并非只执行一次,循环方法不同(setInterval为执行函数前计算间隔;setTimeout为执行函数后计算间隔)
//
//删除一个setInterval循环线程 PokeClickerHelper.Worker.clearInterval(callback,delay)
//删除一个setTimeout循环线程 PokeClickerHelper.Worker.claerTimeout(callback,delay)
//注:删除循环线程需要传入创建时传入的{callback}函数及{delay}间隔
//
//{callback}需要不断执行的tick函数
//{delay}间隔毫秒
function initWebWorker() {
PokeClickerHelper.Worker = {}
PokeClickerHelper.Worker.setInterval = function (callback, delay) {
let callbackList = this['intervalList' + delay]
if (callbackList == void 0) {
callbackList = new Set()
let workerURL = URL.createObjectURL(new Blob([`setInterval(()=>{postMessage('')},${delay})`]))
this.intervalWorker = new Worker(workerURL)
this.intervalWorker.onmessage = () => {
callbackList.forEach(i => i())
}
URL.revokeObjectURL(workerURL) //垃圾回收
this['intervalList' + delay] = callbackList
}
callbackList.add(callback)
}
PokeClickerHelper.Worker.setTimeout = function (callback, delay) {
let callbackList = this['timeoutList' + delay]
if (callbackList == void 0) {
callbackList = new Set()
let workerURL = URL.createObjectURL(new Blob([`(function Timeout(){postMessage('');setTimeout(Timeout,${delay})})()`]))
this.timeoutWorker = new Worker(workerURL)
this.timeoutWorker.onmessage = () => {
callbackList.forEach(i => i())
}
URL.revokeObjectURL(workerURL) //垃圾回收
this['timeoutList' + delay] = callbackList
}
callbackList.add(callback)
}
PokeClickerHelper.Worker.clearInterval = function (callback, delay) {
let callbackList = this['intervalList' + delay]
if (!callbackList) return
callbackList.delete(callback)
if (callbackList.size == 0) {
this.intervalWorker.terminate()
this['intervalList' + delay] = void 0
}
}
PokeClickerHelper.Worker.clearTimeout = function (callback, delay) {
let callbackList = this['timeoutList' + delay]
if (!callbackList) return
callbackList.delete(callback)
if (callbackList.size == 0) {
this.intervalWorker.terminate()
this['timeoutList' + delay] = void 0
}
}
}
///////////////////////
// 委托劫持class函数 //
///////////////////////
//委托劫持class,只委托脚本运行后无法直接访问需要额外new的class,不委托已经new过可直接访问的class,如:Battle、MapHelper
//调用方法:
//初始化委托劫持class函数:PokeClickerHelper.addHook({className},{fuction(new hookClass)}})
//{className} 委托劫持class函数名称
//{fuction(new hookClass)} 委托劫持的class函数对应的劫持方法,传参:劫持后的new hookClass
function initHook() {
PokeClickerHelper.hookLists = new Set()
PokeClickerHelper.addHook = function (className, hookFuc) {
if (PokeClickerHelper.hookLists.has(className)) {
PokeClickerHelper['hook' + className + 'List'].add(hookFuc)
} else {
PokeClickerHelper.hookLists.add(className)
PokeClickerHelper['hook' + className + 'List'] = new Set([hookFuc])
//eval may not harmful but useful(=_=!)
PokeClickerHelper['real' + className] = eval(className)
eval(className + '=' + function (...args) {
const hookedFuc = new PokeClickerHelper['real' + className](...args) //劫持class
PokeClickerHelper['hook' + className] = hookedFuc
PokeClickerHelper['hook' + className + 'List'].forEach(i => i(hookedFuc)) //调用委托劫持函数 传入劫持后的class
return hookedFuc
})
}
}
}
///////////////////////////////
// 委托劫持Game.gameTick函数 //
///////////////////////////////
//利用游戏原生Game.gameTick函数运行脚本定时代码
//(游戏默认100ms执行一次Game.gameTick函数 支持Web Worker较精确定时器)
//调用方法:
//委托增加gameTick执行函数:PokeClickerHelper.hookGameTickList.add({fuction})
//委托删除gameTick执行函数:PokeClickerHelper.hookGameTickList.delete({fuction})
//{function}委托gameTick执行函数
function initGameTickHook() {
PokeClickerHelper.hookGameTickList = new Set()
const gameTickHook = function (Game) {
Game.realGameTick = Game.gameTick
Game.gameTick = function () {
PokeClickerHelper.hookGameTickList.forEach(i => i()) //调用委托劫持Game.gameTick函数
Game.realGameTick()
}
}
//初始化劫持Game 并将委托劫持Game.gameTick函数加入到Game class劫持
PokeClickerHelper.addHook('Game', gameTickHook)
}
////////////////
// 可视化界面 //
////////////////
//同时机不同模块UI加载顺序根据油猴等脚本管理器加载顺序决定
//
//以油猴为例,
//核心模块运行时机为// @run-at document-start
//其余所有功能模块运行时机均应为// @run-at document-body
//无论脚本管理器中脚本序号,核心模块必定优先于功能模块加载
//而功能模块加载时机相同,因此功能模块UI加载顺序根据脚本管理器中功能模块脚本序号决定,序号越小加载越早
//
//若核心模块脚本序号为10,孵蛋模块脚本序号为1,自动地牢/道馆脚本序号为5,
// 加载顺序:核心模块→孵蛋模块→自动地牢/道馆模块。面板UI显示顺序:孵蛋模块→自动地牢/道馆模块
//若核心模块脚本序号为10,孵蛋模块脚本序号为4,自动地牢/道馆脚本序号为2,
// 加载顺序:核心模块→自动地牢/道馆模块→孵蛋模块。面板UI显示顺序:自动地牢/道馆模块→孵蛋模块
//调用方法:
//增加css样式:PokeClickerHelper.UIstyle({styleText})
//{styleText}仅style内css样式文字(不含<style>节点)
//
//增加#PokeClickerHelperBody内DOM元素:PokeClickerHelper.UIDOM({DOMText})
//{DOMText} DOM元素文字(需含子元素节点<div>等)
//
//增加 开始菜单=>设置=>Script标签页内DOM元素:PokeClickerHelper.UIScript({DOMText})
//{DOMText} DOM元素文字(需含子元素节点<tr>等)
//
//增加DOM元素监听事件:PokeClickerHelper.UIlistener.push({DOMlistener})
//{DOMlistener} DOM监听事件函数
//
//如果上述静态方法均无法满足需求,可尝试以下动态自定义方法
//增加动态自定义UI函数:PokeClickerHelper.UICustomFuc.push({UICustomFun})
//{UICustomFun} 自定义UI函数
//
//增加非#PokeClickerHelperBody UI面板:PokeClickerHelper.UIContainerID.push({UIContainerID})
//{UIContainerID} 自定义UI面板ID(增加后与#PokeClickerHelperBody适用相同方法)
function initUI() {
PokeClickerHelper.UIstyle = []
PokeClickerHelper.UIDOM = []
PokeClickerHelper.UIScript = [] //Author:猫猫
PokeClickerHelper.UIlistener = []
PokeClickerHelper.UICustomFuc = []
PokeClickerHelper.UIContainerID = ['#PokeClickerHelperContainer']
//TODO 先这样凑合用吧 摆烂 看着CSS就头疼
const style = `
#PokeClickerHelperContainer{z-index:1;font-family:"Open Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";position:absolute;top:38px;right:0;width:375px;background-color:white;opacity:.9;padding:10px;font-size:12px}
#PokeClickerHelperContainer button{margin-left:5px}
#PokeClickerHelperContainer .custom-row{margin-top:10px;display:flex}
#PokeClickerHelperContainer .form-group{margin-bottom:5px}
.labelContainer{width:93px;display:inline-block}
.contentContainer{flex:1;padding-left:0px;padding-right:0px}
.opacity-25{opacity: 0.25}
#PokeClickerHelperContainer input[type=checkbox]{position: absolute;margin-top: 0.24rem;margin-left: -1rem;}
`
PokeClickerHelper.UIcontainer = `
<div id="PokeClickerHelperContainer" class="shadow bg-white border border-primary" style="width: 375px; top: 50px; right: 10px;">
<div>
<div class="d-inline">
<label>完全隐藏(Shift+F12):</label>
</div>
<button id="PokeClickerHelperToggle" class="btn btn-sm btn-primary">隐藏</button>
</div>
<div class="mt-2 mb-1 border-top border-secondary"></div>
<div id="PokeClickerHelperBody">
</div>
</div>
`
//Author:猫猫
PokeClickerHelper.UIScriptTab = `<li class="nav-item"><a class="nav-link" href="#PokeClickerHelperSettings-Script" data-toggle="tab">Script</a></li>`
PokeClickerHelper.UIScriptTbody = `
<div class="tab-pane" id = "PokeClickerHelperSettings-Script">
<table class="table table-striped table-hover m-0">
<tbody id="PokeClickerHelperSettingsTbody">
</tbody>
</table>
</div>
`
const listener = function () {
//DOM元素监听事件 触发监听事件后自动存储DOM.value(button、input、select均以value存储)
const DOMlistener = function () {
if (this.dataset.save == 'false') return
if (this.nodeName == 'INPUT' && this.type == 'checkbox') this.value = this.checked
PokeClickerHelper.set(PokeClickerHelper.formatId(this), this.value)
}
PokeClickerHelper.UIContainerID.forEach(i => {
$(`${i} button`).on('click', DOMlistener)
$(`${i} input,${i} select`).on('change', DOMlistener)
})
$('#PokeClickerHelperToggle').on('click', function () {
if (this.value == '隐藏') {
$('#PokeClickerHelperContainer *:not(#PokeClickerHelperToggle):not(:has(#PokeClickerHelperToggle))').addClass('d-none')
$('#PokeClickerHelperToggle').text(this.value = '显示')
$('#PokeClickerHelperContainer').css('width', '75px')
} else {
$('#PokeClickerHelperContainer *:not(#PokeClickerHelperToggle):not(:has(#PokeClickerHelperToggle))').removeClass('d-none')
$('#PokeClickerHelperToggle').text(this.value = '隐藏')
$('#PokeClickerHelperContainer').css('width', '375px')
}
})
//拖拽 多重解构语法糖
document.querySelector("#PokeClickerHelperContainer").addEventListener('mousedown', function ({ x: Gx, y: Gy, which, target: { nodeName } }) {
if (which != 1 || nodeName == 'BUTTON' || nodeName == 'INPUT' || nodeName == 'SELECT') return
const that = this
const top = that.style.top.replace('px', '') * 1 - Gy
const right = that.style.right.replace('px', '') * 1 + Gx
const mousemove = function ({ x, y }) {
that.style.top = top + y + 'px'
that.style.right = right - x + 'px'
}
const mouseup = function ({ x, y }) {
this.removeEventListener('mousemove', mousemove)
this.removeEventListener('mouseup', mouseup)
x != Gx && PokeClickerHelper.set('top', that.style.top)
y != Gy && PokeClickerHelper.set('right', that.style.right)
}
document.addEventListener('mousemove', mousemove)
document.addEventListener('mouseup', mouseup)
})
//Shift+F12隐藏
document.addEventListener('keydown', ({ key, shiftKey }) => {
if (key == 'F12' && shiftKey) $("#PokeClickerHelperContainer").toggleClass('d-none')
})
}
PokeClickerHelper.UIstyle.push(style)
PokeClickerHelper.UIlistener.push(listener)
}
//读取DOM.value(button、input、select均以value存储)
PokeClickerHelper.UIsettings = function () {
const clickEvent = new Event('click')
const changeEvent = new Event('change')
PokeClickerHelper.UIContainerID.forEach(i => {
$(`${i} button,${i} input,${i} select`).each(UIsettings)
})
$("#PokeClickerHelperContainer").css({ 'top': PokeClickerHelper.set('top', '50px'), 'right': PokeClickerHelper.get('right', '10px') })
function UIsettings() {
let value = PokeClickerHelper.get(PokeClickerHelper.formatId(this))
if (value == void 0) return
this.value = value
switch (this.nodeName) {
case 'BUTTON': this.dispatchEvent(clickEvent); break
case "INPUT": {
if (this.type == "checkbox") {
this.checked = JSON.parse(value);
}
break
}
case 'SELECT': this.dispatchEvent(changeEvent); break
default: alert('UIsettings Error')
}
}
}
//去除DOM元素ID前缀(DOM元素ID应以PokeClickerHelper开头)
PokeClickerHelper.formatId = function (e) {
let id = e.id
if (!id.startsWith('PokeClickerHelper')) {
console.log(e, 'id规则错误,应以PokeClickerHelper开头\nlocalStorage读写失败')
alert(e.nodeName + ' id规则错误,应以PokeClickerHelper开头,详见控制台。\nlocalStorage读写失败')
throw new Error('id规则错误,应以PokeClickerHelper开头\nlocalStorage读写失败')
}
return id.replace(/^PokeClickerHelper/, '')
}
//加载UI
function appendUI() {
$('body').append('<style>' + PokeClickerHelper.UIstyle.join('\n') + '</style>' + PokeClickerHelper.UIcontainer)
$('#settingsModal .nav.nav-tabs').append(PokeClickerHelper.UIScriptTab) //Author:猫猫
$('#settingsModal .tab-content').eq(0).append(PokeClickerHelper.UIScriptTbody) //Author:猫猫
PokeClickerHelper.UIDOM.forEach(i => $('#PokeClickerHelperBody').append(i))
PokeClickerHelper.UIScript.forEach(i => $('#PokeClickerHelperSettingsTbody').append(i)) //Author:猫猫
PokeClickerHelper.UICustomFuc.forEach(i => i())
PokeClickerHelper.UIlistener.forEach(i => i())
PokeClickerHelper.UIsettings() //读取主面板UI DOM元素存储并设置、触发监听事件
}