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

Add virtual shape processing buildings

This commit is contained in:
tobspr 2020-08-18 20:02:39 +02:00
parent 1ff76e0b2e
commit 296b76bf11
28 changed files with 6929 additions and 6368 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 KiB

After

Width:  |  Height:  |  Size: 254 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 567 KiB

After

Width:  |  Height:  |  Size: 601 KiB

View File

@ -277,6 +277,7 @@
<key type="filename">sprites/blueprints/underground_belt_entry.png</key> <key type="filename">sprites/blueprints/underground_belt_entry.png</key>
<key type="filename">sprites/blueprints/underground_belt_exit-tier2.png</key> <key type="filename">sprites/blueprints/underground_belt_exit-tier2.png</key>
<key type="filename">sprites/blueprints/underground_belt_exit.png</key> <key type="filename">sprites/blueprints/underground_belt_exit.png</key>
<key type="filename">sprites/blueprints/wire_tunnel-coating.png</key>
<key type="filename">sprites/blueprints/wire_tunnel.png</key> <key type="filename">sprites/blueprints/wire_tunnel.png</key>
<key type="filename">sprites/buildings/constant_signal.png</key> <key type="filename">sprites/buildings/constant_signal.png</key>
<key type="filename">sprites/buildings/display.png</key> <key type="filename">sprites/buildings/display.png</key>
@ -295,6 +296,7 @@
<key type="filename">sprites/buildings/underground_belt_entry.png</key> <key type="filename">sprites/buildings/underground_belt_entry.png</key>
<key type="filename">sprites/buildings/underground_belt_exit-tier2.png</key> <key type="filename">sprites/buildings/underground_belt_exit-tier2.png</key>
<key type="filename">sprites/buildings/underground_belt_exit.png</key> <key type="filename">sprites/buildings/underground_belt_exit.png</key>
<key type="filename">sprites/buildings/wire_tunnel-coating.png</key>
<key type="filename">sprites/buildings/wire_tunnel.png</key> <key type="filename">sprites/buildings/wire_tunnel.png</key>
<key type="filename">sprites/wires/lever_on.png</key> <key type="filename">sprites/wires/lever_on.png</key>
<key type="filename">sprites/wires/sets/color_cross.png</key> <key type="filename">sprites/wires/sets/color_cross.png</key>
@ -533,6 +535,8 @@
</struct> </struct>
<key type="filename">sprites/wires/boolean_false.png</key> <key type="filename">sprites/wires/boolean_false.png</key>
<key type="filename">sprites/wires/boolean_true.png</key> <key type="filename">sprites/wires/boolean_true.png</key>
<key type="filename">sprites/wires/network_conflict.png</key>
<key type="filename">sprites/wires/network_empty.png</key>
<key type="filename">sprites/wires/wires_preview.png</key> <key type="filename">sprites/wires/wires_preview.png</key>
<struct type="IndividualSpriteSettings"> <struct type="IndividualSpriteSettings">
<key>pivotPoint</key> <key>pivotPoint</key>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,38 +1,38 @@
$buildings: belt, cutter, miner, mixer, painter, rotater, splitter, stacker, trash, underground_belt, wire, $buildings: belt, cutter, miner, mixer, painter, rotater, splitter, stacker, trash, underground_belt, wire,
constant_signal, logic_gate, lever, filter, wire_tunnel, display; constant_signal, logic_gate, lever, filter, wire_tunnel, display, virtual_processor;
@each $building in $buildings { @each $building in $buildings {
[data-icon="building_icons/#{$building}.png"] { [data-icon="building_icons/#{$building}.png"] {
background-image: uiResource("res/ui/building_icons/#{$building}.png") !important; background-image: uiResource("res/ui/building_icons/#{$building}.png") !important;
} }
} }
$buildingsAndVariants: belt, splitter, splitter-compact, splitter-compact-inverse, underground_belt, $buildingsAndVariants: belt, splitter, splitter-compact, splitter-compact-inverse, underground_belt,
underground_belt-tier2, miner, miner-chainable, cutter, cutter-quad, rotater, rotater-ccw, rotater-fl, underground_belt-tier2, miner, miner-chainable, cutter, cutter-quad, rotater, rotater-ccw, rotater-fl,
stacker, mixer, painter, painter-double, painter-quad, trash, trash-storage; stacker, mixer, painter, painter-double, painter-quad, trash, trash-storage;
@each $building in $buildingsAndVariants { @each $building in $buildingsAndVariants {
[data-icon="building_tutorials/#{$building}.png"] { [data-icon="building_tutorials/#{$building}.png"] {
background-image: uiResource("res/ui/building_tutorials/#{$building}.png") !important; background-image: uiResource("res/ui/building_tutorials/#{$building}.png") !important;
} }
} }
// Special case // Special case
[data-icon="building_tutorials/painter-mirrored.png"] { [data-icon="building_tutorials/painter-mirrored.png"] {
background-image: uiResource("res/ui/building_tutorials/painter.png") !important; background-image: uiResource("res/ui/building_tutorials/painter.png") !important;
} }
$icons: notification_saved, notification_success, notification_upgrade; $icons: notification_saved, notification_success, notification_upgrade;
@each $icon in $icons { @each $icon in $icons {
[data-icon="icons/#{$icon}.png"] { [data-icon="icons/#{$icon}.png"] {
background-image: uiResource("res/ui/icons/#{$icon}.png") !important; background-image: uiResource("res/ui/icons/#{$icon}.png") !important;
} }
} }
$languages: en, de, cs, da, et, es-419, fr, it, pt-BR, sv, tr, el, ru, uk, zh-TW, zh-CN, nb, mt-MT, ar, nl, vi, $languages: en, de, cs, da, et, es-419, fr, it, pt-BR, sv, tr, el, ru, uk, zh-TW, zh-CN, nb, mt-MT, ar, nl, vi,
th, hu, pl, ja, kor, no, pt-PT; th, hu, pl, ja, kor, no, pt-PT;
@each $language in $languages { @each $language in $languages {
[data-languageicon="#{$language}"] { [data-languageicon="#{$language}"] {
background-image: uiResource("languages/#{$language}.svg") !important; background-image: uiResource("languages/#{$language}.svg") !important;
} }
} }

View File

@ -0,0 +1,151 @@
import { Vector, enumDirection } from "../../core/vector";
import { LogicGateComponent, enumLogicGateType } from "../components/logic_gate";
import { WiredPinsComponent, enumPinSlotType } from "../components/wired_pins";
import { Entity } from "../entity";
import { defaultBuildingVariant, MetaBuilding } from "../meta_building";
import { GameRoot } from "../root";
/** @enum {string} */
export const enumVirtualProcessorVariants = {
analyzer: "analyzer",
rotater: "rotater",
unstacker: "unstacker",
shapecompare: "shapecompare",
};
/** @enum {string} */
export const enumVariantToGate = {
[defaultBuildingVariant]: enumLogicGateType.cutter,
[enumVirtualProcessorVariants.analyzer]: enumLogicGateType.analyzer,
[enumVirtualProcessorVariants.rotater]: enumLogicGateType.rotater,
[enumVirtualProcessorVariants.unstacker]: enumLogicGateType.unstacker,
[enumVirtualProcessorVariants.shapecompare]: enumLogicGateType.shapecompare,
};
export class MetaVirtualProcessorBuilding extends MetaBuilding {
constructor() {
super("virtual_processor");
}
getSilhouetteColor() {
return "#823cab";
}
/**
* @param {GameRoot} root
*/
getIsUnlocked(root) {
// @todo
return true;
}
/** @returns {"wires"} **/
getLayer() {
return "wires";
}
getDimensions() {
return new Vector(1, 1);
}
getAvailableVariants() {
return [
defaultBuildingVariant,
enumVirtualProcessorVariants.rotater,
enumVirtualProcessorVariants.unstacker,
enumVirtualProcessorVariants.analyzer,
enumVirtualProcessorVariants.shapecompare,
];
}
getRenderPins() {
// We already have it included
return false;
}
/**
*
* @param {Entity} entity
* @param {number} rotationVariant
*/
updateVariants(entity, rotationVariant, variant) {
const gateType = enumVariantToGate[variant];
entity.components.LogicGate.type = gateType;
const pinComp = entity.components.WiredPins;
switch (gateType) {
case enumLogicGateType.cutter:
case enumLogicGateType.analyzer:
case enumLogicGateType.unstacker: {
pinComp.setSlots([
{
pos: new Vector(0, 0),
direction: enumDirection.left,
type: enumPinSlotType.logicalEjector,
},
{
pos: new Vector(0, 0),
direction: enumDirection.right,
type: enumPinSlotType.logicalEjector,
},
{
pos: new Vector(0, 0),
direction: enumDirection.bottom,
type: enumPinSlotType.logicalAcceptor,
},
]);
break;
}
case enumLogicGateType.rotater: {
pinComp.setSlots([
{
pos: new Vector(0, 0),
direction: enumDirection.top,
type: enumPinSlotType.logicalEjector,
},
{
pos: new Vector(0, 0),
direction: enumDirection.bottom,
type: enumPinSlotType.logicalAcceptor,
},
]);
break;
}
case enumLogicGateType.shapecompare: {
pinComp.setSlots([
{
pos: new Vector(0, 0),
direction: enumDirection.top,
type: enumPinSlotType.logicalEjector,
},
{
pos: new Vector(0, 0),
direction: enumDirection.left,
type: enumPinSlotType.logicalAcceptor,
},
{
pos: new Vector(0, 0),
direction: enumDirection.right,
type: enumPinSlotType.logicalAcceptor,
},
]);
break;
}
default:
assertAlways("unknown logic gate type: " + gateType);
}
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
entity.addComponent(
new WiredPinsComponent({
slots: [],
})
);
entity.addComponent(new LogicGateComponent({}));
}
}

