#!/usr/bin/env python """A simple Multi-User Dungeon (MUD) game. Players can talk to each other, examine their surroundings and move between rooms. Some ideas for things to try adding: * More rooms to explore * An 'emote' command e.g. 'emote laughs out loud' -> 'Mark laughs out loud' * A 'whisper' command for talking to individual players * A 'shout' command for yelling to players in all rooms * Items to look at in rooms e.g. 'look fireplace' -> 'You see a roaring, glowing fire' * Items to pick up e.g. 'take rock' -> 'You pick up the rock' * Monsters to fight * Loot to collect * Saving players accounts between sessions * A password login * A shop from which to buy items author: Mark Frimston - mfrimston@gmail.com """ import time # import the MUD server class from mudserver import MudServer # structure defining the rooms in the game. Try adding more rooms to the game! rooms = { "studio": { "description": "You're in the XPUB studio. Someone is making coffee in the back.", "exits": {"south": "neutral zone"} }, "office": { "description": "You're in the office. Leslie is on the phone.", "exits": {"north": "neutral zone"} }, "neutral zone": { "description": "You're in the neutral zone. Some stuff happens.", "exits": { "south": "office", "north": "studio", "west" : "artificial research station" } }, "artificial research station": { "description": "You're in the artificial research station. What happens here?", "exits": {"south": "neutral zone"} } } # stores the players in the game players = {} # start the server mud = MudServer() # main game loop. We loop forever (i.e. until the program is terminated) while True: # pause for 1/5 of a second on each loop, so that we don't constantly # use 100% CPU time time.sleep(0.2) # 'update' must be called in the loop to keep the game running and give # us up-to-date information mud.update() # go through any newly connected players for id in mud.get_new_players(): # add the new player to the dictionary, noting that they've not been # named yet. # The dictionary key is the player's id number. We set their room to # None initially until they have entered a name # Try adding more player stats - level, gold, inventory, etc players[id] = { "name": None, "room": None, } # send the new player a prompt for their name mud.send_message(id, "What is your name?") # go through any recently disconnected players for id in mud.get_disconnected_players(): # if for any reason the player isn't in the player map, skip them and # move on to the next one if id not in players: continue # go through all the players in the game for pid, pl in players.items(): # send each player a message to tell them about the diconnected # player mud.send_message(pid, "{} quit the game".format(players[id]["name"])) # remove the player's entry in the player dictionary del(players[id]) # go through any new commands sent from players for id, command, params in mud.get_commands(): # if for any reason the player isn't in the player map, skip them and # move on to the next one if id not in players: continue # if the player hasn't given their name yet, use this first command as # their name and move them to the starting room. if players[id]["name"] is None: players[id]["name"] = command # this is the room in which the game starts players[id]["room"] = "studio" # go through all the players in the game for pid, pl in players.items(): # send each player a message to tell them about the new player mud.send_message(pid, "{} entered the game".format( players[id]["name"])) # send the new player a welcome message mud.send_message(id, "Welcome to the game, {}. ".format( players[id]["name"]) + "Type 'help' for a list of commands. Have fun!\n") # send the new player the description of their current room mud.send_message(id, rooms[players[id]["room"]]["description"]) # each of the possible commands is handled below. Try adding new # commands to the game! # 'help' command elif command == "help": # send the player back the list of possible commands mud.send_message(id, "Commands:") mud.send_message(id, " say - Says something out loud, " + "e.g. 'say Hello'") mud.send_message(id, " look - Examines the " + "surroundings, e.g. 'look'") mud.send_message(id, " go - Moves through the exit " + "specified, e.g. 'go outside'") mud.send_message(id, " create - Creates a new exit and room") mud.send_message(id, " describe - Change the description of the current room") # 'say' command elif command == "say": # go through every player in the game for pid, pl in players.items(): # if they're in the same room as the player if players[pid]["room"] == players[id]["room"]: # send them a message telling them what the player said mud.send_message(pid, "{} says: {}".format( players[id]["name"], params)) # 'look' command elif command == "look": # store the player's current room current_room = rooms[players[id]["room"]] # send the player back the description of their current room mud.send_message(id, current_room["description"]) playershere = [] # go through every player in the game for pid, pl in players.items(): # if they're in the same room as the player if players[pid]["room"] == players[id]["room"]: # ... and they have a name to be shown if players[pid]["name"] is not None: # add their name to the list playershere.append(players[pid]["name"]) # send player a message containing the list of players in the room playershere_string = ", ".join(playershere) mud.send_message(id, f"Players here: { playershere_string }") # send player a message containing the list of exits from this room exits = ", ".join(current_room["exits"]) mud.send_message(id, f"Exits are: { exits }") # 'go' command elif command == "go": # store the exit name ex = params.lower() # store the player's current room current_room = rooms[players[id]["room"]] # if the specified exit is found in the room's exits list if ex in current_room["exits"]: # go through all the players in the game for pid, pl in players.items(): # if player is in the same room and isn't the player # sending the command if players[pid]["room"] == players[id]["room"] and pid != id: # send them a message telling them that the player # left the room mud.send_message(pid, "{} left via exit '{}'".format(players[id]["name"], ex)) # update the player's current room to the one the exit leads to players[id]["room"] = current_room["exits"][ex] current_room = rooms[players[id]["room"]] # go through all the players in the game for pid, pl in players.items(): # if player is in the same (new) room and isn't the player # sending the command if players[pid]["room"] == players[id]["room"] \ and pid != id: # send them a message telling them that the player # entered the room mud.send_message(pid, "{} arrived via exit '{}'".format( players[id]["name"], ex)) # send the player a message telling them where they are now mud.send_message(id, "You arrive at '{}'".format( players[id]["room"])) # the specified exit wasn't found in the current room else: # send back an 'unknown exit' message mud.send_message(id, "Unknown exit '{}'".format(ex)) # 'create' command elif command == "create": # store the exit or room that will be created parameters = params.lower() parameters_list = parameters.split() print("[INSPECT] parameters: ", parameters_list) if len(parameters_list) >= 1: # store the new exit name new_exit = parameters_list[0] print("[INSPECT] new exit: ", new_exit) else: new_exit = None if len(parameters_list) >= 2: # store the new room name new_room = " ".join(parameters_list[1:]) print("[INSPECT] new room: ", new_room) else: new_exit = None # store the player's current room current_room = players[id]["room"] print("[INSPECT] current room: ", current_room) # store information about the player's current room current_room_dict = rooms[players[id]["room"]] print("[INSPECT] current room dict: ", current_room_dict) # if both the new exit and new room are given if new_exit is not None and new_room is not None: # send player a message when the exit already exists if new_exit in current_room_dict["exits"]: mud.send_message(id, "This exit already exist.") exits = ", ".join(current_room["exits"]) # create new room else: print(f"[INSPECT] Make new room: { new_room }, in the direction: { new_exit }") # add the new exit to the current room rooms[current_room]["exits"][new_exit] = new_room # store information about the new room rooms[new_room] = {} rooms[new_room]["description"] = "" rooms[new_room]["exits"] = {} # add the opposite exit direction to the exits of the new room if new_exit == "west": exit_to_add = "east" elif new_exit == "east": exit_to_add = "east" if new_exit == "north": exit_to_add = "south" elif new_exit == "south": exit_to_add = "north" # store this exit to the new room rooms[new_room]["exits"][exit_to_add] = current_room # announce the new room to the player mud.send_message(id, f"A new room is added: { new_room } (in the { new_exit })") # invite the player to write a description for the room mud.send_message(id, "The room is not described yet. When you are in the room, you can use 'describe' to add a description. For example: 'describe This is the XML! It smells a bit muffy here.'") # warn the player when the "create" command is not used in the right way else: mud.send_message(id, f"Sorry you cannot create a new room in that way. Try: 'create direction roomname'") # 'describe' command elif command == "describe": # store the exit or room that will be created description = params.lower() print("[INSPECT] description: ", description) # store the player's current room current_room = players[id]["room"] print("[INSPECT] current room: ", current_room) rooms[new_room]["description"] = description # some other, unrecognised command else: # send back an 'unknown command' message mud.send_message(id, "Unknown command '{}'".format(command))