예제 #1
0
def ooc_cmd_bg(client, arg):
    """
    Set the background of an area.
    Usage: /bg <background>
    """
    if len(arg) == 0:
        pos_lock = ''
        if len(client.area.pos_lock) > 0:
            pos = ' '.join(str(l) for l in client.area.pos_lock)
            pos_lock = f'\nAvailable positions: {pos}.'
        client.send_ooc(f'Current background is {client.area.background}.{pos_lock}')
        return
    if not client in client.area.owners and not client.is_mod and client.area.bg_lock:
        raise AreaError("This area's background is locked!")
    if client.area.cannot_ic_interact(client):
        raise AreaError("You are not on the area's invite list!")
    if not client.is_mod and not (client in client.area.owners) and client.char_id == -1:
        raise ClientError("You may not do that while spectating!")
    try:
        client.area.change_background(arg)
    except AreaError:
        raise
    client.area.broadcast_ooc(
        f'{client.showname} changed the background to {arg}.')
    database.log_area('bg', client, client.area, message=arg)
예제 #2
0
        def change_hp(self, side: int, health: int):
            """
            Change a penalty healthbar.

            Parameters
            ----------
            side: int
                Penalty bar to change (1 for def, 2 for pro).
            health: int
                New health value of the penalty bar.

            Raises
            ------
            AreaError
                If an invalid penalty bar or health value was given.

            """

            if not 1 <= side <= 2:
                raise AreaError('Invalid penalty side.')
            if not 0 <= health <= 10:
                raise AreaError('Invalid penalty value.')

            if side == 1:
                self.hp_def = health
            elif side == 2:
                self.hp_pro = health

            for client in self.clients:
                client.send_health(side=side, health=health)
예제 #3
0
def ooc_cmd_hub(client, arg):
    """
    List hubs, or go to another hub.
    Usage: /hub [id/name]
    """
    if arg == '':
        client.send_hub_list()
        return

    try:
        for hub in client.server.hub_manager.hubs:
            if hub.name.lower() == arg.lower() or hub.abbreviation == arg or (arg.isdigit() and hub.id == int(arg)):
                if hub == client.area.area_manager:
                    raise AreaError('User already in specified hub.')
                preflist = client.server.supported_features.copy()
                if not hub.arup_enabled:
                    preflist.remove('arup')
                client.send_command('FL', *preflist)
                client.change_area(hub.default_area())
                client.area.area_manager.send_arup_status([client])
                client.area.area_manager.send_arup_cms([client])
                client.area.area_manager.send_arup_lock([client])
                client.send_hub_info()
                return
        raise AreaError('Targeted hub not found!')
    except ValueError:
        raise ArgumentError('Hub ID must be a name, abbreviation or a number.')
    except (AreaError, ClientError):
        raise
예제 #4
0
def ooc_cmd_bg(client, arg):
    """
    Set the background of an area.
    Usage: /bg <background>
    """
    if len(arg) == 0:
        pos_lock = ""
        if len(client.area.pos_lock) > 0:
            pos = ", ".join(str(lpos) for lpos in client.area.pos_lock)
            pos_lock = f"\nAvailable positions: {pos}."
        client.send_ooc(
            f"Current background is {client.area.background}.{pos_lock}")
        return
    if client not in client.area.owners and not client.is_mod and client.area.bg_lock:
        raise AreaError("This area's background is locked!")
    if client.area.cannot_ic_interact(client):
        raise AreaError("You are not on the area's invite list!")
    if (not client.is_mod and not (client in client.area.owners)
            and client.char_id == -1):
        raise ClientError("You may not do that while spectating!")
    if client.area.dark and not client.is_mod and not (client
                                                       in client.area.owners):
        raise ClientError("You must be authorized to do that.")
    try:
        client.area.change_background(arg)
    except AreaError:
        raise
    client.area.broadcast_ooc(
        f"{client.showname} changed the background to {arg}.")
    database.log_area("bg", client, client.area, message=arg)
예제 #5
0
        def change_hp(self, side, val):
            """
            Change a penalty healthbar.

            Parameters
            ----------
            side: int
                Penalty bar to change (1 for def, 2 for pro).
            val: int
                New health value of the penalty bar.

            Raises
            ------
            AreaError
                If an invalid penalty bar or health value was given.
            """
            if not 0 <= val <= 10:
                raise AreaError('Invalid penalty value.')
            if not 1 <= side <= 2:
                raise AreaError('Invalid penalty side.')

            if side == 1:
                self.hp_def = val
            elif side == 2:
                self.hp_pro = val

            self.send_command('HP', side, val)
