1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2026-03-02 03:39:21 +00:00

Add 1x1 compact splitters

This commit is contained in:
tobspr
2020-08-28 21:28:29 +02:00
parent b6328cd9a0
commit 5459e6470b
16 changed files with 844 additions and 695 deletions

View File

@@ -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 enumCutterVariants = { quad: "quad" };
export class MetaCutterBuilding extends MetaBuilding {
constructor() {
super("cutter");
}
getSilhouetteColor() {
return "#7dcda2";
}
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);
}
}
/**
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
const speed = root.hubGoals.getProcessorBaseSpeed(
variant === enumCutterVariants.quad
? enumItemProcessorTypes.cutterQuad
: enumItemProcessorTypes.cutter
);
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
}
/**
* @param {GameRoot} root
*/
getAvailableVariants(root) {
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_cutter_quad)) {
return [defaultBuildingVariant, enumCutterVariants.quad];
}
return super.getAvailableVariants(root);
}
/**
* @param {GameRoot} root
*/
getIsUnlocked(root) {
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_cutter_and_trash);
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
entity.addComponent(
new ItemProcessorComponent({
inputsPerCharge: 1,
processorType: enumItemProcessorTypes.cutter,
})
);
entity.addComponent(new ItemEjectorComponent({}));
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.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);
}
}
}
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 enumCutterVariants = { quad: "quad" };
export class MetaCutterBuilding extends MetaBuilding {
constructor() {
super("cutter");
}
getSilhouetteColor() {
return "#7dcda2";
}
getDimensions(variant) {
switch (variant) {
case defaultBuildingVariant:
return new Vector(2, 1);
case enumCutterVariants.quad:
return new Vector(4, 1);
default:
assertAlways(false, "Unknown cutter variant: " + variant);
}
}
/**
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
const speed = root.hubGoals.getProcessorBaseSpeed(
variant === enumCutterVariants.quad
? enumItemProcessorTypes.cutterQuad
: enumItemProcessorTypes.cutter
);
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
}
/**
* @param {GameRoot} root
*/
getAvailableVariants(root) {
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_cutter_quad)) {
return [defaultBuildingVariant, enumCutterVariants.quad];
}
return super.getAvailableVariants(root);
}
/**
* @param {GameRoot} root
*/
getIsUnlocked(root) {
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_cutter_and_trash);
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
entity.addComponent(
new ItemProcessorComponent({
inputsPerCharge: 1,
processorType: enumItemProcessorTypes.cutter,
})
);
entity.addComponent(new ItemEjectorComponent({}));
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.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

