[WIP] Recursive recipes
Summary
Features "recursive recipe crafting"
Purpose of change
From the feedback for #81030 it became clear that was actually desired is to be able to craft recursively.
Describe the solution
Give recipe components another flag: [ [ "flour", 22, "CRAFTABLE" ] ]. If those components are not present, recursively check if those components are craftable and craft those first.
When displaying recipes, show recipes which components can be crafted in a different color (similar to when its using rotten components). When crafting, craft required components first.
TODO:
- [ ] selector when multiple components are craftable
- [ ] result information for selector menu (kcal etc.)
- [ ] auto-craft the next recipe when component craft is completed
- [ ] general optimization/caching
- [ ] correct "recraft last recipe" behaviour
- [ ] check circular dependencies
- [ ] check for multiple recipes for same component (suffix)
- [ ] check for in-progress crafts
- [ ] check for components consumed by previous step
Describe alternatives you've considered
Testing
Additional context
Demo:
https://github.com/user-attachments/assets/ce5b8ecf-10bc-41f2-b41e-d10f94fca072
Just a prototype for now, currently very brittle and un-optimized.
Also don't mind the yeast_dough_rested recipe, its in preparation for the future.
Similar principles are used for construction, sometimes with very weird results.
An example: I ordered my companion to build upwards stairs. This requires the construction of half a stair, which in turn requires the construction of a shallow pit. The bizarre path chosen was to build a coffin, bury it, unearth it, and then build the half stairs on the shallow pit left behind.
This is not an isolated case, as base camp expansions can use up much more time and materials than they ought to based on similarly bizarre paths for pits, doors, and windows.
What I'm warning against here is that your recursive logic has to be robust enough to at least find a decent path to get the materials needed, or you may end up having your rare tools deconstructed to get reasonably common components you might have wanted to get through just about any other path.
This is indeed an excellent change, but please bear in mind that recipe steps are equally desired. Unattended steps would be a godsend.
This is indeed an excellent change, but please bear in mind that recipe steps are equally desired. Unattended steps would be a godsend.
I don't think unattended recipes require steps. But that will be a problem for the future.
What I'm warning against here is that your recursive logic has to be robust enough to at least find a decent path to get the materials needed, or you may end up having your rare tools deconstructed to get reasonably common components you might have wanted to get through just about any other path.
Components that are craftable have to have the flag set in the recipe. Components without the flag are ignored.
Deliberately marking components eligible for recursion reduces the risk of stupidity, but it doesn't prevent it. There are quite a few things that can be made using multiple recipes, so a choice of which one to use would have to be made. I believe there is a "base" recipe which is just the name of the item, but there can be alternatives that use suffixes. One approach would be ignore suffixed versions and only considering the base recipe. That would obviously have consequences.
Oh I forgot about suffixes. But since I plan of implementing a choice query for which component to craft if multiple are possible, similarly to current component query, it should not be too difficult to ask for the recipe version you want to use.
I don't think unattended recipes require steps.
I think they will, 'cause otherwise what you end up having is a bunch of half-finished products, and I seem to remember the core dev team being quite opposed to creating a bunch of small items for this sort of thing. It's partly a developer experience thing, in this case.
No pressure. Just wanted to give some feedback on a cool feature.
I think they will, 'cause otherwise what you end up having is a bunch of half-finished products, and I seem to remember the core dev team being quite opposed to creating a bunch of small items for this sort of thing. It's partly a developer experience thing, in this case.
No pressure. Just wanted to give some feedback on a cool feature.
The comments from #81030 made it clear that every step should have its own product to be able to be used in different recipes, so intermediate items no matter what. But yeah, not relevent yet for this PR.
That's actually a pretty decent representation of what we want, methinks
I don't think it is actually necessary to have subcomponent for steps, like i absolutely can see dough not requiring such, or set of crafts that may or may not require to unfreeze the meat before cooking it (atm we have bunch of crafts that do allow to cook frozen meat directly, and another bunch that do not), unless it is handled by allowing to require item with specific flag (like water vs water (hot))
update: can select which recipe to use for a given component. Currently shows recipe id, since I dont think there is a description of the recipe that doesn't just list the result. I will probably allow using the "name" field in recipes for non-practice recipes in a separate PR if it doesn't break other stuff like crafting menu filtering.
https://github.com/user-attachments/assets/297d4012-cb7a-4e37-8a5a-0294d1742e01
Apologies for the slow progress, but this is quite a bit above my current skill-level, but I'm still committed to see this through. Next milestone reached: start next craft when current is finished, correctly implement known recipes, so that we check follower recipes and follower crafting, and checking requirement alternatives (deduped-requirements).
https://github.com/user-attachments/assets/199857e2-2546-4353-9264-21bb3180def5
Currently marking duplicate requirements (notably LIST categories) as craftable is broken, since one part of the component is craftable and the other is not, confusing the system. I will have to adjust the de-duplicator, so that it takes into account the craftable flag. But that part of the code is so opaque that that will probably have to wait for a follow-up.
this is a beautiful PR, good luck.
I'm a little concerned about the direction of selecting components, but hopefully I'm just misunderstanding something.
The use case I'm worried about is recipes where there are dozens of component choices to make. Is there a mechanism here that either prevents that from happening altogether, or makes it where that isn't presenting the player with a dozen or more choices in order to start a craft?
The use case I'm worried about is recipes where there are dozens of component choices to make. Is there a mechanism here that either prevents that from happening altogether, or makes it where that isn't presenting the player with a dozen or more choices in order to start a craft?
If the craft can be done with existing components, it will do that without query. Otherwise if there is only 1 component with with 1 recipe to craft that component, it will do that without query.
I'm not sure if there will be many cases where you'd need to make more then ~4 choices (depending on just how recursive the crafting gets.)
If is not actually recursive, as in it will craft components for the current craft but not components for those crafts, I would imagine it wouldn't get out of control.
If it's actually recursive I don't see it working without at least sometimes walking the player through an unreasonably long list of choices about which component to use for something.
It is fully recursive, but it depends on how many intermediate recipes there are and how many alternate components those recipes have. I expect Recipes with > 4 intermediate steps to be very rare (purely on instinct/feeling).
But no matter what, it will be fewer key-presses then currently, where you have to craft each step individually. Of course I'm very open to suggestions on how to handle this better. Maybe I could calculate the time each recipe/alternate component selection takes and automatically do the shortest one, but the player may, for example, want to craft food with the highest calories instead of the quickest.
(sorry for the late responses, I don't have much time to work on this atm)
What happens when the skill/proficiency requirements of the crafting of missing components exceed the skills/proficiencies of the crafter?
An example: Leather Body Armor (a quest item) is a simple recipe where you just assemble the set of parts requiring Tailoring 1 and Principles of Leatherworking.
- Leather Armor Cuirass: Tailoring 4, Principles of Leatherworking, Skilled Leatherworking
- Leather Arm Guards, same, but Tailoring 3
- Leather Leg Guards: ditto
This is a fairly easy example, as all the skill/proficiency requirements are closely related, but the parts are considerably harder to make than assembling them. It should be similar with other armor assemblies. I tried to find appliance examples, but you currently can't make the difficult parts or make the items at all, it seems (disconnected oven uses parts you can't make, except for crude heating elements, which are harder to make than the assembly).
What happens when the skill/proficiency requirements of the crafting of missing components exceed the skills/proficiencies of the crafter?
I double checked and currently I do not check for skill/proficiency. Thank you, will fix.
What would happen if there is more than one recipe under such id? one of the extensions crafting needs is alternative tools that alter the speed of craft, and i wonder if it can be handled by something like separate recipe for "sew everything by hand" and "sew everything using sewing machine", or it's something out of scope
I agree, that would be very helpful, but I currently don't have the mental capacity to also take that on, my brain is already mush from this PR. Though if someone wants to design the system, I could do the implementation and work that into this PR, but its too much for me alone rn.
Spell checker encountered unrecognized words in the in-game text added in this pull request. See below for details.
Click to expand
- comp %s available (cache)
- comp %s craftable (cache)
This alert is automatically generated. You can simply disregard if this is inaccurate, or (optionally) you can also add the new words to tools/spell_checker/dictionary.txt so they will not trigger an alert next time.
Hints for adding a new word to the dictionary
- If the word is normally in all lowercase, such as the noun
wordor the verbdoes, add it in its lower-case form; if the word is a proper noun, such as the surnameGeorge, add it in its initial-caps form; if the word is an acronym or has special letter case, such as the acronymCDDAor the unitmW, add it by preserving the case of all the letters. A word in the dictionary will also match its initial-caps form (if the word is in all lowercase) and all-uppercase form, so a word should be added to the dictionary in its normal letter case even if used in a different letter case in a sentence. - For a word to be added to the dictionary, it should either be a real, properly-spelled modern American English word, a foreign loan word (including romanized foreign names), or a foreign or made-up word that is used consistently and commonly enough in the game. Intentional misspelling (including eye dialect) of a word should not be added unless it has become a common terminology in the game, because while someone may have a legitimate use for it, another person may spell it that way accidentally.
Just a quick status update: I'm very busy rn and won't be able to work on this for another month, give or take. If anyone wants to pick this up in the meantime, feel I'm more then willing to answer any questions.
I'm back and returning to this.