// ==UserScript==
// @name Automate Arcanum
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Automates the game arcanum by allowing autoclicking and autocasting
// @author You
// @match https://mathiashjelm.gitlab.io/arcanum/
// @icon https://www.google.com/s2/favicons?sz=64&domain=galaxy.click
// @grant GM_addStyle
// @license MIT
// ==/UserScript==
(function() {
'use strict';
const customStyles = `
.timeInput {
width: 6rem;
background-color: #181818;
border-color: #646464;
color: #D7DADC;
text-align: center;
padding: var(--sm-gap);
margin: var(--sm-gap);
}
.checkbox {
position: relative;
display: inline-block;
width: 1.25em;
height: 1.25em;
background-color: transparent;
border: 1px solid #000;
}
.autoCheck {
margin-left: -1.75em;
margin-top: 1.35em;
}
.quickslotTimer {
width: 3rem;
background-color: #181818;
border-color: #646464;
color: #D7DADC;
text-align: center;
padding: var(--sm-gap);
margin: var(--sm-gap);
height: 2rem;
}
.quickbar {
flex-direction: column;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
`;
const loadClass = "load-message"
let hasLoaded = false;
let actionInterval = 0;
let autocastInterval = 0;
let offMain = false;
let intervalId;
let autoKey;
let quickslotTimers = [];
function beginAutoAction() {
clearInterval(intervalId);
intervalId = setInterval(function() {
const button = document.querySelector(`[data-key="${autoKey}"]`);
if (button) {
button.click();
console.log(`Timer is currently ${actionInterval} and it is clicking ${autoKey}`);
}
}, actionInterval);
}
function stopAutoAction() {
clearInterval(intervalId);
}
function beginAutoQuickslot(timer, index) {
clearInterval(quickslotTimers[index]);
quickslotTimers[index] = setInterval(function() {
const quickslot = document.querySelector(`#slot${index}`);
if (quickslot && quickslot.checked) {
const quickslot = document.getElementsByClassName("quickslot")[index];
quickslot.children[0].click();
console.log(`Clicking the quickslot number ${parseInt(index+1)}`)
}
}, timer * 1000);
}
function stopAutoQuickSlot(index) {
clearInterval(quickslotTimers[index]);
}
function checkOnlyOne(id, n){
const checkboxes = document.getElementsByName(n);
Array.prototype.forEach.call(checkboxes,function(e){
if (e != id) {
e.checked = false;
}
});
}
function pageUpdate() {
const taskList = document.querySelector(".task-list")
if (hasLoaded) {
console.log("Page updated, checking if changes need to be made..");
}
let buttons = taskList.querySelectorAll(".task-btn");
let filteredBtns = Array.from(buttons).filter(button => !button.classList.contains("locked"));
let lockedBtns = Array.from(buttons).filter(button => button.classList.contains("locked"));
let i = 0;
let quickslots = document.querySelector(".quickbar").querySelectorAll(".quickslot").forEach(quickslot => {
if (document.getElementById("slot"+i)) {
return
}
const checkbox = document.createElement("input");
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("name", "quickslot");
checkbox.classList.add("quickCheck");
checkbox.classList.add("checkbox");
checkbox.id = "slot"+i;
checkbox.addEventListener("change", function () {
const checkboxIndex = parseInt(this.id.replace("slot", ""));
if (this.checked) {
beginAutoQuickslot(document.getElementById("timer"+checkboxIndex).value, checkboxIndex);
} else {
stopAutoQuickSlot(checkboxIndex, checkboxIndex);
}
});
const timer = document.createElement("input");
timer.setAttribute("placeholder", "(s)");
timer.addEventListener("input", function(e) {
const inputValue = e.target.value;
const cleanedValue = inputValue
.replace(/[^0-9]+/g, '') // Remove non-numeric and non-dot characters
.replace(/(\..*?)\..*/g, '$1') // Remove multiple dots
.replace(/^0[^.]/, '0'); // Remove leading zero before a non-dot character
if (inputValue !== cleanedValue) {
// If the value was changed, update the input field
e.target.value = cleanedValue;
}
if (e.target.id == "actionTimer") {
actionInterval = e.target.value;
beginAutoAction();
}
if (document.querySelector(`#slot${e.target.id.replace("timer", "")}`).checked) {
console.log(`The current timer value is ${e.target.value}`);
beginAutoQuickslot(e.target.value, e.target.id.replace("timer", ""));
}
});
timer.classList.add("quickslotTimer")
timer.setAttribute("type", "text");
timer.id = `timer${i}`;
quickslot.insertAdjacentElement("afterend", timer);
quickslot.insertAdjacentElement('beforeend', checkbox);
i++;
});
filteredBtns.forEach(button => {
const dataKey = button.getAttribute("data-key")
if (document.getElementById(dataKey)) {
return
}
const checkbox = document.createElement("input");
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("name", "task");
checkbox.classList.add("autoCheck");
checkbox.classList.add("checkbox");
checkbox.addEventListener("change", function() {
if (this.checked && actionInterval != 0) {
autoKey = dataKey;
beginAutoAction();
} else {
stopAutoAction();
}
});
checkbox.id = dataKey
button.insertAdjacentElement('afterend', checkbox);
});
lockedBtns.forEach(button => {
const dataKey = button.getAttribute("data-key");
const checkbox = document.getElementById(dataKey);
if (checkbox) {
checkbox.parentNode.removeChild(checkbox);
}
});
}
function handleDivAppeared(mutationsList) {
for (const mutation of mutationsList) {
if(mutation.type === "childList") {
const addedNodes = Array.from(mutation.addedNodes);
for (const addedNode of addedNodes) {
if (addedNode.classList && addedNode.classList.contains("main-tasks")) {
if (document.querySelector(".main-tasks")) {
offMain = false;
pageUpdate();
}
}
}
}
}
}
function handleDivDisappeared(mutationsList) {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
const removedNodes = Array.from(mutation.removedNodes);
for (const removedNode of removedNodes) {
if (removedNode.classList && removedNode.classList.contains("main-task")){
offMain = true;
}
if (removedNode.classList && removedNode.classList.contains(loadClass)) {
// Save loaded, run script
console.log(`Page loaded, beginning automation.`);
// Inject the custom CSS styles into the page
GM_addStyle(customStyles);
hasLoaded = true;
const timer = document.createElement("input");
timer.classList.add("timeInput");
timer.setAttribute("type", "text");
timer.id = "actionTimer";
const label = document.createElement("label");
label.setAttribute("for", "actionTimer")
label.innerHTML="Action interval (ms):"
document.querySelector(".load-opts").appendChild(timer);
document.querySelector(".load-opts").insertBefore(label, document.getElementById("actionTimer"));
timer.addEventListener("input", function(e) {
const inputValue = e.target.value;
const cleanedValue = inputValue
.replace(/[^0-9]+/g, '') // Remove non-numeric and non-dot characters
.replace(/(\..*?)\..*/g, '$1') // Remove multiple dots
.replace(/^0[^.]/, '0'); // Remove leading zero before a non-dot character
if (inputValue !== cleanedValue) {
// If the value was changed, update the input field
e.target.value = cleanedValue;
}
if (e.target.id == "actionTimer") {
actionInterval = e.target.value;
beginAutoAction();
}
});
pageUpdate();
startClassObserver();
}
}
}
}
}
function startClassObserver() {
const classObserver = new MutationObserver((mutationsList, classObserver) => {
// Handle class attribute changes here
pageUpdate();
});
const classConfig = { attributes: true, attributeFilter: ['class'] };
// Start observing class attribute changes
classObserver.observe(document, classConfig);
}
// Create a MutationObserver that watches for changes in the DOM
const observer = new MutationObserver(handleDivDisappeared);
const observer2 = new MutationObserver(handleDivAppeared);
const config = { childList: true, subtree: true };
// Start observing the DOM
observer.observe(document, config);
observer2.observe(document, config);
document.addEventListener("click", function(e) {
if(e.target.classList.contains("autoCheck")){
checkOnlyOne(e.target, e.target.getAttribute("name"));
}
});
})();