1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

Fixed Branch

This commit is contained in:
TcePrepK 2020-11-07 23:08:23 +03:00
parent 0146aa91bb
commit b94f60c5d9
32 changed files with 587 additions and 79 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -1,5 +1,5 @@
$buildings: belt, cutter, miner, mixer, painter, rotater, balancer, stacker, trash, underground_belt, wire,
constant_signal, logic_gate, lever, filter, wire_tunnel, display, virtual_processor, reader, storage,
constant_signal, logic_gate, lever, filter, wire_tunnel, display, wireless_display, virtual_processor, reader, storage,
transistor, analyzer, comparator, item_producer;
@each $building in $buildings {
@ -11,7 +11,7 @@ $buildings: belt, cutter, miner, mixer, painter, rotater, balancer, stacker, tra
$buildingsAndVariants: belt, balancer, underground_belt, underground_belt-tier2, miner, miner-chainable,
cutter, cutter-quad, rotater, rotater-ccw, stacker, mixer, painter-double, painter-quad, trash, storage,
reader, rotater-rotate180, display, constant_signal, wire, wire_tunnel, logic_gate-or, logic_gate-not,
reader, rotater-rotate180, display, wireless_display, wireless_display-remote_control, constant_signal, wire, wire_tunnel, logic_gate-or, logic_gate-not,
logic_gate-xor, analyzer, virtual_processor-rotater, virtual_processor-unstacker, item_producer,
virtual_processor-stacker, virtual_processor-painter, wire-second, painter, painter-mirrored, comparator;
@each $building in $buildingsAndVariants {

View File

@ -0,0 +1,87 @@
import { enumDirection, Vector } from "../../core/vector";
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
import { Entity } from "../entity";
import { defaultBuildingVariant, MetaBuilding } from "../meta_building";
import { GameRoot } from "../root";
import { WirelessDisplayComponent } from "../components/wireless_display";
import { enumHubGoalRewards } from "../tutorial_goals";
import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils";
/** @enum {string} */
export const enumWirelessDisplayVariants = {
remote_control: "remote_control",
};
const overlayMatrices = {
[defaultBuildingVariant]: null,
[enumWirelessDisplayVariants.remote_control]: generateMatrixRotations([0, 1, 0, 0, 1, 1, 0, 1, 0]),
};
export class MetaWirelessDisplayBuilding extends MetaBuilding {
constructor() {
super("wireless_display");
}
getSilhouetteColor() {
return "#aaaaaa";
}
/**
* @param {GameRoot} root
*/
getIsUnlocked(root) {
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_display);
}
/**
* @param {GameRoot} root
*/
getAvailableVariants(root) {
let available = [defaultBuildingVariant];
if (true || root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_display)) {
available.push(enumWirelessDisplayVariants.remote_control);
}
return available;
}
getDimensions() {
return new Vector(1, 1);
}
getShowWiresLayerPreview() {
return true;
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
entity.addComponent(new WirelessDisplayComponent({}));
}
/**
*
* @param {Entity} entity
* @param {number} rotationVariant
* @param {string} variant
*/
updateVariants(entity, rotationVariant, variant) {
if (variant == enumWirelessDisplayVariants.remote_control && !entity.components.WiredPins) {
entity.addComponent(
new WiredPinsComponent({
slots: [
{
pos: new Vector(0, 0),
direction: enumDirection.bottom,
type: enumPinSlotType.logicalAcceptor,
},
],
}),
);
}
}
}

View File