@@ -1,158 +1,197 @@
import { enumDirection, Vector } from "../../core/vector";
import { ItemAcceptorComponent } from "../components/item_acceptor";
import { ItemEjectorComponent } from "../components/item_ejector";
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
import { Entity } from "../entity";
import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
import { GameRoot } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals";
import { T } from "../../translations";
import { formatItemsPerSecond } from "../../core/utils";
import { BeltUnderlaysComponent } from "../components/belt_underlays";
/** @enum {string} */
export const enumSplitterVariants = { compact: "compact", compactInverse: "compact-inverse" };
export class MetaSplitterBuilding extends MetaBuilding {
constructor() {
super("splitter");
}
getDimensions(variant) {
switch (variant) {
case defaultBuildingVariant:
return new Vector(2, 1);
case enumSplitterVariants.compact:
case enumSplitterVariants.compactInverse:
return new Vector(1, 1);
default:
assertAlways(false, "Unknown splitter variant: " + variant);
}
}
/**
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.splitter);
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
}
getSilhouetteColor() {
return "#444";
}
/**
* @param {GameRoot} root
*/
getAvailableVariants(root) {
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_splitter_compact)) {
return [
defaultBuildingVariant,
enumSplitterVariants.compact,
enumSplitterVariants.compactInverse,
];
}
return super.getAvailableVariants(root);
}
/**
* @param {GameRoot} root
*/
getIsUnlocked(root) {
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_splitter);
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
entity.addComponent(
new ItemAcceptorComponent({
slots: [], // set later
})
);
entity.addComponent(
new ItemProcessorComponent({
inputsPerCharge: 1,
processorType: enumItemProcessorTypes.splitter,
})
);
entity.addComponent(
new ItemEjectorComponent({
slots: [], // set later
})
);
entity.addComponent(new BeltUnderlaysComponent({ underlays: [] }));
}
/**
*
* @param {Entity} entity
* @param {number} rotationVariant
* @param {string} variant
*/
updateVariants(entity, rotationVariant, variant) {
switch (variant) {
case defaultBuildingVariant: {
entity.components.ItemAcceptor.setSlots([
{
pos: new Vector(0, 0),
directions: [enumDirection.bottom],
},
{
pos: new Vector(1, 0),
directions: [enumDirection.bottom],
},
]);
entity.components.ItemEjector.setSlots([
{ pos: new Vector(0, 0), direction: enumDirection.top },
{ pos: new Vector(1, 0), direction: enumDirection.top },
]);
entity.components.BeltUnderlays.underlays = [
{ pos: new Vector(0, 0), direction: enumDirection.top },
{ pos: new Vector(1, 0), direction: enumDirection.top },
];
break;
}
case enumSplitterVariants.compact:
case enumSplitterVariants.compactInverse: {
entity.components.ItemAcceptor.setSlots([
{
pos: new Vector(0, 0),
directions: [enumDirection.bottom],
},
{
pos: new Vector(0, 0),
directions: [
variant === enumSplitterVariants.compactInverse
? enumDirection.left
: enumDirection.right,
],
},
]);
entity.components.ItemEjector.setSlots([
{ pos: new Vector(0, 0), direction: enumDirection.top },
]);
entity.components.BeltUnderlays.underlays = [
{ pos: new Vector(0, 0), direction: enumDirection.top },
];
break;
}
default:
assertAlways(false, "Unknown painter variant: " + variant);
}
}
}
import { enumDirection, Vector } from "../../core/vector";
import { ItemAcceptorComponent } from "../components/item_acceptor";
import { ItemEjectorComponent } from "../components/item_ejector";
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
import { Entity } from "../entity";
import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
import { GameRoot } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals";
import { T } from "../../translations";
import { formatItemsPerSecond } from "../../core/utils";
import { BeltUnderlaysComponent } from "../components/belt_underlays";
/** @enum {string} */
export const enumSplitterVariants = {
compact: "compact",
compactInverse: "compact-inverse",
compactMerge: "compact-merge",
compactMergeInverse: "compact-merge-inverse",
};
export class MetaSplitterBuilding extends MetaBuilding {
constructor() {
super("splitter");
}
getDimensions(variant) {
switch (variant) {
case defaultBuildingVariant:
return new Vector(2, 1);
case enumSplitterVariants.compact:
case enumSplitterVariants.compactInverse:
case enumSplitterVariants.compactMerge:
case enumSplitterVariants.compactMergeInverse:
return new Vector(1, 1);
default:
assertAlways(false, "Unknown splitter variant: " + variant);
}
}
/**
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.splitter);
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
}
getSilhouetteColor() {
return "#444";
}
/**
* @param {GameRoot} root
*/
getAvailableVariants(root) {
let available = [defaultBuildingVariant];
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_splitter_compact)) {
available.push(enumSplitterVariants.compact, enumSplitterVariants.compactInverse);
}
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_merger_compact)) {
available.push(enumSplitterVariants.compactMerge, enumSplitterVariants.compactMergeInverse);
}
return available;
}
/**
* @param {GameRoot} root
*/
getIsUnlocked(root) {
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_splitter);
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
entity.addComponent(
new ItemAcceptorComponent({
slots: [], // set later
})
);
entity.addComponent(
new ItemProcessorComponent({
inputsPerCharge: 1,
processorType: enumItemProcessorTypes.splitter,
})
);
entity.addComponent(
new ItemEjectorComponent({
slots: [], // set later
})
);
entity.addComponent(new BeltUnderlaysComponent({ underlays: [] }));
}
/**
*
* @param {Entity} entity
* @param {number} rotationVariant
* @param {string} variant
*/
updateVariants(entity, rotationVariant, variant) {
switch (variant) {
case defaultBuildingVariant: {
entity.components.ItemAcceptor.setSlots([
{
pos: new Vector(0, 0),
directions: [enumDirection.bottom],
},
{
pos: new Vector(1, 0),
directions: [enumDirection.bottom],
},
]);
entity.components.ItemEjector.setSlots([
{ pos: new Vector(0, 0), direction: enumDirection.top },
{ pos: new Vector(1, 0), direction: enumDirection.top },
]);
entity.components.BeltUnderlays.underlays = [
{ pos: new Vector(0, 0), direction: enumDirection.top },
{ pos: new Vector(1, 0), direction: enumDirection.top },
];
break;
}
case enumSplitterVariants.compact:
case enumSplitterVariants.compactInverse: {
entity.components.ItemAcceptor.setSlots([
{
pos: new Vector(0, 0),
directions: [enumDirection.bottom],
},
{
pos: new Vector(0, 0),
directions: [
variant === enumSplitterVariants.compactInverse
? enumDirection.left
: enumDirection.right,
],
},
]);
entity.components.ItemEjector.setSlots([
{ pos: new Vector(0, 0), direction: enumDirection.top },
]);
entity.components.BeltUnderlays.underlays = [
{ pos: new Vector(0, 0), direction: enumDirection.top },
];
break;
}
case enumSplitterVariants.compactMerge:
case enumSplitterVariants.compactMergeInverse: {
entity.components.ItemAcceptor.setSlots([
{
pos: new Vector(0, 0),
directions: [enumDirection.bottom],
},
]);
entity.components.ItemEjector.setSlots([
{
pos: new Vector(0, 0),
direction: enumDirection.top,
},
{
pos: new Vector(0, 0),
direction:
variant === enumSplitterVariants.compactMergeInverse
? enumDirection.left
: enumDirection.right,
},
]);
entity.components.BeltUnderlays.underlays = [
{ pos: new Vector(0, 0), direction: enumDirection.top },
];
break;
}
default:
assertAlways(false, "Unknown splitter variant: " + variant);
}
}
}

