Update toolbar

pull/691/head
tobspr 4 years ago
parent f8371a96cf
commit 9881bd6799

@ -4,25 +4,14 @@
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
// NOTE: This flex rule may not be necessary. Need to find out intent. display: grid;
display: flex; grid-template-rows: auto auto;
flex-direction: column; justify-items: center;
background: transparent; background: transparent;
transition: transform 120ms ease-in-out; transition: transform 120ms ease-in-out;
will-change: transform; will-change: transform;
backdrop-filter: blur(D(3px));
background-color: rgba(0, 40, 80, 0.05);
@include S(border-radius, $globalBorderRadius);
@include DarkThemeOverride {
background-color: rgba(darken($darkModeGameBackground, 15), 0.4);
&#ingame_HUD_wires_toolbar {
background-color: rgba(darken($darkModeGameBackground, 5), 0.1);
}
}
&:not(.visible) { &:not(.visible) {
transform: translateX(-50%) translateY(#{D(100px)}); transform: translateX(-50%) translateY(#{D(100px)});
} }
@ -30,6 +19,34 @@
.buildings { .buildings {
display: grid; display: grid;
grid-auto-flow: column; grid-auto-flow: column;
justify-items: center;
align-self: center;
grid-row: 2 / 3;
background-color: rgba(240, 241, 243, 0.5);
@include S(border-radius, $globalBorderRadius);
@include DarkThemeOverride {
background-color: rgba(darken($darkModeGameBackground, 15), 0.4);
}
&.secondary {
grid-row: 1 / 2;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
.building {
@include S(width, 30px);
@include S(height, 22px);
background-size: 45%;
&:not(.unlocked) {
&::before {
background-size: #{D(13px)};
}
}
}
}
.building { .building {
color: $accentColorDark; color: $accentColorDark;

@ -1,51 +1,51 @@
import { enumDirection, Vector } from "../../core/vector"; import { enumDirection, Vector } from "../../core/vector";
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins"; import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
import { Entity } from "../entity"; import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building"; import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root"; import { GameRoot } from "../root";
import { DisplayComponent } from "../components/display"; import { DisplayComponent } from "../components/display";
import { enumHubGoalRewards } from "../tutorial_goals";
export class MetaDisplayBuilding extends MetaBuilding {
constructor() { export class MetaDisplayBuilding extends MetaBuilding {
super("display"); constructor() {
} super("display");
}
getSilhouetteColor() {
return "#aaaaaa"; getSilhouetteColor() {
} return "#aaaaaa";
}
/**
* @param {GameRoot} root /**
*/ * @param {GameRoot} root
getIsUnlocked(root) { */
// @todo getIsUnlocked(root) {
return true; return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_display);
} }
getDimensions() { getDimensions() {
return new Vector(1, 1); return new Vector(1, 1);
} }
getShowWiresLayerPreview() { getShowWiresLayerPreview() {
return true; return true;
} }
/** /**
* Creates the entity at the given location * Creates the entity at the given location
* @param {Entity} entity * @param {Entity} entity
*/ */
setupEntityComponents(entity) { setupEntityComponents(entity) {
entity.addComponent( entity.addComponent(
new WiredPinsComponent({ new WiredPinsComponent({
slots: [ slots: [
{ {
pos: new Vector(0, 0), pos: new Vector(0, 0),
direction: enumDirection.bottom, direction: enumDirection.bottom,
type: enumPinSlotType.logicalAcceptor, type: enumPinSlotType.logicalAcceptor,
}, },
], ],
}) })
); );
entity.addComponent(new DisplayComponent()); entity.addComponent(new DisplayComponent());
} }
} }

@ -6,6 +6,7 @@ import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
import { Entity } from "../entity"; import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building"; import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root"; import { GameRoot } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals";
export class MetaFilterBuilding extends MetaBuilding { export class MetaFilterBuilding extends MetaBuilding {
constructor() { constructor() {
@ -20,8 +21,7 @@ export class MetaFilterBuilding extends MetaBuilding {
* @param {GameRoot} root * @param {GameRoot} root
*/ */
getIsUnlocked(root) { getIsUnlocked(root) {
// @todo return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_wires_filters_and_levers);
return true;
} }
getDimensions() { getDimensions() {

@ -4,6 +4,7 @@ import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building"; import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root"; import { GameRoot } from "../root";
import { LeverComponent } from "../components/lever"; import { LeverComponent } from "../components/lever";
import { enumHubGoalRewards } from "../tutorial_goals";
export class MetaLeverBuilding extends MetaBuilding { export class MetaLeverBuilding extends MetaBuilding {
constructor() { constructor() {
@ -19,8 +20,7 @@ export class MetaLeverBuilding extends MetaBuilding {
* @param {GameRoot} root * @param {GameRoot} root
*/ */
getIsUnlocked(root) { getIsUnlocked(root) {
// @todo return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_wires_filters_and_levers);
return true;
} }
getDimensions() { getDimensions() {

@ -8,6 +8,7 @@ import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root"; import { GameRoot } from "../root";
import { BeltUnderlaysComponent } from "../components/belt_underlays"; import { BeltUnderlaysComponent } from "../components/belt_underlays";
import { BeltReaderComponent } from "../components/belt_reader"; import { BeltReaderComponent } from "../components/belt_reader";
import { enumHubGoalRewards } from "../tutorial_goals";
export class MetaReaderBuilding extends MetaBuilding { export class MetaReaderBuilding extends MetaBuilding {
constructor() { constructor() {
@ -22,8 +23,7 @@ export class MetaReaderBuilding extends MetaBuilding {
* @param {GameRoot} root * @param {GameRoot} root
*/ */
getIsUnlocked(root) { getIsUnlocked(root) {
// @todo return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_belt_reader);
return true;
} }
getDimensions() { getDimensions() {

@ -1,177 +1,217 @@
import { gMetaBuildingRegistry } from "../../../core/global_registries"; import { gMetaBuildingRegistry } from "../../../core/global_registries";
import { Signal, STOP_PROPAGATION } from "../../../core/signal"; import { Signal, STOP_PROPAGATION } from "../../../core/signal";
import { makeDiv } from "../../../core/utils"; import { makeDiv } from "../../../core/utils";
import { KEYMAPPINGS } from "../../key_action_mapper"; import { KEYMAPPINGS } from "../../key_action_mapper";
import { MetaBuilding } from "../../meta_building"; import { MetaBuilding } from "../../meta_building";
import { GameRoot } from "../../root"; import { GameRoot } from "../../root";
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 HUDBaseToolbar extends BaseHUDPart { export class HUDBaseToolbar extends BaseHUDPart {
/** /**
* @param {GameRoot} root * @param {GameRoot} root
* @param {object} param0 * @param {object} param0
* @param {Array<typeof MetaBuilding>} param0.supportedBuildings * @param {Array<typeof MetaBuilding>} param0.primaryBuildings
* @param {function} param0.visibilityCondition * @param {Array<typeof MetaBuilding>=} param0.secondaryBuildings
* @param {string} param0.htmlElementId * @param {function} param0.visibilityCondition
*/ * @param {string} param0.htmlElementId
constructor(root, { supportedBuildings, visibilityCondition, htmlElementId }) { */
super(root); constructor(root, { primaryBuildings, secondaryBuildings = [], visibilityCondition, htmlElementId }) {
super(root);
this.supportedBuildings = supportedBuildings;
this.visibilityCondition = visibilityCondition; this.primaryBuildings = primaryBuildings;
this.htmlElementId = htmlElementId; this.secondaryBuildings = secondaryBuildings;
this.visibilityCondition = visibilityCondition;
/** @type {Object.<string, { this.htmlElementId = htmlElementId;
* metaBuilding: MetaBuilding,
* unlocked: boolean, /** @type {Object.<string, {
* selected: boolean, * metaBuilding: MetaBuilding,
* element: HTMLElement, * unlocked: boolean,
* index: number * selected: boolean,
* }>} */ * element: HTMLElement,
this.buildingHandles = {}; * index: number
} * }>} */
this.buildingHandles = {};
/** }
* Should create all require elements
* @param {HTMLElement} parent /**
*/ * Should create all require elements
createElements(parent) { * @param {HTMLElement} parent
this.element = makeDiv(parent, this.htmlElementId, ["ingame_buildingsToolbar"], ""); */
} createElements(parent) {
this.element = makeDiv(parent, this.htmlElementId, ["ingame_buildingsToolbar"], "");
initialize() { }
const actionMapper = this.root.keyMapper;
/**
const items = makeDiv(this.element, null, ["buildings"]); * Returns all buildings
* @returns {Array<typeof MetaBuilding>}
for (let i = 0; i < this.supportedBuildings.length; ++i) { */
const metaBuilding = gMetaBuildingRegistry.findByClass(this.supportedBuildings[i]); get allBuildings() {
const binding = actionMapper.getBinding(KEYMAPPINGS.buildings[metaBuilding.getId()]); return [...this.primaryBuildings, ...this.secondaryBuildings];
}
const itemContainer = makeDiv(items, null, ["building"]);
itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png"); initialize() {
const actionMapper = this.root.keyMapper;
binding.add(() => this.selectBuildingForPlacement(metaBuilding)); let rowSecondary;
if (this.secondaryBuildings.length > 0) {
this.trackClicks(itemContainer, () => this.selectBuildingForPlacement(metaBuilding), { rowSecondary = makeDiv(this.element, null, ["buildings", "secondary"]);
clickSound: null,
}); this.secondaryDomAttach = new DynamicDomAttach(this.root, rowSecondary, {
attachClass: "visible",
this.buildingHandles[metaBuilding.id] = { });
metaBuilding, }
element: itemContainer,
unlocked: false, const rowPrimary = makeDiv(this.element, null, ["buildings", "primary"]);
selected: false,
index: i, const allBuildings = this.allBuildings;
};
} for (let i = 0; i < allBuildings.length; ++i) {
const metaBuilding = gMetaBuildingRegistry.findByClass(allBuildings[i]);
this.root.hud.signals.selectedPlacementBuildingChanged.add( const binding = actionMapper.getBinding(KEYMAPPINGS.buildings[metaBuilding.getId()]);
this.onSelectedPlacementBuildingChanged,
this const itemContainer = makeDiv(
); this.primaryBuildings.includes(allBuildings[i]) ? rowPrimary : rowSecondary,
null,
this.domAttach = new DynamicDomAttach(this.root, this.element, { ["building"]
timeToKeepSeconds: 0.12, );
attachClass: "visible", itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png");
}); itemContainer.setAttribute("data-id", metaBuilding.getId());
this.lastSelectedIndex = 0;
actionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildings).add(this.cycleBuildings, this); binding.add(() => this.selectBuildingForPlacement(metaBuilding));
}
this.trackClicks(itemContainer, () => this.selectBuildingForPlacement(metaBuilding), {
/** clickSound: null,
* Updates the toolbar });
*/
update() { this.buildingHandles[metaBuilding.id] = {
const visible = this.visibilityCondition(); metaBuilding,
this.domAttach.update(visible); element: itemContainer,
unlocked: false,
if (visible) { selected: false,
for (const buildingId in this.buildingHandles) { index: i,
const handle = this.buildingHandles[buildingId]; };
const newStatus = handle.metaBuilding.getIsUnlocked(this.root); }
if (handle.unlocked !== newStatus) {
handle.unlocked = newStatus; this.root.hud.signals.selectedPlacementBuildingChanged.add(
handle.element.classList.toggle("unlocked", newStatus); this.onSelectedPlacementBuildingChanged,
} this
} );
}
} this.domAttach = new DynamicDomAttach(this.root, this.element, {
timeToKeepSeconds: 0.12,
/** attachClass: "visible",
* Cycles through all buildings });
*/ this.lastSelectedIndex = 0;
cycleBuildings() { actionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildings).add(this.cycleBuildings, this);
const visible = this.visibilityCondition(); }
if (!visible) {
return; /**
} * Updates the toolbar
*/
let newBuildingFound = false; update() {
let newIndex = this.lastSelectedIndex; const visible = this.visibilityCondition();
for (let i = 0; i < this.supportedBuildings.length; ++i, ++newIndex) { this.domAttach.update(visible);
newIndex %= this.supportedBuildings.length;
const metaBuilding = gMetaBuildingRegistry.findByClass(this.supportedBuildings[newIndex]); if (visible) {
const handle = this.buildingHandles[metaBuilding.id]; let recomputeSecondaryToolbarVisibility = false;
if (!handle.selected && handle.unlocked) { for (const buildingId in this.buildingHandles) {
newBuildingFound = true; const handle = this.buildingHandles[buildingId];
break; const newStatus = handle.metaBuilding.getIsUnlocked(this.root);
} if (handle.unlocked !== newStatus) {
} handle.unlocked = newStatus;
if (!newBuildingFound) { handle.element.classList.toggle("unlocked", newStatus);
return; recomputeSecondaryToolbarVisibility = true;
} }
const metaBuildingClass = this.supportedBuildings[newIndex]; }
const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);
this.selectBuildingForPlacement(metaBuilding); if (recomputeSecondaryToolbarVisibility && this.secondaryDomAttach) {
} let anyUnlocked = false;
for (let i = 0; i < this.secondaryBuildings.length; ++i) {
/** const metaClass = gMetaBuildingRegistry.findByClass(this.secondaryBuildings[i]);
* Called when the selected building got changed if (metaClass.getIsUnlocked(this.root)) {
* @param {MetaBuilding} metaBuilding anyUnlocked = true;
*/ break;
onSelectedPlacementBuildingChanged(metaBuilding) { }
for (const buildingId in this.buildingHandles) { }
const handle = this.buildingHandles[buildingId];
const newStatus = handle.metaBuilding === metaBuilding; this.secondaryDomAttach.update(anyUnlocked);
if (handle.selected !== newStatus) { }
handle.selected = newStatus; }
handle.element.classList.toggle("selected", newStatus); }
}
if (handle.selected) { /**
this.lastSelectedIndex = handle.index; * Cycles through all buildings
} */
} cycleBuildings() {
const visible = this.visibilityCondition();
this.element.classList.toggle("buildingSelected", !!metaBuilding); if (!visible) {
} return;
}
/**
* @param {MetaBuilding} metaBuilding let newBuildingFound = false;
*/ let newIndex = this.lastSelectedIndex;
selectBuildingForPlacement(metaBuilding) { for (let i = 0; i < this.primaryBuildings.length; ++i, ++newIndex) {
if (!this.visibilityCondition()) { newIndex %= this.primaryBuildings.length;
// Not active const metaBuilding = gMetaBuildingRegistry.findByClass(this.primaryBuildings[newIndex]);
return; const handle = this.buildingHandles[metaBuilding.id];
} if (!handle.selected && handle.unlocked) {
newBuildingFound = true;
if (!metaBuilding.getIsUnlocked(this.root)) { break;
this.root.soundProxy.playUiError(); }
return STOP_PROPAGATION; }
} if (!newBuildingFound) {
return;
// Allow clicking an item again to deselect it }
for (const buildingId in this.buildingHandles) { const metaBuildingClass = this.primaryBuildings[newIndex];
const handle = this.buildingHandles[buildingId]; const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);
if (handle.selected && handle.metaBuilding === metaBuilding) { this.selectBuildingForPlacement(metaBuilding);
metaBuilding = null; }
break;
} /**
} * Called when the selected building got changed
* @param {MetaBuilding} metaBuilding
this.root.soundProxy.playUiClick(); */
this.root.hud.signals.buildingSelectedForPlacement.dispatch(metaBuilding); onSelectedPlacementBuildingChanged(metaBuilding) {
this.onSelectedPlacementBuildingChanged(metaBuilding); for (const buildingId in this.buildingHandles) {
} const handle = this.buildingHandles[buildingId];
} const newStatus = handle.metaBuilding === metaBuilding;
if (handle.selected !== newStatus) {
handle.selected = newStatus;
handle.element.classList.toggle("selected", newStatus);
}
if (handle.selected) {
this.lastSelectedIndex = handle.index;
}
}
this.element.classList.toggle("buildingSelected", !!metaBuilding);
}
/**
* @param {MetaBuilding} metaBuilding
*/
selectBuildingForPlacement(metaBuilding) {
if (!this.visibilityCondition()) {
// Not active
return;
}
if (!metaBuilding.getIsUnlocked(this.root)) {
this.root.soundProxy.playUiError();
return STOP_PROPAGATION;
}
// Allow clicking an item again to deselect it
for (const buildingId in this.buildingHandles) {
const handle = this.buildingHandles[buildingId];
if (handle.selected && handle.metaBuilding === metaBuilding) {
metaBuilding = null;
break;
}
}
this.root.soundProxy.playUiClick();
this.root.hud.signals.buildingSelectedForPlacement.dispatch(metaBuilding);
this.onSelectedPlacementBuildingChanged(metaBuilding);
}
}

@ -15,28 +15,28 @@ import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
import { HUDBaseToolbar } from "./base_toolbar"; import { HUDBaseToolbar } from "./base_toolbar";
import { MetaStorageBuilding } from "../../buildings/storage"; import { MetaStorageBuilding } from "../../buildings/storage";
const supportedBuildings = [
MetaBeltBuilding,
MetaBalancerBuilding,
MetaUndergroundBeltBuilding,
MetaMinerBuilding,
MetaCutterBuilding,
MetaRotaterBuilding,
MetaStackerBuilding,
MetaMixerBuilding,
MetaPainterBuilding,
MetaTrashBuilding,
MetaStorageBuilding,
MetaLeverBuilding,
MetaFilterBuilding,
MetaDisplayBuilding,
MetaReaderBuilding,
];
export class HUDBuildingsToolbar extends HUDBaseToolbar { export class HUDBuildingsToolbar extends HUDBaseToolbar {
constructor(root) { constructor(root) {
super(root, { super(root, {
supportedBuildings, primaryBuildings: [
MetaBeltBuilding,
MetaBalancerBuilding,
MetaUndergroundBeltBuilding,
MetaMinerBuilding,
MetaCutterBuilding,
MetaRotaterBuilding,
MetaStackerBuilding,
MetaMixerBuilding,
MetaPainterBuilding,
MetaTrashBuilding,
],
secondaryBuildings: [
MetaStorageBuilding,
MetaLeverBuilding,
MetaFilterBuilding,
MetaDisplayBuilding,
MetaReaderBuilding,
],
visibilityCondition: () => visibilityCondition: () =>
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "regular", !this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "regular",
htmlElementId: "ingame_HUD_buildings_toolbar", htmlElementId: "ingame_HUD_buildings_toolbar",

@ -6,19 +6,17 @@ import { MetaLeverBuilding } from "../../buildings/lever";
import { MetaWireTunnelBuilding } from "../../buildings/wire_tunnel"; import { MetaWireTunnelBuilding } from "../../buildings/wire_tunnel";
import { MetaVirtualProcessorBuilding } from "../../buildings/virtual_processor"; import { MetaVirtualProcessorBuilding } from "../../buildings/virtual_processor";
const supportedBuildings = [
MetaWireBuilding,
MetaWireTunnelBuilding,
MetaConstantSignalBuilding,
MetaLogicGateBuilding,
MetaLeverBuilding,
MetaVirtualProcessorBuilding,
];
export class HUDWiresToolbar extends HUDBaseToolbar { export class HUDWiresToolbar extends HUDBaseToolbar {
constructor(root) { constructor(root) {
super(root, { super(root, {
supportedBuildings, primaryBuildings: [
MetaWireBuilding,
MetaWireTunnelBuilding,
MetaConstantSignalBuilding,
MetaLogicGateBuilding,
MetaLeverBuilding,
MetaVirtualProcessorBuilding,
],
visibilityCondition: () => visibilityCondition: () =>
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "wires", !this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "wires",
htmlElementId: "ingame_HUD_wires_toolbar", htmlElementId: "ingame_HUD_wires_toolbar",

Loading…
Cancel
Save