Skip to content

Commit

Permalink
Basemats Part 1: Framework & Fixes (#10135)
Browse files Browse the repository at this point in the history
* initial

* fix broken recipes

* tgstation/tgstation#46994

* tgstation/tgstation#54178

* tgstation/tgstation#48586

* condenses table code, adds more checks

* tgstation/tgstation#56156

* fix conflicts with knives

* tgstation/tgstation#49173

* tgstation/tgstation#47049

* tgstation/tgstation#48584

* more conflict fixes

* base recipes

* reducee lists & fix uncraftable chairs

* cleanup basemat colors, turn into color matrices

* fix

* glass chairs snowflake

* feex

* remove glass & diamond from basemats for now

* tgstation/tgstation#54858

* tgstation/tgstation#61166
  • Loading branch information
Tsar-Salat committed Dec 19, 2023
1 parent 1a29c10 commit cf39ea7
Show file tree
Hide file tree
Showing 209 changed files with 1,045 additions and 838 deletions.
17 changes: 10 additions & 7 deletions code/__DEFINES/materials.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
/// Hard materials, such as iron or metal
#define MAT_CATEGORY_RIGID "rigid material"

///Use this flag on TRUE if you want the basic recipes
#define MAT_CATEGORY_BASE_RECIPES "basic recipes"

/// Gets the reference for the material type that was given
#define getmaterialref(A) (SSmaterials.materials[A])

/// Flag for atoms, this flag ensures it isn't re-colored by materials. Useful for snowflake icons such as default toolboxes.
#define MATERIAL_NO_COLOR (1<<0)
/// Applies the material greyscale color to the atom's greyscale color.
#define MATERIAL_GREYSCALE (1<<1)
/// Whether a material's mechanical effects should apply to the atom. This is necessary for other flags to work.
#define MATERIAL_EFFECTS (1<<0)
/// Applies the material color to the atom's color. Deprecated, use MATERIAL_GREYSCALE instead
#define MATERIAL_COLOR (1<<1)
/// Whether a prefix describing the material should be added to the name
#define MATERIAL_ADD_PREFIX (1<<2)
/// Whether a material should affect the stats of the atom
#define MATERIAL_AFFECT_STATISTICS (1<<3)
/// Applies the material greyscale color to the atom's greyscale color.
#define MATERIAL_GREYSCALE (1<<4)

/// Create standardized stack sizes.

Expand Down
1 change: 0 additions & 1 deletion code/__DEFINES/subsystems.dm
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@
#define INIT_ORDER_GREYSCALE 81
#define INIT_ORDER_VIS 80
#define INIT_ORDER_ACHIEVEMENTS 77
#define INIT_ORDER_MATERIALS 76
#define INIT_ORDER_RESEARCH 75
#define INIT_ORDER_ORBITS 74 //Other things use the orbital map, so it needs to be made early on.
#define INIT_ORDER_STATION 73 //This is high priority because it manipulates a lot of the subsystems that will initialize after it.
Expand Down
46 changes: 37 additions & 9 deletions code/controllers/subsystem/materials.dm
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,49 @@ These materials call on_applied() on whatever item they are applied to, common e

SUBSYSTEM_DEF(materials)
name = "Materials"
flags = SS_NO_FIRE
init_order = INIT_ORDER_MATERIALS
flags = SS_NO_FIRE | SS_NO_INIT
///Dictionary of material.type || material ref
var/list/materials = list()
var/list/materials
///Dictionary of category || list of material refs
var/list/materials_by_category = list()

/datum/controller/subsystem/materials/Initialize(timeofday)
InitializeMaterials()
return ..()
var/list/materials_by_category
///A cache of all material combinations that have been used
var/list/list/material_combos
///List of stackcrafting recipes for materials using rigid materials
var/list/rigid_stack_recipes = list(
new /datum/stack_recipe("chair", /obj/structure/chair/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
)

///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(timeofday)
/datum/controller/subsystem/materials/proc/InitializeMaterials()
materials = list()
materials_by_category = list()
material_combos = list()
for(var/type in subtypesof(/datum/material))
var/datum/material/ref = new type
materials[type] = ref
for(var/c in ref.categories)
materials_by_category[c] += list(ref)

/datum/controller/subsystem/materials/proc/GetMaterialRef(datum/material/fakemat)
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.
/datum/controller/subsystem/materials/proc/FindOrCreateMaterialCombo(list/materials_declaration, multiplier)
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]"
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
material_combos[combo_index] = combo
return combo
2 changes: 1 addition & 1 deletion code/datums/components/explodable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
/datum/component/explodable/proc/on_equip(datum/source, mob/equipper, slot)
SIGNAL_HANDLER

RegisterSignal(equipper, COMSIG_MOB_APPLY_DAMGE, PROC_REF(explodable_attack_zone))
RegisterSignal(equipper, COMSIG_MOB_APPLY_DAMGE, PROC_REF(explodable_attack_zone), TRUE)

/datum/component/explodable/proc/on_drop(datum/source, mob/user)
SIGNAL_HANDLER
Expand Down
67 changes: 17 additions & 50 deletions code/datums/components/material_container.dm
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(OnExamine))

