mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 02:09:41 +00:00
WIP Aurora Cooking Port
This ports Aurora Cooking, sometimes called Nanako Cooking, from CitRP, who got it from Aurora originally. https://github.com/Citadel-Station-13/Citadel-Station-13-RP/pull/608 Pulled from here with updates to to_chat() Ovens and fryers now work like the microwave, but also have special trays/baskets that can be inserted and removed with things on them. There's also a crapton of new recipes. Note that you can still use the oven to just bake things, or produce variable food items, to my knowledge. This was specifically kept in when it was originally implemented, IIRC. - Cooking now uses several machines to make recipes. Microwave, oven, deep fryer. - Recipes have been redone to reflect this. - Adds a reagent called Space Spice (used in Synnono's food recipes mostly, prevents recipe conflicts) - New foods! Lots of them. - You can cook using held mobs. Also, mouse/ratburgers. I can dump the recipes if you'd like. https://user-images.githubusercontent.com/40557659/52112070-10165a80-25cb-11e9-9a72-2c919f0033dd.png (From their PR, may not be accurate). This is WIP, and will not compile just yet.
This commit is contained in:
@@ -56,3 +56,9 @@
|
||||
. = B[STAT_ENTRY_TIME] - A[STAT_ENTRY_TIME]
|
||||
if (!.)
|
||||
. = B[STAT_ENTRY_COUNT] - A[STAT_ENTRY_COUNT]
|
||||
|
||||
// Compares complexity of recipes for use in cooking, etc. This is for telling which recipe to make, not for showing things to the player.
|
||||
/proc/cmp_recipe_complexity_dsc(datum/recipe/A, datum/recipe/B)
|
||||
var/a_score = LAZYLEN(A.items) + LAZYLEN(A.reagents) + LAZYLEN(A.fruit)
|
||||
var/b_score = LAZYLEN(B.items) + LAZYLEN(B.reagents) + LAZYLEN(B.fruit)
|
||||
return b_score - a_score
|
||||
@@ -50,7 +50,7 @@
|
||||
src.invisibility = INVISIBILITY_MAXIMUM
|
||||
density = 0
|
||||
|
||||
/obj/machinery/cooker/cultify()
|
||||
/obj/machinery/appliance/cooker/cultify()
|
||||
new /obj/structure/cult/talisman(loc)
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
..()
|
||||
bumpopen(M)
|
||||
|
||||
/obj/machinery/cooker/fryer/stumble_into(mob/living/M)
|
||||
/obj/machinery/appliance/cooker/fryer/stumble_into(mob/living/M)
|
||||
visible_message("<span class='warning'>[M] [pick("ran", "slammed")] into \the [src]!</span>")
|
||||
M.apply_damage(15, BURN)
|
||||
M.Weaken(5)
|
||||
|
||||
@@ -115,6 +115,17 @@
|
||||
desc = "This is what you use to make bread fluffy."
|
||||
icon_state = "yeast"
|
||||
center_of_mass = list("x"=16, "y"=6)
|
||||
if("spacespice")
|
||||
name = "bottle of space spice"
|
||||
desc = "An exotic blend of spices for cooking. Definitely not worms."
|
||||
icon = 'modular_citadel/icons/obj/food_syn.dmi'
|
||||
icon_state = "spacespicebottle"
|
||||
center_of_mass = list("x"=16, "y"=6)
|
||||
if("barbecue")
|
||||
name = "barbecue sauce"
|
||||
desc = "Barbecue sauce, it's labeled 'sweet and spicy'."
|
||||
icon_state = "barbecue"
|
||||
center_of_mass = list("x"=16, "y"=6)
|
||||
else
|
||||
name = "Misc Condiment Bottle"
|
||||
if (reagents.reagent_list.len==1)
|
||||
@@ -408,6 +419,7 @@
|
||||
desc = "A big bag of flour. Good for baking!"
|
||||
icon = 'icons/obj/food.dmi'
|
||||
icon_state = "flour"
|
||||
volume = 220
|
||||
center_of_mass = list("x"=16, "y"=8)
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/condiment/flour/on_reagent_change()
|
||||
@@ -415,5 +427,20 @@
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/condiment/flour/Initialize()
|
||||
. = ..()
|
||||
reagents.add_reagent("flour", 30)
|
||||
randpixel_xy()
|
||||
reagents.add_reagent("flour", 200)
|
||||
randpixel_xy()
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/condiment/spacespice
|
||||
name = "space spices"
|
||||
desc = "An exotic blend of spices for cooking. Definitely not worms."
|
||||
icon_state = "spacespicebottle"
|
||||
possible_transfer_amounts = list(1,40) //for clown turning the lid off
|
||||
amount_per_transfer_from_this = 1
|
||||
volume = 40
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/condiment/spacespice/on_reagent_change()
|
||||
return
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/condiment/spacespice/initialize()
|
||||
..()
|
||||
reagents.add_reagent("spacespice", 40)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,19 @@
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/meat/Initialize()
|
||||
. = ..()
|
||||
reagents.add_reagent("protein", 9)
|
||||
src.bitesize = 3
|
||||
reagents.add_reagent("protein", 6)
|
||||
reagents.add_reagent("triglyceride", 2)
|
||||
src.bitesize = 1.5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/meat/cook()
|
||||
|
||||
if (!isnull(cooked_icon))
|
||||
icon_state = cooked_icon
|
||||
flat_icon = null //Force regenating the flat icon for coatings, since we've changed the icon of the thing being coated
|
||||
..()
|
||||
|
||||
if (name == initial(name))
|
||||
name = "cooked [name]"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/meat/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(istype(W,/obj/item/weapon/material/knife))
|
||||
@@ -34,4 +45,16 @@
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/meat/corgi
|
||||
name = "Corgi meat"
|
||||
desc = "Tastes like... well, you know."
|
||||
desc = "Tastes like... well, you know."
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/meat/chicken
|
||||
name = "chicken"
|
||||
icon = 'icons/obj/food_syn.dmi'
|
||||
icon_state = "chickenbreast"
|
||||
cooked_icon = "chickenbreast_cooked"
|
||||
filling_color = "#BBBBAA"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/meat/chicken/initialize()
|
||||
..()
|
||||
reagents.remove_reagent("triglyceride", INFINITY)
|
||||
//Chicken is low fat. Less total calories than other meats
|
||||
728
code/modules/food/kitchen/cooking_machines/_appliance.dm
Normal file
728
code/modules/food/kitchen/cooking_machines/_appliance.dm
Normal file
@@ -0,0 +1,728 @@
|
||||
// This folder contains code that was originally ported from Apollo Station and then refactored/optimized/changed.
|
||||
|
||||
// Tracks precooked food to stop deep fried baked grilled grilled grilled diona nymph cereal.
|
||||
/obj/item/weapon/reagent_containers/food/snacks
|
||||
var/tmp/list/cooked = list()
|
||||
|
||||
// Root type for cooking machines. See following files for specific implementations.
|
||||
/obj/machinery/appliance
|
||||
name = "cooker"
|
||||
desc = "You shouldn't be seeing this!"
|
||||
icon = 'icons/obj/cooking_machines.dmi'
|
||||
var/appliancetype = 0
|
||||
density = 1
|
||||
anchored = 1
|
||||
|
||||
use_power = USE_POWER_IDLE
|
||||
idle_power_usage = 5 // Power used when turned on, but not processing anything
|
||||
active_power_usage = 1000 // Power used when turned on and actively cooking something
|
||||
var/initial_active_power_usage = 1000
|
||||
|
||||
var/cooking_power = 1
|
||||
var/initial_cooking_power = 1
|
||||
var/max_contents = 1 // Maximum number of things this appliance can simultaneously cook
|
||||
var/on_icon // Icon state used when cooking.
|
||||
var/off_icon // Icon state used when not cooking.
|
||||
var/cooking // Whether or not the machine is currently operating.
|
||||
var/cook_type // A string value used to track what kind of food this machine makes.
|
||||
var/can_cook_mobs // Whether or not this machine accepts grabbed mobs.
|
||||
var/mobdamagetype = BRUTE // Burn damage for cooking appliances, brute for cereal/candy
|
||||
var/food_color // Colour of resulting food item.
|
||||
var/cooked_sound = 'sound/machines/ding.ogg' // Sound played when cooking completes.
|
||||
var/can_burn_food // Can the object burn food that is left inside?
|
||||
var/burn_chance = 10 // How likely is the food to burn?
|
||||
var/list/cooking_objs = list() // List of things being cooked
|
||||
|
||||
// If the machine has multiple output modes, define them here.
|
||||
var/selected_option
|
||||
var/list/output_options = list()
|
||||
var/list/datum/recipe/available_recipes
|
||||
|
||||
var/container_type = null
|
||||
|
||||
var/combine_first = 0//If 1, this appliance will do combinaiton cooking before checking recipes
|
||||
|
||||
/obj/machinery/appliance/Initialize()
|
||||
. = ..()
|
||||
component_parts = list()
|
||||
component_parts += /obj/item/weapon/circuitboard/cooking
|
||||
component_parts += /obj/item/weapon/stock_parts/capacitor
|
||||
component_parts += /obj/item/weapon/stock_parts/capacitor
|
||||
component_parts += /obj/item/weapon/stock_parts/capacitor
|
||||
component_parts += /obj/item/weapon/stock_parts/scanning_module
|
||||
component_parts += /obj/item/weapon/stock_parts/matter_bin
|
||||
component_parts += /obj/item/weapon/stock_parts/matter_bin
|
||||
if(output_options.len)
|
||||
verbs += /obj/machinery/appliance/proc/choose_output
|
||||
|
||||
if (!available_recipes)
|
||||
available_recipes = new
|
||||
|
||||
for (var/type in subtypesof(/datum/recipe))
|
||||
var/datum/recipe/test = new type
|
||||
if ((appliancetype & test.appliance))
|
||||
available_recipes += test
|
||||
else
|
||||
qdel(test)
|
||||
|
||||
/obj/machinery/appliance/Destroy()
|
||||
for (var/a in cooking_objs)
|
||||
var/datum/cooking_item/CI = a
|
||||
qdel(CI.container)//Food is fragile, it probably doesnt survive the destruction of the machine
|
||||
cooking_objs -= CI
|
||||
qdel(CI)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/appliance/examine(var/mob/user)
|
||||
..()
|
||||
if(Adjacent(usr))
|
||||
list_contents(user)
|
||||
return 1
|
||||
|
||||
/obj/machinery/appliance/proc/list_contents(var/mob/user)
|
||||
if (cooking_objs.len)
|
||||
var/string = "Contains..."
|
||||
for (var/a in cooking_objs)
|
||||
var/datum/cooking_item/CI = a
|
||||
string += "-\a [CI.container.label(null, CI.combine_target)], [report_progress(CI)]</br>"
|
||||
usr << string
|
||||
else
|
||||
usr << span("notice","It is empty.")
|
||||
|
||||
/obj/machinery/appliance/proc/report_progress(var/datum/cooking_item/CI)
|
||||
if (!CI || !CI.max_cookwork)
|
||||
return null
|
||||
|
||||
if (!CI.cookwork)
|
||||
return "It is cold."
|
||||
var/progress = CI.cookwork / CI.max_cookwork
|
||||
|
||||
if (progress < 0.25)
|
||||
return "It's barely started cooking."
|
||||
if (progress < 0.75)
|
||||
return span("notice","It's cooking away nicely.")
|
||||
if (progress < 1)
|
||||
return span("notice", "<b>It's almost ready!</b>")
|
||||
|
||||
var/half_overcook = (CI.overcook_mult - 1)*0.5
|
||||
if (progress < 1+half_overcook)
|
||||
return span("soghun","<b>It is done !</b>")
|
||||
if (progress < CI.overcook_mult)
|
||||
return span("warning","It looks overcooked, get it out!")
|
||||
else
|
||||
return span("danger","It is burning!!")
|
||||
|
||||
/obj/machinery/appliance/update_icon()
|
||||
if (!stat && cooking_objs.len)
|
||||
icon_state = on_icon
|
||||
|
||||
else
|
||||
icon_state = off_icon
|
||||
|
||||
/obj/machinery/appliance/verb/toggle_power()
|
||||
set name = "Toggle Power"
|
||||
set category = "Object"
|
||||
set src in view()
|
||||
|
||||
attempt_toggle_power(usr)
|
||||
|
||||
/obj/machinery/appliance/proc/attempt_toggle_power(mob/user)
|
||||
if (!isliving(user))
|
||||
return
|
||||
|
||||
if (!user.IsAdvancedToolUser())
|
||||
user << "You lack the dexterity to do that!"
|
||||
return
|
||||
|
||||
if (user.stat || user.restrained() || user.incapacitated())
|
||||
return
|
||||
|
||||
if (!Adjacent(user) && !issilicon(user))
|
||||
user << "You can't reach [src] from here."
|
||||
return
|
||||
|
||||
if (stat & POWEROFF)//Its turned off
|
||||
stat &= ~POWEROFF
|
||||
use_power = 1
|
||||
user.visible_message("[user] turns [src] on.", "You turn on [src].")
|
||||
|
||||
else //Its on, turn it off
|
||||
stat |= POWEROFF
|
||||
use_power = 0
|
||||
user.visible_message("[user] turns [src] off.", "You turn off [src].")
|
||||
|
||||
playsound(src, 'sound/machines/click.ogg', 40, 1)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/appliance/AICtrlClick(mob/user)
|
||||
attempt_toggle_power(user)
|
||||
|
||||
/obj/machinery/appliance/proc/choose_output()
|
||||
set src in view()
|
||||
set name = "Choose output"
|
||||
set category = "Object"
|
||||
|
||||
if (!isliving(usr))
|
||||
return
|
||||
|
||||
if (!usr.IsAdvancedToolUser())
|
||||
usr << "You lack the dexterity to do that!"
|
||||
return
|
||||
|
||||
if (usr.stat || usr.restrained() || usr.incapacitated())
|
||||
return
|
||||
|
||||
if (!Adjacent(usr) && !issilicon(usr))
|
||||
usr << "You can't adjust the [src] from this distance, get closer!"
|
||||
return
|
||||
|
||||
if(output_options.len)
|
||||
var/choice = input("What specific food do you wish to make with \the [src]?") as null|anything in output_options+"Default"
|
||||
if(!choice)
|
||||
return
|
||||
if(choice == "Default")
|
||||
selected_option = null
|
||||
usr << "<span class='notice'>You decide not to make anything specific with \the [src].</span>"
|
||||
else
|
||||
selected_option = choice
|
||||
usr << "<span class='notice'>You prepare \the [src] to make \a [selected_option] with the next thing you put in. Try putting several ingredients in a container!</span>"
|
||||
|
||||
//Handles all validity checking and error messages for inserting things
|
||||
/obj/machinery/appliance/proc/can_insert(var/obj/item/I, var/mob/user)
|
||||
if (istype(I.loc, /mob/living/silicon))
|
||||
return 0
|
||||
else if (istype(I.loc, /obj/item/rig_module))
|
||||
return 0
|
||||
|
||||
// We are trying to cook a grabbed mob.
|
||||
var/obj/item/weapon/grab/G = I
|
||||
if(istype(G))
|
||||
|
||||
if(!can_cook_mobs)
|
||||
user << "<span class='warning'>That's not going to fit.</span>"
|
||||
return 0
|
||||
|
||||
if(!isliving(G.affecting))
|
||||
user << "<span class='warning'>You can't cook that.</span>"
|
||||
return 0
|
||||
|
||||
return 2
|
||||
|
||||
|
||||
if (!has_space(I))
|
||||
user << "<span class='warning'>There's no room in [src] for that!</span>"
|
||||
return 0
|
||||
|
||||
|
||||
if (container_type && istype(I, container_type))
|
||||
return 1
|
||||
|
||||
// We're trying to cook something else. Check if it's valid.
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/check = I
|
||||
if(istype(check) && islist(check.cooked) && (cook_type in check.cooked))
|
||||
user << "<span class='warning'>\The [check] has already been [cook_type].</span>"
|
||||
return 0
|
||||
else if(istype(check, /obj/item/weapon/reagent_containers/glass))
|
||||
user << "<span class='warning'>That would probably break [src].</span>"
|
||||
return 0
|
||||
else if(istype(check, /obj/item/weapon/disk/nuclear))
|
||||
user << "<span class='warning'>You can't cook that.</span>"
|
||||
return 0
|
||||
else if(!istype(check) && !istype(check, /obj/item/weapon/holder))
|
||||
user << "<span class='warning'>That's not edible.</span>"
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
//This function is overridden by cookers that do stuff with containers
|
||||
/obj/machinery/appliance/proc/has_space(var/obj/item/I)
|
||||
if (cooking_objs.len >= max_contents)
|
||||
return 0
|
||||
|
||||
else return 1
|
||||
|
||||
/obj/machinery/appliance/attackby(var/obj/item/I, var/mob/user)
|
||||
if(!cook_type || (stat & (BROKEN)))
|
||||
user << "<span class='warning'>\The [src] is not working.</span>"
|
||||
return
|
||||
|
||||
var/result = can_insert(I, user)
|
||||
if(!result)
|
||||
if(default_deconstruction_screwdriver(user, I))
|
||||
return
|
||||
else if(default_part_replacement(user, I))
|
||||
return
|
||||
else
|
||||
return
|
||||
|
||||
if(result == 2)
|
||||
var/obj/item/weapon/grab/G = I
|
||||
if (G && istype(G) && G.affecting)
|
||||
cook_mob(G.affecting, user)
|
||||
return
|
||||
|
||||
//From here we can start cooking food
|
||||
add_content(I, user)
|
||||
update_icon()
|
||||
|
||||
//Override for container mechanics
|
||||
/obj/machinery/appliance/proc/add_content(var/obj/item/I, var/mob/user)
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
|
||||
var/datum/cooking_item/CI = has_space(I)
|
||||
if (istype(I, /obj/item/weapon/reagent_containers/cooking_container) && CI == 1)
|
||||
var/obj/item/weapon/reagent_containers/cooking_container/CC = I
|
||||
CI = new /datum/cooking_item/(CC)
|
||||
I.forceMove(src)
|
||||
cooking_objs.Add(CI)
|
||||
user.visible_message("<span class='notice'>\The [user] puts \the [I] into \the [src].</span>")
|
||||
if (CC.check_contents() == 0)//If we're just putting an empty container in, then dont start any processing.
|
||||
return
|
||||
else
|
||||
if (CI && istype(CI))
|
||||
I.forceMove(CI.container)
|
||||
|
||||
else //Something went wrong
|
||||
return
|
||||
|
||||
if (selected_option)
|
||||
CI.combine_target = selected_option
|
||||
|
||||
// We can actually start cooking now.
|
||||
user.visible_message("<span class='notice'>\The [user] puts \the [I] into \the [src].</span>")
|
||||
|
||||
get_cooking_work(CI)
|
||||
cooking = 1
|
||||
return CI
|
||||
|
||||
/obj/machinery/appliance/proc/get_cooking_work(var/datum/cooking_item/CI)
|
||||
for (var/obj/item/J in CI.container)
|
||||
oilwork(J, CI)
|
||||
|
||||
for (var/r in CI.container.reagents.reagent_list)
|
||||
var/datum/reagent/R = r
|
||||
if (istype(R, /datum/reagent/nutriment))
|
||||
CI.max_cookwork += R.volume *2//Added reagents contribute less than those in food items due to granular form
|
||||
|
||||
//Nonfat reagents will soak oil
|
||||
if (!istype(R, /datum/reagent/nutriment/triglyceride))
|
||||
CI.max_oil += R.volume * 0.25
|
||||
else
|
||||
CI.max_cookwork += R.volume
|
||||
CI.max_oil += R.volume * 0.10
|
||||
|
||||
//Rescaling cooking work to avoid insanely long times for large things
|
||||
var/buffer = CI.max_cookwork
|
||||
CI.max_cookwork = 0
|
||||
var/multiplier = 1
|
||||
var/step = 4
|
||||
while (buffer > step)
|
||||
buffer -= step
|
||||
CI.max_cookwork += step*multiplier
|
||||
multiplier *= 0.95
|
||||
|
||||
CI.max_cookwork += buffer*multiplier
|
||||
|
||||
//Just a helper to save code duplication in the above
|
||||
/obj/machinery/appliance/proc/oilwork(var/obj/item/I, var/datum/cooking_item/CI)
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/S = I
|
||||
var/work = 0
|
||||
if (istype(S))
|
||||
if (S.reagents)
|
||||
for (var/r in S.reagents.reagent_list)
|
||||
var/datum/reagent/R = r
|
||||
if (istype(R, /datum/reagent/nutriment))
|
||||
work += R.volume *3//Core nutrients contribute much more than peripheral chemicals
|
||||
|
||||
//Nonfat reagents will soak oil
|
||||
if (!istype(R, /datum/reagent/nutriment/triglyceride))
|
||||
CI.max_oil += R.volume * 0.35
|
||||
else
|
||||
work += R.volume
|
||||
CI.max_oil += R.volume * 0.15
|
||||
|
||||
|
||||
else if(istype(I, /obj/item/weapon/holder))
|
||||
var/obj/item/weapon/holder/H = I
|
||||
if (H.held_mob)
|
||||
work += (H.held_mob.mob_size * H.held_mob.mob_size * 2)+2
|
||||
|
||||
CI.max_cookwork += work
|
||||
|
||||
//Called every tick while we're cooking something
|
||||
/obj/machinery/appliance/proc/do_cooking_tick(var/datum/cooking_item/CI)
|
||||
if (!istype(CI) || !CI.max_cookwork)
|
||||
return 0
|
||||
|
||||
var/was_done = 0
|
||||
if (CI.cookwork >= CI.max_cookwork)
|
||||
was_done = 1
|
||||
|
||||
CI.cookwork += cooking_power
|
||||
|
||||
if (!was_done && CI.cookwork >= CI.max_cookwork)
|
||||
//If cookwork has gone from above to below 0, then this item finished cooking
|
||||
finish_cooking(CI)
|
||||
|
||||
else if (!CI.burned && CI.cookwork > CI.max_cookwork * CI.overcook_mult)
|
||||
burn_food(CI)
|
||||
|
||||
// Gotta hurt.
|
||||
for(var/obj/item/weapon/holder/H in CI.container.contents)
|
||||
var/mob/living/M = H.held_mob
|
||||
if (M)
|
||||
M.apply_damage(rand(1,3), mobdamagetype, "chest")
|
||||
|
||||
return 1
|
||||
|
||||
/obj/machinery/appliance/process()
|
||||
if (cooking_power > 0 && cooking)
|
||||
for (var/i in cooking_objs)
|
||||
do_cooking_tick(i)
|
||||
|
||||
|
||||
/obj/machinery/appliance/proc/finish_cooking(var/datum/cooking_item/CI)
|
||||
|
||||
src.visible_message("<span class='notice'>\The [src] pings!</span>")
|
||||
if(cooked_sound)
|
||||
playsound(get_turf(src), cooked_sound, 50, 1)
|
||||
//Check recipes first, a valid recipe overrides other options
|
||||
var/datum/recipe/recipe = null
|
||||
var/atom/C = null
|
||||
if (CI.container)
|
||||
C = CI.container
|
||||
else
|
||||
C = src
|
||||
recipe = select_recipe(available_recipes,C)
|
||||
|
||||
if (recipe)
|
||||
CI.result_type = 4//Recipe type, a specific recipe will transform the ingredients into a new food
|
||||
var/list/results = recipe.make_food(C)
|
||||
|
||||
var/obj/temp = new /obj(src) //To prevent infinite loops, all results will be moved into a temporary location so they're not considered as inputs for other recipes
|
||||
|
||||
for (var/atom/movable/AM in results)
|
||||
AM.forceMove(temp)
|
||||
|
||||
//making multiple copies of a recipe from one container. For example, tons of fries
|
||||
while (select_recipe(available_recipes,C) == recipe)
|
||||
var/list/TR = list()
|
||||
TR += recipe.make_food(C)
|
||||
for (var/atom/movable/AM in TR) //Move results to buffer
|
||||
AM.forceMove(temp)
|
||||
results += TR
|
||||
|
||||
|
||||
for (var/r in results)
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/R = r
|
||||
R.forceMove(C) //Move everything from the buffer back to the container
|
||||
R.cooked |= cook_type
|
||||
|
||||
QDEL_NULL(temp) //delete buffer object
|
||||
. = 1 //None of the rest of this function is relevant for recipe cooking
|
||||
|
||||
else if(CI.combine_target)
|
||||
CI.result_type = 3//Combination type. We're making something out of our ingredients
|
||||
. = combination_cook(CI)
|
||||
|
||||
|
||||
else
|
||||
//Otherwise, we're just doing standard modification cooking. change a color + name
|
||||
for (var/obj/item/i in CI.container)
|
||||
modify_cook(i, CI)
|
||||
|
||||
//Final step. Cook function just cooks batter for now.
|
||||
for (var/obj/item/weapon/reagent_containers/food/snacks/S in CI.container)
|
||||
S.cook()
|
||||
|
||||
|
||||
//Combination cooking involves combining the names and reagents of ingredients into a predefined output object
|
||||
//The ingredients represent flavours or fillings. EG: donut pizza, cheese bread
|
||||
/obj/machinery/appliance/proc/combination_cook(var/datum/cooking_item/CI)
|
||||
var/cook_path = output_options[CI.combine_target]
|
||||
|
||||
var/list/words = list()
|
||||
var/list/cooktypes = list()
|
||||
var/datum/reagents/buffer = new /datum/reagents(1000)
|
||||
var/totalcolour
|
||||
|
||||
for (var/obj/item/I in CI.container)
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/S
|
||||
if (istype(I, /obj/item/weapon/holder))
|
||||
S = create_mob_food(I, CI)
|
||||
else if (istype(I, /obj/item/weapon/reagent_containers/food/snacks))
|
||||
S = I
|
||||
|
||||
if (!S)
|
||||
continue
|
||||
|
||||
words |= text2list(S.name," ")
|
||||
cooktypes |= S.cooked
|
||||
|
||||
if (S.reagents && S.reagents.total_volume > 0)
|
||||
if (S.filling_color)
|
||||
if (!totalcolour || !buffer.total_volume)
|
||||
totalcolour = S.filling_color
|
||||
else
|
||||
var/t = buffer.total_volume + S.reagents.total_volume
|
||||
t = buffer.total_volume / y
|
||||
totalcolour = BlendRGB(totalcolour, S.filling_color, t)
|
||||
//Blend colours in order to find a good filling color
|
||||
|
||||
|
||||
S.reagents.trans_to_holder(buffer, S.reagents.total_volume)
|
||||
//Cleanup these empty husk ingredients now
|
||||
if (I)
|
||||
qdel(I)
|
||||
if (S)
|
||||
qdel(S)
|
||||
|
||||
CI.container.reagents.trans_to_holder(buffer, CI.container.reagents.total_volume)
|
||||
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/result = new cook_path(CI.container)
|
||||
buffer.trans_to(result, buffer.total_volume)
|
||||
|
||||
//Filling overlay
|
||||
var/image/I = image(result.icon, "[result.icon_state]_filling")
|
||||
I.color = totalcolour
|
||||
result.add_overlay(I)
|
||||
result.filling_color = totalcolour
|
||||
|
||||
//Set the name.
|
||||
words -= list("and", "the", "in", "is", "bar", "raw", "sticks", "boiled", "fried", "deep", "-o-", "warm", "two", "flavored")
|
||||
//Remove common connecting words and unsuitable ones from the list. Unsuitable words include those describing
|
||||
//the shape, cooked-ness/temperature or other state of an ingredient which doesn't apply to the finished product
|
||||
words.Remove(result.name)
|
||||
shuffle(words)
|
||||
var/num = 6 //Maximum number of words
|
||||
while (num > 0)
|
||||
num--
|
||||
if (!words.len)
|
||||
break
|
||||
//Add prefixes from the ingredients in a random order until we run out or hit limit
|
||||
result.name = "[pop(words)] [result.name]"
|
||||
|
||||
//This proc sets the size of the output result
|
||||
result.update_icon()
|
||||
return result
|
||||
|
||||
//Helper proc for standard modification cooking
|
||||
/obj/machinery/appliance/proc/modify_cook(var/obj/item/input, var/datum/cooking_item/CI)
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/result
|
||||
if (istype(input, /obj/item/weapon/holder))
|
||||
result = create_mob_food(input, CI)
|
||||
else if (istype(input, /obj/item/weapon/reagent_containers/food/snacks))
|
||||
result = input
|
||||
else
|
||||
//Nonviable item
|
||||
return
|
||||
|
||||
if (!result)
|
||||
return
|
||||
|
||||
result.cooked |= cook_type
|
||||
|
||||
// Set icon and appearance.
|
||||
change_product_appearance(result, CI)
|
||||
|
||||
// Update strings.
|
||||
change_product_strings(result, CI)
|
||||
|
||||
/obj/machinery/appliance/proc/burn_food(var/datum/cooking_item/CI)
|
||||
// You dun goofed.
|
||||
CI.burned = 1
|
||||
CI.container.clear()
|
||||
new /obj/item/weapon/reagent_containers/food/snacks/badrecipe(CI.container)
|
||||
|
||||
// Produce nasty smoke.
|
||||
visible_message("<span class='danger'>\The [src] vomits a gout of rancid smoke!</span>")
|
||||
var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad
|
||||
smoke.attach(src)
|
||||
smoke.set_up(10, 0, get_turf(src), 300)
|
||||
smoke.start()
|
||||
|
||||
/obj/machinery/appliance/attack_hand(var/mob/user)
|
||||
if (cooking_objs.len)
|
||||
if (removal_menu(user))
|
||||
return
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/appliance/proc/removal_menu(var/mob/user)
|
||||
if (can_remove_items(user))
|
||||
var/list/menuoptions = list()
|
||||
for (var/a in cooking_objs)
|
||||
var/datum/cooking_item/CI = a
|
||||
if (CI.container)
|
||||
menuoptions[CI.container.label(menuoptions.len)] = CI
|
||||
|
||||
var/selection = input(user, "Which item would you like to remove?", "Remove ingredients") as null|anything in menuoptions
|
||||
if (selection)
|
||||
var/datum/cooking_item/CI = menuoptions[selection]
|
||||
eject(CI, user)
|
||||
update_icon()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/machinery/appliance/proc/can_remove_items(var/mob/user)
|
||||
if (!Adjacent(user))
|
||||
return 0
|
||||
|
||||
if (isanimal(user))
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
/obj/machinery/appliance/proc/eject(var/datum/cooking_item/CI, var/mob/user = null)
|
||||
var/obj/item/thing
|
||||
var/delete = 1
|
||||
var/status = CI.container.check_contents()
|
||||
if (status == 1)//If theres only one object in a container then we extract that
|
||||
thing = locate(/obj/item) in CI.container
|
||||
delete = 0
|
||||
else//If the container is empty OR contains more than one thing, then we must extract the container
|
||||
thing = CI.container
|
||||
if (!user || !user.put_in_hands(thing))
|
||||
thing.forceMove(get_turf(src))
|
||||
|
||||
if (delete)
|
||||
cooking_objs -= CI
|
||||
qdel(CI)
|
||||
else
|
||||
CI.reset()//reset instead of deleting if the container is left inside
|
||||
|
||||
/obj/machinery/appliance/proc/cook_mob(var/mob/living/victim, var/mob/user)
|
||||
return
|
||||
|
||||
/obj/machinery/appliance/proc/change_product_strings(var/obj/item/weapon/reagent_containers/food/snacks/product, var/datum/cooking_item/CI)
|
||||
product.name = "[cook_type] [product.name]"
|
||||
product.desc = "[product.desc]\nIt has been [cook_type]."
|
||||
|
||||
|
||||
/obj/machinery/appliance/proc/change_product_appearance(var/obj/item/weapon/reagent_containers/food/snacks/product, var/datum/cooking_item/CI)
|
||||
if (!product.coating) //Coatings change colour through a new sprite
|
||||
product.color = food_color
|
||||
product.filling_color = food_color
|
||||
|
||||
/mob/living/proc/calculate_composition() // moved from devour.dm on aurora's side
|
||||
if (!composition_reagent)//if no reagent has been set, then we'll set one
|
||||
if (isSynthetic())
|
||||
src.composition_reagent = "iron"
|
||||
else
|
||||
if(istype(src, /mob/living/carbon/human/diona) || istype(src, /mob/living/carbon/alien/diona))
|
||||
src.composition_reagent = "nutriment" // diona are plants, not meat
|
||||
else
|
||||
src.composition_reagent = "protein"
|
||||
if(istype(src, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(istype(H.species, /datum/species/diona))
|
||||
src.composition_reagent = "nutriment"
|
||||
|
||||
//if the mob is a simple animal with a defined meat quantity
|
||||
if (istype(src, /mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/SA = src
|
||||
if (SA.meat_amount)
|
||||
src.composition_reagent_quantity = SA.meat_amount*2*9
|
||||
|
||||
//The quantity of protein is based on the meat_amount, but multiplied by 2
|
||||
|
||||
var/size_reagent = (src.mob_size * src.mob_size) * 3//The quantity of protein is set to 3x mob size squared
|
||||
if (size_reagent > src.composition_reagent_quantity)//We take the larger of the two
|
||||
src.composition_reagent_quantity = size_reagent
|
||||
|
||||
//This function creates a food item which represents a dead mob
|
||||
/obj/machinery/appliance/proc/create_mob_food(var/obj/item/weapon/holder/H, var/datum/cooking_item/CI)
|
||||
if (!istype(H) || !H.held_mob)
|
||||
qdel(H)
|
||||
return null
|
||||
var/mob/living/victim = H.held_mob
|
||||
if (victim.stat != DEAD)
|
||||
return null //Victim somehow survived the cooking, they do not become food
|
||||
|
||||
victim.calculate_composition()
|
||||
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/variable/mob/result = new /obj/item/weapon/reagent_containers/food/snacks/variable/mob(CI.container)
|
||||
result.w_class = victim.mob_size
|
||||
result.reagents.add_reagent(victim.composition_reagent, victim.composition_reagent_quantity)
|
||||
|
||||
if (victim.reagents)
|
||||
victim.reagents.trans_to_holder(result.reagents, victim.reagents.total_volume)
|
||||
|
||||
if (isanimal(victim))
|
||||
var/mob/living/simple_animal/SA = victim
|
||||
result.kitchen_tag = SA.kitchen_tag
|
||||
|
||||
result.appearance = victim
|
||||
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(45)
|
||||
M.Translate(1,-2)
|
||||
result.transform = M
|
||||
|
||||
// all done, now delete the old objects
|
||||
H.held_mob = null
|
||||
qdel(victim)
|
||||
victim = null
|
||||
qdel(H)
|
||||
H = null
|
||||
|
||||
return result
|
||||
|
||||
/datum/cooking_item
|
||||
var/max_cookwork
|
||||
var/cookwork
|
||||
var/overcook_mult = 5
|
||||
var/result_type = 0
|
||||
var/obj/item/weapon/reagent_containers/cooking_container/container = null
|
||||
var/combine_target = null
|
||||
|
||||
//Result type is one of the following:
|
||||
//0 unfinished, no result yet
|
||||
//1 Standard modification cooking. eg Fried Donk Pocket, Baked wheat, etc
|
||||
//2 Modification but with a new object that's an inert copy of the old. Generally used for deepfried mice
|
||||
//3 Combination cooking, EG Donut Bread, Donk pocket pizza, etc
|
||||
//4:Specific recipe cooking. EG: Turning raw potato sticks into fries
|
||||
|
||||
var/burned = 0
|
||||
|
||||
var/oil = 0
|
||||
var/max_oil = 0//Used for fryers.
|
||||
|
||||
/datum/cooking_item/New(var/obj/item/I)
|
||||
container = I
|
||||
|
||||
//This is called for containers whose contents are ejected without removing the container
|
||||
/datum/cooking_item/proc/reset()
|
||||
max_cookwork = 0
|
||||
cookwork = 0
|
||||
result_type = 0
|
||||
burned = 0
|
||||
max_oil = 0
|
||||
oil = 0
|
||||
combine_target = null
|
||||
//Container is not reset
|
||||
|
||||
/obj/machinery/appliance/RefreshParts()
|
||||
..()
|
||||
var/scan_rating = 0
|
||||
var/cap_rating = 0
|
||||
|
||||
for(var/obj/item/weapon/stock_parts/P in src.component_parts)
|
||||
if(istype(P, /obj/item/weapon/stock_parts/scanning_module))
|
||||
scan_rating += P.rating
|
||||
else if(istype(P, /obj/item/weapon/stock_parts/capacitor))
|
||||
cap_rating += P.rating
|
||||
|
||||
active_power_usage = initial(active_power_usage) - scan_rating*10
|
||||
cooking_power = initial(cooking_power) + (scan_rating+cap_rating)/10
|
||||
|
||||
/obj/item/weapon/circuitboard/cooking
|
||||
name = "kitchen appliance circuitry"
|
||||
desc = "The circuitboard for many kitchen appliances. Not of much use."
|
||||
origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2)
|
||||
req_components = list(
|
||||
/obj/item/weapon/stock_parts/capacitor = 3,
|
||||
/obj/item/weapon/stock_parts/scanning_module = 1,
|
||||
/obj/item/weapon/stock_parts/matter_bin = 2)
|
||||
@@ -1,261 +1,132 @@
|
||||
// This folder contains code that was originally ported from Apollo Station and then refactored/optimized/changed.
|
||||
/obj/machinery/appliance/cooker
|
||||
var/temperature = T20C
|
||||
var/min_temp = 80 + T0C //Minimum temperature to do any cooking
|
||||
var/optimal_temp = 200 + T0C //Temperature at which we have 100% efficiency. efficiency is lowered on either side of this
|
||||
var/optimal_power = 0.1//cooking power at 100%
|
||||
|
||||
// Tracks precooked food to stop deep fried baked grilled grilled grilled diona nymph cereal.
|
||||
/obj/item/weapon/reagent_containers/food/snacks/var/list/cooked
|
||||
var/loss = 1 //Temp lost per proc when equalising
|
||||
var/resistance = 320000 //Resistance to heating. combines with active power usage to determine how long heating takes
|
||||
|
||||
// Root type for cooking machines. See following files for specific implementations.
|
||||
/obj/machinery/cooker
|
||||
name = "cooker"
|
||||
desc = "You shouldn't be seeing this!"
|
||||
icon = 'icons/obj/cooking_machines.dmi'
|
||||
density = 1
|
||||
anchored = 1
|
||||
use_power = USE_POWER_IDLE
|
||||
idle_power_usage = 5
|
||||
var/light_x = 0
|
||||
var/light_y = 0
|
||||
cooking_power = 0
|
||||
|
||||
var/on_icon // Icon state used when cooking.
|
||||
var/off_icon // Icon state used when not cooking.
|
||||
var/cooking // Whether or not the machine is currently operating.
|
||||
var/cook_type // A string value used to track what kind of food this machine makes.
|
||||
var/cook_time = 200 // How many ticks the cooking will take.
|
||||
var/can_cook_mobs // Whether or not this machine accepts grabbed mobs.
|
||||
var/food_color // Colour of resulting food item.
|
||||
var/cooked_sound // Sound played when cooking completes.
|
||||
var/can_burn_food // Can the object burn food that is left inside?
|
||||
var/burn_chance = 10 // How likely is the food to burn?
|
||||
var/obj/item/cooking_obj // Holder for the currently cooking object.
|
||||
|
||||
// If the machine has multiple output modes, define them here.
|
||||
var/selected_option
|
||||
var/list/output_options = list()
|
||||
|
||||
/obj/machinery/cooker/Destroy()
|
||||
if(cooking_obj)
|
||||
qdel(cooking_obj)
|
||||
cooking_obj = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/cooker/proc/set_cooking(new_setting)
|
||||
cooking = new_setting
|
||||
icon_state = new_setting ? on_icon : off_icon
|
||||
|
||||
/obj/machinery/cooker/examine(mob/user)
|
||||
/obj/machinery/appliance/cooker/examine(var/mob/user)
|
||||
. = ..()
|
||||
if(cooking_obj && Adjacent(user))
|
||||
. += "You can see \a [cooking_obj] inside."
|
||||
|
||||
/obj/machinery/cooker/attackby(var/obj/item/I, var/mob/user)
|
||||
|
||||
if(!cook_type || (stat & (NOPOWER|BROKEN)))
|
||||
to_chat(user, "<span class='warning'>\The [src] is not working.</span>")
|
||||
return
|
||||
|
||||
if(cooking)
|
||||
to_chat(user, "<span class='warning'>\The [src] is running!</span>")
|
||||
return
|
||||
|
||||
if(default_unfasten_wrench(user, I, 20))
|
||||
return
|
||||
|
||||
// We are trying to cook a grabbed mob.
|
||||
var/obj/item/weapon/grab/G = I
|
||||
if(istype(G))
|
||||
|
||||
if(!can_cook_mobs)
|
||||
to_chat(user, "<span class='warning'>That's not going to fit.</span>")
|
||||
return
|
||||
|
||||
if(!isliving(G.affecting))
|
||||
to_chat(user, "<span class='warning'>You can't cook that.</span>")
|
||||
return
|
||||
|
||||
cook_mob(G.affecting, user)
|
||||
return
|
||||
|
||||
// We're trying to cook something else. Check if it's valid.
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/check = I
|
||||
if(istype(check) && islist(check.cooked) && (cook_type in check.cooked))
|
||||
to_chat(user, "<span class='warning'>\The [check] has already been [cook_type].</span>")
|
||||
return 0
|
||||
else if(istype(check, /obj/item/weapon/reagent_containers/glass))
|
||||
to_chat(user, "<span class='warning'>That would probably break [src].</span>")
|
||||
return 0
|
||||
else if(istype(check, /obj/item/weapon/disk/nuclear))
|
||||
to_chat(user, "Central Command would kill you if you [cook_type] that.")
|
||||
return 0
|
||||
else if(!istype(check) && !istype(check, /obj/item/weapon/holder) && !istype(check, /obj/item/organ)) //Gripper check has to go here, else it still just cuts it off. ~Mechoid
|
||||
// Is it a borg using a gripper?
|
||||
if(istype(check, /obj/item/weapon/gripper)) // Grippers. ~Mechoid.
|
||||
var/obj/item/weapon/gripper/B = check //B, for Borg.
|
||||
if(!B.wrapped)
|
||||
to_chat(user, "\The [B] is not holding anything.")
|
||||
return 0
|
||||
if(.) //no need to duplicate adjacency check
|
||||
if(!stat)
|
||||
if (temperature < min_temp)
|
||||
to_chat(user, span("warning", "\The [src] is still heating up and is too cold to cook anything yet."))
|
||||
else
|
||||
var/B_held = B.wrapped
|
||||
to_chat(user, "You use \the [B] to put \the [B_held] into \the [src].")
|
||||
return 0
|
||||
to_chat(user, span("notice", "It is running at [round(get_efficiency(), 0.1)]% efficiency!"))
|
||||
to_chat(user, "Temperature: [round(temperature - T0C, 0.1)]C / [round(optimal_temp - T0C, 0.1)]C")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>That's not edible.</span>")
|
||||
return 0
|
||||
|
||||
if(istype(I, /obj/item/organ))
|
||||
var/obj/item/organ/O = I
|
||||
if(O.robotic)
|
||||
to_chat(user, "<span class='warning'>That would probably break [src].</span>")
|
||||
return
|
||||
|
||||
// Gotta hurt.
|
||||
if(istype(cooking_obj, /obj/item/weapon/holder))
|
||||
for(var/mob/living/M in cooking_obj.contents)
|
||||
M.apply_damage(rand(30,40), BURN, "chest")
|
||||
|
||||
// Not sure why a food item that passed the previous checks would fail to drop, but safety first. (Hint: Borg grippers. That is why. ~Mechoid.)
|
||||
if(!user.unEquip(I) && !istype(user,/mob/living/silicon/robot))
|
||||
return
|
||||
|
||||
// We can actually start cooking now.
|
||||
user.visible_message("<span class='notice'>\The [user] puts \the [I] into \the [src].</span>")
|
||||
cooking_obj = I
|
||||
cooking_obj.forceMove(src)
|
||||
set_cooking(TRUE)
|
||||
icon_state = on_icon
|
||||
|
||||
// Doop de doo. Jeopardy theme goes here.
|
||||
sleep(cook_time)
|
||||
|
||||
// Sanity checks.
|
||||
if(!cooking_obj || cooking_obj.loc != src)
|
||||
cooking_obj = null
|
||||
icon_state = off_icon
|
||||
set_cooking(FALSE)
|
||||
return
|
||||
|
||||
// RIP slow-moving held mobs.
|
||||
if(istype(cooking_obj, /obj/item/weapon/holder))
|
||||
for(var/mob/living/M in cooking_obj.contents)
|
||||
M.death()
|
||||
qdel(M)
|
||||
|
||||
// Cook the food.
|
||||
var/cook_path
|
||||
if(selected_option && output_options.len)
|
||||
cook_path = output_options[selected_option]
|
||||
if(!cook_path)
|
||||
cook_path = /obj/item/weapon/reagent_containers/food/snacks/variable
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/result = new cook_path(src) //Holy typepaths, Batman.
|
||||
|
||||
// Set icon and appearance.
|
||||
change_product_appearance(result)
|
||||
|
||||
// Update strings.
|
||||
change_product_strings(result)
|
||||
|
||||
// Copy reagents over. trans_to_obj must be used, as trans_to fails for snacks due to is_open_container() failing.
|
||||
if(cooking_obj.reagents && cooking_obj.reagents.total_volume)
|
||||
cooking_obj.reagents.trans_to_obj(result, cooking_obj.reagents.total_volume)
|
||||
|
||||
// Set cooked data.
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/food_item = cooking_obj
|
||||
if(istype(food_item) && islist(food_item.cooked))
|
||||
result.cooked = food_item.cooked.Copy()
|
||||
to_chat(user, span("warning", "It is switched off."))
|
||||
|
||||
/obj/machinery/appliance/cooker/list_contents(var/mob/user)
|
||||
if (cooking_objs.len)
|
||||
var/string = "Contains...</br>"
|
||||
var/num = 0
|
||||
for (var/a in cooking_objs)
|
||||
num++
|
||||
var/datum/cooking_item/CI = a
|
||||
if (CI && CI.container)
|
||||
string += "- [CI.container.label(num)], [report_progress(CI)]</br>"
|
||||
to_chat(user, string)
|
||||
else
|
||||
result.cooked = list()
|
||||
result.cooked |= cook_type
|
||||
to_chat(user, span("notice","It is empty."))
|
||||
|
||||
/obj/machinery/appliance/cooker/proc/get_efficiency()
|
||||
//RefreshParts()
|
||||
return (cooking_power / optimal_power) * 100
|
||||
|
||||
// Reset relevant variables.
|
||||
qdel(cooking_obj)
|
||||
src.visible_message("<span class='notice'>\The [src] pings!</span>")
|
||||
if(cooked_sound)
|
||||
playsound(src, cooked_sound, 50, 1)
|
||||
/obj/machinery/appliance/cooker/New()
|
||||
. = ..()
|
||||
loss = (active_power_usage / resistance)*0.5
|
||||
cooking_objs = list()
|
||||
for (var/i = 0, i < max_contents, i++)
|
||||
cooking_objs.Add(new /datum/cooking_item/(new container_type(src)))
|
||||
cooking = 0
|
||||
|
||||
if(!can_burn_food)
|
||||
icon_state = off_icon
|
||||
set_cooking(FALSE)
|
||||
result.forceMove(get_turf(src))
|
||||
cooking_obj = null
|
||||
update_icon() // this probably won't cause issues, but Aurora used SSIcons and queue_icon_update() instead
|
||||
|
||||
/obj/machinery/appliance/cooker/update_icon()
|
||||
cut_overlays()
|
||||
var/image/light
|
||||
if (use_power == 2 && !stat)
|
||||
light = image(icon, "light_on")
|
||||
else
|
||||
var/failed
|
||||
var/overcook_period = max(FLOOR(cook_time/5, 1),1)
|
||||
cooking_obj = result
|
||||
var/count = overcook_period
|
||||
while(1)
|
||||
sleep(overcook_period)
|
||||
count += overcook_period
|
||||
if(!cooking || !result || result.loc != src)
|
||||
failed = 1
|
||||
else if(prob(burn_chance) || count == cook_time) //Fail before it has a chance to cook again.
|
||||
// You dun goofed.
|
||||
qdel(cooking_obj)
|
||||
cooking_obj = new /obj/item/weapon/reagent_containers/food/snacks/badrecipe(src)
|
||||
// Produce nasty smoke.
|
||||
visible_message("<span class='danger'>\The [src] vomits a gout of rancid smoke!</span>")
|
||||
var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad()
|
||||
smoke.attach(src)
|
||||
smoke.set_up(10, 0, usr.loc)
|
||||
smoke.start()
|
||||
failed = 1
|
||||
|
||||
if(failed)
|
||||
set_cooking(FALSE)
|
||||
icon_state = off_icon
|
||||
break
|
||||
|
||||
/obj/machinery/cooker/attack_hand(var/mob/user)
|
||||
|
||||
if(cooking_obj && user.Adjacent(src)) //Fixes borgs being able to teleport food in these machines to themselves.
|
||||
to_chat(user, "<span class='notice'>You grab \the [cooking_obj] from \the [src].</span>")
|
||||
user.put_in_hands(cooking_obj)
|
||||
set_cooking(FALSE)
|
||||
cooking_obj = null
|
||||
icon_state = off_icon
|
||||
return
|
||||
|
||||
if(output_options.len)
|
||||
|
||||
if(cooking)
|
||||
to_chat(user, "<span class='warning'>\The [src] is in use!</span>")
|
||||
return
|
||||
|
||||
var/choice = input("What specific food do you wish to make with \the [src]?") as null|anything in output_options+"Default"
|
||||
if(!choice)
|
||||
return
|
||||
if(choice == "Default")
|
||||
selected_option = null
|
||||
to_chat(user, "<span class='notice'>You decide not to make anything specific with \the [src].</span>")
|
||||
else
|
||||
selected_option = choice
|
||||
to_chat(user, "<span class='notice'>You prepare \the [src] to make \a [selected_option].</span>")
|
||||
light = image(icon, "light_off")
|
||||
light.pixel_x = light_x
|
||||
light.pixel_y = light_y
|
||||
add_overlay(light)
|
||||
|
||||
/obj/machinery/appliance/cooker/process()
|
||||
if (!stat)
|
||||
heat_up()
|
||||
else
|
||||
var/turf/T = get_turf(src)
|
||||
if (temperature > T.temperature)
|
||||
equalize_temperature()
|
||||
..()
|
||||
|
||||
/obj/machinery/appliance/cooker/power_change()
|
||||
. = ..()
|
||||
update_icon() // this probably won't cause issues, but Aurora used SSIcons and queue_icon_update() instead
|
||||
|
||||
/obj/machinery/appliance/cooker/proc/update_cooking_power()
|
||||
var/temp_scale = 0
|
||||
if(temperature > min_temp)
|
||||
temp_scale = (temperature - min_temp) / (optimal_temp - min_temp) // If we're between min and optimal this will yield a value in the range 0-1
|
||||
|
||||
/obj/machinery/cooker/proc/cook_mob(var/mob/living/victim, var/mob/user)
|
||||
return
|
||||
|
||||
/obj/machinery/cooker/proc/change_product_strings(var/obj/item/weapon/reagent_containers/food/snacks/product)
|
||||
if(product.type == /obj/item/weapon/reagent_containers/food/snacks/variable) // Base type, generic.
|
||||
product.name = "[cook_type] [cooking_obj.name]"
|
||||
product.desc = "[cooking_obj.desc] It has been [cook_type]."
|
||||
if(temp_scale > 1) // We're above optimal, efficiency goes down as we pass too much over it
|
||||
if(temp_scale >= 2)
|
||||
temp_scale = 0
|
||||
else
|
||||
temp_scale = 1 - (temp_scale - 1)
|
||||
|
||||
cooking_power = optimal_power * temp_scale
|
||||
// RefreshParts()
|
||||
|
||||
/obj/machinery/appliance/cooker/proc/heat_up()
|
||||
if(temperature < optimal_temp)
|
||||
if(use_power == 1 && ((optimal_temp - temperature) > 5))
|
||||
playsound(src, 'sound/machines/click.ogg', 20, 1)
|
||||
use_power = 2.//If we're heating we use the active power
|
||||
update_icon()
|
||||
temperature += active_power_usage / resistance
|
||||
update_cooking_power()
|
||||
return 1
|
||||
else
|
||||
product.name = "[cooking_obj.name] [product.name]"
|
||||
if(use_power == 2)
|
||||
use_power = 1
|
||||
playsound(src, 'sound/machines/click.ogg', 20, 1)
|
||||
update_icon()
|
||||
//We're holding steady. temperature falls more slowly
|
||||
if(prob(25))
|
||||
equalize_temperature()
|
||||
return -1
|
||||
|
||||
/obj/machinery/cooker/proc/change_product_appearance(var/obj/item/weapon/reagent_containers/food/snacks/product)
|
||||
if(product.type == /obj/item/weapon/reagent_containers/food/snacks/variable) // Base type, generic.
|
||||
product.appearance = cooking_obj
|
||||
product.color = food_color
|
||||
product.filling_color = food_color
|
||||
/obj/machinery/appliance/cooker/proc/equalize_temperature()
|
||||
temperature -= loss//Temperature will fall somewhat slowly
|
||||
update_cooking_power()
|
||||
|
||||
// Make 'em into a corpse.
|
||||
if(istype(cooking_obj, /obj/item/weapon/holder))
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(90)
|
||||
M.Translate(1,-6)
|
||||
product.transform = M
|
||||
//Cookers do differently, they use containers
|
||||
/obj/machinery/appliance/cooker/has_space(var/obj/item/I)
|
||||
if(istype(I, /obj/item/weapon/reagent_containers/cooking_container))
|
||||
//Containers can go into an empty slot
|
||||
if(cooking_objs.len < max_contents)
|
||||
return 1
|
||||
else
|
||||
var/image/I = image(product.icon, "[product.icon_state]_filling")
|
||||
if(istype(cooking_obj, /obj/item/weapon/reagent_containers/food/snacks))
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/S = cooking_obj
|
||||
I.color = S.filling_color
|
||||
if(!I.color)
|
||||
I.color = food_color
|
||||
product.overlays += I
|
||||
//Any food items directly added need an empty container. A slot without a container cant hold food
|
||||
for (var/datum/cooking_item/CI in cooking_objs)
|
||||
if (CI.container.check_contents() == 0)
|
||||
return CI
|
||||
|
||||
return 0
|
||||
|
||||
/obj/machinery/appliance/cooker/add_content(var/obj/item/I, var/mob/user)
|
||||
var/datum/cooking_item/CI = ..()
|
||||
if (CI && CI.combine_target)
|
||||
to_chat(user, "\The [I] will be used to make a [selected_option]. Output selection is returned to default for future items.")
|
||||
selected_option = null
|
||||
@@ -1,72 +1,160 @@
|
||||
// Wrapper obj for cooked food. Appearance is set in the cooking code, not on spawn.
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable
|
||||
name = "cooked food"
|
||||
icon = 'icons/obj/food_custom.dmi'
|
||||
desc = "If you can see this description then something is wrong. Please report the bug on the tracker."
|
||||
nutriment_amt = 5
|
||||
bitesize = 2
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/pizza
|
||||
name = "personal pizza"
|
||||
desc = "A personalized pan pizza meant for only one person."
|
||||
icon_state = "personal_pizza"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/bread
|
||||
name = "bread"
|
||||
desc = "Tasty bread."
|
||||
icon_state = "breadcustom"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/pie
|
||||
name = "pie"
|
||||
desc = "Tasty pie."
|
||||
icon_state = "piecustom"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/cake
|
||||
name = "cake"
|
||||
desc = "A popular band."
|
||||
icon_state = "cakecustom"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/pocket
|
||||
name = "hot pocket"
|
||||
desc = "You wanna put a bangin- oh, nevermind."
|
||||
icon_state = "donk"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/kebab
|
||||
name = "kebab"
|
||||
desc = "Remove this!"
|
||||
icon_state = "kabob"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/waffles
|
||||
name = "waffles"
|
||||
desc = "Made with love."
|
||||
icon_state = "waffles"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/cookie
|
||||
name = "cookie"
|
||||
desc = "Sugar snap!"
|
||||
icon_state = "cookie"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/donut
|
||||
name = "filled donut"
|
||||
desc = "Donut eat this!" // kill me
|
||||
icon_state = "donut"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/jawbreaker
|
||||
name = "flavored jawbreaker"
|
||||
desc = "It's like cracking a molar on a rainbow."
|
||||
icon_state = "jawbreaker"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/candybar
|
||||
name = "flavored chocolate bar"
|
||||
desc = "Made in a factory downtown."
|
||||
icon_state = "bar"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/sucker
|
||||
name = "flavored sucker"
|
||||
desc = "Suck, suck, suck."
|
||||
icon_state = "sucker"
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/jelly
|
||||
name = "jelly"
|
||||
desc = "All your friends will be jelly."
|
||||
icon_state = "jellycustom"
|
||||
// Wrapper obj for cooked food. Appearance is set in the cooking code, not on spawn.
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable
|
||||
name = "cooked food"
|
||||
icon = 'icons/obj/food_custom.dmi'
|
||||
desc = "If you can see this description then something is wrong. Please report the bug on the tracker."
|
||||
bitesize = 2
|
||||
|
||||
var/size = 5 //The quantity of reagents which is considered "normal" for this kind of food
|
||||
//These objects will change size depending on the ratio of reagents to this value
|
||||
var/min_scale = 0.5
|
||||
var/max_scale = 2
|
||||
var/scale = 1
|
||||
|
||||
w_class = 2
|
||||
var/prefix
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/initialize()
|
||||
. = ..()
|
||||
if (reagents)
|
||||
reagents.maximum_volume = size*8 + 10
|
||||
else
|
||||
create_reagents(size*8 + 10)
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/update_icon()
|
||||
if (reagents && reagents.total_volume)
|
||||
var/ratio = reagents.total_volume / size
|
||||
|
||||
scale = ratio**(1/3) //Scaling factor is square root of desired area
|
||||
scale = Clamp(scale, min_scale, max_scale)
|
||||
else
|
||||
scale = min_scale
|
||||
|
||||
var/matrix/M = matrix()
|
||||
M.Scale(scale)
|
||||
src.transform = M
|
||||
|
||||
w_class *= scale
|
||||
if (!prefix)
|
||||
if (scale == min_scale)
|
||||
prefix = "tiny"
|
||||
else if (scale <= 0.8)
|
||||
prefix = "small"
|
||||
|
||||
else
|
||||
if (scale >= 1.2)
|
||||
prefix = "large"
|
||||
if (scale >= 1.4)
|
||||
prefix = "extra large"
|
||||
if (scale >= 1.6)
|
||||
prefix = "huge"
|
||||
if (scale >= max_scale)
|
||||
prefix = "massive"
|
||||
|
||||
name = "[prefix] [name]"
|
||||
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/pizza
|
||||
name = "personal pizza"
|
||||
desc = "A personalized pan pizza meant for only one person."
|
||||
icon_state = "personal_pizza"
|
||||
size = 20
|
||||
w_class = 3
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/bread
|
||||
name = "bread"
|
||||
desc = "Tasty bread."
|
||||
icon_state = "breadcustom"
|
||||
size = 40
|
||||
w_class = 3
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/pie
|
||||
name = "pie"
|
||||
desc = "Tasty pie."
|
||||
icon_state = "piecustom"
|
||||
size = 25
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/cake
|
||||
name = "cake"
|
||||
desc = "A popular band."
|
||||
icon_state = "cakecustom"
|
||||
size = 40
|
||||
w_class = 3
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/pocket
|
||||
name = "hot pocket"
|
||||
desc = "You wanna put a bangin- oh, nevermind."
|
||||
icon_state = "donk"
|
||||
size = 8
|
||||
w_class = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/kebab
|
||||
name = "kebab"
|
||||
desc = "Remove this!"
|
||||
icon_state = "kabob"
|
||||
size = 10
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/waffles
|
||||
name = "waffles"
|
||||
desc = "Made with love."
|
||||
icon_state = "waffles"
|
||||
size = 12
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/cookie
|
||||
name = "cookie"
|
||||
desc = "Sugar snap!"
|
||||
icon_state = "cookie"
|
||||
size = 6
|
||||
w_class = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/donut
|
||||
name = "filled donut"
|
||||
desc = "Donut eat this!" // kill me
|
||||
icon_state = "donut"
|
||||
size = 8
|
||||
w_class = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/jawbreaker
|
||||
name = "flavored jawbreaker"
|
||||
desc = "It's like cracking a molar on a rainbow."
|
||||
icon_state = "jawbreaker"
|
||||
size = 4
|
||||
w_class = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/candybar
|
||||
name = "flavored chocolate bar"
|
||||
desc = "Made in a factory downtown."
|
||||
icon_state = "bar"
|
||||
size = 6
|
||||
w_class = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/sucker
|
||||
name = "flavored sucker"
|
||||
desc = "Suck, suck, suck."
|
||||
icon_state = "sucker"
|
||||
size = 4
|
||||
w_class = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/jelly
|
||||
name = "jelly"
|
||||
desc = "All your friends will be jelly."
|
||||
icon_state = "jellycustom"
|
||||
size = 8
|
||||
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/cereal
|
||||
name = "cereal"
|
||||
desc = "Crispy and flaky"
|
||||
icon_state = "cereal_box"
|
||||
size = 30
|
||||
w_class = 3
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/cereal/initialize()
|
||||
. =..()
|
||||
name = pick(list("flakes", "krispies", "crunch", "pops", "O's", "crisp", "loops", "jacks", "clusters"))
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/variable/mob
|
||||
desc = "Poor little thing."
|
||||
size = 5
|
||||
w_class = 1
|
||||
var/kitchen_tag = "animal"
|
||||
141
code/modules/food/kitchen/cooking_machines/_mixer.dm
Normal file
141
code/modules/food/kitchen/cooking_machines/_mixer.dm
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
The mixer subtype is used for the candymaker and cereal maker. They are similar to cookers but with a few
|
||||
fundamental differences
|
||||
1. They have a single container which cant be removed. it will eject multiple contents
|
||||
2. Items can't be added or removed once the process starts
|
||||
3. Items are all placed in the same container when added directly
|
||||
4. They do combining mode only. And will always combine the entire contents of the container into an output
|
||||
*/
|
||||
|
||||
/obj/machinery/appliance/mixer
|
||||
max_contents = 1
|
||||
stat = POWEROFF
|
||||
cooking_power = 0.4
|
||||
active_power_usage = 3000
|
||||
idle_power_usage = 50
|
||||
|
||||
/obj/machinery/appliance/mixer/examine(var/mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>It is currently set to make a [selected_option]</span>")
|
||||
|
||||
/obj/machinery/appliance/mixer/New()
|
||||
. = ..()
|
||||
cooking_objs += new /datum/cooking_item(new /obj/item/weapon/reagent_containers/cooking_container(src))
|
||||
cooking = 0
|
||||
selected_option = pick(output_options)
|
||||
|
||||
//Mixers cannot-not do combining mode. So the default option is removed from this. A combine target must be chosen
|
||||
/obj/machinery/appliance/mixer/choose_output()
|
||||
set src in oview(1)
|
||||
set name = "Choose output"
|
||||
set category = "Object"
|
||||
|
||||
if (!isliving(usr))
|
||||
return
|
||||
|
||||
if (!usr.IsAdvancedToolUser())
|
||||
to_chat(user, "<span class='notice'>You can't operate [src].</span>")
|
||||
return
|
||||
|
||||
if(output_options.len)
|
||||
var/choice = input("What specific food do you wish to make with \the [src]?") as null|anything in output_options
|
||||
if(!choice)
|
||||
return
|
||||
else
|
||||
selected_option = choice
|
||||
to_chat(user, "<span class='notice'>You prepare \the [src] to make \a [selected_option].</span>")
|
||||
var/datum/cooking_item/CI = cooking_objs[1]
|
||||
CI.combine_target = selected_option
|
||||
|
||||
|
||||
/obj/machinery/appliance/mixer/has_space(var/obj/item/I)
|
||||
var/datum/cooking_item/CI = cooking_objs[1]
|
||||
if (!CI || !CI.container)
|
||||
return 0
|
||||
|
||||
if (CI.container.can_fit(I))
|
||||
return CI
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/appliance/mixer/can_remove_items(var/mob/user)
|
||||
if (stat)
|
||||
return 1
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't remove ingredients while it's turned on! Turn it off first or wait for it to finish.</span>")
|
||||
|
||||
//Container is not removable
|
||||
/obj/machinery/appliance/mixer/removal_menu(var/mob/user)
|
||||
if (can_remove_items(user))
|
||||
var/list/menuoptions = list()
|
||||
for (var/a in cooking_objs)
|
||||
var/datum/cooking_item/CI = a
|
||||
if (CI.container)
|
||||
if (!CI.container.check_contents())
|
||||
to_chat(user, "There's nothing in [src] you can remove!")
|
||||
return
|
||||
|
||||
for (var/obj/item/I in CI.container)
|
||||
menuoptions[I.name] = I
|
||||
|
||||
var/selection = input(user, "Which item would you like to remove? If you want to remove chemicals, use an empty beaker.", "Remove ingredients") as null|anything in menuoptions
|
||||
if (selection)
|
||||
var/obj/item/I = menuoptions[selection]
|
||||
if (!user || !user.put_in_hands(I))
|
||||
I.forceMove(get_turf(src))
|
||||
update_icon()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/appliance/mixer/toggle_power()
|
||||
set src in view()
|
||||
set name = "Toggle Power"
|
||||
set category = "Object"
|
||||
|
||||
var/datum/cooking_item/CI = cooking_objs[1]
|
||||
if(!CI.container.check_contents())
|
||||
to_chat("There's nothing in it! Add ingredients before turning [src] on!")
|
||||
return
|
||||
|
||||
if(stat & POWEROFF)//Its turned off
|
||||
stat &= ~POWEROFF
|
||||
if(usr)
|
||||
usr.visible_message("[usr] turns the [src] on", "You turn on \the [src].")
|
||||
get_cooking_work(CI)
|
||||
use_power = 2
|
||||
else //Its on, turn it off
|
||||
stat |= POWEROFF
|
||||
use_power = 0
|
||||
if(usr)
|
||||
usr.visible_message("[usr] turns the [src] off", "You turn off \the [src].")
|
||||
playsound(src, 'sound/machines/click.ogg', 40, 1)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/appliance/mixer/can_insert(var/obj/item/I, var/mob/user)
|
||||
if(!stat)
|
||||
to_chat(user, "<span class='warning'>,You can't add items while \the [src] is running. Wait for it to finish or turn the power off to abort.</span>")
|
||||
return 0
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/appliance/mixer/finish_cooking(var/datum/cooking_item/CI)
|
||||
..()
|
||||
stat |= POWEROFF
|
||||
playsound(src, 'sound/machines/click.ogg', 40, 1)
|
||||
use_power = 0
|
||||
CI.reset()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/appliance/mixer/update_icon()
|
||||
if (!stat)
|
||||
icon_state = on_icon
|
||||
else
|
||||
icon_state = off_icon
|
||||
|
||||
|
||||
/obj/machinery/appliance/mixer/process()
|
||||
if (!stat)
|
||||
for (var/i in cooking_objs)
|
||||
do_cooking_tick(i)
|
||||
@@ -1,18 +1,20 @@
|
||||
/obj/machinery/cooker/candy
|
||||
name = "candy machine"
|
||||
desc = "Get yer candied cheese wheels here!"
|
||||
icon_state = "mixer_off"
|
||||
off_icon = "mixer_off"
|
||||
on_icon = "mixer_on"
|
||||
cook_type = "candied"
|
||||
|
||||
output_options = list(
|
||||
"Jawbreaker" = /obj/item/weapon/reagent_containers/food/snacks/variable/jawbreaker,
|
||||
"Candy Bar" = /obj/item/weapon/reagent_containers/food/snacks/variable/candybar,
|
||||
"Sucker" = /obj/item/weapon/reagent_containers/food/snacks/variable/sucker,
|
||||
"Jelly" = /obj/item/weapon/reagent_containers/food/snacks/variable/jelly
|
||||
)
|
||||
|
||||
/obj/machinery/cooker/candy/change_product_appearance(var/obj/item/weapon/reagent_containers/food/snacks/cooked/product)
|
||||
food_color = get_random_colour(1)
|
||||
. = ..()
|
||||
/obj/machinery/appliance/mixer/candy
|
||||
name = "candy machine"
|
||||
desc = "Get yer candied cheese wheels here!"
|
||||
icon_state = "mixer_off"
|
||||
off_icon = "mixer_off"
|
||||
on_icon = "mixer_on"
|
||||
cook_type = "candied"
|
||||
appliancetype = CANDYMAKER
|
||||
cooking_power = 0.6
|
||||
|
||||
output_options = list(
|
||||
"Jawbreaker" = /obj/item/weapon/reagent_containers/food/snacks/variable/jawbreaker,
|
||||
"Candy Bar" = /obj/item/weapon/reagent_containers/food/snacks/variable/candybar,
|
||||
"Sucker" = /obj/item/weapon/reagent_containers/food/snacks/variable/sucker,
|
||||
"Jelly" = /obj/item/weapon/reagent_containers/food/snacks/variable/jelly
|
||||
)
|
||||
|
||||
/obj/machinery/appliance/mixer/candy/change_product_appearance(var/obj/item/weapon/reagent_containers/food/snacks/cooked/product)
|
||||
food_color = get_random_colour(1)
|
||||
. = ..()
|
||||
|
||||
@@ -1,25 +1,62 @@
|
||||
/obj/machinery/cooker/cereal
|
||||
name = "cereal maker"
|
||||
desc = "Now with Dann O's available!"
|
||||
icon = 'icons/obj/cooking_machines.dmi'
|
||||
icon_state = "cereal_off"
|
||||
cook_type = "cerealized"
|
||||
on_icon = "cereal_on"
|
||||
off_icon = "cereal_off"
|
||||
|
||||
/obj/machinery/cooker/cereal/change_product_strings(var/obj/item/weapon/reagent_containers/food/snacks/product)
|
||||
. = ..()
|
||||
product.name = "box of [cooking_obj.name] cereal"
|
||||
|
||||
/obj/machinery/cooker/cereal/change_product_appearance(var/obj/item/weapon/reagent_containers/food/snacks/product)
|
||||
product.icon = 'icons/obj/food.dmi'
|
||||
product.icon_state = "cereal_box"
|
||||
product.filling_color = cooking_obj.color
|
||||
|
||||
var/image/food_image = image(cooking_obj.icon, cooking_obj.icon_state)
|
||||
food_image.color = cooking_obj.color
|
||||
food_image.overlays += cooking_obj.overlays
|
||||
food_image.transform *= 0.7
|
||||
|
||||
product.overlays += food_image
|
||||
|
||||
/obj/machinery/appliance/mixer/cereal
|
||||
name = "cereal maker"
|
||||
desc = "Now with Dann O's available!"
|
||||
icon = 'icons/obj/cooking_machines.dmi'
|
||||
icon_state = "cereal_off"
|
||||
cook_type = "cerealized"
|
||||
on_icon = "cereal_on"
|
||||
off_icon = "cereal_off"
|
||||
appliancetype = CEREALMAKER
|
||||
|
||||
output_options = list(
|
||||
"Cereal" = /obj/item/weapon/reagent_containers/food/snacks/variable/cereal
|
||||
)
|
||||
|
||||
/*
|
||||
/obj/machinery/appliance/mixer/cereal/change_product_strings(var/obj/item/weapon/reagent_containers/food/snacks/product, var/datum/cooking_item/CI)
|
||||
. = ..()
|
||||
product.name = "box of [CI.object.name] cereal"
|
||||
|
||||
/obj/machinery/appliance/mixer/cereal/change_product_appearance(var/obj/item/weapon/reagent_containers/food/snacks/product)
|
||||
product.icon = 'icons/obj/food.dmi'
|
||||
product.icon_state = "cereal_box"
|
||||
product.filling_color = CI.object.color
|
||||
|
||||
var/image/food_image = image(CI.object.icon, CI.object.icon_state)
|
||||
food_image.color = CI.object.color
|
||||
food_image.overlays += CI.object.overlays
|
||||
food_image.transform *= 0.7
|
||||
|
||||
product.overlays += food_image
|
||||
*/
|
||||
|
||||
/obj/machinery/appliance/mixer/cereal/combination_cook(var/datum/cooking_item/CI)
|
||||
|
||||
var/list/images = list()
|
||||
var/num = 0
|
||||
for (var/obj/item/I in CI.container).
|
||||
if (istype(I, /obj/item/weapon/reagent_containers/food/snacks/variable/cereal))
|
||||
//Images of cereal boxes on cereal boxes is dumb
|
||||
continue
|
||||
|
||||
var/image/food_image = image(I.icon, I.icon_state)
|
||||
food_image.color = I.color
|
||||
food_image.add_overlay(I.overlays)
|
||||
food_image.transform *= 0.7 - (num * 0.05)
|
||||
food_image.pixel_x = rand(-2,2)
|
||||
food_image.pixel_y = rand(-3,5)
|
||||
|
||||
|
||||
if (!images[I.icon_state])
|
||||
images[I.icon_state] = food_image
|
||||
num++
|
||||
|
||||
if (num > 3)
|
||||
continue
|
||||
|
||||
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/result = ..()
|
||||
|
||||
result.color = result.filling_color
|
||||
for (var/i in images)
|
||||
result.overlays += images[i]
|
||||
|
||||
157
code/modules/food/kitchen/cooking_machines/container.dm
Normal file
157
code/modules/food/kitchen/cooking_machines/container.dm
Normal file
@@ -0,0 +1,157 @@
|
||||
//Cooking containers are used in ovens and fryers, to hold multiple ingredients for a recipe.
|
||||
//They work fairly similar to the microwave - acting as a container for objects and reagents,
|
||||
//which can be checked against recipe requirements in order to cook recipes that require several things
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container
|
||||
icon = 'modular_citadel/icons/obj/cooking_machines.dmi'
|
||||
var/shortname
|
||||
var/max_space = 20//Maximum sum of w-classes of foods in this container at once
|
||||
var/max_reagents = 80//Maximum units of reagents
|
||||
flags = OPENCONTAINER | NOREACT
|
||||
var/list/insertable = list(
|
||||
/obj/item/weapon/reagent_containers/food/snacks,
|
||||
/obj/item/weapon/holder,
|
||||
/obj/item/weapon/paper
|
||||
)
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container/initialize()
|
||||
. = ..()
|
||||
create_reagents(max_reagents)
|
||||
flags |= OPENCONTAINER | NOREACT
|
||||
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container/examine(var/mob/user)
|
||||
..()
|
||||
if (contents.len)
|
||||
var/string = "It contains....</br>"
|
||||
for (var/atom/movable/A in contents)
|
||||
string += "[A.name] </br>"
|
||||
user << span("notice", string)
|
||||
if (reagents.total_volume)
|
||||
user << span("notice", "It contains [reagents.total_volume]u of reagents.")
|
||||
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container/attackby(var/obj/item/I as obj, var/mob/user as mob)
|
||||
for (var/possible_type in insertable)
|
||||
if (istype(I, possible_type))
|
||||
if (!can_fit(I))
|
||||
to_chat(user, "<span class='warning'>There's no more space in the [src] for that!</span>")
|
||||
return 0
|
||||
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
I.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You put the [I] into the [src]</span>")
|
||||
return
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container/verb/empty()
|
||||
set src in oview(1)
|
||||
set name = "Empty Container"
|
||||
set category = "Object"
|
||||
set desc = "Removes items from the container, excluding reagents."
|
||||
|
||||
do_empty(usr)
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container/proc/do_empty(mob/user)
|
||||
if (!isliving(user))
|
||||
//Here we only check for ghosts. Animals are intentionally allowed to remove things from oven trays so they can eat it
|
||||
return
|
||||
|
||||
if (user.stat || user.restrained())
|
||||
to_chat(user, "<span class='notice'>You are in no fit state to do this.</span>")
|
||||
return
|
||||
|
||||
if (!Adjacent(user))
|
||||
to_chat(user, "You can't reach [src] from here.")
|
||||
return
|
||||
|
||||
if (!contents.len)
|
||||
to_chat(user, "<span class='warning'>There's nothing in the [src] you can remove!</span>")
|
||||
return
|
||||
|
||||
for (var/atom/movable/A in contents)
|
||||
A.forceMove(get_turf(src))
|
||||
|
||||
to_chat(user, "<span class='notice'>You remove all the solid items from the [src].</span>")
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container/proc/check_contents()
|
||||
if (contents.len == 0)
|
||||
if (!reagents || reagents.total_volume == 0)
|
||||
return 0//Completely empty
|
||||
else if (contents.len == 1)
|
||||
if (!reagents || reagents.total_volume == 0)
|
||||
return 1//Contains only a single object which can be extracted alone
|
||||
return 2//Contains multiple objects and/or reagents
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container/AltClick(var/mob/user)
|
||||
do_empty(user)
|
||||
|
||||
//Deletes contents of container.
|
||||
//Used when food is burned, before replacing it with a burned mess
|
||||
/obj/item/weapon/reagent_containers/cooking_container/proc/clear()
|
||||
for (var/atom/a in contents)
|
||||
qdel(a)
|
||||
|
||||
if (reagents)
|
||||
reagents.clear_reagents()
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container/proc/label(var/number, var/CT = null)
|
||||
//This returns something like "Fryer basket 1 - empty"
|
||||
//The latter part is a brief reminder of contents
|
||||
//This is used in the removal menu
|
||||
. = shortname
|
||||
if (!isnull(number))
|
||||
.+= " [number]"
|
||||
.+= " - "
|
||||
if (CT)
|
||||
.+=CT
|
||||
else if (contents.len)
|
||||
for (var/obj/O in contents)
|
||||
.+=O.name//Just append the name of the first object
|
||||
return
|
||||
else if (reagents && reagents.total_volume > 0)
|
||||
var/datum/reagent/R = reagents.get_master_reagent()
|
||||
.+=R.name//Append name of most voluminous reagent
|
||||
return
|
||||
else
|
||||
. += "empty"
|
||||
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container/proc/can_fit(var/obj/item/I)
|
||||
var/total = 0
|
||||
for (var/obj/item/J in contents)
|
||||
total += J.w_class
|
||||
|
||||
if((max_space - total) >= I.w_class)
|
||||
return 1
|
||||
|
||||
|
||||
//Takes a reagent holder as input and distributes its contents among the items in the container
|
||||
//Distribution is weighted based on the volume already present in each item
|
||||
/obj/item/weapon/reagent_containers/cooking_container/proc/soak_reagent(var/datum/reagents/holder)
|
||||
var/total = 0
|
||||
var/list/weights = list()
|
||||
for (var/obj/item/I in contents)
|
||||
if (I.reagents && I.reagents.total_volume)
|
||||
total += I.reagents.total_volume
|
||||
weights[I] = I.reagents.total_volume
|
||||
|
||||
if (total > 0)
|
||||
for (var/obj/item/I in contents)
|
||||
if (weights[I])
|
||||
holder.trans_to(I, weights[I] / total)
|
||||
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container/oven
|
||||
name = "oven dish"
|
||||
shortname = "shelf"
|
||||
desc = "Put ingredients in this; designed for use with an oven. Warranty void if used."
|
||||
icon_state = "ovendish"
|
||||
max_space = 30
|
||||
max_reagents = 120
|
||||
|
||||
/obj/item/weapon/reagent_containers/cooking_container/fryer
|
||||
name = "fryer basket"
|
||||
shortname = "basket"
|
||||
desc = "Put ingredients in this; designed for use with a deep fryer. Warranty void if used."
|
||||
icon_state = "basket"
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/machinery/cooker/fryer
|
||||
/obj/machinery/appliance/cooker/fryer
|
||||
name = "deep fryer"
|
||||
desc = "Deep fried <i>everything</i>."
|
||||
icon_state = "fryer_off"
|
||||
@@ -9,30 +9,157 @@
|
||||
food_color = "#FFAD33"
|
||||
cooked_sound = 'sound/machines/ding.ogg'
|
||||
var/datum/looping_sound/deep_fryer/fry_loop
|
||||
appliancetype = FRYER
|
||||
active_power_usage = 12 KILOWATTS
|
||||
|
||||
optimal_power = 0.35
|
||||
|
||||
idle_power_usage = 3.6 KILOWATTS
|
||||
// Power used to maintain temperature once it's heated.
|
||||
// Going with 25% of the active power. This is a somewhat arbitrary value.
|
||||
|
||||
/obj/machinery/cooker/fryer/Initialize()
|
||||
resistance = 20000 // Approx. 8-9 minutes to heat up.
|
||||
|
||||
max_contents = 2
|
||||
container_type = /obj/item/weapon/reagent_containers/cooking_container/fryer
|
||||
|
||||
stat = POWEROFF // Starts turned off
|
||||
|
||||
var/datum/reagents/oil
|
||||
var/optimal_oil = 9000 //90 litres of cooking oil
|
||||
|
||||
/obj/machinery/appliance/cooker/fryer/Initialize()
|
||||
. = ..()
|
||||
fry_loop = new(list(src), FALSE)
|
||||
return ..()
|
||||
|
||||
oil = new/datum/reagents(optimal_oil * 1.25, src)
|
||||
var/variance = rand()*0.15
|
||||
// Fryer is always a little below full, but its usually negligible
|
||||
|
||||
/obj/machinery/cooker/fryer/Destroy()
|
||||
if(prob(20))
|
||||
// Sometimes the fryer will start with much less than full oil, significantly impacting efficiency until filled
|
||||
variance = rand()*0.5
|
||||
oil.add_reagent("cornoil", optimal_oil*(1 - variance))
|
||||
|
||||
/obj/machinery/appliance/cooker/fryer/Destroy()
|
||||
QDEL_NULL(fry_loop)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/appliance/cooker/fryer/examine(var/mob/user)
|
||||
if (..())//no need to duplicate adjacency check
|
||||
to_chat(user, "Oil Level: [oil.total_volume]/[optimal_oil]")
|
||||
|
||||
/obj/machinery/appliance/cooker/fryer/heat_up()
|
||||
if (..())
|
||||
//Set temperature of oil reagent
|
||||
var/datum/reagent/nutriment/triglyceride/oil/OL = oil.get_master_reagent()
|
||||
if (OL && istype(OL))
|
||||
OL.data["temperature"] = temperature
|
||||
|
||||
/obj/machinery/cooker/fryer/set_cooking(new_setting)
|
||||
/obj/machinery/appliance/cooker/fryer/equalize_temperature()
|
||||
if (..())
|
||||
//Set temperature of oil reagent
|
||||
var/datum/reagent/nutriment/triglyceride/oil/OL = oil.get_master_reagent()
|
||||
if (OL && istype(OL))
|
||||
OL.data["temperature"] = temperature
|
||||
|
||||
/obj/machinery/appliance/cooker/fryer/set_cooking(new_setting)
|
||||
..()
|
||||
if(new_setting)
|
||||
fry_loop.start()
|
||||
else
|
||||
fry_loop.stop()
|
||||
|
||||
/obj/machinery/appliance/cooker/fryer/update_cooking_power()
|
||||
..()//In addition to parent temperature calculation
|
||||
//Fryer efficiency also drops when oil levels arent optimal
|
||||
var/oil_level = 0
|
||||
var/datum/reagent/nutriment/triglyceride/oil/OL = oil.get_master_reagent()
|
||||
if(OL && istype(OL))
|
||||
oil_level = OL.volume
|
||||
|
||||
/obj/machinery/cooker/fryer/cook_mob(var/mob/living/victim, var/mob/user)
|
||||
var/oil_efficiency = 0
|
||||
if(oil_level)
|
||||
oil_efficiency = oil_level / optimal_oil
|
||||
|
||||
if(oil_efficiency > 1)
|
||||
//We're above optimal, efficiency goes down as we pass too much over it
|
||||
oil_efficiency = 1 - (oil_efficiency - 1)
|
||||
|
||||
|
||||
cooking_power *= oil_efficiency
|
||||
|
||||
/obj/machinery/appliance/cooker/fryer/update_icon()
|
||||
if(cooking)
|
||||
icon_state = on_icon
|
||||
else
|
||||
icon_state = off_icon
|
||||
..()
|
||||
|
||||
//Fryer gradually infuses any cooked food with oil. Moar calories
|
||||
//This causes a slow drop in oil levels, encouraging refill after extended use
|
||||
/obj/machinery/appliance/cooker/fryer/do_cooking_tick(var/datum/cooking_item/CI)
|
||||
if(..() && (CI.oil < CI.max_oil) && prob(20))
|
||||
var/datum/reagents/buffer = new /datum/reagents(2)
|
||||
oil.trans_to_holder(buffer, min(0.5, CI.max_oil - CI.oil))
|
||||
CI.oil += buffer.total_volume
|
||||
CI.container.soak_reagent(buffer)
|
||||
|
||||
|
||||
//To solve any odd logic problems with results having oil as part of their compiletime ingredients.
|
||||
//Upon finishing a recipe the fryer will analyse any oils in the result, and replace them with our oil
|
||||
//As well as capping the total to the max oil
|
||||
/obj/machinery/appliance/cooker/fryer/finish_cooking(var/datum/cooking_item/CI)
|
||||
..()
|
||||
var/total_oil = 0
|
||||
var/total_our_oil = 0
|
||||
var/total_removed = 0
|
||||
var/datum/reagent/our_oil = oil.get_master_reagent()
|
||||
|
||||
for (var/obj/item/I in CI.container)
|
||||
if (I.reagents && I.reagents.total_volume)
|
||||
for (var/datum/reagent/R in I.reagents.reagent_list)
|
||||
if (istype(R, /datum/reagent/nutriment/triglyceride/oil))
|
||||
total_oil += R.volume
|
||||
if (R.id != our_oil.id)
|
||||
total_removed += R.volume
|
||||
I.reagents.remove_reagent(R.id, R.volume)
|
||||
else
|
||||
total_our_oil += R.volume
|
||||
|
||||
|
||||
if (total_removed > 0 || total_oil != CI.max_oil)
|
||||
total_oil = min(total_oil, CI.max_oil)
|
||||
|
||||
if (total_our_oil < total_oil)
|
||||
//If we have less than the combined total, then top up from our reservoir
|
||||
var/datum/reagents/buffer = new /datum/reagents(INFINITY)
|
||||
oil.trans_to_holder(buffer, total_oil - total_our_oil)
|
||||
CI.container.soak_reagent(buffer)
|
||||
else if (total_our_oil > total_oil)
|
||||
|
||||
//If we have more than the maximum allowed then we delete some.
|
||||
//This could only happen if one of the objects spawns with the same type of oil as ours
|
||||
var/portion = 1 - (total_oil / total_our_oil) //find the percentage to remove
|
||||
for (var/obj/item/I in CI.container)
|
||||
if (I.reagents && I.reagents.total_volume)
|
||||
for (var/datum/reagent/R in I.reagents.reagent_list)
|
||||
if (R.id == our_oil.id)
|
||||
I.reagents.remove_reagent(R.id, R.volume*portion)
|
||||
|
||||
/obj/machinery/appliance/cooker/fryer/cook_mob(var/mob/living/victim, var/mob/user)
|
||||
|
||||
if(!istype(victim))
|
||||
return
|
||||
|
||||
user.visible_message("<span class='danger'>\The [user] starts pushing \the [victim] into \the [src]!</span>")
|
||||
icon_state = on_icon
|
||||
cooking = 1
|
||||
// user.visible_message("<span class='danger'>\The [user] starts pushing \the [victim] into \the [src]!</span>")
|
||||
|
||||
//Removed delay on this action in favour of a cooldown after it
|
||||
//If you can lure someone close to the fryer and grab them then you deserve success.
|
||||
//And a delay on this kind of niche action just ensures it never happens
|
||||
//Cooldown ensures it can't be spammed to instakill someone
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN*3)
|
||||
|
||||
fry_loop.start()
|
||||
|
||||
if(!do_mob(user, victim, 20))
|
||||
@@ -48,38 +175,71 @@
|
||||
fry_loop.stop()
|
||||
return
|
||||
|
||||
var/damage = rand(7,13) // Though this damage seems reduced, some hot oil is transferred to the victim and will burn them for a while after
|
||||
|
||||
var/datum/reagent/nutriment/triglyceride/oil/OL = oil.get_master_reagent()
|
||||
damage *= OL.heatdamage(victim)
|
||||
|
||||
var/obj/item/organ/external/E
|
||||
var/nopain
|
||||
if(ishuman(victim) && user.zone_sel.selecting != "groin" && user.zone_sel.selecting != "chest")
|
||||
var/mob/living/carbon/human/H = victim
|
||||
if(H.species.flags & NO_PAIN)
|
||||
nopain = 2
|
||||
E = H.get_organ(user.zone_sel.selecting)
|
||||
if(E.robotic >= ORGAN_ROBOT)
|
||||
if(!E || E.species.flags & NO_PAIN)
|
||||
nopain = 2
|
||||
else if(E.robotic >= ORGAN_ROBOT)
|
||||
nopain = 1
|
||||
|
||||
user.visible_message("<span class='danger'>\The [user] shoves \the [victim][E ? "'s [E.name]" : ""] into \the [src]!</span>")
|
||||
if (damage > 0)
|
||||
if(E)
|
||||
if(E.children && E.children.len)
|
||||
for(var/obj/item/organ/external/child in E.children)
|
||||
if(nopain && nopain < 2 && !(child.robotic >= ORGAN_ROBOT))
|
||||
nopain = 0
|
||||
child.take_damage(0, damage)
|
||||
damage -= (damage*0.5)//IF someone's arm is plunged in, the hand should take most of it
|
||||
E.take_damage(0, damage)
|
||||
else
|
||||
victim.apply_damage(damage, BURN, user.zone_sel.selecting)
|
||||
|
||||
if(E)
|
||||
E.take_damage(0, rand(20,30))
|
||||
if(E.children && E.children.len)
|
||||
for(var/obj/item/organ/external/child in E.children)
|
||||
if(nopain && nopain < 2 && !(child.robotic >= ORGAN_ROBOT))
|
||||
nopain = 0
|
||||
child.take_damage(0, rand(20,30))
|
||||
else
|
||||
victim.apply_damage(rand(30,40), BURN, user.zone_sel.selecting)
|
||||
if(!nopain)
|
||||
victim << "<span class='danger'>Agony consumes you as searing hot oil scorches your [E ? E.name : "flesh"] horribly!</span>"
|
||||
victim.emote("scream")
|
||||
else
|
||||
victim << "<span class='danger'>Searing hot oil scorches your [E ? E.name : "flesh"]!</span>"
|
||||
|
||||
if(!nopain)
|
||||
to_chat(victim, "<span class='danger'>Agony consumes you as searing hot oil scorches your [E ? E.name : "flesh"] horribly!</span>")
|
||||
victim.emote("scream")
|
||||
else
|
||||
to_chat(victim, "<span class='danger'>Searing hot oil scorches your [E ? E.name : "flesh"]!</span>")
|
||||
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Has [cook_type] \the [victim] ([victim.ckey]) in \a [src]</font>")
|
||||
victim.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been [cook_type] in \a [src] by [user.name] ([user.ckey])</font>")
|
||||
msg_admin_attack("[key_name_admin(user)] [cook_type] \the [victim] ([victim.ckey]) in \a [src]. (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)",ckey=key_name(user),ckey_target=key_name(victim))
|
||||
|
||||
if(victim.client)
|
||||
add_attack_logs(user,victim,"[cook_type] in [src]")
|
||||
|
||||
icon_state = off_icon
|
||||
cooking = 0
|
||||
//Coat the victim in some oil
|
||||
oil.trans_to(victim, 40)
|
||||
|
||||
fry_loop.stop()
|
||||
return
|
||||
|
||||
/obj/machinery/appliance/cooker/fryer/attackby(var/obj/item/I, var/mob/user)
|
||||
if(istype(I, /obj/item/weapon/reagent_containers/glass) && I.reagents)
|
||||
if (I.reagents.total_volume <= 0 && oil)
|
||||
//Its empty, handle scooping some hot oil out of the fryer
|
||||
oil.trans_to(I, I.reagents.maximum_volume)
|
||||
user.visible_message("[user] scoops some oil out of \the [src].", span("notice","You scoop some oil out of \the [src]."))
|
||||
return 1
|
||||
else
|
||||
//It contains stuff, handle pouring any oil into the fryer
|
||||
//Possibly in future allow pouring non-oil reagents in, in order to sabotage it and poison food.
|
||||
//That would really require coding some sort of filter or better replacement mechanism first
|
||||
//So for now, restrict to oil only
|
||||
var/amount = 0
|
||||
for (var/datum/reagent/R in I.reagents.reagent_list)
|
||||
if (istype(R, /datum/reagent/nutriment/triglyceride/oil))
|
||||
var/delta = oil.get_free_space()
|
||||
delta = min(delta, R.volume)
|
||||
oil.add_reagent(R.id, delta)
|
||||
I.reagents.remove_reagent(R.id, delta)
|
||||
amount += delta
|
||||
if (amount > 0)
|
||||
user.visible_message("[user] pours some oil into \the [src].", span("notice","You pour [amount]u of oil into \the [src]."), "<span class='notice'>You hear something viscous being poured into a metal container.</span>")
|
||||
return 1
|
||||
//If neither of the above returned, then call parent as normal
|
||||
..()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/obj/machinery/cooker/grill
|
||||
name = "grill"
|
||||
desc = "Backyard grilling, IN SPACE."
|
||||
icon_state = "grill_off"
|
||||
cook_type = "grilled"
|
||||
cook_time = 100
|
||||
food_color = "#A34719"
|
||||
on_icon = "grill_on"
|
||||
off_icon = "grill_off"
|
||||
/obj/machinery/appliance/cooker/grill
|
||||
name = "grill"
|
||||
desc = "Backyard grilling, IN SPACE."
|
||||
icon_state = "grill_off"
|
||||
cook_type = "grilled"
|
||||
cook_time = 100
|
||||
food_color = "#A34719"
|
||||
on_icon = "grill_on"
|
||||
off_icon = "grill_off"
|
||||
can_burn_food = 1
|
||||
@@ -1,23 +1,23 @@
|
||||
/obj/machinery/cooker/oven
|
||||
name = "oven"
|
||||
desc = "Cookies are ready, dear."
|
||||
icon = 'icons/obj/cooking_machines.dmi'
|
||||
icon_state = "oven_off"
|
||||
on_icon = "oven_on"
|
||||
off_icon = "oven_off"
|
||||
cook_type = "baked"
|
||||
cook_time = 300
|
||||
food_color = "#A34719"
|
||||
can_burn_food = 1
|
||||
|
||||
output_options = list(
|
||||
"Personal Pizza" = /obj/item/weapon/reagent_containers/food/snacks/variable/pizza,
|
||||
"Bread" = /obj/item/weapon/reagent_containers/food/snacks/variable/bread,
|
||||
"Pie" = /obj/item/weapon/reagent_containers/food/snacks/variable/pie,
|
||||
"Small Cake" = /obj/item/weapon/reagent_containers/food/snacks/variable/cake,
|
||||
"Hot Pocket" = /obj/item/weapon/reagent_containers/food/snacks/variable/pocket,
|
||||
"Kebab" = /obj/item/weapon/reagent_containers/food/snacks/variable/kebab,
|
||||
"Waffles" = /obj/item/weapon/reagent_containers/food/snacks/variable/waffles,
|
||||
"Cookie" = /obj/item/weapon/reagent_containers/food/snacks/variable/cookie,
|
||||
"Donut" = /obj/item/weapon/reagent_containers/food/snacks/variable/donut,
|
||||
/obj/machinery/appliance/cooker/oven
|
||||
name = "oven"
|
||||
desc = "Cookies are ready, dear."
|
||||
icon = 'icons/obj/cooking_machines.dmi'
|
||||
icon_state = "oven_off"
|
||||
on_icon = "oven_on"
|
||||
off_icon = "oven_off"
|
||||
cook_type = "baked"
|
||||
cook_time = 300
|
||||
food_color = "#A34719"
|
||||
can_burn_food = 1
|
||||
|
||||
output_options = list(
|
||||
"Personal Pizza" = /obj/item/weapon/reagent_containers/food/snacks/variable/pizza,
|
||||
"Bread" = /obj/item/weapon/reagent_containers/food/snacks/variable/bread,
|
||||
"Pie" = /obj/item/weapon/reagent_containers/food/snacks/variable/pie,
|
||||
"Small Cake" = /obj/item/weapon/reagent_containers/food/snacks/variable/cake,
|
||||
"Hot Pocket" = /obj/item/weapon/reagent_containers/food/snacks/variable/pocket,
|
||||
"Kebab" = /obj/item/weapon/reagent_containers/food/snacks/variable/kebab,
|
||||
"Waffles" = /obj/item/weapon/reagent_containers/food/snacks/variable/waffles,
|
||||
"Cookie" = /obj/item/weapon/reagent_containers/food/snacks/variable/cookie,
|
||||
"Donut" = /obj/item/weapon/reagent_containers/food/snacks/variable/donut,
|
||||
)
|
||||
Reference in New Issue
Block a user