Mirroar/hivemind

View on GitHub
src/role/dismantler.ts

Summary

Maintainability
C
1 day
Test Coverage
/* global RoomPosition LOOK_STRUCTURES STRUCTURE_RAMPART */

import RemoteMiningOperation from 'operation/remote-mining';
import Role from 'role/role';
import {encodePosition} from 'utils/serialization';

declare global {
    interface DismantlerCreep extends Creep {
        memory: DismantlerCreepMemory;
        heapMemory: DismantlerCreepHeapMemory;
    }

    interface DismantlerCreepMemory extends CreepMemory {
        role: 'dismantler';
        sourceRoom?: string;
        targetRoom?: string;
        source?: string;
    }

    interface DismantlerCreepHeapMemory extends CreepHeapMemory {
        finishedPositions: string[];
        disabledNotifications: Array<Id<Structure>>;
    }
}

export default class DismantlerRole extends Role {
    /**
     * Makes a creep behave like a dismantler.
     *
     * @param {Creep} creep
     *   The creep to run logic for.
     */
    run(creep: DismantlerCreep) {
        if (!creep.memory.sourceRoom) {
            creep.memory.sourceRoom = creep.pos.roomName;
        }

        if (!creep.memory.targetRoom) {
            creep.memory.targetRoom = creep.pos.roomName;
        }

        if (!creep.heapMemory.disabledNotifications) creep.heapMemory.disabledNotifications = [];

        if (!this.performOperationDismantle(creep)) this.performDismantle(creep);
    }

    /**
     * Dismantles structures blocking an operation.
     *
     * @param {Creep} creep
     *   The creep to run logic for.
     */
    performOperationDismantle(creep: DismantlerCreep): boolean {
        if (!creep.operation) return false;
        if (!(creep.operation instanceof RemoteMiningOperation)) return false;

        if (!creep.heapMemory.finishedPositions) creep.heapMemory.finishedPositions = [];
        if (!creep.operation.needsDismantler(creep.memory.source)) {
            // @todo Return home and suicide.
            const targetPos = new RoomPosition(24, 24, creep.memory.sourceRoom);
            if (targetPos.roomName === creep.pos.roomName && creep.pos.getRangeTo(targetPos) <= 20) return true;

            creep.moveToRange(targetPos, 20);
            return true;
        }

        const targetPositions = creep.operation.getDismantlePositions(creep.memory.source);
        let target: RoomPosition;
        for (const pos of targetPositions) {
            if (creep.heapMemory.finishedPositions.includes(encodePosition(pos))) continue;

            if (pos.roomName === creep.pos.roomName) {
                const structures = _.filter(
                    pos.lookFor(LOOK_STRUCTURES),
                    (s: AnyStructure) => !s.isWalkable(),
                );

                if (structures.length === 0) {
                    creep.heapMemory.finishedPositions.push(encodePosition(pos));
                    continue;
                }
            }

            target = pos;
            break;
        }

        if (!target) {
            // Just to be sure, start again from the top.
            delete creep.heapMemory.finishedPositions;
            return true;
        }

        if (creep.pos.roomName !== target.roomName || creep.pos.getRangeTo(target) > 1) {
            // Get into range of target tile.
            creep.moveToRange(target, 1);
            return true;
        }

        const structure = _.find(
            target.lookFor(LOOK_STRUCTURES),
            (s: AnyStructure) => !s.isWalkable(),
        );

        if (!creep.heapMemory.disabledNotifications.includes(structure.id)) {
            creep.heapMemory.disabledNotifications.push(structure.id);
            structure.notifyWhenAttacked(false);
        }

        creep.dismantle(structure);
        return true;
    }

    /**
     * Makes the creep use energy to finish construction sites in the current room.
     *
     * @param {Creep} creep
     *   The creep to run logic for.
     */
    performDismantle(creep: DismantlerCreep) {
        // First, get to target room.
        const targetPos = new RoomPosition(25, 25, creep.memory.targetRoom);
        if (creep.interRoomTravel(targetPos)) return;
        if (creep.pos.roomName !== creep.memory.targetRoom) return;

        if (!creep.room.roomManager || !creep.room.roomManager.needsDismantling()) return;

        const target = creep.room.roomManager.getDismantleTarget();
        if (!target) return;

        if (!creep.heapMemory.disabledNotifications.includes(target.id)) {
            creep.heapMemory.disabledNotifications.push(target.id);
            target.notifyWhenAttacked(false);
        }

        creep.whenInRange(1, target, () => creep.dismantle(target));
    }
}