예제 #6
0
    def remove_area(self, area):
        """
        Remove an area instance.
        :param area: target area instance.
        
        """
        if not (area in self.areas):
            raise AreaError('Area not found.')
        # Make a copy because it can change size during iteration
        # (causes runtime error otherwise)
        if self.default_area() != area:
            target_area = self.default_area()
        else:
            try:
                target_area = self.get_area_by_id(1)
            except:
                raise AreaError('May not remove last existing area!')
        clients = area.clients.copy()
        for client in clients:
            client.set_area(target_area)

        # Update area links
        for ar in self.areas:
            for link in ar.links.copy():
                # Shift it down as one area was removed
                if int(link) > area.id:
                    ar.links[str(int(link)-1)] = ar.links.pop(link)
                elif link == str(area.id):
                    del ar.links[link]
        self.areas.remove(area)
예제 #7
0
def ooc_cmd_status(client, arg):
    """
    Show or modify the current status of an area.
    Usage: /status <idle|rp|casing|looking-for-players|lfp|recess|gaming>
    """
    if not client.area.area_manager.arup_enabled:
        raise AreaError("This hub does not use the /status system.")
    if len(arg) == 0:
        client.send_ooc(f"Current status: {client.area.status}")
    else:
        if (not client.area.can_change_status and not client.is_mod
                and client not in client.area.owners):
            raise AreaError(
                "This area's status cannot be changed by anyone who's not a CM or mod!"
            )
        if client.area.cannot_ic_interact(client):
            raise AreaError("You are not on the area's invite list!")
        if (not client.is_mod and client not in client.area.owners
                and client.char_id == -1):
            raise ClientError("You may not do that while spectating!")
        try:
            client.area.change_status(arg)
            client.area.broadcast_ooc("{} changed status to {}.".format(
                client.showname, client.area.status))
            database.log_area("status", client, client.area, message=arg)
        except AreaError:
            raise
예제 #8
0
    def load_character_data(self, path="config/character_data.yaml"):
        """
        Load all the character-specific information such as movement delay, keys, etc.
        :param path: filepath to the YAML file.

        """
        try:
            if not os.path.isfile(path):
                raise
            with open(path, "r") as chars:
                data = yaml.safe_load(chars)
        except Exception:
            raise AreaError(
                f"Hub {self.name} trying to load character data: File path {path} is invalid!"
            )

        try:
            for char in data.copy():
                # Convert the old numeric way to store character data into character folder based one
                if isinstance(char, int) and self.is_valid_char_id(char):
                    data[self.char_list[char]] = data.pop(char)
            self.character_data = data
        except Exception:
            raise AreaError(
                "Something went wrong while loading the character data!")
예제 #9
0
 def change_hp(self, side, val):
     if not 0 <= val <= 10:
         raise AreaError('Invalid penalty value.')
     if not 1 <= side <= 2:
         raise AreaError('Invalid penalty side.')
     if side == 1:
         self.hp_def = val
     elif side == 2:
         self.hp_pro = val
     self.send_command('HP', side, val)
예제 #10
0
def ooc_cmd_save_hub(client, arg):
    """
    Save the current Hub in the server's storage/hubs/<name>.yaml file.
    If blank and you're a mod, it will save to server's config/areas_new.yaml for the server owner to approve.
    Usage: /save_hub <name>
    """
    if not client.is_mod:
        if arg == "":
            raise ArgumentError(
                "You must be authorized to save the default hub!")
        if len(arg) < 3:
            raise ArgumentError("Filename must be at least 3 symbols long!")
    try:
        if arg != "":
            path = "storage/hubs"
            num_files = len(
                [f for f in os.listdir(path) if os.path.isfile(
                    os.path.join(path, f))]
            )
            if num_files >= 1000:  # yikes
                raise AreaError(
                    "Server storage full! Please contact the server host to resolve this issue."
                )
            try:
                arg = f"{path}/{arg}.yaml"
                if os.path.isfile(arg):
                    with open(arg, "r", encoding="utf-8") as stream:
                        hub = yaml.safe_load(stream)
                    if "read_only" in hub and hub["read_only"] is True:
                        raise ArgumentError(
                            f"Hub {arg} already exists and it is read-only!"
                        )
                with open(arg, "w", encoding="utf-8") as stream:
                    yaml.dump(
                        client.area.area_manager.save(
                            ignore=["can_gm", "max_areas"]),
                        stream,
                        default_flow_style=False,
                    )
            except ArgumentError:
                raise
            except Exception:
                raise AreaError(f"File path {arg} is invalid!")
            client.send_ooc(f"Saving as {arg}...")
        else:
            client.server.hub_manager.save("config/areas_new.yaml")
            client.send_ooc(
                "Saving all Hubs to areas_new.yaml. Contact the server owner to apply the changes."
            )
    except AreaError:
        raise
