Skip to content

Instantly share code, notes, and snippets.

@FWDekker
Last active January 20, 2025 10:42
Show Gist options
  • Save FWDekker/5ab26c551443bd6e4a30e965c0561c65 to your computer and use it in GitHub Desktop.
Save FWDekker/5ab26c551443bd6e4a30e965c0561c65 to your computer and use it in GitHub Desktop.
Stimulation Clicker Automator
// Stimulation Clicker Automator
//
// Automatically plays the entire game Stimulation Clicker by Neal Agarwal.
// See https://neal.fun/stimulation-clicker/
//
// Copy and paste the entire following code into your browser's console, and press Enter. The game will then play
// itself. To stop the tool, simply write the command `scaStop()` into the console. To start it again, simply use the
// command `scaStart()`.
//
// This tool plays all aspects of the entire game, except that it DOES NOT:
// * buy the final two upgrades
// * buy items in the item shop
//
// Emails are responded to automatically. As a result, you cannot manually check the inbox while the script is running,
// because the script immediately closes the inbox. To work around this, temporarily set `emailEnabled = false`. After
// you're done, you can once again set `emailEnabled = true`.
/*
* Settings
*/
// Number of milliseconds between each loop of the main cycle
var cycleTime = 25;
// Number of cycles between "complex" actions
var slowActionSpeed = 20;
// Questions and answers to Duo's questions
var duoAnswers = {
"How do you say goodbye in Welsh?": "Hwyl far",
"Owls are commonly viewed as harbingers of:": "Death",
"Which language is spoken by more people?": "Mandarin",
"Which one of these is not a German word?": "Gemealez",
"In Japanese, which word represents the sound of silence?": "Shiin",
"The most common starting letter in English is:": "S",
"Which of these used to be a part of the English alphabet?": "&",
"Which of these is not a fictional language?": "Yurok",
"There's only one English word that ends in": "mt",
"What is the plural of octopus": "Octopi or octopuses",
"Owls can spot prey up to ___ away": "Half a mile",
"Past tense of sneak?": "Sneaked or snuck",
"Which of these words have French origin?": "Jury",
"Most common letter in English": "E",
"Hiraeth, deep longing for home, is": "Welsh",
"How many languages exist today?": "Around 7,100",
"Which language has about 421 words for snow?": "Scottish",
"Which is NOT an extinct language?": "Esperanto",
"What is an umlaut?": "¨",
"What does \"fruits de mer\" mean?": "Seafood",
"Which is NOT a romance language?": "Polish",
"Which word appears in the Oxford English Dictionary?": "All of the above",
"Which is NOT a word for potato?": "Potate",
"\"Saudade\" is a Portuguese word for": "Nostalgic longing",
"What is Duo's favorite word?": "Vengence",
"Which word rhymes with \"trough\"?": "Rough",
"What is an owl pellet?": "Undigested prey",
"In medieval Europe, what creature were owls often associated with?": "Witches",
"Owls have double the ___ of humans": "Vertebrae",
"A group of pugs is called a:": "A grumble",
"What is the term for a word that is the same backwards and forwards?": "Palindrome",
"How many degrees can an owl rotate its head?": "270 degrees",
"What is the only letter that doesn't appear in any U.S. state name?": "Q",
"In which language is 'Gesundheit' commonly used after someone sneezes?": "German",
"Which of these words is its own opposite?": "Dust",
"What's the only letter that doesn't appear in the periodic table": "J",
"Which of these is spelled correctly?": "Minuscule",
"Which of these words changes its meaning when capitalized?": "March/march",
};
// List of email actions that should NOT be clicked
var mailExcludeList = ["Thank them for the opportunity", "Donate 2,000 stimulation"];
// List of upgrades that should NOT be bought
var upgradeExcludeList = ["Subway Surfers Wormhole", "Go to the Ocean"];
// Maximum price to spend on repeatable upgrades while you have less than `upgradeMaxCostThreshold` stimulation
var upgradeMaxCost = {"Bouncing DVD": 125, "Hydraulic Speed": 5100};
// Threshold below which `upgradeMaxCost` applies
var upgradeMaxCostThreshold = 1000000;
// Threshold below which certain stocks are bought, and above which certain stocks are sold
var stockThreshold = {"Tesla": 550, "Bitcoin": 20000};
// `true` if timing performance should be written to the console log
var logPerformance = false;
// `true` if responding to emails is enabled
var emailEnabled = true;
/*
* Functions
*/
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function getElement(className, root = document) {
return root.getElementsByClassName(className)[0];
}
function getVisibleElement(className, root = document) {
const element = getElement(className, root);
if (element === undefined || element.className.includes("hide") || element.offsetParent === null) return undefined;
else return element;
}
function getElements(className, root = document) {
return Array.from(root.getElementsByClassName(className));
}
function parseCommaInt(text) {
return parseInt(text.replaceAll(",", ""), 10);
}
function getStimulation() {
const span = getElement("main-stat-num");
if (span === undefined) return 0;
else return parseCommaInt(span.innerText);
}
var scaToggle = true;
function scaStop() {
scaToggle = false;
}
async function scaStart() {
// Cached DOM elements
const stimulationButton = getElement("main-btn");
let hydraulicStartButton = undefined;
let hydraulicCollectButton = undefined;
let tamagotchiFeedButton = undefined;
let duolingoBox = undefined;
let duolingoComplete = false;
let stockSelect = undefined;
let stockCountSpan = undefined;
let stockPriceSpan = undefined;
let stockBuyButton = undefined;
let stockSellButton = undefined;
let stockMadeLoss = false;
let stockMadeLossBought = false;
// Shut down other instances
scaToggle = false;
await sleep(5 * cycleTime);
// Start
scaToggle = true;
let cycleCounter = 0;
let cycleStartDate = undefined;
if (logPerformance) cycleStartDate = performance.now();
while (true) {
/// Preamble
if (!scaToggle) return;
cycleCounter = (cycleCounter + 1) % slowActionSpeed;
if (logPerformance && cycleCounter === 0) {
const endDate = performance.now();
console.log(`Time per cycle: ${(endDate - cycleStartDate) / 10}ms.`);
cycleStartDate = endDate;
}
/// Income
// Stim
stimulationButton.click();
// Level up
if (cycleCounter === 0) getVisibleElement("collect")?.click();
// Hydraulic press
if (hydraulicStartButton === undefined) hydraulicStartButton = getVisibleElement("press-btn");
hydraulicStartButton?.click();
if (hydraulicCollectButton === undefined) hydraulicCollectButton = getVisibleElement("press-collect");
hydraulicCollectButton?.click();
// Lootbox
getElements("loot-box-target").forEach(it => it.click());
// Powerups
getElements("powerup").filter(it => !it.src.includes("serene")).forEach(it => it.click());
// Tamagotchi
if (tamagotchiFeedButton === undefined) tamagotchiFeedButton = getVisibleElement("action-btn");
tamagotchiFeedButton?.click();
getElements("egg-wrapper").forEach(it => it.click());
// DuoLingo
if (duolingoBox === undefined) duolingoBox = getVisibleElement("question");
if (duolingoBox !== undefined && !duolingoComplete) {
const question = getElement("question-text")?.innerText;
if (question === undefined) {
duolingoComplete = true;
} else {
const answer = duoAnswers[question];
getElements("question-choice").filter(it => it.innerText === answer).forEach(it => it.click());
}
}
// Emails
if (emailEnabled && cycleCounter === 0) {
getElement("notification")?.click();
getElements("question-container").forEach(it => {
Array.from(it.getElementsByTagName("input")).forEach(it => it.click());
});
const mailActionButton = getVisibleElement("action");
if (mailActionButton !== undefined && !mailExcludeList.includes(mailActionButton.innerText))
mailActionButton.click();
getVisibleElement("close")?.click();
}
/// Expenses
// Upgrades
if (cycleCounter === 0) {
getElements("upgrade")
.filter(it => {
const stimulation = getStimulation();
const name = getElement("upgrade-name", it).innerText;
const cost = parseCommaInt(getElement("upgrade-cost", it).innerText.slice(6));
return !upgradeExcludeList.includes(name) &&
!(stimulation < upgradeMaxCostThreshold &&
Object.keys(upgradeMaxCost).includes(name) &&
cost > upgradeMaxCost[name]);
})
.forEach(it => it.click());
}
// Stock trading
if (stockSelect === undefined) {
stockSelect = getElement("stock-select");
stockPriceSpan = getElement("last-price");
stockCountSpan = getElement("stock-shares");
stockBuyButton = getElement("stock-buy");
stockSellButton = getElement("stock-sell");
}
if (stockSelect !== undefined) {
const type = (stockSelect.options.length === 4) ? "Tesla" : "Bitcoin";
const threshold = stockThreshold[type];
if (stockSelect.value !== type) {
stockSelect.value = type;
stockSelect.dispatchEvent(new Event("change", {bubbles: true}));
}
const shareValue = parseCommaInt(stockPriceSpan.innerText.slice(1));
const shareCount = parseCommaInt(stockCountSpan.innerText);
const canBuy = getStimulation() >= shareValue
const canSell = shareCount > 0
if (!stockMadeLoss && type === "Bitcoin") {
if (!stockMadeLossBought) {
if (shareValue > threshold && canBuy) {
stockBuyButton.click();
stockMadeLossBought = true;
}
} else {
if (shareValue < threshold && canSell) {
stockSellButton.click();
stockMadeLoss = true;
}
}
} else {
if (shareValue < threshold && canBuy) stockBuyButton.click();
else if (shareValue > threshold && canSell) stockSellButton.click();
}
}
/// /Loop
await sleep(cycleTime);
}
}
scaStart().then(() => console.log("Automator has stopped."));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment