Refactor keybindings overlay to show more appropriate keybindings

pull/256/head
tobspr 4 years ago
parent ecda498cac
commit daef0f1e4e

@ -14,6 +14,10 @@
}
> .binding {
&:not(.visible) {
display: none !important;
}
display: inline-grid;
@include PlainText;
align-items: center;
@ -57,50 +61,6 @@
@include S(margin-left, 5px);
}
}
&:not(.placementActive) .binding.placementOnly,
&.mapOverviewActive .binding.placementOnly {
display: none;
}
&.placementActive:not(.mapOverviewActive) .noPlacementOnly {
display: none;
}
&:not(.mapOverviewActive) .binding.overviewOnly {
display: none;
}
&.mapOverviewActive .noOverviewOnly {
display: none;
}
&:not(.hasDirectionLock) .binding.directionLock {
display: none;
}
&.hasDirectionLock .noDirectionLock {
display: none;
}
.binding.placementOnly,
&:not(.placementActive) .binding.noPlacementOnly {
transform-origin: 0% 50%;
@include InlineAnimation(0.3s ease-in-out) {
0% {
color: $colorRedBright;
transform: scale(1.2);
}
}
}
.keybinding.builtinKey {
transition: all 0.1s ease-in-out;
transition-property: background-color, color, border-color;
background: $colorRedBright;
border-color: $colorRedBright;
color: #fff;
}
}
body.uiHidden #ingame_HUD_KeybindingOverlay .binding:not(.hudToggle) {

@ -1,22 +0,0 @@
#ingame_HUD_MassSelector {
position: absolute;
@include S(top, 50px);
left: 50%;
transform: translateX(-50%);
background: $ingameHudBg;
@include S(padding, 6px, 10px);
@include SuperSmallText;
color: #fff;
// color: #f77;
.keybinding {
vertical-align: middle;
@include S(margin, 0, 1px);
position: relative;
top: unset;
left: unset;
right: unset;
bottom: unset;
@include S(margin-top, -2px);
}
}

