Python / January 14, 2018
Creating a Chat Log for a Game Using Tkinter in Python
Building a simple chat log widget for a single-player game using Python's Tkinter, with color-coded message types and slash commands.
Introduction
While working on a little game of mine written using Python I came across the need for a chat log that had some basic functionality, namely it could:
- consume text input submitted by the player
- store text input submitted by the player
- send text to the player in the console
- have different color tags based on how the text was submitted
This chat log has no network capabilities, as the game I'm making is single-player, and there's no need for it at the moment. I am by no means an expert in Tkinter, but I was able to accomplish the above goals by doing a bit of research. If there are experts out there who see things that could be improved with this little project feel free to comment!
Required tech
The Chat Log
When thinking of a standard chat log it really consists of just a few things, namely a log where the text is displayed, a text box where data is entered, a submit button, and maybe a header. If you want to skip the explanation of the code and just go to the output, click the Results or Project Code section in the table of contents.
GUI
To create the GUI I used Tkinter, which is a well known and popular way to create GUIs. I've pulled the code out of my game structure to illustrate the route I went to get the chatbox to satisfy the requirements I outlined in the Introduction. First, we've got our import statements:
import copy
import threading
import Tkinter We'll use copy to make a copy of the player input. In the game this player input is stored so it can be used later, but in our example here it's only used once for illustrative purposes. The same can be said for threading, we'll need our GUI to spawn a thread that runs a toy chat example. This is necessary because Tkinter will timeout if threading isn't used to execute the functions.
The following code snippets are taken from the GUI class.
# GLOBALS
chat_log = None
chat_log_input = None
def __init__(self):
# root business
self.root = Tkinter.Tk()
self.root.title("a chat log")
# chat_frame
self.chat_frame = Tkinter.Frame(self.root)
self.chat_frame.grid(row=1, column=0)
self.chat_log_title = None
self.scroll = None
self.chat_log_submit = None
# bindings
self.root.bind("<Return>", LOGGER.receive) Our GUI consists of a few main pieces. First I wanted the chat log and its input box to be accessible from elsewhere in my code, so I made them global class variables. There will only be one instance of this class floating around, so I'm ok with that. In our __init__ we generate root, the chat widget, and its components. This consists of a Tkinter Frame filled with the Label, Entry, Text, and Scrollbar widgets.
The binding allows the user to press Enter on their keyboard and send the data through so it can be processed. It uses a callback function inside our Logger class that we'll look at soon called receive.
def build(self):
"""put it all together"""
self.compileChatFrame()
self.root.mainloop() We use the build method to compile everything together, and finally execute the mainloop once all of the widgets are defined.
def compileChatFrame(self):
"""build the chat log frame widget"""
# chat log title
self.chat_log_title = Tkinter.Label(self.chat_frame, text='Chat Log')
self.chat_log_title.grid(row=0, column=0, sticky=Tkinter.W)
# chat log
GUI.chat_log = Tkinter.Text(self.chat_frame)
GUI.chat_log.config(state=Tkinter.DISABLED)
GUI.chat_log.tag_configure(tagName=COMMAND_LOG_TYPE, foreground='purple')
GUI.chat_log.tag_configure(tagName=NARRATOR_LOG_TYPE, foreground='#0000A0')
GUI.chat_log.tag_configure(tagName=PLAYER_LOG_TYPE, foreground='black')
GUI.chat_log.tag_configure(tagName=SYSTEM_LOG_TYPE, foreground='#FF00FF')
GUI.chat_log.grid(row=1, column=0, sticky=Tkinter.W)
# scrollbar
self.scroll = Tkinter.Scrollbar(self.chat_frame,
orient=Tkinter.VERTICAL,
command=GUI.chat_log.yview)
GUI.chat_log.configure(yscrollcommand=self.scroll.set)
self.scroll.config(command=GUI.chat_log.yview)
self.scroll.grid(row=1, column=1, sticky='nsew')
# chat input
GUI.chat_log_input = Tkinter.Entry(self.chat_frame, background='gray')
GUI.chat_log_input.grid(row=2, sticky='nsew')
GUI.chat_log_input.focus()
# chat submit
self.chat_log_submit = Tkinter.Button(self.chat_frame,
text='Submit',
command=LOGGER.receive)
self.chat_log_submit.grid(row=2, column=0, columnspan=2, sticky=Tkinter.E) When we call the method compileChatFrame all of the widgets are linked together. Tkinter's grid system was used to place all of the widgets appropriately.
The chat log is given a header that uses the Label widget, and it has a fixed text value in this example. The chat log itself used tags to add color to the various messages as they come through to help distinguish them from each other.
The scrollbar is added to the right of the chat log, and is configured in the usual way a scrollbar is. You can see how configure is used to link the chat log and scroll bar together.
The chat input uses the Tkinter Entry widget, and it's placed below the chat log. A submit button is placed to the right of the chat input, and calls LOGGER.receive when pressed.
This completes the GUI part of our little project. You can view the entire class, and the final product below.
Full GUI class
class GUI(object):
"""build the game UI"""
# GLOBALS
chat_log = None
chat_log_input = None
def __init__(self):
# root business
self.root = Tkinter.Tk()
self.root.title("a chat log")
# chat_frame
self.chat_frame = Tkinter.Frame(self.root)
self.chat_frame.grid(row=1, column=0)
self.chat_log_title = None
self.scroll = None
self.chat_log_submit = None
# bindings
self.root.bind("<Return>", LOGGER.receive)
def build(self):
""" put it all together"""
self.compileChatFrame()
self.root.mainloop()
def compileChatFrame(self):
"""build the chat log frame widget"""
# chat log title
self.chat_log_title = Tkinter.Label(self.chat_frame, text='Chat Log')
self.chat_log_title.grid(row=0, column=0, sticky=Tkinter.W)
# chat log
GUI.chat_log = Tkinter.Text(self.chat_frame)
GUI.chat_log.config(state=Tkinter.DISABLED)
GUI.chat_log.tag_configure(tagName=COMMAND_LOG_TYPE, foreground='purple')
GUI.chat_log.tag_configure(tagName=NARRATOR_LOG_TYPE, foreground='#0000A0')
GUI.chat_log.tag_configure(tagName=PLAYER_LOG_TYPE, foreground='black')
GUI.chat_log.tag_configure(tagName=SYSTEM_LOG_TYPE, foreground='#FF00FF')
GUI.chat_log.grid(row=1, column=0, sticky=Tkinter.W)
# scrollbar
self.scroll = Tkinter.Scrollbar(self.chat_frame,
orient=Tkinter.VERTICAL,
command=GUI.chat_log.yview)
GUI.chat_log.configure(yscrollcommand=self.scroll.set)
self.scroll.config(command=GUI.chat_log.yview)
self.scroll.grid(row=1, column=1, sticky='nsew')
# chat input
GUI.chat_log_input = Tkinter.Entry(self.chat_frame, background='gray')
GUI.chat_log_input.grid(row=2, sticky='nsew')
GUI.chat_log_input.focus()
# chat submit
self.chat_log_submit = Tkinter.Button(self.chat_frame,
text='Submit',
command=LOGGER.receive)
self.chat_log_submit.grid(row=2, column=0, columnspan=2, sticky=Tkinter.E) Logger
The concept of the Logger class is that it will handle sending and receiving messages in the chat log. One instance of this class would be created that handles the task.
The following code is inside the Logger class. First, within the __init__ we define a few variables that we'll use to send the messages.
def __init__(self):
self.message = None
self.message_type = None
self.received = False
self.stored = None The message variable is the actual text that makes up the message, while message_type will be used with the tags we defined in the GUI to give color to the messages. The received variable will be used to control a loop that waits for player input, and stored is a record of the last input the player provided, excluding commands.
def bm(self, message, message_type):
"""update the GR with a new message so it can be sent using receive/transmit"""
self.message_type = message_type
if self.message_type == PLAYER_LOG_TYPE:
self.message = '[You]: ' + message
elif self.message_type == SYSTEM_LOG_TYPE:
self.message = '[System]: ' + message
elif self.message_type == NARRATOR_LOG_TYPE:
self.message = '[Narrator]: ' + message
elif self.message_type == COMMAND_LOG_TYPE:
self.message = '[Command]: ' + message
else:
self.message = message The first method in the class is bm, which is short for "build message". All it does is update self.message and self.message_type with the message that needs to be sent, and it attaches a string to the front of the message that will be used with the tags we defined earlier.
def transmit(self):
"""transmit the message to the chat log"""
if self.message:
GAME_UI.chat_log.config(state=Tkinter.NORMAL)
GAME_UI.chat_log.insert(Tkinter.END, "\n" + self.message)
GAME_UI.chat_log_input.delete(0, Tkinter.END)
# attempt to find a message type for coloring
if self.message_type is not None:
pattern = '[' + self.message_type + ']:'
GAME_UI.chat_log.color_message_type(pattern=pattern, tag=self.message_type)
GAME_UI.chat_log.see("end")
GAME_UI.chat_log.config(state=Tkinter.DISABLED)
else:
print('attempted to transmit an empty message')
GAME_UI.chat_log.config(state=Tkinter.NORMAL)
GAME_UI.chat_log_input.delete(0, Tkinter.END)
GAME_UI.chat_log.see("end")
GAME_UI.chat_log.config(state=Tkinter.DISABLED)
# reset variables after transmitting
self.message = None
self.message_type = None First transmit checks to see if there is a message. If there is a message then we essentially turn the chat_log "on", insert the message, delete what's in the input widget. Those are the first three lines of code.
Next we finally get to use the tags we defined in the GUI. I looked around and found a way to add color to the various chat entries so they could be distinguished from each other easier. This was done by adding the following function to the core Tkinter project:
def color_message_type(self, pattern, tag, start="1.0", end="end",
regexp=False):
"""Apply the given tag to all text that matches the given pattern
If 'regexp' is set to True, pattern will be treated as a regular
expression according to Tcl's regular expression syntax.
"""
start = self.index(start)
end = self.index(end)
self.mark_set("matchStart", start)
self.mark_set("matchEnd", start)
self.mark_set("searchLimit", end)
count = IntVar()
while True:
index = self.search(pattern, "matchEnd", "searchLimit",
count=count, regexp=regexp)
if index == "": break
if count.get() == 0: break # degenerate pattern which matches zero-length strings
self.mark_set("matchStart", index)
self.mark_set("matchEnd", "%s+%sc" % (index, count.get()))
self.tag_add(tag, "matchStart", "matchEnd") Once the above code is added we use the tag supplied to bm to alter the color of the tag we appended to the beginning of the message. Next we use the Tkinter Text see method and disable the chat_log so the user can't enter data into it directly again.
Notice the steps we take in the not message condition is very similar to the steps where we have a message, minus a few lines that aren't needed (like inserting, and coloring).
Finally, we reset the message and message_type to None after the message was transmitted to the chat_log. This completes the explanation of the transmit method.
The next method we'll look at is the receive method. This is the callback function used in the GUI that was pointed out earlier. I'm going to list the entire method below and then explain what it does.
def receive(self, event=None):
"""use to capture player input"""
# wait for player response
self.message = GAME_UI.chat_log_input.get()
# when message is found
if self.message:
self.message_type = PLAYER_LOG_TYPE
# execute command
if self.message[0] == '/':
COMMANDS.command = self.message
self.message, continue_command = COMMANDS.runCommand()
if continue_command is True:
self.message_type = COMMAND_LOG_TYPE
LOGGER.bm(self.message, self.message_type)
self.transmit()
else:
# keep last thing typed by player in memory, currently overwrite each time
# do not store commands
if self.message_type == PLAYER_LOG_TYPE:
self.stored = copy.deepcopy(self.message)
# send the non-command message
if self.message is None:
LOGGER.bm(self.stored, self.message_type)
else:
LOGGER.bm(self.message, self.message_type)
self.transmit()
self.received = True First we use the get method of the Entry widget to grab input that has been typed into chat_log_input. If there is nothing in self.message, we do nothing. If there is something in self.message then we parse it.
We're using this exclusively with player supplied input, so we set self.message_type. If the player has executed a slash command, for example /help, then we don't want to store it in self.stored, or count it as a response to an NPC instigated query. We'll look at the Command class soon. If we've got a valid response from the player we use bm to create the message, and transmit to send it. The variable self.received is used in the next method, capture.
def capture(self):
"""whenever a player value needs to be stored
works by keeping track of whether the value has been stored or not"""
self.received = False
self.message_type = PLAYER_LOG_TYPE
# wait for keypress
while LOGGER.received is False:
continue
return LOGGER.stored We use capture when we want to grab player input. For example, we might ask the player what their name is, and then use capture to store it and recite it back to them. It's a while loop that runs and only if receive gets a valid player response does it end the loop.
See the entire Logger class in the collapsed code block below.
Full Logger class
class Logger(object):
"""
this class controls how messages are sent to the chat log
fn: bm: update gr with the message and message type. this MUST be done prior to sending
fn: receive: called by pressing enter or submit while the chat input is active
fn: transmit: called be receive and does the actual work of sending the message to the chat log
fn: capture: called when player input is needed to be captured and/or stored
ex:
"""
def __init__(self):
self.message = None
self.message_type = None
self.received = False
self.stored = None
def bm(self, message, message_type):
"""update the GR with a new message so it can be sent using receive/transmit"""
self.message_type = message_type
if self.message_type == PLAYER_LOG_TYPE:
self.message = '[You]: ' + message
elif self.message_type == SYSTEM_LOG_TYPE:
self.message = '[System]: ' + message
elif self.message_type == NARRATOR_LOG_TYPE:
self.message = '[Narrator]: ' + message
elif self.message_type == COMMAND_LOG_TYPE:
self.message = '[Command]: ' + message
else:
self.message = message
def transmit(self):
"""transmit the message to the chat log"""
if self.message:
GAME_UI.chat_log.config(state=Tkinter.NORMAL)
GAME_UI.chat_log.insert(Tkinter.END, "\n" + self.message)
GAME_UI.chat_log_input.delete(0, Tkinter.END)
# attempt to find a message type for coloring
if self.message_type is not None:
pattern = '[' + self.message_type + ']:'
GAME_UI.chat_log.color_message_type(pattern=pattern, tag=self.message_type)
GAME_UI.chat_log.see("end")
GAME_UI.chat_log.config(state=Tkinter.DISABLED)
else:
print('attempted to transmit an empty message')
GAME_UI.chat_log.config(state=Tkinter.NORMAL)
GAME_UI.chat_log_input.delete(0, Tkinter.END)
GAME_UI.chat_log.see("end")
GAME_UI.chat_log.config(state=Tkinter.DISABLED)
# reset variables after transmitting
self.message = None
self.message_type = None
def receive(self, event=None):
"""use to capture player input"""
# wait for player response
self.message = GAME_UI.chat_log_input.get()
# when message is found
if self.message:
self.message_type = PLAYER_LOG_TYPE
# execute command
if self.message[0] == '/':
COMMANDS.command = self.message
self.message, continue_command = COMMANDS.runCommand()
if continue_command is True:
self.message_type = COMMAND_LOG_TYPE
LOGGER.bm(self.message, self.message_type)
self.transmit()
else:
# keep last thing typed by player in memory, currently overwrite each time
# do not store commands
if self.message_type == PLAYER_LOG_TYPE:
self.stored = copy.deepcopy(self.message)
# send the non-command message
if self.message is None:
LOGGER.bm(self.stored, self.message_type)
else:
LOGGER.bm(self.message, self.message_type)
self.transmit()
self.received = True
def capture(self):
"""whenever a player value needs to be stored
works by keeping track of whether the value has been stored or not"""
self.received = False
self.message_type = PLAYER_LOG_TYPE
# wait for keypress
while LOGGER.received is False:
continue
return LOGGER.stored Commands
The Commands class manages what commands the player has available to them, and what happens when a command is executed. I created a few examples so we can see how they would work inside the chat log, namely: /help, /status, and /start chat.
class Commands(object):
# commands
_HELP = '/help'
_STATUS = '/status'
_START_CHAT = '/start chat'
_COMMAND_LS = [_HELP, _STATUS, _START_CHAT]
def __init__(self, command):
self.command = command
def runCommand(self):
# check if command is valid
if self.command not in self._COMMAND_LS:
message = ("'%s' is not a valid slash command. Type '/help' to see a list of commands." % self.command)
return message, True
if self.command in self._COMMAND_LS:
# the help command
if self.command == self._HELP:
message = self.getCommands(self)
return message, True
# the status command
if self.command == self._STATUS:
message = (' Your current status:'
'\n Combat: %s'
'\n Targets: TBD' %
(COMBAT_STATE
))
return message, True
# the start chat command
if self.command == self._START_CHAT:
startThread()
return LOGGER.message, False
@staticmethod
def getCommands(self):
""" give player a list of valid commands """
message = " Available commands:"
for c in self._COMMAND_LS:
message += '\n ' + c
return message We see that this module is mainly a bunch of if statements that provide output to the chat log using bm. A command will return a message and whether or not that message should be sent using the continue_command variable. The toy example I created is a method called "haveAChat".
def haveAChat():
# send some data to the chat widget
LOGGER.bm("Welcome to the chat log!", NARRATOR_LOG_TYPE)
LOGGER.transmit()
# ask a question
LOGGER.bm("How are you feeling today?", NARRATOR_LOG_TYPE)
LOGGER.transmit()
user_feels = LOGGER.capture()
LOGGER.bm(("I see you feel %s...that's either good, bad, or neither. \n Aren't I smart?" % user_feels), NARRATOR_LOG_TYPE)
LOGGER.transmit()
LOGGER.bm("Well, it was nice chatting! Have a great day!", NARRATOR_LOG_TYPE)
LOGGER.transmit()
def startThread():
global submit_thread
submit_thread = threading.Thread(target=haveAChat)
submit_thread.daemon = True
submit_thread.start() Looking through the haveAChat toy example we see that the player is going to be welcomed to the chat, asked a question, waits for a response, and then transmits a couple more messages. A thread is created to let this function run, and this is needed to prevent the GUI from becoming unresponsive as Tkinter's mainloop doesn't want to compete with Python scripts from running after it's been executed.
Results
Now that the program has been explained, let's take a look at it in action!
if __name__ == '__main__':
# core stuff
PLAYER = None
COMBAT_STATE = False
# logging stuff
COMMAND_LOG_TYPE = 'Command'
NARRATOR_LOG_TYPE = 'Narrator'
PLAYER_LOG_TYPE = 'Player'
SYSTEM_LOG_TYPE = 'System'
# build the classes
COMMANDS = Commands(command=None)
LOGGER = Logger()
GAME_UI = GUI()
GAME_UI.build() You can see as we type in data it's echoed to the chat log. We can send data to the chat log and if we ask the player for input we can capture it and echo it to the player. We also have some color associated with each chat message to make it easier to read. This covers all four of our original points we outlined at the beginning of this article!
Conclusion
This was a fun little project and these three classes will be used to facilitate the creation of a text-based Python game. Feel free to grab the code below and configure it for your own project.
Project Code
Full project code
import copy
import threading
import Tkinter
class GUI(object):
"""build the game UI"""
# GLOBALS
chat_log = None
chat_log_input = None
def __init__(self):
# root business
self.root = Tkinter.Tk()
self.root.title("a chat log")
# chat_frame
self.chat_frame = Tkinter.Frame(self.root)
self.chat_frame.grid(row=1, column=0)
self.chat_log_title = None
self.scroll = None
self.chat_log_submit = None
# bindings
self.root.bind("<Return>", LOGGER.receive)
def build(self):
""" put it all together"""
self.compileChatFrame()
self.root.mainloop()
def compileChatFrame(self):
"""build the chat log frame widget"""
# chat log title
self.chat_log_title = Tkinter.Label(self.chat_frame, text='Chat Log')
self.chat_log_title.grid(row=0, column=0, sticky=Tkinter.W)
# chat log
GUI.chat_log = Tkinter.Text(self.chat_frame)
GUI.chat_log.config(state=Tkinter.DISABLED)
GUI.chat_log.tag_configure(tagName=COMMAND_LOG_TYPE, foreground='purple')
GUI.chat_log.tag_configure(tagName=NARRATOR_LOG_TYPE, foreground='#0000A0')
GUI.chat_log.tag_configure(tagName=PLAYER_LOG_TYPE, foreground='black')
GUI.chat_log.tag_configure(tagName=SYSTEM_LOG_TYPE, foreground='#FF00FF')
GUI.chat_log.grid(row=1, column=0, sticky=Tkinter.W)
# scrollbar
self.scroll = Tkinter.Scrollbar(self.chat_frame,
orient=Tkinter.VERTICAL,
command=GUI.chat_log.yview)
GUI.chat_log.configure(yscrollcommand=self.scroll.set)
self.scroll.config(command=GUI.chat_log.yview)
self.scroll.grid(row=1, column=1, sticky='nsew')
# chat input
GUI.chat_log_input = Tkinter.Entry(self.chat_frame, background='gray')
GUI.chat_log_input.grid(row=2, sticky='nsew')
GUI.chat_log_input.focus()
# chat submit
self.chat_log_submit = Tkinter.Button(self.chat_frame,
text='Submit',
command=LOGGER.receive)
self.chat_log_submit.grid(row=2, column=0, columnspan=2, sticky=Tkinter.E)
class Logger(object):
"""
this class controls how messages are sent to the chat log
fn: bm: update gr with the message and message type. this MUST be done prior to sending
fn: receive: called by pressing enter or submit while the chat input is active
fn: transmit: called be receive and does the actual work of sending the message to the chat log
fn: capture: called when player input is needed to be captured and/or stored
ex:
"""
def __init__(self):
self.message = None
self.message_type = None
self.received = False
self.stored = None
def bm(self, message, message_type):
"""update the GR with a new message so it can be sent using receive/transmit"""
self.message_type = message_type
if self.message_type == PLAYER_LOG_TYPE:
self.message = '[You]: ' + message
elif self.message_type == SYSTEM_LOG_TYPE:
self.message = '[System]: ' + message
elif self.message_type == NARRATOR_LOG_TYPE:
self.message = '[Narrator]: ' + message
elif self.message_type == COMMAND_LOG_TYPE:
self.message = '[Command]: ' + message
else:
self.message = message
def transmit(self):
"""transmit the message to the chat log"""
if self.message:
GAME_UI.chat_log.config(state=Tkinter.NORMAL)
GAME_UI.chat_log.insert(Tkinter.END, "\n" + self.message)
GAME_UI.chat_log_input.delete(0, Tkinter.END)
# attempt to find a message type for coloring
if self.message_type is not None:
pattern = '[' + self.message_type + ']:'
GAME_UI.chat_log.color_message_type(pattern=pattern, tag=self.message_type)
GAME_UI.chat_log.see("end")
GAME_UI.chat_log.config(state=Tkinter.DISABLED)
else:
print('attempted to transmit an empty message')
GAME_UI.chat_log.config(state=Tkinter.NORMAL)
GAME_UI.chat_log_input.delete(0, Tkinter.END)
GAME_UI.chat_log.see("end")
GAME_UI.chat_log.config(state=Tkinter.DISABLED)
# reset variables after transmitting
self.message = None
self.message_type = None
def receive(self, event=None):
"""use to capture player input"""
# wait for player response
self.message = GAME_UI.chat_log_input.get()
# when message is found
if self.message:
self.message_type = PLAYER_LOG_TYPE
# execute command
if self.message[0] == '/':
COMMANDS.command = self.message
self.message, continue_command = COMMANDS.runCommand()
if continue_command is True:
self.message_type = COMMAND_LOG_TYPE
LOGGER.bm(self.message, self.message_type)
self.transmit()
else:
# keep last thing typed by player in memory, currently overwrite each time
# do not store commands
if self.message_type == PLAYER_LOG_TYPE:
self.stored = copy.deepcopy(self.message)
# send the non-command message
if self.message is None:
LOGGER.bm(self.stored, self.message_type)
else:
LOGGER.bm(self.message, self.message_type)
self.transmit()
self.received = True
def capture(self):
"""whenever a player value needs to be stored
works by keeping track of whether the value has been stored or not"""
self.received = False
self.message_type = PLAYER_LOG_TYPE
# wait for keypress
while LOGGER.received is False:
continue
return LOGGER.stored
class Commands(object):
# commands
_HELP = '/help'
_STATUS = '/status'
_START_CHAT = '/start chat'
_COMMAND_LS = [_HELP, _STATUS, _START_CHAT]
def __init__(self, command):
self.command = command
def runCommand(self):
# check if command is valid
if self.command not in self._COMMAND_LS:
message = ("'%s' is not a valid slash command. Type '/help' to see a list of commands." % self.command)
return message, True
if self.command in self._COMMAND_LS:
# the help command
if self.command == self._HELP:
message = self.getCommands(self)
return message, True
# the status command
if self.command == self._STATUS:
message = (' Your current status:'
'\n Combat: %s'
'\n Targets: TBD' %
(COMBAT_STATE
))
return message, True
# the start chat command
if self.command == self._START_CHAT:
startThread()
return LOGGER.message, False
@staticmethod
def getCommands(self):
""" give player a list of valid commands """
message = " Available commands:"
for c in self._COMMAND_LS:
message += '\n ' + c
return message
def haveAChat():
# send some data to the chat widget
LOGGER.bm("Welcome to the chat log!", NARRATOR_LOG_TYPE)
LOGGER.transmit()
# ask a question
LOGGER.bm("How are you feeling today?", NARRATOR_LOG_TYPE)
LOGGER.transmit()
user_feels = LOGGER.capture()
LOGGER.bm(("I see you feel %s...that's either good, bad, or neither. \n Aren't I smart?" % user_feels), NARRATOR_LOG_TYPE)
LOGGER.transmit()
LOGGER.bm("Well, it was nice chatting! Have a great day!", NARRATOR_LOG_TYPE)
LOGGER.transmit()
def startThread():
global submit_thread
submit_thread = threading.Thread(target=haveAChat)
submit_thread.daemon = True
submit_thread.start()
if __name__ == '__main__':
# core stuff
PLAYER = None
COMBAT_STATE = False
# logging stuff
COMMAND_LOG_TYPE = 'Command'
NARRATOR_LOG_TYPE = 'Narrator'
PLAYER_LOG_TYPE = 'Player'
SYSTEM_LOG_TYPE = 'System'
# build the classes
COMMANDS = Commands(command=None)
LOGGER = Logger()
GAME_UI = GUI()
GAME_UI.build()