|
|
|
import { BaseHUDPart } from "../base_hud_part";
|
|
|
|
import { makeDiv, removeAllChildren, formatBigNumber } from "../../../core/utils";
|
|
|
|
import { UPGRADES, TIER_LABELS } from "../../upgrades";
|
|
|
|
import { ShapeDefinition } from "../../shape_definition";
|
|
|
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
|
|
|
import { InputReceiver } from "../../../core/input_receiver";
|
|
|
|
import { KeyActionMapper } from "../../key_action_mapper";
|
|
|
|
import { Math_min } from "../../../core/builtins";
|
|
|
|
import { ClickDetector } from "../../../core/click_detector";
|
|
|
|
|
|
|
|
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"]);
|
|
|
|
this.title = makeDiv(this.dialogInner, null, ["title"], `Upgrades`);
|
|
|
|
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 { label } = UPGRADES[upgradeId];
|
|
|
|
const handle = {};
|
|
|
|
handle.requireIndexToElement = [];
|
|
|
|
|
|
|
|
// Wrapper
|
|
|
|
handle.elem = makeDiv(this.contentDiv, null, ["upgrade"]);
|
|
|
|
handle.elem.setAttribute("data-upgrade-id", upgradeId);
|
|
|
|
|
|
|
|
// Title
|
|
|
|
const title = makeDiv(handle.elem, null, ["title"], label);
|
|
|
|
|
|
|
|
// Title > Tier
|
|
|
|
handle.elemTierLabel = makeDiv(title, null, ["tier"], "Tier ?");
|
|
|
|
|
|
|
|
// 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");
|
|
|
|
handle.buyButton.innerText = "Upgrade";
|
|
|
|
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];
|
|
|
|
const { description, tiers } = UPGRADES[upgradeId];
|
|
|
|
|
|
|
|
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
|
|
|
const tierHandle = tiers[currentTier];
|
|
|
|
|
|
|
|
// Set tier
|
|
|
|
handle.elemTierLabel.innerText = "Tier " + TIER_LABELS[currentTier];
|
|
|
|
handle.elemTierLabel.setAttribute("data-tier", currentTier);
|
|
|
|
|
|
|
|
// Cleanup detectors
|
|
|
|
for (let i = 0; i < handle.requireIndexToElement.length; ++i) {
|
|
|
|
const requiredHandle = handle.requireIndexToElement[i];
|
|
|
|
requiredHandle.container.remove();
|
|
|
|
requiredHandle.pinDetector.cleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cleanup
|
|
|
|
handle.requireIndexToElement = [];
|
|
|
|
|
|
|
|
handle.elem.classList.toggle("maxLevel", !tierHandle);
|
|
|
|
|
|
|
|
if (!tierHandle) {
|
|
|
|
// Max level
|
|
|
|
handle.elemDescription.innerText = "Maximum level";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set description
|
|
|
|
handle.elemDescription.innerText = description(tierHandle.improvement);
|
|
|
|
|
|
|
|
tierHandle.required.forEach(({ shape, amount }) => {
|
|
|
|
const container = makeDiv(handle.elemRequirements, null, ["requirement"]);
|
|
|
|
|
|
|
|
const shapeDef = this.root.shapeDefinitionMgr.getShapeFromShortKey(shape);
|
|
|
|
const shapeCanvas = shapeDef.generateAsCanvas(120);
|
|
|
|
shapeCanvas.classList.add();
|
|
|
|
container.appendChild(shapeCanvas);
|
|
|
|
|
|
|
|
const progressContainer = makeDiv(container, null, ["amount"]);
|
|
|
|
const progressBar = document.createElement("label");
|
|
|
|
progressBar.classList.add("progressBar");
|
|
|
|
progressContainer.appendChild(progressBar);
|
|
|
|
|
|
|
|
const progressLabel = document.createElement("label");
|
|
|
|
progressContainer.appendChild(progressLabel);
|
|
|
|
|
|
|
|
const pinButton = document.createElement("button");
|
|
|
|
pinButton.classList.add("pin");
|
|
|
|
container.appendChild(pinButton);
|
|
|
|
|
|
|
|
if (this.root.hud.parts.pinnedShapes.isShapePinned(shape)) {
|
|
|
|
pinButton.classList.add("alreadyPinned");
|
|
|
|
}
|
|
|
|
|
|
|
|
const pinDetector = new ClickDetector(pinButton, {
|
|
|
|
consumeEvents: true,
|
|
|
|
preventDefault: true,
|
|
|
|
});
|
|
|
|
pinDetector.click.add(() => {
|
|
|
|
this.root.hud.signals.shapePinRequested.dispatch(shapeDef, amount);
|
|
|
|
pinButton.classList.add("pinned");
|
|
|
|
});
|
|
|
|
|
|
|
|
handle.requireIndexToElement.push({
|
|
|
|
container,
|
|
|
|
progressLabel,
|
|
|
|
progressBar,
|
|
|
|
definition: shapeDef,
|
|
|
|
required: amount,
|
|
|
|
pinDetector,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
this.keyActionMapper.getBinding("back").add(this.close, this);
|
|
|
|
this.keyActionMapper.getBinding("menu_open_shop").add(this.close, this);
|
|
|
|
|
|
|
|
this.close();
|
|
|
|
|
|
|
|
this.rerenderFull();
|
|
|
|
this.root.signals.upgradePurchased.add(this.rerenderFull, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup() {
|
|
|
|
document.body.classList.remove("ingameDialogOpen");
|
|
|
|
|
|
|
|
// 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 = [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
show() {
|
|
|
|
this.visible = true;
|
|
|
|
document.body.classList.add("ingameDialogOpen");
|
|
|
|
// this.background.classList.add("visible");
|
|
|
|
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
|
|
|
|
this.rerenderFull();
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|