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
This commit is contained in:
warriorstar-orion
2026-02-17 12:54:04 -05:00
committed by GitHub
parent 87a1e11667
commit 523c09bab9
5 changed files with 78 additions and 62 deletions
+5 -10
View File
@@ -59,20 +59,15 @@ GLOBAL_LIST_EMPTY(pcwj_cookbook_lookup)
var/list/applied_steps = tracker.recipes_all_applied_steps[src]
var/output_count = 1
// Remember this is not necessarily a consecutive list of step indexes
// Optional steps may have been skipped
for(var/i in 1 to length(applied_steps))
var/current_index = applied_steps[i]
var/datum/cooking/recipe_step/recipe_step = steps[current_index]
for(var/i in 1 to length(tracker.recipes_applied_step_data))
var/list/applied_step_data = tracker.recipes_applied_step_data[i]
// Filter out reagents based on settings
var/datum/cooking/recipe_step/add_reagent/add_reagent_step = recipe_step
if(istype(add_reagent_step))
var/amount_to_remove = add_reagent_step.amount * (1 - add_reagent_step.remain_percent)
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(add_reagent_step.reagent_id, amount_to_remove, safety = TRUE)
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"]))
+63 -45
View File
@@ -1,3 +1,23 @@
/// A single attempt to perform a step in a recipe.
/// These are created in a recipe tracker and not kept around.
/// This exists only to make the bookkeeping around recipe tracking easier.
/datum/cooking/step_attempt
var/conditions_met
var/current_step_index
var/datum/cooking/recipe/recipe
var/datum/cooking/recipe_step/recipe_step
/datum/cooking/step_attempt/New(
datum/cooking/recipe/recipe,
datum/cooking/recipe_step/recipe_step,
current_step_index,
conditions_met
)
src.recipe = recipe
src.recipe_step = recipe_step
src.current_step_index = current_step_index
src.conditions_met = conditions_met
/// A recipe tracker is an abstract representation of the progress that a
/// cooking container has made towards any of its possible recipe outcomes.
///
@@ -41,7 +61,7 @@
/// Wrapper function for analyzing process_item internally.
/datum/cooking/recipe_tracker/proc/process_item_wrap(mob/user, obj/used)
#ifdef PCWJ_DEBUG
log_debug("/datum/cooking/recipe_tracker/proc/process_item_wrap called!")
log_debug("/datum/cooking/recipe_tracker/proc/process_item_wrap([user], [used])")
#endif
var/response = process_item(user, used)
@@ -74,44 +94,27 @@
// TODO: I *hate* passing in a user here and want to move all the necessary
// UI interactions (selecting which recipe to complete, selecting which step
// to perform) to be moved somewhere else entirely.
var/list/valid_steps = list()
var/list/valid_recipes = list()
var/list/completed_recipes = list()
var/list/silent_recipes = list()
var/list/attempted_step_per_recipe = list()
var/list/step_datas = list()
var/list/step_attempts = list()
var/completed_steps = 0
for(var/datum/cooking/recipe/recipe in recipes_last_completed_step)
var/current_idx = recipes_last_completed_step[recipe]
var/datum/cooking/recipe_step/next_step
var/match = FALSE
do
next_step = recipe.steps[++current_idx]
var/conditions = next_step.check_conditions_met(used, src)
if(conditions == PCWJ_CHECK_VALID)
LAZYADD(valid_steps[next_step.type], next_step)
LAZYADD(valid_recipes[next_step.type], recipe)
attempted_step_per_recipe[recipe] = current_idx
match = TRUE
break
else if(conditions == PCWJ_CHECK_SILENT)
LAZYADD(silent_recipes, recipe)
var/conditions_met = next_step.check_conditions_met(used, src)
if(conditions_met == PCWJ_CHECK_VALID || conditions_met == PCWJ_CHECK_SILENT)
step_attempts += new/datum/cooking/step_attempt(
recipe, next_step, current_idx, conditions_met)
while(next_step && next_step.optional && current_idx <= length(recipe.steps))
if(match)
LAZYOR(recipes_all_applied_steps[recipe], current_idx)
if(length(recipe.steps) == current_idx)
completed_recipes |= recipe
if(!length(valid_steps))
if(length(silent_recipes))
return PCWJ_PARTIAL_SUCCESS
if(!length(step_attempts))
return PCWJ_NO_STEPS
var/list/recipes_with_completed_steps = list()
var/list/step_data
var/complete_steps = 0
for(var/step_type in valid_steps)
for(var/datum/cooking/step_attempt/step_attempt in step_attempts)
// For each valid step type we only call follow_step() once since it's
// pointless to e.g. add an item to the container more than once.
//
@@ -124,21 +127,33 @@
// for now, we do nothing, and just watch out for situations where two
// different recipe steps with incompatible end states are valid with
// the same object.
var/datum/cooking/recipe_step/sample_step = valid_steps[step_type][1]
step_data = sample_step.follow_step(used, src)
step_reaction_message = step_data["message"]
if(!(step_attempt.recipe_step.type in step_datas))
var/step_data = step_attempt.recipe_step.follow_step(used, src)
if(islist(step_data))
step_datas[step_attempt.recipe_step.type] = step_data
step_reaction_message = step_datas[step_attempt.recipe_step.type]["message"]
for(var/i in 1 to length(valid_recipes[step_type]))
var/datum/cooking/recipe/recipe = valid_recipes[step_type][i]
var/datum/cooking/recipe_step/recipe_step = valid_steps[step_type][i]
if(recipe_step.is_complete(used, src, step_data))
recipes_last_completed_step[recipe] = attempted_step_per_recipe[recipe]
recipes_with_completed_steps |= recipe
complete_steps++
var/previous_step = recipes_last_completed_step[step_attempt.recipe]
if(step_attempt.recipe_step.is_complete(used, src, step_datas[step_attempt.recipe_step.type]))
recipes_last_completed_step[step_attempt.recipe] = step_attempt.current_step_index
LAZYOR(recipes_all_applied_steps[step_attempt.recipe], step_attempt.current_step_index)
completed_steps++
if(step_attempt.recipe_step == step_attempt.recipe.steps[length(step_attempt.recipe.steps)])
completed_recipes += step_attempt.recipe
else
recipes_last_completed_step[step_attempt.recipe] = previous_step
if(length(step_datas) > 1)
var/list/types = list()
for(var/step_type in step_datas)
types += "[step_type]"
log_debug("More than one valid step data at the same step, this shouldn't happen. Valid steps: [jointext(types, ", ")]")
var/obj/item/reagent_containers/cooking/container = locateUID(container_uid)
if(complete_steps)
recipes_applied_step_data += list(step_data)
if(completed_steps)
var/list/first_applied_step_data = step_datas[1]
recipes_applied_step_data += list(step_datas[first_applied_step_data])
// Empty out the stove data here so that it can be reused from zero for
// other cooking steps, as well as to prevent cheatiness where a recipe
@@ -147,15 +162,11 @@
if(container)
container.clear_cooking_data()
if("signal" in step_data)
SEND_SIGNAL(container, step_data["signal"])
if("signal" in first_applied_step_data)
SEND_SIGNAL(container, first_applied_step_data["signal"])
else
return PCWJ_PARTIAL_SUCCESS
for(var/recipe in recipes_last_completed_step)
if(!(recipe in recipes_with_completed_steps))
recipes_last_completed_step -= recipe
var/datum/cooking/recipe/recipe_to_complete
if(length(completed_recipes))
if(length(completed_recipes) == 1)
@@ -180,4 +191,11 @@
return PCWJ_COMPLETE
// any recipes that have fewer completed steps than the number
// of steps we've actually accomplished shouldn't be considered
var/completed_step_count = length(recipes_applied_step_data)
for(var/recipe in recipes_last_completed_step)
if(!(recipe in recipes_all_applied_steps) || length(recipes_all_applied_steps[recipe]) < completed_step_count)
recipes_last_completed_step.Remove(recipe)
return PCWJ_SUCCESS
@@ -35,6 +35,7 @@ RESTRICT_TYPE(/datum/cooking/recipe_step)
/// Special function to check if the step has been satisfied. Sometimes just
/// following the step is enough, but not always.
/datum/cooking/recipe_step/proc/is_complete(obj/added_item, datum/cooking/recipe_tracker/tracker, list/step_data)
SHOULD_BE_PURE(TRUE)
return TRUE
/// Return a human readable description of the recipe step as an instruction to the reader.
@@ -79,12 +79,12 @@ RESTRICT_TYPE(/datum/cooking/recipe_step/add_reagent)
/datum/cooking/recipe_step/add_reagent/follow_step(obj/used_item, datum/cooking/recipe_tracker/tracker)
var/obj/item/reagent_containers/our_item = used_item
if(!istype(our_item))
return list()
return
var/obj/item/container = locateUID(tracker.container_uid)
var/trans = our_item.reagents.trans_to(container, our_item.amount_per_transfer_from_this)
return list(message = "You transfer [trans] units to \the [container].")
return list("message" = "You transfer [trans] units to \the [container].", "amount" = amount, "reagent_remain_percent" = remain_percent, "reagent_id" = reagent_id)
/datum/cooking/recipe_step/add_reagent/is_complete(obj/used_item, datum/cooking/recipe_tracker/tracker, list/step_data)
var/obj/item/container = locateUID(tracker.container_uid)
@@ -14,16 +14,18 @@
return
/datum/cooking/recipe_step/use_machine/check_conditions_met(obj/used_item, datum/cooking/recipe_tracker/tracker)
var/obj/item/reagent_containers/cooking/container = locateUID(tracker.container_uid)
if(container.get_cooker_time(cooker_surface_name, temperature) >= time)
return PCWJ_CHECK_VALID
if(istype(used_item, machine_type))
return PCWJ_CHECK_SILENT
return PCWJ_CHECK_INVALID
/datum/cooking/recipe_step/use_machine/is_complete(obj/added_item, datum/cooking/recipe_tracker/tracker, list/step_data)
var/obj/item/reagent_containers/cooking/container = locateUID(tracker.container_uid)
if(istype(container) && container.get_cooker_time(cooker_surface_name, temperature) >= time)
return TRUE
return FALSE
/datum/cooking/recipe_step/use_machine/follow_step(obj/used_item, datum/cooking/recipe_tracker/tracker, mob/user)
var/list/step_data = list(target = used_item.UID())
var/obj/item/reagent_containers/cooking/container = locateUID(tracker.container_uid)