Mirroar/hivemind

View on GitHub
src/spawn-role/harvester.minerals.ts

Summary

Maintainability
B
4 hrs
Test Coverage
/* global FIND_MINERALS STRUCTURE_EXTRACTOR MOVE WORK CARRY CREEP_SPAWN_TIME */

import BodyBuilder, {MOVEMENT_MODE_ROAD} from 'creep/body-builder';
import SpawnRole from 'spawn-role/spawn-role';

interface MineralHarvesterSpawnOption extends SpawnOption {
    source: Id<Mineral>;
}

export default class MineralHarvesterSpawnRole extends SpawnRole {
    /**
     * Adds mineral harvester spawn options for the given room.
     *
     * @param {Room} room
     *   The room to add spawn options for.
     */
    getSpawnOptions(room: Room): MineralHarvesterSpawnOption[] {
        return this.cacheEmptySpawnOptionsFor(room, 50, () => {
            // Stop harvesting if we can't really store any more minerals.
            if (room.isEvacuating()) return [];
            if (room.getEffectiveAvailableEnergy() < 5000) return [];

            // Find mineral sources with an extractor.
            // @todo This could be done on script startup and partially kept in room memory.
            const minerals = room.find(FIND_MINERALS, {
                filter: mineral => {
                    const extractors = mineral.mineralAmount > 0 ? _.filter(room.myStructuresByType[STRUCTURE_EXTRACTOR],
                        structure => structure.isOperational() && mineral.pos.isEqualTo(structure.pos),
                    ) : [];
                    return extractors.length > 0;
                },
            });

            const options: MineralHarvesterSpawnOption[] = [];
            for (const mineral of minerals) {
                if (!mineral.getNearbyContainer()) continue;
                if (room.isFullOnMinerals()) return [];

                const mineralHarvesters = _.filter(mineral.harvesters, creep => creep.spawning || creep.ticksToLive > this.getCreepBody(room).length * CREEP_SPAWN_TIME);
                const maxHarvesters = room.isStripmine() ? Math.min(3, mineral.getNumHarvestSpots()) : 1;
                if (_.size(mineralHarvesters) >= maxHarvesters) continue;

                const minAmount = 0;
                if (mineral.mineralAmount <= minAmount) continue;

                options.push({
                    priority: room.isStripmine() ? 4 : 3,
                    weight: 0.2,
                    source: mineral.id,
                });
            }

            return options;
        });
    }

    /**
     * Gets the body of a creep to be spawned.
     *
     * @param {Room} room
     *   The room to add spawn options for.
     * @param {Object} option
     *   The spawn option for which to generate the body.
     *
     * @return {string[]}
     *   A list of body parts the new creep should consist of.
     */
    getCreepBody(room: Room): BodyPartConstant[] {
        return (new BodyBuilder())
            .setWeights({[CARRY]: 1, [WORK]: 10})
            .setMovementMode(MOVEMENT_MODE_ROAD)
            .setCarryContentLevel(0)
            .setEnergyLimit(Math.min(room.energyCapacityAvailable, Math.max(room.energyCapacityAvailable * 0.9, room.energyAvailable)))
            .build();
    }

    /**
     * Gets memory for a new creep.
     *
     * @param {Room} room
     *   The room to add spawn options for.
     * @param {Object} option
     *   The spawn option for which to generate the body.
     *
     * @return {Object}
     *   The boost compound to use keyed by body part type.
     */
    getCreepMemory(room: Room, option: MineralHarvesterSpawnOption): HarvesterCreepMemory {
        return {
            role: 'harvester',
            singleRoom: room.name,
            fixedMineralSource: option.source,
            operation: 'room:' + room.name,
        };
    }

    /**
     * Gets which boosts to use on a new creep.
     *
     * @param {Room} room
     *   The room to add spawn options for.
     * @param {Object} option
     *   The spawn option for which to generate the body.
     * @param {string[]} body
     *   The body generated for this creep.
     *
     * @return {Object}
     *   The boost compound to use keyed by body part type.
     */
    getCreepBoosts(room: Room, option: MineralHarvesterSpawnOption, body: BodyPartConstant[]): Record<string, ResourceConstant> {
        const mineral = Game.getObjectById(option.source);
        if (mineral.mineralAmount < 2000) return {};

        return this.generateCreepBoosts(room, body, WORK, 'harvest');
    }
}