Merge pull request #2728 from InspectorCaracal/rpsystem-sdesc
Streamline `rpsystem` sdesc processing
This commit is contained in:
commit
62bfa3e8f4
3 changed files with 302 additions and 376 deletions
|
|
@ -4,7 +4,6 @@ Roleplaying emotes and language - Griatch, 2015
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .rpsystem import EmoteError, SdescError, RecogError, LanguageError # noqa
|
from .rpsystem import EmoteError, SdescError, RecogError, LanguageError # noqa
|
||||||
from .rpsystem import ordered_permutation_regex, regex_tuple_from_key_alias # noqa
|
|
||||||
from .rpsystem import parse_language, parse_sdescs_and_recogs, send_emote # noqa
|
from .rpsystem import parse_language, parse_sdescs_and_recogs, send_emote # noqa
|
||||||
from .rpsystem import SdescHandler, RecogHandler # noqa
|
from .rpsystem import SdescHandler, RecogHandler # noqa
|
||||||
from .rpsystem import RPCommand, CmdEmote, CmdSay, CmdSdesc, CmdPose, CmdRecog, CmdMask # noqa
|
from .rpsystem import RPCommand, CmdEmote, CmdSay, CmdSdesc, CmdPose, CmdRecog, CmdMask # noqa
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ Add `RPSystemCmdSet` from this module to your CharacterCmdSet:
|
||||||
|
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
from evennia.contrib.rpg.rpsystem import RPSystemCmdSet <---
|
from evennia.contrib.rpg.rpsystem.rpsystem import RPSystemCmdSet <---
|
||||||
|
|
||||||
class CharacterCmdSet(default_cmds.CharacterCmdset):
|
class CharacterCmdSet(default_cmds.CharacterCmdset):
|
||||||
# ...
|
# ...
|
||||||
|
|
@ -69,7 +69,7 @@ the typeclasses in this module:
|
||||||
```python
|
```python
|
||||||
# in mygame/typeclasses/characters.py
|
# in mygame/typeclasses/characters.py
|
||||||
|
|
||||||
from evennia.contrib.rpg import ContribRPCharacter
|
from evennia.contrib.rpg.rpsystem.rpsystem import ContribRPCharacter
|
||||||
|
|
||||||
class Character(ContribRPCharacter):
|
class Character(ContribRPCharacter):
|
||||||
# ...
|
# ...
|
||||||
|
|
@ -79,7 +79,7 @@ class Character(ContribRPCharacter):
|
||||||
```python
|
```python
|
||||||
# in mygame/typeclasses/objects.py
|
# in mygame/typeclasses/objects.py
|
||||||
|
|
||||||
from evennia.contrib.rpg import ContribRPObject
|
from evennia.contrib.rpg.rpsystem.rpsystem import ContribRPObject
|
||||||
|
|
||||||
class Object(ContribRPObject):
|
class Object(ContribRPObject):
|
||||||
# ...
|
# ...
|
||||||
|
|
@ -89,7 +89,7 @@ class Object(ContribRPObject):
|
||||||
```python
|
```python
|
||||||
# in mygame/typeclasses/rooms.py
|
# in mygame/typeclasses/rooms.py
|
||||||
|
|
||||||
from evennia.contrib.rpg import ContribRPRoom
|
from evennia.contrib.rpg.rpsystem.rpsystem import ContribRPRoom
|
||||||
|
|
||||||
class Room(ContribRPRoom):
|
class Room(ContribRPRoom):
|
||||||
# ...
|
# ...
|
||||||
|
|
@ -125,7 +125,7 @@ Extra Installation Instructions:
|
||||||
|
|
||||||
1. In typeclasses/character.py:
|
1. In typeclasses/character.py:
|
||||||
Import the `ContribRPCharacter` class:
|
Import the `ContribRPCharacter` class:
|
||||||
`from evennia.contrib.rpg.rpsystem import ContribRPCharacter`
|
`from evennia.contrib.rpg.rpsystem.rpsystem import ContribRPCharacter`
|
||||||
Inherit ContribRPCharacter:
|
Inherit ContribRPCharacter:
|
||||||
Change "class Character(DefaultCharacter):" to
|
Change "class Character(DefaultCharacter):" to
|
||||||
`class Character(ContribRPCharacter):`
|
`class Character(ContribRPCharacter):`
|
||||||
|
|
@ -133,13 +133,13 @@ Extra Installation Instructions:
|
||||||
Add `super().at_object_creation()` as the top line.
|
Add `super().at_object_creation()` as the top line.
|
||||||
2. In `typeclasses/rooms.py`:
|
2. In `typeclasses/rooms.py`:
|
||||||
Import the `ContribRPRoom` class:
|
Import the `ContribRPRoom` class:
|
||||||
`from evennia.contrib.rpg.rpsystem import ContribRPRoom`
|
`from evennia.contrib.rpg.rpsystem.rpsystem import ContribRPRoom`
|
||||||
Inherit `ContribRPRoom`:
|
Inherit `ContribRPRoom`:
|
||||||
Change `class Room(DefaultRoom):` to
|
Change `class Room(DefaultRoom):` to
|
||||||
`class Room(ContribRPRoom):`
|
`class Room(ContribRPRoom):`
|
||||||
3. In `typeclasses/objects.py`
|
3. In `typeclasses/objects.py`
|
||||||
Import the `ContribRPObject` class:
|
Import the `ContribRPObject` class:
|
||||||
`from evennia.contrib.rpg.rpsystem import ContribRPObject`
|
`from evennia.contrib.rpg.rpsystem.rpsystem import ContribRPObject`
|
||||||
Inherit `ContribRPObject`:
|
Inherit `ContribRPObject`:
|
||||||
Change `class Object(DefaultObject):` to
|
Change `class Object(DefaultObject):` to
|
||||||
`class Object(ContribRPObject):`
|
`class Object(ContribRPObject):`
|
||||||
|
|
@ -149,18 +149,15 @@ Extra Installation Instructions:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
from re import escape as re_escape
|
from string import punctuation
|
||||||
import itertools
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from evennia.objects.objects import DefaultObject, DefaultCharacter
|
from evennia.objects.objects import DefaultObject, DefaultCharacter
|
||||||
from evennia.objects.models import ObjectDB
|
from evennia.objects.models import ObjectDB
|
||||||
from evennia.commands.command import Command
|
from evennia.commands.command import Command
|
||||||
from evennia.commands.cmdset import CmdSet
|
from evennia.commands.cmdset import CmdSet
|
||||||
from evennia.utils import ansi
|
from evennia.utils import ansi, logger
|
||||||
from evennia.utils.utils import lazy_property, make_iter, variable_from_module
|
from evennia.utils.utils import lazy_property, make_iter, variable_from_module
|
||||||
|
|
||||||
_REGEX_TUPLE_CACHE = {}
|
|
||||||
|
|
||||||
_AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1))
|
_AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1))
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Emote parser
|
# Emote parser
|
||||||
|
|
@ -189,13 +186,13 @@ _EMOTE_MULTIMATCH_ERROR = """|RMultiple possibilities for {ref}:
|
||||||
|
|
||||||
_RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.UNICODE
|
_RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.UNICODE
|
||||||
|
|
||||||
_RE_PREFIX = re.compile(r"^%s" % _PREFIX, re.UNICODE)
|
_RE_PREFIX = re.compile(rf"^{_PREFIX}", re.UNICODE)
|
||||||
|
|
||||||
# This regex will return groups (num, word), where num is an optional counter to
|
# This regex will return groups (num, word), where num is an optional counter to
|
||||||
# separate multimatches from one another and word is the first word in the
|
# separate multimatches from one another and word is the first word in the
|
||||||
# marker. So entering "/tall man" will return groups ("", "tall")
|
# marker. So entering "/tall man" will return groups ("", "tall")
|
||||||
# and "/2-tall man" will return groups ("2", "tall").
|
# and "/2-tall man" will return groups ("2", "tall").
|
||||||
_RE_OBJ_REF_START = re.compile(r"%s(?:([0-9]+)%s)*(\w+)" % (_PREFIX, _NUM_SEP), _RE_FLAGS)
|
_RE_OBJ_REF_START = re.compile(rf"{_PREFIX}(?:([0-9]+){_NUM_SEP})*(\w+)", _RE_FLAGS)
|
||||||
|
|
||||||
_RE_LEFT_BRACKETS = re.compile(r"\{+", _RE_FLAGS)
|
_RE_LEFT_BRACKETS = re.compile(r"\{+", _RE_FLAGS)
|
||||||
_RE_RIGHT_BRACKETS = re.compile(r"\}+", _RE_FLAGS)
|
_RE_RIGHT_BRACKETS = re.compile(r"\}+", _RE_FLAGS)
|
||||||
|
|
@ -239,97 +236,7 @@ class LanguageError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _dummy_process(text, *args, **kwargs):
|
|
||||||
"Pass-through processor"
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
# emoting mechanisms
|
# emoting mechanisms
|
||||||
|
|
||||||
|
|
||||||
def ordered_permutation_regex(sentence):
|
|
||||||
"""
|
|
||||||
Builds a regex that matches 'ordered permutations' of a sentence's
|
|
||||||
words.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
sentence (str): The sentence to build a match pattern to
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
regex (re object): Compiled regex object represented the
|
|
||||||
possible ordered permutations of the sentence, from longest to
|
|
||||||
shortest.
|
|
||||||
Example:
|
|
||||||
The sdesc_regex for an sdesc of " very tall man" will
|
|
||||||
result in the following allowed permutations,
|
|
||||||
regex-matched in inverse order of length (case-insensitive):
|
|
||||||
"the very tall man", "the very tall", "very tall man",
|
|
||||||
"very tall", "the very", "tall man", "the", "very", "tall",
|
|
||||||
and "man".
|
|
||||||
We also add regex to make sure it also accepts num-specifiers,
|
|
||||||
like /2-tall.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# escape {#nnn} markers from sentence, replace with nnn
|
|
||||||
sentence = _RE_REF.sub(r"\1", sentence)
|
|
||||||
# escape {##nnn} markers, replace with nnn
|
|
||||||
sentence = _RE_REF_LANG.sub(r"\1", sentence)
|
|
||||||
# escape self-ref marker from sentence
|
|
||||||
sentence = _RE_SELF_REF.sub(r"", sentence)
|
|
||||||
|
|
||||||
# ordered permutation algorithm
|
|
||||||
words = sentence.split()
|
|
||||||
combinations = itertools.product((True, False), repeat=len(words))
|
|
||||||
solution = []
|
|
||||||
for combination in combinations:
|
|
||||||
comb = []
|
|
||||||
for iword, word in enumerate(words):
|
|
||||||
if combination[iword]:
|
|
||||||
comb.append(word)
|
|
||||||
elif comb:
|
|
||||||
break
|
|
||||||
if comb:
|
|
||||||
solution.append(
|
|
||||||
_PREFIX
|
|
||||||
+ r"[0-9]*%s*%s(?=\W|$)+" % (_NUM_SEP, re_escape(" ".join(comb)).rstrip("\\"))
|
|
||||||
)
|
|
||||||
|
|
||||||
# combine into a match regex, first matching the longest down to the shortest components
|
|
||||||
regex = r"|".join(sorted(set(solution), key=lambda item: (-len(item), item)))
|
|
||||||
return regex
|
|
||||||
|
|
||||||
|
|
||||||
def regex_tuple_from_key_alias(obj):
|
|
||||||
"""
|
|
||||||
This will build a regex tuple for any object, not just from those
|
|
||||||
with sdesc/recog handlers. It's used as a legacy mechanism for
|
|
||||||
being able to mix this contrib with objects not using sdescs, but
|
|
||||||
note that creating the ordered permutation regex dynamically for
|
|
||||||
every object will add computational overhead.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
obj (Object): This object's key and eventual aliases will
|
|
||||||
be used to build the tuple.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
regex_tuple (tuple): A tuple
|
|
||||||
(ordered_permutation_regex, obj, key/alias)
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
global _REGEX_TUPLE_CACHE
|
|
||||||
permutation_string = " ".join([obj.key] + obj.aliases.all())
|
|
||||||
cache_key = f"{obj.id} {permutation_string}"
|
|
||||||
|
|
||||||
if cache_key not in _REGEX_TUPLE_CACHE:
|
|
||||||
_REGEX_TUPLE_CACHE[cache_key] = (
|
|
||||||
re.compile(ordered_permutation_regex(permutation_string), _RE_FLAGS),
|
|
||||||
obj,
|
|
||||||
obj.key,
|
|
||||||
)
|
|
||||||
return _REGEX_TUPLE_CACHE[cache_key]
|
|
||||||
|
|
||||||
|
|
||||||
def parse_language(speaker, emote):
|
def parse_language(speaker, emote):
|
||||||
"""
|
"""
|
||||||
Parse the emote for language. This is
|
Parse the emote for language. This is
|
||||||
|
|
@ -375,9 +282,9 @@ def parse_language(speaker, emote):
|
||||||
langname, saytext = say_match.groups()
|
langname, saytext = say_match.groups()
|
||||||
istart, iend = say_match.start(), say_match.end()
|
istart, iend = say_match.start(), say_match.end()
|
||||||
# the key is simply the running match in the emote
|
# the key is simply the running match in the emote
|
||||||
key = "##%i" % imatch
|
key = f"##{imatch}"
|
||||||
# replace say with ref markers in emote
|
# replace say with ref markers in emote
|
||||||
emote = emote[:istart] + "{%s}" % key + emote[iend:]
|
emote = "{start}{{{key}}}{end}".format( start=emote[:istart], key=key, end=emote[iend:] )
|
||||||
mapping[key] = (langname, saytext)
|
mapping[key] = (langname, saytext)
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
|
|
@ -430,24 +337,20 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False, case_
|
||||||
- says, "..." are
|
- says, "..." are
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Load all candidate regex tuples [(regex, obj, sdesc/recog),...]
|
# build a list of candidates with all possible referrable names
|
||||||
candidate_regexes = (
|
# include 'me' keyword for self-ref
|
||||||
([(_RE_SELF_REF, sender, sender.sdesc.get())] if hasattr(sender, "sdesc") else [])
|
candidate_map = [(sender, 'me')]
|
||||||
+ (
|
for obj in candidates:
|
||||||
[sender.recog.get_regex_tuple(obj) for obj in candidates]
|
# check if sender has any recogs for obj and add
|
||||||
if hasattr(sender, "recog")
|
if hasattr(sender, "recog"):
|
||||||
else []
|
if recog := sender.recog.get(obj):
|
||||||
)
|
candidate_map.append((obj, recog))
|
||||||
+ [obj.sdesc.get_regex_tuple() for obj in candidates if hasattr(obj, "sdesc")]
|
# check if obj has an sdesc and add
|
||||||
+ [
|
if hasattr(obj, "sdesc"):
|
||||||
regex_tuple_from_key_alias(obj) # handle objects without sdescs
|
candidate_map.append((obj, obj.sdesc.get()))
|
||||||
for obj in candidates
|
# if no sdesc, include key plus aliases instead
|
||||||
if not (hasattr(obj, "recog") and hasattr(obj, "sdesc"))
|
else:
|
||||||
]
|
candidate_map.extend( [(obj, obj.key)] + [(obj, alias) for alias in obj.aliases.all()] )
|
||||||
)
|
|
||||||
|
|
||||||
# filter out non-found data
|
|
||||||
candidate_regexes = [tup for tup in candidate_regexes if tup]
|
|
||||||
|
|
||||||
# escape mapping syntax on the form {#id} if it exists already in emote,
|
# escape mapping syntax on the form {#id} if it exists already in emote,
|
||||||
# if so it is replaced with just "id".
|
# if so it is replaced with just "id".
|
||||||
|
|
@ -468,18 +371,48 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False, case_
|
||||||
|
|
||||||
# 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
|
||||||
istart0 = marker_match.start()
|
match_index = marker_match.start()
|
||||||
istart = istart0
|
# split the emote string at the reference marker, to process everything after it
|
||||||
|
head = string[:match_index]
|
||||||
|
tail = string[match_index+1:]
|
||||||
|
|
||||||
# loop over all candidate regexes and match against the string following the match
|
if search_mode:
|
||||||
matches = ((reg.match(string[istart:]), obj, text) for reg, obj, text in candidate_regexes)
|
# match the candidates against the whole search string after the marker
|
||||||
|
rquery = "".join([r"\b(" + re.escape(word.strip(punctuation)) + r").*" for word in iter(tail.split())])
|
||||||
|
matches = ((re.search(rquery, text, _RE_FLAGS), obj, text) for obj, text in candidate_map)
|
||||||
|
# filter out any non-matching candidates
|
||||||
|
bestmatches = [(obj, match.group()) for match, obj, text in matches if match]
|
||||||
|
|
||||||
# score matches by how long part of the string was matched
|
else:
|
||||||
matches = [(match.end() if match else -1, obj, text) for match, obj, text in matches]
|
# to find the longest match, we start from the marker and lengthen the
|
||||||
maxscore = max(score for score, obj, text in matches)
|
# match query one word at a time.
|
||||||
|
word_list = []
|
||||||
|
bestmatches = []
|
||||||
|
# preserve punctuation when splitting
|
||||||
|
tail = re.split('(\W)', tail)
|
||||||
|
iend = 0
|
||||||
|
for i, item in enumerate(tail):
|
||||||
|
# don't add non-word characters to the search query
|
||||||
|
if not item.isalpha():
|
||||||
|
continue
|
||||||
|
word_list.append(item)
|
||||||
|
rquery = "".join([r"\b(" + re.escape(word) + r").*" for word in word_list])
|
||||||
|
# match candidates against the current set of words
|
||||||
|
matches = ((re.search(rquery, text, _RE_FLAGS), obj, text) for obj, text in candidate_map)
|
||||||
|
matches = [(obj, match.group()) for match, obj, text in matches if match]
|
||||||
|
if len(matches) == 0:
|
||||||
|
# no matches at this length, keep previous iteration as best
|
||||||
|
break
|
||||||
|
# since this is the longest match so far, set latest match set as best matches
|
||||||
|
bestmatches = matches
|
||||||
|
# save current index as end point of matched text
|
||||||
|
iend = i
|
||||||
|
|
||||||
|
# save search string
|
||||||
|
matched_text = "".join(tail[1:iend])
|
||||||
|
# recombine remainder of emote back into a string
|
||||||
|
tail = "".join(tail[iend+1:])
|
||||||
|
|
||||||
# we have a valid maxscore, extract all matches with this value
|
|
||||||
bestmatches = [(obj, text) for score, obj, text in matches if maxscore == score != -1]
|
|
||||||
nmatches = len(bestmatches)
|
nmatches = len(bestmatches)
|
||||||
|
|
||||||
if not nmatches:
|
if not nmatches:
|
||||||
|
|
@ -488,12 +421,11 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False, case_
|
||||||
nmatches = 0
|
nmatches = 0
|
||||||
elif nmatches == 1:
|
elif nmatches == 1:
|
||||||
# an exact match.
|
# an exact match.
|
||||||
obj = bestmatches[0][0]
|
obj, match_str = bestmatches[0]
|
||||||
nmatches = 1
|
|
||||||
elif all(bestmatches[0][0].id == obj.id for obj, text in bestmatches):
|
elif all(bestmatches[0][0].id == obj.id for obj, text in bestmatches):
|
||||||
# multi-match but all matches actually reference the same
|
# multi-match but all matches actually reference the same
|
||||||
# obj (could happen with clashing recogs + sdescs)
|
# obj (could happen with clashing recogs + sdescs)
|
||||||
obj = bestmatches[0][0]
|
obj, match_str = bestmatches[0]
|
||||||
nmatches = 1
|
nmatches = 1
|
||||||
else:
|
else:
|
||||||
# multi-match.
|
# multi-match.
|
||||||
|
|
@ -501,7 +433,7 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False, case_
|
||||||
inum = min(max(0, int(num_identifier) - 1), nmatches - 1) if num_identifier else None
|
inum = min(max(0, int(num_identifier) - 1), nmatches - 1) if num_identifier else None
|
||||||
if inum is not None:
|
if inum is not None:
|
||||||
# A valid inum is given. Use this to separate data.
|
# A valid inum is given. Use this to separate data.
|
||||||
obj = bestmatches[inum][0]
|
obj, match_str = bestmatches[inum]
|
||||||
nmatches = 1
|
nmatches = 1
|
||||||
else:
|
else:
|
||||||
# no identifier given - a real multimatch.
|
# no identifier given - a real multimatch.
|
||||||
|
|
@ -519,12 +451,9 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False, case_
|
||||||
# case sensitive mode
|
# case sensitive mode
|
||||||
# internal flags for the case used for the original /query
|
# internal flags for the case used for the original /query
|
||||||
# - t for titled input (like /Name)
|
# - t for titled input (like /Name)
|
||||||
# - ^ for all upercase input (likle /NAME)
|
# - ^ for all upercase input (like /NAME)
|
||||||
# - v for lower-case input (like /name)
|
# - v for lower-case input (like /name)
|
||||||
# - ~ for mixed case input (like /nAmE)
|
# - ~ for mixed case input (like /nAmE)
|
||||||
matchtext = marker_match.group()
|
|
||||||
if not _RE_SELF_REF.match(matchtext):
|
|
||||||
# self-refs are kept as-is, others are parsed by case
|
|
||||||
matchtext = marker_match.group().lstrip(_PREFIX)
|
matchtext = marker_match.group().lstrip(_PREFIX)
|
||||||
if matchtext.istitle():
|
if matchtext.istitle():
|
||||||
case = "t"
|
case = "t"
|
||||||
|
|
@ -533,21 +462,21 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False, case_
|
||||||
elif matchtext.islower():
|
elif matchtext.islower():
|
||||||
case = "v"
|
case = "v"
|
||||||
|
|
||||||
key = "#%i%s" % (obj.id, case)
|
key = f"#{obj.id}{case}"
|
||||||
string = string[:istart0] + "{%s}" % key + string[istart + maxscore :]
|
# recombine emote with matched text replaced by ref
|
||||||
|
string = f"{head}{{{key}}}{tail}"
|
||||||
mapping[key] = obj
|
mapping[key] = obj
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# multimatch error
|
# multimatch error
|
||||||
refname = marker_match.group()
|
refname = marker_match.group()
|
||||||
reflist = [
|
reflist = [
|
||||||
"%s%s%s (%s%s)"
|
"{num}{sep}{name} ({text}{key})".format(
|
||||||
% (
|
num=inum + 1,
|
||||||
inum + 1,
|
sep=_NUM_SEP,
|
||||||
_NUM_SEP,
|
name=_RE_PREFIX.sub("", refname),
|
||||||
_RE_PREFIX.sub("", refname),
|
text=text,
|
||||||
text,
|
key=f" ({sender.key})" if sender == ob else "",
|
||||||
" (%s)" % sender.key if sender == ob else "",
|
|
||||||
)
|
)
|
||||||
for inum, (ob, text) in enumerate(obj)
|
for inum, (ob, text) in enumerate(obj)
|
||||||
]
|
]
|
||||||
|
|
@ -611,7 +540,7 @@ def send_emote(sender, receivers, emote, anonymous_add="first", **kwargs):
|
||||||
sender.msg(str(err))
|
sender.msg(str(err))
|
||||||
return
|
return
|
||||||
|
|
||||||
skey = "#%i" % sender.id
|
skey = f"#{sender.id}"
|
||||||
|
|
||||||
# we escape the object mappings since we'll do the language ones first
|
# we escape the object mappings since we'll do the language ones first
|
||||||
# (the text could have nested object mappings).
|
# (the text could have nested object mappings).
|
||||||
|
|
@ -619,66 +548,45 @@ def send_emote(sender, receivers, emote, anonymous_add="first", **kwargs):
|
||||||
# if anonymous_add is passed as a kwarg, collect and remove it from kwargs
|
# if anonymous_add is passed as a kwarg, collect and remove it from kwargs
|
||||||
if "anonymous_add" in kwargs:
|
if "anonymous_add" in kwargs:
|
||||||
anonymous_add = kwargs.pop("anonymous_add")
|
anonymous_add = kwargs.pop("anonymous_add")
|
||||||
if anonymous_add and not any(1 for tag in obj_mapping if tag.startswith(skey)):
|
# make sure to catch all possible self-refs
|
||||||
# no self-reference in the emote - add to the end
|
self_refs = [f"{skey}{ref}" for ref in ('t','^','v','~','')]
|
||||||
obj_mapping[skey] = sender
|
if anonymous_add and not any(1 for tag in obj_mapping if tag in self_refs):
|
||||||
|
# no self-reference in the emote - add it
|
||||||
if anonymous_add == "first":
|
if anonymous_add == "first":
|
||||||
possessive = "" if emote.startswith("'") else " "
|
# add case flag for initial caps
|
||||||
emote = "%s%s%s" % ("{{%s}}" % skey, possessive, emote)
|
skey += 't'
|
||||||
|
# don't put a space after the self-ref if it's a possessive emote
|
||||||
|
femote = "{key}{emote}" if emote.startswith("'") else "{key} {emote}"
|
||||||
else:
|
else:
|
||||||
emote = "%s [%s]" % (emote, "{{%s}}" % skey)
|
# add it to the end
|
||||||
|
femote = "{emote} [{key}]"
|
||||||
|
emote = femote.format( key="{{"+ skey +"}}", emote=emote )
|
||||||
|
obj_mapping[skey] = sender
|
||||||
|
|
||||||
# broadcast emote to everyone
|
# broadcast emote to everyone
|
||||||
for receiver in receivers:
|
for receiver in receivers:
|
||||||
# first handle the language mapping, which always produce different keys ##nn
|
# first handle the language mapping, which always produce different keys ##nn
|
||||||
receiver_lang_mapping = {}
|
if hasattr(receiver, "process_language") and callable(receiver.process_language):
|
||||||
try:
|
receiver_lang_mapping = {
|
||||||
process_language = receiver.process_language
|
key: receiver.process_language(saytext, sender, langname)
|
||||||
except AttributeError:
|
for key, (langname, saytext) in language_mapping.items()
|
||||||
process_language = _dummy_process
|
}
|
||||||
for key, (langname, saytext) in language_mapping.items():
|
else:
|
||||||
# color says
|
receiver_lang_mapping = {
|
||||||
receiver_lang_mapping[key] = process_language(saytext, sender, langname)
|
key: saytext for key, (langname, saytext) in language_mapping.items()
|
||||||
|
}
|
||||||
# map the language {##num} markers. This will convert the escaped sdesc markers on
|
# map the language {##num} markers. This will convert the escaped sdesc markers on
|
||||||
# the form {{#num}} to {#num} markers ready to sdesc-map in the next step.
|
# the form {{#num}} to {#num} markers ready to sdesc-map in the next step.
|
||||||
sendemote = emote.format(**receiver_lang_mapping)
|
sendemote = emote.format(**receiver_lang_mapping)
|
||||||
|
|
||||||
# handle sdesc mappings. we make a temporary copy that we can modify
|
# map the ref keys to sdescs
|
||||||
try:
|
|
||||||
process_sdesc = receiver.process_sdesc
|
|
||||||
except AttributeError:
|
|
||||||
process_sdesc = _dummy_process
|
|
||||||
|
|
||||||
try:
|
|
||||||
process_recog = receiver.process_recog
|
|
||||||
except AttributeError:
|
|
||||||
process_recog = _dummy_process
|
|
||||||
|
|
||||||
try:
|
|
||||||
recog_get = receiver.recog.get
|
|
||||||
receiver_sdesc_mapping = dict(
|
|
||||||
(ref, process_recog(recog_get(obj), obj, ref=ref, **kwargs))
|
|
||||||
for ref, obj in obj_mapping.items()
|
|
||||||
)
|
|
||||||
except AttributeError:
|
|
||||||
receiver_sdesc_mapping = dict(
|
receiver_sdesc_mapping = dict(
|
||||||
(
|
(
|
||||||
ref,
|
ref,
|
||||||
process_sdesc(obj.sdesc.get(), obj, ref=ref)
|
obj.get_display_name(receiver, ref=ref, noid=True),
|
||||||
if hasattr(obj, "sdesc")
|
|
||||||
else process_sdesc(obj.key, obj, ref=ref),
|
|
||||||
)
|
)
|
||||||
for ref, obj in obj_mapping.items()
|
for ref, obj in obj_mapping.items()
|
||||||
)
|
)
|
||||||
# make sure receiver always sees their real name
|
|
||||||
rkey_start = "#%i" % receiver.id
|
|
||||||
rkey_keep_case = rkey_start + "~" # signifies keeping the case
|
|
||||||
for rkey in (key for key in receiver_sdesc_mapping if key.startswith(rkey_start)):
|
|
||||||
# we could have #%i^, #%it etc depending on input case - we want the
|
|
||||||
# self-reference to retain case.
|
|
||||||
receiver_sdesc_mapping[rkey] = process_sdesc(
|
|
||||||
receiver.key, receiver, ref=rkey_keep_case, **kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
# do the template replacement of the sdesc/recog {#num} markers
|
# do the template replacement of the sdesc/recog {#num} markers
|
||||||
receiver.msg(sendemote.format(**receiver_sdesc_mapping), from_obj=sender, **kwargs)
|
receiver.msg(sendemote.format(**receiver_sdesc_mapping), from_obj=sender, **kwargs)
|
||||||
|
|
@ -713,17 +621,13 @@ class SdescHandler:
|
||||||
"""
|
"""
|
||||||
self.obj = obj
|
self.obj = obj
|
||||||
self.sdesc = ""
|
self.sdesc = ""
|
||||||
self.sdesc_regex = ""
|
|
||||||
self._cache()
|
self._cache()
|
||||||
|
|
||||||
def _cache(self):
|
def _cache(self):
|
||||||
"""
|
"""
|
||||||
Cache data from storage
|
Cache data from storage
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.sdesc = self.obj.attributes.get("_sdesc", default="")
|
self.sdesc = self.obj.attributes.get("_sdesc", default=self.obj.key)
|
||||||
sdesc_regex = self.obj.attributes.get("_sdesc_regex", default="")
|
|
||||||
self.sdesc_regex = re.compile(sdesc_regex, _RE_FLAGS)
|
|
||||||
|
|
||||||
def add(self, sdesc, max_length=60):
|
def add(self, sdesc, max_length=60):
|
||||||
"""
|
"""
|
||||||
|
|
@ -759,17 +663,13 @@ class SdescHandler:
|
||||||
|
|
||||||
if len(cleaned_sdesc) > max_length:
|
if len(cleaned_sdesc) > max_length:
|
||||||
raise SdescError(
|
raise SdescError(
|
||||||
"Short desc can max be %i chars long (was %i chars)."
|
"Short desc can max be {} chars long (was {} chars).".format(max_length, len(cleaned_sdesc))
|
||||||
% (max_length, len(cleaned_sdesc))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# store to attributes
|
# store to attributes
|
||||||
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)
|
|
||||||
# local caching
|
# local caching
|
||||||
self.sdesc = sdesc
|
self.sdesc = sdesc
|
||||||
self.sdesc_regex = re.compile(sdesc_regex, _RE_FLAGS)
|
|
||||||
|
|
||||||
return sdesc
|
return sdesc
|
||||||
|
|
||||||
|
|
@ -781,15 +681,6 @@ class SdescHandler:
|
||||||
"""
|
"""
|
||||||
return self.sdesc or self.obj.key
|
return self.sdesc or self.obj.key
|
||||||
|
|
||||||
def get_regex_tuple(self):
|
|
||||||
"""
|
|
||||||
Return data for sdesc/recog handling
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
tup (tuple): tuple (sdesc_regex, obj, sdesc)
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self.sdesc_regex, self.obj, self.sdesc
|
|
||||||
|
|
||||||
|
|
||||||
class RecogHandler:
|
class RecogHandler:
|
||||||
|
|
@ -802,7 +693,6 @@ class RecogHandler:
|
||||||
|
|
||||||
_recog_ref2recog
|
_recog_ref2recog
|
||||||
_recog_obj2recog
|
_recog_obj2recog
|
||||||
_recog_obj2regex
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -817,7 +707,6 @@ class RecogHandler:
|
||||||
self.obj = obj
|
self.obj = obj
|
||||||
# mappings
|
# mappings
|
||||||
self.ref2recog = {}
|
self.ref2recog = {}
|
||||||
self.obj2regex = {}
|
|
||||||
self.obj2recog = {}
|
self.obj2recog = {}
|
||||||
self._cache()
|
self._cache()
|
||||||
|
|
||||||
|
|
@ -826,11 +715,7 @@ class RecogHandler:
|
||||||
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={})
|
|
||||||
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)) for obj, regex in obj2regex.items() if obj
|
|
||||||
)
|
|
||||||
self.obj2recog = dict((obj, recog) for obj, recog in obj2recog.items() if obj)
|
self.obj2recog = dict((obj, recog) for obj, recog in obj2recog.items() if obj)
|
||||||
|
|
||||||
def add(self, obj, recog, max_length=60):
|
def add(self, obj, recog, max_length=60):
|
||||||
|
|
@ -873,31 +758,27 @@ class RecogHandler:
|
||||||
|
|
||||||
if len(cleaned_recog) > max_length:
|
if len(cleaned_recog) > max_length:
|
||||||
raise RecogError(
|
raise RecogError(
|
||||||
"Recog string cannot be longer than %i chars (was %i chars)"
|
"Recog string cannot be longer than {} chars (was {} chars)".format(max_length, len(cleaned_recog))
|
||||||
% (max_length, len(cleaned_recog))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# mapping #dbref:obj
|
# mapping #dbref:obj
|
||||||
key = "#%i" % obj.id
|
key = f"#{obj.id}"
|
||||||
self.obj.attributes.get("_recog_ref2recog", default={})[key] = recog
|
self.obj.attributes.get("_recog_ref2recog", default={})[key] = recog
|
||||||
self.obj.attributes.get("_recog_obj2recog", default={})[obj] = recog
|
self.obj.attributes.get("_recog_obj2recog", default={})[obj] = recog
|
||||||
regex = ordered_permutation_regex(cleaned_recog)
|
|
||||||
self.obj.attributes.get("_recog_obj2regex", default={})[obj] = regex
|
|
||||||
# local caching
|
# local caching
|
||||||
self.ref2recog[key] = recog
|
self.ref2recog[key] = recog
|
||||||
self.obj2recog[obj] = recog
|
self.obj2recog[obj] = recog
|
||||||
self.obj2regex[obj] = re.compile(regex, _RE_FLAGS)
|
|
||||||
return recog
|
return recog
|
||||||
|
|
||||||
def get(self, obj):
|
def get(self, obj):
|
||||||
"""
|
"""
|
||||||
Get recog replacement string, if one exists, otherwise
|
Get recog replacement string, if one exists.
|
||||||
get sdesc and as a last resort, the object's key.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
obj (Object): The object, whose sdesc to replace
|
obj (Object): The object, whose sdesc to replace
|
||||||
Returns:
|
Returns:
|
||||||
recog (str): The replacement string to use.
|
recog (str or None): The replacement string to use, or
|
||||||
|
None if there is no recog for this object.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
This method will respect a "enable_recog" lock set on
|
This method will respect a "enable_recog" lock set on
|
||||||
|
|
@ -908,10 +789,10 @@ class RecogHandler:
|
||||||
# check an eventual recog_masked lock on the object
|
# check an eventual recog_masked lock on the object
|
||||||
# to avoid revealing masked characters. If lock
|
# to avoid revealing masked characters. If lock
|
||||||
# does not exist, pass automatically.
|
# does not exist, pass automatically.
|
||||||
return self.obj2recog.get(obj, obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key)
|
return self.obj2recog.get(obj, None)
|
||||||
else:
|
else:
|
||||||
# recog_mask log not passed, disable recog
|
# recog_mask lock not passed, disable recog
|
||||||
return obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key
|
return None
|
||||||
|
|
||||||
def all(self):
|
def all(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -932,19 +813,9 @@ class RecogHandler:
|
||||||
"""
|
"""
|
||||||
if obj in self.obj2recog:
|
if obj in self.obj2recog:
|
||||||
del self.obj.db._recog_obj2recog[obj]
|
del self.obj.db._recog_obj2recog[obj]
|
||||||
del self.obj.db._recog_obj2regex[obj]
|
del self.obj.db._recog_ref2recog[f"#{obj.id}"]
|
||||||
del self.obj.db._recog_ref2recog["#%i" % obj.id]
|
|
||||||
self._cache()
|
self._cache()
|
||||||
|
|
||||||
def get_regex_tuple(self, obj):
|
|
||||||
"""
|
|
||||||
Returns:
|
|
||||||
rec (tuple): Tuple (recog_regex, obj, recog)
|
|
||||||
"""
|
|
||||||
if obj in self.obj2recog and obj.access(self.obj, "enable_recog", default=True):
|
|
||||||
return self.obj2regex[obj], obj, self.obj2regex[obj]
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# RP Commands
|
# RP Commands
|
||||||
|
|
@ -994,8 +865,8 @@ class CmdEmote(RPCommand): # replaces the main emote
|
||||||
# we also include ourselves here.
|
# we also include ourselves here.
|
||||||
emote = self.args
|
emote = self.args
|
||||||
targets = self.caller.location.contents
|
targets = self.caller.location.contents
|
||||||
if not emote.endswith((".", "?", "!")): # If emote is not punctuated,
|
if not emote.endswith((".", "?", "!", '"')): # If emote is not punctuated or speech,
|
||||||
emote = "%s." % emote # add a full-stop for good measure.
|
emote += "." # add a full-stop for good measure.
|
||||||
send_emote(self.caller, targets, emote, anonymous_add="first")
|
send_emote(self.caller, targets, emote, anonymous_add="first")
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1025,7 +896,6 @@ class CmdSay(RPCommand): # replaces standard say
|
||||||
|
|
||||||
# calling the speech modifying hook
|
# calling the speech modifying hook
|
||||||
speech = caller.at_pre_say(self.args)
|
speech = caller.at_pre_say(self.args)
|
||||||
# preparing the speech with sdesc/speech parsing.
|
|
||||||
targets = self.caller.location.contents
|
targets = self.caller.location.contents
|
||||||
send_emote(self.caller, targets, speech, anonymous_add=None)
|
send_emote(self.caller, targets, speech, anonymous_add=None)
|
||||||
|
|
||||||
|
|
@ -1061,7 +931,7 @@ class CmdSdesc(RPCommand): # set/look at own sdesc
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
caller.msg(f"Cannot set sdesc on {caller.key}.")
|
caller.msg(f"Cannot set sdesc on {caller.key}.")
|
||||||
return
|
return
|
||||||
caller.msg("%s's sdesc was set to '%s'." % (caller.key, sdesc))
|
caller.msg(f"{caller.key}'s sdesc was set to '{sdesc}'.")
|
||||||
|
|
||||||
|
|
||||||
class CmdPose(RPCommand): # set current pose and default pose
|
class CmdPose(RPCommand): # set current pose and default pose
|
||||||
|
|
@ -1121,8 +991,8 @@ class CmdPose(RPCommand): # set current pose and default pose
|
||||||
caller.msg("Usage: pose <pose-text> OR pose obj = <pose-text>")
|
caller.msg("Usage: pose <pose-text> OR pose obj = <pose-text>")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not pose.endswith("."):
|
if not pose.endswith((".", "?", "!", '"')):
|
||||||
pose = "%s." % pose
|
pose += "."
|
||||||
if target:
|
if target:
|
||||||
# affect something else
|
# affect something else
|
||||||
target = caller.search(target)
|
target = caller.search(target)
|
||||||
|
|
@ -1134,18 +1004,18 @@ class CmdPose(RPCommand): # set current pose and default pose
|
||||||
else:
|
else:
|
||||||
target = caller
|
target = caller
|
||||||
|
|
||||||
|
target_name = target.sdesc.get() if hasattr(target, "sdesc") else target.key
|
||||||
if not target.attributes.has("pose"):
|
if not target.attributes.has("pose"):
|
||||||
caller.msg("%s cannot be posed." % target.key)
|
caller.msg(f"{target_name} cannot be posed.")
|
||||||
return
|
return
|
||||||
|
|
||||||
target_name = target.sdesc.get() if hasattr(target, "sdesc") else target.key
|
|
||||||
# set the pose
|
# set the pose
|
||||||
if self.reset:
|
if self.reset:
|
||||||
pose = target.db.pose_default
|
pose = target.db.pose_default
|
||||||
target.db.pose = pose
|
target.db.pose = pose
|
||||||
elif self.default:
|
elif self.default:
|
||||||
target.db.pose_default = pose
|
target.db.pose_default = pose
|
||||||
caller.msg("Default pose is now '%s %s'." % (target_name, pose))
|
caller.msg(f"Default pose is now '{target_name} {pose}'.")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
# set the pose. We do one-time ref->sdesc mapping here.
|
# set the pose. We do one-time ref->sdesc mapping here.
|
||||||
|
|
@ -1157,12 +1027,12 @@ class CmdPose(RPCommand): # set current pose and default pose
|
||||||
pose = parsed.format(**mapping)
|
pose = parsed.format(**mapping)
|
||||||
|
|
||||||
if len(target_name) + len(pose) > 60:
|
if len(target_name) + len(pose) > 60:
|
||||||
caller.msg("Your pose '%s' is too long." % pose)
|
caller.msg(f"'{pose}' is too long.")
|
||||||
return
|
return
|
||||||
|
|
||||||
target.db.pose = pose
|
target.db.pose = pose
|
||||||
|
|
||||||
caller.msg("Pose will read '%s %s'." % (target_name, pose))
|
caller.msg(f"Pose will read '{target_name} {pose}'.")
|
||||||
|
|
||||||
|
|
||||||
class CmdRecog(RPCommand): # assign personal alias to object in room
|
class CmdRecog(RPCommand): # assign personal alias to object in room
|
||||||
|
|
@ -1241,12 +1111,12 @@ class CmdRecog(RPCommand): # assign personal alias to object in room
|
||||||
caller.msg(_EMOTE_NOMATCH_ERROR.format(ref=sdesc))
|
caller.msg(_EMOTE_NOMATCH_ERROR.format(ref=sdesc))
|
||||||
elif nmatches > 1:
|
elif nmatches > 1:
|
||||||
reflist = [
|
reflist = [
|
||||||
"{}{}{} ({}{})".format(
|
"{num}{sep}{sdesc} ({recog}{key})".format(
|
||||||
inum + 1,
|
num=inum + 1,
|
||||||
_NUM_SEP,
|
sep=_NUM_SEP,
|
||||||
_RE_PREFIX.sub("", sdesc),
|
sdesc=_RE_PREFIX.sub("", sdesc),
|
||||||
caller.recog.get(obj),
|
recog=caller.recog.get(obj) or "no recog",
|
||||||
" (%s)" % caller.key if caller == obj else "",
|
key=f" ({caller.key})" if caller == obj else "",
|
||||||
)
|
)
|
||||||
for inum, obj in enumerate(matches)
|
for inum, obj in enumerate(matches)
|
||||||
]
|
]
|
||||||
|
|
@ -1262,7 +1132,7 @@ class CmdRecog(RPCommand): # assign personal alias to object in room
|
||||||
if forget_mode:
|
if forget_mode:
|
||||||
# remove existing recog
|
# remove existing recog
|
||||||
caller.recog.remove(obj)
|
caller.recog.remove(obj)
|
||||||
caller.msg("%s will now know them only as '%s'." % (caller.key, obj.recog.get(obj)))
|
caller.msg("You will now know them only as '{}'.".format( obj.get_display_name(caller, noid=True) ))
|
||||||
else:
|
else:
|
||||||
# set recog
|
# set recog
|
||||||
sdesc = obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key
|
sdesc = obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key
|
||||||
|
|
@ -1271,7 +1141,7 @@ class CmdRecog(RPCommand): # assign personal alias to object in room
|
||||||
except RecogError as err:
|
except RecogError as err:
|
||||||
caller.msg(err)
|
caller.msg(err)
|
||||||
return
|
return
|
||||||
caller.msg("%s will now remember |w%s|n as |w%s|n." % (caller.key, sdesc, alias))
|
caller.msg("You will now remember |w{}|n as |w{}|n.".format(sdesc, alias))
|
||||||
|
|
||||||
|
|
||||||
class CmdMask(RPCommand):
|
class CmdMask(RPCommand):
|
||||||
|
|
@ -1302,14 +1172,14 @@ class CmdMask(RPCommand):
|
||||||
caller.msg("You are already wearing a mask.")
|
caller.msg("You are already wearing a mask.")
|
||||||
return
|
return
|
||||||
sdesc = _RE_CHAREND.sub("", self.args)
|
sdesc = _RE_CHAREND.sub("", self.args)
|
||||||
sdesc = "%s |H[masked]|n" % sdesc
|
sdesc = f"{sdesc} |H[masked]|n"
|
||||||
if len(sdesc) > 60:
|
if len(sdesc) > 60:
|
||||||
caller.msg("Your masked sdesc is too long.")
|
caller.msg("Your masked sdesc is too long.")
|
||||||
return
|
return
|
||||||
caller.db.unmasked_sdesc = caller.sdesc.get()
|
caller.db.unmasked_sdesc = caller.sdesc.get()
|
||||||
caller.locks.add("enable_recog:false()")
|
caller.locks.add("enable_recog:false()")
|
||||||
caller.sdesc.add(sdesc)
|
caller.sdesc.add(sdesc)
|
||||||
caller.msg("You wear a mask as '%s'." % sdesc)
|
caller.msg(f"You wear a mask as '{sdesc}'.")
|
||||||
else:
|
else:
|
||||||
# unmask
|
# unmask
|
||||||
old_sdesc = caller.db.unmasked_sdesc
|
old_sdesc = caller.db.unmasked_sdesc
|
||||||
|
|
@ -1319,7 +1189,7 @@ class CmdMask(RPCommand):
|
||||||
del caller.db.unmasked_sdesc
|
del caller.db.unmasked_sdesc
|
||||||
caller.locks.remove("enable_recog")
|
caller.locks.remove("enable_recog")
|
||||||
caller.sdesc.add(old_sdesc)
|
caller.sdesc.add(old_sdesc)
|
||||||
caller.msg("You remove your mask and are again '%s'." % old_sdesc)
|
caller.msg(f"You remove your mask and are again '{old_sdesc}'.")
|
||||||
|
|
||||||
|
|
||||||
class RPSystemCmdSet(CmdSet):
|
class RPSystemCmdSet(CmdSet):
|
||||||
|
|
@ -1346,6 +1216,9 @@ class ContribRPObject(DefaultObject):
|
||||||
This class is meant as a mix-in or parent for objects 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 poses.
|
rp-heavy game. It implements the base functionality for poses.
|
||||||
"""
|
"""
|
||||||
|
@lazy_property
|
||||||
|
def sdesc(self):
|
||||||
|
return SdescHandler(self)
|
||||||
|
|
||||||
def at_object_creation(self):
|
def at_object_creation(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1357,6 +1230,10 @@ class ContribRPObject(DefaultObject):
|
||||||
self.db.pose = ""
|
self.db.pose = ""
|
||||||
self.db.pose_default = "is here."
|
self.db.pose_default = "is here."
|
||||||
|
|
||||||
|
# initializing sdesc
|
||||||
|
self.db._sdesc = ""
|
||||||
|
self.sdesc.add("Something")
|
||||||
|
|
||||||
def search(
|
def search(
|
||||||
self,
|
self,
|
||||||
searchdata,
|
searchdata,
|
||||||
|
|
@ -1529,6 +1406,22 @@ class ContribRPObject(DefaultObject):
|
||||||
multimatch_string=multimatch_string,
|
multimatch_string=multimatch_string,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_posed_sdesc(self, sdesc, **kwargs):
|
||||||
|
"""
|
||||||
|
Displays the object with its current pose string.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
pose (str): A string containing the object's sdesc and
|
||||||
|
current or default pose.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# get the current pose, or default if no pose is set
|
||||||
|
pose = self.db.pose or self.db.pose_default
|
||||||
|
|
||||||
|
# return formatted string, or sdesc as fallback
|
||||||
|
return f"{sdesc} {pose}" if pose else sdesc
|
||||||
|
|
||||||
|
|
||||||
def get_display_name(self, looker, **kwargs):
|
def get_display_name(self, looker, **kwargs):
|
||||||
"""
|
"""
|
||||||
Displays the name of the object in a viewer-aware manner.
|
Displays the name of the object in a viewer-aware manner.
|
||||||
|
|
@ -1539,28 +1432,41 @@ class ContribRPObject(DefaultObject):
|
||||||
|
|
||||||
Keyword Args:
|
Keyword Args:
|
||||||
pose (bool): Include the pose (if available) in the return.
|
pose (bool): Include the pose (if available) in the return.
|
||||||
|
ref (str): The reference marker found in string to replace.
|
||||||
|
This is on the form #{num}{case}, like '#12^', where
|
||||||
|
the number is a processing location in the string and the
|
||||||
|
case symbol indicates the case of the original tag input
|
||||||
|
- `t` - input was Titled, like /Tall
|
||||||
|
- `^` - input was all uppercase, like /TALL
|
||||||
|
- `v` - input was all lowercase, like /tall
|
||||||
|
- `~` - input case should be kept, or was mixed-case
|
||||||
|
noid (bool): Don't show DBREF even if viewer has control access.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
name (str): A string of the sdesc containing the name of the object,
|
name (str): A string of the sdesc containing the name of the object,
|
||||||
if this is defined.
|
if this is defined. By default, included the DBREF if this user
|
||||||
including the DBREF if this user is privileged to control
|
is privileged to control said object.
|
||||||
said object.
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
The RPObject version doesn't add color to its display.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
idstr = "(#%s)" % self.id if self.access(looker, access_type="control") else ""
|
ref = kwargs.get("ref","~")
|
||||||
|
|
||||||
if looker == self:
|
if looker == self:
|
||||||
|
# always show your own key
|
||||||
sdesc = self.key
|
sdesc = self.key
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
recog = looker.recog.get(self)
|
# get the sdesc looker should see
|
||||||
|
sdesc = looker.get_sdesc(self, ref=ref)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
recog = None
|
# use own sdesc as a fallback
|
||||||
sdesc = recog or (hasattr(self, "sdesc") and self.sdesc.get()) or self.key
|
sdesc = self.sdesc.get()
|
||||||
pose = " %s" % (self.db.pose or "") if kwargs.get("pose", False) else ""
|
|
||||||
return "%s%s%s" % (sdesc, idstr, pose)
|
# add dbref is looker has control access and `noid` is not set
|
||||||
|
if self.access(looker, access_type="control") and not kwargs.get("noid",False):
|
||||||
|
sdesc = f"{sdesc}(#{self.id})"
|
||||||
|
|
||||||
|
return self.get_posed_sdesc(sdesc) if kwargs.get("pose", False) else sdesc
|
||||||
|
|
||||||
|
|
||||||
def return_appearance(self, looker):
|
def return_appearance(self, looker):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1569,6 +1475,10 @@ class ContribRPObject(DefaultObject):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
looker (Object): Object doing the looking.
|
looker (Object): Object doing the looking.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string (str): A string containing the name, appearance and contents
|
||||||
|
of the object.
|
||||||
"""
|
"""
|
||||||
if not looker:
|
if not looker:
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -1592,6 +1502,7 @@ class ContribRPObject(DefaultObject):
|
||||||
string += "\n|wExits:|n " + ", ".join(exits)
|
string += "\n|wExits:|n " + ", ".join(exits)
|
||||||
if users or things:
|
if users or things:
|
||||||
string += "\n " + "\n ".join(users + things)
|
string += "\n " + "\n ".join(users + things)
|
||||||
|
|
||||||
return string
|
return string
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1608,11 +1519,6 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject):
|
||||||
This is a character class that has poses, sdesc and recog.
|
This is a character class that has poses, sdesc and recog.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Handlers
|
|
||||||
@lazy_property
|
|
||||||
def sdesc(self):
|
|
||||||
return SdescHandler(self)
|
|
||||||
|
|
||||||
@lazy_property
|
@lazy_property
|
||||||
def recog(self):
|
def recog(self):
|
||||||
return RecogHandler(self)
|
return RecogHandler(self)
|
||||||
|
|
@ -1627,29 +1533,45 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject):
|
||||||
|
|
||||||
Keyword Args:
|
Keyword Args:
|
||||||
pose (bool): Include the pose (if available) in the return.
|
pose (bool): Include the pose (if available) in the return.
|
||||||
|
ref (str): The reference marker found in string to replace.
|
||||||
|
This is on the form #{num}{case}, like '#12^', where
|
||||||
|
the number is a processing location in the string and the
|
||||||
|
case symbol indicates the case of the original tag input
|
||||||
|
- `t` - input was Titled, like /Tall
|
||||||
|
- `^` - input was all uppercase, like /TALL
|
||||||
|
- `v` - input was all lowercase, like /tall
|
||||||
|
- `~` - input case should be kept, or was mixed-case
|
||||||
|
noid (bool): Don't show DBREF even if viewer has control access.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
name (str): A string of the sdesc containing the name of the object,
|
name (str): A string of the sdesc containing the name of the object,
|
||||||
if this is defined.
|
if this is defined. By default, included the DBREF if this user
|
||||||
including the DBREF if this user is privileged to control
|
is privileged to control said object.
|
||||||
said object.
|
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
The RPCharacter version of this method colors its display to make
|
The RPCharacter version adds additional processing to sdescs to make
|
||||||
characters stand out from other objects.
|
characters stand out from other objects.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
idstr = "(#%s)" % self.id if self.access(looker, access_type="control") else ""
|
ref = kwargs.get("ref","~")
|
||||||
|
|
||||||
if looker == self:
|
if looker == self:
|
||||||
sdesc = self.key
|
# process your key as recog since you recognize yourself
|
||||||
|
sdesc = self.process_recog(self.key,self)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
recog = looker.recog.get(self)
|
# get the sdesc looker should see, with formatting
|
||||||
|
sdesc = looker.get_sdesc(self, process=True, ref=ref)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
recog = None
|
# use own sdesc as a fallback
|
||||||
sdesc = recog or (hasattr(self, "sdesc") and self.sdesc.get()) or self.key
|
sdesc = self.sdesc.get()
|
||||||
pose = " %s" % (self.db.pose or "is here.") if kwargs.get("pose", False) else ""
|
|
||||||
return "|c%s|n%s%s" % (sdesc, idstr, pose)
|
# add dbref is looker has control access and `noid` is not set
|
||||||
|
if self.access(looker, access_type="control") and not kwargs.get("noid",False):
|
||||||
|
sdesc = f"{sdesc}(#{self.id})"
|
||||||
|
|
||||||
|
return self.get_posed_sdesc(sdesc) if kwargs.get("pose", False) else sdesc
|
||||||
|
|
||||||
|
|
||||||
def at_object_creation(self):
|
def at_object_creation(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1658,10 +1580,8 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject):
|
||||||
super().at_object_creation()
|
super().at_object_creation()
|
||||||
|
|
||||||
self.db._sdesc = ""
|
self.db._sdesc = ""
|
||||||
self.db._sdesc_regex = ""
|
|
||||||
|
|
||||||
self.db._recog_ref2recog = {}
|
self.db._recog_ref2recog = {}
|
||||||
self.db._recog_obj2regex = {}
|
|
||||||
self.db._recog_obj2recog = {}
|
self.db._recog_obj2recog = {}
|
||||||
|
|
||||||
self.cmdset.add(RPSystemCmdSet, persistent=True)
|
self.cmdset.add(RPSystemCmdSet, persistent=True)
|
||||||
|
|
@ -1679,8 +1599,38 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if kwargs.get("whisper"):
|
if kwargs.get("whisper"):
|
||||||
return f'/me whispers "{message}"'
|
return f'/Me whispers "{message}"'
|
||||||
return f'/me says, "{message}"'
|
return f'/Me says, "{message}"'
|
||||||
|
|
||||||
|
def get_sdesc(self, obj, process=False, **kwargs):
|
||||||
|
"""
|
||||||
|
Single method to handle getting recogs with sdesc fallback in an
|
||||||
|
aware manner, to allow separate processing of recogs from sdescs.
|
||||||
|
Gets the sdesc or recog for obj from the view of self.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Object): the object whose sdesc or recog is being gotten
|
||||||
|
Keyword Args:
|
||||||
|
process (bool): If True, the sdesc/recog is run through the
|
||||||
|
appropriate process method for self - .process_sdesc or
|
||||||
|
.process_recog
|
||||||
|
"""
|
||||||
|
# always see own key
|
||||||
|
if obj == self:
|
||||||
|
recog = self.key
|
||||||
|
sdesc = self.key
|
||||||
|
else:
|
||||||
|
# first check if we have a recog for this object
|
||||||
|
recog = self.recog.get(obj)
|
||||||
|
# set sdesc to recog, using sdesc as a fallback, or the object's key if no sdesc
|
||||||
|
sdesc = recog or (hasattr(obj, "sdesc") and obj.sdesc.get()) or obj.key
|
||||||
|
|
||||||
|
if process:
|
||||||
|
# process the sdesc as a recog if a recog was found, else as an sdesc
|
||||||
|
sdesc = (self.process_recog if recog else self.process_sdesc)(sdesc, obj, **kwargs)
|
||||||
|
|
||||||
|
return sdesc
|
||||||
|
|
||||||
|
|
||||||
def process_sdesc(self, sdesc, obj, **kwargs):
|
def process_sdesc(self, sdesc, obj, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1721,7 +1671,7 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject):
|
||||||
sdesc = sdesc.upper()
|
sdesc = sdesc.upper()
|
||||||
elif "v" in ref:
|
elif "v" in ref:
|
||||||
sdesc = sdesc.lower()
|
sdesc = sdesc.lower()
|
||||||
return "|b%s|n" % sdesc
|
return f"|b{sdesc}|n"
|
||||||
|
|
||||||
def process_recog(self, recog, obj, **kwargs):
|
def process_recog(self, recog, obj, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1732,14 +1682,15 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject):
|
||||||
translated from the original sdesc at this point.
|
translated from the original sdesc at this point.
|
||||||
obj (Object): The object the recog:ed string belongs to.
|
obj (Object): The object the recog:ed string belongs to.
|
||||||
This is not used by default.
|
This is not used by default.
|
||||||
Kwargs:
|
|
||||||
ref (str): See process_sdesc.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
recog (str): The modified recog string.
|
recog (str): The modified recog string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.process_sdesc(recog, obj, **kwargs)
|
if not recog:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return f"|m{recog}|n"
|
||||||
|
|
||||||
def process_language(self, text, speaker, language, **kwargs):
|
def process_language(self, text, speaker, language, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1762,4 +1713,7 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject):
|
||||||
the evennia.contrib.rpg.rplanguage module.
|
the evennia.contrib.rpg.rplanguage module.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return "%s|w%s|n" % ("|W(%s)" % language if language else "", text)
|
return "{label}|w{text}|n".format(
|
||||||
|
label=f"|W({language})" if language else "",
|
||||||
|
text=text
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ recog01 = "Mr Receiver"
|
||||||
recog02 = "Mr Receiver2"
|
recog02 = "Mr Receiver2"
|
||||||
recog10 = "Mr Sender"
|
recog10 = "Mr Sender"
|
||||||
emote = 'With a flair, /me looks at /first and /colliding sdesc-guy. She says "This is a test."'
|
emote = 'With a flair, /me looks at /first and /colliding sdesc-guy. She says "This is a test."'
|
||||||
case_emote = "/me looks at /first, then /FIRST, /First and /Colliding twice."
|
case_emote = "/Me looks at /first. Then, /me looks at /FIRST, /First and /Colliding twice."
|
||||||
|
|
||||||
|
|
||||||
class TestRPSystem(BaseEvenniaTest):
|
class TestRPSystem(BaseEvenniaTest):
|
||||||
|
|
@ -113,41 +113,11 @@ class TestRPSystem(BaseEvenniaTest):
|
||||||
rpsystem.ContribRPCharacter, key="Receiver2", location=self.room
|
rpsystem.ContribRPCharacter, key="Receiver2", location=self.room
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_ordered_permutation_regex(self):
|
|
||||||
self.assertEqual(
|
|
||||||
rpsystem.ordered_permutation_regex(sdesc0),
|
|
||||||
"/[0-9]*-*A\\ nice\\ sender\\ of\\ emotes(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*nice\\ sender\\ of\\ emotes(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*A\\ nice\\ sender\\ of(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*sender\\ of\\ emotes(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*nice\\ sender\\ of(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*A\\ nice\\ sender(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*nice\\ sender(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*of\\ emotes(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*sender\\ of(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*A\\ nice(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*emotes(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*sender(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*nice(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*of(?=\\W|$)+|"
|
|
||||||
"/[0-9]*-*A(?=\\W|$)+",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_sdesc_handler(self):
|
def test_sdesc_handler(self):
|
||||||
self.speaker.sdesc.add(sdesc0)
|
self.speaker.sdesc.add(sdesc0)
|
||||||
self.assertEqual(self.speaker.sdesc.get(), sdesc0)
|
self.assertEqual(self.speaker.sdesc.get(), sdesc0)
|
||||||
self.speaker.sdesc.add("This is {#324} ignored")
|
self.speaker.sdesc.add("This is {#324} ignored")
|
||||||
self.assertEqual(self.speaker.sdesc.get(), "This is 324 ignored")
|
self.assertEqual(self.speaker.sdesc.get(), "This is 324 ignored")
|
||||||
self.speaker.sdesc.add("Testing three words")
|
|
||||||
self.assertEqual(
|
|
||||||
self.speaker.sdesc.get_regex_tuple()[0].pattern,
|
|
||||||
"/[0-9]*-*Testing\ three\ words(?=\W|$)+|"
|
|
||||||
"/[0-9]*-*Testing\ three(?=\W|$)+|"
|
|
||||||
"/[0-9]*-*three\ words(?=\W|$)+|"
|
|
||||||
"/[0-9]*-*Testing(?=\W|$)+|"
|
|
||||||
"/[0-9]*-*three(?=\W|$)+|"
|
|
||||||
"/[0-9]*-*words(?=\W|$)+",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_recog_handler(self):
|
def test_recog_handler(self):
|
||||||
self.speaker.sdesc.add(sdesc0)
|
self.speaker.sdesc.add(sdesc0)
|
||||||
|
|
@ -156,12 +126,8 @@ class TestRPSystem(BaseEvenniaTest):
|
||||||
self.speaker.recog.add(self.receiver2, recog02)
|
self.speaker.recog.add(self.receiver2, recog02)
|
||||||
self.assertEqual(self.speaker.recog.get(self.receiver1), recog01)
|
self.assertEqual(self.speaker.recog.get(self.receiver1), recog01)
|
||||||
self.assertEqual(self.speaker.recog.get(self.receiver2), recog02)
|
self.assertEqual(self.speaker.recog.get(self.receiver2), recog02)
|
||||||
self.assertEqual(
|
|
||||||
self.speaker.recog.get_regex_tuple(self.receiver1)[0].pattern,
|
|
||||||
"/[0-9]*-*Mr\\ Receiver(?=\\W|$)+|/[0-9]*-*Receiver(?=\\W|$)+|/[0-9]*-*Mr(?=\\W|$)+",
|
|
||||||
)
|
|
||||||
self.speaker.recog.remove(self.receiver1)
|
self.speaker.recog.remove(self.receiver1)
|
||||||
self.assertEqual(self.speaker.recog.get(self.receiver1), sdesc1)
|
self.assertEqual(self.speaker.recog.get(self.receiver1), None)
|
||||||
|
|
||||||
self.assertEqual(self.speaker.recog.all(), {"Mr Receiver2": self.receiver2})
|
self.assertEqual(self.speaker.recog.all(), {"Mr Receiver2": self.receiver2})
|
||||||
|
|
||||||
|
|
@ -198,6 +164,24 @@ class TestRPSystem(BaseEvenniaTest):
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_get_sdesc(self):
|
||||||
|
looker = self.speaker # Sender
|
||||||
|
target = self.receiver1 # Receiver1
|
||||||
|
looker.sdesc.add(sdesc0) # A nice sender of emotes
|
||||||
|
target.sdesc.add(sdesc1) # The first receiver of emotes.
|
||||||
|
|
||||||
|
# sdesc with no processing
|
||||||
|
self.assertEqual(looker.get_sdesc(target), "The first receiver of emotes.")
|
||||||
|
# sdesc with processing
|
||||||
|
self.assertEqual(looker.get_sdesc(target, process=True), "|bThe first receiver of emotes.|n")
|
||||||
|
|
||||||
|
looker.recog.add(target, recog01) # Mr Receiver
|
||||||
|
|
||||||
|
# recog with no processing
|
||||||
|
self.assertEqual(looker.get_sdesc(target), "Mr Receiver")
|
||||||
|
# recog with processing
|
||||||
|
self.assertEqual(looker.get_sdesc(target, process=True), "|mMr Receiver|n")
|
||||||
|
|
||||||
def test_send_emote(self):
|
def test_send_emote(self):
|
||||||
speaker = self.speaker
|
speaker = self.speaker
|
||||||
receiver1 = self.receiver1
|
receiver1 = self.receiver1
|
||||||
|
|
@ -212,18 +196,18 @@ class TestRPSystem(BaseEvenniaTest):
|
||||||
rpsystem.send_emote(speaker, receivers, emote, case_sensitive=False)
|
rpsystem.send_emote(speaker, receivers, emote, case_sensitive=False)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.out0,
|
self.out0,
|
||||||
"With a flair, |bSender|n looks at |bThe first receiver of emotes.|n "
|
"With a flair, |mSender|n looks at |bThe first receiver of emotes.|n "
|
||||||
'and |bAnother nice colliding sdesc-guy for tests|n. She says |w"This is a test."|n',
|
'and |bAnother nice colliding sdesc-guy for tests|n. She says |w"This is a test."|n',
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.out1,
|
self.out1,
|
||||||
"With a flair, |bA nice sender of emotes|n looks at |bReceiver1|n and "
|
"With a flair, |bA nice sender of emotes|n looks at |mReceiver1|n and "
|
||||||
'|bAnother nice colliding sdesc-guy for tests|n. She says |w"This is a test."|n',
|
'|bAnother nice colliding sdesc-guy for tests|n. She says |w"This is a test."|n',
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.out2,
|
self.out2,
|
||||||
"With a flair, |bA nice sender of emotes|n looks at |bThe first "
|
"With a flair, |bA nice sender of emotes|n looks at |bThe first "
|
||||||
'receiver of emotes.|n and |bReceiver2|n. She says |w"This is a test."|n',
|
'receiver of emotes.|n and |mReceiver2|n. She says |w"This is a test."|n',
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_send_case_sensitive_emote(self):
|
def test_send_case_sensitive_emote(self):
|
||||||
|
|
@ -241,20 +225,21 @@ class TestRPSystem(BaseEvenniaTest):
|
||||||
rpsystem.send_emote(speaker, receivers, case_emote)
|
rpsystem.send_emote(speaker, receivers, case_emote)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.out0,
|
self.out0,
|
||||||
"|bSender|n looks at |bthe first receiver of emotes.|n, then "
|
"|mSender|n looks at |bthe first receiver of emotes.|n. Then, |mSender|n "
|
||||||
"|bTHE FIRST RECEIVER OF EMOTES.|n, |bThe first receiver of emotes.|n and "
|
"looks at |bTHE FIRST RECEIVER OF EMOTES.|n, |bThe first receiver of emotes.|n "
|
||||||
"|bAnother nice colliding sdesc-guy for tests|n twice.",
|
"and |bAnother nice colliding sdesc-guy for tests|n twice.",
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.out1,
|
self.out1,
|
||||||
"|bA nice sender of emotes|n looks at |bReceiver1|n, then |bReceiver1|n, "
|
"|bA nice sender of emotes|n looks at |mReceiver1|n. Then, "
|
||||||
"|bReceiver1|n and |bAnother nice colliding sdesc-guy for tests|n twice.",
|
"|ba nice sender of emotes|n looks at |mReceiver1|n, |mReceiver1|n "
|
||||||
|
"and |bAnother nice colliding sdesc-guy for tests|n twice."
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.out2,
|
self.out2,
|
||||||
"|bA nice sender of emotes|n looks at |bthe first receiver of emotes.|n, "
|
"|bA nice sender of emotes|n looks at |bthe first receiver of emotes.|n. "
|
||||||
"then |bTHE FIRST RECEIVER OF EMOTES.|n, |bThe first receiver of "
|
"Then, |ba nice sender of emotes|n looks at |bTHE FIRST RECEIVER OF EMOTES.|n, "
|
||||||
"emotes.|n and |bReceiver2|n twice.",
|
"|bThe first receiver of emotes.|n and |mReceiver2|n twice.",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_rpsearch(self):
|
def test_rpsearch(self):
|
||||||
|
|
@ -265,18 +250,6 @@ class TestRPSystem(BaseEvenniaTest):
|
||||||
self.assertEqual(self.speaker.search("receiver of emotes"), self.receiver1)
|
self.assertEqual(self.speaker.search("receiver of emotes"), self.receiver1)
|
||||||
self.assertEqual(self.speaker.search("colliding"), self.receiver2)
|
self.assertEqual(self.speaker.search("colliding"), self.receiver2)
|
||||||
|
|
||||||
def test_regex_tuple_from_key_alias(self):
|
|
||||||
self.speaker.aliases.add("foo bar")
|
|
||||||
self.speaker.aliases.add("this thing is a long thing")
|
|
||||||
t0 = time.time()
|
|
||||||
result = rpsystem.regex_tuple_from_key_alias(self.speaker)
|
|
||||||
t1 = time.time()
|
|
||||||
result = rpsystem.regex_tuple_from_key_alias(self.speaker)
|
|
||||||
t2 = time.time()
|
|
||||||
# print(f"t1: {t1 - t0}, t2: {t2 - t1}")
|
|
||||||
self.assertLess(t2 - t1, 10**-4)
|
|
||||||
self.assertEqual(result, (Anything, self.speaker, self.speaker.key))
|
|
||||||
|
|
||||||
|
|
||||||
class TestRPSystemCommands(BaseEvenniaCommandTest):
|
class TestRPSystemCommands(BaseEvenniaCommandTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
@ -305,7 +278,7 @@ class TestRPSystemCommands(BaseEvenniaCommandTest):
|
||||||
self.call(
|
self.call(
|
||||||
rpsystem.CmdRecog(),
|
rpsystem.CmdRecog(),
|
||||||
"barfoo as friend",
|
"barfoo as friend",
|
||||||
"Char will now remember BarFoo Character as friend.",
|
"You will now remember BarFoo Character as friend.",
|
||||||
)
|
)
|
||||||
self.call(
|
self.call(
|
||||||
rpsystem.CmdRecog(),
|
rpsystem.CmdRecog(),
|
||||||
|
|
@ -316,6 +289,6 @@ class TestRPSystemCommands(BaseEvenniaCommandTest):
|
||||||
self.call(
|
self.call(
|
||||||
rpsystem.CmdRecog(),
|
rpsystem.CmdRecog(),
|
||||||
"friend",
|
"friend",
|
||||||
"Char will now know them only as 'BarFoo Character'",
|
"You will now know them only as 'BarFoo Character'",
|
||||||
cmdstring="forget",
|
cmdstring="forget",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue