1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2026-03-02 03:39:21 +00:00

Initial take on wires

This commit is contained in:
tobspr
2020-06-28 19:34:10 +02:00
parent b0cc9539d7
commit 0967d5114c
83 changed files with 2051 additions and 883 deletions

View File

@@ -40,6 +40,7 @@ import { HUDWiresOverlay } from "./parts/wires_overlay";
import { HUDChangesDebugger } from "./parts/debug_changes";
import { queryParamOptions } from "../../core/query_parameters";
import { HUDSandboxController } from "./parts/sandbox_controller";
import { HUDWiresToolbar } from "./parts/wires_toolbar";
export class GameHUD {
/**
@@ -56,6 +57,7 @@ export class GameHUD {
this.parts = {
processingOverlay: new HUDProcessingOverlay(this.root),
buildingsToolbar: new HUDBuildingsToolbar(this.root),
wiresToolbar: new HUDWiresToolbar(this.root),
blueprintPlacer: new HUDBlueprintPlacer(this.root),
buildingPlacer: new HUDBuildingPlacer(this.root),
unlockNotification: new HUDUnlockNotification(this.root),
@@ -75,9 +77,7 @@ export class GameHUD {
screenshotExporter: new HUDScreenshotExporter(this.root),
shapeViewer: new HUDShapeViewer(this.root),
/* wires:start */
wiresOverlay: new HUDWiresOverlay(this.root),
/* wires:end */
// Typing hints
/* typehints:start */
@@ -87,6 +87,7 @@ export class GameHUD {
};
this.signals = {
buildingSelectedForPlacement: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()),
selectedPlacementBuildingChanged: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()),
shapePinRequested: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()),
shapeUnpinRequested: /** @type {TypedSignal<[string]>} */ (new Signal()),
@@ -139,7 +140,6 @@ export class GameHUD {
for (const key in this.parts) {
this.parts[key].initialize();
}
this.internalInitSignalConnections();
this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleHud).add(this.toggleUi, this);
@@ -205,14 +205,6 @@ export class GameHUD {
document.body.classList.toggle("uiHidden");
}
/**
* Initializes connections between parts
*/
internalInitSignalConnections() {
const p = this.parts;
p.buildingsToolbar.sigBuildingSelected.add(p.buildingPlacer.startSelection, p.buildingPlacer);
}
/**
* Updates all parts
*/

View File

