diff --git a/code/game/gamemodes/cult/cultify/obj.dm b/code/game/gamemodes/cult/cultify/obj.dm
index 83dfc857be..d7c0cff5ec 100644
--- a/code/game/gamemodes/cult/cultify/obj.dm
+++ b/code/game/gamemodes/cult/cultify/obj.dm
@@ -50,7 +50,7 @@
src.invisibility = INVISIBILITY_MAXIMUM
density = 0
-/obj/machinery/cooking/cultify()
+/obj/machinery/cooker/cultify()
new /obj/structure/cult/talisman(loc)
qdel(src)
diff --git a/code/game/machinery/kitchen/cooking_machines/_cooker.dm b/code/game/machinery/kitchen/cooking_machines/_cooker.dm
new file mode 100644
index 0000000000..d874c1f9d5
--- /dev/null
+++ b/code/game/machinery/kitchen/cooking_machines/_cooker.dm
@@ -0,0 +1,233 @@
+// 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/list/cooked
+
+// 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 = 1
+ idle_power_usage = 5
+
+ 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/examine()
+ ..()
+ if(cooking_obj && Adjacent(usr))
+ usr << "You can see \a [cooking_obj] inside."
+
+/obj/machinery/cooker/attackby(var/obj/item/I, var/mob/user)
+
+ if(!cook_type || (stat & (NOPOWER|BROKEN)))
+ user << "\The [src] is not working."
+ return
+
+ if(cooking)
+ user << "\The [src] is running!"
+ return
+
+ // We are trying to cook a grabbed mob.
+ var/obj/item/weapon/grab/G = I
+ if(istype(G))
+
+ if(!can_cook_mobs)
+ user << "That's not going to fit."
+ return
+
+ if(!isliving(G.affecting))
+ user << "You can't cook that."
+ 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))
+ user << "\The [check] has already been [cook_type]."
+ return 0
+ else if(istype(check, /obj/item/weapon/reagent_containers/glass))
+ user << "That would probably break [src]."
+ return 0
+ else if(istype(check, /obj/item/weapon/disk/nuclear))
+ user << "Central Command would kill you if you [cook_type] that."
+ return 0
+ else if(!istype(check) && !istype(check, /obj/item/weapon/holder))
+ user << "That's not edible."
+ return 0
+
+ // 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.
+ if(!user.unEquip(I))
+ return
+
+ // We can actually start cooking now.
+ user.visible_message("\The [user] puts \the [I] into \the [src].")
+ cooking_obj = I
+ cooking_obj.forceMove(src)
+ cooking = 1
+ 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
+ cooking = 0
+ 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()
+
+ // 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.
+
+ if(cooking_obj.reagents && cooking_obj.reagents.total_volume)
+ cooking_obj.reagents.trans_to(result, cooking_obj.reagents.total_volume)
+
+ // Set icon and appearance.
+ change_product_appearance(result)
+
+ // Update strings.
+ change_product_strings(result)
+
+ // 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()
+ else
+ result.cooked = list()
+ result.cooked |= cook_type
+
+ // Reset relevant variables.
+ qdel(cooking_obj)
+ src.visible_message("\The [src] pings!")
+ if(cooked_sound)
+ playsound(get_turf(src), cooked_sound, 50, 1)
+
+ if(!can_burn_food)
+ icon_state = off_icon
+ cooking = 0
+ result.forceMove(get_turf(src))
+ cooking_obj = null
+ else
+ var/failed
+ var/overcook_period = max(Floor(cook_time/5),1)
+ cooking_obj = result
+ while(1)
+ sleep(overcook_period)
+ if(!cooking || !result || result.loc != src)
+ failed = 1
+ else if(prob(burn_chance))
+ // You dun goofed.
+ qdel(cooking_obj)
+ cooking_obj = new /obj/item/weapon/reagent_containers/food/snacks/badrecipe(src)
+ // Produce nasty smoke.
+ visible_message("\The [src] vomits a gout of rancid smoke!")
+ var/datum/effect/effect/system/smoke_spread/bad/smoke = PoolOrNew(/datum/effect/effect/system/smoke_spread/bad)
+ smoke.attach(src)
+ smoke.set_up(10, 0, usr.loc)
+ smoke.start()
+ failed = 1
+
+ if(failed)
+ cooking = 0
+ icon_state = off_icon
+ break
+
+/obj/machinery/cooker/attack_hand(var/mob/user)
+
+ if(cooking_obj)
+ user << "You grab \the [cooking_obj] from \the [src]."
+ user.put_in_hands(cooking_obj)
+ cooking = 0
+ cooking_obj = null
+ icon_state = off_icon
+ return
+
+ if(output_options.len)
+
+ if(cooking)
+ user << "\The [src] is in use!"
+ 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
+ user << "You decide not to make anything specific with \the [src]."
+ else
+ selected_option = choice
+ user << "You prepare \the [src] to make \a [selected_option]."
+
+ ..()
+
+/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]."
+ else
+ product.name = "[cooking_obj.name] [product.name]"
+
+/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
+
+ // 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
+ 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
+
diff --git a/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm b/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm
new file mode 100644
index 0000000000..cb4dcd15ed
--- /dev/null
+++ b/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm
@@ -0,0 +1,72 @@
+// 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"
diff --git a/code/game/machinery/kitchen/cooking_machines/candy.dm b/code/game/machinery/kitchen/cooking_machines/candy.dm
new file mode 100644
index 0000000000..21fd506911
--- /dev/null
+++ b/code/game/machinery/kitchen/cooking_machines/candy.dm
@@ -0,0 +1,18 @@
+/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)
+ . = ..()
diff --git a/code/game/machinery/kitchen/cooking_machines/cereal.dm b/code/game/machinery/kitchen/cooking_machines/cereal.dm
new file mode 100644
index 0000000000..3a7b19c9b1
--- /dev/null
+++ b/code/game/machinery/kitchen/cooking_machines/cereal.dm
@@ -0,0 +1,25 @@
+/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
+
diff --git a/code/game/machinery/kitchen/cooking_machines/fryer.dm b/code/game/machinery/kitchen/cooking_machines/fryer.dm
new file mode 100644
index 0000000000..1fc0e75ef1
--- /dev/null
+++ b/code/game/machinery/kitchen/cooking_machines/fryer.dm
@@ -0,0 +1,67 @@
+/obj/machinery/cooker/fryer
+ name = "deep fryer"
+ desc = "Deep fried everything."
+ icon_state = "fryer_off"
+ can_cook_mobs = 1
+ cook_type = "deep fried"
+ on_icon = "fryer_on"
+ off_icon = "fryer_off"
+ food_color = "#FFAD33"
+ cooked_sound = 'sound/machines/ding.ogg'
+
+/obj/machinery/cooker/fryer/cook_mob(var/mob/living/victim, var/mob/user)
+
+ if(!istype(victim))
+ return
+
+ user.visible_message("\The [user] starts pushing \the [victim] into \the [src]!")
+ icon_state = on_icon
+ cooking = 1
+
+ if(!do_mob(user, victim, 20))
+ cooking = 0
+ icon_state = off_icon
+ return
+
+ if(!victim || !victim.Adjacent(user))
+ user << "Your victim slipped free!"
+ cooking = 0
+ icon_state = off_icon
+ return
+
+ 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.status & ORGAN_ROBOT)
+ nopain = 1
+
+ user.visible_message("\The [user] shoves \the [victim][E ? "'s [E.name]" : ""] into \the [src]!")
+
+ 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.status & 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 << "Agony consumes you as searing hot oil scorches your [E ? E.name : "flesh"] horribly!"
+ victim.emote("scream")
+ else
+ victim << "Searing hot oil scorches your [E ? E.name : "flesh"]!"
+
+ if(victim.client)
+ user.attack_log += text("\[[time_stamp()]\] Has [cook_type] \the [victim] ([victim.ckey]) in \a [src]")
+ victim.attack_log += text("\[[time_stamp()]\] Has been [cook_type] in \a [src] by [user.name] ([user.ckey])")
+ msg_admin_attack("[user] ([user.ckey]) [cook_type] \the [victim] ([victim.ckey]) in \a [src]. (JMP)")
+
+ icon_state = off_icon
+ cooking = 0
+ return
diff --git a/code/game/machinery/kitchen/cooking_machines/grill.dm b/code/game/machinery/kitchen/cooking_machines/grill.dm
new file mode 100644
index 0000000000..312189c588
--- /dev/null
+++ b/code/game/machinery/kitchen/cooking_machines/grill.dm
@@ -0,0 +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"
+ can_burn_food = 1
\ No newline at end of file
diff --git a/code/game/machinery/kitchen/cooking_machines/oven.dm b/code/game/machinery/kitchen/cooking_machines/oven.dm
new file mode 100644
index 0000000000..ec941af223
--- /dev/null
+++ b/code/game/machinery/kitchen/cooking_machines/oven.dm
@@ -0,0 +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,
+ )
\ No newline at end of file
diff --git a/code/game/machinery/kitchen/icecream.dm b/code/game/machinery/kitchen/icecream.dm
new file mode 100644
index 0000000000..448b252fd4
--- /dev/null
+++ b/code/game/machinery/kitchen/icecream.dm
@@ -0,0 +1,196 @@
+#define ICECREAM_VANILLA 1
+#define ICECREAM_CHOCOLATE 2
+#define ICECREAM_STRAWBERRY 3
+#define ICECREAM_BLUE 4
+#define CONE_WAFFLE 5
+#define CONE_CHOC 6
+
+// Ported wholesale from Apollo Station.
+
+/obj/machinery/icecream_vat
+ name = "icecream vat"
+ desc = "Ding-aling ding dong. Get your NanoTrasen-approved ice cream!"
+ icon = 'icons/obj/kitchen.dmi'
+ icon_state = "icecream_vat"
+ density = 1
+ anchored = 0
+ use_power = 0
+ flags = OPENCONTAINER | NOREACT
+
+ var/list/product_types = list()
+ var/dispense_flavour = ICECREAM_VANILLA
+ var/flavour_name = "vanilla"
+
+/obj/machinery/icecream_vat/proc/get_ingredient_list(var/type)
+ switch(type)
+ if(ICECREAM_CHOCOLATE)
+ return list("milk", "ice", "coco")
+ if(ICECREAM_STRAWBERRY)
+ return list("milk", "ice", "berryjuice")
+ if(ICECREAM_BLUE)
+ return list("milk", "ice", "singulo")
+ if(CONE_WAFFLE)
+ return list("flour", "sugar")
+ if(CONE_CHOC)
+ return list("flour", "sugar", "coco")
+ else
+ return list("milk", "ice")
+
+/obj/machinery/icecream_vat/proc/get_flavour_name(var/flavour_type)
+ switch(flavour_type)
+ if(ICECREAM_CHOCOLATE)
+ return "chocolate"
+ if(ICECREAM_STRAWBERRY)
+ return "strawberry"
+ if(ICECREAM_BLUE)
+ return "blue"
+ if(CONE_WAFFLE)
+ return "waffle"
+ if(CONE_CHOC)
+ return "chocolate"
+ else
+ return "vanilla"
+
+/obj/machinery/icecream_vat/initialize()
+ ..()
+ create_reagents(100)
+ while(product_types.len < 6)
+ product_types.Add(5)
+ reagents.add_reagent("milk", 5)
+ reagents.add_reagent("flour", 5)
+ reagents.add_reagent("sugar", 5)
+ reagents.add_reagent("ice", 5)
+
+/obj/machinery/icecream_vat/attack_hand(mob/user as mob)
+ user.set_machine(src)
+ interact(user)
+
+/obj/machinery/icecream_vat/interact(mob/user as mob)
+ var/dat
+ dat += "ICECREAM