mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Make ic command better handle multiple-matches.
Resolves #1923. This changes the `ic` command so non-privileged users will search through their `_playable_characters` Attribute list. Privileged (Builder+) users will use their `_playable_characters` list, but if they are already puppeting a char in the same location as an object with the given name, this will be used instead. Only if no match is found neither in `_playable_characters` nor in the current location will a global search for a puppetable target be done (and only for Builders+)
This commit is contained in:
parent
fa09aeef50
commit
dd5c6274b7
5 changed files with 96 additions and 36 deletions
|
|
@ -68,6 +68,8 @@ without arguments starts a full interactive Python console.
|
|||
- Make `Object/Room/Exit.create`'s `account` argument optional. If not given, will set perms
|
||||
to that of the object itself (along with normal Admin/Dev permission).
|
||||
- Make `INLINEFUNC_STACK_MAXSIZE` default visible in `settings_default.py`.
|
||||
- Change how `ic` finds puppets; non-priveleged users will use `_playable_characters` list as
|
||||
candidates, Builders+ will use list, local search and only global search if no match found.
|
||||
|
||||
|
||||
## Evennia 0.9 (2018-2019)
|
||||
|
|
|
|||
|
|
@ -941,6 +941,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
nofound_string=None,
|
||||
multimatch_string=None,
|
||||
use_nicks=True,
|
||||
quiet=False,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
|
|
@ -967,9 +968,13 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
message to echo if `searchdata` leads to multiple matches.
|
||||
If not given, will fall back to the default handler.
|
||||
use_nicks (bool, optional): Use account-level nick replacement.
|
||||
quiet (bool, optional): If set, will not show any error to the user,
|
||||
and will also lead to returning a list of matches.
|
||||
|
||||
Return:
|
||||
match (Account, Object or None): A single Account or Object match.
|
||||
list: If `quiet=True` this is a list of 0, 1 or more Account or Object matches.
|
||||
|
||||
Notes:
|
||||
Extra keywords are ignored, but are allowed in call in
|
||||
order to make API more consistent with
|
||||
|
|
@ -981,28 +986,33 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
# handle wrapping of common terms
|
||||
if searchdata.lower() in ("me", "*me", "self", "*self"):
|
||||
return self
|
||||
searchdata = self.nicks.nickreplace(
|
||||
searchdata, categories=("account",), include_account=False
|
||||
)
|
||||
if search_object:
|
||||
matches = ObjectDB.objects.object_search(
|
||||
searchdata, typeclass=typeclass, use_nicks=use_nicks
|
||||
searchdata, typeclass=typeclass
|
||||
)
|
||||
else:
|
||||
searchdata = self.nicks.nickreplace(
|
||||
searchdata, categories=("account",), include_account=False
|
||||
)
|
||||
|
||||
matches = AccountDB.objects.account_search(searchdata, typeclass=typeclass)
|
||||
matches = _AT_SEARCH_RESULT(
|
||||
matches,
|
||||
self,
|
||||
query=searchdata,
|
||||
nofound_string=nofound_string,
|
||||
multimatch_string=multimatch_string,
|
||||
)
|
||||
if matches and return_puppet:
|
||||
try:
|
||||
return matches.puppet
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
if quiet:
|
||||
matches = list(matches)
|
||||
if return_puppet:
|
||||
matches = [match.puppet for match in matches]
|
||||
else:
|
||||
matches = _AT_SEARCH_RESULT(
|
||||
matches,
|
||||
self,
|
||||
query=searchdata,
|
||||
nofound_string=nofound_string,
|
||||
multimatch_string=multimatch_string,
|
||||
)
|
||||
if matches and return_puppet:
|
||||
try:
|
||||
matches = matches.puppet
|
||||
except AttributeError:
|
||||
return None
|
||||
return matches
|
||||
|
||||
def access(
|
||||
|
|
|
|||
|
|
@ -301,27 +301,60 @@ class CmdIC(COMMAND_DEFAULT_CLASS):
|
|||
session = self.session
|
||||
|
||||
new_character = None
|
||||
character_candidates = []
|
||||
|
||||
if not self.args:
|
||||
new_character = account.db._last_puppet
|
||||
if not new_character:
|
||||
character_candidates = [account.db._last_puppet] or []
|
||||
if not character_candidates:
|
||||
self.msg("Usage: ic <character>")
|
||||
return
|
||||
if not new_character:
|
||||
# search for a matching character
|
||||
new_character = [
|
||||
char for char in search.object_search(self.args) if char.access(account, "puppet")
|
||||
]
|
||||
if not new_character:
|
||||
self.msg("That is not a valid character choice.")
|
||||
return
|
||||
if len(new_character) > 1:
|
||||
self.msg(
|
||||
"Multiple targets with the same name:\n %s"
|
||||
% ", ".join("%s(#%s)" % (obj.key, obj.id) for obj in new_character)
|
||||
else:
|
||||
# argument given
|
||||
|
||||
if account.db._playable_characters:
|
||||
# look at the playable_characters list first
|
||||
character_candidates.extend(
|
||||
account.search(self.args, candidates=account.db._playable_characters,
|
||||
search_object=True, quiet=True)
|
||||
)
|
||||
return
|
||||
else:
|
||||
new_character = new_character[0]
|
||||
|
||||
if account.locks.check_lockstring(account, "perm(Builder)"):
|
||||
# builders and higher should be able to puppet more than their
|
||||
# playable characters.
|
||||
if session.puppet:
|
||||
# start by local search - this helps to avoid the user
|
||||
# getting locked into their playable characters should one
|
||||
# happen to be named the same as another. We replace the suggestion
|
||||
# from playable_characters here - this allows builders to puppet objects
|
||||
# with the same name as their playable chars should it be necessary
|
||||
# (by going to the same location).
|
||||
character_candidates = [
|
||||
char
|
||||
for char in session.puppet.search(self.args, quiet=True)
|
||||
if char.access(account, "puppet")
|
||||
]
|
||||
if not character_candidates:
|
||||
# fall back to global search only if Builder+ has no
|
||||
# playable_characers in list and is not standing in a room
|
||||
# with a matching char.
|
||||
character_candidates.extend([
|
||||
char for char in search.object_search(self.args) if char.access(account, "puppet")]
|
||||
)
|
||||
|
||||
# handle possible candidates
|
||||
if not character_candidates:
|
||||
self.msg("That is not a valid character choice.")
|
||||
return
|
||||
if len(character_candidates) > 1:
|
||||
self.msg(
|
||||
"Multiple targets with the same name:\n %s"
|
||||
% ", ".join("%s(#%s)" % (obj.key, obj.id) for obj in character_candidates)
|
||||
)
|
||||
return
|
||||
else:
|
||||
new_character = character_candidates[0]
|
||||
|
||||
# do the puppet puppet
|
||||
try:
|
||||
account.puppet_object(session, new_character)
|
||||
account.db._last_puppet = new_character
|
||||
|
|
|
|||
|
|
@ -353,11 +353,27 @@ class TestAccount(CommandTest):
|
|||
self.call(account.CmdOOC(), "", "You go OOC.", caller=self.account)
|
||||
|
||||
def test_ic(self):
|
||||
self.account.db._playable_characters = [self.char1]
|
||||
self.account.unpuppet_object(self.session)
|
||||
self.call(
|
||||
account.CmdIC(), "Char", "You become Char.", caller=self.account, receiver=self.char1
|
||||
)
|
||||
|
||||
def test_ic__other_object(self):
|
||||
self.account.db._playable_characters = [self.obj1]
|
||||
self.account.unpuppet_object(self.session)
|
||||
self.call(
|
||||
account.CmdIC(), "Obj", "You become Obj.", caller=self.account, receiver=self.obj1
|
||||
)
|
||||
|
||||
def test_ic__nonaccess(self):
|
||||
self.account.unpuppet_object(self.session)
|
||||
self.call(
|
||||
account.CmdIC(), "Nonexistent", "That is not a valid character choice.",
|
||||
caller=self.account, receiver=self.account
|
||||
)
|
||||
|
||||
|
||||
def test_password(self):
|
||||
self.call(
|
||||
account.CmdPassword(),
|
||||
|
|
|
|||
|
|
@ -389,8 +389,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
- `me,self`: self-reference to this object
|
||||
- `<num>-<string>` - can be used to differentiate
|
||||
between multiple same-named matches
|
||||
global_search (bool): Search all objects globally. This is overruled
|
||||
by `location` keyword.
|
||||
global_search (bool): Search all objects globally. This overrules 'location' data.
|
||||
use_nicks (bool): Use nickname-replace (nicktype "object") on `searchdata`.
|
||||
typeclass (str or Typeclass, or list of either): Limit search only
|
||||
to `Objects` with this typeclass. May be a list of typeclasses
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue