cookie clicker but bigger
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

489 Zeilen
12 KiB

  1. "use strict";
  2. let belongings = {};
  3. let ownedUpgrades = {};
  4. let remainingUpgrades = [];
  5. let resources = {};
  6. let updateRate = 60;
  7. let currentProductivity = {};
  8. function calculateProductivity() {
  9. let productivity = 0;
  10. for (const [key, value] of Object.entries(belongings)) {
  11. productivity += productivityOf(key);
  12. }
  13. for (const [key, value] of Object.entries(upgrades)) {
  14. if (!ownedUpgrades[key]) {
  15. continue;
  16. }
  17. if (value.effect.type == "prod-all") {
  18. productivity *= value.effect.amount;
  19. }
  20. }
  21. return productivity;
  22. }
  23. // here's where upgrades will go :3
  24. function productivityMultiplierOf(type) {
  25. let base = 1;
  26. for (const [key, value] of Object.entries(upgrades)) {
  27. if (!ownedUpgrades[key]) {
  28. continue;
  29. }
  30. if (value.effect.type == "prod") {
  31. if (value.effect.target == type) {
  32. base *= value.effect.amount;
  33. }
  34. }
  35. }
  36. return base;
  37. }
  38. function productivityOf(type) {
  39. let baseProd = buildings[type].prod;
  40. let prod = baseProd * productivityMultiplierOf(type);
  41. return prod * belongings[type].count;
  42. }
  43. function costOfBuilding(type) {
  44. let baseCost = buildings[type].cost
  45. let countCost = baseCost * Math.pow(1.15, belongings[type].count);
  46. return Math.round(countCost);
  47. }
  48. function buyBuilding(type) {
  49. let cost = costOfBuilding(type);
  50. if (resources.food >= cost) {
  51. belongings[type].count += 1;
  52. resources.food -= cost;
  53. }
  54. }
  55. // update stuff
  56. function updateDisplay() {
  57. updateProductivity();
  58. addResources();
  59. displayResources();
  60. displayBuildings();
  61. displayUpgrades();
  62. setTimeout(updateDisplay, 1000/updateRate);
  63. }
  64. function updateProductivity() {
  65. currentProductivity["food"] = calculateProductivity();
  66. }
  67. function addResources() {
  68. resources.food += currentProductivity["food"] * 1 / updateRate;
  69. }
  70. function displayResources() {
  71. document.getElementById("resource-food").innerText = "Food: " + render(resources.food);
  72. document.getElementById("productivity").innerText = (Math.round(calculateProductivity() * 10) / 10) + " food/sec";
  73. }
  74. function displayBuildings() {
  75. for (const [key, value] of Object.entries(belongings)) {
  76. if (!belongings[key].visible) {
  77. if (resources.food * 10 >= costOfBuilding(key)) {
  78. unlockBuilding(key);
  79. } else {
  80. continue;
  81. }
  82. belongings[key].visible = true;
  83. document.querySelector("#building-" + key).classList.remove("hidden");
  84. }
  85. let button = document.querySelector("#building-" + key);
  86. document.querySelector("#building-" + key + " > .building-button-name").innerText = value.count + " " + (value.count == 1 ? buildings[key].name : buildings[key].plural);
  87. document.querySelector("#building-" + key + " > .building-button-cost").innerText = costOfBuilding(key) + " food";
  88. if (costOfBuilding(key) > resources.food) {
  89. button.classList.add("building-button-disabled");
  90. } else {
  91. button.classList.remove("building-button-disabled");
  92. }
  93. }
  94. }
  95. function canAfford(cost) {
  96. for (const [resource, amount] of Object.entries(cost)) {
  97. if (resources[resource] < amount) {
  98. return false;
  99. }
  100. }
  101. return true;
  102. }
  103. function spend(cost) {
  104. for (const [resource, amount] of Object.entries(cost)) {
  105. resources[resource] -= amount;
  106. }
  107. }
  108. function displayUpgrades() {
  109. for (let id of remainingUpgrades) {
  110. let button = document.querySelector("#upgrade-" + id);
  111. if (ownedUpgrades[id]) {
  112. button.style.display = "none";
  113. continue;
  114. }
  115. if (upgradeReachable(id)) {
  116. button.classList.remove("hidden");
  117. } else {
  118. button.classList.add("hidden");
  119. }
  120. if (upgradeAvailable(id)) {
  121. button.classList.remove("upgrade-button-inactive");
  122. } else {
  123. button.classList.add("upgrade-button-inactive");
  124. }
  125. }
  126. // now we throw out stuff
  127. for (let i = remainingUpgrades.length-1; i >= 0; i--) {
  128. if (ownedUpgrades[remainingUpgrades[i]]) {
  129. remainingUpgrades.splice(i, 1);
  130. }
  131. }
  132. }
  133. function buyUpgrade(id) {
  134. if (ownedUpgrades[id]) {
  135. return;
  136. }
  137. let upgrade = upgrades[id];
  138. if (!upgradeAvailable(id)) {
  139. return;
  140. }
  141. spend(upgrade.cost);
  142. ownedUpgrades[id] = true;
  143. }
  144. function eatMicro() {
  145. resources.food += productivityMultiplierOf("micro");
  146. }
  147. // setup stuff lol
  148. // we'll initialize the dict of buildings we can own
  149. function setup() {
  150. initializeData();
  151. createButtons();
  152. createDisplays();
  153. registerListeners();
  154. unlockAtStart();
  155. }
  156. function unlockAtStart() {
  157. unlockBuilding("micro");
  158. }
  159. function unlockBuilding(id) {
  160. belongings[id].visible = true;
  161. document.querySelector("#building-" + id).classList.remove("hidden");
  162. }
  163. function initializeData() {
  164. for (const [key, value] of Object.entries(buildings)) {
  165. belongings[key] = {};
  166. belongings[key].count = 0;
  167. belongings[key].visible = false;
  168. }
  169. for (const [key, value] of Object.entries(resourceTypes)) {
  170. currentProductivity[key] = 0;
  171. }
  172. for (const [key, value] of Object.entries(upgrades)) {
  173. ownedUpgrades[key] = false;
  174. }
  175. }
  176. function registerListeners() {
  177. document.querySelector("#tasty-micro").addEventListener("click", eatMicro);
  178. }
  179. function createButtons() {
  180. createBuildings();
  181. createUpgrades();
  182. }
  183. function createBuildings() {
  184. let container = document.querySelector("#buildings-area");
  185. for (const [key, value] of Object.entries(buildings)) {
  186. let button = document.createElement("div");
  187. button.classList.add("building-button");
  188. button.classList.add("hidden");
  189. button.id = "building-" + key;
  190. let buttonName = document.createElement("div");
  191. buttonName.classList.add("building-button-name");
  192. let buttonCost = document.createElement("div");
  193. buttonCost.classList.add("building-button-cost");
  194. button.appendChild(buttonName);
  195. button.appendChild(buttonCost);
  196. button.addEventListener("mousemove", function(e) { buildingTooltip(key, e); });
  197. button.addEventListener("mouseleave", function() { buildingTooltipRemove(); });
  198. button.addEventListener("click", function() { buyBuilding(key); });
  199. button.addEventListener("click", function(e) { buildingTooltip(key, e); });
  200. container.appendChild(button);
  201. }
  202. }
  203. // do we have previous techs and at least one of each building?
  204. function upgradeReachable(id) {
  205. if (ownedUpgrades[id]) {
  206. return false;
  207. }
  208. for (const [type, reqs] of Object.entries(upgrades[id].prereqs)) {
  209. if (type == "buildings") {
  210. for (const [building, amount] of Object.entries(reqs)) {
  211. if (belongings[building].count == 0) {
  212. return false;
  213. }
  214. }
  215. }
  216. else if (type == "upgrades") {
  217. for (let upgrade of reqs) {
  218. if (!ownedUpgrades[upgrade]) {
  219. return false;
  220. }currentProductivity["food"] = 0;
  221. }
  222. }
  223. }
  224. return true;
  225. }
  226. function upgradeAvailable(id) {
  227. if (!upgradeReachable(id)) {
  228. return false;
  229. }
  230. if (!canAfford(upgrades[id].cost)) {
  231. return false;
  232. }
  233. for (const [type, reqs] of Object.entries(upgrades[id].prereqs)) {
  234. if (type == "buildings") {
  235. for (const [building, amount] of Object.entries(upgrades[id].prereqs[type])) {
  236. if (belongings[building].count < amount) {
  237. return false;
  238. }
  239. }
  240. } else if (type == "productivity") {
  241. console.log(type, reqs);
  242. if (currentProductivity < reqs) {
  243. return false;
  244. }
  245. }
  246. }
  247. return true;
  248. }
  249. function createUpgrades() {
  250. let container = document.querySelector("#upgrades-list");
  251. for (const [key, value] of Object.entries(upgrades)) {
  252. remainingUpgrades.push(key);
  253. let button = document.createElement("div");
  254. button.classList.add("upgrade-button");
  255. button.classList.add("hidden");
  256. button.id = "upgrade-" + key;
  257. let buttonName = document.createElement("div");
  258. buttonName.classList.add("upgrade-button-name");
  259. buttonName.innerText = value.name;
  260. button.appendChild(buttonName);
  261. button.addEventListener("mousemove", function(e) { upgradeTooltip(key, e); });
  262. button.addEventListener("mouseleave", function() { upgradeTooltipRemove(); });
  263. button.addEventListener("click", function() { buyUpgrade(key); });
  264. container.appendChild(button);
  265. }
  266. }
  267. function createDisplays() {
  268. let resourceList = document.querySelector("#resource-list");
  269. for (const [key, value] of Object.entries(resourceTypes)) {
  270. resources[key] = 0;
  271. let line = document.createElement("div");
  272. line.id = "resource-" + key;
  273. resourceList.appendChild(line);
  274. }
  275. }
  276. function renderLine(line) {
  277. let div = document.createElement("div");
  278. div.innerText = line.text;
  279. if (line.valid !== undefined) {
  280. if (line.valid) {
  281. div.classList.add("cost-met");
  282. } else {
  283. div.classList.add("cost-unmet");
  284. }
  285. }
  286. return div;
  287. }
  288. function renderLines(lines) {
  289. let divs = [];
  290. for (let line of lines) {
  291. divs.push(renderLine(line));
  292. }
  293. return divs;
  294. }
  295. function renderCost(cost) {
  296. let list = [];
  297. list.push({
  298. "text": "Cost:"
  299. });
  300. for (const [key, value] of Object.entries(cost)) {
  301. list.push({
  302. "text": value + " " + resourceTypes[key].name,
  303. "valid": resources[key] >= value
  304. });
  305. }
  306. return renderLines(list);
  307. }
  308. function renderPrereqs(prereqs) {
  309. let list = [];
  310. list.push({
  311. "text": "Own:"
  312. });
  313. for (const [key, value] of Object.entries(prereqs)) {
  314. if (key == "buildings") {
  315. for (const [id, amount] of Object.entries(prereqs.buildings)) {
  316. list.push({
  317. "text": buildings[id].name + " x" + amount,
  318. "valid": belongings[id].count >= amount
  319. });
  320. }
  321. } else if (key == "productivity") {
  322. for (const [id, amount] of Object.entries(prereqs.productivity)) {
  323. list.push({
  324. "text": amount + " " + resourceTypes[id].name + "/s",
  325. "valid": currentProductivity[id].count >= amount
  326. });
  327. }
  328. }
  329. }
  330. return renderLines(list);
  331. }
  332. function fillTooltip(type, field, content) {
  333. let item = document.querySelector("#" + type + "-tooltip-" + field);
  334. if (typeof(content) === "string") {
  335. item.innerText = content;
  336. } else {
  337. replaceChildren(item, content);
  338. }
  339. }
  340. function upgradeTooltip(id, event) {
  341. let tooltip = document.querySelector("#upgrade-tooltip");
  342. tooltip.style.setProperty("display", "inline-block");
  343. fillTooltip("upgrade", "name", upgrades[id].name);
  344. fillTooltip("upgrade", "desc", upgrades[id].desc);
  345. fillTooltip("upgrade", "effect", upgrade_types[upgrades[id].effect.type].desc(upgrades[id].effect));
  346. fillTooltip("upgrade", "cost", renderCost(upgrades[id].cost));
  347. fillTooltip("upgrade", "prereqs", renderPrereqs(upgrades[id].prereqs));
  348. let yOffset = tooltip.parentElement.getBoundingClientRect().y;
  349. let yTrans = Math.round(event.clientY - yOffset);
  350. tooltip.style.setProperty("transform", "translate(-220px, " + yTrans + "px)");
  351. }
  352. function upgradeTooltipRemove() {
  353. let tooltip = document.querySelector("#upgrade-tooltip");
  354. tooltip.style.setProperty("display", "none");
  355. }
  356. function buildingTooltip(id, event) {
  357. let tooltip = document.querySelector("#building-tooltip");
  358. tooltip.style.setProperty("display", "inline-block");
  359. fillTooltip("building", "name", buildings[id].name);
  360. fillTooltip("building", "desc", buildings[id].desc);
  361. fillTooltip("building", "cost", costOfBuilding(id) + " food");
  362. let yOffset = tooltip.parentElement.getBoundingClientRect().y;
  363. let xPos = tooltip.parentElement.getBoundingClientRect().x - 450;
  364. let yPos = event.clientY;
  365. tooltip.style.setProperty("transform", "translate(" + xPos + "px, " + yPos + "px)")
  366. }
  367. function buildingTooltipRemove() {
  368. let tooltip = document.querySelector("#building-tooltip");
  369. tooltip.style.setProperty("display", "none");
  370. }
  371. window.onload = function() {
  372. setup();
  373. setTimeout(updateDisplay, 1000/updateRate);
  374. }