1
0
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:
tobspr
2020-05-17 00:21:33 +02:00
parent bce44188c8
commit cad6b357e3
25 changed files with 720 additions and 365 deletions

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);
}
}
}

View File

@@ -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:

View File

@@ -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 }) {

View File

@@ -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",
};

View File

@@ -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

View File

@@ -24,7 +24,7 @@ export class ColorItem extends BaseItem {
}
/**
* @param {string} color
* @param {enumColors} color
*/
constructor(color) {
super();

View File

@@ -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 });
}
}

View File

@@ -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

View File

@@ -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: {