for(var/mat in mat_list) //Make the assoc list ref | amount
var/datum/material/M = getmaterialref(mat) || mat
var/datum/material/M = SSmaterials.GetMaterialRef(mat)
materials[M] = 0

/datum/component/material_container/proc/OnExamine(datum/source, mob/user)
Expand Down Expand Up @@ -75,10 +75,10 @@
return
var/material_amount = get_item_material_amount(I)
if(!material_amount)
to_chat(user, "<span class='warning'>[I] does not contain sufficient amounts of metal or glass to be accepted by [parent].</span>")
to_chat(user, "<span class='warning'>[I] does not contain sufficient materials to be accepted by [parent].</span>")
return
if(!has_space(material_amount))
to_chat(user, "<span class='warning'>[parent] is full. Please remove metal or glass from [parent] in order to insert more.</span>")
to_chat(user, "<span class='warning'>[parent] is full. Please remove materials from [parent] in order to insert more.</span>")
return
user_insert(I, user)

Expand All @@ -100,27 +100,17 @@
return
var/inserted = insert_item(I, stack_amt = requested_amount)
if(inserted)
if(istype(I, /obj/item/stack))
var/obj/item/stack/S = I
to_chat(user, "<span class='notice'>You insert [inserted] [S.singular_name][inserted>1 ? "s" : ""] into [parent].</span>")
if(!QDELETED(I) && I == active_held && !user.put_in_hands(I))
stack_trace("Warning: User could not put object back in hand during material container insertion, line [__LINE__]! This can lead to issues.")
I.forceMove(user.drop_location())
else
to_chat(user, "<span class='notice'>You insert a material total of [inserted] into [parent].</span>")
SEND_SIGNAL(I, COMSIG_OBJ_DECONSTRUCT) //Help prevent using material ingestors to void storage items.
qdel(I)
to_chat(user, "<span class='notice'>You insert a material total of [inserted] into [parent].</span>")
qdel(I)
if(after_insert)
after_insert.Invoke(I.type, last_inserted_id, inserted)
after_insert.Invoke(I, last_inserted_id, inserted)
else if(I == active_held)
user.put_in_active_hand(I)

/// Proc specifically for inserting items, returns the amount of materials entered.
/datum/component/material_container/proc/insert_item(obj/item/I, var/multiplier = 1, stack_amt)
if(QDELETED(I))
return FALSE
if(istype(I, /obj/item/stack))
return insert_stack(I, stack_amt, multiplier)

multiplier = CEILING(multiplier, 0.01)

Expand All @@ -135,41 +125,18 @@
var/primary_mat
var/max_mat_value = 0
for(var/MAT in materials)
materials[MAT] += I.materials[MAT] * multiplier
total_amount += I.materials[MAT] * multiplier
if(I.materials[MAT] > max_mat_value)
materials[MAT] += I.custom_materials[MAT] * multiplier
total_amount += I.custom_materials[MAT] * multiplier
if(I.custom_materials[MAT] > max_mat_value)
primary_mat = MAT
if(primary_mat)
SEND_SIGNAL(parent, COMSIG_MATERIAL_CONTAINER_CHANGED)
return primary_mat

