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))
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 ))
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.")
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_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_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_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 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())))
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 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
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 tick(self): for character in Character.query(self.game): character.tick()
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()) ))
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
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