예제 #11
0
 def change_hp(self, side, val):
     """
     Set the penalty bars.
     :param side: 1 for defense; 2 for prosecution
     :param val: value from 0 to 10
     """
     if not 0 <= val <= 10:
         raise AreaError('Invalid penalty value.')
     if not 1 <= side <= 2:
         raise AreaError('Invalid penalty side.')
     if side == 1:
         self.hp_def = val
     elif side == 2:
         self.hp_pro = val
     self.send_command('HP', side, val)
예제 #12
0
        def change_background(self, bg, validate=True, override_blind=False):
            """
            Change the background of the current area.

            Parameters
            ----------
            bg: str
                New background name.
            validate: bool, optional
                Whether to first determine if background name is listed as a server background
                before changing. Defaults to True.
            override_blind: bool, optional
                Whether to send the intended background to blind people as opposed to the server
                blackout one. Defaults to False (send blackout).

            Raises
            ------
            AreaError
                If the server attempted to validate the background name and failed.
            """

            if validate and bg.lower() not in [
                    name.lower() for name in self.server.backgrounds
            ]:
                raise AreaError('Invalid background name.')

            self.background = bg
            for c in self.clients:
                if c.is_blind and not override_blind:
                    c.send_command('BN',
                                   self.server.config['blackout_background'])
                else:
                    c.send_command('BN', bg)
예제 #13
0
 def get_rand_avail_char_id(self, allow_restricted=False):
     avail_set = set(range(len(
         self.server.char_list))) - self.get_chars_unusable(
             allow_restricted=allow_restricted)
     if len(avail_set) == 0:
         raise AreaError('No available characters.')
     return random.choice(tuple(avail_set))
예제 #14
0
def ooc_cmd_evidence_remove(client, arg):
    """
    Remove a piece of evidence.
    Usage: /evidence_remove <evi_name/id>
    """
    if arg == "":
        raise ArgumentError(
            "Use /evidence_remove <evi_name/id> to remove that piece of evidence."
        )
    try:
        evi_list = client.area.get_evidence_list(client)
        evidence = None
        for i, evi in enumerate(evi_list):
            if (arg.isnumeric()
                    and int(arg) - 1 == i) or arg.lower() == evi[0].lower():
                evidence = evi
                break
        if evidence is None:
            raise AreaError(
                f"Target evidence not found! (/evidence_remove {arg})")
        evi_name = evidence[0]
        client.area.evi_list.del_evidence(client, i)
        database.log_area("evidence.del", client, client.area)
        client.area.broadcast_evidence_list()
        client.send_ooc(f"You have removed evidence '{evi_name}'.")
    except ValueError:
        raise
    except (AreaError, ClientError):
        raise
예제 #15
0
    def load_music(self, path):
        try:
            if not os.path.isfile(path):
                raise AreaError(
                    f"Hub {self.name} trying to load music list: File path {path} is invalid!"
                )
            with open(path, "r", encoding="utf-8") as stream:
                music_list = yaml.safe_load(stream)

            prepath = ""
            for item in music_list:
                # deprecated, use 'replace_music' hub pref instead
                # if 'replace' in item:
                #    self.replace_music = item['replace'] is True
                if "use_unique_folder" in item and item[
                        "use_unique_folder"] is True:
                    prepath = os.path.splitext(os.path.basename(path))[0] + "/"

                if "category" not in item:
                    continue

                if "songs" in item:
                    for song in item["songs"]:
                        song["name"] = prepath + song["name"]
            self.music_list = music_list
        except ValueError:
            raise
        except AreaError:
            raise
예제 #16
0
 def change_status(self, value):
     allowed_values = ('idle', 'building-open', 'building-full',
                       'casing-open', 'casing-full', 'recess')
     if value.lower() not in allowed_values:
         raise AreaError('Invalid status. Possible values: {}'.format(
             ', '.join(allowed_values)))
     self.status = value.upper()
예제 #17
0
def ooc_cmd_area(client, arg):
    """
    List areas, or go to another area.
    Usage: /area [id] or /area [name]
    """
    if arg == "":
        client.send_area_list(
            full=client.is_mod or client in client.area.owners)
        return

    try:
        for area in client.area.area_manager.areas:
            a = arg.split(" ")[0]
            aid = a.strip("[]")
            if ((a.startswith("[") and a.endswith("]") and aid.isdigit()
                 and area.id == int(aid)) or area.name.lower() == arg.lower()
                    or area.abbreviation == arg
                    or (arg.isdigit() and area.id == int(arg))):
                client.change_area(area)
                return
        raise AreaError("Targeted area not found!")
    except ValueError:
        raise ArgumentError(
            "Area ID must be a name, abbreviation or a number.")
    except (AreaError, ClientError):
        raise
예제 #18
0
def ooc_cmd_evidence_present(client, arg):
    """
    Present a piece of evidence on your next IC message.
    Don't include [id] or make it 0 to stop presenting evidence.
    Usage: /evidence_present [id]
    """
    if arg == "" or arg == "0":
        client.send_ooc("No longer presenting evidence.")
        client.presenting = 0
        return

    try:
        evidence = None
        evi_list = client.area.get_evidence_list(client)
        # Check if evidence we're looking for exists
        for i, evi in enumerate(evi_list):
            print(arg.lower(), evi[0].lower())
            if (arg.isnumeric()
                    and int(arg) - 1 == i) or arg.lower() == evi[0].lower():
                evidence = evi
                break
        if evidence is None:
            raise AreaError(
                f"Target evidence not found! (/evidence_present {arg})")
        client.presenting = i + 1
        client.send_ooc(
            f"Will now present evidence [{client.presenting}] {evidence[0]} on next IC message."
        )
    except ValueError:
        raise
    except (AreaError, ClientError):
        raise
예제 #19
0
 def get_rand_avail_char_id(self):
     """Get a random available character ID."""
     avail_set = set(range(len(
         self.server.char_list))) - {x.char_id
                                     for x in self.clients}
     if len(avail_set) == 0:
         raise AreaError('No available characters.')
     return random.choice(tuple(avail_set))
예제 #20
0
 def create_area(self):
     """Create a new area instance and return it."""
     idx = len(self.areas)
     if self.max_areas != -1 and idx >= self.max_areas:
         raise AreaError(f'Area limit reached! ({self.max_areas})')
     area = Area(self, f'Area {idx}')
     self.areas.append(area)
     return area
예제 #21
0
 def change_hp(self, side: int, val: int):
     """Set the penalty bars.
     Args:
         side (int): 1 for defense; 2 for prosecution
         val (int): value from 0 to 10
     Raises:
         AreaError: If side is not between 1-2 inclusive or val is not between 0-10
     """
     if not 0 <= val <= 10:
         raise AreaError('Invalid penalty value.')
     if not 1 <= side <= 2:
         raise AreaError('Invalid penalty side.')
     if side == 1:
         self.hp_def = val
     elif side == 2:
         self.hp_pro = val
     self.send_command('HP', side, val)
예제 #22
0
 def get_area_by_name(self, name, case_sensitive=False):
     """Get an area by name."""
     for area in self.areas:
         a_name = area.name.lower() if case_sensitive else area.name
         name = name.lower() if case_sensitive else name
         if a_name == name:
             return area
     raise AreaError('Area not found.')
예제 #23
0
def ooc_cmd_bg(client, arg):
    """
    Set the background of a room.
    Usage: /bg <background>
    """
    if len(arg) == 0:
        raise ArgumentError('You must specify a name. Use /bg <background>.')
    if not client.is_mod and client.area.bg_lock == "true":
        raise AreaError("This area's background is locked!")
    elif client.area.cannot_ic_interact(client):
        raise AreaError("You are not permitted to change the background in this area!")
    try:
        client.area.change_background(arg)
    except AreaError:
        raise
    client.area.broadcast_ooc(
        f'{client.char_name} changed the background to {arg}.')
    database.log_room('bg', client, client.area, message=arg)
