1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

Fix mouse panning

This commit is contained in:
tobspr 2020-09-19 20:57:20 +02:00
parent ed32238412
commit 24eb060000
7 changed files with 642 additions and 621 deletions

View File

@ -872,6 +872,10 @@ export class Camera extends BasicSerializableObject {
return; return;
} }
if (this.root.hud.shouldPauseGame() || this.root.hud.hasBlockingOverlayOpen()) {
return;
}
if (this.desiredCenter || this.desiredZoom || this.currentlyMoving || this.currentlyPinching) { if (this.desiredCenter || this.desiredZoom || this.currentlyMoving || this.currentlyPinching) {
// Performing another method of movement right now // Performing another method of movement right now
return; return;

View File

@ -194,9 +194,6 @@ export class GameHUD {
* Returns true if the rendering can be paused * Returns true if the rendering can be paused
*/ */
hasBlockingOverlayOpen() { hasBlockingOverlayOpen() {
if (this.root.camera.getIsMapOverlayActive()) {
return true;
}
for (const key in this.parts) { for (const key in this.parts) {
if (this.parts[key].isBlockingOverlay()) { if (this.parts[key].isBlockingOverlay()) {
return true; return true;

View File

@ -1,211 +1,215 @@
/* typehints:start */ /* typehints:start */
import { Application } from "../../../application"; import { Application } from "../../../application";
/* typehints:end */ /* typehints:end */
import { SOUNDS } from "../../../platform/sound"; import { SOUNDS } from "../../../platform/sound";
import { DynamicDomAttach } from "../dynamic_dom_attach"; import { DynamicDomAttach } from "../dynamic_dom_attach";
import { BaseHUDPart } from "../base_hud_part"; import { BaseHUDPart } from "../base_hud_part";
import { Dialog, DialogLoading, DialogOptionChooser } from "../../../core/modal_dialog_elements"; import { Dialog, DialogLoading, DialogOptionChooser } from "../../../core/modal_dialog_elements";
import { makeDiv } from "../../../core/utils"; import { makeDiv } from "../../../core/utils";
import { T } from "../../../translations"; import { T } from "../../../translations";
import { THIRDPARTY_URLS } from "../../../core/config"; import { THIRDPARTY_URLS } from "../../../core/config";
export class HUDModalDialogs extends BaseHUDPart { export class HUDModalDialogs extends BaseHUDPart {
constructor(root, app) { constructor(root, app) {
// Important: Root is not always available here! Its also used in the main menu // Important: Root is not always available here! Its also used in the main menu
super(root); super(root);
/** @type {Application} */ /** @type {Application} */
this.app = root ? root.app : app; this.app = root ? root.app : app;
this.dialogParent = null; this.dialogParent = null;
this.dialogStack = []; this.dialogStack = [];
} }
// For use inside of the game, implementation of base hud part // For use inside of the game, implementation of base hud part
initialize() { initialize() {
this.dialogParent = document.getElementById("ingame_HUD_ModalDialogs"); this.dialogParent = document.getElementById("ingame_HUD_ModalDialogs");
this.domWatcher = new DynamicDomAttach(this.root, this.dialogParent); this.domWatcher = new DynamicDomAttach(this.root, this.dialogParent);
} }
shouldPauseRendering() { shouldPauseRendering() {
return this.dialogStack.length > 0; return this.dialogStack.length > 0;
} }
shouldPauseGame() { shouldPauseGame() {
return this.shouldPauseRendering(); return this.shouldPauseRendering();
} }
createElements(parent) { createElements(parent) {
return makeDiv(parent, "ingame_HUD_ModalDialogs"); return makeDiv(parent, "ingame_HUD_ModalDialogs");
} }
// For use outside of the game // For use outside of the game
initializeToElement(element) { initializeToElement(element) {
assert(element, "No element for dialogs given"); assert(element, "No element for dialogs given");
this.dialogParent = element; this.dialogParent = element;
} }
// Methods isBlockingOverlay() {
return this.dialogStack.length > 0;
/** }
* @param {string} title
* @param {string} text // Methods
* @param {Array<string>} buttons
*/ /**
showInfo(title, text, buttons = ["ok:good"]) { * @param {string} title
const dialog = new Dialog({ * @param {string} text
app: this.app, * @param {Array<string>} buttons
title: title, */
contentHTML: text, showInfo(title, text, buttons = ["ok:good"]) {
buttons: buttons, const dialog = new Dialog({
type: "info", app: this.app,
}); title: title,
this.internalShowDialog(dialog); contentHTML: text,
buttons: buttons,
if (this.app) { type: "info",
this.app.sound.playUiSound(SOUNDS.dialogOk); });
} this.internalShowDialog(dialog);
return dialog.buttonSignals; if (this.app) {
} this.app.sound.playUiSound(SOUNDS.dialogOk);
}
/**
* @param {string} title return dialog.buttonSignals;
* @param {string} text }
* @param {Array<string>} buttons
*/ /**
showWarning(title, text, buttons = ["ok:good"]) { * @param {string} title
const dialog = new Dialog({ * @param {string} text
app: this.app, * @param {Array<string>} buttons
title: title, */
contentHTML: text, showWarning(title, text, buttons = ["ok:good"]) {
buttons: buttons, const dialog = new Dialog({
type: "warning", app: this.app,
}); title: title,
this.internalShowDialog(dialog); contentHTML: text,
buttons: buttons,
if (this.app) { type: "warning",
this.app.sound.playUiSound(SOUNDS.dialogError); });
} this.internalShowDialog(dialog);
return dialog.buttonSignals; if (this.app) {
} this.app.sound.playUiSound(SOUNDS.dialogError);
}
/**
* @param {string} feature return dialog.buttonSignals;
* @param {string} textPrefab }
*/
showFeatureRestrictionInfo(feature, textPrefab = T.dialogs.featureRestriction.desc) { /**
const dialog = new Dialog({ * @param {string} feature
app: this.app, * @param {string} textPrefab
title: T.dialogs.featureRestriction.title, */
contentHTML: textPrefab.replace("<feature>", feature), showFeatureRestrictionInfo(feature, textPrefab = T.dialogs.featureRestriction.desc) {
buttons: ["cancel:bad", "getStandalone:good"], const dialog = new Dialog({
type: "warning", app: this.app,
}); title: T.dialogs.featureRestriction.title,
this.internalShowDialog(dialog); contentHTML: textPrefab.replace("<feature>", feature),
buttons: ["cancel:bad", "getStandalone:good"],
if (this.app) { type: "warning",
this.app.sound.playUiSound(SOUNDS.dialogOk); });
} this.internalShowDialog(dialog);
this.app.analytics.trackUiClick("demo_dialog_show"); if (this.app) {
this.app.sound.playUiSound(SOUNDS.dialogOk);
dialog.buttonSignals.cancel.add(() => { }
this.app.analytics.trackUiClick("demo_dialog_cancel");
}); this.app.analytics.trackUiClick("demo_dialog_show");
dialog.buttonSignals.getStandalone.add(() => { dialog.buttonSignals.cancel.add(() => {
this.app.analytics.trackUiClick("demo_dialog_click"); this.app.analytics.trackUiClick("demo_dialog_cancel");
window.open(THIRDPARTY_URLS.standaloneStorePage); });
});
dialog.buttonSignals.getStandalone.add(() => {
return dialog.buttonSignals; this.app.analytics.trackUiClick("demo_dialog_click");
} window.open(THIRDPARTY_URLS.standaloneStorePage);
});
showOptionChooser(title, options) {
const dialog = new DialogOptionChooser({ return dialog.buttonSignals;
app: this.app, }
title,
options, showOptionChooser(title, options) {
}); const dialog = new DialogOptionChooser({
this.internalShowDialog(dialog); app: this.app,
return dialog.buttonSignals; title,
} options,
});
// Returns method to be called when laoding finishd this.internalShowDialog(dialog);
showLoadingDialog() { return dialog.buttonSignals;
const dialog = new DialogLoading(this.app); }
this.internalShowDialog(dialog);
return this.closeDialog.bind(this, dialog); // Returns method to be called when laoding finishd
} showLoadingDialog() {
const dialog = new DialogLoading(this.app);
internalShowDialog(dialog) { this.internalShowDialog(dialog);
const elem = dialog.createElement(); return this.closeDialog.bind(this, dialog);
dialog.setIndex(this.dialogStack.length); }
// Hide last dialog in queue internalShowDialog(dialog) {
if (this.dialogStack.length > 0) { const elem = dialog.createElement();
this.dialogStack[this.dialogStack.length - 1].hide(); dialog.setIndex(this.dialogStack.length);
}
// Hide last dialog in queue
this.dialogStack.push(dialog); if (this.dialogStack.length > 0) {
this.dialogStack[this.dialogStack.length - 1].hide();
// Append dialog }
dialog.show();
dialog.closeRequested.add(this.closeDialog.bind(this, dialog)); this.dialogStack.push(dialog);
// Append to HTML // Append dialog
this.dialogParent.appendChild(elem); dialog.show();
dialog.closeRequested.add(this.closeDialog.bind(this, dialog));
document.body.classList.toggle("modalDialogActive", this.dialogStack.length > 0);
// Append to HTML
// IMPORTANT: Attach element directly, otherwise double submit is possible this.dialogParent.appendChild(elem);
this.update();
} document.body.classList.toggle("modalDialogActive", this.dialogStack.length > 0);
update() { // IMPORTANT: Attach element directly, otherwise double submit is possible
if (this.domWatcher) { this.update();
this.domWatcher.update(this.dialogStack.length > 0); }
}
} update() {
if (this.domWatcher) {
closeDialog(dialog) { this.domWatcher.update(this.dialogStack.length > 0);
dialog.destroy(); }
}
let index = -1;
for (let i = 0; i < this.dialogStack.length; ++i) { closeDialog(dialog) {
if (this.dialogStack[i] === dialog) { dialog.destroy();
index = i;
break; let index = -1;
} for (let i = 0; i < this.dialogStack.length; ++i) {
} if (this.dialogStack[i] === dialog) {
assert(index >= 0, "Dialog not in dialog stack"); index = i;
this.dialogStack.splice(index, 1); break;
}
if (this.dialogStack.length > 0) { }
// Show the dialog which was previously open assert(index >= 0, "Dialog not in dialog stack");
this.dialogStack[this.dialogStack.length - 1].show(); this.dialogStack.splice(index, 1);
}
if (this.dialogStack.length > 0) {
document.body.classList.toggle("modalDialogActive", this.dialogStack.length > 0); // Show the dialog which was previously open
} this.dialogStack[this.dialogStack.length - 1].show();
}
close() {
for (let i = 0; i < this.dialogStack.length; ++i) { document.body.classList.toggle("modalDialogActive", this.dialogStack.length > 0);
const dialog = this.dialogStack[i]; }
dialog.destroy();
} close() {
this.dialogStack = []; for (let i = 0; i < this.dialogStack.length; ++i) {
} const dialog = this.dialogStack[i];
dialog.destroy();
cleanup() { }
super.cleanup(); this.dialogStack = [];
for (let i = 0; i < this.dialogStack.length; ++i) { }
this.dialogStack[i].destroy();
} cleanup() {
this.dialogStack = []; super.cleanup();
this.dialogParent = null; for (let i = 0; i < this.dialogStack.length; ++i) {
} this.dialogStack[i].destroy();
} }
this.dialogStack = [];
this.dialogParent = null;
}
}

View File

@ -54,6 +54,10 @@ export class HUDSettingsMenu extends BaseHUDPart {
} }
} }
isBlockingOverlay() {
return this.visible;
}
returnToMenu() { returnToMenu() {
this.root.gameState.goBackToMenu(); this.root.gameState.goBackToMenu();
} }