@ -37,7 +37,6 @@
@import "ingame_hud/shop";
@import "ingame_hud/game_menu";
@import "ingame_hud/dialogs";
@import "ingame_hud/mass_selector";
@import "ingame_hud/vignette_overlay";
@import "ingame_hud/statistics";
@import "ingame_hud/pinned_shapes";
@ -67,7 +66,6 @@ ingame_HUD_PinnedShapes,
ingame_HUD_GameMenu,
ingame_HUD_KeybindingOverlay,
ingame_HUD_Notifications,
ingame_HUD_MassSelector,
ingame_HUD_DebugInfo,
ingame_HUD_EntityDebugger,
ingame_HUD_InteractiveTutorial,
@ -101,7 +99,6 @@ body.uiHidden {
#ingame_HUD_buildings_toolbar,
#ingame_HUD_PlacementHints,
#ingame_HUD_GameMenu,
#ingame_HUD_MassSelector,
#ingame_HUD_PinnedShapes,
#ingame_HUD_Notifications,
#ingame_HUD_TutorialHints,

@ -5,6 +5,10 @@ export const CHANGELOG = [
entries: [
"The game soundtrack has been extended! There are now 4 songs with over 13 minutes of playtime from <a href='https://soundcloud.com/pettersumelius' target='blank'>Peppsen</a>!",
"Fix belt planner not placing the last belt",
"Refactor keybindings overlay to show more appropriate keybindings",
"Show keybindings for area-select in the upper left instead",
"Automatically deselect area when selecting a new building",
"Optimize performance by caching miner items (by Phlosioneer)",
],
},
{

@ -1,123 +1,309 @@
import { makeDiv } from "../../../core/utils";
import { T } from "../../../translations";
import { getStringForKeyCode, KEYMAPPINGS } from "../../key_action_mapper";
import {
getStringForKeyCode,
KEYCODE_LMB,
KEYCODE_MMB,
KEYCODE_RMB,
KEYMAPPINGS,
} from "../../key_action_mapper";
import { BaseHUDPart } from "../base_hud_part";
import { TrackedState } from "../../../core/tracked_state";
import { MetaBuilding } from "../../meta_building";
import { DynamicDomAttach } from "../dynamic_dom_attach";
const DIVIDER_TOKEN = "/";
const ADDER_TOKEN = "+";
/**
* @typedef {{ keyCode: number }} KeyCode
*/
/**
* @typedef {{
* condition: () => boolean,
* keys: Array<KeyCode|number|string>,
* 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",
[],
`
<div class="binding">
<code class="keybinding leftMouse noPlacementOnly"></code><i class="noPlacementOnly"></i>
<code class="keybinding">${getKeycode(KEYMAPPINGS.navigation.mapMoveUp)}</code>
<code class="keybinding">${getKeycode(KEYMAPPINGS.navigation.mapMoveLeft)}</code>
<code class="keybinding">${getKeycode(KEYMAPPINGS.navigation.mapMoveDown)}</code>
<code class="keybinding">${getKeycode(KEYMAPPINGS.navigation.mapMoveRight)}</code>
<label>${T.ingame.keybindingsOverlay.moveMap}</label>
</div>
<div class="binding noPlacementOnly noOverviewOnly">
<code class="keybinding rightMouse"></code>
<label>${T.ingame.keybindingsOverlay.delete}</label>
</div>
<div class="binding noPlacementOnly overviewOnly">
<code class="keybinding rightMouse"></code>
<label>${T.ingame.keybindingsOverlay.createMarker}</label>
</div>
<div class="binding noPlacementOnly">
<code class="keybinding builtinKey">${getKeycode(
KEYMAPPINGS.massSelect.massSelectStart
)}</code>+
<code class="keybinding leftMouse"></code>
<label>${T.ingame.keybindingsOverlay.selectBuildings}</label>
</div>
<div class="binding placementOnly">
<code class="keybinding leftMouse"></code>
<label>${T.ingame.keybindingsOverlay.placeBuilding}</label>
</div>
<div class="binding placementOnly">
<code class="keybinding rightMouse"></code><i></i>
<code class="keybinding">${getKeycode(KEYMAPPINGS.placement.abortBuildingPlacement)}</code>
<label>${T.ingame.keybindingsOverlay.stopPlacement}</label>
</div>
<div class="binding placementOnly">
<code class="keybinding">${getKeycode(KEYMAPPINGS.placement.rotateWhilePlacing)}</code>
<label>${T.ingame.keybindingsOverlay.rotateBuilding}</label>
</div>
` +
(this.root.app.settings.getAllSettings().alwaysMultiplace
? ""
: `
<div class="binding placementOnly noDirectionLock">
<code class="keybinding builtinKey shift">${getKeycode(
KEYMAPPINGS.placementModifiers.placeMultiple
)}</code>
<label>${T.ingame.keybindingsOverlay.placeMultiple}</label>
</div>`) +
`
<div class="binding placementOnly directionLock">
<code class="keybinding builtinKey shift">${getKeycode(
KEYMAPPINGS.placementModifiers.lockBeltDirection
)}</code>
<label>${T.ingame.keybindingsOverlay.lockBeltDirection}</label>
</div>
<div class="binding placementOnly directionLock">
<code class="keybinding">${getKeycode(KEYMAPPINGS.placement.switchDirectionLockSide)}</code>
<label>${T.ingame.keybindingsOverlay.plannerSwitchSide}</label>
</div>
`
/**
* 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<KeyBinding>} */
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 += `<code class="keybinding leftMouse"></code>`;
break;
case KEYCODE_RMB:
html += `<code class="keybinding rightMouse"></code>`;
break;
case KEYCODE_MMB:
html += `<code class="keybinding middleMouse"></code>`;
break;
case DIVIDER_TOKEN:
html += `<i></i>`;
break;
case ADDER_TOKEN:
html += `+`;
break;
default:
html += `<code class="keybinding">${getStringForKeyCode(
mapper.getBinding(/** @type {KeyCode} */ (key)).keyCode
)}</code>`;
}
}
html += `<label>${handle.label}</label>`;
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);
}
}
}
}

@ -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("<keyDelete>", `<code class='keybinding'>${removalKeybinding}</code>`)
.replace("<keyCut>", `<code class='keybinding'>${cutKeybinding}</code>`)
.replace("<keyCopy>", `<code class='keybinding'>${copyKeybinding}</code>`)
.replace("<keyCancel>", `<code class='keybinding'>${abortKeybinding}</code>`)
);
}
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

@ -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";

@ -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 <keyCut> to cut, <keyCopy> to copy, <keyDelete> to remove and <keyCancel> to cancel.
# The "Upgrades" window
shop:
title: Upgrades

Loading…
Cancel
Save