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.

🆑
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.
/🆑
This commit is contained in:
Ghom
2025-06-01 23:37:43 +00:00
committed by Roxy
parent 9bd7dce966
commit 1f3894e793
104 changed files with 1294 additions and 758 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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)

View File

@@ -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"

View File

@@ -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,

View File

@@ -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()

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)
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
// We didn't find the required item
if(needed_amount > 0)
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,58 +131,59 @@
/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
if(!present_qualities[required_quality])
return FALSE
for(var/required_path in recipe.tool_paths)
@@ -190,12 +193,15 @@
continue
found_this_tool = TRUE
break
if(found_this_tool)
continue
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)
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
. += 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)
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/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
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
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)
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(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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -139,7 +139,6 @@
else
grilled_result = new cook_result(original_object.loc)
if(original_object.custom_materials)
grilled_result.set_custom_materials(original_object.custom_materials)
if(IsEdible(grilled_result) && positive_result)

View File

@@ -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,26 +254,21 @@
///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
/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_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
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)
@@ -258,14 +279,14 @@
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)

View File

@@ -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

View File

@@ -38,16 +38,13 @@
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)
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)

View File

@@ -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))
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))

View File

@@ -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)

View File

@@ -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

View File

@@ -28,7 +28,6 @@
/datum/material/meat/on_main_applied(atom/source, mat_amount, multiplier)
. = ..()
if(!IS_EDIBLE(source))
make_edible(source, mat_amount, multiplier)
ADD_TRAIT(source, TRAIT_ROD_REMOVE_FISHING_DUD, REF(src)) //The rod itself is the bait... sorta.
@@ -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)
. = ..()

View File

@@ -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)
. = ..()

View File

@@ -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)
/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
object.forceMove(src)
SEND_SIGNAL(object, COMSIG_ATOM_USED_IN_CRAFT, src)
parts_list.Cut()
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)

View File

@@ -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)
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)
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)

View File

@@ -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.
*

View File

@@ -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()

View File

@@ -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)
. = ..()

View File

@@ -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

View File

@@ -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.

View File

@@ -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)
. = ..()

View File

@@ -1,4 +1,3 @@
/obj/effect/decal/cleanable/food
icon = 'icons/effects/tomatodecal.dmi'
gender = NEUTER

View File

@@ -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)
///////////////

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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"

View File

@@ -26,10 +26,12 @@
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))
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...?"))
@@ -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)

View File

@@ -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"

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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"

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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))

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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)

View File

@@ -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"

View File

@@ -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"

View File

@@ -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)
. = ..()

View File

@@ -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

View File

@@ -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!"))

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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()

View File

@@ -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")

View File

@@ -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]"

View File

@@ -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))

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -146,5 +141,8 @@
/obj/item/food/breadslice/moldy = 1,
/obj/item/food/grown = 4,
/obj/item/food/candy_corn = 2,
/datum/reagent/water = 15)
/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

View File

@@ -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

View File

@@ -32,7 +32,6 @@
blacklist = list(
/obj/item/organ/lungs/cybernetic,
)
result = /obj/item/food/shredded_lungs
added_foodtypes = MEAT|GORE
category = CAT_LIZARD

View File

@@ -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

View File

@@ -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(

View File

@@ -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

View File

@@ -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

View File

@@ -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()
. = ..()

View File

@@ -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

View File

@@ -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))

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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()

View File

@@ -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)

View File

@@ -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)

View File

@@ -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"

View File

@@ -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

View File

@@ -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

Some files were not shown because too many files have changed in this diff Show More