/// Proc for putting a stack inside of the container
/datum/component/material_container/proc/insert_stack(obj/item/stack/S, amt, multiplier = 1)
if(isnull(amt))
amt = S.amount

if(amt <= 0)
return FALSE

if(amt > S.amount)
amt = S.amount

var/material_amt = get_item_material_amount(S)
if(!material_amt)
return FALSE

amt = min(amt, round(((max_amount - total_amount) / material_amt)))
if(!amt)
return FALSE

last_inserted_id = insert_item_materials(S,amt * multiplier)
S.use(amt)
return amt

/// For inserting an amount of material
/datum/component/material_container/proc/insert_amount_mat(amt, var/datum/material/mat)
if(!istype(mat))
mat = getmaterialref(mat)
mat = SSmaterials.GetMaterialRef(mat)
if(amt > 0 && has_space(amt))
var/total_amount_saved = total_amount
if(mat)
Expand All @@ -185,7 +152,7 @@
/// Uses an amount of a specific material, effectively removing it.
/datum/component/material_container/proc/use_amount_mat(amt, var/datum/material/mat)
if(!istype(mat))
mat = getmaterialref(mat)
mat = SSmaterials.GetMaterialRef(mat)
var/amount = materials[mat]
if(mat)
if(amount >= amt)
Expand All @@ -198,7 +165,7 @@
/// Proc for transfering materials to another container.
/datum/component/material_container/proc/transer_amt_to(var/datum/component/material_container/T, amt, var/datum/material/mat)
if(!istype(mat))
mat = getmaterialref(mat)
mat = SSmaterials.GetMaterialRef(mat)
if((amt==0)||(!T)||(!mat))
return FALSE
if(amt<0)
Expand Down Expand Up @@ -232,7 +199,7 @@
for(var/x in mats) //Loop through all required materials
var/datum/material/req_mat = x
if(!istype(req_mat))
req_mat = getmaterialref(req_mat) //Get the ref if necesary
req_mat = SSmaterials.GetMaterialRef(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
Expand Down Expand Up @@ -295,7 +262,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 = getmaterialref(req_mat) //Get the ref
req_mat = SSmaterials.GetMaterialRef(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?
Expand Down Expand Up @@ -350,17 +317,17 @@

///returns the amount of material relevant to this container; if this container does not support glass, any glass in 'I' will not be taken into account
/datum/component/material_container/proc/get_item_material_amount(obj/item/I)
if(!istype(I))
if(!istype(I) || !I.custom_materials)
return FALSE
var/material_amount = 0
for(var/MAT in materials)
material_amount += I.materials[MAT]
material_amount += I.custom_materials[MAT]
return material_amount

/// Returns the amount of a specific material in this container.
/datum/component/material_container/proc/get_material_amount(var/datum/material/mat)
if(!istype(mat))
mat = getmaterialref(mat)
mat = SSmaterials.GetMaterialRef(mat)
return materials[mat]

/// List format is list(material_name = list(amount = ..., ref = ..., etc.))
Expand Down
3 changes: 2 additions & 1 deletion code/datums/components/storage/concrete/stack.dm
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
_S.add(can_insert)
S.use(can_insert, TRUE)
return TRUE
return ..(S.change_stack(null, can_insert), override)
I = S.split_stack(null, can_insert)
return ..()

/datum/component/storage/concrete/stack/remove_from_storage(obj/item/I, atom/new_location)
var/atom/real_location = real_location()
Expand Down
4 changes: 2 additions & 2 deletions code/datums/elements/firestacker.dm
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

RegisterSignal(target, COMSIG_MOVABLE_IMPACT, PROC_REF(impact), override = TRUE)
if(isitem(target))
RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(item_attack))
RegisterSignal(target, COMSIG_ITEM_ATTACK_SELF, PROC_REF(item_attack_self))
RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(item_attack), override = TRUE)
RegisterSignal(target, COMSIG_ITEM_ATTACK_SELF, PROC_REF(item_attack_self), override = TRUE)

