Files
warriorstar-orion 523c09bab9 Fix issue with cooking recipes requiring reagents (#30611)
* Fix issue with cooking recipes requiring reagents

* don't spam debug messages with autochef

* reagent step processing, other fuckery

* fix lint

* properly clean up tracked recipes
2026-02-17 17:54:04 +00:00

186 lines
7.0 KiB
Plaintext

GLOBAL_LIST_EMPTY(pcwj_recipe_dictionary)
GLOBAL_LIST_EMPTY(pcwj_cookbook_lookup)
/**
* ## ParaCooking With Jane
*
* A cooking rework ported from Sojourn and heavily adapted for Para.
*
* The recipe datum outlines a list of steps from getting a piece of food from
* point A to point B.
*
* Recipes have clear start and end points. They start with a particular item
* and end with a particular item. That said, a start item can follow multiple
* recipes until they eventually diverge as different steps are followed. In the
* case two recipes have identical steps, the user should be prompted on what
* their intended result should be. (Donuts vs Bagels)
*
* Recipes are loaded at startup. Food items reference it by the recipe_tracker
* datum.
*
* Recipes and their steps are singletons. Cooking processes should never alter
* them.
*/
/datum/cooking/recipe
/// The type of the cooking container the recipe is performed in.
var/obj/item/reagent_containers/cooking/container_type
/// Type path for the product created by the recipe.
var/product_type
/// How much of a thing is made per case of the recipe being followed.
var/product_count = 1
// Special variables that must be defined INSTEAD of product_type in order to create reagents instead of an object.
var/reagent_id
var/reagent_amount
/// Determines if we entirely replace the contents of the food product with the slurry that goes into it.
var/replace_reagents = FALSE
/// Everything appears in the catalog by default.
var/appear_in_default_catalog = TRUE
/// The category of the recipe for the cookbook PDA app and other sources of recipe info.
var/catalog_category = "Miscellaneous"
/// A list of [/datum/cooking/recipe_step]s needed to be followed
/// to create the recipe. Generally steps must be completed in order
/// for the preparation to be considered valid.
var/list/steps
/datum/cooking/recipe/proc/create_product(datum/cooking/recipe_tracker/tracker)
var/obj/item/reagent_containers/cooking/container = locateUID(tracker.container_uid)
if(!istype(container))
log_debug("failure to find container when creating recipe product!")
return
// Build up a list of reagents that went into this.
var/datum/reagents/slurry = new(maximum = 1000000)
slurry.my_atom = container
var/list/applied_steps = tracker.recipes_all_applied_steps[src]
var/output_count = 1
for(var/i in 1 to length(tracker.recipes_applied_step_data))
var/list/applied_step_data = tracker.recipes_applied_step_data[i]
if("reagent_id" in applied_step_data)
var/amount_to_remove = applied_step_data["amount"] * (1 - applied_step_data["reagent_remain_percent"])
if(!amount_to_remove)
continue
container.reagents.remove_reagent(
applied_step_data["reagent_id"], amount_to_remove, safety = TRUE)
if("rating" in applied_step_data)
output_count = max(output_count, min(3, applied_step_data["rating"]))
if(product_type) // Make a regular item
. = make_product_item(container, slurry, applied_steps, output_count)
else
QDEL_LIST_CONTENTS(container.contents)
container.contents = list()
container.reagents.clear_reagents()
if(reagent_id)
container.reagents.add_reagent(reagent_id, reagent_amount)
qdel(slurry)
/datum/cooking/recipe/proc/make_product_item(obj/item/reagent_containers/cooking/container, datum/reagents/slurry, list/applied_steps, output_count = null)
if(isnull(output_count))
output_count = 1
if(container.reagents.total_volume)
#ifdef PCWJ_DEBUG
log_debug("/recipe/proc/create_product: Transferring container reagents of [container.reagents.total_volume] to slurry of current volume [slurry.total_volume] max volume [slurry.maximum_volume]")
#endif
container.reagents.trans_to(slurry, amount=container.reagents.total_volume)
// Do reagent filtering on added items and produce
var/list/exclude_list = list()
for(var/obj/item/added_item in container.contents)
var/can_add = TRUE
var/list/exclude_specific_reagents = list()
#ifdef PCWJ_DEBUG
log_debug("/recipe/proc/create_product: Analyzing reagents of [added_item].")
#endif
for(var/i in 1 to length(applied_steps))
var/current_index = applied_steps[i]
var/datum/cooking/recipe_step = steps[current_index]
if(recipe_step in exclude_list)
continue
var/datum/cooking/recipe_step/add_item/add_item_step = recipe_step
if(istype(add_item_step))
if(add_item_step.exclude_reagents)
exclude_specific_reagents |= add_item_step.exclude_reagents
if(add_item_step.skip_reagents)
can_add = FALSE
exclude_list |= recipe_step
break
var/datum/cooking/recipe_step/add_produce/add_produce_step = recipe_step
if(istype(add_produce_step))
if(add_produce_step.exclude_reagents)
exclude_specific_reagents |= add_produce_step.exclude_reagents
if(add_produce_step.skip_reagents)
can_add = FALSE
exclude_list |= recipe_step
break
if(can_add && added_item.reagents)
if(length(exclude_specific_reagents))
for(var/id in exclude_specific_reagents)
added_item.reagents.remove_reagent(id, added_item.reagents.get_reagent_amount(id), safety = TRUE)
added_item.reagents.trans_to(slurry, amount = added_item.reagents.total_volume)
// Purge the contents of the container we no longer need it
QDEL_LIST_CONTENTS(container.contents)
for(var/i in 1 to (product_count * output_count))
var/obj/item/new_item = new product_type(container)
. = new_item
#ifdef PCWJ_DEBUG
log_debug("/recipe/proc/create_product: Item created with reagents of [new_item.reagents.total_volume]")
#endif
if(replace_reagents)
//Clearing out reagents in data. If initialize hasn't been called, we also null that out here.
#ifdef PCWJ_DEBUG
log_debug("/recipe/proc/create_product: Clearing out reagents from the [new_item]")
#endif
new_item.reagents.clear_reagents()
#ifdef PCWJ_DEBUG
log_debug("/recipe/proc/create_product: Transferring slurry of [slurry.total_volume] to [new_item] of total volume [new_item.reagents.total_volume]")
#endif
slurry.copy_to(new_item, amount=slurry.total_volume)
/proc/initialize_cooking_recipes()
GLOB.pcwj_recipe_dictionary.Cut()
GLOB.pcwj_cookbook_lookup.Cut()
var/list/recipe_paths = subtypesof(/datum/cooking/recipe)
for(var/path in recipe_paths)
var/datum/cooking/recipe/example_recipe = new path()
if(!example_recipe.container_type)
continue
var/obj/item/reagent_containers/cooking/container_type = example_recipe.container_type
LAZYORASSOCLIST(GLOB.pcwj_recipe_dictionary, example_recipe.container_type, example_recipe)
if(!example_recipe.appear_in_default_catalog)
continue
if(example_recipe.product_type)
var/atom/product = example_recipe.product_type
var/list/entry = list()
entry["name"] = product::name
entry["icon"] = product::icon
entry["icon_state"] = product::icon_state
entry["container"] = "[container_type::preposition] \a [container_type::name]"
entry["instructions"] = list()
for(var/datum/cooking/recipe_step/step in example_recipe.steps)
entry["instructions"] += step.get_pda_formatted_desc()
LAZYORASSOCLIST(GLOB.pcwj_cookbook_lookup, example_recipe.catalog_category, list(entry))