Fix merge conflicts
This commit is contained in:
commit
690ed6ecd1
5 changed files with 1763 additions and 9 deletions
|
|
@ -1731,6 +1731,961 @@ class TestRandomStringGenerator(EvenniaTest):
|
|||
SIMPLE_GENERATOR.get()
|
||||
|
||||
|
||||
# Test of the Puzzles module
|
||||
|
||||
import itertools
|
||||
from evennia.contrib import puzzles
|
||||
from evennia.utils import search
|
||||
from evennia.utils.utils import inherits_from
|
||||
|
||||
class TestPuzzles(CommandTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPuzzles, self).setUp()
|
||||
self.steel = create_object(
|
||||
self.object_typeclass,
|
||||
key='steel', location=self.char1.location)
|
||||
self.flint = create_object(
|
||||
self.object_typeclass,
|
||||
key='flint', location=self.char1.location)
|
||||
self.fire = create_object(
|
||||
self.object_typeclass,
|
||||
key='fire', location=self.char1.location)
|
||||
self.steel.tags.add('tag-steel')
|
||||
self.steel.tags.add('tag-steel', category='tagcat')
|
||||
self.flint.tags.add('tag-flint')
|
||||
self.flint.tags.add('tag-flint', category='tagcat')
|
||||
self.fire.tags.add('tag-fire')
|
||||
self.fire.tags.add('tag-fire', category='tagcat')
|
||||
|
||||
def _assert_msg_matched(self, msg, regexs, re_flags=0):
|
||||
matches = []
|
||||
for regex in regexs:
|
||||
m = re.search(regex, msg, re_flags)
|
||||
self.assertIsNotNone(m, "%r didn't match %r" % (regex, msg))
|
||||
matches.append(m)
|
||||
return matches
|
||||
|
||||
def _assert_recipe(self, name, parts, results, and_destroy_it=True, expected_count=1):
|
||||
|
||||
def _keys(items):
|
||||
return [item['key'] for item in items]
|
||||
|
||||
recipes = search.search_script_tag('', category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
self.assertEqual(expected_count, len(recipes))
|
||||
self.assertEqual(name, recipes[expected_count-1].db.puzzle_name)
|
||||
self.assertEqual(parts, _keys(recipes[expected_count-1].db.parts))
|
||||
self.assertEqual(results, _keys(recipes[expected_count-1].db.results))
|
||||
self.assertEqual(
|
||||
puzzles._PUZZLES_TAG_RECIPE,
|
||||
recipes[expected_count-1].tags.get(category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
)
|
||||
recipe_dbref = recipes[expected_count-1].dbref
|
||||
if and_destroy_it:
|
||||
recipes[expected_count-1].delete()
|
||||
return recipe_dbref if not and_destroy_it else None
|
||||
|
||||
def _assert_no_recipes(self):
|
||||
self.assertEqual(
|
||||
0,
|
||||
len(search.search_script_tag('', category=puzzles._PUZZLES_TAG_CATEGORY))
|
||||
)
|
||||
|
||||
# good recipes
|
||||
def _good_recipe(self, name, parts, results, and_destroy_it=True, expected_count=1):
|
||||
regexs = []
|
||||
for p in parts:
|
||||
regexs.append(r'^Part %s\(#\d+\)$' % (p))
|
||||
for r in results:
|
||||
regexs.append(r'^Result %s\(#\d+\)$' % (r))
|
||||
regexs.append(r"^Puzzle '%s' %s\(#\d+\) has been created successfully.$" % (name, name))
|
||||
lhs = [name] + parts
|
||||
cmdstr = ','.join(lhs) + '=' + ','.join(results)
|
||||
msg = self.call(
|
||||
puzzles.CmdCreatePuzzleRecipe(),
|
||||
cmdstr,
|
||||
caller=self.char1
|
||||
)
|
||||
recipe_dbref = self._assert_recipe(name, parts, results, and_destroy_it, expected_count)
|
||||
matches = self._assert_msg_matched(msg, regexs, re_flags=re.MULTILINE | re.DOTALL)
|
||||
return recipe_dbref
|
||||
|
||||
def _check_room_contents(self, expected, check_test_tags=False):
|
||||
by_obj_key = lambda o: o.key
|
||||
room1_contents = sorted(self.room1.contents, key=by_obj_key)
|
||||
for key, grp in itertools.groupby(room1_contents, by_obj_key):
|
||||
if key in expected:
|
||||
grp = list(grp)
|
||||
self.assertEqual(expected[key], len(grp),
|
||||
"Expected %d but got %d for %s" % (expected[key], len(grp), key))
|
||||
if check_test_tags:
|
||||
for gi in grp:
|
||||
tags = gi.tags.all(return_key_and_category=True)
|
||||
self.assertIn(('tag-' + gi.key, None), tags)
|
||||
self.assertIn(('tag-' + gi.key, 'tagcat'), tags)
|
||||
|
||||
def _arm(self, recipe_dbref, name, parts):
|
||||
regexs = [
|
||||
r"^Puzzle Recipe %s\(#\d+\) '%s' found.$" % (name, name),
|
||||
r"^Spawning %d parts ...$" % (len(parts)),
|
||||
]
|
||||
for p in parts:
|
||||
regexs.append(r'^Part %s\(#\d+\) spawned .*$' % (p))
|
||||
regexs.append(r"^Puzzle armed successfully.$")
|
||||
msg = self.call(
|
||||
puzzles.CmdArmPuzzle(),
|
||||
recipe_dbref,
|
||||
caller=self.char1
|
||||
)
|
||||
matches = self._assert_msg_matched(msg, regexs, re_flags=re.MULTILINE | re.DOTALL)
|
||||
|
||||
def test_cmdset_puzzle(self):
|
||||
self.char1.cmdset.add('evennia.contrib.puzzles.PuzzleSystemCmdSet')
|
||||
# FIXME: testing nothing, this is just to bump up coverage
|
||||
|
||||
def test_cmd_puzzle(self):
|
||||
self._assert_no_recipes()
|
||||
|
||||
# bad syntax
|
||||
def _bad_syntax(cmdstr):
|
||||
self.call(
|
||||
puzzles.CmdCreatePuzzleRecipe(),
|
||||
cmdstr,
|
||||
'Usage: @puzzle name,<part1[,...]> = <result1[,...]>',
|
||||
caller=self.char1
|
||||
)
|
||||
|
||||
_bad_syntax('')
|
||||
_bad_syntax('=')
|
||||
_bad_syntax('nothing =')
|
||||
_bad_syntax('= nothing')
|
||||
_bad_syntax('nothing')
|
||||
_bad_syntax(',nothing')
|
||||
_bad_syntax('name, nothing')
|
||||
_bad_syntax('name, nothing =')
|
||||
|
||||
self._assert_no_recipes()
|
||||
|
||||
self._good_recipe('makefire', ['steel', 'flint'], ['fire', 'steel', 'flint'])
|
||||
self._good_recipe('hot steels', ['steel', 'fire'], ['steel', 'fire'])
|
||||
self._good_recipe('furnace', ['steel', 'steel', 'fire'], ['steel', 'steel', 'fire', 'fire', 'fire', 'fire'])
|
||||
|
||||
# bad recipes
|
||||
def _bad_recipe(name, parts, results, fail_regex):
|
||||
cmdstr = ','.join([name] + parts) \
|
||||
+ '=' + ','.join(results)
|
||||
msg = self.call(
|
||||
puzzles.CmdCreatePuzzleRecipe(),
|
||||
cmdstr,
|
||||
caller=self.char1
|
||||
)
|
||||
self._assert_no_recipes()
|
||||
self.assertIsNotNone(re.match(fail_regex, msg), msg)
|
||||
|
||||
_bad_recipe('name', ['nothing'], ['neither'], r"Could not find 'nothing'.")
|
||||
_bad_recipe('name', ['steel'], ['nothing'], r"Could not find 'nothing'.")
|
||||
_bad_recipe('', ['steel', 'fire'], ['steel', 'fire'], r"^Invalid puzzle name ''.")
|
||||
self.steel.location = self.char1
|
||||
_bad_recipe('name', ['steel'], ['fire'], r"^Invalid location for steel$")
|
||||
_bad_recipe('name', ['flint'], ['steel'], r"^Invalid location for steel$")
|
||||
_bad_recipe('name', ['self'], ['fire'], r"^Invalid typeclass for Char$")
|
||||
_bad_recipe('name', ['here'], ['fire'], r"^Invalid typeclass for Room$")
|
||||
|
||||
self._assert_no_recipes()
|
||||
|
||||
def test_cmd_armpuzzle(self):
|
||||
# bad arms
|
||||
self.call(
|
||||
puzzles.CmdArmPuzzle(),
|
||||
'1',
|
||||
"A puzzle recipe's #dbref must be specified",
|
||||
caller=self.char1
|
||||
)
|
||||
self.call(
|
||||
puzzles.CmdArmPuzzle(),
|
||||
'#1',
|
||||
"Invalid puzzle '#1'",
|
||||
caller=self.char1
|
||||
)
|
||||
|
||||
recipe_dbref = self._good_recipe('makefire', ['steel', 'flint'], ['fire', 'steel', 'flint'], and_destroy_it=False)
|
||||
|
||||
# delete proto parts and proto result
|
||||
self.steel.delete()
|
||||
self.flint.delete()
|
||||
self.fire.delete()
|
||||
|
||||
# good arm
|
||||
self._arm(recipe_dbref, 'makefire', ['steel', 'flint'])
|
||||
self._check_room_contents({'steel': 1, 'flint': 1}, check_test_tags=True)
|
||||
|
||||
def _use(self, cmdstr, expmsg):
|
||||
msg = self.call(
|
||||
puzzles.CmdUsePuzzleParts(),
|
||||
cmdstr,
|
||||
expmsg,
|
||||
caller=self.char1
|
||||
)
|
||||
return msg
|
||||
|
||||
def test_cmd_use(self):
|
||||
|
||||
self._use('', 'Use what?')
|
||||
self._use('something', 'There is no something around.')
|
||||
self._use('steel', 'You have no idea how this can be used')
|
||||
self._use('steel flint', 'There is no steel flint around.')
|
||||
self._use('steel, flint', 'You have no idea how these can be used')
|
||||
|
||||
recipe_dbref = self._good_recipe(unicode('makefire'), ['steel', 'flint'], ['fire'] , and_destroy_it=False)
|
||||
recipe2_dbref = self._good_recipe('makefire2', ['steel', 'flint'], ['fire'] , and_destroy_it=False,
|
||||
expected_count=2)
|
||||
|
||||
# although there is steel and flint
|
||||
# those aren't valid puzzle parts because
|
||||
# the puzzle hasn't been armed
|
||||
self._use('steel', 'You have no idea how this can be used')
|
||||
self._use('steel, flint', 'You have no idea how these can be used')
|
||||
self._arm(recipe_dbref, 'makefire', ['steel', 'flint'])
|
||||
self._check_room_contents({'steel': 2, 'flint': 2}, check_test_tags=True)
|
||||
|
||||
# there are duplicated objects now
|
||||
self._use('steel', 'Which steel. There are many')
|
||||
self._use('flint', 'Which flint. There are many')
|
||||
|
||||
# delete proto parts and proto results
|
||||
self.steel.delete()
|
||||
self.flint.delete()
|
||||
self.fire.delete()
|
||||
|
||||
# solve puzzle
|
||||
self._use('steel, flint', 'You are a Genius')
|
||||
self.assertEqual(1,
|
||||
len(list(filter(
|
||||
lambda o: o.key == 'fire' \
|
||||
and ('makefire', puzzles._PUZZLES_TAG_CATEGORY) \
|
||||
in o.tags.all(return_key_and_category=True) \
|
||||
and (puzzles._PUZZLES_TAG_MEMBER, puzzles._PUZZLES_TAG_CATEGORY) \
|
||||
in o.tags.all(return_key_and_category=True),
|
||||
self.room1.contents))))
|
||||
self._check_room_contents({'steel': 0, 'flint': 0, 'fire': 1}, check_test_tags=True)
|
||||
|
||||
# trying again will fail as it was resolved already
|
||||
# and the parts were destroyed
|
||||
self._use('steel, flint', 'There is no steel around')
|
||||
self._use('flint, steel', 'There is no flint around')
|
||||
|
||||
# arm same puzzle twice so there are duplicated parts
|
||||
self._arm(recipe_dbref, 'makefire', ['steel', 'flint'])
|
||||
self._arm(recipe_dbref, 'makefire', ['steel', 'flint'])
|
||||
self._check_room_contents({'steel': 2, 'flint': 2, 'fire': 1}, check_test_tags=True)
|
||||
|
||||
# try solving with multiple parts but incomplete set
|
||||
self._use('1-steel, 2-steel', 'You try to utilize these but nothing happens ... something amiss?')
|
||||
|
||||
# arm the other puzzle. Their parts are identical
|
||||
self._arm(recipe2_dbref, 'makefire2', ['steel', 'flint'])
|
||||
self._check_room_contents({'steel': 3, 'flint': 3, 'fire': 1}, check_test_tags=True)
|
||||
|
||||
# solve with multiple parts for
|
||||
# multiple puzzles. Both can be solved but
|
||||
# only one is.
|
||||
self._use(
|
||||
'1-steel, 2-flint, 3-steel, 3-flint',
|
||||
'Your gears start turning and 2 different ideas come to your mind ... ')
|
||||
self._check_room_contents({'steel': 2, 'flint': 2, 'fire': 2}, check_test_tags=True)
|
||||
|
||||
self.room1.msg_contents = Mock()
|
||||
|
||||
# solve all
|
||||
self._use('1-steel, 1-flint', 'You are a Genius')
|
||||
self.room1.msg_contents.assert_called_once_with('|cChar|n performs some kind of tribal dance and |yfire|n seems to appear from thin air', exclude=(self.char1,))
|
||||
self._use('steel, flint', 'You are a Genius')
|
||||
self._check_room_contents({'steel': 0, 'flint': 0, 'fire': 4}, check_test_tags=True)
|
||||
|
||||
def test_puzzleedit(self):
|
||||
recipe_dbref = self._good_recipe('makefire', ['steel', 'flint'], ['fire'] , and_destroy_it=False)
|
||||
|
||||
def _puzzleedit(swt, dbref, args, expmsg):
|
||||
if (swt is None) and (dbref is None) and (args is None):
|
||||
cmdstr = ''
|
||||
else:
|
||||
cmdstr = '%s %s%s' % (swt, dbref, args)
|
||||
self.call(
|
||||
puzzles.CmdEditPuzzle(),
|
||||
cmdstr,
|
||||
expmsg,
|
||||
caller=self.char1
|
||||
)
|
||||
|
||||
# delete proto parts and proto results
|
||||
self.steel.delete()
|
||||
self.flint.delete()
|
||||
self.fire.delete()
|
||||
|
||||
# bad syntax
|
||||
_puzzleedit(None, None, None, "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit")
|
||||
_puzzleedit('', '1', '', "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit")
|
||||
_puzzleedit('', '', '', "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit")
|
||||
_puzzleedit('', recipe_dbref, 'dummy', "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit")
|
||||
_puzzleedit('', self.script.dbref, '', 'Script(#1) is not a puzzle')
|
||||
|
||||
# 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)
|
||||
|
||||
self._arm(recipe_dbref, 'makefire', ['steel', 'flint'])
|
||||
self.room1.msg_contents = Mock()
|
||||
self._use('steel, 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', ['steel', 'flint'])
|
||||
# change location and desc
|
||||
self.char1.search('steel').db.desc = 'A solid bar of steel'
|
||||
self.char1.search('steel').location = self.char1
|
||||
self.char1.search('flint').db.desc = 'A flint steel'
|
||||
self.char1.search('flint').location = self.char1
|
||||
self._use('steel, 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)
|
||||
self._assert_no_recipes()
|
||||
|
||||
def test_puzzleedit_add_remove_parts_results(self):
|
||||
recipe_dbref = self._good_recipe('makefire', ['steel', 'flint'], ['fire'] , and_destroy_it=False)
|
||||
|
||||
def _puzzleedit(swt, dbref, rhslist, expmsg):
|
||||
cmdstr = '%s %s = %s' % (swt, dbref, ', '.join(rhslist))
|
||||
self.call(
|
||||
puzzles.CmdEditPuzzle(),
|
||||
cmdstr,
|
||||
expmsg,
|
||||
caller=self.char1
|
||||
)
|
||||
|
||||
red_steel = create_object(
|
||||
self.object_typeclass,
|
||||
key='red steel', location=self.char1.location)
|
||||
smoke = create_object(
|
||||
self.object_typeclass,
|
||||
key='smoke', location=self.char1.location)
|
||||
|
||||
_puzzleedit('/addresult', recipe_dbref, ['smoke'], 'smoke were added to results')
|
||||
_puzzleedit('/addpart', recipe_dbref, ['red steel', 'steel'], 'red steel, steel were added to parts')
|
||||
|
||||
# create a box so we can put all objects in
|
||||
# so that they can't be found during puzzle resolution
|
||||
self.box = create_object(
|
||||
self.object_typeclass,
|
||||
key='box', location=self.char1.location)
|
||||
def _box_all():
|
||||
for o in self.room1.contents:
|
||||
if o not in [self.char1, self.char2, self.exit,
|
||||
self.obj1, self.obj2, self.box]:
|
||||
o.location = self.box
|
||||
_box_all()
|
||||
|
||||
self._arm(recipe_dbref, 'makefire', ['steel', 'flint', 'red steel', 'steel'])
|
||||
self._check_room_contents({
|
||||
'steel': 2,
|
||||
'red steel': 1,
|
||||
'flint': 1,
|
||||
})
|
||||
self._use('1-steel, flint', 'You try to utilize these but nothing happens ... something amiss?')
|
||||
self._use('1-steel, flint, red steel, 3-steel', 'You are a Genius')
|
||||
self._check_room_contents({
|
||||
'smoke': 1,
|
||||
'fire': 1
|
||||
})
|
||||
_box_all()
|
||||
|
||||
self.fire.location = self.room1
|
||||
self.steel.location = self.room1
|
||||
|
||||
_puzzleedit('/delresult', recipe_dbref, ['fire'], 'fire were removed from results')
|
||||
_puzzleedit('/delpart', recipe_dbref, ['steel', 'steel'], 'steel, steel were removed from parts')
|
||||
|
||||
_box_all()
|
||||
|
||||
self._arm(recipe_dbref, 'makefire', ['flint', 'red steel'])
|
||||
self._check_room_contents({
|
||||
'red steel': 1,
|
||||
'flint': 1,
|
||||
})
|
||||
self._use('red steel, flint', 'You are a Genius')
|
||||
self._check_room_contents({
|
||||
'smoke': 1,
|
||||
'fire': 0
|
||||
})
|
||||
|
||||
def test_lspuzzlerecipes_lsarmedpuzzles(self):
|
||||
msg = self.call(
|
||||
puzzles.CmdListPuzzleRecipes(),
|
||||
'',
|
||||
caller=self.char1
|
||||
)
|
||||
self._assert_msg_matched(
|
||||
msg,
|
||||
[
|
||||
r"^-+$",
|
||||
r"^Found 0 puzzle\(s\)\.$",
|
||||
r"-+$",
|
||||
],
|
||||
re.MULTILINE | re.DOTALL
|
||||
)
|
||||
|
||||
recipe_dbref = self._good_recipe(
|
||||
'makefire', ['steel', 'flint'], ['fire'],
|
||||
and_destroy_it=False)
|
||||
|
||||
msg = self.call(
|
||||
puzzles.CmdListPuzzleRecipes(),
|
||||
'',
|
||||
caller=self.char1
|
||||
)
|
||||
self._assert_msg_matched(
|
||||
msg,
|
||||
[
|
||||
r"^-+$",
|
||||
r"^Puzzle 'makefire'.*$",
|
||||
r"^Success Caller message:$",
|
||||
r"^Success Location message:$",
|
||||
r"^Mask:$",
|
||||
r"^Parts$",
|
||||
r"^.*key: steel$",
|
||||
r"^.*key: flint$",
|
||||
r"^Results$",
|
||||
r"^.*key: fire$",
|
||||
r"^.*key: steel$",
|
||||
r"^.*key: flint$",
|
||||
r"^-+$",
|
||||
r"^Found 1 puzzle\(s\)\.$",
|
||||
r"^-+$",
|
||||
],
|
||||
re.MULTILINE | re.DOTALL
|
||||
)
|
||||
|
||||
msg = self.call(
|
||||
puzzles.CmdListArmedPuzzles(),
|
||||
'',
|
||||
caller=self.char1
|
||||
)
|
||||
self._assert_msg_matched(
|
||||
msg,
|
||||
[
|
||||
r"^-+$",
|
||||
r"^-+$",
|
||||
r"^Found 0 armed puzzle\(s\)\.$",
|
||||
r"^-+$"
|
||||
],
|
||||
re.MULTILINE | re.DOTALL
|
||||
)
|
||||
|
||||
self._arm(recipe_dbref, 'makefire', ['steel', 'flint'])
|
||||
|
||||
msg = self.call(
|
||||
puzzles.CmdListArmedPuzzles(),
|
||||
'',
|
||||
caller=self.char1
|
||||
)
|
||||
self._assert_msg_matched(
|
||||
msg,
|
||||
[
|
||||
r"^-+$",
|
||||
r"^Puzzle name: makefire$",
|
||||
r"^.*steel.* at \s+ Room.*$",
|
||||
r"^.*flint.* at \s+ Room.*$",
|
||||
r"^Found 1 armed puzzle\(s\)\.$",
|
||||
r"^-+$",
|
||||
],
|
||||
re.MULTILINE | re.DOTALL
|
||||
)
|
||||
|
||||
def test_e2e(self):
|
||||
|
||||
def _destroy_objs_in_room(keys):
|
||||
for obj in self.room1.contents:
|
||||
if obj.key in keys:
|
||||
obj.delete()
|
||||
|
||||
# parts don't survive resolution
|
||||
# but produce a large result set
|
||||
tree = create_object(
|
||||
self.object_typeclass,
|
||||
key='tree', location=self.char1.location)
|
||||
axe = create_object(
|
||||
self.object_typeclass,
|
||||
key='axe', location=self.char1.location)
|
||||
sweat = create_object(
|
||||
self.object_typeclass,
|
||||
key='sweat', location=self.char1.location)
|
||||
dull_axe = create_object(
|
||||
self.object_typeclass,
|
||||
key='dull axe', location=self.char1.location)
|
||||
timber = create_object(
|
||||
self.object_typeclass,
|
||||
key='timber', location=self.char1.location)
|
||||
log = create_object(
|
||||
self.object_typeclass,
|
||||
key='log', location=self.char1.location)
|
||||
parts = ['tree', 'axe']
|
||||
results = (['sweat'] * 10) + ['dull axe'] + (['timber'] * 20) + (['log'] * 50)
|
||||
recipe_dbref = self._good_recipe(
|
||||
'lumberjack',
|
||||
parts, results,
|
||||
and_destroy_it=False
|
||||
)
|
||||
|
||||
_destroy_objs_in_room(set(parts + results))
|
||||
|
||||
sps = sorted(parts)
|
||||
expected = {key: len(list(grp)) for key, grp in itertools.groupby(sps)}
|
||||
expected.update({r: 0 for r in set(results)})
|
||||
|
||||
self._arm(recipe_dbref, 'lumberjack', parts)
|
||||
self._check_room_contents(expected)
|
||||
|
||||
self._use(','.join(parts), 'You are a Genius')
|
||||
srs = sorted(set(results))
|
||||
expected = {(key, len(list(grp))) for key, grp in itertools.groupby(srs)}
|
||||
expected.update({p: 0 for p in set(parts)})
|
||||
self._check_room_contents(expected)
|
||||
|
||||
# parts also appear in results
|
||||
# causing a new puzzle to be armed 'automatically'
|
||||
# i.e. the puzzle is self-sustaining
|
||||
hole = create_object(
|
||||
self.object_typeclass,
|
||||
key='hole', location=self.char1.location)
|
||||
shovel = create_object(
|
||||
self.object_typeclass,
|
||||
key='shovel', location=self.char1.location)
|
||||
dirt = create_object(
|
||||
self.object_typeclass,
|
||||
key='dirt', location=self.char1.location)
|
||||
|
||||
parts = ['shovel', 'hole']
|
||||
results = ['dirt', 'hole', 'shovel']
|
||||
recipe_dbref = self._good_recipe(
|
||||
'digger',
|
||||
parts, results,
|
||||
and_destroy_it=False,
|
||||
expected_count=2
|
||||
)
|
||||
|
||||
_destroy_objs_in_room(set(parts + results))
|
||||
|
||||
nresolutions = 0
|
||||
|
||||
sps = sorted(set(parts))
|
||||
expected = {key: len(list(grp)) for key, grp in itertools.groupby(sps)}
|
||||
expected.update({'dirt': nresolutions})
|
||||
|
||||
self._arm(recipe_dbref, 'digger', parts)
|
||||
self._check_room_contents(expected)
|
||||
|
||||
for i in range(10):
|
||||
self._use(','.join(parts), 'You are a Genius')
|
||||
nresolutions += 1
|
||||
expected.update({'dirt': nresolutions})
|
||||
self._check_room_contents(expected)
|
||||
|
||||
# Uppercase puzzle name
|
||||
balloon = create_object(
|
||||
self.object_typeclass,
|
||||
key='Balloon', location=self.char1.location)
|
||||
parts = ['Balloon']
|
||||
results = ['Balloon']
|
||||
recipe_dbref = self._good_recipe(
|
||||
'boom!!!',
|
||||
parts, results,
|
||||
and_destroy_it=False,
|
||||
expected_count=3
|
||||
)
|
||||
|
||||
_destroy_objs_in_room(set(parts + results))
|
||||
|
||||
sps = sorted(parts)
|
||||
expected = {key: len(list(grp)) for key, grp in itertools.groupby(sps)}
|
||||
|
||||
self._arm(recipe_dbref, 'boom!!!', parts)
|
||||
self._check_room_contents(expected)
|
||||
|
||||
self._use(','.join(parts), 'You are a Genius')
|
||||
srs = sorted(set(results))
|
||||
expected = {(key, len(list(grp))) for key, grp in itertools.groupby(srs)}
|
||||
self._check_room_contents(expected)
|
||||
|
||||
def test_e2e_accumulative(self):
|
||||
flashlight = create_object(
|
||||
self.object_typeclass,
|
||||
key='flashlight', location=self.char1.location)
|
||||
flashlight_w_1 = create_object(
|
||||
self.object_typeclass,
|
||||
key='flashlight-w-1', location=self.char1.location)
|
||||
flashlight_w_2 = create_object(
|
||||
self.object_typeclass,
|
||||
key='flashlight-w-2', location=self.char1.location)
|
||||
flashlight_w_3 = create_object(
|
||||
self.object_typeclass,
|
||||
key='flashlight-w-3',
|
||||
location=self.char1.location)
|
||||
battery = create_object(
|
||||
self.object_typeclass,
|
||||
key='battery', location=self.char1.location)
|
||||
|
||||
battery.tags.add('flashlight-1', category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
battery.tags.add('flashlight-2', category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
battery.tags.add('flashlight-3', category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
|
||||
# TODO: instead of tagging each flashlight,
|
||||
# arm and resolve each puzzle in order so they all
|
||||
# are tagged correctly
|
||||
# it will be necessary to add/remove parts/results because
|
||||
# each battery is supposed to be consumed during resolution
|
||||
# as the new flashlight has one more battery than before
|
||||
flashlight_w_1.tags.add('flashlight-2', category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
flashlight_w_2.tags.add('flashlight-3', category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
|
||||
recipe_fl1_dbref = self._good_recipe('flashlight-1', ['flashlight', 'battery'], ['flashlight-w-1'] , and_destroy_it=False,
|
||||
expected_count=1)
|
||||
recipe_fl2_dbref = self._good_recipe('flashlight-2', ['flashlight-w-1', 'battery'], ['flashlight-w-2'] , and_destroy_it=False,
|
||||
expected_count=2)
|
||||
recipe_fl3_dbref = self._good_recipe('flashlight-3', ['flashlight-w-2', 'battery'], ['flashlight-w-3'] , and_destroy_it=False,
|
||||
expected_count=3)
|
||||
|
||||
# delete protoparts
|
||||
for obj in [battery, flashlight, flashlight_w_1,
|
||||
flashlight_w_2, flashlight_w_3]:
|
||||
obj.delete()
|
||||
|
||||
def _group_parts(parts, excluding=set()):
|
||||
group = dict()
|
||||
dbrefs = dict()
|
||||
for o in self.room1.contents:
|
||||
if o.key in parts and o.dbref not in excluding:
|
||||
if o.key not in group:
|
||||
group[o.key] = []
|
||||
group[o.key].append(o.dbref)
|
||||
dbrefs[o.dbref] = o
|
||||
return group, dbrefs
|
||||
|
||||
# arm each puzzle and group its parts
|
||||
self._arm(recipe_fl1_dbref, 'flashlight-1', ['battery', 'flashlight'])
|
||||
fl1_parts, fl1_dbrefs = _group_parts(['battery', 'flashlight'])
|
||||
self._arm(recipe_fl2_dbref, 'flashlight-2', ['battery', 'flashlight-w-1'])
|
||||
fl2_parts, fl2_dbrefs = _group_parts(['battery', 'flashlight-w-1'], excluding=fl1_dbrefs.keys())
|
||||
self._arm(recipe_fl3_dbref, 'flashlight-3', ['battery', 'flashlight-w-2'])
|
||||
fl3_parts, fl3_dbrefs = _group_parts(['battery', 'flashlight-w-2'], excluding=set(fl1_dbrefs.keys() + fl2_dbrefs.keys()))
|
||||
|
||||
self._check_room_contents({
|
||||
'battery': 3,
|
||||
'flashlight': 1,
|
||||
'flashlight-w-1': 1,
|
||||
'flashlight-w-2': 1,
|
||||
'flashlight-w-3': 0
|
||||
})
|
||||
|
||||
# all batteries have identical protodefs
|
||||
battery_1 = fl1_dbrefs[fl1_parts['battery'][0]]
|
||||
battery_2 = fl2_dbrefs[fl2_parts['battery'][0]]
|
||||
battery_3 = fl3_dbrefs[fl3_parts['battery'][0]]
|
||||
protodef_battery_1 = puzzles.proto_def(battery_1, with_tags=False)
|
||||
del(protodef_battery_1['prototype_key'])
|
||||
protodef_battery_2 = puzzles.proto_def(battery_2, with_tags=False)
|
||||
del(protodef_battery_2['prototype_key'])
|
||||
protodef_battery_3 = puzzles.proto_def(battery_3, with_tags=False)
|
||||
del(protodef_battery_3['prototype_key'])
|
||||
assert protodef_battery_1 == protodef_battery_2 == protodef_battery_3
|
||||
|
||||
# each battery can be used in every other puzzle
|
||||
|
||||
b1_parts_dict, b1_puzzlenames, b1_protodefs = puzzles._lookups_parts_puzzlenames_protodefs([battery_1])
|
||||
_puzzles = puzzles._puzzles_by_names(b1_puzzlenames.keys())
|
||||
assert set(['flashlight-1', 'flashlight-2', 'flashlight-3']) \
|
||||
== set([p.db.puzzle_name for p in _puzzles])
|
||||
matched_puzzles = puzzles._matching_puzzles(_puzzles, b1_puzzlenames, b1_protodefs)
|
||||
assert 0 == len(matched_puzzles)
|
||||
|
||||
b2_parts_dict, b2_puzzlenames, b2_protodefs = puzzles._lookups_parts_puzzlenames_protodefs([battery_2])
|
||||
_puzzles = puzzles._puzzles_by_names(b2_puzzlenames.keys())
|
||||
assert set(['flashlight-1', 'flashlight-2', 'flashlight-3']) \
|
||||
== set([p.db.puzzle_name for p in _puzzles])
|
||||
matched_puzzles = puzzles._matching_puzzles(_puzzles, b2_puzzlenames, b2_protodefs)
|
||||
assert 0 == len(matched_puzzles)
|
||||
b3_parts_dict, b3_puzzlenames, b3_protodefs = puzzles._lookups_parts_puzzlenames_protodefs([battery_3])
|
||||
_puzzles = puzzles._puzzles_by_names(b3_puzzlenames.keys())
|
||||
assert set(['flashlight-1', 'flashlight-2', 'flashlight-3']) \
|
||||
== set([p.db.puzzle_name for p in _puzzles])
|
||||
matched_puzzles = puzzles._matching_puzzles(_puzzles, b3_puzzlenames, b3_protodefs)
|
||||
assert 0 == len(matched_puzzles)
|
||||
|
||||
assert battery_1 == b1_parts_dict.values()[0]
|
||||
assert battery_2 == b2_parts_dict.values()[0]
|
||||
assert battery_3 == b3_parts_dict.values()[0]
|
||||
assert b1_puzzlenames.keys() == b2_puzzlenames.keys() == b3_puzzlenames.keys()
|
||||
for puzzle_name in ['flashlight-1', 'flashlight-2', 'flashlight-3']:
|
||||
assert puzzle_name in b1_puzzlenames
|
||||
assert puzzle_name in b2_puzzlenames
|
||||
assert puzzle_name in b3_puzzlenames
|
||||
assert b1_protodefs.values()[0] == b2_protodefs.values()[0] == b3_protodefs.values()[0] \
|
||||
== protodef_battery_1 == protodef_battery_2 == protodef_battery_3
|
||||
|
||||
# all flashlights have similar protodefs except their key
|
||||
flashlight_1 = fl1_dbrefs[fl1_parts['flashlight'][0]]
|
||||
flashlight_2 = fl2_dbrefs[fl2_parts['flashlight-w-1'][0]]
|
||||
flashlight_3 = fl3_dbrefs[fl3_parts['flashlight-w-2'][0]]
|
||||
protodef_flashlight_1 = puzzles.proto_def(flashlight_1, with_tags=False)
|
||||
del(protodef_flashlight_1['prototype_key'])
|
||||
assert protodef_flashlight_1['key'] == 'flashlight'
|
||||
del(protodef_flashlight_1['key'])
|
||||
protodef_flashlight_2 = puzzles.proto_def(flashlight_2, with_tags=False)
|
||||
del(protodef_flashlight_2['prototype_key'])
|
||||
assert protodef_flashlight_2['key'] == 'flashlight-w-1'
|
||||
del(protodef_flashlight_2['key'])
|
||||
protodef_flashlight_3 = puzzles.proto_def(flashlight_3, with_tags=False)
|
||||
del(protodef_flashlight_3['prototype_key'])
|
||||
assert protodef_flashlight_3['key'] == 'flashlight-w-2'
|
||||
del(protodef_flashlight_3['key'])
|
||||
assert protodef_flashlight_1 == protodef_flashlight_2 == protodef_flashlight_3
|
||||
|
||||
# each flashlight can only be used in its own puzzle
|
||||
|
||||
f1_parts_dict, f1_puzzlenames, f1_protodefs = puzzles._lookups_parts_puzzlenames_protodefs([flashlight_1])
|
||||
_puzzles = puzzles._puzzles_by_names(f1_puzzlenames.keys())
|
||||
assert set(['flashlight-1']) \
|
||||
== set([p.db.puzzle_name for p in _puzzles])
|
||||
matched_puzzles = puzzles._matching_puzzles(_puzzles, f1_puzzlenames, f1_protodefs)
|
||||
assert 0 == len(matched_puzzles)
|
||||
f2_parts_dict, f2_puzzlenames, f2_protodefs = puzzles._lookups_parts_puzzlenames_protodefs([flashlight_2])
|
||||
_puzzles = puzzles._puzzles_by_names(f2_puzzlenames.keys())
|
||||
assert set(['flashlight-2']) \
|
||||
== set([p.db.puzzle_name for p in _puzzles])
|
||||
matched_puzzles = puzzles._matching_puzzles(_puzzles, f2_puzzlenames, f2_protodefs)
|
||||
assert 0 == len(matched_puzzles)
|
||||
f3_parts_dict, f3_puzzlenames, f3_protodefs = puzzles._lookups_parts_puzzlenames_protodefs([flashlight_3])
|
||||
_puzzles = puzzles._puzzles_by_names(f3_puzzlenames.keys())
|
||||
assert set(['flashlight-3']) \
|
||||
== set([p.db.puzzle_name for p in _puzzles])
|
||||
matched_puzzles = puzzles._matching_puzzles(_puzzles, f3_puzzlenames, f3_protodefs)
|
||||
assert 0 == len(matched_puzzles)
|
||||
|
||||
assert flashlight_1 == f1_parts_dict.values()[0]
|
||||
assert flashlight_2 == f2_parts_dict.values()[0]
|
||||
assert flashlight_3 == f3_parts_dict.values()[0]
|
||||
for puzzle_name in set(f1_puzzlenames.keys() + f2_puzzlenames.keys() + f3_puzzlenames.keys()):
|
||||
assert puzzle_name in ['flashlight-1', 'flashlight-2', 'flashlight-3', 'puzzle_member']
|
||||
protodef_flashlight_1['key'] = 'flashlight'
|
||||
assert f1_protodefs.values()[0] == protodef_flashlight_1
|
||||
protodef_flashlight_2['key'] = 'flashlight-w-1'
|
||||
assert f2_protodefs.values()[0] == protodef_flashlight_2
|
||||
protodef_flashlight_3['key'] = 'flashlight-w-2'
|
||||
assert f3_protodefs.values()[0] == protodef_flashlight_3
|
||||
|
||||
# each battery can be matched with every other flashlight
|
||||
# to potentially resolve each puzzle
|
||||
for batt in [battery_1, battery_2, battery_3]:
|
||||
parts_dict, puzzlenames, protodefs = puzzles._lookups_parts_puzzlenames_protodefs([batt, flashlight_1])
|
||||
assert set([batt.dbref, flashlight_1.dbref]) == set(puzzlenames['flashlight-1'])
|
||||
assert set([batt.dbref]) == set(puzzlenames['flashlight-2'])
|
||||
assert set([batt.dbref]) == set(puzzlenames['flashlight-3'])
|
||||
_puzzles = puzzles._puzzles_by_names(puzzlenames.keys())
|
||||
assert set(['flashlight-1', 'flashlight-2', 'flashlight-3']) == set([p.db.puzzle_name for p in _puzzles])
|
||||
matched_puzzles = puzzles._matching_puzzles(_puzzles, puzzlenames, protodefs)
|
||||
assert 1 == len(matched_puzzles)
|
||||
parts_dict, puzzlenames, protodefs = puzzles._lookups_parts_puzzlenames_protodefs([batt, flashlight_2])
|
||||
assert set([batt.dbref]) == set(puzzlenames['flashlight-1'])
|
||||
assert set([batt.dbref, flashlight_2.dbref]) == set(puzzlenames['flashlight-2'])
|
||||
assert set([batt.dbref]) == set(puzzlenames['flashlight-3'])
|
||||
_puzzles = puzzles._puzzles_by_names(puzzlenames.keys())
|
||||
assert set(['flashlight-1','flashlight-2', 'flashlight-3']) == set([p.db.puzzle_name for p in _puzzles])
|
||||
matched_puzzles = puzzles._matching_puzzles(_puzzles, puzzlenames, protodefs)
|
||||
assert 1 == len(matched_puzzles)
|
||||
parts_dict, puzzlenames, protodefs = puzzles._lookups_parts_puzzlenames_protodefs([batt, flashlight_3])
|
||||
assert set([batt.dbref]) == set(puzzlenames['flashlight-1'])
|
||||
assert set([batt.dbref]) == set(puzzlenames['flashlight-2'])
|
||||
assert set([batt.dbref, flashlight_3.dbref]) == set(puzzlenames['flashlight-3'])
|
||||
_puzzles = puzzles._puzzles_by_names(puzzlenames.keys())
|
||||
assert set(['flashlight-1','flashlight-2', 'flashlight-3']) == set([p.db.puzzle_name for p in _puzzles])
|
||||
matched_puzzles = puzzles._matching_puzzles(_puzzles, puzzlenames, protodefs)
|
||||
assert 1 == len(matched_puzzles)
|
||||
|
||||
# delete all parts
|
||||
for part in fl1_dbrefs.values() + fl2_dbrefs.values() + fl3_dbrefs.values():
|
||||
part.delete()
|
||||
|
||||
self._check_room_contents({
|
||||
'battery': 0,
|
||||
'flashlight': 0,
|
||||
'flashlight-w-1': 0,
|
||||
'flashlight-w-2': 0,
|
||||
'flashlight-w-3': 0
|
||||
})
|
||||
|
||||
# arm first puzzle 3 times and group its parts so we can solve
|
||||
# all puzzles with the parts from the 1st armed
|
||||
for i in range(3):
|
||||
self._arm(recipe_fl1_dbref, 'flashlight-1', ['battery', 'flashlight'])
|
||||
fl1_parts, fl1_dbrefs = _group_parts(['battery', 'flashlight'])
|
||||
|
||||
# delete the 2 extra flashlights so we can start solving
|
||||
for flashlight_dbref in fl1_parts['flashlight'][1:]:
|
||||
fl1_dbrefs[flashlight_dbref].delete()
|
||||
|
||||
self._check_room_contents({
|
||||
'battery': 3,
|
||||
'flashlight': 1,
|
||||
'flashlight-w-1': 0,
|
||||
'flashlight-w-2': 0,
|
||||
'flashlight-w-3': 0
|
||||
})
|
||||
|
||||
self._use('1-battery, flashlight', 'You are a Genius')
|
||||
self._check_room_contents({
|
||||
'battery': 2,
|
||||
'flashlight': 0,
|
||||
'flashlight-w-1': 1,
|
||||
'flashlight-w-2': 0,
|
||||
'flashlight-w-3': 0
|
||||
})
|
||||
|
||||
self._use('1-battery, flashlight-w-1', 'You are a Genius')
|
||||
self._check_room_contents({
|
||||
'battery': 1,
|
||||
'flashlight': 0,
|
||||
'flashlight-w-1': 0,
|
||||
'flashlight-w-2': 1,
|
||||
'flashlight-w-3': 0
|
||||
})
|
||||
|
||||
self._use('battery, flashlight-w-2', 'You are a Genius')
|
||||
self._check_room_contents({
|
||||
'battery': 0,
|
||||
'flashlight': 0,
|
||||
'flashlight-w-1': 0,
|
||||
'flashlight-w-2': 0,
|
||||
'flashlight-w-3': 1
|
||||
})
|
||||
|
||||
def test_e2e_interchangeable_parts_and_results(self):
|
||||
# Parts and Results can be used in multiple puzzles
|
||||
egg = create_object(
|
||||
self.object_typeclass,
|
||||
key='egg', location=self.char1.location)
|
||||
flour = create_object(
|
||||
self.object_typeclass,
|
||||
key='flour', location=self.char1.location)
|
||||
boiling_water = create_object(
|
||||
self.object_typeclass,
|
||||
key='boiling water', location=self.char1.location)
|
||||
boiled_egg = create_object(
|
||||
self.object_typeclass,
|
||||
key='boiled egg', location=self.char1.location)
|
||||
dough = create_object(
|
||||
self.object_typeclass,
|
||||
key='dough', location=self.char1.location)
|
||||
pasta = create_object(
|
||||
self.object_typeclass,
|
||||
key='pasta', location=self.char1.location)
|
||||
|
||||
# Three recipes:
|
||||
# 1. breakfast: egg + boiling water = boiled egg & boiling water
|
||||
# 2. dough: egg + flour = dough
|
||||
# 3. entree: dough + boiling water = pasta & boiling water
|
||||
# tag interchangeable parts according to their puzzles' name
|
||||
egg.tags.add('breakfast', category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
egg.tags.add('dough', category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
dough.tags.add('entree', category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
boiling_water.tags.add('breakfast', category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
boiling_water.tags.add('entree', category=puzzles._PUZZLES_TAG_CATEGORY)
|
||||
|
||||
# create recipes
|
||||
recipe1_dbref = self._good_recipe('breakfast', ['egg', 'boiling water'], ['boiled egg', 'boiling water'] , and_destroy_it=False)
|
||||
recipe2_dbref = self._good_recipe('dough', ['egg', 'flour'], ['dough'] , and_destroy_it=False, expected_count=2)
|
||||
recipe3_dbref = self._good_recipe('entree', ['dough', 'boiling water'], ['pasta', 'boiling water'] , and_destroy_it=False, expected_count=3)
|
||||
|
||||
# delete protoparts
|
||||
for obj in [egg, flour, boiling_water,
|
||||
boiled_egg, dough, pasta]:
|
||||
obj.delete()
|
||||
|
||||
# arm each puzzle and group its parts
|
||||
def _group_parts(parts, excluding=set()):
|
||||
group = dict()
|
||||
dbrefs = dict()
|
||||
for o in self.room1.contents:
|
||||
if o.key in parts and o.dbref not in excluding:
|
||||
if o.key not in group:
|
||||
group[o.key] = []
|
||||
group[o.key].append(o.dbref)
|
||||
dbrefs[o.dbref] = o
|
||||
return group, dbrefs
|
||||
|
||||
self._arm(recipe1_dbref, 'breakfast', ['egg', 'boiling water'])
|
||||
breakfast_parts, breakfast_dbrefs = _group_parts(['egg', 'boiling water'])
|
||||
self._arm(recipe2_dbref, 'dough', ['egg', 'flour'])
|
||||
dough_parts, dough_dbrefs = _group_parts(['egg', 'flour'], excluding=breakfast_dbrefs.keys())
|
||||
self._arm(recipe3_dbref, 'entree', ['dough', 'boiling water'])
|
||||
entree_parts, entree_dbrefs = _group_parts(['dough', 'boiling water'], excluding=set(breakfast_dbrefs.keys() + dough_dbrefs.keys()))
|
||||
|
||||
# create a box so we can put all objects in
|
||||
# so that they can't be found during puzzle resolution
|
||||
self.box = create_object(
|
||||
self.object_typeclass,
|
||||
key='box', location=self.char1.location)
|
||||
def _box_all():
|
||||
# print "boxing all\n", "-"*20
|
||||
for o in self.room1.contents:
|
||||
if o not in [self.char1, self.char2, self.exit,
|
||||
self.obj1, self.obj2, self.box]:
|
||||
o.location = self.box
|
||||
# print o.key, o.dbref, "boxed"
|
||||
else:
|
||||
# print "skipped", o.key, o.dbref
|
||||
pass
|
||||
|
||||
def _unbox(dbrefs):
|
||||
# print "unboxing", dbrefs, "\n", "-"*20
|
||||
for o in self.box.contents:
|
||||
if o.dbref in dbrefs:
|
||||
o.location = self.room1
|
||||
# print "unboxed", o.key, o.dbref
|
||||
|
||||
# solve dough puzzle using breakfast's egg
|
||||
# and dough's flour. A new dough will be created
|
||||
_box_all()
|
||||
_unbox(breakfast_parts.pop('egg') + dough_parts.pop('flour'))
|
||||
self._use('egg, flour', 'You are a Genius')
|
||||
|
||||
# solve entree puzzle with newly created dough
|
||||
# and breakfast's boiling water. A new
|
||||
# boiling water and pasta will be created
|
||||
_unbox(breakfast_parts.pop('boiling water'))
|
||||
self._use('boiling water, dough', 'You are a Genius')
|
||||
|
||||
# solve breakfast puzzle with dough's egg
|
||||
# and newly created boiling water. A new
|
||||
# boiling water and boiled egg will be created
|
||||
_unbox(dough_parts.pop('egg'))
|
||||
self._use('boiling water, egg', 'You are a Genius')
|
||||
|
||||
# solve entree puzzle using entree's dough
|
||||
# and newly created boiling water. A new
|
||||
# boiling water and pasta will be created
|
||||
_unbox(entree_parts.pop('dough'))
|
||||
self._use('boiling water, dough', 'You are a Genius')
|
||||
|
||||
self._check_room_contents({
|
||||
'boiling water': 1,
|
||||
'pasta': 2,
|
||||
'boiled egg': 1,
|
||||
})
|
||||
|
||||
# Tests for the building_menu contrib
|
||||
from evennia.contrib.building_menu import BuildingMenu, CmdNoInput, CmdNoMatch
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue