IdlePixel+

Idle-Pixel plugin framework

当前为 2022-07-09 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/441206/1068458/IdlePixel%2B.js

  1. // ==UserScript==
  2. // @name IdlePixel+
  3. // @namespace com.anwinity.idlepixel
  4. // @version 0.2.0
  5. // @description Idle-Pixel plugin framework
  6. // @author Anwinity
  7. // @match *://idle-pixel.com/login/play*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. const CONFIG_TYPES_LABEL = ["label"];
  15. const CONFIG_TYPES_BOOLEAN = ["boolean", "bool", "checkbox"];
  16. const CONFIG_TYPES_INTEGER = ["integer", "int"];
  17. const CONFIG_TYPES_FLOAT = ["number", "num", "float"];
  18. const CONFIG_TYPES_STRING = ["string", "text"];
  19. const CONFIG_TYPES_SELECT = ["select"];
  20. const CONFIG_TYPES_COLOR = ["color"];
  21.  
  22. const INFO = {
  23. ores: {
  24. stone: {
  25. id: "stone",
  26. smeltable: false,
  27. oil: 0,
  28. bar: null,
  29. sellsFor: 1,
  30. miningXP: 0.1
  31. },
  32. copper: {
  33. id: "copper",
  34. smeltable: true,
  35. oil: 1,
  36. bar: "bronze_bar",
  37. sellsFor: 2,
  38. miningXP: 1
  39. },
  40. iron: {
  41. id: "iron",
  42. smeltable: true,
  43. oil: 5,
  44. bar: "iron_bar",
  45. sellsFor: 3,
  46. miningXP: 5
  47. },
  48. silver: {
  49. id: "silver",
  50. smeltable: true,
  51. oil: 20,
  52. bar: "silver_bar",
  53. sellsFor: 5,
  54. miningXP: 10
  55. },
  56. gold: {
  57. id: "gold",
  58. smeltable: true,
  59. oil: 100,
  60. bar: "gold_bar",
  61. sellsFor: 10,
  62. miningXP: 20
  63. },
  64. promethium: {
  65. id: "promethium",
  66. smeltable: false,
  67. oil: 0,
  68. bar: "promethium_bar",
  69. sellsFor: 90,
  70. miningXP: 100
  71. }
  72. },
  73. bars: {
  74. bronze_bar: {
  75. id: "bronze_bar",
  76. sellsFor: 3,
  77. craftingXP: 5
  78. },
  79. iron_bar: {
  80. id: "iron_bar",
  81. sellsFor: 5,
  82. craftingXP: 25
  83. },
  84. silver_bar: {
  85. id: "silver_bar",
  86. sellsFor: 10,
  87. craftingXP: 50
  88. },
  89. gold_bar: {
  90. id: "gold_bar",
  91. sellsFor: 50,
  92. craftingXP: 100
  93. },
  94. promethium_bar: {
  95. id: "promethium_bar",
  96. sellsFor: 1000,
  97. craftingXP: 500
  98. }
  99. },
  100. seeds: {
  101. dotted_green_leaf_seeds: {
  102. id: "dotted_green_leaf_seeds",
  103. level: 1,
  104. stopsDying: 15,
  105. time: 15,
  106. bonemealCost: 0
  107. },
  108. green_leaf_seeds: {
  109. id: "green_leaf_seeds",
  110. level: 15,
  111. stopsDying: 30,
  112. time: 30,
  113. bonemealCost: 0
  114. },
  115. lime_leaf_seeds: {
  116. id: "lime_leaf_seeds",
  117. level: 30,
  118. stopsDying: 40,
  119. time: 1*60,
  120. bonemealCost: 1
  121. },
  122. gold_leaf_seeds: {
  123. id: "gold_leaf_seeds",
  124. level: 50,
  125. stopsDying: 60,
  126. time: 2*60,
  127. bonemealCost: 10
  128. },
  129. crystal_leaf_seeds: {
  130. id: "crystal_leaf_seeds",
  131. level: 70,
  132. stopsDying: 80,
  133. time: 5*60,
  134. bonemealCost: 25
  135. },
  136. red_mushroom_seeds: {
  137. id: "red_mushroom_seeds",
  138. level: 1,
  139. stopsDying: 5,
  140. time: 5,
  141. bonemealCost: 0
  142. },
  143. tree_seeds: {
  144. id: "tree_seeds",
  145. level: 10,
  146. stopsDying: 25,
  147. time: 5*60,
  148. bonemealCost: 10
  149. },
  150. oak_tree_seeds: {
  151. id: "oak_tree_seeds",
  152. level: 25,
  153. stopsDying: 40,
  154. time: 8*60,
  155. bonemealCost: 25
  156. },
  157. willow_tree_seeds: {
  158. id: "willow_tree_seeds",
  159. level: 37,
  160. stopsDying: 55,
  161. time: 12*60,
  162. bonemealCost: 50
  163. },
  164. maple_tree_seeds: {
  165. id: "maple_tree_seeds",
  166. level: 50,
  167. stopsDying: 65,
  168. time: 15*60,
  169. bonemealCost: 120
  170. }
  171. },
  172. combatZones: {
  173. field: {
  174. id: "field",
  175. energyCost: 50,
  176. fightPointCost: 300
  177. },
  178. forest: {
  179. id: "forest",
  180. energyCost: 200,
  181. fightPointCost: 600
  182. },
  183. cave: {
  184. id: "cave",
  185. energyCost: 500,
  186. fightPointCost: 900
  187. },
  188. volcano: {
  189. id: "volcano",
  190. energyCost: 2000,
  191. fightPointCost: 1500
  192. }
  193. },
  194. spellManaCost: {
  195. heal: 2
  196. }
  197. };
  198.  
  199. if(window.IdlePixelPlus) {
  200. // already loaded
  201. return;
  202. }
  203.  
  204. class IdlePixelPlusPlugin {
  205.  
  206. constructor(id, opts) {
  207. if(typeof id !== "string") {
  208. throw new TypeError("IdlePixelPlusPlugin constructor takes the following arguments: (id:string, opts?:object)");
  209. }
  210. this.id = id;
  211. this.opts = opts || {};
  212. this.config = null;
  213. }
  214.  
  215. getConfig(name) {
  216. if(!this.config) {
  217. IdlePixelPlus.loadPluginConfigs(this.id);
  218. }
  219. if(this.config) {
  220. return this.config[name];
  221. }
  222. }
  223.  
  224. /*
  225. onConfigsChanged() { }
  226. onLogin() { }
  227. onMessageReceived(data) { }
  228. onVariableSet(key, valueBefore, valueAfter) { }
  229. onChat(data) { }
  230. onPanelChanged(panelBefore, panelAfter) { }
  231. onCombatStart() { }
  232. onCombatEnd() { }
  233. */
  234.  
  235. }
  236.  
  237. const internal = {
  238. init() {
  239. const self = this;
  240.  
  241. // hook into websocket messages
  242. const original_open_websocket = window.open_websocket;
  243. window.open_websocket = function() {
  244. original_open_websocket.apply(this, arguments);
  245. const original_onmessage = window.websocket.websocket.onmessage;
  246. window.websocket.websocket.onmessage = function(event) {
  247. original_onmessage.apply(window.websocket.websocket, arguments);
  248. self.onMessageReceived(event.data);
  249. }
  250. }
  251.  
  252. // hook into Items.set, which is where var_ values are set
  253. const original_items_set = Items.set;
  254. Items.set = function(key, value) {
  255. let valueBefore = window["var_"+key];
  256. original_items_set.apply(this, arguments);
  257. let valueAfter = window["var_"+key];
  258. self.onVariableSet(key, valueBefore, valueAfter);
  259. }
  260.  
  261. // hook into switch_panels, which is called when the main panel is changed. This is also used for custom panels.
  262. const original_switch_panels = window.switch_panels;
  263. window.switch_panels = function(id) {
  264. let panelBefore = Globals.currentPanel;
  265. if(panelBefore && panelBefore.startsWith("panel-")) {
  266. panelBefore = panelBefore.substring("panel-".length);
  267. }
  268. self.hideCustomPanels();
  269. original_switch_panels.apply(this, arguments);
  270. let panelAfter = Globals.currentPanel;
  271. if(panelAfter && panelAfter.startsWith("panel-")) {
  272. panelAfter = panelAfter.substring("panel-".length);
  273. }
  274. self.onPanelChanged(panelBefore, panelAfter);
  275. }
  276.  
  277. // create plugin menu item and panel
  278. const lastMenuItem = $("#menu-bar-buttons > .hover-menu-bar-item").last();
  279. lastMenuItem.after(`
  280. <div onclick="IdlePixelPlus.setPanel('idlepixelplus')" class="hover hover-menu-bar-item">
  281. <img id="menu-bar-idlepixelplus-icon" src="https://anwinity.com/idlepixelplus/plugins.png"> PLUGINS
  282. </div>
  283. `);
  284. self.addPanel("idlepixelplus", "IdlePixel+ Plugins", function() {
  285. let content = `
  286. <style>
  287. .idlepixelplus-plugin-box {
  288. display: block;
  289. position: relative;
  290. padding: 0.25em;
  291. color: white;
  292. background-color: rgb(107, 107, 107);
  293. border: 1px solid black;
  294. border-radius: 6px;
  295. margin-bottom: 0.5em;
  296. }
  297. .idlepixelplus-plugin-box .idlepixelplus-plugin-settings-button {
  298. position: absolute;
  299. right: 2px;
  300. top: 2px;
  301. cursor: pointer;
  302. }
  303. .idlepixelplus-plugin-box .idlepixelplus-plugin-config-section {
  304. display: grid;
  305. grid-template-columns: minmax(100px, min-content) 1fr;
  306. row-gap: 0.5em;
  307. column-gap: 0.5em;
  308. white-space: nowrap;
  309. }
  310. </style>
  311. `;
  312. self.forEachPlugin(plugin => {
  313. let id = plugin.id;
  314. let name = "An IdlePixel+ Plugin!";
  315. let description = "";
  316. let author = "unknown";
  317. if(plugin.opts.about) {
  318. let about = plugin.opts.about;
  319. name = about.name || name;
  320. description = about.description || description;
  321. author = about.author || author;
  322. }
  323. content += `
  324. <div id="idlepixelplus-plugin-box-${id}" class="idlepixelplus-plugin-box">
  325. <strong><u>${name||id}</u></strong> (by ${author})<br />
  326. <span>${description}</span><br />
  327. <div class="idlepixelplus-plugin-config-section" style="display: none">
  328. <hr style="grid-column: span 2">
  329. `;
  330. if(plugin.opts.config && Array.isArray(plugin.opts.config)) {
  331. plugin.opts.config.forEach(cfg => {
  332. if(CONFIG_TYPES_LABEL.includes(cfg.type)) {
  333. content += `<h5 style="grid-column: span 2; margin-bottom: 0; font-weight: 600">${cfg.label}</h5>`;
  334. }
  335. else if(CONFIG_TYPES_BOOLEAN.includes(cfg.type)) {
  336. content += `
  337. <div>
  338. <label for="idlepixelplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  339. </div>
  340. <div>
  341. <input id="idlepixelplus-config-${plugin.id}-${cfg.id}" type="checkbox" onchange="IdlePixelPlus.setPluginConfigUIDirty('${id}', true)" />
  342. </div>
  343. `;
  344. }
  345. else if(CONFIG_TYPES_INTEGER.includes(cfg.type)) {
  346. content += `
  347. <div>
  348. <label for="idlepixelplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  349. </div>
  350. <div>
  351. <input id="idlepixelplus-config-${plugin.id}-${cfg.id}" type="number" step="1" min="${cfg.min || ''}" max="${cfg.max || ''}" onchange="IdlePixelPlus.setPluginConfigUIDirty('${id}', true)" />
  352. </div>
  353. `;
  354. }
  355. else if(CONFIG_TYPES_FLOAT.includes(cfg.type)) {
  356. content += `
  357. <div>
  358. <label for="idlepixelplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  359. </div>
  360. <div>
  361. <input id="idlepixelplus-config-${plugin.id}-${cfg.id}" type="number" step="${cfg.step || ''}" min="${cfg.min || ''}" max="${cfg.max || ''}" onchange="IdlePixelPlus.setPluginConfigUIDirty('${id}', true)" />
  362. </div>
  363. `;
  364. }
  365. else if(CONFIG_TYPES_STRING.includes(cfg.type)) {
  366. content += `
  367. <div>
  368. <label for="idlepixelplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  369. </div>
  370. <div>
  371. <input id="idlepixelplus-config-${plugin.id}-${cfg.id}" type="text" maxlength="${cfg.max || ''}" onchange="IdlePixelPlus.setPluginConfigUIDirty('${id}', true)" />
  372. </div>
  373. `;
  374. }
  375. else if(CONFIG_TYPES_COLOR.includes(cfg.type)) {
  376. content += `
  377. <div>
  378. <label for="idlepixelplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  379. </div>
  380. <div>
  381. <input id="idlepixelplus-config-${plugin.id}-${cfg.id}" type="color" onchange="IdlePixelPlus.setPluginConfigUIDirty('${id}', true)" />
  382. </div>
  383. `;
  384. }
  385. else if(CONFIG_TYPES_SELECT.includes(cfg.type)) {
  386. content += `
  387. <div>
  388. <label for="idlepixelplus-config-${plugin.id}-${cfg.id}">${cfg.label || cfg.id}</label>
  389. </div>
  390. <div>
  391. <select id="idlepixelplus-config-${plugin.id}-${cfg.id}" onchange="IdlePixelPlus.setPluginConfigUIDirty('${id}', true)">
  392. `;
  393. if(cfg.options && Array.isArray(cfg.options)) {
  394. cfg.options.forEach(option => {
  395. if(typeof option === "string") {
  396. content += `<option value="${option}">${option}</option>`;
  397. }
  398. else {
  399. content += `<option value="${option.value}">${option.label || option.value}</option>`;
  400. }
  401. });
  402. }
  403. content += `
  404. </select>
  405. </div>
  406. `;
  407. }
  408. });
  409. content += `
  410. <div style="grid-column: span 2">
  411. <button id="idlepixelplus-configbutton-${plugin.id}-reload" onclick="IdlePixelPlus.loadPluginConfigs('${id}')">Reload</button>
  412. <button id="idlepixelplus-configbutton-${plugin.id}-apply" onclick="IdlePixelPlus.savePluginConfigs('${id}')">Apply</button>
  413. </div>
  414. `;
  415. }
  416. content += "</div>";
  417. if(plugin.opts.config) {
  418. content += `
  419. <div class="idlepixelplus-plugin-settings-button">
  420. <button onclick="$('#idlepixelplus-plugin-box-${id} .idlepixelplus-plugin-config-section').toggle()">Settings</button>
  421. </div>`;
  422. }
  423. content += "</div>";
  424. });
  425.  
  426. return content;
  427. });
  428.  
  429. console.log(`IdlePixelPlus (v${self.version}) initialized.`);
  430. }
  431. };
  432.  
  433. class IdlePixelPlus {
  434.  
  435. constructor() {
  436. this.version = GM_info.script.version;
  437. this.plugins = {};
  438. this.panels = {};
  439. this.debug = false;
  440. this.info = INFO;
  441. }
  442.  
  443. getVar(name, type) {
  444. let s = window[`var_${name}`];
  445. if(type) {
  446. switch(type) {
  447. case "int":
  448. case "integer":
  449. return parseInt(s);
  450. case "number":
  451. case "float":
  452. return parseFloat(s);
  453. case "boolean":
  454. case "bool":
  455. if(s=="true") return true;
  456. if(s=="false") return false;
  457. return undefined;
  458. }
  459. }
  460. return s;
  461. }
  462.  
  463. getVarOrDefault(name, defaultValue, type) {
  464. let s = window[`var_${name}`];
  465. if(s==null || typeof s === "undefined") {
  466. return defaultValue;
  467. }
  468. if(type) {
  469. let value;
  470. switch(type) {
  471. case "int":
  472. case "integer":
  473. value = parseInt(s);
  474. return isNaN(value) ? defaultValue : value;
  475. case "number":
  476. case "float":
  477. value = parseFloat(s);
  478. return isNaN(value) ? defaultValue : value;
  479. case "boolean":
  480. case "bool":
  481. if(s=="true") return true;
  482. if(s=="false") return false;
  483. return defaultValue;
  484. }
  485. }
  486. return s;
  487. }
  488.  
  489. setPluginConfigUIDirty(id, dirty) {
  490. if(typeof id !== "string" || typeof dirty !== "boolean") {
  491. throw new TypeError("IdlePixelPlus.setPluginConfigUIDirty takes the following arguments: (id:string, dirty:boolean)");
  492. }
  493. const plugin = this.plugins[id];
  494. const button = $(`#idlepixelplus-configbutton-${plugin.id}-apply`);
  495. if(button) {
  496. button.prop("disabled", !(dirty));
  497. }
  498. }
  499.  
  500. loadPluginConfigs(id) {
  501. if(typeof id !== "string") {
  502. throw new TypeError("IdlePixelPlus.reloadPluginConfigs takes the following arguments: (id:string)");
  503. }
  504. const plugin = this.plugins[id];
  505. const config = {};
  506. let stored;
  507. try {
  508. stored = JSON.parse(localStorage.getItem(`idlepixelplus.${id}.config`) || "{}");
  509. }
  510. catch(err) {
  511. console.error(`Failed to load configs for plugin with id "${id} - will use defaults instead."`);
  512. stored = {};
  513. }
  514. if(plugin.opts.config && Array.isArray(plugin.opts.config)) {
  515. plugin.opts.config.forEach(cfg => {
  516. const el = $(`#idlepixelplus-config-${plugin.id}-${cfg.id}`);
  517. let value = stored[cfg.id];
  518. if(value==null || typeof value === "undefined") {
  519. value = cfg.default;
  520. }
  521. config[cfg.id] = value;
  522.  
  523. if(el) {
  524. if(CONFIG_TYPES_BOOLEAN.includes(cfg.type) && typeof value === "boolean") {
  525. el.prop("checked", value);
  526. }
  527. else if(CONFIG_TYPES_INTEGER.includes(cfg.type) && typeof value === "number") {
  528. el.val(value);
  529. }
  530. else if(CONFIG_TYPES_FLOAT.includes(cfg.type) && typeof value === "number") {
  531. el.val(value);
  532. }
  533. else if(CONFIG_TYPES_STRING.includes(cfg.type) && typeof value === "string") {
  534. el.val(value);
  535. }
  536. else if(CONFIG_TYPES_SELECT.includes(cfg.type) && typeof value === "string") {
  537. el.val(value);
  538. }
  539. else if(CONFIG_TYPES_COLOR.includes(cfg.type) && typeof value === "string") {
  540. el.val(value);
  541. }
  542. }
  543. });
  544. }
  545. plugin.config = config;
  546. this.setPluginConfigUIDirty(id, false);
  547. if(typeof plugin.onConfigsChanged === "function") {
  548. plugin.onConfigsChanged();
  549. }
  550. }
  551.  
  552. savePluginConfigs(id) {
  553. if(typeof id !== "string") {
  554. throw new TypeError("IdlePixelPlus.savePluginConfigs takes the following arguments: (id:string)");
  555. }
  556. const plugin = this.plugins[id];
  557. const config = {};
  558. if(plugin.opts.config && Array.isArray(plugin.opts.config)) {
  559. plugin.opts.config.forEach(cfg => {
  560. const el = $(`#idlepixelplus-config-${plugin.id}-${cfg.id}`);
  561. let value;
  562. if(CONFIG_TYPES_BOOLEAN.includes(cfg.type)) {
  563. config[cfg.id] = el.is(":checked");
  564. }
  565. else if(CONFIG_TYPES_INTEGER.includes(cfg.type)) {
  566. config[cfg.id] = parseInt(el.val());
  567. }
  568. else if(CONFIG_TYPES_FLOAT.includes(cfg.type)) {
  569. config[cfg.id] = parseFloat(el.val());
  570. }
  571. else if(CONFIG_TYPES_STRING.includes(cfg.type)) {
  572. config[cfg.id] = el.val();
  573. }
  574. else if(CONFIG_TYPES_SELECT.includes(cfg.type)) {
  575. config[cfg.id] = el.val();
  576. }
  577. else if(CONFIG_TYPES_COLOR.includes(cfg.type)) {
  578. config[cfg.id] = el.val();
  579. }
  580. });
  581. }
  582. plugin.config = config;
  583. localStorage.setItem(`idlepixelplus.${id}.config`, JSON.stringify(config));
  584. this.setPluginConfigUIDirty(id, false);
  585. if(typeof plugin.onConfigsChanged === "function") {
  586. plugin.onConfigsChanged();
  587. }
  588. }
  589.  
  590. addPanel(id, title, content) {
  591. if(typeof id !== "string" || typeof title !== "string" || (typeof content !== "string" && typeof content !== "function") ) {
  592. throw new TypeError("IdlePixelPlus.addPanel takes the following arguments: (id:string, title:string, content:string|function)");
  593. }
  594. const panels = $("#panels");
  595. panels.append(`
  596. <div id="panel-${id}" style="display: none">
  597. <h1>${title}</h1>
  598. <hr>
  599. <div class="idlepixelplus-panel-content"></div>
  600. </div>
  601. `);
  602. this.panels[id] = {
  603. id: id,
  604. title: title,
  605. content: content
  606. };
  607. this.refreshPanel(id);
  608. }
  609.  
  610. refreshPanel(id) {
  611. if(typeof id !== "string") {
  612. throw new TypeError("IdlePixelPlus.refreshPanel takes the following arguments: (id:string)");
  613. }
  614. const panel = this.panels[id];
  615. if(!panel) {
  616. throw new TypeError(`Error rendering panel with id="${id}" - panel has not be added.`);
  617. }
  618. let content = panel.content;
  619. if(!["string", "function"].includes(typeof content)) {
  620. throw new TypeError(`Error rendering panel with id="${id}" - panel.content must be a string or a function returning a string.`);
  621. }
  622. if(typeof content === "function") {
  623. content = content();
  624. if(typeof content !== "string") {
  625. throw new TypeError(`Error rendering panel with id="${id}" - panel.content must be a string or a function returning a string.`);
  626. }
  627. }
  628. const panelContent = $(`#panel-${id} .idlepixelplus-panel-content`);
  629. panelContent.html(content);
  630. if(id === "idlepixelplus") {
  631. this.forEachPlugin(plugin => {
  632. this.loadPluginConfigs(plugin.id);
  633. });
  634. }
  635. }
  636.  
  637. registerPlugin(plugin) {
  638. if(!(plugin instanceof IdlePixelPlusPlugin)) {
  639. throw new TypeError("IdlePixelPlus.registerPlugin takes the following arguments: (plugin:IdlePixelPlusPlugin)");
  640. }
  641. if(plugin.id in this.plugins) {
  642. throw new Error(`IdlePixelPlusPlugin with id "${plugin.id}" is already registered. Make sure your plugin id is unique!`);
  643. }
  644.  
  645. // TODO: easy config system
  646. // TODO: custom panels
  647.  
  648. this.plugins[plugin.id] = plugin;
  649. this.loadPluginConfigs(plugin.id);
  650. console.log(`IdlePixelPlus registered plugin "${plugin.id}"`);
  651. }
  652.  
  653. forEachPlugin(f) {
  654. if(typeof f !== "function") {
  655. throw new TypeError("IdlePixelPlus.forEachPlugin takes the following arguments: (f:function)");
  656. }
  657. Object.values(this.plugins).forEach(plugin => {
  658. try {
  659. f(plugin);
  660. }
  661. catch(err) {
  662. console.error(`Error occurred while executing function for plugin "${plugin.id}."`);
  663. console.error(err);
  664. }
  665. });
  666. }
  667.  
  668. setPanel(panel) {
  669. if(typeof panel !== "string") {
  670. throw new TypeError("IdlePixelPlus.setPanel takes the following arguments: (panel:string)");
  671. }
  672. window.switch_panels(`panel-${panel}`);
  673. }
  674.  
  675. sendMessage(message) {
  676. if(typeof message !== "string") {
  677. throw new TypeError("IdlePixelPlus.sendMessage takes the following arguments: (message:string)");
  678. }
  679. if(window.websocket && window.websocket.websocket && window.websocket.websocket.readyState==1) {
  680. window.websocket.websocket.send(message);
  681. }
  682. }
  683.  
  684. showToast(title, content) {
  685. show_toast(title, content);
  686. }
  687.  
  688. hideCustomPanels() {
  689. Object.values(this.panels).forEach((panel) => {
  690. const el = $(`#panel-${panel.id}`);
  691. if(el) {
  692. el.css("display", "none");
  693. }
  694. });
  695. }
  696.  
  697. onMessageReceived(data) {
  698. if(this.debug) {
  699. console.log(`IP+ onMessageReceived: ${data}`);
  700. }
  701. if(data) {
  702. this.forEachPlugin((plugin) => {
  703. if(typeof plugin.onMessageReceived === "function") {
  704. plugin.onMessageReceived(data);
  705. }
  706. });
  707. if(data.startsWith("VALID_LOGIN")) {
  708. this.onLogin();
  709. }
  710. else if(data.startsWith("CHAT=")) {
  711. const split = data.substring("CHAT=".length).split("~");
  712. const chatData = {
  713. username: split[0],
  714. tag: split[1],
  715. sigil: split[2],
  716. level: parseInt(split[3]),
  717. message: split[4]
  718. };
  719. this.onChat(chatData);
  720. // CHAT=anwinity~none~none~1565~test
  721. }
  722. }
  723. }
  724.  
  725. onCombatStart() {
  726. if(this.debug) {
  727. console.log(`IP+ onCombatStart`);
  728. }
  729. this.forEachPlugin((plugin) => {
  730. if(typeof plugin.onCombatStart === "function") {
  731. plugin.onCombatStart();
  732. }
  733. });
  734. }
  735.  
  736. onCombatEnd() {
  737. if(this.debug) {
  738. console.log(`IP+ onCombatEnd`);
  739. }
  740. this.forEachPlugin((plugin) => {
  741. if(typeof plugin.onCombatEnd === "function") {
  742. plugin.onCombatEnd();
  743. }
  744. });
  745. }
  746.  
  747. onLogin() {
  748. if(this.debug) {
  749. console.log(`IP+ onLogin`);
  750. }
  751. this.forEachPlugin((plugin) => {
  752. if(typeof plugin.onLogin === "function") {
  753. plugin.onLogin();
  754. }
  755. });
  756. }
  757.  
  758. onVariableSet(key, valueBefore, valueAfter) {
  759. if(this.debug) {
  760. console.log(`IP+ onVariableSet "${key}": "${valueBefore}" -> "${valueAfter}"`);
  761. }
  762. this.forEachPlugin((plugin) => {
  763. if(typeof plugin.onVariableSet === "function") {
  764. plugin.onVariableSet(key, valueBefore, valueAfter);
  765. }
  766. });
  767. if(key == "monster_name") {
  768. const combatBefore = !!(valueBefore && valueBefore!="none");
  769. const combatAfter = !!(valueAfter && valueAfter!="none");
  770. if(!combatBefore && combatAfter) {
  771. this.onCombatStart();
  772. }
  773. else if(combatBefore && !combatAfter) {
  774. this.onCombatEnd();
  775. }
  776. }
  777. }
  778.  
  779. onChat(data) {
  780. if(this.debug) {
  781. console.log(`IP+ onChat`, data);
  782. }
  783. this.forEachPlugin((plugin) => {
  784. if(typeof plugin.onChat === "function") {
  785. plugin.onChat(data);
  786. }
  787. });
  788. }
  789.  
  790. onPanelChanged(panelBefore, panelAfter) {
  791. if(this.debug) {
  792. console.log(`IP+ onPanelChanged "${panelBefore}" -> "${panelAfter}"`);
  793. }
  794. if(panelAfter === "idlepixelplus") {
  795. this.refreshPanel("idlepixelplus");
  796. }
  797. this.forEachPlugin((plugin) => {
  798. if(typeof plugin.onPanelChanged === "function") {
  799. plugin.onPanelChanged(panelBefore, panelAfter);
  800. }
  801. });
  802. }
  803.  
  804. }
  805.  
  806. // Add to window and init
  807. window.IdlePixelPlusPlugin = IdlePixelPlusPlugin;
  808. window.IdlePixelPlus = new IdlePixelPlus();
  809. internal.init.call(window.IdlePixelPlus);
  810.  
  811. })();