mirror of
https://github.com/tobspr/shapez.io.git
synced 2026-03-02 03:39:21 +00:00
Initial commit
This commit is contained in:
204
src/js/game/buildings/belt_base.js
Normal file
204
src/js/game/buildings/belt_base.js
Normal file
@@ -0,0 +1,204 @@
|
||||
import { Loader } from "../../core/loader";
|
||||
import { enumAngleToDirection, enumDirection, Vector } from "../../core/vector";
|
||||
import { BeltComponent } from "../components/belt";
|
||||
import { ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { ReplaceableMapEntityComponent } from "../components/replaceable_map_entity";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
|
||||
export const arrayBeltVariantToRotation = [enumDirection.top, enumDirection.left, enumDirection.right];
|
||||
|
||||
export class MetaBeltBaseBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("belt");
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#777";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
entity.addComponent(
|
||||
new BeltComponent({
|
||||
direction: enumDirection.top, // updated later
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(
|
||||
new ItemAcceptorComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(
|
||||
new ItemEjectorComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
direction: enumDirection.top, // updated later
|
||||
},
|
||||
],
|
||||
instantEject: true,
|
||||
})
|
||||
);
|
||||
// Make this entity replaceabel
|
||||
entity.addComponent(new ReplaceableMapEntityComponent());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Entity} entity
|
||||
* @param {number} rotationVariant
|
||||
*/
|
||||
updateRotationVariant(entity, rotationVariant) {
|
||||
entity.components.Belt.direction = arrayBeltVariantToRotation[rotationVariant];
|
||||
entity.components.ItemEjector.slots[0].direction = arrayBeltVariantToRotation[rotationVariant];
|
||||
|
||||
entity.components.StaticMapEntity.spriteKey = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes optimal belt rotation variant
|
||||
* @param {GameRoot} root
|
||||
* @param {Vector} tile
|
||||
* @param {number} rotation
|
||||
* @return {{ rotation: number, rotationVariant: number }}
|
||||
*/
|
||||
computeOptimalDirectionAndRotationVariantAtTile(root, tile, rotation) {
|
||||
const topDirection = enumAngleToDirection[rotation];
|
||||
const rightDirection = enumAngleToDirection[(rotation + 90) % 360];
|
||||
const bottomDirection = enumAngleToDirection[(rotation + 180) % 360];
|
||||
const leftDirection = enumAngleToDirection[(rotation + 270) % 360];
|
||||
|
||||
const { ejectors, acceptors } = root.logic.getEjectorsAndAcceptorsAtTile(tile);
|
||||
|
||||
let hasBottomEjector = false;
|
||||
let hasLeftEjector = false;
|
||||
let hasRightEjector = false;
|
||||
|
||||
let hasTopAcceptor = false;
|
||||
let hasLeftAcceptor = false;
|
||||
let hasRightAcceptor = false;
|
||||
|
||||
// Check all ejectors
|
||||
for (let i = 0; i < ejectors.length; ++i) {
|
||||
const ejector = ejectors[i];
|
||||
|
||||
if (ejector.toDirection === topDirection) {
|
||||
hasBottomEjector = true;
|
||||
} else if (ejector.toDirection === leftDirection) {
|
||||
hasLeftEjector = true;
|
||||
} else if (ejector.toDirection === rightDirection) {
|
||||
hasRightEjector = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check all acceptors
|
||||
for (let i = 0; i < acceptors.length; ++i) {
|
||||
const acceptor = acceptors[i];
|
||||
if (acceptor.fromDirection === bottomDirection) {
|
||||
hasTopAcceptor = true;
|
||||
} else if (acceptor.fromDirection === rightDirection) {
|
||||
hasLeftAcceptor = true;
|
||||
} else if (acceptor.fromDirection === leftDirection) {
|
||||
hasRightAcceptor = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Soo .. if there is any ejector below us we always prioritize
|
||||
// this ejector
|
||||
if (!hasBottomEjector) {
|
||||
// When something ejects to us from the left and nothing from the right,
|
||||
// do a curve from the left to the top
|
||||
if (hasLeftEjector && !hasRightEjector) {
|
||||
return {
|
||||
rotation: (rotation + 270) % 360,
|
||||
rotationVariant: 2,
|
||||
};
|
||||
}
|
||||
|
||||
// When something ejects to us from the right and nothing from the left,
|
||||
// do a curve from the right to the top
|
||||
if (hasRightEjector && !hasLeftEjector) {
|
||||
return {
|
||||
rotation: (rotation + 90) % 360,
|
||||
rotationVariant: 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// When there is a top acceptor, ignore sides
|
||||
// NOTICE: This makes the belt prefer side turns *way* too much!
|
||||
// if (!hasTopAcceptor) {
|
||||
// // When there is an acceptor to the right but no acceptor to the left,
|
||||
// // do a turn to the right
|
||||
// if (hasRightAcceptor && !hasLeftAcceptor) {
|
||||
// return {
|
||||
// rotation,
|
||||
// rotationVariant: 2,
|
||||
// };
|
||||
// }
|
||||
|
||||
// // When there is an acceptor to the left but no acceptor to the right,
|
||||
// // do a turn to the left
|
||||
// if (hasLeftAcceptor && !hasRightAcceptor) {
|
||||
// return {
|
||||
// rotation,
|
||||
// rotationVariant: 1,
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 0,
|
||||
};
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Belt";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Transports items, hold and drag to place multiple, press 'R' to rotate.";
|
||||
}
|
||||
|
||||
getPreviewSprite(rotationVariant) {
|
||||
switch (arrayBeltVariantToRotation[rotationVariant]) {
|
||||
case enumDirection.top: {
|
||||
return Loader.getSprite("sprites/belt/forward_0.png");
|
||||
}
|
||||
case enumDirection.left: {
|
||||
return Loader.getSprite("sprites/belt/left_0.png");
|
||||
}
|
||||
case enumDirection.right: {
|
||||
return Loader.getSprite("sprites/belt/right_0.png");
|
||||
}
|
||||
default: {
|
||||
assertAlways(false, "Invalid belt rotation variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getStayInPlacementMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be overridden
|
||||
*/
|
||||
internalGetBeltDirection(rotationVariant) {
|
||||
return enumDirection.top;
|
||||
}
|
||||
}
|
||||
71
src/js/game/buildings/cutter.js
Normal file
71
src/js/game/buildings/cutter.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { enumItemAcceptorItemFilter, ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
|
||||
export class MetaCutterBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("cutter");
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#7dcda2";
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
return new Vector(2, 1);
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Cut Half";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
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>";
|
||||
}
|
||||
|
||||
/**
|
||||
* @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({
|
||||
slots: [
|
||||
{ pos: new Vector(0, 0), direction: enumDirection.top },
|
||||
{ pos: new Vector(1, 0), direction: enumDirection.top },
|
||||
],
|
||||
})
|
||||
);
|
||||
entity.addComponent(
|
||||
new ItemAcceptorComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
125
src/js/game/buildings/hub.js
Normal file
125
src/js/game/buildings/hub.js
Normal file
@@ -0,0 +1,125 @@
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { enumItemAcceptorItemFilter, ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { ItemProcessorComponent, enumItemProcessorTypes } from "../components/item_processor";
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { UnremovableComponent } from "../components/unremovable";
|
||||
import { HubComponent } from "../components/hub";
|
||||
|
||||
export class MetaHubBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("hub");
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
return new Vector(4, 4);
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#eb5555";
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Hub";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Your central hub, deliver shapes to it to unlock new buildings.";
|
||||
}
|
||||
|
||||
isRotateable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
entity.addComponent(new HubComponent());
|
||||
entity.addComponent(
|
||||
new ItemProcessorComponent({
|
||||
inputsPerCharge: 1,
|
||||
processorType: enumItemProcessorTypes.hub,
|
||||
})
|
||||
);
|
||||
entity.addComponent(new UnremovableComponent());
|
||||
entity.addComponent(
|
||||
new ItemAcceptorComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.top, enumDirection.left],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(1, 0),
|
||||
directions: [enumDirection.top],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(2, 0),
|
||||
directions: [enumDirection.top],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(3, 0),
|
||||
directions: [enumDirection.top, enumDirection.right],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(0, 3),
|
||||
directions: [enumDirection.bottom, enumDirection.left],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(1, 3),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(2, 3),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(3, 3),
|
||||
directions: [enumDirection.bottom, enumDirection.right],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(0, 1),
|
||||
directions: [enumDirection.left],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(0, 2),
|
||||
directions: [enumDirection.left],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(0, 3),
|
||||
directions: [enumDirection.left],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(3, 1),
|
||||
directions: [enumDirection.right],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(3, 2),
|
||||
directions: [enumDirection.right],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(3, 3),
|
||||
directions: [enumDirection.right],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
36
src/js/game/buildings/miner.js
Normal file
36
src/js/game/buildings/miner.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { MinerComponent } from "../components/miner";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
|
||||
export class MetaMinerBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("miner");
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Extract";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#b37dcd";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Place over a shape or color to extract it. Six extractors fill exactly one belt.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
entity.addComponent(new MinerComponent({}));
|
||||
entity.addComponent(
|
||||
new ItemEjectorComponent({
|
||||
slots: [{ pos: new Vector(0, 0), direction: enumDirection.top }],
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
73
src/js/game/buildings/mixer.js
Normal file
73
src/js/game/buildings/mixer.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { ItemAcceptorComponent, enumItemAcceptorItemFilter } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
|
||||
export class MetaMixerBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("mixer");
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
return new Vector(2, 1);
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Mix Colors";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Mixes two colors using additive blending.";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#cdbb7d";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_mixer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
entity.addComponent(
|
||||
new ItemProcessorComponent({
|
||||
inputsPerCharge: 2,
|
||||
processorType: enumItemProcessorTypes.mixer,
|
||||
})
|
||||
);
|
||||
|
||||
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: enumItemAcceptorItemFilter.color,
|
||||
},
|
||||
{
|
||||
pos: new Vector(1, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: enumItemAcceptorItemFilter.color,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
73
src/js/game/buildings/painter.js
Normal file
73
src/js/game/buildings/painter.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { enumItemAcceptorItemFilter, ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
import { GameRoot } from "../root";
|
||||
|
||||
export class MetaPainterBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("painter");
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
return new Vector(2, 1);
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Dye";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Colors the whole shape on the left input with the color from the right input.";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#cd9b7d";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_painter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
entity.addComponent(
|
||||
new ItemProcessorComponent({
|
||||
inputsPerCharge: 2,
|
||||
processorType: enumItemProcessorTypes.painter,
|
||||
})
|
||||
);
|
||||
|
||||
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: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(1, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: enumItemAcceptorItemFilter.color,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
64
src/js/game/buildings/rotater.js
Normal file
64
src/js/game/buildings/rotater.js
Normal file
@@ -0,0 +1,64 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { ItemAcceptorComponent, enumItemAcceptorItemFilter } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
import { GameRoot } from "../root";
|
||||
|
||||
export class MetaRotaterBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("rotater");
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Rotate";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Rotates shapes clockwise by 90 degrees.";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#7dc6cd";
|
||||
}
|
||||
|
||||
/**
|
||||
* @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: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
80
src/js/game/buildings/splitter.js
Normal file
80
src/js/game/buildings/splitter.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
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 } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
|
||||
export class MetaSplitterBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("splitter");
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
return new Vector(2, 1);
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Distribute";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#444";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Accepts up to two inputs and evenly distributes them on the outputs. Can also be used to merge two inputs into one output.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @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: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
},
|
||||
{
|
||||
pos: new Vector(1, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(
|
||||
new ItemProcessorComponent({
|
||||
inputsPerCharge: 1,
|
||||
processorType: enumItemProcessorTypes.splitter,
|
||||
|
||||
beltUnderlays: [
|
||||
{ pos: new Vector(0, 0), direction: enumDirection.top },
|
||||
{ pos: new Vector(1, 0), direction: enumDirection.top },
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(
|
||||
new ItemEjectorComponent({
|
||||
slots: [
|
||||
{ pos: new Vector(0, 0), direction: enumDirection.top },
|
||||
{ pos: new Vector(1, 0), direction: enumDirection.top },
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
73
src/js/game/buildings/stacker.js
Normal file
73
src/js/game/buildings/stacker.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { ItemAcceptorComponent, enumItemAcceptorItemFilter } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
|
||||
export class MetaStackerBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("stacker");
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Combine";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#9fcd7d";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Combines both items. If they can not be merged, the right item is placed above the left item.";
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
return new Vector(2, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_stacker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
entity.addComponent(
|
||||
new ItemProcessorComponent({
|
||||
inputsPerCharge: 2,
|
||||
processorType: enumItemProcessorTypes.stacker,
|
||||
})
|
||||
);
|
||||
|
||||
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: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
{
|
||||
pos: new Vector(1, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
filter: enumItemAcceptorItemFilter.shape,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
73
src/js/game/buildings/trash.js
Normal file
73
src/js/game/buildings/trash.js
Normal file
@@ -0,0 +1,73 @@
|
||||
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 } from "../meta_building";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
import { GameRoot } from "../root";
|
||||
|
||||
export class MetaTrashBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("trash");
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Destroyer";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Accepts inputs from all sides and destroys them. Forever.";
|
||||
}
|
||||
|
||||
isRotateable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#cd7d86";
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.trash,
|
||||
})
|
||||
);
|
||||
|
||||
// Required, since the item processor needs this.
|
||||
entity.addComponent(
|
||||
new ItemEjectorComponent({
|
||||
slots: [],
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(
|
||||
new ItemAcceptorComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [
|
||||
enumDirection.top,
|
||||
enumDirection.right,
|
||||
enumDirection.bottom,
|
||||
enumDirection.left,
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
158
src/js/game/buildings/underground_belt.js
Normal file
158
src/js/game/buildings/underground_belt.js
Normal file
@@ -0,0 +1,158 @@
|
||||
import { Loader } from "../../core/loader";
|
||||
import { enumDirection, Vector, enumAngleToDirection, enumDirectionToVector } from "../../core/vector";
|
||||
import { ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components/underground_belt";
|
||||
import { Entity } from "../entity";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
|
||||
/** @enum {string} */
|
||||
export const arrayUndergroundRotationVariantToMode = [
|
||||
enumUndergroundBeltMode.sender,
|
||||
enumUndergroundBeltMode.receiver,
|
||||
];
|
||||
|
||||
export class MetaUndergroundBeltBuilding extends MetaBuilding {
|
||||
constructor() {
|
||||
super("underground_belt");
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Tunnel";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#555";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Allows to tunnel resources under buildings and belts.";
|
||||
}
|
||||
|
||||
getFlipOrientationAfterPlacement() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getStayInPlacementMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getPreviewSprite(rotationVariant) {
|
||||
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
|
||||
case enumUndergroundBeltMode.sender:
|
||||
return Loader.getSprite("sprites/buildings/underground_belt_entry.png");
|
||||
case enumUndergroundBeltMode.receiver:
|
||||
return Loader.getSprite("sprites/buildings/underground_belt_exit.png");
|
||||
default:
|
||||
assertAlways(false, "Invalid rotation variant");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
getIsUnlocked(root) {
|
||||
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_tunnel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
setupEntityComponents(entity) {
|
||||
// Required, since the item processor needs this.
|
||||
entity.addComponent(
|
||||
new ItemEjectorComponent({
|
||||
slots: [],
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(new UndergroundBeltComponent({}));
|
||||
entity.addComponent(
|
||||
new ItemAcceptorComponent({
|
||||
slots: [],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
* @param {Vector} tile
|
||||
* @param {number} rotation
|
||||
* @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array<Entity> }}
|
||||
*/
|
||||
computeOptimalDirectionAndRotationVariantAtTile(root, tile, rotation) {
|
||||
const searchDirection = enumAngleToDirection[rotation];
|
||||
const searchVector = enumDirectionToVector[searchDirection];
|
||||
|
||||
const targetRotation = (rotation + 180) % 360;
|
||||
|
||||
for (let searchOffset = 1; searchOffset <= globalConfig.undergroundBeltMaxTiles; ++searchOffset) {
|
||||
tile = tile.addScalars(searchVector.x, searchVector.y);
|
||||
|
||||
const contents = root.map.getTileContent(tile);
|
||||
if (contents) {
|
||||
const undergroundComp = contents.components.UndergroundBelt;
|
||||
if (undergroundComp) {
|
||||
const staticComp = contents.components.StaticMapEntity;
|
||||
if (staticComp.rotationDegrees === targetRotation) {
|
||||
if (undergroundComp.mode !== enumUndergroundBeltMode.sender) {
|
||||
// If we encounter an underground receiver on our way which is also faced in our direction, we don't accept that
|
||||
break;
|
||||
}
|
||||
// console.log("GOT IT! rotation is", rotation, "and target is", staticComp.rotationDegrees);
|
||||
|
||||
return {
|
||||
rotation: targetRotation,
|
||||
rotationVariant: 1,
|
||||
connectedEntities: [contents],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Entity} entity
|
||||
* @param {number} rotationVariant
|
||||
*/
|
||||
updateRotationVariant(entity, rotationVariant) {
|
||||
entity.components.StaticMapEntity.spriteKey = this.getPreviewSprite(rotationVariant).spriteName;
|
||||
|
||||
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
|
||||
case enumUndergroundBeltMode.sender: {
|
||||
entity.components.UndergroundBelt.mode = enumUndergroundBeltMode.sender;
|
||||
entity.components.ItemEjector.setSlots([]);
|
||||
entity.components.ItemAcceptor.setSlots([
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
directions: [enumDirection.bottom],
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
case enumUndergroundBeltMode.receiver: {
|
||||
entity.components.UndergroundBelt.mode = enumUndergroundBeltMode.receiver;
|
||||
entity.components.ItemAcceptor.setSlots([]);
|
||||
entity.components.ItemEjector.setSlots([
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
direction: enumDirection.top,
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
assertAlways(false, "Invalid rotation variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user