diff --git a/code/__DEFINES/crafting.dm b/code/__DEFINES/crafting.dm
index 8218d392640..4b783490568 100644
--- a/code/__DEFINES/crafting.dm
+++ b/code/__DEFINES/crafting.dm
@@ -5,3 +5,10 @@
#define CAT_FOOD "Food"
#define CAT_MISC "Misc"
#define CAT_PRIMAL "Tribal"
+
+#define RECIPE_MICROWAVE "Microwave"
+#define RECIPE_OVEN "Oven"
+#define RECIPE_GRILL "Grill"
+#define RECIPE_CANDY "Candy"
+
+#define RECIPE_FAIL null
\ No newline at end of file
diff --git a/code/_globalvars/lists/misc.dm b/code/_globalvars/lists/misc.dm
index 65bffa7515a..8a06b552db2 100644
--- a/code/_globalvars/lists/misc.dm
+++ b/code/_globalvars/lists/misc.dm
@@ -31,6 +31,16 @@ var/list/round_end_sounds = list( // Maps available round end sounds to their du
'sound/goonstation/misc/newround2.ogg' = 14.8 SECONDS
)
+GLOBAL_LIST_INIT(cooking_recipe_types, list(
+ RECIPE_MICROWAVE = /datum/recipe/microwave,
+ RECIPE_OVEN = /datum/recipe/oven,
+ RECIPE_GRILL = /datum/recipe/grill,
+ RECIPE_CANDY = /datum/recipe/candy
+ ))
+GLOBAL_LIST_INIT(cooking_recipes, list(RECIPE_MICROWAVE = list(), RECIPE_OVEN = list(), RECIPE_GRILL = list(), RECIPE_CANDY = list()))
+GLOBAL_LIST_INIT(cooking_ingredients, list(RECIPE_MICROWAVE = list(), RECIPE_OVEN = list(), RECIPE_GRILL = list(), RECIPE_CANDY = list()))
+GLOBAL_LIST_INIT(cooking_reagents, list(RECIPE_MICROWAVE = list(), RECIPE_OVEN = list(), RECIPE_GRILL = list(), RECIPE_CANDY = list()))
+
GLOBAL_LIST(station_level_space_turfs)
-#define EGG_LAYING_MESSAGES list("lays an egg.", "squats down and croons.", "begins making a huge racket.", "begins clucking raucously.")
\ No newline at end of file
+#define EGG_LAYING_MESSAGES list("lays an egg.", "squats down and croons.", "begins making a huge racket.", "begins clucking raucously.")
diff --git a/code/datums/recipe.dm b/code/datums/recipe.dm
index 83ca8f7f0ea..99d97e45626 100644
--- a/code/datums/recipe.dm
+++ b/code/datums/recipe.dm
@@ -53,19 +53,18 @@
return -1
return .
-/datum/recipe/proc/check_items(obj/container) //1=precisely, 0=insufficiently, -1=superfluous
- if(!items)
- if(locate(/obj/) in container)
- return -1
- else
- return 1
+/datum/recipe/proc/check_items(obj/container, list/ignored_items = null) //1=precisely, 0=insufficiently, -1=superfluous
. = 1
- var/list/checklist = items.Copy()
+ var/list/checklist = items ? items.Copy() : list()
for(var/obj/O in container)
+ if(ignored_items && is_type_in_list(O, ignored_items)) //skip if this is something we are ignoring
+ continue
+ if(!items)
+ return -1
var/found = 0
for(var/type in checklist)
if(istype(O,type))
- checklist-=type
+ checklist -= type
found = 1
break
if(!found)
@@ -95,16 +94,16 @@
container.reagents.clear_reagents()
return result_obj
-/proc/select_recipe(list/datum/recipe/avaiable_recipes, obj/obj, exact = 1 as num)
+/proc/select_recipe(list/datum/recipe/available_recipes, obj/obj, exact = 1 as num, list/ignored_items = null)
if(!exact)
exact = -1
var/list/datum/recipe/possible_recipes = new
- for(var/datum/recipe/recipe in avaiable_recipes)
- if(recipe.check_reagents(obj.reagents)==exact && recipe.check_items(obj)==exact)
- possible_recipes+=recipe
- if(possible_recipes.len==0)
+ for(var/datum/recipe/recipe in available_recipes)
+ if(recipe.check_reagents(obj.reagents) == exact && recipe.check_items(obj, ignored_items) == exact)
+ possible_recipes += recipe
+ if(possible_recipes.len == 0)
return null
- else if(possible_recipes.len==1)
+ else if(possible_recipes.len == 1)
return possible_recipes[1]
else //okay, let's select the most complicated recipe
var/r_count = 0
diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index 628b754a5ae..2db64b30bdb 100644
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -943,6 +943,8 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/obj/item/reagent_containers/food/condiment/peppermill,
/obj/item/kitchen/rollingpin,
/obj/item/storage/fancy/egg_box,
+ /obj/item/mixing_bowl,
+ /obj/item/mixing_bowl,
/obj/item/reagent_containers/food/condiment/enzyme,
/obj/item/reagent_containers/food/condiment/sugar,
/obj/item/reagent_containers/food/snacks/meat/monkey,
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 8b179c7618c..823727d46ef 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -1223,7 +1223,7 @@
/obj/item/reagent_containers/food/condiment/pack/hotsauce = 5,
/obj/item/reagent_containers/food/condiment/saltshaker =5,
/obj/item/reagent_containers/food/condiment/peppermill =5,
- /obj/item/whetstone = 2,
+ /obj/item/whetstone = 2, /obj/item/mixing_bowl = 10,
/obj/item/kitchen/mould/bear = 1, /obj/item/kitchen/mould/worm = 1,
/obj/item/kitchen/mould/bean = 1, /obj/item/kitchen/mould/ball = 1,
/obj/item/kitchen/mould/cane = 1, /obj/item/kitchen/mould/cash = 1,
diff --git a/code/game/objects/items/mixing_bowl.dm b/code/game/objects/items/mixing_bowl.dm
new file mode 100644
index 00000000000..1edfdac9561
--- /dev/null
+++ b/code/game/objects/items/mixing_bowl.dm
@@ -0,0 +1,170 @@
+
+/obj/item/mixing_bowl
+ name = "mixing bowl"
+ desc = "Mixing it up in the kitchen."
+ flags = OPENCONTAINER
+ icon = 'icons/obj/kitchen.dmi'
+ icon_state = "mixing_bowl"
+ var/max_n_of_items = 25
+ var/dirty = FALSE
+ var/clean_icon = "mixing_bowl"
+ var/dirty_icon = "mixing_bowl_dirty"
+
+/obj/item/mixing_bowl/New()
+ ..()
+ create_reagents(100)
+
+/obj/item/mixing_bowl/attackby(obj/item/I, mob/user, params)
+ if(dirty)
+ if(istype(I, /obj/item/soap))
+ user.visible_message("[user] starts to scrub [src].", "You start to scrub [src].")
+ if(do_after(user, 20 * I.toolspeed, target = src))
+ clean()
+ user.visible_message("[user] has scrubbed [src] clean.", "You have scrubbed [src] clean.")
+ return 1
+ else
+ to_chat(user, "You should clean [src] before you use it for food prep.")
+ return 0
+ if(is_type_in_list(I, GLOB.cooking_ingredients[RECIPE_MICROWAVE]) || is_type_in_list(I, GLOB.cooking_ingredients[RECIPE_GRILL]) || is_type_in_list(I, GLOB.cooking_ingredients[RECIPE_OVEN]) || is_type_in_list(I, GLOB.cooking_ingredients[RECIPE_CANDY]))
+ if(contents.len>=max_n_of_items)
+ to_chat(user, "This [src] is full of ingredients, you cannot put more.")
+ return 1
+ if(istype(I, /obj/item/stack))
+ var/obj/item/stack/S = I
+ if(S.amount > 1)
+ var/obj/item/stack/to_add = S.split(user, 1)
+ to_add.forceMove(src)
+ user.visible_message("[user] adds one of [S] to [src].", "You add one of [S] to [src].")
+ else
+ return add_item(S, user)
+ else
+ return add_item(I, user)
+ else if(is_type_in_list(I, list(/obj/item/reagent_containers/glass, /obj/item/reagent_containers/food/drinks, /obj/item/reagent_containers/food/condiment)))
+ if(!I.reagents)
+ return 1
+ for(var/datum/reagent/R in I.reagents.reagent_list)
+ if(!(R.id in GLOB.cooking_reagents[RECIPE_MICROWAVE]) && !(R.id in GLOB.cooking_reagents[RECIPE_GRILL]) && !(R.id in GLOB.cooking_reagents[RECIPE_OVEN]) && !(R.id in GLOB.cooking_reagents[RECIPE_CANDY]))
+ to_chat(user, "Your [I] contains components unsuitable for cookery.")
+ return 1
+ else
+ to_chat(user, "You have no idea what you can cook with [I].")
+ return 1
+
+/obj/item/mixing_bowl/proc/add_item(obj/item/I, mob/user)
+ if(!user.drop_item())
+ to_chat(user, "\The [I] is stuck to your hand, you cannot put it in [src]")
+ //return 0
+ else
+ I.forceMove(src)
+ user.visible_message("[user] adds [I] to [src].", "You add [I] to [src].")
+
+/obj/item/mixing_bowl/attack_self(mob/user)
+ var/dat = ""
+ if(dirty)
+ dat = {"This [src] is dirty!"}
+ else
+ var/list/items_counts = new
+ var/list/items_measures = new
+ var/list/items_measures_p = new
+ for(var/obj/O in contents)
+ var/display_name = O.name
+ if(istype(O,/obj/item/reagent_containers/food/snacks/egg))
+ items_measures[display_name] = "egg"
+ items_measures_p[display_name] = "eggs"
+ if(istype(O,/obj/item/reagent_containers/food/snacks/tofu))
+ items_measures[display_name] = "tofu chunk"
+ items_measures_p[display_name] = "tofu chunks"
+ if(istype(O,/obj/item/reagent_containers/food/snacks/meat)) //any meat
+ items_measures[display_name] = "slab of meat"
+ items_measures_p[display_name] = "slabs of meat"
+ if(istype(O,/obj/item/reagent_containers/food/snacks/donkpocket))
+ display_name = "Turnovers"
+ items_measures[display_name] = "turnover"
+ items_measures_p[display_name] = "turnovers"
+ if(istype(O,/obj/item/reagent_containers/food/snacks/carpmeat))
+ items_measures[display_name] = "fillet of meat"
+ items_measures_p[display_name] = "fillets of meat"
+ items_counts[display_name]++
+ for(var/O in items_counts)
+ var/N = items_counts[O]
+ if(!(O in items_measures))
+ dat += {"[capitalize(O)]: [N] [lowertext(O)]\s
Please clean it before use!
"}
+ else
+ if(N==1)
+ dat += {"[capitalize(O)]: [N] [items_measures[O]]
"}
+ else
+ dat += {"[capitalize(O)]: [N] [items_measures_p[O]]
"}
+
+ for(var/datum/reagent/R in reagents.reagent_list)
+ var/display_name = R.name
+ if(R.id == "capsaicin")
+ display_name = "Hotsauce"
+ if(R.id == "frostoil")
+ display_name = "Coldsauce"
+ dat += {"[display_name]: [R.volume] unit\s
"}
+
+ if(items_counts.len==0 && reagents.reagent_list.len==0)
+ dat = {"The [src] is empty
"}
+ else
+ dat = {"Ingredients:
[dat]"}
+ dat += {"
Bzzzzttttt"}
else if(operating)
- dat = {"[pick(cook_verbs)] in progress![pick(cook_verbs)] in progress!
Please wait...!"}
else if(dirty==100)
- dat = {"This [src] is dirty!This [src] is dirty!
Please clean it before use!"}
else
var/list/items_counts = new
var/list/items_measures = new
@@ -260,12 +244,13 @@
stop()
return
- var/datum/recipe/recipe = select_recipe(available_recipes,src)
- var/obj/cooked
- var/obj/byproduct
- if(!recipe)
+ var/list/recipes_to_make = choose_recipes()
+
+ if(recipes_to_make.len == 1 && recipes_to_make[1][2] == RECIPE_FAIL)
+ //This only runs if there is a single recipe source to be made and it is a failure (the machine was loaded with only 1 mixing bowl that results in failure OR was directly loaded with ingredients that results in failure).
+ //If there are multiple sources, this bit gets skipped.
dirty += 1
- if(prob(max(10,dirty*5)))
+ if(prob(max(10,dirty*5))) //chance to get so dirty we require cleaning before next use
if(!wzhzhzh(4))
abort()
return
@@ -274,14 +259,14 @@
muck_finish()
fail()
return
- else if(has_extra_item())
+ else if(has_extra_item()) //if extra items present, break down and require repair before next use
if(!wzhzhzh(4))
abort()
return
broke()
fail()
return
- else
+ else //otherwise just stop without requiring cleaning/repair
if(!wzhzhzh(10))
abort()
return
@@ -289,24 +274,69 @@
fail()
return
else
- var/halftime = round(recipe.time/10/2)
- if(!wzhzhzh(halftime))
+ if(!wzhzhzh(5))
abort()
return
- if(!wzhzhzh(halftime))
+ if(!wzhzhzh(5))
abort()
fail()
return
- cooked = recipe.make_food(src)
- byproduct = recipe.get_byproduct()
- stop()
- if(cooked)
- cooked.forceMove(loc)
- for(var/i=1,i