From 21f634ef7a4953792feaac06be5d8d6fe5999c71 Mon Sep 17 00:00:00 2001 From: Stephen Kerr Date: Tue, 7 Feb 2023 19:05:03 +0100 Subject: [PATCH] added some NPCs, data in JSON, visual stuff --- xpub-mud/README.md | 7 +- xpub-mud/mudserver.py | 77 ++++++++++++++- xpub-mud/npcs.json | 10 ++ xpub-mud/rooms.json | 26 +++++ xpub-mud/xpub_mud.py | 214 ++++++++++++------------------------------ 5 files changed, 179 insertions(+), 155 deletions(-) create mode 100644 xpub-mud/npcs.json create mode 100644 xpub-mud/rooms.json diff --git a/xpub-mud/README.md b/xpub-mud/README.md index f63c217..546b805 100644 --- a/xpub-mud/README.md +++ b/xpub-mud/README.md @@ -1,4 +1,9 @@ -MUD Pi +textpub +====== + +This is a MUD based on the xpub studios. + +Original readme from MUD Pi ====== A simple text-based Multi-User Dungeon (MUD) game, which could be run on a diff --git a/xpub-mud/mudserver.py b/xpub-mud/mudserver.py index ba5077f..13fa6a3 100644 --- a/xpub-mud/mudserver.py +++ b/xpub-mud/mudserver.py @@ -12,6 +12,34 @@ import socket import select import time import sys +import random +import json + +with open('rooms.json', 'r') as f: + rooms = json.load(f) + +chomsky_phrases= [ + { + "phrasetext": "hello! My name is Noam, welcome to xpub", + "qtext" : "Who are you?", + "responses": [1,2], + }, + { + "phrasetext": "I'm here to tell you about language", + "qtext" : "What are you doing here?", + "responses": [0,2,3], + }, + { + "phrasetext": "The obscure language of postmodern, leftist philosophers gives little aid to the working classes", + "qtext" : "What's language?", + "responses": [0,1,3], + }, + { + "phrasetext": "I was never aware of any other option but to question everything.", + "qtext" : "Do you only answer questions?", + "responses": [0], + } +] class MudServer(object): @@ -46,6 +74,39 @@ class MudServer(object): self.buffer = buffer self.lastcheck = lastcheck + + class NPC(object): + """Holds information about a non player character""" + + def __init__(self, name, room, speed, outer_instance): + self.name = name + self.room = room + self.phrases = chomsky_phrases + self.conversation_state = 0 + self.walker = 1 + self.walkspeed = speed #time in seconds + self.starttime = time.time() + self.outer_instance = outer_instance + self.outer_instance.npcs[self.name] = self + + # The npc just changes room on this function for now. it is called as part of the updateNPCLocations function + def move(self, room): + self.room = room + + # The npc should be able to say things to you + # Each interaction is a conversation, you are presented with (two) responses which bring + # you down different paths of the conversation. States of the conversation are like rooms + # and responses are like exits. Eventually could this be more random, from a short list of + # possible interactions or responses? + def interact(self): + pass + # say(json.phrases[conversation_state]) + # print the questions for possible responses + # wait for user response + # self.conversation_state = based on user response + + # End of NPC class------------------------------------------------- + # Used to store different types of occurences _EVENT_NEW_PLAYER = 1 _EVENT_PLAYER_LEFT = 2 @@ -111,6 +172,11 @@ class MudServer(object): # start listening for connections on the socket self._listen_socket.listen(1) + # adding npcs (for testing purposes?) + self.npcs = {} + self.chomsky = self.NPC("chomsky","Corridor",20, self) + self.mario = self.NPC("mario","Corridor",50, self) + def update(self): """Checks for new players, disconnected players, and new messages sent from players. This method must be called before @@ -123,6 +189,7 @@ class MudServer(object): self._check_for_new_connections() self._check_for_disconnected() self._check_for_messages() + self.updateNPCLocations() # move the new events into the main events list so that they can be # obtained with 'get_new_players', 'get_disconnected_players' and @@ -183,7 +250,7 @@ class MudServer(object): """ # we make sure to put a newline on the end so the client receives the # message on its own line - self._attempt_send(to, message+"\n\r") + self._attempt_send(to, message+"\r\n\r\n") def shutdown(self): """Closes down the server, disconnecting all clients and @@ -403,3 +470,11 @@ class MudServer(object): # return the contents of 'message' which is either a string or None return message + + def updateNPCLocations(self): + # global npcs + for i in self.npcs: + if (time.time() - self.npcs[i].starttime > self.npcs[i].walkspeed): + self.npcs[i].move(random.choice(list(rooms.keys()))) + self.npcs[i].starttime = time.time() + # print(self.npcs[i].name + " moved to " + self.npcs[i].room) diff --git a/xpub-mud/npcs.json b/xpub-mud/npcs.json new file mode 100644 index 0000000..3487afb --- /dev/null +++ b/xpub-mud/npcs.json @@ -0,0 +1,10 @@ +{ + "mario" : { + "name" : "mario", + "room" : "Aquarium" + }, + "marx" : { + "name" : "marx", + "room" : "Corridor" + } +} \ No newline at end of file diff --git a/xpub-mud/rooms.json b/xpub-mud/rooms.json new file mode 100644 index 0000000..9cafd63 --- /dev/null +++ b/xpub-mud/rooms.json @@ -0,0 +1,26 @@ +{ + "Studio": { + "name": "Studio", + "description": "You're in a cosy studio. It smells a bit like soup.", + "exits": {"south": "Corridor"} + }, + "Office": { + "name": "Office", + "description": "You're in an office with glass windows to the corridor.", + "exits": {"east": "Corridor", "south": "artificial research station"} + }, + "Corridor": { + "name": "Corridor", + "description": "You're in a short corridor with doors on three sides.", + "exits": {"north": "Studio", "south": "Aquarium", "west": "Office"} + }, + "Aquarium": { + "name": "Aquarium", + "description": "You're in an underwater cavern, somehow you can breathe!", + "exits": {"north": "Corridor"} + }, + "artificial research station": { + "description": "You're in the artificial research station. What happens here?", + "exits": {"north": "Office"} + } +} \ No newline at end of file diff --git a/xpub-mud/xpub_mud.py b/xpub-mud/xpub_mud.py index 80d1e58..8b84805 100644 --- a/xpub-mud/xpub_mud.py +++ b/xpub-mud/xpub_mud.py @@ -3,55 +3,19 @@ """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 json # import the MUD server class from mudserver import MudServer +with open('rooms.json', 'r') as f: + rooms = json.load(f) -# 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 +# stores the players and npcs in the game players = {} # start the server @@ -82,7 +46,16 @@ while True: } # send the new player a prompt for their name - mud.send_message(id, "What is your name?") + mud.send_message(id, """\r + _ _ _ \r +| |_ _____ _| |_ _ __ _ _| |__ \r +| __/ _ \ \/ / __| '_ \| | | | '_ \ \r +| || __/> <| |_| |_) | |_| | |_) |\r + \__\___/_/\_\ __| .__/ \__,_|_.__/ \r + |_| \r + \r\r +Hi there! This is the multiplayer, text-based version of the Experimental Publishing masters at PZI. How about you begin by letting us know what you want to be called? Then press enter. +""") # go through any recently disconnected players for id in mud.get_disconnected_players(): @@ -96,7 +69,8 @@ while True: 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"])) + mud.send_message(pid, "\r{} quit the game".format( + players[id]["name"])) # remove the player's entry in the player dictionary del(players[id]) @@ -114,22 +88,16 @@ while True: if players[id]["name"] is None: players[id]["name"] = command - # this is the room in which the game starts - players[id]["room"] = "studio" + players[id]["room"] = "Corridor" # 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( + mud.send_message(pid, "{} has logged in.".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"]) + # send the new player a welcome message, and a description of the starting room + mud.send_message(id, "Welcome to textpub, " +players[id]["name"]+ ". " + rooms[players[id]["room"]]["description"] + " Type 'help' for a list of commands. Have fun!") # each of the possible commands is handled below. Try adding new # commands to the game! @@ -139,14 +107,12 @@ while True: # send the player back the list of possible commands mud.send_message(id, "Commands:") - mud.send_message(id, " say - Says something out loud, " + mud.send_message(id, " say - Says something out loud, " + "e.g. 'say Hello'") - mud.send_message(id, " look - Examines the " + mud.send_message(id, " look - Examines the " + "surroundings, e.g. 'look'") - mud.send_message(id, " go - Moves through the exit " + 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": @@ -163,10 +129,10 @@ while True: elif command == "look": # store the player's current room - current_room = rooms[players[id]["room"]] + rm = rooms[players[id]["room"]] # send the player back the description of their current room - mud.send_message(id, current_room["description"]) + mud.send_message(id, rm["description"]) playershere = [] # go through every player in the game @@ -178,14 +144,24 @@ while True: # add their name to the list playershere.append(players[pid]["name"]) + # go through every npc in the game + for pid in mud.npcs.keys(): + # if they're in the same room as the player + if mud.npcs[pid].room == players[id]["room"]: + # ... and they have a name to be shown + if mud.npcs[pid].name is not None: + # add their name to the list + playershere.append(mud.npcs[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 }") + mud.send_message(id, "Players here: {}".format( + ", ".join(playershere))) + # 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 }") - + mud.send_message(id, "Exits are: {}".format( + ", ".join(rm["exits"]))) + # 'go' command elif command == "go": @@ -193,23 +169,26 @@ while True: ex = params.lower() # store the player's current room - current_room = rooms[players[id]["room"]] + rm = rooms[players[id]["room"]] # if the specified exit is found in the room's exits list - if ex in current_room["exits"]: + if ex in rm["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: + 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)) + 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"]] + players[id]["room"] = rm["exits"][ex] + rm = rooms[players[id]["room"]] + # print(players[id]["name"] + " moved to the " + players[id]["room"]) # go through all the players in the game for pid, pl in players.items(): @@ -224,7 +203,7 @@ while True: players[id]["name"], ex)) # send the player a message telling them where they are now - mud.send_message(id, "You arrive at '{}'".format( + mud.send_message(id, "You have entered the {}".format( players[id]["room"])) # the specified exit wasn't found in the current room @@ -232,90 +211,19 @@ while True: # 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) + # Item commands, to be completed + # get command + elif command == "get": + mud.send_message(id, "You got it") + + # drop command + elif command == "drop": + mud.send_message(id, "You dropped it") - rooms[new_room]["description"] = description + # make command + elif command == "made": + mud.send_message(id, "You made a ") # some other, unrecognised command else: