main.py 7.5 KB
#!/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 datetime
#import io
import json
import machine
# import the MUD server class
from mudserver import MudServer
from commands import CommandHandler

print('STARTING MUD\r\n\r\n\r\n')

flash_button = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP)

rooms = {}

# stores the players in the game
players = {}

# start the server
mud = MudServer()

cmd_handler = CommandHandler()

def load_room(room_name):
    print("Loading room:" + room_name)
    try:
        if room_name in rooms:
            return rooms[room_name]


        module = __import__('rooms.' + room_name.lower())
        room_module = getattr(module, room_name.lower())
        room_class = getattr(room_module, room_name)
        instance = room_class()
        rooms[room_name] = instance

        return instance
    except Exception as e:
        print(e)
        return None

def save_object_to_file(obj, filename):
    with open(filename, 'w', encoding='utf-8') as f:
      f.write(json.dumps(obj))

def load_object_from_file(filename):
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            return json.loads(f.read())
    except Exception:
        return None

def prompt(pid):
    if "prompt" not in players[pid]:
        players[pid]["prompt"] = "> "
    mud.send_message(pid, "\r\n" + players[pid]["prompt"], '')

# main game loop. We loop forever (i.e. until the program is terminated)
while True:
    gc.collect()
    if flash_button.value() == 0:
        break
    # pause for 1/5 of a second on each loop, so that we don't constantly
    # use 100% CPU time
    time.sleep(0.001)

    # TODO: Add some cache removal if older than X
    # now = datetime.datetime.now()
    # delta = now - datetime.timedelta(minutes = 2)
    # for room in rooms:
    #     if room.created < delta:
    #         del rooms[room]

    # '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,
            "inventory": {},
            "prompt": "> ",
            "aliases": {},
        }

        # 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
            if players[id]["name"] != None:
                mud.send_message(pid, "{} quit the game".format(
                                                        players[id]["name"]))
            else:
                save_object_to_file(players[id], "players/{}.json".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 players[id]["room"]:
            rm = load_room(players[id]["room"])
        # 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:
            if command.strip() == '' or command is None:
                mud.send_message(id, "Invalid Name")
                continue
            loaded_player = load_object_from_file("players/{}.json".format(command))
            if loaded_player is None:            
                players[id]["name"] = command
                players[id]["room"] = "Tavern"
            else:
                players[id] = loaded_player

            # 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, "\r\n\r\nWelcome to the game, {}. ".format(
                                                           players[id]["name"])
                             + "\r\nType 'help' for a list of commands. Have fun!\r\n\r\n")

            # send the new player the description of their current room
            mud.send_message(id, load_room(players[id]["room"]).get_description())

        # each of the possible commands is handled below. Try adding new
        # commands to the game!

        # 'help' command
        elif command == "help":

            with open('help/help.txt', 'r', encoding='utf-8') as f:
                for line in f:
                    mud.send_message(id, line, '\r')
                mud.send_message(id, '')

        # 'help' command
        elif command == "quit":

            # send the player back the list of possible commands
            mud.send_message(id, "Saving...")
            save_object_to_file(players[id], "players/{}.json".format(players[id]["name"]))
            mud.disconnect_player(id)

        # 'help' command
        elif command == "save":

            # send the player back the list of possible commands
            mud.send_message(id, "Saving...")
            save_object_to_file(players[id], "players/{}.json".format(players[id]["name"]))
            mud.send_message(id, "Save complete")

        # '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
        else:

            handler_results = cmd_handler.parse(id, command, params, rm, mud, players, load_room)

        prompt(id)

# Start WIFI Setup
if flash_button.value() == 0:
    import wifiweb