def recalc_military_path(self, origin, target, opts = None): # type: (RoomPosition, RoomPosition, Dict[str, Any]) -> None # TODO: separate the majority of the code this shares with follow_military_path into a new module if opts and "to_home" in opts: to_home = opts["to_home"] else: to_home = False if not origin: origin = movement.find_an_open_space(self.memory.home) if self.creep.fatigue > 0: return if self.pos.getRangeTo(target) < 10 or self.pos.roomName == target.roomName: self.move_to(target) return path_opts = { 'current_room': self.pos.roomName, } if opts: path_opts = _.merge(path_opts, opts) # TODO: this is all stupid, PathFinder is stupid for multiple rooms! if chebyshev_distance_room_pos(origin, target) > 900 \ and not is_path_portal(origin, target): path_opts['max_ops'] = chebyshev_distance_room_pos(origin, target) * 150 path_opts['max_rooms'] = math.ceil(chebyshev_distance_room_pos(origin, target) / 5) path_opts['use_roads'] = False # TODO: handle this better (this is for not having multiple super-duper-long cached paths) if to_home: intermediate = find_an_open_space(origin.roomName) origin = intermediate else: intermediate = center_pos(target.roomName) if self.pos.roomName != intermediate.roomName: target = intermediate path_opts.range = 10 else: # If we're this far away, let's just get to the room using a cached path and then do # basic pathfinding to get to our actual target. self.move_to(target) return if not is_path_portal(origin, target): origin_midpoint = find_midpoint(self.pos, self.pos, origin) if origin_midpoint is not None: origin = origin_midpoint dest_midpoint = find_midpoint(self.pos, origin, target) if dest_midpoint is not None: if self.pos.roomName == dest_midpoint.roomName: origin = dest_midpoint else: target = dest_midpoint path_opts.range = 10 honey.clear_cached_path(origin, target, path_opts)
def find_home(self): # type: () -> RoomPosition spawn = self.home.spawn if spawn: return spawn.pos else: return movement.find_an_open_space(self.home.name)
def find_depot(self): # type: () -> RoomPosition depots = flags.find_flags(self.home, DEPOT) if len(depots): depot = depots[0].pos else: self.log("WARNING: No depots found in {}!".format(self.home.name)) self.home.building.place_depot_flag() depots = flags.find_flags_global(DEPOT) if len(depots): depot = _.min( depots, lambda d: movement.chebyshev_distance_room_pos( self.pos, d.pos)).pos elif self.home.spawn: depot = self.home.spawn.pos else: depot = movement.find_an_open_space(self.home.name) return depot
def run(self): claim_room = self.find_claim_room() if not claim_room: self.creep.suicide() return if self.pos.roomName != claim_room: if Game.rooms[claim_room]: target = Game.rooms[claim_room].controller.pos else: target = movement.find_an_open_space(claim_room) self.follow_energy_path(self.home.spawn, target) self.check_move_parts() return controller = self.room.room.controller if not controller: del self.memory.claiming return True if controller.reservation and controller.reservation.ticksToEnd > 4999: if self.pos.isNearTo(controller): self.creep.suicide() return False else: del self.memory.claiming return True if not self.pos.isNearTo(controller): self.move_to(controller) self.check_move_parts() return False if controller.reservation and controller.reservation.username != self.creep.owner.username: self.log( "Remote reserve creep target owned by another player! {} has taken our reservation!", controller.reservation.username) else: self.creep.reserveController(controller) if Game.time % 5 == 2 and controller.reservation: stored_data.set_reservation_time( self.pos.roomName, controller.reservation.ticksToEnd)
def run(self): if self.creep.ticksToLive > 1450 and not (self.memory.boosted >= 2): if 'boosted' not in self.memory: self.memory.boosted = 0 if self.boost(): return False hostiles_nearby = defense.stored_hostiles_near(self.pos.roomName) if self.creep.hits < self.creep.hitsMax or \ (len(hostiles_nearby) and _.find(hostiles_nearby, lambda h: movement.chebyshev_distance_room_pos( self.pos, positions.deserialize_xy_to_pos(h.pos, h.room)) <= 3)): self.creep.heal(self.creep) marker_flag = cast(Flag, self.targets.get_new_target(self, target_single_flag, RANGED_DEFENSE)) if marker_flag is None: if self.pos.roomName == self.home.name and len(flags.find_flags(self.home, RAID_OVER)): if len(hostiles_nearby) or self.creep.hits < self.creep.hitsMax: self.creep.heal(self.creep) return False else: marker_flag = cast(Flag, {'pos': self.find_depot()}) if len(hostiles_nearby): if _.find(hostiles_nearby, lambda h: h.offensive and movement.chebyshev_distance_room_pos( self.pos, positions.deserialize_xy_to_pos(h.pos, h.room)) <= 5): hostiles_nearby = _.filter(hostiles_nearby, 'offensive') nearby = _.filter(hostiles_nearby, lambda h: movement.chebyshev_distance_room_pos( self.pos, positions.deserialize_xy_to_pos(h.pos, h.room)) <= 5) closest = _.min( hostiles_nearby, lambda h: movement.chebyshev_distance_room_pos(self.pos, positions.deserialize_xy_to_pos(h.pos, h.room)) - (5 if h.offensive else 0) ) closest_pos = positions.deserialize_xy_to_pos(closest.pos, closest.room) harmless = not _.some(nearby, lambda x: x.attack or x.ranged) ranged = _.some(nearby, lambda x: x.ranged and x.ranged > x.attack) only_ranged = not _.some(nearby, lambda h: movement.chebyshev_distance_room_pos( self.pos, positions.deserialize_xy_to_pos(h.pos, h.room)) <= 4 and h.attack) mass_attack = _.some(nearby, lambda h: movement.chebyshev_distance_room_pos( self.pos, positions.deserialize_xy_to_pos(h.pos, h.room)) <= 1 and h.room == self.pos.roomName) else: enemies = self.room.find(FIND_HOSTILE_CREEPS) if len(enemies): if self.pos.roomName != marker_flag.pos.roomName: enemies = _.filter(enemies, lambda h: hostile_utils.is_offensive(h) and hostile_utils.not_sk(h)) else: any_offensive = _.find(enemies, hostile_utils.is_offensive) if any_offensive: enemies = _.filter(enemies, lambda h: hostile_utils.is_offensive(h) and hostile_utils.not_sk(h)) else: enemies = _.filter(enemies, hostile_utils.not_sk) if len(enemies): closest = _.min(enemies, lambda h: movement.chebyshev_distance_room_pos(self.pos, h.pos)) closest_pos = closest.pos nearby = _.filter(enemies, lambda h: movement.chebyshev_distance_room_pos(h.pos, self.pos) <= 5) harmless = not _.some(nearby, lambda h: h.hasActiveBodyparts(ATTACK) or h.hasActiveBodyparts(RANGED_ATTACK)) \ and self.creep.hits >= self.creep.hitsMax ranged = _.some(nearby, lambda h: h.hasActiveBodyparts(RANGED_ATTACK) and h.getActiveBodyparts(RANGED_ATTACK) > h.getActiveBodyparts(ATTACK)) only_ranged = not _.some(nearby, lambda h: movement.chebyshev_distance_room_pos(self.pos, h.pos) <= 4 and h.hasBodyparts(ATTACK)) mass_attack = _.some(nearby, lambda h: self.pos.isNearTo(h.pos) and self.pos.roomName == h.pos.roomName) else: closest = None closest_pos = None harmless = False ranged = False only_ranged = True mass_attack = False if not closest or (closest_pos.roomName != self.pos.roomName and movement.chebyshev_distance_room_pos(closest_pos, self.pos) > 10): del self.memory.last_enemy_pos # self.creep.say("🐾 💚 🐾", True) if self.pos.roomName == marker_flag.pos.roomName and self.creep.hits >= self.creep.hitsMax: hurt = cast(List[Creep], self.room.find(PYFIND_HURT_CREEPS)) if len(hurt): damaged = _.min(hurt, lambda p: movement.chebyshev_distance_room_pos(p.pos, self.pos)) if self.pos.isNearTo(damaged): self.creep.heal(damaged) else: self.move_to(damaged, _MOVE_TO_OPTIONS) return False # TODO: turn this into part of a large generic cross-room movement module if not self.pos.isEqualTo(marker_flag.pos): distance = movement.chebyshev_distance_room_pos(self.pos, marker_flag.pos) if distance > 50: if 'checkpoint' not in self.memory or \ movement.chebyshev_distance_room_pos(self.memory.checkpoint, self.pos) > 50: self.memory.checkpoint = self.pos if self.memory.next_ppos \ and movement.chebyshev_distance_room_pos(self.pos, self.memory.next_ppos) > 10 \ and not hostile_utils.enemy_owns_room(self.pos.roomName): self.memory.checkpoint = self.pos del self.memory.next_ppos del self.memory.off_path_for del self.memory.lost_path_at del self.memory._move if hostile_utils.enemy_owns_room(self.memory.checkpoint.roomName): self.memory.checkpoint = self.home.spawn or movement.find_an_open_space(self.home.name) self.follow_military_path(_.create(RoomPosition.prototype, self.memory.checkpoint), marker_flag.pos, {'range': 1}) self.creep.say("G1") elif distance >= 1: self.move_to(marker_flag, _MOVE_TO_OPTIONS) self.creep.say("G2") else: self.basic_move_to(marker_flag) self.creep.say("G3") return False closest_creep = cast(Creep, Game.getObjectById(closest.id)) min_distance = movement.chebyshev_distance_room_pos(closest_pos, self.pos) if Game.time % 2: self.creep.say("{},{}: {}".format(closest_pos.x, closest_pos.y, min_distance)) else: self.creep.say("🐾 🏹 🐾", True) fatigue = (closest_creep and (closest_creep.fatigue or not closest_creep.hasActiveBodyparts(MOVE))) if self.memory.healing: self.memory.healing = self_damaged = self.creep.hits < self.creep.hitsMax else: # If 1/4 of our ranged attack parts are dead. total_ra = self.creep.getBodyparts(RANGED_ATTACK) alive_ra = self.creep.getActiveBodyparts(RANGED_ATTACK) self.memory.healing = self_damaged = (total_ra < 10 and alive_ra < total_ra / 2) or alive_ra < total_ra / 3 if closest_pos.roomName == self.pos.roomName and min_distance <= 3: if mass_attack: self.creep.rangedMassAttack() else: self.creep.rangedAttack(closest_creep) if (min_distance <= 6) and self.pos.roomName != closest_pos.roomName: self.memory.countdown = (self.memory.countdown or 10) - 1 if self.memory.countdown <= 0: if self.memory.countdown == 0: self.memory.countdown -= 1 if self.memory.countdown <= 5: del self.memory.countdown self.move_to(marker_flag, _MOVE_TO_OPTIONS) return if ranged and self_damaged: safe_distance = 5 elif ranged and only_ranged: safe_distance = 0 else: safe_distance = 3 should_run = (not _.some(self.pos.lookFor(LOOK_STRUCTURES), {'structureType': STRUCTURE_RAMPART, 'my': True}) and not harmless and (min_distance < safe_distance or (min_distance == safe_distance and not fatigue))) should_approach = not should_run and (harmless or min_distance > safe_distance) if should_approach: # NOTE: this depends on our custom moveTo function not checking for instanceof RoomPosition self.move_to(closest_pos, _MOVE_TO_OPTIONS) elif should_run: kiting_path = errorlog.try_exec( 'kiting-offense', kiting_away_raw_path, lambda pos: "Error calculating or moving by kiting path at pos {}.".format(pos), self.pos, [{ 'pos': positions.deserialize_xy_to_pos(h.pos, h.room), 'range': 10, } for h in hostiles_nearby], marker_flag ) if kiting_path is True: # errored self.creep.say("Err") self.go_to_depot() elif len(kiting_path): self.creep.move(self.pos.getDirectionTo(kiting_path[0])) else: self.log("WARNING: kiting offense has no path at position {}!".format(self.pos))
def run(self): if self.memory.dismantling and self.creep.hits < self.creep.hitsMax / 2: self.memory.dismantling = False self.targets.untarget(self, target_single_flag2) if not self.memory.dismantling and self.creep.hits >= self.creep.hitsMax: self.memory.dismantling = True self.targets.untarget(self, target_single_flag2) if self.memory.dismantling: target = cast( Optional[Flag], self.targets.get_new_target(self, target_single_flag, ATTACK_DISMANTLE)) if not target: if len(flags.find_flags(self.home, RAID_OVER)): if self.creep.ticksToLive < 300: self.creep.suicide() else: self.memory.last_role = self.memory.role self.memory.role = role_recycling else: self.log("Dismantler has no target!") self.go_to_depot() return if target.name in Memory.flags and target.memory.civilian: self.memory.running = 'idle' if self.pos.roomName == target.pos.roomName: new_target = False dismantled = False structure = cast( Optional[Structure], self.room.look_at(LOOK_STRUCTURES, target.pos)[0]) if structure: new_target, dismantled = self.do_dismantle(structure) else: site = cast( Optional[ConstructionSite], self.room.look_at(LOOK_CONSTRUCTION_SITES, target.pos)[0]) if site and not site.my: self.move_to(site) elif self.memory.dt: # dismantler target mem_pos = positions.deserialize_xy_to_pos( self.memory.dt, target.pos.roomName) structure = cast( Optional[Structure], self.room.look_at(LOOK_STRUCTURES, mem_pos)[0]) if structure: new_target, dismantled = self.do_dismantle( structure) else: site = self.room.look_at(LOOK_CONSTRUCTION_SITES, mem_pos)[0] if site: self.move_to(site) else: new_target = True else: new_target = True if new_target: if target.name in Memory.flags and 'dismantle_all' in target.memory and \ not target.memory['dismantle_all']: self.remove_target(target) return structures = self.room.find(FIND_STRUCTURES) sites = self.room.find(FIND_CONSTRUCTION_SITES) best_priority = -Infinity best = None hits_per_tick = DISMANTLE_POWER * self.creep.getActiveBodypartsBoostEquivalent( WORK, 'dismantle') for structure in cast( List[Union[Structure, ConstructionSite]], structures.concat(sites)): stype = structure.structureType if structure.my or stype == STRUCTURE_CONTROLLER or stype == STRUCTURE_PORTAL \ or (stype == STRUCTURE_EXTRACTOR and not structure.hits) \ or (cast(StructureContainer, structure).store and _.findKey(cast(StructureContainer, structure).store, lambda amount, key: amount > 100 and (key != RESOURCE_ENERGY or amount > 10 * 1000))): continue distance = movement.chebyshev_distance_room_pos( self.pos, structure.pos) priority = -distance if stype == STRUCTURE_WALL or stype == STRUCTURE_RAMPART: if structure.hits: priority -= structure.hits / hits_per_tick if structure.progressTotal: # a construction site priority -= 50 if stype == STRUCTURE_ROAD and distance > 1: priority -= 500 * distance if priority > best_priority: best_priority = priority best = structure if best: self.memory.dt = positions.serialize_pos_xy( best.pos) # dismantler target if __pragma__('js', '(best instanceof ConstructionSite)'): self.move_to(best) elif not dismantled: self.do_dismantle(best) else: self.move_to(best) else: self.remove_target(target) return else: if self.memory.dt: # dismantler target target = positions.deserialize_xy_to_pos( self.memory.dt, target.pos.roomName) if 'checkpoint' not in self.memory or \ movement.chebyshev_distance_room_pos(self.memory.checkpoint, self.pos) > 50: self.memory.checkpoint = self.pos if hostile_utils.enemy_owns_room( self.memory.checkpoint.roomName): self.memory.checkpoint = self.home.spawn or movement.find_an_open_space( self.home.name) self.follow_military_path( _.create(RoomPosition.prototype, self.memory.checkpoint), target) else: target = self.targets.get_new_target(self, target_single_flag2, TD_H_D_STOP) if not target: if len(flags.find_flags(self.home, RAID_OVER)): if self.creep.ticksToLive < 300: self.creep.suicide() else: self.recycle_me() else: self.log("Dismantler has no healer target!") self.go_to_depot() return if self.pos.roomName != target.pos.roomName: self.creep.moveTo(target) else: room = self.hive.get_room(target.pos.roomName) if room and _.find(room.find(FIND_MY_CREEPS), lambda c: c.memory.role == role_td_healer): if not self.pos.isEqualTo(target): self.creep.moveTo(target) self.follow_military_path(self.home.spawn.pos, target) else: self.go_to_depot()
def follow_military_path(self, origin, target, opts = None): # type: (RoomPosition, RoomPosition, Dict[str, Any]) -> None origin = robjs.pos(origin) target = robjs.pos(target) if opts and "to_home" in opts: to_home = opts["to_home"] else: to_home = False if not origin: origin = movement.find_an_open_space(self.memory.home) if self.creep.fatigue > 0: return if self.pos.getRangeTo(target) < 10 or self.pos.roomName == target.roomName: self.move_to(target) return path_opts = { 'current_room': self.pos.roomName, } if opts: path_opts = _.merge(path_opts, opts) # TODO: this is all stupid, PathFinder is stupid for multiple rooms! if chebyshev_distance_room_pos(origin, target) > 900 \ and not is_path_portal(origin, target) and target.roomName != 'W11S56': path_opts.max_ops = chebyshev_distance_room_pos(origin, target) * 150 path_opts.max_rooms = math.ceil(chebyshev_distance_room_pos(origin, target) / 5) # TODO: handle this better (this is for not having multiple super-duper-long cached paths) if to_home: intermediate = find_an_open_space(origin.roomName) origin = intermediate else: intermediate = center_pos(target.roomName) if self.pos.roomName != intermediate.roomName: target = intermediate path_opts.range = max(path_opts.range or 0, 10) else: # If we're this far away, let's just get to the room using a cached path and then do # basic pathfinding to get to our actual target. self.move_to(target) return pass origin_midpoint = find_midpoint(self.pos, self.pos, origin) if origin_midpoint is not None: origin = origin_midpoint dest_midpoint = find_midpoint(self.pos, origin, target) if dest_midpoint is not None: if self.pos.roomName == dest_midpoint.roomName: origin = dest_midpoint else: target = dest_midpoint path_opts.range = max(path_opts.range or 0, 10) path = self.hive.honey.find_serialized_path(origin, target, path_opts) # TODO: manually check the next position, and if it's a creep check what direction it's going result = self.creep.moveByPath(path) if result == ERR_NOT_FOUND: if self.memory.manual: self.move_to(target) elif not self.memory.next_ppos or movement.chebyshev_distance_room_pos(self.pos, self.memory.next_ppos) \ > CREEP_LIFE_TIME: all_positions = self.hive.honey.list_of_room_positions_in_path(origin, target, path_opts) closest = None closest_distance = Infinity for pos in all_positions: distance = chebyshev_distance_room_pos(self.pos, pos) if distance < closest_distance: closest_distance = distance closest = pos if closest and closest_distance < CREEP_LIFE_TIME: self.memory.next_ppos = closest if closest.isEqualTo(self.pos): self.log("WARNING: ERR_NOT_FOUND when actually still on military path! Path retrieved:\n{}" "\nPos: {}.".format(path, self.pos)) if chebyshev_distance_room_pos(self.pos, target) <= 50: self.memory.manual = True self.move_to(target) return else: portals = cast(List[StructurePortal], _.filter(self.room.find(FIND_STRUCTURES), {'structureType': STRUCTURE_PORTAL})) if len(portals) and movement.chebyshev_distance_room_pos(self.pos, portals[0].pos) \ + movement.chebyshev_distance_room_pos(portals[0].destination, target) \ < movement.chebyshev_distance_room_pos(self.pos, target): self.memory.next_ppos = self.pos.findClosestByRange(portals).pos else: self.log("WARNING: Couldn't find closest position on path from {} to {} near {}!" "\nMoving manually... (all pos: {})" .format(origin, target, self.pos, all_positions)) self.memory.next_ppos = target mtarget = self.memory.next_ppos if mtarget: new_target = __new__(RoomPosition(mtarget.x, mtarget.y, mtarget.roomName)) if self.pos.isNearTo(new_target): self.creep.move(self.pos.getDirectionTo(new_target)) else: if self.memory.checkpoint and movement.chebyshev_distance_room_pos(self.pos, new_target) > 20: del self.memory.checkpoint del self.memory.next_ppos del self.memory.lost_path_at del self.memory.off_path_for return self.move_to(new_target) if self.pos.isEqualTo(new_target): del self.memory.next_ppos if not self.memory.off_path_for: self.memory.off_path_for = 1 self.memory.lost_path_at = self.pos else: if not self.memory.lost_path_at: self.memory.lost_path_at = self.pos self.memory.off_path_for += 1 if self.memory.off_path_for > 10: if chebyshev_distance_room_pos(self.memory.lost_path_at, self.pos) < 5 \ and not self.pos.isEqualTo(new_target) \ and not self.pos.isEqualTo(get_entrance_for_exit_pos(new_target)): honey.clear_cached_path(origin, target, path_opts) del self.memory.off_path_for del self.memory.lost_path_at del self.memory.next_ppos self.log("Lost the path from {} to {}! Pos: {}. Retargeting to: {} (path: {})".format( origin, target, self.pos, new_target, ', '.join([ "({},{})".format(p.x, p.y) for p in Room.deserializePath( _.get(self.memory, ['_move', 'path'], '')) ]))) elif result != OK: self.log("Unknown result from follow_military_path: {}".format(result)) else: # String.fromCodePoint(pos.x | (pos.y << 6)); # var val = str.charCodeAt(i); # var x = (val & 0x3F); # var y = ((val >> 6) & 0x3F); # return {x: x, y: y}; if self.memory.off_path_for: del self.memory.next_ppos del self.memory.off_path_for del self.memory.lost_path_at serialized_pos = self.pos.x | (self.pos.y << 6) if self.memory.last_pos == serialized_pos: self.log("standstill! at: {}", self.pos) if self.memory.standstill_for: self.memory.standstill_for += 1 else: self.memory.standstill_for = 1 if self.memory.standstill_for == 5: del self.memory.next_ppos found_mine = False for pos in self.hive.honey.find_path(origin, target, path_opts): if pos.x == self.pos.x and pos.y == self.pos.y: found_mine = True elif found_mine: if is_block_clear(self.room, pos.x, pos.y): self.memory.next_ppos = {"x": pos.x, "y": pos.y, "roomName": self.pos.roomName} self.move_to(__new__(RoomPosition(pos.x, pos.y, self.pos.roomName))) break if self.memory.standstill_for > 10: del self.memory.last_position del self.memory.standstill_for del self.memory.next_ppos honey.clear_cached_path(origin, target, path_opts) self.move_to(target) else: self.memory.last_pos = serialized_pos del self.memory.standstill_for
def run(self): target_id = self.memory.attack_target if not target_id: best_id = None closest_distance = Infinity for hostile in self.room.defense.dangerous_hostiles(): distance = movement.chebyshev_distance_room_pos( self.pos, hostile.pos) if distance < closest_distance: best_id = hostile.id closest_distance = distance if not best_id: for mem_hostile in self.home.defense.remote_hostiles(): distance = movement.chebyshev_distance_room_pos( self.pos, positions.deserialize_xy_to_pos( mem_hostile.pos, mem_hostile.room)) if mem_hostile.ranged and not mem_hostile.attack: distance += 1000 # Don't go after kiting attackers if distance < closest_distance: best_id = mem_hostile.id closest_distance = distance if best_id: target_id = best_id self.memory.attack_target = best_id else: self.memory.role = role_recycling self.memory.last_role = role_defender return False hostile_info = Memory.hostiles[target_id] if not hostile_info or Game.time >= hostile_info.dead: del self.memory.attack_target return True hostile_room = hostile_info.room hostile_pos = positions.deserialize_xy_to_pos(hostile_info.pos, hostile_room) if self.pos.roomName != hostile_room: if 'checkpoint' not in self.memory or \ movement.chebyshev_distance_room_pos(self.memory.checkpoint, self.pos) > 50: self.memory.checkpoint = self.pos if hostile_utils.enemy_owns_room(self.memory.checkpoint.roomName): self.memory.checkpoint = self.home.spawn or movement.find_an_open_space( self.home.name) if 'enemy_checkpoint' in self.memory: enemy_checkpoint = self.memory.enemy_checkpoint if movement.chebyshev_distance_room_pos( enemy_checkpoint, hostile_pos) > 10: enemy_checkpoint = self.memory.enemy_checkpoint = hostile_pos else: enemy_checkpoint = self.memory.enemy_checkpoint = hostile_pos self.follow_military_path( _.create(RoomPosition.prototype, self.memory.checkpoint), _.create(RoomPosition.prototype, enemy_checkpoint), {'range': 1}) return False target = cast(Creep, Game.getObjectById(target_id)) if target is None or (self.room.hostile and target.owner.username != INVADER_USERNAME): del self.memory.attack_target del Memory.hostiles[target_id] if hostile_room in Memory.rooms: room_hostiles = Memory.rooms[hostile_room][ rmem_key_stored_hostiles] index = _.findIndex(room_hostiles, lambda x: x.id == target_id) if index != -1: room_hostiles.splice(index, 1) return True if self.pos.isNearTo(target): self.creep.attack(target) else: self.move_to(target, {'reusePath': 2})