parent
f8371a96cf
commit
9881bd6799
@ -1,51 +1,51 @@
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { DisplayComponent } from "../components/display";
|
||||
|
||||
export class MetaDisplayBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("display");
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#aaaaaa";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
// @todo
|
||||
return true;
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
return new Vector(1, 1);
|
||||
}
|
||||
|
||||
getShowWiresLayerPreview() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
entity.addComponent(
|
||||
new WiredPinsComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
direction: enumDirection.bottom,
|
||||
type: enumPinSlotType.logicalAcceptor,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
entity.addComponent(new DisplayComponent());
|
||||
}
|
||||
}
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { DisplayComponent } from "../components/display";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
|
||||
export class MetaDisplayBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("display");
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#aaaaaa";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_display);
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
return new Vector(1, 1);
|
||||
}
|
||||
|
||||
getShowWiresLayerPreview() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
entity.addComponent(
|
||||
new WiredPinsComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
direction: enumDirection.bottom,
|
||||
type: enumPinSlotType.logicalAcceptor,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
entity.addComponent(new DisplayComponent());
|
||||
}
|
||||
}
|
||||
|
@ -1,177 +1,217 @@
|
||||
import { gMetaBuildingRegistry } from "../../../core/global_registries";
|
||||
import { Signal, STOP_PROPAGATION } from "../../../core/signal";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { MetaBuilding } from "../../meta_building";
|
||||
import { GameRoot } from "../../root";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
export class HUDBaseToolbar extends BaseHUDPart {
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
* @param {object} param0
|
||||
* @param {Array<typeof MetaBuilding>} param0.supportedBuildings
|
||||
* @param {function} param0.visibilityCondition
|
||||
* @param {string} param0.htmlElementId
|
||||
*/
|
||||
constructor(root, { supportedBuildings, visibilityCondition, htmlElementId }) {
|
||||
super(root);
|
||||
|
||||
this.supportedBuildings = supportedBuildings;
|
||||
this.visibilityCondition = visibilityCondition;
|
||||
this.htmlElementId = htmlElementId;
|
||||
|
||||
/** @type {Object.<string, {
|
||||
* metaBuilding: MetaBuilding,
|
||||
* unlocked: boolean,
|
||||
* selected: boolean,
|
||||
* element: HTMLElement,
|
||||
* index: number
|
||||
* }>} */
|
||||
this.buildingHandles = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Should create all require elements
|
||||
* @param {HTMLElement} parent
|
||||
*/
|
||||
createElements(parent) {
|
||||
this.element = makeDiv(parent, this.htmlElementId, ["ingame_buildingsToolbar"], "");
|
||||
}
|
||||
|
||||
initialize() {
|
||||
const actionMapper = this.root.keyMapper;
|
||||
|
||||
const items = makeDiv(this.element, null, ["buildings"]);
|
||||
|
||||
for (let i = 0; i < this.supportedBuildings.length; ++i) {
|
||||
const metaBuilding = gMetaBuildingRegistry.findByClass(this.supportedBuildings[i]);
|
||||
const binding = actionMapper.getBinding(KEYMAPPINGS.buildings[metaBuilding.getId()]);
|
||||
|
||||
const itemContainer = makeDiv(items, null, ["building"]);
|
||||
itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png");
|
||||
|
||||
binding.add(() => this.selectBuildingForPlacement(metaBuilding));
|
||||
|
||||
this.trackClicks(itemContainer, () => this.selectBuildingForPlacement(metaBuilding), {
|
||||
clickSound: null,
|
||||
});
|
||||
|
||||
this.buildingHandles[metaBuilding.id] = {
|
||||
metaBuilding,
|
||||
element: itemContainer,
|
||||
unlocked: false,
|
||||
selected: false,
|
||||
index: i,
|
||||
};
|
||||
}
|
||||
|
||||
this.root.hud.signals.selectedPlacementBuildingChanged.add(
|
||||
this.onSelectedPlacementBuildingChanged,
|
||||
this
|
||||
);
|
||||
|
||||
this.domAttach = new DynamicDomAttach(this.root, this.element, {
|
||||
timeToKeepSeconds: 0.12,
|
||||
attachClass: "visible",
|
||||
});
|
||||
this.lastSelectedIndex = 0;
|
||||
actionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildings).add(this.cycleBuildings, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the toolbar
|
||||
*/
|
||||
update() {
|
||||
const visible = this.visibilityCondition();
|
||||
this.domAttach.update(visible);
|
||||
|
||||
if (visible) {
|
||||
for (const buildingId in this.buildingHandles) {
|
||||
const handle = this.buildingHandles[buildingId];
|
||||
const newStatus = handle.metaBuilding.getIsUnlocked(this.root);
|
||||
if (handle.unlocked !== newStatus) {
|
||||
handle.unlocked = newStatus;
|
||||
handle.element.classList.toggle("unlocked", newStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles through all buildings
|
||||
*/
|
||||
cycleBuildings() {
|
||||
const visible = this.visibilityCondition();
|
||||
if (!visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newBuildingFound = false;
|
||||
let newIndex = this.lastSelectedIndex;
|
||||
for (let i = 0; i < this.supportedBuildings.length; ++i, ++newIndex) {
|
||||
newIndex %= this.supportedBuildings.length;
|
||||
const metaBuilding = gMetaBuildingRegistry.findByClass(this.supportedBuildings[newIndex]);
|
||||
const handle = this.buildingHandles[metaBuilding.id];
|
||||
if (!handle.selected && handle.unlocked) {
|
||||
newBuildingFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!newBuildingFound) {
|
||||
return;
|
||||
}
|
||||
const metaBuildingClass = this.supportedBuildings[newIndex];
|
||||
const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);
|
||||
this.selectBuildingForPlacement(metaBuilding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the selected building got changed
|
||||
* @param {MetaBuilding} metaBuilding
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
import { gMetaBuildingRegistry } from "../../../core/global_registries";
|
||||
import { Signal, STOP_PROPAGATION } from "../../../core/signal";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { MetaBuilding } from "../../meta_building";
|
||||
import { GameRoot } from "../../root";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
export class HUDBaseToolbar extends BaseHUDPart {
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
* @param {object} param0
|
||||
* @param {Array<typeof MetaBuilding>} param0.primaryBuildings
|
||||
* @param {Array<typeof MetaBuilding>=} param0.secondaryBuildings
|
||||
* @param {function} param0.visibilityCondition
|
||||
* @param {string} param0.htmlElementId
|
||||
*/
|
||||
constructor(root, { primaryBuildings, secondaryBuildings = [], visibilityCondition, htmlElementId }) {
|
||||
super(root);
|
||||
|
||||
this.primaryBuildings = primaryBuildings;
|
||||
this.secondaryBuildings = secondaryBuildings;
|
||||
this.visibilityCondition = visibilityCondition;
|
||||
this.htmlElementId = htmlElementId;
|
||||
|
||||
/** @type {Object.<string, {
|
||||
* metaBuilding: MetaBuilding,
|
||||
* unlocked: boolean,
|
||||
* selected: boolean,
|
||||
* element: HTMLElement,
|
||||
* index: number
|
||||
* }>} */
|
||||
this.buildingHandles = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Should create all require elements
|
||||
* @param {HTMLElement} parent
|
||||
*/
|
||||
createElements(parent) {
|
||||
this.element = makeDiv(parent, this.htmlElementId, ["ingame_buildingsToolbar"], "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all buildings
|
||||
* @returns {Array<typeof MetaBuilding>}
|
||||
*/
|
||||
get allBuildings() {
|
||||
return [...this.primaryBuildings, ...this.secondaryBuildings];
|
||||
}
|
||||
|
||||
initialize() {
|
||||
const actionMapper = this.root.keyMapper;
|
||||
let rowSecondary;
|
||||
if (this.secondaryBuildings.length > 0) {
|
||||
rowSecondary = makeDiv(this.element, null, ["buildings", "secondary"]);
|
||||
|
||||
this.secondaryDomAttach = new DynamicDomAttach(this.root, rowSecondary, {
|
||||
attachClass: "visible",
|
||||
});
|
||||
}
|
||||
|
||||
const rowPrimary = makeDiv(this.element, null, ["buildings", "primary"]);
|
||||
|
||||
const allBuildings = this.allBuildings;
|
||||
|
||||
for (let i = 0; i < allBuildings.length; ++i) {
|
||||
const metaBuilding = gMetaBuildingRegistry.findByClass(allBuildings[i]);
|
||||
const binding = actionMapper.getBinding(KEYMAPPINGS.buildings[metaBuilding.getId()]);
|
||||
|
||||
const itemContainer = makeDiv(
|
||||
this.primaryBuildings.includes(allBuildings[i]) ? rowPrimary : rowSecondary,
|
||||
null,
|
||||
["building"]
|
||||
);
|
||||
itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png");
|
||||
itemContainer.setAttribute("data-id", metaBuilding.getId());
|
||||
|
||||
binding.add(() => this.selectBuildingForPlacement(metaBuilding));
|
||||
|
||||
this.trackClicks(itemContainer, () => this.selectBuildingForPlacement(metaBuilding), {
|
||||
clickSound: null,
|
||||
});
|
||||
|
||||
this.buildingHandles[metaBuilding.id] = {
|
||||
metaBuilding,
|
||||
element: itemContainer,
|
||||
unlocked: false,
|
||||
selected: false,
|
||||
index: i,
|
||||
};
|
||||
}
|
||||
|
||||
this.root.hud.signals.selectedPlacementBuildingChanged.add(
|
||||
this.onSelectedPlacementBuildingChanged,
|
||||
this
|
||||
);
|
||||
|
||||
this.domAttach = new DynamicDomAttach(this.root, this.element, {
|
||||
timeToKeepSeconds: 0.12,
|
||||
attachClass: "visible",
|
||||
});
|
||||
this.lastSelectedIndex = 0;
|
||||
actionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildings).add(this.cycleBuildings, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the toolbar
|
||||
*/
|
||||
update() {
|
||||
const visible = this.visibilityCondition();
|
||||
this.domAttach.update(visible);
|
||||
|
||||
if (visible) {
|
||||
let recomputeSecondaryToolbarVisibility = false;
|
||||
for (const buildingId in this.buildingHandles) {
|
||||
const handle = this.buildingHandles[buildingId];
|
||||
const newStatus = handle.metaBuilding.getIsUnlocked(this.root);
|
||||
if (handle.unlocked !== newStatus) {
|
||||
handle.unlocked = newStatus;
|
||||
handle.element.classList.toggle("unlocked", newStatus);
|
||||
recomputeSecondaryToolbarVisibility = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (recomputeSecondaryToolbarVisibility && this.secondaryDomAttach) {
|
||||
let anyUnlocked = false;
|
||||
for (let i = 0; i < this.secondaryBuildings.length; ++i) {
|
||||
const metaClass = gMetaBuildingRegistry.findByClass(this.secondaryBuildings[i]);
|
||||
if (metaClass.getIsUnlocked(this.root)) {
|
||||
anyUnlocked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.secondaryDomAttach.update(anyUnlocked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles through all buildings
|
||||
*/
|
||||
cycleBuildings() {
|
||||
const visible = this.visibilityCondition();
|
||||
if (!visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newBuildingFound = false;
|
||||
let newIndex = this.lastSelectedIndex;
|
||||
for (let i = 0; i < this.primaryBuildings.length; ++i, ++newIndex) {
|
||||
newIndex %= this.primaryBuildings.length;
|
||||
const metaBuilding = gMetaBuildingRegistry.findByClass(this.primaryBuildings[newIndex]);
|
||||
const handle = this.buildingHandles[metaBuilding.id];
|
||||
if (!handle.selected && handle.unlocked) {
|
||||
newBuildingFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!newBuildingFound) {
|
||||
return;
|
||||
}
|
||||
const metaBuildingClass = this.primaryBuildings[newIndex];
|
||||
const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);
|
||||
this.selectBuildingForPlacement(metaBuilding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the selected building got changed
|
||||
* @param {MetaBuilding} metaBuilding
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue