Skip to content

Commit fd7e71d

Browse files
fix cooking step failures (ParadiseSS13#30349)
* fix cooking step failures * a timing issue one hopes
1 parent 28a2381 commit fd7e71d

File tree

5 files changed

+114
-17
lines changed

5 files changed

+114
-17
lines changed

code/modules/cooking/recipe_tracker.dm

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,24 @@
5252

5353
/// Core function that checks if a object meets all the requirements for certain
5454
/// recipe actions.
55+
///
56+
/// This is one of the thornier and grosser parts of the cooking system and most
57+
/// people working with it or implementing recipes should never have to look at
58+
/// this. The core idea is:
59+
///
60+
/// * we keep track of what recipes are still valid outcomes by testing the used
61+
/// item against the list of recipes which are valid so far.
62+
/// * each valid recipe is at a certain step, and check the used object against
63+
/// [/datum/cooking/recipe_step/proc/check_conditions_met]. if we meet the
64+
/// conditions, we track the recipe and the step.
65+
/// * for each unique step type that we're tracking, call
66+
/// [/datum/cooking/recipe_step/proc/follow_step] on the first instance of
67+
/// that step type, then [/datum/cooking/recipe_step/proc/is_complete] on
68+
/// all recipe step instances of that type, to see if we advance their
69+
/// respective recipes.
70+
///
71+
/// Once a recipe reaches its final step, the tracker completes the recipe and
72+
/// typically stops existing at that point.
5573
/datum/cooking/recipe_tracker/proc/process_item(mob/user, obj/used)
5674
// TODO: I *hate* passing in a user here and want to move all the necessary
5775
// UI interactions (selecting which recipe to complete, selecting which step
@@ -61,8 +79,6 @@
6179
var/list/completed_recipes = list()
6280
var/list/silent_recipes = list()
6381
var/list/attempted_step_per_recipe = list()
64-
var/datum/cooking/recipe_step/use_step_type
65-
6682

6783
for(var/datum/cooking/recipe/recipe in recipes_last_completed_step)
6884
var/current_idx = recipes_last_completed_step[recipe]
@@ -73,11 +89,9 @@
7389
next_step = recipe.steps[++current_idx]
7490
var/conditions = next_step.check_conditions_met(used, src)
7591
if(conditions == PCWJ_CHECK_VALID)
76-
LAZYADD(valid_steps[next_step], next_step)
92+
LAZYADD(valid_steps[next_step.type], next_step)
7793
LAZYADD(valid_recipes[next_step.type], recipe)
7894
attempted_step_per_recipe[recipe] = current_idx
79-
if(!use_step_type)
80-
use_step_type = next_step.type
8195
match = TRUE
8296
break
8397
else if(conditions == PCWJ_CHECK_SILENT)
@@ -94,16 +108,33 @@
94108
return PCWJ_PARTIAL_SUCCESS
95109
return PCWJ_NO_STEPS
96110

97-
var/datum/cooking/recipe_step/sample_step = valid_steps[1]
98-
var/step_data = sample_step.follow_step(used, src)
99-
step_reaction_message = step_data["message"]
111+
var/list/recipes_with_completed_steps = list()
112+
var/list/step_data
100113
var/complete_steps = 0
101-
for(var/i in 1 to length(valid_recipes[use_step_type]))
102-
var/datum/cooking/recipe/recipe = valid_recipes[use_step_type][i]
103-
var/datum/cooking/recipe_step/recipe_step = valid_steps[i]
104-
if(recipe_step.is_complete(used, src, step_data))
105-
recipes_last_completed_step[recipe] = attempted_step_per_recipe[recipe]
106-
complete_steps++
114+
for(var/step_type in valid_steps)
115+
// For each valid step type we only call follow_step() once since it's
116+
// pointless to e.g. add an item to the container more than once.
117+
//
118+
// However, we are still calling follow_step more than once. which means
119+
// we have to deal with the possibility that two valid steps may do two
120+
// different things with the used item and may expect different results.
121+
// Sojurn tried to handle this by adding a user prompt at this point,
122+
// asking which step the player wanted to perform. I want to avoid
123+
// throwing up interfaces during cooking, especially when unexpected, so
124+
// for now, we do nothing, and just watch out for situations where two
125+
// different recipe steps with incompatible end states are valid with
126+
// the same object.
127+
var/datum/cooking/recipe_step/sample_step = valid_steps[step_type][1]
128+
step_data = sample_step.follow_step(used, src)
129+
step_reaction_message = step_data["message"]
130+
131+
for(var/i in 1 to length(valid_recipes[step_type]))
132+
var/datum/cooking/recipe/recipe = valid_recipes[step_type][i]
133+
var/datum/cooking/recipe_step/recipe_step = valid_steps[step_type][i]
134+
if(recipe_step.is_complete(used, src, step_data))
135+
recipes_last_completed_step[recipe] = attempted_step_per_recipe[recipe]
136+
recipes_with_completed_steps |= recipe
137+
complete_steps++
107138

108139
var/obj/item/reagent_containers/cooking/container = locateUID(container_uid)
109140
if(complete_steps)
@@ -121,8 +152,8 @@
121152
else
122153
return PCWJ_PARTIAL_SUCCESS
123154

124-
for(var/datum/cooking/recipe in recipes_last_completed_step)
125-
if(!(recipe in valid_recipes[sample_step.type]))
155+
for(var/recipe in recipes_last_completed_step)
156+
if(!(recipe in recipes_with_completed_steps))
126157
recipes_last_completed_step -= recipe
127158

128159
var/datum/cooking/recipe/recipe_to_complete

code/modules/cooking/steps/recipe_step.dm

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ RESTRICT_TYPE(/datum/cooking/recipe_step)
88
if("optional" in options)
99
optional = options["optional"]
1010

11+
/// See if the *used_item* meets the conditions for this recipe step. This will
12+
/// typically be something like ensuring that a recipe step for adding a
13+
/// specific kind of item has been passed an item of that type.
14+
///
15+
/// Returns one of [PCWJ_CHECK_INVALID], [PCWJ_CHECK_VALID], [PCWJ_CHECK_FULL],
16+
/// [PCWJ_CHECK_SILENT].
1117
/datum/cooking/recipe_step/proc/check_conditions_met(obj/used_item, datum/cooking/recipe_tracker/tracker)
1218
SHOULD_CALL_PARENT(FALSE)
1319
SHOULD_BE_PURE(TRUE)
@@ -26,7 +32,8 @@ RESTRICT_TYPE(/datum/cooking/recipe_step)
2632
/datum/cooking/recipe_step/proc/follow_step(obj/used_item, datum/cooking/recipe_tracker/tracker, mob/user)
2733
return list()
2834

29-
/// Special function to check if the step has been satisfied. Sometimed just following the step is enough, but not always.
35+
/// Special function to check if the step has been satisfied. Sometimes just
36+
/// following the step is enough, but not always.
3037
/datum/cooking/recipe_step/proc/is_complete(obj/added_item, datum/cooking/recipe_tracker/tracker, list/step_data)
3138
return TRUE
3239

code/tests/_game_test_puppeteer.dm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@
7373
puppet.next_click = world.time
7474
puppet.next_move = world.time
7575

76+
/datum/test_puppeteer/proc/alt_click_on(target, params)
77+
var/plist = params2list(params)
78+
plist["alt"] = TRUE
79+
click_on(target, list2params(plist))
80+
7681
/datum/test_puppeteer/proc/spawn_mob_nearby(mob_type)
7782
for(var/turf/T in RANGE_TURFS(1, puppet))
7883
if(!T.is_blocked_turf())

code/tests/game_tests.dm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "test_apc_construction.dm"
2828
#include "test_components.dm"
2929
#include "test_config_sanity.dm"
30+
#include "test_cooking.dm"
3031
#include "test_crafting_lists.dm"
3132
#include "test_dynamic_budget.dm"
3233
#include "test_elements.dm"

code/tests/test_cooking.dm

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/datum/cooking/recipe/test_soylent
2+
container_type = /obj/item/reagent_containers/cooking/pot
3+
product_type = /obj/item/food/soylentgreen
4+
steps = list(
5+
PCWJ_ADD_ITEM(/obj/item/food/meat/human),
6+
PCWJ_ADD_ITEM(/obj/item/food/meat/human),
7+
PCWJ_ADD_REAGENT("water", 10),
8+
PCWJ_USE_STOVE(J_MED, 1 SECONDS),
9+
)
10+
appear_in_default_catalog = FALSE
11+
12+
/datum/game_test/room_test/cooking/Run()
13+
var/datum/test_puppeteer/player = new(src)
14+
player.puppet.name = "Player"
15+
16+
// Burger
17+
var/obj/structure/table/table = player.spawn_obj_nearby(__IMPLIED_TYPE__, SOUTH)
18+
var/obj/item/reagent_containers/cooking/board/board = player.spawn_obj_nearby(__IMPLIED_TYPE__, SOUTH)
19+
player.spawn_obj_in_hand(/obj/item/food/bun)
20+
player.click_on(board)
21+
TEST_ASSERT_LAST_CHATLOG(player, "You add the bun")
22+
player.spawn_obj_in_hand(/obj/item/food/meat/patty)
23+
player.click_on(board)
24+
TEST_ASSERT_LAST_CHATLOG(player, "You add the patty")
25+
player.spawn_obj_in_hand(/obj/item/food/grown/lettuce)
26+
player.click_on(board)
27+
TEST_ASSERT_LAST_CHATLOG(player, "You finish cooking with the cutting board")
28+
player.alt_click_on(board)
29+
TEST_ASSERT(locate(/obj/item/food/burger) in get_turf(board), "could not find completed burger")
30+
31+
// Soylent
32+
var/obj/machinery/cooking/stovetop/stove = player.spawn_obj_nearby(__IMPLIED_TYPE__, EAST)
33+
var/obj/item/reagent_containers/cooking/pot/pot = player.spawn_obj_in_hand(__IMPLIED_TYPE__)
34+
player.click_on(table)
35+
var/obj/item/food/meat/human/meat = player.spawn_obj_in_hand(__IMPLIED_TYPE__)
36+
player.click_on(pot)
37+
TEST_ASSERT_LAST_CHATLOG(player, "You add [meat]")
38+
player.spawn_obj_in_hand(/obj/item/food/meat/human)
39+
player.click_on(pot)
40+
var/obj/item/reagent_containers/glass/beaker/beaker = player.spawn_obj_in_hand(__IMPLIED_TYPE__)
41+
beaker.reagents.add_reagent("water", 10)
42+
player.click_on(pot)
43+
player.put_away(beaker)
44+
player.click_on(pot)
45+
player.click_on(stove, "icon-x=18&icon-y=18")
46+
var/surface_idx = stove.clickpos_to_surface(list("icon-x" = 18, "icon-y" = 18))
47+
var/datum/cooking_surface/surface = stove.surfaces[surface_idx]
48+
surface.temperature = J_MED
49+
surface.turn_on(player.puppet)
50+
sleep(3 SECONDS)
51+
surface.turn_off(player.puppet)
52+
player.alt_click_on(stove, "icon-x=18&icon-y=18")
53+
TEST_ASSERT(locate(/obj/item/food/soylentgreen) in stove.loc, "could not find complete soylent")

0 commit comments

Comments
 (0)