예제 #24
0
 def save(self, path='config/areas.yaml'):
     try:
         with open(path, 'w', encoding='utf-8') as stream:
             hubs = []
             for hub in self.hubs:
                 hubs.append(hub.save())
             yaml.dump(hubs, stream, default_flow_style=False)
     except:
         raise AreaError(f'File path {path} is invalid!')
예제 #25
0
    def change_passage_lock(self,
                            client: ClientManager.Client,
                            areas: List[AreaManager.Area],
                            bilock: bool = False,
                            change_passage_visibility: bool = False):
        now_reachable = []
        num_areas = 2 if bilock else 1

        # First check if the player should be able to change the passage at all
        for i in range(num_areas):
            # First check if it is the case a non-authorized use is trying to change passages to
            # areas that do not allow their passages to be modified
            if not areas[
                    i].change_reachability_allowed and not client.is_staff():
                raise AreaError(
                    'You must be authorized to change passages in area {}.'.
                    format(areas[i].name))

            # And make sure that non-authorized users cannot create passages they cannot see
            if ((not areas[1 - i].name in areas[i].reachable_areas)
                    and not (client.is_staff() or areas[1 - i].name
                             in areas[i].visible_reachable_areas)):
                raise AreaError(
                    'You must be authorized to create a new passage from {} to '
                    '{}.'.format(areas[i].name, areas[1 - i].name))

        # If we are at this point, we are committed to changing the passage locks
        for i in range(num_areas):
            if areas[1 - i].name in areas[
                    i].reachable_areas:  # Case removing a passage
                now_reachable.append(False)
                areas[i].reachable_areas -= {areas[1 - i].name}
                if change_passage_visibility:
                    areas[i].visible_reachable_areas -= {areas[1 - i].name}
            else:  # Case creating a passage
                now_reachable.append(True)
                areas[i].reachable_areas.add(areas[1 - i].name)
                if change_passage_visibility:
                    areas[i].visible_reachable_areas.add(areas[1 - i].name)

            for client in areas[i].clients:
                client.reload_music_list()

        return now_reachable
예제 #26
0
 def save(self, path="config/areas.yaml"):
     try:
         with open(path, "w", encoding="utf-8") as stream:
             hubs = []
             for hub in self.hubs:
                 hubs.append(hub.save())
             yaml.dump(hubs, stream, default_flow_style=False)
     except Exception:
         raise AreaError(
             f"Trying to save Hub list: File path {path} is invalid!")
예제 #27
0
 def change_status(self, value):
     allowed_values = ('idle', 'rp', 'casing', 'looking-for-players',
                       'lfp', 'recess', 'gaming')
     if value.lower() not in allowed_values:
         raise AreaError('Invalid status. Possible values: {}'.format(
             ', '.join(allowed_values)))
     if value.lower() == 'lfp':
         value = 'looking-for-players'
     self.status = value.upper()
     self.server.area_manager.send_arup_status()
예제 #28
0
 def get_area_by_abbreviation(self, abbreviation):
     """Get an area by name."""
     for area in self.areas:
         if area.abbreviation == abbreviation:
             return area
         if area.is_hub:
             for sub in area.subareas:
                 if sub.abbreviation == abbreviation:
                     return sub
     raise AreaError('Area not found.')
예제 #29
0
 def change_background(self, bg):
     """
     Set the background.
     :param bg: background name
     :raises: AreaError if `bg` is not in background list
     """
     if bg.lower() not in (name.lower()
                           for name in self.server.backgrounds):
         raise AreaError('Invalid background name.')
     self.background = bg
     self.send_command('BN', self.background)
예제 #30
0
    def save_character_data(self, path='config/character_data.yaml'):
        """
        Save all the character-specific information such as movement delay, keys, etc.
        :param path: filepath to the YAML file.

        """
        try:
            with open(path, 'w', encoding='utf-8') as stream:
                yaml.dump(self.character_data, stream, default_flow_style=False)
        except:
            raise AreaError(f'File path {path} is invalid!')