示例#1
0
    def tell(self, raw_target, message):
        """
        Tell another player a message.

        tell <name> <message>
        """
        from mud.entities.actor import Actor
        from mud.entities.character import Character

        target = None

        if isinstance(raw_target, Actor):
            target = raw_target
        elif raw_target:
            for potential in Character.query_by("name",
                                                raw_target,
                                                game=self.game):
                if self.can_see(potential):
                    target = potential

        if not target:
            self.echo("Target not found.")
            return

        self.echo("{{gYou tell {}{{g '{{G{}{{g'{{x".format(
            target.format_name_to(self), message))

        if self != target:
            target.echo("{{g{}{{g tells you '{{G{}{{g'{{x".format(
                self.format_name_to(target), message))
示例#2
0
    def tell(self, raw_target, message):
        """
        Tell another player a message.

        tell <name> <message>
        """
        from mud.entities.actor import Actor
        from mud.entities.character import Character

        target = None

        if isinstance(raw_target, Actor):
            target = raw_target
        elif raw_target:
            for potential in Character.query_by("name", raw_target, game=self.game):
                if self.can_see(potential):
                    target = potential

        if not target:
            self.echo("Target not found.")
            return

        self.echo("{{gYou tell {}{{g '{{G{}{{g'{{x".format(
            target.format_name_to(self),
            message
        ))

        if self != target:
            target.echo("{{g{}{{g tells you '{{G{}{{g'{{x".format(
                self.format_name_to(target),
                message
            ))
示例#3
0
def password_command(actor, params, *args, **kwargs):
    from mud.entities.character import Character

    if len(params) < 2:
        actor.echo("Usage: password <old> <new>")
        return

    old = Character.get_password_hash(params[0])
    new = Character.get_password_hash(params[1])

    if actor.password != old:
        actor.echo("Invalid old password.")
        return

    actor.password = new
    actor.save()
    actor.echo("Password updated.")
示例#4
0
    def handle_create_weapon_input(self, message):
        self.display_motd()
        self.state = "motd"

        # First save!
        self.actor = Character.add(self.actor.data, self.game)
        self.actor.set_connection(self)
        self.actor.save()
示例#5
0
    def handle_create_weapon_input(self, message):
        self.display_motd()
        self.state = "motd"

        # First save!
        self.actor = Character.add(self.actor.data, self.game)
        self.actor.set_connection(self)
        self.actor.save()
