PokeClicker+

PokeClicker plugin framework

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/454084/1114168/PokeClicker%2B.js

  1. // ==UserScript==
  2. // @name PokeClicker+
  3. // @namespace pokeclicker.com
  4. // @version 1.0.0
  5. // @description PokeClicker plugin framework
  6. // @author TwoCon
  7. // @match *://www.pokeclicker.com/*
  8. // @icon https://www.google.com/s2/favicons?domain=pokeclicker.com
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14. const VERSION = "1.0.0";
  15.  
  16. if(window.PokeClickerPlus) {
  17. // already loaded
  18. return;
  19. }
  20.  
  21. const LOCAL_STORAGE_KEY_DEBUG = "PokeClickerPlus:debug";
  22.  
  23. const CONFIG_TYPES_LABEL = ["label"];
  24. const CONFIG_TYPES_BOOLEAN = ["boolean", "bool", "checkbox"];
  25. const CONFIG_TYPES_INTEGER = ["integer", "int"];
  26. const CONFIG_TYPES_FLOAT = ["number", "num", "float"];
  27. const CONFIG_TYPES_STRING = ["string", "text"];
  28. const CONFIG_TYPES_SELECT = ["select"];
  29. const CONFIG_TYPES_COLOR = ["color"];
  30.  
  31.  
  32. function logFancy(s, color="#00f7ff") {
  33. console.log("%cPokeClickerPlus: %c"+s, `color: ${color}; font-weight: bold; font-size: 12pt;`, "color: black; font-weight: normal; font-size: 10pt;");
  34. }
  35.  
  36. class PokeClickerPlusPlugin {
  37.  
  38. constructor(id, opts) {
  39. if(typeof id !== "string") {
  40. throw new TypeError("PokeClickerPlusPlugin constructor takes the following arguments: (id:string, opts?:object)");
  41. }
  42. this.id = id;
  43. this.opts = opts || {};
  44. this.config = null;
  45. }
  46.  
  47. getConfig(name) {
  48. if(!this.config) {
  49. PokeClickerPlus.loadPluginConfigs(this.id);
  50. }
  51. if(this.config) {
  52. return this.config[name];
  53. }
  54. }
  55. }
  56.  
  57. const internal = {
  58. init() {
  59. const self = this;
  60.  
  61. $("body").append(`
  62. <div class="modal fade noselect" id="pluginModal" tabindex="-1" role="dialog" aria-labelledby="pluginModalLabel">
  63. <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
  64. <div class="modal-content">
  65. <div class="modal-header">
  66. <h5 class="modal-title">Plugins</h5>
  67. <button type="button" class="btn mr-auto"
  68. data-bind="tooltip: {
  69. title: 'Plugins',
  70. trigger: 'hover',
  71. placement:'top',
  72. html: true,
  73. }">ⓘ</button>
  74. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  75. <span aria-hidden="true">&times;</span>
  76. </button>
  77. </div>
  78. <div class="modal-body">
  79. <div data-bind="foreach: Object.entries(BadgeCaseController.getDisplayableBadges())">
  80. </div>
  81. </div>
  82. </div>
  83.  
  84. <div class="modal-footer">
  85. <button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
  86. </div>
  87. </div>
  88. </div>
  89. </div>
  90.  
  91.  
  92.  
  93. <style>
  94. .ipp-chat-command-help {
  95. padding: 0.5em 0;
  96. }
  97. .ipp-chat-command-help:first-child {
  98. padding-top: 0;
  99. }
  100. .ipp-chat-command-help:last-child {
  101. padding-bottom: 0;
  102. }
  103. dialog.ipp-dialog {
  104. background-color: white;
  105. border: 1px solid rgba(0, 0, 0, 0.2);
  106. width: 500px;
  107. max-width: 800px;
  108. border-radius: 5px;
  109. display: flex;
  110. flex-direction: column;
  111. justify-content: flex-start;
  112. }
  113. dialog.ipp-dialog > div {
  114. width: 100%;
  115. }
  116. dialog.ipp-dialog > .ipp-dialog-header > h4 {
  117. margin-bottom: 0;
  118. }
  119. dialog.ipp-dialog > .ipp-dialog-header {
  120. border-bottom: 1px solid rgba(0, 0, 0, 0.2);
  121. padding-bottom: 0.25em;
  122. }
  123. dialog.ipp-dialog > .ipp-dialog-actions {
  124. padding-top: 0.25em;
  125. padding-bottom: 0.25em;
  126. }
  127. dialog.ipp-dialog > .ipp-dialog-actions {
  128. border-top: 1px solid rgba(0, 0, 0, 0.2);
  129. padding-top: 0.25em;
  130. text-align: right;
  131. }
  132. dialog.ipp-dialog > .ipp-dialog-actions > button {
  133. margin: 4px;
  134. }
  135. </style>
  136. `);
  137.  
  138.  
  139. // hook into switch_panels, which is called when the main panel is changed. This is also used for custom panels.
  140. const original_switch_panels = window.switch_panels;
  141. window.switch_panels = function(id) {
  142. let panelBefore = Globals.currentPanel;
  143. if(panelBefore && panelBefore.startsWith("panel-")) {
  144. panelBefore = panelBefore.substring("panel-".length);
  145. }
  146. self.hideCustomPanels();
  147. original_switch_panels.apply(this, arguments);
  148. let panelAfter = Globals.currentPanel;
  149. if(panelAfter && panelAfter.startsWith("panel-")) {
  150. panelAfter = panelAfter.substring("panel-".length);
  151. }
  152. self.onPanelChanged(panelBefore, panelAfter);
  153. }
  154.  
  155. // create plugin menu item and panel
  156. //const lastMenuItem = document.querySelector("#startMenu > ul > li:nth-child(1)");
  157. /*lastMenuItem.before(`
  158. <li>
  159. <a class="dropdown-item" href="#Test" data-toggle="modal">Plugins</a>
  160. </li>
  161. `);*/
  162.  
  163. // TESTING
  164. var scriptElement = document.createElement('div')
  165. scriptElement.id = 'scriptHandler'
  166. document.body.appendChild(scriptElement)
  167. function loadSettings(){
  168. var addSettings = setInterval(function(){
  169. try{
  170. //Fixes the Scripts nav item getting wrapped to the bottom by increasing the max width of the window
  171. document.getElementById('settingsModal').querySelector('div').style.maxWidth = '850px'
  172.  
  173. //Select the top header row of tabs in Settings
  174. const settingTabs = document.querySelector("#startMenu > ul");
  175.  
  176. //Create and append the new tab for scripts to Settings
  177. let scriptFrag = new DocumentFragment();
  178. let li = document.createElement('li');
  179. //li.classList.add('nav-item');
  180. li.innerHTML = `<a class="dropdown-item" href="#pluginModal" data-toggle="modal">Plugins</a>`;
  181. scriptFrag.appendChild(li);
  182. settingTabs.appendChild(scriptFrag);
  183.  
  184. //Select the parent element that contains the content of the tabs
  185. const tabContent = document.querySelectorAll('.tab-content')[3];
  186.  
  187. //Create and append the content for the script tab to Settings
  188. scriptFrag = new DocumentFragment();
  189. let div = document.createElement('biv');
  190. div.classList.add('tab-pane');
  191. div.setAttribute('id', 'pokeplugs')
  192.  
  193. //Add the table and tbody elements to match the other tabs
  194. const scriptTabContent =
  195. `<table class="table table-striped table-hover m-0"><tbody></tbody></table>`
  196. div.innerHTML = `${scriptTabContent}`;
  197. scriptFrag.appendChild(div);
  198. tabContent.appendChild(scriptFrag);
  199.  
  200. //Add a setting to enable each script in the scripts settings menu
  201. document.getElementById('scriptHandler').childNodes.forEach(childNode => {
  202. var setting = document.createElement('tr')
  203. setting.innerHTML =
  204. `<td class="p-2">
  205. <label class="m-0">Enable ` + childNode.id + `</label>
  206. </td>
  207. <td class="p-2 tight">
  208. <input id="Toggle-`+ childNode.id + `" type="checkbox">
  209. </td>`
  210.  
  211. document.getElementById('pokeplugs').querySelector('table tbody').prepend(setting)
  212. //Check if the checkbox should be filled or not
  213. document.getElementById('Toggle-'+ childNode.id).checked = localStorage.getItem(childNode.id) == 'true' ? true : false
  214. document.getElementById('Toggle-'+ childNode.id).addEventListener('change', event => {
  215. if (event.target.checked == false) {
  216. localStorage.setItem(childNode.id, "false");
  217. } else {
  218. localStorage.setItem(childNode.id, "true");
  219. }
  220. });
  221. })
  222. //Add info about restarting to the top
  223. var info = document.createElement('tr')
  224. info.innerHTML =
  225. `<td class="p-2">
  226. <label class="m-0">The script settings will take effect on restart</label>
  227. </td>`
  228. document.getElementById('pokeplugs').querySelector('table tbody').prepend(info)
  229.  
  230. clearInterval(addSettings)
  231. } catch(err) { }
  232. }, 100)
  233. logFancy("Settings Loaded");
  234. }
  235.  
  236.  
  237.  
  238.  
  239. loadSettings()
  240. // END TESTING
  241.  
  242.  
  243. self.addPanel("pokeclickerplus", "PokeClicker+ Plugins", function() {
  244. let content = `
  245. <style>
  246. .pokeclickerplus-plugin-box {
  247. display: block;
  248. position: relative;
  249. padding: 0.25em;
  250. color: white;
  251. background-color: rgb(107, 107, 107);
  252. border: 1px solid black;
  253. border-radius: 6px;
  254. margin-bottom: 0.5em;
  255. }
  256. .pokeclickerplus-plugin-box .pokeclickerplus-plugin-settings-button {
  257. position: absolute;
  258. right: 2px;
  259. top: 2px;
  260. cursor: pointer;
  261. }
  262. .pokeclickerplus-plugin-box .pokeclickerplus-plugin-config-section {
  263. display: grid;
  264. grid-template-columns: minmax(100px, min-content) 1fr;
  265. row-gap: 0.5em;
  266. column-gap: 0.5em;
  267. white-space: nowrap;
  268. }
  269. </style>
  270. `;
  271. self.forEachPlugin(plugin => {
  272. let id = plugin.id;
  273. let name = "A PokeClicker+ Plugin!";
  274. let description = "";
  275. let author = "unknown";
  276. if(plugin.opts.about) {
  277. let about = plugin.opts.about;
  278. name = about.name || name;
  279. description = about.description || description;
  280. author = about.author || author;
  281. }
  282. content += `
  283. <div id="pokeclickerplus-plugin-box-${id}" class="pokeclickerplus-plugin-box">
  284. <strong><u>${name||id}</u></strong> (by ${author})<br />
  285. <span>${description}</span><br />
  286. <div class="pokeclickerplus-plugin-config-section" style="display: none">
  287. <hr style="grid-column: span 2">
  288. `;
  289. logFancy("Adding Plugin" & name)
  290. if(plugin.opts.config && Array.isArray(plugin.opts.config)) {
  291. plugin.opts.config.forEach(cfg => {
  292. if(CONFIG_TYPES_LABEL.includes(cfg.type)) {
  293. content += `<h5 style="grid-column: span 2; margin-bottom: 0; font-weight: 600">${cfg.label}</h5>`;
  294. }
  295. else if(CONFIG_TYPES_BOOLEAN.includes(cfg.type)) {
  296. content += `
  297. <div>
  298. <label for="pokeclickerplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  299. </div>
  300. <div>
  301. <input id="pokeclickerplus-config-${plugin.id}-${cfg.id}" type="checkbox" onchange="PokeClickerPlus.setPluginConfigUIDirty('${id}', true)" />
  302. </div>
  303. `;
  304. }
  305. else if(CONFIG_TYPES_INTEGER.includes(cfg.type)) {
  306. content += `
  307. <div>
  308. <label for="pokeclickerplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  309. </div>
  310. <div>
  311. <input id="pokeclickerplus-config-${plugin.id}-${cfg.id}" type="number" step="1" min="${cfg.min || ''}" max="${cfg.max || ''}" onchange="PokeClickerPlus.setPluginConfigUIDirty('${id}', true)" />
  312. </div>
  313. `;
  314. }
  315. else if(CONFIG_TYPES_FLOAT.includes(cfg.type)) {
  316. content += `
  317. <div>
  318. <label for="pokeclickerplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  319. </div>
  320. <div>
  321. <input id="pokeclickerplus-config-${plugin.id}-${cfg.id}" type="number" step="${cfg.step || ''}" min="${cfg.min || ''}" max="${cfg.max || ''}" onchange="PokeClickerPlus.setPluginConfigUIDirty('${id}', true)" />
  322. </div>
  323. `;
  324. }
  325. else if(CONFIG_TYPES_STRING.includes(cfg.type)) {
  326. content += `
  327. <div>
  328. <label for="pokeclickerplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  329. </div>
  330. <div>
  331. <input id="pokeclickerplus-config-${plugin.id}-${cfg.id}" type="text" maxlength="${cfg.max || ''}" onchange="PokeClickerPlus.setPluginConfigUIDirty('${id}', true)" />
  332. </div>
  333. `;
  334. }
  335. else if(CONFIG_TYPES_COLOR.includes(cfg.type)) {
  336. content += `
  337. <div>
  338. <label for="pokeclickerplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  339. </div>
  340. <div>
  341. <input id="pokeclickerplus-config-${plugin.id}-${cfg.id}" type="color" onchange="PokeClickerPlus.setPluginConfigUIDirty('${id}', true)" />
  342. </div>
  343. `;
  344. }
  345. else if(CONFIG_TYPES_SELECT.includes(cfg.type)) {
  346. content += `
  347. <div>
  348. <label for="pokeclickerplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  349. </div>
  350. <div>
  351. <select id="pokeclickerplus-config-${plugin.id}-${cfg.id}" onchange="PokeClickerPlus.setPluginConfigUIDirty('${id}', true)">
  352. `;
  353. if(cfg.options && Array.isArray(cfg.options)) {
  354. cfg.options.forEach(option => {
  355. if(typeof option === "string") {
  356. content += `<option value="${option}">${option}</option>`;
  357. }
  358. else {
  359. content += `<option value="${option.value}">${option.label || option.value}</option>`;
  360. }
  361.  
  362. });
  363. }
  364. content += `
  365. </select>
  366. </div>
  367. `;
  368. }
  369. });
  370. content += `
  371. <div style="grid-column: span 2">
  372. <button id="pokeclickerplus-configbutton-${plugin.id}-reload" onclick="PokeClickerPlus.loadPluginConfigs('${id}')">Reload</button>
  373. <button id="pokeclickerplus-configbutton-${plugin.id}-apply" onclick="PokeClickerPlus.savePluginConfigs('${id}')">Apply</button>
  374. </div>
  375. `;
  376. }
  377. content += "</div>";
  378. if(plugin.opts.config) {
  379. content += `
  380. <div class="pokeclickerplus-plugin-settings-button">
  381. <button onclick="$('#pokeclickerplus-plugin-box-${id} .pokeclickerplus-plugin-config-section').toggle()">Settings</button>
  382. </div>`;
  383. }
  384. content += "</div>";
  385. });
  386.  
  387. return content;
  388. });
  389.  
  390. logFancy(`(v${self.version}) initialized.`);
  391. }
  392. };
  393.  
  394. class PokeClickerPlus {
  395.  
  396. constructor() {
  397. this.version = VERSION;
  398. this.plugins = {};
  399. this.panels = {};
  400. this.debug = false;
  401. this.nextUniqueId = 1;
  402.  
  403. if(localStorage.getItem(LOCAL_STORAGE_KEY_DEBUG) == "1") {
  404. this.debug = true;
  405. }
  406. }
  407.  
  408.  
  409. uniqueId() {
  410. return this.nextUniqueId++;
  411. }
  412.  
  413. setDebug(debug) {
  414. if(debug) {
  415. this.debug = true;
  416. localStorage.setItem(LOCAL_STORAGE_KEY_DEBUG, "1");
  417. }
  418. else {
  419. this.debug = false;
  420. localStorage.removeItem(LOCAL_STORAGE_KEY_DEBUG);
  421. }
  422. }
  423.  
  424. getVar(name, type) {
  425. let s = window[`var_${name}`];
  426. if(type) {
  427. switch(type) {
  428. case "int":
  429. case "integer":
  430. return parseInt(s);
  431. case "number":
  432. case "float":
  433. return parseFloat(s);
  434. case "boolean":
  435. case "bool":
  436. if(s=="true") return true;
  437. if(s=="false") return false;
  438. return undefined;
  439. }
  440. }
  441. return s;
  442. }
  443.  
  444. setPluginConfigUIDirty(id, dirty) {
  445. if(typeof id !== "string" || typeof dirty !== "boolean") {
  446. throw new TypeError("PokeClickerPlus.setPluginConfigUIDirty takes the following arguments: (id:string, dirty:boolean)");
  447. }
  448. const plugin = this.plugins[id];
  449. const button = $(`#pokeclickerplus-configbutton-${plugin.id}-apply`);
  450. if(button) {
  451. button.prop("disabled", !(dirty));
  452. }
  453. }
  454.  
  455. loadPluginConfigs(id) {
  456. if(typeof id !== "string") {
  457. throw new TypeError("PokeClickerPlus.reloadPluginConfigs takes the following arguments: (id:string)");
  458. }
  459. const plugin = this.plugins[id];
  460. const config = {};
  461. let stored;
  462. try {
  463. stored = JSON.parse(localStorage.getItem(`pokeclickerplus.${id}.config`) || "{}");
  464. }
  465. catch(err) {
  466. console.error(`Failed to load configs for plugin with id "${id} - will use defaults instead."`);
  467. stored = {};
  468. }
  469. if(plugin.opts.config && Array.isArray(plugin.opts.config)) {
  470. plugin.opts.config.forEach(cfg => {
  471. const el = $(`#pokeclickerplus-config-${plugin.id}-${cfg.id}`);
  472. let value = stored[cfg.id];
  473. if(value==null || typeof value === "undefined") {
  474. value = cfg.default;
  475. }
  476. config[cfg.id] = value;
  477.  
  478. if(el) {
  479. if(CONFIG_TYPES_BOOLEAN.includes(cfg.type) && typeof value === "boolean") {
  480. el.prop("checked", value);
  481. }
  482. else if(CONFIG_TYPES_INTEGER.includes(cfg.type) && typeof value === "number") {
  483. el.val(value);
  484. }
  485. else if(CONFIG_TYPES_FLOAT.includes(cfg.type) && typeof value === "number") {
  486. el.val(value);
  487. }
  488. else if(CONFIG_TYPES_STRING.includes(cfg.type) && typeof value === "string") {
  489. el.val(value);
  490. }
  491. else if(CONFIG_TYPES_SELECT.includes(cfg.type) && typeof value === "string") {
  492. el.val(value);
  493. }
  494. else if(CONFIG_TYPES_COLOR.includes(cfg.type) && typeof value === "string") {
  495. el.val(value);
  496. }
  497. }
  498. });
  499. }
  500. plugin.config = config;
  501. this.setPluginConfigUIDirty(id, false);
  502. if(typeof plugin.onConfigsChanged === "function") {
  503. plugin.onConfigsChanged();
  504. }
  505. }
  506.  
  507. savePluginConfigs(id) {
  508. if(typeof id !== "string") {
  509. throw new TypeError("PokeClickerPlus.savePluginConfigs takes the following arguments: (id:string)");
  510. }
  511. const plugin = this.plugins[id];
  512. const config = {};
  513. if(plugin.opts.config && Array.isArray(plugin.opts.config)) {
  514. plugin.opts.config.forEach(cfg => {
  515. const el = $(`#pokeclickerplus-config-${plugin.id}-${cfg.id}`);
  516. let value;
  517. if(CONFIG_TYPES_BOOLEAN.includes(cfg.type)) {
  518. config[cfg.id] = el.is(":checked");
  519. }
  520. else if(CONFIG_TYPES_INTEGER.includes(cfg.type)) {
  521. config[cfg.id] = parseInt(el.val());
  522. }
  523. else if(CONFIG_TYPES_FLOAT.includes(cfg.type)) {
  524. config[cfg.id] = parseFloat(el.val());
  525. }
  526. else if(CONFIG_TYPES_STRING.includes(cfg.type)) {
  527. config[cfg.id] = el.val();
  528. }
  529. else if(CONFIG_TYPES_SELECT.includes(cfg.type)) {
  530. config[cfg.id] = el.val();
  531. }
  532. else if(CONFIG_TYPES_COLOR.includes(cfg.type)) {
  533. config[cfg.id] = el.val();
  534. }
  535. });
  536. }
  537. plugin.config = config;
  538. localStorage.setItem(`pokeclickerplus.${id}.config`, JSON.stringify(config));
  539. this.setPluginConfigUIDirty(id, false);
  540. if(typeof plugin.onConfigsChanged === "function") {
  541. plugin.onConfigsChanged();
  542. }
  543. }
  544.  
  545. addPanel(id, title, content) {
  546. if(typeof id !== "string" || typeof title !== "string" || (typeof content !== "string" && typeof content !== "function") ) {
  547. throw new TypeError("PokeClickerPlus.addPanel takes the following arguments: (id:string, title:string, content:string|function)");
  548. }
  549. const panels = $("#pluginModal");
  550. panels.append(`
  551. <div id="panel-${id}" style="display: none">
  552. <h1>${title}</h1>
  553. <hr>
  554. <div class="pokeclickerplus-panel-content"></div>
  555. </div>
  556. `);
  557. this.panels[id] = {
  558. id: id,
  559. title: title,
  560. content: content
  561. };
  562. this.refreshPanel(id);
  563. }
  564.  
  565. refreshPanel(id) {
  566. if(typeof id !== "string") {
  567. throw new TypeError("PokeClickerPlus.refreshPanel takes the following arguments: (id:string)");
  568. }
  569. const panel = this.panels[id];
  570. if(!panel) {
  571. throw new TypeError(`Error rendering panel with id="${id}" - panel has not be added.`);
  572. }
  573. let content = panel.content;
  574. if(!["string", "function"].includes(typeof content)) {
  575. throw new TypeError(`Error rendering panel with id="${id}" - panel.content must be a string or a function returning a string.`);
  576. }
  577. if(typeof content === "function") {
  578. content = content();
  579. if(typeof content !== "string") {
  580. throw new TypeError(`Error rendering panel with id="${id}" - panel.content must be a string or a function returning a string.`);
  581. }
  582. }
  583. const panelContent = $(`#panel-${id} .pokeclickerplus-panel-content`);
  584. panelContent.html(content);
  585. if(id === "pokeclickerplus") {
  586. this.forEachPlugin(plugin => {
  587. this.loadPluginConfigs(plugin.id);
  588. });
  589. }
  590. }
  591.  
  592. registerPlugin(plugin) {
  593. if(!(plugin instanceof PokeClickerPlusPlugin)) {
  594. throw new TypeError("PokeClickerPlus.registerPlugin takes the following arguments: (plugin:PokeClickerPlusPlugin)");
  595. }
  596. if(plugin.id in this.plugins) {
  597. throw new Error(`PokeClickerPlusPlugin with id "${plugin.id}" is already registered. Make sure your plugin id is unique!`);
  598. }
  599.  
  600. this.plugins[plugin.id] = plugin;
  601. this.loadPluginConfigs(plugin.id);
  602. let versionString = plugin.opts&&plugin.opts.about&&plugin.opts.about.version ? ` (v${plugin.opts.about.version})` : "";
  603. logFancy(`registered plugin "${plugin.id}"${versionString}`);
  604. }
  605.  
  606. forEachPlugin(f) {
  607. if(typeof f !== "function") {
  608. throw new TypeError("PokeClickerPlus.forEachPlugin takes the following arguments: (f:function)");
  609. }
  610. Object.values(this.plugins).forEach(plugin => {
  611. try {
  612. f(plugin);
  613. }
  614. catch(err) {
  615. console.error(`Error occurred while executing function for plugin "${plugin.id}."`);
  616. console.error(err);
  617. }
  618. });
  619. }
  620.  
  621. setPanel(panel) {
  622. if(typeof panel !== "string") {
  623. throw new TypeError("PokeClickerPlus.setPanel takes the following arguments: (panel:string)");
  624. }
  625. window.switch_panels(`panel-${panel}`);
  626. }
  627.  
  628. hideCustomPanels() {
  629. Object.values(this.panels).forEach((panel) => {
  630. const el = $(`#panel-${panel.id}`);
  631. if(el) {
  632. el.css("display", "none");
  633. }
  634. });
  635. }
  636.  
  637. onVariableSet(key, valueBefore, valueAfter) {
  638. if(this.debug) {
  639. console.log(`IP+ onVariableSet "${key}": "${valueBefore}" -> "${valueAfter}"`);
  640. }
  641. this.forEachPlugin((plugin) => {
  642. if(typeof plugin.onVariableSet === "function") {
  643. plugin.onVariableSet(key, valueBefore, valueAfter);
  644. }
  645. });
  646. if(key == "monster_name") {
  647. const combatBefore = !!(valueBefore && valueBefore!="none");
  648. const combatAfter = !!(valueAfter && valueAfter!="none");
  649. if(!combatBefore && combatAfter) {
  650. this.onCombatStart();
  651. }
  652. else if(combatBefore && !combatAfter) {
  653. this.onCombatEnd();
  654. }
  655. }
  656. }
  657.  
  658. onPanelChanged(panelBefore, panelAfter) {
  659. if(this.debug) {
  660. console.log(`IP+ onPanelChanged "${panelBefore}" -> "${panelAfter}"`);
  661. }
  662. if(panelAfter === "pokeclickerplus") {
  663. this.refreshPanel("pokeclickerplus");
  664. }
  665. this.forEachPlugin((plugin) => {
  666. if(typeof plugin.onPanelChanged === "function") {
  667. plugin.onPanelChanged(panelBefore, panelAfter);
  668. }
  669. });
  670. }
  671.  
  672. }
  673.  
  674. // Add to window and init
  675. window.PokeClickerPlusPlugin = PokeClickerPlusPlugin;
  676. window.PokeClickerPlus = new PokeClickerPlus();
  677.  
  678.  
  679. internal.init.call(window.PokeClickerPlus);
  680.  
  681. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址