Contrib: Added a "time" command for viewing the time info on ExtendedRooms. Also added more listing functionality to the Extended @desc command.

This commit is contained in:
Griatch 2012-06-26 09:13:23 +02:00
parent 5a1642ab32
commit 43f16094c1
3 changed files with 181 additions and 140 deletions

View file

@ -44,9 +44,17 @@ will also look through the available details at the current location
if applicable. An extended @desc command is used to set details. if applicable. An extended @desc command is used to set details.
Installation: 4) Extra commands
1) Add CmdExtendedLook and CmdExtendedDesc from this module to the default cmdset (see wiki how to do this). CmdExtendedLook - look command supporting room details
CmdExtendedDesc - @desc command allowing to add seasonal descs and details,
as well as listing them
CmdGameTime - A simple "time" command, displaying the current time and season.
Installation/testing:
1) Add CmdExtendedLook, CmdExtendedDesc and CmdGameTime to the default cmdset (see wiki how to do this).
2) @dig a room of type contrib.extended_room.ExtendedRoom (or make it the default room type) 2) @dig a room of type contrib.extended_room.ExtendedRoom (or make it the default room type)
3) Use @desc and @detail to customize the room, then play around! 3) Use @desc and @detail to customize the room, then play around!
@ -126,7 +134,6 @@ class ExtendedRoom(Room):
elif DAY_BOUNDARIES[2] <= timeslot < DAY_BOUNDARIES[3]: curr_timeslot = "afternoon" elif DAY_BOUNDARIES[2] <= timeslot < DAY_BOUNDARIES[3]: curr_timeslot = "afternoon"
else: curr_timeslot = "evening" else: curr_timeslot = "evening"
print "season:%s, timeslot:%s" % (curr_season, curr_timeslot)
return curr_season, curr_timeslot return curr_season, curr_timeslot
def replace_timeslots(self, raw_desc, curr_time): def replace_timeslots(self, raw_desc, curr_time):
@ -283,9 +290,9 @@ class CmdExtendedDesc(default_cmds.CmdDesc):
def func(self): def func(self):
"Define extended command" "Define extended command"
caller = self.caller caller = self.caller
location = caller.location
if self.cmdstring == '@detail': if self.cmdstring == '@detail':
# switch to detailing mode. This operates only on current location # switch to detailing mode. This operates only on current location
location = self.caller.location
if not location: if not location:
caller.msg("No location to detail!") caller.msg("No location to detail!")
return return
@ -308,20 +315,28 @@ class CmdExtendedDesc(default_cmds.CmdDesc):
del location.db.detail del location.db.detail
caller.msg("Detail %s deleted, if it existed." % self.lhs) caller.msg("Detail %s deleted, if it existed." % self.lhs)
return return
# setting a detail # setting a detail
location.db.details[self.lhs] = self.rhs location.db.details[self.lhs] = self.rhs
caller.msg("Set Detail %s to '%s'." % (self.lhs, self.rhs)) caller.msg("Set Detail %s to '%s'." % (self.lhs, self.rhs))
return return
else: else:
# we are doing a @desc call # we are doing a @desc call
if not self.args:
if location:
string = "{wDescriptions on %s{n:\n" % location.key
string += " {wspring:{n %s\n" % location.db.spring_desc
string += " {wsummer:{n %s\n" % location.db.summer_desc
string += " {wautumn:{n %s\n" % location.db.autumn_desc
string += " {wwinter:{n %s\n" % location.db.winter_desc
string += " {wgeneral:{n %s" % location.db.general_desc
caller.msg(string)
return
if self.switches and self.switches[0] in ("spring", "summer", "autumn", "winter"): if self.switches and self.switches[0] in ("spring", "summer", "autumn", "winter"):
# a seasonal switch was given # a seasonal switch was given
if self.rhs: if self.rhs:
caller.msg("Seasonal descs only works with rooms, not objects.") caller.msg("Seasonal descs only works with rooms, not objects.")
return return
switch = self.switches[0] switch = self.switches[0]
location = caller.location
if not location: if not location:
caller.msg("No location was found!") caller.msg("No location was found!")
return return
@ -346,3 +361,29 @@ class CmdExtendedDesc(default_cmds.CmdDesc):
obj.db.desc = self.args # compatability obj.db.desc = self.args # compatability
caller.msg("General description was set on %s." % obj.key) caller.msg("General description was set on %s." % obj.key)
# Simple command to view the current time and season
class CmdGameTime(default_cmds.MuxCommand):
"""
Check the game time
Usage:
time
Shows the current in-game time and season.
"""
key = "time"
locks = "cmd:all()"
help_category = "General"
def func(self):
"Reads time info from current room"
location = self.caller.location
if not location or not hasattr(location, "get_time_and_season"):
self.caller.msg("No location available - you are outside time.")
else:
season, timeslot = location.get_time_and_season()
prep = "a"
if season == "autumn":
prep = "an"
self.caller.msg("It's %s %s day, in the %s." % (prep, season, timeslot))

View file

