diff --git a/code/__DEFINES/_flags/_flags.dm b/code/__DEFINES/_flags/_flags.dm
index b1324000b8..7daf9fa8a3 100644
--- a/code/__DEFINES/_flags/_flags.dm
+++ b/code/__DEFINES/_flags/_flags.dm
@@ -145,4 +145,19 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
/// If the thing can reflect light (lasers/energy)
#define RICOCHET_SHINY (1<<0)
/// If the thing can reflect matter (bullets/bomb shrapnel)
-#define RICOCHET_HARD (1<<1)
\ No newline at end of file
+#define RICOCHET_HARD (1<<1)
+
+#define KEEP_TOGETHER_ORIGINAL "keep_together_original"
+
+//setter for KEEP_TOGETHER to allow for multiple sources to set and unset it
+#define ADD_KEEP_TOGETHER(x, source)\
+ if ((x.appearance_flags & KEEP_TOGETHER) && !HAS_TRAIT(x, TRAIT_KEEP_TOGETHER)) ADD_TRAIT(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL); \
+ ADD_TRAIT(x, TRAIT_KEEP_TOGETHER, source);\
+ x.appearance_flags |= KEEP_TOGETHER
+
+#define REMOVE_KEEP_TOGETHER(x, source)\
+ REMOVE_TRAIT(x, TRAIT_KEEP_TOGETHER, source);\
+ if(HAS_TRAIT_FROM_ONLY(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL))\
+ REMOVE_TRAIT(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL);\
+ else if(!HAS_TRAIT(x, TRAIT_KEEP_TOGETHER))\
+ x.appearance_flags &= ~KEEP_TOGETHER
diff --git a/code/__DEFINES/_flags/item_flags.dm b/code/__DEFINES/_flags/item_flags.dm
index c6a3886ed3..b3b65bcf59 100644
--- a/code/__DEFINES/_flags/item_flags.dm
+++ b/code/__DEFINES/_flags/item_flags.dm
@@ -52,3 +52,4 @@
#define ORGAN_VITAL (1<<4) //Currently only the brain
#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances
#define ORGAN_NO_DISMEMBERMENT (1<<6) //Immune to disembowelment.
+#define ORGAN_EDIBLE (1<<5) //is a snack? :D
\ No newline at end of file
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index 8a88f2dbb6..38524d0e0c 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -35,6 +35,7 @@
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
#define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
+#define COMSIG_ATOM_ATTACK_ANIMAL "attack_animal" //from base of atom/animal_attack(): (/mob/user)
#define COMSIG_PARENT_EXAMINE "atom_examine" //from base of atom/examine(): (/mob, list/examine_return_text)
#define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name" //from base of atom/get_examine_name(): (/mob, list/overrides)
//Positions for overrides list
@@ -280,6 +281,7 @@
#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
#define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args)
#define COMSIG_ITEM_WEARERCROSSED "wearer_crossed" //called on item when crossed by something (): (/atom/movable)
+#define COMSIG_ITEM_MICROWAVE_ACT "microwave_act" //called on item when microwaved (): (obj/machinery/microwave/M)
#define COMSIG_ITEM_WORN_OVERLAYS "item_worn_overlays" //from base of obj/item/worn_overlays(): (isinhands, icon_file, used_state, style_flags, list/overlays)
// THE FOLLOWING TWO BLOCKS SHOULD RETURN BLOCK FLAGS AS DEFINED IN __DEFINES/combat.dm!
#define COMSIG_ITEM_CHECK_BLOCK "check_block" //from base of obj/item/check_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
diff --git a/code/__DEFINES/food.dm b/code/__DEFINES/food.dm
index a347fd7327..77e8d82aca 100644
--- a/code/__DEFINES/food.dm
+++ b/code/__DEFINES/food.dm
@@ -18,4 +18,8 @@
#define DRINK_VERYGOOD 3
#define DRINK_FANTASTIC 4
#define FOOD_AMAZING 5
-#define RACE_DRINK 6
\ No newline at end of file
+#define RACE_DRINK 6
+
+#define FOOD_IN_CONTAINER (1<<0)
+
+#define STOP_SERVING_BREAKFAST (15 MINUTES)
diff --git a/code/__DEFINES/footsteps.dm b/code/__DEFINES/footsteps.dm
index 5acda2274c..2dd66b9833 100644
--- a/code/__DEFINES/footsteps.dm
+++ b/code/__DEFINES/footsteps.dm
@@ -6,6 +6,7 @@
#define FOOTSTEP_GRASS "grass"
#define FOOTSTEP_WATER "water"
#define FOOTSTEP_LAVA "lava"
+#define FOOTSTEP_MEAT "meat"
//barefoot sounds
#define FOOTSTEP_WOOD_BAREFOOT "woodbarefoot"
#define FOOTSTEP_WOOD_CLAW "woodclaw"
@@ -89,6 +90,8 @@ GLOBAL_LIST_INIT(footstep, list(
'sound/effects/footstep/lava1.ogg',
'sound/effects/footstep/lava2.ogg',
'sound/effects/footstep/lava3.ogg'), 100, 0),
+ FOOTSTEP_MEAT = list(list(
+ 'sound/effects/meatslap.ogg'), 100, 0)
))
//bare footsteps lists
@@ -131,6 +134,8 @@ GLOBAL_LIST_INIT(barefootstep, list(
'sound/effects/footstep/lava1.ogg',
'sound/effects/footstep/lava2.ogg',
'sound/effects/footstep/lava3.ogg'), 100, 0),
+ FOOTSTEP_MEAT = list(list(
+ 'sound/effects/meatslap.ogg'), 100, 0)
))
//claw footsteps lists
@@ -173,6 +178,8 @@ GLOBAL_LIST_INIT(clawfootstep, list(
'sound/effects/footstep/lava1.ogg',
'sound/effects/footstep/lava2.ogg',
'sound/effects/footstep/lava3.ogg'), 100, 0),
+ FOOTSTEP_MEAT = list(list(
+ 'sound/effects/meatslap.ogg'), 100, 0)
))
//heavy footsteps list
@@ -189,4 +196,6 @@ GLOBAL_LIST_INIT(heavyfootstep, list(
'sound/effects/footstep/lava1.ogg',
'sound/effects/footstep/lava2.ogg',
'sound/effects/footstep/lava3.ogg'), 100, 0),
+ FOOTSTEP_MEAT = list(list(
+ 'sound/effects/meatslap.ogg'), 100, 0)
))
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index de9ada7560..90c7c34f8d 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -135,6 +135,8 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define iscat(A) (istype(A, /mob/living/simple_animal/pet/cat))
+#define isdog(A) (istype(A, /mob/living/simple_animal/pet/dog))
+
#define iscorgi(A) (istype(A, /mob/living/simple_animal/pet/dog/corgi))
#define ishostile(A) (istype(A, /mob/living/simple_animal/hostile))
diff --git a/code/__DEFINES/materials.dm b/code/__DEFINES/materials.dm
index e2ae22345f..e7e62aafe1 100644
--- a/code/__DEFINES/materials.dm
+++ b/code/__DEFINES/materials.dm
@@ -4,8 +4,13 @@
/// 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"
+
/// Flag for atoms, this flag ensures it isn't re-colored by materials. Useful for snowflake icons such as default toolboxes.
#define MATERIAL_COLOR (1<<0)
#define MATERIAL_ADD_PREFIX (1<<1)
#define MATERIAL_EFFECTS (1<<2)
-#define MATERIAL_AFFECT_STATISTICS (1<<3)
\ No newline at end of file
+#define MATERIAL_AFFECT_STATISTICS (1<<3)
+
+#define MATERIAL_SOURCE(mat) "[mat.name]_material"
\ No newline at end of file
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 3977b3c085..eb86c52301 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -61,6 +61,12 @@
} while (0)
#define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE)
#define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE)
+#define HAS_TRAIT_FROM_ONLY(target, trait, source) (\
+ target.status_traits ?\
+ (target.status_traits[trait] ?\
+ ((source in target.status_traits[trait]) && (length(target.status_traits) == 1))\
+ : FALSE)\
+ : FALSE)
#define HAS_TRAIT_NOT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (length(target.status_traits[trait] - source) > 0) : FALSE) : FALSE)
//mob traits
@@ -226,6 +232,8 @@
#define VEHICLE_TRAIT "vehicle" // inherited from riding vehicles
#define INNATE_TRAIT "innate"
+///Used for managing KEEP_TOGETHER in [appearance_flags]
+#define TRAIT_KEEP_TOGETHER "keep-together"
// item traits
#define TRAIT_NODROP "nodrop"
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index d4ec44a641..059f9d518e 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -108,7 +108,7 @@
A.attack_animal(src)
/atom/proc/attack_animal(mob/user)
- return
+ SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_ANIMAL, user)
/mob/living/RestrainedClickOn(atom/A)
return
diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm
index 96d733e8da..23d5a7a2b7 100644
--- a/code/controllers/subsystem/materials.dm
+++ b/code/controllers/subsystem/materials.dm
@@ -10,24 +10,52 @@ SUBSYSTEM_DEF(materials)
var/list/materials
///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
+ ///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),
new /datum/stack_recipe("toilet", /obj/structure/toilet/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
new /datum/stack_recipe("sink", /obj/structure/sink/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
+ new /datum/stack_recipe("Floor tile", /obj/item/stack/tile/material, 1, 4, 20, 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()
materials = list()
materials_by_category = list()
+ materialtypes_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)
+ materialtypes_by_category[c] += list(type)
/datum/controller/subsystem/materials/proc/GetMaterialRef(datum/material/fakemat)
if(!materials)
InitializeMaterials()
- return materials[fakemat] || fakemat
\ No newline at end of file
+ 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
diff --git a/code/datums/components/edible.dm b/code/datums/components/edible.dm
new file mode 100644
index 0000000000..b2b75ab032
--- /dev/null
+++ b/code/datums/components/edible.dm
@@ -0,0 +1,243 @@
+/*!
+This component makes it possible to make things edible. What this means is that you can take a bite or force someone to take a bite (in the case of items).
+These items take a specific time to eat, and can do most of the things our original food items could.
+Behavior that's still missing from this component that original food items had that should either be put into seperate components or somewhere else:
+ Components:
+ Drying component (jerky etc)
+ Customizable component (custom pizzas etc)
+ Processable component (Slicing and cooking behavior essentialy, making it go from item A to B when conditions are met.)
+ Dunkable component (Dunking things into reagent containers to absorb a specific amount of reagents)
+ Misc:
+ Something for cakes (You can store things inside)
+*/
+/datum/component/edible
+ ///Amount of reagents taken per bite
+ var/bite_consumption = 2
+ ///Amount of bites taken so far
+ var/bitecount = 0
+ ///Flags for food
+ var/food_flags = NONE
+ ///Bitfield of the types of this food
+ var/foodtypes = NONE
+ ///Amount of seconds it takes to eat this food
+ var/eat_time = 30
+ ///Defines how much it lowers someones satiety (Need to eat, essentialy)
+ var/junkiness = 0
+ ///Message to send when eating
+ var/list/eatverbs
+ ///Callback to be ran for when you take a bite of something
+ var/datum/callback/after_eat
+ ///Last time we checked for food likes
+ var/last_check_time
+
+/datum/component/edible/Initialize(list/initial_reagents, food_flags = NONE, foodtypes = NONE, volume = 50, eat_time = 30, list/tastes, list/eatverbs = list("bite","chew","nibble","gnaw","gobble","chomp"), bite_consumption = 2, datum/callback/after_eat)
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
+ RegisterSignal(parent, COMSIG_ATOM_ATTACK_ANIMAL, .proc/UseByAnimal)
+ if(isitem(parent))
+ RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/UseFromHand)
+ else if(isturf(parent))
+ RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/TryToEatTurf)
+
+ src.bite_consumption = bite_consumption
+ src.food_flags = food_flags
+ src.foodtypes = foodtypes
+ src.eat_time = eat_time
+ src.eatverbs = eatverbs
+ src.junkiness = junkiness
+ src.after_eat = after_eat
+
+ var/atom/owner = parent
+
+ owner.create_reagents(volume, INJECTABLE)
+
+ if(initial_reagents)
+ for(var/rid in initial_reagents)
+ var/amount = initial_reagents[rid]
+ if(tastes && tastes.len && (rid == /datum/reagent/consumable/nutriment || rid == /datum/reagent/consumable/nutriment/vitamin))
+ owner.reagents.add_reagent(rid, amount, tastes.Copy())
+ else
+ owner.reagents.add_reagent(rid, amount)
+
+/datum/component/edible/proc/examine(datum/source, mob/user, list/examine_list)
+ if(!(food_flags & FOOD_IN_CONTAINER))
+ switch (bitecount)
+ if (0)
+ return
+ if(1)
+ examine_list += "[parent] was bitten by someone!"
+ if(2,3)
+ examine_list += "[parent] was bitten [bitecount] times!"
+ else
+ examine_list += "[parent] was bitten multiple times!"
+
+/datum/component/edible/proc/UseFromHand(obj/item/source, mob/living/M, mob/living/user)
+ return TryToEat(M, user)
+
+/datum/component/edible/proc/TryToEatTurf(datum/source, mob/user)
+ return TryToEat(user, user)
+
+///All the checks for the act of eating itself and
+/datum/component/edible/proc/TryToEat(mob/living/eater, mob/living/feeder)
+
+ set waitfor = FALSE
+
+ var/atom/owner = parent
+
+ if(feeder.a_intent == INTENT_HARM)
+ return
+ if(!owner.reagents.total_volume)//Shouldn't be needed but it checks to see if it has anything left in it.
+ to_chat(feeder, "None of [owner] left, oh no!")
+ if(isturf(parent))
+ var/turf/T = parent
+ T.ScrapeAway(1, CHANGETURF_INHERIT_AIR)
+ else
+ qdel(parent)
+ return
+ if(!CanConsume(eater, feeder))
+ return
+ var/fullness = eater.nutrition + 10 //The theoretical fullness of the person eating if they were to eat this
+ for(var/datum/reagent/consumable/C in eater.reagents.reagent_list) //we add the nutrition value of what we're currently digesting
+ fullness += C.nutriment_factor * C.volume / C.metabolization_rate
+
+ . = COMPONENT_ITEM_NO_ATTACK //Point of no return I suppose
+
+ if(eater == feeder)//If you're eating it yourself.
+ if(!do_mob(feeder, eater, eat_time)) //Gotta pass the minimal eat time
+ return
+ var/eatverb = pick(eatverbs)
+ if(junkiness && eater.satiety < -150 && eater.nutrition > NUTRITION_LEVEL_STARVING + 50 && !HAS_TRAIT(eater, TRAIT_VORACIOUS))
+ to_chat(eater, "You don't feel like eating any more junk food at the moment!")
+ return
+ else if(fullness <= 50)
+ eater.visible_message("[eater] hungrily [eatverb]s \the [parent], gobbling it down!", "You hungrily [eatverb] \the [parent], gobbling it down!")
+ else if(fullness > 50 && fullness < 150)
+ eater.visible_message("[eater] hungrily [eatverb]s \the [parent].", "You hungrily [eatverb] \the [parent].")
+ else if(fullness > 150 && fullness < 500)
+ eater.visible_message("[eater] [eatverb]s \the [parent].", "You [eatverb] \the [parent].")
+ else if(fullness > 500 && fullness < 600)
+ eater.visible_message("[eater] unwillingly [eatverb]s a bit of \the [parent].", "You unwillingly [eatverb] a bit of \the [parent].")
+ else if(fullness > (600 * (1 + eater.overeatduration / 2000))) // The more you eat - the more you can eat
+ eater.visible_message("[eater] cannot force any more of \the [parent] to go down [eater.p_their()] throat!", "You cannot force any more of \the [parent] to go down your throat!")
+ return
+ else //If you're feeding it to someone else.
+ if(isbrain(eater))
+ to_chat(feeder, "[eater] doesn't seem to have a mouth!")
+ return
+ if(fullness <= (600 * (1 + eater.overeatduration / 1000)))
+ eater.visible_message("[feeder] attempts to feed [eater] [parent].", \
+ "[feeder] attempts to feed you [parent].")
+ else
+ eater.visible_message("[feeder] cannot force any more of [parent] down [eater]'s throat!", \
+ "[feeder] cannot force any more of [parent] down your throat!")
+ return
+ if(!do_mob(feeder, eater)) //Wait 3 seconds before you can feed
+ return
+
+ log_combat(feeder, eater, "fed", owner.reagents.log_list())
+ eater.visible_message("[feeder] forces [eater] to eat [parent]!", \
+ "[feeder] forces you to eat [parent]!")
+
+ TakeBite(eater, feeder)
+
+///This function lets the eater take a bite and transfers the reagents to the eater.
+/datum/component/edible/proc/TakeBite(mob/living/eater, mob/living/feeder)
+
+ var/atom/owner = parent
+
+ if(!owner?.reagents)
+ return FALSE
+ if(eater.satiety > -200)
+ eater.satiety -= junkiness
+ playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE)
+ if(owner.reagents.total_volume)
+ SEND_SIGNAL(parent, COMSIG_FOOD_EATEN, eater, feeder)
+ var/fraction = min(bite_consumption / owner.reagents.total_volume, 1)
+ owner.reagents.trans_to(eater, bite_consumption, transfered_by = feeder, method = INGEST)
+ bitecount++
+ On_Consume(eater)
+ checkLiked(fraction, eater)
+
+ //Invoke our after eat callback if it is valid
+ if(after_eat)
+ after_eat.Invoke(eater, feeder)
+
+ return TRUE
+
+///Checks whether or not the eater can actually consume the food
+/datum/component/edible/proc/CanConsume(mob/living/eater, mob/living/feeder)
+ if(!iscarbon(eater))
+ return FALSE
+ var/mob/living/carbon/C = eater
+ var/covered = ""
+ if(C.is_mouth_covered(head_only = 1))
+ covered = "headgear"
+ else if(C.is_mouth_covered(mask_only = 1))
+ covered = "mask"
+ if(covered)
+ var/who = (isnull(feeder) || eater == feeder) ? "your" : "[eater.p_their()]"
+ to_chat(feeder, "You have to remove [who] [covered] first!")
+ return FALSE
+ return TRUE
+
+///Check foodtypes to see if we should send a moodlet
+/datum/component/edible/proc/checkLiked(var/fraction, mob/M)
+ if(last_check_time + 50 > world.time)
+ return FALSE
+ if(!ishuman(M))
+ return FALSE
+ var/mob/living/carbon/human/H = M
+ if(HAS_TRAIT(H, TRAIT_AGEUSIA) && foodtypes & H.dna.species.toxic_food)
+ to_chat(H, "You don't feel so good...")
+ H.adjust_disgust(25 + 30 * fraction)
+ else
+ if(foodtypes & H.dna.species.toxic_food)
+ to_chat(H,"What the hell was that thing?!")
+ H.adjust_disgust(25 + 30 * fraction)
+ SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "toxic_food", /datum/mood_event/disgusting_food)
+ else if(foodtypes & H.dna.species.disliked_food)
+ to_chat(H,"That didn't taste very good...")
+ H.adjust_disgust(11 + 15 * fraction)
+ SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "gross_food", /datum/mood_event/gross_food)
+ else if(foodtypes & H.dna.species.liked_food)
+ to_chat(H,"I love this taste!")
+ H.adjust_disgust(-5 + -2.5 * fraction)
+ SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "fav_food", /datum/mood_event/favorite_food)
+ if((foodtypes & BREAKFAST) && world.time - SSticker.round_start_time < STOP_SERVING_BREAKFAST)
+ SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "breakfast", /datum/mood_event/breakfast)
+ last_check_time = world.time
+
+///Delete the item when it is fully eaten
+/datum/component/edible/proc/On_Consume(mob/living/eater)
+
+ var/atom/owner = parent
+
+ if(!eater)
+ return
+ if(!owner.reagents.total_volume)
+ if(isturf(parent))
+ var/turf/T = parent
+ T.ScrapeAway(1, CHANGETURF_INHERIT_AIR)
+ else
+ qdel(parent)
+
+///Ability to feed food to puppers
+/datum/component/edible/proc/UseByAnimal(datum/source, mob/user)
+
+ var/atom/owner = parent
+
+ if(!isdog(user))
+ return
+ var/mob/living/L = user
+ if(bitecount == 0 || prob(50))
+ L.emote("me", 1, "nibbles away at \the [parent]")
+ bitecount++
+ . = COMPONENT_ITEM_NO_ATTACK
+ L.taste(owner.reagents) // why should carbons get all the fun?
+ if(bitecount >= 5)
+ var/sattisfaction_text = pick("burps from enjoyment", "yaps for more", "woofs twice", "looks at the area where \the [parent] was")
+ if(sattisfaction_text)
+ L.emote("me", 1, "[sattisfaction_text]")
+ qdel(parent)
diff --git a/code/datums/components/radioactive.dm b/code/datums/components/radioactive.dm
index decc2dd65c..f12e8bf007 100644
--- a/code/datums/components/radioactive.dm
+++ b/code/datums/components/radioactive.dm
@@ -69,8 +69,9 @@
out += "[out ? " and it " : "[master] "]seems to be glowing a bit."
if(RAD_AMOUNT_HIGH to INFINITY) //At this level the object can contaminate other objects
out += "[out ? " and it " : "[master] "]hurts to look at."
- else
- out += "."
+ if(!LAZYLEN(out))
+ return
+ out += "."
examine_list += out.Join()
/datum/component/radioactive/proc/rad_attack(datum/source, atom/movable/target, mob/living/user)
diff --git a/code/datums/elements/beauty.dm b/code/datums/elements/beauty.dm
index 8acfda73e1..8895026967 100644
--- a/code/datums/elements/beauty.dm
+++ b/code/datums/elements/beauty.dm
@@ -8,8 +8,11 @@
if(. == ELEMENT_INCOMPATIBLE || !isatom(target) || isarea(target))
return ELEMENT_INCOMPATIBLE
beauty = beautyamount
- RegisterSignal(target, COMSIG_ENTER_AREA, .proc/enter_area)
- RegisterSignal(target, COMSIG_EXIT_AREA, .proc/exit_area)
+
+ if(ismovable(target))
+ RegisterSignal(target, COMSIG_ENTER_AREA, .proc/enter_area)
+ RegisterSignal(target, COMSIG_EXIT_AREA, .proc/exit_area)
+
var/area/A = get_area(target)
if(A)
enter_area(null, A)
diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm
index 1a8ce755e1..5148aab4ac 100644
--- a/code/datums/materials/_material.dm
+++ b/code/datums/materials/_material.dm
@@ -6,8 +6,6 @@ Simple datum which is instanced once per type and is used for every object of sa
/datum/material
var/name = "material"
var/desc = "its..stuff."
- ///Var that's mostly used by science machines to identify specific materials, should most likely be phased out at some point
- var/id = "mat"
///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.
@@ -26,6 +24,20 @@ Simple datum which is instanced once per type and is used for every object of sa
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
+ ///Can be used to override the sound items make, lets add some SLOSHing.
+ var/item_sound_override
+ ///Can be used to override the stepsound a turf makes. MORE SLOOOSH
+ var/turf_sound_override
+ ///what texture icon state to overlay
+ var/texture_layer_icon_state
+ ///a cached filter for the texture icon
+ var/cached_texture_filter
+
+/datum/material/New()
+ . = ..()
+ if(texture_layer_icon_state)
+ var/texture_icon = icon('icons/materials/composite.dmi', texture_layer_icon_state)
+ cached_texture_filter = filter(type="layer", icon=texture_icon, blend_mode = BLEND_INSET_OVERLAY)
///This proc is called when the material is added to an object.
/datum/material/proc/on_applied(atom/source, amount, material_flags)
@@ -34,16 +46,27 @@ Simple datum which is instanced once per type and is used for every object of sa
source.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
if(alpha)
source.alpha = alpha
+ if(texture_layer_icon_state)
+ ADD_KEEP_TOGETHER(source, MATERIAL_SOURCE(src))
+ source.filters += cached_texture_filter
if(material_flags & MATERIAL_ADD_PREFIX)
source.name = "[name] [source.name]"
- if(istype(source, /obj)) //objs
- on_applied_obj(source, amount, material_flags)
-
if(beauty_modifier)
addtimer(CALLBACK(source, /datum.proc/_AddElement, list(/datum/element/beauty, beauty_modifier * amount)), 0)
+ if(istype(source, /obj)) //objs
+ on_applied_obj(source, amount, material_flags)
+
+ else if(isturf(source, /turf)) //turfs
+ on_applied_turf(source, amount, material_flags)
+
+ source.mat_update_desc(src)
+
+///This proc is called when a material updates an object's description
+/atom/proc/mat_update_desc(/datum/material/mat)
+ return
///This proc is called when the material is added to an object specifically.
/datum/material/proc/on_applied_obj(var/obj/o, amount, material_flags)
if(material_flags & MATERIAL_AFFECT_STATISTICS)
@@ -61,6 +84,24 @@ Simple datum which is instanced once per type and is used for every object of sa
for(var/i in current_armor)
temp_armor_list[i] = current_armor[i] * armor_modifiers[i]
o.armor = getArmor(arglist(temp_armor_list))
+ if(!isitem(o))
+ return
+ var/obj/item/I = o
+ if(!item_sound_override)
+ return
+ I.hitsound = item_sound_override
+ I.usesound = item_sound_override
+ I.throwhitsound = item_sound_override
+
+/datum/material/proc/on_applied_turf(var/turf/T, amount, material_flags)
+ if(isopenturf(T))
+ if(!turf_sound_override)
+ return
+ var/turf/open/O = T
+ O.footstep = turf_sound_override
+ O.barefootstep = turf_sound_override
+ O.clawfootstep = turf_sound_override
+ O.heavyfootstep = turf_sound_override
///This proc is called when the material is removed from an object.
/datum/material/proc/on_removed(atom/source, material_flags)
@@ -68,6 +109,9 @@ Simple datum which is instanced once per type and is used for every object of sa
if(color)
source.remove_atom_colour(FIXED_COLOUR_PRIORITY, color)
source.alpha = initial(source.alpha)
+ if(texture_layer_icon_state)
+ source.filters -= cached_texture_filter
+ REMOVE_KEEP_TOGETHER(source, MATERIAL_SOURCE(src))
if(material_flags & MATERIAL_ADD_PREFIX)
source.name = initial(source.name)
@@ -75,10 +119,16 @@ Simple datum which is instanced once per type and is used for every object of sa
if(istype(source, /obj)) //objs
on_removed_obj(source, material_flags)
+ else if(istype(source, /turf)) //turfs
+ on_removed_turf(source, material_flags)
+
///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)
+/datum/material/proc/on_removed_obj(obj/o, material_flags)
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)
+
+/datum/material/proc/on_removed_turf(turf/T, material_flags)
+ return
diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm
index d4921a04d2..721af65449 100644
--- a/code/datums/materials/basemats.dm
+++ b/code/datums/materials/basemats.dm
@@ -1,21 +1,19 @@
///Has no special properties.
/datum/material/iron
name = "iron"
- id = "iron"
desc = "Common iron ore often found in sedimentary and igneous layers of the crust."
color = "#878687"
- categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/metal
value_per_unit = 0.0025
///Breaks extremely easily but is transparent.
/datum/material/glass
name = "glass"
- id = "glass"
desc = "Glass forged by melting sand."
color = "#88cdf1"
alpha = 150
- categories = list(MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
integrity_modifier = 0.1
sheet_type = /obj/item/stack/sheet/glass
value_per_unit = 0.0025
@@ -30,10 +28,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Has no special properties. Could be good against vampires in the future perhaps.
/datum/material/silver
name = "silver"
- id = "silver"
desc = "Silver"
color = list(255/255, 284/255, 302/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
- categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/silver
value_per_unit = 0.025
beauty_modifier = 0.075
@@ -41,11 +38,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Slight force increase
/datum/material/gold
name = "gold"
- id = "gold"
desc = "Gold"
color = list(340/255, 240/255, 50/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //gold is shiny, but not as bright as bananium
strength_modifier = 1.2
- categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/gold
value_per_unit = 0.0625
beauty_modifier = 0.15
@@ -54,11 +50,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Has no special properties
/datum/material/diamond
name = "diamond"
- id = "diamond"
desc = "Highly pressurized carbon"
color = list(48/255, 272/255, 301/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
alpha = 132
- categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/diamond
value_per_unit = 0.25
beauty_modifier = 0.3
@@ -67,10 +62,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Is slightly radioactive
/datum/material/uranium
name = "uranium"
- id = "uranium"
desc = "Uranium"
color = rgb(48, 237, 26)
- categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/uranium
value_per_unit = 0.05
beauty_modifier = 0.3 //It shines so beautiful
@@ -88,10 +82,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Adds firestacks on hit (Still needs support to turn into gas on destruction)
/datum/material/plasma
name = "plasma"
- id = "plasma"
desc = "Isn't plasma a state of matter? Oh whatever."
color = list(298/255, 46/255, 352/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
- categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/plasma
value_per_unit = 0.1
beauty_modifier = 0.15
@@ -111,7 +104,6 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Can cause bluespace effects on use. (Teleportation) (Not yet implemented)
/datum/material/bluespace
name = "bluespace crystal"
- id = "bluespace_crystal"
desc = "Crystals with bluespace properties"
color = list(119/255, 217/255, 396/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
alpha = 200
@@ -123,10 +115,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Honks and slips
/datum/material/bananium
name = "bananium"
- id = "bananium"
desc = "Material with hilarious properties"
color = list(460/255, 464/255, 0, 0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //obnoxiously bright yellow
- categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/bananium
value_per_unit = 0.5
beauty_modifier = 0.5
@@ -146,11 +137,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Mediocre force increase
/datum/material/titanium
name = "titanium"
- id = "titanium"
desc = "Titanium"
color = "#b3c0c7"
strength_modifier = 1.3
- categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/titanium
value_per_unit = 0.0625
beauty_modifier = 0.05
@@ -158,11 +148,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
/datum/material/runite
name = "runite"
- id = "runite"
desc = "Runite"
color = "#3F9995"
strength_modifier = 1.3
- categories = list(MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/runite
beauty_modifier = 0.5
armor_modifiers = list("melee" = 1.35, "bullet" = 2, "laser" = 0.5, "energy" = 1.25, "bomb" = 1.25, "bio" = 1, "rad" = 1, "fire" = 1.4, "acid" = 1) //rune is weak against magic lasers but strong against bullets. This is the combat triangle.
@@ -170,7 +159,6 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Force decrease
/datum/material/plastic
name = "plastic"
- id = "plastic"
desc = "Plastic"
color = "#caccd9"
strength_modifier = 0.85
@@ -182,7 +170,6 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Force decrease and mushy sound effect. (Not yet implemented)
/datum/material/biomass
name = "biomass"
- id = "biomass"
desc = "Organic matter"
color = "#735b4d"
strength_modifier = 0.8
@@ -190,12 +177,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
/datum/material/wood
name = "wood"
- id = "wood"
desc = "Flexible, durable, but flamable. Hard to come across in space."
color = "#bb8e53"
strength_modifier = 0.5
sheet_type = /obj/item/stack/sheet/mineral/wood
- categories = list(MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
value_per_unit = 0.06
beauty_modifier = 0.1
armor_modifiers = list("melee" = 1.1, "bullet" = 1.1, "laser" = 0.4, "energy" = 0.4, "bomb" = 1, "bio" = 0.2, "rad" = 0, "fire" = 0, "acid" = 0.3)
@@ -215,11 +201,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Stronk force increase
/datum/material/adamantine
name = "adamantine"
- id = "adamantine"
desc = "A powerful material made out of magic, I mean science!"
color = "#6d7e8e"
strength_modifier = 1.5
- categories = list(MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/adamantine
value_per_unit = 0.25
beauty_modifier = 0.4
@@ -228,10 +213,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
///RPG Magic. (Admin only)
/datum/material/mythril
name = "mythril"
- id = "mythril"
desc = "How this even exists is byond me"
color = "#f2d5d7"
- categories = list(MAT_CATEGORY_RIGID = TRUE)
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/mythril
value_per_unit = 0.75
beauty_modifier = 0.5
@@ -246,3 +230,134 @@ Unless you know what you're doing, only use the first three numbers. They're in
. = ..()
if(istype(source, /obj/item))
qdel(source.GetComponent(/datum/component/fantasy))
+
+//I don't like sand. It's coarse, and rough, and irritating, and it gets everywhere.
+/datum/material/sand
+ name = "sand"
+ desc = "You know, it's amazing just how structurally sound sand can be."
+ color = "#EDC9AF"
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ sheet_type = /obj/item/stack/sheet/sandblock
+ value_per_unit = 0.001
+ strength_modifier = 0.5
+ integrity_modifier = 0.1
+ armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 1.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
+ beauty_modifier = 0.25
+ turf_sound_override = FOOTSTEP_SAND
+ texture_layer_icon_state = "sand"
+
+//And now for our lavaland dwelling friends, sand, but in stone form! Truly revolutionary.
+/datum/material/sandstone
+ name = "sandstone"
+ desc = "Bialtaakid 'ant taerif ma hdha."
+ color = "#B77D31"
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ sheet_type = /obj/item/stack/sheet/mineral/sandstone
+ value_per_unit = 0.0025
+ armor_modifiers = list("melee" = 0.5, "bullet" = 0.5, "laser" = 1.25, "energy" = 0.5, "bomb" = 0.5, "bio" = 0.25, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
+ beauty_modifier = 0.3
+ turf_sound_override = FOOTSTEP_WOOD
+ texture_layer_icon_state = "brick"
+
+/datum/material/snow
+ name = "snow"
+ desc = "There's no business like snow business."
+ color = "#FFFFFF"
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ sheet_type = /obj/item/stack/sheet/mineral/snow
+ value_per_unit = 0.0025
+ armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 0.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 0.25, "acid" = 1.5)
+ beauty_modifier = 0.3
+ turf_sound_override = FOOTSTEP_SAND
+ texture_layer_icon_state = "sand"
+
+/datum/material/runedmetal
+ name = "runed metal"
+ desc = "Mir'ntrath barhah Nar'sie."
+ color = "#3C3434"
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ sheet_type = /obj/item/stack/sheet/runed_metal
+ value_per_unit = 0.75
+ armor_modifiers = list("melee" = 1.2, "bullet" = 1.2, "laser" = 1, "energy" = 1, "bomb" = 1.2, "bio" = 1.2, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
+ beauty_modifier = -0.15
+ texture_layer_icon_state = "runed"
+
+/datum/material/bronze
+ name = "bronze"
+ desc = "Clock Cult? Never heard of it."
+ color = "#92661A"
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ sheet_type = /obj/item/stack/tile/bronze
+ value_per_unit = 0.025
+ armor_modifiers = list("melee" = 1, "bullet" = 1, "laser" = 1, "energy" = 1, "bomb" = 1, "bio" = 1, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
+ beauty_modifier = 0.2
+
+/datum/material/paper
+ name = "paper"
+ desc = "Ten thousand folds of pure starchy power."
+ color = "#E5DCD5"
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ sheet_type = /obj/item/stack/sheet/paperframes
+ value_per_unit = 0.0025
+ armor_modifiers = list("melee" = 0.1, "bullet" = 0.1, "laser" = 0.1, "energy" = 0.1, "bomb" = 0.1, "bio" = 0.1, "rad" = 1.5, "fire" = 0, "acid" = 1.5)
+ beauty_modifier = 0.3
+ turf_sound_override = FOOTSTEP_SAND
+ texture_layer_icon_state = "paper"
+
+/datum/material/paper/on_applied_obj(obj/source, amount, material_flags)
+ . = ..()
+ if(material_flags & MATERIAL_AFFECT_STATISTICS)
+ var/obj/paper = source
+ paper.resistance_flags |= FLAMMABLE
+ paper.obj_flags |= UNIQUE_RENAME
+
+/datum/material/paper/on_removed_obj(obj/source, material_flags)
+ if(material_flags & MATERIAL_AFFECT_STATISTICS)
+ var/obj/paper = source
+ paper.resistance_flags &= ~FLAMMABLE
+ return ..()
+
+/datum/material/cardboard
+ name = "cardboard"
+ desc = "They say cardboard is used by hobos to make incredible things."
+ color = "#5F625C"
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ sheet_type = /obj/item/stack/sheet/cardboard
+ value_per_unit = 0.003
+ armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 0.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 0, "acid" = 1.5)
+ beauty_modifier = -0.1
+
+/datum/material/cardboard/on_applied_obj(obj/source, amount, material_flags)
+ . = ..()
+ if(material_flags & MATERIAL_AFFECT_STATISTICS)
+ var/obj/cardboard = source
+ cardboard.resistance_flags |= FLAMMABLE
+ cardboard.obj_flags |= UNIQUE_RENAME
+
+/datum/material/cardboard/on_removed_obj(obj/source, material_flags)
+ if(material_flags & MATERIAL_AFFECT_STATISTICS)
+ var/obj/cardboard = source
+ cardboard.resistance_flags &= ~FLAMMABLE
+ return ..()
+
+/datum/material/bone
+ name = "bone"
+ desc = "Man, building with this will make you the coolest caveman on the block."
+ color = "#e3dac9"
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ sheet_type = /obj/item/stack/sheet/bone
+ value_per_unit = 0.05
+ armor_modifiers = list("melee" = 1.2, "bullet" = 0.75, "laser" = 0.75, "energy" = 1.2, "bomb" = 1, "bio" = 1, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
+ beauty_modifier = -0.2
+
+/datum/material/bamboo
+ name = "bamboo"
+ desc = "If it's good enough for pandas, it's good enough for you."
+ color = "#339933"
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ sheet_type = /obj/item/stack/sheet/mineral/bamboo
+ value_per_unit = 0.0025
+ armor_modifiers = list("melee" = 0.5, "bullet" = 0.5, "laser" = 0.5, "energy" = 0.5, "bomb" = 0.5, "bio" = 0.51, "rad" = 1.5, "fire" = 0.5, "acid" = 1.5)
+ beauty_modifier = 0.2
+ turf_sound_override = FOOTSTEP_WOOD
+ texture_layer_icon_state = "bamboo"
diff --git a/code/datums/materials/meat.dm b/code/datums/materials/meat.dm
new file mode 100644
index 0000000000..14a373f2d2
--- /dev/null
+++ b/code/datums/materials/meat.dm
@@ -0,0 +1,32 @@
+///It's gross, gets the name of it's owner, and is all kinds of fucked up
+/datum/material/meat
+ name = "meat"
+ desc = "Meat"
+ color = rgb(214, 67, 67)
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ sheet_type = /obj/item/stack/sheet/meat
+ value_per_unit = 0.05
+ beauty_modifier = -0.3
+ strength_modifier = 0.7
+ armor_modifiers = list("melee" = 0.3, "bullet" = 0.3, "laser" = 1.2, "energy" = 1.2, "bomb" = 0.3, "bio" = 0, "rad" = 0.7, "fire" = 1, "acid" = 1)
+ item_sound_override = 'sound/effects/meatslap.ogg'
+ turf_sound_override = FOOTSTEP_MEAT
+ texture_layer_icon_state = "meat"
+
+/datum/material/meat/on_removed(atom/source, material_flags)
+ . = ..()
+ qdel(source.GetComponent(/datum/component/edible))
+
+/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)
+ . = ..()
+ make_edible(T, amount, material_flags)
+
+/datum/material/meat/proc/make_edible(atom/source, amount, material_flags)
+ var/nutriment_count = 3 * (amount / MINERAL_MATERIAL_AMOUNT)
+ 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"))
diff --git a/code/datums/materials/pizza.dm b/code/datums/materials/pizza.dm
new file mode 100644
index 0000000000..2a9542234f
--- /dev/null
+++ b/code/datums/materials/pizza.dm
@@ -0,0 +1,30 @@
+/datum/material/pizza
+ name = "pizza"
+ desc = "~Jamme, jamme, n'coppa, jamme ja! Jamme, jamme, n'coppa jamme ja, funi-culi funi-cala funi-culi funi-cala!! Jamme jamme ja funiculi funicula!~"
+ color = "#FF9F23"
+ categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ sheet_type = /obj/item/stack/sheet/pizza
+ value_per_unit = 0.05
+ beauty_modifier = 0.1
+ strength_modifier = 0.7
+ armor_modifiers = list("melee" = 0.3, "bullet" = 0.3, "laser" = 1.2, "energy" = 1.2, "bomb" = 0.3, "bio" = 0, "rad" = 0.7, "fire" = 1, "acid" = 1)
+ item_sound_override = 'sound/effects/meatslap.ogg'
+ turf_sound_override = FOOTSTEP_MEAT
+ texture_layer_icon_state = "pizza"
+
+/datum/material/pizza/on_removed(atom/source, material_flags)
+ . = ..()
+ qdel(source.GetComponent(/datum/component/edible))
+
+/datum/material/pizza/on_applied_obj(obj/O, amount, material_flags)
+ . = ..()
+ make_edible(O, amount, material_flags)
+
+/datum/material/pizza/on_applied_turf(turf/T, amount, material_flags)
+ . = ..()
+ make_edible(T, amount, material_flags)
+
+/datum/material/pizza/proc/make_edible(atom/source, amount, material_flags)
+ var/nutriment_count = 3 * (amount / MINERAL_MATERIAL_AMOUNT)
+ 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, GRAIN | MEAT | DAIRY | VEGETABLES, null, 30, list("crust", "tomato", "cheese", "meat"))
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index e3f4829d3d..d498362c85 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -48,6 +48,7 @@
var/rad_insulation = RAD_NO_INSULATION
///The custom materials this atom is made of, used by a lot of things like furniture, walls, and floors (if I finish the functionality, that is.)
+ ///The list referenced by this var can be shared by multiple objects and should not be directly modified. Instead, use [set_custom_materials][/atom/proc/set_custom_materials].
var/list/custom_materials
///Bitfield for how the atom handles materials.
var/material_flags = NONE
@@ -114,11 +115,8 @@
if (canSmoothWith)
canSmoothWith = typelist("canSmoothWith", canSmoothWith)
- var/temp_list = list()
- for(var/i in custom_materials)
- temp_list[SSmaterials.GetMaterialRef(i)] = custom_materials[i] //Get the proper instanced version
- custom_materials = null //Null the list to prepare for applying the materials properly
- set_custom_materials(temp_list)
+ // apply materials properly from the default custom_materials value
+ set_custom_materials(custom_materials)
ComponentInitialize()
@@ -1006,26 +1004,21 @@ Proc for attack log creation, because really why not
///Sets the custom materials for an item.
/atom/proc/set_custom_materials(var/list/materials, multiplier = 1)
-
- if(!materials)
- materials = custom_materials
-
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)
custom_material.on_removed(src, material_flags) //Remove the current materials
if(!length(materials))
+ custom_materials = null
return
- custom_materials = list() //Reset the list
+ if(material_flags & MATERIAL_EFFECTS)
+ for(var/x in materials)
+ var/datum/material/custom_material = SSmaterials.GetMaterialRef(x)
+ custom_material.on_applied(src, materials[x] * multiplier * material_modifier, material_flags)
- for(var/x in materials)
- var/datum/material/custom_material = SSmaterials.GetMaterialRef(x)
-
- if(material_flags & MATERIAL_EFFECTS)
- custom_material.on_applied(src, materials[custom_material] * multiplier * material_modifier, material_flags)
- custom_materials[custom_material] += materials[x] * multiplier
+ custom_materials = SSmaterials.FindOrCreateMaterialCombo(materials, multiplier)
/**
* Returns true if this atom has gravity for the passed in turf
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 4eeb6b8b0f..1f0687151d 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -46,29 +46,16 @@
"Dinnerware",
"Imported"
)
- var/list/allowed_materials = list(
- /datum/material/iron,
- /datum/material/glass,
- /datum/material/gold,
- /datum/material/silver,
- /datum/material/diamond,
- /datum/material/uranium,
- /datum/material/plasma,
- /datum/material/bluespace,
- /datum/material/bananium,
- /datum/material/titanium,
- /datum/material/runite,
- /datum/material/plastic,
- /datum/material/adamantine,
- /datum/material/mythril,
- /datum/material/wood
- )
+ var/list/allowed_materials
/// Base print speed
var/base_print_speed = 10
/obj/machinery/autolathe/Initialize()
- AddComponent(/datum/component/material_container, allowed_materials, _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
+ var/list/mats = allowed_materials
+ if(!mats)
+ mats = SSmaterials.materialtypes_by_category[MAT_CATEGORY_RIGID]
+ AddComponent(/datum/component/material_container, mats, _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
. = ..()
wires = new /datum/wires/autolathe(src)
stored_research = new stored_research
diff --git a/code/game/machinery/sheetifier.dm b/code/game/machinery/sheetifier.dm
new file mode 100644
index 0000000000..7b83401194
--- /dev/null
+++ b/code/game/machinery/sheetifier.dm
@@ -0,0 +1,44 @@
+/obj/machinery/sheetifier
+ name = "Sheet-meister 2000"
+ desc = "A very sheety machine"
+ icon = 'icons/obj/machines/sheetifier.dmi'
+ icon_state = "base_machine"
+ density = TRUE
+ use_power = IDLE_POWER_USE
+ idle_power_usage = 10
+ active_power_usage = 100
+ circuit = /obj/item/circuitboard/machine/sheetifier
+ layer = BELOW_OBJ_LAYER
+ var/busy_processing = FALSE
+
+/obj/machinery/sheetifier/Initialize()
+ . = ..()
+ AddComponent(/datum/component/material_container, list(/datum/material/meat), MINERAL_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, TRUE, /obj/item/reagent_containers/food/snacks/meat/slab, CALLBACK(src, .proc/CanInsertMaterials), CALLBACK(src, .proc/AfterInsertMaterials))
+
+/obj/machinery/sheetifier/update_overlays()
+ . = ..()
+ if(stat & (BROKEN|NOPOWER))
+ return
+ var/mutable_appearance/on_overlay = mutable_appearance(icon, "buttons_on")
+ . += on_overlay
+
+/obj/machinery/sheetifier/update_icon_state()
+ icon_state = "base_machine[busy_processing ? "_processing" : ""]"
+
+/obj/machinery/sheetifier/proc/CanInsertMaterials()
+ return !busy_processing
+
+/obj/machinery/sheetifier/proc/AfterInsertMaterials(item_inserted, id_inserted, amount_inserted)
+ busy_processing = TRUE
+ update_icon()
+ var/datum/material/last_inserted_material = id_inserted
+ var/mutable_appearance/processing_overlay = mutable_appearance(icon, "processing")
+ processing_overlay.color = last_inserted_material.color
+ flick_overlay_static(processing_overlay, src, 64)
+ addtimer(CALLBACK(src, .proc/finish_processing), 64)
+
+/obj/machinery/sheetifier/proc/finish_processing()
+ busy_processing = FALSE
+ update_icon()
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
+ materials.retrieve_all() //Returns all as sheets
diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm
index 4ddb5281ea..c13cb1d1c6 100644
--- a/code/game/mecha/equipment/tools/other_tools.dm
+++ b/code/game/mecha/equipment/tools/other_tools.dm
@@ -388,7 +388,7 @@
/obj/item/mecha_parts/mecha_equipment/generator/get_equip_info()
var/output = ..()
if(output)
- return "[output] \[[fuel]: [round(fuel.amount*fuel.mats_per_stack,0.1)] cm3\] - [equip_ready?"A":"Dea"]ctivate"
+ return "[output] \[[fuel]: [round(fuel.amount*MINERAL_MATERIAL_AMOUNT,0.1)] cm3\] - [equip_ready?"A":"Dea"]ctivate"
/obj/item/mecha_parts/mecha_equipment/generator/action(target)
if(chassis)
@@ -398,9 +398,9 @@
/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(var/obj/item/stack/sheet/P)
if(P.type == fuel.type && P.amount > 0)
- var/to_load = max(max_fuel - fuel.amount*fuel.mats_per_stack,0)
+ var/to_load = max(max_fuel - fuel.amount*MINERAL_MATERIAL_AMOUNT,0)
if(to_load)
- var/units = min(max(round(to_load / P.mats_per_stack),1),P.amount)
+ var/units = min(max(round(to_load / MINERAL_MATERIAL_AMOUNT),1),P.amount)
fuel.amount += units
P.use(units)
occupant_message("[units] unit\s of [fuel] successfully loaded.")
@@ -454,7 +454,7 @@
if(cur_charge < chassis.cell.maxcharge)
use_fuel = fuel_per_cycle_active
chassis.give_power(power_per_cycle)
- fuel.amount -= min(use_fuel/fuel.mats_per_stack,fuel.amount)
+ fuel.amount -= min(use_fuel/MINERAL_MATERIAL_AMOUNT,fuel.amount)
update_equip_info()
return 1
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 60bae4016a..79e0eceb8f 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -778,6 +778,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
..()
/obj/item/proc/microwave_act(obj/machinery/microwave/M)
+ SEND_SIGNAL(src, COMSIG_ITEM_MICROWAVE_ACT, M)
if(istype(M) && M.dirty < 100)
M.dirty++
diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm
index ea839ae12d..56eb25f953 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -61,6 +61,14 @@
name = "Experimental Clone Pod (Machine Board)"
build_path = /obj/machinery/clonepod/experimental
+/obj/item/circuitboard/machine/sheetifier
+ name = "Sheet-meister 2000 (Machine Board)"
+ icon_state = "supply"
+ build_path = /obj/machinery/sheetifier
+ req_components = list(
+ /obj/item/stock_parts/manipulator = 2,
+ /obj/item/stock_parts/matter_bin = 2)
+
/obj/item/circuitboard/machine/abductor
name = "alien board (Report This)"
icon_state = "abductor_mod"
diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm
index 6fdea26683..efcc075110 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/game/objects/items/stacks/rods.dm
@@ -17,7 +17,6 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
throw_speed = 3
throw_range = 7
custom_materials = list(/datum/material/iron=1000)
- mats_per_stack = 1000
max_amount = 50
attack_verb = list("hit", "bludgeoned", "whacked")
hitsound = 'sound/weapons/grenadelaunch.ogg'
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index d28ae52b52..f5843a7df2 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -39,9 +39,11 @@ GLOBAL_LIST_INIT(sandstone_recipes, list ( \
item_state = "sheet-sandstone"
throw_speed = 3
throw_range = 5
- custom_materials = list(/datum/material/glass=MINERAL_MATERIAL_AMOUNT)
+ custom_materials = list(/datum/material/sandstone=MINERAL_MATERIAL_AMOUNT)
sheettype = "sandstone"
merge_type = /obj/item/stack/sheet/mineral/sandstone
+ walltype = /turf/closed/wall/mineral/sandstone
+ material_type = /datum/material/sandstone
/obj/item/stack/sheet/mineral/sandstone/get_main_recipes()
. = ..()
@@ -107,6 +109,7 @@ GLOBAL_LIST_INIT(sandbag_recipes, list ( \
point_value = 25
merge_type = /obj/item/stack/sheet/mineral/diamond
material_type = /datum/material/diamond
+ walltype = /turf/closed/wall/mineral/diamond
GLOBAL_LIST_INIT(diamond_recipes, list ( \
new/datum/stack_recipe("diamond door", /obj/structure/mineral_door/transparent/diamond, 10, one_per_turf = 1, on_floor = 1), \
@@ -135,6 +138,7 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \
point_value = 20
merge_type = /obj/item/stack/sheet/mineral/uranium
material_type = /datum/material/uranium
+ walltype = /turf/closed/wall/mineral/uranium
GLOBAL_LIST_INIT(uranium_recipes, list ( \
new/datum/stack_recipe("uranium door", /obj/structure/mineral_door/uranium, 10, one_per_turf = 1, on_floor = 1), \
@@ -163,6 +167,7 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \
point_value = 20
merge_type = /obj/item/stack/sheet/mineral/plasma
material_type = /datum/material/plasma
+ walltype = /turf/closed/wall/mineral/plasma
/obj/item/stack/sheet/mineral/plasma/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins licking \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -205,6 +210,7 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \
point_value = 20
merge_type = /obj/item/stack/sheet/mineral/gold
material_type = /datum/material/gold
+ walltype = /turf/closed/wall/mineral/gold
GLOBAL_LIST_INIT(gold_recipes, list ( \
new/datum/stack_recipe("golden door", /obj/structure/mineral_door/gold, 10, one_per_turf = 1, on_floor = 1), \
@@ -236,6 +242,7 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \
merge_type = /obj/item/stack/sheet/mineral/silver
material_type = /datum/material/silver
tableVariant = /obj/structure/table/optable
+ walltype = /turf/closed/wall/mineral/silver
GLOBAL_LIST_INIT(silver_recipes, list ( \
new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, one_per_turf = 1, on_floor = 1), \
@@ -266,6 +273,7 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \
point_value = 50
merge_type = /obj/item/stack/sheet/mineral/bananium
material_type = /datum/material/bananium
+ walltype = /turf/closed/wall/mineral/bananium
GLOBAL_LIST_INIT(bananium_recipes, list ( \
new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20), \
@@ -294,6 +302,7 @@ GLOBAL_LIST_INIT(bananium_recipes, list ( \
point_value = 20
merge_type = /obj/item/stack/sheet/mineral/titanium
material_type = /datum/material/titanium
+ walltype = /turf/closed/wall/mineral/titanium
GLOBAL_LIST_INIT(titanium_recipes, list ( \
new/datum/stack_recipe("titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20), \
@@ -324,6 +333,7 @@ GLOBAL_LIST_INIT(titanium_recipes, list ( \
custom_materials = list(/datum/material/titanium=MINERAL_MATERIAL_AMOUNT, /datum/material/plasma=MINERAL_MATERIAL_AMOUNT)
point_value = 45
merge_type = /obj/item/stack/sheet/mineral/plastitanium
+ walltype = /turf/closed/wall/mineral/plastitanium
/obj/item/stack/sheet/mineral/plastitanium/fifty
amount = 50
@@ -390,11 +400,14 @@ GLOBAL_LIST_INIT(adamantine_recipes, list(
name = "snow"
icon_state = "sheet-snow"
item_state = "sheet-snow"
+ custom_materials = list(/datum/material/snow = MINERAL_MATERIAL_AMOUNT)
singular_name = "snow block"
force = 1
throwforce = 2
grind_results = list(/datum/reagent/consumable/ice = 20)
merge_type = /obj/item/stack/sheet/mineral/snow
+ walltype = /turf/closed/wall/mineral/snow
+ material_type = /datum/material/snow
GLOBAL_LIST_INIT(snow_recipes, list ( \
new/datum/stack_recipe("Snow Wall", /turf/closed/wall/mineral/snow, 5, one_per_turf = 1, on_floor = 1), \
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index c11b619431..f0a57fddb2 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -205,7 +205,7 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \
desc = "This sheet is an alloy of iron and plasma."
icon_state = "sheet-plasteel"
item_state = "sheet-metal"
- custom_materials = list(/datum/material/iron=2000, /datum/material/plasma=2000)
+ custom_materials = list(/datum/material/iron=MINERAL_MATERIAL_AMOUNT, /datum/material/plasma=MINERAL_MATERIAL_AMOUNT)
throwforce = 10
flags_1 = CONDUCT_1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 80)
@@ -289,6 +289,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
novariants = TRUE
material_type = /datum/material/wood
grind_results = list(/datum/reagent/carbon = 20)
+ walltype = /turf/closed/wall/mineral/wood
/obj/item/stack/sheet/mineral/wood/attackby(obj/item/W, mob/user, params) // NOTE: sheet_types.dm is where the WOOD stack lives. Maybe move this over there.
// Taken from /obj/item/stack/rods/attackby in [rods.dm]
@@ -344,11 +345,13 @@ GLOBAL_LIST_INIT(bamboo_recipes, list ( \
icon_state = "sheet-bamboo"
item_state = "sheet-bamboo"
icon = 'icons/obj/stack_objects.dmi'
+ custom_materials = list(/datum/material/bamboo = MINERAL_MATERIAL_AMOUNT)
throwforce = 15
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 0)
resistance_flags = FLAMMABLE
merge_type = /obj/item/stack/sheet/mineral/bamboo
grind_results = list(/datum/reagent/carbon = 5)
+ material_type = /datum/material/bamboo
/obj/item/stack/sheet/mineral/bamboo/get_main_recipes()
. = ..()
@@ -513,12 +516,14 @@ GLOBAL_LIST_INIT(cardboard_recipes, list ( \
desc = "Large sheets of card, like boxes folded flat."
singular_name = "cardboard sheet"
icon_state = "sheet-card"
+ custom_materials = list(/datum/material/cardboard = MINERAL_MATERIAL_AMOUNT)
item_state = "sheet-card"
resistance_flags = FLAMMABLE
force = 0
throwforce = 0
merge_type = /obj/item/stack/sheet/cardboard
novariants = TRUE
+ material_type = /datum/material/cardboard
/obj/item/stack/sheet/cardboard/get_main_recipes()
. = ..()
@@ -558,10 +563,12 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list ( \
icon_state = "sheet-runed"
item_state = "sheet-runed"
icon = 'icons/obj/stack_objects.dmi'
+ custom_materials = list(/datum/material/runedmetal = MINERAL_MATERIAL_AMOUNT)
sheettype = "runed"
merge_type = /obj/item/stack/sheet/runed_metal
novariants = TRUE
grind_results = list(/datum/reagent/iron = 5, /datum/reagent/blood = 15)
+ material_type = /datum/material/runedmetal
/obj/item/stack/sheet/runed_metal/ratvar_act()
new /obj/item/stack/tile/brass(loc, amount)
@@ -680,6 +687,7 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \
icon_state = "sheet-brass"
item_state = "sheet-brass"
icon = 'icons/obj/stack_objects.dmi'
+ custom_materials = list(/datum/material/bronze = MINERAL_MATERIAL_AMOUNT)
resistance_flags = FIRE_PROOF | ACID_PROOF
throwforce = 10
max_amount = 50
@@ -690,6 +698,7 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \
grind_results = list(/datum/reagent/iron = 5, /datum/reagent/copper = 3) //we have no "tin" reagent so this is the closest thing
merge_type = /obj/item/stack/tile/bronze
tableVariant = /obj/structure/table/bronze
+ material_type = /datum/material/bronze
/obj/item/stack/tile/bronze/attack_self(mob/living/user)
if(is_servant_of_ratvar(user)) //still lets them build with it, just gives a message
@@ -737,6 +746,7 @@ GLOBAL_LIST_INIT(bone_recipes, list(
icon = 'icons/obj/mining.dmi'
icon_state = "bone"
item_state = "sheet-bone"
+ custom_materials = list(/datum/material/bone = MINERAL_MATERIAL_AMOUNT)
singular_name = "bone"
desc = "Someone's been drinking their milk."
force = 7
@@ -747,6 +757,7 @@ GLOBAL_LIST_INIT(bone_recipes, list(
throw_range = 3
grind_results = list(/datum/reagent/carbon = 10)
merge_type = /obj/item/stack/sheet/bone
+ material_type = /datum/material/bone
/obj/item/stack/sheet/bone/get_main_recipes()
. = ..()
@@ -774,6 +785,7 @@ GLOBAL_LIST_INIT(plastic_recipes, list(
custom_materials = list(/datum/material/plastic=MINERAL_MATERIAL_AMOUNT)
throwforce = 7
grind_results = list(/datum/reagent/glitter/white = 60)
+ material_type = /datum/material/plastic
merge_type = /obj/item/stack/sheet/plastic
/obj/item/stack/sheet/plastic/fifty
@@ -799,9 +811,11 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra
singular_name = "paper frame"
icon_state = "sheet-paper"
item_state = "sheet-paper"
+ custom_materials = list(/datum/material/paper = MINERAL_MATERIAL_AMOUNT)
merge_type = /obj/item/stack/sheet/paperframes
resistance_flags = FLAMMABLE
merge_type = /obj/item/stack/sheet/paperframes
+ material_type = /datum/material/paper
/obj/item/stack/sheet/paperframes/get_main_recipes()
. = ..()
@@ -842,3 +856,55 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra
merge_type = /obj/item/stack/sheet/cotton/durathread
pull_effort = 70
loom_result = /obj/item/stack/sheet/durathread
+
+/obj/item/stack/sheet/meat
+ name = "meat sheets"
+ desc = "Something's bloody meat compressed into a nice solid sheet"
+ singular_name = "meat sheet"
+ icon_state = "sheet-meat"
+ material_flags = MATERIAL_COLOR
+ custom_materials = list(/datum/material/meat = MINERAL_MATERIAL_AMOUNT)
+ merge_type = /obj/item/stack/sheet/meat
+ material_type = /datum/material/meat
+ material_modifier = 1 //None of that wussy stuff
+
+/obj/item/stack/sheet/meat/fifty
+ amount = 50
+/obj/item/stack/sheet/meat/twenty
+ amount = 20
+/obj/item/stack/sheet/meat/five
+ amount = 5
+
+/obj/item/stack/sheet/pizza
+ name = "pepperoni sheetzzas"
+ desc = "It's a delicious pepperoni sheetzza!"
+ singular_name = "pepperoni sheetzza"
+ icon_state = "sheet-pizza"
+ custom_materials = list(/datum/material/pizza = MINERAL_MATERIAL_AMOUNT)
+ merge_type = /obj/item/stack/sheet/pizza
+ material_type = /datum/material/pizza
+ material_modifier = 1
+
+/obj/item/stack/sheet/pizza/fifty
+ amount = 50
+/obj/item/stack/sheet/pizza/twenty
+ amount = 20
+/obj/item/stack/sheet/pizza/five
+ amount = 5
+
+/obj/item/stack/sheet/sandblock
+ name = "blocks of sand"
+ desc = "You're too old to be playing with sandcastles. Now you build... sandstations."
+ singular_name = "block of sand"
+ icon_state = "sheet-sandstone"
+ custom_materials = list(/datum/material/sand = MINERAL_MATERIAL_AMOUNT)
+ merge_type = /obj/item/stack/sheet/sandblock
+ material_type = /datum/material/sand
+ material_modifier = 1
+
+/obj/item/stack/sheet/sandblock/fifty
+ amount = 50
+/obj/item/stack/sheet/sandblock/twenty
+ amount = 20
+/obj/item/stack/sheet/sandblock/five
+ amount = 5
diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm
index dfba533247..57c8ba75d8 100644
--- a/code/game/objects/items/stacks/sheets/sheets.dm
+++ b/code/game/objects/items/stacks/sheets/sheets.dm
@@ -10,10 +10,14 @@
throw_range = 3
attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "smashed")
novariants = FALSE
- mats_per_stack = MINERAL_MATERIAL_AMOUNT
- var/sheettype = null //this is used for girders in the creation of walls/false walls
- var/point_value = 0 //turn-in value for the gulag stacker - loosely relative to its rarity
- var/shard_type // the shard debris typepath left over by solar panels and windows etc.
+ ///this is used for girders in the creation of walls/false walls
+ var/sheettype = null
+ ///turn-in value for the gulag stacker - loosely relative to its rarity
+ var/point_value = 0
+ /// the shard debris typepath left over by solar panels and windows etc.
+ var/shard_type
+ ///What type of wall does this sheet spawn
+ var/walltype
/obj/item/stack/sheet/Initialize(mapload, new_amount, merge)
. = ..()
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 2c8e700316..b124908bf2 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -22,7 +22,7 @@
var/merge_type = null // This path and its children should merge with this stack, defaults to src.type
var/full_w_class = WEIGHT_CLASS_NORMAL //The weight class the stack should have at amount > 2/3rds max_amount
var/novariants = TRUE //Determines whether the item should update it's sprites based on amount.
- var/mats_per_stack = 0
+ var/list/mats_per_unit //list that tells you how much is in a single unit.
///Datum material type that this stack is made of
var/material_type
//NOTE: When adding grind_results, the amounts should be for an INDIVIDUAL ITEM - these amounts will be multiplied by the stack size in on_grind()
@@ -47,8 +47,11 @@
if(!merge_type)
merge_type = type
if(custom_materials && custom_materials.len)
+ mats_per_unit = list()
+ var/in_process_mat_list = custom_materials.Copy()
for(var/i in custom_materials)
- custom_materials[SSmaterials.GetMaterialRef(i)] = mats_per_stack * amount
+ mats_per_unit[SSmaterials.GetMaterialRef(i)] = in_process_mat_list[i]
+ custom_materials[i] *= amount
. = ..()
if(merge)
for(var/obj/item/stack/S in loc)
@@ -60,7 +63,7 @@
var/datum/material/M = SSmaterials.GetMaterialRef(material_type) //First/main material
for(var/i in M.categories)
switch(i)
- if(MAT_CATEGORY_RIGID)
+ if(MAT_CATEGORY_BASE_RECIPES)
var/list/temp = SSmaterials.rigid_stack_recipes.Copy()
recipes += temp
update_weight()
@@ -309,16 +312,19 @@
/obj/item/stack/use(used, transfer = FALSE, check = TRUE) // return 0 = borked; return 1 = had enough
if(check && zero_amount())
- return FALSE
+ return TRUE
if (is_cyborg)
return source.use_charge(used * cost)
if (amount < used)
return FALSE
amount -= used
- if(check)
- zero_amount()
- for(var/i in custom_materials)
- custom_materials[i] = amount * mats_per_stack
+ if(check && zero_amount())
+ return FALSE
+ if(length(mats_per_unit))
+ var/temp_materials = custom_materials.Copy()
+ for(var/i in mats_per_unit)
+ temp_materials[i] = mats_per_unit[i] * src.amount
+ set_custom_materials(temp_materials)
update_icon()
update_weight()
return TRUE
@@ -350,10 +356,11 @@
source.add_charge(amount * cost)
else
src.amount += amount
- if(custom_materials && custom_materials.len)
- for(var/i in custom_materials)
- custom_materials[SSmaterials.GetMaterialRef(i)] = MINERAL_MATERIAL_AMOUNT * src.amount
- set_custom_materials() //Refresh
+ if(length(mats_per_unit))
+ var/temp_materials = custom_materials.Copy()
+ for(var/i in mats_per_unit)
+ temp_materials[i] = mats_per_unit[i] * src.amount
+ set_custom_materials(temp_materials)
update_icon()
update_weight()
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index 0635c55ca3..13fca1e8fe 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -9,16 +9,35 @@
throw_speed = 3
throw_range = 7
max_amount = 60
- mats_per_stack = 500
var/turf_type = null
var/mineralType = null
novariants = TRUE
+ var/human_maxHealth = 100
/obj/item/stack/tile/Initialize(mapload, amount)
. = ..()
pixel_x = rand(-3, 3)
pixel_y = rand(-3, 3) //randomize a little
+/obj/item/stack/tile/examine(mob/user)
+ . = ..()
+ if(throwforce && !is_cyborg) //do not want to divide by zero or show the message to borgs who can't throw
+ var/verb
+ switch(CEILING(human_maxHealth / throwforce, 1)) //throws to crit a human
+ if(1 to 3)
+ verb = "superb"
+ if(4 to 6)
+ verb = "great"
+ if(7 to 9)
+ verb = "good"
+ if(10 to 12)
+ verb = "fairly decent"
+ if(13 to 15)
+ verb = "mediocre"
+ if(!verb)
+ return
+ . += "Those could work as a [verb] throwing weapon."
+
/obj/item/stack/tile/attackby(obj/item/W, mob/user, params)
if (istype(W, /obj/item/weldingtool))
@@ -470,7 +489,7 @@
/obj/item/stack/tile/plasteel
name = "floor tile"
singular_name = "floor tile"
- desc = "Those could work as a pretty decent throwing weapon."
+ desc = "The ground you walk on."
icon_state = "tile"
force = 6
custom_materials = list(/datum/material/iron=500)
@@ -482,7 +501,15 @@
resistance_flags = FIRE_PROOF
/obj/item/stack/tile/plasteel/cyborg
- desc = "The ground you walk on." //Not the usual floor tile desc as that refers to throwing, Cyborgs can't do that - RR
custom_materials = null // All other Borg versions of items have no Metal or Glass - RR
is_cyborg = 1
cost = 125
+
+/obj/item/stack/tile/material
+ name = "floor tile"
+ singular_name = "floor tile"
+ desc = "The ground you walk on."
+ throwforce = 10
+ icon_state = "material_tile"
+ turf_type = /turf/open/floor/material
+ material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index cacf361722..ff62b9cc48 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -170,7 +170,7 @@
qdel(src)
return
- if(S.sheettype && S.sheettype != "runed")
+ if(S.sheettype != "runed")
var/M = S.sheettype
if(state == GIRDER_DISPLACED)
var/F = text2path("/obj/structure/falsewall/[M]")
@@ -188,9 +188,13 @@
transfer_fingerprints_to(FW)
qdel(src)
else
- var/F = text2path("/turf/closed/wall/mineral/[M]")
+ var/list/material_list
+ var/F = S.walltype
if(!F)
- return
+ F = /turf/closed/wall/material
+ if(S.material_type)
+ material_list = list()
+ material_list[SSmaterials.GetMaterialRef(S.material_type)] = MINERAL_MATERIAL_AMOUNT * 2
if(S.get_amount() < 2)
to_chat(user, "You need at least two sheets to add plating!")
return
@@ -201,7 +205,9 @@
S.use(2)
to_chat(user, "You add the plating.")
var/turf/T = get_turf(src)
- T.PlaceOnTop(F)
+ var/turf/newturf = T.PlaceOnTop(F)
+ if(material_list)
+ newturf.set_custom_materials(material_list)
transfer_fingerprints_to(T)
qdel(src)
return
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 5eecc6962a..41e7c6c60f 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -157,8 +157,7 @@
secret_type = /obj/effect/spawner/lootdrop/prison_loot_toilet
/obj/structure/toilet/greyscale
-
- material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR
+ material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_EFFECTS
buildstacktype = null
/obj/structure/urinal
@@ -582,6 +581,12 @@
G.use(1)
return
+ if(istype(O, /obj/item/stack/ore/glass))
+ new /obj/item/stack/sheet/sandblock(loc)
+ to_chat(user, "You wet the sand in the sink and form it into a block.")
+ O.use(1)
+ return
+
if(!istype(O))
return
if(O.item_flags & ABSTRACT) //Abstract items like grabs won't wash. No-drop items will though because it's still technically an item in your hand.
@@ -702,11 +707,6 @@
icon_state = "puddle"
resistance_flags = UNACIDABLE
-/obj/structure/sink/greyscale
- icon_state = "sink_greyscale"
- material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR
- buildstacktype = null
-
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/structure/sink/puddle/attack_hand(mob/M)
icon_state = "puddle-splash"
@@ -722,7 +722,8 @@
qdel(src)
/obj/structure/sink/greyscale
- material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR
+ icon_state = "sink_greyscale"
+ material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_EFFECTS
buildstacktype = null
//Shower Curtains//
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index 75603a1116..bdca384bd0 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -189,9 +189,12 @@
if(user && !silent)
to_chat(user, "You remove the floor tile.")
if(floor_tile && make_tile)
- new floor_tile(src)
+ spawn_tile()
return make_plating()
+/turf/open/floor/proc/spawn_tile()
+ new floor_tile(src)
+
/turf/open/floor/singularity_pull(S, current_size)
. = ..()
switch(current_size)
@@ -293,3 +296,13 @@
return TRUE
return FALSE
+
+/turf/open/floor/material
+ name = "floor"
+ icon_state = "materialfloor"
+ material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+
+/turf/open/floor/material/spawn_tile()
+ for(var/i in custom_materials)
+ var/datum/material/M = i
+ new M.sheet_type(src, FLOOR(custom_materials[M] / MINERAL_MATERIAL_AMOUNT, 1))
diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm
index 8e0eace9cd..f26a4b827a 100644
--- a/code/game/turfs/simulated/floor/plating.dm
+++ b/code/game/turfs/simulated/floor/plating.dm
@@ -76,11 +76,15 @@
var/obj/item/stack/tile/W = C
if(!W.use(1))
return
- var/turf/open/floor/T = PlaceOnTop(W.turf_type, flags = CHANGETURF_INHERIT_AIR)
- if(istype(W, /obj/item/stack/tile/light)) //TODO: get rid of this ugly check somehow
- var/obj/item/stack/tile/light/L = W
- var/turf/open/floor/light/F = T
- F.state = L.state
+ if(istype(W, /obj/item/stack/tile/material))
+ var/turf/newturf = PlaceOnTop(/turf/open/floor/material, flags = CHANGETURF_INHERIT_AIR)
+ newturf.set_custom_materials(W.custom_materials)
+ else if(W.turf_type)
+ var/turf/open/floor/T = PlaceOnTop(W.turf_type, flags = CHANGETURF_INHERIT_AIR)
+ if(istype(W, /obj/item/stack/tile/light)) //TODO: get rid of this ugly check somehow
+ var/obj/item/stack/tile/light/L = W
+ var/turf/open/floor/light/F = T
+ F.state = L.state
playsound(src, 'sound/weapons/genhit.ogg', 50, 1)
else
to_chat(user, "This section is too damaged to support a tile! Use a welder to fix the damage.")
diff --git a/code/game/turfs/simulated/wall/material_walls.dm b/code/game/turfs/simulated/wall/material_walls.dm
new file mode 100644
index 0000000000..d3952609e0
--- /dev/null
+++ b/code/game/turfs/simulated/wall/material_walls.dm
@@ -0,0 +1,22 @@
+/turf/closed/wall/material
+ name = "wall"
+ desc = "A huge chunk of material used to separate rooms."
+ icon = 'icons/turf/walls/materialwall.dmi'
+ icon_state = "wall"
+ canSmoothWith = list(/turf/closed/wall/material)
+ smooth = SMOOTH_TRUE
+ material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+
+/turf/closed/wall/material/break_wall()
+ for(var/i in custom_materials)
+ var/datum/material/M = i
+ new M.sheet_type(src, FLOOR(custom_materials[M] / MINERAL_MATERIAL_AMOUNT, 1))
+ return new girder_type(src)
+
+/turf/closed/wall/material/devastate_wall()
+ for(var/i in custom_materials)
+ var/datum/material/M = i
+ new M.sheet_type(src, FLOOR(custom_materials[M] / MINERAL_MATERIAL_AMOUNT, 1))
+
+/turf/closed/wall/material/mat_update_desc(mat)
+ desc = "A huge chunk of [mat] used to separate rooms."
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 88f6dd6962..5db289bd31 100755
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -85,6 +85,9 @@
if (opacity)
has_opaque_atom = TRUE
+ // apply materials properly from the default custom_materials value
+ set_custom_materials(custom_materials)
+
ComponentInitialize()
return INITIALIZE_HINT_NORMAL
diff --git a/code/modules/antagonists/bloodsucker/items/bloodsucker_organs.dm b/code/modules/antagonists/bloodsucker/items/bloodsucker_organs.dm
index 640c53946f..25de64fe34 100644
--- a/code/modules/antagonists/bloodsucker/items/bloodsucker_organs.dm
+++ b/code/modules/antagonists/bloodsucker/items/bloodsucker_organs.dm
@@ -31,10 +31,6 @@
beating = 0
var/fakingit = 0
-/obj/item/organ/heart/vampheart/prepare_eat()
- ..()
- // Do cool stuff for eating vamp heart?
-
/obj/item/organ/heart/vampheart/Restart()
beating = 0 // DONT run ..(). We don't want to start beating again.
return 0
diff --git a/code/modules/arousal/genitals.dm b/code/modules/arousal/genitals.dm
index fb254a2dcc..4d2e5e6fef 100644
--- a/code/modules/arousal/genitals.dm
+++ b/code/modules/arousal/genitals.dm
@@ -1,7 +1,7 @@
/obj/item/organ/genital
color = "#fcccb3"
w_class = WEIGHT_CLASS_SMALL
- organ_flags = ORGAN_NO_DISMEMBERMENT
+ organ_flags = ORGAN_NO_DISMEMBERMENT|ORGAN_EDIBLE
var/shape
var/sensitivity = 1 // wow if this were ever used that'd be cool but it's not but i'm keeping it for my unshit code
var/genital_flags //see citadel_defines.dm
diff --git a/code/modules/food_and_drinks/food.dm b/code/modules/food_and_drinks/food.dm
index 203eb3eef6..f83a1222fd 100644
--- a/code/modules/food_and_drinks/food.dm
+++ b/code/modules/food_and_drinks/food.dm
@@ -6,7 +6,6 @@
/// get_random_food proc.
////////////////////////////////////////////////////////////////////////////////
-#define STOP_SERVING_BREAKFAST (15 MINUTES)
/obj/item/reagent_containers/food
possible_transfer_amounts = list()
@@ -51,5 +50,3 @@
if((foodtype & BREAKFAST) && world.time - SSticker.round_start_time < STOP_SERVING_BREAKFAST)
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "breakfast", /datum/mood_event/breakfast)
last_check_time = world.time
-
-#undef STOP_SERVING_BREAKFAST
diff --git a/code/modules/food_and_drinks/food/snacks/meat.dm b/code/modules/food_and_drinks/food/snacks/meat.dm
index b8fa64a7bc..a35dcc1dc4 100644
--- a/code/modules/food_and_drinks/food/snacks/meat.dm
+++ b/code/modules/food_and_drinks/food/snacks/meat.dm
@@ -1,6 +1,7 @@
/obj/item/reagent_containers/food/snacks/meat
var/subjectname = ""
var/subjectjob = null
+ custom_materials = list(/datum/material/meat = MINERAL_MATERIAL_AMOUNT * 4)
/obj/item/reagent_containers/food/snacks/meat/slab
name = "meat"
diff --git a/code/modules/food_and_drinks/food/snacks_pizza.dm b/code/modules/food_and_drinks/food/snacks_pizza.dm
index ebc67a28c1..f30c182963 100644
--- a/code/modules/food_and_drinks/food/snacks_pizza.dm
+++ b/code/modules/food_and_drinks/food/snacks_pizza.dm
@@ -10,6 +10,17 @@
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1)
foodtype = GRAIN | DAIRY | VEGETABLES
+/obj/item/reagent_containers/food/snacks/pizzaslice/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/kitchen/rollingpin))
+ if(!isturf(loc))
+ to_chat(user, "You need to put [src] on a surface to roll it out!")
+ return
+ new /obj/item/stack/sheet/pizza(loc)
+ to_chat(user, "You smoosh [src] into a cheesy sheet.")
+ qdel(src)
+ return
+ return ..()
+
/obj/item/reagent_containers/food/snacks/pizzaslice
icon = 'icons/obj/food/pizzaspaghetti.dmi'
list_reagents = list(/datum/reagent/consumable/nutriment = 5)
diff --git a/code/modules/mining/equipment/regenerative_core.dm b/code/modules/mining/equipment/regenerative_core.dm
index 439929b9c1..1de3a86702 100644
--- a/code/modules/mining/equipment/regenerative_core.dm
+++ b/code/modules/mining/equipment/regenerative_core.dm
@@ -111,9 +111,6 @@
go_inert()
return ..()
-/obj/item/organ/regenerative_core/prepare_eat()
- return null
-
/*************************Legion core********************/
/obj/item/organ/regenerative_core/legion
desc = "A strange rock that crackles with power. It can be used to heal completely, but it will rapidly decay into uselessness."
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index f6b7110803..f429230453 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -17,7 +17,6 @@
var/points = 0 //How many points this ore gets you from the ore redemption machine
var/refined_type = null //What this ore defaults to being refined into
novariants = TRUE // Ore stacks handle their icon updates themselves to keep the illusion that there's more going
- mats_per_stack = MINERAL_MATERIAL_AMOUNT
var/list/stack_overlays
/obj/item/stack/ore/update_overlays()
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index 687442c1f8..4fda02317e 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -76,9 +76,6 @@
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C)
C.update_hair()
-/obj/item/organ/brain/prepare_eat()
- return // Too important to eat.
-
/obj/item/organ/brain/proc/transfer_identity(mob/living/L)
name = "[L.name]'s brain"
if(brainmob)
diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm
index 8485fece85..8e3966eb03 100644
--- a/code/modules/mob/living/carbon/alien/organs.dm
+++ b/code/modules/mob/living/carbon/alien/organs.dm
@@ -1,7 +1,8 @@
/obj/item/organ/alien
icon_state = "xgibmid2"
+ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
var/list/alien_powers = list()
- organ_flags = ORGAN_NO_SPOIL
+ organ_flags = ORGAN_NO_SPOIL|ORGAN_EDIBLE
/obj/item/organ/alien/Initialize()
. = ..()
@@ -26,12 +27,6 @@
owner.RemoveAbility(P)
..()
-/obj/item/organ/alien/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
- return S
-
-
/obj/item/organ/alien/plasmavessel
name = "plasma vessel"
icon_state = "plasma"
@@ -39,17 +34,13 @@
zone = BODY_ZONE_CHEST
slot = "plasmavessel"
alien_powers = list(/obj/effect/proc_holder/alien/plant, /obj/effect/proc_holder/alien/transfer)
+ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/plasma = 10)
var/storedPlasma = 100
var/max_plasma = 250
var/heal_rate = 5
var/plasma_rate = 10
-/obj/item/organ/alien/plasmavessel/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent(/datum/reagent/toxin/plasma, storedPlasma/10)
- return S
-
/obj/item/organ/alien/plasmavessel/large
name = "large plasma vessel"
icon_state = "plasma_large"
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index 9bb50bdf42..bb92eb79bd 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -4,6 +4,7 @@
name = "alien embryo"
icon = 'icons/mob/alien.dmi'
icon_state = "larva0_dead"
+ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
var/stage = 0
var/bursting = FALSE
@@ -16,11 +17,6 @@
if(prob(10))
AttemptGrow(0)
-/obj/item/organ/body_egg/alien_embryo/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
- return S
-
/obj/item/organ/body_egg/alien_embryo/on_life()
. = ..()
if(!owner)
diff --git a/code/modules/mob/living/carbon/human/species_types/dwarves.dm b/code/modules/mob/living/carbon/human/species_types/dwarves.dm
index bc5f198b4d..7ca057711e 100644
--- a/code/modules/mob/living/carbon/human/species_types/dwarves.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dwarves.dm
@@ -89,11 +89,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
//These count in on_life ticks which should be 2 seconds per every increment of 1 in a perfect world.
var/dwarf_eth_ticker = 0 //Currently set =< 1, that means this will fire the proc around every 2 seconds
var/last_alcohol_spam
-
-/obj/item/organ/dwarfgland/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent(/datum/reagent/consumable/ethanol, stored_alcohol/10)
- return S
+ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/ethanol = 10)
/obj/item/organ/dwarfgland/on_life() //Primary loop to hook into to start delayed loops for other loops..
. = ..()
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index cb43a8489a..9e1e7a1b89 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -128,7 +128,7 @@
S.source = get_or_create_estorage(/datum/robot_energy_storage/wrapping_paper)
if(S && S.source)
- S.custom_materials = null
+ S.set_custom_materials(null)
S.is_cyborg = 1
if(I.loc != src)
diff --git a/code/modules/projectiles/boxes_magazines/_box_magazine.dm b/code/modules/projectiles/boxes_magazines/_box_magazine.dm
index 8ebddaa24f..9ea030da99 100644
--- a/code/modules/projectiles/boxes_magazines/_box_magazine.dm
+++ b/code/modules/projectiles/boxes_magazines/_box_magazine.dm
@@ -114,11 +114,13 @@
/obj/item/ammo_box/update_icon()
. = ..()
desc = "[initial(desc)] There [stored_ammo.len == 1 ? "is" : "are"] [stored_ammo.len] shell\s left!"
- for (var/material in bullet_cost)
- var/material_amount = bullet_cost[material]
- material_amount = (material_amount*stored_ammo.len) + base_cost[material]
- custom_materials[material] = material_amount
- set_custom_materials(custom_materials)//make sure we setup the correct properties again
+ if(length(bullet_cost))
+ var/temp_materials = custom_materials.Copy()
+ for (var/material in bullet_cost)
+ var/material_amount = bullet_cost[material]
+ material_amount = (material_amount*stored_ammo.len) + base_cost[material]
+ temp_materials[material] = material_amount
+ set_custom_materials(temp_materials)
/obj/item/ammo_box/update_icon_state()
switch(multiple_sprites)
diff --git a/code/modules/research/designs/machine_desings/machine_designs_all_misc.dm b/code/modules/research/designs/machine_desings/machine_designs_all_misc.dm
index 804556cb04..e0702be689 100644
--- a/code/modules/research/designs/machine_desings/machine_designs_all_misc.dm
+++ b/code/modules/research/designs/machine_desings/machine_designs_all_misc.dm
@@ -154,3 +154,12 @@
build_path = /obj/item/circuitboard/machine/shuttle/heater
category = list ("Shuttle Machinery")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/board/sheetifier
+ name = "Sheetifier"
+ desc = "This machine turns weird things into sheets."
+ id = "sheetifier"
+ build_path = /obj/item/circuitboard/machine/sheetifier
+ category = list ("Misc. Machinery")
+ departmental_flags = DEPARTMENTAL_FLAG_ALL
+
diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm
index a5df3f4d12..5a50120833 100644
--- a/code/modules/research/machinery/_production.dm
+++ b/code/modules/research/machinery/_production.dm
@@ -96,7 +96,7 @@
for(var/i in 1 to amount)
var/obj/O = new path(get_turf(src))
if(efficient_with(O.type))
- O.set_custom_materials(matlist.Copy())
+ O.set_custom_materials(matlist)
O.rnd_crafted(src)
SSblackbox.record_feedback("nested tally", "item_printed", amount, list("[type]", "[path]"))
investigate_log("[key_name(user)] built [amount] of [path] at [src]([type]).", INVESTIGATE_RESEARCH)
diff --git a/code/modules/research/techweb/nodes/engineering_nodes.dm b/code/modules/research/techweb/nodes/engineering_nodes.dm
index eac8c2faf2..d024823c85 100644
--- a/code/modules/research/techweb/nodes/engineering_nodes.dm
+++ b/code/modules/research/techweb/nodes/engineering_nodes.dm
@@ -16,7 +16,9 @@
display_name = "Advanced Engineering"
description = "Pushing the boundaries of physics, one chainsaw-fist at a time."
prereq_ids = list("engineering", "emp_basic")
- design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask" , "rcd_loaded", "rpd", "tray_goggles_prescription", "engine_goggles_prescription", "mesons_prescription", "rcd_upgrade_frames", "rcd_upgrade_simple_circuits", "rcd_ammo_large")
+ design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask" , "rcd_loaded", "rpd",
+ "tray_goggles_prescription", "engine_goggles_prescription", "mesons_prescription", "rcd_upgrade_frames",
+ "rcd_upgrade_simple_circuits", "rcd_ammo_large", "sheetifier")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000)
/datum/techweb_node/anomaly
diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm
index f493137424..4ce51ae119 100644
--- a/code/modules/surgery/organ_manipulation.dm
+++ b/code/modules/surgery/organ_manipulation.dm
@@ -61,7 +61,7 @@
time = 64
name = "manipulate organs"
repeatable = 1
- implements = list(/obj/item/organ = 100, /obj/item/reagent_containers/food/snacks/organ = 0, /obj/item/organ_storage = 100)
+ implements = list(/obj/item/organ = 100, /obj/item/organ_storage = 100)
var/implements_extract = list(TOOL_HEMOSTAT = 100, TOOL_CROWBAR = 55)
var/current_type
var/obj/item/organ/I = null
@@ -85,6 +85,10 @@
if(target_zone != I.zone || target.getorganslot(I.slot))
to_chat(user, "There is no room for [I] in [target]'s [parse_zone(target_zone)]!")
return -1
+ var/obj/item/organ/meatslab = tool
+ if(!meatslab.useable)
+ to_chat(user, "[I] seems to have been chewed on, you can't use this!")
+ return -1
display_results(user, target, "You begin to insert [tool] into [target]'s [parse_zone(target_zone)]...",
"[user] begins to insert [tool] into [target]'s [parse_zone(target_zone)].",
"[user] begins to insert something into [target]'s [parse_zone(target_zone)].")
@@ -111,9 +115,6 @@
else
return -1
- else if(istype(tool, /obj/item/reagent_containers/food/snacks/organ))
- to_chat(user, "[tool] was bitten by someone! It's too damaged to use!")
- return -1
/datum/surgery_step/manipulate_organs/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(current_type == "insert")
if(istype(tool, /obj/item/organ_storage))
diff --git a/code/modules/surgery/organs/appendix.dm b/code/modules/surgery/organs/appendix.dm
index c737e8bc30..782991d79c 100644
--- a/code/modules/surgery/organs/appendix.dm
+++ b/code/modules/surgery/organs/appendix.dm
@@ -37,9 +37,3 @@
..()
if(inflamed)
M.ForceContractDisease(new /datum/disease/appendicitis(), FALSE, TRUE)
-
-/obj/item/organ/appendix/prepare_eat()
- var/obj/S = ..()
- if(inflamed)
- S.reagents.add_reagent(/datum/reagent/toxin/bad_food, 5)
- return S
diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm
index 465c10c4cd..e251abfd35 100644
--- a/code/modules/surgery/organs/heart.dm
+++ b/code/modules/surgery/organs/heart.dm
@@ -61,10 +61,10 @@
return "a healthy"
return "an unstable"
-/obj/item/organ/heart/prepare_eat()
- var/obj/S = ..()
- S.icon_state = "[icon_base]-off"
- return S
+/obj/item/organ/heart/OnEatFrom(eater, feeder)
+ . = ..()
+ beating = FALSE
+ update_icon()
/obj/item/organ/heart/on_life()
. = ..()
diff --git a/code/modules/surgery/organs/liver.dm b/code/modules/surgery/organs/liver.dm
index b24034ca4a..2465b63800 100755
--- a/code/modules/surgery/organs/liver.dm
+++ b/code/modules/surgery/organs/liver.dm
@@ -23,6 +23,7 @@
var/toxLethality = LIVER_DEFAULT_TOX_LETHALITY//affects how much damage toxins do to the liver
var/filterToxins = TRUE //whether to filter toxins
var/cachedmoveCalc = 1
+ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/iron = 5)
/obj/item/organ/liver/on_life()
. = ..()
@@ -44,11 +45,6 @@
if(damage > 10 && prob(damage/3))//the higher the damage the higher the probability
to_chat(owner, "You feel a dull pain in your abdomen.")
-/obj/item/organ/liver/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent(/datum/reagent/iron, 5)
- return S
-
/obj/item/organ/liver/applyOrganDamage(d, maximum = maxHealth)
. = ..()
if(!. || QDELETED(owner))
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index b3020ae13f..949eef62d0 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -24,6 +24,8 @@
now_fixed = "Your lungs seem to once again be able to hold air."
high_threshold_cleared = "The constriction around your chest loosens as your breathing calms down."
+ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/medicine/salbutamol = 5)
+
//Breath damage
var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa
@@ -458,11 +460,6 @@
else if(!(organ_flags & ORGAN_FAILING))
failed = FALSE
-/obj/item/organ/lungs/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent(/datum/reagent/medicine/salbutamol, 5)
- return S
-
/obj/item/organ/lungs/ipc
name = "ipc lungs"
icon_state = "lungs-c"
diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm
index 761ebc17a2..0378340117 100644
--- a/code/modules/surgery/organs/organ_internal.dm
+++ b/code/modules/surgery/organs/organ_internal.dm
@@ -8,7 +8,7 @@
var/zone = BODY_ZONE_CHEST
var/slot
// DO NOT add slots with matching names to different zones - it will break internal_organs_slot list!
- var/organ_flags = NONE
+ var/organ_flags = ORGAN_EDIBLE
var/maxHealth = STANDARD_ORGAN_THRESHOLD
var/damage = 0 //total damage this organ has sustained
///Healing factor and decay factor function on % of maxhealth, and do not work by applying a static number per tick
@@ -25,7 +25,23 @@
var/now_fixed
var/high_threshold_cleared
var/low_threshold_cleared
- rad_flags = RAD_NO_CONTAMINATE
+
+ ///When you take a bite you cant jam it in for surgery anymore.
+ var/useable = TRUE
+ var/list/food_reagents = list(/datum/reagent/consumable/nutriment = 5)
+
+/obj/item/organ/Initialize()
+ . = ..()
+ if(organ_flags & ORGAN_EDIBLE)
+ AddComponent(/datum/component/edible, food_reagents, null, RAW | MEAT | GROSS, null, 10, null, null, null, CALLBACK(src, .proc/OnEatFrom))
+ START_PROCESSING(SSobj, src)
+
+/obj/item/organ/Destroy()
+ if(owner)
+ // The special flag is important, because otherwise mobs can die
+ // while undergoing transformation into different mobs.
+ Remove(TRUE)
+ return ..()
/obj/item/organ/proc/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
if(!iscarbon(M) || owner == M)
@@ -157,47 +173,8 @@
if(damage > high_threshold)
. += "[src] is starting to look discolored."
-
-/obj/item/organ/proc/prepare_eat()
- var/obj/item/reagent_containers/food/snacks/organ/S = new
- S.name = name
- S.desc = desc
- S.icon = icon
- S.icon_state = icon_state
- S.w_class = w_class
-
- return S
-
-/obj/item/reagent_containers/food/snacks/organ
- name = "appendix"
- icon_state = "appendix"
- icon = 'icons/obj/surgery.dmi'
- list_reagents = list(/datum/reagent/consumable/nutriment = 5)
- foodtype = RAW | MEAT | GROSS
-
-
-/obj/item/organ/Initialize()
- . = ..()
- START_PROCESSING(SSobj, src)
-
-/obj/item/organ/Destroy()
- if(owner)
- // The special flag is important, because otherwise mobs can die
- // while undergoing transformation into different mobs.
- Remove(TRUE)
- return ..()
-
-/obj/item/organ/attack(mob/living/carbon/M, mob/user)
- if(M == user && ishuman(user))
- var/mob/living/carbon/human/H = user
- if(status == ORGAN_ORGANIC)
- var/obj/item/reagent_containers/food/snacks/S = prepare_eat()
- if(S)
- qdel(src)
- if(H.put_in_active_hand(S))
- S.attack(H, H)
- else
- ..()
+/obj/item/organ/proc/OnEatFrom(eater, feeder)
+ useable = FALSE //You can't use it anymore after eating it you spaztic
/obj/item/organ/item_action_slot_check(slot,mob/user)
return //so we don't grant the organ's action to mobs who pick up the organ.
diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm
index f8547dda6e..1c4a2d3043 100644
--- a/code/modules/surgery/organs/tongue.dm
+++ b/code/modules/surgery/organs/tongue.dm
@@ -252,6 +252,7 @@
name = "robotic voicebox"
desc = "A voice synthesizer that can interface with organic lifeforms."
status = ORGAN_ROBOTIC
+ organ_flags = ORGAN_NO_SPOIL
icon_state = "tonguerobot"
say_mod = "states"
attack_verb = list("beeped", "booped")
diff --git a/icons/materials/composite.dmi b/icons/materials/composite.dmi
new file mode 100644
index 0000000000..a2a92b6eb7
Binary files /dev/null and b/icons/materials/composite.dmi differ
diff --git a/icons/obj/machines/sheetifier.dmi b/icons/obj/machines/sheetifier.dmi
new file mode 100644
index 0000000000..46d8b06bab
Binary files /dev/null and b/icons/obj/machines/sheetifier.dmi differ
diff --git a/icons/obj/stack_objects.dmi b/icons/obj/stack_objects.dmi
index ac6478928d..aa29bd63cc 100644
Binary files a/icons/obj/stack_objects.dmi and b/icons/obj/stack_objects.dmi differ
diff --git a/icons/obj/tiles.dmi b/icons/obj/tiles.dmi
index 09568ebea1..df080ce3e6 100644
Binary files a/icons/obj/tiles.dmi and b/icons/obj/tiles.dmi differ
diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi
index 477120870b..20963e7fbe 100644
Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ
diff --git a/icons/turf/walls/materialwall.dmi b/icons/turf/walls/materialwall.dmi
new file mode 100644
index 0000000000..c497f76c2e
Binary files /dev/null and b/icons/turf/walls/materialwall.dmi differ
diff --git a/sound/effects/meatslap.ogg b/sound/effects/meatslap.ogg
new file mode 100644
index 0000000000..3d8ea7df1a
Binary files /dev/null and b/sound/effects/meatslap.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index 78cce84a0c..7559e432f4 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -405,6 +405,7 @@
#include "code\datums\components\construction.dm"
#include "code\datums\components\dejavu.dm"
#include "code\datums\components\earprotection.dm"
+#include "code\datums\components\edible.dm"
#include "code\datums\components\edit_complainer.dm"
#include "code\datums\components\embedded.dm"
#include "code\datums\components\explodable.dm"
@@ -579,6 +580,8 @@
#include "code\datums\martial\wrestling.dm"
#include "code\datums\materials\_material.dm"
#include "code\datums\materials\basemats.dm"
+#include "code\datums\materials\meat.dm"
+#include "code\datums\materials\pizza.dm"
#include "code\datums\mood_events\beauty_events.dm"
#include "code\datums\mood_events\drink_events.dm"
#include "code\datums\mood_events\drug_events.dm"
@@ -761,6 +764,7 @@
#include "code\game\machinery\rechargestation.dm"
#include "code\game\machinery\recycler.dm"
#include "code\game\machinery\requests_console.dm"
+#include "code\game\machinery\sheetifier.dm"
#include "code\game\machinery\shieldgen.dm"
#include "code\game\machinery\Sleeper.dm"
#include "code\game\machinery\slotmachine.dm"
@@ -1272,6 +1276,7 @@
#include "code\game\turfs\simulated\floor\plating\asteroid.dm"
#include "code\game\turfs\simulated\floor\plating\dirt.dm"
#include "code\game\turfs\simulated\floor\plating\misc_plating.dm"
+#include "code\game\turfs\simulated\wall\material_walls.dm"
#include "code\game\turfs\simulated\wall\mineral_walls.dm"
#include "code\game\turfs\simulated\wall\misc_walls.dm"
#include "code\game\turfs\simulated\wall\reinf_walls.dm"