Exemple #1
0
    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
Exemple #2
0
    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}
Exemple #3
0
def get_team(channel : discord.TextChannel) -> Optional[str]:
    """
    Gets the name of the category channel of the channel the message was sent in.
    """
    category_channel = bot.get_channel(channel.category_id)
    if category_channel:
        team = category_channel.name.lower()
        if team in get_subs():
            return team
    return None
Exemple #4
0
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_subs, get_sub
    from ALTANTIS.npcs.npc import get_npcs, get_npc
    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)
        damage = power - sub_dist

        if damage > 0:
            await sub.send_message(f"Explosion in {pos}!", "captain")
            sub.damage(damage)

    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)
        damage = power - npc_dist

        if damage > 0:
            await npc_obj.send_message(f"Explosion in {pos}!", "captain")
            npc_obj.damage(damage)
Exemple #5
0
async def perform_timestep(counter: int):
    """
    Does all time-related stuff, including movement, power changes and so on.
    Called at a time interval, when allowed.
    """
    global NO_SAVE
    NO_SAVE = True

    print(f"Running turn {counter}.")

    def is_active_sub(subname):
        sub = get_sub(subname)
        if not sub: return False
        return sub.power.activated()

    # Get all active subs. (Can you tell I'm a functional programmer?)
    # Note: we still collect all messages for all subs, as there are some
    # messages that inactive subs should receive.
    subsubset: List[str] = list(filter(is_active_sub, get_subs()))
    submessages: Dict[str, Dict[str, str]] = {
        i: {
            "engineer": "",
            "captain": "",
            "scientist": ""
        }
        for i in get_subs()
    }
    message_opening: str = f"---------**TURN {counter}**----------\n"

    # Emergency messaging
    for subname in subsubset:
        sub = get_sub(subname)
        if sub.power.total_power == 1:
            emergency_message = f"EMERGENCY!!! {random.choice(emergencies)}\n"
            submessages[subname]["captain"] += emergency_message
            submessages[subname]["scientist"] += emergency_message
            submessages[subname]["engineer"] += emergency_message

    # Power management
    for subname in subsubset:
        sub = get_sub(subname)
        power_message = sub.power.apply_power_schedule()
        if power_message:
            power_message = f"{power_message}\n"
            submessages[subname]["captain"] += power_message
            submessages[subname]["engineer"] += power_message

    # Weapons
    for subname in subsubset:
        sub = get_sub(subname)
        weapons_message = sub.weapons.weaponry_tick()
        if weapons_message:
            weapons_message = f"{weapons_message}\n"
            submessages[subname]["captain"] += weapons_message

    # NPCs
    await npc_tick()
    # Map
    map_tick()

    # The crane
    for subname in subsubset:
        sub = get_sub(subname)
        crane_message = await sub.inventory.crane_tick()
        if crane_message:
            crane_message = f"{crane_message}\n"
            submessages[subname]["scientist"] += crane_message

    # Movement, trade and puzzles
    for subname in subsubset:
        sub = get_sub(subname)
        move_message, trade_messages = await sub.movement.movement_tick()
        if move_message:
            move_message = f"{move_message}\n"
            submessages[subname]["captain"] += move_message
        for target in trade_messages:
            submessages[target]["captain"] += trade_messages[target] + "\n"

    # Scanning (as we enter a new square only)
    for subname in subsubset:
        sub = get_sub(subname)
        scan_message = sub.scan.scan_string()
        if scan_message != "":
            submessages[subname]["captain"] += scan_message
            submessages[subname]["scientist"] += scan_message

    # Postponed events
    for subname in subsubset:
        sub = get_sub(subname)
        await sub.upgrades.postponed_tick()

    # Damage
    for subname in get_subs():
        sub = get_sub(subname)
        damage_message = await sub.power.damage_tick()
        if damage_message:
            damage_message = f"{damage_message}\n"
            submessages[subname]["captain"] += damage_message
            submessages[subname]["engineer"] += damage_message
            submessages[subname]["scientist"] += damage_message

    for subname in get_subs():
        messages = submessages[subname]
        sub = get_sub(subname)
        if messages["captain"] == "":
            if subname not in subsubset:
                messages[
                    "captain"] = "Your submarine is deactivated so nothing happened.\n"
            else:
                messages[
                    "captain"] = "Your submarine is active, but there is nothing to notify you about.\n"
        await sub.send_message(f"{message_opening}{messages['captain'][:-1]}",
                               "captain")
        if messages["engineer"] != "":
            await sub.send_message(
                f"{message_opening}{messages['engineer'][:-1]}", "engineer")
        if messages["scientist"] != "":
            await sub.send_message(
                f"{message_opening}{messages['scientist'][:-1]}", "scientist")

    NO_SAVE = False
    save_game()
Exemple #6
0
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