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.
 
 
 
 

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