def find_new_target_rampart_defense_spot(targets, creep): # type: (TargetMind, RoleBase) -> Optional[str] hot_spots, cold_spots = creep.home.defense.get_current_defender_spots() nearest = None nearest_distance = Infinity for location in hot_spots: if not targets.targets[target_rampart_defense][location.name]: distance = movement.chebyshev_distance_room_pos( location, creep.pos) if distance < nearest_distance: nearest = location nearest_distance = distance if nearest is None: for location in cold_spots: if not targets.targets[target_rampart_defense][location.name]: distance = movement.chebyshev_distance_room_pos( location, creep.pos) if distance < nearest_distance: nearest = location nearest_distance = distance if nearest is None: for location in creep.home.defense.get_old_defender_spots(): if not targets.targets[target_rampart_defense][location.name]: distance = movement.chebyshev_distance_room_pos( location, creep.pos) if distance < nearest_distance: nearest = location nearest_distance = distance if nearest: return nearest.name else: return None
def move_to_closest_of(c, targets): # type: (SquadDrone, List[Union[RoomPosition, RoomObject, SquadDrone]]) -> bool target = None distance = Infinity for test_target in targets: test_distance = movement.chebyshev_distance_room_pos( c.pos, robjs.pos(test_target)) if test_distance < distance: distance = test_distance target = test_target target = robjs.pos(target) if c.pos.roomName == target.roomName: if c.pos.isNearTo(target): return False else: c.move_to(target) return True elif movement.chebyshev_distance_room_pos(c.pos, target) < 100: c.move_to(target) return True else: # TODO: this should accommodate reroutes _faster_? reroute = portals.recommended_reroute(c.pos, target) if reroute is not None: target = reroute[0] c.move_to(target) return True
def mark_creeps(room): # type: (RoomMind) -> None """ :type room: rooms.room_mind.RoomMind """ all_hostiles = room.room.find(FIND_HOSTILE_CREEPS) hostiles = [] for creep in cast(List[Creep], all_hostiles): if creep.hasActiveOffenseBodyparts(): hostiles.append(creep) count = len(hostiles) if count > 3: for creep in cast(List[Creep], room.find(FIND_MY_CREEPS)): Memory.deathwatch.append([ creep.name, creep.memory.home, _(hostiles).map(lambda h: _.get(h, ['owner', 'username'], 'unknown')).uniq().value(), room.name, ]) elif count > 0: for creep in cast(List[Creep], room.find(FIND_MY_CREEPS)): if _.some( hostiles, lambda h: movement.chebyshev_distance_room_pos( h.pos, creep.pos) < 4): Memory.deathwatch.append([ creep.name, creep.memory.home, _(hostiles).filter( lambda h: movement.chebyshev_distance_room_pos( h.pos, creep.pos) < 4).map( lambda h: _.get(h, ['owner', 'username'], 'unknown')).uniq().value(), room.name, ])
def closest_deposit_point_to_mine(self, flag): # type: (Flag) -> Optional[Structure] """ Gets the closest deposit point to the mine. Currently just returns storage or spawn, since we need to do more changes in order to support links well anyways. :param flag: :return: """ key = "mine_{}_deposit".format(flag.name) target_id = self.room.get_cached_property(key) if target_id: target = cast(Structure, Game.getObjectById(target_id)) if target: return target # Even if we don't have a link manager active right now, we will soon if there is a main link if self.room.links.main_link and flag.pos.roomName == self.room.name: main_link_id = self.room.links.main_link.id upgrader_link = self.room.get_upgrader_energy_struct() upgrader_link_id = upgrader_link and upgrader_link.id or None storage = self.room.room.storage if storage and storage.storeCapacity > 0: # TODO: see if this produces an error...? it should distance = movement.chebyshev_distance_room_pos( storage.pos, flag.pos) if distance <= 2: best_priority = -40 best = storage else: best_priority = 0 best = storage else: best_priority = Infinity best = None if best_priority > -40: for link in self.room.links.links: if link.energyCapacity <= 0 or link.id == main_link_id: continue distance = movement.chebyshev_distance_room_pos( link.pos, flag.pos) if distance <= 2: priority = -20 elif link.id == upgrader_link_id: continue else: priority = distance if priority < best_priority: best_priority = priority best = link target = best elif self.room.room.storage and self.room.room.storage.storeCapacity > 0: target = self.room.room.storage elif self.room.spawn: target = self.room.spawn else: return None target_id = target.id self.room.store_cached_property(key, target_id, 50) return target
def move_to(self, target): # type: (RoomPosition) -> None """ Method that judges distance to target, and then delegates to stage_0, stage_1 or stage_2 movement. """ hive = self.home.hive home = self.find_home() origin = self.find_origin() total_distance = hive.honey.find_path_length(origin, target, self.new_movement_opts()) min_distance_from_home = Infinity min_distance_to_origin = Infinity min_distance_to_target = movement.chebyshev_distance_room_pos( self.members_movement_order()[0].pos, target) max_distance_to_target = -Infinity any_hostiles = False for member in self.members: distance_to_home = movement.chebyshev_distance_room_pos( member.pos, home) distance_to_origin = movement.chebyshev_distance_room_pos( member.pos, origin) distance_to_target = movement.chebyshev_distance_room_pos( member.pos, target) if distance_to_home < min_distance_from_home: min_distance_from_home = distance_to_home if distance_to_target > max_distance_to_target: max_distance_to_target = distance_to_target if distance_to_origin < min_distance_to_origin: min_distance_to_origin = distance_to_origin if len(member.room.find(FIND_HOSTILE_CREEPS)): any_hostiles = True if min_distance_to_origin > 100: mv_order = self.members_movement_order() self.set_origin(mv_order[len(mv_order) - 1].pos) if min_distance_from_home < 50 and (max_distance_to_target < total_distance / 2): self.log( "move_to: chose stage 0 (minimum distance from home: {}, maximum distance from home: {}," " total distance: {})".format(min_distance_from_home, max_distance_to_target, total_distance)) self.move_to_stage_0(target) elif min_distance_to_target < 300 and any_hostiles: self.move_to_stage_2(target) elif min_distance_to_target > 60 or max_distance_to_target > 200: # self.log("move_to: chose stage 1 (minimum distance from home: {}, total distance: {}, " # "minimum distance to target: {}, maximum distance to target: {})" # .format(min_distance_from_home, total_distance, # min_distance_to_target, max_distance_to_target)) self.move_to_stage_1(target, any_hostiles) else: # self.log("move_to: chose stage 2 (minimum distance from home: {}, total distance: {}, " # "minimum distance to target: {}, maximum distance to target: {})" # .format(min_distance_from_home, total_distance, # min_distance_to_target, max_distance_to_target)) self.move_to_stage_2(target)
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_new_target_source(targets, creep): # type: (TargetMind, RoleBase) -> Optional[str] has_work = not not creep.creep.hasActiveBodyparts(WORK) any_miners = not not creep.home.role_count(role_miner) highest_priority = -Infinity best_source = None for source in creep.home.sources: if not has_work and not _.some( creep.home.find_in_range(FIND_MY_CREEPS, 1, source.pos), lambda c: c.memory.role == role_miner): continue distance = movement.chebyshev_distance_room_pos(source.pos, creep.pos) current_work_force = targets.workforce_of(target_source, source.id) if any_miners: energy = _.sum( creep.home.find_in_range(FIND_DROPPED_RESOURCES, 1, source.pos), 'amount') priority = energy - current_work_force * 100 - distance * 2 else: oss = creep.home.get_open_source_spaces_around(source) priority = oss * 10 - 100 * current_work_force / oss - distance if source.energy <= 0: priority -= 200 if not priority: print("[targets] Strange priority result for source {}: {}".format( source, priority)) if priority > highest_priority: best_source = source.id highest_priority = priority return best_source
def run_squad(self, members, target): # type: (List[SquadDrone], Location) -> None best_near_rank = -Infinity best_near = None best_damaged_rank = -Infinity best_damaged_near = None for to_check in members: if self.pos.isNearTo(to_check.pos): specialty = to_check.findSpecialty() if specialty == HEAL and to_check.creep.hits < to_check.creep.hitsMax * 0.7: rank = 7 elif specialty == RANGED_ATTACK or specialty == ATTACK or specialty == WORK: rank = 5 else: rank = 1 if to_check.creep.hits < to_check.creep.hitsMax: rank += (to_check.creep.hitsMax - to_check.creep.hits) / to_check.creep.hitsMax if best_damaged_rank < rank: best_damaged_near = to_check best_damaged_rank = rank if best_near_rank < rank: best_near = to_check best_near_rank = rank if best_damaged_near: result = self.creep.heal(best_damaged_near.creep) if result != OK: self.log("Unknown result using {}.heal({}): {}" .format(self.creep, best_damaged_rank.creep, result)) elif movement.chebyshev_distance_room_pos(self.pos, target) < 100 and best_near: result = self.creep.heal(best_near.creep) if result != OK: self.log("Unknown result using {}.heal({}): {}" .format(self.creep, best_near.creep, result))
def run(self): claim_flag = self.targets.get_new_target(self, target_single_flag, CLAIM_LATER) if not claim_flag: self.memory.last_role = self.memory.role self.memory.role = role_recycling return if self.pos.roomName != claim_flag.pos.roomName: target = claim_flag.pos if 'checkpoint' not in self.memory or \ movement.chebyshev_distance_room_pos(self.memory.checkpoint, self.pos) > 50: self.memory.checkpoint = self.pos opts = {'range': 15} if self.creep.getActiveBodyparts(MOVE) >= len( self.creep.body) * 5 / 7: opts.ignore_swamp = True opts.use_roads = False elif self.creep.getActiveBodyparts(MOVE) >= len( self.creep.body) / 2: opts.use_roads = False self.follow_military_path( _.create(RoomPosition.prototype, self.memory.checkpoint), target, opts) return False target = self.creep.room.controller if not target: self.log("ERROR: Claim can't find controller in room {}!".format( self.creep.room.name)) self.targets.untarget_all(self) return True if target.my: self.memory.home = self.pos.roomName self.targets.untarget_all(self) # I guess we can try and claim something else, if we have the life? otherwise this will go and activate the # recycle code. return True if not self.pos.isNearTo(target): self.move_to(target) return False if target.owner: self.creep.attackController(target) else: self.creep.claimController(target) room = self.hive.get_room(target.pos.roomName) room.mem.sponsor = self.home.name if _.get( flags.find_flags(room, CLAIM_LATER)[0], 'memory.prio_walls', False): room.mem.prio_walls = True if _.get( flags.find_flags(room, CLAIM_LATER)[0], 'memory.prio_spawn', False): room.mem.prio_spawn = True
def run(self): # flag to other creeps if 'filling' in self.memory: del self.memory.filling if self.pos.roomName != self.home.name: target = None if self.carry_sum() > 0: target = self.home.room.storage if target == undefined: target = self.home.spawn if target == undefined or self.creep.ticksToLive < movement.chebyshev_distance_room_pos( self.pos, target.pos): self.creep.suicide() return False if 'checkpoint' not in self.memory or \ movement.chebyshev_distance_room_pos(self.memory.checkpoint, self.pos) > 50: self.memory.checkpoint = self.pos self.follow_military_path( _.create(RoomPosition.prototype, self.memory.checkpoint), target.pos, {'range': 1}) return False if self.carry_sum() > 0: storage = self.home.room.storage if storage and _.sum(storage.store) < storage.storeCapacity: if self.pos.isNearTo(storage): for rtype in Object.keys(self.creep.carry): if self.creep.carry[rtype] > 0: result = self.creep.transfer(storage, rtype) if result == OK: break else: self.log( "Unknown result from recycling-creep.transfer({}, {}): {}" .format(storage, rtype, result)) elif self.creep.ticksToLive <= self.pos.getRangeTo( storage.pos): self.creep.suicide() else: self.move_to(storage) return False elif self.creep.carry[RESOURCE_ENERGY] > 0: return self.refill_creeps() self.recycle_me()
def move_to_can_reach(self, target): # type: (RoomPosition) -> bool self.move_to(target) path = Room.deserializePath(self.memory['_move']['path']) # If we can't reach the target, let's find a new one pos = __new__( RoomPosition(path[len(path) - 1].x, path[len(path) - 1].y, self.pos.roomName)) return len(path) and movement.chebyshev_distance_room_pos(pos, target) <= 1
def get_military_path_length(self, spawn, target, opts = None): # type: (RoomPosition, RoomPosition, Dict[str, Any]) -> int spawn = robjs.pos(spawn) target = robjs.pos(target) if opts: path_opts = opts else: path_opts = {} # if distance_squared_room_pos(spawn, target) > math.pow(200, 2): # # TODO: handle this better (this is for not having multiple super-duper-long cached paths) # intermediate = __new__(RoomPosition(25, 25, target.roomName)) # path_opts.max_ops = 30000 # path_opts.max_rooms = 30 # path_opts.use_roads = False # path1 = self.hive.honey.find_path(spawn, intermediate, path_opts) # path2 = self.hive.honey.find_path(intermediate, target, path_opts) # return len(path1) + 20 + len(path2) # else: path_opts.max_ops = chebyshev_distance_room_pos(spawn, target) * 150 path_opts.max_rooms = math.ceil(chebyshev_distance_room_pos(spawn, target) / 5) return self.hive.honey.find_path_length(spawn, target, path_opts)
def find_new_target_energy_site(targets, creep, pos): # type: (TargetMind, RoleBase, Optional[RoomPosition]) -> Optional[str] if not pos: pos = creep.pos if creep.home.full_storage_use: best = creep.home.room.storage # Still usually prefer storage over any links, unless a lot longer distance (>13 more away) best_priority = movement.chebyshev_distance_room_pos(pos, best.pos) - 13 if creep.home.links.enabled: for struct in creep.home.links.links: current_targets = targets.targets[target_closest_energy_site][ struct.id] priority = movement.chebyshev_distance_room_pos( pos, struct.pos) if priority < best_priority and (not current_targets or current_targets < 2): best = struct best_priority = priority return best.id else: return None
def run_boosts(self): # type: () -> None for specialty, creeps in list(self._boost_registered.entries()): mineral = _boosts_to_use[specialty] creeps = _.sortBy(creeps, lambda c: c.ticksToLive) original_labs = self.room.minerals.labs_for(mineral) labs = _.clone(original_labs) while len(creeps): creep = creeps.js_pop() closest_lab = None closest_distance = Infinity if len(labs): for lab in labs: distance = movement.chebyshev_distance_room_pos( lab.pos, creep.pos) if distance < closest_distance: closest_lab = lab closest_distance = distance _.pull(labs, [closest_lab]) boost_if_close = True else: for lab in original_labs: distance = movement.chebyshev_distance_room_pos( lab.pos, creep.pos) if distance < closest_distance: closest_lab = lab closest_distance = distance boost_if_close = False if creep.pos.isNearTo(closest_lab) and ( boost_if_close or not closest_lab.__boosted): result = closest_lab.boostCreep(creep.creep) closest_lab.__boosted = True if result != OK: print( "[{}][squads] Unknown result from {}.boostCreep({}): {}" .format(self.room.name, closest_lab, creep.creep, result)) else: creep.move_to(closest_lab)
def run_lab_drop_off(self): mind = self.home.minerals best_lab = None best_resource = None closest_distance = Infinity for lab, mineral, amount in mind.get_lab_targets(): if lab.mineralAmount < amount and self.creep.carry[mineral]: distance = movement.chebyshev_distance_room_pos( self.pos, lab.pos) if distance < closest_distance: closest_distance = distance best_lab = lab best_resource = mineral if not best_lab: for lab in mind.labs(): if lab.energy < lab.energyCapacity and self.creep.carry[ RESOURCE_ENERGY]: distance = movement.chebyshev_distance_room_pos( self.pos, lab.pos) if distance < closest_distance: closest_distance = distance best_lab = lab best_resource = RESOURCE_ENERGY if not best_lab: if self.memory.debug: self.log("Untargeting labs: no minerals needed that we have.") del self.memory.state return if not self.pos.isNearTo(best_lab): self.move_to(best_lab) return False result = self.creep.transfer(best_lab, best_resource) if result != OK: self.log("Unknown result from mineral-hauler.transfer({}, {}): {}". format(best_lab, best_resource, result))
def find_new_target_small_repair_site( targets, creep, max_hits, max_work=_default_maximum_repair_workforce): # type: (TargetMind, RoleBase, int, int) -> Optional[str] repair_targets = creep.home.building.get_repair_targets() if not len(repair_targets): return None # closest_distance = Infinity # smallest_num_builders = Infinity # best_id = None if len(repair_targets) <= 1 and not len( creep.home.building.get_construction_targets()): max_work = Infinity best_id = None second_best_id = None for struct_id in repair_targets: structure = cast(Structure, Game.getObjectById(struct_id)) if not structure: continue # TODO: merge this logic with ConstructionMind _efficiently!_ this_hits_max = min(structure.hitsMax, max_hits) if structure and structure.hits < this_hits_max * 0.9: distance = movement.chebyshev_distance_room_pos( structure.pos, creep.pos) ticks_to_repair = (structure.hitsMax - structure.hits) \ / (creep.creep.getActiveBodyparts(WORK) * REPAIR_POWER) if ticks_to_repair < 10 and distance < 3: return structure.id elif distance + ticks_to_repair < 15: best_id = structure.id if second_best_id: continue if max_work is Infinity: current_max = Infinity else: current_max = min( max_work, math.ceil((this_hits_max - structure.hits) / 50)) current_workforce = targets.workforce_of(target_repair, struct_id) if not current_workforce or current_workforce < current_max: # or current_workforce < smallest_num_builders + 1: # Already priority sorted second_best_id = structure.id # distance = movement.distance_squared_room_pos(structure.pos, creep.creep.pos) # if distance < closest_distance: # smallest_num_builders = current_workforce # closest_distance = distance # best_id = struct_id if best_id: return best_id else: return second_best_id
def get_main_link(self): # type: () -> Optional[StructureLink] if self._main_link is undefined: if self.room.my and self.room.room.storage and len( self.links) >= 2: for link in self.links: if movement.chebyshev_distance_room_pos( self.room.room.storage.pos, link.pos) <= 2: if self._main_link is undefined: self._main_link = link else: self._second_link = link if self._main_link is undefined: self._main_link = None if self._second_link is undefined: self._second_link = None return self._main_link
def run_squad(self, members, target): # type: (List[SquadDrone], Location) -> None attacked = False here = cast(List[Creep], self.room.find(FIND_HOSTILE_CREEPS)) if len(here): directly_nearby = 0 best = None best_range = Infinity best_rank = -Infinity for enemy in here: enemy_range = movement.chebyshev_distance_room_pos(enemy.pos, self.pos) if enemy_range <= 3: specialty = enemy.findSpecialty() if specialty == ATTACK or specialty == RANGED_ATTACK: rank = 40 elif specialty == WORK: rank = 35 else: rank = 30 if _.some(self.room.look_at(LOOK_STRUCTURES, enemy.pos), lambda s: s.structureType == STRUCTURE_RAMPART and not s.my): rank -= 20 rank += (enemy.hitsMax - enemy.hits) / enemy.hitsMax * 5 if enemy_range < 1: directly_nearby += rank if rank > best_rank: best_rank = rank best_range = enemy_range best = enemy if directly_nearby > 65 or best_range <= 1: result = self.creep.rangedMassAttack() if result != OK: self.log("Unknown result from {}.rangedMassAttack(): {}" .format(self.creep, result)) attacked = True elif best: result = self.creep.rangedAttack(best) if result != OK: self.log("Unknown result from {}.rangedAttack({}): {}" .format(self.creep, best, result)) attacked = True if not attacked: to_dismantle = volatile_cache.mem('dismantle_squad_dismantling').get(target.name) if to_dismantle: self.creep.rangedAttack(to_dismantle)
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 get_ordered(self, target: RoomPosition, serialized_obj: Dict[str, str], dismantle: List[SquadDismantle], heal: List[SquadDrone], attack: List[SquadDrone], already_repathed: bool = False) -> Tuple[bool, bool]: rebuilt = robjs.concat_lists(dismantle, heal, attack) first_creep = rebuilt[0] serialized_path_this_room = serialized_obj[first_creep.pos.roomName] if serialized_path_this_room: path_this_room = Room.deserializePath(serialized_path_this_room) total_positions_this_room = len(path_this_room) else: total_positions_this_room = 0 path_this_room = None if path_this_room is not None and total_positions_this_room >= len( self.members) + 4: if total_positions_this_room >= len(self.members) * 2 + 4: first_index = int(len(path_this_room) / 2) else: first_index = len(path_this_room) - 2 any_off = False for index in range(0, len(rebuilt)): pos = path_this_room[first_index - index] creep = rebuilt[index] pos = __new__( RoomPosition(pos.x, pos.y, first_creep.pos.roomName)) if creep.pos.isEqualTo(pos): continue else: any_off = True creep.move_to(pos) if not any_off: self.mem[dismemkey_ordered] = True return True, already_repathed else: next_intermediate_goal = target origin = _.max( self.members, lambda m: movement.chebyshev_distance_room_pos( m.pos, next_intermediate_goal)).pos reroute = portals.recommended_reroute(origin, target) if reroute is not None: next_intermediate_goal = reroute[0] origin = _.max( self.members, lambda m: movement.chebyshev_distance_room_pos( m, next_intermediate_goal)) self.set_origin(origin) serialized_obj = self.home.hive.honey.get_serialized_path_obj( origin, target, self.new_movement_opts()) if not serialized_obj[first_creep.pos.roomName]: self.log( "Uh-oh - path from furthest creep to target did not include the room the first creep is in." " Setting origin to first creep's pos.") self.set_origin(first_creep.pos) serialized_obj = self.home.hive.honey.get_serialized_path_obj( origin, target, self.new_movement_opts()) if not serialized_obj[first_creep.pos.roomName]: self.log( "Path from first creep {} to {} did not include room {}! ...", first_creep.pos, target, first_creep.pos.roomName) return False, False return self.get_ordered(target, serialized_obj, dismantle, heal, attack, True) return False, already_repathed
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 run_squad(self, members, target, do_things = False): """ :type members: list[SquadDrone] :type target: position_management.locations.Location :type do_things: bool """ if not do_things: return 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 = target 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) 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.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)) 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 nearby = [] harmless = False ranged = False only_ranged = True mass_attack = False if not closest: self.move_to(target) return 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(ATTACK) alive_ra = self.creep.getActiveBodyparts(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 <= 1: self.creep.attack(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 elif self_damaged: safe_distance = 3 else: safe_distance = 0 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_away_check(creep, hostile_path_targets): # type: (Creep, List[Dict[str, Any]]) -> bool check_path = is_room_mostly_safe(creep.pos.roomName) if check_path and not creep.memory._safe or not creep.memory._safe_from \ or movement.chebyshev_distance_room_pos(creep.memory._safe_from, creep.pos) > 2: creep.memory._safe = [] creep.memory._safe_from = creep.pos any_unsafe = False for obj in hostile_path_targets: target = obj['pos'] target_range = obj['range'] # NOTE: target_range here is twice what we actually want, so that when passing to PathFinder we get a better # path. See NOTE above. distance = movement.chebyshev_distance_room_pos(target, creep.pos) if distance > target_range * 0.25 + 1: continue if check_path: safe = False for safe_pos in creep.memory._safe: if movement.chebyshev_distance_room_pos(safe_pos, target) < 2: safe = True break if safe: continue enemy_path = PathFinder.search( target, { "pos": creep.pos, "range": 1 }, { "roomCallback": enemy_purposes_cost_matrix, "maxRooms": 5, "plainCost": 1, "swampCost": 1, # for speed purposes "maxCost": 10, }) if enemy_path.incomplete: creep.memory._safe.push(target) continue distance = movement.chebyshev_distance_room_pos(target, creep.pos) if distance <= target_range * 0.25: break else: # elif distance <= target_range * 0.25 + 1: # We check this above any_unsafe = True else: return any_unsafe and random.randint( 0, 3 ) < 3 # if we're between target_range and target_range + 1, just pause path = get_cached_away_path(creep, hostile_path_targets) if len(path): del creep.memory.was_on_the_path result = creep.moveByPath(path) if result == ERR_NO_PATH or result == ERR_NOT_FOUND: # del creep.memory._away_path # path = get_cached_away_path(creep, hostile_path_targets) # result = creep.creep.moveByPath(path) # I had the above enabled previously, and I don't think it really helped any... the ERR_NOT_FOUND would just # happen with the newly-generated path too. return True if result != OK: print("[{}][{}] Unknown result from moving when running away: {}". format(creep.memory.home, creep.name, result)) return True else: # we're a safe distance away from all enemies return False
def find_target_here(self, target): # type: (Location) -> Optional[RoomPosition] opts = get_opts(self.pos.roomName) if self.memory.tloctimeout > Game.time: pos = positions.deserialize_xy_to_pos(self.memory.tloc, target.roomName) if pos: if _.some(self.room.look_at(LOOK_STRUCTURES, pos), get_dismantle_condition_not_a_road(opts)): return pos structure_target = _.find(self.room.look_at(LOOK_STRUCTURES, target), get_dismantle_condition_not_a_road(opts)) if structure_target: self.memory.tloc = positions.serialize_pos_xy(structure_target.pos) self.memory.tloctimeout = Game.time + 50 return structure_target.pos if self.pos.roomName != target.roomName: return None best_target = None best_rank = -Infinity enemy_structures = cast(List[OwnedStructure], self.room.find(FIND_HOSTILE_STRUCTURES)) opts = get_opts(self.pos.roomName) for struct in enemy_structures: structure_type = struct.structureType if not can_target_struct(struct, opts): continue if structure_type == STRUCTURE_SPAWN: rank = 50 elif structure_type == STRUCTURE_LAB: rank = 40 elif structure_type == STRUCTURE_TOWER: rank = 30 elif structure_type == STRUCTURE_EXTENSION: rank = 20 elif structure_type != STRUCTURE_RAMPART: rank = 10 else: rank = 0 rank -= movement.chebyshev_distance_room_pos(self.pos, struct.pos) / 20 if structure_type != STRUCTURE_RAMPART: rampart = cast( StructureRampart, _.find(self.room.look_at(LOOK_STRUCTURES, struct.pos), {'structureType': STRUCTURE_RAMPART})) if rampart: rank -= 10 * rampart.hits / (DISMANTLE_POWER * MAX_CREEP_SIZE / 2 * CREEP_LIFE_TIME * 0.9) if rank > best_rank: best_target = struct best_rank = rank if best_target: self.memory.tloc = positions.serialize_pos_xy(best_target.pos) self.memory.tloctimeout = Game.time + 100 return best_target.pos else: if self.pos.isNearTo(target): flag = flags.look_for(self.room, target, SQUAD_DISMANTLE_RANGED) if flag: msg = "[dismantle squad][{}][{}] Dismantle job in {} completed at {}! Removing flag {} ({})." \ .format(self.home.name, self.name, self.pos.roomName, Game.time, flag, flag.pos) self.log(msg) Game.notify(msg) flag.remove() self.memory.tloc = positions.serialize_pos_xy(target) self.memory.tloctimeout = Game.time + 20 return target
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): if 'goading' not in self.memory: self.memory.goading = False if self.memory.goading and self.creep.hits < self.creep.hitsMax / 2: self.memory.goading = False self.targets.untarget_all(self) if not self.memory.goading and self.creep.hits >= self.creep.hitsMax: self.memory.goading = True self.targets.untarget_all(self) goad_target = self.targets.get_new_target(self, target_single_flag, TD_D_GOAD) if not goad_target: self.log("TowerDrainer has no target!") self.memory.last_role = self.memory.role self.memory.role = role_recycling return def set_max_avoid_regular_matrix(room_name, cost_matrix): # type: (str, PathFinder.CostMatrix) -> None if room_name == goad_target.pos.roomName: for x in range(0, 50): for y in range(0, 50): existing = cost_matrix.get(x, y) if existing == 0: terrain = Game.map.getTerrainAt(x, y, room_name) if terrain[0] == 'p': existing = 2 elif terrain[0] == 's': existing = 10 else: continue cost_matrix.set(x, y, existing + 20) if self.memory.goading: if self.pos.isEqualTo(goad_target): pass elif movement.chebyshev_distance_room_pos(self.pos, goad_target) < 50: self.move_to(goad_target, {'costCallback': set_max_avoid_regular_matrix}) else: self.follow_military_path( self.home.spawn.pos, goad_target, {'avoid_rooms': [goad_target.pos.roomName]}) else: heal_target = self.targets.get_new_target(self, target_single_flag2, TD_H_D_STOP) if not heal_target: if len(flags.find_flags(self.home, RAID_OVER)): self.recycle_me() else: self.go_to_depot() return if self.pos.isEqualTo(heal_target): pass elif movement.chebyshev_distance_room_pos(self.pos, heal_target) < 50: # TODO: make a military moveTo method like this self.move_to(heal_target, {'costCallback': set_max_avoid_regular_matrix}) else: self.follow_military_path( self.home.spawn.pos, heal_target, {'avoid_rooms': [goad_target.pos.roomName]}) autoactions.instinct_do_attack(self)
def run(self): if self.creep.ticksToLive < recycle_time and not self.home.under_siege( ): self.memory.role = role_recycling self.memory.last_role = role_spawn_fill return False if self.memory.filling and self.creep.carry[ RESOURCE_ENERGY] >= self.creep.carryCapacity: self.memory.filling = False if self.memory.role == role_spawn_fill or self.memory.role == role_tower_fill: self.targets.untarget_all(self) else: return True elif not self.memory.filling and ( self.creep.carry[RESOURCE_ENERGY] <= 0 or (self.creep.carry[RESOURCE_ENERGY] <= 20 and self.home.room.storage and movement.chebyshev_distance_room_pos( self.pos, self.home.room.storage.pos) < 5)): self.memory.filling = True del self.memory.running if self.memory.role == role_spawn_fill or self.memory.role == role_tower_fill: self.targets.untarget_all(self) else: return True if self.memory.filling: return self.harvest_energy() else: if 'running' in self.memory: if self.memory.running == role_upgrader: return upgrading.Upgrader.run(self) elif self.memory.running == role_builder: return building.Builder.run(self) elif self.memory.running == "refill": return self.refill_creeps() elif self.memory.running != role_spawn_fill and self.memory.running != "spawn_wait": self.log("WARNING: Unknown running value: {}", self.memory.running) del self.memory.running elif self.home.room.energyCapacityAvailable < 550 and self.home.room.energyAvailable < 300 \ and self.home.next_role is None: if self.creep.hasActiveBodyparts(WORK): self.memory.running = role_builder return building.Builder.run(self) else: self.memory.running = "refill" return self.refill_creeps() target = cast( Union[StructureExtension, Flag, None], self.targets.get_new_target(self, target_spawn_deposit)) if target: if cast(Flag, target).color: # it's a spawn fill wait flag assert isinstance(target, Flag) self.memory.running = "spawn_wait" rwc_cache = volatile_cache.mem("sfrwc") if not rwc_cache.has(self.pos.roomName): rwc_cache.set( self.pos.roomName, not not _.find( self.room.find(FIND_MY_STRUCTURES), lambda s: (s.structureType == STRUCTURE_EXTENSION or s. structureType == STRUCTURE_SPAWN) and s.energy < s.energyCapacity)) if rwc_cache.get(self.pos.roomName): self.targets.untarget(self, target_spawn_deposit) return True if self.creep.carry[ RESOURCE_ENERGY] < self.creep.carryCapacity: self.memory.filling = True return True if not self.home.full_storage_use: self.memory.running = "refill" return self.refill_creeps() if not self.pos.isEqualTo(target): self.move_to(target) return False else: assert isinstance(target, StructureExtension) if self.memory.running == "spawn_wait": del self.memory.running if target.energy >= target.energyCapacity: self.targets.untarget(self, target_spawn_deposit) return True else: if not self.pos.isNearTo(target): self.move_to(target) return False del self.memory.nbm result = self.creep.transfer(target, RESOURCE_ENERGY) if result == OK: if self.creep.carry[ RESOURCE_ENERGY] > target.energyCapacity - target.energy: volatile_cache.mem("extensions_filled").set( target.id, True) if self.creep.carry[ RESOURCE_ENERGY] + target.energy - target.energyCapacity > 0: self.targets.untarget( self, target_spawn_deposit) new_target = self.targets.get_new_target( self, target_spawn_deposit) if new_target and not self.pos.isNearTo( new_target): self.move_to(new_target) else: self.harvest_energy( ) # Get a head start on this too! elif result == ERR_FULL: self.targets.untarget(self, target_spawn_deposit) return True else: self.log( "Unknown result from spawn_fill-creep.transfer({}): {}", target, result) self.targets.untarget(self, target_spawn_deposit) return True return False if self.home.full_storage_use and self.memory.role == role_spawn_fill_backup \ and self.home.carry_mass_of(role_tower_fill) + self.home.carry_mass_of(role_spawn_fill) \ >= self.home.get_target_total_spawn_fill_mass(): self.memory.role = role_builder return building.Builder.run(self) elif self.memory.role == role_spawn_fill_backup: if _.find(self.room.building.get_construction_targets(), lambda s: s.structureType == STRUCTURE_EXTENSION ) or self.home.upgrading_deprioritized(): self.memory.running = role_builder return building.Builder.run(self) else: self.memory.running = role_upgrader return upgrading.Upgrader.run(self) elif not self.home.full_storage_use or self.home.room.storage.storeCapacity <= 0: self.memory.running = "refill" return self.refill_creeps() elif self.creep.carry[RESOURCE_ENERGY] < self.creep.carryCapacity: self.memory.filling = True return self.harvest_energy() return False
def follow_energy_path(self, origin, target, mine=None): # type: (Union[RoomObject, RoomPosition], Union[RoomObject, RoomPosition], Any) -> None origin = robjs.pos(origin) target = robjs.pos(target) if self.creep.fatigue > 0: return if origin.isNearTo(target): if self.pos.roomName == target.roomName: self.move_to(target) return else: origin = self.home.spawn.pos if mine: opts = { 'current_room': self.pos.roomName, 'paved_for': mine, } elif self.carry_sum() == 0: opts = {'current_room': self.pos.roomName, 'use_roads': False} else: opts = {'current_room': self.pos.roomName} path = self.hive.honey.find_serialized_path(origin, target, 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 or result == ERR_NO_PATH: if self.pos.isNearTo(target): self.basic_move_to(target) return if not self.memory.next_ppos or self.memory.off_path_for > 10 or movement.chebyshev_distance_room_pos( self.pos, self.memory.next_ppos) > CREEP_LIFE_TIME: self.memory.off_path_for = 0 # Recalculate next_ppos if we're off path for a long time all_positions = self.hive.honey.list_of_room_positions_in_path( origin, target, opts) closest = None closest_distance = Infinity for index, pos in enumerate(all_positions): if movement.chebyshev_distance_room_pos(pos, origin) < 3 \ or movement.chebyshev_distance_room_pos(pos, target) < 3: room = self.hive.get_room(pos.roomName) if room and not movement.is_block_clear( room, pos.x, pos.y): continue # Don't try and target where the miner is right now! # subtract how far we are on the path! # NOTE: 0.7 is used in building._repath_roads_for and should be changed there if changed here. distance = movement.chebyshev_distance_room_pos( self.pos, pos) - index * 0.7 if pos.roomName != self.pos.roomName or pos.x < 2 or pos.x > 48 or pos.y < 2 or pos.y > 48: distance += 10 if distance < closest_distance: closest_distance = distance closest = pos if not closest or closest_distance >= CREEP_LIFE_TIME: 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: Transport creep off path, with no positions to return to. I'm at {}, going" " from {} to {}. All positions: {}!".format( self.pos, origin, target, all_positions)) if mine and self.home.mining.is_mine_linked(mine): self.log( "I'm a hauler for a linked mine! Suiciding.") self.memory.role = role_recycling if not len(all_positions): if Game.time % 20 == 10: honey.clear_cached_path(origin, target) return self.memory.next_ppos = closest mtarget = self.memory.next_ppos new_target = __new__( RoomPosition(mtarget.x, mtarget.y, mtarget.roomName)) if self.pos.isEqualTo(new_target): del self.memory.next_ppos if not self.memory.tried_new_next_ppos: self.memory.tried_new_next_ppos = True else: del self.memory.tried_new_next_ppos # the path is incorrect! self.log( "WARNING: Path from {} to {} found to be cached incorrectly - it should contain {}, but" " it doesn't.".format(origin, target, new_target)) self.log( "Path (tbd) retrieved from HoneyTrails with options ({}):\n{}" .format(opts, JSON.stringify(path, 0, 4))) honey.clear_cached_path(origin, target, opts) elif self.pos.isNearTo(new_target): if movement.is_block_clear(self.room, new_target.x, new_target.y): self.basic_move_to(new_target) else: del self.memory.next_ppos del self.memory.tried_new_next_ppos return else: del self.memory.tried_new_next_ppos self.move_to(new_target) if not self.memory.off_path_for: self.memory.off_path_for = 1 else: self.memory.off_path_for += 1 elif result != OK: self.log( "Unknown result from follow_energy_path: {}. Going from {} to {} (path {}, in {})" .format(result, origin, target, path, self.pos.roomName)) else: del self.memory.tried_new_next_ppos if self.memory.off_path_for: self.memory.on_path_for = 1 del self.memory.off_path_for elif self.memory.on_path_for: self.memory.on_path_for += 1 if self.memory.on_path_for >= 2: del self.memory.next_ppos del self.memory.on_path_for serialized_pos = self.pos.x | (self.pos.y << 6) if self.memory.last_pos == serialized_pos: if 'standstill_for' in self.memory: self.memory.standstill_for += 1 else: self.memory.standstill_for = 1 if self.memory.standstill_for % 10 == 5 and \ (not self.memory.filling or not _.find(self.room.find_in_range(FIND_MY_CREEPS, 1, self.pos), lambda c: c.memory.role != role_hauler and c.memory.role != role_miner)): del self.memory.next_ppos found_mine = False for pos in self.hive.honey.find_path(origin, target, opts): if pos.x == self.pos.x and pos.y == self.pos.y: found_mine = True elif found_mine: if movement.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 elif not self.creep.fatigue: self.memory.last_pos = serialized_pos del self.memory.standstill_for
def run_squad(self, members, target): # type: (List[SquadDrone], Location) -> None if movement.chebyshev_distance_room_pos(self.pos, target) > 150: return opts = get_opts(self.pos.roomName) self.log("running with opts {}", JSON.stringify(opts)) owner = stored_data._find_room_owner(self.room.room) if (owner and (Memory.meta.friends.includes(owner.name.lower()) or owner.name == self.creep.owner.username)): return next_pos = None path = _.get(self.memory, ['_move', 'path']) if path: next_pos = self.creep.findNextPathPos(path) if not _.isObject(next_pos) or not self.pos.isNearTo(next_pos): next_pos = None if next_pos is None and self.creep.__direction_moved: next_pos = movement.apply_direction(self.pos, self.creep.__direction_moved) if next_pos is not None: best_structure = cast( Structure, _.find(self.room.look_at(LOOK_STRUCTURES, next_pos), get_dismantle_condition_not_a_road(opts))) if best_structure: result = self.creep.dismantle(best_structure) if result != OK: self.log("Unknown result from {}.dismantle({}): {}", self.creep, best_structure, result) if result != ERR_NOT_IN_RANGE: return elif next_pos == ERR_NOT_FOUND: del self.memory['_move'] structures_around = cast( List[Dict[str, Structure]], self.room.look_for_in_area_around(LOOK_STRUCTURES, self.pos, 1)) best_structure = None our_dismantle_power = DISMANTLE_POWER * self.creep.getActiveBodypartsBoostEquivalent( WORK, 'dismantle') if len(structures_around) > 1: ramparts_at = None for structure_obj in structures_around: if structure_obj[ LOOK_STRUCTURES].structureType == STRUCTURE_RAMPART: if ramparts_at is None: ramparts_at = {} ramparts_at[positions.serialize_pos_xy(structure_obj[LOOK_STRUCTURES].pos)] \ = structure_obj[LOOK_STRUCTURES].hits best_rank = -Infinity for structure_obj in cast( List[Dict[str, Structure]], self.room.look_for_in_area_around(LOOK_STRUCTURES, self.pos, 1)): structure = structure_obj[LOOK_STRUCTURES] if not can_target_struct(structure, opts): continue structure_type = structure.structureType if structure_type == STRUCTURE_TOWER: rank = 55 elif structure_type == STRUCTURE_SPAWN: rank = 50 elif structure_type == STRUCTURE_LAB: rank = 45 elif structure_type == STRUCTURE_EXTENSION: rank = 40 elif structure_type == STRUCTURE_LINK: rank = 30 else: rank = 10 hits = structure.hits if structure_type != STRUCTURE_RAMPART and ramparts_at: rampart = ramparts_at[positions.serialize_pos_xy( structure.pos)] if rampart and rampart.hits: hits += rampart.hits if hits < our_dismantle_power: rank -= hits / our_dismantle_power if rank > best_rank: best_rank = rank best_structure = structure elif len(structures_around): best_structure = structures_around[0][LOOK_STRUCTURES] if not can_target_struct(best_structure, opts): return else: return if best_structure: result = self.creep.dismantle(best_structure) volatile_cache.mem('dismantle_squad_dismantling').set( target.name, best_structure) if result == OK: if best_structure.hits < our_dismantle_power \ or best_structure.hits < our_dismantle_power + _.sum( members, lambda x: x.creep.getActiveBodypartsBoostEquivalent(RANGED_ATTACK, 'rangedAttack') * RANGED_ATTACK_POWER): del self.memory._move else: self.log("Unknown result from {}.dismantle({}): {}".format( self.creep, best_structure, result))