mirror of
https://github.com/tobspr/shapez.io.git
synced 2026-03-02 03:39:21 +00:00
Add quad cutter and painter
This commit is contained in:
@@ -97,6 +97,12 @@
|
||||
&[data-tile-w="2"] {
|
||||
@include S(width, 2 * $iconSize);
|
||||
}
|
||||
&[data-tile-w="3"] {
|
||||
@include S(width, 3 * $iconSize);
|
||||
}
|
||||
&[data-tile-w="4"] {
|
||||
@include S(width, 4 * $iconSize);
|
||||
}
|
||||
|
||||
&[data-tile-h="2"] {
|
||||
@include S(height, 2 * $iconSize);
|
||||
|
||||
@@ -46,10 +46,12 @@ export const globalConfig = {
|
||||
|
||||
buildingSpeeds: {
|
||||
cutter: 1 / 4,
|
||||
cutterQuad: 1 / 4,
|
||||
rotater: 1 / 1,
|
||||
rotaterCCW: 1 / 1,
|
||||
painter: 1 / 3,
|
||||
painterDouble: 1 / 3,
|
||||
painterQuad: 1 / 3,
|
||||
mixer: 1 / 2,
|
||||
stacker: 1 / 5,
|
||||
},
|
||||
@@ -74,7 +76,7 @@ export const globalConfig = {
|
||||
|
||||
debug: {
|
||||
/* dev:start */
|
||||
fastGameEnter: true,
|
||||
// fastGameEnter: true,
|
||||
noArtificialDelays: true,
|
||||
// disableSavegameWrite: true,
|
||||
showEntityBounds: false,
|
||||
|
||||
@@ -4,10 +4,13 @@ import { enumItemAcceptorItemFilter, ItemAcceptorComponent } from "../components
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumCutterVariants = { quad: "quad" };
|
||||
|
||||
export class MetaCutterBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("cutter");
|
||||
@@ -16,9 +19,15 @@ export class MetaCutterBuilding extends MetaBuilding {
|
||||
getSilhouetteColor() {
|
||||
return "#7dcda2";
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
return new Vector(2, 1);
|
||||
getDimensions(variant) {
|
||||
switch (variant) {
|
||||
case defaultBuildingVariant:
|
||||
return new Vector(2, 1);
|
||||
case enumCutterVariants.quad:
|
||||
return new Vector(4, 1);
|
||||
default:
|
||||
assertAlways(false, "Unknown splitter variant: " + variant);
|
||||
}
|
||||
}
|
||||
|
||||
getName() {
|
||||
@@ -29,6 +38,10 @@ export class MetaCutterBuilding extends MetaBuilding {
|
||||
return "Cuts shapes from top to bottom and outputs both halfs. <strong>If you use only one part, be sure to destroy the other part or it will stall!</strong>";
|
||||
}
|
||||
|
||||
getAvailableVariants(root) {
|
||||
return [defaultBuildingVariant, enumCutterVariants.quad];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
@@ -47,15 +60,7 @@ export class MetaCutterBuilding extends MetaBuilding {
|
||||
processorType: enumItemProcessorTypes.cutter,
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(
|
||||
new ItemEjectorComponent({
|
||||
slots: [
|
||||
{ pos: new Vector(0, 0), direction: enumDirection.top },
|
||||
{ pos: new Vector(1, 0), direction: enumDirection.top },
|
||||
],
|
||||
})
|
||||
);
|
||||
entity.addComponent(new ItemEjectorComponent({}));
|
||||
entity.addComponent(
|
||||
new ItemAcceptorComponent({
|
||||
slots: [
|
||||
@@ -68,4 +73,36 @@ export class MetaCutterBuilding 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 },
|
||||
{ pos: new Vector(1, 0), direction: enumDirection.top },
|
||||
]);
|
||||
entity.components.ItemProcessor.type = enumItemProcessorTypes.cutter;
|
||||
break;
|
||||
}
|
||||
case enumCutterVariants.quad: {
|
||||
entity.components.ItemEjector.setSlots([
|
||||
{ pos: new Vector(0, 0), direction: enumDirection.top },
|
||||
{ pos: new Vector(1, 0), direction: enumDirection.top },
|
||||
{ pos: new Vector(2, 0), direction: enumDirection.top },
|
||||
{ pos: new Vector(3, 0), direction: enumDirection.top },
|
||||
]);
|
||||
entity.components.ItemProcessor.type = enumItemProcessorTypes.cutterQuad;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assertAlways(false, "Unknown painter variant: " + variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
import { GameRoot } from "../root";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumPainterVariants = { double: "double" };
|
||||
export const enumPainterVariants = { double: "double", quad: "quad" };
|
||||
|
||||
export class MetaPainterBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
@@ -22,6 +22,8 @@ export class MetaPainterBuilding extends MetaBuilding {
|
||||
return new Vector(2, 1);
|
||||
case enumPainterVariants.double:
|
||||
return new Vector(2, 2);
|
||||
case enumPainterVariants.quad:
|
||||
return new Vector(4, 1);
|
||||
default:
|
||||
assertAlways(false, "Unknown painter variant: " + variant);
|
||||
}
|
||||
@@ -40,7 +42,7 @@ export class MetaPainterBuilding extends MetaBuilding {
|
||||
}
|
||||
|
||||
getAvailableVariants(root) {
|
||||
return [defaultBuildingVariant, enumPainterVariants.double];
|
||||
return [defaultBuildingVariant, enumPainterVariants.double, enumPainterVariants.quad];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,6 +106,9 @@ export class MetaPainterBuilding extends MetaBuilding {
|
||||
|
||||
entity.components.ItemProcessor.type = enumItemProcessorTypes.painter;
|
||||
entity.components.ItemProcessor.inputsPerCharge = 2;
|
||||
entity.components.ItemEjector.setSlots([
|
||||
{ pos: new Vector(1, 0), direction: enumDirection.right },
|
||||
]);
|
||||
break;
|
||||
}
|
||||
case enumPainterVariants.double: {
|
||||
@@ -127,6 +132,47 @@ export class MetaPainterBuilding extends MetaBuilding {
|
||||
|
||||
entity.components.ItemProcessor.type = enumItemProcessorTypes.painterDouble;
|
||||
entity.components.ItemProcessor.inputsPerCharge = 3;
|
||||
|
||||
entity.components.ItemEjector.setSlots([
|
||||
{ pos: new Vector(1, 0), direction: enumDirection.right },
|
||||
]);
|
||||
break;
|
||||
}
|
||||
case enumPainterVariants.quad: {
|
||||
entity.components.ItemAcceptor.setSlots([
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.left],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: enumItemAcceptorItemFilter.color,
|
||||
},
|
||||
{
|
||||
pos: new Vector(1, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: enumItemAcceptorItemFilter.color,
|
||||
},
|
||||
{
|
||||
pos: new Vector(2, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: enumItemAcceptorItemFilter.color,
|
||||
},
|
||||
{
|
||||
pos: new Vector(3, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: enumItemAcceptorItemFilter.color,
|
||||
},
|
||||
]);
|
||||
|
||||
entity.components.ItemProcessor.type = enumItemProcessorTypes.painterQuad;
|
||||
entity.components.ItemProcessor.inputsPerCharge = 5;
|
||||
|
||||
entity.components.ItemEjector.setSlots([
|
||||
{ pos: new Vector(0, 0), direction: enumDirection.top },
|
||||
]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -35,7 +35,7 @@ export class ItemEjectorComponent extends Component {
|
||||
/**
|
||||
*
|
||||
* @param {object} param0
|
||||
* @param {Array<{pos: Vector, direction: enumDirection}>} param0.slots The slots to eject on
|
||||
* @param {Array<{pos: Vector, direction: enumDirection}>=} param0.slots The slots to eject on
|
||||
* @param {boolean=} param0.instantEject If the ejection is instant
|
||||
*/
|
||||
constructor({ slots = [], instantEject = false }) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { gItemRegistry } from "../../core/global_registries";
|
||||
export const enumItemProcessorTypes = {
|
||||
splitter: "splitter",
|
||||
cutter: "cutter",
|
||||
cutterQuad: "cutterQuad",
|
||||
rotater: "rotater",
|
||||
rotaterCCW: "rotaterCCW",
|
||||
stacker: "stacker",
|
||||
@@ -15,6 +16,7 @@ export const enumItemProcessorTypes = {
|
||||
mixer: "mixer",
|
||||
painter: "painter",
|
||||
painterDouble: "painterDouble",
|
||||
painterQuad: "painterQuad",
|
||||
hub: "hub",
|
||||
};
|
||||
|
||||
|
||||
@@ -383,12 +383,14 @@ export class HubGoals extends BasicSerializableObject {
|
||||
case enumItemProcessorTypes.splitter:
|
||||
return globalConfig.beltSpeedItemsPerSecond * this.upgradeImprovements.belt * 2;
|
||||
case enumItemProcessorTypes.cutter:
|
||||
case enumItemProcessorTypes.cutterQuad:
|
||||
case enumItemProcessorTypes.rotater:
|
||||
case enumItemProcessorTypes.rotaterCCW:
|
||||
case enumItemProcessorTypes.stacker:
|
||||
case enumItemProcessorTypes.mixer:
|
||||
case enumItemProcessorTypes.painter:
|
||||
case enumItemProcessorTypes.painterDouble:
|
||||
case enumItemProcessorTypes.painterQuad:
|
||||
assert(
|
||||
globalConfig.buildingSpeeds[processorType],
|
||||
"Processor type has no speed set in globalConfig.buildingSpeeds: " + processorType
|
||||
|
||||
@@ -24,7 +24,7 @@ export class ColorItem extends BaseItem {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} color
|
||||
* @param {enumColors} color
|
||||
*/
|
||||
constructor(color) {
|
||||
super();
|
||||
|
||||
@@ -483,4 +483,23 @@ export class ShapeDefinition extends BasicSerializableObject {
|
||||
}
|
||||
return new ShapeDefinition({ layers: newLayers });
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the shape and colors everything in the given colors
|
||||
* @param {[enumColors, enumColors, enumColors, enumColors]} colors
|
||||
*/
|
||||
cloneAndPaintWith4Colors(colors) {
|
||||
const newLayers = this.internalCloneLayers();
|
||||
|
||||
for (let layerIndex = 0; layerIndex < newLayers.length; ++layerIndex) {
|
||||
const quadrants = newLayers[layerIndex];
|
||||
for (let quadrantIndex = 0; quadrantIndex < 4; ++quadrantIndex) {
|
||||
const item = quadrants[quadrantIndex];
|
||||
if (item) {
|
||||
item.color = colors[quadrantIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ShapeDefinition({ layers: newLayers });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,28 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -125,7 +147,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
||||
/**
|
||||
* Generates a definition for painting it with the given color
|
||||
* @param {ShapeDefinition} definition
|
||||
* @param {string} color
|
||||
* @param {enumColors} color
|
||||
* @returns {ShapeDefinition}
|
||||
*/
|
||||
shapeActionPaintWith(definition, color) {
|
||||
@@ -139,6 +161,23 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -151,22 +151,37 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
||||
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
|
||||
const inputDefinition = inputItem.definition;
|
||||
|
||||
const [cutDefinition1, cutDefinition2] = this.root.shapeDefinitionMgr.shapeActionCutHalf(
|
||||
inputDefinition
|
||||
);
|
||||
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutHalf(inputDefinition);
|
||||
|
||||
if (!cutDefinition1.isEntirelyEmpty()) {
|
||||
outItems.push({
|
||||
item: new ShapeItem(cutDefinition1),
|
||||
requiredSlot: 0,
|
||||
});
|
||||
for (let i = 0; i < cutDefinitions.length; ++i) {
|
||||
const definition = cutDefinitions[i];
|
||||
if (!definition.isEntirelyEmpty()) {
|
||||
outItems.push({
|
||||
item: new ShapeItem(definition),
|
||||
requiredSlot: i,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!cutDefinition2.isEntirelyEmpty()) {
|
||||
outItems.push({
|
||||
item: new ShapeItem(cutDefinition2),
|
||||
requiredSlot: 1,
|
||||
});
|
||||
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: new ShapeItem(definition),
|
||||
requiredSlot: i,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -298,6 +313,33 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
||||
break;
|
||||
}
|
||||
|
||||
// PAINTER (QUAD)
|
||||
|
||||
case enumItemProcessorTypes.painterQuad: {
|
||||
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
||||
const colorItem1 = /** @type {ColorItem} */ (itemsBySlot[1].item);
|
||||
const colorItem2 = /** @type {ColorItem} */ (itemsBySlot[2].item);
|
||||
const colorItem3 = /** @type {ColorItem} */ (itemsBySlot[3].item);
|
||||
const colorItem4 = /** @type {ColorItem} */ (itemsBySlot[4].item);
|
||||
|
||||
assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape");
|
||||
assert(colorItem1 instanceof ColorItem, "Input for painter is not a color");
|
||||
assert(colorItem2 instanceof ColorItem, "Input for painter is not a color");
|
||||
assert(colorItem3 instanceof ColorItem, "Input for painter is not a color");
|
||||
assert(colorItem4 instanceof ColorItem, "Input for painter is not a color");
|
||||
|
||||
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors(
|
||||
shapeItem.definition,
|
||||
[colorItem2.color, colorItem3.color, colorItem4.color, colorItem1.color]
|
||||
);
|
||||
|
||||
outItems.push({
|
||||
item: new ShapeItem(colorizedDefinition),
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// HUB
|
||||
|
||||
case enumItemProcessorTypes.hub: {
|
||||
|
||||
Reference in New Issue
Block a user