View File

@@ -55,6 +55,8 @@ export function initMetaBuildingRegistry() {
registerBuildingVariant(4, MetaSplitterBuilding);
registerBuildingVariant(5, MetaSplitterBuilding, enumSplitterVariants.compact);
registerBuildingVariant(6, MetaSplitterBuilding, enumSplitterVariants.compactInverse);
registerBuildingVariant(47, MetaSplitterBuilding, enumSplitterVariants.compactMerge);
registerBuildingVariant(48, MetaSplitterBuilding, enumSplitterVariants.compactMergeInverse);
// Miner
registerBuildingVariant(7, MetaMinerBuilding);

View File

@@ -1,179 +1,182 @@
import { ShapeDefinition } from "./shape_definition";
import { finalGameShape } from "./upgrades";
/**
* Don't forget to also update tutorial_goals_mappings.js as well as the translations!
* @enum {string}
*/
export const enumHubGoalRewards = {
reward_cutter_and_trash: "reward_cutter_and_trash",
reward_rotater: "reward_rotater",
reward_painter: "reward_painter",
reward_mixer: "reward_mixer",
reward_stacker: "reward_stacker",
reward_splitter: "reward_splitter",
reward_tunnel: "reward_tunnel",
reward_rotater_ccw: "reward_rotater_ccw",
reward_rotater_fl: "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",
reward_cutter_quad: "reward_cutter_quad",
reward_painter_double: "reward_painter_double",
reward_painter_quad: "reward_painter_quad",
reward_storage: "reward_storage",
reward_blueprints: "reward_blueprints",
reward_freeplay: "reward_freeplay",
no_reward: "no_reward",
no_reward_freeplay: "no_reward_freeplay",
};
export const tutorialGoals = [
// 1
// Circle
{
shape: "CuCuCuCu", // belts t1
required: 40,
reward: enumHubGoalRewards.reward_cutter_and_trash,
},
// 2
// Cutter
{
shape: "----CuCu", //
required: 40,
reward: enumHubGoalRewards.no_reward,
},
// 3
// Rectangle
{
shape: "RuRuRuRu", // miners t1
required: 100,
reward: enumHubGoalRewards.reward_splitter,
},
// 4
{
shape: "RuRu----", // processors t2
required: 120,
reward: enumHubGoalRewards.reward_rotater,
},
// 5
// Rotater
{
shape: "Cu----Cu", // belts t2
required: 200,
reward: enumHubGoalRewards.reward_tunnel,
},
// 6
{
shape: "Cu------", // miners t2
required: 400,
reward: enumHubGoalRewards.reward_painter,
},
// 7
// Painter
{
shape: "CrCrCrCr", // unused
required: 800,
reward: enumHubGoalRewards.reward_rotater_ccw,
},
// 8
{
shape: "RbRb----", // painter t2
required: 1000,
reward: enumHubGoalRewards.reward_mixer,
},
// 9
// Mixing (purple)
{
shape: "CpCpCpCp", // belts t3
required: 1400,
reward: enumHubGoalRewards.reward_splitter_compact,
},
// 10
// Star shape + cyan
{
shape: "ScScScSc", // miners t3
required: 1600,
reward: enumHubGoalRewards.reward_stacker,
},
// 11
// Stacker
{
shape: "CgScScCg", // processors t3
required: 1800,
reward: enumHubGoalRewards.reward_miner_chainable,
},
// 12
// Blueprints
{
shape: "CbCbCbRb:CwCwCwCw",
required: 2000,
reward: enumHubGoalRewards.reward_blueprints,
},
// 13
{
shape: "RpRpRpRp:CwCwCwCw", // painting t3
required: 12000,
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
},
// 14
{
shape: "SrSrSrSr:CyCyCyCy", // unused
required: 16000,
reward: enumHubGoalRewards.reward_storage,
},
// 15
{
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
required: 25000,
reward: enumHubGoalRewards.reward_cutter_quad,
},
// 16
{
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
required: 50000,
reward: enumHubGoalRewards.reward_painter_double,
},
// 17
{
shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", // processors t4 (two variants)
required: 120000,
reward: enumHubGoalRewards.reward_painter_quad,
},
// 18
{
shape: finalGameShape,
required: 250000,
reward: enumHubGoalRewards.reward_freeplay,
},
];
if (G_IS_DEV) {
tutorialGoals.forEach(({ shape }) => {
try {
ShapeDefinition.fromShortKey(shape);
} catch (ex) {
throw new Error("Invalid tutorial goal: '" + ex + "' for shape" + shape);
}
});
}
import { ShapeDefinition } from "./shape_definition";
import { finalGameShape } from "./upgrades";
/**
* Don't forget to also update tutorial_goals_mappings.js as well as the translations!
* @enum {string}
*/
export const enumHubGoalRewards = {
reward_cutter_and_trash: "reward_cutter_and_trash",
reward_rotater: "reward_rotater",
reward_painter: "reward_painter",
reward_mixer: "reward_mixer",
reward_stacker: "reward_stacker",
reward_splitter: "reward_splitter",
reward_tunnel: "reward_tunnel",
reward_rotater_ccw: "reward_rotater_ccw",
reward_rotater_fl: "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",
reward_cutter_quad: "reward_cutter_quad",
reward_painter_double: "reward_painter_double",
reward_painter_quad: "reward_painter_quad",
reward_storage: "reward_storage",
// @todo: unlock
reward_merger_compact: "reward_compact_merger",
reward_blueprints: "reward_blueprints",
reward_freeplay: "reward_freeplay",
no_reward: "no_reward",
no_reward_freeplay: "no_reward_freeplay",
};
export const tutorialGoals = [
// 1
// Circle
{
shape: "CuCuCuCu", // belts t1
required: 40,
reward: enumHubGoalRewards.reward_cutter_and_trash,
},
// 2
// Cutter
{
shape: "----CuCu", //
required: 40,
reward: enumHubGoalRewards.no_reward,
},
// 3
// Rectangle
{
shape: "RuRuRuRu", // miners t1
required: 100,
reward: enumHubGoalRewards.reward_splitter,
},
// 4
{
shape: "RuRu----", // processors t2
required: 120,
reward: enumHubGoalRewards.reward_rotater,
},
// 5
// Rotater
{
shape: "Cu----Cu", // belts t2
required: 200,
reward: enumHubGoalRewards.reward_tunnel,
},
// 6
{
shape: "Cu------", // miners t2
required: 400,
reward: enumHubGoalRewards.reward_painter,
},
// 7
// Painter
{
shape: "CrCrCrCr", // unused
required: 800,
reward: enumHubGoalRewards.reward_rotater_ccw,
},
// 8
{
shape: "RbRb----", // painter t2
required: 1000,
reward: enumHubGoalRewards.reward_mixer,
},
// 9
// Mixing (purple)
{
shape: "CpCpCpCp", // belts t3
required: 1400,
reward: enumHubGoalRewards.reward_splitter_compact,
},
// 10
// Star shape + cyan
{
shape: "ScScScSc", // miners t3
required: 1600,
reward: enumHubGoalRewards.reward_stacker,
},
// 11
// Stacker
{
shape: "CgScScCg", // processors t3
required: 1800,
reward: enumHubGoalRewards.reward_miner_chainable,
},
// 12
// Blueprints
{
shape: "CbCbCbRb:CwCwCwCw",
required: 2000,
reward: enumHubGoalRewards.reward_blueprints,
},
// 13
{
shape: "RpRpRpRp:CwCwCwCw", // painting t3
required: 12000,
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
},
// 14
{
shape: "SrSrSrSr:CyCyCyCy", // unused
required: 16000,
reward: enumHubGoalRewards.reward_storage,
},
// 15
{
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
required: 25000,
reward: enumHubGoalRewards.reward_cutter_quad,
},
// 16
{
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
required: 50000,
reward: enumHubGoalRewards.reward_painter_double,
},
// 17
{
shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", // processors t4 (two variants)
required: 120000,
reward: enumHubGoalRewards.reward_painter_quad,
},
// 18
{
shape: finalGameShape,
required: 250000,
reward: enumHubGoalRewards.reward_freeplay,
},
];
if (G_IS_DEV) {
tutorialGoals.forEach(({ shape }) => {
try {
ShapeDefinition.fromShortKey(shape);
} catch (ex) {
throw new Error("Invalid tutorial goal: '" + ex + "' for shape" + shape);
}
});
}