Vue.component("battery", {
props: ["layer", "data"],
template: `
{{ layers.generators.clickables[data].name || data[0].toUpperCase() + data.slice(1) }} battery
x{{ format(layers.generators.clickables[data].effect()) }}
{{ layers[data].resource }} gain
`
});
function getBatteryCharger(id, title, name) {
return {
title: title + "
",
layer: "generators",
id,
name,
display() {
return `Charge battery with joules.
Currently: ${format(player[this.layer].batteries[this.id])}/${format(layers[this.layer].buyables[this.id].effect())}`;
},
onClick() {
const chargeAmount = Decimal.min(player.generators.points.times(player.generators.allocPerc), layers[this.layer].buyables[this.id].effect().sub(player.generators.batteries[this.id]));
if (chargeAmount.gt(0)) {
player.generators.points = player.generators.points.sub(chargeAmount);
player.generators.batteries[this.id] = player.generators.batteries[this.id].add(chargeAmount);
}
},
effect() {
if (!tmp[this.layer].layerShown || (player.tab !== this.layer && !player[this.layer].timeLoopActive)) {
return new Decimal(1);
}
return player[this.layer].batteries[this.id].max(1).log10().add(1);
}
};
}
function getBatteryCapBuyable(id, title) {
return {
title: title + "
",
layer: "generators",
id,
name,
style: {
width: "150px",
height: "150px"
},
display() {
return `Multiply battery cap by ${formatWhole(buyableEffect(this.layer, 13))}x.
Currently: ${formatWhole(this.effect())}
Cost: ${formatWhole(this.cost())} charge`;
},
cost(x) {
const amount = x || getBuyableAmount(this.layer, this.id);
return Decimal.pow(10, amount.add(1)).times(0.9);
},
canAfford() {
return player[this.layer].batteries[this.id].gte(this.cost());
},
buy() {
player[this.layer].batteries[this.id] = player[this.layer].batteries[this.id].sub(this.cost());
setBuyableAmount(this.layer, this.id, getBuyableAmount(this.layer, this.id).add(1));
},
effect() {
return Decimal.pow(buyableEffect(this.layer, 13), getBuyableAmount(this.layer, this.id).add(1));
},
unlocked: () => hasMilestone("generators", 1)
};
}
addLayer("generators", {
name: "generators",
resource: "joules",
image: "images/PIXNIO-1742428-5028x2828.jpg",
color: electricColor,
jobName: "Run Generators",
showJobDelay: 1,
layerShown: () => hasMilestone("distill", 5),
startData() {
return {
unlocked: true,
points: new Decimal(0),
xp: new Decimal(0),
lastLevel: new Decimal(0),
timeLoopActive: false,
allocPerc: new Decimal(1),
flowersActive: false,
distillActive: false,
studyActive: false,
sandsActive: false,
ritualsActive: false,
flowersDuration: 0,
distillDuration: 0,
studyDuration: 0,
sandsDuration: 0,
ritualsDuration: 0,
batteries: {
generators: new Decimal(0),
flowers: new Decimal(0),
distill: new Decimal(0),
study: new Decimal(0),
sands: new Decimal(0)
}
};
},
getResetGain() {
if (!tmp[this.layer].layerShown || (player.tab !== this.layer && !player[this.layer].timeLoopActive)) {
return new Decimal(0);
}
let gain = new Decimal(0);
if (player.generators.flowersActive && (player.tab === "flowers" || player.flowers.timeLoopActive)) {
gain = gain.add(layers.generators.clickables.flowersGenerator.effect());
}
if (player.generators.distillActive && (player.tab === "distill" || player.distill.timeLoopActive)) {
gain = gain.add(layers.generators.clickables.distillGenerator.effect());
}
if (player.generators.studyActive && (player.tab === "study" || player.study.timeLoopActive)) {
gain = gain.add(layers.generators.clickables.studyGenerator.effect());
}
if (player.generators.sandsActive && (player.tab === "sands" || player.sands.timeLoopActive)) {
gain = gain.add(layers.generators.clickables.sandsGenerator.effect());
}
if (player.generators.ritualsActive && (player.tab === "rituals" || player.rituals.timeLoopActive)) {
gain = gain.add(layers.generators.clickables.ritualsGenerator.effect());
}
gain = gain.times(buyableEffect(this.layer, 11));
gain = gain.times(new Decimal(1.1).pow(getJobLevel(this.layer)));
gain = gain.times(layers.generators.clickables[this.layer].effect());
gain = gain.times(ritualEffect("gain"));
if (hasUpgrade(this.layer, 11)) {
gain = gain.times(upgradeEffect(this.layer, 11));
}
return gain;
},
passiveGeneration: new Decimal(1),
tabFormat: {
"Main": {
content: () => [
"main-display",
["display-text", `You are collecting ${format(tmp.generators.getResetGain)} joules per second`],
"blank",
["display-text", (() => {
if (!hasMilestone("generators", 0)) {
return "Discover new ways to harness the electric power at level 2";
}
if (!hasMilestone("generators", 1)) {
return "Discover new ways to harness the electric power at level 4";
}
if (!hasMilestone("generators", 3)) {
return "Discover new ways to harness the electric power at level 6";
}
if (!hasMilestone("generators", 4)) {
return "Discover new ways to harness the electric power at level 8";
}
if (!hasMilestone("generators", 5)) {
return "Discover new ways to harness the electric power at level 10";
}
return "";
})()],
"blank",
"blank",
["row", ["flowersGenerator", "studyGenerator", "distillGenerator", "sandsGenerator", "ritualsGenerator"].filter(id => tmp.generators.clickables[id].unlocked).map(id => ["clickable", id])],
"blank",
"blank",
"upgrades",
"buyables",
"blank",
["milestones-filtered", [2, 5, 6]]
],
shouldNotify: () => [11, 12, 13].map(id => tmp.generators.buyables[id]).some(buyable => buyable.unlocked && buyable.canAfford)
},
"Batteries": {
content: () => [
"main-display",
["display-text", "Each battery effects a job's output.
Every power of 10 joules increases that job's gain by 1x.
Batteries slowly lose charge over time.
"],
"blank",
["sticky", ["80px", ["row", [
["clickable", "perc1"],
"blank",
["clickable", "perc10"],
"blank",
["clickable", "perc50"],
"blank",
["clickable", "perc100"]
]]]],
"blank",
["row", [["battery", "flowers"], ["battery", "study"]]],
["row", [["battery", "distill"], ["battery", "sands"]]],
["row", [["battery", "generators"]]]
],
unlocked: () => hasMilestone("generators", 0)
}
},
update(diff) {
if (player.tab === this.layer || player[this.layer].timeLoopActive) {
Object.keys(player[this.layer].batteries).forEach(key => {
player[this.layer].batteries[key] = player[this.layer].batteries[key].times(Decimal.pow(Math.E, Decimal.times(diff, buyableEffect(this.layer, 12)))).clamp(0, layers[this.layer].buyables[key].effect());
if (player[this.layer].batteries[key].lt(0.01)) {
player[this.layer].batteries[key] = new Decimal(0);
}
});
["flowers", "distill", "study", "sands", "rituals"].forEach(key => {
if (player[this.layer][`${key}Active`]) {
player[this.layer][`${key}Duration`] += diff;
}
});
}
},
onAddPoints(gain) {
let xpGain = gain;
if (hasUpgrade("generators", 13)) {
xpGain = xpGain.times(layers.generators.clickables[this.layer].effect());
}
xpGain = xpGain.times(ritualEffect("globalXp"));
player[this.layer].xp = player[this.layer].xp.add(xpGain);
checkJobXP(this.layer);
},
milestones: {
0: {
requirementDescription: "Level 2",
done: () => player.generators.xp.gte(10)
},
1: {
requirementDescription: "Level 4",
done: () => player.generators.xp.gte(1e3)
},
2: {
title: "Silence Earthling!",
requirementDescription: "Level 5",
"effectDescription": "Unlock a new feature in experiments job",
done: () => player.generators.xp.gte(1e4)
},
3: {
requirementDescription: "Level 6",
done: () => player.generators.xp.gte(1e5)
},
4: {
requirementDescription: "Level 8",
done: () => player.generators.xp.gte(1e7)
},
5: {
title: "My name is Darth Vader.",
requirementDescription: "Level 10",
"effectDescription": "Unlock candypop feature in collecting job",
done: () => player.generators.xp.gte(1e9),
unlocked: () => hasMilestone("generators", 2)
},
6: {
title: "I am an extraterrestrial",
requirementDescription: "Level 25",
"effectDescription": "Unlock ???",
done: () => player.generators.xp.gte(1e24) && player.chapter > 2,
unlocked: () => player.chapter > 3
}
},
upgrades: {
rows: 1,
cols: 3,
11: {
title: "Well, good luck.
",
description: "Multiply joules gain by 2 raised to the number of active generators
",
cost: new Decimal(1e4),
effect: () => Decimal.pow(2, ["flower", "distill", "study", "sands", "rituals"].filter(g => player.generators[`${g}Active`]).length),
unlocked: () => hasMilestone("generators", 3),
effectDisplay() {
return `x${formatWhole(this.effect())}`;
}
},
12: {
title: "For both our sakes.
",
description: "Increase generator's output by 1% for each second it has been activated
",
cost: new Decimal(1e5),
unlocked: () => hasMilestone("generators", 3)
},
13: {
title: "See you in the future.
",
description: "Apply batteries' effects to their job's xp as well
",
cost: new Decimal(1e6),
unlocked: () => hasMilestone("generators", 3)
}
},
clickables: {
flowersGenerator: {
title: "I hate manure!
",
display() {
return `Generate ${format(this.effect())} joules/s if collecting job is active.
(based on collecting level)
Flowers gain is softcapped immediately and the job runs 10x slower.
Currently: ${player.generators.flowersActive ? "ACTIVE" : "INACTIVE"}`;
},
class: () => ({"gradient-border": player.generators.flowersActive}),
style: {
width: "200px",
height: "200px"
},
onClick() {
player.generators.flowersActive = !player.generators.flowersActive;
},
effect() {
let effect = getJobLevel("flowers").div(16);
if (hasUpgrade("generators", 12)) {
effect = effect.times(Decimal.times(0.01, player.generators.flowersDuration).add(1));
}
return effect;
},
unlocked: () => tmp.flowers.layerShown
},
distillGenerator: {
title: "Wait A Minute, Doc.
",
display() {
return `Generate ${format(this.effect())} joules/s if distilling job is active.
(based on distilling level)
Essentia gain is softcapped immediately and the job runs 10x slower.
Currently: ${player.generators.distillActive ? "ACTIVE" : "INACTIVE"}`;
},
class: () => ({"gradient-border": player.generators.distillActive}),
style: {
width: "200px",
height: "200px"
},
onClick() {
player.generators.distillActive = !player.generators.distillActive;
},
effect() {
let effect = getJobLevel("distill").div(8);
if (hasUpgrade("generators", 12)) {
effect = effect.times(Decimal.times(0.01, player.generators.distillDuration).add(1));
}
return effect;
},
unlocked: () => tmp.distill.layerShown
},
studyGenerator: {
title: "Great Scott!
",
display() {
return `Generate ${format(this.effect())} joules/s if studying job is active.
(based on studying level)
Properties gain is softcapped immediately and the job runs 10x slower.
Currently: ${player.generators.studyActive ? "ACTIVE" : "INACTIVE"}`;
},
class: () => ({"gradient-border": player.generators.studyActive}),
style: {
width: "200px",
height: "200px"
},
onClick() {
player.generators.studyActive = !player.generators.studyActive;
},
effect() {
let effect = getJobLevel("study").div(4);
if (hasUpgrade("generators", 12)) {
effect = effect.times(Decimal.times(0.01, player.generators.studyDuration).add(1));
}
return effect;
},
unlocked: () => tmp.study.layerShown
},
sandsGenerator: {
title: "This is heavy!
",
display() {
return `Generate ${format(this.effect())} joules/s if experiments job is active.
(based on experimenting level)
Potentia gain is softcapped immediately and the job runs 10x slower.
Currently: ${player.generators.sandsActive ? "ACTIVE" : "INACTIVE"}`;
},
class: () => ({"gradient-border": player.generators.sandsActive}),
style: {
width: "200px",
height: "200px"
},
onClick() {
player.generators.sandsActive = !player.generators.sandsActive;
},
effect() {
let effect = getJobLevel("sands").div(2);
if (hasUpgrade("generators", 12)) {
effect = effect.times(Decimal.times(0.01, player.generators.sandsDuration).add(1));
}
return effect;
},
unlocked: () => tmp.sands.layerShown
},
ritualsGenerator: {
title: "Nobody Calls Me Chicken.
",
display() {
return `Generate ${format(this.effect())} joules/s if rituals job is active.
(based on rituals level)
All ritual effects are softcapped immediately and the job runs 10x slower.
Currently: ${player.generators.ritualsActive ? "ACTIVE" : "INACTIVE"}`;
},
class: () => ({"gradient-border": player.generators.ritualsActive}),
style: {
width: "200px",
height: "200px"
},
onClick() {
player.generators.ritualsActive = !player.generators.ritualsActive;
},
effect() {
let effect = getJobLevel("rituals");
if (hasUpgrade("generators", 12)) {
effect = effect.times(Decimal.times(0.01, player.generators.ritualsDuration).add(1));
}
return effect;
},
unlocked: () => tmp.rituals.layerShown
},
flowers: getBatteryCharger("flowers", "History is gonna change.", "Collecting"),
distill: getBatteryCharger("distill", "You disintegrated Einstein!"),
study: getBatteryCharger("study", "I figured, what the hell?"),
sands: getBatteryCharger("sands", "Ronald Reagan? The actor? Ha!", "Experiments"),
generators: getBatteryCharger("generators", "Good night, future boy!"),
"perc1": {
title: "1%",
class: { 'generator-selector': true },
style: {
width: "60px",
minHeight: "60px",
color: "black",
backgroundColor: electricColor
},
canClick: () => player.generators.allocPerc.neq(0.01),
onClick: () => {
player.generators.allocPerc = new Decimal(0.01);
}
},
"perc10": {
title: "10%",
class: { 'generator-selector': true },
style: {
width: "60px",
minHeight: "60px",
color: "black",
backgroundColor: electricColor
},
canClick: () => player.generators.allocPerc.neq(0.1),
onClick: () => {
player.generators.allocPerc = new Decimal(0.1);
}
},
"perc50": {
title: "50%",
class: { 'generator-selector': true },
style: {
width: "60px",
minHeight: "60px",
color: "black",
backgroundColor: electricColor
},
canClick: () => player.generators.allocPerc.neq(0.5),
onClick: () => {
player.generators.allocPerc = new Decimal(0.5);
}
},
"perc100": {
title: "100%",
class: { 'generator-selector': true },
style: {
width: "60px",
minHeight: "60px",
color: "black",
backgroundColor: electricColor
},
canClick: () => player.generators.allocPerc.neq(1),
onClick: () => {
player.generators.allocPerc = new Decimal(1);
}
}
},
buyables: {
rows: 1,
cols: 3,
11: {
title: "1.21 Gigawatts!?!
",
display() {
return `Improve generator efficiency by 10%
Currently: x${format(this.effect())}
Cost: ${format(this.cost())} joules`;
},
cost(x) {
const amount = x || getBuyableAmount(this.layer, this.id);
return new Decimal(1e6).times(new Decimal(5).pow(amount));
},
effect() {
return new Decimal(1.1).pow(getBuyableAmount(this.layer, this.id));
},
canAfford() {
return player[this.layer].points.gte(this.cost());
},
buy() {
player[this.layer].points = player[this.layer].points.sub(this.cost());
setBuyableAmount(this.layer, this.id, getBuyableAmount(this.layer, this.id).add(1));
},
unlocked: () => hasMilestone("generators", 4)
},
12: {
title: "88 Miles Per Hour
",
display() {
return `Decrease battery discharge by 10%/sec
Currently: ${format(this.effect().times(100))}%/sec
Cost: ${format(this.cost())} joules`;
},
cost(x) {
const amount = x || getBuyableAmount(this.layer, this.id);
return new Decimal(1e7).times(new Decimal(10).pow(amount));
},
effect() {
return new Decimal(-.1).div(Decimal.pow(1.1, getBuyableAmount(this.layer, this.id)));
},
canAfford() {
return player[this.layer].points.gte(this.cost());
},
buy() {
player[this.layer].points = player[this.layer].points.sub(this.cost());
setBuyableAmount(this.layer, this.id, getBuyableAmount(this.layer, this.id).add(1));
},
unlocked: () => hasMilestone("generators", 4)
},
13: {
title: "Where We’re Going, We Don’t Need Roads.
",
display() {
return `Add 1 to the amount each battery cap upgrade multiples the cap by
Currently: x${formatWhole(this.effect())}
Cost: ${format(this.cost())} joules`;
},
cost(x) {
const amount = x || getBuyableAmount(this.layer, this.id);
return new Decimal(1e8).times(new Decimal(8).pow(amount));
},
effect() {
return Decimal.add(10, getBuyableAmount(this.layer, this.id));
},
canAfford() {
return player[this.layer].points.gte(this.cost());
},
buy() {
player[this.layer].points = player[this.layer].points.sub(this.cost());
setBuyableAmount(this.layer, this.id, getBuyableAmount(this.layer, this.id).add(1));
},
unlocked: () => hasMilestone("generators", 4)
},
flowers: getBatteryCapBuyable("flowers", "It's \"leave\", you idiot!"),
distill: getBatteryCapBuyable("distill", "A hundred years ago?"),
study: getBatteryCapBuyable("study", "I'm back from the future."),
sands: getBatteryCapBuyable("sands", "Alright, boys, buckle up."),
generators: getBatteryCapBuyable("generators", "Unless you've got power!")
},
bars: {
job: getJobProgressBar("generators", electricColor)
}
});
// animate electricity svg
const numberOfPoints = 20;
const lineWidth = 4;
const amplitude = 30;
const margin = 10;
const maxHeight = 200 - margin * 2;
const width = 100;
let animateElectricity = () => {
const containers = document.querySelectorAll(".battery > svg");
for (let i = 0; i < containers.length; i++) {
const container = containers[i];
const height = parseInt(getComputedStyle(container).getPropertyValue("height").slice(0, -2));
if (height === margin * 2) {
continue;
}
if (Math.random() < .5) {
continue;
}
const numPoints = Math.max(3, Math.floor(numberOfPoints * height / maxHeight));
let coords = new Array(numPoints).fill(1).map((_, i) => {
let first = i === 0;
let last = i === numPoints - 1;
let y = (height - margin * 2) / (numPoints - 1) * i + margin;
let x = (first || last) ? width / 2 : (width - amplitude) / 2 + Math.random() * amplitude;
return {x, y};
});
// Draw path
let path = container.querySelector("path");
path.setAttribute("d", "M" + coords.map(coord => coord.x + "," + coord.y).join(" L"));
// Style path
let deviation = Math.random() * (5 - 2) + 2;
path.style.opacity = deviation / 5 + 0.2;
path.style.strokeWidth = lineWidth;
// Style glow
let glow = container.querySelector("#glow feDropShadow");
glow.setAttribute("stdDeviation", deviation);
}
requestAnimationFrame(animateElectricity);
};
requestAnimationFrame(animateElectricity);