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