/**
 * Creep tasks setup instructions
 *
 * Javascript:
 * 1. In main.js:    require("creep-tasks");
 * 2. As needed:     var Tasks = require("<path to creep-tasks.js>");
 *
 * Typescript:
 * 1. In main.ts:    import "<path to index.ts>";
 * 2. As needed:     import {Tasks} from "<path to Tasks.ts>"
 *
 * If you use Traveler, change all occurrences of creep.moveTo() to creep.travelTo()
 */ import { initializeTask } from './utilities/initializer' ; import { deref , derefRoomPosition } from './utilities/helpers' ; export type targetType = { ref : string ; pos : RoomPosition ; } ; export abstract class Task implements ITask { static taskName : string ; name : string ; _creep : { name : string ; } ; _target : { ref : string ; _pos : protoPos ; } ; _parent : protoTask | null ; tick : number ; settings : TaskSettings ; options : TaskOptions ; data : TaskData ; constructor ( taskName , target , options = { } as TaskOptions ) { this . name = taskName ; this . _creep = { name : '' , } ; if ( target ) { this . _target = { ref : target . ref , _pos : target . pos , } ; } else { this . _target = { ref : '' , _pos : { x : - 1 , y : - 1 , roomName : '' , } } ; } this . _parent = null ; this . settings = { targetRange : 1 , workOffRoad : false , oneShot : false , } ; _ . defaults ( options , { blind : false , moveOptions : { } , } ) ; this . tick = Game . time ; this . options = options ; this . data = { quiet : true , } ; } get proto ( ) : protoTask { return { name : this . name , _creep : this . _creep , _target : this . _target , _parent : this . _parent , options : this . options , data : this . data , tick : this . tick , } ; } set proto ( protoTask ) { this . _creep = protoTask . _creep ; this . _target = protoTask . _target ; this . _parent = protoTask . _parent ; this . options = protoTask . options ; this . data = protoTask . data ; this . tick = protoTask . tick ; } get creep ( ) : Creep { return Game . creeps [ this . _creep . name ] ; } set creep ( creep ) { this . _creep . name = creep . name ; } get target ( ) : RoomObject | null { return deref ( this . _target . ref ) ; } get targetPos ( ) : RoomPosition { if ( this . target ) { this . _target . _pos = this . target . pos ; } return derefRoomPosition ( this . _target . _pos ) ; } get parent ( ) : Task | null { return ( this . _parent ? initializeTask ( this . _parent ) : null ) ; } set parent ( parentTask ) { this . _parent = parentTask ? parentTask . proto : null ; if ( this . creep ) { this . creep . task = this ; } } get manifest ( ) : Task [ ] { let manifest = [ this ] ; let parent = this . parent ; while ( parent ) { manifest . push ( parent ) ; parent = parent . parent ; } return manifest ; } get targetManifest ( ) : ( RoomObject | null ) [ ] { let targetRefs = [ this . _target . ref ] ; let parent = this . _parent ; while ( parent ) { targetRefs . push ( parent . _target . ref ) ; parent = parent . _parent ; } return _ . map ( targetRefs , ref => deref ( ref ) ) ; } get targetPosManifest ( ) : RoomPosition [ ] { let targetPositions = [ this . _target . _pos ] ; let parent = this . _parent ; while ( parent ) { targetPositions . push ( parent . _target . _pos ) ; parent = parent . _parent ; } return _ . map ( targetPositions , protoPos => derefRoomPosition ( protoPos ) ) ; } fork ( newTask ) { newTask . parent = this ; if ( this . creep ) { this . creep . task = newTask ; } return newTask ; } abstract isValidTask ( ) ; abstract isValidTarget ( ) ; isValid ( ) { let validTask = false ; if ( this . creep ) { validTask = this . isValidTask ( ) ; } let validTarget = false ; if ( this . target ) { validTarget = this . isValidTarget ( ) ; } else if ( this . options . blind && ! Game . rooms [ this . targetPos . roomName ] ) { validTarget = true ; } if ( validTask && validTarget ) { return true ; } else { this . finish ( ) ; return this . parent ? this . parent . isValid ( ) : false ; } } moveToTarget ( range = this . settings . targetRange ) { if ( this . options . moveOptions && ! this . options . moveOptions . range ) { this . options . moveOptions . range = range ; } return this . creep . moveTo ( this . targetPos , this . options . moveOptions ) ; } moveToNextPos ( ) { if ( this . options . nextPos ) { let nextPos = derefRoomPosition ( this . options . nextPos ) ; return this . creep . moveTo ( nextPos ) ; } } get eta ( ) : number | undefined { if ( this . creep && ( < any > this . creep . memory ) . _trav ) { return ( < any > this . creep . memory ) . _trav . path . length ; } } run ( ) { if ( this . creep . pos . inRangeTo ( this . targetPos , this . settings . targetRange ) && ! this . creep . pos . isEdge ) { if ( this . settings . workOffRoad ) { this . parkCreep ( this . creep , this . targetPos , true ) ; } let result = this . work ( ) ; if ( this . settings . oneShot && result == OK ) { this . finish ( ) ; } return result ; } else { this . moveToTarget ( ) ; } } protected parkCreep ( creep , pos = creep . pos , maintainDistance = false ) { let road = _ . find ( creep . pos . lookFor ( LOOK_STRUCTURES ) , s => s . structureType == STRUCTURE_ROAD ) ; if ( ! road ) return OK ; let positions = _ . sortBy ( creep . pos . availableNeighbors ( ) , ( p ) => p . getRangeTo ( pos ) ) ; if ( maintainDistance ) { let currentRange = creep . pos . getRangeTo ( pos ) ; positions = _ . filter ( positions , ( p ) => p . getRangeTo ( pos ) <= currentRange ) ; } let swampPosition ; for ( let position of positions ) { if ( _ . find ( position . lookFor ( LOOK_STRUCTURES ) , s => s . structureType == STRUCTURE_ROAD ) ) continue ; let terrain = position . lookFor ( LOOK_TERRAIN ) [ 0 ] ; if ( terrain === 'swamp' ) { swampPosition = position ; } else { return creep . move ( creep . pos . getDirectionTo ( position ) ) ; } } if ( swampPosition ) { return creep . move ( creep . pos . getDirectionTo ( swampPosition ) ) ; } return creep . moveTo ( pos ) ; } abstract work ( ) ; finish ( ) { this . moveToNextPos ( ) ; if ( this . creep ) { this . creep . task = this . parent ; } else { console . log ( `No creep executing ${ this . name }!` ) ; } } }