Material Science 1: A bunch of math (#95090)

This commit is contained in:
SmArtKar
2026-02-22 16:53:51 +11:00
committed by GitHub
parent 6561c841d0
commit a3498fdcd7
95 changed files with 1816 additions and 1435 deletions
+106 -71
View File
@@ -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
+2 -2
View File
@@ -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