diff --git a/code/__defines/materials.dm b/code/__defines/materials.dm
new file mode 100644
index 0000000000..499c974b47
--- /dev/null
+++ b/code/__defines/materials.dm
@@ -0,0 +1,63 @@
+#define DEFAULT_TABLE_MATERIAL "plastic"
+#define DEFAULT_WALL_MATERIAL "steel"
+
+#define MAT_IRON "iron"
+#define MAT_MARBLE "marble"
+#define MAT_STEEL "steel"
+#define MAT_PLASTIC "plastic"
+#define MAT_GLASS "glass"
+#define MAT_SILVER "silver"
+#define MAT_GOLD "gold"
+#define MAT_URANIUM "uranium"
+#define MAT_TITANIUM "titanium"
+#define MAT_PHORON "phoron"
+#define MAT_DIAMOND "diamond"
+#define MAT_SNOW "snow"
+#define MAT_SNOWBRICK "packed snow"
+#define MAT_WOOD "wood"
+#define MAT_LOG "log"
+#define MAT_SIFWOOD "alien wood"
+#define MAT_SIFLOG "alien log"
+#define MAT_STEELHULL "steel hull"
+#define MAT_PLASTEEL "plasteel"
+#define MAT_PLASTEELHULL "plasteel hull"
+#define MAT_DURASTEEL "durasteel"
+#define MAT_DURASTEELHULL "durasteel hull"
+#define MAT_TITANIUMHULL "titanium hull"
+#define MAT_VERDANTIUM "verdantium"
+#define MAT_MORPHIUM "morphium"
+#define MAT_MORPHIUMHULL "morphium hull"
+#define MAT_VALHOLLIDE "valhollide"
+#define MAT_LEAD "lead"
+#define MAT_SUPERMATTER "supermatter"
+#define MAT_METALHYDROGEN "mhydrogen"
+#define MAT_OSMIUM "osmium"
+#define MAT_GRAPHITE "graphite"
+#define MAT_LEATHER "leather"
+#define MAT_CHITIN "chitin"
+#define MAT_CLOTH "cloth"
+#define MAT_SYNCLOTH "syncloth"
+#define MAT_COPPER "copper"
+#define MAT_QUARTZ "quartz"
+#define MAT_TIN "tin"
+#define MAT_VOPAL "void opal"
+#define MAT_ALUMINIUM "aluminium"
+#define MAT_BRONZE "bronze"
+#define MAT_PAINITE "painite"
+#define MAT_BOROSILICATE "borosilicate glass"
+#define MAT_SANDSTONE "sandstone"
+
+#define SHARD_SHARD "shard"
+#define SHARD_SHRAPNEL "shrapnel"
+#define SHARD_STONE_PIECE "piece"
+#define SHARD_SPLINTER "splinters"
+#define SHARD_NONE ""
+
+#define MATERIAL_UNMELTABLE 0x1
+#define MATERIAL_BRITTLE 0x2
+#define MATERIAL_PADDING 0x4
+
+#define DEFAULT_TABLE_MATERIAL "plastic"
+#define DEFAULT_WALL_MATERIAL "steel"
+
+#define TABLE_BRITTLE_MATERIAL_MULTIPLIER 4 // Amount table damage is multiplied by if it is made of a brittle material (e.g. glass)
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index f867182c09..eeb824b405 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -121,65 +121,6 @@
#define WALL_CAN_OPEN 1
#define WALL_OPENING 2
-#define DEFAULT_TABLE_MATERIAL "plastic"
-#define DEFAULT_WALL_MATERIAL "steel"
-
-#define MAT_IRON "iron"
-#define MAT_MARBLE "marble"
-#define MAT_STEEL "steel"
-#define MAT_PLASTIC "plastic"
-#define MAT_GLASS "glass"
-#define MAT_SILVER "silver"
-#define MAT_GOLD "gold"
-#define MAT_URANIUM "uranium" //Did it
-#define MAT_TITANIUM "titanium"
-#define MAT_PHORON "phoron"
-#define MAT_DIAMOND "diamond"
-#define MAT_SNOW "snow"
-#define MAT_WOOD "wood"
-#define MAT_LOG "log"
-#define MAT_SIFWOOD "alien wood"
-#define MAT_SIFLOG "alien log"
-#define MAT_STEELHULL "steel hull"
-#define MAT_PLASTEEL "plasteel"
-#define MAT_PLASTEELHULL "plasteel hull"
-#define MAT_DURASTEEL "durasteel"
-#define MAT_DURASTEELHULL "durasteel hull"
-#define MAT_TITANIUMHULL "titanium hull"
-#define MAT_VERDANTIUM "verdantium"
-#define MAT_MORPHIUM "morphium"
-#define MAT_MORPHIUMHULL "morphium hull"
-#define MAT_VALHOLLIDE "valhollide"
-#define MAT_LEAD "lead"
-#define MAT_SUPERMATTER "supermatter"
-#define MAT_METALHYDROGEN "mhydrogen"
-#define MAT_OSMIUM "osmium"
-#define MAT_GRAPHITE "graphite"
-#define MAT_LEATHER "leather"
-#define MAT_CHITIN "chitin"
-#define MAT_CLOTH "cloth"
-#define MAT_SYNCLOTH "syncloth"
-#define MAT_COPPER "copper"
-#define MAT_QUARTZ "quartz"
-#define MAT_TIN "tin"
-#define MAT_VOPAL "void opal"
-#define MAT_ALUMINIUM "aluminium"
-#define MAT_BRONZE "bronze"
-#define MAT_PAINITE "painite"
-#define MAT_BOROSILICATE "borosilicate glass"
-
-#define SHARD_SHARD "shard"
-#define SHARD_SHRAPNEL "shrapnel"
-#define SHARD_STONE_PIECE "piece"
-#define SHARD_SPLINTER "splinters"
-#define SHARD_NONE ""
-
-#define MATERIAL_UNMELTABLE 0x1
-#define MATERIAL_BRITTLE 0x2
-#define MATERIAL_PADDING 0x4
-
-#define TABLE_BRITTLE_MATERIAL_MULTIPLIER 4 // Amount table damage is multiplied by if it is made of a brittle material (e.g. glass)
-
#define BOMBCAP_DVSTN_RADIUS (max_explosion_range/4)
#define BOMBCAP_HEAVY_RADIUS (max_explosion_range/2)
#define BOMBCAP_LIGHT_RADIUS max_explosion_range
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
deleted file mode 100644
index c2535ec3eb..0000000000
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ /dev/null
@@ -1,102 +0,0 @@
-/* Glass stack types
- * Contains:
- * Glass sheets
- * Reinforced glass sheets
- * Phoron Glass Sheets
- * Reinforced Phoron Glass Sheets (AKA Holy fuck strong windows)
- * Glass shards - TODO: Move this into code/game/object/item/weapons
- */
-
-/*
- * Glass sheets
- */
-/obj/item/stack/material/glass
- name = "glass"
- singular_name = "glass sheet"
- icon_state = "sheet-glass"
- var/is_reinforced = 0
- default_type = "glass"
- drop_sound = 'sound/items/drop/glass.ogg'
- pickup_sound = 'sound/items/pickup/glass.ogg'
-
-/obj/item/stack/material/glass/attack_self(mob/user as mob)
- construct_window(user)
-
-/obj/item/stack/material/glass/attackby(obj/item/W, mob/user)
- ..()
- if(!is_reinforced)
- if(istype(W,/obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/CC = W
- if (get_amount() < 1 || CC.get_amount() < 5)
- to_chat(user, "You need five lengths of coil and one sheet of glass to make wired glass.")
- return
-
- CC.use(5)
- use(1)
- to_chat(user, "You attach wire to the [name].")
- new /obj/item/stack/light_w(user.loc)
- else if(istype(W, /obj/item/stack/rods))
- var/obj/item/stack/rods/V = W
- if (V.get_amount() < 1 || get_amount() < 1)
- to_chat(user, "You need one rod and one sheet of glass to make reinforced glass.")
- return
-
- var/obj/item/stack/material/glass/reinforced/RG = new (user.loc)
- RG.add_fingerprint(user)
- RG.add_to_stacks(user)
- var/obj/item/stack/material/glass/G = src
- src = null
- var/replace = (user.get_inactive_hand()==G)
- V.use(1)
- G.use(1)
- if (!G && replace)
- user.put_in_hands(RG)
-
-
-
-
-/*
- * Reinforced glass sheets
- */
-/obj/item/stack/material/glass/reinforced
- name = "reinforced glass"
- singular_name = "reinforced glass sheet"
- icon_state = "sheet-rglass"
- default_type = "reinforced glass"
- is_reinforced = 1
-
-/*
- * Phoron Glass sheets
- */
-/obj/item/stack/material/glass/phoronglass
- name = "phoron glass"
- singular_name = "phoron glass sheet"
- icon_state = "sheet-phoronglass"
- default_type = "phoron glass"
-
-/obj/item/stack/material/glass/phoronglass/attackby(obj/item/W, mob/user)
- ..()
- if( istype(W, /obj/item/stack/rods) )
- var/obj/item/stack/rods/V = W
- var/obj/item/stack/material/glass/phoronrglass/RG = new (user.loc)
- RG.add_fingerprint(user)
- RG.add_to_stacks(user)
- V.use(1)
- var/obj/item/stack/material/glass/G = src
- src = null
- var/replace = (user.get_inactive_hand()==G)
- G.use(1)
- if (!G && !RG && replace)
- user.put_in_hands(RG)
- else
- return ..()
-
-/*
- * Reinforced phoron glass sheets
- */
-/obj/item/stack/material/glass/phoronrglass
- name = "reinforced phoron glass"
- singular_name = "reinforced phoron glass sheet"
- icon_state = "sheet-phoronrglass"
- default_type = "reinforced phoron glass"
- is_reinforced = 1
diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm
deleted file mode 100644
index c48f57e693..0000000000
--- a/code/game/objects/items/stacks/sheets/leather.dm
+++ /dev/null
@@ -1,286 +0,0 @@
-/obj/item/stack/animalhide
- name = "hide"
- desc = "The hide of some creature."
- description_info = "Use something sharp, like a knife, to scrape the hairs/feathers/etc off this hide to prepare it for tanning."
- icon_state = "sheet-hide"
- drop_sound = 'sound/items/drop/cloth.ogg'
- pickup_sound = 'sound/items/pickup/cloth.ogg'
- amount = 1
- max_amount = 20
- stacktype = "hide"
- no_variants = TRUE
-// This needs to be very clearly documented for players. Whether it should stay in the main description is up for debate.
-/obj/item/stack/animalhide/examine(var/mob/user)
- . = ..()
- . += description_info
-
-/obj/item/stack/animalhide/human
- name = "skin"
- desc = "The by-product of sapient farming."
- singular_name = "skin piece"
- icon_state = "sheet-hide"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/leather.ogg'
- pickup_sound = 'sound/items/pickup/leather.ogg'
- stacktype = "hide-human"
-
-/obj/item/stack/animalhide/corgi
- name = "corgi hide"
- desc = "The by-product of corgi farming."
- singular_name = "corgi hide piece"
- icon_state = "sheet-corgi"
- stacktype = "hide-corgi"
-
-/obj/item/stack/animalhide/cat
- name = "cat hide"
- desc = "The by-product of cat farming."
- singular_name = "cat hide piece"
- icon_state = "sheet-cat"
- stacktype = "hide-cat"
-
-/obj/item/stack/animalhide/monkey
- name = "monkey hide"
- desc = "The by-product of monkey farming."
- singular_name = "monkey hide piece"
- icon_state = "sheet-monkey"
- stacktype = "hide-monkey"
-
-/obj/item/stack/animalhide/lizard
- name = "lizard skin"
- desc = "Sssssss..."
- singular_name = "lizard skin piece"
- icon_state = "sheet-lizard"
- stacktype = "hide-lizard"
-
-/obj/item/stack/animalhide/xeno
- name = "alien hide"
- desc = "The skin of a terrible creature."
- singular_name = "alien hide piece"
- icon_state = "sheet-xeno"
- stacktype = "hide-xeno"
-
-//don't see anywhere else to put these, maybe together they could be used to make the xenos suit?
-/obj/item/stack/xenochitin
- name = "alien chitin"
- desc = "A piece of the hide of a terrible creature."
- singular_name = "alien chitin piece"
- icon = 'icons/mob/alien.dmi'
- icon_state = "chitin"
- stacktype = "hide-chitin"
-
-/obj/item/xenos_claw
- name = "alien claw"
- desc = "The claw of a terrible creature."
- icon = 'icons/mob/alien.dmi'
- icon_state = "claw"
-
-/obj/item/weed_extract
- name = "weed extract"
- desc = "A piece of slimy, purplish weed."
- icon = 'icons/mob/alien.dmi'
- icon_state = "weed_extract"
-
-//Step one - dehairing.
-/obj/item/stack/animalhide/attackby(obj/item/weapon/W as obj, mob/user as mob)
- if(has_edge(W) || is_sharp(W))
- //visible message on mobs is defined as visible_message(var/message, var/self_message, var/blind_message)
- user.visible_message("\The [user] starts cutting hair off \the [src]", "You start cutting the hair off \the [src]", "You hear the sound of a knife rubbing against flesh")
- var/scraped = 0
- while(amount > 0 && do_after(user, 2.5 SECONDS)) // 2.5s per hide
- //Try locating an exisitng stack on the tile and add to there if possible
- var/obj/item/stack/hairlesshide/H = null
- for(var/obj/item/stack/hairlesshide/HS in user.loc) // Could be scraping something inside a locker, hence the .loc, not get_turf
- if(HS.amount < HS.max_amount)
- H = HS
- break
-
- // Either we found a valid stack, in which case increment amount,
- // Or we need to make a new stack
- if(istype(H))
- H.amount++
- else
- H = new /obj/item/stack/hairlesshide(user.loc)
-
- // Increment the amount
- src.use(1)
- scraped++
-
- if(scraped)
- to_chat(user, SPAN_NOTICE("You scrape the hair off [scraped] hide\s."))
- else
- ..()
-
-
-//Step two - washing..... it's actually in washing machine code, and ere.
-
-/obj/item/stack/hairlesshide
- name = "hairless hide"
- desc = "This hide was stripped of it's hair, but still needs tanning."
- description_info = "Get it wet to continue tanning this into leather.
\
- You could set it in a river, wash it with a sink, or just splash water on it with a bucket."
- singular_name = "hairless hide piece"
- icon_state = "sheet-hairlesshide"
- no_variants = FALSE
- max_amount = 20
- stacktype = "hairlesshide"
-
-/obj/item/stack/hairlesshide/examine(var/mob/user)
- . = ..()
- . += description_info
-
-/obj/item/stack/hairlesshide/water_act(var/wateramount)
- . = ..()
- wateramount = min(amount, round(wateramount))
- for(var/i in 1 to wateramount)
- var/obj/item/stack/wetleather/H = null
- for(var/obj/item/stack/wetleather/HS in get_turf(src)) // Doesn't have a user, can't just use their loc
- if(HS.amount < HS.max_amount)
- H = HS
- break
-
- // Either we found a valid stack, in which case increment amount,
- // Or we need to make a new stack
- if(istype(H))
- H.amount++
- else
- H = new /obj/item/stack/wetleather(get_turf(src))
-
- // Increment the amount
- src.use(1)
-
-/obj/item/stack/hairlesshide/proc/rapidcure(var/stacknum = 1)
- stacknum = min(stacknum, amount)
-
- while(stacknum)
- var/obj/item/stack/wetleather/I = new /obj/item/stack/wetleather(get_turf(src))
-
- if(istype(I))
- I.dry()
-
- use(1)
- stacknum -= 1
-
-//Step three - drying
-/obj/item/stack/wetleather
- name = "wet leather"
- desc = "This leather has been cleaned but still needs to be dried."
- description_info = "To finish tanning the leather, you need to dry it. \
- You could place it under a fire, \
- put it in a drying rack, \
- or build a tanning rack from steel or wooden boards."
- singular_name = "wet leather piece"
- icon_state = "sheet-wetleather"
- var/wetness = 30 //Reduced when exposed to high temperautres
- var/drying_threshold_temperature = 500 //Kelvin to start drying
- no_variants = FALSE
- max_amount = 20
- stacktype = "wetleather"
-
- var/dry_type = /obj/item/stack/material/leather
-
-/obj/item/stack/wetleather/examine(var/mob/user)
- . = ..()
- . += description_info
- . += "\The [src] is [get_dryness_text()]."
-
-/obj/item/stack/wetleather/proc/get_dryness_text()
- if(wetness > 20)
- return "wet"
- if(wetness > 10)
- return "damp"
- if(wetness)
- return "almost dry"
- return "dry"
-
-/obj/item/stack/wetleather/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- ..()
- if(exposed_temperature >= drying_threshold_temperature)
- wetness--
- if(wetness == 0)
- dry()
-
-/obj/item/stack/wetleather/proc/dry()
- var/obj/item/stack/material/leather/L = new(src.loc)
- L.amount = amount
- use(amount)
- return L
-
-/obj/item/stack/wetleather/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified)
- . = ..()
- if(.) // If it transfers any, do a weighted average of the wetness
- var/obj/item/stack/wetleather/W = S
- var/oldamt = W.amount - .
- W.wetness = round(((oldamt * W.wetness) + (. * wetness)) / W.amount)
-
-
-
-/obj/structure/tanning_rack
- name = "tanning rack"
- desc = "A rack used to stretch leather out and hold it taut during the tanning process."
- icon = 'icons/obj/kitchen.dmi'
- icon_state = "spike"
-
- var/obj/item/stack/wetleather/drying = null
-
-/obj/structure/tanning_rack/Initialize()
- . = ..()
- START_PROCESSING(SSobj, src) // SSObj fires ~every 2s , starting from wetness 30 takes ~1m
-
-/obj/structure/tanning_rack/Destroy()
- STOP_PROCESSING(SSobj, src)
- return ..()
-
-/obj/structure/tanning_rack/process()
- if(drying && drying.wetness)
- drying.wetness = max(drying.wetness - 1, 0)
- if(!drying.wetness)
- visible_message("The [drying] is dry!")
- update_icon()
-
-/obj/structure/tanning_rack/examine(var/mob/user)
- . = ..()
- if(drying)
- . += "\The [drying] is [drying.get_dryness_text()]."
-
-/obj/structure/tanning_rack/update_icon()
- overlays.Cut()
- if(drying)
- var/image/I
- if(drying.wetness)
- I = image(icon, "leather_wet")
- else
- I = image(icon, "leather_dry")
- add_overlay(I)
-
-/obj/structure/tanning_rack/attackby(var/atom/A, var/mob/user)
- if(istype(A, /obj/item/stack/wetleather))
- if(!drying) // If not drying anything, start drying the thing
- if(user.unEquip(A, target = src))
- drying = A
- else // Drying something, add if possible
- var/obj/item/stack/wetleather/W = A
- W.transfer_to(drying, W.amount, TRUE)
- update_icon()
- return TRUE
- return ..()
-
-/obj/structure/tanning_rack/attack_hand(var/mob/user)
- if(drying)
- var/obj/item/stack/S = drying
- if(!drying.wetness) // If it's dry, make a stack of dry leather and prepare to put that in their hands
- var/obj/item/stack/material/leather/L = new(src)
- L.amount = drying.amount
- drying.use(drying.amount)
- S = L
-
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- if(!H.put_in_any_hand_if_possible(S))
- S.forceMove(get_turf(src))
- else
- S.forceMove(get_turf(src))
- drying = null
- update_icon()
-
-/obj/structure/tanning_rack/attack_robot(var/mob/user)
- attack_hand(user) // That has checks to
\ No newline at end of file
diff --git a/code/modules/mining/coins.dm b/code/modules/economy/coins.dm
similarity index 100%
rename from code/modules/mining/coins.dm
rename to code/modules/economy/coins.dm
diff --git a/code/modules/mining/mint.dm b/code/modules/economy/mint.dm
similarity index 100%
rename from code/modules/mining/mint.dm
rename to code/modules/economy/mint.dm
diff --git a/code/modules/mining/money_bag.dm b/code/modules/economy/money_bag.dm
similarity index 95%
rename from code/modules/mining/money_bag.dm
rename to code/modules/economy/money_bag.dm
index fd1cb561b0..3e85d62e46 100644
--- a/code/modules/mining/money_bag.dm
+++ b/code/modules/economy/money_bag.dm
@@ -1,98 +1,98 @@
-/*****************************Money bag********************************/
-
-/obj/item/weapon/moneybag
- icon = 'icons/obj/storage.dmi'
- name = "Money bag"
- icon_state = "moneybag"
- force = 10.0
- throwforce = 2.0
- w_class = ITEMSIZE_LARGE
-
-/obj/item/weapon/moneybag/attack_hand(user as mob)
- var/amt_gold = 0
- var/amt_silver = 0
- var/amt_diamond = 0
- var/amt_iron = 0
- var/amt_phoron = 0
- var/amt_uranium = 0
-
- for (var/obj/item/weapon/coin/C in contents)
- if (istype(C,/obj/item/weapon/coin/diamond))
- amt_diamond++;
- if (istype(C,/obj/item/weapon/coin/phoron))
- amt_phoron++;
- if (istype(C,/obj/item/weapon/coin/iron))
- amt_iron++;
- if (istype(C,/obj/item/weapon/coin/silver))
- amt_silver++;
- if (istype(C,/obj/item/weapon/coin/gold))
- amt_gold++;
- if (istype(C,/obj/item/weapon/coin/uranium))
- amt_uranium++;
-
- var/dat = text("The contents of the moneybag reveal...
")
- if (amt_gold)
- dat += text("Gold coins: [amt_gold] Remove one
")
- if (amt_silver)
- dat += text("Silver coins: [amt_silver] Remove one
")
- if (amt_iron)
- dat += text("Metal coins: [amt_iron] Remove one
")
- if (amt_diamond)
- dat += text("Diamond coins: [amt_diamond] Remove one
")
- if (amt_phoron)
- dat += text("Phoron coins: [amt_phoron] Remove one
")
- if (amt_uranium)
- dat += text("Uranium coins: [amt_uranium] Remove one
")
- user << browse("[dat]", "window=moneybag")
-
-/obj/item/weapon/moneybag/attackby(obj/item/weapon/W as obj, mob/user as mob)
- ..()
- if (istype(W, /obj/item/weapon/coin))
- var/obj/item/weapon/coin/C = W
- to_chat(user, "You add the [C.name] into the bag.")
- usr.drop_item()
- contents += C
- if (istype(W, /obj/item/weapon/moneybag))
- var/obj/item/weapon/moneybag/C = W
- for (var/obj/O in C.contents)
- contents += O;
- to_chat(user, "You empty the [C.name] into the bag.")
- return
-
-/obj/item/weapon/moneybag/Topic(href, href_list)
- if(..())
- return 1
- usr.set_machine(src)
- src.add_fingerprint(usr)
- if(href_list["remove"])
- var/obj/item/weapon/coin/COIN
- switch(href_list["remove"])
- if("gold")
- COIN = locate(/obj/item/weapon/coin/gold,src.contents)
- if("silver")
- COIN = locate(/obj/item/weapon/coin/silver,src.contents)
- if("iron")
- COIN = locate(/obj/item/weapon/coin/iron,src.contents)
- if("diamond")
- COIN = locate(/obj/item/weapon/coin/diamond,src.contents)
- if("phoron")
- COIN = locate(/obj/item/weapon/coin/phoron,src.contents)
- if("uranium")
- COIN = locate(/obj/item/weapon/coin/uranium,src.contents)
- if(!COIN)
- return
- COIN.loc = src.loc
- return
-
-
-
-/obj/item/weapon/moneybag/vault
-
-/obj/item/weapon/moneybag/vault/New()
- ..()
- new /obj/item/weapon/coin/silver(src)
- new /obj/item/weapon/coin/silver(src)
- new /obj/item/weapon/coin/silver(src)
- new /obj/item/weapon/coin/silver(src)
- new /obj/item/weapon/coin/gold(src)
+/*****************************Money bag********************************/
+
+/obj/item/weapon/moneybag
+ icon = 'icons/obj/storage.dmi'
+ name = "Money bag"
+ icon_state = "moneybag"
+ force = 10.0
+ throwforce = 2.0
+ w_class = ITEMSIZE_LARGE
+
+/obj/item/weapon/moneybag/attack_hand(user as mob)
+ var/amt_gold = 0
+ var/amt_silver = 0
+ var/amt_diamond = 0
+ var/amt_iron = 0
+ var/amt_phoron = 0
+ var/amt_uranium = 0
+
+ for (var/obj/item/weapon/coin/C in contents)
+ if (istype(C,/obj/item/weapon/coin/diamond))
+ amt_diamond++;
+ if (istype(C,/obj/item/weapon/coin/phoron))
+ amt_phoron++;
+ if (istype(C,/obj/item/weapon/coin/iron))
+ amt_iron++;
+ if (istype(C,/obj/item/weapon/coin/silver))
+ amt_silver++;
+ if (istype(C,/obj/item/weapon/coin/gold))
+ amt_gold++;
+ if (istype(C,/obj/item/weapon/coin/uranium))
+ amt_uranium++;
+
+ var/dat = text("The contents of the moneybag reveal...
")
+ if (amt_gold)
+ dat += text("Gold coins: [amt_gold] Remove one
")
+ if (amt_silver)
+ dat += text("Silver coins: [amt_silver] Remove one
")
+ if (amt_iron)
+ dat += text("Metal coins: [amt_iron] Remove one
")
+ if (amt_diamond)
+ dat += text("Diamond coins: [amt_diamond] Remove one
")
+ if (amt_phoron)
+ dat += text("Phoron coins: [amt_phoron] Remove one
")
+ if (amt_uranium)
+ dat += text("Uranium coins: [amt_uranium] Remove one
")
+ user << browse("[dat]", "window=moneybag")
+
+/obj/item/weapon/moneybag/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ ..()
+ if (istype(W, /obj/item/weapon/coin))
+ var/obj/item/weapon/coin/C = W
+ to_chat(user, "You add the [C.name] into the bag.")
+ usr.drop_item()
+ contents += C
+ if (istype(W, /obj/item/weapon/moneybag))
+ var/obj/item/weapon/moneybag/C = W
+ for (var/obj/O in C.contents)
+ contents += O;
+ to_chat(user, "You empty the [C.name] into the bag.")
+ return
+
+/obj/item/weapon/moneybag/Topic(href, href_list)
+ if(..())
+ return 1
+ usr.set_machine(src)
+ src.add_fingerprint(usr)
+ if(href_list["remove"])
+ var/obj/item/weapon/coin/COIN
+ switch(href_list["remove"])
+ if("gold")
+ COIN = locate(/obj/item/weapon/coin/gold,src.contents)
+ if("silver")
+ COIN = locate(/obj/item/weapon/coin/silver,src.contents)
+ if("iron")
+ COIN = locate(/obj/item/weapon/coin/iron,src.contents)
+ if("diamond")
+ COIN = locate(/obj/item/weapon/coin/diamond,src.contents)
+ if("phoron")
+ COIN = locate(/obj/item/weapon/coin/phoron,src.contents)
+ if("uranium")
+ COIN = locate(/obj/item/weapon/coin/uranium,src.contents)
+ if(!COIN)
+ return
+ COIN.loc = src.loc
+ return
+
+
+
+/obj/item/weapon/moneybag/vault
+
+/obj/item/weapon/moneybag/vault/New()
+ ..()
+ new /obj/item/weapon/coin/silver(src)
+ new /obj/item/weapon/coin/silver(src)
+ new /obj/item/weapon/coin/silver(src)
+ new /obj/item/weapon/coin/silver(src)
+ new /obj/item/weapon/coin/gold(src)
new /obj/item/weapon/coin/gold(src)
\ No newline at end of file
diff --git a/code/game/machinery/vending.dm b/code/modules/economy/vending.dm
similarity index 96%
rename from code/game/machinery/vending.dm
rename to code/modules/economy/vending.dm
index 58107d9d0b..9c2106adc0 100644
--- a/code/game/machinery/vending.dm
+++ b/code/modules/economy/vending.dm
@@ -1,720 +1,722 @@
-///
-/// A vending machine
-///
-
-//
-// ALL THE VENDING MACHINES ARE IN vending_machines.dm now!
-//
-
-/obj/machinery/vending
- name = "Vendomat"
- desc = "A generic vending machine."
- icon = 'icons/obj/vending.dmi'
- icon_state = "generic"
- anchored = 1
- density = 1
- clicksound = "button"
-
- // Power
- use_power = USE_POWER_IDLE
- idle_power_usage = 10
- var/vend_power_usage = 150 //actuators and stuff
-
- // Vending-related
- var/active = 1 //No sales pitches if off!
- var/vend_ready = 1 //Are we ready to vend?? Is it time??
- var/vend_delay = 10 //How long does it take to vend?
- var/categories = CAT_NORMAL // Bitmask of cats we're currently showing
- var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now
- var/vending_sound = "machines/vending/vending_drop.ogg"
-
- /*
- Variables used to initialize the product list
- These are used for initialization only, and so are optional if
- product_records is specified
- */
- var/list/products = list() // For each, use the following pattern:
- var/list/contraband = list() // list(/type/path = amount,/type/path2 = amount2)
- var/list/premium = list() // No specified amount = only one in stock
- var/list/prices = list() // Prices for each item, list(/type/path = price), items not in the list don't have a price.
-
- // List of vending_product items available.
- var/list/product_records = list()
-
-
- // Variables used to initialize advertising
- var/product_slogans = "" //String of slogans spoken out loud, separated by semicolons
- var/product_ads = "" //String of small ad messages in the vending screen
-
- var/list/ads_list = list()
-
- // Stuff relating vocalizations
- var/list/slogan_list = list()
- var/shut_up = 1 //Stop spouting those godawful pitches!
- var/vend_reply //Thank you for shopping!
- var/last_reply = 0
- var/last_slogan = 0 //When did we last pitch?
- var/slogan_delay = 6000 //How long until we can pitch again?
-
- // Things that can go wrong
- emagged = 0 //Ignores if somebody doesn't have card access to that machine.
- var/seconds_electrified = 0 //Shock customers like an airlock.
- var/shoot_inventory = 0 //Fire items at customers! We're broken!
-
- var/scan_id = 1
- var/obj/item/weapon/coin/coin
- var/datum/wires/vending/wires = null
-
- var/list/log = list()
- var/req_log_access = access_cargo //default access for checking logs is cargo
- var/has_logs = 0 //defaults to 0, set to anything else for vendor to have logs
- var/can_rotate = 1 //Defaults to yes, can be set to 0 for vendors without or with unwanted directionals.
-
-
-/obj/machinery/vending/Initialize()
- . = ..()
- wires = new(src)
- if(product_slogans)
- slogan_list += splittext(product_slogans, ";")
-
- // So not all machines speak at the exact same time.
- // The first time this machine says something will be at slogantime + this random value,
- // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated.
- last_slogan = world.time + rand(0, slogan_delay)
-
- if(product_ads)
- ads_list += splittext(product_ads, ";")
-
- build_inventory()
- power_change()
-
-GLOBAL_LIST_EMPTY(vending_products)
-/**
- * Build produdct_records from the products lists
- *
- * products, contraband, premium, and prices allow specifying
- * products that the vending machine is to carry without manually populating
- * product_records.
- */
-/obj/machinery/vending/proc/build_inventory()
- var/list/all_products = list(
- list(products, CAT_NORMAL),
- list(contraband, CAT_HIDDEN),
- list(premium, CAT_COIN))
-
- for(var/current_list in all_products)
- var/category = current_list[2]
-
- for(var/entry in current_list[1])
- var/datum/stored_item/vending_product/product = new/datum/stored_item/vending_product(src, entry)
-
- product.price = (entry in prices) ? prices[entry] : 0
- product.amount = (current_list[1][entry]) ? current_list[1][entry] : 1
- product.category = category
-
- product_records.Add(product)
- GLOB.vending_products[entry] = 1
-
-/obj/machinery/vending/Destroy()
- qdel(wires)
- wires = null
- qdel(coin)
- coin = null
- for(var/datum/stored_item/vending_product/R in product_records)
- qdel(R)
- product_records = null
- return ..()
-
-/obj/machinery/vending/ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- return
- if(2.0)
- if(prob(50))
- qdel(src)
- return
- if(3.0)
- if(prob(25))
- spawn(0)
- malfunction()
- return
- return
- else
- return
-
-/obj/machinery/vending/emag_act(var/remaining_charges, var/mob/user)
- if(!emagged)
- emagged = 1
- to_chat(user, "You short out \the [src]'s product lock.")
- return 1
-
-/obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob)
- var/obj/item/weapon/card/id/I = W.GetID()
-
- if(I || istype(W, /obj/item/weapon/spacecash))
- attack_hand(user)
- return
- else if(W.is_screwdriver())
- panel_open = !panel_open
- to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.")
- playsound(src, W.usesound, 50, 1)
- if(panel_open)
- wires.Interact(user)
- add_overlay("[initial(icon_state)]-panel")
- else
- cut_overlay("[initial(icon_state)]-panel")
-
- SStgui.update_uis(src) // Speaker switch is on the main UI, not wires UI
- return
- else if(istype(W, /obj/item/device/multitool) || W.is_wirecutter())
- if(panel_open)
- attack_hand(user)
- return
- else if(istype(W, /obj/item/weapon/coin) && premium.len > 0)
- user.drop_item()
- W.forceMove(src)
- coin = W
- categories |= CAT_COIN
- to_chat(user, "You insert \the [W] into \the [src].")
- SStgui.update_uis(src)
- return
- else if(W.is_wrench())
- playsound(src, W.usesound, 100, 1)
- if(anchored)
- user.visible_message("[user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
- else
- user.visible_message("[user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.")
-
- if(do_after(user, 20 * W.toolspeed))
- if(!src) return
- to_chat(user, "You [anchored? "un" : ""]secured \the [src]!")
- anchored = !anchored
- return
- else
-
- for(var/datum/stored_item/vending_product/R in product_records)
- if(istype(W, R.item_path) && (W.name == R.item_name))
- stock(W, R, user)
- return
- ..()
-
-/**
- * Receive payment with cashmoney.
- *
- * usr is the mob who gets the change.
- */
-/obj/machinery/vending/proc/pay_with_cash(var/obj/item/weapon/spacecash/cashmoney, mob/user)
- if(currently_vending.price > cashmoney.worth)
-
- // This is not a status display message, since it's something the character
- // themselves is meant to see BEFORE putting the money in
- to_chat(usr, "[bicon(cashmoney)] That is not enough money.")
- return 0
-
- if(istype(cashmoney, /obj/item/weapon/spacecash))
-
- visible_message("\The [usr] inserts some cash into \the [src].")
- cashmoney.worth -= currently_vending.price
-
- if(cashmoney.worth <= 0)
- usr.drop_from_inventory(cashmoney)
- qdel(cashmoney)
- else
- cashmoney.update_icon()
-
- // Vending machines have no idea who paid with cash
- credit_purchase("(cash)")
- return 1
-
-/**
- * Scan a chargecard and deduct payment from it.
- *
- * Takes payment for whatever is the currently_vending item. Returns 1 if
- * successful, 0 if failed.
- */
-/obj/machinery/vending/proc/pay_with_ewallet(var/obj/item/weapon/spacecash/ewallet/wallet)
- visible_message("\The [usr] swipes \the [wallet] through \the [src].")
- playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
- if(currently_vending.price > wallet.worth)
- to_chat(usr, "Insufficient funds on chargecard.")
- return 0
- else
- wallet.worth -= currently_vending.price
- credit_purchase("[wallet.owner_name] (chargecard)")
- return 1
-
-/**
- * Scan a card and attempt to transfer payment from associated account.
- *
- * Takes payment for whatever is the currently_vending item. Returns 1 if
- * successful, 0 if failed
- */
-/obj/machinery/vending/proc/pay_with_card(obj/item/weapon/card/id/I, mob/M)
- visible_message("[M] swipes a card through [src].")
- playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
-
- var/datum/money_account/customer_account = get_account(I.associated_account_number)
- if(!customer_account)
- to_chat(M, "Error: Unable to access account. Please contact technical support if problem persists.")
- return FALSE
-
- if(customer_account.suspended)
- to_chat(M, "Unable to access account: account suspended.")
- return FALSE
-
- // Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is
- // empty at high security levels
- if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2)
- var/attempt_pin = input("Enter pin code", "Vendor transaction") as num
- customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2)
-
- if(!customer_account)
- to_chat(M, "Unable to access account: incorrect credentials.")
- return FALSE
-
- if(currently_vending.price > customer_account.money)
- to_chat(M, "Insufficient funds in account.")
- return FALSE
-
- // Okay to move the money at this point
-
- // debit money from the purchaser's account
- customer_account.money -= currently_vending.price
-
- // create entry in the purchaser's account log
- var/datum/transaction/T = new()
- T.target_name = "[vendor_account.owner_name] (via [name])"
- T.purpose = "Purchase of [currently_vending.item_name]"
- if(currently_vending.price > 0)
- T.amount = "([currently_vending.price])"
- else
- T.amount = "[currently_vending.price]"
- T.source_terminal = name
- T.date = current_date_string
- T.time = stationtime2text()
- customer_account.transaction_log.Add(T)
-
- // Give the vendor the money. We use the account owner name, which means
- // that purchases made with stolen/borrowed card will look like the card
- // owner made them
- credit_purchase(customer_account.owner_name)
- return 1
-
-/**
- * Add money for current purchase to the vendor account.
- *
- * Called after the money has already been taken from the customer.
- */
-/obj/machinery/vending/proc/credit_purchase(var/target as text)
- vendor_account.money += currently_vending.price
-
- var/datum/transaction/T = new()
- T.target_name = target
- T.purpose = "Purchase of [currently_vending.item_name]"
- T.amount = "[currently_vending.price]"
- T.source_terminal = name
- T.date = current_date_string
- T.time = stationtime2text()
- vendor_account.transaction_log.Add(T)
-
-/obj/machinery/vending/attack_ghost(mob/user)
- return attack_hand(user)
-
-/obj/machinery/vending/attack_ai(mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/vending/attack_hand(mob/user as mob)
- if(stat & (BROKEN|NOPOWER))
- return
-
- if(seconds_electrified != 0)
- if(shock(user, 100))
- return
-
- wires.Interact(user)
- tgui_interact(user)
-
-/obj/machinery/vending/ui_assets(mob/user)
- return list(
- get_asset_datum(/datum/asset/spritesheet/vending),
- )
-
-/obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "Vending", name)
- ui.open()
-
-/obj/machinery/vending/tgui_data(mob/user)
- var/list/data = list()
- var/list/listed_products = list()
-
- data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE
- for(var/key = 1 to product_records.len)
- var/datum/stored_item/vending_product/I = product_records[key]
-
- if(!(I.category & categories))
- continue
-
- listed_products.Add(list(list(
- "key" = key,
- "name" = I.item_name,
- "price" = I.price,
- "color" = I.display_color,
- "isatom" = ispath(I.item_path, /atom),
- "path" = replacetext(replacetext("[I.item_path]", "/obj/item/", ""), "/", "-"),
- "amount" = I.get_amount()
- )))
-
- data["products"] = listed_products
-
- if(coin)
- data["coin"] = coin.name
- else
- data["coin"] = FALSE
-
- if(currently_vending)
- data["actively_vending"] = currently_vending.item_name
- else
- data["actively_vending"] = null
-
- if(panel_open)
- data["panel"] = 1
- data["speaker"] = shut_up ? 0 : 1
- else
- data["panel"] = 0
-
- var/mob/living/carbon/human/H
- var/obj/item/weapon/card/id/C
-
- data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash.";
- data["userMoney"] = 0
- data["user"] = null
- if(ishuman(user))
- H = user
- C = H.GetIdCard()
- var/obj/item/weapon/spacecash/S = H.get_active_hand()
- if(istype(S))
- data["userMoney"] = S.worth
- data["guestNotice"] = "Accepting [S.initial_name]. You have: [S.worth]₮."
- else if(istype(C))
- var/datum/money_account/A = get_account(C.associated_account_number)
- if(istype(A))
- data["user"] = list()
- data["user"]["name"] = A.owner_name
- data["userMoney"] = A.money
- data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job"
- else
- data["guestNotice"] = "Unlinked ID detected. Present cash to pay.";
-
- return data
-
-/obj/machinery/vending/tgui_act(action, params)
- if(stat & (BROKEN|NOPOWER))
- return
- if(usr.stat || usr.restrained())
- return
- if(..())
- return TRUE
-
- . = TRUE
- switch(action)
- if("remove_coin")
- if(issilicon(usr))
- return FALSE
-
- if(!coin)
- to_chat(usr, "There is no coin in this machine.")
- return
-
- coin.forceMove(src.loc)
- if(!usr.get_active_hand())
- usr.put_in_hands(coin)
-
- to_chat(usr, "You remove \the [coin] from \the [src].")
- coin = null
- categories &= ~CAT_COIN
- return TRUE
- if("vend")
- if(!vend_ready)
- to_chat(usr, "[src] is busy!")
- return
- if(!allowed(usr) && !emagged && scan_id)
- to_chat(usr, "Access denied.") //Unless emagged of course
- flick("[icon_state]-deny",src)
- playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
- return
- if(panel_open)
- to_chat(usr, "[src] cannot dispense products while its service panel is open!")
- return
-
- var/key = text2num(params["vend"])
- var/datum/stored_item/vending_product/R = product_records[key]
-
- // This should not happen unless the request from NanoUI was bad
- if(!(R.category & categories))
- return
-
- if(!can_buy(R, usr))
- return
- if(R.price <= 0)
- vend(R, usr)
- add_fingerprint(usr)
- return TRUE
-
- if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something.
- to_chat(usr, "Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.")
- return
- if(!ishuman(usr))
- return
-
-
- vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved.
-
- var/mob/living/carbon/human/H = usr
- var/obj/item/weapon/card/id/C = H.GetIdCard()
-
- if(!vendor_account || vendor_account.suspended)
- to_chat(usr, "Vendor account offline. Unable to process transaction.")
- flick("[icon_state]-deny",src)
- vend_ready = TRUE
- return
-
- currently_vending = R
-
- var/paid = FALSE
-
- if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash))
- var/obj/item/weapon/spacecash/cash = usr.get_active_hand()
- paid = pay_with_cash(cash, usr)
- else if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash/ewallet))
- var/obj/item/weapon/spacecash/ewallet/wallet = usr.get_active_hand()
- paid = pay_with_ewallet(wallet)
- else if(istype(C, /obj/item/weapon/card))
- paid = pay_with_card(C, usr)
- /*else if(usr.can_advanced_admin_interact())
- to_chat(usr, "Vending object due to admin interaction.")
- paid = TRUE*/
- else
- to_chat(usr, "Payment failure: you have no ID or other method of payment.")
- vend_ready = TRUE
- flick("[icon_state]-deny",src)
- return TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update.
- if(paid)
- vend(currently_vending, usr) // vend will handle vend_ready
- . = TRUE
- else
- to_chat(usr, "Payment failure: unable to process payment.")
- vend_ready = TRUE
-
- if("togglevoice")
- if(!panel_open)
- return FALSE
- shut_up = !shut_up
-
-/obj/machinery/vending/proc/can_buy(datum/stored_item/vending_product/R, mob/user)
- if(!allowed(user) && !emagged && scan_id)
- to_chat(user, "Access denied.") //Unless emagged of course
- flick("[icon_state]-deny",src)
- playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
- return FALSE
- return TRUE
-
-/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user)
- if(!can_buy(R, user))
- return
-
- if(!R.amount)
- to_chat(user, "[src] has ran out of that product.")
- vend_ready = TRUE
- return
-
- vend_ready = FALSE //One thing at a time!!
- SStgui.update_uis(src)
-
- if(R.category & CAT_COIN)
- if(!coin)
- to_chat(user, "You need to insert a coin to get this item.")
- return
- if(coin.string_attached)
- if(prob(50))
- to_chat(user, "You successfully pull the coin out before \the [src] could swallow it.")
- else
- to_chat(user, "You weren't able to pull the coin out fast enough, the machine ate it, string and all.")
- qdel(coin)
- coin = null
- categories &= ~CAT_COIN
- else
- qdel(coin)
- coin = null
- categories &= ~CAT_COIN
-
- if(((last_reply + (vend_delay + 200)) <= world.time) && vend_reply)
- spawn(0)
- speak(vend_reply)
- last_reply = world.time
-
- use_power(vend_power_usage) //actuators and stuff
- flick("[icon_state]-vend",src)
- addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay)
-
-/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user)
- R.get_product(get_turf(src))
- if(has_logs)
- do_logging(R, user, 1)
- if(prob(1))
- sleep(3)
- if(R.get_product(get_turf(src)))
- visible_message("\The [src] clunks as it vends an additional item.")
- playsound(src, "sound/[vending_sound]", 100, 1, 1)
-
- vend_ready = 1
- currently_vending = null
- SStgui.update_uis(src)
- GLOB.items_sold_shift_roundstat++
-
-/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0)
- if(user.GetIdCard())
- var/obj/item/weapon/card/id/tempid = user.GetIdCard()
- var/list/list_item = list()
- if(vending)
- list_item += "vend"
- else
- list_item += "stock"
- list_item += tempid.registered_name
- list_item += stationtime2text()
- list_item += R.item_name
- log[++log.len] = list_item
-
-/obj/machinery/vending/proc/show_log(mob/user as mob)
- if(user.GetIdCard())
- var/obj/item/weapon/card/id/tempid = user.GetIdCard()
- if(req_log_access in tempid.GetAccess())
- var/datum/browser/popup = new(user, "vending_log", "Vending Log", 700, 500)
- var/dat = ""
- dat += "
[name] Vending Log"
- dat += "Welcome [user.name]!
"
- dat += "Below are the recent vending logs for your vending machine.
"
- for(var/i in log)
- dat += json_encode(i)
- dat += ";
"
- popup.set_content(dat)
- popup.open()
- else
- to_chat(user,"You do not have the required access to view the vending logs for this machine.")
-
-
-/obj/machinery/vending/verb/rotate_clockwise()
- set name = "Rotate Vending Machine Clockwise"
- set category = "Object"
- set src in oview(1)
-
- if (src.can_rotate == 0)
- to_chat(usr, "\The [src] cannot be rotated.")
- return 0
-
- if (src.anchored || usr:stat)
- to_chat(usr, "It is bolted down!")
- return 0
- src.set_dir(turn(src.dir, 270))
- return 1
-
-/obj/machinery/vending/verb/check_logs()
- set name = "Check Vending Logs"
- set category = "Object"
- set src in oview(1)
-
- show_log(usr)
-
-/**
- * Add item to the machine
- *
- * Checks if item is vendable in this machine should be performed before
- * calling. W is the item being inserted, R is the associated vending_product entry.
- */
-/obj/machinery/vending/proc/stock(obj/item/weapon/W, var/datum/stored_item/vending_product/R, var/mob/user)
- if(!user.unEquip(W))
- return
-
- to_chat(user, "You insert \the [W] in the product receptor.")
- R.add_product(W)
- if(has_logs)
- do_logging(R, user)
-
- SStgui.update_uis(src)
-
-/obj/machinery/vending/process()
- if(stat & (BROKEN|NOPOWER))
- return
-
- if(!active)
- return
-
- if(seconds_electrified > 0)
- seconds_electrified--
-
- //Pitch to the people! Really sell it!
- if(((last_slogan + slogan_delay) <= world.time) && (slogan_list.len > 0) && (!shut_up) && prob(5))
- var/slogan = pick(slogan_list)
- speak(slogan)
- last_slogan = world.time
-
- if(shoot_inventory && prob(2))
- throw_item()
-
- return
-
-/obj/machinery/vending/proc/speak(var/message)
- if(stat & NOPOWER)
- return
-
- if(!message)
- return
-
- for(var/mob/O in hearers(src, null))
- O.show_message("\The [src] beeps, \"[message]\"",2)
- return
-
-/obj/machinery/vending/power_change()
- ..()
- if(stat & BROKEN)
- icon_state = "[initial(icon_state)]-broken"
- else
- if(!(stat & NOPOWER))
- icon_state = initial(icon_state)
- else
- spawn(rand(0, 15))
- icon_state = "[initial(icon_state)]-off"
-
-//Oh no we're malfunctioning! Dump out some product and break.
-/obj/machinery/vending/proc/malfunction()
- for(var/datum/stored_item/vending_product/R in product_records)
- while(R.get_amount()>0)
- R.get_product(loc)
- break
-
- stat |= BROKEN
- icon_state = "[initial(icon_state)]-broken"
- return
-
-//Somebody cut an important wire and now we're following a new definition of "pitch."
-/obj/machinery/vending/proc/throw_item()
- var/obj/throw_item = null
- var/mob/living/target = locate() in view(7,src)
- if(!target)
- return 0
-
- for(var/datum/stored_item/vending_product/R in product_records)
- throw_item = R.get_product(loc)
- if(!throw_item)
- continue
- break
- if(!throw_item)
- return 0
- spawn(0)
- throw_item.throw_at(target, 16, 3, src)
- visible_message("\The [src] launches \a [throw_item] at \the [target]!")
- return 1
-
-//Actual machines are in vending_machines.dm
+///
+/// A vending machine
+///
+
+//
+// ALL THE VENDING MACHINES ARE IN vending_machines.dm now!
+//
+
+/obj/machinery/vending
+ name = "Vendomat"
+ desc = "A generic vending machine."
+ icon = 'icons/obj/vending.dmi'
+ icon_state = "generic"
+ anchored = 1
+ density = 1
+ clicksound = "button"
+
+ // Power
+ use_power = USE_POWER_IDLE
+ idle_power_usage = 10
+ var/vend_power_usage = 150 //actuators and stuff
+
+ // Vending-related
+ var/active = 1 //No sales pitches if off!
+ var/vend_ready = 1 //Are we ready to vend?? Is it time??
+ var/vend_delay = 10 //How long does it take to vend?
+ var/categories = CAT_NORMAL // Bitmask of cats we're currently showing
+ var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now
+ var/vending_sound = "machines/vending/vending_drop.ogg"
+
+ /*
+ Variables used to initialize the product list
+ These are used for initialization only, and so are optional if
+ product_records is specified
+ */
+ var/list/products = list() // For each, use the following pattern:
+ var/list/contraband = list() // list(/type/path = amount,/type/path2 = amount2)
+ var/list/premium = list() // No specified amount = only one in stock
+ var/list/prices = list() // Prices for each item, list(/type/path = price), items not in the list don't have a price.
+
+ // List of vending_product items available.
+ var/list/product_records = list()
+
+
+ // Variables used to initialize advertising
+ var/product_slogans = "" //String of slogans spoken out loud, separated by semicolons
+ var/product_ads = "" //String of small ad messages in the vending screen
+
+ var/list/ads_list = list()
+
+ // Stuff relating vocalizations
+ var/list/slogan_list = list()
+ var/shut_up = 1 //Stop spouting those godawful pitches!
+ var/vend_reply //Thank you for shopping!
+ var/last_reply = 0
+ var/last_slogan = 0 //When did we last pitch?
+ var/slogan_delay = 6000 //How long until we can pitch again?
+
+ // Things that can go wrong
+ emagged = 0 //Ignores if somebody doesn't have card access to that machine.
+ var/seconds_electrified = 0 //Shock customers like an airlock.
+ var/shoot_inventory = 0 //Fire items at customers! We're broken!
+
+ var/scan_id = 1
+ var/obj/item/weapon/coin/coin
+ var/datum/wires/vending/wires = null
+
+ var/list/log = list()
+ var/req_log_access = access_cargo //default access for checking logs is cargo
+ var/has_logs = 0 //defaults to 0, set to anything else for vendor to have logs
+ var/can_rotate = 1 //Defaults to yes, can be set to 0 for vendors without or with unwanted directionals.
+
+
+/obj/machinery/vending/Initialize()
+ . = ..()
+ wires = new(src)
+ if(product_slogans)
+ slogan_list += splittext(product_slogans, ";")
+
+ // So not all machines speak at the exact same time.
+ // The first time this machine says something will be at slogantime + this random value,
+ // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated.
+ last_slogan = world.time + rand(0, slogan_delay)
+
+ if(product_ads)
+ ads_list += splittext(product_ads, ";")
+
+ build_inventory()
+ power_change()
+
+GLOBAL_LIST_EMPTY(vending_products)
+/**
+ * Build produdct_records from the products lists
+ *
+ * products, contraband, premium, and prices allow specifying
+ * products that the vending machine is to carry without manually populating
+ * product_records.
+ */
+/obj/machinery/vending/proc/build_inventory()
+ var/list/all_products = list(
+ list(products, CAT_NORMAL),
+ list(contraband, CAT_HIDDEN),
+ list(premium, CAT_COIN))
+
+ for(var/current_list in all_products)
+ var/category = current_list[2]
+
+ for(var/entry in current_list[1])
+ var/datum/stored_item/vending_product/product = new/datum/stored_item/vending_product(src, entry)
+
+ product.price = (entry in prices) ? prices[entry] : 0
+ product.amount = (current_list[1][entry]) ? current_list[1][entry] : 1
+ product.category = category
+
+ product_records.Add(product)
+ GLOB.vending_products[entry] = 1
+
+/obj/machinery/vending/Destroy()
+ qdel(wires)
+ wires = null
+ qdel(coin)
+ coin = null
+ for(var/datum/stored_item/vending_product/R in product_records)
+ qdel(R)
+ product_records = null
+ return ..()
+
+/obj/machinery/vending/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ qdel(src)
+ return
+ if(2.0)
+ if(prob(50))
+ qdel(src)
+ return
+ if(3.0)
+ if(prob(25))
+ spawn(0)
+ malfunction()
+ return
+ return
+ else
+ return
+
+/obj/machinery/vending/emag_act(var/remaining_charges, var/mob/user)
+ if(!emagged)
+ emagged = 1
+ to_chat(user, "You short out \the [src]'s product lock.")
+ return 1
+
+/obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ var/obj/item/weapon/card/id/I = W.GetID()
+
+ if(I || istype(W, /obj/item/weapon/spacecash))
+ attack_hand(user)
+ return
+ else if(W.is_screwdriver())
+ panel_open = !panel_open
+ to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.")
+ playsound(src, W.usesound, 50, 1)
+ if(panel_open)
+ wires.Interact(user)
+ add_overlay("[initial(icon_state)]-panel")
+ else
+ cut_overlay("[initial(icon_state)]-panel")
+
+ SStgui.update_uis(src) // Speaker switch is on the main UI, not wires UI
+ return
+ else if(istype(W, /obj/item/device/multitool) || W.is_wirecutter())
+ if(panel_open)
+ attack_hand(user)
+ return
+ else if(istype(W, /obj/item/weapon/coin) && premium.len > 0)
+ user.drop_item()
+ W.forceMove(src)
+ coin = W
+ categories |= CAT_COIN
+ to_chat(user, "You insert \the [W] into \the [src].")
+ SStgui.update_uis(src)
+ return
+ else if(W.is_wrench())
+ playsound(src, W.usesound, 100, 1)
+ if(anchored)
+ user.visible_message("[user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
+ else
+ user.visible_message("[user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.")
+
+ if(do_after(user, 20 * W.toolspeed))
+ if(!src) return
+ to_chat(user, "You [anchored? "un" : ""]secured \the [src]!")
+ anchored = !anchored
+ return
+ else
+
+ for(var/datum/stored_item/vending_product/R in product_records)
+ if(istype(W, R.item_path) && (W.name == R.item_name))
+ stock(W, R, user)
+ return
+ ..()
+
+/**
+ * Receive payment with cashmoney.
+ *
+ * usr is the mob who gets the change.
+ */
+/obj/machinery/vending/proc/pay_with_cash(var/obj/item/weapon/spacecash/cashmoney, mob/user)
+ if(currently_vending.price > cashmoney.worth)
+
+ // This is not a status display message, since it's something the character
+ // themselves is meant to see BEFORE putting the money in
+ to_chat(usr, "[bicon(cashmoney)] That is not enough money.")
+ return 0
+
+ if(istype(cashmoney, /obj/item/weapon/spacecash))
+
+ visible_message("\The [usr] inserts some cash into \the [src].")
+ cashmoney.worth -= currently_vending.price
+
+ if(cashmoney.worth <= 0)
+ usr.drop_from_inventory(cashmoney)
+ qdel(cashmoney)
+ else
+ cashmoney.update_icon()
+
+ // Vending machines have no idea who paid with cash
+ credit_purchase("(cash)")
+ return 1
+
+/**
+ * Scan a chargecard and deduct payment from it.
+ *
+ * Takes payment for whatever is the currently_vending item. Returns 1 if
+ * successful, 0 if failed.
+ */
+/obj/machinery/vending/proc/pay_with_ewallet(var/obj/item/weapon/spacecash/ewallet/wallet)
+ visible_message("\The [usr] swipes \the [wallet] through \the [src].")
+ playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
+ if(currently_vending.price > wallet.worth)
+ to_chat(usr, "Insufficient funds on chargecard.")
+ return 0
+ else
+ wallet.worth -= currently_vending.price
+ credit_purchase("[wallet.owner_name] (chargecard)")
+ return 1
+
+/**
+ * Scan a card and attempt to transfer payment from associated account.
+ *
+ * Takes payment for whatever is the currently_vending item. Returns 1 if
+ * successful, 0 if failed
+ */
+/obj/machinery/vending/proc/pay_with_card(obj/item/weapon/card/id/I, mob/M)
+ visible_message("[M] swipes a card through [src].")
+ playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
+
+ var/datum/money_account/customer_account = get_account(I.associated_account_number)
+ if(!customer_account)
+ to_chat(M, "Error: Unable to access account. Please contact technical support if problem persists.")
+ return FALSE
+
+ if(customer_account.suspended)
+ to_chat(M, "Unable to access account: account suspended.")
+ return FALSE
+
+ // Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is
+ // empty at high security levels
+ if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2)
+ var/attempt_pin = input("Enter pin code", "Vendor transaction") as num
+ customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2)
+
+ if(!customer_account)
+ to_chat(M, "Unable to access account: incorrect credentials.")
+ return FALSE
+
+ if(currently_vending.price > customer_account.money)
+ to_chat(M, "Insufficient funds in account.")
+ return FALSE
+
+ // Okay to move the money at this point
+
+ // debit money from the purchaser's account
+ customer_account.money -= currently_vending.price
+
+ // create entry in the purchaser's account log
+ var/datum/transaction/T = new()
+ T.target_name = "[vendor_account.owner_name] (via [name])"
+ T.purpose = "Purchase of [currently_vending.item_name]"
+ if(currently_vending.price > 0)
+ T.amount = "([currently_vending.price])"
+ else
+ T.amount = "[currently_vending.price]"
+ T.source_terminal = name
+ T.date = current_date_string
+ T.time = stationtime2text()
+ customer_account.transaction_log.Add(T)
+
+ // Give the vendor the money. We use the account owner name, which means
+ // that purchases made with stolen/borrowed card will look like the card
+ // owner made them
+ credit_purchase(customer_account.owner_name)
+ return 1
+
+/**
+ * Add money for current purchase to the vendor account.
+ *
+ * Called after the money has already been taken from the customer.
+ */
+/obj/machinery/vending/proc/credit_purchase(var/target as text)
+ vendor_account.money += currently_vending.price
+
+ var/datum/transaction/T = new()
+ T.target_name = target
+ T.purpose = "Purchase of [currently_vending.item_name]"
+ T.amount = "[currently_vending.price]"
+ T.source_terminal = name
+ T.date = current_date_string
+ T.time = stationtime2text()
+ vendor_account.transaction_log.Add(T)
+
+/obj/machinery/vending/attack_ghost(mob/user)
+ return attack_hand(user)
+
+/obj/machinery/vending/attack_ai(mob/user as mob)
+ return attack_hand(user)
+
+/obj/machinery/vending/attack_hand(mob/user as mob)
+ if(stat & (BROKEN|NOPOWER))
+ return
+
+ if(seconds_electrified != 0)
+ if(shock(user, 100))
+ return
+
+ wires.Interact(user)
+ tgui_interact(user)
+
+/obj/machinery/vending/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/spritesheet/vending),
+ )
+
+/obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Vending", name)
+ ui.open()
+
+/obj/machinery/vending/tgui_data(mob/user)
+ var/list/data = list()
+ var/list/listed_products = list()
+
+ data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE
+ for(var/key = 1 to product_records.len)
+ var/datum/stored_item/vending_product/I = product_records[key]
+
+ if(!(I.category & categories))
+ continue
+
+ listed_products.Add(list(list(
+ "key" = key,
+ "name" = I.item_name,
+ "price" = I.price,
+ "color" = I.display_color,
+ "isatom" = ispath(I.item_path, /atom),
+ "path" = replacetext(replacetext("[I.item_path]", "/obj/item/", ""), "/", "-"),
+ "amount" = I.get_amount()
+ )))
+
+ data["products"] = listed_products
+
+ if(coin)
+ data["coin"] = coin.name
+ else
+ data["coin"] = FALSE
+
+ if(currently_vending)
+ data["actively_vending"] = currently_vending.item_name
+ else
+ data["actively_vending"] = null
+
+ if(panel_open)
+ data["panel"] = 1
+ data["speaker"] = shut_up ? 0 : 1
+ else
+ data["panel"] = 0
+
+ var/mob/living/carbon/human/H
+ var/obj/item/weapon/card/id/C
+
+ data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash.";
+ data["userMoney"] = 0
+ data["user"] = null
+ if(ishuman(user))
+ H = user
+ C = H.GetIdCard()
+ var/obj/item/weapon/spacecash/S = H.get_active_hand()
+ if(istype(S))
+ data["userMoney"] = S.worth
+ data["guestNotice"] = "Accepting [S.initial_name]. You have: [S.worth]₮."
+ else if(istype(C))
+ var/datum/money_account/A = get_account(C.associated_account_number)
+ if(istype(A))
+ data["user"] = list()
+ data["user"]["name"] = A.owner_name
+ data["userMoney"] = A.money
+ data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job"
+ else
+ data["guestNotice"] = "Unlinked ID detected. Present cash to pay.";
+
+ return data
+
+/obj/machinery/vending/tgui_act(action, params)
+ if(stat & (BROKEN|NOPOWER))
+ return
+ if(usr.stat || usr.restrained())
+ return
+ if(..())
+ return TRUE
+
+ . = TRUE
+ switch(action)
+ if("remove_coin")
+ if(issilicon(usr))
+ return FALSE
+
+ if(!coin)
+ to_chat(usr, "There is no coin in this machine.")
+ return
+
+ coin.forceMove(src.loc)
+ if(!usr.get_active_hand())
+ usr.put_in_hands(coin)
+
+ to_chat(usr, "You remove \the [coin] from \the [src].")
+ coin = null
+ categories &= ~CAT_COIN
+ return TRUE
+ if("vend")
+ if(!vend_ready)
+ to_chat(usr, "[src] is busy!")
+ return
+ if(!allowed(usr) && !emagged && scan_id)
+ to_chat(usr, "Access denied.") //Unless emagged of course
+ flick("[icon_state]-deny",src)
+ playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
+ return
+ if(panel_open)
+ to_chat(usr, "[src] cannot dispense products while its service panel is open!")
+ return
+
+ var/key = text2num(params["vend"])
+ var/datum/stored_item/vending_product/R = product_records[key]
+
+ // This should not happen unless the request from NanoUI was bad
+ if(!(R.category & categories))
+ return
+
+ if(!can_buy(R, usr))
+ return
+
+ if(R.price <= 0)
+ vend(R, usr)
+ add_fingerprint(usr)
+ return TRUE
+
+ if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something.
+ to_chat(usr, "Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.")
+ return
+ if(!ishuman(usr))
+ return
+
+ vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved.
+
+ var/mob/living/carbon/human/H = usr
+ var/obj/item/weapon/card/id/C = H.GetIdCard()
+
+ if(!vendor_account || vendor_account.suspended)
+ to_chat(usr, "Vendor account offline. Unable to process transaction.")
+ flick("[icon_state]-deny",src)
+ vend_ready = TRUE
+ return
+
+ currently_vending = R
+
+ var/paid = FALSE
+
+ if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash))
+ var/obj/item/weapon/spacecash/cash = usr.get_active_hand()
+ paid = pay_with_cash(cash, usr)
+ else if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash/ewallet))
+ var/obj/item/weapon/spacecash/ewallet/wallet = usr.get_active_hand()
+ paid = pay_with_ewallet(wallet)
+ else if(istype(C, /obj/item/weapon/card))
+ paid = pay_with_card(C, usr)
+ /*else if(usr.can_advanced_admin_interact())
+ to_chat(usr, "Vending object due to admin interaction.")
+ paid = TRUE*/
+ else
+ to_chat(usr, "Payment failure: you have no ID or other method of payment.")
+ vend_ready = TRUE
+ flick("[icon_state]-deny",src)
+ return TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update.
+ if(paid)
+ vend(currently_vending, usr) // vend will handle vend_ready
+ . = TRUE
+ else
+ to_chat(usr, "Payment failure: unable to process payment.")
+ vend_ready = TRUE
+
+ if("togglevoice")
+ if(!panel_open)
+ return FALSE
+ shut_up = !shut_up
+
+/obj/machinery/vending/proc/can_buy(datum/stored_item/vending_product/R, mob/user)
+ if(!allowed(user) && !emagged && scan_id)
+ to_chat(user, "Access denied.") //Unless emagged of course
+ flick("[icon_state]-deny",src)
+ playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
+ return FALSE
+ return TRUE
+
+/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user)
+ if(!can_buy(R, user))
+ return
+
+ if(!R.amount)
+ to_chat(user, "[src] has ran out of that product.")
+ vend_ready = TRUE
+ return
+
+ vend_ready = FALSE //One thing at a time!!
+ SStgui.update_uis(src)
+
+ if(R.category & CAT_COIN)
+ if(!coin)
+ to_chat(user, "You need to insert a coin to get this item.")
+ return
+ if(coin.string_attached)
+ if(prob(50))
+ to_chat(user, "You successfully pull the coin out before \the [src] could swallow it.")
+ else
+ to_chat(user, "You weren't able to pull the coin out fast enough, the machine ate it, string and all.")
+ qdel(coin)
+ coin = null
+ categories &= ~CAT_COIN
+ else
+ qdel(coin)
+ coin = null
+ categories &= ~CAT_COIN
+
+ if(((last_reply + (vend_delay + 200)) <= world.time) && vend_reply)
+ spawn(0)
+ speak(vend_reply)
+ last_reply = world.time
+
+ use_power(vend_power_usage) //actuators and stuff
+ flick("[icon_state]-vend",src)
+ addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay)
+
+/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user)
+ R.get_product(get_turf(src))
+ if(has_logs)
+ do_logging(R, user, 1)
+ if(prob(1))
+ sleep(3)
+ if(R.get_product(get_turf(src)))
+ visible_message("\The [src] clunks as it vends an additional item.")
+ playsound(src, "sound/[vending_sound]", 100, 1, 1)
+
+ GLOB.items_sold_shift_roundstat++
+
+ vend_ready = 1
+ currently_vending = null
+ SStgui.update_uis(src)
+
+
+/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0)
+ if(user.GetIdCard())
+ var/obj/item/weapon/card/id/tempid = user.GetIdCard()
+ var/list/list_item = list()
+ if(vending)
+ list_item += "vend"
+ else
+ list_item += "stock"
+ list_item += tempid.registered_name
+ list_item += stationtime2text()
+ list_item += R.item_name
+ log[++log.len] = list_item
+
+/obj/machinery/vending/proc/show_log(mob/user as mob)
+ if(user.GetIdCard())
+ var/obj/item/weapon/card/id/tempid = user.GetIdCard()
+ if(req_log_access in tempid.GetAccess())
+ var/datum/browser/popup = new(user, "vending_log", "Vending Log", 700, 500)
+ var/dat = ""
+ dat += "[name] Vending Log"
+ dat += "Welcome [user.name]!
"
+ dat += "Below are the recent vending logs for your vending machine.
"
+ for(var/i in log)
+ dat += json_encode(i)
+ dat += ";
"
+ popup.set_content(dat)
+ popup.open()
+ else
+ to_chat(user,"You do not have the required access to view the vending logs for this machine.")
+
+
+/obj/machinery/vending/verb/rotate_clockwise()
+ set name = "Rotate Vending Machine Clockwise"
+ set category = "Object"
+ set src in oview(1)
+
+ if (src.can_rotate == 0)
+ to_chat(usr, "\The [src] cannot be rotated.")
+ return 0
+
+ if (src.anchored || usr:stat)
+ to_chat(usr, "It is bolted down!")
+ return 0
+ src.set_dir(turn(src.dir, 270))
+ return 1
+
+/obj/machinery/vending/verb/check_logs()
+ set name = "Check Vending Logs"
+ set category = "Object"
+ set src in oview(1)
+
+ show_log(usr)
+
+/**
+ * Add item to the machine
+ *
+ * Checks if item is vendable in this machine should be performed before
+ * calling. W is the item being inserted, R is the associated vending_product entry.
+ */
+/obj/machinery/vending/proc/stock(obj/item/weapon/W, var/datum/stored_item/vending_product/R, var/mob/user)
+ if(!user.unEquip(W))
+ return
+
+ to_chat(user, "You insert \the [W] in the product receptor.")
+ R.add_product(W)
+ if(has_logs)
+ do_logging(R, user)
+
+ SStgui.update_uis(src)
+
+/obj/machinery/vending/process()
+ if(stat & (BROKEN|NOPOWER))
+ return
+
+ if(!active)
+ return
+
+ if(seconds_electrified > 0)
+ seconds_electrified--
+
+ //Pitch to the people! Really sell it!
+ if(((last_slogan + slogan_delay) <= world.time) && (slogan_list.len > 0) && (!shut_up) && prob(5))
+ var/slogan = pick(slogan_list)
+ speak(slogan)
+ last_slogan = world.time
+
+ if(shoot_inventory && prob(2))
+ throw_item()
+
+ return
+
+/obj/machinery/vending/proc/speak(var/message)
+ if(stat & NOPOWER)
+ return
+
+ if(!message)
+ return
+
+ for(var/mob/O in hearers(src, null))
+ O.show_message("\The [src] beeps, \"[message]\"",2)
+ return
+
+/obj/machinery/vending/power_change()
+ ..()
+ if(stat & BROKEN)
+ icon_state = "[initial(icon_state)]-broken"
+ else
+ if(!(stat & NOPOWER))
+ icon_state = initial(icon_state)
+ else
+ spawn(rand(0, 15))
+ icon_state = "[initial(icon_state)]-off"
+
+//Oh no we're malfunctioning! Dump out some product and break.
+/obj/machinery/vending/proc/malfunction()
+ for(var/datum/stored_item/vending_product/R in product_records)
+ while(R.get_amount()>0)
+ R.get_product(loc)
+ break
+
+ stat |= BROKEN
+ icon_state = "[initial(icon_state)]-broken"
+ return
+
+//Somebody cut an important wire and now we're following a new definition of "pitch."
+/obj/machinery/vending/proc/throw_item()
+ var/obj/throw_item = null
+ var/mob/living/target = locate() in view(7,src)
+ if(!target)
+ return 0
+
+ for(var/datum/stored_item/vending_product/R in product_records)
+ throw_item = R.get_product(loc)
+ if(!throw_item)
+ continue
+ break
+ if(!throw_item)
+ return 0
+ spawn(0)
+ throw_item.throw_at(target, 16, 3, src)
+ visible_message("\The [src] launches \a [throw_item] at \the [target]!")
+ return 1
+
+//Actual machines are in vending_machines.dm
diff --git a/code/game/machinery/vending_machines.dm b/code/modules/economy/vending_machines.dm
similarity index 100%
rename from code/game/machinery/vending_machines.dm
rename to code/modules/economy/vending_machines.dm
diff --git a/code/game/objects/items/stacks/fifty_spawner.dm b/code/modules/materials/fifty_spawner.dm
similarity index 100%
rename from code/game/objects/items/stacks/fifty_spawner.dm
rename to code/modules/materials/fifty_spawner.dm
diff --git a/code/modules/materials/fifty_spawner_mats_vr.dm b/code/modules/materials/fifty_spawner_mats_vr.dm
new file mode 100644
index 0000000000..0b6e29ffa0
--- /dev/null
+++ b/code/modules/materials/fifty_spawner_mats_vr.dm
@@ -0,0 +1,19 @@
+/obj/fiftyspawner/titanium
+ name = "stack of titanium"
+ type_to_spawn = /obj/item/stack/material/titanium
+
+/obj/fiftyspawner/titanium_glass
+ name = "stack of ti-glass"
+ type_to_spawn = /obj/item/stack/material/glass/titanium
+
+/obj/fiftyspawner/plastitanium
+ name = "stack of plastitanium"
+ type_to_spawn = /obj/item/stack/material/plastitanium
+
+/obj/fiftyspawner/plastitanium_hull
+ name = "stack of plastitanium"
+ type_to_spawn = /obj/item/stack/material/plastitanium/hull
+
+/obj/fiftyspawner/plastitanium_glass
+ name = "stack of plastitanium glass"
+ type_to_spawn = /obj/item/stack/material/glass/plastitanium
diff --git a/code/modules/materials/material_recipes_vr.dm b/code/modules/materials/material_recipes_vr.dm
deleted file mode 100644
index bf5b54d853..0000000000
--- a/code/modules/materials/material_recipes_vr.dm
+++ /dev/null
@@ -1,90 +0,0 @@
-
-/datum/material/steel/generate_recipes()
- . = ..()
- recipes += new/datum/stack_recipe_list("mounted chairs", list(
- new/datum/stack_recipe("mounted chair", /obj/structure/bed/chair/bay/chair, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("red mounted chair", /obj/structure/bed/chair/bay/chair/padded/red, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("brown mounted chair", /obj/structure/bed/chair/bay/chair/padded/brown, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("teal mounted chair", /obj/structure/bed/chair/bay/chair/padded/teal, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("black mounted chair", /obj/structure/bed/chair/bay/chair/padded/black, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("green mounted chair", /obj/structure/bed/chair/bay/chair/padded/green, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("purple mounted chair", /obj/structure/bed/chair/bay/chair/padded/purple, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("blue mounted chair", /obj/structure/bed/chair/bay/chair/padded/blue, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("beige mounted chair", /obj/structure/bed/chair/bay/chair/padded/beige, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("lime mounted chair", /obj/structure/bed/chair/bay/chair/padded/lime, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("yellow mounted chair", /obj/structure/bed/chair/bay/chair/padded/yellow, 2, one_per_turf = 1, on_floor = 1, time = 10)
- ))
- recipes += new/datum/stack_recipe_list("mounted comfy chairs", list(
- new/datum/stack_recipe("mounted comfy chair", /obj/structure/bed/chair/bay/comfy, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("red mounted comfy chair", /obj/structure/bed/chair/bay/comfy/red, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("brown mounted comfy chair", /obj/structure/bed/chair/bay/comfy/brown, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("teal mounted comfy chair", /obj/structure/bed/chair/bay/comfy/teal, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("black mounted comfy chair", /obj/structure/bed/chair/bay/comfy/black, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("green mounted comfy chair", /obj/structure/bed/chair/bay/comfy/green, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("purple mounted comfy chair", /obj/structure/bed/chair/bay/comfy/purple, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("blue mounted comfy chair", /obj/structure/bed/chair/bay/comfy/blue, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("beige mounted comfy chair", /obj/structure/bed/chair/bay/comfy/beige, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("lime mounted comfy chair", /obj/structure/bed/chair/bay/comfy/lime, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("yellow mounted comfy chair", /obj/structure/bed/chair/bay/comfy/yellow, 3, one_per_turf = 1, on_floor = 1, time = 20)
- ))
- recipes += new/datum/stack_recipe("mounted captain's chair", /obj/structure/bed/chair/bay/comfy/captain, 4, one_per_turf = 1, on_floor = 1, time = 20)
- recipes += new/datum/stack_recipe("dropship seat", /obj/structure/bed/chair/bay/shuttle, 4, one_per_turf = 1, on_floor = 1, time = 20)
- recipes += new/datum/stack_recipe("small teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/smallnest, 2, one_per_turf = 1, on_floor = 1, time = 10)
- recipes += new/datum/stack_recipe("large teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/bignest, 4, one_per_turf = 1, on_floor = 1, time = 20)
- recipes += new/datum/stack_recipe("dance pole", /obj/structure/dancepole, 2, one_per_turf = 1, on_floor = 1, time = 20)
- recipes += new/datum/stack_recipe("light switch frame", /obj/item/frame/lightswitch, 2)
- recipes += new/datum/stack_recipe_list("sofas", list(
- new/datum/stack_recipe("red sofa middle", /obj/structure/bed/chair/sofa, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("red sofa left", /obj/structure/bed/chair/sofa/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("red sofa right", /obj/structure/bed/chair/sofa/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("red sofa corner", /obj/structure/bed/chair/sofa/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("brown sofa middle", /obj/structure/bed/chair/sofa/brown, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("brown sofa left", /obj/structure/bed/chair/sofa/brown/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("brown sofa right", /obj/structure/bed/chair/sofa/brown/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("brown sofa corner", /obj/structure/bed/chair/sofa/brown/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("teal sofa middle", /obj/structure/bed/chair/sofa/teal, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("teal sofa left", /obj/structure/bed/chair/sofa/teal/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("teal sofa right", /obj/structure/bed/chair/sofa/teal/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("teal sofa corner", /obj/structure/bed/chair/sofa/teal/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("black sofa middle", /obj/structure/bed/chair/sofa/black, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("black sofa left", /obj/structure/bed/chair/sofa/black/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("black sofa right", /obj/structure/bed/chair/sofa/black/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("black sofa corner", /obj/structure/bed/chair/sofa/black/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("green sofa middle", /obj/structure/bed/chair/sofa/green, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("green sofa left", /obj/structure/bed/chair/sofa/green/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("green sofa right", /obj/structure/bed/chair/sofa/green/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("green sofa corner", /obj/structure/bed/chair/sofa/green/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("purple sofa middle", /obj/structure/bed/chair/sofa/purp, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("purple sofa left", /obj/structure/bed/chair/sofa/purp/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("purple sofa right", /obj/structure/bed/chair/sofa/purp/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("purple sofa corner", /obj/structure/bed/chair/sofa/purp/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("blue sofa middle", /obj/structure/bed/chair/sofa/blue, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("blue sofa left", /obj/structure/bed/chair/sofa/blue/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("blue sofa right", /obj/structure/bed/chair/sofa/blue/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("blue sofa corner", /obj/structure/bed/chair/sofa/blue/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("beige sofa middle", /obj/structure/bed/chair/sofa/beige, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("beige sofa left", /obj/structure/bed/chair/sofa/beige/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("beige sofa right", /obj/structure/bed/chair/sofa/beige/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("beige sofa corner", /obj/structure/bed/chair/sofa/beige/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("lime sofa middle", /obj/structure/bed/chair/sofa/lime, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("lime sofa left", /obj/structure/bed/chair/sofa/lime/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("lime sofa right", /obj/structure/bed/chair/sofa/lime/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("lime sofa corner", /obj/structure/bed/chair/sofa/lime/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("yellow sofa middle", /obj/structure/bed/chair/sofa/yellow, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("yellow sofa left", /obj/structure/bed/chair/sofa/yellow/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("yellow sofa right", /obj/structure/bed/chair/sofa/yellow/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("yellow sofa corner", /obj/structure/bed/chair/sofa/yellow/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("orange sofa middle", /obj/structure/bed/chair/sofa/orange, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("orange sofa left", /obj/structure/bed/chair/sofa/orange/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("orange sofa right", /obj/structure/bed/chair/sofa/orange/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("orange sofa corner", /obj/structure/bed/chair/sofa/orange/corner, 1, one_per_turf = 1, on_floor = 1), \
- ))
-
-/datum/material/durasteel/generate_recipes()
- . = ..()
- recipes += new/datum/stack_recipe("durasteel fishing rod", /obj/item/weapon/material/fishing_rod/modern/strong, 2)
- recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 30)
-
-/datum/material/plastitanium/generate_recipes()
- . = ..()
- recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 20)
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
deleted file mode 100644
index 3fd995378c..0000000000
--- a/code/modules/materials/material_sheets.dm
+++ /dev/null
@@ -1,565 +0,0 @@
-// Stacked resources. They use a material datum for a lot of inherited values.
-// If you're adding something here, make sure to add it to fifty_spawner_mats.dm as well
-/obj/item/stack/material
- force = 5.0
- throwforce = 5
- w_class = ITEMSIZE_NORMAL
- throw_speed = 3
- throw_range = 3
- center_of_mass = null
- max_amount = 50
- item_icons = list(
- slot_l_hand_str = 'icons/mob/items/lefthand_material.dmi',
- slot_r_hand_str = 'icons/mob/items/righthand_material.dmi',
- )
-
- var/default_type = DEFAULT_WALL_MATERIAL
- var/datum/material/material
- var/perunit = SHEET_MATERIAL_AMOUNT
- var/apply_colour //temp pending icon rewrite
- drop_sound = 'sound/items/drop/axe.ogg'
- pickup_sound = 'sound/items/pickup/axe.ogg'
-
-/obj/item/stack/material/Initialize()
- . = ..()
-
- randpixel_xy()
-
- if(!default_type)
- default_type = DEFAULT_WALL_MATERIAL
- material = get_material_by_name("[default_type]")
- if(!material)
- return INITIALIZE_HINT_QDEL
-
- recipes = material.get_recipes()
- stacktype = material.stack_type
- if(islist(material.stack_origin_tech))
- origin_tech = material.stack_origin_tech.Copy()
-
- if(apply_colour)
- color = material.icon_colour
-
- if(!material.conductive)
- flags |= NOCONDUCT
-
- matter = material.get_matter()
- update_strings()
-
-/obj/item/stack/material/get_material()
- return material
-
-/obj/item/stack/material/proc/update_strings()
- // Update from material datum.
- singular_name = material.sheet_singular_name
-
- if(amount>1)
- name = "[material.use_name] [material.sheet_plural_name]"
- desc = "A stack of [material.use_name] [material.sheet_plural_name]."
- gender = PLURAL
- else
- name = "[material.use_name] [material.sheet_singular_name]"
- desc = "A [material.sheet_singular_name] of [material.use_name]."
- gender = NEUTER
-
-/obj/item/stack/material/use(var/used)
- . = ..()
- update_strings()
- return
-
-/obj/item/stack/material/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified)
- var/obj/item/stack/material/M = S
- if(!istype(M) || material.name != M.material.name)
- return 0
- var/transfer = ..(S,tamount,1)
- if(src) update_strings()
- if(M) M.update_strings()
- return transfer
-
-/obj/item/stack/material/attack_self(var/mob/user)
- if(!material.build_windows(user, src))
- ..()
-
-/obj/item/stack/material/attackby(var/obj/item/W, var/mob/user)
- if(istype(W,/obj/item/stack/cable_coil))
- material.build_wired_product(user, W, src)
- return
- else if(istype(W, /obj/item/stack/rods))
- material.build_rod_product(user, W, src)
- return
- return ..()
-
-//VOREStation Add
-/obj/item/stack/material/attack(mob/living/M as mob, mob/living/user as mob)
- if(M.handle_eat_minerals(src, user))
- return
- ..()
-
-/obj/item/stack/material/attack_generic(var/mob/living/user) //Allow adminbussed mobs to eat ore if they click it while NOT on help intent.
- if(user.handle_eat_minerals(src))
- return
- ..()
-//VOREStation Add End
-
-/obj/item/stack/material/iron
- name = "iron"
- icon_state = "sheet-ingot"
- default_type = "iron"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/lead
- name = "lead"
- icon_state = "sheet-ingot"
- default_type = "lead"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/sandstone
- name = "sandstone brick"
- icon_state = "sheet-sandstone"
- default_type = "sandstone"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/boots.ogg'
- pickup_sound = 'sound/items/pickup/boots.ogg'
-
-/obj/item/stack/material/marble
- name = "marble brick"
- icon_state = "sheet-marble"
- default_type = "marble"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/boots.ogg'
- pickup_sound = 'sound/items/pickup/boots.ogg'
-
-/obj/item/stack/material/diamond
- name = "diamond"
- icon_state = "sheet-diamond"
- default_type = "diamond"
- drop_sound = 'sound/items/drop/glass.ogg'
- pickup_sound = 'sound/items/pickup/glass.ogg'
-
-/obj/item/stack/material/uranium
- name = "uranium"
- icon_state = "sheet-uranium"
- default_type = "uranium"
- no_variants = FALSE
-
-/obj/item/stack/material/phoron
- name = "solid phoron"
- icon_state = "sheet-phoron"
- default_type = "phoron"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/glass.ogg'
- pickup_sound = 'sound/items/pickup/glass.ogg'
-
-/obj/item/stack/material/plastic
- name = "plastic"
- icon_state = "sheet-plastic"
- default_type = "plastic"
- no_variants = FALSE
-
-/obj/item/stack/material/graphite
- name = "graphite"
- icon_state = "sheet-puck"
- default_type = MAT_GRAPHITE
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/gold
- name = "gold"
- icon_state = "sheet-ingot"
- default_type = "gold"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/silver
- name = "silver"
- icon_state = "sheet-ingot"
- default_type = "silver"
- no_variants = FALSE
- apply_colour = TRUE
-
-//Valuable resource, cargo can sell it.
-/obj/item/stack/material/platinum
- name = "platinum"
- icon_state = "sheet-adamantine"
- default_type = "platinum"
- no_variants = FALSE
- apply_colour = TRUE
-
-//Extremely valuable to Research.
-/obj/item/stack/material/mhydrogen
- name = "metallic hydrogen"
- icon_state = "sheet-mythril"
- default_type = "mhydrogen"
- no_variants = FALSE
-
-//Fuel for MRSPACMAN generator.
-/obj/item/stack/material/tritium
- name = "tritium"
- icon_state = "sheet-puck"
- default_type = "tritium"
- apply_colour = TRUE
- no_variants = FALSE
-
-/obj/item/stack/material/osmium
- name = "osmium"
- icon_state = "sheet-ingot"
- default_type = "osmium"
- apply_colour = 1
- no_variants = FALSE
-
-//R-UST port
-// Fusion fuel.
-/obj/item/stack/material/deuterium
- name = "deuterium"
- icon_state = "sheet-puck"
- default_type = "deuterium"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/steel
- name = DEFAULT_WALL_MATERIAL
- icon_state = "sheet-refined"
- default_type = DEFAULT_WALL_MATERIAL
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/steel/hull
- name = MAT_STEELHULL
- default_type = MAT_STEELHULL
-
-/obj/item/stack/material/plasteel
- name = "plasteel"
- icon_state = "sheet-reinforced"
- default_type = "plasteel"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/plasteel/hull
- name = MAT_PLASTEELHULL
- default_type = MAT_PLASTEELHULL
-
-/obj/item/stack/material/durasteel
- name = "durasteel"
- icon_state = "sheet-reinforced"
- item_state = "sheet-metal"
- default_type = "durasteel"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/durasteel/hull
- name = MAT_DURASTEELHULL
-
-/obj/item/stack/material/titanium
- name = MAT_TITANIUM
- icon_state = "sheet-refined"
- apply_colour = TRUE
- item_state = "sheet-silver"
- default_type = MAT_TITANIUM
- no_variants = FALSE
-
-/obj/item/stack/material/titanium/hull
- name = MAT_TITANIUMHULL
- default_type = MAT_TITANIUMHULL
-
-// Particle Smasher and Exotic material.
-/obj/item/stack/material/verdantium
- name = MAT_VERDANTIUM
- icon_state = "sheet-wavy"
- item_state = "mhydrogen"
- default_type = MAT_VERDANTIUM
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/morphium
- name = MAT_MORPHIUM
- icon_state = "sheet-wavy"
- item_state = "mhydrogen"
- default_type = MAT_MORPHIUM
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/morphium/hull
- name = MAT_MORPHIUMHULL
- default_type = MAT_MORPHIUMHULL
-
-/obj/item/stack/material/valhollide
- name = MAT_VALHOLLIDE
- icon_state = "sheet-gem"
- item_state = "diamond"
- default_type = MAT_VALHOLLIDE
- no_variants = FALSE
- apply_colour = TRUE
-
-// Forged in the equivalent of Hell, one piece at a time.
-/obj/item/stack/material/supermatter
- name = MAT_SUPERMATTER
- icon_state = "sheet-super"
- item_state = "diamond"
- default_type = MAT_SUPERMATTER
- apply_colour = TRUE
-
-/obj/item/stack/material/supermatter/proc/update_mass() // Due to how dangerous they can be, the item will get heavier and larger the more are in the stack.
- slowdown = amount / 10
- w_class = min(5, round(amount / 10) + 1)
- throw_range = round(amount / 7) + 1
-
-/obj/item/stack/material/supermatter/use(var/used)
- . = ..()
- update_mass()
- return
-
-/obj/item/stack/material/supermatter/attack_hand(mob/user)
- . = ..()
-
- update_mass()
- SSradiation.radiate(src, 5 + amount)
- var/mob/living/M = user
- if(!istype(M))
- return
-
- var/burn_user = TRUE
- if(istype(M, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = user
- var/obj/item/clothing/gloves/G = H.gloves
- if(istype(G) && ((G.flags & THICKMATERIAL && prob(70)) || istype(G, /obj/item/clothing/gloves/gauntlets)))
- burn_user = FALSE
-
- if(burn_user)
- H.visible_message("\The [src] flashes as it scorches [H]'s hands!")
- H.apply_damage(amount / 2 + 5, BURN, "r_hand", used_weapon="Supermatter Chunk")
- H.apply_damage(amount / 2 + 5, BURN, "l_hand", used_weapon="Supermatter Chunk")
- H.drop_from_inventory(src, get_turf(H))
- return
-
- if(istype(user, /mob/living/silicon/robot))
- burn_user = FALSE
-
- if(burn_user)
- M.apply_damage(amount, BURN, null, used_weapon="Supermatter Chunk")
-
-/obj/item/stack/material/supermatter/ex_act(severity) // An incredibly hard to manufacture material, SM chunks are unstable by their 'stabilized' nature.
- if(prob((4 / severity) * 20))
- SSradiation.radiate(get_turf(src), amount * 4)
- explosion(get_turf(src),round(amount / 12) , round(amount / 6), round(amount / 3), round(amount / 25))
- qdel(src)
- return
- SSradiation.radiate(get_turf(src), amount * 2)
- ..()
-
-/obj/item/stack/material/wood
- name = "wooden plank"
- icon_state = "sheet-wood"
- default_type = MAT_WOOD
- strict_color_stacking = TRUE
- apply_colour = 1
- drop_sound = 'sound/items/drop/wooden.ogg'
- pickup_sound = 'sound/items/pickup/wooden.ogg'
- no_variants = FALSE
-
-/obj/item/stack/material/wood/sif
- name = "alien wooden plank"
- color = "#0099cc"
- default_type = MAT_SIFWOOD
-
-/obj/item/stack/material/log
- name = "log"
- icon_state = "sheet-log"
- default_type = MAT_LOG
- no_variants = FALSE
- color = "#824B28"
- max_amount = 25
- w_class = ITEMSIZE_HUGE
- description_info = "Use inhand to craft things, or use a sharp and edged object on this to convert it into two wooden planks."
- var/plank_type = /obj/item/stack/material/wood
- drop_sound = 'sound/items/drop/wooden.ogg'
- pickup_sound = 'sound/items/pickup/wooden.ogg'
-
-/obj/item/stack/material/log/sif
- name = "alien log"
- default_type = MAT_SIFLOG
- color = "#0099cc"
- plank_type = /obj/item/stack/material/wood/sif
-
-/obj/item/stack/material/log/attackby(var/obj/item/W, var/mob/user)
- if(!istype(W) || W.force <= 0)
- return ..()
- if(W.sharp && W.edge)
- var/time = (3 SECONDS / max(W.force / 10, 1)) * W.toolspeed
- user.setClickCooldown(time)
- if(do_after(user, time, src) && use(1))
- to_chat(user, "You cut up a log into planks.")
- playsound(src, 'sound/effects/woodcutting.ogg', 50, 1)
- var/obj/item/stack/material/wood/existing_wood = null
- for(var/obj/item/stack/material/wood/M in user.loc)
- if(M.material.name == src.material.name)
- existing_wood = M
- break
-
- var/obj/item/stack/material/wood/new_wood = new plank_type(user.loc)
- new_wood.amount = 2
- if(existing_wood && new_wood.transfer_to(existing_wood))
- to_chat(user, "You add the newly-formed wood to the stack. It now contains [existing_wood.amount] planks.")
- else
- return ..()
-
-
-/obj/item/stack/material/cloth
- name = "cloth"
- icon_state = "sheet-cloth"
- default_type = "cloth"
- no_variants = FALSE
- pass_color = TRUE
- strict_color_stacking = TRUE
- drop_sound = 'sound/items/drop/clothing.ogg'
- pickup_sound = 'sound/items/pickup/clothing.ogg'
-
-/obj/item/stack/material/cloth/diyaab
- color = "#c6ccf0"
-
-/obj/item/stack/material/resin
- name = "resin"
- icon_state = "sheet-resin"
- default_type = "resin"
- no_variants = TRUE
- apply_colour = TRUE
- pass_color = TRUE
- strict_color_stacking = TRUE
-
-/obj/item/stack/material/cardboard
- name = "cardboard"
- icon_state = "sheet-card"
- default_type = "cardboard"
- no_variants = FALSE
- pass_color = TRUE
- strict_color_stacking = TRUE
- drop_sound = 'sound/items/drop/cardboardbox.ogg'
- pickup_sound = 'sound/items/pickup/cardboardbox.ogg'
-
-/obj/item/stack/material/snow
- name = "snow"
- desc = "The temptation to build a snowman rises."
- icon_state = "sheet-snow"
- drop_sound = 'sound/items/drop/gloves.ogg'
- pickup_sound = 'sound/items/pickup/clothing.ogg'
- default_type = "snow"
-
-/obj/item/stack/material/snowbrick
- name = "snow brick"
- desc = "For all of your igloo building needs."
- icon_state = "sheet-snowbrick"
- default_type = "packed snow"
- drop_sound = 'sound/items/drop/gloves.ogg'
- pickup_sound = 'sound/items/pickup/clothing.ogg'
-
-/obj/item/stack/material/leather
- name = "leather"
- desc = "The by-product of mob grinding."
- icon_state = "sheet-leather"
- default_type = MAT_LEATHER
- no_variants = FALSE
- pass_color = TRUE
- strict_color_stacking = TRUE
- drop_sound = 'sound/items/drop/leather.ogg'
- pickup_sound = 'sound/items/pickup/leather.ogg'
-
-/obj/item/stack/material/chitin
- name = "chitin"
- desc = "The by-product of mob grinding."
- icon_state = "chitin"
- default_type = MAT_CHITIN
- no_variants = FALSE
- pass_color = TRUE
- strict_color_stacking = TRUE
- drop_sound = 'sound/items/drop/leather.ogg'
- pickup_sound = 'sound/items/pickup/leather.ogg'
-
-/obj/item/stack/material/glass
- name = "glass"
- icon_state = "sheet-transparent"
- default_type = "glass"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/glass.ogg'
- pickup_sound = 'sound/items/pickup/glass.ogg'
- apply_colour = TRUE
-
-/obj/item/stack/material/glass/reinforced
- name = "reinforced glass"
- icon_state = "sheet-rtransparent"
- default_type = "rglass"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/glass/phoronglass
- name = "borosilicate glass"
- desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures"
- singular_name = "borosilicate glass sheet"
- icon_state = "sheet-transparent"
- default_type = "borosilicate glass"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/glass/phoronrglass
- name = "reinforced borosilicate glass"
- desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures. It is reinforced with few rods."
- singular_name = "reinforced borosilicate glass sheet"
- icon_state = "sheet-rtransparent"
- default_type = "reinforced borosilicate glass"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/bronze
- name = "bronze"
- icon_state = "sheet-ingot"
- singular_name = "bronze ingot"
- default_type = "bronze"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/tin
- name = "tin"
- icon_state = "sheet-ingot"
- singular_name = "tin ingot"
- default_type = "tin"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/copper
- name = "copper"
- icon_state = "sheet-ingot"
- singular_name = "copper ingot"
- default_type = "copper"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/painite
- name = "painite"
- icon_state = "sheet-gem"
- singular_name = "painite gem"
- default_type = "painite"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/void_opal
- name = "void opal"
- icon_state = "sheet-void_opal"
- singular_name = "void opal"
- default_type = "void opal"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/quartz
- name = "quartz"
- icon_state = "sheet-gem"
- singular_name = "quartz gem"
- default_type = "quartz"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/aluminium
- name = "aluminium"
- icon_state = "sheet-ingot"
- singular_name = "aluminium ingot"
- default_type = "aluminium"
- apply_colour = 1
- no_variants = FALSE
diff --git a/code/modules/materials/material_sheets_vr.dm b/code/modules/materials/material_sheets_vr.dm
deleted file mode 100644
index 71d7e7d3ea..0000000000
--- a/code/modules/materials/material_sheets_vr.dm
+++ /dev/null
@@ -1,66 +0,0 @@
-/obj/item/stack/material/titanium
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-titanium"
- no_variants = FALSE
-
-/obj/fiftyspawner/titanium
- name = "stack of titanium"
- type_to_spawn = /obj/item/stack/material/titanium
-
-/obj/item/stack/material/glass/titanium
- name = "ti-glass sheets"
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-titaniumglass"
- item_state = "sheet-silver"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/glass.ogg'
- default_type = MAT_TITANIUMGLASS
-
-/obj/fiftyspawner/titanium_glass
- name = "stack of ti-glass"
- type_to_spawn = /obj/item/stack/material/glass/titanium
-
-/obj/item/stack/material/plastitanium
- name = "plastitanium sheets"
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-plastitanium"
- item_state = "sheet-silver"
- no_variants = FALSE
- default_type = MAT_PLASTITANIUM
-
-/obj/fiftyspawner/plastitanium
- name = "stack of plastitanium"
- type_to_spawn = /obj/item/stack/material/plastitanium
-
-/obj/item/stack/material/plastitanium/hull
- name = "plastitanium hull sheets"
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-plastitanium"
- item_state = "sheet-silver"
- no_variants = FALSE
- default_type = MAT_PLASTITANIUMHULL
-
-/obj/fiftyspawner/plastitanium_hull
- name = "stack of plastitanium"
- type_to_spawn = /obj/item/stack/material/plastitanium/hull
-
-/obj/item/stack/material/glass/plastitanium
- name = "plastitanium glass sheets"
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-plastitaniumglass"
- item_state = "sheet-silver"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/glass.ogg'
- default_type = MAT_PLASTITANIUMGLASS
-
-/obj/fiftyspawner/plastitanium_glass
- name = "stack of plastitanium glass"
- type_to_spawn = /obj/item/stack/material/glass/plastitanium
-
-/obj/item/stack/material/gold/hull
- name = "gold hull sheets"
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-plastitanium"
- item_state = "sheet-silver"
- no_variants = FALSE
- default_type = MAT_GOLDHULL
\ No newline at end of file
diff --git a/code/modules/materials/materials/_materials.dm b/code/modules/materials/materials/_materials.dm
new file mode 100644
index 0000000000..1b6cabffd9
--- /dev/null
+++ b/code/modules/materials/materials/_materials.dm
@@ -0,0 +1,284 @@
+/*
+ MATERIAL DATUMS
+ This data is used by various parts of the game for basic physical properties and behaviors
+ of the metals/materials used for constructing many objects. Each var is commented and should be pretty
+ self-explanatory but the various object types may have their own documentation. ~Z
+
+ PATHS THAT USE DATUMS
+ turf/simulated/wall
+ obj/item/weapon/material
+ obj/structure/barricade
+ obj/item/stack/material
+ obj/structure/table
+
+ VALID ICONS
+ WALLS
+ stone
+ metal
+ solid
+ resin
+ ONLY WALLS
+ cult
+ hull
+ curvy
+ jaggy
+ brick
+ REINFORCEMENT
+ reinf_over
+ reinf_mesh
+ reinf_cult
+ reinf_metal
+ DOORS
+ stone
+ metal
+ resin
+ wood
+*/
+
+// Assoc list containing all material datums indexed by name.
+var/list/name_to_material
+
+//Returns the material the object is made of, if applicable.
+//Will we ever need to return more than one value here? Or should we just return the "dominant" material.
+/obj/proc/get_material()
+ return null
+
+//mostly for convenience
+/obj/proc/get_material_name()
+ var/datum/material/material = get_material()
+ if(material)
+ return material.name
+
+// Builds the datum list above.
+/proc/populate_material_list(force_remake=0)
+ if(name_to_material && !force_remake) return // Already set up!
+ name_to_material = list()
+ for(var/type in subtypesof(/datum/material))
+ var/datum/material/new_mineral = new type
+ if(!new_mineral.name)
+ continue
+ name_to_material[lowertext(new_mineral.name)] = new_mineral
+ return 1
+
+// Safety proc to make sure the material list exists before trying to grab from it.
+/proc/get_material_by_name(name)
+ if(!name_to_material)
+ populate_material_list()
+ return name_to_material[name]
+
+/proc/material_display_name(name)
+ var/datum/material/material = get_material_by_name(name)
+ if(material)
+ return material.display_name
+ return null
+
+// Material definition and procs follow.
+/datum/material
+ var/name // Unique name for use in indexing the list.
+ var/display_name // Prettier name for display.
+ var/use_name
+ var/flags = 0 // Various status modifiers.
+ var/sheet_singular_name = "sheet"
+ var/sheet_plural_name = "sheets"
+ var/is_fusion_fuel
+
+ // Shards/tables/structures
+ var/shard_type = SHARD_SHRAPNEL // Path of debris object.
+ var/shard_icon // Related to above.
+ var/shard_can_repair = 1 // Can shards be turned into sheets with a welder?
+ var/list/recipes // Holder for all recipes usable with a sheet of this material.
+ var/destruction_desc = "breaks apart" // Fancy string for barricades/tables/objects exploding.
+
+ // Icons
+ var/icon_colour // Colour applied to products of this material.
+ var/icon_base = "metal" // Wall and table base icon tag. See header.
+ var/door_icon_base = "metal" // Door base icon tag. See header.
+ var/icon_reinf = "reinf_metal" // Overlay used
+ var/list/stack_origin_tech = list(TECH_MATERIAL = 1) // Research level for stacks.
+ var/pass_stack_colors = FALSE // Will stacks made from this material pass their colors onto objects?
+
+ // Attributes
+ var/cut_delay = 0 // Delay in ticks when cutting through this wall.
+ var/radioactivity // Radiation var. Used in wall and object processing to irradiate surroundings.
+ var/ignition_point // K, point at which the material catches on fire.
+ var/melting_point = 1800 // K, walls will take damage if they're next to a fire hotter than this
+ var/integrity = 150 // General-use HP value for products.
+ var/protectiveness = 10 // How well this material works as armor. Higher numbers are better, diminishing returns applies.
+ var/opacity = 1 // Is the material transparent? 0.5< makes transparent walls/doors.
+ var/reflectivity = 0 // How reflective to light is the material? Currently used for laser reflection and defense.
+ var/explosion_resistance = 5 // Only used by walls currently.
+ var/negation = 0 // Objects that respect this will randomly absorb impacts with this var as the percent chance.
+ var/spatial_instability = 0 // Objects that have trouble staying in the same physical space by sheer laws of nature have this. Percent for respecting items to cause teleportation.
+ var/conductive = 1 // Objects without this var add NOCONDUCT to flags on spawn.
+ var/conductivity = null // How conductive the material is. Iron acts as the baseline, at 10.
+ var/list/composite_material // If set, object matter var will be a list containing these values.
+ var/luminescence
+ var/radiation_resistance = 0 // Radiation resistance, which is added on top of a material's weight for blocking radiation. Needed to make lead special without superrobust weapons.
+ var/supply_conversion_value // Supply points per sheet that this material sells for.
+
+ // Placeholder vars for the time being, todo properly integrate windows/light tiles/rods.
+ var/created_window
+ var/created_fulltile_window
+ var/rod_product
+ var/wire_product
+ var/list/window_options = list()
+
+ // Damage values.
+ var/hardness = 60 // Prob of wall destruction by hulk, used for edge damage in weapons. Also used for bullet protection in armor.
+ var/weight = 20 // Determines blunt damage/throwforce for weapons.
+
+ // Noise when someone is faceplanted onto a table made of this material.
+ var/tableslam_noise = 'sound/weapons/tablehit1.ogg'
+ // Noise made when a simple door made of this material opens or closes.
+ var/dooropen_noise = 'sound/effects/stonedoor_openclose.ogg'
+ // Path to resulting stacktype. Todo remove need for this.
+ var/stack_type
+ // Wallrot crumble message.
+ var/rotting_touch_message = "crumbles under your touch"
+
+// Placeholders for light tiles and rglass.
+/datum/material/proc/build_rod_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
+ if(!rod_product)
+ to_chat(user, "You cannot make anything out of \the [target_stack]")
+ return
+ if(used_stack.get_amount() < 1 || target_stack.get_amount() < 1)
+ to_chat(user, "You need one rod and one sheet of [display_name] to make anything useful.")
+ return
+ used_stack.use(1)
+ target_stack.use(1)
+ var/obj/item/stack/S = new rod_product(get_turf(user))
+ S.add_fingerprint(user)
+ S.add_to_stacks(user)
+
+/datum/material/proc/build_wired_product(var/mob/living/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
+ if(!wire_product)
+ to_chat(user, "You cannot make anything out of \the [target_stack]")
+ return
+ if(used_stack.get_amount() < 5 || target_stack.get_amount() < 1)
+ to_chat(user, "You need five wires and one sheet of [display_name] to make anything useful.")
+ return
+
+ used_stack.use(5)
+ target_stack.use(1)
+ to_chat(user, "You attach wire to the [name].")
+ var/obj/item/product = new wire_product(get_turf(user))
+ user.put_in_hands(product)
+
+// Make sure we have a display name and shard icon even if they aren't explicitly set.
+/datum/material/New()
+ ..()
+ if(!display_name)
+ display_name = name
+ if(!use_name)
+ use_name = display_name
+ if(!shard_icon)
+ shard_icon = shard_type
+
+// This is a placeholder for proper integration of windows/windoors into the system.
+/datum/material/proc/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
+ return 0
+
+// Weapons handle applying a divisor for this value locally.
+/datum/material/proc/get_blunt_damage()
+ return weight //todo
+
+// Return the matter comprising this material.
+/datum/material/proc/get_matter()
+ var/list/temp_matter = list()
+ if(islist(composite_material))
+ for(var/material_string in composite_material)
+ temp_matter[material_string] = composite_material[material_string]
+ else if(SHEET_MATERIAL_AMOUNT)
+ temp_matter[name] = SHEET_MATERIAL_AMOUNT
+ return temp_matter
+
+// As above.
+/datum/material/proc/get_edge_damage()
+ return hardness //todo
+
+// Snowflakey, only checked for alien doors at the moment.
+/datum/material/proc/can_open_material_door(var/mob/living/user)
+ return 1
+
+// Currently used for weapons and objects made of uranium to irradiate things.
+/datum/material/proc/products_need_process()
+ return (radioactivity>0) //todo
+
+// Used by walls when qdel()ing to avoid neighbor merging.
+/datum/material/placeholder
+ name = "placeholder"
+
+// Places a girder object when a wall is dismantled, also applies reinforced material.
+/datum/material/proc/place_dismantled_girder(var/turf/target, var/datum/material/reinf_material, var/datum/material/girder_material)
+ var/obj/structure/girder/G = new(target)
+ if(reinf_material)
+ G.reinf_material = reinf_material
+ G.reinforce_girder()
+ if(girder_material)
+ if(istype(girder_material, /datum/material))
+ girder_material = girder_material.name
+ G.set_material(girder_material)
+
+
+// General wall debris product placement.
+// Not particularly necessary aside from snowflakey cult girders.
+/datum/material/proc/place_dismantled_product(var/turf/target)
+ place_sheet(target)
+
+// Debris product. Used ALL THE TIME.
+/datum/material/proc/place_sheet(var/turf/target)
+ if(stack_type)
+ return new stack_type(target)
+
+// As above.
+/datum/material/proc/place_shard(var/turf/target)
+ if(shard_type)
+ return new /obj/item/weapon/material/shard(target, src.name)
+
+// Used by walls and weapons to determine if they break or not.
+/datum/material/proc/is_brittle()
+ return !!(flags & MATERIAL_BRITTLE)
+
+/datum/material/proc/combustion_effect(var/turf/T, var/temperature)
+ return
+
+// Used by walls to do on-touch things, after checking for crumbling and open-ability.
+/datum/material/proc/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L)
+ return
+
+/datum/material/proc/get_recipes()
+ if(!recipes)
+ generate_recipes()
+ return recipes
+
+/datum/material/proc/generate_recipes()
+ // If is_brittle() returns true, these are only good for a single strike.
+ recipes = list(
+ new /datum/stack_recipe("[display_name] baseball bat", /obj/item/weapon/material/twohanded/baseballbat, 10, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] spoon", /obj/item/weapon/material/kitchen/utensil/spoon/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] armor plate insert", /obj/item/weapon/material/armor_plating/insert, 2, time = 40, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] grave marker", /obj/item/weapon/material/gravemarker, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ )
+
+ if(integrity>=50)
+ recipes += list(
+ new /datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ )
+
+ if(hardness>50)
+ recipes += list(
+ new /datum/stack_recipe("[display_name] fork", /obj/item/weapon/material/kitchen/utensil/fork/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/knife/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] blade", /obj/item/weapon/material/butterflyblade, 6, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] defense wire", /obj/item/weapon/material/barbedwire, 10, time = 1 MINUTE, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/_materials_vr.dm b/code/modules/materials/materials/_materials_vr.dm
new file mode 100644
index 0000000000..8c91622fb3
--- /dev/null
+++ b/code/modules/materials/materials/_materials_vr.dm
@@ -0,0 +1,9 @@
+/obj/item/stack/material/attack(mob/living/M as mob, mob/living/user as mob)
+ if(M.handle_eat_minerals(src, user))
+ return
+ ..()
+
+/obj/item/stack/material/attack_generic(var/mob/living/user) //Allow adminbussed mobs to eat ore if they click it while NOT on help intent.
+ if(user.handle_eat_minerals(src))
+ return
+ ..()
diff --git a/code/modules/materials/materials/alien_alloy.dm b/code/modules/materials/materials/alien_alloy.dm
new file mode 100644
index 0000000000..741f0275b7
--- /dev/null
+++ b/code/modules/materials/materials/alien_alloy.dm
@@ -0,0 +1,36 @@
+// Adminspawn only, do not let anyone get this.
+/datum/material/alienalloy
+ name = "alienalloy"
+ display_name = "durable alloy"
+ stack_type = null
+ flags = MATERIAL_UNMELTABLE
+ icon_colour = "#6C7364"
+ integrity = 1200
+ melting_point = 6000 // Hull plating.
+ explosion_resistance = 200 // Hull plating.
+ hardness = 500
+ weight = 500
+ protectiveness = 80 // 80%
+
+/datum/material/alienalloy/elevatorium
+ name = "elevatorium"
+ display_name = "elevator panelling"
+ icon_colour = "#666666"
+
+/datum/material/alienalloy/dungeonium
+ name = "dungeonium"
+ display_name = "ultra-durable"
+ icon_base = "dungeon"
+ icon_colour = "#FFFFFF"
+
+/datum/material/alienalloy/bedrock
+ name = "bedrock"
+ display_name = "impassable rock"
+ icon_base = "rock"
+ icon_colour = "#FFFFFF"
+
+/datum/material/alienalloy/alium
+ name = "alium"
+ display_name = "alien"
+ icon_base = "alien"
+ icon_colour = "#FFFFFF"
\ No newline at end of file
diff --git a/code/modules/materials/materials/cult.dm b/code/modules/materials/materials/cult.dm
new file mode 100644
index 0000000000..7d8d4be9f2
--- /dev/null
+++ b/code/modules/materials/materials/cult.dm
@@ -0,0 +1,23 @@
+/datum/material/cult
+ name = "cult"
+ display_name = "disturbing stone"
+ icon_base = "cult"
+ icon_colour = "#402821"
+ icon_reinf = "reinf_cult"
+ shard_type = SHARD_STONE_PIECE
+ sheet_singular_name = "brick"
+ sheet_plural_name = "bricks"
+ conductive = 0
+
+/datum/material/cult/place_dismantled_girder(var/turf/target)
+ new /obj/structure/girder/cult(target, "cult")
+
+/datum/material/cult/place_dismantled_product(var/turf/target)
+ new /obj/effect/decal/cleanable/blood(target)
+
+/datum/material/cult/reinf
+ name = "cult2"
+ display_name = "human remains"
+
+/datum/material/cult/reinf/place_dismantled_product(var/turf/target)
+ new /obj/effect/decal/remains/human(target)
\ No newline at end of file
diff --git a/code/modules/materials/materials/gems.dm b/code/modules/materials/materials/gems.dm
new file mode 100644
index 0000000000..9ec22a86b1
--- /dev/null
+++ b/code/modules/materials/materials/gems.dm
@@ -0,0 +1,154 @@
+/datum/material/phoron
+ name = "phoron"
+ stack_type = /obj/item/stack/material/phoron
+ ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE
+ icon_base = "stone"
+ icon_colour = "#FC2BC5"
+ shard_type = SHARD_SHARD
+ hardness = 30
+ stack_origin_tech = list(TECH_MATERIAL = 2, TECH_PHORON = 2)
+ door_icon_base = "stone"
+ sheet_singular_name = "crystal"
+ sheet_plural_name = "crystals"
+ supply_conversion_value = 5
+
+/*
+// Commenting this out while fires are so spectacularly lethal, as I can't seem to get this balanced appropriately.
+/datum/material/phoron/combustion_effect(var/turf/T, var/temperature, var/effect_multiplier)
+ if(isnull(ignition_point))
+ return 0
+ if(temperature < ignition_point)
+ return 0
+ var/totalPhoron = 0
+ for(var/turf/simulated/floor/target_tile in range(2,T))
+ var/phoronToDeduce = (temperature/30) * effect_multiplier
+ totalPhoron += phoronToDeduce
+ target_tile.assume_gas("phoron", phoronToDeduce, 200+T0C)
+ spawn (0)
+ target_tile.hotspot_expose(temperature, 400)
+ return round(totalPhoron/100)
+*/
+
+/datum/material/diamond
+ name = "diamond"
+ stack_type = /obj/item/stack/material/diamond
+ flags = MATERIAL_UNMELTABLE
+ cut_delay = 60
+ icon_colour = "#00FFE1"
+ opacity = 0.4
+ reflectivity = 0.6
+ conductive = 0
+ conductivity = 1
+ shard_type = SHARD_SHARD
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ hardness = 100
+ stack_origin_tech = list(TECH_MATERIAL = 6)
+ supply_conversion_value = 8
+
+/datum/material/quartz
+ name = "quartz"
+ display_name = "quartz"
+ use_name = "quartz"
+ icon_colour = "#e6d7df"
+ stack_type = /obj/item/stack/material/quartz
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ sheet_singular_name = "crystal"
+ sheet_plural_name = "crystals"
+ supply_conversion_value = 4
+
+/datum/material/painite
+ name = "painite"
+ display_name = "painite"
+ use_name = "painite"
+ icon_colour = "#6b4947"
+ stack_type = /obj/item/stack/material/painite
+ flags = MATERIAL_UNMELTABLE
+ reflectivity = 0.3
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ sheet_singular_name = "gem"
+ sheet_plural_name = "gems"
+ supply_conversion_value = 4
+
+/datum/material/void_opal
+ name = "void opal"
+ display_name = "void opal"
+ use_name = "void opal"
+ icon_colour = "#0f0f0f"
+ stack_type = /obj/item/stack/material/void_opal
+ flags = MATERIAL_UNMELTABLE
+ cut_delay = 60
+ reflectivity = 0
+ conductivity = 1
+ shard_type = SHARD_SHARD
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ hardness = 100
+ stack_origin_tech = list(TECH_ARCANE = 1, TECH_MATERIAL = 6)
+ sheet_singular_name = "gem"
+ sheet_plural_name = "gems"
+ supply_conversion_value = 30 // These are hilariously rare.
+
+// Particle Smasher and other exotic materials.
+/datum/material/valhollide
+ name = MAT_VALHOLLIDE
+ stack_type = /obj/item/stack/material/valhollide
+ icon_base = "stone"
+ door_icon_base = "stone"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "##FFF3B2"
+ protectiveness = 30
+ integrity = 240
+ weight = 30
+ hardness = 45
+ negation = 2
+ conductive = 0
+ conductivity = 5
+ reflectivity = 0.5
+ radiation_resistance = 20
+ spatial_instability = 30
+ stack_origin_tech = list(TECH_MATERIAL = 7, TECH_PHORON = 5, TECH_BLUESPACE = 5)
+ sheet_singular_name = "gem"
+ sheet_plural_name = "gems"
+
+/datum/material/verdantium
+ name = MAT_VERDANTIUM
+ stack_type = /obj/item/stack/material/verdantium
+ icon_base = "metal"
+ door_icon_base = "metal"
+ icon_reinf = "reinf_metal"
+ icon_colour = "#4FE95A"
+ integrity = 80
+ protectiveness = 15
+ weight = 15
+ hardness = 30
+ shard_type = SHARD_SHARD
+ negation = 15
+ conductivity = 60
+ reflectivity = 0.3
+ radiation_resistance = 5
+ stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 5, TECH_BIO = 4)
+ sheet_singular_name = "sheet"
+ sheet_plural_name = "sheets"
+ supply_conversion_value = 8
+
+/datum/material/morphium
+ name = MAT_MORPHIUM
+ stack_type = /obj/item/stack/material/morphium
+ icon_base = "metal"
+ door_icon_base = "metal"
+ icon_colour = "#37115A"
+ icon_reinf = "reinf_metal"
+ protectiveness = 60
+ integrity = 300
+ conductive = 0
+ conductivity = 1.5
+ hardness = 90
+ shard_type = SHARD_SHARD
+ weight = 30
+ negation = 25
+ explosion_resistance = 85
+ reflectivity = 0.2
+ radiation_resistance = 10
+ stack_origin_tech = list(TECH_MATERIAL = 8, TECH_ILLEGAL = 1, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_ARCANE = 1)
+ supply_conversion_value = 13
+
+
diff --git a/code/modules/materials/materials/glass.dm b/code/modules/materials/materials/glass.dm
new file mode 100644
index 0000000000..7953542278
--- /dev/null
+++ b/code/modules/materials/materials/glass.dm
@@ -0,0 +1,143 @@
+/datum/material/glass
+ name = "glass"
+ stack_type = /obj/item/stack/material/glass
+ flags = MATERIAL_BRITTLE
+ icon_colour = "#00E1FF"
+ opacity = 0.3
+ integrity = 100
+ shard_type = SHARD_SHARD
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ hardness = 30
+ weight = 15
+ protectiveness = 0 // 0%
+ conductive = 0
+ conductivity = 1 // Glass shards don't conduct.
+ door_icon_base = "stone"
+ destruction_desc = "shatters"
+ window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 2)
+ created_window = /obj/structure/window/basic
+ created_fulltile_window = /obj/structure/window/basic/full
+ rod_product = /obj/item/stack/material/glass/reinforced
+
+/datum/material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
+
+ if(!user || !used_stack || !created_window || !created_fulltile_window || !window_options.len)
+ return 0
+
+ if(!user.IsAdvancedToolUser())
+ to_chat(user, "This task is too complex for your clumsy hands.")
+ return 1
+
+ var/turf/T = user.loc
+ if(!istype(T))
+ to_chat(user, "You must be standing on open flooring to build a window.")
+ return 1
+
+ var/title = "Sheet-[used_stack.name] ([used_stack.get_amount()] sheet\s left)"
+ var/choice = input(title, "What would you like to construct?") as null|anything in window_options
+
+ if(!choice || !used_stack || !user || used_stack.loc != user || user.stat || user.loc != T)
+ return 1
+
+ // Get data for building windows here.
+ var/list/possible_directions = cardinal.Copy()
+ var/window_count = 0
+ for (var/obj/structure/window/check_window in user.loc)
+ window_count++
+ possible_directions -= check_window.dir
+ for (var/obj/structure/windoor_assembly/check_assembly in user.loc)
+ window_count++
+ possible_directions -= check_assembly.dir
+ for (var/obj/machinery/door/window/check_windoor in user.loc)
+ window_count++
+ possible_directions -= check_windoor.dir
+
+ // Get the closest available dir to the user's current facing.
+ var/build_dir = SOUTHWEST //Default to southwest for fulltile windows.
+ var/failed_to_build
+
+ if(window_count >= 4)
+ failed_to_build = 1
+ else
+ if(choice in list("One Direction","Windoor"))
+ if(possible_directions.len)
+ for(var/direction in list(user.dir, turn(user.dir,90), turn(user.dir,270), turn(user.dir,180)))
+ if(direction in possible_directions)
+ build_dir = direction
+ break
+ else
+ failed_to_build = 1
+ if(failed_to_build)
+ to_chat(user, "There is no room in this location.")
+ return 1
+
+ var/build_path = /obj/structure/windoor_assembly
+ var/sheets_needed = window_options[choice]
+ if(choice == "Windoor")
+ if(is_reinforced())
+ build_path = /obj/structure/windoor_assembly/secure
+ else if(choice == "Full Window")
+ build_path = created_fulltile_window
+ else
+ build_path = created_window
+
+ if(used_stack.get_amount() < sheets_needed)
+ to_chat(user, "You need at least [sheets_needed] sheets to build this.")
+ return 1
+
+ // Build the structure and update sheet count etc.
+ used_stack.use(sheets_needed)
+ new build_path(T, build_dir, 1)
+ return 1
+
+/datum/material/glass/proc/is_reinforced()
+ return (hardness > 35) //todo
+
+/datum/material/glass/reinforced
+ name = "rglass"
+ display_name = "reinforced glass"
+ stack_type = /obj/item/stack/material/glass/reinforced
+ flags = MATERIAL_BRITTLE
+ icon_colour = "#00E1FF"
+ opacity = 0.3
+ integrity = 100
+ shard_type = SHARD_SHARD
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ hardness = 40
+ weight = 30
+ stack_origin_tech = list(TECH_MATERIAL = 2)
+ composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2, "glass" = SHEET_MATERIAL_AMOUNT)
+ window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 2)
+ created_window = /obj/structure/window/reinforced
+ created_fulltile_window = /obj/structure/window/reinforced/full
+ wire_product = null
+ rod_product = null
+
+/datum/material/glass/phoron
+ name = "borosilicate glass"
+ display_name = "borosilicate glass"
+ stack_type = /obj/item/stack/material/glass/phoronglass
+ flags = MATERIAL_BRITTLE
+ integrity = 100
+ icon_colour = "#FC2BC5"
+ stack_origin_tech = list(TECH_MATERIAL = 4)
+ window_options = list("One Direction" = 1, "Full Window" = 4)
+ created_window = /obj/structure/window/phoronbasic
+ created_fulltile_window = /obj/structure/window/phoronbasic/full
+ wire_product = null
+ rod_product = /obj/item/stack/material/glass/phoronrglass
+
+/datum/material/glass/phoron/reinforced
+ name = "reinforced borosilicate glass"
+ display_name = "reinforced borosilicate glass"
+ stack_type = /obj/item/stack/material/glass/phoronrglass
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ composite_material = list() //todo
+ window_options = list("One Direction" = 1, "Full Window" = 4)
+ created_window = /obj/structure/window/phoronreinforced
+ created_fulltile_window = /obj/structure/window/phoronreinforced/full
+ hardness = 40
+ weight = 30
+ stack_origin_tech = list(TECH_MATERIAL = 2)
+ composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2, "borosilicate glass" = SHEET_MATERIAL_AMOUNT)
+ rod_product = null
diff --git a/code/modules/materials/materials/glass_vr.dm b/code/modules/materials/materials/glass_vr.dm
new file mode 100644
index 0000000000..9d7cd81879
--- /dev/null
+++ b/code/modules/materials/materials/glass_vr.dm
@@ -0,0 +1,33 @@
+/datum/material/glass/titaniumglass
+ name = MAT_TITANIUMGLASS
+ display_name = "titanium glass"
+ stack_type = /obj/item/stack/material/glass/titanium
+ integrity = 150
+ hardness = 50
+ weight = 50
+ flags = MATERIAL_BRITTLE
+ icon_colour = "#A7A3A6"
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ window_options = list("One Direction" = 1, "Full Window" = 4)
+ created_window = /obj/structure/window/titanium
+ created_fulltile_window = /obj/structure/window/titanium/full
+ wire_product = null
+ rod_product = /obj/item/stack/material/glass/titanium
+ composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT)
+
+/datum/material/glass/plastaniumglass
+ name = MAT_PLASTITANIUMGLASS
+ display_name = "plas-titanium glass"
+ stack_type = /obj/item/stack/material/glass/plastitanium
+ integrity = 200
+ hardness = 60
+ weight = 80
+ flags = MATERIAL_BRITTLE
+ icon_colour = "#676366"
+ stack_origin_tech = list(TECH_MATERIAL = 6)
+ window_options = list("One Direction" = 1, "Full Window" = 4)
+ created_window = /obj/structure/window/plastitanium
+ created_fulltile_window = /obj/structure/window/plastitanium/full
+ wire_product = null
+ rod_product = /obj/item/stack/material/glass/plastitanium
+ composite_material = list(MAT_PLASTITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT)
diff --git a/code/modules/materials/materials/holographic.dm b/code/modules/materials/materials/holographic.dm
new file mode 100644
index 0000000000..ff6474ec1e
--- /dev/null
+++ b/code/modules/materials/materials/holographic.dm
@@ -0,0 +1,17 @@
+/datum/material/steel/holographic
+ name = "holo" + DEFAULT_WALL_MATERIAL
+ display_name = DEFAULT_WALL_MATERIAL
+ stack_type = null
+ shard_type = SHARD_NONE
+
+/datum/material/plastic/holographic
+ name = "holoplastic"
+ display_name = "plastic"
+ stack_type = null
+ shard_type = SHARD_NONE
+
+/datum/material/wood/holographic
+ name = "holowood"
+ display_name = "wood"
+ stack_type = null
+ shard_type = SHARD_NONE
\ No newline at end of file
diff --git a/code/modules/materials/materials/metals/hull.dm b/code/modules/materials/materials/metals/hull.dm
new file mode 100644
index 0000000000..caf8f13de7
--- /dev/null
+++ b/code/modules/materials/materials/metals/hull.dm
@@ -0,0 +1,53 @@
+/datum/material/steel/hull
+ name = MAT_STEELHULL
+ stack_type = /obj/item/stack/material/steel/hull
+ integrity = 250
+ explosion_resistance = 10
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "#666677"
+
+/datum/material/steel/hull/place_sheet(var/turf/target) //Deconstructed into normal steel sheets.
+ new /obj/item/stack/material/steel(target)
+
+/datum/material/plasteel/hull
+ name = MAT_PLASTEELHULL
+ stack_type = /obj/item/stack/material/plasteel/hull
+ integrity = 600
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "#777788"
+ explosion_resistance = 40
+
+/datum/material/plasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
+ new /obj/item/stack/material/plasteel(target)
+
+/datum/material/durasteel/hull //The 'Hardball' of starship hulls.
+ name = MAT_DURASTEELHULL
+ stack_type = /obj/item/stack/material/durasteel/hull
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "#45829a"
+ explosion_resistance = 90
+ reflectivity = 0.9
+
+/datum/material/durasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal durasteel sheets.
+ new /obj/item/stack/material/durasteel(target)
+
+/datum/material/titanium/hull
+ name = MAT_TITANIUMHULL
+ stack_type = /obj/item/stack/material/titanium/hull
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+
+/datum/material/titanium/hull/place_sheet(var/turf/target) //Deconstructed into normal titanium sheets.
+ new /obj/item/stack/material/titanium(target)
+
+/datum/material/morphium/hull
+ name = MAT_MORPHIUMHULL
+ stack_type = /obj/item/stack/material/morphium/hull
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+
+/datum/material/morphium/hull/place_sheet(var/turf/target)
+ new /obj/item/stack/material/morphium(target)
\ No newline at end of file
diff --git a/code/modules/materials/materials/metals/hull_vr.dm b/code/modules/materials/materials/metals/hull_vr.dm
new file mode 100644
index 0000000000..3c35b3cf39
--- /dev/null
+++ b/code/modules/materials/materials/metals/hull_vr.dm
@@ -0,0 +1,20 @@
+/datum/material/plastitanium/hull
+ name = MAT_PLASTITANIUMHULL
+ stack_type = /obj/item/stack/material/plastitanium/hull
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "#585658"
+ explosion_resistance = 50
+
+/datum/material/plastitanium/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
+ new /obj/item/stack/material/plastitanium(target)
+
+/datum/material/gold/hull
+ name = MAT_GOLDHULL
+ stack_type = /obj/item/stack/material/gold/hull
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+ explosion_resistance = 50
+
+/datum/material/gold/hull/place_sheet(var/turf/target) //Deconstructed into normal gold sheets.
+ new /obj/item/stack/material/gold(target)
diff --git a/code/modules/materials/materials/metals/metals.dm b/code/modules/materials/materials/metals/metals.dm
new file mode 100644
index 0000000000..a36ffef5c1
--- /dev/null
+++ b/code/modules/materials/materials/metals/metals.dm
@@ -0,0 +1,199 @@
+
+
+
+
+// Very rare alloy that is reflective, should be used sparingly.
+/datum/material/durasteel
+ name = "durasteel"
+ stack_type = /obj/item/stack/material/durasteel
+ integrity = 600
+ melting_point = 7000
+ icon_base = "metal"
+ icon_reinf = "reinf_metal"
+ icon_colour = "#6EA7BE"
+ explosion_resistance = 75
+ hardness = 100
+ weight = 28
+ protectiveness = 60 // 75%
+ reflectivity = 0.7 // Not a perfect mirror, but close.
+ stack_origin_tech = list(TECH_MATERIAL = 8)
+ composite_material = list("plasteel" = SHEET_MATERIAL_AMOUNT, "diamond" = SHEET_MATERIAL_AMOUNT) //shrug
+ supply_conversion_value = 9
+
+/datum/material/titanium
+ name = MAT_TITANIUM
+ stack_type = /obj/item/stack/material/titanium
+ conductivity = 2.38
+ icon_base = "metal"
+ door_icon_base = "metal"
+ icon_colour = "#D1E6E3"
+ icon_reinf = "reinf_metal"
+ composite_material = null
+
+/datum/material/iron
+ name = "iron"
+ stack_type = /obj/item/stack/material/iron
+ icon_colour = "#5C5454"
+ weight = 22
+ conductivity = 10
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+
+/datum/material/lead
+ name = MAT_LEAD
+ stack_type = /obj/item/stack/material/lead
+ icon_colour = "#273956"
+ weight = 23 // Lead is a bit more dense than silver IRL, and silver has 22 ingame.
+ conductivity = 10
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ radiation_resistance = 25 // Lead is Special and so gets to block more radiation than it normally would with just weight, totalling in 48 protection.
+ supply_conversion_value = 2
+
+/datum/material/gold
+ name = "gold"
+ stack_type = /obj/item/stack/material/gold
+ icon_colour = "#EDD12F"
+ weight = 24
+ hardness = 40
+ conductivity = 41
+ stack_origin_tech = list(TECH_MATERIAL = 4)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 2
+
+/datum/material/silver
+ name = "silver"
+ stack_type = /obj/item/stack/material/silver
+ icon_colour = "#D1E6E3"
+ weight = 22
+ hardness = 50
+ conductivity = 63
+ stack_origin_tech = list(TECH_MATERIAL = 3)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 2
+
+/datum/material/platinum
+ name = "platinum"
+ stack_type = /obj/item/stack/material/platinum
+ icon_colour = "#9999FF"
+ weight = 27
+ conductivity = 9.43
+ stack_origin_tech = list(TECH_MATERIAL = 2)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 5
+
+/datum/material/uranium
+ name = "uranium"
+ stack_type = /obj/item/stack/material/uranium
+ radioactivity = 12
+ icon_base = "stone"
+ icon_reinf = "reinf_stone"
+ icon_colour = "#007A00"
+ weight = 22
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ door_icon_base = "stone"
+ supply_conversion_value = 2
+
+/datum/material/mhydrogen
+ name = "mhydrogen"
+ stack_type = /obj/item/stack/material/mhydrogen
+ icon_colour = "#E6C5DE"
+ stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 6, TECH_MAGNET = 5)
+ conductivity = 100
+ is_fusion_fuel = 1
+ supply_conversion_value = 6
+
+/datum/material/deuterium
+ name = "deuterium"
+ stack_type = /obj/item/stack/material/deuterium
+ icon_colour = "#999999"
+ stack_origin_tech = list(TECH_MATERIAL = 3)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ is_fusion_fuel = 1
+ conductive = 0
+
+/datum/material/tritium
+ name = "tritium"
+ stack_type = /obj/item/stack/material/tritium
+ icon_colour = "#777777"
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ is_fusion_fuel = 1
+ conductive = 0
+
+/datum/material/osmium
+ name = "osmium"
+ stack_type = /obj/item/stack/material/osmium
+ icon_colour = "#9999FF"
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ conductivity = 100
+ supply_conversion_value = 6
+
+/datum/material/graphite
+ name = MAT_GRAPHITE
+ stack_type = /obj/item/stack/material/graphite
+ flags = MATERIAL_BRITTLE
+ icon_base = "solid"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "#333333"
+ hardness = 75
+ weight = 15
+ integrity = 175
+ protectiveness = 15
+ conductivity = 18
+ melting_point = T0C+3600
+ radiation_resistance = 15
+ stack_origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2)
+
+/datum/material/bronze
+ name = "bronze"
+ stack_type = /obj/item/stack/material/bronze
+ icon_colour = "#EDD12F"
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ integrity = 120
+ conductivity = 12
+ protectiveness = 9 // 33%
+
+/datum/material/tin
+ name = "tin"
+ display_name = "tin"
+ use_name = "tin"
+ stack_type = /obj/item/stack/material/tin
+ icon_colour = "#b2afaf"
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 1
+ hardness = 50
+ weight = 13
+
+/datum/material/copper
+ name = "copper"
+ display_name = "copper"
+ use_name = "copper"
+ stack_type = /obj/item/stack/material/copper
+ conductivity = 52
+ icon_colour = "#af633e"
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 1
+ weight = 13
+ hardness = 50
+
+/datum/material/aluminium
+ name = "aluminium"
+ display_name = "aluminium"
+ use_name = "aluminium"
+ icon_colour = "#e5e2d0"
+ stack_type = /obj/item/stack/material/aluminium
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 2
+ weight = 10
\ No newline at end of file
diff --git a/code/modules/materials/materials/metals/metals_vr.dm b/code/modules/materials/materials/metals/metals_vr.dm
new file mode 100644
index 0000000000..f600b2fe02
--- /dev/null
+++ b/code/modules/materials/materials/metals/metals_vr.dm
@@ -0,0 +1,6 @@
+/datum/material/durasteel/generate_recipes()
+ . = ..()
+ recipes += list(
+ new /datum/stack_recipe("durasteel fishing rod", /obj/item/weapon/material/fishing_rod/modern/strong, 2),
+ new /datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 30),
+ )
diff --git a/code/modules/materials/materials/metals/plasteel.dm b/code/modules/materials/materials/metals/plasteel.dm
new file mode 100644
index 0000000000..6fc7ed29de
--- /dev/null
+++ b/code/modules/materials/materials/metals/plasteel.dm
@@ -0,0 +1,27 @@
+/datum/material/plasteel
+ name = "plasteel"
+ stack_type = /obj/item/stack/material/plasteel
+ integrity = 400
+ melting_point = 6000
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#777777"
+ explosion_resistance = 25
+ hardness = 80
+ weight = 23
+ protectiveness = 20 // 50%
+ conductivity = 13 // For the purposes of balance.
+ stack_origin_tech = list(TECH_MATERIAL = 2)
+ composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT, "platinum" = SHEET_MATERIAL_AMOUNT) //todo
+ supply_conversion_value = 6
+
+/datum/material/plasteel/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("Metal crate", /obj/structure/closet/crate, 10, time = 50, one_per_turf = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("knife grip", /obj/item/weapon/material/butterflyhandle, 4, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("dark floor tile", /obj/item/stack/tile/floor/dark, 1, 4, 20, recycle_material = "[name]"),
+ new /datum/stack_recipe("roller bed", /obj/item/roller, 5, time = 30, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 10, recycle_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/metals/plasteel_vr.dm b/code/modules/materials/materials/metals/plasteel_vr.dm
new file mode 100644
index 0000000000..bca3fdf27b
--- /dev/null
+++ b/code/modules/materials/materials/metals/plasteel_vr.dm
@@ -0,0 +1,22 @@
+/datum/material/plastitanium
+ name = MAT_PLASTITANIUM
+ stack_type = /obj/item/stack/material/plastitanium
+ integrity = 600
+ melting_point = 9000
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#585658"
+ explosion_resistance = 35
+ hardness = 90
+ weight = 40
+ protectiveness = 30
+ conductivity = 7
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, MAT_PLASTEEL = SHEET_MATERIAL_AMOUNT)
+ supply_conversion_value = 8
+
+/datum/material/plastitanium/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 20),
+ )
diff --git a/code/modules/materials/materials/metals/steel.dm b/code/modules/materials/materials/metals/steel.dm
new file mode 100644
index 0000000000..ca323c8137
--- /dev/null
+++ b/code/modules/materials/materials/metals/steel.dm
@@ -0,0 +1,87 @@
+/datum/material/steel
+ name = DEFAULT_WALL_MATERIAL
+ stack_type = /obj/item/stack/material/steel
+ integrity = 150
+ conductivity = 11 // Assuming this is carbon steel, it would actually be slightly less conductive than iron, but lets ignore that.
+ protectiveness = 10 // 33%
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#666666"
+
+/datum/material/steel/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe_list("office chairs",list(
+ new /datum/stack_recipe("dark office chair", /obj/structure/bed/chair/office/dark, 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("light office chair", /obj/structure/bed/chair/office/light, 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
+ )),
+ new /datum/stack_recipe_list("comfy chairs", list(
+ new /datum/stack_recipe("beige comfy chair", /obj/structure/bed/chair/comfy/beige, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("black comfy chair", /obj/structure/bed/chair/comfy/black, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("brown comfy chair", /obj/structure/bed/chair/comfy/brown, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("lime comfy chair", /obj/structure/bed/chair/comfy/lime, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("teal comfy chair", /obj/structure/bed/chair/comfy/teal, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("red comfy chair", /obj/structure/bed/chair/comfy/red, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("blue comfy chair", /obj/structure/bed/chair/comfy/blue, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("purple comfy chair", /obj/structure/bed/chair/comfy/purp, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("green comfy chair", /obj/structure/bed/chair/comfy/green, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("yellow comfy chair", /obj/structure/bed/chair/comfy/yellow, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("orange comfy chair", /obj/structure/bed/chair/comfy/orange, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ )),
+ new /datum/stack_recipe_list("airlock assemblies", list(
+ new /datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("eng atmos airlock assembly", /obj/structure/door_assembly/door_assembly_eat, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("voidcraft airlock assembly horizontal", /obj/structure/door_assembly/door_assembly_voidcraft, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("voidcraft airlock assembly vertical", /obj/structure/door_assembly/door_assembly_voidcraft/vertical, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("emergency shutter", /obj/structure/firedoor_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("multi-tile airlock assembly", /obj/structure/door_assembly/multi_tile, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ )),
+ new /datum/stack_recipe_list("modular computer frames", list(
+ new /datum/stack_recipe("modular console frame", /obj/item/modular_computer/console, 20, recycle_material = "[name]"),\
+ new /datum/stack_recipe("modular telescreen frame", /obj/item/modular_computer/telescreen, 10, recycle_material = "[name]"),\
+ new /datum/stack_recipe("modular laptop frame", /obj/item/modular_computer/laptop, 10, recycle_material = "[name]"),\
+ new /datum/stack_recipe("modular tablet frame", /obj/item/modular_computer/tablet, 5, recycle_material = "[name]"),\
+ )),
+ new /datum/stack_recipe_list("filing cabinets", list(
+ new /datum/stack_recipe("filing cabinet", /obj/structure/filingcabinet, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("tall filing cabinet", /obj/structure/filingcabinet/filingcabinet, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("chest drawer", /obj/structure/filingcabinet/chestdrawer, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ )),
+ new /datum/stack_recipe("table frame", /obj/structure/table, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("bench frame", /obj/structure/table/bench, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("rack", /obj/structure/table/rack, 1, time = 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("cannon frame", /obj/item/weapon/cannonframe, 10, time = 15, one_per_turf = 0, on_floor = 0, recycle_material = "[name]"),
+ new /datum/stack_recipe("regular floor tile", /obj/item/stack/tile/floor, 1, 4, 20, recycle_material = "[name]"),
+ new /datum/stack_recipe("roofing tile", /obj/item/stack/tile/roofing, 3, 4, 20, recycle_material = "[name]"),
+ new /datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60, recycle_material = "[name]"),
+ new /datum/stack_recipe("frame", /obj/item/frame, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("mirror frame", /obj/item/frame/mirror, 1, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("fire extinguisher cabinet frame", /obj/item/frame/extinguisher_cabinet, 4, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("railing", /obj/structure/railing, 2, time = 50, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ //new /datum/stack_recipe("IV drip", /obj/machinery/iv_drip, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), //VOREStation Removal
+ new /datum/stack_recipe("medical stand", /obj/structure/medical_stand, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), //VOREStation Replacement,
+ new /datum/stack_recipe("conveyor switch", /obj/machinery/conveyor_switch, 2, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade, recycle_material = "[name]"),
+ new /datum/stack_recipe("light fixture frame", /obj/item/frame/light, 2, recycle_material = "[name]"),
+ new /datum/stack_recipe("small light fixture frame", /obj/item/frame/light/small, 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("floor lamp fixture frame", /obj/machinery/light_construct/flamp, 2, recycle_material = "[name]"),
+ new /datum/stack_recipe("apc frame", /obj/item/frame/apc, 2, recycle_material = "[name]"),
+ new /datum/stack_recipe("desk bell", /obj/item/weapon/deskbell, 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("tanning rack", /obj/structure/tanning_rack, 3, one_per_turf = TRUE, time = 20, on_floor = TRUE, supplied_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/metals/steel_vr.dm b/code/modules/materials/materials/metals/steel_vr.dm
new file mode 100644
index 0000000000..b112f36217
--- /dev/null
+++ b/code/modules/materials/materials/metals/steel_vr.dm
@@ -0,0 +1,82 @@
+/datum/material/steel/generate_recipes()
+ . = ..()
+ recipes += list(
+ new /datum/stack_recipe_list("mounted chairs",list(
+ new /datum/stack_recipe("mounted chair", /obj/structure/bed/chair/bay/chair, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("red mounted chair", /obj/structure/bed/chair/bay/chair/padded/red, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("brown mounted chair", /obj/structure/bed/chair/bay/chair/padded/brown, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("teal mounted chair", /obj/structure/bed/chair/bay/chair/padded/teal, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("black mounted chair", /obj/structure/bed/chair/bay/chair/padded/black, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("green mounted chair", /obj/structure/bed/chair/bay/chair/padded/green, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("purple mounted chair", /obj/structure/bed/chair/bay/chair/padded/purple, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("blue mounted chair", /obj/structure/bed/chair/bay/chair/padded/blue, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("beige mounted chair", /obj/structure/bed/chair/bay/chair/padded/beige, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("lime mounted chair", /obj/structure/bed/chair/bay/chair/padded/lime, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("yellow mounted chair", /obj/structure/bed/chair/bay/chair/padded/yellow, 2, one_per_turf = 1, on_floor = 1, time = 10)
+ )),
+ new /datum/stack_recipe_list("mounted comfy chairs",list(
+ new /datum/stack_recipe("mounted comfy chair", /obj/structure/bed/chair/bay/comfy, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("red mounted comfy chair", /obj/structure/bed/chair/bay/comfy/red, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("brown mounted comfy chair", /obj/structure/bed/chair/bay/comfy/brown, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("teal mounted comfy chair", /obj/structure/bed/chair/bay/comfy/teal, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("black mounted comfy chair", /obj/structure/bed/chair/bay/comfy/black, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("green mounted comfy chair", /obj/structure/bed/chair/bay/comfy/green, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("purple mounted comfy chair", /obj/structure/bed/chair/bay/comfy/purple, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("blue mounted comfy chair", /obj/structure/bed/chair/bay/comfy/blue, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("beige mounted comfy chair", /obj/structure/bed/chair/bay/comfy/beige, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("lime mounted comfy chair", /obj/structure/bed/chair/bay/comfy/lime, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("yellow mounted comfy chair", /obj/structure/bed/chair/bay/comfy/yellow, 3, one_per_turf = 1, on_floor = 1, time = 20)
+ )),
+ new /datum/stack_recipe("mounted captain's chair", /obj/structure/bed/chair/bay/comfy/captain, 4, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("dropship seat", /obj/structure/bed/chair/bay/shuttle, 4, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("small teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/smallnest, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("large teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/bignest, 4, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("dance pole", /obj/structure/dancepole, 2, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("light switch frame", /obj/item/frame/lightswitch, 2),
+ new /datum/stack_recipe_list("sofas",list(
+ new /datum/stack_recipe("red sofa middle", /obj/structure/bed/chair/sofa, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("red sofa left", /obj/structure/bed/chair/sofa/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("red sofa right", /obj/structure/bed/chair/sofa/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("red sofa corner", /obj/structure/bed/chair/sofa/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("brown sofa middle", /obj/structure/bed/chair/sofa/brown, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("brown sofa left", /obj/structure/bed/chair/sofa/brown/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("brown sofa right", /obj/structure/bed/chair/sofa/brown/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("brown sofa corner", /obj/structure/bed/chair/sofa/brown/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("teal sofa middle", /obj/structure/bed/chair/sofa/teal, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("teal sofa left", /obj/structure/bed/chair/sofa/teal/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("teal sofa right", /obj/structure/bed/chair/sofa/teal/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("teal sofa corner", /obj/structure/bed/chair/sofa/teal/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("black sofa middle", /obj/structure/bed/chair/sofa/black, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("black sofa left", /obj/structure/bed/chair/sofa/black/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("black sofa right", /obj/structure/bed/chair/sofa/black/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("black sofa corner", /obj/structure/bed/chair/sofa/black/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("green sofa middle", /obj/structure/bed/chair/sofa/green, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("green sofa left", /obj/structure/bed/chair/sofa/green/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("green sofa right", /obj/structure/bed/chair/sofa/green/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("green sofa corner", /obj/structure/bed/chair/sofa/green/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("purple sofa middle", /obj/structure/bed/chair/sofa/purp, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("purple sofa left", /obj/structure/bed/chair/sofa/purp/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("purple sofa right", /obj/structure/bed/chair/sofa/purp/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("purple sofa corner", /obj/structure/bed/chair/sofa/purp/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("blue sofa middle", /obj/structure/bed/chair/sofa/blue, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("blue sofa left", /obj/structure/bed/chair/sofa/blue/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("blue sofa right", /obj/structure/bed/chair/sofa/blue/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("blue sofa corner", /obj/structure/bed/chair/sofa/blue/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("beige sofa middle", /obj/structure/bed/chair/sofa/beige, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("beige sofa left", /obj/structure/bed/chair/sofa/beige/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("beige sofa right", /obj/structure/bed/chair/sofa/beige/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("beige sofa corner", /obj/structure/bed/chair/sofa/beige/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("lime sofa middle", /obj/structure/bed/chair/sofa/lime, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("lime sofa left", /obj/structure/bed/chair/sofa/lime/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("lime sofa right", /obj/structure/bed/chair/sofa/lime/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("lime sofa corner", /obj/structure/bed/chair/sofa/lime/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("yellow sofa middle", /obj/structure/bed/chair/sofa/yellow, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("yellow sofa left", /obj/structure/bed/chair/sofa/yellow/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("yellow sofa right", /obj/structure/bed/chair/sofa/yellow/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("yellow sofa corner", /obj/structure/bed/chair/sofa/yellow/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("orange sofa middle", /obj/structure/bed/chair/sofa/orange, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("orange sofa left", /obj/structure/bed/chair/sofa/orange/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("orange sofa right", /obj/structure/bed/chair/sofa/orange/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("orange sofa corner", /obj/structure/bed/chair/sofa/orange/corner, 1, one_per_turf = 1, on_floor = 1), \
+ )),
+ )
diff --git a/code/modules/materials/materials/organic/animal_products.dm b/code/modules/materials/materials/organic/animal_products.dm
new file mode 100644
index 0000000000..592cc6bc7b
--- /dev/null
+++ b/code/modules/materials/materials/organic/animal_products.dm
@@ -0,0 +1,28 @@
+/datum/material/diona
+ name = "biomass"
+ icon_colour = null
+ stack_type = null
+ integrity = 600
+ icon_base = "diona"
+ icon_reinf = "noreinf"
+
+/datum/material/diona/place_dismantled_product()
+ return
+
+/datum/material/diona/place_dismantled_girder(var/turf/target)
+ spawn_diona_nymph(target)
+
+/datum/material/chitin
+ name = MAT_CHITIN
+ icon_colour = "#8d6653"
+ stack_type = /obj/item/stack/material/chitin
+ stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4)
+ icon_base = "solid"
+ icon_reinf = "reinf_mesh"
+ integrity = 60
+ weight = 10
+ ignition_point = T0C+400
+ melting_point = T0C+500
+ protectiveness = 20
+ conductive = 0
+ supply_conversion_value = 4
diff --git a/code/modules/materials/materials/organic/cloth.dm b/code/modules/materials/materials/organic/cloth.dm
new file mode 100644
index 0000000000..588a7ad86f
--- /dev/null
+++ b/code/modules/materials/materials/organic/cloth.dm
@@ -0,0 +1,121 @@
+/datum/material/cloth
+ name = "cloth"
+ stack_origin_tech = list(TECH_MATERIAL = 2)
+ door_icon_base = "wood"
+ ignition_point = T0C+232
+ melting_point = T0C+300
+ protectiveness = 1 // 4%
+ flags = MATERIAL_PADDING
+ conductive = 0
+ integrity = 40
+ pass_stack_colors = TRUE
+ supply_conversion_value = 2
+
+/datum/material/cloth/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]"),
+ new /datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("crude bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
+ )
+
+/datum/material/cloth/syncloth
+ name = "syncloth"
+ stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 2)
+ ignition_point = T0C+532
+ melting_point = T0C+600
+ integrity = 200
+ protectiveness = 15 // 4%
+ pass_stack_colors = TRUE
+ supply_conversion_value = 3
+
+/datum/material/cloth/teal
+ name = "teal"
+ display_name ="teal"
+ use_name = "teal cloth"
+ icon_colour = "#00EAFA"
+
+/datum/material/cloth/black
+ name = "black"
+ display_name = "black"
+ use_name = "black cloth"
+ icon_colour = "#505050"
+
+/datum/material/cloth/green
+ name = "green"
+ display_name = "green"
+ use_name = "green cloth"
+ icon_colour = "#01C608"
+
+/datum/material/cloth/puple
+ name = "purple"
+ display_name = "purple"
+ use_name = "purple cloth"
+ icon_colour = "#9C56C4"
+
+/datum/material/cloth/blue
+ name = "blue"
+ display_name = "blue"
+ use_name = "blue cloth"
+ icon_colour = "#6B6FE3"
+
+/datum/material/cloth/beige
+ name = "beige"
+ display_name = "beige"
+ use_name = "beige cloth"
+ icon_colour = "#E8E7C8"
+
+/datum/material/cloth/lime
+ name = "lime"
+ display_name = "lime"
+ use_name = "lime cloth"
+ icon_colour = "#62E36C"
+
+/datum/material/cloth/yellow
+ name = "yellow"
+ display_name = "yellow"
+ use_name = "yellow cloth"
+ icon_colour = "#EEF573"
+
+/datum/material/cloth/orange
+ name = "orange"
+ display_name = "orange"
+ use_name = "orange cloth"
+ icon_colour = "#E3BF49"
+
+
+
+/datum/material/carpet
+ name = "carpet"
+ display_name = "comfy"
+ use_name = "red upholstery"
+ icon_colour = "#DA020A"
+ flags = MATERIAL_PADDING
+ ignition_point = T0C+232
+ melting_point = T0C+300
+ sheet_singular_name = "tile"
+ sheet_plural_name = "tiles"
+ protectiveness = 1 // 4%
+ conductive = 0
+
+/datum/material/cotton
+ name = "cotton"
+ display_name ="cotton"
+ icon_colour = "#FFFFFF"
+ flags = MATERIAL_PADDING
+ ignition_point = T0C+232
+ melting_point = T0C+300
+ protectiveness = 1 // 4%
+ conductive = 0
\ No newline at end of file
diff --git a/code/modules/materials/materials/organic/leather.dm b/code/modules/materials/materials/organic/leather.dm
new file mode 100644
index 0000000000..f5fc8cb2f9
--- /dev/null
+++ b/code/modules/materials/materials/organic/leather.dm
@@ -0,0 +1,37 @@
+/datum/material/leather
+ name = MAT_LEATHER
+ display_name = "plainleather"
+ icon_colour = "#5C4831"
+ stack_type = /obj/item/stack/material/leather
+ stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
+ flags = MATERIAL_PADDING
+ ignition_point = T0C+300
+ melting_point = T0C+300
+ protectiveness = 3 // 13%
+ conductive = 0
+ integrity = 40
+ supply_conversion_value = 3
+
+/datum/material/leather/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]"),
+ new /datum/stack_recipe("whip", /obj/item/weapon/material/whip, 5, time = 15 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/organic/resin.dm b/code/modules/materials/materials/organic/resin.dm
new file mode 100644
index 0000000000..a42735627a
--- /dev/null
+++ b/code/modules/materials/materials/organic/resin.dm
@@ -0,0 +1,45 @@
+/datum/material/resin
+ name = "resin"
+ icon_colour = "#35343a"
+ icon_base = "resin"
+ dooropen_noise = 'sound/effects/attackblob.ogg'
+ door_icon_base = "resin"
+ icon_reinf = "reinf_mesh"
+ melting_point = T0C+300
+ sheet_singular_name = "blob"
+ sheet_plural_name = "blobs"
+ conductive = 0
+ explosion_resistance = 60
+ radiation_resistance = 10
+ stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_BIO = 7)
+ stack_type = /obj/item/stack/material/resin
+
+/datum/material/resin/can_open_material_door(var/mob/living/user)
+ var/mob/living/carbon/M = user
+ if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs)
+ return TRUE
+ return FALSE
+
+/datum/material/resin/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L)
+ var/mob/living/carbon/M = L
+ if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs)
+ to_chat(M, "\The [W] shudders under your touch, starting to become porous.")
+ playsound(W, 'sound/effects/attackblob.ogg', 50, 1)
+ if(do_after(L, 5 SECONDS))
+ spawn(2)
+ playsound(W, 'sound/effects/attackblob.ogg', 100, 1)
+ W.dismantle_wall()
+ return TRUE
+ return FALSE
+
+/datum/material/resin/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("[display_name] door", /obj/structure/simple_door/resin, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] barricade", /obj/effect/alien/resin/wall, 5, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("[display_name] nest", /obj/structure/bed/nest, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] wall girders", /obj/structure/girder/resin, 2, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] membrane", /obj/effect/alien/resin/membrane, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("[display_name] node", /obj/effect/alien/weeds/node, 1, time = 4 SECONDS, recycle_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/organic/wood.dm b/code/modules/materials/materials/organic/wood.dm
new file mode 100644
index 0000000000..ecdad547ca
--- /dev/null
+++ b/code/modules/materials/materials/organic/wood.dm
@@ -0,0 +1,84 @@
+/datum/material/wood
+ name = MAT_WOOD
+ stack_type = /obj/item/stack/material/wood
+ icon_colour = "#9c5930"
+ integrity = 50
+ icon_base = "wood"
+ explosion_resistance = 2
+ shard_type = SHARD_SPLINTER
+ shard_can_repair = 0 // you can't weld splinters back into planks
+ hardness = 15
+ weight = 18
+ protectiveness = 8 // 28%
+ conductive = 0
+ conductivity = 1
+ melting_point = T0C+300 //okay, not melting in this case, but hot enough to destroy wood
+ ignition_point = T0C+288
+ stack_origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1)
+ dooropen_noise = 'sound/effects/doorcreaky.ogg'
+ door_icon_base = "wood"
+ destruction_desc = "splinters"
+ sheet_singular_name = "plank"
+ sheet_plural_name = "planks"
+
+/datum/material/wood/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("oar", /obj/item/weapon/oar, 2, time = 30, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("boat", /obj/vehicle/boat, 20, time = 10 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("dragon boat", /obj/vehicle/boat/dragon, 50, time = 30 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wood circlet", /obj/item/clothing/head/woodcirclet, 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("clipboard", /obj/item/weapon/clipboard, 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wooden chair", /obj/structure/bed/chair/wood, 3, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("crossbow frame", /obj/item/weapon/crossbowframe, 5, time = 25, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("beehive assembly", /obj/item/beehive_assembly, 4, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("beehive frame", /obj/item/honey_frame, 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("book shelf", /obj/structure/bookcase, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("noticeboard frame", /obj/item/frame/noticeboard, 4, time = 5, one_per_turf = 0, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wooden bucket", /obj/item/weapon/reagent_containers/glass/bucket/wood, 2, time = 4, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("coilgun stock", /obj/item/weapon/coilgun_assembly, 5, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("crude fishing rod", /obj/item/weapon/material/fishing_rod/built, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wooden standup figure", /obj/structure/barricade/cutout, 5, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), //VOREStation Add
+ new /datum/stack_recipe("noticeboard", /obj/structure/noticeboard, 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("tanning rack", /obj/structure/tanning_rack, 3, one_per_turf = TRUE, time = 20, on_floor = TRUE, supplied_material = "[name]")
+ )
+
+/datum/material/wood/sif
+ name = MAT_SIFWOOD
+ stack_type = /obj/item/stack/material/wood/sif
+ icon_colour = "#0099cc" // Cyan-ish
+ stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) // Alien wood would presumably be more interesting to the analyzer.
+
+/datum/material/wood/sif/generate_recipes()
+ ..()
+ recipes += new /datum/stack_recipe("alien wood floor tile", /obj/item/stack/tile/wood/sif, 1, 4, 20, pass_stack_color = TRUE)
+ for(var/datum/stack_recipe/r_recipe in recipes)
+ if(r_recipe.title == "wood floor tile")
+ recipes -= r_recipe
+ continue
+ if(r_recipe.title == "wooden chair")
+ recipes -= r_recipe
+ continue
+
+/datum/material/wood/log
+ name = MAT_LOG
+ icon_base = "log"
+ stack_type = /obj/item/stack/material/log
+ sheet_singular_name = null
+ sheet_plural_name = "pile"
+ pass_stack_colors = TRUE
+ supply_conversion_value = 1
+
+/datum/material/wood/log/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("bonfire", /obj/structure/bonfire, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE, recycle_material = "[name]")
+ )
+
+/datum/material/wood/log/sif
+ name = MAT_SIFLOG
+ icon_colour = "#0099cc" // Cyan-ish
+ stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
+ stack_type = /obj/item/stack/material/log/sif
\ No newline at end of file
diff --git a/code/modules/materials/materials/other_vr.dm b/code/modules/materials/materials/other_vr.dm
new file mode 100644
index 0000000000..d54dd4f726
--- /dev/null
+++ b/code/modules/materials/materials/other_vr.dm
@@ -0,0 +1,32 @@
+/datum/material/flesh
+ name = "flesh"
+ display_name = "chunk of flesh"
+ icon_colour = "#dd90aa"
+ sheet_singular_name = "meat"
+ sheet_plural_name = "meats"
+ integrity = 1200
+ melting_point = 6000
+ explosion_resistance = 200
+ hardness = 500
+ weight = 500
+
+/datum/material/fluff //This is to allow for 2 handed weapons that don't want to have a prefix.
+ name = " "
+ display_name = ""
+ icon_colour = "#000000"
+ sheet_singular_name = "fluff"
+ sheet_plural_name = "fluffs"
+ hardness = 60
+ weight = 20 //Strong as iron.
+
+/datum/material/darkglass
+ name = "darkglass"
+ display_name = "darkglass"
+ icon_base = "darkglass"
+ icon_colour = "#FFFFFF"
+
+/datum/material/fancyblack
+ name = "fancyblack"
+ display_name = "fancyblack"
+ icon_base = "fancyblack"
+ icon_colour = "#FFFFFF"
diff --git a/code/modules/materials/materials/plastic.dm b/code/modules/materials/materials/plastic.dm
new file mode 100644
index 0000000000..6cf45fe677
--- /dev/null
+++ b/code/modules/materials/materials/plastic.dm
@@ -0,0 +1,88 @@
+/datum/material/plastic
+ name = "plastic"
+ stack_type = /obj/item/stack/material/plastic
+ flags = MATERIAL_BRITTLE
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#CCCCCC"
+ hardness = 10
+ weight = 12
+ protectiveness = 5 // 20%
+ conductive = 0
+ conductivity = 2 // For the sake of material armor diversity, we're gonna pretend this plastic is a good insulator.
+ melting_point = T0C+371 //assuming heat resistant plastic
+ stack_origin_tech = list(TECH_MATERIAL = 3)
+
+/datum/material/plastic/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("plastic crate", /obj/structure/closet/crate/plastic, 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("plastic bag", /obj/item/weapon/storage/bag/plasticbag, 3, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("blood pack", /obj/item/weapon/reagent_containers/blood/empty, 4, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("reagent dispenser cartridge (large)", /obj/item/weapon/reagent_containers/chem_disp_cartridge, 5, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]"), // 500u
+ new /datum/stack_recipe("reagent dispenser cartridge (med)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/medium, 3, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]"), // 250u
+ new /datum/stack_recipe("reagent dispenser cartridge (small)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/small, 1, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]"), // 100u
+ new /datum/stack_recipe("white floor tile", /obj/item/stack/tile/floor/white, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("freezer floor tile", /obj/item/stack/tile/floor/freezer, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("shower curtain", /obj/structure/curtain, 4, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 4, time = 25, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("water-cooler", /obj/structure/reagent_dispensers/water_cooler, 4, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("lampshade", /obj/item/weapon/lampshade, 1, time = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("plastic net", /obj/item/weapon/material/fishing_net, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("plastic fishtank", /obj/item/glass_jar/fish/plastic, 2, time = 30 SECONDS, recycle_material = "[name]"),
+ new /datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]")
+ )
+
+/datum/material/cardboard
+ name = "cardboard"
+ stack_type = /obj/item/stack/material/cardboard
+ flags = MATERIAL_BRITTLE
+ integrity = 10
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#AAAAAA"
+ hardness = 1
+ weight = 1
+ protectiveness = 0 // 0%
+ conductive = 0
+ ignition_point = T0C+232 //"the temperature at which book-paper catches fire, and burns." close enough
+ melting_point = T0C+232 //temperature at which cardboard walls would be destroyed
+ stack_origin_tech = list(TECH_MATERIAL = 1)
+ door_icon_base = "wood"
+ destruction_desc = "crumples"
+ radiation_resistance = 1
+ pass_stack_colors = TRUE
+
+/datum/material/cardboard/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("box", /obj/item/weapon/storage/box, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("donut box", /obj/item/weapon/storage/box/donut/empty, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("egg box", /obj/item/weapon/storage/fancy/egg_box, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("light tubes box", /obj/item/weapon/storage/box/lights/tubes, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("light bulbs box", /obj/item/weapon/storage/box/lights/bulbs, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("mouse traps box", /obj/item/weapon/storage/box/mousetraps, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("pizza box", /obj/item/pizzabox, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe_list("folders",list(
+ new /datum/stack_recipe("blue folder", /obj/item/weapon/folder/blue, recycle_material = "[name]"),
+ new /datum/stack_recipe("grey folder", /obj/item/weapon/folder, recycle_material = "[name]"),
+ new /datum/stack_recipe("red folder", /obj/item/weapon/folder/red, recycle_material = "[name]"),
+ new /datum/stack_recipe("white folder", /obj/item/weapon/folder/white, recycle_material = "[name]"),
+ new /datum/stack_recipe("yellow folder", /obj/item/weapon/folder/yellow, recycle_material = "[name]")
+ ))
+ )
+
+/datum/material/toy_foam
+ name = "foam"
+ display_name = "foam"
+ use_name = "foam"
+ flags = MATERIAL_PADDING
+ ignition_point = T0C+232
+ melting_point = T0C+300
+ icon_colour = "#ff9900"
+ hardness = 1
+ weight = 1
+ protectiveness = 0 // 0%
+ conductive = 0
\ No newline at end of file
diff --git a/code/modules/materials/materials/snow.dm b/code/modules/materials/materials/snow.dm
new file mode 100644
index 0000000000..bd53579811
--- /dev/null
+++ b/code/modules/materials/materials/snow.dm
@@ -0,0 +1,56 @@
+/datum/material/snow
+ name = MAT_SNOW
+ stack_type = /obj/item/stack/material/snow
+ flags = MATERIAL_BRITTLE
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#FFFFFF"
+ integrity = 1
+ hardness = 1
+ weight = 1
+ protectiveness = 0 // 0%
+ stack_origin_tech = list(TECH_MATERIAL = 1)
+ melting_point = T0C+1
+ destruction_desc = "crumples"
+ sheet_singular_name = "pile"
+ sheet_plural_name = "pile" //Just a bigger pile
+ radiation_resistance = 1
+
+/datum/material/snow/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("snowball", /obj/item/weapon/material/snow/snowball, 1, time = 10, recycle_material = "[name]"),
+ new /datum/stack_recipe("snow brick", /obj/item/stack/material/snowbrick, 2, time = 10, recycle_material = "[name]"),
+ new /datum/stack_recipe("snowman", /obj/structure/snowman, 2, time = 15, recycle_material = "[name]"),
+ new /datum/stack_recipe("snow robot", /obj/structure/snowman/borg, 2, time = 10, recycle_material = "[name]"),
+ new /datum/stack_recipe("snow spider", /obj/structure/snowman/spider, 3, time = 20, recycle_material = "[name]")
+ )
+
+/datum/material/snowbrick //only slightly stronger than snow, used to make igloos mostly
+ name = "packed snow"
+ flags = MATERIAL_BRITTLE
+ stack_type = /obj/item/stack/material/snowbrick
+ icon_base = "stone"
+ icon_reinf = "reinf_stone"
+ icon_colour = "#D8FDFF"
+ integrity = 50
+ weight = 2
+ hardness = 2
+ protectiveness = 0 // 0%
+ stack_origin_tech = list(TECH_MATERIAL = 1)
+ melting_point = T0C+1
+ destruction_desc = "crumbles"
+ sheet_singular_name = "brick"
+ sheet_plural_name = "bricks"
+ radiation_resistance = 1
+
+/datum/material/snowbrick/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/stone.dm b/code/modules/materials/materials/stone.dm
new file mode 100644
index 0000000000..823dd19914
--- /dev/null
+++ b/code/modules/materials/materials/stone.dm
@@ -0,0 +1,35 @@
+/datum/material/stone
+ name = "sandstone"
+ stack_type = /obj/item/stack/material/sandstone
+ icon_base = "stone"
+ icon_reinf = "reinf_stone"
+ icon_colour = "#D9C179"
+ shard_type = SHARD_STONE_PIECE
+ weight = 22
+ hardness = 55
+ protectiveness = 5 // 20%
+ conductive = 0
+ conductivity = 5
+ door_icon_base = "stone"
+ sheet_singular_name = "brick"
+ sheet_plural_name = "bricks"
+
+/datum/material/stone/generate_recipes()
+ ..()
+ recipes += new /datum/stack_recipe("planting bed", /obj/machinery/portable_atmospherics/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
+
+/datum/material/stone/marble
+ name = "marble"
+ icon_colour = "#AAAAAA"
+ weight = 26
+ hardness = 30 //VOREStation Edit - Please.
+ integrity = 201 //hack to stop kitchen benches being flippable, todo: refactor into weight system
+ stack_type = /obj/item/stack/material/marble
+ supply_conversion_value = 2
+
+/datum/material/stone/marble/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("light marble floor tile", /obj/item/stack/tile/wmarble, 1, 4, 20, recycle_material = "[name]"),
+ new /datum/stack_recipe("dark marble floor tile", /obj/item/stack/tile/bmarble, 1, 4, 20, recycle_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/supermatter.dm b/code/modules/materials/materials/supermatter.dm
new file mode 100644
index 0000000000..5ee3b34671
--- /dev/null
+++ b/code/modules/materials/materials/supermatter.dm
@@ -0,0 +1,23 @@
+//R-UST port
+/datum/material/supermatter
+ name = "supermatter"
+ icon_colour = "#FFFF00"
+ stack_type = /obj/item/stack/material/supermatter
+ shard_type = SHARD_SHARD
+ radioactivity = 20
+ stack_type = null
+ luminescence = 3
+ ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE
+ icon_base = "stone"
+ shard_type = SHARD_SHARD
+ hardness = 30
+ door_icon_base = "stone"
+ sheet_singular_name = "crystal"
+ sheet_plural_name = "crystals"
+ is_fusion_fuel = 1
+ stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 5, TECH_BLUESPACE = 4)
+
+/datum/material/supermatter/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("supermatter shard", /obj/machinery/power/supermatter/shard, 30 , one_per_turf = 1, time = 600, on_floor = 1, recycle_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials_vr.dm b/code/modules/materials/materials_vr.dm
deleted file mode 100644
index e66f1ebfa8..0000000000
--- a/code/modules/materials/materials_vr.dm
+++ /dev/null
@@ -1,104 +0,0 @@
-/datum/material/flesh
- name = "flesh"
- display_name = "chunk of flesh"
- icon_colour = "#dd90aa"
- sheet_singular_name = "meat"
- sheet_plural_name = "meats"
- integrity = 1200
- melting_point = 6000
- explosion_resistance = 200
- hardness = 500
- weight = 500
-
-/datum/material/fluff //This is to allow for 2 handed weapons that don't want to have a prefix.
- name = " "
- display_name = ""
- icon_colour = "#000000"
- sheet_singular_name = "fluff"
- sheet_plural_name = "fluffs"
- hardness = 60
- weight = 20 //Strong as iron.
-
-/datum/material/darkglass
- name = "darkglass"
- display_name = "darkglass"
- icon_base = "darkglass"
- icon_colour = "#FFFFFF"
-
-/datum/material/fancyblack
- name = "fancyblack"
- display_name = "fancyblack"
- icon_base = "fancyblack"
- icon_colour = "#FFFFFF"
-
-/datum/material/glass/titaniumglass
- name = MAT_TITANIUMGLASS
- display_name = "titanium glass"
- stack_type = /obj/item/stack/material/glass/titanium
- integrity = 150
- hardness = 50
- weight = 50
- flags = MATERIAL_BRITTLE
- icon_colour = "#A7A3A6"
- stack_origin_tech = list(TECH_MATERIAL = 5)
- window_options = list("One Direction" = 1, "Full Window" = 4)
- created_window = /obj/structure/window/titanium
- created_fulltile_window = /obj/structure/window/titanium/full
- wire_product = null
- rod_product = /obj/item/stack/material/glass/titanium
- composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT)
-
-/datum/material/plastitanium
- name = MAT_PLASTITANIUM
- stack_type = /obj/item/stack/material/plastitanium
- integrity = 600
- melting_point = 9000
- icon_base = "solid"
- icon_reinf = "reinf_over"
- icon_colour = "#585658"
- explosion_resistance = 35
- hardness = 90
- weight = 40
- protectiveness = 30
- conductivity = 7
- stack_origin_tech = list(TECH_MATERIAL = 5)
- composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, MAT_PLASTEEL = SHEET_MATERIAL_AMOUNT)
- supply_conversion_value = 8
-
-/datum/material/plastitanium/hull
- name = MAT_PLASTITANIUMHULL
- stack_type = /obj/item/stack/material/plastitanium/hull
- icon_base = "hull"
- icon_reinf = "reinf_mesh"
- icon_colour = "#585658"
- explosion_resistance = 50
-
-/datum/material/plastitanium/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
- new /obj/item/stack/material/plastitanium(target)
-
-/datum/material/glass/plastaniumglass
- name = MAT_PLASTITANIUMGLASS
- display_name = "plas-titanium glass"
- stack_type = /obj/item/stack/material/glass/plastitanium
- integrity = 200
- hardness = 60
- weight = 80
- flags = MATERIAL_BRITTLE
- icon_colour = "#676366"
- stack_origin_tech = list(TECH_MATERIAL = 6)
- window_options = list("One Direction" = 1, "Full Window" = 4)
- created_window = /obj/structure/window/plastitanium
- created_fulltile_window = /obj/structure/window/plastitanium/full
- wire_product = null
- rod_product = /obj/item/stack/material/glass/plastitanium
- composite_material = list(MAT_PLASTITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT)
-
-/datum/material/gold/hull
- name = MAT_GOLDHULL
- stack_type = /obj/item/stack/material/gold/hull
- icon_base = "hull"
- icon_reinf = "reinf_mesh"
- explosion_resistance = 50
-
-/datum/material/gold/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
- new /obj/item/stack/material/gold(target)
\ No newline at end of file
diff --git a/code/modules/materials/sheets/_sheets.dm b/code/modules/materials/sheets/_sheets.dm
new file mode 100644
index 0000000000..7572d0e654
--- /dev/null
+++ b/code/modules/materials/sheets/_sheets.dm
@@ -0,0 +1,89 @@
+// Stacked resources. They use a material datum for a lot of inherited values.
+// If you're adding something here, make sure to add it to fifty_spawner_mats.dm as well
+/obj/item/stack/material
+ force = 5.0
+ throwforce = 5
+ w_class = ITEMSIZE_NORMAL
+ throw_speed = 3
+ throw_range = 3
+ center_of_mass = null
+ max_amount = 50
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_material.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_material.dmi',
+ )
+
+ var/default_type = DEFAULT_WALL_MATERIAL
+ var/datum/material/material
+ var/perunit = SHEET_MATERIAL_AMOUNT
+ var/apply_colour //temp pending icon rewrite
+ drop_sound = 'sound/items/drop/axe.ogg'
+ pickup_sound = 'sound/items/pickup/axe.ogg'
+
+/obj/item/stack/material/Initialize()
+ . = ..()
+
+ randpixel_xy()
+
+ if(!default_type)
+ default_type = DEFAULT_WALL_MATERIAL
+ material = get_material_by_name("[default_type]")
+ if(!material)
+ return INITIALIZE_HINT_QDEL
+
+ recipes = material.get_recipes()
+ stacktype = material.stack_type
+ if(islist(material.stack_origin_tech))
+ origin_tech = material.stack_origin_tech.Copy()
+
+ if(apply_colour)
+ color = material.icon_colour
+
+ if(!material.conductive)
+ flags |= NOCONDUCT
+
+ matter = material.get_matter()
+ update_strings()
+
+/obj/item/stack/material/get_material()
+ return material
+
+/obj/item/stack/material/proc/update_strings()
+ // Update from material datum.
+ singular_name = material.sheet_singular_name
+
+ if(amount>1)
+ name = "[material.use_name] [material.sheet_plural_name]"
+ desc = "A stack of [material.use_name] [material.sheet_plural_name]."
+ gender = PLURAL
+ else
+ name = "[material.use_name] [material.sheet_singular_name]"
+ desc = "A [material.sheet_singular_name] of [material.use_name]."
+ gender = NEUTER
+
+/obj/item/stack/material/use(var/used)
+ . = ..()
+ update_strings()
+ return
+
+/obj/item/stack/material/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified)
+ var/obj/item/stack/material/M = S
+ if(!istype(M) || material.name != M.material.name)
+ return 0
+ var/transfer = ..(S,tamount,1)
+ if(src) update_strings()
+ if(M) M.update_strings()
+ return transfer
+
+/obj/item/stack/material/attack_self(var/mob/user)
+ if(!material.build_windows(user, src))
+ ..()
+
+/obj/item/stack/material/attackby(var/obj/item/W, var/mob/user)
+ if(istype(W,/obj/item/stack/cable_coil))
+ material.build_wired_product(user, W, src)
+ return
+ else if(istype(W, /obj/item/stack/rods))
+ material.build_rod_product(user, W, src)
+ return
+ return ..()
\ No newline at end of file
diff --git a/code/modules/materials/sheets/gems.dm b/code/modules/materials/sheets/gems.dm
new file mode 100644
index 0000000000..1906da8eab
--- /dev/null
+++ b/code/modules/materials/sheets/gems.dm
@@ -0,0 +1,66 @@
+/obj/item/stack/material/phoron
+ name = "solid phoron"
+ icon_state = "sheet-phoron"
+ default_type = "phoron"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/glass.ogg'
+ pickup_sound = 'sound/items/pickup/glass.ogg'
+
+/obj/item/stack/material/diamond
+ name = "diamond"
+ icon_state = "sheet-diamond"
+ default_type = "diamond"
+ drop_sound = 'sound/items/drop/glass.ogg'
+ pickup_sound = 'sound/items/pickup/glass.ogg'
+
+/obj/item/stack/material/painite
+ name = "painite"
+ icon_state = "sheet-gem"
+ singular_name = "painite gem"
+ default_type = "painite"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/void_opal
+ name = "void opal"
+ icon_state = "sheet-void_opal"
+ singular_name = "void opal"
+ default_type = "void opal"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/quartz
+ name = "quartz"
+ icon_state = "sheet-gem"
+ singular_name = "quartz gem"
+ default_type = "quartz"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/valhollide
+ name = MAT_VALHOLLIDE
+ icon_state = "sheet-gem"
+ item_state = "diamond"
+ default_type = MAT_VALHOLLIDE
+ no_variants = FALSE
+ apply_colour = TRUE
+
+// Particle Smasher and Exotic material.
+/obj/item/stack/material/verdantium
+ name = MAT_VERDANTIUM
+ icon_state = "sheet-wavy"
+ item_state = "mhydrogen"
+ default_type = MAT_VERDANTIUM
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/morphium
+ name = MAT_MORPHIUM
+ icon_state = "sheet-wavy"
+ item_state = "mhydrogen"
+ default_type = MAT_MORPHIUM
+ no_variants = FALSE
+ apply_colour = TRUE
+
+
+
diff --git a/code/modules/materials/sheets/glass.dm b/code/modules/materials/sheets/glass.dm
new file mode 100644
index 0000000000..bf891347ea
--- /dev/null
+++ b/code/modules/materials/sheets/glass.dm
@@ -0,0 +1,33 @@
+/obj/item/stack/material/glass
+ name = "glass"
+ icon_state = "sheet-transparent"
+ default_type = "glass"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/glass.ogg'
+ pickup_sound = 'sound/items/pickup/glass.ogg'
+ apply_colour = TRUE
+
+/obj/item/stack/material/glass/reinforced
+ name = "reinforced glass"
+ icon_state = "sheet-rtransparent"
+ default_type = "rglass"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/glass/phoronglass
+ name = "borosilicate glass"
+ desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures"
+ singular_name = "borosilicate glass sheet"
+ icon_state = "sheet-transparent"
+ default_type = "borosilicate glass"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/glass/phoronrglass
+ name = "reinforced borosilicate glass"
+ desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures. It is reinforced with few rods."
+ singular_name = "reinforced borosilicate glass sheet"
+ icon_state = "sheet-rtransparent"
+ default_type = "reinforced borosilicate glass"
+ no_variants = FALSE
+ apply_colour = TRUE
\ No newline at end of file
diff --git a/code/modules/materials/sheets/glass_vr.dm b/code/modules/materials/sheets/glass_vr.dm
new file mode 100644
index 0000000000..23aad9c0cc
--- /dev/null
+++ b/code/modules/materials/sheets/glass_vr.dm
@@ -0,0 +1,17 @@
+/obj/item/stack/material/glass/titanium
+ name = "ti-glass sheets"
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-titaniumglass"
+ item_state = "sheet-silver"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/glass.ogg'
+ default_type = MAT_TITANIUMGLASS
+
+/obj/item/stack/material/glass/plastitanium
+ name = "plastitanium glass sheets"
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-plastitaniumglass"
+ item_state = "sheet-silver"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/glass.ogg'
+ default_type = MAT_PLASTITANIUMGLASS
diff --git a/code/modules/materials/sheets/metals/hull.dm b/code/modules/materials/sheets/metals/hull.dm
new file mode 100644
index 0000000000..5a6d429f44
--- /dev/null
+++ b/code/modules/materials/sheets/metals/hull.dm
@@ -0,0 +1,18 @@
+/obj/item/stack/material/steel/hull
+ name = MAT_STEELHULL
+ default_type = MAT_STEELHULL
+
+/obj/item/stack/material/plasteel/hull
+ name = MAT_PLASTEELHULL
+ default_type = MAT_PLASTEELHULL
+
+/obj/item/stack/material/durasteel/hull
+ name = MAT_DURASTEELHULL
+
+/obj/item/stack/material/titanium/hull
+ name = MAT_TITANIUMHULL
+ default_type = MAT_TITANIUMHULL
+
+/obj/item/stack/material/morphium/hull
+ name = MAT_MORPHIUMHULL
+ default_type = MAT_MORPHIUMHULL
\ No newline at end of file
diff --git a/code/modules/materials/sheets/metals/hull_vr.dm b/code/modules/materials/sheets/metals/hull_vr.dm
new file mode 100644
index 0000000000..29e267ab81
--- /dev/null
+++ b/code/modules/materials/sheets/metals/hull_vr.dm
@@ -0,0 +1,15 @@
+/obj/item/stack/material/plastitanium/hull
+ name = "plastitanium hull sheets"
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-plastitanium"
+ item_state = "sheet-silver"
+ no_variants = FALSE
+ default_type = MAT_PLASTITANIUMHULL
+
+/obj/item/stack/material/gold/hull
+ name = "gold hull sheets"
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-plastitanium"
+ item_state = "sheet-silver"
+ no_variants = FALSE
+ default_type = MAT_GOLDHULL
diff --git a/code/modules/materials/sheets/metals/metal.dm b/code/modules/materials/sheets/metals/metal.dm
new file mode 100644
index 0000000000..bbad559c12
--- /dev/null
+++ b/code/modules/materials/sheets/metals/metal.dm
@@ -0,0 +1,140 @@
+/obj/item/stack/material/steel
+ name = DEFAULT_WALL_MATERIAL
+ icon_state = "sheet-refined"
+ default_type = DEFAULT_WALL_MATERIAL
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/plasteel
+ name = "plasteel"
+ icon_state = "sheet-reinforced"
+ default_type = "plasteel"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/durasteel
+ name = "durasteel"
+ icon_state = "sheet-reinforced"
+ item_state = "sheet-metal"
+ default_type = "durasteel"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/titanium
+ name = MAT_TITANIUM
+ icon_state = "sheet-refined"
+ apply_colour = TRUE
+ item_state = "sheet-silver"
+ default_type = MAT_TITANIUM
+ no_variants = FALSE
+
+/obj/item/stack/material/iron
+ name = "iron"
+ icon_state = "sheet-ingot"
+ default_type = "iron"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/lead
+ name = "lead"
+ icon_state = "sheet-ingot"
+ default_type = "lead"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/gold
+ name = "gold"
+ icon_state = "sheet-ingot"
+ default_type = "gold"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/silver
+ name = "silver"
+ icon_state = "sheet-ingot"
+ default_type = "silver"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+//Valuable resource, cargo can sell it.
+/obj/item/stack/material/platinum
+ name = "platinum"
+ icon_state = "sheet-adamantine"
+ default_type = "platinum"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/uranium
+ name = "uranium"
+ icon_state = "sheet-uranium"
+ default_type = "uranium"
+ no_variants = FALSE
+
+//Extremely valuable to Research.
+/obj/item/stack/material/mhydrogen
+ name = "metallic hydrogen"
+ icon_state = "sheet-mythril"
+ default_type = "mhydrogen"
+ no_variants = FALSE
+
+// Fusion fuel.
+/obj/item/stack/material/deuterium
+ name = "deuterium"
+ icon_state = "sheet-puck"
+ default_type = "deuterium"
+ apply_colour = 1
+ no_variants = FALSE
+
+//Fuel for MRSPACMAN generator.
+/obj/item/stack/material/tritium
+ name = "tritium"
+ icon_state = "sheet-puck"
+ default_type = "tritium"
+ apply_colour = TRUE
+ no_variants = FALSE
+
+/obj/item/stack/material/osmium
+ name = "osmium"
+ icon_state = "sheet-ingot"
+ default_type = "osmium"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/graphite
+ name = "graphite"
+ icon_state = "sheet-puck"
+ default_type = MAT_GRAPHITE
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/bronze
+ name = "bronze"
+ icon_state = "sheet-ingot"
+ singular_name = "bronze ingot"
+ default_type = "bronze"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/tin
+ name = "tin"
+ icon_state = "sheet-ingot"
+ singular_name = "tin ingot"
+ default_type = "tin"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/copper
+ name = "copper"
+ icon_state = "sheet-ingot"
+ singular_name = "copper ingot"
+ default_type = "copper"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/aluminium
+ name = "aluminium"
+ icon_state = "sheet-ingot"
+ singular_name = "aluminium ingot"
+ default_type = "aluminium"
+ apply_colour = 1
+ no_variants = FALSE
diff --git a/code/modules/materials/sheets/metals/metal_vr.dm b/code/modules/materials/sheets/metals/metal_vr.dm
new file mode 100644
index 0000000000..1a867ea957
--- /dev/null
+++ b/code/modules/materials/sheets/metals/metal_vr.dm
@@ -0,0 +1,12 @@
+/obj/item/stack/material/titanium
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-titanium"
+ no_variants = FALSE
+
+/obj/item/stack/material/plastitanium
+ name = "plastitanium sheets"
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-plastitanium"
+ item_state = "sheet-silver"
+ no_variants = FALSE
+ default_type = MAT_PLASTITANIUM
diff --git a/code/game/objects/items/stacks/rods.dm b/code/modules/materials/sheets/metals/rods.dm
similarity index 96%
rename from code/game/objects/items/stacks/rods.dm
rename to code/modules/materials/sheets/metals/rods.dm
index 9844ae1cba..d1c4a1ee24 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/modules/materials/sheets/metals/rods.dm
@@ -1,109 +1,109 @@
-/obj/item/stack/rods
- name = "metal rod"
- desc = "Some rods. Can be used for building, or something."
- singular_name = "metal rod"
- icon_state = "rods"
- w_class = ITEMSIZE_NORMAL
- force = 9.0
- throwforce = 15.0
- throw_speed = 5
- throw_range = 20
- drop_sound = 'sound/items/drop/metalweapon.ogg'
- pickup_sound = 'sound/items/pickup/metalweapon.ogg'
- matter = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2)
- max_amount = 60
- attack_verb = list("hit", "bludgeoned", "whacked")
-
- color = "#666666"
-
-/obj/item/stack/rods/cyborg
- name = "metal rod synthesizer"
- desc = "A device that makes metal rods."
- gender = NEUTER
- matter = null
- uses_charge = 1
- charge_costs = list(500)
- stacktype = /obj/item/stack/rods
- no_variants = TRUE
-
-/obj/item/stack/rods/Initialize()
- . = ..()
- recipes = rods_recipes
- update_icon()
-
-/obj/item/stack/rods/update_icon()
- var/amount = get_amount()
- if((amount <= 5) && (amount > 0))
- icon_state = "rods-[amount]"
- else
- icon_state = "rods"
-
-var/global/list/datum/stack_recipe/rods_recipes = list( \
- new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 10, one_per_turf = 1, on_floor = 0),
- new/datum/stack_recipe("catwalk", /obj/structure/catwalk, 2, time = 80, one_per_turf = 1, on_floor = 1))
-
-/obj/item/stack/rods/attackby(obj/item/W as obj, mob/user as mob)
- if (istype(W, /obj/item/weapon/weldingtool))
- var/obj/item/weapon/weldingtool/WT = W
-
- if(get_amount() < 2)
- to_chat(user, "You need at least two rods to do this.")
- return
-
- if(WT.remove_fuel(0,user))
- var/obj/item/stack/material/steel/new_item = new(usr.loc)
- new_item.add_to_stacks(usr)
- for (var/mob/M in viewers(src))
- M.show_message("[src] is shaped into metal by [user.name] with the weldingtool.", 3, "You hear welding.", 2)
- var/obj/item/stack/rods/R = src
- src = null
- var/replace = (user.get_inactive_hand()==R)
- R.use(2)
- if (!R && replace)
- user.put_in_hands(new_item)
- return
-
- if (istype(W, /obj/item/weapon/tape_roll))
- var/obj/item/stack/medical/splint/ghetto/new_splint = new(get_turf(user))
- new_splint.add_fingerprint(user)
-
- user.visible_message("\The [user] constructs \a [new_splint] out of a [singular_name].", \
- "You use make \a [new_splint] out of a [singular_name].")
- src.use(1)
- return
-
- ..()
-
-/*
-/obj/item/stack/rods/attack_self(mob/user as mob)
- src.add_fingerprint(user)
-
- if(!istype(user.loc,/turf)) return 0
-
- if (locate(/obj/structure/grille, usr.loc))
- for(var/obj/structure/grille/G in usr.loc)
- if (G.destroyed)
- G.health = 10
- G.density = 1
- G.destroyed = 0
- G.icon_state = "grille"
- use(1)
- else
- return 1
-
- else if(!in_use)
- if(get_amount() < 2)
- to_chat(user, "You need at least two rods to do this.")
- return
- to_chat(usr, "Assembling grille...")
- in_use = 1
- if (!do_after(usr, 10))
- in_use = 0
- return
- var/obj/structure/grille/F = new /obj/structure/grille/ ( usr.loc )
- to_chat(usr, "You assemble a grille")
- in_use = 0
- F.add_fingerprint(usr)
- use(2)
- return
+/obj/item/stack/rods
+ name = "metal rod"
+ desc = "Some rods. Can be used for building, or something."
+ singular_name = "metal rod"
+ icon_state = "rods"
+ w_class = ITEMSIZE_NORMAL
+ force = 9.0
+ throwforce = 15.0
+ throw_speed = 5
+ throw_range = 20
+ drop_sound = 'sound/items/drop/metalweapon.ogg'
+ pickup_sound = 'sound/items/pickup/metalweapon.ogg'
+ matter = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2)
+ max_amount = 60
+ attack_verb = list("hit", "bludgeoned", "whacked")
+
+ color = "#666666"
+
+/obj/item/stack/rods/cyborg
+ name = "metal rod synthesizer"
+ desc = "A device that makes metal rods."
+ gender = NEUTER
+ matter = null
+ uses_charge = 1
+ charge_costs = list(500)
+ stacktype = /obj/item/stack/rods
+ no_variants = TRUE
+
+/obj/item/stack/rods/Initialize()
+ . = ..()
+ recipes = rods_recipes
+ update_icon()
+
+/obj/item/stack/rods/update_icon()
+ var/amount = get_amount()
+ if((amount <= 5) && (amount > 0))
+ icon_state = "rods-[amount]"
+ else
+ icon_state = "rods"
+
+var/global/list/datum/stack_recipe/rods_recipes = list( \
+ new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 10, one_per_turf = 1, on_floor = 0),
+ new/datum/stack_recipe("catwalk", /obj/structure/catwalk, 2, time = 80, one_per_turf = 1, on_floor = 1))
+
+/obj/item/stack/rods/attackby(obj/item/W as obj, mob/user as mob)
+ if (istype(W, /obj/item/weapon/weldingtool))
+ var/obj/item/weapon/weldingtool/WT = W
+
+ if(get_amount() < 2)
+ to_chat(user, "You need at least two rods to do this.")
+ return
+
+ if(WT.remove_fuel(0,user))
+ var/obj/item/stack/material/steel/new_item = new(usr.loc)
+ new_item.add_to_stacks(usr)
+ for (var/mob/M in viewers(src))
+ M.show_message("[src] is shaped into metal by [user.name] with the weldingtool.", 3, "You hear welding.", 2)
+ var/obj/item/stack/rods/R = src
+ src = null
+ var/replace = (user.get_inactive_hand()==R)
+ R.use(2)
+ if (!R && replace)
+ user.put_in_hands(new_item)
+ return
+
+ if (istype(W, /obj/item/weapon/tape_roll))
+ var/obj/item/stack/medical/splint/ghetto/new_splint = new(get_turf(user))
+ new_splint.add_fingerprint(user)
+
+ user.visible_message("\The [user] constructs \a [new_splint] out of a [singular_name].", \
+ "You use make \a [new_splint] out of a [singular_name].")
+ src.use(1)
+ return
+
+ ..()
+
+/*
+/obj/item/stack/rods/attack_self(mob/user as mob)
+ src.add_fingerprint(user)
+
+ if(!istype(user.loc,/turf)) return 0
+
+ if (locate(/obj/structure/grille, usr.loc))
+ for(var/obj/structure/grille/G in usr.loc)
+ if (G.destroyed)
+ G.health = 10
+ G.density = 1
+ G.destroyed = 0
+ G.icon_state = "grille"
+ use(1)
+ else
+ return 1
+
+ else if(!in_use)
+ if(get_amount() < 2)
+ to_chat(user, "You need at least two rods to do this.")
+ return
+ to_chat(usr, "Assembling grille...")
+ in_use = 1
+ if (!do_after(usr, 10))
+ in_use = 0
+ return
+ var/obj/structure/grille/F = new /obj/structure/grille/ ( usr.loc )
+ to_chat(usr, "You assemble a grille")
+ in_use = 0
+ F.add_fingerprint(usr)
+ use(2)
+ return
*/
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/animal_products.dm b/code/modules/materials/sheets/organic/animal_products.dm
new file mode 100644
index 0000000000..4620da5ea9
--- /dev/null
+++ b/code/modules/materials/sheets/organic/animal_products.dm
@@ -0,0 +1,31 @@
+/obj/item/stack/material/chitin
+ name = "chitin"
+ desc = "The by-product of mob grinding."
+ icon_state = "chitin"
+ default_type = MAT_CHITIN
+ no_variants = FALSE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
+ drop_sound = 'sound/items/drop/leather.ogg'
+ pickup_sound = 'sound/items/pickup/leather.ogg'
+
+//don't see anywhere else to put these, maybe together they could be used to make the xenos suit?
+/obj/item/stack/xenochitin
+ name = "alien chitin"
+ desc = "A piece of the hide of a terrible creature."
+ singular_name = "alien chitin piece"
+ icon = 'icons/mob/alien.dmi'
+ icon_state = "chitin"
+ stacktype = "hide-chitin"
+
+/obj/item/xenos_claw
+ name = "alien claw"
+ desc = "The claw of a terrible creature."
+ icon = 'icons/mob/alien.dmi'
+ icon_state = "claw"
+
+/obj/item/weed_extract
+ name = "weed extract"
+ desc = "A piece of slimy, purplish weed."
+ icon = 'icons/mob/alien.dmi'
+ icon_state = "weed_extract"
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/resin.dm b/code/modules/materials/sheets/organic/resin.dm
new file mode 100644
index 0000000000..7120911f2d
--- /dev/null
+++ b/code/modules/materials/sheets/organic/resin.dm
@@ -0,0 +1,8 @@
+/obj/item/stack/material/resin
+ name = "resin"
+ icon_state = "sheet-resin"
+ default_type = "resin"
+ no_variants = TRUE
+ apply_colour = TRUE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/tanning/hide.dm b/code/modules/materials/sheets/organic/tanning/hide.dm
new file mode 100644
index 0000000000..a8b229c9eb
--- /dev/null
+++ b/code/modules/materials/sheets/organic/tanning/hide.dm
@@ -0,0 +1,90 @@
+/obj/item/stack/animalhide
+ name = "hide"
+ desc = "The hide of some creature."
+ description_info = "Use something sharp, like a knife, to scrape the hairs/feathers/etc off this hide to prepare it for tanning."
+ icon_state = "sheet-hide"
+ drop_sound = 'sound/items/drop/cloth.ogg'
+ pickup_sound = 'sound/items/pickup/cloth.ogg'
+ amount = 1
+ max_amount = 20
+ stacktype = "hide"
+ no_variants = TRUE
+// This needs to be very clearly documented for players. Whether it should stay in the main description is up for debate.
+/obj/item/stack/animalhide/examine(var/mob/user)
+ . = ..()
+ . += description_info
+
+//Step one - dehairing.
+/obj/item/stack/animalhide/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(has_edge(W) || is_sharp(W))
+ //visible message on mobs is defined as visible_message(var/message, var/self_message, var/blind_message)
+ user.visible_message("\The [user] starts cutting hair off \the [src]", "You start cutting the hair off \the [src]", "You hear the sound of a knife rubbing against flesh")
+ var/scraped = 0
+ while(amount > 0 && do_after(user, 2.5 SECONDS)) // 2.5s per hide
+ //Try locating an exisitng stack on the tile and add to there if possible
+ var/obj/item/stack/hairlesshide/H = null
+ for(var/obj/item/stack/hairlesshide/HS in user.loc) // Could be scraping something inside a locker, hence the .loc, not get_turf
+ if(HS.amount < HS.max_amount)
+ H = HS
+ break
+
+ // Either we found a valid stack, in which case increment amount,
+ // Or we need to make a new stack
+ if(istype(H))
+ H.amount++
+ else
+ H = new /obj/item/stack/hairlesshide(user.loc)
+
+ // Increment the amount
+ src.use(1)
+ scraped++
+
+ if(scraped)
+ to_chat(user, SPAN_NOTICE("You scrape the hair off [scraped] hide\s."))
+ else
+ ..()
+
+/obj/item/stack/animalhide/human
+ name = "skin"
+ desc = "The by-product of sapient farming."
+ singular_name = "skin piece"
+ icon_state = "sheet-hide"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/leather.ogg'
+ pickup_sound = 'sound/items/pickup/leather.ogg'
+ stacktype = "hide-human"
+
+/obj/item/stack/animalhide/corgi
+ name = "corgi hide"
+ desc = "The by-product of corgi farming."
+ singular_name = "corgi hide piece"
+ icon_state = "sheet-corgi"
+ stacktype = "hide-corgi"
+
+/obj/item/stack/animalhide/cat
+ name = "cat hide"
+ desc = "The by-product of cat farming."
+ singular_name = "cat hide piece"
+ icon_state = "sheet-cat"
+ stacktype = "hide-cat"
+
+/obj/item/stack/animalhide/monkey
+ name = "monkey hide"
+ desc = "The by-product of monkey farming."
+ singular_name = "monkey hide piece"
+ icon_state = "sheet-monkey"
+ stacktype = "hide-monkey"
+
+/obj/item/stack/animalhide/lizard
+ name = "lizard skin"
+ desc = "Sssssss..."
+ singular_name = "lizard skin piece"
+ icon_state = "sheet-lizard"
+ stacktype = "hide-lizard"
+
+/obj/item/stack/animalhide/xeno
+ name = "alien hide"
+ desc = "The skin of a terrible creature."
+ singular_name = "alien hide piece"
+ icon_state = "sheet-xeno"
+ stacktype = "hide-xeno"
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/tanning/hide_hairless.dm b/code/modules/materials/sheets/organic/tanning/hide_hairless.dm
new file mode 100644
index 0000000000..72b235e415
--- /dev/null
+++ b/code/modules/materials/sheets/organic/tanning/hide_hairless.dm
@@ -0,0 +1,48 @@
+//Step two - washing..... it's actually in washing machine code, and ere.
+
+/obj/item/stack/hairlesshide
+ name = "hairless hide"
+ desc = "This hide was stripped of it's hair, but still needs tanning."
+ description_info = "Get it wet to continue tanning this into leather.
\
+ You could set it in a river, wash it with a sink, or just splash water on it with a bucket."
+ singular_name = "hairless hide piece"
+ icon_state = "sheet-hairlesshide"
+ no_variants = FALSE
+ max_amount = 20
+ stacktype = "hairlesshide"
+
+/obj/item/stack/hairlesshide/examine(var/mob/user)
+ . = ..()
+ . += description_info
+
+/obj/item/stack/hairlesshide/water_act(var/wateramount)
+ . = ..()
+ wateramount = min(amount, round(wateramount))
+ for(var/i in 1 to wateramount)
+ var/obj/item/stack/wetleather/H = null
+ for(var/obj/item/stack/wetleather/HS in get_turf(src)) // Doesn't have a user, can't just use their loc
+ if(HS.amount < HS.max_amount)
+ H = HS
+ break
+
+ // Either we found a valid stack, in which case increment amount,
+ // Or we need to make a new stack
+ if(istype(H))
+ H.amount++
+ else
+ H = new /obj/item/stack/wetleather(get_turf(src))
+
+ // Increment the amount
+ src.use(1)
+
+/obj/item/stack/hairlesshide/proc/rapidcure(var/stacknum = 1)
+ stacknum = min(stacknum, amount)
+
+ while(stacknum)
+ var/obj/item/stack/wetleather/I = new /obj/item/stack/wetleather(get_turf(src))
+
+ if(istype(I))
+ I.dry()
+
+ use(1)
+ stacknum -= 1
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/tanning/leather_wet.dm b/code/modules/materials/sheets/organic/tanning/leather_wet.dm
new file mode 100644
index 0000000000..64f672512c
--- /dev/null
+++ b/code/modules/materials/sheets/organic/tanning/leather_wet.dm
@@ -0,0 +1,51 @@
+//Step three - drying
+/obj/item/stack/wetleather
+ name = "wet leather"
+ desc = "This leather has been cleaned but still needs to be dried."
+ description_info = "To finish tanning the leather, you need to dry it. \
+ You could place it under a fire, \
+ put it in a drying rack, \
+ or build a tanning rack from steel or wooden boards."
+ singular_name = "wet leather piece"
+ icon_state = "sheet-wetleather"
+ var/wetness = 30 //Reduced when exposed to high temperautres
+ var/drying_threshold_temperature = 500 //Kelvin to start drying
+ no_variants = FALSE
+ max_amount = 20
+ stacktype = "wetleather"
+
+ var/dry_type = /obj/item/stack/material/leather
+
+/obj/item/stack/wetleather/examine(var/mob/user)
+ . = ..()
+ . += description_info
+ . += "\The [src] is [get_dryness_text()]."
+
+/obj/item/stack/wetleather/proc/get_dryness_text()
+ if(wetness > 20)
+ return "wet"
+ if(wetness > 10)
+ return "damp"
+ if(wetness)
+ return "almost dry"
+ return "dry"
+
+/obj/item/stack/wetleather/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ ..()
+ if(exposed_temperature >= drying_threshold_temperature)
+ wetness--
+ if(wetness == 0)
+ dry()
+
+/obj/item/stack/wetleather/proc/dry()
+ var/obj/item/stack/material/leather/L = new(src.loc)
+ L.amount = amount
+ use(amount)
+ return L
+
+/obj/item/stack/wetleather/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified)
+ . = ..()
+ if(.) // If it transfers any, do a weighted average of the wetness
+ var/obj/item/stack/wetleather/W = S
+ var/oldamt = W.amount - .
+ W.wetness = round(((oldamt * W.wetness) + (. * wetness)) / W.amount)
diff --git a/code/modules/materials/sheets/organic/tanning/tanning_rack.dm b/code/modules/materials/sheets/organic/tanning/tanning_rack.dm
new file mode 100644
index 0000000000..96d70d9096
--- /dev/null
+++ b/code/modules/materials/sheets/organic/tanning/tanning_rack.dm
@@ -0,0 +1,70 @@
+/obj/structure/tanning_rack
+ name = "tanning rack"
+ desc = "A rack used to stretch leather out and hold it taut during the tanning process."
+ icon = 'icons/obj/kitchen.dmi'
+ icon_state = "spike"
+
+ var/obj/item/stack/wetleather/drying = null
+
+/obj/structure/tanning_rack/Initialize()
+ . = ..()
+ START_PROCESSING(SSobj, src) // SSObj fires ~every 2s , starting from wetness 30 takes ~1m
+
+/obj/structure/tanning_rack/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/structure/tanning_rack/process()
+ if(drying && drying.wetness)
+ drying.wetness = max(drying.wetness - 1, 0)
+ if(!drying.wetness)
+ visible_message("The [drying] is dry!")
+ update_icon()
+
+/obj/structure/tanning_rack/examine(var/mob/user)
+ . = ..()
+ if(drying)
+ . += "\The [drying] is [drying.get_dryness_text()]."
+
+/obj/structure/tanning_rack/update_icon()
+ overlays.Cut()
+ if(drying)
+ var/image/I
+ if(drying.wetness)
+ I = image(icon, "leather_wet")
+ else
+ I = image(icon, "leather_dry")
+ add_overlay(I)
+
+/obj/structure/tanning_rack/attackby(var/atom/A, var/mob/user)
+ if(istype(A, /obj/item/stack/wetleather))
+ if(!drying) // If not drying anything, start drying the thing
+ if(user.unEquip(A, target = src))
+ drying = A
+ else // Drying something, add if possible
+ var/obj/item/stack/wetleather/W = A
+ W.transfer_to(drying, W.amount, TRUE)
+ update_icon()
+ return TRUE
+ return ..()
+
+/obj/structure/tanning_rack/attack_hand(var/mob/user)
+ if(drying)
+ var/obj/item/stack/S = drying
+ if(!drying.wetness) // If it's dry, make a stack of dry leather and prepare to put that in their hands
+ var/obj/item/stack/material/leather/L = new(src)
+ L.amount = drying.amount
+ drying.use(drying.amount)
+ S = L
+
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(!H.put_in_any_hand_if_possible(S))
+ S.forceMove(get_turf(src))
+ else
+ S.forceMove(get_turf(src))
+ drying = null
+ update_icon()
+
+/obj/structure/tanning_rack/attack_robot(var/mob/user)
+ attack_hand(user) // That has checks to
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/textiles.dm b/code/modules/materials/sheets/organic/textiles.dm
new file mode 100644
index 0000000000..a534ee19b1
--- /dev/null
+++ b/code/modules/materials/sheets/organic/textiles.dm
@@ -0,0 +1,23 @@
+/obj/item/stack/material/leather
+ name = "leather"
+ desc = "The by-product of mob grinding."
+ icon_state = "sheet-leather"
+ default_type = MAT_LEATHER
+ no_variants = FALSE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
+ drop_sound = 'sound/items/drop/leather.ogg'
+ pickup_sound = 'sound/items/pickup/leather.ogg'
+
+/obj/item/stack/material/cloth
+ name = "cloth"
+ icon_state = "sheet-cloth"
+ default_type = "cloth"
+ no_variants = FALSE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
+ drop_sound = 'sound/items/drop/clothing.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
+
+/obj/item/stack/material/cloth/diyaab
+ color = "#c6ccf0"
diff --git a/code/modules/materials/sheets/organic/wood.dm b/code/modules/materials/sheets/organic/wood.dm
new file mode 100644
index 0000000000..d3d1fd6418
--- /dev/null
+++ b/code/modules/materials/sheets/organic/wood.dm
@@ -0,0 +1,55 @@
+/obj/item/stack/material/wood
+ name = "wooden plank"
+ icon_state = "sheet-wood"
+ default_type = MAT_WOOD
+ strict_color_stacking = TRUE
+ apply_colour = 1
+ drop_sound = 'sound/items/drop/wooden.ogg'
+ pickup_sound = 'sound/items/pickup/wooden.ogg'
+ no_variants = FALSE
+
+/obj/item/stack/material/wood/sif
+ name = "alien wooden plank"
+ color = "#0099cc"
+ default_type = MAT_SIFWOOD
+
+/obj/item/stack/material/log
+ name = "log"
+ icon_state = "sheet-log"
+ default_type = MAT_LOG
+ no_variants = FALSE
+ color = "#824B28"
+ max_amount = 25
+ w_class = ITEMSIZE_HUGE
+ description_info = "Use inhand to craft things, or use a sharp and edged object on this to convert it into two wooden planks."
+ var/plank_type = /obj/item/stack/material/wood
+ drop_sound = 'sound/items/drop/wooden.ogg'
+ pickup_sound = 'sound/items/pickup/wooden.ogg'
+
+/obj/item/stack/material/log/sif
+ name = "alien log"
+ default_type = MAT_SIFLOG
+ color = "#0099cc"
+ plank_type = /obj/item/stack/material/wood/sif
+
+/obj/item/stack/material/log/attackby(var/obj/item/W, var/mob/user)
+ if(!istype(W) || W.force <= 0)
+ return ..()
+ if(W.sharp && W.edge)
+ var/time = (3 SECONDS / max(W.force / 10, 1)) * W.toolspeed
+ user.setClickCooldown(time)
+ if(do_after(user, time, src) && use(1))
+ to_chat(user, "You cut up a log into planks.")
+ playsound(src, 'sound/effects/woodcutting.ogg', 50, 1)
+ var/obj/item/stack/material/wood/existing_wood = null
+ for(var/obj/item/stack/material/wood/M in user.loc)
+ if(M.material.name == src.material.name)
+ existing_wood = M
+ break
+
+ var/obj/item/stack/material/wood/new_wood = new plank_type(user.loc)
+ new_wood.amount = 2
+ if(existing_wood && new_wood.transfer_to(existing_wood))
+ to_chat(user, "You add the newly-formed wood to the stack. It now contains [existing_wood.amount] planks.")
+ else
+ return ..()
diff --git a/code/modules/materials/sheets/plastic.dm b/code/modules/materials/sheets/plastic.dm
new file mode 100644
index 0000000000..41415af606
--- /dev/null
+++ b/code/modules/materials/sheets/plastic.dm
@@ -0,0 +1,15 @@
+/obj/item/stack/material/plastic
+ name = "plastic"
+ icon_state = "sheet-plastic"
+ default_type = "plastic"
+ no_variants = FALSE
+
+/obj/item/stack/material/cardboard
+ name = "cardboard"
+ icon_state = "sheet-card"
+ default_type = "cardboard"
+ no_variants = FALSE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
+ drop_sound = 'sound/items/drop/cardboardbox.ogg'
+ pickup_sound = 'sound/items/pickup/cardboardbox.ogg'
diff --git a/code/modules/materials/sheets/snow.dm b/code/modules/materials/sheets/snow.dm
new file mode 100644
index 0000000000..7ecc4c4e64
--- /dev/null
+++ b/code/modules/materials/sheets/snow.dm
@@ -0,0 +1,16 @@
+// Ok, technically not stones, but the snowbrick's function is similar to sandstone and marble
+/obj/item/stack/material/snow
+ name = "snow"
+ desc = "The temptation to build a snowman rises."
+ icon_state = "sheet-snow"
+ drop_sound = 'sound/items/drop/gloves.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
+ default_type = "snow"
+
+/obj/item/stack/material/snowbrick
+ name = "snow brick"
+ desc = "For all of your igloo building needs."
+ icon_state = "sheet-snowbrick"
+ default_type = "packed snow"
+ drop_sound = 'sound/items/drop/gloves.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
\ No newline at end of file
diff --git a/code/modules/materials/sheets/stone.dm b/code/modules/materials/sheets/stone.dm
new file mode 100644
index 0000000000..17347ff9d8
--- /dev/null
+++ b/code/modules/materials/sheets/stone.dm
@@ -0,0 +1,15 @@
+/obj/item/stack/material/sandstone
+ name = "sandstone brick"
+ icon_state = "sheet-sandstone"
+ default_type = "sandstone"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/boots.ogg'
+ pickup_sound = 'sound/items/pickup/boots.ogg'
+
+/obj/item/stack/material/marble
+ name = "marble brick"
+ icon_state = "sheet-marble"
+ default_type = "marble"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/boots.ogg'
+ pickup_sound = 'sound/items/pickup/boots.ogg'
diff --git a/code/modules/materials/sheets/supermatter.dm b/code/modules/materials/sheets/supermatter.dm
new file mode 100644
index 0000000000..c56f298088
--- /dev/null
+++ b/code/modules/materials/sheets/supermatter.dm
@@ -0,0 +1,55 @@
+// Forged in the equivalent of Hell, one piece at a time.
+/obj/item/stack/material/supermatter
+ name = MAT_SUPERMATTER
+ icon_state = "sheet-super"
+ item_state = "diamond"
+ default_type = MAT_SUPERMATTER
+ apply_colour = TRUE
+
+/obj/item/stack/material/supermatter/proc/update_mass() // Due to how dangerous they can be, the item will get heavier and larger the more are in the stack.
+ slowdown = amount / 10
+ w_class = min(5, round(amount / 10) + 1)
+ throw_range = round(amount / 7) + 1
+
+/obj/item/stack/material/supermatter/use(var/used)
+ . = ..()
+ update_mass()
+ return
+
+/obj/item/stack/material/supermatter/attack_hand(mob/user)
+ . = ..()
+
+ update_mass()
+ SSradiation.radiate(src, 5 + amount)
+ var/mob/living/M = user
+ if(!istype(M))
+ return
+
+ var/burn_user = TRUE
+ if(istype(M, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = user
+ var/obj/item/clothing/gloves/G = H.gloves
+ if(istype(G) && ((G.flags & THICKMATERIAL && prob(70)) || istype(G, /obj/item/clothing/gloves/gauntlets)))
+ burn_user = FALSE
+
+ if(burn_user)
+ H.visible_message("\The [src] flashes as it scorches [H]'s hands!")
+ H.apply_damage(amount / 2 + 5, BURN, "r_hand", used_weapon="Supermatter Chunk")
+ H.apply_damage(amount / 2 + 5, BURN, "l_hand", used_weapon="Supermatter Chunk")
+ H.drop_from_inventory(src, get_turf(H))
+ return
+
+ if(istype(user, /mob/living/silicon/robot))
+ burn_user = FALSE
+
+ if(burn_user)
+ M.apply_damage(amount, BURN, null, used_weapon="Supermatter Chunk")
+
+/obj/item/stack/material/supermatter/ex_act(severity) // An incredibly hard to manufacture material, SM chunks are unstable by their 'stabilized' nature.
+ if(prob((4 / severity) * 20))
+ SSradiation.radiate(get_turf(src), amount * 4)
+ explosion(get_turf(src),round(amount / 12) , round(amount / 6), round(amount / 3), round(amount / 25))
+ qdel(src)
+ return
+ SSradiation.radiate(get_turf(src), amount * 2)
+ ..()
\ No newline at end of file
diff --git a/code/modules/mining/machine_input_output_plates.dm b/code/modules/mining/machinery/machine_input_output_plates.dm
similarity index 90%
rename from code/modules/mining/machine_input_output_plates.dm
rename to code/modules/mining/machinery/machine_input_output_plates.dm
index d8693a1316..0e7680e672 100644
--- a/code/modules/mining/machine_input_output_plates.dm
+++ b/code/modules/mining/machinery/machine_input_output_plates.dm
@@ -1,19 +1,19 @@
-/**********************Input and output plates**************************/
-
-/obj/machinery/mineral/input
- icon = 'icons/mob/screen1.dmi'
- icon_state = "x2"
- name = "Input area"
- density = 0
- anchored = 1.0
- New()
- icon_state = "blank"
-
-/obj/machinery/mineral/output
- icon = 'icons/mob/screen1.dmi'
- icon_state = "x"
- name = "Output area"
- density = 0
- anchored = 1.0
- New()
+/**********************Input and output plates**************************/
+
+/obj/machinery/mineral/input
+ icon = 'icons/mob/screen1.dmi'
+ icon_state = "x2"
+ name = "Input area"
+ density = 0
+ anchored = 1.0
+ New()
+ icon_state = "blank"
+
+/obj/machinery/mineral/output
+ icon = 'icons/mob/screen1.dmi'
+ icon_state = "x"
+ name = "Output area"
+ density = 0
+ anchored = 1.0
+ New()
icon_state = "blank"
\ No newline at end of file
diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machinery/machine_processing.dm
similarity index 100%
rename from code/modules/mining/machine_processing.dm
rename to code/modules/mining/machinery/machine_processing.dm
diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machinery/machine_stacking.dm
similarity index 100%
rename from code/modules/mining/machine_stacking.dm
rename to code/modules/mining/machinery/machine_stacking.dm
diff --git a/code/modules/mining/machine_unloading.dm b/code/modules/mining/machinery/machine_unloading.dm
similarity index 100%
rename from code/modules/mining/machine_unloading.dm
rename to code/modules/mining/machinery/machine_unloading.dm
diff --git a/vorestation.dme b/vorestation.dme
index 155511a30f..dc5b8c2658 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -58,6 +58,7 @@
#include "code\__defines\lighting_vr.dm"
#include "code\__defines\machinery.dm"
#include "code\__defines\map.dm"
+#include "code\__defines\materials.dm"
#include "code\__defines\math.dm"
#include "code\__defines\math_physics.dm"
#include "code\__defines\MC.dm"
@@ -885,8 +886,6 @@
#include "code\game\machinery\teleporter.dm"
#include "code\game\machinery\transportpod.dm"
#include "code\game\machinery\turret_control.dm"
-#include "code\game\machinery\vending.dm"
-#include "code\game\machinery\vending_machines.dm"
#include "code\game\machinery\vending_machines_vr.dm"
#include "code\game\machinery\vending_yw.dm"
#include "code\game\machinery\vitals_monitor.dm"
@@ -1260,19 +1259,16 @@
#include "code\game\objects\items\robot\robot_parts.dm"
#include "code\game\objects\items\robot\robot_upgrades.dm"
#include "code\game\objects\items\robot\robot_upgrades_vr.dm"
-#include "code\game\objects\items\stacks\fifty_spawner.dm"
#include "code\game\objects\items\stacks\marker_beacons.dm"
#include "code\game\objects\items\stacks\matter_synth.dm"
#include "code\game\objects\items\stacks\medical.dm"
#include "code\game\objects\items\stacks\medical_vr.dm"
#include "code\game\objects\items\stacks\nanopaste.dm"
#include "code\game\objects\items\stacks\nanopaste_vr.dm"
-#include "code\game\objects\items\stacks\rods.dm"
#include "code\game\objects\items\stacks\sandbags.dm"
#include "code\game\objects\items\stacks\stack.dm"
#include "code\game\objects\items\stacks\telecrystal.dm"
#include "code\game\objects\items\stacks\tickets.dm"
-#include "code\game\objects\items\stacks\sheets\leather.dm"
#include "code\game\objects\items\stacks\tiles\fifty_spawner_tiles.dm"
#include "code\game\objects\items\stacks\tiles\fifty_spawner_tiles_yw.dm"
#include "code\game\objects\items\stacks\tiles\tile_types.dm"
@@ -2195,17 +2191,26 @@
#include "code\modules\economy\ATM.dm"
#include "code\modules\economy\cash.dm"
#include "code\modules\economy\cash_register.dm"
+<<<<<<< HEAD
#include "code\modules\economy\casinocash_ch.dm"
+||||||| parent of d9937399de... Merge pull request #10192 from VOREStation/upstream-merge-8022
+=======
+#include "code\modules\economy\coins.dm"
+>>>>>>> d9937399de... Merge pull request #10192 from VOREStation/upstream-merge-8022
#include "code\modules\economy\economy_misc.dm"
#include "code\modules\economy\EFTPOS.dm"
#include "code\modules\economy\Events.dm"
#include "code\modules\economy\Events_Mundane.dm"
#include "code\modules\economy\lorenews.dm"
+#include "code\modules\economy\mint.dm"
+#include "code\modules\economy\money_bag.dm"
#include "code\modules\economy\price_list.dm"
#include "code\modules\economy\price_list_ch.dm"
#include "code\modules\economy\price_list_yw.dm"
#include "code\modules\economy\retail_scanner.dm"
#include "code\modules\economy\TradeDestinations.dm"
+#include "code\modules\economy\vending.dm"
+#include "code\modules\economy\vending_machines.dm"
#include "code\modules\entopics_vr\alternate_appearance.dm"
#include "code\modules\entopics_vr\entopics.dm"
#include "code\modules\error_handler\_defines.dm"
@@ -2565,16 +2570,79 @@
#include "code\modules\maps\tg\map_template.dm"
#include "code\modules\maps\tg\map_template_vr.dm"
#include "code\modules\maps\tg\reader.dm"
+#include "code\modules\materials\fifty_spawner.dm"
#include "code\modules\materials\fifty_spawner_mats.dm"
+<<<<<<< HEAD
#include "code\modules\materials\material_recipes.dm"
#include "code\modules\materials\material_recipes_ch.dm"
#include "code\modules\materials\material_recipes_vr.dm"
#include "code\modules\materials\material_sheets.dm"
#include "code\modules\materials\material_sheets_vr.dm"
+||||||| parent of d9937399de... Merge pull request #10192 from VOREStation/upstream-merge-8022
+#include "code\modules\materials\material_recipes.dm"
+#include "code\modules\materials\material_recipes_vr.dm"
+#include "code\modules\materials\material_sheets.dm"
+#include "code\modules\materials\material_sheets_vr.dm"
+=======
+#include "code\modules\materials\fifty_spawner_mats_vr.dm"
+>>>>>>> d9937399de... Merge pull request #10192 from VOREStation/upstream-merge-8022
#include "code\modules\materials\material_synth.dm"
+<<<<<<< HEAD
#include "code\modules\materials\materials.dm"
#include "code\modules\materials\materials_ch.dm"
#include "code\modules\materials\materials_vr.dm"
+||||||| parent of d9937399de... Merge pull request #10192 from VOREStation/upstream-merge-8022
+#include "code\modules\materials\materials.dm"
+#include "code\modules\materials\materials_vr.dm"
+=======
+#include "code\modules\materials\materials\_materials.dm"
+#include "code\modules\materials\materials\_materials_vr.dm"
+#include "code\modules\materials\materials\alien_alloy.dm"
+#include "code\modules\materials\materials\cult.dm"
+#include "code\modules\materials\materials\gems.dm"
+#include "code\modules\materials\materials\glass.dm"
+#include "code\modules\materials\materials\glass_vr.dm"
+#include "code\modules\materials\materials\holographic.dm"
+#include "code\modules\materials\materials\other_vr.dm"
+#include "code\modules\materials\materials\plastic.dm"
+#include "code\modules\materials\materials\snow.dm"
+#include "code\modules\materials\materials\stone.dm"
+#include "code\modules\materials\materials\supermatter.dm"
+#include "code\modules\materials\materials\metals\hull.dm"
+#include "code\modules\materials\materials\metals\hull_vr.dm"
+#include "code\modules\materials\materials\metals\metals.dm"
+#include "code\modules\materials\materials\metals\metals_vr.dm"
+#include "code\modules\materials\materials\metals\plasteel.dm"
+#include "code\modules\materials\materials\metals\plasteel_vr.dm"
+#include "code\modules\materials\materials\metals\steel.dm"
+#include "code\modules\materials\materials\metals\steel_vr.dm"
+#include "code\modules\materials\materials\organic\animal_products.dm"
+#include "code\modules\materials\materials\organic\cloth.dm"
+#include "code\modules\materials\materials\organic\leather.dm"
+#include "code\modules\materials\materials\organic\resin.dm"
+#include "code\modules\materials\materials\organic\wood.dm"
+#include "code\modules\materials\sheets\_sheets.dm"
+#include "code\modules\materials\sheets\gems.dm"
+#include "code\modules\materials\sheets\glass.dm"
+#include "code\modules\materials\sheets\glass_vr.dm"
+#include "code\modules\materials\sheets\plastic.dm"
+#include "code\modules\materials\sheets\snow.dm"
+#include "code\modules\materials\sheets\stone.dm"
+#include "code\modules\materials\sheets\supermatter.dm"
+#include "code\modules\materials\sheets\metals\hull.dm"
+#include "code\modules\materials\sheets\metals\hull_vr.dm"
+#include "code\modules\materials\sheets\metals\metal.dm"
+#include "code\modules\materials\sheets\metals\metal_vr.dm"
+#include "code\modules\materials\sheets\metals\rods.dm"
+#include "code\modules\materials\sheets\organic\animal_products.dm"
+#include "code\modules\materials\sheets\organic\resin.dm"
+#include "code\modules\materials\sheets\organic\textiles.dm"
+#include "code\modules\materials\sheets\organic\wood.dm"
+#include "code\modules\materials\sheets\organic\tanning\hide.dm"
+#include "code\modules\materials\sheets\organic\tanning\hide_hairless.dm"
+#include "code\modules\materials\sheets\organic\tanning\leather_wet.dm"
+#include "code\modules\materials\sheets\organic\tanning\tanning_rack.dm"
+>>>>>>> d9937399de... Merge pull request #10192 from VOREStation/upstream-merge-8022
#include "code\modules\media\media_machinery.dm"
#include "code\modules\media\media_player_html5.dm"
#include "code\modules\media\media_player_vlc.dm"
@@ -2589,20 +2657,13 @@
#include "code\modules\mining\abandonedcrates_vr.dm"
#include "code\modules\mining\alloys.dm"
#include "code\modules\mining\alloys_vr.dm"
-#include "code\modules\mining\coins.dm"
#include "code\modules\mining\fulton.dm"
-#include "code\modules\mining\machine_input_output_plates.dm"
-#include "code\modules\mining\machine_processing.dm"
-#include "code\modules\mining\machine_stacking.dm"
-#include "code\modules\mining\machine_unloading.dm"
#include "code\modules\mining\mine_items.dm"
#include "code\modules\mining\mine_items_vr.dm"
#include "code\modules\mining\mine_outcrops.dm"
#include "code\modules\mining\mine_turfs.dm"
#include "code\modules\mining\mine_turfs_vr.dm"
#include "code\modules\mining\mineral_effect.dm"
-#include "code\modules\mining\mint.dm"
-#include "code\modules\mining\money_bag.dm"
#include "code\modules\mining\ore.dm"
#include "code\modules\mining\ore_box.dm"
#include "code\modules\mining\ore_datum.dm"
@@ -2611,6 +2672,10 @@
#include "code\modules\mining\shelters_vr.dm"
#include "code\modules\mining\drilling\drill.dm"
#include "code\modules\mining\drilling\scanner.dm"
+#include "code\modules\mining\machinery\machine_input_output_plates.dm"
+#include "code\modules\mining\machinery\machine_processing.dm"
+#include "code\modules\mining\machinery\machine_stacking.dm"
+#include "code\modules\mining\machinery\machine_unloading.dm"
#include "code\modules\mining\ore_redemption_machine\construction.dm"
#include "code\modules\mining\ore_redemption_machine\equipment_vendor.dm"
#include "code\modules\mining\ore_redemption_machine\mine_point_items.dm"