/datum/element/firestacker/Detach(datum/source)
. = ..()
Expand Down
2 changes: 1 addition & 1 deletion code/datums/holocall.dm
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@
desc = "Stores recorder holocalls."
icon_state = "holodisk"
obj_flags = UNIQUE_RENAME
materials = list(/datum/material/iron = 100, /datum/material/glass = 100)
custom_materials = list(/datum/material/iron = 100, /datum/material/glass = 100)
var/datum/holorecord/record
//Preset variables
var/preset_image_type
Expand Down
44 changes: 27 additions & 17 deletions code/datums/materials/_material.dm
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,26 @@ Simple datum which is instanced once per type and is used for every object of sa
var/greyscale_colors
///Base alpha of the material, is used for greyscale icons.
var/alpha
///Materials "Traits". its a map of key = category | Value = Bool. Used to define what it can be used for.gold
///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.
///The type of sheet this material creates. This should be replaced as soon as possible by greyscale sheets
var/sheet_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
///This is the amount of value per 1 unit of the material
var/value_per_unit = 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, "rad" = 1, "fire" = 1, "acid" = 1)
///How beautiful is this material per unit
var/beauty_modifier = 0
*/

///This proc is called when the material is added to an object.
/datum/material/proc/on_applied(atom/source, amount, material_flags)
if(!(material_flags & MATERIAL_NO_COLOR)) //Prevent changing things with pre-set colors, to keep colored toolboxes their looks for example
if(material_flags & MATERIAL_COLOR) //Prevent changing things with pre-set colors, to keep colored toolboxes their looks for example
if(color) //Do we have a custom color?
source.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
if(alpha)
Expand All @@ -48,12 +54,18 @@ Simple datum which is instanced once per type and is used for every object of sa

///This proc is called when the material is added to an object specifically.
/datum/material/proc/on_applied_obj(obj/o, amount, material_flags)
var/new_max_integrity = CEILING(o.max_integrity * integrity_modifier, 1)
// This is to keep the same damage relative to the max integrity of the object
o.obj_integrity = (o.obj_integrity / o.max_integrity) * new_max_integrity
o.max_integrity = new_max_integrity
o.force *= strength_modifier
o.throwforce *= strength_modifier
if(material_flags & MATERIAL_AFFECT_STATISTICS)
var/new_max_integrity = CEILING(o.max_integrity * integrity_modifier, 1)
o.modify_max_integrity(new_max_integrity)
o.force *= strength_modifier
o.throwforce *= strength_modifier

/*
var/list/temp_armor_list = list() //Time to add armor modifiers!
if(!istype(o.armor))
return
*/

if(!isitem(o))
return
Expand All @@ -73,7 +85,7 @@ Simple datum which is instanced once per type and is used for every object of sa

///This proc is called when the material is removed from an object.
/datum/material/proc/on_removed(atom/source, material_flags)
if(!(material_flags & MATERIAL_NO_COLOR)) //Prevent changing things with pre-set colors, to keep colored toolboxes their looks for example
if(material_flags & MATERIAL_COLOR) //Prevent changing things with pre-set colors, to keep colored toolboxes their looks for example
if(color)
source.remove_atom_colour(FIXED_COLOUR_PRIORITY, color)
source.alpha = initial(source.alpha)
Expand All @@ -89,13 +101,11 @@ Simple datum which is instanced once per type and is used for every object of sa

///This proc is called when the material is removed from an object specifically.
/datum/material/proc/on_removed_obj(var/obj/o, amount, material_flags)
var/new_max_integrity = initial(o.max_integrity)
// This is to keep the same damage relative to the max integrity of the object
o.obj_integrity = (o.obj_integrity / o.max_integrity) * new_max_integrity

o.max_integrity = new_max_integrity
o.force = initial(o.force)
o.throwforce = initial(o.throwforce)
if(material_flags & MATERIAL_AFFECT_STATISTICS)
var/new_max_integrity = initial(o.max_integrity)
o.modify_max_integrity(new_max_integrity)
o.force = initial(o.force)
o.throwforce = initial(o.throwforce)

if(isitem(o) && (material_flags & MATERIAL_GREYSCALE))
var/obj/item/item = o
Expand Down
Loading

0 comments on commit cf39ea7

Please sign in to comment.