View File

@ -1,30 +1,36 @@
import { Component } from "../component"; import { Component } from "../component";
/** @enum {string} */ /** @enum {string} */
export const enumLogicGateType = { export const enumLogicGateType = {
and: "and", and: "and",
not: "not", not: "not",
xor: "xor", xor: "xor",
or: "or", or: "or",
transistor: "transistor", transistor: "transistor",
};
analyzer: "analyzer",
export class LogicGateComponent extends Component { rotater: "rotater",
static getId() { unstacker: "unstacker",
return "LogicGate"; cutter: "cutter",
} shapecompare: "shapecompare",
};
duplicateWithoutContents() {
return new LogicGateComponent({ type: this.type }); export class LogicGateComponent extends Component {
} static getId() {
return "LogicGate";
/** }
*
* @param {object} param0 duplicateWithoutContents() {
* @param {enumLogicGateType=} param0.type return new LogicGateComponent({ type: this.type });
*/ }
constructor({ type = enumLogicGateType.and }) {
super(); /**
this.type = type; *
} * @param {object} param0
} * @param {enumLogicGateType=} param0.type
*/
constructor({ type = enumLogicGateType.and }) {
super();
this.type = type;
}
}

View File

@ -1,25 +1,27 @@
import { HUDBaseToolbar } from "./base_toolbar"; import { HUDBaseToolbar } from "./base_toolbar";
import { MetaWireBuilding } from "../../buildings/wire"; import { MetaWireBuilding } from "../../buildings/wire";
import { MetaConstantSignalBuilding } from "../../buildings/constant_signal"; import { MetaConstantSignalBuilding } from "../../buildings/constant_signal";
import { MetaLogicGateBuilding } from "../../buildings/logic_gate"; import { MetaLogicGateBuilding } from "../../buildings/logic_gate";
import { MetaLeverBuilding } from "../../buildings/lever"; import { MetaLeverBuilding } from "../../buildings/lever";
import { MetaWireTunnelBuilding } from "../../buildings/wire_tunnel"; import { MetaWireTunnelBuilding } from "../../buildings/wire_tunnel";
import { MetaVirtualProcessorBuilding } from "../../buildings/virtual_processor";
const supportedBuildings = [
MetaWireBuilding, const supportedBuildings = [
MetaWireTunnelBuilding, MetaWireBuilding,
MetaConstantSignalBuilding, MetaWireTunnelBuilding,
MetaLogicGateBuilding, MetaConstantSignalBuilding,
MetaLeverBuilding, MetaLogicGateBuilding,
]; MetaLeverBuilding,
MetaVirtualProcessorBuilding,
export class HUDWiresToolbar extends HUDBaseToolbar { ];
constructor(root) {
super(root, { export class HUDWiresToolbar extends HUDBaseToolbar {
supportedBuildings, constructor(root) {
visibilityCondition: () => super(root, {
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "wires", supportedBuildings,
htmlElementId: "ingame_HUD_wires_toolbar", visibilityCondition: () =>
}); !this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "wires",
} htmlElementId: "ingame_HUD_wires_toolbar",
} });
}
}

View File

@ -1,456 +1,457 @@
/* typehints:start */ /* typehints:start */
import { GameRoot } from "./root"; import { GameRoot } from "./root";
import { InputReceiver } from "../core/input_receiver"; import { InputReceiver } from "../core/input_receiver";
import { Application } from "../application"; import { Application } from "../application";
/* typehints:end */ /* typehints:end */
import { Signal, STOP_PROPAGATION } from "../core/signal"; import { Signal, STOP_PROPAGATION } from "../core/signal";
import { IS_MOBILE } from "../core/config"; import { IS_MOBILE } from "../core/config";
import { T } from "../translations"; import { T } from "../translations";
function key(str) { function key(str) {
return str.toUpperCase().charCodeAt(0); return str.toUpperCase().charCodeAt(0);
} }
export const KEYMAPPINGS = { export const KEYMAPPINGS = {
general: { general: {
confirm: { keyCode: 13 }, // enter confirm: { keyCode: 13 }, // enter
back: { keyCode: 27, builtin: true }, // escape back: { keyCode: 27, builtin: true }, // escape
}, },
ingame: { ingame: {
menuOpenShop: { keyCode: key("F") }, menuOpenShop: { keyCode: key("F") },
menuOpenStats: { keyCode: key("G") }, menuOpenStats: { keyCode: key("G") },
menuClose: { keyCode: key("Q") }, menuClose: { keyCode: key("Q") },
toggleHud: { keyCode: 113 }, // F2 toggleHud: { keyCode: 113 }, // F2
exportScreenshot: { keyCode: 114 }, // F3PS exportScreenshot: { keyCode: 114 }, // F3PS
toggleFPSInfo: { keyCode: 115 }, // F4 toggleFPSInfo: { keyCode: 115 }, // F4
switchLayers: { keyCode: key("Y") }, switchLayers: { keyCode: key("Y") },
}, },
navigation: { navigation: {
mapMoveUp: { keyCode: key("W") }, mapMoveUp: { keyCode: key("W") },
mapMoveRight: { keyCode: key("D") }, mapMoveRight: { keyCode: key("D") },
mapMoveDown: { keyCode: key("S") }, mapMoveDown: { keyCode: key("S") },
mapMoveLeft: { keyCode: key("A") }, mapMoveLeft: { keyCode: key("A") },
mapMoveFaster: { keyCode: 16 }, //shift mapMoveFaster: { keyCode: 16 }, //shift
centerMap: { keyCode: 32 }, // SPACE centerMap: { keyCode: 32 }, // SPACE
mapZoomIn: { keyCode: 187, repeated: true }, // "+" mapZoomIn: { keyCode: 187, repeated: true }, // "+"
mapZoomOut: { keyCode: 189, repeated: true }, // "-" mapZoomOut: { keyCode: 189, repeated: true }, // "-"
createMarker: { keyCode: key("M") }, createMarker: { keyCode: key("M") },
}, },
buildings: { buildings: {
belt: { keyCode: key("1") }, belt: { keyCode: key("1") },
splitter: { keyCode: key("2") }, splitter: { keyCode: key("2") },
underground_belt: { keyCode: key("3") }, underground_belt: { keyCode: key("3") },
miner: { keyCode: key("4") }, miner: { keyCode: key("4") },
cutter: { keyCode: key("5") }, cutter: { keyCode: key("5") },
rotater: { keyCode: key("6") }, rotater: { keyCode: key("6") },
stacker: { keyCode: key("7") }, stacker: { keyCode: key("7") },
mixer: { keyCode: key("8") }, mixer: { keyCode: key("8") },
painter: { keyCode: key("9") }, painter: { keyCode: key("9") },
trash: { keyCode: key("0") }, trash: { keyCode: key("0") },
lever: { keyCode: key("L") }, lever: { keyCode: key("L") },
filter: { keyCode: key("B") }, filter: { keyCode: key("B") },
display: { keyCode: key("N") }, display: { keyCode: key("N") },
wire: { keyCode: key("1") }, wire: { keyCode: key("1") },
wire_tunnel: { keyCode: key("2") }, wire_tunnel: { keyCode: key("2") },
constant_signal: { keyCode: key("3") }, constant_signal: { keyCode: key("3") },
logic_gate: { keyCode: key("4") }, logic_gate: { keyCode: key("4") },
}, virtual_processor: { keyCode: key("5") },
},
placement: {
pipette: { keyCode: key("Q") }, placement: {
rotateWhilePlacing: { keyCode: key("R") }, pipette: { keyCode: key("Q") },
rotateInverseModifier: { keyCode: 16 }, // SHIFT rotateWhilePlacing: { keyCode: key("R") },
cycleBuildingVariants: { keyCode: key("T") }, rotateInverseModifier: { keyCode: 16 }, // SHIFT
cycleBuildings: { keyCode: 9 }, // TAB cycleBuildingVariants: { keyCode: key("T") },
switchDirectionLockSide: { keyCode: key("R") }, cycleBuildings: { keyCode: 9 }, // TAB
}, switchDirectionLockSide: { keyCode: key("R") },
},
massSelect: {
massSelectStart: { keyCode: 17 }, // CTRL massSelect: {
massSelectSelectMultiple: { keyCode: 16 }, // SHIFT massSelectStart: { keyCode: 17 }, // CTRL
massSelectCopy: { keyCode: key("C") }, massSelectSelectMultiple: { keyCode: 16 }, // SHIFT
massSelectCut: { keyCode: key("X") }, massSelectCopy: { keyCode: key("C") },
confirmMassDelete: { keyCode: 46 }, // DEL massSelectCut: { keyCode: key("X") },
pasteLastBlueprint: { keyCode: key("V") }, confirmMassDelete: { keyCode: 46 }, // DEL
}, pasteLastBlueprint: { keyCode: key("V") },
},
placementModifiers: {
lockBeltDirection: { keyCode: 16 }, // SHIFT placementModifiers: {
placementDisableAutoOrientation: { keyCode: 17 }, // CTRL lockBeltDirection: { keyCode: 16 }, // SHIFT
placeMultiple: { keyCode: 16 }, // SHIFT placementDisableAutoOrientation: { keyCode: 17 }, // CTRL
placeInverse: { keyCode: 18 }, // ALT placeMultiple: { keyCode: 16 }, // SHIFT
}, placeInverse: { keyCode: 18 }, // ALT
}; },
};
// Assign ids
for (const categoryId in KEYMAPPINGS) { // Assign ids
for (const mappingId in KEYMAPPINGS[categoryId]) { for (const categoryId in KEYMAPPINGS) {
KEYMAPPINGS[categoryId][mappingId].id = mappingId; for (const mappingId in KEYMAPPINGS[categoryId]) {
} KEYMAPPINGS[categoryId][mappingId].id = mappingId;
} }
}
export const KEYCODE_LMB = 1;
export const KEYCODE_MMB = 2; export const KEYCODE_LMB = 1;
export const KEYCODE_RMB = 3; export const KEYCODE_MMB = 2;
export const KEYCODE_RMB = 3;
/**
* Returns a keycode -> string /**
* @param {number} code * Returns a keycode -> string
* @returns {string} * @param {number} code
*/ * @returns {string}
export function getStringForKeyCode(code) { */
switch (code) { export function getStringForKeyCode(code) {
case KEYCODE_LMB: switch (code) {
return "LMB"; case KEYCODE_LMB:
case KEYCODE_MMB: return "LMB";
return "MMB"; case KEYCODE_MMB:
case KEYCODE_RMB: return "MMB";
return "RMB"; case KEYCODE_RMB:
case 4: return "RMB";
return "MB4"; case 4:
case 5: return "MB4";
return "MB5"; case 5:
case 8: return "MB5";
return "⌫"; case 8:
case 9: return "⌫";
return T.global.keys.tab; case 9:
case 13: return T.global.keys.tab;
return "⏎"; case 13:
case 16: return "⏎";
return "⇪"; case 16:
case 17: return "⇪";
return T.global.keys.control; case 17:
case 18: return T.global.keys.control;
return T.global.keys.alt; case 18:
case 19: return T.global.keys.alt;
return "PAUSE"; case 19:
case 20: return "PAUSE";
return "CAPS"; case 20:
case 27: return "CAPS";
return T.global.keys.escape; case 27:
case 32: return T.global.keys.escape;
return T.global.keys.space; case 32:
case 33: return T.global.keys.space;
return "PGUP"; case 33:
case 34: return "PGUP";
return "PGDOWN"; case 34:
case 35: return "PGDOWN";
return "END"; case 35:
case 36: return "END";
return "HOME"; case 36:
case 37: return "HOME";
return "⬅"; case 37:
case 38: return "⬅";
return "⬆"; case 38:
case 39: return "⬆";
return "➡"; case 39:
case 40: return "➡";
return "⬇"; case 40:
case 44: return "⬇";
return "PRNT"; case 44:
case 45: return "PRNT";
return "INS"; case 45:
case 46: return "INS";
return "DEL"; case 46:
case 93: return "DEL";
return "SEL"; case 93:
case 96: return "SEL";
return "NUM 0"; case 96:
case 97: return "NUM 0";
return "NUM 1"; case 97:
case 98: return "NUM 1";
return "NUM 2"; case 98:
case 99: return "NUM 2";
return "NUM 3"; case 99:
case 100: return "NUM 3";
return "NUM 4"; case 100:
case 101: return "NUM 4";
return "NUM 5"; case 101:
case 102: return "NUM 5";
return "NUM 6"; case 102:
case 103: return "NUM 6";
return "NUM 7"; case 103:
case 104: return "NUM 7";
return "NUM 8"; case 104:
case 105: return "NUM 8";
return "NUM 9"; case 105:
case 106: return "NUM 9";
return "*"; case 106:
case 107: return "*";
return "+"; case 107:
case 109: return "+";
return "-"; case 109:
case 110: return "-";
return "."; case 110:
case 111: return ".";
return "/"; case 111:
case 112: return "/";
return "F1"; case 112:
case 113: return "F1";
return "F2"; case 113:
case 114: return "F2";
return "F3"; case 114:
case 115: return "F3";
return "F4"; case 115:
case 116: return "F4";
return "F4"; case 116:
case 117: return "F4";
return "F5"; case 117:
case 118: return "F5";
return "F6"; case 118:
case 119: return "F6";
return "F7"; case 119:
case 120: return "F7";
return "F8"; case 120:
case 121: return "F8";
return "F9"; case 121:
case 122: return "F9";
return "F10"; case 122:
case 123: return "F10";
return "F11"; case 123:
case 124: return "F11";
return "F12"; case 124:
return "F12";
case 144:
return "NUMLOCK"; case 144:
case 145: return "NUMLOCK";
return "SCRLOCK"; case 145:
case 182: return "SCRLOCK";
return "COMP"; case 182:
case 183: return "COMP";
return "CALC"; case 183:
case 186: return "CALC";
return ";"; case 186:
case 187: return ";";
return "+"; case 187:
case 188: return "+";
return ","; case 188:
case 189: return ",";
return "-"; case 189:
case 191: return "-";
return "/"; case 191:
case 219: return "/";
return "["; case 219:
case 220: return "[";
return "\\"; case 220:
case 221: return "\\";
return "]"; case 221:
case 222: return "]";
return "'"; case 222:
} return "'";
}
return String.fromCharCode(code);
} return String.fromCharCode(code);
}
export class Keybinding {
/** export class Keybinding {
* /**
* @param {KeyActionMapper} keyMapper *
* @param {Application} app * @param {KeyActionMapper} keyMapper
* @param {object} param0 * @param {Application} app
* @param {number} param0.keyCode * @param {object} param0
* @param {boolean=} param0.builtin * @param {number} param0.keyCode
* @param {boolean=} param0.repeated * @param {boolean=} param0.builtin
*/ * @param {boolean=} param0.repeated
constructor(keyMapper, app, { keyCode, builtin = false, repeated = false }) { */
assert(keyCode && Number.isInteger(keyCode), "Invalid key code: " + keyCode); constructor(keyMapper, app, { keyCode, builtin = false, repeated = false }) {
this.keyMapper = keyMapper; assert(keyCode && Number.isInteger(keyCode), "Invalid key code: " + keyCode);
this.app = app; this.keyMapper = keyMapper;
this.keyCode = keyCode; this.app = app;
this.builtin = builtin; this.keyCode = keyCode;
this.repeated = repeated; this.builtin = builtin;
this.repeated = repeated;
this.signal = new Signal();
this.toggled = new Signal(); this.signal = new Signal();
} this.toggled = new Signal();
}
/**
* Returns whether this binding is currently pressed /**
* @returns {boolean} * Returns whether this binding is currently pressed
*/ * @returns {boolean}
get pressed() { */
// Check if the key is down get pressed() {
if (this.app.inputMgr.keysDown.has(this.keyCode)) { // Check if the key is down
// Check if it is the top reciever if (this.app.inputMgr.keysDown.has(this.keyCode)) {
const reciever = this.keyMapper.inputReceiver; // Check if it is the top reciever
return this.app.inputMgr.getTopReciever() === reciever; const reciever = this.keyMapper.inputReceiver;
} return this.app.inputMgr.getTopReciever() === reciever;
return false; }
} return false;
}
/**
* Adds an event listener /**
* @param {function() : void} receiver * Adds an event listener
* @param {object=} scope * @param {function() : void} receiver
*/ * @param {object=} scope
add(receiver, scope = null) { */
this.signal.add(receiver, scope); add(receiver, scope = null) {
} this.signal.add(receiver, scope);
}
/**
* @param {Element} elem /**
* @returns {HTMLElement} the created element, or null if the keybindings are not shown * @param {Element} elem
* */ * @returns {HTMLElement} the created element, or null if the keybindings are not shown
appendLabelToElement(elem) { * */
if (IS_MOBILE) { appendLabelToElement(elem) {
return null; if (IS_MOBILE) {
} return null;
const spacer = document.createElement("code"); }
spacer.classList.add("keybinding"); const spacer = document.createElement("code");
spacer.innerHTML = getStringForKeyCode(this.keyCode); spacer.classList.add("keybinding");
elem.appendChild(spacer); spacer.innerHTML = getStringForKeyCode(this.keyCode);
return spacer; elem.appendChild(spacer);
} return spacer;
}
/**
* Returns the key code as a nice string /**
*/ * Returns the key code as a nice string
getKeyCodeString() { */
return getStringForKeyCode(this.keyCode); getKeyCodeString() {
} return getStringForKeyCode(this.keyCode);
}
/**
* Remvoes all signal receivers /**
*/ * Remvoes all signal receivers
clearSignalReceivers() { */
this.signal.removeAll(); clearSignalReceivers() {
} this.signal.removeAll();
} }
}
export class KeyActionMapper {
/** export class KeyActionMapper {
* /**
* @param {GameRoot} root *
* @param {InputReceiver} inputReciever * @param {GameRoot} root
*/ * @param {InputReceiver} inputReciever
constructor(root, inputReciever) { */
this.root = root; constructor(root, inputReciever) {
this.inputReceiver = inputReciever; this.root = root;
this.inputReceiver = inputReciever;
inputReciever.keydown.add(this.handleKeydown, this);
inputReciever.keyup.add(this.handleKeyup, this); inputReciever.keydown.add(this.handleKeydown, this);
inputReciever.keyup.add(this.handleKeyup, this);
/** @type {Object.<string, Keybinding>} */
this.keybindings = {}; /** @type {Object.<string, Keybinding>} */
this.keybindings = {};
const overrides = root.app.settings.getKeybindingOverrides();
const overrides = root.app.settings.getKeybindingOverrides();
for (const category in KEYMAPPINGS) {
for (const key in KEYMAPPINGS[category]) { for (const category in KEYMAPPINGS) {
let payload = Object.assign({}, KEYMAPPINGS[category][key]); for (const key in KEYMAPPINGS[category]) {
if (overrides[key]) { let payload = Object.assign({}, KEYMAPPINGS[category][key]);
payload.keyCode = overrides[key]; if (overrides[key]) {
} payload.keyCode = overrides[key];
}
this.keybindings[key] = new Keybinding(this, this.root.app, payload);
} this.keybindings[key] = new Keybinding(this, this.root.app, payload);
} }
}
inputReciever.pageBlur.add(this.onPageBlur, this);
inputReciever.destroyed.add(this.cleanup, this); inputReciever.pageBlur.add(this.onPageBlur, this);
} inputReciever.destroyed.add(this.cleanup, this);
}
/**
* Returns all keybindings starting with the given id /**
* @param {string} pattern * Returns all keybindings starting with the given id
* @returns {Array<Keybinding>} * @param {string} pattern
*/ * @returns {Array<Keybinding>}
getKeybindingsStartingWith(pattern) { */
let result = []; getKeybindingsStartingWith(pattern) {
for (const key in this.keybindings) { let result = [];
if (key.startsWith(pattern)) { for (const key in this.keybindings) {
result.push(this.keybindings[key]); if (key.startsWith(pattern)) {
} result.push(this.keybindings[key]);
} }
return result; }
} return result;
}
/**
* Forwards the given events to the other mapper (used in tooltips) /**
* @param {KeyActionMapper} receiver * Forwards the given events to the other mapper (used in tooltips)
* @param {Array<string>} bindings * @param {KeyActionMapper} receiver
*/ * @param {Array<string>} bindings
forward(receiver, bindings) { */
for (let i = 0; i < bindings.length; ++i) { forward(receiver, bindings) {
const key = bindings[i]; for (let i = 0; i < bindings.length; ++i) {
this.keybindings[key].signal.add((...args) => receiver.keybindings[key].signal.dispatch(...args)); const key = bindings[i];
} this.keybindings[key].signal.add((...args) => receiver.keybindings[key].signal.dispatch(...args));
} }
}
cleanup() {
for (const key in this.keybindings) { cleanup() {
this.keybindings[key].signal.removeAll(); for (const key in this.keybindings) {
} this.keybindings[key].signal.removeAll();
} }
}
onPageBlur() {
// Reset all down states onPageBlur() {
// Find mapping // Reset all down states
for (const key in this.keybindings) { // Find mapping
/** @type {Keybinding} */ for (const key in this.keybindings) {
const binding = this.keybindings[key]; /** @type {Keybinding} */
} const binding = this.keybindings[key];
} }
}
/**
* Internal keydown handler /**
* @param {object} param0 * Internal keydown handler
* @param {number} param0.keyCode * @param {object} param0
* @param {boolean} param0.shift * @param {number} param0.keyCode
* @param {boolean} param0.alt * @param {boolean} param0.shift
* @param {boolean=} param0.initial * @param {boolean} param0.alt
*/ * @param {boolean=} param0.initial
handleKeydown({ keyCode, shift, alt, initial }) { */
let stop = false; handleKeydown({ keyCode, shift, alt, initial }) {
let stop = false;
// Find mapping
for (const key in this.keybindings) { // Find mapping
/** @type {Keybinding} */ for (const key in this.keybindings) {
const binding = this.keybindings[key]; /** @type {Keybinding} */
if (binding.keyCode === keyCode && (initial || binding.repeated)) { const binding = this.keybindings[key];
/** @type {Signal} */ if (binding.keyCode === keyCode && (initial || binding.repeated)) {
const signal = this.keybindings[key].signal; /** @type {Signal} */
if (signal.dispatch() === STOP_PROPAGATION) { const signal = this.keybindings[key].signal;
return; if (signal.dispatch() === STOP_PROPAGATION) {
} return;
} }
} }
}
if (stop) {
return STOP_PROPAGATION; if (stop) {
} return STOP_PROPAGATION;
} }
}
/**
* Internal keyup handler /**
* @param {object} param0 * Internal keyup handler
* @param {number} param0.keyCode * @param {object} param0
* @param {boolean} param0.shift * @param {number} param0.keyCode
* @param {boolean} param0.alt * @param {boolean} param0.shift
*/ * @param {boolean} param0.alt
handleKeyup({ keyCode, shift, alt }) { */
// Empty handleKeyup({ keyCode, shift, alt }) {
} // Empty
}
/**
* Returns a given keybinding /**
* @param {{ keyCode: number }} binding * Returns a given keybinding
* @returns {Keybinding} * @param {{ keyCode: number }} binding
*/ * @returns {Keybinding}
getBinding(binding) { */
// @ts-ignore getBinding(binding) {
const id = binding.id; // @ts-ignore
assert(id, "Not a valid keybinding: " + JSON.stringify(binding)); const id = binding.id;
assert(this.keybindings[id], "Keybinding " + id + " not known!"); assert(id, "Not a valid keybinding: " + JSON.stringify(binding));
return this.keybindings[id]; assert(this.keybindings[id], "Keybinding " + id + " not known!");
} return this.keybindings[id];
} }
}

View File

@ -1,162 +1,171 @@
import { gMetaBuildingRegistry } from "../core/global_registries"; import { gMetaBuildingRegistry } from "../core/global_registries";
import { createLogger } from "../core/logging"; import { createLogger } from "../core/logging";
import { MetaBeltBuilding } from "./buildings/belt"; import { MetaBeltBuilding } from "./buildings/belt";
import { MetaBeltBaseBuilding } from "./buildings/belt_base"; import { MetaBeltBaseBuilding } from "./buildings/belt_base";
import { enumCutterVariants, MetaCutterBuilding } from "./buildings/cutter"; import { enumCutterVariants, MetaCutterBuilding } from "./buildings/cutter";
import { MetaHubBuilding } from "./buildings/hub"; import { MetaHubBuilding } from "./buildings/hub";
import { enumMinerVariants, MetaMinerBuilding } from "./buildings/miner"; import { enumMinerVariants, MetaMinerBuilding } from "./buildings/miner";
import { MetaMixerBuilding } from "./buildings/mixer"; import { MetaMixerBuilding } from "./buildings/mixer";
import { enumPainterVariants, MetaPainterBuilding } from "./buildings/painter"; import { enumPainterVariants, MetaPainterBuilding } from "./buildings/painter";
import { enumRotaterVariants, MetaRotaterBuilding } from "./buildings/rotater"; import { enumRotaterVariants, MetaRotaterBuilding } from "./buildings/rotater";
import { enumSplitterVariants, MetaSplitterBuilding } from "./buildings/splitter"; import { enumSplitterVariants, MetaSplitterBuilding } from "./buildings/splitter";
import { MetaStackerBuilding } from "./buildings/stacker"; import { MetaStackerBuilding } from "./buildings/stacker";
import { enumTrashVariants, MetaTrashBuilding } from "./buildings/trash"; import { enumTrashVariants, MetaTrashBuilding } from "./buildings/trash";
import { enumUndergroundBeltVariants, MetaUndergroundBeltBuilding } from "./buildings/underground_belt"; import { enumUndergroundBeltVariants, MetaUndergroundBeltBuilding } from "./buildings/underground_belt";
import { MetaWireBuilding } from "./buildings/wire"; import { MetaWireBuilding } from "./buildings/wire";
import { gBuildingVariants, registerBuildingVariant } from "./building_codes"; import { gBuildingVariants, registerBuildingVariant } from "./building_codes";
import { defaultBuildingVariant } from "./meta_building"; import { defaultBuildingVariant } from "./meta_building";
import { MetaConstantSignalBuilding } from "./buildings/constant_signal"; import { MetaConstantSignalBuilding } from "./buildings/constant_signal";
import { MetaLogicGateBuilding, enumLogicGateVariants } from "./buildings/logic_gate"; import { MetaLogicGateBuilding, enumLogicGateVariants } from "./buildings/logic_gate";
import { MetaLeverBuilding } from "./buildings/lever"; import { MetaLeverBuilding } from "./buildings/lever";
import { MetaFilterBuilding } from "./buildings/filter"; import { MetaFilterBuilding } from "./buildings/filter";
import { MetaWireTunnelBuilding, enumWireTunnelVariants } from "./buildings/wire_tunnel"; import { MetaWireTunnelBuilding, enumWireTunnelVariants } from "./buildings/wire_tunnel";
import { MetaDisplayBuilding } from "./buildings/display"; import { MetaDisplayBuilding } from "./buildings/display";
import { MetaVirtualProcessorBuilding, enumVirtualProcessorVariants } from "./buildings/virtual_processor";
const logger = createLogger("building_registry");
const logger = createLogger("building_registry");
export function initMetaBuildingRegistry() {
gMetaBuildingRegistry.register(MetaSplitterBuilding); export function initMetaBuildingRegistry() {
gMetaBuildingRegistry.register(MetaMinerBuilding); gMetaBuildingRegistry.register(MetaSplitterBuilding);
gMetaBuildingRegistry.register(MetaCutterBuilding); gMetaBuildingRegistry.register(MetaMinerBuilding);
gMetaBuildingRegistry.register(MetaRotaterBuilding); gMetaBuildingRegistry.register(MetaCutterBuilding);
gMetaBuildingRegistry.register(MetaStackerBuilding); gMetaBuildingRegistry.register(MetaRotaterBuilding);
gMetaBuildingRegistry.register(MetaMixerBuilding); gMetaBuildingRegistry.register(MetaStackerBuilding);
gMetaBuildingRegistry.register(MetaPainterBuilding); gMetaBuildingRegistry.register(MetaMixerBuilding);
gMetaBuildingRegistry.register(MetaTrashBuilding); gMetaBuildingRegistry.register(MetaPainterBuilding);
gMetaBuildingRegistry.register(MetaBeltBuilding); gMetaBuildingRegistry.register(MetaTrashBuilding);
gMetaBuildingRegistry.register(MetaUndergroundBeltBuilding); gMetaBuildingRegistry.register(MetaBeltBuilding);
gMetaBuildingRegistry.register(MetaHubBuilding); gMetaBuildingRegistry.register(MetaUndergroundBeltBuilding);
gMetaBuildingRegistry.register(MetaWireBuilding); gMetaBuildingRegistry.register(MetaHubBuilding);
gMetaBuildingRegistry.register(MetaConstantSignalBuilding); gMetaBuildingRegistry.register(MetaWireBuilding);
gMetaBuildingRegistry.register(MetaLogicGateBuilding); gMetaBuildingRegistry.register(MetaConstantSignalBuilding);
gMetaBuildingRegistry.register(MetaLeverBuilding); gMetaBuildingRegistry.register(MetaLogicGateBuilding);
gMetaBuildingRegistry.register(MetaFilterBuilding); gMetaBuildingRegistry.register(MetaLeverBuilding);
gMetaBuildingRegistry.register(MetaWireTunnelBuilding); gMetaBuildingRegistry.register(MetaFilterBuilding);
gMetaBuildingRegistry.register(MetaDisplayBuilding); gMetaBuildingRegistry.register(MetaWireTunnelBuilding);
gMetaBuildingRegistry.register(MetaDisplayBuilding);
// Belt gMetaBuildingRegistry.register(MetaVirtualProcessorBuilding);
registerBuildingVariant(1, MetaBeltBaseBuilding, defaultBuildingVariant, 0);
registerBuildingVariant(2, MetaBeltBaseBuilding, defaultBuildingVariant, 1); // Belt
registerBuildingVariant(3, MetaBeltBaseBuilding, defaultBuildingVariant, 2); registerBuildingVariant(1, MetaBeltBaseBuilding, defaultBuildingVariant, 0);
registerBuildingVariant(2, MetaBeltBaseBuilding, defaultBuildingVariant, 1);
// Splitter registerBuildingVariant(3, MetaBeltBaseBuilding, defaultBuildingVariant, 2);
registerBuildingVariant(4, MetaSplitterBuilding);
registerBuildingVariant(5, MetaSplitterBuilding, enumSplitterVariants.compact); // Splitter
registerBuildingVariant(6, MetaSplitterBuilding, enumSplitterVariants.compactInverse); registerBuildingVariant(4, MetaSplitterBuilding);
registerBuildingVariant(5, MetaSplitterBuilding, enumSplitterVariants.compact);
// Miner registerBuildingVariant(6, MetaSplitterBuilding, enumSplitterVariants.compactInverse);
registerBuildingVariant(7, MetaMinerBuilding);
registerBuildingVariant(8, MetaMinerBuilding, enumMinerVariants.chainable); // Miner
registerBuildingVariant(7, MetaMinerBuilding);
// Cutter registerBuildingVariant(8, MetaMinerBuilding, enumMinerVariants.chainable);
registerBuildingVariant(9, MetaCutterBuilding);
registerBuildingVariant(10, MetaCutterBuilding, enumCutterVariants.quad); // Cutter
registerBuildingVariant(9, MetaCutterBuilding);
// Rotater registerBuildingVariant(10, MetaCutterBuilding, enumCutterVariants.quad);
registerBuildingVariant(11, MetaRotaterBuilding);
registerBuildingVariant(12, MetaRotaterBuilding, enumRotaterVariants.ccw); // Rotater
registerBuildingVariant(13, MetaRotaterBuilding, enumRotaterVariants.fl); registerBuildingVariant(11, MetaRotaterBuilding);
registerBuildingVariant(12, MetaRotaterBuilding, enumRotaterVariants.ccw);
// Stacker registerBuildingVariant(13, MetaRotaterBuilding, enumRotaterVariants.fl);
registerBuildingVariant(14, MetaStackerBuilding);
// Stacker
// Mixer registerBuildingVariant(14, MetaStackerBuilding);
registerBuildingVariant(15, MetaMixerBuilding);
// Mixer
// Painter registerBuildingVariant(15, MetaMixerBuilding);
registerBuildingVariant(16, MetaPainterBuilding);
registerBuildingVariant(17, MetaPainterBuilding, enumPainterVariants.mirrored); // Painter
registerBuildingVariant(18, MetaPainterBuilding, enumPainterVariants.double); registerBuildingVariant(16, MetaPainterBuilding);
registerBuildingVariant(19, MetaPainterBuilding, enumPainterVariants.quad); registerBuildingVariant(17, MetaPainterBuilding, enumPainterVariants.mirrored);
registerBuildingVariant(18, MetaPainterBuilding, enumPainterVariants.double);
// Trash registerBuildingVariant(19, MetaPainterBuilding, enumPainterVariants.quad);
registerBuildingVariant(20, MetaTrashBuilding);
registerBuildingVariant(21, MetaTrashBuilding, enumTrashVariants.storage); // Trash
registerBuildingVariant(20, MetaTrashBuilding);
// Underground belt registerBuildingVariant(21, MetaTrashBuilding, enumTrashVariants.storage);
registerBuildingVariant(22, MetaUndergroundBeltBuilding, defaultBuildingVariant, 0);
registerBuildingVariant(23, MetaUndergroundBeltBuilding, defaultBuildingVariant, 1); // Underground belt
registerBuildingVariant(24, MetaUndergroundBeltBuilding, enumUndergroundBeltVariants.tier2, 0); registerBuildingVariant(22, MetaUndergroundBeltBuilding, defaultBuildingVariant, 0);
registerBuildingVariant(25, MetaUndergroundBeltBuilding, enumUndergroundBeltVariants.tier2, 1); registerBuildingVariant(23, MetaUndergroundBeltBuilding, defaultBuildingVariant, 1);
registerBuildingVariant(24, MetaUndergroundBeltBuilding, enumUndergroundBeltVariants.tier2, 0);
// Hub registerBuildingVariant(25, MetaUndergroundBeltBuilding, enumUndergroundBeltVariants.tier2, 1);
registerBuildingVariant(26, MetaHubBuilding);
// Hub
// Wire registerBuildingVariant(26, MetaHubBuilding);
registerBuildingVariant(27, MetaWireBuilding, defaultBuildingVariant, 0);
registerBuildingVariant(28, MetaWireBuilding, defaultBuildingVariant, 1); // Wire
registerBuildingVariant(29, MetaWireBuilding, defaultBuildingVariant, 2); registerBuildingVariant(27, MetaWireBuilding, defaultBuildingVariant, 0);
registerBuildingVariant(30, MetaWireBuilding, defaultBuildingVariant, 3); registerBuildingVariant(28, MetaWireBuilding, defaultBuildingVariant, 1);
registerBuildingVariant(29, MetaWireBuilding, defaultBuildingVariant, 2);
// Constant signal registerBuildingVariant(30, MetaWireBuilding, defaultBuildingVariant, 3);
registerBuildingVariant(31, MetaConstantSignalBuilding);
// Constant signal
// Logic gate registerBuildingVariant(31, MetaConstantSignalBuilding);
registerBuildingVariant(32, MetaLogicGateBuilding);
registerBuildingVariant(34, MetaLogicGateBuilding, enumLogicGateVariants.not); // Logic gate
registerBuildingVariant(35, MetaLogicGateBuilding, enumLogicGateVariants.xor); registerBuildingVariant(32, MetaLogicGateBuilding);
registerBuildingVariant(36, MetaLogicGateBuilding, enumLogicGateVariants.or); registerBuildingVariant(34, MetaLogicGateBuilding, enumLogicGateVariants.not);
registerBuildingVariant(38, MetaLogicGateBuilding, enumLogicGateVariants.transistor); registerBuildingVariant(35, MetaLogicGateBuilding, enumLogicGateVariants.xor);
registerBuildingVariant(36, MetaLogicGateBuilding, enumLogicGateVariants.or);
// Lever registerBuildingVariant(38, MetaLogicGateBuilding, enumLogicGateVariants.transistor);
registerBuildingVariant(33, MetaLeverBuilding);
// Lever
// Filter registerBuildingVariant(33, MetaLeverBuilding);
registerBuildingVariant(37, MetaFilterBuilding);
// Filter
// Wire tunnel registerBuildingVariant(37, MetaFilterBuilding);
registerBuildingVariant(39, MetaWireTunnelBuilding);
registerBuildingVariant(41, MetaWireTunnelBuilding, enumWireTunnelVariants.coating); // Wire tunnel
registerBuildingVariant(39, MetaWireTunnelBuilding);
// Display registerBuildingVariant(41, MetaWireTunnelBuilding, enumWireTunnelVariants.coating);
registerBuildingVariant(40, MetaDisplayBuilding);
// Display
// Propagate instances registerBuildingVariant(40, MetaDisplayBuilding);
for (const key in gBuildingVariants) {
gBuildingVariants[key].metaInstance = gMetaBuildingRegistry.findByClass( // Virtual Processor
gBuildingVariants[key].metaClass registerBuildingVariant(42, MetaVirtualProcessorBuilding);
); registerBuildingVariant(43, MetaVirtualProcessorBuilding, enumVirtualProcessorVariants.analyzer);
} registerBuildingVariant(44, MetaVirtualProcessorBuilding, enumVirtualProcessorVariants.rotater);
registerBuildingVariant(45, MetaVirtualProcessorBuilding, enumVirtualProcessorVariants.unstacker);
for (const key in gBuildingVariants) { registerBuildingVariant(46, MetaVirtualProcessorBuilding, enumVirtualProcessorVariants.shapecompare);
const variant = gBuildingVariants[key];
assert(variant.metaClass, "Variant has no meta: " + key); // Propagate instances
for (const key in gBuildingVariants) {
if (typeof variant.rotationVariant === "undefined") { gBuildingVariants[key].metaInstance = gMetaBuildingRegistry.findByClass(
variant.rotationVariant = 0; gBuildingVariants[key].metaClass
} );
if (typeof variant.variant === "undefined") { }
variant.variant = defaultBuildingVariant;
} for (const key in gBuildingVariants) {
} const variant = gBuildingVariants[key];
assert(variant.metaClass, "Variant has no meta: " + key);
logger.log("Registered", gMetaBuildingRegistry.getNumEntries(), "buildings");
logger.log("Registered", Object.keys(gBuildingVariants).length, "building codes"); if (typeof variant.rotationVariant === "undefined") {
} variant.rotationVariant = 0;
}
/** if (typeof variant.variant === "undefined") {
* Once all sprites are loaded, propagates the cache variant.variant = defaultBuildingVariant;
*/ }
export function initBuildingCodesAfterResourcesLoaded() { }
logger.log("Propagating sprite cache");
for (const key in gBuildingVariants) { logger.log("Registered", gMetaBuildingRegistry.getNumEntries(), "buildings");
const variant = gBuildingVariants[key]; logger.log("Registered", Object.keys(gBuildingVariants).length, "building codes");
}
variant.sprite = variant.metaInstance.getSprite(variant.rotationVariant, variant.variant);
variant.blueprintSprite = variant.metaInstance.getBlueprintSprite( /**
variant.rotationVariant, * Once all sprites are loaded, propagates the cache
variant.variant */
); export function initBuildingCodesAfterResourcesLoaded() {
variant.silhouetteColor = variant.metaInstance.getSilhouetteColor(); logger.log("Propagating sprite cache");
} for (const key in gBuildingVariants) {
} const variant = gBuildingVariants[key];
variant.sprite = variant.metaInstance.getSprite(variant.rotationVariant, variant.variant);
variant.blueprintSprite = variant.metaInstance.getBlueprintSprite(
variant.rotationVariant,
variant.variant
);
variant.silhouetteColor = variant.metaInstance.getSilhouetteColor();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,180 +1,318 @@
import { LogicGateComponent, enumLogicGateType } from "../components/logic_gate"; import { BaseItem } from "../base_item";
import { GameSystemWithFilter } from "../game_system_with_filter"; import { enumColors } from "../colors";
import { BaseItem } from "../base_item"; import { enumLogicGateType, LogicGateComponent } from "../components/logic_gate";
import { enumPinSlotType } from "../components/wired_pins"; import { enumPinSlotType } from "../components/wired_pins";
import { BOOL_TRUE_SINGLETON, BOOL_FALSE_SINGLETON, BooleanItem } from "../items/boolean_item"; import { GameSystemWithFilter } from "../game_system_with_filter";
import { enumItemProcessorTypes } from "../components/item_processor"; import { BOOL_FALSE_SINGLETON, BOOL_TRUE_SINGLETON, BooleanItem } from "../items/boolean_item";
import { COLOR_ITEM_SINGLETONS } from "../items/color_item";
export class LogicGateSystem extends GameSystemWithFilter { import { ShapeDefinition } from "../shape_definition";
constructor(root) { import { ShapeItem } from "../items/shape_item";
super(root, [LogicGateComponent]);
export class LogicGateSystem extends GameSystemWithFilter {
this.boundOperations = { constructor(root) {
[enumLogicGateType.and]: this.compute_AND.bind(this), super(root, [LogicGateComponent]);
[enumLogicGateType.not]: this.compute_NOT.bind(this),
[enumLogicGateType.xor]: this.compute_XOR.bind(this), this.boundOperations = {
[enumLogicGateType.or]: this.compute_OR.bind(this), [enumLogicGateType.and]: this.compute_AND.bind(this),
[enumLogicGateType.transistor]: this.compute_IF.bind(this), [enumLogicGateType.not]: this.compute_NOT.bind(this),
}; [enumLogicGateType.xor]: this.compute_XOR.bind(this),
} [enumLogicGateType.or]: this.compute_OR.bind(this),
[enumLogicGateType.transistor]: this.compute_IF.bind(this),
update() {
for (let i = 0; i < this.allEntities.length; ++i) { [enumLogicGateType.rotater]: this.compute_ROTATE.bind(this),
const entity = this.allEntities[i]; [enumLogicGateType.analyzer]: this.compute_ANALYZE.bind(this),
const logicComp = entity.components.LogicGate; [enumLogicGateType.cutter]: this.compute_CUT.bind(this),
const slotComp = entity.components.WiredPins; [enumLogicGateType.unstacker]: this.compute_UNSTACK.bind(this),
[enumLogicGateType.shapecompare]: this.compute_SHAPECOMPARE.bind(this),
const slotValues = []; };
}
for (let i = 0; i < slotComp.slots.length; ++i) {
const slot = slotComp.slots[i]; update() {
if (slot.type !== enumPinSlotType.logicalAcceptor) { for (let i = 0; i < this.allEntities.length; ++i) {
continue; const entity = this.allEntities[i];
} const logicComp = entity.components.LogicGate;
if (slot.linkedNetwork) { const slotComp = entity.components.WiredPins;
slotValues.push(slot.linkedNetwork.currentValue);
} else { const slotValues = [];
slotValues.push(null);
} for (let i = 0; i < slotComp.slots.length; ++i) {
} const slot = slotComp.slots[i];
if (slot.type !== enumPinSlotType.logicalAcceptor) {
const result = this.boundOperations[logicComp.type](slotValues); continue;
}
// @TODO: For now we hardcode the value to always be slot 0 if (slot.linkedNetwork) {
assert( slotValues.push(slot.linkedNetwork.currentValue);
slotValues.length === slotComp.slots.length - 1, } else {
"Bad slot config, should have N acceptor slots and 1 ejector" slotValues.push(null);
); }
assert(slotComp.slots[0].type === enumPinSlotType.logicalEjector, "Slot 0 should be ejector"); }
slotComp.slots[0].value = result; const result = this.boundOperations[logicComp.type](slotValues);
}
} if (Array.isArray(result)) {
let resultIndex = 0;
/** for (let i = 0; i < slotComp.slots.length; ++i) {
* @param {Array<BaseItem|null>} parameters const slot = slotComp.slots[i];
* @returns {BaseItem} if (slot.type !== enumPinSlotType.logicalEjector) {
*/ continue;
compute_AND(parameters) { }
assert(parameters.length === 2, "bad parameter count for AND"); slot.value = result[resultIndex++];
}
const param1 = parameters[0]; } else {
const param2 = parameters[1]; // @TODO: For now we hardcode the value to always be slot 0
if (!param1 || !param2) { assert(
// Not enough params slotValues.length === slotComp.slots.length - 1,
return BOOL_FALSE_SINGLETON; "Bad slot config, should have N acceptor slots and 1 ejector"
} );
assert(slotComp.slots[0].type === enumPinSlotType.logicalEjector, "Slot 0 should be ejector");
const itemType = param1.getItemType(); slotComp.slots[0].value = result;
}
if (itemType !== param2.getItemType()) { }
// Differing type }
return BOOL_FALSE_SINGLETON;
} /**
* @param {Array<BaseItem|null>} parameters
if (itemType === "boolean") { * @returns {BaseItem}
return /** @type {BooleanItem} */ (param1).value && /** @type {BooleanItem} */ (param2).value */
? BOOL_TRUE_SINGLETON compute_AND(parameters) {
: BOOL_FALSE_SINGLETON; assert(parameters.length === 2, "bad parameter count for AND");
}
const param1 = parameters[0];
return BOOL_FALSE_SINGLETON; const param2 = parameters[1];
} if (!param1 || !param2) {
// Not enough params
/** return BOOL_FALSE_SINGLETON;
* @param {Array<BaseItem|null>} parameters }
* @returns {BaseItem}
*/ const itemType = param1.getItemType();
compute_NOT(parameters) {
const item = parameters[0]; if (itemType !== param2.getItemType()) {
if (!item) { // Differing type
return BOOL_TRUE_SINGLETON; return BOOL_FALSE_SINGLETON;
} }
if (item.getItemType() !== "boolean") { if (itemType === "boolean") {
// Not a boolean actually return /** @type {BooleanItem} */ (param1).value && /** @type {BooleanItem} */ (param2).value
return BOOL_FALSE_SINGLETON; ? BOOL_TRUE_SINGLETON
} : BOOL_FALSE_SINGLETON;
}
const value = /** @type {BooleanItem} */ (item).value;
return value ? BOOL_FALSE_SINGLETON : BOOL_TRUE_SINGLETON; return BOOL_FALSE_SINGLETON;
} }
/** /**
* @param {Array<BaseItem|null>} parameters * @param {Array<BaseItem|null>} parameters
* @returns {BaseItem} * @returns {BaseItem}
*/ */
compute_XOR(parameters) { compute_NOT(parameters) {
assert(parameters.length === 2, "bad parameter count for XOR"); const item = parameters[0];
if (!item) {
const param1 = parameters[0]; return BOOL_TRUE_SINGLETON;
const param2 = parameters[1]; }
if (!param1 && !param2) {
// Not enough params if (item.getItemType() !== "boolean") {
return BOOL_FALSE_SINGLETON; // Not a boolean actually
} return BOOL_FALSE_SINGLETON;
}
// Check for the right types
if (param1 && param1.getItemType() !== "boolean") { const value = /** @type {BooleanItem} */ (item).value;
return BOOL_FALSE_SINGLETON; return value ? BOOL_FALSE_SINGLETON : BOOL_TRUE_SINGLETON;
} }
if (param2 && param2.getItemType() !== "boolean") { /**
return BOOL_FALSE_SINGLETON; * @param {Array<BaseItem|null>} parameters
} * @returns {BaseItem}
*/
const valueParam1 = param1 ? /** @type {BooleanItem} */ (param1).value : 0; compute_XOR(parameters) {
const valueParam2 = param2 ? /** @type {BooleanItem} */ (param2).value : 0; assert(parameters.length === 2, "bad parameter count for XOR");
return valueParam1 ^ valueParam2 ? BOOL_TRUE_SINGLETON : BOOL_FALSE_SINGLETON; const param1 = parameters[0];
} const param2 = parameters[1];
if (!param1 && !param2) {
/** // Not enough params
* @param {Array<BaseItem|null>} parameters return BOOL_FALSE_SINGLETON;
* @returns {BaseItem} }
*/
compute_OR(parameters) { // Check for the right types
assert(parameters.length === 2, "bad parameter count for OR"); if (param1 && param1.getItemType() !== "boolean") {
return BOOL_FALSE_SINGLETON;
const param1 = parameters[0]; }
const param2 = parameters[1];
if (!param1 && !param2) { if (param2 && param2.getItemType() !== "boolean") {
// Not enough params return BOOL_FALSE_SINGLETON;
return BOOL_FALSE_SINGLETON; }
}
const valueParam1 = param1 ? /** @type {BooleanItem} */ (param1).value : 0;
const valueParam1 = const valueParam2 = param2 ? /** @type {BooleanItem} */ (param2).value : 0;
param1 && param1.getItemType() === "boolean" ? /** @type {BooleanItem} */ (param1).value : 0;
const valueParam2 = return valueParam1 ^ valueParam2 ? BOOL_TRUE_SINGLETON : BOOL_FALSE_SINGLETON;
param2 && param2.getItemType() === "boolean" ? /** @type {BooleanItem} */ (param2).value : 0; }
return valueParam1 || valueParam2 ? BOOL_TRUE_SINGLETON : BOOL_FALSE_SINGLETON; /**
} * @param {Array<BaseItem|null>} parameters
* @returns {BaseItem}
/** */
* @param {Array<BaseItem|null>} parameters compute_OR(parameters) {
* @returns {BaseItem} assert(parameters.length === 2, "bad parameter count for OR");
*/
compute_IF(parameters) { const param1 = parameters[0];
assert(parameters.length === 2, "bad parameter count for IF"); const param2 = parameters[1];
if (!param1 && !param2) {
const flag = parameters[0]; // Not enough params
const value = parameters[1]; return BOOL_FALSE_SINGLETON;
if (!flag || !value) { }
// Not enough params
return null; const valueParam1 =
} param1 && param1.getItemType() === "boolean" ? /** @type {BooleanItem} */ (param1).value : 0;
const valueParam2 =
if (flag.getItemType() !== "boolean") { param2 && param2.getItemType() === "boolean" ? /** @type {BooleanItem} */ (param2).value : 0;
// Flag is not a boolean
return null; return valueParam1 || valueParam2 ? BOOL_TRUE_SINGLETON : BOOL_FALSE_SINGLETON;
} }
// pass through item /**
if (/** @type {BooleanItem} */ (flag).value) { * @param {Array<BaseItem|null>} parameters
return value; * @returns {BaseItem}
} */
compute_IF(parameters) {
return null; assert(parameters.length === 2, "bad parameter count for IF");
}
} const flag = parameters[0];
const value = parameters[1];
if (!flag || !value) {
// Not enough params
return null;
}
if (flag.getItemType() !== "boolean") {
// Flag is not a boolean
return null;
}
// pass through item
if (/** @type {BooleanItem} */ (flag).value) {
return value;
}
return null;
}
/**
* @param {Array<BaseItem|null>} parameters
* @returns {BaseItem}
*/
compute_ROTATE(parameters) {
const item = parameters[0];
if (!item || item.getItemType() !== "shape") {
// Not a shape
return null;
}
const definition = /** @type {ShapeItem} */ (item).definition;
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(definition);
return this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition);
}
/**
* @param {Array<BaseItem|null>} parameters
* @returns {[BaseItem, BaseItem]}
*/
compute_ANALYZE(parameters) {
const item = parameters[0];
if (!item || item.getItemType() !== "shape") {
// Not a shape
return [null, null];
}
const definition = /** @type {ShapeItem} */ (item).definition;
const lowerLayer = /** @type {import("../shape_definition").ShapeLayer} */ (definition.layers[0]);
const topRightContent = lowerLayer[0];
if (!topRightContent) {
return [null, null];
}
const newDefinition = new ShapeDefinition({
layers: [
[
{ subShape: topRightContent.subShape, color: enumColors.uncolored },
{ subShape: topRightContent.subShape, color: enumColors.uncolored },
{ subShape: topRightContent.subShape, color: enumColors.uncolored },
{ subShape: topRightContent.subShape, color: enumColors.uncolored },
],
],
});
return [
COLOR_ITEM_SINGLETONS[topRightContent.color],
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(newDefinition),
];
}
/**
* @param {Array<BaseItem|null>} parameters
* @returns {[BaseItem, BaseItem]}
*/
compute_CUT(parameters) {
const item = parameters[0];
if (!item || item.getItemType() !== "shape") {
// Not a shape
return [null, null];
}
const definition = /** @type {ShapeItem} */ (item).definition;
const result = this.root.shapeDefinitionMgr.shapeActionCutHalf(definition);
return [
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(result[0]),
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(result[1]),
];
}
/**
* @param {Array<BaseItem|null>} parameters
* @returns {[BaseItem, BaseItem]}
*/
compute_UNSTACK(parameters) {
const item = parameters[0];
if (!item || item.getItemType() !== "shape") {
// Not a shape
return [null, null];
}
const definition = /** @type {ShapeItem} */ (item).definition;
const layers = /** @type {Array<import("../shape_definition").ShapeLayer>} */ (definition.layers);
const upperLayerDefinition = new ShapeDefinition({
layers: [layers[layers.length - 1]],
});
const lowerLayers = layers.slice(0, layers.length - 1);
const lowerLayerDefinition =
lowerLayers.length > 0 ? new ShapeDefinition({ layers: lowerLayers }) : null;
return [
lowerLayerDefinition
? this.root.shapeDefinitionMgr.getShapeItemFromDefinition(lowerLayerDefinition)
: null,
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(upperLayerDefinition),
];
}
/**
* @param {Array<BaseItem|null>} parameters
* @returns {BaseItem}
*/
compute_SHAPECOMPARE(parameters) {
const itemA = parameters[0];
const itemB = parameters[1];
return itemA &&
itemB &&
itemA.getItemType() === "shape" &&
itemB.getItemType() === "shape" &&
/** @type {ShapeItem} */ (itemA).definition.getHash() ===
/** @type {ShapeItem} */ (itemB).definition.getHash()
? BOOL_TRUE_SINGLETON
: BOOL_FALSE_SINGLETON;
}
}

