You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
324 lines
13 KiB
Python
324 lines
13 KiB
Python
2 years ago
|
#!/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 <message> - Says something out loud, "
|
||
|
+ "e.g. 'say Hello'")
|
||
|
mud.send_message(id, " look - Examines the "
|
||
|
+ "surroundings, e.g. 'look'")
|
||
|
mud.send_message(id, " go <exit> - Moves through the exit "
|
||
|
+ "specified, e.g. 'go outside'")
|
||
|
mud.send_message(id, " create <exit> <new roomname> - Creates a new exit and room")
|
||
|
mud.send_message(id, " describe <description> - 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))
|