evolve-helper/evolve-helper.js
2024-12-08 11:25:33 +08:00

217 lines
5.6 KiB
JavaScript

// ==UserScript==
// @name Evolve Helper
// @namespace http://tampermonkey.net/
// @version 2024-12-06
// @description accerlate and automate
// @author liooil
// @match https://pmotschmann.github.io/Evolve/
// @icon https://www.google.com/s2/favicons?sz=64&domain=github.io
// @grant none
// ==/UserScript==
let autoIds = getStrSet("autoIds") ?? new Set();
let vueMethod;
let scanTimer = setInterval(scan, getInt("scanInterval") ?? 1000);
let autoTimer = setInterval(auto, getInt("autoInterval") ?? 100);
function scan() {
const versionLogEl = document.getElementById("versionLog");
if (versionLogEl) {
menuBtn(versionLogEl, "scanInterval", "int", 1000, (val) => {
clearInterval(scanTimer);
scanTimer = setInterval(scan, val);
});
menuBtn(versionLogEl, "autoInterval", "int", 100, (val) => {
clearInterval(autoTimer);
autoTimer = setInterval(scan, val);
});
menuBtn(versionLogEl, "customSpeed", "int", 1, () => {
if (!vueMethod._data.s.pause) {
fromScript = true;
vueMethod.pause();
}
});
menuBtn(versionLogEl, "autoRun", "bool", true);
vueMethod = document.getElementById("topBar").__vue__;
}
for (const node of document.querySelectorAll("div.action.vb")) {
autoBtn(node, node.firstChild);
}
for (const node of document.querySelectorAll("div.resource.crafted")) {
if (node.style.display === "none") continue;
autoBtn(node, node.firstChild);
}
for (const node of document.getElementById("market")?.querySelectorAll("div.market-item") ?? []) {
if (node.style.display === "none") continue;
for (const type of ['buy', 'sell']) {
const span = node.querySelector('span.' + type);
if (!span) continue;
autoBtn(span, span, node.id + '-' + type);
}
}
}
function auto() {
if (!getBool("autoRun")) return;
for (const id of autoIds) {
for (const type of ['buy', 'sell']) {
if (id.endsWith('-' + type)) {
const el = document.getElementById(id.slice(0, -type.length - 1));
if (!el) continue;
const prev = el.querySelector('span.' + type);
if (!prev) continue;
prev.nextElementSibling.click();
}
}
const el = document.getElementById(id);
if (!el || el.classList.contains("cna")) continue;
/** @type {HTMLElement} */
const a = el.querySelector("a.button,a:has(span[data-val='A'])");
if (a) a.click();
}
}
/**
* @param {string} key
* @param {number} defaultVal
*/
function useInt(key, defaultVal) {
let text = localStorage.getItem(key);
let val = text ? parseInt(text) : defaultVal;
return [
() => val,
/** @type {(val: number) => void} */
(v) => {
val = v;
localStorage.setItem(key, v.toString());
}
];
}
/**
* @param {string} key
*/
function getInt(key) {
const val = localStorage.getItem(key);
if (val !== null) return parseFloat(val);
}
/**
* @param {string} key
* @param {number} val
*/
function setInt(key, val) {
localStorage.setItem(key, val)
}
/**
* @param {string} key
*/
function getStrSet(key) {
const val = localStorage.getItem(key);
if (val !== null) return new Set(val.split(","));
}
/**
* @param {string} key
* @param {Set<string>} val
*/
function setStrSet(key, val) {
localStorage.setItem(key, [...val.keys()].join(","))
}
/**
* @param {string} key
*/
function getBool(key) {
const val = localStorage.getItem(key);
if (val !== null) return val === "true";
}
/**
* @param {string} key
* @param {boolean} val
*/
function setBool(key, val) {
localStorage.setItem(key, val.toString());
}
/**
* @param {HTMLElement} nextElementSibling
* @param {string} id
* @param {"int" | "bool"} type
* @param {number} defaultVal
* @param {(val: number) => void} cb
*/
function menuBtn(nextElementSibling, id, type, defaultVal, cb) {
if (document.getElementById(id)) return;
const el = document.createElement("span");
el.id = id;
el.classList.add("version");
el.style.cursor = "pointer";
el.textContent = `${id}=${getInt(id) ?? defaultVal}`;
el.onclick = () => {
let val;
if (type === "bool") {
val = !(getBool(id) ?? defaultVal);
setBool(id, val);
} else {
let input = prompt(`${id}=`, `${getInt(id) ?? defaultVal}`);
if (input === null) return;
val = parseInt(input)
setInt(id, input);
}
el.textContent = `${id}=${val}`;
cb?.(val);
}
nextElementSibling.before(el);
return el;
}
/**
* add auto button
* @param {HTMLElement} root
* @param {HTMLElement?} parent
*/
function autoBtn(root, parent = root, id = root.id) {
/** @type {HTMLButtonElement} */
let auto = root.querySelector(".auto");
if (!auto) {
auto = parent.appendChild(document.createElement("span"));
auto.classList.add("auto");
auto.textContent = "A";
auto.onclick = (e) => {
e.preventDefault();
e.stopPropagation();
if (autoIds.has(id)) {
autoIds.delete(id);
auto.style.color = "gray";
} else {
autoIds.add(id);
auto.style.color = "green";
}
setStrSet("autoIds", autoIds);
}
}
if (autoIds.has(id)) {
auto.style.color = "green";
} else {
auto.style.color = "gray";
}
}
let fromScript = false;
const oldPost = Worker.prototype.postMessage;
Worker.prototype.postMessage = async function (...args) {
let that = this
async function hookPost() {
if (args[0].period) {
args[0].period = args[0].period / (getInt("customSpeed") ?? 1)
}
oldPost.apply(that, args)
}
let hookResult = await hookPost()
if (fromScript) {
vueMethod.pause()
fromScript = false
}
return hookResult
}