示例#6
0
    def handle_login_username_input(self, message):
        self.username = Character.get_clean_name(message)

        if not self.username:
            self.write("Sorry, try again: ")
        else:
            ch_data = Character.get_from_file(self.username, self.game)

            if not ch_data:
                starting_room = Room.find_by("id", "3001", game=self.game)
                self.actor = Character(self.game, {
                    "uid": self.username,
                    "id": self.username,
                    "name": self.username,
                    "room_id": starting_room.id,
                    "room_uid": starting_room.uid,
                })
                self.actor.set_connection(self)

                self.state = "create_confirm_username"
                self.write("""\
+------------------------[ Welcome to Waterdeep ]-------------------------+

  We are a roleplaying -encouraged- mud, meaning roleplaying is not
  required by our players but we ask that non-roleplayers abide to a few
  rules and regulations.  All names are to be roleplayish in nature and
  this policy is enforced by the staff.

    1. Do not use names such as Joe, Bob, Larry, Carl and so forth.
    2. Names of Forgotten Realms Deities are reserved for staff members.
    3. Do not use combo word names such as Blackbeard or Rockdeath, etc.

  If we find your name is not suitable for our environment, an immortal
  staff member will appear before you and offer you a rename.  Please be
  nice and civil, and we will return with the same.

+--------------[ This MUD is rated R for Mature Audiences ]---------------+

Did I get that right, {} (Y/N)? """.format(
                    self.username
                ))
                return

            self.write("Password: "******"login_password"
示例#7
0
    def handle_login_username_input(self, message):
        self.username = Character.get_clean_name(message)

        if not self.username:
            self.write("Sorry, try again: ")
        else:
            ch_data = Character.get_from_file(self.username, self.game)

            if not ch_data:
                starting_room = Room.find_by("id", "3001", game=self.game)
                self.actor = Character(
                    self.game, {
                        "uid": self.username,
                        "id": self.username,
                        "name": self.username,
                        "room_id": starting_room.id,
                        "room_uid": starting_room.uid,
                    })
                self.actor.set_connection(self)

                self.state = "create_confirm_username"
                self.write("""\
+------------------------[ Welcome to Waterdeep ]-------------------------+

  We are a roleplaying -encouraged- mud, meaning roleplaying is not
  required by our players but we ask that non-roleplayers abide to a few
  rules and regulations.  All names are to be roleplayish in nature and
  this policy is enforced by the staff.

    1. Do not use names such as Joe, Bob, Larry, Carl and so forth.
    2. Names of Forgotten Realms Deities are reserved for staff members.
    3. Do not use combo word names such as Blackbeard or Rockdeath, etc.

  If we find your name is not suitable for our environment, an immortal
  staff member will appear before you and offer you a rename.  Please be
  nice and civil, and we will return with the same.

+--------------[ This MUD is rated R for Mature Audiences ]---------------+

Did I get that right, {} (Y/N)? """.format(self.username))
                return

            self.write("Password: "******"login_password"
示例#8
0
    def handle_create_password_input(self, message):
        cleaned = message.strip()

        if not cleaned:
            self.writeln("You didn't provide a password, please try again.")
            self.write("Password: "******"Please confirm your password: "******"create_password_confirm"
示例#9
0
    def handle_create_password_input(self, message):
        cleaned = message.strip()

        if not cleaned:
            self.writeln("You didn't provide a password, please try again.")
            self.write("Password: "******"Please confirm your password: "******"create_password_confirm"
示例#10
0
def roles_command(actor, params, command, game, *args, **kwargs):
    from mud.entities.character import Character

    def params_details():
        actor.echo("Usage: {} <name> - List roles".format(command))
        actor.echo("       {} <name> add <role> - Add a role".format(command))
        actor.echo(
            "       {} <name> remove <role> - Remove a role".format(command))

    remainder = list(params)
    if not remainder:
        actor.echo("You must provide a name.")
        params_details()
        return

    name = remainder.pop(0)

    target = Character.find_by("name", name, game)
    if not target:
        actor.echo("Target not found.")
        return

    actor.echo("Target: {}".format(target.name))
    if not remainder:
        actor.echo("{}'s roles: {}".format(target.name,
                                           ', '.join(target.get_roles())))
    else:
        action = remainder.pop(0).lower()

        if not remainder:
            actor.echo("A role must be provided.")
            params_details()
            return

        role = remainder.pop(0).lower()

        if action == "add":
            target.add_role(role)
            actor.echo("Added role '{}' to {}.".format(role, target.name))
        elif action == "remove":
            if not target.has_role(role):
                actor.echo("{} does not have role '{}'.".format(
                    target.name,
                    role,
                ))
                return

            target.remove_role(role)
            actor.echo("Removed role '{}' to {}.".format(role, target.name))
        else:
            actor.echo("Invalid action '{}'.".format(action))
            params_details()
            return

        actor.echo("Updateed roles: {}".format(', '.join(target.get_roles())))
示例#11
0
    def handle_login_password_input(self, message):
        ch_data = Character.get_from_file(self.username, self.game)
        cleaned = message.strip()

        if not cleaned:
            self.writeln("Invalid password.")
            self.destroy()
            return

        password = Character.get_password_hash(cleaned)

        if password != ch_data["password"]:
            self.writeln("Invalid password.")
            self.destroy()
            return

        connection = self.game.get_actor_connection(actor_id=self.username)

        if connection is None:
            Character.add(ch_data, self.game)
            ch = Character.get_by_uid(self.username, self.game)
            self.actor = ch
            self.actor.set_connection(self)
            self.state = "motd"
            self.display_motd()

        else:
            connection.close()
            self.actor = connection.actor
            self.actor.set_connection(self)
            self.server.remove_connection(connection)
            self.state = "playing"
            self.playing = True

            self.writeln("Reconnecting..")
            self.writeln()

            self.actor.handle_input("look")
示例#12
0
    def handle_login_password_input(self, message):
        ch_data = Character.get_from_file(self.username, self.game)
        cleaned = message.strip()

        if not cleaned:
            self.writeln("Invalid password.")
            self.destroy()
            return

        password = Character.get_password_hash(cleaned)

        if password != ch_data["password"]:
            self.writeln("Invalid password.")
            self.destroy()
            return

        connection = self.game.get_actor_connection(actor_id=self.username)

        if connection is None:
            Character.add(ch_data, self.game)
            ch = Character.get_by_uid(self.username, self.game)
            self.actor = ch
            self.actor.set_connection(self)
            self.state = "motd"
            self.display_motd()

        else:
            connection.close()
            self.actor = connection.actor
            self.actor.set_connection(self)
            self.server.remove_connection(connection)
            self.state = "playing"
            self.playing = True

            self.writeln("Reconnecting..")
            self.writeln()

            self.actor.handle_input("look")
示例#13
0
    def get_actors(self, exclude=None):
        """
        Get all the Actors in this Room.
        """
        from mud.entities.actor import Actor
        from mud.entities.character import Character

        # FIXME use some kind of reusable filtering function
        for actor in Actor.query_by_room_uid(self.uid, game=self.game):
            if actor == exclude:
                continue

            yield actor

        for actor in Character.query_by_room_uid(self.uid, game=self.game):
            if actor == exclude:
                continue

            yield actor
示例#14
0
    def handle_create_password_confirm_input(self, message):
        cleaned = message.strip()

        if Character.get_password_hash(cleaned) != self.actor.password:
            self.writeln("Passwords don't match.")
            self.write("Retype password: "******"create_password"
            return

        self.writeln("""\
+---------------------------[ Pick your Race ]----------------------------+

  Welcome to the birthing process of your character.  Below you will
  find a list of available races and their basic stats.  You will gain
  an additional +2 points on a specific stat depending on your choice
  of class.  For detailed information see our website located at
  http://waterdeep.org or type HELP (Name of Race) below.

            STR INT WIS DEX CON                 STR INT WIS DEX CON
  Avian     17  19  20  16  17      HalfElf     17  18  19  18  18
  Centaur   20  17  15  13  21      HalfOrc     19  15  15  20  21
  Draconian 22  18  16  15  21      Heucuva     25  10  10  25  25
  Drow      18  22  20  23  17      Human       21  19  19  19  21
  Dwarf     20  18  22  16  21      Kenku       19  19  21  20  19
  Elf       16  20  18  21  15      Minotaur    23  16  15  16  22
  Esper     14  21  21  20  14      Pixie       14  20  20  23  14
  Giant     22  15  18  15  20      Podrikev    25  18  18  15  25
  Gnoll     20  16  15  20  19      Thri'Kreen  17  22  22  16  25
  Gnome     16  23  19  15  15      Titan       25  18  18  15  25
  Goblin    16  20  16  19  20      Satyr       23  19  10  14  21
  Halfling  15  20  16  21  18

+-------------------------------------------------------------------------+

Please choose a race, or HELP (Name of Race) for more info: \
""")
        self.state = "create_race"
示例#15
0
    def handle_create_password_confirm_input(self, message):
        cleaned = message.strip()

        if Character.get_password_hash(cleaned) != self.actor.password:
            self.writeln("Passwords don't match.")
            self.write("Retype password: "******"create_password"
            return

        self.writeln("""\
+---------------------------[ Pick your Race ]----------------------------+

  Welcome to the birthing process of your character.  Below you will
  find a list of available races and their basic stats.  You will gain
  an additional +2 points on a specific stat depending on your choice
  of class.  For detailed information see our website located at
  http://waterdeep.org or type HELP (Name of Race) below.

            STR INT WIS DEX CON                 STR INT WIS DEX CON
  Avian     17  19  20  16  17      HalfElf     17  18  19  18  18
  Centaur   20  17  15  13  21      HalfOrc     19  15  15  20  21
  Draconian 22  18  16  15  21      Heucuva     25  10  10  25  25
  Drow      18  22  20  23  17      Human       21  19  19  19  21
  Dwarf     20  18  22  16  21      Kenku       19  19  21  20  19
  Elf       16  20  18  21  15      Minotaur    23  16  15  16  22
  Esper     14  21  21  20  14      Pixie       14  20  20  23  14
  Giant     22  15  18  15  20      Podrikev    25  18  18  15  25
  Gnoll     20  16  15  20  19      Thri'Kreen  17  22  22  16  25
  Gnome     16  23  19  15  15      Titan       25  18  18  15  25
  Goblin    16  20  16  19  20      Satyr       23  19  10  14  21
  Halfling  15  20  16  21  18

+-------------------------------------------------------------------------+

Please choose a race, or HELP (Name of Race) for more info: \
""")
        self.state = "create_race"
示例#16
0
 def tick(self):
     for character in Character.query(self.game):
         character.tick()
示例#17
0
def roles_command(actor, params, command, game, *args, **kwargs):
    from mud.entities.character import Character

    def params_details():
        actor.echo("Usage: {} <name> - List roles".format(command))
        actor.echo("       {} <name> add <role> - Add a role".format(command))
        actor.echo("       {} <name> remove <role> - Remove a role".format(command))

    remainder = list(params)
    if not remainder:
        actor.echo("You must provide a name.")
        params_details()
        return

    name = remainder.pop(0)

    target = Character.find_by("name", name, game)
    if not target:
        actor.echo("Target not found.")
        return

    actor.echo("Target: {}".format(target.name))
    if not remainder:
        actor.echo("{}'s roles: {}".format(
            target.name,
            ', '.join(target.get_roles())
        ))
    else:
        action = remainder.pop(0).lower()

        if not remainder:
            actor.echo("A role must be provided.")
            params_details()
            return

        role = remainder.pop(0).lower()

        if action == "add":
            target.add_role(role)
            actor.echo("Added role '{}' to {}.".format(
                role,
                target.name
            ))
        elif action == "remove":
            if not target.has_role(role):
                actor.echo("{} does not have role '{}'.".format(
                    target.name,
                    role,
                ))
                return

            target.remove_role(role)
            actor.echo("Removed role '{}' to {}.".format(
                role,
                target.name
            ))
        else:
            actor.echo("Invalid action '{}'.".format(action))
            params_details()
            return

        actor.echo("Updateed roles: {}".format(
            ', '.join(target.get_roles())
        ))
示例#18
0
class TelnetConnection(Greenlet):
    NEWLINE = "\r\n"

    INPUT_AFTER_DELAY = 0.4  # Between commands.
    INPUT_IDLE_DELAY = 0.05  # No commands lately.

    def __init__(self, server, conn, addr):
        super(TelnetConnection, self).__init__()
        self.playing = False
        self.server = server
        self.socket = conn
        self.hostname = addr[0]
        self.port = addr[1]
        self.ip = addr[0]  # FIXME make this look up IP if hostname not IP
        self.username = ""
        self.input_buffer = []
        self.output_buffer = ''
        self.last_character_sent = ''
        self.state = 'login_username'
        self.game = server.get_game()
        self.delay = 0
        self.actor = None
        self.color = True
        self.last_command = ""
        self.id = self.game.get_unique_connection_id()

    def is_playing(self):
        return self.playing

    def get_actor(self):
        return self.actor

    def toggle_color(self):
        self.color = not self.color

    def has_color(self):
        return self.color

    def add_delay(self, seconds):
        self.delay += seconds

    def handle_login_username_input(self, message):
        self.username = Character.get_clean_name(message)

        if not self.username:
            self.write("Sorry, try again: ")
        else:
            ch_data = Character.get_from_file(self.username, self.game)

            if not ch_data:
                starting_room = Room.find_by("id", "3001", game=self.game)
                self.actor = Character(self.game, {
                    "uid": self.username,
                    "id": self.username,
                    "name": self.username,
                    "room_id": starting_room.id,
                    "room_uid": starting_room.uid,
                })
                self.actor.set_connection(self)

                self.state = "create_confirm_username"
                self.write("""\
+------------------------[ Welcome to Waterdeep ]-------------------------+

  We are a roleplaying -encouraged- mud, meaning roleplaying is not
  required by our players but we ask that non-roleplayers abide to a few
  rules and regulations.  All names are to be roleplayish in nature and
  this policy is enforced by the staff.

    1. Do not use names such as Joe, Bob, Larry, Carl and so forth.
    2. Names of Forgotten Realms Deities are reserved for staff members.
    3. Do not use combo word names such as Blackbeard or Rockdeath, etc.

  If we find your name is not suitable for our environment, an immortal
  staff member will appear before you and offer you a rename.  Please be
  nice and civil, and we will return with the same.

+--------------[ This MUD is rated R for Mature Audiences ]---------------+

Did I get that right, {} (Y/N)? """.format(
                    self.username
                ))
                return

            self.write("Password: "******"login_password"

    def handle_login_password_input(self, message):
        ch_data = Character.get_from_file(self.username, self.game)
        cleaned = message.strip()

        if not cleaned:
            self.writeln("Invalid password.")
            self.destroy()
            return

        password = Character.get_password_hash(cleaned)

        if password != ch_data["password"]:
            self.writeln("Invalid password.")
            self.destroy()
            return

        connection = self.game.get_actor_connection(actor_id=self.username)

        if connection is None:
            Character.add(ch_data, self.game)
            ch = Character.get_by_uid(self.username, self.game)
            self.actor = ch
            self.actor.set_connection(self)
            self.state = "motd"
            self.display_motd()

        else:
            connection.close()
            self.actor = connection.actor
            self.actor.set_connection(self)
            self.server.remove_connection(connection)
            self.state = "playing"
            self.playing = True

            self.writeln("Reconnecting..")
            self.writeln()

            self.actor.handle_input("look")

    def destroy(self):
        if self.actor:
            if self.playing:
                self.actor.save()
                self.actor.remove()

        self.playing = False

        self.flush()
        self.server.remove_connection(self)
        self.close()

    def clean_input(self, message):
        cleaned = message.lower().strip()
        return cleaned

    def handle_create_confirm_username_input(self, message):
        cleaned = self.clean_input(message)

        if cleaned.startswith("y"):
            self.write("""\
A new life has been created.

Please choose a password for {}: """.format(
                self.actor.name
            ))
            self.state = "create_password"

        elif cleaned.startswith("n"):
            self.actor = None
            self.state = "login_username"

            self.writeln()
            self.write("Ok, what IS it, then? ")
        else:
            self.write("Please type Yes or No: ")

    def handle_create_password_input(self, message):
        cleaned = message.strip()

        if not cleaned:
            self.writeln("You didn't provide a password, please try again.")
            self.write("Password: "******"Please confirm your password: "******"create_password_confirm"

    def handle_create_password_confirm_input(self, message):
        cleaned = message.strip()

        if Character.get_password_hash(cleaned) != self.actor.password:
            self.writeln("Passwords don't match.")
            self.write("Retype password: "******"create_password"
            return

        self.writeln("""\
+---------------------------[ Pick your Race ]----------------------------+

  Welcome to the birthing process of your character.  Below you will
  find a list of available races and their basic stats.  You will gain
  an additional +2 points on a specific stat depending on your choice
  of class.  For detailed information see our website located at
  http://waterdeep.org or type HELP (Name of Race) below.

            STR INT WIS DEX CON                 STR INT WIS DEX CON
  Avian     17  19  20  16  17      HalfElf     17  18  19  18  18
  Centaur   20  17  15  13  21      HalfOrc     19  15  15  20  21
  Draconian 22  18  16  15  21      Heucuva     25  10  10  25  25
  Drow      18  22  20  23  17      Human       21  19  19  19  21
  Dwarf     20  18  22  16  21      Kenku       19  19  21  20  19
  Elf       16  20  18  21  15      Minotaur    23  16  15  16  22
  Esper     14  21  21  20  14      Pixie       14  20  20  23  14
  Giant     22  15  18  15  20      Podrikev    25  18  18  15  25
  Gnoll     20  16  15  20  19      Thri'Kreen  17  22  22  16  25
  Gnome     16  23  19  15  15      Titan       25  18  18  15  25
  Goblin    16  20  16  19  20      Satyr       23  19  10  14  21
  Halfling  15  20  16  21  18

+-------------------------------------------------------------------------+

Please choose a race, or HELP (Name of Race) for more info: \
""")
        self.state = "create_race"

    def handle_create_race_input(self, message):
        from settings.races import RACES

        cleaned = self.clean_input(message)

        for race in RACES:
            if race["id"].startswith(cleaned):
                self.actor.race_id = race["id"]
                self.write("""\
+--------------------------[ Pick your Gender ]---------------------------+

                                  Male
                                  Female
                                  Neutral

+-------------------------------------------------------------------------+

Please choose a gender for your character: """)
                self.state = "create_gender"
                return

        self.writeln("That's not a race.")
        self.write("What IS your race? ")

    def handle_create_gender_input(self, message):
        cleaned = self.clean_input(message)
        for gender_id in ["male", "female", "neutral"]:
            if gender_id.startswith(cleaned):
                self.actor.gender_id = gender_id
                break

        if self.actor.gender_id:
            self.write("""\
+--------------------------[ Pick your Class ]---------------------------+

  Waterdeep has a 101 level, 2 Tier remorting system.  After the first
  101 levels you will reroll and be able to choose a new race and class.
  2nd Tier classes are upgrades from their 1st tier counterparts.

  For more information type HELP (Name of Class) to see their help files.

                               Mage
                               Cleric
                               Thief
                               Warrior
                               Ranger
                               Druid
                               Vampire

+-------------------------------------------------------------------------+

Select a class or type HELP (Class) for details: """)
            self.state = "create_class"
        else:
            self.writeln("That's not a sex.")
            self.write("What IS your sex?")

    def handle_create_class_input(self, message):
        self.write("""\
+------------------------[ Pick your Alignment ]-------------------------+

  Your alignment will effect how much experience you get from certain
  mobiles, such as you gain less experience if you are evil, and you kill
  evil mobiles.  You gain more for killing good mobiles.  There are spells
  available that can counter this effect.

                                  Good
                                  Neutral
                                  Evil

+-------------------------------------------------------------------------+

Choose your alignment: """)
        self.actor.class_id = "warrior"
        self.state = "create_alignment"

    def handle_create_alignment_input(self, message):
        self.actor.alignment = 0
        self.write("""\
+----------------------[ Character Customization ]-----------------------+

  Your character is given a basic set of skills and or spells depending
  on your choice of class.  You can customize your character which allows
  you to choose from a wider range of skills and abilities.

+-------------------------------------------------------------------------+

Do you wish to customize? (Yes or No): """)
        self.state = "create_customize_prompt"

    def handle_create_customize_prompt_input(self, message):
        self.write("""\
+-------------------------[ Pick your Weapon ]---------------------------+

  Please pick a weapon to learn from the following choices:

  dagger
+-------------------------------------------------------------------------+


Your choice?: """)
        self.state = "create_weapon"

    def handle_create_weapon_input(self, message):
        self.display_motd()
        self.state = "motd"

        # First save!
        self.actor = Character.add(self.actor.data, self.game)
        self.actor.set_connection(self)
        self.actor.save()

    def handle_motd_input(self, message):
        if not self.is_playing():
            self.actor.act_around("[actor.name] slowly fades into existence.")
            self.actor.handle_input("look")

        self.state = "playing"
        self.playing = True

    def handle_playing_input(self, message):
        # FIXME improve this or use constant?
        if message.strip() == "":
            self.write(" ")
            return

        if message.startswith("!"):
            self.handle_playing_input(self.last_command)
            return

        self.last_command = message
        self.actor.handle_input(message)

    def handle_input(self, message):
        message = message.strip()

        method_name = 'handle_{}_input'.format(self.state)
        if not hasattr(self, method_name):
            raise Exception("Invalid TelnetConnection state '{}'".format(
                self.state
            ))

        method = getattr(self, method_name)
        try:
            method(message)
        except Exception as e:
            self.game.handle_exception(e)

    def display_motd(self):
        self.writeln("MOTD")
        self.writeln()
        self.writeln("Press any key to continue")

    def write_from_template(self, template):
        path = "templates/telnet/" + template
        try:
            with open(path, "r") as template_file:
                contents = template_file.read()
                self.write(contents.strip("\r\n"))
        except IOError:
            self.writeln("Unable to load template '{}'".format(path))

    def flush(self):
        if self.output_buffer:

            # Prefix a newline if we didn't send one last time.
            if self.last_character_sent != self.NEWLINE[-1]:
                self.output_buffer = self.NEWLINE + self.output_buffer

            if self.actor:
                self.writeln()
                if self.playing:
                    if self.actor.is_fighting():
                        self.writeln(self.actor.format_combat_prompt())
                    self.write(self.actor.format_prompt())

            self.last_character_sent = self.output_buffer[-1]
            self.socket.sendall(bytes(self.output_buffer, encoding="UTF-8"))
            self.output_buffer = ''

    def input_loop(self):
        while self.connected:

            # Handle any imposed delay on user input by the game.
            delay = self.delay
            self.delay = 0
            if delay:
                gevent.sleep(delay)

            # FIXME make this cleaner?
            # Allow players to clear their input buffer.
            if "clear" in self.input_buffer:
                self.input_buffer = []
                self.writeln("Input buffer cleared.")

            # Pop off a command and execute it.
            if self.input_buffer:
                next_input = self.input_buffer.pop(0)
                self.handle_input(next_input)
                gevent.sleep(self.INPUT_AFTER_DELAY)
            else:
                gevent.sleep(self.INPUT_IDLE_DELAY)

    def _run(self):
        # self.write_from_template("login")
        self.writeln("Undermountain")
        self.writeln()
        self.write("Username: "******"UTF-8").strip("\r\n").split("\n")
                self.input_buffer += lines
            else:
                if not self.playing:
                    self.destroy()
                self.connected = False

    def read(self):
        if self.lines:
            return self.lines.pop()
        return None

    def write(self, message=""):
        if self.color:
            message = Ansi.colorize(message)

        self.output_buffer += message

    def writeln(self, message=""):
        self.write(message + self.NEWLINE)

    def close(self):
        self.connected = False
        try:
            self.socket.shutdown(socket.SHUT_WR)
            self.socket.close()
        except Exception as e:
            pass
示例#19
0
class TelnetConnection(Greenlet):
    NEWLINE = "\r\n"

    INPUT_AFTER_DELAY = 0.4  # Between commands.
    INPUT_IDLE_DELAY = 0.05  # No commands lately.

    def __init__(self, server, conn, addr):
        super(TelnetConnection, self).__init__()
        self.playing = False
        self.server = server
        self.socket = conn
        self.hostname = addr[0]
        self.port = addr[1]
        self.ip = addr[0]  # FIXME make this look up IP if hostname not IP
        self.username = ""
        self.input_buffer = []
        self.output_buffer = ''
        self.last_character_sent = ''
        self.state = 'login_username'
        self.game = server.get_game()
        self.delay = 0
        self.actor = None
        self.color = True
        self.last_command = ""
        self.id = self.game.get_unique_connection_id()

    def is_playing(self):
        return self.playing

    def get_actor(self):
        return self.actor

    def toggle_color(self):
        self.color = not self.color

    def has_color(self):
        return self.color

    def add_delay(self, seconds):
        self.delay += seconds

    def handle_login_username_input(self, message):
        self.username = Character.get_clean_name(message)

        if not self.username:
            self.write("Sorry, try again: ")
        else:
            ch_data = Character.get_from_file(self.username, self.game)

            if not ch_data:
                starting_room = Room.find_by("id", "3001", game=self.game)
                self.actor = Character(
                    self.game, {
                        "uid": self.username,
                        "id": self.username,
                        "name": self.username,
                        "room_id": starting_room.id,
                        "room_uid": starting_room.uid,
                    })
                self.actor.set_connection(self)

                self.state = "create_confirm_username"
                self.write("""\
+------------------------[ Welcome to Waterdeep ]-------------------------+

  We are a roleplaying -encouraged- mud, meaning roleplaying is not
  required by our players but we ask that non-roleplayers abide to a few
  rules and regulations.  All names are to be roleplayish in nature and
  this policy is enforced by the staff.

    1. Do not use names such as Joe, Bob, Larry, Carl and so forth.
    2. Names of Forgotten Realms Deities are reserved for staff members.
    3. Do not use combo word names such as Blackbeard or Rockdeath, etc.

  If we find your name is not suitable for our environment, an immortal
  staff member will appear before you and offer you a rename.  Please be
  nice and civil, and we will return with the same.

+--------------[ This MUD is rated R for Mature Audiences ]---------------+

Did I get that right, {} (Y/N)? """.format(self.username))
                return

            self.write("Password: "******"login_password"

    def handle_login_password_input(self, message):
        ch_data = Character.get_from_file(self.username, self.game)
        cleaned = message.strip()

        if not cleaned:
            self.writeln("Invalid password.")
            self.destroy()
            return

        password = Character.get_password_hash(cleaned)

        if password != ch_data["password"]:
            self.writeln("Invalid password.")
            self.destroy()
            return

        connection = self.game.get_actor_connection(actor_id=self.username)

        if connection is None:
            Character.add(ch_data, self.game)
            ch = Character.get_by_uid(self.username, self.game)
            self.actor = ch
            self.actor.set_connection(self)
            self.state = "motd"
            self.display_motd()

        else:
            connection.close()
            self.actor = connection.actor
            self.actor.set_connection(self)
            self.server.remove_connection(connection)
            self.state = "playing"
            self.playing = True

            self.writeln("Reconnecting..")
            self.writeln()

            self.actor.handle_input("look")

    def destroy(self):
        if self.actor:
            if self.playing:
                self.actor.save()
                self.actor.remove()

        self.playing = False

        self.flush()
        self.server.remove_connection(self)
        self.close()

    def clean_input(self, message):
        cleaned = message.lower().strip()
        return cleaned

    def handle_create_confirm_username_input(self, message):
        cleaned = self.clean_input(message)

        if cleaned.startswith("y"):
            self.write("""\
A new life has been created.

Please choose a password for {}: """.format(self.actor.name))
            self.state = "create_password"

        elif cleaned.startswith("n"):
            self.actor = None
            self.state = "login_username"

            self.writeln()
            self.write("Ok, what IS it, then? ")
        else:
            self.write("Please type Yes or No: ")

    def handle_create_password_input(self, message):
        cleaned = message.strip()

        if not cleaned:
            self.writeln("You didn't provide a password, please try again.")
            self.write("Password: "******"Please confirm your password: "******"create_password_confirm"

    def handle_create_password_confirm_input(self, message):
        cleaned = message.strip()

        if Character.get_password_hash(cleaned) != self.actor.password:
            self.writeln("Passwords don't match.")
            self.write("Retype password: "******"create_password"
            return

        self.writeln("""\
+---------------------------[ Pick your Race ]----------------------------+

  Welcome to the birthing process of your character.  Below you will
  find a list of available races and their basic stats.  You will gain
  an additional +2 points on a specific stat depending on your choice
  of class.  For detailed information see our website located at
  http://waterdeep.org or type HELP (Name of Race) below.

            STR INT WIS DEX CON                 STR INT WIS DEX CON
  Avian     17  19  20  16  17      HalfElf     17  18  19  18  18
  Centaur   20  17  15  13  21      HalfOrc     19  15  15  20  21
  Draconian 22  18  16  15  21      Heucuva     25  10  10  25  25
  Drow      18  22  20  23  17      Human       21  19  19  19  21
  Dwarf     20  18  22  16  21      Kenku       19  19  21  20  19
  Elf       16  20  18  21  15      Minotaur    23  16  15  16  22
  Esper     14  21  21  20  14      Pixie       14  20  20  23  14
  Giant     22  15  18  15  20      Podrikev    25  18  18  15  25
  Gnoll     20  16  15  20  19      Thri'Kreen  17  22  22  16  25
  Gnome     16  23  19  15  15      Titan       25  18  18  15  25
  Goblin    16  20  16  19  20      Satyr       23  19  10  14  21
  Halfling  15  20  16  21  18

+-------------------------------------------------------------------------+

Please choose a race, or HELP (Name of Race) for more info: \
""")
        self.state = "create_race"

    def handle_create_race_input(self, message):
        from settings.races import RACES

        cleaned = self.clean_input(message)

        for race in RACES:
            if race["id"].startswith(cleaned):
                self.actor.race_id = race["id"]
                self.write("""\
+--------------------------[ Pick your Gender ]---------------------------+

                                  Male
                                  Female
                                  Neutral

+-------------------------------------------------------------------------+

Please choose a gender for your character: """)
                self.state = "create_gender"
                return

        self.writeln("That's not a race.")
        self.write("What IS your race? ")

    def handle_create_gender_input(self, message):
        cleaned = self.clean_input(message)
        for gender_id in ["male", "female", "neutral"]:
            if gender_id.startswith(cleaned):
                self.actor.gender_id = gender_id
                break

        if self.actor.gender_id:
            self.write("""\
+--------------------------[ Pick your Class ]---------------------------+

  Waterdeep has a 101 level, 2 Tier remorting system.  After the first
  101 levels you will reroll and be able to choose a new race and class.
  2nd Tier classes are upgrades from their 1st tier counterparts.

  For more information type HELP (Name of Class) to see their help files.

                               Mage
                               Cleric
                               Thief
                               Warrior
                               Ranger
                               Druid
                               Vampire

+-------------------------------------------------------------------------+

Select a class or type HELP (Class) for details: """)
            self.state = "create_class"
        else:
            self.writeln("That's not a sex.")
            self.write("What IS your sex?")

    def handle_create_class_input(self, message):
        self.write("""\
+------------------------[ Pick your Alignment ]-------------------------+

  Your alignment will effect how much experience you get from certain
  mobiles, such as you gain less experience if you are evil, and you kill
  evil mobiles.  You gain more for killing good mobiles.  There are spells
  available that can counter this effect.

                                  Good
                                  Neutral
                                  Evil

+-------------------------------------------------------------------------+

Choose your alignment: """)
        self.actor.class_id = "warrior"
        self.state = "create_alignment"

    def handle_create_alignment_input(self, message):
        self.actor.alignment = 0
        self.write("""\
+----------------------[ Character Customization ]-----------------------+

  Your character is given a basic set of skills and or spells depending
  on your choice of class.  You can customize your character which allows
  you to choose from a wider range of skills and abilities.

+-------------------------------------------------------------------------+

Do you wish to customize? (Yes or No): """)
        self.state = "create_customize_prompt"

    def handle_create_customize_prompt_input(self, message):
        self.write("""\
+-------------------------[ Pick your Weapon ]---------------------------+

  Please pick a weapon to learn from the following choices:

  dagger
+-------------------------------------------------------------------------+


Your choice?: """)
        self.state = "create_weapon"

    def handle_create_weapon_input(self, message):
        self.display_motd()
        self.state = "motd"

        # First save!
        self.actor = Character.add(self.actor.data, self.game)
        self.actor.set_connection(self)
        self.actor.save()

    def handle_motd_input(self, message):
        if not self.is_playing():
            self.actor.act_around("[actor.name] slowly fades into existence.")
            self.actor.handle_input("look")

        self.state = "playing"
        self.playing = True

    def handle_playing_input(self, message):
        # FIXME improve this or use constant?
        if message.strip() == "":
            self.write(" ")
            return

        if message.startswith("!"):
            self.handle_playing_input(self.last_command)
            return

        self.last_command = message
        self.actor.handle_input(message)

    def handle_input(self, message):
        message = message.strip()

        method_name = 'handle_{}_input'.format(self.state)
        if not hasattr(self, method_name):
            raise Exception("Invalid TelnetConnection state '{}'".format(
                self.state))

        method = getattr(self, method_name)
        try:
            method(message)
        except Exception as e:
            self.game.handle_exception(e)

    def display_motd(self):
        self.writeln("MOTD")
        self.writeln()
        self.writeln("Press any key to continue")

    def write_from_template(self, template):
        path = "templates/telnet/" + template
        try:
            with open(path, "r") as template_file:
                contents = template_file.read()
                self.write(contents.strip("\r\n"))
        except IOError:
            self.writeln("Unable to load template '{}'".format(path))

    def flush(self):
        if self.output_buffer:

            # Prefix a newline if we didn't send one last time.
            if self.last_character_sent != self.NEWLINE[-1]:
                self.output_buffer = self.NEWLINE + self.output_buffer

            if self.actor:
                self.writeln()
                if self.playing:
                    if self.actor.is_fighting():
                        self.writeln(self.actor.format_combat_prompt())
                    self.write(self.actor.format_prompt())

            self.last_character_sent = self.output_buffer[-1]
            self.socket.sendall(bytes(self.output_buffer, encoding="UTF-8"))
            self.output_buffer = ''

    def input_loop(self):
        while self.connected:

            # Handle any imposed delay on user input by the game.
            delay = self.delay
            self.delay = 0
            if delay:
                gevent.sleep(delay)

            # FIXME make this cleaner?
            # Allow players to clear their input buffer.
            if "clear" in self.input_buffer:
                self.input_buffer = []
                self.writeln("Input buffer cleared.")

            # Pop off a command and execute it.
            if self.input_buffer:
                next_input = self.input_buffer.pop(0)
                self.handle_input(next_input)
                gevent.sleep(self.INPUT_AFTER_DELAY)
            else:
                gevent.sleep(self.INPUT_IDLE_DELAY)

    def _run(self):
        # self.write_from_template("login")
        self.writeln("Undermountain")
        self.writeln()
        self.write("Username: "******"UTF-8").strip("\r\n").split("\n")
                self.input_buffer += lines
            else:
                if not self.playing:
                    self.destroy()
                self.connected = False

    def read(self):
        if self.lines:
            return self.lines.pop()
        return None

    def write(self, message=""):
        if self.color:
            message = Ansi.colorize(message)

        self.output_buffer += message

    def writeln(self, message=""):
        self.write(message + self.NEWLINE)

    def close(self):
        self.connected = False
        try:
            self.socket.shutdown(socket.SHUT_WR)
            self.socket.close()
        except Exception as e:
            pass