| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | import { Math_min } from "../../../core/builtins"; | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  | import { ClickDetector } from "../../../core/click_detector"; | 
					
						
							| 
									
										
										
										
											2020-05-17 10:12:13 +00:00
										 |  |  | import { InputReceiver } from "../../../core/input_receiver"; | 
					
						
							|  |  |  | import { formatBigNumber, makeDiv } from "../../../core/utils"; | 
					
						
							|  |  |  | import { T } from "../../../translations"; | 
					
						
							| 
									
										
										
										
											2020-05-19 07:14:40 +00:00
										 |  |  | import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper"; | 
					
						
							| 
									
										
										
										
											2020-05-17 10:12:13 +00:00
										 |  |  | import { UPGRADES } from "../../upgrades"; | 
					
						
							|  |  |  | import { BaseHUDPart } from "../base_hud_part"; | 
					
						
							|  |  |  | import { DynamicDomAttach } from "../dynamic_dom_attach"; | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | export class HUDShop extends BaseHUDPart { | 
					
						
							|  |  |  |     createElements(parent) { | 
					
						
							|  |  |  |         this.background = makeDiv(parent, "ingame_HUD_Shop", ["ingameDialog"]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // DIALOG Inner / Wrapper
 | 
					
						
							|  |  |  |         this.dialogInner = makeDiv(this.background, null, ["dialogInner"]); | 
					
						
							| 
									
										
										
										
											2020-05-17 10:12:13 +00:00
										 |  |  |         this.title = makeDiv(this.dialogInner, null, ["title"], T.ingame.shop.title); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |         this.closeButton = makeDiv(this.title, null, ["closeButton"]); | 
					
						
							|  |  |  |         this.trackClicks(this.closeButton, this.close); | 
					
						
							|  |  |  |         this.contentDiv = makeDiv(this.dialogInner, null, ["content"]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.upgradeToElements = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Upgrades
 | 
					
						
							|  |  |  |         for (const upgradeId in UPGRADES) { | 
					
						
							|  |  |  |             const handle = {}; | 
					
						
							|  |  |  |             handle.requireIndexToElement = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Wrapper
 | 
					
						
							|  |  |  |             handle.elem = makeDiv(this.contentDiv, null, ["upgrade"]); | 
					
						
							|  |  |  |             handle.elem.setAttribute("data-upgrade-id", upgradeId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Title
 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:12:13 +00:00
										 |  |  |             const title = makeDiv(handle.elem, null, ["title"], T.shopUpgrades[upgradeId].name); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // Title > Tier
 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:12:13 +00:00
										 |  |  |             handle.elemTierLabel = makeDiv(title, null, ["tier"]); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // Icon
 | 
					
						
							|  |  |  |             handle.icon = makeDiv(handle.elem, null, ["icon"]); | 
					
						
							|  |  |  |             handle.icon.setAttribute("data-icon", "upgrades/" + upgradeId + ".png"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Description
 | 
					
						
							|  |  |  |             handle.elemDescription = makeDiv(handle.elem, null, ["description"], "??"); | 
					
						
							|  |  |  |             handle.elemRequirements = makeDiv(handle.elem, null, ["requirements"]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Buy button
 | 
					
						
							|  |  |  |             handle.buyButton = document.createElement("button"); | 
					
						
							|  |  |  |             handle.buyButton.classList.add("buy", "styledButton"); | 
					
						
							| 
									
										
										
										
											2020-05-17 10:12:13 +00:00
										 |  |  |             handle.buyButton.innerText = T.ingame.shop.buttonUnlock; | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |             handle.elem.appendChild(handle.buyButton); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             this.trackClicks(handle.buyButton, () => this.tryUnlockNextTier(upgradeId)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Assign handle
 | 
					
						
							|  |  |  |             this.upgradeToElements[upgradeId] = handle; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rerenderFull() { | 
					
						
							|  |  |  |         for (const upgradeId in this.upgradeToElements) { | 
					
						
							|  |  |  |             const handle = this.upgradeToElements[upgradeId]; | 
					
						
							| 
									
										
										
										
											2020-05-17 10:12:13 +00:00
										 |  |  |             const { tiers } = UPGRADES[upgradeId]; | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId); | 
					
						
							| 
									
										
										
										
											2020-05-29 20:35:41 +00:00
										 |  |  |             const currentTierMultiplier = this.root.hubGoals.upgradeImprovements[upgradeId]; | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |             const tierHandle = tiers[currentTier]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Set tier
 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:12:13 +00:00
										 |  |  |             handle.elemTierLabel.innerText = T.ingame.shop.tier.replace( | 
					
						
							|  |  |  |                 "<x>", | 
					
						
							|  |  |  |                 "" + T.ingame.shop.tierLabels[currentTier] | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |             handle.elemTierLabel.setAttribute("data-tier", currentTier); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  |             // Cleanup detectors
 | 
					
						
							|  |  |  |             for (let i = 0; i < handle.requireIndexToElement.length; ++i) { | 
					
						
							|  |  |  |                 const requiredHandle = handle.requireIndexToElement[i]; | 
					
						
							|  |  |  |                 requiredHandle.container.remove(); | 
					
						
							|  |  |  |                 requiredHandle.pinDetector.cleanup(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |             // Cleanup
 | 
					
						
							|  |  |  |             handle.requireIndexToElement = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             handle.elem.classList.toggle("maxLevel", !tierHandle); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!tierHandle) { | 
					
						
							|  |  |  |                 // Max level
 | 
					
						
							| 
									
										
										
										
											2020-05-29 20:35:41 +00:00
										 |  |  |                 handle.elemDescription.innerText = T.ingame.shop.maximumLevel.replace( | 
					
						
							|  |  |  |                     "<currentMult>", | 
					
						
							|  |  |  |                     currentTierMultiplier.toString() | 
					
						
							|  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Set description
 | 
					
						
							| 
									
										
										
										
											2020-05-29 20:35:41 +00:00
										 |  |  |             handle.elemDescription.innerText = T.shopUpgrades[upgradeId].description | 
					
						
							|  |  |  |                 .replace("<currentMult>", currentTierMultiplier.toString()) | 
					
						
							| 
									
										
										
										
											2020-06-11 09:06:28 +00:00
										 |  |  |                 .replace("<newMult>", (currentTierMultiplier + tierHandle.improvement).toString()) | 
					
						
							|  |  |  |                 // Backwards compatibility
 | 
					
						
							|  |  |  |                 .replace("<gain>", (tierHandle.improvement * 100.0).toString()); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             tierHandle.required.forEach(({ shape, amount }) => { | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  |                 const container = makeDiv(handle.elemRequirements, null, ["requirement"]); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-13 16:04:51 +00:00
										 |  |  |                 const shapeDef = this.root.shapeDefinitionMgr.getShapeFromShortKey(shape); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                 const shapeCanvas = shapeDef.generateAsCanvas(120); | 
					
						
							|  |  |  |                 shapeCanvas.classList.add(); | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  |                 container.appendChild(shapeCanvas); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  |                 const progressContainer = makeDiv(container, null, ["amount"]); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                 const progressBar = document.createElement("label"); | 
					
						
							|  |  |  |                 progressBar.classList.add("progressBar"); | 
					
						
							|  |  |  |                 progressContainer.appendChild(progressBar); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const progressLabel = document.createElement("label"); | 
					
						
							|  |  |  |                 progressContainer.appendChild(progressLabel); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  |                 const pinButton = document.createElement("button"); | 
					
						
							|  |  |  |                 pinButton.classList.add("pin"); | 
					
						
							|  |  |  |                 container.appendChild(pinButton); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-06 00:33:35 +00:00
										 |  |  |                 const currentGoalShape = this.root.hubGoals.currentGoal.definition.getHash(); | 
					
						
							|  |  |  |                 if (shape === currentGoalShape) { | 
					
						
							|  |  |  |                     pinButton.classList.add("isGoal"); | 
					
						
							|  |  |  |                 } else if (this.root.hud.parts.pinnedShapes.isShapePinned(shape)) { | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  |                     pinButton.classList.add("alreadyPinned"); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const pinDetector = new ClickDetector(pinButton, { | 
					
						
							|  |  |  |                     consumeEvents: true, | 
					
						
							|  |  |  |                     preventDefault: true, | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |                 pinDetector.click.add(() => { | 
					
						
							| 
									
										
										
										
											2020-06-06 00:33:35 +00:00
										 |  |  |                     if (this.root.hud.parts.pinnedShapes.isShapePinned(shape)) { | 
					
						
							|  |  |  |                         this.root.hud.signals.shapeUnpinRequested.dispatch(shape); | 
					
						
							|  |  |  |                         pinButton.classList.add("unpinned"); | 
					
						
							|  |  |  |                         pinButton.classList.remove("pinned", "alreadyPinned"); | 
					
						
							|  |  |  |                     } else { | 
					
						
							| 
									
										
										
										
											2020-06-12 16:38:13 +00:00
										 |  |  |                         this.root.hud.signals.shapePinRequested.dispatch(shapeDef); | 
					
						
							| 
									
										
										
										
											2020-06-06 00:33:35 +00:00
										 |  |  |                         pinButton.classList.add("pinned"); | 
					
						
							|  |  |  |                         pinButton.classList.remove("unpinned"); | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  |                 }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                 handle.requireIndexToElement.push({ | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  |                     container, | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                     progressLabel, | 
					
						
							|  |  |  |                     progressBar, | 
					
						
							|  |  |  |                     definition: shapeDef, | 
					
						
							|  |  |  |                     required: amount, | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  |                     pinDetector, | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                 }); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     renderCountsAndStatus() { | 
					
						
							|  |  |  |         for (const upgradeId in this.upgradeToElements) { | 
					
						
							|  |  |  |             const handle = this.upgradeToElements[upgradeId]; | 
					
						
							|  |  |  |             for (let i = 0; i < handle.requireIndexToElement.length; ++i) { | 
					
						
							|  |  |  |                 const { progressLabel, progressBar, definition, required } = handle.requireIndexToElement[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const haveAmount = this.root.hubGoals.getShapesStored(definition); | 
					
						
							|  |  |  |                 const progress = Math_min(haveAmount / required, 1.0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 progressLabel.innerText = formatBigNumber(haveAmount) + " / " + formatBigNumber(required); | 
					
						
							|  |  |  |                 progressBar.style.width = progress * 100.0 + "%"; | 
					
						
							|  |  |  |                 progressBar.classList.toggle("complete", progress >= 1.0); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             handle.buyButton.classList.toggle("buyable", this.root.hubGoals.canUnlockUpgrade(upgradeId)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     initialize() { | 
					
						
							|  |  |  |         this.domAttach = new DynamicDomAttach(this.root, this.background, { | 
					
						
							|  |  |  |             attachClass: "visible", | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.inputReciever = new InputReceiver("shop"); | 
					
						
							|  |  |  |         this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-19 07:14:40 +00:00
										 |  |  |         this.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.close, this); | 
					
						
							|  |  |  |         this.keyActionMapper.getBinding(KEYMAPPINGS.ingame.menuOpenShop).add(this.close, this); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.close(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.rerenderFull(); | 
					
						
							|  |  |  |         this.root.signals.upgradePurchased.add(this.rerenderFull, this); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cleanup() { | 
					
						
							|  |  |  |         document.body.classList.remove("ingameDialogOpen"); | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Cleanup detectors
 | 
					
						
							|  |  |  |         for (const upgradeId in this.upgradeToElements) { | 
					
						
							|  |  |  |             const handle = this.upgradeToElements[upgradeId]; | 
					
						
							|  |  |  |             for (let i = 0; i < handle.requireIndexToElement.length; ++i) { | 
					
						
							|  |  |  |                 const requiredHandle = handle.requireIndexToElement[i]; | 
					
						
							|  |  |  |                 requiredHandle.container.remove(); | 
					
						
							|  |  |  |                 requiredHandle.pinDetector.cleanup(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             handle.requireIndexToElement = []; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     show() { | 
					
						
							|  |  |  |         this.visible = true; | 
					
						
							|  |  |  |         document.body.classList.add("ingameDialogOpen"); | 
					
						
							|  |  |  |         // this.background.classList.add("visible");
 | 
					
						
							|  |  |  |         this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever); | 
					
						
							| 
									
										
										
										
											2020-05-14 11:29:42 +00:00
										 |  |  |         this.rerenderFull(); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     close() { | 
					
						
							|  |  |  |         this.visible = false; | 
					
						
							|  |  |  |         document.body.classList.remove("ingameDialogOpen"); | 
					
						
							|  |  |  |         this.root.app.inputMgr.makeSureDetached(this.inputReciever); | 
					
						
							|  |  |  |         this.update(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     update() { | 
					
						
							|  |  |  |         this.domAttach.update(this.visible); | 
					
						
							|  |  |  |         if (this.visible) { | 
					
						
							|  |  |  |             this.renderCountsAndStatus(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tryUnlockNextTier(upgradeId) { | 
					
						
							|  |  |  |         // Nothing
 | 
					
						
							|  |  |  |         this.root.hubGoals.tryUnlockUgprade(upgradeId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |