,
+ * label: string,
+ * cachedElement?: HTMLElement,
+ * cachedVisibility?: boolean
+ * }} KeyBinding
+ */
export class HUDKeybindingOverlay extends BaseHUDPart {
- initialize() {
- this.root.hud.signals.selectedPlacementBuildingChanged.add(
- this.onSelectedBuildingForPlacementChanged,
- this
- );
+ initialize() {}
- this.trackedMapOverviewActive = new TrackedState(this.applyCssClasses, this);
+ /**
+ * HELPER / Returns if there is a building selected for placement
+ * @returns {boolean}
+ */
+ get buildingPlacementActive() {
+ const placer = this.root.hud.parts.buildingPlacer;
+ return !this.mapOverviewActive && placer && !!placer.currentMetaBuilding.get();
}
- createElements(parent) {
- const mapper = this.root.keyMapper;
-
- const getKeycode = id => {
- return getStringForKeyCode(mapper.getBinding(id).keyCode);
- };
-
- this.element = makeDiv(
- parent,
- "ingame_HUD_KeybindingOverlay",
- [],
- `
-
-
-
- ${getKeycode(KEYMAPPINGS.navigation.mapMoveUp)}
- ${getKeycode(KEYMAPPINGS.navigation.mapMoveLeft)}
- ${getKeycode(KEYMAPPINGS.navigation.mapMoveDown)}
- ${getKeycode(KEYMAPPINGS.navigation.mapMoveRight)}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${getKeycode(
- KEYMAPPINGS.massSelect.massSelectStart
- )}
+
-
-
-
-
-
-
-
-
-
-
-
- ${getKeycode(KEYMAPPINGS.placement.abortBuildingPlacement)}
-
-
-
-
- ${getKeycode(KEYMAPPINGS.placement.rotateWhilePlacing)}
-
-
-
- ` +
- (this.root.app.settings.getAllSettings().alwaysMultiplace
- ? ""
- : `
-
- ${getKeycode(
- KEYMAPPINGS.placementModifiers.placeMultiple
- )}
-
-
`) +
- `
-
-
- ${getKeycode(
- KEYMAPPINGS.placementModifiers.lockBeltDirection
- )}
-
-
-
-
- ${getKeycode(KEYMAPPINGS.placement.switchDirectionLockSide)}
-
-
- `
+ /**
+ * HELPER / Returns if there is a building selected for placement and
+ * it supports the belt planner
+ * @returns {boolean}
+ */
+ get buildingPlacementBeltPlanner() {
+ const placer = this.root.hud.parts.buildingPlacer;
+ return (
+ !this.mapOverviewActive &&
+ placer &&
+ placer.currentMetaBuilding.get() &&
+ placer.currentMetaBuilding.get().getHasDirectionLockAvailable()
);
}
/**
- *
- * @param {MetaBuilding} selectedMetaBuilding
+ * HELPER / Returns if there is a building selected for placement and
+ * it has multiplace enabled by default
+ * @returns {boolean}
*/
- onSelectedBuildingForPlacementChanged(selectedMetaBuilding) {
- this.element.classList.toggle("placementActive", !!selectedMetaBuilding);
- this.element.classList.toggle(
- "hasDirectionLock",
- selectedMetaBuilding && selectedMetaBuilding.getHasDirectionLockAvailable()
+ get buildingPlacementStaysInPlacement() {
+ const placer = this.root.hud.parts.buildingPlacer;
+ return (
+ !this.mapOverviewActive &&
+ placer &&
+ placer.currentMetaBuilding.get() &&
+ placer.currentMetaBuilding.get().getStayInPlacementMode()
);
}
- applyCssClasses() {
- this.element.classList.toggle("mapOverviewActive", this.root.camera.getIsMapOverlayActive());
+ /**
+ * HELPER / Returns if there is a blueprint selected for placement
+ * @returns {boolean}
+ */
+ get blueprintPlacementActive() {
+ const placer = this.root.hud.parts.blueprintPlacer;
+ return placer && !!placer.currentBlueprint.get();
+ }
+
+ /**
+ * HELPER / Returns if the belt planner is currently active
+ * @returns {boolean}
+ */
+ get beltPlannerActive() {
+ const placer = this.root.hud.parts.buildingPlacer;
+ return !this.mapOverviewActive && placer && placer.isDirectionLockActive;
+ }
+
+ /**
+ * HELPER / Returns if there is a last blueprint available
+ * @returns {boolean}
+ */
+ get lastBlueprintAvailable() {
+ const placer = this.root.hud.parts.blueprintPlacer;
+ return placer && !!placer.lastBlueprintUsed;
+ }
+
+ /**
+ * HELPER / Returns if there is anything selected on the map
+ * @returns {boolean}
+ */
+ get anythingSelectedOnMap() {
+ const selector = this.root.hud.parts.massSelector;
+ return selector && selector.selectedUids.size > 0;
+ }
+
+ /**
+ * HELPER / Returns if there is a building or blueprint selected for placement
+ * @returns {boolean}
+ */
+ get anyPlacementActive() {
+ return this.buildingPlacementActive || this.blueprintPlacementActive;
+ }
+
+ /**
+ * HELPER / Returns if the map overview is active
+ * @returns {boolean}
+ */
+ get mapOverviewActive() {
+ return this.root.camera.getIsMapOverlayActive();
+ }
+
+ /**
+ * Initializes the element
+ * @param {HTMLElement} parent
+ */
+ createElements(parent) {
+ const mapper = this.root.keyMapper;
+ const k = KEYMAPPINGS;
+
+ /** @type {Array} */
+ this.keybindings = [
+ {
+ // Move map - Including mouse
+ label: T.ingame.keybindingsOverlay.moveMap,
+ keys: [
+ KEYCODE_LMB,
+ DIVIDER_TOKEN,
+ k.navigation.mapMoveUp,
+ k.navigation.mapMoveLeft,
+ k.navigation.mapMoveDown,
+ k.navigation.mapMoveRight,
+ ],
+ condition: () => !this.anyPlacementActive,
+ },
+
+ {
+ // Move map - No mouse
+ label: T.ingame.keybindingsOverlay.moveMap,
+ keys: [
+ k.navigation.mapMoveUp,
+ k.navigation.mapMoveLeft,
+ k.navigation.mapMoveDown,
+ k.navigation.mapMoveRight,
+ ],
+ condition: () => this.anyPlacementActive,
+ },
+
+ {
+ // [OVERVIEW] Create marker with right click
+ label: T.ingame.keybindingsOverlay.createMarker,
+ keys: [KEYCODE_RMB],
+ condition: () => this.mapOverviewActive && !this.blueprintPlacementActive,
+ },
+
+ {
+ // Cancel placement
+ label: T.ingame.keybindingsOverlay.stopPlacement,
+ keys: [KEYCODE_RMB, DIVIDER_TOKEN, k.placement.abortBuildingPlacement],
+ condition: () => this.anyPlacementActive,
+ },
+
+ {
+ // Delete with right click
+ label: T.ingame.keybindingsOverlay.delete,
+ keys: [KEYCODE_RMB],
+ condition: () =>
+ !this.anyPlacementActive && !this.mapOverviewActive && !this.anythingSelectedOnMap,
+ },
+
+ {
+ // Area select
+ label: T.ingame.keybindingsOverlay.selectBuildings,
+ keys: [k.massSelect.massSelectStart, ADDER_TOKEN, KEYCODE_LMB],
+ condition: () => !this.anyPlacementActive && !this.anythingSelectedOnMap,
+ },
+
+ {
+ // Place building
+ label: T.ingame.keybindingsOverlay.placeBuilding,
+ keys: [KEYCODE_LMB],
+ condition: () => this.anyPlacementActive,
+ },
+
+ {
+ // Rotate
+ label: T.ingame.keybindingsOverlay.rotateBuilding,
+ keys: [k.placement.rotateWhilePlacing],
+ condition: () => this.anyPlacementActive && !this.beltPlannerActive,
+ },
+
+ {
+ // [BELT PLANNER] Flip Side
+ label: T.ingame.keybindingsOverlay.plannerSwitchSide,
+ keys: [k.placement.switchDirectionLockSide],
+ condition: () => this.beltPlannerActive,
+ },
+
+ {
+ // Place last blueprint
+ label: T.ingame.keybindingsOverlay.pasteLastBlueprint,
+ keys: [k.massSelect.pasteLastBlueprint],
+ condition: () => !this.blueprintPlacementActive && this.lastBlueprintAvailable,
+ },
+
+ {
+ // Belt planner
+ label: T.ingame.keybindingsOverlay.lockBeltDirection,
+ keys: [k.placementModifiers.lockBeltDirection],
+ condition: () => this.buildingPlacementActive && !this.beltPlannerActive,
+ },
+
+ {
+ // [SELECTION] Destroy
+ label: T.ingame.keybindingsOverlay.delete,
+ keys: [k.massSelect.confirmMassDelete],
+ condition: () => this.anythingSelectedOnMap,
+ },
+
+ {
+ // [SELECTION] Cancel
+ label: T.ingame.keybindingsOverlay.clearSelection,
+ keys: [k.general.back],
+ condition: () => this.anythingSelectedOnMap,
+ },
+ {
+ // [SELECTION] Cut
+ label: T.ingame.keybindingsOverlay.cutSelection,
+ keys: [k.massSelect.massSelectCut],
+ condition: () => this.anythingSelectedOnMap,
+ },
+
+ {
+ // [SELECTION] Copy
+ label: T.ingame.keybindingsOverlay.copySelection,
+ keys: [k.massSelect.massSelectCopy],
+ condition: () => this.anythingSelectedOnMap,
+ },
+ ];
+
+ if (!this.root.app.settings.getAllSettings().alwaysMultiplace) {
+ this.keybindings.push({
+ // Multiplace
+ label: T.ingame.keybindingsOverlay.placeMultiple,
+ keys: [k.placementModifiers.placeMultiple],
+ condition: () => this.anyPlacementActive && !this.buildingPlacementStaysInPlacement,
+ });
+ }
+
+ this.element = makeDiv(parent, "ingame_HUD_KeybindingOverlay", []);
+
+ for (let i = 0; i < this.keybindings.length; ++i) {
+ let html = "";
+ const handle = this.keybindings[i];
+
+ for (let k = 0; k < handle.keys.length; ++k) {
+ const key = handle.keys[k];
+
+ switch (key) {
+ case KEYCODE_LMB:
+ html += `
`;
+ break;
+ case KEYCODE_RMB:
+ html += `
`;
+ break;
+ case KEYCODE_MMB:
+ html += `
`;
+ break;
+ case DIVIDER_TOKEN:
+ html += ``;
+ break;
+ case ADDER_TOKEN:
+ html += `+`;
+ break;
+ default:
+ html += `${getStringForKeyCode(
+ mapper.getBinding(/** @type {KeyCode} */ (key)).keyCode
+ )}
`;
+ }
+ }
+ html += ``;
+
+ handle.cachedElement = makeDiv(this.element, null, ["binding"], html);
+ handle.cachedVisibility = false;
+ }
}
update() {
- this.trackedMapOverviewActive.set(this.root.camera.getIsMapOverlayActive());
+ for (let i = 0; i < this.keybindings.length; ++i) {
+ const handle = this.keybindings[i];
+ const visibility = handle.condition();
+ if (visibility !== handle.cachedVisibility) {
+ handle.cachedVisibility = visibility;
+ handle.cachedElement.classList.toggle("visible", visibility);
+ }
+ }
}
}
diff --git a/src/js/game/hud/parts/mass_selector.js b/src/js/game/hud/parts/mass_selector.js
index 0dc872c5..7e6710c0 100644
--- a/src/js/game/hud/parts/mass_selector.js
+++ b/src/js/game/hud/parts/mass_selector.js
@@ -17,29 +17,7 @@ import { enumHubGoalRewards } from "../../tutorial_goals";
const logger = createLogger("hud/mass_selector");
export class HUDMassSelector extends BaseHUDPart {
- createElements(parent) {
- const removalKeybinding = this.root.keyMapper
- .getBinding(KEYMAPPINGS.massSelect.confirmMassDelete)
- .getKeyCodeString();
- const abortKeybinding = this.root.keyMapper.getBinding(KEYMAPPINGS.general.back).getKeyCodeString();
- const cutKeybinding = this.root.keyMapper
- .getBinding(KEYMAPPINGS.massSelect.massSelectCut)
- .getKeyCodeString();
- const copyKeybinding = this.root.keyMapper
- .getBinding(KEYMAPPINGS.massSelect.massSelectCopy)
- .getKeyCodeString();
-
- this.element = makeDiv(
- parent,
- "ingame_HUD_MassSelector",
- [],
- T.ingame.massSelect.infoText
- .replace("", `${removalKeybinding}
`)
- .replace("", `${cutKeybinding}
`)
- .replace("", `${copyKeybinding}
`)
- .replace("", `${abortKeybinding}
`)
- );
- }
+ createElements(parent) {}
initialize() {
this.deletionMarker = Loader.getSprite("sprites/misc/deletion_marker.png");
@@ -49,6 +27,7 @@ export class HUDMassSelector extends BaseHUDPart {
this.selectedUids = new Set();
this.root.signals.entityQueuedForDestroy.add(this.onEntityDestroyed, this);
+ this.root.hud.signals.pasteBlueprintRequested.add(this.clearSelection, this);
this.root.camera.downPreHandler.add(this.onMouseDown, this);
this.root.camera.movePreHandler.add(this.onMouseMove, this);
@@ -61,7 +40,7 @@ export class HUDMassSelector extends BaseHUDPart {
this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectCut).add(this.confirmCut, this);
this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectCopy).add(this.startCopy, this);
- this.domAttach = new DynamicDomAttach(this.root, this.element);
+ this.root.hud.signals.selectedPlacementBuildingChanged.add(this.clearSelection, this);
}
/**
@@ -83,6 +62,13 @@ export class HUDMassSelector extends BaseHUDPart {
}
}
+ /**
+ * Clears the entire selection
+ */
+ clearSelection() {
+ this.selectedUids = new Set();
+ }
+
confirmDelete() {
if (this.selectedUids.size > 100) {
const { ok } = this.root.hud.parts.dialogs.showWarning(
@@ -230,10 +216,6 @@ export class HUDMassSelector extends BaseHUDPart {
}
}
- update() {
- this.domAttach.update(this.selectedUids.size > 0);
- }
-
/**
*
* @param {DrawParameters} parameters
diff --git a/src/js/game/key_action_mapper.js b/src/js/game/key_action_mapper.js
index 6a1e265c..659f01e6 100644
--- a/src/js/game/key_action_mapper.js
+++ b/src/js/game/key_action_mapper.js
@@ -88,6 +88,10 @@ for (const categoryId in KEYMAPPINGS) {
}
}
+export const KEYCODE_LMB = 1;
+export const KEYCODE_MMB = 2;
+export const KEYCODE_RMB = 3;
+
/**
* Returns a keycode -> string
* @param {number} code
@@ -95,11 +99,11 @@ for (const categoryId in KEYMAPPINGS) {
*/
export function getStringForKeyCode(code) {
switch (code) {
- case 1:
+ case KEYCODE_LMB:
return "LMB";
- case 2:
+ case KEYCODE_MMB:
return "MMB";
- case 3:
+ case KEYCODE_RMB:
return "RMB";
case 4:
return "MB4";
diff --git a/translations/base-en.yaml b/translations/base-en.yaml
index 8321e20b..afe4907d 100644
--- a/translations/base-en.yaml
+++ b/translations/base-en.yaml
@@ -285,6 +285,9 @@ ingame:
pasteLastBlueprint: Paste last blueprint
lockBeltDirection: Enable belt planner
plannerSwitchSide: Flip planner side
+ cutSelection: Cut
+ copySelection: Copy
+ clearSelection: Clear Selection
# Everything related to placing buildings (I.e. as soon as you selected a building
# from the toolbar)
@@ -320,11 +323,6 @@ ingame:
newUpgrade: A new upgrade is available!
gameSaved: Your game has been saved.
- # Mass select information, this is when you hold CTRL and then drag with your mouse
- # to select multiple buildings
- massSelect:
- infoText: Press to cut, to copy, to remove and to cancel.
-
# The "Upgrades" window
shop:
title: Upgrades