diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 4a483268e81..878ed53f990 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -42,13 +42,13 @@ #define ARMOR_ALL "all_damage_types" /// Armor values that are used for damage -#define ARMOR_LIST_DAMAGE(...) list(BIO, BOMB, BULLET, ENERGY, LASER, MELEE, WOUND) +#define ARMOR_LIST_DAMAGE list(BIO, BOMB, BULLET, ENERGY, LASER, MELEE, WOUND) /// Armor values that are used for durability -#define ARMOR_LIST_DURABILITY(...) list(ACID, FIRE) +#define ARMOR_LIST_DURABILITY list(ACID, FIRE) /// All armors, preferable in the order as seen above -#define ARMOR_LIST_ALL(...) list(ACID, BIO, BOMB, BULLET, CONSUME, ENERGY, FIRE, LASER, MELEE, WOUND) +#define ARMOR_LIST_ALL list(ACID, BIO, BOMB, BULLET, CONSUME, ENERGY, FIRE, LASER, MELEE, WOUND) //bitflag damage defines used for suicide_act #define BRUTELOSS (1<<0) diff --git a/code/__DEFINES/construction/material.dm b/code/__DEFINES/construction/material.dm index 462e69334ae..4cf54b8de2f 100644 --- a/code/__DEFINES/construction/material.dm +++ b/code/__DEFINES/construction/material.dm @@ -14,59 +14,121 @@ /// Maximum amount of cable in a coil #define MAXCOIL 30 -//Category of materials -/// Can this material be stored in the ore silo -#define MAT_CATEGORY_SILO "silo capable" -/// Hard materials, such as iron or silver -#define MAT_CATEGORY_RIGID "rigid material" -/// Materials that can be used to craft items -#define MAT_CATEGORY_ITEM_MATERIAL "item material" -/** - * Materials that can also be used to craft items for designs that require two custom mats. - * This is mainly a work around to the fact we can't (easily) have the same category show - * multiple times in a list with different values, because list access operator [] will fetch the - * top-most value. - */ -#define MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY "item material complementary" - -/// Use this flag on TRUE if you want the basic recipes -#define MAT_CATEGORY_BASE_RECIPES "basic recipes" - -///Flags for map loaded materials +// Flags for material loading /// Used to make a material initialize at roundstart. -#define MATERIAL_INIT_MAPLOAD (1<<0) +#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) +#define MATERIAL_INIT_BESPOKE (1 << 1) -//Material Container Flags. -///If the container shows the amount of contained materials on examine. -#define MATCONTAINER_EXAMINE (1<<0) -///If the container cannot have materials inserted through attackby(). -#define MATCONTAINER_NO_INSERT (1<<1) -///If the user can insert mats into the container despite the intent. -#define MATCONTAINER_ANY_INTENT (1<<2) -///If the user won't receive a warning when attacking the container with an unallowed item. -#define MATCONTAINER_SILENT (1<<3) -///Alloys won't be disassembled in its components when inserted. -#define MATCONTAINER_ACCEPT_ALLOYS (1<<4) +// Flags for material behaviors +// Negative values can be used to instead act as a blacklist +/// This material can be stored in an ore silo +#define MATERIAL_SILO_STORED (1 << 0) +/// This material can be used in basic recipes, such as chairs/toilets/tiles +#define MATERIAL_BASIC_RECIPES (1 << 1) +/// This material counts as a rigid enough solid to be used to craft tough objects like carving blocks or air tanks +#define MATERIAL_CLASS_RIGID (1 << 2) +/// The opposite of rigid, this means that the material cannot hold a solid form (like sand) and cannot be used in item crafting +#define MATERIAL_CLASS_AMORPHOUS (1 << 3) +/// This material is a metal and can be used in construction as one +#define MATERIAL_CLASS_METAL (1 << 4) +/// This material is a fabric and can be used to make clothing +#define MATERIAL_CLASS_FABRIC (1 << 5) +/// This material is a crystal and can be used to make windows or shards +#define MATERIAL_CLASS_CRYSTAL (1 << 6) +/// This is an organic material, meaning its probably alive in some way. Or was alive at one point, rather. +#define MATERIAL_CLASS_ORGANIC (1 << 7) +/// This is a polymer of some sorts +#define MATERIAL_CLASS_POLYMER (1 << 8) +/// Wildcard flag for recipes and alike to allow any material to be used +#define MATERIAL_CLASS_ANY 0 + +/// All material class flags usable for generic crafting +#define ITEM_MATERIAL_CLASSES (MATERIAL_CLASS_METAL | MATERIAL_CLASS_CRYSTAL | MATERIAL_CLASS_POLYMER | MATERIAL_CLASS_RIGID) +/// All material type class flags +#define MATERIAL_TYPE_CLASSES (MATERIAL_CLASS_METAL | MATERIAL_CLASS_FABRIC | MATERIAL_CLASS_CRYSTAL | MATERIAL_CLASS_ORGANIC | MATERIAL_CLASS_POLYMER) + +/// Assoc list of material flags used in designs to their display names +GLOBAL_LIST_INIT(material_flags_to_string, alist( + MATERIAL_CLASS_RIGID = "rigid", + MATERIAL_CLASS_AMORPHOUS = "amorphous", + MATERIAL_CLASS_METAL = "metallic", + MATERIAL_CLASS_FABRIC = "fabric", + MATERIAL_CLASS_CRYSTAL = "crystalline", + MATERIAL_CLASS_ORGANIC = "organic", + MATERIAL_CLASS_POLYMER = "polymer", +)) + +// You can use a calculator at https://www.desmos.com/calculator/wbkx4ttj3j for easy property calculations + +// Core material property IDs +#define MATERIAL_DENSITY "density" +#define MATERIAL_HARDNESS "hardness" +#define MATERIAL_FLEXIBILITY "flexibility" +#define MATERIAL_REFLECTIVITY "reflectivity" +#define MATERIAL_ELECTRICAL "electrical_conductivity" +#define MATERIAL_THERMAL "thermal_conductivity" +#define MATERIAL_CHEMICAL "chemical_resistance" + +// Optional material property IDs +#define MATERIAL_FLAMMABILITY "flammability" +#define MATERIAL_RADIOACTIVITY "radioactivity" + +// Derived material property IDs +#define MATERIAL_INTEGRITY "integrity" +#define MATERIAL_BEAUTY "beauty" + +/// Maximum value for a core material property +#define MATERIAL_PROPERTY_MAX 10 +/// Allows to easily add "deadzones" for properties, and only adjust stats if they go below/above said deadzones. Basically two starting points for modifiers. +#define MATERIAL_PROPERTY_DIVERGENCE(property, minimum, maximum) (min(0, property - minimum) + max(0, property - maximum)) + +/// Minimum theoretical item force multiplier from materials +#define MATERIAL_MIN_FORCE_MULTIPLIER 0.1 +/// Maximum theoretical item force multiplier from materials +#define MATERIAL_MAX_FORCE_MULTIPLIER 2 + +/// Slowdown per density over 6 / below 3 per sheet of material +#define MATERIAL_DENSITY_SLOWDOWN 0.02 + +/// Multiplier for the amount of reagents added to the item upon accidental consumption +#define MATERIAL_REAGENT_CONSUMPTION_MULT 0.4 +/// Amount of reagents per sheet of material. Not affected by density for simplicity and easier consistency upkeep +#define MATERIAL_REAGENTS_PER_SHEET 20 + +// Material Container Flags. +/// If the container shows the amount of contained materials on examine. +#define MATCONTAINER_EXAMINE (1 << 0) +/// If the container cannot have materials inserted through attackby(). +#define MATCONTAINER_NO_INSERT (1 << 1) +/// If the user can insert mats into the container despite the intent. +#define MATCONTAINER_ANY_INTENT (1 << 2) +/// If the user won't receive a warning when attacking the container with an unallowed item. +#define MATCONTAINER_SILENT (1 << 3) +/// Alloys won't be disassembled in its components when inserted. +#define MATCONTAINER_ACCEPT_ALLOYS (1 << 4) +/// Prevents material items from displaying their descriptors in examine_more with sci glasses +#define MATERIAL_NO_DESCRIPTORS (1 << 5) + +// Atom material behavior flags /// Whether a material's mechanical effects should apply to the atom. This is necessary for other flags to work. -#define MATERIAL_EFFECTS (1<<0) +#define MATERIAL_EFFECTS (1 << 0) /// Applies the material color to the atom's color. Deprecated, use MATERIAL_GREYSCALE instead -#define MATERIAL_COLOR (1<<1) +#define MATERIAL_COLOR (1 << 1) /// Whether a prefix describing the material should be added to the name -#define MATERIAL_ADD_PREFIX (1<<2) +#define MATERIAL_ADD_PREFIX (1 << 2) /// Whether a material should affect the stats of the atom -#define MATERIAL_AFFECT_STATISTICS (1<<3) +#define MATERIAL_AFFECT_STATISTICS (1 << 3) /// Applies the material greyscale color to the atom's greyscale color. -#define MATERIAL_GREYSCALE (1<<4) +#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) +#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) +/// Ignore custom material grind results +#define MATERIAL_NO_REAGENTS (1 << 7) //Special return values of [/datum/material_container/insert_item] /// No material was found inside them item @@ -76,14 +138,13 @@ /// The item material type was not accepted or other reasons #define MATERIAL_INSERT_ITEM_FAILURE 0 - // Slowdown values. /// The slowdown value of one [SHEET_MATERIAL_AMOUNT] of plasteel. #define MATERIAL_SLOWDOWN_PLASTEEL (0.05) /// The slowdown value of one [SHEET_MATERIAL_AMOUNT] of alien alloy. #define MATERIAL_SLOWDOWN_ALIEN_ALLOY (0.1) -//Stock market stock values. +// Stock market stock values. /// How much quantity of a material stock exists for common materials like iron & glass. #define MATERIAL_QUANTITY_COMMON 5000 /// How much quantity of a material stock exists for uncommon materials like silver & titanium. @@ -105,9 +166,9 @@ /// Is this material only going to spawn once in ore vents? (6% of vents on lavaland) #define MATERIAL_RARITY_UNDISCOVERED 1 -///The key to access the 'optimal' amount of a material key from its assoc value list. +/// The key to access the 'optimal' amount of a material key from its assoc value list. #define MATERIAL_LIST_OPTIMAL_AMOUNT "optimal_amount" -///The key to access the multiplier used to selectively control effects and modifiers of a material. +/// The key to access the multiplier used to selectively control effects and modifiers of a material. #define MATERIAL_LIST_MULTIPLIER "multiplier" -///A macro that ensures some multiplicative modifiers higher than 1 don't become lower than 1 and vice-versa because of the multiplier. +/// A macro that ensures some multiplicative modifiers higher than 1 don't become lower than 1 and vice-versa because of the multiplier. #define GET_MATERIAL_MODIFIER(modifier, multiplier) (modifier >= 1 ? 1 + ((modifier) - 1) * (multiplier) : (modifier)**(multiplier)) diff --git a/code/__DEFINES/dcs/signals/signals_materials.dm b/code/__DEFINES/dcs/signals/signals_materials.dm new file mode 100644 index 00000000000..2eefb523548 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_materials.dm @@ -0,0 +1,10 @@ +/// from base of [/datum/materials_controller/proc/initialize_material]: (/datum/material) +#define COMSIG_MATERIALS_INIT_MAT "SSmaterials_init_mat" +/// from /datum/material/proc/on_applied(source, mat_amount, multiplier): (atom/new_atom, mat_amount, multiplier) +#define COMSIG_MATERIAL_APPLIED "material_applied" +/// from /datum/material/proc/on_main_applied(source, mat_amount, multiplier): (atom/new_atom, mat_amount, multiplier) +#define COMSIG_MATERIAL_MAIN_APPLIED "material_main_applied" +/// from /datum/material/proc/on_removed(source, mat_amount, multiplier): (atom/old_atom, amount, material_flags) +#define COMSIG_MATERIAL_REMOVED "material_removed" +/// from /datum/material/proc/on_main_removed(source, mat_amount, multiplier): (atom/old_atom, mat_amount, multiplier) +#define COMSIG_MATERIAL_MAIN_REMOVED "material_main_removed" diff --git a/code/__DEFINES/dcs/signals/signals_reagent.dm b/code/__DEFINES/dcs/signals/signals_reagent.dm index 157f7058a4c..8bdd4cbd397 100644 --- a/code/__DEFINES/dcs/signals/signals_reagent.dm +++ b/code/__DEFINES/dcs/signals/signals_reagent.dm @@ -21,9 +21,6 @@ ///from base of [/datum/reagent/proc/on_transfer_creation(reagent, target_holder, new_reagent)]: (datum/reagents/target_holder, datum/reagent/new_reagent) #define COMSIG_REAGENT_ON_TRANSFER "reagent_on_transfer" -///from base of [/datum/materials_controller/proc/InitializeMaterial]: (/datum/material) -#define COMSIG_MATERIALS_INIT_MAT "SSmaterials_init_mat" - ///from base of [/datum/component/multiple_lives/proc/respawn]: (mob/respawned_mob, gibbed, lives_left) #define COMSIG_ON_MULTIPLE_LIVES_RESPAWN "on_multiple_lives_respawn" diff --git a/code/__HELPERS/construction.dm b/code/__HELPERS/construction.dm index 49a048c0160..557f93efc34 100644 --- a/code/__HELPERS/construction.dm +++ b/code/__HELPERS/construction.dm @@ -1,9 +1,6 @@ /// Makes sure only integer values are used when consuming, removing & checking for mats #define OPTIMAL_COST(cost)(max(1, floor(cost))) -/// 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)) - // Wrapper to convert material name into its source name #define MATERIAL_SOURCE(mat) "[mat.name]_material" diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm index 7d34b600939..62d72a9d18c 100644 --- a/code/controllers/subsystem/materials.dm +++ b/code/controllers/subsystem/materials.dm @@ -7,19 +7,15 @@ 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.id || material ref + /// Dictionary of material.id || material ref var/list/materials - ///Dictionary of type || list of material refs + /// Flat list of materials + var/list/flat_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 ids, mostly used by rnd machines like autolathes. - var/list/materialids_by_category - ///A cache of all material combinations that have been used + /// A cache of all material combinations that have been used var/list/list/material_combos - ///List of stackcrafting recipes for materials using base recipes + /// List of stackcrafting recipes for materials using base recipes var/list/base_stack_recipes = list( new /datum/stack_recipe("Chair", /obj/structure/chair/greyscale, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_SKIP_MATERIALS_PARITY, category = CAT_FURNITURE), new /datum/stack_recipe("Toilet", /obj/structure/toilet/greyscale, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_SKIP_MATERIALS_PARITY, category = CAT_FURNITURE), @@ -28,95 +24,123 @@ SUBSYSTEM_DEF(materials) new /datum/stack_recipe("Material airlock assembly", /obj/structure/door_assembly/door_assembly_material, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_SKIP_MATERIALS_PARITY, category = CAT_DOORS), new /datum/stack_recipe("Material platform", /obj/structure/platform/material, 2, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_SKIP_MATERIALS_PARITY, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75, category = CAT_STRUCTURE), \ ) - ///List of stackcrafting recipes for materials using rigid recipes + /// List of stackcrafting recipes for materials using rigid recipes var/list/rigid_stack_recipes = list( new /datum/stack_recipe("Carving block", /obj/structure/carving_block, 5, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_SKIP_MATERIALS_PARITY, category = CAT_STRUCTURE), ) - ///A list of dimensional themes used by the dimensional anomaly and other things, most of which require materials to function. + /// A list of dimensional themes used by the dimensional anomaly and other things, most of which require materials to function. var/list/datum/dimension_theme/dimensional_themes + /// An ID -> instance list of material properties + var/list/datum/material_property/properties + /// A typepath -> instance list of material requirements + var/list/datum/material_requirement/requirements -///Ran on initialize, populated the materials and materials_by_category dictionaries with their appropriate vars (See these variables for more info) -/datum/controller/subsystem/materials/proc/InitializeMaterials() +///Ran on initialize, populated the materials and material dictionaries with their appropriate vars (See these variables for more info) +/datum/controller/subsystem/materials/proc/initialize_materials() materials = list() + flat_materials = list() materials_by_type = list() - materialids_by_type = list() - materials_by_category = list() - materialids_by_category = list() material_combos = list() - for(var/type in subtypesof(/datum/material)) - 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)) + + properties = list() + for(var/datum/material_property/property_type as anything in valid_subtypesof(/datum/material_property)) + properties[property_type::id] = new property_type() + + requirements = list() + for(var/datum/material_requirement/requirement_type as anything in valid_subtypesof(/datum/material_requirement)) + requirements[requirement_type] = new requirement_type() + + for(var/datum/material/mat_type as anything in valid_subtypesof(/datum/material)) + if(initial(mat_type.init_flags) & MATERIAL_INIT_MAPLOAD) + initialize_material(mat_type) dimensional_themes = init_subtypes_w_path_keys(/datum/dimension_theme) /** Creates and caches a material datum. - * - * Arguments: - * - [arguments][/list]: The arguments to use to create the material datum - * - The first element is the type of material to initialize. + * The first argument is the type of material to initialize, the rest are passed to the material's init */ -/datum/controller/subsystem/materials/proc/InitializeMaterial(list/arguments) - var/datum/material/mat_type = arguments[1] +/datum/controller/subsystem/materials/proc/initialize_material(datum/material/mat_type, ...) + var/mat_id = mat_type if(initial(mat_type.init_flags) & MATERIAL_INIT_BESPOKE) - arguments[1] = GetIdFromArguments(arguments) + mat_id = get_id_from_args(arglist(list(mat_type) + args.Copy(2))) var/datum/material/mat_ref = new mat_type - if(!mat_ref.Initialize(arglist(arguments))) + if(!mat_ref.Initialize(arglist(list(mat_id) + args.Copy(2)))) return null - var/mat_id = mat_ref.id + mat_id = mat_ref.id materials[mat_id] = mat_ref + flat_materials += 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. - * +/** + * 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 + * - The first argument 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) +/datum/controller/subsystem/materials/proc/get_material(datum/material/material_type, ...) + RETURN_TYPE(/datum/material) + if(!materials) - InitializeMaterials() + initialize_materials() - 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(istype(material_type)) + return material_type // We are assuming here that the only thing allowed to create material datums is [/datum/controller/subsystem/materials/proc/initialize_material] - if(istext(key)) // Handle text id - . = materials[key] + if(istext(material_type)) // Handle text id + . = materials[material_type] if(!.) - WARNING("Attempted to fetch material ref with invalid text id '[key]'") + WARNING("Attempted to fetch material ref with invalid text id '[material_type]'") return - if(!ispath(key, /datum/material)) - CRASH("Attempted to fetch material ref with invalid key [key]") + if(!ispath(material_type, /datum/material)) + CRASH("Attempted to fetch material ref with invalid key [material_type]") - if(!(initial(key.init_flags) & MATERIAL_INIT_BESPOKE)) - . = materials[key] + if(!(initial(material_type.init_flags) & MATERIAL_INIT_BESPOKE)) + . = materials[material_type] if(!.) - WARNING("Attempted to fetch reference to an abstract material with key [key]") + WARNING("Attempted to fetch reference to an abstract material with key [material_type]") return - key = GetIdFromArguments(arguments) - return materials[key] || InitializeMaterial(arguments) + var/material_id = get_id_from_args(arglist(list(material_type) + args.Copy(2))) + return materials[material_id] || initialize_material(arglist(list(material_type) + args.Copy(2))) -/** I'm not going to lie, this was swiped from [SSdcs][/datum/controller/subsystem/processing/dcs]. +/// Fetches all materials that match a flag, or that don't have a flag if the passed flag is negative +/datum/controller/subsystem/materials/proc/get_materials_by_flag(mat_flag) + if (isnull(mat_flag) || mat_flag == MATERIAL_CLASS_ANY) // Wildcard for "any" material + return flat_materials + + // Lazy cache for access speed on repeated calls + var/static/list/materials_by_flag + if (!materials_by_flag) + materials_by_flag = list() + + var/list/result = materials_by_flag["[mat_flag]"] + if (result) + return result + + result = list() + for (var/datum/material/material as anything in flat_materials) + if (mat_flag > 0) + if (material.mat_flags & mat_flag) + result += material + else if (!(material.mat_flags & (-mat_flag))) + result += material + + materials_by_flag["[mat_flag]"] = result + return result + +/** + * 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 @@ -124,15 +148,14 @@ SUBSYSTEM_DEF(materials) * 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]") +/datum/controller/subsystem/materials/proc/get_id_from_args(datum/material/mat_type, ...) + var/list/fullid = list("[initial(mat_type.id) || mat_type]") var/list/named_arguments = list() - for(var/i in 2 to length(arguments)) - var/key = arguments[i] + for(var/i in 2 to length(args)) + var/key = args[i] var/value if(istext(key)) - value = arguments[key] + value = args[key] if(!(istext(key) || isnum(key))) key = REF(key) key = "[key]" // Key is stringified so numbers don't break things @@ -150,12 +173,12 @@ SUBSYSTEM_DEF(materials) /// 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 = 1) +/datum/controller/subsystem/materials/proc/get_material_set_cache(list/materials_declaration, multiplier = 1) 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() + initialize_materials() var/list/combo_params = list() for(var/datum/material/mat as anything in materials_declaration) combo_params += "[istype(mat) ? mat.id : mat]=[OPTIMAL_COST(materials_declaration[mat] * multiplier)]" @@ -165,6 +188,18 @@ SUBSYSTEM_DEF(materials) if(!combo) combo = list() for(var/mat in materials_declaration) - combo[GET_MATERIAL_REF(mat)] = OPTIMAL_COST(materials_declaration[mat] * multiplier) + combo[SSmaterials.get_material(mat)] = OPTIMAL_COST(materials_declaration[mat] * multiplier) material_combos[combo_index] = combo return combo + +/// Returns all materials that fit a requirement datum +/datum/controller/subsystem/materials/proc/get_materials_by_req(datum/material_requirement/requirement) + if (ispath(requirement)) + if (!requirements[requirement]) + CRASH("Invalid material requirement passed into get_materials_by_req: [requirement]") + requirement = requirements[requirement] + + . = list() + for (var/datum/material/material as anything in get_materials_by_flag(requirement.required_flags)) // If none are set, this returns all materials + if (requirement.valid_material(material)) + . += material diff --git a/code/controllers/subsystem/stock_market.dm b/code/controllers/subsystem/stock_market.dm index 8ecd6cc8085..a77745d295c 100644 --- a/code/controllers/subsystem/stock_market.dm +++ b/code/controllers/subsystem/stock_market.dm @@ -34,7 +34,7 @@ SUBSYSTEM_DEF(stock_market) ///Adjust the price of a material(either through buying or selling) ensuring it stays within limits /datum/controller/subsystem/stock_market/proc/adjust_material_price(datum/material/mat, delta) - mat = GET_MATERIAL_REF(mat) + mat = SSmaterials.get_material(mat) //adjust the price var/new_price = materials_prices[mat.type] + delta @@ -51,7 +51,7 @@ SUBSYSTEM_DEF(stock_market) ///Adjust the amount of material(either through buying or selling) ensuring it stays within limits /datum/controller/subsystem/stock_market/proc/adjust_material_quantity(datum/material/mat, delta) - mat = GET_MATERIAL_REF(mat) + mat = SSmaterials.get_material(mat) //adjust the quantity var/new_quantity = materials_quantity[mat.type] + delta diff --git a/code/datums/armor/_armor.dm b/code/datums/armor/_armor.dm index f990a57842e..5f1c8f11cc0 100644 --- a/code/datums/armor/_armor.dm +++ b/code/datums/armor/_armor.dm @@ -72,7 +72,7 @@ GLOBAL_LIST_INIT(armor_by_type, generate_armor_type_cache()) /datum/armor/proc/generate_new_with_modifiers(list/modifiers) var/datum/armor/new_armor = new - var/all_keys = ARMOR_LIST_ALL() + var/all_keys = ARMOR_LIST_ALL if(ARMOR_ALL in modifiers) var/modifier_all = modifiers[ARMOR_ALL] if(!modifier_all) @@ -95,7 +95,7 @@ GLOBAL_LIST_INIT(armor_by_type, generate_armor_type_cache()) /datum/armor/proc/generate_new_with_multipliers(list/multipliers) var/datum/armor/new_armor = new - var/all_keys = ARMOR_LIST_ALL() + var/all_keys = ARMOR_LIST_ALL if(ARMOR_ALL in multipliers) var/multiplier_all = multipliers[ARMOR_ALL] if(!multiplier_all) @@ -118,7 +118,7 @@ GLOBAL_LIST_INIT(armor_by_type, generate_armor_type_cache()) /datum/armor/proc/generate_new_with_specific(list/values) var/datum/armor/new_armor = new - var/all_keys = ARMOR_LIST_ALL() + var/all_keys = ARMOR_LIST_ALL if(ARMOR_ALL in values) var/value_all = values[ARMOR_ALL] if(!value_all) @@ -140,7 +140,7 @@ GLOBAL_LIST_INIT(armor_by_type, generate_armor_type_cache()) /// Gets the rating of armor for the specified rating /datum/armor/proc/get_rating(rating) // its not that I don't trust coders, it's just that I don't trust coders - if(!(rating in ARMOR_LIST_ALL())) + if(!(rating in ARMOR_LIST_ALL)) CRASH("Attempted to get a rating '[rating]' that doesn't exist") return vars[rating] @@ -150,7 +150,7 @@ GLOBAL_LIST_INIT(armor_by_type, generate_armor_type_cache()) /// Converts all the ratings of the armor into a list, optionally inverted /datum/armor/proc/get_rating_list(inverse = FALSE) var/ratings = list() - for(var/rating in ARMOR_LIST_ALL()) + for(var/rating in ARMOR_LIST_ALL) var/value = vars[rating] if(inverse) value *= -1 @@ -183,7 +183,7 @@ GLOBAL_LIST_INIT(armor_by_type, generate_armor_type_cache()) /// Checks if any of the armor values are non-zero, so this technically also counts negative armor! /datum/armor/proc/has_any_armor() - for(var/rating in ARMOR_LIST_ALL()) + for(var/rating in ARMOR_LIST_ALL) if(vars[rating]) return TRUE return FALSE diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index 71621f623d2..b1f7eebab1f 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -266,7 +266,7 @@ for (var/obj/item/food/meat/meat in results) meat.name = "[target.owner.real_name]'s [meat.name]" - meat.set_custom_materials(list(GET_MATERIAL_REF(/datum/material/meat/mob_meat, target.owner) = 4 * SHEET_MATERIAL_AMOUNT)) + meat.set_custom_materials(list(SSmaterials.get_material(/datum/material/meat/mob_meat, target.owner) = 4 * SHEET_MATERIAL_AMOUNT)) meat.subjectname = target.owner.real_name meat.subjectjob = target.owner.job @@ -450,7 +450,7 @@ 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, target) = counterlist_sum(meat_mats))) + carrion.set_custom_materials((carrion.custom_materials - meat_mats) + list(SSmaterials.get_material(/datum/material/meat/mob_meat, target) = counterlist_sum(meat_mats))) // Transfer delicious reagents to meat if (target.reagents) diff --git a/code/datums/elements/blood_reagent.dm b/code/datums/elements/blood_reagent.dm index f71c1a7aca8..0c6cc76a5ad 100644 --- a/code/datums/elements/blood_reagent.dm +++ b/code/datums/elements/blood_reagent.dm @@ -33,10 +33,10 @@ if (!blood_source) - target.material = GET_MATERIAL_REF(/datum/material/meat/blood_meat, target) + target.material = SSmaterials.get_material(/datum/material/meat/blood_meat, target) return - target.material = GET_MATERIAL_REF(/datum/material/meat/mob_meat, blood_source) + target.material = SSmaterials.get_material(/datum/material/meat/mob_meat, blood_source) var/list/blood_data = blood_source.get_blood_data() if(blood_data["viruses"]) diff --git a/code/datums/material/material_container.dm b/code/datums/material/material_container.dm index 8a074d5c36e..256c1ea4717 100644 --- a/code/datums/material/material_container.dm +++ b/code/datums/material/material_container.dm @@ -56,7 +56,7 @@ //Make the assoc list material reference -> amount for(var/mat in init_mats) - var/mat_ref = GET_MATERIAL_REF(mat) + var/mat_ref = SSmaterials.get_material(mat) if(isnull(mat_ref)) continue var/mat_amt = init_mats[mat] @@ -188,7 +188,7 @@ var/total_amount_saved = total_amount() if(mat) if(!istype(mat)) - mat = GET_MATERIAL_REF(mat) + mat = SSmaterials.get_material(mat) materials[mat] += amt else var/num_materials = length(materials) @@ -559,7 +559,7 @@ */ /datum/material_container/proc/get_material_amount(datum/material/mat) if(!istype(mat)) - mat = GET_MATERIAL_REF(mat) + mat = SSmaterials.get_material(mat) return materials[mat] /** @@ -639,7 +639,7 @@ //get ref if necessary if(!istype(mat)) - mat = GET_MATERIAL_REF(mat) + mat = SSmaterials.get_material(mat) //check if sufficient is available if(materials[mat] < amt) diff --git a/code/datums/material/remote_materials.dm b/code/datums/material/remote_materials.dm index 9f15f3d0cb5..5a58e1c9a11 100644 --- a/code/datums/material/remote_materials.dm +++ b/code/datums/material/remote_materials.dm @@ -95,7 +95,7 @@ handles linking back and forth. mat_container = new ( \ parent, \ - SSmaterials.materials_by_category[MAT_CATEGORY_SILO], \ + SSmaterials.get_materials_by_flag(MATERIAL_SILO_STORED), \ local_size, \ mat_container_flags, \ container_signals = mat_container_signals, \ diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm index 3a1c376c838..f830fa5b7b5 100644 --- a/code/datums/materials/_material.dm +++ b/code/datums/materials/_material.dm @@ -6,18 +6,25 @@ Simple datum which is instanced once per type and is used for every object of sa /datum/material + abstract_type = /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 + var/id = null - /** - * Base color of the material, for items that don't have greyscale configs nor are made of multiple materials. Item isn't changed in color if this is null. - * This can be a RGB or color matrix, but it cannot be RGBA as alpha is automatically filled in. - */ - var/color + /// Bitflags that influence how SSmaterials handles this material. + var/init_flags = MATERIAL_INIT_MAPLOAD + /// Material behaviors, controls how the material is categorized and in what recipes it can be used + var/mat_flags = NONE + /// List of material property IDs to their values, 0 - 10 + var/mat_properties = null + + // Color values + /// Base color of the material, for items that don't have greyscale configs nor are made of multiple materials. Item isn't changed in color if this is null. + /// This can be a RGB or color matrix, but it cannot be RGBA as alpha is automatically filled in. + var/color = null /** * If the color is a color matrix and either the item uses greyscale configs or is made of multiple colored materials. This will be used instead because * neither greyscale configs nor BlendRGB() support color matrices. @@ -25,78 +32,52 @@ Simple datum which is instanced once per type and is used for every object of sa * * Basically, set this if the color is a color matrix (list) */ - var/greyscale_color + var/greyscale_color = null /// Base alpha of the material var/alpha = 255 - ///Starlight color of the material - ///This is the color of light it'll emit if its turf is transparent and over space. Defaults to COLOR_STARLIGHT if not set - var/starlight_color - ///Bitflags that influence how SSmaterials handles this material. - var/init_flags = MATERIAL_INIT_MAPLOAD - ///Materials "Traits". its a map of key = category | Value = Bool. Used to define what it can be used for - var/list/categories = list() - ///The type of sheet this material creates. This should be replaced as soon as possible by greyscale sheets - var/sheet_type - /// What type of ore is this material associated with? Used for mining, and not every material has one. - var/obj/item/ore_type - ///This is a modifier for force, and resembles the strength of the material - var/strength_modifier = 1 - ///This is a modifier for integrity, and resembles the strength of the material - var/integrity_modifier = 1 + /// Starlight color of the material + /// This is the color of light it'll emit if its turf is transparent and over space. Defaults to GLOB.starlight_color if not set + var/starlight_color = null - ///This is the amount of value per 1 unit of the material + // Trading values + /// This is the amount of value per 1 unit of the material var/value_per_unit = 0 - ///This is the minimum value of the material, used in the stock market for any mat that isn't set to null + /// This is the minimum value of the material, used in the stock market for any mat that isn't set to null var/minimum_value_override = null - ///Is this material traded on the stock market? + /// Is this material traded on the stock market? var/tradable = FALSE - ///If this material is tradable, what is the base quantity of the material on the stock market? + /// If this material is tradable, what is the base quantity of the material on the stock market? var/tradable_base_quantity = 0 - ///Armor modifiers, multiplies an items normal armor vars by these amounts. - var/armor_modifiers = list(MELEE = 1, BULLET = 1, LASER = 1, ENERGY = 1, BOMB = 1, BIO = 1, FIRE = 1, ACID = 1) - ///How beautiful is this material per unit. - var/beauty_modifier = 0 - ///Can be used to override the sound items make, lets add some SLOSHing. - var/item_sound_override - ///Can be used to override the stepsound a turf makes. MORE SLOOOSH - var/turf_sound_override - ///what texture icon state to overlay - var/texture_layer_icon_state - ///a cached icon for the texture filter - var/cached_texture_filter_icon - ///What type of shard the material will shatter to - var/obj/item/shard_type - ///How resistant the material is to rusting when applied to a turf + // Associated item types + /// The type of sheet this material creates. + var/sheet_type = null + /// What type of ore is this material associated with? Used for mining, and not every material has one. + var/obj/item/ore_type = null + /// What type of shard the material will shatter to + var/obj/item/shard_type = null + /// What type of debris the tile will leave behind when shattered. + var/obj/effect/decal/debris_type = null + /// Reagent type(s) of this material. Can be a reagent typepath or a list. + var/list/material_reagent = null + + // Misc stats + /// How resistant the material is to rusting when applied to a turf var/mat_rust_resistance = RUST_RESISTANCE_ORGANIC - ///What type of debris the tile will leave behind when shattered. - var/obj/effect/decal/debris_type /// How likely this mineral is to be found in a boulder during mining. var/mineral_rarity = MATERIAL_RARITY_COMMON /// How many points per units of ore does this grant? var/points_per_unit = 1 - /// The slowdown that is added to items. - var/added_slowdown = 0 - /// Fish made of or infused with this material have their weight multiplied by this value. - var/fish_weight_modifier = 1 - - /// Additive bonus/malus to the fishing difficulty modifier of any rod made of this item. Negative is good, positive bad - var/fishing_difficulty_modifier = 0 - /// Additive bonus/malus to the cast range of the fishing rod - var/fishing_cast_range = 0 - /// The multiplier of how much experience is gained when using a fishing rod made of this material - var/fishing_experience_multiplier = 1 - /// The multiplier to the completion gain of the fishing rod made of this material - var/fishing_completion_speed = 1 - /// The multiplier of the bait/bobber speed of the fishing challenge for fishing rods made of this material - var/fishing_bait_speed_mult = 1 - /// The multiplier of the deceleration/friction for fishing rods made of this material - var/fishing_deceleration_mult = 1 - /// The multiplier of the bounciness of the bait/bobber upon hitting the edges of the minigame area - var/fishing_bounciness_mult = 1 - /// The multiplier of negative velocity that pulls the bait/bobber of a fishing rod down when not holding the click - var/fishing_gravity_mult = 1 + // Sound/icon stats, not inherited + /// Can be used to override the sound items make, lets add some SLOSHing. + var/item_sound_override = null + /// Can be used to override the stepsound a turf makes. MORE SLOOOSH + var/turf_sound_override = null + /// What texture icon state to overlay + var/texture_layer_icon_state = null + /// A cached icon for the texture filter + var/icon/cached_texture_filter_icon = null /** Handles initializing the material. * @@ -112,17 +93,21 @@ Simple datum which is instanced once per type and is used for every object of sa if(texture_layer_icon_state) cached_texture_filter_icon = icon('icons/turf/composite.dmi', texture_layer_icon_state) + for (var/prop_id in mat_properties) + var/datum/material_property/property = SSmaterials.properties[prop_id] + property.attach_to(src) + return TRUE ///This proc is called when the material is added to an object. /datum/material/proc/on_applied(atom/source, mat_amount, multiplier) - return + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_MATERIAL_APPLIED, source, mat_amount, multiplier) ///This proc is called when the material becomes the one the object is composed of the most /datum/material/proc/on_main_applied(atom/source, mat_amount, multiplier) SHOULD_CALL_PARENT(TRUE) - if(beauty_modifier >= 0.15 && HAS_TRAIT(source, TRAIT_FISHING_BAIT)) - source.AddElement(/datum/element/shiny_bait) + SEND_SIGNAL(src, COMSIG_MATERIAL_MAIN_APPLIED, source, mat_amount, multiplier) /datum/material/proc/setup_glow(turf/on) if(GET_TURF_PLANE_OFFSET(on) != GET_LOWEST_STACK_OFFSET(on.z)) // We ain't the bottom brother @@ -142,15 +127,15 @@ Simple datum which is instanced once per type and is used for every object of sa /datum/material/proc/lit_turf_deleted(turf/source) source.set_light(0, 0, null) -///This proc is called when the material is removed from an object. +/// This proc is called when the material is removed from an object. /datum/material/proc/on_removed(atom/source, amount, material_flags) - return + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_MATERIAL_REMOVED, source, amount, material_flags) -///This proc is called when the material is no longer the one the object is composed by the most +/// This proc is called when the material is no longer the one the object is composed by the most /datum/material/proc/on_main_removed(atom/source, mat_amount, multiplier) SHOULD_CALL_PARENT(TRUE) - if(beauty_modifier >= 0.15 && HAS_TRAIT(source, TRAIT_FISHING_BAIT)) - source.RemoveElement(/datum/element/shiny_bait) + SEND_SIGNAL(src, COMSIG_MATERIAL_MAIN_REMOVED, source, mat_amount, multiplier) ////Called in `/datum/component/edible/proc/on_material_effects` /datum/material/proc/on_edible_applied(atom/source, datum/component/edible/edible) @@ -166,8 +151,23 @@ Simple datum which is instanced once per type and is used for every object of sa * * M - person consuming the mat * * S - (optional) item the mat is contained in (NOT the item with the mat itself) */ -/datum/material/proc/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S) - return FALSE +/datum/material/proc/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + SHOULD_CALL_PARENT(TRUE) + + if (!material_reagent) + return FALSE + + var/effect_multiplier = source_item.custom_materials[type] / SHEET_MATERIAL_AMOUNT + if (!islist(material_reagent)) + victim.reagents?.add_reagent(material_reagent, rand(6, 8) * effect_multiplier) + source_item?.reagents?.add_reagent(material_reagent, source_item.reagents.total_volume * MATERIAL_REAGENT_CONSUMPTION_MULT * effect_multiplier) + return TRUE + + for (var/datum/reagent/reagent_type as anything in material_reagent) + var/amount_mult = material_reagent[reagent_type] / length(material_reagent) + victim.reagents?.add_reagent(material_reagent, rand(6, 8) * effect_multiplier * amount_mult) + source_item?.reagents?.add_reagent(material_reagent, source_item.reagents.total_volume * MATERIAL_REAGENT_CONSUMPTION_MULT * effect_multiplier * amount_mult) + return TRUE /** Returns the composition of this material. * @@ -183,7 +183,48 @@ Simple datum which is instanced once per type and is used for every object of sa ///Returns the list of armor modifiers, with each element having its assoc value multiplied by the multiplier arg /datum/material/proc/get_armor_modifiers(multiplier) SHOULD_NOT_OVERRIDE(TRUE) - var/list/return_list = list() - for(var/armor in armor_modifiers) - return_list[armor] = return_list[armor] * multiplier - return return_list + var/density = get_property(MATERIAL_DENSITY) + var/hardness = get_property(MATERIAL_HARDNESS) + var/flexibility = get_property(MATERIAL_FLEXIBILITY) + var/reflectivity = get_property(MATERIAL_REFLECTIVITY) + var/electric = get_property(MATERIAL_ELECTRICAL) + var/thermal = get_property(MATERIAL_THERMAL) + var/chemical = get_property(MATERIAL_CHEMICAL) + var/flammability = get_property(MATERIAL_FLAMMABILITY) // Optional, might be not present + // Welcome to hell + var/list/armor_modifiers = list( + // Based on density, with a bonus/malus for matching flexibility + // We cap divergence at 4 (reduced by hardness above 6 for REALLY dense stuff) to make it not extremely punishing on light fabrics or heavy materials + // Iron at a baseline of density of 6 and flexibility of 4 has divergence of 4, so (1 + 0.2) / (0.8 + 0.4) = 1 + MELEE = (1 + (density - 4) * 0.1) / (0.8 + min(4 - max(0, hardness - 6), abs(flexibility - density)) * 0.1), + // Hardness and density, with flexibility actually being detrimental + BULLET = (1 + (density - 4) * 0.025 + (hardness - 4) * 0.075) / (1 - max(0, flexibility - 2) * 0.1), + // 0.6 ~ 1 for reflectivity below 4, 1 ~ 1.4 for reflectivity above 6, reduced for transparent materials + LASER = 1 + MATERIAL_PROPERTY_DIVERGENCE(reflectivity, 4, 6) * 0.1 - (255 - alpha) / 50 * 0.2, + // Essentially laser but with contribution split between reflectivity and inverse electric conductivity + // Here reflectivity applies if its below 4 or above 8, and conductivity if its below 4 or above 6 + ENERGY = 1 + MATERIAL_PROPERTY_DIVERGENCE(reflectivity, 4, 8) * 0.05 - MATERIAL_PROPERTY_DIVERGENCE(electric, 4, 6) * 0.1, + // Linearly scales from 0.2 to 1.8 with density + BOMB = 1 + (density - 4) * 0.2, + // Each level of flammability reduces FIRE armor by 20%, with thermal conductivity reducing it by further 20% for each level above 6 and increasing for each level below 2 + FIRE = max(0, 1 - max(0, (thermal - 6) * 0.2) + max(0, (2 - thermal) * 0.2) - flammability * 0.2), + // Linearly scales from 0.2 to 1.8 with chemical resistance + ACID = 1 + (chemical - 4) * 0.2, + ) + + for (var/armor_key in armor_modifiers) + // Safety check to ensure that we don't have inverted armor values + if (armor_modifiers[armor_key] < 0) + armor_modifiers[armor_key] = 0 + armor_modifiers[armor_key] = GET_MATERIAL_MODIFIER(armor_modifiers[armor_key], multiplier) + + return armor_modifiers + +/datum/material/proc/get_property(prop_id) + if (!isnull(mat_properties?[prop_id])) + return mat_properties[prop_id] + + var/datum/material_property/derived/derived_prop = SSmaterials.properties[prop_id] + if (!istype(derived_prop)) + return null // Property was not specified on the material and wasn't a derived one + return derived_prop.get_value(src) diff --git a/code/datums/materials/alloys.dm b/code/datums/materials/alloys.dm index b1025f4130e..6d90eb4ff1a 100644 --- a/code/datums/materials/alloys.dm +++ b/code/datums/materials/alloys.dm @@ -1,9 +1,8 @@ -/** Materials made from other materials. - */ +/// Materials made from other materials. /datum/material/alloy name = "alloy" desc = "A material composed of two or more other materials." - init_flags = NONE + abstract_type = /datum/material/alloy /// The materials this alloy is made from weighted by their ratios. var/list/composition = null @@ -15,14 +14,13 @@ var/list/cached_comp = composition for(var/comp_mat in cached_comp) - var/datum/material/component_material = GET_MATERIAL_REF(comp_mat) + var/datum/material/component_material = SSmaterials.get_material(comp_mat) var/list/component_composition = component_material.return_composition(cached_comp[comp_mat], flags) for(var/comp_comp_mat in component_composition) .[comp_comp_mat] += component_composition[comp_comp_mat] * amount - -/** Plasteel - * +/** + * Plasteel * An alloy of iron and plasma. * Applies a significant slowdown effect to any and all items that contain it. */ @@ -30,25 +28,21 @@ name = "plasteel" desc = "The heavy duty result of infusing iron with plasma." color = "#706374" - init_flags = MATERIAL_INIT_MAPLOAD - value_per_unit = 0.135 - strength_modifier = 1.25 - integrity_modifier = 1.5 // Heavy duty. - armor_modifiers = list(MELEE = 1.4, BULLET = 1.4, LASER = 1.1, ENERGY = 1.1, BOMB = 1.5, BIO = 1, FIRE = 1.1, ACID = 1) - sheet_type = /obj/item/stack/sheet/plasteel - categories = list( - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 6, + MATERIAL_HARDNESS = 8, + MATERIAL_FLEXIBILITY = 1, + MATERIAL_REFLECTIVITY = 5, + MATERIAL_ELECTRICAL = 8, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 6, ) - composition = list(/datum/material/iron=1, /datum/material/plasma=1) + value_per_unit = 0.135 + sheet_type = /obj/item/stack/sheet/plasteel + material_reagent = list(/datum/reagent/iron = 1, /datum/reagent/toxin/plasma = 1) + composition = list(/datum/material/iron = 1, /datum/material/plasma = 1) mat_rust_resistance = RUST_RESISTANCE_REINFORCED - added_slowdown = 0.05 - fish_weight_modifier = 1.75 - fishing_difficulty_modifier = 5 - fishing_experience_multiplier = 1.1 - fishing_gravity_mult = 1.6 /datum/material/alloy/plasteel/on_applied(atom/target, mat_amount, multiplier) . = ..() @@ -60,32 +54,29 @@ if(istype(target, /obj/item/fishing_rod)) REMOVE_TRAIT(target, TRAIT_ROD_LAVA_USABLE, REF(src)) -/** Plastitanium - * +/** + * Plastitanium * An alloy of titanium and plasma. */ /datum/material/alloy/plastitanium name = "plastitanium" desc = "The extremely heat resistant result of infusing titanium with plasma." color = "#3a313a" - init_flags = MATERIAL_INIT_MAPLOAD - value_per_unit = 0.225 - strength_modifier = 0.9 // It's a lightweight alloy. - integrity_modifier = 1.3 - armor_modifiers = list(MELEE = 1.1, BULLET = 1.1, LASER = 1.4, ENERGY = 1.4, BOMB = 1.1, BIO = 1.2, FIRE = 1.5, ACID = 1) - sheet_type = /obj/item/stack/sheet/mineral/plastitanium - categories = list( - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 4, + MATERIAL_HARDNESS = 8, + MATERIAL_FLEXIBILITY = 1, + MATERIAL_REFLECTIVITY = 8, + MATERIAL_ELECTRICAL = 6, + MATERIAL_THERMAL = 1, + MATERIAL_CHEMICAL = 8, ) - composition = list(/datum/material/titanium=1, /datum/material/plasma=1) + value_per_unit = 0.225 + sheet_type = /obj/item/stack/sheet/mineral/plastitanium + material_reagent = /datum/reagent/toxin/plasma + composition = list(/datum/material/titanium = 1, /datum/material/plasma = 1) mat_rust_resistance = RUST_RESISTANCE_TITANIUM - fish_weight_modifier = 1.1 - fishing_difficulty_modifier = -7 - fishing_cast_range = 1 - fishing_experience_multiplier = 0.95 /datum/material/alloy/plastitanium/on_applied(atom/target, mat_amount, multiplier) . = ..() @@ -97,8 +88,8 @@ if(istype(target, /obj/item/fishing_rod)) REMOVE_TRAIT(target, TRAIT_ROD_LAVA_USABLE, REF(src)) -/** Plasmaglass - * +/** + * Plasmaglass * An alloy of silicate and plasma. */ /datum/material/alloy/plasmaglass @@ -107,27 +98,25 @@ color = "#ff80f4" alpha = 150 starlight_color = COLOR_STRONG_MAGENTA - init_flags = MATERIAL_INIT_MAPLOAD - integrity_modifier = 0.5 - armor_modifiers = list(MELEE = 0.8, BULLET = 0.8, LASER = 1.2, ENERGY = 1.2, BOMB = 0.3, BIO = 1.2, FIRE = 2, ACID = 2) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_CRYSTAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 5, + MATERIAL_HARDNESS = 6, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 8, + MATERIAL_ELECTRICAL = 0, + MATERIAL_THERMAL = 2, + MATERIAL_CHEMICAL = 8, + ) sheet_type = /obj/item/stack/sheet/plasmaglass shard_type = /obj/item/shard/plasma debris_type = /obj/effect/decal/cleanable/glass/plasma + material_reagent = list(/datum/reagent/silicon = 1, /datum/reagent/toxin/plasma = 0.5) value_per_unit = 0.075 - categories = list( - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) - composition = list(/datum/material/glass=1, /datum/material/plasma=0.5) - fish_weight_modifier = 1.2 - fishing_difficulty_modifier = 5 - fishing_experience_multiplier = 1.3 - fishing_gravity_mult = 0.9 + composition = list(/datum/material/glass = 1, /datum/material/plasma = 0.5) -/** Titaniumglass - * +/** + * Titanium Glass * An alloy of glass and titanium. */ /datum/material/alloy/titaniumglass @@ -136,26 +125,25 @@ color = "#cfbee0" alpha = 150 starlight_color = COLOR_COMMAND_BLUE - init_flags = MATERIAL_INIT_MAPLOAD - armor_modifiers = list(MELEE = 1.2, BULLET = 1.2, LASER = 0.8, ENERGY = 0.8, BOMB = 0.5, BIO = 1.2, FIRE = 0.8, ACID = 2) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_CRYSTAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 5, + MATERIAL_HARDNESS = 7, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 8, + MATERIAL_ELECTRICAL = 0, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 8, + ) sheet_type = /obj/item/stack/sheet/titaniumglass shard_type = /obj/item/shard/titanium debris_type = /obj/effect/decal/cleanable/glass/titanium + material_reagent = /datum/reagent/silicon value_per_unit = 0.04 - categories = list( - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) - composition = list(/datum/material/glass=1, /datum/material/titanium=0.5) - fish_weight_modifier = 1.25 - fishing_difficulty_modifier = -5 - fishing_experience_multiplier = 1.25 - fishing_gravity_mult = 0.95 + composition = list(/datum/material/glass = 1, /datum/material/titanium = 0.5) -/** Plastitanium Glass - * +/** + * Plastitanium Glass * An alloy of plastitanium and glass. */ /datum/material/alloy/plastitaniumglass @@ -164,26 +152,25 @@ color = "#5d3369" starlight_color = COLOR_CENTCOM_BLUE alpha = 150 - init_flags = MATERIAL_INIT_MAPLOAD - integrity_modifier = 1.1 - armor_modifiers = list(MELEE = 1.2, BULLET = 1.2, LASER = 1.2, ENERGY = 1.2, BOMB = 0.5, BIO = 1.2, FIRE = 2, ACID = 2) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_CRYSTAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 4, + MATERIAL_HARDNESS = 8, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 8, + MATERIAL_ELECTRICAL = 0, + MATERIAL_THERMAL = 2, + MATERIAL_CHEMICAL = 8, + ) sheet_type = /obj/item/stack/sheet/plastitaniumglass shard_type = /obj/item/shard/plastitanium debris_type = /obj/effect/decal/cleanable/glass/plastitanium + material_reagent = list(/datum/reagent/silicon = 1, /datum/reagent/toxin/plasma = 0.5) value_per_unit = 0.125 - categories = list( - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) - composition = list(/datum/material/glass=1, /datum/material/alloy/plastitanium=0.5) - fish_weight_modifier = 1.2 - fishing_experience_multiplier = 1.5 - fishing_gravity_mult = 0.9 + composition = list(/datum/material/glass = 1, /datum/material/alloy/plastitanium = 0.5) -/** Alien Alloy - * +/** + * Alien Alloy * Densified plasteel. * Applies a significant slowdown effect to anything that contains it. * Anything constructed from it can slowly regenerate. @@ -192,29 +179,20 @@ name = "alien alloy" desc = "An extremely dense alloy similar to plasteel in composition. It requires exotic metallurgical processes to create." color = "#6041aa" - init_flags = MATERIAL_INIT_MAPLOAD - strength_modifier = 1.5 // It's twice the density of plasteel and just as durable. Getting hit with it is going to HURT. - integrity_modifier = 1.5 - armor_modifiers = list(MELEE = 1.4, BULLET = 1.4, LASER = 1.2, ENERGY = 1.2, BOMB = 1.5, BIO = 1.2, FIRE = 1.2, ACID = 1.2) - sheet_type = /obj/item/stack/sheet/mineral/abductor - value_per_unit = 0.4 - categories = list( - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 8, + MATERIAL_HARDNESS = 8, + MATERIAL_FLEXIBILITY = 3, + MATERIAL_REFLECTIVITY = 7, + MATERIAL_ELECTRICAL = 8, + MATERIAL_THERMAL = 1, + MATERIAL_CHEMICAL = 10, ) - composition = list(/datum/material/iron=2, /datum/material/plasma=2) - added_slowdown = 0.1 - fish_weight_modifier = 2.4 - fishing_difficulty_modifier = -20 - fishing_cast_range = 2 - fishing_experience_multiplier = 0.5 - fishing_completion_speed = 2 - fishing_bait_speed_mult = 1.25 - fishing_deceleration_mult = 1.5 - fishing_bounciness_mult = 0.5 - fishing_gravity_mult = 2 + sheet_type = /obj/item/stack/sheet/mineral/abductor + material_reagent = list(/datum/reagent/iron = 1, /datum/reagent/toxin/plasma = 1) + value_per_unit = 0.4 + composition = list(/datum/material/iron = 2, /datum/material/plasma = 2) /datum/material/alloy/alien/on_applied(atom/target, mat_amount, multiplier) . = ..() diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm index 5c56a8a451d..412e94090d9 100644 --- a/code/datums/materials/basemats.dm +++ b/code/datums/materials/basemats.dm @@ -3,15 +3,19 @@ name = "iron" desc = "Common iron ore often found in sedimentary and igneous layers of the crust." color = "#B6BEC2" - categories = list( - MAT_CATEGORY_SILO = TRUE, - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_SILO_STORED | MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 6, + MATERIAL_HARDNESS = 6, + MATERIAL_FLEXIBILITY = 2, + MATERIAL_REFLECTIVITY = 3, + MATERIAL_ELECTRICAL = 6, + MATERIAL_THERMAL = 7, + MATERIAL_CHEMICAL = 3, ) sheet_type = /obj/item/stack/sheet/iron ore_type = /obj/item/stack/ore/iron + material_reagent = /datum/reagent/iron value_per_unit = 5 / SHEET_MATERIAL_AMOUNT mat_rust_resistance = RUST_RESISTANCE_BASIC mineral_rarity = MATERIAL_RARITY_COMMON @@ -19,10 +23,9 @@ minimum_value_override = 0 tradable = TRUE tradable_base_quantity = MATERIAL_QUANTITY_COMMON - fish_weight_modifier = 1.3 - fishing_gravity_mult = 1.1 /datum/material/iron/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5) return TRUE @@ -33,14 +36,17 @@ desc = "Glass forged by melting sand." color = "#6292AF" alpha = 150 - categories = list( - MAT_CATEGORY_SILO = TRUE, - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_SILO_STORED | MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_CRYSTAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 4, + MATERIAL_HARDNESS = 4, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 7, + MATERIAL_ELECTRICAL = 0, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 8, ) - integrity_modifier = 0.1 + material_reagent = /datum/reagent/silicon sheet_type = /obj/item/stack/sheet/glass ore_type = /obj/item/stack/ore/glass/basalt shard_type = /obj/item/shard @@ -49,69 +55,53 @@ minimum_value_override = 0 tradable = TRUE tradable_base_quantity = MATERIAL_QUANTITY_COMMON - beauty_modifier = 0.05 - armor_modifiers = list(MELEE = 0.2, BULLET = 0.2, ENERGY = 1, BIO = 0.2, FIRE = 1, ACID = 0.2) mineral_rarity = MATERIAL_RARITY_COMMON points_per_unit = 1 / SHEET_MATERIAL_AMOUNT texture_layer_icon_state = "shine" - fish_weight_modifier = 1.2 - fishing_difficulty_modifier = 5 - fishing_experience_multiplier = 1.2 - fishing_bait_speed_mult = 0.9 - fishing_deceleration_mult = 1.2 - fishing_bounciness_mult = 0.5 - fishing_gravity_mult = 0.9 /datum/material/glass/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5, sharpness = TRUE) //cronch return TRUE /datum/material/glass/on_main_applied(atom/source, mat_amount, multiplier) . = ..() - if(isobj(source) && !isstack(source)) + if(isobj(source) && !isstack(source) && (source.material_flags & MATERIAL_AFFECT_STATISTICS)) source.AddElement(/datum/element/can_shatter, shard_type, round(mat_amount / SHEET_MATERIAL_AMOUNT * multiplier), SFX_SHATTER) /datum/material/glass/on_main_removed(atom/source, mat_amount, multiplier) . = ..() - if(isobj(source) && !isstack(source)) + if(isobj(source) && !isstack(source) && (source.material_flags & MATERIAL_AFFECT_STATISTICS)) source.RemoveElement(/datum/element/can_shatter, shard_type, round(mat_amount / SHEET_MATERIAL_AMOUNT * multiplier), SFX_SHATTER) -/* -Color matrices are like regular colors but unlike with normal colors, you can go over 255 on a channel. -Unless you know what you're doing, only use the first three numbers. They're in RGB order. -*/ - -///Has no special properties. Could be good against vampires in the future perhaps. +/// Has no special properties. Could be good against vampires in the future perhaps. /datum/material/silver name = "silver" - desc = "Silver" + desc = "A precious metal known for being hated by oversized bats and dogs." color = "#B5BCBB" - categories = list( - MAT_CATEGORY_SILO = TRUE, - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_SILO_STORED | MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 7, + MATERIAL_HARDNESS = 4, + MATERIAL_FLEXIBILITY = 3, + MATERIAL_REFLECTIVITY = 8, + MATERIAL_ELECTRICAL = 9, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 4, ) sheet_type = /obj/item/stack/sheet/mineral/silver ore_type = /obj/item/stack/ore/silver + material_reagent = /datum/reagent/silver value_per_unit = 50 / SHEET_MATERIAL_AMOUNT tradable = TRUE tradable_base_quantity = MATERIAL_QUANTITY_UNCOMMON - beauty_modifier = 0.075 mineral_rarity = MATERIAL_RARITY_SEMIPRECIOUS points_per_unit = 16 / SHEET_MATERIAL_AMOUNT texture_layer_icon_state = "shine" - fish_weight_modifier = 1.35 - fishing_difficulty_modifier = -5 - fishing_experience_multiplier = 0.85 - fishing_completion_speed = 1.1 - fishing_deceleration_mult = 1.1 - fishing_bounciness_mult = 0.9 - fishing_gravity_mult = 1.1 /datum/material/silver/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5) return TRUE @@ -119,159 +109,120 @@ Unless you know what you're doing, only use the first three numbers. They're in ///Slight force increase /datum/material/gold name = "gold" - desc = "Gold" + desc = "All that glitters is not gold." color = "#E6BB45" - strength_modifier = 1.2 - categories = list( - MAT_CATEGORY_SILO = TRUE, - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_properties = list( + MATERIAL_DENSITY = 9, + MATERIAL_HARDNESS = 3, + MATERIAL_FLEXIBILITY = 3, + MATERIAL_REFLECTIVITY = 6, + MATERIAL_ELECTRICAL = 8, + MATERIAL_THERMAL = 8, + MATERIAL_CHEMICAL = 2, ) + mat_flags = MATERIAL_SILO_STORED | MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID sheet_type = /obj/item/stack/sheet/mineral/gold ore_type = /obj/item/stack/ore/gold + material_reagent = /datum/reagent/gold value_per_unit = 125 / SHEET_MATERIAL_AMOUNT tradable = TRUE tradable_base_quantity = MATERIAL_QUANTITY_RARE - beauty_modifier = 0.15 - armor_modifiers = list(MELEE = 1.1, BULLET = 1.1, LASER = 1.15, ENERGY = 1.15, BOMB = 1, BIO = 1, FIRE = 0.7, ACID = 1.1) mineral_rarity = MATERIAL_RARITY_PRECIOUS points_per_unit = 18 / SHEET_MATERIAL_AMOUNT texture_layer_icon_state = "shine" - fish_weight_modifier = 1.5 - fishing_difficulty_modifier = -8 - fishing_cast_range = 1 - fishing_experience_multiplier = 0.75 - fishing_completion_speed = 1.2 - fishing_bait_speed_mult = 1.1 - fishing_deceleration_mult = 1.2 - fishing_bounciness_mult = 0.8 - fishing_gravity_mult = 1.2 /datum/material/gold/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) - victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5) - return TRUE + . = ..() + if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) + victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5) + return TRUE ///Has no special properties /datum/material/diamond name = "diamond" - desc = "Highly pressurized carbon" + desc = "Highly pressurized carbon." color = "#C9D8F2" - categories = list( - MAT_CATEGORY_SILO = TRUE, - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_SILO_STORED | MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_CRYSTAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 4, // Wow these are light + MATERIAL_HARDNESS = 9, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 10, + MATERIAL_ELECTRICAL = 0, // Did you know they're also an *extremely* potent insulator, only beaten by some synthetic compounds? + MATERIAL_THERMAL = 9, + MATERIAL_CHEMICAL = 4, ) sheet_type = /obj/item/stack/sheet/mineral/diamond ore_type = /obj/item/stack/ore/diamond + material_reagent = /datum/reagent/carbon alpha = 132 starlight_color = COLOR_BLUE_LIGHT value_per_unit = 500 / SHEET_MATERIAL_AMOUNT - strength_modifier = 1.1 - integrity_modifier = 1.25 tradable = TRUE tradable_base_quantity = MATERIAL_QUANTITY_EXOTIC - beauty_modifier = 0.3 - armor_modifiers = list(MELEE = 1.3, BULLET = 1.3, LASER = 0.6, ENERGY = 1, BOMB = 1.2, BIO = 1, FIRE = 1, ACID = 1) mineral_rarity = MATERIAL_RARITY_RARE points_per_unit = 50 / SHEET_MATERIAL_AMOUNT - fish_weight_modifier = 1.4 - fishing_difficulty_modifier = -12 - fishing_cast_range = -1 - fishing_experience_multiplier = 0.7 - fishing_completion_speed = 1.25 - fishing_bait_speed_mult = 1.1 - fishing_deceleration_mult = 1.25 - fishing_bounciness_mult = 0.8 - fishing_gravity_mult = 1.1 /datum/material/diamond/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(15, BRUTE, BODY_ZONE_HEAD, wound_bonus = 7) return TRUE -///Is slightly radioactive +/// Is slightly radioactive /datum/material/uranium name = "uranium" - desc = "Uranium" + desc = "Very spicy rocks." color = "#2C992C" - categories = list( - MAT_CATEGORY_SILO = TRUE, - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_SILO_STORED | MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 9, + MATERIAL_HARDNESS = 5, + MATERIAL_FLEXIBILITY = 1, + MATERIAL_REFLECTIVITY = 0, // Its a bar of glowing stone + MATERIAL_ELECTRICAL = 6, + MATERIAL_THERMAL = 6, + MATERIAL_CHEMICAL = 6, + MATERIAL_BEAUTY = 0.3, // Overriden cause its ~shiny~ + MATERIAL_RADIOACTIVITY = 4, ) sheet_type = /obj/item/stack/sheet/mineral/uranium ore_type = /obj/item/stack/ore/uranium + material_reagent = /datum/reagent/uranium value_per_unit = 100 / SHEET_MATERIAL_AMOUNT tradable = TRUE tradable_base_quantity = MATERIAL_QUANTITY_RARE - beauty_modifier = 0.3 //It shines so beautiful - armor_modifiers = list(MELEE = 1.5, BULLET = 1.4, LASER = 0.5, ENERGY = 0.5, FIRE = 1, ACID = 1) mineral_rarity = MATERIAL_RARITY_SEMIPRECIOUS points_per_unit = 30 / SHEET_MATERIAL_AMOUNT - fish_weight_modifier = 2 - fishing_completion_speed = 0.9 - fishing_bait_speed_mult = 0.8 - fishing_deceleration_mult = 1.4 - fishing_bounciness_mult = 0.6 - fishing_gravity_mult = 1.4 -/datum/material/uranium/on_applied(atom/source, mat_amount, multiplier) - . = ..() - - // Uranium structures should irradiate, but not items, because item irradiation is a lot more annoying. - // For example, consider picking up uranium as a miner. - if (isitem(source)) - return - - source.AddElement(/datum/element/radioactive, chance = URANIUM_IRRADIATION_CHANCE * multiplier) - -/datum/material/uranium/on_removed(atom/source, mat_amount, multiplier) - . = ..() - - if (isitem(source)) - return - - source.RemoveElement(/datum/element/radioactive, chance = URANIUM_IRRADIATION_CHANCE * multiplier) - -/datum/material/uranium/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) - victim.reagents.add_reagent(/datum/reagent/uranium, rand(4, 6)) - source_item?.reagents?.add_reagent(/datum/reagent/uranium, source_item.reagents.total_volume*(2/5)) - return TRUE - -///Adds firestacks on hit (Still needs support to turn into gas on destruction) +/// Adds firestacks on hit (Still needs support to turn into gas on destruction) /datum/material/plasma name = "plasma" desc = "Isn't plasma a state of matter? Oh whatever." color = "#BA3692" - categories = list( - MAT_CATEGORY_SILO = TRUE, - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_SILO_STORED | MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_CRYSTAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 6, + MATERIAL_HARDNESS = 4, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 8, + MATERIAL_ELECTRICAL = 10, + MATERIAL_THERMAL = 8, + MATERIAL_CHEMICAL = 0, + MATERIAL_FLAMMABILITY = 9, // Literally sets itself on fire from any excitement ) sheet_type = /obj/item/stack/sheet/mineral/plasma ore_type = /obj/item/stack/ore/plasma + material_reagent = /datum/reagent/toxin/plasma value_per_unit = 200 / SHEET_MATERIAL_AMOUNT - beauty_modifier = 0.15 - armor_modifiers = list(MELEE = 1.4, BULLET = 0.7, ENERGY = 1.2, BIO = 1.2, ACID = 0.5) mineral_rarity = MATERIAL_RARITY_PRECIOUS points_per_unit = 15 / SHEET_MATERIAL_AMOUNT - fish_weight_modifier = 1.3 - fishing_deceleration_mult = 1.3 - fishing_bounciness_mult = 0.6 /datum/material/plasma/on_applied(atom/source, mat_amount, multiplier) . = ..() if(ismovable(source)) source.AddElement(/datum/element/firestacker, 1 * multiplier) - source.AddComponent(/datum/component/combustible_flooder, "plasma", mat_amount * 0.05 * multiplier) //Empty temp arg, fully dependent on whatever ignited it. + source.AddComponent(/datum/component/combustible_flooder, GAS_PLASMA, mat_amount * 0.05 * multiplier) //Empty temp arg, fully dependent on whatever ignited it. if(istype(source, /obj/item/fishing_rod)) ADD_TRAIT(source, TRAIT_ROD_LAVA_USABLE, REF(src)) @@ -279,46 +230,36 @@ Unless you know what you're doing, only use the first three numbers. They're in . = ..() source.RemoveElement(/datum/element/firestacker, mat_amount = 1 * multiplier) qdel(source.GetComponent(/datum/component/combustible_flooder)) - qdel(source.GetComponent(/datum/component/explodable)) if(istype(source, /obj/item/fishing_rod)) ADD_TRAIT(source, TRAIT_ROD_LAVA_USABLE, REF(src)) -/datum/material/plasma/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) - victim.reagents.add_reagent(/datum/reagent/toxin/plasma, rand(6, 8)) - source_item?.reagents?.add_reagent(/datum/reagent/toxin/plasma, source_item.reagents.total_volume*(2/5)) - return TRUE - ///Can cause bluespace effects on use. (Teleportation) (Not yet implemented) /datum/material/bluespace name = "bluespace crystal" - desc = "Crystals with bluespace properties" + desc = "Crystals with bluespace properties." color = "#2E50B7" alpha = 200 starlight_color = COLOR_BLUE - categories = list( - MAT_CATEGORY_SILO = TRUE, - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_SILO_STORED | MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_CRYSTAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 2, + MATERIAL_HARDNESS = 8, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 10, + MATERIAL_ELECTRICAL = 10, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 4, + MATERIAL_BEAUTY = 0.5, // Absolutely mesmerizing ) - beauty_modifier = 0.5 sheet_type = /obj/item/stack/sheet/bluespace_crystal ore_type = /obj/item/stack/ore/bluespace_crystal + material_reagent = /datum/reagent/bluespace value_per_unit = 300 / SHEET_MATERIAL_AMOUNT mineral_rarity = MATERIAL_RARITY_RARE points_per_unit = 50 / SHEET_MATERIAL_AMOUNT tradable = TRUE tradable_base_quantity = MATERIAL_QUANTITY_EXOTIC texture_layer_icon_state = "shine" - fish_weight_modifier = 1.3 - fishing_difficulty_modifier = -5 - fishing_cast_range = 5 //space-bending scifi magic - fishing_experience_multiplier = 0.85 - fishing_completion_speed = 1.1 - fishing_bait_speed_mult = 1.1 - fishing_deceleration_mult = 0.9 - fishing_bounciness_mult = 1.1 /datum/material/bluespace/on_main_applied(atom/source, mat_amount, multiplier) . = ..() @@ -341,38 +282,29 @@ Unless you know what you're doing, only use the first three numbers. They're in if(istype(source, /obj/item/fishing_rod)) UnregisterSignal(source, COMSIG_ROD_BEGIN_FISHING) -/datum/material/bluespace/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) - victim.reagents.add_reagent(/datum/reagent/bluespace, rand(5, 8)) - source_item?.reagents?.add_reagent(/datum/reagent/bluespace, source_item.reagents.total_volume*(2/5)) - return TRUE - ///Honks and slips /datum/material/bananium name = "bananium" - desc = "Material with hilarious properties" + desc = "Material with hilarious properties." color = list(460/255, 464/255, 0, 0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //obnoxiously bright yellow //It's literally perfect I can't change it greyscale_color = "#FFF269" - categories = list( - MAT_CATEGORY_SILO = TRUE, - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_SILO_STORED | MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 4, + MATERIAL_HARDNESS = 6, + MATERIAL_FLEXIBILITY = 2, + MATERIAL_REFLECTIVITY = 4, + MATERIAL_ELECTRICAL = 1, // ...Rubbery? + MATERIAL_THERMAL = 6, + MATERIAL_CHEMICAL = 6, + MATERIAL_BEAUTY = 0.5, // Honk ) sheet_type = /obj/item/stack/sheet/mineral/bananium ore_type = /obj/item/stack/ore/bananium + material_reagent = /datum/reagent/consumable/banana value_per_unit = 1000 / SHEET_MATERIAL_AMOUNT - beauty_modifier = 0.5 - armor_modifiers = list(BOMB = 100, FIRE = 10) //Clowns cant be blown away. mineral_rarity = MATERIAL_RARITY_UNDISCOVERED points_per_unit = 60 / SHEET_MATERIAL_AMOUNT - fishing_difficulty_modifier = 20 //can't get a good grip on slipperiness. - fishing_cast_range = 3 //long slide - fishing_experience_multiplier = 1.6 - fishing_completion_speed = 1.3 - fishing_bait_speed_mult = 1.5 - fishing_deceleration_mult = 0.5 - fishing_bounciness_mult = 2 /datum/material/bananium/on_applied(atom/source, mat_amount, multiplier) . = ..() @@ -410,44 +342,32 @@ Unless you know what you're doing, only use the first three numbers. They're in if(istype(source, /obj/item/fishing_rod)) UnregisterSignal(source, COMSIG_ROD_BEGIN_FISHING) -/datum/material/bananium/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) - victim.reagents.add_reagent(/datum/reagent/consumable/banana, rand(8, 12)) - source_item?.reagents?.add_reagent(/datum/reagent/consumable/banana, source_item.reagents.total_volume*(2/5)) - return TRUE - ///Mediocre force increase /datum/material/titanium name = "titanium" desc = "Titanium" color = "#EFEFEF" - strength_modifier = 1.3 - categories = list( - MAT_CATEGORY_SILO = TRUE, - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_properties = list( + MATERIAL_DENSITY = 5, + MATERIAL_HARDNESS = 7, + MATERIAL_FLEXIBILITY = 2, + MATERIAL_REFLECTIVITY = 8, + MATERIAL_ELECTRICAL = 5, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 6, ) + mat_flags = MATERIAL_SILO_STORED | MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID sheet_type = /obj/item/stack/sheet/mineral/titanium ore_type = /obj/item/stack/ore/titanium value_per_unit = 125 / SHEET_MATERIAL_AMOUNT tradable = TRUE tradable_base_quantity = MATERIAL_QUANTITY_UNCOMMON - beauty_modifier = 0.05 - armor_modifiers = list(MELEE = 1.35, BULLET = 1.3, LASER = 1.3, ENERGY = 1.25, BOMB = 1.25, BIO = 1, FIRE = 0.7, ACID = 1) mat_rust_resistance = RUST_RESISTANCE_TITANIUM mineral_rarity = MATERIAL_RARITY_SEMIPRECIOUS texture_layer_icon_state = "shine" - fish_weight_modifier = 1.2 - fishing_difficulty_modifier = -5 - fishing_cast_range = 1 - fishing_completion_speed = 1.15 - fishing_bait_speed_mult = 1.1 - fishing_deceleration_mult = 1.3 - fishing_bounciness_mult = 0.75 - fishing_gravity_mult = 1.1 /datum/material/titanium/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(15, BRUTE, BODY_ZONE_HEAD, wound_bonus = 7) return TRUE @@ -456,27 +376,20 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "runite" desc = "Runite" color = "#526F77" - strength_modifier = 1.3 - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 9, + MATERIAL_HARDNESS = 9, + MATERIAL_FLEXIBILITY = 1, + MATERIAL_REFLECTIVITY = 0, + MATERIAL_ELECTRICAL = 1, + MATERIAL_THERMAL = 0, + MATERIAL_CHEMICAL = 9, + ) sheet_type = /obj/item/stack/sheet/mineral/runite value_per_unit = 600 / SHEET_MATERIAL_AMOUNT - beauty_modifier = 0.5 - armor_modifiers = list(MELEE = 1.35, BULLET = 2, LASER = 0.5, ENERGY = 1.25, BOMB = 1.25, BIO = 1, FIRE = 1.4, ACID = 1) //rune is weak against magic lasers but strong against bullets. This is the combat triangle. mineral_rarity = MATERIAL_RARITY_UNDISCOVERED points_per_unit = 100 / SHEET_MATERIAL_AMOUNT - fish_weight_modifier = 1.5 - fishing_difficulty_modifier = -13 - fishing_cast_range = 1 - fishing_experience_multiplier = 3.2 //grind all the way to level 100 in no time. - fishing_completion_speed = 1.3 - fishing_bait_speed_mult = 0.9 - fishing_deceleration_mult = 1.2 - fishing_gravity_mult = 1.2 /datum/material/runite/on_applied(atom/source, mat_amount, multiplier) . = ..() @@ -489,6 +402,7 @@ Unless you know what you're doing, only use the first three numbers. They're in REMOVE_TRAIT(source, TRAIT_ROD_REMOVE_FISHING_DUD, REF(src)) //light-absorbing, environment-cancelling fishing rod. /datum/material/runite/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = 10) return TRUE @@ -498,159 +412,115 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "plastic" desc = "Plastic" color = "#BFB9AC" - strength_modifier = 0.85 - sheet_type = /obj/item/stack/sheet/plastic - ore_type = /obj/item/stack/ore/slag //No plastic or coal ore, so we use slag. - categories = list( - MAT_CATEGORY_SILO = TRUE, - MAT_CATEGORY_RIGID=TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, + mat_flags = MATERIAL_SILO_STORED | MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_POLYMER | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 3, + MATERIAL_HARDNESS = 2, + MATERIAL_FLEXIBILITY = 5, + MATERIAL_REFLECTIVITY = 3, + MATERIAL_ELECTRICAL = 1, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 4, + MATERIAL_FLAMMABILITY = 4, ) + sheet_type = /obj/item/stack/sheet/plastic + ore_type = /obj/item/stack/ore/slag // No plastic or coal ore, so we use slag. + material_reagent = /datum/reagent/plastic_polymers value_per_unit = 25 / SHEET_MATERIAL_AMOUNT - beauty_modifier = -0.01 - armor_modifiers = list(MELEE = 1.5, BULLET = 1.1, LASER = 0.3, ENERGY = 0.5, BOMB = 1, BIO = 1, FIRE = 1.1, ACID = 1) - mineral_rarity = MATERIAL_RARITY_UNDISCOVERED //Nobody's found oil on lavaland yet. + mineral_rarity = MATERIAL_RARITY_UNDISCOVERED // Nobody's found oil on lavaland yet. points_per_unit = 4 / SHEET_MATERIAL_AMOUNT - fish_weight_modifier = 0.8 - fishing_difficulty_modifier = -5 - fishing_cast_range = 2 - fishing_experience_multiplier = 1.2 - fishing_bait_speed_mult = 1.2 - fishing_deceleration_mult = 0.8 - fishing_bounciness_mult = 1.3 - fishing_gravity_mult = 0.85 -/datum/material/plastic/on_accidental_mat_consumption(mob/living/carbon/eater, obj/item/food) - eater.reagents.add_reagent(/datum/reagent/plastic_polymers, rand(6, 8)) - food?.reagents?.add_reagent(/datum/reagent/plastic_polymers, food.reagents.total_volume*(2/5)) - return TRUE - -///Force decrease and mushy sound effect. (Not yet implemented) +/// Force decrease and mushy sound effect. (Not yet implemented) /datum/material/biomass name = "biomass" desc = "Organic matter." color = "#735b4d" - strength_modifier = 0.8 value_per_unit = 50 / SHEET_MATERIAL_AMOUNT /datum/material/wood name = "wood" desc = "Flexible, durable, but flammable. Hard to come across in space." color = "#855932" - strength_modifier = 0.5 + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_ORGANIC | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 2, + MATERIAL_HARDNESS = 4, + MATERIAL_FLEXIBILITY = 4, + MATERIAL_REFLECTIVITY = 1, + MATERIAL_ELECTRICAL = 8, + MATERIAL_THERMAL = 3, + MATERIAL_CHEMICAL = 1, + MATERIAL_FLAMMABILITY = 6, + MATERIAL_BEAUTY = 0.1, // Pretty patterns + ) sheet_type = /obj/item/stack/sheet/mineral/wood - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + material_reagent = /datum/reagent/cellulose value_per_unit = 20 / SHEET_MATERIAL_AMOUNT - beauty_modifier = 0.1 - armor_modifiers = list(MELEE = 1.1, BULLET = 1.1, LASER = 0.4, ENERGY = 0.4, BOMB = 1, BIO = 0.2, ACID = 0.3) texture_layer_icon_state = "woodgrain" - fish_weight_modifier = 0.5 - fishing_difficulty_modifier = 8 - fishing_cast_range = -1 - fishing_experience_multiplier = 1.3 - fishing_completion_speed = 0.9 - fishing_bait_speed_mult = 0.8 - fishing_deceleration_mult = 1.3 - fishing_bounciness_mult = 0.4 - fishing_gravity_mult = 0.8 - -/datum/material/wood/on_main_applied(atom/source, mat_amount, multiplier) - . = ..() - if(source.material_flags & MATERIAL_AFFECT_STATISTICS && isobj(source)) - var/obj/wooden = source - wooden.resistance_flags |= FLAMMABLE - -/datum/material/wood/on_main_removed(atom/source, mat_amount, multiplier) - . = ..() - if(source.material_flags & MATERIAL_AFFECT_STATISTICS && isobj(source)) - var/obj/wooden = source - wooden.resistance_flags &= ~FLAMMABLE /datum/material/wood/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(5, BRUTE, BODY_ZONE_HEAD) - victim.reagents.add_reagent(/datum/reagent/cellulose, rand(8, 12)) - source_item?.reagents?.add_reagent(/datum/reagent/cellulose, source_item.reagents.total_volume*(2/5)) + return TRUE - return TRUE - -///Stronk force increase +/// Stronk force increase /datum/material/adamantine name = "adamantine" desc = "A powerful material made out of magic, I mean science!" color = "#2B7A74" - strength_modifier = 1.5 - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_properties = list( + MATERIAL_DENSITY = 7, + MATERIAL_HARDNESS = 9, + MATERIAL_FLEXIBILITY = 3, + MATERIAL_REFLECTIVITY = 6, + MATERIAL_ELECTRICAL = 6, + MATERIAL_THERMAL = 1, + MATERIAL_CHEMICAL = 9, + ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID sheet_type = /obj/item/stack/sheet/mineral/adamantine value_per_unit = 500 / SHEET_MATERIAL_AMOUNT - beauty_modifier = 0.4 - armor_modifiers = list(MELEE = 1.5, BULLET = 1.5, LASER = 1.3, ENERGY = 1.3, BOMB = 1, BIO = 1, FIRE = 2.5, ACID = 1) - mineral_rarity = MATERIAL_RARITY_UNDISCOVERED //Doesn't naturally spawn on lavaland. + mineral_rarity = MATERIAL_RARITY_UNDISCOVERED // Doesn't naturally spawn on lavaland. points_per_unit = 100 / SHEET_MATERIAL_AMOUNT - fish_weight_modifier = 1.6 - fishing_difficulty_modifier = -17 - fishing_cast_range = 1 - fishing_experience_multiplier = 0.6 - fishing_completion_speed = 1.3 - fishing_bait_speed_mult = 1.2 - fishing_deceleration_mult = 1.3 - fishing_bounciness_mult = 0.7 - fishing_gravity_mult = 1.3 /datum/material/adamantine/on_applied(atom/source, mat_amount, multiplier) . = ..() if(istype(source, /obj/item/fishing_rod)) - ADD_TRAIT(source, TRAIT_ROD_REMOVE_FISHING_DUD, REF(src)) //light-absorbing, environment-cancelling fishing rod. + ADD_TRAIT(source, TRAIT_ROD_REMOVE_FISHING_DUD, REF(src)) // light-absorbing, environment-cancelling fishing rod. /datum/material/adamantine/on_removed(atom/source, mat_amount, multiplier) . = ..() if(istype(source, /obj/item/fishing_rod)) - REMOVE_TRAIT(source, TRAIT_ROD_REMOVE_FISHING_DUD, REF(src)) //light-absorbing, environment-cancelling fishing rod. + REMOVE_TRAIT(source, TRAIT_ROD_REMOVE_FISHING_DUD, REF(src)) // light-absorbing, environment-cancelling fishing rod. /datum/material/adamantine/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = 10) return TRUE -///RPG Magic. +/// RPG Magic. /datum/material/mythril name = "mythril" desc = "How this even exists is byond me" color = "#f2d5d7" - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 4, + MATERIAL_HARDNESS = 10, + MATERIAL_FLEXIBILITY = 4, + MATERIAL_REFLECTIVITY = 8, + MATERIAL_ELECTRICAL = 6, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 9, + MATERIAL_BEAUTY = 0.5, + MATERIAL_INTEGRITY = 2, // This is magic, I ain't gotta explain shit + ) sheet_type = /obj/item/stack/sheet/mineral/mythril value_per_unit = 1500 / SHEET_MATERIAL_AMOUNT - strength_modifier = 1.2 - armor_modifiers = list(MELEE = 1.5, BULLET = 1.5, LASER = 1.5, ENERGY = 1.5, BOMB = 1.5, BIO = 1.5, FIRE = 1.5, ACID = 1.5) - beauty_modifier = 0.5 - mineral_rarity = MATERIAL_RARITY_UNDISCOVERED //Doesn't naturally spawn on lavaland. + mineral_rarity = MATERIAL_RARITY_UNDISCOVERED // Doesn't naturally spawn on lavaland. points_per_unit = 100 / SHEET_MATERIAL_AMOUNT - fish_weight_modifier = 1.4 - fishing_difficulty_modifier = -20 - fishing_cast_range = 2 - fishing_experience_multiplier = 0.5 - fishing_completion_speed = 1.35 - fishing_bait_speed_mult = 1.2 - fishing_deceleration_mult = 1.35 - fishing_bounciness_mult = 0.65 - fishing_gravity_mult = 1.3 /datum/material/mythril/on_applied(atom/source, mat_amount, multiplier) . = ..() @@ -665,6 +535,7 @@ Unless you know what you're doing, only use the first three numbers. They're in qdel(source.GetComponent(/datum/component/fantasy)) /datum/material/mythril/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = 10) return TRUE @@ -676,67 +547,51 @@ Unless you know what you're doing, only use the first three numbers. They're in color = "#88cdf1" alpha = 150 starlight_color = COLOR_BLUE_LIGHT - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_CRYSTAL + mat_properties = list( + MATERIAL_DENSITY = 4, + MATERIAL_HARDNESS = 2, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 8, + MATERIAL_ELECTRICAL = 9, + MATERIAL_THERMAL = 8, + MATERIAL_CHEMICAL = 4, + MATERIAL_FLAMMABILITY = 10, + ) sheet_type = /obj/item/stack/sheet/hot_ice + material_reagent = /datum/reagent/toxin/hot_ice value_per_unit = 400 / SHEET_MATERIAL_AMOUNT - beauty_modifier = 0.2 - fish_weight_modifier = 0.9 - fishing_difficulty_modifier = -8 - fishing_cast_range = 1 - fishing_experience_multiplier = 0.9 - fishing_completion_speed = 1.4 - fishing_bait_speed_mult = 1.3 - fishing_deceleration_mult = 0.5 - fishing_bounciness_mult = 0.3 - fishing_gravity_mult = 0.8 /datum/material/hot_ice/on_applied(atom/source, mat_amount, multiplier) . = ..() - source.AddComponent(/datum/component/combustible_flooder, "plasma", mat_amount * 1.5 * multiplier, (mat_amount * 0.2 + 300) * multiplier) + source.AddComponent(/datum/component/combustible_flooder, GAS_PLASMA, mat_amount * 1.5 * multiplier, (mat_amount * 0.2 + 300) * multiplier) /datum/material/hot_ice/on_removed(atom/source, mat_amount, multiplier) + . = ..() qdel(source.GetComponent(/datum/component/combustible_flooder)) - return ..() - -/datum/material/hot_ice/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) - victim.reagents.add_reagent(/datum/reagent/toxin/plasma, rand(5, 6)) - source_item?.reagents?.add_reagent(/datum/reagent/toxin/plasma, source_item.reagents.total_volume*(3/5)) - return TRUE // It's basically adamantine, but it isn't! /datum/material/metalhydrogen name = "Metal Hydrogen" desc = "Solid metallic hydrogen. Some say it should be impossible" color = "#62708A" - alpha = 150 starlight_color = COLOR_MODERATE_BLUE - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 3, + MATERIAL_HARDNESS = 10, + MATERIAL_FLEXIBILITY = 1, + MATERIAL_REFLECTIVITY = 8, + MATERIAL_ELECTRICAL = 2, + MATERIAL_THERMAL = 2, + MATERIAL_CHEMICAL = 8, + ) sheet_type = /obj/item/stack/sheet/mineral/metal_hydrogen + material_reagent = /datum/reagent/hydrogen value_per_unit = 700 / SHEET_MATERIAL_AMOUNT - beauty_modifier = 0.35 - strength_modifier = 1.2 - armor_modifiers = list(MELEE = 1.35, BULLET = 1.3, LASER = 1.3, ENERGY = 1.25, BOMB = 0.7, BIO = 1, FIRE = 1.3, ACID = 1) - fish_weight_modifier = 0.6 //It may be metallic, but it's just "denser" hydrogen at the end of the day, no? - fishing_difficulty_modifier = -13 - fishing_cast_range = 4 - fishing_experience_multiplier = 0.8 - fishing_completion_speed = 1.4 - fishing_bait_speed_mult = 1.3 - fishing_deceleration_mult = 0.8 - fishing_bounciness_mult = 1.7 - fishing_gravity_mult = 0.7 /datum/material/metalhydrogen/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(15, BRUTE, BODY_ZONE_HEAD, wound_bonus = 7) return TRUE @@ -746,31 +601,25 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "sand" desc = "You know, it's amazing just how structurally sound sand can be." color = "#EDC9AF" - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_AMORPHOUS + mat_properties = list( + MATERIAL_DENSITY = 2, + MATERIAL_HARDNESS = 0, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 7, + MATERIAL_ELECTRICAL = 1, + MATERIAL_THERMAL = 8, + MATERIAL_CHEMICAL = 4, + ) ore_type = /obj/item/stack/ore/glass + material_reagent = /datum/reagent/silicon value_per_unit = 2 / SHEET_MATERIAL_AMOUNT - strength_modifier = 0.5 - integrity_modifier = 0.1 - armor_modifiers = list(MELEE = 0.25, BULLET = 0.25, LASER = 1.25, ENERGY = 0.25, BOMB = 0.25, BIO = 0.25, FIRE = 1.5, ACID = 1.5) - beauty_modifier = 0.25 turf_sound_override = FOOTSTEP_SAND texture_layer_icon_state = "sand" mat_rust_resistance = RUST_RESISTANCE_BASIC - fish_weight_modifier = 1.2 - fishing_difficulty_modifier = 30 //Sand fishing rods? What the hell are you doing? - fishing_cast_range = -2 - fishing_experience_multiplier = 0.2 - fishing_completion_speed = 0.8 - fishing_bait_speed_mult = 0.8 - fishing_deceleration_mult = 2.5 - fishing_bounciness_mult = 0.3 - fishing_gravity_mult = 0.9 /datum/material/sand/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() victim.adjust_disgust(17) return TRUE @@ -779,86 +628,63 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "sandstone" desc = "Bialtaakid 'ant taerif ma hdha." color = "#ECD5A8" - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES + mat_properties = list( + MATERIAL_DENSITY = 4, + MATERIAL_HARDNESS = 3, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 2, + MATERIAL_ELECTRICAL = 2, + MATERIAL_THERMAL = 6, + MATERIAL_CHEMICAL = 6, + ) sheet_type = /obj/item/stack/sheet/mineral/sandstone + material_reagent = /datum/reagent/silicon value_per_unit = 5 / SHEET_MATERIAL_AMOUNT - armor_modifiers = list(MELEE = 0.5, BULLET = 0.5, LASER = 1.25, ENERGY = 0.5, BOMB = 0.5, BIO = 0.25, FIRE = 1.5, ACID = 1.5) - beauty_modifier = 0.3 turf_sound_override = FOOTSTEP_WOOD texture_layer_icon_state = "brick" mat_rust_resistance = RUST_RESISTANCE_BASIC - fish_weight_modifier = 1.2 - fishing_difficulty_modifier = 25 //Sand fishing rods? What the hell are you doing? - fishing_cast_range = -2 - fishing_experience_multiplier = 0.3 - fishing_completion_speed = 0.9 - fishing_bait_speed_mult = 0.8 - fishing_deceleration_mult = 2.5 - fishing_bounciness_mult = 0.2 - fishing_gravity_mult = 0.9 /datum/material/snow name = "snow" desc = "There's no business like snow business." color = COLOR_WHITE - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_AMORPHOUS + mat_properties = list( + MATERIAL_DENSITY = 2, + MATERIAL_HARDNESS = 1, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 6, + MATERIAL_ELECTRICAL = 6, + MATERIAL_THERMAL = 6, + MATERIAL_CHEMICAL = 1, + ) sheet_type = /obj/item/stack/sheet/mineral/snow - strength_modifier = 0.4 - integrity_modifier = 0.4 - value_per_unit = 5 / SHEET_MATERIAL_AMOUNT - armor_modifiers = list(MELEE = 0.25, BULLET = 0.25, LASER = 0.25, ENERGY = 0.25, BOMB = 0.25, BIO = 0.25, FIRE = 0.25, ACID = 1.5) - beauty_modifier = 0.3 + material_reagent = /datum/reagent/consumable/ice turf_sound_override = FOOTSTEP_SAND texture_layer_icon_state = "sand" mat_rust_resistance = RUST_RESISTANCE_ORGANIC - fish_weight_modifier = 0.8 - fishing_difficulty_modifier = 25 - fishing_cast_range = -2 - fishing_experience_multiplier = 0.3 - fishing_completion_speed = 0.9 - fishing_bait_speed_mult = 0.75 - fishing_deceleration_mult = 0.3 - fishing_bounciness_mult = 0.2 - fishing_gravity_mult = 0.7 - -/datum/material/snow/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) - victim.reagents.add_reagent(/datum/reagent/water, rand(5, 10)) - return TRUE /datum/material/runedmetal name = "runed metal" desc = "Mir'ntrath barhah Nar'sie." color = "#504742" - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 7, + MATERIAL_HARDNESS = 7, + MATERIAL_FLEXIBILITY = 3, + MATERIAL_REFLECTIVITY = 2, + MATERIAL_ELECTRICAL = 5, + MATERIAL_THERMAL = 1, + MATERIAL_CHEMICAL = 8, + ) sheet_type = /obj/item/stack/sheet/runed_metal value_per_unit = 1500 / SHEET_MATERIAL_AMOUNT - armor_modifiers = list(MELEE = 1.2, BULLET = 1.2, LASER = 1, ENERGY = 1, BOMB = 1.2, BIO = 1.2, FIRE = 1.5, ACID = 1.5) - beauty_modifier = -0.15 texture_layer_icon_state = "runed" - fish_weight_modifier = 1.5 - fishing_difficulty_modifier = -6.66 - fishing_experience_multiplier = 0.666 - fishing_completion_speed = 1.666 - fishing_bait_speed_mult = 1.666 - fishing_deceleration_mult = 1.666 - fishing_bounciness_mult = 0.666 - fishing_gravity_mult = 1.666 /datum/material/runedmetal/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() victim.reagents.add_reagent(/datum/reagent/fuel/unholywater, rand(8, 12)) if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5) @@ -868,54 +694,47 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "bronze" desc = "Clock Cult? Never heard of it." color = "#876223" - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 8, // Bronze is *very* dense, almost as dense as lead + MATERIAL_HARDNESS = 5, + MATERIAL_FLEXIBILITY = 3, + MATERIAL_REFLECTIVITY = 7, + MATERIAL_ELECTRICAL = 8, + MATERIAL_THERMAL = 8, + MATERIAL_CHEMICAL = 5, + ) sheet_type = /obj/item/stack/sheet/bronze + material_reagent = list(/datum/reagent/iron = 0.75, /datum/reagent/copper = 0.25) value_per_unit = 50 / SHEET_MATERIAL_AMOUNT - armor_modifiers = list(MELEE = 1, BULLET = 1, LASER = 1, ENERGY = 1, BOMB = 1, BIO = 1, FIRE = 1.5, ACID = 1.5) - beauty_modifier = 0.2 - fish_weight_modifier = 1.4 - fishing_bait_speed_mult = 1.1 - fishing_deceleration_mult = 0.8 - fishing_bounciness_mult = 1.2 - fishing_gravity_mult = 1.05 /datum/material/paper name = "paper" desc = "Ten thousand folds of pure starchy power." color = "#E5DCD5" - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_ORGANIC + mat_properties = list( + MATERIAL_DENSITY = 0, + MATERIAL_HARDNESS = 0, + MATERIAL_FLEXIBILITY = 8, + MATERIAL_REFLECTIVITY = 1, + MATERIAL_ELECTRICAL = 4, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 0, + MATERIAL_FLAMMABILITY = 8, + MATERIAL_BEAUTY = 0.3, // Origami is beautiful + ) + material_reagent = /datum/reagent/cellulose sheet_type = /obj/item/stack/sheet/paperframes value_per_unit = 5 / SHEET_MATERIAL_AMOUNT - strength_modifier = 0.3 - armor_modifiers = list(MELEE = 0.1, BULLET = 0.1, LASER = 0.1, ENERGY = 0.1, BOMB = 0.1, BIO = 0.1, ACID = 1.5) - beauty_modifier = 0.3 turf_sound_override = FOOTSTEP_SAND texture_layer_icon_state = "paper" - fish_weight_modifier = 0.4 - fishing_difficulty_modifier = 40 //child's play - fishing_cast_range = -2 - fishing_experience_multiplier = 0.1 - fishing_bait_speed_mult = 0.7 - fishing_deceleration_mult = 1.5 - fishing_bounciness_mult = 0.2 - fishing_gravity_mult = 0.6 /datum/material/paper/on_main_applied(atom/source, mat_amount, multiplier) . = ..() if(!isobj(source) || !(source.material_flags & MATERIAL_AFFECT_STATISTICS)) return var/obj/paper = source - paper.resistance_flags |= FLAMMABLE paper.obj_flags |= UNIQUE_RENAME if(istype(paper, /obj/item/fishing_rod)) RegisterSignal(paper, COMSIG_ROD_BEGIN_FISHING, PROC_REF(on_begin_fishing)) @@ -931,73 +750,51 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/paper/on_main_removed(atom/source, mat_amount, multiplier) . = ..() - if(!isobj(source) || !(source.material_flags & MATERIAL_AFFECT_STATISTICS)) - return - var/obj/paper = source - paper.resistance_flags &= ~FLAMMABLE - if(istype(paper, /obj/item/fishing_rod)) - UnregisterSignal(paper, COMSIG_ROD_BEGIN_FISHING) + if(istype(source, /obj/item/fishing_rod) && (source.material_flags & MATERIAL_AFFECT_STATISTICS)) + UnregisterSignal(source, COMSIG_ROD_BEGIN_FISHING) /datum/material/cardboard name = "cardboard" desc = "They say cardboard is used by hobos to make incredible things." color = "#5F625C" - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_ORGANIC + mat_properties = list( + MATERIAL_DENSITY = 1, + MATERIAL_HARDNESS = 0, + MATERIAL_FLEXIBILITY = 6, + MATERIAL_REFLECTIVITY = 1, + MATERIAL_ELECTRICAL = 4, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 2, + MATERIAL_FLAMMABILITY = 6, + ) sheet_type = /obj/item/stack/sheet/cardboard + material_reagent = /datum/reagent/cellulose value_per_unit = 6 / SHEET_MATERIAL_AMOUNT - strength_modifier = 0.3 - armor_modifiers = list(MELEE = 0.25, BULLET = 0.25, LASER = 0.25, ENERGY = 0.25, BOMB = 0.25, BIO = 0.25, ACID = 1.5) - beauty_modifier = -0.1 - fish_weight_modifier = 0.4 - fishing_difficulty_modifier = 40 //child's play - fishing_cast_range = -2 - fishing_experience_multiplier = 0.1 - fishing_bait_speed_mult = 0.7 - fishing_deceleration_mult = 1.5 - fishing_bounciness_mult = 0.2 - fishing_gravity_mult = 0.6 /datum/material/cardboard/on_main_applied(atom/source, mat_amount, multiplier) . = ..() if(isobj(source) && source.material_flags & MATERIAL_AFFECT_STATISTICS) var/obj/cardboard = source - cardboard.resistance_flags |= FLAMMABLE cardboard.obj_flags |= UNIQUE_RENAME -/datum/material/cardboard/on_main_removed(atom/source, mat_amount, multiplier) - if(isobj(source) && source.material_flags & MATERIAL_AFFECT_STATISTICS) - var/obj/cardboard = source - cardboard.resistance_flags &= ~FLAMMABLE - return ..() - /datum/material/bone name = "bone" desc = "Man, building with this will make you the coolest caveman on the block." color = "#e3dac9" - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_ORGANIC | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 3, + MATERIAL_HARDNESS = 5, + MATERIAL_FLEXIBILITY = 2, + MATERIAL_REFLECTIVITY = 4, + MATERIAL_ELECTRICAL = 3, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 2, + ) sheet_type = /obj/item/stack/sheet/bone + material_reagent = /datum/reagent/bone_dust value_per_unit = 100 / SHEET_MATERIAL_AMOUNT - armor_modifiers = list(MELEE = 1.2, BULLET = 0.75, LASER = 0.75, ENERGY = 1.2, BOMB = 1, BIO = 1, FIRE = 1.5, ACID = 1.5) - beauty_modifier = -0.2 - fish_weight_modifier = 1.05 - fishing_difficulty_modifier = 15 - fishing_cast_range = -2 - fishing_experience_multiplier = 0.85 - fishing_completion_speed = 0.9 - fishing_bait_speed_mult = 0.9 - fishing_deceleration_mult = 0.9 - fishing_bounciness_mult = 0.8 - fishing_gravity_mult = 0.85 /datum/material/bone/on_main_applied(atom/source, mat_amount, multiplier) . = ..() @@ -1036,51 +833,41 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "bamboo" desc = "If it's good enough for pandas, it's good enough for you." color = "#87a852" - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_ORGANIC | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 3, // Denser and bendier than wood, but pretty much the same otherwise + MATERIAL_HARDNESS = 4, + MATERIAL_FLEXIBILITY = 5, + MATERIAL_REFLECTIVITY = 1, + MATERIAL_ELECTRICAL = 6, + MATERIAL_THERMAL = 3, + MATERIAL_CHEMICAL = 1, + MATERIAL_FLAMMABILITY = 6, + MATERIAL_BEAUTY = 0.2, // Prettier patterns + ) sheet_type = /obj/item/stack/sheet/mineral/bamboo - strength_modifier = 0.5 + material_reagent = /datum/reagent/cellulose value_per_unit = 5 / SHEET_MATERIAL_AMOUNT - armor_modifiers = list(MELEE = 0.5, BULLET = 0.5, LASER = 0.5, ENERGY = 0.5, BOMB = 0.5, BIO = 0.51, FIRE = 0.5, ACID = 1.5) - beauty_modifier = 0.2 turf_sound_override = FOOTSTEP_WOOD texture_layer_icon_state = "bamboo" - fish_weight_modifier = 0.5 - fishing_difficulty_modifier = -4 - fishing_cast_range = -1 - fishing_experience_multiplier = 1.3 - fishing_completion_speed = 1.15 - fishing_bait_speed_mult = 1.1 - fishing_deceleration_mult = 0.8 - fishing_bounciness_mult = 0.7 - fishing_gravity_mult = 0.7 /datum/material/zaukerite name = "zaukerite" desc = "A light absorbing crystal" color = COLOR_ALMOST_BLACK - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_CRYSTAL | MATERIAL_CLASS_RIGID + mat_properties = list( + MATERIAL_DENSITY = 1, + MATERIAL_HARDNESS = 9, + MATERIAL_FLEXIBILITY = 0, + MATERIAL_REFLECTIVITY = 0, + MATERIAL_ELECTRICAL = 1, + MATERIAL_THERMAL = 9, + MATERIAL_CHEMICAL = 0, + ) sheet_type = /obj/item/stack/sheet/mineral/zaukerite + material_reagent = /datum/reagent/toxin/plasma value_per_unit = 900 / SHEET_MATERIAL_AMOUNT - armor_modifiers = list(MELEE = 0.9, BULLET = 0.9, LASER = 1.75, ENERGY = 1.75, BOMB = 0.5, BIO = 1, FIRE = 0.1, ACID = 1) - beauty_modifier = 0.001 - fish_weight_modifier = 1.2 - fishing_difficulty_modifier = -14 - fishing_experience_multiplier = 0.9 - fishing_completion_speed = 1.3 - fishing_bait_speed_mult = 1.2 - fishing_deceleration_mult = 1.3 - fishing_bounciness_mult = 1.1 - fishing_gravity_mult = 1.3 /datum/material/zaukerite/on_applied(atom/source, mat_amount, multiplier) . = ..() @@ -1093,7 +880,7 @@ Unless you know what you're doing, only use the first three numbers. They're in REMOVE_TRAIT(source, TRAIT_ROD_IGNORE_ENVIRONMENT, REF(src)) //light-absorbing, environment-cancelling fishing rod. /datum/material/zaukerite/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + . = ..() if(!HAS_TRAIT(victim, TRAIT_ROCK_EATER)) victim.apply_damage(30, BURN, BODY_ZONE_HEAD, wound_bonus = 5) - source_item?.reagents?.add_reagent(/datum/reagent/toxin/plasma, source_item.reagents.total_volume*5) return TRUE diff --git a/code/datums/materials/hauntium.dm b/code/datums/materials/hauntium.dm index e6611678932..8ac8c750cb5 100644 --- a/code/datums/materials/hauntium.dm +++ b/code/datums/materials/hauntium.dm @@ -5,25 +5,20 @@ greyscale_color = "#FFFFFF" alpha = 100 starlight_color = COLOR_ALMOST_BLACK - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_METAL | MATERIAL_CLASS_FABRIC // Metal for crafting, and fabric because bedsheets and ghosts... you get it. + mat_properties = list( + MATERIAL_DENSITY = 2, + MATERIAL_HARDNESS = 6, + MATERIAL_FLEXIBILITY = 8, // Fabric + MATERIAL_REFLECTIVITY = 4, + MATERIAL_ELECTRICAL = 4, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 2, + MATERIAL_FLAMMABILITY = 6, + ) sheet_type = /obj/item/stack/sheet/hauntium + material_reagent = /datum/reagent/hauntium value_per_unit = 0.05 - beauty_modifier = 0.25 - //pretty good but only the undead can actually make use of these modifiers - strength_modifier = 1.2 - armor_modifiers = list(MELEE = 1.1, BULLET = 1.1, LASER = 1.15, ENERGY = 1.15, BOMB = 1, BIO = 1, FIRE = 1, ACID = 0.7) - fish_weight_modifier = 1.4 - fishing_difficulty_modifier = -25 //Only the undead and the coroner can game this. - fishing_cast_range = 2 - fishing_experience_multiplier = 1.5 - fishing_completion_speed = 1.1 - fishing_bait_speed_mult = 0.85 - fishing_gravity_mult = 0.8 /datum/material/hauntium/on_main_applied(atom/source, mat_amount, multiplier) . = ..() diff --git a/code/datums/materials/meat.dm b/code/datums/materials/meat.dm index 87f6318a64b..8e33c31a50f 100644 --- a/code/datums/materials/meat.dm +++ b/code/datums/materials/meat.dm @@ -4,27 +4,21 @@ 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, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_ORGANIC + mat_properties = list( + MATERIAL_DENSITY = 5, + MATERIAL_HARDNESS = 0, + MATERIAL_FLEXIBILITY = 6, + MATERIAL_REFLECTIVITY = 4, + MATERIAL_ELECTRICAL = 8, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 2, + MATERIAL_BEAUTY = -0.3, // EWW + ) sheet_type = /obj/item/stack/sheet/meat - value_per_unit = 0.05 - beauty_modifier = -0.3 - strength_modifier = 0.7 - armor_modifiers = list(MELEE = 0.3, BULLET = 0.3, LASER = 1.2, ENERGY = 1.2, BOMB = 0.3, FIRE = 1, ACID = 1) item_sound_override = 'sound/effects/meatslap.ogg' turf_sound_override = FOOTSTEP_MEAT texture_layer_icon_state = "meat" - fishing_difficulty_modifier = 13 - fishing_cast_range = -2 - fishing_experience_multiplier = 0.8 - fishing_bait_speed_mult = 0.9 - fishing_deceleration_mult = 0.9 - fishing_bounciness_mult = 0.9 - fishing_gravity_mult = 0.85 var/list/blood_dna /datum/material/meat/on_main_applied(atom/source, mat_amount, multiplier) diff --git a/code/datums/materials/pizza.dm b/code/datums/materials/pizza.dm index fbc54cf65c6..3eb8bb533e2 100644 --- a/code/datums/materials/pizza.dm +++ b/code/datums/materials/pizza.dm @@ -2,29 +2,21 @@ name = "pizza" desc = "~Jamme, jamme, n'coppa, jamme ja! Jamme, jamme, n'coppa jamme ja, funi-culi funi-cala funi-culi funi-cala!! Jamme jamme ja funiculi funicula!~" color = "#FF9F23" - categories = list( - MAT_CATEGORY_RIGID = TRUE, - MAT_CATEGORY_BASE_RECIPES = TRUE, - MAT_CATEGORY_ITEM_MATERIAL = TRUE, - MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = TRUE, - ) + mat_flags = MATERIAL_BASIC_RECIPES | MATERIAL_CLASS_ORGANIC + mat_properties = list( + MATERIAL_DENSITY = 4, + MATERIAL_HARDNESS = 1, + MATERIAL_FLEXIBILITY = 6, + MATERIAL_REFLECTIVITY = 2, + MATERIAL_ELECTRICAL = 8, + MATERIAL_THERMAL = 4, + MATERIAL_CHEMICAL = 2, + ) sheet_type = /obj/item/stack/sheet/pizza - value_per_unit = 0.05 - beauty_modifier = 0.1 - strength_modifier = 0.7 - armor_modifiers = list(MELEE = 0.3, BULLET = 0.3, LASER = 1.2, ENERGY = 1.2, BOMB = 0.3, FIRE = 1, ACID = 1) item_sound_override = 'sound/effects/meatslap.ogg' turf_sound_override = FOOTSTEP_MEAT texture_layer_icon_state = "pizza" mat_rust_resistance = RUST_RESISTANCE_REINFORCED - fish_weight_modifier = 0.9 - fishing_difficulty_modifier = 13 - fishing_cast_range = -2 - fishing_experience_multiplier = 0.8 - fishing_bait_speed_mult = 0.9 - fishing_deceleration_mult = 0.9 - fishing_bounciness_mult = 0.9 - fishing_gravity_mult = 0.8 /datum/material/pizza/on_main_applied(atom/source, mat_amount, multiplier) . = ..() diff --git a/code/datums/materials/properties/_properties.dm b/code/datums/materials/properties/_properties.dm new file mode 100644 index 00000000000..b9fa27e26a0 --- /dev/null +++ b/code/datums/materials/properties/_properties.dm @@ -0,0 +1,174 @@ +/// Singleton datums used to hold material property info +/datum/material_property + abstract_type = /datum/material_property + var/name = "Error" + /// Associated property ID + var/id = null + /// Should this property be inherited by child materials? + var/inherited = TRUE + +/// Returns a string to display to sci glasses wearers when the material is examined +/datum/material_property/proc/get_descriptor(value) + return null + +/// Called whenever a material with this property initializes. Mostly used for behavior tracking on optional properties +/datum/material_property/proc/attach_to(datum/material/material) + return + +/// How dense a material is +/datum/material_property/density + name = "Density" + id = MATERIAL_DENSITY + +/datum/material_property/density/get_descriptor(value) + // Just for reference, IRL density of ABS plastic and water is ~1g/cm3, glass is 2.5, iron is 7.5 and lead is 11 + // So 0 ~ 1 would be paper/cardboard, then wood at 2, plastic at 3, glass at 4, iron at 6 and lead at 8 ~ 9 + switch(value) + if (0 to 1) + return "extremely light" + if (1 to 2) + return "very light" + if (2 to 3) + return "light" + if (3 to 4) + return "slightly dense" + if (4 to 6) + return "dense" + if (6 to 8) + return "very dense" + if (8 to INFINITY) + return "extremely dense" + +/// How hard to deformation a material is, pierce/slashing impacts +/datum/material_property/hardness + name = "Hardness" + id = MATERIAL_HARDNESS + +/datum/material_property/hardness/get_descriptor(value) + switch(value) + if (0 to 1) + return "extremely soft" + if (1 to 2) + return "very soft" + if (2 to 3) + return "soft" + if (3 to 4) + return "slightly hard" + if (4 to 6) + return "hard" + if (6 to 8) + return "very hard" + if (8 to INFINITY) + return "extremely hard" + +/// How well a material bends and sustains deformation +/datum/material_property/flexibility + name = "Flexibility" + id = MATERIAL_FLEXIBILITY + +/datum/material_property/flexibility/get_descriptor(value) + switch(value) + if (0 to 1) + return "extremely rigid" + if (1 to 2) + return "very rigid" + if (2 to 3) + return "rigid" + if (3 to 4) + return "slightly flexible" + if (4 to 6) + return "flexible" + if (6 to 8) + return "very flexible" + if (8 to INFINITY) + return "extremely flexible" + +/// How shiny a material is +/datum/material_property/reflectivity + name = "Reflectivity" + id = MATERIAL_REFLECTIVITY + +/datum/material_property/reflectivity/get_descriptor(value) + switch(value) + if (0 to 1) + return "extremely dull" + if (1 to 2) + return "very dull" + if (2 to 3) + return "dull" + if (3 to 4) + return "matte" + if (4 to 6) + return "reflective" + if (6 to 8) + return "very reflective" + if (8 to INFINITY) + return "extremely reflective" + +/// How electrically conductive a material is (siemens coeff) +/datum/material_property/electric_conductivity + name = "Electric Conductivity" + id = MATERIAL_ELECTRICAL + +/datum/material_property/electric_conductivity/get_descriptor(value) + switch(value) + if (0) + return "perfectly insulating" + if (0 to 1) + return "highly insulating" + if (1 to 2) + return "insulating" + if (2 to 3) + return "poorly insulating" + if (3 to 4) + return "mildly conductive" + if (4 to 6) + return "conductive" + if (6 to 8) + return "highly conductive" + if (8 to INFINITY) + return "extremely conductive" + +/// How well a material conducts heat +/datum/material_property/thermal_conductivity + name = "Thermal Conductivity" + id = MATERIAL_THERMAL + +/datum/material_property/thermal_conductivity/get_descriptor(value) + switch(value) + if (0 to 1) + return "extremely temperature-resistant" + if (1 to 2) + return "very temperature-resistant" + if (2 to 3) + return "temperature-resistant" + if (3 to 4) + return "slightly thermally conductive" + if (4 to 6) + return "thermally conductive" + if (6 to 8) + return "very thermally conductive" + if (8 to INFINITY) + return "extremely thermally conductive" + +/// How well the material resists acids and other similar chemicals +/datum/material_property/chemical_resistance + name = "Chemical Resistance" + id = MATERIAL_CHEMICAL + +/datum/material_property/chemical_resistance/get_descriptor(value) + switch(value) + if (0 to 1) + return "extremely reactive" + if (1 to 2) + return "reactive" + if (2 to 3) + return "slightly reactive" + if (3 to 4) + return "mildly chemically resistant" + if (4 to 6) + return "chemically resistant" + if (6 to 8) + return "highly chemically resistant" + if (8 to INFINITY) + return "extremely chemically resistant" diff --git a/code/datums/materials/properties/derived.dm b/code/datums/materials/properties/derived.dm new file mode 100644 index 00000000000..4c18c035de7 --- /dev/null +++ b/code/datums/materials/properties/derived.dm @@ -0,0 +1,47 @@ +/// Derived properties aren't present on materials, and are instead just centralized holders for formulas +/datum/material_property/derived + abstract_type = /datum/material_property/derived + inherited = FALSE + +/// Does this property apply to our material? +/datum/material_property/derived/proc/is_present(datum/material/material) + return TRUE + +/// Calculate and fetch the value of the property on this material +/datum/material_property/derived/proc/get_value(datum/material/material) + return 0 + +#define INTEGRITY_MIN 0.1 +// This results in iron being almost exactly 1 +#define INTEGRITY_COEFF 1.57 + +/// Base atom integrity multiplier of items made from this material +/datum/material_property/derived/integrity + id = MATERIAL_INTEGRITY + +/datum/material_property/derived/integrity/get_value(datum/material/material) + // Integrity is a combination of density, hardness and flexibility + var/density = material.get_property(MATERIAL_DENSITY) + var/hardness = material.get_property(MATERIAL_HARDNESS) + var/flexibility = material.get_property(MATERIAL_FLEXIBILITY) + // Its primarily hardness - the harder a material is, the more it is resistant to direct impacts + // But unless it has enough bend to it, it'll also fracture - which is why flexibility needs to be in a sweetspot, based on density + var/hardness_coeff = (2 + max(0, hardness - 4) * 2 - max(0, 2 - hardness)) / MATERIAL_PROPERTY_MAX + var/bend_coeff = 1 - abs(flexibility - sqrt(density)) * 0.1 + // Check the math for yourself in https://www.desmos.com/calculator/ez2n34w772 + return round(INTEGRITY_MIN + hardness_coeff * bend_coeff * INTEGRITY_COEFF, 0.01) + +#undef INTEGRITY_MIN +#undef INTEGRITY_COEFF + +/// How pretty a material is +/datum/material_property/derived/beauty + id = MATERIAL_BEAUTY + +/datum/material_property/derived/beauty/is_present(datum/material/material) + return abs(material.get_property(MATERIAL_REFLECTIVITY)) > MATERIAL_PROPERTY_MAX / 2 + +/datum/material_property/derived/beauty/get_value(datum/material/material) + // Requires the material to be especially shiny or dull + var/reflectivity = material.get_property(MATERIAL_REFLECTIVITY) + return MATERIAL_PROPERTY_DIVERGENCE(reflectivity, 3, 6) * 0.05 diff --git a/code/datums/materials/properties/optional.dm b/code/datums/materials/properties/optional.dm new file mode 100644 index 00000000000..8982e0d5e7c --- /dev/null +++ b/code/datums/materials/properties/optional.dm @@ -0,0 +1,89 @@ + +// Optional properties, not guaranteed to be present on all materials + +/// Minimum flammability value required to make an object made out of this material flammable +#define MINIMUM_FLAMMABILITY 4 + +/// If a material has this property, it is flammable and has reduced fire protection. +/datum/material_property/flammability + name = "Flammability" + id = MATERIAL_FLAMMABILITY + +/datum/material_property/flammability/get_descriptor(value) + switch(value) + if (0) + return "fireproof" + if (0 to 1) + return "nonflammable" + if (1 to 2) + return "mostly nonflammable" + if (2 to 3) + return "slightly fire-resistant" + if (3 to 4) + return "flammable" + if (4 to 6) + return "highly flammable" + if (6 to 8) + return "extremely flammable" + if (8 to INFINITY) + return "insanely flammable" + +/datum/material_property/flammability/attach_to(datum/material/material) + . = ..() + RegisterSignal(material, COMSIG_MATERIAL_APPLIED, PROC_REF(on_applied)) + RegisterSignal(material, COMSIG_MATERIAL_REMOVED, PROC_REF(on_removed)) + +/datum/material_property/flammability/proc/on_applied(datum/material/source, atom/new_atom, mat_amount, multiplier) + SIGNAL_HANDLER + + if (isobj(new_atom) && (new_atom.material_flags & MATERIAL_AFFECT_STATISTICS) && source.get_property(id) > MINIMUM_FLAMMABILITY) + new_atom.resistance_flags |= FLAMMABLE + +/datum/material_property/flammability/proc/on_removed(datum/material/source, atom/old_atom, mat_amount, multiplier) + SIGNAL_HANDLER + + if (isobj(old_atom) && (old_atom.material_flags & MATERIAL_AFFECT_STATISTICS) && source.get_property(id) > MINIMUM_FLAMMABILITY && !(initial(old_atom.resistance_flags) & FLAMMABLE)) + old_atom.resistance_flags &= ~FLAMMABLE + +#undef MINIMUM_FLAMMABILITY + +// An average value of 4 would equate to URANIUM_IRRADIATION_CHANCE radioactivity +#define URANIUM_RADIOACTIVITY 4 + +/datum/material_property/radioactivity + name = "Radioactivity" + id = MATERIAL_RADIOACTIVITY + +/datum/material_property/radioactivity/get_descriptor(value) + switch(value) + if (0) + return null + if (0 to 2) + return "slightly radioactive" + if (2 to 4) + return "radioactive" + if (4 to 6) + return "highly radioactive" + if (6 to 8) + return "extremely radioactive" + if (8 to INFINITY) + return "insanely radioactive" + +/datum/material_property/radioactivity/attach_to(datum/material/material) + . = ..() + RegisterSignal(material, COMSIG_MATERIAL_APPLIED, PROC_REF(on_applied)) + RegisterSignal(material, COMSIG_MATERIAL_REMOVED, PROC_REF(on_removed)) + +/datum/material_property/radioactivity/proc/on_applied(datum/material/source, atom/new_atom, mat_amount, multiplier) + SIGNAL_HANDLER + // Uranium structures should irradiate, but not items, because item irradiation is a lot more annoying. + if (!isitem(new_atom)) + new_atom.AddElement(/datum/element/radioactive, chance = source.get_property(id) / URANIUM_RADIOACTIVITY * URANIUM_IRRADIATION_CHANCE * multiplier) + +/datum/material_property/radioactivity/proc/on_removed(datum/material/source, atom/old_atom, mat_amount, multiplier) + SIGNAL_HANDLER + + if (!isitem(old_atom)) + old_atom.RemoveElement(/datum/element/radioactive, chance = source.get_property(id) / URANIUM_RADIOACTIVITY * URANIUM_IRRADIATION_CHANCE * multiplier) + +#undef URANIUM_RADIOACTIVITY diff --git a/code/datums/materials/requirements/_requirement.dm b/code/datums/materials/requirements/_requirement.dm new file mode 100644 index 00000000000..2447add5960 --- /dev/null +++ b/code/datums/materials/requirements/_requirement.dm @@ -0,0 +1,62 @@ +/// A datum holding a set of flags or minimum/maximum properties to decide which materials can be used in a design +/datum/material_requirement + abstract_type = /datum/material_requirement + /// Flags which materials need to have to pass + var/required_flags = NONE + /// Minimum property values that materials need to have to pass + var/list/property_minimums = null + /// Maximum property values that materials need to have to pass + var/list/property_maximums = null + +/// Returns a string description of materials that'd fit this requirement +/datum/material_requirement/proc/get_description() + var/list/flag_strings = list() + for (var/flag in bitfield_to_list(required_flags)) + flag_strings += GLOB.material_flags_to_string[flag] + if (!length(property_minimums) && !length(property_maximums)) + return "[capitalize(english_list(flag_strings, and_text = " or "))] material" + + var/list/prop_reqs = list() + for (var/prop_id in (property_minimums || list()) | (property_maximums || list())) + var/datum/material_property/property = SSmaterials.properties[prop_id] + if (property_minimums && property_maximums && !isnull(property_minimums[prop_id]) && !isnull(property_maximums[prop_id])) + prop_reqs += "[LOWER_TEXT(property.name)] between [property_minimums[prop_id]] and [property_maximums[prop_id]]" + else if (property_minimums && !isnull(property_minimums[prop_id])) + prop_reqs += "[LOWER_TEXT(property.name)] equal to or above [property_minimums[prop_id]]" + else + prop_reqs += "[LOWER_TEXT(property.name)] equal to or below [property_maximums[prop_id]]" + + return "[capitalize(english_list(flag_strings, and_text = " or "))] material with [english_list(prop_reqs)]" + +/datum/material_requirement/proc/valid_material(datum/material/material) + if (required_flags > 0 && !(material.mat_flags & required_flags)) + return FALSE + + if (required_flags < 0 && (material.mat_flags & (-required_flags))) + return FALSE + + for (var/prop_id, min_val in property_minimums) + if (material.get_property(prop_id) < min_val) + return FALSE + for (var/prop_id, max_val in property_maximums) + if (material.get_property(prop_id) > max_val) + return FALSE + return TRUE + +// Actual requirement datums +/datum/material_requirement/armor_material + required_flags = ITEM_MATERIAL_CLASSES + property_minimums = list( + MATERIAL_HARDNESS = 2, + ) + property_maximums = list( + MATERIAL_FLEXIBILITY = 5, + ) + +/datum/material_requirement/solid_material + property_minimums = list( + MATERIAL_HARDNESS = 2, + ) + +/datum/material_requirement/rigid_material + required_flags = MATERIAL_CLASS_RIGID diff --git a/code/game/atom/atom_examine.dm b/code/game/atom/atom_examine.dm index 7b6260758d0..a19b83ad84d 100644 --- a/code/game/atom/atom_examine.dm +++ b/code/game/atom/atom_examine.dm @@ -114,7 +114,7 @@ return var/mats_list = list() for(var/custom_material in custom_materials) - var/datum/material/current_material = GET_MATERIAL_REF(custom_material) + var/datum/material/current_material = SSmaterials.get_material(custom_material) mats_list += span_tooltip("It is made out of [current_material.name].", current_material.name) . += "made of [english_list(mats_list)]" @@ -134,6 +134,23 @@ SEND_SIGNAL(src, COMSIG_ATOM_EXAMINE_MORE, user, .) SEND_SIGNAL(user, COMSIG_MOB_EXAMINING_MORE, src, .) + if (!length(custom_materials) || (material_flags & MATERIAL_NO_DESCRIPTORS) || !HAS_TRAIT(user, TRAIT_RESEARCH_SCANNER)) + return + + for (var/datum/material/material as anything in custom_materials) + var/list/material_string = list() + for (var/prop_id in material.mat_properties) + var/datum/material_property/property = SSmaterials.properties[prop_id] + var/prop_value = material.get_property(prop_id) + if (isnull(prop_value)) // Error? + continue + var/descriptor = property?.get_descriptor(prop_value) + if (descriptor) // Overriden derivative property? + material_string += span_tooltip("[property]: [prop_value < 0 ? "-" : ""]\Roman[round(abs(prop_value), 1)]", descriptor) + + if (length(material_string)) + . += span_info("[capitalize(material.name)] is [english_list(material_string)].") + /** * Get the name of this object for examine * diff --git a/code/game/atom/atom_materials.dm b/code/game/atom/atom_materials.dm index a4200fd418f..16153284345 100644 --- a/code/game/atom/atom_materials.dm +++ b/code/game/atom/atom_materials.dm @@ -10,7 +10,8 @@ /// 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. + // Easy way to know no changes are being made. + if((custom_materials == materials) && multiplier == 1) return var/replace_mats = length(materials) @@ -55,7 +56,7 @@ var/list/material_effects = get_material_effects_list(materials) finalize_material_effects(material_effects) - custom_materials = SSmaterials.FindOrCreateMaterialCombo(materials) + custom_materials = SSmaterials.get_material_set_cache(materials) /// Proc responsible for removing material effects when setting materials. /atom/proc/remove_material_effects(replace_mats = TRUE) @@ -74,7 +75,7 @@ var/list/material_effects = list() var/index = 1 for(var/current_material in materials) - var/datum/material/material = GET_MATERIAL_REF(current_material) + var/datum/material/material = SSmaterials.get_material(current_material) material_effects[material] = list( MATERIAL_LIST_OPTIMAL_AMOUNT = OPTIMAL_COST(materials[current_material] * material_modifier), MATERIAL_LIST_MULTIPLIER = get_material_multiplier(material, materials, index), @@ -92,7 +93,7 @@ * be 1 if below 1. Just don't return negative values. */ /atom/proc/get_material_multiplier(datum/material/custom_material, list/materials, index) - return 1/length(materials) + return 1 / length(materials) ///Called by apply_material_effects(). It ACTUALLY handles applying effects common to all atoms (depending on material flags) /atom/proc/finalize_material_effects(list/materials) @@ -116,8 +117,6 @@ gather_material_color(custom_material, colors, mat_amount, multicolor = mat_length > 1) var/added_alpha = custom_material.alpha * (custom_material.alpha / 255) total_alpha += GET_MATERIAL_MODIFIER(added_alpha, multiplier) - if(custom_material.beauty_modifier) - AddElement(/datum/element/beauty, custom_material.beauty_modifier * mat_amount) apply_main_material_effects(main_material, main_mat_amount, main_mat_mult) @@ -213,28 +212,37 @@ if(!config_type) return for(var/datum/greyscale_config/path as anything in subtypesof(config_type)) - if(mat_type != initial(path.material_skin)) - continue - return path + if(mat_type == initial(path.material_skin)) + return path ///Apply material effects of a single material. /atom/proc/apply_single_mat_effect(datum/material/material, amount, multiplier) SHOULD_CALL_PARENT(TRUE) + + var/beauty_modifier = material.get_property(MATERIAL_BEAUTY) + if(beauty_modifier) + AddElement(/datum/element/beauty, beauty_modifier * amount) + if(beauty_modifier >= 0.15 && HAS_TRAIT(src, TRAIT_FISHING_BAIT)) + AddElement(/datum/element/shiny_bait) + if(!(material_flags & MATERIAL_AFFECT_STATISTICS) || !uses_integrity) return - var/integrity_mod = GET_MATERIAL_MODIFIER(material.integrity_modifier, multiplier) + + var/base_modifier = material.get_property(MATERIAL_INTEGRITY) + var/integrity_mod = GET_MATERIAL_MODIFIER(base_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) +/atom/proc/apply_main_material_effects(datum/material/main_material, amount, multiplier) SHOULD_CALL_PARENT(TRUE) - if(main_material.texture_layer_icon_state && material_flags & MATERIAL_COLOR) + + if(main_material.texture_layer_icon_state && (material_flags & MATERIAL_COLOR)) ADD_KEEP_TOGETHER(src, MATERIAL_SOURCE(main_material)) add_filter("material_texture_[main_material.name]", 1, layering_filter(icon = main_material.cached_texture_filter_icon, blend_mode = BLEND_INSET_OVERLAY)) - main_material.on_main_applied(src, amount, multipier) + main_material.on_main_applied(src, amount, multiplier) ///Called by remove_material_effects(). It ACTUALLY handles removing effects common to all atoms (depending on material flags) /atom/proc/finalize_remove_material_effects(list/materials) @@ -255,8 +263,6 @@ custom_material.on_removed(src, mat_amount, multiplier) if(material_flags & MATERIAL_COLOR) gather_material_color(custom_material, colors, mat_amount, multicolor = mat_length > 1) - if(custom_material.beauty_modifier) - RemoveElement(/datum/element/beauty, custom_material.beauty_modifier * mat_amount) remove_main_material_effects(main_material, main_mat_amount, main_mat_mult) @@ -271,16 +277,36 @@ if(material_flags & MATERIAL_ADD_PREFIX) name = initial(name) + // Ensure that we restore armor zero'd out by zero multipliers, as we don't have anything to go off other than our initial values + if((material_flags & MATERIAL_AFFECT_STATISTICS) && uses_integrity && initial(armor_type)) + var/datum/armor/inital_armor = get_armor_by_type(initial(armor_type)) + for (var/armor_id in ARMOR_LIST_ALL) + var/initial_rating = inital_armor.get_rating(armor_id) + if (get_armor_rating(armor_id) == 0 && initial_rating != 0) + set_armor_rating(armor_id, initial_rating) + 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/material, amount, multiplier) SHOULD_CALL_PARENT(TRUE) + + var/beauty_modifier = material.get_property(MATERIAL_BEAUTY) + if(beauty_modifier) + RemoveElement(/datum/element/beauty, beauty_modifier * amount) + if(beauty_modifier >= 0.15 && HAS_TRAIT(src, TRAIT_FISHING_BAIT)) + RemoveElement(/datum/element/shiny_bait) + if(!(material_flags & MATERIAL_AFFECT_STATISTICS) || !uses_integrity) return - var/integrity_mod = GET_MATERIAL_MODIFIER(material.integrity_modifier, multiplier) + + var/base_modifier = material.get_property(MATERIAL_INTEGRITY) + var/integrity_mod = GET_MATERIAL_MODIFIER(base_modifier, multiplier) modify_max_integrity(floor(max_integrity / integrity_mod)) - var/list/armor_mods = material.get_armor_modifiers(1 / multiplier) + var/list/armor_mods = material.get_armor_modifiers(multiplier) + for (var/armor_type, value in armor_mods) + if (value != 0) // Needs to be restored to initial values in finalize effects, sorry + armor_mods[armor_type] = 1 / value set_armor(get_armor().generate_new_with_multipliers(armor_mods)) ///A proc to remove the material effects previously applied by the (ex-)main material @@ -323,7 +349,7 @@ var/list/cached_materials = custom_materials for(var/mat in cached_materials) - var/datum/material/material = GET_MATERIAL_REF(mat) + var/datum/material/material = SSmaterials.get_material(mat) var/list/material_comp = material.return_composition(cached_materials[mat], flags) for(var/comp_mat in material_comp) .[comp_mat] += material_comp[comp_mat] @@ -344,60 +370,23 @@ for(var/current_material in cached_materials) if(cached_materials[current_material] < mat_amount) continue - var/datum/material/material = GET_MATERIAL_REF(current_material) + var/datum/material/material = SSmaterials.get_material(current_material) if(!istype(material, required_material)) continue LAZYSET(materials_of_type, material, cached_materials[current_material]) return materials_of_type -/** - * 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 - - var/materials_of_category - for(var/current_material in cached_materials) - if(cached_materials[current_material] < mat_amount) - continue - var/datum/material/material = GET_MATERIAL_REF(current_material) - 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 - LAZYSET(materials_of_category, material, cached_materials[current_material]) - return materials_of_category - -/** - * Gets the most common material in the object. - */ +/// Gets the most common material in the object. /atom/proc/get_master_material() - return length(custom_materials) ? GET_MATERIAL_REF(custom_materials[1]) : null //materials are sorted by amount, the first is always the main one + return length(custom_materials) ? SSmaterials.get_material(custom_materials[1]) : null //materials are sorted by amount, the first is always the main one -/** - * Gets the total amount of materials in this atom. - */ +/// Gets the total amount of materials in this atom. /atom/proc/get_custom_material_amount() return isnull(custom_materials) ? 0 : counterlist_sum(custom_materials) - -///A simple proc that iterates through each material that the object is made of and spawns some stacks based on their amount and associated sheet/ore type. -/atom/proc/drop_costum_materials(multiplier = 1) +/// A simple proc that iterates through each material that the object is made of and spawns some stacks based on their amount and associated sheet/ore type. +/atom/proc/drop_custom_materials(multiplier = 1) for(var/datum/material/material as anything in custom_materials) var/stack_type = material.sheet_type || material.ore_type if(!stack_type) diff --git a/code/game/atom/atom_vv.dm b/code/game/atom/atom_vv.dm index 176ee8e5248..14e20d23b9d 100644 --- a/code/game/atom/atom_vv.dm +++ b/code/game/atom/atom_vv.dm @@ -91,7 +91,7 @@ if(result["button"] == 2) // If the user pressed the cancel button return - var/list/armor_all = ARMOR_LIST_ALL() + var/list/armor_all = ARMOR_LIST_ALL // text2num conveniently returns a null on invalid values var/list/converted = list() for(var/armor_key in armor_all) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 58800d06398..ef6e24e2d83 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -36,7 +36,7 @@ print_sound = new(src, FALSE) materials = new ( \ src, \ - SSmaterials.materials_by_category[MAT_CATEGORY_ITEM_MATERIAL], \ + SSmaterials.flat_materials, \ 0, \ MATCONTAINER_EXAMINE|MATCONTAINER_ACCEPT_ALLOYS, \ container_signals = list(COMSIG_MATCONTAINER_ITEM_CONSUMED = TYPE_PROC_REF(/obj/machinery/autolathe, AfterMaterialInsert)) \ @@ -151,16 +151,21 @@ var/coeff = (ispath(design.build_path, /obj/item/stack) ? 1 : creation_efficiency) var/list/cost = list() var/customMaterials = FALSE - for(var/i in design.materials) - var/datum/material/mat = i - - var/design_cost = OPTIMAL_COST(design.materials[i] * coeff) + for(var/datum/material/mat as anything in design.materials) + var/mat_cost = design.materials[mat] + var/design_cost = OPTIMAL_COST(mat_cost * coeff) if(istype(mat)) cost[mat.name] = design_cost customMaterials = FALSE - else - cost[i] = design_cost - customMaterials = TRUE + continue + + var/datum/material_requirement/requirement = SSmaterials.requirements[mat] + if (!requirement) + stack_trace("Design [design] has an invalid material requirement [requirement]") + continue + + cost[requirement.get_description()] = design_cost + customMaterials = TRUE //create & send ui data var/icon_size = spritesheet.icon_size_id(design.id) @@ -215,11 +220,13 @@ if(action != "make") stack_trace("unknown autolathe ui_act: [action]") return + if(disabled) say("Unable to print, voltage mismatch in internal wiring.") return + if(busy) - say("currently printing.") + say("Currently printing.") return //validate design @@ -248,32 +255,38 @@ return build_count = clamp(build_count, 1, 50) - //check for materials required. For custom material items decode their required materials + // Check for materials required. For custom material items decode their required materials var/list/materials_needed = list() - for(var/material in design.materials) - var/amount_needed = design.materials[material] - if(istext(material)) // category - var/list/choices = list() - for(var/datum/material/valid_candidate as anything in SSmaterials.materials_by_category[material]) - if(materials.get_material_amount(valid_candidate) < (amount_needed + materials_needed[material])) - continue + var/mat_choice = FALSE + for(var/material, amount_needed in design.materials) + if(!ispath(material, /datum/material_requirement)) // Material requirement + if(!istype(material, /datum/material)) + CRASH("Autolathe ui_act got passed an invalid material id: [material]") + materials_needed[material] += amount_needed + continue + + var/list/choices = list() + for(var/datum/material/valid_candidate as anything in SSmaterials.get_materials_by_req(material)) + if(materials.get_material_amount(valid_candidate) >= (amount_needed + materials_needed[valid_candidate])) choices[valid_candidate.name] = valid_candidate - if(!length(choices)) - say("No valid materials with applicable amounts detected for design.") - return - var/chosen = tgui_input_list( - ui.user, - "Select the material to use", - "Material Selection", - sort_list(choices), - ) - if(isnull(chosen)) - return // user cancelled - material = choices[chosen] + + if(!length(choices)) + say("No valid materials with applicable amounts detected for design.") + return + + var/chosen = tgui_input_list( + ui.user, + "Select the material to use", + "Material Selection", + sort_list(choices), + ) + if(isnull(chosen)) + return // user cancelled + + material = choices[chosen] if(isnull(material)) - stack_trace("got passed an invalid material id: [material]") - return + CRASH("A player chose an invalid custom material in autolathe ui_act: [material]") materials_needed[material] += amount_needed //checks for available materials @@ -284,8 +297,9 @@ //compute power & time to print 1 item var/charge_per_item = 0 - for(var/material in design.materials) - charge_per_item += design.materials[material] + for(var/material, amount in design.materials) + charge_per_item += amount + charge_per_item = ROUND_UP((charge_per_item / (MAX_STACK_SIZE * SHEET_MATERIAL_AMOUNT)) * material_cost_coefficient * active_power_usage) var/build_time_per_item = (design.construction_time * design.lathe_time_factor) ** 0.8 @@ -304,7 +318,7 @@ target_location = get_turf(src) //give achievement for using unique material - if(design.materials[MAT_CATEGORY_ITEM_MATERIAL]) + if(mat_choice) for(var/datum/material/material in materials_needed) if(!istype(material, /datum/material/glass) && !istype(material, /datum/material/iron)) ui.user.client.give_award(/datum/award/achievement/misc/getting_an_upgrade, ui.user) @@ -364,24 +378,20 @@ var/max_stack_amount = initial(stack_item.max_amount) var/number_to_make = (initial(stack_item.amount) * items_remaining) while(number_to_make > max_stack_amount) - created = new stack_item(null, max_stack_amount) //it's imporant to spawn things in nullspace, since obj's like stacks qdel when they enter a tile/merge with other stacks of the same type, resulting in runtimes. + created = design.create_result(target, materials_needed, amount = max_stack_amount) if(isitem(created)) created.pixel_x = created.base_pixel_x + rand(-6, 6) created.pixel_y = created.base_pixel_y + rand(-6, 6) - created.forceMove(target) number_to_make -= max_stack_amount - - created = new stack_item(null, number_to_make) - + created = design.create_result(target, materials_needed, amount = number_to_make) else - created = new design.build_path(null) + created = design.create_result(target, materials_needed) split_materials_uniformly(materials_needed, material_cost_coefficient, created) if(isitem(created)) created.pixel_x = created.base_pixel_x + rand(-6, 6) created.pixel_y = created.base_pixel_y + rand(-6, 6) SSblackbox.record_feedback("nested tally", "lathe_printed_items", 1, list("[type]", "[created.type]")) - created.forceMove(target) if(is_stack) items_remaining = 0 @@ -483,10 +493,10 @@ mat_capacity += new_matter_bin.tier * (37.5*SHEET_MATERIAL_AMOUNT) materials.max_amount = mat_capacity - var/efficiency=1.8 + var/efficiency = 1.8 for(var/datum/stock_part/servo/new_servo in component_parts) efficiency -= new_servo.tier * 0.2 - creation_efficiency = max(1,efficiency) // creation_efficiency goes 1.6 -> 1.4 -> 1.2 -> 1 per level of servo efficiency + creation_efficiency = max(1, round(efficiency, 0.1)) // creation_efficiency goes 1.6 -> 1.4 -> 1.2 -> 1 per level of servo efficiency /** * Cut a wire in the autolathe diff --git a/code/game/machinery/fat_sucker.dm b/code/game/machinery/fat_sucker.dm index 0652ab1605e..0301aef0bf3 100644 --- a/code/game/machinery/fat_sucker.dm +++ b/code/game/machinery/fat_sucker.dm @@ -183,11 +183,11 @@ while(nutrients >= nutrient_to_meat) nutrients -= nutrient_to_meat var/atom/meat = new C.type_of_meat (drop_location()) - meat.set_custom_materials(list(GET_MATERIAL_REF(/datum/material/meat/mob_meat, C) = SHEET_MATERIAL_AMOUNT * 4)) + meat.set_custom_materials(list(SSmaterials.get_material(/datum/material/meat/mob_meat, C) = SHEET_MATERIAL_AMOUNT * 4)) while(nutrients >= nutrient_to_meat / 3) nutrients -= nutrient_to_meat / 3 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(SHEET_MATERIAL_AMOUNT * (4/3)))) + meat.set_custom_materials(list(SSmaterials.get_material(/datum/material/meat/mob_meat, C) = round(SHEET_MATERIAL_AMOUNT * (4/3)))) nutrients = 0 /obj/machinery/fat_sucker/screwdriver_act(mob/living/user, obj/item/I) diff --git a/code/game/machinery/flatpacker.dm b/code/game/machinery/flatpacker.dm index 563d74c23f5..50490abef60 100644 --- a/code/game/machinery/flatpacker.dm +++ b/code/game/machinery/flatpacker.dm @@ -35,7 +35,7 @@ materials = new ( \ src, \ - SSmaterials.materials_by_category[MAT_CATEGORY_SILO], \ + SSmaterials.get_materials_by_flag(MATERIAL_SILO_STORED), \ 0, \ MATCONTAINER_EXAMINE, \ container_signals = list(COMSIG_MATCONTAINER_ITEM_CONSUMED = TYPE_PROC_REF(/obj/machinery/flatpacker, AfterMaterialInsert)) \ @@ -159,7 +159,7 @@ var/efficiency = initial(creation_efficiency) for(var/datum/stock_part/micro_laser/laser in component_parts) efficiency -= laser.tier * 0.2 - creation_efficiency = max(1.2, efficiency) + creation_efficiency = max(1.2, round(efficiency, 0.1)) /obj/machinery/flatpacker/proc/AfterMaterialInsert(container, obj/item/item_inserted, last_inserted_id, mats_consumed, amount_inserted, atom/context) SIGNAL_HANDLER diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 9ce642b513f..de28621888b 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -21,7 +21,7 @@ /obj/machinery/recycler/Initialize(mapload) materials = new ( src, \ - SSmaterials.materials_by_category[MAT_CATEGORY_SILO], \ + SSmaterials.get_materials_by_flag(MATERIAL_SILO_STORED), \ INFINITY, \ MATCONTAINER_NO_INSERT \ ) diff --git a/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm b/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm index 0b1e620abdc..7035e301f4d 100644 --- a/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm +++ b/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm @@ -36,7 +36,7 @@ /datum/dimension_theme/New() if (material) - var/datum/material/using_mat = GET_MATERIAL_REF(material) + var/datum/material/using_mat = SSmaterials.get_material(material) window_colour = using_mat.color /** @@ -230,7 +230,7 @@ /datum/dimension_theme/proc/apply_materials(turf/affected_turf) PROTECTED_PROC(TRUE) - var/list/custom_materials = list(GET_MATERIAL_REF(material) = SHEET_MATERIAL_AMOUNT) + var/list/custom_materials = list(SSmaterials.get_material(material) = SHEET_MATERIAL_AMOUNT) if (istype(affected_turf, /turf/open/floor/material) || istype(affected_turf, /turf/closed/wall/material)) affected_turf.set_custom_materials(custom_materials) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 4d4d8868645..92c916b02bc 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1013,14 +1013,26 @@ return SEND_SIGNAL(src, COMSIG_ITEM_MICROWAVE_ACT, microwave_source, microwaver, randomize_pixel_offset) ///Used to check for extra requirements for blending(grinding or juicing) an object -/obj/item/proc/blend_requirements(obj/machinery/reagentgrinder/R) +/obj/item/proc/blend_requirements(atom/movable/grinder, mob/living/user) return TRUE ///Returns a reagent list containing the reagents this item produces when ground up in a grinder /obj/item/proc/grind_results() RETURN_TYPE(/list/datum/reagent) + if (!length(custom_materials) || (material_flags & MATERIAL_NO_REAGENTS)) + return null - return null + . = list() + for (var/mat_id, amount in custom_materials) + var/datum/material/material = SSmaterials.get_material(mat_id) + if (!material.material_reagent) + continue + if (!islist(material.material_reagent)) + .[material.material_reagent] = .[material.material_reagent] + amount * MATERIAL_REAGENTS_PER_SHEET / SHEET_MATERIAL_AMOUNT + continue + for (var/reagent_type in material.material_reagent) + .[reagent_type] = .[reagent_type] + amount * material.material_reagent[reagent_type] / length(material.material_reagent) * MATERIAL_REAGENTS_PER_SHEET / SHEET_MATERIAL_AMOUNT + return . ///Called BEFORE the object is ground up - use this to change grind results based on conditions. Return "-1" to prevent the grinding from occurring /obj/item/proc/on_grind() @@ -1392,7 +1404,7 @@ 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[GET_MATERIAL_REF(/datum/material/glass)] >= total_material_amount * 0.60) + if(custom_materials[SSmaterials.get_material(/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) @@ -1930,9 +1942,9 @@ return TRUE return FALSE -/obj/item/apply_main_material_effects(datum/material/main_material, amount, multipier) +/obj/item/apply_main_material_effects(datum/material/main_material, amount, multiplier) . = ..() - if(material_flags & MATERIAL_GREYSCALE) + if (material_flags & MATERIAL_GREYSCALE) var/main_mat_type = main_material.type var/worn_path = get_material_greyscale_config(main_mat_type, greyscale_config_worn) var/lefthand_path = get_material_greyscale_config(main_mat_type, greyscale_config_inhand_left) @@ -1942,8 +1954,16 @@ new_inhand_left = lefthand_path, new_inhand_right = righthand_path ) - if(!main_material.item_sound_override) + + if ((material_flags & MATERIAL_AFFECT_STATISTICS) && !(material_flags & MATERIAL_NO_SLOWDOWN)) + var/flexibility = main_material.get_property(MATERIAL_FLEXIBILITY) + // If the item applies slowdown only when worn, poor flexibility will increase our slowdown + if (!(item_flags & SLOWS_WHILE_IN_HAND) && flexibility < 6) + slowdown = max(slowdown >= 0 ? 0 : slowdown, slowdown + (flexibility - 6) * 0.025 * multiplier) + + if (!main_material.item_sound_override) return + hitsound = main_material.item_sound_override usesound = main_material.item_sound_override mob_throw_hit_sound = main_material.item_sound_override @@ -1951,16 +1971,24 @@ pickup_sound = main_material.item_sound_override drop_sound = main_material.item_sound_override -/obj/item/remove_main_material_effects(datum/material/main_material, amount, multipier) +/obj/item/remove_main_material_effects(datum/material/main_material, amount, multiplier) . = ..() - if(material_flags & MATERIAL_GREYSCALE) + if (material_flags & MATERIAL_GREYSCALE) set_greyscale( new_worn_config = initial(greyscale_config_worn), new_inhand_left = initial(greyscale_config_inhand_left), new_inhand_right = initial(greyscale_config_inhand_right) ) - if(!main_material.item_sound_override) + + if ((material_flags & MATERIAL_AFFECT_STATISTICS) && !(material_flags & MATERIAL_NO_SLOWDOWN)) + var/flexibility = main_material.get_property(MATERIAL_FLEXIBILITY) + // If the item applies slowdown only when worn, poor flexibility will increase our slowdown + if (!(item_flags & SLOWS_WHILE_IN_HAND) && flexibility < 6) + slowdown = min(initial(slowdown), slowdown - (flexibility - 6) * 0.025 * multiplier) + + if (!main_material.item_sound_override) return + hitsound = initial(hitsound) usesound = initial(usesound) mob_throw_hit_sound = initial(mob_throw_hit_sound) @@ -1970,15 +1998,132 @@ /obj/item/apply_single_mat_effect(datum/material/material, mat_amount, multiplier) . = ..() - if(!(material_flags & MATERIAL_AFFECT_STATISTICS) || (material_flags & MATERIAL_NO_SLOWDOWN) || !material.added_slowdown) + if (!(material_flags & MATERIAL_AFFECT_STATISTICS)) return - slowdown += GET_MATERIAL_MODIFIER(material.added_slowdown * mat_amount, multiplier) + + // [0 ~ 1] is fully insulating, (1 ~ 6] maps to (0 ~ 1] and [6 ~ 10] maps to [1 ~ 2] + // 1.18 and 0.15 here are to allow 6 to map to 1 and 10 to map to 2 and are pulled out of my ass (system in the desmos below) + // See https://www.desmos.com/calculator/rdbv1x8oty + var/conductivity = material.get_property(MATERIAL_ELECTRICAL) + var/siemens_modifier = round(max(0, conductivity - 1) ** 1.18 * 0.15, 0.01) + // Cannot use the base formula as it would make any item with glass not conduct electricity + if (siemens_modifier > 1) + siemens_coefficient *= 1 + (siemens_modifier - 1) * multiplier + else + siemens_coefficient *= max(0, 1 - (1 - siemens_modifier) * multiplier) + + if (siemens_coefficient == 0) + obj_flags &= ~CONDUCTS_ELECTRICITY + + if (material_flags & MATERIAL_NO_SLOWDOWN) + return + + // Density above 6 adds slowdown, density below 3 can reduce existing slowdown + var/density = material.get_property(MATERIAL_DENSITY) + var/slowdown_change = 0 + + if (density > 6) + slowdown_change = (density - 6) * MATERIAL_DENSITY_SLOWDOWN * mat_amount / SHEET_MATERIAL_AMOUNT + else if (density < 3) + slowdown_change = (3 - density) * -MATERIAL_DENSITY_SLOWDOWN * mat_amount / SHEET_MATERIAL_AMOUNT + + // Slowdown cannot be reduced below 0 if the item slows you down, or at all if the item speeds you up + if (slowdown_change) + slowdown = max(slowdown >= 0 ? 0 : slowdown, slowdown + slowdown_change * multiplier) /obj/item/remove_single_mat_effect(datum/material/material, mat_amount, multiplier) . = ..() - if(!(material_flags & MATERIAL_AFFECT_STATISTICS) || (material_flags & MATERIAL_NO_SLOWDOWN) || !material.added_slowdown) + if (!(material_flags & MATERIAL_AFFECT_STATISTICS)) return - slowdown -= GET_MATERIAL_MODIFIER(material.added_slowdown * mat_amount, multiplier) + + var/conductivity = material.get_property(MATERIAL_ELECTRICAL) + // 0 ~ 1 count as perfect insulators + var/siemens_modifier = round(max(conductivity - 1, 0) ** 1.18 * 0.15, 0.01) + // Cannot use the base formula as it would make any item with glass not conduct electricity + if (siemens_modifier > 1) + siemens_coefficient /= 1 + (siemens_modifier - 1) * multiplier + else + var/used_mult = 1 - (1 - siemens_modifier) * multiplier + if (used_mult > 0) // Perfect insulators need to be restored in finalize + siemens_coefficient /= used_mult + + if (siemens_coefficient > 0 && (initial(obj_flags) & CONDUCTS_ELECTRICITY) && !(obj_flags & CONDUCTS_ELECTRICITY)) + obj_flags |= CONDUCTS_ELECTRICITY + + if (material_flags & MATERIAL_NO_SLOWDOWN) + return + + var/density = material.get_property(MATERIAL_DENSITY) + var/slowdown_change = 0 + + if (density > 6) + slowdown_change = (density - 6) * MATERIAL_DENSITY_SLOWDOWN * mat_amount / SHEET_MATERIAL_AMOUNT + else if (density < 3) + slowdown_change = (3 - density) * -MATERIAL_DENSITY_SLOWDOWN * mat_amount / SHEET_MATERIAL_AMOUNT + + if (slowdown_change > 0) + slowdown -= slowdown_change * multiplier + else if (slowdown_change < 0) + // Not guaranteed to be correct if something modified our slowdown buuuut about as good as we can get + slowdown = min(initial(slowdown), slowdown - slowdown_change * multiplier) + +/obj/item/finalize_remove_material_effects(list/materials) + . = ..() + // If we were made from an insulator we cannot restore via division + if (initial(siemens_coefficient) != 0 && siemens_coefficient == 0) + siemens_coefficient = initial(siemens_coefficient) + if (siemens_coefficient > 0 && (initial(obj_flags) & CONDUCTS_ELECTRICITY) && !(obj_flags & CONDUCTS_ELECTRICITY)) + obj_flags |= CONDUCTS_ELECTRICITY + +/obj/item/change_material_strength(datum/material/material, mat_amount, multiplier, remove = FALSE) + var/density = material.get_property(MATERIAL_DENSITY) + var/hardness = material.get_property(MATERIAL_HARDNESS) + var/flexibility = material.get_property(MATERIAL_FLEXIBILITY) + + // Item force calculation depends on its initial (assumed to be main) sharpness + // Transforming component doesn't work with materials at all and will need a refactor to change that, so we don't care about it here. + + var/force_mod = 1 + var/throwforce_mod = 1 + + switch (sharpness) + if (NONE) + // Blunt items are really hurt by all the flexing + force_mod = (1 + (density - 4) * 0.1) / (1 + flexibility * 0.1) + throwforce_mod = 1 + (density - 4) * 0.1 - flexibility * 0.1 + + if (SHARP_EDGED) + // Sharp items don't care about density and need high hardness to get a real bonus, but can tolerate (and benefit from) some flex + force_mod = 1 + (hardness - 4) * 0.1 + throwforce_mod = 1 + (hardness - 4) * 0.1 + + // Peaks out at 20% at flexibility of 1, drops off up to -80% at 10 + if (flexibility < 2) + force_mod *= 1 + (1 - abs(1 - flexibility)) * 0.2 + throwforce_mod += (1 - abs(1 - flexibility)) * 0.2 + else + force_mod *= 1 - (flexibility - 2) * 0.1 + throwforce_mod -= (flexibility - 2) * 0.1 + + if (SHARP_POINTY) + // Pointy items care about both density and hardness + force_mod = 1 + MATERIAL_PROPERTY_DIVERGENCE(density, 4, 6) * 0.05 + (hardness - 4) * 0.1 + throwforce_mod = 1 + MATERIAL_PROPERTY_DIVERGENCE(density, 4, 6) * 0.05 * 0.05 + (hardness - 4) * 0.1 + // But are not affected by flexibility until higher values, although they don't benefit from it either + if (flexibility > 4) + force_mod *= (1 - (flexibility - 4) * 0.2) + throwforce_mod -= (flexibility - 4) * 0.2 + + // Just for sanity in case something breaks + force_mod = round(clamp(force_mod, MATERIAL_MIN_FORCE_MULTIPLIER, MATERIAL_MAX_FORCE_MULTIPLIER), 0.01) + throwforce_mod = round(clamp(throwforce_mod, MATERIAL_MIN_FORCE_MULTIPLIER, MATERIAL_MAX_FORCE_MULTIPLIER), 0.01) + + if (!remove) + force *= GET_MATERIAL_MODIFIER(force_mod, multiplier) + throwforce *= GET_MATERIAL_MODIFIER(throwforce_mod, multiplier) + else + force /= GET_MATERIAL_MODIFIER(force_mod, multiplier) + throwforce /= GET_MATERIAL_MODIFIER(throwforce_mod, multiplier) /** * Returns the atom(either itself or an internal module) that will interact/attack the target on behalf of us diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm index a278c02ce13..64d594b8baf 100644 --- a/code/game/objects/items/stacks/bscrystal.dm +++ b/code/game/objects/items/stacks/bscrystal.dm @@ -15,9 +15,6 @@ /// The teleport range when crushed/thrown at someone. var/blink_range = 8 -/obj/item/stack/ore/bluespace_crystal/grind_results() - return list(/datum/reagent/bluespace = 20) - /obj/item/stack/ore/bluespace_crystal/refined name = "refined bluespace crystal" points = 0 @@ -59,7 +56,7 @@ /obj/item/stack/ore/bluespace_crystal/artificial name = "artificial bluespace crystal" desc = "An artificially made bluespace crystal, it looks delicate." - mats_per_unit = list(/datum/material/bluespace=SHEET_MATERIAL_AMOUNT*0.5) + mats_per_unit = list(/datum/material/bluespace = HALF_SHEET_MATERIAL_AMOUNT) blink_range = 4 // Not as good as the organic stuff! points = 0 //nice try refined_type = null @@ -67,10 +64,7 @@ drop_sound = null //till I make a better one pickup_sound = null -/obj/item/stack/ore/bluespace_crystal/artificial/grind_results() - return list(/datum/reagent/bluespace = 10, /datum/reagent/silicon = 20) - -//Polycrystals, aka stacks +// Polycrystals, aka stacks /obj/item/stack/sheet/bluespace_crystal name = "bluespace polycrystal" icon = 'icons/obj/stack_objects.dmi' @@ -87,9 +81,6 @@ material_type = /datum/material/bluespace var/crystal_type = /obj/item/stack/ore/bluespace_crystal/refined -/obj/item/stack/sheet/bluespace_crystal/grind_results() - return list(/datum/reagent/bluespace = 20) - /obj/item/stack/sheet/bluespace_crystal/attack_self(mob/user)// to prevent the construction menu from ever happening to_chat(user, span_warning("You cannot crush the polycrystal in-hand, try breaking one off.")) diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index 038f8fde839..57288319c6a 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -38,9 +38,6 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \ fire = 50 acid = 100 -/obj/item/stack/sheet/glass/grind_results() - return list(/datum/reagent/silicon = 20) - /obj/item/stack/sheet/glass/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] begins to slice [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) return BRUTELOSS @@ -108,9 +105,6 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \ pickup_sound = 'sound/items/handling/materials/glass_pick_up.ogg' drop_sound = 'sound/items/handling/materials/glass_drop.ogg' -/obj/item/stack/sheet/plasmaglass/grind_results() - return list(/datum/reagent/silicon = 20, /datum/reagent/toxin/plasma = 10) - /obj/item/stack/sheet/plasmaglass/fifty amount = 50 @@ -171,7 +165,7 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \ drop_sound = 'sound/items/handling/materials/glass_drop.ogg' /obj/item/stack/sheet/rglass/grind_results() - return list(/datum/reagent/silicon = 20, /datum/reagent/iron = 10) + return list(/datum/reagent/silicon = 10, /datum/reagent/iron = 10) /obj/item/stack/sheet/rglass/fifty amount = 50 @@ -213,7 +207,7 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \ drop_sound = 'sound/items/handling/materials/glass_drop.ogg' /obj/item/stack/sheet/plasmarglass/grind_results() - return list(/datum/reagent/silicon = 20, /datum/reagent/toxin/plasma = 10, /datum/reagent/iron = 10) + return list(/datum/reagent/silicon = 10, /datum/reagent/toxin/plasma = 10, /datum/reagent/iron = 10) /datum/armor/sheet_plasmarglass melee = 20 diff --git a/code/game/objects/items/stacks/sheets/hot_ice.dm b/code/game/objects/items/stacks/sheets/hot_ice.dm index de42ef32e44..ab7ee22a8ca 100644 --- a/code/game/objects/items/stacks/sheets/hot_ice.dm +++ b/code/game/objects/items/stacks/sheets/hot_ice.dm @@ -8,9 +8,6 @@ material_type = /datum/material/hot_ice merge_type = /obj/item/stack/sheet/hot_ice -/obj/item/stack/sheet/hot_ice/grind_results() - return list(/datum/reagent/toxin/hot_ice = 25) - /obj/item/stack/sheet/hot_ice/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] begins licking \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) return FIRELOSS//dont you kids know that stuff is toxic? diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm index ca0585c6f9f..efa71586bdb 100644 --- a/code/game/objects/items/stacks/sheets/mineral.dm +++ b/code/game/objects/items/stacks/sheets/mineral.dm @@ -117,9 +117,6 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \ new/datum/stack_recipe("diamond tile", /obj/item/stack/tile/mineral/diamond, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) -/obj/item/stack/sheet/mineral/diamond/grind_results() - return list(/datum/reagent/carbon = 20) - /obj/item/stack/sheet/mineral/diamond/get_main_recipes() . = ..() . += GLOB.diamond_recipes @@ -151,9 +148,6 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \ new/datum/stack_recipe("uranium tile", /obj/item/stack/tile/mineral/uranium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) -/obj/item/stack/sheet/mineral/uranium/grind_results() - return list(/datum/reagent/uranium = 20) - /obj/item/stack/sheet/mineral/uranium/get_main_recipes() . = ..() . += GLOB.uranium_recipes @@ -184,9 +178,6 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \ material_type = /datum/material/plasma walltype = /turf/closed/wall/mineral/plasma -/obj/item/stack/sheet/mineral/plasma/grind_results() - return list(/datum/reagent/toxin/plasma = 20) - /obj/item/stack/sheet/mineral/plasma/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] begins licking \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) return TOXLOSS//dont you kids know that stuff is toxic? @@ -232,9 +223,6 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \ new/datum/stack_recipe("Simple Crown", /obj/item/clothing/head/costume/crown, 5, crafting_flags = NONE, category = CAT_CLOTHING), \ )) -/obj/item/stack/sheet/mineral/gold/grind_results() - return list(/datum/reagent/gold = 20) - /obj/item/stack/sheet/mineral/gold/get_main_recipes() . = ..() . += GLOB.gold_recipes @@ -264,9 +252,6 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \ new/datum/stack_recipe("silver tile", /obj/item/stack/tile/mineral/silver, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) -/obj/item/stack/sheet/mineral/silver/grind_results() - return list(/datum/reagent/silver = 20) - /obj/item/stack/sheet/mineral/silver/get_main_recipes() . = ..() . += GLOB.silver_recipes @@ -293,9 +278,6 @@ GLOBAL_LIST_INIT(bananium_recipes, list ( \ new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) -/obj/item/stack/sheet/mineral/bananium/grind_results() - return list(/datum/reagent/consumable/banana = 20) - /obj/item/stack/sheet/mineral/bananium/get_main_recipes() . = ..() . += GLOB.bananium_recipes @@ -417,9 +399,6 @@ GLOBAL_LIST_INIT(snow_recipes, list ( \ . = ..() AddComponent(/datum/component/storm_hating) -/obj/item/stack/sheet/mineral/snow/grind_results() - return list(/datum/reagent/consumable/ice = 20) - /obj/item/stack/sheet/mineral/snow/get_main_recipes() . = ..() . += GLOB.snow_recipes diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index f231a69cc35..16f0e675e55 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -188,9 +188,6 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ ) AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) -/obj/item/stack/sheet/iron/grind_results() - return list(/datum/reagent/iron = 20) - /obj/item/stack/sheet/iron/examine(mob/user) . = ..() . += span_notice("Right click on floor to build:") @@ -329,9 +326,6 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \ fire = 100 acid = 80 -/obj/item/stack/sheet/plasteel/grind_results() - return list(/datum/reagent/iron = 20, /datum/reagent/toxin/plasma = 20) - /obj/item/stack/sheet/plasteel/get_main_recipes() . = ..() . += GLOB.plasteel_recipes @@ -430,9 +424,6 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ /datum/armor/mineral_wood fire = 50 -/obj/item/stack/sheet/mineral/wood/grind_results() - return list(/datum/reagent/cellulose = 20) - /obj/item/stack/sheet/mineral/wood/get_main_recipes() . = ..() . += GLOB.wood_recipes @@ -498,9 +489,6 @@ GLOBAL_LIST_INIT(bamboo_recipes, list ( \ /datum/armor/mineral_bamboo fire = 50 -/obj/item/stack/sheet/mineral/bamboo/grind_results() - return list(/datum/reagent/cellulose = 10) - /obj/item/stack/sheet/mineral/bamboo/get_main_recipes() . = ..() . += GLOB.bamboo_recipes @@ -747,9 +735,6 @@ GLOBAL_LIST_INIT(cardboard_recipes, list ( \ slapcraft_recipes = slapcraft_recipe_list,\ ) -/obj/item/stack/sheet/cardboard/grind_results() - return list(/datum/reagent/cellulose = 10) - /obj/item/stack/sheet/cardboard/get_main_recipes() . = ..() . += GLOB.cardboard_recipes @@ -818,9 +803,6 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \ walltype = /turf/closed/wall/mineral/bronze has_unique_girder = TRUE -/obj/item/stack/sheet/bronze/grind_results() - return list(/datum/reagent/iron = 20, /datum/reagent/copper = 12) - /obj/item/stack/sheet/bronze/get_main_recipes() . = ..() . += GLOB.bronze_recipes @@ -891,9 +873,6 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \ slapcraft_recipes = slapcraft_recipe_list,\ ) -/obj/item/stack/sheet/bone/grind_results() - return list(/datum/reagent/carbon = 10) - GLOBAL_LIST_INIT(plastic_recipes, list( new /datum/stack_recipe("plastic floor tile", /obj/item/stack/tile/plastic, 1, 4, 20, time = 2 SECONDS, crafting_flags = NONE, category = CAT_TILES), \ new /datum/stack_recipe("light tram tile", /obj/item/stack/thermoplastic/light, 1, 4, 20, time = 2 SECONDS, crafting_flags = NONE, category = CAT_TILES), \ @@ -953,9 +932,6 @@ GLOBAL_LIST_INIT(paperframe_recipes, list( drop_sound = null pickup_sound = null -/obj/item/stack/sheet/paperframes/grind_results() - return list(/datum/reagent/cellulose = 20) - /obj/item/stack/sheet/paperframes/get_main_recipes() . = ..() . += GLOB.paperframe_recipes @@ -1024,9 +1000,6 @@ GLOBAL_LIST_INIT(pizza_sheet_recipes, list( material_type = /datum/material/hauntium material_modifier = 1 //None of that wussy stuff -/obj/item/stack/sheet/hauntium/grind_results() - return list(/datum/reagent/hauntium = 20) - /obj/item/stack/sheet/hauntium/fifty amount = 50 /obj/item/stack/sheet/hauntium/twenty diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm index bd50d1648e8..862d255133e 100644 --- a/code/game/objects/items/stacks/sheets/sheets.dm +++ b/code/game/objects/items/stacks/sheets/sheets.dm @@ -13,7 +13,7 @@ attack_verb_continuous = list("bashes", "batters", "bludgeons", "thrashes", "smashes") attack_verb_simple = list("bash", "batter", "bludgeon", "thrash", "smash") novariants = FALSE - material_flags = MATERIAL_EFFECTS + material_flags = MATERIAL_EFFECTS | MATERIAL_NO_DESCRIPTORS table_type = /obj/structure/table/greyscale pickup_sound = 'sound/items/handling/materials/metal_pick_up.ogg' drop_sound = 'sound/items/handling/materials/metal_drop.ogg' @@ -43,7 +43,24 @@ /obj/item/stack/sheet/examine(mob/user) . = ..() if (manufactured && gulag_valid) - . += "It has been embossed with a manufacturer's mark of guaranteed quality." + . += span_notice("It has been embossed with a manufacturer's mark of guaranteed quality.") + + var/datum/material/material = get_master_material() + if (!HAS_TRAIT(user, TRAIT_RESEARCH_SCANNER) || !material) + return + + var/list/material_string = list() + for (var/prop_id in material.mat_properties) + var/datum/material_property/property = SSmaterials.properties[prop_id] + var/prop_value = material.get_property(prop_id) + if (isnull(prop_value)) // Error? + continue + var/descriptor = property?.get_descriptor(prop_value) + if (descriptor) // Overriden derivative property? + material_string += span_tooltip("[property]: [prop_value < 0 ? "-" : ""]\Roman[round(abs(prop_value), 1)]", descriptor) + + if (length(material_string)) + . += span_info("[capitalize(material.name)] is [english_list(material_string)].") /obj/item/stack/sheet/add(_amount) . = ..() diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index cefc8aa6fa2..d6f12c38265 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -84,18 +84,16 @@ if(LAZYLEN(mat_override)) mats_per_unit = mat_override if(LAZYLEN(mats_per_unit)) - mats_per_unit = SSmaterials.FindOrCreateMaterialCombo(mats_per_unit, mat_amt) + mats_per_unit = SSmaterials.get_material_set_cache(mats_per_unit, mat_amt) initialize_materials(mats_per_unit, amount) recipes = get_main_recipes().Copy() if(material_type) - var/datum/material/what_are_we_made_of = GET_MATERIAL_REF(material_type) //First/main material - for(var/category in what_are_we_made_of.categories) - switch(category) - if(MAT_CATEGORY_BASE_RECIPES) - recipes |= SSmaterials.base_stack_recipes.Copy() - if(MAT_CATEGORY_RIGID) - recipes |= SSmaterials.rigid_stack_recipes.Copy() + var/datum/material/our_mat = SSmaterials.get_material(material_type) //First/main material + if (our_mat.mat_flags & MATERIAL_BASIC_RECIPES) + recipes |= SSmaterials.base_stack_recipes.Copy() + if (our_mat.mat_flags & MATERIAL_CLASS_RIGID) + recipes |= SSmaterials.rigid_stack_recipes.Copy() update_weight() update_appearance() @@ -156,11 +154,12 @@ other_stack = find_other_stack(already_found, TRUE) return TRUE -/obj/item/stack/blend_requirements() - if(is_cyborg) - to_chat(usr, span_warning("[src] is too integrated into your chassis and can't be ground up!")) - return - return TRUE +/obj/item/stack/blend_requirements(atom/movable/grinder, mob/living/user) + if(!is_cyborg) + return TRUE + if (user) + to_chat(user, span_warning("[src] is too integrated into your chassis and can't be ground up!")) + return FALSE /obj/item/stack/grind_atom(datum/reagents/target_holder, mob/user) var/current_amount = get_amount() @@ -179,7 +178,7 @@ total_volume += grind_reagents[reagent] //compute number of pieces(or sheets) from available_volume - var/available_amount = min(current_amount, round(available_volume / total_volume)) + var/available_amount = ceil(current_amount * min(1, available_volume / total_volume)) if(available_amount <= 0) return FALSE @@ -476,7 +475,7 @@ if(isstack(created)) var/obj/item/stack/crafted_stack = created - crafted_stack.mats_per_unit = SSmaterials.FindOrCreateMaterialCombo(result_mats) + crafted_stack.mats_per_unit = SSmaterials.get_material_set_cache(result_mats) update_custom_materials() else created.set_custom_materials(result_mats, recipe.req_amount * multiplier) diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 8310bffc8d5..227b601c784 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -249,16 +249,13 @@ // 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 * INVERSE_MEAT_STRENTGH - throwforce = 15 * INVERSE_MEAT_STRENTGH + force = 15 + throwforce = 15 material_flags = MATERIAL_EFFECTS | MATERIAL_AFFECT_STATISTICS attack_verb_continuous = list("MEATS", "MEAT MEATS") attack_verb_simple = list("MEAT", "MEAT MEAT") @@ -284,7 +281,10 @@ AddComponent(/datum/component/squeak, meat_sounds) -#undef INVERSE_MEAT_STRENTGH +/obj/item/storage/backpack/meat/change_material_strength(datum/material/material, mat_amount, multiplier, remove) + // Our base 15 force includes the implied meat force + if (!istype(material, /datum/material/meat)) + return ..() /* * Satchel Types diff --git a/code/game/objects/items/weaponry/melee/spear.dm b/code/game/objects/items/weaponry/melee/spear.dm index 3f7b0e1bfd7..00035afbc59 100644 --- a/code/game/objects/items/weaponry/melee/spear.dm +++ b/code/game/objects/items/weaponry/melee/spear.dm @@ -16,7 +16,7 @@ demolition_mod = 0.75 // Note: This is significant, as this needs to be low enough that any possible force adjustments from better spears does not go over airlock deflection. See AIRLOCK_DAMAGE_DEFLECTION_N. embed_type = /datum/embedding/spear armour_penetration = 5 - custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 0.65, /datum/material/glass= SHEET_MATERIAL_AMOUNT * 1.15) + custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 0.65, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 1.15) hitsound = 'sound/items/weapons/bladeslice.ogg' attack_verb_continuous = list("attacks", "pokes", "jabs", "tears", "lacerates", "gores") attack_verb_simple = list("attack", "poke", "jab", "tear", "lacerate", "gore") @@ -25,6 +25,7 @@ armor_type = /datum/armor/item_spear wound_bonus = -15 exposed_wound_bonus = 15 + material_flags = MATERIAL_EFFECTS /// The icon prefix for this flavor of spear var/icon_prefix = "spearglass" /// How much damage to do unwielded @@ -35,6 +36,8 @@ var/improvised_construction = TRUE /// What is left over when a spear breaks var/spear_leftovers = /obj/item/stack/rods + /// Material type from which our tip is made + var/tip_mat_type = null /// What pike do we construct if someone kills themselves with us? var/pike_type = /obj/structure/headpike @@ -101,81 +104,91 @@ return BRUTELOSS // Just in case they survived losing the head /obj/item/spear/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) + var/obj/item/stack/rods/rod = locate() in components + if (rod) + spear_leftovers = rod.type + var/obj/item/shard/tip = locate() in components - if(!tip) + if (!tip) return ..() - switch(tip.type) - if(/obj/item/shard/plasma) - force = 11 - throwforce = 21 + var/datum/material/tip_material = tip.get_master_material() + // For master material effects. As on_craft_completion is ran before set_custom_materials, this will allow the speartip to be treated as our master material no matter what + tip_mat_type = tip_material.id + switch (tip_mat_type) + if (/datum/material/alloy/plasmaglass) icon_prefix = "spearplasma" - modify_max_integrity(220) - wound_bonus = -10 - force_unwielded = 11 - force_wielded = 19 - AddComponent(/datum/component/two_handed, \ - force_unwielded = force_unwielded, \ - force_wielded = force_wielded, \ - icon_wielded = "[icon_prefix]1", \ - wield_callback = CALLBACK(src, PROC_REF(on_wield)), \ - unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \ - ) - - if(/obj/item/shard/titanium) - force = 12 - throwforce = 22 - throw_range = 8 - throw_speed = 5 - modify_max_integrity(230) - wound_bonus = -5 - force_unwielded = 12 - force_wielded = 20 - armour_penetration = 10 + if (/datum/material/alloy/titaniumglass) icon_prefix = "speartitanium" - AddComponent(/datum/component/two_handed, \ - force_unwielded = force_unwielded, \ - force_wielded = force_wielded, \ - icon_wielded = "[icon_prefix]1", \ - wield_callback = CALLBACK(src, PROC_REF(on_wield)), \ - unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \ - ) - - if(/obj/item/shard/plastitanium) - force = 13 - throwforce = 23 - throw_range = 9 - throw_speed = 5 - modify_max_integrity(240) - wound_bonus = 0 - exposed_wound_bonus = 20 - force_unwielded = 13 - force_wielded = 21 - armour_penetration = 15 + if (/datum/material/alloy/plastitaniumglass) icon_prefix = "spearplastitanium" - AddComponent(/datum/component/two_handed, \ - force_unwielded = force_unwielded, \ - force_wielded = force_wielded, \ - icon_wielded = "[icon_prefix]1", \ - wield_callback = CALLBACK(src, PROC_REF(on_wield)), \ - unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \ - ) - update_appearance() return ..() +/obj/item/spear/get_master_material() + if (tip_mat_type && custom_materials[tip_mat_type]) + return SSmaterials.get_material(tip_mat_type) + return ..() + +/obj/item/spear/apply_main_material_effects(datum/material/main_material, amount, multiplier) + . = ..() + var/density = main_material.get_property(MATERIAL_DENSITY) + var/hardness = main_material.get_property(MATERIAL_HARDNESS) + // If a spear is too hard its unwieldy, if it is too light it doesn't have enough weight behind it + var/force_change = (hardness - 4) - max(0, density - 4) - max(0, 4 - density) * 2 + force_unwielded += force_change + force_wielded += force_change + force = force_unwielded + throwforce += force_change + wound_bonus += force_change * 5 + modify_max_integrity(max_integrity + (hardness - 4) * 10) + throw_range += (hardness - 4) - (density - 4) * 2 + throw_speed += floor(((hardness - 4) - (density - 4) * 2) / 2) + // These try to keep parity with titanium/plastitanium spears as armorpen boost was exclusive to them + armour_penetration += MATERIAL_PROPERTY_DIVERGENCE(hardness, 4, 6) * 5 + exposed_wound_bonus += (MATERIAL_PROPERTY_DIVERGENCE(hardness, 4, 6) - (density - 4)) * 5 + AddComponent(/datum/component/two_handed, \ + force_unwielded = force_unwielded, \ + force_wielded = force_wielded, \ + icon_wielded = "[icon_prefix]1", \ + wield_callback = CALLBACK(src, PROC_REF(on_wield)), \ + unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \ + ) + +/obj/item/spear/remove_main_material_effects(datum/material/main_material, amount, multiplier) + . = ..() + var/density = main_material.get_property(MATERIAL_DENSITY) + var/hardness = main_material.get_property(MATERIAL_HARDNESS) + var/force_change = (hardness - 4) - (density - 4) + force_unwielded -= force_change + force_wielded -= force_change + force = force_unwielded + throwforce -= force_change + wound_bonus -= force_change * 5 + modify_max_integrity(max_integrity - (hardness - 4) * 10) + throw_range -= (hardness - 4) - (density - 4) * 2 + throw_speed -= floor(((hardness - 4) - (density - 4) * 2) / 2) + // These try to keep parity with titanium/plastitanium spears as armorpen boost was exclusive to them + armour_penetration -= MATERIAL_PROPERTY_DIVERGENCE(hardness, 4, 6) * 5 + exposed_wound_bonus -= (MATERIAL_PROPERTY_DIVERGENCE(hardness, 4, 6) - (density - 4)) * 5 + AddComponent(/datum/component/two_handed, \ + force_unwielded = force_unwielded, \ + force_wielded = force_wielded, \ + icon_wielded = "[icon_prefix]1", \ + wield_callback = CALLBACK(src, PROC_REF(on_wield)), \ + unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \ + ) + /obj/item/spear/afterattack(atom/target, mob/user, list/modifiers, list/attack_modifiers) - if(!improvised_construction) - return - take_damage(force/2, sound_effect = FALSE) + if(improvised_construction) + take_damage(force / 2, sound_effect = FALSE) /obj/item/spear/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) . = ..() if (.) //spear was caught return - if(!improvised_construction) - return - take_damage(throwforce/2, sound_effect = FALSE) + if(improvised_construction) + take_damage(throwforce / 2, sound_effect = FALSE) /obj/item/spear/atom_destruction(damage_flag) playsound(src, 'sound/effects/grillehit.ogg', 50) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 57b343934cf..88f8b247363 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -332,18 +332,30 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) . = ..() if(!(material_flags & MATERIAL_AFFECT_STATISTICS)) return - var/strength_mod = GET_MATERIAL_MODIFIER(material.strength_modifier, multiplier) - force *= strength_mod - throwforce *= strength_mod + change_material_strength(material, mat_amount, multiplier) -///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 - var/strength_mod = GET_MATERIAL_MODIFIER(material.strength_modifier, multiplier) - force /= strength_mod - throwforce /= strength_mod + change_material_strength(material, mat_amount, multiplier, remove = TRUE) + +/// Changes force and throwforce of an item based on its properties. Split into a separate proc as to allow items to change theirs based on sharpness and behavior +/obj/proc/change_material_strength(datum/material/material, mat_amount, multiplier, remove = FALSE) + var/density = material.get_property(MATERIAL_DENSITY) + var/hardness = material.get_property(MATERIAL_HARDNESS) + var/flexibility = material.get_property(MATERIAL_FLEXIBILITY) + // Dense and hard objects make for good melee weapons, bendy ones not so much + var/force_mod = (1 + (density - 4) * 0.05 + (hardness - 4) * 0.05) * (1 - flexibility * 0.1) + // Hardness doesn't matter much when we're just whacking someone in the back of the head + var/throwforce_mod = 1 + (density - 4) * 0.1 - flexibility * 0.1 + + if (!remove) + force *= GET_MATERIAL_MODIFIER(force_mod, multiplier) + throwforce *= GET_MATERIAL_MODIFIER(throwforce_mod, multiplier) + else + force /= GET_MATERIAL_MODIFIER(force_mod, multiplier) + throwforce /= GET_MATERIAL_MODIFIER(throwforce_mod, multiplier) /// Returns modifier to how much damage this object does to a target considered vulnerable to "demolition" (other objects, robots, etc) /obj/proc/get_demolition_modifier(obj/target) diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 3c5040e83cc..3f8387469c6 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -469,7 +469,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) if(remaining_mats) for(var/M=1 to remaining_mats) new stack_type(get_turf(loc)) - else if(custom_materials[GET_MATERIAL_REF(/datum/material/iron)]) + else if(custom_materials[SSmaterials.get_material(/datum/material/iron)]) new /obj/item/stack/rods(get_turf(loc), 2) qdel(src) diff --git a/code/game/objects/structures/toiletbong.dm b/code/game/objects/structures/toiletbong.dm index 47e9c64f99c..0a7d288b0cc 100644 --- a/code/game/objects/structures/toiletbong.dm +++ b/code/game/objects/structures/toiletbong.dm @@ -97,7 +97,7 @@ new /obj/item/flamethrower(get_turf(src)) var/obj/item/tank/internals/plasma/ptank = new /obj/item/tank/internals/plasma(get_turf(src)) ptank.air_contents.gases[/datum/gas/plasma][MOLES] = (0) - drop_costum_materials() + drop_custom_materials() qdel(src) return TRUE diff --git a/code/game/objects/structures/water_structures/toilet.dm b/code/game/objects/structures/water_structures/toilet.dm index 5b7dd6068ae..e62251c5caf 100644 --- a/code/game/objects/structures/water_structures/toilet.dm +++ b/code/game/objects/structures/water_structures/toilet.dm @@ -237,7 +237,7 @@ /obj/structure/toilet/atom_deconstruct(dissambled = TRUE) dump_contents() - drop_costum_materials() + drop_custom_materials() if(has_water_reclaimer) new /obj/item/stock_parts/water_recycler(drop_location()) @@ -425,7 +425,7 @@ if (suicide.transferItemToLoc(thing, newloc = src, silent = TRUE)) add_cistern_item(thing) suicide.gib(DROP_BRAIN) //we delete everything but the brain, as it's going to be moved to the cistern - set_custom_materials(list(GET_MATERIAL_REF(/datum/material/meat/mob_meat, suicide) = SHEET_MATERIAL_AMOUNT)) + set_custom_materials(list(SSmaterials.get_material(/datum/material/meat/mob_meat, suicide) = SHEET_MATERIAL_AMOUNT)) else toilet_brain = new(drop_location()) set_custom_materials(list(/datum/material/meat = SHEET_MATERIAL_AMOUNT)) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 9caca0a8174..4c7b253f1d6 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -346,7 +346,7 @@ ///Spawns shard and debris decal based on the glass_material_datum, spawns rods if window is reinforned and number of shards/rods is determined by the window being fulltile or not. /obj/structure/window/proc/spawn_debris(location) - var/datum/material/glass_material_ref = GET_MATERIAL_REF(glass_material_datum) + var/datum/material/glass_material_ref = SSmaterials.get_material(glass_material_datum) var/obj/item/shard_type = glass_material_ref.shard_type var/obj/effect/decal/debris_type = glass_material_ref.debris_type var/list/dropped_debris = list() diff --git a/code/game/turfs/closed/wall/misc_walls.dm b/code/game/turfs/closed/wall/misc_walls.dm index 861533c4b17..19449bc4929 100644 --- a/code/game/turfs/closed/wall/misc_walls.dm +++ b/code/game/turfs/closed/wall/misc_walls.dm @@ -120,7 +120,7 @@ /turf/closed/wall/material/meat/Initialize(mapload) . = ..() - set_custom_materials(list(GET_MATERIAL_REF(/datum/material/meat) = SHEET_MATERIAL_AMOUNT)) + set_custom_materials(list(SSmaterials.get_material(/datum/material/meat) = SHEET_MATERIAL_AMOUNT)) /turf/closed/wall/material/meat/airless baseturfs = /turf/open/floor/material/meat/airless diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index 4fa24bd3841..9948c3ea26c 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -569,7 +569,7 @@ playsound(src, 'sound/items/weapons/genhit.ogg', 50, TRUE) new used_tiles.tile_type(src) -/turf/open/apply_main_material_effects(datum/material/main_material, amount, multipier) +/turf/open/apply_main_material_effects(datum/material/main_material, amount, multiplier) . = ..() if(!main_material.turf_sound_override) return diff --git a/code/game/turfs/open/floor/misc_floor.dm b/code/game/turfs/open/floor/misc_floor.dm index b35ca869182..61f2c76bc79 100644 --- a/code/game/turfs/open/floor/misc_floor.dm +++ b/code/game/turfs/open/floor/misc_floor.dm @@ -345,7 +345,7 @@ /turf/open/floor/material/meat/Initialize(mapload) . = ..() - set_custom_materials(list(GET_MATERIAL_REF(/datum/material/meat) = SHEET_MATERIAL_AMOUNT)) + set_custom_materials(list(SSmaterials.get_material(/datum/material/meat) = SHEET_MATERIAL_AMOUNT)) /turf/open/floor/material/meat/airless initial_gas_mix = AIRLESS_ATMOS diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index bc95c6ed9fc..9051c2414ed 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -786,14 +786,14 @@ GLOBAL_LIST_EMPTY(station_turfs) inherent_explosive_resistance = explosion_block explosive_resistance += get_explosive_block() -/turf/apply_main_material_effects(datum/material/main_material, amount, multipier) +/turf/apply_main_material_effects(datum/material/main_material, amount, multiplier) . = ..() if(alpha < 255) ADD_TURF_TRANSPARENCY(src, MATERIAL_SOURCE(main_material)) main_material.setup_glow(src) rust_resistance = main_material.mat_rust_resistance -/turf/remove_main_material_effects(datum/material/custom_material, amount, multipier) +/turf/remove_main_material_effects(datum/material/custom_material, amount, multiplier) . = ..() rust_resistance = initial(rust_resistance) if(alpha == 255) diff --git a/code/modules/art/statues.dm b/code/modules/art/statues.dm index 7e4174ebcfb..2bb49122747 100644 --- a/code/modules/art/statues.dm +++ b/code/modules/art/statues.dm @@ -50,7 +50,7 @@ /obj/structure/statue/atom_deconstruct(disassembled = TRUE) var/amount_mod = disassembled ? 0 : -2 for(var/mat in custom_materials) - var/datum/material/custom_material = GET_MATERIAL_REF(mat) + var/datum/material/custom_material = SSmaterials.get_material(mat) var/amount = max(0,round(custom_materials[mat]/SHEET_MATERIAL_AMOUNT) + amount_mod) if(amount > 0) new custom_material.sheet_type(drop_location(), amount) diff --git a/code/modules/atmospherics/machinery/components/tank.dm b/code/modules/atmospherics/machinery/components/tank.dm index d329ca248ab..1bfb9c1d5b2 100644 --- a/code/modules/atmospherics/machinery/components/tank.dm +++ b/code/modules/atmospherics/machinery/components/tank.dm @@ -593,8 +593,8 @@ . = FALSE if(!stack.material_type) balloon_alert(user, "invalid material!") - var/datum/material/stack_mat = GET_MATERIAL_REF(stack.material_type) - if(!(MAT_CATEGORY_RIGID in stack_mat.categories)) + var/datum/material/stack_mat = SSmaterials.get_material(stack.material_type) + if(!(stack_mat.mat_flags & MATERIAL_CLASS_RIGID)) to_chat(user, span_notice("This material doesn't seem rigid enough to hold the shape of a tank...")) return diff --git a/code/modules/autowiki/pages/stockparts.dm b/code/modules/autowiki/pages/stockparts.dm index 71500601482..99a8f20bccd 100644 --- a/code/modules/autowiki/pages/stockparts.dm +++ b/code/modules/autowiki/pages/stockparts.dm @@ -82,9 +82,8 @@ /datum/autowiki/stock_parts/proc/generate_material_list(datum/design/recipe) var/list/materials = list() - for(var/ingredient_type in recipe.materials) + for(var/ingredient_type, amount in recipe.materials) var/datum/material/ingredient = new ingredient_type() - - materials += "[recipe.materials[ingredient_type]] [ingredient.name]" + materials += "[amount] [ingredient.name]" return materials.Join("
") diff --git a/code/modules/cargo/exports/materials.dm b/code/modules/cargo/exports/materials.dm index 3889946d5dd..36f358a11eb 100644 --- a/code/modules/cargo/exports/materials.dm +++ b/code/modules/cargo/exports/materials.dm @@ -35,7 +35,7 @@ */ /datum/export/material/proc/init_export_types(export_data) PROTECTED_PROC(TRUE) - + if(!use_shared_exports) return generate_export_typecache(export_data) @@ -54,7 +54,7 @@ var/obj/item/our_item = exported_item var/list/mat_comp = our_item.get_material_composition() - var/datum/material/mat_ref = ispath(material_id) ? locate(material_id) in mat_comp : GET_MATERIAL_REF(material_id) + var/datum/material/mat_ref = ispath(material_id) ? locate(material_id) in mat_comp : SSmaterials.get_material(material_id) var/amount = mat_comp[mat_ref] if(!amount) return 0 diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index ccec75931e5..0c1eda829a6 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -402,7 +402,7 @@ var/datum/armor/armor = get_armor() var/added_damage_header = FALSE - for(var/damage_key in ARMOR_LIST_DAMAGE()) + for(var/damage_key in ARMOR_LIST_DAMAGE) var/rating = armor.get_rating(damage_key) if(!rating) continue @@ -412,7 +412,7 @@ readout += "[armor_to_protection_name(damage_key)] [armor_to_protection_class(rating)]" var/added_durability_header = FALSE - for(var/durability_key in ARMOR_LIST_DURABILITY()) + for(var/durability_key in ARMOR_LIST_DURABILITY) var/rating = armor.get_rating(durability_key) if(!rating) continue diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index acd57c27990..ba37bb03c68 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -552,7 +552,7 @@ desc = "A classic suit of armour, able to be made from many different materials." icon_state = "knight_greyscale" inhand_icon_state = null - material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS//Can change color and add prefix + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS // Can change color and add prefix armor_type = /datum/armor/knight_greyscale /datum/armor/knight_greyscale diff --git a/code/modules/clothing/suits/reactive_armour_dimensional_themes.dm b/code/modules/clothing/suits/reactive_armour_dimensional_themes.dm index f66b23b1261..46617aa3f6c 100644 --- a/code/modules/clothing/suits/reactive_armour_dimensional_themes.dm +++ b/code/modules/clothing/suits/reactive_armour_dimensional_themes.dm @@ -83,7 +83,7 @@ to_convert.ChangeTurf(replace_wall) if (material) - var/list/custom_materials = list(GET_MATERIAL_REF(material) = SHEET_MATERIAL_AMOUNT) + var/list/custom_materials = list(SSmaterials.get_material(material) = SHEET_MATERIAL_AMOUNT) to_convert.set_custom_materials(custom_materials) /** @@ -103,7 +103,7 @@ var/to_place = rand(MIN_BARRIERS, MAX_BARRIERS) var/list/custom_materials = list() if (material) - custom_materials = list(GET_MATERIAL_REF(material) = SHEET_MATERIAL_AMOUNT) + custom_materials = list(SSmaterials.get_material(material) = SHEET_MATERIAL_AMOUNT) while (target_area.len > 0 && to_place > 0) var/turf/place_turf = pick(target_area) diff --git a/code/modules/experisci/experiment/types/scanning_material.dm b/code/modules/experisci/experiment/types/scanning_material.dm index f65950d0479..cff52dd1958 100644 --- a/code/modules/experisci/experiment/types/scanning_material.dm +++ b/code/modules/experisci/experiment/types/scanning_material.dm @@ -19,6 +19,6 @@ return ..() && target.custom_materials && target.has_material_type(required_materials[typepath]) /datum/experiment/scanning/random/material/serialize_progress_stage(atom/target, list/seen_instances) - var/datum/material/required_material = GET_MATERIAL_REF(required_materials[target]) + var/datum/material/required_material = SSmaterials.get_material(required_materials[target]) return EXPERIMENT_PROG_INT("Scan samples of \a [required_material.name] [initial(target.name)]", \ traits & EXPERIMENT_TRAIT_DESTRUCTIVE ? scanned[target] : seen_instances.len, required_atoms[target]) diff --git a/code/modules/explorer_drone/exploration_events/resource.dm b/code/modules/explorer_drone/exploration_events/resource.dm index 908ad0cb81d..437506eb97d 100644 --- a/code/modules/explorer_drone/exploration_events/resource.dm +++ b/code/modules/explorer_drone/exploration_events/resource.dm @@ -289,13 +289,13 @@ /datum/exploration_event/simple/resource/mineral_deposit/New() . = ..() chosen_material_type = pick(possible_materials) - var/datum/material/chosen_mat = GET_MATERIAL_REF(chosen_material_type) + var/datum/material/chosen_mat = SSmaterials.get_material(chosen_material_type) name = "[chosen_mat.name] Deposit" discovery_log = "Discovered a sizeable [chosen_mat.name] deposit" success_log = "Extracted [chosen_mat.name]." description = "You locate a rich surface deposit of [chosen_mat.name]." /datum/exploration_event/simple/resource/mineral_deposit/dispense_loot(obj/item/exodrone/drone) - var/datum/material/chosen_mat = GET_MATERIAL_REF(chosen_material_type) + var/datum/material/chosen_mat = SSmaterials.get_material(chosen_material_type) var/obj/loot = new chosen_mat.sheet_type(loot_amount) drone.try_transfer(loot) diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index 31c871f8937..397a2d89672 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -702,8 +702,8 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( var/multiplier = 1 / mats_len var/unmodified_weight = weight for(var/mat_type in custom_materials) - var/datum/material/material = GET_MATERIAL_REF(mat_type) - unmodified_weight /= GET_MATERIAL_MODIFIER(material.fish_weight_modifier, multiplier) + var/datum/material/material = SSmaterials.get_material(mat_type) + unmodified_weight /= GET_MATERIAL_MODIFIER(1 + (material.get_property(MATERIAL_DENSITY) - 4) * 0.1, multiplier) multiplier = unmodified_weight / weight for(var/mat_type in new_mats_list) new_mats_list[mat_type] *= multiplier @@ -755,12 +755,16 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( if(bonus_malus) calculate_fish_force_bonus(bonus_malus) + throwforce = force + if(material_flags & MATERIAL_EFFECTS && length(custom_materials)) //struck by metal gen or something. - var/multiplier = 1 / length(custom_materials) if(material_flags & MATERIAL_AFFECT_STATISTICS) + var/index = 1 for(var/current_material in custom_materials) - var/datum/material/material = GET_MATERIAL_REF(current_material) - force *= GET_MATERIAL_MODIFIER(material.strength_modifier, multiplier) + var/datum/material/material = SSmaterials.get_material(current_material) + change_material_strength(material, custom_materials[material], get_material_multiplier(material, custom_materials, index)) + index += 1 + var/datum/material/master = get_master_material() if(master?.item_sound_override) hitsound = master.item_sound_override @@ -771,10 +775,7 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( drop_sound = master.item_sound_override SEND_SIGNAL(src, COMSIG_FISH_FORCE_UPDATED, weight_rank, bonus_malus) - - throwforce = force - - if(force >=15 && hitsound == SFX_DEFAULT_FISH_SLAP) // don't override special attack sounds + if(force >= 15 && hitsound == SFX_DEFAULT_FISH_SLAP) // don't override special attack sounds hitsound = SFX_ALT_FISH_SLAP // do more damage - do heavier slap sound ///A proc that makes the fish slightly stronger or weaker if there's a noticeable discrepancy between size and weight. @@ -805,9 +806,8 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( /obj/item/fish/apply_single_mat_effect(datum/material/custom_material, amount, multiplier) . = ..() //The materials are being increased/decreased along with the weight. - if(fish_flags & FISH_FLAG_UPDATING_SIZE_AND_WEIGHT) - return - material_weight_mult *= GET_MATERIAL_MODIFIER(custom_material.fish_weight_modifier, multiplier) + if(!(fish_flags & FISH_FLAG_UPDATING_SIZE_AND_WEIGHT)) + material_weight_mult *= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_DENSITY) - 4) * 0.1, multiplier) /obj/item/fish/apply_material_effects() . = ..() diff --git a/code/modules/fishing/fish/fish_traits.dm b/code/modules/fishing/fish/fish_traits.dm index 71243f571c5..b70d6af0072 100644 --- a/code/modules/fishing/fish/fish_traits.dm +++ b/code/modules/fishing/fish/fish_traits.dm @@ -240,14 +240,6 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits()) name = "Demersal" catalog_description = "This fish tends to stay near the waterbed." -/datum/fish_trait/heavy/catch_weight_mod(obj/item/fishing_rod/rod, mob/fisherman, atom/location, obj/item/fish/fish_type) - . = ..() - var/datum/material/material = rod.get_master_material() - if(!material) - return - //the fish weight modifier of the material influences the chance of cathing this type of fish. - .[MULTIPLICATIVE_FISHING_MOD] = material.fish_weight_modifier - /datum/fish_trait/heavy/apply_to_mob(mob/living/basic/mob) . = ..() mob.add_movespeed_modifier(/datum/movespeed_modifier/heavy_fish) diff --git a/code/modules/fishing/fish_mount.dm b/code/modules/fishing/fish_mount.dm index 0aa95678051..b82a8de7197 100644 --- a/code/modules/fishing/fish_mount.dm +++ b/code/modules/fishing/fish_mount.dm @@ -140,7 +140,7 @@ var/beauty = 100 + mounted_fish.beauty * 1.2 var/datum/material/main_material = mounted_fish.get_master_material() if(main_material) - beauty += main_material.beauty_modifier * mounted_fish.weight + beauty += main_material.get_property(MATERIAL_BEAUTY) * mounted_fish.weight return round(beauty) /obj/structure/fish_mount/proc/on_fish_attack_hand(datum/source, mob/living/user) diff --git a/code/modules/fishing/fishing_rod.dm b/code/modules/fishing/fishing_rod.dm index a3bb9a229c2..8f21acb8829 100644 --- a/code/modules/fishing/fishing_rod.dm +++ b/code/modules/fishing/fishing_rod.dm @@ -161,13 +161,7 @@ . += boxed_message(block.Join("\n")) if(get_percent && (material_flags & MATERIAL_EFFECTS) && length(custom_materials)) - block = list() - block += span_info("Right now, fish caught by this fishing rod have a [get_material_fish_chance(user)]% of being made of its same materials.") - var/datum/material/material = get_master_material() - if(material.fish_weight_modifier != 1) - var/heavier = material.fish_weight_modifier > 1 ? "heavier" : "lighter" - block += span_info("Fish made of the same material as this rod tend to be [abs(material.fish_weight_modifier - 1) * 100]% [heavier].") - . += boxed_message(block.Join("\n")) + . += boxed_message(span_info("Right now, fish caught by this fishing rod have a [get_material_fish_chance(user)]% of being made of its same materials.")) block = list() if(HAS_TRAIT(src, TRAIT_ROD_ATTRACT_SHINY_LOVERS)) @@ -196,32 +190,19 @@ /obj/item/fishing_rod/apply_single_mat_effect(datum/material/custom_material, amount, multiplier) . = ..() - difficulty_modifier += custom_material.fishing_difficulty_modifier * multiplier - cast_range += custom_material.fishing_cast_range * multiplier - experience_multiplier *= GET_MATERIAL_MODIFIER(custom_material.fishing_experience_multiplier, multiplier) - completion_speed_mult *= GET_MATERIAL_MODIFIER(custom_material.fishing_completion_speed, multiplier) - bait_speed_mult *= GET_MATERIAL_MODIFIER(custom_material.fishing_bait_speed_mult, multiplier) - deceleration_mult *= GET_MATERIAL_MODIFIER(custom_material.fishing_deceleration_mult, multiplier) - bounciness_mult *= GET_MATERIAL_MODIFIER(custom_material.fishing_bounciness_mult, multiplier) - gravity_mult *= GET_MATERIAL_MODIFIER(custom_material.fishing_gravity_mult, multiplier) - var/height_mod = GET_MATERIAL_MODIFIER(custom_material.strength_modifier, multiplier) - if(height_mod > 1) - bait_height_mult *= height_mod**0.75 - + cast_range += round(2 - custom_material.get_property(MATERIAL_DENSITY) / 2) * multiplier + bait_speed_mult *= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_REFLECTIVITY) - 4) * 0.1, multiplier) + deceleration_mult *= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_HARDNESS) - 4) * 0.1, multiplier) + bounciness_mult *= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_FLEXIBILITY) - 4) * 0.1, multiplier) + gravity_mult *= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_DENSITY) - 4) * 0.1, multiplier) /obj/item/fishing_rod/remove_single_mat_effect(datum/material/custom_material, amount, multiplier) . = ..() - difficulty_modifier -= custom_material.fishing_difficulty_modifier * multiplier - cast_range -= custom_material.fishing_cast_range * multiplier - experience_multiplier /= GET_MATERIAL_MODIFIER(custom_material.fishing_experience_multiplier, multiplier) - completion_speed_mult /= GET_MATERIAL_MODIFIER(custom_material.fishing_completion_speed, multiplier) - bait_speed_mult /= GET_MATERIAL_MODIFIER(custom_material.fishing_bait_speed_mult, multiplier) - deceleration_mult /= GET_MATERIAL_MODIFIER(custom_material.fishing_deceleration_mult, multiplier) - bounciness_mult /= GET_MATERIAL_MODIFIER(custom_material.fishing_bounciness_mult, multiplier) - gravity_mult /= GET_MATERIAL_MODIFIER(custom_material.fishing_gravity_mult, multiplier) - var/height_mod = GET_MATERIAL_MODIFIER(custom_material.strength_modifier, multiplier) - if(height_mod > 1) - bait_height_mult *= 1/(height_mod**0.75) + cast_range -= round(2 - custom_material.get_property(MATERIAL_DENSITY) / 2) * multiplier + bait_speed_mult /= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_REFLECTIVITY) - 4) * 0.1, multiplier) + deceleration_mult /= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_HARDNESS) - 4) * 0.1, multiplier) + bounciness_mult /= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_FLEXIBILITY) - 4) * 0.1, multiplier) + gravity_mult /= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_DENSITY) - 4) * 0.1, multiplier) /** * Is there a reason why this fishing rod couldn't fish in target_fish_source? diff --git a/code/modules/food_and_drinks/machinery/gibber.dm b/code/modules/food_and_drinks/machinery/gibber.dm index 0152332dac4..3422eee9944 100644 --- a/code/modules/food_and_drinks/machinery/gibber.dm +++ b/code/modules/food_and_drinks/machinery/gibber.dm @@ -279,7 +279,7 @@ /obj/machinery/gibber/proc/spawn_meat(mob/living/victim, meat_type = /obj/item/food/meat/slab, list/datum/disease/diseases) var/obj/item/food/meat/meat = new meat_type(src, blood_dna_info) meat.name = "[victim.real_name]'s [meat.name]" - meat.set_custom_materials(list(GET_MATERIAL_REF(/datum/material/meat/mob_meat, victim) = 4 * SHEET_MATERIAL_AMOUNT)) + meat.set_custom_materials(list(SSmaterials.get_material(/datum/material/meat/mob_meat, victim) = 4 * SHEET_MATERIAL_AMOUNT)) if (!istype(meat)) return meat.subjectname = victim.real_name diff --git a/code/modules/food_and_drinks/machinery/microwave.dm b/code/modules/food_and_drinks/machinery/microwave.dm index fce07350527..1dfc3a24362 100644 --- a/code/modules/food_and_drinks/machinery/microwave.dm +++ b/code/modules/food_and_drinks/machinery/microwave.dm @@ -750,7 +750,7 @@ else dirty++ - metal_amount += (cooked_item.custom_materials?[GET_MATERIAL_REF(/datum/material/iron)] || 0) + metal_amount += (cooked_item.custom_materials?[SSmaterials.get_material(/datum/material/iron)] || 0) if(cursed_chef && (metal_amount || prob(5))) // If we're unlucky and have metal, we're guaranteed to explode spark() diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm index b2dd7cb3a93..30eb26c206f 100644 --- a/code/modules/hydroponics/biogenerator.dm +++ b/code/modules/hydroponics/biogenerator.dm @@ -359,10 +359,10 @@ /obj/machinery/biogenerator/proc/use_biomass(list/materials, amount = 1, remove_biomass = TRUE) - if(materials.len != 1 || materials[1] != GET_MATERIAL_REF(/datum/material/biomass)) + if(materials.len != 1 || materials[1] != SSmaterials.get_material(/datum/material/biomass)) return FALSE - var/cost = materials[GET_MATERIAL_REF(/datum/material/biomass)] * amount / efficiency + var/cost = materials[SSmaterials.get_material(/datum/material/biomass)] * amount / efficiency if (cost > biomass) return FALSE @@ -392,13 +392,12 @@ if(!use_biomass(design.materials, amount)) return FALSE + var/drop_location = drop_location() if(istype(design.build_path, /obj/item/stack/sheet)) - new design.build_path(drop_location(), amount) - + design.create_result(drop_location, amount = amount) else - var/drop_location = drop_location() for(var/i in 1 to amount) - new design.build_path(drop_location) + design.create_result(drop_location) return TRUE @@ -519,7 +518,7 @@ "id" = design.id, "name" = design.name, "is_reagent" = design.make_reagent != null, - "cost" = design.materials[GET_MATERIAL_REF(/datum/material/biomass)] / efficiency, + "cost" = design.materials[SSmaterials.get_material(/datum/material/biomass)] / efficiency, )) data["categories"] += list(cat) diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 16521e3c27a..f5f58af7bbf 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -105,11 +105,12 @@ return new trash_type(location || drop_location()) -/obj/item/food/grown/blend_requirements() - if(dry_grind && !HAS_TRAIT(src, TRAIT_DRIED)) - to_chat(usr, span_warning("[src] needs to be dry before it can be ground up!")) - return - return TRUE +/obj/item/food/grown/blend_requirements(atom/movable/grinder, mob/living/user) + if(!dry_grind || HAS_TRAIT(src, TRAIT_DRIED)) + return TRUE + if (user) + to_chat(user, span_warning("[src] needs to be dry before it can be ground up!")) + return FALSE /// Turns the nutriments and vitamins into the distill reagent or fruit wine /obj/item/food/grown/proc/ferment() diff --git a/code/modules/manufactorio/machines/lathe.dm b/code/modules/manufactorio/machines/lathe.dm index 6a32b3ed953..559b92b7c10 100644 --- a/code/modules/manufactorio/machines/lathe.dm +++ b/code/modules/manufactorio/machines/lathe.dm @@ -22,7 +22,7 @@ print_sound = new(src, FALSE) materials = new ( \ src, \ - SSmaterials.materials_by_category[MAT_CATEGORY_ITEM_MATERIAL], \ + SSmaterials.flat_materials, \ 0, \ MATCONTAINER_EXAMINE|MATCONTAINER_NO_INSERT, \ ) @@ -61,11 +61,10 @@ if(isnull(design)) return . += span_notice("It needs:") - for(var/valid_type in design.materials) + for(var/valid_type, amount in design.materials) var/atom/ingredient = valid_type - var/amount = design.materials[ingredient] / SHEET_MATERIAL_AMOUNT - . += "[amount] sheets of [initial(ingredient.name)]" + . += "[amount / SHEET_MATERIAL_AMOUNT] sheets of [initial(ingredient.name)]" /obj/machinery/power/manufacturing/lathe/update_overlays() . = ..() @@ -113,14 +112,12 @@ return //check for materials required. For custom material items decode their required materials var/list/materials_needed = list() - for(var/material in design.materials) - var/amount_needed = design.materials[material] - if(istext(material)) // category - for(var/datum/material/valid_candidate as anything in SSmaterials.materials_by_category[material]) - if(materials.get_material_amount(valid_candidate) < amount_needed) - continue - material = valid_candidate - break + for(var/material, amount_needed in design.materials) + if(ispath(material, /datum/material_requirement)) // Material requirement + for(var/datum/material/valid_candidate as anything in SSmaterials.get_materials_by_req(material)) + if(materials.get_material_amount(valid_candidate) >= amount_needed) + material = valid_candidate + break if(isnull(material)) return materials_needed[material] = amount_needed @@ -150,13 +147,13 @@ var/max_stack_amount = initial(stack_item.max_amount) var/amount = initial(stack_item.amount) while(amount > max_stack_amount) - var/obj/item/stack/new_stack = new stack_item(null, max_stack_amount) + var/obj/item/stack/new_stack = new stack_item(drop_location(), max_stack_amount) if(!send_resource(new_stack, dir)) withheld = new_stack amount -= max_stack_amount - created = new stack_item(null, amount) + created = new stack_item(drop_location(), amount) else - created = new design.build_path(null) + created = design.create_result(drop_location(), materials_needed) split_materials_uniformly(materials_needed, target_object = created) if(isitem(created)) created.pixel_x = created.base_pixel_x + rand(-6, 6) diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index f41c0aeef17..87e95469de6 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -152,7 +152,7 @@ materials = new ( \ src, \ - SSmaterials.materials_by_category[MAT_CATEGORY_SILO], \ + SSmaterials.get_materials_by_flag(MATERIAL_SILO_STORED), \ INFINITY, \ MATCONTAINER_EXAMINE, \ allowed_items = accepted_type \ @@ -160,7 +160,7 @@ if(!GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter]) GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter] = new /datum/techweb/autounlocking/smelter stored_research = GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter] - selected_material = GET_MATERIAL_REF(/datum/material/iron) + selected_material = SSmaterials.get_material(/datum/material/iron) /obj/machinery/mineral/processing_unit/Destroy() QDEL_NULL(proximity_monitor) @@ -267,16 +267,14 @@ generate_mineral(alloy.build_path) -/obj/machinery/mineral/processing_unit/proc/can_smelt(datum/design/D, seconds_per_tick = 2) - if(D.make_reagent) +/obj/machinery/mineral/processing_unit/proc/can_smelt(datum/design/design, seconds_per_tick = 2) + if(design.make_reagent) return FALSE var/build_amount = SMELT_AMOUNT * seconds_per_tick - for(var/mat_cat in D.materials) - var/required_amount = D.materials[mat_cat] + for(var/mat_cat, required_amount in design.materials) var/amount = materials.materials[mat_cat] - build_amount = min(build_amount, round(amount / required_amount)) return build_amount diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index e32783b5e25..6f5d2cfbbca 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -91,15 +91,14 @@ points += gathered_ore.points * point_upgrade * gathered_ore.amount /// Returns the amount of a specific alloy design, based on the accessible materials -/obj/machinery/mineral/ore_redemption/proc/can_smelt_alloy(datum/design/D) +/obj/machinery/mineral/ore_redemption/proc/can_smelt_alloy(datum/design/design) var/datum/material_container/mat_container = materials.mat_container - if(!mat_container || D.make_reagent) + if(!mat_container || design.make_reagent) return FALSE var/build_amount = 0 - for(var/mat in D.materials) - var/amount = D.materials[mat] + for(var/mat, amount in design.materials) var/datum/material/redemption_mat_amount = mat_container.materials[mat] if(!amount || !redemption_mat_amount) @@ -371,11 +370,11 @@ if(amount < 1) //no negative mats return materials.use_materials(alloy.materials, multiplier = amount, action = "withdrawn", name = "sheets", user_data = ID_DATA(usr)) - var/output + var/atom/movable/output if(ispath(alloy.build_path, /obj/item/stack/sheet)) - output = new alloy.build_path(src, amount) + output = alloy.create_result(src, amount = amount) else - output = new alloy.build_path(src) + output = alloy.create_result(src) unload_mineral(output) else to_chat(usr, span_warning("Required access not found.")) diff --git a/code/modules/mining/machine_silo.dm b/code/modules/mining/machine_silo.dm index 871d4e7ab7e..e551ede4841 100644 --- a/code/modules/mining/machine_silo.dm +++ b/code/modules/mining/machine_silo.dm @@ -73,7 +73,7 @@ materials = new ( \ src, \ - SSmaterials.materials_by_category[MAT_CATEGORY_SILO], \ + SSmaterials.get_materials_by_flag(MATERIAL_SILO_STORED), \ INFINITY, \ MATCONTAINER_EXAMINE, \ container_signals = list( \ diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 88aa662c168..3b8d40d66d6 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -438,7 +438,6 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ force = 1 throwforce = 2 w_class = WEIGHT_CLASS_TINY - custom_materials = list(/datum/material/iron = COIN_MATERIAL_AMOUNT) material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS var/string_attached var/list/sideslist = list("heads","tails") @@ -554,45 +553,27 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ /obj/item/coin/gold custom_materials = list(/datum/material/gold = COIN_MATERIAL_AMOUNT) -/obj/item/coin/gold/grind_results() - return list(/datum/reagent/gold = 4) - /obj/item/coin/silver custom_materials = list(/datum/material/silver = COIN_MATERIAL_AMOUNT) -/obj/item/coin/silver/grind_results() - return list(/datum/reagent/silver = 4) - /obj/item/coin/diamond custom_materials = list(/datum/material/diamond = COIN_MATERIAL_AMOUNT) -/obj/item/coin/diamond/grind_results() - return list(/datum/reagent/carbon = 4) - /obj/item/coin/plasma custom_materials = list(/datum/material/plasma = COIN_MATERIAL_AMOUNT) -/obj/item/coin/plasma/grind_results() - return list(/datum/reagent/toxin/plasma = 4) - /obj/item/coin/uranium custom_materials = list(/datum/material/uranium = COIN_MATERIAL_AMOUNT) -/obj/item/coin/uranium/grind_results() - return list(/datum/reagent/uranium = 4) - /obj/item/coin/titanium custom_materials = list(/datum/material/titanium = COIN_MATERIAL_AMOUNT) /obj/item/coin/titanium/grind_results() - return list(/datum/reagent/flash_powder = 4) + return list(/datum/reagent/flash_powder = 8) /obj/item/coin/bananium custom_materials = list(/datum/material/bananium = COIN_MATERIAL_AMOUNT) -/obj/item/coin/bananium/grind_results() - return list(/datum/reagent/consumable/nutriment/soup/clown_tears = 4) - /obj/item/coin/adamantine custom_materials = list(/datum/material/adamantine = COIN_MATERIAL_AMOUNT) @@ -600,19 +581,16 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ custom_materials = list(/datum/material/mythril = COIN_MATERIAL_AMOUNT) /obj/item/coin/mythril/grind_results() - return list(/datum/reagent/medicine/omnizine/godblood = 4) + return list(/datum/reagent/medicine/omnizine/godblood = 8) /obj/item/coin/plastic custom_materials = list(/datum/material/plastic = COIN_MATERIAL_AMOUNT) -/obj/item/coin/plastic/grind_results() - return list(/datum/reagent/plastic_polymers = 4) - /obj/item/coin/runite custom_materials = list(/datum/material/runite = COIN_MATERIAL_AMOUNT) /obj/item/coin/runite/grind_results() - return list(/datum/reagent/iron = 2, /datum/reagent/consumable/ethanol/ritual_wine = 2) + return list(/datum/reagent/iron = 4, /datum/reagent/consumable/ethanol/ritual_wine = 4) /obj/item/coin/twoheaded desc = "Hey, this coin's the same on both sides!" @@ -629,17 +607,17 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ override_material_worth = TRUE /obj/item/coin/antagtoken/grind_results() - return list(/datum/reagent/ants = 2, /datum/reagent/consumable/eggyolk = 2) + return list(/datum/reagent/ants = 4, /datum/reagent/consumable/eggyolk = 4) -/obj/item/coin/iron/grind_results() - return list(/datum/reagent/iron = 4) +/obj/item/coin/iron + custom_materials = list(/datum/material/iron = COIN_MATERIAL_AMOUNT) /obj/item/coin/gold/debug custom_materials = list(/datum/material/gold = COIN_MATERIAL_AMOUNT) desc = "If you got this somehow, be aware that it will dust you. Almost certainly." /obj/item/coin/gold/debug/grind_results() - return list(/datum/reagent/gold/cursed = 4) + return list(/datum/reagent/gold/cursed = 8) /obj/item/coin/gold/debug/attack_self(mob/user) if(cooldown < world.time) diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm index 1e95ae542ac..714b66d462b 100644 --- a/code/modules/mob/living/silicon/robot/robot_model.dm +++ b/code/modules/mob/living/silicon/robot/robot_model.dm @@ -213,7 +213,7 @@ if(!to_stock) //Nothing for us in the silo continue - storage_datum.energy += charger.materials.use_materials(list(GET_MATERIAL_REF(storage_datum.mat_type) = to_stock), action = "restocked", name = "units", user_data = ID_DATA(robot)) + storage_datum.energy += charger.materials.use_materials(list(SSmaterials.get_material(storage_datum.mat_type) = to_stock), action = "restocked", name = "units", user_data = ID_DATA(robot)) charger.balloon_alert(robot, "+ [to_stock]u [initial(storage_datum.mat_type.name)]") playsound(charger, 'sound/items/weapons/gun/general/mag_bullet_insert.ogg', 50, vary = FALSE) return diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index 092bdd654b9..6196fd56888 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -822,7 +822,7 @@ . = ..() if(!length(accepted_mats)) - accepted_mats = SSmaterials.materials_by_category[MAT_CATEGORY_SILO] + accepted_mats = SSmaterials.get_materials_by_flag(MATERIAL_SILO_STORED) container = new ( \ src, \ diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 67c800f76a7..15140879421 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -91,9 +91,6 @@ LAZYREMOVE(SSpersistence.queued_message_bottles, src) return ..() -/obj/item/paper/grind_results() - return list(/datum/reagent/cellulose = 3) - /obj/item/paper/custom_fire_overlay() if (!custom_fire_overlay) custom_fire_overlay = mutable_appearance('icons/obj/service/bureaucracy.dmi', "paper_onfire_overlay", appearance_flags = RESET_COLOR|KEEP_APART) diff --git a/code/modules/plumbing/plumbers/grinder_chemical.dm b/code/modules/plumbing/plumbers/grinder_chemical.dm index d1c21bf5c32..2341d7fae8e 100644 --- a/code/modules/plumbing/plumbers/grinder_chemical.dm +++ b/code/modules/plumbing/plumbers/grinder_chemical.dm @@ -130,6 +130,7 @@ if((item_to_blend.item_flags & ABSTRACT) || (item_to_blend.flags_1 & HOLOGRAM_1)) return + if(!item_to_blend.blend_requirements(src)) return diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm index f74860662bd..ec67e2f80ba 100644 --- a/code/modules/power/apc/apc_tool_act.dm +++ b/code/modules/power/apc/apc_tool_act.dm @@ -34,7 +34,7 @@ /obj/machinery/power/apc/proc/fork_outlet_act(mob/living/user, obj/item/tool) var/metal = 0 var/shock_source = null - metal += LAZYACCESS(tool.custom_materials, GET_MATERIAL_REF(/datum/material/iron))//This prevents wooden rolling pins from shocking the user + metal += LAZYACCESS(tool.custom_materials, SSmaterials.get_material(/datum/material/iron))//This prevents wooden rolling pins from shocking the user if(cell || terminal) //The mob gets shocked by whichever powersource has the most electricity if(cell && terminal) diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm index 2a912988c05..bdbe041d2cf 100644 --- a/code/modules/projectiles/guns/magic/staff.dm +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -292,7 +292,7 @@ /obj/item/gun/magic/staff/door/do_suicide(mob/living/user) . = ..() var/obj/machinery/door/airlock/material/door = new(user.drop_location()) - door.set_custom_materials(list(GET_MATERIAL_REF(/datum/material/meat) = SHEET_MATERIAL_AMOUNT)) + door.set_custom_materials(list(SSmaterials.get_material(/datum/material/meat) = SHEET_MATERIAL_AMOUNT)) door.update_appearance(updates = UPDATE_ICON) door.name = user.real_name addtimer(CALLBACK(door, TYPE_PROC_REF(/obj/machinery/door, open)), 1.5 SECONDS) diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index b998523bc25..51c3a4590bb 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -177,21 +177,22 @@ //surface level checks to filter out items that can be grinded/juice var/list/obj/item/filtered_list = list() for(var/obj/item/ingredient as anything in to_add) - //what are we trying to grind exactly? + // What are we trying to grind exactly? if((ingredient.item_flags & ABSTRACT) || (ingredient.flags_1 & HOLOGRAM_1)) continue - //Nothing would come from grinding or juicing + // Nothing would come from grinding or juicing if(!length(ingredient.grind_results()) && !ingredient.reagents.total_volume) to_chat(user, span_warning("You cannot grind/juice [ingredient] into reagents!")) continue - //Error messages should be in the objects' definitions - if(!ingredient.blend_requirements(src)) + // Error messages should be in the objects' definitions + if(!ingredient.blend_requirements(src, user)) continue filtered_list += ingredient - if(!filtered_list.len) + + if(!length(filtered_list)) return FALSE //find total weight of all items already in grinder diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 984dd121067..78897d6b09f 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -101,7 +101,7 @@ . = ..() if(material) - material = GET_MATERIAL_REF(material) + material = SSmaterials.get_material(material) if(glass_price) AddElement(/datum/element/venue_price, glass_price) if(!mass) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index fe3effbc61f..77a7dbe2dbb 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -2831,6 +2831,9 @@ if(!metal_amount) metal_amount = default_material_amount //some stuff doesn't have materials at all. To still give them properties, we give them a material. Basically doesn't exist + // Delete existing materials first before changing the material flags + if(length(target.custom_materials)) + target.set_custom_materials() var/list/metal_dat = list((metal_ref) = metal_amount) target.material_flags = applied_material_flags target.set_custom_materials(metal_dat) diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index f0895a21b39..39feda61fb4 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -231,7 +231,7 @@ */ /obj/item/reagent_containers/cup/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(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) + set_custom_materials(list(SSmaterials.get_material(/datum/material/glass) = 5))//sets it to glass so, later on, it gets picked up by the glass catch (hope it doesn't 'break' things lol) return ..() /// Callback for [datum/component/takes_reagent_appearance] to inherent style footypes @@ -660,8 +660,7 @@ if(grinded) to_chat(user, span_warning("There is something inside already!")) return ITEM_INTERACT_BLOCKING - if(!tool.blend_requirements(src)) - to_chat(user, span_warning("Cannot grind this!")) + if(!tool.blend_requirements(src, user)) return ITEM_INTERACT_BLOCKING if((length(tool.grind_results()) || tool.reagents?.total_volume) && user.transferItemToLoc(tool, src)) grinded = tool diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm index 2c49b8e3ec0..dd1e71b2cca 100644 --- a/code/modules/religion/rites.dm +++ b/code/modules/religion/rites.dm @@ -423,14 +423,24 @@ var/obj/item/stack/sheet/converted /datum/religion_rites/ceremonial_weapon/perform_rite(mob/living/user, atom/religious_tool) + var/not_rigid = null + var/datum/material_requirement/requirement = SSmaterials.requirements[/datum/material_requirement/rigid_material] for(var/obj/item/stack/sheet/could_blade in get_turf(religious_tool)) - if(!(GET_MATERIAL_REF(could_blade.material_type) in SSmaterials.materials_by_category[MAT_CATEGORY_ITEM_MATERIAL])) + var/datum/material/blade_mat = SSmaterials.get_material(could_blade.material_type) + if(!blade_mat) + continue + if(!requirement.valid_material(blade_mat)) + not_rigid = blade_mat continue if(could_blade.amount < 5) continue converted = could_blade return ..() - to_chat(user, span_warning("You need at least 5 sheets of a material that can be made into items!")) + // We've found a material but it wasn't solid enough. + if(not_rigid) + to_chat(user, span_warning("[not_rigid] is not suitable for being made into gear!")) + else + to_chat(user, span_warning("You need at least 5 sheets of a rigid material that can be made into gear!")) return FALSE /datum/religion_rites/ceremonial_weapon/invoke_effect(mob/living/user, atom/movable/religious_tool) @@ -446,7 +456,7 @@ if(!used_for_blade.use(5))//use 5 of the material return var/obj/item/ceremonial_blade/blade = new(altar_turf) - blade.set_custom_materials(list(GET_MATERIAL_REF(material_used) = SHEET_MATERIAL_AMOUNT * 5)) + blade.set_custom_materials(list(SSmaterials.get_material(material_used) = SHEET_MATERIAL_AMOUNT * 5)) return TRUE /datum/religion_rites/unbreakable diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index fd0ed96de61..a6e3c103417 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -29,7 +29,7 @@ other types of metals and chemistry for reagents). var/id = DESIGN_ID_IGNORE /// Bitflags indicating what machines this design is compatable with. ([IMPRINTER]|[AWAY_IMPRINTER]|[PROTOLATHE]|[AWAY_LATHE]|[AUTOLATHE]|[MECHFAB]|[BIOGENERATOR]|[LIMBGROWER]|[SMELTER]) var/build_type = null - /// List of materials required to create one unit of the product. Format is (typepath or caregory) -> amount + /// List of materials required to create one unit of the product. Format is (typepath or requirements datum) -> amount var/list/materials = list() /// The amount of time required to create one unit of the product. var/construction_time = 3.2 SECONDS @@ -68,13 +68,16 @@ other types of metals and chemistry for reagents). /datum/design/proc/InitializeMaterials() var/list/temp_list = list() - 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 = GET_MATERIAL_REF(i) - temp_list[M] = amount - else - temp_list[i] = amount + // Go through all of our materials, get the subsystem instance, and then replace the list. + for(var/mat_type, amount in materials) + if(ispath(mat_type, /datum/material_requirement)) + temp_list[mat_type] = amount + continue + + // Not a material requirement, so get the ref the normal way + var/datum/material/mat = SSmaterials.get_material(mat_type) + temp_list[mat] = amount + materials = temp_list /datum/design/proc/icon_html(client/user) @@ -88,6 +91,17 @@ other types of metals and chemistry for reagents). return isnull(desc) ? initial(object_build_item_path.desc) : desc +/// Produce the resulting item, optionally with a specfic amount if we're a stack design +/datum/design/proc/create_result(atom/drop_loc, list/custom_materials, amount = null) + if (!ispath(build_path, /obj/item/stack) && !isnull(amount)) + CRASH("[src] create_result was passed an amount, despite not being a stack design!") + + if (!ispath(build_path, /obj/item/stack)) + return new build_path(drop_loc) + + if (isnull(amount)) + amount = 1 + return new build_path(drop_loc, amount) //////////////////////////////////////// //Disks for transporting design datums// diff --git a/code/modules/research/designs/autolathe/multi-department_designs.dm b/code/modules/research/designs/autolathe/multi-department_designs.dm index bb6a1d47840..b9bcbc4c808 100644 --- a/code/modules/research/designs/autolathe/multi-department_designs.dm +++ b/code/modules/research/designs/autolathe/multi-department_designs.dm @@ -187,18 +187,31 @@ name = "Toolbox" id = "tool_box" build_type = AUTOLATHE - materials = list(MAT_CATEGORY_ITEM_MATERIAL =SMALL_MATERIAL_AMOUNT*5) + materials = list(/datum/material_requirement/solid_material = SMALL_MATERIAL_AMOUNT * 5) build_path = /obj/item/storage/toolbox category = list( RND_CATEGORY_INITIAL, RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_ENGINEERING, ) +/datum/design/toolbox/create_result(atom/drop_loc, list/custom_materials, amount) + var/obj/item/storage/toolbox/toolbox = ..() + if (length(custom_materials) && !istype(custom_materials[1], /datum/material/iron)) + return toolbox + + // Default and custom material iron toolboxes get a random color assigned rather than being greyscale'd + var/toolbox_color = pick("blue", "yellow", "red") + toolbox.icon_state = toolbox_color + toolbox.inhand_icon_state = "toolbox_[toolbox_color]" + toolbox.material_flags &= ~MATERIAL_COLOR + toolbox.remove_atom_colour(FIXED_COLOUR_PRIORITY) + return toolbox + /datum/design/emergency_oxygen name = "Emergency Oxygen Tank" id = "emergency_oxygen" build_type = AUTOLATHE | PROTOLATHE | AWAY_LATHE - materials = list(/datum/material/iron =SMALL_MATERIAL_AMOUNT*5) + materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT*5) build_path = /obj/item/tank/internals/emergency_oxygen/empty category = list( RND_CATEGORY_INITIAL, diff --git a/code/modules/research/designs/autolathe/service_designs.dm b/code/modules/research/designs/autolathe/service_designs.dm index cfad5497e20..3d6720ec469 100644 --- a/code/modules/research/designs/autolathe/service_designs.dm +++ b/code/modules/research/designs/autolathe/service_designs.dm @@ -530,7 +530,7 @@ name = "Material Fishing Rod" id = "fishing_rod_material" build_type = AUTOLATHE - materials = list(MAT_CATEGORY_ITEM_MATERIAL = SMALL_MATERIAL_AMOUNT * 4) + materials = list(/datum/material_requirement/solid_material = SMALL_MATERIAL_AMOUNT * 4) build_path = /obj/item/fishing_rod/material category = list( RND_CATEGORY_INITIAL, diff --git a/code/modules/research/designs/bluespace_designs.dm b/code/modules/research/designs/bluespace_designs.dm index 58bccd53d03..6e586c27d93 100644 --- a/code/modules/research/designs/bluespace_designs.dm +++ b/code/modules/research/designs/bluespace_designs.dm @@ -32,7 +32,7 @@ desc = "A small blue crystal with mystical properties." id = "bluespace_crystal" build_type = PROTOLATHE | AWAY_LATHE - materials = list(/datum/material/diamond =HALF_SHEET_MATERIAL_AMOUNT * 1.5, /datum/material/plasma =HALF_SHEET_MATERIAL_AMOUNT * 1.5) + materials = list(/datum/material/diamond = HALF_SHEET_MATERIAL_AMOUNT * 1.5, /datum/material/plasma = HALF_SHEET_MATERIAL_AMOUNT * 1.5) build_path = /obj/item/stack/ore/bluespace_crystal/artificial category = list( RND_CATEGORY_CONSTRUCTION + RND_SUBCATEGORY_CONSTRUCTION_MATERIALS diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index 435612149a4..7d33c3ed09f 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -446,7 +446,7 @@ desc = "A set of surgical tools hidden behind a concealed panel on the user's arm." id = "ci-surgery" build_type = PROTOLATHE | AWAY_LATHE | MECHFAB - materials = list ( + materials = list( /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.25, /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT * 1.5, /datum/material/silver = HALF_SHEET_MATERIAL_AMOUNT * 1.5, @@ -463,7 +463,7 @@ desc = "A stripped-down version of engineering cyborg toolset, designed to be installed on subject's arm." id = "ci-toolset" build_type = PROTOLATHE | AWAY_LATHE | MECHFAB - materials = list ( + materials = list( /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.25, /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT * 1.5, /datum/material/silver = HALF_SHEET_MATERIAL_AMOUNT * 1.5, diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index 20a552095ef..3a1662c0dab 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -730,7 +730,7 @@ desc = "A royal knight's favorite garments. Can be trimmed by any friendly person." id = "knight_armour" build_type = AUTOLATHE - materials = list(MAT_CATEGORY_ITEM_MATERIAL = SHEET_MATERIAL_AMOUNT*5) + materials = list(/datum/material_requirement/armor_material = SHEET_MATERIAL_AMOUNT * 5) build_path = /obj/item/clothing/suit/armor/riot/knight/greyscale category = list(RND_CATEGORY_IMPORTED) @@ -739,7 +739,7 @@ desc = "A royal knight's favorite hat. If you hold it upside down it's actually a bucket." id = "knight_helmet" build_type = AUTOLATHE - materials = list(MAT_CATEGORY_ITEM_MATERIAL = SHEET_MATERIAL_AMOUNT*2.5) + materials = list(/datum/material_requirement/armor_material = SHEET_MATERIAL_AMOUNT * 2.5) build_path = /obj/item/clothing/head/helmet/knight/greyscale category = list(RND_CATEGORY_IMPORTED) diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 2b702f442b2..1cd6b3134aa 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -604,7 +604,7 @@ desc = "A mace fit for a cleric. Useful for bypassing plate armor, but too bulky for much else." id = "cleric_mace" build_type = AUTOLATHE - materials = list(MAT_CATEGORY_ITEM_MATERIAL = SHEET_MATERIAL_AMOUNT * 4.5, MAT_CATEGORY_ITEM_MATERIAL_COMPLEMENTARY = SHEET_MATERIAL_AMOUNT * 1.5) + materials = list(/datum/material_requirement/solid_material = SHEET_MATERIAL_AMOUNT * 4.5, /datum/material_requirement/rigid_material = SHEET_MATERIAL_AMOUNT * 1.5) build_path = /obj/item/melee/cleric_mace category = list(RND_CATEGORY_IMPORTED) diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index 1134674d93c..646ae764af9 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -250,8 +250,9 @@ var/cost = list() coefficient = build_efficiency(design.build_path) - for(var/datum/material/mat in design.materials) - cost[mat.name] = OPTIMAL_COST(design.materials[mat] * coefficient) + for(var/datum/material/mat as anything in design.materials) + var/amount = design.materials[mat] + cost[mat.name] = OPTIMAL_COST(amount * coefficient) var/icon_size = spritesheet.icon_size_id(design.id) designs[design.id] = list( @@ -346,8 +347,8 @@ //compute power & time to print 1 item var/charge_per_item = 0 - for(var/material in design.materials) - charge_per_item += design.materials[material] + for(var/material, amount in design.materials) + charge_per_item += amount charge_per_item = ROUND_UP((charge_per_item / (MAX_STACK_SIZE * SHEET_MATERIAL_AMOUNT)) * coefficient * active_power_usage) var/build_time_per_item = (design.construction_time * design.lathe_time_factor * efficiency_coeff) ** 0.8 @@ -431,23 +432,21 @@ var/max_stack_amount = initial(stack_item.max_amount) var/number_to_make = (initial(stack_item.amount) * items_remaining) while(number_to_make > max_stack_amount) - created = new stack_item(null, max_stack_amount) //it's imporant to spawn things in nullspace, since obj's like stacks qdel when they enter a tile/merge with other stacks of the same type, resulting in runtimes. + created = design.create_result(target, design_materials, amount = max_stack_amount) if(isitem(created)) created.pixel_x = created.base_pixel_x + rand(-6, 6) created.pixel_y = created.base_pixel_y + rand(-6, 6) - created.forceMove(target) number_to_make -= max_stack_amount - created = new stack_item(null, number_to_make) + created = design.create_result(target, design_materials, amount = number_to_make) else - created = new design.build_path(null) + created = design.create_result(target, design_materials) split_materials_uniformly(design_materials, material_cost_coefficient, created) if(isitem(created)) created.pixel_x = created.base_pixel_x + rand(-6, 6) created.pixel_y = created.base_pixel_y + rand(-6, 6) SSblackbox.record_feedback("nested tally", "lathe_printed_items", 1, list("[type]", "[created.type]")) - created.forceMove(target) if(is_stack) items_remaining = 0 diff --git a/code/modules/unit_tests/armor_verification.dm b/code/modules/unit_tests/armor_verification.dm index ef4613e49f1..14fc3dfa905 100644 --- a/code/modules/unit_tests/armor_verification.dm +++ b/code/modules/unit_tests/armor_verification.dm @@ -28,6 +28,6 @@ /datum/unit_test/armor_verification/proc/armor_totals(datum/armor/armor) var/total = 0 - for(var/key in ARMOR_LIST_ALL()) + for(var/key in ARMOR_LIST_ALL) total += armor.vars[key] return total diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 4aa974f0de3..89df835c034 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -571,7 +571,7 @@ var/datum/armor/armor = get_armor() var/added_damage_header = FALSE - for(var/damage_key in ARMOR_LIST_DAMAGE()) + for(var/damage_key in ARMOR_LIST_DAMAGE) var/rating = armor.get_rating(damage_key) if(!rating) continue @@ -581,7 +581,7 @@ readout += "[armor_to_protection_name(damage_key)] [armor_to_protection_class(rating)]" var/added_durability_header = FALSE - for(var/durability_key in ARMOR_LIST_DURABILITY()) + for(var/durability_key in ARMOR_LIST_DURABILITY) var/rating = armor.get_rating(durability_key) if(!rating) continue diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm index 4175c1fc0b6..4e1fbbdc1ea 100644 --- a/code/modules/vehicles/mecha/mech_fabricator.dm +++ b/code/modules/vehicles/mecha/mech_fabricator.dm @@ -281,7 +281,7 @@ * * dispensed_design - Design datum to attempt to dispense. */ /obj/machinery/mecha_part_fabricator/proc/dispense_built_part(datum/design/dispensed_design) - var/obj/item/built_part = new dispensed_design.build_path(src) + var/obj/item/built_part = dispensed_design.create_result(src) SSblackbox.record_feedback("nested tally", "lathe_printed_items", 1, list("[type]", "[built_part.type]")) being_built = null diff --git a/code/modules/wiremod/core/component_printer.dm b/code/modules/wiremod/core/component_printer.dm index 48baef54b89..cda5a9adee1 100644 --- a/code/modules/wiremod/core/component_printer.dm +++ b/code/modules/wiremod/core/component_printer.dm @@ -137,7 +137,7 @@ return materials.use_materials(design.materials, efficiency_coeff, 1, "processed", "[design.name]", user_data) - return new design.build_path(drop_location()) + return design.create_result(drop_location()) /obj/machinery/component_printer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() @@ -165,7 +165,7 @@ balloon_alert_to_viewers("printed [design.name]") materials.use_materials(design.materials, efficiency_coeff, 1, "processed", "[design.name]", user_data) - var/atom/printed_design = new design.build_path(drop_location()) + var/atom/printed_design = design.create_result(drop_location()) printed_design.pixel_x = printed_design.base_pixel_x + rand(-5, 5) printed_design.pixel_y = printed_design.base_pixel_y + rand(-5, 5) if ("remove_mat") @@ -196,8 +196,8 @@ continue var/list/cost = list() - for(var/datum/material/mat in design.materials) - cost[mat.name] = OPTIMAL_COST(design.materials[mat] * efficiency_coeff) + for(var/datum/material/mat, amount in design.materials) + cost[mat.name] = OPTIMAL_COST(amount * efficiency_coeff) var/icon_size = spritesheet.icon_size_id(design.id) designs[researched_design_id] = list( @@ -461,7 +461,7 @@ data["name"] = module.display_name data["desc"] = "A module that has been loaded in by [user]." - data["materials"] = list(GET_MATERIAL_REF(/datum/material/glass) = module.circuit_size * cost_per_component) + data["materials"] = list(SSmaterials.get_material(/datum/material/glass) = module.circuit_size * cost_per_component) else if(istype(weapon, /obj/item/integrated_circuit)) var/obj/item/integrated_circuit/integrated_circuit = weapon if(HAS_TRAIT(integrated_circuit, TRAIT_CIRCUIT_UNDUPABLE)) @@ -473,9 +473,9 @@ data["desc"] = "An integrated circuit that has been loaded in by [user]." var/datum/design/integrated_circuit/circuit_design = SSresearch.techweb_design_by_id("integrated_circuit") - var/materials = list(GET_MATERIAL_REF(/datum/material/glass) = integrated_circuit.current_size * cost_per_component) - for(var/material_type in circuit_design.materials) - materials[material_type] += circuit_design.materials[material_type] + var/materials = list(SSmaterials.get_material(/datum/material/glass) = integrated_circuit.current_size * cost_per_component) + for(var/material_type, amount in circuit_design.materials) + materials[material_type] += amount data["materials"] = materials data["integrated_circuit"] = TRUE diff --git a/tgstation.dme b/tgstation.dme index a8f3b57cedb..5c48665d7ee 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -354,6 +354,7 @@ #include "code\__DEFINES\dcs\signals\signals_lockable_storage.dm" #include "code\__DEFINES\dcs\signals\signals_market.dm" #include "code\__DEFINES\dcs\signals\signals_material_container.dm" +#include "code\__DEFINES\dcs\signals\signals_materials.dm" #include "code\__DEFINES\dcs\signals\signals_medical.dm" #include "code\__DEFINES\dcs\signals\signals_mind.dm" #include "code\__DEFINES\dcs\signals\signals_mining.dm" @@ -1803,6 +1804,10 @@ #include "code\datums\materials\hauntium.dm" #include "code\datums\materials\meat.dm" #include "code\datums\materials\pizza.dm" +#include "code\datums\materials\properties\_properties.dm" +#include "code\datums\materials\properties\derived.dm" +#include "code\datums\materials\properties\optional.dm" +#include "code\datums\materials\requirements\_requirement.dm" #include "code\datums\memory\_memory.dm" #include "code\datums\memory\general_memories.dm" #include "code\datums\memory\key_memories.dm"