cookie clicker but bigger
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

973 lines
23 KiB

  1. "use strict";
  2. let belongings = {};
  3. let ownedUpgrades = {};
  4. let remainingUpgrades = [];
  5. let showOwnedUpgrades = false;
  6. let effects = {};
  7. let resources = {};
  8. let updateRate = 60;
  9. let currentProductivity = {};
  10. let clickBonus = 0;
  11. let clickVictim = "micro";
  12. let lastTime = 0;
  13. const activePowerups = [];
  14. function tickPowerups(delta) {
  15. const powerupList = document.querySelector("#powerup-list");
  16. let changed = false;
  17. // I love mutating arrays as I traverse them.
  18. for (let i = activePowerups.length-1; i >= 0; i--) {
  19. activePowerups[i].lifetime -= delta;
  20. if (activePowerups[i].lifetime <= 0) {
  21. clickPopup("OOF", "info", [500, 500]);
  22. powerupList.removeChild(activePowerups[i].element);
  23. activePowerups.splice(i, 1);
  24. changed = true;
  25. }
  26. }
  27. if (changed) {
  28. updateAll();
  29. }
  30. }
  31. function addPowerup(powerup) {
  32. const powerupList = document.querySelector("#powerup-list");
  33. const powerupEntry = document.createElement("div");
  34. powerupEntry.innerText = powerup.name;
  35. powerupList.appendChild(powerupEntry);
  36. activePowerups.push({powerup: powerup, lifetime: powerup.duration, element: powerupEntry});
  37. updateAll();
  38. }
  39. function applyGlobalProdBonuses(productivity) {
  40. for (let effect of effects["prod-all"]) {
  41. if (ownedUpgrades[effect.parent]) {
  42. productivity = effect.apply(productivity);
  43. }
  44. }
  45. return productivity;
  46. }
  47. function calculateProductivity() {
  48. let productivity = 0;
  49. for (const [key, value] of Object.entries(belongings)) {
  50. productivity += productivityOf(key);
  51. }
  52. return productivity;
  53. }
  54. // here's where upgrades will go :3
  55. function productivityMultiplierOf(type) {
  56. let base = 1;
  57. for (let effect of effects["prod"]) {
  58. if (ownedUpgrades[effect.parent] && effect.target == type) {
  59. base = effect.apply(base);
  60. }
  61. }
  62. for (let effect of effects["helper"]) {
  63. if (ownedUpgrades[effect.parent] && effect.helped == type) {
  64. base = effect.apply(base, belongings[effect.helper].count);
  65. }
  66. }
  67. return base;
  68. }
  69. function productivityOf(type) {
  70. let baseProd = buildings[type].prod;
  71. let prod = baseProd * productivityMultiplierOf(type);
  72. prod = applyGlobalProdBonuses(prod);
  73. return prod * belongings[type].count;
  74. }
  75. function costOfBuilding(type) {
  76. let baseCost = buildings[type].cost
  77. let countCost = baseCost * Math.pow(1.15, belongings[type].count);
  78. return Math.round(countCost);
  79. }
  80. function buyBuilding(type) {
  81. let cost = costOfBuilding(type);
  82. if (resources.food >= cost) {
  83. belongings[type].count += 1;
  84. resources.food -= cost;
  85. }
  86. updateProductivity();
  87. updateClickBonus();
  88. }
  89. function updateAll() {
  90. updateProductivity();
  91. updateClickBonus();
  92. updateClickVictim();
  93. }
  94. // update stuff
  95. function updateDisplay() {
  96. let newTime = performance.now();
  97. let delta = newTime - lastTime;
  98. lastTime = newTime;
  99. addResources(delta);
  100. displayResources();
  101. displayBuildings();
  102. displayUpgrades(showOwnedUpgrades);
  103. tickPowerups(delta);
  104. setTimeout(updateDisplay, 1000/updateRate);
  105. }
  106. function updateProductivity() {
  107. currentProductivity["food"] = calculateProductivity();
  108. activePowerups.forEach(entry => {
  109. const powerup = entry.powerup;
  110. const state = {
  111. ownedUpgrades: ownedUpgrades,
  112. resources: resources,
  113. currentProductivity: currentProductivity,
  114. belongings: belongings
  115. };
  116. console.log(currentProductivity);
  117. powerup.effect(state);
  118. console.log(currentProductivity);
  119. })
  120. }
  121. function addResources(delta) {
  122. for (const [resource, amount] of Object.entries(currentProductivity)) {
  123. resources[resource] += amount * delta / 1000;
  124. }
  125. }
  126. function displayResources() {
  127. document.title = "Gorge - " + round(resources.food) + " food";
  128. replaceChildren(document.querySelector("#resource-list"), renderResources());
  129. }
  130. function renderResources() {
  131. let list = [];
  132. for (const [key, value] of Object.entries(resources)) {
  133. let line1 = render(value, 3, 0) + " " + resourceTypes[key].name;
  134. let line2 = render(currentProductivity[key], 1, 1) + " " + resourceTypes[key].name + "/sec";
  135. list.push({"text": line1, "class": "resource-quantity"});
  136. list.push({"text": line2, "class": "resource-rate"});
  137. }
  138. return renderLines(list);
  139. }
  140. function displayBuildings() {
  141. for (const [key, value] of Object.entries(belongings)) {
  142. if (!belongings[key].visible) {
  143. if (resources.food * 10 >= costOfBuilding(key)) {
  144. unlockBuilding(key);
  145. } else {
  146. continue;
  147. }
  148. belongings[key].visible = true;
  149. document.querySelector("#building-" + key).classList.remove("hidden");
  150. }
  151. let button = document.querySelector("#building-" + key);
  152. let name = document.querySelector("#building-" + key + " > .building-button-name");
  153. let cost = document.querySelector("#building-" + key + " > .building-button-cost");
  154. name.innerText = value.count + " " + (value.count == 1 ? buildings[key].name : buildings[key].plural);
  155. cost.innerText = render(costOfBuilding(key)) + " food";
  156. if (costOfBuilding(key) > resources.food) {
  157. button.classList.add("building-button-disabled");
  158. cost.classList.add("building-button-cost-invalid");
  159. } else {
  160. button.classList.remove("building-button-disabled");
  161. cost.classList.add("building-button-cost-valid");
  162. }
  163. }
  164. }
  165. function canAfford(cost) {
  166. for (const [resource, amount] of Object.entries(cost)) {
  167. if (resources[resource] < amount) {
  168. return false;
  169. }
  170. }
  171. return true;
  172. }
  173. function spend(cost) {
  174. for (const [resource, amount] of Object.entries(cost)) {
  175. resources[resource] -= amount;
  176. }
  177. }
  178. function switchShowOwnedUpgrades() {
  179. if (showOwnedUpgrades) {
  180. document.querySelector("#upgrades").innerText = "Upgrades";
  181. } else {
  182. document.querySelector("#upgrades").innerText = "Owned Upgrades";
  183. }
  184. showOwnedUpgrades = !showOwnedUpgrades;
  185. }
  186. function displayUpgrades(owned) {
  187. if (owned) {
  188. Object.entries(ownedUpgrades).forEach(([key, val]) => {
  189. let button = document.querySelector("#upgrade-" + key);
  190. if (val) {
  191. button.classList.remove("hidden");
  192. } else {
  193. button.classList.add("hidden");
  194. }
  195. });
  196. }
  197. else {
  198. for (let id of remainingUpgrades) {
  199. let button = document.querySelector("#upgrade-" + id);
  200. if (ownedUpgrades[id]) {
  201. button.classList.add("hidden");
  202. continue;
  203. }
  204. if (upgradeReachable(id)) {
  205. button.classList.remove("hidden");
  206. } else {
  207. button.classList.add("hidden");
  208. }
  209. if (upgradeAvailable(id)) {
  210. button.classList.remove("upgrade-button-inactive");
  211. } else {
  212. button.classList.add("upgrade-button-inactive");
  213. }
  214. }
  215. // we aren't trimming the list of upgrades now
  216. // because we need to switch between owned and unowned upgrades
  217. // - thus we need to be able to show or hide anything
  218. /*
  219. for (let i = remainingUpgrades.length-1; i >= 0; i--) {
  220. if (ownedUpgrades[remainingUpgrades[i]]) {
  221. remainingUpgrades.splice(i, 1);
  222. }
  223. }*/
  224. }
  225. }
  226. function updateClickBonus() {
  227. let bonus = 0;
  228. for (let effect of effects["click"]) {
  229. if (ownedUpgrades[effect.parent]) {
  230. bonus = effect.apply(bonus, currentProductivity["food"]);
  231. }
  232. }
  233. clickBonus = bonus;
  234. }
  235. function updateClickVictim() {
  236. for (let effect of effects["click-victim"]) {
  237. if (ownedUpgrades[effect.parent]) {
  238. clickVictim = effect.id;
  239. document.querySelector("#tasty-micro").innerText = "Eat " + buildings[effect.id].name;
  240. }
  241. }
  242. }
  243. function buyUpgrade(id, e) {
  244. if (ownedUpgrades[id]) {
  245. return;
  246. }
  247. let upgrade = upgrades[id];
  248. if (!upgradeAvailable(id)) {
  249. return;
  250. }
  251. spend(upgrade.cost);
  252. ownedUpgrades[id] = true;
  253. let text = "Bought " + upgrade.name + "!";
  254. clickPopup(text, "upgrade", [e.clientX, e.clientY]);
  255. updateProductivity();
  256. updateClickBonus();
  257. updateClickVictim();
  258. }
  259. function eatPrey() {
  260. const add = buildings[clickVictim]["prod"] * 10 * productivityMultiplierOf(clickVictim) + clickBonus;
  261. resources.food += add;
  262. return add;
  263. }
  264. // setup stuff lol
  265. // we'll initialize the dict of buildings we can own
  266. function setup() {
  267. // create static data
  268. createTemplateUpgrades();
  269. // prepare dynamic stuff
  270. initializeData();
  271. createButtons();
  272. createDisplays();
  273. registerListeners();
  274. load();
  275. unlockAtStart();
  276. updateAll();
  277. }
  278. function unlockAtStart() {
  279. unlockBuilding("micro");
  280. for (const [key, value] of Object.entries(belongings)) {
  281. if (belongings[key].visible) {
  282. unlockBuilding(key);
  283. }
  284. }
  285. }
  286. function unlockBuilding(id) {
  287. belongings[id].visible = true;
  288. document.querySelector("#building-" + id).classList.remove("hidden");
  289. }
  290. function initializeData() {
  291. for (const [key, value] of Object.entries(buildings)) {
  292. belongings[key] = {};
  293. belongings[key].count = 0;
  294. belongings[key].visible = false;
  295. }
  296. for (const [key, value] of Object.entries(resourceTypes)) {
  297. resources[key] = 0;
  298. currentProductivity[key] = 0;
  299. }
  300. for (const [id, upgrade] of Object.entries(upgrades)) {
  301. ownedUpgrades[id] = false;
  302. for (let effect of upgrade.effects) {
  303. if (effects[effect.type] === undefined) {
  304. effects[effect.type] = [];
  305. }
  306. // copy the data and add an entry for the upgrade id that owns the effect
  307. let newEffect = {};
  308. for (const [key, value] of Object.entries(effect)) {
  309. newEffect[key] = value;
  310. }
  311. newEffect.parent = id;
  312. // unfortunate name collision here
  313. // I'm using apply() to pass on any number of arguments to the
  314. // apply() function of the effect type
  315. newEffect.apply = function(...args) { return effect_types[effect.type].apply.apply(null, [effect].concat(args)); }
  316. effects[effect.type].push(newEffect);
  317. }
  318. }
  319. }
  320. function registerListeners() {
  321. document.querySelector("#tasty-micro").addEventListener("click", (e) => {
  322. const add = eatPrey();
  323. const text = "+" + round(add, 1) + " food";
  324. const gulp = "*glp*";
  325. clickPopup(text, "food", [e.clientX, e.clientY]);
  326. clickPopup(gulp, "gulp", [e.clientX, e.clientY]);
  327. });
  328. document.querySelector("#save").addEventListener("click", save);
  329. document.querySelector("#reset").addEventListener("click", reset);
  330. document.querySelector("#upgrades").addEventListener("click", switchShowOwnedUpgrades);
  331. }
  332. function createButtons() {
  333. createBuildings();
  334. createUpgrades();
  335. }
  336. function createBuildings() {
  337. let container = document.querySelector("#buildings-list");
  338. for (const [key, value] of Object.entries(buildings)) {
  339. let button = document.createElement("div");
  340. button.classList.add("building-button");
  341. button.classList.add("hidden");
  342. button.id = "building-" + key;
  343. let buttonName = document.createElement("div");
  344. buttonName.classList.add("building-button-name");
  345. let buttonCost = document.createElement("div");
  346. buttonCost.classList.add("building-button-cost");
  347. let buildingIcon = document.createElement("i");
  348. buildingIcon.classList.add("fas");
  349. buildingIcon.classList.add(value.icon);
  350. button.appendChild(buttonName);
  351. button.appendChild(buttonCost);
  352. button.appendChild(buildingIcon);
  353. button.addEventListener("mousemove", function(e) { buildingTooltip(key, e); });
  354. button.addEventListener("mouseleave", function() { buildingTooltipRemove(); });
  355. button.addEventListener("click", function() { buyBuilding(key); });
  356. button.addEventListener("click", function(e) { buildingTooltip(key, e); });
  357. container.appendChild(button);
  358. }
  359. }
  360. // do we have previous techs and at least one of each building?
  361. function upgradeReachable(id) {
  362. if (ownedUpgrades[id]) {
  363. return false;
  364. }
  365. if (upgrades[id].prereqs !== undefined ){
  366. for (const [type, reqs] of Object.entries(upgrades[id].prereqs)) {
  367. if (type == "buildings") {
  368. for (const [building, amount] of Object.entries(reqs)) {
  369. if (belongings[building].count == 0) {
  370. return false;
  371. }
  372. }
  373. }
  374. else if (type == "upgrades") {
  375. for (let upgrade of reqs) {
  376. if (!ownedUpgrades[upgrade]) {
  377. return false;
  378. }
  379. }
  380. }
  381. }
  382. }
  383. return true;
  384. }
  385. function upgradeAvailable(id) {
  386. if (!upgradeReachable(id)) {
  387. return false;
  388. }
  389. if (!canAfford(upgrades[id].cost)) {
  390. return false;
  391. }
  392. if (upgrades[id].prereqs !== undefined) {
  393. for (const [type, reqs] of Object.entries(upgrades[id].prereqs)) {
  394. if (type == "buildings") {
  395. for (const [building, amount] of Object.entries(upgrades[id].prereqs[type])) {
  396. if (belongings[building].count < amount) {
  397. return false;
  398. }
  399. }
  400. } else if (type == "productivity") {
  401. for (const [key, value] of Object.entries(reqs)) {
  402. if (currentProductivity[key] < value) {
  403. return false;
  404. }
  405. }
  406. }
  407. }
  408. }
  409. return true;
  410. }
  411. function createUpgrades() {
  412. let container = document.querySelector("#upgrades-list");
  413. for (const [key, value] of Object.entries(upgrades)) {
  414. remainingUpgrades.push(key);
  415. let button = document.createElement("div");
  416. button.classList.add("upgrade-button");
  417. button.classList.add("hidden");
  418. button.id = "upgrade-" + key;
  419. let buttonName = document.createElement("div");
  420. buttonName.classList.add("upgrade-button-name");
  421. buttonName.innerText = value.name;
  422. let upgradeIcon = document.createElement("i");
  423. upgradeIcon.classList.add("fas");
  424. upgradeIcon.classList.add(value.icon);
  425. button.appendChild(buttonName);
  426. button.appendChild(upgradeIcon);
  427. button.addEventListener("mouseenter", function(e) { upgradeTooltip(key, e); });
  428. button.addEventListener("mousemove", function(e) { upgradeTooltip(key, e); });
  429. button.addEventListener("mouseleave", function() { upgradeTooltipRemove(); });
  430. button.addEventListener("click", function(e) { buyUpgrade(key, e); });
  431. container.appendChild(button);
  432. }
  433. }
  434. function createDisplays() {
  435. // nop
  436. }
  437. function renderLine(line) {
  438. let div = document.createElement("div");
  439. div.innerText = line.text;
  440. if (line.valid !== undefined) {
  441. if (line.valid) {
  442. div.classList.add("cost-met");
  443. } else {
  444. div.classList.add("cost-unmet");
  445. }
  446. }
  447. if (line.class !== undefined) {
  448. for (let entry of line.class.split(",")) {
  449. div.classList.add(entry);
  450. }
  451. }
  452. return div;
  453. }
  454. function renderLines(lines) {
  455. let divs = [];
  456. for (let line of lines) {
  457. divs.push(renderLine(line));
  458. }
  459. return divs;
  460. }
  461. function renderCost(cost) {
  462. let list = [];
  463. list.push({
  464. "text": "Cost:"
  465. });
  466. for (const [key, value] of Object.entries(cost)) {
  467. list.push({
  468. "text": render(value,0) + " " + resourceTypes[key].name,
  469. "valid": resources[key] >= value
  470. });
  471. }
  472. return renderLines(list);
  473. }
  474. function renderPrereqs(prereqs) {
  475. let list = [];
  476. if (prereqs === undefined) {
  477. return renderLines(list);
  478. }
  479. list.push({
  480. "text": "Own:"
  481. });
  482. for (const [key, value] of Object.entries(prereqs)) {
  483. if (key == "buildings") {
  484. for (const [id, amount] of Object.entries(prereqs.buildings)) {
  485. list.push({
  486. "text": buildings[id].name + " x" + render(amount,0),
  487. "valid": belongings[id].count >= amount
  488. });
  489. }
  490. } else if (key == "productivity") {
  491. for (const [id, amount] of Object.entries(prereqs.productivity)) {
  492. list.push({
  493. "text": render(amount,0) + " " + resourceTypes[id].name + "/s",
  494. "valid": currentProductivity[id] >= amount
  495. });
  496. }
  497. }
  498. }
  499. return renderLines(list);
  500. }
  501. function renderEffects(effectList) {
  502. let list = [];
  503. for (let effect of effectList) {
  504. list.push({"text": effect_types[effect.type].desc(effect)});
  505. }
  506. return renderLines(list);
  507. }
  508. function clickPopup(text, type, location) {
  509. const div = document.createElement("div");
  510. div.textContent = text;
  511. div.classList.add("click-popup-" + type);
  512. var direction;
  513. if (type == "food") {
  514. direction = -150;
  515. } else if (type == "gulp") {
  516. direction = -150;
  517. } else if (type == "upgrade") {
  518. direction = -50;
  519. } else if (type == "info") {
  520. direction = 0;
  521. }
  522. direction *= Math.random() * 0.5 + 1;
  523. direction = Math.round(direction) + "px"
  524. div.style.setProperty("--target", direction)
  525. div.style.left = location[0] + "px";
  526. div.style.top = location[1] + "px";
  527. const body = document.querySelector("body");
  528. body.appendChild(div);
  529. setTimeout(() => {
  530. body.removeChild(div);
  531. }, 2000);
  532. }
  533. function doNews() {
  534. const state = {
  535. ownedUpgrades: ownedUpgrades,
  536. resources: resources,
  537. currentProductivity: currentProductivity,
  538. belongings: belongings
  539. };
  540. let options = [];
  541. news.forEach(entry => {
  542. if (entry.condition(state)) {
  543. options = options.concat(entry.lines);
  544. }
  545. });
  546. const choice = Math.floor(Math.random() * options.length);
  547. showNews(options[choice](state));
  548. setTimeout(() => {
  549. doNews();
  550. }, 15000 + Math.random() * 2500);
  551. }
  552. function showNews(text) {
  553. const div = document.createElement("div");
  554. div.textContent = text;
  555. div.classList.add("news-text");
  556. const body = document.querySelector("body");
  557. body.appendChild(div);
  558. setTimeout(() => {
  559. body.removeChild(div);
  560. }, 10000);
  561. }
  562. function doPowerup() {
  563. const lifetime = 10000;
  564. const button = document.createElement("div");
  565. const left = Math.round(Math.random() * 50 + 25) + "%";
  566. const top = Math.round(Math.random() * 50 + 25) + "%";
  567. button.classList.add("powerup");
  568. button.style.setProperty("--lifetime", lifetime/1000 + "s");
  569. button.style.setProperty("--leftpos", left);
  570. button.style.setProperty("--toppos", top);
  571. const body = document.querySelector("body");
  572. body.appendChild(button);
  573. const choices = [];
  574. Object.entries(powerups).forEach(([key, val]) => {
  575. choices.push(key);
  576. });
  577. const choice = Math.floor(Math.random() * choices.length);
  578. const powerup = powerups[choices[choice]];
  579. const icon = document.createElement("div");
  580. icon.classList.add("fas");
  581. icon.classList.add(powerup.icon);
  582. button.appendChild(icon);
  583. const remove = setTimeout(() => {
  584. body.removeChild(button);
  585. }, lifetime);
  586. setTimeout(() => {
  587. doPowerup();
  588. }, 20000);
  589. const state = {
  590. ownedUpgrades: ownedUpgrades,
  591. resources: resources,
  592. currentProductivity: currentProductivity,
  593. belongings: belongings
  594. };
  595. button.addEventListener("mousedown", e => {
  596. if (powerup.duration !== undefined) {
  597. addPowerup(powerup);
  598. } else {
  599. powerup.effect(state);
  600. }
  601. powerup.popup(powerup, e);
  602. button.classList.add("powerup-clicked");
  603. resources.food += 1000;
  604. clearTimeout(remove);
  605. setTimeout(() => {
  606. body.removeChild(button);
  607. }, 500);
  608. });
  609. }
  610. function fillTooltip(type, field, content) {
  611. let item = document.querySelector("#" + type + "-tooltip-" + field);
  612. if (typeof(content) === "string") {
  613. item.innerText = content;
  614. } else {
  615. replaceChildren(item, content);
  616. }
  617. }
  618. function upgradeTooltip(id, event) {
  619. let tooltip = document.querySelector("#upgrade-tooltip");
  620. tooltip.style.setProperty("display", "inline-block");
  621. fillTooltip("upgrade", "name", upgrades[id].name);
  622. fillTooltip("upgrade", "desc", upgrades[id].desc);
  623. fillTooltip("upgrade", "effect", renderEffects(upgrades[id].effects));
  624. fillTooltip("upgrade", "cost", renderCost(upgrades[id].cost));
  625. fillTooltip("upgrade", "prereqs", renderPrereqs(upgrades[id].prereqs));
  626. let yOffset = tooltip.parentElement.getBoundingClientRect().y;
  627. let tooltipSize = tooltip.getBoundingClientRect().height;
  628. let yTrans = Math.round(event.clientY - yOffset);
  629. var body = document.body,
  630. html = document.documentElement;
  631. var height = Math.max(window.innerHeight);
  632. yTrans = Math.min(yTrans, height - tooltipSize - 150);
  633. tooltip.style.setProperty("transform", "translate(-220px, " + yTrans + "px)");
  634. }
  635. function upgradeTooltipRemove() {
  636. let tooltip = document.querySelector("#upgrade-tooltip");
  637. tooltip.style.setProperty("display", "none");
  638. }
  639. function prodSummary(id) {
  640. let list = [];
  641. list.push(
  642. {"text": "Each " + buildings[id].name + " produces " + round(productivityMultiplierOf(id) * buildings[id].prod,1) + " food/sec"}
  643. );
  644. list.push(
  645. {"text": "Your " + render(belongings[id].count) + " " + (belongings[id].count == 1 ? buildings[id].name + " is": buildings[id].plural + " are") + " producing " + round(productivityOf(id),1) + " food/sec"}
  646. );
  647. let percentage = round(100 * productivityOf(id) / currentProductivity["food"], 2);
  648. if (isNaN(percentage)) {
  649. percentage = 0;
  650. }
  651. list.push(
  652. {"text": "(" + percentage + "% of all food)"}
  653. );
  654. return renderLines(list);
  655. }
  656. function buildingTooltip(id, event) {
  657. let tooltip = document.querySelector("#building-tooltip");
  658. tooltip.style.setProperty("display", "inline-block");
  659. fillTooltip("building", "name", buildings[id].name);
  660. fillTooltip("building", "desc", buildings[id].desc);
  661. fillTooltip("building", "cost", render(costOfBuilding(id)) + " food");
  662. fillTooltip("building", "prod", prodSummary(id));
  663. let xPos = tooltip.parentElement.getBoundingClientRect().x - 450;
  664. // wow browsers are bad
  665. var body = document.body,
  666. html = document.documentElement;
  667. var height = Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight );
  668. let yPos = Math.min(event.clientY, height - 200);
  669. tooltip.style.setProperty("transform", "translate(" + xPos + "px, " + yPos + "px)")
  670. }
  671. function buildingTooltipRemove() {
  672. let tooltip = document.querySelector("#building-tooltip");
  673. tooltip.style.setProperty("display", "none");
  674. }
  675. window.onload = function() {
  676. setup();
  677. lastTime = performance.now();
  678. doNews();
  679. doPowerup();
  680. setTimeout(updateDisplay, 1000/updateRate);
  681. setTimeout(autosave, 60000);
  682. }
  683. function autosave() {
  684. saveGame();
  685. let x = window.innerWidth / 2;
  686. let y = window.innerHeight * 9 / 10;
  687. clickPopup("Autosaving...", "info", [x, y]);
  688. setTimeout(autosave, 60000);
  689. }
  690. function save(e) {
  691. saveGame();
  692. clickPopup("Saved!", "info", [e.clientX, e.clientY]);
  693. }
  694. function saveGame() {
  695. let storage = window.localStorage;
  696. storage.setItem("save-version", "0.0.1");
  697. storage.setItem("ownedUpgrades", JSON.stringify(ownedUpgrades));
  698. storage.setItem("resources", JSON.stringify(resources));
  699. storage.setItem("belongings", JSON.stringify(belongings));
  700. }
  701. function load() {
  702. let storage = window.localStorage;
  703. if (!storage.getItem("save-version")) {
  704. return;
  705. }
  706. let newOwnedUpgrades = JSON.parse(storage.getItem("ownedUpgrades"));
  707. for (const [key, value] of Object.entries(newOwnedUpgrades)) {
  708. ownedUpgrades[key] = value;
  709. }
  710. let newResources = JSON.parse(storage.getItem("resources"));
  711. for (const [key, value] of Object.entries(newResources)) {
  712. resources[key] = value;
  713. }
  714. let newBelongings = JSON.parse(storage.getItem("belongings"));
  715. for (const [key, value] of Object.entries(newBelongings)) {
  716. belongings[key] = value;
  717. }
  718. }
  719. function reset() {
  720. window.localStorage.clear();
  721. }