mirror of
https://github.com/evennia/evennia.git
synced 2026-03-27 10:16:32 +01:00
Addition of mask to puzzles. Mask allows to mask-out part attributes during parts-and-recipes matching
This commit is contained in:
parent
6254762b41
commit
e52e68a08e
2 changed files with 44 additions and 17 deletions
|
|
@ -116,6 +116,18 @@ def proto_def(obj, with_tags=True):
|
|||
protodef['tags'] = tags
|
||||
return protodef
|
||||
|
||||
|
||||
def maskout_protodef(protodef, mask):
|
||||
"""
|
||||
Returns a new protodef after removing protodef values based on mask
|
||||
"""
|
||||
protodef = dict(protodef)
|
||||
for m in mask:
|
||||
if m in protodef:
|
||||
protodef.pop(m)
|
||||
return protodef
|
||||
|
||||
|
||||
# Colorize the default success message
|
||||
def _colorize_message(msg):
|
||||
_i = 0
|
||||
|
|
@ -140,6 +152,7 @@ class PuzzleRecipe(DefaultScript):
|
|||
self.db.puzzle_name = str(puzzle_name)
|
||||
self.db.parts = tuple(parts)
|
||||
self.db.results = tuple(results)
|
||||
self.db.mask = tuple()
|
||||
self.tags.add(_PUZZLES_TAG_RECIPE, category=_PUZZLES_TAG_CATEGORY)
|
||||
self.db.use_success_message = _PUZZLE_DEFAULT_SUCCESS_USE_MESSAGE
|
||||
self.db.use_success_location_message = _PUZZLE_DEFAULT_SUCCESS_USE_LOCATION_MESSAGE
|
||||
|
|
@ -275,6 +288,7 @@ class CmdCreatePuzzleRecipe(MuxCommand):
|
|||
|
||||
puzzle = create_script(PuzzleRecipe, key=puzzle_name)
|
||||
puzzle.save_recipe(puzzle_name, proto_parts, proto_results)
|
||||
puzzle.locks.add('control:id(%s) or perm(Builder)' % caller.dbref[1:])
|
||||
|
||||
caller.msg(
|
||||
"Puzzle |y'%s' |w%s(%s)|n has been created |gsuccessfully|n."
|
||||
|
|
@ -297,6 +311,7 @@ class CmdEditPuzzle(MuxCommand):
|
|||
@puzzleedit[/delete] <#dbref>
|
||||
@puzzleedit <#dbref>/use_success_message = <Your custom message>
|
||||
@puzzleedit <#dbref>/use_success_location_message = <Your custom message from {caller} producing {result_names}>
|
||||
@puzzleedit <#dbref>/mask = attr1[,attr2,...]>
|
||||
@puzzleedit[/addpart] <#dbref> = <obj[,obj2,...]>
|
||||
@puzzleedit[/delpart] <#dbref> = <obj[,obj2,...]>
|
||||
@puzzleedit[/addresult] <#dbref> = <obj[,obj2,...]>
|
||||
|
|
@ -309,6 +324,7 @@ class CmdEditPuzzle(MuxCommand):
|
|||
delresult - removes results from the puzzle
|
||||
delete - deletes the recipe. Existing parts and results aren't modified
|
||||
|
||||
mask - attributes to exclude during matching (e.g. location, desc, etc.)
|
||||
use_success_location_message containing {result_names} and {caller} will automatically be replaced with correct values. Both are optional.
|
||||
|
||||
When removing parts/results, it's possible to remove all.
|
||||
|
|
@ -400,6 +416,12 @@ class CmdEditPuzzle(MuxCommand):
|
|||
"%s use_success_location_message = %s\n" % (puzzle_name_id, puzzle.db.use_success_location_message)
|
||||
)
|
||||
return
|
||||
elif attr == 'mask':
|
||||
puzzle.db.mask = tuple(self.rhslist)
|
||||
caller.msg(
|
||||
"%s mask = %r\n" % (puzzle_name_id, puzzle.db.mask)
|
||||
)
|
||||
return
|
||||
|
||||
def _get_objs(self):
|
||||
if not self.rhslist:
|
||||
|
|
@ -576,14 +598,19 @@ class CmdUsePuzzleParts(MuxCommand):
|
|||
matched_puzzles = dict()
|
||||
for puzzle in puzzles:
|
||||
puzzle_protoparts = list(puzzle.db.parts[:])
|
||||
puzzle_mask = puzzle.db.mask[:]
|
||||
# remove tags and prototype_key as they prevent equality
|
||||
for puzzle_protopart in puzzle_protoparts:
|
||||
for i, puzzle_protopart in enumerate(puzzle_protoparts[:]):
|
||||
del(puzzle_protopart['tags'])
|
||||
del(puzzle_protopart['prototype_key'])
|
||||
puzzle_protopart = maskout_protodef(puzzle_protopart, puzzle_mask)
|
||||
puzzle_protoparts[i] = puzzle_protopart
|
||||
|
||||
matched_dbrefparts = []
|
||||
parts_dbrefs = puzzlename_tags_dict[puzzle.db.puzzle_name]
|
||||
for part_dbref in parts_dbrefs:
|
||||
protopart = puzzle_ingredients[part_dbref]
|
||||
protopart = maskout_protodef(protopart, puzzle_mask)
|
||||
if protopart in puzzle_protoparts:
|
||||
puzzle_protoparts.remove(protopart)
|
||||
matched_dbrefparts.append(part_dbref)
|
||||
|
|
@ -669,6 +696,7 @@ class CmdListPuzzleRecipes(MuxCommand):
|
|||
text.append(msgf_recipe % (recipe.db.puzzle_name, recipe.name, recipe.dbref))
|
||||
text.append('Success Caller message:\n' + recipe.db.use_success_message + '\n')
|
||||
text.append('Success Location message:\n' + recipe.db.use_success_location_message + '\n')
|
||||
text.append('Mask:\n' + str(recipe.db.mask) + '\n')
|
||||
text.append('Parts')
|
||||
for protopart in recipe.db.parts[:]:
|
||||
mark = '-'
|
||||
|
|
|
|||
|
|
@ -2015,14 +2015,6 @@ class TestPuzzles(CommandTest):
|
|||
_puzzleedit('', recipe_dbref, 'dummy', "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit")
|
||||
_puzzleedit('', self.script.dbref, '', 'Script(#1) is not a puzzle')
|
||||
|
||||
# no permissions
|
||||
_puzzleedit('', recipe_dbref, '/use_success_message = Yes!', "You don't have permission")
|
||||
_puzzleedit('/delete', recipe_dbref, '', "You don't have permission")
|
||||
|
||||
# grant perm to char1
|
||||
puzzle = search.search_script(recipe_dbref)[0]
|
||||
puzzle.locks.add('control:id(%s)' % self.char1.dbref[1:])
|
||||
|
||||
# edit use_success_message and use_success_location_message
|
||||
_puzzleedit('', recipe_dbref, '/use_success_message = Yes!', 'makefire(%s) use_success_message = Yes!' % recipe_dbref)
|
||||
_puzzleedit('', recipe_dbref, '/use_success_location_message = {result_names} Yeah baby! {caller}', 'makefire(%s) use_success_location_message = {result_names} Yeah baby! {caller}' % recipe_dbref)
|
||||
|
|
@ -2031,6 +2023,20 @@ class TestPuzzles(CommandTest):
|
|||
self.room1.msg_contents = Mock()
|
||||
self._use('stone, flint', 'Yes!')
|
||||
self.room1.msg_contents.assert_called_once_with('fire Yeah baby! Char', exclude=(self.char1,))
|
||||
self.room1.msg_contents.reset_mock()
|
||||
|
||||
# edit mask: exclude location and desc during matching
|
||||
_puzzleedit('', recipe_dbref, '/mask = location,desc',
|
||||
"makefire(%s) mask = ('location', 'desc')" % recipe_dbref)
|
||||
|
||||
self._arm(recipe_dbref, 'makefire', ['stone', 'flint'])
|
||||
# change location and desc
|
||||
self.char1.search('stone').db.desc = 'A solid slab of granite'
|
||||
self.char1.search('stone').location = self.char1
|
||||
self.char1.search('flint').db.desc = 'A flint stone'
|
||||
self.char1.search('flint').location = self.char1
|
||||
self._use('stone, flint', 'Yes!')
|
||||
self.room1.msg_contents.assert_called_once_with('fire Yeah baby! Char', exclude=(self.char1,))
|
||||
|
||||
# delete
|
||||
_puzzleedit('/delete', recipe_dbref, '', 'makefire(%s) was deleted' % recipe_dbref)
|
||||
|
|
@ -2135,6 +2141,7 @@ class TestPuzzles(CommandTest):
|
|||
r"^Puzzle 'makefire'.*$",
|
||||
r"^Success Caller message:$",
|
||||
r"^Success Location message:$",
|
||||
r"^Mask:$",
|
||||
r"^Parts$",
|
||||
r"^.*key: stone$",
|
||||
r"^.*key: flint$",
|
||||
|
|
@ -2301,14 +2308,6 @@ class TestPuzzles(CommandTest):
|
|||
expected = {(key, len(list(grp))) for key, grp in itertools.groupby(srs)}
|
||||
self._check_room_contents(expected)
|
||||
|
||||
# TODO: results has Exit
|
||||
|
||||
# TODO: results has NPC
|
||||
|
||||
# TODO: results has Room
|
||||
|
||||
# TODO: parts' location can be different from Character's location
|
||||
|
||||
def test_e2e_interchangeable_parts_and_results(self):
|
||||
# Parts and Results can be used in multiple puzzles
|
||||
egg = create_object(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue