Add stack support for object.search

This commit is contained in:
Griatch 2020-07-31 23:24:13 +02:00
parent 7015b4992d
commit 42612c92a7
4 changed files with 57 additions and 13 deletions

View file

@ -11,13 +11,15 @@
- Using `lunr` search indexing for better `help` matching and suggestions. Also improve
the main help command's default listing output.
- Added `content_types` indexing to DefaultObject's ContentsHandler. (volund)
- Made most of the networking classes such as Protocols and the SessionHandlers
- Made most of the networking classes such as Protocols and the SessionHandlers
replaceable via `settings.py` for modding enthusiasts. (volund)
- The `initial_setup.py` file can now be substituted in `settings.py` to customize
- The `initial_setup.py` file can now be substituted in `settings.py` to customize
initial game database state. (volund)
- Added new Traits contrib, converted and expanded from Ainneve project.
- Added new `requirements_extra.txt` file for easily getting all optional dependencies.
- Change default multimatch syntax from 1-obj, 2-obj to obj-1, obj-2.
- Change default multimatch syntax from 1-obj, 2-obj to obj-1, obj-2.
- Make `object.search` support 'stacks=0' keyword - if ``>0``, the method will return
N identical matches instead of triggering a multi-match error.
### Already in master
- Renamed Tutorial classes "Weapon" and "WeaponRack" to "TutorialWeapon" and

View file

@ -91,7 +91,7 @@ bulletin boards.
#### How will the world be built?
There are two main ways to handle this:
- Traditionally, from in-game with build-commands: This pretty means builders creating content in their game
- Traditionally, from in-game with build-commands: This means builders creating content in their game
client. This has the advantage of not requiring Python skills nor server access. This can often be a quite
intuitive way to build since you are sort-of walking around in your creation as you build it. However, the
developer (you) must make sure to provide build-commands that are flexible enough for builders to be able to
@ -119,13 +119,13 @@ code (such as what you can do with the `py` command). You can
it's suggested that this is accomplished by adding more powerful build-commands for them to use.
For our tutorial-game, we will only allow privileged builders to modify the world. The exception is crafting,
where we will allow players to to use in-game commands to create specific, prescribed objects from recipes.
which we will limit to repairing broken items by combining them with other repair-related items.
### Systems
#### Do you base your game off an existing RPG system or make up your own?
We will make use of [Open Adventure](http://www.geekguild.com/openadventure/), an 'old school' RRG-system
We will make use of [Open Adventure](http://www.geekguild.com/openadventure/), a simple 'old school' RPG-system
that is available for free under the Creative Commons license. We'll only use a subset of the rules from
the blue "basic" book. For the sake of keeping down the length of this tutorial we will limit what features
we will include:
@ -140,12 +140,11 @@ we will include:
#### What are the game mechanics? How do you decide if an action succeeds or fails?
Open Adventure's conflict resolution is based on adding a trait (such as Strength) with a random number in
order beat a target. We will emulate this in code.
order to beat a target. We will emulate this in code.
There are no pre-set "skills", all resolution is based on using suitable traits in different combinations.
The computer can't do this decision on-the-fly like a GM could, so we need to encode what is needed
to achieve a certain effect - this will be a set of 'skills'. We will only make the minimum amount of skills
needed to accomplish the actions we want to support. This will mean custom Commands.
Having a "skill" means getting a bonus to that roll for a more narrow action.
Since the computer will need to know exactly what those skills are, we will add them more explicitly than
in the rules, but we will only add the minimum to show off the functionality we need.
#### Does the flow of time matter in your game - does night and day change? What about seasons?

View file

@ -375,6 +375,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
nofound_string=None,
multimatch_string=None,
use_dbref=None,
stacked=0,
):
"""
Returns an Object matching a search string/condition
@ -430,10 +431,19 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
will be treated like a normal string. If `None` (default), the ability to query by
#dbref is turned on if `self` has the permission 'Builder' and is turned off
otherwise.
stacked (int, optional): If > 0, multimatches will be analyzed to determine if they
only contains identical objects; these are then assumed 'stacked' and no multi-match
error will be generated, instead `stacked` number of matches will be returned. If
`stacked` is larger than number of matches, returns that number of matches. If
the found stack is a mix of objects, return None and handle the multi-match
error depending on the value of `quiet`.
Returns:
match (Object, None or list): will return an Object/None if `quiet=False`,
otherwise it will return a list of 0, 1 or more matches.
Object: If finding a match an `quiet=False`
None: If not finding a unique match and `quiet=False`.
list: With 0, 1 or more matching objects if `quiet=True`
list: With 2 or more matching objects if `stacked` is a positive integer and
the matched stack has only object-copies.
Notes:
To find Accounts, use eg. `evennia.account_search`. If
@ -501,8 +511,29 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
use_dbref=use_dbref,
)
nresults = len(results)
if stacked > 0 and nresults > 1:
# handle stacks, disable multimatch errors
nstack = nresults
if not exact:
# we re-run exact match agains one of the matches to
# make sure we were not catching partial matches not belonging
# to the stack
nstack = len(ObjectDB.objects.get_objs_with_key_or_alias(
results[0].key,
exact=True,
candidates=list(results),
typeclasses=[typeclass] if typeclass else None
))
if nstack == nresults:
# a valid stack, return multiple results
return list(results)[:stacked]
if quiet:
# don't auto-handle error messaging
return list(results)
# handle error messages
return _AT_SEARCH_RESULT(
results,
self,

View file

@ -74,6 +74,18 @@ class DefaultObjectTest(EvenniaTest):
self.assertTrue(self.room1.get_absolute_url())
self.assertTrue("admin" in self.room1.web_get_admin_url())
def test_search_stacked(self):
"Test searching stacks"
coin1 = DefaultObject.create("coin", location=self.room1)[0]
coin2 = DefaultObject.create("coin", location=self.room1)[0]
colon = DefaultObject.create("colon", location=self.room1)[0]
# stack
self.assertEqual(self.char1.search("coin", stacked=2), [coin1, coin2])
self.assertEqual(self.char1.search("coin", stacked=5), [coin1, coin2])
# partial match to 'colon' - multimatch error since stack is not homogenous
self.assertEqual(self.char1.search("co", stacked=2), None)
class TestObjectManager(EvenniaTest):
"Test object manager methods"