View File

@ -312,7 +312,6 @@ ingame:
black: Schwarz black: Schwarz
uncolored: Farblos uncolored: Farblos
# Everything related to placing buildings (I.e. as soon as you selected a building # Everything related to placing buildings (I.e. as soon as you selected a building
# from the toolbar) # from the toolbar)
buildingPlacement: buildingPlacement:
@ -424,7 +423,6 @@ ingame:
1_3_expand: >- 1_3_expand: >-
Dies ist <strong>KEIN</strong> Idle-Game! Baue mehr Extrahierer und Förderbänder, um das Ziel schneller zu erreichen.<br><br>Tipp: Halte <strong>UMSCH</strong>, um mehrere Gebäude zu platzieren und nutze <strong>R</strong> um sie zu rotieren. Dies ist <strong>KEIN</strong> Idle-Game! Baue mehr Extrahierer und Förderbänder, um das Ziel schneller zu erreichen.<br><br>Tipp: Halte <strong>UMSCH</strong>, um mehrere Gebäude zu platzieren und nutze <strong>R</strong> um sie zu rotieren.
# All shop upgrades # All shop upgrades
shopUpgrades: shopUpgrades:
belt: belt:
@ -564,7 +562,6 @@ buildings:
name: Kabelverbinder name: Kabelverbinder
description: Verbindet zwei Energiekabel zu einem. description: Verbindet zwei Energiekabel zu einem.
storyRewards: storyRewards:
# Those are the rewards gained from completing the store # Those are the rewards gained from completing the store
reward_cutter_and_trash: reward_cutter_and_trash:
@ -837,7 +834,6 @@ keybindings:
Modifikator: stattdessen gegen den UZS rotieren Modifikator: stattdessen gegen den UZS rotieren
cycleBuildingVariants: Variante wählen cycleBuildingVariants: Variante wählen
confirmMassDelete: Massenlöschung bestätigen confirmMassDelete: Massenlöschung bestätigen
pasteLastBlueprint: Letzte Blaupause einfügen
cycleBuildings: Gebäude rotieren cycleBuildings: Gebäude rotieren
lockBeltDirection: Bandplaner aktivieren lockBeltDirection: Bandplaner aktivieren
switchDirectionLockSide: >- switchDirectionLockSide: >-
@ -852,14 +848,6 @@ keybindings:
placeMultiple: Im Platziermodus bleiben placeMultiple: Im Platziermodus bleiben
placeInverse: Automatische Förderbandorientierung invertieren placeInverse: Automatische Förderbandorientierung invertieren
pasteLastBlueprint: Letzte Blaupause einfügen pasteLastBlueprint: Letzte Blaupause einfügen
massSelectCut: Areal ausschneiden
exportScreenshot: Ganze Fabrik als Foto exportieren
mapMoveFaster: Schneller bewegen
lockBeltDirection: Bandplaner aktivieren
switchDirectionLockSide: "Planer: Seite wechseln"
pipette: Pipette
menuClose: Close Menu
switchLayers: Switch layers
advanced_processor: Farbinvertierer advanced_processor: Farbinvertierer
energy_generator: Energiegenerator energy_generator: Energiegenerator
wire: Energiekabel wire: Energiekabel

File diff suppressed because it is too large Load Diff