@ -8,12 +8,12 @@ This implements an advanced line editor for editing longer texts
in-game. The editor mimics the command mechanisms of the VI editor as in-game. The editor mimics the command mechanisms of the VI editor as
far as possible. far as possible.
Features of the editor: Features of the editor:
undo/redo undo/redo
edit/replace on any line of the buffer edit/replace on any line of the buffer
search&replace text anywhere in buffer search&replace text anywhere in buffer
formatting of buffer, or selection, to certain width + indentations formatting of buffer, or selection, to certain width + indentations
allow to echo the input or not depending on your client. allow to echo the input or not depending on your client.
""" """
import re import re
@ -34,23 +34,23 @@ class CmdEditorBase(Command):
help_entry = "LineEditor" help_entry = "LineEditor"
code = None code = None
editor = None editor = None
def parse(self): def parse(self):
""" """
Handles pre-parsing Handles pre-parsing
Editor commands are on the form Editor commands are on the form
:cmd [li] [w] [txt] :cmd [li] [w] [txt]
Where all arguments are optional. Where all arguments are optional.
li - line number (int), starting from 1. This could also be a range given as <l>:<l> li - line number (int), starting from 1. This could also be a range given as <l>:<l>
w - word(s) (string), could be encased in quotes. w - word(s) (string), could be encased in quotes.
txt - extra text (string), could be encased in quotes txt - extra text (string), could be encased in quotes
""" """
linebuffer = [] linebuffer = []
if self.editor: if self.editor:
linebuffer = self.editor.buffer.split("\n") linebuffer = self.editor.buffer.split("\n")
nlines = len(linebuffer) nlines = len(linebuffer)
@ -63,39 +63,39 @@ class CmdEditorBase(Command):
arglist = [part for part in RE_GROUP.findall(self.args) if part] arglist = [part for part in RE_GROUP.findall(self.args) if part]
temp = [] temp = []
for arg in arglist: for arg in arglist:
# we want to clean the quotes, but only one type, in case we are nesting. # we want to clean the quotes, but only one type, in case we are nesting.
if arg.startswith('"'): if arg.startswith('"'):
arg.strip('"') arg.strip('"')
elif arg.startswith("'"): elif arg.startswith("'"):
arg.strip("'") arg.strip("'")
temp.append(arg) temp.append(arg)
arglist = temp arglist = temp
# A dumb split, without grouping quotes # A dumb split, without grouping quotes
words = self.args.split() words = self.args.split()
# current line number # current line number
cline = nlines - 1 cline = nlines - 1
# the first argument could also be a range of line numbers, on the # the first argument could also be a range of line numbers, on the
# form <lstart>:<lend>. Either of the ends could be missing, to # form <lstart>:<lend>. Either of the ends could be missing, to
# mean start/end of buffer respectively. # mean start/end of buffer respectively.
lstart, lend = cline, cline + 1 lstart, lend = cline, cline + 1
linerange = False linerange = False
if arglist and ':' in arglist[0]: if arglist and ':' in arglist[0]:
part1, part2 = arglist[0].split(':') part1, part2 = arglist[0].split(':')
if part1 and part1.isdigit(): if part1 and part1.isdigit():
lstart = min(max(0, int(part1)) - 1, nlines) lstart = min(max(0, int(part1)) - 1, nlines)
linerange = True linerange = True
if part2 and part2.isdigit(): if part2 and part2.isdigit():
lend = min(lstart + 1, int(part2)) + 1 lend = min(lstart + 1, int(part2)) + 1
linerange = True linerange = True
elif arglist and arglist[0].isdigit(): elif arglist and arglist[0].isdigit():
lstart = min(max(0, int(arglist[0]) - 1), nlines) lstart = min(max(0, int(arglist[0]) - 1), nlines)
lend = lstart + 1 lend = lstart + 1
linerange = True linerange = True
if linerange: if linerange:
arglist = arglist[1:] arglist = arglist[1:]
@ -107,7 +107,7 @@ class CmdEditorBase(Command):
lstr = "lines %i-%i" % (lstart + 1, lend) lstr = "lines %i-%i" % (lstart + 1, lend)
# arg1 and arg2 is whatever arguments. Line numbers or -ranges are never included here. # arg1 and arg2 is whatever arguments. Line numbers or -ranges are never included here.
args = " ".join(arglist) args = " ".join(arglist)
arg1, arg2 = "", "" arg1, arg2 = "", ""
if len(arglist) > 1: if len(arglist) > 1:
@ -124,30 +124,30 @@ class CmdEditorBase(Command):
self.lstart = lstart self.lstart = lstart
self.lend = lend self.lend = lend
self.linerange = linerange self.linerange = linerange
self.lstr = lstr self.lstr = lstr
self.words = words self.words = words
self.args = args self.args = args
self.arg1 = arg1 self.arg1 = arg1
self.arg2 = arg2 self.arg2 = arg2
def func(self): def func(self):
"Implements the Editor commands" "Implements the Editor commands"
pass pass
class CmdLineInput(CmdEditorBase): class CmdLineInput(CmdEditorBase):
""" """
No command match - Inputs line of text into buffer. No command match - Inputs line of text into buffer.
""" """
key = CMD_NOMATCH key = CMD_NOMATCH
aliases = [CMD_NOINPUT] aliases = [CMD_NOINPUT]
def func(self): def func(self):
"Adds the line without any formatting changes." "Adds the line without any formatting changes."
# add a line of text # add a line of text
if not self.editor.buffer: if not self.editor.buffer:
buf = self.args buf = self.args
else: else:
buf = self.editor.buffer + "\n%s" % self.args buf = self.editor.buffer + "\n%s" % self.args
self.editor.update_buffer(buf) self.editor.update_buffer(buf)
if self.editor.echo_mode: if self.editor.echo_mode:
self.caller.msg("%02i| %s" % (self.cline + 1, self.args)) self.caller.msg("%02i| %s" % (self.cline + 1, self.args))
@ -164,18 +164,18 @@ class CmdEditorGroup(CmdEditorBase):
def func(self): def func(self):
""" """
This command handles all the in-editor :-style commands. Since each command This command handles all the in-editor :-style commands. Since each command
is small and very limited, this makes for a more efficient presentation. is small and very limited, this makes for a more efficient presentation.
""" """
caller = self.caller caller = self.caller
editor = self.editor editor = self.editor
linebuffer = self.linebuffer linebuffer = self.linebuffer
lstart, lend = self.lstart, self.lend lstart, lend = self.lstart, self.lend
cmd = self.cmdstring cmd = self.cmdstring
echo_mode = self.editor.echo_mode echo_mode = self.editor.echo_mode
string = "" string = ""
if cmd == ":": if cmd == ":":
# Echo buffer # Echo buffer
if self.linerange: if self.linerange:
buf = linebuffer[lstart:lend] buf = linebuffer[lstart:lend]
string = editor.display_buffer(buf=buf, offset=lstart) string = editor.display_buffer(buf=buf, offset=lstart)
@ -189,9 +189,9 @@ class CmdEditorGroup(CmdEditorBase):
else: else:
string = editor.display_buffer(linenums=False) string = editor.display_buffer(linenums=False)
self.caller.msg(string, data={"raw":True}) self.caller.msg(string, data={"raw":True})
return return
elif cmd == ":::": elif cmd == ":::":
# Insert single colon alone on a line # Insert single colon alone on a line
editor.update_buffer(editor.buffer + "\n:") editor.update_buffer(editor.buffer + "\n:")
if echo_mode: if echo_mode:
string = "Single ':' added to buffer." string = "Single ':' added to buffer."
@ -212,25 +212,25 @@ class CmdEditorGroup(CmdEditorBase):
yescode = "self.caller.ndb._lineeditor.save_buffer()\nself.caller.ndb._lineeditor.quit()", yescode = "self.caller.ndb._lineeditor.save_buffer()\nself.caller.ndb._lineeditor.quit()",
nocode = "self.caller.msg(self.caller.ndb._lineeditor.quit())", default="Y") nocode = "self.caller.msg(self.caller.ndb._lineeditor.quit())", default="Y")
else: else:
string = editor.quit() string = editor.quit()
elif cmd == ":q!": elif cmd == ":q!":
# force quit, not checking saving # force quit, not checking saving
string = editor.quit() string = editor.quit()
elif cmd == ":u": elif cmd == ":u":
# undo # undo
string = editor.update_undo(-1) string = editor.update_undo(-1)
elif cmd == ":uu": elif cmd == ":uu":
# redo # redo
string = editor.update_undo(1) string = editor.update_undo(1)
elif cmd == ":UU": elif cmd == ":UU":
# reset buffer # reset buffer
editor.update_buffer(editor.pristine_buffer) editor.update_buffer(editor.pristine_buffer)
string = "Reverted all changes to the buffer back to original state." string = "Reverted all changes to the buffer back to original state."
elif cmd == ":dd": elif cmd == ":dd":
# :dd <l> - delete line <l> # :dd <l> - delete line <l>
buf = linebuffer[:lstart] + linebuffer[lend:] buf = linebuffer[:lstart] + linebuffer[lend:]
editor.update_buffer(buf) editor.update_buffer(buf)
string = "Deleted %s." % (self.lstr) string = "Deleted %s." % (self.lstr)
elif cmd == ":dw": elif cmd == ":dw":
# :dw <w> - delete word in entire buffer # :dw <w> - delete word in entire buffer
# :dw <l> <w> delete word only on line(s) <l> # :dw <l> <w> delete word only on line(s) <l>
@ -241,7 +241,7 @@ class CmdEditorGroup(CmdEditorBase):
lstart = 0 lstart = 0
lend = self.cline + 1 lend = self.cline + 1
string = "Removed %s for lines %i-%i." % (self.arg1, lstart + 1 , lend + 1) string = "Removed %s for lines %i-%i." % (self.arg1, lstart + 1 , lend + 1)
else: else:
string = "Removed %s for %s." % (self.arg1, self.lstr) string = "Removed %s for %s." % (self.arg1, self.lstr)
sarea = "\n".join(linebuffer[lstart:lend]) sarea = "\n".join(linebuffer[lstart:lend])
sarea = re.sub(r"%s" % self.arg1.strip("\'").strip('\"'), "", sarea, re.MULTILINE) sarea = re.sub(r"%s" % self.arg1.strip("\'").strip('\"'), "", sarea, re.MULTILINE)
@ -250,16 +250,16 @@ class CmdEditorGroup(CmdEditorBase):
elif cmd == ":DD": elif cmd == ":DD":
# clear buffer # clear buffer
editor.update_buffer("") editor.update_buffer("")
string = "Cleared %i lines from buffer." % self.nlines string = "Cleared %i lines from buffer." % self.nlines
elif cmd == ":y": elif cmd == ":y":
# :y <l> - yank line(s) to copy buffer # :y <l> - yank line(s) to copy buffer
cbuf = linebuffer[lstart:lend] cbuf = linebuffer[lstart:lend]
editor.copy_buffer = cbuf editor.copy_buffer = cbuf
string = "%s, %s yanked." % (self.lstr.capitalize(), cbuf) string = "%s, %s yanked." % (self.lstr.capitalize(), cbuf)
elif cmd == ":x": elif cmd == ":x":
# :x <l> - cut line to copy buffer # :x <l> - cut line to copy buffer
cbuf = linebuffer[lstart:lend] cbuf = linebuffer[lstart:lend]
editor.copy_buffer = cbuf editor.copy_buffer = cbuf
buf = linebuffer[:lstart] + linebuffer[lend:] buf = linebuffer[:lstart] + linebuffer[lend:]
editor.update_buffer(buf) editor.update_buffer(buf)
string = "%s, %s cut." % (self.lstr.capitalize(), cbuf) string = "%s, %s cut." % (self.lstr.capitalize(), cbuf)
@ -272,16 +272,16 @@ class CmdEditorGroup(CmdEditorBase):
editor.update_buffer(buf) editor.update_buffer(buf)
string = "Copied buffer %s to %s." % (editor.copy_buffer, self.lstr) string = "Copied buffer %s to %s." % (editor.copy_buffer, self.lstr)
elif cmd == ":i": elif cmd == ":i":
# :i <l> <txt> - insert new line # :i <l> <txt> - insert new line
new_lines = self.args.split('\n') new_lines = self.args.split('\n')
if not new_lines: if not new_lines:
string = "You need to enter a new line and where to insert it." string = "You need to enter a new line and where to insert it."
else: else:
buf = linebuffer[:lstart] + new_lines + linebuffer[lstart:] buf = linebuffer[:lstart] + new_lines + linebuffer[lstart:]
editor.update_buffer(buf) editor.update_buffer(buf)
string = "Inserted %i new line(s) at %s." % (len(new_lines), self.lstr) string = "Inserted %i new line(s) at %s." % (len(new_lines), self.lstr)
elif cmd == ":r": elif cmd == ":r":
# :r <l> <txt> - replace lines # :r <l> <txt> - replace lines
new_lines = self.args.split('\n') new_lines = self.args.split('\n')
if not new_lines: if not new_lines:
string = "You need to enter a replacement string." string = "You need to enter a replacement string."
@ -290,7 +290,7 @@ class CmdEditorGroup(CmdEditorBase):
editor.update_buffer(buf) editor.update_buffer(buf)
string = "Replaced %i line(s) at %s." % (len(new_lines), self.lstr) string = "Replaced %i line(s) at %s." % (len(new_lines), self.lstr)
elif cmd == ":I": elif cmd == ":I":
# :I <l> <txt> - insert text at beginning of line(s) <l> # :I <l> <txt> - insert text at beginning of line(s) <l>
if not self.args: if not self.args:
string = "You need to enter text to insert." string = "You need to enter text to insert."
else: else:
@ -314,17 +314,17 @@ class CmdEditorGroup(CmdEditorBase):
lstart = 0 lstart = 0
lend = self.cline + 1 lend = self.cline + 1
string = "Search-replaced %s -> %s for lines %i-%i." % (self.arg1, self.arg2, lstart + 1 , lend) string = "Search-replaced %s -> %s for lines %i-%i." % (self.arg1, self.arg2, lstart + 1 , lend)
else: else:
string = "Search-replaced %s -> %s for %s." % (self.arg1, self.arg2, self.lstr) string = "Search-replaced %s -> %s for %s." % (self.arg1, self.arg2, self.lstr)
sarea = "\n".join(linebuffer[lstart:lend]) sarea = "\n".join(linebuffer[lstart:lend])
regex = r"%s|^%s(?=\s)|(?<=\s)%s(?=\s)|^%s$|(?<=\s)%s$" regex = r"%s|^%s(?=\s)|(?<=\s)%s(?=\s)|^%s$|(?<=\s)%s$"
regarg = self.arg1.strip("\'").strip('\"') regarg = self.arg1.strip("\'").strip('\"')
if " " in regarg: if " " in regarg:
regarg = regarg.replace(" ", " +") regarg = regarg.replace(" ", " +")
sarea = re.sub(regex % (regarg, regarg, regarg, regarg, regarg), self.arg2.strip("\'").strip('\"'), sarea, re.MULTILINE) sarea = re.sub(regex % (regarg, regarg, regarg, regarg, regarg), self.arg2.strip("\'").strip('\"'), sarea, re.MULTILINE)
buf = linebuffer[:lstart] + sarea.split("\n") + linebuffer[lend:] buf = linebuffer[:lstart] + sarea.split("\n") + linebuffer[lend:]
editor.update_buffer(buf) editor.update_buffer(buf)
elif cmd == ":f": elif cmd == ":f":
# :f <l> flood-fill buffer or <l> lines of buffer. # :f <l> flood-fill buffer or <l> lines of buffer.
width = 78 width = 78
@ -332,7 +332,7 @@ class CmdEditorGroup(CmdEditorBase):
lstart = 0 lstart = 0
lend = self.cline + 1 lend = self.cline + 1
string = "Flood filled lines %i-%i." % (lstart + 1 , lend) string = "Flood filled lines %i-%i." % (lstart + 1 , lend)
else: else:
string = "Flood filled %s." % self.lstr string = "Flood filled %s." % self.lstr
fbuf = "\n".join(linebuffer[lstart:lend]) fbuf = "\n".join(linebuffer[lstart:lend])
fbuf = utils.fill(fbuf, width=width) fbuf = utils.fill(fbuf, width=width)
@ -345,7 +345,7 @@ class CmdEditorGroup(CmdEditorBase):
lstart = 0 lstart = 0
lend = self.cline + 1 lend = self.cline + 1
string = "Indented lines %i-%i." % (lstart + 1 , lend) string = "Indented lines %i-%i." % (lstart + 1 , lend)
else: else:
string = "Indented %s." % self.lstr string = "Indented %s." % self.lstr
fbuf = [indent + line for line in linebuffer[lstart:lend]] fbuf = [indent + line for line in linebuffer[lstart:lend]]
buf = linebuffer[:lstart] + fbuf + linebuffer[lend:] buf = linebuffer[:lstart] + fbuf + linebuffer[lend:]
@ -356,7 +356,7 @@ class CmdEditorGroup(CmdEditorBase):
lstart = 0 lstart = 0
lend = self.cline + 1 lend = self.cline + 1
string = "Removed left margin (dedented) lines %i-%i." % (lstart + 1 , lend) string = "Removed left margin (dedented) lines %i-%i." % (lstart + 1 , lend)
else: else:
string = "Removed left margin (dedented) %s." % self.lstr string = "Removed left margin (dedented) %s." % self.lstr
fbuf = "\n".join(linebuffer[lstart:lend]) fbuf = "\n".join(linebuffer[lstart:lend])
fbuf = utils.dedent(fbuf) fbuf = utils.dedent(fbuf)
@ -365,7 +365,7 @@ class CmdEditorGroup(CmdEditorBase):
elif cmd == ":echo": elif cmd == ":echo":
# set echoing on/off # set echoing on/off
editor.echo_mode = not editor.echo_mode editor.echo_mode = not editor.echo_mode
string = "Echo mode set to %s" % editor.echo_mode string = "Echo mode set to %s" % editor.echo_mode
caller.msg(string) caller.msg(string)
@ -378,7 +378,7 @@ class LineEditor(object):
""" """
This defines a line editor object. It creates all relevant commands This defines a line editor object. It creates all relevant commands
and tracks the current state of the buffer. It also cleans up after and tracks the current state of the buffer. It also cleans up after
itself. itself.
""" """
def __init__(self, caller, loadcode="", savecode="", key=""): def __init__(self, caller, loadcode="", savecode="", key=""):
@ -388,11 +388,11 @@ class LineEditor(object):
savecode - code to execute in order to save the result savecode - code to execute in order to save the result
key = an optional key for naming this session (such as which attribute is being edited) key = an optional key for naming this session (such as which attribute is being edited)
""" """
self.key = key self.key = key
self.caller = caller self.caller = caller
self.caller.ndb._lineeditor = self self.caller.ndb._lineeditor = self
self.buffer = "" self.buffer = ""
self.unsaved = False self.unsaved = False
if loadcode: if loadcode:
try: try:
exec(loadcode) exec(loadcode)
@ -410,12 +410,12 @@ class LineEditor(object):
editor_cmdset = EditorCmdSet() editor_cmdset = EditorCmdSet()
editor_cmdset.add(cmd1) editor_cmdset.add(cmd1)
editor_cmdset.add(cmd2) editor_cmdset.add(cmd2)
self.caller.cmdset.add(editor_cmdset) self.caller.cmdset.add(editor_cmdset)
# store the original version # store the original version
self.pristine_buffer = self.buffer self.pristine_buffer = self.buffer
self.savecode = savecode self.savecode = savecode
self.sep = "-" self.sep = "-"
# undo operation buffer # undo operation buffer
@ -425,9 +425,9 @@ class LineEditor(object):
# copy buffer # copy buffer
self.copy_buffer = [] self.copy_buffer = []
# echo inserted text back to caller # echo inserted text back to caller
self.echo_mode = False self.echo_mode = False
# show the buffer ui # show the buffer ui
self.caller.msg(self.display_buffer()) self.caller.msg(self.display_buffer())
@ -435,15 +435,15 @@ class LineEditor(object):
def update_buffer(self, buf): def update_buffer(self, buf):
""" """
This should be called when the buffer has been changed somehow. This should be called when the buffer has been changed somehow.
It will handle unsaved flag and undo updating. It will handle unsaved flag and undo updating.
""" """
if utils.is_iter(buf): if utils.is_iter(buf):
buf = "\n".join(buf) buf = "\n".join(buf)
if buf != self.buffer: if buf != self.buffer:
self.buffer = buf self.buffer = buf
self.update_undo() self.update_undo()
self.unsaved = True self.unsaved = True
def quit(self): def quit(self):
"Cleanly exit the editor." "Cleanly exit the editor."
@ -456,7 +456,7 @@ class LineEditor(object):
if self.unsaved: if self.unsaved:
try: try:
exec(self.savecode) exec(self.savecode)
self.unsaved = False self.unsaved = False
return "Buffer saved." return "Buffer saved."
except Exception, e: except Exception, e:
return "%s\n{rSave code gave an error. Buffer not saved." % e return "%s\n{rSave code gave an error. Buffer not saved." % e
@ -466,30 +466,30 @@ class LineEditor(object):
def update_undo(self, step=None): def update_undo(self, step=None):
""" """
This updates the undo position. This updates the undo position.
""" """
if step and step < 0: if step and step < 0:
if self.undo_pos <= 0: if self.undo_pos <= 0:
return "Nothing to undo." return "Nothing to undo."
self.undo_pos = max(0, self.undo_pos + step) self.undo_pos = max(0, self.undo_pos + step)
self.buffer = self.undo_buffer[self.undo_pos] self.buffer = self.undo_buffer[self.undo_pos]
return "Undo." return "Undo."
elif step and step > 0: elif step and step > 0:
if self.undo_pos >= len(self.undo_buffer) - 1 or self.undo_pos + 1 >= self.undo_max: if self.undo_pos >= len(self.undo_buffer) - 1 or self.undo_pos + 1 >= self.undo_max:
return "Nothing to redo." return "Nothing to redo."
self.undo_pos = min(self.undo_pos + step, min(len(self.undo_buffer), self.undo_max) - 1) self.undo_pos = min(self.undo_pos + step, min(len(self.undo_buffer), self.undo_max) - 1)
self.buffer = self.undo_buffer[self.undo_pos] self.buffer = self.undo_buffer[self.undo_pos]
return "Redo." return "Redo."
if not self.undo_buffer or (self.undo_buffer and self.buffer != self.undo_buffer[self.undo_pos]): if not self.undo_buffer or (self.undo_buffer and self.buffer != self.undo_buffer[self.undo_pos]):
self.undo_buffer = self.undo_buffer[:self.undo_pos + 1] + [self.buffer] self.undo_buffer = self.undo_buffer[:self.undo_pos + 1] + [self.buffer]
self.undo_pos = len(self.undo_buffer) - 1 self.undo_pos = len(self.undo_buffer) - 1
def display_buffer(self, buf=None, offset=0, linenums=True): def display_buffer(self, buf=None, offset=0, linenums=True):
""" """
This displays the line editor buffer, or selected parts of it. This displays the line editor buffer, or selected parts of it.
If buf is set and is not the full buffer, offset should define If buf is set and is not the full buffer, offset should define
the starting line number, to get the linenum display right. the starting line number, to get the linenum display right.
""" """
if buf == None: if buf == None:
buf = self.buffer buf = self.buffer
@ -504,32 +504,32 @@ class LineEditor(object):
sep = self.sep sep = self.sep
header = "{n" + sep * 10 + "Line Editor [%s]" % self.key + sep * (78-25-len(self.key)) header = "{n" + sep * 10 + "Line Editor [%s]" % self.key + sep * (78-25-len(self.key))
footer = "{n" + sep * 10 + "[l:%02i w:%03i c:%04i]" % (nlines, nwords, nchars) + sep * 12 + "(:h for help)" + sep * 23 footer = "{n" + sep * 10 + "[l:%02i w:%03i c:%04i]" % (nlines, nwords, nchars) + sep * 12 + "(:h for help)" + sep * 23
if linenums: if linenums:
main = "\n".join("{b%02i|{n %s" % (iline + 1 + offset, line) for iline, line in enumerate(lines)) main = "\n".join("{b%02i|{n %s" % (iline + 1 + offset, line) for iline, line in enumerate(lines))
else: else:
main = "\n".join(lines) main = "\n".join(lines)
string = "%s\n%s\n%s" % (header, main, footer) string = "%s\n%s\n%s" % (header, main, footer)
return string return string
def display_help(self): def display_help(self):
""" """
Shows the help entry for the editor. Shows the help entry for the editor.
""" """
string = self.sep*78 + """ string = self.sep*78 + """
<txt> - any non-command is appended to the end of the buffer. <txt> - any non-command is appended to the end of the buffer.
: <l> - view buffer or only line <l> : <l> - view buffer or only line <l>
:: <l> - view buffer without line numbers or other parsing :: <l> - view buffer without line numbers or other parsing
::: - print a ':' as the only character on the line... ::: - print a ':' as the only character on the line...
:h - this help. :h - this help.
:w - saves the buffer (don't quit) :w - saves the buffer (don't quit)
:wq - save buffer and quit :wq - save buffer and quit
:q - quits (will be asked to save if buffer was changed) :q - quits (will be asked to save if buffer was changed)
:q! - quit without saving, no questions asked :q! - quit without saving, no questions asked
:u - (undo) step backwards in undo history :u - (undo) step backwards in undo history
:uu - (redo) step forward in undo history :uu - (redo) step forward in undo history
:UU - reset all changes back to initial :UU - reset all changes back to initial
:dd <l> - delete line <n> :dd <l> - delete line <n>
:dw <l> <w> - delete word or regex <w> in entire buffer or on line <l> :dw <l> <w> - delete word or regex <w> in entire buffer or on line <l>
@ -539,7 +539,7 @@ class LineEditor(object):
:x <l> - cut line <l> and store it in the copy buffer :x <l> - cut line <l> and store it in the copy buffer
:p <l> - put (paste) previously copied line directly after <l> :p <l> - put (paste) previously copied line directly after <l>
:i <l> <txt> - insert new text <txt> at line <l>. Old line will be shifted down :i <l> <txt> - insert new text <txt> at line <l>. Old line will be shifted down
:r <l> <txt> - replace line <l> with text <txt> :r <l> <txt> - replace line <l> with text <txt>
:I <l> <txt> - insert text at the beginning of line <l> :I <l> <txt> - insert text at the beginning of line <l>
:A <l> <txt> - append text after the end of line <l> :A <l> <txt> - append text after the end of line <l>
@ -547,17 +547,17 @@ class LineEditor(object):
:f <l> - flood-fill entire buffer or line <l> :f <l> - flood-fill entire buffer or line <l>
:fi <l> - indent entire buffer or line <l> :fi <l> - indent entire buffer or line <l>
:fd <l> - de-indent entire buffer or line <l> :fd <l> - de-indent entire buffer or line <l>
:echo - turn echoing of the input on/off (helpful for some clients) :echo - turn echoing of the input on/off (helpful for some clients)
Legend: Legend:
<l> - line numbers, or range lstart:lend, e.g. '3:7'. <l> - line numbers, or range lstart:lend, e.g. '3:7'.
<w> - one word or several enclosed in quotes. <w> - one word or several enclosed in quotes.
<txt> - longer string, usually not needed to be enclosed in quotes. <txt> - longer string, usually not needed to be enclosed in quotes.
""" + self.sep * 78 """ + self.sep * 78
return string return string
@ -566,15 +566,15 @@ class LineEditor(object):
# #
class CmdEditor(Command): class CmdEditor(Command):
""" """
start editor start editor
Usage: Usage:
@editor <obj>/<attr> @editor <obj>/<attr>
This will start Evennia's powerful line editor, which This will start Evennia's powerful line editor, which
has a host of commands on its own. Use :h for a list has a host of commands on its own. Use :h for a list
of commands. of commands.
""" """
@ -588,23 +588,23 @@ class CmdEditor(Command):
if not self.args or not '/' in self.args: if not self.args or not '/' in self.args:
self.caller.msg("Usage: @editor <obj>/<attrname>") self.caller.msg("Usage: @editor <obj>/<attrname>")
return return
objname, attrname = [part.strip() for part in self.args.split("/")] objname, attrname = [part.strip() for part in self.args.split("/")]
obj = self.caller.search(objname) obj = self.caller.search(objname)
if not obj: if not obj:
return return
# the load/save codes define what the editor shall do when wanting to # the load/save codes define what the editor shall do when wanting to
# save the result of the editing. The editor makes self.buffer and # save the result of the editing. The editor makes self.buffer and
# self.caller available for this code - self.buffer holds the editable text. # self.caller available for this code - self.buffer holds the editable text.
loadcode = "obj = self.caller.search('%s')\n" % obj.id loadcode = "obj = self.caller.search('%s')\n" % obj.id
loadcode += "if obj.db.%s: self.buffer = obj.db.%s" % (attrname, attrname) loadcode += "if obj.db.%s: self.buffer = obj.db.%s" % (attrname, attrname)
savecode = "obj = self.caller.search('%s')\n" % obj.id savecode = "obj = self.caller.search('%s')\n" % obj.id
savecode += "obj.db.%s = self.buffer" % attrname savecode += "obj.db.%s = self.buffer" % attrname
editor_key = "%s/%s" % (objname, attrname) editor_key = "%s/%s" % (objname, attrname)
# start editor, it will handle things from here. # start editor, it will handle things from here.
LineEditor(self.caller, loadcode=loadcode, savecode=savecode, key=editor_key) LineEditor(self.caller, loadcode=loadcode, savecode=savecode, key=editor_key)

