From 4b36426a77338b4771fac7d3d8b19e018506216d Mon Sep 17 00:00:00 2001 From: Sense101 <67970865+Sense101@users.noreply.github.com> Date: Wed, 25 Aug 2021 10:56:29 +0100 Subject: [PATCH] Added shape tooltip - final version (#1251) * Added shape tooltip * Shortened and simplified shape tooltip code * added special logic for cutters so they remove overlays of empty outputs, and added clearing overlays on clear items --- src/js/game/components/item_ejector.js | 4 ++ src/js/game/hud/hud.js | 1 + src/js/game/hud/parts/shape_tooltip.js | 90 ++++++++++++++++++++++++++ src/js/game/key_action_mapper.js | 2 + src/js/game/modes/puzzle.js | 2 + src/js/game/systems/item_processor.js | 30 ++++++--- translations/base-en.yaml | 2 + 7 files changed, 121 insertions(+), 10 deletions(-) create mode 100644 src/js/game/hud/parts/shape_tooltip.js diff --git a/src/js/game/components/item_ejector.js b/src/js/game/components/item_ejector.js index 719925af..bfc54cd8 100644 --- a/src/js/game/components/item_ejector.js +++ b/src/js/game/components/item_ejector.js @@ -11,6 +11,7 @@ import { typeItemSingleton } from "../item_resolver"; * pos: Vector, * direction: enumDirection, * item: BaseItem, + * lastItem: BaseItem, * progress: number?, * cachedDestSlot?: import("./item_acceptor").ItemAcceptorLocatedSlot, * cachedBeltPath?: BeltPath, @@ -51,6 +52,7 @@ export class ItemEjectorComponent extends Component { clear() { for (const slot of this.slots) { slot.item = null; + slot.lastItem = null; slot.progress = 0; } } @@ -67,6 +69,7 @@ export class ItemEjectorComponent extends Component { pos: slot.pos, direction: slot.direction, item: null, + lastItem: null, progress: 0, cachedDestSlot: null, cachedTargetEntity: null, @@ -131,6 +134,7 @@ export class ItemEjectorComponent extends Component { return false; } this.slots[slotIndex].item = item; + this.slots[slotIndex].lastItem = item; this.slots[slotIndex].progress = 0; return true; } diff --git a/src/js/game/hud/hud.js b/src/js/game/hud/hud.js index f35fe018..e3ce76e6 100644 --- a/src/js/game/hud/hud.js +++ b/src/js/game/hud/hud.js @@ -189,6 +189,7 @@ export class GameHUD { "colorBlindHelper", "changesDebugger", "minerHighlight", + "shapeTooltip", ]; for (let i = 0; i < partsOrder.length; ++i) { diff --git a/src/js/game/hud/parts/shape_tooltip.js b/src/js/game/hud/parts/shape_tooltip.js new file mode 100644 index 00000000..282d963c --- /dev/null +++ b/src/js/game/hud/parts/shape_tooltip.js @@ -0,0 +1,90 @@ +import { DrawParameters } from "../../../core/draw_parameters"; +import { Vector } from "../../../core/vector"; +import { Entity } from "../../entity"; +import { KEYMAPPINGS } from "../../key_action_mapper"; +import { BaseHUDPart } from "../base_hud_part"; + +export class HUDShapeTooltip extends BaseHUDPart { + createElements(parent) {} + + initialize() { + /** @type {Vector} */ + this.currentTile = new Vector(0, 0); + + /** @type {Entity} */ + this.currentEntity = null; + + this.isPlacingBuilding = false; + + this.root.signals.entityQueuedForDestroy.add(() => { + this.currentEntity = null; + }, this); + + this.root.hud.signals.selectedPlacementBuildingChanged.add(metaBuilding => { + this.isPlacingBuilding = metaBuilding; + }, this); + } + + isActive() { + const hudParts = this.root.hud.parts; + + // return false if any other placer is active + return ( + this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.showShapeTooltip).pressed && + !this.isPlacingBuilding && + !hudParts.massSelector.currentSelectionStartWorld && + hudParts.massSelector.selectedUids.size < 1 && + !hudParts.blueprintPlacer.currentBlueprint.get() + ); + } + + /** + * + * @param {DrawParameters} parameters + */ + draw(parameters) { + if (this.isActive()) { + const mousePos = this.root.app.mousePosition; + + if (mousePos) { + const tile = this.root.camera.screenToWorld(mousePos.copy()).toTileSpace(); + if (!tile.equals(this.currentTile)) { + this.currentTile = tile; + + const entity = this.root.map.getLayerContentXY(tile.x, tile.y, this.root.currentLayer); + + if (entity && entity.components.ItemProcessor && entity.components.ItemEjector) { + this.currentEntity = entity; + } else { + this.currentEntity = null; + } + } + } + + if (!this.currentEntity) { + return; + } + + const ejectorComp = this.currentEntity.components.ItemEjector; + const staticComp = this.currentEntity.components.StaticMapEntity; + + for (let i = 0; i < ejectorComp.slots.length; ++i) { + const slot = ejectorComp.slots[i]; + + if (!slot.lastItem || slot.lastItem._type != "shape") { + continue; + } + + /** @type {Vector} */ + let drawPos = null; + if (ejectorComp.slots.length == 1) { + drawPos = staticComp.getTileSpaceBounds().getCenter().toWorldSpace(); + } else { + drawPos = staticComp.localTileToWorld(slot.pos).toWorldSpaceCenterOfTile(); + } + + slot.lastItem.drawItemCenteredClipped(drawPos.x, drawPos.y, parameters, 25); + } + } + } +} diff --git a/src/js/game/key_action_mapper.js b/src/js/game/key_action_mapper.js index 41208d13..090b8b83 100644 --- a/src/js/game/key_action_mapper.js +++ b/src/js/game/key_action_mapper.js @@ -32,6 +32,8 @@ export const KEYMAPPINGS = { toggleFPSInfo: { keyCode: 115 }, // F4 switchLayers: { keyCode: key("E") }, + + showShapeTooltip: { keyCode: 18 }, // ALT }, navigation: { diff --git a/src/js/game/modes/puzzle.js b/src/js/game/modes/puzzle.js index c953b0a6..cdbc16cc 100644 --- a/src/js/game/modes/puzzle.js +++ b/src/js/game/modes/puzzle.js @@ -8,6 +8,7 @@ import { enumGameModeTypes, GameMode } from "../game_mode"; import { HUDPuzzleBackToMenu } from "../hud/parts/puzzle_back_to_menu"; import { HUDPuzzleDLCLogo } from "../hud/parts/puzzle_dlc_logo"; import { HUDMassSelector } from "../hud/parts/mass_selector"; +import { HUDShapeTooltip } from "../hud/parts/shape_tooltip"; export class PuzzleGameMode extends GameMode { static getType() { @@ -32,6 +33,7 @@ export class PuzzleGameMode extends GameMode { puzzleBackToMenu: HUDPuzzleBackToMenu, puzzleDlcLogo: HUDPuzzleDLCLogo, massSelector: HUDMassSelector, + shapeTooltip: HUDShapeTooltip, }; this.zoneWidth = data.zoneWidth || 8; diff --git a/src/js/game/systems/item_processor.js b/src/js/game/systems/item_processor.js index b57d735c..d41b7cc7 100644 --- a/src/js/game/systems/item_processor.js +++ b/src/js/game/systems/item_processor.js @@ -334,14 +334,19 @@ export class ItemProcessorSystem extends GameSystemWithFilter { const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutHalf(inputDefinition); + const ejectorComp = payload.entity.components.ItemEjector; for (let i = 0; i < cutDefinitions.length; ++i) { const definition = cutDefinitions[i]; - if (!definition.isEntirelyEmpty()) { - payload.outItems.push({ - item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition), - requiredSlot: i, - }); + + if (definition.isEntirelyEmpty()) { + ejectorComp.slots[i].lastItem = null; + continue; } + + payload.outItems.push({ + item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition), + requiredSlot: i, + }); } } @@ -355,14 +360,19 @@ export class ItemProcessorSystem extends GameSystemWithFilter { const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutQuad(inputDefinition); + const ejectorComp = payload.entity.components.ItemEjector; for (let i = 0; i < cutDefinitions.length; ++i) { const definition = cutDefinitions[i]; - if (!definition.isEntirelyEmpty()) { - payload.outItems.push({ - item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition), - requiredSlot: i, - }); + + if (definition.isEntirelyEmpty()) { + ejectorComp.slots[i].lastItem = null; + continue; } + + payload.outItems.push({ + item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition), + requiredSlot: i, + }); } } diff --git a/translations/base-en.yaml b/translations/base-en.yaml index e803ea8e..f15dfc0b 100644 --- a/translations/base-en.yaml +++ b/translations/base-en.yaml @@ -1363,6 +1363,8 @@ keybindings: placeMultiple: Stay in placement mode placeInverse: Invert automatic belt orientation + showShapeTooltip: Show shape output tooltip + about: title: About this Game body: >-