Skip to content

Instantly share code, notes, and snippets.

@Eibwen
Last active October 1, 2019 21:52
Show Gist options
  • Save Eibwen/e05f0e38f9fad1753ae4b06bedd4a6fb to your computer and use it in GitHub Desktop.
Save Eibwen/e05f0e38f9fad1753ae4b06bedd4a6fb to your computer and use it in GitHub Desktop.
/*
* This is designed to (semi-)passively help with https://gzgreg.github.io/DerivativeClicker/
* The main function is to only keep a baseline of count for all Buildings
* it does this by buying any buildings which 1 second worth of time will pay for
* By doing that it still allows your base money to continue growing constantly
*
* NEW ADDED: Which doesn't fully follow that. Is auto-buying any TierUpgrades possible as soon as you can afford it
* NEW ADDED: Also not following that. If it reaches the point where your cash-on-hand can buy all the highest tier items, it will buy those for you, so that the rewards trickle down even if you're AFK
*
*
* TODO: Do I want this to be semi-passive still, or just have it trying to be optimized, especially as you progress to higher tiers
*
* TO USE:
* Just open your debugging console, and paste this in
*/
// Update scripts
(function() {
if (boughtRecently) console.log("Updated Script: Auto-Bought", boughtRecently);
if (autoRunTimeout) clearTimeout(autoRunTimeout);
if (statsTimeout) {
clearTimeout(statsTimeout);
statsTimeout = null;
}
})();
function calculateMoneyPerSecond() {
var autoClickRate = player.upgrades[0] / player.autoclickInterval;
var netPossibleChange = player.netMoneyPerSecond + (autoClickRate * player.moneyPerAutoclick);
// Negative income, doesn't mean negative purchase power
var incomePerSecond = (netPossibleChange > 0) ? netPossibleChange : 0;
// Don't claim we can purchase INTO negative either
return Math.min(incomePerSecond, player.money);
}
var boughtRecently = {};
function autoBuy() {
// Upgrades are top-priority
autoBuyTierUpgrades();
var maxIndex = (tierUnlockLevel() + 1) * 5;
var purchasableItems = player.buildings.map((x, i) =>
({
index: i,
priority: i,
moneyCostFunc: () => player.buildings[i].moneyCost,
proofCostFunc: () => player.buildings[i].proofCost,
purchaseFunc: () => buyBuilding(i)
}))
.filter(x => x.moneyCostFunc() <= calculateMoneyPerSecond() && x.proofCostFunc() <= player.proofsPerSecond && x.index < maxIndex)
// If don't have any auto-clicker, don't buy those buildings
.filter(x => (x.index % 5) != 3 || player.moneyPerAutoclick > 0);
if (player.upgradeCosts[0] < calculateMoneyPerSecond()) {
// Include Autoclicker
purchasableItems.push({
index: "upgrade0",
priority: 9,
moneyCostFunc: () => player.upgradeCosts[0],
proofCostFunc: () => 0,
purchaseFunc: () => buyUpgrade(0)
});
}
if (purchasableItems.length == 0) {
// Check the trickleDown instead
trickleDown();
return false;
}
// Reverse sort by priority (higher priority first)
purchasableItems.sort((a, b) => b.priority - a.priority);
var countLimit = 0;
// Fast-catch-up logic. Try to spend all of what we made in the second on this building
var moneySpent = -1;
var proofsSpent = -1;
while (moneySpent < calculateMoneyPerSecond() && proofsSpent < player.proofsPerSecond) {
var building = purchasableItems[0];
moneySpent += building.moneyCostFunc();
proofsSpent += building.proofCostFunc();
building.purchaseFunc()
boughtRecently[building.index] = boughtRecently[building.index]+1 || 1;
if (++countLimit >= 500) {
console.log("Hit Limit!!");
console.log("building", building);
console.log("location, col", building.index % 5, "row", Math.floor(building.index / 5));
break;
}
}
}
function tierUnlockLevel() {
return 3 + (player.currBuyables[0].owned && 1) + (player.currBuyables[1].owned && 1) + (player.currBuyables[2].owned && 1);
}
// Buy Tier Upgrades as soon as you can afford it, from max to min (as the optimal will trend that way)
function autoBuyTierUpgrades() {
var maxTier = tierUnlockLevel();
var purchasable = [];
for (var i = maxTier; i >= 0; --i) {
if (player.tierUpgradeCosts[i] < player.money) {
purchasable.push(i);
}
}
if (purchasable.length == 0) {
return;
}
var buildingLevelCount = player.buildings.reduce((acc, cur, i) => { acc[~~(i / 5)] += cur.manual; return acc;},
{ 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0 });
const boostPerLevel = [ 0.0005, 0.002, 0.005, 0.01, 0.02, 0.04, NaN ];
var afterPurchase = purchasable.map((i) => {
var after = player.mult[i] + (buildingLevelCount[i] * boostPerLevel[i]);
return {
index: i,
multBefore: player.mult[i],
multAfter: after,
percentIncrease: after/player.mult[i]
};
});
console.log("TIERPURCHASE_DATA", afterPurchase);
// Assuming the gains are semi-leveled out... Don't want to figure out all the math needed for a more accurate calculation (TODO)
var bestPurchase = afterPurchase.reduce((prev, current) => {
return (prev.percentIncrease > current.percentIncrease) ? prev : current
});
buyTierUpgrade(bestPurchase.index);
boughtRecently["tier"+bestPurchase.index] = boughtRecently["tier"+bestPurchase.index]+1 || 1;
console.log("TIERPERCENT_AFTER", player.mult);
}
// Idea being, overnight or whatever, don't just build up infinite money (as its mostly pointless in this clicker)
// So if we can afford the most expensive of: [ auto-click upgrade, maxTierBuildings ]
// Switch a state machine to "purchase mode", and buy up all of those from most expensive to cheapest?
// Until can't buy any, and switch back to a "passive state"
// TODO risk, how this plays with the upgrades might be interesting to see
function trickleDown() {
var maxTier = tierUnlockLevel();
var money = player.money;
var proofs = player.proofs;
var purchaseConsideration = player.buildings.map((x, i) => (
{
name: 'building' + i,
canAfford: x.moneyCost < money && x.proofCost <= proofs,
moneyCost: x.moneyCost,
proofCost: x.proofCost,
purchaseFunc: () => { buyBuilding(i) }
}))
.slice(maxTier*5, maxTier*5+5);
purchaseConsideration.push({
name: 'auto-click',
canAfford: player.upgradeCosts[0] < money,
moneyCost: player.upgradeCosts[0],
proofCost: 0,
purchaseFunc: () => { buyUpgrade(0) }
})
if (expensiveBuyMode === 'passive') {
// Check if we can buy all the target things
if (purchaseConsideration.every(x => x.canAfford)
// wait 60 cycles before changing modes --TODO revisit this idea?
&& ++expensiveBuyCounter == 60) {
console.log('=== MOVING TO PURCHASE STATE ===');
expensiveBuyMode = 'purchase';
}
}
else if (expensiveBuyMode === 'purchase') {
// how to compare Proofs cost vs Money Cost?? Or just always buy proofs first/last, no big deal really!!!
// Find most expensive that is purchasable
var toPurchase = purchaseConsideration.reduce((acc, cur, i) => (cur.canAfford && (!acc || cur.moneyCost > acc.moneyCost)) ? cur : acc, null);
console.log("TRICKLE_DOWN_DEBUG", purchaseConsideration);
if (toPurchase) {
console.log("TRICKLE_DOWN_BUY", toPurchase);
toPurchase.purchaseFunc();
// Reset counter
expensiveBuyCounter = 0;
} else if (++expensiveBuyCounter >= 30) {
// wait 30 cycles before changing modes --TODO revisit this idea?
// Nothing left to buy, switch back to passive mode
console.log('--- ENDING TO PURCHASE STATE ---');
expensiveBuyMode = 'passive'
expensiveBuyCounter = 0;
}
}
else {
// Default to passive in an error state
expensiveBuyMode = 'passive'
}
expensiveBuyCounter %= 60;
}
var expensiveBuyCounter = 0;
var expensiveBuyMode = 'passive';
function dumpStats() {
// Do not print nor reset the object if nothing was bought
if (JSON.stringify(Object.getOwnPropertyNames(boughtRecently)) !== '["date","loopticks"]') {
console.log("Auto-Bought", boughtRecently);
boughtRecently = { date: new Date() };
}
statsTimeout = null;
}
var autoRunTimeout = undefined;
var statsTimeout = null;
function autoRunAutoBuy() {
boughtRecently["loopticks"] = boughtRecently["loopticks"]+1 || 1;
autoRunTimeout = setTimeout(() => { autoBuy(); autoRunAutoBuy(); }, 1000);
if (!statsTimeout) statsTimeout = setTimeout(dumpStats, 60000);
}
autoRunAutoBuy();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment