[READY] Bespoke Datum Mats (#55296)

* Bespoke Material Backend

- Adds support for bespoke materials:
  - Reimplements [/datum/material/var/id]
  - Ports GetIdFromArguments from SSdcs
  - Adds a wrapper define for GetMaterialRef
  - Adds [MATERIAL_INIT_BESPOKE]
  - Adds [/datum/material/proc/Initialize]
- Does not actually add any bespoke materials

- [ ] TODO: Code docs
- [ ] TODO: Actually adding bespoke materials

* Some has_material procs and cleaning up some spaghetti

- Adds a pair of has_material procs for use in checking whether a given atom has a given material

* Adds meat

- Adds bespoke meat variants
  - Does not make them accessible
- Shuts up the linter

* Implements bespoke meat

- Makes the material container preserve bespoke materials
- Makes the sheetifier accept bespoke materials
- Makes the autolathe accept bespoke materials
- Makes the gibber produce bespoke meats

* Makes butchering produce bespoke meats

This is jank and really needs to be folded into a unified butchering and gibbing system

* Material documentation

- Adds, fixes, and touches up some documentation

* Material container insertion callback

- Changes the proc used to expand the material container's material list ot a proc used to check whether a material fits into a material container
- Instantiating new materials is no longer O(n) relative to the number of autolathes in existence.

* Makes processing meat conserve materials

- Makes bespoke meat carry over into meatballs

* Makes preserving custom materials an option

- Implements the ability to turn preserving custom materials _off_ for processor recipes

* Fixes all bespoke materials of the same type using the same singleton

- We use ids now, not just types.

* Makes the fat sucker produce bespoke meats

- Because consistency is good.

* Fixes autolathes merging bespoke stacks into normal stacks.

* Makes the callback to test materials for holdibility optional

- @Floyd

* GetMaterialRef -> GET_MATERIAL_REF

- We capitalize macros.

* Removes an extraneous callback

- Makes the sheetifier use functionality I didn't notice I implemented a few commits ago.

* Makes mob and species meat null compatible

* Fixes the ore silo

- The ore silo had really snowflake material handling that has been brought in line with the rest.
- The materials should show up in the correct order.

* Fixes minor lathe bugs

- Fixes stack_traces caused when lathes tried to fetch materials using reagent typepaths
- Fixed the selective reagent disposal topic. I have no idea how long this has been broken.

* Various documentation fixes

- Clarified a couple comments
- Removes an extraneous ?. operator
- Fixed mat floor tiles having bugged reagent temperatures

* More fixes

-/datum/material/meat/mob -> /datum/material/meat/mob_meat
- Adds atom typecheck to material containers.

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