@ -19,6 +19,8 @@ import { DisplayComponent } from "./components/display";
import { BeltReaderComponent } from "./components/belt_reader";
import { FilterComponent } from "./components/filter";
import { ItemProducerComponent } from "./components/item_producer";
import { WirelessDisplayComponent } from "./components/wireless_display";
import { WirelessCodeComponent } from "./components/wireless_code";
export function initComponentRegistry() {
gComponentRegistry.register(StaticMapEntityComponent);
@ -38,9 +40,11 @@ export function initComponentRegistry() {
gComponentRegistry.register(LeverComponent);
gComponentRegistry.register(WireTunnelComponent);
gComponentRegistry.register(DisplayComponent);
gComponentRegistry.register(WirelessDisplayComponent);
gComponentRegistry.register(BeltReaderComponent);
gComponentRegistry.register(FilterComponent);
gComponentRegistry.register(ItemProducerComponent);
gComponentRegistry.register(WirelessCodeComponent);
// IMPORTANT ^^^^^ UPDATE ENTITY COMPONENT STORAGE AFTERWARDS

View File

@ -1,3 +1,4 @@
import { Component } from "../component";
export class WireTunnelComponent extends Component {

View File

@ -0,0 +1,23 @@
import { Component } from "../component";
import { types } from "../../savegame/serialization";
export class WirelessCodeComponent extends Component {
static getId() {
return "WirelessCode";
}
static getSchema() {
return {
wireless_code: types.string
};
}
/**
*
* @param {object} id
*/
constructor(id) {
super();
this.wireless_code = id;
}
}

View File

@ -0,0 +1,36 @@
import { Component } from "../component";
import { types } from "../../savegame/serialization";
import { BaseItem } from "../base_item";
import { typeItemSingleton } from "../item_resolver";
export class WirelessDisplayComponent extends Component {
static getId() {
return "WirelessDisplay";
}
static getSchema() {
return {
signal: types.nullable(typeItemSingleton),
};
}
/**
* Copy the current state to another component
* @param {WirelessDisplayComponent} otherComponent
*/
copyAdditionalStateTo(otherComponent) {
otherComponent.signal = this.signal;
}
/**
*
* @param {object} param0
* @param {BaseItem=} param0.signal The signal to store
*/
constructor({ signal = null }) {
super();
this.signal = signal;
}
}

View File

@ -89,7 +89,6 @@ export class GameCore {
this.root.savegame = savegame;
this.root.gameWidth = this.app.screenWidth;
this.root.gameHeight = this.app.screenHeight;
// Initialize canvas element & context
this.internalInitCanvas();

View File

@ -96,6 +96,7 @@ export class Entity extends BasicSerializableObject {
rotation: staticComp.rotation,
rotationVariant: buildingData.rotationVariant,
variant: buildingData.variant,
wireless_code: this.components.WirelessCode,
});
for (const key in this.components) {

View File

@ -19,6 +19,8 @@ import { DisplayComponent } from "./components/display";
import { BeltReaderComponent } from "./components/belt_reader";
import { FilterComponent } from "./components/filter";
import { ItemProducerComponent } from "./components/item_producer";
import { WirelessDisplayComponent } from "./components/wireless_display";
import { WirelessCodeComponent } from "./components/wireless_code";
/* typehints:end */
/**
@ -80,6 +82,9 @@ export class EntityComponentStorage {
/** @type {DisplayComponent} */
this.Display;
/** @type {WirelessDisplayComponent} */
this.WirelessDisplay;
/** @type {BeltReaderComponent} */
this.BeltReader;
@ -89,6 +94,9 @@ export class EntityComponentStorage {
/** @type {ItemProducerComponent} */
this.ItemProducer;
/** @type {WirelessCodeComponent} */
this.WirelessCode;
/* typehints:end */
}
}

View File

@ -20,6 +20,7 @@ import { ConstantSignalSystem } from "./systems/constant_signal";
import { LogicGateSystem } from "./systems/logic_gate";
import { LeverSystem } from "./systems/lever";
import { DisplaySystem } from "./systems/display";
import { WirelessDisplaySystem } from "./systems/wireless_display";
import { ItemProcessorOverlaysSystem } from "./systems/item_processor_overlays";
import { BeltReaderSystem } from "./systems/belt_reader";
import { FilterSystem } from "./systems/filter";
@ -88,6 +89,9 @@ export class GameSystemManager {
/** @type {DisplaySystem} */
display: null,
/** @type {WirelessDisplaySystem} */
wirelessDisplay: null,
/** @type {ItemProcessorOverlaysSystem} */
itemProcessorOverlays: null,
@ -162,6 +166,7 @@ export class GameSystemManager {
add("beltReader", BeltReaderSystem);
add("display", DisplaySystem);
add("wirelessDisplay", WirelessDisplaySystem);
add("itemProcessorOverlays", ItemProcessorOverlaysSystem);

View File

@ -238,7 +238,8 @@ export class HubGoals extends BasicSerializableObject {
return;
}
const required = Math.min(200, 4 + (this.level - 27) * 0.25);
//Floor Required amount to remove confusion
const required = Math.min(200, Math.floor(4 + (this.level - 27) * 0.25));
this.currentGoal = {
definition: this.computeFreeplayShape(this.level),
required,

View File

@ -1,6 +1,7 @@
import { MetaBeltBuilding } from "../../buildings/belt";
import { MetaCutterBuilding } from "../../buildings/cutter";
import { MetaDisplayBuilding } from "../../buildings/display";
import { MetaWirelessDisplayBuilding } from "../../buildings/wireless_display";
import { MetaFilterBuilding } from "../../buildings/filter";
import { MetaLeverBuilding } from "../../buildings/lever";
import { MetaMinerBuilding } from "../../buildings/miner";
@ -39,6 +40,7 @@ export class HUDBuildingsToolbar extends HUDBaseToolbar {
MetaLeverBuilding,
MetaFilterBuilding,
MetaDisplayBuilding,
MetaWirelessDisplayBuilding,
],
visibilityCondition: () =>
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "regular",

View File

@ -14,6 +14,7 @@ import { KEYMAPPINGS } from "../../key_action_mapper";
import { THEME } from "../../theme";
import { enumHubGoalRewards } from "../../tutorial_goals";
import { Blueprint } from "../../blueprint";
import { drawRotatedSprite } from "../../../core/draw_utils";
const logger = createLogger("hud/mass_selector");
@ -304,16 +305,9 @@ export class HUDMassSelector extends BaseHUDPart {
renderedUids.add(uid);
const staticComp = contents.components.StaticMapEntity;
const bounds = staticComp.getTileSpaceBounds();
parameters.context.beginRoundedRect(
bounds.x * globalConfig.tileSize + boundsBorder,
bounds.y * globalConfig.tileSize + boundsBorder,
bounds.w * globalConfig.tileSize - 2 * boundsBorder,
bounds.h * globalConfig.tileSize - 2 * boundsBorder,
2
);
parameters.context.fill();
staticComp.drawSpriteOnBoundsClipped(parameters, staticComp.getBlueprintSprite(), 0);
}
parameters.context.globalAlpha = 1;
}
}
}
@ -322,15 +316,8 @@ export class HUDMassSelector extends BaseHUDPart {
this.selectedUids.forEach(uid => {
const entity = this.root.entityMgr.findByUid(uid);
const staticComp = entity.components.StaticMapEntity;
const bounds = staticComp.getTileSpaceBounds();
parameters.context.beginRoundedRect(
bounds.x * globalConfig.tileSize + boundsBorder,
bounds.y * globalConfig.tileSize + boundsBorder,
bounds.w * globalConfig.tileSize - 2 * boundsBorder,
bounds.h * globalConfig.tileSize - 2 * boundsBorder,
2
);
parameters.context.fill();
staticComp.drawSpriteOnBoundsClipped(parameters, staticComp.getBlueprintSprite(), 0);
});
}
}

View File

@ -11,6 +11,7 @@ import { MetaComparatorBuilding } from "../../buildings/comparator";
import { MetaReaderBuilding } from "../../buildings/reader";
import { MetaFilterBuilding } from "../../buildings/filter";
import { MetaDisplayBuilding } from "../../buildings/display";
import { MetaWirelessDisplayBuilding } from "../../buildings/wireless_display";
import { MetaStorageBuilding } from "../../buildings/storage";
export class HUDWiresToolbar extends HUDBaseToolbar {
@ -32,6 +33,7 @@ export class HUDWiresToolbar extends HUDBaseToolbar {
MetaLeverBuilding,
MetaFilterBuilding,
MetaDisplayBuilding,
MetaWirelessDisplayBuilding,
],
visibilityCondition: () =>
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "wires",

View File

@ -65,6 +65,7 @@ export const KEYMAPPINGS = {
lever: { keyCode: key("I") },
filter: { keyCode: key("O") },
display: { keyCode: key("P") },
wireless_display: { keyCode: key("K") },
// Wires toolbar
wire: { keyCode: key("1") },

View File

@ -193,6 +193,9 @@ export class GameLogic {
* @param {enumDirection} param0.edge The edge to check for
*/
computeWireEdgeStatus({ wireVariant, tile, edge }) {
/**
* @type {Vector}
*/
const offset = enumDirectionToVector[edge];
const targetTile = tile.add(offset);
@ -240,10 +243,10 @@ export class GameLogic {
const targetStaticComp = targetEntity.components.StaticMapEntity;
// Check if its a crossing
// Check if its a tunnel
const wireTunnelComp = targetEntity.components.WireTunnel;
if (wireTunnelComp) {
return true;
return wireTunnelComp.CanConnectWorld(targetStaticComp, offset);
}
// Check if its a wire

View File

@ -68,6 +68,7 @@ export class MapChunkView extends MapChunk {
systems.staticMapEntities.drawChunk(parameters, this);
systems.lever.drawChunk(parameters, this);
systems.display.drawChunk(parameters, this);
systems.wirelessDisplay.drawChunk(parameters, this);
systems.storage.drawChunk(parameters, this);
systems.itemProcessorOverlays.drawChunk(parameters, this);
}

View File

@ -199,7 +199,7 @@ export class MetaBuilding {
* @param {number} param0.rotationVariant Rotation variant
* @param {string} param0.variant
*/
createEntity({ root, origin, rotation, originalRotation, rotationVariant, variant }) {
createEntity({ root, origin, rotation, originalRotation, rotationVariant, variant, wireless_code }) {
const entity = new Entity(root);
entity.layer = this.getLayer();
entity.addComponent(
@ -213,6 +213,11 @@ export class MetaBuilding {
);
this.setupEntityComponents(entity, root);
this.updateVariants(entity, rotationVariant, variant);
if (entity.components.WirelessDisplay && wireless_code) {
if (!entity.components.WirelessCode) {
entity.components.WirelessCode = wireless_code;
}
}
return entity;
}

View File

@ -26,6 +26,7 @@ import { enumUndergroundBeltVariants, MetaUndergroundBeltBuilding } from "./buil
import { enumVirtualProcessorVariants, MetaVirtualProcessorBuilding } from "./buildings/virtual_processor";
import { MetaWireBuilding } from "./buildings/wire";
import { MetaWireTunnelBuilding } from "./buildings/wire_tunnel";
import { MetaWirelessDisplayBuilding, enumWirelessDisplayVariants } from "./buildings/wireless_display";
import { buildBuildingCodeCache, gBuildingVariants, registerBuildingVariant } from "./building_codes";
import { enumWireVariant } from "./components/wire";
import { KEYMAPPINGS } from "./key_action_mapper";
@ -59,6 +60,7 @@ export function initMetaBuildingRegistry() {
gMetaBuildingRegistry.register(MetaAnalyzerBuilding);
gMetaBuildingRegistry.register(MetaComparatorBuilding);
gMetaBuildingRegistry.register(MetaItemProducerBuilding);
gMetaBuildingRegistry.register(MetaWirelessDisplayBuilding);
// Belt
registerBuildingVariant(1, MetaBeltBuilding, defaultBuildingVariant, 0);
@ -121,7 +123,7 @@ export function initMetaBuildingRegistry() {
registerBuildingVariant(52, MetaWireBuilding, enumWireVariant.second, 0);
registerBuildingVariant(53, MetaWireBuilding, enumWireVariant.second, 1);
registerBuildingVariant(54, MetaWireBuilding, enumWireVariant.second, 2);
registerBuildingVariant(55, MetaWireBuilding, enumWireVariant.second, 3);
registerBuildingVariant(55, MetaWireBuilding, enumWireVariant.second, 3);
// Constant signal
registerBuildingVariant(31, MetaConstantSignalBuilding);
@ -165,6 +167,10 @@ export function initMetaBuildingRegistry() {
// Item producer
registerBuildingVariant(61, MetaItemProducerBuilding);
// Wireless Display
registerBuildingVariant(62, MetaWirelessDisplayBuilding);
registerBuildingVariant(63, MetaWirelessDisplayBuilding, enumWirelessDisplayVariants.remote_control);
// Propagate instances
for (const key in gBuildingVariants) {
gBuildingVariants[key].metaInstance = gMetaBuildingRegistry.findByClass(

View File

@ -99,7 +99,6 @@ export class ConstantSignalSystem extends GameSystemWithFilter {
}
if (itemInput.chosenItem) {
console.log(itemInput.chosenItem);
constantComp.signal = itemInput.chosenItem;
} else {
constantComp.signal = this.parseSignalCode(signalValueInput.getValue());

View File

@ -1,6 +1,6 @@
import { globalConfig } from "../../core/config";
import { Loader } from "../../core/loader";
import { smoothPulse } from "../../core/utils";
import { round1DigitLocalized, smoothPulse } from "../../core/utils";
import { enumItemProcessorRequirements, enumItemProcessorTypes } from "../components/item_processor";
import { Entity } from "../entity";
import { GameSystem } from "../game_system";
@ -92,7 +92,7 @@ export class ItemProcessorOverlaysSystem extends GameSystem {
parameters.context.textAlign = "center";
parameters.context.font = "bold 10px GameFont";
parameters.context.fillText(
"" + Math.round(readerComp.lastThroughput * 10) / 10,
round1DigitLocalized(readerComp.lastThroughput),
(staticComp.origin.x + 0.5) * globalConfig.tileSize,
(staticComp.origin.y + 0.62) * globalConfig.tileSize
);

View File

@ -316,6 +316,11 @@ export class WireSystem extends GameSystemWithFilter {
}
}
const tunnelComp = nextEntity.components.WireTunnel;
if (tunnelComp) {
//const outputDir = tunnelComp.GetOutputDirection(staticComp, offset);
}
if (newSearchTile) {
// Find new surrounding wire targets
const newTargets = this.findSurroundingWireTargets(
@ -364,7 +369,7 @@ export class WireSystem extends GameSystemWithFilter {
* @param {Vector} initialTile
* @param {Array<enumDirection>} directions
* @param {WireNetwork} network
* @param {enumWireVariant=} variantMask Only accept connections to this mask
* @param {enumWireVariant} variantMask Only accept connections to this mask
* @returns {Array<any>}
*/
findSurroundingWireTargets(initialTile, directions, network, variantMask = null) {
@ -386,9 +391,6 @@ export class WireSystem extends GameSystemWithFilter {
const offset = enumDirectionToVector[direction];
const initialSearchTile = initialTile.add(offset);
// Store which tunnels we already visited to avoid infinite loops
const visitedTunnels = new Set();
// First, find the initial connected entities
const initialContents = this.root.map.getLayersContentsMultipleXY(
initialSearchTile.x,
@ -396,17 +398,18 @@ export class WireSystem extends GameSystemWithFilter {
);
// Link the initial tile to the initial entities, since it may change
/** @type {Array<{entity: Entity, tile: Vector}>} */
/** @type {Array<{entity: Entity, tile: Vector, dir: Vector}>} */
const contents = [];
for (let j = 0; j < initialContents.length; ++j) {
contents.push({
entity: initialContents[j],
tile: initialSearchTile,
dir: offset,
});
}
for (let k = 0; k < contents.length; ++k) {
const { entity, tile } = contents[k];
const { entity, tile, dir } = contents[k];
const wireComp = entity.components.Wire;
// Check for wire
@ -438,8 +441,17 @@ export class WireSystem extends GameSystemWithFilter {
}
// Check if the direction (inverted) matches
const pinDirection = staticComp.localDirectionToWorld(slot.direction);
if (pinDirection !== enumInvertedDirections[direction]) {
// const pinDirection = staticComp.localDirectionToWorld(slot.direction);
// if (pinDirection !== enumInvertedDirections[direction]) {
// continue;
// }
// /**
// * @type {Vector}
// */
const worldDir = staticComp.localDirectionToWorld(slot.direction);
const invDir = enumInvertedDirections[worldDir];
const pinDirection = enumDirectionToVector[invDir];
if (!pinDirection.equals(dir)) {
continue;
}
@ -458,14 +470,20 @@ export class WireSystem extends GameSystemWithFilter {
// Check if it's a tunnel, if so, go to the forwarded item
const tunnelComp = entity.components.WireTunnel;
if (tunnelComp) {
if (visitedTunnels.has(entity.uid)) {
continue;
}
const staticComp = entity.components.StaticMapEntity;
//const localDir = staticComp.worldToLocalTile(tile.sub(offset));
//staticComp.localDirectionToWorld();
const outputDir = tunnelComp.GetOutputDirection(staticComp, dir);
if (!outputDir) {
continue;
}
const forwardedTile = staticComp.origin.add(outputDir);
//TODO: Alter to Allow for different tunnel Types
// Compute where this tunnel connects to
const forwardedTile = staticComp.origin.add(offset);
//const forwardedTile = staticComp.origin.add(offset);
VERBOSE_WIRES &&
logger.log(
" Found tunnel",
@ -487,6 +505,7 @@ export class WireSystem extends GameSystemWithFilter {
contents.push({
entity: connectedContents[h],
tile: forwardedTile,
dir: outputDir,
});
}
@ -497,9 +516,6 @@ export class WireSystem extends GameSystemWithFilter {
if (network.tunnels.indexOf(entity) < 0) {
network.tunnels.push(entity);
}
// Remember this tunnel
visitedTunnels.add(entity.uid);
}
}
}

View File

@ -189,9 +189,10 @@ export class WiredPinsSystem extends GameSystemWithFilter {
);
if (staticComp.getMetaBuilding().getRenderPins()) {
this.sprite = this.pinSprites[slot.type];
drawRotatedSprite({
parameters,
sprite: this.pinSprites[slot.type],
sprite: this.sprite,
x: worldPos.x,
y: worldPos.y,
angle: effectiveRotation,

View File

@ -0,0 +1,273 @@
import { globalConfig } from "../../core/config";
import { Loader } from "../../core/loader";
import { BaseItem } from "../base_item";
import { enumColors } from "../colors";
import { WirelessDisplayComponent } from "../components/wireless_display";
import { GameSystemWithFilter } from "../game_system_with_filter";
import { isTrueItem } from "../items/boolean_item";
import { ColorItem, COLOR_ITEM_SINGLETONS } from "../items/color_item";
import { MapChunkView } from "../map_chunk_view";
import { THIRDPARTY_URLS } from "../../core/config";
import { DialogWithForm } from "../../core/modal_dialog_elements";
import { FormElementInput, FormElementItemChooser } from "../../core/modal_dialog_forms";
import { fillInLinkIntoTranslation } from "../../core/utils";
import { T } from "../../translations";
import { Entity } from "../entity";
import { WirelessCodeComponent } from "../components/wireless_code";
import { THEME} from "../theme";
export class WirelessDisplaySystem extends GameSystemWithFilter {
constructor(root) {
super(root, [WirelessDisplayComponent]);
this.root.signals.entityManuallyPlaced.add(this.channelSignalValue, this);
/** @type {Object<string, import("../../core/draw_utils").AtlasSprite>} */
this.displaySprites = {};
for (const colorId in enumColors) {
if (colorId === enumColors.uncolored) {
continue;
}
this.displaySprites[colorId] = Loader.getSprite("sprites/wires/display/" + colorId + ".png");
}
this.wirelessMachineList = {};
this.displayNumber = 0;
this.entityCount = 0;
}
update() {
if (this.entityCount != this.allEntities.length) {
for (let i = 0; i < this.allEntities.length; i++) {
const entity = this.allEntities[i];
if (entity.components.WirelessDisplay && entity.components.WiredPins && entity.components.WirelessCode && !this.wirelessMachineList[entity.components.WirelessCode]) {
this.wirelessMachineList[entity.components.WirelessCode["wireless_code"]] = entity;
}
}
this.entityCount = this.allEntities.length;
}
const mousePos = this.root.app.mousePosition;
}
/**
* Asks the entity to enter a valid signal code
* @param {Entity} entity
*/
channelSignalValue(entity) {
if (entity.components.WirelessDisplay) {
// Ok, query, but also save the uid because it could get stale
const uid = entity.uid;
const signalValueInput = new FormElementInput({
id: "channelValue",
label: fillInLinkIntoTranslation(T.dialogs.editChannel.descShortKey, THIRDPARTY_URLS.shapeViewer),
placeholder: "",
defaultValue: "",
validator: val => val,
});
const channeldialog = new DialogWithForm({
app: this.root.app,
title: T.dialogs.editChannel.title,
desc: T.dialogs.editChannel.descItems,
formElements: [signalValueInput],
buttons: ["cancel:bad:escape", "ok:good:enter"],
closeButton: false,
});
this.root.hud.parts.dialogs.internalShowDialog(channeldialog);
// When confirmed, set the signal
const closeHandler = () => {
if (!this.root || !this.root.entityMgr) {
// Game got stopped
return;
}
const entityRef = this.root.entityMgr.findByUid(uid, false);
if (!entityRef) {
// outdated
return;
}
const constantComp = entityRef.components.WirelessDisplay;
if (!constantComp) {
// no longer interesting
return;
}
if (signalValueInput.getValue() && !entity.components.WiredPins) {
entity.addComponent(new WirelessCodeComponent(signalValueInput.getValue()));
} else if (signalValueInput.getValue() && entity.components.WiredPins) {
entity.addComponent(new WirelessCodeComponent(signalValueInput.getValue()));
this.wirelessMachineList[entity.components.WirelessCode["wireless_code"]] = entity;
}
};
channeldialog.buttonSignals.ok.add(closeHandler);
channeldialog.valueChosen.add(closeHandler);
// When cancelled, destroy the entity again
channeldialog.buttonSignals.cancel.add(() => {
if (!this.root || !this.root.entityMgr) {
// Game got stopped
return;
}
const entityRef = this.root.entityMgr.findByUid(uid, false);
if (!entityRef) {
// outdated
return;
}
const constantComp = entityRef.components.WirelessDisplay;
if (!constantComp) {
// no longer interesting
return;
}
this.root.logic.tryDeleteBuilding(entityRef);
});
}
}
/**
* Returns the color / value a display should show
* @param {BaseItem} value
* @returns {BaseItem}
*/
getDisplayItem(value) {
if (!value) {
return null;
}
switch (value.getItemType()) {
case "boolean": {
return isTrueItem(value) ? COLOR_ITEM_SINGLETONS[enumColors.white] : null;
}
case "color": {
const item = /**@type {ColorItem} */ (value);
return item.color === enumColors.uncolored ? null : item;
}
case "shape": {
return value;
}
default:
assertAlways(false, "Unknown item type: " + value.getItemType());
}
}
/**
* Computes the color below the current tile
* @returns {number}
*/
computeColorBelowTile() {
const mousePosition = this.root.app.mousePosition;
if (!mousePosition) {
// Not on screen
return null;
}
const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile, "regular");
if (contents && contents.components.WirelessDisplay) {
// We hovered a lower layer, show the color there
if (contents && contents.components.WirelessCode && contents.components.WirelessCode.wireless_code) {
return contents.components.WirelessCode.wireless_code;
}
}
return null;
}
/**
* Draws Text Storked
* @param {string} text
* @param {number} y
* @param {number} x
* @param {number=} width
*/
drawStroked(ctx, text, x, y, width = undefined) {
ctx.font = '15px Sans-serif';
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.miterLimit=2
ctx.strokeText(text, x, y, width);
ctx.fillStyle = 'white';
ctx.fillText(text, x, y, width);
}
/**
* Draws a given chunk
* @param {import("../../core/draw_utils").DrawParameters} parameters
* @param {MapChunkView} chunk
*/
drawChunk(parameters, chunk) {
const contents = chunk.containedEntitiesByLayer.regular;
for (let i = 0; i < contents.length; ++i) {
const entity_a = contents[i];
if (entity_a && entity_a.components.WirelessDisplay) {
const below = this.computeColorBelowTile();
if (below) {
// We have something below our tile
const mousePosition = this.root.app.mousePosition;
const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace().toWorldSpace();
this.drawStroked(parameters.context, below.toString(), worldPos.x + 5, worldPos.y + 5)
parameters.context.strokeStyle = THEME.map.colorBlindPickerTile;
parameters.context.beginPath();
parameters.context.rect(tile.x, tile.y, globalConfig.tileSize, globalConfig.tileSize);
parameters.context.stroke();
}
if (!entity_a.components.WiredPins) {
const entity_b = this.wirelessMachineList[entity_a.components.WirelessCode["wireless_code"]];
if (entity_b) {
if (!this.allEntities.includes(entity_b)) {
this.wirelessMachineList[entity_b] = undefined;
return;
}
const origin = entity_a.components.StaticMapEntity.origin;
const pinsComp = entity_b.components.WiredPins;
const network = pinsComp.slots[0].linkedNetwork;
if (!network) {
continue;
}
const value = this.getDisplayItem(network.currentValue);
if (!value) {
continue;
}
if (value.getItemType()) {
if (value.getItemType() === "color") {
this.displaySprites[/** @type {ColorItem} */ (value).color].drawCachedCentered(
parameters,
(origin.x + 0.5) * globalConfig.tileSize,
(origin.y + 0.5) * globalConfig.tileSize,
globalConfig.tileSize
);
} else if (value.getItemType() === "shape") {
value.drawItemCenteredClipped(
(origin.x + 0.5) * globalConfig.tileSize,
(origin.y + 0.5) * globalConfig.tileSize,
parameters,
30
);
}
}
}
}
}
}
}
}

View File

@ -3,7 +3,7 @@
#
# Contributing:
#
# If you want to contribute, please make a pull request on this respository
# If you want to contribute, please make a pull request on this repository
# and I will have a look.
#
# Placeholders:
@ -30,9 +30,11 @@ steamPage:
intro: >-
Do you like automation games? Then you are in the right place!
shapez.io is a relaxed game in which you have to build factories for the automated production of geometric shapes. As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
shapez.io is a relaxed game in which you have to build factories for the automated production of geometric shapes. As the level increases, the shapes become more and more complex, and you
have to spread out on the infinite map.
And as if that wasn't enough, you also have to produce exponentially more to satisfy the demands - the only thing that helps is scaling! While you only have to process shapes at the beginning, you will later have to color them - by extracting and mixing colors!
And as if that wasn't enough, you also have to produce exponentially more to satisfy the demands - the only thing that helps is scaling! While you only have to process shapes at the
beginning, you will later have to color them - by extracting and mixing colors!
Buying the game on Steam gives you access to the full version, but you can also play a demo at shapez.io first and decide later!
@ -40,7 +42,7 @@ steamPage:
advantages:
- <b>12 New Levels</b> for a total of 26 levels
- <b>18 New Buildings</b> for a fully automated factory!
- <b>20 Upgrade Tiers</b> for many hours of fun!
- <b>Unlimited Upgrade Tiers</b> for many hours of fun!
- <b>Wires Update</b> for an entirely new dimension!
- <b>Dark Mode</b>!
- Unlimited Savegames
@ -79,7 +81,7 @@ global:
# How big numbers are rendered, e.g. "10,000"
thousandsDivider: ","
# What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4"
# What symbol to use to separate the integer part from the fractional part of a number, e.g. "0.4"
decimalSeparator: "."
# The suffix for large numbers, e.g. 1.3k, 400.2M, etc.
@ -255,6 +257,12 @@ dialogs:
titleEdit: Edit Marker
desc: Give it a meaningful name, you can also include a <strong>short key</strong> of a shape (Which you can generate <link>here</link>)
editChannel:
title: Set Channel
descItems: >-
Enter used <strong>channel name</strong>
descShortKey: or enter new <strong>channel name</strong>
editSignal:
title: Set Signal
descItems: >-
@ -402,7 +410,9 @@ ingame:
waypoints:
waypoints: Markers
hub: HUB
description: Left-click a marker to jump to it, right-click to delete it.<br><br>Press <keybinding> to create a marker from the current view, or <strong>right-click</strong> to create a marker at the selected location.
description: >-
Left-click a marker to jump to it, right-click to delete it.<br><br>Press <keybinding> to create a marker from the current view, or <strong>right-click</strong> to create a marker at the
selected location.
creationSuccessNotification: Marker has been created.
# Shape viewer
@ -420,7 +430,8 @@ ingame:
Connect the extractor with a <strong>conveyor belt</strong> to your hub!<br><br>Tip: <strong>Click and drag</strong> the belt with your mouse!
1_3_expand: >-
This is <strong>NOT</strong> an idle game! Build more extractors and belts to finish the goal quicker.<br><br>Tip: Hold <strong>SHIFT</strong> to place multiple extractors, and use <strong>R</strong> to rotate them.
This is <strong>NOT</strong> an idle game! Build more extractors and belts to finish the goal quicker.<br><br>Tip: Hold <strong>SHIFT</strong> to place multiple extractors, and use
<strong>R</strong> to rotate them.
2_1_place_cutter: >-
Now place a <strong>Cutter</strong> to cut the circles in two halves!<br><br>
@ -482,7 +493,7 @@ ingame:
desc: As many as your heart desires!
upgrades:
title: 20 Upgrade Tiers
title: Upgrade Tiers
desc: This demo version has only 5!
markers:
@ -499,7 +510,7 @@ ingame:
support:
title: Support me
desc: I develop it in my spare time!
desc: I develop the game in my spare time!
# All shop upgrades
shopUpgrades:
@ -581,13 +592,13 @@ buildings:
rotater:
default:
name: &rotater Rotate
name: &rotater Rotator
description: Rotates shapes clockwise by 90 degrees.
ccw:
name: Rotate (CCW)
name: Rotator (CCW)
description: Rotates shapes counter-clockwise by 90 degrees.
rotate180:
name: Rotate (180°)
name: Rotator (180°)
description: Rotates shapes by 180 degrees.
stacker:
@ -636,10 +647,23 @@ buildings:
name: *wire
description: *wire_desc
third:
name: *wire
description: *wire_desc
wire_tunnel:
default:
name: &wire_tunnel Wire Crossing
name: &wire_tunnel Wire Tunnel
description: Allows two wires to cross without connecting to each other.
elbow:
name: Elbow Tunnel
description: Allows a wire to turn a corner without connecting to anything else
straight:
name: Straight tunnel
description: Allows a wire to go straight without connecting to anything else
double_elbow:
name: Double Elbow Tunnel
description: Allows two wires to turn corners without connecting to each other.
constant_signal:
default:
@ -684,6 +708,14 @@ buildings:
name: &display Display
description: Connect a signal to show it on the display - It can be a shape, color or boolean.
wireless_display:
default:
name: &wireless_display Wireless Display
description: Connect to a channel and if channel connects, it receives the signal coming from Remote Control - Signal can be a shape, color or boolean.
remote_control:
name: Remote Control
description: Connect to a channel and if channel connects, it emits signal to Wireless Control - Signal can be a shape, color or boolean.
reader:
default:
name: &reader Belt Reader
@ -705,7 +737,7 @@ buildings:
description: Virtually cuts the shape into two halves.
rotater:
name: Virtual Rotater
name: Virtual Rotator
description: Virtually rotates the shape clockwise.
unstacker:
@ -729,16 +761,19 @@ storyRewards:
# Those are the rewards gained from completing the store
reward_cutter_and_trash:
title: Cutting Shapes
desc: You just unlocked the <strong>cutter</strong>, which cuts shapes in half from top to bottom <strong>regardless of its orientation</strong>!<br><br>Be sure to get rid of the waste, or otherwise <strong>it will clog and stall</strong> - For this purpose I have given you the <strong>trash</strong>, which destroys everything you put into it!
desc: >-
You just unlocked the <strong>cutter</strong>, which cuts shapes in half from top to bottom <strong>regardless of its orientation</strong>!<br><br>Be sure to get rid of the waste, or
otherwise <strong>it will clog and stall</strong> - For this purpose I have given you the <strong>trash</strong>, which destroys everything you put into it!
reward_rotater:
title: Rotating
desc: The <strong>rotater</strong> has been unlocked! It rotates shapes clockwise by 90 degrees.
desc: The <strong>rotator</strong> has been unlocked! It rotates shapes clockwise by 90 degrees.
reward_painter:
title: Painting
desc: >-
The <strong>painter</strong> has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!<br><br>PS: If you are colorblind, there is a <strong>colorblind mode</strong> in the settings!
The <strong>painter</strong> has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!<br><br>PS: If you are
colorblind, there is a <strong>colorblind mode</strong> in the settings!
reward_mixer:
title: Color Mixing
@ -746,7 +781,9 @@ storyRewards:
reward_stacker:
title: Stacker
desc: You can now combine shapes with the <strong>stacker</strong>! Both inputs are combined, and if they can be put next to each other, they will be <strong>fused</strong>. If not, the right input is <strong>stacked on top</strong> of the left input!
desc: >-
You can now combine shapes with the <strong>stacker</strong>! Both inputs are combined, and if they can be put next to each other, they will be <strong>fused</strong>. If not, the right
input is <strong>stacked on top</strong> of the left input!
reward_balancer:
title: Balancer
@ -758,7 +795,9 @@ storyRewards:
reward_rotater_ccw:
title: CCW Rotating
desc: You have unlocked a variant of the <strong>rotater</strong> - It allows you to rotate shapes counter-clockwise! To build it, select the rotater and <strong>press 'T' to cycle through its variants</strong>!
desc: >-
You have unlocked a variant of the <strong>rotator</strong> - It allows you to rotate shapes counter-clockwise! To build it, select the rotator and
<strong>press 'T' to cycle through its variants</strong>!
reward_miner_chainable:
title: Chaining Extractor
@ -791,7 +830,9 @@ storyRewards:
reward_painter_double:
title: Double Painting
desc: You have unlocked a variant of the <strong>painter</strong> - It works similar to the regular painter but processes <strong>two shapes at once</strong>, consuming just one color instead of two!
desc: >-
You have unlocked a variant of the <strong>painter</strong> - It works similar to the regular painter but processes <strong>two shapes at once</strong>, consuming just one color
instead of two!
reward_storage:
title: Storage
@ -801,11 +842,13 @@ storyRewards:
reward_blueprints:
title: Blueprints
desc: You can now <strong>copy and paste</strong> parts of your factory! Select an area (Hold CTRL, then drag with your mouse), and press 'C' to copy it.<br><br>Pasting it is <strong>not free</strong>, you need to produce <strong>blueprint shapes</strong> to afford it! (Those you just delivered).
desc: >-
You can now <strong>copy and paste</strong> parts of your factory! Select an area (Hold CTRL, then drag with your mouse), and press 'C' to copy it.<br><br>Pasting it is
<strong>not free</strong>, you need to produce <strong>blueprint shapes</strong> to afford it! (Those you just delivered).
reward_rotater_180:
title: Rotater (180°)
desc: You just unlocked the 180 degrees <strong>rotater</strong>! - It allows you to rotate a shape by 180 degress (Surprise! :D)
title: Rotator (180°)
desc: You just unlocked the 180 degrees <strong>rotator</strong>! - It allows you to rotate a shape by 180 degrees (Surprise! :D)
reward_wires_painter_and_levers:
title: >-
@ -846,18 +889,19 @@ storyRewards:
title: Virtual Processing
desc: >-
I just gave a whole bunch of new buildings which allow you to <strong>simulate the processing of shapes</strong>!<br><br>
You can now simulate a cutter, rotater, stacker and more on the wires layer!
You can now simulate a cutter, rotator, stacker and more on the wires layer!
With this you now have three options to continue the game:<br><br>
- Build an <strong>automated machine</strong> to create any possible shape requested by the HUB (I recommend to try it!).<br><br>
- Build something cool with wires.<br><br>
- Continue to play regulary.<br><br>
- Continue to play normally.<br><br>
Whatever you choose, remember to have fun!
# Special reward, which is shown when there is no reward actually
no_reward:
title: Next level
desc: >-
This level gave you no reward, but the next one will! <br><br> PS: Better not destroy your existing factory - You'll need <strong>all</strong> those shapes later to <strong>unlock upgrades</strong>!
This level gave you no reward, but the next one will! <br><br> PS: Better not destroy your existing factory - You'll need <strong>all</strong> those shapes later to
<strong>unlock upgrades</strong>!
no_reward_freeplay:
title: Next level
@ -986,7 +1030,8 @@ settings:
refreshRate:
title: Tick Rate
description: >-
This determines how many game ticks happen per second. In general, a higher tick rate means better precision but also worse performance. On lower tickrates, the throughput may not be exact.
This determines how many game ticks happen per second. In general, a higher tick rate means better precision but also worse performance. On lower tickrates, the throughput may not be
exact.
alwaysMultiplace:
title: Multiplace
@ -1037,7 +1082,8 @@ settings:
clearCursorOnDeleteWhilePlacing:
title: Clear Cursor on Right Click
description: >-
Enabled by default, clears the cursor whenever you right click while you have a building selected for placement. If disabled, you can delete buildings by right-clicking while placing a building.
Enabled by default, clears the cursor whenever you right click while you have a building selected for placement. If disabled, you can delete buildings by right-clicking while placing
a building.
lowQualityTextures:
title: Low quality textures (Ugly)
@ -1132,6 +1178,7 @@ keybindings:
filter: *filter
wire_tunnel: *wire_tunnel
display: *display
wireless_display: *wireless_display
reader: *reader
virtual_processor: *virtual_processor
transistor: *transistor
@ -1211,7 +1258,7 @@ tips:
- Cutters always cut vertically, regardless of their orientation.
- The storage buffer prioritises the left output.
- Invest time to build repeatable designs - it's worth it!
- Holding <b>SHIFT</b> lets you place multiple buildings in one click.
- Holding <b>SHIFT</b> lets you place multiple buildings at a time.
- You can hold <b>ALT</b> to invert the direction of placed belts.
- Efficiency is key!
- Shape patches that are further away from the hub are more complex.