Start to add unittests
This commit is contained in:
parent
f7cce4ad10
commit
add5f90609
2 changed files with 160 additions and 112 deletions
|
|
@ -92,7 +92,7 @@ recipes.
|
||||||
|
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from evennia.utils.utils import (
|
from evennia.utils.utils import (
|
||||||
iter_to_str, callables_from_module, inherits_from)
|
iter_to_str, callables_from_module, inherits_from, make_iter)
|
||||||
from evennia.prototypes.spawner import spawn
|
from evennia.prototypes.spawner import spawn
|
||||||
from evennia.utils.create import create_object
|
from evennia.utils.create import create_object
|
||||||
|
|
||||||
|
|
@ -108,9 +108,12 @@ def _load_recipes():
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
global _RECIPE_CLASSES
|
global _RECIPE_CLASSES
|
||||||
if not _RECIPE_CLASSES:
|
if not _RECIPE_CLASSES:
|
||||||
for path in settings.CRAFT_RECIPE_MODULES:
|
paths = ["evennia.contrib.crafting.example_recipes"]
|
||||||
for cls in callables_from_module(path):
|
if hasattr(settings, "CRAFT_RECIPE_MODULES"):
|
||||||
if inherits_from(cls, CraftingRecipe):
|
paths += make_iter(settings.CRAFT_RECIPE_MODULES)
|
||||||
|
for path in paths:
|
||||||
|
for cls in callables_from_module(path).values():
|
||||||
|
if inherits_from(cls, CraftingRecipeBase):
|
||||||
_RECIPE_CLASSES[cls.name] = cls
|
_RECIPE_CLASSES[cls.name] = cls
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -120,6 +123,12 @@ class CraftingError(RuntimeError):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
class CraftingValidationError(CraftingError):
|
||||||
|
"""
|
||||||
|
Error if crafting validation failed.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
class CraftingRecipeBase:
|
class CraftingRecipeBase:
|
||||||
"""
|
"""
|
||||||
This is the base of the crafting system. The recipe handles all aspects of
|
This is the base of the crafting system. The recipe handles all aspects of
|
||||||
|
|
@ -142,6 +151,8 @@ class CraftingRecipeBase:
|
||||||
# don't set this unless crafting inputs are *not* consumed by the crafting
|
# don't set this unless crafting inputs are *not* consumed by the crafting
|
||||||
# process (otherwise subsequent calls will fail).
|
# process (otherwise subsequent calls will fail).
|
||||||
allow_reuse = False
|
allow_reuse = False
|
||||||
|
# this is set to avoid re-validation if recipe is re-run
|
||||||
|
is_validated = False
|
||||||
|
|
||||||
def __init__(self, crafter, *inputs, **kwargs):
|
def __init__(self, crafter, *inputs, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -155,9 +166,10 @@ class CraftingRecipeBase:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.crafter = crafter
|
self.crafter = crafter
|
||||||
self.inputs = self.inputs
|
self.inputs = inputs
|
||||||
self.craft_kwargs = kwargs
|
self.craft_kwargs = kwargs
|
||||||
self.allow_craft = True
|
self.allow_craft = True
|
||||||
|
self.validated_inputs = []
|
||||||
|
|
||||||
def msg(self, message, **kwargs):
|
def msg(self, message, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -171,81 +183,79 @@ class CraftingRecipeBase:
|
||||||
"""
|
"""
|
||||||
self.crafter.msg(message, {"type": "crafting"})
|
self.crafter.msg(message, {"type": "crafting"})
|
||||||
|
|
||||||
def validate_inputs(self, *inputs, **kwargs):
|
def validate_inputs(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Hook to override.
|
Hook to override.
|
||||||
|
|
||||||
Make sure the provided inputs are valid. This should always be run.
|
Make sure the provided inputs are valid. This should always be run.
|
||||||
|
This should validate `self.inputs` which are the inputs given when
|
||||||
|
creating this recipe.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
inputs (any): Items to be tried. .
|
**kwargs: These are optional extra flags passed during intialization.
|
||||||
Returns:
|
|
||||||
list or None: Return whichever items were validated (some recipes
|
Raises:
|
||||||
may allow for partial/too many ingredients) or `None` if validation failed.
|
CraftingValidationError: If validation fails.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
This method is also responsible for properly sending error messages
|
This method should store validated results on the recipe for the
|
||||||
to e.g. self.crafter (usually via `self.msg`).
|
other hooks to access. It is also responsible for properly sending
|
||||||
|
error messages to e.g. self.crafter (usually via `self.msg`).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.allow_craft:
|
if self.allow_craft:
|
||||||
return self.inputs[:]
|
self.validated_inputs = self.inputs[:]
|
||||||
|
else:
|
||||||
|
raise CraftingValidationError
|
||||||
|
|
||||||
def pre_craft(self, validated_inputs, **kwargs):
|
def pre_craft(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Hook to override.
|
Hook to override.
|
||||||
|
|
||||||
This is called just before crafting operation, after inputs have
|
This is called just before crafting operation, after inputs have been
|
||||||
been validated.
|
validated. At this point the validated inputs are available on the
|
||||||
|
class instance.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
validated_inputs (any): Data previously returned from `validate_inputs`.
|
**kwargs: Optional extra flags passed during initialization.
|
||||||
**kwargs (any): Passed from `self.craft`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
any: The validated_inputs, modified or not.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not validated_inputs:
|
|
||||||
raise CraftingError()
|
|
||||||
|
|
||||||
return validated_inputs
|
|
||||||
|
|
||||||
def do_craft(self, validated_inputs, **kwargs):
|
|
||||||
"""
|
|
||||||
Hook to override.
|
|
||||||
|
|
||||||
This performs the actual crafting. At this point the inputs are
|
|
||||||
expected to have been verified already.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
validated_inputs (any): Data previously returned from `pre_craft`.
|
|
||||||
kwargs (any): Passed from `self.craft`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
any: The result of the crafting.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def post_craft(self, validated_inputs, craft_result, **kwargs):
|
def do_craft(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Hook to override.
|
Hook to override.
|
||||||
|
|
||||||
This is called just after crafting has finished. A common use of
|
This performs the actual crafting. At this point the inputs are
|
||||||
this method is to delete the inputs.
|
expected to have been verified already. If needed, the validated
|
||||||
|
inputs are available on this recipe instance.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
validated_inputs (any): The inputs used as part of the crafting.
|
validated_inputs (any): Data previously returned from `pre_craft`.
|
||||||
craft_result (any): The crafted result, provided by `self.do_craft`.
|
**kwargs: Any extra flags passed at initialization.
|
||||||
kwargs (any): Passed from `self.craft`.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
any: The return of the craft, possibly modified in this method.
|
any: The result of crafting.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return craft_result
|
return None
|
||||||
|
|
||||||
|
def post_craft(self, crafting_result, **kwargs):
|
||||||
|
"""
|
||||||
|
Hook to override.
|
||||||
|
|
||||||
|
This is called just after crafting has finished. A common use of this
|
||||||
|
method is to delete the inputs.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
crafting_result (any): The outcome of crafting, as returned by `do_craft`.
|
||||||
|
**kwargs: Any extra flags passed at initialization.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
any: The final crafting result.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return crafting_result
|
||||||
|
|
||||||
def craft(self, raise_exception=False, **kwargs):
|
def craft(self, raise_exception=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -264,8 +274,10 @@ class CraftingRecipeBase:
|
||||||
any: The result of the craft, or `None` if crafting failed.
|
any: The result of the craft, or `None` if crafting failed.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
CraftingError: If crafting would return `None` and raise_exception`
|
CraftingValidationError: If recipe validation failed and
|
||||||
is set.
|
`raise_exception` is True.
|
||||||
|
CraftingError: On If trying to rerun a no-rerun recipe, or if crafting
|
||||||
|
would return `None` and raise_exception` is set.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
craft_result = None
|
craft_result = None
|
||||||
|
|
@ -276,22 +288,24 @@ class CraftingRecipeBase:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# this assigns to self.validated_inputs
|
# this assigns to self.validated_inputs
|
||||||
validated_inputs = self.validate_inputs(*self.inputs, **craft_kwargs)
|
if not self.is_validated:
|
||||||
|
self.validate_inputs(**craft_kwargs)
|
||||||
|
self.is_validated = True
|
||||||
|
|
||||||
# run the crafting process
|
# run the crafting process - each accesses validated data directly
|
||||||
self.pre_craft(validated_inputs, **craft_kwargs)
|
self.pre_craft(**craft_kwargs)
|
||||||
craft_result = self.do_craft(validated_inputs, **craft_kwargs)
|
craft_result = self.do_craft(**craft_kwargs)
|
||||||
craft_result = self.post_craft(validated_inputs, craft_result, **craft_kwargs)
|
self.post_craft(craft_result, **craft_kwargs)
|
||||||
except CraftingError as exc:
|
except (CraftingError, CraftingValidationError) as exc:
|
||||||
# use this to abort crafting early
|
# use this to abort crafting early
|
||||||
if exc.message:
|
if raise_exception:
|
||||||
self.msg(exc.message)
|
raise
|
||||||
# possibly turn off re-use depending on class setting
|
# possibly turn off re-use depending on class setting
|
||||||
self.allow_craft = self.allow_reuse
|
self.allow_craft = self.allow_reuse
|
||||||
else:
|
elif not self.allow_reuse:
|
||||||
err = "Cannot re-run crafting without refreshing recipe first."
|
raise CraftingError("Cannot re-run crafting without refreshing recipe first.")
|
||||||
if craft_result is None and raise_exception:
|
if craft_result is None and raise_exception:
|
||||||
raise CraftingError(err)
|
raise CraftingError(f"Crafting of {self.name} failed.")
|
||||||
return craft_result
|
return craft_result
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -368,7 +382,7 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
|
|
||||||
custom messages all have custom formatting markers (default strings are shown):
|
custom messages all have custom formatting markers (default strings are shown):
|
||||||
|
|
||||||
{missing}: Comma-separated list of components missing for missing/out of order errors.
|
{missing}: Comma-separated list of tool/consumable missing for missing/out of order errors.
|
||||||
{inputs}: Comma-separated list of any inputs (tools + consumables) involved in error.
|
{inputs}: Comma-separated list of any inputs (tools + consumables) involved in error.
|
||||||
{tools}: Comma-sepatated list of tools involved in error.
|
{tools}: Comma-sepatated list of tools involved in error.
|
||||||
{consumables}: Comma-separated list of consumables involved in error.
|
{consumables}: Comma-separated list of consumables involved in error.
|
||||||
|
|
@ -464,37 +478,70 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
failed_message = "Failed to craft {outputs}."
|
failed_message = "Failed to craft {outputs}."
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Internally, this class stores validated data in
|
||||||
|
`.validated_consumables` and `.validated_tools` respectively. The
|
||||||
|
`.validated_inputs` holds a list of all types in the order inserted
|
||||||
|
to the class constructor.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.validated_consumables = []
|
||||||
|
self.validated_tools = []
|
||||||
|
|
||||||
if self.consumable_names:
|
if self.consumable_names:
|
||||||
assert len(self.consumable_names) == len(self.consumable_tags), \
|
assert len(self.consumable_names) == len(self.consumable_tags), \
|
||||||
"Crafting .consumable_names list must have the same length as .consumable_tags."
|
f"Crafting {self.__class__}.consumable_names list must " \
|
||||||
|
"have the same length as .consumable_tags."
|
||||||
else:
|
else:
|
||||||
self.consumable_names = self.consumable_tags
|
self.consumable_names = self.consumable_tags
|
||||||
|
|
||||||
|
if self.tool_names:
|
||||||
|
assert len(self.tool_names) == len(self.tool_tags), \
|
||||||
|
f"Crafting {self.__class__}.tool_names list must " \
|
||||||
|
"have the same length as .tool_tags."
|
||||||
|
else:
|
||||||
|
self.tool_names = self.tool_tags
|
||||||
|
|
||||||
if self.output_names:
|
if self.output_names:
|
||||||
assert len(self.consumable_names) == len(self.consumable_tags), \
|
assert len(self.consumable_names) == len(self.consumable_tags), \
|
||||||
"Crafting .output_names list must have the same length as .output_prototypes."
|
f"Crafting {self.__class__}.output_names list must " \
|
||||||
|
"have the same length as .output_prototypes."
|
||||||
else:
|
else:
|
||||||
self.output_names = [
|
self.output_names = [
|
||||||
prot.get("key", prot.get("typeclass"), "unnamed")
|
prot.get("key", prot.get("typeclass", "unnamed"))
|
||||||
for prot in self.output_prototypes]
|
if isinstance(prot, dict) else str(prot)
|
||||||
|
for prot in self.output_prototypes
|
||||||
|
]
|
||||||
|
|
||||||
self.allow_reuse = not self.consume_inputs
|
assert isinstance(self.output_prototypes, (list, tuple)), \
|
||||||
|
"Crafting {self.__class__}.output_prototypes must be a list or tuple."
|
||||||
|
|
||||||
|
# don't allow reuse if we have consumables. If only tools we can reuse
|
||||||
|
# over and over since nothing changes.
|
||||||
|
self.allow_reuse = not bool(self.consumable_tags)
|
||||||
|
|
||||||
def _format_message(self, message, **kwargs):
|
def _format_message(self, message, **kwargs):
|
||||||
|
|
||||||
missing = iter_to_str(kwargs.get("missing", "nothing"))
|
missing = iter_to_str(kwargs.get("missing", ""))
|
||||||
|
involved_tools = iter_to_str(kwargs.get("tools", ""))
|
||||||
|
involved_cons = iter_to_str(kwargs.get("consumables", ""))
|
||||||
|
|
||||||
# build template context
|
# build template context
|
||||||
mapping = {"missing": iter_to_str(missing)}
|
mapping = {"missing": iter_to_str(missing)}
|
||||||
mapping.update({
|
mapping.update({
|
||||||
f"i{ind}": self.consumable_names[ind]
|
f"i{ind}": self.consumable_names[ind]
|
||||||
for ind, name in enumerate(self.consumable_names.values())
|
for ind, name in enumerate(self.consumable_names or self.consumable_tags)
|
||||||
})
|
})
|
||||||
mapping.update({
|
mapping.update({
|
||||||
f"o{ind}": self.output_names[ind]
|
f"o{ind}": self.output_names[ind]
|
||||||
for ind, name in enumerate(self.output_names.values())
|
for ind, name in enumerate(self.output_names)
|
||||||
})
|
})
|
||||||
|
mapping["tools"] = involved_tools
|
||||||
|
mapping["consumables"] = involved_cons
|
||||||
|
|
||||||
mapping["inputs"] = iter_to_str(self.consumable_names)
|
mapping["inputs"] = iter_to_str(self.consumable_names)
|
||||||
mapping["outputs"] = iter_to_str(self.output_names)
|
mapping["outputs"] = iter_to_str(self.output_names)
|
||||||
|
|
||||||
|
|
@ -536,7 +583,7 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
|
|
||||||
tools = []
|
tools = []
|
||||||
for itag, tag in enumerate(self.tool_tags):
|
for itag, tag in enumerate(self.tool_tags):
|
||||||
tools.append(
|
tools.extend(
|
||||||
create_object(
|
create_object(
|
||||||
key=tool_key or (self.tool_names[itag] if self.tool_names
|
key=tool_key or (self.tool_names[itag] if self.tool_names
|
||||||
else tag.capitalize()),
|
else tag.capitalize()),
|
||||||
|
|
@ -546,7 +593,7 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
)
|
)
|
||||||
consumables = []
|
consumables = []
|
||||||
for itag, tag in enumerate(self.consumable_tags):
|
for itag, tag in enumerate(self.consumable_tags):
|
||||||
consumables.append(
|
consumables.extend(
|
||||||
create_object(
|
create_object(
|
||||||
key=cons_key or (self.consumable_names[itag] if
|
key=cons_key or (self.consumable_names[itag] if
|
||||||
self.consumable_names else
|
self.consumable_names else
|
||||||
|
|
@ -557,11 +604,15 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
)
|
)
|
||||||
return tools, consumables
|
return tools, consumables
|
||||||
|
|
||||||
def validate_inputs(self, *inputs, **kwargs):
|
def validate_inputs(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Check so the given inputs are what is needed.
|
Check so the given inputs are what is needed. This operates on `self.inputs` which
|
||||||
|
is set to the inputs added to the class constructor. Validated data is stored as
|
||||||
|
lists on `.validated_tools` and `.validated_consumables` respectively.
|
||||||
|
|
||||||
Note that on successful validation we return a tuple `(tools, consumables)`.
|
Args:
|
||||||
|
**kwargs: Any optional extra kwargs passed during initialization of
|
||||||
|
the recipe class.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -581,25 +632,25 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
self.msg(self._format_message(
|
self.msg(self._format_message(
|
||||||
error_missing_message,
|
error_missing_message,
|
||||||
missing=namelist[itag] if namelist else tagkey.capitalize()))
|
missing=namelist[itag] if namelist else tagkey.capitalize()))
|
||||||
return []
|
raise CraftingValidationError
|
||||||
if exact_order:
|
if exact_order:
|
||||||
# if we get here order is wrong
|
# if we get here order is wrong
|
||||||
self.msg(self._format_message(
|
self.msg(self._format_message(
|
||||||
error_order_message,
|
error_order_message,
|
||||||
missing=namelist[itag] if namelist else tagkey.capitalize()))
|
missing=namelist[itag] if namelist else tagkey.capitalize()))
|
||||||
return []
|
raise CraftingValidationError
|
||||||
|
|
||||||
# since we pop from the mapping, it gets ever shorter
|
# since we pop from the mapping, it gets ever shorter
|
||||||
match = tagmap.pop(found_obj, None)
|
match = tagmap.pop(found_obj, None)
|
||||||
if match:
|
if match:
|
||||||
valids.append(match)
|
valids.append(found_obj)
|
||||||
return valids
|
return valids
|
||||||
|
|
||||||
# get tools and consumables from inputs from
|
# get tools and consumables from self.inputs
|
||||||
tool_map = {obj: obj.tags.get(category=self.tool_tag_category, return_list=True)
|
tool_map = {obj: obj.tags.get(category=self.tool_tag_category, return_list=True)
|
||||||
for obj in inputs if obj and hasattr(obj, "tags")}
|
for obj in self.inputs if obj and hasattr(obj, "tags")}
|
||||||
consumable_map = {obj: obj.tags.get(category=self.tag_category, return_list=True)
|
consumable_map = {obj: obj.tags.get(category=self.tag_category, return_list=True)
|
||||||
for obj in inputs
|
for obj in self.inputs
|
||||||
if obj and hasattr(obj, "tags") and obj not in tool_map}
|
if obj and hasattr(obj, "tags") and obj not in tool_map}
|
||||||
|
|
||||||
tools = _check_completeness(
|
tools = _check_completeness(
|
||||||
|
|
@ -608,7 +659,7 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
self.tool_names,
|
self.tool_names,
|
||||||
self.exact_tools,
|
self.exact_tools,
|
||||||
self.exact_tool_order,
|
self.exact_tool_order,
|
||||||
self.error_tool_message,
|
self.error_tool_missing_message,
|
||||||
self.error_tool_order_message
|
self.error_tool_order_message
|
||||||
)
|
)
|
||||||
consumables = _check_completeness(
|
consumables = _check_completeness(
|
||||||
|
|
@ -622,13 +673,18 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
)
|
)
|
||||||
# regardless of flags, the tools/consumable lists much contain exactly
|
# regardless of flags, the tools/consumable lists much contain exactly
|
||||||
# all the recipe needs now.
|
# all the recipe needs now.
|
||||||
if (len(tools) == len(self.tool_tags) and len(consumables) == len(self.consumable_tags)):
|
if len(tools) != len(self.tool_tags):
|
||||||
return tools, consumables
|
raise CraftingValidationError
|
||||||
return None
|
if len(consumables) == len(self.consumable_tags):
|
||||||
|
raise CraftingValidationError
|
||||||
|
|
||||||
|
# all is ok!
|
||||||
|
self.validated_tools = tools
|
||||||
|
self.validated_consumables = tools
|
||||||
|
|
||||||
# including also empty hooks here for easier reference
|
# including also empty hooks here for easier reference
|
||||||
|
|
||||||
def pre_craft(self, validated_inputs, **kwargs):
|
def pre_craft(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Hook to override.
|
Hook to override.
|
||||||
|
|
||||||
|
|
@ -636,7 +692,7 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
been validated.
|
been validated.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
validated_inputs (tuple): Data previously returned from
|
*validated_inputs (any): Data previously returned from
|
||||||
`validate_inputs`. This is a tuple `(tools, consumables)`.
|
`validate_inputs`. This is a tuple `(tools, consumables)`.
|
||||||
**kwargs (any): Passed from `self.craft`.
|
**kwargs (any): Passed from `self.craft`.
|
||||||
|
|
||||||
|
|
@ -644,13 +700,9 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
any: The validated_inputs, modified or not.
|
any: The validated_inputs, modified or not.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not validated_inputs:
|
pass
|
||||||
# abort crafting here, remove if wanting some other action
|
|
||||||
raise CraftingError(f"Crafting validation error {self.name}")
|
|
||||||
|
|
||||||
return validated_inputs
|
def do_craft(self, **kwargs):
|
||||||
|
|
||||||
def do_craft(self, validated_inputs, **kwargs):
|
|
||||||
"""
|
"""
|
||||||
Hook to override.
|
Hook to override.
|
||||||
|
|
||||||
|
|
@ -670,7 +722,7 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
"""
|
"""
|
||||||
return spawn(*self.output_prototypes)
|
return spawn(*self.output_prototypes)
|
||||||
|
|
||||||
def post_craft(self, validated_inputs, craft_result, **kwargs):
|
def post_craft(self, craft_result, **kwargs):
|
||||||
"""
|
"""
|
||||||
Hook to override.
|
Hook to override.
|
||||||
|
|
||||||
|
|
@ -678,29 +730,22 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
this method is to delete the inputs.
|
this method is to delete the inputs.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
validated_inputs (tuple): the validated inputs, a tuple `(tools, consumables)`.
|
|
||||||
craft_result (any): The crafted result, provided by `self.do_craft`.
|
craft_result (any): The crafted result, provided by `self.do_craft`.
|
||||||
|
validated_inputs (tuple): the validated inputs, a tuple `(tools, consumables)`.
|
||||||
**kwargs (any): Passed from `self.craft`.
|
**kwargs (any): Passed from `self.craft`.
|
||||||
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
any: The return of the craft, possibly modified in this method.
|
any: The return of the craft, possibly modified in this method.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
consume = self.consume_inputs
|
|
||||||
|
|
||||||
_, consumables = validated_inputs or (None, None)
|
|
||||||
|
|
||||||
if craft_result:
|
if craft_result:
|
||||||
self.msg(self._format_message(self.success_message))
|
self.msg(self._format_message(self.success_message))
|
||||||
else:
|
else:
|
||||||
self.msg(self._format_message(self.failure_message))
|
self.msg(self._format_message(self.failure_message))
|
||||||
consume = self.consume_on_fail
|
|
||||||
|
|
||||||
if consume and consumables:
|
if craft_result or self.consume_on_fail:
|
||||||
# consume the inputs
|
# consume the inputs
|
||||||
for obj in consumables:
|
for obj in self.validated_consumables:
|
||||||
obj.delete()
|
obj.delete()
|
||||||
|
|
||||||
return craft_result
|
return craft_result
|
||||||
|
|
@ -709,7 +754,7 @@ class CraftingRecipe(CraftingRecipeBase):
|
||||||
# access functions
|
# access functions
|
||||||
|
|
||||||
|
|
||||||
def craft(crafter, recipe_name, *inputs, raise_exception=False, **kwargs):
|
def craft(crafter, recipe_name, *inputs, return_list=True, raise_exception=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
Craft a given recipe from a source recipe module. A recipe module is a
|
Craft a given recipe from a source recipe module. A recipe module is a
|
||||||
Python module containing recipe classes. Note that this requires
|
Python module containing recipe classes. Note that this requires
|
||||||
|
|
@ -720,8 +765,10 @@ def craft(crafter, recipe_name, *inputs, raise_exception=False, **kwargs):
|
||||||
crafter (Object): The one doing the crafting.
|
crafter (Object): The one doing the crafting.
|
||||||
recipe_name (str): This should match the `CraftRecipe.name` to use.
|
recipe_name (str): This should match the `CraftRecipe.name` to use.
|
||||||
*inputs: Suitable ingredients (Objects) to use in the crafting.
|
*inputs: Suitable ingredients (Objects) to use in the crafting.
|
||||||
|
return_list (bool, optional): Always return a list, even if zero or one items were
|
||||||
|
cracted.
|
||||||
raise_exception (bool, optional): If crafting failed for whatever
|
raise_exception (bool, optional): If crafting failed for whatever
|
||||||
reason, raise `CraftingError`.
|
reason, raise `CraftingError`. The user will still be informed by the recipe.
|
||||||
**kwargs: Optional kwargs to pass into the recipe (will passed into recipe.craft).
|
**kwargs: Optional kwargs to pass into the recipe (will passed into recipe.craft).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
|
||||||
|
|
@ -934,8 +934,8 @@ def spawn(*prototypes, **kwargs):
|
||||||
|
|
||||||
val = prot.pop("tags", [])
|
val = prot.pop("tags", [])
|
||||||
tags = []
|
tags = []
|
||||||
for (tag, category, data) in val:
|
for (tag, category, *data) in val:
|
||||||
tags.append((init_spawn_value(tag, str), category, data))
|
tags.append((init_spawn_value(tag, str), category, data[0] if data else None))
|
||||||
|
|
||||||
prototype_key = prototype.get("prototype_key", None)
|
prototype_key = prototype.get("prototype_key", None)
|
||||||
if prototype_key:
|
if prototype_key:
|
||||||
|
|
@ -955,8 +955,9 @@ def spawn(*prototypes, **kwargs):
|
||||||
# the rest are attribute tuples (attrname, value, category, locks)
|
# the rest are attribute tuples (attrname, value, category, locks)
|
||||||
val = make_iter(prot.pop("attrs", []))
|
val = make_iter(prot.pop("attrs", []))
|
||||||
attributes = []
|
attributes = []
|
||||||
for (attrname, value, category, locks) in val:
|
for (attrname, value, *rest) in val:
|
||||||
attributes.append((attrname, init_spawn_value(value), category, locks))
|
attributes.append((attrname, init_spawn_value(value),
|
||||||
|
rest[0] if rest else None, rest[1] if len(rest) > 1 else None))
|
||||||
|
|
||||||
simple_attributes = []
|
simple_attributes = []
|
||||||
for key, value in (
|
for key, value in (
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue