From 1f3894e793f3893f9897514e338b92aba2a09013 Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Sun, 1 Jun 2025 23:37:43 +0000 Subject: [PATCH] Crafting refactor, implementing materials (#89465) My original plan was to just implement materials into crafting so that items would inherit the materials of their components, allowing for some interesting stuff if the material flags of the item allow it. However to my dismay crafting is a pile of old tech debt, starting from the old `del_reqs` and `CheckParts` which still contain lines about old janky bandaids that are no longer in use nor reachable, up to the `customizable_reagent_holder` component which has some harddel issues when your custom food is sliced, and items used in food recipes not being deleted and instead stored inside the result with no purpose as well as other inconsistencies like stack recipes that transfer materials having counterparts in the UI that don't do that. EDIT: Several things have come up while working on this, so I apologise that it ended up changing over 100+ files. I managed to atomize some of the changes, but it's a bit tedious. EDIT: TLDR because I was told this section is too vague and there's too much going on. This PR: - Improves the dated crafting code (not the UI). - replaced `atom/CheckParts` and `crafting_recipe/on_craft_completion` with `atom/on_craft_completion`. - Reqs used in food recipes are now deleted by default and not stored inside the result (they did nothing). - Renames the customizable_reagent_holder comp and improves it (No harddels/ref issues). - Adds a unit test that tries to craft all recipes to see what's wrong (it skips some of the much more specific reqs for now). - In the unit test is also the code to make sure materials of the crafted item and a non-crafted item of the same type are roughly the same, so far only applied to food. - Some mild material/food refactoring around the fact that food item code has been changed to support materials. Improving the backbone of the crafting system. Also materials and food code. :cl: refactor: Refactored crafting backend. Report possible pesky bugs. balance: the MEAT backpack (from the MEAT cargo pack) may be a smidge different because of code standardization. /:cl: --- code/__DEFINES/construction/material.dm | 5 + code/__DEFINES/crafting.dm | 6 +- code/__DEFINES/dcs/declarations.dm | 4 +- .../signals/signals_atom/signals_atom_main.dm | 5 + .../signals_atom/signals_atom_x_act.dm | 6 +- .../dcs/signals/signals_customizable.dm | 2 +- code/__DEFINES/food.dm | 7 + code/__DEFINES/traits/declarations.dm | 4 +- code/_globalvars/traits/_traits.dm | 4 +- code/datums/components/crafting/_recipes.dm | 21 +- .../datums/components/crafting/atmospheric.dm | 7 - code/datums/components/crafting/chemistry.dm | 14 - code/datums/components/crafting/crafting.dm | 471 +++++++++--------- .../components/crafting/entertainment.dm | 19 +- code/datums/components/crafting/equipment.dm | 8 - .../components/crafting/melee_weapon.dm | 1 - .../components/crafting/ranged_weapon.dm | 1 - code/datums/components/crafting/robot.dm | 25 +- code/datums/components/crafting/tools.dm | 31 +- code/datums/components/food/edible.dm | 25 +- code/datums/components/grillable.dm | 3 +- ...eagent_holder.dm => ingredients_holder.dm} | 214 ++++---- code/datums/components/storm_hating.dm | 7 +- code/datums/elements/dryable.dm | 19 +- code/datums/elements/elevation.dm | 31 +- code/datums/elements/food/microwavable.dm | 1 + code/datums/materials/_material.dm | 8 + code/datums/materials/meat.dm | 37 +- code/datums/materials/pizza.dm | 30 +- code/game/atom/_atom.dm | 52 +- code/game/atom/atom_materials.dm | 36 +- code/game/atoms_movable.dm | 5 + code/game/machinery/_machinery.dm | 4 +- code/game/machinery/medipen_refiller.dm | 2 +- code/game/machinery/pipe/construction.dm | 10 + code/game/machinery/spaceheater.dm | 12 + code/game/machinery/syndicatebomb.dm | 49 +- .../objects/effects/decals/cleanable/food.dm | 1 - code/game/objects/items/cigarettes.dm | 2 +- code/game/objects/items/defib.dm | 4 +- code/game/objects/items/devices/aicard.dm | 10 + code/game/objects/items/devices/flashlight.dm | 2 +- code/game/objects/items/flamethrower.dm | 4 +- code/game/objects/items/food/_food.dm | 47 +- code/game/objects/items/food/bread.dm | 11 +- code/game/objects/items/food/burgers.dm | 53 +- code/game/objects/items/food/cake.dm | 5 +- code/game/objects/items/food/donkpocket.dm | 18 + code/game/objects/items/food/donuts.dm | 9 + code/game/objects/items/food/dough.dm | 4 +- code/game/objects/items/food/egg.dm | 2 + code/game/objects/items/food/frozen.dm | 1 + code/game/objects/items/food/lizard.dm | 21 +- code/game/objects/items/food/martian.dm | 44 +- code/game/objects/items/food/meatdish.dm | 31 ++ code/game/objects/items/food/meatslab.dm | 11 +- code/game/objects/items/food/mexican.dm | 10 +- code/game/objects/items/food/misc.dm | 19 +- code/game/objects/items/food/moth.dm | 1 + code/game/objects/items/food/packaged.dm | 1 + code/game/objects/items/food/pastries.dm | 1 + code/game/objects/items/food/pie.dm | 8 +- code/game/objects/items/food/pizza.dm | 15 +- code/game/objects/items/food/salad.dm | 6 +- code/game/objects/items/food/sandwichtoast.dm | 11 + code/game/objects/items/food/snacks.dm | 1 + code/game/objects/items/food/spaghetti.dm | 11 +- code/game/objects/items/food/vegetables.dm | 1 + code/game/objects/items/spear.dm | 21 +- code/game/objects/items/storage/backpack.dm | 35 +- code/game/objects/items/storage/storage.dm | 6 + code/game/objects/objs.dm | 10 - code/game/objects/structures.dm | 6 + .../structures/crates_lockers/closets.dm | 18 +- code/game/objects/structures/headpike.dm | 17 +- code/game/objects/structures/toiletbong.dm | 15 + code/modules/events/holiday/easter.dm | 1 + code/modules/fishing/fish/_fish.dm | 2 +- .../food_and_drinks/recipes/food_mixtures.dm | 15 +- .../recipes/processor_recipes.dm | 2 +- .../recipes/tablecraft/recipes_burger.dm | 5 +- .../recipes/tablecraft/recipes_drink.dm | 38 +- .../recipes/tablecraft/recipes_guide.dm | 1 + .../recipes/tablecraft/recipes_lizard.dm | 1 - .../recipes/tablecraft/recipes_misc.dm | 7 +- .../recipes/tablecraft/recipes_pastry.dm | 9 - .../recipes/tablecraft/recipes_pie.dm | 1 + code/modules/manufactorio/machines/crafter.dm | 4 +- .../mob/living/basic/bots/medbot/medbot.dm | 9 + code/modules/mob/living/basic/pets/cat/cat.dm | 2 + .../mob/living/basic/pets/cat/keeki.dm | 4 +- .../mob/living/basic/pets/dog/dog_subtypes.dm | 4 +- .../living/basic/space_fauna/bear/_bear.dm | 4 +- code/modules/mod/mod_core.dm | 6 +- .../reagents/chemistry/holder/holder.dm | 16 +- code/modules/reagents/reagent_containers.dm | 6 + .../reagent_containers/cups/glassbottle.dm | 15 +- code/modules/unit_tests/_unit_tests.dm | 1 + code/modules/unit_tests/crafting.dm | 199 ++++++++ code/modules/vehicles/mecha/_mecha.dm | 3 +- .../mecha/mecha_construction_paths.dm | 4 +- code/modules/vehicles/mecha/mecha_defense.dm | 2 +- code/modules/vehicles/motorized_wheelchair.dm | 10 +- tgstation.dme | 2 +- 104 files changed, 1294 insertions(+), 758 deletions(-) rename code/datums/components/{customizable_reagent_holder.dm => ingredients_holder.dm} (55%) create mode 100644 code/modules/unit_tests/crafting.dm diff --git a/code/__DEFINES/construction/material.dm b/code/__DEFINES/construction/material.dm index 423c1c1075b..f01ea621183 100644 --- a/code/__DEFINES/construction/material.dm +++ b/code/__DEFINES/construction/material.dm @@ -62,6 +62,11 @@ #define MATERIAL_GREYSCALE (1<<4) /// Materials like plasteel and alien alloy won't apply slowdowns. #define MATERIAL_NO_SLOWDOWN (1<<5) +/** + * This item is not affected by the standard food-related effects of materials like meat and pizza. + * Necessary for the edible component counterparts, on_edible_applied() and on_edible_removed() + */ +#define MATERIAL_NO_EDIBILITY (1<<6) //Special return values of [/datum/component/material_container/insert_item] /// No material was found inside them item diff --git a/code/__DEFINES/crafting.dm b/code/__DEFINES/crafting.dm index e71004f7f53..b4bbff71ce9 100644 --- a/code/__DEFINES/crafting.dm +++ b/code/__DEFINES/crafting.dm @@ -6,8 +6,6 @@ #define CRAFTING_MACHINERY_USE 0 ///If the structure is only "used" i.e. it checks to see if it's nearby and allows crafting, but doesn't delete it #define CRAFTING_STRUCTURE_USE 0 -///If the ingredient is only "used" i.e. it checks to see if it's nearby and allows crafting, but doesn't delete it -#define CRAFTING_INGREDIENT_USE 0 //stack recipe placement check types /// Checks if there is an object of the result type in any of the cardinal directions @@ -34,6 +32,10 @@ #define CRAFT_TRANSFERS_REAGENTS (1<<7) /// Crafting clears all reagents present in the finished product #define CRAFT_CLEARS_REAGENTS (1<<8) +/// For the crafting unit test, ensures that the custom materials of an item are the same when crafted and spawned. +#define CRAFT_ENFORCE_MATERIALS_PARITY (1<<9) +/// Exclusive to the personal_crafting component, skips the time spent crafting the recipe. +#define CRAFT_IGNORE_DO_AFTER (1<<10) //food/drink crafting defines //When adding new defines, please make sure to also add them to the encompassing list diff --git a/code/__DEFINES/dcs/declarations.dm b/code/__DEFINES/dcs/declarations.dm index 95ad093f995..f5be9fbc6d3 100644 --- a/code/__DEFINES/dcs/declarations.dm +++ b/code/__DEFINES/dcs/declarations.dm @@ -69,11 +69,11 @@ #define CALTROP_NOSTUN (1 << 3) #define CALTROP_NOCRAWL (1 << 4) -//Ingredient type in datum/component/customizable_reagent_holder +//Ingredient type in datum/component/ingredients_holder #define CUSTOM_INGREDIENT_TYPE_EDIBLE 1 #define CUSTOM_INGREDIENT_TYPE_DRYABLE 2 -//Icon overlay type in datum/component/customizable_reagent_holder +//Icon overlay type in datum/component/ingredients_holder #define CUSTOM_INGREDIENT_ICON_NOCHANGE 0 #define CUSTOM_INGREDIENT_ICON_FILL 1 #define CUSTOM_INGREDIENT_ICON_SCATTER 2 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 95168ec3606..1f261db129a 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm @@ -149,6 +149,11 @@ /// From /datum/component/tether/UnregisterFromParent() #define COMSIG_ATOM_TETHER_SNAPPED "atom_tether_snapped" +/// From /atom/finalize_material_effects(): (list/materials, datum/material/main_material) +#define COMSIG_ATOM_FINALIZE_MATERIAL_EFFECTS "atom_finalize_material_effects" +/// From /atom/finalize_remove_material_effects(): (list/materials, datum/material/main_material) +#define COMSIG_ATOM_FINALIZE_REMOVE_MATERIAL_EFFECTS "atom_finalize_remove_material_effects" + /// From /atom/proc/update_atom_colour() : (color_changed) #define COMSIG_ATOM_COLOR_UPDATED "atom_color_updated" /// Cancels update_appearance call in case you are somehow forced to call it manually to prevent dupe calls diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm index e7c048dbed7..0b732912726 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm @@ -24,9 +24,9 @@ #define COMPONENT_BULLET_PIERCED (1<<2) ///from base of atom/bullet_act(): (/obj/proj, def_zone, piercing_hit, blocked) #define COMSIG_ATOM_BULLET_ACT "atom_bullet_act" -///from base of atom/CheckParts(): (list/parts_list, datum/crafting_recipe/R) -#define COMSIG_ATOM_CHECKPARTS "atom_checkparts" -///from base of atom/CheckParts(): (atom/movable/new_craft) - The atom has just been used in a crafting recipe and has been moved inside new_craft. +///from base of atom/on_craft_completion(): (components, datum/crafting_recipe/current_recipe) +#define COMSIG_ATOM_ON_CRAFT "atom_checkparts" +///from base of atom/used_in_craft(): (atom/result) #define COMSIG_ATOM_USED_IN_CRAFT "atom_used_in_craft" ///from base of atom/blob_act(): (/obj/structure/blob) #define COMSIG_ATOM_BLOB_ACT "atom_blob_act" diff --git a/code/__DEFINES/dcs/signals/signals_customizable.dm b/code/__DEFINES/dcs/signals/signals_customizable.dm index babdeb276fc..6656aac9c03 100644 --- a/code/__DEFINES/dcs/signals/signals_customizable.dm +++ b/code/__DEFINES/dcs/signals/signals_customizable.dm @@ -1,3 +1,3 @@ //Customizable -///called when an atom with /datum/component/customizable_reagent_holder is customized (obj/item/I) +///called when an atom with /datum/component/ingredients_holder is customized (obj/item/I) #define COMSIG_ATOM_CUSTOMIZED "atom_customized" diff --git a/code/__DEFINES/food.dm b/code/__DEFINES/food.dm index ae78295bd2c..0f77bccca0f 100644 --- a/code/__DEFINES/food.dm +++ b/code/__DEFINES/food.dm @@ -285,3 +285,10 @@ DEFINE_BITFIELD(food_flags, list( /// How much milk is needed to make butter on a reagent grinder #define MILK_TO_BUTTER_COEFF 25 + +/// How much material one slab of meat usually contains +#define MEATSLAB_MATERIAL_AMOUNT SHEET_MATERIAL_AMOUNT * 4 +/// How many cutlets or meatballs one slab gives when processed +#define MEATSLAB_PROCESSED_AMOUNT 3 +/// This should be 1/3 of the amount found in a slab (a portion will be lost when rounding but it's negligible) +#define MEATDISH_MATERIAL_AMOUNT (MEATSLAB_MATERIAL_AMOUNT / MEATSLAB_PROCESSED_AMOUNT) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index d788081055b..e4fe95aad41 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -798,6 +798,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_T_RAY_VISIBLE "t-ray-visible" /// If this item's been fried #define TRAIT_FOOD_FRIED "food_fried" +/// Has the ingredients_holder component +#define TRAIT_INGREDIENTS_HOLDER "ingredients_holder" /// If this item's been bbq grilled #define TRAIT_FOOD_BBQ_GRILLED "food_bbq_grilled" /// This is a silver slime created item @@ -949,8 +951,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_DRYABLE "trait_dryable" ///Trait for dried items #define TRAIT_DRIED "trait_dried" -/// Trait for customizable reagent holder -#define TRAIT_CUSTOMIZABLE_REAGENT_HOLDER "customizable_reagent_holder" /// Trait for allowing an item that isn't food into the customizable reagent holder #define TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT "odd_customizable_food_ingredient" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 1d24deae3ff..acd6fd97416 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -15,7 +15,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_COMMISSIONED" = TRAIT_COMMISSIONED, "TRAIT_CLIMBABLE" = TRAIT_CLIMBABLE, "TRAIT_CURRENTLY_CLEANING" = TRAIT_CURRENTLY_CLEANING, - "TRAIT_CUSTOMIZABLE_REAGENT_HOLDER" = TRAIT_CUSTOMIZABLE_REAGENT_HOLDER, "TRAIT_DO_NOT_SPLASH" = TRAIT_DO_NOT_SPLASH, "TRAIT_DRIED" = TRAIT_DRIED, "TRAIT_DRYABLE" = TRAIT_DRYABLE, @@ -24,11 +23,12 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_FOOD_CHEF_MADE" = TRAIT_FOOD_CHEF_MADE, "TRAIT_FOOD_FRIED" = TRAIT_FOOD_FRIED, "TRAIT_GOT_DAMPENED" = TRAIT_GOT_DAMPENED, - "TRAIT_QUALITY_FOOD_INGREDIENT" = TRAIT_QUALITY_FOOD_INGREDIENT, + "TRAIT_INGREDIENTS_HOLDER" = TRAIT_INGREDIENTS_HOLDER, "TRAIT_FOOD_SILVER" = TRAIT_FOOD_SILVER, "TRAIT_KEEP_TOGETHER" = TRAIT_KEEP_TOGETHER, "TRAIT_LIGHTING_DEBUGGED" = TRAIT_LIGHTING_DEBUGGED, "TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION" = TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION, + "TRAIT_QUALITY_FOOD_INGREDIENT" = TRAIT_QUALITY_FOOD_INGREDIENT, "TRAIT_RECENTLY_COINED" = TRAIT_RECENTLY_COINED, "TRAIT_RUSTY" = TRAIT_RUSTY, "TRAIT_SPINNING" = TRAIT_SPINNING, diff --git a/code/datums/components/crafting/_recipes.dm b/code/datums/components/crafting/_recipes.dm index aaa22239065..02a10ccf4e2 100644 --- a/code/datums/components/crafting/_recipes.dm +++ b/code/datums/components/crafting/_recipes.dm @@ -15,10 +15,17 @@ var/list/tool_behaviors /// Type paths of items needed but not consumed. Lazy list. var/list/tool_paths + /** + * If defined, it'll spawn paths in this list first during the unit test. + * This is an assoc list, with the key being the paths and the value being the amount (e.g. list(/obj/item = 2)) + */ + var/list/unit_test_spawn_extras ///time in seconds. Remember to use the SECONDS define! var/time = 3 SECONDS - ///type paths of items that will be forceMoved() into the result, or added to the reagents of it + ///type paths of items that will be forceMoved() into the result instead of being deleted var/list/parts = list() + ///items, structures and machineries of types that are in this list won't transfer their materials to the result + var/list/requirements_mats_blacklist ///like tool_behaviors but for reagents var/list/chem_catalysts = list() ///where it shows up in the crafting UI @@ -71,6 +78,10 @@ tool_behaviors = string_list(tool_behaviors) if(tool_paths) tool_paths = string_list(tool_paths) + for(var/key in parts) + if(!parts[key]) + //ensure every single, same-type part used for the recipe will be transferred if the value is otherwise not specified + parts[key] = INFINITY /datum/crafting_recipe/stack/New(obj/item/stack/material, datum/stack_recipe/stack_recipe) if(!material || !stack_recipe || !stack_recipe.result_type) @@ -86,6 +97,9 @@ src.category = stack_recipe.category || CAT_MISC src.placement_checks = stack_recipe.placement_checks + if(!(stack_recipe.crafting_flags & CRAFT_APPLIES_MATS)) + requirements_mats_blacklist = list(material) //the item is not intended to have mats :shrug: + /** * Run custom pre-craft checks for this recipe, don't add feedback messages in this because it will spam the client * @@ -95,8 +109,9 @@ /datum/crafting_recipe/proc/check_requirements(mob/user, list/collected_requirements) return TRUE -/datum/crafting_recipe/proc/on_craft_completion(mob/user, atom/result) - return +///Run custom pre-craft checks for this recipe for tools, rather than consumed requirements. +/datum/crafting_recipe/proc/check_tools(atom/source, list/collected_tools, final_check = FALSE) + return TRUE /// Additional UI data to be passed to the crafting UI for this recipe /datum/crafting_recipe/proc/crafting_ui_data() diff --git a/code/datums/components/crafting/atmospheric.dm b/code/datums/components/crafting/atmospheric.dm index 82e817be072..6bf75e1c884 100644 --- a/code/datums/components/crafting/atmospheric.dm +++ b/code/datums/components/crafting/atmospheric.dm @@ -49,13 +49,6 @@ return TRUE return FALSE -/datum/crafting_recipe/spec_pipe/on_craft_completion(mob/user, atom/result) - var/obj/item/pipe/crafted_pipe = result - crafted_pipe.pipe_type = pipe_type - crafted_pipe.pipe_color = ATMOS_COLOR_OMNI - crafted_pipe.setDir(user.dir) - crafted_pipe.update() - /datum/crafting_recipe/spec_pipe/layer_adapter name = "Layer manifold fitting" tool_behaviors = list(TOOL_WRENCH, TOOL_WELDER) diff --git a/code/datums/components/crafting/chemistry.dm b/code/datums/components/crafting/chemistry.dm index eecbecea1ae..7f7d5136e83 100644 --- a/code/datums/components/crafting/chemistry.dm +++ b/code/datums/components/crafting/chemistry.dm @@ -18,7 +18,6 @@ /obj/item/rag = 1, /obj/item/reagent_containers/cup/glass/bottle = 1, ) - parts = list(/obj/item/reagent_containers/cup/glass/bottle = 1) time = 4 SECONDS category = CAT_CHEMISTRY @@ -30,7 +29,6 @@ /obj/item/grenade/c4 = 1, /obj/item/grenade/chem_grenade = 2 ) - parts = list(/obj/item/stock_parts/matter_bin = 1, /obj/item/grenade/chem_grenade = 2) time = 3 SECONDS category = CAT_CHEMISTRY @@ -42,7 +40,6 @@ /obj/item/gibtonite = 1, /obj/item/grenade/chem_grenade = 2, ) - parts = list(/obj/item/stock_parts/matter_bin = 1, /obj/item/grenade/chem_grenade = 2) time = 5 SECONDS category = CAT_CHEMISTRY @@ -149,17 +146,6 @@ machinery = list(/obj/machinery/space_heater = CRAFTING_MACHINERY_CONSUME) category = CAT_CHEMISTRY -/datum/crafting_recipe/improvised_chem_heater/on_craft_completion(mob/user, atom/result) - if(!istype(user)) - return - var/obj/item/stock_parts/power_store/cell/cell = locate(/obj/item/stock_parts/power_store/cell) in range(1) - if(!cell) - return - var/obj/machinery/space_heater/improvised_chem_heater/heater = result - var/turf/turf = get_turf(cell) - heater.forceMove(turf) - heater.attackby(cell, user) //puts it into the heater - /datum/crafting_recipe/improvised_coolant name = "Improvised cooling spray" tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index e5e16d84e86..ed6b776e072 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -1,3 +1,10 @@ +//list key declarations used in check_contents(), get_surroundings() and check_tools() +#define CONTENTS_INSTANCES "instances" +#define CONTENTS_MACHINERY "machinery" +#define CONTENTS_STRUCTURES "structures" +#define CONTENTS_REAGENTS "reagents" +#define CONTENTS_TOOL_BEHAVIOUR "tool_behaviour" + /datum/component/personal_crafting /// Custom screen_loc for our element var/screen_loc_override @@ -37,32 +44,32 @@ check_contents - takes a recipe and a key-type list and checks if said recipe can be done with available stuff check_tools - takes recipe, a key-type list, and a user and checks if there are enough tools to do the stuff, checks bugs one level deep construct_item - takes a recipe and a user, call all the checking procs, calls do_after, checks all the things again, calls del_reqs, creates result, calls CheckParts of said result with argument being list returned by deel_reqs - del_reqs - takes recipe and a user, loops over the recipes reqs var and tries to find everything in the list make by get_environment and delete it/add to parts list, then returns the said list + get_used_reqs - takes recipe, a user and a list (for mats), loops over the recipes reqs var and tries to find everything in the list make by get_environment and returns a list of the components to be used */ /** * Check that the contents of the recipe meet the requirements. * * user: The /mob that initated the crafting. - * R: The /datum/crafting_recipe being attempted. - * contents: List of items to search for R's reqs. + * recipe: The /datum/crafting_recipe being attempted. + * contents: List of items to search for the recipe's reqs. */ -/datum/component/personal_crafting/proc/check_contents(atom/a, datum/crafting_recipe/R, list/contents) - var/list/item_instances = contents["instances"] - var/list/machines = contents["machinery"] - var/list/structures = contents["structures"] - contents = contents["other"] +/datum/component/personal_crafting/proc/check_contents(atom/a, datum/crafting_recipe/recipe, list/contents) + var/list/item_instances = contents[CONTENTS_INSTANCES] + var/list/machines = contents[CONTENTS_MACHINERY] + var/list/structures = contents[CONTENTS_STRUCTURES] + contents = contents[CONTENTS_REAGENTS] var/list/requirements_list = list() // Process all requirements - for(var/requirement_path in R.reqs) + for(var/requirement_path in recipe.reqs) // Check we have the appropriate amount available in the contents list - var/needed_amount = R.reqs[requirement_path] + var/needed_amount = recipe.reqs[requirement_path] for(var/content_item_path in contents) // Right path and not blacklisted - if(!ispath(content_item_path, requirement_path) || R.blacklist.Find(content_item_path)) + if(!ispath(content_item_path, requirement_path) || recipe.blacklist.Find(content_item_path)) continue needed_amount -= contents[content_item_path] @@ -72,7 +79,7 @@ if(needed_amount > 0) return FALSE - // Store the instances of what we will use for R.check_requirements() for requirement_path + // Store the instances of what we will use for recipe.check_requirements() for requirement_path var/list/instances_list = list() for(var/instance_path in item_instances) if(ispath(instance_path, requirement_path)) @@ -80,37 +87,32 @@ requirements_list[requirement_path] = instances_list - for(var/requirement_path in R.chem_catalysts) - if(contents[requirement_path] < R.chem_catalysts[requirement_path]) + for(var/requirement_path in recipe.chem_catalysts) + if(contents[requirement_path] < recipe.chem_catalysts[requirement_path]) return FALSE var/mech_found = FALSE - for(var/machinery_path in R.machinery) + for(var/machinery_path in recipe.machinery) mech_found = FALSE for(var/obj/machinery/machine as anything in machines) - if(ispath(machine, machinery_path))//We don't care for volume with machines, just if one is there or not + if(ispath(machine, machinery_path))// We only need one machine per key, unlike items mech_found = TRUE break if(!mech_found) return FALSE - for(var/required_structure_path in R.structures) - // Check for the presence of the required structure. Allow for subtypes to be used if not blacklisted - var/needed_amount = R.structures[required_structure_path] - for(var/structure_path in structures) - if(!ispath(structure_path, required_structure_path) || R.blacklist.Find(structure_path)) - continue - - needed_amount -= structures[required_structure_path] - requirements_list[required_structure_path] = structures[structure_path] // Store an instance of what we are using for check_requirements - if(needed_amount <= 0) - break - - // We didn't find the required item - if(needed_amount > 0) + var/found = FALSE + for(var/structure_path in recipe.structures) + found = FALSE + for(var/obj/structure/structure as anything in structures) + if(ispath(structure, structure_path))// We only need one structure per key, unlike items + found = TRUE + break + if(!found) return FALSE - return R.check_requirements(a, requirements_list) + //Skip extra requirements when unit testing, like, underwater basket weaving? Get the hell out of here + return PERFORM_ALL_TESTS(crafting) || recipe.check_requirements(a, requirements_list) /datum/component/personal_crafting/proc/get_environment(atom/a, list/blacklist = null, radius_range = 1) . = list() @@ -129,59 +131,60 @@ /datum/component/personal_crafting/proc/get_surroundings(atom/a, list/blacklist=null) . = list() - .["tool_behaviour"] = list() - .["other"] = list() - .["instances"] = list() - .["machinery"] = list() - .["structures"] = list() + .[CONTENTS_TOOL_BEHAVIOUR] = list() + .[CONTENTS_REAGENTS] = list() + .[CONTENTS_INSTANCES] = list() + .[CONTENTS_MACHINERY] = list() + .[CONTENTS_STRUCTURES] = list() for(var/obj/object in get_environment(a, blacklist)) if(isitem(object)) var/obj/item/item = object - LAZYADDASSOCLIST(.["instances"], item.type, item) + LAZYADDASSOCLIST(.[CONTENTS_INSTANCES], item.type, item) if(isstack(item)) var/obj/item/stack/stack = item - .["other"][item.type] += stack.amount + .[CONTENTS_REAGENTS][item.type] += stack.amount else - .["other"][item.type] += 1 + .[CONTENTS_REAGENTS][item.type] += 1 if(is_reagent_container(item) && item.is_drainable() && length(item.reagents.reagent_list)) //some container that has some reagents inside it that can be drained var/obj/item/reagent_containers/container = item for(var/datum/reagent/reagent as anything in container.reagents.reagent_list) - .["other"][reagent.type] += reagent.volume + .[CONTENTS_REAGENTS][reagent.type] += reagent.volume else //a reagent container that is empty can also be used as a tool. e.g. glass bottle can be used as a rolling pin if(item.tool_behaviour) - .["tool_behaviour"] += item.tool_behaviour + .[CONTENTS_TOOL_BEHAVIOUR] += item.tool_behaviour else if (ismachinery(object)) - LAZYADDASSOCLIST(.["machinery"], object.type, object) + LAZYADDASSOCLIST(.[CONTENTS_MACHINERY], object.type, object) else if (isstructure(object)) - LAZYADDASSOCLIST(.["structures"], object.type, object) + LAZYADDASSOCLIST(.[CONTENTS_STRUCTURES], object.type, object) /// Returns a boolean on whether the tool requirements of the input recipe are satisfied by the input source and surroundings. -/datum/component/personal_crafting/proc/check_tools(atom/source, datum/crafting_recipe/recipe, list/surroundings) +/datum/component/personal_crafting/proc/check_tools(atom/source, datum/crafting_recipe/recipe, list/surroundings, final_check = FALSE) if(!length(recipe.tool_behaviors) && !length(recipe.tool_paths)) return TRUE + var/list/available_tools = list() var/list/present_qualities = list() - for(var/obj/item/contained_item in source.contents) - if(contained_item.atom_storage) - for(var/obj/item/subcontained_item in contained_item.contents) - available_tools[subcontained_item.type] = TRUE - if(subcontained_item.tool_behaviour) - present_qualities[subcontained_item.tool_behaviour] = TRUE + var/list/all_instances = list() + for(var/atom/movable/movable as anything in source.contents) + all_instances += movable + if(movable.atom_storage) + all_instances += movable.contents + + for(var/obj/item/contained_item in all_instances) //fill the available tools list with available tool types and behaviours available_tools[contained_item.type] = TRUE if(contained_item.tool_behaviour) present_qualities[contained_item.tool_behaviour] = TRUE - for(var/quality in surroundings["tool_behaviour"]) + for(var/quality in surroundings[CONTENTS_TOOL_BEHAVIOUR]) present_qualities[quality] = TRUE - for(var/path in surroundings["other"]) + for(var/path in surroundings[CONTENTS_REAGENTS]) available_tools[path] = TRUE for(var/required_quality in recipe.tool_behaviors) - if(present_qualities[required_quality]) - continue - return FALSE + if(!present_qualities[required_quality]) + return FALSE for(var/required_path in recipe.tool_paths) var/found_this_tool = FALSE @@ -190,12 +193,15 @@ continue found_this_tool = TRUE break - if(found_this_tool) - continue - return FALSE + if(!found_this_tool) + return FALSE - return TRUE + //add the contents of the assoc list of the surrounding instances to all_instances for the recipe.check_tools() call + var/list/surrounding_instances = surroundings[CONTENTS_INSTANCES] + for(var/type_key in surrounding_instances) + all_instances |= surrounding_instances[type_key] + return recipe.check_tools(source, all_instances, final_check) /datum/component/personal_crafting/proc/construct_item(atom/crafter, datum/crafting_recipe/recipe) if(!crafter) @@ -205,13 +211,82 @@ return ", invalid recipe!" // This can happen, I can't really explain why, but it can. Better safe than sorry. var/list/contents = get_surroundings(crafter, recipe.blacklist) - var/send_feedback = 1 - var/turf/dest_turf = get_turf(crafter) + var/fail_message = perform_all_checks(crafter, recipe, contents, check_tools_last = ignored_flags & CRAFT_IGNORE_DO_AFTER) + if(fail_message) + return fail_message + //If we're a mob we'll try a do_after; non mobs will instead instantly construct the item + if(!(ignored_flags & CRAFT_IGNORE_DO_AFTER)) + // BUBBER EDIT ADDITION BEGIN - Construction skill + var/mob/crafting_mob = crafter + var/skill_modifier = 1 + if(istype(crafting_mob)) + skill_modifier = crafter_mob.mind.get_skill_modifier(/datum/skill/construction, SKILL_SPEED_MODIFIER) + // BUBBER EDIT ADDITION END - Construction skill + if(!do_after(crafter, recipe.time * skill_modifier, target = crafter)) // BUBBER EDIT CHANGE - Construction skill - Original: if(!do_after(crafter, recipe.time, target = crafter)) + return "." + contents = get_surroundings(crafter, recipe.blacklist) + fail_message = perform_all_checks(crafter, recipe, contents, check_tools_last = TRUE) + if(fail_message) + return fail_message + + //used to gather the material composition of the utilized requirements to transfer to the result + var/list/total_materials = list() + var/list/stuff_to_use = get_used_reqs(recipe, crafter, total_materials) + var/atom/result + var/turf/craft_turf = get_turf(crafter.loc) + var/set_materials = TRUE + if(ispath(recipe.result, /turf)) + result = craft_turf.place_on_top(recipe.result) + else if(ispath(recipe.result, /obj/item/stack)) + //we don't merge the stack right away but try to put it in the hand of the crafter + result = new recipe.result(craft_turf, recipe.result_amount || 1, /*merge =*/FALSE) + set_materials = FALSE //stacks are bit too complex for it for now, but you're free to change that. + else + result = new recipe.result(craft_turf) + if(result.atom_storage && recipe.delete_contents) + for(var/obj/item/thing in result) + qdel(thing) + // BUBBER EDIT ADDITION BEGIN - Construction skill + var/mob/crafting_mob = crafter + if(istype(crafting_mob)) + crafting_mob.mind.adjust_experience(/datum/skill/construction, 5) + // BUBBER EDIT ADDITION END - Construction skill + result.setDir(crafter.dir) + var/datum/reagents/holder = locate() in stuff_to_use + if(holder) //transfer reagents from ingredients to result + if(!ispath(recipe.result, /obj/item/reagent_containers) && result.reagents) + if(recipe.crafting_flags & CRAFT_CLEARS_REAGENTS) + result.reagents.clear_reagents() + if(recipe.crafting_flags & CRAFT_TRANSFERS_REAGENTS) + holder.trans_to(result.reagents, holder.total_volume, no_react = TRUE) + stuff_to_use -= holder //This is the only non-movable in our list, we need to remove it. + qdel(holder) + result.on_craft_completion(stuff_to_use, recipe, crafter) + if(set_materials) + result.set_custom_materials(total_materials) + for(var/atom/movable/component as anything in stuff_to_use) //delete anything that wasn't stored inside the object + if(component.loc != result || isturf(result)) + qdel(component) + if(!PERFORM_ALL_TESTS(crafting)) + SSblackbox.record_feedback("tally", "object_crafted", 1, result.type) + return result //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item + +///This proc performs all the necessary conditional control statement to ensure that the object is allowed to be crafted by the crafter. +/datum/component/personal_crafting/proc/perform_all_checks(atom/crafter, datum/crafting_recipe/recipe, list/contents, check_tools_last = FALSE) if(!check_contents(crafter, recipe, contents)) return ", missing component." - if(!check_tools(crafter, recipe, contents)) + var/turf/dest_turf = get_turf(crafter) + + // Mobs call perform_all_checks() twice since they don't have the CRAFT_IGNORE_DO_AFTER flag, + // one before the do_after() and another after that. While other entities may have that flag and therefore only call the proc once. + // Check_tools() meanwhile has a final_check arg which, if true, may perform some statements that can + // modify some of the tools, like expending charges from a crayon or spraycan, which may make it unable + // to meet some criterias afterward, so it's important to call that, last by the end of the final perform_all_checks(). + // For any non-final perform_all_checks() call, just keep check_tools() here because it's + // the most imporant feedback after "missing component". + if(!check_tools_last && !check_tools(crafter, recipe, contents, FALSE)) return ", missing tool." var/considered_flags = recipe.crafting_flags & ~(ignored_flags) @@ -256,185 +331,99 @@ if(!locate(/obj/structure/transport/linear/tram) in dest_turf) return ", must be made on a tram!" - //If we're a mob we'll try a do_after; non mobs will instead instantly construct the item - //SKYRAT EDIT START: Two Skills (Construction) - var/mob/crafter_mob - var/skill_modifier = 1 - if(ismob(crafter)) - crafter_mob = crafter - skill_modifier = crafter_mob.mind.get_skill_modifier(/datum/skill/construction, SKILL_SPEED_MODIFIER) - if(!do_after(crafter, recipe.time * skill_modifier, target = crafter)) - return "." - contents = get_surroundings(crafter, recipe.blacklist) - if(!check_contents(crafter, recipe, contents)) - return ", missing component." - if(!check_tools(crafter, recipe, contents)) + if(check_tools_last && !check_tools(crafter, recipe, contents, TRUE)) return ", missing tool." - var/list/parts = del_reqs(recipe, crafter) - var/atom/movable/result - if(ispath(recipe.result, /obj/item/stack)) - result = new recipe.result(get_turf(crafter.loc), recipe.result_amount || 1) - result.dir = crafter.dir - else - result = new recipe.result(get_turf(crafter.loc)) - result.dir = crafter.dir - if(result.atom_storage && recipe.delete_contents) - for(var/obj/item/thing in result) - qdel(thing) - if(crafter_mob) - crafter_mob.mind.adjust_experience(/datum/skill/construction, 5) - //SKYRAT EDIT END - var/datum/reagents/holder = locate() in parts - if(holder) //transfer reagents from ingredients to result - if(!ispath(recipe.result, /obj/item/reagent_containers) && result.reagents) - if(recipe.crafting_flags & CRAFT_CLEARS_REAGENTS) - result.reagents.clear_reagents() - if(recipe.crafting_flags & CRAFT_TRANSFERS_REAGENTS) - holder.trans_to(result.reagents, holder.total_volume, no_react = TRUE) - parts -= holder - qdel(holder) - result.CheckParts(parts, recipe) - if(send_feedback) - SSblackbox.record_feedback("tally", "object_crafted", 1, result.type) - return result //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item -/*Del reqs works like this: +/** + * get_used_reqs works like this: + * Loop over reqs var of the recipe + * Set var amt to the value current cycle req is pointing to, its amount of type we need to delete + * Get var/surroundings list of things accessable to crafting by get_environment() + * Check the type of the current cycle req + * * If its reagent then do a while loop, inside it try to locate() reagent containers, inside such containers try to locate needed reagent, if there isn't remove thing from surroundings + * * * Transfer a quantity (The required amount of the contained quantity, whichever is lower) of the reagent to the temporary reagents holder + * + * * If it's a stack, create a tally stack and then transfer an amount of the stack to the stack until it reaches the required amount. + * + * * If it's anything else just locate() it in the list in a while loop, for each find reduce the amt var by 1 and put the found stuff in return list + * + * For stacks and items, the material composition is also tallied in total_materials, to be transferred to the result after that is spawned. + * + * get_used_reqs returns the list of used required object the result will receive as argument of atom/CheckParts() + * If one or some of the object types is in the 'parts' list of the recipe, they will be stored inside the contents of the result + * The rest will instead be deleted by atom/CheckParts() +**/ - Loop over reqs var of the recipe - Set var amt to the value current cycle req is pointing to, its amount of type we need to delete - Get var/surroundings list of things accessable to crafting by get_environment() - Check the type of the current cycle req - If its reagent then do a while loop, inside it try to locate() reagent containers, inside such containers try to locate needed reagent, if there isn't remove thing from surroundings - If there is enough reagent in the search result then delete the needed amount, create the same type of reagent with the same data var and put it into deletion list - If there isn't enough take all of that reagent from the container, put into deletion list, substract the amt var by the volume of reagent, remove the container from surroundings list and keep searching - While doing above stuff check deletion list if it already has such reagnet, if yes merge instead of adding second one - If its stack check if it has enough amount - If yes create new stack with the needed amount and put in into deletion list, substract taken amount from the stack - If no put all of the stack in the deletion list, substract its amount from amt and keep searching - While doing above stuff check deletion list if it already has such stack type, if yes try to merge them instead of adding new one - If its anything else just locate() in in the list in a while loop, each find --s the amt var and puts the found stuff in deletion loop - - Then do a loop over parts var of the recipe - Do similar stuff to what we have done above, but now in deletion list, until the parts conditions are satisfied keep taking from the deletion list and putting it into parts list for return - - After its done loop over deletion list and delete all the shit that wasn't taken by parts loop - - del_reqs return the list of parts resulting object will receive as argument of CheckParts proc, on the atom level it will add them all to the contents, on all other levels it calls ..() and does whatever is needed afterwards but from contents list already -*/ - -/datum/component/personal_crafting/proc/del_reqs(datum/crafting_recipe/R, atom/a) - . = list() +/datum/component/personal_crafting/proc/get_used_reqs(datum/crafting_recipe/recipe, atom/atom, list/total_materials = list()) + var/list/return_list = list() var/datum/reagents/holder - var/list/surroundings - var/list/Deletion = list() - var/amt var/list/requirements = list() - if(R.reqs) - requirements += R.reqs - if(R.machinery) - requirements += R.machinery - if(R.structures) - requirements += R.structures - main_loop: - for(var/path_key in requirements) - amt = R.reqs?[path_key] || R.machinery?[path_key] || R.structures?[path_key] - if(!amt)//since machinery & structures can have 0 aka CRAFTING_MACHINERY_USE - i.e. use it, don't consume it! - continue main_loop - surroundings = get_environment(a, R.blacklist) - surroundings -= Deletion - if(ispath(path_key, /datum/reagent)) - while(amt > 0) - var/obj/item/reagent_containers/RC = locate() in surroundings - if(isnull(RC)) //not found - break - if(QDELING(RC)) //deleting so is unusable - surroundings -= RC - continue + if(recipe.reqs) + requirements += recipe.reqs + if(recipe.machinery) + requirements += recipe.machinery + if(recipe.structures) + requirements += recipe.structures - var/reagent_volume = RC.reagents.get_reagent_amount(path_key) - if(reagent_volume) - if(!holder) - holder = new(INFINITY, NO_REACT) //an infinite volume holder than can store reagents without reacting - . += holder - if(reagent_volume >= amt) - RC.reagents.trans_to(holder, amt, target_id = path_key, no_react = TRUE) - continue main_loop - else - RC.reagents.trans_to(holder, reagent_volume, target_id = path_key, no_react = TRUE) - surroundings -= RC - amt -= reagent_volume - else - surroundings -= RC - RC.update_appearance(UPDATE_ICON) - else if(ispath(path_key, /obj/item/stack)) - var/obj/item/stack/S - var/obj/item/stack/SD - while(amt > 0) - S = locate(path_key) in surroundings - if(S.amount >= amt) - if(!locate(S.type) in Deletion) - SD = new S.type() - Deletion += SD - S.use(amt) - SD = SD || locate(S.type) in Deletion // SD might be already set here, no sense in searching for it again - SD.amount += amt - continue main_loop - else - amt -= S.amount - if(!locate(S.type) in Deletion) - Deletion += S - else - SD = SD || locate(S.type) in Deletion - SD.add(S.amount) // add the amount to our tally stack, SD - qdel(S) // We can just delete it straight away as it's going to be fully consumed anyway, saving some overhead from calling use() - surroundings -= S - else - var/atom/movable/I - while(amt > 0) - I = locate(path_key) in surroundings - Deletion += I - surroundings -= I - amt-- - var/list/partlist = list(R.parts.len) - for(var/M in R.parts) - partlist[M] = R.parts[M] - for(var/part in R.parts) - if(istype(part, /datum/reagent)) - var/datum/reagent/RG = locate(part) in Deletion - if(RG.volume > partlist[part]) - RG.volume = partlist[part] - . += RG - Deletion -= RG - continue - else if(isstack(part)) - var/obj/item/stack/ST = locate(part) in Deletion - if(ST.amount > partlist[part]) - ST.amount = partlist[part] - . += ST - Deletion -= ST + for(var/path_key in requirements) + var/list/surroundings + var/amount = recipe.reqs?[path_key] || recipe.machinery?[path_key] || recipe.structures?[path_key] + if(!amount)//since machinery & structures can have 0 aka CRAFTING_MACHINERY_USE - i.e. use it, don't consume it! continue + surroundings = get_environment(atom, recipe.blacklist) + surroundings -= return_list + if(ispath(path_key, /datum/reagent)) + if(!holder) + holder = new(INFINITY, NO_REACT) //an infinite volume holder than can store reagents without reacting + return_list += holder + while(amount > 0) + var/obj/item/reagent_containers/container = locate() in surroundings + if(isnull(container)) //This would only happen if the previous checks for contents and tools were flawed. + stack_trace("couldn't fulfill the required amount for [path_key]. Dangit") + if(QDELING(container)) //it's deleting... + surroundings -= container + continue + var/reagent_volume = container.reagents.get_reagent_amount(path_key) + if(reagent_volume) + container.reagents.trans_to(holder, min(amount, reagent_volume), target_id = path_key, no_react = TRUE) + amount -= reagent_volume + surroundings -= container + container.update_appearance(UPDATE_ICON) + else if(ispath(path_key, /obj/item/stack)) + var/obj/item/stack/tally_stack + while(amount > 0) + var/obj/item/stack/origin_stack = locate(path_key) in surroundings + if(isnull(origin_stack)) //This would only happen if the previous checks for contents and tools were flawed. + stack_trace("couldn't fulfill the required amount for [path_key]. Dangit") + if(QDELING(origin_stack)) + continue + var/amount_to_give = min(origin_stack.amount, amount) + if(!tally_stack) + tally_stack = origin_stack.split_stack(amount = amount_to_give) + return_list += tally_stack + else + origin_stack.merge(tally_stack, amount_to_give) + amount -= amount_to_give + surroundings -= origin_stack + if(!(path_key in recipe.requirements_mats_blacklist)) + for(var/material in tally_stack.custom_materials) + total_materials[material] += tally_stack.custom_materials[material] else - while(partlist[part] > 0) - var/atom/movable/AM = locate(part) in Deletion - . += AM - Deletion -= AM - partlist[part] -= 1 - while(Deletion.len) - var/DL = Deletion[Deletion.len] - Deletion.Cut(Deletion.len) - // Snowflake handling of reagent containers, storage atoms, and structures with contents. - // If we consumed them in our crafting, we should dump their contents out before qdeling them. - if(is_reagent_container(DL)) - var/obj/item/reagent_containers/container = DL - container.reagents.expose(container.loc, TOUCH) - else if(istype(DL, /obj/item/storage)) - var/obj/item/storage/container = DL - container.emptyStorage() - else if(isstructure(DL)) - var/obj/structure/structure = DL - structure.dump_contents(structure.drop_location()) - qdel(DL) + while(amount > 0) + var/atom/movable/item = locate(path_key) in surroundings + if(isnull(item)) //This would only happen if the previous checks for contents and tools were flawed. + stack_trace("couldn't fulfill the required amount for [path_key]. Dangit") + if(QDELING(item)) + continue + return_list += item + surroundings -= item + amount-- + if(!(path_key in recipe.requirements_mats_blacklist)) + for(var/material in item.custom_materials) + total_materials[material] += item.custom_materials[material] + + return return_list /datum/component/personal_crafting/proc/is_recipe_available(datum/crafting_recipe/recipe, mob/user) if((recipe.crafting_flags & CRAFT_MUST_BE_LEARNED) && !(recipe.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this. @@ -541,17 +530,17 @@ return data /datum/component/personal_crafting/proc/make_action(datum/crafting_recipe/recipe, mob/user) - var/atom/movable/result = construct_item(user, recipe) + var/atom/result = construct_item(user, recipe) if(istext(result)) //We failed to make an item and got a fail message to_chat(user, span_warning("Construction failed[result]")) return FALSE if(ismob(user) && isitem(result)) //In case the user is actually possessing a non mob like a machine user.put_in_hands(result) - else if(!istype(result, /obj/effect/spawner)) - result.forceMove(user.drop_location()) + else if(ismovable(result) && !istype(result, /obj/effect/spawner)) + var/atom/movable/movable = result + movable.forceMove(user.drop_location()) to_chat(user, span_notice("[recipe.name] crafted.")) user.investigate_log("crafted [recipe]", INVESTIGATE_CRAFTING) - recipe.on_craft_completion(user, result) return TRUE @@ -723,7 +712,7 @@ return FALSE /datum/component/personal_crafting/machine - ignored_flags = CRAFT_CHECK_DENSITY + ignored_flags = CRAFT_CHECK_DENSITY|CRAFT_IGNORE_DO_AFTER /datum/component/personal_crafting/machine/get_environment(atom/crafter, list/blacklist = null, radius_range = 1) . = list() @@ -737,5 +726,11 @@ continue . += content -/datum/component/personal_crafting/machine/check_tools(atom/source, datum/crafting_recipe/recipe, list/surroundings) +/datum/component/personal_crafting/machine/check_tools(atom/source, datum/crafting_recipe/recipe, list/surroundings, final_check = FALSE) return TRUE + +#undef CONTENTS_INSTANCES +#undef CONTENTS_MACHINERY +#undef CONTENTS_STRUCTURES +#undef CONTENTS_REAGENTS +#undef CONTENTS_TOOL_BEHAVIOUR diff --git a/code/datums/components/crafting/entertainment.dm b/code/datums/components/crafting/entertainment.dm index 42dfd43f13b..486551f1e30 100644 --- a/code/datums/components/crafting/entertainment.dm +++ b/code/datums/components/crafting/entertainment.dm @@ -6,7 +6,6 @@ /obj/item/stack/sheet/animalhide/mothroach = 2, /obj/item/clothing/shoes/clown_shoes = 1, ) - parts = list(/obj/item/clothing/shoes/clown_shoes = 1) blacklist = list( /obj/item/clothing/shoes/clown_shoes/combat, /obj/item/clothing/shoes/clown_shoes/banana_shoes, @@ -83,7 +82,6 @@ /obj/item/camera = 1, /datum/reagent/water/holywater = 10, ) - parts = list(/obj/item/camera = 1) category = CAT_ENTERTAINMENT @@ -186,7 +184,7 @@ category = CAT_ENTERTAINMENT tool_behaviors = list(TOOL_WRENCH) reqs = list(/obj/item/flamethrower = 1) - structures = list(/obj/structure/toilet = CRAFTING_STRUCTURE_USE) // we will handle the consumption manually in on_craft_completion for this one + structures = list(/obj/structure/toilet = CRAFTING_STRUCTURE_CONSUME) result = /obj/structure/toiletbong time = 5 SECONDS steps = list( @@ -199,21 +197,6 @@ return FALSE return ..() -/datum/crafting_recipe/toiletbong/on_craft_completion(mob/user, atom/result) - var/obj/structure/toiletbong/toiletbong = result - - // because we want to set the toilet's location and dir, we need to do the consumption manually - var/obj/structure/toilet/toilet = locate(/obj/structure/toilet) in range(1) - if(toilet) - for (var/obj/item/cistern_item in toilet.contents) - cistern_item.forceMove(user.drop_location()) - to_chat(user, span_warning("[cistern_item] falls out of the toilet!")) - toiletbong.dir = toilet.dir - toiletbong.loc = toilet.loc - qdel(toilet) - - to_chat(user, span_notice("[user] attaches the flamethrower to the repurposed toilet.")) - /datum/crafting_recipe/punching_bag name = "Punching Bag" result = /obj/structure/punching_bag diff --git a/code/datums/components/crafting/equipment.dm b/code/datums/components/crafting/equipment.dm index 81f395303b0..0255818e907 100644 --- a/code/datums/components/crafting/equipment.dm +++ b/code/datums/components/crafting/equipment.dm @@ -72,8 +72,6 @@ /obj/item/stock_parts/power_store/cell = 1, ) parts = list( - /obj/item/stock_parts/servo = 2, - /obj/item/stock_parts/capacitor = 1, /obj/item/stock_parts/power_store/cell = 1, ) tool_behaviors = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WRENCH) @@ -88,9 +86,6 @@ /obj/item/assembly/igniter/condenser = 1, /obj/item/electronics/airlock = 1, ) - parts = list( - /obj/item/electronics/airlock = 1, - ) time = 5 SECONDS category = CAT_EQUIPMENT @@ -112,9 +107,6 @@ /obj/item/stack/sheet/iron = 5, /obj/item/electronics/airlock = 1, ) - parts = list( - /obj/item/electronics/airlock = 1, - ) time = 5 SECONDS category = CAT_EQUIPMENT diff --git a/code/datums/components/crafting/melee_weapon.dm b/code/datums/components/crafting/melee_weapon.dm index 9c817ffa437..9ea3d59ac29 100644 --- a/code/datums/components/crafting/melee_weapon.dm +++ b/code/datums/components/crafting/melee_weapon.dm @@ -98,7 +98,6 @@ /obj/item/shard = 1, /obj/item/stack/rods = 1, ) - parts = list(/obj/item/shard = 1) time = 4 SECONDS category = CAT_WEAPON_MELEE diff --git a/code/datums/components/crafting/ranged_weapon.dm b/code/datums/components/crafting/ranged_weapon.dm index 64205b3d80d..24c391a32aa 100644 --- a/code/datums/components/crafting/ranged_weapon.dm +++ b/code/datums/components/crafting/ranged_weapon.dm @@ -448,7 +448,6 @@ /obj/item/grenade/chem_grenade = 2, /obj/item/assembly/signaler/anomaly/dimensional = 1, ) - parts = list(/obj/item/gibtonite = 1, /obj/item/grenade/chem_grenade = 2) tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WELDER) time = 12 SECONDS category = CAT_WEAPON_RANGED diff --git a/code/datums/components/crafting/robot.dm b/code/datums/components/crafting/robot.dm index 94c1aa979d1..7a2cea7072c 100644 --- a/code/datums/components/crafting/robot.dm +++ b/code/datums/components/crafting/robot.dm @@ -38,7 +38,7 @@ /obj/item/assembly/prox_sensor = 1, /obj/item/bodypart/arm/right/robot = 1, ) - parts = list(/obj/item/reagent_containers/cup/bucket = 1) + parts = list(/obj/item/reagent_containers/cup/bucket = 1) //cleanbot/Entered() handles bucket colors time = 4 SECONDS category = CAT_ROBOT @@ -70,15 +70,6 @@ time = 4 SECONDS category = CAT_ROBOT -/datum/crafting_recipe/medbot/on_craft_completion(mob/user, atom/result) - var/mob/living/basic/bot/medbot/bot = result - var/obj/item/storage/medkit/medkit = bot.contents[3] - bot.medkit_type = medkit - bot.health_analyzer = bot.contents[4] - bot.skin = medkit.get_medbot_skin() - bot.damage_type_healer = initial(medkit.damagetype_healed) ? initial(medkit.damagetype_healed) : BRUTE - bot.update_appearance() - /datum/crafting_recipe/honkbot name = "Honkbot" result = /mob/living/basic/bot/honkbot @@ -151,7 +142,6 @@ /obj/item/food/grown/potato = 1, /obj/item/stack/cable_coil = 5, ) - parts = list(/obj/item/aicard = 1) category = CAT_ROBOT /datum/crafting_recipe/aitater/aispook @@ -163,18 +153,6 @@ /obj/item/stack/cable_coil = 5, ) -/datum/crafting_recipe/aitater/on_craft_completion(mob/user, atom/result) - var/obj/item/aicard/new_card = result - var/obj/item/aicard/base_card = result.contents[1] - var/mob/living/silicon/ai = base_card.AI - - if(ai) - base_card.AI = null - ai.forceMove(new_card) - new_card.AI = ai - new_card.update_appearance() - qdel(base_card) - /datum/crafting_recipe/mod_core_standard name = "MOD core (Standard)" result = /obj/item/mod/core/standard @@ -213,6 +191,5 @@ /obj/item/stack/sheet/glass = 1, /obj/item/soulstone = 1, ) - parts = list(/obj/item/soulstone = 1) category = CAT_ROBOT crafting_flags = parent_type::crafting_flags | CRAFT_MUST_BE_LEARNED diff --git a/code/datums/components/crafting/tools.dm b/code/datums/components/crafting/tools.dm index 10b0352d376..a837a80d3e4 100644 --- a/code/datums/components/crafting/tools.dm +++ b/code/datums/components/crafting/tools.dm @@ -12,7 +12,7 @@ name = "Bonfire" time = 6 SECONDS reqs = list(/obj/item/grown/log = 5) - parts = list(/obj/item/grown/log = 5) + parts = list(/obj/item/grown/log = 5) //Will be returned if the bonfire is dismantled blacklist = list(/obj/item/grown/log/steel) result = /obj/structure/bonfire category = CAT_TOOLS @@ -84,31 +84,29 @@ result = /obj/item/shuttle_blueprints/crude reqs = list( /obj/item/paper = 1, - /obj/item/toy/crayon = CRAFTING_INGREDIENT_USE, ) + tool_paths = list(/obj/item/toy/crayon) + //we can't use a generic crayon so we spawn a blue one + unit_test_spawn_extras = list(/obj/item/toy/crayon/blue = 1) steps = list( "You must use either a a blue crayon, a rainbow crayon, or a spray can.", "The crayon or spray can you use must have at least 10 uses remaining." ) time = 10 SECONDS category = CAT_TOOLS + var/static/list/valid_types = typecacheof(list( + /obj/item/toy/crayon/blue, + /obj/item/toy/crayon/rainbow, + /obj/item/toy/crayon/spraycan, + )) -/datum/crafting_recipe/shuttle_blueprints/check_requirements(mob/user, list/collected_requirements) - var/list/crayons = collected_requirements[/obj/item/toy/crayon] - for(var/obj/item/toy/crayon/crayon as anything in crayons) - if(!is_type_in_list(crayon, list(/obj/item/toy/crayon/blue, /obj/item/toy/crayon/rainbow, /obj/item/toy/crayon/spraycan))) +/datum/crafting_recipe/shuttle_blueprints/check_tools(atom/user, list/collected_tools, final_check = FALSE) + for(var/obj/item/toy/crayon/crayon in collected_tools) + if(!is_type_in_typecache(crayon, valid_types)) continue - if(!crayon.check_empty(user, 10)) + if(final_check ? crayon.use_charges(user, 10) : crayon.check_empty(user, 10)) return TRUE - -/datum/crafting_recipe/shuttle_blueprints/on_craft_completion(mob/user, atom/result) - var/static/list/valid_types = list(/obj/item/toy/crayon/blue, /obj/item/toy/crayon/rainbow, /obj/item/toy/crayon/spraycan) - for(var/valid_type in valid_types) - var/obj/item/toy/crayon/crayon = locate(valid_type) in range(1) - if(!crayon) - continue - if(crayon.use_charges(user, 10)) - return + return FALSE /datum/crafting_recipe/makeshift_radio_jammer name = "Makeshift Radio Jammer" @@ -119,3 +117,4 @@ /obj/item/stack/cable_coil = 5, ) category = CAT_TOOLS + diff --git a/code/datums/components/food/edible.dm b/code/datums/components/food/edible.dm index a5e96335c19..21bb8a49f97 100644 --- a/code/datums/components/food/edible.dm +++ b/code/datums/components/food/edible.dm @@ -76,10 +76,12 @@ Behavior that's still missing from this component that original food items had t /datum/component/edible/RegisterWithParent() RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(examine)) RegisterSignal(parent, COMSIG_ATOM_ATTACK_ANIMAL, PROC_REF(UseByAnimal)) - RegisterSignal(parent, COMSIG_ATOM_CHECKPARTS, PROC_REF(OnCraft)) + RegisterSignal(parent, COMSIG_ATOM_ON_CRAFT, PROC_REF(OnCraft)) RegisterSignal(parent, COMSIG_OOZE_EAT_ATOM, PROC_REF(on_ooze_eat)) RegisterSignal(parent, COMSIG_FOOD_INGREDIENT_ADDED, PROC_REF(edible_ingredient_added)) RegisterSignal(parent, COMSIG_ATOM_CREATEDBY_PROCESSING, PROC_REF(created_by_processing)) + RegisterSignal(parent, COMSIG_ATOM_FINALIZE_MATERIAL_EFFECTS, PROC_REF(on_material_effects)) + RegisterSignal(parent, COMSIG_ATOM_FINALIZE_REMOVE_MATERIAL_EFFECTS, PROC_REF(on_remove_material_effects)) if(isturf(parent)) RegisterSignal(parent, COMSIG_ATOM_ENTERED, PROC_REF(on_entered)) @@ -105,7 +107,7 @@ Behavior that's still missing from this component that original food items had t UnregisterSignal(parent, list( COMSIG_ATOM_ATTACK_ANIMAL, COMSIG_ATOM_ATTACK_HAND, - COMSIG_ATOM_CHECKPARTS, + COMSIG_ATOM_ON_CRAFT, COMSIG_ATOM_CREATEDBY_PROCESSING, COMSIG_ATOM_ENTERED, COMSIG_FOOD_INGREDIENT_ADDED, @@ -333,11 +335,11 @@ Behavior that's still missing from this component that original food items had t this_food.desc = "[original_atom.desc]" ///Called when food is crafted through a crafting recipe datum. -/datum/component/edible/proc/OnCraft(datum/source, list/parts_list, datum/crafting_recipe/food/recipe) +/datum/component/edible/proc/OnCraft(datum/source, list/components, datum/crafting_recipe/food/recipe) SIGNAL_HANDLER var/atom/this_food = parent - for(var/obj/item/food/crafted_part in parts_list) + for(var/obj/item/food/crafted_part in components) if(!crafted_part.reagents) continue this_food.reagents.maximum_volume += crafted_part.reagents.maximum_volume @@ -742,4 +744,19 @@ Behavior that's still missing from this component that original food items had t qdel(food) return COMPONENT_ATOM_EATEN +#define REQUIRED_MAT_FLAGS (MATERIAL_EFFECTS|MATERIAL_NO_EDIBILITY) + +///Calls on_edible_applied() for the main material composing the atom parent +/datum/component/edible/proc/on_material_effects(atom/source, list/materials, datum/material/main_material) + SIGNAL_HANDLER + if((source.material_flags & REQUIRED_MAT_FLAGS) == REQUIRED_MAT_FLAGS) + main_material.on_edible_applied(source, src) + +///Calls on_edible_removed() for the main material no longer composing the atom parent +/datum/component/edible/proc/on_remove_material_effects(atom/source, list/materials, datum/material/main_material) + SIGNAL_HANDLER + if((source.material_flags & REQUIRED_MAT_FLAGS) == REQUIRED_MAT_FLAGS) + main_material.on_edible_removed(source, src) + +#undef REQUIRED_MAT_FLAGS #undef DEFAULT_EDIBLE_VOLUME diff --git a/code/datums/components/grillable.dm b/code/datums/components/grillable.dm index 3b3ef047c83..afa2ea31a0e 100644 --- a/code/datums/components/grillable.dm +++ b/code/datums/components/grillable.dm @@ -139,8 +139,7 @@ else grilled_result = new cook_result(original_object.loc) - if(original_object.custom_materials) - grilled_result.set_custom_materials(original_object.custom_materials) + grilled_result.set_custom_materials(original_object.custom_materials) if(IsEdible(grilled_result) && positive_result) BLACKBOX_LOG_FOOD_MADE(grilled_result.type) diff --git a/code/datums/components/customizable_reagent_holder.dm b/code/datums/components/ingredients_holder.dm similarity index 55% rename from code/datums/components/customizable_reagent_holder.dm rename to code/datums/components/ingredients_holder.dm index e82633e62b1..f67de7bb76a 100644 --- a/code/datums/components/customizable_reagent_holder.dm +++ b/code/datums/components/ingredients_holder.dm @@ -2,16 +2,14 @@ * # Custom Atom Component * * When added to an atom, item ingredients can be put into that. - * The sprite is updated and reagents are transferred. + * The sprite is updated and reagents and custom materials are transferred. * * If the component is added to something that is processed, creating new objects (being cut, for example), * the replacement type needs to also have the component. The ingredients will be copied over. Reagents are not * copied over since other components already take care of that. */ -/datum/component/customizable_reagent_holder +/datum/component/ingredients_holder can_transfer = TRUE - ///List of item ingredients. - var/list/obj/item/ingredients ///Type path of replacement atom. var/replacement ///Type of fill, can be [CUSTOM_INGREDIENT_ICON_NOCHANGE] for example. @@ -25,12 +23,19 @@ /// Adds screentips for all items that call on this proc, defaults to "Add" var/screentip_verb -/datum/component/customizable_reagent_holder/Initialize( + /// Stores the names of the ingredients used on the holder, to pass down if processed into new instances. + var/list/ingredient_names + ///List of colors to be used for fillings, to pass down if processed into new instances. + var/list/filling_colors + /// The custom name attached to the original name of the holder, to pass down if processed into new instances. + var/custom_name + +/datum/component/ingredients_holder/Initialize( atom/replacement, fill_type, ingredient_type = CUSTOM_INGREDIENT_TYPE_EDIBLE, max_ingredients = MAX_ATOM_OVERLAYS - 3, // The cap is >= MAX_ATOM_OVERLAYS so we reserve 2 for top /bottom of item + 1 to stay under cap - list/obj/item/initial_ingredients = null, + datum/component/ingredients_holder/processed_holder, //when processing a holder, the results receive their own comps, but need the ingredient names and filling passed down screentip_verb = "Add", ) if(!isatom(parent)) @@ -48,30 +53,29 @@ src.ingredient_type = ingredient_type src.screentip_verb = screentip_verb - if (initial_ingredients) - for (var/_ingredient in initial_ingredients) - var/obj/item/ingredient = _ingredient - add_ingredient(ingredient) - handle_fill(ingredient) + if(!processed_holder || !length(processed_holder.ingredient_names)) + return + ingredient_names = processed_holder.ingredient_names + custom_name = processed_holder.custom_name + atom_parent.name = "[custom_adjective()] [custom_name] [atom_parent.name]" + for(var/fillcol as anything in processed_holder.filling_colors) + apply_fill(fillcol) -/datum/component/customizable_reagent_holder/Destroy(force) +/datum/component/ingredients_holder/Destroy(force) QDEL_NULL(top_overlay) - LAZYCLEARLIST(ingredients) return ..() - -/datum/component/customizable_reagent_holder/RegisterWithParent() +/datum/component/ingredients_holder/RegisterWithParent() . = ..() RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(customizable_attack)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) RegisterSignal(parent, COMSIG_ATOM_EXITED, PROC_REF(food_exited)) RegisterSignal(parent, COMSIG_ATOM_PROCESSED, PROC_REF(on_processed)) RegisterSignal(parent, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item)) - ADD_TRAIT(parent, TRAIT_CUSTOMIZABLE_REAGENT_HOLDER, REF(src)) + ADD_TRAIT(parent, TRAIT_INGREDIENTS_HOLDER, INNATE_TRAIT) - -/datum/component/customizable_reagent_holder/UnregisterFromParent() +/datum/component/ingredients_holder/UnregisterFromParent() . = ..() UnregisterSignal(parent, list( COMSIG_ATOM_ATTACKBY, @@ -80,9 +84,9 @@ COMSIG_ATOM_PROCESSED, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, )) - REMOVE_TRAIT(parent, TRAIT_CUSTOMIZABLE_REAGENT_HOLDER, REF(src)) + REMOVE_TRAIT(parent, TRAIT_INGREDIENTS_HOLDER, INNATE_TRAIT) -/datum/component/customizable_reagent_holder/PostTransfer(datum/new_parent) +/datum/component/ingredients_holder/PostTransfer(datum/new_parent) if(!isatom(new_parent)) return COMPONENT_INCOMPATIBLE var/atom/atom_parent = new_parent @@ -90,21 +94,18 @@ return COMPONENT_INCOMPATIBLE ///Handles when the customizable food is examined. -/datum/component/customizable_reagent_holder/proc/on_examine(atom/A, mob/user, list/examine_list) +/datum/component/ingredients_holder/proc/on_examine(atom/A, mob/user, list/examine_list) SIGNAL_HANDLER var/atom/atom_parent = parent - var/list/ingredients_listed = list() - for(var/obj/item/ingredient as anything in ingredients) - ingredients_listed += "\a [ingredient.name]" - examine_list += "It [LAZYLEN(ingredients) \ - ? "contains [english_list(ingredients_listed)] making a [custom_adjective()]-sized [initial(atom_parent.name)]" \ + examine_list += "It [LAZYLEN(ingredient_names) \ + ? "contains [english_list(ingredient_names)] making a [custom_adjective()]-sized [initial(atom_parent.name)]" \ : "does not contain any ingredients"]." //// Proc that checks if an ingredient is valid or not, returning false if it isnt and true if it is. -/datum/component/customizable_reagent_holder/proc/valid_ingredient(obj/ingredient) - if (HAS_TRAIT(ingredient, TRAIT_CUSTOMIZABLE_REAGENT_HOLDER)) +/datum/component/ingredients_holder/proc/valid_ingredient(obj/ingredient) + if (HAS_TRAIT(ingredient, TRAIT_INGREDIENTS_HOLDER)) return FALSE if(HAS_TRAIT(ingredient, TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT)) return TRUE @@ -116,7 +117,7 @@ return TRUE ///Handles when the customizable food is attacked by something. -/datum/component/customizable_reagent_holder/proc/customizable_attack(datum/source, obj/ingredient, mob/attacker, silent = FALSE, force = FALSE) +/datum/component/ingredients_holder/proc/customizable_attack(datum/source, obj/ingredient, mob/attacker, silent = FALSE, force = FALSE) SIGNAL_HANDLER if (!valid_ingredient(ingredient)) @@ -126,38 +127,34 @@ attacker.balloon_alert(attacker, "doesn't go on that!") return - if (LAZYLEN(ingredients) >= max_ingredients) + if (LAZYLEN(ingredient_names) >= max_ingredients) attacker.balloon_alert(attacker, "too full!") return COMPONENT_NO_AFTERATTACK - var/atom/atom_parent = parent - if(!attacker.transferItemToLoc(ingredient, atom_parent)) + if(!attacker.transferItemToLoc(ingredient, parent)) return - if (replacement) - var/atom/replacement_parent = new replacement(atom_parent.drop_location()) - ingredient.forceMove(replacement_parent) - replacement = null - replacement_parent.TakeComponent(src) - handle_reagents(atom_parent) - qdel(atom_parent) - handle_reagents(ingredient) add_ingredient(ingredient) - handle_fill(ingredient) -///Handles the icon update for a new ingredient. -/datum/component/customizable_reagent_holder/proc/handle_fill(obj/item/ingredient) - if (fill_type == CUSTOM_INGREDIENT_ICON_NOCHANGE) +///Extract the filling color from the ingredient, than calls apply_fill() +/datum/component/ingredients_holder/proc/get_fill(obj/item/ingredient) + // get average color + var/icon/icon = new(ingredient.icon, ingredient.icon_state) + if(ingredient.color) + icon.Blend(ingredient.color, ICON_MULTIPLY) + icon.Scale(1, 1) + var/fillcol = copytext(icon.GetPixel(1, 1), 1, 8) // remove opacity + LAZYADD(filling_colors, fillcol) + apply_fill(fillcol) + +///Add a filling overlay to the parent atom. +/datum/component/ingredients_holder/proc/apply_fill(fill_color) + if(fill_type == CUSTOM_INGREDIENT_ICON_NOCHANGE) //don't bother doing the icon procs return var/atom/atom_parent = parent var/mutable_appearance/filling = mutable_appearance(atom_parent.icon, "[initial(atom_parent.icon_state)]_filling") - // get average color - var/icon/icon = new(ingredient.icon, ingredient.icon_state) - icon.Scale(1, 1) - var/fillcol = copytext(icon.GetPixel(1, 1), 1, 8) // remove opacity - filling.color = fillcol - + filling.color = fill_color switch(fill_type) if(CUSTOM_INGREDIENT_ICON_SCATTER) filling.pixel_w = rand(-1,1) @@ -165,18 +162,18 @@ if(CUSTOM_INGREDIENT_ICON_STACK) filling.pixel_w = rand(-1,1) // we're gonna abuse position layering to ensure overlays render right - filling.pixel_y = -LAZYLEN(ingredients) - filling.pixel_z = 2 * LAZYLEN(ingredients) - 1 + LAZYLEN(ingredients) + filling.pixel_y = -LAZYLEN(ingredient_names) + filling.pixel_z = 3 * LAZYLEN(ingredient_names) - 1 if(CUSTOM_INGREDIENT_ICON_STACKPLUSTOP) filling.pixel_w = rand(-1,1) // similar here - filling.pixel_y = -LAZYLEN(ingredients) - filling.pixel_z = 2 * LAZYLEN(ingredients) - 1 + LAZYLEN(ingredients) + filling.pixel_y = -LAZYLEN(ingredient_names) + filling.pixel_z = 3 * LAZYLEN(ingredient_names) - 1 if (top_overlay) // delete old top if exists atom_parent.cut_overlay(top_overlay) top_overlay = mutable_appearance(atom_parent.icon, "[atom_parent.icon_state]_top") - top_overlay.pixel_y = -(LAZYLEN(ingredients) + 1) - top_overlay.pixel_z = 2 * LAZYLEN(ingredients) + 3 + LAZYLEN(ingredients) + 1 + top_overlay.pixel_y = -LAZYLEN(ingredient_names) - 1 + top_overlay.pixel_z = 3 * LAZYLEN(ingredient_names) + 4 atom_parent.add_overlay(filling) atom_parent.add_overlay(top_overlay) return @@ -191,7 +188,7 @@ ///Takes the reagents from an ingredient. -/datum/component/customizable_reagent_holder/proc/handle_reagents(obj/item/ingredient) +/datum/component/ingredients_holder/proc/handle_reagents(obj/item/ingredient) var/atom/atom_parent = parent if (atom_parent.reagents && ingredient.reagents) atom_parent.reagents.maximum_volume += ingredient.reagents.maximum_volume // If we don't do this custom food starts voiding reagents past a certain point. @@ -200,21 +197,50 @@ ///Adds a new ingredient and updates the parent's name. -/datum/component/customizable_reagent_holder/proc/add_ingredient(obj/item/ingredient) +/datum/component/ingredients_holder/proc/add_ingredient(obj/item/ingredient) var/atom/atom_parent = parent - LAZYADD(ingredients, ingredient) + + if (replacement) + var/atom/replacement_parent = new replacement(atom_parent.drop_location()) + ingredient.forceMove(replacement_parent) + replacement = null + replacement_parent.TakeComponent(src) + atom_parent = parent + handle_reagents(atom_parent) + qdel(atom_parent) + + handle_reagents(ingredient) + + LAZYADD(ingredient_names, "\a [ingredient.name]") if(isitem(atom_parent)) var/obj/item/item_parent = atom_parent if(ingredient.w_class > item_parent.w_class) item_parent.update_weight_class(ingredient.w_class) - atom_parent.name = "[custom_adjective()] [custom_type()] [initial(atom_parent.name)]" + if(!custom_name) + set_custom_name(ingredient) + atom_parent.name = "[custom_adjective()] [custom_name] [initial(atom_parent.name)]" SEND_SIGNAL(atom_parent, COMSIG_ATOM_CUSTOMIZED, ingredient) SEND_SIGNAL(ingredient, COMSIG_ITEM_USED_AS_INGREDIENT, atom_parent) + get_fill(ingredient) + handle_materials(ingredient) + + if(ingredient.loc != atom_parent) + ingredient.forceMove(atom_parent) + +///Rebuilds the custom materials the holder is composed of based on the materials of each ingredient +/datum/component/ingredients_holder/proc/handle_materials(obj/item/ingredient, remove = FALSE) + if(!ingredient.custom_materials) + return + var/atom/atom_parent = parent + var/list/new_materials = atom_parent.custom_materials?.Copy() || list() + for(var/mat in ingredient.custom_materials) + new_materials[mat] += ingredient.custom_materials[mat] * (remove ? -1 : 1) + atom_parent.set_custom_materials(new_materials) ///Gives an adjective to describe the size of the custom food. -/datum/component/customizable_reagent_holder/proc/custom_adjective() - switch(LAZYLEN(ingredients)) +/datum/component/ingredients_holder/proc/custom_adjective() + switch(LAZYLEN(ingredient_names)) if (0 to 2) return "small" if (3 to 5) @@ -228,44 +254,39 @@ ///Gives the type of custom food (based on what the first ingredient was). -/datum/component/customizable_reagent_holder/proc/custom_type() - var/custom_type = "empty" - if (LAZYLEN(ingredients)) - var/obj/item/first_ingredient = ingredients[1] - if (istype(first_ingredient, /obj/item/food/meat)) - var/obj/item/food/meat/meat = first_ingredient - if (meat.subjectname) - custom_type = meat.subjectname - else if (meat.subjectjob) - custom_type = meat.subjectjob - if (custom_type == "empty" && first_ingredient.name) - custom_type = first_ingredient.name - return custom_type - +/datum/component/ingredients_holder/proc/set_custom_name(obj/item/ingredient) + if (istype(ingredient, /obj/item/food/meat)) + var/obj/item/food/meat/meat = ingredient + if (meat.subjectname) + custom_name = meat.subjectname + return + if (meat.subjectjob) + custom_name = meat.subjectjob + return + custom_name = ingredient.name ///Returns the color of the input mixed with the top_overlay's color. -/datum/component/customizable_reagent_holder/proc/mix_color(color) - if(LAZYLEN(ingredients) == 1 || !top_overlay) +/datum/component/ingredients_holder/proc/mix_color(color) + if(length(filling_colors) == 1 || !top_overlay) return color - else - var/list/rgbcolor = list(0,0,0,0) - var/customcolor = GetColors(color) - var/ingcolor = GetColors(top_overlay.color) - rgbcolor[1] = (customcolor[1]+ingcolor[1])/2 - rgbcolor[2] = (customcolor[2]+ingcolor[2])/2 - rgbcolor[3] = (customcolor[3]+ingcolor[3])/2 - rgbcolor[4] = (customcolor[4]+ingcolor[4])/2 - return rgb(rgbcolor[1], rgbcolor[2], rgbcolor[3], rgbcolor[4]) + var/list/rgbcolor = list(0,0,0,0) + var/customcolor = GetColors(color) + var/ingcolor = GetColors(top_overlay.color) + rgbcolor[1] = (customcolor[1]+ingcolor[1])/2 + rgbcolor[2] = (customcolor[2]+ingcolor[2])/2 + rgbcolor[3] = (customcolor[3]+ingcolor[3])/2 + rgbcolor[4] = (customcolor[4]+ingcolor[4])/2 + return rgb(rgbcolor[1], rgbcolor[2], rgbcolor[3], rgbcolor[4]) -///Copies over the parent's ingredients to the processing results (such as slices when the parent is cut). -/datum/component/customizable_reagent_holder/proc/on_processed(datum/source, mob/living/user, obj/item/ingredient, list/atom/results) +///Copies over the parent's fillings and name of ingredients to the processing results (such as slices when the parent is cut). +/datum/component/ingredients_holder/proc/on_processed(datum/source, mob/living/user, obj/item/ingredient, list/atom/results) SIGNAL_HANDLER - // Reagents are not transferred since that should be handled elsewhere. - for (var/r in results) - var/atom/result = r - result.AddComponent(/datum/component/customizable_reagent_holder, null, fill_type, ingredient_type = ingredient_type, max_ingredients = max_ingredients, initial_ingredients = ingredients) + // Reagents are not transferred since that should be handled elsewhere + // while custom materials are already transferred evenly between results by atom/proc/StartProcessingAtom() + for (var/atom/result as anything in results) + result.AddComponent(/datum/component/ingredients_holder, null, fill_type, ingredient_type = ingredient_type, max_ingredients = max_ingredients, processed_holder = src) /** * Adds context sensitivy directly to the customizable reagent holder file for screentips @@ -275,7 +296,7 @@ * * held_item - refers to the item in your hand, which is hopefully an ingredient * * user - refers to user who will see the screentip when the proper context and tool are there */ -/datum/component/customizable_reagent_holder/proc/on_requesting_context_from_item(datum/source, list/context, obj/item/held_item, mob/user) +/datum/component/ingredients_holder/proc/on_requesting_context_from_item(datum/source, list/context, obj/item/held_item, mob/user) SIGNAL_HANDLER // only accept valid ingredients @@ -287,6 +308,7 @@ return CONTEXTUAL_SCREENTIP_SET /// Clear refs if our food "goes away" somehow -/datum/component/customizable_reagent_holder/proc/food_exited(datum/source, atom/movable/gone) +/datum/component/ingredients_holder/proc/food_exited(datum/source, atom/movable/gone) SIGNAL_HANDLER - LAZYREMOVE(ingredients, gone) + LAZYREMOVE(ingredient_names, "\a [gone.name]") + handle_materials(gone, remove = TRUE) diff --git a/code/datums/components/storm_hating.dm b/code/datums/components/storm_hating.dm index 4060dc09a5e..896c9cd471a 100644 --- a/code/datums/components/storm_hating.dm +++ b/code/datums/components/storm_hating.dm @@ -22,9 +22,10 @@ /datum/component/storm_hating/UnregisterFromParent() . = ..() - on_area_exited(parent, get_area(parent)) - UnregisterSignal(parent, COMSIG_ENTER_AREA) - RegisterSignal(parent, COMSIG_EXIT_AREA) + UnregisterSignal(parent, list(COMSIG_ENTER_AREA, COMSIG_EXIT_AREA)) + var/area/old_area = get_area(parent) + if(old_area) + on_area_exited(parent, old_area) /datum/component/storm_hating/proc/on_area_entered(atom/source, area/new_area) SIGNAL_HANDLER diff --git a/code/datums/elements/dryable.dm b/code/datums/elements/dryable.dm index 583c74764ee..16c5a8c1a5d 100644 --- a/code/datums/elements/dryable.dm +++ b/code/datums/elements/dryable.dm @@ -38,18 +38,15 @@ apply_dried_status(resulting_atom, drying_user) qdel(source) return - else if(istype(source, /obj/item/food) && ispath(dry_result, /obj/item/food)) + + var/obj/item/food/resulting_atom = new dry_result(source.loc) + if(istype(source, /obj/item/food) && ispath(dry_result, /obj/item/food)) var/obj/item/food/source_food = source - var/obj/item/food/resulting_food = new dry_result(source.loc) - resulting_food.reagents.clear_reagents() - source_food.reagents.trans_to(resulting_food, source_food.reagents.total_volume) - apply_dried_status(resulting_food, drying_user) - qdel(source) - return - else - var/atom/movable/resulting_atom = new dry_result(source.loc) - apply_dried_status(resulting_atom, drying_user) - qdel(source) + resulting_atom.reagents.clear_reagents() + source_food.reagents.trans_to(resulting_atom, source_food.reagents.total_volume) + resulting_atom.set_custom_materials(source.custom_materials) + apply_dried_status(resulting_atom, drying_user) + qdel(source) /datum/element/dryable/proc/apply_dried_status(atom/target, datum/weakref/drying_user) ADD_TRAIT(target, TRAIT_DRIED, ELEMENT_TRAIT(type)) diff --git a/code/datums/elements/elevation.dm b/code/datums/elements/elevation.dm index ad19d52ab18..ad98c055e0d 100644 --- a/code/datums/elements/elevation.dm +++ b/code/datums/elements/elevation.dm @@ -1,5 +1,5 @@ /** - * Manages the elevation of the turf the source is on (can be the turf itself) + * Manages the elevation of the turf the source is on * The atom with the highest pixel_shift gets to set the elevation of the turf to that value. */ /datum/element/elevation @@ -10,24 +10,17 @@ /datum/element/elevation/Attach(datum/target, pixel_shift) . = ..() - if(!isatom(target) || isarea(target)) + if(!ismovable(target)) return ELEMENT_INCOMPATIBLE ADD_TRAIT(target, TRAIT_ELEVATING_OBJECT, ref(src)) src.pixel_shift = pixel_shift - if(ismovable(target)) - RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) + RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) var/atom/atom_target = target - if(isturf(atom_target.loc)) - var/turf/turf = atom_target.loc - if(!HAS_TRAIT(turf, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift))) - RegisterSignal(turf, COMSIG_TURF_RESET_ELEVATION, PROC_REF(check_elevation)) - RegisterSignal(turf, COMSIG_TURF_CHANGE, PROC_REF(pre_change_turf)) - reset_elevation(turf) - ADD_TRAIT(turf, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift), ref(target)) + register_turf(atom_target, atom_target.loc) /datum/element/elevation/Detach(atom/movable/source) unregister_turf(source, source.loc) @@ -53,12 +46,16 @@ /datum/element/elevation/proc/on_moved(atom/movable/source, atom/oldloc) SIGNAL_HANDLER unregister_turf(source, oldloc) - if(isturf(source.loc)) - if(!HAS_TRAIT(source.loc, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift))) - RegisterSignal(source.loc, COMSIG_TURF_RESET_ELEVATION, PROC_REF(check_elevation)) - RegisterSignal(source.loc, COMSIG_TURF_CHANGE, PROC_REF(pre_change_turf)) - reset_elevation(source.loc) - ADD_TRAIT(source.loc, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift), ref(source)) + register_turf(source, source.loc) + +/datum/element/elevation/proc/register_turf(atom/movable/source, atom/location) + if(!isturf(location)) + return + if(!HAS_TRAIT(location, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift))) + RegisterSignal(location, COMSIG_TURF_RESET_ELEVATION, PROC_REF(check_elevation)) + RegisterSignal(location, COMSIG_TURF_CHANGE, PROC_REF(pre_change_turf)) + reset_elevation(location) + ADD_TRAIT(location, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift), ref(source)) /datum/element/elevation/proc/unregister_turf(atom/movable/source, atom/location) if(!isturf(location)) diff --git a/code/datums/elements/food/microwavable.dm b/code/datums/elements/food/microwavable.dm index 5fdd4c084ad..94267a876c4 100644 --- a/code/datums/elements/food/microwavable.dm +++ b/code/datums/elements/food/microwavable.dm @@ -41,6 +41,7 @@ result = new result_typepath(result_loc, stack_source.amount) else result = new result_typepath(result_loc) + result.set_custom_materials(source.custom_materials) var/efficiency = istype(used_microwave) ? used_microwave.efficiency : 1 SEND_SIGNAL(result, COMSIG_ITEM_MICROWAVE_COOKED, source, efficiency) diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm index 58b2817e94f..3a1c376c838 100644 --- a/code/datums/materials/_material.dm +++ b/code/datums/materials/_material.dm @@ -152,6 +152,14 @@ Simple datum which is instanced once per type and is used for every object of sa if(beauty_modifier >= 0.15 && HAS_TRAIT(source, TRAIT_FISHING_BAIT)) source.RemoveElement(/datum/element/shiny_bait) +////Called in `/datum/component/edible/proc/on_material_effects` +/datum/material/proc/on_edible_applied(atom/source, datum/component/edible/edible) + return + +////Called in `/datum/component/edible/proc/on_remove_material_effects` +/datum/material/proc/on_edible_removed(atom/source, datum/component/edible/edible) + return + /** * This proc is called when the mat is found in an item that's consumed by accident. see /obj/item/proc/on_accidental_consumption. * Arguments diff --git a/code/datums/materials/meat.dm b/code/datums/materials/meat.dm index 7eeb88144e5..b5c2f5e4bef 100644 --- a/code/datums/materials/meat.dm +++ b/code/datums/materials/meat.dm @@ -28,8 +28,7 @@ /datum/material/meat/on_main_applied(atom/source, mat_amount, multiplier) . = ..() - if(!IS_EDIBLE(source)) - make_edible(source, mat_amount, multiplier) + make_edible(source, mat_amount, multiplier) ADD_TRAIT(source, TRAIT_ROD_REMOVE_FISHING_DUD, REF(src)) //The rod itself is the bait... sorta. /datum/material/meat/on_applied(atom/source, mat_amount, multiplier) @@ -37,21 +36,44 @@ if(IS_EDIBLE(source)) make_edible(source, mat_amount, multiplier) +/datum/material/meat/on_edible_applied(atom/source, datum/component/edible/edible) + source.reagents.convert_reagent(/datum/reagent/consumable/nutriment, /datum/reagent/consumable/nutriment/protein, keep_data = TRUE) + var/datum/reagent/meaty_chem = source.reagents.has_reagent(/datum/reagent/consumable/nutriment/protein) + if(meaty_chem) + LAZYSET(meaty_chem.data, "meat", length(meaty_chem.data) || 1) //adds meatiness to its tastes + source.reagents.convert_reagent(/datum/reagent/consumable/nutriment/fat/oil, /datum/reagent/consumable/nutriment/fat, include_source_subtypes = TRUE, keep_data = TRUE) + meaty_chem = source.reagents.has_reagent(/datum/reagent/consumable/nutriment/fat) + if(meaty_chem) + LAZYSET(meaty_chem.data, "meat", length(meaty_chem.data) || 1) //adds meatiness to its tastes + source.AddComponentFrom(SOURCE_EDIBLE_MEAT_MAT, /datum/component/edible, foodtypes = MEAT) + +/datum/material/meat/on_edible_removed(atom/source, datum/component/edible/edible) + source.reagents.convert_reagent(/datum/reagent/consumable/nutriment/protein, /datum/reagent/consumable/nutriment, keep_data = TRUE) + var/datum/reagent/unmeaty_chem = source.reagents.has_reagent(/datum/reagent/consumable/nutriment) + if(unmeaty_chem) + LAZYREMOVE(unmeaty_chem.data, "meat") + source.reagents.convert_reagent(/datum/reagent/consumable/nutriment/fat, /datum/reagent/consumable/nutriment/fat/oil, keep_data = TRUE) + unmeaty_chem = source.reagents.has_reagent(/datum/reagent/consumable/nutriment/fat/oil) + if(unmeaty_chem) + LAZYREMOVE(unmeaty_chem.data, "meat") + //the edible source is removed by on_removed() + /datum/material/meat/proc/make_edible(atom/source, mat_amount, multiplier) + if(source.material_flags & MATERIAL_NO_EDIBILITY) + return var/protein_count = 3 * (mat_amount / SHEET_MATERIAL_AMOUNT) * multiplier var/fat_count = 2 * (mat_amount / SHEET_MATERIAL_AMOUNT) * multiplier - - source.AddComponentFrom( + source.AddComponentFrom( \ SOURCE_EDIBLE_MEAT_MAT, \ /datum/component/edible, \ initial_reagents = list(/datum/reagent/consumable/nutriment/protein = protein_count, /datum/reagent/consumable/nutriment/fat = fat_count), \ foodtypes = RAW | MEAT, \ eat_time = 3 SECONDS, \ - tastes = list("meat")) + tastes = list("meat" = 1)) source.AddComponent( /datum/component/bloody_spreader,\ - blood_left = (protein_count + fat_count) * 0.3,\ + blood_left = (protein_count + fat_count) * 0.3 * multiplier,\ ) // Turfs can't handle the meaty goodness of blood walk. @@ -62,7 +84,7 @@ /datum/component/blood_walk,\ blood_type = /obj/effect/decal/cleanable/blood,\ blood_spawn_chance = 35,\ - max_blood = (protein_count + fat_count) * 0.3,\ + max_blood = (protein_count + fat_count) * 0.3 * multiplier,\ ) /datum/material/meat/on_removed(atom/source, mat_amount, multiplier) @@ -70,6 +92,7 @@ source.RemoveComponentSource(SOURCE_EDIBLE_MEAT_MAT, /datum/component/edible) qdel(source.GetComponent(/datum/component/blood_walk)) qdel(source.GetComponent(/datum/component/bloody_spreader)) + source.RemoveComponentSource(SOURCE_EDIBLE_MEAT_MAT, /datum/component/edible) /datum/material/meat/on_main_removed(atom/source, mat_amount, multiplier) . = ..() diff --git a/code/datums/materials/pizza.dm b/code/datums/materials/pizza.dm index 9c71f760139..dfd38434886 100644 --- a/code/datums/materials/pizza.dm +++ b/code/datums/materials/pizza.dm @@ -27,8 +27,7 @@ /datum/material/pizza/on_main_applied(atom/source, mat_amount, multiplier) . = ..() - if(!IS_EDIBLE(source)) - make_edible(source, mat_amount, multiplier) + make_edible(source, mat_amount) ADD_TRAIT(source, TRAIT_ROD_REMOVE_FISHING_DUD, REF(src)) //the fishing rod itself is the bait... sorta. /datum/material/pizza/on_applied(atom/source, mat_amount, multiplier) @@ -36,16 +35,31 @@ if(IS_EDIBLE(source)) make_edible(source, mat_amount, multiplier) -/datum/material/pizza/proc/make_edible(atom/source, mat_amount, multiplier) - var/nutriment_count = 3 * (mat_amount / SHEET_MATERIAL_AMOUNT) * multiplier - var/oil_count = 2 * (mat_amount / SHEET_MATERIAL_AMOUNT) * multiplier - source.AddComponentFrom( - SOURCE_EDIBLE_PIZZA_MAT, \ +/datum/material/pizza/on_edible_applied(atom/source, datum/component/edible/edible) + for(var/datum/reagent/consumable/nutriment/foodchem in source.reagents.reagent_list) + var/list/margherita_tastes = /obj/item/food/pizza/margherita::tastes + for(var/taste in margherita_tastes) + LAZYSET(foodchem.data, taste, 1) + source.AddComponentFrom(SOURCE_EDIBLE_MEAT_MAT, /datum/component/edible, foodtypes = GRAIN | DAIRY | VEGETABLES) + +/datum/material/pizza/on_edible_removed(atom/source, datum/component/edible/edible) + for(var/datum/reagent/consumable/nutriment/foodchem in source.reagents.reagent_list) + var/list/margherita_tastes = /obj/item/food/pizza/margherita::tastes + for(var/taste in margherita_tastes) + LAZYREMOVE(foodchem.data, taste) + //the edible source is removed by on_removed() + +/datum/material/pizza/proc/make_edible(atom/source, mat_amount) + if(source.material_flags & MATERIAL_NO_EDIBILITY) + return + var/nutriment_count = 3 * (mat_amount / SHEET_MATERIAL_AMOUNT) + var/oil_count = 2 * (mat_amount / SHEET_MATERIAL_AMOUNT) + source.AddComponentFrom(SOURCE_EDIBLE_PIZZA_MAT, \ /datum/component/edible, \ initial_reagents = list(/datum/reagent/consumable/nutriment = nutriment_count, /datum/reagent/consumable/nutriment/fat/oil = oil_count), \ foodtypes = GRAIN | DAIRY | VEGETABLES, \ eat_time = 3 SECONDS, \ - tastes = list("crust", "tomato", "cheese")) + tastes = /obj/item/food/pizza/margherita::tastes) /datum/material/pizza/on_removed(atom/source, mat_amount, multiplier) . = ..() diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index 0e913d9be6a..975e4703547 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -334,33 +334,33 @@ /** * Ensure a list of atoms/reagents exists inside this atom * - * Goes throught he list of passed in parts, if they're reagents, adds them to our reagent holder - * creating the reagent holder if it exists. - * - * If the part is a moveable atom and the previous location of the item was a mob/living, - * it calls the inventory handler transferItemToLoc for that mob/living and transfers the part - * to this atom - * - * Otherwise it simply forceMoves the atom into this atom + * Cycles through the list of movables used up in the recipe and calls used_in_craft() for each of them + * then it either moves them inside the object or deletes + * them depending on whether they're in the list of parts for the recipe or not */ -/atom/proc/CheckParts(list/parts_list, datum/crafting_recipe/current_recipe) - SEND_SIGNAL(src, COMSIG_ATOM_CHECKPARTS, parts_list, current_recipe) - if(!parts_list) - return - for(var/part in parts_list) - if(istype(part, /datum/reagent)) - if(!reagents) - reagents = new() - reagents.reagent_list.Add(part) - else if(ismovable(part)) - var/atom/movable/object = part - if(isliving(object.loc)) - var/mob/living/living = object.loc - living.transferItemToLoc(object, src) - else - object.forceMove(src) - SEND_SIGNAL(object, COMSIG_ATOM_USED_IN_CRAFT, src) - parts_list.Cut() +/atom/proc/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_ATOM_ON_CRAFT, components, current_recipe) + var/list/remaining_parts = current_recipe?.parts?.Copy() + var/list/parts_by_type = remaining_parts?.Copy() + for(var/parttype in parts_by_type) //necessary for our is_type_in_list() call with the zebra arg set to true + parts_by_type[parttype] = parttype + for(var/obj/item/item in components) // machinery or structure objects in the list are guaranteed to be used up. We only check items. + item.used_in_craft(src, current_recipe) + var/matched_type = is_type_in_list(item, parts_by_type, zebra = TRUE) + if(!matched_type) + continue + + if(isliving(item.loc)) + var/mob/living/living = item.loc + living.transferItemToLoc(item, src) + else + item.forceMove(src) + + if(matched_type) + remaining_parts[matched_type] -= 1 + if(remaining_parts[matched_type] <= 0) + remaining_parts -= matched_type ///Take air from the passed in gas mixture datum /atom/proc/assume_air(datum/gas_mixture/giver) diff --git a/code/game/atom/atom_materials.dm b/code/game/atom/atom_materials.dm index e8e291e708c..1c227db2394 100644 --- a/code/game/atom/atom_materials.dm +++ b/code/game/atom/atom_materials.dm @@ -10,6 +10,9 @@ /// Sets the custom materials for an atom. This is what you want to call, since most of the ones below are mainly internal. /atom/proc/set_custom_materials(list/materials, multiplier = 1) SHOULD_NOT_OVERRIDE(TRUE) + if((custom_materials == materials) && multiplier == 1) //Easy way to know no changes are being made. + return + var/replace_mats = length(materials) if(length(custom_materials)) remove_material_effects(replace_mats) @@ -30,6 +33,7 @@ for(var/current_material in materials) materials[current_material] *= multiplier + sortTim(materials, GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE) apply_material_effects(materials) ///proc responsible for applying material effects when setting materials. @@ -84,17 +88,13 @@ var/total_alpha = 0 var/list/colors = list() var/mat_length = length(materials) - var/datum/material/main_material //the material with the highest amount (after calculations) - var/main_mat_amount - var/main_mat_mult + var/datum/material/main_material = materials[1]//the material with the highest amount (after calculations) + var/main_mat_amount = materials[main_material][MATERIAL_LIST_OPTIMAL_AMOUNT] + var/main_mat_mult = materials[main_material][MATERIAL_LIST_MULTIPLIER] for(var/datum/material/custom_material as anything in materials) var/list/deets = materials[custom_material] var/mat_amount = deets[MATERIAL_LIST_OPTIMAL_AMOUNT] var/multiplier = deets[MATERIAL_LIST_MULTIPLIER] - if(mat_amount > main_mat_amount) - main_material = custom_material - main_mat_amount = mat_amount - main_mat_mult = multiplier apply_single_mat_effect(custom_material, mat_amount, multiplier) custom_material.on_applied(src, mat_amount, multiplier) @@ -135,6 +135,8 @@ var/prefixes = get_material_prefixes(materials) name = "[prefixes] [name]" + SEND_SIGNAL(src, COMSIG_ATOM_FINALIZE_MATERIAL_EFFECTS, materials, main_material) + /** * A proc used by both finalize_material_effects() and finalize_remove_material_effects() to get the colors * that will later be applied to or removed from the atom @@ -204,9 +206,14 @@ return path ///Apply material effects of a single material. -/atom/proc/apply_single_mat_effect(datum/material/custom_material, amount, multipier) +/atom/proc/apply_single_mat_effect(datum/material/material, amount, multiplier) SHOULD_CALL_PARENT(TRUE) - return + if(!(material_flags & MATERIAL_AFFECT_STATISTICS) || !uses_integrity) + return + var/integrity_mod = GET_MATERIAL_MODIFIER(material.integrity_modifier, multiplier) + modify_max_integrity(ceil(max_integrity * integrity_mod)) + var/list/armor_mods = material.get_armor_modifiers(multiplier) + set_armor(get_armor().generate_new_with_multipliers(armor_mods)) ///A proc for material effects that only the main material (which the atom's primarly composed of) should apply. /atom/proc/apply_main_material_effects(datum/material/main_material, amount, multipier) @@ -252,10 +259,17 @@ if(material_flags & MATERIAL_ADD_PREFIX) name = initial(name) + SEND_SIGNAL(src, COMSIG_ATOM_FINALIZE_REMOVE_MATERIAL_EFFECTS, materials, main_material) + ///Remove material effects of a single material. -/atom/proc/remove_single_mat_effect(datum/material/custom_material, amount, multipier) +/atom/proc/remove_single_mat_effect(datum/material/material, amount, multiplier) SHOULD_CALL_PARENT(TRUE) - return + if(!(material_flags & MATERIAL_AFFECT_STATISTICS) || !uses_integrity) + return + var/integrity_mod = GET_MATERIAL_MODIFIER(material.integrity_modifier, multiplier) + modify_max_integrity(floor(max_integrity / integrity_mod)) + var/list/armor_mods = material.get_armor_modifiers(1 / multiplier) + set_armor(get_armor().generate_new_with_multipliers(armor_mods)) ///A proc to remove the material effects previously applied by the (ex-)main material /atom/proc/remove_main_material_effects(datum/material/main_material, amount, multipier) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index e72d1ad4e19..e18cbb5b96c 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1778,6 +1778,11 @@ /atom/movable/proc/keybind_face_direction(direction) setDir(direction) +///This handles special behavior that happens when the movable is used in crafting (slapcrafting and UI, not sheets or lathes or processing with a tool) +/atom/movable/proc/used_in_craft(atom/result, datum/crafting_recipe/current_recipe) + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_ATOM_USED_IN_CRAFT, result) + /** * Check if the other atom/movable has any factions the same as us. Defined at the atom/movable level so it can be defined for just about anything. * diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 501535d2590..5ccd95567e7 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -836,8 +836,8 @@ return TRUE return ..() -/obj/machinery/CheckParts(list/parts_list) - ..() +/obj/machinery/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + . = ..() RefreshParts() /obj/machinery/proc/RefreshParts() diff --git a/code/game/machinery/medipen_refiller.dm b/code/game/machinery/medipen_refiller.dm index 9236ff68a26..e81b43c9600 100644 --- a/code/game/machinery/medipen_refiller.dm +++ b/code/game/machinery/medipen_refiller.dm @@ -26,7 +26,7 @@ AddComponent(/datum/component/plumbing/simple_demand) AddComponent(/datum/component/simple_rotation) register_context() - CheckParts() + RefreshParts() /obj/machinery/medipen_refiller/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index e27af79c89c..2f50397bb94 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -30,6 +30,16 @@ Buildable meters ///Initial direction of the created pipe (either made from the RPD or after unwrenching the pipe) var/p_init_dir = SOUTH +/obj/item/pipe/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + . = ..() + if(!istype(current_recipe, /datum/crafting_recipe/spec_pipe)) + return + var/datum/crafting_recipe/spec_pipe/pipe_recipe = current_recipe + pipe_type = pipe_recipe.pipe_type + pipe_color = ATMOS_COLOR_OMNI + setDir(crafter.dir) + update() + /obj/item/pipe/directional RPD_type = PIPE_UNARY /obj/item/pipe/directional/he_junction diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index 64df6a03c98..04990c12bab 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -338,6 +338,18 @@ . = ..() QDEL_NULL(beaker) +/obj/machinery/space_heater/improvised_chem_heater/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + . = ..() + if(!isliving(crafter)) + return + var/mob/living/user = crafter + var/obj/item/stock_parts/power_store/cell/cell = (locate() in range(1)) || user.is_holding_item_of_type(/obj/item/stock_parts/power_store/cell) + if(!cell) + return + var/turf/turf = get_turf(cell) + forceMove(turf) + attackby(cell, user) //puts it into the heater + /obj/machinery/space_heater/improvised_chem_heater/heating_examine() . = ..() // Conducted energy per joule of thermal energy difference in a tick. diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index ed27105b11a..ded98937c85 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -551,45 +551,42 @@ return ..() -/obj/item/bombcore/chemical/CheckParts(list/parts_list) - ..() +/obj/item/bombcore/chemical/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) // Using different grenade casings, causes the payload to have different properties. - var/obj/item/stock_parts/matter_bin/MB = locate(/obj/item/stock_parts/matter_bin) in src - if(MB) - max_beakers += MB.rating // max beakers = 2-5. - qdel(MB) - for(var/obj/item/grenade/chem_grenade/G in src) + var/obj/item/stock_parts/matter_bin/bin = locate(/obj/item/stock_parts/matter_bin) in components + if(bin) + max_beakers += bin.rating // max beakers = 2-5. + for(var/obj/item/grenade/chem_grenade/nade in components) - if(istype(G, /obj/item/grenade/chem_grenade/large)) - var/obj/item/grenade/chem_grenade/large/LG = G + if(istype(nade, /obj/item/grenade/chem_grenade/large)) max_beakers += 1 // Adding two large grenades only allows for a maximum of 7 beakers. spread_range += 2 // Extra range, reduced density. temp_boost += 50 // maximum of +150K blast using only large beakers. Not enough to self ignite. - for(var/obj/item/slime_extract/S in LG.beakers) // And slime cores. + for(var/obj/item/slime_extract/slime in nade.beakers) // And slime cores. if(beakers.len < max_beakers) - beakers += S - S.forceMove(src) + beakers += slime + slime.forceMove(src) else - S.forceMove(drop_location()) + slime.forceMove(drop_location()) - if(istype(G, /obj/item/grenade/chem_grenade/cryo)) + if(istype(nade, /obj/item/grenade/chem_grenade/cryo)) spread_range -= 1 // Reduced range, but increased density. temp_boost -= 100 // minimum of -150K blast. - if(istype(G, /obj/item/grenade/chem_grenade/pyro)) + if(istype(nade, /obj/item/grenade/chem_grenade/pyro)) temp_boost += 150 // maximum of +350K blast, which is enough to self ignite. Which means a self igniting bomb can't take advantage of other grenade casing properties. Sorry? - if(istype(G, /obj/item/grenade/chem_grenade/adv_release)) - time_release += 50 // A typical bomb, using basic beakers, will explode over 2-4 seconds. Using two will make the reaction last for less time, but it will be more dangerous overall. + if(istype(nade, /obj/item/grenade/chem_grenade/adv_release)) + time_release += 5 SECONDS // A typical bomb, using basic beakers, will explode over 2-4 seconds. Using two will make the reaction last for less time, but it will be more dangerous overall. - for(var/obj/item/reagent_containers/cup/B in G) + for(var/obj/item/reagent_containers/cup/beaker in nade) if(beakers.len < max_beakers) - beakers += B - B.forceMove(src) + beakers += beaker + beaker.forceMove(src) else - B.forceMove(drop_location()) + beaker.forceMove(drop_location()) - qdel(G) + return ..() /obj/item/bombcore/emp name = "EMP payload" @@ -618,22 +615,20 @@ chosen_theme = null return ..() -/obj/item/bombcore/dimensional/CheckParts(list/parts_list) +/obj/item/bombcore/dimensional/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) . = ..() range_heavy = 13 - for(var/obj/item/grenade/chem_grenade/nade in src) + for(var/obj/item/grenade/chem_grenade/nade in components) if(istype(nade, /obj/item/grenade/chem_grenade/large) || istype(nade, /obj/item/grenade/chem_grenade/adv_release)) range_heavy += 1 for(var/obj/item/thing as anything in nade.beakers) //remove beakers, then delete the grenade. thing.forceMove(drop_location()) - qdel(nade) - var/obj/item/gibtonite/ore = locate() in src + var/obj/item/gibtonite/ore = locate() in components switch(ore.quality) if(GIBTONITE_QUALITY_LOW) range_heavy -= 2 if(GIBTONITE_QUALITY_HIGH) range_heavy += 4 - qdel(ore) /obj/item/bombcore/dimensional/examine(mob/user) . = ..() diff --git a/code/game/objects/effects/decals/cleanable/food.dm b/code/game/objects/effects/decals/cleanable/food.dm index 911f1ba4f14..243b10dfebb 100644 --- a/code/game/objects/effects/decals/cleanable/food.dm +++ b/code/game/objects/effects/decals/cleanable/food.dm @@ -1,4 +1,3 @@ - /obj/effect/decal/cleanable/food icon = 'icons/effects/tomatodecal.dmi' gender = NEUTER diff --git a/code/game/objects/items/cigarettes.dm b/code/game/objects/items/cigarettes.dm index 447e51ea601..521e184cace 100644 --- a/code/game/objects/items/cigarettes.dm +++ b/code/game/objects/items/cigarettes.dm @@ -950,7 +950,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/rollingpaper/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, /obj/item/cigarette/rollie, CUSTOM_INGREDIENT_ICON_NOCHANGE, ingredient_type=CUSTOM_INGREDIENT_TYPE_DRYABLE, max_ingredients=2) + AddComponent(/datum/component/ingredients_holder, /obj/item/cigarette/rollie, CUSTOM_INGREDIENT_ICON_NOCHANGE, ingredient_type=CUSTOM_INGREDIENT_TYPE_DRYABLE, max_ingredients=2) /////////////// diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index f1a3854fb88..38942a22d64 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -109,8 +109,8 @@ if(!safety && emagged_state) . += emagged_state -/obj/item/defibrillator/CheckParts(list/parts_list) - ..() +/obj/item/defibrillator/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + . = ..() cell = locate(/obj/item/stock_parts/power_store) in contents update_power() diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index 77eefa8a150..47875695bfb 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -160,3 +160,13 @@ AI.updatehealth() sleep(0.5 SECONDS) flush = FALSE + +/obj/item/aicard/used_in_craft(atom/result, datum/crafting_recipe/current_recipe) + . = ..() + if(!AI || !istype(result, /obj/item/aicard)) + return + var/obj/item/aicard/new_card = result + AI.forceMove(new_card) + new_card.AI = AI + new_card.update_appearance() + AI = null diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 38845ba737c..9c9f2aa8026 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -554,7 +554,7 @@ randomize_fuel = FALSE trash_type = /obj/item/trash/candle can_be_extinguished = TRUE - var/scented_type //SKYRAT EDIT ADDITION /// Pollutant type for scented candles + custom_materials = null //candles are made of wax (which doesn't exists as a material type as of 2025) and not plastic /// The current wax level, used for drawing the correct icon var/current_wax_level = 1 /// The previous wax level, remembered so we only have to make 3 update_appearance calls total as opposed to every tick diff --git a/code/game/objects/items/flamethrower.dm b/code/game/objects/items/flamethrower.dm index 659bdc11667..d6cf9fd9336 100644 --- a/code/game/objects/items/flamethrower.dm +++ b/code/game/objects/items/flamethrower.dm @@ -193,8 +193,8 @@ set_light_on(lit) update_appearance() -/obj/item/flamethrower/CheckParts(list/parts_list) - ..() +/obj/item/flamethrower/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + . =..() weldtool = locate(/obj/item/weldingtool) in contents igniter = locate(/obj/item/assembly/igniter) in contents weldtool.status = FALSE diff --git a/code/game/objects/items/food/_food.dm b/code/game/objects/items/food/_food.dm index 091c8a9949a..4ef13601e67 100644 --- a/code/game/objects/items/food/_food.dm +++ b/code/game/objects/items/food/_food.dm @@ -10,6 +10,16 @@ righthand_file = 'icons/mob/inhands/items/food_righthand.dmi' obj_flags = UNIQUE_RENAME grind_results = list() + material_flags = MATERIAL_NO_EDIBILITY + /** + * A list of material paths. the main material in the custom_materials list is also added on init. + * + * If the food has materials and as long as the main one is in this list, effects and properties of materials are disabled + * Food is coded mainly around reagents than materials, and the two may cause some issues if overlapped. For example, this + * stops food *normally* containing meat from having redundant prefixes, an unfitting appearance and too much meatiness overall. + * However, the same material effects will apply on a fruit or a vegetable. + */ + var/list/intrisic_food_materials ///List of reagents this food gets on creation during reaction or map spawn var/list/food_reagents ///Extra flags for things such as if the food is in a container or not @@ -54,7 +64,20 @@ /obj/item/food/Initialize(mapload) if(food_reagents) food_reagents = string_assoc_list(food_reagents) + + ///This has to be done before set_custom_materials is called at atom level + if(custom_materials) + var/main_mat_type = null + var/mat_amount = 0 + for(var/mat_type in custom_materials) + if(custom_materials[mat_type] > mat_amount) + main_mat_type = mat_type + LAZYADD(intrisic_food_materials, main_mat_type) + if(intrisic_food_materials) + intrisic_food_materials = typecacheof(intrisic_food_materials) + . = ..() + if(tastes) tastes = string_assoc_list(tastes) if(eatverbs) @@ -70,6 +93,20 @@ make_microwaveable() ADD_TRAIT(src, TRAIT_FISHING_BAIT, INNATE_TRAIT) +/obj/item/food/apply_material_effects(list/materials) + if(!HAS_TRAIT(src, TRAIT_INGREDIENTS_HOLDER)) //ingredients holder handle prefixes and colors differently + var/datum/material/main_material = materials[1] //The list is sorted by amount so the first of the list is the main mat + if(!is_type_in_typecache(main_material, intrisic_food_materials)) + material_flags |= MATERIAL_EFFECTS|MATERIAL_AFFECT_STATISTICS|MATERIAL_ADD_PREFIX|MATERIAL_COLOR + else + //food items with the ingredients holders component are still affected by the materials stats and effects wise. + material_flags |= MATERIAL_EFFECTS|MATERIAL_AFFECT_STATISTICS + return ..() + +/obj/item/food/remove_material_effects(replace_mats = TRUE) + . = ..() + material_flags &= ~(MATERIAL_EFFECTS|MATERIAL_AFFECT_STATISTICS|MATERIAL_ADD_PREFIX|MATERIAL_COLOR) + ///This proc adds the edible component, overwrite this if you for some reason want to change some specific args like callbacks. /obj/item/food/proc/make_edible() AddComponentFrom( @@ -87,6 +124,12 @@ reagent_purity = starting_reagent_purity,\ ) +/obj/item/food/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + . = ..() + var/mob/living/user = crafter + if(istype(user) && !isnull(user.mind)) + ADD_TRAIT(src, TRAIT_FOOD_CHEF_MADE, REF(user.mind)) + ///This proc handles processable elements, overwrite this if you want to add behavior such as slicing, forking, spooning, whatever, to turn the item into something else /obj/item/food/proc/make_processable() return @@ -123,14 +166,14 @@ if(!preserved_food) AddComponent(/datum/component/decomposition, mapload, decomp_req_handle, decomp_flags = foodtypes, decomp_result = decomp_type, ant_attracting = ant_attracting, custom_time = decomposition_time, stink_particles = decomposition_particles) -/obj/item/food/CheckParts(list/parts, datum/crafting_recipe/food/current_recipe) +/obj/item/food/on_craft_completion(list/components, datum/crafting_recipe/food/current_recipe, atom/crafter) . = ..() if(!istype(current_recipe)) return var/made_with_food = FALSE var/final_foodtypes = current_recipe.added_foodtypes - for(var/obj/item/food/ingredient in parts) + for(var/obj/item/food/ingredient in components) made_with_food = TRUE final_foodtypes |= ingredient.foodtypes if(!made_with_food) diff --git a/code/game/objects/items/food/bread.dm b/code/game/objects/items/food/bread.dm index 24435f799cd..12a9a4b35de 100644 --- a/code/game/objects/items/food/bread.dm +++ b/code/game/objects/items/food/bread.dm @@ -50,10 +50,9 @@ venue_value = FOOD_PRICE_CHEAP slice_type = /obj/item/food/breadslice/plain crafting_complexity = FOOD_COMPLEXITY_1 - /obj/item/food/bread/plain/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/bread/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) + AddComponent(/datum/component/ingredients_holder, /obj/item/food/bread/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) /obj/item/food/breadslice/plain name = "bread slice" @@ -67,7 +66,7 @@ /obj/item/food/breadslice/plain/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_STACK) + AddComponent(/datum/component/ingredients_holder, null, CUSTOM_INGREDIENT_ICON_STACK) /obj/item/food/breadslice/plain/make_grillable() AddComponent(/datum/component/grillable, /obj/item/food/griddle_toast, rand(15 SECONDS, 25 SECONDS), TRUE, TRUE) @@ -103,6 +102,7 @@ /datum/reagent/consumable/nutriment/vitamin = 10, /datum/reagent/consumable/nutriment/protein = 12, ) + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) tastes = list("bread" = 10, "meat" = 10) foodtypes = GRAIN | MEAT | DAIRY venue_value = FOOD_PRICE_CHEAP @@ -135,6 +135,7 @@ foodtypes = GRAIN | MEAT slice_type = /obj/item/food/breadslice/sausage crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/breadslice/sausage name = "sausagebread slice" @@ -153,6 +154,7 @@ name = "xenomeatbread loaf" desc = "The culinary base of every self-respecting eloquen/tg/entleman. Extra Heretical." icon_state = "xenomeatbread" + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) food_reagents = list( /datum/reagent/consumable/nutriment = 20, /datum/reagent/consumable/nutriment/vitamin = 10, @@ -180,6 +182,7 @@ name = "spider meat loaf" desc = "Reassuringly green meatloaf made from spider meat." icon_state = "spidermeatbread" + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) food_reagents = list( /datum/reagent/consumable/nutriment = 20, /datum/reagent/toxin = 15, @@ -327,7 +330,7 @@ /obj/item/food/breadslice/empty/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) + AddComponent(/datum/component/ingredients_holder, null, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) /obj/item/food/baguette name = "baguette" diff --git a/code/game/objects/items/food/burgers.dm b/code/game/objects/items/food/burgers.dm index c5d5cd35367..5bcf079c24f 100644 --- a/code/game/objects/items/food/burgers.dm +++ b/code/game/objects/items/food/burgers.dm @@ -26,18 +26,20 @@ custom_price = PAYCHECK_CREW * 0.8 venue_value = FOOD_PRICE_CHEAP crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/plain/Initialize(mapload) . = ..() - if(prob(1)) - new/obj/effect/particle_effect/fluid/smoke(get_turf(src)) - playsound(src, 'sound/effects/smoke.ogg', 50, TRUE) - visible_message(span_warning("Oh, ye gods! [src] is ruined! But what if...?")) - name = "steamed ham" - desc = pick("Ahh, Head of Personnel, welcome. I hope you're prepared for an unforgettable luncheon!", - "And you call these steamed hams despite the fact that they are obviously microwaved?", - "Aurora Station 13? At this time of shift, in this time of year, in this sector of space, localized entirely within your freezer?", - "You know, these hamburgers taste quite similar to the ones they have at the Maltese Falcon.") + if(!prob(1)) + return + new/obj/effect/particle_effect/fluid/smoke(get_turf(src)) + playsound(src, 'sound/effects/smoke.ogg', 50, TRUE) + visible_message(span_warning("Oh, ye gods! [src] is ruined! But what if...?")) + name = "steamed ham" + desc = pick("Ahh, Head of Personnel, welcome. I hope you're prepared for an unforgettable luncheon!", + "And you call these steamed hams despite the fact that they are obviously microwaved?", + "Aurora Station 13? At this time of shift, in this time of year, in this sector of space, localized entirely within your freezer?", + "You know, these hamburgers taste quite similar to the ones they have at the Maltese Falcon.") /obj/item/food/burger/human name = "human burger" @@ -51,11 +53,11 @@ foodtypes = MEAT | GRAIN venue_value = FOOD_PRICE_CHEAP crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) -/obj/item/food/burger/human/CheckParts(list/parts_list) - ..() - var/obj/item/food/patty/human/human_patty = locate(/obj/item/food/patty/human) in contents - for(var/datum/material/meat/mob_meat/mob_meat_material in human_patty.custom_materials) +/obj/item/food/burger/human/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + . = ..() + for(var/datum/material/meat/mob_meat/mob_meat_material in custom_materials) if(mob_meat_material.subjectname) name = "[mob_meat_material.subjectname] burger" else if(mob_meat_material.subjectjob) @@ -73,6 +75,7 @@ foodtypes = GRAIN | MEAT venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/appendix name = "appendix burger" @@ -151,6 +154,7 @@ foodtypes = GRAIN | MEAT venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/bearger name = "bearger" @@ -165,6 +169,7 @@ foodtypes = GRAIN | MEAT venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/clown name = "clown burger" @@ -279,6 +284,7 @@ tastes = list("bun" = 2, "red" = 2) foodtypes = GRAIN | MEAT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/orange name = "orange burger" @@ -294,6 +300,7 @@ tastes = list("bun" = 2, "orange" = 2) foodtypes = GRAIN | MEAT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/yellow name = "yellow burger" @@ -309,6 +316,7 @@ tastes = list("bun" = 2, "yellow" = 2) foodtypes = GRAIN | MEAT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/green name = "green burger" @@ -324,6 +332,7 @@ tastes = list("bun" = 2, "green" = 2) foodtypes = GRAIN | MEAT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/blue name = "blue burger" @@ -339,6 +348,7 @@ tastes = list("bun" = 2, "blue" = 2) foodtypes = GRAIN | MEAT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/purple name = "purple burger" @@ -354,6 +364,7 @@ tastes = list("bun" = 2, "purple" = 2) foodtypes = GRAIN | MEAT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/black name = "black burger" @@ -369,6 +380,7 @@ tastes = list("bun" = 2, "black" = 2) foodtypes = GRAIN | MEAT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/white name = "white burger" @@ -384,6 +396,7 @@ tastes = list("bun" = 2, "white" = 2) foodtypes = GRAIN | MEAT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/spell name = "spell burger" @@ -413,6 +426,7 @@ foodtypes = GRAIN | MEAT | DAIRY venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/burger/jelly name = "jelly burger" @@ -455,6 +469,7 @@ foodtypes = GRAIN | MEAT | DAIRY | VEGETABLES venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_5 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/burger/superbite/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] starts to eat [src] in one bite, it looks like [user.p_theyre()] trying to commit suicide!")) @@ -477,6 +492,7 @@ foodtypes = GRAIN | MEAT | VEGETABLES venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/rat name = "rat burger" @@ -506,6 +522,7 @@ custom_price = PAYCHECK_CREW * 0.8 venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = /obj/item/melee/baseball_bat::custom_materials /obj/item/food/burger/baconburger name = "bacon burger" @@ -521,6 +538,7 @@ custom_premium_price = PAYCHECK_CREW * 1.6 venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/burger/empoweredburger name = "empowered burger" @@ -549,6 +567,7 @@ tastes = list("bun" = 4, "meat" = 2, "cat" = 2) foodtypes = GRAIN | MEAT | GORE crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/crab name = "crab burger" @@ -563,6 +582,7 @@ foodtypes = GRAIN | SEAFOOD venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/burger/soylent name = "soylent burger" @@ -577,6 +597,7 @@ foodtypes = GRAIN | MEAT | DAIRY venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/burger/rib name = "mcrib" @@ -592,6 +613,7 @@ foodtypes = GRAIN | MEAT | SUGAR | VEGETABLES venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/burger/mcguffin name = "mcguffin" @@ -607,6 +629,7 @@ foodtypes = GRAIN | MEAT | BREAKFAST | FRIED venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/burger/chicken name = "chicken sandwich" @@ -625,6 +648,7 @@ foodtypes = GRAIN | MEAT venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/cheese name = "cheese burger" @@ -639,6 +663,7 @@ foodtypes = GRAIN | MEAT | DAIRY venue_value = FOOD_PRICE_CHEAP crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/cheese/Initialize(mapload) . = ..() @@ -659,6 +684,7 @@ tastes = list("bun" = 2, "beef patty" = 4, "cheese" = 2, "beef soaked in chili" = 3, "a smoking flare" = 2) foodtypes = GRAIN | MEAT | DAIRY | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2, /datum/material/plastic= SMALL_MATERIAL_AMOUNT * 0.5) /obj/item/food/burger/crazy/Initialize(mapload) . = ..() @@ -691,3 +717,4 @@ foodtypes = MEAT|VEGETABLES|GRAIN venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) diff --git a/code/game/objects/items/food/cake.dm b/code/game/objects/items/food/cake.dm index 17453300117..f6c123208c4 100644 --- a/code/game/objects/items/food/cake.dm +++ b/code/game/objects/items/food/cake.dm @@ -47,7 +47,7 @@ /obj/item/food/cake/plain/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/cake/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 16) + AddComponent(/datum/component/ingredients_holder, /obj/item/food/cake/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 16) /obj/item/food/cakeslice/plain name = "plain cake slice" @@ -71,7 +71,7 @@ /obj/item/food/cakeslice/empty/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 16) + AddComponent(/datum/component/ingredients_holder, null, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 16) /obj/item/food/cake/carrot name = "carrot cake" @@ -485,6 +485,7 @@ foodtypes = GRAIN|DAIRY|SUGAR|GROSS slice_type = /obj/item/food/cakeslice/hardware_cake_slice crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/glass = SHEET_MATERIAL_AMOUNT) /obj/item/food/cakeslice/hardware_cake_slice name = "hardware cake slice" diff --git a/code/game/objects/items/food/donkpocket.dm b/code/game/objects/items/food/donkpocket.dm index f5e382942f7..c2047e17d96 100644 --- a/code/game/objects/items/food/donkpocket.dm +++ b/code/game/objects/items/food/donkpocket.dm @@ -51,10 +51,12 @@ foodtypes = MEAT|GRAIN tastes = list("meat" = 2, "dough" = 2, "comfiness" = 1) warm_type = /obj/item/food/donkpocket/warm/homemade + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/donkpocket/warm/homemade foodtypes = MEAT|GRAIN tastes = list("meat" = 2, "dough" = 2, "comfiness" = 1) + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/donkpocket/dank name = "\improper Dank-pocket" @@ -126,10 +128,12 @@ tastes = list("meat" = 2, "dough" = 2, "spice" = 1) foodtypes = MEAT|VEGETABLES|GRAIN warm_type = /obj/item/food/donkpocket/warm/spicy/homemade + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/donkpocket/warm/spicy/homemade tastes = list("meat" = 2, "dough" = 2, "weird spices" = 1) foodtypes = MEAT|VEGETABLES|GRAIN + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/donkpocket/teriyaki name = "\improper Teriyaki-pocket" @@ -167,10 +171,12 @@ tastes = list("meat" = 2, "dough" = 2, "soy sauce" = 2) foodtypes = MEAT|GRAIN warm_type = /obj/item/food/donkpocket/warm/teriyaki/homemade + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/donkpocket/warm/teriyaki/homemade tastes = list("meat" = 2, "dough" = 2, "soy sauce" = 2) foodtypes = MEAT|GRAIN + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/donkpocket/pizza name = "\improper Pizza-pocket" @@ -220,6 +226,7 @@ /datum/reagent/medicine/omnizine = 2, /datum/reagent/consumable/laughter = 6, ) + custom_materials = null /obj/item/food/donkpocket/honk/make_bakeable() AddComponent(/datum/component/bakeable, warm_type, rand(baking_time_short, baking_time_long), TRUE, TRUE, honk_added_reagents) @@ -240,6 +247,7 @@ tastes = list("banana" = 2, "dough" = 2, "children's antibiotics" = 1) foodtypes = GRAIN|FRUIT|SUGAR crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = null /obj/item/food/donkpocket/berry name = "\improper Berry-pocket" @@ -252,6 +260,7 @@ tastes = list("dough" = 2, "jam" = 2) foodtypes = GRAIN|FRUIT|SUGAR warm_type = /obj/item/food/donkpocket/warm/berry + custom_materials = null /obj/item/food/donkpocket/berry/make_bakeable() AddComponent(/datum/component/bakeable, warm_type, rand(baking_time_short, baking_time_long), TRUE, TRUE, child_added_reagents) @@ -270,6 +279,7 @@ ) tastes = list("dough" = 2, "warm jam" = 2) foodtypes = GRAIN|FRUIT|SUGAR + custom_materials = null /obj/item/food/donkpocket/gondola name = "\improper Gondola-pocket" @@ -284,6 +294,7 @@ foodtypes = GRAIN|MEAT warm_type = /obj/item/food/donkpocket/warm/gondola + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) var/static/list/gondola_added_reagents = list( /datum/reagent/medicine/omnizine = 2, /datum/reagent/gondola_mutation_toxin = 5, @@ -307,6 +318,7 @@ ) tastes = list("meat" = 2, "dough" = 2, "inner peace" = 1) foodtypes = GRAIN|MEAT + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/donkpocket/deluxe name = "\improper Donk-pocket Deluxe" @@ -326,6 +338,7 @@ var/static/list/deluxe_added_reagents = list( /datum/reagent/medicine/omnizine = 8, ) + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/donkpocket/deluxe/make_bakeable() AddComponent(/datum/component/bakeable, warm_type, rand(baking_time_short, baking_time_long), TRUE, TRUE, deluxe_added_reagents) @@ -345,6 +358,7 @@ ) tastes = list("quality meat" = 2, "dough" = 2, "fanciness" = 1) foodtypes = GRAIN|MEAT|VEGETABLES|FRIED + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/donkpocket/deluxe/nocarb name = "\improper Meat-pocket" @@ -359,6 +373,7 @@ foodtypes = MEAT|RAW crafting_complexity = FOOD_COMPLEXITY_4 warm_type = /obj/item/food/donkpocket/warm/deluxe/nocarb + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 4) /obj/item/food/donkpocket/deluxe/meat/make_bakeable() AddComponent(/datum/component/bakeable, warm_type, rand(baking_time_short, baking_time_long), TRUE, TRUE, deluxe_added_reagents) @@ -377,6 +392,7 @@ ) tastes = list("meat" = 2, "more meat" = 2, "no carbs" = 1) foodtypes = MEAT + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 4) /obj/item/food/donkpocket/deluxe/vegan name = "\improper Donk-roll" @@ -391,6 +407,7 @@ foodtypes = GRAIN | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_4 warm_type = /obj/item/food/donkpocket/warm/deluxe/vegan + custom_materials = null /obj/item/food/donkpocket/deluxe/vegan/make_bakeable() AddComponent(/datum/component/bakeable, warm_type, rand(baking_time_short, baking_time_long), TRUE, TRUE, deluxe_added_reagents) @@ -409,3 +426,4 @@ ) tastes = list("rice patty" = 2, "fried dough" = 2, "peppery kick" = 1) foodtypes = GRAIN | VEGETABLES | FRIED + custom_materials = null diff --git a/code/game/objects/items/food/donuts.dm b/code/game/objects/items/food/donuts.dm index 5542925b2d3..ce43431e2b6 100644 --- a/code/game/objects/items/food/donuts.dm +++ b/code/game/objects/items/food/donuts.dm @@ -24,6 +24,14 @@ if(prob(DONUT_SPRINKLE_CHANCE)) decorate_donut() +// It is so stupid that we have to do this but because food crafting clears all reagents that got added during init, +// here we are adding it again (but only for crafting, maploaded and spawned donuts work fine). +// Until the issues with crafted items' reagents are resolved this will have to do +/obj/item/food/donut/plain/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + . = ..() + if(is_decorated) + reagents.add_reagent(/datum/reagent/consumable/sprinkles, 1) + ///Override for checkliked callback /obj/item/food/donut/make_edible() . = ..() @@ -92,6 +100,7 @@ foodtypes = GRAIN|DAIRY|JUNKFOOD|FRIED|BREAKFAST|MEAT|GORE is_decorated = TRUE crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/donut/berry name = "pink donut" diff --git a/code/game/objects/items/food/dough.dm b/code/game/objects/items/food/dough.dm index 283cd347f55..fe58ad5b09e 100644 --- a/code/game/objects/items/food/dough.dm +++ b/code/game/objects/items/food/dough.dm @@ -46,7 +46,7 @@ /obj/item/food/pizzabread/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/pizza, CUSTOM_INGREDIENT_ICON_SCATTER, max_ingredients = 12) + AddComponent(/datum/component/ingredients_holder, /obj/item/food/pizza, CUSTOM_INGREDIENT_ICON_SCATTER, max_ingredients = 12) /obj/item/food/doughslice name = "dough slice" @@ -78,7 +78,7 @@ /obj/item/food/bun/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/burger/empty, CUSTOM_INGREDIENT_ICON_STACKPLUSTOP) + AddComponent(/datum/component/ingredients_holder, /obj/item/food/burger/empty, CUSTOM_INGREDIENT_ICON_STACKPLUSTOP) /obj/item/food/cakebatter name = "cake batter" diff --git a/code/game/objects/items/food/egg.dm b/code/game/objects/items/food/egg.dm index d154ce1ea51..958ca9c0e60 100644 --- a/code/game/objects/items/food/egg.dm +++ b/code/game/objects/items/food/egg.dm @@ -255,6 +255,7 @@ GLOBAL_VAR_INIT(chicks_from_eggs, 0) tastes = list("egg" = 4, "meat" = 4) venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/boiledegg/rotten food_reagents = list(/datum/reagent/consumable/eggrot = 10) @@ -315,6 +316,7 @@ GLOBAL_VAR_INIT(chicks_from_eggs, 0) foodtypes = MEAT|BREAKFAST|GRAIN|FRIED venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/eggwrap name = "egg wrap" diff --git a/code/game/objects/items/food/frozen.dm b/code/game/objects/items/food/frozen.dm index 4728ecc1e76..b26f3bce675 100644 --- a/code/game/objects/items/food/frozen.dm +++ b/code/game/objects/items/food/frozen.dm @@ -454,3 +454,4 @@ overlay_state = "meatsicle" foodtypes = RAW | MEAT | SUGAR crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) diff --git a/code/game/objects/items/food/lizard.dm b/code/game/objects/items/food/lizard.dm index 65c3f4145b4..5c66986a74f 100644 --- a/code/game/objects/items/food/lizard.dm +++ b/code/game/objects/items/food/lizard.dm @@ -16,6 +16,7 @@ foodtypes = MEAT|RAW w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_1 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/raw_tiziran_sausage/Initialize(mapload) . = ..() @@ -35,6 +36,7 @@ w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 custom_price = PAYCHECK_CREW + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/raw_headcheese name = "raw headcheese block" @@ -49,6 +51,7 @@ foodtypes = MEAT|RAW|GORE w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_1 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/raw_headcheese/Initialize(mapload) . = ..() @@ -67,6 +70,7 @@ foodtypes = MEAT | GORE w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/headcheese/make_processable() AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/headcheese_slice, 5, 3 SECONDS, table_required = TRUE, screentip_verb = "Slice") @@ -122,6 +126,7 @@ foodtypes = MEAT|VEGETABLES w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/moonfish_eggs name = "moonfish eggs" @@ -212,6 +217,7 @@ foodtypes = MEAT|NUTS|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) //Why does like, every language on the planet besides English call them pommes? Who knows, who cares- the lizards call them it too, because funny. /obj/item/food/lizard_fries @@ -230,6 +236,7 @@ foodtypes = MEAT | VEGETABLES | FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/brain_pate name = "eyeball-and-brain pate" @@ -349,6 +356,7 @@ foodtypes = MEAT | SEAFOOD | VEGETABLES w_class = WEIGHT_CLASS_BULKY crafting_complexity = FOOD_COMPLEXITY_5 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 3) //Spaghetti Dishes @@ -541,7 +549,7 @@ /obj/item/food/bread/root/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/bread/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) + AddComponent(/datum/component/ingredients_holder, /obj/item/food/bread/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) /obj/item/food/bread/root/egg foodtypes = parent_type::foodtypes | MEAT @@ -559,7 +567,7 @@ /obj/item/food/breadslice/root/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_STACK) + AddComponent(/datum/component/ingredients_holder, null, CUSTOM_INGREDIENT_ICON_STACK) /obj/item/food/breadslice/root/egg foodtypes = parent_type::foodtypes | MEAT @@ -597,6 +605,7 @@ foodtypes = VEGETABLES | NUTS | MEAT boxtag = "Italic Flatbread" crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/pizza/flatbread/imperial name = "\improper Imperial flatbread" @@ -611,6 +620,7 @@ foodtypes = VEGETABLES | MEAT | NUTS | GORE boxtag = "Imperial Victory Flatbread" crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 4) /obj/item/food/pizza/flatbread/rawmeat name = "meatlovers flatbread" @@ -623,6 +633,7 @@ tastes = list("bread" = 1, "meat" = 1) foodtypes = MEAT|VEGETABLES|RAW|NUTS crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/pizza/flatbread/stinging name = "\improper Stinging flatbread" @@ -700,6 +711,7 @@ food_flags = FOOD_FINGER_FOOD w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/honey_roll name = "honey sweetroll" @@ -926,6 +938,7 @@ ) foodtypes = MEAT|VEGETABLES|NUTS crafting_complexity = FOOD_COMPLEXITY_3 //Gotta make the dough, +1 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/rat/korta name = "rat rootburger" @@ -956,6 +969,7 @@ foodtypes = NUTS | MEAT | BREAKFAST | VEGETABLES | FRIED venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/burger/rootrib name = "rootrib" @@ -972,6 +986,7 @@ foodtypes = NUTS | MEAT | VEGETABLES | SUGAR venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/burger/rootchicken name = "chicken rootwich" @@ -989,6 +1004,7 @@ foodtypes = NUTS | MEAT | VEGETABLES venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/burger/rootfish name = "Fish rootwich" @@ -1019,3 +1035,4 @@ foodtypes = NUTS | MEAT | VEGETABLES venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) diff --git a/code/game/objects/items/food/martian.dm b/code/game/objects/items/food/martian.dm index b1d8fee480b..be233b18a8a 100644 --- a/code/game/objects/items/food/martian.dm +++ b/code/game/objects/items/food/martian.dm @@ -126,6 +126,7 @@ foodtypes = MEAT|FRIED|GRAIN w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/rice_dough name = "rice dough" @@ -213,6 +214,7 @@ foodtypes = MEAT | GRAIN | PINEAPPLE | FRUIT | VEGETABLES w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/salad/ikareis name = "ikareis" @@ -229,6 +231,7 @@ foodtypes = MEAT | GRAIN | SEAFOOD | VEGETABLES w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/salad/hawaiian_fried_rice name = "\improper Hawaiian fried rice" @@ -260,6 +263,7 @@ foodtypes = MEAT | GRAIN | VEGETABLES w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/salad/mediterranean_fried_rice name = "mediterranean fried rice" @@ -275,6 +279,7 @@ foodtypes = MEAT | GRAIN | VEGETABLES | DAIRY | FRUIT w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/salad/egg_fried_rice name = "egg fried rice" @@ -292,7 +297,7 @@ /obj/item/food/salad/egg_fried_rice/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_STACK) + AddComponent(/datum/component/ingredients_holder, null, CUSTOM_INGREDIENT_ICON_STACK) /obj/item/food/salad/bibimbap name = "bibimbap" @@ -309,10 +314,11 @@ foodtypes = MEAT | VEGETABLES | GRAIN w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/salad/bibimbap/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_STACK) + AddComponent(/datum/component/ingredients_holder, null, CUSTOM_INGREDIENT_ICON_STACK) // Noodles /obj/item/food/salad/bulgogi_noodles @@ -329,6 +335,7 @@ foodtypes = MEAT | GRAIN | VEGETABLES | FRUIT w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/salad/yakisoba_katsu name = "yakisoba katsu" @@ -344,6 +351,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/salad/martian_fried_noodles name = "\improper Martian fried noodles" @@ -359,6 +367,7 @@ foodtypes = GRAIN | NUTS | MEAT | VEGETABLES w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/salad/simple_fried_noodles name = "simple fried noodles" @@ -377,7 +386,7 @@ /obj/item/food/salad/simple_fried_noodles/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_STACK) + AddComponent(/datum/component/ingredients_holder, null, CUSTOM_INGREDIENT_ICON_STACK) // Curry /obj/item/food/salad/setagaya_curry //let me explain... @@ -395,6 +404,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|FRUIT|SUGAR w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_5 //Extensive and secretly guarded. Was previously 2 and I thought it was pathetic. + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) // Burgers and Sandwiches /obj/item/food/burger/big_blue @@ -411,6 +421,7 @@ foodtypes = MEAT | GRAIN | DAIRY | VEGETABLES | FRUIT | PINEAPPLE w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 //It's THE big blue, Baby! + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/burger/chappy name = "\improper Chappy patty" @@ -441,6 +452,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/marte_cubano_sandwich name = "\improper Marte Cubano sandwich" @@ -456,6 +468,7 @@ foodtypes = MEAT | DAIRY | VEGETABLES | GRAIN w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/little_shiro_sandwich name = "\improper Little Shiro sandwich" @@ -472,6 +485,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|DAIRY|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/croque_martienne name = "croque-martienne" @@ -487,6 +501,7 @@ foodtypes = MEAT|GRAIN|FRUIT|DAIRY|FRIED|PINEAPPLE|BREAKFAST w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/prospect_sunrise name = "\improper Prospect Sunrise" @@ -502,6 +517,7 @@ foodtypes = MEAT | DAIRY | VEGETABLES | GRAIN | BREAKFAST w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) // Snacks /obj/item/food/takoyaki @@ -548,6 +564,7 @@ foodtypes = MEAT|GRAIN|FRIED|VEGETABLES|DAIRY|SEAFOOD w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 //Batter AND Cargo ingredients. + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/okonomiyaki name = "okonomiyaki" @@ -566,7 +583,7 @@ //hey, the name literally means "grilled how you like it", it'd be crazy to not make it customisable /obj/item/food/okonomiyaki/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_STACK) + AddComponent(/datum/component/ingredients_holder, null, CUSTOM_INGREDIENT_ICON_STACK) /obj/item/food/brat_kimchi name = "brat-kimchi" @@ -583,6 +600,7 @@ foodtypes = MEAT | VEGETABLES w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/tonkatsuwurst name = "tonkatsuwurst" @@ -598,6 +616,7 @@ foodtypes = MEAT|VEGETABLES|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 //Cargo ingredients and a few steps. + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/kebab/ti_hoeh_koe name = "ti hoeh koe skewer" @@ -642,6 +661,7 @@ foodtypes = GRAIN | MEAT | VEGETABLES | FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/roti_john name = "roti john" @@ -657,6 +677,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|BREAKFAST w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/izakaya_fries name = "izakaya fries" @@ -688,6 +709,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/loco_moco name = "loco moco" @@ -702,6 +724,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/wild_duck_fries name = "wild duck fries" @@ -718,6 +741,7 @@ foodtypes = MEAT | VEGETABLES | FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 //Requires a complex 3 as an ingredient. + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/little_hawaii_hotdog name = "\improper Little Hawaii hotdog" @@ -734,6 +758,7 @@ w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 custom_price = PAYCHECK_CREW * 1.2 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/salt_chilli_fries name = "salt n' chilli fries" @@ -778,6 +803,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|DAIRY|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/chapsilog name = "chapsilog" @@ -840,6 +866,7 @@ foodtypes = MEAT|GRAIN|FRUIT w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/salad/huoxing_tofu name = "\improper Huoxing tofu" @@ -856,6 +883,7 @@ foodtypes = MEAT | VEGETABLES w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/feizhou_ji name = "fēizhōu jī" @@ -871,7 +899,7 @@ foodtypes = MEAT | VEGETABLES w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 - + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/salad/galinha_de_cabidela name = "galinha de cabidela" @@ -886,6 +914,7 @@ foodtypes = MEAT | VEGETABLES | GRAIN w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/salad/katsu_curry name = "katsu curry" @@ -900,6 +929,7 @@ foodtypes = MEAT|GRAIN|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/salad/beef_bowl name = "beef bowl" @@ -915,6 +945,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|SEAFOOD w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/salad/salt_chilli_bowl name = "salt n' chilli octopus bowl" @@ -996,6 +1027,7 @@ foodtypes = MEAT|GRAIN|FRUIT|SUGAR|ORANGES w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) // Desserts /obj/item/food/cake/spekkoek @@ -1213,6 +1245,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|FRUIT|PINEAPPLE|SEAFOOD w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 //Uses Sambal + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) custom_price = PAYCHECK_CREW * 2 /obj/item/food/frickles @@ -1277,6 +1310,7 @@ foodtypes = MEAT | RAW w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/kebab/raw_ballpark_tsukune/make_grillable() AddComponent(/datum/component/grillable, /obj/item/food/kebab/ballpark_tsukune, rand(15 SECONDS, 25 SECONDS), TRUE, TRUE) diff --git a/code/game/objects/items/food/meatdish.dm b/code/game/objects/items/food/meatdish.dm index cd81f6d10aa..34685f5373f 100644 --- a/code/game/objects/items/food/meatdish.dm +++ b/code/game/objects/items/food/meatdish.dm @@ -315,6 +315,7 @@ w_class = WEIGHT_CLASS_SMALL venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/fish_poke name = "fish poke" @@ -420,6 +421,7 @@ foodtypes = MEAT | VEGETABLES w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/bearsteak name = "Filet migrawr" @@ -436,12 +438,14 @@ w_class = WEIGHT_CLASS_SMALL venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/raw_meatball name = "raw meatball" desc = "A great meal all round. Not a cord of wood. Kinda raw" icon = 'icons/obj/food/meat.dmi' icon_state = "raw_meatball" + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) food_reagents = list(/datum/reagent/consumable/nutriment/protein = 2) tastes = list("meat" = 1) foodtypes = MEAT | RAW @@ -486,6 +490,7 @@ icon = 'icons/obj/food/meat.dmi' icon_state = "meatball" inhand_icon_state = "meatball" + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) food_reagents = list(/datum/reagent/consumable/nutriment/protein = 2) tastes = list("meat" = 1) foodtypes = MEAT @@ -518,6 +523,7 @@ desc = "I'm.....NOT REAAADDYY." icon = 'icons/obj/food/meat.dmi' icon_state = "raw_patty" + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) food_reagents = list(/datum/reagent/consumable/nutriment/protein = 2) tastes = list("meat" = 1) foodtypes = MEAT | RAW @@ -555,6 +561,7 @@ desc = "The Nanotrasen patty is the patty for you and me!" icon = 'icons/obj/food/meat.dmi' icon_state = "patty" + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) food_reagents = list(/datum/reagent/consumable/nutriment/protein = 2) tastes = list("meat" = 1) foodtypes = MEAT @@ -597,6 +604,7 @@ eatverbs = list("bite", "chew", "nibble", "deep throat", "gobble", "chomp") w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_1 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/raw_sausage/make_grillable() AddComponent(/datum/component/grillable, /obj/item/food/sausage, rand(60 SECONDS, 75 SECONDS), TRUE) @@ -618,6 +626,7 @@ venue_value = FOOD_PRICE_CHEAP crafting_complexity = FOOD_COMPLEXITY_2 custom_price = PAYCHECK_CREW * 0.6 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/sausage/make_processable() AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/salami, 6, 3 SECONDS, table_required = TRUE, screentip_verb = "Slice") @@ -658,6 +667,7 @@ foodtypes = MEAT|GRAIN|VEGETABLES w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/rawkhinkali/make_grillable() AddComponent(/datum/component/grillable, /obj/item/food/khinkali, rand(50 SECONDS, 60 SECONDS), TRUE) @@ -693,6 +703,7 @@ w_class = WEIGHT_CLASS_SMALL venue_value = FOOD_PRICE_CHEAP crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/stewedsoymeat name = "stewed soy meat" @@ -738,6 +749,7 @@ foodtypes = MEAT|BUGS w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/sashimi name = "spider sashimi" @@ -777,6 +789,7 @@ w_class = WEIGHT_CLASS_TINY venue_value = FOOD_PRICE_CHEAP crafting_complexity = FOOD_COMPLEXITY_1 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) var/meat_source = "\"chicken\"" /obj/item/food/nugget/Initialize(mapload) @@ -808,6 +821,7 @@ w_class = WEIGHT_CLASS_TINY crafting_complexity = FOOD_COMPLEXITY_3 custom_price = PAYCHECK_CREW + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/bbqribs name = "bbq ribs" @@ -823,6 +837,7 @@ tastes = list("meat" = 3, "smokey sauce" = 1) foodtypes = MEAT | SUGAR crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/meatclown name = "meat clown" @@ -838,6 +853,7 @@ w_class = WEIGHT_CLASS_SMALL foodtypes = MEAT | FRUIT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/meatclown/Initialize(mapload) . = ..() @@ -856,6 +872,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|DAIRY venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) //////////////////////////////////////////// KEBABS AND OTHER SKEWERS //////////////////////////////////////////// @@ -879,6 +896,7 @@ tastes = list("tender meat" = 3, "metal" = 1) foodtypes = MEAT | GORE venue_value = FOOD_PRICE_CHEAP + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/kebab/monkey name = "meat-kebab" @@ -890,6 +908,7 @@ tastes = list("meat" = 3, "metal" = 1) foodtypes = MEAT venue_value = FOOD_PRICE_CHEAP + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/kebab/tofu name = "tofu-kebab" @@ -945,6 +964,7 @@ tastes = list("tex-mex" = 3, "cumin" = 2) foodtypes = MEAT | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/fried_chicken name = "fried chicken" @@ -957,6 +977,7 @@ junkiness = 25 w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/fried_chicken/Initialize(mapload) . = ..() @@ -980,6 +1001,7 @@ //basic ingredients, but a lot of them. just covering costs here venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/beef_wellington name = "beef wellington" @@ -995,6 +1017,7 @@ w_class = WEIGHT_CLASS_NORMAL venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_5 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 4) /obj/item/food/beef_wellington/make_processable() AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/beef_wellington_slice, 3, 3 SECONDS, table_required = TRUE, screentip_verb = "Cut") @@ -1028,6 +1051,7 @@ w_class = WEIGHT_CLASS_NORMAL venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_5 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 4) /obj/item/food/korta_wellington/make_processable() AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/korta_wellington_slice, 3, 3 SECONDS, table_required = TRUE, screentip_verb = "Cut") @@ -1061,6 +1085,7 @@ w_class = WEIGHT_CLASS_NORMAL venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_5 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/roast_dinner/make_processable() AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/roast_slice, 3, 3 SECONDS, table_required = TRUE, screentip_verb = "Cut") @@ -1094,6 +1119,7 @@ w_class = WEIGHT_CLASS_NORMAL venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_5 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/roast_dinner_lizzy/make_processable() AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/roast_slice_lizzy, 3, 3 SECONDS, table_required = TRUE, screentip_verb = "Cut") @@ -1160,6 +1186,7 @@ w_class = WEIGHT_CLASS_SMALL venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_5 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 4) /obj/item/food/raw_meatloaf name = "raw meatloaf" @@ -1175,6 +1202,7 @@ foodtypes = MEAT | RAW | VEGETABLES w_class = WEIGHT_CLASS_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/raw_meatloaf/make_bakeable() AddComponent(/datum/component/bakeable, /obj/item/food/meatloaf, rand(30 SECONDS, 40 SECONDS), TRUE, TRUE) @@ -1193,6 +1221,7 @@ foodtypes = MEAT | VEGETABLES w_class = WEIGHT_CLASS_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/meatloaf/make_processable() AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/meatloaf_slice, 4, 3 SECONDS, table_required = TRUE, screentip_verb = "Cut") @@ -1225,6 +1254,7 @@ tastes = list("meat" = 5, "savory sauce" = 4, "tangy pineapple" = 3, "pepper" = 2) foodtypes = MEAT | VEGETABLES | FRUIT | PINEAPPLE crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/kebab/pineapple_skewer name = "pineapple skewer" @@ -1238,6 +1268,7 @@ tastes = list("juicy meat" = 4, "pineapple" = 3) foodtypes = MEAT | FRUIT | PINEAPPLE crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/futomaki_sushi_roll name = "futomaki sushi roll" diff --git a/code/game/objects/items/food/meatslab.dm b/code/game/objects/items/food/meatslab.dm index 179812872e7..561ad192ed5 100644 --- a/code/game/objects/items/food/meatslab.dm +++ b/code/game/objects/items/food/meatslab.dm @@ -1,5 +1,5 @@ /obj/item/food/meat - custom_materials = list(/datum/material/meat = SHEET_MATERIAL_AMOUNT * 4) + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) w_class = WEIGHT_CLASS_SMALL icon = 'icons/obj/food/meat.dmi' var/subjectname = "" @@ -9,7 +9,7 @@ /obj/item/food/meat/Initialize(mapload, blood_dna_list = list("meaty DNA" = get_blood_type(BLOOD_TYPE_MEAT))) . = ..() - if(!blood_decal_type) + if(!blood_decal_type || !length(custom_materials)) return AddComponent( @@ -50,7 +50,7 @@ AddComponent(/datum/component/grillable, /obj/item/food/meat/steak/plain, rand(30 SECONDS, 90 SECONDS), TRUE, TRUE) //Add medium rare later maybe? /obj/item/food/meat/slab/make_processable() - AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/meat/rawcutlet/plain, 3, 3 SECONDS, table_required = TRUE, screentip_verb = "Cut") + AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/meat/rawcutlet/plain, MEATSLAB_PROCESSED_AMOUNT, 3 SECONDS, table_required = TRUE, screentip_verb = "Cut") ///////////////////////////////////// HUMAN MEATS ////////////////////////////////////////////////////// @@ -245,6 +245,7 @@ desc = "A slice from a huge tomato." icon_state = "tomatomeat" food_reagents = list(/datum/reagent/consumable/nutriment = 2) + custom_materials = null tastes = list("tomato" = 1) foodtypes = FRUIT blood_decal_type = /obj/effect/decal/cleanable/food/tomato_smudge @@ -355,6 +356,7 @@ desc = "A raw piece of bacon." icon_state = "bacon" bite_consumption = 2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) food_reagents = list( /datum/reagent/consumable/nutriment/protein = 2, /datum/reagent/consumable/nutriment/fat = 3, @@ -370,6 +372,7 @@ name = "piece of bacon" desc = "A delicious piece of bacon." icon_state = "baconcooked" + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) food_reagents = list( /datum/reagent/consumable/nutriment/protein = 2, /datum/reagent/consumable/nutriment/vitamin = 1, @@ -605,6 +608,7 @@ desc = "A raw meat cutlet." icon_state = "rawcutlet" bite_consumption = 2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) food_reagents = list(/datum/reagent/consumable/nutriment/protein = 2) tastes = list("meat" = 1) foodtypes = MEAT | RAW @@ -715,6 +719,7 @@ desc = "A cooked meat cutlet." icon_state = "cutlet" bite_consumption = 2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) food_reagents = list(/datum/reagent/consumable/nutriment/protein = 2) tastes = list("meat" = 1) foodtypes = MEAT diff --git a/code/game/objects/items/food/mexican.dm b/code/game/objects/items/food/mexican.dm index 5f46e4f917e..7afbe0e30f7 100644 --- a/code/game/objects/items/food/mexican.dm +++ b/code/game/objects/items/food/mexican.dm @@ -62,6 +62,7 @@ w_class = WEIGHT_CLASS_SMALL venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/fuegoburrito name = "fuego plasma burrito" @@ -142,6 +143,7 @@ w_class = WEIGHT_CLASS_SMALL venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/taco/plain name = "plain taco" @@ -164,6 +166,7 @@ tastes = list("taco" = 4, "fish" = 2, "cheese" = 2, "cabbage" = 1) foodtypes = SEAFOOD | DAIRY | GRAIN | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = null /obj/item/food/enchiladas name = "enchiladas" @@ -181,6 +184,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/stuffedlegion name = "stuffed legion" @@ -198,6 +202,7 @@ venue_value = FOOD_PRICE_LEGENDARY crafting_complexity = FOOD_COMPLEXITY_5 crafted_food_buff = /datum/status_effect/food/trait/ashstorm_immune + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/chipsandsalsa name = "chips and salsa" @@ -229,6 +234,7 @@ foodtypes = MEAT | GRAIN | VEGETABLES | DAIRY | FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/vegetarian_chimichanga name = "vegetarian chimichanga" @@ -257,7 +263,7 @@ /obj/item/food/hard_taco_shell/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/hard_taco_shell/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 6) + AddComponent(/datum/component/ingredients_holder, /obj/item/food/hard_taco_shell/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 6) // empty taco shell for custom tacos /obj/item/food/hard_taco_shell/empty @@ -282,6 +288,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN|DAIRY|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/plain_hard_shell_taco name = "plain hard-shell taco" @@ -297,6 +304,7 @@ foodtypes = MEAT|GRAIN|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/refried_beans name = "refried beans" diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm index c2d7b4c6da8..4e5bee86fe3 100644 --- a/code/game/objects/items/food/misc.dm +++ b/code/game/objects/items/food/misc.dm @@ -297,14 +297,6 @@ foodtypes = FRUIT | ALCOHOL crafting_complexity = FOOD_COMPLEXITY_2 -/obj/item/food/melonkeg/CheckParts(list/parts_list) - . = ..() - var/obj/item/reagent_containers/cup/glass/bottle/bottle = locate() in contents - if(!bottle) - return - if(bottle.message_in_a_bottle) - bottle.message_in_a_bottle.forceMove(drop_location()) - /obj/item/food/honeybar name = "honey nut bar" desc = "Oats and nuts compressed together into a bar, held together with a honey glaze." @@ -342,6 +334,7 @@ foodtypes = GRAIN | FRUIT | SUGAR food_flags = FOOD_FINGER_FOOD crafting_complexity = FOOD_COMPLEXITY_5 + custom_materials = list(/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 3) /obj/item/food/branrequests name = "bran requests cereal" @@ -444,6 +437,7 @@ foodtypes = MEAT | DAIRY | GRAIN venue_value = FOOD_PRICE_CHEAP crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/pesto name = "pesto" @@ -513,6 +507,7 @@ foodtypes = MEAT|VEGETABLES|GRAIN w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/seaweedsheet name = "seaweed sheet" @@ -528,7 +523,7 @@ /obj/item/food/seaweedsheet/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/sushi/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 6) + AddComponent(/datum/component/ingredients_holder, /obj/item/food/sushi/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 6) /obj/item/food/seaweedsheet/saltcane name = "dried saltcane sheathe" @@ -573,7 +568,7 @@ /obj/item/food/onigiri/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/onigiri/empty, CUSTOM_INGREDIENT_ICON_NOCHANGE, max_ingredients = 4) + AddComponent(/datum/component/ingredients_holder, /obj/item/food/onigiri/empty, CUSTOM_INGREDIENT_ICON_NOCHANGE, max_ingredients = 4) // empty onigiri for custom onigiri /obj/item/food/onigiri/empty @@ -664,6 +659,7 @@ foodtypes = GRAIN | VEGETABLES | MEAT w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/stuffed_eggplant name = "stuffed eggplant" @@ -678,6 +674,7 @@ foodtypes = VEGETABLES | MEAT | DAIRY w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/moussaka name = "moussaka" @@ -691,6 +688,7 @@ tastes = list("cooked eggplant" = 5, "potato" = 1, "baked veggies" = 2, "meat" = 4, "bechamel sauce" = 3) foodtypes = MEAT|VEGETABLES|GRAIN|DAIRY crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/moussaka/make_processable() AddElement(/datum/element/processable, TOOL_KNIFE, /obj/item/food/moussaka_slice, 4, 3 SECONDS, table_required = TRUE, screentip_verb = "Cut") @@ -800,6 +798,7 @@ foodtypes = VEGETABLES | GRAIN | MEAT w_class = WEIGHT_CLASS_TINY crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/vegetarian_gyro name = "vegetarian gyro" diff --git a/code/game/objects/items/food/moth.dm b/code/game/objects/items/food/moth.dm index db06689d795..92587947a6b 100644 --- a/code/game/objects/items/food/moth.dm +++ b/code/game/objects/items/food/moth.dm @@ -472,6 +472,7 @@ foodtypes = MEAT|GRAIN|FRIED w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/bowled/fried_eggplant_polenta name = "fried eggplant and polenta" diff --git a/code/game/objects/items/food/packaged.dm b/code/game/objects/items/food/packaged.dm index 559e0fa7943..5b5f45a8d28 100644 --- a/code/game/objects/items/food/packaged.dm +++ b/code/game/objects/items/food/packaged.dm @@ -106,6 +106,7 @@ tastes = list("dog food" = 5, "狗肉" = 3) foodtypes = MEAT | GROSS crafting_complexity = FOOD_COMPLEXITY_1 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/canned/envirochow/attack_animal(mob/living/simple_animal/user, list/modifiers) if(!check_buffability(user)) diff --git a/code/game/objects/items/food/pastries.dm b/code/game/objects/items/food/pastries.dm index a46802c496a..f409f83a9a2 100644 --- a/code/game/objects/items/food/pastries.dm +++ b/code/game/objects/items/food/pastries.dm @@ -93,6 +93,7 @@ foodtypes = MEAT|GRAIN|DAIRY w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 2) /obj/item/food/soylenviridians name = "\improper Soylent Virdians" diff --git a/code/game/objects/items/food/pie.dm b/code/game/objects/items/food/pie.dm index de9d7bb2c49..f0131dc9a27 100644 --- a/code/game/objects/items/food/pie.dm +++ b/code/game/objects/items/food/pie.dm @@ -40,7 +40,7 @@ /obj/item/food/pie/plain/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/pie/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) + AddComponent(/datum/component/ingredients_holder, /obj/item/food/pie/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) /obj/item/food/pie/empty name = "pie" @@ -55,7 +55,7 @@ /obj/item/food/pieslice/empty/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) + AddComponent(/datum/component/ingredients_holder, null, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) /obj/item/food/pie/cream name = "banana cream pie" @@ -112,6 +112,7 @@ tastes = list("pie" = 1, "meat" = 1, "salmon" = 1) foodtypes = GRAIN|DAIRY|SUGAR|MEAT|FRUIT crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/pie/meatpie name = "meat-pie" @@ -127,6 +128,7 @@ venue_value = FOOD_PRICE_NORMAL slice_type = /obj/item/food/pieslice/meatpie crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/pieslice/meatpie name = "meat-pie slice" @@ -210,6 +212,7 @@ foodtypes = MEAT|GRAIN|DAIRY slice_type = /obj/item/food/pieslice/xemeatpie crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/pieslice/xemeatpie name = "xeno-pie slice" @@ -464,6 +467,7 @@ slice_type = /obj/item/food/pieslice/shepherds_pie yield = 4 crafting_complexity = FOOD_COMPLEXITY_5 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/pieslice/shepherds_pie name = "shepherds pie slice" diff --git a/code/game/objects/items/food/pizza.dm b/code/game/objects/items/food/pizza.dm index 33aefddd187..a634ab83680 100644 --- a/code/game/objects/items/food/pizza.dm +++ b/code/game/objects/items/food/pizza.dm @@ -178,7 +178,7 @@ /obj/item/food/pizzaslice/margherita/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 12) + AddComponent(/datum/component/ingredients_holder, null, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 12) /obj/item/food/pizza/meat name = "meatpizza" @@ -194,6 +194,7 @@ slice_type = /obj/item/food/pizzaslice/meat boxtag = "Meatlovers' Supreme" crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 4) /obj/item/food/pizza/meat/raw name = "raw meatpizza" @@ -301,6 +302,7 @@ slice_type = /obj/item/food/pizzaslice/donkpocket boxtag = "Bangin' Donk" crafting_complexity = FOOD_COMPLEXITY_3 + intrisic_food_materials = list(/datum/material/meat) //default donkpockets do not contain meat but homemade ones do. /obj/item/food/pizza/donkpocket/raw name = "raw donkpocket pizza" @@ -317,6 +319,7 @@ icon_state = "donkpocketpizzaslice" tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "umami" = 1, "laziness" = 1) foodtypes = GRAIN|VEGETABLES|DAIRY|JUNKFOOD + intrisic_food_materials = list(/datum/material/meat) //default donkpockets do not contain meat but homemade ones do. /obj/item/food/pizza/dank name = "dank pizza" @@ -328,7 +331,7 @@ /datum/reagent/consumable/tomatojuice = 6, /datum/reagent/consumable/nutriment/vitamin = 5, ) - tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "meat" = 1) + tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "weed" = 1) foodtypes = GRAIN | VEGETABLES | DAIRY slice_type = /obj/item/food/pizzaslice/dank boxtag = "Fresh Herb" @@ -347,7 +350,7 @@ name = "dank pizza slice" desc = "So good, man..." icon_state = "dankpizzaslice" - tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "meat" = 1) + tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "weed" = 1) foodtypes = GRAIN | VEGETABLES | DAIRY /obj/item/food/pizza/sassysage @@ -365,6 +368,7 @@ slice_type = /obj/item/food/pizzaslice/sassysage boxtag = "Sausage Lovers" crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/pizza/sassysage/raw name = "raw sassysage pizza" @@ -399,6 +403,7 @@ slice_type = /obj/item/food/pizzaslice/pineapple boxtag = "Honolulu Chew" crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/pizza/pineapple/raw name = "raw Hawaiian pizza" @@ -460,6 +465,7 @@ boxtag = "9mm Pepperoni" foodtypes = MEAT|GRAIN|DAIRY|VEGETABLES crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 4, /datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/pizza/arnold/raw name = "raw Arnold pizza" @@ -543,6 +549,7 @@ foodtypes = GRAIN|TOXIC boxtag = "24 Hour Energy" crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.4, /datum/material/glass = SMALL_MATERIAL_AMOUNT) /obj/item/food/pizza/energy/raw name = "raw energy pizza" @@ -574,6 +581,7 @@ foodtypes = GRAIN|VEGETABLES|DAIRY|MEAT|RAW w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/raw_meat_calzone/make_bakeable() AddComponent(/datum/component/bakeable, /obj/item/food/meat_calzone, rand(20 SECONDS, 40 SECONDS), TRUE, TRUE) @@ -591,6 +599,7 @@ foodtypes = GRAIN|VEGETABLES|DAIRY|MEAT w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/raw_vegetarian_calzone name = "raw vegetarian calzone" diff --git a/code/game/objects/items/food/salad.dm b/code/game/objects/items/food/salad.dm index 58dffd65a60..ccd00ce505e 100644 --- a/code/game/objects/items/food/salad.dm +++ b/code/game/objects/items/food/salad.dm @@ -37,6 +37,7 @@ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/protein = 5, /datum/reagent/consumable/doctor_delight = 8, /datum/reagent/consumable/nutriment/vitamin = 6) tastes = list("leaves" = 1, "potato" = 1, "meat" = 1, "valids" = 1) foodtypes = VEGETABLES | MEAT | FRIED + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/salad/fruit name = "fruit salad" @@ -119,6 +120,7 @@ tastes = list("rice" = 1, "meat" = 1) foodtypes = GRAIN | MEAT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/salad/risotto name = "risotto" @@ -170,6 +172,7 @@ tastes = list("building heat" = 2, "savory meat and vegtables" = 1) foodtypes = GRAIN | MEAT | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/reagent_containers/cup/bowl name = "bowl" @@ -192,7 +195,7 @@ . = ..() RegisterSignal(src, COMSIG_ATOM_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/ingredients_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)), \ @@ -330,3 +333,4 @@ tastes = list("lettuce" = 2, "salami" = 2, "mozzarella cheese" = 2, "tomatoes" = 2, "dressing" = 1) foodtypes = MEAT|VEGETABLES|FRUIT|DAIRY crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) diff --git a/code/game/objects/items/food/sandwichtoast.dm b/code/game/objects/items/food/sandwichtoast.dm index 4c29252bd94..62d766839a9 100644 --- a/code/game/objects/items/food/sandwichtoast.dm +++ b/code/game/objects/items/food/sandwichtoast.dm @@ -13,6 +13,7 @@ food_flags = FOOD_FINGER_FOOD w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/sandwich/cheese name = "cheese sandwich" @@ -26,6 +27,7 @@ foodtypes = GRAIN | DAIRY venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = null /obj/item/food/sandwich/cheese/make_grillable() AddComponent(/datum/component/grillable, /obj/item/food/sandwich/cheese/grilled, rand(30 SECONDS, 60 SECONDS), TRUE) @@ -52,6 +54,7 @@ tastes = list("bread" = 1, "jelly" = 1) foodtypes = GRAIN crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = null /obj/item/food/sandwich/jelly/slime food_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/toxin/slimejelly = 10, /datum/reagent/consumable/nutriment/vitamin = 4) @@ -72,6 +75,7 @@ tastes = list("nothing suspicious" = 1) foodtypes = GRAIN | GROSS crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = null /obj/item/food/griddle_toast name = "griddle toast" @@ -154,6 +158,7 @@ venue_value = FOOD_PRICE_CHEAP crafting_complexity = FOOD_COMPLEXITY_3 custom_price = PAYCHECK_CREW * 0.7 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) // Used for unit tests, do not delete /obj/item/food/hotdog/debug @@ -177,6 +182,7 @@ venue_value = FOOD_PRICE_NORMAL crafting_complexity = FOOD_COMPLEXITY_4 custom_price = PAYCHECK_CREW + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/sandwich/blt name = "\improper BLT" @@ -191,6 +197,7 @@ tastes = list("bacon" = 3, "lettuce" = 2, "tomato" = 2, "bread" = 2) foodtypes = GRAIN | MEAT | VEGETABLES | BREAKFAST crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/sandwich/peanut_butter_jelly name = "peanut butter and jelly sandwich" @@ -204,6 +211,7 @@ tastes = list("peanut butter" = 1, "jelly" = 1, "bread" = 2) foodtypes = GRAIN | FRUIT | NUTS crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = null /obj/item/food/sandwich/peanut_butter_banana name = "peanut butter and banana sandwich" @@ -218,6 +226,7 @@ tastes = list("peanut butter" = 1, "banana" = 1, "bread" = 2) foodtypes = GRAIN | FRUIT | NUTS crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = null /obj/item/food/sandwich/philly_cheesesteak name = "Philly cheesesteak" @@ -231,6 +240,7 @@ tastes = list("bread" = 1, "juicy meat" = 1, "melted cheese" = 1, "onions" = 1) foodtypes = GRAIN | MEAT | DAIRY | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/sandwich/toast_sandwich name = "toast sandwich" @@ -244,6 +254,7 @@ tastes = list("bread" = 2, "Britain" = 1, "butter" = 1, "toast" = 1) foodtypes = GRAIN|DAIRY crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = null /obj/item/food/sandwich/death name = "death sandwich" diff --git a/code/game/objects/items/food/snacks.dm b/code/game/objects/items/food/snacks.dm index dfdd0e5bbe7..9da40b24807 100644 --- a/code/game/objects/items/food/snacks.dm +++ b/code/game/objects/items/food/snacks.dm @@ -71,6 +71,7 @@ w_class = WEIGHT_CLASS_SMALL foodtypes = JUNKFOOD | MEAT | SUGAR crafting_complexity = FOOD_COMPLEXITY_1 + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT) /obj/item/food/sosjerky/healthy name = "homemade beef jerky" diff --git a/code/game/objects/items/food/spaghetti.dm b/code/game/objects/items/food/spaghetti.dm index feb299101fc..30e2a05a858 100644 --- a/code/game/objects/items/food/spaghetti.dm +++ b/code/game/objects/items/food/spaghetti.dm @@ -43,7 +43,7 @@ /obj/item/food/spaghetti/boiledspaghetti/Initialize(mapload) . = ..() - AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_SCATTER, max_ingredients = 6) + AddComponent(/datum/component/ingredients_holder, null, CUSTOM_INGREDIENT_ICON_SCATTER, max_ingredients = 6) /obj/item/food/spaghetti/pastatomato name = "spaghetti" @@ -100,6 +100,7 @@ tastes = list("pasta" = 1, "meat" = 1) foodtypes = GRAIN | MEAT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/spaghetti/spesslaw name = "spesslaw" @@ -113,6 +114,7 @@ tastes = list("pasta" = 1, "meat" = 1) foodtypes = GRAIN | MEAT crafting_complexity = FOOD_COMPLEXITY_2 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 4) /obj/item/food/spaghetti/chowmein name = "chow mein" @@ -126,6 +128,7 @@ tastes = list("noodle" = 1, "meat" = 1, "fried vegetables" = 1) foodtypes = GRAIN | MEAT | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/spaghetti/beefnoodle name = "beef noodle" @@ -141,6 +144,7 @@ tastes = list("noodles" = 1, "meat" = 1) foodtypes = GRAIN | MEAT | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/spaghetti/butternoodles name = "butter noodles" @@ -179,6 +183,7 @@ tastes = list("noodles" = 5, "meat" = 3, "egg" = 4, "dried seaweed" = 2) foodtypes = GRAIN | MEAT | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/spaghetti/kitakata_ramen name = "kitakata ramen" @@ -193,6 +198,7 @@ tastes = list("noodles" = 5, "meat" = 4, "mushrooms" = 3, "onion" = 2) foodtypes = GRAIN | MEAT | VEGETABLES crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/spaghetti/kitsune_udon name = "kitsune udon" @@ -221,6 +227,7 @@ tastes = list("noodles" = 5, "meat" = 4, "potato" = 3, "onion" = 2, "mixed veggies" = 2) foodtypes = GRAIN | VEGETABLES | MEAT crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT * 2) /obj/item/food/spaghetti/pho name = "pho" @@ -235,6 +242,7 @@ tastes = list("noodles" = 5, "meat" = 4, "cabbage" = 3, "onion" = 2, "herbs" = 2) foodtypes = GRAIN | VEGETABLES | MEAT crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/spaghetti/pad_thai name = "pad thai" @@ -262,6 +270,7 @@ tastes = list("spaghetti" = 1, "parmigiano reggiano" = 1, "guanciale" = 1) foodtypes = GRAIN | MEAT | DAIRY crafting_complexity = FOOD_COMPLEXITY_4 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) /obj/item/food/spaghetti/carbonara/Initialize(mapload) . = ..() diff --git a/code/game/objects/items/food/vegetables.dm b/code/game/objects/items/food/vegetables.dm index 000ada0907c..3730d1a3feb 100644 --- a/code/game/objects/items/food/vegetables.dm +++ b/code/game/objects/items/food/vegetables.dm @@ -99,6 +99,7 @@ foodtypes = VEGETABLES | DAIRY | MEAT w_class = WEIGHT_CLASS_SMALL crafting_complexity = FOOD_COMPLEXITY_3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) // Fries /obj/item/food/fries diff --git a/code/game/objects/items/spear.dm b/code/game/objects/items/spear.dm index 0bd8cae7d3f..ee84f9a8dd3 100644 --- a/code/game/objects/items/spear.dm +++ b/code/game/objects/items/spear.dm @@ -77,8 +77,8 @@ user.visible_message(span_suicide("[user] begins to sword-swallow \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) return BRUTELOSS -/obj/item/spear/CheckParts(list/parts_list) - var/obj/item/shard/tip = locate() in parts_list +/obj/item/spear/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + var/obj/item/shard/tip = locate() in components if(!tip) return ..() @@ -116,8 +116,6 @@ AddComponent(/datum/component/two_handed, force_unwielded=force_unwielded, force_wielded=force_wielded, icon_wielded="[icon_prefix]1") update_appearance() - parts_list -= tip - qdel(tip) return ..() /obj/item/spear/explosive @@ -138,17 +136,14 @@ explosive = G desc = "A makeshift spear with [G] attached to it" -/obj/item/spear/explosive/CheckParts(list/parts_list) - var/obj/item/grenade/G = locate() in parts_list - if(G) - var/obj/item/spear/lancePart = locate() in parts_list +/obj/item/spear/explosive/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + var/obj/item/grenade/nade = locate() in components + if(nade) + var/obj/item/spear/lancePart = locate() in components throwforce = lancePart.throwforce icon_prefix = lancePart.icon_prefix - parts_list -= G - parts_list -= lancePart - set_explosive(G) - qdel(lancePart) - ..() + set_explosive(nade) + return ..() /obj/item/spear/explosive/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] begins to sword-swallow \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 66a01dfbfa3..12405255be3 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -243,27 +243,26 @@ // MEAT MEAT MEAT MEAT MEAT +///This nullifies the force malus from the meat material while not touching other stats. +#define INVERSE_MEAT_STRENTGH (1 / /datum/material/meat::strength_modifier) + /obj/item/storage/backpack/meat name = "\improper MEAT" desc = "MEAT MEAT MEAT MEAT MEAT MEAT" icon_state = "meatmeatmeat" inhand_icon_state = "meatmeatmeat" - force = 15 - throwforce = 15 + force = 15 * INVERSE_MEAT_STRENTGH + throwforce = 15 * INVERSE_MEAT_STRENTGH + material_flags = MATERIAL_EFFECTS | MATERIAL_AFFECT_STATISTICS attack_verb_continuous = list("MEATS", "MEAT MEATS") attack_verb_simple = list("MEAT", "MEAT MEAT") - custom_materials = list(/datum/material/meat = SHEET_MATERIAL_AMOUNT * 25) // MEAT + custom_materials = list(/datum/material/meat = SHEET_MATERIAL_AMOUNT * 15) // MEAT ///Sounds used in the squeak component var/list/meat_sounds = list('sound/effects/blob/blobattack.ogg' = 1) - ///Reagents added to the edible component, ingested when you EAT the MEAT + ///Reagents added to the edible component on top of the meat material, ingested when you EAT the MEAT var/list/meat_reagents = list( - /datum/reagent/consumable/nutriment/protein = 10, - /datum/reagent/consumable/nutriment/vitamin = 10, + /datum/reagent/consumable/nutriment/vitamin = 15, ) - ///The food types of the edible component - var/foodtypes = MEAT | RAW - ///How our MEAT tastes. It tastes like MEAT - var/list/tastes = list("MEAT" = 1) ///Eating verbs when consuming the MEAT var/list/eatverbs = list("MEAT", "absorb", "gnaw", "consume") @@ -273,21 +272,13 @@ SOURCE_EDIBLE_INNATE, \ /datum/component/edible,\ initial_reagents = meat_reagents,\ - foodtypes = foodtypes,\ - tastes = tastes,\ + tastes = list("meat" = 1),\ eatverbs = eatverbs,\ ) + AddComponent(/datum/component/squeak, meat_sounds) - AddComponent( - /datum/component/blood_walk,\ - blood_type = /obj/effect/decal/cleanable/blood,\ - blood_spawn_chance = 15,\ - max_blood = custom_materials[custom_materials[1]] / SHEET_MATERIAL_AMOUNT,\ - ) - AddComponent( - /datum/component/bloody_spreader,\ - blood_left = custom_materials[custom_materials[1]] / SHEET_MATERIAL_AMOUNT,\ - ) + +#undef INVERSE_MEAT_STRENTGH /* * Satchel Types diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm index 618c5ed57b4..8ea02a9a462 100644 --- a/code/game/objects/items/storage/storage.dm +++ b/code/game/objects/items/storage/storage.dm @@ -99,6 +99,12 @@ /obj/item/storage/proc/get_types_to_preload() return +/obj/item/storage/used_in_craft(atom/result, datum/crafting_recipe/current_recipe) + . = ..() + // If we consumed in crafting, we should dump contents out before qdeling them. + if(!is_type_in_list(src, current_recipe.parts)) + emptyStorage() + /// Removes an item or puts it in mouth from the contents, if any /obj/item/storage/proc/quick_remove_item(obj/item/grabbies, mob/user, equip_to_mouth = FALSE) var/obj/item/finger = locate(grabbies) in contents diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index f51ffd339f9..fcd618dda70 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -326,28 +326,18 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) . = ..() if(!(material_flags & MATERIAL_AFFECT_STATISTICS)) return - if(uses_integrity) - var/integrity_mod = GET_MATERIAL_MODIFIER(material.integrity_modifier, multiplier) - modify_max_integrity(ceil(max_integrity * integrity_mod)) var/strength_mod = GET_MATERIAL_MODIFIER(material.strength_modifier, multiplier) force *= strength_mod throwforce *= strength_mod - var/list/armor_mods = material.get_armor_modifiers(multiplier) - set_armor(get_armor().generate_new_with_multipliers(armor_mods)) ///This proc is called when the material is removed from an object specifically. /obj/remove_single_mat_effect(datum/material/material, mat_amount, multiplier) . = ..() if(!(material_flags & MATERIAL_AFFECT_STATISTICS)) return - if(uses_integrity) - var/integrity_mod = GET_MATERIAL_MODIFIER(material.integrity_modifier, multiplier) - modify_max_integrity(floor(max_integrity / integrity_mod)) var/strength_mod = GET_MATERIAL_MODIFIER(material.strength_modifier, multiplier) force /= strength_mod throwforce /= strength_mod - var/list/armor_mods = material.get_armor_modifiers(1 / multiplier) - set_armor(get_armor().generate_new_with_multipliers(armor_mods)) /// Returns modifier to how much damage this object does to a target considered vulnerable to "demolition" (other objects, robots, etc) /obj/proc/get_demolition_modifier(obj/target) diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 193a5c8b669..6fd74ecaac5 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -77,3 +77,9 @@ flying_mob.apply_damage(damage = rand(5, 15), damagetype = BRUTE, wound_bonus = 15, bare_wound_bonus = 25, sharpness = SHARP_EDGED, attack_direction = get_dir(src, oldloc)) new /obj/effect/decal/cleanable/glass(get_step(flying_mob, flying_mob.dir)) deconstruct(disassembled = FALSE) + +/obj/structure/used_in_craft(atom/result, datum/crafting_recipe/current_recipe) + . = ..() + // If we consumed in crafting, we should dump contents out before qdeling them. + if(!is_type_in_list(src, current_recipe.parts)) + dump_contents() diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 827da840f2d..a1c3f213d1a 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -614,21 +614,22 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) if(!broken) bust_open() -/obj/structure/closet/CheckParts(list/parts_list) - var/obj/item/electronics/airlock/access_control = locate() in parts_list +/obj/structure/closet/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + var/obj/item/electronics/airlock/access_control = locate() in components if(QDELETED(access_control)) - return + return ..() + inherit_airlock_electronics_access(access_control) + + return ..() + +/obj/structure/closet/proc/inherit_airlock_electronics_access(obj/item/electronics/airlock/access_control) if (access_control.one_access) req_one_access = access_control.accesses req_access = null else req_access = access_control.accesses req_one_access = null - access_control.moveToNullspace() - - parts_list -= access_control - qdel(access_control) /obj/structure/closet/multitool_act(mob/living/user, obj/item/tool) if(!secure || !card_reader_installed || broken || locked || opened) @@ -742,7 +743,8 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) if(!user.transferItemToLoc(weapon, src)) return - CheckParts(list(weapon)) + inherit_airlock_electronics_access(weapon) + qdel(weapon) secure = TRUE balloon_alert(user, "electronics installed") diff --git a/code/game/objects/structures/headpike.dm b/code/game/objects/structures/headpike.dm index d7a46463118..c9b9562ce73 100644 --- a/code/game/objects/structures/headpike.dm +++ b/code/game/objects/structures/headpike.dm @@ -24,7 +24,9 @@ /obj/structure/headpike/Initialize(mapload) . = ..() if(mapload) - CheckParts() + spear = new speartype(src) + victim = new(src) + victim.real_name = generate_random_name() pixel_x = rand(-8, 8) /obj/structure/headpike/Destroy() @@ -32,16 +34,11 @@ QDEL_NULL(spear) return ..() -/obj/structure/headpike/CheckParts(list/parts_list) - victim = locate() in parts_list - if(!victim) //likely a mapspawned one - victim = new(src) - victim.real_name = generate_random_name() - spear = locate(speartype) in parts_list - if(!spear) - spear = new speartype(src) +/obj/structure/headpike/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + . = ..() + victim = locate() in contents + spear = locate(speartype) in contents update_appearance() - return ..() /obj/structure/headpike/update_name() name = "[victim.real_name] on a [spear.name]" diff --git a/code/game/objects/structures/toiletbong.dm b/code/game/objects/structures/toiletbong.dm index 6d4c8d64ee3..fa770dd75ee 100644 --- a/code/game/objects/structures/toiletbong.dm +++ b/code/game/objects/structures/toiletbong.dm @@ -17,6 +17,21 @@ weed_overlay = mutable_appearance('icons/obj/watercloset.dmi', "[base_icon_state]_overlay") START_PROCESSING(SSobj, src) +/obj/structure/toiletbong/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + var/obj/structure/toilet/toilet = locate(/obj/structure/toilet) in components + if(toilet) + for(var/obj/item/cistern_item in toilet.contents) + cistern_item.forceMove(crafter.drop_location()) + to_chat(crafter, span_warning("[cistern_item] falls out of the toilet!")) + setDir(toilet.dir) + forceMove(toilet.loc) + + crafter.visible_message( + span_notice("[crafter] attaches the flamethrower to the repurposed toilet."), + span_notice("You attach the flamethrower to the repurposed toilet."), + ) + return ..() + /obj/structure/toiletbong/update_overlays() . = ..() if (LAZYLEN(contents)) diff --git a/code/modules/events/holiday/easter.dm b/code/modules/events/holiday/easter.dm index 3e77def2581..b26e4c6a016 100644 --- a/code/modules/events/holiday/easter.dm +++ b/code/modules/events/holiday/easter.dm @@ -160,6 +160,7 @@ icon = 'icons/obj/food/egg.dmi' icon_state = "scotchegg" bite_consumption = 3 + custom_materials = list(/datum/material/meat = MEATDISH_MATERIAL_AMOUNT) food_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 2) crafting_complexity = FOOD_COMPLEXITY_2 foodtypes = MEAT diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index 361520f2d15..2a8e7dc6cb0 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -35,7 +35,7 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( obj_flags = UNIQUE_RENAME item_flags = SLOWS_WHILE_IN_HAND //we handle slowdowns internally, and the fish weight modifier from materials already contributes to it. - material_flags = MATERIAL_EFFECTS|MATERIAL_AFFECT_STATISTICS|MATERIAL_COLOR|MATERIAL_ADD_PREFIX|MATERIAL_NO_SLOWDOWN + material_flags = MATERIAL_EFFECTS|MATERIAL_AFFECT_STATISTICS|MATERIAL_COLOR|MATERIAL_ADD_PREFIX|MATERIAL_NO_SLOWDOWN|MATERIAL_NO_EDIBILITY /// Flags for fish variables that would otherwise be TRUE/FALSE var/fish_flags = FISH_FLAG_SHOW_IN_CATALOG|FISH_DO_FLOP_ANIM|FISH_FLAG_EXPERIMENT_SCANNABLE diff --git a/code/modules/food_and_drinks/recipes/food_mixtures.dm b/code/modules/food_and_drinks/recipes/food_mixtures.dm index e90f3ac6dbc..0440c4780bf 100644 --- a/code/modules/food_and_drinks/recipes/food_mixtures.dm +++ b/code/modules/food_and_drinks/recipes/food_mixtures.dm @@ -1,21 +1,18 @@ /datum/crafting_recipe/food mass_craftable = TRUE - crafting_flags = parent_type::crafting_flags | CRAFT_TRANSFERS_REAGENTS | CRAFT_CLEARS_REAGENTS + requirements_mats_blacklist = list( + /obj/item/reagent_containers/cup/bowl, + /obj/item/popsicle_stick, + /obj/item/stack/rods, + ) + crafting_flags = parent_type::crafting_flags | CRAFT_TRANSFERS_REAGENTS | CRAFT_CLEARS_REAGENTS | CRAFT_ENFORCE_MATERIALS_PARITY ///The food types that are added to the result when the recipe is completed var/added_foodtypes = NONE ///The food types that are removed to the result when the recipe is completed var/removed_foodtypes = NONE -/datum/crafting_recipe/food/on_craft_completion(mob/user, atom/result) - SHOULD_CALL_PARENT(TRUE) - . = ..() - if(istype(result) && istype(user) && !isnull(user.mind)) - ADD_TRAIT(result, TRAIT_FOOD_CHEF_MADE, REF(user.mind)) - /datum/crafting_recipe/food/New() . = ..() - parts |= reqs - //rarely, but a few cooking recipes (cake cat & co) don't result food items. if(!PERFORM_ALL_TESTS(focus_only/check_foodtypes) || non_craftable || !ispath(result, /obj/item/food)) return diff --git a/code/modules/food_and_drinks/recipes/processor_recipes.dm b/code/modules/food_and_drinks/recipes/processor_recipes.dm index 14f93b45cd8..f0deb6e0bb8 100644 --- a/code/modules/food_and_drinks/recipes/processor_recipes.dm +++ b/code/modules/food_and_drinks/recipes/processor_recipes.dm @@ -22,7 +22,7 @@ /obj/item/food/meat/slab/xeno, /obj/item/food/meat/slab/bear, /obj/item/food/meat/slab/chicken) - food_multiplier = 3 + food_multiplier = MEATSLAB_PROCESSED_AMOUNT /datum/food_processor_process/cutlet input = /obj/item/food/meat/cutlet/plain diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_burger.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_burger.dm index 9f857a73a9b..be01b1f6293 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_burger.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_burger.dm @@ -10,9 +10,6 @@ /obj/item/food/bun = 1, /obj/item/food/patty/human = 1 ) - parts = list( - /obj/item/food/patty = 1 - ) result = /obj/item/food/burger/human category = CAT_BURGER @@ -304,7 +301,7 @@ /obj/item/stack/sheet/mineral/plasma = 2, /obj/item/food/bun = 1 ) - + requirements_mats_blacklist = list(/obj/item/stack/sheet/mineral/plasma) result = /obj/item/food/burger/empoweredburger added_foodtypes = TOXIC category = CAT_BURGER diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm index 5a7947c569e..74c1ce5f6d3 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm @@ -1,10 +1,5 @@ - // This is the home of drink related tablecrafting recipes, I have opted to only let players bottle fancy boozes to reduce the number of entries. -///Abstract types for all drink recipes that use bottles and result in another bottle, so that the message_in_a_bottle item is properly transferred. -/datum/crafting_recipe/bottled - parts = list(/obj/item/reagent_containers/cup/glass/bottle = 1) - ///////////////// Booze & Bottles /////////////////// /datum/crafting_recipe/lizardwine @@ -18,7 +13,7 @@ result = /obj/item/reagent_containers/cup/glass/bottle/lizardwine category = CAT_DRINK -/datum/crafting_recipe/bottled/moonshinejug +/datum/crafting_recipe/moonshinejug name = "Moonshine Jug" time = 30 reqs = list( @@ -28,7 +23,7 @@ result = /obj/item/reagent_containers/cup/glass/bottle/moonshine category = CAT_DRINK -/datum/crafting_recipe/bottled/hoochbottle +/datum/crafting_recipe/hoochbottle name = "Hooch Bottle" time = 30 reqs = list( @@ -39,7 +34,7 @@ result = /obj/item/reagent_containers/cup/glass/bottle/hooch category = CAT_DRINK -/datum/crafting_recipe/bottled/blazaambottle +/datum/crafting_recipe/blazaambottle name = "Blazaam Bottle" time = 20 reqs = list( @@ -49,7 +44,7 @@ result = /obj/item/reagent_containers/cup/glass/bottle/blazaam category = CAT_DRINK -/datum/crafting_recipe/bottled/champagnebottle +/datum/crafting_recipe/champagnebottle name = "Champagne Bottle" time = 30 reqs = list( @@ -59,7 +54,7 @@ result = /obj/item/reagent_containers/cup/glass/bottle/champagne category = CAT_DRINK -/datum/crafting_recipe/bottled/trappistbottle +/datum/crafting_recipe/trappistbottle name = "Trappist Bottle" time = 15 reqs = list( @@ -69,7 +64,7 @@ result = /obj/item/reagent_containers/cup/glass/bottle/trappist category = CAT_DRINK -/datum/crafting_recipe/bottled/goldschlagerbottle +/datum/crafting_recipe/goldschlagerbottle name = "Goldschlager Bottle" time = 30 reqs = list( @@ -79,7 +74,7 @@ result = /obj/item/reagent_containers/cup/glass/bottle/goldschlager category = CAT_DRINK -/datum/crafting_recipe/bottled/patronbottle +/datum/crafting_recipe/patronbottle name = "Patron Bottle" time = 30 reqs = list( @@ -91,7 +86,7 @@ ////////////////////// Non-alcoholic recipes /////////////////// -/datum/crafting_recipe/bottled/holybottle +/datum/crafting_recipe/holybottle name = "Holy Water Flask" time = 30 reqs = list( @@ -103,7 +98,7 @@ //flask of unholy water is a beaker for some reason, I will try making it a bottle and add it here once the antag freeze is over. t. kryson -/datum/crafting_recipe/bottled/nothingbottle +/datum/crafting_recipe/nothingbottle name = "Nothing Bottle" time = 30 reqs = list( @@ -120,7 +115,7 @@ reqs = list(/obj/item/stack/sheet/cardboard = 1) category = CAT_CONTAINERS -/datum/crafting_recipe/bottled/candycornliquor +/datum/crafting_recipe/candycornliquor name = "candy corn liquor" result = /obj/item/reagent_containers/cup/glass/bottle/candycornliquor time = 30 @@ -129,7 +124,7 @@ /obj/item/reagent_containers/cup/glass/bottle = 1) category = CAT_DRINK -/datum/crafting_recipe/bottled/kong +/datum/crafting_recipe/kong name = "Kong" result = /obj/item/reagent_containers/cup/glass/bottle/kong time = 30 @@ -143,8 +138,11 @@ result = /obj/item/reagent_containers/cup/glass/bottle/pruno time = 30 reqs = list(/obj/item/storage/bag/trash = 1, - /obj/item/food/breadslice/moldy = 1, - /obj/item/food/grown = 4, - /obj/item/food/candy_corn = 2, - /datum/reagent/water = 15) + /obj/item/food/breadslice/moldy = 1, + /obj/item/food/grown = 4, + /obj/item/food/candy_corn = 2, + /datum/reagent/water = 15, + ) + //We can't spawn the abstract food/grown path + unit_test_spawn_extras = list(/obj/item/food/grown/banana = 4) category = CAT_DRINK 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 4d028de06fb..313eb635853 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_guide.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_guide.dm @@ -18,6 +18,7 @@ /datum/crafting_recipe/runed_metal reqs = list(/obj/item/stack/sheet/plasteel = 1) + requirements_mats_blacklist = list(/obj/item/stack/sheet/plasteel) // runed metal has its own material result = /obj/item/stack/sheet/runed_metal category = CAT_CULT non_craftable = TRUE 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 8b7a523f78e..5a0ba09e413 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm @@ -32,7 +32,6 @@ blacklist = list( /obj/item/organ/lungs/cybernetic, ) - result = /obj/item/food/shredded_lungs added_foodtypes = MEAT|GORE 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 e2c09cfe02c..40051d67cb5 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm @@ -27,10 +27,8 @@ /datum/crafting_recipe/food/chococoin name = "Choco coin" - reqs = list( - /obj/item/coin = 1, - /obj/item/food/chocolatebar = 1, - ) + reqs = list(/obj/item/food/chocolatebar = 1) + tool_paths = list(/obj/item/coin) result = /obj/item/food/chococoin category = CAT_MISCFOOD @@ -97,7 +95,6 @@ /obj/item/food/grown/holymelon = 1, /obj/item/reagent_containers/cup/glass/bottle/vodka = 1 ) - parts = list(/obj/item/reagent_containers/cup/glass/bottle/vodka = 1) result = /obj/item/food/melonkeg added_foodtypes = ALCOHOL category = CAT_MISCFOOD diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm index 75f52d816c3..d3c761a64f1 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm @@ -15,15 +15,6 @@ removed_foodtypes = RAW category = CAT_PASTRY -// It is so stupid that we have to do this but because food crafting clears all reagents that got added during init, -// here we are adding it again (but only for crafting, maploaded and spawned donuts work fine). -// Until the issues with crafted items' reagents are resolved this will have to do -/datum/crafting_recipe/food/donut/on_craft_completion(mob/user, atom/result) - . = ..() - var/obj/item/food/donut/donut_result = result - if(donut_result.is_decorated) - donut_result.reagents.add_reagent(/datum/reagent/consumable/sprinkles, 1) - /datum/crafting_recipe/food/donut/chaos name = "Chaos donut" reqs = list( diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm index 5eff8da6318..7b7b2c95830 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm @@ -262,6 +262,7 @@ /obj/item/food/pie/plain = 1, /obj/item/stock_parts/power_store/cell = 2, ) + requirements_mats_blacklist = list(/obj/item/stock_parts/power_store/cell) result = /obj/item/food/pie/bacid_pie added_foodtypes = TOXIC category = CAT_PIE diff --git a/code/modules/manufactorio/machines/crafter.dm b/code/modules/manufactorio/machines/crafter.dm index f17efc27c4e..b6f9a653cdb 100644 --- a/code/modules/manufactorio/machines/crafter.dm +++ b/code/modules/manufactorio/machines/crafter.dm @@ -106,6 +106,9 @@ if(istext(result)) say("Crafting failed[result]") return + if(isstack(result)) //it doesn't have hands to pick up stacks so let's try to merge them instead + var/obj/item/stack/stack = result + stack.merge_with_loc() var/list/diff = get_overfloor_objects() - prediff for(var/atom/movable/diff_result as anything in diff) if(iseffect(diff_result) || ismob(diff_result)) // PLEASE dont stuff cats (or other mobs) into the cat grinder 9000 @@ -114,7 +117,6 @@ diff_result.pixel_x += rand(-4, 4) diff_result.pixel_y += rand(-4, 4) withheld += WEAKREF(diff_result) - recipe.on_craft_completion(src, diff_result) send_withheld() /obj/machinery/power/manufacturing/crafter/cooker diff --git a/code/modules/mob/living/basic/bots/medbot/medbot.dm b/code/modules/mob/living/basic/bots/medbot/medbot.dm index fb11d53790d..94eefc283f7 100644 --- a/code/modules/mob/living/basic/bots/medbot/medbot.dm +++ b/code/modules/mob/living/basic/bots/medbot/medbot.dm @@ -162,6 +162,15 @@ if(!CONFIG_GET(flag/no_default_techweb_link) && !linked_techweb) CONNECT_TO_RND_SERVER_ROUNDSTART(linked_techweb, src) +/mob/living/basic/bot/medbot/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + . = ..() + var/obj/item/storage/medkit/medkit = locate() in contents + medkit_type = medkit + health_analyzer = locate(/obj/item/healthanalyzer) in contents + skin = medkit.get_medbot_skin() + damage_type_healer = initial(medkit.damagetype_healed) ? initial(medkit.damagetype_healed) : BRUTE + update_appearance() + /mob/living/basic/bot/medbot/update_icon_state() . = ..() diff --git a/code/modules/mob/living/basic/pets/cat/cat.dm b/code/modules/mob/living/basic/pets/cat/cat.dm index 8c51c100eb5..4a9d1c95344 100644 --- a/code/modules/mob/living/basic/pets/cat/cat.dm +++ b/code/modules/mob/living/basic/pets/cat/cat.dm @@ -193,6 +193,8 @@ /obj/item/food/breadslice/plain = 1 ) collar_icon_state = null + //just ensuring the mats contained by the cat when spawned are the same of when crafted + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 3) /mob/living/basic/pet/cat/breadcat/add_cell_sample() return diff --git a/code/modules/mob/living/basic/pets/cat/keeki.dm b/code/modules/mob/living/basic/pets/cat/keeki.dm index 93bafae582b..9f48a13dbf2 100644 --- a/code/modules/mob/living/basic/pets/cat/keeki.dm +++ b/code/modules/mob/living/basic/pets/cat/keeki.dm @@ -21,6 +21,8 @@ death_sound = SFX_BODYFALL held_state = "cak" can_interact_with_stove = TRUE + //just ensuring the mats contained by the cat when spawned are the same of when crafted + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 3) /mob/living/basic/pet/cat/cak/Initialize(mapload) . = ..() @@ -38,7 +40,7 @@ /mob/living/basic/pet/cat/cak/add_cell_sample() return -/mob/living/basic/pet/cat/cak/CheckParts(list/parts) +/mob/living/basic/pet/cat/cak/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) . = ..() var/obj/item/organ/brain/candidate = locate(/obj/item/organ/brain) in contents if(isnull(candidate?.brainmob?.mind)) diff --git a/code/modules/mob/living/basic/pets/dog/dog_subtypes.dm b/code/modules/mob/living/basic/pets/dog/dog_subtypes.dm index 1d6dc3e6ee4..fa9dffb0f10 100644 --- a/code/modules/mob/living/basic/pets/dog/dog_subtypes.dm +++ b/code/modules/mob/living/basic/pets/dog/dog_subtypes.dm @@ -98,8 +98,10 @@ attacked_sound = 'sound/items/eatfood.ogg' held_state = "breaddog" worn_slot_flags = ITEM_SLOT_HEAD + //just ensuring the mats contained by the dog when spawned are the same of when crafted + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 3) -/mob/living/basic/pet/dog/breaddog/CheckParts(list/parts) +/mob/living/basic/pet/dog/breaddog/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) . = ..() var/obj/item/organ/brain/candidate = locate(/obj/item/organ/brain) in contents if(!candidate || !candidate.brainmob || !candidate.brainmob.mind) diff --git a/code/modules/mob/living/basic/space_fauna/bear/_bear.dm b/code/modules/mob/living/basic/space_fauna/bear/_bear.dm index 75c9f44a53f..c198d47c196 100644 --- a/code/modules/mob/living/basic/space_fauna/bear/_bear.dm +++ b/code/modules/mob/living/basic/space_fauna/bear/_bear.dm @@ -138,6 +138,8 @@ attack_vis_effect = ATTACK_EFFECT_DISARM attack_verb_simple = "slap" attack_verb_continuous = "slaps" + //just ensuring the mats contained by the bear when spawned are the same of when crafted + custom_materials = list(/datum/material/meat = MEATSLAB_MATERIAL_AMOUNT * 5) /mob/living/basic/bear/butter/Initialize(mapload) . = ..() @@ -159,7 +161,7 @@ user.reagents.add_reagent(/datum/reagent/consumable/nutriment, 1) user.reagents.add_reagent(/datum/reagent/consumable/nutriment/vitamin, 0.1) -/mob/living/basic/bear/butter/CheckParts(list/parts) //Borrowed code from Cak, allows the brain used to actually control the bear. +/mob/living/basic/bear/butter/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) //Borrowed code from Cak, allows the brain used to actually control the bear. . = ..() var/obj/item/organ/brain/candidate = locate(/obj/item/organ/brain) in contents if(!candidate || !candidate.brainmob || !candidate.brainmob.mind) diff --git a/code/modules/mod/mod_core.dm b/code/modules/mod/mod_core.dm index f9c3793b074..caf162c9c41 100644 --- a/code/modules/mod/mod_core.dm +++ b/code/modules/mod/mod_core.dm @@ -553,14 +553,12 @@ greyscale_colors = "#00ff00" return ..() -/obj/item/mod/core/soul/CheckParts(list/parts_list, datum/crafting_recipe/current_recipe) - var/obj/item/soulstone/stone = locate() in parts_list +/obj/item/mod/core/soul/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + var/obj/item/soulstone/stone = locate() in components set_theme(stone.theme) for(var/mob/living/basic/shade/shade in stone) shade.forceMove(get_turf(src)) shade.visible_message(span_warning("[shade] is ejected from [stone] as it is inserted into [src]!"), span_warning("You are ejected from [stone] as it is inserted into [src]!")) - parts_list -= stone - qdel(stone) return ..() /obj/item/mod/core/soul/proc/set_theme(new_theme) diff --git a/code/modules/reagents/chemistry/holder/holder.dm b/code/modules/reagents/chemistry/holder/holder.dm index ef2a27feb1a..9bde908c1c0 100644 --- a/code/modules/reagents/chemistry/holder/holder.dm +++ b/code/modules/reagents/chemistry/holder/holder.dm @@ -339,7 +339,8 @@ datum/reagent/source_reagent_typepath, datum/reagent/target_reagent_typepath, multiplier = 1, - include_source_subtypes = FALSE + include_source_subtypes = FALSE, + keep_data = FALSE, ) if(!ispath(source_reagent_typepath)) stack_trace("invalid reagent path passed to convert reagent [source_reagent_typepath]") @@ -352,6 +353,8 @@ var/weighted_purity = 0 var/weighted_ph = 0 var/reagent_volume = 0 + ///Stores the data value of the reagent to be converted if keep_data is TRUE. Might not work well if include_source_subtypes is TRUE. + var/list/reagent_data var/list/cached_reagents = reagent_list for(var/datum/reagent/cached_reagent as anything in cached_reagents) @@ -370,6 +373,8 @@ //zero the volume out so it gets removed cached_reagent.volume = 0 + if(keep_data) + reagent_data = copy_data(cached_reagent) //if we reached here means we have found our specific reagent type so break if(!include_source_subtypes) @@ -378,7 +383,14 @@ //add the new target reagent with the averaged values from the source reagents if(weighted_volume > 0) update_total() - add_reagent(target_reagent_typepath, weighted_volume * multiplier, reagtemp = chem_temp, added_purity = (weighted_purity / weighted_volume), added_ph = (weighted_ph / weighted_volume)) + add_reagent( + target_reagent_typepath, + weighted_volume * multiplier, + data = reagent_data, + reagtemp = chem_temp, + added_purity = (weighted_purity / weighted_volume), + added_ph = (weighted_ph / weighted_volume), + ) /// Removes all reagents /datum/reagents/proc/clear_reagents() diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 8fed0009459..c57f4a57616 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -342,3 +342,9 @@ . = ..() if(!initial && (slot & ITEM_SLOT_HANDS) && reagent_container_liquid_sound && reagents.total_volume > 0) playsound(src, reagent_container_liquid_sound, LIQUID_SLOSHING_SOUND_VOLUME, vary = TRUE, ignore_walls = FALSE) + +/obj/item/reagent_containers/used_in_craft(atom/result, datum/crafting_recipe/current_recipe) + . = ..() + // If consumed in crafting, we should dump contents out before qdeling them. + if(!is_type_in_list(src, current_recipe.parts)) + reagents.expose(loc, TOUCH) diff --git a/code/modules/reagents/reagent_containers/cups/glassbottle.dm b/code/modules/reagents/reagent_containers/cups/glassbottle.dm index 2969758475b..2438be6bd9c 100644 --- a/code/modules/reagents/reagent_containers/cups/glassbottle.dm +++ b/code/modules/reagents/reagent_containers/cups/glassbottle.dm @@ -58,12 +58,9 @@ update_icon(UPDATE_OVERLAYS) return ..() -/obj/item/reagent_containers/cup/glass/bottle/CheckParts(list/parts_list) +/obj/item/reagent_containers/cup/glass/bottle/used_in_craft(atom/result, datum/crafting_recipe/current_recipe) . = ..() - var/obj/item/reagent_containers/cup/glass/bottle/bottle = locate() in contents - if(bottle.message_in_a_bottle) - message_in_a_bottle = bottle.message_in_a_bottle - bottle.message_in_a_bottle.forceMove(src) + message_in_a_bottle?.forceMove(drop_location()) /obj/item/reagent_containers/cup/glass/bottle/examine(mob/user) . = ..() @@ -916,16 +913,16 @@ /datum/reagent/toxin/spore_burning, ) -/obj/item/reagent_containers/cup/glass/bottle/molotov/CheckParts(list/parts_list) - . = ..() - var/obj/item/reagent_containers/cup/glass/bottle/bottle = locate() in contents +/obj/item/reagent_containers/cup/glass/bottle/molotov/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + var/obj/item/reagent_containers/cup/glass/bottle/bottle = locate() in components if(!bottle) - return + return ..() icon_state = bottle.icon_state bottle.reagents.copy_to(src, 100) if(istype(bottle, /obj/item/reagent_containers/cup/glass/bottle/juice)) desc += " You're not sure if making this out of a carton was the brightest idea." isGlass = FALSE + return ..() /obj/item/reagent_containers/cup/glass/bottle/molotov/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum, do_splash = FALSE) ..(hit_atom, throwingdatum, do_splash = FALSE) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index a216c2b422c..3ebfeef01d5 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -138,6 +138,7 @@ #include "confusion.dm" #include "connect_loc.dm" #include "container_sanity.dm" +#include "crafting.dm" #include "crayons.dm" #include "create_and_destroy.dm" #include "damp_rag.dm" diff --git a/code/modules/unit_tests/crafting.dm b/code/modules/unit_tests/crafting.dm new file mode 100644 index 00000000000..d76926e2749 --- /dev/null +++ b/code/modules/unit_tests/crafting.dm @@ -0,0 +1,199 @@ +/** + * The accepted discrepancy between the amount of material between an item when crafted and the same item when spawned + * so we don't have to be obnoxious about small portion of mats being lost for items that are processed in multiple other + * results (eg. a slab of meat being cut in three cutlets, and each cutlet can be used to craft different things) + * right now it's around 3 points per 100 units of a material. + */ +#define ACCEPTABLE_MATERIAL_DEVIATION 0.033 + +/** + * Check if a generic atom (because both mobs and the crafter machinery can do it) can potentially craft all recipes, + * with the exact same types required in the recipe, and also compare the materials of crafted result with one of the same type + * to ansure they match if the recipe has the CRAFT_ENFORCE_MATERIALS_PARITY flag. + */ +/datum/unit_test/crafting + +/datum/unit_test/crafting/Run() + var/atom/movable/crafter = allocate(__IMPLIED_TYPE__) + + ///Clear the area around our crafting movable of objects that may mess with the unit test + for(var/atom/movable/trash in (range(1, crafter) - crafter)) + qdel(trash) + + var/turf/turf = crafter.loc + var/old_turf_type = turf.type + var/datum/component/personal_crafting/unit_test/craft_comp = crafter.AddComponent(__IMPLIED_TYPE__) + var/obj/item/reagent_containers/cup/bottomless_cup = allocate_bottomless_cup() + + var/list/tools = list() + + var/list/all_recipes = GLOB.crafting_recipes + GLOB.cooking_recipes + for(var/datum/crafting_recipe/recipe as anything in all_recipes) + if(recipe.non_craftable) + continue + //split into a different proc, so if something fails it's both easier to track and doesn't halt the loop. + process_recipe(crafter, craft_comp, recipe, bottomless_cup, tools) + if(QDELETED(bottomless_cup) || bottomless_cup.loc != turf) //The cup itself was used in a recipe, rather than its contents. + bottomless_cup = allocate_bottomless_cup() + + // We have one or two recipes that generate turf (from stacks, like snow walls), which shouldn't be carried between tests + if(turf.type != old_turf_type) + turf.ChangeTurf(old_turf_type) + +///Allocate a reagent container with infinite capacity and no reaction to use in crafting +/datum/unit_test/crafting/proc/allocate_bottomless_cup() + var/obj/item/reagent_containers/cup/bottomless_cup = allocate(__IMPLIED_TYPE__) + bottomless_cup.reagents.flags |= NO_REACT|DRAINABLE + bottomless_cup.reagents.maximum_volume = INFINITY + return bottomless_cup + +/datum/unit_test/crafting/proc/process_recipe( + atom/crafter, + datum/component/personal_crafting/unit_test/craft_comp, + datum/crafting_recipe/recipe, + obj/item/reagent_containers/bottomless_cup, + list/tools +) + var/turf/turf = crafter.loc + //Components that have to be deleted later so they don't mess up with other recipes + var/list/spawned_components = list() + //Warn if uncreatables were found in the recipe if it fails + //If it doesn't fail, then it was already handled, maybe through `unit_test_spawn_extras` + var/list/uncreatables_found + + for(var/spawn_path in recipe.unit_test_spawn_extras) + var/amount = recipe.unit_test_spawn_extras[spawn_path] + if(ispath(spawn_path, /obj/item/stack)) + spawned_components += new spawn_path(turf, /*new_amount =*/ amount, /*merge =*/ FALSE) + continue + for(var/index in 1 to amount) + spawned_components += new spawn_path(turf) + + for(var/req_path in recipe.reqs) //spawn items and reagents + var/amount = recipe.reqs[req_path] + + if(ispath(req_path, /datum/reagent)) //it's a reagent + if(!bottomless_cup.reagents.has_reagent(req_path, amount)) + bottomless_cup.reagents.add_reagent(req_path, amount + 1, no_react = TRUE) + continue + + if(req_path in uncreatables) + LAZYADD(uncreatables_found, req_path) + continue + + if(ispath(req_path, /obj/item/stack)) //it's a stack + spawned_components += new req_path(turf, /*new_amount =*/ amount, /*merge =*/ FALSE) + continue + + //it's any other item + for(var/iteration in 1 to amount) + spawned_components += new req_path(turf) + + for(var/req_path in recipe.chem_catalysts) // spawn catalysts + var/amount = recipe.chem_catalysts[req_path] + if(!bottomless_cup.reagents.has_reagent(req_path, amount)) + bottomless_cup.reagents.add_reagent(req_path, amount + 1, no_react = TRUE) + + var/list/bulky_objects = list() + bulky_objects += recipe.structures + recipe.machinery //either structures and machinery could be null + list_clear_nulls(bulky_objects) //so we clear the list + for(var/req_path in bulky_objects) //spawn required machinery or structures + if(req_path in uncreatables) + LAZYADD(uncreatables_found, req_path) + continue + spawned_components += new req_path(turf) + + var/list/needed_tools = list() + needed_tools += recipe.tool_behaviors + recipe.tool_paths //either tool_behaviors and tool_paths could be null + list_clear_nulls(needed_tools) //so we clear the list + ///tool instances which have been moved to the crafter loc, which are moved back to nullspace once the recipe is done + var/list/summoned_tools = list() + for(var/tooltype in needed_tools) + var/obj/item/tool = tools[tooltype] + if(!QDELETED(tool)) + tool.forceMove(turf) + else + var/is_behaviour = istext(tooltype) + var/path_to_use = is_behaviour ? /obj/item : tooltype + tool = allocate(path_to_use, turf) //we shouldn't delete the tools and allocate and keep them between recipes + if(is_behaviour) + tool.tool_behaviour = tooltype + else if(tooltype in uncreatables) + LAZYADD(uncreatables_found, tooltype) + continue + tools[tooltype] = tool + summoned_tools |= tool + + var/atom/result = craft_comp.construct_item(crafter, recipe) + + for(var/atom/movable/tool as anything in summoned_tools) + tool.moveToNullspace() + + if(istext(result) || isnull(result)) //construct_item() returned a text string telling us why it failed. + TEST_FAIL("[recipe.type] couldn't be crafted during unit test[result || ", result is null for some reason!"]") + if(uncreatables_found) + TEST_FAIL("The following objects that shouldn't initialize during unit tests were found in [recipe]: [english_list(uncreatables_found)]") + delete_components(spawned_components) + return + //enforcing materials parity between crafted and spawned for turfs would be more trouble than worth right now + if(isturf(result)) + delete_components(spawned_components) + return + + spawned_components += result + + if(!(recipe.crafting_flags & CRAFT_ENFORCE_MATERIALS_PARITY)) + delete_components(spawned_components) + return + + var/atom/copycat = new result.type(turf) + spawned_components += copycat + + // SSmaterials caches the combinations so we don't have to run more complex checks + if(result.custom_materials == copycat.custom_materials) + delete_components(spawned_components) + return + var/comparison_failed = TRUE + if(length(result.custom_materials) == length(copycat.custom_materials)) + comparison_failed = FALSE + for(var/mat in result.custom_materials) + var/enemy_amount = copycat.custom_materials[mat] + if(!enemy_amount) //break the loop early, we cannot perform a division by zero anyway + comparison_failed = TRUE + break + var/ratio_difference = abs((result.custom_materials[mat] / enemy_amount) - 1) + if(ratio_difference > ACCEPTABLE_MATERIAL_DEVIATION) + comparison_failed = TRUE + if(comparison_failed) + var/warning = "custom_materials of [result.type] when crafted and spawned don't match" + var/what_it_should_be = "null" + //compose a text string containing the syntax and paths to use for editing the custom_materials var + if(result.custom_materials) + what_it_should_be = "\[list(" + var/index = 1 + var/mats_len = length(result.custom_materials) + for(var/datum/material/mat as anything in result.custom_materials) + what_it_should_be += "[mat.type] = [result.custom_materials[mat]]" + if(index < mats_len) + what_it_should_be += ", " + index++ + what_it_should_be += ")\] (you can round values a bit)" + TEST_FAIL("[warning]. custom_materials should be [what_it_should_be]. \ + Otherwise set the requirements_mats_blacklist variable for [recipe] \ + or remove the CRAFT_ENFORCE_MATERIALS_PARITY crafting flag from it") + + delete_components(spawned_components) + +/** + * Clear the area of the components that have been spawned as either the requirements of a recipe or its result + * so they don't mess up with recipes that come after it. + */ +/datum/unit_test/crafting/proc/delete_components(list/comps) + for(var/atom/movable/used as anything in comps) + if(!QDELETED(used)) + qdel(used) + +/datum/component/personal_crafting/unit_test + ignored_flags = CRAFT_MUST_BE_LEARNED|CRAFT_ONE_PER_TURF|CRAFT_CHECK_DIRECTION|CRAFT_CHECK_DENSITY|CRAFT_ON_SOLID_GROUND|CRAFT_IGNORE_DO_AFTER + +#undef ACCEPTABLE_MATERIAL_DEVIATION diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index c73c282d899..4c9cc36adb4 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -317,8 +317,7 @@ servo = new /obj/item/stock_parts/servo(src) update_part_values() -/obj/vehicle/sealed/mecha/CheckParts(list/parts_list) - . = ..() +/obj/vehicle/sealed/mecha/proc/locate_parts() cell = locate(/obj/item/stock_parts/power_store) in contents diag_hud_set_mechcell() scanmod = locate(/obj/item/stock_parts/scanning_module) in contents diff --git a/code/modules/vehicles/mecha/mecha_construction_paths.dm b/code/modules/vehicles/mecha/mecha_construction_paths.dm index a8a7c224491..226b3e2107a 100644 --- a/code/modules/vehicles/mecha/mecha_construction_paths.dm +++ b/code/modules/vehicles/mecha/mecha_construction_paths.dm @@ -31,7 +31,9 @@ // Remove default mech power cell, as we replace it with a new one. var/obj/vehicle/sealed/mecha/mech = new result(drop_location(), /* built_manually = */ TRUE) var/obj/item/mecha_parts/chassis/parent_chassis = parent - mech.CheckParts(parent_chassis.contents) + for(var/atom/movable/content in parent_chassis.contents) + content.forceMove(mech) + mech.locate_parts() SSblackbox.record_feedback("tally", "mechas_created", 1, mech.name) ADD_TRAIT(mech, TRAIT_MECHA_CREATED_NORMALLY, mech) QDEL_NULL(parent) diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm index 39419ce47b2..2bdd0c1f260 100644 --- a/code/modules/vehicles/mecha/mecha_defense.dm +++ b/code/modules/vehicles/mecha/mecha_defense.dm @@ -410,7 +410,7 @@ if(!(locate(part_to_remove) in contents)) return user.put_in_hands(part_to_remove) - CheckParts() + locate_parts() diag_hud_set_mechcell() tool.play_tool_sound(src) return diff --git a/code/modules/vehicles/motorized_wheelchair.dm b/code/modules/vehicles/motorized_wheelchair.dm index 29efdc39504..abe02f12e24 100644 --- a/code/modules/vehicles/motorized_wheelchair.dm +++ b/code/modules/vehicles/motorized_wheelchair.dm @@ -40,15 +40,14 @@ /obj/vehicle/ridden/wheelchair/motorized/make_ridable() AddElement(/datum/element/ridable, /datum/component/riding/vehicle/wheelchair/motorized) -/obj/vehicle/ridden/wheelchair/motorized/CheckParts(list/parts_list) +/obj/vehicle/ridden/wheelchair/motorized/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) // This wheelchair was crafted, so clean out default parts qdel(power_cell) component_parts = list() - for(var/obj/item/stock_parts/part in parts_list) + for(var/obj/item/stock_parts/part in contents) if(istype(part, /obj/item/stock_parts/power_store/cell)) // power cell, physically moves into the wheelchair power_cell = part - part.forceMove(src) continue // find matching datum/stock_part for this part and add to component list @@ -56,11 +55,10 @@ if(isnull(newstockpart)) CRASH("No corresponding datum/stock_part for [part.type]") component_parts += newstockpart - // delete this part - part.moveToNullspace() - qdel(part) refresh_parts() + return ..() + /obj/vehicle/ridden/wheelchair/motorized/proc/refresh_parts() speed = 1 // Should never be under 1 for(var/datum/stock_part/servo/servo in component_parts) diff --git a/tgstation.dme b/tgstation.dme index d4505686677..1607445ee84 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1270,7 +1270,6 @@ #include "code\datums\components\curse_of_hunger.dm" #include "code\datums\components\curse_of_polymorph.dm" #include "code\datums\components\custom_area.dm" -#include "code\datums\components\customizable_reagent_holder.dm" #include "code\datums\components\damage_aura.dm" #include "code\datums\components\damage_chain.dm" #include "code\datums\components\dart_insert.dm" @@ -1323,6 +1322,7 @@ #include "code\datums\components\holographic_nature.dm" #include "code\datums\components\igniter.dm" #include "code\datums\components\infective.dm" +#include "code\datums\components\ingredients_holder.dm" #include "code\datums\components\interaction_booby_trap.dm" #include "code\datums\components\irradiated.dm" #include "code\datums\components\item_equipped_movement_rustle.dm"