// 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/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 = TRUE anchored = TRUE 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/cooking_power = 0 // Effectiveness/speed at cooking var/cooking_coeff = 0 // Optimal power * proximity to optimal temp; used to calc. cooking power. var/heating_power = 1000 // Effectiveness at heating up; not used for mixers, should be equal to active_power_usage 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 = FALSE // 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 = FALSE // 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/appliance_available_recipes = list() var/container_type = null var/combine_first = FALSE // If TRUE, this appliance will do combination cooking before checking recipes var/food_safety = FALSE // If true, the appliance automatically ejects food instead of burning it var/static/radial_eject = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_eject") var/static/radial_power = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_power") var/static/radial_safety = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_safety") var/static/radial_output = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_change_output") /obj/machinery/appliance/Initialize(mapload) . = ..() default_apply_parts() if(output_options.len) verbs += /obj/machinery/appliance/proc/choose_output if(!LAZYLEN(appliance_available_recipes)) for(var/datum/recipe/test as anything in subtypesof(/datum/recipe)) if((appliancetype & initial(test.appliance))) appliance_available_recipes += new test /obj/machinery/appliance/Destroy() for(var/datum/cooking_item/CI as anything in cooking_objs) 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(user)) . += list_contents(user) /obj/machinery/appliance/proc/list_contents(var/mob/user) if (cooking_objs.len) var/string = "Contains..." for(var/datum/cooking_item/CI as anything in cooking_objs) string += "-\a [CI.container.label(null, CI.combine_target)], [report_progress(CI)]
" return string else to_chat(user, span_notice("It is empty.")) /obj/machinery/appliance/proc/report_progress_tgui(datum/cooking_item/CI) if(!CI || !CI.max_cookwork) return list("average", "Not Cooking.") if(!CI.cookwork) return list("blue", "Cold.") var/progress = CI.cookwork / CI.max_cookwork if (progress < 0.25) return list("blue", "It's barely started cooking.") if (progress < 0.75) return list("average", "It's cooking away nicely.") if (progress < 1) return list("good", "It's almost ready!") var/half_overcook = (CI.overcook_mult - 1)*0.5 if (progress < 1+half_overcook) return list("good", "It's done!") if (progress < CI.overcook_mult) return list("bad", "It looks overcooked, get it out!") else return list("bad", "It is burning!") /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_boldnotice("It's almost ready!") var/half_overcook = (CI.overcook_mult - 1)*0.5 if (progress < 1+half_overcook) return span_soghun(span_bold("It is done!")) 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()) to_chat(user, span_warning("You lack the dexterity to do that!")) return if (user.stat || user.restrained() || user.incapacitated()) return if (!Adjacent(user) && !issilicon(user)) to_chat(user, span_warning("You can't reach [src] from here!")) return if (stat & POWEROFF)//Its turned off stat &= ~POWEROFF use_power = 1 user.visible_message(span_filter_notice("[user] turns [src] on."), span_filter_notice("You turn on [src].")) else //Its on, turn it off stat |= POWEROFF use_power = 0 user.visible_message(span_filter_notice("[user] turns [src] off."), span_filter_notice("You turn off [src].")) cooking = FALSE // Stop cooking here, too, just in case. playsound(src, 'sound/machines/click.ogg', 40, 1) update_icon() /obj/machinery/appliance/ctrl_click_ai(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()) to_chat(usr, span_filter_notice("You lack the dexterity to do that!")) return if (usr.stat || usr.restrained() || usr.incapacitated()) return if (!Adjacent(usr) && !issilicon(usr)) to_chat(usr, span_filter_notice("You can't adjust the [src] from this distance, get closer!")) return if(output_options.len) var/choice = tgui_input_list(usr, "What specific food do you wish to make with \the [src]?", "Food Output Choice", output_options+"Default") if(!choice) return if(choice == "Default") selected_option = null to_chat(usr, span_notice("You decide not to make anything specific with \the [src].")) else selected_option = choice to_chat(usr, span_notice("You prepare \the [src] to make \a [selected_option] with the next thing you put in. Try putting several ingredients in a container!")) //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/grab/G = I if(istype(G)) if(!can_cook_mobs) to_chat(user, span_warning("That's not going to fit.")) return 0 if(!isliving(G.affecting)) to_chat(user, span_warning("You can't cook that.")) return 0 return 2 if (!has_space(I)) to_chat(user, span_warning("There's no room in [src] for that!")) 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/reagent_containers/food/snacks/check = I if(istype(check) && islist(check.cooked) && (cook_type in check.cooked)) to_chat(user, span_warning("\The [check] has already been [cook_type].")) return 0 else if(istype(check, /obj/item/reagent_containers/glass)) to_chat(user, span_warning("That would probably break [src].")) return 0 else if(istype(check, /obj/item/disk/nuclear)) to_chat(user, span_warning("You can't cook that.")) return 0 else if(I.has_tool_quality(TOOL_CROWBAR) || I.has_tool_quality(TOOL_SCREWDRIVER) || istype(I, /obj/item/storage/part_replacer)) // You can't cook tools, dummy. return 0 else if(!istype(check) && !istype(check, /obj/item/holder)) to_chat(user, span_warning("That's not edible.")) 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 FALSE return TRUE /obj/machinery/appliance/attackby(var/obj/item/I, var/mob/user) if(!cook_type || (stat & (BROKEN))) to_chat(user, span_warning("\The [src] is not working.")) return FALSE var/obj/item/ToCook = I if(istype(I, /obj/item/gripper)) var/obj/item/gripper/GR = I var/obj/item/wrap = GR.get_current_pocket() if(wrap) wrap.loc = get_turf(src) var/result = can_insert(wrap, user) if(!result) wrap.forceMove(GR) if(!(default_deconstruction_screwdriver(user, I))) default_part_replacement(user, I) return if(QDELETED(wrap)) GR.update_ref(null) if(wrap.loc != src) GR.drop_item_nm() ToCook = wrap else attack_hand(user) return else var/result = can_insert(I, user) if(!result) if(!(default_deconstruction_screwdriver(user, I))) default_part_replacement(user, I) return if(result == 2) var/obj/item/grab/G = I if (G && istype(G) && G.affecting) cook_mob(G.affecting, user) return //From here we can start cooking food add_content(ToCook, user) update_icon() //Override for container mechanics /obj/machinery/appliance/proc/add_content(var/obj/item/I, var/mob/user) if(!user.unEquip(I) && !isturf(I.loc)) return var/datum/cooking_item/CI = has_space(I) if (istype(I, /obj/item/reagent_containers/cooking_container) && CI == 1) var/obj/item/reagent_containers/cooking_container/CC = I CI = new /datum/cooking_item/(CC) I.forceMove(src) cooking_objs.Add(CI) user.visible_message(span_infoplain(span_bold("\The [user]") + " puts \the [I] into \the [src].")) if (CC.check_contents() == 0)//If we're just putting an empty container in, then dont start any processing. return TRUE else if (CI && istype(CI)) I.forceMove(CI.container) else //Something went wrong return FALSE if (selected_option) CI.combine_target = selected_option // We can actually start cooking now. user.visible_message(span_infoplain(span_bold("\The [user]") + " puts \the [I] into \the [src].")) get_cooking_work(CI) cooking = TRUE return CI /obj/machinery/appliance/proc/get_cooking_work(var/datum/cooking_item/CI) for (var/obj/item/J in CI.container) cookwork_by_item(J, CI) for(var/datum/reagent/R as anything in CI.container.reagents.reagent_list) 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 = 0.35 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/cookwork_by_item(var/obj/item/I, var/datum/cooking_item/CI) var/obj/item/reagent_containers/food/snacks/S = I var/work = 0 if (istype(S)) if (S.reagents) for(var/datum/reagent/R as anything in S.reagents.reagent_list) 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/holder)) var/obj/item/holder/H = I if (H.held_mob) work += ((H.held_mob.mob_size * H.held_mob.size_multiplier) * (H.held_mob.mob_size * H.held_mob.size_multiplier) * 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 FALSE var/was_done = FALSE if (CI.cookwork >= CI.max_cookwork) was_done = TRUE 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 > min(CI.max_cookwork * CI.overcook_mult, CI.max_cookwork + 30)) if(!food_safety) burn_food(CI) else eject(CI, null) // Gotta hurt. for(var/obj/item/holder/H in CI.container.contents) var/mob/living/M = H.held_mob if(M) M.apply_damage(rand(1,3) * (1/M.size_multiplier), mobdamagetype, pick(BP_ALL)) return TRUE /obj/machinery/appliance/process() if(cooking_power > 0 && cooking) var/all_done_cooking = TRUE for(var/datum/cooking_item/CI in cooking_objs) do_cooking_tick(CI) if(CI.max_cookwork > 0) all_done_cooking = FALSE if(all_done_cooking) cooking = FALSE update_icon() /obj/machinery/appliance/proc/predict_cooking(datum/cooking_item/CI) var/datum/recipe/recipe = null var/atom/C = null if(CI.container) C = CI.container else C = src recipe = select_recipe(appliance_available_recipes, C) var/list/results = list() if(recipe) var/obj/O = recipe.result results += initial(O.name) else if(CI.combine_target) results += predict_combination(CI) else for(var/obj/item/I in CI.container) results += predict_modification(I, CI) return jointext(results, ", ") /obj/machinery/appliance/proc/predict_combination(datum/cooking_item/CI) var/obj/cook_path = output_options[CI.combine_target] var/list/words = list() var/list/cooktypes = list() for(var/obj/item/reagent_containers/food/snacks/S in CI.container) words |= splittext(S.name, " ") cooktypes |= S.cooked //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 var/name = initial(cook_path.name) words.Remove(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 name = "[pop(words)] [name]" return name /obj/machinery/appliance/proc/predict_modification(obj/item/input, datum/cooking_item/CI) return "[cook_type] [input.name]" /obj/machinery/appliance/proc/finish_cooking(var/datum/cooking_item/CI) src.visible_message(span_infoplain(span_bold("\The [src]") + " pings!")) 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(appliance_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(appliance_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/obj/item/reagent_containers/food/snacks/R as anything in results) 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/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 var/reagents_determine_color if(!LAZYLEN(CI.container.contents)) // It's possible to make something, such as a cake in the oven, with only reagents. This stops them from being grey and sad. reagents_determine_color = TRUE for (var/obj/item/I in CI.container) var/obj/item/reagent_containers/food/snacks/S if (istype(I, /obj/item/holder)) S = create_mob_food(I, CI) else if (istype(I, /obj/item/reagent_containers/food/snacks)) S = I if (!S) continue words |= splittext(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/reagent_containers/food/snacks/result = new cook_path(CI.container) buffer.trans_to_holder(result.reagents, buffer.total_volume) //trans_to doesn't handle food items well, so //just call trans_to_holder instead // Reagent-only foods. if(reagents_determine_color) totalcolour = result.reagents.get_color() for(var/datum/reagent/reag in result.reagents.reagent_list) words |= text2list(reag.name, " ") //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/reagent_containers/food/snacks/result if (istype(input, /obj/item/holder)) result = create_mob_food(input, CI) else if (istype(input, /obj/item/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/reagent_containers/food/snacks/badrecipe(CI.container) // Produce nasty smoke. visible_message(span_danger("\The [src] vomits a gout of rancid smoke!")) var/datum/effect/effect/system/smoke_spread/bad/burntfood/smoke = new /datum/effect/effect/system/smoke_spread/bad/burntfood playsound(src, 'sound/effects/smoke.ogg', 20, 1) smoke.attach(src) smoke.set_up(10, 0, get_turf(src), 300) smoke.start() // CHOMPAdd - Chance to make a terrible fire if(prob(70)) var/turf/T = get_turf(src) T.lingering_fire(0.45) // CHOMPAdd End // Set off fire alarms! var/obj/machinery/firealarm/FA = locate() in get_area(src) if(FA) FA.alarm() /obj/machinery/appliance/attack_hand(var/mob/user) if(..()) return interact(user) /obj/machinery/appliance/interact(mob/user) var/list/options = list( "power" = radial_power, "safety" = radial_safety, ) if(LAZYLEN(cooking_objs)) options["remove"] = radial_eject if(LAZYLEN(output_options)) options["select_output"] = radial_output var/choice = show_radial_menu(user, src, options, require_near = !issilicon(user)) switch(choice) if("power") toggle_power() if("safety") toggle_safety() if("remove") removal_menu(user) if("select_output") choose_output() /obj/machinery/appliance/proc/removal_menu(var/mob/user) if (can_remove_items(user)) var/list/menuoptions = list() for(var/datum/cooking_item/CI as anything in cooking_objs) if (CI.container) menuoptions[CI.container.label(menuoptions.len)] = CI var/selection = tgui_input_list(user, "Which item would you like to remove?", "Remove ingredients", menuoptions) if (selection) var/datum/cooking_item/CI = menuoptions[selection] eject(CI, user) update_icon() return TRUE return FALSE /obj/machinery/appliance/proc/can_remove_items(var/mob/user, show_warning = TRUE) if (!Adjacent(user)) return FALSE if (isanimal(user)) return FALSE return TRUE /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) if(!user.put_in_hands(thing)) thing.forceMove(get_turf(src)) else if(istype(thing, /obj/item/reagent_containers/cooking_container)) var/obj/item/reagent_containers/cooking_container/cc = thing cc.do_empty() delete = 0 else 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 if(user) user.visible_message(span_notice("\The [user] remove \the [thing] from \the [src].")) else src.visible_message(span_infoplain(span_bold("\The [src]") + " pings as it automatically ejects its contents!")) if(cooked_sound) playsound(get_turf(src), cooked_sound, 50, 1) /obj/machinery/appliance/proc/cook_mob(var/mob/living/victim, var/mob/user) return /obj/machinery/appliance/proc/change_product_strings(var/obj/item/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/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 = REAGENT_ID_IRON else if(istype(src, /mob/living/carbon/human/diona) || istype(src, /mob/living/carbon/alien/diona)) src.composition_reagent = REAGENT_ID_NUTRIMENT // diona are plants, not meat else src.composition_reagent = REAGENT_ID_PROTEIN if(ishuman(src)) var/mob/living/carbon/human/H = src if(istype(H.species, /datum/species/diona)) src.composition_reagent = REAGENT_ID_NUTRIMENT //if the mob is a simple animal - MOB NOT ANIMAL - with a defined meat quantity if (isanimal(src)) var/mob/living/simple_mob/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/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/reagent_containers/food/snacks/variable/mob/result = new /obj/item/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_mob/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 = 6 // How long it takes to overcook. This is max_cookwork x overcook mult. If you're changing this, mind that at 3x, a max_cookwork of 30 becomes 90 ticks for the purpose of burning, and a max_cookwork of 4 only has 12 before burning! // CHOMPedit: doubled to 6 var/result_type = 0 var/obj/item/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/stock_parts/P in src.component_parts) if(istype(P, /obj/item/stock_parts/scanning_module)) scan_rating += P.rating - 1 // Default parts shouldn't mess with stats // to_world("RefreshParts returned scan rating of [scan_rating] during this step.") // Debug lines, uncomment if you need to test. else if(istype(P, /obj/item/stock_parts/capacitor)) cap_rating += P.rating - 1 // Default parts shouldn't mess with stats // to_world("RefreshParts returned cap rating of [cap_rating] during this step.") // Debug lines, uncomment if you need to test. active_power_usage = initial(active_power_usage) - scan_rating * 25 heating_power = initial(heating_power) + cap_rating * 25 cooking_power = cooking_coeff * (1 + (scan_rating + cap_rating) / 20) // 100% eff. becomes 120%, 140%, 160% w/ better parts, thus rewarding upgrading the appliances during your shift. // to_world("RefreshParts returned cooking power of [cooking_power] during this step.") // Debug lines, uncomment if you need to test. /obj/machinery/appliance/verb/toggle_safety() set name = "Toggle Safety" set desc = "Toggles whether the appliance automatically ejects food when it starts to burn." set category = "Object" set src in view(1) if(!isliving(usr)) return food_safety = !food_safety to_chat(usr, span_notice("You flip \the [src]'s safe mode switch. Safe mode is now [food_safety ? "on" : "off"]."))