@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cb9537349ef6920b23a1e1a601309a902d4eb05a1075c28b09189638686e2500
|
||||
size 77571
|
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 46 KiB |
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:22db7ba3795716bb5adf1d1eeb80af52ae7e4aa9e267324f5a541b90bf84e053
|
||||
size 548633
|
After Width: | Height: | Size: 48 KiB |
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:27c8d1eaa48beb7187e37244bd6ef7f43429be84ac88fffa96a4d72eb0e6565b
|
||||
size 158809
|
||||
oid sha256:7f04a2e96f79d013838dc95e0fcc9c2c2b3519cedc5d44602ecde29b85558239
|
||||
size 174256
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:590751d33bdb2ffa0f3c7f533688f6f93c37940e1e906be7972c9d5757ab7f69
|
||||
size 57790
|
||||
oid sha256:b0e6ae46466addd1bcb55a8005bbfb58fdf9e66c7fbae5620b723bdb21943b1c
|
||||
size 89487
|
||||
|
After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 201 KiB |
Before Width: | Height: | Size: 471 KiB After Width: | Height: | Size: 476 KiB |
Before Width: | Height: | Size: 980 KiB After Width: | Height: | Size: 956 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 5.3 KiB |
@ -0,0 +1,226 @@
|
||||
import { Loader } from "../../core/loader";
|
||||
import { enumAngleToDirection, enumDirection, Vector } from "../../core/vector";
|
||||
import { SOUNDS } from "../../platform/sound";
|
||||
import { BeltComponent } from "../components/belt";
|
||||
import { ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { ReplaceableMapEntityComponent } from "../components/replaceable_map_entity";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { enumLayer, GameRoot } from "../root";
|
||||
|
||||
export const arrayBeltVariantToRotation = [enumDirection.top, enumDirection.left, enumDirection.right];
|
||||
|
||||
export class MetaWireBaseBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("wire");
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#c425d7";
|
||||
}
|
||||
|
||||
getLayer() {
|
||||
return enumLayer.wires;
|
||||
}
|
||||
|
||||
getHasDirectionLockAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getPreviewSprite(rotationVariant) {
|
||||
switch (arrayBeltVariantToRotation[rotationVariant]) {
|
||||
case enumDirection.top: {
|
||||
return Loader.getSprite("sprites/buildings/wire_top.png");
|
||||
}
|
||||
case enumDirection.left: {
|
||||
return Loader.getSprite("sprites/buildings/wire_left.png");
|
||||
}
|
||||
case enumDirection.right: {
|
||||
return Loader.getSprite("sprites/buildings/wire_right.png");
|
||||
}
|
||||
default: {
|
||||
assertAlways(false, "Invalid belt rotation variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getBlueprintSprite(rotationVariant) {
|
||||
switch (arrayBeltVariantToRotation[rotationVariant]) {
|
||||
case enumDirection.top: {
|
||||
return Loader.getSprite("sprites/blueprints/wire_top.png");
|
||||
}
|
||||
case enumDirection.left: {
|
||||
return Loader.getSprite("sprites/blueprints/wire_left.png");
|
||||
}
|
||||
case enumDirection.right: {
|
||||
return Loader.getSprite("sprites/blueprints/wire_right.png");
|
||||
}
|
||||
default: {
|
||||
assertAlways(false, "Invalid belt rotation variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getStayInPlacementMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getRotateAutomaticallyWhilePlacing() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getPlacementSound() {
|
||||
return SOUNDS.placeBelt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
entity.addComponent(
|
||||
new BeltComponent({
|
||||
direction: enumDirection.top, // updated later
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(
|
||||
new ItemAcceptorComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
layer: enumLayer.wires,
|
||||
},
|
||||
],
|
||||
animated: false,
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(
|
||||
new ItemEjectorComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
direction: enumDirection.top, // updated later
|
||||
layer: enumLayer.wires,
|
||||
},
|
||||
],
|
||||
instantEject: true,
|
||||
})
|
||||
);
|
||||
// Make this entity replaceable
|
||||
entity.addComponent(new ReplaceableMapEntityComponent());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Entity} entity
|
||||
* @param {number} rotationVariant
|
||||
*/
|
||||
updateVariants(entity, rotationVariant) {
|
||||
entity.components.Belt.direction = arrayBeltVariantToRotation[rotationVariant];
|
||||
entity.components.ItemEjector.slots[0].direction = arrayBeltVariantToRotation[rotationVariant];
|
||||
entity.components.StaticMapEntity.spriteKey = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes optimal belt rotation variant
|
||||
* @param {GameRoot} root
|
||||
* @param {Vector} tile
|
||||
* @param {number} rotation
|
||||
* @param {string} variant
|
||||
* @return {{ rotation: number, rotationVariant: number }}
|
||||
*/
|
||||
computeOptimalDirectionAndRotationVariantAtTile(root, tile, rotation, variant) {
|
||||
const topDirection = enumAngleToDirection[rotation];
|
||||
const rightDirection = enumAngleToDirection[(rotation + 90) % 360];
|
||||
const bottomDirection = enumAngleToDirection[(rotation + 180) % 360];
|
||||
const leftDirection = enumAngleToDirection[(rotation + 270) % 360];
|
||||
|
||||
const { ejectors, acceptors } = root.logic.getEjectorsAndAcceptorsAtTile(tile, enumLayer.wires);
|
||||
|
||||
let hasBottomEjector = false;
|
||||
let hasRightEjector = false;
|
||||
let hasLeftEjector = false;
|
||||
|
||||
let hasTopAcceptor = false;
|
||||
let hasLeftAcceptor = false;
|
||||
let hasRightAcceptor = false;
|
||||
|
||||
// Check all ejectors
|
||||
for (let i = 0; i < ejectors.length; ++i) {
|
||||
const ejector = ejectors[i];
|
||||
|
||||
if (ejector.toDirection === topDirection) {
|
||||
hasBottomEjector = true;
|
||||
} else if (ejector.toDirection === leftDirection) {
|
||||
hasRightEjector = true;
|
||||
} else if (ejector.toDirection === rightDirection) {
|
||||
hasLeftEjector = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check all acceptors
|
||||
for (let i = 0; i < acceptors.length; ++i) {
|
||||
const acceptor = acceptors[i];
|
||||
if (acceptor.fromDirection === bottomDirection) {
|
||||
hasTopAcceptor = true;
|
||||
} else if (acceptor.fromDirection === rightDirection) {
|
||||
hasLeftAcceptor = true;
|
||||
} else if (acceptor.fromDirection === leftDirection) {
|
||||
hasRightAcceptor = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Soo .. if there is any ejector below us we always prioritize
|
||||
// this ejector
|
||||
if (!hasBottomEjector) {
|
||||
// When something ejects to us from the left and nothing from the right,
|
||||
// do a curve from the left to the top
|
||||
|
||||
if (hasRightEjector && !hasLeftEjector) {
|
||||
return {
|
||||
rotation: (rotation + 270) % 360,
|
||||
rotationVariant: 2,
|
||||
};
|
||||
}
|
||||
|
||||
// When something ejects to us from the right and nothing from the left,
|
||||
// do a curve from the right to the top
|
||||
if (hasLeftEjector && !hasRightEjector) {
|
||||
return {
|
||||
rotation: (rotation + 90) % 360,
|
||||
rotationVariant: 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// When there is a top acceptor, ignore sides
|
||||
// NOTICE: This makes the belt prefer side turns *way* too much!
|
||||
if (!hasTopAcceptor) {
|
||||
// When there is an acceptor to the right but no acceptor to the left,
|
||||
// do a turn to the right
|
||||
if (hasRightAcceptor && !hasLeftAcceptor) {
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 2,
|
||||
};
|
||||
}
|
||||
|
||||
// When there is an acceptor to the left but no acceptor to the right,
|
||||
// do a turn to the left
|
||||
if (hasLeftAcceptor && !hasRightAcceptor) {
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 0,
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { MetaWireBaseBuilding } from "../../buildings/wire_base";
|
||||
import { enumLayer } from "../../root";
|
||||
import { HUDBaseToolbar } from "./base_toolbar";
|
||||
|
||||
const supportedBuildings = [MetaWireBaseBuilding];
|
||||
|
||||
export class HUDWiresToolbar extends HUDBaseToolbar {
|
||||
constructor(root) {
|
||||
super(root, {
|
||||
supportedBuildings,
|
||||
visibilityCondition: () =>
|
||||
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === enumLayer.wires,
|
||||
htmlElementId: "ingame_HUD_wires_toolbar",
|
||||
});
|
||||
}
|
||||
}
|
@ -1,8 +1,12 @@
|
||||
import { gItemRegistry } from "../core/global_registries";
|
||||
import { ShapeItem } from "./items/shape_item";
|
||||
import { ColorItem } from "./items/color_item";
|
||||
import { PositiveEnergyItem } from "./items/positive_energy_item";
|
||||
import { NegativeEnergyItem } from "./items/negative_energy_item";
|
||||
|
||||
export function initItemRegistry() {
|
||||
gItemRegistry.register(ShapeItem);
|
||||
gItemRegistry.register(ColorItem);
|
||||
gItemRegistry.register(PositiveEnergyItem);
|
||||
gItemRegistry.register(NegativeEnergyItem);
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { smoothenDpi } from "../../core/dpi_manager";
|
||||
import { DrawParameters } from "../../core/draw_parameters";
|
||||
import { types } from "../../savegame/serialization";
|
||||
import { BaseItem, enumItemType } from "../base_item";
|
||||
|
||||
export class NegativeEnergyItem extends BaseItem {
|
||||
static getId() {
|
||||
return "negative_energy";
|
||||
}
|
||||
|
||||
static getSchema() {
|
||||
return types.uint;
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
deserialize(data) {}
|
||||
|
||||
getItemType() {
|
||||
return enumItemType.negativeEnergy;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.bufferGenerator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {number} size
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
draw(x, y, parameters, size = 12) {
|
||||
if (!this.bufferGenerator) {
|
||||
this.bufferGenerator = this.internalGenerateBuffer.bind(this);
|
||||
}
|
||||
|
||||
const dpi = smoothenDpi(globalConfig.shapesSharpness * parameters.zoomLevel);
|
||||
|
||||
const key = size + "/" + dpi;
|
||||
const canvas = parameters.root.buffers.getForKey(key, "", size, size, dpi, this.bufferGenerator);
|
||||
parameters.context.drawImage(canvas, x - size / 2, y - size / 2, size, size);
|
||||
}
|
||||
/**
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
* @param {CanvasRenderingContext2D} context
|
||||
* @param {number} w
|
||||
* @param {number} h
|
||||
* @param {number} dpi
|
||||
*/
|
||||
internalGenerateBuffer(canvas, context, w, h, dpi) {
|
||||
context.translate((w * dpi) / 2, (h * dpi) / 2);
|
||||
context.scale((dpi * w) / 12, (dpi * h) / 12);
|
||||
|
||||
context.fillStyle = "#1d2725";
|
||||
context.strokeStyle = "#eee";
|
||||
context.lineWidth = 1;
|
||||
context.beginCircle(0, 0, 5);
|
||||
context.fill();
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
export const POSITIVE_ENERGY_ITEM_SINGLETON = new NegativeEnergyItem();
|
@ -0,0 +1,68 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { smoothenDpi } from "../../core/dpi_manager";
|
||||
import { DrawParameters } from "../../core/draw_parameters";
|
||||
import { types } from "../../savegame/serialization";
|
||||
import { BaseItem, enumItemType } from "../base_item";
|
||||
|
||||
export class PositiveEnergyItem extends BaseItem {
|
||||
static getId() {
|
||||
return "positive_energy";
|
||||
}
|
||||
|
||||
static getSchema() {
|
||||
return types.uint;
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
deserialize(data) {}
|
||||
|
||||
getItemType() {
|
||||
return enumItemType.positiveEnergy;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.bufferGenerator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {number} size
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
draw(x, y, parameters, size = 12) {
|
||||
if (!this.bufferGenerator) {
|
||||
this.bufferGenerator = this.internalGenerateBuffer.bind(this);
|
||||
}
|
||||
|
||||
const dpi = smoothenDpi(globalConfig.shapesSharpness * parameters.zoomLevel);
|
||||
|
||||
const key = size + "/" + dpi;
|
||||
const canvas = parameters.root.buffers.getForKey(key, "", size, size, dpi, this.bufferGenerator);
|
||||
parameters.context.drawImage(canvas, x - size / 2, y - size / 2, size, size);
|
||||
}
|
||||
/**
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
* @param {CanvasRenderingContext2D} context
|
||||
* @param {number} w
|
||||
* @param {number} h
|
||||
* @param {number} dpi
|
||||
*/
|
||||
internalGenerateBuffer(canvas, context, w, h, dpi) {
|
||||
context.translate((w * dpi) / 2, (h * dpi) / 2);
|
||||
context.scale((dpi * w) / 12, (dpi * h) / 12);
|
||||
|
||||
context.fillStyle = "#e84a4a";
|
||||
context.strokeStyle = "#eee";
|
||||
context.lineWidth = 1;
|
||||
context.beginCircle(0, 0, 5);
|
||||
context.fill();
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
export const POSITIVE_ENERGY_ITEM_SINGLETON = new PositiveEnergyItem();
|