mirror of
https://github.com/teoxoy/factorio-blueprint-editor.git
synced 2025-03-27 21:39:03 +02:00
Adds circuit wires (#248)
* add option to allow unreachable wire connections this affects how the entities can be repositionned * refactor IConnection to allow arbitrary wire connection points * made getEntityAtPosition take a IPoint instead of x and y * add util.sumprod function for vector manipulation * add helper functions for locating wire connection points namely: - Entity.getWireConnectionBoundingBox - PositionGrid.getConnectionPointAtPosition * add circuit wire placement from the UI * fix tile rotation (e.g., hazard concrete) * make the connection point bounding box a full cell when it is single * make wire "rotation" cycling from red to green * make BlueprintContainer default settings reflect the saved settings (dirty fix, it would have been cleaner to save the settings outside of BPC) * mostly fixing typos * make pressing the pipette (Q) while placing wire cancel the wire
This commit is contained in:
parent
21ab873d83
commit
0bec144b89
@ -93,6 +93,13 @@ export class Editor {
|
||||
G.UI.quickbarPanel.generateSlots(items)
|
||||
}
|
||||
|
||||
public get limitWireReach(): boolean {
|
||||
return G.BPC.limitWireReach
|
||||
}
|
||||
public set limitWireReach(limit: boolean) {
|
||||
G.BPC.limitWireReach = limit
|
||||
}
|
||||
|
||||
public get oilOutpostSettings(): IOilOutpostSettings {
|
||||
return oilOutpostSettings
|
||||
}
|
||||
@ -231,7 +238,7 @@ export class Editor {
|
||||
: entity.direction
|
||||
G.BPC.spawnPaintContainer(itemName, direction)
|
||||
} else if (G.BPC.mode === EditorMode.PAINT) {
|
||||
G.BPC.paintContainer.destroy()
|
||||
G.BPC.paintContainer.destroy(true)
|
||||
}
|
||||
G.BPC.exitCopyMode(true)
|
||||
G.BPC.exitDeleteMode(true)
|
||||
|
@ -232,14 +232,12 @@ export class EntityInfoPanel extends Panel {
|
||||
// const fromP = util.rotatePointBasedOnDir([0, -tiles], entity.direction)
|
||||
const toP = util.rotatePointBasedOnDir([0, tiles], entity.direction)
|
||||
// const from = G.bp.entities.get(
|
||||
// G.bp.entityPositionGrid.getCellAtPosition({
|
||||
// x: entity.position.x + fromP.x,
|
||||
// y: entity.position.y + fromP.y
|
||||
// })
|
||||
// G.bp.entityPositionGrid.getCellAtPosition(
|
||||
// util.sumprod(entity.position, fromP)
|
||||
// )
|
||||
// )
|
||||
const to = G.bp.entityPositionGrid.getEntityAtPosition(
|
||||
entity.position.x + toP.x,
|
||||
entity.position.y + toP.y
|
||||
util.sumprod(entity.position, toP)
|
||||
)
|
||||
if (to && isBelt(to)) {
|
||||
speed = containerToBelt(
|
||||
|
@ -65,7 +65,7 @@ export class InventoryDialog extends Dialog {
|
||||
|
||||
let groupIndex = 0
|
||||
for (const group of FD.inventoryLayout) {
|
||||
// Make creative entities avalible only in the main inventory
|
||||
// Make creative entities available only in the main inventory
|
||||
if (group.name === 'creative' && itemsFilter !== undefined) {
|
||||
continue
|
||||
}
|
||||
@ -81,7 +81,7 @@ export class InventoryDialog extends Dialog {
|
||||
if (itemsFilter === undefined) {
|
||||
const itemData = FD.items[item.name]
|
||||
if (!itemData) continue
|
||||
if (!itemData.place_result && !itemData.place_as_tile) continue
|
||||
if (!itemData.place_result && !itemData.place_as_tile && !itemData.wire_count) continue
|
||||
// needed for robots/trains/cars
|
||||
if (itemData.place_result && !FD.entities[itemData.place_result]) continue
|
||||
} else {
|
||||
@ -194,7 +194,7 @@ export class InventoryDialog extends Dialog {
|
||||
)
|
||||
}
|
||||
|
||||
/** Update recipe visulaization */
|
||||
/** Update recipe visualization */
|
||||
private updateRecipeVisualization(recipeName?: string): void {
|
||||
// Update Recipe Label
|
||||
this.m_RecipeLabel.text = undefined
|
||||
|
@ -8,9 +8,32 @@ const getRandomInt = (min: number, max: number): number => {
|
||||
|
||||
const getRandomItem = <T>(array: T[]): T => array[getRandomInt(0, array.length - 1)]
|
||||
|
||||
const Point = (p: IPoint | number[]): IPoint => {
|
||||
if (Array.isArray(p)) return { x: p[0], y: p[1] }
|
||||
return { ...p }
|
||||
}
|
||||
|
||||
/** Computes a weighted sum of vectors. Weights are preceding their corresponding vector, and equal to 1 if not specified */
|
||||
const sumprod = (...args: (number | (number[]|IPoint))[]): IPoint => {
|
||||
const ans: IPoint = {x:0, y:0}
|
||||
let coef: number = undefined
|
||||
for (let arg of args) {
|
||||
if (typeof arg === 'number') {
|
||||
coef = (coef ?? 1) * arg
|
||||
continue
|
||||
}
|
||||
if (Array.isArray(arg)) arg = { x: arg[0], y: arg[1] }
|
||||
ans.x += (coef ?? 1) * arg.x
|
||||
ans.y += (coef ?? 1) * arg.y
|
||||
coef = undefined
|
||||
}
|
||||
if (coef !== undefined) throw new TypeError("weights should be followed by a vector")
|
||||
return ans
|
||||
}
|
||||
|
||||
const rotatePointBasedOnDir = (p: IPoint | number[], dir: number): IPoint => {
|
||||
const point: IPoint = { x: 0, y: 0 }
|
||||
const nP = Array.isArray(p) ? { x: p[0], y: p[1] } : { ...p }
|
||||
const nP = Point(p)
|
||||
switch (dir) {
|
||||
case 0:
|
||||
// x y
|
||||
@ -144,6 +167,8 @@ export default {
|
||||
duplicate,
|
||||
getRandomInt,
|
||||
getRandomItem,
|
||||
Point,
|
||||
sumprod,
|
||||
getRelativeDirection,
|
||||
rotatePointBasedOnDir,
|
||||
transformConnectionPosition,
|
||||
|
@ -15,6 +15,7 @@ import { OverlayContainer } from './OverlayContainer'
|
||||
import { PaintEntityContainer } from './PaintEntityContainer'
|
||||
import { TileContainer } from './TileContainer'
|
||||
import { PaintTileContainer } from './PaintTileContainer'
|
||||
import { PaintWireContainer } from './PaintWireContainer'
|
||||
import { PaintContainer } from './PaintContainer'
|
||||
import { PaintBlueprintContainer } from './PaintBlueprintContainer'
|
||||
import { OptimizedContainer } from './OptimizedContainer'
|
||||
@ -60,9 +61,10 @@ export class BlueprintContainer extends PIXI.Container {
|
||||
3
|
||||
)
|
||||
|
||||
private _moveSpeed = 10
|
||||
private _gridColor = 0x303030
|
||||
private _gridPattern: GridPattern = 'grid'
|
||||
private _moveSpeed = Number(localStorage.getItem('moveSpeed') ?? 10)
|
||||
private _gridColor = (localStorage.getItem('darkTheme') ?? 'true') === 'true' ? 0x303030 : 0xc9c9c9
|
||||
private _gridPattern: GridPattern = (localStorage.getItem('pattern') ?? 'grid') as GridPattern
|
||||
private _limitWireReach = (localStorage.getItem('limitWireReach') ?? 'true') === 'true'
|
||||
private _mode: EditorMode = EditorMode.NONE
|
||||
public readonly bp: Blueprint
|
||||
public readonly gridData: GridData
|
||||
@ -77,6 +79,7 @@ export class BlueprintContainer extends PIXI.Container {
|
||||
public readonly wiresContainer: WiresContainer
|
||||
public readonly overlayContainer: OverlayContainer
|
||||
private readonly entityPaintSlot: PIXI.Container
|
||||
private readonly wirePaintSlot: PIXI.Container
|
||||
|
||||
public hoverContainer: EntityContainer
|
||||
public paintContainer: PaintContainer
|
||||
@ -114,6 +117,7 @@ export class BlueprintContainer extends PIXI.Container {
|
||||
this.wiresContainer = new WiresContainer(this.bp)
|
||||
this.overlayContainer = new OverlayContainer(this)
|
||||
this.entityPaintSlot = new PIXI.Container()
|
||||
this.wirePaintSlot = new PIXI.Container()
|
||||
|
||||
this.addChild(
|
||||
this.grid,
|
||||
@ -124,7 +128,8 @@ export class BlueprintContainer extends PIXI.Container {
|
||||
this.entitySprites,
|
||||
this.wiresContainer,
|
||||
this.overlayContainer,
|
||||
this.entityPaintSlot
|
||||
this.entityPaintSlot,
|
||||
this.wirePaintSlot
|
||||
)
|
||||
|
||||
this.on('pointerover', () => {
|
||||
@ -439,10 +444,10 @@ export class BlueprintContainer extends PIXI.Container {
|
||||
|
||||
if (!this.bp) return
|
||||
|
||||
const entity = this.bp.entityPositionGrid.getEntityAtPosition(
|
||||
this.gridData.x32,
|
||||
this.gridData.y32
|
||||
)
|
||||
const entity = this.bp.entityPositionGrid.getEntityAtPosition({
|
||||
x: this.gridData.x32,
|
||||
y: this.gridData.y32
|
||||
})
|
||||
const eC = entity ? EntityContainer.mappings.get(entity.entityNumber) : undefined
|
||||
|
||||
if (eC && this.hoverContainer === eC) return
|
||||
@ -555,6 +560,14 @@ export class BlueprintContainer extends PIXI.Container {
|
||||
return grid
|
||||
}
|
||||
|
||||
public get limitWireReach(): boolean {
|
||||
return this._limitWireReach
|
||||
}
|
||||
|
||||
public set limitWireReach(limit: boolean) {
|
||||
this._limitWireReach = limit
|
||||
}
|
||||
|
||||
public initBP(): void {
|
||||
// Render Bp
|
||||
for (const [, e] of this.bp.entities) {
|
||||
@ -706,10 +719,14 @@ export class BlueprintContainer extends PIXI.Container {
|
||||
|
||||
if (typeof itemNameOrEntities === 'string') {
|
||||
const itemData = FD.items[itemNameOrEntities]
|
||||
const wireResult = itemData.wire_count && itemNameOrEntities
|
||||
const tileResult = itemData.place_as_tile && itemData.place_as_tile.result
|
||||
const placeResult = itemData.place_result || tileResult
|
||||
const placeResult = itemData.place_result || tileResult || wireResult
|
||||
|
||||
if (tileResult) {
|
||||
if (wireResult) {
|
||||
this.paintContainer = new PaintWireContainer(this, placeResult)
|
||||
this.wirePaintSlot.addChild(this.paintContainer)
|
||||
} else if (tileResult) {
|
||||
this.paintContainer = new PaintTileContainer(this, placeResult)
|
||||
this.tilePaintSlot.addChild(this.paintContainer)
|
||||
} else {
|
||||
|
@ -301,13 +301,7 @@ export class OverlayContainer extends PIXI.Container {
|
||||
case 6:
|
||||
position.x += offset
|
||||
}
|
||||
const arrow = createArrow(
|
||||
{
|
||||
x: position.x * 64,
|
||||
y: position.y * 64,
|
||||
},
|
||||
type
|
||||
)
|
||||
const arrow = createArrow(util.sumprod(64,position), type)
|
||||
if (entity.type === 'boiler' && type === 2) {
|
||||
arrow.rotation = 0.5 * Math.PI
|
||||
}
|
||||
|
@ -163,15 +163,17 @@ export class PaintBlueprintContainer extends PaintContainer {
|
||||
for (const [oldID] of oldEntIDToNewEntID) {
|
||||
this.bp.wireConnections
|
||||
.getEntityConnections(oldID)
|
||||
.filter(
|
||||
connection =>
|
||||
oldEntIDToNewEntID.has(connection.entityNumber1) &&
|
||||
oldEntIDToNewEntID.has(connection.entityNumber2)
|
||||
.filter(connection =>
|
||||
connection.cps.every(cp =>
|
||||
oldEntIDToNewEntID.has(cp.entityNumber)
|
||||
)
|
||||
)
|
||||
.map(connection => ({
|
||||
...connection,
|
||||
entityNumber1: oldEntIDToNewEntID.get(connection.entityNumber1),
|
||||
entityNumber2: oldEntIDToNewEntID.get(connection.entityNumber2),
|
||||
cps: connection.cps.map(cp => ({
|
||||
...cp,
|
||||
entityNumber: oldEntIDToNewEntID.get(cp.entityNumber),
|
||||
}))
|
||||
}))
|
||||
.forEach(conn => this.bpc.bp.wireConnections.create(conn))
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import F from '../UI/controls/functions'
|
||||
import { Entity } from '../core/Entity'
|
||||
import { Blueprint } from '../core/Blueprint'
|
||||
import util from '../common/util'
|
||||
import { EntitySprite } from './EntitySprite'
|
||||
import { VisualizationArea } from './VisualizationArea'
|
||||
import { BlueprintContainer } from './BlueprintContainer'
|
||||
@ -31,26 +32,17 @@ export class PaintBlueprintEntityContainer {
|
||||
|
||||
this.entitySprites = EntitySprite.getParts(
|
||||
this.entity,
|
||||
{
|
||||
x: this.entity.position.x * 32,
|
||||
y: this.entity.position.y * 32,
|
||||
},
|
||||
util.sumprod(32,this.entity.position),
|
||||
this.bp.entityPositionGrid
|
||||
)
|
||||
}
|
||||
|
||||
private get entityPosition(): IPoint {
|
||||
return {
|
||||
x: this.pbpc.x / 32 + this.entity.position.x,
|
||||
y: this.pbpc.y / 32 + this.entity.position.y,
|
||||
}
|
||||
return util.sumprod(1/32,this.pbpc, this.entity.position)
|
||||
}
|
||||
|
||||
private get position(): IPoint {
|
||||
return {
|
||||
x: this.pbpc.x + this.entity.position.x,
|
||||
y: this.pbpc.y + this.entity.position.y,
|
||||
}
|
||||
return util.sumprod(this.pbpc, this.entity.position)
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
@ -73,7 +65,7 @@ export class PaintBlueprintEntityContainer {
|
||||
direction,
|
||||
position
|
||||
) ||
|
||||
this.bpc.bp.entityPositionGrid.isAreaAvalible(this.entity.name, position, direction)
|
||||
this.bpc.bp.entityPositionGrid.isAreaAvailable(this.entity.name, position, direction)
|
||||
|
||||
for (const s of this.entitySprites) {
|
||||
F.applyTint(s, {
|
||||
@ -142,7 +134,7 @@ export class PaintBlueprintEntityContainer {
|
||||
}
|
||||
|
||||
let ent: Entity
|
||||
if (this.bpc.bp.entityPositionGrid.isAreaAvalible(this.entity.name, position, direction)) {
|
||||
if (this.bpc.bp.entityPositionGrid.isAreaAvailable(this.entity.name, position, direction)) {
|
||||
ent = this.bpc.bp.createEntity({
|
||||
...this.entity.serialize(),
|
||||
entity_number: undefined,
|
||||
|
@ -13,7 +13,8 @@ export class IllegalFlipError {
|
||||
|
||||
export abstract class PaintContainer extends PIXI.Container {
|
||||
protected readonly bpc: BlueprintContainer
|
||||
private readonly icon: PIXI.DisplayObject
|
||||
private _name: string
|
||||
private icon: PIXI.DisplayObject
|
||||
private _blocked = false
|
||||
private tint = {
|
||||
r: 0.4,
|
||||
@ -29,12 +30,22 @@ export abstract class PaintContainer extends PIXI.Container {
|
||||
|
||||
this.on('childAdded', (s: PIXI.Sprite) => F.applyTint(s, this.tint))
|
||||
|
||||
this.icon = F.CreateIcon(this.getItemName())
|
||||
G.UI.addPaintIcon(this.icon)
|
||||
window.addEventListener('mousemove', this.updateIconPos)
|
||||
this.show()
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return this._name
|
||||
}
|
||||
|
||||
protected set name(name: string) {
|
||||
this._name = name
|
||||
this.icon?.destroy()
|
||||
this.icon = F.CreateIcon(this.getItemName())
|
||||
G.UI.addPaintIcon(this.icon)
|
||||
this.updateIconPos()
|
||||
}
|
||||
|
||||
protected get blocked(): boolean {
|
||||
return this._blocked
|
||||
}
|
||||
@ -73,15 +84,19 @@ export abstract class PaintContainer extends PIXI.Container {
|
||||
}
|
||||
}
|
||||
|
||||
protected setNewPosition(size: IPoint): void {
|
||||
if (size.x % 2 === 0) {
|
||||
protected setNewPosition(size?: IPoint): void {
|
||||
if (size === undefined) {
|
||||
this.x = this.bpc.gridData.x
|
||||
} else if (size.x % 2 === 0) {
|
||||
const npx = this.bpc.gridData.x16 * 16
|
||||
this.x = npx + (npx % 32 === 0 ? 0 : 16)
|
||||
} else {
|
||||
this.x = this.bpc.gridData.x32 * 32 + 16
|
||||
}
|
||||
|
||||
if (size.y % 2 === 0) {
|
||||
if (size === undefined) {
|
||||
this.y = this.bpc.gridData.y
|
||||
} else if (size.y % 2 === 0) {
|
||||
const npy = this.bpc.gridData.y16 * 16
|
||||
this.y = npy + (npy % 32 === 0 ? 0 : 16)
|
||||
} else {
|
||||
|
@ -70,7 +70,7 @@ export class PaintEntityContainer extends PaintContainer {
|
||||
direction,
|
||||
position
|
||||
) ||
|
||||
this.bpc.bp.entityPositionGrid.isAreaAvalible(this.name, position, direction)
|
||||
this.bpc.bp.entityPositionGrid.isAreaAvailable(this.name, position, direction)
|
||||
) {
|
||||
this.blocked = false
|
||||
} else {
|
||||
@ -206,7 +206,7 @@ export class PaintEntityContainer extends PaintContainer {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.bpc.bp.entityPositionGrid.isAreaAvalible(this.name, position, direction)) {
|
||||
if (this.bpc.bp.entityPositionGrid.isAreaAvailable(this.name, position, direction)) {
|
||||
this.bpc.bp.createEntity(
|
||||
{
|
||||
name: this.name,
|
||||
|
@ -1,9 +1,9 @@
|
||||
import FD from '../core/factorioData'
|
||||
import { Tile } from '../core/Tile'
|
||||
import util from '../common/util'
|
||||
import { TileContainer } from './TileContainer'
|
||||
import { PaintContainer } from './PaintContainer'
|
||||
import { BlueprintContainer } from './BlueprintContainer'
|
||||
import { Entity } from '../core/Entity'
|
||||
|
||||
export class PaintTileContainer extends PaintContainer {
|
||||
private static size = 2
|
||||
@ -60,7 +60,7 @@ export class PaintTileContainer extends PaintContainer {
|
||||
this.redraw()
|
||||
}
|
||||
|
||||
public rotate(): void {
|
||||
public rotate(ccw = false): void {
|
||||
const nD = FD.tiles[this.name].next_direction
|
||||
if (nD) {
|
||||
this.name = nD
|
||||
@ -68,8 +68,8 @@ export class PaintTileContainer extends PaintContainer {
|
||||
}
|
||||
}
|
||||
|
||||
public rotatedEntities(): Entity[] {
|
||||
return undefined
|
||||
public canFlipOrRotateByCopying(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected redraw(): void {
|
||||
@ -95,10 +95,9 @@ export class PaintTileContainer extends PaintContainer {
|
||||
const position = this.getGridPosition()
|
||||
|
||||
this.bpc.bp.removeTiles(
|
||||
PaintTileContainer.getTilePositions().map(p => ({
|
||||
x: p.x + position.x,
|
||||
y: p.y + position.y,
|
||||
}))
|
||||
PaintTileContainer.getTilePositions().map(p =>
|
||||
util.sumprod(p, position)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -109,10 +108,9 @@ export class PaintTileContainer extends PaintContainer {
|
||||
|
||||
this.bpc.bp.createTiles(
|
||||
this.name,
|
||||
PaintTileContainer.getTilePositions().map(p => ({
|
||||
x: p.x + position.x,
|
||||
y: p.y + position.y,
|
||||
}))
|
||||
PaintTileContainer.getTilePositions().map(p =>
|
||||
util.sumprod(p, position)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
175
packages/editor/src/containers/PaintWireContainer.ts
Normal file
175
packages/editor/src/containers/PaintWireContainer.ts
Normal file
@ -0,0 +1,175 @@
|
||||
import * as PIXI from 'pixi.js'
|
||||
import G from '../common/globals'
|
||||
import U from '../core/generators/util'
|
||||
import { IConnection, IConnectionPoint } from '../core/WireConnections'
|
||||
import { Entity } from '../core/Entity'
|
||||
import { EntityContainer } from './EntityContainer'
|
||||
import { PaintContainer } from './PaintContainer'
|
||||
import { BlueprintContainer } from './BlueprintContainer'
|
||||
|
||||
export class PaintWireContainer extends PaintContainer {
|
||||
private color? : string
|
||||
private cp? : IConnectionPoint? = undefined
|
||||
/** This is only a reference */
|
||||
private cursorBox: PIXI.Container
|
||||
|
||||
public constructor(bpc: BlueprintContainer, name: string) {
|
||||
super(bpc, name)
|
||||
|
||||
this.color = name.split("_",1)[0]
|
||||
this.cp = undefined
|
||||
|
||||
this.moveAtCursor()
|
||||
this.redraw()
|
||||
}
|
||||
|
||||
private get entity(): Entity {
|
||||
if (this.cp === undefined) return undefined
|
||||
return this.bpc.bp.entities.get(this.cp.entityNumber)
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
super.hide()
|
||||
}
|
||||
|
||||
public show(): void {
|
||||
super.hide() // keep icon visible
|
||||
this.visible = true
|
||||
}
|
||||
|
||||
public destroy(pipette = false): void {
|
||||
if (pipette && this.cp) {
|
||||
this.cp = undefined
|
||||
this.redraw()
|
||||
return
|
||||
}
|
||||
this.bpc.wiresContainer.remove('paint-wire')
|
||||
this.destroycursorBox()
|
||||
super.destroy()
|
||||
}
|
||||
|
||||
public getItemName(): string {
|
||||
return this.name
|
||||
}
|
||||
|
||||
private updatecursorBox(): IConnectionPoint {
|
||||
this.destroycursorBox()
|
||||
const cursor_position = this.getGridPosition()
|
||||
const entity = this.bpc.bp.entityPositionGrid.getEntityAtPosition(cursor_position)
|
||||
if (entity === undefined) return undefined
|
||||
const ec = EntityContainer.mappings.get(entity.entityNumber)
|
||||
|
||||
const cp = this.bpc.bp.entityPositionGrid.getConnectionPointAtPosition(cursor_position, this.color)
|
||||
|
||||
let connectionsReach = true
|
||||
if (this.cp && G.BPC.limitWireReach) {
|
||||
connectionsReach &&= U.pointInCircle(
|
||||
entity.position,
|
||||
this.cp.position ?? this.entity.position,
|
||||
Math.min(
|
||||
entity.maxWireDistance ?? Infinity,
|
||||
this.entity?.maxWireDistance ?? Infinity
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
this.cursorBox = this.bpc.overlayContainer.createCursorBox(
|
||||
ec.position,
|
||||
entity.size,
|
||||
cp === undefined ? 'not_allowed'
|
||||
: (!connectionsReach) ? 'not_allowed'
|
||||
: 'regular'
|
||||
)
|
||||
if (connectionsReach) return cp
|
||||
}
|
||||
private destroycursorBox(): void {
|
||||
this.cursorBox?.destroy()
|
||||
}
|
||||
|
||||
public rotate(ccw = false): void {
|
||||
if (!this.visible) return
|
||||
|
||||
// const cursor_position = this.getGridPosition()
|
||||
// const entity = this.bpc.bp.entityPositionGrid.getEntityAtPosition(cursor_position)
|
||||
// entity?.rotate(ccw, true)
|
||||
|
||||
/** Non-standard behavior: cycle between colors */
|
||||
if (this.name === "red_wire") this.name = "green_wire"
|
||||
else if (this.name === "green_wire") this.name = "red_wire"
|
||||
this.color = this.name.split("_",1)[0]
|
||||
|
||||
this.redraw()
|
||||
}
|
||||
|
||||
public canFlipOrRotateByCopying(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected redraw(): void {
|
||||
this.updatecursorBox()
|
||||
this.bpc.wiresContainer.remove('paint-wire')
|
||||
if (this.cp) {
|
||||
const connection : IConnection = {
|
||||
color: this.color,
|
||||
cps: [this.cp, { position: this.getGridPosition() }],
|
||||
}
|
||||
this.bpc.wiresContainer.add('paint-wire', connection)
|
||||
}
|
||||
}
|
||||
|
||||
public moveAtCursor(): void {
|
||||
this.setNewPosition()
|
||||
this.redraw()
|
||||
}
|
||||
|
||||
public placeEntityContainer(): void {
|
||||
if (!this.visible) return
|
||||
|
||||
const cp = this.updatecursorBox()
|
||||
if (cp === undefined) return
|
||||
|
||||
if (this.cp?.entityNumber === undefined) {
|
||||
this.cp = cp
|
||||
} else {
|
||||
const connection : IConnection = {
|
||||
color: this.color,
|
||||
cps: [this.cp, cp],
|
||||
}
|
||||
if (cp.entityNumber === this.cp.entityNumber && cp.entitySide === this.cp.entitySide) {
|
||||
this.cp = undefined
|
||||
} else if (this.bpc.bp.wireConnections.has(connection)) {
|
||||
this.bpc.bp.wireConnections.remove(connection)
|
||||
this.cp = undefined
|
||||
} else {
|
||||
this.bpc.bp.wireConnections.create(connection)
|
||||
this.cp = cp
|
||||
}
|
||||
}
|
||||
this.moveAtCursor()
|
||||
}
|
||||
|
||||
/** Non-standard behavior: on right click, keep focusing same connection point. */
|
||||
public removeContainerUnder(): void {
|
||||
if (!this.visible) return
|
||||
|
||||
const cp = this.updatecursorBox()
|
||||
if (cp === undefined) return
|
||||
|
||||
if (this.cp?.entityNumber === undefined) {
|
||||
this.cp = cp
|
||||
} else {
|
||||
const connection : IConnection = {
|
||||
color: this.color,
|
||||
cps: [this.cp, cp],
|
||||
}
|
||||
if (cp.entityNumber === this.cp.entityNumber && cp.entitySide === this.cp.entitySide) {
|
||||
this.cp = undefined
|
||||
} else if (this.bpc.bp.wireConnections.has(connection)) {
|
||||
this.bpc.bp.wireConnections.remove(connection)
|
||||
} else {
|
||||
this.bpc.bp.wireConnections.create(connection)
|
||||
}
|
||||
}
|
||||
this.moveAtCursor()
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import * as PIXI from 'pixi.js'
|
||||
import { Blueprint } from '../core/Blueprint'
|
||||
import { IConnection } from '../core/WireConnections'
|
||||
import { IConnection, IConnectionPoint } from '../core/WireConnections'
|
||||
import U from '../core/generators/util'
|
||||
import { EntityContainer } from './EntityContainer'
|
||||
|
||||
export class WiresContainer extends PIXI.Container {
|
||||
@ -12,7 +13,7 @@ export class WiresContainer extends PIXI.Container {
|
||||
this.bp = bp
|
||||
}
|
||||
|
||||
private static createWire(p1: IPoint, p2: IPoint, color: string): PIXI.Graphics {
|
||||
private static createWire(p1: IPoint, p2: IPoint, color: string, connectionsReach = true): PIXI.Graphics {
|
||||
const wire = new PIXI.Graphics()
|
||||
|
||||
const minX = Math.min(p1.x, p2.x)
|
||||
@ -28,7 +29,11 @@ export class WiresContainer extends PIXI.Container {
|
||||
green: 0x588c38,
|
||||
}
|
||||
|
||||
wire.lineStyle({ width: 1.5, color: colorMap[color] })
|
||||
wire.lineStyle({
|
||||
width: 1.5,
|
||||
color: colorMap[color],
|
||||
alpha: (connectionsReach ? 1 : 0.3),
|
||||
})
|
||||
wire.moveTo(0, 0)
|
||||
|
||||
if (p1.x === p2.x) {
|
||||
@ -94,7 +99,7 @@ export class WiresContainer extends PIXI.Container {
|
||||
|
||||
for (const conn of connections) {
|
||||
const entNr =
|
||||
entityNumber === conn.entityNumber1 ? conn.entityNumber2 : conn.entityNumber1
|
||||
entityNumber === conn.cps[0].entityNumber ? conn.cps[1].entityNumber : conn.cps[0].entityNumber
|
||||
const ec = EntityContainer.mappings.get(entNr)
|
||||
if (ec.entity.type === 'electric_pole') {
|
||||
ec.redraw()
|
||||
@ -106,12 +111,11 @@ export class WiresContainer extends PIXI.Container {
|
||||
}
|
||||
|
||||
private updateConnectedEntities(connection: IConnection): void {
|
||||
const ent0 = EntityContainer.mappings.get(connection.entityNumber1)
|
||||
const ent1 = EntityContainer.mappings.get(connection.entityNumber2)
|
||||
ent0.redraw()
|
||||
ent1.redraw()
|
||||
this.update(connection.entityNumber1)
|
||||
this.update(connection.entityNumber2)
|
||||
for (const cp of connection.cps) {
|
||||
const ec = EntityContainer.mappings.get(cp.entityNumber)
|
||||
ec.redraw()
|
||||
this.update(cp.entityNumber)
|
||||
}
|
||||
}
|
||||
|
||||
/** This is done in cases where the connection doesn't change but the rotation does */
|
||||
@ -125,19 +129,46 @@ export class WiresContainer extends PIXI.Container {
|
||||
}
|
||||
|
||||
private getWireSprite(connection: IConnection): PIXI.Graphics {
|
||||
const getWirePos = (entityNumber: number, color: string, side: number): IPoint => {
|
||||
const entity = this.bp.entities.get(entityNumber)
|
||||
const point = entity.getWireConnectionPoint(color, side, entity.direction)
|
||||
return {
|
||||
x: (entity.position.x + point[0]) * 32,
|
||||
y: (entity.position.y + point[1]) * 32,
|
||||
const getWirePos = (cp: IConnectionPoint, color: string): IPoint => {
|
||||
if (cp.entityNumber) {
|
||||
const entity = this.bp.entities.get(cp.entityNumber)
|
||||
const point = entity.getWireConnectionPoint(color, cp.entitySide)
|
||||
return {
|
||||
x: (entity.position.x + point[0]) * 32,
|
||||
y: (entity.position.y + point[1]) * 32,
|
||||
}
|
||||
} else if (cp.position) {
|
||||
return {
|
||||
x: cp.position.x * 32,
|
||||
y: cp.position.y * 32,
|
||||
}
|
||||
}
|
||||
}
|
||||
const getPos = (cp: IConnectionPoint): IPoint => {
|
||||
if (cp.entityNumber) {
|
||||
const entity = this.bp.entities.get(cp.entityNumber)
|
||||
return entity.position
|
||||
} else if (cp.position) {
|
||||
return cp.position
|
||||
}
|
||||
}
|
||||
const getMaxWireDistance = (cp: IConnectionPoint): number => {
|
||||
if (cp.entityNumber) {
|
||||
const entity = this.bp.entities.get(cp.entityNumber)
|
||||
return entity.maxWireDistance
|
||||
}
|
||||
}
|
||||
const connectionsReach = U.pointInCircle(
|
||||
getPos(connection.cps[0]),
|
||||
getPos(connection.cps[1]),
|
||||
Math.min(Infinity, ...connection.cps.map(getMaxWireDistance).filter(d => d !== undefined))
|
||||
)
|
||||
|
||||
return WiresContainer.createWire(
|
||||
getWirePos(connection.entityNumber1, connection.color, connection.entitySide1),
|
||||
getWirePos(connection.entityNumber2, connection.color, connection.entitySide2),
|
||||
connection.color
|
||||
getWirePos(connection.cps[0], connection.color),
|
||||
getWirePos(connection.cps[1], connection.color),
|
||||
connection.color,
|
||||
connectionsReach
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -160,10 +160,7 @@ class Blueprint extends EventEmitter {
|
||||
delete e.neighbours
|
||||
return this.createEntity({
|
||||
...e,
|
||||
position: {
|
||||
x: e.position.x + offset.x,
|
||||
y: e.position.y + offset.y,
|
||||
},
|
||||
position: util.sumprod(e.position, offset),
|
||||
})
|
||||
}),
|
||||
e => e.entityNumber
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { EventEmitter } from 'eventemitter3'
|
||||
import util from '../common/util'
|
||||
import { IllegalFlipError } from '../containers/PaintContainer'
|
||||
import G from '../common/globals'
|
||||
import FD, { Entity as FD_Entity } from './factorioData'
|
||||
import { Blueprint } from './Blueprint'
|
||||
import { getBeltWireConnectionIndex } from './spriteDataBuilder'
|
||||
@ -70,6 +71,10 @@ export class Entity extends EventEmitter {
|
||||
return FD.entities[this.name]
|
||||
}
|
||||
|
||||
public get rawEntity(): BPS.IEntity {
|
||||
return this.m_rawEntity;
|
||||
}
|
||||
|
||||
/** Entity size */
|
||||
public get size(): IPoint {
|
||||
return util.switchSizeBasedOnDirection(this.entityData.size, this.direction)
|
||||
@ -80,28 +85,30 @@ export class Entity extends EventEmitter {
|
||||
return this.m_rawEntity.position
|
||||
}
|
||||
|
||||
public get rawEntity(): BPS.IEntity {
|
||||
return this.m_rawEntity;
|
||||
}
|
||||
|
||||
public set position(position: IPoint) {
|
||||
if (util.areObjectsEquivalent(this.m_rawEntity.position, position)) return
|
||||
|
||||
if (!this.m_BP.entityPositionGrid.canMoveTo(this, position)) return
|
||||
|
||||
// Make sure all entity connections reach the new position
|
||||
const connectionsReach = this.m_BP.wireConnections
|
||||
// Check if the new position breaks any valid entity connections
|
||||
const connectionsBreak = this.m_BP.wireConnections
|
||||
.getEntityConnections(this.entityNumber)
|
||||
.map(c => (c.entityNumber1 === this.entityNumber ? c.entityNumber2 : c.entityNumber1))
|
||||
.map(c => (c.cps[0].entityNumber === this.entityNumber ? c.cps[1].entityNumber : c.cps[0].entityNumber))
|
||||
.map(otherEntityNumer => this.m_BP.entities.get(otherEntityNumer))
|
||||
.every(e =>
|
||||
.some(e =>
|
||||
// Make sure that a reaching connection is not broken
|
||||
U.pointInCircle(
|
||||
e.position,
|
||||
this.position,
|
||||
Math.min(e.maxWireDistance, this.maxWireDistance)
|
||||
) &&
|
||||
!U.pointInCircle(
|
||||
e.position,
|
||||
position,
|
||||
Math.min(e.maxWireDistance, this.maxWireDistance)
|
||||
)
|
||||
)
|
||||
if (!connectionsReach) return
|
||||
if (G.BPC.limitWireReach && connectionsBreak) return
|
||||
|
||||
this.m_BP.history
|
||||
.updateValue(this.m_rawEntity, ['position'], position, 'Change position')
|
||||
@ -121,11 +128,22 @@ export class Entity extends EventEmitter {
|
||||
)
|
||||
}
|
||||
|
||||
public connectionsReach(position?: IPoint): boolean {
|
||||
return this.m_BP.wireConnections
|
||||
.getEntityConnections(this.entityNumber)
|
||||
.map(c => (c.cps[0].entityNumber === this.entityNumber ? c.cps[1].entityNumber : c.cps[0].entityNumber))
|
||||
.map(otherEntityNumer => this.m_BP.entities.get(otherEntityNumer))
|
||||
.every(e =>
|
||||
U.pointInCircle(
|
||||
e.position,
|
||||
position ?? this.position,
|
||||
Math.min(e.maxWireDistance, this.maxWireDistance)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
public moveBy(offset: IPoint): void {
|
||||
this.position = {
|
||||
x: this.position.x + offset.x,
|
||||
y: this.position.y + offset.y,
|
||||
}
|
||||
this.position = util.sumprod(this.position, offset)
|
||||
}
|
||||
|
||||
/** Entity direction */
|
||||
@ -870,6 +888,50 @@ export class Entity extends EventEmitter {
|
||||
return e.circuit_wire_connection_points[getIndex()].wire[color]
|
||||
}
|
||||
|
||||
private getWire_connection_box(
|
||||
color: string,
|
||||
side: number,
|
||||
direction = this.direction
|
||||
): number[][] {
|
||||
const e = this.entityData
|
||||
const size_box = [
|
||||
[-e.size.width/2, -e.size.height/2],
|
||||
[+e.size.width/2, +e.size.height/2],
|
||||
]
|
||||
// use size_box for cell-wise selection, use e.selection_box for "true" selection
|
||||
if (side===1 && e.connection_points?.[direction/2].wire[color]) return size_box
|
||||
if (side===1 && e.circuit_wire_connection_point?.wire[color]) return size_box
|
||||
if (side===1 && e.circuit_wire_connection_points?.[direction/2].wire[color]) return size_box
|
||||
if (side===1 && e.input_connection_points?.[direction/2].wire[color]) return e.input_connection_bounding_box
|
||||
if (side===2 && e.output_connection_points?.[direction/2].wire[color]) return e.output_connection_bounding_box
|
||||
if (side===1 && e.left_wire_connection_point?.wire[color]) {
|
||||
const box = util.duplicate(size_box)
|
||||
box[1][0] = (box[0][0]+box[1][0])/2
|
||||
return box
|
||||
}
|
||||
if (side===2 && e.right_wire_connection_point?.wire[color]) {
|
||||
const box = util.duplicate(size_box)
|
||||
box[0][0] = (box[0][0]+box[1][0])/2
|
||||
return box
|
||||
}
|
||||
}
|
||||
|
||||
public getWireConnectionBoundingBox(
|
||||
color: string,
|
||||
side: number,
|
||||
direction = this.direction
|
||||
): IPoint[] {
|
||||
const box = this.getWire_connection_box(color, side, direction)
|
||||
if (box === undefined) return undefined
|
||||
let bbox : IPoint[] = box.map(util.Point)
|
||||
bbox = bbox.map(p => util.rotatePointBasedOnDir(p, direction))
|
||||
bbox = [
|
||||
{x: Math.min(...bbox.map(p => p.x)), y: Math.min(...bbox.map(p => p.y))},
|
||||
{x: Math.max(...bbox.map(p => p.x)), y: Math.max(...bbox.map(p => p.y))},
|
||||
]
|
||||
return bbox
|
||||
}
|
||||
|
||||
public serialize(entNrWhitelist?: Set<number>): BPS.IEntity {
|
||||
return util.duplicate({
|
||||
...this.m_rawEntity,
|
||||
|
@ -2,6 +2,7 @@ import util from '../common/util'
|
||||
import FD from './factorioData'
|
||||
import { Blueprint } from './Blueprint'
|
||||
import { Entity } from './Entity'
|
||||
import { IConnectionPoint } from './WireConnections'
|
||||
|
||||
/** Anchor is in the middle */
|
||||
interface IArea {
|
||||
@ -56,8 +57,8 @@ export class PositionGrid {
|
||||
}
|
||||
}
|
||||
|
||||
public getEntityAtPosition(x: number, y: number): Entity {
|
||||
const cell = this.grid.get(`${Math.floor(x)},${Math.floor(y)}`)
|
||||
public getEntityAtPosition(position: IPoint): Entity {
|
||||
const cell = this.grid.get(`${Math.floor(position.x)},${Math.floor(position.y)}`)
|
||||
if (cell) {
|
||||
if (typeof cell === 'number') {
|
||||
return this.bp.entities.get(cell)
|
||||
@ -67,6 +68,23 @@ export class PositionGrid {
|
||||
}
|
||||
}
|
||||
|
||||
public getConnectionPointAtPosition(position: IPoint, color: string): IConnectionPoint {
|
||||
const entity = this.getEntityAtPosition(position)
|
||||
if (entity === undefined) return undefined
|
||||
const rel_position = util.sumprod(position, -1,entity.position)
|
||||
for (let side = 1; side <= 10; side++) {
|
||||
const bbox = entity.getWireConnectionBoundingBox(color, side)
|
||||
if (bbox === undefined) break // no more sides expected for that color
|
||||
const rel_bbox = bbox.map(b => util.sumprod(rel_position, -1,b))
|
||||
if (Object.values(rel_bbox[0]).some(v => v < 0)) continue
|
||||
if (Object.values(rel_bbox[1]).some(v => v > 0)) continue
|
||||
return {
|
||||
entityNumber: entity.entityNumber,
|
||||
entitySide: side,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public setTileData(entity: Entity, position: IPoint = entity.position): void {
|
||||
// if (entity.entityData.flags.includes('placeable_off_grid')) {
|
||||
// return
|
||||
@ -138,12 +156,12 @@ export class PositionGrid {
|
||||
|
||||
public canMoveTo(entity: Entity, newPosition: IPoint): boolean {
|
||||
this.removeTileData(entity)
|
||||
const spaceAvalible = this.isAreaAvalible(entity.name, newPosition, entity.direction)
|
||||
const spaceAvalible = this.isAreaAvailable(entity.name, newPosition, entity.direction)
|
||||
this.setTileData(entity)
|
||||
return spaceAvalible
|
||||
}
|
||||
|
||||
public isAreaAvalible(name: string, pos: IPoint, direction = 0): boolean {
|
||||
public isAreaAvailable(name: string, pos: IPoint, direction = 0): boolean {
|
||||
const size = util.switchSizeBasedOnDirection(FD.entities[name].size, direction)
|
||||
|
||||
const straightRails: Entity[] = []
|
||||
|
@ -16,9 +16,9 @@ export class WireConnectionMap extends Map<string, IConnection> {
|
||||
const conn = this.entNrToConnHash.get(entityNumber) || []
|
||||
this.entNrToConnHash.set(entityNumber, [...conn, hash])
|
||||
}
|
||||
add(connection.entityNumber1)
|
||||
if (connection.entityNumber1 !== connection.entityNumber2) {
|
||||
add(connection.entityNumber2)
|
||||
add(connection.cps[0].entityNumber)
|
||||
if (connection.cps[0].entityNumber !== connection.cps[1].entityNumber) {
|
||||
add(connection.cps[1].entityNumber)
|
||||
}
|
||||
|
||||
return super.set(hash, connection)
|
||||
@ -34,9 +34,9 @@ export class WireConnectionMap extends Map<string, IConnection> {
|
||||
this.entNrToConnHash.delete(entityNumber)
|
||||
}
|
||||
}
|
||||
rem(connection.entityNumber1)
|
||||
if (connection.entityNumber1 !== connection.entityNumber2) {
|
||||
rem(connection.entityNumber2)
|
||||
rem(connection.cps[0].entityNumber)
|
||||
if (connection.cps[0].entityNumber !== connection.cps[1].entityNumber) {
|
||||
rem(connection.cps[1].entityNumber)
|
||||
}
|
||||
|
||||
return super.delete(hash)
|
||||
|
@ -8,10 +8,13 @@ const MAX_POLE_CONNECTION_COUNT = 5
|
||||
|
||||
export interface IConnection {
|
||||
color: string
|
||||
entityNumber1: number
|
||||
entityNumber2: number
|
||||
entitySide1: number
|
||||
entitySide2: number
|
||||
cps: IConnectionPoint[]
|
||||
}
|
||||
|
||||
export interface IConnectionPoint {
|
||||
entityNumber?: number
|
||||
entitySide?: number
|
||||
position?: IPoint
|
||||
}
|
||||
|
||||
export class WireConnections extends EventEmitter {
|
||||
@ -24,10 +27,9 @@ export class WireConnections extends EventEmitter {
|
||||
}
|
||||
|
||||
private static hash(conn: IConnection): string {
|
||||
const firstE = Math.min(conn.entityNumber1, conn.entityNumber2)
|
||||
const secondE = Math.max(conn.entityNumber1, conn.entityNumber2)
|
||||
const firstS = firstE === conn.entityNumber1 ? conn.entitySide1 : conn.entitySide2
|
||||
const secondS = secondE === conn.entityNumber2 ? conn.entitySide2 : conn.entitySide1
|
||||
const cps = conn.cps.sort((cp1,cp2) => cp1.entityNumber - cp2.entityNumber)
|
||||
const [firstE, secondE] = cps.map(cp => cp.entityNumber)
|
||||
const [firstS, secondS] = cps.map(cp => cp.entitySide)
|
||||
return `${conn.color}-${firstE}-${secondE}-${firstS}-${secondS}`
|
||||
}
|
||||
|
||||
@ -46,10 +48,16 @@ export class WireConnections extends EventEmitter {
|
||||
for (const data of conn[color]) {
|
||||
parsedConnections.push({
|
||||
color,
|
||||
entityNumber1: entityNumber,
|
||||
entityNumber2: data.entity_id,
|
||||
entitySide1: Number(side),
|
||||
entitySide2: data.circuit_id || 1,
|
||||
cps: [
|
||||
{
|
||||
entityNumber: entityNumber,
|
||||
entitySide: Number(side)
|
||||
},
|
||||
{
|
||||
entityNumber: data.entity_id,
|
||||
entitySide: data.circuit_id || 1
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -62,10 +70,16 @@ export class WireConnections extends EventEmitter {
|
||||
const data = (connections[side] as BPS.IWireColor[])[0]
|
||||
parsedConnections.push({
|
||||
color,
|
||||
entityNumber1: entityNumber,
|
||||
entityNumber2: data.entity_id,
|
||||
entitySide1: Number(side.slice(2, 3)) + 1,
|
||||
entitySide2: 1,
|
||||
cps: [
|
||||
{
|
||||
entityNumber: entityNumber,
|
||||
entitySide: Number(side.slice(2, 3)) + 1
|
||||
},
|
||||
{
|
||||
entityNumber: data.entity_id,
|
||||
entitySide: 1
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -97,39 +111,38 @@ export class WireConnections extends EventEmitter {
|
||||
const neighbours: number[] = []
|
||||
|
||||
for (const connection of connections) {
|
||||
const isEntity1 = connection.entityNumber1 === entityNumber
|
||||
const side = isEntity1 ? connection.entitySide1 : connection.entitySide2
|
||||
const isEntity0 = connection.cps[0].entityNumber === entityNumber
|
||||
const [thisE, otherE] = isEntity0 ? connection.cps : connection.cps.reverse()
|
||||
const entitySide = thisE.entitySide
|
||||
const color = connection.color
|
||||
const otherEntNr = isEntity1 ? connection.entityNumber2 : connection.entityNumber1
|
||||
const otherEntSide = isEntity1 ? connection.entitySide2 : connection.entitySide1
|
||||
|
||||
if (entNrWhitelist && !entNrWhitelist.has(otherEntNr)) continue
|
||||
if (entNrWhitelist && !entNrWhitelist.has(otherE.entityNumber)) continue
|
||||
|
||||
if (color === 'copper' && getType(otherEntNr) === 'electric_pole') {
|
||||
if (color === 'copper' && getType(otherE.entityNumber) === 'electric_pole') {
|
||||
if (getType(entityNumber) === 'electric_pole') {
|
||||
neighbours.push(otherEntNr)
|
||||
neighbours.push(otherE.entityNumber)
|
||||
} else if (getType(entityNumber) === 'power_switch') {
|
||||
const SIDE = `Cu${side - 1}`
|
||||
const SIDE = `Cu${entitySide - 1}`
|
||||
if (serialized[SIDE] === undefined) {
|
||||
serialized[SIDE] = []
|
||||
}
|
||||
const c = serialized[SIDE] as BPS.IWireColor[]
|
||||
c.push({
|
||||
entity_id: otherEntNr,
|
||||
entity_id: otherE.entityNumber,
|
||||
wire_id: 0,
|
||||
})
|
||||
}
|
||||
} else if (color === 'red' || color === 'green') {
|
||||
if (serialized[side] === undefined) {
|
||||
serialized[side] = {}
|
||||
if (serialized[entitySide] === undefined) {
|
||||
serialized[entitySide] = {}
|
||||
}
|
||||
const SIDE = serialized[side] as BPS.IConnSide
|
||||
const SIDE = serialized[entitySide] as BPS.IConnSide
|
||||
if (SIDE[color] === undefined) {
|
||||
SIDE[color] = []
|
||||
}
|
||||
SIDE[color].push({
|
||||
entity_id: otherEntNr,
|
||||
circuit_id: otherEntSide,
|
||||
entity_id: otherE.entityNumber,
|
||||
circuit_id: otherE.entitySide,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -143,13 +156,24 @@ export class WireConnections extends EventEmitter {
|
||||
private static toPoleConnection(entityNumber1: number, entityNumber2: number): IConnection {
|
||||
return {
|
||||
color: 'copper',
|
||||
entityNumber1,
|
||||
entityNumber2,
|
||||
entitySide1: 1,
|
||||
entitySide2: 1,
|
||||
cps: [
|
||||
{
|
||||
entityNumber: entityNumber1,
|
||||
entitySide: 1
|
||||
},
|
||||
{
|
||||
entityNumber: entityNumber2,
|
||||
entitySide: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
public has(connection: IConnection): boolean {
|
||||
const hash = WireConnections.hash(connection)
|
||||
return this.connections.has(hash)
|
||||
}
|
||||
|
||||
public create(connection: IConnection): void {
|
||||
const hash = WireConnections.hash(connection)
|
||||
if (this.connections.has(hash)) return
|
||||
@ -160,7 +184,7 @@ export class WireConnections extends EventEmitter {
|
||||
.commit()
|
||||
}
|
||||
|
||||
private remove(connection: IConnection): void {
|
||||
public remove(connection: IConnection): void {
|
||||
const hash = WireConnections.hash(connection)
|
||||
if (!this.connections.has(hash)) return
|
||||
|
||||
@ -267,9 +291,9 @@ export class WireConnections extends EventEmitter {
|
||||
for (const connection of this.getEntityConnections(pole.entityNumber)) {
|
||||
if (connection.color === 'copper') {
|
||||
const otherEntNr =
|
||||
pole.entityNumber === connection.entityNumber1
|
||||
? connection.entityNumber2
|
||||
: connection.entityNumber1
|
||||
pole.entityNumber === connection.cps[0].entityNumber
|
||||
? connection.cps[1].entityNumber
|
||||
: connection.cps[0].entityNumber
|
||||
blacklist.add(otherEntNr)
|
||||
}
|
||||
}
|
||||
@ -360,7 +384,7 @@ export class WireConnections extends EventEmitter {
|
||||
|
||||
public getPowerPoleDirection(entityNumber: number): number {
|
||||
const connections = this.getEntityConnections(entityNumber).map(conn =>
|
||||
entityNumber === conn.entityNumber1 ? conn.entityNumber2 : conn.entityNumber1
|
||||
entityNumber === conn.cps[0].entityNumber ? conn.cps[1].entityNumber : conn.cps[0].entityNumber
|
||||
)
|
||||
if (connections.length === 0) return 0
|
||||
|
||||
|
@ -227,7 +227,7 @@ function generateCovers(e: FD_Entity, data: IDrawData): SpriteData[] {
|
||||
y: Math.floor(data.position.y + connection.y),
|
||||
}
|
||||
|
||||
const ent = data.positionGrid.getEntityAtPosition(pos.x, pos.y)
|
||||
const ent = data.positionGrid.getEntityAtPosition(pos)
|
||||
if (!ent) return true
|
||||
|
||||
if (
|
||||
@ -547,7 +547,7 @@ function getBeltSprites(
|
||||
if (d.entity.direction === (d.relDir + 4) % 8) return d
|
||||
})
|
||||
|
||||
const entAtPos = positionGrid.getEntityAtPosition(pos.x, pos.y)
|
||||
const entAtPos = positionGrid.getEntityAtPosition(pos)
|
||||
if (
|
||||
forceStraight ||
|
||||
entAtPos.type === 'splitter' ||
|
||||
@ -1077,10 +1077,7 @@ function generateGraphics(e: FD_Entity): (data: IDrawData) => SpriteData[] {
|
||||
h: size.y,
|
||||
})
|
||||
.filter(e => e.name === 'gate')
|
||||
.map(e => ({
|
||||
x: e.position.x - data.position.x,
|
||||
y: e.position.y - data.position.y,
|
||||
}))
|
||||
.map(e => util.sumprod(e.position, -1,data.position))
|
||||
// Rotate relative to mid point
|
||||
.map(p => util.rotatePointBasedOnDir(p, dir).y)
|
||||
// Remove duplicates
|
||||
@ -1240,8 +1237,7 @@ function generateGraphics(e: FD_Entity): (data: IDrawData) => SpriteData[] {
|
||||
]
|
||||
.map(o => {
|
||||
const ent = data.positionGrid.getEntityAtPosition(
|
||||
data.position.x + o[0],
|
||||
data.position.y + o[1]
|
||||
util.sumprod(data.position, o)
|
||||
)
|
||||
return !!ent && ent.name === 'stone_wall'
|
||||
})
|
||||
@ -1308,10 +1304,10 @@ function generateGraphics(e: FD_Entity): (data: IDrawData) => SpriteData[] {
|
||||
}
|
||||
|
||||
if (data.dir === 0 && data.positionGrid) {
|
||||
const wall = data.positionGrid.getEntityAtPosition(
|
||||
data.position.x,
|
||||
data.position.y + 1
|
||||
)
|
||||
const wall = data.positionGrid.getEntityAtPosition({
|
||||
x: data.position.x,
|
||||
y: data.position.y + 1
|
||||
})
|
||||
if (wall && wall.name === 'stone_wall') {
|
||||
return [...getBaseSprites(), e.wall_patch.layers[0]]
|
||||
}
|
||||
@ -1464,10 +1460,7 @@ function generateGraphics(e: FD_Entity): (data: IDrawData) => SpriteData[] {
|
||||
const belt0Parts = getBeltSprites(
|
||||
e.belt_animation_set,
|
||||
data.positionGrid
|
||||
? {
|
||||
x: data.position.x + b0Offset.x,
|
||||
y: data.position.y + b0Offset.y,
|
||||
}
|
||||
? util.sumprod(data.position, b0Offset)
|
||||
: b0Offset,
|
||||
data.dir,
|
||||
data.positionGrid,
|
||||
@ -1479,10 +1472,7 @@ function generateGraphics(e: FD_Entity): (data: IDrawData) => SpriteData[] {
|
||||
const belt1Parts = getBeltSprites(
|
||||
e.belt_animation_set,
|
||||
data.positionGrid
|
||||
? {
|
||||
x: data.position.x + b1Offset.x,
|
||||
y: data.position.y + b1Offset.y,
|
||||
}
|
||||
? util.sumprod(data.position, b1Offset)
|
||||
: b1Offset,
|
||||
data.dir,
|
||||
data.positionGrid,
|
||||
|
@ -96,6 +96,17 @@ export function initSettingsPane(
|
||||
}
|
||||
editor.debug = debug
|
||||
})
|
||||
|
||||
if (localStorage.getItem('limitWireReach')) {
|
||||
const limitWireReach = localStorage.getItem('limitWireReach') === 'true'
|
||||
editor.limitWireReach = limitWireReach
|
||||
}
|
||||
gui.add({ limitWireReach: editor.limitWireReach }, 'limitWireReach')
|
||||
.name('Limit Wires Length')
|
||||
.onChange((limitWireReach: boolean) => {
|
||||
localStorage.setItem('limitWireReach', limitWireReach.toString())
|
||||
editor.limitWireReach = limitWireReach
|
||||
})
|
||||
|
||||
if (localStorage.getItem('oilOutpostSettings')) {
|
||||
const settings = JSON.parse(localStorage.getItem('oilOutpostSettings'))
|
||||
|
Loading…
x
Reference in New Issue
Block a user