|
- "use strict";
-
- const belongings = {};
-
- const stats = {};
-
- const macroDesc = {
- name: "Fen",
- species: "crux",
- proSubject: "he",
- proObject: "him",
- proPossessive: "his",
- }
-
- const ownedUpgrades = {};
- const remainingUpgrades = [];
- let showOwnedUpgrades = false;
-
- const effects = {};
-
- const resources = {};
-
- let updateRate = 60;
-
- const currentProductivity = {};
- const contributions = {};
-
- const clickPowers = {
- clickBonus: 0,
- clickMultiplier: 1,
- clickVictim: "micro",
- clickSeconds: 10
- }
-
-
- let clickBonus = 0;
- let clickVictim = "micro";
-
- let lastTime = 0;
-
- let controlHeld = false;
- let shiftHeld = false;
-
- let mouseTarget = undefined;
-
- let newsShowTimer;
- let newsRemoveTimer;
-
- const newsDelay = 8000;
-
- const newsWeightFactors = [];
-
- let buttonClicked = false;
-
- const state = {
- ownedUpgrades: ownedUpgrades,
- resources: resources,
- currentProductivity: currentProductivity,
- belongings: belongings,
- clickPowers: clickPowers,
- stats: stats
- };
-
- const numberModes = {
- words: {
- name: "Words",
- render: numberText,
- next: "smallWords"
- },
- smallWords: {
- name: "Small Words",
- render: numberTextSmall,
- next: "scientific"
- },
- scientific: {
- name: "Scientific",
- render: numberScientific,
- next: "full",
- },
- full: {
- name: "Full",
- render: numberFull,
- next: "words"
- }
- }
-
- deepFreeze(numberModes);
-
- let numberMode = numberModes["words"];
-
- const activePowerups = {};
-
- function tickPowerups(delta) {
- const powerupList = document.querySelector("#powerup-list");
- let changed = false;
- // I love mutating arrays as I traverse them.
-
- Object.entries(activePowerups).filter(x => x[1].life > 0).forEach(([key, data]) => {
- const newLife = data.life - delta;
-
- if (newLife <= 0) {
- setTimeout(() => {
- powerupList.removeChild(data.element);
- }, 1000);
- data.element.classList.add("powerup-entry-done");
- activePowerups[key].life = 0;
- changed = true;
- } else {
- data.life = newLife;
- const frac = (data.maxLife - data.life) / (data.maxLife);
- data.element.style.setProperty("--progress", frac * 100 + "%")
- }
- });
-
- if (changed) {
- updateAll();
- }
- }
-
- function addPowerup(key, powerup) {
- // powerup already exists
- if (activePowerups[key].life > 0) {
- activePowerups[key].life += powerup.duration;
- activePowerups[key].maxLife = activePowerups[key].life;
- } else {
- const powerupList = document.querySelector("#powerup-list");
-
- const powerupEntry = document.createElement("div");
- powerupEntry.classList.add("powerup-entry");
-
- const powerupIconHolder = document.createElement("div");
- powerupIconHolder.classList.add("powerup-entry-icon-holder");
-
- const powerupIcon = document.createElement("i");
- powerupIcon.classList.add("fas");
- powerupIcon.classList.add(powerup.icon);
-
- powerupIconHolder.appendChild(powerupIcon);
- powerupEntry.appendChild(powerupIconHolder);
-
- powerupList.appendChild(powerupEntry);
-
- activePowerups[key] = {powerup: powerup, life: powerup.duration, maxLife: powerup.duration, element: powerupEntry };
-
- powerupEntry.addEventListener("mousemove", function (e) { powerupTooltip(key, e); });
- powerupEntry.addEventListener("mouseleave", function () { powerupTooltipRemove(); });
-
- updateAll();
- }
-
- }
-
- function applyGlobalProdBonus(cost) {
-
- for (let effect of effects["prod-all"]) {
-
- if (ownedUpgrades[effect.parent]) {
- effect.apply(cost);
- }
- }
- }
-
- function calculateProductivity() {
- let productivity = makeCost();
-
- for (const [key, value] of Object.entries(belongings)) {
- const provided = productivityOf(key);
- productivity = addCost(productivity, provided);
- contributions[key] = provided;
- }
-
- return productivity;
- }
-
- // here's where upgrades will go :3
-
- function applyProductivityMultipliers(type, cost) {
-
- for (let effect of effects["prod"]) {
-
- if (ownedUpgrades[effect.parent] && effect.target == type) {
- effect.apply(cost);
- }
- }
-
- for (let effect of effects["helper"]) {
-
- if (ownedUpgrades[effect.parent] && effect.helped == type) {
- effect.apply(cost, belongings[effect.helper].count);
- }
- }
- }
-
- function productivityOf(type) {
- let baseProd = makeCost(buildings[type].prod);
-
- applyProductivityMultipliers(type, baseProd);
-
- applyGlobalProdBonus(baseProd);
-
- scaleCost(baseProd, belongings[type].count);
-
- return baseProd;
- }
-
- function makeCost(source) {
- const empty = mapObject(resourceTypes, () => 0);
- return {...empty, ...source};
- }
-
- function addCost(cost1, cost2) {
- return Object.keys(resourceTypes).reduce((o, k) => {o[k] += cost2[k]; return o;}, cost1);
- }
-
- function scaleCost(cost, scale) {
- return Object.keys(resourceTypes).reduce((o, k) => {o[k] *= scale; return o;}, cost);
- }
-
- function costOfBuilding(type, count = 1) {
- let total = makeCost();
-
- while (count > 0) {
- let baseCost = makeCost(buildings[type].cost);
- baseCost = scaleCost(baseCost, Math.pow(1.15, belongings[type].count + count - 1));
- total = addCost(total, baseCost);
- count--;
- }
-
- return mapObject(total, round);
- }
-
- function buildingCount() {
- if (controlHeld) {
- return 10;
- } else if (shiftHeld) {
- return 100;
- } else {
- return 1;
- }
- }
- function buyBuilding(type, e) {
-
- const count = buildingCount();
-
- let cost = costOfBuilding(type, count);
-
- if (canAfford(cost)) {
- spend(cost);
- belongings[type].count += count;
- }
-
- updateProductivity();
-
- }
-
- function updateAll() {
- updateProductivity();
- updateClickVictim();
- updateOptions();
- }
-
- function updateOptions() {
- cache.optionButtons.numbers.innerText = "Number mode: " + numberMode.name;
- }
-
- // update stuff
-
- function updateDisplay() {
-
- let newTime = performance.now();
- let delta = newTime - lastTime;
- lastTime = newTime;
-
- addResources(delta);
- displayResources();
- displayBuildings();
- displayUpgrades(showOwnedUpgrades);
- tickPowerups(delta);
-
- Object.keys(statTypes).forEach(key => {
- const value = document.querySelector("#stat-value-" + key);
-
- value.innerText = render(stats[key]);
- })
-
- stats.seconds += delta / 1000;
-
- setTimeout(updateDisplay, 1000 / updateRate);
- }
-
- function updateProductivity() {
- Object.assign(currentProductivity, calculateProductivity());
-
-
- // maybe this should go somewhere else - it also does clicking...
- updateClickPowers();
-
- Object.entries(activePowerups).forEach(([key, entry]) => {
- if (entry.life > 0) {
- const powerup = entry.powerup;
-
- powerup.effect(state);
- }
-
- });
-
- }
-
- function addResources(delta) {
- for (const [resource, amount] of Object.entries(currentProductivity)) {
- const gained = amount * delta / 1000;
- resources[resource] += gained;
- if (resource == "food")
- stats.food += gained;
- }
- }
-
- function displayResources() {
- document.title = "Gorge - " + round(resources.food) + " food";
-
- Object.keys(resources).forEach(key => {
- cache.resourceLabels[key].quantity.innerText = render(resources[key]) + " " + resourceTypes[key].name;
-
- if (resourceTypes[key].generated)
- cache.resourceLabels[key].rate.innerText = render(currentProductivity[key]) + " " + resourceTypes[key].name + "/sec";
-
- })
- }
-
- function displayBuildings() {
- const count = buildingCount();
-
- for (const [key, value] of Object.entries(belongings)) {
-
- let available = states.buildings[key].available;
-
- if (!belongings[key].visible) {
- if (resources.food * 10 >= costOfBuilding(key).food) {
- unlockBuilding(key);
- } if (belongings[key].count > 0) {
- unlockBuilding(key);
- } else {
- continue;
- }
- belongings[key].visible = true;
- let button = cache.buildingButtons[key].button;
- button.classList.remove("hidden");
- }
-
- let button = cache.buildingButtons[key].button;
- let name = cache.buildingButtons[key].name;
- let cost = cache.buildingButtons[key].cost;
-
- const buildingCost = costOfBuilding(key, count);
-
- const newName = value.count + " " + (value.count == 1 ? buildings[key].name : buildings[key].plural);
- if (newName != states.buildings[key].name) {
- name.innerText = newName;
- states.buildings[key].name = newName;
- }
-
- const newCost = render(buildingCost.food) + " food";
- if (newCost != states.buildings[key].cost) {
- cost.innerText = newCost;
- states.buildings[key].cost = newCost;
- }
-
-
- if (canAfford(buildingCost) && available !== true) {
- button.classList.remove("building-button-disabled");
- cost.classList.add("building-button-cost-valid");
- states.buildings[key].available = true;
- } else if (!canAfford(buildingCost) && available !== false) {
- button.classList.add("building-button-disabled");
- cost.classList.add("building-button-cost-invalid");
- states.buildings[key].available = false;
- }
- }
- }
-
- function canAfford(cost) {
- for (const [resource, amount] of Object.entries(cost)) {
- if (resources[resource] < amount) {
- return false;
- }
- }
-
- return true;
- }
-
- function spend(cost) {
- for (const [resource, amount] of Object.entries(cost)) {
- resources[resource] -= amount;
- }
- }
-
- function switchShowOwnedUpgrades() {
-
- initializeUpgradeStates();
-
- if (showOwnedUpgrades) {
- document.querySelector("#upgrades").innerText = "Upgrades";
- } else {
- document.querySelector("#upgrades").innerText = "Owned Upgrades";
- }
-
- showOwnedUpgrades = !showOwnedUpgrades;
- }
-
- function displayUpgrades(owned) {
- if (owned) {
- Object.entries(ownedUpgrades).forEach(([key, val]) => {
-
- let button = cache.upgradeButtons[key];
- if (val) {
- button.classList.remove("hidden");
- } else {
- button.classList.add("hidden");
- }
- });
- }
- else {
- for (let id of remainingUpgrades) {
- let button = cache.upgradeButtons[id];
- let visible = states.upgrades[id].visible;
- let available = states.upgrades[id].available;
-
- if (ownedUpgrades[id] && visible !== false) {
- button.classList.add("hidden");
- states.upgrades[id].visible = false;
- continue;
- }
-
- if (upgradeReachable(id) && visible !== true) {
- button.classList.remove("hidden");
- states.upgrades[id].visible = true;
- } else if (!upgradeReachable(id) && visible !== false) {
- button.classList.add("hidden");
- states.upgrades[id].visible = false;
- }
-
- if (upgradeAvailable(id) && available !== true) {
- button.classList.remove("upgrade-button-inactive");
- states.upgrades[id].available = true;
- } else if (!upgradeAvailable(id) && available !== false) {
- button.classList.add("upgrade-button-inactive");
- states.upgrades[id].available = false;
- }
- }
-
- // we aren't trimming the list of upgrades now
- // because we need to switch between owned and unowned upgrades
- // - thus we need to be able to show or hide anything
- /*
- for (let i = remainingUpgrades.length-1; i >= 0; i--) {
- if (ownedUpgrades[remainingUpgrades[i]]) {
- remainingUpgrades.splice(i, 1);
- }
- }*/
- }
- }
-
- function updateClickPowers() {
- let bonus = 0;
- clickPowers.clickMultiplier = 1;
-
- for (let effect of effects["click"]) {
- if (ownedUpgrades[effect.parent]) {
- bonus = effect.apply(bonus, currentProductivity["food"]);
- }
- }
-
- clickPowers.clickBonus = bonus;
- }
-
- function updateClickVictim() {
- const button = document.querySelector("#tasty-micro");
- button.classList.remove(...button.classList);
- for (let i=effects["click-victim"].length - 1; i >=0; i--) {
- const effect = effects["click-victim"][i];
- if (ownedUpgrades[effect.parent]) {
- clickPowers.clickVictim = effect.id;
- button.classList.add("fas")
- button.classList.add(buildings[effect.id].icon)
- return;
- }
- }
- clickPowers.clickVictim = "micro";
- button.classList.add("fas")
- button.classList.add(buildings.micro.icon)
- }
-
- function buyUpgrade(id, e) {
- if (ownedUpgrades[id]) {
- return;
- }
-
- let upgrade = upgrades[id];
-
- if (!upgradeAvailable(id)) {
- return;
- }
-
- spend(upgrade.cost);
-
- ownedUpgrades[id] = true;
-
- let text = "Bought " + upgrade.name + "!";
-
- clickPopup(text, "upgrade", [e.clientX, e.clientY]);
-
- updateProductivity();
- updateClickVictim();
- }
-
- function eatPrey() {
- const add = clickPowers.clickMultiplier * (buildings[clickPowers.clickVictim]["prod"].food * clickPowers.clickSeconds + clickPowers.clickBonus);
- resources.food += add;
- stats.foodClicked += add;
- return add;
- }
-
- // setup stuff lol
-
- // we'll initialize the dict of buildings we can own
-
- function setup() {
-
- // create static data
-
- createTemplateUpgrades();
-
- // prepare dynamic stuff
-
- initializeData();
- initializeNews();
- createButtons();
- createDisplays();
- registerListeners();
- load();
- unlockAtStart();
- initializeCaches();
- initializeStates();
- updateAll();
- }
-
- function initializeNews() {
- news.forEach(entry => {
- newsWeightFactors.push(0);
- });
- }
-
- const cache = {};
-
- function initializeCaches() {
-
- const buildingButtons = {};
-
- for (const [key, value] of Object.entries(belongings)) {
-
- let button = document.querySelector("#building-" + key);
- let name = document.querySelector("#building-" + key + " > .building-button-name");
- let cost = document.querySelector("#building-" + key + " > .building-button-cost");
-
- buildingButtons[key] = {
- button: button,
- name: name,
- cost: cost
- }
- }
-
- cache.buildingButtons = buildingButtons;
-
- const upgradeButtons = {};
-
- Object.keys(upgrades).forEach(key => {
- upgradeButtons[key] = document.querySelector("#upgrade-" + key);
- });
-
- cache.upgradeButtons = upgradeButtons;
-
- const resourceLabels = {};
-
- Object.keys(resourceTypes).forEach(key => {
- resourceLabels[key] = {
- quantity: document.querySelector("#resource-quantity-" + key),
- }
- if (resourceTypes[key].generated)
- resourceLabels[key].rate = document.querySelector("#resource-rate-" + key);
-
- });
-
- cache.resourceLabels = resourceLabels;
-
- const optionButtons = {};
-
- optionButtons.numbers = document.querySelector("#numbers");
-
- cache.optionButtons = optionButtons;
- }
-
- const states = {};
-
- // we can keep track of some things, like whether
- // specific upgrades are currently visible. this
- // way, we don't have to set them visible every tick;
- // we can just check if they've been handled already
-
- function initializeStates() {
- initializeBuildingStates();
- initializeUpgradeStates();
- }
-
- function initializeBuildingStates() {
- const buildingStates = {};
-
- Object.keys(buildings).forEach(key => {
- buildingStates[key] = {
- visible: undefined,
- available: undefined,
- name: undefined,
- cost: undefined
- }
- });
-
- states.buildings = buildingStates;
- }
-
- function initializeUpgradeStates() {
- const upgradeStates = {};
-
- Object.keys(upgrades).forEach(key => {
- upgradeStates[key] = {
- visible: undefined,
- available: undefined
- }
- });
-
- states.upgrades = upgradeStates;
- }
-
-
- function unlockAtStart() {
- unlockBuilding("micro");
-
- for (const [key, value] of Object.entries(belongings)) {
- if (belongings[key].visible) {
- unlockBuilding(key);
- }
- }
- }
-
- function unlockBuilding(id) {
- belongings[id].visible = true;
- document.querySelector("#building-" + id).classList.remove("hidden");
- }
-
- function initializeData() {
- for (const [key, value] of Object.entries(buildings)) {
- belongings[key] = {};
- belongings[key].count = 0;
- belongings[key].visible = false;
- contributions[key] = makeCost();
- }
-
- for (const [key, value] of Object.entries(resourceTypes)) {
- resources[key] = 0;
- currentProductivity[key] = 0;
- }
-
- for (const [id, upgrade] of Object.entries(upgrades)) {
- ownedUpgrades[id] = false;
-
- for (let effect of upgrade.effects) {
- if (effects[effect.type] === undefined) {
- effects[effect.type] = [];
- }
-
- // copy the data and add an entry for the upgrade id that owns the effect
-
- let newEffect = {};
-
- for (const [key, value] of Object.entries(effect)) {
- newEffect[key] = value;
- }
-
- newEffect.parent = id;
-
- // unfortunate name collision here
- // I'm using apply() to pass on any number of arguments to the
- // apply() function of the effect type
-
- newEffect.apply = function (...args) { return effect_types[effect.type].apply.apply(null, [effect].concat(args)); }
-
- effects[effect.type].push(newEffect);
- }
-
- }
-
- Object.keys(powerups).filter(x => powerups[x].duration !== undefined).forEach(key => activePowerups[key] = {
- life: 0
- });
-
- Object.entries(statTypes).forEach(([key, info]) => {
- stats[key] = 0;
- });
- }
-
- function handleButton(e) {
- const add = eatPrey();
- const text = "+" + render(round(add, 1), 3) + " food";
- const gulp = "*glp*";
- clickPopup(text, "food", [e.clientX, e.clientY]);
- clickPopup(gulp, "gulp", [e.clientX, e.clientY]);
- stats.clicks += 1;
- }
-
- function registerListeners() {
- document.addEventListener("mouseup", (e) => {
- if (buttonClicked) {
- buttonClicked = false;
- handleButton(e);
- return false;
- } else {
- return true;
- }
- });
-
- document.querySelector("#tasty-micro").addEventListener("mousedown", (e) => {
- buttonClicked = true;
- });
-
- document.querySelector("#save").addEventListener("click", save);
- document.querySelector("#reset").addEventListener("click", reset);
- document.querySelector("#numbers").addEventListener("click", cycleNumbers);
-
- document.querySelector("#stats").addEventListener("click", () => document.querySelector("#stats-modal").classList.add("modal-active"));
- document.querySelector("#options").addEventListener("click", openOptions);
-
- document.querySelector("#stats-exit").addEventListener("click", () => document.querySelector("#stats-modal").classList.remove("modal-active"));
- document.querySelector("#options-exit").addEventListener("click", closeOptions);
-
-
- document.querySelector("#upgrades").addEventListener("click", switchShowOwnedUpgrades);
-
- document.addEventListener("keydown", e => {
- shiftHeld = e.shiftKey;
- controlHeld = e.ctrlKey;
- if (mouseTarget)
- mouseTarget.dispatchEvent(new Event("mousemove"));
- return true;
- });
-
- document.addEventListener("keyup", e => {
- shiftHeld = e.shiftKey;
- controlHeld = e.ctrlKey;
- if (mouseTarget)
- mouseTarget.dispatchEvent(new Event("mousemove"));
- return true;
- });
- }
-
- function openOptions() {
- document.querySelector("#options-modal").classList.add("modal-active");
-
- Object.keys(options).forEach(key => {
- const input = document.querySelector("#option-value-" + key);
- input.value = options[key].get();
- });
-
- }
-
- function closeOptions() {
- document.querySelector("#options-modal").classList.remove("modal-active");
-
- Object.keys(options).forEach(key => {
- const input = document.querySelector("#option-value-" + key);
- options[key].set(input.value);
- });
- }
-
- function createButtons() {
- createBuildings();
- createUpgrades();
- }
-
- function createBuildings() {
- let container = document.querySelector("#buildings-list");
-
- for (const [key, value] of Object.entries(buildings)) {
- let button = document.createElement("div");
- button.classList.add("building-button");
- button.classList.add("hidden");
- button.id = "building-" + key;
- let buttonName = document.createElement("div");
- buttonName.classList.add("building-button-name");
- let buttonCost = document.createElement("div");
- buttonCost.classList.add("building-button-cost");
-
- let buildingIcon = document.createElement("i");
- buildingIcon.classList.add("fas");
- buildingIcon.classList.add(value.icon);
-
- button.appendChild(buttonName);
- button.appendChild(buttonCost);
- button.appendChild(buildingIcon);
- button.addEventListener("mousemove", function (e) { mouseTarget = button; buildingTooltip(key, e); });
- button.addEventListener("mouseleave", function () { mouseTarget = undefined; buildingTooltipRemove(); });
- button.addEventListener("click", function (e) { buyBuilding(key, e); });
- button.addEventListener("click", function (e) { buildingTooltip(key, e); });
-
- container.appendChild(button);
- }
- }
-
- // do we have previous techs and at least one of each building?
-
- function upgradeReachable(id) {
-
- if (ownedUpgrades[id]) {
- return false;
- }
-
- if (upgrades[id].prereqs !== undefined) {
- for (const [type, reqs] of Object.entries(upgrades[id].prereqs)) {
- if (type == "buildings") {
- for (const [building, amount] of Object.entries(reqs)) {
- if (belongings[building].count == 0) {
- return false;
- }
- }
- }
- else if (type == "upgrades") {
- for (let upgrade of reqs) {
- if (!ownedUpgrades[upgrade]) {
- return false;
- }
- }
- }
- else if (type == "resources") {
- for (const [resource, amount] of Object.entries(reqs)) {
- if (resources[resource] < amount) {
- return false;
- }
- };
- }
- else if (type == "stats") {
- for (const [stat, amount] of Object.entries(reqs)) {
- if (stats[stat] < amount) {
- return false;
- }
- };
- }
- }
- }
-
-
- return true;
- }
- function upgradeAvailable(id) {
- if (!upgradeReachable(id)) {
- return false;
- }
-
- if (!canAfford(upgrades[id].cost)) {
- return false;
- }
-
- if (upgrades[id].prereqs !== undefined) {
- for (const [type, reqs] of Object.entries(upgrades[id].prereqs)) {
- if (type == "buildings") {
- for (const [building, amount] of Object.entries(upgrades[id].prereqs[type])) {
- if (belongings[building].count < amount) {
- return false;
- }
- }
- } else if (type == "productivity") {
- for (const [key, value] of Object.entries(reqs)) {
- if (currentProductivity[key] < value) {
- return false;
- }
- }
- }
- }
- }
-
-
- return true;
- }
-
- function createUpgrades() {
- let container = document.querySelector("#upgrades-list");
-
- for (const [key, value] of Object.entries(upgrades)) {
-
- remainingUpgrades.push(key);
-
- let button = document.createElement("div");
- button.classList.add("upgrade-button");
- button.classList.add("hidden");
- button.id = "upgrade-" + key;
-
- const holder = document.createElement("div");
- holder.classList.add("upgrade-icon-holder");
- button.appendChild(holder);
-
- if (typeof(value.icon) == "object") {
- value.icon.forEach(icon => {
- let upgradeIcon = document.createElement("i");
- upgradeIcon.classList.add("fas");
- upgradeIcon.classList.add(icon.icon);
- upgradeIcon.style.color = icon.color;
- holder.appendChild(upgradeIcon);
- if (icon.transform) {
- upgradeIcon.style.transform = icon.transform;
- }
- })
- } else {
- let upgradeIcon = document.createElement("i");
- upgradeIcon.classList.add("fas");
- upgradeIcon.classList.add(value.icon);
- holder.appendChild(upgradeIcon);
- }
-
-
- button.addEventListener("mouseenter", function (e) { mouseTarget = button; upgradeTooltip(key, e); });
- button.addEventListener("mousemove", function (e) { mouseTarget = button; upgradeTooltip(key, e); });
- button.addEventListener("mouseleave", function () { mouseTarget = undefined; upgradeTooltipRemove(); });
- button.addEventListener("click", function (e) { buyUpgrade(key, e); });
-
- container.appendChild(button);
- }
- }
-
- function createDisplays() {
- const resourceList = document.querySelector("#resource-list");
-
- Object.keys(resourceTypes).forEach(key => {
- const quantity = document.createElement("div");
- quantity.classList.add("resource-quantity");
- quantity.id = "resource-quantity-" + key;
- resourceList.appendChild(quantity);
-
- if (resourceTypes[key].generated) {
- const rate = document.createElement("div");
- rate.classList.add("resource-rate");
- rate.id = "resource-rate-" + key;
- resourceList.appendChild(rate);
- }
-
- })
-
- const statHolder = document.querySelector("#stats-holder");
-
- Object.keys(statTypes).forEach(key => {
- const div = document.createElement("div");
- div.classList.add("stat-line");
-
- const name = document.createElement("div");
- name.classList.add("stat-name");
-
- const value = document.createElement("div");
- value.classList.add("stat-value");
- value.id = "stat-value-" + key;
-
- name.innerText = statTypes[key].name;
-
- value.innerText = stats[key];
-
- div.appendChild(name);
- div.appendChild(value);
-
- statHolder.append(div);
- });
-
- const optionHolder = document.querySelector("#options-holder");
-
- Object.keys(options).forEach(key => {
- const div = document.createElement("div");
- div.classList.add("option-line");
-
- const name = document.createElement("div");
- name.classList.add("option-name");
-
- const value = document.createElement("input");
- value.classList.add("option-value");
- value.id = "option-value-" + key;
-
- name.innerText = options[key].name;
-
- value.innerText = options[key].get();
-
- div.appendChild(name);
- div.appendChild(value);
-
- optionHolder.append(div);
- });
- }
-
- function renderLine(line) {
- let div = document.createElement("div");
- div.innerText = line.text;
-
- if (line.valid !== undefined) {
- if (line.valid) {
- div.classList.add("cost-met");
- } else {
- div.classList.add("cost-unmet");
- }
- }
-
- if (line.class !== undefined) {
- for (let entry of line.class.split(",")) {
- div.classList.add(entry);
- }
- }
-
- return div;
- }
-
- function renderLines(lines) {
- let divs = [];
-
- for (let line of lines) {
- divs.push(renderLine(line));
- }
-
- return divs;
- }
-
- function renderCost(cost) {
- let list = [];
-
- list.push({
- "text": "Cost:"
- });
-
- for (const [key, value] of Object.entries(cost)) {
- list.push({
- "text": render(value, 0) + " " + resourceTypes[key].name,
- "valid": resources[key] >= value
- });
- }
-
- return renderLines(list);
- }
-
- function renderPrereqs(prereqs) {
- let list = [];
-
- if (prereqs === undefined) {
- return renderLines(list);
- }
-
- list.push({
- "text": "Own:"
- });
-
- for (const [key, value] of Object.entries(prereqs)) {
- if (key == "buildings") {
- for (const [id, amount] of Object.entries(prereqs.buildings)) {
- list.push({
- "text": buildings[id].name + " x" + render(amount, 0),
- "valid": belongings[id].count >= amount
- });
- }
- } else if (key == "productivity") {
- for (const [id, amount] of Object.entries(prereqs.productivity)) {
- list.push({
- "text": render(amount, 0) + " " + resourceTypes[id].name + "/s",
- "valid": currentProductivity[id] >= amount
- });
- }
- }
- }
-
- return renderLines(list);
- }
-
- function renderEffects(effectList) {
- let list = [];
-
- for (let effect of effectList) {
- list.push({ "text": effect_types[effect.type].desc(effect) });
- }
-
- return renderLines(list);
- }
-
- function clickPopup(text, type, location) {
- const div = document.createElement("div");
- div.textContent = text;
-
- div.classList.add("click-popup-" + type);
-
- var direction;
-
- if (type == "food") {
- direction = -150;
- } else if (type == "gulp") {
- direction = -150;
- } else if (type == "upgrade") {
- direction = -50;
- } else if (type == "info") {
- direction = 0;
- }
-
- direction *= Math.random() * 0.5 + 1;
-
- direction = Math.round(direction) + "px"
-
- div.style.setProperty("--target", direction)
-
- div.style.left = location[0] + "px";
- div.style.top = location[1] + "px";
-
- const body = document.querySelector("body");
-
- body.appendChild(div);
-
- setTimeout(() => {
- body.removeChild(div);
- }, 2000);
- }
-
- function doNews() {
- let options = [];
- let weights = [];
- let indices = [];
- let index = 0;
- news.forEach(entry => {
- if (entry.condition(state) && newsWeightFactors[index] != 1) {
- options = options.concat(entry.lines);
- weights.push(1 - newsWeightFactors[index])
- indices.push(index);
- }
- index += 1;
- });
-
- const choice = weightedSelect(weights);
-
- showNews(options[choice](state));
-
- for (let i = 0; i < newsWeightFactors.length; i++) {
- newsWeightFactors[i] *= 0.9;
- }
-
- newsWeightFactors[indices[choice]] = 1;
-
- newsShowTimer = setTimeout(() => {
- doNews();
- }, 8000);
- }
-
- function showNews(text) {
- const div = document.createElement("div");
- div.innerHTML = text;
-
- div.classList.add("news-text");
- const body = document.querySelector("body");
-
- div.addEventListener("click", () => {
- clearTimeout(newsShowTimer);
- clearTimeout(newsRemoveTimer);
- div.classList.add("news-text-leaving");
- setTimeout(() => {
- body.removeChild(div);
- }, 1000);
- doNews();
- });
-
-
- body.appendChild(div);
-
- newsRemoveTimer = setTimeout(() => {
- div.classList.add("news-text-leaving");
- setTimeout(() => {
- body.removeChild(div);
- }, 1000);
- }, 8000);
- }
-
- function doPowerup() {
- const lifetime = 10000;
-
- const button = document.createElement("div");
-
- const left = Math.round(Math.random() * 50 + 25) + "%";
- const top = Math.round(Math.random() * 50 + 25) + "%";
-
- button.classList.add("powerup");
-
- button.style.setProperty("--lifetime", lifetime / 1000 + "s");
- button.style.setProperty("--leftpos", left);
- button.style.setProperty("--toppos", top);
-
- const body = document.querySelector("body");
-
- body.appendChild(button);
-
- const choices = [];
-
- Object.entries(powerups).forEach(([key, val]) => {
- if (val.prereqs(state))
- choices.push(key);
- });
-
- const choice = Math.floor(Math.random() * choices.length);
-
- const powerup = powerups[choices[choice]];
-
- const icon = document.createElement("div");
-
- icon.classList.add("fas");
- icon.classList.add(powerup.icon);
-
- button.appendChild(icon);
-
- const remove = setTimeout(() => {
- body.removeChild(button);
- }, lifetime);
-
- let delay = 60000 + Math.random() * 30000;
-
- for (let effect of effects["powerup-freq"]) {
- if (ownedUpgrades[effect.parent]) {
- delay = effect.apply(delay);
- }
- }
-
- setTimeout(() => {
- doPowerup();
- }, delay);
-
- button.addEventListener("mousedown", e => {
- if (powerup.duration !== undefined) {
- addPowerup(choices[choice], powerup);
- } else {
- powerup.effect(state);
- }
-
- powerup.popup(powerup, e);
- button.classList.add("powerup-clicked");
-
- resources.powerups += 1;
-
- clearTimeout(remove);
-
- stats.powerups += 1;
-
- setTimeout(() => {
- body.removeChild(button);
- }, 500);
- });
-
- }
-
-
-
- function fillTooltip(type, field, content) {
- let item = document.querySelector("#" + type + "-tooltip-" + field);
- if (typeof (content) === "string") {
- item.innerText = content;
- } else {
- replaceChildren(item, content);
- }
- }
-
- function upgradeTooltip(id, event) {
-
- let tooltip = document.querySelector("#upgrade-tooltip");
- tooltip.style.setProperty("display", "inline-block");
-
- fillTooltip("upgrade", "name", upgrades[id].name);
- fillTooltip("upgrade", "desc", upgrades[id].desc);
- fillTooltip("upgrade", "effect", renderEffects(upgrades[id].effects));
- fillTooltip("upgrade", "cost", renderCost(upgrades[id].cost));
- fillTooltip("upgrade", "prereqs", renderPrereqs(upgrades[id].prereqs));
-
- let yOffset = tooltip.parentElement.getBoundingClientRect().y;
- let tooltipSize = tooltip.getBoundingClientRect().height;
-
- let yTrans = Math.round(event.clientY - yOffset);
-
- var body = document.body,
- html = document.documentElement;
-
- var height = Math.max(window.innerHeight);
-
- yTrans = Math.min(yTrans, height - tooltipSize - 150);
-
- tooltip.style.setProperty("transform", "translate(-420px, " + yTrans + "px)");
- }
-
- function upgradeTooltipRemove() {
- let tooltip = document.querySelector("#upgrade-tooltip");
-
- tooltip.style.setProperty("display", "none");
- }
-
- function prodSummary(id) {
- let list = [];
-
- list.push(
- { "text": "Each " + buildings[id].name + " produces " + render(belongings[id].count == 0 ? 0 : contributions[id].food / belongings[id].count, 3) + " food/sec" }
- );
-
- list.push(
- { "text": "Your " + render(belongings[id].count) + " " + (belongings[id].count == 1 ? buildings[id].name + " is" : buildings[id].plural + " are") + " producing " + render(contributions[id].food, 3) + " food/sec" }
- );
-
- let percentage = round(100 * contributions[id].food / currentProductivity["food"], 2);
-
- if (isNaN(percentage)) {
- percentage = 0;
- }
- list.push(
- { "text": "(" + percentage + "% of all food)" }
- );
-
- return renderLines(list);
- }
-
- function buildingTooltip(id, event) {
-
- let tooltip = document.querySelector("#building-tooltip");
- tooltip.style.setProperty("display", "inline-block");
-
- const count = buildingCount();
-
- fillTooltip("building", "name", (count != 1 ? count + "x " : "") + buildings[id].name);
- fillTooltip("building", "desc", buildings[id].desc);
- fillTooltip("building", "cost", render(costOfBuilding(id, count).food) + " food");
- fillTooltip("building", "prod", prodSummary(id));
-
- let xPos = tooltip.parentElement.getBoundingClientRect().x - 450;
-
- // wow browsers are bad
-
- var body = document.body,
- html = document.documentElement;
-
- var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
-
- let yPos = Math.min(event.clientY, height - 200);
-
- tooltip.style.setProperty("transform", "translate(" + xPos + "px, " + yPos + "px)")
- }
-
- function buildingTooltipRemove() {
- let tooltip = document.querySelector("#building-tooltip");
-
- tooltip.style.setProperty("display", "none");
- }
-
- function powerupTooltip(id, event) {
-
- let tooltip = document.querySelector("#powerup-tooltip");
- tooltip.style.setProperty("display", "inline-block");
-
- fillTooltip("powerup", "name", powerups[id].name);
- fillTooltip("powerup", "desc", powerups[id].description);
-
- let xPos = tooltip.parentElement.getBoundingClientRect().x + 100;
-
- // wow browsers are bad
-
- var body = document.body,
- html = document.documentElement;
-
- var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
-
- let yPos = Math.min(event.clientY - 100, height - 150);
-
- tooltip.style.setProperty("transform", "translate(" + xPos + "px, " + yPos + "px)")
- }
-
- function powerupTooltipRemove() {
- let tooltip = document.querySelector("#powerup-tooltip");
-
- tooltip.style.setProperty("display", "none");
- }
-
- window.onload = function () {
- setup();
-
- lastTime = performance.now();
-
- doNews();
- doPowerup();
-
- setTimeout(updateDisplay, 1000 / updateRate);
-
- setTimeout(autosave, 60000);
- }
-
- window.onblur = function() {
- controlHeld = false;
- shiftHeld = false;
- }
-
- window.onfocus = function() {
- window.dispatchEvent(new Event("keydown"))
- }
-
- function autosave() {
- saveGame();
- let x = window.innerWidth / 2;
- let y = window.innerHeight * 9 / 10;
- clickPopup("Autosaving...", "info", [x, y]);
- setTimeout(autosave, 60000);
- }
-
- function save(e) {
- saveGame();
- clickPopup("Saved!", "info", [e.clientX, e.clientY]);
- }
-
- function saveGame() {
- try {
- let storage = window.localStorage;
- const save = {}
-
- save.version = migrations.length;
- save.ownedUpgrades = ownedUpgrades;
- save.resources = resources;
- save.belongings = belongings;
- save.stats = stats;
- save.macroDesc = macroDesc;
-
- storage.setItem("save", JSON.stringify(save));
- } catch (e) {
- clickPopup("Can't save - no access to local storage.", "info", [window.innerWidth / 2, window.innerHeight / 5]);
- }
- }
-
- const migrations = [
- // dummy migration, because there was no version 0
-
- save => {
-
- },
-
- // introduce stats
- save => {
- save.stats = {}
- },
-
- // introduce macroDesc
- save => {
- save.macroDesc = {}
- }
- ]
-
- function migrate(save) {
- let version = save.version;
-
- while (version != migrations.length) {
- migrations[version](save);
- version += 1;
- }
-
- save.version = version;
- }
-
- function load() {
- try {
- let storage = window.localStorage;
-
-
- // migrate to everything in one
- if (storage.getItem("save-version") !== null) {
- const save = {};
- save.ownedUpgrades = JSON.parse(storage.getItem("ownedUpgrades"));
- save.resources = JSON.parse(storage.getItem("resources"));
- save.belongings = JSON.parse(storage.getItem("belongings"));
- save.version = 1;
- storage.clear();
- storage.setItem("save", JSON.stringify(save))
- }
-
-
- const save = JSON.parse(storage.getItem("save"));
-
- if (save == null)
- return;
-
- migrate(save);
-
- for (const [key, value] of Object.entries(save.ownedUpgrades)) {
- ownedUpgrades[key] = value;
- }
-
- for (const [key, value] of Object.entries(save.resources)) {
- resources[key] = value;
- }
-
- for (const [key, value] of Object.entries(save.belongings)) {
- belongings[key] = value;
- }
-
- for (const [key, value] of Object.entries(save.stats)) {
- stats[key] = value;
- }
-
- for (const [key, value] of Object.entries(save.macroDesc)) {
- macroDesc[key] = value;
- }
- } catch (e) {
- console.error(e);
- clickPopup("Can't load - no access to local storage.", "info", [window.innerWidth / 2, window.innerHeight / 5]);
- }
-
- }
-
- function reset() {
- window.localStorage.clear();
- }
-
- function cycleNumbers() {
- numberMode = numberModes[numberMode.next];
- updateOptions();
- }
|