Further refinement of the rpsystem contrib, making a more reasonable division of typeclass functionality
This commit is contained in:
parent
4ab6414ffa
commit
45371289f4
2 changed files with 123 additions and 59 deletions
|
|
@ -58,8 +58,8 @@ import re
|
||||||
from re import match as re_match
|
from re import match as re_match
|
||||||
import itertools
|
import itertools
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from evennia import DefaultObject, DefaultCharacter
|
from evennia import DefaultObject, DefaultCharacter, DefaultRoom
|
||||||
from evennia import Command
|
from evennia import Command, CmdSet
|
||||||
from evennia import ansi
|
from evennia import ansi
|
||||||
from evennia.utils.utils import lazy_property
|
from evennia.utils.utils import lazy_property
|
||||||
|
|
||||||
|
|
@ -142,9 +142,11 @@ class EmoteError(Exception):
|
||||||
class SdescError(Exception):
|
class SdescError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class RecogError(Exception):
|
class RecogError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class LanguageError(Exception):
|
class LanguageError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -240,7 +242,6 @@ def parse_language(speaker, emote):
|
||||||
# in-place without messing up indexes for future matches
|
# in-place without messing up indexes for future matches
|
||||||
# note that saytext includes surrounding "...".
|
# note that saytext includes surrounding "...".
|
||||||
langname, saytext = say_match.groups()
|
langname, saytext = say_match.groups()
|
||||||
print "language:", langname, saytext
|
|
||||||
if not _LANGUAGE_AVAILABLE(langname):
|
if not _LANGUAGE_AVAILABLE(langname):
|
||||||
errors.append(_LANGUAGE_NOMATCH_ERROR.format(langname=langname))
|
errors.append(_LANGUAGE_NOMATCH_ERROR.format(langname=langname))
|
||||||
continue
|
continue
|
||||||
|
|
@ -326,19 +327,16 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False):
|
||||||
|
|
||||||
# first see if there is a number given (e.g. 1-tall)
|
# first see if there is a number given (e.g. 1-tall)
|
||||||
num_identifier, _ = marker_match.groups("") # return "" if no match, rather than None
|
num_identifier, _ = marker_match.groups("") # return "" if no match, rather than None
|
||||||
print "num_identifier", num_identifier
|
|
||||||
istart0 = marker_match.start()
|
istart0 = marker_match.start()
|
||||||
# +1 for _NUM_SEP, if defined
|
# +1 for _NUM_SEP, if defined
|
||||||
istart = istart0 #+ (len(num_identifier) + 1 if num_identifier else 0)
|
istart = istart0 #+ (len(num_identifier) + 1 if num_identifier else 0)
|
||||||
|
|
||||||
print "marker match:", marker_match.group(), istart0, istart, string[istart:]
|
|
||||||
#print "candidates:", [tup[2] for tup in candidate_regexes]
|
#print "candidates:", [tup[2] for tup in candidate_regexes]
|
||||||
# loop over all candidate regexes and match against the string following the match
|
# loop over all candidate regexes and match against the string following the match
|
||||||
matches = ((reg.match(string[istart:]), obj, text) for reg, obj, text in candidate_regexes)
|
matches = ((reg.match(string[istart:]), obj, text) for reg, obj, text in candidate_regexes)
|
||||||
|
|
||||||
# score matches by how long part of the string was matched
|
# score matches by how long part of the string was matched
|
||||||
matches = [(match.end() if match else -1, obj, text) for match, obj, text in matches]
|
matches = [(match.end() if match else -1, obj, text) for match, obj, text in matches]
|
||||||
print "matches:", istart, matches
|
|
||||||
maxscore = max(score for score, obj, text in matches)
|
maxscore = max(score for score, obj, text in matches)
|
||||||
|
|
||||||
# we have a valid maxscore, extract all matches with this value
|
# we have a valid maxscore, extract all matches with this value
|
||||||
|
|
@ -428,8 +426,6 @@ def receive_emote(sender, receiver, emote, sdesc_mapping, language_mapping):
|
||||||
# we make a local copy that we can modify
|
# we make a local copy that we can modify
|
||||||
mapping = copy(sdesc_mapping)
|
mapping = copy(sdesc_mapping)
|
||||||
# overload mapping with receiver's recogs (which is on the same form)
|
# overload mapping with receiver's recogs (which is on the same form)
|
||||||
print "receiver.db.recog_refmap:", receiver, receiver.db.recog_refmap
|
|
||||||
print "mapping:", mapping
|
|
||||||
try:
|
try:
|
||||||
mapping.update(receiver.recog.ref2recog)
|
mapping.update(receiver.recog.ref2recog)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
|
@ -464,7 +460,6 @@ def send_emote(sender, receivers, emote, no_anonymous=True):
|
||||||
if so.
|
if so.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
print "receivers:", receivers
|
|
||||||
try:
|
try:
|
||||||
emote, sdesc_mapping = parse_sdescs_and_recogs(sender, receivers, emote)
|
emote, sdesc_mapping = parse_sdescs_and_recogs(sender, receivers, emote)
|
||||||
emote, language_mapping = parse_language(sender, emote)
|
emote, language_mapping = parse_language(sender, emote)
|
||||||
|
|
@ -527,8 +522,11 @@ class CmdEmote(RPCommand): # replaces the main emote
|
||||||
self.caller.msg("What do you want to do?")
|
self.caller.msg("What do you want to do?")
|
||||||
else:
|
else:
|
||||||
# we also include ourselves here.
|
# we also include ourselves here.
|
||||||
|
emote = self.args
|
||||||
targets = self.caller.location.contents
|
targets = self.caller.location.contents
|
||||||
send_emote(self.caller, targets, self.args, no_anonymous=True)
|
if not emote.endswith("."):
|
||||||
|
emote = "%s." % emote
|
||||||
|
send_emote(self.caller, targets, emote, no_anonymous=True)
|
||||||
|
|
||||||
|
|
||||||
class CmdSdesc(RPCommand): # set/look at own sdesc
|
class CmdSdesc(RPCommand): # set/look at own sdesc
|
||||||
|
|
@ -562,14 +560,18 @@ class CmdPose(Command): # set current pose and default pose
|
||||||
Usage:
|
Usage:
|
||||||
pose <pose>
|
pose <pose>
|
||||||
pose default <pose>
|
pose default <pose>
|
||||||
|
pose reset
|
||||||
|
pose obj = <pose>
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
pose leans against the tree
|
pose leans against the tree
|
||||||
pose is talking to the barkeep.
|
pose is talking to the barkeep.
|
||||||
|
pose box = is sitting on the floor.
|
||||||
|
|
||||||
Set a static pose. This is the end of a full sentence that
|
Set a static pose. This is the end of a full sentence that
|
||||||
starts with your sdesc. If no full stop is given, it will
|
starts with your sdesc. If no full stop is given, it will
|
||||||
be added automatically. The default pose means
|
be added automatically. The default pose is the pose you
|
||||||
|
get when using pose reset.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
key = "pose"
|
key = "pose"
|
||||||
|
|
@ -580,8 +582,17 @@ class CmdPose(Command): # set current pose and default pose
|
||||||
"""
|
"""
|
||||||
args = self.args.strip()
|
args = self.args.strip()
|
||||||
default = args.startswith("default")
|
default = args.startswith("default")
|
||||||
|
reset = args.startswith("reset")
|
||||||
if default:
|
if default:
|
||||||
args = args.strip("default ")
|
args = re.sub(r"^default", "", args)
|
||||||
|
if reset:
|
||||||
|
args = re.sub(r"^reset", "", args)
|
||||||
|
target = None
|
||||||
|
if "=" in args:
|
||||||
|
target, args = [part.strip() for part in args.split("=", 1)]
|
||||||
|
|
||||||
|
self.target = target
|
||||||
|
self.reset = reset
|
||||||
self.default = default
|
self.default = default
|
||||||
self.args = args.strip()
|
self.args = args.strip()
|
||||||
|
|
||||||
|
|
@ -589,16 +600,40 @@ class CmdPose(Command): # set current pose and default pose
|
||||||
"Create the pose"
|
"Create the pose"
|
||||||
caller = self.caller
|
caller = self.caller
|
||||||
pose = self.args
|
pose = self.args
|
||||||
if not pose:
|
target = self.target
|
||||||
caller.msg("Usage: pose <pose-text> OR pose default <pose-text>")
|
if not pose and not self.reset:
|
||||||
|
caller.msg("Usage: pose <pose-text> OR pose default <pose-text> OR pose reset")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not pose.endswith("."):
|
||||||
|
pose = "%s." % pose
|
||||||
|
if target:
|
||||||
|
# affect something else
|
||||||
|
target = caller.search(target)
|
||||||
|
if not target:
|
||||||
|
return
|
||||||
|
if not target.access(caller, "edit"):
|
||||||
|
caller.msg("You can't pose that.")
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
if not pose.endswith("."):
|
target = caller
|
||||||
pose = "%s." % pose
|
|
||||||
if self.default:
|
if not target.attributes.has("pose"):
|
||||||
caller.db.pose_default = pose
|
caller.msg("%s cannot be posed." % target.key)
|
||||||
else:
|
return
|
||||||
caller.db.pose = pose
|
|
||||||
caller.msg("Your pose is now '%s %s'." % pose)
|
target_name = target.sdesc.get() if hasattr(target, "sdesc") else target.key
|
||||||
|
# set the pose
|
||||||
|
if self.reset:
|
||||||
|
pose = target.db.pose_default
|
||||||
|
target.db.pose = pose
|
||||||
|
elif self.default:
|
||||||
|
target.db.pose_default = pose
|
||||||
|
caller.msg("Default pose is now '%s %s'." % (target_name, pose))
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
caller.db.pose = pose
|
||||||
|
caller.msg("Pose will read '%s %s'." % (target_name, pose))
|
||||||
|
|
||||||
|
|
||||||
class CmdRecog(Command): # assign personal alias to object in room
|
class CmdRecog(Command): # assign personal alias to object in room
|
||||||
|
|
@ -668,7 +703,21 @@ class CmdLanguage(Command): # list available languages
|
||||||
self.caller.msg("Languages available: %s" % ", ".join(_LANGUAGE_LIST))
|
self.caller.msg("Languages available: %s" % ", ".join(_LANGUAGE_LIST))
|
||||||
|
|
||||||
|
|
||||||
# Handlers
|
class RPSystemCmdSet(CmdSet):
|
||||||
|
"""
|
||||||
|
Mix-in for adding rp-commands to default cmdset.
|
||||||
|
"""
|
||||||
|
def at_cmdset_creation(self):
|
||||||
|
self.add(CmdEmote())
|
||||||
|
self.add(CmdSdesc())
|
||||||
|
self.add(CmdPose())
|
||||||
|
self.add(CmdRecog())
|
||||||
|
self.add(CmdLanguage())
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# Handlers for sdesc and recog
|
||||||
|
#------------------------------------------------------------
|
||||||
|
|
||||||
class SdescHandler(object):
|
class SdescHandler(object):
|
||||||
"""
|
"""
|
||||||
|
|
@ -695,8 +744,8 @@ class SdescHandler(object):
|
||||||
Cache data from storage
|
Cache data from storage
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.sdesc = self.obj.attributes.get("sdesc", default="")
|
self.sdesc = self.obj.attributes.get("_sdesc", default="")
|
||||||
sdesc_regex = self.obj.attributes.get("sdesc_regex", default="")
|
sdesc_regex = self.obj.attributes.get("_sdesc_regex", default="")
|
||||||
self.sdesc_regex = re.compile(sdesc_regex, _RE_FLAGS)
|
self.sdesc_regex = re.compile(sdesc_regex, _RE_FLAGS)
|
||||||
|
|
||||||
def add(self, sdesc, max_length=60):
|
def add(self, sdesc, max_length=60):
|
||||||
|
|
@ -730,8 +779,8 @@ class SdescHandler(object):
|
||||||
|
|
||||||
# store to attributes
|
# store to attributes
|
||||||
sdesc_regex = ordered_permutation_regex(cleaned_sdesc)
|
sdesc_regex = ordered_permutation_regex(cleaned_sdesc)
|
||||||
self.obj.attributes.add("sdesc", sdesc)
|
self.obj.attributes.add("_sdesc", sdesc)
|
||||||
self.obj.attributes.add("sdesc_regex", sdesc_regex)
|
self.obj.attributes.add("_sdesc_regex", sdesc_regex)
|
||||||
# local caching
|
# local caching
|
||||||
self.sdesc = sdesc
|
self.sdesc = sdesc
|
||||||
self.sdesc_regex = re.compile(sdesc_regex, _RE_FLAGS)
|
self.sdesc_regex = re.compile(sdesc_regex, _RE_FLAGS)
|
||||||
|
|
@ -780,9 +829,9 @@ class RecogHandler(object):
|
||||||
"""
|
"""
|
||||||
Load data to handler cache
|
Load data to handler cache
|
||||||
"""
|
"""
|
||||||
self.ref2recog = self.obj.attributes.get("recog_ref2recog", default={})
|
self.ref2recog = self.obj.attributes.get("_recog_ref2recog", default={})
|
||||||
obj2regex = self.obj.attributes.get("recog_obj2regex", default={})
|
obj2regex = self.obj.attributes.get("_recog_obj2regex", default={})
|
||||||
obj2recog = self.obj.attributes.get("recog_obj2recog", default={})
|
obj2recog = self.obj.attributes.get("_recog_obj2recog", default={})
|
||||||
self.obj2regex = dict((obj, re.compile(regex, _RE_FLAGS))
|
self.obj2regex = dict((obj, re.compile(regex, _RE_FLAGS))
|
||||||
for obj, regex in obj2regex.items() if obj)
|
for obj, regex in obj2regex.items() if obj)
|
||||||
self.obj2recog = dict((obj, recog)
|
self.obj2recog = dict((obj, recog)
|
||||||
|
|
@ -822,10 +871,10 @@ class RecogHandler(object):
|
||||||
|
|
||||||
# mapping #dbref:obj
|
# mapping #dbref:obj
|
||||||
key = "#%i" % obj.id
|
key = "#%i" % obj.id
|
||||||
self.db.ref2recog[key] = recog
|
self.db._ref2recog[key] = recog
|
||||||
self.db.obj2recog[obj] = recog
|
self.db._obj2recog[obj] = recog
|
||||||
regex = ordered_permutation_regex(cleaned_recog)
|
regex = ordered_permutation_regex(cleaned_recog)
|
||||||
self.db.obj2regex[obj] = regex
|
self.db._obj2regex[obj] = regex
|
||||||
# local caching
|
# local caching
|
||||||
self.ref2recog[key] = recog
|
self.ref2recog[key] = recog
|
||||||
self.obj2recog[obj] = recog
|
self.obj2recog[obj] = recog
|
||||||
|
|
@ -867,25 +916,16 @@ class RecogHandler(object):
|
||||||
|
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
# RP Object typeclass
|
# RP typeclasses
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
||||||
class RPObject(DefaultObject):
|
class RPObject(DefaultObject):
|
||||||
"""
|
"""
|
||||||
This class is meant as a mix-in or parent for characters in an
|
This class is meant as a mix-in or parent for objects in an
|
||||||
rp-heavy game. It implements the base functionality for sdescs,
|
rp-heavy game. It implements the base functionality for sdescs,
|
||||||
name replacement and look extensions.
|
name replacement and look extensions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Handlers
|
|
||||||
@lazy_property
|
|
||||||
def sdesc(self):
|
|
||||||
return SdescHandler(self)
|
|
||||||
|
|
||||||
@lazy_property
|
|
||||||
def recog(self):
|
|
||||||
return RecogHandler(self)
|
|
||||||
|
|
||||||
def at_object_creation(self):
|
def at_object_creation(self):
|
||||||
"""
|
"""
|
||||||
Called at initial creation.
|
Called at initial creation.
|
||||||
|
|
@ -896,15 +936,6 @@ class RPObject(DefaultObject):
|
||||||
self.db.pose = ""
|
self.db.pose = ""
|
||||||
self.db.pose_default = "is here."
|
self.db.pose_default = "is here."
|
||||||
|
|
||||||
self.db.sdesc = ""
|
|
||||||
self.db.sdesc_regex = ""
|
|
||||||
|
|
||||||
self.db.recog_ref2recog = {}
|
|
||||||
self.db.recog_obj2regex = {}
|
|
||||||
self.db.recog_obj2recog = {}
|
|
||||||
|
|
||||||
# initializing
|
|
||||||
self.sdesc.add("A normal person")
|
|
||||||
|
|
||||||
def search(self, searchdata, **kwargs):
|
def search(self, searchdata, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -926,12 +957,10 @@ class RPObject(DefaultObject):
|
||||||
matches = parse_sdescs_and_recogs(self, self.location.contents,
|
matches = parse_sdescs_and_recogs(self, self.location.contents,
|
||||||
_PREFIX + searchdata, search_mode=True)
|
_PREFIX + searchdata, search_mode=True)
|
||||||
nmatches = len(matches)
|
nmatches = len(matches)
|
||||||
print "matches:", matches
|
|
||||||
if nmatches == 1:
|
if nmatches == 1:
|
||||||
return matches[0]
|
return matches[0]
|
||||||
elif nmatches > 1:
|
elif nmatches > 1:
|
||||||
# multimatch
|
# multimatch
|
||||||
print matches
|
|
||||||
reflist = ["%s%s%s (%s)" % (inum+1, _NUM_SEP, searchdata, obj.sdesc.get())
|
reflist = ["%s%s%s (%s)" % (inum+1, _NUM_SEP, searchdata, obj.sdesc.get())
|
||||||
for inum, obj in enumerate(matches)]
|
for inum, obj in enumerate(matches)]
|
||||||
self.msg(_EMOTE_MULTIMATCH_ERROR.format(ref=searchdata,reflist="\n ".join(reflist)))
|
self.msg(_EMOTE_MULTIMATCH_ERROR.format(ref=searchdata,reflist="\n ".join(reflist)))
|
||||||
|
|
@ -958,14 +987,14 @@ class RPObject(DefaultObject):
|
||||||
said object.
|
said object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
idstr = " (#%s)" % self.id if self.access(looker, access_type='control') else ""
|
idstr = "(#%s)" % self.id if self.access(looker, access_type='control') else ""
|
||||||
try:
|
try:
|
||||||
recog = looker.recog.get(self)
|
recog = looker.recog.get(self)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
recog = None
|
recog = None
|
||||||
sdesc = recog or self.db.sdesc or self.key
|
sdesc = recog or (hasattr(self, "sdesc") and self.sdesc.get()) or self.key
|
||||||
pose = " %s" % self.db.pose or "" if kwargs.get("pose", False) else ""
|
pose = " %s" % self.db.pose or "" if kwargs.get("pose", False) else ""
|
||||||
return "%s%s%s" % (sdesc, pose, idstr)
|
return "{c%s{n%s%s" % (sdesc, idstr, pose)
|
||||||
|
|
||||||
def return_appearance(self, looker):
|
def return_appearance(self, looker):
|
||||||
"""
|
"""
|
||||||
|
|
@ -986,7 +1015,7 @@ class RPObject(DefaultObject):
|
||||||
if con.destination:
|
if con.destination:
|
||||||
exits.append(key)
|
exits.append(key)
|
||||||
elif con.has_player:
|
elif con.has_player:
|
||||||
users.append("{c%s{n" % key)
|
users.append(key)
|
||||||
else:
|
else:
|
||||||
things.append(key)
|
things.append(key)
|
||||||
# get description, build string
|
# get description, build string
|
||||||
|
|
@ -997,13 +1026,44 @@ class RPObject(DefaultObject):
|
||||||
if exits:
|
if exits:
|
||||||
string += "\n{wExits:{n " + ", ".join(exits)
|
string += "\n{wExits:{n " + ", ".join(exits)
|
||||||
if users or things:
|
if users or things:
|
||||||
string += "\n{wYou see:{n " + "\n ".join(users + things)
|
string += "\n " + "\n ".join(users + things)
|
||||||
return string
|
return string
|
||||||
|
|
||||||
|
|
||||||
|
class RPRoom(DefaultRoom):
|
||||||
|
"""
|
||||||
|
Rooms don't have sdescs nor poses of their own, so we
|
||||||
|
just borrow its return_appearance hook here.
|
||||||
|
"""
|
||||||
|
return_appearance = RPObject.__dict__["return_appearance"]
|
||||||
|
|
||||||
class RPCharacter(DefaultCharacter, RPObject):
|
class RPCharacter(DefaultCharacter, RPObject):
|
||||||
"""
|
"""
|
||||||
This is a character aware of RP systems.
|
This is a character aware of RP systems.
|
||||||
"""
|
"""
|
||||||
|
# Handlers
|
||||||
|
@lazy_property
|
||||||
|
def sdesc(self):
|
||||||
|
return SdescHandler(self)
|
||||||
|
|
||||||
|
@lazy_property
|
||||||
|
def recog(self):
|
||||||
|
return RecogHandler(self)
|
||||||
|
|
||||||
def at_object_creation(self):
|
def at_object_creation(self):
|
||||||
|
"""
|
||||||
|
Called at initial creation.
|
||||||
|
"""
|
||||||
super(RPCharacter, self).at_object_creation()
|
super(RPCharacter, self).at_object_creation()
|
||||||
|
|
||||||
|
self.db._sdesc = ""
|
||||||
|
self.db._sdesc_regex = ""
|
||||||
|
|
||||||
|
self.db._recog_ref2recog = {}
|
||||||
|
self.db._recog_obj2regex = {}
|
||||||
|
self.db._recog_obj2recog = {}
|
||||||
|
|
||||||
|
self.cmdset.add(RPSystemCmdSet, permanent=True)
|
||||||
|
# initializing sdesc
|
||||||
|
self.sdesc.add("A normal item")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -326,6 +326,8 @@ class AttributeHandler(object):
|
||||||
The default `None` is the normal category used.
|
The default `None` is the normal category used.
|
||||||
lockstring (str, optional): A lock string limiting access
|
lockstring (str, optional): A lock string limiting access
|
||||||
to the attribute.
|
to the attribute.
|
||||||
|
strattr (bool, optional): Make this a string-only Attribute.
|
||||||
|
This is only ever useful for optimization purposes.
|
||||||
accessing_obj (object, optional): An entity to check for
|
accessing_obj (object, optional): An entity to check for
|
||||||
the `attrcreate` access-type. If not passing, this method
|
the `attrcreate` access-type. If not passing, this method
|
||||||
will be exited.
|
will be exited.
|
||||||
|
|
@ -384,6 +386,8 @@ class AttributeHandler(object):
|
||||||
The default `None` is the normal category used.
|
The default `None` is the normal category used.
|
||||||
lockstring (str, optional): A lock string limiting access
|
lockstring (str, optional): A lock string limiting access
|
||||||
to the attribute.
|
to the attribute.
|
||||||
|
strattr (bool, optional): Make this a string-only Attribute.
|
||||||
|
This is only ever useful for optimization purposes.
|
||||||
accessing_obj (object, optional): An entity to check for
|
accessing_obj (object, optional): An entity to check for
|
||||||
the `attrcreate` access-type. If not passing, this method
|
the `attrcreate` access-type. If not passing, this method
|
||||||
will be exited.
|
will be exited.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue