mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Move item processing into separate methods
This commit is contained in:
parent
3c56c4772f
commit
5ab3afdd30
@ -197,7 +197,7 @@
|
||||
<key>scaleMode</key>
|
||||
<enum type="ScaleMode">Smooth</enum>
|
||||
<key>extrude</key>
|
||||
<uint>2</uint>
|
||||
<uint>4</uint>
|
||||
<key>trimThreshold</key>
|
||||
<uint>2</uint>
|
||||
<key>trimMargin</key>
|
||||
@ -281,6 +281,7 @@
|
||||
<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/virtual_processor-analyzer.png</key>
|
||||
<key type="filename">sprites/blueprints/virtual_processor-painter.png</key>
|
||||
<key type="filename">sprites/blueprints/virtual_processor-rotater.png</key>
|
||||
<key type="filename">sprites/blueprints/virtual_processor-shapecompare.png</key>
|
||||
<key type="filename">sprites/blueprints/virtual_processor-stacker.png</key>
|
||||
@ -309,6 +310,7 @@
|
||||
<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/virtual_processor-analyzer.png</key>
|
||||
<key type="filename">sprites/buildings/virtual_processor-painter.png</key>
|
||||
<key type="filename">sprites/buildings/virtual_processor-rotater.png</key>
|
||||
<key type="filename">sprites/buildings/virtual_processor-shapecompare.png</key>
|
||||
<key type="filename">sprites/buildings/virtual_processor-stacker.png</key>
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@ -1,122 +1,122 @@
|
||||
import { formatItemsPerSecond } from "../../core/utils";
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { T } from "../../translations";
|
||||
import { ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
|
||||
import { Entity } from "../entity";
|
||||
import { defaultBuildingVariant, MetaBuilding } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumRotaterVariants = { ccw: "ccw", fl: "fl" };
|
||||
|
||||
export class MetaRotaterBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("rotater");
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#7dc6cd";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
* @param {string} variant
|
||||
* @returns {Array<[string, string]>}
|
||||
*/
|
||||
getAdditionalStatistics(root, variant) {
|
||||
switch (variant) {
|
||||
case defaultBuildingVariant: {
|
||||
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.rotater);
|
||||
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
|
||||
}
|
||||
case enumRotaterVariants.ccw: {
|
||||
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.rotaterCCW);
|
||||
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
|
||||
}
|
||||
case enumRotaterVariants.fl: {
|
||||
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.rotaterFL);
|
||||
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getAvailableVariants(root) {
|
||||
let variants = [defaultBuildingVariant];
|
||||
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_rotater_ccw)) {
|
||||
variants.push(enumRotaterVariants.ccw);
|
||||
}
|
||||
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_rotater_fl)) {
|
||||
variants.push(enumRotaterVariants.fl);
|
||||
}
|
||||
return variants;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_rotater);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
entity.addComponent(
|
||||
new ItemProcessorComponent({
|
||||
inputsPerCharge: 1,
|
||||
processorType: enumItemProcessorTypes.rotater,
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(
|
||||
new ItemEjectorComponent({
|
||||
slots: [{ pos: new Vector(0, 0), direction: enumDirection.top }],
|
||||
})
|
||||
);
|
||||
entity.addComponent(
|
||||
new ItemAcceptorComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: "shape",
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Entity} entity
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
updateVariants(entity, rotationVariant, variant) {
|
||||
switch (variant) {
|
||||
case defaultBuildingVariant: {
|
||||
entity.components.ItemProcessor.type = enumItemProcessorTypes.rotater;
|
||||
break;
|
||||
}
|
||||
case enumRotaterVariants.ccw: {
|
||||
entity.components.ItemProcessor.type = enumItemProcessorTypes.rotaterCCW;
|
||||
break;
|
||||
}
|
||||
case enumRotaterVariants.fl: {
|
||||
entity.components.ItemProcessor.type = enumItemProcessorTypes.rotaterFL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assertAlways(false, "Unknown rotater variant: " + variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
import { formatItemsPerSecond } from "../../core/utils";
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { T } from "../../translations";
|
||||
import { ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
|
||||
import { Entity } from "../entity";
|
||||
import { defaultBuildingVariant, MetaBuilding } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumRotaterVariants = { ccw: "ccw", rotate180: "rotate180" };
|
||||
|
||||
export class MetaRotaterBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("rotater");
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#7dc6cd";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
* @param {string} variant
|
||||
* @returns {Array<[string, string]>}
|
||||
*/
|
||||
getAdditionalStatistics(root, variant) {
|
||||
switch (variant) {
|
||||
case defaultBuildingVariant: {
|
||||
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.rotater);
|
||||
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
|
||||
}
|
||||
case enumRotaterVariants.ccw: {
|
||||
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.rotaterCCW);
|
||||
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
|
||||
}
|
||||
case enumRotaterVariants.rotate180: {
|
||||
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.rotater180);
|
||||
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getAvailableVariants(root) {
|
||||
let variants = [defaultBuildingVariant];
|
||||
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_rotater_ccw)) {
|
||||
variants.push(enumRotaterVariants.ccw);
|
||||
}
|
||||
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_rotater_180)) {
|
||||
variants.push(enumRotaterVariants.rotate180);
|
||||
}
|
||||
return variants;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_rotater);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
entity.addComponent(
|
||||
new ItemProcessorComponent({
|
||||
inputsPerCharge: 1,
|
||||
processorType: enumItemProcessorTypes.rotater,
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(
|
||||
new ItemEjectorComponent({
|
||||
slots: [{ pos: new Vector(0, 0), direction: enumDirection.top }],
|
||||
})
|
||||
);
|
||||
entity.addComponent(
|
||||
new ItemAcceptorComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: "shape",
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Entity} entity
|
||||
* @param {number} rotationVariant
|
||||
* @param {string} variant
|
||||
*/
|
||||
updateVariants(entity, rotationVariant, variant) {
|
||||
switch (variant) {
|
||||
case defaultBuildingVariant: {
|
||||
entity.components.ItemProcessor.type = enumItemProcessorTypes.rotater;
|
||||
break;
|
||||
}
|
||||
case enumRotaterVariants.ccw: {
|
||||
entity.components.ItemProcessor.type = enumItemProcessorTypes.rotaterCCW;
|
||||
break;
|
||||
}
|
||||
case enumRotaterVariants.rotate180: {
|
||||
entity.components.ItemProcessor.type = enumItemProcessorTypes.rotater180;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assertAlways(false, "Unknown rotater variant: " + variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,15 @@
|
||||
import { types } from "../../savegame/serialization";
|
||||
import { BaseItem } from "../base_item";
|
||||
import { Component } from "../component";
|
||||
import { typeItemSingleton } from "../item_resolver";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumItemProcessorTypes = {
|
||||
splitter: "splitter",
|
||||
splitterWires: "splitterWires",
|
||||
cutter: "cutter",
|
||||
cutterQuad: "cutterQuad",
|
||||
rotater: "rotater",
|
||||
rotaterCCW: "rotaterCCW",
|
||||
rotaterFL: "rotaterFL",
|
||||
rotater180: "rotater180",
|
||||
stacker: "stacker",
|
||||
trash: "trash",
|
||||
mixer: "mixer",
|
||||
|
@ -396,9 +396,6 @@ export class HubGoals extends BasicSerializableObject {
|
||||
*/
|
||||
getProcessorBaseSpeed(processorType) {
|
||||
switch (processorType) {
|
||||
case enumItemProcessorTypes.splitterWires:
|
||||
return globalConfig.wiresSpeedItemsPerSecond * 2;
|
||||
|
||||
case enumItemProcessorTypes.trash:
|
||||
case enumItemProcessorTypes.hub:
|
||||
return 1e30;
|
||||
@ -427,7 +424,7 @@ export class HubGoals extends BasicSerializableObject {
|
||||
case enumItemProcessorTypes.cutterQuad:
|
||||
case enumItemProcessorTypes.rotater:
|
||||
case enumItemProcessorTypes.rotaterCCW:
|
||||
case enumItemProcessorTypes.rotaterFL:
|
||||
case enumItemProcessorTypes.rotater180:
|
||||
case enumItemProcessorTypes.stacker: {
|
||||
assert(
|
||||
globalConfig.buildingSpeeds[processorType],
|
||||
|
@ -70,7 +70,7 @@ export function initMetaBuildingRegistry() {
|
||||
// Rotater
|
||||
registerBuildingVariant(11, MetaRotaterBuilding);
|
||||
registerBuildingVariant(12, MetaRotaterBuilding, enumRotaterVariants.ccw);
|
||||
registerBuildingVariant(13, MetaRotaterBuilding, enumRotaterVariants.fl);
|
||||
registerBuildingVariant(13, MetaRotaterBuilding, enumRotaterVariants.rotate180);
|
||||
|
||||
// Stacker
|
||||
registerBuildingVariant(14, MetaStackerBuilding);
|
||||
|
@ -487,10 +487,10 @@ export class ShapeDefinition extends BasicSerializableObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a definition which was rotated 180 degrees (flipped)
|
||||
* Returns a definition which was rotated 180 degrees
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
cloneRotateFL() {
|
||||
cloneRotate180() {
|
||||
const newLayers = this.internalCloneLayers();
|
||||
for (let layerIndex = 0; layerIndex < newLayers.length; ++layerIndex) {
|
||||
const quadrants = newLayers[layerIndex];
|
||||
|
@ -1,259 +1,259 @@
|
||||
import { createLogger } from "../core/logging";
|
||||
import { BasicSerializableObject } from "../savegame/serialization";
|
||||
import { enumColors } from "./colors";
|
||||
import { ShapeItem } from "./items/shape_item";
|
||||
import { GameRoot } from "./root";
|
||||
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
||||
|
||||
const logger = createLogger("shape_definition_manager");
|
||||
|
||||
export class ShapeDefinitionManager extends BasicSerializableObject {
|
||||
static getId() {
|
||||
return "ShapeDefinitionManager";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
constructor(root) {
|
||||
super();
|
||||
this.root = root;
|
||||
|
||||
/**
|
||||
* Store a cache from key -> definition
|
||||
* @type {Object<string, ShapeDefinition>}
|
||||
*/
|
||||
this.shapeKeyToDefinition = {};
|
||||
|
||||
/**
|
||||
* Store a cache from key -> item
|
||||
*/
|
||||
this.shapeKeyToItem = {};
|
||||
|
||||
// Caches operations in the form of 'operation:def1[:def2]'
|
||||
/** @type {Object.<string, Array<ShapeDefinition>|ShapeDefinition>} */
|
||||
this.operationCache = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shape instance from a given short key
|
||||
* @param {string} hash
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
getShapeFromShortKey(hash) {
|
||||
const cached = this.shapeKeyToDefinition[hash];
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
return (this.shapeKeyToDefinition[hash] = ShapeDefinition.fromShortKey(hash));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a item instance from a given short key
|
||||
* @param {string} hash
|
||||
* @returns {ShapeItem}
|
||||
*/
|
||||
getShapeItemFromShortKey(hash) {
|
||||
const cached = this.shapeKeyToItem[hash];
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const definition = this.getShapeFromShortKey(hash);
|
||||
return (this.shapeKeyToItem[hash] = new ShapeItem(definition));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shape item for a given definition
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {ShapeItem}
|
||||
*/
|
||||
getShapeItemFromDefinition(definition) {
|
||||
return this.getShapeItemFromShortKey(definition.getHash());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new shape definition
|
||||
* @param {ShapeDefinition} definition
|
||||
*/
|
||||
registerShapeDefinition(definition) {
|
||||
const id = definition.getHash();
|
||||
assert(!this.shapeKeyToDefinition[id], "Shape Definition " + id + " already exists");
|
||||
this.shapeKeyToDefinition[id] = definition;
|
||||
// logger.log("Registered shape with key", id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for splitting a shape definition in two halfs
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {[ShapeDefinition, ShapeDefinition]}
|
||||
*/
|
||||
shapeActionCutHalf(definition) {
|
||||
const key = "cut:" + definition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key]);
|
||||
}
|
||||
const rightSide = definition.cloneFilteredByQuadrants([2, 3]);
|
||||
const leftSide = definition.cloneFilteredByQuadrants([0, 1]);
|
||||
|
||||
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key] = [
|
||||
this.registerOrReturnHandle(rightSide),
|
||||
this.registerOrReturnHandle(leftSide),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for splitting a shape definition in four quads
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {[ShapeDefinition, ShapeDefinition, ShapeDefinition, ShapeDefinition]}
|
||||
*/
|
||||
shapeActionCutQuad(definition) {
|
||||
const key = "cut-quad:" + definition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {[ShapeDefinition, ShapeDefinition, ShapeDefinition, ShapeDefinition]} */ (this
|
||||
.operationCache[key]);
|
||||
}
|
||||
|
||||
return /** @type {[ShapeDefinition, ShapeDefinition, ShapeDefinition, ShapeDefinition]} */ (this.operationCache[
|
||||
key
|
||||
] = [
|
||||
this.registerOrReturnHandle(definition.cloneFilteredByQuadrants([0])),
|
||||
this.registerOrReturnHandle(definition.cloneFilteredByQuadrants([1])),
|
||||
this.registerOrReturnHandle(definition.cloneFilteredByQuadrants([2])),
|
||||
this.registerOrReturnHandle(definition.cloneFilteredByQuadrants([3])),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for rotating a shape clockwise
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionRotateCW(definition) {
|
||||
const key = "rotate-cw:" + definition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
|
||||
const rotated = definition.cloneRotateCW();
|
||||
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
rotated
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for rotating a shape counter clockwise
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionRotateCCW(definition) {
|
||||
const key = "rotate-ccw:" + definition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
|
||||
const rotated = definition.cloneRotateCCW();
|
||||
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
rotated
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for rotating a shape counter clockwise
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionRotateFL(definition) {
|
||||
const key = "rotate-fl:" + definition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
|
||||
const rotated = definition.cloneRotateFL();
|
||||
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
rotated
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for stacking the upper definition onto the lower one
|
||||
* @param {ShapeDefinition} lowerDefinition
|
||||
* @param {ShapeDefinition} upperDefinition
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionStack(lowerDefinition, upperDefinition) {
|
||||
const key = "stack:" + lowerDefinition.getHash() + ":" + upperDefinition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
const stacked = lowerDefinition.cloneAndStackWith(upperDefinition);
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
stacked
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for painting it with the given color
|
||||
* @param {ShapeDefinition} definition
|
||||
* @param {enumColors} color
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionPaintWith(definition, color) {
|
||||
const key = "paint:" + definition.getHash() + ":" + color;
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
const colorized = definition.cloneAndPaintWith(color);
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
colorized
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for painting it with the 4 colors
|
||||
* @param {ShapeDefinition} definition
|
||||
* @param {[enumColors, enumColors, enumColors, enumColors]} colors
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionPaintWith4Colors(definition, colors) {
|
||||
const key = "paint4:" + definition.getHash() + ":" + colors.join(",");
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
const colorized = definition.cloneAndPaintWith4Colors(colors);
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
colorized
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we already have cached this definition, and if so throws it away and returns the already
|
||||
* cached variant
|
||||
* @param {ShapeDefinition} definition
|
||||
*/
|
||||
registerOrReturnHandle(definition) {
|
||||
const id = definition.getHash();
|
||||
if (this.shapeKeyToDefinition[id]) {
|
||||
return this.shapeKeyToDefinition[id];
|
||||
}
|
||||
this.shapeKeyToDefinition[id] = definition;
|
||||
// logger.log("Registered shape with key (2)", id);
|
||||
return definition;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {[enumSubShape, enumSubShape, enumSubShape, enumSubShape]} subShapes
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
getDefinitionFromSimpleShapes(subShapes, color = enumColors.uncolored) {
|
||||
const shapeLayer = /** @type {import("./shape_definition").ShapeLayer} */ (subShapes.map(
|
||||
subShape => ({ subShape, color })
|
||||
));
|
||||
|
||||
return this.registerOrReturnHandle(new ShapeDefinition({ layers: [shapeLayer] }));
|
||||
}
|
||||
}
|
||||
import { createLogger } from "../core/logging";
|
||||
import { BasicSerializableObject } from "../savegame/serialization";
|
||||
import { enumColors } from "./colors";
|
||||
import { ShapeItem } from "./items/shape_item";
|
||||
import { GameRoot } from "./root";
|
||||
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
||||
|
||||
const logger = createLogger("shape_definition_manager");
|
||||
|
||||
export class ShapeDefinitionManager extends BasicSerializableObject {
|
||||
static getId() {
|
||||
return "ShapeDefinitionManager";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
constructor(root) {
|
||||
super();
|
||||
this.root = root;
|
||||
|
||||
/**
|
||||
* Store a cache from key -> definition
|
||||
* @type {Object<string, ShapeDefinition>}
|
||||
*/
|
||||
this.shapeKeyToDefinition = {};
|
||||
|
||||
/**
|
||||
* Store a cache from key -> item
|
||||
*/
|
||||
this.shapeKeyToItem = {};
|
||||
|
||||
// Caches operations in the form of 'operation:def1[:def2]'
|
||||
/** @type {Object.<string, Array<ShapeDefinition>|ShapeDefinition>} */
|
||||
this.operationCache = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shape instance from a given short key
|
||||
* @param {string} hash
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
getShapeFromShortKey(hash) {
|
||||
const cached = this.shapeKeyToDefinition[hash];
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
return (this.shapeKeyToDefinition[hash] = ShapeDefinition.fromShortKey(hash));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a item instance from a given short key
|
||||
* @param {string} hash
|
||||
* @returns {ShapeItem}
|
||||
*/
|
||||
getShapeItemFromShortKey(hash) {
|
||||
const cached = this.shapeKeyToItem[hash];
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const definition = this.getShapeFromShortKey(hash);
|
||||
return (this.shapeKeyToItem[hash] = new ShapeItem(definition));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shape item for a given definition
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {ShapeItem}
|
||||
*/
|
||||
getShapeItemFromDefinition(definition) {
|
||||
return this.getShapeItemFromShortKey(definition.getHash());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new shape definition
|
||||
* @param {ShapeDefinition} definition
|
||||
*/
|
||||
registerShapeDefinition(definition) {
|
||||
const id = definition.getHash();
|
||||
assert(!this.shapeKeyToDefinition[id], "Shape Definition " + id + " already exists");
|
||||
this.shapeKeyToDefinition[id] = definition;
|
||||
// logger.log("Registered shape with key", id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for splitting a shape definition in two halfs
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {[ShapeDefinition, ShapeDefinition]}
|
||||
*/
|
||||
shapeActionCutHalf(definition) {
|
||||
const key = "cut:" + definition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key]);
|
||||
}
|
||||
const rightSide = definition.cloneFilteredByQuadrants([2, 3]);
|
||||
const leftSide = definition.cloneFilteredByQuadrants([0, 1]);
|
||||
|
||||
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key] = [
|
||||
this.registerOrReturnHandle(rightSide),
|
||||
this.registerOrReturnHandle(leftSide),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for splitting a shape definition in four quads
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {[ShapeDefinition, ShapeDefinition, ShapeDefinition, ShapeDefinition]}
|
||||
*/
|
||||
shapeActionCutQuad(definition) {
|
||||
const key = "cut-quad:" + definition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {[ShapeDefinition, ShapeDefinition, ShapeDefinition, ShapeDefinition]} */ (this
|
||||
.operationCache[key]);
|
||||
}
|
||||
|
||||
return /** @type {[ShapeDefinition, ShapeDefinition, ShapeDefinition, ShapeDefinition]} */ (this.operationCache[
|
||||
key
|
||||
] = [
|
||||
this.registerOrReturnHandle(definition.cloneFilteredByQuadrants([0])),
|
||||
this.registerOrReturnHandle(definition.cloneFilteredByQuadrants([1])),
|
||||
this.registerOrReturnHandle(definition.cloneFilteredByQuadrants([2])),
|
||||
this.registerOrReturnHandle(definition.cloneFilteredByQuadrants([3])),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for rotating a shape clockwise
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionRotateCW(definition) {
|
||||
const key = "rotate-cw:" + definition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
|
||||
const rotated = definition.cloneRotateCW();
|
||||
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
rotated
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for rotating a shape counter clockwise
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionRotateCCW(definition) {
|
||||
const key = "rotate-ccw:" + definition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
|
||||
const rotated = definition.cloneRotateCCW();
|
||||
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
rotated
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for rotating a shape FL
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionRotate180(definition) {
|
||||
const key = "rotate-fl:" + definition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
|
||||
const rotated = definition.cloneRotate180();
|
||||
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
rotated
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for stacking the upper definition onto the lower one
|
||||
* @param {ShapeDefinition} lowerDefinition
|
||||
* @param {ShapeDefinition} upperDefinition
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionStack(lowerDefinition, upperDefinition) {
|
||||
const key = "stack:" + lowerDefinition.getHash() + ":" + upperDefinition.getHash();
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
const stacked = lowerDefinition.cloneAndStackWith(upperDefinition);
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
stacked
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for painting it with the given color
|
||||
* @param {ShapeDefinition} definition
|
||||
* @param {enumColors} color
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionPaintWith(definition, color) {
|
||||
const key = "paint:" + definition.getHash() + ":" + color;
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
const colorized = definition.cloneAndPaintWith(color);
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
colorized
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a definition for painting it with the 4 colors
|
||||
* @param {ShapeDefinition} definition
|
||||
* @param {[enumColors, enumColors, enumColors, enumColors]} colors
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionPaintWith4Colors(definition, colors) {
|
||||
const key = "paint4:" + definition.getHash() + ":" + colors.join(",");
|
||||
if (this.operationCache[key]) {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
const colorized = definition.cloneAndPaintWith4Colors(colors);
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||
colorized
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we already have cached this definition, and if so throws it away and returns the already
|
||||
* cached variant
|
||||
* @param {ShapeDefinition} definition
|
||||
*/
|
||||
registerOrReturnHandle(definition) {
|
||||
const id = definition.getHash();
|
||||
if (this.shapeKeyToDefinition[id]) {
|
||||
return this.shapeKeyToDefinition[id];
|
||||
}
|
||||
this.shapeKeyToDefinition[id] = definition;
|
||||
// logger.log("Registered shape with key (2)", id);
|
||||
return definition;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {[enumSubShape, enumSubShape, enumSubShape, enumSubShape]} subShapes
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
getDefinitionFromSimpleShapes(subShapes, color = enumColors.uncolored) {
|
||||
const shapeLayer = /** @type {import("./shape_definition").ShapeLayer} */ (subShapes.map(
|
||||
subShape => ({ subShape, color })
|
||||
));
|
||||
|
||||
return this.registerOrReturnHandle(new ShapeDefinition({ layers: [shapeLayer] }));
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,56 @@ import { ShapeItem } from "../items/shape_item";
|
||||
*/
|
||||
const MAX_QUEUED_CHARGES = 2;
|
||||
|
||||
/**
|
||||
* Whole data for a produced item
|
||||
*
|
||||
* @typedef {{
|
||||
* item: BaseItem,
|
||||
* preferredSlot?: number,
|
||||
* requiredSlot?: number,
|
||||
* doNotTrack?: boolean
|
||||
* }} ProducedItem
|
||||
*/
|
||||
|
||||
/**
|
||||
* Type of a processor implementation
|
||||
* @typedef {{
|
||||
* entity: Entity,
|
||||
* items: Array<{ item: BaseItem, sourceSlot: number }>,
|
||||
* itemsBySlot: Object<number, BaseItem>,
|
||||
* outItems: Array<ProducedItem>
|
||||
* }} ProcessorImplementationPayload
|
||||
*/
|
||||
|
||||
export class ItemProcessorSystem extends GameSystemWithFilter {
|
||||
constructor(root) {
|
||||
super(root, [ItemProcessorComponent]);
|
||||
|
||||
/**
|
||||
* @type {Object<enumItemProcessorTypes, function(ProcessorImplementationPayload) : string>}
|
||||
*/
|
||||
this.handlers = {
|
||||
[enumItemProcessorTypes.splitter]: this.process_SPLITTER,
|
||||
[enumItemProcessorTypes.cutter]: this.process_CUTTER,
|
||||
[enumItemProcessorTypes.cutterQuad]: this.process_CUTTER_QUAD,
|
||||
[enumItemProcessorTypes.rotater]: this.process_ROTATER,
|
||||
[enumItemProcessorTypes.rotaterCCW]: this.process_ROTATER_CCW,
|
||||
[enumItemProcessorTypes.rotater180]: this.process_ROTATER_180,
|
||||
[enumItemProcessorTypes.stacker]: this.process_STACKER,
|
||||
[enumItemProcessorTypes.trash]: this.process_TRASH,
|
||||
[enumItemProcessorTypes.mixer]: this.process_MIXER,
|
||||
[enumItemProcessorTypes.painter]: this.process_PAINTER,
|
||||
[enumItemProcessorTypes.painterDouble]: this.process_PAINTER_DOUBLE,
|
||||
[enumItemProcessorTypes.painterQuad]: this.process_PAINTER_QUAD,
|
||||
[enumItemProcessorTypes.hub]: this.process_HUB,
|
||||
[enumItemProcessorTypes.filter]: this.process_FILTER,
|
||||
[enumItemProcessorTypes.reader]: this.process_READER,
|
||||
};
|
||||
|
||||
// Bind all handlers
|
||||
for (const key in this.handlers) {
|
||||
this.handlers[key] = this.handlers[key].bind(this);
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
@ -238,310 +285,30 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
||||
const items = processorComp.inputSlots;
|
||||
processorComp.inputSlots = [];
|
||||
|
||||
/** @type {Object.<string, { item: BaseItem, sourceSlot: number }>} */
|
||||
/** @type {Object<string, BaseItem>} */
|
||||
const itemsBySlot = {};
|
||||
for (let i = 0; i < items.length; ++i) {
|
||||
itemsBySlot[items[i].sourceSlot] = items[i];
|
||||
itemsBySlot[items[i].sourceSlot] = items[i].item;
|
||||
}
|
||||
|
||||
/** @type {Array<{item: BaseItem, requiredSlot?: number, preferredSlot?: number}>} */
|
||||
/** @type {Array<ProducedItem>} */
|
||||
const outItems = [];
|
||||
|
||||
// Whether to track the production towards the analytics
|
||||
let trackProduction = true;
|
||||
/** @type {function(ProcessorImplementationPayload) : void} */
|
||||
const handler = this.handlers[processorComp.type];
|
||||
assert(handler, "No handler for processor type defined: " + processorComp.type);
|
||||
|
||||
// DO SOME MAGIC
|
||||
|
||||
switch (processorComp.type) {
|
||||
// SPLITTER
|
||||
case enumItemProcessorTypes.splitterWires:
|
||||
case enumItemProcessorTypes.splitter: {
|
||||
trackProduction = false;
|
||||
const availableSlots = entity.components.ItemEjector.slots.length;
|
||||
|
||||
let nextSlot = processorComp.nextOutputSlot++ % availableSlots;
|
||||
for (let i = 0; i < items.length; ++i) {
|
||||
outItems.push({
|
||||
item: items[i].item,
|
||||
preferredSlot: (nextSlot + i) % availableSlots,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// CUTTER
|
||||
case enumItemProcessorTypes.cutter: {
|
||||
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
||||
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
|
||||
const inputDefinition = inputItem.definition;
|
||||
|
||||
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutHalf(inputDefinition);
|
||||
|
||||
for (let i = 0; i < cutDefinitions.length; ++i) {
|
||||
const definition = cutDefinitions[i];
|
||||
if (!definition.isEntirelyEmpty()) {
|
||||
outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
|
||||
requiredSlot: i,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// CUTTER (Quad)
|
||||
case enumItemProcessorTypes.cutterQuad: {
|
||||
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
||||
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
|
||||
const inputDefinition = inputItem.definition;
|
||||
|
||||
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutQuad(inputDefinition);
|
||||
|
||||
for (let i = 0; i < cutDefinitions.length; ++i) {
|
||||
const definition = cutDefinitions[i];
|
||||
if (!definition.isEntirelyEmpty()) {
|
||||
outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
|
||||
requiredSlot: i,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// ROTATER
|
||||
case enumItemProcessorTypes.rotater: {
|
||||
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
||||
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
||||
const inputDefinition = inputItem.definition;
|
||||
|
||||
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(inputDefinition);
|
||||
outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// ROTATER (CCW)
|
||||
case enumItemProcessorTypes.rotaterCCW: {
|
||||
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
||||
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
||||
const inputDefinition = inputItem.definition;
|
||||
|
||||
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCCW(inputDefinition);
|
||||
outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// ROTATER (FL)
|
||||
case enumItemProcessorTypes.rotaterFL: {
|
||||
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
||||
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
||||
const inputDefinition = inputItem.definition;
|
||||
|
||||
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateFL(inputDefinition);
|
||||
outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// STACKER
|
||||
|
||||
case enumItemProcessorTypes.stacker: {
|
||||
const lowerItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
||||
const upperItem = /** @type {ShapeItem} */ (itemsBySlot[1].item);
|
||||
|
||||
assert(lowerItem instanceof ShapeItem, "Input for lower stack is not a shape");
|
||||
assert(upperItem instanceof ShapeItem, "Input for upper stack is not a shape");
|
||||
|
||||
const stackedDefinition = this.root.shapeDefinitionMgr.shapeActionStack(
|
||||
lowerItem.definition,
|
||||
upperItem.definition
|
||||
);
|
||||
outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(stackedDefinition),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// TRASH
|
||||
|
||||
case enumItemProcessorTypes.trash: {
|
||||
// Well this one is easy .. simply do nothing with the item
|
||||
break;
|
||||
}
|
||||
|
||||
// MIXER
|
||||
|
||||
case enumItemProcessorTypes.mixer: {
|
||||
// Find both colors and combine them
|
||||
const item1 = /** @type {ColorItem} */ (items[0].item);
|
||||
const item2 = /** @type {ColorItem} */ (items[1].item);
|
||||
assert(item1 instanceof ColorItem, "Input for color mixer is not a color");
|
||||
assert(item2 instanceof ColorItem, "Input for color mixer is not a color");
|
||||
|
||||
const color1 = item1.color;
|
||||
const color2 = item2.color;
|
||||
|
||||
// Try finding mixer color, and if we can't mix it we simply return the same color
|
||||
const mixedColor = enumColorMixingResults[color1][color2];
|
||||
let resultColor = color1;
|
||||
if (mixedColor) {
|
||||
resultColor = mixedColor;
|
||||
}
|
||||
outItems.push({
|
||||
item: COLOR_ITEM_SINGLETONS[resultColor],
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// PAINTER
|
||||
|
||||
case enumItemProcessorTypes.painter: {
|
||||
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
||||
const colorItem = /** @type {ColorItem} */ (itemsBySlot[1].item);
|
||||
|
||||
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||
shapeItem.definition,
|
||||
colorItem.color
|
||||
);
|
||||
|
||||
outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// PAINTER (DOUBLE)
|
||||
|
||||
case enumItemProcessorTypes.painterDouble: {
|
||||
const shapeItem1 = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
||||
const shapeItem2 = /** @type {ShapeItem} */ (itemsBySlot[1].item);
|
||||
const colorItem = /** @type {ColorItem} */ (itemsBySlot[2].item);
|
||||
|
||||
assert(shapeItem1 instanceof ShapeItem, "Input for painter is not a shape");
|
||||
assert(shapeItem2 instanceof ShapeItem, "Input for painter is not a shape");
|
||||
assert(colorItem instanceof ColorItem, "Input for painter is not a color");
|
||||
|
||||
const colorizedDefinition1 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||
shapeItem1.definition,
|
||||
colorItem.color
|
||||
);
|
||||
|
||||
const colorizedDefinition2 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||
shapeItem2.definition,
|
||||
colorItem.color
|
||||
);
|
||||
outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition1),
|
||||
});
|
||||
|
||||
outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition2),
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// PAINTER (QUAD)
|
||||
|
||||
case enumItemProcessorTypes.painterQuad: {
|
||||
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
||||
assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape");
|
||||
|
||||
/** @type {Array<enumColors>} */
|
||||
const colors = [null, null, null, null];
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
if (itemsBySlot[i + 1]) {
|
||||
colors[i] = /** @type {ColorItem} */ (itemsBySlot[i + 1].item).color;
|
||||
}
|
||||
}
|
||||
|
||||
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors(
|
||||
shapeItem.definition,
|
||||
/** @type {[string, string, string, string]} */ (colors)
|
||||
);
|
||||
|
||||
outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// FILTER
|
||||
case enumItemProcessorTypes.filter: {
|
||||
// TODO
|
||||
trackProduction = false;
|
||||
|
||||
const item = itemsBySlot[0].item;
|
||||
|
||||
const network = entity.components.WiredPins.slots[0].linkedNetwork;
|
||||
if (!network || !network.currentValue) {
|
||||
outItems.push({
|
||||
item,
|
||||
requiredSlot: 1,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
const value = network.currentValue;
|
||||
if (value.equals(BOOL_TRUE_SINGLETON) || value.equals(item)) {
|
||||
outItems.push({
|
||||
item,
|
||||
requiredSlot: 0,
|
||||
});
|
||||
} else {
|
||||
outItems.push({
|
||||
item,
|
||||
requiredSlot: 1,
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// READER
|
||||
case enumItemProcessorTypes.reader: {
|
||||
// Pass through the item
|
||||
const item = itemsBySlot[0].item;
|
||||
outItems.push({ item });
|
||||
|
||||
// Track the item
|
||||
const readerComp = entity.components.BeltReader;
|
||||
readerComp.lastItemTimes.push(this.root.time.now());
|
||||
readerComp.lastItem = item;
|
||||
break;
|
||||
}
|
||||
|
||||
// HUB
|
||||
case enumItemProcessorTypes.hub: {
|
||||
trackProduction = false;
|
||||
|
||||
const hubComponent = entity.components.Hub;
|
||||
assert(hubComponent, "Hub item processor has no hub component");
|
||||
|
||||
for (let i = 0; i < items.length; ++i) {
|
||||
const item = /** @type {ShapeItem} */ (items[i].item);
|
||||
this.root.hubGoals.handleDefinitionDelivered(item.definition);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assertAlways(false, "Unkown item processor type: " + processorComp.type);
|
||||
}
|
||||
// Call implementation
|
||||
handler({
|
||||
entity,
|
||||
items,
|
||||
itemsBySlot,
|
||||
outItems,
|
||||
});
|
||||
|
||||
// Track produced items
|
||||
if (trackProduction) {
|
||||
for (let i = 0; i < outItems.length; ++i) {
|
||||
for (let i = 0; i < outItems.length; ++i) {
|
||||
if (!outItems[i].doNotTrack) {
|
||||
this.root.signals.itemProduced.dispatch(outItems[i].item);
|
||||
}
|
||||
}
|
||||
@ -559,4 +326,292 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
||||
remainingTime: timeToProcess,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_SPLITTER(payload) {
|
||||
// trackProduction = false;
|
||||
const availableSlots = payload.entity.components.ItemEjector.slots.length;
|
||||
const processorComp = payload.entity.components.ItemProcessor;
|
||||
|
||||
const nextSlot = processorComp.nextOutputSlot++ % availableSlots;
|
||||
|
||||
for (let i = 0; i < payload.items.length; ++i) {
|
||||
payload.outItems.push({
|
||||
item: payload.items[i].item,
|
||||
preferredSlot: (nextSlot + i) % availableSlots,
|
||||
doNotTrack: true,
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_CUTTER(payload) {
|
||||
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item);
|
||||
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
|
||||
const inputDefinition = inputItem.definition;
|
||||
|
||||
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutHalf(inputDefinition);
|
||||
|
||||
for (let i = 0; i < cutDefinitions.length; ++i) {
|
||||
const definition = cutDefinitions[i];
|
||||
if (!definition.isEntirelyEmpty()) {
|
||||
payload.outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
|
||||
requiredSlot: i,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_CUTTER_QUAD(payload) {
|
||||
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item);
|
||||
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
|
||||
const inputDefinition = inputItem.definition;
|
||||
|
||||
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutQuad(inputDefinition);
|
||||
|
||||
for (let i = 0; i < cutDefinitions.length; ++i) {
|
||||
const definition = cutDefinitions[i];
|
||||
if (!definition.isEntirelyEmpty()) {
|
||||
payload.outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
|
||||
requiredSlot: i,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_ROTATER(payload) {
|
||||
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item);
|
||||
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
||||
const inputDefinition = inputItem.definition;
|
||||
|
||||
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(inputDefinition);
|
||||
payload.outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_ROTATER_CCW(payload) {
|
||||
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item);
|
||||
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
||||
const inputDefinition = inputItem.definition;
|
||||
|
||||
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCCW(inputDefinition);
|
||||
payload.outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_ROTATER_180(payload) {
|
||||
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item);
|
||||
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
||||
const inputDefinition = inputItem.definition;
|
||||
|
||||
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotate180(inputDefinition);
|
||||
payload.outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_STACKER(payload) {
|
||||
const lowerItem = /** @type {ShapeItem} */ (payload.itemsBySlot[0]);
|
||||
const upperItem = /** @type {ShapeItem} */ (payload.itemsBySlot[1]);
|
||||
|
||||
assert(lowerItem instanceof ShapeItem, "Input for lower stack is not a shape");
|
||||
assert(upperItem instanceof ShapeItem, "Input for upper stack is not a shape");
|
||||
|
||||
const stackedDefinition = this.root.shapeDefinitionMgr.shapeActionStack(
|
||||
lowerItem.definition,
|
||||
upperItem.definition
|
||||
);
|
||||
payload.outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(stackedDefinition),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_TRASH(payload) {
|
||||
// Do nothing ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_MIXER(payload) {
|
||||
// Find both colors and combine them
|
||||
const item1 = /** @type {ColorItem} */ (payload.items[0].item);
|
||||
const item2 = /** @type {ColorItem} */ (payload.items[1].item);
|
||||
assert(item1 instanceof ColorItem, "Input for color mixer is not a color");
|
||||
assert(item2 instanceof ColorItem, "Input for color mixer is not a color");
|
||||
|
||||
const color1 = item1.color;
|
||||
const color2 = item2.color;
|
||||
|
||||
// Try finding mixer color, and if we can't mix it we simply return the same color
|
||||
const mixedColor = enumColorMixingResults[color1][color2];
|
||||
let resultColor = color1;
|
||||
if (mixedColor) {
|
||||
resultColor = mixedColor;
|
||||
}
|
||||
payload.outItems.push({
|
||||
item: COLOR_ITEM_SINGLETONS[resultColor],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_PAINTER(payload) {
|
||||
const shapeItem = /** @type {ShapeItem} */ (payload.itemsBySlot[0]);
|
||||
const colorItem = /** @type {ColorItem} */ (payload.itemsBySlot[1]);
|
||||
|
||||
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||
shapeItem.definition,
|
||||
colorItem.color
|
||||
);
|
||||
|
||||
payload.outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_PAINTER_DOUBLE(payload) {
|
||||
const shapeItem1 = /** @type {ShapeItem} */ (payload.itemsBySlot[0]);
|
||||
const shapeItem2 = /** @type {ShapeItem} */ (payload.itemsBySlot[1]);
|
||||
const colorItem = /** @type {ColorItem} */ (payload.itemsBySlot[2]);
|
||||
|
||||
assert(shapeItem1 instanceof ShapeItem, "Input for painter is not a shape");
|
||||
assert(shapeItem2 instanceof ShapeItem, "Input for painter is not a shape");
|
||||
assert(colorItem instanceof ColorItem, "Input for painter is not a color");
|
||||
|
||||
const colorizedDefinition1 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||
shapeItem1.definition,
|
||||
colorItem.color
|
||||
);
|
||||
|
||||
const colorizedDefinition2 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||
shapeItem2.definition,
|
||||
colorItem.color
|
||||
);
|
||||
payload.outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition1),
|
||||
});
|
||||
|
||||
payload.outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition2),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_PAINTER_QUAD(payload) {
|
||||
const shapeItem = /** @type {ShapeItem} */ (payload.itemsBySlot[0]);
|
||||
assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape");
|
||||
|
||||
/** @type {Array<enumColors>} */
|
||||
const colors = [null, null, null, null];
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
if (payload.itemsBySlot[i + 1]) {
|
||||
colors[i] = /** @type {ColorItem} */ (payload.itemsBySlot[i + 1]).color;
|
||||
}
|
||||
}
|
||||
|
||||
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors(
|
||||
shapeItem.definition,
|
||||
/** @type {[string, string, string, string]} */ (colors)
|
||||
);
|
||||
|
||||
payload.outItems.push({
|
||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_FILTER(payload) {
|
||||
const item = payload.itemsBySlot[0];
|
||||
|
||||
const network = payload.entity.components.WiredPins.slots[0].linkedNetwork;
|
||||
if (!network || !network.currentValue) {
|
||||
payload.outItems.push({
|
||||
item,
|
||||
requiredSlot: 1,
|
||||
doNotTrack: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const value = network.currentValue;
|
||||
if (value.equals(BOOL_TRUE_SINGLETON) || value.equals(item)) {
|
||||
payload.outItems.push({
|
||||
item,
|
||||
requiredSlot: 0,
|
||||
doNotTrack: true,
|
||||
});
|
||||
} else {
|
||||
payload.outItems.push({
|
||||
item,
|
||||
requiredSlot: 1,
|
||||
doNotTrack: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_READER(payload) {
|
||||
// Pass through the item
|
||||
const item = payload.itemsBySlot[0];
|
||||
payload.outItems.push({
|
||||
item,
|
||||
doNotTrack: true,
|
||||
});
|
||||
|
||||
// Track the item
|
||||
const readerComp = payload.entity.components.BeltReader;
|
||||
readerComp.lastItemTimes.push(this.root.time.now());
|
||||
readerComp.lastItem = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ProcessorImplementationPayload} payload
|
||||
*/
|
||||
process_HUB(payload) {
|
||||
const hubComponent = payload.entity.components.Hub;
|
||||
assert(hubComponent, "Hub item processor has no hub component");
|
||||
|
||||
for (let i = 0; i < payload.items.length; ++i) {
|
||||
const item = /** @type {ShapeItem} */ (payload.items[i].item);
|
||||
this.root.hubGoals.handleDefinitionDelivered(item.definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ export const enumHubGoalRewards = {
|
||||
reward_tunnel: "reward_tunnel",
|
||||
|
||||
reward_rotater_ccw: "reward_rotater_ccw",
|
||||
reward_rotater_fl: "reward_rotater_fl",
|
||||
reward_rotater_180: "reward_rotater_fl",
|
||||
reward_miner_chainable: "reward_miner_chainable",
|
||||
reward_underground_belt_tier_2: "reward_underground_belt_tier_2",
|
||||
reward_splitter_compact: "reward_splitter_compact",
|
||||
|
@ -1,52 +1,52 @@
|
||||
import { MetaBuilding, defaultBuildingVariant } from "./meta_building";
|
||||
import { MetaCutterBuilding, enumCutterVariants } from "./buildings/cutter";
|
||||
import { MetaRotaterBuilding, enumRotaterVariants } from "./buildings/rotater";
|
||||
import { MetaPainterBuilding, enumPainterVariants } from "./buildings/painter";
|
||||
import { MetaMixerBuilding } from "./buildings/mixer";
|
||||
import { MetaStackerBuilding } from "./buildings/stacker";
|
||||
import { MetaSplitterBuilding, enumSplitterVariants } from "./buildings/splitter";
|
||||
import { MetaUndergroundBeltBuilding, enumUndergroundBeltVariants } from "./buildings/underground_belt";
|
||||
import { MetaMinerBuilding, enumMinerVariants } from "./buildings/miner";
|
||||
import { MetaTrashBuilding, enumTrashVariants } from "./buildings/trash";
|
||||
|
||||
/** @typedef {Array<[typeof MetaBuilding, string]>} TutorialGoalReward */
|
||||
|
||||
import { enumHubGoalRewards } from "./tutorial_goals";
|
||||
|
||||
/**
|
||||
* Helper method for proper types
|
||||
* @returns {TutorialGoalReward}
|
||||
*/
|
||||
const typed = x => x;
|
||||
|
||||
/**
|
||||
* Stores which reward unlocks what
|
||||
* @enum {TutorialGoalReward?}
|
||||
*/
|
||||
export const enumHubGoalRewardsToContentUnlocked = {
|
||||
[enumHubGoalRewards.reward_cutter_and_trash]: typed([[MetaCutterBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_rotater]: typed([[MetaRotaterBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_painter]: typed([[MetaPainterBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_mixer]: typed([[MetaMixerBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_stacker]: typed([[MetaStackerBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_splitter]: typed([[MetaSplitterBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_tunnel]: typed([[MetaUndergroundBeltBuilding, defaultBuildingVariant]]),
|
||||
|
||||
[enumHubGoalRewards.reward_rotater_ccw]: typed([[MetaRotaterBuilding, enumRotaterVariants.ccw]]),
|
||||
[enumHubGoalRewards.reward_rotater_fl]: typed([[MetaRotaterBuilding, enumRotaterVariants.fl]]),
|
||||
[enumHubGoalRewards.reward_miner_chainable]: typed([[MetaMinerBuilding, enumMinerVariants.chainable]]),
|
||||
[enumHubGoalRewards.reward_underground_belt_tier_2]: typed([
|
||||
[MetaUndergroundBeltBuilding, enumUndergroundBeltVariants.tier2],
|
||||
]),
|
||||
[enumHubGoalRewards.reward_splitter_compact]: typed([
|
||||
[MetaSplitterBuilding, enumSplitterVariants.compact],
|
||||
]),
|
||||
[enumHubGoalRewards.reward_cutter_quad]: typed([[MetaCutterBuilding, enumCutterVariants.quad]]),
|
||||
[enumHubGoalRewards.reward_painter_double]: typed([[MetaPainterBuilding, enumPainterVariants.double]]),
|
||||
[enumHubGoalRewards.reward_painter_quad]: typed([[MetaPainterBuilding, enumPainterVariants.quad]]),
|
||||
[enumHubGoalRewards.reward_storage]: typed([[MetaTrashBuilding, enumTrashVariants.storage]]),
|
||||
|
||||
[enumHubGoalRewards.reward_freeplay]: null,
|
||||
[enumHubGoalRewards.no_reward]: null,
|
||||
[enumHubGoalRewards.no_reward_freeplay]: null,
|
||||
};
|
||||
import { MetaBuilding, defaultBuildingVariant } from "./meta_building";
|
||||
import { MetaCutterBuilding, enumCutterVariants } from "./buildings/cutter";
|
||||
import { MetaRotaterBuilding, enumRotaterVariants } from "./buildings/rotater";
|
||||
import { MetaPainterBuilding, enumPainterVariants } from "./buildings/painter";
|
||||
import { MetaMixerBuilding } from "./buildings/mixer";
|
||||
import { MetaStackerBuilding } from "./buildings/stacker";
|
||||
import { MetaSplitterBuilding, enumSplitterVariants } from "./buildings/splitter";
|
||||
import { MetaUndergroundBeltBuilding, enumUndergroundBeltVariants } from "./buildings/underground_belt";
|
||||
import { MetaMinerBuilding, enumMinerVariants } from "./buildings/miner";
|
||||
import { MetaTrashBuilding, enumTrashVariants } from "./buildings/trash";
|
||||
|
||||
/** @typedef {Array<[typeof MetaBuilding, string]>} TutorialGoalReward */
|
||||
|
||||
import { enumHubGoalRewards } from "./tutorial_goals";
|
||||
|
||||
/**
|
||||
* Helper method for proper types
|
||||
* @returns {TutorialGoalReward}
|
||||
*/
|
||||
const typed = x => x;
|
||||
|
||||
/**
|
||||
* Stores which reward unlocks what
|
||||
* @enum {TutorialGoalReward?}
|
||||
*/
|
||||
export const enumHubGoalRewardsToContentUnlocked = {
|
||||
[enumHubGoalRewards.reward_cutter_and_trash]: typed([[MetaCutterBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_rotater]: typed([[MetaRotaterBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_painter]: typed([[MetaPainterBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_mixer]: typed([[MetaMixerBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_stacker]: typed([[MetaStackerBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_splitter]: typed([[MetaSplitterBuilding, defaultBuildingVariant]]),
|
||||
[enumHubGoalRewards.reward_tunnel]: typed([[MetaUndergroundBeltBuilding, defaultBuildingVariant]]),
|
||||
|
||||
[enumHubGoalRewards.reward_rotater_ccw]: typed([[MetaRotaterBuilding, enumRotaterVariants.ccw]]),
|
||||
[enumHubGoalRewards.reward_rotater_180]: typed([[MetaRotaterBuilding, enumRotaterVariants.rotate180]]),
|
||||
[enumHubGoalRewards.reward_miner_chainable]: typed([[MetaMinerBuilding, enumMinerVariants.chainable]]),
|
||||
[enumHubGoalRewards.reward_underground_belt_tier_2]: typed([
|
||||
[MetaUndergroundBeltBuilding, enumUndergroundBeltVariants.tier2],
|
||||
]),
|
||||
[enumHubGoalRewards.reward_splitter_compact]: typed([
|
||||
[MetaSplitterBuilding, enumSplitterVariants.compact],
|
||||
]),
|
||||
[enumHubGoalRewards.reward_cutter_quad]: typed([[MetaCutterBuilding, enumCutterVariants.quad]]),
|
||||
[enumHubGoalRewards.reward_painter_double]: typed([[MetaPainterBuilding, enumPainterVariants.double]]),
|
||||
[enumHubGoalRewards.reward_painter_quad]: typed([[MetaPainterBuilding, enumPainterVariants.quad]]),
|
||||
[enumHubGoalRewards.reward_storage]: typed([[MetaTrashBuilding, enumTrashVariants.storage]]),
|
||||
|
||||
[enumHubGoalRewards.reward_freeplay]: null,
|
||||
[enumHubGoalRewards.no_reward]: null,
|
||||
[enumHubGoalRewards.no_reward_freeplay]: null,
|
||||
};
|
||||
|
@ -2,5 +2,6 @@
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"checkJs": true
|
||||
}
|
||||
},
|
||||
"include": ["./**/*.js"]
|
||||
}
|
||||
|
@ -518,7 +518,7 @@ buildings:
|
||||
ccw:
|
||||
name: Rotate (CCW)
|
||||
description: Rotates shapes counter-clockwise by 90 degrees.
|
||||
fl:
|
||||
rotate180:
|
||||
name: Rotate (180)
|
||||
description: Rotates shapes by 180 degrees.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user