View file

@ -1,17 +1,17 @@
""" """
Evennia Talkative NPC Evennia Talkative NPC
Contribution - Griatch 2011 Contribution - Griatch 2011
This is a simple NPC object capable of holding a This is a simple NPC object capable of holding a
simple menu-driven conversation. Create it by simple menu-driven conversation. Create it by
creating an object of typeclass contrib.talking_npc.TalkingNPC, creating an object of typeclass contrib.talking_npc.TalkingNPC,
For example using @create: For example using @create:
@create John : contrib.talking_npc.TalkingNPC @create John : contrib.talking_npc.TalkingNPC
Walk up to it and give the talk command Walk up to it and give the talk command
to strike up a conversation. If there are many to strike up a conversation. If there are many
talkative npcs in the same room you will get to talkative npcs in the same room you will get to
choose which one's talk command to call (Evennia choose which one's talk command to call (Evennia
@ -19,18 +19,18 @@ handles this automatically).
Note that this is only a prototype class, showcasing Note that this is only a prototype class, showcasing
the uses of the menusystem module. It is NOT a full the uses of the menusystem module. It is NOT a full
mob implementation. mob implementation.
""" """
from contrib import menusystem from contrib import menusystem
from game.gamesrc.objects.baseobjects import Object from game.gamesrc.objects.baseobjects import Object
from game.gamesrc.commands.basecmdset import CmdSet from game.gamesrc.commands.basecmdset import CmdSet
from game.gamesrc.commands.basecommand import MuxCommand from game.gamesrc.commands.basecommand import MuxCommand
# #
# The talk command # The talk command
# #
class CmdTalk(MuxCommand): class CmdTalk(MuxCommand):
@ -42,32 +42,32 @@ class CmdTalk(MuxCommand):
This command is only available if a talkative non-player-character (NPC) This command is only available if a talkative non-player-character (NPC)
is actually present. It will strike up a conversation with that NPC is actually present. It will strike up a conversation with that NPC
and give you options on what to talk about. and give you options on what to talk about.
""" """
key = "talk" key = "talk"
locks = "cmd:all()" locks = "cmd:all()"
help_category = "General" help_category = "General"
def func(self): def func(self):
"Implements the command." "Implements the command."
# self.obj is the NPC this is defined on # self.obj is the NPC this is defined on
obj = self.obj obj = self.obj
self.caller.msg("(You walk up and talk to %s.)" % self.obj.key) self.caller.msg("(You walk up and talk to %s.)" % self.obj.key)
# conversation is a dictionary of keys, each pointing to a dictionary defining # conversation is a dictionary of keys, each pointing to a dictionary defining
# the keyword arguments to the MenuNode constructor. # the keyword arguments to the MenuNode constructor.
conversation = obj.db.conversation conversation = obj.db.conversation
if not conversation: if not conversation:
self.caller.msg("%s says: 'Sorry, I don't have time to talk right now.'" % (self.obj.key)) self.caller.msg("%s says: 'Sorry, I don't have time to talk right now.'" % (self.obj.key))
return return
# build all nodes by loading them from the conversation tree. # build all nodes by loading them from the conversation tree.
menu = menusystem.MenuTree(self.caller) menu = menusystem.MenuTree(self.caller)
for key, kwargs in conversation.items(): for key, kwargs in conversation.items():
menu.add(menusystem.MenuNode(key, **kwargs)) menu.add(menusystem.MenuNode(key, **kwargs))
menu.start() menu.start()
class TalkingCmdSet(CmdSet): class TalkingCmdSet(CmdSet):
"Stores the talk command." "Stores the talk command."
@ -102,22 +102,22 @@ CONV = {"START":{"text": "Hello there, how can I help you?",
"code":None}, "code":None},
"info3":{"text":"Well ... I'm sort of busy so, have to go. NPC business. Important stuff. You wouldn't understand.", "info3":{"text":"Well ... I'm sort of busy so, have to go. NPC business. Important stuff. You wouldn't understand.",
"links":["END", "info2"], "links":["END", "info2"],
"linktexts":["Oookay ... I won't keep you. Bye.", "linktexts":["Oookay ... I won't keep you. Bye.",
"Wait, why don't you tell me your name first?"], "Wait, why don't you tell me your name first?"],
"keywords":None, "keywords":None,
"code":None}, "code":None},
} }
class TalkingNPC(Object): class TalkingNPC(Object):
""" """
This implements a simple Object using the talk command and using the This implements a simple Object using the talk command and using the
conversation defined above. . conversation defined above. .
""" """
def at_object_creation(self): def at_object_creation(self):
"This is called when object is first created." "This is called when object is first created."
# store the conversation. # store the conversation.
self.db.conversation = CONV self.db.conversation = CONV
self.db.desc = "This is a talkative NPC." self.db.desc = "This is a talkative NPC."
# assign the talk command to npc # assign the talk command to npc
self.cmdset.add_default(TalkingCmdSet, permanent=True) self.cmdset.add_default(TalkingCmdSet, permanent=True)