View File

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

View File

@ -155,6 +155,10 @@ export class HUDStatistics extends BaseHUDPart {
document.body.classList.remove("ingameDialogOpen"); document.body.classList.remove("ingameDialogOpen");
} }
isBlockingOverlay() {
return this.visible;
}
show() { show() {
this.visible = true; this.visible = true;
document.body.classList.add("ingameDialogOpen"); document.body.classList.add("ingameDialogOpen");

View File

@ -1,156 +1,160 @@
import { globalConfig } from "../../../core/config"; import { globalConfig } from "../../../core/config";
import { gMetaBuildingRegistry } from "../../../core/global_registries"; import { gMetaBuildingRegistry } from "../../../core/global_registries";
import { makeDiv } from "../../../core/utils"; import { makeDiv } from "../../../core/utils";
import { SOUNDS } from "../../../platform/sound"; import { SOUNDS } from "../../../platform/sound";
import { T } from "../../../translations"; import { T } from "../../../translations";
import { defaultBuildingVariant } from "../../meta_building"; import { defaultBuildingVariant } from "../../meta_building";
import { enumHubGoalRewards } from "../../tutorial_goals"; import { enumHubGoalRewards } from "../../tutorial_goals";
import { BaseHUDPart } from "../base_hud_part"; import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach"; import { DynamicDomAttach } from "../dynamic_dom_attach";
import { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings"; import { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings";
import { InputReceiver } from "../../../core/input_receiver"; import { InputReceiver } from "../../../core/input_receiver";
export class HUDUnlockNotification extends BaseHUDPart { export class HUDUnlockNotification extends BaseHUDPart {
initialize() { initialize() {
this.visible = false; this.visible = false;
this.domAttach = new DynamicDomAttach(this.root, this.element, { this.domAttach = new DynamicDomAttach(this.root, this.element, {
timeToKeepSeconds: 0, timeToKeepSeconds: 0,
}); });
if (!(G_IS_DEV && globalConfig.debug.disableUnlockDialog)) { if (!(G_IS_DEV && globalConfig.debug.disableUnlockDialog)) {
this.root.signals.storyGoalCompleted.add(this.showForLevel, this); this.root.signals.storyGoalCompleted.add(this.showForLevel, this);
} }
this.buttonShowTimeout = null; this.buttonShowTimeout = null;
} }
createElements(parent) { createElements(parent) {
this.inputReciever = new InputReceiver("unlock-notification"); this.inputReciever = new InputReceiver("unlock-notification");
this.element = makeDiv(parent, "ingame_HUD_UnlockNotification", ["noBlur"]); this.element = makeDiv(parent, "ingame_HUD_UnlockNotification", ["noBlur"]);
const dialog = makeDiv(this.element, null, ["dialog"]); const dialog = makeDiv(this.element, null, ["dialog"]);
this.elemTitle = makeDiv(dialog, null, ["title"]); this.elemTitle = makeDiv(dialog, null, ["title"]);
this.elemSubTitle = makeDiv(dialog, null, ["subTitle"], T.ingame.levelCompleteNotification.completed); this.elemSubTitle = makeDiv(dialog, null, ["subTitle"], T.ingame.levelCompleteNotification.completed);
this.elemContents = makeDiv(dialog, null, ["contents"]); this.elemContents = makeDiv(dialog, null, ["contents"]);
this.btnClose = document.createElement("button"); this.btnClose = document.createElement("button");
this.btnClose.classList.add("close", "styledButton"); this.btnClose.classList.add("close", "styledButton");
this.btnClose.innerText = T.ingame.levelCompleteNotification.buttonNextLevel; this.btnClose.innerText = T.ingame.levelCompleteNotification.buttonNextLevel;
dialog.appendChild(this.btnClose); dialog.appendChild(this.btnClose);
this.trackClicks(this.btnClose, this.requestClose); this.trackClicks(this.btnClose, this.requestClose);
} }
/** /**
* @param {number} level * @param {number} level
* @param {enumHubGoalRewards} reward * @param {enumHubGoalRewards} reward
*/ */
showForLevel(level, reward) { showForLevel(level, reward) {
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever); this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
this.elemTitle.innerText = T.ingame.levelCompleteNotification.levelTitle.replace( this.elemTitle.innerText = T.ingame.levelCompleteNotification.levelTitle.replace(
"<level>", "<level>",
("" + level).padStart(2, "0") ("" + level).padStart(2, "0")
); );
const rewardName = T.storyRewards[reward].title; const rewardName = T.storyRewards[reward].title;
let html = ` let html = `
<div class="rewardName"> <div class="rewardName">
${T.ingame.levelCompleteNotification.unlockText.replace("<reward>", rewardName)} ${T.ingame.levelCompleteNotification.unlockText.replace("<reward>", rewardName)}
</div> </div>
<div class="rewardDesc"> <div class="rewardDesc">
${T.storyRewards[reward].desc} ${T.storyRewards[reward].desc}
</div> </div>
`; `;
html += "<div class='images'>"; html += "<div class='images'>";
const gained = enumHubGoalRewardsToContentUnlocked[reward]; const gained = enumHubGoalRewardsToContentUnlocked[reward];
if (gained) { if (gained) {
gained.forEach(([metaBuildingClass, variant]) => { gained.forEach(([metaBuildingClass, variant]) => {
const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass); const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);
html += `<div class="buildingExplanation" data-icon="building_tutorials/${ html += `<div class="buildingExplanation" data-icon="building_tutorials/${
metaBuilding.getId() + (variant === defaultBuildingVariant ? "" : "-" + variant) metaBuilding.getId() + (variant === defaultBuildingVariant ? "" : "-" + variant)
}.png"></div>`; }.png"></div>`;
}); });
} }
html += "</div>"; html += "</div>";
this.elemContents.innerHTML = html; this.elemContents.innerHTML = html;
this.visible = true; this.visible = true;
this.root.soundProxy.playUi(SOUNDS.levelComplete); this.root.soundProxy.playUi(SOUNDS.levelComplete);
if (this.buttonShowTimeout) { if (this.buttonShowTimeout) {
clearTimeout(this.buttonShowTimeout); clearTimeout(this.buttonShowTimeout);
} }
this.element.querySelector("button.close").classList.remove("unlocked"); this.element.querySelector("button.close").classList.remove("unlocked");
if (this.root.app.settings.getAllSettings().offerHints) { if (this.root.app.settings.getAllSettings().offerHints) {
this.buttonShowTimeout = setTimeout( this.buttonShowTimeout = setTimeout(
() => this.element.querySelector("button.close").classList.add("unlocked"), () => this.element.querySelector("button.close").classList.add("unlocked"),
G_IS_DEV ? 100 : 5000 G_IS_DEV ? 100 : 5000
); );
} else { } else {
this.element.querySelector("button.close").classList.add("unlocked"); this.element.querySelector("button.close").classList.add("unlocked");
} }
} }
cleanup() { cleanup() {
this.root.app.inputMgr.makeSureDetached(this.inputReciever); this.root.app.inputMgr.makeSureDetached(this.inputReciever);
if (this.buttonShowTimeout) { if (this.buttonShowTimeout) {
clearTimeout(this.buttonShowTimeout); clearTimeout(this.buttonShowTimeout);
this.buttonShowTimeout = null; this.buttonShowTimeout = null;
} }
} }
requestClose() { isBlockingOverlay() {
this.root.app.adProvider.showVideoAd().then(() => { return this.visible;
this.close(); }
if (!this.root.app.settings.getAllSettings().offerHints) { requestClose() {
return; this.root.app.adProvider.showVideoAd().then(() => {
} this.close();
if (this.root.hubGoals.level === 3) { if (!this.root.app.settings.getAllSettings().offerHints) {
const { showUpgrades } = this.root.hud.parts.dialogs.showInfo( return;
T.dialogs.upgradesIntroduction.title, }
T.dialogs.upgradesIntroduction.desc,
["showUpgrades:good:timeout"] if (this.root.hubGoals.level === 3) {
); const { showUpgrades } = this.root.hud.parts.dialogs.showInfo(
showUpgrades.add(() => this.root.hud.parts.shop.show()); T.dialogs.upgradesIntroduction.title,
} T.dialogs.upgradesIntroduction.desc,
["showUpgrades:good:timeout"]
if (this.root.hubGoals.level === 5) { );
const { showKeybindings } = this.root.hud.parts.dialogs.showInfo( showUpgrades.add(() => this.root.hud.parts.shop.show());
T.dialogs.keybindingsIntroduction.title, }
T.dialogs.keybindingsIntroduction.desc,
["showKeybindings:misc", "ok:good:timeout"] if (this.root.hubGoals.level === 5) {
); const { showKeybindings } = this.root.hud.parts.dialogs.showInfo(
showKeybindings.add(() => this.root.gameState.goToKeybindings()); T.dialogs.keybindingsIntroduction.title,
} T.dialogs.keybindingsIntroduction.desc,
}); ["showKeybindings:misc", "ok:good:timeout"]
} );
showKeybindings.add(() => this.root.gameState.goToKeybindings());
close() { }
this.root.app.inputMgr.makeSureDetached(this.inputReciever); });
if (this.buttonShowTimeout) { }
clearTimeout(this.buttonShowTimeout);
this.buttonShowTimeout = null; close() {
} this.root.app.inputMgr.makeSureDetached(this.inputReciever);
this.visible = false; if (this.buttonShowTimeout) {
} clearTimeout(this.buttonShowTimeout);
this.buttonShowTimeout = null;
update() { }
this.domAttach.update(this.visible); this.visible = false;
if (!this.visible && this.buttonShowTimeout) { }
clearTimeout(this.buttonShowTimeout);
this.buttonShowTimeout = null; update() {
} this.domAttach.update(this.visible);
} if (!this.visible && this.buttonShowTimeout) {
} clearTimeout(this.buttonShowTimeout);
this.buttonShowTimeout = null;
}
}
}