From 6f3befe233a1c1b718e2e6eae979312703d9d451 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sat, 8 Apr 2023 19:30:41 +0200 Subject: [PATCH] [MIRROR] Reagent soup / Soup rework / Stoves - A kitchen expansion [MDB IGNORE] (#20410) * Reagent soup / Soup rework / Stoves - A kitchen expansion * fixes that stuff * puts the range stove on maps that sohuld have it * fixes some paths that don't exist anymore --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Paxilmaniac --- ...cemoon_underground_abandoned_homestead.dmm | 5 +- .../LavaRuins/lavaland_biodome_beach.dmm | 2 +- .../SpaceRuins/DJstation/kitchen_4.dmm | 2 +- _maps/RandomRuins/SpaceRuins/deepstorage.dmm | 2 +- _maps/RandomRuins/SpaceRuins/oldstation.dmm | 2 +- _maps/RandomRuins/SpaceRuins/spacehotel.dmm | 2 +- _maps/RandomRuins/SpaceRuins/waystation.dmm | 2 +- _maps/RandomZLevels/SnowCabin.dmm | 3 +- _maps/RandomZLevels/TheBeach.dmm | 2 +- _maps/RandomZLevels/undergroundoutpost45.dmm | 2 +- .../map_files/Deltastation/DeltaStation2.dmm | 4 +- .../map_files/IceBoxStation/IceBoxStation.dmm | 15 +- _maps/map_files/KiloStation/KiloStation.dmm | 6 +- _maps/map_files/MetaStation/MetaStation.dmm | 2 +- _maps/map_files/VoidRaptor/VoidRaptor.dmm | 2 +- _maps/map_files/generic/CentCom_skyrat_z2.dmm | 24 +- _maps/map_files/tramstation/tramstation.dmm | 4 +- _maps/shuttles/emergency_nature.dmm | 2 +- _maps/templates/lazy_templates/ninja_den.dmm | 2 +- _maps/templates/lazy_templates/nukie_base.dmm | 2 +- code/__DEFINES/ai.dm | 8 +- .../signals/signals_atom/signals_atom_main.dm | 7 +- code/__DEFINES/dcs/signals/signals_object.dm | 2 + .../dcs/signals/signals_restaurant.dm | 6 + code/__DEFINES/food.dm | 8 + code/__HELPERS/global_lists.dm | 31 +- code/__HELPERS/randoms.dm | 44 +- code/_globalvars/lists/objects.dm | 16 +- .../robot_customer_controller.dm | 25 +- code/datums/components/crafting/_recipes.dm | 10 +- code/datums/components/crafting/crafting.dm | 91 +- .../components/food/ice_cream_holder.dm | 2 +- .../components/takes_reagent_appearance.dm | 7 +- code/datums/elements/food/foodlike_drink.dm | 49 + code/datums/elements/food/venue_price.dm | 23 +- code/game/atoms.dm | 44 +- code/game/atoms_movable.dm | 6 +- code/game/machinery/_machinery.dm | 1 + .../fluid_spread/effects_foam.dm | 12 +- code/game/objects/effects/particle_holder.dm | 5 + code/game/objects/effects/particles/smoke.dm | 5 + .../effects/spawners/random/food_or_drink.dm | 13 +- .../effects/spawners/random/techstorage.dm | 2 +- .../machines/machine_circuitboards.dm | 16 +- code/game/objects/items/food/lizard.dm | 67 - code/game/objects/items/food/moth.dm | 169 +- code/game/objects/items/food/salad.dm | 54 +- code/game/objects/items/food/soup.dm | 456 +---- code/game/objects/items/kitchen.dm | 112 +- code/modules/asset_cache/assets/crafting.dm | 46 +- code/modules/cargo/bounties/chef.dm | 16 +- code/modules/cargo/bounty.dm | 2 +- .../cargo/markets/market_items/consumables.dm | 4 +- code/modules/events/holiday/easter.dm | 2 +- .../food_and_drinks/machinery/griddle.dm | 9 +- .../modules/food_and_drinks/machinery/oven.dm | 53 +- .../food_and_drinks/machinery/stove.dm | 201 ++ .../machinery/stove_component.dm | 244 +++ .../recipes/drinks/drinks_alcoholic.dm | 2 +- .../food_and_drinks/recipes/food_mixtures.dm | 111 +- .../food_and_drinks/recipes/soup_guide.dm | 140 ++ .../food_and_drinks/recipes/soup_mixtures.dm | 1720 +++++++++++++++++ .../recipes/tablecraft/recipes_guide.dm | 22 +- .../recipes/tablecraft/recipes_lizard.dm | 86 +- .../recipes/tablecraft/recipes_misc.dm | 20 + .../recipes/tablecraft/recipes_moth.dm | 220 +-- .../recipes/tablecraft/recipes_salad.dm | 13 - .../recipes/tablecraft/recipes_soup.dm | 384 ---- .../food_and_drinks/restaurant/_venue.dm | 31 +- .../restaurant/custom_order.dm | 105 + .../restaurant/customers/_customer.dm | 52 +- .../restaurant/generic_venues.dm | 74 +- code/modules/hydroponics/grown/onion.dm | 2 +- code/modules/jobs/job_types/cook.dm | 18 +- code/modules/mining/lavaland/ash_flora.dm | 12 +- code/modules/reagents/chemistry/holder.dm | 22 +- code/modules/reagents/chemistry/reagents.dm | 9 +- .../chemistry/reagents/alcohol_reagents.dm | 5 +- .../chemistry/reagents/drink_reagents.dm | 39 +- .../chemistry/reagents/food_reagents.dm | 13 +- code/modules/reagents/chemistry/recipes.dm | 14 +- .../reagents/chemistry/recipes/others.dm | 4 + .../chemistry/recipes/slime_extracts.dm | 59 +- code/modules/reagents/reagent_containers.dm | 15 +- .../reagents/reagent_containers/cups/_cup.dm | 10 + .../reagent_containers/cups/_glass_datum.dm | 45 +- .../reagent_containers/cups/bottle.dm | 2 +- .../reagent_containers/cups/drinkingglass.dm | 14 +- .../reagent_containers/cups/drinks.dm | 16 +- .../research/designs/machine_designs.dm | 20 + code/modules/research/techweb/all_nodes.dm | 2 + .../vatgrowing/samples/cell_lines/common.dm | 6 +- code/modules/unit_tests/focus_only_tests.dm | 3 + .../unit_tests/reagent_recipe_collisions.dm | 23 +- code/modules/vending/drinnerware.dm | 6 +- icons/obj/food/soupsalad.dmi | Bin 32342 -> 32345 bytes icons/obj/kitchen.dmi | Bin 28821 -> 28462 bytes icons/obj/lavaland/ash_flora.dmi | Bin 24306 -> 24749 bytes icons/obj/machines/kitchen_stove.dmi | Bin 0 -> 702 bytes icons/obj/machines/kitchenmachines.dmi | Bin 2939 -> 4848 bytes icons/obj/soup_pot.dmi | Bin 0 -> 413 bytes .../datums/components/crafting/recipes.dm | 2 +- .../modules/morefermentplants/code/banana.dm | 2 +- tgstation.dme | 6 +- 104 files changed, 3439 insertions(+), 1865 deletions(-) create mode 100644 code/datums/elements/food/foodlike_drink.dm create mode 100644 code/modules/food_and_drinks/machinery/stove.dm create mode 100644 code/modules/food_and_drinks/machinery/stove_component.dm create mode 100644 code/modules/food_and_drinks/recipes/soup_guide.dm create mode 100644 code/modules/food_and_drinks/recipes/soup_mixtures.dm delete mode 100644 code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm create mode 100644 icons/obj/machines/kitchen_stove.dmi create mode 100644 icons/obj/soup_pot.dmi diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_homestead.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_homestead.dmm index 2972bf7ae84..46985529cc5 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_homestead.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_homestead.dmm @@ -132,10 +132,7 @@ pixel_x = -8; pixel_y = 13 }, -/obj/item/food/soup/stew{ - name = "porridge"; - pixel_y = 3 - }, +/obj/item/reagent_containers/cup/bowl/soup/stew, /turf/open/floor/wood/large{ initial_gas_mix = "ICEMOON_ATMOS" }, diff --git a/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm b/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm index 751ea8edbaf..51a1e26b898 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm @@ -3,7 +3,7 @@ /turf/template_noop, /area/template_noop) "ad" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/wood, /area/ruin/powered/beach) "aj" = ( diff --git a/_maps/RandomRuins/SpaceRuins/DJstation/kitchen_4.dmm b/_maps/RandomRuins/SpaceRuins/DJstation/kitchen_4.dmm index 597111c9c76..c7f5d9d5718 100644 --- a/_maps/RandomRuins/SpaceRuins/DJstation/kitchen_4.dmm +++ b/_maps/RandomRuins/SpaceRuins/DJstation/kitchen_4.dmm @@ -55,7 +55,7 @@ /turf/closed/wall, /area/ruin/space/djstation) "z" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/iron/white, /area/ruin/space/djstation) "A" = ( diff --git a/_maps/RandomRuins/SpaceRuins/deepstorage.dmm b/_maps/RandomRuins/SpaceRuins/deepstorage.dmm index 0fda79ab8d6..c89703ae007 100644 --- a/_maps/RandomRuins/SpaceRuins/deepstorage.dmm +++ b/_maps/RandomRuins/SpaceRuins/deepstorage.dmm @@ -384,7 +384,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4{ dir = 9 }, -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/iron/cafeteria, /area/ruin/space/has_grav/deepstorage/kitchen) "bb" = ( diff --git a/_maps/RandomRuins/SpaceRuins/oldstation.dmm b/_maps/RandomRuins/SpaceRuins/oldstation.dmm index fdc22f91a4d..6d4b8e71fd8 100644 --- a/_maps/RandomRuins/SpaceRuins/oldstation.dmm +++ b/_maps/RandomRuins/SpaceRuins/oldstation.dmm @@ -7012,7 +7012,7 @@ /area/ruin/space/ancientstation/beta/mining) "Kv" = ( /obj/effect/decal/cleanable/dirt, -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/iron/cafeteria, /area/ruin/space/ancientstation/charlie/kitchen) "Kw" = ( diff --git a/_maps/RandomRuins/SpaceRuins/spacehotel.dmm b/_maps/RandomRuins/SpaceRuins/spacehotel.dmm index 9f370c70cea..ba39055ecde 100644 --- a/_maps/RandomRuins/SpaceRuins/spacehotel.dmm +++ b/_maps/RandomRuins/SpaceRuins/spacehotel.dmm @@ -4028,7 +4028,7 @@ }, /area/ruin/space/has_grav/hotel/workroom) "Tm" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /obj/structure/sign/warning/no_smoking/circle/directional/north, /obj/machinery/camera/directional/north{ c_tag = "Kitchen"; diff --git a/_maps/RandomRuins/SpaceRuins/waystation.dmm b/_maps/RandomRuins/SpaceRuins/waystation.dmm index 9b879b4b362..b88995e4949 100644 --- a/_maps/RandomRuins/SpaceRuins/waystation.dmm +++ b/_maps/RandomRuins/SpaceRuins/waystation.dmm @@ -1773,7 +1773,7 @@ /turf/open/floor/iron/grimy, /area/ruin/space/has_grav/waystation/qm) "Ga" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /obj/machinery/light/small/directional/north, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/cafeteria, diff --git a/_maps/RandomZLevels/SnowCabin.dmm b/_maps/RandomZLevels/SnowCabin.dmm index 7821d686618..afd6074d2e1 100644 --- a/_maps/RandomZLevels/SnowCabin.dmm +++ b/_maps/RandomZLevels/SnowCabin.dmm @@ -454,8 +454,7 @@ /turf/open/floor/iron/cafeteria, /area/awaymission/cabin) "by" = ( -/obj/machinery/oven, -/obj/item/plate/oven_tray, +/obj/machinery/oven/range, /turf/open/floor/iron/cafeteria, /area/awaymission/cabin) "bz" = ( diff --git a/_maps/RandomZLevels/TheBeach.dmm b/_maps/RandomZLevels/TheBeach.dmm index b4018912d3a..1e8ac374713 100644 --- a/_maps/RandomZLevels/TheBeach.dmm +++ b/_maps/RandomZLevels/TheBeach.dmm @@ -1109,7 +1109,7 @@ /turf/open/floor/wood, /area/awaymission/beach) "Jr" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/wood, /area/awaymission/beach) "Kg" = ( diff --git a/_maps/RandomZLevels/undergroundoutpost45.dmm b/_maps/RandomZLevels/undergroundoutpost45.dmm index c805b992823..aa8c6ab593e 100644 --- a/_maps/RandomZLevels/undergroundoutpost45.dmm +++ b/_maps/RandomZLevels/undergroundoutpost45.dmm @@ -10649,7 +10649,7 @@ }, /area/awaymission/undergroundoutpost45/caves) "Ar" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/iron/cafeteria{ dir = 5; heat_capacity = 1e+006 diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index edad165ffc9..e9df241846a 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -55743,7 +55743,7 @@ /turf/open/floor/iron/white, /area/station/medical/cryo) "nPA" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/iron/cafeteria, /area/station/service/kitchen) "nPF" = ( @@ -64628,7 +64628,7 @@ /obj/machinery/light_switch/directional/north{ pixel_x = 8 }, -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/plating, /area/station/service/kitchen/abandoned) "qbW" = ( diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index c7e1aa2b8a4..bbdd9e5b676 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -4956,7 +4956,7 @@ /area/station/security/prison/workout) "bDe" = ( /obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/iron/kitchen/diagonal, /area/station/service/kitchen) "bDj" = ( @@ -26020,6 +26020,7 @@ pixel_x = 3 }, /obj/effect/spawner/random/food_or_drink/cake_ingredients, +/obj/item/food/piedough, /turf/open/floor/iron/kitchen/diagonal, /area/station/service/kitchen) "iot" = ( @@ -30310,7 +30311,7 @@ /turf/open/openspace/icemoon, /area/station/science/server) "jIW" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/plating, /area/station/maintenance/port/aft) "jIX" = ( @@ -36974,12 +36975,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/mine/laborcamp) -"lLO" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/table, -/obj/item/food/piedough, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "lLY" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/recharge_floor, @@ -54591,7 +54586,7 @@ /turf/open/floor/iron/dark/textured_half, /area/mine/mechbay) "rmD" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/iron/cafeteria, /area/station/security/prison/mess) "rmM" = ( @@ -246809,7 +246804,7 @@ xlv iXH qZB oEh -lLO +bDe kvs qfe ecZ diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index 49ed7d0c762..7d35896e310 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -4240,12 +4240,12 @@ /turf/open/floor/iron/showroomfloor, /area/station/medical/exam_room) "buD" = ( -/obj/machinery/griddle, /obj/effect/turf_decal/bot, /obj/machinery/newscaster/directional/north, /obj/effect/turf_decal/tile/neutral/half/contrasted{ dir = 1 }, +/obj/machinery/oven/range, /turf/open/floor/iron/dark, /area/station/service/kitchen) "buJ" = ( @@ -14891,11 +14891,11 @@ /turf/open/floor/plating, /area/station/maintenance/port/fore) "fby" = ( -/obj/machinery/oven, /obj/effect/turf_decal/bot, /obj/effect/turf_decal/tile/neutral/half/contrasted{ dir = 1 }, +/obj/machinery/oven/range, /turf/open/floor/iron/dark, /area/station/service/kitchen) "fbz" = ( @@ -56258,12 +56258,12 @@ /turf/open/floor/iron/dark, /area/station/medical/medbay/central) "srk" = ( -/obj/machinery/deepfryer, /obj/effect/turf_decal/bot, /obj/structure/sign/poster/random/directional/north, /obj/effect/turf_decal/tile/neutral/half/contrasted{ dir = 1 }, +/obj/machinery/griddle, /turf/open/floor/iron/dark, /area/station/service/kitchen) "srs" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index ddd27f5039e..387c609ca89 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -7033,7 +7033,7 @@ /turf/open/floor/iron/dark, /area/station/engineering/atmos) "cFe" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/iron/cafeteria, /area/station/service/kitchen) "cFp" = ( diff --git a/_maps/map_files/VoidRaptor/VoidRaptor.dmm b/_maps/map_files/VoidRaptor/VoidRaptor.dmm index 3d015ce2de2..a9e6430e75c 100644 --- a/_maps/map_files/VoidRaptor/VoidRaptor.dmm +++ b/_maps/map_files/VoidRaptor/VoidRaptor.dmm @@ -65598,8 +65598,8 @@ /area/station/command/heads_quarters/ce) "sxW" = ( /obj/structure/disposalpipe/segment, -/obj/machinery/oven, /obj/effect/turf_decal/bot, +/obj/machinery/oven/range, /turf/open/floor/iron/kitchen, /area/station/service/kitchen) "syd" = ( diff --git a/_maps/map_files/generic/CentCom_skyrat_z2.dmm b/_maps/map_files/generic/CentCom_skyrat_z2.dmm index fc057752dee..f937fb7ad35 100644 --- a/_maps/map_files/generic/CentCom_skyrat_z2.dmm +++ b/_maps/map_files/generic/CentCom_skyrat_z2.dmm @@ -1298,7 +1298,7 @@ /turf/open/misc/dirt/planet, /area/centcom/holding/cafepark) "atq" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/indestructible/hoteltile{ icon_state = "cafeteria" }, @@ -3048,7 +3048,7 @@ /area/centcom/holding/cafedorms) "aMI" = ( /obj/machinery/vending/hydronutrients{ - products = list(/obj/item/reagent_containers/cup/bottle/nutrient/ez = 50, /obj/item/reagent_containers/cup/bottle/nutrient/l4z = 20, /obj/item/reagent_containers/cup/bottle/nutrient/rh = 10, /obj/item/reagent_containers/spray/pestspray = 30, /obj/item/reagent_containers/syringe = 5, /obj/item/storage/bag/plants = 30, /obj/item/cultivator = 10, /obj/item/shovel/spade = 10, /obj/item/plant_analyzer = 10) + products = list(/obj/item/reagent_containers/cup/bottle/nutrient/ez=50,/obj/item/reagent_containers/cup/bottle/nutrient/l4z=20,/obj/item/reagent_containers/cup/bottle/nutrient/rh=10,/obj/item/reagent_containers/spray/pestspray=30,/obj/item/reagent_containers/syringe=5,/obj/item/storage/bag/plants=30,/obj/item/cultivator=10,/obj/item/shovel/spade=10,/obj/item/plant_analyzer=10) }, /turf/open/indestructible/hoteltile{ icon_state = "darkfull" @@ -3181,13 +3181,13 @@ /obj/item/storage/box/ingredients/american, /obj/item/storage/box/ingredients/exotic, /obj/item/reagent_containers/condiment/flour{ - list_reagents = list(/datum/reagent/consumable/flour = 90); + list_reagents = list(/datum/reagent/consumable/flour=90); name = "large flour sack"; possible_transfer_amounts = list(1,5,10,15,30,60,90); volume = 90 }, /obj/item/reagent_containers/condiment/flour{ - list_reagents = list(/datum/reagent/consumable/flour = 90); + list_reagents = list(/datum/reagent/consumable/flour=90); name = "large flour sack"; possible_transfer_amounts = list(1,5,10,15,30,60,90); volume = 90 @@ -6801,12 +6801,12 @@ /obj/item/reagent_containers/condiment/soysauce, /obj/item/reagent_containers/condiment/sugar, /obj/item/reagent_containers/condiment/rice{ - list_reagents = list(/datum/reagent/consumable/rice = 90); + list_reagents = list(/datum/reagent/consumable/rice=90); name = "large rice sack"; possible_transfer_amounts = list(1,5,10,15,20,25,30,50,60,90) }, /obj/item/reagent_containers/condiment/rice{ - list_reagents = list(/datum/reagent/consumable/rice = 90); + list_reagents = list(/datum/reagent/consumable/rice=90); name = "large rice sack"; possible_transfer_amounts = list(1,5,10,15,20,25,30,50,60,90) }, @@ -8708,7 +8708,7 @@ /turf/open/misc/grass/planet, /area/centcom/holding/cafepark) "lXo" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/wood, /area/centcom/holding/cafe) "mac" = ( @@ -9580,24 +9580,24 @@ /obj/item/storage/box/ingredients/american, /obj/item/storage/box/ingredients/exotic, /obj/item/reagent_containers/condiment/flour{ - list_reagents = list(/datum/reagent/consumable/flour = 90); + list_reagents = list(/datum/reagent/consumable/flour=90); name = "large flour sack"; possible_transfer_amounts = list(1,5,10,15,30,60,90); volume = 90 }, /obj/item/reagent_containers/condiment/flour{ - list_reagents = list(/datum/reagent/consumable/flour = 90); + list_reagents = list(/datum/reagent/consumable/flour=90); name = "large flour sack"; possible_transfer_amounts = list(1,5,10,15,30,60,90); volume = 90 }, /obj/item/reagent_containers/condiment/rice{ - list_reagents = list(/datum/reagent/consumable/rice = 90); + list_reagents = list(/datum/reagent/consumable/rice=90); name = "large rice sack"; possible_transfer_amounts = list(1,5,10,15,20,25,30,50,60,90) }, /obj/item/reagent_containers/condiment/rice{ - list_reagents = list(/datum/reagent/consumable/rice = 90); + list_reagents = list(/datum/reagent/consumable/rice=90); name = "large rice sack"; possible_transfer_amounts = list(1,5,10,15,20,25,30,50,60,90) }, @@ -10507,7 +10507,7 @@ /turf/open/floor/iron/dark/textured_large, /area/cruiser_dock) "qvk" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/iron/cafeteria, /area/centcom/interlink) "qwk" = ( diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index d281f2483f3..f90ff1dab88 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -43951,7 +43951,7 @@ /turf/open/floor/catwalk_floor, /area/station/maintenance/tram/mid) "oCu" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/iron/white, /area/station/commons/vacant_room) "oCv" = ( @@ -58261,7 +58261,7 @@ /turf/open/floor/iron/white, /area/station/medical/medbay/central) "tJg" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /turf/open/floor/iron/white, /area/station/service/kitchen) "tJh" = ( diff --git a/_maps/shuttles/emergency_nature.dmm b/_maps/shuttles/emergency_nature.dmm index a9080d727ad..26e74d66b30 100644 --- a/_maps/shuttles/emergency_nature.dmm +++ b/_maps/shuttles/emergency_nature.dmm @@ -379,7 +379,7 @@ dir = 5 }, /obj/structure/table/glass, -/obj/item/food/soup/monkeysdelight{ +/obj/item/reagent_containers/cup/bowl/soup/monkey{ pixel_y = 4 }, /obj/item/reagent_containers/cup/soda_cans/monkey_energy{ diff --git a/_maps/templates/lazy_templates/ninja_den.dmm b/_maps/templates/lazy_templates/ninja_den.dmm index 3b4ff7b14b1..25de2aa8ca6 100644 --- a/_maps/templates/lazy_templates/ninja_den.dmm +++ b/_maps/templates/lazy_templates/ninja_den.dmm @@ -1815,7 +1815,7 @@ }, /area/centcom/central_command_areas/holding) "Rg" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /obj/machinery/light/directional/north, /turf/open/floor/iron/cafeteria, /area/centcom/central_command_areas/holding) diff --git a/_maps/templates/lazy_templates/nukie_base.dmm b/_maps/templates/lazy_templates/nukie_base.dmm index 4f3e9d1884e..87f592054f5 100644 --- a/_maps/templates/lazy_templates/nukie_base.dmm +++ b/_maps/templates/lazy_templates/nukie_base.dmm @@ -1144,7 +1144,7 @@ /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_chemicalwarfare) "nb" = ( -/obj/machinery/oven, +/obj/machinery/oven/range, /obj/structure/sign/poster/contraband/eat{ pixel_x = -32 }, diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm index 32ed1445b55..8a62039228e 100644 --- a/code/__DEFINES/ai.dm +++ b/code/__DEFINES/ai.dm @@ -125,13 +125,19 @@ #define BB_VENDING_BUSY_TILTING "BB_vending_busy_tilting" #define BB_VENDING_LAST_HIT_SUCCESFUL "BB_vending_last_hit_succesful" -///Robot customer AI controller blackboard keys +//Robot customer AI controller blackboard keys +/// Corresponds to the customer's order. +/// This can be a an item typepath or an instance of a custom order datum #define BB_CUSTOMER_CURRENT_ORDER "BB_customer_current_order" #define BB_CUSTOMER_MY_SEAT "BB_customer_my_seat" #define BB_CUSTOMER_PATIENCE "BB_customer_patience" +/// A reference to a customer data datum, containing stuff like saylines and food desires #define BB_CUSTOMER_CUSTOMERINFO "BB_customer_customerinfo" +/// Whether we're busy eating something already #define BB_CUSTOMER_EATING "BB_customer_eating" +/// A reference to the venue being attended #define BB_CUSTOMER_ATTENDING_VENUE "BB_customer_attending_avenue" +/// Whether we're leaving the venue entirely, either happily or forced out #define BB_CUSTOMER_LEAVING "BB_customer_leaving" #define BB_CUSTOMER_CURRENT_TARGET "BB_customer_current_target" /// Robot customer has said their can't find seat line at least once. Used to rate limit how often they'll complain after the first time. diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm index d80e3084e52..062e5ef00dc 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm @@ -11,7 +11,12 @@ #define COMSIG_PARENT_EXAMINE "atom_examine" ///from base of atom/get_examine_name(): (/mob, list/overrides) #define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name" -#define COMSIG_PARENT_EXAMINE_MORE "atom_examine_more" ///from base of atom/examine_more(): (/mob) +///from base of atom/examine(): (/mob, list/examine_text, can_see_inside) +#define COMSIG_PARENT_REAGENT_EXAMINE "atom_reagent_examine" + /// Stop the generic reagent examine text + #define STOP_GENERIC_REAGENT_EXAMINE (1<<0) +///from base of atom/examine_more(): (/mob) +#define COMSIG_PARENT_EXAMINE_MORE "atom_examine_more" //Positions for overrides list #define EXAMINE_POSITION_ARTICLE (1<<0) #define EXAMINE_POSITION_BEFORE (1<<1) diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 3f0edab3f75..d21b80deee6 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -30,6 +30,8 @@ #define COMSIG_MACHINERY_START_PROCESSING_AIR "start_processing_air" ///from /datum/controller/subsystem/air/proc/stop_processing_machine: () #define COMSIG_MACHINERY_STOP_PROCESSING_AIR "stop_processing_air" +///from /obj/machinery/RefreshParts: () +#define COMSIG_MACHINERY_REFRESH_PARTS "machine_refresh_parts" ///from /obj/machinery/can_interact(mob/user): Called on user when attempting to interact with a machine (obj/machinery/machine) #define COMSIG_TRY_USE_MACHINE "try_use_machine" diff --git a/code/__DEFINES/dcs/signals/signals_restaurant.dm b/code/__DEFINES/dcs/signals/signals_restaurant.dm index 2a23262e887..a63fc5fdaad 100644 --- a/code/__DEFINES/dcs/signals/signals_restaurant.dm +++ b/code/__DEFINES/dcs/signals/signals_restaurant.dm @@ -6,3 +6,9 @@ ///(customer, container) venue signal sent when a venue sells an item. source is the thing sold, which can be a datum, so we send container for location checks #define COMSIG_ITEM_SOLD_TO_CUSTOMER "item_sold_to_customer" +///(customer, container) venue signal sent when a venue sells an reagent. source is the thing sold, which can be a datum, so we send container for location checks +#define COMSIG_REAGENT_SOLD_TO_CUSTOMER "reagent_sold_to_customer" + /// Return from either above signal to denote the transaction completed successfully, so the venue can finish processing it + #define TRANSACTION_SUCCESS (1<<0) + /// Return from either above to stop the venue default processing, allowing you to handle cleanup / aftermath yourself + #define TRANSACTION_HANDLED (1<<1) diff --git a/code/__DEFINES/food.dm b/code/__DEFINES/food.dm index f5c811b61a0..b6ba97ef312 100644 --- a/code/__DEFINES/food.dm +++ b/code/__DEFINES/food.dm @@ -182,6 +182,14 @@ DEFINE_BITFIELD(food_flags, list( #define BLACKBOX_LOG_FOOD_MADE(food) SSblackbox.record_feedback("tally", "food_made", 1, food) +/// Point water boils at +#define WATER_BOILING_POINT (T0C + 100) +/// Point at which soups begin to burn at +#define SOUP_BURN_TEMP 540 + +/// Serving size of soup. Plus or minus five units. +#define SOUP_SERVING_SIZE 25 + // Venues for the barbots. #define VENUE_RESTAURANT "Restaurant Venue" #define VENUE_BAR "Bar Venue" diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index c7de9f016d3..b82a86c91bf 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -164,44 +164,39 @@ /proc/init_crafting_recipes_atoms() var/list/recipe_lists = list( GLOB.crafting_recipes, - GLOB.cooking_recipes + GLOB.cooking_recipes, ) var/list/atom_lists = list( GLOB.crafting_recipes_atoms, - GLOB.cooking_recipes_atoms + GLOB.cooking_recipes_atoms, ) - for(var/recipe_list in recipe_lists) + for(var/list_index in 1 to length(recipe_lists)) + var/list/recipe_list = recipe_lists[list_index] + var/list/atom_list = atom_lists[list_index] for(var/datum/crafting_recipe/recipe as anything in recipe_list) - var/list_index = recipe_lists.Find(recipe_list) // Result - if(!(recipe.result in atom_lists[list_index])) - atom_lists[list_index] += recipe.result + atom_list |= recipe.result // Ingredients for(var/atom/req_atom as anything in recipe.reqs) - if(!(req_atom in atom_lists[list_index])) - atom_lists[list_index] += req_atom + atom_list |= req_atom // Catalysts for(var/atom/req_atom as anything in recipe.chem_catalysts) - if(!(req_atom in atom_lists[list_index])) - atom_lists[list_index] += req_atom + atom_list |= req_atom // Reaction data - required container if(recipe.reaction) var/required_container = initial(recipe.reaction.required_container) - if(required_container && !(required_container in atom_lists[list_index])) - atom_lists[list_index] += required_container + if(required_container) + atom_list |= required_container // Tools for(var/atom/req_atom as anything in recipe.tool_paths) - if(!(req_atom in atom_lists[list_index])) - atom_lists[list_index] += req_atom + atom_list |= req_atom // Machinery for(var/atom/req_atom as anything in recipe.machinery) - if(!(req_atom in atom_lists[list_index])) - atom_lists[list_index] += req_atom + atom_list |= req_atom // Structures for(var/atom/req_atom as anything in recipe.structures) - if(!(req_atom in atom_lists[list_index])) - atom_lists[list_index] += req_atom + atom_list |= req_atom //creates every subtype of prototype (excluding prototype) and adds it to list L. //if no list/L is provided, one is created. diff --git a/code/__HELPERS/randoms.dm b/code/__HELPERS/randoms.dm index ed542417377..de94471d7ff 100644 --- a/code/__HELPERS/randoms.dm +++ b/code/__HELPERS/randoms.dm @@ -4,28 +4,28 @@ if(!LAZYLEN(allowed_food)) //it's static so we only ever do this once var/list/blocked = list( - /obj/item/food/drug, - /obj/item/food/spaghetti, - /obj/item/food/bread, - /obj/item/food/breadslice, - /obj/item/food/cake, - /obj/item/food/cakeslice, - /obj/item/food/pie, - /obj/item/food/pieslice, - /obj/item/food/kebab, - /obj/item/food/pizza, - /obj/item/food/pizzaslice, - /obj/item/food/salad, - /obj/item/food/meat, - /obj/item/food/meat/slab, - /obj/item/food/soup, - /obj/item/food/grown, - /obj/item/food/grown/mushroom, - /obj/item/food/clothing, - /obj/item/food/meat/slab/human/mutant, - /obj/item/food/grown/ash_flora, - /obj/item/food/grown/nettle, - /obj/item/food/grown/shell + /obj/item/food/bowled, + /obj/item/food/bread, + /obj/item/food/breadslice, + /obj/item/food/cake, + /obj/item/food/cakeslice, + /obj/item/food/clothing, + /obj/item/food/drug, + /obj/item/food/grown, + /obj/item/food/grown/ash_flora, + /obj/item/food/grown/mushroom, + /obj/item/food/grown/nettle, + /obj/item/food/grown/shell, + /obj/item/food/kebab, + /obj/item/food/meat, + /obj/item/food/meat/slab, + /obj/item/food/meat/slab/human/mutant, + /obj/item/food/pie, + /obj/item/food/pieslice, + /obj/item/food/pizza, + /obj/item/food/pizzaslice, + /obj/item/food/salad, + /obj/item/food/spaghetti, ) var/list/unfiltered_allowed_food = subtypesof(/obj/item/food) - blocked diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index bee8a5c0184..6c9496108a3 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -26,10 +26,18 @@ GLOBAL_LIST(chemical_reactions_results_lookup_list) //List of all reactions with GLOBAL_LIST(fake_reagent_blacklist) //List of all reagents that are parent types used to define a bunch of children - but aren't used themselves as anything. GLOBAL_LIST_EMPTY(tech_list) //list of all /datum/tech datums indexed by id. GLOBAL_LIST_EMPTY(surgeries_list) //list of all surgeries by name, associated with their path. -GLOBAL_LIST_EMPTY(crafting_recipes) //list of all crafting recipes -GLOBAL_LIST_EMPTY(crafting_recipes_atoms) //list of all atoms occuring in crafting recipes -GLOBAL_LIST_EMPTY(cooking_recipes) //list of all cooking recipes -GLOBAL_LIST_EMPTY(cooking_recipes_atoms) //list of all atoms occuring in cooking recipes + +/// Global list of all non-cooking related crafting recipes. +GLOBAL_LIST_EMPTY(crafting_recipes) +/// This is a global list of typepaths, these typepaths are atoms or reagents that are associated with crafting recipes. +/// This includes stuff like recipe components and results. +GLOBAL_LIST_EMPTY(crafting_recipes_atoms) +/// Global list of all cooking related crafting recipes. +GLOBAL_LIST_EMPTY(cooking_recipes) +/// This is a global list of typepaths, these typepaths are atoms or reagents that are associated with cooking recipes. +/// This includes stuff like recipe components and results. +GLOBAL_LIST_EMPTY(cooking_recipes_atoms) + GLOBAL_LIST_EMPTY(rcd_list) //list of Rapid Construction Devices. GLOBAL_LIST_EMPTY(intercoms_list) //list of wallmounted intercom radios. GLOBAL_LIST_EMPTY(apcs_list) //list of all Area Power Controller machines, separate from machines for powernet speeeeeeed. diff --git a/code/datums/ai/robot_customer/robot_customer_controller.dm b/code/datums/ai/robot_customer/robot_customer_controller.dm index cf53c521b3a..ebbfe31fbed 100644 --- a/code/datums/ai/robot_customer/robot_customer_controller.dm +++ b/code/datums/ai/robot_customer/robot_customer_controller.dm @@ -35,9 +35,11 @@ SIGNAL_HANDLER var/datum/venue/attending_venue = blackboard[BB_CUSTOMER_ATTENDING_VENUE] if(attending_venue.is_correct_order(I, blackboard[BB_CUSTOMER_CURRENT_ORDER])) - to_chat(user, span_notice("You hand [I] to [pawn]")) + to_chat(user, span_notice("You hand [I] to [pawn].")) eat_order(I, attending_venue) return COMPONENT_NO_AFTERATTACK + else if(!I.force) + INVOKE_ASYNC(src, PROC_REF(dont_want_that), I, user) else INVOKE_ASYNC(src, PROC_REF(warn_greytider), user) @@ -46,13 +48,15 @@ INVOKE_ASYNC(src, PROC_REF(warn_greytider), attacker) /datum/ai_controller/robot_customer/proc/eat_order(obj/item/order_item, datum/venue/attending_venue) - if(!blackboard[BB_CUSTOMER_EATING]) - blackboard[BB_CUSTOMER_EATING] = TRUE - attending_venue.on_get_order(pawn, order_item) - var/our_order = blackboard[BB_CUSTOMER_CURRENT_ORDER] - if(isdatum(our_order)) - qdel(our_order) - blackboard[BB_CUSTOMER_CURRENT_ORDER] = null + if(blackboard[BB_CUSTOMER_EATING]) + return + + blackboard[BB_CUSTOMER_EATING] = TRUE + attending_venue.on_get_order(pawn, order_item) + var/our_order = blackboard[BB_CUSTOMER_CURRENT_ORDER] + if(isdatum(our_order)) + qdel(our_order) + blackboard[BB_CUSTOMER_CURRENT_ORDER] = null ///Called when @@ -76,7 +80,10 @@ customer.resist() - +/datum/ai_controller/robot_customer/proc/dont_want_that(mob/living/chef, obj/item/thing) + var/mob/living/simple_animal/robot_customer/customer = pawn + var/datum/customer_data/customer_data = blackboard[BB_CUSTOMER_CUSTOMERINFO] + customer.say(customer_data.wrong_item_line) /datum/ai_controller/robot_customer/proc/warn_greytider(mob/living/greytider) var/mob/living/simple_animal/robot_customer/customer = pawn diff --git a/code/datums/components/crafting/_recipes.dm b/code/datums/components/crafting/_recipes.dm index 1298822f978..56f8ed23970 100644 --- a/code/datums/components/crafting/_recipes.dm +++ b/code/datums/components/crafting/_recipes.dm @@ -1,6 +1,10 @@ /datum/crafting_recipe - ///in-game display name + /// in-game display name + /// Optional, if not set uses result name var/name + /// description displayed in game + /// Optional, if not set uses result desc + var/desc ///type paths of items consumed associated with how many are needed var/list/reqs = list() ///type paths of items explicitly not allowed as an ingredient @@ -77,3 +81,7 @@ if(ispath(required_pipe.pipe_type, /obj/machinery/atmospherics/pipe/smart)) return TRUE return FALSE + +/// Additional UI data to be passed to the crafting UI for this recipe +/datum/crafting_recipe/proc/crafting_ui_data() + return list() diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index 1b50b4e7b63..59f689e5b9d 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -405,7 +405,7 @@ data["recipes"] = list() data["categories"] = list() - data["foodtypes"] = list() + data["foodtypes"] = FOOD_FLAGS if(user.has_dna()) var/mob/living/carbon/carbon = user @@ -415,27 +415,14 @@ if(!is_recipe_available(recipe, user)) continue - if(recipe.category && !(recipe.category in data["categories"])) - data["categories"] += recipe.category - - if(ispath(recipe.result, /obj/item/food)) - var/obj/item/food/item = recipe.result - var/list/foodtypes = bitfield_to_list(initial(item.foodtypes), FOOD_FLAGS) - for(var/type in foodtypes) - if(!(type in data["foodtypes"])) - data["foodtypes"] += type + if(recipe.category) + data["categories"] |= recipe.category // Materials for(var/req in recipe.reqs) - if(!(req in material_occurences)) - material_occurences[req] = 1 - else - material_occurences[req] += 1 + material_occurences[req] += 1 for(var/req in recipe.chem_catalysts) - if(!(req in material_occurences)) - material_occurences[req] = 1 - else - material_occurences[req] += 1 + material_occurences[req] += 1 data["recipes"] += list(build_crafting_data(recipe)) @@ -508,39 +495,32 @@ var/atom/atom = recipe.result data["result"] = atoms.Find(atom) - if(ispath(recipe.type, /datum/crafting_recipe/food) && ispath(recipe.result, /obj/item/food)) - // Foodtypes - var/obj/item/food/item = recipe.result - var/list/foodtypes = bitfield_to_list(initial(item.foodtypes), FOOD_FLAGS) - for(var/type in foodtypes) - if(!(type in data["foodtypes"])) - data["foodtypes"] += type - data["foodtypes"] = foodtypes - // Nutriments - var/datum/crafting_recipe/food/food_recipe = recipe - data["nutriments"] = food_recipe.total_nutriment_factor + var/recipe_data = recipe.crafting_ui_data() + for(var/new_data in recipe_data) + data[new_data] = recipe_data[new_data] // Category data["category"] = recipe.category // Name, Description - data["name"] = initial(atom.name) - if(recipe.name) // Override if recipe has a name - data["name"] = recipe.name + data["name"] = recipe.name || initial(atom.name) if(ispath(recipe.result, /datum/reagent)) var/datum/reagent/reagent = recipe.result if(recipe.result_amount > 1) data["name"] = "[data["name"]] [recipe.result_amount]u" - data["desc"] = initial(reagent.description) + data["desc"] = recipe.desc || initial(reagent.description) + else if(ispath(recipe.result, /obj/item/pipe)) var/obj/item/pipe/pipe_obj = recipe.result var/obj/pipe_real = initial(pipe_obj.pipe_type) - data["desc"] = initial(pipe_real.desc) + data["desc"] = recipe.desc || initial(pipe_real.desc) + else if(ispath(recipe.result, /obj/item/stack) && recipe.result_amount > 1) data["name"] = "[data["name"]] [recipe.result_amount]x" - data["desc"] = initial(atom.desc) + data["desc"] = recipe.desc || initial(atom.desc) + // Crafting if(recipe.non_craftable) @@ -553,50 +533,55 @@ data["tool_behaviors"] = recipe.tool_behaviors if(recipe.tool_paths) data["tool_paths"] = list() - for(var/req_atom as anything in recipe.tool_paths) + for(var/req_atom in recipe.tool_paths) data["tool_paths"] += atoms.Find(req_atom) // Machinery if(recipe.machinery) data["machinery"] = list() - for(var/req_atom as anything in recipe.machinery) + for(var/req_atom in recipe.machinery) data["machinery"] += atoms.Find(req_atom) // Structures if(recipe.structures) data["structures"] = list() - for(var/req_atom as anything in recipe.structures) + for(var/req_atom in recipe.structures) data["structures"] += atoms.Find(req_atom) // Ingredients / Materials if(recipe.reqs.len) data["reqs"] = list() - for(var/req_atom as anything in recipe.reqs) + for(var/req_atom in recipe.reqs) var/id = atoms.Find(req_atom) data["reqs"]["[id]"] = recipe.reqs[req_atom] // Catalysts if(recipe.chem_catalysts.len) data["chem_catalysts"] = list() - for(var/req_atom as anything in recipe.chem_catalysts) + for(var/req_atom in recipe.chem_catalysts) var/id = atoms.Find(req_atom) data["chem_catalysts"]["[id]"] = recipe.chem_catalysts[req_atom] // Reaction data - if(recipe.reaction) + if(ispath(recipe.reaction)) data["is_reaction"] = TRUE - var/datum/chemical_reaction/reaction = GLOB.chemical_reactions_list[recipe.reaction] - if(!data["steps"]) - data["steps"] = list() - if(!reaction.required_container && (recipe.reqs.len > 1 || reaction.required_catalysts.len)) - data["steps"] += "Mix all ingredients together" - if(reaction.required_temp > T20C) - data["steps"] += "Heat up to [reaction.required_temp]K" - if(reaction.required_container) - var/atom/req_atom = reaction.required_container - var/id = atoms.Find(req_atom) - data["reqs"]["[id]"] = 1 - data["steps"] += "Add all ingredients into the [initial(req_atom.name)]" + // May be called before chemical reactions list is setup + var/datum/chemical_reaction/reaction = GLOB.chemical_reactions_list[recipe.reaction] || new recipe.reaction() + if(istype(reaction)) + if(!data["steps"]) + data["steps"] = list() + if(reaction.required_container) + var/id = atoms.Find(reaction.required_container) + data["reqs"]["[id]"] = 1 + data["steps"] += "Add all ingredients into \a [initial(reaction.required_container.name)]" + else if(length(recipe.reqs) > 1 || length(reaction.required_catalysts)) + data["steps"] += "Mix all ingredients together" + if(reaction.required_temp > T20C) + data["steps"] += "Heat up to [reaction.required_temp]K" + else + stack_trace("Invalid reaction found in recipe code! ([recipe.reaction])") + else if(!isnull(recipe.reaction)) + stack_trace("Invalid reaction found in recipe code! ([recipe.reaction])") return data diff --git a/code/datums/components/food/ice_cream_holder.dm b/code/datums/components/food/ice_cream_holder.dm index 41267981187..60da9b207d6 100644 --- a/code/datums/components/food/ice_cream_holder.dm +++ b/code/datums/components/food/ice_cream_holder.dm @@ -169,7 +169,7 @@ if(compare_list(our_scoops, icecream_order.wanted_flavors)) return COMPONENT_CORRECT_ORDER -/datum/component/ice_cream_holder/proc/sell_ice_cream(obj/item/source, mob/living/simple_animal/robot_customer/sold_to, obj/item/container) +/datum/component/ice_cream_holder/proc/sell_ice_cream(obj/item/source, mob/living/simple_animal/robot_customer/sold_to) SIGNAL_HANDLER //the price of ice cream scales with the number of scoops. Yummy. diff --git a/code/datums/components/takes_reagent_appearance.dm b/code/datums/components/takes_reagent_appearance.dm index c54882ac5b4..0d5730fc80d 100644 --- a/code/datums/components/takes_reagent_appearance.dm +++ b/code/datums/components/takes_reagent_appearance.dm @@ -98,7 +98,7 @@ item_parent.name = initial(item_parent.name) else if(style.name) // style - item_parent.name = style.name + style.set_name(item_parent) return COMSIG_ATOM_NO_UPDATE_NAME return NONE @@ -120,7 +120,7 @@ item_parent.desc = initial(item_parent.desc) else if(style.desc) // style - item_parent.desc = style.desc + style.set_desc(item_parent) return COMSIG_ATOM_NO_UPDATE_DESC return NONE @@ -139,8 +139,7 @@ item_parent.icon_state = icon_state_pre_change else if(style.icon && style.icon_state) // style - item_parent.icon = style.icon - item_parent.icon_state = style.icon_state + style.set_appearance(item_parent) on_icon_changed?.InvokeAsync(style) return COMSIG_ATOM_NO_UPDATE_ICON_STATE diff --git a/code/datums/elements/food/foodlike_drink.dm b/code/datums/elements/food/foodlike_drink.dm new file mode 100644 index 00000000000..e83468d68a1 --- /dev/null +++ b/code/datums/elements/food/foodlike_drink.dm @@ -0,0 +1,49 @@ +#define DOAFTER_SOURCE_FOODLIKE_DRINK "doafter_foodlike_drink" + +/** + * This element can be attached to a reagent container to make it loop after drinking like a food item + */ +/datum/element/foodlike_drink + +/datum/element/foodlike_drink/Attach(datum/target) + . = ..() + if(!is_reagent_container(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_GLASS_DRANK, PROC_REF(on_drink)) + +/datum/element/foodlike_drink/Detach(datum/source, ...) + . = ..() + UnregisterSignal(source, COMSIG_GLASS_DRANK) + +/datum/element/foodlike_drink/proc/on_drink(obj/item/reagent_containers/source, mob/living/drinker, mob/living/user) + SIGNAL_HANDLER + + if(drinker != user) + return + + if(DOING_INTERACTION(user, DOAFTER_SOURCE_FOODLIKE_DRINK)) + return + + INVOKE_ASYNC(src, PROC_REF(continue_drinking), source, user) + +/datum/element/foodlike_drink/proc/continue_drinking(obj/item/reagent_containers/source, mob/living/user) + if(!do_after( + user = user, + delay = 1.25 SECONDS, + timed_action_flags = IGNORE_USER_LOC_CHANGE, + extra_checks = CALLBACK(src, PROC_REF(can_keep_drinking), source, user), + interaction_key = DOAFTER_SOURCE_FOODLIKE_DRINK, + )) + return + + source.attack(user, user) + +/datum/element/foodlike_drink/proc/can_keep_drinking(obj/item/reagent_containers/source, mob/living/user) + if(QDELETED(source) || user.get_active_held_item() != source) + return FALSE + if(source.reagents.total_volume <= 0) + return FALSE + return TRUE + +#undef DOAFTER_SOURCE_FOODLIKE_DRINK diff --git a/code/datums/elements/food/venue_price.dm b/code/datums/elements/food/venue_price.dm index 514346a22e3..1fcf9de040d 100644 --- a/code/datums/elements/food/venue_price.dm +++ b/code/datums/elements/food/venue_price.dm @@ -10,17 +10,32 @@ stack_trace("A venue_price element was attached to something without specifying an actual price.") return ELEMENT_INCOMPATIBLE src.venue_price = venue_price - RegisterSignal(target, COMSIG_ITEM_SOLD_TO_CUSTOMER, PROC_REF(item_sold)) + + if(isitem(target)) + RegisterSignal(target, COMSIG_ITEM_SOLD_TO_CUSTOMER, PROC_REF(item_sold)) + if(istype(target, /datum/reagent)) + RegisterSignal(target, COMSIG_REAGENT_SOLD_TO_CUSTOMER, PROC_REF(reagent_sold)) /datum/element/venue_price/Detach(datum/target) . = ..() UnregisterSignal(target, COMSIG_ITEM_SOLD_TO_CUSTOMER) + UnregisterSignal(target, COMSIG_REAGENT_SOLD_TO_CUSTOMER) -/datum/element/venue_price/proc/item_sold(datum/thing_sold, mob/living/simple_animal/robot_customer/sold_to, obj/item/container) +/datum/element/venue_price/proc/item_sold(obj/item/thing_sold, mob/living/simple_animal/robot_customer/sold_to) SIGNAL_HANDLER - var/datum/venue/venue_to_pay = sold_to.ai_controller?.blackboard[BB_CUSTOMER_ATTENDING_VENUE] + produce_cash(sold_to, thing_sold) + return TRANSACTION_SUCCESS +/datum/element/venue_price/proc/reagent_sold(datum/reagent/reagent_sold, mob/living/simple_animal/robot_customer/sold_to, obj/item/container) + SIGNAL_HANDLER + + produce_cash(sold_to, container) + return TRANSACTION_SUCCESS + +/datum/element/venue_price/proc/produce_cash(mob/living/simple_animal/robot_customer/sold_to, obj/item/container) new /obj/item/holochip(get_turf(container), venue_price) + playsound(container, 'sound/effects/cashregister.ogg', 60, TRUE) + + var/datum/venue/venue_to_pay = sold_to.ai_controller.blackboard[BB_CUSTOMER_ATTENDING_VENUE] venue_to_pay.total_income += venue_price - playsound(get_turf(container), 'sound/effects/cashregister.ogg', 60, TRUE) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 0b13fbc15e4..f86b0c9ab6d 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -734,31 +734,29 @@ . += EXAMINE_SECTION_BREAK //SKYRAT EDIT ADDITION //SKYRAT EDIT ADDITION END if(reagents) - if(reagents.flags & TRANSPARENT) - . += EXAMINE_SECTION_BREAK //SKYRAT EDIT ADDITION - HR sections - . += "It contains:" - if(length(reagents.reagent_list)) - if(user.can_see_reagents()) //Show each individual reagent - for(var/datum/reagent/current_reagent as anything in reagents.reagent_list) - . += "• [round(current_reagent.volume, 0.01)] units of [current_reagent.name]" - if(reagents.is_reacting) - . += span_warning("  It is currently reacting!") // SKYRAT EDIT CHANGE - added spacing - . += span_notice("The solution's pH is [round(reagents.ph, 0.01)] and has a temperature of [reagents.chem_temp]K.") - else //Otherwise, just show the total volume - var/total_volume = 0 - for(var/datum/reagent/current_reagent as anything in reagents.reagent_list) - total_volume += current_reagent.volume - . += "[total_volume] units of various reagents" - else - . += "Nothing." - . += EXAMINE_SECTION_BREAK //SKYRAT EDIT ADDITION - else if(reagents.flags & AMOUNT_VISIBLE) - if(reagents.total_volume) - . += span_notice("It has [reagents.total_volume] unit\s left.") - else - . += span_danger("It's empty.") + var/user_sees_reagents = user.can_see_reagents() + var/reagent_sigreturn = SEND_SIGNAL(src, COMSIG_PARENT_REAGENT_EXAMINE, user, ., user_sees_reagents) + if(!(reagent_sigreturn & STOP_GENERIC_REAGENT_EXAMINE)) + if(reagents.flags & TRANSPARENT) + if(reagents.total_volume > 0) + . += "It contains [round(reagents.total_volume, 0.01)] units of various reagents[user_sees_reagents ? ":" : "."]" + if(user_sees_reagents) //Show each individual reagent + for(var/datum/reagent/current_reagent as anything in reagents.reagent_list) + . += "• [round(current_reagent.volume, 0.01)] units of [current_reagent.name]" + if(reagents.is_reacting) + . += span_warning("It is currently reacting!") + . += span_notice("The solution's pH is [round(reagents.ph, 0.01)] and has a temperature of [reagents.chem_temp]K.") + + else + . += "It contains:
Nothing." + else if(reagents.flags & AMOUNT_VISIBLE) + if(reagents.total_volume) + . += span_notice("It has [reagents.total_volume] unit\s left.") + else + . += span_danger("It's empty.") SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .) + /** * Called when a mob examines (shift click or verb) this atom twice (or more) within EXAMINE_MORE_WINDOW (default 1 second) * diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 8db2ff2261c..a46d34a3b26 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -283,10 +283,12 @@ underlay_appearance.overlays += turf_mask /atom/movable/update_overlays() - . = ..() + var/list/overlays = ..() var/emissive_block = update_emissive_block() if(emissive_block) - . += emissive_block + // Emissive block should always go at the beginning of the list + overlays.Insert(1, emissive_block) + return overlays /atom/movable/proc/onZImpact(turf/impacted_turf, levels, message = TRUE) SHOULD_CALL_PARENT(TRUE) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 8ba617003af..7055e19df96 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -781,6 +781,7 @@ idle_power_usage = initial(idle_power_usage) * (1 + parts_energy_rating) active_power_usage = initial(active_power_usage) * (1 + parts_energy_rating) update_current_power_usage() + SEND_SIGNAL(src, COMSIG_MACHINERY_REFRESH_PARTS) /obj/machinery/proc/default_pry_open(obj/item/crowbar, close_after_pry = FALSE, open_density = FALSE, closed_density = TRUE) . = !(state_open || panel_open || is_operational || (flags_1 & NODECONSTRUCT_1)) && crowbar.tool_behaviour == TOOL_CROWBAR diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm index 230c82950ec..0d44043197f 100644 --- a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm @@ -172,9 +172,9 @@ QDEL_NULL(chemholder) return ..() -/datum/effect_system/fluid_spread/foam/set_up(range = 1, amount = DIAMOND_AREA(range), atom/holder, atom/location = null, datum/reagents/carry = null, result_type = null) +/datum/effect_system/fluid_spread/foam/set_up(range = 1, amount = DIAMOND_AREA(range), atom/holder, atom/location = null, datum/reagents/carry = null, result_type = null, stop_reactions = FALSE) . = ..() - carry?.copy_to(chemholder, carry.total_volume) + carry?.copy_to(chemholder, carry.total_volume, no_react = stop_reactions) if(!isnull(result_type)) src.result_type = result_type @@ -440,6 +440,14 @@ for(var/obj/item/potential_tinder in location) potential_tinder.extinguish() +/datum/effect_system/fluid_spread/foam/dirty + effect_type = /obj/effect/particle_effect/fluid/foam/dirty + +/obj/effect/particle_effect/fluid/foam/dirty + name = "dirty foam" + allow_duplicate_results = FALSE + result_type = /obj/effect/decal/cleanable/dirt + #undef MINIMUM_FOAM_DILUTION_RANGE #undef MINIMUM_FOAM_DILUTION #undef FOAM_REAGENT_SCALE diff --git a/code/game/objects/effects/particle_holder.dm b/code/game/objects/effects/particle_holder.dm index 3758e808be0..99de07740ed 100644 --- a/code/game/objects/effects/particle_holder.dm +++ b/code/game/objects/effects/particle_holder.dm @@ -65,3 +65,8 @@ particle_mob.vis_contents += src //readd to ourselves attached_to.vis_contents |= src + +/// Sets the particles position to the passed coordinate list (X, Y, Z) +/// See [https://www.byond.com/docs/ref/#/{notes}/particles] for position documentation +/obj/effect/abstract/particle_holder/proc/set_particle_position(list/pos) + particles.position = pos diff --git a/code/game/objects/effects/particles/smoke.dm b/code/game/objects/effects/particles/smoke.dm index 33d93596455..bf66fdb6b07 100644 --- a/code/game/objects/effects/particles/smoke.dm +++ b/code/game/objects/effects/particles/smoke.dm @@ -23,6 +23,11 @@ velocity = list(0, 0.3, 0) friction = 0.25 +/particles/smoke/steam/bad + icon_state = list("steam_1" = 1, "smoke_1" = 1, "smoke_2" = 1, "smoke_3" = 1) + spawning = 2 + velocity = list(0, 0.25, 0) + /particles/smoke/ash icon_state = list("ash_1" = 2, "ash_2" = 2, "ash_3" = 1, "smoke_1" = 3, "smoke_2" = 2) count = 500 diff --git a/code/game/objects/effects/spawners/random/food_or_drink.dm b/code/game/objects/effects/spawners/random/food_or_drink.dm index 8753c2cfff8..a1b9976cab2 100644 --- a/code/game/objects/effects/spawners/random/food_or_drink.dm +++ b/code/game/objects/effects/spawners/random/food_or_drink.dm @@ -72,12 +72,12 @@ name = "soup spawner" icon_state = "soup" loot = list( - /obj/item/food/soup/beet, - /obj/item/food/soup/sweetpotato, - /obj/item/food/soup/stew, - /obj/item/food/soup/hotchili, - /obj/item/food/soup/nettle, - /obj/item/food/soup/meatball, + /obj/item/reagent_containers/cup/bowl/soup/hotchili, + /obj/item/reagent_containers/cup/bowl/soup/meatball_soup, + /obj/item/reagent_containers/cup/bowl/soup/nettle, + /obj/item/reagent_containers/cup/bowl/soup/stew, + /obj/item/reagent_containers/cup/bowl/soup/sweetpotato, + /obj/item/reagent_containers/cup/bowl/soup/white_beet, ) /obj/effect/spawner/random/food_or_drink/salad @@ -271,4 +271,3 @@ if(!HAS_TRAIT(SSstation, STATION_TRAIT_BIRTHDAY)) spawn_loot_chance = 0 return ..() - diff --git a/code/game/objects/effects/spawners/random/techstorage.dm b/code/game/objects/effects/spawners/random/techstorage.dm index ad347539201..0fe2f487130 100644 --- a/code/game/objects/effects/spawners/random/techstorage.dm +++ b/code/game/objects/effects/spawners/random/techstorage.dm @@ -38,6 +38,7 @@ /obj/item/circuitboard/machine/griddle, /obj/item/circuitboard/machine/reagentgrinder, /obj/item/circuitboard/machine/oven, + /obj/item/circuitboard/machine/stove, /obj/item/circuitboard/machine/processor, /obj/item/circuitboard/machine/gibber, /obj/item/circuitboard/machine/chem_dispenser/drinks, @@ -121,4 +122,3 @@ /obj/item/circuitboard/computer/apc_control, /obj/item/circuitboard/computer/robotics, ) - diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index 3cdc8bc0a4e..25f17d83b07 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -1113,7 +1113,21 @@ greyscale_colors = CIRCUIT_COLOR_SERVICE build_path = /obj/machinery/oven req_components = list(/datum/stock_part/micro_laser = 1) - needs_anchored = FALSE + needs_anchored = TRUE + +/obj/item/circuitboard/machine/stove + name = "Stove" + greyscale_colors = CIRCUIT_COLOR_SERVICE + build_path = /obj/machinery/stove + req_components = list(/datum/stock_part/micro_laser = 1) + needs_anchored = TRUE + +/obj/item/circuitboard/machine/range + name = "Range (Oven & Stove)" + greyscale_colors = CIRCUIT_COLOR_SERVICE + build_path = /obj/machinery/oven/range + req_components = list(/datum/stock_part/micro_laser = 2) + needs_anchored = TRUE /obj/item/circuitboard/machine/dish_drive name = "Dish Drive" diff --git a/code/game/objects/items/food/lizard.dm b/code/game/objects/items/food/lizard.dm index b4dea6bc828..6975991ea24 100644 --- a/code/game/objects/items/food/lizard.dm +++ b/code/game/objects/items/food/lizard.dm @@ -605,73 +605,6 @@ food_flags = FOOD_FINGER_FOOD w_class = WEIGHT_CLASS_SMALL -//Soup Dishes -/obj/item/food/soup/atrakor_dumplings - name = "\improper Atrakor dumpling soup" - desc = "A bowl of rich, meaty dumpling soup, traditionally served during the festival of Atrakor's Might on Tizira. The dumplings are shaped like the Night Sky Lord himself." - icon = 'icons/obj/food/lizard.dmi' - icon_state = "atrakor_dumplings" - food_reagents = list( - /datum/reagent/consumable/nutriment = 6, - /datum/reagent/consumable/nutriment/protein = 10, - /datum/reagent/consumable/nutriment/vitamin = 4, - /datum/reagent/water = 5, - ) - tastes = list("bone broth" = 1, "onion" = 1, "potato" = 1) - foodtypes = MEAT | VEGETABLES | NUTS - -/obj/item/food/soup/meatball_noodles - name = "meatball noodle soup" - desc = "A hearty noodle soup made from meatballs and nizaya in a rich broth. Commonly topped with a handful of chopped nuts." - icon = 'icons/obj/food/lizard.dmi' - icon_state = "meatball_noodles" - food_reagents = list( - /datum/reagent/consumable/nutriment = 6, - /datum/reagent/consumable/nutriment/protein = 8, - /datum/reagent/consumable/nutriment/vitamin = 6, - /datum/reagent/water = 5, - ) - tastes = list("bone broth" = 1, "meat" = 1, "gnocchi" = 1, "peanuts" = 1) - foodtypes = MEAT | VEGETABLES | NUTS - -/obj/item/food/soup/black_broth - name = "\improper Tiziran black broth" - desc = "A bowl of sausage, onion, blood and vinegar, served ice cold. Every bit as rough as it sounds." - icon = 'icons/obj/food/lizard.dmi' - icon_state = "black_broth" - food_reagents = list( - /datum/reagent/consumable/nutriment/protein = 10, - /datum/reagent/blood = 8, - /datum/reagent/consumable/liquidgibs = 2, - ) - tastes = list("vinegar" = 1, "metal" = 1) - foodtypes = MEAT | VEGETABLES | GORE - -/obj/item/food/soup/jellyfish - name = "jellyfish stew" - desc = "A slimy bowl of jellyfish stew. It jiggles if you shake it." - icon = 'icons/obj/food/lizard.dmi' - icon_state = "jellyfish_stew" - food_reagents = list( - /datum/reagent/consumable/nutriment/protein = 10, - /datum/reagent/consumable/nutriment = 6, - ) - tastes = list("slime" = 1) - foodtypes = MEAT | VEGETABLES | GORE - -/obj/item/food/soup/rootbread_soup - name = "rootbread soup" - desc = "A big bowl of spicy, savoury soup made with rootbread. Heavily seasoned, and very tasty." - icon = 'icons/obj/food/lizard.dmi' - icon_state = "rootbread_soup" - food_reagents = list( - /datum/reagent/consumable/nutriment/protein = 6, - /datum/reagent/consumable/nutriment = 10, - /datum/reagent/consumable/nutriment/vitamin = 6, - ) - tastes = list("bread" = 1, "egg" = 1, "chili" = 1, "garlic" = 1) - foodtypes = MEAT | VEGETABLES - //Egg Dishes /obj/item/food/black_eggs name = "black scrambled eggs" diff --git a/code/game/objects/items/food/moth.dm b/code/game/objects/items/food/moth.dm index a78b9d2127a..40e28b0676c 100644 --- a/code/game/objects/items/food/moth.dm +++ b/code/game/objects/items/food/moth.dm @@ -433,122 +433,7 @@ making up a typical meal- tomato soup, roast pumpkin, and blueberry pie." //Thankfully not made by Willy Wonka tastes = list("tomato soup" = 1, "roast pumpkin" = 1, "blueberry pie" = 1) -//Soups -/obj/item/food/soup/moth_cotton_soup - name = "flöfrölenmæsch" //flöf = cotton, rölen = ball, mæsch = soup - desc = "A soup made from raw cotton in a flavourful vegetable broth. Enjoyed only by moths and the criminally tasteless." - icon = 'icons/obj/food/moth.dmi' - icon_state = "moth_cotton_soup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 6, - /datum/reagent/consumable/nutriment/vitamin = 12, - /datum/reagent/water = 5, - ) - tastes = list("cotton" = 1, "broth" = 1) - foodtypes = VEGETABLES | CLOTH - w_class = WEIGHT_CLASS_SMALL - -/obj/item/food/soup/moth_cheese_soup - name = "ælosterrmæsch" //ælo = cheese, sterr = melt, mæsch = soup - desc = "A simple and filling soup made from homemade cheese and sweet potato. \ - The curds provide texture while the whey provides volume- and they both provide deliciousness!" - icon = 'icons/obj/food/moth.dmi' - icon_state = "moth_cheese_soup" - food_reagents = list( - /datum/reagent/consumable/nutriment/protein = 12, - /datum/reagent/consumable/nutriment/vitamin = 4, - /datum/reagent/consumable/nutriment = 4, - ) - tastes = list("cheese" = 1, "cream" = 1, "sweet potato" = 1) - foodtypes = DAIRY | GRAIN - w_class = WEIGHT_CLASS_SMALL - -/obj/item/food/soup/moth_seed_soup - name = "misklmæsch" //miskl = seed, mæsch = soup - desc = "A seed based soup, made by germinating seeds and then boiling them. \ - Produces a particularly bitter broth which is usually balanced by the addition of vinegar." - icon = 'icons/obj/food/moth.dmi' - icon_state = "moth_seed_soup" - food_reagents = list( - /datum/reagent/consumable/nutriment/vitamin = 12, - /datum/reagent/consumable/nutriment = 6, - /datum/reagent/water = 5, - ) - tastes = list("bitterness" = 1, "sourness" = 1) - foodtypes = VEGETABLES - w_class = WEIGHT_CLASS_SMALL - -/obj/item/food/soup/vegetarian_chili - name = "chili sin carne" - desc = "For the hombres who don't want carne." - icon_state = "hotchili" - food_reagents = list( - /datum/reagent/consumable/nutriment = 4, - /datum/reagent/consumable/nutriment/protein = 4, - /datum/reagent/consumable/capsaicin = 3, - /datum/reagent/consumable/tomatojuice = 4, - /datum/reagent/consumable/nutriment/vitamin = 6, - ) - tastes = list("bitterness" = 1, "sourness" = 1) - foodtypes = VEGETABLES - w_class = WEIGHT_CLASS_SMALL - -/obj/item/food/soup/moth_bean_stew - name = "prickeldröndolhaskl" //prickeld = spicy, röndol = bean, haskl = stew - desc = "A spicy bean stew with lots of veggies, commonly served aboard the fleet as a filling and satisfying meal with rice or bread." - icon = 'icons/obj/food/moth.dmi' - icon_state = "moth_bean_stew" - food_reagents = list( - /datum/reagent/consumable/nutriment/protein = 6, - /datum/reagent/consumable/nutriment/vitamin = 14, - /datum/reagent/consumable/nutriment = 4, - ) - tastes = list("beans" = 1, "cabbage" = 1, "spicy sauce" = 1) - foodtypes = VEGETABLES - w_class = WEIGHT_CLASS_SMALL - -/obj/item/food/soup/moth_oat_stew - name = "häfmisklhaskl" //häfmiskl = oat (häf from German hafer meaning oat, miskl meaning seed), haskl = stew - desc = "A hearty oat stew, prepared with oats, sweet potatoes, and various winter vegetables." - icon = 'icons/obj/food/moth.dmi' - icon_state = "moth_oat_stew" - food_reagents = list( - /datum/reagent/consumable/nutriment/vitamin = 14, - /datum/reagent/consumable/nutriment = 8, - ) - tastes = list("oats" = 1, "sweet potato" = 1, "carrot" = 1, "parsnip" = 1, "pumpkin" = 1) - foodtypes = VEGETABLES | GRAIN - w_class = WEIGHT_CLASS_SMALL - -/obj/item/food/soup/moth_fire_soup - name = "tömpröttkrakklmæsch" //tömprött = heart (tömp = thump, rött = muscle), krakkl = fire, mæsch = soup - desc = "Tömpröttkrakklmæsch, or heartburn soup, is a cold soup dish that originated amongst the jungle moths, \ - and is named for two things- its rosy pink colour, and its scorchingly hot chili heat." - icon = 'icons/obj/food/moth.dmi' - icon_state = "moth_fire_soup" - food_reagents = list( - /datum/reagent/consumable/nutriment/protein = 10, - /datum/reagent/consumable/nutriment/vitamin = 10, - ) - tastes = list("love" = 1, "hate" = 1) - foodtypes = VEGETABLES | DAIRY - w_class = WEIGHT_CLASS_SMALL - -/obj/item/food/soup/rice_porridge - name = "rice porridge" - desc = "A plate of rice porridge. It's mostly flavourless, but it does fill a spot. \ - To the Chinese it's congee, and moths call it höllflöfmisklsløsk." //höllflöfmiskl = rice (höllflöf = cloud, miskl = seed), sløsk = porridge - icon = 'icons/obj/food/moth.dmi' - icon_state = "rice_porridge" - food_reagents = list( - /datum/reagent/consumable/nutriment = 6, - /datum/reagent/consumable/nutriment/vitamin = 8, - ) - tastes = list("nothing" = 1) - foodtypes = GRAIN - w_class = WEIGHT_CLASS_SMALL - -/obj/item/food/soup/hua_mulan_congee +/obj/item/food/bowled/hua_mulan_congee name = "\improper Hua Mulan congee" desc = "Nobody is quite sure why this smiley bowl of rice porridge with eggs and bacon is named after a mythological Chinese figure- \ it's just sorta what it's always been called." @@ -563,44 +448,7 @@ foodtypes = MEAT | GRAIN w_class = WEIGHT_CLASS_SMALL -/obj/item/food/soup/toechtauese_rice_porridge - name = "töchtaüse rice porridge" - desc = "Commonly served aboard the mothic fleet, rice porridge with töchtaüse syrup is more palatable than the regular stuff, if even just because it's spicier than normal." - icon = 'icons/obj/food/moth.dmi' - icon_state = "toechtauese_rice_porridge" - food_reagents = list(/datum/reagent/consumable/nutriment/protein = 6, /datum/reagent/consumable/nutriment/vitamin = 12) - tastes = list("sugar" = 1, "spice" = 1) - foodtypes = GRAIN | VEGETABLES - w_class = WEIGHT_CLASS_SMALL - -/obj/item/food/soup/cornmeal_porridge - name = "cornmeal porridge" - desc = "A plate of cornmeal porridge. It's more flavourful than most porridges, and makes a good base for other flavours, too." - icon = 'icons/obj/food/moth.dmi' - icon_state = "cornmeal_porridge" - food_reagents = list( - /datum/reagent/consumable/nutriment = 8, - /datum/reagent/consumable/nutriment/vitamin = 4, - ) - tastes = list("cornmeal" = 1) - foodtypes = GRAIN - w_class = WEIGHT_CLASS_SMALL - -/obj/item/food/soup/cheesy_porridge //milk, polenta, firm cheese, curd cheese, butter - name = "cheesy porridge" - desc = "A rich and creamy bowl of cheesy cornmeal porridge." - icon = 'icons/obj/food/moth.dmi' - icon_state = "cheesy_porridge" - food_reagents = list( - /datum/reagent/consumable/nutriment/protein = 8, - /datum/reagent/consumable/nutriment/vitamin = 4, - /datum/reagent/consumable/nutriment = 8, - ) - tastes = list("cornmeal" = 1, "cheese" = 1, "more cheese" = 1, "lots of cheese" = 1) - foodtypes = DAIRY | GRAIN - w_class = WEIGHT_CLASS_SMALL - -/obj/item/food/soup/fried_eggplant_polenta +/obj/item/food/bowled/fried_eggplant_polenta name = "fried eggplant and polenta" desc = "Polenta loaded with cheese, served with a few discs of fried eggplant and some tomato sauce. Lække!" icon = 'icons/obj/food/moth.dmi' @@ -982,19 +830,6 @@ tastes = list("vanilla" = 1, "clouds" = 1, "chocolate" = 1) foodtypes = VEGETABLES | SUGAR -/obj/item/food/soup/red_porridge - name = "eltsløsk ül a priktæolk" //eltsløsk = red porridge, ül a = with, prikt = sour, æolk = cream - desc = "Red porridge with yoghurt. The name and vegetable ingredients obscure the sweet nature of the dish, which is commonly served as a dessert aboard the fleet." - icon = 'icons/obj/food/moth.dmi' - icon_state = "red_porridge" - food_reagents = list( - /datum/reagent/consumable/nutriment/vitamin = 8, - /datum/reagent/consumable/nutriment/protein = 8, - /datum/reagent/consumable/sugar = 8, - ) - tastes = list("sweet beets" = 1, "sugar" = 1, "sweetened yoghurt" = 1) - foodtypes = VEGETABLES | SUGAR | DAIRY - //misc food /obj/item/food/bubblegum/wake_up name = "wake-up gum" diff --git a/code/game/objects/items/food/salad.dm b/code/game/objects/items/food/salad.dm index dac93e80d2f..0c4dd9a59d6 100644 --- a/code/game/objects/items/food/salad.dm +++ b/code/game/objects/items/food/salad.dm @@ -164,14 +164,66 @@ desc = "A simple bowl, used for soups and salads." icon = 'icons/obj/food/soupsalad.dmi' icon_state = "bowl" - reagent_flags = OPENCONTAINER + base_icon_state = "bowl" + reagent_flags = OPENCONTAINER | DUNKABLE custom_materials = list(/datum/material/glass = 500) w_class = WEIGHT_CLASS_NORMAL custom_price = PAYCHECK_CREW * 0.6 + fill_icon_thresholds = list(0) + fill_icon_state = "fullbowl" + fill_icon = 'icons/obj/food/soupsalad.dmi' + + volume = SOUP_SERVING_SIZE + 5 + gulp_size = 3 /obj/item/reagent_containers/cup/bowl/Initialize(mapload) . = ..() + RegisterSignal(src, COMSIG_PARENT_REAGENT_EXAMINE, PROC_REF(reagent_special_examine)) + AddElement(/datum/element/foodlike_drink) AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/salad/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 6) + AddComponent( \ + /datum/component/takes_reagent_appearance, \ + on_icon_changed = CALLBACK(src, PROC_REF(on_cup_change)), \ + on_icon_reset = CALLBACK(src, PROC_REF(on_cup_reset)), \ + base_container_type = /obj/item/reagent_containers/cup/bowl, \ + ) + +/obj/item/reagent_containers/cup/bowl/on_cup_change(datum/glass_style/style) + . = ..() + fill_icon_thresholds = null + +/obj/item/reagent_containers/cup/bowl/on_cup_reset() + . = ..() + fill_icon_thresholds ||= list(0) + +/** + * Override standard reagent examine + * so that anyone examining a bowl of soup sees the soup but nothing else (unless they have sci goggles) + */ +/obj/item/reagent_containers/cup/bowl/proc/reagent_special_examine(datum/source, mob/user, list/examine_list, can_see_insides = FALSE) + SIGNAL_HANDLER + + if(can_see_insides || reagents.total_volume <= 0) + return + + var/unknown_volume = 0 + var/list/soups_found = list() + for(var/datum/reagent/current_reagent as anything in reagents.reagent_list) + if(istype(current_reagent, /datum/reagent/consumable/nutriment/soup)) + soups_found += "• [round(current_reagent.volume, 0.01)] units of [current_reagent.name]" + else + unknown_volume += current_reagent.volume + + if(!length(soups_found)) + // There was no soup in the pot, do normal examine + return + + examine_list += "Inside, you can see:" + examine_list += soups_found + if(unknown_volume > 0) + examine_list += "• [round(unknown_volume, 0.01)] units of unknown reagents" + + return STOP_GENERIC_REAGENT_EXAMINE // empty salad for custom salads /obj/item/food/salad/empty diff --git a/code/game/objects/items/food/soup.dm b/code/game/objects/items/food/soup.dm index 0985c0842d3..7e84cea5f87 100644 --- a/code/game/objects/items/food/soup.dm +++ b/code/game/objects/items/food/soup.dm @@ -1,281 +1,37 @@ -/obj/item/food/soup +/obj/item/food/bowled w_class = WEIGHT_CLASS_NORMAL icon = 'icons/obj/food/soupsalad.dmi' - trash_type = /obj/item/reagent_containers/cup/bowl bite_consumption = 5 max_volume = 80 - food_reagents = list( - /datum/reagent/consumable/nutriment = 8, - /datum/reagent/water = 5, - /datum/reagent/consumable/nutriment/vitamin = 4, - ) - tastes = list("tasteless soup" = 1) - foodtypes = VEGETABLES + foodtypes = NONE eatverbs = list("slurp", "sip", "inhale", "drink") venue_value = FOOD_PRICE_CHEAP -/obj/item/food/soup/wish +/obj/item/food/bowled/wish name = "wish soup" desc = "I wish this was soup." icon_state = "wishsoup" food_reagents = list(/datum/reagent/water = 10) tastes = list("wishes" = 1) -/obj/item/food/soup/wish/Initialize(mapload) +/obj/item/food/bowled/wish/Initialize(mapload) . = ..() - var/wish_true = prob(25) - if(wish_true) + if(prob(25)) desc = "A wish come true!" reagents.add_reagent(/datum/reagent/consumable/nutriment, 9) reagents.add_reagent(/datum/reagent/consumable/nutriment/vitamin, 1) -/obj/item/food/soup/meatball - name = "meatball soup" - desc = "You've got balls kid, BALLS!" - icon_state = "meatballsoup" +/obj/item/food/bowled/mammi + name = "Mammi" + desc = "A bowl of mushy bread and milk. It reminds you, not too fondly, of a bowel movement." + icon_state = "mammi" food_reagents = list( - /datum/reagent/consumable/nutriment = 6, - /datum/reagent/consumable/nutriment/protein = 6, - /datum/reagent/consumable/nutriment/vitamin = 8, - /datum/reagent/water = 5, + /datum/reagent/consumable/nutriment = 11, + /datum/reagent/consumable/nutriment/vitamin = 2, ) - tastes = list("meat" = 1) - foodtypes = MEAT - venue_value = FOOD_PRICE_NORMAL + foodtypes = SUGAR | DAIRY -/obj/item/food/soup/slime - name = "slime soup" - desc = "If no water is available, you may substitute tears." - icon_state = "slimesoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 6, - /datum/reagent/toxin/slimejelly = 10, - /datum/reagent/consumable/nutriment/vitamin = 9, - /datum/reagent/water = 5, - ) - tastes = list("slime" = 1) - foodtypes = TOXIC | SUGAR - venue_value = FOOD_PRICE_NORMAL - -/obj/item/food/soup/blood - name = "tomato soup" - desc = "Smells like copper." - icon_state = "tomatosoup" - food_reagents = list( - /datum/reagent/consumable/nutriment/protein = 6, - /datum/reagent/blood = 10, /datum/reagent/water = 5, - /datum/reagent/consumable/nutriment/vitamin = 10, - ) - tastes = list("iron" = 1) - foodtypes = GROSS - -/obj/item/food/soup/wingfangchu - name = "wing fang chu" - desc = "A savory dish of alien wing wang in soy." - icon_state = "wingfangchu" - trash_type = /obj/item/reagent_containers/cup/bowl - food_reagents = list( - /datum/reagent/consumable/nutriment/protein = 9, - /datum/reagent/consumable/soysauce = 10, - /datum/reagent/consumable/nutriment/vitamin = 7, - ) - tastes = list("soy" = 1) - foodtypes = MEAT - -/obj/item/food/soup/clownstears - name = "clown's tears" - desc = "Not very funny." - icon_state = "clownstears" - food_reagents = list( - /datum/reagent/consumable/nutriment = 5, - /datum/reagent/consumable/banana = 10, - /datum/reagent/lube = 5, - /datum/reagent/consumable/nutriment/vitamin = 16, - /datum/reagent/consumable/clownstears = 10, - ) - tastes = list("a bad joke" = 1) - foodtypes = FRUIT | SUGAR - -/obj/item/food/soup/vegetable - name = "vegetable soup" - desc = "A true vegan meal." - icon_state = "vegetablesoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 9, - /datum/reagent/water = 5, - /datum/reagent/consumable/nutriment/vitamin = 8, - ) - tastes = list("vegetables" = 1) - foodtypes = VEGETABLES - venue_value = FOOD_PRICE_NORMAL - -/obj/item/food/soup/nettle - name = "nettle soup" - desc = "To think, the botanist would've beat you to death with one of these." - icon_state = "nettlesoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 5, - /datum/reagent/consumable/nutriment/protein = 2, - /datum/reagent/water = 5, - /datum/reagent/consumable/nutriment/vitamin = 9, - /datum/reagent/medicine/omnizine = 5, - ) - tastes = list("nettles" = 1) - foodtypes = VEGETABLES - venue_value = FOOD_PRICE_NORMAL - -/obj/item/food/soup/mystery - name = "mystery soup" - desc = "The mystery is, why aren't you eating it?" - icon_state = "mysterysoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 2, - /datum/reagent/consumable/nutriment/protein = 5, - ) - tastes = list("chaos" = 1) - -/obj/item/food/soup/mystery/Initialize(mapload) - . = ..() - var/extra_reagent = null - extra_reagent = pick( - /datum/reagent/blood, - /datum/reagent/carbon, - /datum/reagent/consumable/banana, - /datum/reagent/consumable/capsaicin, - /datum/reagent/consumable/frostoil, - /datum/reagent/medicine/oculine, - /datum/reagent/medicine/omnizine, - /datum/reagent/toxin, - /datum/reagent/toxin/slimejelly, - ) - reagents.add_reagent(extra_reagent, 5) - reagents.add_reagent(/datum/reagent/consumable/nutriment, 6) - -/obj/item/food/soup/hotchili - name = "hot chili" - desc = "A five alarm Texan Chili!" - icon_state = "hotchili" - food_reagents = list( - /datum/reagent/consumable/nutriment = 4, - /datum/reagent/consumable/nutriment/protein = 6, - /datum/reagent/consumable/capsaicin = 3, - /datum/reagent/consumable/tomatojuice = 4, - /datum/reagent/consumable/nutriment/vitamin = 4, - ) - tastes = list("hot peppers" = 1) - foodtypes = VEGETABLES | MEAT - venue_value = FOOD_PRICE_NORMAL -/obj/item/food/soup/coldchili - name = "cold chili" - desc = "This slush is barely a liquid!" - icon_state = "coldchili" - food_reagents = list( - /datum/reagent/consumable/nutriment = 4, - /datum/reagent/consumable/nutriment/protein = 6, - /datum/reagent/consumable/frostoil = 3, - /datum/reagent/consumable/tomatojuice = 4, - /datum/reagent/consumable/nutriment/vitamin = 4, - ) - tastes = list("tomato" = 1, "mint" = 1) - foodtypes = VEGETABLES | MEAT - -/obj/item/food/soup/clownchili - name = "chili con carnival" - desc = "A delicious stew of meat, chiles, and salty, salty clown tears." - icon_state = "clownchili" - food_reagents = list( - /datum/reagent/consumable/nutriment = 6, - /datum/reagent/consumable/capsaicin = 1, - /datum/reagent/consumable/tomatojuice = 4, - /datum/reagent/consumable/nutriment/vitamin = 4, - /datum/reagent/consumable/banana = 1, - /datum/reagent/consumable/laughter = 1, - ) - tastes = list("tomato" = 1, "hot peppers" = 2, "clown feet" = 2, "kind of funny" = 2, "someone's parents" = 2) - foodtypes = VEGETABLES | MEAT - -/obj/item/food/soup/monkeysdelight - name = "monkey's delight" - desc = "A delicious soup with dumplings and hunks of monkey meat simmered to perfection, in a broth that tastes faintly of bananas." - icon_state = "monkeysdelight" - food_reagents = list( - /datum/reagent/consumable/nutriment = 3, - /datum/reagent/consumable/nutriment/protein = 9, - /datum/reagent/consumable/banana = 5, - /datum/reagent/consumable/nutriment/vitamin = 10, - ) - tastes = list("the jungle" = 1, "banana" = 1) - foodtypes = FRUIT - venue_value = FOOD_PRICE_NORMAL - -/obj/item/food/soup/tomato - name = "tomato soup" - desc = "Drinking this feels like being a vampire! A tomato vampire..." - icon_state = "tomatosoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 6, - /datum/reagent/consumable/tomatojuice = 10, - /datum/reagent/consumable/nutriment/vitamin = 3, - ) - tastes = list("tomato" = 1) - foodtypes = VEGETABLES - -/obj/item/food/soup/tomato/eyeball - name = "eyeball soup" - desc = "It looks back at you..." - icon_state = "eyeballsoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 2, - /datum/reagent/consumable/nutriment/protein = 6, - /datum/reagent/consumable/tomatojuice = 10, - /datum/reagent/consumable/nutriment/vitamin = 4, - /datum/reagent/consumable/liquidgibs = 3, - ) - tastes = list("tomato" = 1, "squirming" = 1) - foodtypes = MEAT | GORE - -/obj/item/food/soup/miso - name = "miso soup" - desc = "The universe's best soup! Yum!!!" - icon_state = "misosoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 4, - /datum/reagent/consumable/nutriment/protein = 8, - /datum/reagent/water = 5, - /datum/reagent/consumable/nutriment/vitamin = 4, - ) - tastes = list("miso" = 1) - foodtypes = VEGETABLES | BREAKFAST - venue_value = FOOD_PRICE_NORMAL - -/obj/item/food/soup/mushroom - name = "chantrelle soup" - desc = "A delicious and hearty mushroom soup." - icon_state = "mushroomsoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 9, - /datum/reagent/consumable/nutriment/vitamin = 6, - ) - tastes = list("mushroom" = 1) - foodtypes = VEGETABLES | DAIRY - -/obj/item/food/soup/beet - name = "beet soup" - desc = "Wait, how do you spell it again...?" - icon_state = "beetsoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 9, - /datum/reagent/water = 5, - /datum/reagent/consumable/nutriment/vitamin = 6, - ) - foodtypes = VEGETABLES - -/obj/item/food/soup/beet/Initialize(mapload) - . = ..() - name = pick("borsch", "bortsch", "borstch", "borsh", "borshch", "borscht") - tastes = list(name = 1) - -/obj/item/food/soup/spacylibertyduff +/obj/item/food/bowled/spacylibertyduff name = "spacy liberty duff" desc = "Jello gelatin, from Alfred Hubbard's cookbook." icon_state = "spacylibertyduff" @@ -288,7 +44,7 @@ tastes = list("jelly" = 1, "mushroom" = 1) foodtypes = VEGETABLES -/obj/item/food/soup/amanitajelly +/obj/item/food/bowled/amanitajelly name = "amanita jelly" desc = "Looks curiously toxic." icon_state = "amanitajelly" @@ -301,187 +57,3 @@ ) tastes = list("jelly" = 1, "mushroom" = 1) foodtypes = VEGETABLES | TOXIC - -/obj/item/food/soup/stew - name = "stew" - desc = "A nice and warm stew. Healthy and strong." - icon_state = "stew" - food_reagents = list( - /datum/reagent/consumable/nutriment = 11, - /datum/reagent/consumable/tomatojuice = 10, - /datum/reagent/consumable/nutriment/vitamin = 6, - ) - bite_consumption = 7 - max_volume = 100 - tastes = list("tomato" = 1, "carrot" = 1) - foodtypes = VEGETABLES | MEAT - venue_value = FOOD_PRICE_NORMAL - -/obj/item/food/soup/sweetpotato - name = "sweet potato soup" - desc = "Delicious sweet potato in soup form." - icon_state = "sweetpotatosoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 12, - /datum/reagent/water = 5, - /datum/reagent/consumable/nutriment/vitamin = 6, - ) - tastes = list("sweet potato" = 1) - foodtypes = VEGETABLES | SUGAR - venue_value = FOOD_PRICE_NORMAL - -/obj/item/food/soup/beet/red - name = "red beet soup" - desc = "Quite a delicacy." - icon_state = "redbeetsoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 12, - /datum/reagent/water = 5, - /datum/reagent/consumable/nutriment/vitamin = 3, - ) - tastes = list("beet" = 1) - foodtypes = VEGETABLES - -/obj/item/food/soup/onion - name = "french onion soup" - desc = "Good enough to make a grown mime cry." - icon_state = "onionsoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 7, - /datum/reagent/consumable/nutriment/protein = 8, - /datum/reagent/consumable/tomatojuice = 8, - /datum/reagent/consumable/nutriment/vitamin = 5, - ) - tastes = list("caramelized onions" = 1) - foodtypes = VEGETABLES | DAIRY - -/obj/item/food/soup/bisque - name = "bisque" - desc = "A classic entree from Space-France." - icon_state = "bisque" - food_reagents = list( - /datum/reagent/consumable/nutriment = 6, - /datum/reagent/consumable/nutriment/protein = 6, - /datum/reagent/water = 5, - /datum/reagent/consumable/nutriment/vitamin = 6, - ) - tastes = list("creamy texture" = 1, "crab" = 4) - foodtypes = MEAT - venue_value = FOOD_PRICE_EXOTIC - -/obj/item/food/soup/electron - name = "electron soup" - desc = "A gastronomic curiosity of ethereal origin. It is famed for the minature weather system formed over a properly prepared soup." - icon_state = "electronsoup" - food_reagents = list( - /datum/reagent/consumable/nutriment = 3, - /datum/reagent/consumable/liquidelectricity/enriched = 12, - ) - tastes = list("mushroom" = 1, "electrons" = 4) - foodtypes = VEGETABLES | TOXIC - -/obj/item/food/soup/bungocurry - name = "bungo curry" - desc = "A spicy vegetable curry made with the humble bungo fruit, Exotic!" - icon_state = "bungocurry" - food_reagents = list( - /datum/reagent/consumable/nutriment = 6, - /datum/reagent/consumable/bungojuice = 9, - /datum/reagent/consumable/capsaicin = 5, - /datum/reagent/consumable/nutriment/vitamin = 5, - ) - tastes = list("bungo" = 2, "hot curry" = 4, "tropical sweetness" = 1) - foodtypes = VEGETABLES | FRUIT | DAIRY - -/obj/item/food/soup/mammi - name = "Mammi" - desc = "A bowl of mushy bread and milk. It reminds you, not too fondly, of a bowel movement." - icon_state = "mammi" - food_reagents = list( - /datum/reagent/consumable/nutriment = 11, - /datum/reagent/consumable/nutriment/vitamin = 2, - ) - -/obj/item/food/soup/peasoup - name = "pea soup" - desc = "A humble split pea soup." - icon_state = "peasoup" - food_reagents = list ( - /datum/reagent/consumable/nutriment = 8, - /datum/reagent/consumable/nutriment/vitamin = 5, - ) - tastes = list("creamy peas"= 2, "parsnip" = 1) - foodtypes = VEGETABLES - -/obj/item/food/soup/indian_curry - name = "indian chicken curry" - desc = "A mild, creamy curry from the old subcontinent. Liked by the Space-British, because it reminds them of the Raj." - icon_state = "indian_curry" - food_reagents = list( - /datum/reagent/consumable/nutriment = 8, - /datum/reagent/consumable/capsaicin = 1, - /datum/reagent/consumable/nutriment/vitamin = 4, - ) - tastes = list("chicken" = 2, "creamy curry" = 4, "earthy heat" = 1) - foodtypes = VEGETABLES | MEAT | DAIRY - venue_value = FOOD_PRICE_NORMAL - -/obj/item/food/soup/oatmeal - name = "oatmeal" - desc = "A nice bowl of oatmeal." - icon_state = "oatmeal" - food_reagents = list( - /datum/reagent/consumable/nutriment = 11, - /datum/reagent/consumable/milk = 10, - /datum/reagent/consumable/nutriment/vitamin = 6, - ) - tastes = list("oats" = 1, "milk" = 1) - foodtypes = DAIRY | GRAIN | BREAKFAST - -/obj/item/food/soup/zurek - name = "zurek" - desc = "A traditional Polish soup composed of vegetables, meat, and an egg. Goes great with bread." - icon_state = "zurek" - food_reagents = list ( - /datum/reagent/consumable/nutriment = 8, - /datum/reagent/consumable/nutriment/vitamin = 2, - /datum/reagent/consumable/nutriment/protein = 2, - ) - tastes = list("creamy vegetables"= 2, "sausage" = 1) - foodtypes = VEGETABLES | MEAT | GRAIN | BREAKFAST - -/obj/item/food/soup/cullen_skink - name = "cullen skink" - desc = "A thick Scottish soup made of smoked fish, potatoes and onions." - icon_state = "cullen_skink" - food_reagents = list ( - /datum/reagent/consumable/nutriment = 12, - /datum/reagent/consumable/nutriment/vitamin = 4, - /datum/reagent/consumable/nutriment/protein = 6, - ) - tastes = list("creamy broth" = 1, "fish" = 1, "vegetables" = 1) - foodtypes = VEGETABLES | SEAFOOD | DAIRY - -/obj/item/food/soup/chicken_noodle_soup - name = "chicken noodle soup" - desc = "A hearty bowl of chicken noodle soup, perfect for when you're stuck at home and sick." - icon_state = "chicken_noodle_soup" - food_reagents = list ( - /datum/reagent/consumable/nutriment = 8, - /datum/reagent/consumable/nutriment/vitamin = 8, - /datum/reagent/consumable/nutriment/protein = 6, - ) - tastes = list("broth" = 1, "chicken" = 1, "noodles" = 1, "carrots" = 1) - foodtypes = VEGETABLES | MEAT | GRAIN - -/obj/item/food/soup/corn_chowder - name = "corn chowder" - desc = "A creamy bowl of corn chowder, with bacon bits and mixed vegetables. One bowl is never enough." - icon_state = "corn_chowder" - food_reagents = list ( - /datum/reagent/consumable/nutriment = 10, - /datum/reagent/consumable/nutriment/vitamin = 8, - /datum/reagent/consumable/nutriment/protein = 6, - ) - tastes = list("creamy broth" = 1, "bacon" = 1, "mixed vegetables" = 1) - foodtypes = VEGETABLES | MEAT diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm index 139777dd757..03c64de236e 100644 --- a/code/game/objects/items/kitchen.dm +++ b/code/game/objects/items/kitchen.dm @@ -73,7 +73,7 @@ w_class = WEIGHT_CLASS_TINY throwforce = 0 custom_materials = list(/datum/material/plastic=80) - custom_price = PAYCHECK_LOWER * 2 + custom_price = PAYCHECK_LOWER * 1 /obj/item/kitchen/fork/plastic/Initialize(mapload) . = ..() @@ -140,6 +140,7 @@ name = "spoon" desc = "Just be careful your food doesn't melt the spoon first." icon_state = "spoon" + base_icon_state = "spoon" w_class = WEIGHT_CLASS_TINY flags_1 = CONDUCT_1 force = 2 @@ -149,17 +150,109 @@ attack_verb_continuous = list("whacks", "spoons", "taps") armor_type = /datum/armor/kitchen_spoon custom_materials = list(/datum/material/iron=120) - custom_price = PAYCHECK_LOWER * 5 + custom_price = PAYCHECK_LOWER * 2 tool_behaviour = TOOL_MINING toolspeed = 25 // Literally 25 times worse than the base pickaxe + var/spoon_sip_size = 5 + +/obj/item/kitchen/spoon/Initialize(mapload) + . = ..() + create_reagents(5, INJECTABLE|OPENCONTAINER|DUNKABLE) + register_item_context() + +/obj/item/kitchen/spoon/add_item_context(obj/item/source, list/context, atom/target, mob/living/user) + if(target.is_open_container()) + context[SCREENTIP_CONTEXT_LMB] = "Empty spoonful" + context[SCREENTIP_CONTEXT_RMB] = "Grab spoonful" + return CONTEXTUAL_SCREENTIP_SET + if(isliving(target)) + context[SCREENTIP_CONTEXT_LMB] = target == user ? "[spoon_sip_size >= reagents.maximum_volume ? "Swallow" : "Taste"] spoonful" : "Give spoonful" + return CONTEXTUAL_SCREENTIP_SET + return NONE + +/obj/item/kitchen/spoon/update_overlays() + . = ..() + if(reagents.total_volume <= 0) + return + var/mutable_appearance/filled_overlay = mutable_appearance(icon, "[base_icon_state]_filled") + filled_overlay.color = mix_color_from_reagents(reagents.reagent_list) + . += filled_overlay + +/obj/item/kitchen/spoon/attack(mob/living/target_mob, mob/living/user, params) + if(!target_mob.reagents || reagents.total_volume <= 0) + return ..() + + if(target_mob == user) + user.visible_message( + span_notice("[user] scoops a spoonful into [user.p_their()] mouth."), + span_notice("You scoop a spoonful into your mouth.") + ) + + else + to_chat(target_mob, span_userdanger("[target_mob.is_blind() ? "Someone" : "[user]"] forces a spoon into your face!")) + target_mob.balloon_alert(user, "feeding spoonful...") + if(!do_after(user, 3 SECONDS, target_mob)) + target_mob.balloon_alert(user, "interrupted!") + return TRUE + + to_chat(target_mob, span_userdanger("[target_mob.is_blind() ? "You are forced to" : "[user] forces you to"] swallow a spoonful of something!")) + user.visible_message( + span_danger("[user] scoops a spoonful into [target_mob]'s mouth."), + span_notice("You scoop a spoonful into [target_mob]'s mouth.") + ) + + playsound(target_mob, 'sound/items/drink.ogg', rand(10,50), vary = TRUE) + reagents.trans_to(target_mob, spoon_sip_size, methods = INGEST) + return TRUE + +/obj/item/kitchen/spoon/pre_attack(atom/attacked_atom, mob/living/user, params) + . = ..() + if(.) + return + if(isliving(attacked_atom)) + return + if(!attacked_atom.is_open_container()) + return + if(reagents.total_volume <= 0) + return + + var/amount_given = reagents.trans_to(attacked_atom, reagents.maximum_volume) + if(amount_given >= reagents.total_volume) + attacked_atom.balloon_alert(user, "spoon emptied") + else if(amount_given > 0) + attacked_atom.balloon_alert(user, "spoon partially emptied") + else + attacked_atom.balloon_alert(user, "it's full!") + update_appearance(UPDATE_OVERLAYS) + return TRUE + +/obj/item/kitchen/spoon/pre_attack_secondary(atom/attacked_atom, mob/living/user, params) + . = ..() + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) + return + if(isliving(attacked_atom)) + return SECONDARY_ATTACK_CALL_NORMAL + if(!attacked_atom.is_open_container()) + return SECONDARY_ATTACK_CALL_NORMAL + + if(reagents.total_volume >= reagents.maximum_volume || attacked_atom.reagents.total_volume <= 0) + return SECONDARY_ATTACK_CALL_NORMAL + + if(attacked_atom.reagents.trans_to(src, reagents.maximum_volume)) + attacked_atom.balloon_alert(user, "grabbed spoonful") + else + attacked_atom.balloon_alert(user, "spoon is full!") + update_appearance(UPDATE_OVERLAYS) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + /obj/item/kitchen/spoon/plastic name = "plastic spoon" icon_state = "plastic_spoon" force = 0 custom_materials = list(/datum/material/plastic=120) - custom_price = PAYCHECK_LOWER * 2 toolspeed = 75 // The plastic spoon takes 5 minutes to dig through a single mineral turf... It's one, continuous, breakable, do_after... + custom_price = PAYCHECK_LOWER * 1 /datum/armor/kitchen_spoon fire = 50 @@ -169,4 +262,17 @@ . = ..() AddElement(/datum/element/easily_fragmented, PLASTIC_BREAK_PROBABILITY) +/obj/item/kitchen/spoon/soup_ladle + name = "ladle" + desc = "What is a ladle but a comically large spoon?" + icon_state = "ladle" + base_icon_state = "ladle" + inhand_icon_state = "spoon" + custom_price = PAYCHECK_LOWER * 4 + spoon_sip_size = 3 // just a taste + +/obj/item/kitchen/spoon/soup_ladle/Initialize(mapload) + . = ..() + create_reagents(SOUP_SERVING_SIZE + 5, INJECTABLE|OPENCONTAINER) + #undef PLASTIC_BREAK_PROBABILITY diff --git a/code/modules/asset_cache/assets/crafting.dm b/code/modules/asset_cache/assets/crafting.dm index 8f38cd19bfa..80b95be169f 100644 --- a/code/modules/asset_cache/assets/crafting.dm +++ b/code/modules/asset_cache/assets/crafting.dm @@ -2,33 +2,47 @@ /datum/asset/spritesheet/crafting name = "crafting" -/datum/asset/spritesheet/crafting/cooking - name = "cooking" - /datum/asset/spritesheet/crafting/create_spritesheets() var/id = 1 for(var/atom in GLOB.crafting_recipes_atoms) add_atom_icon(atom, id++) add_tool_icons() +/datum/asset/spritesheet/crafting/cooking + name = "cooking" + /datum/asset/spritesheet/crafting/cooking/create_spritesheets() var/id = 1 for(var/atom in GLOB.cooking_recipes_atoms) add_atom_icon(atom, id++) -///Adds the atom icon to the spritesheet with given ID -/datum/asset/spritesheet/crafting/proc/add_atom_icon(atom, id) - var/obj/obj = initial(atom) - if(ispath(atom, /datum/reagent)) - var/datum/reagent/reagent = atom - obj = initial(reagent.default_container) - var/icon_file = initial(obj.icon_preview) || initial(obj.icon) - var/icon_state = initial(obj.icon_state_preview) || initial(obj.icon_state) - #ifdef UNIT_TESTS - if(!(icon_state in icon_states(icon_file))) - stack_trace("Atom [atom] with icon '[icon_file]' missing state '[icon_state]'") - return - #endif +/** + * Adds the ingredient icon to the spritesheet with given ID + * + * ingredient_typepath can be an obj typepath OR a reagent typepath + * + * If it a reagent, it will use the default container's icon state, + * OR if it has a glass style associated, it will use that + */ +/datum/asset/spritesheet/crafting/proc/add_atom_icon(ingredient_typepath, id) + var/icon_file + var/icon_state + var/obj/preview_item = ingredient_typepath + if(ispath(ingredient_typepath, /datum/reagent)) + var/datum/reagent/reagent = ingredient_typepath + preview_item = initial(reagent.default_container) + var/datum/glass_style/style = GLOB.glass_style_singletons[preview_item]?[reagent] + if(istype(style)) + icon_file = style.icon + icon_state = style.icon_state + + icon_file ||= initial(preview_item.icon_preview) || initial(preview_item.icon) + icon_state ||= initial(preview_item.icon_state_preview) || initial(preview_item.icon_state) + + if(PERFORM_ALL_TESTS(focus_only/bad_cooking_crafting_icons)) + if(!icon_exists(icon_file, icon_state, scream = TRUE)) + return + Insert("a[id]", icon(icon_file, icon_state, SOUTH)) ///Adds tool icons to the spritesheet diff --git a/code/modules/cargo/bounties/chef.dm b/code/modules/cargo/bounties/chef.dm index 905e04dbba1..db65252df68 100644 --- a/code/modules/cargo/bounties/chef.dm +++ b/code/modules/cargo/bounties/chef.dm @@ -7,12 +7,18 @@ /obj/item/food/cakeslice/birthday = TRUE ) -/datum/bounty/item/chef/soup +/datum/bounty/reagent/chef/soup name = "Soup" - description = "To quell the homeless uprising, Nanotrasen will be serving soup to all underpaid workers. Ship any type of soup." - reward = CARGO_CRATE_VALUE * 6 - required_count = 3 - wanted_types = list(/obj/item/food/soup = TRUE) + description = "To quell the homeless uprising, Nanotrasen will be serving soup to all underpaid workers." + +/datum/bounty/reagent/chef/soup/New() + . = ..() + required_volume = pick(10, 15, 20, 25) + wanted_reagent = pick(subtypesof(/datum/reagent/consumable/nutriment/soup)) + reward = CARGO_CRATE_VALUE * round(required_volume / 3) + // In the future there could be tiers of soup bounty corresponding to soup difficulty + // (IE, stew is harder to make than tomato soup, so it should reward more) + description += " Send us [required_volume] units of [initial(wanted_reagent.name)]." /datum/bounty/item/chef/popcorn name = "Popcorn Bags" diff --git a/code/modules/cargo/bounty.dm b/code/modules/cargo/bounty.dm index 18d176ddc86..aa527e84762 100644 --- a/code/modules/cargo/bounty.dm +++ b/code/modules/cargo/bounty.dm @@ -47,7 +47,7 @@ if(CIV_JOB_ROBO) chosen_type = pick(subtypesof(/datum/bounty/item/mech)) if(CIV_JOB_CHEF) - chosen_type = pick(subtypesof(/datum/bounty/item/chef)) + chosen_type = pick(subtypesof(/datum/bounty/item/chef) + subtypesof(/datum/bounty/reagent/chef)) if(CIV_JOB_SEC) chosen_type = pick(subtypesof(/datum/bounty/item/security)) if(CIV_JOB_DRINK) diff --git a/code/modules/cargo/markets/market_items/consumables.dm b/code/modules/cargo/markets/market_items/consumables.dm index 32955b8f843..153241e5d3d 100644 --- a/code/modules/cargo/markets/market_items/consumables.dm +++ b/code/modules/cargo/markets/market_items/consumables.dm @@ -2,9 +2,9 @@ category = "Consumables" /datum/market_item/consumable/clown_tears - name = "Bowl of Clown's Tears" + name = "Bottle of Clown's Tears" desc = "Guaranteed fresh from Weepy Boggins Tragic Kitchen" - item = /obj/item/food/soup/clownstears + item = /obj/item/reagent_containers/cup/bottle/clownstears stock = 1 price_min = CARGO_CRATE_VALUE * 2.6 diff --git a/code/modules/events/holiday/easter.dm b/code/modules/events/holiday/easter.dm index f3e853eb4b6..f4fa2a038e0 100644 --- a/code/modules/events/holiday/easter.dm +++ b/code/modules/events/holiday/easter.dm @@ -186,7 +186,7 @@ /obj/item/food/chocolatebar = 1, /datum/reagent/consumable/milk = 5 ) - result = /obj/item/food/soup/mammi + result = /obj/item/food/bowled/mammi category = CAT_MISCFOOD /obj/item/food/chocolatebunny diff --git a/code/modules/food_and_drinks/machinery/griddle.dm b/code/modules/food_and_drinks/machinery/griddle.dm index e7db23898be..2bb01f65e57 100644 --- a/code/modules/food_and_drinks/machinery/griddle.dm +++ b/code/modules/food_and_drinks/machinery/griddle.dm @@ -6,6 +6,7 @@ density = TRUE pass_flags_self = PASSMACHINE | PASSTABLE| LETPASSTHROW // It's roughly the height of a table. idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.05 + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION layer = BELOW_OBJ_LAYER circuit = /obj/item/circuitboard/machine/griddle processing_flags = START_PROCESSING_MANUALLY @@ -152,9 +153,7 @@ return STORAGE_DUMP_HANDLED /obj/machinery/griddle/process(delta_time) - ..() - for(var/i in griddled_objects) - var/obj/item/griddled_item = i + for(var/obj/item/griddled_item as anything in griddled_objects) if(SEND_SIGNAL(griddled_item, COMSIG_ITEM_GRILL_PROCESS, src, delta_time) & COMPONENT_HANDLED_GRILLING) continue griddled_item.fire_act(1000) //Hot hot hot! @@ -163,6 +162,10 @@ use_power(active_power_usage) + var/turf/griddle_loc = loc + if(isturf(griddle_loc)) + griddle_loc.hotspot_expose(800, 100) + /obj/machinery/griddle/update_icon_state() icon_state = "griddle[variant]_[on ? "on" : "off"]" return ..() diff --git a/code/modules/food_and_drinks/machinery/oven.dm b/code/modules/food_and_drinks/machinery/oven.dm index a93e69bd8de..a63b41ef58e 100644 --- a/code/modules/food_and_drinks/machinery/oven.dm +++ b/code/modules/food_and_drinks/machinery/oven.dm @@ -13,12 +13,15 @@ desc = "Why do they call it oven when you of in the cold food of out hot eat the food?" icon = 'icons/obj/machines/kitchenmachines.dmi' icon_state = "oven_off" + base_icon_state = "oven" density = TRUE pass_flags_self = PASSMACHINE | LETPASSTHROW layer = BELOW_OBJ_LAYER circuit = /obj/item/circuitboard/machine/oven processing_flags = START_PROCESSING_MANUALLY resistance_flags = FIRE_PROOF + idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.1 + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.8 ///The tray inside of this oven, if there is one. var/obj/item/plate/oven_tray/used_tray @@ -32,36 +35,44 @@ /obj/machinery/oven/Initialize(mapload) . = ..() oven_loop = new(src) - add_tray_to_oven(new /obj/item/plate/oven_tray(src)) //Start with a tray + if(mapload) + add_tray_to_oven(new /obj/item/plate/oven_tray(src)) //Start with a tray /obj/machinery/oven/Destroy() QDEL_NULL(oven_loop) QDEL_NULL(particles) - . = ..() + return ..() + +/// Used to determine if the oven appears active and cooking, or offline. +/obj/machinery/oven/proc/appears_active() + return !open && length(used_tray?.contents) && !(machine_stat & (BROKEN|NOPOWER)) /obj/machinery/oven/update_icon_state() - if(!open && used_tray?.contents.len) - icon_state = "oven_on" + if(appears_active()) + icon_state = "[base_icon_state]_on" else - icon_state = "oven_off" + icon_state = "[base_icon_state]_off" return ..() /obj/machinery/oven/update_overlays() . = ..() if(open) - var/mutable_appearance/door_overlay = mutable_appearance(icon, "oven_lid_open") + var/mutable_appearance/door_overlay = mutable_appearance(icon, "[base_icon_state]_lid_open") door_overlay.pixel_y = OVEN_LID_Y_OFFSET . += door_overlay else - . += mutable_appearance(icon, "oven_lid_closed") - if(used_tray?.contents.len) - . += emissive_appearance(icon, "oven_light_mask", src, alpha = src.alpha) + . += mutable_appearance(icon, "[base_icon_state]_lid_closed") + if(length(used_tray?.contents)) + . += emissive_appearance(icon, "[base_icon_state]_light_mask", src, alpha = src.alpha) /obj/machinery/oven/process(delta_time) - ..() - if(!used_tray) //Are we actually working? + if(!appears_active()) set_smoke_state(OVEN_SMOKE_STATE_NONE) + update_baking_audio() + update_appearance(UPDATE_ICON) + end_processing() return + ///We take the worst smoke state, so if something is burning we always know. var/worst_cooked_food_state = 0 for(var/obj/item/baked_item in used_tray.contents) @@ -152,7 +163,7 @@ /obj/machinery/oven/proc/update_baking_audio() if(!oven_loop) return - if(!open && used_tray?.contents.len) + if(appears_active()) oven_loop.start() else oven_loop.stop() @@ -170,7 +181,7 @@ if(OVEN_SMOKE_STATE_NEUTRAL) particles = new /particles/smoke/steam() if(OVEN_SMOKE_STATE_GOOD) - particles = new /particles/smoke/steam/mild + particles = new /particles/smoke/steam/mild() /obj/machinery/oven/crowbar_act(mob/living/user, obj/item/tool) return default_deconstruction_crowbar(tool, ignore_panel = TRUE) @@ -179,6 +190,22 @@ default_unfasten_wrench(user, tool, time = 2 SECONDS) return TOOL_ACT_TOOLTYPE_SUCCESS +/obj/machinery/oven/range + name = "range" + desc = "And Oven AND a Stove? I guess that's why it's got range!" + icon_state = "range_off" + base_icon_state = "range" + pass_flags_self = PASSMACHINE|PASSTABLE|LETPASSTHROW // Like the griddle, short + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 1.2 + circuit = /obj/item/circuitboard/machine/range + +/obj/machinery/oven/range/Initialize(mapload) + . = ..() + var/obj/item/reagent_containers/cup/soup_pot/mapload_container + if(mapload) + mapload_container = new(loc) + + AddComponent(/datum/component/stove, container_x = -6, container_y = 14, spawn_container = mapload_container) /obj/item/plate/oven_tray name = "oven tray" diff --git a/code/modules/food_and_drinks/machinery/stove.dm b/code/modules/food_and_drinks/machinery/stove.dm new file mode 100644 index 00000000000..8382e6ff98f --- /dev/null +++ b/code/modules/food_and_drinks/machinery/stove.dm @@ -0,0 +1,201 @@ +/obj/machinery/stove + name = "stove" + desc = "You'd think this thing would be more useful in here." + icon = 'icons/obj/machines/kitchen_stove.dmi' + icon_state = "stove" + base_icon_state = "stove" + density = TRUE + pass_flags_self = PASSMACHINE | LETPASSTHROW + layer = BELOW_OBJ_LAYER + circuit = /obj/item/circuitboard/machine/stove + processing_flags = START_PROCESSING_MANUALLY + resistance_flags = FIRE_PROOF + idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.1 + active_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.8 + + // Stove icon is 32x48, we'll use a Range for preview instead + icon_preview = 'icons/obj/machines/kitchenmachines.dmi' + icon_state_preview = "range_off" + +/obj/machinery/stove/Initialize(mapload) + . = ..() + AddComponent(/datum/component/stove, container_x = -6, container_y = 16) + +// Soup pot for cooking soup +// Future addention ideas: +// - Thermostat you can stick in the pot to see in examine the temperature +// - Tasting the pot to learn its exact contents w/o sci goggles (chef skillchip?) +/obj/item/reagent_containers/cup/soup_pot + name = "soup pot" + desc = "A tall soup designed to mix and cook all kinds of soup." + icon = 'icons/obj/soup_pot.dmi' + icon_state = "pot" + base_icon_state = "pot" + volume = 200 + possible_transfer_amounts = list(20, 50, 100, 200) + amount_per_transfer_from_this = 50 + amount_list_position = 2 + reagent_flags = REFILLABLE | DRAINABLE + custom_materials = list(/datum/material/iron = 5000) + w_class = WEIGHT_CLASS_BULKY + custom_price = PAYCHECK_LOWER * 8 + fill_icon_thresholds = null + + /// Max number of ingredients we can add + var/max_ingredients = 24 + /// A lazylist of all the ingredients we have added + var/list/obj/item/added_ingredients + +/obj/item/reagent_containers/cup/soup_pot/Initialize(mapload, vol) + . = ..() + RegisterSignal(reagents, COMSIG_REAGENTS_CLEAR_REAGENTS, PROC_REF(on_reagents_cleared)) + RegisterSignal(src, COMSIG_PARENT_REAGENT_EXAMINE, PROC_REF(reagent_special_examine)) + register_context() + +/obj/item/reagent_containers/cup/soup_pot/add_context(atom/source, list/context, obj/item/held_item, mob/user) + if(isnull(held_item)) + context[SCREENTIP_CONTEXT_RMB] = "Remove ingredient" + return CONTEXTUAL_SCREENTIP_SET + + else if(can_add_ingredient(held_item)) + context[SCREENTIP_CONTEXT_LMB] = "Add ingredient" + return CONTEXTUAL_SCREENTIP_SET + + return NONE + +/obj/item/reagent_containers/cup/soup_pot/examine(mob/user) + . = ..() + . += span_notice("There's room for [max_ingredients - LAZYLEN(added_ingredients)] more ingredients \ + or [reagents.maximum_volume - reagents.total_volume] more units of reagents in there.") + +/** + * Override standard reagent examine with something a bit more sensible for the soup pot, + * including the ingredients we have within as well + */ +/obj/item/reagent_containers/cup/soup_pot/proc/reagent_special_examine(datum/source, mob/user, list/examine_list, can_see_insides = FALSE) + SIGNAL_HANDLER + + examine_list += "Inside, you can see:" + + if(LAZYLEN(added_ingredients) || reagents.total_volume > 0) + var/list/ingredient_amounts = list() + for(var/obj/item/ingredient as anything in added_ingredients) + ingredient_amounts[ingredient.type] += 1 + + for(var/obj/item/ingredient_type as anything in ingredient_amounts) + examine_list += "• [ingredient_amounts[ingredient_type]] [initial(ingredient_type.name)]\s" + + var/unknown_volume = 0 + for(var/datum/reagent/current_reagent as anything in reagents.reagent_list) + if(can_see_insides \ + || istype(current_reagent, /datum/reagent/water) \ + || istype(current_reagent, /datum/reagent/consumable) \ + ) + examine_list += "• [round(current_reagent.volume, 0.01)] units of [current_reagent.name]" + else + unknown_volume += current_reagent.volume + + if(unknown_volume > 0) + examine_list += "• [round(unknown_volume, 0.01)] units of unknown reagents" + + if(reagents.total_volume > 0) + if(can_see_insides) + examine_list += span_notice("The contents of [src] have a temperature of [reagents.chem_temp]K.") + else if(reagents.chem_temp > WATER_BOILING_POINT) // boiling point + examine_list += span_notice("The contents of [src] are boiling.") + + else + examine_list += "Nothing." + + if(reagents.is_reacting) + examine_list += span_warning("It is currently mixing!") + + return STOP_GENERIC_REAGENT_EXAMINE + +/obj/item/reagent_containers/cup/soup_pot/Exited(atom/movable/gone, direction) + . = ..() + LAZYREMOVE(added_ingredients, gone) + +/obj/item/reagent_containers/cup/soup_pot/attackby(obj/item/attacking_item, mob/user, params) + . = ..() + if(.) + return + + if(!can_add_ingredient(attacking_item)) + return FALSE + + // Too many ingredients + if(LAZYLEN(added_ingredients) >= max_ingredients) + balloon_alert(user, "too many ingredients!") + return TRUE + if(!user.transferItemToLoc(attacking_item, src)) + balloon_alert(user, "can't add that!") + return TRUE + + var/atom/balloon_loc = ismachinery(loc) ? loc : src + balloon_loc.balloon_alert(user, "ingredient added") + user.face_atom(balloon_loc) + LAZYADD(added_ingredients, attacking_item) + + update_appearance(UPDATE_OVERLAYS) + return TRUE + +/obj/item/reagent_containers/cup/soup_pot/attack_hand_secondary(mob/user, list/modifiers) + if(!LAZYLEN(added_ingredients)) + return SECONDARY_ATTACK_CALL_NORMAL + + var/obj/item/removed = added_ingredients[1] + removed.forceMove(get_turf(src)) + user.put_in_hands(removed) + var/atom/balloon_loc = ismachinery(loc) ? loc : src + balloon_loc.balloon_alert(user, "ingredient removed") + user.face_atom(balloon_loc) + + update_appearance(UPDATE_OVERLAYS) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/item/reagent_containers/cup/soup_pot/proc/can_add_ingredient(obj/item/ingredient) + // Let default reagent handling take this + if(ingredient.is_open_container()) + return FALSE + // To big for the pot + if(ingredient.w_class >= WEIGHT_CLASS_BULKY) + return FALSE + if(ingredient.item_flags & (ABSTRACT|DROPDEL|HAND_ITEM)) + return FALSE + if(HAS_TRAIT(ingredient, TRAIT_NO_STORAGE_INSERT)) + return FALSE + return TRUE + +/obj/item/reagent_containers/cup/soup_pot/proc/on_reagents_cleared(datum/source, datum/reagent/changed) + SIGNAL_HANDLER + + dump_ingredients() + +/obj/item/reagent_containers/cup/soup_pot/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum, do_splash) + . = ..() + if(!. && LAZYLEN(added_ingredients)) + // Clearing reagents Will do this for us already, but if we have no reagents this is a failsafe + dump_ingredients() + +/obj/item/reagent_containers/cup/soup_pot/proc/dump_ingredients(atom/drop_loc = drop_location()) + for(var/obj/item/ingredient as anything in added_ingredients) + ingredient.forceMove(drop_loc) + ingredient.pixel_x += rand(-4, 4) + ingredient.pixel_y += rand(-4, 4) + ingredient.SpinAnimation(loops = 1) + update_appearance(UPDATE_OVERLAYS) + +/obj/item/reagent_containers/cup/soup_pot/update_overlays() + . = ..() + if(length(added_ingredients) <= 0 && reagents.total_volume <= 0) + return + var/mutable_appearance/filled_overlay = mutable_appearance(icon, "[base_icon_state]_filling_overlay") + var/list/food_reagents = list() + for(var/obj/item/ingredient as anything in added_ingredients) + if(isnull(ingredient.reagents)) + continue + food_reagents |= ingredient.reagents.reagent_list + + filled_overlay.color = mix_color_from_reagents(reagents.reagent_list + food_reagents) + . += filled_overlay diff --git a/code/modules/food_and_drinks/machinery/stove_component.dm b/code/modules/food_and_drinks/machinery/stove_component.dm new file mode 100644 index 00000000000..cb3e4e051fa --- /dev/null +++ b/code/modules/food_and_drinks/machinery/stove_component.dm @@ -0,0 +1,244 @@ +/** + * # Stove Component + * + * Makes the attached object a stove + * + * Pots can be put on the stove to make soup, and attack-handing it will start processing + * where it will heat up the pot's reagents inside + */ +/datum/component/stove + /// Whether we're currently cooking + VAR_FINAL/on = FALSE + /// A reference to the current soup pot overtop + VAR_FINAL/obj/item/container + /// A particle holder for the smoke that comes out of the soup while a container is cooking. + VAR_FINAL/obj/effect/abstract/particle_holder/soup_smoke + /// Typepath of particles to use for the particle holder. + VAR_FINAL/particle_type = /particles/smoke/steam/mild + /// The color of the flames around the burner. + var/flame_color = "#006eff" + /// Container's pixel x when placed on the stove + var/container_x = 0 + /// Container's pixel y when placed on the stove + var/container_y = 8 + /// Modifies how much temperature is exposed to the reagents, and in turn modifies how fast the reagents are heated. + var/heat_coefficient = 0.033 + +/datum/component/stove/Initialize(container_x = 0, container_y = 8, obj/item/spawn_container) + if(!ismachinery(parent)) + return COMPONENT_INCOMPATIBLE + + src.container_x = container_x + src.container_y = container_y + + // To allow maploaded pots on top of your stove. + if(spawn_container) + spawn_container.forceMove(parent) + add_container(spawn_container) + +/datum/component/stove/RegisterWithParent() + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, PROC_REF(on_attackby)) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND_SECONDARY, PROC_REF(on_attack_hand_secondary)) + RegisterSignal(parent, COMSIG_ATOM_EXITED, PROC_REF(on_exited)) + RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_overlay_update)) + RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, PROC_REF(on_deconstructed)) + RegisterSignal(parent, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context)) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_MACHINERY_REFRESH_PARTS, PROC_REF(on_refresh_parts)) + + var/obj/machinery/real_parent = parent + real_parent.flags_1 |= HAS_CONTEXTUAL_SCREENTIPS_1 + +/datum/component/stove/UnregisterFromParent() + if(!QDELING(parent)) + var/obj/machinery/real_parent = parent + container.forceMove(real_parent.drop_location()) + + QDEL_NULL(soup_smoke) + + UnregisterSignal(parent, list( + COMSIG_ATOM_ATTACK_HAND_SECONDARY, + COMSIG_OBJ_DECONSTRUCT, + COMSIG_ATOM_EXITED, + COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, + COMSIG_ATOM_UPDATE_OVERLAYS, + COMSIG_PARENT_ATTACKBY, + COMSIG_PARENT_EXAMINE, + COMSIG_MACHINERY_REFRESH_PARTS, + )) + +/datum/component/stove/process(delta_time) + var/obj/machinery/real_parent = parent + if(real_parent.machine_stat & NOPOWER) + turn_off() + return + + container?.reagents.expose_temperature(SOUP_BURN_TEMP + 80, heat_coefficient) + real_parent.use_power(real_parent.active_power_usage) + + var/turf/stove_spot = real_parent.loc + if(isturf(stove_spot)) + stove_spot.hotspot_expose(SOUP_BURN_TEMP + 80, 100) + +/datum/component/stove/proc/turn_on() + var/obj/machinery/real_parent = parent + if(real_parent.machine_stat & (BROKEN|NOPOWER)) + return + START_PROCESSING(SSmachines, src) + on = TRUE + real_parent.update_appearance(UPDATE_OVERLAYS) + +/datum/component/stove/proc/turn_off() + var/obj/machinery/real_parent = parent + STOP_PROCESSING(SSmachines, src) + on = FALSE + real_parent.update_appearance(UPDATE_OVERLAYS) + +/datum/component/stove/proc/on_attack_hand_secondary(obj/machinery/source) + SIGNAL_HANDLER + + var/obj/machinery/real_parent = parent + if(on) + turn_off() + + else if(real_parent.machine_stat & (BROKEN|NOPOWER)) + real_parent.balloon_alert_to_viewers("no power!") + return COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN + + else + turn_on() + + real_parent.balloon_alert_to_viewers("burners [on ? "on" : "off"]") + playsound(real_parent, 'sound/machines/click.ogg', 30, TRUE) + playsound(real_parent, on ? 'sound/items/welderactivate.ogg' : 'sound/items/welderdeactivate.ogg', 15, TRUE) + + return COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN + +/datum/component/stove/proc/on_attackby(obj/machinery/source, obj/item/attacking_item, mob/user, params) + SIGNAL_HANDLER + + if(!attacking_item.is_open_container()) + return + if(!isnull(container)) + to_chat(span_warning("You wouldn't dare try to cook two things on the same stove simultaneously. \ + What if it cross contaminates?")) + return COMPONENT_NO_AFTERATTACK + + if(user.transferItemToLoc(attacking_item, parent)) + add_container(attacking_item, user) + to_chat(user, span_notice("You put [attacking_item] onto [parent].")) + return COMPONENT_NO_AFTERATTACK + +/datum/component/stove/proc/on_exited(obj/machinery/source, atom/movable/gone, direction) + SIGNAL_HANDLER + + if(gone == container) + remove_container() + +/datum/component/stove/proc/on_deconstructed(obj/machinery/source) + SIGNAL_HANDLER + + container.forceMove(source.drop_location()) + +/datum/component/stove/proc/on_overlay_update(obj/machinery/source, list/overlays) + SIGNAL_HANDLER + + update_smoke() + + if(!on) + return + + var/obj/real_parent = parent + + // Flames around the pot + var/mutable_appearance/flames = mutable_appearance(real_parent.icon, "[real_parent.base_icon_state]_on_flame", alpha = real_parent.alpha) + flames.color = flame_color + overlays += flames + overlays += emissive_appearance(real_parent.icon, "[real_parent.base_icon_state]_on_flame", real_parent, alpha = real_parent.alpha) + + // A green light that shows it's active + var/mutable_appearance/light = mutable_appearance(real_parent.icon, "[real_parent.base_icon_state]_on_overlay", alpha = real_parent.alpha) + light.color = "#00ff00" + overlays += light + overlays += emissive_appearance(real_parent.icon, "[real_parent.base_icon_state]_on_overlay", real_parent, alpha = real_parent.alpha) + +/datum/component/stove/proc/on_requesting_context(obj/machinery/source, list/context, obj/item/held_item) + SIGNAL_HANDLER + + if(isnull(held_item)) + context[SCREENTIP_CONTEXT_RMB] = "Turn [on ? "off":"on"] burner" + return CONTEXTUAL_SCREENTIP_SET + + if(held_item.is_open_container()) + context[SCREENTIP_CONTEXT_LMB] = "Place container" + return CONTEXTUAL_SCREENTIP_SET + +/datum/component/stove/proc/on_examine(obj/machinery/source, mob/user, list/examine_list) + SIGNAL_HANDLER + + examine_list += span_notice("You can turn the stovetop burners [on ? "off" : "on"] with right click.") + +/datum/component/stove/proc/on_refresh_parts(obj/machinery/source) + SIGNAL_HANDLER + + var/new_multiplier = 0 + for(var/datum/stock_part/micro_laser/part in source.component_parts) + new_multiplier += (part.tier * 0.5) + + heat_coefficient = initial(heat_coefficient) * max(round(new_multiplier), 1) + +/datum/component/stove/proc/add_container(obj/item/new_container, mob/user) + var/obj/real_parent = parent + real_parent.vis_contents += new_container + new_container.flags_1 |= IS_ONTOP_1 + new_container.vis_flags |= VIS_INHERIT_PLANE + + container = new_container + container.pixel_x = container_x + container.pixel_y = container_y + + update_smoke_type() + RegisterSignal(container.reagents, COMSIG_REAGENTS_TEMP_CHANGE, PROC_REF(update_smoke_type)) + real_parent.update_appearance(UPDATE_OVERLAYS) + +/datum/component/stove/proc/remove_container() + var/obj/real_parent = parent + container.flags_1 &= ~IS_ONTOP_1 + container.vis_flags &= ~VIS_INHERIT_PLANE + real_parent.vis_contents -= container + + UnregisterSignal(container.reagents, COMSIG_REAGENTS_TEMP_CHANGE) + + container.pixel_x = container.base_pixel_x + container.pixel_y = container.base_pixel_y + container = null + + update_smoke_type() + real_parent.update_appearance(UPDATE_OVERLAYS) + +/datum/component/stove/proc/update_smoke_type(datum/source, new_temp, old_temp) + SIGNAL_HANDLER + + var/existing_temp = container?.reagents.chem_temp || 0 + if(existing_temp >= SOUP_BURN_TEMP) + particle_type = /particles/smoke/steam/bad + else if(existing_temp >= WATER_BOILING_POINT) + particle_type = /particles/smoke/steam/mild + else + particle_type = null + + update_smoke() + +/datum/component/stove/proc/update_smoke() + if(on && container?.reagents.total_volume > 0) + // Don't override existing particles, wasteful + if(isnull(soup_smoke) || soup_smoke.particles.type != particle_type) + QDEL_NULL(soup_smoke) + if(isnull(particle_type)) + return + // this gets badly murdered by sidemap + soup_smoke = new(parent, particle_type) + soup_smoke.set_particle_position(list(container_x, round(world.icon_size * 0.66), 0)) + return + + QDEL_NULL(soup_smoke) diff --git a/code/modules/food_and_drinks/recipes/drinks/drinks_alcoholic.dm b/code/modules/food_and_drinks/recipes/drinks/drinks_alcoholic.dm index fc09d88ed7b..ec3813cfd56 100644 --- a/code/modules/food_and_drinks/recipes/drinks/drinks_alcoholic.dm +++ b/code/modules/food_and_drinks/recipes/drinks/drinks_alcoholic.dm @@ -393,7 +393,7 @@ /datum/chemical_reaction/drink/quintuplesec results = list(/datum/reagent/consumable/ethanol/quintuple_sec = 15) - required_reagents = list(/datum/reagent/consumable/ethanol/quadruple_sec = 5, /datum/reagent/consumable/clownstears = 5, /datum/reagent/consumable/ethanol/syndicatebomb = 5) + required_reagents = list(/datum/reagent/consumable/ethanol/quadruple_sec = 5, /datum/reagent/consumable/nutriment/soup/clown_tears = 5, /datum/reagent/consumable/ethanol/syndicatebomb = 5) mix_message = "Judgement is upon you." mix_sound = 'sound/items/airhorn2.ogg' reaction_tags = REACTION_TAG_DRINK | REACTION_TAG_EASY | REACTION_TAG_OTHER diff --git a/code/modules/food_and_drinks/recipes/food_mixtures.dm b/code/modules/food_and_drinks/recipes/food_mixtures.dm index ff9dfbcdb85..dd7b7ef655f 100644 --- a/code/modules/food_and_drinks/recipes/food_mixtures.dm +++ b/code/modules/food_and_drinks/recipes/food_mixtures.dm @@ -1,19 +1,33 @@ /datum/crafting_recipe/food - var/real_parts - var/total_nutriment_factor + /// A rough equivilance for how much nutrition this recipe's result will provide + var/total_nutriment_factor = 0 /datum/crafting_recipe/food/on_craft_completion(mob/user, atom/result) - if(user.mind) + SHOULD_CALL_PARENT(TRUE) + . = ..() + if(istype(result) && !isnull(user.mind)) ADD_TRAIT(result, TRAIT_FOOD_CHEF_MADE, REF(user.mind)) /datum/crafting_recipe/food/New() + . = ..() if(ispath(result, /obj/item/food)) - var/obj/item/food/result_food = new result + var/obj/item/food/result_food = new result() for(var/datum/reagent/consumable/nutriment as anything in result_food.food_reagents) total_nutriment_factor += initial(nutriment.nutriment_factor) * result_food.food_reagents[nutriment] - real_parts = parts.Copy() + qdel(result_food) + parts |= reqs +/datum/crafting_recipe/food/crafting_ui_data() + var/list/data = list() + + if(ispath(result, /obj/item/food)) + var/obj/item/food/item = result + data["foodtypes"] = bitfield_to_list(initial(item.foodtypes), FOOD_FLAGS) + data["nutriments"] = total_nutriment_factor + + return data + //////////////////////////////////////////FOOD MIXTURES//////////////////////////////////// /datum/chemical_reaction/food @@ -25,27 +39,28 @@ H_ion_release = 0 reaction_tags = REACTION_TAG_FOOD | REACTION_TAG_EASY + /// Typepath of food that is created on reaction + var/atom/resulting_food_path + +/datum/chemical_reaction/food/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) + if(resulting_food_path) + var/atom/location = holder.my_atom.drop_location() + for(var/i in 1 to created_volume) + new resulting_food_path(location) + /datum/chemical_reaction/food/tofu required_reagents = list(/datum/reagent/consumable/soymilk = 10) required_catalysts = list(/datum/reagent/consumable/enzyme = 5) mob_react = FALSE reaction_flags = REACTION_INSTANT + resulting_food_path = /obj/item/food/tofu /datum/chemical_reaction/food/candycorn required_reagents = list(/datum/reagent/consumable/cornoil = 5) required_catalysts = list(/datum/reagent/consumable/sugar = 5) mob_react = FALSE reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/candycorn/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i in 1 to created_volume) - new /obj/item/food/candy_corn(location) - -/datum/chemical_reaction/food/tofu/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i in 1 to created_volume) - new /obj/item/food/tofu(location) + resulting_food_path = /obj/item/food/candy_corn /datum/chemical_reaction/food/chocolatepudding results = list(/datum/reagent/consumable/chocolatepudding = 20) @@ -58,30 +73,18 @@ /datum/chemical_reaction/food/chocolate_bar required_reagents = list(/datum/reagent/consumable/soymilk = 2, /datum/reagent/consumable/coco = 2, /datum/reagent/consumable/sugar = 2) reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/chocolate_bar/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i in 1 to created_volume) - new /obj/item/food/chocolatebar(location) + resulting_food_path = /obj/item/food/chocolatebar /datum/chemical_reaction/food/chocolate_bar2 required_reagents = list(/datum/reagent/consumable/milk/chocolate_milk = 4, /datum/reagent/consumable/sugar = 2) mob_react = FALSE reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/chocolate_bar2/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i in 1 to created_volume) - new /obj/item/food/chocolatebar(location) + resulting_food_path = /obj/item/food/chocolatebar /datum/chemical_reaction/food/chocolate_bar3 required_reagents = list(/datum/reagent/consumable/milk = 2, /datum/reagent/consumable/coco = 2, /datum/reagent/consumable/sugar = 2) reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/chocolate_bar3/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i in 1 to created_volume) - new /obj/item/food/chocolatebar(location) + resulting_food_path = /obj/item/food/chocolatebar /datum/chemical_reaction/food/soysauce results = list(/datum/reagent/consumable/soysauce = 5) @@ -111,21 +114,13 @@ required_reagents = list(/datum/reagent/consumable/milk = 40) required_catalysts = list(/datum/reagent/consumable/enzyme = 5) reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/cheesewheel/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i in 1 to created_volume) - new /obj/item/food/cheese/wheel(location) + resulting_food_path = /obj/item/food/cheese/wheel /datum/chemical_reaction/food/synthmeat required_reagents = list(/datum/reagent/blood = 5, /datum/reagent/medicine/cryoxadone = 1) mob_react = FALSE reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/synthmeat/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i in 1 to created_volume) - new /obj/item/food/meat/slab/synthmeat(location) + resulting_food_path = /obj/item/food/meat/slab/synthmeat /datum/chemical_reaction/food/hot_ramen results = list(/datum/reagent/consumable/hot_ramen = 3) @@ -155,21 +150,13 @@ required_reagents = list(/datum/reagent/water = 10, /datum/reagent/consumable/flour = 15) mix_message = "The ingredients form a dough." reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/dough/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i in 1 to created_volume) - new /obj/item/food/dough(location) + resulting_food_path = /obj/item/food/dough /datum/chemical_reaction/food/cakebatter required_reagents = list(/datum/reagent/consumable/eggyolk = 6, /datum/reagent/consumable/eggwhite = 12, /datum/reagent/consumable/flour = 15, /datum/reagent/consumable/sugar = 5) mix_message = "The ingredients form a cake batter." reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/cakebatter/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i in 1 to created_volume) - new /obj/item/food/cakebatter(location) + resulting_food_path = /obj/item/food/cakebatter /datum/chemical_reaction/food/cakebatter/vegan required_reagents = list(/datum/reagent/consumable/soymilk = 15, /datum/reagent/consumable/flour = 15, /datum/reagent/consumable/sugar = 5) @@ -222,22 +209,14 @@ required_reagents = list(/datum/reagent/consumable/milk = 5, /datum/reagent/consumable/quality_oil = 2, /datum/reagent/medicine/salglu_solution = 5, /datum/reagent/consumable/cornmeal = 10, /datum/reagent/consumable/flour = 5) mix_message = "The ingredients form a pizza dough." reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/mothic_pizza_dough/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i = 1, i <= created_volume, i++) - new /obj/item/food/mothic_pizza_dough(location) + resulting_food_path = /obj/item/food/mothic_pizza_dough /datum/chemical_reaction/food/curd_cheese required_reagents = list(/datum/reagent/consumable/milk = 15, /datum/reagent/consumable/vinegar = 5, /datum/reagent/consumable/cream = 5) mix_message = "The milk curdles into cheese." required_temp = 353 reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/curd_cheese/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i = 1, i <= created_volume, i++) - new /obj/item/food/cheese/curd_cheese(location) + resulting_food_path = /obj/item/food/cheese/curd_cheese /datum/chemical_reaction/food/mozzarella required_reagents = list(/datum/reagent/consumable/milk = 10, /datum/reagent/consumable/cream = 10) @@ -245,11 +224,7 @@ mix_message = "Fine ribbons of curd form in the milk." required_temp = 353 reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/mozzarella/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i = 1, i <= created_volume, i++) - new /obj/item/food/cheese/mozzarella(location) + resulting_food_path = /obj/item/food/cheese/mozzarella /datum/chemical_reaction/food/cornmeal_batter results = list(/datum/reagent/consumable/cornmeal_batter = 35) @@ -261,11 +236,7 @@ mix_message = "The batter bakes into cornbread- somehow!" required_temp = 473 reaction_flags = REACTION_INSTANT - -/datum/chemical_reaction/food/cornbread/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/location = get_turf(holder.my_atom) - for(var/i = 1, i <= created_volume, i++) - new /obj/item/food/bread/corn(location) + resulting_food_path = /obj/item/food/bread/corn /datum/chemical_reaction/food/yoghurt required_reagents = list(/datum/reagent/consumable/cream = 10, /datum/reagent/consumable/virus_food = 2) diff --git a/code/modules/food_and_drinks/recipes/soup_guide.dm b/code/modules/food_and_drinks/recipes/soup_guide.dm new file mode 100644 index 00000000000..4a1e0a58132 --- /dev/null +++ b/code/modules/food_and_drinks/recipes/soup_guide.dm @@ -0,0 +1,140 @@ +/datum/crafting_recipe/food/reaction/soup + machinery = list(/obj/machinery/stove) + category = CAT_SOUP + non_craftable = TRUE + + var/expected_container = /obj/item/reagent_containers/cup/bowl + +/datum/crafting_recipe/food/reaction/soup/crafting_ui_data() + var/list/data = list() + + var/datum/glass_style/has_foodtype/soup_style = GLOB.glass_style_singletons[expected_container][result] + if(istype(soup_style)) + data["foodtypes"] = bitfield_to_list(soup_style.drink_type, FOOD_FLAGS) + data["nutriments"] = total_nutriment_factor + + return data + +/datum/crafting_recipe/food/reaction/soup/setup_chemical_reaction_details(datum/chemical_reaction/food/soup/chemical_reaction) + . = ..() + if(!istype(chemical_reaction)) + return + for(var/obj/item/ingredienttype as anything in chemical_reaction.required_ingredients) + reqs[ingredienttype] = chemical_reaction.required_ingredients[ingredienttype] + + if(ispath(result, /datum/reagent/consumable)) + var/datum/reagent/consumable/soup_result = result + total_nutriment_factor = initial(soup_result.nutriment_factor) * result_amount + +/datum/crafting_recipe/food/reaction/soup/meatball_soup + reaction = /datum/chemical_reaction/food/soup/meatballsoup + +/datum/crafting_recipe/food/reaction/soup/vegetable_soup + reaction = /datum/chemical_reaction/food/soup/vegetable_soup + +/datum/crafting_recipe/food/reaction/soup/nettle + reaction = /datum/chemical_reaction/food/soup/nettlesoup + +/datum/crafting_recipe/food/reaction/soup/wingfangchu + reaction = /datum/chemical_reaction/food/soup/wingfangchu + +/datum/crafting_recipe/food/reaction/soup/hotchili + reaction = /datum/chemical_reaction/food/soup/hotchili + +/datum/crafting_recipe/food/reaction/soup/coldchili + reaction = /datum/chemical_reaction/food/soup/coldchili + +/datum/crafting_recipe/food/reaction/soup/clownchili + reaction = /datum/chemical_reaction/food/soup/clownchili + +/datum/crafting_recipe/food/reaction/soup/tomatosoup + reaction = /datum/chemical_reaction/food/soup/tomatosoup + +/datum/crafting_recipe/food/reaction/soup/bloodsoup + name = "Blood Soup" + desc = "Smells like copper." + reaction = /datum/chemical_reaction/food/soup/bloodsoup + // Uses tomato soup's icon + result = /datum/reagent/consumable/nutriment/soup/tomato + // More of a vague guess than anything + result_amount = 30 + +/datum/crafting_recipe/food/reaction/soup/eyeballsoup + reaction = /datum/chemical_reaction/food/soup/eyeballsoup + +/datum/crafting_recipe/food/reaction/soup/misosoup + reaction = /datum/chemical_reaction/food/soup/misosoup + +/datum/crafting_recipe/food/reaction/soup/slimesoup + reaction = /datum/chemical_reaction/food/soup/slimesoup + +/datum/crafting_recipe/food/reaction/soup/slimesoup_alt + reaction = /datum/chemical_reaction/food/soup/slimesoup/alt + +/datum/crafting_recipe/food/reaction/soup/clownstears + reaction = /datum/chemical_reaction/food/soup/clownstears + +/datum/crafting_recipe/food/reaction/soup/mysterysoup + reaction = /datum/chemical_reaction/food/soup/mysterysoup + +/datum/crafting_recipe/food/reaction/soup/monkey + reaction = /datum/chemical_reaction/food/soup/monkey + +/datum/crafting_recipe/food/reaction/soup/mushroomsoup + reaction = /datum/chemical_reaction/food/soup/mushroomsoup + +/datum/crafting_recipe/food/reaction/soup/beetsoup + reaction = /datum/chemical_reaction/food/soup/beetsoup + +/datum/crafting_recipe/food/reaction/soup/stew + reaction = /datum/chemical_reaction/food/soup/stew + +/datum/crafting_recipe/food/reaction/soup/sweetpotatosoup + reaction = /datum/chemical_reaction/food/soup/sweetpotatosoup + +/datum/crafting_recipe/food/reaction/soup/redbeetsoup + reaction = /datum/chemical_reaction/food/soup/redbeetsoup + +/datum/crafting_recipe/food/reaction/soup/onionsoup + reaction = /datum/chemical_reaction/food/soup/onionsoup + +/datum/crafting_recipe/food/reaction/soup/bisque + reaction = /datum/chemical_reaction/food/soup/bisque + +/datum/crafting_recipe/food/reaction/soup/bungocurry + reaction = /datum/chemical_reaction/food/soup/bungocurry + +/datum/crafting_recipe/food/reaction/soup/electron + reaction = /datum/chemical_reaction/food/soup/electron + +/datum/crafting_recipe/food/reaction/soup/peasoup + reaction = /datum/chemical_reaction/food/soup/peasoup + +/datum/crafting_recipe/food/reaction/soup/indian_curry + reaction = /datum/chemical_reaction/food/soup/indian_curry + +/datum/crafting_recipe/food/reaction/soup/oatmeal + reaction = /datum/chemical_reaction/food/soup/oatmeal + +/datum/crafting_recipe/food/reaction/soup/zurek + reaction = /datum/chemical_reaction/food/soup/zurek + +/datum/crafting_recipe/food/reaction/soup/cullen_skink + reaction = /datum/chemical_reaction/food/soup/cullen_skink + +/datum/crafting_recipe/food/reaction/soup/chicken_noodle_soup + reaction = /datum/chemical_reaction/food/soup/chicken_noodle_soup + +/datum/crafting_recipe/food/reaction/soup/corn_chowder + reaction = /datum/chemical_reaction/food/soup/corn_chowder + +// Other + +/datum/crafting_recipe/food/wishsoup + name = "Wish soup" + reqs = list( + /datum/reagent/water = 20, + /obj/item/reagent_containers/cup/bowl = 1 + ) + result= /obj/item/food/bowled/wish + category = CAT_SOUP diff --git a/code/modules/food_and_drinks/recipes/soup_mixtures.dm b/code/modules/food_and_drinks/recipes/soup_mixtures.dm new file mode 100644 index 00000000000..5005236ceb4 --- /dev/null +++ b/code/modules/food_and_drinks/recipes/soup_mixtures.dm @@ -0,0 +1,1720 @@ +/// Abstract parent for soup reagents. +/// These are the majority result from soup recipes, +/// but bear in mind it will(should) have other reagents along side it. +/datum/reagent/consumable/nutriment/soup + name = "Soup" + chemical_flags = NONE + nutriment_factor = 12 * REAGENTS_METABOLISM // Slightly less to that of nutriment as soups will come with nutriments in tow + burning_temperature = 520 + default_container = /obj/item/reagent_containers/cup/bowl + glass_price = FOOD_PRICE_CHEAP + fallback_icon = 'icons/obj/food/soupsalad.dmi' + fallback_icon_state = "bowl" + restaurant_order = /datum/custom_order/reagent/soup + +/** + * ## Soup base chemical reaction. + * + * Somewhat important note! Keep in mind one serving of soup is roughly 20-25 units. Adjust your results according. + * + * Try to aim to have each reaction worth 3 servings of soup (60u - 90u). + * By default soup reactions require 50 units of water, + * and they will also inherent the reagents of the ingredients used, + * so you might end up with more nutrient than you expect. + */ +/datum/chemical_reaction/food/soup + required_temp = 450 + optimal_temp = 480 + overheat_temp = SOUP_BURN_TEMP + optimal_ph_min = 1 + optimal_ph_max = 14 + thermic_constant = 10 + required_reagents = null + mob_react = FALSE + required_other = TRUE + required_container = /obj/item/reagent_containers/cup/soup_pot + mix_message = "You smell something good coming from the steaming pot of soup." + reaction_tags = REACTION_TAG_FOOD | REACTION_TAG_EASY + + // General soup guideline: + // - Soups should produce 60-90 units (3-4 servings) + // - One serving size is 20-25 units (8-9 sips, with 3u sips) + // - The first index of the result list should be the soup type + + /// An assoc list of what ingredients are necessary to how much is needed + var/list/required_ingredients + /// Tracks the total number of ingredient items needed, for calculating multipliers. Only done once in first on_reaction + VAR_FINAL/total_ingredient_max + + /// Multiplier applied to all reagents transfered from reagents to pot when the soup is cooked + var/ingredient_reagent_multiplier = 0.8 + /// What percent of nutriment is converted to "soup" (what percent does not stay final product)? + /// Raise this if your ingredients have a lot of nutriment and is overpowering your other reagents + /// Lower this if your ingredients have a small amount of nutriment and isn't filling enough per serving + /// (EX: A tomato with 10 nutriment will lose 2.5 nutriment before being added to the pot) + var/percentage_of_nutriment_converted = 0.25 + +/datum/chemical_reaction/food/soup/pre_reaction_other_checks(datum/reagents/holder) + var/obj/item/reagent_containers/cup/soup_pot/pot = holder.my_atom + if(!istype(pot)) + return FALSE + if(!length(required_ingredients)) + return TRUE + + // This is very unoptimized for something ran every handle-reaction for every soup recipe. + // Look into ways for improving this, cause bleh + var/list/reqs_copy = required_ingredients.Copy() + for(var/obj/item/ingredient as anything in pot.added_ingredients) + // See if we fulfill all reqs + for(var/ingredient_type in required_ingredients) + if(!istype(ingredient, ingredient_type)) + continue + if(isstack(ingredient)) + var/obj/item/stack/stack_ingredient = ingredient + reqs_copy[ingredient_type] -= stack_ingredient.amount + else + reqs_copy[ingredient_type] -= 1 + + for(var/fulfilled in reqs_copy) + if(reqs_copy[fulfilled] > 0) + return FALSE + return TRUE + +/datum/chemical_reaction/food/soup/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) + if(!length(required_ingredients)) + return + + if(isnull(total_ingredient_max)) + total_ingredient_max = 0 + // We only need to calculate this once, effectively static per-type + for(var/ingredient_type in required_ingredients) + total_ingredient_max += required_ingredients[ingredient_type] + + var/obj/item/reagent_containers/cup/soup_pot/pot = holder.my_atom + var/list/tracked_ingredients = list() + for(var/obj/item/ingredient as anything in pot.added_ingredients) + // Track all ingredients in data. Assoc list of weakref to ingredient to initial total volume. + tracked_ingredients[WEAKREF(ingredient)] = ingredient.reagents?.total_volume || 1 + // Equalize temps. Otherwise when we add ingredient temps in, it'll lower reaction temp + ingredient.reagents?.chem_temp = holder.chem_temp + + // Store a list of weakrefs to ingredients as + reaction.data["ingredients"] = tracked_ingredients + + testing("Soup reaction started of type [type]! [length(pot.added_ingredients)] inside.") + +/datum/chemical_reaction/food/soup/reaction_step(datum/reagents/holder, datum/equilibrium/reaction, delta_t, delta_ph, step_reaction_vol) + if(!length(required_ingredients)) + return + + testing("Soup reaction step progressing with an increment volume of [step_reaction_vol] and delta_t of [delta_t].") + var/obj/item/reagent_containers/cup/soup_pot/pot = holder.my_atom + var/list/cached_ingredients = reaction.data["ingredients"] + var/num_current_ingredients = length(pot.added_ingredients) + var/num_cached_ingredients = length(cached_ingredients) + + // Clamp multiplier to ingredient number + reaction.multiplier = min(reaction.multiplier, num_current_ingredients / total_ingredient_max) + + // An ingredient was removed during the mixing process. + // Stop reacting immediately, we can't verify the reaction is correct still. + // If it is still correct it will restart shortly. + if(num_current_ingredients < num_cached_ingredients) + testing("Soup reaction ended due to losing ingredients.") + return END_REACTION + + // An ingredient was added mid mix. + // Throw it in the ingredients list + else if(num_current_ingredients > num_cached_ingredients) + for(var/obj/item/new_ingredient as anything in pot.added_ingredients) + var/datum/weakref/new_ref = WEAKREF(new_ingredient) + if(cached_ingredients[new_ref]) + continue + new_ingredient.reagents?.chem_temp = holder.chem_temp + cached_ingredients[new_ref] = new_ingredient.reagents?.total_volume || 1 + + for(var/datum/weakref/ingredient_ref as anything in cached_ingredients) + var/obj/item/ingredient = ingredient_ref.resolve() + // An ingredient has gone missing, stop the reaction + if(QDELETED(ingredient) || ingredient.loc != holder.my_atom) + testing("Soup reaction ended due to having an invalid ingredient present.") + return END_REACTION + + // Don't add any more reagents if we've boiled over + if(reaction.data["boiled_over"]) + continue + + // Transfer 20% of the initial reagent volume of the ingredient to the soup + transfer_ingredient_reagents(ingredient, holder, max(cached_ingredients[ingredient_ref] * 0.2, 2)) + + // Uh oh we reached the top of the pot, the soup's gonna boil over. + if(holder.total_volume >= holder.maximum_volume * 0.95) + boil_over(holder) + reaction.data["boiled_over"] = TRUE + +/datum/chemical_reaction/food/soup/reaction_finish(datum/reagents/holder, datum/equilibrium/reaction, react_vol) + . = ..() + var/obj/item/reagent_containers/cup/soup_pot/pot = holder.my_atom + if(!istype(pot)) + CRASH("[pot ? "Non-pot atom" : "Null pot"]) made it to the end of the [type] reaction chain.") + reaction.data["ingredients"] = null + + testing("Soup reaction finished with a total react volume of [react_vol] and [length(pot.added_ingredients)] ingredients. Cleaning up.") + + for(var/obj/item/ingredient as anything in pot.added_ingredients) + // Let's not mess with fireproof / indestructible items. + // It's not likely that soups use fireproof items as ingredients, + // and chef doesn't need more ways to delete things with cooking. + if(ingredient.resistance_flags & (FIRE_PROOF|INDESTRUCTIBLE)) + continue + + // Things that had reagents or ingredients in the soup will get deleted + if(!isnull(ingredient.reagents) || is_type_in_list(ingredient, required_ingredients)) + // Send everything left behind + transfer_ingredient_reagents(ingredient, holder) + // Delete, it's done + qdel(ingredient) + + // Everything else will just get fried + else + ingredient.AddElement(/datum/element/fried_item, 30) + + LAZYNULL(pot.added_ingredients) + // Blackbox log the chemical reaction used, to account for soup reaction that don't produce typical results + BLACKBOX_LOG_FOOD_MADE(type) + +/datum/chemical_reaction/food/soup/proc/transfer_ingredient_reagents(obj/item/ingredient, datum/reagents/holder, amount) + var/datum/reagents/ingredient_pool = ingredient.reagents + // Some ingredients are purely flavor (no pun intended) and will have reagents + if(isnull(ingredient_pool) || ingredient_pool.total_volume <= 0) + return + if(isnull(amount)) + amount = ingredient_pool.total_volume + testing("Soup reaction has made it to the finishing step with ingredients that still contain reagents. [amount] reagents left in [ingredient].") + + // Some of the nutriment goes into "creating the soup reagent" itself, gets deleted. + // Mainly done so that nutriment doesn't overpower the main course + ingredient_pool.remove_reagent(/datum/reagent/consumable/nutriment, amount * percentage_of_nutriment_converted) + ingredient_pool.remove_reagent(/datum/reagent/consumable/nutriment/vitamin, amount * percentage_of_nutriment_converted) + // The other half of the nutriment, and the rest of the reagents, will get put directly into the pot + ingredient_pool.trans_to(holder, amount, ingredient_reagent_multiplier, no_react = TRUE) + +/datum/chemical_reaction/food/soup/proc/boil_over(datum/reagents/holder) + var/obj/item/reagent_containers/cup/soup_pot/pot = holder.my_atom + var/turf/below_pot = get_turf(pot) + below_pot.visible_message(span_warning("[pot] starts to boil over!")) + // Create a spread of dirty foam + var/datum/effect_system/fluid_spread/foam/dirty/soup_mess = new() + soup_mess.reagent_scale = 0.1 // (Just a little) + soup_mess.set_up(range = 1, holder = pot, location = below_pot, carry = holder, stop_reactions = TRUE) + soup_mess.start() + // Loses a bit from the foam + for(var/datum/reagent/reagent as anything in holder.reagent_list) + reagent.volume = round(reagent.volume * 0.9, 0.05) + holder.update_total() + +#ifdef TESTING + +/obj/item/soup_test_kit/Initialize(mapload) + ..() + new /obj/item/food/meatball(loc) + new /obj/item/food/grown/carrot(loc) + new /obj/item/food/grown/potato(loc) + new /obj/item/reagent_containers/cup/soup_pot(loc) + return INITIALIZE_HINT_QDEL + +#endif + +/// This subtype is only for easy mapping / spawning in specific types of soup. +/// Do not use it anywhere else. +/obj/item/reagent_containers/cup/bowl/soup + var/initial_reagent + var/initial_portion = SOUP_SERVING_SIZE + +/obj/item/reagent_containers/cup/bowl/soup/Initialize(mapload) + . = ..() + if(initial_reagent) + reagents.add_reagent(initial_reagent, initial_portion) + +/// This style runs dual purpose - +/// Primarily it's just a bowl style for water, +/// but secondarily it lets chefs know if their soup had too much water in it +/datum/glass_style/has_foodtype/soup/watery_soup + required_drink_type = /datum/reagent/water + name = "Bowl of water" + desc = "A very wet bowl." + icon_state = "wishsoup" + +/datum/glass_style/has_foodtype/soup/watery_soup/set_name(obj/item/thing) + if(length(thing.reagents.reagent_list) <= 2) + return ..() + + thing.name = "Watery bowl of something" + +/datum/glass_style/has_foodtype/soup/watery_soup/set_desc(obj/item/thing) + if(length(thing.reagents.reagent_list) <= 2) + return ..() + + thing.desc = "Looks like whatever's in there is very watered down." + +/// So this one's kind of a "failed" result, but also a "custom" result +/// Getting to this temperature and having no other soup reaction made means you're either messing something up +/// or you simply aren't following a recipe. So it'll just combine +/datum/chemical_reaction/food/soup/custom + required_temp = SOUP_BURN_TEMP + 40 // Only done if it's been burning for a little bit + optimal_temp = SOUP_BURN_TEMP + 50 + overheat_temp = SOUP_BURN_TEMP + 60 + thermic_constant = 0 + mix_message = span_warning("You smell something gross coming from the pot of soup.") + required_reagents = list(/datum/reagent/water = 30) + results = list(/datum/reagent/water = 10) + ingredient_reagent_multiplier = 1 + percentage_of_nutriment_converted = 0 + +/datum/chemical_reaction/food/soup/custom/pre_reaction_other_checks(datum/reagents/holder) + var/obj/item/reagent_containers/cup/soup_pot/pot = holder.my_atom + if(!istype(pot)) + return FALSE // Not a pot + if(holder.is_reacting) + return FALSE // Another soup is being made + if(length(pot.added_ingredients) <= 3) + return FALSE // Not a lot here to go off of + return TRUE + +// Meatball Soup +/datum/reagent/consumable/nutriment/soup/meatball_soup + name = "Meatball Soup" + description = "You've got balls kid, BALLS!" + data = list("meat" = 1) + glass_price = FOOD_PRICE_NORMAL + color = "#FFFDCF" + +/datum/glass_style/has_foodtype/soup/meatball_soup + required_drink_type = /datum/reagent/consumable/nutriment/soup/meatball_soup + icon_state = "meatballsoup" + drink_type = MEAT + +/obj/item/reagent_containers/cup/bowl/soup/meatball_soup + initial_reagent = /datum/reagent/consumable/nutriment/soup/meatball_soup + +/datum/chemical_reaction/food/soup/meatballsoup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/meatball = 1, + /obj/item/food/grown/carrot = 1, + /obj/item/food/grown/potato = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/meatball_soup = 30, + /datum/reagent/water = 9, + ) + +// Vegetable Soup +/datum/reagent/consumable/nutriment/soup/vegetable_soup + name = "Vegetable Soup" + description = "A true vegan meal." + data = list("vegetables" = 1) + glass_price = FOOD_PRICE_NORMAL + color = "#FAA810" + +/datum/glass_style/has_foodtype/soup/vegetable_soup + required_drink_type = /datum/reagent/consumable/nutriment/soup/vegetable_soup + icon_state = "vegetablesoup" + drink_type = VEGETABLES + +/datum/chemical_reaction/food/soup/vegetable_soup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/grown/carrot = 1, + /obj/item/food/grown/corn = 1, + /obj/item/food/grown/eggplant = 1, + /obj/item/food/grown/potato = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/vegetable_soup = 30, + /datum/reagent/water = 9, + ) + +// Nettle soup - gains some omnizine to offset the acid damage +/datum/reagent/consumable/nutriment/soup/nettle + name = "Nettle Soup" + description = "To think, the botanist would've beat you to death with one of these." + data = list("nettles" = 1) + glass_price = FOOD_PRICE_NORMAL + color = "#C1E212" + +/datum/glass_style/has_foodtype/soup/nettle + required_drink_type = /datum/reagent/consumable/nutriment/soup/nettle + icon_state = "nettlesoup" + drink_type = VEGETABLES + +/obj/item/reagent_containers/cup/bowl/soup/nettle + initial_reagent = /datum/reagent/consumable/nutriment/soup/nettle + +/datum/chemical_reaction/food/soup/nettlesoup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/grown/nettle = 1, + /obj/item/food/grown/potato = 1, + /obj/item/food/boiledegg = 1 + ) + results = list( + /datum/reagent/consumable/nutriment/soup/nettle = 30, + /datum/reagent/water = 9, + /datum/reagent/medicine/omnizine = 6, + ) + ingredient_reagent_multiplier = 0.2 // Too much acid + percentage_of_nutriment_converted = 0 + +// Wing Fang Chu +/datum/reagent/consumable/nutriment/soup/wingfangchu + name = "Wing Fang Chu" + description = "A savory dish of alien wing wang in soy." + data = list("soy" = 1) + color = "#C1E212" + +/datum/glass_style/has_foodtype/soup/wingfangchu + required_drink_type = /datum/reagent/consumable/nutriment/soup/wingfangchu + icon_state = "wingfangchu" + drink_type = MEAT + +/datum/chemical_reaction/food/soup/wingfangchu + required_reagents = list( + /datum/reagent/water = 50, + /datum/reagent/consumable/soysauce = 5, + ) + required_ingredients = list( + /obj/item/food/meat/cutlet/xeno = 2, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/wingfangchu = 30, + /datum/reagent/consumable/soysauce = 10, + ) + +// Chili (Hot, not cold) +/datum/reagent/consumable/nutriment/soup/hotchili + name = "Hot Chili" + description = "A five alarm Texan Chili!" + data = list("hot peppers" = 1) + glass_price = FOOD_PRICE_NORMAL + color = "#E23D12" + +/datum/glass_style/has_foodtype/soup/hotchili + required_drink_type = /datum/reagent/consumable/nutriment/soup/hotchili + icon_state = "hotchili" + drink_type = VEGETABLES | MEAT + +/obj/item/reagent_containers/cup/bowl/soup/hotchili + initial_reagent = /datum/reagent/consumable/nutriment/soup/hotchili + +/datum/chemical_reaction/food/soup/hotchili + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/meat/cutlet = 2, + /obj/item/food/grown/chili = 1, + /obj/item/food/grown/tomato = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/hotchili = 30, + /datum/reagent/consumable/tomatojuice = 10, + // Capsaicin comes from the chillis, meaning you can make tame chili. + /* + /datum/reagent/consumable/nutriment = 4, + /datum/reagent/consumable/nutriment/protein = 6, + /datum/reagent/consumable/nutriment/vitamin = 4 + */ + ) + ingredient_reagent_multiplier = 0.33 // Chilis have a TON of capsaicin naturally + percentage_of_nutriment_converted = 0 + +// Chili (Cold) +/datum/reagent/consumable/nutriment/soup/coldchili + name = "Cold Chili" + description = "This slush is barely a liquid!" + data = list("tomato" = 1, "mint" = 1) + glass_price = FOOD_PRICE_NORMAL + color = "#3861C2" + +/datum/glass_style/has_foodtype/soup/coldchili + required_drink_type = /datum/reagent/consumable/nutriment/soup/coldchili + icon_state = "coldchili" + drink_type = VEGETABLES | MEAT + +/datum/chemical_reaction/food/soup/coldchili + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/meat/cutlet = 2, + /obj/item/food/grown/icepepper = 1, + /obj/item/food/grown/tomato = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/coldchili = 30, + /datum/reagent/consumable/tomatojuice = 10, + // Frost Oil comes from the chilis + ) + ingredient_reagent_multiplier = 0.33 // Chilis have a TON of frost oil naturally + percentage_of_nutriment_converted = 0 + +// Chili (Clownish) +/datum/reagent/consumable/nutriment/soup/clownchili + name = "Chili Con Carnival" + description = "A delicious stew of meat, chiles, and salty, salty clown tears." + data = list( + "tomato" = 1, + "hot peppers" = 2, + "clown feet" = 2, + "kind of funny" = 2, + "someone's parents" = 2, + ) + glass_price = FOOD_PRICE_EXOTIC + color = "#FF0000" + +/datum/glass_style/has_foodtype/soup/clownchili + required_drink_type = /datum/reagent/consumable/nutriment/soup/clownchili + icon_state = "clownchili" + drink_type = VEGETABLES | MEAT + +/datum/chemical_reaction/food/soup/clownchili + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/meat/cutlet = 2, + /obj/item/food/grown/chili = 1, + /obj/item/food/grown/tomato = 1, + /obj/item/clothing/shoes/clown_shoes = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/clownchili = 30, + /datum/reagent/consumable/tomatojuice = 8, + /datum/reagent/consumable/laughter = 4, + /datum/reagent/consumable/banana = 4, + ) + percentage_of_nutriment_converted = 0.15 + +// Vegan Chili +/datum/reagent/consumable/nutriment/soup/chili_sin_carne + name = "Chili Sin Carne" + description = "For the hombres who don't want carne." + data = list("bitterness" = 1, "sourness" = 1) + color = "#E23D12" + +/datum/glass_style/has_foodtype/soup/chili_sin_carne + required_drink_type = /datum/reagent/consumable/nutriment/soup/chili_sin_carne + icon_state = "hotchili" + drink_type = VEGETABLES + +/datum/chemical_reaction/food/soup/chili_sin_carne + required_reagents = list( + /datum/reagent/water = 40, + /datum/reagent/consumable/salt = 5, + ) + required_ingredients = list( + /obj/item/food/grown/chili = 1, + /obj/item/food/grown/tomato = 1 + ) + results = list( + /datum/reagent/consumable/nutriment/soup/chili_sin_carne = 30, + /datum/reagent/consumable/tomatojuice = 10, + ) + +// Tomato soup +/datum/reagent/consumable/nutriment/soup/tomato + name = "Tomato Soup" + description = "Drinking this feels like being a vampire! A tomato vampire..." + data = list("tomato" = 1) + color = "#FF0000" + +/datum/glass_style/has_foodtype/soup/tomato + required_drink_type = /datum/reagent/consumable/nutriment/soup/tomato + name = "Tomato Soup" + icon_state = "tomatosoup" + drink_type = VEGETABLES | FRUIT // ?? + +/datum/chemical_reaction/food/soup/tomatosoup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/grown/tomato = 2, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/tomato = 30, + /datum/reagent/consumable/tomatojuice = 20, + /* + /datum/reagent/consumable/nutriment = 6, + /datum/reagent/consumable/tomatojuice = 10, + /datum/reagent/consumable/nutriment/vitamin = 3 + */ + ) + percentage_of_nutriment_converted = 0.1 + +// Tomato-eyeball soup +/datum/reagent/consumable/nutriment/soup/eyeball + name = "Eyeball Soup" + description = "It looks back at you..." + data = list("tomato" = 1, "squirming" = 1) + color = "#FF1C1C" + +/datum/glass_style/has_foodtype/soup/eyeball + required_drink_type = /datum/reagent/consumable/nutriment/soup/eyeball + icon_state = "eyeballsoup" + drink_type = VEGETABLES | FRUIT | MEAT | GORE // Tomato soup + an eyeball + +/datum/chemical_reaction/food/soup/eyeballsoup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/grown/tomato = 2, + /obj/item/organ/internal/eyes = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/eyeball = 20, + // Logically this would be more but we wouldn't get the eyeball icon state if it was. + /datum/reagent/consumable/nutriment/soup/tomato = 10, + /datum/reagent/consumable/nutriment = 2, + /datum/reagent/consumable/nutriment/protein = 6, + /datum/reagent/consumable/tomatojuice = 6, + /datum/reagent/consumable/liquidgibs = 6, + ) + percentage_of_nutriment_converted = 0.1 + +// Miso soup +/datum/reagent/consumable/nutriment/soup/miso + name = "Miso Soup" + description = "The universes best soup! Yum!!!" + data = list("miso" = 1) + glass_price = FOOD_PRICE_NORMAL + color = "#E2BD12" + +/datum/glass_style/has_foodtype/soup/miso + required_drink_type = /datum/reagent/consumable/nutriment/soup/miso + icon_state = "misosoup" + drink_type = VEGETABLES | BREAKFAST + +/datum/chemical_reaction/food/soup/misosoup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/soydope = 2, + /obj/item/food/tofu = 2, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/miso = 30, + /datum/reagent/water = 10, + ) + percentage_of_nutriment_converted = 0 // Soy has very low nutrients. + +// Blood soup +// Fake tomato soup. +// Can also appear by pouring blood into a bowl! +/datum/glass_style/has_foodtype/soup/tomato/blood + required_drink_type = /datum/reagent/blood + name = "Tomato Soup" + desc = "Smells like copper." + drink_type = GROSS + +/datum/chemical_reaction/food/soup/bloodsoup + required_reagents = list( + /datum/reagent/water = 10, + /datum/reagent/blood = 10, + ) + required_ingredients = list( + /obj/item/food/grown/tomato/blood = 2, + ) + results = list( + // Blood tomatos will give us like 30u blood, so just add in the 10 from the recipe + /datum/reagent/blood = 10, + /datum/reagent/water = 8, + /datum/reagent/consumable/nutriment/protein = 7, + ) + percentage_of_nutriment_converted = 0.1 + +// Slime soup +// Made with a slime extract, toxic to non-slime-people. +// Can also be created by mixing water and slime jelly. +/datum/reagent/consumable/nutriment/soup/slime + name = "Slime Soup" + description = "If no water is available, you may substitute tears." + data = list("slime" = 1) + glass_price = FOOD_PRICE_NORMAL + color = "#41C0C0" + +/datum/glass_style/has_foodtype/soup/slime + required_drink_type = /datum/reagent/consumable/nutriment/soup/slime + icon_state = "slimesoup" + drink_type = GROSS + +/datum/chemical_reaction/food/soup/slimesoup + required_reagents = list( + /datum/reagent/water = 40, + ) + required_ingredients = list( + /obj/item/slime_extract = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/slime = 30, + /datum/reagent/toxin/slimejelly = 20, + // Comes out of thin air, as none of our ingredients contain nutrients naturally. + /datum/reagent/consumable/nutriment = 7, + /datum/reagent/consumable/nutriment/vitamin = 7, + /datum/reagent/water = 6, + ) + +/datum/chemical_reaction/food/soup/slimesoup/alt + // Alt recipe that allows you to create a slime soup by just mixing slime jelly and water. + // Pretty much just a normal chemical reaction. + // This also creates nutrients out of thin air. + + required_other = FALSE + required_reagents = list( + /datum/reagent/water = 40, + /datum/reagent/toxin/slimejelly = 20, + ) + required_ingredients = null + +// Clown Tear soup +/datum/reagent/consumable/nutriment/soup/clown_tears + name = "Clown's Tears" + description = "The sorrow and melancholy of a thousand bereaved clowns, forever denied their Honkmechs." + nutriment_factor = 5 * REAGENTS_METABOLISM + ph = 9.2 + data = list("a bad joke" = 1, "mournful honking" = 1) + color = "#EEF442" + +/datum/glass_style/has_foodtype/soup/clown_tears + required_drink_type = /datum/reagent/consumable/nutriment/soup/clown_tears + name = "clown's tears" + desc = "Not very funny." + icon_state = "clownstears" + drink_type = FRUIT | SUGAR + +/datum/chemical_reaction/food/soup/clownstears + required_reagents = list( + /datum/reagent/lube = 30, + ) + required_ingredients = list( + /obj/item/food/grown/banana = 1, + /obj/item/stack/sheet/mineral/bananium = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/clown_tears = 30, + /datum/reagent/consumable/banana = 8, + /datum/reagent/consumable/nutriment/vitamin = 12, + /datum/reagent/lube = 5, + ) + percentage_of_nutriment_converted = 0 // Bananas have a small amount of nutrition naturally + +// Mystery soup +// Acts a little funny, because when it's mixed it gains a new random reagent as well +/datum/reagent/consumable/nutriment/soup/mystery + name = "Mystery Soup" + description = "The mystery is, why aren't you eating it?" + data = list("chaos" = 1) + color = "#4C2A18" + +/datum/glass_style/has_foodtype/soup/mystery + required_drink_type = /datum/reagent/consumable/nutriment/soup/mystery + icon_state = "mysterysoup" + +/datum/chemical_reaction/food/soup/mysterysoup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/badrecipe = 1, + /obj/item/food/tofu = 1, + /obj/item/food/boiledegg = 1, + /obj/item/food/cheese/wedge = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/mystery = 30, + ) + percentage_of_nutriment_converted = 0.33 // Full of garbage + + /// A list of reagent types we can randomly gain in the soup on creation + var/list/extra_reagent_types = list( + /datum/reagent/blood, + /datum/reagent/carbon, + /datum/reagent/consumable/banana, + /datum/reagent/consumable/capsaicin, + /datum/reagent/consumable/frostoil, + /datum/reagent/medicine/oculine, + /datum/reagent/medicine/omnizine, + /datum/reagent/toxin, + /datum/reagent/toxin/slimejelly, + ) + +/datum/chemical_reaction/food/soup/mysterysoup/reaction_finish(datum/reagents/holder, datum/equilibrium/reaction, react_vol) + . = ..() + holder.add_reagent(pick(extra_reagent_types), 10) + +// Monkey Soup +/datum/reagent/consumable/nutriment/soup/monkey + name = "Monkey's Delight" + description = "A delicious soup with dumplings and hunks of monkey meat simmered to perfection, in a broth that tastes faintly of bananas." + data = list("the jungle" = 1, "banana" = 1) + glass_price = FOOD_PRICE_NORMAL + color = "#4C2A18" + +/datum/glass_style/has_foodtype/soup/monkey + required_drink_type = /datum/reagent/consumable/nutriment/soup/monkey + icon_state = "monkeysdelight" + drink_type = FRUIT + +/obj/item/reagent_containers/cup/bowl/soup/monkey + initial_reagent = /datum/reagent/consumable/nutriment/soup/monkey + +/datum/chemical_reaction/food/soup/monkey + required_reagents = list( + /datum/reagent/water = 25, + /datum/reagent/consumable/flour = 5, + /datum/reagent/consumable/salt = 5, + /datum/reagent/consumable/blackpepper = 5, + ) + required_ingredients = list( + /obj/item/food/monkeycube = 1, // This will make a monkey if a batch of 2 is made + /obj/item/food/grown/banana = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/monkey = 30, + /datum/reagent/consumable/nutriment = 12, + /datum/reagent/consumable/salt = 4, + /datum/reagent/consumable/blackpepper = 4, + ) + +// Cream of mushroom soup +/datum/reagent/consumable/nutriment/soup/mushroom + name = "Chantrelle Soup" + description = "A delicious and hearty mushroom soup." + data = list("mushroom" = 1) + color = "#CEB1B0" + +/datum/glass_style/has_foodtype/soup/mushroom + required_drink_type = /datum/reagent/consumable/nutriment/soup/mushroom + icon_state = "mushroomsoup" + drink_type = VEGETABLES | DAIRY + +/datum/chemical_reaction/food/soup/mushroomsoup + required_reagents = list( + /datum/reagent/water = 40, + /datum/reagent/consumable/milk = 10, + ) + required_ingredients = list( + /obj/item/food/grown/mushroom/chanterelle = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/mushroom = 30, + /datum/reagent/consumable/nutriment = 9, + /datum/reagent/consumable/nutriment/vitamin = 8, + /datum/reagent/consumable/milk = 2, + ) + +// Beet soup (Borscht) +// This has a gimmick where it randomizes its name based on common mispellings on Borsch +/datum/reagent/consumable/nutriment/soup/white_beet + name = "Beet Soup" + description = "Wait, how do you spell it again..?" + data = list("beet" = 1) + color = "#E00000" + +/datum/glass_style/has_foodtype/soup/white_beet + required_drink_type = /datum/reagent/consumable/nutriment/soup/white_beet + icon_state = "beetsoup" + drink_type = VEGETABLES | DAIRY + +/datum/glass_style/has_foodtype/soup/white_beet/set_name(obj/item/thing) + var/how_do_you_spell_it = pick("borsch", "bortsch", "borstch", "borsh", "borshch", "borscht") + thing.name = how_do_you_spell_it + + var/datum/reagent/soup = locate(required_drink_type) in thing.reagents + if(!soup) + // Shouldn't happen but things are weird + return + + // Update tastes with the new name + LAZYSET(soup.data, how_do_you_spell_it, 1) + // Not perfect. Doesn't clear when the bowl type is unset. But it'll do well enough + +/obj/item/reagent_containers/cup/bowl/soup/white_beet + initial_reagent = /datum/reagent/consumable/nutriment/soup/white_beet + +/datum/chemical_reaction/food/soup/beetsoup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/grown/whitebeet = 1, + /obj/item/food/grown/cabbage = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/white_beet = 30, + /datum/reagent/water = 10, + ) + percentage_of_nutriment_converted = 0.1 + +// Stew +/datum/reagent/consumable/nutriment/soup/stew + name = "Stew" + description = "A nice and warm stew. Healthy and strong." + data = list("tomato" = 1, "carrot" = 1) + glass_price = FOOD_PRICE_NORMAL + color = "#EB7C82" + +/datum/glass_style/has_foodtype/soup/stew + required_drink_type = /datum/reagent/consumable/nutriment/soup/stew + icon_state = "stew" + drink_type = VEGETABLES | FRUIT | MEAT + +/obj/item/reagent_containers/cup/bowl/soup/stew + initial_reagent = /datum/reagent/consumable/nutriment/soup/stew + +/datum/chemical_reaction/food/soup/stew + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/grown/tomato = 1, + /obj/item/food/meat/cutlet = 3, + /obj/item/food/grown/potato = 1, + /obj/item/food/grown/carrot = 1, + /obj/item/food/grown/eggplant = 1, + /obj/item/food/grown/mushroom = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/stew = 30, + /datum/reagent/consumable/tomatojuice = 10, + // Gains a ton of nutriments from the variety of ingredients. + ) + +// Sweet potato soup +/datum/reagent/consumable/nutriment/soup/sweetpotato + name = "Sweet Potato Soup" + description = "Delicious sweet potato in soup form." + data = list("sweet potato" = 1) + color = "#903E22" + +/datum/glass_style/has_foodtype/soup/sweetpotato + required_drink_type = /datum/reagent/consumable/nutriment/soup/sweetpotato + icon_state = "sweetpotatosoup" + drink_type = VEGETABLES | SUGAR + +/obj/item/reagent_containers/cup/bowl/soup/sweetpotato + initial_reagent = /datum/reagent/consumable/nutriment/soup/sweetpotato + +/datum/chemical_reaction/food/soup/sweetpotatosoup + required_reagents = list( + /datum/reagent/water = 40, + /datum/reagent/consumable/milk = 10, // Coconut milk, but, close enough + ) + required_ingredients = list( + /obj/item/food/grown/potato/sweet = 2, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/sweetpotato = 30, + /datum/reagent/water = 10, + ) + +// Red beet soup +/datum/reagent/consumable/nutriment/soup/red_beet + name = "Red Beet Soup" + description = "Quite a delicacy." + data = list("beet" = 1) + color = "#851127" + +/datum/glass_style/has_foodtype/soup/red_beet + required_drink_type = /datum/reagent/consumable/nutriment/soup/red_beet + icon_state = "redbeetsoup" + drink_type = VEGETABLES + +/datum/chemical_reaction/food/soup/redbeetsoup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/grown/redbeet = 1, + /obj/item/food/grown/cabbage = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/red_beet = 30, + /datum/reagent/water = 10, + ) + percentage_of_nutriment_converted = 0.1 + +// French Onion soup +/datum/reagent/consumable/nutriment/soup/french_onion + name = "French Onion Soup" + description = "Good enough to make a grown mime cry." + data = list("caramelized onions" = 1) + color = "#E1C47F" + +/datum/glass_style/has_foodtype/soup/french_onion + required_drink_type = /datum/reagent/consumable/nutriment/soup/french_onion + icon_state = "onionsoup" + drink_type = VEGETABLES | DAIRY + +/datum/chemical_reaction/food/soup/onionsoup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/grown/onion = 1, + /obj/item/food/cheese/wedge = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/french_onion = 30, + /datum/reagent/consumable/nutriment/protein = 8, // No idea where this comes from + /datum/reagent/consumable/tomatojuice = 8, // No idea where this comes from + ) + ingredient_reagent_multiplier = 0.5 // Onions are very reagent heavy + percentage_of_nutriment_converted = 0.1 + +// Bisque / Crab soup +/datum/reagent/consumable/nutriment/soup/bisque + name = "Bisque" + description = "A classic entree from Space-France." + data = list("creamy texture" = 1, "crab" = 4) + glass_price = FOOD_PRICE_EXOTIC + color = "#C8682F" + +/datum/glass_style/has_foodtype/soup/bisque + required_drink_type = /datum/reagent/consumable/nutriment/soup/bisque + icon_state = "bisque" + drink_type = MEAT + +/datum/chemical_reaction/food/soup/bisque + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/meat/crab = 1, + /obj/item/food/boiledrice = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/bisque = 30, + /datum/reagent/consumable/nutriment/protein = 6, + /datum/reagent/consumable/nutriment/vitamin = 4, + /datum/reagent/water = 5, + ) + +// Bungo Tree Curry +/datum/reagent/consumable/nutriment/soup/bungo + name = "Bungo Curry" + description = "A spicy vegetable curry made with the humble bungo fruit, Exotic!" + data = list("bungo" = 2, "hot curry" = 4, "tropical sweetness" = 1) + glass_price = FOOD_PRICE_NORMAL + color = "#E6BC32" + +/datum/glass_style/has_foodtype/soup/bungo + required_drink_type = /datum/reagent/consumable/nutriment/soup/bungo + icon_state = "bungocurry" + drink_type = VEGETABLES | FRUIT | DAIRY + +/datum/chemical_reaction/food/soup/bungocurry + required_reagents = list( + /datum/reagent/water = 40, + /datum/reagent/consumable/cream = 10, + ) + required_ingredients = list( + /obj/item/food/grown/chili = 1, + /obj/item/food/grown/bungofruit = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/bungo = 30, + /datum/reagent/consumable/bungojuice = 15, + ) + percentage_of_nutriment_converted = 0.1 + +// Electron Soup. +// Special soup for Ethereals to consume to gain nutrition (energy) from. +/datum/reagent/consumable/nutriment/soup/electrons + name = "Electron Soup" + description = "A gastronomic curiosity of ethereal origin. It is famed for the minature weather system formed over a properly prepared soup." + data = list("mushroom" = 1, "electrons" = 4) + glass_price = FOOD_PRICE_EXOTIC + color = "#E60040" + +/datum/glass_style/has_foodtype/soup/electrons + required_drink_type = /datum/reagent/consumable/nutriment/soup/electrons + icon_state = "electronsoup" + drink_type = VEGETABLES | TOXIC + +/datum/chemical_reaction/food/soup/electron + required_reagents = list( + /datum/reagent/water = 45, + /datum/reagent/consumable/salt = 5, + ) + required_ingredients = list( + /obj/item/food/grown/mushroom/jupitercup = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/electrons = 30, + // Jupiter cups obviously contain a fair amount of LE naturally, + // but to make it "worthwhile" for Ethereals to eat we add a bit extra + /datum/reagent/consumable/liquidelectricity/enriched = 10, + ) + percentage_of_nutriment_converted = 0.10 + +// Pea Soup +/datum/reagent/consumable/nutriment/soup/pea + name = "Pea Soup" + description = "A humble split pea soup." + data = list("creamy peas" = 2, "parsnip" = 1) + color = "#9D7B20" + +/datum/glass_style/has_foodtype/soup/pea + required_drink_type = /datum/reagent/consumable/nutriment/soup/pea + icon_state = "peasoup" + drink_type = VEGETABLES + +/datum/chemical_reaction/food/soup/peasoup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/grown/peas = 2, + /obj/item/food/grown/parsnip = 1, + /obj/item/food/grown/carrot = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/pea = 30, + /datum/reagent/water = 10, + ) + +// Indian curry +/datum/reagent/consumable/nutriment/soup/indian_curry + name = "Indian Chicken Curry" + description = "A mild, creamy curry from the old subcontinent. Liked by the Space-British, because it reminds them of the Raj." + data = list("chicken" = 2, "creamy curry" = 4, "earthy heat" = 1) + glass_price = FOOD_PRICE_NORMAL + color = "#BB2D1A" + +/datum/glass_style/has_foodtype/soup/indian_curry + required_drink_type = /datum/reagent/consumable/nutriment/soup/indian_curry + icon_state = "indian_curry" + drink_type = VEGETABLES | MEAT | DAIRY + +/datum/chemical_reaction/food/soup/indian_curry + required_reagents = list( + /datum/reagent/water = 50, + /datum/reagent/consumable/cream = 5, + ) + required_ingredients = list( + /obj/item/food/meat/slab/chicken = 1, + /obj/item/food/grown/onion = 2, + /obj/item/food/grown/chili = 1, + /obj/item/food/grown/garlic = 1, + /obj/item/food/butter = 1, + /obj/item/food/boiledrice = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/indian_curry = 30, + // Gains a ton of other reagents from ingredients. + ) + +// Oatmeal (Soup like) +/datum/reagent/consumable/nutriment/soup/oatmeal + name = "Oatmeal" + description = "A nice bowl of oatmeal." + data = list("oats" = 1, "milk" = 1) + color = "#FFD7B4" + +/datum/glass_style/has_foodtype/soup/oatmeal + required_drink_type = /datum/reagent/consumable/nutriment/soup/oatmeal + icon_state = "oatmeal" + drink_type = DAIRY | GRAIN | BREAKFAST + +/datum/chemical_reaction/food/soup/oatmeal + required_reagents = list( + /datum/reagent/consumable/milk = 20, + ) + required_ingredients = list( + /obj/item/food/grown/oat = 2, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/oatmeal = 20, + /datum/reagent/consumable/milk = 12, + /datum/reagent/consumable/nutriment/vitamin = 8, + ) + percentage_of_nutriment_converted = 0 // Oats have barely any nutrients + +// Zurek, a Polish soup +/datum/reagent/consumable/nutriment/soup/zurek + name = "Zurek" + description = "A traditional Polish soup composed of vegetables, meat, and an egg. Goes great with bread." + data = list("creamy vegetables" = 2, "sausage" = 1) + color = "#F1CB6D" + +/datum/glass_style/has_foodtype/soup/zurek + required_drink_type = /datum/reagent/consumable/nutriment/soup/zurek + icon_state = "zurek" + drink_type = VEGETABLES | MEAT | GRAIN | BREAKFAST + +/datum/chemical_reaction/food/soup/zurek + required_reagents = list( + /datum/reagent/water = 40, + /datum/reagent/consumable/flour = 10, + ) + required_ingredients = list( + /obj/item/food/boiledegg = 1, + /obj/item/food/meat/cutlet = 1, + /obj/item/food/grown/carrot = 1, + /obj/item/food/grown/onion = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/zurek = 30, + ) + ingredient_reagent_multiplier = 0.5 + percentage_of_nutriment_converted = 0.1 + +// Cullen Skink, a Scottish soup with a funny name +/datum/reagent/consumable/nutriment/soup/cullen_skink + name = "Cullen Skink" + description = "A thick Scottish soup made of smoked fish, potatoes and onions." + data = list("creamy broth" = 1, "fish" = 1, "vegetables" = 1) + color = "#F6F664" + +/datum/glass_style/has_foodtype/soup/cullen_skink + required_drink_type = /datum/reagent/consumable/nutriment/soup/cullen_skink + icon_state = "cullen_skink" + drink_type = VEGETABLES | SEAFOOD | DAIRY + +/datum/chemical_reaction/food/soup/cullen_skink + required_reagents = list( + /datum/reagent/water = 40, + /datum/reagent/consumable/milk = 10, + /datum/reagent/consumable/blackpepper = 4, + ) + required_ingredients = list( + /obj/item/food/fishmeat = 1, + /obj/item/food/grown/onion = 1, + /obj/item/food/grown/potato = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/cullen_skink = 30, + /datum/reagent/consumable/nutriment = 6, + /datum/reagent/consumable/nutriment/protein = 4, + /datum/reagent/consumable/nutriment/vitamin = 4, + /datum/reagent/water = 6, + ) + ingredient_reagent_multiplier = 0.5 + percentage_of_nutriment_converted = 0 + +// Chicken Noodle Soup +/datum/reagent/consumable/nutriment/soup/chicken_noodle_soup + name = "Chicken Noodle Soup" + description = "A hearty bowl of chicken noodle soup, perfect for when you're stuck at home and sick." + data = list("broth" = 1, "chicken" = 1, "noodles" = 1, "carrots" = 1) + color = "#DDB23E" + +/datum/glass_style/has_foodtype/soup/chicken_noodle_soup + required_drink_type = /datum/reagent/consumable/nutriment/soup/chicken_noodle_soup + icon_state = "chicken_noodle_soup" + drink_type = VEGETABLES | MEAT | GRAIN + +/datum/chemical_reaction/food/soup/chicken_noodle_soup + required_reagents = list(/datum/reagent/water = 30) + required_ingredients = list( + /obj/item/food/grown/carrot = 1, + /obj/item/food/meat/slab/chicken = 1, + /obj/item/food/spaghetti/boiledspaghetti = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/chicken_noodle_soup = 30, + /datum/reagent/consumable/nutriment = 2, + /datum/reagent/consumable/nutriment/vitamin = 3, + /datum/reagent/consumable/nutriment/protein = 5, + ) + +// Corn Cowder +/datum/reagent/consumable/nutriment/soup/corn_chowder + name = "Corn Chowder" + description = "A creamy bowl of corn chowder, with bacon bits and mixed vegetables. One bowl is never enough." + data = list("creamy broth" = 1, "bacon" = 1, "mixed vegetables" = 1) + color = "#FFF200" + +/datum/glass_style/has_foodtype/soup/corn_chowder + required_drink_type = /datum/reagent/consumable/nutriment/soup/corn_chowder + icon_state = "corn_chowder" + drink_type = VEGETABLES | MEAT + +/datum/chemical_reaction/food/soup/corn_chowder + required_reagents = list( + /datum/reagent/water = 40, + /datum/reagent/consumable/cream = 5, + ) + required_ingredients = list( + /obj/item/food/grown/corn = 1, + /obj/item/food/grown/potato = 1, + /obj/item/food/grown/carrot = 1, + /obj/item/food/meat/bacon = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/corn_chowder = 30, + /datum/reagent/consumable/nutriment/protein = 4, + /datum/reagent/consumable/nutriment = 2, + ) + +// Lizard stuff + +// Atrakor Dumpling soup +/datum/reagent/consumable/nutriment/soup/atrakor_dumplings + name = "\improper Atrakor dumpling soup" + description = "A bowl of rich, meaty dumpling soup, traditionally served during the festival of Atrakor's Might on Tizira. The dumplings are shaped like the Night Sky Lord himself." + data = list("bone broth" = 1, "onion" = 1, "potato" = 1) + color = "#7B453B" + +/datum/glass_style/has_foodtype/soup/atrakor_dumplings + required_drink_type = /datum/reagent/consumable/nutriment/soup/atrakor_dumplings + icon = 'icons/obj/food/lizard.dmi' + icon_state = "atrakor_dumplings" + drink_type = MEAT | VEGETABLES | NUTS + +/datum/chemical_reaction/food/soup/atrakor_dumplings + required_reagents = list( + /datum/reagent/water = 40, + /datum/reagent/consumable/soysauce = 10, + ) + required_ingredients = list( + /obj/item/food/meat/rawcutlet = 2, + /obj/item/food/grown/onion = 1, + /obj/item/food/lizard_dumplings = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/atrakor_dumplings = 30, + /datum/reagent/water = 10, + ) + ingredient_reagent_multiplier = 0.5 + percentage_of_nutriment_converted = 0.2 + +// Meatball Soup, but lizard-like +/datum/reagent/consumable/nutriment/soup/meatball_noodles + name = "Meatball Noodle Soup" + description = "A hearty noodle soup made from meatballs and nizaya in a rich broth. Commonly topped with a handful of chopped nuts." + data = list("bone broth" = 1, "meat" = 1, "gnocchi" = 1, "peanuts" = 1) + color = "#915145" + +/datum/glass_style/has_foodtype/soup/meatball_noodles + required_drink_type = /datum/reagent/consumable/nutriment/soup/meatball_noodles + icon = 'icons/obj/food/lizard.dmi' + icon_state = "meatball_noodles" + drink_type = MEAT | VEGETABLES | NUTS + +/datum/chemical_reaction/food/soup/meatball_noodles + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/meat/rawcutlet = 2, + /obj/item/food/grown/onion = 1, + /obj/item/food/spaghetti/nizaya = 1, + /obj/item/food/meatball = 2, + /obj/item/food/grown/peanut = 1 + ) + results = list( + /datum/reagent/consumable/nutriment/soup/meatball_noodles = 30, + /datum/reagent/water = 10, + ) + ingredient_reagent_multiplier = 0.5 + percentage_of_nutriment_converted = 0.1 + +// Black Broth +/datum/reagent/consumable/nutriment/soup/black_broth + name = "\improper Tiziran black broth" + description = "A bowl of sausage, onion, blood and vinegar, served ice cold. Every bit as rough as it sounds." + data = list("vinegar" = 1, "iron" = 1) + color = "#340010" + +/datum/glass_style/has_foodtype/soup/black_broth + required_drink_type = /datum/reagent/consumable/nutriment/soup/black_broth + icon = 'icons/obj/food/lizard.dmi' + icon_state = "black_broth" + drink_type = MEAT | VEGETABLES | GORE + +/datum/chemical_reaction/food/soup/black_broth + required_reagents = list( + /datum/reagent/water = 40, + /datum/reagent/consumable/vinegar = 8, + /datum/reagent/blood = 8, + /datum/reagent/consumable/ice = 4, + ) + required_ingredients = list( + /obj/item/food/tiziran_sausage = 1, + /obj/item/food/grown/onion = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/black_broth = 30, + /datum/reagent/blood = 8, + /datum/reagent/consumable/liquidgibs = 7, + /datum/reagent/consumable/vinegar = 5, + ) + ingredient_reagent_multiplier = 0.5 + percentage_of_nutriment_converted = 0.1 + +// Jellyfish Stew +/datum/reagent/consumable/nutriment/soup/jellyfish + name = "Jellyfish Stew" + description = "A slimy bowl of jellyfish stew. It jiggles if you shake it." + data = list("slime" = 1) + color = "#3FAA7E" + +/datum/glass_style/has_foodtype/soup/jellyfish + required_drink_type = /datum/reagent/consumable/nutriment/soup/jellyfish + icon = 'icons/obj/food/lizard.dmi' + icon_state = "jellyfish_stew" + drink_type = MEAT | VEGETABLES | GORE + +/datum/chemical_reaction/food/soup/jellyfish_stew + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/canned/jellyfish = 1, + /obj/item/food/grown/soybeans = 1, + /obj/item/food/grown/redbeet = 1, + /obj/item/food/grown/potato = 1 + ) + results = list( + /datum/reagent/consumable/nutriment/soup/jellyfish = 30, + /datum/reagent/water = 5, + ) + +// Rootbread Soup +/datum/reagent/consumable/nutriment/soup/rootbread + name = "Rootbread Soup" + description = "A big bowl of spicy, savoury soup made with rootbread. Heavily seasoned, and very tasty." + data = list("bread" = 1, "egg" = 1, "chili" = 1, "garlic" = 1) + color = "#AC3232" + +/datum/glass_style/has_foodtype/soup/rootbread + required_drink_type = /datum/reagent/consumable/nutriment/soup/rootbread + icon = 'icons/obj/food/lizard.dmi' + icon_state = "rootbread_soup" + drink_type = MEAT | VEGETABLES + +/datum/chemical_reaction/food/soup/rootbread_soup + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/breadslice/root = 2, + /obj/item/food/grown/garlic = 1, + /obj/item/food/grown/chili = 1, + /obj/item/food/egg = 1 + ) + results = list( + /datum/reagent/consumable/nutriment/soup/rootbread = 30, + /datum/reagent/consumable/nutriment/protein = 8, + ) + percentage_of_nutriment_converted = 0.2 + +// Moth stuff + +// Cotton Soup +/datum/reagent/consumable/nutriment/soup/cottonball + name = "Flöfrölenmæsch" //flöf = cotton, rölen = ball, mæsch = soup + description = "A soup made from raw cotton in a flavourful vegetable broth. Enjoyed only by moths and the criminally tasteless." + data = list("cotton" = 1, "broth" = 1) + color = "#E6A625" + +/datum/glass_style/has_foodtype/soup/cottonball + required_drink_type = /datum/reagent/consumable/nutriment/soup/cottonball + name = "flöfrölenmæsch" + icon = 'icons/obj/food/moth.dmi' + icon_state = "moth_cotton_soup" + drink_type = VEGETABLES | CLOTH + +/datum/chemical_reaction/food/soup/cottonball + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/grown/cotton = 1, // Why are you buying clothes at the soup store?! + /obj/item/food/grown/onion = 1, + /obj/item/food/grown/carrot = 1, + /obj/item/food/grown/eggplant = 1, + /obj/item/food/oven_baked_corn = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/cottonball = 30, + ) + ingredient_reagent_multiplier = 0.5 + percentage_of_nutriment_converted = 0.1 // Cotton has no nutrition + +// Cheese Soup +/datum/reagent/consumable/nutriment/soup/cheese + name = "Ælosterrmæsch" //ælo = cheese, sterr = melt, mæsch = soup + description = "A simple and filling soup made from homemade cheese and sweet potato. \ + The curds provide texture while the whey provides volume- and they both provide deliciousness!" + data = list("cheese" = 1, "cream" = 1, "sweet potato" = 1) + color = "#F3CE3A" + +/datum/glass_style/has_foodtype/soup/cheese + required_drink_type = /datum/reagent/consumable/nutriment/soup/cheese + name = "ælosterrmæsch" + icon = 'icons/obj/food/moth.dmi' + icon_state = "moth_cheese_soup" + drink_type = DAIRY | GRAIN + +/datum/chemical_reaction/food/soup/cheese + required_reagents = list( + /datum/reagent/water = 30, + /datum/reagent/consumable/flour = 10, + /datum/reagent/consumable/milk = 10, + ) + required_ingredients = list( + /obj/item/food/cheese/wedge = 2, + /obj/item/food/butter = 1, + /obj/item/food/grown/potato/sweet = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/cheese = 30, + /datum/reagent/consumable/nutriment/protein = 8, + /datum/reagent/consumable/milk = 2, + ) + +// Seed Soup +/datum/reagent/consumable/nutriment/soup/seed + name = "Misklmæsch" //miskl = seed, mæsch = soup + description = "A seed based soup, made by germinating seeds and then boiling them. \ + Produces a particularly bitter broth which is usually balanced by the addition of vinegar." + data = list("bitterness" = 1, "sourness" = 1) + color = "#4F6F31" + +/datum/glass_style/has_foodtype/soup/seed + required_drink_type = /datum/reagent/consumable/nutriment/soup/seed + name = "misklmæsch" + icon = 'icons/obj/food/moth.dmi' + icon_state = "moth_seed_soup" + drink_type = VEGETABLES + +/datum/chemical_reaction/food/soup/seed + required_reagents = list( + /datum/reagent/water = 40, + /datum/reagent/consumable/vinegar = 10, + ) + required_ingredients = list( + /obj/item/seeds/sunflower = 1, + /obj/item/seeds/poppy/lily = 1, + /obj/item/seeds/ambrosia = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/seed = 30, + /datum/reagent/consumable/nutriment/vitamin = 13, + /datum/reagent/consumable/nutriment = 12, + /datum/reagent/consumable/vinegar = 8, + /datum/reagent/water = 7, + ) + +// Bean Soup +/datum/reagent/consumable/nutriment/soup/beans + name = "Prickeldröndolhaskl" //prickeld = spicy, röndol = bean, haskl = stew + description = "A spicy bean stew with lots of veggies, commonly served aboard the fleet as a filling and satisfying meal with rice or bread." + data = list("beans" = 1, "cabbage" = 1, "spicy sauce" = 1) + color = "#DF7126" + +/datum/glass_style/has_foodtype/soup/beans + required_drink_type = /datum/reagent/consumable/nutriment/soup/beans + name = "prickeldröndolhaskl" + icon = 'icons/obj/food/moth.dmi' + icon_state = "moth_bean_stew" + drink_type = VEGETABLES + +/datum/chemical_reaction/food/soup/beans + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/canned/beans = 1, + /obj/item/food/grown/cabbage = 1, + /obj/item/food/grown/tomato = 1, + /obj/item/food/grown/onion = 1, + /obj/item/food/grown/chili = 1, + /obj/item/food/oven_baked_corn = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/beans = 30, + /datum/reagent/consumable/nutriment/protein = 10, + /datum/reagent/water = 10, + ) + ingredient_reagent_multiplier = 0.5 + percentage_of_nutriment_converted = 0.1 + +// Oat Soup, but not oatmeal +/datum/reagent/consumable/nutriment/soup/moth_oats + name = "Häfmisklhaskl" //häfmiskl = oat (häf from German hafer meaning oat, miskl meaning seed), haskl = stew + description = "A spicy bean stew with lots of veggies, commonly served aboard the fleet as a filling and satisfying meal with rice or bread." + data = list("oats" = 1, "sweet potato" = 1, "carrot" = 1, "parsnip" = 1, "pumpkin" = 1) + color = "#CAA94E" + +/datum/glass_style/has_foodtype/soup/moth_oats + required_drink_type = /datum/reagent/consumable/nutriment/soup/moth_oats + name = "häfmisklhaskl" + icon = 'icons/obj/food/moth.dmi' + icon_state = "moth_oat_stew" + drink_type = VEGETABLES | GRAIN + +/datum/chemical_reaction/food/soup/moth_oats + required_reagents = list(/datum/reagent/water = 50) + required_ingredients = list( + /obj/item/food/grown/oat = 1, + /obj/item/food/grown/potato/sweet = 1, + /obj/item/food/grown/parsnip = 1, + /obj/item/food/grown/carrot = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/moth_oats = 30, + ) + percentage_of_nutriment_converted = 0.1 + +// Fire Soup +/datum/reagent/consumable/nutriment/soup/fire_soup + name = "Tömpröttkrakklmæsch" //tömprött = heart (tömp = thump, rött = muscle), krakkl = fire, mæsch = soup + description = "Tömpröttkrakklmæsch, or heartburn soup, is a cold soup dish that originated amongst the jungle moths, \ + and is named for two things- its rosy pink colour, and its scorchingly hot chili heat." + data = list("love" = 1, "hate" = 1) + color = "#FBA8F3" + +/datum/glass_style/has_foodtype/soup/fire_soup + required_drink_type = /datum/reagent/consumable/nutriment/soup/fire_soup + name = "tömpröttkrakklmæsch" + icon = 'icons/obj/food/moth.dmi' + icon_state = "moth_fire_soup" + drink_type = VEGETABLES | DAIRY + +/datum/chemical_reaction/food/soup/fire_soup + required_reagents = list( + /datum/reagent/water = 30, + /datum/reagent/consumable/yoghurt = 15, + /datum/reagent/consumable/vinegar = 5, + ) + required_ingredients = list( + /obj/item/food/grown/ghost_chili = 1, + /obj/item/food/tofu = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/fire_soup = 30, + /datum/reagent/consumable/nutriment/protein = 8, + /datum/reagent/consumable/vinegar = 2, + ) + ingredient_reagent_multiplier = 0.33 // Chilis have a TON of capsaicin naturally + percentage_of_nutriment_converted = 0 + +// Rice Porridge (Soup-ish) +/datum/reagent/consumable/nutriment/soup/rice_porridge + name = "Rice Porridge" + description = "A plate of rice porridge. It's mostly flavourless, but it does fill a spot. \ + To the Chinese it's congee, and moths call it höllflöfmisklsløsk." //höllflöfmiskl = rice (höllflöf = cloud, miskl = seed), sløsk = porridge + data = list("nothing" = 1) + color = "#EDE3E3" + +/datum/glass_style/has_foodtype/soup/rice_porridge + required_drink_type = /datum/reagent/consumable/nutriment/soup/rice_porridge + name = "rice porridge" + icon = 'icons/obj/food/moth.dmi' + icon_state = "rice_porridge" + drink_type = GRAIN + +/datum/chemical_reaction/food/soup/rice_porridge + required_reagents = list( + /datum/reagent/water = 30, + /datum/reagent/consumable/salt = 5, + ) + required_ingredients = list( + /obj/item/food/boiledrice = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/rice_porridge = 20, + /datum/reagent/consumable/salt = 5, + ) + percentage_of_nutriment_converted = 0.15 + +// Cornmeal Porridge (Soup-ish) +// Also, pretty much just a normal chemical reaction. Used in other stuff +/datum/reagent/consumable/nutriment/soup/cornmeal_porridge + name = "Cornmeal Porridge" + description = "A plate of cornmeal porridge. It's more flavourful than most porridges, and makes a good base for other flavours, too." + data = list("cornmeal" = 1) + color = "#ECDA7B" + +/datum/glass_style/has_foodtype/soup/cornmeal_porridge + required_drink_type = /datum/reagent/consumable/nutriment/soup/cornmeal_porridge + name = "cornmeal porridge" + icon = 'icons/obj/food/moth.dmi' + icon_state = "cornmeal_porridge" + drink_type = GRAIN + +/datum/chemical_reaction/food/soup/cornmeal_porridge + required_other = FALSE + required_reagents = list( + /datum/reagent/consumable/cornmeal = 20, + /datum/reagent/water = 20, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/cornmeal_porridge = 20, + ) + +// Cheese Porridge (Soup-ish) +/datum/reagent/consumable/nutriment/soup/cheese_porridge + name = "Cheesy Porridge" //milk, polenta, firm cheese, curd cheese, butter + description = "A rich and creamy bowl of cheesy cornmeal porridge." + data = list("cornmeal" = 1, "cheese" = 1, "more cheese" = 1, "lots of cheese" = 1) + color = "#F0DD5A" + +/datum/glass_style/has_foodtype/soup/cheese_porridge + required_drink_type = /datum/reagent/consumable/nutriment/soup/cheese_porridge + name = "cheesy porridge" + icon = 'icons/obj/food/moth.dmi' + icon_state = "cheesy_porridge" + drink_type = DAIRY | GRAIN + +/datum/chemical_reaction/food/soup/cheese_porridge + required_reagents = list( + /datum/reagent/consumable/milk = 5, + /datum/reagent/consumable/nutriment/soup/cornmeal_porridge = 20, + /datum/reagent/water = 20, + ) + required_ingredients = list( + /obj/item/food/cheese/firm_cheese_slice = 1, + /obj/item/food/cheese/curd_cheese = 1, + /obj/item/food/butter = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/cheese_porridge = 30, + /datum/reagent/consumable/nutriment/vitamin = 8, + /datum/reagent/consumable/nutriment/protein = 4, + ) + +// Rice Porridge again but with Toechtause +/datum/reagent/consumable/nutriment/soup/toechtauese_rice_porridge + name = "Töchtaüse Rice Porridge" + description = "Commonly served aboard the mothic fleet, rice porridge with töchtaüse syrup is more palatable than the regular stuff, if even just because it's spicier than normal." + data = list("sugar" = 1, "spice" = 1) + color = "#D8CFCC" + +/datum/glass_style/has_foodtype/soup/toechtauese_rice_porridge + required_drink_type = /datum/reagent/consumable/nutriment/soup/toechtauese_rice_porridge + name = "töchtaüse rice porridge" + icon = 'icons/obj/food/moth.dmi' + icon_state = "toechtauese_rice_porridge" + drink_type = GRAIN | VEGETABLES + +/datum/chemical_reaction/food/soup/toechtauese_rice_porridge + required_reagents = list( + /datum/reagent/consumable/nutriment/soup/rice_porridge = 20, + /datum/reagent/consumable/toechtauese_syrup = 10, + /datum/reagent/water = 10, + ) + required_ingredients = list( + /obj/item/food/grown/chili = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/toechtauese_rice_porridge = 30, + /datum/reagent/consumable/nutriment/protein = 6, + /datum/reagent/consumable/nutriment/vitamin = 6, + /datum/reagent/consumable/toechtauese_syrup = 6, + ) + +// Red Porridge +/datum/reagent/consumable/nutriment/soup/red_porridge + name = "Eltsløsk ül a priktæolk" //eltsløsk = red porridge, ül a = with, prikt = sour, æolk = cream + description = "Red porridge with yoghurt. The name and vegetable ingredients obscure the sweet nature of the dish, which is commonly served as a dessert aboard the fleet." + data = list("sweet beets" = 1, "sugar" = 1, "sweetened yoghurt" = 1) + color = "#FF858B" + +/datum/glass_style/has_foodtype/soup/red_porridge + required_drink_type = /datum/reagent/consumable/nutriment/soup/red_porridge + name = "eltsløsk ül a priktæolk" + icon = 'icons/obj/food/moth.dmi' + icon_state = "red_porridge" + drink_type = VEGETABLES | SUGAR | DAIRY + +/datum/chemical_reaction/food/soup/red_porridge + required_temp = WATER_BOILING_POINT + optimal_temp = 400 + overheat_temp = 415 // Caramel forms + thermic_constant = 0 + required_reagents = list( + /datum/reagent/consumable/vanilla = 10, + /datum/reagent/consumable/yoghurt = 20, + /datum/reagent/consumable/sugar = 10, + ) + required_ingredients = list( + /obj/item/food/grown/redbeet = 1, + ) + results = list( + /datum/reagent/consumable/nutriment/soup/red_porridge = 24, + /datum/reagent/consumable/nutriment/protein = 8, + /datum/reagent/consumable/sugar = 8, + ) + percentage_of_nutriment_converted = 0.1 diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_guide.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_guide.dm index 23612db1aca..e14b6e9a962 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_guide.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_guide.dm @@ -37,13 +37,25 @@ non_craftable = TRUE /datum/crafting_recipe/food/reaction/New() - ..() + . = ..() if(!reaction) return - var/datum/chemical_reaction/chemical_reaction = new reaction // This could use GLOB.chemical_reactions_list if it was initialized by now - reqs = chemical_reaction.required_reagents - chem_catalysts = chemical_reaction.required_catalysts - if (chemical_reaction.results.len) + + if(length(GLOB.chemical_reactions_list)) + setup_chemical_reaction_details(GLOB.chemical_reactions_list[reaction]) + else + // May be called before chemical reactions list is instantiated + var/datum/chemical_reaction/chemical_reaction = new reaction() + setup_chemical_reaction_details(chemical_reaction) + qdel(chemical_reaction) + +/** + * Sets up information for our recipe based on the chemical reaction we have set. + */ +/datum/crafting_recipe/food/reaction/proc/setup_chemical_reaction_details(datum/chemical_reaction/chemical_reaction) + reqs = chemical_reaction.required_reagents?.Copy() + chem_catalysts = chemical_reaction.required_catalysts?.Copy() + if(isnull(result) && length(chemical_reaction.results)) result = chemical_reaction.results[1] result_amount = chemical_reaction.results[result] diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm index ee6b94d6d7f..ec5db9baf14 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm @@ -350,70 +350,6 @@ result = /obj/item/food/honey_roll category = CAT_LIZARD -/datum/crafting_recipe/food/atrakor_dumplings - name = "Atrakor dumpling soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/meat/rawcutlet = 2, - /obj/item/food/grown/onion = 1, - /obj/item/food/lizard_dumplings = 1, - /datum/reagent/consumable/soysauce = 5 - ) - result = /obj/item/food/soup/atrakor_dumplings - category = CAT_LIZARD - -/datum/crafting_recipe/food/meatball_noodles - name = "Meatball noodle soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/meat/rawcutlet = 2, - /obj/item/food/grown/onion = 1, - /obj/item/food/spaghetti/nizaya = 1, - /obj/item/food/meatball = 2, - /obj/item/food/grown/peanut = 1 - ) - result = /obj/item/food/soup/meatball_noodles - category = CAT_LIZARD - -/datum/crafting_recipe/food/black_broth - name = "Tiziran black broth" - reqs = list( - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/tiziran_sausage = 1, - /obj/item/food/grown/onion = 1, - /datum/reagent/consumable/vinegar = 5, - /datum/reagent/blood = 5, - /datum/reagent/consumable/ice = 2 - ) - result = /obj/item/food/soup/black_broth - category = CAT_LIZARD - -/datum/crafting_recipe/food/jellyfish_stew - name = "Jellyfish stew" - reqs = list( - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/canned/jellyfish = 1, - /obj/item/food/grown/soybeans = 1, - /obj/item/food/grown/redbeet = 1, - /obj/item/food/grown/potato = 1 - ) - result = /obj/item/food/soup/jellyfish - category = CAT_LIZARD - -/datum/crafting_recipe/food/rootbread_soup - name = "Rootbread soup" - reqs = list( - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/breadslice/root = 2, - /obj/item/food/grown/garlic = 1, - /obj/item/food/grown/chili = 1, - /obj/item/food/egg = 1 - ) - result = /obj/item/food/soup/rootbread_soup - category = CAT_LIZARD - /datum/crafting_recipe/food/black_eggs name = "Black scrambled eggs" reqs = list( @@ -495,3 +431,25 @@ ) result = /obj/item/food/steeped_mushrooms category = CAT_LIZARD + +// Soups + +/datum/crafting_recipe/food/reaction/soup/atrakor_dumplings + reaction = /datum/chemical_reaction/food/soup/atrakor_dumplings + category = CAT_LIZARD + +/datum/crafting_recipe/food/reaction/soup/meatball_noodles + reaction = /datum/chemical_reaction/food/soup/meatball_noodles + category = CAT_LIZARD + +/datum/crafting_recipe/food/reaction/soup/black_broth + reaction = /datum/chemical_reaction/food/soup/black_broth + category = CAT_LIZARD + +/datum/crafting_recipe/food/reaction/soup/jellyfish_stew + reaction = /datum/chemical_reaction/food/soup/jellyfish_stew + category = CAT_LIZARD + +/datum/crafting_recipe/food/reaction/soup/rootbread_soup + reaction = /datum/chemical_reaction/food/soup/rootbread_soup + category = CAT_LIZARD diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm index 263cddc3b84..1f238916b6a 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm @@ -321,6 +321,26 @@ result = /obj/item/food/popcorn/salty category = CAT_MISCFOOD +/datum/crafting_recipe/food/spacylibertyduff + name = "Spacy liberty duff" + reqs = list( + /datum/reagent/consumable/ethanol/vodka = 5, + /obj/item/reagent_containers/cup/bowl = 1, + /obj/item/food/grown/mushroom/libertycap = 3 + ) + result = /obj/item/food/bowled/spacylibertyduff + category = CAT_MISCFOOD + +/datum/crafting_recipe/food/amanitajelly + name = "Amanita jelly" + reqs = list( + /datum/reagent/consumable/ethanol/vodka = 5, + /obj/item/reagent_containers/cup/bowl = 1, + /obj/item/food/grown/mushroom/amanita = 3 + ) + result = /obj/item/food/bowled/amanitajelly + category = CAT_MISCFOOD + /datum/crafting_recipe/food/buttered_baked_potato name = "Buttered baked potato" reqs = list( diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_moth.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_moth.dm index e5b7305b4ae..fadfe23a87e 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_moth.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_moth.dm @@ -69,8 +69,8 @@ /datum/crafting_recipe/food/loaded_curds name = "Ozlsettitæloskekllön ede pommes (Loaded curds and fries)" reqs = list( + /datum/reagent/consumable/nutriment/soup/chili_sin_carne = 10, /obj/item/food/cheese/cheese_curds = 1, - /obj/item/food/soup/vegetarian_chili = 1, /obj/item/food/onion_slice = 1, /obj/item/food/cheese/wedge = 1, /obj/item/food/fries = 1 @@ -99,11 +99,11 @@ /datum/crafting_recipe/food/raw_baked_rice reqs = list( + /datum/reagent/consumable/nutriment/soup/vegetable_soup = 10, /obj/item/food/boiledrice = 2, - /obj/item/food/soup/vegetable = 1, - /obj/item/food/grown/potato = 2, /obj/item/food/grown/chili = 1, - /obj/item/food/grown/herbs = 1 + /obj/item/food/grown/herbs = 1, + /obj/item/food/grown/potato = 2, ) result = /obj/item/food/raw_baked_rice category = CAT_MOTH @@ -182,149 +182,26 @@ result = /obj/item/food/mac_balls category = CAT_MOTH -/datum/crafting_recipe/food/moth_cotton_soup - name = "Flöfrölenmæsch (Cottonball soup)" - reqs = list( - /obj/item/grown/cotton = 1, - /obj/item/food/grown/onion = 1, - /obj/item/food/grown/carrot = 1, - /obj/item/food/grown/eggplant = 1, - /obj/item/food/oven_baked_corn = 1, - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1 - ) - result = /obj/item/food/soup/moth_cotton_soup - category = CAT_MOTH - -/datum/crafting_recipe/food/moth_cheese_soup - name = "Ælosterrmæsch (Cheese soup)" - reqs = list( - /obj/item/food/cheese/wedge = 2, - /obj/item/food/butter = 1, - /obj/item/food/grown/potato/sweet = 1, - /datum/reagent/consumable/flour = 5, - /datum/reagent/consumable/milk = 5, - /obj/item/reagent_containers/cup/bowl = 1 - ) - result = /obj/item/food/soup/moth_cheese_soup - category = CAT_MOTH - -/datum/crafting_recipe/food/moth_seed_soup - name = "Misklmæsch (Seed soup)" - reqs = list( - /obj/item/seeds/sunflower = 1, - /obj/item/seeds/poppy/lily = 1, - /obj/item/seeds/ambrosia = 1, - /datum/reagent/water = 10, - /datum/reagent/consumable/vinegar = 5, - /obj/item/reagent_containers/cup/bowl = 1 - ) - result = /obj/item/food/soup/moth_seed_soup - category = CAT_MOTH - -/datum/crafting_recipe/food/moth_bean_stew - name = "Prickeldröndolhaskl (Spicy bean stew)" - reqs = list( - /obj/item/food/canned/beans = 1, - /obj/item/food/grown/cabbage = 1, - /obj/item/food/grown/tomato = 1, - /obj/item/food/grown/onion = 1, - /obj/item/food/grown/chili = 1, - /obj/item/food/oven_baked_corn = 1, - /datum/reagent/water = 5, - /obj/item/reagent_containers/cup/bowl = 1 - ) - result = /obj/item/food/soup/moth_bean_stew - category = CAT_MOTH - -/datum/crafting_recipe/food/moth_oat_stew - name = "Häfmisklhaskl (Oat stew)" - reqs = list( - /obj/item/food/grown/oat = 1, - /obj/item/food/grown/potato/sweet = 1, - /obj/item/food/grown/parsnip = 1, - /obj/item/food/grown/carrot = 1, - /datum/reagent/water = 5, - /obj/item/reagent_containers/cup/bowl = 1 - ) - result = /obj/item/food/soup/moth_oat_stew - category = CAT_MOTH - -/datum/crafting_recipe/food/moth_fire_soup - name = "Tömpröttkrakklmæsch (Heartburn soup)" - reqs = list( - /obj/item/food/grown/ghost_chili = 1, - /obj/item/food/tofu = 1, - /datum/reagent/consumable/yoghurt = 10, - /datum/reagent/consumable/vinegar = 2, - /obj/item/reagent_containers/cup/bowl = 1 - ) - result = /obj/item/food/soup/moth_fire_soup - category = CAT_MOTH - -/datum/crafting_recipe/food/rice_porridge - name = "Rice porridge" - reqs = list( - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/boiledrice = 1, - /datum/reagent/water = 10, - /datum/reagent/consumable/salt = 2 - ) - result = /obj/item/food/soup/rice_porridge - category = CAT_MOTH - /datum/crafting_recipe/food/hua_mulan_congee name = "Hua Mulan congee" reqs = list( - /obj/item/food/soup/rice_porridge = 1, + /datum/reagent/consumable/nutriment/soup/rice_porridge = 10, /obj/item/food/meat/bacon = 1, /obj/item/food/friedegg = 2 ) - result = /obj/item/food/soup/hua_mulan_congee - category = CAT_MOTH - -/datum/crafting_recipe/food/toechtauese_rice_porridge - name = "Töchtaüse rice porridge" - reqs = list( - /obj/item/food/soup/rice_porridge = 1, - /obj/item/food/grown/chili = 1, - /datum/reagent/consumable/toechtauese_syrup = 5 - ) - result = /obj/item/food/soup/toechtauese_rice_porridge - category = CAT_MOTH - -/datum/crafting_recipe/food/cornmeal_porridge - name = "Cornmeal porridge" - reqs = list( - /datum/reagent/consumable/cornmeal = 10, - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1 - ) - result = /obj/item/food/soup/cornmeal_porridge - category = CAT_MOTH - -/datum/crafting_recipe/food/cheesy_porridge - name = "Cheesy porridge" - reqs = list( - /obj/item/food/soup/cornmeal_porridge = 1, - /datum/reagent/consumable/milk = 5, - /obj/item/food/cheese/firm_cheese_slice = 1, - /obj/item/food/cheese/curd_cheese = 1, - /obj/item/food/butter = 1 - ) - result = /obj/item/food/soup/cheesy_porridge + result = /obj/item/food/bowled/hua_mulan_congee category = CAT_MOTH /datum/crafting_recipe/food/fried_eggplant_polenta name = "Fried eggplant and polenta" reqs = list( - /obj/item/food/soup/cheesy_porridge = 1, + /datum/reagent/consumable/nutriment/soup/cornmeal_porridge = 10, /obj/item/food/grown/eggplant = 1, /obj/item/food/breadslice/plain = 2, /obj/item/food/tomato_sauce = 1, /obj/item/food/cheese/mozzarella = 1 ) - result = /obj/item/food/soup/fried_eggplant_polenta + result = /obj/item/food/bowled/fried_eggplant_polenta category = CAT_MOTH /datum/crafting_recipe/food/caprese_salad @@ -470,29 +347,6 @@ result = /obj/item/food/cake/mothmallow category = CAT_MOTH -/datum/crafting_recipe/food/red_porridge - name = "Eltsløsk ül a priktæolk (Red Porridge and Yoghurt)" - reqs = list( - /obj/item/food/grown/redbeet = 1, - /datum/reagent/consumable/vanilla = 5, - /datum/reagent/consumable/yoghurt = 10, - /datum/reagent/consumable/sugar = 5 - ) - result = /obj/item/food/soup/red_porridge - category = CAT_MOTH - -/datum/crafting_recipe/food/chili_sin_carne - name = "Chili sin carne (vegetarian chili)" - reqs = list( - /obj/item/reagent_containers/cup/bowl = 1, - /datum/reagent/water = 10, - /datum/reagent/consumable/salt = 1, - /obj/item/food/grown/chili = 1, - /obj/item/food/grown/tomato = 1 - ) - result = /obj/item/food/soup/vegetarian_chili - category = CAT_MOTH - /datum/crafting_recipe/food/moffin name = "Moffin" reqs = list( @@ -502,3 +356,61 @@ ) result = /obj/item/food/muffin/moffin category = CAT_MOTH + +// Soups + +/datum/crafting_recipe/food/reaction/soup/cottonball + name = "Flöfrölenmæsch (cottonball soup)" + reaction = /datum/chemical_reaction/food/soup/cottonball + category = CAT_MOTH + +/datum/crafting_recipe/food/reaction/soup/cheese + name = "Ælosterrmæsch (cheese soup)" + reaction = /datum/chemical_reaction/food/soup/cheese + category = CAT_MOTH + +/datum/crafting_recipe/food/reaction/soup/seed + name = "Misklmæsch (seed soup)" + reaction = /datum/chemical_reaction/food/soup/seed + category = CAT_MOTH + +/datum/crafting_recipe/food/reaction/soup/beans + name = "Prickeldröndolhaskl (spicy bean stew)" + reaction = /datum/chemical_reaction/food/soup/beans + category = CAT_MOTH + +/datum/crafting_recipe/food/reaction/soup/moth_oats + name = "Häfmisklhaskl (oat stew)" + reaction = /datum/chemical_reaction/food/soup/moth_oats + category = CAT_MOTH + +/datum/crafting_recipe/food/reaction/soup/fire_soup + name = "Tömpröttkrakklmæsch (heartburn soup)" + reaction = /datum/chemical_reaction/food/soup/fire_soup + category = CAT_MOTH + +/datum/crafting_recipe/food/reaction/soup/rice_porridge + reaction = /datum/chemical_reaction/food/soup/rice_porridge + category = CAT_MOTH + +/datum/crafting_recipe/food/reaction/soup/toechtauese_rice_porridge + reaction = /datum/chemical_reaction/food/soup/toechtauese_rice_porridge + category = CAT_MOTH + +/datum/crafting_recipe/food/reaction/soup/red_porridge + name = "Eltsløsk ül a priktæolk (red porridge and yoghurt)" + reaction = /datum/chemical_reaction/food/soup/red_porridge + category = CAT_MOTH + +/datum/crafting_recipe/food/reaction/soup/cornmeal_porridge + reaction = /datum/chemical_reaction/food/soup/cornmeal_porridge + category = CAT_MOTH + +/datum/crafting_recipe/food/reaction/soup/cheese_porridge + reaction = /datum/chemical_reaction/food/soup/cheese_porridge + category = CAT_MOTH + +/datum/crafting_recipe/food/reaction/soup/chili_sin_carne + name = "Chili Sin Carne (Vegetarian Chili)" + reaction = /datum/chemical_reaction/food/soup/chili_sin_carne + category = CAT_MOTH diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_salad.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_salad.dm index 220fbdaf6cc..653aac9672c 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_salad.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_salad.dm @@ -34,19 +34,6 @@ result = /obj/item/food/salad/validsalad category = CAT_SALAD -/datum/crafting_recipe/food/monkeysdelight - name = "Monkeys delight" - reqs = list( - /datum/reagent/consumable/flour = 5, - /datum/reagent/consumable/salt = 1, - /datum/reagent/consumable/blackpepper = 1, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/monkeycube = 1, - /obj/item/food/grown/banana = 1 - ) - result = /obj/item/food/soup/monkeysdelight - category = CAT_SALAD - /datum/crafting_recipe/food/melonfruitbowl name ="Melon fruit bowl" reqs = list( diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm deleted file mode 100644 index f9993277061..00000000000 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm +++ /dev/null @@ -1,384 +0,0 @@ - -// see code/module/crafting/table.dm - -////////////////////////////////////////////////SOUP//////////////////////////////////////////////// - -/datum/crafting_recipe/food/meatballsoup - name = "Meatball soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/meatball = 1, - /obj/item/food/grown/carrot = 1, - /obj/item/food/grown/potato = 1 - ) - result = /obj/item/food/soup/meatball - category = CAT_SOUP - -/datum/crafting_recipe/food/vegetablesoup - name = "Vegetable soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/carrot = 1, - /obj/item/food/grown/corn = 1, - /obj/item/food/grown/eggplant = 1, - /obj/item/food/grown/potato = 1 - ) - result = /obj/item/food/soup/vegetable - category = CAT_SOUP - -/datum/crafting_recipe/food/nettlesoup - name = "Nettle soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/nettle = 1, - /obj/item/food/grown/potato = 1, - /obj/item/food/boiledegg = 1 - ) - result = /obj/item/food/soup/nettle - category = CAT_SOUP - -/datum/crafting_recipe/food/wingfangchu - name = "Wingfangchu" - reqs = list( - /obj/item/reagent_containers/cup/bowl = 1, - /datum/reagent/consumable/soysauce = 5, - /obj/item/food/meat/cutlet/xeno = 2 - ) - result = /obj/item/food/soup/wingfangchu - category = CAT_SOUP - -/datum/crafting_recipe/food/wishsoup - name = "Wish soup" - reqs = list( - /datum/reagent/water = 20, - /obj/item/reagent_containers/cup/bowl = 1 - ) - result= /obj/item/food/soup/wish - category = CAT_SOUP - -/datum/crafting_recipe/food/hotchili - name = "Hot chili" - reqs = list( - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/meat/cutlet = 2, - /obj/item/food/grown/chili = 1, - /obj/item/food/grown/tomato = 1 - ) - result = /obj/item/food/soup/hotchili - category = CAT_SOUP - -/datum/crafting_recipe/food/coldchili - name = "Cold chili" - reqs = list( - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/meat/cutlet = 2, - /obj/item/food/grown/icepepper = 1, - /obj/item/food/grown/tomato = 1 - ) - result = /obj/item/food/soup/coldchili - category = CAT_SOUP - -/datum/crafting_recipe/food/clownchili - name = "Chili con carnival" - reqs = list( - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/meat/cutlet = 2, - /obj/item/food/grown/chili = 1, - /obj/item/food/grown/tomato = 1, - /obj/item/clothing/shoes/clown_shoes = 1 - ) - result = /obj/item/food/soup/clownchili - category = CAT_SOUP - -/datum/crafting_recipe/food/tomatosoup - name = "Tomato soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/tomato = 2 - ) - result = /obj/item/food/soup/tomato - category = CAT_SOUP - -/datum/crafting_recipe/food/eyeballsoup - name = "Eyeball soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/tomato = 2, - /obj/item/organ/internal/eyes = 1 - ) - result = /obj/item/food/soup/tomato/eyeball - category = CAT_SOUP - - -/datum/crafting_recipe/food/misosoup - name = "Miso soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/soydope = 2, - /obj/item/food/tofu = 2 - ) - result = /obj/item/food/soup/miso - category = CAT_SOUP - -/datum/crafting_recipe/food/bloodsoup - name = "Blood soup" - reqs = list( - /datum/reagent/blood = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/tomato/blood = 2 - ) - result = /obj/item/food/soup/blood - category = CAT_SOUP - -/datum/crafting_recipe/food/slimesoup - name = "Slime soup" - reqs = list( - /datum/reagent/water = 10, - /datum/reagent/toxin/slimejelly = 5, - /obj/item/reagent_containers/cup/bowl = 1 - ) - result = /obj/item/food/soup/slime - category = CAT_SOUP - -/datum/crafting_recipe/food/clownstears - name = "Clowns tears" - reqs = list( - /datum/reagent/lube = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/banana = 1, - /obj/item/stack/sheet/mineral/bananium = 1 - ) - result = /obj/item/food/soup/clownstears - category = CAT_SOUP - -/datum/crafting_recipe/food/mysterysoup - name = "Mystery soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/badrecipe = 1, - /obj/item/food/tofu = 1, - /obj/item/food/boiledegg = 1, - /obj/item/food/cheese/wedge = 1, - ) - result = /obj/item/food/soup/mystery - category = CAT_SOUP - -/datum/crafting_recipe/food/mushroomsoup - name = "Mushroom soup" - reqs = list( - /datum/reagent/consumable/milk = 5, - /datum/reagent/water = 5, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/mushroom/chanterelle = 1 - ) - result = /obj/item/food/soup/mushroom - category = CAT_SOUP - -/datum/crafting_recipe/food/beetsoup - name = "Beet soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/whitebeet = 1, - /obj/item/food/grown/cabbage = 1, - ) - result = /obj/item/food/soup/beet - category = CAT_SOUP - -/datum/crafting_recipe/food/stew - name = "Stew" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/tomato = 1, - /obj/item/food/meat/cutlet = 3, - /obj/item/food/grown/potato = 1, - /obj/item/food/grown/carrot = 1, - /obj/item/food/grown/eggplant = 1, - /obj/item/food/grown/mushroom = 1 - ) - result = /obj/item/food/soup/stew - category = CAT_SOUP - -/datum/crafting_recipe/food/spacylibertyduff - name = "Spacy liberty duff" - reqs = list( - /datum/reagent/consumable/ethanol/vodka = 5, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/mushroom/libertycap = 3 - ) - result = /obj/item/food/soup/spacylibertyduff - category = CAT_SOUP - -/datum/crafting_recipe/food/amanitajelly - name = "Amanita jelly" - reqs = list( - /datum/reagent/consumable/ethanol/vodka = 5, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/mushroom/amanita = 3 - ) - result = /obj/item/food/soup/amanitajelly - category = CAT_SOUP - -/datum/crafting_recipe/food/sweetpotatosoup - name = "Sweet potato soup" - reqs = list( - /datum/reagent/water = 10, - /datum/reagent/consumable/sugar = 5, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/potato/sweet = 2 - ) - result = /obj/item/food/soup/sweetpotato - category = CAT_SOUP - -/datum/crafting_recipe/food/redbeetsoup - name = "Red beet soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/redbeet = 1, - /obj/item/food/grown/cabbage = 1 - ) - result = /obj/item/food/soup/beet/red - category = CAT_SOUP - -/datum/crafting_recipe/food/onionsoup - name = "French onion soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/onion = 1, - /obj/item/food/cheese/wedge = 1, - ) - result = /obj/item/food/soup/onion - category = CAT_SOUP - -/datum/crafting_recipe/food/bisque - name = "Bisque" - reqs = list( - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/meat/crab = 1, - /obj/item/food/boiledrice = 1 - ) - result = /obj/item/food/soup/bisque - category = CAT_SOUP - -/datum/crafting_recipe/food/bungocurry - name = "Bungo Curry" - reqs = list( - /datum/reagent/water = 5, - /datum/reagent/consumable/cream = 5, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/chili = 1, - /obj/item/food/grown/bungofruit = 1 - ) - result = /obj/item/food/soup/bungocurry - category = CAT_SOUP - -/datum/crafting_recipe/food/electron - name = "Electron Soup" - reqs = list( - /datum/reagent/water = 10, - /datum/reagent/consumable/salt = 5, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/mushroom/jupitercup = 1 - ) - result = /obj/item/food/soup/electron - category = CAT_SOUP - -/datum/crafting_recipe/food/peasoup - name = "Pea soup" - reqs = list( - /datum/reagent/water = 10, - /obj/item/food/grown/peas = 2, - /obj/item/food/grown/parsnip = 1, - /obj/item/food/grown/carrot = 1, - /obj/item/reagent_containers/cup/bowl = 1 - ) - result = /obj/item/food/soup/peasoup - category = CAT_SOUP - -/datum/crafting_recipe/food/indian_curry - name = "Indian Chicken Curry" - reqs = list( - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/meat/slab/chicken = 1, - /obj/item/food/grown/onion = 2, - /obj/item/food/grown/chili = 1, - /obj/item/food/grown/garlic = 1, - /obj/item/food/butter = 1, - /obj/item/food/boiledrice = 1, - /datum/reagent/consumable/cream = 5 - ) - result = /obj/item/food/soup/indian_curry - category = CAT_SOUP - -/datum/crafting_recipe/food/oatmeal - name = "Oatmeal" - reqs = list( - /datum/reagent/consumable/milk = 10, - /obj/item/reagent_containers/cup/bowl = 1, - /obj/item/food/grown/oat = 1 - ) - result = /obj/item/food/soup/oatmeal - category = CAT_SOUP - -/datum/crafting_recipe/food/zurek - name = "Zurek" - reqs = list( - /datum/reagent/water = 10, - /datum/reagent/consumable/flour = 5, - /obj/item/food/boiledegg = 1, - /obj/item/food/meat/cutlet = 1, - /obj/item/food/grown/carrot = 1, - /obj/item/food/grown/onion = 1, - /obj/item/reagent_containers/cup/bowl = 1, - ) - result = /obj/item/food/soup/zurek - category = CAT_SOUP - -/datum/crafting_recipe/food/cullen_skink - name = "Cullen Skink" - reqs = list( - /datum/reagent/consumable/milk = 5, - /obj/item/food/fishmeat = 1, - /obj/item/food/grown/onion = 1, - /obj/item/food/grown/potato = 1, - /datum/reagent/consumable/blackpepper = 2, - /obj/item/reagent_containers/cup/bowl = 1, - ) - result = /obj/item/food/soup/cullen_skink - category = CAT_SOUP - -/datum/crafting_recipe/food/chicken_noodle_soup - name = "Chicken Noodle Soup" - reqs = list( - /obj/item/food/meat/slab/chicken = 1, - /obj/item/food/spaghetti/boiledspaghetti = 1, - /obj/item/food/grown/carrot = 1, - /datum/reagent/water = 10, - /obj/item/reagent_containers/cup/bowl = 1, - ) - result = /obj/item/food/soup/chicken_noodle_soup - category = CAT_SOUP - -/datum/crafting_recipe/food/corn_chowder - name = "Corn Chowder" - reqs = list( - /obj/item/food/grown/corn = 1, - /obj/item/food/grown/potato = 1, - /obj/item/food/grown/carrot = 1, - /obj/item/food/meat/bacon = 1, - /datum/reagent/consumable/cream = 5, - /obj/item/reagent_containers/cup/bowl = 1, - ) - result = /obj/item/food/soup/corn_chowder - category = CAT_SOUP diff --git a/code/modules/food_and_drinks/restaurant/_venue.dm b/code/modules/food_and_drinks/restaurant/_venue.dm index 970e2819c1b..b31edd5ead8 100644 --- a/code/modules/food_and_drinks/restaurant/_venue.dm +++ b/code/modules/food_and_drinks/restaurant/_venue.dm @@ -65,17 +65,25 @@ /datum/venue/proc/order_food(mob/living/simple_animal/robot_customer/customer_pawn, datum/customer_data/customer_data) var/order = pick_weight(customer_data.orderable_objects[venue_type]) + var/list/order_args // Only for custom orders - arguments passed into New var/image/food_image var/food_line + if(ispath(order, /datum/reagent)) + // This is pain + var/datum/reagent/reagent_order = order + order_args = list("reagent_type" = reagent_order) + order = initial(reagent_order.restaurant_order) + if(ispath(order, /datum/custom_order)) // generate the special order - var/datum/custom_order/custom_order = new order(src) + var/datum/custom_order/custom_order = new order(arglist(order_args || list())) food_image = custom_order.get_order_appearance(src) food_line = custom_order.get_order_line(src) order = custom_order.dispense_order() else food_image = get_food_appearance(order) food_line = order_food_line(order) + customer_pawn.say(food_line) // common code for the food thoughts appearance @@ -106,7 +114,26 @@ ///Effects for when a customer receives their order at this venue /datum/venue/proc/on_get_order(mob/living/simple_animal/robot_customer/customer_pawn, obj/item/order_item) - SEND_SIGNAL(order_item, COMSIG_ITEM_SOLD_TO_CUSTOMER, customer_pawn, order_item) + SHOULD_CALL_PARENT(TRUE) + + // This is an item typepath, a reagent typepath, or a custom order datum instance. + var/order = customer_pawn.ai_controller.blackboard[BB_CUSTOMER_CURRENT_ORDER] + + . = SEND_SIGNAL(order_item, COMSIG_ITEM_SOLD_TO_CUSTOMER, customer_pawn) + + for(var/datum/reagent/reagent as anything in order_item.reagents?.reagent_list) + // Our order can be a reagent within the item we're receiving + if(reagent.type == order) + . |= SEND_SIGNAL(reagent, COMSIG_REAGENT_SOLD_TO_CUSTOMER, customer_pawn, order_item) + break + + // Order can be a /datum/custom_order instance + if(istype(order, /datum/custom_order)) + var/datum/custom_order/special_order = order + . |= special_order.handle_get_order(customer_pawn, order_item) + + if(. & TRANSACTION_SUCCESS) + customers_served++ ///Toggles whether the venue is open or not /datum/venue/proc/toggle_open() diff --git a/code/modules/food_and_drinks/restaurant/custom_order.dm b/code/modules/food_and_drinks/restaurant/custom_order.dm index 583c9ad2034..25ea8780241 100644 --- a/code/modules/food_and_drinks/restaurant/custom_order.dm +++ b/code/modules/food_and_drinks/restaurant/custom_order.dm @@ -28,6 +28,15 @@ stack_trace("[type]/get_order_line() not set") return "broken custom order pls call a coder" +/** + * Handles what the bot does with the order when it gets it + * + * Return [TRANSACTION_SUCCESS] to denote the order went through successfully (Not generally necessary to include here) + * Return [TRANSACTION_HANDLED] to not do any further handling of the order by the + */ +/datum/custom_order/proc/handle_get_order(mob/living/simple_animal/robot_customer/customer_pawn, obj/item/order_item) + return NONE + /datum/custom_order/moth_clothing /// The item type that we want to order, usually clothing var/wanted_clothing_type @@ -53,6 +62,13 @@ if (!QDELETED(buffet.shoes)) orderable[buffet.shoes.type] = 1 + if(!length(orderable)) + orderable = list( + /obj/item/clothing/head/utility/chefhat = 3, + /obj/item/clothing/shoes/sneakers/black = 3, + /obj/item/clothing/gloves/color/black = 1, + ) + wanted_clothing_type = pick_weight(orderable) @@ -110,3 +126,92 @@ food_image.add_overlay(i_scream) return food_image + +/datum/custom_order/reagent + /// This is the typepath of reagent we desire + var/datum/reagent/consumable/nutriment/soup/reagent_type + /// What typepath container we want it to be in + var/obj/item/container_needed + /// How many reagents is needed + var/reagents_needed = VENUE_BAR_MINIMUM_REAGENTS + +/datum/custom_order/reagent/New(reagent_type) + . = ..() + src.reagent_type = reagent_type + +/datum/custom_order/reagent/get_order_line(datum/venue/our_venue) + return "I'll take [reagents_needed]u of [initial(reagent_type.name)]" + +/datum/custom_order/reagent/get_order_appearance(datum/venue/our_venue) + var/image/food_image = image(icon = 'icons/effects/effects.dmi' , icon_state = "thought_bubble") + var/datum/glass_style/draw_as = GLOB.glass_style_singletons[container_needed][reagent_type] + var/image/drink_image = image( + icon = draw_as?.icon || initial(reagent_type.fallback_icon) || initial(container_needed.icon), + icon_state = draw_as?.icon_state || initial(reagent_type.fallback_icon_state) || initial(container_needed.icon_state), + ) + food_image.add_overlay(drink_image) + return food_image + +/datum/custom_order/reagent/handle_get_order(mob/living/simple_animal/robot_customer/customer_pawn, obj/item/order_item) + . = TRANSACTION_HANDLED + + for(var/datum/reagent/reagent as anything in order_item.reagents?.reagent_list) + if(reagent.type == reagent_type) + . |= SEND_SIGNAL(reagent, COMSIG_REAGENT_SOLD_TO_CUSTOMER, customer_pawn, order_item) + + playsound(customer_pawn, 'sound/items/drink.ogg', rand(10, 50), TRUE) + order_item.reagents.clear_reagents() + +/datum/custom_order/reagent/is_correct_order(obj/item/object_used) + if(..()) + return TRUE + if(!istype(object_used, container_needed) || isnull(object_used.reagents)) + return FALSE + + var/datum/reagents/holder = object_used.reagents + // The container must be majority reagent + if(holder.get_master_reagent_id() != reagent_type) + return FALSE + // We must fulfill the sample size threshold + if(reagents_needed > holder.total_volume) + return FALSE + // Also must be at least 1/3rd of that reagent, prevent cheese + if(holder.get_reagent_amount(reagent_type) < holder.total_volume * 0.33) + return FALSE + return TRUE + +/datum/custom_order/reagent/drink + container_needed = /obj/item/reagent_containers/cup/glass/drinkingglass + +/datum/custom_order/reagent/drink/handle_get_order(mob/living/simple_animal/robot_customer/customer_pawn, obj/item/order_item) + customer_pawn.visible_message( + span_danger("[customer_pawn] slurps up [order_item] in one go!"), + span_danger("You slurp up [order_item] in one go."), + ) + return ..() + +/datum/custom_order/reagent/soup + container_needed = /obj/item/reagent_containers/cup/bowl + + /// What serving we picked for the order + var/picked_serving + +/datum/custom_order/reagent/soup/New(reagent_type) + . = ..() + var/list/serving_sizes = list( + "small serving (15u)" = 15, + "medium serving (20u)" = 20, + "large serving (25u)" = 25, + ) + picked_serving = pick(serving_sizes) + reagents_needed = serving_sizes[picked_serving] + +/datum/custom_order/reagent/soup/get_order_line(datum/venue/our_venue) + return "I'll take a [picked_serving] of [initial(reagent_type.name)]" + +/datum/custom_order/reagent/soup/handle_get_order(mob/living/simple_animal/robot_customer/customer_pawn, obj/item/order_item) + customer_pawn.visible_message( + span_danger("[customer_pawn] pours [order_item] right down [customer_pawn.p_their()] hatch!"), + span_danger("You pour [order_item] down your hatch in one go."), + ) + return ..() diff --git a/code/modules/food_and_drinks/restaurant/customers/_customer.dm b/code/modules/food_and_drinks/restaurant/customers/_customer.dm index c7ff95cb1ad..eca347011fc 100644 --- a/code/modules/food_and_drinks/restaurant/customers/_customer.dm +++ b/code/modules/food_and_drinks/restaurant/customers/_customer.dm @@ -25,6 +25,8 @@ var/second_warning_line = "This is your last warning!" ///Line when harrased by someone for the last time var/self_defense_line = "Omae wa mo, shinderou." + ///Line sent when the customer is clicked on by someone with a 0 force item that's not the correct order + var/wrong_item_line = "No, I don't want that." ///Clothing sets to pick from when dressing the robot. var/list/clothing_sets = list("amerifat_clothes") @@ -85,10 +87,10 @@ /obj/item/food/danish_hotdog = 3, ), VENUE_BAR = list( + /datum/reagent/consumable/ethanol/beer = 25, /datum/reagent/consumable/ethanol/b52 = 6, /datum/reagent/consumable/ethanol/manhattan = 3, /datum/reagent/consumable/ethanol/atomicbomb = 1, - /datum/reagent/consumable/ethanol/beer = 25, ), ) @@ -157,10 +159,10 @@ VENUE_RESTAURANT = list( /obj/item/food/baguette = 20, /obj/item/food/garlicbread = 5, - /obj/item/food/soup/onion = 4, - /obj/item/food/pie/berryclafoutis = 2, /obj/item/food/omelette = 15, /datum/custom_order/icecream = 6, + /datum/reagent/consumable/nutriment/soup/french_onion = 4, + /obj/item/food/pie/berryclafoutis = 2, ), VENUE_BAR = list( /datum/reagent/consumable/ethanol/champagne = 10, @@ -199,16 +201,16 @@ speech_sound = 'sound/creatures/tourist/tourist_talk_japanese1.ogg' orderable_objects = list( VENUE_RESTAURANT = list( - /obj/item/food/tofu = 5, - /obj/item/food/breadslice/plain = 5, - /obj/item/food/soup/miso = 10, - /obj/item/food/soup/vegetable = 4, - /obj/item/food/sashimi = 4, - /obj/item/food/chawanmushi = 4, - /obj/item/food/muffin/berry = 2, - /obj/item/food/beef_stroganoff = 2, /datum/custom_order/icecream = 4, + /datum/reagent/consumable/nutriment/soup/miso = 10, + /datum/reagent/consumable/nutriment/soup/vegetable_soup = 4, + /obj/item/food/beef_stroganoff = 2, + /obj/item/food/breadslice/plain = 5, + /obj/item/food/chawanmushi = 4, /obj/item/food/fish_poke = 5, + /obj/item/food/muffin/berry = 2, + /obj/item/food/sashimi = 4, + /obj/item/food/tofu = 5, ), VENUE_BAR = list( /datum/reagent/consumable/ethanol/sake = 8, @@ -243,14 +245,14 @@ speech_sound = 'sound/creatures/tourist/tourist_talk_japanese2.ogg' orderable_objects = list( VENUE_RESTAURANT = list( - /obj/item/food/tofu = 5, - /obj/item/food/soup/miso = 6, - /obj/item/food/soup/vegetable = 4, - /obj/item/food/sashimi = 4, - /obj/item/food/chawanmushi = 4, - /obj/item/food/meatbun = 4, + /datum/reagent/consumable/nutriment/soup/miso = 6, + /datum/reagent/consumable/nutriment/soup/vegetable_soup = 4, /obj/item/food/beef_stroganoff = 2, + /obj/item/food/chawanmushi = 4, /obj/item/food/meat_poke = 4, + /obj/item/food/meatbun = 4, + /obj/item/food/sashimi = 4, + /obj/item/food/tofu = 5, ), VENUE_BAR = list( /datum/reagent/consumable/ethanol/beer = 14, @@ -384,16 +386,16 @@ orderable_objects = list( VENUE_RESTAURANT = list( + /datum/custom_order/icecream = 8, + /datum/reagent/consumable/nutriment/soup/indian_curry = 3, + /datum/reagent/consumable/nutriment/soup/stew = 10, + /obj/item/food/beef_wellington_slice = 2, + /obj/item/food/benedict = 5, /obj/item/food/fishandchips = 10, - /obj/item/food/soup/stew = 10, - /obj/item/food/salad/ricepudding = 5, + /obj/item/food/full_english = 2, /obj/item/food/grilled_cheese_sandwich = 5, /obj/item/food/pie/meatpie = 5, - /obj/item/food/benedict = 5, - /obj/item/food/full_english = 2, - /obj/item/food/soup/indian_curry = 3, - /obj/item/food/beef_wellington_slice = 2, - /datum/custom_order/icecream = 8 + /obj/item/food/salad/ricepudding = 5, ), VENUE_BAR = list( /datum/reagent/consumable/ethanol/ale = 10, @@ -460,5 +462,3 @@ first_warning_line = "You'd fit in well where I'm from. But you better stop." second_warning_line = "Breaking-you-so-bad-you'll-reminisce-the-days-before-I-made-you-crooked.exe: booting..." self_defense_line = "I have been designed to do two things: Order food, and break every bone in your body." - - diff --git a/code/modules/food_and_drinks/restaurant/generic_venues.dm b/code/modules/food_and_drinks/restaurant/generic_venues.dm index ffa678d38b4..19f1ff61323 100644 --- a/code/modules/food_and_drinks/restaurant/generic_venues.dm +++ b/code/modules/food_and_drinks/restaurant/generic_venues.dm @@ -43,15 +43,20 @@ return "I'll take \a [initial(object_to_order.name)]" /datum/venue/restaurant/on_get_order(mob/living/simple_animal/robot_customer/customer_pawn, obj/item/order_item) - . = ..() - var/obj/item/food/ordered_food = order_item - customer_pawn.visible_message(span_danger("[customer_pawn] pushes [ordered_food] into their mouth-shaped hole!"), span_danger("You push [ordered_food] into your mouth-shaped hole.")) - playsound(get_turf(customer_pawn),'sound/items/eatfood.ogg', rand(10,50), TRUE) - customers_served += 1 - qdel(ordered_food) + var/transaction_result = ..() + if((transaction_result & TRANSACTION_HANDLED) || !(transaction_result & TRANSACTION_SUCCESS)) + return + + customer_pawn.visible_message( + span_danger("[customer_pawn] pushes [order_item] into their mouth-shaped hole!"), + span_danger("You push [order_item] into your mouth-shaped hole."), + ) + playsound(customer_pawn, 'sound/items/eatfood.ogg', rand(10,50), TRUE) + qdel(order_item) /obj/machinery/restaurant_portal/restaurant linked_venue = /datum/venue/restaurant + /obj/item/holosign_creator/robot_seat/restaurant name = "restaurant seating indicator placer" holosign_type = /obj/structure/holosign/robot_seat/restaurant @@ -61,8 +66,6 @@ linked_venue = /datum/venue/restaurant - - /////BAR///// /datum/venue/bar name = "bar" @@ -82,61 +85,6 @@ /datum/customer_data/malfunction = 1, ) -/datum/venue/bar/get_food_appearance(order) - var/datum/reagent/reagent_to_order = order - // Default the icon to the fallback icon - var/glass_visual_icon = initial(reagent_to_order.fallback_icon) - var/glass_visual_icon_state = initial(reagent_to_order.fallback_icon_state) - - // Look for a glass style based on this reagent type - for(var/potential_container in GLOB.glass_style_singletons) - var/datum/glass_style/draw_as = GLOB.glass_style_singletons[potential_container][reagent_to_order] - if(isnull(draw_as)) - continue - - // Override the crummy fallback icon if we find a glass style to use instead - glass_visual_icon = draw_as.icon - glass_visual_icon_state = draw_as.icon_state - break - - // If we have no icon or fallback, well... Scream. Someone should fix it - if(!glass_visual_icon || !glass_visual_icon_state) - stack_trace("[reagent_to_order] has no icon sprite for restaurant code, please set a fallback icon for this reagent.") - glass_visual_icon = 'icons/obj/drinks/drinks.dmi' - glass_visual_icon_state = "glass_empty" - - var/image/food_image = image(icon = 'icons/effects/effects.dmi', icon_state = "thought_bubble") - food_image.add_overlay(mutable_appearance(glass_visual_icon, glass_visual_icon_state)) - - return food_image - -/datum/venue/bar/order_food_line(order) - var/datum/reagent/reagent_to_order = order - return "I'll take a glass of [initial(reagent_to_order.name)]" - -/datum/venue/bar/on_get_order(mob/living/simple_animal/robot_customer/customer_pawn, obj/item/order_item) - var/datum/reagent/consumable/ordered_reagent_type = customer_pawn.ai_controller.blackboard[BB_CUSTOMER_CURRENT_ORDER] - - for(var/datum/reagent/reagent as anything in order_item.reagents.reagent_list) - if(reagent.type != ordered_reagent_type) - continue - SEND_SIGNAL(reagent, COMSIG_ITEM_SOLD_TO_CUSTOMER, customer_pawn, order_item) - - customer_pawn.visible_message(span_danger("[customer_pawn] slurps up [order_item] in one go!"), span_danger("You slurp up [order_item] in one go.")) - playsound(get_turf(customer_pawn), 'sound/items/drink.ogg', 50, TRUE) - customers_served += 1 - order_item.reagents.clear_reagents() - - -///The bar needs to have a minimum amount of the reagent -/datum/venue/bar/is_correct_order(object_used, wanted_item) - . = ..() - if(.) - return - if(istype(object_used, /obj/item/reagent_containers/cup/glass)) - var/obj/item/reagent_containers/cup/glass/potential_drink = object_used - return potential_drink.reagents.has_reagent(wanted_item, VENUE_BAR_MINIMUM_REAGENTS) - /obj/machinery/restaurant_portal/bar linked_venue = /datum/venue/bar diff --git a/code/modules/hydroponics/grown/onion.dm b/code/modules/hydroponics/grown/onion.dm index b363bb26fa2..217fe0a6d56 100644 --- a/code/modules/hydroponics/grown/onion.dm +++ b/code/modules/hydroponics/grown/onion.dm @@ -14,7 +14,7 @@ growthstages = 3 weed_chance = 3 growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi' - reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1, /datum/reagent/consumable/tearjuice = 0.5) + reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1, /datum/reagent/consumable/tearjuice = 0.25) mutatelist = list(/obj/item/seeds/onion/red) /obj/item/food/grown/onion diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm index cc596cbd9f5..6be121085d2 100644 --- a/code/modules/jobs/job_types/cook.dm +++ b/code/modules/jobs/job_types/cook.dm @@ -30,16 +30,18 @@ /obj/item/clothing/head/utility/chefhat, ) + // Adds up to 100, don't mess it up mail_goodies = list( - /obj/item/storage/box/ingredients/random = 80, - /obj/item/reagent_containers/cup/bottle/caramel = 20, - /obj/item/reagent_containers/condiment/flour = 20, - /obj/item/reagent_containers/condiment/rice = 20, - /obj/item/reagent_containers/condiment/ketchup = 20, - /obj/item/reagent_containers/condiment/enzyme = 15, - /obj/item/reagent_containers/condiment/soymilk = 15, + /obj/item/storage/box/ingredients/random = 40, + /obj/item/reagent_containers/cup/bottle/caramel = 8, + /obj/item/reagent_containers/condiment/flour = 8, + /obj/item/reagent_containers/condiment/rice = 8, + /obj/item/reagent_containers/condiment/ketchup = 8, + /obj/item/reagent_containers/condiment/enzyme = 8, + /obj/item/reagent_containers/condiment/soymilk = 8, + /obj/item/kitchen/spoon/soup_ladle = 6, /obj/item/knife/kitchen = 4, - /obj/item/knife/butcher = 2 + /obj/item/knife/butcher = 2, ) rpg_title = "Tavern Chef" diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm index 95d8237dbd6..9da9e3592bd 100644 --- a/code/modules/mining/lavaland/ash_flora.dm +++ b/code/modules/mining/lavaland/ash_flora.dm @@ -382,16 +382,10 @@ desc = "A bowl made out of mushrooms. Not food, though it might have contained some at some point." icon = 'icons/obj/lavaland/ash_flora.dmi' icon_state = "mushroom_bowl" - -/obj/item/reagent_containers/cup/bowl/mushroom_bowl/update_overlays() - . = ..() - if(!reagents?.total_volume) - return - var/mutable_appearance/filling = mutable_appearance('icons/obj/lavaland/ash_flora.dmi', "fullbowl") - filling.color = mix_color_from_reagents(reagents.reagent_list) - . += filling + fill_icon_state = "fullbowl" + fill_icon = 'icons/obj/lavaland/ash_flora.dmi' /obj/item/reagent_containers/cup/bowl/mushroom_bowl/update_icon_state() - if(!reagents || !reagents.total_volume) + if(!reagents.total_volume) icon_state = "mushroom_bowl" return ..() diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 94cded825ed..b8dfe753925 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -66,10 +66,16 @@ for(var/reaction in D.required_reagents) reaction_ids += reaction var/datum/reagent/reagent = find_reagent_object_from_type(reaction) + if(!istype(reagent)) + stack_trace("Invalid reagent found in [D] required_reagents: [reaction]") + continue reagents += list(list("name" = reagent.name, "id" = reagent.type)) for(var/product in D.results) var/datum/reagent/reagent = find_reagent_object_from_type(product) + if(!istype(reagent)) + stack_trace("Invalid reagent found in [D] results: [product]") + continue product_names += reagent.name product_ids += product @@ -951,21 +957,13 @@ break total_matching_catalysts++ if(cached_my_atom) - if(!reaction.required_container) - matching_container = TRUE - else - if(cached_my_atom.type == reaction.required_container) - matching_container = TRUE - if (isliving(cached_my_atom) && !reaction.mob_react) //Makes it so certain chemical reactions don't occur in mobs + matching_container = reaction.required_container ? (cached_my_atom.type == reaction.required_container) : TRUE + + if(isliving(cached_my_atom) && !reaction.mob_react) //Makes it so certain chemical reactions don't occur in mobs matching_container = FALSE - if(!reaction.required_other) - matching_other = TRUE - else if(istype(cached_my_atom, /obj/item/slime_extract)) - var/obj/item/slime_extract/extract = cached_my_atom + matching_other = reaction.required_other ? reaction.pre_reaction_other_checks(src) : TRUE - if(extract.Uses > 0) // added a limit to slime cores -- Muskets requested this - matching_other = TRUE else if(!reaction.required_container) matching_container = TRUE diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index f03cd699d2b..f8dbd09ddb9 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -93,17 +93,18 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) /// See "Organ defines for carbon mobs" in /code/_DEFINES/mobs.dm var/affected_organtype = ORGAN_ORGANIC + ///The default reagent container for the reagent, used for icon generation + var/obj/item/reagent_containers/default_container = /obj/item/reagent_containers/cup/bottle + // Used for restaurants. ///The amount a robot will pay for a glass of this (20 units but can be higher if you pour more, be frugal!) var/glass_price - - ///The default reagent container for the reagent - var/obj/item/reagent_containers/default_container = /obj/item/reagent_containers/cup/bottle - /// Icon for fallback item displayed in a tourist's thought bubble for if this reagent had no associated glass_style datum. var/fallback_icon /// Icon state for fallback item displayed in a tourist's thought bubble for if this reagent had no associated glass_style datum. var/fallback_icon_state + /// When ordered in a restaurant, what custom order do we create? + var/restaurant_order = /datum/custom_order/reagent/drink /datum/reagent/New() SHOULD_CALL_PARENT(TRUE) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index a3b548661d3..59336ce4d85 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -2086,13 +2086,14 @@ taste_description = "custard and alcohol" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED -/datum/glass_style/drinking_glass/eggnog +/datum/glass_style/has_foodtype/drinking_glass/eggnog required_drink_type = /datum/reagent/consumable/ethanol/eggnog name = "eggnog" desc = "For enjoying the most wonderful time of the year." icon_state = "glass_yellow" + drink_type = FRUIT -/datum/glass_style/juicebox/eggnog +/datum/glass_style/has_foodtype/juicebox/eggnog required_drink_type = /datum/reagent/consumable/ethanol/eggnog name = "carton of eggnog" desc = "Tasty grape juice in a fun little container. Non-alcoholic!" diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index c949be0b702..3a32a98e799 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -13,13 +13,14 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED default_container = /obj/item/reagent_containers/cup/glass/bottle/juice/orangejuice -/datum/glass_style/drinking_glass/orangejuice +/datum/glass_style/has_foodtype/drinking_glass/orangejuice required_drink_type = /datum/reagent/consumable/orangejuice name = "glass of orange juice" desc = "Vitamins! Yay!" icon_state = "glass_orange" + drink_type = FRUIT | BREAKFAST -/datum/glass_style/juicebox/orangejuice +/datum/glass_style/has_foodtype/juicebox/orangejuice required_drink_type = /datum/reagent/consumable/orangejuice name = "orange juice box" desc = "A great source of vitamins. Stay healthy!" @@ -119,7 +120,7 @@ taste_description = "apples" ph = 3.2 // ~ 2.7 -> 3.7 -/datum/glass_style/juicebox/applejuice +/datum/glass_style/has_foodtype/juicebox/applejuice required_drink_type = /datum/reagent/consumable/applejuice name = "apple juice box" desc = "Sweet apple juice. Don't be late for school!" @@ -263,12 +264,12 @@ taste_description = "grape soda" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED -/datum/glass_style/juicebox/grapejuice +/datum/glass_style/has_foodtype/juicebox/grapejuice required_drink_type = /datum/reagent/consumable/grapejuice name = "grape juice box" - desc = "For enjoying the most wonderful time of the year." - icon_state = "nog2" - drink_type = MEAT + desc = "Tasty grape juice in a fun little container. Non-alcoholic!" + icon_state = "grapebox" + drink_type = FRUIT /datum/reagent/consumable/plumjuice name = "Plum Juice" @@ -277,11 +278,12 @@ taste_description = "plums" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED -/datum/glass_style/drinking_glass/plumjuice +/datum/glass_style/has_foodtype/drinking_glass/plumjuice required_drink_type = /datum/reagent/consumable/plumjuice name = "glass of plum juice" desc = "Noice." icon_state = "plumjuiceglass" + drink_type = FRUIT /datum/reagent/consumable/milk name = "Milk" @@ -292,13 +294,14 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED default_container = /obj/item/reagent_containers/condiment/milk -/datum/glass_style/drinking_glass/milk +/datum/glass_style/has_foodtype/drinking_glass/milk required_drink_type = /datum/reagent/consumable/milk name = "glass of milk" desc = "White and nutritious goodness!" icon_state = "glass_white" + drink_type = DAIRY | BREAKFAST -/datum/glass_style/juicebox/milk +/datum/glass_style/has_foodtype/juicebox/milk required_drink_type = /datum/reagent/consumable/milk name = "carton of milk" desc = "An excellent source of calcium for growing space explorers." @@ -1196,7 +1199,7 @@ taste_description = "chocolate milk" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED -/datum/glass_style/juicebox/chocolate_milk +/datum/glass_style/has_foodtype/juicebox/chocolate_milk required_drink_type = /datum/reagent/consumable/milk/chocolate_milk name = "carton of chocolate milk" desc = "Milk for cool kids!" @@ -1211,11 +1214,12 @@ taste_description = "creamy chocolate" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED -/datum/glass_style/drinking_glass/hot_coco +/datum/glass_style/has_foodtype/drinking_glass/hot_coco required_drink_type = /datum/reagent/consumable/hot_coco name = "glass of hot coco" desc = "A favorite winter drink to warm you up." icon_state = "chocolateglass" + drink_type = SUGAR | DAIRY /datum/reagent/consumable/hot_coco/on_mob_life(mob/living/carbon/affected_mob, delta_time, times_fired) affected_mob.adjust_bodytemperature(5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * delta_time, 0, affected_mob.get_body_temp_normal()) @@ -1283,9 +1287,10 @@ taste_description = "parsnip" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED -/datum/glass_style/drinking_glass/parsnipjuice +/datum/glass_style/has_foodtype/drinking_glass/parsnipjuice required_drink_type = /datum/reagent/consumable/parsnipjuice name = "glass of parsnip juice" + drink_type = FRUIT /datum/reagent/consumable/pineapplejuice name = "Pineapple Juice" @@ -1295,12 +1300,13 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED default_container = /obj/item/reagent_containers/cup/glass/bottle/juice/pineapplejuice -/datum/glass_style/drinking_glass/pineapplejuice +/datum/glass_style/has_foodtype/drinking_glass/pineapplejuice required_drink_type = /datum/reagent/consumable/pineapplejuice name = "glass of pineapple juice" desc = "Tart, tropical, and hotly debated." + drink_type = FRUIT | PINEAPPLE -/datum/glass_style/juicebox/pineapplejuice +/datum/glass_style/has_foodtype/juicebox/pineapplejuice required_drink_type = /datum/reagent/consumable/pineapplejuice name = "pineapple juice box" desc = "Why would you even want this?" @@ -1314,9 +1320,10 @@ taste_description = "peaches" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED -/datum/glass_style/drinking_glass/peachjuice +/datum/glass_style/has_foodtype/drinking_glass/peachjuice required_drink_type = /datum/reagent/consumable/peachjuice name = "glass of peach juice" + drink_type = FRUIT /datum/reagent/consumable/cream_soda name = "Cream Soda" diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 691d38c87ef..3952366f6c0 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -15,7 +15,8 @@ inverse_chem = null /// How much nutrition this reagent supplies var/nutriment_factor = 1 * REAGENTS_METABOLISM - var/quality = 0 //affects mood, typically higher for mixed drinks with more complex recipes' + /// affects mood, typically higher for mixed drinks with more complex recipes' + var/quality = 0 /datum/reagent/consumable/on_mob_life(mob/living/carbon/M, delta_time, times_fired) current_cycle++ @@ -825,16 +826,6 @@ . = TRUE ..() -/datum/reagent/consumable/clownstears - name = "Clown's Tears" - description = "The sorrow and melancholy of a thousand bereaved clowns, forever denied their Honkmechs." - nutriment_factor = 5 * REAGENTS_METABOLISM - color = "#eef442" // rgb: 238, 244, 66 - taste_description = "mournful honking" - ph = 9.2 - chemical_flags = REAGENT_CAN_BE_SYNTHESIZED - - /datum/reagent/consumable/liquidelectricity name = "Liquid Electricity" description = "The blood of Ethereals, and the stuff that keeps them going. Great for them, horrid for anyone else." diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index ca2a0215dfa..1c7d8d2adab 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -13,11 +13,10 @@ ///Required chemicals that must be present in the container but are not USED. var/list/required_catalysts = new/list() - // Both of these variables are mostly going to be used with slime cores - but if you want to, you can use them for other things - /// the exact container path required for the reaction to happen - var/required_container + /// the exact container path required for the reaction to happen, typepath + var/atom/required_container /// an integer required for the reaction to happen - var/required_other = 0 + var/required_other = FALSE ///Determines if a chemical reaction can occur inside a mob var/mob_react = TRUE @@ -80,8 +79,15 @@ /datum/chemical_reaction/proc/update_info() return + ///REACTION PROCS +/** + * Checks if this reaction can occur. Only is ran if required_other is set to TRUE. + */ +/datum/chemical_reaction/proc/pre_reaction_other_checks(datum/reagents/holder) + return TRUE + /** * Shit that happens on reaction * Only procs at the START of a reaction diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 1f1687b3217..b35c7f9c9df 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -175,6 +175,10 @@ /datum/chemical_reaction/virus_food results = list(/datum/reagent/consumable/virus_food = 15) required_reagents = list(/datum/reagent/water = 5, /datum/reagent/consumable/milk = 5) + is_cold_recipe = TRUE + required_temp = 200 + optimal_temp = 150 + overheat_temp = 50 /datum/chemical_reaction/virus_food_mutagen results = list(/datum/reagent/toxin/mutagen/mutagenvirusfood = 1) diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm index 2934306b3c6..012655eec4d 100644 --- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm +++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm @@ -1,8 +1,16 @@ /datum/chemical_reaction/slime - var/deletes_extract = TRUE reaction_flags = REACTION_INSTANT reaction_tags = REACTION_TAG_EASY | REACTION_TAG_SLIME + required_other = TRUE + var/deletes_extract = TRUE + +/datum/chemical_reaction/slime/pre_reaction_other_checks(datum/reagents/holder) + var/obj/item/slime_extract/extract = holder.my_atom + if(!istype(extract)) + return FALSE + + return extract.Uses > 0 /datum/chemical_reaction/slime/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) use_slime_core(holder) @@ -21,7 +29,6 @@ /datum/chemical_reaction/slime/slimespawn required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/grey - required_other = TRUE /datum/chemical_reaction/slime/slimespawn/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) var/mob/living/simple_animal/slime/S = new(get_turf(holder.my_atom), "grey") @@ -31,13 +38,11 @@ /datum/chemical_reaction/slime/slimeinaprov results = list(/datum/reagent/medicine/epinephrine = 3) required_reagents = list(/datum/reagent/water = 5) - required_other = TRUE required_container = /obj/item/slime_extract/grey /datum/chemical_reaction/slime/slimemonkey required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/grey - required_other = TRUE /datum/chemical_reaction/slime/slimemonkey/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) for(var/i in 1 to 3) @@ -48,26 +53,22 @@ /datum/chemical_reaction/slime/slimemutate results = list(/datum/reagent/mutationtoxin/jelly = 1) required_reagents = list(/datum/reagent/toxin/plasma = 1) - required_other = TRUE required_container = /obj/item/slime_extract/green /datum/chemical_reaction/slime/slimehuman results = list(/datum/reagent/mutationtoxin = 1) required_reagents = list(/datum/reagent/blood = 1) - required_other = TRUE required_container = /obj/item/slime_extract/green /datum/chemical_reaction/slime/slimelizard results = list(/datum/reagent/mutationtoxin/lizard = 1) required_reagents = list(/datum/reagent/uranium/radium = 1) - required_other = TRUE required_container = /obj/item/slime_extract/green //Metal /datum/chemical_reaction/slime/slimemetal required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/metal - required_other = TRUE /datum/chemical_reaction/slime/slimemetal/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) var/turf/location = get_turf(holder.my_atom) @@ -78,7 +79,6 @@ /datum/chemical_reaction/slime/slimeglass required_reagents = list(/datum/reagent/water = 1) required_container = /obj/item/slime_extract/metal - required_other = TRUE /datum/chemical_reaction/slime/slimeglass/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) var/turf/location = get_turf(holder.my_atom) @@ -90,7 +90,6 @@ /datum/chemical_reaction/slime/slimemobspawn required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/gold - required_other = TRUE deletes_extract = FALSE //we do delete, but we don't do so instantly reaction_tags = REACTION_TAG_EASY | REACTION_TAG_SLIME | REACTION_TAG_DANGEROUS @@ -133,7 +132,6 @@ /datum/chemical_reaction/slime/slimebork required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/silver - required_other = TRUE /datum/chemical_reaction/slime/slimebork/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) //BORK BORK BORK @@ -171,12 +169,10 @@ results = list(/datum/reagent/consumable/frostoil = 10) required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/blue - required_other = TRUE /datum/chemical_reaction/slime/slimestabilizer required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/blue - required_other = TRUE /datum/chemical_reaction/slime/slimestabilizer/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/slimepotion/slime/stabilizer(get_turf(holder.my_atom)) @@ -185,7 +181,6 @@ /datum/chemical_reaction/slime/slimefoam required_reagents = list(/datum/reagent/water = 5) required_container = /obj/item/slime_extract/blue - required_other = TRUE /datum/chemical_reaction/slime/slimefoam/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) holder.create_foam(/datum/effect_system/fluid_spread/foam, 80, span_danger("[src] spews out foam!"), log = TRUE) @@ -194,7 +189,6 @@ /datum/chemical_reaction/slime/slimefreeze required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/darkblue - required_other = TRUE deletes_extract = FALSE /datum/chemical_reaction/slime/slimefreeze/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) @@ -216,7 +210,6 @@ /datum/chemical_reaction/slime/slimefireproof required_reagents = list(/datum/reagent/water = 1) required_container = /obj/item/slime_extract/darkblue - required_other = TRUE /datum/chemical_reaction/slime/slimefireproof/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/slimepotion/fireproof(get_turf(holder.my_atom)) @@ -227,12 +220,10 @@ results = list(/datum/reagent/consumable/capsaicin = 10) required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/orange - required_other = TRUE /datum/chemical_reaction/slime/slimefire required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/orange - required_other = TRUE deletes_extract = FALSE /datum/chemical_reaction/slime/slimefire/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) @@ -255,13 +246,11 @@ results = list(/datum/reagent/phosphorus = 10, /datum/reagent/potassium = 10, /datum/reagent/consumable/sugar = 10) required_reagents = list(/datum/reagent/water = 5) required_container = /obj/item/slime_extract/orange - required_other = TRUE //Yellow /datum/chemical_reaction/slime/slimeoverload required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/yellow - required_other = TRUE reaction_tags = REACTION_TAG_EASY | REACTION_TAG_SLIME | REACTION_TAG_DANGEROUS /datum/chemical_reaction/slime/slimeoverload/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) @@ -271,7 +260,6 @@ /datum/chemical_reaction/slime/slimecell required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/yellow - required_other = TRUE /datum/chemical_reaction/slime/slimecell/on_reaction(datum/reagents/holder, created_volume) new /obj/item/stock_parts/cell/emproof/slime(get_turf(holder.my_atom)) @@ -280,7 +268,6 @@ /datum/chemical_reaction/slime/slimeglow required_reagents = list(/datum/reagent/water = 1) required_container = /obj/item/slime_extract/yellow - required_other = TRUE /datum/chemical_reaction/slime/slimeglow/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) var/turf/T = get_turf(holder.my_atom) @@ -292,7 +279,6 @@ /datum/chemical_reaction/slime/slimepsteroid required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/purple - required_other = TRUE /datum/chemical_reaction/slime/slimepsteroid/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/slimepotion/slime/steroid(get_turf(holder.my_atom)) @@ -302,13 +288,11 @@ results = list(/datum/reagent/medicine/regen_jelly = 5) required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/purple - required_other = TRUE //Dark Purple /datum/chemical_reaction/slime/slimeplasma required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/darkpurple - required_other = TRUE /datum/chemical_reaction/slime/slimeplasma/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/stack/sheet/mineral/plasma(get_turf(holder.my_atom), 3) @@ -318,7 +302,6 @@ /datum/chemical_reaction/slime/slimemutator required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/red - required_other = TRUE /datum/chemical_reaction/slime/slimemutator/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/slimepotion/slime/mutator(get_turf(holder.my_atom)) @@ -327,7 +310,6 @@ /datum/chemical_reaction/slime/slimebloodlust required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/red - required_other = TRUE reaction_tags = REACTION_TAG_EASY | REACTION_TAG_SLIME | REACTION_TAG_DANGEROUS /datum/chemical_reaction/slime/slimebloodlust/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) @@ -344,7 +326,6 @@ /datum/chemical_reaction/slime/slimespeed required_reagents = list(/datum/reagent/water = 1) required_container = /obj/item/slime_extract/red - required_other = TRUE /datum/chemical_reaction/slime/slimespeed/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/slimepotion/speed(get_turf(holder.my_atom)) @@ -354,7 +335,6 @@ /datum/chemical_reaction/slime/docility required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/pink - required_other = TRUE /datum/chemical_reaction/slime/docility/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/slimepotion/slime/docility(get_turf(holder.my_atom)) @@ -363,7 +343,6 @@ /datum/chemical_reaction/slime/gender required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/pink - required_other = TRUE /datum/chemical_reaction/slime/gender/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/slimepotion/genderchange(get_turf(holder.my_atom)) @@ -373,14 +352,12 @@ /datum/chemical_reaction/slime/slimemutate2 results = list(/datum/reagent/aslimetoxin = 1) required_reagents = list(/datum/reagent/toxin/plasma = 1) - required_other = TRUE required_container = /obj/item/slime_extract/black //Oil /datum/chemical_reaction/slime/slimeexplosion required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/oil - required_other = TRUE deletes_extract = FALSE reaction_tags = REACTION_TAG_EASY | REACTION_TAG_SLIME | REACTION_TAG_DANGEROUS @@ -410,13 +387,11 @@ results = list(/datum/reagent/consumable/cornoil = 10) required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/oil - required_other = TRUE //Light Pink /datum/chemical_reaction/slime/slimepotion2 required_container = /obj/item/slime_extract/lightpink required_reagents = list(/datum/reagent/toxin/plasma = 1) - required_other = TRUE /datum/chemical_reaction/slime/slimepotion2/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/slimepotion/slime/sentience(get_turf(holder.my_atom)) @@ -425,7 +400,6 @@ /datum/chemical_reaction/slime/renaming required_container = /obj/item/slime_extract/lightpink required_reagents = list(/datum/reagent/water = 1) - required_other = TRUE /datum/chemical_reaction/slime/renaming/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/slimepotion/slime/renaming(holder.my_atom.drop_location()) @@ -436,7 +410,6 @@ /datum/chemical_reaction/slime/adamantine required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/adamantine - required_other = TRUE /datum/chemical_reaction/slime/adamantine/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/stack/sheet/mineral/adamantine(get_turf(holder.my_atom)) @@ -446,7 +419,6 @@ /datum/chemical_reaction/slime/slimefloor2 required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/bluespace - required_other = TRUE /datum/chemical_reaction/slime/slimefloor2/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/stack/tile/bluespace(get_turf(holder.my_atom), 25) @@ -456,7 +428,6 @@ /datum/chemical_reaction/slime/slimecrystal required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/bluespace - required_other = TRUE /datum/chemical_reaction/slime/slimecrystal/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) var/obj/item/stack/ore/bluespace_crystal/BC = new (get_turf(holder.my_atom)) @@ -466,7 +437,6 @@ /datum/chemical_reaction/slime/slimeradio required_reagents = list(/datum/reagent/water = 1) required_container = /obj/item/slime_extract/bluespace - required_other = TRUE /datum/chemical_reaction/slime/slimeradio/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/slimepotion/slime/slimeradio(get_turf(holder.my_atom)) @@ -476,7 +446,6 @@ /datum/chemical_reaction/slime/slimepsteroid2 required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/cerulean - required_other = TRUE /datum/chemical_reaction/slime/slimepsteroid2/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/slimepotion/enhancer(get_turf(holder.my_atom)) @@ -485,7 +454,6 @@ /datum/chemical_reaction/slime/slime_territory required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/cerulean - required_other = TRUE /datum/chemical_reaction/slime/slime_territory/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/areaeditor/blueprints/slime(get_turf(holder.my_atom)) @@ -495,7 +463,6 @@ /datum/chemical_reaction/slime/slimestop required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/sepia - required_other = TRUE /datum/chemical_reaction/slime/slimestop/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) addtimer(CALLBACK(src, PROC_REF(slime_stop), holder), 5 SECONDS) @@ -514,7 +481,6 @@ /datum/chemical_reaction/slime/slimecamera required_reagents = list(/datum/reagent/water = 1) required_container = /obj/item/slime_extract/sepia - required_other = TRUE /datum/chemical_reaction/slime/slimecamera/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/camera(get_turf(holder.my_atom)) @@ -524,7 +490,6 @@ /datum/chemical_reaction/slime/slimefloor required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/sepia - required_other = TRUE /datum/chemical_reaction/slime/slimefloor/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) new /obj/item/stack/tile/sepia(get_turf(holder.my_atom), 25) @@ -534,7 +499,6 @@ /datum/chemical_reaction/slime/slimepaint required_reagents = list(/datum/reagent/toxin/plasma = 1) required_container = /obj/item/slime_extract/pyrite - required_other = TRUE /datum/chemical_reaction/slime/slimepaint/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) var/chosen = pick(subtypesof(/obj/item/paint)) @@ -544,7 +508,6 @@ /datum/chemical_reaction/slime/slimecrayon required_reagents = list(/datum/reagent/blood = 1) required_container = /obj/item/slime_extract/pyrite - required_other = TRUE /datum/chemical_reaction/slime/slimecrayon/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) var/chosen = pick(difflist(subtypesof(/obj/item/toy/crayon),typesof(/obj/item/toy/crayon/spraycan))) @@ -554,7 +517,6 @@ //Rainbow :o) /datum/chemical_reaction/slime/slime_rng required_reagents = list(/datum/reagent/toxin/plasma = 1) - required_other = TRUE required_container = /obj/item/slime_extract/rainbow /datum/chemical_reaction/slime/slime_rng/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) @@ -571,7 +533,6 @@ /datum/chemical_reaction/slime/slimebomb required_reagents = list(/datum/reagent/toxin/slimejelly = 1) - required_other = TRUE required_container = /obj/item/slime_extract/rainbow /datum/chemical_reaction/slime/slimebomb/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) @@ -593,7 +554,6 @@ /datum/chemical_reaction/slime/slime_transfer required_reagents = list(/datum/reagent/blood = 1) - required_other = TRUE required_container = /obj/item/slime_extract/rainbow /datum/chemical_reaction/slime/slime_transfer/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) @@ -602,7 +562,6 @@ /datum/chemical_reaction/slime/flight_potion required_reagents = list(/datum/reagent/water/holywater = 5, /datum/reagent/uranium = 5) - required_other = TRUE required_container = /obj/item/slime_extract/rainbow /datum/chemical_reaction/slime/flight_potion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 8d1ec8f8344..be88ae1c00b 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -22,9 +22,18 @@ var/disease_amount = 20 /// If the reagents inside of this container will splash out when the container tries to splash onto someone or something var/spillable = FALSE - /// The different thresholds at which the reagent fill overlay will change + /** + * The different thresholds at which the reagent fill overlay will change. See reagentfillings.dmi. + * + * Should be a list of integers which correspond to a reagent unit threshold. + * If null, no automatic fill overlays are generated. + * + * For example, list(0) will mean it will gain a the overlay with any reagents present. This overlay is "overlayname0". + * list(0, 10) whill have two overlay options, for 0-10 units ("overlayname0") and 10+ units ("overlayname10"). + */ var/list/fill_icon_thresholds = null /// The optional custom name for the reagent fill icon_state prefix + /// If not set, uses the current icon state. var/fill_icon_state = null /// The icon file to take fill icon appearances from var/fill_icon = 'icons/obj/reagentfillings.dmi' @@ -265,13 +274,13 @@ if(!reagents.total_volume) return - var/fill_name = fill_icon_state? fill_icon_state : icon_state + var/fill_name = fill_icon_state ? fill_icon_state : icon_state var/mutable_appearance/filling = mutable_appearance(fill_icon, "[fill_name][fill_icon_thresholds[1]]") var/percent = round((reagents.total_volume / volume) * 100) for(var/i in 1 to fill_icon_thresholds.len) var/threshold = fill_icon_thresholds[i] - var/threshold_end = (i == fill_icon_thresholds.len)? INFINITY : fill_icon_thresholds[i+1] + var/threshold_end = (i == fill_icon_thresholds.len) ? INFINITY : fill_icon_thresholds[i+1] if(threshold <= percent && percent < threshold_end) filling.icon_state = "[fill_name][fill_icon_thresholds[i]]" diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index 295921c5d24..93283d07d62 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -204,6 +204,16 @@ set_custom_materials(list(GET_MATERIAL_REF(/datum/material/glass) = 5))//sets it to glass so, later on, it gets picked up by the glass catch (hope it doesn't 'break' things lol) return ..() +/// Callback for [datum/component/takes_reagent_appearance] to inherent style footypes +/obj/item/reagent_containers/cup/proc/on_cup_change(datum/glass_style/has_foodtype/style) + if(!istype(style)) + return + drink_type = style.drink_type + +/// Callback for [datum/component/takes_reagent_appearance] to reset to no foodtypes +/obj/item/reagent_containers/cup/proc/on_cup_reset() + drink_type = NONE + /obj/item/reagent_containers/cup/beaker name = "beaker" desc = "A beaker. It can hold up to 60 units." //SKYRAT EDIT: Used to say can hold up to 50 units. diff --git a/code/modules/reagents/reagent_containers/cups/_glass_datum.dm b/code/modules/reagents/reagent_containers/cups/_glass_datum.dm index af3061ec067..41c6a9f00cf 100644 --- a/code/modules/reagents/reagent_containers/cups/_glass_datum.dm +++ b/code/modules/reagents/reagent_containers/cups/_glass_datum.dm @@ -51,7 +51,7 @@ GLOBAL_LIST_INIT(glass_style_singletons, create_glass_styles()) /datum/glass_style /// Required - What EXACT type of reagent is needed for this style to be used /// If not supplied, will be assumed to be an abstract type and will not be instantiated - var/required_drink_type + var/datum/reagent/required_drink_type /// Required - What EXACT type of atom is needed for this style to be used /// If not supplied, will be assumed to be an abstract type and will not be instantiated var/required_container_type @@ -64,6 +64,25 @@ GLOBAL_LIST_INIT(glass_style_singletons, create_glass_styles()) /// Suggested - What icon state is used for this glass style var/icon_state +/// Helper to apply the entire style to something. +/datum/glass_style/proc/set_all(obj/item/thing) + set_name(thing) + set_desc(thing) + set_appearance(thing) + +/// Sets the passed item to our name. +/datum/glass_style/proc/set_name(obj/item/thing) + thing.name = name + +/// Sets the passed item to our description. +/datum/glass_style/proc/set_desc(obj/item/thing) + thing.desc = desc + +/// Sets the passed item to our icon and icon state. +/datum/glass_style/proc/set_appearance(obj/item/thing) + thing.icon = icon + thing.icon_state = icon_state + /datum/glass_style/drinking_glass required_container_type = /obj/item/reagent_containers/cup/glass/drinkingglass icon = 'icons/obj/drinks/drinks.dmi' @@ -72,8 +91,26 @@ GLOBAL_LIST_INIT(glass_style_singletons, create_glass_styles()) required_container_type = /obj/item/reagent_containers/cup/glass/drinkingglass/shotglass icon = 'icons/obj/drinks/shot_glasses.dmi' -/datum/glass_style/juicebox - required_container_type = /obj/item/reagent_containers/cup/glass/bottle/juice/smallcarton - icon = 'icons/obj/drinks/boxes.dmi' +/datum/glass_style/has_foodtype /// This style changes the "drink type" of the container it's placed it as well, it's like food types var/drink_type = NONE + +/datum/glass_style/has_foodtype/drinking_glass + required_container_type = /obj/item/reagent_containers/cup/glass/drinkingglass + icon = 'icons/obj/drinks/drinks.dmi' + +/datum/glass_style/has_foodtype/juicebox + required_container_type = /obj/item/reagent_containers/cup/glass/bottle/juice/smallcarton + icon = 'icons/obj/drinks/boxes.dmi' + +/datum/glass_style/has_foodtype/soup + required_container_type = /obj/item/reagent_containers/cup/bowl + icon = 'icons/obj/food/soupsalad.dmi' + +/datum/glass_style/has_foodtype/soup/New() + . = ..() + // By default: If name or description is unset, it will inherent from the soup reagent set + if(!name) + name = initial(required_drink_type.name) + if(!desc) + desc = initial(required_drink_type.description) diff --git a/code/modules/reagents/reagent_containers/cups/bottle.dm b/code/modules/reagents/reagent_containers/cups/bottle.dm index 2dbc5287a76..50907cc8b8f 100644 --- a/code/modules/reagents/reagent_containers/cups/bottle.dm +++ b/code/modules/reagents/reagent_containers/cups/bottle.dm @@ -434,7 +434,7 @@ /obj/item/reagent_containers/cup/bottle/clownstears name = "bottle of distilled clown misery" desc = "A small bottle. Contains a mythical liquid used by sublime bartenders; made from the unhappiness of clowns." - list_reagents = list(/datum/reagent/consumable/clownstears = 30) + list_reagents = list(/datum/reagent/consumable/nutriment/soup/clown_tears = 30) /obj/item/reagent_containers/cup/bottle/saltpetre name = "saltpetre bottle" diff --git a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm index c17332fb046..65f255e61dc 100644 --- a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm +++ b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm @@ -26,8 +26,8 @@ . = ..() AddComponent( \ /datum/component/takes_reagent_appearance, \ - CALLBACK(src, PROC_REF(on_glass_change)), \ - CALLBACK(src, PROC_REF(on_glass_reset)), \ + CALLBACK(src, PROC_REF(on_cup_change)), \ + CALLBACK(src, PROC_REF(on_cup_reset)), \ base_container_type = base_container_type, \ ) @@ -36,12 +36,14 @@ if(!length(reagents.reagent_list)) renamedByPlayer = FALSE //so new drinks can rename the glass -/// Having our icon state change removes fill thresholds -/obj/item/reagent_containers/cup/glass/drinkingglass/proc/on_glass_change(datum/glass_style/style) +// Having our icon state change removes fill thresholds +/obj/item/reagent_containers/cup/glass/drinkingglass/on_cup_change(datum/glass_style/style) + . = ..() fill_icon_thresholds = null -/// And having our icon reset restores our fill thresholds -/obj/item/reagent_containers/cup/glass/drinkingglass/proc/on_glass_reset() +// And having our icon reset restores our fill thresholds +/obj/item/reagent_containers/cup/glass/drinkingglass/on_cup_reset() + . = ..() fill_icon_thresholds ||= list(0) //Shot glasses!// diff --git a/code/modules/reagents/reagent_containers/cups/drinks.dm b/code/modules/reagents/reagent_containers/cups/drinks.dm index db94be24894..41549a8f689 100644 --- a/code/modules/reagents/reagent_containers/cups/drinks.dm +++ b/code/modules/reagents/reagent_containers/cups/drinks.dm @@ -380,16 +380,12 @@ /obj/item/reagent_containers/cup/glass/bottle/juice/smallcarton/Initialize(mapload, vol) . = ..() - AddComponent(/datum/component/takes_reagent_appearance, CALLBACK(src, PROC_REF(on_box_change)), CALLBACK(src, PROC_REF(on_box_reset))) - -/// Having our icon state change changes our food type -/obj/item/reagent_containers/cup/glass/bottle/juice/smallcarton/proc/on_box_change(datum/glass_style/juicebox/style) - if(!istype(style)) - return - drink_type = style.drink_type - -/obj/item/reagent_containers/cup/glass/bottle/juice/smallcarton/proc/on_box_reset() - drink_type = NONE + AddComponent( \ + /datum/component/takes_reagent_appearance, \ + on_icon_changed = CALLBACK(src, PROC_REF(on_cup_change)), \ + on_icon_reset = CALLBACK(src, PROC_REF(on_cup_reset)), \ + base_container_type = /obj/item/reagent_containers/cup/glass/bottle/juice/smallcarton, \ + ) /obj/item/reagent_containers/cup/glass/bottle/juice/smallcarton/smash(atom/target, mob/thrower, ranged = FALSE) if(bartender_check(target) && ranged) diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index 2668804b205..eb731bc9f32 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -714,6 +714,26 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SERVICE +/datum/design/board/stove + name = "Stove Board" + desc = "The circuit board for a Stove." + id = "stove" + build_path = /obj/item/circuitboard/machine/stove + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_KITCHEN + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE + +/datum/design/board/range + name = "Range Board" + desc = "The circuit board for a Range, which is both an Oven and a Stove." + id = "range" + build_path = /obj/item/circuitboard/machine/range + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_KITCHEN + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE + /datum/design/board/donksofttoyvendor name = "Donksoft Toy Vendor Board" desc = "The circuit board for a Donksoft Toy Vendor." diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index da032f640b6..44b61d50a72 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -495,8 +495,10 @@ "monkey_recycler", "oven", "processor", + "range", // should be in a further node, probably "reagentgrinder", "smartfridge", + "stove", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000) discount_experiments = list(/datum/experiment/scanning/random/cytology = 3000) //Big discount to reinforce doing it. diff --git a/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm b/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm index 8fd2b67d3e4..7015344276f 100644 --- a/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm +++ b/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm @@ -504,7 +504,7 @@ /datum/reagent/plantnutriment/robustharvestnutriment = 1) suppressive_reagents = list( - /datum/reagent/consumable/clownstears = -8, + /datum/reagent/consumable/nutriment/soup/clown_tears = -8, /datum/reagent/toxin/plantbgone = -4, /datum/reagent/consumable/ethanol/silencer = -3, /datum/reagent/consumable/nothing = -2, @@ -529,7 +529,7 @@ /datum/reagent/consumable/space_cola = 1) suppressive_reagents = list( - /datum/reagent/consumable/clownstears = -8, + /datum/reagent/consumable/nutriment/soup/clown_tears = -8, /datum/reagent/consumable/mintextract = -6, /datum/reagent/consumable/ethanol/silencer = -3, /datum/reagent/consumable/ethanol/fernet = -3, @@ -553,7 +553,7 @@ /datum/reagent/nitrous_oxide = 2) suppressive_reagents = list( - /datum/reagent/consumable/clownstears = -8, + /datum/reagent/consumable/nutriment/soup/clown_tears = -8, /datum/reagent/consumable/ethanol/beepsky_smash = -3, /datum/reagent/consumable/ethanol/silencer = -3, /datum/reagent/toxin/mutetoxin = -3, diff --git a/code/modules/unit_tests/focus_only_tests.dm b/code/modules/unit_tests/focus_only_tests.dm index 6bb367eab38..18b2cfbdcd5 100644 --- a/code/modules/unit_tests/focus_only_tests.dm +++ b/code/modules/unit_tests/focus_only_tests.dm @@ -32,3 +32,6 @@ /// Checks that no light shares a tile/pixel offsets with another /datum/unit_test/focus_only/stacked_lights + +/// Checks for bad icon / icon state setups in cooking crafting menu +/datum/unit_test/focus_only/bad_cooking_crafting_icons diff --git a/code/modules/unit_tests/reagent_recipe_collisions.dm b/code/modules/unit_tests/reagent_recipe_collisions.dm index 263bef45e1a..6623c73a31d 100644 --- a/code/modules/unit_tests/reagent_recipe_collisions.dm +++ b/code/modules/unit_tests/reagent_recipe_collisions.dm @@ -1,15 +1,16 @@ - - /datum/unit_test/reagent_recipe_collisions /datum/unit_test/reagent_recipe_collisions/Run() build_chemical_reactions_lists() - var/list/reactions = list() - for(var/V in GLOB.chemical_reactions_list_reactant_index) - reactions += GLOB.chemical_reactions_list_reactant_index[V] - for(var/i in 1 to (reactions.len-1)) - for(var/i2 in (i+1) to reactions.len) - var/datum/chemical_reaction/r1 = reactions[i] - var/datum/chemical_reaction/r2 = reactions[i2] - if(chem_recipes_do_conflict(r1, r2)) - TEST_FAIL("Chemical recipe conflict between [r1.type] and [r2.type]") + + // Exclude soup from this test, they all have the same "reagents" just about + var/list/reactions_sans_soup = GLOB.chemical_reactions_list - subtypesof(/datum/chemical_reaction/food/soup) + + for(var/reaction_type_a as anything in reactions_sans_soup) + for(var/reaction_type_b as anything in reactions_sans_soup) + if(reaction_type_a == reaction_type_b) + continue + var/datum/chemical_reaction/reaction_a = reactions_sans_soup[reaction_type_a] + var/datum/chemical_reaction/reaction_b = reactions_sans_soup[reaction_type_b] + if(chem_recipes_do_conflict(reaction_a, reaction_b)) + TEST_FAIL("Chemical recipe conflict between [reaction_type_a] and [reaction_type_b]") diff --git a/code/modules/vending/drinnerware.dm b/code/modules/vending/drinnerware.dm index 073f2aabf4f..e7492f43d94 100644 --- a/code/modules/vending/drinnerware.dm +++ b/code/modules/vending/drinnerware.dm @@ -6,9 +6,11 @@ panel_type = "panel4" products = list( /obj/item/storage/bag/tray = 8, - /obj/item/reagent_containers/cup/bowl = 20, + /obj/item/reagent_containers/cup/bowl = 30, + /obj/item/reagent_containers/cup/soup_pot = 3, /obj/item/kitchen/fork = 6, - /obj/item/kitchen/spoon = 6, + /obj/item/kitchen/spoon = 10, + /obj/item/kitchen/spoon/soup_ladle = 3, /obj/item/reagent_containers/cup/glass/drinkingglass = 8, /obj/item/reagent_containers/condiment/pack/ketchup = 5, /obj/item/reagent_containers/condiment/pack/hotsauce = 5, diff --git a/icons/obj/food/soupsalad.dmi b/icons/obj/food/soupsalad.dmi index 52a2c99fb3abac15547528f25a1a2ab202a00329..60fd78017786cc428d376507a678ce59be4247e0 100644 GIT binary patch delta 548 zcmV+<0^9x8`~lhg0gxmCHIXGSe`UtB=u*-c?&-S-+5~A+5rzR9c%r_)_~}dc?f(12 zle>F-=+3B_B)OBj{dDXO8-+5tlly$r9VVnWm6w-XprAXs3ojh}L`)amA&_Qwa@XBq zR9Nuk`42fsv4NgtOEz>tC<8EOscREXSPG*F-6&5c@Qe`)4Cb;aj*z0Ce`@>FB+a<$4Lc6V~uSASh^O@>4Tf1Z(f|97dcua&+WUrQXjgW^UhygOZ3miE-h8)8|dSOcTv zaTT2h*|-g3FvrGI(Q1zPb4`)a)&-+hDmD~jw0#(PG=pmm!Pb1l7?eC3%4R7=nw&sc z5ZW@w$~?%%M^i#fkg&n-9nF6%NhHZOsVV=cZ4Z&r7yVz&+c(L*e|;aE`Oq{krmJRh-)<$c!W9$pkJ4?HS-JGp0Vz zl-k?Rz}VYti;6fKSr3>&jc{I-QZ&LZGud3368NbfwNf#zfmCRPY~I69;OXn@i=;2zxBKr8 zPwwvVp*v$PB*~rJ?WbdR*eGapC-?cLJ4B=@>dT*^py*ES!V3o{)ddBHqf(d$%ZZnIskK#x;Ej2s*EOdqY_Qv87EX2%(7`3Ax%EkfA-NN&A69< zOjFb*uCjoN$wgsWY<>qsHGxYlF^eoF*t2Y@C_*l6uZmlH_q{0Q-R6{vEhSinEQR1) zd4f#E=UO6$c9~-y3NW-uz(U!Eo`EUY(BGxokHk!AYG1N!Y=+AUerFmm>mKSjez4%! z9Rf1!?&Pko{(9bq42cw;f023rx762Hr7y=>8VKRAK zCC`Iw+=elj+s2dTYHso8nkGhD6^yx(+EAP(+rh}A8C+`!w&EkkkjbM#wuq`UIRRY| z+BV0^Y&wq_5;mm0qxpj+i6q$uHI*N=9U(G$&HvN9ebczN@4I!Ve`yk5bN--L-=Hgk z$@o;4p?#$oFxiTkQXojZ&15@*Pd8U@ey=Nk){JvI1etN95>4QO&>jK4GGpq?OsT#7 z42-=kwkaddM%Dus$VRxVnbKs0Uq-T7nG*QekGYZ>*FaKQp_upZk^GFQPa=V_x6O3P jsrON~fcYc%(%nDZ4!OI>hwc}*n`4m2CQu5qVgmPj5_cAk diff --git a/icons/obj/kitchen.dmi b/icons/obj/kitchen.dmi index b92034675b7d36bee1d3e2800a01c7925d8c4d19..8c5781ec985c0dcfa0c52eb636e3b0297ccaa3dc 100644 GIT binary patch literal 28462 zcmZ^K1yEICyY8Y9r6dI@L8MEN?vj%3?(XgeX{1BC8>AZvk?ux1q&FQK*mwD#Gw00Q zxp&Qc?8V+|)>m&m@B4fa3ST7A(TLCh06>@eET#kia0dSxDl+&@s9}LD0Kmt3sc5)} znK~OgSvt5_+S>tu$M@vaF}ng5tbmD4+Wec0s*D`co5_*#x$^K6dX3<^y5PERwqJk9 zcT*RlFMZ0W!+QPI{@3>Tqht5u^#k<8_x@tPiZBFod1?33=@z2FfYBC7*J;B!Ao4=D zf~zwGRk3ieeeytJ6)#E}8o#zMAmU{)aOESH{Hyg4RpMnPWLOJWEF+SLMY=@A znUpuPI-20*8{{DcZSyJ}WU>=MLISTkywEz)&NM%IBqG>5Z|Gt?hU6?wNxTnw_NF)8 zr-j8k-8lJI?1YbKCKQ$X7i8J&9i2{lwMQXyqK+ti9DrKTzavb!tWTr!Cdi7q3-FRg zqgIB;8JZ0W`0%#p)F2gQ}~eddf#GAH~#qdaE%jtpBL0D<&C< z#=jFs>Q{Je^%z!CKGV?rHU*YaQCT|NSKk zD|ju5v58WyYt)DB?CocELPA=&Iy%f^Mpy64U~6QU2XAxy&e(&u`!Aa3Zayw`qf&@b zC)OE{nxuU9$}~8dulljGV^ZH{R7tKo4!LvOaEBx3=1zw)zhy4&W^B$G@>A8-mKxtT zHC~Ehe%-{GCKea4Kan$$rJvZliu;%RHx z9WPu!Mut|q<_BtQ01=o{R75_z>OJqhA3N74BJp*8vn`Y`IQH frBJjV(q~c-9Rg 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

DgJO&5Z{&1+YxO&%AC&TM>HVt=ppB8%QU#ARe2 znPz7T6m}dFr7E8?KFlE*vPNdKwzX-o3yuv%(t6wc96bb@imo~pX7Jz^npK8DK=#!k zdpcpgwZ=>ViiD6&3+^?U$ zXIF&s`vq7f3ZLFT2{pqA@C?vo53Y=C1QVYkQnV~OsrO5)2(3e7yiEW?kE>T?%=$M%=H4b~-%C;?^ z9-hDdijE#GEHewR?j`O1xDMi7e7+gw*SRcd+Gx=;F++X?ac z`MI>LjFmVD1(TEtaDbjPkNo9Xb)Mjt7;E>wwTpU6Pdk49aNSYZUbeD_T{0FKq=|TJ z0O{P%_MV(8(j9B<>?8p%PI+XxrJ+CV?vy+{M3$D8i=E!hOB?8@r~pu@TOa1(;gw(1 z`exnlQm*FG-OW{VX9Ce?rD-gmfd6uDERogUac37vQ+dYHX%jv^1MLmB>*f3JCHq`J zF=y}y0QSexbk83u5@dz*%!tS^z_Z(%#_GWN=l-XmzPh@&YC!I zr@lm!y)l~(n*d=Pqh44m*5TRn!_`9fTA26Q^?PT11h+@Iycb@h*1_N576Wnd@sW*Z zFhSEw&1sU4*#Q?ASXy0fgwlfysrup2ZNJ(w#ejP4?(f?MJzd$TxMyn&4@ddpmb0h# zn-#c4c!RJ3x^m4VyW9;qLXJplh0LM03{Ly((dj{Z8PYyzdv~4Jc8vG=#facmjr%(C z1}Xwe;yoHFYR`&&cZ_DeSzVT)F&OH7lhgM_0^%`=Os*D!%IN6ma;H}-XQroR?E;Fs zp+_^{C?!pr|F{w7DYD2(fm_#KxyxIpoE0(joRpqUOTSPU55gMiqQpB0ZA~dl#d-Sk z={j*pvh@4m;o)2ry0I{3u-_#*dU{b&(cqtCiKf^NIy!Gh1F^^i93368{MN$nqYw=J z7If-x5fg{nJkIl}^aTwL%gU5Xwji5*klR~HU0ssH!^7x|n*WOW8}FiCKmF0SVg){? z7ske7^bZaabJ$8bvaT4uvpC-x@PIwt*14T%6%^}tdU2#M>C!DX&*C%dMT22_VR11L zhp(C%etv%bLv*(QsJh^5G}WuCt97^yj0>=-9UHu^tui0XO--+@{qf;GvR)hS?(GqA z=z{vaqWP*vc0Q^0xTX&86T?&h9KvGknR!09s$m_AZyz+H`wx7YMHd!%y%~a_*vzMr z(WV%*WYwS$-%8cbM-14S zlH^`gRZ%h6PSxLH54iQ{D}pTS7T9;b6|N-IBKxLP)}K04B3h^tp`i)jUxKhpU#`!zve>U38Ta*2VC!a(QlUQrGt&7DNr}z=`>1m6!Mo z#4>5vK0qHhOYIsXtJkER3YTdMW3~T-{ z-_!1rl9GX=*LZkEb9m3GT1_|R*er>A+1+h>3`W7E2# z%rY8T{L!U!e~WU545lMU4)E~tjgA-V@KvYlT&<06mNVXfeMQfM$|DA&>PSsZm3xBz zc>VhIXC0mI;t)K6d`?cz#MM=ug1Eq9Y-h#gDUN1gH|>Xd)HEp>dbP^zdAA8`eQi&d#7;%@&Kkg3BF;%Y@h8 zFbn<*F8X4}cU{E!J}kZ@AUqHb%7dlh=^edt(4 z_k!Jx_2yuE{j9p%58a?hNh$=TJufd$lKwMVC_EUy@_#{-6ntUR`9uVh4fM|-{r8us z9TnPte%8E@ljOAM)B`@Hm5lzk_Br9XcJAh~gAET&Ji~#|`|*@>uv=fx-w4Vpi#U2l zuoe@#B?uqksBnC6J~6){uZ-1sS8_e~G!g3$>w50LaZf|#;^ob3|BHizGt-|j|9y~o znWdq6kombmx+vkR>+3};sON~7;nN#jb=-}6$!9x{$2trKH$6(|VRozF7>wymn1Q#^C&z*O?CTKzaLFrB?I7ddc*V{Q&%`koa z?vUpW7!-Q0uKO5E;{WZDWUKzFtE-F6>q8EkY2=jq73jYkj*pM^$kM$Mb(r@39!bVw zZ!+emn)SEiwj$vxpJx17Y_1GCXE2EQ3Hu~4B^<@!zyVDW+z9eMA8w!Fu#$>?c*L%9 zeeYFbTSYHyt^2~~-LLv>`w$IdJ`BiRiA?CVxeF8TuzBSUbFcLH!a=CR(0!XgGYsh< zRWAplU%H!cdgFrG)lOUYcR>P~|LxDdE0INCNUeb9W07<>*V_Pp(BY5LDi;?%-K^NB z&)<9+R6ic9necxk$Zom4ZwMyyt+G#GrxosaC@`}jLSYrJ@}wqqVLos5J7t> zDAVrNA#{s4V8tSXv}HXAi^{`!{tAAsFvoQ-9uS0o7G9Kj=);Y;zWWgE6-AHs>Wi|D zVgNY(PV65=Y)O7BW_&W;8u-@_V$qyjG4lN$cVf{C#1z_eq6a9(zv{1K1Z9LL2Lqn9 z2z8E6n7Q>)R+n-39+WVZj$zM9es#^;HS`0MTI%_n*W?4|XEFx_Q2+x28O{40A75Wn zPy|fO&CRFT16bJb_Wb+x$h3FA> z-^hdI`0t$M=U_f@KZ)G>Ur+hx8%)r367YuhOoi;yP2-K`JRQR z;{5exyVH;i(DV!yU)5bQhLJM6+|O(l??t?o!gc7BFl_$Z%@p=dzs}U=AvA~!J0iiR zrs@_2={tvh&>OFvrj(qz0|Jcx2>T_fC!@n>mKQxD5VVo5sZFIIF3@sTar)EBko{Z8 z`MCC*yOuv>)67jk75~F+@>P@~eKBT7?+-in&DF_C0MN0;X03R4LHx+FGf`9a?iXC{ z0j9D2Ya>0E$CDEKP4B3tyMdzqRalrb9ArUC*1ruyP)EZa>zQ4o6PALPFB(^@AN}W6 ziNyZ_zpL3IN?%8Mw!8=Ve;%HbgjxQ37(MMyT`IPl7P_Y4PaxAnFAMj#JlkAKta2ph zEN>!bex#Ta-nvMlKc)J_|M^?@HmEO!H~{Xe3Be0@#isT6?z~bB2H119-&7-P_Z(Bi z^_(|&Dh*uAp;*CdPF#w}-F0x1OkkL>P2-65x5r92yt^&Bib~AOVy-m%fQwXB z{fjmPB}m_YSs~G`>4uY{JLwlp%JKZV>FHOmQ2CQR!`J>bm{BSRKK;9v@%)5$Gk>?6~yodH^4eF<%<$9`Hllap<#*Fn5Nq2wteDtn(VP5WE zQ$+qZwg4r_|HDk`C0;QD!?&uZ(5>K95%oL;lj%(#tSAc66=s{%o@MAd(etl8!>X*5 zS~YCG;Qj7gUHA%pe>KP%&4XVw>=3Yeb^tK_FY?@q*aJ3=M(ANs)AG5DuzdT#gJ>ou6wfolfZatorTsI5?Zb!1y0DpZx{?_p8;Fz}orP=Em+$y{|T~Tl;?xV#*`3TBUH8 z3$DPPykYg*6S0DzQ@~O7mlkGWy;kic_$C1u%z~gPl^OEJwk)iL;EDXEO-OdYEUT{C3B$wh62TzR8YXQ{e{e@!)gB+xYBaRjouESZ zDf!|XeI&?jg$@|Z=sIdN2<8xjI#7NPlS-Kh9@EHIOg09aXBDd_3Ng84M8 zvH}CzM_Ltm_Bn7}iYsd^7-(q~dvSU;`-tI6^?RlWTwe9c8vWi0A{&U0abKnn1|Ad@gM${*1G zTzmao0$HguM%f$BiV6uqd_^XpV{b*y$w}a%RYz_k2W!Qg*thd=|HF+A^%p4Q@VlQb zX^gvt<`D8{2c`|>sJcD&1^9Ag)A``U#ou!!r~kCDLiRzyhzv7d%(Ado>Y*f;`uMh=2#d+{ z-jt1;1?%+u{BLDNUr#B`wL?G}njwL)yq_~!cahT5Y#GlCmOwbBxwJ3fw;iaqz(q^x zr#!=KRMp41?nBvrRNekN=lSYGLqo&gEW3-HAqWJrvFB(4J6Un36cE5zX+Hbqd;5oS z`CJ88Uvzr9L{UWro_c2Uh{TbMCqqVve0$?1;AgCt@V56obGK~AYn&-feN5o34_wdf zX}erl?GP=hwxA!3CUH|wWP1MaO->+NQiLw=MEJ%pL>+rf+dYS5S|T*_ZjZ;)1ao_ZI$pRbvh zE++)#C1Qv|&yVzaBa;2k;5siZoWOmgpr@C);>BGT+^)uCv4lA%KwrWUk>Uq^qugS> zDDtQ>{1t2dgW*9HC$7hH1MAgQ3>?tFsS4J4bh-no=jn6=YBdsQ(ng?e?tMdj2nZsx zgN@q{u7HrX)C-=YBgKo05ednk)RH~(eveHm?C9^*5TA(y%BY3ZZT!Iiuhe2EGchq3 z9EzRC=g+7jA|mn0$?wYqV|=Pk{23^5NjtRQ@{3!*_LQ&?j07-*S?0=Iy?Nu82N}t4rs0biAdY;Fo`x zomF`!j%&jR16R=%17*Jw;x(BL8^jqw>lSSK4J}7P6d0SreD4QD;rxvYK zF$?(O*t8U~n@3y6Az>+>FnZTW?JUj?e^n}qMyO!Lrq>C(-2-3wOwc}SQ)<=h_YB!$ zEGHv5T*rnah6@r!x_wq7GFl|I|1Aw{VH1R(rr+u7mcTt_e9&x3LjoYKBGgEdI=#ubjxfR&byvcvWn+!6g$k zW1lVFTa@uc!FARBwP6r3IDR`sDT=nxrrZA2+lS9irxku-!@xyN-T1dCrj+ulv24=r zllOlN;|}nxPyM^Vyt&oPNuj4ctC)Va6s`C|5T;|?+eqt2l_qef9e2jsw zts?7oZS*&gy`oin0T>g{Vpk_>JU4ymzAFCx`!j=1OZ*XNdGR`leo**6T`%0Nj3a3E znK+w~kMygg=igZNIF-REawwX{HU%l6P#ktOr1s!?qLzK$n=U8?Iji>>F+7~Y&5 z=f*ZG)-@xi0;WN3D#7F=Jaxo718YG)<$x(IeGs2&RI6<1>g#8%xn!l#Co7bxSXfxp zqK1S$qKgk0-LE)5gx2Kezw3B@IMQgeN}k)4+2z>$#7-gz4|q6?zdCLv7dM#D>TFfO zC;pLBDBDTKW=_yBhxe1-ggx>icH2u1Pt88%=Kbp0cWX9qgV<=P5x)S3+IHlND>(ZV z+PPMxgL)DAy{y0rYR9it)Q}_b{elrz{E%M{w{AFW3+vc3WZ)n@z$Ku#j%r>b|9&bs znQuBN;Zi8g|5fq2rKt|bR<7}{O_k)XE8eniLOGUYi?ubOVujG zg~RfxwWWx?8zu=AYjLpL-0ySuW~S?>y+m&y(?>Ag1~Js%;9T10?sVXT@zcrfLEpEA zw%oU*UBTj-_<~4vXVC2XjdaX3{qM4dW^3xH%fz@2POjl`3qlQd(See_tX9M$RZSDb z+AEt|JBY0nulnf$#xXgIYSkZ!igdu`Wltx+U(`4M!Ybbv+VILWxH_&Dn{AVu4_e3{ zi$sE|p3qNVYarZtKnv#}Hc3#z?NC%S1QWF4Lb+t+6;_SE4&WWN4qZ&lo`#=Ldak4V zHoaa2wx21)UtB^+kI_}5T%Bu35p*_=Hp5QC%<46`jYc8g`gUg`*sDah z4ULqhZNB~b6QQolf{W3Wrwh7C5A+1z!h~O=HqYybs9W=cvbXi?x&pKxmUF(ke-?x0 zW0~%}UWw^mqBpp^eaz6p>6vfYIG}9D3h7-fuSS)91zB2NCyj;E2dQ+F!otG*!y6Ye z!cI6{zZ~N3yF<)*9F}MvyKI~zr%>NOx5o6b~2HCNA!=Gj~Y0)~T z)*`~@F~lCc3nb=-i>S1gd4HN@$aV=?#Hy@sH{*(T-H{hg->RY+|6I_{p}9we1C#y<5FkAJ4e4R2P!d zn*aVJrA1w4R80Z}Zjg;l+!}TZ`VU0Fhfh~=eKjzJ_|F~mc0kShB8|g}1}-2FLC2w> z6X!(t&)vPq8+tejj)3bx>EoCB1gO5gzInKOH_BL%=mN^Z3>+R+ov_e+eG0$F^TC*m zY(LV^m1ljLeS+*P-#su~7J|+mZUy&%hbQ%QE8&)ViHa|PGUTGbunul?c0w6TNgv{J z?=wl`$=n)J23NPBo+@~~vyNJcu4jGXpXYYGn1}SqxWrurRy>c-2MG^{)HE;T<+tGe z#NPDSz{I=`sI8tA1szE$f*E5Ts}#I}^$-?n6&#%?C%iXek;?G+_`k4J$^hqbMy%-y zGZuA$_lt(3sK%`9Xui4Zs~$HbBWDGy_4m@G zpS+<)HlQB5(i02Y!Df{_Q7(8n z`tkFZFP|z_2pU|E)HI!(erW#b+L(A}Q0#}WVc6%>xRIGqkNiQhYO@V+$S*@K5RgX# zhA21hFZZ3}VW;h9EVj!a`)paCqaDDxCKz)Twx6Z#YMn-z6rX)LrDcoJ`f>_UOy(@V@ume3~V`Cc)loHVa6&3WfO!y^+ z86YV%0{NTgWj{2Y3hAtD6{*F0{Jo7&Ie==g&k9z2M59uia+z23UdU0^d|4S2?{ML( z+Qh?W#cgQcCO#+QG&VMlXl~{tA}0Q(r5h~MSHS9ZWx;l1MN2ms$l|eO;(`U_wzm_< z#KeFVph2+G!hpQrWV`YkEUk&Jq=3C+JCi>~q!P5A%+ijwLG5(fT%<@2$g;wiQ!3)S zoL(lywZc_bw-o3`^c@L>RfpJEy0Dj-mV5+4)j#NFGPmOEQA~P8bg|-YM zyH4>Vsoxy75Rt<@MR#{m1T_)9x1pX^TlURK6|ipY=S;B@-no8$m64e#9%!$c?2)6j z4suh6u%7!zqW)2A#&=BK&bjQnxEM@yc&5$Np$|F}0G9#WD@_zn6LMV1?SM?d$04YC z&G24H@eka9m`10u6_Y<11Sa_i9z(?DUT;@1^+~N82d4+A`>}vhyEaY!*$jOXM$h|Q z(iOqu7|zN)*cw=Wgy=Wfqz^nN=8FvN*txIn9lQXzew;{pc(#hBLy#nxGf)ApID6p2 zFwV1tN_?|@W{%KX<{ezX@G?)8Bhk0$UN%jzCVfrm!fZ>`(%Nd+p9zx~${_fLO&Z%y zbfi#YBe}T2lyvVA%-&p3(MF>9!C!PRmqO^t^-c_$+p+rNtY9pYQ=Z!FK{%Sd|BJf1 z&+06qho|9qlkMWcVdRYD4Lm??F^vt4Jsv0*q(6U_Mi$gQ63nrsT&Pa|N(RU5x&104 z3QfYNkoS;?7aLEyTg*F51EDug?kfc;!U`7YUK~sE%b=hz2ZCk}avcz3m$ep@8FD^ax+D+JmTe#35Bcr0`YrtH zOA(HBqIKKHnkpYc;em|tY@~!M=I|iS-||m+vVO#9?7pm~7l^oc$r~zWVLx4o&iA^{ z*R>@#Heae}{83idU&GzS^=(U;57LJ$0{Tu2(zle?eVWiC;#2 zw;-D$w1iq@_a^~}^GnBnFTQo<@5X(zo!A(5ucsB&?u&WFV;{e6fOwBCVQQPDhAUe{ z(-l@&sEC|;4w_v=pt@QsR*-Z=7!(yafC5#F*yQgGs)#GX#;$6x(N>V5Y4Y!EJ~a~6 zmX<4x*s|gO4^{T@+OMrl>J!Lh()4xvG_C&0aQ;dZlJgOz;)%Z&wggq^Hb$ABZ!qX> zvi+;^Cv5w2PqX7`Z~ViY(_7(9!*ePgo^K(c;f6bDjxBCgh+)&1W^i0gbc81)e^B2Z zN0zr?%vSI?cIrJbmcvzlNlW07y+F4;qk^2Di;4Pv%*fErv$C4HHL0K6AaBy>z0KEl` zz+fENV8{!chA_D_7C7*q1)?Tjs9hGegQ+bEicy}dWky|YE}*W?s4h7zCkN)>ai!l( z&I*x(SPnTfcUOXwX*46ExR{#BmO=vYEdc?F3^_xHJy=kmo}L~>p8kqWX(FmFqNb`E zs0mUF_G}NhZl3%K-CYew0^si2>pudyX8T|8!5d2*8!F; zD}T^EUb%>@vbf*3FQulo~2AsS}zcz3Qv20u12A*rgGJfP@cYD`I; z#f7x*-x(*3E`;iIp6G;}M5z``POxc6LCF1%v_elS5QNE%U5}I6h&It7ss`6Y@sGU`^WfU1c6kfU z<(r-0XG)ev z-${5q^jIRF6RYq4ga<+^3rkC|kj?V=^fb3oSt$l)HLG>&kLh21JR^*NJtho3p#(rB z^m=Y4U_YPMbA%yR3Hy!HXzroq6Py{BbGHYi#$whk$;rt>K)hjJ7zMq|A94lh4J;js zsTM_yo&<(mxRkObb6vNAOoa%ZdB>32^GGnH3K}eL(I64FiLil~wt{%D3du(o!1S z3p)9BHE^}>O*oqj6+L?0`JJhz*Ng(2RT|2& zy-R*^8TQE^-M=yU=3%ngPuiD_ zTKN8@55$2SVE^-$TjMEtPjKzT*r8RA^fV33r?NST@iiGYOOa=OvdtjkYh9R(rYAhb zP#H0?I8+csnkxSt7#NtKV{?UU!0e=Z6!za7Xt&eV2*-N!KG%~^R5feUHKeeiYP+f(d z_k1!-lxiK)$-Q9W?HrJN8%y5YA6k%~kKeTxoU2p@IlPHVfGW4lpDc@m?#*#~7_S8x zrJ%lzNR-s;vy(sCLUi;iCy)X|$;(SzS64^F#3TXk=)m)~QLtlME<8Z<$IGE4 zPTT?!IYEa}D3fGj0uPkJNl+M1IqR$uIeo*iI4m`Oq5|i z>&;hY{ih4167F(RP&<5RBWn!nUyxPo^trEh`4WLEHQ~>Maxd6W1DfnMtP-zo|NQQuQ7Vk^@kPE*OS;5E?~(PDXFMT+TsWkz4kjsK zJ-YPXiFW6Kak+`knb2YYbqfvU=9(g)=}fTvv0fp>3z*{H`>6UWMa9E@T@nabY;qGy zyvb>`Nq61&=z&XZvl6zz%M16vd};Uh4mRHFaREc_)~LgmQz}j`NSTC;c@;c^b30{t zCN?Iq5;FME&E<0f2_dF{*>w85T6GR|hoAAvC0HMYVx4YjT$*(PE)AGf*c*%k1_9i- zj6$Y-<9xIKi=Xc1``yHq``;3%UhZu!=(gA9c9Jl=y29Dnm3DampcnY$FYsVTRNO{b zS`(D|@@FG{Zb4>l6*1xMntcL)dfRZvx6I5a*6m*+isiM0T_CfGerA>t}PV?{39kJFB3~Oycou{*f{B zXh~5~1dwO-3RrA+uTeaD|6c@kuUCR@#~Kq!QU9UsDBf%~x{`Y@c>eSsXXm>)cuzyN z5|$5#&@xQG!Rx+NcSqaObPB*V8CjXBtVj8E>xw$uBMQxOt{ic;#Vfm!#M!lzzwxo; z*3S_Z_|4;rS~fJp@Q-4qjCrn%6-u{Hx?QlNi%hw@Lv!*8TOLmh0f6^G&MWHdt90EG zZQV+B_#Z*>?O0A`02XltdVEGp`A@5m=H z=TsXr91q#L6a|76bl1OL&2rgwWoW%8)f2!=hWc-Yp$9O>;?XhceGmx290(PiTm1Uu zc<583ql_@Fa|ho89$RpI=2Qpy9ATBeF#EgbjR0rH{Hja%TAcdj`#vI@3+nkapgVTJPQ*yVF9iE6*vrJ3dgvk?Ijc)cX6Z$xL z*oe3ZgYQ~lm#;q45M5LiyP>UM~mP0A{QKRX{Lv$V7$ z@fr2><~!PG#K5l-H=`lRJd4ar?A5(ed+NDRb1q1J6+UqeU5~N;n8Rn(M0<4{)nB(Q z^CB#hn!3ZLdkfQ@4lgm#DJUiSx2>jBvmkgfpss$;uy5!caVAI611zj;g_SGX>L{7r zF&VKq*Da8C5Lzq?ZkxA$Uq~2y$2=sOElIh(`2y^5T6MAWWOVpn)7|Q}xR-=%e%0sO z0(}U0x~l3EzFk8jHW8Bch4|P1CZ#78&$ZL&9l1Zk9%=5a!Xi<0N6L#Xo5?689Qq`q z2`Spa2=_&+wr?dV)P>G(nHzp)zm!r>t_{w11+E#2v9ZiU?)$#w_3Ky{JvaZRBp3Gi zyy7b2_rt^%cGiQz+7nW3=vEuq

nMEnXbjY|LQd=Y%G0!OdRT`sI8#jFqk44+-#r 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 literal 28821 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 diff --git a/icons/obj/lavaland/ash_flora.dmi b/icons/obj/lavaland/ash_flora.dmi index 8e7bbe5df292b100bc6c4bbdb51ba19eabb459ad..d796c200071c009a5c0f78b15e5df29463e98b0b 100644 GIT binary patch literal 24749 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 literal 24306 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 NO|=JiOKw|+{tuf%7~B8= diff --git a/icons/obj/machines/kitchen_stove.dmi b/icons/obj/machines/kitchen_stove.dmi new file mode 100644 index 0000000000000000000000000000000000000000..1a9e264158e41644fa31a2194763978d26a7aae8 GIT binary patch literal 702 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 H*hl^skF|fi literal 2939 zcma);c{tQx7r?*MFqUkUC0WK!Sq5cmF_viz$`V;)^h37ndzcx!7&|StU)BnZRN^Pb zG`2D!hK4Yf5u#+x&O810zR&yq@&0kodG0;;oafwoKF>Y(zJ-|)H|H5n006j+QHUE% zjr%j$Axzn>dz->ko%gKmLJ;o3u0dV_AzuD|01#1>pVi6}FTvOC5s{jc0jPMk2*D&05CQ#GHk0aO6fZs;^ z9~XfiYzn{b&hk!&8*7z*i_ac!4V>IEg|i7+RIPHv2&qh;@QHOc(oJ3YIuqO!sxjni z2=6xNdo|!-s1E>~fyM}Z>xiPC#n`(;b7Eb8i-d5YZm^gBV`?wK!Fj@m{f2^6H8RHv zEF5w(4uTS>h%JBe#QoW|vf6SPQc^SO`fwS~eWn%WH3h@5a%S<1J8RP zbliT_zKSy}Jd{BmO;c$It?+Lpn%06$C~1i^m7NOf_tdm}2xn(vmw^Ip9wC^Mbu>qX zf97Gw%C+mF$#MZzqBud+q{D%~T@^z6TcQE!u7D zcT&RA!^qY_#T??}c{F1TUwmG%Y%%S$4t4_aC$pTmospa9UdwCT(&5`xX}H#72e1U1+P_Up1JrzDZeLUbGW&D93Kq$^-Ts*_}h&+*K)n;(R?ZKv(Gw zv$}I^E=5gIpiC)|MjOXLiQQos_JzaVNU8Zc7+)Xg(=b(2{T6{`eDRhXX9@dG%~JjU zAz||Kc^|+pQU6`sZn0H$O65>mzc;Z>{t+1AlT7&#lIO)$4N)DF1wfRM^P&JfBK3Ia;u%EgGrkA2$5ndv1j%0K`Tfy>_#>G+aJk&+hu_nUj+@*Bqo%3x5wsEw6+L{IzHAmsajPq;3b_?Th{>AFaOJj%}X*pft* zXU^T}O&9)nihIW*@JfW7OqJa|=pk%&ow-pUQq%(%zMn?;*%2}e~JZH4s`cY)- zaU<#oJjkn(?3nQTElmEgI5itRmTrEi;m|67y-@V^3Mkzdcq%FAT;TE6*8H5`mVy8g_3|~^DmJ;i zhI@*oLqv_)@?z=zA^Eep)Tw;`BL!8jHP?uMqc%$#nAe(ib?@ChCUIF-4aA`PCHvUJ zmGC=asW0Aa|0+|k9c}YmolGC`Wx;uvmtywMp6%PmQKm`BXb;ijMlds@3B`ewtlsrl{?YyPB4S+&8H{X}5j zb%Nw+E-dDOb1_$yks4Vb;$3V-W@g!-(mJvn(T;!T9RtcLrgu8`KtLCodnzwkVU1#} zbbjGu4J#%>MrODWO`K?|21y+}FUwDX+WkwN8%ddxl|^0(Ot1wo>3hmf85Gvj;l=ICweR^a-4&BK~PXGoS>tBykf|kaoK=_{C)hbBs z7=xh9%#cAr>iZb@W%10JZ(DnnmlH5uS4D91k+XAi)dWg!FKhogk|)zkNlmYFZ9p?I zTNCJCAA~s_mXWoRWCKA1Gt^DJ#Nvo+T6(pAPV=Ao1s;!=ID7W&UnU*N)u4{i27J{_ zx`ed3@D=gQ4%P)piwadm~p#>VRD+a(_((_gjI00001bW%=J06^y0W&i*H zdU{k?bVOxyV{&P5bZKvH004NLQ&wh@oM2U+tC9|j)$TQ^POe;#vO@*+L)x@V|=Hz7N zrN`$3Eyzi%#HB}B!PU<|DrEh+T7^O^hr005y$L_t(IjbmUK1;{{9iGaMZYZ^Xz z#x%8LX8}A4#LCr@(+rVCIyzAdNCzoUMlzzKYvxR31?Ff9I67v|S}_5kpwPU$C^=0{ z9La>0Gmz|HPbw}iS5wL^D?o^$*ua!tWTK>$TwSJs!w*bmNy#C`YGui|6fgj_JEy4? z;R#G3kb-L5^7K%^uI!wqRDeeTgPNIAIX-y?hI9h*LmU7A)*UHZ^wqmr00000NkvXX Hu0mjfPiU>* literal 0 HcmV?d00001 diff --git a/modular_skyrat/modules/customization/datums/components/crafting/recipes.dm b/modular_skyrat/modules/customization/datums/components/crafting/recipes.dm index 21d1d8b2bde..9d88e61442a 100644 --- a/modular_skyrat/modules/customization/datums/components/crafting/recipes.dm +++ b/modular_skyrat/modules/customization/datums/components/crafting/recipes.dm @@ -6,7 +6,7 @@ /obj/item/organ/internal/lungs = 1, /obj/item/organ/internal/stomach = 1, /obj/item/food/grown/onion = 1, - /obj/item/food/soup/oatmeal = 1, + /obj/item/food/grown/oat = 1, /datum/reagent/consumable/salt = 1, ) result = /obj/item/food/snacks/store/bread/haggis diff --git a/modular_skyrat/modules/morefermentplants/code/banana.dm b/modular_skyrat/modules/morefermentplants/code/banana.dm index 4e0c9d66e90..449e798ba1e 100644 --- a/modular_skyrat/modules/morefermentplants/code/banana.dm +++ b/modular_skyrat/modules/morefermentplants/code/banana.dm @@ -1,2 +1,2 @@ /obj/item/food/grown/banana/bluespace - distill_reagent = /datum/reagent/consumable/clownstears + distill_reagent = /datum/reagent/consumable/nutriment/soup/clown_tears diff --git a/tgstation.dme b/tgstation.dme index 3d6097c892d..9ba1bd9837a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1318,6 +1318,7 @@ #include "code\datums\elements\decals\blood.dm" #include "code\datums\elements\food\dunkable.dm" #include "code\datums\elements\food\food_trash.dm" +#include "code\datums\elements\food\foodlike_drink.dm" #include "code\datums\elements\food\fried_item.dm" #include "code\datums\elements\food\grilled_item.dm" #include "code\datums\elements\food\microwavable.dm" @@ -3446,8 +3447,12 @@ #include "code\modules\food_and_drinks\machinery\oven.dm" #include "code\modules\food_and_drinks\machinery\processor.dm" #include "code\modules\food_and_drinks\machinery\smartfridge.dm" +#include "code\modules\food_and_drinks\machinery\stove.dm" +#include "code\modules\food_and_drinks\machinery\stove_component.dm" #include "code\modules\food_and_drinks\recipes\food_mixtures.dm" #include "code\modules\food_and_drinks\recipes\processor_recipes.dm" +#include "code\modules\food_and_drinks\recipes\soup_guide.dm" +#include "code\modules\food_and_drinks\recipes\soup_mixtures.dm" #include "code\modules\food_and_drinks\recipes\drinks\drinks_alcoholic.dm" #include "code\modules\food_and_drinks\recipes\drinks\drinks_lizard.dm" #include "code\modules\food_and_drinks\recipes\drinks\drinks_moth.dm" @@ -3470,7 +3475,6 @@ #include "code\modules\food_and_drinks\recipes\tablecraft\recipes_salad.dm" #include "code\modules\food_and_drinks\recipes\tablecraft\recipes_sandwich.dm" #include "code\modules\food_and_drinks\recipes\tablecraft\recipes_seafood.dm" -#include "code\modules\food_and_drinks\recipes\tablecraft\recipes_soup.dm" #include "code\modules\food_and_drinks\recipes\tablecraft\recipes_spaghetti.dm" #include "code\modules\food_and_drinks\restaurant\_venue.dm" #include "code\modules\food_and_drinks\restaurant\custom_order.dm"