import { enumDirection, enumInvertedDirections, Vector } from "../../core/vector"; import { types } from "../../savegame/serialization"; import { BaseItem } from "../base_item"; import { Component } from "../component"; /** @typedef {{ * pos: Vector, * directions: enumDirection[], * filter?: ItemType * }} ItemAcceptorSlot */ /** * Contains information about a slot plus its location * @typedef {{ * slot: ItemAcceptorSlot, * index: number, * acceptedDirection: enumDirection * }} ItemAcceptorLocatedSlot */ /** @typedef {{ * pos: Vector, * directions: enumDirection[], * filter?: ItemType * }} ItemAcceptorSlotConfig */ export class ItemAcceptorComponent extends Component { static getId() { return "ItemAcceptor"; } /** * * @param {object} param0 * @param {Array} param0.slots The slots from which we accept items */ constructor({ slots = [] }) { super(); this.setSlots(slots); this.clear(); } clear() { /** * Fixes belt animations * @type {Array<{ * item: BaseItem, * slotIndex: number, * animProgress: number, * direction: enumDirection * }>} */ this.itemConsumptionAnimations = []; } /** * * @param {Array} slots */ setSlots(slots) { /** @type {Array} */ this.slots = []; for (let i = 0; i < slots.length; ++i) { const slot = slots[i]; this.slots.push({ pos: slot.pos, directions: slot.directions, // Which type of item to accept (shape | color | all) @see ItemType filter: slot.filter, }); } } /** * Returns if this acceptor can accept a new item at slot N * * NOTICE: The belt path ignores this for performance reasons and does his own check * @param {number} slotIndex * @param {BaseItem=} item */ canAcceptItem(slotIndex, item) { const slot = this.slots[slotIndex]; return !slot.filter || slot.filter === item.getItemType(); } /** * Called when an item has been accepted so that * @param {number} slotIndex * @param {enumDirection} direction * @param {BaseItem} item * @param {number} remainingProgress World space remaining progress, can be set to set the start position of the item */ onItemAccepted(slotIndex, direction, item, remainingProgress = 0.0) { this.itemConsumptionAnimations.push({ item, slotIndex, direction, animProgress: Math.min(1, remainingProgress * 2), }); } /** * Tries to find a slot which accepts the current item * @param {Vector} targetLocalTile * @param {enumDirection} fromLocalDirection * @returns {ItemAcceptorLocatedSlot|null} */ findMatchingSlot(targetLocalTile, fromLocalDirection) { // We need to invert our direction since the acceptor specifies *from* which direction // it accepts items, but the ejector specifies *into* which direction it ejects items. // E.g.: Ejector ejects into "right" direction but acceptor accepts from "left" direction. const desiredDirection = enumInvertedDirections[fromLocalDirection]; // Go over all slots and try to find a target slot for (let slotIndex = 0; slotIndex < this.slots.length; ++slotIndex) { const slot = this.slots[slotIndex]; // Make sure the acceptor slot is on the right position if (!slot.pos.equals(targetLocalTile)) { continue; } // Check if the acceptor slot accepts items from our direction for (let i = 0; i < slot.directions.length; ++i) { // const localDirection = targetStaticComp.localDirectionToWorld(slot.directions[l]); if (desiredDirection === slot.directions[i]) { return { slot, index: slotIndex, acceptedDirection: desiredDirection, }; } } } return null; } }