@@ -1,23 +1,26 @@
import { gMetaBuildingRegistry } from "../../../core/global_registries";
import { Signal, STOP_PROPAGATION } from "../../../core/signal";
import { TrackedState } from "../../../core/tracked_state";
import { makeDiv } from "../../../core/utils";
import { KEYMAPPINGS } from "../../key_action_mapper";
import { MetaBuilding } from "../../meta_building";
import { BaseHUDPart } from "../base_hud_part";
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 {Array<typeof MetaBuilding>} supportedBuildings
* @param {function} visibilityCondition
* @param {object} param0
* @param {Array<typeof MetaBuilding>} param0.supportedBuildings
* @param {function} param0.visibilityCondition
* @param {string} param0.htmlElementId
*/
constructor(root, supportedBuildings, visibilityCondition) {
constructor(root, { supportedBuildings, visibilityCondition, htmlElementId }) {
super(root);
this.supportedBuildings = supportedBuildings;
this.visibilityCondition = visibilityCondition;
this.htmlElementId = htmlElementId;
/** @type {Object.<string, {
* metaBuilding: MetaBuilding,
@@ -27,17 +30,6 @@ export class HUDBaseToolbar extends BaseHUDPart {
* index: number
* }>} */
this.buildingHandles = {};
this.sigBuildingSelected = new Signal();
this.trackedIsVisisible = new TrackedState(this.onVisibilityChanged, this);
}
/**
* Called when the visibility of the toolbar changed
* @param {boolean} visible
*/
onVisibilityChanged(visible) {
this.element.classList.toggle("visible", visible);
}
/**
@@ -45,7 +37,7 @@ export class HUDBaseToolbar extends BaseHUDPart {
* @param {HTMLElement} parent
*/
createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_buildings_toolbar", ["ingame_buildingsToolbar"], "");
this.element = makeDiv(parent, this.htmlElementId, ["ingame_buildingsToolbar"], "");
}
initialize() {
@@ -80,6 +72,10 @@ export class HUDBaseToolbar extends BaseHUDPart {
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);
}
@@ -88,11 +84,10 @@ export class HUDBaseToolbar extends BaseHUDPart {
* Updates the toolbar
*/
update() {
this.trackedIsVisisible.set(this.visibilityCondition());
const visible = this.visibilityCondition();
this.domAttach.update(visible);
if (!this.trackedIsVisisible.get()) {
// Currently not active
} else {
if (visible) {
for (const buildingId in this.buildingHandles) {
const handle = this.buildingHandles[buildingId];
const newStatus = handle.metaBuilding.getIsUnlocked(this.root);
@@ -166,7 +161,7 @@ export class HUDBaseToolbar extends BaseHUDPart {
}
this.root.soundProxy.playUiClick();
this.sigBuildingSelected.dispatch(metaBuilding);
this.root.hud.signals.buildingSelectedForPlacement.dispatch(metaBuilding);
this.onSelectedPlacementBuildingChanged(metaBuilding);
}
}

View File

@@ -11,6 +11,7 @@ import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { Blueprint } from "../../blueprint";
import { SOUNDS } from "../../../platform/sound";
import { enumLayer } from "../../root";
export class HUDBlueprintPlacer extends BaseHUDPart {
createElements(parent) {
@@ -26,7 +27,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
}
initialize() {
this.root.hud.signals.buildingsSelectedForCopy.add(this.onBuildingsSelected, this);
this.root.hud.signals.buildingsSelectedForCopy.add(this.createBlueprintFromBuildings, this);
/** @type {TypedTrackedState<Blueprint?>} */
this.currentBlueprint = new TrackedState(this.onBlueprintChanged, this);
@@ -43,6 +44,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
this.root.camera.movePreHandler.add(this.onMouseMove, this);
this.root.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this);
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);
this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent);
this.trackedCanAfford = new TrackedState(this.onCanAffordChanged, this);
@@ -56,6 +58,24 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
}
}
/**
* Called when the layer was changed
* @param {enumLayer} layer
*/
onEditModeChanged(layer) {
// Check if the layer of the blueprint differs and thus we have to deselect it
const blueprint = this.currentBlueprint.get();
if (blueprint) {
if (blueprint.layer !== layer) {
this.currentBlueprint.set(null);
}
}
}
/**
* Called when the blueprint is now affordable or not
* @param {boolean} canAfford
*/
onCanAffordChanged(canAfford) {
this.costDisplayParent.classList.toggle("canAfford", canAfford);
}
@@ -67,6 +87,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
}
/**
* Called when the blueprint was changed
* @param {Blueprint} blueprint
*/
onBlueprintChanged(blueprint) {
@@ -105,13 +126,12 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
const cost = blueprint.getCost();
this.root.hubGoals.takeShapeByKey(blueprintShape, cost);
this.root.soundProxy.playUi(SOUNDS.placeBuilding);
// This actually feels weird
// if (!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeMultiple).pressed) {
// this.currentBlueprint.set(null);
// }
}
}
/**
* Mose move handler
*/
onMouseMove() {
// Prevent movement while blueprint is selected
if (this.currentBlueprint.get()) {
@@ -120,15 +140,19 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
}
/**
* Called when an array of bulidings was selected
* @param {Array<number>} uids
*/
onBuildingsSelected(uids) {
createBlueprintFromBuildings(uids) {
if (uids.length === 0) {
return;
}
this.currentBlueprint.set(Blueprint.fromUids(this.root, uids));
}
/**
* Attempts to rotate the current blueprint
*/
rotateBlueprint() {
if (this.currentBlueprint.get()) {
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) {
@@ -139,8 +163,17 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
}
}
/**
* Attempts to paste the last blueprint
*/
pasteBlueprint() {
if (this.lastBlueprintUsed !== null) {
if (this.lastBlueprintUsed.layer !== this.root.currentLayer) {
// Not compatible
this.root.soundProxy.playUiError();
return;
}
this.root.hud.signals.pasteBlueprintRequested.dispatch();
this.currentBlueprint.set(this.lastBlueprintUsed);
} else {

View File

@@ -49,6 +49,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
// Bind to signals
this.signals.variantChanged.add(this.rerenderVariants, this);
this.root.hud.signals.buildingSelectedForPlacement.add(this.startSelection, this);
this.domAttach = new DynamicDomAttach(this.root, this.element, {});
this.variantsAttach = new DynamicDomAttach(this.root, this.variantsElement, {});
@@ -389,7 +390,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const goodArrowSprite = Loader.getSprite("sprites/misc/slot_good_arrow.png");
const badArrowSprite = Loader.getSprite("sprites/misc/slot_bad_arrow.png");
// Just ignore this code ...
// Just ignore the following code please ... thanks!
const offsetShift = 10;
@@ -397,6 +398,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const slots = acceptorComp.slots;
for (let acceptorSlotIndex = 0; acceptorSlotIndex < slots.length; ++acceptorSlotIndex) {
const slot = slots[acceptorSlotIndex];
const acceptorSlotWsTile = staticComp.localTileToWorld(slot.pos);
const acceptorSlotWsPos = acceptorSlotWsTile.toWorldSpaceCenterOfTile();
@@ -409,7 +411,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const worldDirection = staticComp.localDirectionToWorld(direction);
const sourceTile = acceptorSlotWsTile.add(enumDirectionToVector[worldDirection]);
const sourceEntity = this.root.map.getTileContent(sourceTile);
const sourceEntity = this.root.map.getTileContent(sourceTile, this.root.currentLayer);
let sprite = goodArrowSprite;
let alpha = 0.5;
@@ -419,7 +421,13 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const sourceEjector = sourceEntity.components.ItemEjector;
const sourceStaticComp = sourceEntity.components.StaticMapEntity;
const ejectorAcceptLocalTile = sourceStaticComp.worldToLocalTile(acceptorSlotWsTile);
if (sourceEjector && sourceEjector.anySlotEjectsToLocalTile(ejectorAcceptLocalTile)) {
if (
sourceEjector &&
sourceEjector.anySlotEjectsToLocalTile(
ejectorAcceptLocalTile,
this.root.currentLayer
)
) {
sprite = goodArrowSprite;
}
alpha = 1.0;
@@ -443,7 +451,10 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
if (ejectorComp) {
const slots = ejectorComp.slots;
for (let ejectorSlotIndex = 0; ejectorSlotIndex < slots.length; ++ejectorSlotIndex) {
const slot = ejectorComp.slots[ejectorSlotIndex];
const slot = slots[ejectorSlotIndex];
if (slot.layer !== this.root.currentLayer) {
continue;
}
const ejectorSlotWsTile = staticComp.localTileToWorld(
ejectorComp.getSlotTargetLocalTile(ejectorSlotIndex)
@@ -451,7 +462,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const ejectorSLotWsPos = ejectorSlotWsTile.toWorldSpaceCenterOfTile();
const ejectorSlotWsDirection = staticComp.localDirectionToWorld(slot.direction);
const destEntity = this.root.map.getTileContent(ejectorSlotWsTile);
const destEntity = this.root.map.getTileContent(ejectorSlotWsTile, this.root.currentLayer);
let sprite = goodArrowSprite;
let alpha = 0.5;
@@ -463,7 +474,9 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
if (destAcceptor) {
const destLocalTile = destStaticComp.worldToLocalTile(ejectorSlotWsTile);
const destLocalDir = destStaticComp.worldDirectionToLocal(ejectorSlotWsDirection);
if (destAcceptor.findMatchingSlot(destLocalTile, destLocalDir)) {
if (
destAcceptor.findMatchingSlot(destLocalTile, destLocalDir, this.root.currentLayer)
) {
sprite = goodArrowSprite;
} else {
sprite = badArrowSprite;

View File

@@ -12,7 +12,7 @@ import { BaseHUDPart } from "../base_hud_part";
import { SOUNDS } from "../../../platform/sound";
import { MetaMinerBuilding, enumMinerVariants } from "../../buildings/miner";
import { enumHubGoalRewards } from "../../tutorial_goals";
import { enumEditMode } from "../../root";
import { enumLayer } from "../../root";
/**
* Contains all logic for the building placer - this doesn't include the rendering
@@ -125,12 +125,12 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
/**
* Called when the edit mode got changed
* @param {enumEditMode} editMode
* @param {enumLayer} editMode
*/
onEditModeChanged(editMode) {
const metaBuilding = this.currentMetaBuilding.get();
if (metaBuilding) {
if (metaBuilding.getEditLayer() !== editMode) {
if (metaBuilding.getLayer() !== editMode) {
// This layer doesn't fit the edit mode anymore
this.currentMetaBuilding.set(null);
}
@@ -276,7 +276,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile);
const contents = this.root.map.getTileContent(tile, this.root.currentLayer);
if (contents) {
if (this.root.logic.tryDeleteBuilding(contents)) {
this.root.soundProxy.playUi(SOUNDS.destroyBuilding);
@@ -302,7 +302,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile);
const contents = this.root.map.getTileContent(tile, this.root.currentLayer);
if (!contents) {
const tileBelow = this.root.map.getLowerLayerContentXY(tile.x, tile.y);
@@ -322,6 +322,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
// Try to extract the building
const extracted = this.hack_reconstructMetaBuildingAndVariantFromBuilding(contents);
// If the building we are picking is the same as the one we have, clear the cursor.
if (
!extracted ||
@@ -335,11 +336,6 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
this.currentMetaBuilding.set(extracted.metaBuilding);
this.currentVariant.set(extracted.variant);
this.currentBaseRotation = contents.components.StaticMapEntity.rotation;
// Make sure we selected something, and also make sure it's not a special entity
// if (contents && !contents.components.Unremovable) {
// }
}
/**
@@ -760,7 +756,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
while (this.currentlyDeleting || this.currentMetaBuilding.get()) {
if (this.currentlyDeleting) {
// Deletion
const contents = this.root.map.getTileContentXY(x0, y0);
const contents = this.root.map.getLayerContentXY(x0, y0, this.root.currentLayer);
if (contents && !contents.queuedForDestroy && !contents.destroyed) {
if (this.root.logic.tryDeleteBuilding(contents)) {
anythingDeleted = true;

View File

@@ -9,10 +9,10 @@ import { MetaSplitterBuilding } from "../../buildings/splitter";
import { MetaStackerBuilding } from "../../buildings/stacker";
import { MetaTrashBuilding } from "../../buildings/trash";
import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
import { enumEditMode } from "../../root";
import { enumLayer } from "../../root";
import { HUDBaseToolbar } from "./base_toolbar";
const toolbarBuildings = [
const supportedBuildings = [
MetaBeltBaseBuilding,
MetaSplitterBuilding,
MetaUndergroundBeltBuilding,
@@ -24,17 +24,16 @@ const toolbarBuildings = [
MetaPainterBuilding,
MetaTrashBuilding,
/* wires:start */
MetaEnergyGenerator,
/* wires:end */
];
export class HUDBuildingsToolbar extends HUDBaseToolbar {
constructor(root) {
super(
root,
toolbarBuildings,
() => !this.root.camera.getIsMapOverlayActive() && this.root.editMode === enumEditMode.regular
);
super(root, {
supportedBuildings,
visibilityCondition: () =>
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === enumLayer.regular,
htmlElementId: "ingame_HUD_buildings_toolbar",
});
}
}

View File

@@ -8,7 +8,7 @@ import { THEME } from "../../theme";
import { globalConfig } from "../../../core/config";
import { T } from "../../../translations";
import { enumItemType } from "../../base_item";
import { enumEditMode } from "../../root";
import { enumLayer } from "../../root";
export class HUDColorBlindHelper extends BaseHUDPart {
createElements(parent) {
@@ -41,14 +41,14 @@ export class HUDColorBlindHelper extends BaseHUDPart {
return null;
}
if (this.root.editMode !== enumEditMode.regular) {
if (this.root.currentLayer !== enumLayer.regular) {
// Not in regular mode
return null;
}
const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile);
const contents = this.root.map.getTileContent(tile, this.root.currentLayer);
if (contents && !contents.components.Miner) {
const beltComp = contents.components.Belt;
@@ -66,6 +66,9 @@ export class HUDColorBlindHelper extends BaseHUDPart {
if (ejectorComp) {
for (let i = 0; i < ejectorComp.slots.length; ++i) {
const slot = ejectorComp.slots[i];
if (slot.layer !== this.root.currentLayer) {
continue;
}
if (slot.item && slot.item.getItemType() === enumItemType.color) {
return /** @type {ColorItem} */ (slot.item).color;
}

View File

@@ -36,7 +36,7 @@ export class HUDEntityDebugger extends BaseHUDPart {
this.mousePosElem.innerText = worldTile.x + " / " + worldTile.y;
this.chunkPosElem.innerText = chunk.x + " / " + chunk.y;
const entity = this.root.map.getTileContent(worldTile);
const entity = this.root.map.getTileContent(worldTile, this.root.currentLayer);
if (entity) {
removeAllChildren(this.entityInfoElem);
let html = "Entity";

View File

@@ -255,14 +255,12 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
condition: () => this.anythingSelectedOnMap,
},
/* wires:start */
{
// Switch layers
label: T.ingame.keybindingsOverlay.switchLayers,
keys: [k.ingame.switchLayers],
condition: () => true,
},
/* wires:end */
];
if (!this.root.app.settings.getAllSettings().alwaysMultiplace) {

View File

@@ -210,7 +210,7 @@ export class HUDMassSelector extends BaseHUDPart {
for (let x = realTileStart.x; x <= realTileEnd.x; ++x) {
for (let y = realTileStart.y; y <= realTileEnd.y; ++y) {
const contents = this.root.map.getTileContentXY(x, y);
const contents = this.root.map.getLayerContentXY(x, y, this.root.currentLayer);
if (contents && this.root.logic.canDeleteBuilding(contents)) {
this.selectedUids.add(contents.uid);
}
@@ -259,7 +259,7 @@ export class HUDMassSelector extends BaseHUDPart {
for (let x = realTileStart.x; x <= realTileEnd.x; ++x) {
for (let y = realTileStart.y; y <= realTileEnd.y; ++y) {
const contents = this.root.map.getTileContentXY(x, y);
const contents = this.root.map.getLayerContentXY(x, y, this.root.currentLayer);
if (contents && this.root.logic.canDeleteBuilding(contents)) {
const staticComp = contents.components.StaticMapEntity;
const bounds = staticComp.getTileSpaceBounds();

View File

@@ -132,7 +132,7 @@ export class HUDSandboxController extends BaseHUDPart {
}
});
this.visible = true;
this.visible = !G_IS_DEV;
this.domAttach = new DynamicDomAttach(this.root, this.element);
}

View File

@@ -2,7 +2,7 @@ import { makeOffscreenBuffer } from "../../../core/buffer_utils";
import { globalConfig } from "../../../core/config";
import { DrawParameters } from "../../../core/draw_parameters";
import { KEYMAPPINGS } from "../../key_action_mapper";
import { enumEditMode } from "../../root";
import { enumLayer } from "../../root";
import { THEME } from "../../theme";
import { BaseHUDPart } from "../base_hud_part";
import { Loader } from "../../../core/loader";
@@ -26,12 +26,12 @@ export class HUDWiresOverlay extends BaseHUDPart {
* Switches between layers
*/
switchLayers() {
if (this.root.editMode === enumEditMode.regular) {
this.root.editMode = enumEditMode.wires;
if (this.root.currentLayer === enumLayer.regular) {
this.root.currentLayer = enumLayer.wires;
} else {
this.root.editMode = enumEditMode.regular;
this.root.currentLayer = enumLayer.regular;
}
this.root.signals.editModeChanged.dispatch(this.root.editMode);
this.root.signals.editModeChanged.dispatch(this.root.currentLayer);
}
/**
@@ -50,7 +50,7 @@ export class HUDWiresOverlay extends BaseHUDPart {
}
update() {
const desiredAlpha = this.root.editMode === enumEditMode.wires ? 1.0 : 0.0;
const desiredAlpha = this.root.currentLayer === enumLayer.wires ? 1.0 : 0.0;
this.currentAlpha = lerp(this.currentAlpha, desiredAlpha, 0.08);
}
@@ -63,6 +63,10 @@ export class HUDWiresOverlay extends BaseHUDPart {
return;
}
if (this.root.camera.getIsMapOverlayActive()) {
return;
}
if (!this.cachedPatternBackground) {
this.cachedPatternBackground = parameters.context.createPattern(this.tilePatternCanvas, "repeat");
}

View File

@@ -0,0 +1,16 @@
import { MetaWireBaseBuilding } from "../../buildings/wire_base";
import { enumLayer } from "../../root";
import { HUDBaseToolbar } from "./base_toolbar";
const supportedBuildings = [MetaWireBaseBuilding];
export class HUDWiresToolbar extends HUDBaseToolbar {
constructor(root) {
super(root, {
supportedBuildings,
visibilityCondition: () =>
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === enumLayer.wires,
htmlElementId: "ingame_HUD_wires_toolbar",
});
}
}