def hits(self, x: int, y: int) -> Dict[str, List[Entity]]: # Returns a list of indirect and direct hits. indirect = [] direct = [] for subname in get_subs(): sub = get_sub(subname) pos = sub.movement.get_position() distance = diagonal_distance(pos, (x, y)) if distance == 0: direct.append(sub) elif distance == 1: indirect.append(sub) for npcid in get_npcs(): npc = get_npc(npcid) pos = npc.get_position() distance = diagonal_distance(pos, (x, y)) if distance == 0: direct.append(npc) elif distance == 1: indirect.append(npc) shuffle(indirect) shuffle(direct) return {"indirect": indirect, "direct": direct}
async def broadcast(self, content: str): if self.last_comms + COMMS_COOLDOWN > now(): return False my_pos = self.sub.movement.get_position() for subname in get_subs(): if subname == self.sub._name: continue sub = get_sub(subname) dist = diagonal_distance(my_pos, sub.movement.get_position()) garbled = self.garble(content, dist) if garbled is not None: await sub.send_message( f"**Message received from {self.sub.name()}**:\n`{garbled}`\n**END MESSAGE**", "captain") for npcid in get_npcs(): npc = get_npc(npcid) dist = diagonal_distance(my_pos, npc.get_position()) garbled = self.garble(content, dist) if garbled is not None: await npc.send_message( f"**Message received from {self.sub.name()}**:\n`{garbled}`\n**END MESSAGE**", "") self.last_comms = now() return True
async def explode(pos: Tuple[int, int], power: int, sub_exclusions: List[str] = [], npc_exclusions: List[int] = []): """ Makes an explosion in pos, dealing power damage to the centre square, power-1 to the surrounding ones, power-2 to those that surround and so on. """ from ALTANTIS.subs.state import get_sub_objects from ALTANTIS.npcs.npc import get_npc_objects for sub in get_sub_objects(): if sub._name in sub_exclusions: continue sub_pos = sub.movement.get_position() sub_dist = diagonal_distance(pos, sub_pos) damage = power - sub_dist if damage > 0: await sub.send_message(f"Explosion in {pos}!", "captain") sub.damage(damage) for npc in get_npc_objects(): if npc.id in npc_exclusions: continue npc_pos = npc.get_position() npc_dist = diagonal_distance(pos, npc_pos) damage = power - npc_dist if damage > 0: await npc.send_message(f"Explosion in {pos}!", "captain") npc.damage(damage)
def move_towards_sub(self, dist: int) -> bool: """ Looks for the closest sub in range, and moves towards it. """ nearby_entities: List[Entity] = all_in_submap(self.get_position(), dist) closest: Tuple[Optional[Submarine], int] = (None, 0) for entity in nearby_entities: if isinstance(entity, Submarine): sub: Submarine = entity this_dist = diagonal_distance(self.get_position(), sub.get_position()) if (closest[0] is None) or this_dist < closest[1]: closest = (entity, this_dist) if closest[0] is not None: direction = determine_direction(self.get_position(), closest[0].get_position()) if direction is not None: rotated = rotate_direction(direction) directions = [direction] if rotated is not None: directions.append(rotated[0]) directions.append(rotated[1]) for possible_direction in directions: if self.move(*go_in_direction(possible_direction)): return True return False
def all_in_submap(pos: Tuple[int, int], dist: int, sub_exclusions: List[str] = [], npc_exclusions: List[int] = []) -> List[Entity]: from ALTANTIS.subs.state import filtered_teams, get_sub from ALTANTIS.npcs.npc import filtered_npcs, get_npc """ Gets all entities some distance from the chosen square. Ignores any entities in exclusions. """ result: List[Entity] = [] subs_in_range = filtered_teams( lambda sub: diagonal_distance(sub.movement.get_position( ), pos) <= dist and sub._name not in sub_exclusions) for sub in map(get_sub, subs_in_range): if sub: result.append(sub) npcs_in_range = filtered_npcs(lambda npc: diagonal_distance( npc.get_position(), pos) <= dist and npc.id not in npc_exclusions) for npc in map(get_npc, npcs_in_range): if npc: result.append(npc) return result
def prepare_shot(self, damaging: bool, x: int, y: int) -> str: if not in_world(x, y): return "Coordinate outside of world." if diagonal_distance(self.sub.movement.get_position(), (x, y)) > self.range: return "Coordinate outside of range." if damaging and self.weapons_charge >= 2: self.planned_shots.append((True, x, y)) self.weapons_charge -= 2 return f"Damaging shot fired at ({x}, {y})!" if (not damaging) and self.weapons_charge >= 1: self.planned_shots.append((False, x, y)) self.weapons_charge -= 1 return f"Non-damaging shot fired at ({x}, {y})!" return "Not enough charge to use that."
async def broadcast(self, content : str) -> str: if self.last_comms + COMMS_COOLDOWN > now(): return f"The comms system is still cooling down! (Requires {int(self.last_comms + COMMS_COOLDOWN - now())}s more.)" if self.sub.power.get_power("comms") == 0: return "Cannot use comms system that isn't powered!" my_pos = self.sub.movement.get_position() for sub in get_sub_objects(): if sub._name == self.sub._name: continue dist = diagonal_distance(my_pos, sub.movement.get_position()) garbled = self.garble(content, dist) if garbled is not None: await sub.send_message(f"**Message received from {self.sub.name()}**:\n`{garbled}`\n**END MESSAGE**", "captain") for npc in get_npc_objects(): dist = diagonal_distance(my_pos, npc.get_position()) garbled = self.garble(content, dist) if garbled is not None: await npc.send_message(f"**Message received from {self.sub.name()}**:\n`{garbled}`\n**END MESSAGE**", "") self.last_comms = now() return "Transmitted message."
def explore_submap(pos: Tuple[int, int], dist: int, sub_exclusions: Collection[str] = (), npc_exclusions: Collection[int] = (), with_distance: bool = False) -> List[str]: """ Explores the area centered around pos = (cx, cy) spanning distance dist. Returns all outward_broadcast events (as a list) formatted for output. Ignores any NPCs or subs with a name included in exclusions. """ events = [] (cx, cy) = pos # First, map squares. for i in range(-dist, dist + 1): x = cx + i if x < 0 or x >= X_LIMIT: continue for j in range(-dist, dist + 1): y = cy + j if y < 0 or y >= Y_LIMIT: continue this_dist = diagonal_distance((0, 0), (i, j)) event = get_square(x, y).outward_broadcast(dist - this_dist) if event != "": direction = determine_direction((cx, cy), (x, y)) if direction is None: event = f"{event} - in your current square!" else: distance_measure = "" if with_distance: distance_measure = f" at a distance of {this_dist} away" event = f"{event} - in direction {direction.upper()}{distance_measure}!" events.append(event) # Then, submarines. for subname in get_subs(): if subname in sub_exclusions: continue sub = get_sub(subname) sub_pos = sub.movement.get_position() sub_dist = diagonal_distance(pos, sub_pos) # If out of range, drop it. if sub_dist > dist: continue event = sub.scan.outward_broadcast(dist - sub_dist) direction = determine_direction(pos, sub_pos) if direction is None: event = f"{event} in your current square!" else: event = f"{event} in direction {direction.upper()}!" events.append(event) # Finally, NPCs. for npcid in get_npcs(): if npcid in npc_exclusions: continue npc_obj = get_npc(npcid) npc_pos = npc_obj.get_position() npc_dist = diagonal_distance(pos, npc_pos) if npc_dist > dist: continue event = npc_obj.outward_broadcast(dist - npc_dist) direction = determine_direction(pos, npc_pos) if direction is None: event = f"{event} in your current square!" else: event = f"{event} in direction {direction.upper()}!" events.append(event) return events