diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 14bc65811fa..5261fa38db0 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -183,6 +183,9 @@ ///from base of [/datum/reagent/proc/expose_atom]: (/turf, reac_volume) #define COMSIG_REAGENT_EXPOSE_TURF "reagent_expose_turf" +///from base of [/datum/controller/subsystem/materials/proc/InitializeMaterial]: (/datum/material) +#define COMSIG_MATERIALS_INIT_MAT "SSmaterials_init_mat" + ///from base of [/datum/reagents/proc/add_reagent]: (/datum/reagent, amount, reagtemp, data, no_react) #define COMSIG_REAGENTS_NEW_REAGENT "reagents_new_reagent" ///from base of [/datum/reagents/proc/add_reagent]: (/datum/reagent, amount, reagtemp, data, no_react) diff --git a/code/__DEFINES/materials.dm b/code/__DEFINES/materials.dm index 9a7bf2e468e..107e8c841ff 100644 --- a/code/__DEFINES/materials.dm +++ b/code/__DEFINES/materials.dm @@ -9,6 +9,8 @@ /// Used to make a material initialize at roundstart. #define MATERIAL_INIT_MAPLOAD (1<<0) +/// Used to make a material type able to be instantiated on demand after roundstart. +#define MATERIAL_INIT_BESPOKE (1<<1) //Material Container Flags. ///If the container shows the amount of contained materials on examine. @@ -46,6 +48,9 @@ #define MATERIAL_NO_EFFECTS (1<<2) #define MATERIAL_AFFECT_STATISTICS (1<<3) +/// Wrapper for fetching material references. Exists exclusively so that people don't need to wrap everything in a list every time. +#define GET_MATERIAL_REF(arguments...) SSmaterials._GetMaterialRef(list(##arguments)) + #define MATERIAL_SOURCE(mat) "[mat.name]_material" diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm index 1fdc72cbfab..cebdcc9be5e 100644 --- a/code/controllers/subsystem/materials.dm +++ b/code/controllers/subsystem/materials.dm @@ -8,12 +8,16 @@ These materials call on_applied() on whatever item they are applied to, common e SUBSYSTEM_DEF(materials) name = "Materials" flags = SS_NO_FIRE | SS_NO_INIT - ///Dictionary of material.type || material ref + ///Dictionary of material.id || material ref var/list/materials + ///Dictionary of type || list of material refs + var/list/materials_by_type + ///Dictionary of type || list of material ids + var/list/materialids_by_type ///Dictionary of category || list of material refs var/list/materials_by_category - ///Dictionary of category || list of material types, mostly used by rnd machines like autolathes. - var/list/materialtypes_by_category + ///Dictionary of category || list of material ids, mostly used by rnd machines like autolathes. + var/list/materialids_by_category ///A cache of all material combinations that have been used var/list/list/material_combos ///List of stackcrafting recipes for materials using base recipes @@ -31,40 +35,131 @@ SUBSYSTEM_DEF(materials) ///Ran on initialize, populated the materials and materials_by_category dictionaries with their appropiate vars (See these variables for more info) /datum/controller/subsystem/materials/proc/InitializeMaterials() materials = list() + materials_by_type = list() + materialids_by_type = list() materials_by_category = list() - materialtypes_by_category = list() + materialids_by_category = list() material_combos = list() for(var/type in subtypesof(/datum/material)) - var/datum/material/ref = type - if(!(initial(ref.init_flags) & MATERIAL_INIT_MAPLOAD)) - continue // Do not initialize + var/datum/material/mat_type = type + if(!(initial(mat_type.init_flags) & MATERIAL_INIT_MAPLOAD)) + continue // Do not initialize at mapload + InitializeMaterial(list(mat_type)) - ref = new ref - materials[type] = ref - for(var/c in ref.categories) - materials_by_category[c] += list(ref) - materialtypes_by_category[c] += list(type) +/** Creates and caches a material datum. + * + * Arugments: + * - [arguments][/list]: The arguments to use to create the material datum + * - The first element is the type of material to initialize. + */ +/datum/controller/subsystem/materials/proc/InitializeMaterial(list/arguments) + var/datum/material/mat_type = arguments[1] + if(initial(mat_type.init_flags) & MATERIAL_INIT_BESPOKE) + arguments[1] = GetIdFromArguments(arguments) -/datum/controller/subsystem/materials/proc/GetMaterialRef(datum/material/fakemat) + var/datum/material/mat_ref = new mat_type + if(!mat_ref.Initialize(arglist(arguments))) + return null + + var/mat_id = mat_ref.id + materials[mat_id] = mat_ref + materials_by_type[mat_type] += list(mat_ref) + materialids_by_type[mat_type] += list(mat_id) + for(var/category in mat_ref.categories) + materials_by_category[category] += list(mat_ref) + materialids_by_category[category] += list(mat_id) + + SEND_SIGNAL(src, COMSIG_MATERIALS_INIT_MAT, mat_ref) + return mat_ref + +/** Fetches a cached material singleton when passed sufficient arguments. + * + * Arguments: + * - [arguments][/list]: The list of arguments used to fetch the material ref. + * - The first element is a material datum, text string, or material type. + * - [Material datums][/datum/material] are assumed to be references to the cached datum and are returned + * - Text is assumed to be the text ID of a material and the corresponding material is fetched from the cache + * - A material type is checked for bespokeness: + * - If the material type is not bespoke the type is assumed to be the id for a material and the corresponding material is loaded from the cache. + * - If the material type is bespoke a text ID is generated from the arguments list and used to load a material datum from the cache. + * - The following elements are used to generate bespoke IDs + */ +/datum/controller/subsystem/materials/proc/_GetMaterialRef(list/arguments) if(!materials) InitializeMaterials() - return materials[fakemat] || fakemat -///Returns a list to be used as an object's custom_materials. Lists will be cached and re-used based on the parameters. + var/datum/material/key = arguments[1] + if(istype(key)) + return key // We are assuming here that the only thing allowed to create material datums is [/datum/controller/subsystem/materials/proc/InitializeMaterial] + + if(istext(key)) // Handle text id + . = materials[key] + if(!.) + WARNING("Attempted to fetch material ref with invalid text id '[key]'") + return + + if(!ispath(key, /datum/material)) + CRASH("Attempted to fetch material ref with invalid key [key]") + + if(!(initial(key.init_flags) & MATERIAL_INIT_BESPOKE)) + . = materials[key] + if(!.) + WARNING("Attempted to fetch reference to an abstract material with key [key]") + return + + key = GetIdFromArguments(arguments) + return materials[key] || InitializeMaterial(arguments) + +/** I'm not going to lie, this was swiped from [SSdcs][/datum/controller/subsystem/processing/dcs]. + * Credit does to ninjanomnom + * + * Generates an id for bespoke ~~elements~~ materials when given the argument list + * Generating the id here is a bit complex because we need to support named arguments + * Named arguments can appear in any order and we need them to appear after ordered arguments + * We assume that no one will pass in a named argument with a value of null + **/ +/datum/controller/subsystem/materials/proc/GetIdFromArguments(list/arguments) + var/datum/material/mattype = arguments[1] + var/list/fullid = list("[initial(mattype.id) || mattype]") + var/list/named_arguments = list() + for(var/i in 2 to length(arguments)) + var/key = arguments[i] + var/value + if(istext(key)) + value = arguments[key] + if(!(istext(key) || isnum(key))) + key = REF(key) + key = "[key]" // Key is stringified so numbers dont break things + if(!isnull(value)) + if(!(istext(value) || isnum(value))) + value = REF(value) + named_arguments["[key]"] = value + else + fullid += "[key]" + + if(length(named_arguments)) + named_arguments = sortList(named_arguments) + fullid += named_arguments + return list2params(fullid) + + +/// Returns a list to be used as an object's custom_materials. Lists will be cached and re-used based on the parameters. /datum/controller/subsystem/materials/proc/FindOrCreateMaterialCombo(list/materials_declaration, multiplier) + if(!LAZYLEN(materials_declaration)) + return null // If we get a null we pass it right back, we don't want to generate stack traces just because something is clearing out its materials list. + if(!material_combos) InitializeMaterials() var/list/combo_params = list() for(var/x in materials_declaration) var/datum/material/mat = x - var/path_name = ispath(mat) ? "[mat]" : "[mat.type]" - combo_params += "[path_name]=[materials_declaration[mat] * multiplier]" + combo_params += "[istype(mat) ? mat.id : mat]=[materials_declaration[mat] * multiplier]" sortTim(combo_params, /proc/cmp_text_asc) // We have to sort now in case the declaration was not in order var/combo_index = combo_params.Join("-") var/list/combo = material_combos[combo_index] if(!combo) combo = list() for(var/mat in materials_declaration) - combo[GetMaterialRef(mat)] = materials_declaration[mat] * multiplier + combo[GET_MATERIAL_REF(mat)] = materials_declaration[mat] * multiplier material_combos[combo_index] = combo return combo diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index 70f13376639..cddebbab6a1 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -1,9 +1,15 @@ /datum/component/butchering - var/speed = 80 //time in deciseconds taken to butcher something - var/effectiveness = 100 //percentage effectiveness; numbers above 100 yield extra drops - var/bonus_modifier = 0 //percentage increase to bonus item chance - var/butcher_sound = 'sound/effects/butcher.ogg' //sound played when butchering + /// Time in deciseconds taken to butcher something + var/speed = 8 SECONDS + /// Percentage effectiveness; numbers above 100 yield extra drops + var/effectiveness = 100 + /// Percentage increase to bonus item chance + var/bonus_modifier = 0 + /// Sound played when butchering + var/butcher_sound = 'sound/effects/butcher.ogg' + /// Whether or not this component can be used to butcher currently. Used to temporarily disable butchering var/butchering_enabled = TRUE + /// Whether or not this component is compatible with blunt tools. var/can_be_blunt = FALSE /datum/component/butchering/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled, _can_be_blunt) @@ -77,7 +83,15 @@ screaming_through_a_slit_throat.apply_wound(slit_throat) H.apply_status_effect(/datum/status_effect/neck_slice) +/** + * Handles a user butchering a target + * + * Arguments: + * - [butcher][/mob/living]: The mob doing the butchering + * - [meat][/mob/living]: The mob being butchered + */ /datum/component/butchering/proc/Butcher(mob/living/butcher, mob/living/meat) + var/list/results = list() var/turf/T = meat.drop_location() var/final_effectiveness = effectiveness - meat.butcher_difficulty var/bonus_chance = max(0, (final_effectiveness - 100) + bonus_modifier) //so 125 total effectiveness = 25% extra chance @@ -88,20 +102,29 @@ if(!prob(final_effectiveness)) if(butcher) to_chat(butcher, "You fail to harvest some of the [initial(bones.name)] from [meat].") - else if(prob(bonus_chance)) + continue + + if(prob(bonus_chance)) if(butcher) to_chat(butcher, "You harvest some extra [initial(bones.name)] from [meat]!") - for(var/i in 1 to 2) - new bones (T) - else - new bones (T) + results += new bones (T) + results += new bones (T) + meat.butcher_results.Remove(bones) //in case you want to, say, have it drop its results on gib + for(var/V in meat.guaranteed_butcher_results) var/obj/sinew = V var/amount = meat.guaranteed_butcher_results[sinew] for(var/i in 1 to amount) - new sinew (T) + results += new sinew (T) meat.guaranteed_butcher_results.Remove(sinew) + + for(var/obj/item/carrion in results) + var/list/meat_mats = carrion.has_material_type(/datum/material/meat) + if(!length(meat_mats)) + continue + carrion.set_custom_materials((carrion.custom_materials - meat_mats) + list(GET_MATERIAL_REF(/datum/material/meat/mob_meat, meat) = counterlist_sum(meat_mats))) + if(butcher) butcher.visible_message("[butcher] butchers [meat].", \ "You butcher [meat].") diff --git a/code/datums/components/material_container.dm b/code/datums/components/material_container.dm index 010500d4adf..83ec8d61194 100644 --- a/code/datums/components/material_container.dm +++ b/code/datums/components/material_container.dm @@ -10,42 +10,78 @@ */ /datum/component/material_container + /// The total amount of materials this material container contains var/total_amount = 0 + /// The maximum amount of materials this material container can contain var/max_amount - var/sheet_type + /// Map of material ref -> amount var/list/materials //Map of key = material ref | Value = amount - var/disable_attackby - var/list/allowed_typecache + /// The list of materials that this material container can accept + var/list/allowed_materials + /// The typecache of things that this material container can accept + var/list/allowed_item_typecache + /// The last main material that was inserted into this container var/last_inserted_id + /// Whether or not this material container allows specific amounts from sheets to be inserted var/precise_insertion = FALSE + /// A callback for checking wheter we can insert a material into this container + var/datum/callback/insertion_check + /// A callback invoked before materials are inserted into this container var/datum/callback/precondition + /// A callback invoked after materials are inserted into this container var/datum/callback/after_insert - ///The material container flags. See __DEFINES/materials.dm. + /// The material container flags. See __DEFINES/materials.dm. var/mat_container_flags /// Sets up the proper signals and fills the list of materials with the appropriate references. -/datum/component/material_container/Initialize(list/mat_list, max_amt = 0, _mat_container_flags=NONE, list/allowed_types, datum/callback/_precondition, datum/callback/_after_insert) +/datum/component/material_container/Initialize(list/init_mats, max_amt = 0, _mat_container_flags=NONE, list/allowed_mats=init_mats, list/allowed_items, datum/callback/_insertion_check, datum/callback/_precondition, datum/callback/_after_insert) + if(!isatom(parent)) + return COMPONENT_INCOMPATIBLE + materials = list() max_amount = max(0, max_amt) mat_container_flags = _mat_container_flags - if(allowed_types) - if(ispath(allowed_types) && allowed_types == /obj/item/stack) - allowed_typecache = GLOB.typecache_stack + allowed_materials = allowed_mats || list() + if(allowed_items) + if(ispath(allowed_items) && allowed_items == /obj/item/stack) + allowed_item_typecache = GLOB.typecache_stack else - allowed_typecache = typecacheof(allowed_types) + allowed_item_typecache = typecacheof(allowed_items) + insertion_check = _insertion_check precondition = _precondition after_insert = _after_insert + for(var/mat in init_mats) //Make the assoc list material reference -> amount + var/mat_ref = GET_MATERIAL_REF(mat) + if(isnull(mat_ref)) + continue + var/mat_amt = init_mats[mat] + if(isnull(mat_amt)) + mat_amt = 0 + materials[mat_ref] += mat_amt + +/datum/component/material_container/Destroy(force, silent) + materials = null + allowed_materials = null + if(insertion_check) + QDEL_NULL(insertion_check) + if(precondition) + QDEL_NULL(precondition) + if(after_insert) + QDEL_NULL(after_insert) + return ..() + + +/datum/component/material_container/RegisterWithParent() + . = ..() + if(!(mat_container_flags & MATCONTAINER_NO_INSERT)) RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/on_attackby) if(mat_container_flags & MATCONTAINER_EXAMINE) RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine) - for(var/mat in mat_list) //Make the assoc list ref | amount - var/datum/material/M = SSmaterials.GetMaterialRef(mat) - materials[M] = 0 /datum/component/material_container/vv_edit_var(var_name, var_value) var/old_flags = mat_container_flags @@ -75,7 +111,7 @@ /datum/component/material_container/proc/on_attackby(datum/source, obj/item/I, mob/living/user) SIGNAL_HANDLER - var/list/tc = allowed_typecache + var/list/tc = allowed_item_typecache if(!(mat_container_flags & MATCONTAINER_ANY_INTENT) && user.a_intent != INTENT_HELP) return if(I.item_flags & ABSTRACT) @@ -136,54 +172,91 @@ last_inserted_id = insert_item_materials(I, multiplier, breakdown_flags) return material_amount -/datum/component/material_container/proc/insert_item_materials(obj/item/I, multiplier = 1, breakdown_flags = mat_container_flags) +/** + * Inserts the relevant materials from an item into this material container. + * + * Arguments: + * - [source][/obj/item]: The source of the materials we are inserting. + * - multiplier: The multiplier for the materials being inserted. + * - breakdown_flags: The breakdown bitflags that will be used to retrieve the materials from the source + */ +/datum/component/material_container/proc/insert_item_materials(obj/item/source, multiplier = 1, breakdown_flags = mat_container_flags) var/primary_mat var/max_mat_value = 0 - var/list/item_materials = I.get_material_composition(breakdown_flags) - for(var/MAT in materials) + var/list/item_materials = source.get_material_composition(breakdown_flags) + for(var/MAT in item_materials) + if(!can_hold_material(MAT)) + continue materials[MAT] += item_materials[MAT] * multiplier total_amount += item_materials[MAT] * multiplier if(item_materials[MAT] > max_mat_value) max_mat_value = item_materials[MAT] primary_mat = MAT + return primary_mat +/** + * The default check for whether we can add materials to this material container. + * + * Arguments: + * - [mat][/atom/material]: The material we are checking for insertability. + */ +/datum/component/material_container/proc/can_hold_material(datum/material/mat) + if(mat in allowed_materials) + return TRUE + if(istype(mat) && ((mat.id in allowed_materials) || (mat.type in allowed_materials))) + allowed_materials += mat // This could get messy with passing lists by ref... but if you're doing that the list expansion is probably being taken care of elsewhere anyway... + return TRUE + if(insertion_check?.Invoke(mat)) + allowed_materials += mat + return TRUE + return FALSE + /// For inserting an amount of material /datum/component/material_container/proc/insert_amount_mat(amt, datum/material/mat) - if(!istype(mat)) - mat = SSmaterials.GetMaterialRef(mat) - if(amt > 0 && has_space(amt)) - var/total_amount_saved = total_amount - if(mat) - materials[mat] += amt - else - for(var/i in materials) - materials[i] += amt - total_amount += amt - return (total_amount - total_amount_saved) - return FALSE + if(amt <= 0 || !has_space(amt)) + return 0 + + var/total_amount_saved = total_amount + if(mat) + if(!istype(mat)) + mat = GET_MATERIAL_REF(mat) + materials[mat] += amt + else + var/num_materials = length(materials) + if(!num_materials) + return 0 + + amt /= num_materials + for(var/i in materials) + materials[i] += amt + total_amount += amt + return (total_amount - total_amount_saved) /// Uses an amount of a specific material, effectively removing it. /datum/component/material_container/proc/use_amount_mat(amt, datum/material/mat) if(!istype(mat)) - mat = SSmaterials.GetMaterialRef(mat) + mat = GET_MATERIAL_REF(mat) + + if(!mat) + return 0 var/amount = materials[mat] - if(mat) - if(amount >= amt) - materials[mat] -= amt - total_amount -= amt - return amt - return FALSE + if(amount < amt) + return 0 + + materials[mat] -= amt + total_amount -= amt + return amt /// Proc for transfering materials to another container. /datum/component/material_container/proc/transer_amt_to(datum/component/material_container/T, amt, datum/material/mat) if(!istype(mat)) - mat = SSmaterials.GetMaterialRef(mat) + mat = GET_MATERIAL_REF(mat) if((amt==0)||(!T)||(!mat)) return FALSE if(amt<0) return T.transer_amt_to(src, -amt, mat) - var/tr = min(amt, materials[mat],T.can_insert_amount_mat(amt, mat)) + var/tr = min(amt, materials[mat], T.can_insert_amount_mat(amt, mat)) if(tr) use_amount_mat(tr, mat) T.insert_amount_mat(tr, mat) @@ -191,14 +264,14 @@ return FALSE /// Proc for checking if there is room in the component, returning the amount or else the amount lacking. -/datum/component/material_container/proc/can_insert_amount_mat(amt, mat) - if(amt && mat) - var/datum/material/M = mat - if(M) - if((total_amount + amt) <= max_amount) - return amt - else - return (max_amount-total_amount) +/datum/component/material_container/proc/can_insert_amount_mat(amt, datum/material/mat) + if(!amt || !mat) + return 0 + + if((total_amount + amt) <= max_amount) + return amt + else + return (max_amount - total_amount) /// For consuming a dictionary of materials. mats is the map of materials to use and the corresponding amounts, example: list(M/datum/material/glass =100, datum/material/iron=200) @@ -211,7 +284,7 @@ for(var/x in mats) //Loop through all required materials var/datum/material/req_mat = x if(!istype(req_mat)) - req_mat = SSmaterials.GetMaterialRef(req_mat) //Get the ref if necesary + req_mat = GET_MATERIAL_REF(req_mat) //Get the ref if necesary if(!materials[req_mat]) //Do we have the resource? return FALSE //Can't afford it var/amount_required = mats[x] * multiplier @@ -228,24 +301,25 @@ return total_amount_save - total_amount /// For spawning mineral sheets at a specific location. Used by machines to output sheets. -/datum/component/material_container/proc/retrieve_sheets(sheet_amt, datum/material/M, target = null) +/datum/component/material_container/proc/retrieve_sheets(sheet_amt, datum/material/M, atom/target = null) if(!M.sheet_type) return 0 //Add greyscale sheet handling here later if(sheet_amt <= 0) return 0 if(!target) - target = get_turf(parent) + var/atom/parent_atom = parent + target = parent_atom.drop_location() if(materials[M] < (sheet_amt * MINERAL_MATERIAL_AMOUNT)) sheet_amt = round(materials[M] / MINERAL_MATERIAL_AMOUNT) var/count = 0 while(sheet_amt > MAX_STACK_SIZE) - new M.sheet_type(target, MAX_STACK_SIZE) + new M.sheet_type(target, MAX_STACK_SIZE, null, list((M) = MINERAL_MATERIAL_AMOUNT)) count += MAX_STACK_SIZE use_amount_mat(sheet_amt * MINERAL_MATERIAL_AMOUNT, M) sheet_amt -= MAX_STACK_SIZE if(sheet_amt >= 1) - new M.sheet_type(target, sheet_amt) + new M.sheet_type(target, sheet_amt, null, list((M) = MINERAL_MATERIAL_AMOUNT)) count += sheet_amt use_amount_mat(sheet_amt * MINERAL_MATERIAL_AMOUNT, M) return count @@ -272,7 +346,7 @@ var/datum/material/req_mat = x if(!istype(req_mat)) if(ispath(req_mat)) //Is this an actual material, or is it a category? - req_mat = SSmaterials.GetMaterialRef(req_mat) //Get the ref + req_mat = GET_MATERIAL_REF(req_mat) //Get the ref else // Its a category. (For example MAT_CATEGORY_RIGID) if(!has_enough_of_category(req_mat, mats[x], multiplier)) //Do we have enough of this category? @@ -294,7 +368,6 @@ categories += x return categories - /// Returns TRUE if you have enough of the specified material. /datum/component/material_container/proc/has_enough_of_material(datum/material/req_mat, amount, multiplier=1) if(!materials[req_mat]) //Do we have the resource? @@ -331,12 +404,14 @@ return 0 var/material_amount = 0 var/list/item_materials = I.get_material_composition(breakdown_flags) - for(var/MAT in materials) + for(var/MAT in item_materials) + if(!can_hold_material(MAT)) + continue material_amount += item_materials[MAT] return material_amount /// Returns the amount of a specific material in this container. /datum/component/material_container/proc/get_material_amount(datum/material/mat) if(!istype(mat)) - mat = SSmaterials.GetMaterialRef(mat) - return(materials[mat]) + mat = GET_MATERIAL_REF(mat) + return materials[mat] diff --git a/code/datums/components/remote_materials.dm b/code/datums/components/remote_materials.dm index f8ee6a830e9..566b3b5c1d3 100644 --- a/code/datums/components/remote_materials.dm +++ b/code/datums/components/remote_materials.dm @@ -72,7 +72,7 @@ handles linking back and forth. /datum/material/plastic, ) - mat_container = parent.AddComponent(/datum/component/material_container, allowed_mats, local_size, mat_container_flags, /obj/item/stack) + mat_container = parent.AddComponent(/datum/component/material_container, allowed_mats, local_size, mat_container_flags, allowed_items=/obj/item/stack) /datum/component/remote_materials/proc/set_local_size(size) local_size = size diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm index 3f55b6aa12b..f28e82c45af 100644 --- a/code/datums/materials/_material.dm +++ b/code/datums/materials/_material.dm @@ -6,8 +6,13 @@ Simple datum which is instanced once per type and is used for every object of sa /datum/material + /// What the material is referred to as IC. var/name = "material" + /// A short description of the material. Not used anywhere, yet... var/desc = "its..stuff." + /// What the material is indexed by in the SSmaterials.materials list. Defaults to the type of the material. + var/id + ///Base color of the material, is used for greyscale. Item isn't changed in color if this is null. var/color ///Base alpha of the material, is used for greyscale icons. @@ -39,12 +44,21 @@ Simple datum which is instanced once per type and is used for every object of sa ///What type of shard the material will shatter to var/obj/item/shard_type -/datum/material/New() - . = ..() +/** Handles initializing the material. + * + * Arugments: + * - _id: The ID the material should use. Overrides the existing ID. + */ +/datum/material/proc/Initialize(_id, ...) + if(_id) + id = _id + else if(isnull(id)) + id = type + if(texture_layer_icon_state) cached_texture_filter_icon = icon('icons/materials/composite.dmi', texture_layer_icon_state) - + return TRUE ///This proc is called when the material is added to an object. /datum/material/proc/on_applied(atom/source, amount, material_flags) diff --git a/code/datums/materials/alloys.dm b/code/datums/materials/alloys.dm index 68150493504..eec3809e110 100644 --- a/code/datums/materials/alloys.dm +++ b/code/datums/materials/alloys.dm @@ -16,7 +16,7 @@ . = list() var/list/cached_comp = composition for(var/comp_mat in cached_comp) - var/datum/material/component_material = SSmaterials.GetMaterialRef(comp_mat) + var/datum/material/component_material = GET_MATERIAL_REF(comp_mat) var/list/component_composition = component_material.return_composition(cached_comp[comp_mat], breakdown_flags) for(var/comp_comp_mat in component_composition) .[comp_comp_mat] += component_composition[comp_comp_mat] * amount diff --git a/code/datums/materials/meat.dm b/code/datums/materials/meat.dm index 447b2db8ea5..ffa23b7a2ab 100644 --- a/code/datums/materials/meat.dm +++ b/code/datums/materials/meat.dm @@ -2,6 +2,7 @@ /datum/material/meat name = "meat" desc = "Meat" + id = /datum/material/meat // So the bespoke versions are categorized under this color = rgb(214, 67, 67) categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) sheet_type = /obj/item/stack/sheet/meat @@ -19,7 +20,6 @@ /datum/material/meat/on_applied_obj(obj/O, amount, material_flags) . = ..() - O.obj_flags |= UNIQUE_RENAME //So you can name it after the person its made from, a depressing comprimise. make_edible(O, amount, material_flags) /datum/material/meat/on_applied_turf(turf/T, amount, material_flags) @@ -31,3 +31,23 @@ var/oil_count = 2 * (amount / MINERAL_MATERIAL_AMOUNT) source.AddComponent(/datum/component/edible, list(/datum/reagent/consumable/nutriment = nutriment_count, /datum/reagent/consumable/cooking_oil = oil_count), null, RAW | MEAT | GROSS, null, 30, list("Fleshy")) + +/datum/material/meat/mob_meat + init_flags = MATERIAL_INIT_BESPOKE + +/datum/material/meat/mob_meat/Initialize(_id, mob/living/source) + if(!istype(source)) + return FALSE + + name = "[source?.name ? "[source.name]'s" : "mystery"] [initial(name)]" + return ..() + +/datum/material/meat/species_meat + init_flags = MATERIAL_INIT_BESPOKE + +/datum/material/meat/species_meat/Initialize(_id, datum/species/source) + if(!istype(source)) + return FALSE + + name = "[source?.name || "mystery"] [initial(name)]" + return ..() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index d2e89e0ac15..0176d01ce7e 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1576,11 +1576,11 @@ /atom/proc/intercept_zImpact(atom/movable/AM, levels = 1) . |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, AM, levels) -///Sets the custom materials for an item. +/// Sets the custom materials for an item. /atom/proc/set_custom_materials(list/materials, multiplier = 1) if(custom_materials) //Only runs if custom materials existed at first. Should usually be the case but check anyways for(var/i in custom_materials) - var/datum/material/custom_material = SSmaterials.GetMaterialRef(i) + var/datum/material/custom_material = GET_MATERIAL_REF(i) custom_material.on_removed(src, custom_materials[i], material_flags) //Remove the current materials if(!length(materials)) @@ -1589,11 +1589,110 @@ if(!(material_flags & MATERIAL_NO_EFFECTS)) for(var/x in materials) - var/datum/material/custom_material = SSmaterials.GetMaterialRef(x) + var/datum/material/custom_material = GET_MATERIAL_REF(x) custom_material.on_applied(src, materials[x] * multiplier * material_modifier, material_flags) custom_materials = SSmaterials.FindOrCreateMaterialCombo(materials, multiplier) +/** + * Returns the material composition of the atom. + * + * Used when recycling items, specifically to turn alloys back into their component mats. + * + * Exists because I'd need to add a way to un-alloy alloys or otherwise deal + * with people converting the entire stations material supply into alloys. + * + * Arguments: + * - flags: A set of flags determining how exactly the materials are broken down. + */ +/atom/proc/get_material_composition(breakdown_flags=NONE) + . = list() + if(!(breakdown_flags & BREAKDOWN_INCLUDE_ALCHEMY) && HAS_TRAIT(src, TRAIT_MAT_TRANSMUTED)) + return + + var/list/cached_materials = custom_materials + for(var/mat in cached_materials) + var/datum/material/material = GET_MATERIAL_REF(mat) + var/list/material_comp = material.return_composition(cached_materials[mat], breakdown_flags) + for(var/comp_mat in material_comp) + .[comp_mat] += material_comp[comp_mat] + +/** + * Fetches a list of all of the materials this object has of the desired type + * + * Arguments: + * - [mat_type][/datum/material]: The type of material we are checking for + * - exact: Whether to search for the _exact_ material type + * - mat_amount: The minimum required amount of material + */ +/atom/proc/has_material_type(datum/material/mat_type, exact=FALSE, mat_amount=0) + var/list/cached_materials = custom_materials + if(!length(cached_materials)) + return null + + . = list() + for(var/m in cached_materials) + if(cached_materials[m] < mat_amount) + continue + var/datum/material/material = GET_MATERIAL_REF(m) + if(exact ? material.type != m : !istype(material, mat_type)) + continue + .[material] = cached_materials[m] + +/** + * Fetches a list of all of the materials this object has with the desired material category. + * + * Arguments: + * - category: The category to check for + * - any_flags: Any bitflags that must be present for the category + * - all_flags: All bitflags that must be present for the category + * - no_flags: Any bitflags that must not be present for the category + * - mat_amount: The minimum amount of materials that must be present + */ +/atom/proc/has_material_category(category, any_flags=0, all_flags=0, no_flags=0, mat_amount=0) + var/list/cached_materials = custom_materials + if(!length(cached_materials)) + return null + + . = list() + for(var/m in cached_materials) + if(cached_materials[m] < mat_amount) + continue + var/datum/material/material = GET_MATERIAL_REF(m) + var/category_flags = material?.categories[category] + if(isnull(category_flags)) + continue + if(any_flags && !(category_flags & any_flags)) + continue + if(all_flags && (all_flags != (category_flags & all_flags))) + continue + if(no_flags && (category_flags & no_flags)) + continue + .[material] = cached_materials[m] + +/** + * Gets the most common material in the object. + */ +/atom/proc/get_master_material() + var/list/cached_materials = custom_materials + if(!length(cached_materials)) + return null + + var/most_common_material = null + var/max_amount = 0 + for(var/m in cached_materials) + if(cached_materials[m] > max_amount) + most_common_material = m + max_amount = cached_materials[m] + + if(most_common_material) + return GET_MATERIAL_REF(most_common_material) + +/** + * Gets the total amount of materials in this atom. + */ +/atom/proc/get_custom_material_amount() + return isnull(custom_materials) ? 0 : counterlist_sum(custom_materials) ///Setter for the `base_pixel_x` variable to append behavior related to its changing. /atom/proc/set_base_pixel_x(new_value) @@ -1614,29 +1713,6 @@ pixel_y = pixel_y + base_pixel_y - . - -/**Returns the material composition of the atom. - * - * Used when recycling items, specifically to turn alloys back into their component mats. - * - * Exists because I'd need to add a way to un-alloy alloys or otherwise deal - * with people converting the entire stations material supply into alloys. - * - * Arguments: - * - flags: A set of flags determining how exactly the materials are broken down. - */ -/atom/proc/get_material_composition(breakdown_flags=NONE) - . = list() - if(!(breakdown_flags & BREAKDOWN_INCLUDE_ALCHEMY) && HAS_TRAIT(src, TRAIT_MAT_TRANSMUTED)) - return - - var/list/cached_materials = custom_materials - for(var/mat in cached_materials) - var/datum/material/material = SSmaterials.GetMaterialRef(mat) - var/list/material_comp = material.return_composition(cached_materials[material], breakdown_flags) - for(var/comp_mat in material_comp) - .[comp_mat] += material_comp[comp_mat] - /** * Returns true if this atom has gravity for the passed in turf * diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index c4da40b3b11..049e2274c8d 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -48,7 +48,7 @@ ) /obj/machinery/autolathe/Initialize() - AddComponent(/datum/component/material_container, SSmaterials.materialtypes_by_category[MAT_CATEGORY_RIGID], 0, MATCONTAINER_EXAMINE, null, null, CALLBACK(src, .proc/AfterMaterialInsert)) + AddComponent(/datum/component/material_container, SSmaterials.materials_by_category[MAT_CATEGORY_RIGID], 0, MATCONTAINER_EXAMINE, _after_insert = CALLBACK(src, .proc/AfterMaterialInsert)) . = ..() wires = new /datum/wires/autolathe(src) @@ -123,14 +123,13 @@ return ..() -/obj/machinery/autolathe/proc/AfterMaterialInsert(item_inserted, id_inserted, amount_inserted) +/obj/machinery/autolathe/proc/AfterMaterialInsert(obj/item/item_inserted, id_inserted, amount_inserted) if(istype(item_inserted, /obj/item/stack/ore/bluespace_crystal)) use_power(MINERAL_MATERIAL_AMOUNT / 10) - else if(custom_materials && custom_materials.len && custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)]) - flick("autolathe_r",src)//plays glass insertion animation by default otherwise + else if(item_inserted.has_material_type(/datum/material/glass)) + flick("autolathe_r", src)//plays glass insertion animation by default otherwise else - flick("autolathe_o",src)//plays metal insertion animation - + flick("autolathe_o", src)//plays metal insertion animation use_power(min(1000, amount_inserted / 100)) updateUsrDialog() @@ -222,7 +221,7 @@ materials.use_materials(materials_used) if(is_stack) - var/obj/item/stack/N = new being_built.build_path(A, multiplier) + var/obj/item/stack/N = new being_built.build_path(A, multiplier, FALSE) N.update_icon() N.autolathe_crafted(src) else diff --git a/code/game/machinery/droneDispenser.dm b/code/game/machinery/droneDispenser.dm index 4345c76a800..460363f8468 100644 --- a/code/game/machinery/droneDispenser.dm +++ b/code/game/machinery/droneDispenser.dm @@ -50,7 +50,7 @@ /obj/machinery/drone_dispenser/Initialize() . = ..() - var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, list(/datum/material/iron, /datum/material/glass), MINERAL_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_DRONE_DISPENSER, /obj/item/stack) + var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, list(/datum/material/iron, /datum/material/glass), MINERAL_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_DRONE_DISPENSER, allowed_items=/obj/item/stack) materials.insert_amount_mat(starting_amount) materials.precise_insertion = TRUE using_materials = list(/datum/material/iron = metal_cost, /datum/material/glass = glass_cost) diff --git a/code/game/machinery/fat_sucker.dm b/code/game/machinery/fat_sucker.dm index b530d2362be..b026ed542c7 100644 --- a/code/game/machinery/fat_sucker.dm +++ b/code/game/machinery/fat_sucker.dm @@ -179,10 +179,12 @@ C.put_in_hands(new /obj/item/food/cookie, del_on_fail = TRUE) while(nutrients >= nutrient_to_meat) nutrients -= nutrient_to_meat - new C.type_of_meat (drop_location()) + var/atom/meat = new C.type_of_meat (drop_location()) + meat.set_custom_materials(list(GET_MATERIAL_REF(/datum/material/meat/mob_meat, C) = MINERAL_MATERIAL_AMOUNT * 4)) while(nutrients >= nutrient_to_meat / 3) nutrients -= nutrient_to_meat / 3 - new /obj/item/food/meat/rawcutlet/plain (drop_location()) + var/atom/meat = new /obj/item/food/meat/rawcutlet/plain (drop_location()) + meat.set_custom_materials(list(GET_MATERIAL_REF(/datum/material/meat/mob_meat, C) = round(MINERAL_MATERIAL_AMOUNT * (4/3)))) nutrients = 0 /obj/machinery/fat_sucker/screwdriver_act(mob/living/user, obj/item/I) diff --git a/code/game/machinery/sheetifier.dm b/code/game/machinery/sheetifier.dm index d388564aaae..924b12e6b84 100644 --- a/code/game/machinery/sheetifier.dm +++ b/code/game/machinery/sheetifier.dm @@ -13,7 +13,8 @@ /obj/machinery/sheetifier/Initialize() . = ..() - AddComponent(/datum/component/material_container, list(/datum/material/meat), MINERAL_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_SHEETIFIER, /obj/item/food/meat/slab, CALLBACK(src, .proc/CanInsertMaterials), CALLBACK(src, .proc/AfterInsertMaterials)) + + AddComponent(/datum/component/material_container, list(/datum/material/meat), MINERAL_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_SHEETIFIER, typesof(/datum/material/meat), /obj/item/food/meat, null, CALLBACK(src, .proc/CanInsertMaterials), CALLBACK(src, .proc/AfterInsertMaterials)) /obj/machinery/sheetifier/update_overlays() . = ..() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 2a0354df308..7e059ca465d 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1065,7 +1065,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb found_mats++ //if there's glass in it and the glass is more than 60% of the item, then we can shatter it - if(custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)] >= total_material_amount * 0.60) + if(custom_materials[GET_MATERIAL_REF(/datum/material/glass)] >= total_material_amount * 0.60) if(prob(66)) //66% chance to break it /// The glass shard that is spawned into the source item var/obj/item/shard/broken_glass = new /obj/item/shard(loc) diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index f1dafbb75ab..b8c9a5b5181 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -161,7 +161,7 @@ RLD return FALSE var/list/materials = list() - materials[SSmaterials.GetMaterialRef(/datum/material/iron)] = 500 + materials[GET_MATERIAL_REF(/datum/material/iron)] = 500 silo_mats.mat_container.use_materials(materials, amount) silo_mats.silo_log(src, "consume", -amount, "build", materials) return TRUE diff --git a/code/game/objects/items/apc_frame.dm b/code/game/objects/items/apc_frame.dm index 6eff92125fb..e9e9304dc06 100644 --- a/code/game/objects/items/apc_frame.dm +++ b/code/game/objects/items/apc_frame.dm @@ -66,8 +66,8 @@ if(iswallturf(T)) T.attackby(src, user, params) - var/metal_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]/MINERAL_MATERIAL_AMOUNT) //Replace this shit later - var/glass_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)]/MINERAL_MATERIAL_AMOUNT) //Replace this shit later + var/metal_amt = round(custom_materials[GET_MATERIAL_REF(/datum/material/iron)]/MINERAL_MATERIAL_AMOUNT) //Replace this shit later + var/glass_amt = round(custom_materials[GET_MATERIAL_REF(/datum/material/glass)]/MINERAL_MATERIAL_AMOUNT) //Replace this shit later if(W.tool_behaviour == TOOL_WRENCH && (metal_amt || glass_amt)) to_chat(user, "You dismantle [src].") diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm index 6634fc11e47..f529627524f 100644 --- a/code/game/objects/items/stacks/bscrystal.dm +++ b/code/game/objects/items/stacks/bscrystal.dm @@ -22,7 +22,7 @@ refined_type = null merge_type = /obj/item/stack/ore/bluespace_crystal/refined -/obj/item/stack/ore/bluespace_crystal/Initialize() +/obj/item/stack/ore/bluespace_crystal/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() pixel_x = rand(-5, 5) pixel_y = rand(-5, 5) diff --git a/code/game/objects/items/stacks/cash.dm b/code/game/objects/items/stacks/cash.dm index d49c8db08bf..73aa5eecb50 100644 --- a/code/game/objects/items/stacks/cash.dm +++ b/code/game/objects/items/stacks/cash.dm @@ -14,7 +14,7 @@ var/value = 0 grind_results = list(/datum/reagent/cellulose = 10) -/obj/item/stack/spacecash/Initialize() +/obj/item/stack/spacecash/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() update_desc() diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 89dd43a97e4..85e214f4bae 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -278,7 +278,7 @@ grind_results = list(/datum/reagent/medicine/spaceacillin = 2) merge_type = /obj/item/stack/medical/mesh -/obj/item/stack/medical/mesh/Initialize() +/obj/item/stack/medical/mesh/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() if(amount == max_amount) //only seal full mesh packs is_open = FALSE diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index e57cae20fad..6236538efc7 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -36,7 +36,7 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \ user.visible_message("[user] begins to stuff \the [src] down [user.p_their()] throat! It looks like [user.p_theyre()] trying to commit suicide!")//it looks like theyre ur mum return BRUTELOSS -/obj/item/stack/rods/Initialize(mapload, new_amount, merge = TRUE) +/obj/item/stack/rods/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() update_icon() diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm index 29741f3cd9c..0678745adab 100644 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -153,7 +153,7 @@ GLOBAL_LIST_INIT(xeno_recipes, list ( \ /// Kelvin to start drying var/drying_threshold_temperature = 500 -/obj/item/stack/sheet/wethide/Initialize(mapload, new_amount, merge) +/obj/item/stack/sheet/wethide/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() AddElement(/datum/element/dryable, /obj/item/stack/sheet/leather) diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 0de720af211..b69815948b4 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -595,7 +595,7 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \ . = ..() . += GLOB.bronze_recipes -/obj/item/stack/sheet/paperframes/Initialize() +/obj/item/stack/sheet/paperframes/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() pixel_x = 0 pixel_y = 0 diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm index 6d0daa37fa4..92b17d57606 100644 --- a/code/game/objects/items/stacks/sheets/sheets.dm +++ b/code/game/objects/items/stacks/sheets/sheets.dm @@ -16,7 +16,7 @@ ///What type of wall does this sheet spawn var/walltype -/obj/item/stack/sheet/Initialize(mapload, new_amount, merge) +/obj/item/stack/sheet/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() pixel_x = rand(-4, 4) pixel_y = rand(-4, 4) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 5393091e631..0745ab26a7b 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -40,7 +40,7 @@ /// Amount of matter for RCD var/matter_amount = 0 -/obj/item/stack/Initialize(mapload, new_amount, merge = TRUE) +/obj/item/stack/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) if(new_amount != null) amount = new_amount while(amount > max_amount) @@ -49,7 +49,9 @@ if(!merge_type) merge_type = type - if(LAZYLEN(mats_per_unit)) + if(LAZYLEN(mat_override)) + set_mats_per_unit(mat_override, mat_amt) + else if(LAZYLEN(mats_per_unit)) set_mats_per_unit(mats_per_unit, 1) else if(LAZYLEN(custom_materials)) set_mats_per_unit(custom_materials, amount ? 1/amount : 1) @@ -62,7 +64,7 @@ var/list/temp_recipes = get_main_recipes() recipes = temp_recipes.Copy() if(material_type) - var/datum/material/M = SSmaterials.GetMaterialRef(material_type) //First/main material + var/datum/material/M = GET_MATERIAL_REF(material_type) //First/main material for(var/i in M.categories) switch(i) if(MAT_CATEGORY_BASE_RECIPES) @@ -477,9 +479,8 @@ /obj/item/stack/proc/split_stack(mob/user, amount) if(!use(amount, TRUE, FALSE)) return null - var/obj/item/stack/F = new type(user? user : drop_location(), amount, FALSE) + var/obj/item/stack/F = new type(user? user : drop_location(), amount, FALSE, mats_per_unit) . = F - F.set_mats_per_unit(mats_per_unit, 1) // Required for greyscale sheets and tiles. F.copy_evidences(src) if(user) if(!user.put_in_hands(F, merge_stacks = FALSE)) diff --git a/code/game/objects/items/stacks/tickets.dm b/code/game/objects/items/stacks/tickets.dm index 45db72771ac..92a66471c6b 100644 --- a/code/game/objects/items/stacks/tickets.dm +++ b/code/game/objects/items/stacks/tickets.dm @@ -8,7 +8,7 @@ max_amount = 30 merge_type = /obj/item/stack/arcadeticket -/obj/item/stack/arcadeticket/Initialize(mapload, new_amount, merge = TRUE) +/obj/item/stack/arcadeticket/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() update_icon() diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 4c5cd820216..19384a21064 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -20,7 +20,7 @@ var/list/tile_reskin_types -/obj/item/stack/tile/Initialize(mapload, amount) +/obj/item/stack/tile/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() pixel_x = rand(-3, 3) pixel_y = rand(-3, 3) //randomize a little diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index c616a78ff8b..30eec3b0212 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -320,7 +320,7 @@ if(remaining_mats) for(var/M=1 to remaining_mats) new stack_type(get_turf(loc)) - else if(custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]) + else if(custom_materials[GET_MATERIAL_REF(/datum/material/iron)]) new /obj/item/stack/rods(get_turf(loc), 2) qdel(src) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 96b4f9d8a5b..3b5e562cadd 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -200,7 +200,7 @@ var/turf/newturf = T.PlaceOnTop(/turf/closed/wall/material) var/list/material_list = list() if(S.material_type) - material_list[SSmaterials.GetMaterialRef(S.material_type)] = MINERAL_MATERIAL_AMOUNT * 2 + material_list[GET_MATERIAL_REF(S.material_type)] = MINERAL_MATERIAL_AMOUNT * 2 if(material_list) newturf.set_custom_materials(material_list) diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm index 7c27b782cd7..1935e6692e5 100644 --- a/code/game/objects/structures/statues.dm +++ b/code/game/objects/structures/statues.dm @@ -52,7 +52,7 @@ if(!(flags_1 & NODECONSTRUCT_1)) var/amount_mod = disassembled ? 0 : -2 for(var/mat in custom_materials) - var/datum/material/custom_material = SSmaterials.GetMaterialRef(mat) + var/datum/material/custom_material = GET_MATERIAL_REF(mat) var/amount = max(0,round(custom_materials[mat]/MINERAL_MATERIAL_AMOUNT) + amount_mod) if(amount > 0) new custom_material.sheet_type(drop_location(),amount) @@ -520,7 +520,7 @@ Moving interrupts var/list/carving_cost = statue_costs[statue_path] var/enough_materials = TRUE for(var/required_material in carving_cost) - if(!custom_materials[required_material] || custom_materials[required_material] < carving_cost[required_material]) + if(!has_material_type(required_material, TRUE, carving_cost[required_material])) enough_materials = FALSE break if(enough_materials) diff --git a/code/modules/antagonists/gang/gang.dm b/code/modules/antagonists/gang/gang.dm index d4f4954f7a7..c429896ba10 100644 --- a/code/modules/antagonists/gang/gang.dm +++ b/code/modules/antagonists/gang/gang.dm @@ -545,6 +545,6 @@ return FALSE // didnt pass the bar check, no point in continuing to loop var/obj/machinery/ore_silo/S = GLOB.ore_silo_default var/datum/component/material_container/mat_container = S.GetComponent(/datum/component/material_container) - if(mat_container.materials[SSmaterials.GetMaterialRef(/datum/material/gold)] >= 2000) // if theres at least 1 bar of gold left in the silo, they've failed to heist all of it + if(mat_container.materials[GET_MATERIAL_REF(/datum/material/gold)] >= 2000) // if theres at least 1 bar of gold left in the silo, they've failed to heist all of it return FALSE return TRUE diff --git a/code/modules/cargo/exports/materials.dm b/code/modules/cargo/exports/materials.dm index 1b2359cc853..123c2326dc5 100644 --- a/code/modules/cargo/exports/materials.dm +++ b/code/modules/cargo/exports/materials.dm @@ -16,10 +16,11 @@ var/obj/item/I = O var/list/mat_comp = I.get_material_composition(BREAKDOWN_FLAGS_EXPORT) - if(isnull(mat_comp[SSmaterials.GetMaterialRef(material_id)])) + var/datum/material/mat_ref = ispath(material_id) ? locate(material_id) in mat_comp : GET_MATERIAL_REF(material_id) + if(isnull(mat_comp[mat_ref])) return 0 - var/amount = mat_comp[SSmaterials.GetMaterialRef(material_id)] + var/amount = mat_comp[mat_ref] if(istype(I, /obj/item/stack/ore)) amount *= 0.8 // Station's ore redemption equipment is really goddamn good. diff --git a/code/modules/clothing/shoes/bananashoes.dm b/code/modules/clothing/shoes/bananashoes.dm index 0d34acf075b..e98cef336a7 100644 --- a/code/modules/clothing/shoes/bananashoes.dm +++ b/code/modules/clothing/shoes/bananashoes.dm @@ -16,7 +16,7 @@ /obj/item/clothing/shoes/clown_shoes/banana_shoes/ComponentInitialize() . = ..() AddElement(/datum/element/update_icon_updates_onmob) - AddComponent(/datum/component/material_container, list(/datum/material/bananium), 200000, MATCONTAINER_EXAMINE|MATCONTAINER_ANY_INTENT|MATCONTAINER_SILENT, /obj/item/stack) + AddComponent(/datum/component/material_container, list(/datum/material/bananium), 100 * MINERAL_MATERIAL_AMOUNT, MATCONTAINER_EXAMINE|MATCONTAINER_ANY_INTENT|MATCONTAINER_SILENT, allowed_items=/obj/item/stack) AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 75, falloff_exponent = 20) /obj/item/clothing/shoes/clown_shoes/banana_shoes/step_action() diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index 0d45eb253c9..20764d3c590 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -69,7 +69,7 @@ */ /obj/item/reagent_containers/food/drinks/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE) if(isGlass && !custom_materials) - set_custom_materials(list(SSmaterials.GetMaterialRef(/datum/material/glass) = 5)) + set_custom_materials(list(GET_MATERIAL_REF(/datum/material/glass) = 5)) return ..() /obj/item/reagent_containers/food/drinks/afterattack(obj/target, mob/user , proximity) diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm index 2c02c85a59e..8a198ca4391 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm @@ -139,6 +139,7 @@ if(!occupant) audible_message("You hear a loud metallic grinding sound.") return + use_power(1000) audible_message("You hear a loud squelchy grinding sound.") playsound(loc, 'sound/machines/juicer.ogg', 50, TRUE) @@ -174,12 +175,14 @@ gibtype = C.gib_type if(isalien(C)) typeofskin = /obj/item/stack/sheet/animalhide/xeno + var/occupant_volume if(occupant?.reagents) occupant_volume = occupant.reagents.total_volume for (var/i=1 to meat_produced) var/obj/item/food/meat/slab/newmeat = new typeofmeat newmeat.name = "[sourcename] [newmeat.name]" + newmeat.set_custom_materials(list(GET_MATERIAL_REF(/datum/material/meat/mob_meat, occupant) = 4 * MINERAL_MATERIAL_AMOUNT)) if(istype(newmeat)) newmeat.subjectname = sourcename newmeat.reagents.add_reagent (/datum/reagent/consumable/nutriment, sourcenutriment / meat_produced) // Thehehe. Fat guys go first diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm index 37f37889eba..e10e4041409 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm @@ -319,9 +319,9 @@ var/metal = 0 for(var/obj/item/O in ingredients) O.microwave_act(src) - if(O.custom_materials && length(O.custom_materials)) - if(O.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]) - metal += O.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)] + if(LAZYLEN(O.custom_materials)) + if(O.custom_materials[GET_MATERIAL_REF(/datum/material/iron)]) + metal += O.custom_materials[GET_MATERIAL_REF(/datum/material/iron)] if(metal) spark() diff --git a/code/modules/food_and_drinks/kitchen_machinery/processor.dm b/code/modules/food_and_drinks/kitchen_machinery/processor.dm index 73555c300dc..2b6eb0e7342 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/processor.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/processor.dm @@ -28,10 +28,15 @@ . += "The status display reads: Outputting [rating_amount] item(s) at [rating_speed*100]% speed." /obj/machinery/processor/proc/process_food(datum/food_processor_process/recipe, atom/movable/what) - if (recipe.output && loc && !QDELETED(src)) - for(var/i = 0, i < (rating_amount * recipe.multiplier), i++) - new recipe.output(drop_location()) - if (isliving(what)) + if(recipe.output && loc && !QDELETED(src)) + var/list/cached_mats = recipe.preserve_materials && what.custom_materials + var/cached_multiplier = recipe.multiplier + for(var/i in 1 to cached_multiplier) + var/atom/processed_food = new recipe.output(drop_location()) + if(cached_mats) + processed_food.set_custom_materials(cached_mats, 1 / cached_multiplier) + + if(isliving(what)) var/mob/living/themob = what themob.gib(TRUE,TRUE,TRUE) else diff --git a/code/modules/food_and_drinks/recipes/processor_recipes.dm b/code/modules/food_and_drinks/recipes/processor_recipes.dm index 54ec6e7ad1f..c135551db25 100644 --- a/code/modules/food_and_drinks/recipes/processor_recipes.dm +++ b/code/modules/food_and_drinks/recipes/processor_recipes.dm @@ -1,9 +1,16 @@ /datum/food_processor_process + /// What this recipe takes var/input + /// What this recipe creates var/output + /// The amount of time this recipe takes. var/time = 40 + /// The machine required to do this recipe var/required_machine = /obj/machinery/processor + /// The number of products this recipe creates. var/multiplier = 1 //This multiplies the number of products produced per object processed. + /// Whether to copy the materials from the input to the output + var/preserve_materials = TRUE /datum/food_processor_process/meat input = /obj/item/food/meat/slab @@ -100,3 +107,4 @@ input = /obj/item/grown/log output = /obj/item/popsicle_stick multiplier = 3 + preserve_materials = FALSE diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm index b580fada7a3..fedd36ac1d1 100644 --- a/code/modules/hydroponics/biogenerator.dm +++ b/code/modules/hydroponics/biogenerator.dm @@ -188,13 +188,13 @@ update_icon() /obj/machinery/biogenerator/proc/check_cost(list/materials, multiplier = 1, remove_points = TRUE) - if(materials.len != 1 || materials[1] != SSmaterials.GetMaterialRef(/datum/material/biomass)) + if(materials.len != 1 || materials[1] != GET_MATERIAL_REF(/datum/material/biomass)) return FALSE - if (materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency > points) + if (materials[GET_MATERIAL_REF(/datum/material/biomass)]*multiplier/efficiency > points) return FALSE else if(remove_points) - points -= materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency + points -= materials[GET_MATERIAL_REF(/datum/material/biomass)]*multiplier/efficiency update_icon() return TRUE @@ -297,7 +297,7 @@ cat["items"] += list(list( "id" = D.id, "name" = D.name, - "cost" = D.materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]/efficiency, + "cost" = D.materials[GET_MATERIAL_REF(/datum/material/biomass)]/efficiency, )) data["categories"] += list(cat) diff --git a/code/modules/mining/equipment/marker_beacons.dm b/code/modules/mining/equipment/marker_beacons.dm index 3222a3c0aa2..710572122a4 100644 --- a/code/modules/mining/equipment/marker_beacons.dm +++ b/code/modules/mining/equipment/marker_beacons.dm @@ -33,7 +33,7 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sortList(list( /obj/item/stack/marker_beacon/thirty //and they're bought in stacks of 1, 10, or 30 amount = 30 -/obj/item/stack/marker_beacon/Initialize(mapload) +/obj/item/stack/marker_beacon/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() update_icon() diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index b484deb5a30..93175fbe18d 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -144,9 +144,9 @@ /datum/material/titanium, /datum/material/bluespace ) - AddComponent(/datum/component/material_container, allowed_materials, INFINITY, MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_ORE_PROCESSOR, /obj/item/stack) + AddComponent(/datum/component/material_container, allowed_materials, INFINITY, MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_ORE_PROCESSOR, allowed_items=/obj/item/stack) stored_research = new /datum/techweb/specialized/autounlocking/smelter - selected_material = SSmaterials.GetMaterialRef(/datum/material/iron) + selected_material = GET_MATERIAL_REF(/datum/material/iron) /obj/machinery/mineral/processing_unit/Destroy() CONSOLE = null diff --git a/code/modules/mining/machine_silo.dm b/code/modules/mining/machine_silo.dm index e1e9544fb7b..de05a2e612e 100644 --- a/code/modules/mining/machine_silo.dm +++ b/code/modules/mining/machine_silo.dm @@ -28,7 +28,7 @@ GLOBAL_LIST_EMPTY(silo_access_logs) /datum/material/bluespace, /datum/material/plastic, ) - AddComponent(/datum/component/material_container, materials_list, INFINITY, MATCONTAINER_NO_INSERT, /obj/item/stack) + AddComponent(/datum/component/material_container, materials_list, INFINITY, MATCONTAINER_NO_INSERT, allowed_items=/obj/item/stack) if (!GLOB.ore_silo_default && mapload && is_station_level(z)) GLOB.ore_silo_default = src @@ -57,8 +57,8 @@ GLOBAL_LIST_EMPTY(silo_access_logs) if(!istype(I) || (I.flags_1 & HOLOGRAM_1) || (I.item_flags & NO_MAT_REDEMPTION)) to_chat(user, "[M] won't accept [I]!") return - var/item_mats = I.get_material_composition(breakdown_flags) & materials.materials - if(!length(item_mats)) + var/item_mats = materials.get_item_material_amount(I, breakdown_flags) + if(!item_mats) to_chat(user, "[I] does not contain sufficient materials to be accepted by [M].") return // assumes unlimited space... diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index c5f97a6ba27..f6096c6edc0 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -326,7 +326,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ explosion(src,0,1,3,adminlog = notify_admins) qdel(src) -/obj/item/stack/ore/Initialize() +/obj/item/stack/ore/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() pixel_x = base_pixel_x + rand(0, 16) - 8 pixel_y = base_pixel_y + rand(0, 8) - 8 diff --git a/code/modules/mob/living/simple_animal/hostile/goose.dm b/code/modules/mob/living/simple_animal/hostile/goose.dm index 28284705cff..aa003c2ab64 100644 --- a/code/modules/mob/living/simple_animal/hostile/goose.dm +++ b/code/modules/mob/living/simple_animal/hostile/goose.dm @@ -60,7 +60,7 @@ /mob/living/simple_animal/hostile/retaliate/goose/vomit/handle_automated_action() if(length(nummies)) var/obj/item/E = pick(nummies) - if(!(E.custom_materials && E.custom_materials[SSmaterials.GetMaterialRef(/datum/material/plastic)])) + if(!E.has_material_type(/datum/material/plastic)) nummies -= E // remove non-plastic item from queue E = locate(/obj/item/reagent_containers/food) in nummies // find food if(E && E.loc == loc) @@ -70,7 +70,7 @@ /mob/living/simple_animal/hostile/retaliate/goose/proc/feed(obj/item/suffocator) if(stat == DEAD || choking) // plapatin I swear to god return FALSE - if(suffocator.custom_materials && suffocator.custom_materials[SSmaterials.GetMaterialRef(/datum/material/plastic)]) // dumb goose'll swallow food or drink with plastic in it + if(suffocator.has_material_type(/datum/material/plastic)) // dumb goose'll swallow food or drink with plastic in it visible_message("[src] hungrily gobbles up \the [suffocator]! ") visible_message("[src] is choking on \the [suffocator]! ") suffocator.forceMove(src) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 060435232db..7ee0ecd6f4c 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -414,7 +414,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri var/obj/structure/cable/target_type = /obj/structure/cable var/target_layer = CABLE_LAYER_2 -/obj/item/stack/cable_coil/Initialize(mapload, new_amount = null) +/obj/item/stack/cable_coil/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) . = ..() pixel_x = base_pixel_x + rand(-2, 2) pixel_y = base_pixel_y + rand(-2, 2) @@ -591,7 +591,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri icon_state = "coil2" worn_icon_state = "coil" -/obj/item/stack/cable_coil/cut/Initialize(mapload) +/obj/item/stack/cable_coil/cut/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) if(!amount) amount = rand(1,2) . = ..() diff --git a/code/modules/power/pipecleaners.dm b/code/modules/power/pipecleaners.dm index 996a5e3e6d2..adecef56c63 100644 --- a/code/modules/power/pipecleaners.dm +++ b/code/modules/power/pipecleaners.dm @@ -81,9 +81,9 @@ By design, d1 is the smallest direction and d2 is the highest d2 = text2num(copytext(icon_state, dash + length(icon_state[dash]))) if(d1) - stored = new/obj/item/stack/pipe_cleaner_coil(null, 2, color) + stored = new/obj/item/stack/pipe_cleaner_coil(null, 2, null, null, null, color) else - stored = new/obj/item/stack/pipe_cleaner_coil(null, 1, color) + stored = new/obj/item/stack/pipe_cleaner_coil(null, 1, null, null, null, color) color = param_color || color if(!color) @@ -234,10 +234,11 @@ By design, d1 is the smallest direction and d2 is the highest user.visible_message("[user] is strangling [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!") return(OXYLOSS) -/obj/item/stack/pipe_cleaner_coil/Initialize(mapload, new_amount = null, param_color = null) +/obj/item/stack/pipe_cleaner_coil/Initialize(mapload, new_amount = null, list/mat_override=null, mat_amt=1, param_color = null) . = ..() - color = param_color || color + if(param_color) + color = param_color if(!color) var/list/pipe_cleaner_colors = GLOB.pipe_cleaner_colors var/random_color = pick(pipe_cleaner_colors) diff --git a/code/modules/projectiles/boxes_magazines/_box_magazine.dm b/code/modules/projectiles/boxes_magazines/_box_magazine.dm index 62e55cf75f7..9d9192a6693 100644 --- a/code/modules/projectiles/boxes_magazines/_box_magazine.dm +++ b/code/modules/projectiles/boxes_magazines/_box_magazine.dm @@ -35,14 +35,9 @@ /obj/item/ammo_box/Initialize() . = ..() - if (!bullet_cost) - for (var/material in custom_materials) - var/material_amount = custom_materials[material] - LAZYSET(base_cost, material, (material_amount * 0.10)) - - material_amount *= 0.90 // 10% for the container - material_amount /= max_ammo - LAZYSET(bullet_cost, material, material_amount) + if(!bullet_cost) + base_cost = SSmaterials.FindOrCreateMaterialCombo(custom_materials, 0.1) + bullet_cost = SSmaterials.FindOrCreateMaterialCombo(custom_materials, 0.9 / max_ammo) if(!start_empty) top_off(starting=TRUE) update_icon() diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index ca440a8cb0a..eacddfc0fa1 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -139,7 +139,11 @@ iter_reagent.on_merge(data, amount) if(reagtemp != cached_temp) - set_temperature(((old_heat_capacity * cached_temp) + (iter_reagent.specific_heat * amount * reagtemp)) / heat_capacity()) + var/new_heat_capacity = heat_capacity() + if(new_heat_capacity) + set_temperature(((old_heat_capacity * cached_temp) + (iter_reagent.specific_heat * amount * reagtemp)) / new_heat_capacity) + else + set_temperature(reagtemp) SEND_SIGNAL(src, COMSIG_REAGENTS_ADD_REAGENT, iter_reagent, amount, reagtemp, data, no_react) if(!no_react) @@ -160,7 +164,11 @@ update_total() if(reagtemp != cached_temp) - set_temperature(((old_heat_capacity * cached_temp) + (new_reagent.specific_heat * amount * reagtemp)) / heat_capacity()) + var/new_heat_capacity = heat_capacity() + if(new_heat_capacity) + set_temperature(((old_heat_capacity * cached_temp) + (new_reagent.specific_heat * amount * reagtemp)) / new_heat_capacity) + else + set_temperature(reagtemp) SEND_SIGNAL(src, COMSIG_REAGENTS_NEW_REAGENT, new_reagent, amount, reagtemp, data, no_react) if(!no_react) @@ -978,6 +986,8 @@ */ /datum/reagents/proc/adjust_thermal_energy(delta_energy, min_temp = 2.7, max_temp = 1000) var/heat_capacity = heat_capacity() + if(!heat_capacity) + return // no div/0 please set_temperature(clamp(chem_temp + (delta_energy / heat_capacity), min_temp, max_temp)) /// Applies heat to this holder diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 5f27bcbe39a..480f5f949f2 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -85,7 +85,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) addiction_type = type if(material) - material = SSmaterials.GetMaterialRef(material) + material = GET_MATERIAL_REF(material) /datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references . = ..() diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index 49361566f7d..1a460dbf595 100755 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -125,7 +125,7 @@ */ /obj/item/reagent_containers/glass/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE) if(!custom_materials) - set_custom_materials(list(SSmaterials.GetMaterialRef(/datum/material/glass) = 5))//sets it to glass so, later on, it gets picked up by the glass catch (hope it doesn't 'break' things lol) + set_custom_materials(list(GET_MATERIAL_REF(/datum/material/glass) = 5))//sets it to glass so, later on, it gets picked up by the glass catch (hope it doesn't 'break' things lol) return ..() /obj/item/reagent_containers/glass/beaker diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index 21e5c69996d..a4fb1d63a32 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -175,7 +175,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) "You struggle to pry up \the [src] with \the [I].") if(I.use_tool(src, user, 40, volume=40)) if(!(machine_stat & BROKEN)) - var/obj/item/stack/conveyor/C = new /obj/item/stack/conveyor(loc, 1, TRUE, id) + var/obj/item/stack/conveyor/C = new /obj/item/stack/conveyor(loc, 1, TRUE, null, null, id) transfer_fingerprints_to(C) to_chat(user, "You remove the conveyor belt.") qdel(src) @@ -425,7 +425,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) ///id for linking var/id = "" -/obj/item/stack/conveyor/Initialize(mapload, new_amount, merge = TRUE, _id) +/obj/item/stack/conveyor/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1, _id) . = ..() id = _id diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index f47744d6e8f..85477d2510f 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -21,23 +21,41 @@ other types of metals and chemistry for reagents). //DO NOT REFERENCE OUTSIDE OF SSRESEARCH. USE THE PROCS IN SSRESEARCH TO OBTAIN A REFERENCE. /datum/design //Datum for object designs, used in construction - var/name = "Name" //Name of the created object. - var/desc = "Desc" //Description of the created object. - var/id = DESIGN_ID_IGNORE //ID of the created object for easy refernece. Alphanumeric, lower-case, no symbols - var/build_type = null //Flag as to what kind machine the design is built in. See defines. - var/list/materials = list() //List of materials. Format: "id" = amount. - var/construction_time //Amount of time required for building the object - var/build_path = null //The file path of the object that gets created - var/list/make_reagents = list() //Reagents produced. Format: "id" = amount. Currently only supported by the biogenerator. - var/list/category = null //Primarily used for Mech Fabricators, but can be used for anything - var/list/reagents_list = list() //List of reagents. Format: "id" = amount. + /// Name of the created object + var/name = "Name" + /// Description of the created object + var/desc = "Desc" + /// The ID of the design. Used for quick reference. Alphanumeric, lower-case, no symbols + var/id = DESIGN_ID_IGNORE + /// Bitflags indicating what machines this design is compatable with. ([IMPRINTER]|[PROTOLATHE]|[AUTOLATHE]|[CRAFTLATHE]|[MECHFAB]|[BIOGENERATOR]|[LIMBGROWER]|[SMELTER]|[NANITE_COMPILER]) + var/build_type = null + /// List of materials required to create one unit of the product. Format is (typepath or caregory) -> amount + var/list/materials = list() + /// The amount of time required to create one unit of the product. + var/construction_time + /// The typepath of the object produced by this design + var/build_path = null + /// List of reagents produced by this design. Currently only supported by the biogenerator. + var/list/make_reagents = list() + /// What category this design falls under. Used for sorting in production machines, mostly the mechfab. + var/list/category = null + /// List of reagents required to create one unit of the product. + var/list/reagents_list = list() + /// The maximum number of units of whatever is produced by this can be produced in one go. var/maxstack = 1 - var/lathe_time_factor = 1 //How many times faster than normal is this to build on the protolathe - var/dangerous_construction = FALSE //notify and log for admin investigations if this is printed. - var/departmental_flags = ALL //bitflags for deplathes. + /// How many times faster than normal is this to build on the protolathe + var/lathe_time_factor = 1 + /// If this is [TRUE] the admins get notified whenever anyone prints this. Currently only used by the BoH. + var/dangerous_construction = FALSE + /// Bitflags indicating what departmental lathes should be allowed to process this design. + var/departmental_flags = ALL + /// What techwebs nodes unlock this design. Constructed by SSresearch var/list/datum/techweb_node/unlocked_by = list() - var/research_icon //Replaces the item icon in the research console + /// Override for the automatic icon generation used for the research console. + var/research_icon + /// Override for the automatic icon state generation used for the research console. var/research_icon_state + /// Appears to be unused. var/icon_cache /// Optional string that interfaces can use as part of search filters. See- item/borg/upgrade/ai and the Exosuit Fabs. var/search_metadata @@ -55,7 +73,7 @@ other types of metals and chemistry for reagents). for(var/i in materials) //Go through all of our materials, get the subsystem instance, and then replace the list. var/amount = materials[i] if(!istext(i)) //Not a category, so get the ref the normal way - var/datum/material/M = SSmaterials.GetMaterialRef(i) + var/datum/material/M = GET_MATERIAL_REF(i) temp_list[M] = amount else temp_list[i] = amount diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index a79f539b2df..469ca211da0 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -83,19 +83,45 @@ I.set_custom_materials(matlist) SSblackbox.record_feedback("nested tally", "item_printed", amount, list("[type]", "[path]")) -/obj/machinery/rnd/production/proc/check_mat(datum/design/being_built, mat) // now returns how many times the item can be built with the material - if (!materials.mat_container) // no connected silo +/** + * Returns how many times over the given material requirement for the given design is satisfied. + * + * Arguments: + * - [being_built][/datum/design]: The design being referenced. + * - material: The material being checked. + */ +/obj/machinery/rnd/production/proc/check_material_req(datum/design/being_built, material) + if(!materials.mat_container) // no connected silo return 0 - var/list/all_materials = being_built.reagents_list + being_built.materials - var/A = materials.mat_container.get_material_amount(mat) - if(!A) - A = reagents.get_reagent_amount(mat) + var/mat_amt = materials.mat_container.get_material_amount(material) + if(!mat_amt) + return 0 // these types don't have their .materials set in do_print, so don't allow // them to be constructed efficiently - var/ef = efficient_with(being_built.build_path) ? efficiency_coeff : 1 - return round(A / max(1, all_materials[mat] / ef)) + var/efficiency = efficient_with(being_built.build_path) ? efficiency_coeff : 1 + return round(mat_amt / max(1, being_built.materials[material] / efficiency)) + +/** + * Returns how many times over the given reagent requirement for the given design is satisfied. + * + * Arguments: + * - [being_built][/datum/design]: The design being referenced. + * - reagent: The reagent being checked. + */ +/obj/machinery/rnd/production/proc/check_reagent_req(datum/design/being_built, reagent) + if(!reagents) // no reagent storage + return 0 + + var/chem_amt = reagents.get_reagent_amount(reagent) + if(!chem_amt) + return 0 + + // these types don't have their .materials set in do_print, so don't allow + // them to be constructed efficiently + var/efficiency = efficient_with(being_built.build_path) ? efficiency_coeff : 1 + return round(chem_amt / max(1, being_built.reagents_list[reagent] / efficiency)) /obj/machinery/rnd/production/proc/efficient_with(path) return !ispath(path, /obj/item/stack/sheet) && !ispath(path, /obj/item/stack/ore/bluespace_crystal) @@ -239,35 +265,47 @@ /obj/machinery/rnd/production/proc/design_menu_entry(datum/design/D, coeff) if(!istype(D)) return - if(!coeff) - coeff = efficiency_coeff if(!efficient_with(D.build_path)) coeff = 1 - var/list/l = list() - var/temp_material - var/c = 50 - var/t - var/all_materials = D.materials + D.reagents_list - for(var/M in all_materials) - t = check_mat(D, M) - temp_material += " | " - if (t < 1) - temp_material += "[all_materials[M]/coeff] [CallMaterialName(M)]" - else - temp_material += " [all_materials[M]/coeff] [CallMaterialName(M)]" - c = min(c,t) + else if(!coeff) + coeff = efficiency_coeff - if (c >= 1) - l += "[D.name][RDSCREEN_NOBREAK]" - if(c >= 5) - l += "x5[RDSCREEN_NOBREAK]" - if(c >= 10) - l += "x10[RDSCREEN_NOBREAK]" - l += "[temp_material][RDSCREEN_NOBREAK]" + var/list/entry_text = list() + var/temp_material + var/max_production = 50 + var/list/cached_mats = D.materials + for(var/material in cached_mats) + var/enough_mats = check_material_req(D, material) + max_production = min(max_production, enough_mats) + + temp_material += " | " + if (enough_mats < 1) + temp_material += "[cached_mats[material]/coeff] [CallMaterialName(material)]" + else + temp_material += " [cached_mats[material]/coeff] [CallMaterialName(material)]" + + var/list/cached_reagents = D.reagents_list + for(var/reagent in cached_reagents) + var/enough_chems = check_reagent_req(D, reagent) + max_production = min(max_production, enough_chems) + + temp_material += " | " + if (enough_chems < 1) + temp_material += "[cached_reagents[reagent]/coeff] [CallMaterialName(reagent)]" + else + temp_material += " [cached_reagents[reagent]/coeff] [CallMaterialName(reagent)]" + + if (max_production >= 1) + entry_text += "[D.name][RDSCREEN_NOBREAK]" + if(max_production >= 5) + entry_text += "x5[RDSCREEN_NOBREAK]" + if(max_production >= 10) + entry_text += "x10[RDSCREEN_NOBREAK]" + entry_text += "[temp_material][RDSCREEN_NOBREAK]" else - l += "[D.name][temp_material][RDSCREEN_NOBREAK]" - l += "" - return l + entry_text += "[D.name][temp_material][RDSCREEN_NOBREAK]" + entry_text += "" + return entry_text /obj/machinery/rnd/production/Topic(raw, ls) if(..()) @@ -290,7 +328,11 @@ if(ls["category"]) selected_category = ls["category"] if(ls["dispose"]) //Causes the protolathe to dispose of a single reagent (all of it) - reagents.del_reagent(ls["dispose"]) + var/reagent_path = text2path(ls["dispose"]) + if(!ispath(reagent_path, /datum/reagent)) + stack_trace("Invalid reagent typepath - [ls["dispose"]] - returned in reagent disposal topic call") + else + reagents.del_reagent(reagent_path) if(ls["disposeall"]) //Causes the protolathe to dispose of all it's reagents. reagents.clear_reagents() if(ls["ejectsheet"]) //Causes the protolathe to eject a sheet of material diff --git a/code/modules/swarmers/swarmer_act.dm b/code/modules/swarmers/swarmer_act.dm index 0c73a66da4b..80c6def2a7e 100644 --- a/code/modules/swarmers/swarmer_act.dm +++ b/code/modules/swarmers/swarmer_act.dm @@ -55,7 +55,7 @@ /obj/item/integrate_amount() //returns the amount of resources gained when eating this item var/list/mats = get_material_composition(ALL) // Ensures that items made from plasteel, and plas/titanium/plastitaniumglass get integrated correctly. - if(length(mats) && (mats[SSmaterials.GetMaterialRef(/datum/material/iron)] || mats[SSmaterials.GetMaterialRef(/datum/material/glass)])) + if(length(mats) && (mats[GET_MATERIAL_REF(/datum/material/iron)] || mats[GET_MATERIAL_REF(/datum/material/glass)])) return 1 return ..() diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index c606e031bc2..b5a9dd61f6e 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -1202,8 +1202,7 @@ to_chat(user, "You add [ammo_needed] [A.round_term][ammo_needed > 1?"s":""] to the [gun.name]") A.rounds = A.rounds - ammo_needed if(A.custom_materials) - for(var/i in A.custom_materials) - A.custom_materials[i] = A.custom_materials[i] * (A.rounds/initial(A.rounds)) + A.set_custom_materials(A.custom_materials, A.rounds / initial(A.rounds)) A.update_name() return TRUE