Added some changes to revision conttrol.

This commit is contained in:
Griatch 2009-08-28 19:07:25 +00:00
parent e39537dc04
commit 72ec7377b9
2 changed files with 600 additions and 0 deletions

View file

@ -0,0 +1,389 @@
"""
This is an example in-game line editor. It uses the state system of Evennia (see
gamesrc/examples/state_example.py).
Usage:
@edit object=attributename
The editor is invoked on an object's attribute and allows some more editing
facilities over just writing everything in one go. Check the help for more info.
If you choose to edit atribute-lists instead of simple strings, the editor adapts
by switching to line-mode.
"""
from src.cmdtable import GLOBAL_CMD_TABLE
from src.statetable import GLOBAL_STATE_TABLE
from src.objects.models import Object, Attribute
import src.defines_global
STATENAME = 'line_editor'
#editor variables and settings
BUF = '_EDITOR_EDITORBUF'
LINEMODE = '_EDITOR_LINEMODE'
NOUPDATE = '_EDITOR_NOUPDATE'
EDIT_ATTR = '_EDITOR_EDIT_ATTR'
def cmd_edit(command):
"""
Edit an attribute using the editor.
Usage:
@edit[/switches] [object=]attribute
switches:
clear - if the attribute already had a value, clear it before
entering the editor.
line - work and save in line mode
noup - only updates the buffer when explicitly
listing it (avoid large screen-redraws if there's
a lot of text)
If no object is given, attribute is assumed to be defined on the
caller.
The editor supports modifying, replacing and inserting text into an attribute
in various ways, as well as cancelling your changes.
Technically, the 'line' mode of the editor works and saves lines in a list-attribute.
This mode supports more formatting operations than just working on a string. When
working on a normal string (string mode) the editor has no concept of lines,
but new text is added and inserted into the string.
See the help text in the editor for more information.
"""
source_object = command.source_object
args = command.command_argument
switches = command.command_switches
if not args:
source_object.emit_to("You must specify an attribute to @edit.")
return
args = args.strip()
if '=' not in args:
args = "me=" + args
objname, attr = args.split('=',1)
obj = validate_obj(source_object, objname, attr)
if not obj:
return
source_object.set_attribute(LINEMODE, 'line' in switches)
if not 'clear' in switches:
curr_value = obj.get_attribute_value(attr.strip())
if type(curr_value) == type(list()):
source_object.set_attribute(LINEMODE,True)
source_object.set_attribute(BUF, curr_value)
source_object.set_attribute(NOUPDATE, 'noup' in switches)
#setup the editor temporary attributes
source_object.set_attribute(EDIT_ATTR,args)
#enter edit state
source_object.set_state(STATENAME)
source_object.execute_cmd('list')
def cmd_list(command):
"""
list the buffer
"""
source_object = command.source_object
buf = source_object.get_attribute_value(BUF)
linemode = source_object.get_attribute_value(LINEMODE)
header = "%s-----------------------------------------%s\n\r" % ('%cy', '%cn')
attr = source_object.get_attribute_value(EDIT_ATTR)
if linemode:
footer = "\n\r%s@edit mode (line) (%s%s%s) (h for help)" % ('%cy','%ch',attr,'%cn%cy')
else:
footer = "\n\r%s@edit mode (str) (%s%s%s) (h for help)" % ('%cy','%ch',attr,'%cn%cy')
if buf:
if type(buf)==type(list()):
s = ""
for i, line in enumerate(buf):
s += "%s%2i|%s %s\n\r" % ('%ch%cw', i+1, '%cn', line)
s = header + s[:-2] + footer
else:
if linemode:
s = "%s%2i|%s %s\n\r" % ('%ch%cw', 1, '%cn', buf)
s = header + s + footer
else:
s = header + buf + footer
else:
s = header + footer
source_object.emit_to(s)
def cmd_append(command):
"""
Append text to buffer.
"""
source_object = command.source_object
args = command.command_argument
buf = source_object.get_attribute_value(BUF)
if not args:
args = " "
if source_object.get_attribute_value(LINEMODE):
if not buf:
buf = [args]
else:
if type(buf) != type(list()):
buf = [buf]
buf.extend([args])
else:
if not buf:
buf = ""
elif buf[-1] in '.,;:':
buf += ' '
buf += args
source_object.set_attribute(BUF, buf)
if not source_object.get_attribute_value(NOUPDATE):
cmd_list(command)
def cmd_insert(command):
"""
Insert new line before given line
"""
source_object = command.source_object
args = command.command_argument
buf = source_object.get_attribute_value(BUF)
if source_object.get_attribute_value(LINEMODE):
if args:
args = args.split(" ",1)
if len(args)>1:
linenum, text = args[0],args[1]
else:
source_object.emit_to("Usage: .i # <text>")
return
try:
buf.insert(int(linenum)-1, text)
except:
source_object.emit_to("%s'%s' is not a valid line number." % ('%cr',linenum))
return
source_object.set_attribute(BUF, buf)
if not source_object.get_attribute_value(NOUPDATE):
cmd_list(command)
else:
source_object.emit_to("%s.i only works in line mode" % '%cr')
def cmd_clear(command):
"""
clears the buffer
"""
source_object = command.source_object
args = command.command_argument
buf = source_object.get_attribute_value(BUF)
if source_object.get_attribute_value(LINEMODE):
if args:
try:
del buf[int(args)-1]
source_object.set_attribute(BUF,buf)
except:
source_object.emit_to("%sCould not clear line '%s'" % ('%cr',args))
else:
source_object.set_attribute(BUF,[])
else:
source_object.set_attribute(BUF,"")
if not source_object.get_attribute_value(NOUPDATE):
cmd_list(command)
def cmd_replace(command):
"""
replace all occurences of a text.
"""
source_object = command.source_object
buf = source_object.get_attribute_value(BUF)
if not buf:
return
args = command.command_argument
if not args:
source_object.emit_to("Usage: .r old or .r old=new")
return
if source_object.get_attribute_value(LINEMODE):
if args[0].isdigit():
num, args = args.split(" ",1)
if '=' in args:
old, new = args.split('=')
old, new = old, new
else:
old = args
new = ""
try:
buf[int(num)-1] = buf[int(num)-1].replace(old, new)
except:
source_object.emit_to("%s%s is not a valid line number." % ('%cr',num))
return
else:
if '=' in args:
old, new = args.split('=')
old, new = old, new
else:
old = args
new = ""
newbuf = []
for line in buf:
newbuf.append(line.replace(old,new))
buf = newbuf
else:
if '=' in args:
old, new = args.split('=')
old, new = old, new
else:
old = args
new = ""
buf = buf.replace(old, new)
source_object.set_attribute(BUF, buf)
if not source_object.get_attribute_value(NOUPDATE):
cmd_list(command)
def cmd_save(command):
source_object = command.source_object
buf = source_object.get_attribute_value(BUF)
if not buf: buf = ""
attr = source_object.get_attribute_value(EDIT_ATTR)
objname, attr = attr.split('=',1)
obj = validate_obj(source_object, objname, attr)
if not obj:
cmd_exit(command)
else:
obj.set_attribute(attr, buf)
source_object.emit_to("%s%s=%s saved." % ('%cg',objname,attr))
def cmd_save_exit(command):
cmd_save(command)
util_exit(command)
def cmd_exit(command):
"exits without saving."
source_object = command.source_object
attr = source_object.get_attribute_value(EDIT_ATTR)
source_object.emit_to('%s%s not saved/changed.' % ('%cr', attr))
util_exit(command)
def util_exit(command):
"cleans up and exits"
source_object = command.source_object
source_object.clear_attribute(BUF)
source_object.clear_attribute(LINEMODE)
source_object.clear_attribute(NOUPDATE)
source_object.clear_attribute(EDIT_ATTR)
source_object.clear_state()
source_object.execute_cmd('look')
def cmd_help(command):
"""
A custom help screen.
"""
source_object = command.source_object
buf = source_object.get_attribute_value(BUF)
if source_object.get_attribute_value(LINEMODE):
s = \
"""
%sEditor commands:
. <text> - enter text into the buffer
.i # <text> - insert new line before line #
.c - clear buffer
.c # - clear line #
.r <words> - remove all matching <words>
.r <old>=<new> - replace all <old> with <new>
.r # <new> - replace line # with <new>
.r # <old>=<new> - replace <old> with <new> on line #
.s - save buffer
.xs, .sx - save and exit
.x, .q - exit without saving
.l, l, list - list buffer
.h, h, help - this help
"""
else:
s = \
"""
%sEditor commands:
. <text> - enter text into the buffer
.c - clear buffer
.r <words> - remove all matching <words>
.r <old>=<new> - replace all <old> with <new>
.s - save buffer
.xs, .sx - save and exit
.x, .q - exit without saving
.l, l, list - list buffer
.h, h, help - this help
"""
source_object.emit_to(s % '%cy')
#
# Helper function
#
def validate_obj(source_object, objname, attr):
"Helper function"
#test that object exists.
results = Object.objects.local_and_global_search(source_object, objname)
if not results:
source_object.emit_to("No name matches found for %s." % (objname,))
return None
if len(results) > 1:
source_object.emit_to("Multiple name matches for: %s" % (objname,))
s = ""
for result in results:
s += " %s\n\r" % (result.get_name(fullname=False),)
s += "%d matches returned." % (len(results),)
source_object.emit_to(s)
return None
obj = results[0]
#permission checks
if not source_object.controls_other(obj):
source_object.emit_to(defines_global.NOCONTROL_MSG)
return None
if not Attribute.objects.is_modifiable_attrib(attr):
source_object.emit_to("You can't modify that attribute.")
return None
return obj
#editor entry command
GLOBAL_CMD_TABLE.add_command("@edit", cmd_edit, auto_help=True)
#create the state
GLOBAL_STATE_TABLE.add_state(STATENAME)
#editor commands
GLOBAL_STATE_TABLE.add_command(STATENAME, ".", cmd_append)
GLOBAL_STATE_TABLE.add_command(STATENAME, ".i", cmd_insert)
GLOBAL_STATE_TABLE.add_command(STATENAME, ".r", cmd_replace)
GLOBAL_STATE_TABLE.add_command(STATENAME, ".c", cmd_clear)
GLOBAL_STATE_TABLE.add_command(STATENAME, ".s", cmd_save)
GLOBAL_STATE_TABLE.add_command(STATENAME, ".xs", cmd_save_exit)
GLOBAL_STATE_TABLE.add_command(STATENAME, ".sx", cmd_save_exit)
GLOBAL_STATE_TABLE.add_command(STATENAME, ".x", cmd_exit)
GLOBAL_STATE_TABLE.add_command(STATENAME, ".q", cmd_exit)
GLOBAL_STATE_TABLE.add_command(STATENAME, ".l", cmd_list)
GLOBAL_STATE_TABLE.add_command(STATENAME, "l", cmd_list)
GLOBAL_STATE_TABLE.add_command(STATENAME, "list", cmd_list)
GLOBAL_STATE_TABLE.add_command(STATENAME, ".h", cmd_help)
GLOBAL_STATE_TABLE.add_command(STATENAME, "h", cmd_help)
GLOBAL_STATE_TABLE.add_command(STATENAME, "help", cmd_help)

