diff --git a/code/modules/cooking/cooking_recipe.dm b/code/modules/cooking/cooking_recipe.dm index 5934c1878a5..33a48155e52 100644 --- a/code/modules/cooking/cooking_recipe.dm +++ b/code/modules/cooking/cooking_recipe.dm @@ -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"])) diff --git a/code/modules/cooking/recipe_tracker.dm b/code/modules/cooking/recipe_tracker.dm index 2853dfe6335..8776ef6dcf4 100644 --- a/code/modules/cooking/recipe_tracker.dm +++ b/code/modules/cooking/recipe_tracker.dm @@ -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 diff --git a/code/modules/cooking/steps/recipe_step.dm b/code/modules/cooking/steps/recipe_step.dm index 313c7e34a1b..a66370bc17e 100644 --- a/code/modules/cooking/steps/recipe_step.dm +++ b/code/modules/cooking/steps/recipe_step.dm @@ -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. diff --git a/code/modules/cooking/steps/recipe_step_add_reagent.dm b/code/modules/cooking/steps/recipe_step_add_reagent.dm index 826f89541e4..5b768fc3307 100644 --- a/code/modules/cooking/steps/recipe_step_add_reagent.dm +++ b/code/modules/cooking/steps/recipe_step_add_reagent.dm @@ -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) diff --git a/code/modules/cooking/steps/recipe_step_use_machine.dm b/code/modules/cooking/steps/recipe_step_use_machine.dm index 8ca0abe245b..dd69141d443 100644 --- a/code/modules/cooking/steps/recipe_step_use_machine.dm +++ b/code/modules/cooking/steps/recipe_step_use_machine.dm @@ -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)