Improve wire auto-connect
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 1001 KiB After Width: | Height: | Size: 1003 KiB |
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 205 KiB |
Before Width: | Height: | Size: 486 KiB After Width: | Height: | Size: 492 KiB |
Before Width: | Height: | Size: 945 KiB After Width: | Height: | Size: 956 KiB |
3
res_raw/sounds/music/theme-full.mp3
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4e6959df75e915fb1a8d55e3d0ab750349b27276788ded63178f2a117c2edcf5
|
||||
size 79441572
|
BIN
res_raw/sprites/blueprints/constant_signal.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
res_raw/sprites/blueprints/wire-cross.png
Normal file
After Width: | Height: | Size: 660 B |
Before Width: | Height: | Size: 558 B After Width: | Height: | Size: 554 B |
Before Width: | Height: | Size: 506 B After Width: | Height: | Size: 516 B |
Before Width: | Height: | Size: 421 B After Width: | Height: | Size: 421 B |
BIN
res_raw/sprites/buildings/constant_signal.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
res_raw/sprites/buildings/wire-cross.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 6.2 KiB |
@ -12,7 +12,7 @@ export const CHANGELOG = [
|
||||
"Fix rare crash regarding the buildings toolbar (by isaisstillalive)",
|
||||
"Fixed some phrases (by EnderDoom77)",
|
||||
"Zoom towards mouse cursor (by Dimava)",
|
||||
"Updated the soundtrack again, it is now 20 minutes in total!",
|
||||
"Updated the soundtrack again, it is now 40 minutes in total!",
|
||||
"Updated and added new translations (Thanks to all contributors!)",
|
||||
"Allow editing waypoints (by isaisstillalive)",
|
||||
"Show confirmation when cutting area which is too expensive to get pasted again (by isaisstillalive)",
|
||||
|
@ -1,35 +1,24 @@
|
||||
import { Loader } from "../../core/loader";
|
||||
import { rotateDirectionalObject } from "../../core/utils";
|
||||
import { Vector } from "../../core/vector";
|
||||
import { generateMatrixRotations } from "../../core/utils";
|
||||
import { enumDirection, enumDirectionToAngle, enumDirectionToVector, Vector } from "../../core/vector";
|
||||
import { SOUNDS } from "../../platform/sound";
|
||||
import { enumWireType, WireComponent } from "../components/wire";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { enumLayer, GameRoot } from "../root";
|
||||
|
||||
export const arrayWireRotationVariantToType = [enumWireType.regular, enumWireType.turn, enumWireType.split];
|
||||
export const arrayWireRotationVariantToType = [
|
||||
enumWireType.regular,
|
||||
enumWireType.turn,
|
||||
enumWireType.split,
|
||||
enumWireType.cross,
|
||||
];
|
||||
|
||||
export const wireOverlayMatrices = {
|
||||
[enumWireType.regular]: {
|
||||
0: [0, 1, 0, 0, 1, 0, 0, 1, 0],
|
||||
90: [0, 0, 0, 1, 1, 1, 0, 0, 0],
|
||||
180: [0, 1, 0, 0, 1, 0, 0, 1, 0],
|
||||
270: [0, 0, 0, 1, 1, 1, 0, 0, 0],
|
||||
},
|
||||
|
||||
[enumWireType.split]: {
|
||||
0: [0, 0, 0, 1, 1, 1, 0, 1, 0],
|
||||
90: [0, 1, 0, 1, 1, 0, 0, 1, 0],
|
||||
180: [0, 1, 0, 1, 1, 1, 0, 0, 0],
|
||||
270: [0, 1, 0, 0, 1, 1, 0, 1, 0],
|
||||
},
|
||||
|
||||
[enumWireType.turn]: {
|
||||
0: [0, 0, 0, 0, 1, 1, 0, 1, 0],
|
||||
90: [0, 0, 0, 1, 1, 0, 0, 1, 0],
|
||||
180: [0, 1, 0, 1, 1, 0, 0, 0, 0],
|
||||
270: [0, 1, 0, 0, 1, 1, 0, 0, 0],
|
||||
},
|
||||
[enumWireType.regular]: generateMatrixRotations([0, 1, 0, 0, 1, 0, 0, 1, 0]),
|
||||
[enumWireType.split]: generateMatrixRotations([0, 0, 0, 1, 1, 1, 0, 1, 0]),
|
||||
[enumWireType.turn]: generateMatrixRotations([0, 0, 0, 0, 1, 1, 0, 1, 0]),
|
||||
[enumWireType.cross]: generateMatrixRotations([0, 1, 0, 1, 1, 1, 0, 1, 0]),
|
||||
};
|
||||
|
||||
export class MetaWireBuilding extends MetaBuilding {
|
||||
@ -121,8 +110,11 @@ export class MetaWireBuilding extends MetaBuilding {
|
||||
case enumWireType.split: {
|
||||
return Loader.getSprite("sprites/buildings/wire-split.png");
|
||||
}
|
||||
case enumWireType.cross: {
|
||||
return Loader.getSprite("sprites/buildings/wire-cross.png");
|
||||
}
|
||||
default: {
|
||||
assertAlways(false, "Invalid belt rotation variant");
|
||||
assertAlways(false, "Invalid wire rotation variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -138,8 +130,11 @@ export class MetaWireBuilding extends MetaBuilding {
|
||||
case enumWireType.split: {
|
||||
return Loader.getSprite("sprites/blueprints/wire-split.png");
|
||||
}
|
||||
case enumWireType.cross: {
|
||||
return Loader.getSprite("sprites/blueprints/wire-cross.png");
|
||||
}
|
||||
default: {
|
||||
assertAlways(false, "Invalid belt rotation variant");
|
||||
assertAlways(false, "Invalid wire rotation variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,21 +150,24 @@ export class MetaWireBuilding extends MetaBuilding {
|
||||
* @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array<Entity> }}
|
||||
*/
|
||||
computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) {
|
||||
const connections = root.logic.getLocalWireConnectionsAtTile(tile);
|
||||
|
||||
const d = rotateDirectionalObject(connections, rotation);
|
||||
|
||||
// "Sticky" bottom
|
||||
connections.bottom = true;
|
||||
const connections = {
|
||||
top: root.logic.computeWireEdgeStatus({ tile, rotation, edge: enumDirection.top }),
|
||||
right: root.logic.computeWireEdgeStatus({ tile, rotation, edge: enumDirection.right }),
|
||||
bottom: root.logic.computeWireEdgeStatus({ tile, rotation, edge: enumDirection.bottom }),
|
||||
left: root.logic.computeWireEdgeStatus({ tile, rotation, edge: enumDirection.left }),
|
||||
};
|
||||
|
||||
let flag = 0;
|
||||
flag |= d.top ? 0x1000 : 0;
|
||||
flag |= d.right ? 0x100 : 0;
|
||||
flag |= d.bottom ? 0x10 : 0;
|
||||
flag |= d.left ? 0x1 : 0;
|
||||
flag |= connections.top ? 0x1000 : 0;
|
||||
flag |= connections.right ? 0x100 : 0;
|
||||
flag |= connections.bottom ? 0x10 : 0;
|
||||
flag |= connections.left ? 0x1 : 0;
|
||||
|
||||
let targetType = enumWireType.regular;
|
||||
|
||||
// First, reset rotation
|
||||
rotation = 0;
|
||||
|
||||
switch (flag) {
|
||||
case 0x0000:
|
||||
// Nothing
|
||||
@ -177,12 +175,12 @@ export class MetaWireBuilding extends MetaBuilding {
|
||||
|
||||
case 0x0001:
|
||||
// Left
|
||||
targetType = enumWireType.turn;
|
||||
rotation += 90;
|
||||
break;
|
||||
|
||||
case 0x0010:
|
||||
// Bottom
|
||||
// END
|
||||
break;
|
||||
|
||||
case 0x0011:
|
||||
@ -193,12 +191,11 @@ export class MetaWireBuilding extends MetaBuilding {
|
||||
|
||||
case 0x0100:
|
||||
// Right
|
||||
targetType = enumWireType.turn;
|
||||
rotation += 90;
|
||||
break;
|
||||
|
||||
case 0x0101:
|
||||
// Right | Left
|
||||
// @todo: Might want to do rotation += 90 here
|
||||
rotation += 90;
|
||||
break;
|
||||
|
||||
@ -252,7 +249,7 @@ export class MetaWireBuilding extends MetaBuilding {
|
||||
|
||||
case 0x1111:
|
||||
// Top | Right | Bottom | Left
|
||||
// @todo: Crossing
|
||||
targetType = enumWireType.cross;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,8 @@ import { Rectangle } from "../../core/rectangle";
|
||||
import { AtlasSprite } from "../../core/sprites";
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { types } from "../../savegame/serialization";
|
||||
import { Component } from "../component";
|
||||
import { getBuildingDataFromCode } from "../building_codes";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { Component } from "../component";
|
||||
|
||||
export class StaticMapEntityComponent extends Component {
|
||||
static getId() {
|
||||
@ -58,7 +57,7 @@ export class StaticMapEntityComponent extends Component {
|
||||
|
||||
/**
|
||||
* Returns the meta building
|
||||
* @returns {MetaBuilding}
|
||||
* @returns {import("../meta_building").MetaBuilding}
|
||||
*/
|
||||
getMetaBuilding() {
|
||||
return getBuildingDataFromCode(this.code).metaInstance;
|
||||
|
@ -5,6 +5,7 @@ export const enumWireType = {
|
||||
regular: "regular",
|
||||
turn: "turn",
|
||||
split: "split",
|
||||
cross: "cross",
|
||||
};
|
||||
|
||||
export class WireComponent extends Component {
|
||||
@ -30,31 +31,38 @@ export class WireComponent extends Component {
|
||||
* @returns {import("../../core/utils").DirectionalObject}
|
||||
*/
|
||||
getLocalConnections() {
|
||||
switch (this.type) {
|
||||
case enumWireType.regular:
|
||||
return {
|
||||
top: true,
|
||||
right: false,
|
||||
bottom: true,
|
||||
left: false,
|
||||
};
|
||||
case enumWireType.turn:
|
||||
return {
|
||||
top: false,
|
||||
right: true,
|
||||
bottom: true,
|
||||
left: false,
|
||||
};
|
||||
case enumWireType.split:
|
||||
return {
|
||||
top: false,
|
||||
right: true,
|
||||
bottom: true,
|
||||
left: true,
|
||||
};
|
||||
|
||||
default:
|
||||
assertAlways(false, "Invalid wire type: " + this.type);
|
||||
}
|
||||
// switch (this.type) {
|
||||
// case enumWireType.regular:
|
||||
// return {
|
||||
// top: true,
|
||||
// right: false,
|
||||
// bottom: true,
|
||||
// left: false,
|
||||
// };
|
||||
// case enumWireType.turn:
|
||||
// return {
|
||||
// top: false,
|
||||
// right: true,
|
||||
// bottom: true,
|
||||
// left: false,
|
||||
// };
|
||||
// case enumWireType.split:
|
||||
// return {
|
||||
// top: false,
|
||||
// right: true,
|
||||
// bottom: true,
|
||||
// left: true,
|
||||
// };
|
||||
|
||||
// default:
|
||||
// assertAlways(false, "Invalid wire type: " + this.type);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { BaseItem } from "../base_item";
|
||||
import { Component } from "../component";
|
||||
import { Vector, enumDirection } from "../../core/vector";
|
||||
import { types } from "../../savegame/serialization";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumPinSlotType = {
|
||||
@ -17,7 +17,8 @@ export const enumPinSlotType = {
|
||||
/** @typedef {{
|
||||
* pos: Vector,
|
||||
* type: enumPinSlotType,
|
||||
* direction: enumDirection
|
||||
* direction: enumDirection,
|
||||
* value: BaseItem
|
||||
* }} WirePinSlot */
|
||||
|
||||
export class WiredPinsComponent extends Component {
|
||||
@ -63,6 +64,7 @@ export class WiredPinsComponent extends Component {
|
||||
pos: slotData.pos,
|
||||
type: slotData.type,
|
||||
direction: slotData.direction,
|
||||
value: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,12 @@
|
||||
import { createLogger } from "../core/logging";
|
||||
import { round2Digits, rotateDirectionalObject } from "../core/utils";
|
||||
import { enumDirection, enumDirectionToVector, Vector } from "../core/vector";
|
||||
import {
|
||||
enumDirection,
|
||||
enumDirectionToVector,
|
||||
Vector,
|
||||
enumDirectionToAngle,
|
||||
enumInvertedDirections,
|
||||
} from "../core/vector";
|
||||
import { Entity } from "./entity";
|
||||
import { MetaBuilding } from "./meta_building";
|
||||
import { GameRoot, enumLayer } from "./root";
|
||||
@ -8,6 +14,13 @@ import { STOP_PROPAGATION } from "../core/signal";
|
||||
|
||||
const logger = createLogger("ingame/logic");
|
||||
|
||||
/** @enum {number} */
|
||||
export const enumWireEdgeFlag = {
|
||||
empty: 0,
|
||||
filled: 1,
|
||||
connected: 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Typing helper
|
||||
* @typedef {Array<{
|
||||
@ -214,11 +227,111 @@ export class GameLogic {
|
||||
const wiresComp = contents.components.Wire;
|
||||
if (wiresComp) {
|
||||
const connections = wiresComp.getLocalConnections();
|
||||
return rotateDirectionalObject(connections, staticComp.rotation);
|
||||
return rotateDirectionalObject(connections, staticComp.originalRotation);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Computes the flag for a given tile
|
||||
* @param {object} param0
|
||||
* @param {Vector} param0.tile The tile to check at
|
||||
* @param {enumDirection} param0.edge The edge to check for
|
||||
* @param {number} param0.rotation The local tiles base rotation
|
||||
*/
|
||||
computeWireEdgeStatus({ tile, edge, rotation }) {
|
||||
const offset = enumDirectionToVector[edge];
|
||||
const refTile = tile.add(offset);
|
||||
const angle = enumDirectionToAngle[edge];
|
||||
|
||||
// // First, check if this edge can be connected from locally
|
||||
// const canConnectLocally = rotation === angle || (rotation + 180) % 360 === angle;
|
||||
|
||||
const neighbourStatus = this.getWireEdgeFlag(refTile, edge);
|
||||
|
||||
if (neighbourStatus === enumWireEdgeFlag.empty) {
|
||||
// It's empty, no point in connecting
|
||||
return false;
|
||||
}
|
||||
|
||||
if (neighbourStatus === enumWireEdgeFlag.filled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (neighbourStatus === enumWireEdgeFlag.connected) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the flag at the given tile
|
||||
* @param {Vector} tile
|
||||
* @param {enumDirection} edge
|
||||
* @returns {enumWireEdgeFlag}
|
||||
*/
|
||||
getWireEdgeFlag(tile, edge) {
|
||||
// Search for relevant pins
|
||||
const pinEntities = this.root.map.getLayersContentsMultipleXY(tile.x, tile.y);
|
||||
|
||||
// Go over all entities which could have a pin
|
||||
for (let i = 0; i < pinEntities.length; ++i) {
|
||||
const pinEntity = pinEntities[i];
|
||||
const pinComp = pinEntity.components.WiredPins;
|
||||
const staticComp = pinEntity.components.StaticMapEntity;
|
||||
|
||||
// Skip those who don't have pins
|
||||
if (!pinComp) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Go over all pins
|
||||
const pins = pinComp.slots;
|
||||
for (let k = 0; k < pinComp.slots.length; ++k) {
|
||||
const pinSlot = pins[k];
|
||||
const pinLocation = staticComp.localTileToWorld(pinSlot.pos);
|
||||
|
||||
// Check if the pin has the right location
|
||||
if (!pinLocation.equals(tile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the pin has the right direction
|
||||
if (pinSlot.direction !== enumInvertedDirections[edge]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found a pin!
|
||||
return enumWireEdgeFlag.connected;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check if there's a connectable wire
|
||||
const targetEntity = this.root.map.getTileContent(tile, enumLayer.wires);
|
||||
if (!targetEntity) {
|
||||
return enumWireEdgeFlag.empty;
|
||||
}
|
||||
|
||||
// Check if its a wire
|
||||
const wiresComp = targetEntity.components.Wire;
|
||||
if (!wiresComp) {
|
||||
return enumWireEdgeFlag.empty;
|
||||
}
|
||||
|
||||
const refAngle = enumDirectionToAngle[edge];
|
||||
const refRotation = targetEntity.components.StaticMapEntity.originalRotation;
|
||||
const canConnectRemotely = refRotation === refAngle || (refRotation + 180) % 360 === refAngle;
|
||||
|
||||
// Check if the wire points towards the right direction
|
||||
if (!canConnectRemotely) {
|
||||
// Seems its not the right direction - well, still its filled
|
||||
return enumWireEdgeFlag.filled;
|
||||
}
|
||||
|
||||
// Actually connected
|
||||
return enumWireEdgeFlag.connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the acceptors and ejectors which affect the current tile
|
||||
* @param {Vector} tile
|
||||
|
@ -84,6 +84,7 @@ export function initMetaBuildingRegistry() {
|
||||
registerBuildingVariant(27, MetaWireBuilding, defaultBuildingVariant, 0);
|
||||
registerBuildingVariant(28, MetaWireBuilding, defaultBuildingVariant, 1);
|
||||
registerBuildingVariant(29, MetaWireBuilding, defaultBuildingVariant, 2);
|
||||
registerBuildingVariant(30, MetaWireBuilding, defaultBuildingVariant, 3);
|
||||
|
||||
// Propagate instances
|
||||
for (const key in gBuildingVariants) {
|
||||
|
@ -5,6 +5,7 @@ import { Entity } from "../entity";
|
||||
import { formatBigNumber } from "../../core/utils";
|
||||
import { Loader } from "../../core/loader";
|
||||
import { T } from "../../translations";
|
||||
import { ShapeItem } from "../items/shape_item";
|
||||
|
||||
export class HubSystem extends GameSystemWithFilter {
|
||||
constructor(root) {
|
||||
@ -17,7 +18,14 @@ export class HubSystem extends GameSystemWithFilter {
|
||||
this.forEachMatchingEntityOnScreen(parameters, this.drawEntity.bind(this));
|
||||
}
|
||||
|
||||
update() {}
|
||||
update() {
|
||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||
// Set hub goal
|
||||
const entity = this.allEntities[i];
|
||||
const pinsComp = entity.components.WiredPins;
|
||||
pinsComp.slots[0].value = new ShapeItem(this.root.hubGoals.currentGoal.definition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {DrawParameters} parameters
|
||||
|
@ -17,6 +17,7 @@ export class WireSystem extends GameSystemWithFilter {
|
||||
[enumWireType.regular]: Loader.getSprite("sprites/buildings/wire.png"),
|
||||
[enumWireType.turn]: Loader.getSprite("sprites/buildings/wire-turn.png"),
|
||||
[enumWireType.split]: Loader.getSprite("sprites/buildings/wire-split.png"),
|
||||
[enumWireType.cross]: Loader.getSprite("sprites/buildings/wire-cross.png"),
|
||||
};
|
||||
|
||||
this.root.signals.entityDestroyed.add(this.updateSurroundingWirePlacement, this);
|
||||
@ -36,7 +37,36 @@ export class WireSystem extends GameSystemWithFilter {
|
||||
if (entity && entity.components.Wire) {
|
||||
const wireType = entity.components.Wire.type;
|
||||
const sprite = this.wireSprites[wireType];
|
||||
entity.components.StaticMapEntity.drawSpriteOnFullEntityBounds(parameters, sprite, 0);
|
||||
assert(sprite, "Unknown wire type: " + wireType);
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
staticComp.drawSpriteOnFullEntityBounds(parameters, sprite, 0);
|
||||
|
||||
if (G_IS_DEV && globalConfig.debug.renderWireRotations) {
|
||||
parameters.context.fillStyle = "red";
|
||||
parameters.context.font = "5px Tahoma";
|
||||
parameters.context.fillText(
|
||||
"" + staticComp.originalRotation,
|
||||
staticComp.origin.x * globalConfig.tileSize,
|
||||
staticComp.origin.y * globalConfig.tileSize + 5
|
||||
);
|
||||
|
||||
parameters.context.fillStyle = "rgba(255, 0, 0, 0.2)";
|
||||
if (staticComp.originalRotation % 180 === 0) {
|
||||
parameters.context.fillRect(
|
||||
(staticComp.origin.x + 0.5) * globalConfig.tileSize,
|
||||
staticComp.origin.y * globalConfig.tileSize,
|
||||
3,
|
||||
globalConfig.tileSize
|
||||
);
|
||||
} else {
|
||||
parameters.context.fillRect(
|
||||
staticComp.origin.x * globalConfig.tileSize,
|
||||
(staticComp.origin.y + 0.5) * globalConfig.tileSize,
|
||||
globalConfig.tileSize,
|
||||
3
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,6 +179,12 @@ export class WiredPinsSystem extends GameSystemWithFilter {
|
||||
offsetX: 0,
|
||||
offsetY: 0,
|
||||
});
|
||||
|
||||
// Draw contained item to visualize whats emitted
|
||||
const value = slot.value;
|
||||
if (value) {
|
||||
value.draw(worldPos.x, worldPos.y, parameters, 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export const SOUNDS = {
|
||||
};
|
||||
|
||||
export const MUSIC = {
|
||||
theme: "theme",
|
||||
theme: G_IS_STANDALONE ? "theme-full" : "theme-short",
|
||||
menu: "menu",
|
||||
};
|
||||
|
||||
|