View file

@ -0,0 +1,211 @@
"""
A more sophisticated nested menu module. This could easily be adapted for anything
from character creation to npc quest dialogues.
Default functionality:
- Multiple-choice options, numbered 1-10
- Any level of option nesting and structure
- Run arbitrary command in each menu node (character attributes, anybody?)
- Menu history; allows you to step back all the way to the beginning.
- Exit function
Note that this makes full use of expanded attributes, by saving a list of objects
in a temporary attribute. So if you haven't updated/reinitialized the database
after revision 626 you should do that or this menu will not work.
This can be used as a template for any menu. Copy this to a new module (activate in
settings.py if necessary), then change STATENAME and adjust the cmd_update() to look
the way you want. Decide if you want back-stepping functionality and be able to
exit the menu at any time (deactivate those commands if so). Finally define the menu
itself by interconnecting Node objects.
"""
from src.cmdtable import GLOBAL_CMD_TABLE
from src.statetable import GLOBAL_STATE_TABLE
STATENAME = 'nestedmenu'
#temporary attribute
NODELIST = '_menu_node_history'
#
# Defining the menu tree
#
class Node(object):
"""
This holds one single point in the menu tree.
"""
def __init__(self,header, text="", func=None):
self.header = header
self.text = text
self.func = func
self.choices = []
#
# functions to be run at particular nodes
#
def node_func(command):
"function to be called at a node"
source_object = command.source_object
source_object.emit_to("This is the node function being called!")
def endmenu(command):
"Exit the menu."
cmd_exit_menu(command)
#
# The menu tree
#
#available nodes
START = Node("Start menu", text="Welcome to the menu.")
secondnode = Node("Second menu")
thirdnode = Node("Third menu")
fourthnode = Node("Fourth menu", text="This is an extra text.")
fifthnode = Node("Fifth menu", func=node_func)
endnode = Node("Endpoint", text="Goodbye.", func=endmenu)
#linking the nodes together
START.choices = [secondnode,thirdnode]
secondnode.choices = [fourthnode, fifthnode]
thirdnode.choices = [secondnode, fifthnode]
fourthnode.choices = [fifthnode, thirdnode]
fifthnode.choices = [START, endnode]
#
# Menu mechanics
#
# Menu entry command
def cmd_entermenu(command):
"entry command"
source_object = command.source_object
source_object.set_state(STATENAME)
#assumes a node START has been defined as the initial one.
source_object.set_attribute(NODELIST, [START])
cmd_update(command)
def cmd_update(command):
"""Runs the current node in the tree and displays
its contents."""
source_object = command.source_object
node = source_object.get_attribute_value(NODELIST)[-1]
s = "\n\r%s%s\n\r%s" % ('%ch%cw',node.header,'%cn')
if node.text:
s += node.text + '\n\r'
if node.choices:
for i,ch in enumerate(node.choices):
s += " %s%i %s%s\n\r" % ('%ch%cw', i+1, '%cn%cy', ch.header)
s += " (back)"
source_object.emit_to(s)
if callable(node.func):
node.func(command)
def cmd_exit_menu(command):
"helper command"
source_object = command.source_object
source_object.clear_attribute(NODELIST)
source_object.clear_state()
source_object.execute_cmd('look')
def cmd_prev(command):
source_object = command.source_object
prevlist = source_object.get_attribute_value(NODELIST)
exiting = False
try:
prevlist.pop()
if not prevlist: exiting = True
except IndexError:
exiting = True
if exiting:
cmd_exit_menu(command)
return
source_object.set_attribute(NODELIST,prevlist)
cmd_update(command)
def cmd_help(command):
source_object = command.source_object
s = \
"""
%sMenu help
%s1-10 - Select an option
l,look - redraw the menu
b,back - back to previous
exit - leave menu""" % ('%ch%cw', '%cn%cy')
source_object.emit_to(s)
def option(function):
"Option Decorator"
def retfunc(command):
val = function()
source_object = command.source_object
nodelist = source_object.get_attribute_value(NODELIST)
choices = nodelist[-1].choices
try:
choicenode = choices[val-1]
except IndexError:
source_object.emit_to("Not a valid option.")
return
nodelist.append(choicenode)
source_object.set_attribute(NODELIST, nodelist)
cmd_update(command)
return retfunc
@option
def cmd_option1():
return 1
@option
def cmd_option2():
return 2
@option
def cmd_option3():
return 3
@option
def cmd_option4():
return 4
@option
def cmd_option5():
return 5
@option
def cmd_option6():
return 6
@option
def cmd_option7():
return 7
@option
def cmd_option8():
return 8
@option
def cmd_option9():
return 9
@option
def cmd_option10():
return 10
#entry command
GLOBAL_CMD_TABLE.add_command("enter_nested", cmd_entermenu)
#create the state
GLOBAL_STATE_TABLE.add_state(STATENAME)
#menu commands
GLOBAL_STATE_TABLE.add_command(STATENAME, '1', cmd_option1)
GLOBAL_STATE_TABLE.add_command(STATENAME, '2', cmd_option2)
GLOBAL_STATE_TABLE.add_command(STATENAME, '3', cmd_option3)
GLOBAL_STATE_TABLE.add_command(STATENAME, '4', cmd_option4)
GLOBAL_STATE_TABLE.add_command(STATENAME, '5', cmd_option5)
GLOBAL_STATE_TABLE.add_command(STATENAME, '6', cmd_option6)
GLOBAL_STATE_TABLE.add_command(STATENAME, '7', cmd_option7)
GLOBAL_STATE_TABLE.add_command(STATENAME, '8', cmd_option8)
GLOBAL_STATE_TABLE.add_command(STATENAME, '9', cmd_option9)
GLOBAL_STATE_TABLE.add_command(STATENAME, '10',cmd_option10)
GLOBAL_STATE_TABLE.add_command(STATENAME, 'l', cmd_update)
GLOBAL_STATE_TABLE.add_command(STATENAME, 'look', cmd_update)
GLOBAL_STATE_TABLE.add_command(STATENAME, 'h', cmd_help)
GLOBAL_STATE_TABLE.add_command(STATENAME, 'help', cmd_help)
GLOBAL_STATE_TABLE.add_command(STATENAME, 'b', cmd_prev)
GLOBAL_STATE_TABLE.add_command(STATENAME, 'back', cmd_prev)
GLOBAL_STATE_TABLE.add_command(STATENAME, 'exit', cmd_exit_menu)