Resolve merge conflicts
This commit is contained in:
commit
862d2a5d06
9 changed files with 228 additions and 121 deletions
|
|
@ -77,7 +77,9 @@ without arguments starts a full interactive Python console.
|
||||||
- `list_to_string` is now `iter_to_string` (but old name still works as legacy alias). It will
|
- `list_to_string` is now `iter_to_string` (but old name still works as legacy alias). It will
|
||||||
now accept any input, including generators and single values.
|
now accept any input, including generators and single values.
|
||||||
- EvTable should now correctly handle columns with wider asian-characters in them.
|
- EvTable should now correctly handle columns with wider asian-characters in them.
|
||||||
|
- Update Twisted requirement to >=2.3.0 to close security vulnerability
|
||||||
|
- Add `$random` inlinefunc, supports minval,maxval arguments that can be ints and floats.
|
||||||
|
- Add `evennia.utils.inlinefuncs.raw(<str>)` as a helper to escape inlinefuncs in a string.
|
||||||
|
|
||||||
|
|
||||||
## Evennia 0.9 (2018-2019)
|
## Evennia 0.9 (2018-2019)
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,13 @@ from evennia.utils.utils import (
|
||||||
dbref,
|
dbref,
|
||||||
interactive,
|
interactive,
|
||||||
list_to_string,
|
list_to_string,
|
||||||
|
display_len,
|
||||||
)
|
)
|
||||||
from evennia.utils.eveditor import EvEditor
|
from evennia.utils.eveditor import EvEditor
|
||||||
from evennia.utils.evmore import EvMore
|
from evennia.utils.evmore import EvMore
|
||||||
from evennia.prototypes import spawner, prototypes as protlib, menus as olc_menus
|
from evennia.prototypes import spawner, prototypes as protlib, menus as olc_menus
|
||||||
from evennia.utils.ansi import raw
|
from evennia.utils.ansi import raw as ansi_raw
|
||||||
|
from evennia.utils.inlinefuncs import raw as inlinefunc_raw
|
||||||
|
|
||||||
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
||||||
|
|
||||||
|
|
@ -2357,26 +2359,37 @@ class CmdExamine(ObjManipCommand):
|
||||||
arg_regex = r"(/\w+?(\s|$))|\s|$"
|
arg_regex = r"(/\w+?(\s|$))|\s|$"
|
||||||
|
|
||||||
account_mode = False
|
account_mode = False
|
||||||
|
detail_color = "|c"
|
||||||
|
header_color = "|w"
|
||||||
|
quell_color = "|r"
|
||||||
|
separator = "-"
|
||||||
|
|
||||||
def list_attribute(self, crop, attr, category, value):
|
def list_attribute(self, crop, attr, category, value):
|
||||||
"""
|
"""
|
||||||
Formats a single attribute line.
|
Formats a single attribute line.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
crop (bool): If output should be cropped if too long.
|
||||||
|
attr (str): Attribute key.
|
||||||
|
category (str): Attribute category.
|
||||||
|
value (any): Attribute value.
|
||||||
|
Returns:
|
||||||
"""
|
"""
|
||||||
if crop:
|
if crop:
|
||||||
if not isinstance(value, str):
|
if not isinstance(value, str):
|
||||||
value = utils.to_str(value)
|
value = utils.to_str(value)
|
||||||
value = utils.crop(value)
|
value = utils.crop(value)
|
||||||
|
value = inlinefunc_raw(ansi_raw(value))
|
||||||
if category:
|
if category:
|
||||||
string = "\n %s[%s] = %s" % (attr, category, value)
|
return f"{attr}[{category}] = {value}"
|
||||||
else:
|
else:
|
||||||
string = "\n %s = %s" % (attr, value)
|
return f"{attr} = {value}"
|
||||||
string = raw(string)
|
|
||||||
return string
|
|
||||||
|
|
||||||
def format_attributes(self, obj, attrname=None, crop=True):
|
def format_attributes(self, obj, attrname=None, crop=True):
|
||||||
"""
|
"""
|
||||||
Helper function that returns info about attributes and/or
|
Helper function that returns info about attributes and/or
|
||||||
non-persistent data stored on object
|
non-persistent data stored on object
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if attrname:
|
if attrname:
|
||||||
|
|
@ -2391,81 +2404,108 @@ class CmdExamine(ObjManipCommand):
|
||||||
ndb_attr = obj.nattributes.all(return_tuples=True)
|
ndb_attr = obj.nattributes.all(return_tuples=True)
|
||||||
except Exception:
|
except Exception:
|
||||||
ndb_attr = None
|
ndb_attr = None
|
||||||
string = ""
|
output = {}
|
||||||
if db_attr and db_attr[0]:
|
if db_attr and db_attr[0]:
|
||||||
string += "\n|wPersistent attributes|n:"
|
output["Persistent attribute(s)"] = "\n " + "\n ".join(
|
||||||
for attr, value, category in db_attr:
|
sorted(self.list_attribute(crop, attr, category, value)
|
||||||
string += self.list_attribute(crop, attr, category, value)
|
for attr, value, category in db_attr)
|
||||||
|
)
|
||||||
if ndb_attr and ndb_attr[0]:
|
if ndb_attr and ndb_attr[0]:
|
||||||
string += "\n|wNon-Persistent attributes|n:"
|
output["Non-Persistent attribute(s)"] = " \n" + " \n".join(
|
||||||
for attr, value in ndb_attr:
|
sorted(self.list_attribute(crop, attr, None, value)
|
||||||
string += self.list_attribute(crop, attr, None, value)
|
for attr, value in ndb_attr)
|
||||||
return string
|
)
|
||||||
|
return output
|
||||||
|
|
||||||
def format_output(self, obj, avail_cmdset):
|
def format_output(self, obj, avail_cmdset):
|
||||||
"""
|
"""
|
||||||
Helper function that creates a nice report about an object.
|
Helper function that creates a nice report about an object.
|
||||||
|
|
||||||
returns a string.
|
Args:
|
||||||
|
obj (any): Object to analyze.
|
||||||
|
avail_cmdset (CmdSet): Current cmdset for object.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The formatted string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
string = "\n|wName/key|n: |c%s|n (%s)" % (obj.name, obj.dbref)
|
hclr = self.header_color
|
||||||
|
dclr = self.detail_color
|
||||||
|
qclr = self.quell_color
|
||||||
|
|
||||||
|
output = {}
|
||||||
|
# main key
|
||||||
|
output["Name/key"] = f"{dclr}{obj.name}|n ({obj.dbref})"
|
||||||
|
# aliases
|
||||||
if hasattr(obj, "aliases") and obj.aliases.all():
|
if hasattr(obj, "aliases") and obj.aliases.all():
|
||||||
string += "\n|wAliases|n: %s" % (", ".join(utils.make_iter(str(obj.aliases))))
|
output["Aliases"] = ", ".join(utils.make_iter(str(obj.aliases)))
|
||||||
|
# typeclass
|
||||||
|
output["Typeclass"] = f"{obj.typename} ({obj.typeclass_path})"
|
||||||
|
# sessions
|
||||||
if hasattr(obj, "sessions") and obj.sessions.all():
|
if hasattr(obj, "sessions") and obj.sessions.all():
|
||||||
string += "\n|wSession id(s)|n: %s" % (
|
output["Session id(s)"] = ", ".join(f"#{sess.sessid}" for sess in obj.sessions.all())
|
||||||
", ".join("#%i" % sess.sessid for sess in obj.sessions.all())
|
# email, if any
|
||||||
)
|
|
||||||
if hasattr(obj, "email") and obj.email:
|
if hasattr(obj, "email") and obj.email:
|
||||||
string += "\n|wEmail|n: |c%s|n" % obj.email
|
output["Email"] = f"{dclr}{obj.email}|n"
|
||||||
|
# account, for puppeted objects
|
||||||
if hasattr(obj, "has_account") and obj.has_account:
|
if hasattr(obj, "has_account") and obj.has_account:
|
||||||
string += "\n|wAccount|n: |c%s|n" % obj.account.name
|
output["Account"] = f"{dclr}{obj.account.name}|n ({obj.account.dbref})"
|
||||||
|
# account typeclass
|
||||||
|
output[" Account Typeclass"] = f"{obj.account.typename} ({obj.account.typeclass_path})"
|
||||||
|
# account permissions
|
||||||
perms = obj.account.permissions.all()
|
perms = obj.account.permissions.all()
|
||||||
if obj.account.is_superuser:
|
if obj.account.is_superuser:
|
||||||
perms = ["<Superuser>"]
|
perms = ["<Superuser>"]
|
||||||
elif not perms:
|
elif not perms:
|
||||||
perms = ["<None>"]
|
perms = ["<None>"]
|
||||||
string += "\n|wAccount Perms|n: %s" % (", ".join(perms))
|
perms = ", ".join(perms)
|
||||||
if obj.account.attributes.has("_quell"):
|
if obj.account.attributes.has("_quell"):
|
||||||
string += " |r(quelled)|n"
|
perms += f" {qclr}(quelled)|n"
|
||||||
string += "\n|wTypeclass|n: %s (%s)" % (obj.typename, obj.typeclass_path)
|
output[" Account Permissions"] = perms
|
||||||
|
# location
|
||||||
if hasattr(obj, "location"):
|
if hasattr(obj, "location"):
|
||||||
string += "\n|wLocation|n: %s" % obj.location
|
loc = str(obj.location)
|
||||||
if obj.location:
|
if obj.location:
|
||||||
string += " (#%s)" % obj.location.id
|
loc += f" (#{obj.location.id})"
|
||||||
|
output["Location"] = loc
|
||||||
|
# home
|
||||||
if hasattr(obj, "home"):
|
if hasattr(obj, "home"):
|
||||||
string += "\n|wHome|n: %s" % obj.home
|
home = str(obj.home)
|
||||||
if obj.home:
|
if obj.home:
|
||||||
string += " (#%s)" % obj.home.id
|
home += f" (#{obj.home.id})"
|
||||||
|
output["Home"] = home
|
||||||
|
# destination, for exits
|
||||||
if hasattr(obj, "destination") and obj.destination:
|
if hasattr(obj, "destination") and obj.destination:
|
||||||
string += "\n|wDestination|n: %s" % obj.destination
|
dest = str(obj.destination)
|
||||||
if obj.destination:
|
if obj.destination:
|
||||||
string += " (#%s)" % obj.destination.id
|
dest += f" (#{obj.destination.id})"
|
||||||
|
output["Destination"] = dest
|
||||||
|
# main permissions
|
||||||
perms = obj.permissions.all()
|
perms = obj.permissions.all()
|
||||||
|
perms_string = ""
|
||||||
if perms:
|
if perms:
|
||||||
perms_string = ", ".join(perms)
|
perms_string = ", ".join(perms)
|
||||||
else:
|
|
||||||
perms_string = "<None>"
|
|
||||||
if obj.is_superuser:
|
if obj.is_superuser:
|
||||||
perms_string += " [Superuser]"
|
perms_string += " <Superuser>"
|
||||||
|
if perms_string:
|
||||||
string += "\n|wPermissions|n: %s" % perms_string
|
output["Permissions"] = perms_string
|
||||||
|
# locks
|
||||||
locks = str(obj.locks)
|
locks = str(obj.locks)
|
||||||
if locks:
|
if locks:
|
||||||
locks_string = utils.fill("; ".join([lock for lock in locks.split(";")]), indent=6)
|
locks_string = "\n" + utils.fill(
|
||||||
|
"; ".join([lock for lock in locks.split(";")]), indent=2)
|
||||||
else:
|
else:
|
||||||
locks_string = " Default"
|
locks_string = " Default"
|
||||||
string += "\n|wLocks|n:%s" % locks_string
|
output["Locks"] = locks_string
|
||||||
|
# cmdsets
|
||||||
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "_EMPTY_CMDSET"):
|
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "_EMPTY_CMDSET"):
|
||||||
# all() returns a 'stack', so make a copy to sort.
|
# all() returns a 'stack', so make a copy to sort.
|
||||||
stored_cmdsets = sorted(obj.cmdset.all(), key=lambda x: x.priority, reverse=True)
|
stored_cmdsets = sorted(obj.cmdset.all(), key=lambda x: x.priority,
|
||||||
string += "\n|wStored Cmdset(s)|n:\n %s" % (
|
reverse=True)
|
||||||
"\n ".join(
|
output["Stored Cmdset(s)"] = (
|
||||||
"%s [%s] (%s, prio %s)"
|
"\n " + "\n ".join(
|
||||||
% (cmdset.path, cmdset.key, cmdset.mergetype, cmdset.priority)
|
f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype}, prio {cmdset.priority})"
|
||||||
for cmdset in stored_cmdsets
|
for cmdset in stored_cmdsets if cmdset.key != "_EMPTY_CMDSET"
|
||||||
if cmdset.key != "_EMPTY_CMDSET"
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -2500,40 +2540,32 @@ class CmdExamine(ObjManipCommand):
|
||||||
pass
|
pass
|
||||||
all_cmdsets = [cmdset for cmdset in dict(all_cmdsets).values()]
|
all_cmdsets = [cmdset for cmdset in dict(all_cmdsets).values()]
|
||||||
all_cmdsets.sort(key=lambda x: x.priority, reverse=True)
|
all_cmdsets.sort(key=lambda x: x.priority, reverse=True)
|
||||||
string += "\n|wMerged Cmdset(s)|n:\n %s" % (
|
output["Merged Cmdset(s)"] = (
|
||||||
"\n ".join(
|
"\n " + "\n ".join(
|
||||||
"%s [%s] (%s, prio %s)"
|
f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype} prio {cmdset.priority})"
|
||||||
% (cmdset.path, cmdset.key, cmdset.mergetype, cmdset.priority)
|
|
||||||
for cmdset in all_cmdsets
|
for cmdset in all_cmdsets
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# list the commands available to this object
|
# list the commands available to this object
|
||||||
avail_cmdset = sorted([cmd.key for cmd in avail_cmdset if cmd.access(obj, "cmd")])
|
avail_cmdset = sorted([cmd.key for cmd in avail_cmdset if cmd.access(obj, "cmd")])
|
||||||
|
|
||||||
cmdsetstr = utils.fill(", ".join(avail_cmdset), indent=2)
|
cmdsetstr = "\n" + utils.fill(", ".join(avail_cmdset), indent=2)
|
||||||
string += "\n|wCommands available to %s (result of Merged CmdSets)|n:\n %s" % (
|
output[f"Commands available to {obj.key} (result of Merged CmdSets)"] = str(cmdsetstr)
|
||||||
obj.key,
|
# scripts
|
||||||
cmdsetstr,
|
|
||||||
)
|
|
||||||
|
|
||||||
if hasattr(obj, "scripts") and hasattr(obj.scripts, "all") and obj.scripts.all():
|
if hasattr(obj, "scripts") and hasattr(obj.scripts, "all") and obj.scripts.all():
|
||||||
string += "\n|wScripts|n:\n %s" % obj.scripts
|
output["Scripts"] = "\n " + f"{obj.scripts}"
|
||||||
# add the attributes
|
# add the attributes
|
||||||
string += self.format_attributes(obj)
|
output.update(self.format_attributes(obj))
|
||||||
|
# Tags
|
||||||
# display Tags
|
tags = obj.tags.all(return_key_and_category=True)
|
||||||
tags_string = utils.fill(
|
tags_string = "\n" + utils.fill(
|
||||||
", ".join(
|
", ".join(
|
||||||
"%s[%s]" % (tag, category)
|
sorted(f"{tag}[{category}]" for tag, category in tags )),
|
||||||
for tag, category in obj.tags.all(return_key_and_category=True)
|
indent=2,
|
||||||
),
|
|
||||||
indent=5,
|
|
||||||
)
|
)
|
||||||
if tags_string:
|
if tags:
|
||||||
string += "\n|wTags[category]|n: %s" % tags_string.strip()
|
output["Tags[category]"] = tags_string
|
||||||
|
# Contents of object
|
||||||
# add the contents
|
|
||||||
exits = []
|
exits = []
|
||||||
pobjs = []
|
pobjs = []
|
||||||
things = []
|
things = []
|
||||||
|
|
@ -2546,24 +2578,23 @@ class CmdExamine(ObjManipCommand):
|
||||||
else:
|
else:
|
||||||
things.append(content)
|
things.append(content)
|
||||||
if exits:
|
if exits:
|
||||||
string += "\n|wExits|n: %s" % ", ".join(
|
output["Exits (has .destination)"] = ", ".join(f"{exit.name}({exit.dbref})" for exit in exits)
|
||||||
["%s(%s)" % (exit.name, exit.dbref) for exit in exits]
|
|
||||||
)
|
|
||||||
if pobjs:
|
if pobjs:
|
||||||
string += "\n|wCharacters|n: %s" % ", ".join(
|
output["Characters"] = ", ".join(f"{dclr}{pobj.name}|n({pobj.dbref})" for pobj in pobjs)
|
||||||
["|c%s|n(%s)" % (pobj.name, pobj.dbref) for pobj in pobjs]
|
|
||||||
)
|
|
||||||
if things:
|
if things:
|
||||||
string += "\n|wContents|n: %s" % ", ".join(
|
output["Contents"] = ", ".join(
|
||||||
[
|
f"{cont.name}({cont.dbref})"
|
||||||
"%s(%s)" % (cont.name, cont.dbref)
|
for cont in obj.contents
|
||||||
for cont in obj.contents
|
if cont not in exits and cont not in pobjs
|
||||||
if cont not in exits and cont not in pobjs
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
separator = "-" * _DEFAULT_WIDTH
|
# format output
|
||||||
# output info
|
max_width = -1
|
||||||
return "%s\n%s\n%s" % (separator, string.strip(), separator)
|
for block in output.values():
|
||||||
|
max_width = max(max_width, max(display_len(line) for line in block.split("\n")))
|
||||||
|
sep = self.separator * max_width
|
||||||
|
mainstr = "\n".join(f"{hclr}{header}|n: {block}" for (header, block) in output.items())
|
||||||
|
return f"{sep}\n{mainstr}\n{sep}"
|
||||||
|
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
"""Process command"""
|
"""Process command"""
|
||||||
|
|
@ -2578,8 +2609,7 @@ class CmdExamine(ObjManipCommand):
|
||||||
that function finishes. Taking the resulting cmdset, we continue
|
that function finishes. Taking the resulting cmdset, we continue
|
||||||
to format and output the result.
|
to format and output the result.
|
||||||
"""
|
"""
|
||||||
string = self.format_output(obj, cmdset)
|
self.msg(self.format_output(obj, cmdset).strip())
|
||||||
self.msg(string.strip())
|
|
||||||
|
|
||||||
if not self.args:
|
if not self.args:
|
||||||
# If no arguments are provided, examine the invoker's location.
|
# If no arguments are provided, examine the invoker's location.
|
||||||
|
|
@ -2633,7 +2663,10 @@ class CmdExamine(ObjManipCommand):
|
||||||
if obj_attrs:
|
if obj_attrs:
|
||||||
for attrname in obj_attrs:
|
for attrname in obj_attrs:
|
||||||
# we are only interested in specific attributes
|
# we are only interested in specific attributes
|
||||||
caller.msg(self.format_attributes(obj, attrname, crop=False))
|
ret = "\n".join(
|
||||||
|
f"{self.header_color}{header}|n:{value}"
|
||||||
|
for header, value in self.format_attributes(obj, attrname, crop=False).items())
|
||||||
|
self.caller.msg(ret)
|
||||||
else:
|
else:
|
||||||
session = None
|
session = None
|
||||||
if obj.sessions.count():
|
if obj.sessions.count():
|
||||||
|
|
|
||||||
|
|
@ -150,11 +150,17 @@ class CommandTest(EvenniaTest):
|
||||||
returned_msg = msg_sep.join(
|
returned_msg = msg_sep.join(
|
||||||
_RE.sub("", ansi.parse_ansi(mess, strip_ansi=noansi)) for mess in stored_msg
|
_RE.sub("", ansi.parse_ansi(mess, strip_ansi=noansi)) for mess in stored_msg
|
||||||
).strip()
|
).strip()
|
||||||
if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()):
|
msg = msg.strip()
|
||||||
|
if msg == "" and returned_msg or not returned_msg.startswith(msg):
|
||||||
|
prt = ""
|
||||||
|
for ic, char in enumerate(msg):
|
||||||
|
import re
|
||||||
|
prt += char
|
||||||
|
|
||||||
sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n"
|
sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n"
|
||||||
sep2 = "\n" + "=" * 30 + "Returned message" + "=" * 32 + "\n"
|
sep2 = "\n" + "=" * 30 + "Returned message" + "=" * 32 + "\n"
|
||||||
sep3 = "\n" + "=" * 78
|
sep3 = "\n" + "=" * 78
|
||||||
retval = sep1 + msg.strip() + sep2 + returned_msg + sep3
|
retval = sep1 + msg + sep2 + returned_msg + sep3
|
||||||
raise AssertionError(retval)
|
raise AssertionError(retval)
|
||||||
else:
|
else:
|
||||||
returned_msg = "\n".join(str(msg) for msg in stored_msg)
|
returned_msg = "\n".join(str(msg) for msg in stored_msg)
|
||||||
|
|
@ -470,10 +476,14 @@ class TestBuilding(CommandTest):
|
||||||
self.call(building.CmdExamine(), "*TestAccount", "Name/key: TestAccount")
|
self.call(building.CmdExamine(), "*TestAccount", "Name/key: TestAccount")
|
||||||
|
|
||||||
self.char1.db.test = "testval"
|
self.char1.db.test = "testval"
|
||||||
self.call(building.CmdExamine(), "self/test", "Persistent attributes:\n test = testval")
|
self.call(building.CmdExamine(), "self/test", "Persistent attribute(s):\n test = testval")
|
||||||
self.call(building.CmdExamine(), "NotFound", "Could not find 'NotFound'.")
|
self.call(building.CmdExamine(), "NotFound", "Could not find 'NotFound'.")
|
||||||
self.call(building.CmdExamine(), "out", "Name/key: out")
|
self.call(building.CmdExamine(), "out", "Name/key: out")
|
||||||
|
|
||||||
|
# escape inlinefuncs
|
||||||
|
self.char1.db.test2 = "this is a $random() value."
|
||||||
|
self.call(building.CmdExamine(), "self/test2", "Persistent attribute(s):\n test2 = this is a \$random() value.")
|
||||||
|
|
||||||
self.room1.scripts.add(self.script.__class__)
|
self.room1.scripts.add(self.script.__class__)
|
||||||
self.call(building.CmdExamine(), "")
|
self.call(building.CmdExamine(), "")
|
||||||
self.account.scripts.add(self.script.__class__)
|
self.account.scripts.add(self.script.__class__)
|
||||||
|
|
|
||||||
|
|
@ -125,14 +125,14 @@ CURLY_COLOR_ANSI_EXTRA_MAP = [
|
||||||
(r"{c", _ANSI_HILITE + _ANSI_CYAN),
|
(r"{c", _ANSI_HILITE + _ANSI_CYAN),
|
||||||
(r"{w", _ANSI_HILITE + _ANSI_WHITE), # pure white
|
(r"{w", _ANSI_HILITE + _ANSI_WHITE), # pure white
|
||||||
(r"{x", _ANSI_HILITE + _ANSI_BLACK), # dark grey
|
(r"{x", _ANSI_HILITE + _ANSI_BLACK), # dark grey
|
||||||
(r"{R", _ANSI_HILITE + _ANSI_RED),
|
(r"{R", _ANSI_UNHILITE + _ANSI_RED),
|
||||||
(r"{G", _ANSI_HILITE + _ANSI_GREEN),
|
(r"{G", _ANSI_UNHILITE + _ANSI_GREEN),
|
||||||
(r"{Y", _ANSI_HILITE + _ANSI_YELLOW),
|
(r"{Y", _ANSI_UNHILITE + _ANSI_YELLOW),
|
||||||
(r"{B", _ANSI_HILITE + _ANSI_BLUE),
|
(r"{B", _ANSI_UNHILITE + _ANSI_BLUE),
|
||||||
(r"{M", _ANSI_HILITE + _ANSI_MAGENTA),
|
(r"{M", _ANSI_UNHILITE + _ANSI_MAGENTA),
|
||||||
(r"{C", _ANSI_HILITE + _ANSI_CYAN),
|
(r"{C", _ANSI_UNHILITE + _ANSI_CYAN),
|
||||||
(r"{W", _ANSI_HILITE + _ANSI_WHITE), # light grey
|
(r"{W", _ANSI_UNHILITE + _ANSI_WHITE), # light grey
|
||||||
(r"{X", _ANSI_HILITE + _ANSI_BLACK), # pure black
|
(r"{X", _ANSI_UNHILITE + _ANSI_BLACK), # pure black
|
||||||
# hilight-able colors
|
# hilight-able colors
|
||||||
(r"{h", _ANSI_HILITE),
|
(r"{h", _ANSI_HILITE),
|
||||||
(r"{H", _ANSI_UNHILITE),
|
(r"{H", _ANSI_UNHILITE),
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ And change your game's character typeclass to inherit from TBRangeCharacter
|
||||||
instead of the default:
|
instead of the default:
|
||||||
|
|
||||||
class Character(TBRangeCharacter):
|
class Character(TBRangeCharacter):
|
||||||
|
|
||||||
Do the same thing in your game's objects.py module for TBRangeObject:
|
Do the same thing in your game's objects.py module for TBRangeObject:
|
||||||
|
|
||||||
from evennia.contrib.turnbattle.tb_range import TBRangeObject
|
from evennia.contrib.turnbattle.tb_range import TBRangeObject
|
||||||
|
|
@ -246,10 +246,10 @@ def apply_damage(defender, damage):
|
||||||
def at_defeat(defeated):
|
def at_defeat(defeated):
|
||||||
"""
|
"""
|
||||||
Announces the defeat of a fighter in combat.
|
Announces the defeat of a fighter in combat.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
defeated (obj): Fighter that's been defeated.
|
defeated (obj): Fighter that's been defeated.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
All this does is announce a defeat message by default, but if you
|
All this does is announce a defeat message by default, but if you
|
||||||
want anything else to happen to defeated fighters (like putting them
|
want anything else to happen to defeated fighters (like putting them
|
||||||
|
|
@ -300,11 +300,11 @@ def resolve_attack(attacker, defender, attack_type, attack_value=None, defense_v
|
||||||
def get_range(obj1, obj2):
|
def get_range(obj1, obj2):
|
||||||
"""
|
"""
|
||||||
Gets the combat range between two objects.
|
Gets the combat range between two objects.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
obj1 (obj): First object
|
obj1 (obj): First object
|
||||||
obj2 (obj): Second object
|
obj2 (obj): Second object
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
range (int or None): Distance between two objects or None if not applicable
|
range (int or None): Distance between two objects or None if not applicable
|
||||||
"""
|
"""
|
||||||
|
|
@ -324,7 +324,7 @@ def get_range(obj1, obj2):
|
||||||
def distance_inc(mover, target):
|
def distance_inc(mover, target):
|
||||||
"""
|
"""
|
||||||
Function that increases distance in range field between mover and target.
|
Function that increases distance in range field between mover and target.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
mover (obj): The object moving
|
mover (obj): The object moving
|
||||||
target (obj): The object to be moved away from
|
target (obj): The object to be moved away from
|
||||||
|
|
@ -340,11 +340,11 @@ def distance_inc(mover, target):
|
||||||
def approach(mover, target):
|
def approach(mover, target):
|
||||||
"""
|
"""
|
||||||
Manages a character's whole approach, including changes in ranges to other characters.
|
Manages a character's whole approach, including changes in ranges to other characters.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
mover (obj): The object moving
|
mover (obj): The object moving
|
||||||
target (obj): The object to be moved toward
|
target (obj): The object to be moved toward
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
The mover will also automatically move toward any objects that are closer to the
|
The mover will also automatically move toward any objects that are closer to the
|
||||||
target than the mover is. The mover will also move away from anything they started
|
target than the mover is. The mover will also move away from anything they started
|
||||||
|
|
@ -354,7 +354,7 @@ def approach(mover, target):
|
||||||
def distance_dec(mover, target):
|
def distance_dec(mover, target):
|
||||||
"""
|
"""
|
||||||
Helper function that decreases distance in range field between mover and target.
|
Helper function that decreases distance in range field between mover and target.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
mover (obj): The object moving
|
mover (obj): The object moving
|
||||||
target (obj): The object to be moved toward
|
target (obj): The object to be moved toward
|
||||||
|
|
@ -388,11 +388,11 @@ def approach(mover, target):
|
||||||
def withdraw(mover, target):
|
def withdraw(mover, target):
|
||||||
"""
|
"""
|
||||||
Manages a character's whole withdrawal, including changes in ranges to other characters.
|
Manages a character's whole withdrawal, including changes in ranges to other characters.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
mover (obj): The object moving
|
mover (obj): The object moving
|
||||||
target (obj): The object to be moved away from
|
target (obj): The object to be moved away from
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
The mover will also automatically move away from objects that are close to the target
|
The mover will also automatically move away from objects that are close to the target
|
||||||
of their withdrawl. The mover will never inadvertently move toward anything else while
|
of their withdrawl. The mover will never inadvertently move toward anything else while
|
||||||
|
|
@ -540,7 +540,8 @@ class TBRangeTurnHandler(DefaultScript):
|
||||||
room as its object.
|
room as its object.
|
||||||
|
|
||||||
Fights persist until only one participant is left with any HP or all
|
Fights persist until only one participant is left with any HP or all
|
||||||
remaining participants choose to end the combat with the 'disengage' command.
|
remaining participants choose to end the combat with the 'disengage'
|
||||||
|
command.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def at_script_creation(self):
|
def at_script_creation(self):
|
||||||
|
|
@ -615,7 +616,7 @@ class TBRangeTurnHandler(DefaultScript):
|
||||||
def init_range(self, to_init):
|
def init_range(self, to_init):
|
||||||
"""
|
"""
|
||||||
Initializes range values for an object at the start of a fight.
|
Initializes range values for an object at the start of a fight.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
to_init (object): Object to initialize range field for.
|
to_init (object): Object to initialize range field for.
|
||||||
"""
|
"""
|
||||||
|
|
@ -638,14 +639,13 @@ class TBRangeTurnHandler(DefaultScript):
|
||||||
def join_rangefield(self, to_init, anchor_obj=None, add_distance=0):
|
def join_rangefield(self, to_init, anchor_obj=None, add_distance=0):
|
||||||
"""
|
"""
|
||||||
Adds a new object to the range field of a fight in progress.
|
Adds a new object to the range field of a fight in progress.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
to_init (object): Object to initialize range field for.
|
to_init (object): Object to initialize range field for.
|
||||||
|
|
||||||
Keyword args:
|
Keyword args:
|
||||||
anchor_obj (object): Object to copy range values from, or None for a random object.
|
anchor_obj (object): Object to copy range values from, or None for a random object.
|
||||||
add_distance (int): Distance to put between to_init object and anchor object.
|
add_distance (int): Distance to put between to_init object and anchor object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Get a list of room's contents without to_init object.
|
# Get a list of room's contents without to_init object.
|
||||||
contents = self.obj.contents
|
contents = self.obj.contents
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,9 @@ class SessionHandler(dict):
|
||||||
elif isinstance(data, (str, bytes)):
|
elif isinstance(data, (str, bytes)):
|
||||||
data = _utf8(data)
|
data = _utf8(data)
|
||||||
|
|
||||||
if _INLINEFUNC_ENABLED and not raw and isinstance(self, ServerSessionHandler):
|
if (_INLINEFUNC_ENABLED
|
||||||
|
and not raw
|
||||||
|
and isinstance(self, ServerSessionHandler)):
|
||||||
# only parse inlinefuncs on the outgoing path (sessionhandler->)
|
# only parse inlinefuncs on the outgoing path (sessionhandler->)
|
||||||
data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session)
|
data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ never traceback.
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
import random as base_random
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from evennia.utils import utils, logger
|
from evennia.utils import utils, logger
|
||||||
|
|
@ -72,6 +73,53 @@ from evennia.utils import utils, logger
|
||||||
|
|
||||||
# example/testing inline functions
|
# example/testing inline functions
|
||||||
|
|
||||||
|
def random(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
Inlinefunc. Returns a random number between
|
||||||
|
0 and 1, from 0 to a maximum value, or within a given range (inclusive).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
minval (str, optional): Minimum value. If not given, assumed 0.
|
||||||
|
maxval (str, optional): Maximum value.
|
||||||
|
|
||||||
|
Keyword argumuents:
|
||||||
|
session (Session): Session getting the string.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
If either of the min/maxvalue has a '.' in it, a floating-point random
|
||||||
|
value will be returned. Otherwise it will be an integer value in the
|
||||||
|
given range.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
`$random()`
|
||||||
|
`$random(5)`
|
||||||
|
`$random(5, 10)`
|
||||||
|
|
||||||
|
"""
|
||||||
|
nargs = len(args)
|
||||||
|
if nargs == 1:
|
||||||
|
# only maxval given
|
||||||
|
minval, maxval = '0', args[0]
|
||||||
|
elif nargs > 1:
|
||||||
|
minval, maxval = args[:2]
|
||||||
|
else:
|
||||||
|
minval, maxval = ('0', '1')
|
||||||
|
|
||||||
|
if "." in minval or "." in maxval:
|
||||||
|
# float mode
|
||||||
|
try:
|
||||||
|
minval, maxval = float(minval), float(maxval)
|
||||||
|
except ValueError:
|
||||||
|
minval, maxval = 0, 1
|
||||||
|
return "{:.2f}".format(minval + maxval * base_random.random())
|
||||||
|
else:
|
||||||
|
# int mode
|
||||||
|
try:
|
||||||
|
minval, maxval = int(minval), int(maxval)
|
||||||
|
except ValueError:
|
||||||
|
minval, maxval = 0, 1
|
||||||
|
return str(base_random.randint(minval, maxval))
|
||||||
|
|
||||||
|
|
||||||
def pad(*args, **kwargs):
|
def pad(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -82,7 +130,8 @@ def pad(*args, **kwargs):
|
||||||
width (str, optional): Will be converted to integer. Width
|
width (str, optional): Will be converted to integer. Width
|
||||||
of padding.
|
of padding.
|
||||||
align (str, optional): Alignment of padding; one of 'c', 'l' or 'r'.
|
align (str, optional): Alignment of padding; one of 'c', 'l' or 'r'.
|
||||||
fillchar (str, optional): Character used for padding. Defaults to a space.
|
fillchar (str, optional): Character used for padding. Defaults to a
|
||||||
|
space.
|
||||||
|
|
||||||
Keyword args:
|
Keyword args:
|
||||||
session (Session): Session performing the pad.
|
session (Session): Session performing the pad.
|
||||||
|
|
@ -468,6 +517,17 @@ def parse_inlinefunc(string, strip=False, available_funcs=None, stacktrace=False
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
|
|
||||||
|
def raw(string):
|
||||||
|
"""
|
||||||
|
Escape all inlinefuncs in a string so they won't get parsed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
string (str): String with inlinefuncs to escape.
|
||||||
|
"""
|
||||||
|
def _escape(match):
|
||||||
|
return "\\" + match.group(0)
|
||||||
|
return _RE_STARTTOKEN.sub(_escape, string)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Nick templating
|
# Nick templating
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -2025,8 +2025,8 @@ def display_len(target):
|
||||||
strip MXP patterns.
|
strip MXP patterns.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
target (string): A string with potential MXP components
|
target (any): Something to measure the length of. If a string, it will be
|
||||||
to search.
|
measured keeping asian-character and MXP links in mind.
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
int: The visible width of the target.
|
int: The visible width of the target.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
# general
|
# general
|
||||||
attrs >= 19.2.0
|
attrs >= 19.2.0
|
||||||
django >= 2.2.5, < 2.3
|
django >= 2.2.5, < 2.3
|
||||||
twisted >= 19.2.1, < 20.0.0
|
twisted >= 20.3.0, < 21.0.0
|
||||||
pytz
|
pytz
|
||||||
djangorestframework >= 3.10.3, < 3.12
|
djangorestframework >= 3.10.3, < 3.12
|
||||||
django-filter >= 2.2.0, < 2.3
|
django-filter >= 2.2.0, < 2.3
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue