cookie clicker but bigger
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

398 рядки
9.3 KiB

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