Created
October 1, 2024 15:20
-
-
Save sudofox/d7695d09277b33fbb6484bd52e5542ce to your computer and use it in GitHub Desktop.
A helper script for the Universal Paperclips game. Eventually it might play the game for you.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Universal Paperclips Helper | |
// @namespace universal-paperclips-helper | |
// @description A helper script for the Universal Paperclips game. Eventually it might play the game for you. | |
// @include https://www.decisionproblem.com/paperclips/index2.html | |
// @version 12 | |
// @grant none | |
// @author sudofox, takayatodorokif1 | |
// ==/UserScript== | |
// Helper function definitions | |
const getEl = id => document.getElementById(id); | |
const clickEl = id => getEl(id) && getEl(id).click(); | |
const checkOpsMaxed = () => operations >= (memory * 1000); | |
// Create and inject helper UI | |
const helperDiv = document.createElement("div"); | |
helperDiv.id = "helper"; | |
helperDiv.style.cssText = "float: left; width: 250px; padding: 10px; border: 1px solid #000; background-color: #f9f9f9;"; | |
helperDiv.innerHTML = ` | |
<b>Helper</b> | |
<div style="margin-bottom: 10px;"> | |
<label><input id='autoFireClipper' type='checkbox' checked> Autofire 'Make Paperclip'</label><br> | |
<label><input id='autoQuantum' type='checkbox' checked> Smart Quantum Ops</label><br> | |
<label><input id='autoTournaments' type='checkbox' checked> Autostart Tournaments</label><br> | |
<label><input id='startTournamentsAtMaxOps' type='checkbox' checked> Start Tournaments at Max Ops</label><br> | |
</div> | |
<div style="margin-bottom: 10px;"> | |
<label><input id='autoEntertain' type='checkbox' checked> Auto-Entertain Swarm</label><br> | |
<label><input id='autoSpendGifts' type='checkbox'> Auto-Spend Swarm Gifts on Processors</label><br> | |
<label><input id='autoFireProbe' type='checkbox'> Autofire Launch Probe</label><br> | |
</div> | |
<div style="margin-bottom: 10px;"> | |
<label><input id='autoBuyWire' type='checkbox'> Auto-Buy Wire</label><br> | |
<label><input id='keepAlive' type='checkbox'> Keep Page Alive</label> | |
</div> | |
<button id="autoProcessorMemory">Auto Processors to 5, Memory to 10</button> | |
<button id="autoMemoryTo250">Auto Memory to 250</button> | |
<button id="cancelAutoAllocation">Cancel Auto Allocation</button> | |
`; | |
document.getElementById("page").appendChild(helperDiv); | |
// Ensure the tournament logic works correctly and disable the 'Start Tournaments at Max Ops' when 'Autostart Tournaments' is unchecked | |
function updateTournamentOptions() { | |
const autostartCheckbox = getEl("autoTournaments"); | |
const maxOpsCheckbox = getEl("startTournamentsAtMaxOps"); | |
if (!autostartCheckbox.checked) { | |
maxOpsCheckbox.disabled = true; | |
maxOpsCheckbox.parentElement.style.opacity = 0.5; // Reduce opacity for visual feedback | |
} else { | |
maxOpsCheckbox.disabled = false; | |
maxOpsCheckbox.parentElement.style.opacity = 1; | |
} | |
} | |
// Add event listener to check for changes to 'Autostart Tournaments' | |
getEl("autoTournaments").addEventListener('change', updateTournamentOptions); | |
updateTournamentOptions(); // Initial call to ensure correct state | |
let quantumDelay = 3; | |
let titleAnimationIndex = 0; | |
const titlePatterns = ["[🖇=======]", "[=🖇======]", "[==🖇=====]", "[===🖇====]", "[====🖇===]", "[=====🖇==]", "[======🖇=]", "[=======🖇]", "[======🖇=]", "[=====🖇==]", "[====🖇===]", "[===🖇====]", "[==🖇=====]", "[=🖇======]"]; | |
// Store the interval IDs | |
let autoProcMemInterval, autoMemTo250Interval; | |
let autoProcMemActive = false; | |
let autoMemTo250Active = false; | |
// Auto Processor and Memory Function | |
function autoProcessorMemory() { | |
if (!autoProcMemActive) { | |
autoProcMemActive = true; | |
autoProcMemInterval = setInterval(() => { | |
const processors = parseInt(getEl("processors").innerText); | |
const memory = parseInt(getEl("memory").innerText); | |
if (processors < 5 && isElementVisibleAndEnabled("btnAddProc")) { | |
clickEl("btnAddProc"); | |
} else if (memory < 10 && isElementVisibleAndEnabled("btnAddMem")) { | |
clickEl("btnAddMem"); | |
} | |
if (processors >= 5 && memory >= 10) { | |
clearInterval(autoProcMemInterval); | |
autoProcMemActive = false; // Stop when both conditions are satisfied | |
} | |
}, 100); // Check every 100ms | |
} | |
} | |
// Auto Memory to 250 Function | |
function autoMemoryTo250() { | |
if (!autoMemTo250Active) { | |
autoMemTo250Active = true; | |
autoMemTo250Interval = setInterval(() => { | |
const memory = parseInt(getEl("memory").innerText); | |
if (memory < 250 && isElementVisibleAndEnabled("btnAddMem")) { | |
clickEl("btnAddMem"); | |
} | |
if (memory >= 250) { | |
clearInterval(autoMemTo250Interval); | |
autoMemTo250Active = false; // Stop when memory reaches 250 | |
} | |
}, 100); // Check every 100ms | |
} | |
} | |
// Cancel Auto Allocation Button | |
function cancelAutoAllocation() { | |
if (autoProcMemInterval) { | |
clearInterval(autoProcMemInterval); | |
autoProcMemActive = false; | |
} | |
if (autoMemTo250Interval) { | |
clearInterval(autoMemTo250Interval); | |
autoMemTo250Active = false; | |
} | |
} | |
getEl("cancelAutoAllocation").addEventListener('click', cancelAutoAllocation); | |
getEl("autoProcessorMemory").addEventListener('click', autoProcessorMemory); | |
getEl("autoMemoryTo250").addEventListener('click', autoMemoryTo250); | |
// Helper Functions for Auto Tasks | |
function autohelper() { | |
if (getEl("autoEntertain").checked && isElementVisibleAndEnabled("btnEntertainSwarm")) clickEl("btnEntertainSwarm"); | |
if (getEl("autoTournaments").checked && getEl("tournamentManagement").style.display === "" && (!getEl("startTournamentsAtMaxOps").checked || checkOpsMaxed())) { | |
getEl("stratPicker").selectedIndex = getEl("stratPicker").childElementCount - 1; | |
clickEl("btnNewTournament"); | |
clickEl("btnRunTournament"); | |
} | |
if (getEl("keepAlive").checked) { | |
keepPageAlive(); | |
} | |
} | |
// Tasks that should run as fast as possible | |
function fastTasks() { | |
if (getEl("autoFireClipper").checked) clickEl("btnMakePaperclip"); | |
if (getEl("autoSpendGifts").checked && isElementVisibleAndEnabled("btnAddProc")) clickEl("btnAddProc"); | |
if (getEl("autoFireProbe").checked && isElementVisibleAndEnabled("btnMakeProbe")) { | |
clickEl("btnMakeProbe"); | |
} | |
if (getEl("autoBuyWire").checked && isElementVisibleAndEnabled("btnBuyWire")) { | |
clickEl("btnBuyWire"); | |
} | |
if (getEl("autoQuantum").checked) { | |
autoQuantum(); | |
} | |
} | |
function autoQuantum() { | |
quantumDelay--; | |
if (qCompDisplayValue() > 0) quantumDelay = 0; | |
if (quantumDelay <= 0) { | |
clickEl("btnQcompute"); | |
if (qCompDisplayValue() <= 0) { | |
quantumDelay = 2 - qCompDisplayValue() * 3; | |
} else { | |
quantumDelay = 1; | |
} | |
} | |
} | |
function qCompDisplayValue() { | |
return parseInt(getEl("qCompDisplay").childNodes[0].nodeValue.substr(6, 20)); | |
} | |
function isElementVisibleAndEnabled(id) { | |
const el = getEl(id); | |
// Check if the element exists | |
if (!el) return false; | |
// Check if the element is hidden or disabled | |
if (el.style.display === "none" || el.disabled) return false; | |
// Check computed style visibility | |
const style = window.getComputedStyle(el); | |
if (style.visibility === "hidden" || style.display === "none") return false; | |
// Recursively check if any parent element is hidden | |
let parent = el.parentElement; | |
while (parent) { | |
const parentStyle = window.getComputedStyle(parent); | |
if (parentStyle.visibility === "hidden" || parentStyle.display === "none") return false; | |
parent = parent.parentElement; | |
} | |
return true; | |
} | |
function keepPageAlive() { | |
let audioElements = document.querySelectorAll("audio"); | |
let playing = Array.from(audioElements).some(audio => !audio.paused); | |
if (!playing) { | |
let silentAudio = document.getElementById("silentAudio"); | |
if (!silentAudio) { | |
silentAudio = document.createElement("audio"); | |
silentAudio.id = "silentAudio"; | |
silentAudio.loop = true; | |
let ctx = new (window.AudioContext || window.webkitAudioContext)(); | |
let oscillator = ctx.createOscillator(); | |
oscillator.type = 'sine'; | |
oscillator.frequency.setValueAtTime(0, ctx.currentTime); // 0 Hz = silence | |
oscillator.connect(ctx.destination); | |
oscillator.start(); | |
let audioStream = ctx.createMediaStreamDestination(); | |
oscillator.connect(audioStream); | |
silentAudio.srcObject = audioStream.stream; | |
document.body.appendChild(silentAudio); | |
silentAudio.play(); | |
} | |
} | |
} | |
function animateTitle() { | |
if (getEl("keepAlive").checked) { | |
document.title = titlePatterns[titleAnimationIndex]; | |
titleAnimationIndex = (titleAnimationIndex + 1) % titlePatterns.length; | |
} | |
} | |
// Set different intervals for different tasks | |
setInterval(fastTasks, 1); // Runs fast tasks every 1ms | |
setInterval(autohelper, 100); // Runs general helper functions every 100ms | |
setInterval(autoQuantum, 1); // Runs quantum helper every 1ms | |
setInterval(animateTitle, 300); // Runs title animation every 300ms |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment