From b8c3668d88edf2a258e14f2d109f72b0469ede18 Mon Sep 17 00:00:00 2001 From: tobspr Date: Tue, 16 Jun 2020 13:19:53 +0200 Subject: [PATCH] Placing underground belts now removes belts and other (unneeded) tunnels inbetween --- src/js/changelog.js | 2 + src/js/game/hud/parts/building_placer.js | 4 + src/js/game/root.js | 1 + src/js/game/systems/underground_belt.js | 150 +++++++++++++++++++++-- 4 files changed, 150 insertions(+), 7 deletions(-) diff --git a/src/js/changelog.js b/src/js/changelog.js index 5574953b..a7122823 100644 --- a/src/js/changelog.js +++ b/src/js/changelog.js @@ -6,6 +6,8 @@ export const CHANGELOG = [ "There is now an indicator (compass) to the HUB for the HUB Marker!", "You can now include shape short keys in markers to render shape icons instead of text!", "Added mirrored variant of the painter", + "When placing tunnels, unnecessary belts inbetween are now removed!", + "You can now drag tunnels and they will automatically expand! (Just try it out, its intuitive)", ], }, { diff --git a/src/js/game/hud/parts/building_placer.js b/src/js/game/hud/parts/building_placer.js index 6da065b2..7e20eef7 100644 --- a/src/js/game/hud/parts/building_placer.js +++ b/src/js/game/hud/parts/building_placer.js @@ -483,6 +483,10 @@ export class HUDBuildingPlacer extends BaseHUDPart { ) { // Succesfully placed + const entity = this.root.map.getTileContent(tile); + assert(entity, "Entity was not actually placed"); + this.root.signals.entityManuallyPlaced.dispatch(entity); + if ( metaBuilding.getFlipOrientationAfterPlacement() && !this.root.keyMapper diff --git a/src/js/game/root.js b/src/js/game/root.js index 91efd137..cc6007de 100644 --- a/src/js/game/root.js +++ b/src/js/game/root.js @@ -130,6 +130,7 @@ export class GameRoot { this.signals = { // Entities + entityManuallyPlaced: /** @type {TypedSignal<[Entity]>} */ (new Signal()), entityAdded: /** @type {TypedSignal<[Entity]>} */ (new Signal()), entityGotNewComponent: /** @type {TypedSignal<[Entity]>} */ (new Signal()), entityComponentRemoved: /** @type {TypedSignal<[Entity]>} */ (new Signal()), diff --git a/src/js/game/systems/underground_belt.js b/src/js/game/systems/underground_belt.js index 34decc11..393df04a 100644 --- a/src/js/game/systems/underground_belt.js +++ b/src/js/game/systems/underground_belt.js @@ -1,12 +1,17 @@ -import { GameSystemWithFilter } from "../game_system_with_filter"; -import { UndergroundBeltComponent, enumUndergroundBeltMode } from "../components/underground_belt"; -import { Entity } from "../entity"; -import { Loader } from "../../core/loader"; import { Math_max } from "../../core/builtins"; import { globalConfig } from "../../core/config"; -import { enumDirection, enumDirectionToVector, enumDirectionToAngle } from "../../core/vector"; -import { MapChunkView } from "../map_chunk_view"; -import { DrawParameters } from "../../core/draw_parameters"; +import { Loader } from "../../core/loader"; +import { + enumDirection, + enumDirectionToAngle, + enumDirectionToVector, + Vector, + enumAngleToDirection, + enumInvertedDirections, +} from "../../core/vector"; +import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components/underground_belt"; +import { Entity } from "../entity"; +import { GameSystemWithFilter } from "../game_system_with_filter"; export class UndergroundBeltSystem extends GameSystemWithFilter { constructor(root) { @@ -20,6 +25,8 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { "sprites/buildings/underground_belt_exit.png" ), }; + + this.root.signals.entityManuallyPlaced.add(this.onEntityPlaced, this); } update() { @@ -46,6 +53,135 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { } } + /** + * Callback when an entity got placed, used to remove belts between underground belts + * @param {Entity} entity + */ + onEntityPlaced(entity) { + const undergroundComp = entity.components.UndergroundBelt; + if (undergroundComp && undergroundComp.mode === enumUndergroundBeltMode.receiver) { + const staticComp = entity.components.StaticMapEntity; + const tile = staticComp.origin; + + const direction = enumAngleToDirection[staticComp.rotation]; + const inverseDirection = enumInvertedDirections[direction]; + const offset = enumDirectionToVector[inverseDirection]; + + let currentPos = tile.copy(); + + const tier = undergroundComp.tier; + const range = globalConfig.undergroundBeltMaxTilesByTier[tier]; + + // Search for the entrance which is furthes apart (this is why we can't reuse logic here) + let matchingEntrance = null; + for (let i = 0; i < range; ++i) { + currentPos.addInplace(offset); + const contents = this.root.map.getTileContent(currentPos); + if (!contents) { + continue; + } + + const contentsUndergroundComp = contents.components.UndergroundBelt; + if ( + contentsUndergroundComp && + contentsUndergroundComp.tier === undergroundComp.tier && + contentsUndergroundComp.mode === enumUndergroundBeltMode.sender + ) { + matchingEntrance = { + entity: contents, + range: i, + }; + } + } + + if (!matchingEntrance) { + // Nothing found + return; + } + + // Remove any belts between entrance and exit which have the same direction + currentPos = tile.copy(); + for (let i = 0; i < matchingEntrance.range; ++i) { + currentPos.addInplace(offset); + + const contents = this.root.map.getTileContent(currentPos); + if (!contents) { + continue; + } + + const contentsStaticComp = contents.components.StaticMapEntity; + const contentsBeltComp = contents.components.Belt; + + if (contentsBeltComp) { + // It's a belt + if ( + contentsBeltComp.direction === enumDirection.top && + enumAngleToDirection[contentsStaticComp.rotation] === direction + ) { + // It's same rotation, drop it + this.root.logic.tryDeleteBuilding(contents); + } + } + } + + // Remove any double tunnels, by checking the tile plus the tile above + currentPos = tile.copy().add(offset); + for (let i = 0; i < matchingEntrance.range - 1; ++i) { + const posBefore = currentPos.copy(); + currentPos.addInplace(offset); + + const entityBefore = this.root.map.getTileContent(posBefore); + const entityAfter = this.root.map.getTileContent(currentPos); + + if (!entityBefore || !entityAfter) { + continue; + } + + const undergroundBefore = entityBefore.components.UndergroundBelt; + const undergroundAfter = entityAfter.components.UndergroundBelt; + + if (!undergroundBefore || !undergroundAfter) { + // Not an underground belt + continue; + } + + if ( + // Both same tier + undergroundBefore.tier !== undergroundAfter.tier || + // And same tier as our original entity + undergroundBefore.tier !== undergroundComp.tier + ) { + // Mismatching tier + continue; + } + + if ( + undergroundBefore.mode !== enumUndergroundBeltMode.sender || + undergroundAfter.mode !== enumUndergroundBeltMode.receiver + ) { + // Not the right mode + continue; + } + + // Check rotations + const staticBefore = entityBefore.components.StaticMapEntity; + const staticAfter = entityAfter.components.StaticMapEntity; + + if ( + enumAngleToDirection[staticBefore.rotation] !== direction || + enumAngleToDirection[staticAfter.rotation] !== direction + ) { + // Wrong rotation + continue; + } + + // All good, can remove + this.root.logic.tryDeleteBuilding(entityBefore); + this.root.logic.tryDeleteBuilding(entityAfter); + } + } + } + /** * * @param {Entity} entity