import { DrawParameters } from "../../../core/draw_parameters"; import { STOP_PROPAGATION } from "../../../core/signal"; import { TrackedState } from "../../../core/tracked_state"; import { Vector } from "../../../core/vector"; import { enumMouseButton } from "../../camera"; import { KEYMAPPINGS } from "../../key_action_mapper"; import { BaseHUDPart } from "../base_hud_part"; import { Blueprint } from "./blueprint"; import { makeDiv } from "../../../core/utils"; import { DynamicDomAttach } from "../dynamic_dom_attach"; import { blueprintShape } from "../../upgrades"; import { T } from "../../../translations"; export class HUDBlueprintPlacer extends BaseHUDPart { createElements(parent) { const blueprintCostShape = this.root.shapeDefinitionMgr.getShapeFromShortKey(blueprintShape); const blueprintCostShapeCanvas = blueprintCostShape.generateAsCanvas(80); this.costDisplayParent = makeDiv(parent, "ingame_HUD_BlueprintPlacer", [], ``); makeDiv(this.costDisplayParent, null, ["label"], T.ingame.blueprintPlacer.cost); const costContainer = makeDiv(this.costDisplayParent, null, ["costContainer"], ""); this.costDisplayText = makeDiv(costContainer, null, ["costText"], ""); costContainer.appendChild(blueprintCostShapeCanvas); } initialize() { this.root.hud.signals.buildingsSelectedForCopy.add(this.onBuildingsSelected, this); /** @type {TypedTrackedState} */ this.currentBlueprint = new TrackedState(this.onBlueprintChanged, this); /** @type {Blueprint?} */ this.lastBlueprintUsed = null; const keyActionMapper = this.root.keyMapper; keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.abortPlacement, this); keyActionMapper .getBinding(KEYMAPPINGS.placement.abortBuildingPlacement) .add(this.abortPlacement, this); keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.rotateBlueprint, this); keyActionMapper.getBinding(KEYMAPPINGS.massSelect.pasteLastBlueprint).add(this.pasteBlueprint, this); this.root.camera.downPreHandler.add(this.onMouseDown, this); this.root.camera.movePreHandler.add(this.onMouseMove, this); this.root.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this); this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent); this.trackedCanAfford = new TrackedState(this.onCanAffordChanged, this); } abortPlacement() { if (this.currentBlueprint.get()) { this.currentBlueprint.set(null); return STOP_PROPAGATION; } } onCanAffordChanged(canAfford) { this.costDisplayParent.classList.toggle("canAfford", canAfford); } update() { this.domAttach.update(this.currentBlueprint.get()); this.trackedCanAfford.set( this.currentBlueprint.get() && this.currentBlueprint.get().canAfford(this.root) ); } /** * @param {Blueprint} blueprint */ onBlueprintChanged(blueprint) { if (blueprint) { this.lastBlueprintUsed = blueprint; this.costDisplayText.innerText = "" + blueprint.getCost(); } } /** * mouse down pre handler * @param {Vector} pos * @param {enumMouseButton} button */ onMouseDown(pos, button) { if (button === enumMouseButton.right) { if (this.currentBlueprint.get()) { this.abortPlacement(); return STOP_PROPAGATION; } } const blueprint = this.currentBlueprint.get(); if (!blueprint) { return; } if (!blueprint.canAfford(this.root)) { this.root.soundProxy.playUiError(); return; } const worldPos = this.root.camera.screenToWorld(pos); const tile = worldPos.toTileSpace(); if (blueprint.tryPlace(this.root, tile)) { const cost = blueprint.getCost(); this.root.hubGoals.takeShapeByKey(blueprintShape, cost); // This actually feels weird // if (!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeMultiple).isCurrentlyPressed()) { // this.currentBlueprint.set(null); // } } } onMouseMove() { // Prevent movement while blueprint is selected if (this.currentBlueprint.get()) { return STOP_PROPAGATION; } } /** * @param {Array} uids */ onBuildingsSelected(uids) { if (uids.length === 0) { return; } this.currentBlueprint.set(Blueprint.fromUids(this.root, uids)); } rotateBlueprint() { if (this.currentBlueprint.get()) { if ( this.root.keyMapper .getBinding(KEYMAPPINGS.placement.rotateInverseModifier) .isCurrentlyPressed() ) { this.currentBlueprint.get().rotateCcw(); } else { this.currentBlueprint.get().rotateCw(); } } } pasteBlueprint() { if (this.lastBlueprintUsed !== null) { this.root.hud.signals.pasteBlueprintRequested.dispatch(); this.currentBlueprint.set(this.lastBlueprintUsed); } else { this.root.soundProxy.playUiError(); } } /** * * @param {DrawParameters} parameters */ draw(parameters) { const blueprint = this.currentBlueprint.get(); if (!blueprint) { return; } const mousePosition = this.root.app.mousePosition; if (!mousePosition) { // Not on screen return; } const worldPos = this.root.camera.screenToWorld(mousePosition); const tile = worldPos.toTileSpace(); blueprint.draw(parameters, tile); } }