Add @puzzleedit and puzzle.db.use_success_message so puzzle resolution message can be customized by builder
This commit is contained in:
parent
c5b2e49ffa
commit
4f5c2f51ad
2 changed files with 131 additions and 15 deletions
|
|
@ -87,6 +87,9 @@ _PUZZLES_TAG_RECIPE = 'puzzle_recipe'
|
||||||
# puzzle part and puzzle result
|
# puzzle part and puzzle result
|
||||||
_PUZZLES_TAG_MEMBER = 'puzzle_member'
|
_PUZZLES_TAG_MEMBER = 'puzzle_member'
|
||||||
|
|
||||||
|
_PUZZLE_DEFAULT_FAIL_USE_MESSAGE = 'You try to utilize %s but nothing happens ... something amiss?'
|
||||||
|
_PUZZLE_DEFAULT_SUCCESS_USE_MESSAGE = 'You are a Genius!!!'
|
||||||
|
|
||||||
# ----------- UTILITY FUNCTIONS ------------
|
# ----------- UTILITY FUNCTIONS ------------
|
||||||
|
|
||||||
def proto_def(obj, with_tags=True):
|
def proto_def(obj, with_tags=True):
|
||||||
|
|
@ -106,6 +109,15 @@ def proto_def(obj, with_tags=True):
|
||||||
del(protodef['tags'])
|
del(protodef['tags'])
|
||||||
return protodef
|
return protodef
|
||||||
|
|
||||||
|
# Colorize the default success message
|
||||||
|
_i = 0
|
||||||
|
_colors = ['|r', '|g', '|y']
|
||||||
|
_msg = []
|
||||||
|
for l in _PUZZLE_DEFAULT_SUCCESS_USE_MESSAGE:
|
||||||
|
_msg += _colors[_i] + l
|
||||||
|
_i = (_i + 1) % len(_colors)
|
||||||
|
_PUZZLE_DEFAULT_SUCCESS_USE_MESSAGE = ''.join(_msg) + '|n'
|
||||||
|
|
||||||
# ------------------------------------------
|
# ------------------------------------------
|
||||||
|
|
||||||
class PuzzlePartObject(DefaultObject):
|
class PuzzlePartObject(DefaultObject):
|
||||||
|
|
@ -138,6 +150,7 @@ class PuzzleRecipe(DefaultScript):
|
||||||
self.db.parts = tuple(parts)
|
self.db.parts = tuple(parts)
|
||||||
self.db.results = tuple(results)
|
self.db.results = tuple(results)
|
||||||
self.tags.add(_PUZZLES_TAG_RECIPE, category=_PUZZLES_TAG_CATEGORY)
|
self.tags.add(_PUZZLES_TAG_RECIPE, category=_PUZZLES_TAG_CATEGORY)
|
||||||
|
self.db.use_success_message = _PUZZLE_DEFAULT_SUCCESS_USE_MESSAGE
|
||||||
|
|
||||||
|
|
||||||
class CmdCreatePuzzleRecipe(MuxCommand):
|
class CmdCreatePuzzleRecipe(MuxCommand):
|
||||||
|
|
@ -246,12 +259,80 @@ class CmdCreatePuzzleRecipe(MuxCommand):
|
||||||
caller.msg(
|
caller.msg(
|
||||||
'You may now dispose all parts and results. '
|
'You may now dispose all parts and results. '
|
||||||
'Typically, results and parts are useless afterwards.\n'
|
'Typically, results and parts are useless afterwards.\n'
|
||||||
|
'Remember to add a "success message" via:\n'
|
||||||
|
' @puzzleedit #dbref/use_success_message = <Your custom success message>\n'
|
||||||
'You are now able to arm this puzzle using Builder command:\n'
|
'You are now able to arm this puzzle using Builder command:\n'
|
||||||
' @armpuzzle <puzzle #dbref>\n\n'
|
' @armpuzzle <puzzle #dbref>\n'
|
||||||
'Or programmatically.\n'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CmdEditPuzzle(MuxCommand):
|
||||||
|
"""
|
||||||
|
Edits puzzle properties
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
@puzzleedit[/delete] <#dbref>
|
||||||
|
@puzzleedit <#dbref>/use_success_message = <Your custom message>
|
||||||
|
|
||||||
|
Switches:
|
||||||
|
delete - deletes the recipe. Existing parts and results aren't modified
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = '@puzzleedit'
|
||||||
|
# FIXME: permissions for scripts?
|
||||||
|
locks = 'cmd:perm(puzzleedit) or perm(Builder)'
|
||||||
|
help_category = 'Puzzles'
|
||||||
|
|
||||||
|
def func(self):
|
||||||
|
_USAGE = "Usage: @puzzleedit[/switches] <dbref>[/attribute = <value>]"
|
||||||
|
caller = self.caller
|
||||||
|
|
||||||
|
if not self.lhslist:
|
||||||
|
caller.msg(_USAGE)
|
||||||
|
return
|
||||||
|
|
||||||
|
if '/' in self.lhslist[0]:
|
||||||
|
recipe_dbref, attr = self.lhslist[0].split('/')
|
||||||
|
else:
|
||||||
|
recipe_dbref = self.lhslist[0]
|
||||||
|
|
||||||
|
if not utils.dbref(recipe_dbref):
|
||||||
|
caller.msg("A puzzle recipe's #dbref must be specified.\n" + _USAGE)
|
||||||
|
return
|
||||||
|
|
||||||
|
puzzle = search.search_script(recipe_dbref)
|
||||||
|
if not puzzle or not inherits_from(puzzle[0], PuzzleRecipe):
|
||||||
|
caller.msg('Invalid puzzle %r' % (recipe_dbref))
|
||||||
|
return
|
||||||
|
|
||||||
|
puzzle = puzzle[0]
|
||||||
|
puzzle_name_id = '%s(%s)' % (puzzle.name, puzzle.dbref)
|
||||||
|
|
||||||
|
if 'delete' in self.switches:
|
||||||
|
if not (puzzle.access(caller, 'control') or puzzle.access(caller, 'delete')):
|
||||||
|
caller.msg("You don't have permission to delete %s." % puzzle_name_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
puzzle.delete()
|
||||||
|
caller.msg('%s was deleted' % puzzle_name_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
else:
|
||||||
|
# edit attributes
|
||||||
|
|
||||||
|
if not (puzzle.access(caller, 'control') or puzzle.access(caller, 'edit')):
|
||||||
|
caller.msg("You don't have permission to edit %s." % puzzle_name_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
if attr == 'use_success_message':
|
||||||
|
puzzle.db.use_success_message = self.rhs
|
||||||
|
caller.msg(
|
||||||
|
"%s use_success_message = %s\n" % (puzzle_name_id, puzzle.db.use_success_message)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
class CmdArmPuzzle(MuxCommand):
|
class CmdArmPuzzle(MuxCommand):
|
||||||
"""
|
"""
|
||||||
Arms a puzzle by spawning all its parts
|
Arms a puzzle by spawning all its parts
|
||||||
|
|
@ -396,10 +477,10 @@ class CmdUsePuzzleParts(MuxCommand):
|
||||||
matched_puzzles[puzzle.dbref] = matched_dbrefparts
|
matched_puzzles[puzzle.dbref] = matched_dbrefparts
|
||||||
|
|
||||||
if len(matched_puzzles) == 0:
|
if len(matched_puzzles) == 0:
|
||||||
# FIXME: Add more random messages
|
# TODO: we could use part.fail_message instead, if any
|
||||||
# random part falls and lands on your feet
|
# random part falls and lands on your feet
|
||||||
# random part hits you square on the face
|
# random part hits you square on the face
|
||||||
caller.msg("As you try to utilize %s, nothing happens." % (many))
|
caller.msg(_PUZZLE_DEFAULT_FAIL_USE_MESSAGE % (many))
|
||||||
return
|
return
|
||||||
|
|
||||||
puzzletuples = sorted(matched_puzzles.items(), key=lambda t: len(t[1]), reverse=True)
|
puzzletuples = sorted(matched_puzzles.items(), key=lambda t: len(t[1]), reverse=True)
|
||||||
|
|
@ -440,17 +521,11 @@ class CmdUsePuzzleParts(MuxCommand):
|
||||||
for dbref in matched_dbrefparts:
|
for dbref in matched_dbrefparts:
|
||||||
parts_dict[dbref].delete()
|
parts_dict[dbref].delete()
|
||||||
|
|
||||||
# FIXME: Add random messages
|
|
||||||
# You are a genius ... no matter what your 2nd grade teacher told you
|
|
||||||
# You hear thunders and a cloud of dust raises leaving
|
|
||||||
result_names = ', '.join(result_names)
|
result_names = ', '.join(result_names)
|
||||||
caller.msg(
|
caller.msg(puzzle.db.use_success_message)
|
||||||
"You are a |wG|re|wn|ri|wu|rs|n!!!\nYou just created %s" % (
|
|
||||||
result_names
|
|
||||||
))
|
|
||||||
caller.location.msg_contents(
|
caller.location.msg_contents(
|
||||||
"|c%s|n performs some kind of tribal dance"
|
"|c%s|n performs some kind of tribal dance"
|
||||||
" and seems to create |y%s|n from thin air" % (
|
" and |y%s|n seems to appear from thin air" % (
|
||||||
caller, result_names), exclude=(caller,)
|
caller, result_names), exclude=(caller,)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -479,6 +554,7 @@ class CmdListPuzzleRecipes(MuxCommand):
|
||||||
msgf_item = "%2s|c%15s|n: |w%s|n"
|
msgf_item = "%2s|c%15s|n: |w%s|n"
|
||||||
for recipe in recipes:
|
for recipe in recipes:
|
||||||
text.append(msgf_recipe % (recipe.db.puzzle_name, recipe.name, recipe.dbref))
|
text.append(msgf_recipe % (recipe.db.puzzle_name, recipe.name, recipe.dbref))
|
||||||
|
text.append('Success message: ' + recipe.db.use_success_message)
|
||||||
text.append('Parts')
|
text.append('Parts')
|
||||||
for protopart in recipe.db.parts[:]:
|
for protopart in recipe.db.parts[:]:
|
||||||
mark = '-'
|
mark = '-'
|
||||||
|
|
@ -542,6 +618,7 @@ class PuzzleSystemCmdSet(CmdSet):
|
||||||
super(PuzzleSystemCmdSet, self).at_cmdset_creation()
|
super(PuzzleSystemCmdSet, self).at_cmdset_creation()
|
||||||
|
|
||||||
self.add(CmdCreatePuzzleRecipe())
|
self.add(CmdCreatePuzzleRecipe())
|
||||||
|
self.add(CmdEditPuzzle())
|
||||||
self.add(CmdArmPuzzle())
|
self.add(CmdArmPuzzle())
|
||||||
self.add(CmdListPuzzleRecipes())
|
self.add(CmdListPuzzleRecipes())
|
||||||
self.add(CmdListArmedPuzzles())
|
self.add(CmdListArmedPuzzles())
|
||||||
|
|
|
||||||
|
|
@ -1265,6 +1265,7 @@ class TestPuzzles(CommandTest):
|
||||||
|
|
||||||
def test_cmdset_puzzle(self):
|
def test_cmdset_puzzle(self):
|
||||||
self.char1.cmdset.add('evennia.contrib.puzzles.PuzzleSystemCmdSet')
|
self.char1.cmdset.add('evennia.contrib.puzzles.PuzzleSystemCmdSet')
|
||||||
|
# FIXME: testing nothing, this is just to bump up coverage
|
||||||
|
|
||||||
def test_cmd_puzzle(self):
|
def test_cmd_puzzle(self):
|
||||||
self._assert_no_recipes()
|
self._assert_no_recipes()
|
||||||
|
|
@ -1375,10 +1376,9 @@ class TestPuzzles(CommandTest):
|
||||||
self._use('stone', 'Which stone. There are many')
|
self._use('stone', 'Which stone. There are many')
|
||||||
self._use('flint', 'Which flint. There are many')
|
self._use('flint', 'Which flint. There are many')
|
||||||
|
|
||||||
# delete proto parts
|
# delete proto parts and proto results
|
||||||
self.stone.delete()
|
self.stone.delete()
|
||||||
self.flint.delete()
|
self.flint.delete()
|
||||||
# delete proto result
|
|
||||||
self.fire.delete()
|
self.fire.delete()
|
||||||
|
|
||||||
# solve puzzle
|
# solve puzzle
|
||||||
|
|
@ -1401,7 +1401,7 @@ class TestPuzzles(CommandTest):
|
||||||
self._check_room_contents({'stone': 2, 'flint': 2, 'fire': 1})
|
self._check_room_contents({'stone': 2, 'flint': 2, 'fire': 1})
|
||||||
|
|
||||||
# try solving with multiple parts but incomplete set
|
# try solving with multiple parts but incomplete set
|
||||||
self._use('1-stone, 2-stone', 'As you try to utilize these, nothing happens.')
|
self._use('1-stone, 2-stone', 'You try to utilize these but nothing happens ... something amiss?')
|
||||||
|
|
||||||
# arm the other puzzle. Their parts are identical
|
# arm the other puzzle. Their parts are identical
|
||||||
self._arm(recipe2_dbref, 'makefire2', ['stone', 'flint'])
|
self._arm(recipe2_dbref, 'makefire2', ['stone', 'flint'])
|
||||||
|
|
@ -1420,6 +1420,44 @@ class TestPuzzles(CommandTest):
|
||||||
self._use('stone, flint', 'You are a Genius')
|
self._use('stone, flint', 'You are a Genius')
|
||||||
self._check_room_contents({'stone': 0, 'flint': 0, 'fire': 4})
|
self._check_room_contents({'stone': 0, 'flint': 0, 'fire': 4})
|
||||||
|
|
||||||
|
def test_puzzleedit(self):
|
||||||
|
recipe_dbref = self._good_recipe('makefire', ['stone', 'flint'], ['fire'] , and_destroy_it=False)
|
||||||
|
|
||||||
|
# delete proto parts and proto results
|
||||||
|
self.stone.delete()
|
||||||
|
self.flint.delete()
|
||||||
|
self.fire.delete()
|
||||||
|
|
||||||
|
def _puzzleedit(swt, dbref, args, expmsg):
|
||||||
|
self.call(
|
||||||
|
puzzles.CmdEditPuzzle(),
|
||||||
|
'%s %s%s' % (swt, dbref, args),
|
||||||
|
expmsg,
|
||||||
|
caller=self.char1
|
||||||
|
)
|
||||||
|
|
||||||
|
# bad syntax
|
||||||
|
_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")
|
||||||
|
|
||||||
|
# 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
|
||||||
|
_puzzleedit('', recipe_dbref, '/use_success_message = Yes!', 'makefire(%s) use_success_message = Yes!' % recipe_dbref)
|
||||||
|
self._arm(recipe_dbref, 'makefire', ['stone', 'flint'])
|
||||||
|
self._use('stone, flint', 'Yes!')
|
||||||
|
|
||||||
|
# delete
|
||||||
|
_puzzleedit('/delete', recipe_dbref, '', 'makefire(%s) was deleted' % recipe_dbref)
|
||||||
|
self._assert_no_recipes()
|
||||||
|
|
||||||
def test_lspuzzlerecipes_lsarmedpuzzles(self):
|
def test_lspuzzlerecipes_lsarmedpuzzles(self):
|
||||||
msg = self.call(
|
msg = self.call(
|
||||||
puzzles.CmdListPuzzleRecipes(),
|
puzzles.CmdListPuzzleRecipes(),
|
||||||
|
|
@ -1449,6 +1487,7 @@ class TestPuzzles(CommandTest):
|
||||||
[
|
[
|
||||||
r"^-+$",
|
r"^-+$",
|
||||||
r"^Puzzle 'makefire'.*$",
|
r"^Puzzle 'makefire'.*$",
|
||||||
|
r"^Success message: .*$",
|
||||||
r"^Parts$",
|
r"^Parts$",
|
||||||
r"^.*key: stone$",
|
r"^.*key: stone$",
|
||||||
r"^.*key: flint$",
|
r"^.*key: flint$",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue