mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-13 13:04:03 +00:00
Add unstacker building
This commit is contained in:
parent
c6bf070287
commit
c23e4ff50b
@ -1,15 +1,17 @@
|
|||||||
import { globalConfig } from "../../core/config";
|
|
||||||
import { enumDirection, Vector } from "../../core/vector";
|
import { enumDirection, Vector } from "../../core/vector";
|
||||||
import { ItemAcceptorComponent, enumItemAcceptorItemFilter } from "../components/item_acceptor";
|
import { ItemAcceptorComponent, enumItemAcceptorItemFilter } from "../components/item_acceptor";
|
||||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||||
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
|
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
|
||||||
import { Entity } from "../entity";
|
import { Entity } from "../entity";
|
||||||
import { MetaBuilding } from "../meta_building";
|
import { defaultBuildingVariant, MetaBuilding } from "../meta_building";
|
||||||
import { GameRoot } from "../root";
|
import { GameRoot } from "../root";
|
||||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||||
import { formatItemsPerSecond } from "../../core/utils";
|
import { formatItemsPerSecond } from "../../core/utils";
|
||||||
import { T } from "../../translations";
|
import { T } from "../../translations";
|
||||||
|
|
||||||
|
/** @enum {string} */
|
||||||
|
export const enumStackerVariants = { unstacker: "unstacker" };
|
||||||
|
|
||||||
export class MetaStackerBuilding extends MetaBuilding {
|
export class MetaStackerBuilding extends MetaBuilding {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("stacker");
|
super("stacker");
|
||||||
@ -29,10 +31,24 @@ export class MetaStackerBuilding extends MetaBuilding {
|
|||||||
* @returns {Array<[string, string]>}
|
* @returns {Array<[string, string]>}
|
||||||
*/
|
*/
|
||||||
getAdditionalStatistics(root, variant) {
|
getAdditionalStatistics(root, variant) {
|
||||||
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.stacker);
|
const speed = root.hubGoals.getProcessorBaseSpeed(
|
||||||
|
variant === enumStackerVariants.unstacker
|
||||||
|
? enumItemProcessorTypes.unstacker
|
||||||
|
: enumItemProcessorTypes.stacker
|
||||||
|
);
|
||||||
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
|
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {GameRoot} root
|
||||||
|
*/
|
||||||
|
getAvailableVariants(root) {
|
||||||
|
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_unstacker)) {
|
||||||
|
return [defaultBuildingVariant, enumStackerVariants.unstacker];
|
||||||
|
}
|
||||||
|
return super.getAvailableVariants(root);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {GameRoot} root
|
* @param {GameRoot} root
|
||||||
*/
|
*/
|
||||||
@ -74,4 +90,54 @@ export class MetaStackerBuilding extends MetaBuilding {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Entity} entity
|
||||||
|
* @param {number} rotationVariant
|
||||||
|
* @param {string} variant
|
||||||
|
*/
|
||||||
|
updateVariants(entity, rotationVariant, variant) {
|
||||||
|
switch (variant) {
|
||||||
|
case defaultBuildingVariant: {
|
||||||
|
entity.components.ItemEjector.setSlots([
|
||||||
|
{ pos: new Vector(0, 0), direction: enumDirection.top },
|
||||||
|
]);
|
||||||
|
entity.components.ItemAcceptor.setSlots([
|
||||||
|
{
|
||||||
|
pos: new Vector(0, 0),
|
||||||
|
directions: [enumDirection.bottom],
|
||||||
|
filter: enumItemAcceptorItemFilter.shape,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pos: new Vector(1, 0),
|
||||||
|
directions: [enumDirection.bottom],
|
||||||
|
filter: enumItemAcceptorItemFilter.shape,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
entity.components.ItemProcessor.type = enumItemProcessorTypes.stacker;
|
||||||
|
entity.components.ItemProcessor.inputsPerCharge = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case enumStackerVariants.unstacker: {
|
||||||
|
entity.components.ItemEjector.setSlots([
|
||||||
|
{ pos: new Vector(0, 0), direction: enumDirection.top },
|
||||||
|
{ pos: new Vector(1, 0), direction: enumDirection.top },
|
||||||
|
]);
|
||||||
|
entity.components.ItemAcceptor.setSlots([
|
||||||
|
{
|
||||||
|
pos: new Vector(0, 0),
|
||||||
|
directions: [enumDirection.bottom],
|
||||||
|
filter: enumItemAcceptorItemFilter.shape,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
entity.components.ItemProcessor.type = enumItemProcessorTypes.unstacker;
|
||||||
|
entity.components.ItemProcessor.inputsPerCharge = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assertAlways(false, "Unknown stacker variant: " + variant);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ export const enumItemProcessorTypes = {
|
|||||||
rotater: "rotater",
|
rotater: "rotater",
|
||||||
rotaterCCW: "rotaterCCW",
|
rotaterCCW: "rotaterCCW",
|
||||||
stacker: "stacker",
|
stacker: "stacker",
|
||||||
|
unstacker: "unstacker",
|
||||||
trash: "trash",
|
trash: "trash",
|
||||||
mixer: "mixer",
|
mixer: "mixer",
|
||||||
painter: "painter",
|
painter: "painter",
|
||||||
|
@ -407,7 +407,8 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
case enumItemProcessorTypes.cutterQuad:
|
case enumItemProcessorTypes.cutterQuad:
|
||||||
case enumItemProcessorTypes.rotater:
|
case enumItemProcessorTypes.rotater:
|
||||||
case enumItemProcessorTypes.rotaterCCW:
|
case enumItemProcessorTypes.rotaterCCW:
|
||||||
case enumItemProcessorTypes.stacker: {
|
case enumItemProcessorTypes.stacker:
|
||||||
|
case enumItemProcessorTypes.unstacker: {
|
||||||
assert(
|
assert(
|
||||||
globalConfig.buildingSpeeds[processorType],
|
globalConfig.buildingSpeeds[processorType],
|
||||||
"Processor type has no speed set in globalConfig.buildingSpeeds: " + processorType
|
"Processor type has no speed set in globalConfig.buildingSpeeds: " + processorType
|
||||||
|
@ -465,6 +465,43 @@ export class ShapeDefinition extends BasicSerializableObject {
|
|||||||
return new ShapeDefinition({ layers: newLayers });
|
return new ShapeDefinition({ layers: newLayers });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stacks the given shape definition on top.
|
||||||
|
*/
|
||||||
|
cloneAndUnstack() {
|
||||||
|
const lowerLayers = this.internalCloneLayers();
|
||||||
|
|
||||||
|
if (this.isEntirelyEmpty()) {
|
||||||
|
assert(false, "Can not stack entirely empty definition");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there is only one layer
|
||||||
|
if (this.layers.length === 1) {
|
||||||
|
return [new ShapeDefinition({ layers: lowerLayers })];
|
||||||
|
}
|
||||||
|
|
||||||
|
let upperLayers = [];
|
||||||
|
|
||||||
|
layerCheck:
|
||||||
|
for (let i = lowerLayers.length - 1; i >= 0; --i) {
|
||||||
|
const layerToCheck = lowerLayers[i];
|
||||||
|
|
||||||
|
for (let quadrantIndex = 0; quadrantIndex < 4; ++quadrantIndex) {
|
||||||
|
// Check for a layer with items on it to remove
|
||||||
|
if (layerToCheck[quadrantIndex]) {
|
||||||
|
upperLayers.push(layerToCheck);
|
||||||
|
lowerLayers[i] = [null, null, null, null];
|
||||||
|
break layerCheck;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
new ShapeDefinition({ layers: lowerLayers }),
|
||||||
|
new ShapeDefinition({ layers: upperLayers }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clones the shape and colors everything in the given color
|
* Clones the shape and colors everything in the given color
|
||||||
* @param {enumColors} color
|
* @param {enumColors} color
|
||||||
|
@ -144,6 +144,21 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a definition for stacking the upper definition onto the lower one
|
||||||
|
* @param {ShapeDefinition} definition
|
||||||
|
* @returns {[ShapeDefinition, ShapeDefinition]}
|
||||||
|
*/
|
||||||
|
shapeActionUnstack(definition) {
|
||||||
|
const key = "unstack:" + definition.getHash();
|
||||||
|
if (this.operationCache[key]) {
|
||||||
|
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const unstacked = definition.cloneAndUnstack();
|
||||||
|
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key] = unstacked);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a definition for painting it with the given color
|
* Generates a definition for painting it with the given color
|
||||||
* @param {ShapeDefinition} definition
|
* @param {ShapeDefinition} definition
|
||||||
|
@ -23,7 +23,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
|||||||
// First of all, process the current recipe
|
// First of all, process the current recipe
|
||||||
processorComp.secondsUntilEject = Math_max(
|
processorComp.secondsUntilEject = Math_max(
|
||||||
0,
|
0,
|
||||||
processorComp.secondsUntilEject - this.root.dynamicTickrate.deltaSeconds
|
processorComp.secondsUntilEject - this.root.dynamicTickrate.deltaSeconds,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check if we have any finished items we can eject
|
// Check if we have any finished items we can eject
|
||||||
@ -196,7 +196,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
|||||||
|
|
||||||
const stackedDefinition = this.root.shapeDefinitionMgr.shapeActionStack(
|
const stackedDefinition = this.root.shapeDefinitionMgr.shapeActionStack(
|
||||||
lowerItem.definition,
|
lowerItem.definition,
|
||||||
upperItem.definition
|
upperItem.definition,
|
||||||
);
|
);
|
||||||
outItems.push({
|
outItems.push({
|
||||||
item: new ShapeItem(stackedDefinition),
|
item: new ShapeItem(stackedDefinition),
|
||||||
@ -204,6 +204,23 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UNSTACKER
|
||||||
|
|
||||||
|
case enumItemProcessorTypes.unstacker: {
|
||||||
|
const item = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
||||||
|
assert(item instanceof ShapeItem, "Input for unstack is not a shape");
|
||||||
|
|
||||||
|
const unstackedDefinitions = this.root.shapeDefinitionMgr.shapeActionUnstack(item.definition);
|
||||||
|
|
||||||
|
for (let i = 0; i < unstackedDefinitions.length; ++i) {
|
||||||
|
outItems.push({
|
||||||
|
item: new ShapeItem(unstackedDefinitions[i]),
|
||||||
|
requiredSlot: i,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// TRASH
|
// TRASH
|
||||||
|
|
||||||
case enumItemProcessorTypes.trash: {
|
case enumItemProcessorTypes.trash: {
|
||||||
@ -244,7 +261,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
|||||||
|
|
||||||
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||||
shapeItem.definition,
|
shapeItem.definition,
|
||||||
colorItem.color
|
colorItem.color,
|
||||||
);
|
);
|
||||||
|
|
||||||
outItems.push({
|
outItems.push({
|
||||||
@ -267,12 +284,12 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
|||||||
|
|
||||||
const colorizedDefinition1 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
const colorizedDefinition1 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||||
shapeItem1.definition,
|
shapeItem1.definition,
|
||||||
colorItem.color
|
colorItem.color,
|
||||||
);
|
);
|
||||||
|
|
||||||
const colorizedDefinition2 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
const colorizedDefinition2 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||||
shapeItem2.definition,
|
shapeItem2.definition,
|
||||||
colorItem.color
|
colorItem.color,
|
||||||
);
|
);
|
||||||
outItems.push({
|
outItems.push({
|
||||||
item: new ShapeItem(colorizedDefinition1),
|
item: new ShapeItem(colorizedDefinition1),
|
||||||
@ -302,7 +319,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
|||||||
|
|
||||||
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors(
|
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors(
|
||||||
shapeItem.definition,
|
shapeItem.definition,
|
||||||
[colorItem2.color, colorItem3.color, colorItem4.color, colorItem1.color]
|
[colorItem2.color, colorItem3.color, colorItem4.color, colorItem1.color],
|
||||||
);
|
);
|
||||||
|
|
||||||
outItems.push({
|
outItems.push({
|
||||||
|
@ -11,6 +11,7 @@ export const enumHubGoalRewards = {
|
|||||||
reward_painter: "reward_painter",
|
reward_painter: "reward_painter",
|
||||||
reward_mixer: "reward_mixer",
|
reward_mixer: "reward_mixer",
|
||||||
reward_stacker: "reward_stacker",
|
reward_stacker: "reward_stacker",
|
||||||
|
reward_unstacker: "reward_unstacker",
|
||||||
reward_splitter: "reward_splitter",
|
reward_splitter: "reward_splitter",
|
||||||
reward_tunnel: "reward_tunnel",
|
reward_tunnel: "reward_tunnel",
|
||||||
|
|
||||||
|
@ -341,6 +341,9 @@ buildings:
|
|||||||
default:
|
default:
|
||||||
name: &stacker Stacker
|
name: &stacker Stacker
|
||||||
description: Stacks both items. If they can not be merged, the right item is placed above the left item.
|
description: Stacks both items. If they can not be merged, the right item is placed above the left item.
|
||||||
|
unstacker:
|
||||||
|
name: Unstacker
|
||||||
|
description: Takes the top most shape off of a stack and outputs it onto the right.
|
||||||
|
|
||||||
mixer:
|
mixer:
|
||||||
default:
|
default:
|
||||||
|
Loading…
Reference in New Issue
Block a user