diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000000..d7cffbcfb68
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,60 @@
+FROM tgstation/byond:513.1533 as base
+
+FROM base as rust_g
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends \
+ git \
+ ca-certificates
+
+WORKDIR /rust_g
+
+RUN apt-get install -y --no-install-recommends \
+ libssl-dev \
+ pkg-config \
+ curl \
+ gcc-multilib \
+ && curl https://sh.rustup.rs -sSf | sh -s -- -y --default-host i686-unknown-linux-gnu \
+ && git init \
+ && git remote add origin https://github.com/tgstation/rust-g
+
+COPY _build_dependencies.sh .
+
+RUN /bin/bash -c "source _build_dependencies.sh \
+ && git fetch --depth 1 origin \$RUST_G_VERSION" \
+ && git checkout FETCH_HEAD \
+ && ~/.cargo/bin/cargo build --release
+
+FROM base as dm_base
+
+WORKDIR /vorestation
+
+FROM dm_base as build
+
+COPY . .
+
+RUN DreamMaker -max_errors 0 vorestation.dme
+
+FROM dm_base
+
+EXPOSE 2303
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends software-properties-common \
+ && add-apt-repository ppa:ubuntu-toolchain-r/test \
+ && apt-get update \
+ && apt-get upgrade -y \
+ && apt-get dist-upgrade -y \
+ && apt-get install -y --no-install-recommends \
+ libmariadb2 \
+ mariadb-client \
+ libssl1.0.0 \
+ && rm -rf /var/lib/apt/lists/* \
+ && mkdir -p /root/.byond/bin
+
+COPY --from=rust_g /rust_g/target/release/librust_g.so /root/.byond/bin/rust_g
+COPY --from=build /vorestation/ ./
+
+#VOLUME [ "/vorestation/config", "/vorestation/data" ]
+
+ENTRYPOINT [ "DreamDaemon", "vorestation.dmb", "-port", "2303", "-trusted", "-close", "-verbose" ]
diff --git a/code/__defines/chemistry.dm b/code/__defines/chemistry.dm
index 0976ed5ea36..f1de2ddd45e 100644
--- a/code/__defines/chemistry.dm
+++ b/code/__defines/chemistry.dm
@@ -49,3 +49,11 @@ var/list/tachycardics = list("coffee", "inaprovaline", "hyperzine", "nitroglyce
var/list/bradycardics = list("neurotoxin", "cryoxadone", "clonexadone", "space_drugs", "stoxin") // Decrease heart rate.
var/list/heartstopper = list("potassium_chlorophoride", "zombie_powder") // This stops the heart.
var/list/cheartstopper = list("potassium_chloride") // This stops the heart when overdose is met. -- c = conditional
+
+#define MAX_PILL_SPRITE 24 //max icon state of the pill sprites
+#define MAX_BOTTLE_SPRITE 4 //max icon state of the pill sprites
+#define MAX_MULTI_AMOUNT 20 // Max number of pills/patches that can be made at once
+#define MAX_UNITS_PER_PILL 60 // Max amount of units in a pill
+#define MAX_UNITS_PER_PATCH 60 // Max amount of units in a patch
+#define MAX_UNITS_PER_BOTTLE 60 // Max amount of units in a bottle (it's volume)
+#define MAX_CUSTOM_NAME_LEN 64 // Max length of a custom pill/condiment/whatever
\ No newline at end of file
diff --git a/code/__defines/materials.dm b/code/__defines/materials.dm
new file mode 100644
index 00000000000..499c974b475
--- /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 e9e7126dbe6..bb0387ab4ee 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
@@ -504,3 +445,7 @@ GLOBAL_LIST_INIT(all_volume_channels, list(
#define APPEARANCECHANGER_CHANGED_EYES "Eye Color"
#define GET_DECL(D) (ispath(D, /decl) ? (decls_repository.fetched_decls[D] || decls_repository.get_decl(D)) : null)
+
+#define LOADOUT_WHITELIST_OFF 0
+#define LOADOUT_WHITELIST_LAX 1
+#define LOADOUT_WHITELIST_STRICT 2
\ No newline at end of file
diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 1e2b2e63f30..1b77745067e 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -272,6 +272,10 @@
#define TASTE_DULL 0.5 //anything below 30%
#define TASTE_NUMB 0.1 //anything below 150%
+//Used by emotes
+#define VISIBLE_MESSAGE 1
+#define AUDIBLE_MESSAGE 2
+
// If they're in an FBP, what braintype.
#define FBP_NONE ""
#define FBP_CYBORG "Cyborg"
@@ -436,3 +440,5 @@
#define MAX_NUTRITION 5000 //VOREStation Edit
#define FAKE_INVIS_ALPHA_THRESHOLD 127 // If something's alpha var is at or below this number, certain things will pretend it is invisible.
+
+#define DEATHGASP_NO_MESSAGE "no message"
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 67d14623cf6..1f82939221a 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -284,7 +284,10 @@ var/list/gamemode_cache = list()
var/static/disable_cid_warn_popup = FALSE
// whether or not to use the nightshift subsystem to perform lighting changes
- var/static/enable_night_shifts = FALSE
+ var/static/enable_night_shifts = FALSE
+
+ // How strictly the loadout enforces object species whitelists
+ var/loadout_whitelist = LOADOUT_WHITELIST_LAX
var/static/vgs_access_identifier = null // VOREStation Edit - VGS
var/static/vgs_server_port = null // VOREStation Edit - VGS
diff --git a/code/controllers/subsystems/chemistry.dm b/code/controllers/subsystems/chemistry.dm
new file mode 100644
index 00000000000..148e9755421
--- /dev/null
+++ b/code/controllers/subsystems/chemistry.dm
@@ -0,0 +1,58 @@
+SUBSYSTEM_DEF(chemistry)
+ name = "Chemistry"
+ wait = 20
+ flags = SS_NO_FIRE
+ init_order = INIT_ORDER_CHEMISTRY
+
+ var/list/chemical_reactions = list()
+ var/list/instant_reactions_by_reagent = list()
+ var/list/distilled_reactions_by_reagent = list()
+// var/list/fusion_reactions_by_reagent = list() // TODO: Fusion reactions as chemical reactions
+ var/list/chemical_reagents = list()
+
+/datum/controller/subsystem/chemistry/Recover()
+ log_debug("[name] subsystem Recover().")
+ chemical_reactions = SSchemistry.chemical_reactions
+ chemical_reagents = SSchemistry.chemical_reagents
+
+/datum/controller/subsystem/chemistry/Initialize()
+ initialize_chemical_reagents()
+ initialize_chemical_reactions()
+ ..()
+
+/datum/controller/subsystem/chemistry/stat_entry()
+ ..("C: [chemical_reagents.len] | R: [chemical_reactions.len]")
+
+//Chemical Reactions - Initialises all /decl/chemical_reaction into a list
+// It is filtered into multiple lists within a list.
+// For example:
+// chemical_reactions_by_reagent["phoron"] is a list of all reactions relating to phoron
+// Note that entries in the list are NOT duplicated. So if a reaction pertains to
+// more than one chemical it will still only appear in only one of the sublists.
+/datum/controller/subsystem/chemistry/proc/initialize_chemical_reactions()
+ var/list/paths = decls_repository.get_decls_of_subtype(/decl/chemical_reaction)
+
+ for(var/path in paths)
+ var/decl/chemical_reaction/D = paths[path]
+ chemical_reactions += D
+ if(D.required_reagents && D.required_reagents.len)
+ var/reagent_id = D.required_reagents[1]
+
+ var/list/add_to = instant_reactions_by_reagent // Default to instant reactions list, if something's gone wrong
+// if(istype(D, /decl/chemical_reaction/fusion)) // TODO: fusion reactions as chemical reactions
+// add_to = fusion_reactions_by_reagent
+ if(istype(D, /decl/chemical_reaction/distilling))
+ add_to = distilled_reactions_by_reagent
+
+ LAZYINITLIST(add_to[reagent_id])
+ add_to[reagent_id] += D
+
+//Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
+/datum/controller/subsystem/chemistry/proc/initialize_chemical_reagents()
+ var/paths = subtypesof(/datum/reagent)
+ chemical_reagents = list()
+ for(var/path in paths)
+ var/datum/reagent/D = new path()
+ if(!D.name)
+ continue
+ chemical_reagents[D.id] = D
diff --git a/code/controllers/subsystems/processing/chemistry.dm b/code/controllers/subsystems/processing/chemistry.dm
deleted file mode 100644
index b4641ba7e00..00000000000
--- a/code/controllers/subsystems/processing/chemistry.dm
+++ /dev/null
@@ -1,54 +0,0 @@
-PROCESSING_SUBSYSTEM_DEF(chemistry)
- name = "Chemistry"
- wait = 20
- flags = SS_BACKGROUND|SS_POST_FIRE_TIMING
- init_order = INIT_ORDER_CHEMISTRY
- var/list/chemical_reactions = list()
- var/list/chemical_reactions_by_reagent = list()
- var/list/chemical_reagents = list()
-
-/datum/controller/subsystem/processing/chemistry/Recover()
- log_debug("[name] subsystem Recover().")
- if(SSchemistry.current_thing)
- log_debug("current_thing was: (\ref[SSchemistry.current_thing])[SSchemistry.current_thing]([SSchemistry.current_thing.type]) - currentrun: [SSchemistry.currentrun.len] vs total: [SSchemistry.processing.len]")
- var/list/old_processing = SSchemistry.processing.Copy()
- for(var/datum/D in old_processing)
- if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
- processing |= D
-
- chemical_reactions = SSchemistry.chemical_reactions
- chemical_reagents = SSchemistry.chemical_reagents
-
-/datum/controller/subsystem/processing/chemistry/Initialize()
- initialize_chemical_reactions()
- initialize_chemical_reagents()
- ..()
-
-//Chemical Reactions - Initialises all /datum/chemical_reaction into a list
-// It is filtered into multiple lists within a list.
-// For example:
-// chemical_reaction_list["phoron"] is a list of all reactions relating to phoron
-// Note that entries in the list are NOT duplicated. So if a reaction pertains to
-// more than one chemical it will still only appear in only one of the sublists.
-/datum/controller/subsystem/processing/chemistry/proc/initialize_chemical_reactions()
- var/paths = typesof(/datum/chemical_reaction) - /datum/chemical_reaction
- chemical_reactions = list()
- chemical_reactions_by_reagent = list()
-
- for(var/path in paths)
- var/datum/chemical_reaction/D = new path
- chemical_reactions += D
- if(D.required_reagents && D.required_reagents.len)
- var/reagent_id = D.required_reagents[1]
- LAZYINITLIST(chemical_reactions_by_reagent[reagent_id])
- chemical_reactions_by_reagent[reagent_id] += D
-
-//Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
-/datum/controller/subsystem/processing/chemistry/proc/initialize_chemical_reagents()
- var/paths = typesof(/datum/reagent) - /datum/reagent
- chemical_reagents = list()
- for(var/path in paths)
- var/datum/reagent/D = new path()
- if(!D.name)
- continue
- chemical_reagents[D.id] = D
diff --git a/code/datums/looping_sounds/weather_sounds.dm b/code/datums/looping_sounds/weather_sounds.dm
index 106c25643af..4a029930587 100644
--- a/code/datums/looping_sounds/weather_sounds.dm
+++ b/code/datums/looping_sounds/weather_sounds.dm
@@ -11,7 +11,7 @@
start_sound = 'sound/effects/weather/snowstorm/outside/active_start.ogg'
start_length = 13 SECONDS
end_sound = 'sound/effects/weather/snowstorm/outside/active_end.ogg'
- volume = 80
+ volume = 40
/datum/looping_sound/weather/inside_blizzard
mid_sounds = list(
@@ -23,7 +23,7 @@
start_sound = 'sound/effects/weather/snowstorm/inside/active_start.ogg'
start_length = 13 SECONDS
end_sound = 'sound/effects/weather/snowstorm/inside/active_end.ogg'
- volume = 60
+ volume = 20
/datum/looping_sound/weather/outside_snow
mid_sounds = list(
@@ -35,7 +35,7 @@
start_sound = 'sound/effects/weather/snowstorm/outside/weak_start.ogg'
start_length = 13 SECONDS
end_sound = 'sound/effects/weather/snowstorm/outside/weak_end.ogg'
- volume = 50
+ volume = 20
/datum/looping_sound/weather/inside_snow
mid_sounds = list(
@@ -47,7 +47,7 @@
start_sound = 'sound/effects/weather/snowstorm/inside/weak_start.ogg'
start_length = 13 SECONDS
end_sound = 'sound/effects/weather/snowstorm/inside/weak_end.ogg'
- volume = 30
+ volume = 10
/datum/looping_sound/weather/wind
mid_sounds = list(
@@ -59,11 +59,17 @@
'sound/effects/weather/wind/wind_5_1.ogg' = 1
)
mid_length = 10 SECONDS // The lengths for the files vary, but the longest is ten seconds, so this will make it sound like intermittent wind.
- volume = 50
+ volume = 45
// Don't have special sounds so we just make it quieter indoors.
/datum/looping_sound/weather/wind/indoors
- volume = 30
+ volume = 25
+
+/datum/looping_sound/weather/wind/gentle
+ volume = 15
+
+/datum/looping_sound/weather/wind/gentle/indoors
+ volume = 5
/datum/looping_sound/weather/rain
mid_sounds = list(
@@ -73,7 +79,13 @@
start_sound = 'sound/effects/weather/acidrain_start.ogg'
start_length = 13 SECONDS
end_sound = 'sound/effects/weather/acidrain_end.ogg'
- volume = 50
+ volume = 20
/datum/looping_sound/weather/rain/indoors
- volume = 30
\ No newline at end of file
+ volume = 10
+
+/datum/looping_sound/weather/rain/heavy
+ volume = 40
+
+/datum/looping_sound/weather/rain/heavy/indoors
+ volume = 20
\ No newline at end of file
diff --git a/code/datums/supplypacks/engineering.dm b/code/datums/supplypacks/engineering.dm
index f295676402b..0529f5aedd4 100644
--- a/code/datums/supplypacks/engineering.dm
+++ b/code/datums/supplypacks/engineering.dm
@@ -247,11 +247,21 @@
/obj/item/clothing/suit/radiation = 3,
/obj/item/clothing/head/radiation = 3
)
- name = "Radiation suits package"
+ name = "Radiation suits package (Humanoid)"
cost = 20
containertype = /obj/structure/closet/radiation
containername = "Radiation suit locker"
+/datum/supply_pack/eng/radsuitteshari
+ contains = list(
+ /obj/item/clothing/suit/radiation/teshari = 3,
+ /obj/item/clothing/head/radiation/teshari = 3
+ )
+ name = "Radiation suits package (Teshari)"
+ cost = 40
+ containertype = /obj/structure/closet/crate/aether
+ containername = "Teshari radiation suit locker"
+
/datum/supply_pack/eng/pacman_parts
name = "P.A.C.M.A.N. portable generator parts"
cost = 25
diff --git a/code/datums/uplink/visible_weapons_vr.dm b/code/datums/uplink/visible_weapons_vr.dm
index d8df7d15eb8..764e30b12f9 100644
--- a/code/datums/uplink/visible_weapons_vr.dm
+++ b/code/datums/uplink/visible_weapons_vr.dm
@@ -2,11 +2,21 @@
* Highly Visible and Dangerous Weapons *
***************************************/
/datum/uplink_item/item/visible_weapons/holdout
- name = "Holdout Phaser"
+ name = "Frontier Holdout"
item_cost = 30
path = /obj/item/weapon/gun/energy/locked/frontier/holdout/unlocked
/datum/uplink_item/item/visible_weapons/frontier
- name = "Frontier Carbine"
+ name = "Frontier Phaser"
item_cost = 75
+ path = /obj/item/weapon/gun/energy/locked/frontier/unlocked
+
+/datum/uplink_item/item/visible_weapons/carbine
+ name = "Frontier Carbine"
+ item_cost = 85
path = /obj/item/weapon/gun/energy/locked/frontier/carbine/unlocked
+
+/datum/uplink_item/item/visible_weapons/rifle
+ name = "Frontier Marksman Rifle"
+ item_cost = 100
+ path = /obj/item/weapon/gun/energy/locked/frontier/rifle/unlocked
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index e4ad20f5d48..46f001c8e1b 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -490,7 +490,7 @@
// Use for objects performing visible actions
// message is output to anyone who can see, e.g. "The [src] does something!"
// blind_message (optional) is what blind people will hear e.g. "You hear something!"
-/atom/proc/visible_message(var/message, var/blind_message, var/list/exclude_mobs = null)
+/atom/proc/visible_message(var/message, var/blind_message, var/list/exclude_mobs, var/range = world.view)
//VOREStation Edit
var/list/see
@@ -498,7 +498,7 @@
var/obj/belly/B = loc
see = B.get_mobs_and_objs_in_belly()
else
- see = get_mobs_and_objs_in_view_fast(get_turf(src),world.view,remote_ghosts = FALSE)
+ see = get_mobs_and_objs_in_view_fast(get_turf(src), range, remote_ghosts = FALSE)
//VOREStation Edit End
var/list/seeing_mobs = see["mobs"]
@@ -508,20 +508,20 @@
for(var/obj in seeing_objs)
var/obj/O = obj
- O.show_message(message, 1, blind_message, 2)
+ O.show_message(message, VISIBLE_MESSAGE, blind_message, AUDIBLE_MESSAGE)
for(var/mob in seeing_mobs)
var/mob/M = mob
if(M.see_invisible >= invisibility && MOB_CAN_SEE_PLANE(M, plane))
- M.show_message(message, 1, blind_message, 2)
+ M.show_message(message, VISIBLE_MESSAGE, blind_message, AUDIBLE_MESSAGE)
else if(blind_message)
- M.show_message(blind_message, 2)
+ M.show_message(blind_message, AUDIBLE_MESSAGE)
// Show a message to all mobs and objects in earshot of this atom
// Use for objects performing audible actions
// message is the message output to anyone who can hear.
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
-/atom/proc/audible_message(var/message, var/deaf_message, var/hearing_distance)
+/atom/proc/audible_message(var/message, var/deaf_message, var/hearing_distance, var/radio_message)
var/range = hearing_distance || world.view
var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src),range,remote_ghosts = FALSE)
@@ -529,14 +529,19 @@
var/list/hearing_mobs = hear["mobs"]
var/list/hearing_objs = hear["objs"]
- for(var/obj in hearing_objs)
- var/obj/O = obj
- O.show_message(message, 2, deaf_message, 1)
+ if(radio_message)
+ for(var/obj in hearing_objs)
+ var/obj/O = obj
+ O.hear_talk(src, list(new /datum/multilingual_say_piece(GLOB.all_languages["Noise"], radio_message)), null)
+ else
+ for(var/obj in hearing_objs)
+ var/obj/O = obj
+ O.show_message(message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
for(var/mob in hearing_mobs)
var/mob/M = mob
var/msg = message
- M.show_message(msg, 2, deaf_message, 1)
+ M.show_message(msg, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
/atom/movable/proc/dropInto(var/atom/destination)
while(istype(destination))
@@ -647,4 +652,7 @@
/atom/Exited(atom/movable/AM, atom/new_loc)
. = ..()
- SEND_SIGNAL(src, COMSIG_ATOM_EXITED, AM, new_loc)
\ No newline at end of file
+ SEND_SIGNAL(src, COMSIG_ATOM_EXITED, AM, new_loc)
+
+/atom/proc/get_visible_gender()
+ return gender
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index 5b4305844ef..f17c97a627b 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -507,7 +507,6 @@
log_and_message_admins("[key_name(to_despawn)] ([to_despawn.mind.role_alt_title]) entered cryostorage.")
announce.autosay("[to_despawn.real_name], [to_despawn.mind.role_alt_title], [on_store_message]", "[on_store_name]", announce_channel, using_map.get_map_levels(z, TRUE, om_range = DEFAULT_OVERMAP_RANGE))
- //visible_message("\The [initial(name)] hums and hisses as it moves [to_despawn.real_name] into storage.", 3)
visible_message("\The [initial(name)] [on_store_visible_message_1] [to_despawn.real_name] [on_store_visible_message_2]", 3)
//VOREStation Edit begin: Dont delete mobs-in-mobs
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 8175ee91dae..27e54fd6430 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -634,10 +634,6 @@
model_text = "Exploration"
departments = list("Exploration","Expedition Medic","Old Exploration","No Change")
-/obj/machinery/suit_cycler/exploration/Initialize()
- species -= SPECIES_TESHARI
- return ..()
-
/obj/machinery/suit_cycler/pilot
name = "Pilot suit cycler"
model_text = "Pilot"
diff --git a/code/game/machinery/vending_machines_vr.dm b/code/game/machinery/vending_machines_vr.dm
index 94a55bba1b4..e6c5058881d 100644
--- a/code/game/machinery/vending_machines_vr.dm
+++ b/code/game/machinery/vending_machines_vr.dm
@@ -4614,3 +4614,36 @@
/obj/machinery/vending/cola/soft
icon = 'icons/obj/vending_vr.dmi'
icon_state = "Cola_Machine"
+
+//////////////////////Bepis Drinks (04/29/2021)//////////////////////
+
+/obj/machinery/vending/bepis
+ name = "Bepis Softdrinks"
+ desc = "A strange softdrink vendor that isn't owned by NanoTrasen... Why (and how) is it here?"
+ icon = 'icons/obj/vending_vr.dmi'
+ icon_state = "bepis"
+ product_slogans = "Refreshing!;Have a sip, you won't believe the taste!;Puts the 'B' in Best Soda!"
+ product_ads = "Refreshing!;Hope you're thirsty!;Please, have a drink!;Drink up!"
+ products = list(/obj/item/weapon/reagent_containers/food/drinks/cans/bepis = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/astrodew = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/buzz = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/shambler = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/cranberry = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/icecoffee = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/gingerale = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/root_beer = 10)
+
+ prices = list(/obj/item/weapon/reagent_containers/food/drinks/cans/bepis = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/astrodew = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/buzz = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/shambler = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/cranberry = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/icecoffee = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/gingerale = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/root_beer = 1)
+ idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan.
+ vending_sound = "machines/vending/vending_cans.ogg"
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 21775d0403c..6e10f0e783d 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -552,9 +552,7 @@ var/list/global/slot_flags_enumeration = list(
if(!hit_zone)
U.do_attack_animation(M)
playsound(src, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- //visible_message("[U] attempts to stab [M] in the eyes, but misses!")
- for(var/mob/V in viewers(M))
- V.show_message("[U] attempts to stab [M] in the eyes, but misses!")
+ visible_message(SPAN_DANGER("\The [U] attempts to stab \the [M] in the eyes, but misses!"))
return
add_attack_logs(user,M,"Attack eyes with [name]")
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 c2535ec3eb8..00000000000
--- 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 c48f57e693a..00000000000
--- 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/game/objects/items/weapons/material/misc.dm b/code/game/objects/items/weapons/material/misc.dm
index bfa8b616805..7dbb927f853 100644
--- a/code/game/objects/items/weapons/material/misc.dm
+++ b/code/game/objects/items/weapons/material/misc.dm
@@ -74,14 +74,12 @@
/obj/item/weapon/material/snow/snowball/attack_self(mob/user as mob)
if(user.a_intent == I_HURT)
- //visible_message("[user] has smashed the snowball in their hand!", "You smash the snowball in your hand.")
- to_chat(user, "You smash the snowball in your hand.")
+ to_chat(user, SPAN_NOTICE("You smash the snowball in your hand."))
var/atom/S = new /obj/item/stack/material/snow(user.loc)
qdel(src)
user.put_in_hands(S)
else
- //visible_message("[user] starts compacting the snowball.", "You start compacting the snowball.")
- to_chat(user, "You start compacting the snowball.")
+ to_chat(user, SPAN_NOTICE("You start compacting the snowball."))
if(do_after(user, 2 SECONDS))
var/atom/S = new /obj/item/weapon/material/snow/snowball/reinforced(user.loc)
qdel(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/misc_vr.dm b/code/game/objects/structures/crates_lockers/closets/misc_vr.dm
index 4b6c275a1a1..6be3942fd7e 100644
--- a/code/game/objects/structures/crates_lockers/closets/misc_vr.dm
+++ b/code/game/objects/structures/crates_lockers/closets/misc_vr.dm
@@ -176,7 +176,6 @@
/obj/item/stack/marker_beacon/thirty,
/obj/item/weapon/material/knife/tacknife/survival,
/obj/item/weapon/material/knife/machete/deluxe,
- /obj/item/weapon/gun/energy/locked/frontier/carbine,
/obj/item/clothing/accessory/holster/machete,
/obj/random/explorer_shield,
/obj/item/weapon/reagent_containers/food/snacks/liquidfood,
diff --git a/code/modules/admin/admin_vr.dm b/code/modules/admin/admin_vr.dm
index 356d69a3761..e40db3f525a 100644
--- a/code/modules/admin/admin_vr.dm
+++ b/code/modules/admin/admin_vr.dm
@@ -8,5 +8,7 @@
traitors.spawn_uplink(H)
H.mind.tcrystals = DEFAULT_TELECRYSTAL_AMOUNT
H.mind.accept_tcrystals = 1
+ var/msg = "[key_name(usr)] has given [H.ckey] an uplink."
+ message_admins(msg)
else
to_chat(usr, "You do not have access to this command.")
\ No newline at end of file
diff --git a/code/modules/blob2/core_chunk.dm b/code/modules/blob2/core_chunk.dm
index 4abc06843eb..15db91e89ec 100644
--- a/code/modules/blob2/core_chunk.dm
+++ b/code/modules/blob2/core_chunk.dm
@@ -118,19 +118,19 @@
return FALSE
-/datum/chemical_reaction/blob_reconstitution
+/decl/chemical_reaction/instant/blob_reconstitution
name = "Hostile Blob Revival"
id = "blob_revival"
result = null
required_reagents = list("phoron" = 60)
result_amount = 1
-/datum/chemical_reaction/blob_reconstitution/can_happen(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/blob_reconstitution/can_happen(var/datum/reagents/holder)
if(holder.my_atom && istype(holder.my_atom, /obj/item/weapon/blobcore_chunk))
return ..()
return FALSE
-/datum/chemical_reaction/blob_reconstitution/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/blob_reconstitution/on_reaction(var/datum/reagents/holder)
var/obj/item/weapon/blobcore_chunk/chunk = holder.my_atom
if(chunk.can_genesis && chunk.regen())
chunk.visible_message("[chunk] bubbles, surrounding itself with a rapidly expanding mass of [chunk.blob_type.name]!")
@@ -138,14 +138,14 @@
else
chunk.visible_message("[chunk] shifts strangely, but falls still.")
-/datum/chemical_reaction/blob_reconstitution/domination
+/decl/chemical_reaction/instant/blob_reconstitution/domination
name = "Allied Blob Revival"
id = "blob_friend"
result = null
required_reagents = list("hydrophoron" = 40, "peridaxon" = 20, "mutagen" = 20)
result_amount = 1
-/datum/chemical_reaction/blob_reconstitution/domination/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/blob_reconstitution/domination/on_reaction(var/datum/reagents/holder)
var/obj/item/weapon/blobcore_chunk/chunk = holder.my_atom
if(chunk.can_genesis && chunk.regen("neutral"))
chunk.visible_message("[chunk] bubbles, surrounding itself with a rapidly expanding mass of [chunk.blob_type.name]!")
diff --git a/code/modules/client/preference_setup/general/02_language.dm b/code/modules/client/preference_setup/general/02_language.dm
index 673e273af0b..783358d692b 100644
--- a/code/modules/client/preference_setup/general/02_language.dm
+++ b/code/modules/client/preference_setup/general/02_language.dm
@@ -15,8 +15,18 @@
if(!islist(pref.alternate_languages)) pref.alternate_languages = list()
if(pref.species)
var/datum/species/S = GLOB.all_species[pref.species]
- if(S && pref.alternate_languages.len > S.num_alternate_languages)
+ if(!istype(S))
+ return
+
+ if(pref.alternate_languages.len > S.num_alternate_languages)
pref.alternate_languages.len = S.num_alternate_languages // Truncate to allowed length
+
+ // Sanitize illegal languages
+ for(var/language in pref.alternate_languages)
+ var/datum/language/L = GLOB.all_languages[language]
+ if((L.flags & RESTRICTED) || (!(language in S.secondary_langs) && !is_lang_whitelisted(pref.client, L)))
+ pref.alternate_languages -= language
+
if(isnull(pref.language_prefixes) || !pref.language_prefixes.len)
pref.language_prefixes = config.language_prefixes.Copy()
for(var/prefix in pref.language_prefixes)
diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm
index 949d613b6b5..15f079d31cb 100644
--- a/code/modules/client/preference_setup/general/03_body.dm
+++ b/code/modules/client/preference_setup/general/03_body.dm
@@ -37,6 +37,43 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
var/g_wing3 = 30 // Wing tertiary color
var/b_wing3 = 30 // Wing tertiary color
+// Sanitize ear/wing/tail styles
+/datum/preferences/proc/sanitize_body_styles()
+
+ // Grandfather in anyone loading paths from a save.
+ if(ispath(ear_style, /datum/sprite_accessory))
+ var/datum/sprite_accessory/instance = global.ear_styles_list[ear_style]
+ if(istype(instance))
+ ear_style = instance.name
+ if(ispath(wing_style, /datum/sprite_accessory))
+ var/datum/sprite_accessory/instance = global.wing_styles_list[wing_style]
+ if(istype(instance))
+ wing_style = instance.name
+ if(ispath(tail_style, /datum/sprite_accessory))
+ var/datum/sprite_accessory/instance = global.tail_styles_list[tail_style]
+ if(istype(instance))
+ tail_style = instance.name
+
+ // Sanitize for non-existent keys.
+ if(ear_style && !(ear_style in get_available_styles(global.ear_styles_list)))
+ ear_style = null
+ if(wing_style && !(wing_style in get_available_styles(global.wing_styles_list)))
+ wing_style = null
+ if(tail_style && !(tail_style in get_available_styles(global.tail_styles_list)))
+ tail_style = null
+
+/datum/preferences/proc/get_available_styles(var/style_list)
+ . = list("Normal" = null)
+ for(var/path in style_list)
+ var/datum/sprite_accessory/instance = style_list[path]
+ if(!istype(instance))
+ continue
+ if(instance.ckeys_allowed && (!client || !(client.ckey in instance.ckeys_allowed)))
+ continue
+ if(instance.species_allowed && (!species || !(species in instance.species_allowed)) && (!client || !check_rights(R_ADMIN | R_EVENT | R_FUN, 0, client)))
+ continue
+ .[instance.name] = instance
+
/datum/category_item/player_setup_item/general/body
name = "Body"
sort_order = 3
@@ -228,21 +265,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.r_wing3 = sanitize_integer(pref.r_wing3, 0, 255, initial(pref.r_wing3))
pref.g_wing3 = sanitize_integer(pref.g_wing3, 0, 255, initial(pref.g_wing3))
pref.b_wing3 = sanitize_integer(pref.b_wing3, 0, 255, initial(pref.b_wing3))
- if(pref.ear_style)
- pref.ear_style = sanitize_inlist(pref.ear_style, ear_styles_list, initial(pref.ear_style))
- var/datum/sprite_accessory/temp_ear_style = ear_styles_list[pref.ear_style]
- if(temp_ear_style.apply_restrictions && (!(pref.species in temp_ear_style.species_allowed)))
- pref.ear_style = initial(pref.ear_style)
- if(pref.tail_style)
- pref.tail_style = sanitize_inlist(pref.tail_style, tail_styles_list, initial(pref.tail_style))
- var/datum/sprite_accessory/temp_tail_style = tail_styles_list[pref.tail_style]
- if(temp_tail_style.apply_restrictions && (!(pref.species in temp_tail_style.species_allowed)))
- pref.tail_style = initial(pref.tail_style)
- if(pref.wing_style)
- pref.wing_style = sanitize_inlist(pref.wing_style, wing_styles_list, initial(pref.wing_style))
- var/datum/sprite_accessory/temp_wing_style = wing_styles_list[pref.wing_style]
- if(temp_wing_style.apply_restrictions && (!(pref.species in temp_wing_style.species_allowed)))
- pref.wing_style = initial(pref.wing_style)
+
+ pref.sanitize_body_styles()
// Moved from /datum/preferences/proc/copy_to()
/datum/category_item/player_setup_item/general/body/copy_to_mob(var/mob/living/carbon/human/character)
@@ -274,37 +298,44 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
character.g_synth = pref.g_synth
character.b_synth = pref.b_synth
character.synth_markings = pref.synth_markings
- character.ear_style = ear_styles_list[pref.ear_style]
- character.r_ears = pref.r_ears
- character.b_ears = pref.b_ears
- character.g_ears = pref.g_ears
- character.r_ears2 = pref.r_ears2
- character.b_ears2 = pref.b_ears2
- character.g_ears2 = pref.g_ears2
- character.r_ears3 = pref.r_ears3
- character.b_ears3 = pref.b_ears3
- character.g_ears3 = pref.g_ears3
- character.tail_style = tail_styles_list[pref.tail_style]
- character.r_tail = pref.r_tail
- character.b_tail = pref.b_tail
- character.g_tail = pref.g_tail
- character.r_tail2 = pref.r_tail2
- character.b_tail2 = pref.b_tail2
- character.g_tail2 = pref.g_tail2
- character.r_tail3 = pref.r_tail3
- character.b_tail3 = pref.b_tail3
- character.g_tail3 = pref.g_tail3
- character.wing_style = wing_styles_list[pref.wing_style]
- character.r_wing = pref.r_wing
- character.b_wing = pref.b_wing
- character.g_wing = pref.g_wing
- character.r_wing2 = pref.r_wing2
- character.b_wing2 = pref.b_wing2
- character.g_wing2 = pref.g_wing2
- character.r_wing3 = pref.r_wing3
- character.b_wing3 = pref.b_wing3
- character.g_wing3 = pref.g_wing3
- character.set_gender( pref.biological_gender)
+
+ var/list/ear_styles = pref.get_available_styles(global.ear_styles_list)
+ character.ear_style = ear_styles[pref.ear_style]
+ character.r_ears = pref.r_ears
+ character.b_ears = pref.b_ears
+ character.g_ears = pref.g_ears
+ character.r_ears2 = pref.r_ears2
+ character.b_ears2 = pref.b_ears2
+ character.g_ears2 = pref.g_ears2
+ character.r_ears3 = pref.r_ears3
+ character.b_ears3 = pref.b_ears3
+ character.g_ears3 = pref.g_ears3
+
+ var/list/tail_styles = pref.get_available_styles(global.tail_styles_list)
+ character.tail_style = tail_styles[pref.tail_style]
+ character.r_tail = pref.r_tail
+ character.b_tail = pref.b_tail
+ character.g_tail = pref.g_tail
+ character.r_tail2 = pref.r_tail2
+ character.b_tail2 = pref.b_tail2
+ character.g_tail2 = pref.g_tail2
+ character.r_tail3 = pref.r_tail3
+ character.b_tail3 = pref.b_tail3
+ character.g_tail3 = pref.g_tail3
+
+ var/list/wing_styles = pref.get_available_styles(global.wing_styles_list)
+ character.wing_style = wing_styles[pref.wing_style]
+ character.r_wing = pref.r_wing
+ character.b_wing = pref.b_wing
+ character.g_wing = pref.g_wing
+ character.r_wing2 = pref.r_wing2
+ character.b_wing2 = pref.b_wing2
+ character.g_wing2 = pref.g_wing2
+ character.r_wing3 = pref.r_wing3
+ character.b_wing3 = pref.b_wing3
+ character.g_wing3 = pref.g_wing3
+
+ character.set_gender(pref.biological_gender)
// Destroy/cyborgize organs and limbs.
for(var/name in list(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM, BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG, BP_GROIN, BP_TORSO))
@@ -519,59 +550,47 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
. += "
Genetics Settings
"
- var/ear_display = "Normal"
- if(pref.ear_style && (pref.ear_style in ear_styles_list))
- var/datum/sprite_accessory/ears/instance = ear_styles_list[pref.ear_style]
- ear_display = instance.name
-
- else if(pref.ear_style)
- ear_display = "REQUIRES UPDATE"
+ var/list/ear_styles = pref.get_available_styles(global.ear_styles_list)
+ var/datum/sprite_accessory/ears/ear = ear_styles[pref.ear_style]
. += "Ears
"
- . += " Style: [ear_display]
"
- if(ear_styles_list[pref.ear_style])
- var/datum/sprite_accessory/ears/ear = ear_styles_list[pref.ear_style]
+ if(istype(ear))
+ . += " Style: [ear.name]
"
if(ear.do_colouration)
. += "Change Color [color_square(pref.r_ears, pref.g_ears, pref.b_ears)]
"
if(ear.extra_overlay)
. += "Change Secondary Color [color_square(pref.r_ears2, pref.g_ears2, pref.b_ears2)]
"
if(ear.extra_overlay2)
. += "Change Tertiary Color [color_square(pref.r_ears3, pref.g_ears3, pref.b_ears3)]
"
+ else
+ . += " Style: Select
"
- var/tail_display = "Normal"
- if(pref.tail_style && (pref.tail_style in tail_styles_list))
- var/datum/sprite_accessory/tail/instance = tail_styles_list[pref.tail_style]
- tail_display = instance.name
- else if(pref.tail_style)
- tail_display = "REQUIRES UPDATE"
+ var/list/tail_styles = pref.get_available_styles(global.tail_styles_list)
+ var/datum/sprite_accessory/tail/tail = tail_styles[pref.tail_style]
. += "Tail
"
- . += " Style: [tail_display]
"
-
- if(tail_styles_list[pref.tail_style])
- var/datum/sprite_accessory/tail/T = tail_styles_list[pref.tail_style]
- if(T.do_colouration)
+ if(istype(tail))
+ . += " Style: [tail.name]
"
+ if(tail.do_colouration)
. += "Change Color [color_square(pref.r_tail, pref.g_tail, pref.b_tail)]
"
- if(T.extra_overlay)
+ if(tail.extra_overlay)
. += "Change Secondary Color [color_square(pref.r_tail2, pref.g_tail2, pref.b_tail2)]
"
- if(T.extra_overlay2)
+ if(tail.extra_overlay2)
. += "Change Tertiary Color [color_square(pref.r_tail3, pref.g_tail3, pref.b_tail3)]
"
+ else
+ . += " Style: Select
"
- var/wing_display = "Normal"
- if(pref.wing_style && (pref.wing_style in wing_styles_list))
- var/datum/sprite_accessory/wing/instance = wing_styles_list[pref.wing_style]
- wing_display = instance.name
- else if(pref.wing_style)
- wing_display = "REQUIRES UPDATE"
+ var/list/wing_styles = pref.get_available_styles(global.wing_styles_list)
+ var/datum/sprite_accessory/wing/wings = wing_styles[pref.wing_style]
. += "Wing
"
- . += " Style: [wing_display]
"
-
- if(wing_styles_list[pref.wing_style])
- var/datum/sprite_accessory/wing/W = wing_styles_list[pref.wing_style]
- if(W.do_colouration)
+ if(istype(wings))
+ . += " Style: [wings.name]
"
+ if(wings.do_colouration)
. += "Change Color [color_square(pref.r_wing, pref.g_wing, pref.b_wing)]
"
- if(W.extra_overlay)
+ if(wings.extra_overlay)
. += "Change Secondary Color [color_square(pref.r_wing2, pref.g_wing2, pref.b_wing2)]
"
- if(W.extra_overlay2)
+ if(wings.extra_overlay2)
. += "Change Secondary Color [color_square(pref.r_wing3, pref.g_wing3, pref.b_wing3)]
"
+ else
+ . += " Style: Select
"
. += "
Body Markings +
"
. += ""
@@ -669,7 +688,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
reset_limbs() // Safety for species with incompatible manufacturers; easier than trying to do it case by case.
pref.body_markings.Cut() // Basically same as above.
-
+
+ pref.sanitize_body_styles()
+
var/min_age = get_min_age()
var/max_age = get_max_age()
pref.age = max(min(pref.age, max_age), min_age)
@@ -1085,17 +1106,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["ear_style"])
- // Construct the list of names allowed for this user.
- var/list/pretty_ear_styles = list("Normal" = null)
- for(var/path in ear_styles_list)
- var/datum/sprite_accessory/ears/instance = ear_styles_list[path]
- if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit
- pretty_ear_styles[instance.name] = path
-
- // Present choice to user
- var/new_ear_style = input(user, "Pick ears", "Character Preference", pref.ear_style) as null|anything in pretty_ear_styles
+ var/new_ear_style = input(user, "Select an ear style for this character:", "Character Preference", pref.ear_style) as null|anything in pref.get_available_styles(global.ear_styles_list)
if(new_ear_style)
- pref.ear_style = pretty_ear_styles[new_ear_style]
+ pref.ear_style = new_ear_style
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -1127,18 +1140,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["tail_style"])
- // Construct the list of names allowed for this user.
- var/list/pretty_tail_styles = list("Normal" = null)
- for(var/path in tail_styles_list)
- var/datum/sprite_accessory/tail/instance = tail_styles_list[path]
- if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit
- pretty_tail_styles[instance.name] = path
-
- // Present choice to user
- var/new_tail_style = input(user, "Pick tails", "Character Preference", pref.tail_style) as null|anything in pretty_tail_styles
+ var/new_tail_style = input(user, "Select a tail style for this character:", "Character Preference", pref.tail_style) as null|anything in pref.get_available_styles(global.tail_styles_list)
if(new_tail_style)
- pref.tail_style = pretty_tail_styles[new_tail_style]
-
+ pref.tail_style = new_tail_style
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["tail_color"])
@@ -1169,17 +1173,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["wing_style"])
- // Construct the list of names allowed for this user.
- var/list/pretty_wing_styles = list("Normal" = null)
- for(var/path in wing_styles_list)
- var/datum/sprite_accessory/wing/instance = wing_styles_list[path]
- if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit
- pretty_wing_styles[instance.name] = path
-
- // Present choice to user
- var/new_wing_style = input(user, "Pick wings", "Character Preference", pref.wing_style) as null|anything in pretty_wing_styles
+ var/new_wing_style = input(user, "Select a wing style for this character:", "Character Preference", pref.wing_style) as null|anything in pref.get_available_styles(global.wing_styles_list)
if(new_wing_style)
- pref.wing_style = pretty_wing_styles[new_wing_style]
+ pref.wing_style = new_wing_style
return TOPIC_REFRESH_UPDATE_PREVIEW
diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm
index c91b2314c89..e5822353990 100644
--- a/code/modules/client/preference_setup/loadout/loadout.dm
+++ b/code/modules/client/preference_setup/loadout/loadout.dm
@@ -62,12 +62,15 @@ var/list/gear_datums = list()
/datum/category_item/player_setup_item/loadout/proc/valid_gear_choices(var/max_cost)
. = list()
- var/mob/preference_mob = preference_mob()
+ var/mob/preference_mob = preference_mob() //VOREStation Add
for(var/gear_name in gear_datums)
var/datum/gear/G = gear_datums[gear_name]
- if(G.whitelisted && !is_alien_whitelisted(preference_mob, GLOB.all_species[G.whitelisted]))
- continue
+ if(G.whitelisted && config.loadout_whitelist != LOADOUT_WHITELIST_OFF)
+ if(config.loadout_whitelist == LOADOUT_WHITELIST_STRICT && G.whitelisted != pref.species)
+ continue
+ if(config.loadout_whitelist == LOADOUT_WHITELIST_LAX && !is_alien_whitelisted(preference_mob(), GLOB.all_species[G.whitelisted]))
+ continue
if(max_cost && G.cost > max_cost)
continue
//VOREStation Edit Start
diff --git a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
index 1b75e208ee7..52666a24190 100644
--- a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
@@ -632,6 +632,12 @@
ckeywhitelist = list("luminescentring")
character_name = list("Briana Moore")
+/datum/gear/fluff/entchtut_medal
+ path = /obj/item/clothing/accessory/medal/conduct
+ display_name = "Entchtut's Conduct Medal"
+ ckeywhitelist = list("littlebigkid2000")
+ character_name = list("Entchtut Cenein")
+
// M CKEYS
/datum/gear/fluff/phi_box
path = /obj/item/weapon/storage/box/fluff/phi
@@ -806,6 +812,18 @@
character_name = list("Clara Mali")
cost = 1
+/datum/gear/fluff/luna_sci_medal
+ path = /obj/item/clothing/accessory/medal/nobel_science
+ display_name = "LUNA's Nobel Science Award"
+ ckeywhitelist = list("residentcody")
+ character_name = list("LUNA")
+
+/datum/gear/fluff/luna_conduct_medal
+ path = /obj/item/clothing/accessory/medal/conduct
+ display_name = "LUNA's Distinguished Conduct Medal"
+ ckeywhitelist = list("residentcody")
+ character_name = list("LUNA")
+
/datum/gear/fluff/nikki_dorky_outfit
path = /obj/item/weapon/storage/box/fluff
display_name = "Nikki's Witchy Outfit"
diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm
index aaec0a08401..f607b9945ff 100644
--- a/code/modules/client/preference_setup/preference_setup.dm
+++ b/code/modules/client/preference_setup/preference_setup.dm
@@ -129,6 +129,7 @@
for(var/datum/category_item/player_setup_item/PI in items)
PI.load_character(S)
+
/datum/category_group/player_setup_category/proc/save_character(var/savefile/S)
// Sanitize all data, then save it
for(var/datum/category_item/player_setup_item/PI in items)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 0c32155812c..a98e0898510 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -169,8 +169,8 @@ datum/preferences
if(!IsGuestKey(C.key))
load_path(C.ckey)
if(load_preferences())
- if(load_character())
- return
+ load_character()
+
/datum/preferences/Destroy()
. = ..()
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index cb25e733967..cb2b3cf0b34 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -82,10 +82,8 @@
player_setup.load_character(S)
S.cd = "/character[default_slot]"
player_setup.save_character(S)
- sanitize_preferences()
- player_setup.load_character(S)
- clear_character_previews() // Recalculate them on next show
+ clear_character_previews() // VOREStation Edit
return 1
/datum/preferences/proc/save_character()
diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm
index 0ecbe0390d6..0dde614e048 100644
--- a/code/modules/clothing/suits/utility.dm
+++ b/code/modules/clothing/suits/utility.dm
@@ -78,7 +78,7 @@
* Radiation protection
*/
/obj/item/clothing/head/radiation
- name = "Radiation Hood"
+ name = "Radiation hood"
icon_state = "rad"
desc = "A hood with radiation protective properties. Label: Made with lead, do not eat insulation"
flags_inv = BLOCKHAIR
@@ -98,4 +98,20 @@
slowdown = 1.5
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100)
flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER
- item_flags = THICKMATERIAL
\ No newline at end of file
+ item_flags = THICKMATERIAL
+
+/obj/item/clothing/suit/radiation/teshari
+ name = "Small radiation suit"
+ desc = "A specialist suit that protects against radiation, designed specifically for use by Teshari. Made to order by Aether."
+ icon = 'icons/obj/clothing/species/teshari/suits.dmi'
+ icon_override = 'icons/mob/species/teshari/suit.dmi'
+ icon_state = "rad_fitted"
+ species_restricted = list(SPECIES_TESHARI)
+
+/obj/item/clothing/head/radiation/teshari
+ name = "Small radiation hood"
+ desc = "A specialist hood with radiation protective properties, designed specifically for use by Teshari. Made to order by Aether."
+ icon = 'icons/obj/clothing/species/teshari/hats.dmi'
+ icon_override = 'icons/mob/species/teshari/head.dmi'
+ icon_state = "rad_fitted"
+ species_restricted = list(SPECIES_TESHARI)
\ 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 fd1cb561b0e..3e85d62e460 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/modules/economy/price_list.dm b/code/modules/economy/price_list.dm
index 9e3fb438d82..839148ebaf2 100644
--- a/code/modules/economy/price_list.dm
+++ b/code/modules/economy/price_list.dm
@@ -13,7 +13,7 @@
//---Beverages---//
//***************//
-/datum/reagent/var/price_tag = null
+/datum/reagent/var/price_tag = 0
// Juices, soda and similar //
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 58107d9d0b4..9c2106adc01 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/modules/emotes/definitions/_mob.dm b/code/modules/emotes/definitions/_mob.dm
new file mode 100644
index 00000000000..8c10b4cde2f
--- /dev/null
+++ b/code/modules/emotes/definitions/_mob.dm
@@ -0,0 +1,41 @@
+var/list/_default_mob_emotes = list(
+ /decl/emote/visible,
+ /decl/emote/visible/scratch,
+ /decl/emote/visible/drool,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/sway,
+ /decl/emote/visible/sulk,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/twitch_v,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/roll,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/jump,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/collapse,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible,
+ /decl/emote/audible/hiss,
+ /decl/emote/audible/whimper,
+ /decl/emote/audible/gasp,
+ /decl/emote/audible/scretch,
+ /decl/emote/audible/choke,
+ /decl/emote/audible/moan,
+ /decl/emote/audible/gnarl,
+)
+
+/mob
+ var/list/usable_emotes
+
+/mob/proc/update_emotes(var/skip_sort)
+ usable_emotes = list()
+ for(var/emote in get_default_emotes())
+ var/decl/emote/emote_datum = decls_repository.get_decl(emote)
+ if(emote_datum.check_user(src))
+ usable_emotes[emote_datum.key] = emote_datum
+ if(!skip_sort)
+ usable_emotes = sortAssoc(usable_emotes)
+
+/mob/proc/get_default_emotes()
+ return global._default_mob_emotes
diff --git a/code/modules/emotes/definitions/_species.dm b/code/modules/emotes/definitions/_species.dm
new file mode 100644
index 00000000000..ff15df2fae5
--- /dev/null
+++ b/code/modules/emotes/definitions/_species.dm
@@ -0,0 +1,11 @@
+/datum/species
+ var/list/default_emotes = list()
+
+/mob/living/carbon/update_emotes(var/skip_sort)
+ . = ..(skip_sort = TRUE)
+ if(species)
+ for(var/emote in species.default_emotes)
+ var/decl/emote/emote_datum = decls_repository.get_decl(emote)
+ if(emote_datum.check_user(src))
+ usable_emotes[emote_datum.key] = emote_datum
+ usable_emotes = sortAssoc(usable_emotes)
diff --git a/code/modules/emotes/definitions/audible_cough.dm b/code/modules/emotes/definitions/audible_cough.dm
new file mode 100644
index 00000000000..4e28d1db918
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_cough.dm
@@ -0,0 +1,52 @@
+/decl/emote/audible/cough
+ key = "cough"
+ emote_message_1p = "You cough!"
+ emote_message_1p_target = "You cough on TARGET!"
+ emote_message_3p = "coughs!"
+ emote_message_3p_target = "coughs on TARGET!"
+ emote_message_synthetic_1p_target = "You emit a robotic cough towards TARGET."
+ emote_message_synthetic_1p = "You emit a robotic cough."
+ emote_message_synthetic_3p_target = "emits a robotic cough towards TARGET."
+ emote_message_synthetic_3p = "emits a robotic cough."
+ emote_volume = 120
+ emote_volume_synthetic = 50
+
+ conscious = FALSE
+ emote_sound_synthetic = list(
+ FEMALE = list(
+ 'sound/effects/mob_effects/f_machine_cougha.ogg',
+ 'sound/effects/mob_effects/f_machine_coughb.ogg'
+ ),
+ MALE = list(
+ 'sound/effects/mob_effects/m_machine_cougha.ogg',
+ 'sound/effects/mob_effects/m_machine_coughb.ogg',
+ 'sound/effects/mob_effects/m_machine_coughc.ogg'
+ ),
+ NEUTER = list(
+ 'sound/effects/mob_effects/m_machine_cougha.ogg',
+ 'sound/effects/mob_effects/m_machine_coughb.ogg',
+ 'sound/effects/mob_effects/m_machine_coughc.ogg'
+ ),
+ PLURAL = list(
+ 'sound/effects/mob_effects/m_machine_cougha.ogg',
+ 'sound/effects/mob_effects/m_machine_coughb.ogg',
+ 'sound/effects/mob_effects/m_machine_coughc.ogg'
+ )
+ )
+
+/decl/emote/audible/cough/get_emote_sound(var/atom/user)
+ if(ishuman(user) && !check_synthetic(user))
+ var/mob/living/carbon/human/H = user
+ if(H.get_gender() == FEMALE)
+ if(length(H.species.female_cough_sounds))
+ return list(
+ "sound" = H.species.female_cough_sounds,
+ "vol" = emote_volume
+ )
+ else
+ if(length(H.species.male_cough_sounds))
+ return list(
+ "sound" = H.species.male_cough_sounds,
+ "vol" = emote_volume
+ )
+ return ..()
diff --git a/code/modules/emotes/definitions/audible_furry_vr.dm b/code/modules/emotes/definitions/audible_furry_vr.dm
new file mode 100644
index 00000000000..681e9101a29
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_furry_vr.dm
@@ -0,0 +1,129 @@
+/decl/emote/audible/awoo
+ key = "awoo"
+ emote_message_3p = "lets out an awoo."
+ emote_sound = 'sound/voice/awoo.ogg'
+/decl/emote/audible/awoo2
+ key = "awoo2"
+ emote_message_3p = "lets out an awoo."
+ emote_sound = 'sound/voice/long_awoo.ogg'
+/decl/emote/audible/growl
+ key = "growl"
+ emote_message_3p = "lets out a growl."
+ emote_sound = 'sound/voice/growl.ogg'
+/decl/emote/audible/woof
+ key = "woof"
+ emote_message_3p = "lets out a woof."
+ emote_sound = 'sound/voice/woof.ogg'
+/decl/emote/audible/woof2
+ key = "woof2"
+ emote_message_3p = "lets out a woof."
+ emote_sound = 'sound/voice/woof2.ogg'
+/decl/emote/audible/nya
+ key = "nya"
+ emote_message_3p = "lets out a nya."
+ emote_sound = 'sound/voice/nya.ogg'
+/decl/emote/audible/mrowl
+ key = "mrowl"
+ emote_message_3p = "mrowls."
+ emote_sound = 'sound/voice/mrow.ogg'
+/decl/emote/audible/peep
+ key = "peep"
+ emote_message_3p = "peeps like a bird."
+ emote_sound = 'sound/voice/peep.ogg'
+/decl/emote/audible/chirp
+ key = "chirp"
+ emote_message_3p = "chirps!"
+ emote_sound = 'sound/misc/nymphchirp.ogg'
+/decl/emote/audible/hoot
+ key = "hoot"
+ emote_message_3p = "hoots!"
+ emote_sound = 'sound/voice/hoot.ogg'
+/decl/emote/audible/weh
+ key = "weh"
+ emote_message_3p = "lets out a weh."
+ emote_sound = 'sound/voice/weh.ogg'
+/decl/emote/audible/merp
+ key = "merp"
+ emote_message_3p = "lets out a merp."
+ emote_sound = 'sound/voice/merp.ogg'
+/decl/emote/audible/myarp
+ key = "myarp"
+ emote_message_3p = "lets out a myarp."
+ emote_sound = 'sound/voice/myarp.ogg'
+/decl/emote/audible/bark
+ key = "bark"
+ emote_message_3p = "lets out a bark."
+ emote_sound = 'sound/voice/bark2.ogg'
+/decl/emote/audible/bork
+ key = "bork"
+ emote_message_3p = "lets out a bork."
+ emote_sound = 'sound/voice/bork.ogg'
+/decl/emote/audible/mrow
+ emote_message_3p = "lets out a mrow."
+ emote_sound = 'sound/voice/mrow.ogg'
+/decl/emote/audible/hypno
+ emote_message_3p = "lets out a mystifying tone."
+ emote_sound = 'sound/voice/hypno.ogg'
+/decl/emote/audible/hiss
+ key = "hiss"
+ emote_message_3p = "lets out a hiss."
+ emote_sound = 'sound/voice/hiss.ogg'
+/decl/emote/audible/rattle
+ key = "rattle"
+ emote_message_3p = "rattles!"
+ emote_sound = 'sound/voice/rattle.ogg'
+/decl/emote/audible/squeak
+ key = "squeak"
+ emote_message_3p = "lets out a squeak."
+ emote_sound = 'sound/effects/mouse_squeak.ogg'
+/decl/emote/audible/geck
+ key = "geck"
+ emote_message_3p = "geckers!"
+ emote_sound = 'sound/voice/geck.ogg'
+/decl/emote/audible/baa
+ key = "baa"
+ emote_message_3p = "lets out a baa."
+ emote_sound = 'sound/voice/baa.ogg'
+/decl/emote/audible/baa2
+ key = "baa2"
+ emote_message_3p = "bleats."
+ emote_sound = 'sound/voice/baa2.ogg'
+/*
+/decl/emote/audible/deathgasp2
+ key = "deathgasp2"
+ emote_message_3p = "[species.get_death_message()]"
+ m_type = 1
+ emote_sound = 'sound/voice/deathgasp2.ogg'
+*/
+/decl/emote/audible/mar
+ key = "mar"
+ emote_message_3p = "lets out a mar."
+ emote_sound = 'sound/voice/mar.ogg'
+/decl/emote/audible/wurble
+ key = "wurble"
+ emote_message_3p = "lets out a wurble."
+ emote_sound = 'sound/voice/wurble.ogg'
+/decl/emote/audible/snort
+ key = "snort"
+ emote_message_3p = "snorts!"
+ emote_sound = 'sound/voice/Snort.ogg'
+/decl/emote/audible/meow
+ key = "meow"
+ emote_message_3p = "gently meows!"
+ emote_sound = 'sound/voice/Meow.ogg'
+/decl/emote/audible/moo
+ key = "moo"
+ emote_message_3p = "takes a breath and lets out a moo."
+ emote_sound = 'sound/voice/Moo.ogg'
+/decl/emote/audible/croak
+ key = "croak"
+ emote_message_3p = "rumbles their throat, puffs their cheeks and croaks."
+ emote_sound = 'sound/voice/Croak.ogg'
+/decl/emote/audible/gao
+ key = "gao"
+ emote_message_3p = "lets out a gao."
+ emote_sound = 'sound/voice/gao.ogg'
+/decl/emote/audible/cackle
+ key = "cackle"
+ emote_message_3p = "cackles hysterically!"
+ emote_sound = 'sound/voice/YeenCackle.ogg'
diff --git a/code/modules/emotes/definitions/audible_scream.dm b/code/modules/emotes/definitions/audible_scream.dm
new file mode 100644
index 00000000000..00ed9c29fc3
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_scream.dm
@@ -0,0 +1,16 @@
+/decl/emote/audible/scream
+ key = "scream"
+ emote_message_1p = "You scream!"
+ emote_message_3p = "screams!"
+
+/decl/emote/audible/scream/get_emote_message_1p(var/atom/user, var/atom/target, var/extra_params)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ return "You [H.species.scream_verb_1p]!"
+ . = ..()
+
+/decl/emote/audible/cough/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ return "[H.species.scream_verb_3p]!"
+ . = ..()
diff --git a/code/modules/emotes/definitions/audible_slap.dm b/code/modules/emotes/definitions/audible_slap.dm
new file mode 100644
index 00000000000..d0b5466c30c
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_slap.dm
@@ -0,0 +1,24 @@
+/decl/emote/audible/slap
+ key = "slap"
+ emote_message_1p_target = "You slap TARGET across the face. Ouch!"
+ emote_message_1p = "You slap yourself across the face!"
+ emote_message_3p_target = "slaps TARGET across the face. Ouch!"
+ emote_message_3p = "slaps USER_SELF across the face!"
+ emote_sound = 'sound/effects/snap.ogg'
+ check_restraints = TRUE
+ check_range = 1
+
+/decl/emote/audible/slap/New()
+ ..()
+ emote_message_1p_target = SPAN_DANGER(emote_message_1p_target)
+ emote_message_1p = SPAN_DANGER(emote_message_1p)
+ emote_message_3p_target = SPAN_DANGER(emote_message_3p_target)
+ emote_message_3p = SPAN_DANGER(emote_message_3p)
+
+/decl/emote/audible/slap/do_extra(var/atom/user, var/atom/target)
+ . = ..()
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ var/obj/item/clothing/mask/smokable/mask = H.wear_mask
+ if(istype(mask) && H.unEquip(mask))
+ mask.forceMove(get_turf(H))
diff --git a/code/modules/emotes/definitions/audible_sneeze.dm b/code/modules/emotes/definitions/audible_sneeze.dm
new file mode 100644
index 00000000000..a15cbaf46db
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_sneeze.dm
@@ -0,0 +1,29 @@
+/decl/emote/audible/sneeze
+ key = "sneeze"
+ emote_message_1p = "You sneeze."
+ emote_message_3p = "sneezes."
+ emote_sound_synthetic = list(
+ FEMALE = 'sound/effects/mob_effects/machine_sneeze.ogg',
+ MALE = 'sound/effects/mob_effects/f_machine_sneeze.ogg',
+ NEUTER = 'sound/effects/mob_effects/f_machine_sneeze.ogg',
+ PLURAL = 'sound/effects/mob_effects/f_machine_sneeze.ogg'
+ )
+ emote_message_synthetic_1p = "You emit a robotic sneeze."
+ emote_message_synthetic_1p_target = "You emit a robotic sneeze towards TARGET."
+ emote_message_synthetic_3p = "emits a robotic sneeze."
+ emote_message_synthetic_3p_target = "emits a robotic sneeze towards TARGET."
+
+/decl/emote/audible/sneeze/get_emote_sound(var/atom/user)
+ if(ishuman(user) && !check_synthetic(user))
+ var/mob/living/carbon/human/H = user
+ if(H.get_gender() == FEMALE)
+ return list(
+ "sound" = H.species.female_sneeze_sound,
+ "vol" = emote_volume
+ )
+ else
+ return list(
+ "sound" = H.species.male_sneeze_sound,
+ "vol" = emote_volume
+ )
+ return ..()
diff --git a/code/modules/emotes/definitions/audible_whistle.dm b/code/modules/emotes/definitions/audible_whistle.dm
new file mode 100644
index 00000000000..dabd64af59d
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_whistle.dm
@@ -0,0 +1,36 @@
+/decl/emote/audible/whistle
+ key = "whistle"
+ emote_message_1p = "You whistle a tune."
+ emote_message_3p = "whistles a tune."
+ emote_sound = 'sound/voice/longwhistle.ogg'
+ emote_message_muffled = "makes a light spitting noise, a poor attempt at a whistle."
+ emote_sound_synthetic = 'sound/voice/longwhistle_robot.ogg'
+ emote_message_synthetic_1p = "You whistle a robotic tune."
+ emote_message_synthetic_3p = "whistles a robotic tune."
+
+/decl/emote/audible/whistle/quiet
+ key = "qwhistle"
+ emote_message_1p = "You whistle quietly."
+ emote_message_3p = "whistles quietly."
+ emote_sound = 'sound/voice/shortwhistle.ogg'
+ emote_message_synthetic_1p = "You whistle robotically."
+ emote_message_synthetic_3p = "whistles robotically."
+ emote_sound_synthetic = 'sound/voice/shortwhistle_robot.ogg'
+
+/decl/emote/audible/whistle/wolf
+ key = "wwhistle"
+ emote_message_1p = "You whistle inappropriately."
+ emote_message_3p = "whistles inappropriately."
+ emote_sound = 'sound/voice/wolfwhistle.ogg'
+ emote_message_synthetic_1p = "You beep inappropriately."
+ emote_message_synthetic_3p = "beeps inappropriately."
+ emote_sound_synthetic = 'sound/voice/wolfwhistle_robot.ogg'
+
+/decl/emote/audible/whistle/summon
+ key = "swhistle"
+ emote_message_1p = "You whistle a tune."
+ emote_message_3p = "whistles a tune."
+ emote_sound = 'sound/voice/summon_whistle.ogg'
+ emote_message_synthetic_1p = "You whistle a robotic tune."
+ emote_message_synthetic_3p = "whistles a robotic tune."
+ emote_sound_synthetic = 'sound/voice/summon_whistle_robot.ogg'
diff --git a/code/modules/emotes/definitions/exertion.dm b/code/modules/emotes/definitions/exertion.dm
new file mode 100644
index 00000000000..ac0061cca32
--- /dev/null
+++ b/code/modules/emotes/definitions/exertion.dm
@@ -0,0 +1,40 @@
+/decl/emote/exertion/biological
+ key = "esweat"
+ emote_range = 4
+ emote_message_1p = "You are sweating heavily."
+ emote_message_3p = "is sweating heavily."
+
+/decl/emote/exertion/biological/check_user(mob/living/user)
+ if(istype(user) && !user.isSynthetic())
+ return ..()
+ return FALSE
+
+/decl/emote/exertion/biological/breath
+ key = "ebreath"
+ emote_message_1p = "You feel out of breath."
+ emote_message_3p = "looks out of breath."
+
+/decl/emote/exertion/biological/pant
+ key = "epant"
+ emote_range = 3
+ message_type = AUDIBLE_MESSAGE
+ emote_message_1p = "You pant to catch your breath."
+ emote_message_3p = "pants for air."
+ emote_message_impaired = "You can see USER breathing heavily."
+
+/decl/emote/exertion/synthetic
+ key = "ewhine"
+ emote_range = 3
+ message_type = AUDIBLE_MESSAGE
+ emote_message_1p = "You overstress your actuators."
+ emote_message_3p = "USER's actuators whine with strain."
+
+/decl/emote/exertion/synthetic/check_user(mob/living/user)
+ if(istype(user) && user.isSynthetic())
+ return ..()
+ return FALSE
+
+/decl/emote/exertion/synthetic/creak
+ key = "ecreak"
+ emote_message_1p = "Your chassis stress indicators spike."
+ emote_message_3p = "USER's joints creak with stress."
diff --git a/code/modules/emotes/definitions/helpers_vr.dm b/code/modules/emotes/definitions/helpers_vr.dm
new file mode 100644
index 00000000000..6dc3a79bddc
--- /dev/null
+++ b/code/modules/emotes/definitions/helpers_vr.dm
@@ -0,0 +1,33 @@
+// Not specifically /human type because those won't allow FBPs to use them
+/decl/emote/helper/vwag
+ key = "vwag"
+ emote_message_3p = ""
+
+/decl/emote/helper/vwag/check_user(mob/living/carbon/human/user)
+ if(!istype(user) || (!user.tail_style || !user.tail_style.ani_state))
+ return FALSE
+ return ..()
+
+/decl/emote/helper/vwag/do_emote(var/mob/living/carbon/human/user, var/extra_params)
+ if(user.toggle_tail(message = 1))
+ return ..()
+
+/decl/emote/helper/vwag/get_emote_message_3p(var/mob/living/carbon/human/user, var/atom/target, var/extra_params)
+ return "[user.wagging ? "starts" : "stops"] wagging USER_THEIR tail."
+
+
+/decl/emote/helper/vflap
+ key = "vflap"
+ emote_message_3p = ""
+
+/decl/emote/helper/vflap/check_user(mob/living/carbon/human/user)
+ if(!istype(user) || (!user.wing_style || !user.wing_style.ani_state))
+ return FALSE
+ return ..()
+
+/decl/emote/helper/vflap/do_emote(var/mob/living/carbon/human/user, var/extra_params)
+ if(user.toggle_wing(message = 1))
+ return ..()
+
+/decl/emote/helper/vflap/get_emote_message_3p(var/mob/living/carbon/human/user, var/atom/target, var/extra_params)
+ return "[user.flapping ? "starts" : "stops"] flapping USER_THEIR wings."
diff --git a/code/modules/emotes/definitions/human.dm b/code/modules/emotes/definitions/human.dm
new file mode 100644
index 00000000000..982e472c5f2
--- /dev/null
+++ b/code/modules/emotes/definitions/human.dm
@@ -0,0 +1,62 @@
+/decl/emote/human
+ key = "vomit"
+
+/decl/emote/human/check_user(var/mob/living/carbon/human/user)
+ return (istype(user))//VOREStation Edit - What does a mouth have to do with wagging?? && user.check_has_mouth() && !user.isSynthetic())
+
+/decl/emote/human/do_emote(var/mob/living/carbon/human/user)
+ user.vomit()
+
+/decl/emote/human/deathgasp
+ key = "deathgasp"
+
+/decl/emote/human/deathgasp/do_emote(mob/living/carbon/human/user)
+ if(istype(user) && user.species.get_death_message(user) == DEATHGASP_NO_MESSAGE)
+ to_chat(user, SPAN_WARNING("Your species has no deathgasp."))
+ return
+ . = ..()
+
+/decl/emote/human/deathgasp/get_emote_message_3p(var/mob/living/carbon/human/user)
+ return "USER [user.species.get_death_message(user)]"
+
+/decl/emote/human/swish
+ key = "swish"
+
+/decl/emote/human/swish/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_once()
+
+/decl/emote/human/wag
+ key = "wag"
+
+/decl/emote/human/wag/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_start()
+
+/decl/emote/human/sway
+ key = "sway"
+
+/decl/emote/human/sway/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_start()
+
+/decl/emote/human/qwag
+ key = "qwag"
+
+/decl/emote/human/qwag/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_fast()
+
+/decl/emote/human/fastsway
+ key = "fastsway"
+
+/decl/emote/human/fastsway/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_fast()
+
+/decl/emote/human/swag
+ key = "swag"
+
+/decl/emote/human/swag/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_stop()
+
+/decl/emote/human/stopsway
+ key = "stopsway"
+
+/decl/emote/human/stopsway/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_stop()
diff --git a/code/modules/emotes/definitions/slimes.dm b/code/modules/emotes/definitions/slimes.dm
new file mode 100644
index 00000000000..877422825ba
--- /dev/null
+++ b/code/modules/emotes/definitions/slimes.dm
@@ -0,0 +1,32 @@
+/decl/emote/slime
+ key = "nomood"
+ var/mood
+
+/decl/emote/slime/do_extra(var/mob/living/simple_mob/slime/user)
+ . = ..()
+ if(istype(user))
+ user.mood = mood
+ user.update_icon()
+
+/decl/emote/slime/check_user(var/atom/user)
+ return isslime(user)
+
+/decl/emote/slime/pout
+ key = "pout"
+ mood = "pout"
+
+/decl/emote/slime/sad
+ key = "sad"
+ mood = "sad"
+
+/decl/emote/slime/angry
+ key = "angry"
+ mood = "angry"
+
+/decl/emote/slime/frown
+ key = "frown"
+ mood = "mischevous"
+
+/decl/emote/slime/smile
+ key = "smile"
+ mood = ":3"
diff --git a/code/modules/emotes/definitions/visible_animated.dm b/code/modules/emotes/definitions/visible_animated.dm
new file mode 100644
index 00000000000..2e035d289c7
--- /dev/null
+++ b/code/modules/emotes/definitions/visible_animated.dm
@@ -0,0 +1,76 @@
+/decl/emote/visible/spin
+ key = "spin"
+ check_restraints = TRUE
+ emote_message_3p = "spins!"
+
+/decl/emote/visible/spin/do_extra(mob/user)
+ if(istype(user))
+ user.spin(20, 1)
+
+/decl/emote/visible/sidestep
+ key = "sidestep"
+ check_restraints = TRUE
+ emote_message_3p = "steps rhythmically and moves side to side."
+
+/decl/emote/visible/sidestep/do_extra(mob/user)
+ if(istype(user))
+ animate(user, pixel_x = 5, time = 5)
+ sleep(3)
+ animate(user, pixel_x = -5, time = 5)
+ animate(pixel_x = user.default_pixel_x, pixel_y = user.default_pixel_x, time = 2)
+
+/decl/emote/visible/flip
+ key = "flip"
+ emote_message_1p = "You do a flip!"
+ emote_message_3p = "does a flip!"
+ emote_sound = 'sound/effects/bodyfall4.ogg'
+
+/decl/emote/visible/flip/do_extra(mob/user)
+ . = ..()
+ if(istype(user))
+ user.SpinAnimation(7,1)
+
+/decl/emote/visible/floorspin
+ key = "floorspin"
+ emote_message_1p = "You spin around on the floor!"
+ emote_message_3p = "spins around on the floor!"
+ var/static/list/spin_dirs = list(
+ NORTH,
+ SOUTH,
+ EAST,
+ WEST,
+ EAST,
+ SOUTH,
+ NORTH,
+ SOUTH,
+ EAST,
+ WEST,
+ EAST,
+ SOUTH,
+ NORTH,
+ SOUTH,
+ EAST,
+ WEST,
+ EAST,
+ SOUTH
+ )
+
+/decl/emote/visible/floorspin/proc/spin_dir(var/mob/user)
+ set waitfor = FALSE
+ for(var/i in spin_dirs)
+ user.set_dir(i)
+ sleep(1)
+ if(QDELETED(user))
+ return
+
+/decl/emote/visible/floorspin/proc/spin_anim(var/mob/user)
+ set waitfor = FALSE
+ sleep(1)
+ if(!QDELETED(user))
+ user.SpinAnimation(10,1)
+
+/decl/emote/visible/floorspin/do_extra(mob/user)
+ . = ..()
+ if(istype(user))
+ spin_dir(user)
+ spin_anim(user)
diff --git a/code/modules/emotes/definitions/visible_vomit.dm b/code/modules/emotes/definitions/visible_vomit.dm
new file mode 100644
index 00000000000..1ec79dea6a9
--- /dev/null
+++ b/code/modules/emotes/definitions/visible_vomit.dm
@@ -0,0 +1,10 @@
+/decl/emote/visible/vomit
+ key = "vomit"
+
+/decl/emote/visible/vomit/do_emote(var/atom/user, var/extra_params)
+ if(isliving(user))
+ var/mob/living/M = user
+ if(!M.isSynthetic())
+ M.vomit()
+ return
+ to_chat(src, SPAN_WARNING("You are unable to vomit."))
diff --git a/code/modules/emotes/definitions/visible_vr.dm b/code/modules/emotes/definitions/visible_vr.dm
new file mode 100644
index 00000000000..69252cf43be
--- /dev/null
+++ b/code/modules/emotes/definitions/visible_vr.dm
@@ -0,0 +1,7 @@
+/decl/emote/visible/mlem
+ key = "mlem"
+ emote_message_3p = "mlems USER_THEIR tongue up over USER_THEIR nose. Mlem."
+
+/decl/emote/visible/blep
+ key = "blep"
+ emote_message_3p = "bleps USER_THEIR tongue out. Blep."
diff --git a/code/modules/emotes/emote_define.dm b/code/modules/emotes/emote_define.dm
new file mode 100644
index 00000000000..845a5202d31
--- /dev/null
+++ b/code/modules/emotes/emote_define.dm
@@ -0,0 +1,181 @@
+// Note about emote messages:
+// - USER / TARGET will be replaced with the relevant name, in bold.
+// - USER_THEM / TARGET_THEM / USER_THEIR / TARGET_THEIR will be replaced with a
+// gender-appropriate version of the same.
+// - Impaired messages do not do any substitutions.
+
+/decl/emote
+ var/key // Command to use emote ie. '*[key]'
+ var/emote_message_1p // First person message ('You do a flip!')
+ var/emote_message_3p // Third person message ('Urist McBackflip does a flip!')
+ var/emote_message_synthetic_1p // First person message for robits.
+ var/emote_message_synthetic_3p // Third person message for robits.
+
+ var/emote_message_impaired // Deaf/blind message ('You hear someone flipping out.', 'You see someone opening and closing their mouth')
+
+ var/emote_message_1p_target // 'You do a flip at Urist McTarget!'
+ var/emote_message_3p_target // 'Urist McShitter does a flip at Urist McTarget!'
+ var/emote_message_synthetic_1p_target // First person targeted message for robits.
+ var/emote_message_synthetic_3p_target // Third person targeted message for robits.
+
+ var/emote_message_radio // A message to send over the radio if one picks up this emote.
+ var/emote_message_radio_synthetic // As above, but for synthetics.
+ var/emote_message_muffled // A message to show if the emote is audible and the user is muzzled.
+
+ var/list/emote_sound // A sound for the emote to play.
+ // Can either be a single sound, a list of sounds to pick from, or an
+ // associative array of gender to single sounds/a list of sounds.
+ var/list/emote_sound_synthetic // As above, but used when check_synthetic() is true.
+ var/emote_volume = 50 // Volume of sound to play.
+ var/emote_volume_synthetic = 50 // As above, but used when check_synthetic() is true.
+
+ var/message_type = VISIBLE_MESSAGE // Audible/visual flag
+ var/check_restraints // Can this emote be used while restrained?
+ var/check_range // falsy, or a range outside which the emote will not work
+ var/conscious = TRUE // Do we need to be awake to emote this?
+ var/emote_range = 0 // If >0, restricts emote visibility to viewers within range.
+
+/decl/emote/proc/get_emote_message_1p(var/atom/user, var/atom/target, var/extra_params)
+ if(target)
+ if(emote_message_synthetic_1p_target && check_synthetic(user))
+ return emote_message_synthetic_1p_target
+ return emote_message_1p_target
+ if(emote_message_synthetic_1p && check_synthetic(user))
+ return emote_message_synthetic_1p
+ return emote_message_1p
+
+/decl/emote/proc/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params)
+ if(target)
+ if(emote_message_synthetic_3p_target && check_synthetic(user))
+ return emote_message_synthetic_3p_target
+ return emote_message_3p_target
+ if(emote_message_synthetic_3p && check_synthetic(user))
+ return emote_message_synthetic_3p
+ return emote_message_3p
+
+/decl/emote/proc/get_emote_sound(var/atom/user)
+ if(check_synthetic(user) && emote_sound_synthetic)
+ return list(
+ "sound" = emote_sound_synthetic,
+ "vol" = emote_volume_synthetic
+ )
+ if(emote_sound)
+ return list(
+ "sound" = emote_sound,
+ "vol" = emote_volume
+ )
+
+/decl/emote/proc/do_emote(var/atom/user, var/extra_params)
+ if(ismob(user) && check_restraints)
+ var/mob/M = user
+ if(M.restrained())
+ to_chat(user, SPAN_WARNING("You are restrained and cannot do that."))
+ return
+
+ var/atom/target
+ if(can_target() && extra_params)
+ extra_params = lowertext(extra_params)
+ for(var/atom/thing in view(user))
+ if(extra_params == lowertext(thing.name))
+ target = thing
+ break
+
+ if(target && target != user && check_range)
+ if (get_dist(user, target) > check_range)
+ to_chat(user, SPAN_WARNING("\The [target] is too far away."))
+ return
+
+ var/use_1p = get_emote_message_1p(user, target, extra_params)
+ if(use_1p)
+ if(target)
+ use_1p = replace_target_tokens(use_1p, target)
+ use_1p = "[capitalize(replace_user_tokens(use_1p, user))]"
+ var/use_3p = get_emote_message_3p(user, target, extra_params)
+ if(use_3p)
+ if(target)
+ use_3p = replace_target_tokens(use_3p, target)
+ use_3p = "\The [user] [replace_user_tokens(use_3p, user)]"
+ var/use_radio = get_radio_message(user)
+ if(use_radio)
+ if(target)
+ use_radio = replace_target_tokens(use_radio, target)
+ use_radio = replace_user_tokens(use_radio, user)
+
+ var/use_range = emote_range
+ if (!use_range)
+ use_range = world.view
+
+ if(ismob(user))
+ var/mob/M = user
+ if(message_type == AUDIBLE_MESSAGE)
+ if(isliving(user))
+ var/mob/living/L = user
+ if(L.silent)
+ M.visible_message(message = "[user] opens their mouth silently!", self_message = "You cannot say anything!", blind_message = emote_message_impaired)
+ return
+ else
+ M.audible_message(message = use_3p, self_message = use_1p, deaf_message = emote_message_impaired, hearing_distance = use_range, radio_message = use_radio)
+ else
+ M.visible_message(message = use_3p, self_message = use_1p, blind_message = emote_message_impaired, range = use_range)
+
+ do_extra(user, target)
+ do_sound(user)
+
+/decl/emote/proc/replace_target_tokens(var/msg, var/atom/target)
+ . = msg
+ if(istype(target))
+ var/datum/gender/target_gender = gender_datums[target.get_visible_gender()]
+ . = replacetext(., "TARGET_THEM", target_gender.him)
+ . = replacetext(., "TARGET_THEIR", target_gender.his)
+ . = replacetext(., "TARGET_SELF", target_gender.himself)
+ . = replacetext(., "TARGET", "\the [target]")
+
+/decl/emote/proc/replace_user_tokens(var/msg, var/atom/user)
+ . = msg
+ if(istype(user))
+ var/datum/gender/user_gender = gender_datums[user.get_visible_gender()]
+ . = replacetext(., "USER_THEM", user_gender.him)
+ . = replacetext(., "USER_THEIR", user_gender.his)
+ . = replacetext(., "USER_SELF", user_gender.himself)
+ . = replacetext(., "USER", "\the [user]")
+
+/decl/emote/proc/get_radio_message(var/atom/user)
+ if(emote_message_radio_synthetic && check_synthetic(user))
+ return emote_message_radio_synthetic
+ return emote_message_radio
+
+/decl/emote/proc/do_extra(var/atom/user, var/atom/target)
+ return
+
+/decl/emote/proc/do_sound(var/atom/user)
+ var/list/use_sound = get_emote_sound(user)
+ if(!islist(use_sound) || length(use_sound) < 2)
+ return
+ var/sound_to_play = use_sound["sound"]
+ if(!sound_to_play)
+ return
+ if(islist(sound_to_play))
+ if(sound_to_play[user.gender])
+ sound_to_play = sound_to_play[user.gender]
+ if(islist(sound_to_play) && length(sound_to_play))
+ sound_to_play = pick(sound_to_play)
+ if(sound_to_play)
+ playsound(user.loc, sound_to_play, use_sound["vol"], 0, preference = /datum/client_preference/emote_noises) //VOREStation Add - Preference
+
+/decl/emote/proc/check_user(var/atom/user)
+ return TRUE
+
+/decl/emote/proc/can_target()
+ return (emote_message_1p_target || emote_message_3p_target)
+
+/decl/emote/dd_SortValue()
+ return key
+
+/decl/emote/proc/check_synthetic(var/mob/living/user)
+ . = istype(user) && user.isSynthetic()
+ if(!. && ishuman(user) && message_type == AUDIBLE_MESSAGE)
+ var/mob/living/carbon/human/H = user
+ if(H.should_have_organ(O_LUNGS))
+ var/obj/item/organ/internal/lungs/L = H.internal_organs_by_name[O_LUNGS]
+ if(L && L.robotic == 2) //Hard-coded to 2, incase we add lifelike robotic lungs
+ . = TRUE
diff --git a/code/modules/emotes/emote_mob.dm b/code/modules/emotes/emote_mob.dm
new file mode 100644
index 00000000000..3e45f05091e
--- /dev/null
+++ b/code/modules/emotes/emote_mob.dm
@@ -0,0 +1,183 @@
+/mob/proc/can_emote(var/emote_type)
+ return (stat == CONSCIOUS)
+
+/mob/living/can_emote(var/emote_type)
+ return (..() && !(silent && emote_type == AUDIBLE_MESSAGE))
+
+/mob/proc/emote(var/act, var/m_type, var/message)
+ set waitfor = FALSE
+ // s-s-snowflake
+ if(src.stat == DEAD && act != "deathgasp")
+ return
+
+ if(usr == src) //client-called emote
+ if (client && (client.prefs.muted & MUTE_IC))
+ to_chat(src, "You cannot send IC messages (muted).")
+ return
+
+ if(act == "help")
+ to_chat(src,"Usable emotes: [english_list(usable_emotes)].")
+ return
+
+ if(!can_emote(m_type))
+ to_chat(src, SPAN_WARNING("You cannot currently [m_type == AUDIBLE_MESSAGE ? "audibly" : "visually"] emote!"))
+ return
+
+ if(act == "me")
+ return custom_emote(m_type, message)
+
+ if(act == "custom")
+ if(!message)
+ message = sanitize_or_reflect(input(src,"Choose an emote to display.") as text|null, src) //VOREStation Edit - Reflect too long messages, within reason
+ if(!message)
+ return
+ if (!m_type)
+ if(alert(src, "Is this an audible emote?", "Emote", "Yes", "No") == "No")
+ m_type = VISIBLE_MESSAGE
+ else
+ m_type = AUDIBLE_MESSAGE
+ return custom_emote(m_type, message)
+
+ var/splitpoint = findtext(act, " ")
+ if(splitpoint > 0)
+ var/tempstr = act
+ act = copytext(tempstr,1,splitpoint)
+ message = copytext(tempstr,splitpoint+1,0)
+
+ //VOREStation Add - NIF soulcatcher shortcuts
+ if(act == "nsay")
+ return nsay(message)
+
+ if(act == "nme")
+ return nme(message)
+ //VOREStation Add End
+
+ var/decl/emote/use_emote = usable_emotes[act]
+ if(!use_emote)
+ to_chat(src, SPAN_WARNING("Unknown emote '[act]'. Type say *help for a list of usable emotes."))
+ return
+
+ if(m_type != use_emote.message_type && use_emote.conscious && stat != CONSCIOUS)
+ return
+
+ if(use_emote.message_type == AUDIBLE_MESSAGE && is_muzzled())
+ audible_message("\The [src] [use_emote.emote_message_muffled || "makes a muffled sound."]")
+ return
+ else
+ use_emote.do_emote(src, message)
+
+ for (var/obj/item/weapon/implant/I in src)
+ if (I.implanted)
+ I.trigger(act, src)
+
+/mob/proc/format_emote(var/emoter = null, var/message = null)
+ var/pretext
+ var/subtext
+ var/nametext
+ var/end_char
+ var/start_char
+ var/name_anchor
+
+ if(!message || !emoter)
+ return
+
+ message = html_decode(message)
+
+ name_anchor = findtext(message, "*")
+ if(name_anchor > 0) // User supplied emote with visible_emote token (default ^)
+ pretext = copytext(message, 1, name_anchor)
+ subtext = copytext(message, name_anchor + 1, length(message) + 1)
+ else
+ // No token. Just the emote as usual.
+ subtext = message
+
+ // Oh shit, we got this far! Let's see... did the user attempt to use more than one token?
+ if(findtext(subtext, "*"))
+ // abort abort!
+ to_chat(emoter, SPAN_WARNING("You may use only one \"["*"]\" symbol in your emote."))
+ return
+
+ if(pretext)
+ // Add a space at the end if we didn't already supply one.
+ end_char = copytext(pretext, length(pretext), length(pretext) + 1)
+ if(end_char != " ")
+ pretext += " "
+
+ // Grab the last character of the emote message.
+ end_char = copytext(subtext, length(subtext), length(subtext) + 1)
+ if(!(end_char in list(".", "?", "!", "\"", "-", "~"))) // gotta include ~ for all you fucking weebs
+ // No punctuation supplied. Tack a period on the end.
+ subtext += "."
+
+ // Add a space to the subtext, unless it begins with an apostrophe or comma.
+ if(subtext != ".")
+ // First, let's get rid of any existing space, to account for sloppy emoters ("X, ^ , Y")
+ subtext = trim_left(subtext)
+ start_char = copytext(subtext, 1, 2)
+ if(start_char != "," && start_char != "'")
+ subtext = " " + subtext
+
+ pretext = capitalize(html_encode(pretext))
+ nametext = html_encode(nametext)
+ subtext = html_encode(subtext)
+ // Store the player's name in a nice bold, naturalement
+ nametext = "[emoter]"
+ return pretext + nametext + subtext
+
+/mob/proc/custom_emote(var/m_type = VISIBLE_MESSAGE, var/message, var/range = world.view)
+
+ if((usr && stat) || (!use_me && usr == src))
+ to_chat(src, "You are unable to emote.")
+ return
+
+ var/input
+ if(!message)
+ input = sanitize(input(src,"Choose an emote to display.") as text|null)
+ else
+ input = message
+
+ if(input)
+ message = format_emote(src, message)
+ else
+ return
+
+ if(input)
+ log_emote(message,src) //Log before we add junk
+ message = "[src] [input]"
+ else
+ return
+
+ if(message)
+ message = encode_html_emphasis(message)
+
+ // Hearing gasp and such every five seconds is not good emotes were not global for a reason.
+ // Maybe some people are okay with that.
+ var/turf/T = get_turf(src)
+ if(!T) return
+ var/list/in_range = get_mobs_and_objs_in_view_fast(T,range,2,remote_ghosts = client ? TRUE : FALSE)
+ var/list/m_viewers = in_range["mobs"]
+ var/list/o_viewers = in_range["objs"]
+
+ for(var/mob in m_viewers)
+ var/mob/M = mob
+ spawn(0) // It's possible that it could be deleted in the meantime, or that it runtimes.
+ if(M)
+ if(isobserver(M))
+ message = "[src] ([ghost_follow_link(src, M)]) [input]"
+ M.show_message(message, m_type)
+
+ for(var/obj in o_viewers)
+ var/obj/O = obj
+ spawn(0)
+ if(O)
+ O.see_emote(src, message, m_type)
+
+
+
+// Specific mob type exceptions below.
+/mob/living/silicon/ai/emote(var/act, var/type, var/message)
+ var/obj/machinery/hologram/holopad/T = src.holo
+ if(T && T.masters[src]) //Is the AI using a holopad?
+ src.holopad_emote(message)
+ else //Emote normally, then.
+ ..()
diff --git a/code/modules/events/supply_demand_vr.dm b/code/modules/events/supply_demand_vr.dm
index 6447630c9e5..64d402c443e 100644
--- a/code/modules/events/supply_demand_vr.dm
+++ b/code/modules/events/supply_demand_vr.dm
@@ -274,8 +274,7 @@
/datum/event/supply_demand/proc/choose_chemistry_items(var/differentTypes)
// Checking if they show up in health analyzer is good huristic for it being a drug
var/list/medicineReagents = list()
- for(var/path in typesof(/datum/chemical_reaction) - /datum/chemical_reaction)
- var/datum/chemical_reaction/CR = path // Stupid casting required for reading
+ for(var/decl/chemical_reaction/instant/CR in SSchemistry.chemical_reactions)
var/datum/reagent/R = SSchemistry.chemical_reagents[initial(CR.result)]
if(R && R.scannable)
medicineReagents += R
@@ -288,8 +287,7 @@
/datum/event/supply_demand/proc/choose_bar_items(var/differentTypes)
var/list/drinkReagents = list()
- for(var/path in typesof(/datum/chemical_reaction) - /datum/chemical_reaction)
- var/datum/chemical_reaction/CR = path // Stupid casting required for reading
+ for(var/decl/chemical_reaction/instant/drinks/CR in SSchemistry.chemical_reactions)
var/datum/reagent/R = SSchemistry.chemical_reagents[initial(CR.result)]
if(istype(R, /datum/reagent/drink) || istype(R, /datum/reagent/ethanol))
drinkReagents += R
diff --git a/code/modules/examine/descriptions/weapons.dm b/code/modules/examine/descriptions/weapons.dm
index 8acb089a4c6..747fa0f75f6 100644
--- a/code/modules/examine/descriptions/weapons.dm
+++ b/code/modules/examine/descriptions/weapons.dm
@@ -30,7 +30,7 @@
description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \
then click where you want to fire. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger."
-/obj/item/weapon/gun/energy/gun/stunrevolver
+/obj/item/weapon/gun/energy/stunrevolver
description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \
then click where you want to fire. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger."
diff --git a/code/modules/food/food/cans_vr.dm b/code/modules/food/food/cans_vr.dm
new file mode 100644
index 00000000000..4807d021ef5
--- /dev/null
+++ b/code/modules/food/food/cans_vr.dm
@@ -0,0 +1,75 @@
+//////////////////////Bepis Drinks (04/29/2021)//////////////////////
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/bepis
+ name = "\improper Bepis"
+ desc = "It has a smell of 'off-brand' whenever you open it..."
+ description_fluff = "Puts the 'B' in Best Soda! Bepis is the number one competitor to \
+ Space Cola and has vendors scattered across the frontier. While the drink is not as \
+ popular as Space Cola, many people across known space enjoy the sweet beverage."
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "bepis"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/bepis/Initialize()
+ . = ..()
+ reagents.add_reagent("bepis", 30)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/astrodew
+ name = "\improper Astro Dew Spring Water"
+ desc = "A can of refreshing 'spring' water! Or so the can claims."
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "watercan"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/astrodew/Initialize()
+ . = ..()
+ reagents.add_reagent("water", 30)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/icecoffee
+ name = "\improper Café Del Consumir"
+ desc = "A can of deliciously sweet iced coffee that originates from Earth."
+ description_fluff = "Café Del Consumir originates from a small coffee brewery in México \
+ that still opperates to this day. Café Del Consumir prides itself on being true to form \
+ and retaining its original recipe. They've been producing and selling thier product across \
+ the galaxy for decades without fail. NanoTrasen has attempted to by out the small company for \
+ years now, howerver all attempts they've made have failed."
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "coffeecan"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/icecoffee/Initialize()
+ . = ..()
+ reagents.add_reagent("icecoffee", 30)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/buzz
+ name = "\improper Buzz Fuzz"
+ desc = "Uses real honey, making it a sweet tooth's dream drink."
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "buzzfuzz"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/buzz/Initialize()
+ . = ..()
+ reagents.add_reagent("buzz_fuzz", 30)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/shambler
+ name = "\improper Shambler's Juice"
+ desc = "~Shake me up some of that Shambler's Juice!~"
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "shambler"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/shambler/Initialize()
+ . = ..()
+ reagents.add_reagent("shamblers", 30)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/cranberry
+ name = "\improper Sprited Cranberry"
+ desc = "A delicious blend of fresh cranberry juice and various spices, the perfect drink."
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "cranberry"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/cranberry/Initialize()
+ . = ..()
+ reagents.add_reagent("sprited_cranberry", 30)
\ No newline at end of file
diff --git a/code/modules/food/food/drinks/bottle.dm b/code/modules/food/food/drinks/bottle.dm
index 56d303371a7..1f7beec6b9e 100644
--- a/code/modules/food/food/drinks/bottle.dm
+++ b/code/modules/food/food/drinks/bottle.dm
@@ -341,20 +341,20 @@
. = ..()
reagents.add_reagent("absinthe", 100)
-/obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor
- name = "Emeraldine Melon Liquor"
+/obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor //MODIFIED ON 04/21/2021
+ name = "Emeraldine Melon Liqueur"
desc = "A bottle of 46 proof Emeraldine Melon Liquor. Sweet and light."
- icon_state = "alco-green" //Placeholder.
+ icon_state = "melon_liqueur"
center_of_mass = list("x"=16, "y"=6)
/obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor/Initialize()
. = ..()
reagents.add_reagent("melonliquor", 100)
-/obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao
+/obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao //MODIFIED ON 04/21/2021
name = "Miss Blue Curacao"
desc = "A fruity, exceptionally azure drink. Does not allow the imbiber to use the fifth magic."
- icon_state = "alco-blue" //Placeholder.
+ icon_state = "blue_curacao"
center_of_mass = list("x"=16, "y"=6)
/obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao/Initialize()
@@ -371,36 +371,6 @@
. = ..()
reagents.add_reagent("grenadine", 100)
-/obj/item/weapon/reagent_containers/food/drinks/bottle/cola
- name = "\improper Space Cola"
- desc = "Cola. in space"
- icon_state = "colabottle"
- center_of_mass = list("x"=16, "y"=6)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/cola/Initialize()
- . = ..()
- reagents.add_reagent("cola", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/space_up
- name = "\improper Space-Up"
- desc = "Tastes like a hull breach in your mouth."
- icon_state = "space-up_bottle"
- center_of_mass = list("x"=16, "y"=6)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/space_up/Initialize()
- . = ..()
- reagents.add_reagent("space_up", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/space_mountain_wind
- name = "\improper Space Mountain Wind"
- desc = "Blows right through you like a space wind."
- icon_state = "space_mountain_wind_bottle"
- center_of_mass = list("x"=16, "y"=6)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/space_mountain_wind/Initialize()
- . = ..()
- reagents.add_reagent("spacemountainwind", 100)
-
/obj/item/weapon/reagent_containers/food/drinks/bottle/pwine
name = "Warlock's Velvet"
desc = "What a delightful packaging for a surely high quality wine! The vintage must be amazing!"
@@ -421,7 +391,107 @@
. = ..()
reagents.add_reagent("unathiliquor", 100)
-//////////////////////////JUICES AND STUFF ///////////////////////
+/obj/item/weapon/reagent_containers/food/drinks/bottle/sake
+ name = "Mono-No-Aware Luxury Sake"
+ desc = "Dry alcohol made from rice, a favorite of businessmen."
+ icon_state = "sakebottle"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/sake/Initialize()
+ . = ..()
+ reagents.add_reagent("sake", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/champagne
+ name = "Gilthari Luxury Champagne"
+ desc = "For those special occassions."
+ icon_state = "champagne"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/champagne/Initialize()
+ . = ..()
+ reagents.add_reagent("champagne", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/peppermintschnapps
+ name = "Dr. Bone's Peppermint Schnapps"
+ desc = "A flavoured grain liqueur with a fresh, minty taste."
+ icon_state = "schnapps_pep"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/peppermintschnapps/Initialize()
+ . = ..()
+ reagents.add_reagent("schnapps_pep", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/peachschnapps
+ name = "Dr. Bone's Peach Schnapps"
+ desc = "A flavoured grain liqueur with a fruity peach taste."
+ icon_state = "schnapps_pea"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/peachschnapps/Initialize()
+ . = ..()
+ reagents.add_reagent("schnapps_pea", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/lemonadeschnapps
+ name = "Dr. Bone's Lemonade Schnapps"
+ desc = "A flavoured grain liqueur with a sweetish, lemon taste."
+ icon_state = "schnapps_lem"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/lemonadeschnapps/Initialize()
+ . = ..()
+ reagents.add_reagent("schnapps_lem", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/jager
+ name = "Schusskonig"
+ desc = "A complex tasting digestif. Thank god the original's trademark lapsed."
+ icon_state = "jager_bottle"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/jager/Initialize()
+ . = ..()
+ reagents.add_reagent("jager", 100)
+
+//////////////////////////JUICES AND STUFF///////////////////////
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/cola //MODIFIED ON 04/21/2021
+ name = "\improper two-liter Space Cola"
+ desc = "Cola. In space."
+ icon_state = "colabottle"
+ center_of_mass = list("x"=16, "y"=6)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/cola/Initialize()
+ . = ..()
+ reagents.add_reagent("cola", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/space_up //MODIFIED ON 04/21/2021
+ name = "\improper two-liter Space-Up"
+ desc = "Tastes like a hull breach in your mouth."
+ icon_state = "space-up_bottle"
+ center_of_mass = list("x"=16, "y"=6)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/space_up/Initialize()
+ . = ..()
+ reagents.add_reagent("space_up", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/space_mountain_wind //MODIFIED ON 04/21/2021
+ name = "\improper two-liter Space Mountain Wind"
+ desc = "Blows right through you like a space wind."
+ icon_state = "space_mountain_wind_bottle"
+ center_of_mass = list("x"=16, "y"=6)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/space_mountain_wind/Initialize()
+ . = ..()
+ reagents.add_reagent("spacemountainwind", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/dr_gibb //ADDED ON 04/21/2021
+ name = "\improper two-liter Dr. Gibb"
+ desc = "A delicious mixture of 42 different flavors."
+ icon_state = "dr_gibb_bottle"
+ center_of_mass = list("x"=16, "y"=6)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/dr_gibb/Initialize()
+ . = ..()
+ reagents.add_reagent("dr_gibb", 100)
/obj/item/weapon/reagent_containers/food/drinks/bottle/orangejuice
name = "Orange Juice"
@@ -507,7 +577,8 @@
. = ..()
reagents.add_reagent("lemonjuice", 100)
-//Small bottles
+//////////////////////////SMALL BOTTLES///////////////////////
+
/obj/item/weapon/reagent_containers/food/drinks/bottle/small
volume = 50
smash_duration = 1
@@ -578,63 +649,3 @@
/obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale/hushedwhisper/Initialize()
. = ..()
reagents.add_reagent("ale", 50)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/sake
- name = "Mono-No-Aware Luxury Sake"
- desc = "Dry alcohol made from rice, a favorite of businessmen."
- icon_state = "sakebottle"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/sake/Initialize()
- . = ..()
- reagents.add_reagent("sake", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/champagne
- name = "Gilthari Luxury Champagne"
- desc = "For those special occassions."
- icon_state = "champagne"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/champagne/Initialize()
- . = ..()
- reagents.add_reagent("champagne", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/peppermintschnapps
- name = "Dr. Bone's Peppermint Schnapps"
- desc = "A flavoured grain liqueur with a fresh, minty taste."
- icon_state = "schnapps_pep"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/peppermintschnapps/Initialize()
- . = ..()
- reagents.add_reagent("schnapps_pep", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/peachschnapps
- name = "Dr. Bone's Peach Schnapps"
- desc = "A flavoured grain liqueur with a fruity peach taste."
- icon_state = "schnapps_pea"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/peachschnapps/Initialize()
- . = ..()
- reagents.add_reagent("schnapps_pea", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/lemonadeschnapps
- name = "Dr. Bone's Lemonade Schnapps"
- desc = "A flavoured grain liqueur with a sweetish, lemon taste."
- icon_state = "schnapps_lem"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/lemonadeschnapps/Initialize()
- . = ..()
- reagents.add_reagent("schnapps_lem", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/jager
- name = "Schusskonig"
- desc = "A complex tasting digestif. Thank god the original's trademark lapsed."
- icon_state = "jager_bottle"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/jager/Initialize()
- . = ..()
- reagents.add_reagent("jager", 100)
diff --git a/code/modules/food/recipe_dump.dm b/code/modules/food/recipe_dump.dm
index df0e6874aa6..63dc510eb94 100644
--- a/code/modules/food/recipe_dump.dm
+++ b/code/modules/food/recipe_dump.dm
@@ -8,13 +8,11 @@
//////////////////////// DRINK
var/list/drink_recipes = list()
- for(var/path in typesof(/datum/chemical_reaction/drinks) - /datum/chemical_reaction/drinks)
- var/datum/chemical_reaction/drinks/CR = new path()
- drink_recipes[path] = list("Result" = CR.name,
+ for(var/decl/chemical_reaction/instant/drinks/CR in SSchemistry.chemical_reactions)
+ drink_recipes[CR.type] = list("Result" = CR.name,
"ResAmt" = CR.result_amount,
"Reagents" = CR.required_reagents,
"Catalysts" = CR.catalysts)
- qdel(CR)
//////////////////////// FOOD
var/list/food_recipes = typesof(/datum/recipe) - /datum/recipe
@@ -43,16 +41,14 @@
qdel(R)
//////////////////////// FOOD+ (basically condiments, tofu, cheese, soysauce, etc)
- for(var/path in typesof(/datum/chemical_reaction/food) - /datum/chemical_reaction/food)
- var/datum/chemical_reaction/food/CR = new path()
- food_recipes[path] = list("Result" = CR.name,
+ for(var/decl/chemical_reaction/instant/food/CR in SSchemistry.chemical_reactions)
+ food_recipes[CR.type] = list("Result" = CR.name,
"ResAmt" = CR.result_amount,
"Reagents" = CR.required_reagents,
"Catalysts" = CR.catalysts,
"Fruit" = list(),
"Ingredients" = list(),
"Image" = null)
- qdel(CR)
//////////////////////// PROCESSING
//Items needs further processing into human-readability.
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 00000000000..0b6e29ffa0a
--- /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.dm b/code/modules/materials/material_recipes.dm
deleted file mode 100644
index c1239b234c9..00000000000
--- a/code/modules/materials/material_recipes.dm
+++ /dev/null
@@ -1,278 +0,0 @@
-/datum/material/proc/get_recipes()
- if(!recipes)
- generate_recipes()
- return recipes
-
-/datum/material/proc/generate_recipes()
- recipes = list()
-
- // If is_brittle() returns true, these are only good for a single strike.
- recipes += 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)
- recipes += 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)
- recipes += 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)
- recipes += 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)
- recipes += 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)
- recipes += new/datum/stack_recipe("[display_name] grave marker", /obj/item/weapon/material/gravemarker, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += 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 += 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)
- recipes += 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)
- recipes += 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)
- recipes += 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)
- recipes += 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)
- recipes += 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)
- recipes += 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 += 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)
- recipes += new/datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/knife/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += 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)
- recipes += 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)
-
-/datum/material/steel/generate_recipes()
- ..()
- recipes += 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]") \
- ))
- recipes += 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]"), \
- ))
- recipes += new/datum/stack_recipe("table frame", /obj/structure/table, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("bench frame", /obj/structure/table/bench, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("rack", /obj/structure/table/rack, 1, time = 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("cannon frame", /obj/item/weapon/cannonframe, 10, time = 15, one_per_turf = 0, on_floor = 0, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("regular floor tile", /obj/item/stack/tile/floor, 1, 4, 20, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("roofing tile", /obj/item/stack/tile/roofing, 3, 4, 20, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("frame", /obj/item/frame, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("mirror frame", /obj/item/frame/mirror, 1, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]")
- recipes += 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]")
- //recipes += new/datum/stack_recipe("fire axe cabinet frame", /obj/item/frame/fireaxe_cabinet, 4, time = 5, one_per_turf = 0, on_floor = 1)
- recipes += new/datum/stack_recipe("railing", /obj/structure/railing, 2, time = 50, one_per_turf = 0, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += 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]"), \
- ))
- //recipes += 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
- recipes += 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
- recipes += new/datum/stack_recipe("conveyor switch", /obj/machinery/conveyor_switch, 2, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("light fixture frame", /obj/item/frame/light, 2, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("small light fixture frame", /obj/item/frame/light/small, 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("floor lamp fixture frame", /obj/machinery/light_construct/flamp, 2, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("apc frame", /obj/item/frame/apc, 2, recycle_material = "[name]")
- recipes += 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]"),\
- ))
- recipes += 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]"), \
- ))
- recipes += new/datum/stack_recipe("desk bell", /obj/item/weapon/deskbell, 1, on_floor = 1, supplied_material = "[name]")
- recipes += 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/plasteel/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("Metal crate", /obj/structure/closet/crate, 10, time = 50, one_per_turf = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("knife grip", /obj/item/weapon/material/butterflyhandle, 4, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("dark floor tile", /obj/item/stack/tile/floor/dark, 1, 4, 20, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("roller bed", /obj/item/roller, 5, time = 30, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 10, recycle_material = "[name]")
-
-/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/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe("light marble floor tile", /obj/item/stack/tile/wmarble, 1, 4, 20, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("dark marble floor tile", /obj/item/stack/tile/bmarble, 1, 4, 20, recycle_material = "[name]")
-
-/datum/material/plastic/generate_recipes()
- ..()
- recipes += 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]")
- recipes += new/datum/stack_recipe("plastic bag", /obj/item/weapon/storage/bag/plasticbag, 3, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("blood pack", /obj/item/weapon/reagent_containers/blood/empty, 4, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += 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
- recipes += 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
- recipes += 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
- recipes += new/datum/stack_recipe("white floor tile", /obj/item/stack/tile/floor/white, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("freezer floor tile", /obj/item/stack/tile/floor/freezer, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += 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]")
- recipes += 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]")
- recipes += 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]")
- recipes += new/datum/stack_recipe("lampshade", /obj/item/weapon/lampshade, 1, time = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("plastic net", /obj/item/weapon/material/fishing_net, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("plastic fishtank", /obj/item/glass_jar/fish/plastic, 2, time = 30 SECONDS, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]")
-
-/datum/material/wood/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe("oar", /obj/item/weapon/oar, 2, time = 30, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("boat", /obj/vehicle/boat, 20, time = 10 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("dragon boat", /obj/vehicle/boat/dragon, 50, time = 30 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("wood circlet", /obj/item/clothing/head/woodcirclet, 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("clipboard", /obj/item/weapon/clipboard, 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += 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]")
- recipes += 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]")
- recipes += 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]")
- recipes += new/datum/stack_recipe("beehive assembly", /obj/item/beehive_assembly, 4, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("beehive frame", /obj/item/honey_frame, 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += 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]")
- recipes += 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]")
- recipes += 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]")
- recipes += new/datum/stack_recipe("coilgun stock", /obj/item/weapon/coilgun_assembly, 5, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += 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]")
- recipes += new/datum/stack_recipe("wooden standup figure", /obj/structure/barricade/cutout, 5, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") //VOREStation Add
- recipes += new/datum/stack_recipe("noticeboard", /obj/structure/noticeboard, 1, recycle_material = "[name]")
- recipes += 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/log/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE, recycle_material = "[name]")
-
-/datum/material/cardboard/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe("box", /obj/item/weapon/storage/box, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("donut box", /obj/item/weapon/storage/box/donut/empty, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("egg box", /obj/item/weapon/storage/fancy/egg_box, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("light tubes box", /obj/item/weapon/storage/box/lights/tubes, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("light bulbs box", /obj/item/weapon/storage/box/lights/bulbs, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("mouse traps box", /obj/item/weapon/storage/box/mousetraps, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("pizza box", /obj/item/pizzabox, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += 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/snow/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("snowball", /obj/item/weapon/material/snow/snowball, 1, time = 10, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("snow brick", /obj/item/stack/material/snowbrick, 2, time = 10, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("snowman", /obj/structure/snowman, 2, time = 15, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("snow robot", /obj/structure/snowman/borg, 2, time = 10, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("snow spider", /obj/structure/snowman/spider, 3, time = 20, recycle_material = "[name]")
-
-/datum/material/snowbrick/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
-
-/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/supermatter/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("supermatter shard", /obj/machinery/power/supermatter/shard, 30 , one_per_turf = 1, time = 600, on_floor = 1, recycle_material = "[name]")
-
-/datum/material/cloth/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("crude bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
-
-/datum/material/resin/generate_recipes()
- recipes = list()
- recipes += 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)
- recipes += 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]")
- recipes += 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)
- recipes += 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)
- recipes += 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]")
- recipes += new/datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] membrane", /obj/effect/alien/resin/membrane, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] node", /obj/effect/alien/weeds/node, 1, time = 4 SECONDS, recycle_material = "[name]")
-
-/datum/material/leather/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += 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]")
- recipes += new/datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += 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)
- recipes += new/datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("whip", /obj/item/weapon/material/whip, 5, time = 15 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
diff --git a/code/modules/materials/material_recipes_vr.dm b/code/modules/materials/material_recipes_vr.dm
deleted file mode 100644
index bf5b54d8535..00000000000
--- 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 3fd995378c5..00000000000
--- 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 71d7e7d3ea8..00000000000
--- 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.dm b/code/modules/materials/materials.dm
deleted file mode 100644
index b591ee26c54..00000000000
--- a/code/modules/materials/materials.dm
+++ /dev/null
@@ -1,1295 +0,0 @@
-/*
- 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)
- qdel(new_mineral)
- 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 definitions follow.
-/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/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/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/gold/bronze //placeholder for ashtrays
- name = "bronze"
- icon_colour = "#EDD12F"
-
-/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
-
-//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/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/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/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/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/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/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/steel/holographic
- name = "holo" + DEFAULT_WALL_MATERIAL
- display_name = DEFAULT_WALL_MATERIAL
- stack_type = null
- shard_type = SHARD_NONE
-
-/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/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)
-
-// Very rare alloy that is reflective, should be used sparingly.
-/datum/material/durasteel
- name = "durasteel"
- stack_type = /obj/item/stack/material/durasteel/hull
- 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/durasteel/hull //The 'Hardball' of starship hulls.
- name = MAT_DURASTEELHULL
- 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/plasteel/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/plasteel/titanium/hull
- name = MAT_TITANIUMHULL
- stack_type = /obj/item/stack/material/titanium/hull
- icon_base = "hull"
- icon_reinf = "reinf_mesh"
-
-/datum/material/plasteel/titanium/hull/place_sheet(var/turf/target) //Deconstructed into normal titanium sheets.
- new /obj/item/stack/material/titanium(target)
-
-/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
-
-/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/holographic
- name = "holoplastic"
- display_name = "plastic"
- stack_type = null
- shard_type = SHARD_NONE
-
-/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/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/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/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/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/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/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
-
-// Particle Smasher and other exotic materials.
-
-/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
-
-/datum/material/morphium/hull
- name = MAT_MORPHIUMHULL
- stack_type = /obj/item/stack/material/morphium/hull
- icon_base = "hull"
- icon_reinf = "reinf_mesh"
-
-/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"
-
-
-// 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%
-
-// Likewise.
-/datum/material/alienalloy/elevatorium
- name = "elevatorium"
- display_name = "elevator panelling"
- icon_colour = "#666666"
-
-// Ditto.
-/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"
-
-/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 1
- return 0
-
-/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 1
- return 0
-
-/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/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/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
-
-/datum/material/wood/holographic
- name = "holowood"
- display_name = "wood"
- stack_type = null
- shard_type = SHARD_NONE
-
-/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/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/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/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/cloth //todo
- 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/syncloth
- name = "syncloth"
- stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 2)
- door_icon_base = "wood"
- ignition_point = T0C+532
- melting_point = T0C+600
- integrity = 200
- protectiveness = 15 // 4%
- flags = MATERIAL_PADDING
- conductive = 0
- pass_stack_colors = TRUE
- supply_conversion_value = 3
-
-/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)
-
-/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
-
-//TODO PLACEHOLDERS:
-/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/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
-
-// This all needs to be OOP'd and use inheritence if its ever used in the future.
-/datum/material/cloth_teal
- name = "teal"
- display_name ="teal"
- use_name = "teal cloth"
- icon_colour = "#00EAFA"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_black
- name = "black"
- display_name = "black"
- use_name = "black cloth"
- icon_colour = "#505050"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_green
- name = "green"
- display_name = "green"
- use_name = "green cloth"
- icon_colour = "#01C608"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_puple
- name = "purple"
- display_name = "purple"
- use_name = "purple cloth"
- icon_colour = "#9C56C4"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_blue
- name = "blue"
- display_name = "blue"
- use_name = "blue cloth"
- icon_colour = "#6B6FE3"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_beige
- name = "beige"
- display_name = "beige"
- use_name = "beige cloth"
- icon_colour = "#E8E7C8"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_lime
- name = "lime"
- display_name = "lime"
- use_name = "lime cloth"
- icon_colour = "#62E36C"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_yellow
- name = "yellow"
- display_name = "yellow"
- use_name = "yellow cloth"
- icon_colour = "#EEF573"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_orange
- name = "orange"
- display_name = "orange"
- use_name = "orange cloth"
- icon_colour = "#E3BF49"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/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
-
-/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.
-
-/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/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/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/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
diff --git a/code/modules/materials/materials/_materials.dm b/code/modules/materials/materials/_materials.dm
new file mode 100644
index 00000000000..1b6cabffd96
--- /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 00000000000..8c91622fb35
--- /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 00000000000..741f0275b75
--- /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 00000000000..7d8d4be9f2f
--- /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 00000000000..9ec22a86b13
--- /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 00000000000..79535422785
--- /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 00000000000..9d7cd818796
--- /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 00000000000..ff6474ec1e7
--- /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 00000000000..caf8f13de74
--- /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 00000000000..3c35b3cf398
--- /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 00000000000..a36ffef5c1c
--- /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 00000000000..f600b2fe025
--- /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 00000000000..6fc7ed29dec
--- /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 00000000000..bca3fdf27b8
--- /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 00000000000..ca323c81374
--- /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 00000000000..b112f362171
--- /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 00000000000..592cc6bc7bb
--- /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 00000000000..588a7ad86fb
--- /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 00000000000..f5fc8cb2f97
--- /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 00000000000..a42735627aa
--- /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 00000000000..ecdad547ca5
--- /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 00000000000..d54dd4f726e
--- /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 00000000000..6cf45fe677e
--- /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 00000000000..bd535798118
--- /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 00000000000..823dd19914c
--- /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 00000000000..5ee3b34671c
--- /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 e66f1ebfa85..00000000000
--- 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 00000000000..7572d0e6545
--- /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 00000000000..1906da8eab0
--- /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 00000000000..bf891347ea0
--- /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 00000000000..23aad9c0cc2
--- /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 00000000000..5a6d429f448
--- /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 00000000000..29e267ab818
--- /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 00000000000..bbad559c128
--- /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 00000000000..1a867ea9578
--- /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 9844ae1cba9..d1c4a1ee240 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 00000000000..4620da5ea9c
--- /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 00000000000..7120911f2d5
--- /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 00000000000..a8b229c9eba
--- /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 00000000000..72b235e415d
--- /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 00000000000..64f672512ce
--- /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 00000000000..96d70d90967
--- /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 00000000000..a534ee19b1c
--- /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 00000000000..d3d1fd6418e
--- /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 00000000000..41415af606a
--- /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 00000000000..7ecc4c4e64d
--- /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 00000000000..17347ff9d8f
--- /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 00000000000..c56f2980881
--- /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 d8693a1316b..0e7680e6728 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/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index 9747179320c..2608e3c7887 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -40,7 +40,7 @@ var/list/mining_overlay_cache = list()
var/datum/artifact_find/artifact_find
var/ignore_mapgen
- var/ore_types = list(
+ var/static/list/ore_types = list(
"hematite" = /obj/item/weapon/ore/iron,
"uranium" = /obj/item/weapon/ore/uranium,
"gold" = /obj/item/weapon/ore/gold,
diff --git a/code/modules/mining/ore_redemption_machine/survey_vendor.dm b/code/modules/mining/ore_redemption_machine/survey_vendor.dm
index 9956084c11d..0d15c5675aa 100644
--- a/code/modules/mining/ore_redemption_machine/survey_vendor.dm
+++ b/code/modules/mining/ore_redemption_machine/survey_vendor.dm
@@ -52,6 +52,7 @@
EQUIPMENT("Defense Equipment - Plasteel Machete", /obj/item/weapon/material/knife/machete, 50),
EQUIPMENT("Defense Equipment - Razor Drone Deployer", /obj/item/weapon/grenade/spawnergrenade/manhacks/station/locked, 100),
EQUIPMENT("Defense Equipment - Sentry Drone Deployer", /obj/item/weapon/grenade/spawnergrenade/ward, 150),
+ EQUIPMENT("Defense Equipment - Frontier Carbine", /obj/item/weapon/gun/energy/locked/frontier/carbine, 750),
EQUIPMENT("Fishing Net", /obj/item/weapon/material/fishing_net, 50),
EQUIPMENT("Titanium Fishing Rod", /obj/item/weapon/material/fishing_rod/modern, 100),
EQUIPMENT("Durasteel Fishing Rod", /obj/item/weapon/material/fishing_rod/modern/strong, 750),
@@ -81,6 +82,7 @@
prize_list["Digging Tools"] = list(
EQUIPMENT("Survey Tools - Shovel", /obj/item/weapon/shovel, 40),
EQUIPMENT("Survey Tools - Mechanical Trap", /obj/item/weapon/beartrap, 50),
+ EQUIPMENT("Survey Tools - Binoculars", /obj/item/device/binoculars,40),
)
prize_list["Miscellaneous"] = list(
EQUIPMENT("Absinthe", /obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe, 10),
diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm
index 9d6735ee8b6..1badc92926a 100644
--- a/code/modules/mob/death.dm
+++ b/code/modules/mob/death.dm
@@ -73,7 +73,7 @@
if(src.loc && istype(loc,/obj/belly) || istype(loc,/obj/item/device/dogborg/sleeper)) deathmessage = "no message" //VOREStation Add - Prevents death messages from inside mobs
facing_dir = null
- if(!gibbed && deathmessage != "no message") // This is gross, but reliable. Only brains use it.
+ if(!gibbed && deathmessage != DEATHGASP_NO_MESSAGE)
src.visible_message("\The [src.name] [deathmessage]")
set_stat(DEAD)
diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm
index 2a8af560804..f59ebf612cd 100644
--- a/code/modules/mob/emote.dm
+++ b/code/modules/mob/emote.dm
@@ -1,64 +1,9 @@
-// All mobs should have custom emote, really..
-//m_type == 1 --> visual.
-//m_type == 2 --> audible
-/mob/proc/custom_emote(var/m_type=1,var/message = null,var/range=world.view)
- if(stat || !use_me && usr == src)
- to_chat(src, "You are unable to emote.")
- return
-
- var/muzzled = is_muzzled()
- if(m_type == 2 && muzzled) return
-
- var/input
- if(!message)
- input = sanitize_or_reflect(input(src,"Choose an emote to display.") as text|null, src) //VOREStation Edit - Reflect too long messages, within reason
- else
- input = message
- if(input)
- log_emote(message,src) //Log before we add junk
- message = "[src] [input]"
- else
- return
-
-
- if (message)
- message = encode_html_emphasis(message)
-
- // Hearing gasp and such every five seconds is not good emotes were not global for a reason.
- // Maybe some people are okay with that.
-
- var/turf/T = get_turf(src)
- if(!T) return
- var/list/in_range = get_mobs_and_objs_in_view_fast(T,range,2,remote_ghosts = client ? TRUE : FALSE)
- var/list/m_viewers = in_range["mobs"]
- var/list/o_viewers = in_range["objs"]
-
- for(var/mob in m_viewers)
- var/mob/M = mob
- spawn(0) // It's possible that it could be deleted in the meantime, or that it runtimes.
- if(M)
- if(isobserver(M))
- //VOREStation Edit Start
- var/mob/observer/dead/D = M
- if(ckey || (src in view(D)))
- M.show_message(message, m_type)
- message = "[src] ([ghost_follow_link(src, M)]) [input]"
- else
- M.show_message(message, m_type)
- //VOREStation Edit End
-
- for(var/obj in o_viewers)
- var/obj/O = obj
- spawn(0)
- if(O)
- O.see_emote(src, message, m_type)
-
// Shortcuts for above proc
/mob/proc/visible_emote(var/act_desc)
- custom_emote(1, act_desc)
+ custom_emote(VISIBLE_MESSAGE, act_desc)
/mob/proc/audible_emote(var/act_desc)
- custom_emote(2, act_desc)
+ custom_emote(AUDIBLE_MESSAGE, act_desc)
/mob/proc/emote_dead(var/message)
diff --git a/code/modules/mob/living/carbon/alien/diona/diona.dm b/code/modules/mob/living/carbon/alien/diona/diona.dm
index 01f1d2f57d2..739c3b09c6b 100644
--- a/code/modules/mob/living/carbon/alien/diona/diona.dm
+++ b/code/modules/mob/living/carbon/alien/diona/diona.dm
@@ -1,3 +1,29 @@
+var/list/_nymph_default_emotes = list(
+ /decl/emote/visible,
+ /decl/emote/visible/scratch,
+ /decl/emote/visible/drool,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/sway,
+ /decl/emote/visible/sulk,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/roll,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/jump,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/collapse,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible/hiss,
+ /decl/emote/audible,
+ /decl/emote/audible/scretch,
+ /decl/emote/audible/choke,
+ /decl/emote/audible/gnarl,
+ /decl/emote/audible/bug_hiss,
+ /decl/emote/audible/bug_chitter,
+ /decl/emote/audible/chirp
+)
+
/mob/living/carbon/alien/diona
name = "diona nymph"
voice_name = "diona nymph"
@@ -20,6 +46,9 @@
holder_type = /obj/item/weapon/holder/diona
var/obj/item/hat
+/mob/living/carbon/alien/diona/get_default_emotes()
+ return global._nymph_default_emotes
+
/mob/living/carbon/alien/diona/Initialize()
. = ..()
species = GLOB.all_species[SPECIES_DIONA]
diff --git a/code/modules/mob/living/carbon/alien/emote.dm b/code/modules/mob/living/carbon/alien/emote.dm
index 5cff048e10b..b0517e7a952 100644
--- a/code/modules/mob/living/carbon/alien/emote.dm
+++ b/code/modules/mob/living/carbon/alien/emote.dm
@@ -1,108 +1,31 @@
-/mob/living/carbon/alien/emote(var/act, var/m_type=1, var/message = null)
- var/param = null
- if(findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- param = copytext(act, t1 + 1, length(act) + 1)
- act = copytext(act, 1, t1)
+var/list/_alien_default_emotes = list(
+ /decl/emote/visible,
+ /decl/emote/visible/scratch,
+ /decl/emote/visible/drool,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/sway,
+ /decl/emote/visible/sulk,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/twitch_v,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/roll,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/jump,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/collapse,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible/hiss,
+ /decl/emote/audible,
+ /decl/emote/audible/deathgasp_alien,
+ /decl/emote/audible/whimper,
+ /decl/emote/audible/gasp,
+ /decl/emote/audible/scretch,
+ /decl/emote/audible/choke,
+ /decl/emote/audible/moan,
+ /decl/emote/audible/gnarl,
+ /decl/emote/audible/chirp
+)
- var/muzzled = is_muzzled()
- act = lowertext(act)
-
- switch(act)
- if("sign")
- if(!restrained())
- var/num = null
- if(text2num(param))
- num = "the number [text2num(param)]"
- if(num)
- message = "[src] signs [num]."
- m_type = 1
- if("burp")
- if(!muzzled)
- message = "[src] burps."
- m_type = 2
- if("deathgasp")
- message = "[src] lets out a waning guttural screech, green blood bubbling from its maw."
- m_type = 2
- if("scratch")
- if(!restrained())
- message = "[src] scratches."
- m_type = 1
- if("whimper")
- if(!muzzled)
- message = "[src] whimpers."
- m_type = 2
- if("tail")
- message = "[src] waves its tail."
- m_type = 1
- if("gasp")
- message = "[src] gasps."
- m_type = 2
- if("shiver")
- message = "[src] shivers."
- m_type = 2
- if("drool")
- message = "[src] drools."
- m_type = 1
- if("scretch")
- if(!muzzled)
- message = "[src] scretches."
- m_type = 2
- if("choke")
- message = "[src] chokes."
- m_type = 2
- if("moan")
- message = "[src] moans!"
- m_type = 2
- if("nod")
- message = "[src] nods its head."
- m_type = 1
-// if("sit")
-// message = "[src] sits down." //Larvan can't sit down, /N
-// m_type = 1
- if("sway")
- message = "[src] sways around dizzily."
- m_type = 1
- if("sulk")
- message = "[src] sulks down sadly."
- m_type = 1
- if("twitch")
- message = "[src] twitches."
- m_type = 1
- if("twitch_v")
- message = "[src] twitches violently."
- m_type = 1
- if("dance")
- if(!restrained())
- message = "[src] dances around happily."
- m_type = 1
- if("roll")
- if(!restrained())
- message = "[src] rolls."
- m_type = 1
- if("shake")
- message = "[src] shakes its head."
- m_type = 1
- if("gnarl")
- if(!muzzled)
- message = "[src] gnarls and shows its teeth.."
- m_type = 2
- if("jump")
- message = "[src] jumps!"
- m_type = 1
- if("hiss_")
- message = "[src] hisses softly."
- m_type = 1
- if("collapse")
- Paralyse(2)
- message = "[src] collapses!"
- m_type = 2
- if("chirp")
- message = "[src] chirps!"
- playsound(src, 'sound/misc/nymphchirp.ogg', 50, 0)
- m_type = 2
- if("help")
- to_chat(src, "burp, chirp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, twitch, whimper")
-
- if(!stat)
- ..(act, m_type, message)
+/mob/living/carbon/alien/get_default_emotes()
+ . = global._alien_default_emotes
diff --git a/code/modules/mob/living/carbon/brain/death.dm b/code/modules/mob/living/carbon/brain/death.dm
index 8b6e7f71756..687372c6ee1 100644
--- a/code/modules/mob/living/carbon/brain/death.dm
+++ b/code/modules/mob/living/carbon/brain/death.dm
@@ -3,7 +3,7 @@
container.icon_state = "mmi_dead"
return ..(gibbed,"beeps shrilly as the MMI flatlines!")
else
- return ..(gibbed,"no message")
+ return ..(gibbed, DEATHGASP_NO_MESSAGE)
/mob/living/carbon/brain/gib()
if(istype(container, /obj/item/device/mmi))
diff --git a/code/modules/mob/living/carbon/brain/emote.dm b/code/modules/mob/living/carbon/brain/emote.dm
index 05706fe299e..cb6ed6a1b7b 100644
--- a/code/modules/mob/living/carbon/brain/emote.dm
+++ b/code/modules/mob/living/carbon/brain/emote.dm
@@ -1,47 +1,17 @@
-/mob/living/carbon/brain/emote(var/act,var/m_type=1,var/message = null)
- if(!(container && istype(container, /obj/item/device/mmi)))//No MMI, no emotes
- return
+var/list/_brain_default_emotes = list(
+ /decl/emote/audible/alarm,
+ /decl/emote/audible/alert,
+ /decl/emote/audible/notice,
+ /decl/emote/audible/whistle,
+ /decl/emote/audible/synth,
+ /decl/emote/audible/beep,
+ /decl/emote/audible/boop,
+ /decl/emote/visible/blink,
+ /decl/emote/visible/flash
+)
- if(findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- act = copytext(act, 1, t1)
+/mob/living/carbon/brain/can_emote()
+ return (istype(container, /obj/item/device/mmi) && ..())
- if(stat == DEAD)
- return
- switch(act)
- if("alarm")
- to_chat(src, "You sound an alarm.")
- message = "[src] sounds an alarm."
- m_type = 2
- if("alert")
- to_chat(src, "You let out a distressed noise.")
- message = "[src] lets out a distressed noise."
- m_type = 2
- if("notice")
- to_chat(src, "You play a loud tone.")
- message = "[src] plays a loud tone."
- m_type = 2
- if("flash")
- message = "The lights on [src] flash quickly."
- m_type = 1
- if("blink")
- message = "[src] blinks."
- m_type = 1
- if("whistle")
- to_chat(src, "You whistle.")
- message = "[src] whistles."
- m_type = 2
- if("beep")
- to_chat(src, "You beep.")
- message = "[src] beeps."
- m_type = 2
- if("boop")
- to_chat(src, "You boop.")
- message = "[src] boops."
- m_type = 2
- if("help")
- to_chat(src, "alarm, alert, notice, flash, blink, whistle, beep, boop")
-
- if(!stat)
- ..(act, m_type, message)
-
\ No newline at end of file
+/mob/living/carbon/brain/get_default_emotes()
+ return global._brain_default_emotes
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index 6afe10cdec7..a705f034506 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -1,843 +1,140 @@
-/mob/living/carbon/human/emote(var/act,var/m_type=1,var/message = null)
- var/param = null
-
- var/datum/gender/T = gender_datums[get_visible_gender()]
-
- if(findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- param = copytext(act, t1 + 1, length(act) + 1)
- act = copytext(act, 1, t1)
-
- var/muzzled = is_muzzled()
- //var/m_type = 1
-
- for(var/obj/item/organ/O in organs)
- for(var/obj/item/weapon/implant/I in O)
- if(I.implanted)
- I.trigger(act, src)
-
- if(stat == DEAD && (act != "deathgasp"))
- return
-
- if(attempt_vr(src, "handle_emote_vr", list(act, m_type, message))) return //VOREStation Add - Custom Emote Handler
-
- switch(act)
- if("airguitar")
- if(!restrained())
- message = "is strumming the air and headbanging like a safari chimp."
- m_type = 1
-
- //Machine-only emotes
- if("ping", "beep", "buzz", "yes", "ye", "dwoop", "no", "rcough", "rsneeze")
-
- if(!isSynthetic())
- to_chat(src, "You are not a synthetic.")
- return
-
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- var/display_msg = "beeps"
- var/use_sound = 'sound/machines/twobeep.ogg'
- if(act == "buzz")
- display_msg = "buzzes"
- use_sound = 'sound/machines/buzz-sigh.ogg'
- else if(act == "ping")
- display_msg = "pings"
- use_sound = 'sound/machines/ping.ogg'
- else if(act == "yes" || act == "ye")
- display_msg = "emits an affirmative blip"
- use_sound = 'sound/machines/synth_yes.ogg'
- else if(act == "dwoop")
- display_msg = "chirps happily"
- use_sound = 'sound/machines/dwoop.ogg'
- else if(act == "no")
- display_msg = "emits a negative blip"
- use_sound = 'sound/machines/synth_no.ogg'
- else if(act == "rcough")
- display_msg = "emits a robotic cough"
- if(get_gender() == FEMALE)
- use_sound = pick('sound/effects/mob_effects/f_machine_cougha.ogg','sound/effects/mob_effects/f_machine_coughb.ogg')
- else
- use_sound = pick('sound/effects/mob_effects/m_machine_cougha.ogg','sound/effects/mob_effects/m_machine_coughb.ogg', 'sound/effects/mob_effects/m_machine_coughc.ogg')
- else if(act == "rsneeze")
- display_msg = "emits a robotic sneeze"
- if(get_gender() == FEMALE)
- use_sound = 'sound/effects/mob_effects/machine_sneeze.ogg'
- else
- use_sound = 'sound/effects/mob_effects/f_machine_sneeze.ogg'
-
- if(param)
- message = "[display_msg] at [param]."
- else
- message = "[display_msg]."
- playsound(src, use_sound, 50, 0, preference = /datum/client_preference/emote_noises) //VOREStation Add
- m_type = 1
-
- //Promethean-only emotes
- if("squish")
- /* VOREStation Removal Start - Eh. People can squish maybe.
- if(species.bump_flag != SLIME) //This should definitely do it.
- to_chat(src, "You are not a slime thing!")
- return
- */ //VOREStation Removal End
- playsound(src, 'sound/effects/slime_squish.ogg', 50, 0, preference = /datum/client_preference/emote_noises) //VOREStation Add //Credit to DrMinky (freesound.org) for the sound.
- message = "squishes."
- m_type = 1
-
- if("chirp")
- /* VOREStation Removal Start - Eh. People can chirp maybe.
- if ((species.bump_flag != SLIME) && (species.name != SPECIES_DIONA))
- to_chat(src, "You are not a diona or slime!")
- return
- */ //VOREStation Removal End
- playsound(src, 'sound/misc/nymphchirp.ogg', 50, 0)
- message = "chirps."
- m_type = 2
-
- //Skrell-only emotes
- if("warble")
- if(species.name != SPECIES_SKRELL)
- to_chat(src, "You are not a Skrell!")
- return
-
- playsound(src, 'sound/effects/warble.ogg', 50, 0, preference = /datum/client_preference/emote_noises) //VOREStation Add // Copyright CC BY 3.0 alienistcog (freesound.org) for the sound.
- message = "warbles."
- m_type = 2
-
- if("blink")
- message = "blinks."
- m_type = 1
-
- if("blink_r")
- message = "blinks rapidly."
- m_type = 1
-
- if("bow")
- if(!buckled)
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "bows to [param]."
- else
- message = "bows."
- m_type = 1
-
- if("custom")
- var/input = sanitize(input("Choose an emote to display.") as text|null)
- if(!input)
- return
- var/input2 = input("Is this a visible or hearable emote?") in list("Visible","Hearable")
- if(input2 == "Visible")
- m_type = 1
- else if(input2 == "Hearable")
- if(miming)
- return
- m_type = 2
- else
- alert("Unable to use this emote, must be either hearable or visible.")
- return
- return custom_emote(m_type, input)
-
- if("me")
-
- //if(silent && silent > 0 && findtext(message,"\"",1, null) > 0)
- // return //This check does not work and I have no idea why, I'm leaving it in for reference.
-
- if(client)
- if(client.prefs.muted & MUTE_IC)
- to_chat(src, "You cannot send IC messages (muted).")
- return
- if(stat)
- return
- if(!(message))
- return
- return custom_emote(m_type, message)
-
- if("salute")
- if(!buckled)
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "salutes to [param]."
- else
- message = "salutes."
- m_type = 1
-
- if("choke")
- if(miming)
- message = "clutches [T.his] throat desperately!"
- m_type = 1
- else
- if(!muzzled)
- message = "chokes!"
- m_type = 2
- else
- message = "makes a strong noise."
- m_type = 2
-
- if("clap")
- if(!restrained())
- message = "claps."
- playsound(src, 'sound/misc/clapping.ogg')
- m_type = 2
- if(miming)
- m_type = 1
-
- if("flap")
- if(!restrained())
- message = "flaps [T.his] wings."
- m_type = 2
- if(miming)
- m_type = 1
-
- if("aflap")
- if(!restrained())
- message = "flaps [T.his] wings ANGRILY!"
- m_type = 2
- if(miming)
- m_type = 1
-
- if("drool")
- message = "drools."
- m_type = 1
-
- if("eyebrow")
- message = "raises an eyebrow."
- m_type = 1
-
- if("chuckle")
- if(miming)
- message = "appears to chuckle."
- m_type = 1
- else
- if(!muzzled)
- message = "chuckles."
- m_type = 2
- else
- message = "makes a noise."
- m_type = 2
-
- if("twitch")
- message = "twitches."
- m_type = 1
-
- if("twitch_v")
- message = "twitches violently."
- m_type = 1
-
- if("faint")
- message = "faints."
- if(sleeping)
- return //Can't faint while asleep
- Sleeping(10)
- m_type = 1
-
- if("cough", "coughs")
- if(miming)
- message = "appears to cough!"
- m_type = 1
- else
- if(!muzzled)
- var/robotic = 0
- m_type = 2
- if(should_have_organ(O_LUNGS))
- var/obj/item/organ/internal/lungs/L = internal_organs_by_name[O_LUNGS]
- if(L && L.robotic == 2) //Hard-coded to 2, incase we add lifelike robotic lungs
- robotic = 1
- if(!robotic && !isSynthetic())
- message = "coughs!"
- if(get_gender() == FEMALE)
- if(species.female_cough_sounds)
- playsound(src, pick(species.female_cough_sounds), 120, preference = /datum/client_preference/emote_noises) //VOREStation Add
- else
- if(species.male_cough_sounds)
- playsound(src, pick(species.male_cough_sounds), 120, preference = /datum/client_preference/emote_noises) //VOREStation Add
- else
- message = "emits a robotic cough"
- var/use_sound
- if(get_gender() == FEMALE)
- use_sound = pick('sound/effects/mob_effects/f_machine_cougha.ogg','sound/effects/mob_effects/f_machine_coughb.ogg')
- else
- use_sound = pick('sound/effects/mob_effects/m_machine_cougha.ogg','sound/effects/mob_effects/m_machine_coughb.ogg', 'sound/effects/mob_effects/m_machine_coughc.ogg')
- playsound(src, use_sound, 50, 0, preference = /datum/client_preference/emote_noises) //VOREStation Add
- else
- message = "makes a strong noise."
- m_type = 2
-
- if("frown")
- message = "frowns."
- m_type = 1
-
- if("nod")
- message = "nods."
- m_type = 1
-
- if("blush")
- message = "blushes."
- m_type = 1
-
- if("wave")
- message = "waves."
- m_type = 1
-
- if("gasp")
- if(miming)
- message = "appears to be gasping!"
- m_type = 1
- else
- if(!muzzled)
- message = "gasps!"
- m_type = 2
- else
- message = "makes a weak noise."
- m_type = 2
-
- if("deathgasp")
- message = "[species.get_death_message()]"
- m_type = 1
-
- if("giggle")
- if(miming)
- message = "giggles silently!"
- m_type = 1
- else
- if(!muzzled)
- message = "giggles."
- m_type = 2
- else
- message = "makes a noise."
- m_type = 2
-
- if("glare")
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "glares at [param]."
- else
- message = "glares."
-
- if("stare")
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "stares at [param]."
- else
- message = "stares."
-
- if("look")
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
-
- if(!M)
- param = null
-
- if(param)
- message = "looks at [param]."
- else
- message = "looks."
- m_type = 1
-
- if("grin")
- message = "grins."
- m_type = 1
-
- if("cry")
- if(miming)
- message = "cries."
- m_type = 1
- else
- if(!muzzled)
- message = "cries."
- m_type = 2
- else
- message = "makes a weak noise. [T.he] [get_visible_gender() == NEUTER ? "frown" : "frowns"]." // no good, non-unwieldy alternative to this ternary at the moment
- m_type = 2
-
- if("sigh")
- if(miming)
- message = "sighs."
- m_type = 1
- else
- if(!muzzled)
- message = "sighs."
- m_type = 2
- else
- message = "makes a weak noise."
- m_type = 2
-
- if("laugh")
- if(miming)
- message = "acts out a laugh."
- m_type = 1
- else
- if(!muzzled)
- message = "laughs."
- m_type = 2
- else
- message = "makes a noise."
- m_type = 2
-
- if("mumble")
- message = "mumbles!"
- m_type = 2
- if(miming)
- m_type = 1
-
- if("grumble")
- if(miming)
- message = "grumbles!"
- m_type = 1
- if(!muzzled)
- message = "grumbles!"
- m_type = 2
- else
- message = "makes a noise."
- m_type = 2
-
- if("groan")
- if(miming)
- message = "appears to groan!"
- m_type = 1
- else
- if(!muzzled)
- message = "groans!"
- m_type = 2
- else
- message = "makes a loud noise."
- m_type = 2
-
- if("moan")
- if(miming)
- message = "appears to moan!"
- m_type = 1
- else
- message = "moans!"
- m_type = 2
-
- if("johnny")
- var/M
- if(param)
- M = param
- if(!M)
- param = null
- else
- if(miming)
- message = "takes a drag from a cigarette and blows \"[M]\" out in smoke."
- m_type = 1
- else
- message = "says, \"[M], please. He had a family.\" [name] takes a drag from a cigarette and blows his name out in smoke."
- m_type = 2
-
- if("point")
- if(!restrained())
- var/mob/M = null
- if(param)
- for(var/atom/A as mob|obj|turf|area in view(null, null))
- if(param == A.name)
- M = A
- break
-
- if(!M)
- message = "points."
- else
- pointed(M)
-
- if(M)
- message = "points to [M]."
- else
- m_type = 1
-
- if("crack")
- if(!restrained())
- message = "cracks [T.his] knuckles."
- playsound(src, 'sound/voice/knuckles.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- m_type = 1
-
- if("raise")
- if(!restrained())
- message = "raises a hand."
- m_type = 1
-
- if("shake")
- message = "shakes [T.his] head."
- m_type = 1
-
- if("shrug")
- message = "shrugs."
- m_type = 1
-
- if("signal")
- if(!restrained())
- var/t1 = round(text2num(param))
- if(isnum(t1))
- if(t1 <= 5 && (!r_hand || !l_hand))
- message = "raises [t1] finger\s."
- else if(t1 <= 10 && (!r_hand && !l_hand))
- message = "raises [t1] finger\s."
- m_type = 1
-
- if("smile")
- message = "smiles."
- m_type = 1
-
- if("shiver")
- message = "shivers."
- m_type = 2
- if(miming)
- m_type = 1
-
- if("pale")
- message = "goes pale for a second."
- m_type = 1
-
- if("tremble")
- message = "trembles in fear!"
- m_type = 1
-
- if("sneeze", "sneezes")
- if(miming)
- message = "sneezes."
- m_type = 1
- else
- if(!muzzled)
- var/robotic = 0
- m_type = 2
- if(should_have_organ(O_LUNGS))
- var/obj/item/organ/internal/lungs/L = internal_organs_by_name[O_LUNGS]
- if(L && L.robotic == 2) //Hard-coded to 2, incase we add lifelike robotic lungs
- robotic = 1
- if(!robotic && !isSynthetic())
- message = "sneezes."
- if(get_gender() == FEMALE)
- playsound(src, species.female_sneeze_sound, 70, preference = /datum/client_preference/emote_noises) //VOREStation Add
- else
- playsound(src, species.male_sneeze_sound, 70, preference = /datum/client_preference/emote_noises) //VOREStation Add
- m_type = 2
- else
- message = "emits a robotic sneeze"
- var/use_sound
- if(get_gender() == FEMALE)
- use_sound = 'sound/effects/mob_effects/machine_sneeze.ogg'
- else
- use_sound = 'sound/effects/mob_effects/f_machine_sneeze.ogg'
- playsound(src, use_sound, 50, 0, preference = /datum/client_preference/emote_noises) //VOREStation Add
- else
- message = "makes a strange noise."
- m_type = 2
-
- if("sniff")
- message = "sniffs."
- m_type = 2
- if(miming)
- m_type = 1
-
- if("snore")
- if(miming)
- message = "sleeps soundly."
- m_type = 1
- else
- if(!muzzled)
- message = "snores."
- m_type = 2
- else
- message = "makes a noise."
- m_type = 2
-
- if("whimper")
- if(miming)
- message = "appears hurt."
- m_type = 1
- else
- if(!muzzled)
- message = "whimpers."
- m_type = 2
- else
- message = "makes a weak noise."
- m_type = 2
-
- if("wink")
- message = "winks."
- m_type = 1
-
- if("yawn")
- if(!muzzled)
- message = "yawns."
- m_type = 2
- if(miming)
- m_type = 1
-
- if("collapse")
- Paralyse(2)
- message = "collapses!"
- m_type = 2
- if(miming)
- m_type = 1
-
- if("hug")
- m_type = 1
- if(!restrained())
- var/M = null
- if(param)
- for(var/mob/A in view(1, null))
- if(param == A.name)
- M = A
- break
- if(M == src)
- M = null
-
- if(M)
- message = "hugs [M]."
- else
- message = "hugs [T.himself]."
-
- if("handshake")
- m_type = 1
- if(!restrained() && !r_hand)
- var/mob/living/M = null
- if(param)
- for(var/mob/living/A in view(1, null))
- if(param == A.name)
- M = A
- break
- if(M == src)
- M = null
-
- if(M)
- if(M.canmove && !M.r_hand && !M.restrained())
- message = "shakes hands with [M]."
- else
- message = "holds out [T.his] hand to [M]."
-
- if("dap")
- m_type = 1
- if(!restrained())
- var/M = null
- if(param)
- for(var/mob/A in view(1, null))
- if(param == A.name)
- M = A
- break
- if(M)
- message = "gives daps to [M]."
- else
- message = "sadly can't find anybody to give daps to, and daps [T.himself]. Shameful."
-
- if("slap", "slaps")
- m_type = 1
- if(!restrained())
- var/M = null
- if(param)
- for(var/mob/A in view(1, null))
- if(param == A.name)
- M = A
- break
- if(M)
- message = "slaps [M] across the face. Ouch!"
- playsound(src, 'sound/effects/snap.ogg', 50, 1, preference = /datum/client_preference/emote_noises) //VOREStation Add
- if(ishuman(M)) //Snowflakey!
- var/mob/living/carbon/human/H = M
- if(istype(H.wear_mask,/obj/item/clothing/mask/smokable))
- H.drop_from_inventory(H.wear_mask)
- else
- message = "slaps [T.himself]!"
- playsound(src, 'sound/effects/snap.ogg', 50, 1, preference = /datum/client_preference/emote_noises) //VOREStation Add
-
- if("scream", "screams")
- if(miming)
- message = "acts out a scream!"
- m_type = 1
- else
- if(!muzzled)
- message = "[species.scream_verb]!"
- m_type = 2
- /* Removed, pending the location of some actually good, properly licensed sounds.
- if(get_gender() == FEMALE)
- playsound(src, "[species.female_scream_sound]", 80, 1)
- else
- playsound(src, "[species.male_scream_sound]", 80, 1) //default to male screams if no gender is present.
- */
- else
- message = "makes a very loud noise."
- m_type = 2
-
- if("snap", "snaps")
- m_type = 2
- var/mob/living/carbon/human/H = src
- var/obj/item/organ/external/L = H.get_organ("l_hand")
- var/obj/item/organ/external/R = H.get_organ("r_hand")
- var/left_hand_good = 0
- var/right_hand_good = 0
- if(L && (!(L.status & ORGAN_DESTROYED)) && (!(L.splinted)) && (!(L.status & ORGAN_BROKEN)))
- left_hand_good = 1
- if(R && (!(R.status & ORGAN_DESTROYED)) && (!(R.splinted)) && (!(R.status & ORGAN_BROKEN)))
- right_hand_good = 1
-
- if(!left_hand_good && !right_hand_good)
- to_chat(usr, "You need at least one hand in good working order to snap your fingers.")
- return
-
- message = "snaps [T.his] fingers."
- playsound(src, 'sound/effects/fingersnap.ogg', 50, 1, -3, preference = /datum/client_preference/emote_noises) //VOREStation Add
-
- if("swish")
- animate_tail_once()
-
- if("wag", "sway")
- animate_tail_start()
-
- if("qwag", "fastsway")
- animate_tail_fast()
-
- if("swag", "stopsway")
- animate_tail_stop()
-
- if("vomit")
- if(isSynthetic())
- to_chat(src, "You are unable to vomit.")
- return
- vomit()
- return
-
- if("whistle" || "whistles")
- if(!muzzled)
- if(!isSynthetic())
- message = "whistles a tune."
- playsound(src, 'sound/voice/longwhistle.ogg', 50, 1, preference = /datum/client_preference/emote_noises) //praying this doesn't get abused
- else
- message = "whistles a robotic tune."
- playsound(src, 'sound/voice/longwhistle_robot.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "makes a light spitting noise, a poor attempt at a whistle."
-
- if("qwhistle")
- if(!muzzled)
- if(!isSynthetic())
- message = "whistles quietly."
- playsound(src, 'sound/voice/shortwhistle.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "whistles robotically."
- playsound(src, 'sound/voice/shortwhistle_robot.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "makes a light spitting noise, a poor attempt at a whistle."
-
- if("wwhistle")
- if(!muzzled)
- if(!isSynthetic())
- message = "whistles inappropriately."
- playsound(src, 'sound/voice/wolfwhistle.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "beeps inappropriately."
- playsound(src, 'sound/voice/wolfwhistle_robot.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "makes a light spitting noise, a poor attempt at a whistle."
-
- if("swhistle")
- if(!muzzled)
- if(!isSynthetic())
- message = "summon whistles."
- playsound(src, 'sound/voice/summon_whistle.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "summon whistles robotically."
- playsound(src, 'sound/voice/summon_whistle_robot.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "makes a light spitting noise, a poor attempt at a whistle."
-
- if("flip")
- m_type = 1
- if (!src.restrained())
- //message = "performs an amazing, gravity-defying backflip before landing skillfully back to the ground."
- playsound(src.loc, 'sound/effects/bodyfall4.ogg', 50, 1)
- src.SpinAnimation(7,1)
- else
- to_chat(usr, "You can't quite do something as difficult as a backflip while so... restricted.")
-
- if("spin")
- m_type = 1
- if (!src.restrained())
- //message = "spins in a dance smoothly on their feet. Wow!"
- src.spin(20, 1)
- else
- to_chat(usr, "You can't quite do something as difficult as a spin while so... restricted.")
-
- if("floorspin")
- m_type = 1
- if (!src.restrained())
- //message = "gets down on the floor and spins their entire body around!"
- spawn(0)
- for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
- set_dir(i)
- sleep(1)
- src.SpinAnimation(20,1)
- else
- to_chat(usr, "You can't quite do something as difficult as a spin while so... restricted.")
-
- if("sidestep")
- m_type = 1
- if (!src.restrained())
- //message = "steps rhymatically and conservatively as they move side to side."
- playsound(src.loc, 'sound/effects/bodyfall4.ogg', 50, 1)
- var/default_pixel_x = initial(pixel_x)
- var/default_pixel_y = initial(pixel_y)
- default_pixel_x = src.default_pixel_x
- default_pixel_y = src.default_pixel_y
-
- animate(src, pixel_x = 5, time = 20)
- sleep(3)
- animate(src, pixel_x = -5, time = 20)
- animate(pixel_x = default_pixel_x, pixel_y = default_pixel_y, time = 2)
- else
- to_chat(usr, "Sidestepping sure seems unachieveable when you're this restricted.")
-
- if("help")
- to_chat(src, "blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, eyebrow, fastsway/qwag, \
- frown, gasp, giggle, glare-(none)/mob, grin, groan, grumble, handshake, hug-(none)/mob, laugh, look-(none)/mob, moan, mumble, nod, pale, point-atom, \
- qwhistle, raise, salute, scream, sneeze, shake, shiver, shrug, sigh, signal-#1-10, slap-(none)/mob, smile, sneeze, sniff, snore, stare-(none)/mob, stopsway/swag, sway/wag, swish, swhistle, \
- tremble, twitch, twitch_v, vomit, whimper, wink, whistle, wwhistle, yawn. Prometheans: squish Synthetics: beep, buzz, dwoop, yes, no, rcough, rsneeze, ping. Skrell: warble")
-
- else
- to_chat(src, "Unusable emote '[act]'. Say *help or *vhelp for a list.") //VOREStation Edit, mention *vhelp for Virgo-specific emotes located in emote_vr.dm.
-
- if(message)
- custom_emote(m_type,message)
+var/list/_human_default_emotes = list(
+ /decl/emote/visible/blink,
+ /decl/emote/audible/synth,
+ /decl/emote/audible/synth/ping,
+ /decl/emote/audible/synth/buzz,
+ /decl/emote/audible/synth/confirm,
+ /decl/emote/audible/synth/deny,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/collapse,
+ /decl/emote/audible/gasp,
+ /decl/emote/audible/choke,
+ /decl/emote/audible/sneeze,
+ /decl/emote/audible/sniff,
+ /decl/emote/audible/snore,
+ /decl/emote/audible/whimper,
+ /decl/emote/audible/whistle,
+ /decl/emote/audible/whistle/quiet,
+ /decl/emote/audible/whistle/wolf,
+ /decl/emote/audible/whistle/summon,
+ /decl/emote/audible/yawn,
+ /decl/emote/audible/clap,
+ /decl/emote/audible/chuckle,
+ /decl/emote/audible/cough,
+ /decl/emote/audible/cry,
+ /decl/emote/audible/sigh,
+ /decl/emote/audible/laugh,
+ /decl/emote/audible/mumble,
+ /decl/emote/audible/grumble,
+ /decl/emote/audible/groan,
+ /decl/emote/audible/moan,
+ /decl/emote/audible/grunt,
+ /decl/emote/audible/slap,
+ /decl/emote/audible/crack,
+ /decl/emote/human,
+ /decl/emote/human/deathgasp,
+ /decl/emote/audible/giggle,
+ /decl/emote/audible/scream,
+ /decl/emote/visible/airguitar,
+ /decl/emote/visible/blink_r,
+ /decl/emote/visible/bow,
+ /decl/emote/visible/salute,
+ /decl/emote/visible/flap,
+ /decl/emote/visible/aflap,
+ /decl/emote/visible/drool,
+ /decl/emote/visible/eyebrow,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/twitch_v,
+ /decl/emote/visible/faint,
+ /decl/emote/visible/frown,
+ /decl/emote/visible/blush,
+ /decl/emote/visible/wave,
+ /decl/emote/visible/glare,
+ /decl/emote/visible/stare,
+ /decl/emote/visible/look,
+ /decl/emote/visible/point,
+ /decl/emote/visible/raise,
+ /decl/emote/visible/grin,
+ /decl/emote/visible/shrug,
+ /decl/emote/visible/smile,
+ /decl/emote/visible/pale,
+ /decl/emote/visible/tremble,
+ /decl/emote/visible/wink,
+ /decl/emote/visible/hug,
+ /decl/emote/visible/dap,
+ /decl/emote/visible/signal,
+ /decl/emote/visible/handshake,
+ /decl/emote/visible/afold,
+ /decl/emote/visible/alook,
+ /decl/emote/visible/eroll,
+ /decl/emote/visible/hbow,
+ /decl/emote/visible/hip,
+ /decl/emote/visible/holdup,
+ /decl/emote/visible/hshrug,
+ /decl/emote/visible/crub,
+ /decl/emote/visible/erub,
+ /decl/emote/visible/fslap,
+ /decl/emote/visible/ftap,
+ /decl/emote/visible/hrub,
+ /decl/emote/visible/hspread,
+ /decl/emote/visible/pocket,
+ /decl/emote/visible/rsalute,
+ /decl/emote/visible/rshoulder,
+ /decl/emote/visible/squint,
+ /decl/emote/visible/tfist,
+ /decl/emote/visible/tilt,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible/snap,
+ /decl/emote/visible/vomit,
+ /decl/emote/visible/floorspin,
+ /decl/emote/visible/flip,
+ //VOREStation Add
+ /decl/emote/audible/awoo,
+ /decl/emote/audible/awoo2,
+ /decl/emote/audible/growl,
+ /decl/emote/audible/woof,
+ /decl/emote/audible/woof2,
+ /decl/emote/audible/nya,
+ /decl/emote/audible/mrowl,
+ /decl/emote/audible/peep,
+ /decl/emote/audible/chirp,
+ /decl/emote/audible/hoot,
+ /decl/emote/audible/weh,
+ /decl/emote/audible/merp,
+ /decl/emote/audible/myarp,
+ /decl/emote/audible/bark,
+ /decl/emote/audible/bork,
+ /decl/emote/audible/mrow,
+ /decl/emote/audible/hypno,
+ /decl/emote/audible/hiss,
+ /decl/emote/audible/rattle,
+ /decl/emote/audible/squeak,
+ /decl/emote/audible/geck,
+ /decl/emote/audible/baa,
+ /decl/emote/audible/baa2,
+ /decl/emote/audible/mar,
+ /decl/emote/audible/wurble,
+ /decl/emote/audible/snort,
+ /decl/emote/audible/meow,
+ /decl/emote/audible/moo,
+ /decl/emote/audible/croak,
+ /decl/emote/audible/gao,
+ /decl/emote/audible/cackle,
+
+ /decl/emote/visible/mlem,
+ /decl/emote/visible/blep,
+
+ /decl/emote/helper/vwag,
+ /decl/emote/helper/vflap
+ //VOREStation Add End
+)
+
+/mob/living/carbon/human/get_default_emotes()
+ return global._human_default_emotes
/mob/living/carbon/human/verb/pose()
set name = "Set Pose"
diff --git a/code/modules/mob/living/carbon/human/emote_vr.dm b/code/modules/mob/living/carbon/human/emote_vr.dm
index d8deee8e7bf..f4bc98bcbe6 100644
--- a/code/modules/mob/living/carbon/human/emote_vr.dm
+++ b/code/modules/mob/living/carbon/human/emote_vr.dm
@@ -1,185 +1,11 @@
-/mob
- var/nextemote = 1
+/mob/living/carbon/human/verb/toggle_resizing_immunity()
+ set name = "Toggle Resizing Immunity"
+ set desc = "Toggles your ability to resist resizing attempts"
+ set category = "IC"
-/mob/living/carbon/human/proc/handle_emote_vr(var/act,var/m_type=1,var/message = null)
- //Reduces emote spamming
- if(nextemote >= world.time)// || user.stat != CONSCIOUS
- return 1
- nextemote = world.time + 12
+ resizable = !resizable
+ to_chat(src, "You are now [resizable ? "susceptible" : "immune"] to being resized.")
- switch(act)
- if("vwag")
- if(toggle_tail(message = 1))
- m_type = 1
- message = "[wagging ? "starts" : "stops"] wagging their tail."
- else
- return 1
- if("vflap")
- if(toggle_wing(message = 1))
- m_type = 1
- message = "[flapping ? "starts" : "stops"] flapping their wings."
- else
- return 1
- if("mlem")
- message = "mlems [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] tongue up over [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] nose. Mlem."
- m_type = 1
- if("blep")
- message = "bleps [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] tongue out. Blep."
- m_type = 1
- if("awoo")
- m_type = 2
- message = "lets out an awoo."
- playsound(src, 'sound/voice/awoo.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("awoo2")
- m_type = 2
- message = "lets out an awoo."
- playsound(src, 'sound/voice/long_awoo.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("growl")
- m_type = 2
- message = "lets out a growl."
- playsound(src, 'sound/voice/growl.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("woof")
- m_type = 2
- message = "lets out a woof."
- playsound(src, 'sound/voice/woof.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("woof2")
- m_type = 2
- message = "lets out a woof."
- playsound(src, 'sound/voice/woof2.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("nya")
- message = "lets out a nya."
- m_type = 2
- playsound(src, 'sound/voice/nya.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("mrowl")
- message = "mrowls."
- m_type = 2
- playsound(src, 'sound/voice/mrow.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("peep")
- message = "peeps like a bird."
- m_type = 2
- playsound(src, 'sound/voice/peep.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("chirp")
- message = "chirps!"
- playsound(src, 'sound/misc/nymphchirp.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- m_type = 2
- if("hoot")
- message = "hoots!"
- playsound(src, 'sound/voice/hoot.ogg', 50, 1, ,-1, preference = /datum/client_preference/emote_noises)
- m_type = 2
- if("weh")
- message = "lets out a weh."
- m_type = 2
- playsound(src, 'sound/voice/weh.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("merp")
- message = "lets out a merp."
- m_type = 2
- playsound(src, 'sound/voice/merp.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("myarp")
- message = "lets out a myarp."
- m_type = 2
- playsound(src, 'sound/voice/myarp.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("bark")
- message = "lets out a bark."
- m_type = 2
- playsound(src, 'sound/voice/bark2.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("bork")
- m_type = 2
- message = "lets out a bork."
- playsound(src, 'sound/voice/bork.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if ("mrow")
- m_type = 2
- message = "lets out a mrow."
- playsound(src, 'sound/voice/mrow.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if ("hypno")
- m_type = 2
- message = "lets out a mystifying tone."
- playsound(src, 'sound/voice/hypno.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("hiss")
- message = "lets out a hiss."
- m_type = 2
- playsound(src, 'sound/voice/hiss.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("rattle")
- message = "rattles!"
- m_type = 2
- playsound(src, 'sound/voice/rattle.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("squeak")
- message = "lets out a squeak."
- m_type = 2
- playsound(src, 'sound/effects/mouse_squeak.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("geck")
- message = "geckers!"
- m_type = 2
- playsound(src, 'sound/voice/geck.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("baa")
- message = "lets out a baa."
- m_type = 2
- playsound(src, 'sound/voice/baa.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("baa2")
- message = "bleats."
- m_type = 2
- playsound(src, 'sound/voice/baa2.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("deathgasp2")
- message = "[species.get_death_message()]"
- m_type = 1
- playsound(src, 'sound/voice/deathgasp2.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("mar")
- message = "lets out a mar."
- m_type = 2
- playsound(src, 'sound/voice/mar.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("wurble")
- message = "lets out a wurble."
- m_type = 2
- playsound(src, 'sound/voice/wurble.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("snort")
- message = "snorts!"
- m_type = 2
- playsound(src, 'sound/voice/Snort.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("meow")
- message = "gently meows!"
- m_type = 2
- playsound(src, 'sound/voice/Meow.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("moo")
- message = "takes a breath and lets out a moo."
- m_type = 2
- playsound(src, 'sound/voice/Moo.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("croak")
- message = "rumbles their throat, puffs their cheeks and croaks."
- m_type = 2
- playsound(src, 'sound/voice/Croak.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("gao")
- message = "lets out a gao."
- m_type = 2
- playsound(src, 'sound/voice/gao.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("cackle")
- message = "cackles hysterically!"
- m_type = 2
- playsound(src, 'sound/voice/YeenCackle.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("nsay")
- nsay()
- return TRUE
- if("nme")
- nme()
- return TRUE
- if("flip")
- var/list/involved_parts = list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)
- //Check if they are physically capable
- if(sleeping || resting || buckled || weakened || restrained() || involved_parts.len < 2)
- to_chat(src, "You can't *flip in your current state!")
- return 1
- else
- nextemote += 12 //Double delay
- handle_flip_vr()
- message = "does a flip!"
- m_type = 1
- if("vhelp") //Help for Virgo-specific emotes.
- to_chat(src, "vwag, vflap, mlem, blep, awoo, awoo2, growl, nya, peep, chirp, hoot, weh, merp, myarp, bark, bork, mrow, mrowl, hypno, hiss, rattle, squeak, geck, baa, baa2, mar, wurble, snort, meow, moo, croak, gao, cackle, nsay, nme, flip")
- return TRUE
-
- if(message)
- custom_emote(m_type,message)
- return TRUE
-
- return FALSE
/mob/living/carbon/human/proc/handle_flip_vr()
var/original_density = density
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index b351c3d79be..823125109e4 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1162,6 +1162,9 @@
//A slew of bits that may be affected by our species change
regenerate_icons()
+ // Update our available emote list.
+ update_emotes()
+
if(species)
//if(mind) //VOREStation Removal
//apply_traits() //VOREStation Removal
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 34b93b25738..15ea6a45542 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -81,7 +81,6 @@
var/voice = "" //Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life()
- var/miming = null //Toggle for the mime's abilities.
var/special_voice = "" // For changing our voice. Used by a symptom.
var/last_dam = -1 //Used for determining if we need to process all organs or just some or even none.
@@ -156,4 +155,3 @@
// Custom Species Name
var/custom_species
-
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 6795d670647..c0360d3297a 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -98,7 +98,8 @@
// This is the 'mechanical' check for synthetic-ness, not appearance
// Returns the company that made the synthetic
/mob/living/carbon/human/isSynthetic()
- if(synthetic) return synthetic //Your synthetic-ness is not going away
+ if(synthetic)
+ return synthetic //Your synthetic-ness is not going away
var/obj/item/organ/external/T = organs_by_name[BP_TORSO]
if(T && T.robotic >= ORGAN_ROBOT)
src.verbs += /mob/living/carbon/human/proc/self_diagnostics
@@ -106,9 +107,9 @@
src.verbs += /mob/living/carbon/human/proc/setmonitor_state
var/datum/robolimb/R = all_robolimbs[T.model]
synthetic = R
+ update_emotes()
return synthetic
-
- return 0
+ return FALSE
// Would an onlooker know this person is synthetic?
// Based on sort of logical reasoning, 'Look at head, look at torso'
diff --git a/code/modules/mob/living/carbon/human/species/outsider/vox.dm b/code/modules/mob/living/carbon/human/species/outsider/vox.dm
index b29bead4f9c..e8ff96175a7 100644
--- a/code/modules/mob/living/carbon/human/species/outsider/vox.dm
+++ b/code/modules/mob/living/carbon/human/species/outsider/vox.dm
@@ -25,7 +25,8 @@
speech_sounds = list('sound/voice/shriek1.ogg')
speech_chance = 20
- scream_verb = "shrieks"
+ scream_verb_1p = "shriek"
+ scream_verb_3p = "shrieks"
male_scream_sound = 'sound/voice/shriek1.ogg'
female_scream_sound = 'sound/voice/shriek1.ogg'
male_cough_sounds = list('sound/voice/shriekcough.ogg')
@@ -86,7 +87,11 @@
/datum/mob_descriptor/height = -1,
/datum/mob_descriptor/build = 1,
/datum/mob_descriptor/vox_markings = 0
- )
+ )
+
+ default_emotes = list(
+ /decl/emote/audible/vox_shriek
+ )
/datum/species/vox/get_random_name(var/gender)
var/datum/language/species_language = GLOB.all_languages[default_language]
diff --git a/code/modules/mob/living/carbon/human/species/shadekin/shadekin_trait.dm b/code/modules/mob/living/carbon/human/species/shadekin/shadekin_trait.dm
index 73c182dfadd..7f16315e851 100644
--- a/code/modules/mob/living/carbon/human/species/shadekin/shadekin_trait.dm
+++ b/code/modules/mob/living/carbon/human/species/shadekin/shadekin_trait.dm
@@ -2,7 +2,7 @@
allowed_species = list(SPECIES_SHADEKIN)
var/color = BLUE_EYES
name = "Shadekin Blue Adaptation"
- desc = "Makes your shadekin adapted as a Blue eyed kin! This gives you decreased energy regeneration in darkness, decreased regeneration in the light amd unchanged health!"
+ desc = "Makes your shadekin adapted as a Blue eyed kin! This gives you decreased energy regeneration in darkness, decreased regeneration in the light and unchanged health!"
cost = 0
var_changes = list( "total_health" = 100,
"energy_light" = 0.5,
@@ -13,7 +13,7 @@
/datum/trait/kintype/red
name = "Shadekin Red Adaptation"
color = RED_EYES
- desc = "Makes your shadekin adapted as a Red eyed kin! This gives you minimal energy regeneration in darkness, moderate regeneration in the light amd increased health!"
+ desc = "Makes your shadekin adapted as a Red eyed kin! This gives you minimal energy regeneration in darkness, moderate degeneration in the light and increased health!"
var_changes = list( "total_health" = 200,
"energy_light" = -1,
"energy_dark" = 0.1,
@@ -22,37 +22,37 @@
/datum/trait/kintype/purple
name = "Shadekin Purple Adaptation"
color = PURPLE_EYES
- desc = "Makes your shadekin adapted as a Purple eyed kin! This gives you moderate energy regeneration in darkness, minor degeneration in the light amd increased health!"
+ desc = "Makes your shadekin adapted as a Purple eyed kin! This gives you moderate energy regeneration in darkness, minor degeneration in the light and increased health!"
var_changes = list( "total_health" = 150,
- "energy_light" = 1,
- "energy_dark" = -0.5,
+ "energy_light" = -0.5,
+ "energy_dark" = 1,
"unarmed_types" = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/shadekin, /datum/unarmed_attack/bite/sharp/shadekin,/datum/unarmed_attack/shadekinharmbap))
/datum/trait/kintype/yellow
name = "Shadekin Yellow Adaptation"
color = YELLOW_EYES
- desc = "Makes your shadekin adapted as a Yellow eyed kin! This gives you the highest energy regeneration in darkness, high degeneration in the light amd unchanged health!"
+ desc = "Makes your shadekin adapted as a Yellow eyed kin! This gives you the highest energy regeneration in darkness, high degeneration in the light and unchanged health!"
var_changes = list( "total_health" = 100,
- "energy_light" = 3,
- "energy_dark" = -2,
+ "energy_light" = -2,
+ "energy_dark" = 3,
"unarmed_types" = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/shadekin, /datum/unarmed_attack/bite/sharp/shadekin,/datum/unarmed_attack/shadekinharmbap))
/datum/trait/kintype/green
name = "Shadekin Green Adaptation"
color = GREEN_EYES
- desc = "Makes your shadekin adapted as a Green eyed kin! This gives you high energy regeneration in darkness, minor regeneration in the light amd unchanged health!"
+ desc = "Makes your shadekin adapted as a Green eyed kin! This gives you high energy regeneration in darkness, minor regeneration in the light and unchanged health!"
var_changes = list( "total_health" = 100,
- "energy_light" = 2,
- "energy_dark" = 0.125,
+ "energy_light" = 0.125,
+ "energy_dark" = 2,
"unarmed_types" = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/shadekin, /datum/unarmed_attack/bite/sharp/shadekin,/datum/unarmed_attack/shadekinharmbap))
/datum/trait/kintype/orange
name = "Shadekin Orange Adaptation"
color = ORANGE_EYES
- desc = "Makes your shadekin adapted as a Orange eyed kin! This gives you minor energy regeneration in darkness, modeate degeneration in the light amd increased health!"
+ desc = "Makes your shadekin adapted as a Orange eyed kin! This gives you minor energy regeneration in darkness, moderate degeneration in the light and increased health!"
var_changes = list( "total_health" = 175,
- "energy_light" = 0.25,
- "energy_dark" = -0.5,
+ "energy_light" = -0.5,
+ "energy_dark" = 0.25,
"unarmed_types" = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/shadekin, /datum/unarmed_attack/bite/sharp/shadekin,/datum/unarmed_attack/shadekinharmbap))
/datum/trait/kintype/apply(var/datum/species/shadekin/S,var/mob/living/carbon/human/H)
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index 80ad0763e27..3ae68b2c7d8 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -75,7 +75,8 @@
var/list/assisted_langs = list(LANGUAGE_EAL, LANGUAGE_SKRELLIAN, LANGUAGE_SKRELLIANFAR, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) //VOREStation Edit
//Soundy emotey things.
- var/scream_verb = "screams"
+ var/scream_verb_1p = "scream"
+ var/scream_verb_3p = "screams"
var/male_scream_sound //= 'sound/goonstation/voice/male_scream.ogg' Removed due to licensing, replace!
var/female_scream_sound //= 'sound/goonstation/voice/female_scream.ogg' Removed due to licensing, replace!
var/male_cough_sounds = list('sound/effects/mob_effects/m_cougha.ogg','sound/effects/mob_effects/m_coughb.ogg', 'sound/effects/mob_effects/m_coughc.ogg')
diff --git a/code/modules/mob/living/carbon/human/species/species_getters.dm b/code/modules/mob/living/carbon/human/species/species_getters.dm
index 0eeea4f9d4c..7b635613ea1 100644
--- a/code/modules/mob/living/carbon/human/species/species_getters.dm
+++ b/code/modules/mob/living/carbon/human/species/species_getters.dm
@@ -44,7 +44,7 @@
if(config.show_human_death_message)
return ((H && H.isSynthetic()) ? "gives one shrill beep before falling lifeless." : death_message)
else
- return "no message"
+ return DEATHGASP_NO_MESSAGE
/datum/species/proc/get_ssd(var/mob/living/carbon/human/H)
if(H)
diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
index bfb1b7d5e3d..8ec116221ed 100644
--- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm
+++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
@@ -119,6 +119,15 @@ var/datum/species/shapeshifter/promethean/prometheans
var/heal_rate = 0.5 // Temp. Regen per tick.
+ default_emotes = list(
+ /decl/emote/audible/squish,
+ /decl/emote/audible/chirp,
+ /decl/emote/visible/bounce,
+ /decl/emote/visible/jiggle,
+ /decl/emote/visible/lightup,
+ /decl/emote/visible/vibrate
+ )
+
/datum/species/shapeshifter/promethean/New()
..()
prometheans = src
diff --git a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm
index ec0bab797cb..a0a505d61aa 100644
--- a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm
+++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm
@@ -163,12 +163,14 @@
return ..()
/mob/living/simple_mob/protean_blob/adjustBruteLoss(var/amount)
+ amount *= 1.5
if(humanform)
return humanform.adjustBruteLoss(amount)
else
return ..()
/mob/living/simple_mob/protean_blob/adjustFireLoss(var/amount)
+ amount *= 1.5
if(humanform)
return humanform.adjustFireLoss(amount)
else
diff --git a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm
index 087338fd739..8bd2192be8c 100755
--- a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm
+++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm
@@ -313,8 +313,8 @@
material_name = MAT_STEEL
/datum/modifier/protean/steel/tick()
- holder.adjustBruteLoss(-2,include_robo = TRUE) //Looks high, but these ARE modified by species resistances, so this is really 20% of this
- holder.adjustFireLoss(-1,include_robo = TRUE) //And this is really double this
+ holder.adjustBruteLoss(-1,include_robo = TRUE) //Modified by species resistances
+ holder.adjustFireLoss(-0.5,include_robo = TRUE) //Modified by species resistances
var/mob/living/carbon/human/H = holder
for(var/organ in H.internal_organs)
var/obj/item/organ/O = organ
diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm
index f74505e770b..21e19f68d43 100644
--- a/code/modules/mob/living/carbon/human/species/station/station.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station.dm
@@ -160,6 +160,16 @@
/datum/mob_descriptor/build = 2
)
+ default_emotes = list(
+ /decl/emote/human/swish,
+ /decl/emote/human/wag,
+ /decl/emote/human/sway,
+ /decl/emote/human/qwag,
+ /decl/emote/human/fastsway,
+ /decl/emote/human/swag,
+ /decl/emote/human/stopsway
+ )
+
/datum/species/unathi/equip_survival_gear(var/mob/living/carbon/human/H)
..()
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H),slot_shoes)
@@ -250,6 +260,16 @@
O_INTESTINE = /obj/item/organ/internal/intestine
)
+ default_emotes = list(
+ /decl/emote/human/swish,
+ /decl/emote/human/wag,
+ /decl/emote/human/sway,
+ /decl/emote/human/qwag,
+ /decl/emote/human/fastsway,
+ /decl/emote/human/swag,
+ /decl/emote/human/stopsway
+ )
+
/datum/species/tajaran/equip_survival_gear(var/mob/living/carbon/human/H)
..()
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H),slot_shoes)
@@ -533,6 +553,11 @@
genders = list(PLURAL)
+ default_emotes = list(
+ /decl/emote/audible/chirp,
+ /decl/emote/audible/multichirp
+ )
+
/datum/species/diona/can_understand(var/mob/other)
if(istype(other, /mob/living/carbon/alien/diona))
return TRUE
diff --git a/code/modules/mob/living/carbon/human/species/station/teshari.dm b/code/modules/mob/living/carbon/human/species/station/teshari.dm
index 3a282707c35..42afbbdbfcb 100644
--- a/code/modules/mob/living/carbon/human/species/station/teshari.dm
+++ b/code/modules/mob/living/carbon/human/species/station/teshari.dm
@@ -139,7 +139,7 @@
descriptors = list(
/datum/mob_descriptor/height = -3,
/datum/mob_descriptor/build = -3
- )
+ )
var/static/list/flight_bodyparts = list(
BP_L_ARM,
@@ -152,6 +152,12 @@
/obj/item/clothing/suit/straight_jacket
)
+ default_emotes = list(
+ /decl/emote/audible/teshsqueak,
+ /decl/emote/audible/teshchirp,
+ /decl/emote/audible/teshtrill
+ )
+
/datum/species/teshari/equip_survival_gear(var/mob/living/carbon/human/H)
..()
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H),slot_shoes)
@@ -159,7 +165,7 @@
/datum/species/teshari/handle_falling(mob/living/carbon/human/H, atom/hit_atom, damage_min, damage_max, silent, planetary)
// Tesh can glide to save themselves from some falls. Basejumping bird
- // without parachute, or falling bird without free wings goes splat.
+ // without parachute, or falling bird without free wings, goes splat.
// Are we landing from orbit, or handcuffed/unconscious/tied to something?
if(planetary || !istype(H) || H.incapacitated(INCAPACITATION_DEFAULT|INCAPACITATION_DISABLED))
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 877e8542767..ae1b09ae714 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -433,38 +433,5 @@ proc/get_radio_key_from_channel(var/channel)
/mob/proc/GetVoice()
return name
-/mob/living/emote(var/act, var/type, var/message) //emote code is terrible, this is so that anything that isn't
- if(stat) //already snowflaked to shit can call the parent and handle emoting sanely
- return FALSE
-
- if(..(act, type, message))
- return TRUE
-
- if(act && type && message)
- log_emote(message, src)
-
- for(var/mob/M in dead_mob_list)
- if(!M.client)
- continue
-
- if(isnewplayer(M))
- continue
-
- if(isobserver(M) && M.is_preference_enabled(/datum/client_preference/ghost_sight))
- M.show_message(message)
-
- switch(type)
- if(1) // Visible
- visible_message(message)
- return TRUE
- if(2) // Audible
- audible_message(message)
- return TRUE
- else
- if(act == "help")
- return // Mobs handle this individually
- to_chat(src, "Unusable emote '[act]'. Say *help for a list.")
-
-
/mob/proc/speech_bubble_appearance()
return "normal"
diff --git a/code/modules/mob/living/silicon/emote.dm b/code/modules/mob/living/silicon/emote.dm
index 00a5e429932..6aa6ae2150f 100644
--- a/code/modules/mob/living/silicon/emote.dm
+++ b/code/modules/mob/living/silicon/emote.dm
@@ -1,113 +1,13 @@
-/mob/living/silicon/emote(var/act, var/m_type = 1,var/message = null)
- var/param = null
- if(findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- param = copytext(act, t1 + 1, length(act) + 1)
- act = copytext(act, 1, t1)
+var/list/_silicon_default_emotes = list(
+ /decl/emote/audible/synth,
+ /decl/emote/audible/synth/ping,
+ /decl/emote/audible/synth/buzz,
+ /decl/emote/audible/synth/confirm,
+ /decl/emote/audible/synth/deny,
+ /decl/emote/audible/synth/dwoop,
+ /decl/emote/audible/synth/security,
+ /decl/emote/audible/synth/security/halt
+)
- if(findtext(act, "s", -1) && !findtext(act, "_", -2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act, 1, length(act))
-
- switch(act)
- if("beep")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if (param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] beeps at [param]."
- else
- message = "[src] beeps."
- playsound(src, 'sound/machines/twobeep.ogg', 50, 0)
- m_type = 1
-
- if("ping")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if (param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] pings at [param]."
- else
- message = "[src] pings."
- playsound(src, 'sound/machines/ping.ogg', 50, 0)
- m_type = 1
-
- if("buzz")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if (param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] buzzes at [param]."
- else
- message = "[src] buzzes."
- playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
- m_type = 1
-
- if("yes", "ye")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if (param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] emits an affirmative blip at [param]."
- else
- message = "[src] emits an affirmative blip."
- playsound(src, 'sound/machines/synth_yes.ogg', 50, 0)
- m_type = 1
-
- if("dwoop")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] chirps happily at [param]"
- else
- message = "[src] chirps happily."
- playsound(src, 'sound/machines/dwoop.ogg', 50, 0)
- m_type = 1
-
- if("no")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if (param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] emits a negative blip at [param]."
- else
- message = "[src] emits a negative blip."
- playsound(src, 'sound/machines/synth_no.ogg', 50, 0)
- m_type = 1
-
- ..(act, m_type, message)
\ No newline at end of file
+/mob/living/silicon/get_default_emotes()
+ return global._silicon_default_emotes
diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm
index 9560c6b528e..2b83568e7bf 100644
--- a/code/modules/mob/living/silicon/robot/emote.dm
+++ b/code/modules/mob/living/silicon/robot/emote.dm
@@ -1,155 +1,33 @@
-/mob/living/silicon/robot/emote(var/act,var/m_type=1,var/message = null)
- var/param = null
- if(findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- param = copytext(act, t1 + 1, length(act) + 1)
- act = copytext(act, 1, t1)
+var/list/_robot_default_emotes = list(
+ /decl/emote/audible/clap,
+ /decl/emote/visible/bow,
+ /decl/emote/visible/salute,
+ /decl/emote/visible/flap,
+ /decl/emote/visible/aflap,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/twitch_v,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/glare,
+ /decl/emote/visible/look,
+ /decl/emote/visible/stare,
+ /decl/emote/visible/deathgasp_robot,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible/synth,
+ /decl/emote/audible/synth/ping,
+ /decl/emote/audible/synth/buzz,
+ /decl/emote/audible/synth/confirm,
+ /decl/emote/audible/synth/deny,
+ /decl/emote/audible/synth/dwoop,
+ /decl/emote/audible/synth/security,
+ /decl/emote/audible/synth/security/halt,
+ //VOREStation Add
+ /decl/emote/visible/mlem,
+ /decl/emote/visible/blep
+ //VOREStation Add End
+)
- if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act,1,length(act))
-
- switch(act)
- if("salute")
- if(!src.buckled)
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "[src] salutes to [param]."
- else
- message = "[src] salutes."
- m_type = 1
- if("bow")
- if(!src.buckled)
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "[src] bows to [param]."
- else
- message = "[src] bows."
- m_type = 1
-
- if("clap")
- if(!src.restrained())
- message = "[src] claps."
- m_type = 2
- if("flap")
- if(!src.restrained())
- message = "[src] flaps its wings."
- m_type = 2
-
- if("aflap")
- if(!src.restrained())
- message = "[src] flaps its wings ANGRILY!"
- m_type = 2
-
- if("twitch")
- message = "[src] twitches."
- m_type = 1
-
- if("twitch_v")
- message = "[src] twitches violently."
- m_type = 1
-
- if("nod")
- message = "[src] nods."
- m_type = 1
-
- if("deathgasp")
- message = "[src] shudders violently for a moment, then becomes motionless, its eyes slowly darkening."
- m_type = 1
-
- if("glare")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "[src] glares at [param]."
- else
- message = "[src] glares."
-
- if("stare")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "[src] stares at [param]."
- else
- message = "[src] stares."
-
- if("look")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
-
- if(!M)
- param = null
-
- if(param)
- message = "[src] looks at [param]."
- else
- message = "[src] looks."
- m_type = 1
-
- if("law")
- if(istype(module,/obj/item/weapon/robot_module/robot/security) || istype(module,/obj/item/weapon/robot_module/robot/knine)) //VOREStation Add - K9
- message = "[src] shows its legal authorization barcode."
-
- playsound(src, 'sound/voice/biamthelaw.ogg', 50, 0)
- m_type = 2
- else
- to_chat(src, "You are not THE LAW, pal.")
-
- if("halt")
- if(istype(module,/obj/item/weapon/robot_module/robot/security) || istype(module,/obj/item/weapon/robot_module/robot/knine)) //VOREStation Add - K9
- message = "[src] 's speakers skreech, \"Halt! Security!\"."
-
- playsound(src, 'sound/voice/halt.ogg', 50, 0)
- m_type = 2
- else
- to_chat(src, "You are not security.")
- //Vorestation addition start
- if("bark")
- if (istype(module,/obj/item/weapon/robot_module/robot/knine) || istype(module,/obj/item/weapon/robot_module/robot/medihound) || istype(module,/obj/item/weapon/robot_module/robot/scrubpup) || istype(module,/obj/item/weapon/robot_module/robot/ert) || istype(module,/obj/item/weapon/robot_module/robot/science) || istype(module,/obj/item/weapon/robot_module/robot/engiedog) || istype(module,/obj/item/weapon/robot_module/robot/clerical/brodog) || istype(module,/obj/item/weapon/robot_module/robot/kmine) )
- message = "[src] lets out a bark."
-
- playsound(src, 'sound/voice/bark2.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- m_type = 2
- else
- to_chat(src, "You're not a dog!")
- //Vorestation addition end
-
-
-
- if("help")
- to_chat(src, "salute, bow-(none)/mob, clap, flap, aflap, twitch, twitch_s, nod, deathgasp, glare-(none)/mob, stare-(none)/mob, look, beep, ping, \nbuzz, law, halt, yes, dwoop, no")
-
- ..(act, m_type, message)
+/mob/living/silicon/robot/get_default_emotes()
+ return global._robot_default_emotes
diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm
index ef870cb1f35..34f6096ede0 100644
--- a/code/modules/mob/living/silicon/say.dm
+++ b/code/modules/mob/living/silicon/say.dm
@@ -114,7 +114,7 @@
return 0
return 1
-/mob/living/silicon/ai/emote(var/act, var/type, var/message)
+/mob/living/silicon/ai/emote(var/act, var/m_type, var/message)
var/obj/machinery/hologram/holopad/T = holo
if(T && T.masters[src]) //Is the AI using a holopad?
. = holopad_emote(message)
diff --git a/code/modules/mob/living/simple_mob/simple_mob_vr.dm b/code/modules/mob/living/simple_mob/simple_mob_vr.dm
index b51577ce078..f18a745486b 100644
--- a/code/modules/mob/living/simple_mob/simple_mob_vr.dm
+++ b/code/modules/mob/living/simple_mob/simple_mob_vr.dm
@@ -84,6 +84,7 @@
icon_state = "[icon_dead]-[vore_fullness]"
else if(((stat == UNCONSCIOUS) || resting || incapacitated(INCAPACITATION_DISABLED) ) && icon_rest && (vore_icons & SA_ICON_REST))
icon_state = "[icon_rest]-[vore_fullness]"
+ update_transform()
/mob/living/simple_mob/proc/will_eat(var/mob/living/M)
if(client) //You do this yourself, dick!
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm b/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm
index 9db6a6bffa0..c48f94bf277 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm
@@ -1,3 +1,32 @@
+var/list/_cat_default_emotes = list(
+ /decl/emote/visible,
+ /decl/emote/visible/scratch,
+ /decl/emote/visible/drool,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/sway,
+ /decl/emote/visible/sulk,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/twitch_v,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/roll,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/jump,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/collapse,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible,
+ /decl/emote/audible/hiss,
+ /decl/emote/audible/whimper,
+ /decl/emote/audible/gasp,
+ /decl/emote/audible/scretch,
+ /decl/emote/audible/choke,
+ /decl/emote/audible/moan,
+ /decl/emote/audible/gnarl,
+ /decl/emote/audible/purr,
+ /decl/emote/audible/purrlong
+)
+
/mob/living/simple_mob/animal/passive/cat
name = "cat"
desc = "A domesticated, feline pet. Has a tendency to adopt crewmembers."
@@ -28,6 +57,9 @@
update_icon()
return ..()
+/mob/living/simple_mob/animal/passive/cat/get_default_emotes()
+ return global._cat_default_emotes
+
/mob/living/simple_mob/animal/passive/cat/handle_special()
if(!stat && prob(2)) // spooky
var/mob/observer/dead/spook = locate() in range(src, 5)
diff --git a/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm b/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
index a5419bc5599..f8d47a4b2dc 100644
--- a/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
@@ -1,5 +1,21 @@
-// The top-level slime defines. Xenobio slimes and feral slimes will inherit from this.
+var/list/_slime_default_emotes = list(
+ /decl/emote/audible/moan,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/sway,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/bounce,
+ /decl/emote/visible/jiggle,
+ /decl/emote/visible/lightup,
+ /decl/emote/visible/vibrate,
+ /decl/emote/slime,
+ /decl/emote/slime/pout,
+ /decl/emote/slime/sad,
+ /decl/emote/slime/angry,
+ /decl/emote/slime/frown,
+ /decl/emote/slime/smile
+)
+// The top-level slime defines. Xenobio slimes and feral slimes will inherit from this.
/mob/living/simple_mob/slime
name = "slime"
desc = "It's a slime."
@@ -64,6 +80,9 @@
can_enter_vent_with = list(/obj/item/clothing/head)
+/mob/living/simple_mob/slime/get_default_emotes()
+ return global._slime_default_emotes
+
/datum/say_list/slime
speak = list("Blorp...", "Blop...")
emote_see = list("bounces", "jiggles", "sways")
diff --git a/code/modules/mob/living/voice/voice.dm b/code/modules/mob/living/voice/voice.dm
index 2d070d1a298..9caa58cb33d 100644
--- a/code/modules/mob/living/voice/voice.dm
+++ b/code/modules/mob/living/voice/voice.dm
@@ -137,6 +137,6 @@
return TRUE
return ..()
-/mob/living/voice/custom_emote(var/m_type=1,var/message = null,var/range=world.view)
+/mob/living/voice/custom_emote(var/m_type = VISIBLE_MESSAGE, var/message = null, var/range = world.view)
if(!comm) return
..(m_type,message,comm.video_range)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 3b4b478a7eb..c41691a8575 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -42,6 +42,7 @@
lastarea = get_area(src)
hook_vr("mob_new",list(src)) //VOREStation Code
update_transform() // Some mobs may start bigger or smaller than normal.
+ update_emotes()
return ..()
/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
@@ -49,19 +50,19 @@
if(!client && !teleop) return
if (type)
- if((type & 1) && (is_blind() || paralysis) )//Vision related
+ if((type & VISIBLE_MESSAGE) && (is_blind() || paralysis) )//Vision related
if (!( alt ))
return
else
msg = alt
type = alt_type
- if ((type & 2) && is_deaf())//Hearing related
+ if ((type & AUDIBLE_MESSAGE) && is_deaf())//Hearing related
if (!( alt ))
return
else
msg = alt
type = alt_type
- if ((type & 1) && (sdisabilities & BLIND))
+ if ((type & VISIBLE_MESSAGE) && (sdisabilities & BLIND))
return
// Added voice muffling for Issue 41.
if(stat == UNCONSCIOUS || sleeping > 0)
@@ -77,14 +78,17 @@
// message is the message output to anyone who can see e.g. "[src] does something!"
// self_message (optional) is what the src mob sees e.g. "You do something!"
// blind_message (optional) is what blind people will hear e.g. "You hear something!"
-/mob/visible_message(var/message, var/self_message, var/blind_message, var/list/exclude_mobs = null)
+/mob/visible_message(var/message, var/self_message, var/blind_message, var/list/exclude_mobs = null, var/range = world.view)
if(self_message)
if(LAZYLEN(exclude_mobs))
exclude_mobs |= src
else
exclude_mobs = list(src)
src.show_message(self_message, 1, blind_message, 2)
- . = ..(message, blind_message, exclude_mobs)
+ // Transfer messages about what we are doing to upstairs
+ if(shadow)
+ shadow.visible_message(message, self_message, blind_message, exclude_mobs, range)
+ . = ..(message, blind_message, exclude_mobs, range) // Really not ideal that atom/visible_message has different arg numbering :(
// Returns an amount of power drawn from the object (-1 if it's not viable).
// If drain_check is set it will not actually drain power, just return a value.
@@ -99,7 +103,7 @@
// self_message (optional) is what the src mob hears.
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
-/mob/audible_message(var/message, var/deaf_message, var/hearing_distance, var/self_message)
+/mob/audible_message(var/message, var/deaf_message, var/hearing_distance, var/self_message, var/radio_message)
var/range = hearing_distance || world.view
var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src),range,remote_ghosts = FALSE)
@@ -107,16 +111,21 @@
var/list/hearing_mobs = hear["mobs"]
var/list/hearing_objs = hear["objs"]
- for(var/obj in hearing_objs)
- var/obj/O = obj
- O.show_message(message, 2, deaf_message, 1)
+ if(radio_message)
+ for(var/obj in hearing_objs)
+ var/obj/O = obj
+ O.hear_talk(src, list(new /datum/multilingual_say_piece(GLOB.all_languages["Noise"], radio_message)), null)
+ else
+ for(var/obj in hearing_objs)
+ var/obj/O = obj
+ O.show_message(message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
for(var/mob in hearing_mobs)
var/mob/M = mob
var/msg = message
if(self_message && M==src)
msg = self_message
- M.show_message(msg, 2, deaf_message, 1)
+ M.show_message(msg, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
/mob/proc/findname(msg)
for(var/mob/M in mob_list)
@@ -576,9 +585,6 @@
/mob/proc/get_gender()
return gender
-/mob/proc/get_visible_gender()
- return gender
-
/mob/proc/see(message)
if(!is_active())
return 0
diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm
index f04cde9c4cf..1a13a7ed621 100644
--- a/code/modules/mob/new_player/sprite_accessories.dm
+++ b/code/modules/mob/new_player/sprite_accessories.dm
@@ -28,7 +28,7 @@
// Determines if the accessory will be skipped or included in random hair generations
var/gender = NEUTER
- // Restrict some styles to specific species
+ // Restrict some styles to specific species. Set to null to perform no checking.
var/list/species_allowed = list(SPECIES_HUMAN,SPECIES_PROMETHEAN,SPECIES_HUMAN_VATBORN)
// Whether or not the accessory can be affected by colouration
@@ -38,7 +38,6 @@
// Ckey of person allowed to use this, if defined.
var/list/ckeys_allowed = null
- var/apply_restrictions = FALSE //whether to apply restrictions for specific tails/ears/wings
/*
////////////////////////////
diff --git a/code/modules/mob/new_player/sprite_accessories_ear.dm b/code/modules/mob/new_player/sprite_accessories_ear.dm
index 6262b8ba606..24e82043e41 100644
--- a/code/modules/mob/new_player/sprite_accessories_ear.dm
+++ b/code/modules/mob/new_player/sprite_accessories_ear.dm
@@ -23,7 +23,7 @@
icon_state = "shadekin"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
- apply_restrictions = TRUE
+ species_allowed = list() // SPECIES_SHADEKIN, SPECIES_SHADEKIN_CREW
/datum/sprite_accessory/ears/taj_ears
name = "Tajaran Ears"
diff --git a/code/modules/mob/new_player/sprite_accessories_ear_vr.dm b/code/modules/mob/new_player/sprite_accessories_ear_vr.dm
index 7705e1a8217..fd82cac5b2e 100644
--- a/code/modules/mob/new_player/sprite_accessories_ear_vr.dm
+++ b/code/modules/mob/new_player/sprite_accessories_ear_vr.dm
@@ -20,7 +20,6 @@
icon_state = "shadekin"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
- apply_restrictions = TRUE
species_allowed = list(SPECIES_SHADEKIN, SPECIES_SHADEKIN_CREW)
// Ears avaliable to anyone
diff --git a/code/modules/mob/new_player/sprite_accessories_tail.dm b/code/modules/mob/new_player/sprite_accessories_tail.dm
index 0b8d75b84e3..dec95139744 100644
--- a/code/modules/mob/new_player/sprite_accessories_tail.dm
+++ b/code/modules/mob/new_player/sprite_accessories_tail.dm
@@ -922,7 +922,6 @@
icon_state = "shadekin-short"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
- //apply_restrictions = TRUE
//species_allowed = list(SPECIES_SHADEKIN, SPECIES_SHADEKIN_CREW)
/datum/sprite_accessory/tail/wartacosushi_tail //brightened +20RGB from matching roboparts
diff --git a/code/modules/mob/new_player/sprite_accessories_taur.dm b/code/modules/mob/new_player/sprite_accessories_taur.dm
index db2394f84af..dad54ed188c 100644
--- a/code/modules/mob/new_player/sprite_accessories_taur.dm
+++ b/code/modules/mob/new_player/sprite_accessories_taur.dm
@@ -333,7 +333,6 @@
hide_body_parts = null
clip_mask_icon = null
clip_mask_state = null
- //apply_restrictions = TRUE
//species_allowed = list(SPECIES_SHADEKIN, SPECIES_SHADEKIN_CREW)
/datum/sprite_accessory/tail/taur/shadekin_tail/shadekin_tail_2c
diff --git a/code/modules/mob/new_player/sprite_accessories_taur_vr.dm b/code/modules/mob/new_player/sprite_accessories_taur_vr.dm
index 4bc79e1629b..fc3994b528f 100644
--- a/code/modules/mob/new_player/sprite_accessories_taur_vr.dm
+++ b/code/modules/mob/new_player/sprite_accessories_taur_vr.dm
@@ -83,6 +83,12 @@
extra_overlay2 = "synthwolf_glow"
//icon_sprite_tag = "synthwolf"
+/datum/sprite_accessory/tail/taur/ch/wolf/fatsynthwolf
+ name = "Fat SynthWolf dual-color (Taur)"
+ icon_state = "fatsynthwolf_s"
+ extra_overlay = "fatsynthwolf_markings"
+ extra_overlay2 = "fatsynthwolf_glow"
+
/datum/sprite_accessory/tail/taur/skunk
name = "Skunk (Taur)"
icon_state = "skunk_s"
@@ -213,6 +219,15 @@
extra_overlay = "lizard_markings"
//icon_sprite_tag = "lizard2c"
+/datum/sprite_accessory/tail/taur/ch/lizard/fat
+ name = "Fat Lizard (Taur)"
+ icon_state = "fatlizard_s"
+
+/datum/sprite_accessory/tail/taur/ch/lizard/fat_2c
+ name = "Fat Lizard (Taur, dual-color)"
+ icon_state = "fatlizard_s"
+ extra_overlay= "fatlizard_markings"
+
/datum/sprite_accessory/tail/taur/lizard/synthlizard
name = "SynthLizard dual-color (Taur)"
icon_state = "synthlizard_s"
@@ -220,6 +235,12 @@
extra_overlay2 = "synthlizard_glow"
//icon_sprite_tag = "synthlizard"
+/datum/sprite_accessory/tail/taur/ch/lizard/fatsynthlizard
+ name = "Fat SynthLizard dual-color (Taur)"
+ icon_state = "fatsynthlizard_s"
+ extra_overlay = "fatsynthlizard_markings"
+ extra_overlay2 = "fatsynthlizard_glow"
+
/datum/sprite_accessory/tail/taur/spider
name = "Spider (Taur)"
icon_state = "spider_s"
@@ -305,6 +326,12 @@
extra_overlay2 = "synthfeline_glow"
//icon_sprite_tag = "synthfeline"
+/datum/sprite_accessory/tail/taur/ch/feline/fatsynthfeline
+ name = "Fat SynthFeline dual-color (Taur)"
+ icon_state = "fatsynthfeline_s"
+ extra_overlay = "fatsynthfeline_markings"
+ extra_overlay2 = "fatsynthfeline_glow"
+
/datum/sprite_accessory/tail/taur/slug
name = "Slug (Taur)"
icon_state = "slug_s"
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index 52e843a9eeb..c30d256c596 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -105,11 +105,6 @@
verb = "asks"
return verb
-
-/mob/proc/emote(var/act, var/type, var/message)
- if(act == "me")
- return custom_emote(type, message)
-
/mob/proc/get_ear()
// returns an atom representing a location on the map from which this
// mob can hear things
diff --git a/code/modules/multiz/zshadow.dm b/code/modules/multiz/zshadow.dm
index fcc5ecad650..e43ab219395 100644
--- a/code/modules/multiz/zshadow.dm
+++ b/code/modules/multiz/zshadow.dm
@@ -113,12 +113,6 @@
if(shadow)
shadow.set_dir(new_dir)
-// Transfer messages about what we are doing to upstairs
-/mob/visible_message(var/message, var/self_message, var/blind_message, var/list/exclude_mobs = null)
- . = ..()
- if(shadow)
- shadow.visible_message(message, self_message, blind_message, exclude_mobs)
-
/mob/zshadow/set_typing_indicator(var/state)
if(!typing_indicator)
init_typing_indicator("typing")
diff --git a/code/modules/nifsoft/software/01_vision.dm b/code/modules/nifsoft/software/01_vision.dm
index 7a792009f45..c68a6feb0cc 100644
--- a/code/modules/nifsoft/software/01_vision.dm
+++ b/code/modules/nifsoft/software/01_vision.dm
@@ -34,9 +34,9 @@
/datum/nifsoft/ar_eng
name = "AR Overlay (Eng)"
- desc = "Like the civilian model, but provides station alert notices."
+ desc = "Like the civilian model, but provides ... well, nothing. For now."
list_pos = NIF_ENGINE_AR
- cost = 375
+ cost = 250
access = access_engine
a_drain = 0.01
planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_AUGMENTED)
@@ -47,7 +47,7 @@
name = "AR Overlay (Sci)"
desc = "Like the civilian model, but provides ... well, nothing. For now."
list_pos = NIF_SCIENCE_AR
- cost = 375
+ cost = 250
access = access_research
a_drain = 0.01
planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_AUGMENTED)
diff --git a/code/modules/nifsoft/software/13_soulcatcher.dm b/code/modules/nifsoft/software/13_soulcatcher.dm
index c1de0855326..07607216fbe 100644
--- a/code/modules/nifsoft/software/13_soulcatcher.dm
+++ b/code/modules/nifsoft/software/13_soulcatcher.dm
@@ -45,14 +45,14 @@
/datum/nifsoft/soulcatcher/install()
if((. = ..()))
nif.set_flag(NIF_O_SCOTHERS,NIF_FLAGS_OTHER) //Required on install, because other_flags aren't sufficient for our complicated settings.
- nif.human.verbs |= /mob/living/carbon/human/proc/nsay
- nif.human.verbs |= /mob/living/carbon/human/proc/nme
+ nif.human.verbs |= /mob/living/carbon/human/nsay
+ nif.human.verbs |= /mob/living/carbon/human/nme
/datum/nifsoft/soulcatcher/uninstall()
QDEL_LIST_NULL(brainmobs)
if((. = ..()) && nif && nif.human) //Sometimes NIFs are deleted outside of a human
- nif.human.verbs -= /mob/living/carbon/human/proc/nsay
- nif.human.verbs -= /mob/living/carbon/human/proc/nme
+ nif.human.verbs -= /mob/living/carbon/human/nsay
+ nif.human.verbs -= /mob/living/carbon/human/nme
/datum/nifsoft/soulcatcher/proc/save_settings()
if(!nif)
@@ -476,20 +476,26 @@
///////////////////
//Verbs for humans
-/mob/living/carbon/human/proc/nsay(message as text|null)
+/mob/proc/nsay(message as text|null)
set name = "NSay"
set desc = "Speak into your NIF's Soulcatcher."
set category = "IC"
+ to_chat(src, SPAN_WARNING("You must be a humanoid with a NIF implanted to use that."))
+
+/mob/living/carbon/human/nsay(message as text|null)
+ if(stat != CONSCIOUS)
+ to_chat(src,SPAN_WARNING("You can't use NSay while unconscious."))
+ return
if(!nif)
- to_chat(src,"You can't use NSay without a NIF.")
+ to_chat(src,SPAN_WARNING("You can't use NSay without a NIF."))
return
var/datum/nifsoft/soulcatcher/SC = nif.imp_check(NIF_SOULCATCHER)
if(!SC)
- to_chat(src,"You need the Soulcatcher software to use NSay.")
+ to_chat(src,SPAN_WARNING("You need the Soulcatcher software to use NSay."))
return
if(!SC.brainmobs.len)
- to_chat(src,"You need a loaded mind to use NSay.")
+ to_chat(src,SPAN_WARNING("You need a loaded mind to use NSay."))
return
if(!message)
message = input("Type a message to say.","Speak into Soulcatcher") as text|null
@@ -497,20 +503,26 @@
var/sane_message = sanitize(message)
SC.say_into(sane_message,src)
-/mob/living/carbon/human/proc/nme(message as text|null)
+/mob/proc/nme(message as text|null)
set name = "NMe"
set desc = "Emote into your NIF's Soulcatcher."
set category = "IC"
+
+ to_chat(src, SPAN_WARNING("You must be a humanoid with a NIF implanted to use that."))
+/mob/living/carbon/human/nme(message as text|null)
+ if(stat != CONSCIOUS)
+ to_chat(src,SPAN_WARNING("You can't use NMe while unconscious."))
+ return
if(!nif)
- to_chat(src,"You can't use NMe without a NIF.")
+ to_chat(src,SPAN_WARNING("You can't use NMe without a NIF."))
return
var/datum/nifsoft/soulcatcher/SC = nif.imp_check(NIF_SOULCATCHER)
if(!SC)
- to_chat(src,"You need the Soulcatcher software to use NMe.")
+ to_chat(src,SPAN_WARNING("You need the Soulcatcher software to use NMe."))
return
if(!SC.brainmobs.len)
- to_chat(src,"You need a loaded mind to use NMe.")
+ to_chat(src,SPAN_WARNING("You need a loaded mind to use NMe."))
return
if(!message)
@@ -563,7 +575,7 @@
QDEL_NULL(eyeobj)
soulcatcher.notify_into("[src] ended AR projection.")
-/mob/living/carbon/brain/caught_soul/verb/nsay(message as text|null)
+/mob/living/carbon/brain/caught_soul/verb/nsay_brain(message as text|null)
set name = "NSay"
set desc = "Speak into the NIF's Soulcatcher (circumventing AR speaking)."
set category = "Soulcatcher"
@@ -574,7 +586,7 @@
var/sane_message = sanitize(message)
soulcatcher.say_into(sane_message,src,null)
-/mob/living/carbon/brain/caught_soul/verb/nme(message as text|null)
+/mob/living/carbon/brain/caught_soul/verb/nme_brain(message as text|null)
set name = "NMe"
set desc = "Emote into the NIF's Soulcatcher (circumventing AR speaking)."
set category = "Soulcatcher"
diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm
index c334a3a2829..3a4717224ee 100644
--- a/code/modules/organs/internal/brain.dm
+++ b/code/modules/organs/internal/brain.dm
@@ -276,19 +276,19 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain)
qdel(src)
return 1
-/datum/chemical_reaction/promethean_brain_revival
+/decl/chemical_reaction/instant/promethean_brain_revival
name = "Promethean Revival"
id = "prom_revival"
result = null
required_reagents = list("phoron" = 40)
result_amount = 1
-/datum/chemical_reaction/promethean_brain_revival/can_happen(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/promethean_brain_revival/can_happen(var/datum/reagents/holder)
if(holder.my_atom && istype(holder.my_atom, /obj/item/organ/internal/brain/slime))
return ..()
return FALSE
-/datum/chemical_reaction/promethean_brain_revival/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/promethean_brain_revival/on_reaction(var/datum/reagents/holder)
var/obj/item/organ/internal/brain/slime/brain = holder.my_atom
if(brain.reviveBody())
brain.visible_message("[brain] bubbles, surrounding itself with a rapidly expanding mass of slime!")
diff --git a/code/modules/planet/sif.dm b/code/modules/planet/sif.dm
index 798cebcaac2..cefc549d2a6 100644
--- a/code/modules/planet/sif.dm
+++ b/code/modules/planet/sif.dm
@@ -156,6 +156,9 @@ var/datum/planet/sif/planet_sif = null
sky_visible = TRUE
observed_message = "The sky is clear."
+ outdoor_sounds_type = /datum/looping_sound/weather/wind/gentle
+ indoor_sounds_type = /datum/looping_sound/weather/wind/gentle/indoors
+
/datum/weather/sif/overcast
name = "overcast"
light_modifier = 0.8
@@ -174,6 +177,9 @@ var/datum/planet/sif/planet_sif = null
"It's very cloudy."
)
+ outdoor_sounds_type = /datum/looping_sound/weather/wind/gentle
+ indoor_sounds_type = /datum/looping_sound/weather/wind/gentle/indoors
+
/datum/weather/sif/light_snow
name = "light snow"
icon_state = "snowfall_light"
@@ -192,6 +198,9 @@ var/datum/planet/sif/planet_sif = null
"It begins to snow lightly.",
)
+ outdoor_sounds_type = /datum/looping_sound/weather/wind/gentle
+ indoor_sounds_type = /datum/looping_sound/weather/wind/gentle/indoors
+
/datum/weather/sif/snow
name = "moderate snow"
icon_state = "snowfall_med"
@@ -282,8 +291,8 @@ var/datum/planet/sif/planet_sif = null
transition_messages = list(
"The sky is dark, and rain falls down upon you."
)
-// outdoor_sounds_type = /datum/looping_sound/weather/rain
-// indoor_sounds_type = /datum/looping_sound/weather/rain/indoors
+ outdoor_sounds_type = /datum/looping_sound/weather/rain
+ indoor_sounds_type = /datum/looping_sound/weather/rain/indoors
/datum/weather/sif/rain/process_effects()
..()
@@ -327,8 +336,8 @@ var/datum/planet/sif/planet_sif = null
"Loud thunder is heard in the distance.",
"A bright flash heralds the approach of a storm."
)
-// outdoor_sounds_type = /datum/looping_sound/weather/rain
-// indoor_sounds_type = /datum/looping_sound/weather/rain/indoors
+ outdoor_sounds_type = /datum/looping_sound/weather/rain/heavy
+ indoor_sounds_type = /datum/looping_sound/weather/rain/heavy/indoors
transition_chances = list(
diff --git a/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm b/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm
index 91c08513a58..89b11da6c10 100644
--- a/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm
+++ b/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm
@@ -1,3 +1,4 @@
+#define FUSION_ROD_SHEET_AMT 15
/obj/machinery/fusion_fuel_compressor
name = "fuel compressor"
icon = 'icons/obj/machines/power/fusion.dmi'
@@ -53,15 +54,17 @@
if(!mat.is_fusion_fuel)
to_chat(user, "It would be pointless to make a fuel rod out of [mat.use_name].")
return
- if(M.get_amount() < 15)
+ if(M.get_amount() < FUSION_ROD_SHEET_AMT)
to_chat(user, "You need at least 25 [mat.sheet_plural_name] to make a fuel rod.")
return
var/obj/item/weapon/fuel_assembly/F = new(get_turf(src), mat.name)
visible_message("\The [src] compresses the [mat.use_name] into a new fuel assembly.")
- M.use(15)
+ M.use(FUSION_ROD_SHEET_AMT)
user.put_in_hands(F)
else if(do_special_fuel_compression(thing, user))
return
- return ..()
\ No newline at end of file
+ return ..()
+
+#undef FUSION_ROD_SHEET_AMT
\ No newline at end of file
diff --git a/code/modules/power/fusion/fusion_reagents.dm b/code/modules/power/fusion/fusion_reagents.dm
deleted file mode 100644
index 80b1cbb3361..00000000000
--- a/code/modules/power/fusion/fusion_reagents.dm
+++ /dev/null
@@ -1,18 +0,0 @@
-//Additional fusion reagents. These likely don't have any other use aside from the RUST, but if you want to make stuff with 'em, be my guest.
-
-/datum/reagent/helium3
- name = "helium-3"
- description = "A colorless, odorless, tasteless and generally inert gas used in fusion reactors. Non-radioactive."
- id = "helium-3"
- reagent_state = GAS
- color = "#808080"
-
-/obj/structure/reagent_dispensers/he3
- name = "fueltank"
- desc = "A fueltank."
- icon = 'icons/obj/objects.dmi'
- icon_state = "weldtank"
- amount_per_transfer_from_this = 10
- New()
- ..()
- reagents.add_reagent("helium-3",1000)
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/energy/laser_vr.dm b/code/modules/projectiles/guns/energy/laser_vr.dm
index fe29c85f0ee..4256cb50d45 100644
--- a/code/modules/projectiles/guns/energy/laser_vr.dm
+++ b/code/modules/projectiles/guns/energy/laser_vr.dm
@@ -189,12 +189,14 @@
return 0
return ..()
-//Expedition Frontier Phaser
+////////////////Expedition Frontier Phaser////////////////
+
/obj/item/weapon/gun/energy/locked/frontier
name = "frontier phaser"
desc = "An extraordinarily rugged laser weapon, built to last and requiring effectively no maintenance. Includes a built-in crank charger for recharging away from civilization. This one has a safety interlock that prevents firing while in proximity to the facility."
+ description_fluff = "The NT Brand Model E2 Secured Phaser System, a specialty phaser that has an intergrated chip that prevents the user from opperating the weapon within the vicinity of any NanoTrasen opperated outposts/stations/bases. However, this chip can be disabled so the weapon CAN BE used in the vicinity of any NanoTrasen opperated outposts/stations/bases. The weapon doesn't use traditional weapon power cells and instead works via a pump action that recharges the internal cells. It is a staple amongst exploration personell who usually don't have the license to opperate a lethal weapon through NT and provides them with a weapon that can be recharged away from civilization."
icon = 'icons/obj/gun_vr.dmi'
- icon_state = "phaser"
+ icon_state = "phaserkill"
item_state = "phaser"
item_icons = list(slot_l_hand_str = 'icons/mob/items/lefthand_guns_vr.dmi', slot_r_hand_str = 'icons/mob/items/righthand_guns_vr.dmi', "slot_belt" = 'icons/mob/belt_vr.dmi')
fire_sound = 'sound/weapons/laser2.ogg'
@@ -208,9 +210,11 @@
var/phase_power = 75
projectile_type = /obj/item/projectile/beam/blue
+
+ modifystate = "phaserkill"
firemodes = list(
- list(mode_name="lethal", fire_delay=12, projectile_type=/obj/item/projectile/beam/blue, charge_cost = 300),
- list(mode_name="low-power", fire_delay=8, projectile_type=/obj/item/projectile/beam/weaklaser/blue, charge_cost = 80),
+ list(mode_name="lethal", fire_delay=12, projectile_type=/obj/item/projectile/beam/blue, modifystate="phaserkill", charge_cost = 300),
+ list(mode_name="low-power", fire_delay=8, projectile_type=/obj/item/projectile/beam/weaklaser/blue, modifystate="phaserstun", charge_cost = 80),
)
/obj/item/weapon/gun/energy/locked/frontier/unload_ammo(var/mob/user)
@@ -249,19 +253,22 @@
locked = 0
lockable = 0
-//Phaser Carbine - Reskinned phaser
+////////////////Phaser Carbine////////////////
+
/obj/item/weapon/gun/energy/locked/frontier/carbine
name = "frontier carbine"
desc = "An ergonomically improved version of the venerable frontier phaser, the carbine is a fairly new weapon, and has only been produced in limited numbers so far. Includes a built-in crank charger for recharging away from civilization. This one has a safety interlock that prevents firing while in proximity to the facility."
+ description_fluff = "The NT Brand Model AT2 Secured Phaser System, a specialty phaser that has an intergrated chip that prevents the user from opperating the weapon within the vicinity of any NanoTrasen opperated outposts/stations/bases. However, this chip can be disabled so the weapon CAN BE used in the vicinity of any NanoTrasen opperated outposts/stations/bases. The weapon doesn't use traditional weapon power cells and instead works via a pump action that recharges the internal cells. It is a staple amongst exploration personell who usually don't have the license to opperate a lethal weapon through NT and provides them with a weapon that can be recharged away from civilization."
icon = 'icons/obj/gun_vr.dmi'
icon_state = "carbinekill"
- item_state = "retro"
+ item_state = "energykill"
item_icons = list(slot_l_hand_str = 'icons/mob/items/lefthand_guns.dmi', slot_r_hand_str = 'icons/mob/items/righthand_guns.dmi')
+ phase_power = 150
modifystate = "carbinekill"
firemodes = list(
- list(mode_name="lethal", fire_delay=12, projectile_type=/obj/item/projectile/beam/blue, modifystate="carbinekill", charge_cost = 300),
- list(mode_name="low-power", fire_delay=8, projectile_type=/obj/item/projectile/beam/weaklaser/blue, modifystate="carbinestun", charge_cost = 80),
+ list(mode_name="lethal", fire_delay=8, projectile_type=/obj/item/projectile/beam/blue, modifystate="carbinekill", charge_cost = 300),
+ list(mode_name="low-power", fire_delay=5, projectile_type=/obj/item/projectile/beam/weaklaser/blue, modifystate="carbinestun", charge_cost = 80),
)
/obj/item/weapon/gun/energy/locked/frontier/carbine/update_icon()
@@ -272,12 +279,13 @@
..()
/obj/item/weapon/gun/energy/locked/frontier/carbine/unlocked
- desc = "An ergonomically improved version of the venerable frontier phaser, the carbine is a fairly new weapon, and has only been produced in limited numbers so far."
+ desc = "An ergonomically improved version of the venerable frontier phaser, the carbine is a fairly new weapon, and has only been produced in limited numbers so far. Includes a built-in crank charger for recharging away from civilization."
req_access = newlist() //for toggling safety
locked = 0
lockable = 0
-//Expeditionary Holdout Phaser Pistol
+////////////////Expeditionary Holdout Phaser Pistol////////////////
+
/obj/item/weapon/gun/energy/locked/frontier/holdout
name = "holdout frontier phaser"
desc = "An minaturized weapon designed for the purpose of expeditionary support to defend themselves on the field. Includes a built-in crank charger for recharging away from civilization. This one has a safety interlock that prevents firing while in proximity to the facility."
@@ -300,3 +308,51 @@
req_access = newlist() //for toggling safety
locked = 0
lockable = 0
+
+////////////////Phaser Rifle////////////////
+
+/obj/item/weapon/gun/energy/locked/frontier/rifle
+ name = "frontier marksman rifle"
+ desc = "A much larger, heavier weapon than the typical frontier-type weapons, this DMR can be fired both from the hip, and in scope. Includes a built-in crank charger for recharging away from civilization. This one has a safety interlock that prevents firing while in proximity to the facility."
+ icon = 'icons/obj/gun_vr.dmi'
+ icon_state = "riflekill"
+ item_state = "sniper"
+ item_state_slots = list(slot_r_hand_str = "lsniper", slot_l_hand_str = "lsniper")
+ wielded_item_state = "lsniper-wielded"
+ action_button_name = "Use Scope"
+ w_class = ITEMSIZE_LARGE
+ item_icons = list(slot_l_hand_str = 'icons/mob/items/lefthand_guns.dmi', slot_r_hand_str = 'icons/mob/items/righthand_guns.dmi')
+ accuracy = -15 //better than most snipers but still has penalty
+ scoped_accuracy = 40
+ one_handed_penalty = 50 // The weapon itself is heavy, and the long barrel makes it hard to hold steady with just one hand.
+ phase_power = 150 //efficient crank charger
+
+ projectile_type = /obj/item/projectile/beam/sniper
+ modifystate = "riflekill"
+ firemodes = list(
+ list(mode_name="sniper", fire_delay=35, projectile_type=/obj/item/projectile/beam/sniper, modifystate="riflekill", charge_cost = 600),
+ list(mode_name="lethal", fire_delay=12, projectile_type=/obj/item/projectile/beam, modifystate="riflestun", charge_cost = 200),
+ )
+
+/obj/item/weapon/gun/energy/locked/frontier/rifle/ui_action_click()
+ scope()
+
+/obj/item/weapon/gun/energy/locked/frontier/rifle/verb/scope()
+ set category = "Object"
+ set name = "Use Scope"
+ set popup_menu = 1
+
+ toggle_scope(2.0)
+
+/obj/item/weapon/gun/energy/locked/frontier/rifle/update_icon()
+ if(recharging)
+ icon_state = "[modifystate]_pump"
+ update_held_icon()
+ return
+ ..()
+
+/obj/item/weapon/gun/energy/locked/frontier/rifle/unlocked
+ desc = "A much larger, heavier weapon than the typical frontier-type weapons, this DMR can be fired both from the hip, and in scope. Includes a built-in crank charger for recharging away from civilization."
+ req_access = newlist() //for toggling safety
+ locked = 0
+ lockable = 0
diff --git a/code/modules/projectiles/guns/energy/stun_vr.dm b/code/modules/projectiles/guns/energy/stun_vr.dm
index b0bfd53e463..db038e58fde 100644
--- a/code/modules/projectiles/guns/energy/stun_vr.dm
+++ b/code/modules/projectiles/guns/energy/stun_vr.dm
@@ -3,4 +3,5 @@
fire_delay = 4
/obj/item/weapon/gun/energy/stunrevolver
+ icon = 'icons/obj/gun_vr.dmi'
charge_cost = 400
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm
index 626dfe56843..e9fce291a34 100644
--- a/code/modules/projectiles/guns/projectile/automatic.dm
+++ b/code/modules/projectiles/guns/projectile/automatic.dm
@@ -389,9 +389,18 @@
)
/obj/item/weapon/gun/projectile/automatic/tommygun/update_icon()
- ..()
- icon_state = (ammo_magazine)? "tommygun" : "tommygun-empty"
-// update_held_icon()
+ //VOREStation Edit Start - vr sprite
+ if(istype(ammo_magazine,/obj/item/ammo_magazine/m45tommy))
+ icon_state = "tommygun-mag"
+ item_state = icon_state
+ else if(istype(ammo_magazine,/obj/item/ammo_magazine/m45tommydrum))
+ icon_state = "tommygun-drum"
+ item_state = icon_state
+ else
+ icon_state = "tommygun-empty"
+ item_state = icon_state
+ update_held_icon()
+ //VOREStation Edit End
/obj/item/weapon/gun/projectile/automatic/bullpup // Admin abuse assault rifle. ToDo: Make this less shit. Maybe remove its autofire, and make it spawn with only 10 rounds at start.
name = "bullpup rifle"
diff --git a/code/modules/projectiles/guns/projectile/automatic_vr.dm b/code/modules/projectiles/guns/projectile/automatic_vr.dm
index 5d4cd08eafc..148045b562e 100644
--- a/code/modules/projectiles/guns/projectile/automatic_vr.dm
+++ b/code/modules/projectiles/guns/projectile/automatic_vr.dm
@@ -1,6 +1,9 @@
/obj/item/weapon/gun/projectile/automatic/wt550/lethal
magazine_type = /obj/item/ammo_magazine/m9mmt
+/obj/item/weapon/gun/projectile/automatic/tommygun
+ icon = 'icons/obj/gun_vr.dmi'
+
////////////////////////////////////////////////////////////
//////////////////// Projectile Weapons ////////////////////
////////////////////////////////////////////////////////////
diff --git a/code/modules/projectiles/guns/projectile/boltaction.dm b/code/modules/projectiles/guns/projectile/boltaction.dm
index 1aa8e839575..52e8c17ca96 100644
--- a/code/modules/projectiles/guns/projectile/boltaction.dm
+++ b/code/modules/projectiles/guns/projectile/boltaction.dm
@@ -16,7 +16,7 @@
action_sound = 'sound/weapons/riflebolt.ogg'
pump_animation = null
-/obj/item/weapon/gun/projectile/shotgun/pump/rifle/practice // For target practice
+/obj/item/weapon/gun/projectile/shotgun/pump/rifle/practice //For target practice
desc = "A bolt-action rifle with a lightweight synthetic wood stock, designed for competitive shooting. Comes shipped with practice rounds pre-loaded into the gun. Popular among professional marksmen. Uses 7.62mm rounds."
ammo_type = /obj/item/ammo_casing/a762/practice
diff --git a/code/modules/projectiles/guns/projectile/boltaction_vr.dm b/code/modules/projectiles/guns/projectile/boltaction_vr.dm
new file mode 100644
index 00000000000..3e538adf4ee
--- /dev/null
+++ b/code/modules/projectiles/guns/projectile/boltaction_vr.dm
@@ -0,0 +1,55 @@
+/obj/item/weapon/gun/projectile/shotgun/pump/rifle
+ desc = "The Weissen Company Type-19 is a modern interpretation of an almost ancient weapon design. The model is popular among hunters and collectors due to its reliability. Uses 7.62mm rounds."
+ description_fluff = "The frontier’s largest home-grown firearms manufacturer, the APEX Arms Company offers a range of high-quality, high-cost hunting rifles and shotguns designed with the wild frontier wilderness - and its wildlife - in mind. \
+ The company operates just one production plant in the Mytis system, but their weapons have found popularity on garden worlds as far afield as the Tajaran homeworld due to their excellent build quality, precision, and stopping power."
+ icon = 'icons/obj/gun_vr.dmi'
+
+/obj/item/weapon/gun/projectile/shotgun/pump/rifle/practice //For target practice
+ name = "practice rifle"
+ icon = 'icons/obj/gun_vr.dmi'
+ icon_state = "boltaction_p"
+ item_state = "boltaction_p"
+ item_icons = list(slot_l_hand_str = 'icons/mob/items/lefthand_guns_vr.dmi', slot_r_hand_str = 'icons/mob/items/righthand_guns_vr.dmi')
+ max_shells = 4
+
+/obj/item/weapon/gun/projectile/shotgun/pump/rifle/ceremonial
+ max_shells = 5
+
+/obj/item/weapon/gun/projectile/shotgun/pump/rifle/lever
+ desc = "The Weissen Company Thunderking is the latest version of an almost ancient weapon design from the 19th century, popular with some due to its simplistic design. This one uses a lever-action to move new rounds into the chamber. Uses 7.62mm rounds."
+ description_fluff = "The frontier’s largest home-grown firearms manufacturer, the Weissen Company offers a range of high-quality, high-cost hunting rifles and shotguns designed with the wild frontier wilderness - and its wildlife - in mind. \
+ The company operates just one production plant in the Mytis system, but their weapons have found popularity on garden worlds as far afield as the Tajaran homeworld due to their excellent build quality, precision, and stopping power."
+ icon = 'icons/obj/gun_vr.dmi'
+ icon_state = "levergun"
+ max_shells = 6
+
+/obj/item/weapon/gun/projectile/shotgun/pump/rifle/lever/vintage
+ desc = "The Weissen Company's version of an iconic manually operated lever action rifle, the Bushhog, offering adequate stopping power due to it's still powerful cartridge while at the same time having a rather respectable firing rate due to it's mechanism. It is very probable this is a replica instead of a museum piece, but rifles of this pattern still see usage as colonist guns in some far off regions. Uses 7.62mm rounds."
+ description_fluff = "The frontier’s largest home-grown firearms manufacturer, the Weissen Company offers a range of high-quality, high-cost hunting rifles and shotguns designed with the wild frontier wilderness - and its wildlife - in mind. \
+ The company operates just one production plant in the Mytis system, but their weapons have found popularity on garden worlds as far afield as the Tajaran homeworld due to their excellent build quality, precision, and stopping power."
+ icon = 'icons/obj/gun_vr.dmi'
+ icon_state = "levergunv"
+ item_state = "leveraction"
+ max_shells = 5
+ caliber = "7.62mm"
+ load_method = SINGLE_CASING
+ pump_animation = null
+
+////////////////////////surplus gun - for derelicts (04/26/2021)////////////////////////
+
+/obj/item/weapon/gun/projectile/shotgun/pump/surplus
+ name = "surplus rifle"
+ desc = "An ancient weapon from an era long pas, crude in design, but still just as effective as any modern interpretation. Uses 7.62mm rounds."
+ icon = 'icons/obj/gun_vr.dmi'
+ icon_state = "boltaction_s"
+ item_state = "boltaction_p"
+ item_icons = list(slot_l_hand_str = 'icons/mob/items/lefthand_guns_vr.dmi', slot_r_hand_str = 'icons/mob/items/righthand_guns_vr.dmi')
+ fire_sound = 'sound/weapons/Gunshot_generic_rifle.ogg'
+ max_shells = 4
+ slot_flags = null
+ caliber = "7.62mm"
+ origin_tech = list(TECH_COMBAT = 1) // Old(er) as shit rifle doesn't have very good tech.
+ ammo_type = /obj/item/ammo_casing/a762
+ load_method = SINGLE_CASING|SPEEDLOADER
+ action_sound = 'sound/weapons/riflebolt.ogg'
+ pump_animation = null
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index 559fb2a12b6..734d14c63ad 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -44,7 +44,7 @@
damage = 30
armor_penetration = 10
-
+
/obj/item/projectile/beam/midlaser
damage = 40
armor_penetration = 10
diff --git a/code/modules/projectiles/projectile/beams_vr.dm b/code/modules/projectiles/projectile/beams_vr.dm
index f4aa2522de5..a3a149502cd 100644
--- a/code/modules/projectiles/projectile/beams_vr.dm
+++ b/code/modules/projectiles/projectile/beams_vr.dm
@@ -43,6 +43,9 @@
impact_type = /obj/effect/projectile/impact/laser_blue
/obj/item/projectile/beam/weaklaser/blue
+ icon_state = "bluelaser"
+ light_color = "#0066FF"
+
muzzle_type = /obj/effect/projectile/muzzle/laser_blue
tracer_type = /obj/effect/projectile/tracer/laser_blue
impact_type = /obj/effect/projectile/impact/laser_blue
@@ -79,4 +82,4 @@
M.adjustFireLoss(-15)
M.adjustToxLoss(-5)
M.adjustOxyLoss(-5)
- return 1
\ No newline at end of file
+ return 1
diff --git a/code/modules/reagents/Chemistry-Logging.dm b/code/modules/reagents/Chemistry-Logging.dm
index cccf37bb6fd..4c7b2343ad8 100644
--- a/code/modules/reagents/Chemistry-Logging.dm
+++ b/code/modules/reagents/Chemistry-Logging.dm
@@ -1,7 +1,7 @@
/var/list/chemical_reaction_logs = list()
-/proc/log_chemical_reaction(atom/A, datum/chemical_reaction/R, multiplier)
+/proc/log_chemical_reaction(atom/A, decl/chemical_reaction/R, multiplier)
if(!A || !R)
return
diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm
deleted file mode 100644
index a49751fa956..00000000000
--- a/code/modules/reagents/Chemistry-Recipes.dm
+++ /dev/null
@@ -1,2684 +0,0 @@
-//helper that ensures the reaction rate holds after iterating
-//Ex. REACTION_RATE(0.3) means that 30% of the reagents will react each chemistry tick (~2 seconds by default).
-#define REACTION_RATE(rate) (1.0 - (1.0-rate)**(1.0/PROCESS_REACTION_ITER))
-
-//helper to define reaction rate in terms of half-life
-//Ex.
-//HALF_LIFE(0) -> Reaction completes immediately (default chems)
-//HALF_LIFE(1) -> Half of the reagents react immediately, the rest over the following ticks.
-//HALF_LIFE(2) -> Half of the reagents are consumed after 2 chemistry ticks.
-//HALF_LIFE(3) -> Half of the reagents are consumed after 3 chemistry ticks.
-#define HALF_LIFE(ticks) (ticks? 1.0 - (0.5)**(1.0/(ticks*PROCESS_REACTION_ITER)) : 1.0)
-
-/datum/chemical_reaction
- var/name = null
- var/id = null
- var/result = null
- var/list/required_reagents = list()
- var/list/catalysts = list()
- var/list/inhibitors = list()
- var/result_amount = 0
-
- //how far the reaction proceeds each time it is processed. Used with either REACTION_RATE or HALF_LIFE macros.
- var/reaction_rate = HALF_LIFE(0)
-
- //if less than 1, the reaction will be inhibited if the ratio of products/reagents is too high.
- //0.5 = 50% yield -> reaction will only proceed halfway until products are removed.
- var/yield = 1.0
-
- //If limits on reaction rate would leave less than this amount of any reagent (adjusted by the reaction ratios),
- //the reaction goes to completion. This is to prevent reactions from going on forever with tiny reagent amounts.
- var/min_reaction = 2
-
- var/mix_message = "The solution begins to bubble."
- var/reaction_sound = 'sound/effects/bubbles.ogg'
-
- var/log_is_important = 0 // If this reaction should be considered important for logging. Important recipes message admins when mixed, non-important ones just log to file.
-
-/datum/chemical_reaction/proc/can_happen(var/datum/reagents/holder)
- //check that all the required reagents are present
- if(!holder.has_all_reagents(required_reagents))
- return 0
-
- //check that all the required catalysts are present in the required amount
- if(!holder.has_all_reagents(catalysts))
- return 0
-
- //check that none of the inhibitors are present in the required amount
- if(holder.has_any_reagent(inhibitors))
- return 0
-
- return 1
-
-/datum/chemical_reaction/proc/calc_reaction_progress(var/datum/reagents/holder, var/reaction_limit)
- var/progress = reaction_limit * reaction_rate //simple exponential progression
-
- //calculate yield
- if(1-yield > 0.001) //if yield ratio is big enough just assume it goes to completion
- /*
- Determine the max amount of product by applying the yield condition:
- (max_product/result_amount) / reaction_limit == yield/(1-yield)
-
- We make use of the fact that:
- reaction_limit = (holder.get_reagent_amount(reactant) / required_reagents[reactant]) of the limiting reagent.
- */
- var/yield_ratio = yield/(1-yield)
- var/max_product = yield_ratio * reaction_limit * result_amount //rearrange to obtain max_product
- var/yield_limit = max(0, max_product - holder.get_reagent_amount(result))/result_amount
-
- progress = min(progress, yield_limit) //apply yield limit
-
- //apply min reaction progress - wasn't sure if this should go before or after applying yield
- //I guess people can just have their miniscule reactions go to completion regardless of yield.
- for(var/reactant in required_reagents)
- var/remainder = holder.get_reagent_amount(reactant) - progress*required_reagents[reactant]
- if(remainder <= min_reaction*required_reagents[reactant])
- progress = reaction_limit
- break
-
- return progress
-
-/datum/chemical_reaction/process(var/datum/reagents/holder)
- //determine how far the reaction can proceed
- var/list/reaction_limits = list()
- for(var/reactant in required_reagents)
- reaction_limits += holder.get_reagent_amount(reactant) / required_reagents[reactant]
-
- //determine how far the reaction proceeds
- var/reaction_limit = min(reaction_limits)
- var/progress_limit = calc_reaction_progress(holder, reaction_limit)
-
- var/reaction_progress = min(reaction_limit, progress_limit) //no matter what, the reaction progress cannot exceed the stoichiometric limit.
-
- //need to obtain the new reagent's data before anything is altered
- var/data = send_data(holder, reaction_progress)
-
- //remove the reactants
- for(var/reactant in required_reagents)
- var/amt_used = required_reagents[reactant] * reaction_progress
- holder.remove_reagent(reactant, amt_used, safety = 1)
-
- //add the product
- var/amt_produced = result_amount * reaction_progress
- if(result)
- holder.add_reagent(result, amt_produced, data, safety = 1)
-
- on_reaction(holder, amt_produced)
-
- return reaction_progress
-
-//called when a reaction processes
-/datum/chemical_reaction/proc/on_reaction(var/datum/reagents/holder, var/created_volume)
- return
-
-//called after processing reactions, if they occurred
-/datum/chemical_reaction/proc/post_reaction(var/datum/reagents/holder)
- var/atom/container = holder.my_atom
- if(mix_message && container && !ismob(container))
- var/turf/T = get_turf(container)
- var/list/seen = viewers(4, T)
- for(var/mob/M in seen)
- M.show_message("[bicon(container)] [mix_message]", 1)
- playsound(T, reaction_sound, 80, 1)
-
-//obtains any special data that will be provided to the reaction products
-//this is called just before reactants are removed.
-/datum/chemical_reaction/proc/send_data(var/datum/reagents/holder, var/reaction_limit)
- return null
-
-/* Common reactions */
-
-/datum/chemical_reaction/inaprovaline
- name = "Inaprovaline"
- id = "inaprovaline"
- result = "inaprovaline"
- required_reagents = list("oxygen" = 1, "carbon" = 1, "sugar" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/dylovene
- name = "Dylovene"
- id = "anti_toxin"
- result = "anti_toxin"
- required_reagents = list("silicon" = 1, "potassium" = 1, "nitrogen" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/carthatoline
- name = "Carthatoline"
- id = "carthatoline"
- result = "carthatoline"
- required_reagents = list("anti_toxin" = 1, "carbon" = 2, "phoron" = 0.1)
- catalysts = list("phoron" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/paracetamol
- name = "Paracetamol"
- id = "paracetamol"
- result = "paracetamol"
- required_reagents = list("inaprovaline" = 1, "nitrogen" = 1, "water" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/tramadol
- name = "Tramadol"
- id = "tramadol"
- result = "tramadol"
- required_reagents = list("paracetamol" = 1, "ethanol" = 1, "oxygen" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/oxycodone
- name = "Oxycodone"
- id = "oxycodone"
- result = "oxycodone"
- required_reagents = list("ethanol" = 1, "tramadol" = 1)
- catalysts = list("phoron" = 5)
- result_amount = 1
-
-/datum/chemical_reaction/sterilizine
- name = "Sterilizine"
- id = "sterilizine"
- result = "sterilizine"
- required_reagents = list("ethanol" = 1, "anti_toxin" = 1, "chlorine" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/silicate
- name = "Silicate"
- id = "silicate"
- result = "silicate"
- required_reagents = list("aluminum" = 1, "silicon" = 1, "oxygen" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/mutagen
- name = "Unstable mutagen"
- id = "mutagen"
- result = "mutagen"
- required_reagents = list("radium" = 1, "phosphorus" = 1, "chlorine" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/water
- name = "Water"
- id = "water"
- result = "water"
- required_reagents = list("oxygen" = 1, "hydrogen" = 2)
- result_amount = 1
-
-/datum/chemical_reaction/thermite
- name = "Thermite"
- id = "thermite"
- result = "thermite"
- required_reagents = list("aluminum" = 1, "iron" = 1, "oxygen" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/space_drugs
- name = "Space Drugs"
- id = "space_drugs"
- result = "space_drugs"
- required_reagents = list("mercury" = 1, "sugar" = 1, "lithium" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/lube
- name = "Space Lube"
- id = "lube"
- result = "lube"
- required_reagents = list("water" = 1, "silicon" = 1, "oxygen" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/pacid
- name = "Polytrinic acid"
- id = "pacid"
- result = "pacid"
- required_reagents = list("sacid" = 1, "chlorine" = 1, "potassium" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/synaptizine
- name = "Synaptizine"
- id = "synaptizine"
- result = "synaptizine"
- required_reagents = list("sugar" = 1, "lithium" = 1, "water" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/hyronalin
- name = "Hyronalin"
- id = "hyronalin"
- result = "hyronalin"
- required_reagents = list("radium" = 1, "anti_toxin" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/arithrazine
- name = "Arithrazine"
- id = "arithrazine"
- result = "arithrazine"
- required_reagents = list("hyronalin" = 1, "hydrogen" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/impedrezene
- name = "Impedrezene"
- id = "impedrezene"
- result = "impedrezene"
- required_reagents = list("mercury" = 1, "oxygen" = 1, "sugar" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/kelotane
- name = "Kelotane"
- id = "kelotane"
- result = "kelotane"
- required_reagents = list("silicon" = 1, "carbon" = 1)
- result_amount = 2
- log_is_important = 1
-
-/datum/chemical_reaction/peridaxon
- name = "Peridaxon"
- id = "peridaxon"
- result = "peridaxon"
- required_reagents = list("bicaridine" = 2, "clonexadone" = 2)
- catalysts = list("phoron" = 5)
- result_amount = 2
-
-/datum/chemical_reaction/osteodaxon
- name = "Osteodaxon"
- id = "osteodaxon"
- result = "osteodaxon"
- required_reagents = list("bicaridine" = 2, "phoron" = 0.1, "carpotoxin" = 1)
- catalysts = list("phoron" = 5)
- inhibitors = list("clonexadone" = 1) // Messes with cryox
- result_amount = 2
-
-/datum/chemical_reaction/respirodaxon
- name = "Respirodaxon"
- id = "respirodaxon"
- result = "respirodaxon"
- required_reagents = list("dexalinp" = 2, "biomass" = 2, "phoron" = 1)
- catalysts = list("phoron" = 5)
- inhibitors = list("dexalin" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/gastirodaxon
- name = "Gastirodaxon"
- id = "gastirodaxon"
- result = "gastirodaxon"
- required_reagents = list("carthatoline" = 1, "biomass" = 2, "tungsten" = 2)
- catalysts = list("phoron" = 5)
- inhibitors = list("lithium" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/hepanephrodaxon
- name = "Hepanephrodaxon"
- id = "hepanephrodaxon"
- result = "hepanephrodaxon"
- required_reagents = list("carthatoline" = 2, "biomass" = 2, "lithium" = 1)
- catalysts = list("phoron" = 5)
- inhibitors = list("tungsten" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/cordradaxon
- name = "Cordradaxon"
- id = "cordradaxon"
- result = "cordradaxon"
- required_reagents = list("potassium_chlorophoride" = 1, "biomass" = 2, "bicaridine" = 2)
- catalysts = list("phoron" = 5)
- inhibitors = list("clonexadone" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/virus_food
- name = "Virus Food"
- id = "virusfood"
- result = "virusfood"
- required_reagents = list("water" = 1, "milk" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/leporazine
- name = "Leporazine"
- id = "leporazine"
- result = "leporazine"
- required_reagents = list("silicon" = 1, "copper" = 1)
- catalysts = list("phoron" = 5)
- result_amount = 2
-
-/datum/chemical_reaction/cryptobiolin
- name = "Cryptobiolin"
- id = "cryptobiolin"
- result = "cryptobiolin"
- required_reagents = list("potassium" = 1, "oxygen" = 1, "sugar" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/tricordrazine
- name = "Tricordrazine"
- id = "tricordrazine"
- result = "tricordrazine"
- required_reagents = list("inaprovaline" = 1, "anti_toxin" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/alkysine
- name = "Alkysine"
- id = "alkysine"
- result = "alkysine"
- required_reagents = list("chlorine" = 1, "nitrogen" = 1, "anti_toxin" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/dexalin
- name = "Dexalin"
- id = "dexalin"
- result = "dexalin"
- required_reagents = list("oxygen" = 2, "phoron" = 0.1)
- catalysts = list("phoron" = 1)
- inhibitors = list("water" = 1) // Messes with cryox
- result_amount = 1
-
-/datum/chemical_reaction/dermaline
- name = "Dermaline"
- id = "dermaline"
- result = "dermaline"
- required_reagents = list("oxygen" = 1, "phosphorus" = 1, "kelotane" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/dexalinp
- name = "Dexalin Plus"
- id = "dexalinp"
- result = "dexalinp"
- required_reagents = list("dexalin" = 1, "carbon" = 1, "iron" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/bicaridine
- name = "Bicaridine"
- id = "bicaridine"
- result = "bicaridine"
- required_reagents = list("inaprovaline" = 1, "carbon" = 1)
- inhibitors = list("sugar" = 1) // Messes up with inaprovaline
- result_amount = 2
-
-/datum/chemical_reaction/myelamine
- name = "Myelamine"
- id = "myelamine"
- result = "myelamine"
- required_reagents = list("bicaridine" = 1, "iron" = 2, "spidertoxin" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/hyperzine
- name = "Hyperzine"
- id = "hyperzine"
- result = "hyperzine"
- required_reagents = list("sugar" = 1, "phosphorus" = 1, "sulfur" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/stimm
- name = "Stimm"
- id = "stimm"
- result = "stimm"
- required_reagents = list("left4zed" = 1, "fuel" = 1)
- catalysts = list("fuel" = 5)
- result_amount = 2
-
-/datum/chemical_reaction/ryetalyn
- name = "Ryetalyn"
- id = "ryetalyn"
- result = "ryetalyn"
- required_reagents = list("arithrazine" = 1, "carbon" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/cryoxadone
- name = "Cryoxadone"
- id = "cryoxadone"
- result = "cryoxadone"
- required_reagents = list("dexalin" = 1, "water" = 1, "oxygen" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/clonexadone
- name = "Clonexadone"
- id = "clonexadone"
- result = "clonexadone"
- required_reagents = list("cryoxadone" = 1, "sodium" = 1, "phoron" = 0.1)
- catalysts = list("phoron" = 5)
- result_amount = 2
-
-/datum/chemical_reaction/mortiferin
- name = "Mortiferin"
- id = "mortiferin"
- result = "mortiferin"
- required_reagents = list("cryptobiolin" = 1, "clonexadone" = 1, "corophizine" = 1)
- result_amount = 2
- catalysts = list("phoron" = 5)
-
-/datum/chemical_reaction/spaceacillin
- name = "Spaceacillin"
- id = "spaceacillin"
- result = "spaceacillin"
- required_reagents = list("cryptobiolin" = 1, "inaprovaline" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/corophizine
- name = "Corophizine"
- id = "corophizine"
- result = "corophizine"
- required_reagents = list("spaceacillin" = 1, "carbon" = 1, "phoron" = 0.1)
- catalysts = list("phoron" = 5)
- result_amount = 2
-
-/datum/chemical_reaction/immunosuprizine
- name = "Immunosuprizine"
- id = "immunosuprizine"
- result = "immunosuprizine"
- required_reagents = list("corophizine" = 1, "tungsten" = 1, "sacid" = 1)
- catalysts = list("phoron" = 5)
- result_amount = 2
-
-/datum/chemical_reaction/imidazoline
- name = "imidazoline"
- id = "imidazoline"
- result = "imidazoline"
- required_reagents = list("carbon" = 1, "hydrogen" = 1, "anti_toxin" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/ethylredoxrazine
- name = "Ethylredoxrazine"
- id = "ethylredoxrazine"
- result = "ethylredoxrazine"
- required_reagents = list("oxygen" = 1, "anti_toxin" = 1, "carbon" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/calciumcarbonate
- name = "Calcium Carbonate"
- id = "calciumcarbonate"
- result = "calciumcarbonate"
- required_reagents = list("oxygen" = 3, "calcium" = 1, "carbon" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/soporific
- name = "Soporific"
- id = "stoxin"
- result = "stoxin"
- required_reagents = list("chloralhydrate" = 1, "sugar" = 4)
- inhibitors = list("phosphorus") // Messes with the smoke
- result_amount = 5
-
-/datum/chemical_reaction/chloralhydrate
- name = "Chloral Hydrate"
- id = "chloralhydrate"
- result = "chloralhydrate"
- required_reagents = list("ethanol" = 1, "chlorine" = 3, "water" = 1)
- result_amount = 1
-
-/datum/chemical_reaction/potassium_chloride
- name = "Potassium Chloride"
- id = "potassium_chloride"
- result = "potassium_chloride"
- required_reagents = list("sodiumchloride" = 1, "potassium" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/potassium_chlorophoride
- name = "Potassium Chlorophoride"
- id = "potassium_chlorophoride"
- result = "potassium_chlorophoride"
- required_reagents = list("potassium_chloride" = 1, "phoron" = 1, "chloralhydrate" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/zombiepowder
- name = "Zombie Powder"
- id = "zombiepowder"
- result = "zombiepowder"
- required_reagents = list("carpotoxin" = 5, "stoxin" = 5, "copper" = 5)
- result_amount = 2
-
-/datum/chemical_reaction/carpotoxin
- name = "Carpotoxin"
- id = "carpotoxin"
- result = "carpotoxin"
- required_reagents = list("spidertoxin" = 2, "biomass" = 1, "sifsap" = 2)
- catalysts = list("sifsap" = 10)
- inhibitors = list("radium" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/mindbreaker
- name = "Mindbreaker Toxin"
- id = "mindbreaker"
- result = "mindbreaker"
- required_reagents = list("silicon" = 1, "hydrogen" = 1, "anti_toxin" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/lipozine
- name = "Lipozine"
- id = "Lipozine"
- result = "lipozine"
- required_reagents = list("sodiumchloride" = 1, "ethanol" = 1, "radium" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/surfactant
- name = "Foam surfactant"
- id = "foam surfactant"
- result = "fluorosurfactant"
- required_reagents = list("fluorine" = 2, "carbon" = 2, "sacid" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/ammonia
- name = "Ammonia"
- id = "ammonia"
- result = "ammonia"
- required_reagents = list("hydrogen" = 3, "nitrogen" = 1)
- inhibitors = list("phoron" = 1) // Messes with lexorin
- result_amount = 3
-
-/datum/chemical_reaction/diethylamine
- name = "Diethylamine"
- id = "diethylamine"
- result = "diethylamine"
- required_reagents = list ("ammonia" = 1, "ethanol" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/left4zed
- name = "Left4Zed"
- id = "left4zed"
- result = "left4zed"
- required_reagents = list ("diethylamine" = 2, "mutagen" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/robustharvest
- name = "RobustHarvest"
- id = "robustharvest"
- result = "robustharvest"
- required_reagents = list ("ammonia" = 1, "calcium" = 1, "neurotoxic_protein" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/space_cleaner
- name = "Space cleaner"
- id = "cleaner"
- result = "cleaner"
- required_reagents = list("ammonia" = 1, "water" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/plantbgone
- name = "Plant-B-Gone"
- id = "plantbgone"
- result = "plantbgone"
- required_reagents = list("toxin" = 1, "water" = 4)
- result_amount = 5
-
-/datum/chemical_reaction/foaming_agent
- name = "Foaming Agent"
- id = "foaming_agent"
- result = "foaming_agent"
- required_reagents = list("lithium" = 1, "hydrogen" = 1)
- result_amount = 1
-
-/datum/chemical_reaction/glycerol
- name = "Glycerol"
- id = "glycerol"
- result = "glycerol"
- required_reagents = list("cornoil" = 3, "sacid" = 1)
- result_amount = 1
-
-/datum/chemical_reaction/sodiumchloride
- name = "Sodium Chloride"
- id = "sodiumchloride"
- result = "sodiumchloride"
- required_reagents = list("sodium" = 1, "chlorine" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/condensedcapsaicin
- name = "Condensed Capsaicin"
- id = "condensedcapsaicin"
- result = "condensedcapsaicin"
- required_reagents = list("capsaicin" = 2)
- catalysts = list("phoron" = 5)
- result_amount = 1
-
-/datum/chemical_reaction/coolant
- name = "Coolant"
- id = "coolant"
- result = "coolant"
- required_reagents = list("tungsten" = 1, "oxygen" = 1, "water" = 1)
- result_amount = 3
- log_is_important = 1
-
-/datum/chemical_reaction/rezadone
- name = "Rezadone"
- id = "rezadone"
- result = "rezadone"
- required_reagents = list("carpotoxin" = 1, "cryptobiolin" = 1, "copper" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/lexorin
- name = "Lexorin"
- id = "lexorin"
- result = "lexorin"
- required_reagents = list("phoron" = 1, "hydrogen" = 1, "nitrogen" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/methylphenidate
- name = "Methylphenidate"
- id = "methylphenidate"
- result = "methylphenidate"
- required_reagents = list("mindbreaker" = 1, "hydrogen" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/citalopram
- name = "Citalopram"
- id = "citalopram"
- result = "citalopram"
- required_reagents = list("mindbreaker" = 1, "carbon" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/paroxetine
- name = "Paroxetine"
- id = "paroxetine"
- result = "paroxetine"
- required_reagents = list("mindbreaker" = 1, "oxygen" = 1, "inaprovaline" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/neurotoxin
- name = "Neurotoxin"
- id = "neurotoxin"
- result = "neurotoxin"
- required_reagents = list("gargleblaster" = 1, "stoxin" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/luminol
- name = "Luminol"
- id = "luminol"
- result = "luminol"
- required_reagents = list("hydrogen" = 2, "carbon" = 2, "ammonia" = 2)
- result_amount = 6
-
-/* Solidification */
-
-/datum/chemical_reaction/solidification
- name = "Solid Iron"
- id = "solidiron"
- result = null
- required_reagents = list("frostoil" = 5, "iron" = REAGENTS_PER_SHEET)
- result_amount = 1
- var/sheet_to_give = /obj/item/stack/material/iron
-
-/datum/chemical_reaction/solidification/on_reaction(var/datum/reagents/holder, var/created_volume)
- new sheet_to_give(get_turf(holder.my_atom), created_volume)
- return
-
-
-/datum/chemical_reaction/solidification/phoron
- name = "Solid Phoron"
- id = "solidphoron"
- required_reagents = list("frostoil" = 5, "phoron" = REAGENTS_PER_SHEET)
- sheet_to_give = /obj/item/stack/material/phoron
-
-
-/datum/chemical_reaction/solidification/silver
- name = "Solid Silver"
- id = "solidsilver"
- required_reagents = list("frostoil" = 5, "silver" = REAGENTS_PER_SHEET)
- sheet_to_give = /obj/item/stack/material/silver
-
-
-/datum/chemical_reaction/solidification/gold
- name = "Solid Gold"
- id = "solidgold"
- required_reagents = list("frostoil" = 5, "gold" = REAGENTS_PER_SHEET)
- sheet_to_give = /obj/item/stack/material/gold
-
-
-/datum/chemical_reaction/solidification/platinum
- name = "Solid Platinum"
- id = "solidplatinum"
- required_reagents = list("frostoil" = 5, "platinum" = REAGENTS_PER_SHEET)
- sheet_to_give = /obj/item/stack/material/platinum
-
-
-/datum/chemical_reaction/solidification/uranium
- name = "Solid Uranium"
- id = "soliduranium"
- required_reagents = list("frostoil" = 5, "uranium" = REAGENTS_PER_SHEET)
- sheet_to_give = /obj/item/stack/material/uranium
-
-
-/datum/chemical_reaction/solidification/hydrogen
- name = "Solid Hydrogen"
- id = "solidhydrogen"
- required_reagents = list("frostoil" = 100, "hydrogen" = REAGENTS_PER_SHEET)
- sheet_to_give = /obj/item/stack/material/mhydrogen
-
-
-// These are from Xenobio.
-/datum/chemical_reaction/solidification/steel
- name = "Solid Steel"
- id = "solidsteel"
- required_reagents = list("frostoil" = 5, "steel" = REAGENTS_PER_SHEET)
- sheet_to_give = /obj/item/stack/material/steel
-
-
-/datum/chemical_reaction/solidification/plasteel
- name = "Solid Plasteel"
- id = "solidplasteel"
- required_reagents = list("frostoil" = 10, "plasteel" = REAGENTS_PER_SHEET)
- sheet_to_give = /obj/item/stack/material/plasteel
-
-
-/datum/chemical_reaction/plastication
- name = "Plastic"
- id = "solidplastic"
- result = null
- required_reagents = list("pacid" = 1, "plasticide" = 2)
- result_amount = 1
-
-/datum/chemical_reaction/plastication/on_reaction(var/datum/reagents/holder, var/created_volume)
- new /obj/item/stack/material/plastic(get_turf(holder.my_atom), created_volume)
- return
-
-/* Grenade reactions */
-
-/datum/chemical_reaction/explosion_potassium
- name = "Explosion"
- id = "explosion_potassium"
- result = null
- required_reagents = list("water" = 1, "potassium" = 1)
- result_amount = 2
- mix_message = null
-
-/datum/chemical_reaction/explosion_potassium/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/datum/effect/effect/system/reagents_explosion/e = new()
- e.set_up(round (created_volume/10, 1), holder.my_atom, 0, 0)
- if(isliving(holder.my_atom))
- e.amount *= 0.5
- var/mob/living/L = holder.my_atom
- if(L.stat != DEAD)
- e.amount *= 0.5
- //VOREStation Add Start
- else
- holder.clear_reagents() //No more powergaming by creating a tiny amount of this
- //VORESTation Add End
- e.start()
- //holder.clear_reagents() //VOREStation Removal
- return
-
-/datum/chemical_reaction/flash_powder
- name = "Flash powder"
- id = "flash_powder"
- result = null
- required_reagents = list("aluminum" = 1, "potassium" = 1, "sulfur" = 1 )
- result_amount = null
-
-/datum/chemical_reaction/flash_powder/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(2, 1, location)
- s.start()
- for(var/mob/living/carbon/M in viewers(world.view, location))
- switch(get_dist(M, location))
- if(0 to 3)
- if(hasvar(M, "glasses"))
- if(istype(M:glasses, /obj/item/clothing/glasses/sunglasses))
- continue
-
- M.flash_eyes()
- M.Weaken(15)
-
- if(4 to 5)
- if(hasvar(M, "glasses"))
- if(istype(M:glasses, /obj/item/clothing/glasses/sunglasses))
- continue
-
- M.flash_eyes()
- M.Stun(5)
-
-/datum/chemical_reaction/emp_pulse
- name = "EMP Pulse"
- id = "emp_pulse"
- result = null
- required_reagents = list("uranium" = 1, "iron" = 1) // Yes, laugh, it's the best recipe I could think of that makes a little bit of sense
- result_amount = 2
-
-/datum/chemical_reaction/emp_pulse/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
- // 100 created volume = 4 heavy range & 7 light range. A few tiles smaller than traitor EMP grandes.
- // 200 created volume = 8 heavy range & 14 light range. 4 tiles larger than traitor EMP grenades.
- empulse(location, round(created_volume / 24), round(created_volume / 20), round(created_volume / 18), round(created_volume / 14), 1)
- //VOREStation Edit Start
- if(!isliving(holder.my_atom)) //No more powergaming by creating a tiny amount of this
- holder.clear_reagents()
- //VOREStation Edit End
- return
-
-/datum/chemical_reaction/nitroglycerin
- name = "Nitroglycerin"
- id = "nitroglycerin"
- result = "nitroglycerin"
- required_reagents = list("glycerol" = 1, "pacid" = 1, "sacid" = 1)
- result_amount = 2
- log_is_important = 1
-
-/datum/chemical_reaction/nitroglycerin/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/datum/effect/effect/system/reagents_explosion/e = new()
- e.set_up(round (created_volume/2, 1), holder.my_atom, 0, 0)
- if(isliving(holder.my_atom))
- e.amount *= 0.5
- var/mob/living/L = holder.my_atom
- if(L.stat!=DEAD)
- e.amount *= 0.5
- //VOREStation Add Start
- else
- holder.clear_reagents() //No more powergaming by creating a tiny amount of this
- //VOREStation Add End
- e.start()
-
- //holder.clear_reagents() //VOREStation Removal
- return
-
-/datum/chemical_reaction/napalm
- name = "Napalm"
- id = "napalm"
- result = null
- required_reagents = list("aluminum" = 1, "phoron" = 1, "sacid" = 1 )
- result_amount = 1
-
-/datum/chemical_reaction/napalm/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/turf/location = get_turf(holder.my_atom.loc)
- for(var/turf/simulated/floor/target_tile in range(0,location))
- target_tile.assume_gas("volatile_fuel", created_volume, 400+T0C)
- spawn (0) target_tile.hotspot_expose(700, 400)
- holder.del_reagent("napalm")
- return
-
-/datum/chemical_reaction/chemsmoke
- name = "Chemsmoke"
- id = "chemsmoke"
- result = null
- required_reagents = list("potassium" = 1, "sugar" = 1, "phosphorus" = 1)
- result_amount = 0.4
-
-/datum/chemical_reaction/chemsmoke/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
- var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem
- S.attach(location)
- S.set_up(holder, created_volume, 0, location)
- playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3)
- spawn(0)
- S.start()
- //VOREStation Edit Start
- if(!isliving(holder.my_atom)) //No more powergaming by creating a tiny amount of this
- holder.clear_reagents()
- //VOREStation Edit End
- return
-
-/datum/chemical_reaction/foam
- name = "Foam"
- id = "foam"
- result = null
- required_reagents = list("fluorosurfactant" = 1, "water" = 1)
- result_amount = 2
- mix_message = "The solution violently bubbles!"
-
-/datum/chemical_reaction/foam/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
-
- for(var/mob/M in viewers(5, location))
- to_chat(M, "The solution spews out foam!")
-
- var/datum/effect/effect/system/foam_spread/s = new()
- s.set_up(created_volume, location, holder, 0)
- s.start()
- //VOREStation Edit Start
- if(!isliving(holder.my_atom)) //No more powergaming by creating a tiny amount of this
- holder.clear_reagents()
- //VOREStation Edit End
- return
-
-/datum/chemical_reaction/metalfoam
- name = "Metal Foam"
- id = "metalfoam"
- result = null
- required_reagents = list("aluminum" = 3, "foaming_agent" = 1, "pacid" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/metalfoam/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
-
- for(var/mob/M in viewers(5, location))
- to_chat(M, "The solution spews out a metalic foam!")
-
- var/datum/effect/effect/system/foam_spread/s = new()
- s.set_up(created_volume, location, holder, 1)
- s.start()
- return
-
-/datum/chemical_reaction/ironfoam
- name = "Iron Foam"
- id = "ironlfoam"
- result = null
- required_reagents = list("iron" = 3, "foaming_agent" = 1, "pacid" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/ironfoam/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
-
- for(var/mob/M in viewers(5, location))
- to_chat(M, "The solution spews out a metalic foam!")
-
- var/datum/effect/effect/system/foam_spread/s = new()
- s.set_up(created_volume, location, holder, 2)
- s.start()
- return
-
-/* Paint */
-
-/datum/chemical_reaction/red_paint
- name = "Red paint"
- id = "red_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_red" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/red_paint/send_data()
- return "#FE191A"
-
-/datum/chemical_reaction/orange_paint
- name = "Orange paint"
- id = "orange_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_orange" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/orange_paint/send_data()
- return "#FFBE4F"
-
-/datum/chemical_reaction/yellow_paint
- name = "Yellow paint"
- id = "yellow_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_yellow" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/yellow_paint/send_data()
- return "#FDFE7D"
-
-/datum/chemical_reaction/green_paint
- name = "Green paint"
- id = "green_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_green" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/green_paint/send_data()
- return "#18A31A"
-
-/datum/chemical_reaction/blue_paint
- name = "Blue paint"
- id = "blue_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_blue" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/blue_paint/send_data()
- return "#247CFF"
-
-/datum/chemical_reaction/purple_paint
- name = "Purple paint"
- id = "purple_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_purple" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/purple_paint/send_data()
- return "#CC0099"
-
-/datum/chemical_reaction/grey_paint //mime
- name = "Grey paint"
- id = "grey_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_grey" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/grey_paint/send_data()
- return "#808080"
-
-/datum/chemical_reaction/brown_paint
- name = "Brown paint"
- id = "brown_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_brown" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/brown_paint/send_data()
- return "#846F35"
-
-/datum/chemical_reaction/blood_paint
- name = "Blood paint"
- id = "blood_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "blood" = 2)
- result_amount = 5
-
-/datum/chemical_reaction/blood_paint/send_data(var/datum/reagents/T)
- var/t = T.get_data("blood")
- if(t && t["blood_colour"])
- return t["blood_colour"]
- return "#FE191A" // Probably red
-
-/datum/chemical_reaction/milk_paint
- name = "Milk paint"
- id = "milk_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "milk" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/milk_paint/send_data()
- return "#F0F8FF"
-
-/datum/chemical_reaction/orange_juice_paint
- name = "Orange juice paint"
- id = "orange_juice_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "orangejuice" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/orange_juice_paint/send_data()
- return "#E78108"
-
-/datum/chemical_reaction/tomato_juice_paint
- name = "Tomato juice paint"
- id = "tomato_juice_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "tomatojuice" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/tomato_juice_paint/send_data()
- return "#731008"
-
-/datum/chemical_reaction/lime_juice_paint
- name = "Lime juice paint"
- id = "lime_juice_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "limejuice" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/lime_juice_paint/send_data()
- return "#365E30"
-
-/datum/chemical_reaction/carrot_juice_paint
- name = "Carrot juice paint"
- id = "carrot_juice_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "carrotjuice" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/carrot_juice_paint/send_data()
- return "#973800"
-
-/datum/chemical_reaction/berry_juice_paint
- name = "Berry juice paint"
- id = "berry_juice_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "berryjuice" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/berry_juice_paint/send_data()
- return "#990066"
-
-/datum/chemical_reaction/grape_juice_paint
- name = "Grape juice paint"
- id = "grape_juice_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "grapejuice" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/grape_juice_paint/send_data()
- return "#863333"
-
-/datum/chemical_reaction/poisonberry_juice_paint
- name = "Poison berry juice paint"
- id = "poisonberry_juice_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "poisonberryjuice" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/poisonberry_juice_paint/send_data()
- return "#863353"
-
-/datum/chemical_reaction/watermelon_juice_paint
- name = "Watermelon juice paint"
- id = "watermelon_juice_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "watermelonjuice" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/watermelon_juice_paint/send_data()
- return "#B83333"
-
-/datum/chemical_reaction/lemon_juice_paint
- name = "Lemon juice paint"
- id = "lemon_juice_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "lemonjuice" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/lemon_juice_paint/send_data()
- return "#AFAF00"
-
-/datum/chemical_reaction/banana_juice_paint
- name = "Banana juice paint"
- id = "banana_juice_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "banana" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/banana_juice_paint/send_data()
- return "#C3AF00"
-
-/datum/chemical_reaction/potato_juice_paint
- name = "Potato juice paint"
- id = "potato_juice_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "potatojuice" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/potato_juice_paint/send_data()
- return "#302000"
-
-/datum/chemical_reaction/carbon_paint
- name = "Carbon paint"
- id = "carbon_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "carbon" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/carbon_paint/send_data()
- return "#333333"
-
-/datum/chemical_reaction/aluminum_paint
- name = "Aluminum paint"
- id = "aluminum_paint"
- result = "paint"
- required_reagents = list("plasticide" = 1, "water" = 3, "aluminum" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/aluminum_paint/send_data()
- return "#F0F8FF"
-
-/* Food */
-
-/datum/chemical_reaction/food/tofu
- name = "Tofu"
- id = "tofu"
- result = null
- required_reagents = list("soymilk" = 10)
- catalysts = list("enzyme" = 5)
- result_amount = 1
-
-/datum/chemical_reaction/food/tofu/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
- for(var/i = 1, i <= created_volume, i++)
- new /obj/item/weapon/reagent_containers/food/snacks/tofu(location)
- return
-
-/datum/chemical_reaction/food/chocolate_bar
- name = "Chocolate Bar"
- id = "chocolate_bar"
- result = null
- required_reagents = list("soymilk" = 2, "coco" = 2, "sugar" = 2)
- result_amount = 1
-
-/datum/chemical_reaction/food/chocolate_bar/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
- for(var/i = 1, i <= created_volume, i++)
- new /obj/item/weapon/reagent_containers/food/snacks/chocolatebar(location)
- return
-
-/datum/chemical_reaction/food/chocolate_bar2
- name = "Chocolate Bar"
- id = "chocolate_bar"
- result = null
- required_reagents = list("milk" = 2, "coco" = 2, "sugar" = 2)
- result_amount = 1
-
-/datum/chemical_reaction/food/chocolate_bar2/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
- for(var/i = 1, i <= created_volume, i++)
- new /obj/item/weapon/reagent_containers/food/snacks/chocolatebar(location)
- return
-
-/datum/chemical_reaction/drinks/coffee
- name = "Coffee"
- id = "coffee"
- result = "coffee"
- required_reagents = list("water" = 5, "coffeepowder" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/tea
- name = "Black tea"
- id = "tea"
- result = "tea"
- required_reagents = list("water" = 5, "teapowder" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/hot_coco
- name = "Hot Coco"
- id = "hot_coco"
- result = "hot_coco"
- required_reagents = list("water" = 5, "coco" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/food/soysauce
- name = "Soy Sauce"
- id = "soysauce"
- result = "soysauce"
- required_reagents = list("soymilk" = 4, "sacid" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/grapejuice
- name = "Grape Juice"
- id = "grapejuice"
- result = "grapejuice"
- required_reagents = list("water" = 3, "instantgrape" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/orangejuice
- name = "Orange Juice"
- id = "orangejuice"
- result = "orangejuice"
- required_reagents = list("water" = 3, "instantorange" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/watermelonjuice
- name = "Watermelon Juice"
- id = "watermelonjuice"
- result = "watermelonjuice"
- required_reagents = list("water" = 3, "instantwatermelon" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/applejuice
- name = "Apple Juice"
- id = "applejuice"
- result = "applejuice"
- required_reagents = list("water" = 3, "instantapple" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/food/ketchup
- name = "Ketchup"
- id = "ketchup"
- result = "ketchup"
- required_reagents = list("tomatojuice" = 2, "water" = 1, "sugar" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/food/barbecue
- name = "Barbeque Sauce"
- id = "barbecue"
- result = "barbecue"
- required_reagents = list("tomatojuice" = 2, "applejuice" = 1, "sugar" = 1, "spacespice" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/food/peanutbutter
- name = "Peanut Butter"
- id = "peanutbutter"
- result = "peanutbutter"
- required_reagents = list("peanutoil" = 2, "sugar" = 1, "sodiumchloride" = 1)
- catalysts = list("enzyme" = 5)
- result_amount = 3
-
-/datum/chemical_reaction/food/mayonnaise
- name = "mayonnaise"
- id = "mayo"
- result = "mayo"
- required_reagents = list("egg" = 9, "cornoil" = 5, "lemonjuice" = 5, "sodiumchloride" = 1)
- result_amount = 15
-
-/datum/chemical_reaction/food/cheesewheel
- name = "Cheesewheel"
- id = "cheesewheel"
- result = null
- required_reagents = list("milk" = 40)
- catalysts = list("enzyme" = 5)
- result_amount = 1
-
-/datum/chemical_reaction/food/cheesewheel/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
- for(var/i = 1, i <= created_volume, i++)
- new /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesewheel(location)
- return
-
-/datum/chemical_reaction/food/meatball
- name = "Meatball"
- id = "meatball"
- result = null
- required_reagents = list("protein" = 3, "flour" = 5)
- result_amount = 3
-
-/datum/chemical_reaction/food/meatball/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
- for(var/i = 1, i <= created_volume, i++)
- new /obj/item/weapon/reagent_containers/food/snacks/meatball(location)
- return
-
-/datum/chemical_reaction/food/dough
- name = "Dough"
- id = "dough"
- result = null
- required_reagents = list("egg" = 3, "flour" = 10)
- inhibitors = list("water" = 1, "beer" = 1) //To prevent it messing with batter recipes
- result_amount = 1
-
-/datum/chemical_reaction/food/dough/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
- for(var/i = 1, i <= created_volume, i++)
- new /obj/item/weapon/reagent_containers/food/snacks/dough(location)
- return
-
-/datum/chemical_reaction/food/syntiflesh
- name = "Syntiflesh"
- id = "syntiflesh"
- result = null
- required_reagents = list("blood" = 5, "clonexadone" = 5)
- result_amount = 1
-
-/datum/chemical_reaction/food/syntiflesh/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
- for(var/i = 1, i <= created_volume, i++)
- new /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh(location)
- return
-
-/datum/chemical_reaction/hot_ramen
- name = "Hot Ramen"
- id = "hot_ramen"
- result = "hot_ramen"
- required_reagents = list("water" = 1, "dry_ramen" = 3)
- result_amount = 3
-
-/datum/chemical_reaction/hell_ramen
- name = "Hell Ramen"
- id = "hell_ramen"
- result = "hell_ramen"
- required_reagents = list("capsaicin" = 1, "hot_ramen" = 6)
- result_amount = 6
-
-/* Alcohol */
-
-/datum/chemical_reaction/drinks/goldschlager
- name = "Goldschlager"
- id = "goldschlager"
- result = "goldschlager"
- required_reagents = list("vodka" = 10, "gold" = 1)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/patron
- name = "Patron"
- id = "patron"
- result = "patron"
- required_reagents = list("tequilla" = 10, "silver" = 1)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/bilk
- name = "Bilk"
- id = "bilk"
- result = "bilk"
- required_reagents = list("milk" = 1, "beer" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/icetea
- name = "Iced Tea"
- id = "icetea"
- result = "icetea"
- required_reagents = list("ice" = 1, "tea" = 2)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/icecoffee
- name = "Iced Coffee"
- id = "icecoffee"
- result = "icecoffee"
- required_reagents = list("ice" = 1, "coffee" = 2)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/nuka_cola
- name = "Nuclear Cola"
- id = "nuka_cola"
- result = "nuka_cola"
- required_reagents = list("uranium" = 1, "cola" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/moonshine
- name = "Moonshine"
- id = "moonshine"
- result = "moonshine"
- required_reagents = list("nutriment" = 10)
- catalysts = list("enzyme" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/grenadine
- name = "Grenadine Syrup"
- id = "grenadine"
- result = "grenadine"
- required_reagents = list("berryjuice" = 10)
- catalysts = list("enzyme" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/wine
- name = "Wine"
- id = "wine"
- result = "wine"
- required_reagents = list("grapejuice" = 10)
- catalysts = list("enzyme" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/pwine
- name = "Poison Wine"
- id = "pwine"
- result = "pwine"
- required_reagents = list("poisonberryjuice" = 10)
- catalysts = list("enzyme" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/melonliquor
- name = "Melon Liquor"
- id = "melonliquor"
- result = "melonliquor"
- required_reagents = list("watermelonjuice" = 10)
- catalysts = list("enzyme" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/bluecuracao
- name = "Blue Curacao"
- id = "bluecuracao"
- result = "bluecuracao"
- required_reagents = list("orangejuice" = 10)
- catalysts = list("enzyme" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/spacebeer
- name = "Space Beer"
- id = "spacebeer"
- result = "beer"
- required_reagents = list("cornoil" = 10)
- catalysts = list("enzyme" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/vodka
- name = "Vodka"
- id = "vodka"
- result = "vodka"
- required_reagents = list("potatojuice" = 10)
- catalysts = list("enzyme" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/cider
- name = "Cider"
- id = "cider"
- result = "cider"
- required_reagents = list("applejuice" = 10)
- catalysts = list("enzyme" = 5)
- result_amount = 10
-
-
-/datum/chemical_reaction/drinks/sake
- name = "Sake"
- id = "sake"
- result = "sake"
- required_reagents = list("rice" = 10)
- catalysts = list("enzyme" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/kahlua
- name = "Kahlua"
- id = "kahlua"
- result = "kahlua"
- required_reagents = list("coffee" = 5, "sugar" = 5)
- catalysts = list("enzyme" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/gin_tonic
- name = "Gin and Tonic"
- id = "gintonic"
- result = "gintonic"
- required_reagents = list("gin" = 2, "tonic" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/cuba_libre
- name = "Cuba Libre"
- id = "cubalibre"
- result = "cubalibre"
- required_reagents = list("rum" = 2, "cola" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/martini
- name = "Classic Martini"
- id = "martini"
- result = "martini"
- required_reagents = list("gin" = 2, "vermouth" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/vodkamartini
- name = "Vodka Martini"
- id = "vodkamartini"
- result = "vodkamartini"
- required_reagents = list("vodka" = 2, "vermouth" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/white_russian
- name = "White Russian"
- id = "whiterussian"
- result = "whiterussian"
- required_reagents = list("blackrussian" = 2, "cream" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/whiskey_cola
- name = "Whiskey Cola"
- id = "whiskeycola"
- result = "whiskeycola"
- required_reagents = list("whiskey" = 2, "cola" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/screwdriver
- name = "Screwdriver"
- id = "screwdrivercocktail"
- result = "screwdrivercocktail"
- required_reagents = list("vodka" = 2, "orangejuice" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/bloody_mary
- name = "Bloody Mary"
- id = "bloodymary"
- result = "bloodymary"
- required_reagents = list("vodka" = 2, "tomatojuice" = 3, "limejuice" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/gargle_blaster
- name = "Pan-Galactic Gargle Blaster"
- id = "gargleblaster"
- result = "gargleblaster"
- required_reagents = list("vodka" = 2, "gin" = 1, "whiskey" = 1, "cognac" = 1, "limejuice" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/brave_bull
- name = "Brave Bull"
- id = "bravebull"
- result = "bravebull"
- required_reagents = list("tequilla" = 2, "kahlua" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/tequilla_sunrise
- name = "Tequilla Sunrise"
- id = "tequillasunrise"
- result = "tequillasunrise"
- required_reagents = list("tequilla" = 2, "orangejuice" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/phoron_special
- name = "Toxins Special"
- id = "phoronspecial"
- result = "phoronspecial"
- required_reagents = list("rum" = 2, "vermouth" = 2, "phoron" = 2)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/beepsky_smash
- name = "Beepksy Smash"
- id = "beepksysmash"
- result = "beepskysmash"
- required_reagents = list("limejuice" = 1, "whiskey" = 1, "iron" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/doctor_delight
- name = "The Doctor's Delight"
- id = "doctordelight"
- result = "doctorsdelight"
- required_reagents = list("limejuice" = 1, "tomatojuice" = 1, "orangejuice" = 1, "cream" = 2, "tricordrazine" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/irish_cream
- name = "Irish Cream"
- id = "irishcream"
- result = "irishcream"
- required_reagents = list("whiskey" = 2, "cream" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/manly_dorf
- name = "The Manly Dorf"
- id = "manlydorf"
- result = "manlydorf"
- required_reagents = list ("beer" = 1, "ale" = 2)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/hooch
- name = "Hooch"
- id = "hooch"
- result = "hooch"
- required_reagents = list ("sugar" = 1, "ethanol" = 2, "fuel" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/irish_coffee
- name = "Irish Coffee"
- id = "irishcoffee"
- result = "irishcoffee"
- required_reagents = list("irishcream" = 1, "coffee" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/b52
- name = "B-52"
- id = "b52"
- result = "b52"
- required_reagents = list("irishcream" = 1, "kahlua" = 1, "cognac" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/atomicbomb
- name = "Atomic Bomb"
- id = "atomicbomb"
- result = "atomicbomb"
- required_reagents = list("b52" = 10, "uranium" = 1)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/margarita
- name = "Margarita"
- id = "margarita"
- result = "margarita"
- required_reagents = list("tequilla" = 2, "limejuice" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/longislandicedtea
- name = "Long Island Iced Tea"
- id = "longislandicedtea"
- result = "longislandicedtea"
- required_reagents = list("vodka" = 1, "gin" = 1, "tequilla" = 1, "cubalibre" = 3)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/icedtea
- name = "Long Island Iced Tea"
- id = "longislandicedtea"
- result = "longislandicedtea"
- required_reagents = list("vodka" = 1, "gin" = 1, "tequilla" = 1, "cubalibre" = 3)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/threemileisland
- name = "Three Mile Island Iced Tea"
- id = "threemileisland"
- result = "threemileisland"
- required_reagents = list("longislandicedtea" = 10, "uranium" = 1)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/whiskeysoda
- name = "Whiskey Soda"
- id = "whiskeysoda"
- result = "whiskeysoda"
- required_reagents = list("whiskey" = 2, "sodawater" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/black_russian
- name = "Black Russian"
- id = "blackrussian"
- result = "blackrussian"
- required_reagents = list("vodka" = 2, "kahlua" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/manhattan
- name = "Manhattan"
- id = "manhattan"
- result = "manhattan"
- required_reagents = list("whiskey" = 2, "vermouth" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/manhattan_proj
- name = "Manhattan Project"
- id = "manhattan_proj"
- result = "manhattan_proj"
- required_reagents = list("manhattan" = 10, "uranium" = 1)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/vodka_tonic
- name = "Vodka and Tonic"
- id = "vodkatonic"
- result = "vodkatonic"
- required_reagents = list("vodka" = 2, "tonic" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/gin_fizz
- name = "Gin Fizz"
- id = "ginfizz"
- result = "ginfizz"
- required_reagents = list("gin" = 1, "sodawater" = 1, "limejuice" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/bahama_mama
- name = "Bahama mama"
- id = "bahama_mama"
- result = "bahama_mama"
- required_reagents = list("rum" = 2, "orangejuice" = 2, "limejuice" = 1, "ice" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/singulo
- name = "Singulo"
- id = "singulo"
- result = "singulo"
- required_reagents = list("vodka" = 5, "radium" = 1, "wine" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/alliescocktail
- name = "Allies Cocktail"
- id = "alliescocktail"
- result = "alliescocktail"
- required_reagents = list("martini" = 1, "vodka" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/demonsblood
- name = "Demons Blood"
- id = "demonsblood"
- result = "demonsblood"
- required_reagents = list("rum" = 3, "spacemountainwind" = 1, "blood" = 1, "dr_gibb" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/booger
- name = "Booger"
- id = "booger"
- result = "booger"
- required_reagents = list("cream" = 2, "banana" = 1, "rum" = 1, "watermelonjuice" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/antifreeze
- name = "Anti-freeze"
- id = "antifreeze"
- result = "antifreeze"
- required_reagents = list("vodka" = 1, "cream" = 1, "ice" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/barefoot
- name = "Barefoot"
- id = "barefoot"
- result = "barefoot"
- required_reagents = list("berryjuice" = 1, "cream" = 1, "vermouth" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/grapesoda
- name = "Grape Soda"
- id = "grapesoda"
- result = "grapesoda"
- required_reagents = list("grapejuice" = 2, "cola" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/sbiten
- name = "Sbiten"
- id = "sbiten"
- result = "sbiten"
- required_reagents = list("vodka" = 10, "capsaicin" = 1)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/red_mead
- name = "Red Mead"
- id = "red_mead"
- result = "red_mead"
- required_reagents = list("blood" = 1, "mead" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/mead
- name = "Mead"
- id = "mead"
- result = "mead"
- required_reagents = list("sugar" = 1, "water" = 1)
- catalysts = list("enzyme" = 5)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/iced_beer
- name = "Iced Beer"
- id = "iced_beer"
- result = "iced_beer"
- required_reagents = list("beer" = 10, "frostoil" = 1)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/iced_beer2
- name = "Iced Beer"
- id = "iced_beer"
- result = "iced_beer"
- required_reagents = list("beer" = 5, "ice" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/grog
- name = "Grog"
- id = "grog"
- result = "grog"
- required_reagents = list("rum" = 1, "water" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/soy_latte
- name = "Soy Latte"
- id = "soy_latte"
- result = "soy_latte"
- required_reagents = list("coffee" = 1, "soymilk" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/cafe_latte
- name = "Cafe Latte"
- id = "cafe_latte"
- result = "cafe_latte"
- required_reagents = list("coffee" = 1, "milk" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/acidspit
- name = "Acid Spit"
- id = "acidspit"
- result = "acidspit"
- required_reagents = list("sacid" = 1, "wine" = 5)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/amasec
- name = "Amasec"
- id = "amasec"
- result = "amasec"
- required_reagents = list("iron" = 1, "wine" = 5, "vodka" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/changelingsting
- name = "Changeling Sting"
- id = "changelingsting"
- result = "changelingsting"
- required_reagents = list("screwdrivercocktail" = 1, "limejuice" = 1, "lemonjuice" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/aloe
- name = "Aloe"
- id = "aloe"
- result = "aloe"
- required_reagents = list("cream" = 1, "whiskey" = 1, "watermelonjuice" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/andalusia
- name = "Andalusia"
- id = "andalusia"
- result = "andalusia"
- required_reagents = list("rum" = 1, "whiskey" = 1, "lemonjuice" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/snowwhite
- name = "Snow White"
- id = "snowwhite"
- result = "snowwhite"
- required_reagents = list("pineapplejuice" = 1, "rum" = 1, "lemon_lime" = 1, "egg" = 1, "kahlua" = 1, "sugar" = 1) //VoreStation Edit
- result_amount = 2
-
-/datum/chemical_reaction/drinks/irishcarbomb
- name = "Irish Car Bomb"
- id = "irishcarbomb"
- result = "irishcarbomb"
- required_reagents = list("ale" = 1, "irishcream" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/syndicatebomb
- name = "Syndicate Bomb"
- id = "syndicatebomb"
- result = "syndicatebomb"
- required_reagents = list("beer" = 1, "whiskeycola" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/erikasurprise
- name = "Erika Surprise"
- id = "erikasurprise"
- result = "erikasurprise"
- required_reagents = list("ale" = 2, "limejuice" = 1, "whiskey" = 1, "banana" = 1, "ice" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/devilskiss
- name = "Devils Kiss"
- id = "devilskiss"
- result = "devilskiss"
- required_reagents = list("blood" = 1, "kahlua" = 1, "rum" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/hippiesdelight
- name = "Hippies Delight"
- id = "hippiesdelight"
- result = "hippiesdelight"
- required_reagents = list("psilocybin" = 1, "gargleblaster" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/bananahonk
- name = "Banana Honk"
- id = "bananahonk"
- result = "bananahonk"
- required_reagents = list("banana" = 1, "cream" = 1, "sugar" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/silencer
- name = "Silencer"
- id = "silencer"
- result = "silencer"
- required_reagents = list("nothing" = 1, "cream" = 1, "sugar" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/driestmartini
- name = "Driest Martini"
- id = "driestmartini"
- result = "driestmartini"
- required_reagents = list("nothing" = 1, "gin" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/lemonade
- name = "Lemonade"
- id = "lemonade"
- result = "lemonade"
- required_reagents = list("lemonjuice" = 1, "sugar" = 1, "water" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/melonade
- name = "Melonade"
- id = "melonade"
- result = "melonade"
- required_reagents = list("watermelonjuice" = 1, "sugar" = 1, "sodawater" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/appleade
- name = "Appleade"
- id = "appleade"
- result = "appleade"
- required_reagents = list("applejuice" = 1, "sugar" = 1, "sodawater" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/pineappleade
- name = "Pineappleade"
- id = "pineappleade"
- result = "pineappleade"
- required_reagents = list("pineapplejuice" = 2, "limejuice" = 1, "sodawater" = 2, "honey" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/driverspunch
- name = "Driver`s Punch"
- id = "driverspunch"
- result = "driverspunch"
- required_reagents = list("appleade" = 2, "orangejuice" = 1, "mint" = 1, "sodawater" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/mintapplesparkle
- name = "Mint Apple Sparkle"
- id = "mintapplesparkle"
- result = "mintapplesparkle"
- required_reagents = list("appleade" = 2, "mint" = 1)
- inhibitors = list("sodawater" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/berrycordial
- name = "Berry Cordial"
- id = "berrycordial"
- result = "berrycordial"
- required_reagents = list("berryjuice" = 4, "sugar" = 1, "lemonjuice" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/tropicalfizz
- name = "Tropical Fizz"
- id = "tropicalfizz"
- result = "tropicalfizz"
- required_reagents = list("sodawater" = 6, "berryjuice" = 1, "mint" = 1, "limejuice" = 1, "lemonjuice" = 1, "pineapplejuice" = 1)
- inhibitors = list("sugar" = 1)
- result_amount = 8
-
-/datum/chemical_reaction/drinks/melonspritzer
- name = "Melon Spritzer"
- id = "melonspritzer"
- result = "melonspritzer"
- required_reagents = list("watermelonjuice" = 2, "wine" = 2, "applejuice" = 1, "limejuice" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/fauxfizz
- name = "Faux Fizz"
- id = "fauxfizz"
- result = "fauxfizz"
- required_reagents = list("sodawater" = 2, "berryjuice" = 1, "applejuice" = 1, "limejuice" = 1, "honey" = 1)
- inhibitors = list("sugar" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/firepunch
- name = "Fire Punch"
- id = "firepunch"
- result = "firepunch"
- required_reagents = list("sugar" = 1, "rum" = 2)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/kiraspecial
- name = "Kira Special"
- id = "kiraspecial"
- result = "kiraspecial"
- required_reagents = list("orangejuice" = 1, "limejuice" = 1, "sodawater" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/brownstar
- name = "Brown Star"
- id = "brownstar"
- result = "brownstar"
- required_reagents = list("orangejuice" = 2, "cola" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/milkshake
- name = "Milkshake"
- id = "milkshake"
- result = "milkshake"
- required_reagents = list("cream" = 1, "ice" = 2, "milk" = 2)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/peanutmilkshake
- name = "Peanutbutter Milkshake"
- id = "peanutmilkshake"
- result = "peanutmilkshake"
- required_reagents = list("cream" = 1, "ice" = 1, "peanutbutter" = 2, "milk" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/rewriter
- name = "Rewriter"
- id = "rewriter"
- result = "rewriter"
- required_reagents = list("spacemountainwind" = 1, "coffee" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/suidream
- name = "Sui Dream"
- id = "suidream"
- result = "suidream"
- required_reagents = list("space_up" = 1, "bluecuracao" = 1, "melonliquor" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/shirleytemple
- name = "Shirley Temple"
- id = "shirley_temple"
- result = "shirley_temple"
- required_reagents = list("gingerale" = 4, "grenadine" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/royrogers
- name = "Roy Rogers"
- id = "roy_rogers"
- result = "roy_rogers"
- required_reagents = list("shirley_temple" = 5, "lemon_lime" = 2)
- result_amount = 7
-
-/datum/chemical_reaction/drinks/collinsmix
- name = "Collins Mix"
- id = "collins_mix"
- result = "collins_mix"
- required_reagents = list("lemon_lime" = 3, "sodawater" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/drinks/arnoldpalmer
- name = "Arnold Palmer"
- id = "arnold_palmer"
- result = "arnold_palmer"
- required_reagents = list("icetea" = 1, "lemonade" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/minttea
- name = "Mint Tea"
- id = "minttea"
- result = "minttea"
- required_reagents = list("tea" = 5, "mint" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/lemontea
- name = "Lemon Tea"
- id = "lemontea"
- result = "lemontea"
- required_reagents = list("tea" = 5, "lemonjuice" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/limetea
- name = "Lime Tea"
- id = "limetea"
- result = "limetea"
- required_reagents = list("tea" = 5, "limejuice" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/orangetea
- name = "Orange Tea"
- id = "orangetea"
- result = "orangetea"
- required_reagents = list("tea" = 5, "orangejuice" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/berrytea
- name = "Berry Tea"
- id = "berrytea"
- result = "berrytea"
- required_reagents = list("tea" = 5, "berryjuice" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/sakebomb
- name = "Sake Bomb"
- id = "sakebomb"
- result = "sakebomb"
- required_reagents = list("beer" = 2, "sake" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/tamagozake
- name = "Tamagozake"
- id = "tamagozake"
- result = "tamagozake"
- required_reagents = list("sake" = 10, "sugar" = 5, "egg" = 3)
- result_amount = 15
-
-/datum/chemical_reaction/drinks/ginzamary
- name = "Ginza Mary"
- id = "ginzamary"
- result = "ginzamary"
- required_reagents = list("sake" = 2, "vodka" = 2, "tomatojuice" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/tokyorose
- name = "Tokyo Rose"
- id = "tokyorose"
- result = "tokyorose"
- required_reagents = list("sake" = 1, "berryjuice" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/saketini
- name = "Saketini"
- id = "saketini"
- result = "saketini"
- required_reagents = list("sake" = 1, "gin" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/elysiumfacepunch
- name = "Elysium Facepunch"
- id = "elysiumfacepunch"
- result = "elysiumfacepunch"
- required_reagents = list("kahlua" = 1, "lemonjuice" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/erebusmoonrise
- name = "Erebus Moonrise"
- id = "erebusmoonrise"
- result = "erebusmoonrise"
- required_reagents = list("whiskey" = 1, "vodka" = 1, "tequilla" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/balloon
- name = "Balloon"
- id = "balloon"
- result = "balloon"
- required_reagents = list("cream" = 1, "bluecuracao" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/natunabrandy
- name = "Natuna Brandy"
- id = "natunabrandy"
- result = "natunabrandy"
- required_reagents = list("beer" = 1, "sodawater" = 2)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/euphoria
- name = "Euphoria"
- id = "euphoria"
- result = "euphoria"
- required_reagents = list("specialwhiskey" = 1, "cognac" = 2)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/xanaducannon
- name = "Xanadu Cannon"
- id = "xanaducannon"
- result = "xanaducannon"
- required_reagents = list("ale" = 1, "dr_gibb" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/debugger
- name = "Debugger"
- id = "debugger"
- result = "debugger"
- required_reagents = list("fuel" = 1, "sugar" = 2, "cornoil" = 2)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/spacersbrew
- name = "Spacer's Brew"
- id = "spacersbrew"
- result = "spacersbrew"
- required_reagents = list("brownstar" = 4, "ethanol" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/binmanbliss
- name = "Binman Bliss"
- id = "binmanbliss"
- result = "binmanbliss"
- required_reagents = list("sake" = 1, "tequilla" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/chrysanthemum
- name = "Chrysanthemum"
- id = "chrysanthemum"
- result = "chrysanthemum"
- required_reagents = list("sake" = 1, "melonliquor" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/deathbell
- name = "Deathbell"
- id = "deathbell"
- result = "deathbell"
- required_reagents = list("antifreeze" = 1, "gargleblaster" = 1, "syndicatebomb" =1)
- result_amount = 3
-
-/datum/chemical_reaction/bitters
- name = "Bitters"
- id = "bitters"
- result = "bitters"
- required_reagents = list("mint" = 5)
- catalysts = list("enzyme" = 5)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/soemmerfire
- name = "Soemmer Fire"
- id = "soemmerfire"
- result = "soemmerfire"
- required_reagents = list("manhattan" = 2, "condensedcapsaicin" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/winebrandy
- name = "Wine brandy"
- id = "winebrandy"
- result = "winebrandy"
- required_reagents = list("wine" = 10)
- catalysts = list("enzyme" = 10) //10u enzyme so it requires more than is usually added. Stops overlap with wine recipe
- result_amount = 5
-
-/datum/chemical_reaction/drinks/lovepotion
- name = "Love Potion"
- id = "lovepotion"
- result = "lovepotion"
- required_reagents = list("cream" = 1, "berryjuice" = 1, "sugar" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/morningafter
- name = "Morning After"
- id = "morningafter"
- result = "morningafter"
- required_reagents = list("sbiten" = 1, "coffee" = 5)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/vesper
- name = "Vesper"
- id = "vesper"
- result = "vesper"
- required_reagents = list("gin" = 3, "vodka" = 1, "wine" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/drinks/rotgut
- name = "Rotgut Fever Dream"
- id = "rotgut"
- result = "rotgut"
- required_reagents = list("vodka" = 3, "rum" = 1, "whiskey" = 1, "cola" = 3)
- result_amount = 8
-
-/datum/chemical_reaction/drinks/entdraught
- name = "Ent's Draught"
- id = "entdraught"
- result = "entdraught"
- required_reagents = list("tonic" = 1, "holywater" = 1, "honey" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/voxdelight
- name = "Vox's Delight"
- id = "voxdelight"
- result = "voxdelight"
- required_reagents = list("phoron" = 3, "fuel" = 1, "water" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/drinks/screamingviking
- name = "Screaming Viking"
- id = "screamingviking"
- result = "screamingviking"
- required_reagents = list("martini" = 2, "vodkatonic" = 2, "limejuice" = 1, "rum" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/vilelemon
- name = "Vile Lemon"
- id = "vilelemon"
- result = "vilelemon"
- required_reagents = list("lemonade" = 5, "spacemountainwind" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/dreamcream
- name = "Dream Cream"
- id = "dreamcream"
- result = "dreamcream"
- required_reagents = list("milk" = 2, "cream" = 1, "honey" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/drinks/robustin
- name = "Robustin"
- id = "robustin"
- result = "robustin"
- required_reagents = list("antifreeze" = 1, "phoron" = 1, "fuel" = 1, "vodka" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/drinks/virginsip
- name = "Virgin Sip"
- id = "virginsip"
- result = "virginsip"
- required_reagents = list("driestmartini" = 1, "water" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/chocoshake
- name = "Chocolate Milkshake"
- id = "chocoshake"
- result = "chocoshake"
- required_reagents = list("milkshake" = 1, "coco" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/berryshake
- name = "Berry Milkshake"
- id = "berryshake"
- result = "berryshake"
- required_reagents = list("milkshake" = 1, "berryjuice" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/coffeeshake
- name = "Coffee Milkshake"
- id = "coffeeshake"
- result = "coffeeshake"
- required_reagents = list("milkshake" = 1, "coffee" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/jellyshot
- name = "Jelly Shot"
- id = "jellyshot"
- result = "jellyshot"
- required_reagents = list("cherryjelly" = 4, "vodka" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/slimeshot
- name = "Named Bullet"
- id = "slimeshot"
- result = "slimeshot"
- required_reagents = list("slimejelly" = 4, "vodka" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/negroni
- name = "Negroni"
- id = "negroni"
- result = "negroni"
- required_reagents = list("gin" = 1, "bitters" = 1, "vermouth" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/cloverclub
- name = "Clover Club"
- id = "cloverclub"
- result = "cloverclub"
- required_reagents = list("berryjuice" = 1, "lemonjuice" = 1, "gin" = 3)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/oldfashioned
- name = "Old Fashioned"
- id = "oldfashioned"
- result = "oldfashioned"
- required_reagents = list("whiskey" = 3, "bitters" = 1, "sugar" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/whiskeysour
- name = "Whiskey Sour"
- id = "whiskeysour"
- result = "whiskeysour"
- required_reagents = list("whiskey" = 2, "lemonjuice" = 1, "sugar" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/drinks/daiquiri
- name = "Daiquiri"
- id = "daiquiri"
- result = "daiquiri"
- required_reagents = list("rum" = 3, "limejuice" = 2, "sugar" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/mintjulep
- name = "Mint Julep"
- id = "mintjulep"
- result = "mintjulep"
- required_reagents = list("whiskey" = 2, "water" = 1, "mint" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/drinks/paloma
- name = "Paloma"
- id = "paloma"
- result = "paloma"
- required_reagents = list("orangejuice" = 1, "sodawater" = 1, "tequilla" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/mojito
- name = "Mojito"
- id = "mojito"
- result = "mojito"
- required_reagents = list("rum" = 3, "limejuice" = 1, "mint" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/virginmojito
- name = "Mojito"
- id = "virginmojito"
- result = "virginmojito"
- required_reagents = list("sodawater" = 3, "limejuice" = 1, "mint" = 1, "sugar" = 1)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/piscosour
- name = "Pisco Sour"
- id = "piscosour"
- result = "piscosour"
- required_reagents = list("winebrandy" = 1, "lemonjuice" = 1, "sugar" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/coldfront
- name = "Cold Front"
- id = "coldfront"
- result = "coldfront"
- required_reagents = list("icecoffee" = 1, "whiskey" = 1, "mint" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/godsake
- name = "Gods Sake"
- id = "godsake"
- result = "godsake"
- required_reagents = list("sake" = 2, "holywater" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/godka //Why you would put this in your body, I don't know.
- name = "Godka"
- id = "godka"
- result = "godka"
- required_reagents = list("vodka" = 1, "holywater" = 1, "ethanol" = 1, "carthatoline" = 1)
- catalysts = list("enzyme" = 5, "holywater" = 5)
- result_amount = 1
-
-/datum/chemical_reaction/drinks/holywine
- name = "Angel Ichor"
- id = "holywine"
- result = "holywine"
- required_reagents = list("grapejuice" = 5, "gold" = 5)
- catalysts = list("holywater" = 5)
- result_amount = 10
-
-/datum/chemical_reaction/drinks/holy_mary
- name = "Holy Mary"
- id = "holymary"
- result = "holymary"
- required_reagents = list("vodka" = 2, "holywine" = 3, "limejuice" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/angelskiss
- name = "Angels Kiss"
- id = "angelskiss"
- result = "angelskiss"
- required_reagents = list("holywine" = 1, "kahlua" = 1, "rum" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/angelswrath
- name = "Angels Wrath"
- id = "angelswrath"
- result = "angelswrath"
- required_reagents = list("rum" = 3, "spacemountainwind" = 1, "holywine" = 1, "dr_gibb" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/ichor_mead
- name = "Ichor Mead"
- id = "ichor_mead"
- result = "ichor_mead"
- required_reagents = list("holywine" = 1, "mead" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/oilslick
- name = "Oil Slick"
- id = "oilslick"
- result = "oilslick"
- required_reagents = list("cornoil" = 2, "honey" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/slimeslam
- name = "Slick Slime Slammer"
- id = "slimeslammer"
- result = "slimeslammer"
- required_reagents = list("cornoil" = 2, "peanutbutter" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/virginsexonthebeach
- name = "Virgin Sex On The Beach"
- id = "virginsexonthebeach"
- result = "virginsexonthebeach"
- required_reagents = list("orangejuice" = 3, "grenadine" = 2)
- result_amount = 5
-
-/datum/chemical_reaction/drinks/sexonthebeach
- name = "Sex On The Beach"
- id = "sexonthebeach"
- result = "sexonthebeach"
- required_reagents = list("virginsexonthebeach" = 5, "vodka" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/eggnog
- name = "Eggnog"
- id = "eggnog"
- result = "eggnog"
- required_reagents = list("milk" = 5, "cream" = 5, "sugar" = 5, "egg" = 3)
- result_amount = 15
-
-/datum/chemical_reaction/drinks/nuclearwaste_radium
- name = "Nuclear Waste"
- id = "nuclearwasterad"
- result = "nuclearwaste"
- required_reagents = list("oilslick" = 1, "radium" = 1, "limejuice" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/nuclearwaste_uranium
- name = "Nuclear Waste"
- id = "nuclearwasteuran"
- result = "nuclearwaste"
- required_reagents = list("oilslick" = 2, "uranium" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/sodaoil
- name = "Soda Oil"
- id = "sodaoil"
- result = "sodaoil"
- required_reagents = list("cornoil" = 4, "sodawater" = 1, "carbon" = 1, "tricordrazine" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/fusionnaire
- name = "Fusionnaire"
- id = "fusionnaire"
- result = "fusionnaire"
- required_reagents = list("lemonjuice" = 3, "vodka" = 2, "schnapps_pep" = 1, "schnapps_lem" = 1, "rum" = 1, "ice" = 1)
- result_amount = 9
-
-//R-UST Port
-/datum/chemical_reaction/hyrdophoron
- name = "Hydrophoron"
- id = "hydrophoron"
- result = "hydrophoron"
- required_reagents = list("hydrogen" = 1, "phoron" = 1)
- inhibitors = list("nitrogen" = 1) //So it doesn't mess with lexorin
- result_amount = 2
-
-/datum/chemical_reaction/deuterium
- name = "Deuterium"
- id = "deuterium"
- result = null
- required_reagents = list("hydrophoron" = 5, "water" = 10)
- result_amount = 15
-
-/datum/chemical_reaction/deuterium/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/turf/T = get_turf(holder.my_atom)
- if(istype(T)) new /obj/item/stack/material/deuterium(T, created_volume)
- return
-
-//Skrellian crap.
-/datum/chemical_reaction/talum_quem
- name = "Talum-quem"
- id = "talum_quem"
- result = "talum_quem"
- required_reagents = list("space_drugs" = 2, "sugar" = 1, "amatoxin" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/qerr_quem
- name = "Qerr-quem"
- id = "qerr_quem"
- result = "qerr_quem"
- required_reagents = list("nicotine" = 1, "carbon" = 1, "sugar" = 2)
- result_amount = 4
-
-/datum/chemical_reaction/malish_qualem
- name = "Malish-Qualem"
- id = "malish-qualem"
- result = "malish-qualem"
- required_reagents = list("immunosuprizine" = 1, "qerr_quem" = 1, "inaprovaline" = 1)
- catalysts = list("phoron" = 5)
- result_amount = 2
-
-// Biomass, for cloning and bioprinters
-/datum/chemical_reaction/biomass
- name = "Biomass"
- id = "biomass"
- result = "biomass"
- required_reagents = list("protein" = 1, "sugar" = 1, "phoron" = 1)
- result_amount = 1 // Roughly 20u per phoron sheet
-
-// Neutralization.
-
-/datum/chemical_reaction/neutralize_neurotoxic_protein
- name = "Neutralize Toxic Proteins"
- id = "neurotoxic_protein_neutral"
- result = "protein"
- required_reagents = list("anti_toxin" = 1, "neurotoxic_protein" = 2)
- result_amount = 2
-
-/datum/chemical_reaction/neutralize_carpotoxin
- name = "Neutralize Carpotoxin"
- id = "carpotoxin_neutral"
- result = "protein"
- required_reagents = list("radium" = 1, "carpotoxin" = 1, "sifsap" = 1)
- catalysts = list("sifsap" = 10)
- result_amount = 2
-
-/datum/chemical_reaction/neutralize_spidertoxin
- name = "Neutralize Spidertoxin"
- id = "spidertoxin_neutral"
- result = "protein"
- required_reagents = list("radium" = 1, "spidertoxin" = 1, "sifsap" = 1)
- catalysts = list("sifsap" = 10)
- result_amount = 2
-
-/*
-====================
- Aurora Food
-====================
-*/
-
-/datum/chemical_reaction/coating/batter
- name = "Batter"
- id = "batter"
- result = "batter"
- required_reagents = list("egg" = 3, "flour" = 10, "water" = 5, "sodiumchloride" = 2)
- result_amount = 20
-
-/datum/chemical_reaction/coating/beerbatter
- name = "Beer Batter"
- id = "beerbatter"
- result = "beerbatter"
- required_reagents = list("egg" = 3, "flour" = 10, "beer" = 5, "sodiumchloride" = 2)
- result_amount = 20
-
-/datum/chemical_reaction/browniemix
- name = "Brownie Mix"
- id = "browniemix"
- result = "browniemix"
- required_reagents = list("flour" = 5, "coco" = 5, "sugar" = 5)
- result_amount = 15
-
-/datum/chemical_reaction/butter
- name = "Butter"
- id = "butter"
- result = null
- required_reagents = list("cream" = 20, "sodiumchloride" = 1)
- result_amount = 1
-
-/datum/chemical_reaction/butter/on_reaction(var/datum/reagents/holder, var/created_volume)
- var/location = get_turf(holder.my_atom)
- for(var/i = 1, i <= created_volume, i++)
- new /obj/item/weapon/reagent_containers/food/snacks/spreads/butter(location)
- return
-
-/datum/chemical_reaction/browniemix
- name = "Brownie Mix"
- id = "browniemix"
- result = "browniemix"
- required_reagents = list("flour" = 5, "coco" = 5, "sugar" = 5)
- result_amount = 15
diff --git a/code/modules/reagents/holder/distilling.dm b/code/modules/reagents/holder/distilling.dm
new file mode 100644
index 00000000000..1599f395d91
--- /dev/null
+++ b/code/modules/reagents/holder/distilling.dm
@@ -0,0 +1,26 @@
+/datum/reagents/distilling/handle_reactions()
+ if(QDELETED(my_atom))
+ return FALSE
+ if(my_atom.flags & NOREACT)
+ return FALSE
+ var/reaction_occurred
+ var/list/eligible_reactions = list()
+ var/list/effect_reactions = list()
+ do
+ reaction_occurred = FALSE
+ for(var/i in reagent_list)
+ var/datum/reagent/R = i
+ if(SSchemistry.distilled_reactions_by_reagent[R.id])
+ eligible_reactions |= SSchemistry.distilled_reactions_by_reagent[R.id]
+
+ for(var/i in eligible_reactions)
+ var/decl/chemical_reaction/C = i
+ if(C.can_happen(src) && C.process(src))
+ effect_reactions |= C
+ reaction_occurred = TRUE
+ eligible_reactions.len = 0
+ while(reaction_occurred)
+ for(var/i in effect_reactions)
+ var/decl/chemical_reaction/C = i
+ C.post_reaction(src)
+ update_total()
\ No newline at end of file
diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/holder/holder.dm
similarity index 94%
rename from code/modules/reagents/Chemistry-Holder.dm
rename to code/modules/reagents/holder/holder.dm
index aa50a4b79f9..923ffb6bc97 100644
--- a/code/modules/reagents/Chemistry-Holder.dm
+++ b/code/modules/reagents/holder/holder.dm
@@ -1,518 +1,519 @@
-#define PROCESS_REACTION_ITER 5 //when processing a reaction, iterate this many times
-
-/datum/reagents
- var/list/datum/reagent/reagent_list = list()
- var/total_volume = 0
- var/maximum_volume = 100
- var/atom/my_atom = null
-
-/datum/reagents/New(var/max = 100, atom/A = null)
- ..()
- maximum_volume = max
- my_atom = A
-
- //I dislike having these here but map-objects are initialised before world/New() is called. >_>
- if(!SSchemistry.chemical_reagents)
- //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
- var/paths = typesof(/datum/reagent) - /datum/reagent
- SSchemistry.chemical_reagents = list()
- for(var/path in paths)
- var/datum/reagent/D = new path()
- if(!D.name)
- continue
- SSchemistry.chemical_reagents[D.id] = D
-
-/datum/reagents/Destroy()
- STOP_PROCESSING(SSchemistry, src)
- for(var/datum/reagent/R in reagent_list)
- qdel(R)
- reagent_list = null
- if(my_atom && my_atom.reagents == src)
- my_atom.reagents = null
- return ..()
-
-/* Internal procs */
-
-/datum/reagents/proc/get_free_space() // Returns free space.
- return maximum_volume - total_volume
-
-/datum/reagents/proc/get_master_reagent() // Returns reference to the reagent with the biggest volume.
- var/the_reagent = null
- var/the_volume = 0
-
- for(var/datum/reagent/A in reagent_list)
- if(A.volume > the_volume)
- the_volume = A.volume
- the_reagent = A
-
- return the_reagent
-
-/datum/reagents/proc/get_master_reagent_name() // Returns the name of the reagent with the biggest volume.
- var/the_name = null
- var/the_volume = 0
- for(var/datum/reagent/A in reagent_list)
- if(A.volume > the_volume)
- the_volume = A.volume
- the_name = A.name
-
- return the_name
-
-/datum/reagents/proc/get_master_reagent_id() // Returns the id of the reagent with the biggest volume.
- var/the_id = null
- var/the_volume = 0
- for(var/datum/reagent/A in reagent_list)
- if(A.volume > the_volume)
- the_volume = A.volume
- the_id = A.id
-
- return the_id
-
-/datum/reagents/proc/update_total() // Updates volume.
- total_volume = 0
- for(var/datum/reagent/R in reagent_list)
- if(R.volume < MINIMUM_CHEMICAL_VOLUME)
- del_reagent(R.id)
- else
- total_volume += R.volume
- return
-
-/datum/reagents/proc/handle_reactions()
- if(QDELETED(my_atom))
- return FALSE
- if(my_atom.flags & NOREACT)
- return FALSE
- var/reaction_occurred
- var/list/eligible_reactions = list()
- var/list/effect_reactions = list()
- do
- reaction_occurred = FALSE
- for(var/i in reagent_list)
- var/datum/reagent/R = i
- if(SSchemistry.chemical_reactions_by_reagent[R.id])
- eligible_reactions |= SSchemistry.chemical_reactions_by_reagent[R.id]
-
- for(var/i in eligible_reactions)
- var/datum/chemical_reaction/C = i
- if(C.can_happen(src) && C.process(src))
- effect_reactions |= C
- reaction_occurred = TRUE
- eligible_reactions.len = 0
- while(reaction_occurred)
- for(var/i in effect_reactions)
- var/datum/chemical_reaction/C = i
- C.post_reaction(src)
- update_total()
-
-/* Holder-to-chemical */
-
-/datum/reagents/proc/add_reagent(var/id, var/amount, var/data = null, var/safety = 0)
- if(!isnum(amount) || amount <= 0)
- return 0
-
- update_total()
- amount = min(amount, get_free_space())
-
- if(istype(my_atom,/obj/item/weapon/reagent_containers/food)) //The following code is targeted specifically at getting allergen reagents into food items, since for the most part they're not applied by default.
- var/list/add_reagents = list()
- var/totalnum = 0
-
- for(var/item in data) //Try to find the ID
- var/add_reagent_id = null
- if(item in SSchemistry.chemical_reagents)
- add_reagent_id = item
- else if("[item]juice" in SSchemistry.chemical_reagents)
- add_reagent_id = "[item]juice"
- if(add_reagent_id) //If we did find it, add it to our list of reagents to add, and add the number to our total.
- add_reagents[add_reagent_id] += data[item]
- totalnum += data[item]
-
- if(totalnum)
- var/multconst = amount/totalnum //We're going to add these extra reagents so that they share the ratio described, but only add up to 1x the existing amount at the most
- for(var/item in add_reagents)
- add_reagent(item,add_reagents[item]*multconst)
-
-
-
-
- for(var/datum/reagent/current in reagent_list)
- if(current.id == id)
- if(current.id == "blood")
- if(LAZYLEN(data) && !isnull(data["species"]) && !isnull(current.data["species"]) && data["species"] != current.data["species"]) // Species bloodtypes are already incompatible, this just stops it from mixing into the one already in a container.
- continue
-
- current.volume += amount
- if(!isnull(data)) // For all we know, it could be zero or empty string and meaningful
- current.mix_data(data, amount)
- update_total()
- if(!safety)
- handle_reactions()
- if(my_atom)
- my_atom.on_reagent_change()
- return 1
- var/datum/reagent/D = SSchemistry.chemical_reagents[id]
- if(D)
- var/datum/reagent/R = new D.type()
- reagent_list += R
- R.holder = src
- R.volume = amount
- R.initialize_data(data)
- update_total()
- if(!safety)
- handle_reactions()
- if(my_atom)
- my_atom.on_reagent_change()
- return 1
- else
- crash_with("[my_atom] attempted to add a reagent called '[id]' which doesn't exist. ([usr])")
- return 0
-
-/datum/reagents/proc/isolate_reagent(reagent)
- for(var/A in reagent_list)
- var/datum/reagent/R = A
- if(R.id != reagent)
- del_reagent(R.id)
- update_total()
-
-/datum/reagents/proc/remove_reagent(var/id, var/amount, var/safety = 0)
- if(!isnum(amount))
- return 0
- for(var/datum/reagent/current in reagent_list)
- if(current.id == id)
- current.volume -= amount // It can go negative, but it doesn't matter
- update_total() // Because this proc will delete it then
- if(!safety)
- handle_reactions()
- if(my_atom)
- my_atom.on_reagent_change()
- return 1
- return 0
-
-/datum/reagents/proc/del_reagent(var/id)
- for(var/datum/reagent/current in reagent_list)
- if (current.id == id)
- reagent_list -= current
- qdel(current)
- update_total()
- if(my_atom)
- my_atom.on_reagent_change()
- return 0
-
-/datum/reagents/proc/has_reagent(var/id, var/amount = 0)
- for(var/datum/reagent/current in reagent_list)
- if(current.id == id)
- if(current.volume >= amount)
- return 1
- else
- return 0
- return 0
-
-/datum/reagents/proc/has_any_reagent(var/list/check_reagents)
- for(var/datum/reagent/current in reagent_list)
- if(current.id in check_reagents)
- if(current.volume >= check_reagents[current.id])
- return 1
- else
- return 0
- return 0
-
-/datum/reagents/proc/has_all_reagents(var/list/check_reagents)
- //this only works if check_reagents has no duplicate entries... hopefully okay since it expects an associative list
- var/missing = check_reagents.len
- for(var/datum/reagent/current in reagent_list)
- if(current.id in check_reagents)
- if(current.volume >= check_reagents[current.id])
- missing--
- return !missing
-
-/datum/reagents/proc/clear_reagents()
- for(var/datum/reagent/current in reagent_list)
- del_reagent(current.id)
- return
-
-/datum/reagents/proc/get_reagent_amount(var/id)
- for(var/datum/reagent/current in reagent_list)
- if(current.id == id)
- return current.volume
- return 0
-
-/datum/reagents/proc/get_data(var/id)
- for(var/datum/reagent/current in reagent_list)
- if(current.id == id)
- return current.get_data()
- return 0
-
-/datum/reagents/proc/get_reagents()
- . = list()
- for(var/datum/reagent/current in reagent_list)
- . += "[current.id] ([current.volume])"
- return english_list(., "EMPTY", "", ", ", ", ")
-
-/* Holder-to-holder and similar procs */
-
-/datum/reagents/proc/remove_any(var/amount = 1) // Removes up to [amount] of reagents from [src]. Returns actual amount removed.
- amount = min(amount, total_volume)
-
- if(!amount)
- return
-
- var/part = amount / total_volume
-
- for(var/datum/reagent/current in reagent_list)
- var/amount_to_remove = current.volume * part
- remove_reagent(current.id, amount_to_remove, 1)
-
- update_total()
- handle_reactions()
- return amount
-
-/datum/reagents/proc/trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. Returns actual amount removed from [src] (not amount transferred to [target]).
- if(!target || !istype(target))
- return
-
- amount = max(0, min(amount, total_volume, target.get_free_space() / multiplier))
-
- if(!amount)
- return
-
- var/part = amount / total_volume
-
- for(var/datum/reagent/current in reagent_list)
- var/amount_to_transfer = current.volume * part
- target.add_reagent(current.id, amount_to_transfer * multiplier, current.get_data(), safety = 1) // We don't react until everything is in place
- if(!copy)
- remove_reagent(current.id, amount_to_transfer, 1)
-
- if(!copy)
- handle_reactions()
- target.handle_reactions()
- return amount
-
-/* Holder-to-atom and similar procs */
-
-//The general proc for applying reagents to things. This proc assumes the reagents are being applied externally,
-//not directly injected into the contents. It first calls touch, then the appropriate trans_to_*() or splash_mob().
-//If for some reason touch effects are bypassed (e.g. injecting stuff directly into a reagent container or person),
-//call the appropriate trans_to_*() proc.
-/datum/reagents/proc/trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
- touch(target) //First, handle mere touch effects
-
- if(ismob(target))
- return splash_mob(target, amount, copy)
- if(isturf(target))
- return trans_to_turf(target, amount, multiplier, copy)
- if(isobj(target) && target.is_open_container())
- return trans_to_obj(target, amount, multiplier, copy)
- return 0
-
-//Splashing reagents is messier than trans_to, the target's loc gets some of the reagents as well.
-/datum/reagents/proc/splash(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/min_spill=0, var/max_spill=60)
- var/spill = 0
- if(!isturf(target) && target.loc)
- spill = amount*(rand(min_spill, max_spill)/100)
- amount -= spill
- if(spill)
- splash(target.loc, spill, multiplier, copy, min_spill, max_spill)
-
- if(!trans_to(target, amount, multiplier, copy))
- touch(target, amount)
-
-/datum/reagents/proc/trans_type_to(var/target, var/rtype, var/amount = 1)
- if (!target)
- return
-
- var/datum/reagent/transfering_reagent = get_reagent(rtype)
-
- if (istype(target, /atom))
- var/atom/A = target
- if (!A.reagents || !A.simulated)
- return
-
- amount = min(amount, transfering_reagent.volume)
-
- if(!amount)
- return
-
-
- var/datum/reagents/F = new /datum/reagents(amount)
- var/tmpdata = get_data(rtype)
- F.add_reagent(rtype, amount, tmpdata)
- remove_reagent(rtype, amount)
-
-
- if (istype(target, /atom))
- return F.trans_to(target, amount) // Let this proc check the atom's type
- else if (istype(target, /datum/reagents))
- return F.trans_to_holder(target, amount)
-
-/datum/reagents/proc/trans_id_to(var/atom/target, var/id, var/amount = 1)
- if (!target || !target.reagents)
- return
-
- amount = min(amount, get_reagent_amount(id))
-
- if(!amount)
- return
-
- var/datum/reagents/F = new /datum/reagents(amount)
- var/tmpdata = get_data(id)
- F.add_reagent(id, amount, tmpdata)
- remove_reagent(id, amount)
-
- return F.trans_to(target, amount) // Let this proc check the atom's type
-
-// When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent.
-// This does not handle transferring reagents to things.
-// For example, splashing someone with water will get them wet and extinguish them if they are on fire,
-// even if they are wearing an impermeable suit that prevents the reagents from contacting the skin.
-/datum/reagents/proc/touch(var/atom/target, var/amount)
- if(ismob(target))
- touch_mob(target, amount)
- if(isturf(target))
- touch_turf(target, amount)
- if(isobj(target))
- touch_obj(target, amount)
- return
-
-/datum/reagents/proc/touch_mob(var/mob/target)
- if(!target || !istype(target))
- return
-
- for(var/datum/reagent/current in reagent_list)
- current.touch_mob(target, current.volume)
-
- update_total()
-
-/datum/reagents/proc/touch_turf(var/turf/target, var/amount)
- if(!target || !istype(target))
- return
-
- for(var/datum/reagent/current in reagent_list)
- current.touch_turf(target, amount)
-
- update_total()
-
-/datum/reagents/proc/touch_obj(var/obj/target, var/amount)
- if(!target || !istype(target))
- return
-
- for(var/datum/reagent/current in reagent_list)
- current.touch_obj(target, amount)
-
- update_total()
-
-// Attempts to place a reagent on the mob's skin.
-// Reagents are not guaranteed to transfer to the target.
-// Do not call this directly, call trans_to() instead.
-/datum/reagents/proc/splash_mob(var/mob/target, var/amount = 1, var/copy = 0)
- var/perm = 1
- if(isliving(target)) //will we ever even need to tranfer reagents to non-living mobs?
- var/mob/living/L = target
- if(ishuman(L))
- var/mob/living/carbon/human/H = L
- if(H.check_shields(0, null, null, null, "the spray") == 1) //If they block the spray, it does nothing.
- amount = 0
- perm = L.reagent_permeability()
- return trans_to_mob(target, amount, CHEM_TOUCH, perm, copy)
-
-/datum/reagents/proc/trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_BLOOD, var/multiplier = 1, var/copy = 0) // Transfer after checking into which holder...
- if(!target || !istype(target))
- return
- if(iscarbon(target))
- var/mob/living/carbon/C = target
- if(type == CHEM_BLOOD)
- var/datum/reagents/R = C.reagents
- return trans_to_holder(R, amount, multiplier, copy)
- if(type == CHEM_INGEST)
- var/datum/reagents/R = C.ingested
- return C.ingest(src, R, amount, multiplier, copy)
- if(type == CHEM_TOUCH)
- var/datum/reagents/R = C.touching
- return trans_to_holder(R, amount, multiplier, copy)
- else
- var/datum/reagents/R = new /datum/reagents(amount)
- . = trans_to_holder(R, amount, multiplier, copy)
- R.touch_mob(target)
-
-/datum/reagents/proc/trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Turfs don't have any reagents (at least, for now). Just touch it.
- if(!target)
- return
-
- var/datum/reagents/R = new /datum/reagents(amount * multiplier)
- . = trans_to_holder(R, amount, multiplier, copy)
- R.touch_turf(target, amount)
- return
-
-/datum/reagents/proc/trans_to_obj(var/obj/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Objects may or may not; if they do, it's probably a beaker or something and we need to transfer properly; otherwise, just touch.
- if(!target)
- return
-
- if(!target.reagents)
- var/datum/reagents/R = new /datum/reagents(amount * multiplier)
- . = trans_to_holder(R, amount, multiplier, copy)
- R.touch_obj(target, amount)
- return
-
- return trans_to_holder(target.reagents, amount, multiplier, copy)
-
-/* Atom reagent creation - use it all the time */
-
-/atom/proc/create_reagents(var/max_vol)
- reagents = new/datum/reagents(max_vol, src)
-
-// Aurora Cooking Port
-/datum/reagents/proc/get_reagent(var/id) // Returns reference to reagent matching passed ID
- for(var/datum/reagent/A in reagent_list)
- if (A.id == id)
- return A
-
- return null
-
-//Spreads the contents of this reagent holder all over the vicinity of the target turf.
-/datum/reagents/proc/splash_area(var/turf/epicentre, var/range = 3, var/portion = 1.0, var/multiplier = 1, var/copy = 0)
- var/list/things = dview(range, epicentre, INVISIBILITY_LIGHTING)
- var/list/turfs = list()
- for (var/turf/T in things)
- turfs += T
- if (!turfs.len)
- return//Nowhere to splash to, somehow
- //Create a temporary holder to hold all the amount that will be spread
- var/datum/reagents/R = new /datum/reagents(total_volume * portion * multiplier)
- trans_to_holder(R, total_volume * portion, multiplier, copy)
- //The exact amount that will be given to each turf
- var/turfportion = R.total_volume / turfs.len
- for (var/turf/T in turfs)
- var/datum/reagents/TR = new /datum/reagents(turfportion)
- R.trans_to_holder(TR, turfportion, 1, 0)
- TR.splash_turf(T)
- qdel(R)
-
-
-//Spreads the contents of this reagent holder all over the target turf, dividing among things in it.
-//50% is divided between mobs, 20% between objects, and whatever is left on the turf itself
-/datum/reagents/proc/splash_turf(var/turf/T, var/amount = null, var/multiplier = 1, var/copy = 0)
- if (isnull(amount))
- amount = total_volume
- else
- amount = min(amount, total_volume)
- if (amount <= 0)
- return
- var/list/mobs = list()
- for (var/mob/M in T)
- mobs += M
- var/list/objs = list()
- for (var/obj/O in T)
- objs += O
- if (objs.len)
- var/objportion = (amount * 0.2) / objs.len
- for (var/o in objs)
- var/obj/O = o
- trans_to(O, objportion, multiplier, copy)
- amount = min(amount, total_volume)
- if (mobs.len)
- var/mobportion = (amount * 0.5) / mobs.len
- for (var/m in mobs)
- var/mob/M = m
- trans_to(M, mobportion, multiplier, copy)
- trans_to(T, total_volume, multiplier, copy)
- if (total_volume <= 0)
+#define PROCESS_REACTION_ITER 5 //when processing a reaction, iterate this many times
+
+/datum/reagents
+ var/list/datum/reagent/reagent_list = list()
+ var/total_volume = 0
+ var/maximum_volume = 100
+ var/atom/my_atom = null
+
+/datum/reagents/New(var/max = 100, atom/A = null)
+ ..()
+ maximum_volume = max
+ my_atom = A
+
+ //I dislike having these here but map-objects are initialised before world/New() is called. >_>
+ if(!SSchemistry.chemical_reagents)
+ //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
+ var/paths = subtypesof(/datum/reagent)
+ SSchemistry.chemical_reagents = list()
+ for(var/path in paths)
+ var/datum/reagent/D = new path()
+ if(!D.name)
+ continue
+ SSchemistry.chemical_reagents[D.id] = D
+
+/datum/reagents/Destroy()
+ for(var/datum/reagent/R in reagent_list)
+ qdel(R)
+ reagent_list = null
+ if(my_atom && my_atom.reagents == src)
+ my_atom.reagents = null
+ return ..()
+
+/* Internal procs */
+
+/datum/reagents/proc/get_free_space() // Returns free space.
+ return maximum_volume - total_volume
+
+/datum/reagents/proc/get_master_reagent() // Returns reference to the reagent with the biggest volume.
+ var/the_reagent = null
+ var/the_volume = 0
+
+ for(var/datum/reagent/A in reagent_list)
+ if(A.volume > the_volume)
+ the_volume = A.volume
+ the_reagent = A
+
+ return the_reagent
+
+/datum/reagents/proc/get_master_reagent_name() // Returns the name of the reagent with the biggest volume.
+ var/the_name = null
+ var/the_volume = 0
+ for(var/datum/reagent/A in reagent_list)
+ if(A.volume > the_volume)
+ the_volume = A.volume
+ the_name = A.name
+
+ return the_name
+
+/datum/reagents/proc/get_master_reagent_id() // Returns the id of the reagent with the biggest volume.
+ var/the_id = null
+ var/the_volume = 0
+ for(var/datum/reagent/A in reagent_list)
+ if(A.volume > the_volume)
+ the_volume = A.volume
+ the_id = A.id
+
+ return the_id
+
+/datum/reagents/proc/update_total() // Updates volume.
+ total_volume = 0
+ for(var/datum/reagent/R in reagent_list)
+ if(R.volume < MINIMUM_CHEMICAL_VOLUME)
+ del_reagent(R.id)
+ else
+ total_volume += R.volume
+ return
+
+/datum/reagents/proc/handle_reactions()
+ if(QDELETED(my_atom))
+ return FALSE
+ if(my_atom.flags & NOREACT)
+ return FALSE
+ var/reaction_occurred
+ var/list/eligible_reactions = list()
+ var/list/effect_reactions = list()
+ do
+ reaction_occurred = FALSE
+ for(var/i in reagent_list)
+ var/datum/reagent/R = i
+ if(SSchemistry.instant_reactions_by_reagent[R.id])
+ eligible_reactions |= SSchemistry.instant_reactions_by_reagent[R.id]
+
+ for(var/i in eligible_reactions)
+ var/decl/chemical_reaction/C = i
+ if(C.can_happen(src) && C.process(src))
+ effect_reactions |= C
+ reaction_occurred = TRUE
+ eligible_reactions.len = 0
+ while(reaction_occurred)
+ for(var/i in effect_reactions)
+ var/decl/chemical_reaction/C = i
+ C.post_reaction(src)
+ update_total()
+
+/* Holder-to-chemical */
+
+/datum/reagents/proc/add_reagent(var/id, var/amount, var/data = null, var/safety = 0)
+ if(!isnum(amount) || amount <= 0)
+ return 0
+
+ update_total()
+ amount = min(amount, get_free_space())
+
+ if(istype(my_atom,/obj/item/weapon/reagent_containers/food)) //The following code is targeted specifically at getting allergen reagents into food items, since for the most part they're not applied by default.
+ var/list/add_reagents = list()
+ var/totalnum = 0
+
+ for(var/item in data) //Try to find the ID
+ var/add_reagent_id = null
+ if(item in SSchemistry.chemical_reagents)
+ add_reagent_id = item
+ else if("[item]juice" in SSchemistry.chemical_reagents)
+ add_reagent_id = "[item]juice"
+ if(add_reagent_id) //If we did find it, add it to our list of reagents to add, and add the number to our total.
+ add_reagents[add_reagent_id] += data[item]
+ totalnum += data[item]
+
+ if(totalnum)
+ var/multconst = amount/totalnum //We're going to add these extra reagents so that they share the ratio described, but only add up to 1x the existing amount at the most
+ for(var/item in add_reagents)
+ add_reagent(item,add_reagents[item]*multconst)
+
+
+
+
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ if(current.id == "blood")
+ if(LAZYLEN(data) && !isnull(data["species"]) && !isnull(current.data["species"]) && data["species"] != current.data["species"]) // Species bloodtypes are already incompatible, this just stops it from mixing into the one already in a container.
+ continue
+
+ current.volume += amount
+ if(!isnull(data)) // For all we know, it could be zero or empty string and meaningful
+ current.mix_data(data, amount)
+ update_total()
+ if(!safety)
+ handle_reactions()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 1
+ var/datum/reagent/D = SSchemistry.chemical_reagents[id]
+ if(D)
+ var/datum/reagent/R = new D.type()
+ reagent_list += R
+ R.holder = src
+ R.volume = amount
+ R.initialize_data(data)
+ update_total()
+ if(!safety)
+ handle_reactions()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 1
+ else
+ crash_with("[my_atom] attempted to add a reagent called '[id]' which doesn't exist. ([usr])")
+ return 0
+
+/datum/reagents/proc/isolate_reagent(reagent)
+ for(var/A in reagent_list)
+ var/datum/reagent/R = A
+ if(R.id != reagent)
+ del_reagent(R.id)
+ update_total()
+
+/datum/reagents/proc/remove_reagent(var/id, var/amount, var/safety = 0)
+ if(!isnum(amount))
+ return 0
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ current.volume -= amount // It can go negative, but it doesn't matter
+ update_total() // Because this proc will delete it then
+ if(!safety)
+ handle_reactions()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 1
+ return 0
+
+/datum/reagents/proc/del_reagent(var/id)
+ for(var/datum/reagent/current in reagent_list)
+ if (current.id == id)
+ reagent_list -= current
+ qdel(current)
+ update_total()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 0
+
+/datum/reagents/proc/has_reagent(var/id, var/amount = 0)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ if(current.volume >= amount)
+ return 1
+ else
+ return 0
+ return 0
+
+/datum/reagents/proc/has_any_reagent(var/list/check_reagents)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id in check_reagents)
+ if(current.volume >= check_reagents[current.id])
+ return 1
+ else
+ return 0
+ return 0
+
+/datum/reagents/proc/has_all_reagents(var/list/check_reagents)
+ //this only works if check_reagents has no duplicate entries... hopefully okay since it expects an associative list
+ var/missing = check_reagents.len
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id in check_reagents)
+ if(current.volume >= check_reagents[current.id])
+ missing--
+ return !missing
+
+/datum/reagents/proc/clear_reagents()
+ for(var/datum/reagent/current in reagent_list)
+ del_reagent(current.id)
+ return
+
+/datum/reagents/proc/get_reagent_amount(var/id)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ return current.volume
+ return 0
+
+/datum/reagents/proc/get_data(var/id)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ return current.get_data()
+ return 0
+
+/datum/reagents/proc/get_reagents()
+ . = list()
+ for(var/datum/reagent/current in reagent_list)
+ . += "[current.id] ([current.volume])"
+ return english_list(., "EMPTY", "", ", ", ", ")
+
+/* Holder-to-holder and similar procs */
+
+/datum/reagents/proc/remove_any(var/amount = 1) // Removes up to [amount] of reagents from [src]. Returns actual amount removed.
+ amount = min(amount, total_volume)
+
+ if(!amount)
+ return
+
+ var/part = amount / total_volume
+
+ for(var/datum/reagent/current in reagent_list)
+ var/amount_to_remove = current.volume * part
+ remove_reagent(current.id, amount_to_remove, 1)
+
+ update_total()
+ handle_reactions()
+ return amount
+
+/datum/reagents/proc/trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. Returns actual amount removed from [src] (not amount transferred to [target]).
+ if(!target || !istype(target))
+ return
+
+ amount = max(0, min(amount, total_volume, target.get_free_space() / multiplier))
+
+ if(!amount)
+ return
+
+ var/part = amount / total_volume
+
+ for(var/datum/reagent/current in reagent_list)
+ var/amount_to_transfer = current.volume * part
+ target.add_reagent(current.id, amount_to_transfer * multiplier, current.get_data(), safety = 1) // We don't react until everything is in place
+ if(!copy)
+ remove_reagent(current.id, amount_to_transfer, 1)
+
+ if(!copy)
+ handle_reactions()
+ target.handle_reactions()
+ return amount
+
+/* Holder-to-atom and similar procs */
+
+//The general proc for applying reagents to things. This proc assumes the reagents are being applied externally,
+//not directly injected into the contents. It first calls touch, then the appropriate trans_to_*() or splash_mob().
+//If for some reason touch effects are bypassed (e.g. injecting stuff directly into a reagent container or person),
+//call the appropriate trans_to_*() proc.
+/datum/reagents/proc/trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
+ touch(target) //First, handle mere touch effects
+
+ if(ismob(target))
+ return splash_mob(target, amount, copy)
+ if(isturf(target))
+ return trans_to_turf(target, amount, multiplier, copy)
+ if(isobj(target) && target.is_open_container())
+ return trans_to_obj(target, amount, multiplier, copy)
+ return 0
+
+//Splashing reagents is messier than trans_to, the target's loc gets some of the reagents as well.
+/datum/reagents/proc/splash(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/min_spill=0, var/max_spill=60)
+ var/spill = 0
+ if(!isturf(target) && target.loc)
+ spill = amount*(rand(min_spill, max_spill)/100)
+ amount -= spill
+ if(spill)
+ splash(target.loc, spill, multiplier, copy, min_spill, max_spill)
+
+ if(!trans_to(target, amount, multiplier, copy))
+ touch(target, amount)
+
+/datum/reagents/proc/trans_type_to(var/target, var/rtype, var/amount = 1)
+ if (!target)
+ return
+
+ var/datum/reagent/transfering_reagent = get_reagent(rtype)
+
+ if (istype(target, /atom))
+ var/atom/A = target
+ if (!A.reagents || !A.simulated)
+ return
+
+ amount = min(amount, transfering_reagent.volume)
+
+ if(!amount)
+ return
+
+
+ var/datum/reagents/F = new /datum/reagents(amount)
+ var/tmpdata = get_data(rtype)
+ F.add_reagent(rtype, amount, tmpdata)
+ remove_reagent(rtype, amount)
+
+
+ if (istype(target, /atom))
+ return F.trans_to(target, amount) // Let this proc check the atom's type
+ else if (istype(target, /datum/reagents))
+ return F.trans_to_holder(target, amount)
+
+/datum/reagents/proc/trans_id_to(var/atom/target, var/id, var/amount = 1)
+ if (!target || !target.reagents)
+ return
+
+ amount = min(amount, get_reagent_amount(id))
+
+ if(!amount)
+ return
+
+ var/datum/reagents/F = new /datum/reagents(amount)
+ var/tmpdata = get_data(id)
+ F.add_reagent(id, amount, tmpdata)
+ remove_reagent(id, amount)
+
+ return F.trans_to(target, amount) // Let this proc check the atom's type
+
+// When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent.
+// This does not handle transferring reagents to things.
+// For example, splashing someone with water will get them wet and extinguish them if they are on fire,
+// even if they are wearing an impermeable suit that prevents the reagents from contacting the skin.
+/datum/reagents/proc/touch(var/atom/target, var/amount)
+ if(ismob(target))
+ touch_mob(target, amount)
+ if(isturf(target))
+ touch_turf(target, amount)
+ if(isobj(target))
+ touch_obj(target, amount)
+ return
+
+/datum/reagents/proc/touch_mob(var/mob/target)
+ if(!target || !istype(target))
+ return
+
+ for(var/datum/reagent/current in reagent_list)
+ current.touch_mob(target, current.volume)
+
+ update_total()
+
+/datum/reagents/proc/touch_turf(var/turf/target, var/amount)
+ if(!target || !istype(target))
+ return
+
+ for(var/datum/reagent/current in reagent_list)
+ current.touch_turf(target, amount)
+
+ update_total()
+
+/datum/reagents/proc/touch_obj(var/obj/target, var/amount)
+ if(!target || !istype(target))
+ return
+
+ for(var/datum/reagent/current in reagent_list)
+ current.touch_obj(target, amount)
+
+ update_total()
+
+// Attempts to place a reagent on the mob's skin.
+// Reagents are not guaranteed to transfer to the target.
+// Do not call this directly, call trans_to() instead.
+/datum/reagents/proc/splash_mob(var/mob/target, var/amount = 1, var/copy = 0)
+ var/perm = 1
+ if(isliving(target)) //will we ever even need to tranfer reagents to non-living mobs?
+ var/mob/living/L = target
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(H.check_shields(0, null, null, null, "the spray") == 1) //If they block the spray, it does nothing.
+ amount = 0
+ perm = L.reagent_permeability()
+ return trans_to_mob(target, amount, CHEM_TOUCH, perm, copy)
+
+/datum/reagents/proc/trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_BLOOD, var/multiplier = 1, var/copy = 0) // Transfer after checking into which holder...
+ if(!target || !istype(target))
+ return
+ if(iscarbon(target))
+ var/mob/living/carbon/C = target
+ if(type == CHEM_BLOOD)
+ var/datum/reagents/R = C.reagents
+ return trans_to_holder(R, amount, multiplier, copy)
+ if(type == CHEM_INGEST)
+ var/datum/reagents/R = C.ingested
+ return C.ingest(src, R, amount, multiplier, copy)
+ if(type == CHEM_TOUCH)
+ var/datum/reagents/R = C.touching
+ return trans_to_holder(R, amount, multiplier, copy)
+ else
+ var/datum/reagents/R = new /datum/reagents(amount)
+ . = trans_to_holder(R, amount, multiplier, copy)
+ R.touch_mob(target)
+
+/datum/reagents/proc/trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Turfs don't have any reagents (at least, for now). Just touch it.
+ if(!target)
+ return
+
+ var/datum/reagents/R = new /datum/reagents(amount * multiplier)
+ . = trans_to_holder(R, amount, multiplier, copy)
+ R.touch_turf(target, amount)
+ return
+
+/datum/reagents/proc/trans_to_obj(var/obj/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Objects may or may not; if they do, it's probably a beaker or something and we need to transfer properly; otherwise, just touch.
+ if(!target)
+ return
+
+ if(!target.reagents)
+ var/datum/reagents/R = new /datum/reagents(amount * multiplier)
+ . = trans_to_holder(R, amount, multiplier, copy)
+ R.touch_obj(target, amount)
+ return
+
+ return trans_to_holder(target.reagents, amount, multiplier, copy)
+
+/* Atom reagent creation - use it all the time */
+
+/atom/proc/create_reagents(var/max_vol, var/reagents_type = /datum/reagents)
+ if(!ispath(reagents_type))
+ reagents_type = /datum/reagents
+ reagents = new reagents_type(max_vol, src)
+
+// Aurora Cooking Port
+/datum/reagents/proc/get_reagent(var/id) // Returns reference to reagent matching passed ID
+ for(var/datum/reagent/A in reagent_list)
+ if (A.id == id)
+ return A
+
+ return null
+
+//Spreads the contents of this reagent holder all over the vicinity of the target turf.
+/datum/reagents/proc/splash_area(var/turf/epicentre, var/range = 3, var/portion = 1.0, var/multiplier = 1, var/copy = 0)
+ var/list/things = dview(range, epicentre, INVISIBILITY_LIGHTING)
+ var/list/turfs = list()
+ for (var/turf/T in things)
+ turfs += T
+ if (!turfs.len)
+ return//Nowhere to splash to, somehow
+ //Create a temporary holder to hold all the amount that will be spread
+ var/datum/reagents/R = new /datum/reagents(total_volume * portion * multiplier)
+ trans_to_holder(R, total_volume * portion, multiplier, copy)
+ //The exact amount that will be given to each turf
+ var/turfportion = R.total_volume / turfs.len
+ for (var/turf/T in turfs)
+ var/datum/reagents/TR = new /datum/reagents(turfportion)
+ R.trans_to_holder(TR, turfportion, 1, 0)
+ TR.splash_turf(T)
+ qdel(R)
+
+
+//Spreads the contents of this reagent holder all over the target turf, dividing among things in it.
+//50% is divided between mobs, 20% between objects, and whatever is left on the turf itself
+/datum/reagents/proc/splash_turf(var/turf/T, var/amount = null, var/multiplier = 1, var/copy = 0)
+ if (isnull(amount))
+ amount = total_volume
+ else
+ amount = min(amount, total_volume)
+ if (amount <= 0)
+ return
+ var/list/mobs = list()
+ for (var/mob/M in T)
+ mobs += M
+ var/list/objs = list()
+ for (var/obj/O in T)
+ objs += O
+ if (objs.len)
+ var/objportion = (amount * 0.2) / objs.len
+ for (var/o in objs)
+ var/obj/O = o
+ trans_to(O, objportion, multiplier, copy)
+ amount = min(amount, total_volume)
+ if (mobs.len)
+ var/mobportion = (amount * 0.5) / mobs.len
+ for (var/m in mobs)
+ var/mob/M = m
+ trans_to(M, mobportion, multiplier, copy)
+ trans_to(T, total_volume, multiplier, copy)
+ if (total_volume <= 0)
qdel(src)
\ No newline at end of file
diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/machinery/chem_master.dm
similarity index 58%
rename from code/modules/reagents/Chemistry-Machinery.dm
rename to code/modules/reagents/machinery/chem_master.dm
index b5fe99b0540..3fdca52296a 100644
--- a/code/modules/reagents/Chemistry-Machinery.dm
+++ b/code/modules/reagents/machinery/chem_master.dm
@@ -1,862 +1,498 @@
-#define SOLID 1
-#define LIQUID 2
-#define GAS 3
-
-#define MAX_PILL_SPRITE 24 //max icon state of the pill sprites
-#define MAX_BOTTLE_SPRITE 4 //max icon state of the pill sprites
-#define MAX_MULTI_AMOUNT 20 // Max number of pills/patches that can be made at once
-#define MAX_UNITS_PER_PILL 60 // Max amount of units in a pill
-#define MAX_UNITS_PER_PATCH 60 // Max amount of units in a patch
-#define MAX_UNITS_PER_BOTTLE 60 // Max amount of units in a bottle (it's volume)
-#define MAX_CUSTOM_NAME_LEN 64 // Max length of a custom pill/condiment/whatever
-
-
-
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/obj/machinery/chem_master
- name = "ChemMaster 3000"
- desc = "Used to seperate and package chemicals in to patches, pills, or bottles. Warranty void if used to create Space Drugs."
- density = 1
- anchored = 1
- icon = 'icons/obj/chemical.dmi'
- icon_state = "mixer0"
- circuit = /obj/item/weapon/circuitboard/chem_master
- use_power = USE_POWER_IDLE
- idle_power_usage = 20
- var/obj/item/weapon/reagent_containers/beaker = null
- var/obj/item/weapon/storage/pill_bottle/loaded_pill_bottle = null
- var/mode = 0
- var/condi = 0
- var/useramount = 15 // Last used amount
- var/pillamount = 10
- var/list/bottle_styles
- var/bottlesprite = 1
- var/pillsprite = 1
- var/max_pill_count = 20
- var/printing = FALSE
- flags = OPENCONTAINER
- clicksound = "button"
-
-/obj/machinery/chem_master/New()
- ..()
- var/datum/reagents/R = new/datum/reagents(900) //Just a huge random number so the buffer should (probably) never dump your reagents.
- reagents = R //There should be a nano ui thingy to warn of this.
- R.my_atom = src
-
-/obj/machinery/chem_master/ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- return
- if(2.0)
- if (prob(50))
- qdel(src)
- return
-
-/obj/machinery/chem_master/update_icon()
- icon_state = "mixer[beaker ? "1" : "0"]"
-
-/obj/machinery/chem_master/attackby(var/obj/item/weapon/B as obj, var/mob/user as mob)
-
- if(istype(B, /obj/item/weapon/reagent_containers/glass) || istype(B, /obj/item/weapon/reagent_containers/food))
-
- if(src.beaker)
- to_chat(user, "\A [beaker] is already loaded into the machine.")
- return
- src.beaker = B
- user.drop_item()
- B.loc = src
- to_chat(user, "You add \the [B] to the machine.")
- update_icon()
-
- else if(istype(B, /obj/item/weapon/storage/pill_bottle))
-
- if(src.loaded_pill_bottle)
- to_chat(user, "A \the [loaded_pill_bottle] s already loaded into the machine.")
- return
-
- src.loaded_pill_bottle = B
- user.drop_item()
- B.loc = src
- to_chat(user, "You add \the [loaded_pill_bottle] into the dispenser slot.")
-
- else if(default_unfasten_wrench(user, B, 20))
- return
- if(default_deconstruction_screwdriver(user, B))
- return
- if(default_deconstruction_crowbar(user, B))
- return
-
- return
-
-/obj/machinery/chem_master/attack_hand(mob/user as mob)
- if(stat & BROKEN)
- return
- user.set_machine(src)
- tgui_interact(user)
-
-/obj/machinery/chem_master/ui_assets(mob/user)
- return list(
- get_asset_datum(/datum/asset/chem_master),
- )
-
-/obj/machinery/chem_master/tgui_interact(mob/user, datum/tgui/ui = null)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "ChemMaster", name)
- ui.open()
-
-/**
- * Display the NanoUI window for the chem master.
- *
- * See NanoUI documentation for details.
- */
-/obj/machinery/chem_master/tgui_data(mob/user)
- var/list/data = list()
-
- data["condi"] = condi
-
- data["loaded_pill_bottle"] = !!loaded_pill_bottle
- if(loaded_pill_bottle)
- data["loaded_pill_bottle_name"] = loaded_pill_bottle.name
- data["loaded_pill_bottle_contents_len"] = loaded_pill_bottle.contents.len
- data["loaded_pill_bottle_storage_slots"] = loaded_pill_bottle.max_storage_space
-
- data["beaker"] = !!beaker
- if(beaker)
- var/list/beaker_reagents_list = list()
- data["beaker_reagents"] = beaker_reagents_list
- for(var/datum/reagent/R in beaker.reagents.reagent_list)
- beaker_reagents_list[++beaker_reagents_list.len] = list("name" = R.name, "volume" = R.volume, "description" = R.description, "id" = R.id)
-
- var/list/buffer_reagents_list = list()
- data["buffer_reagents"] = buffer_reagents_list
- for(var/datum/reagent/R in reagents.reagent_list)
- buffer_reagents_list[++buffer_reagents_list.len] = list("name" = R.name, "volume" = R.volume, "id" = R.id, "description" = R.description)
-
- data["pillsprite"] = pillsprite
- data["bottlesprite"] = bottlesprite
- data["mode"] = mode
- data["printing"] = printing
-
- // Transfer modal information if there is one
- data["modal"] = tgui_modal_data(src)
-
- return data
-
-/**
- * Called in tgui_act() to process modal actions
- *
- * Arguments:
- * * action - The action passed by tgui
- * * params - The params passed by tgui
- */
-/obj/machinery/chem_master/proc/tgui_act_modal(action, params, datum/tgui/ui, datum/tgui_state/state)
- . = TRUE
- var/id = params["id"] // The modal's ID
- var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
- switch(tgui_modal_act(src, action, params))
- if(TGUI_MODAL_OPEN)
- switch(id)
- if("analyze")
- var/idx = text2num(arguments["idx"]) || 0
- var/from_beaker = text2num(arguments["beaker"]) || FALSE
- var/reagent_list = from_beaker ? beaker.reagents.reagent_list : reagents.reagent_list
- if(idx < 1 || idx > length(reagent_list))
- return
-
- var/datum/reagent/R = reagent_list[idx]
- var/list/result = list("idx" = idx, "name" = R.name, "desc" = R.description)
- if(!condi && istype(R, /datum/reagent/blood))
- var/datum/reagent/blood/B = R
- result["blood_type"] = B.data["blood_type"]
- result["blood_dna"] = B.data["blood_DNA"]
-
- arguments["analysis"] = result
- tgui_modal_message(src, id, "", null, arguments)
- // if("change_pill_bottle_style")
- // if(!loaded_pill_bottle)
- // return
- // if(!pill_bottle_wrappers)
- // pill_bottle_wrappers = list(
- // "CLEAR" = "Default",
- // COLOR_RED = "Red",
- // COLOR_GREEN = "Green",
- // COLOR_PALE_BTL_GREEN = "Pale green",
- // COLOR_BLUE = "Blue",
- // COLOR_CYAN_BLUE = "Light blue",
- // COLOR_TEAL = "Teal",
- // COLOR_YELLOW = "Yellow",
- // COLOR_ORANGE = "Orange",
- // COLOR_PINK = "Pink",
- // COLOR_MAROON = "Brown"
- // )
- // var/current = pill_bottle_wrappers[loaded_pill_bottle.wrapper_color] || "Default"
- // tgui_modal_choice(src, id, "Please select a pill bottle wrapper:", null, arguments, current, pill_bottle_wrappers)
- if("addcustom")
- if(!beaker || !beaker.reagents.total_volume)
- return
- tgui_modal_input(src, id, "Please enter the amount to transfer to buffer:", null, arguments, useramount)
- if("removecustom")
- if(!reagents.total_volume)
- return
- tgui_modal_input(src, id, "Please enter the amount to transfer to [mode ? "beaker" : "disposal"]:", null, arguments, useramount)
- if("create_condi_pack")
- if(!condi || !reagents.total_volume)
- return
- tgui_modal_input(src, id, "Please name your new condiment pack:", null, arguments, reagents.get_master_reagent_name(), MAX_CUSTOM_NAME_LEN)
- if("create_pill")
- if(condi || !reagents.total_volume)
- return
- var/num = round(text2num(arguments["num"] || 1))
- if(!num)
- return
- arguments["num"] = num
- var/amount_per_pill = CLAMP(reagents.total_volume / num, 0, MAX_UNITS_PER_PILL)
- var/default_name = "[reagents.get_master_reagent_name()] ([amount_per_pill]u)"
- var/pills_text = num == 1 ? "new pill" : "[num] new pills"
- tgui_modal_input(src, id, "Please name your [pills_text]:", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
- if("create_pill_multiple")
- if(condi || !reagents.total_volume)
- return
- tgui_modal_input(src, id, "Please enter the amount of pills to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
- if("change_pill_style")
- var/list/choices = list()
- for(var/i = 1 to MAX_PILL_SPRITE)
- choices += "pill[i].png"
- tgui_modal_bento(src, id, "Please select the new style for pills:", null, arguments, pillsprite, choices)
- if("create_patch")
- if(condi || !reagents.total_volume)
- return
- var/num = round(text2num(arguments["num"] || 1))
- if(!num)
- return
- arguments["num"] = num
- var/amount_per_patch = CLAMP(reagents.total_volume / num, 0, MAX_UNITS_PER_PATCH)
- var/default_name = "[reagents.get_master_reagent_name()] ([amount_per_patch]u)"
- var/patches_text = num == 1 ? "new patch" : "[num] new patches"
- tgui_modal_input(src, id, "Please name your [patches_text]:", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
- if("create_patch_multiple")
- if(condi || !reagents.total_volume)
- return
- tgui_modal_input(src, id, "Please enter the amount of patches to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
- if("create_bottle")
- if(condi || !reagents.total_volume)
- return
- var/num = round(text2num(arguments["num"] || 1))
- if(!num)
- return
- arguments["num"] = num
- var/amount_per_bottle = CLAMP(reagents.total_volume / num, 0, MAX_UNITS_PER_BOTTLE)
- var/default_name = "[reagents.get_master_reagent_name()]"
- var/bottles_text = num == 1 ? "new bottle" : "[num] new bottles"
- tgui_modal_input(src, id, "Please name your [bottles_text] ([amount_per_bottle]u in bottle):", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
- if("create_bottle_multiple")
- if(condi || !reagents.total_volume)
- return
- tgui_modal_input(src, id, "Please enter the amount of bottles to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
- if("change_bottle_style")
- var/list/choices = list()
- for(var/i = 1 to MAX_BOTTLE_SPRITE)
- choices += "bottle-[i].png"
- tgui_modal_bento(src, id, "Please select the new style for bottles:", null, arguments, bottlesprite, choices)
- else
- return FALSE
- if(TGUI_MODAL_ANSWER)
- var/answer = params["answer"]
- switch(id)
- // if("change_pill_bottle_style")
- // if(!pill_bottle_wrappers || !loaded_pill_bottle) // wat?
- // return
- // var/color = "CLEAR"
- // for(var/col in pill_bottle_wrappers)
- // var/col_name = pill_bottle_wrappers[col]
- // if(col_name == answer)
- // color = col
- // break
- // if(length(color) && color != "CLEAR")
- // loaded_pill_bottle.wrapper_color = color
- // loaded_pill_bottle.apply_wrap()
- // else
- // loaded_pill_bottle.wrapper_color = null
- // loaded_pill_bottle.cut_overlays()
- if("addcustom")
- var/amount = isgoodnumber(text2num(answer))
- if(!amount || !arguments["id"])
- return
- tgui_act("add", list("id" = arguments["id"], "amount" = amount), ui, state)
- if("removecustom")
- var/amount = isgoodnumber(text2num(answer))
- if(!amount || !arguments["id"])
- return
- tgui_act("remove", list("id" = arguments["id"], "amount" = amount), ui, state)
- if("create_condi_pack")
- if(!condi || !reagents.total_volume)
- return
- if(!length(answer))
- answer = reagents.get_master_reagent_name()
- var/obj/item/weapon/reagent_containers/pill/P = new(loc)
- P.name = "[answer] pack"
- P.desc = "A small condiment pack. The label says it contains [answer]."
- P.icon_state = "bouilloncube"//Reskinned monkey cube
- reagents.trans_to_obj(P, 10)
- if("create_pill")
- if(condi || !reagents.total_volume)
- return
- var/count = CLAMP(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
- if(!count)
- return
-
- if(!length(answer))
- answer = reagents.get_master_reagent_name()
- var/amount_per_pill = CLAMP(reagents.total_volume / count, 0, MAX_UNITS_PER_PILL)
- while(count--)
- if(reagents.total_volume <= 0)
- to_chat(usr, "Not enough reagents to create these pills!")
- return
-
- var/obj/item/weapon/reagent_containers/pill/P = new(loc)
- P.name = "[answer] pill"
- P.pixel_x = rand(-7, 7) // Random position
- P.pixel_y = rand(-7, 7)
- P.icon_state = "pill[pillsprite]"
- if(P.icon_state in list("pill1", "pill2", "pill3", "pill4")) // if using greyscale, take colour from reagent
- P.color = reagents.get_color()
- reagents.trans_to_obj(P, amount_per_pill)
- // Load the pills in the bottle if there's one loaded
- if(istype(loaded_pill_bottle) && length(loaded_pill_bottle.contents) < loaded_pill_bottle.max_storage_space)
- P.forceMove(loaded_pill_bottle)
- if("create_pill_multiple")
- if(condi || !reagents.total_volume)
- return
- tgui_act("modal_open", list("id" = "create_pill", "arguments" = list("num" = answer)), ui, state)
- if("change_pill_style")
- var/new_style = CLAMP(text2num(answer) || 0, 0, MAX_PILL_SPRITE)
- if(!new_style)
- return
- pillsprite = new_style
- if("create_patch")
- if(condi || !reagents.total_volume)
- return
- var/count = CLAMP(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
- if(!count)
- return
-
- if(!length(answer))
- answer = reagents.get_master_reagent_name()
- var/amount_per_patch = CLAMP(reagents.total_volume / count, 0, MAX_UNITS_PER_PATCH)
- // var/is_medical_patch = chemical_safety_check(reagents)
- while(count--)
- if(reagents.total_volume <= 0)
- to_chat(usr, "Not enough reagents to create these patches!")
- return
-
- var/obj/item/weapon/reagent_containers/pill/patch/P = new(loc)
- P.name = "[answer] patch"
- P.pixel_x = rand(-7, 7) // random position
- P.pixel_y = rand(-7, 7)
- reagents.trans_to_obj(P, amount_per_patch)
- // if(is_medical_patch)
- // P.instant_application = TRUE
- // P.icon_state = "bandaid_med"
- if("create_patch_multiple")
- if(condi || !reagents.total_volume)
- return
- tgui_act("modal_open", list("id" = "create_patch", "arguments" = list("num" = answer)), ui, state)
- if("create_bottle")
- if(condi || !reagents.total_volume)
- return
- var/count = CLAMP(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
- if(!count)
- return
-
- if(!length(answer))
- answer = reagents.get_master_reagent_name()
- var/amount_per_bottle = CLAMP(reagents.total_volume / count, 0, MAX_UNITS_PER_BOTTLE)
- while(count--)
- if(reagents.total_volume <= 0)
- to_chat(usr, "Not enough reagents to create these bottles!")
- return
- var/obj/item/weapon/reagent_containers/glass/bottle/P = new(loc)
- P.name = "[answer] bottle"
- P.pixel_x = rand(-7, 7) // random position
- P.pixel_y = rand(-7, 7)
- P.icon_state = "bottle-[bottlesprite]" || "bottle-1"
- reagents.trans_to_obj(P, amount_per_bottle)
- P.update_icon()
- if("create_bottle_multiple")
- if(condi || !reagents.total_volume)
- return
- tgui_act("modal_open", list("id" = "create_bottle", "arguments" = list("num" = answer)), ui, state)
- if("change_bottle_style")
- var/new_style = CLAMP(text2num(answer) || 0, 0, MAX_BOTTLE_SPRITE)
- if(!new_style)
- return
- bottlesprite = new_style
- else
- return FALSE
- else
- return FALSE
-
-/obj/machinery/chem_master/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state)
- if(..())
- return TRUE
-
- if(tgui_act_modal(action, params, ui, state))
- return TRUE
-
- add_fingerprint(usr)
- usr.set_machine(src)
-
- . = TRUE
- switch(action)
- if("toggle")
- mode = !mode
- if("ejectp")
- if(loaded_pill_bottle)
- loaded_pill_bottle.forceMove(get_turf(src))
- if(Adjacent(usr) && !issilicon(usr))
- usr.put_in_hands(loaded_pill_bottle)
- loaded_pill_bottle = null
- if("print")
- if(printing || condi)
- return
-
- var/idx = text2num(params["idx"]) || 0
- var/from_beaker = text2num(params["beaker"]) || FALSE
- var/reagent_list = from_beaker ? beaker.reagents.reagent_list : reagents.reagent_list
- if(idx < 1 || idx > length(reagent_list))
- return
-
- var/datum/reagent/R = reagent_list[idx]
-
- printing = TRUE
- visible_message("[src] rattles and prints out a sheet of paper.")
- // playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
-
- var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(loc)
- P.info = "Chemical Analysis
"
- P.info += "Time of analysis: [worldtime2stationtime(world.time)]
"
- P.info += "Chemical name: [R.name]
"
- if(istype(R, /datum/reagent/blood))
- var/datum/reagent/blood/B = R
- P.info += "Description: N/A
Blood Type: [B.data["blood_type"]]
DNA: [B.data["blood_DNA"]]"
- else
- P.info += "Description: [R.description]"
- P.info += "
Notes:
"
- P.name = "Chemical Analysis - [R.name]"
- spawn(50)
- printing = FALSE
- else
- . = FALSE
-
- if(. || !beaker)
- return
-
- . = TRUE
- var/datum/reagents/R = beaker.reagents
- switch(action)
- if("add")
- var/id = params["id"]
- var/amount = text2num(params["amount"])
- if(!id || !amount)
- return
- R.trans_id_to(src, id, amount)
- if("remove")
- var/id = params["id"]
- var/amount = text2num(params["amount"])
- if(!id || !amount)
- return
- if(mode)
- reagents.trans_id_to(beaker, id, amount)
- else
- reagents.remove_reagent(id, amount)
- if("eject")
- if(!beaker)
- return
- beaker.forceMove(get_turf(src))
- if(Adjacent(usr) && !issilicon(usr))
- usr.put_in_hands(beaker)
- beaker = null
- reagents.clear_reagents()
- update_icon()
- if("create_condi_bottle")
- if(!condi || !reagents.total_volume)
- return
- var/obj/item/weapon/reagent_containers/food/condiment/P = new(loc)
- reagents.trans_to_obj(P, 50)
- else
- return FALSE
-
-/obj/machinery/chem_master/attack_ai(mob/user)
- return attack_hand(user)
-
-/obj/machinery/chem_master/proc/isgoodnumber(num)
- if(isnum(num))
- if(num > 200)
- num = 200
- else if(num < 0)
- num = 1
- return num
- else
- return FALSE
-
-// /obj/machinery/chem_master/proc/chemical_safety_check(datum/reagents/R)
-// var/all_safe = TRUE
-// for(var/datum/reagent/A in R.reagent_list)
-// if(!GLOB.safe_chem_list.Find(A.id))
-// all_safe = FALSE
-// return all_safe
-
-/obj/machinery/chem_master/condimaster
- name = "CondiMaster 3000"
- condi = 1
-
-////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////
-/obj/machinery/reagentgrinder
-
- name = "All-In-One Grinder"
- desc = "Grinds stuff into itty bitty bits."
- icon = 'icons/obj/kitchen.dmi'
- icon_state = "juicer1"
- density = 0
- anchored = 0
- use_power = USE_POWER_IDLE
- idle_power_usage = 5
- active_power_usage = 100
- circuit = /obj/item/weapon/circuitboard/grinder
- var/inuse = 0
- var/obj/item/weapon/reagent_containers/beaker = null
- var/limit = 10
- var/list/holdingitems = list()
- var/list/sheet_reagents = list( //have a number of reageents divisible by REAGENTS_PER_SHEET (default 20) unless you like decimals,
- /obj/item/stack/material/iron = list("iron"),
- /obj/item/stack/material/uranium = list("uranium"),
- /obj/item/stack/material/phoron = list("phoron"),
- /obj/item/stack/material/gold = list("gold"),
- /obj/item/stack/material/silver = list("silver"),
- /obj/item/stack/material/platinum = list("platinum"),
- /obj/item/stack/material/mhydrogen = list("hydrogen"),
- /obj/item/stack/material/steel = list("iron", "carbon"),
- /obj/item/stack/material/plasteel = list("iron", "iron", "carbon", "carbon", "platinum"), //8 iron, 8 carbon, 4 platinum,
- /obj/item/stack/material/snow = list("water"),
- /obj/item/stack/material/sandstone = list("silicon", "oxygen"),
- /obj/item/stack/material/glass = list("silicon"),
- /obj/item/stack/material/glass/phoronglass = list("platinum", "silicon", "silicon", "silicon"), //5 platinum, 15 silicon,
- )
-
- var/static/radial_examine = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_examine")
- var/static/radial_eject = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_eject")
- var/static/radial_grind = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_grind")
- // var/static/radial_juice = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_juice")
- // var/static/radial_mix = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_mix")
-
-/obj/machinery/reagentgrinder/Initialize()
- . = ..()
- beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
- default_apply_parts()
-
-/obj/machinery/reagentgrinder/examine(mob/user)
- . = ..()
- if(!in_range(user, src) && !issilicon(user) && !isobserver(user))
- . += "You're too far away to examine [src]'s contents and display!"
- return
-
- if(inuse)
- . += "\The [src] is operating."
- return
-
- if(beaker || length(holdingitems))
- . += "\The [src] contains:"
- if(beaker)
- . += "- \A [beaker]."
- for(var/i in holdingitems)
- var/obj/item/O = i
- . += "- \A [O.name]."
-
- if(!(stat & (NOPOWER|BROKEN)))
- . += "The status display reads:\n"
- if(beaker)
- for(var/datum/reagent/R in beaker.reagents.reagent_list)
- . += "- [R.volume] units of [R.name]."
-
-/obj/machinery/reagentgrinder/update_icon()
- icon_state = "juicer"+num2text(!isnull(beaker))
- return
-
-/obj/machinery/reagentgrinder/attackby(var/obj/item/O as obj, var/mob/user as mob)
- if(beaker)
- if(default_deconstruction_screwdriver(user, O))
- return
- if(default_deconstruction_crowbar(user, O))
- return
-
- //vorestation edit start - for solargrubs
- if (istype(O, /obj/item/device/multitool))
- return ..()
- //vorestation edit end
-
-
- if (istype(O,/obj/item/weapon/reagent_containers/glass) || \
- istype(O,/obj/item/weapon/reagent_containers/food/drinks/glass2) || \
- istype(O,/obj/item/weapon/reagent_containers/food/drinks/shaker))
-
- if (beaker)
- return 1
- else
- src.beaker = O
- user.drop_item()
- O.loc = src
- update_icon()
- src.updateUsrDialog()
- return 0
-
- if(holdingitems && holdingitems.len >= limit)
- to_chat(user, "The machine cannot hold anymore items.")
- return 1
-
- if(!istype(O))
- return
-
- if(istype(O,/obj/item/weapon/storage/bag/plants))
- var/obj/item/weapon/storage/bag/plants/bag = O
- var/failed = 1
- for(var/obj/item/G in O.contents)
- if(!G.reagents || !G.reagents.total_volume)
- continue
- failed = 0
- bag.remove_from_storage(G, src)
- holdingitems += G
- if(holdingitems && holdingitems.len >= limit)
- break
-
- if(failed)
- to_chat(user, "Nothing in the plant bag is usable.")
- return 1
-
- if(!O.contents.len)
- to_chat(user, "You empty \the [O] into \the [src].")
- else
- to_chat(user, "You fill \the [src] from \the [O].")
-
- src.updateUsrDialog()
- return 0
-
- if(istype(O,/obj/item/weapon/gripper))
- var/obj/item/weapon/gripper/B = O //B, for Borg.
- if(!B.wrapped)
- to_chat(user, "\The [B] is not holding anything.")
- return 0
- else
- var/B_held = B.wrapped
- to_chat(user, "You use \the [B] to load \the [src] with \the [B_held].")
-
- return 0
-
- if(!sheet_reagents[O.type] && (!O.reagents || !O.reagents.total_volume))
- to_chat(user, "\The [O] is not suitable for blending.")
- return 1
-
- user.remove_from_mob(O)
- O.loc = src
- holdingitems += O
- return 0
-
-/obj/machinery/reagentgrinder/AltClick(mob/user)
- . = ..()
- if(user.incapacitated() || !Adjacent(user))
- return
- replace_beaker(user)
-
-/obj/machinery/reagentgrinder/attack_hand(mob/user as mob)
- interact(user)
-
-/obj/machinery/reagentgrinder/interact(mob/user as mob) // The microwave Menu //I am reasonably certain that this is not a microwave
- if(inuse || user.incapacitated())
- return
-
- var/list/options = list()
-
- if(beaker || length(holdingitems))
- options["eject"] = radial_eject
-
- if(isAI(user))
- if(stat & NOPOWER)
- return
- options["examine"] = radial_examine
-
- // if there is no power or it's broken, the procs will fail but the buttons will still show
- if(length(holdingitems))
- options["grind"] = radial_grind
-
- var/choice
- if(length(options) < 1)
- return
- if(length(options) == 1)
- for(var/key in options)
- choice = key
- else
- choice = show_radial_menu(user, src, options, require_near = !issilicon(user))
-
- // post choice verification
- if(inuse || (isAI(user) && stat & NOPOWER) || user.incapacitated())
- return
-
- switch(choice)
- if("eject")
- eject(user)
- if("grind")
- grind(user)
- if("examine")
- examine(user)
-
-/obj/machinery/reagentgrinder/proc/eject(mob/user)
- if(user.incapacitated())
- return
- for(var/obj/item/O in holdingitems)
- O.loc = src.loc
- holdingitems -= O
- holdingitems.Cut()
- if(beaker)
- replace_beaker(user)
-
-/obj/machinery/reagentgrinder/proc/grind()
-
- power_change()
- if(stat & (NOPOWER|BROKEN))
- return
-
- // Sanity check.
- if (!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume))
- return
-
- playsound(src, 'sound/machines/blender.ogg', 50, 1)
- inuse = 1
-
- // Reset the machine.
- spawn(60)
- inuse = 0
-
- // Process.
- for (var/obj/item/O in holdingitems)
-
- var/remaining_volume = beaker.reagents.maximum_volume - beaker.reagents.total_volume
- if(remaining_volume <= 0)
- break
-
- if(sheet_reagents[O.type])
- var/obj/item/stack/stack = O
- if(istype(stack))
- var/list/sheet_components = sheet_reagents[stack.type]
- var/amount_to_take = max(0,min(stack.amount,round(remaining_volume/REAGENTS_PER_SHEET)))
- if(amount_to_take)
- stack.use(amount_to_take)
- if(QDELETED(stack))
- holdingitems -= stack
- if(islist(sheet_components))
- amount_to_take = (amount_to_take/(sheet_components.len))
- for(var/i in sheet_components)
- beaker.reagents.add_reagent(i, (amount_to_take*REAGENTS_PER_SHEET))
- else
- beaker.reagents.add_reagent(sheet_components, (amount_to_take*REAGENTS_PER_SHEET))
- continue
-
- if(O.reagents)
- O.reagents.trans_to_obj(beaker, min(O.reagents.total_volume, remaining_volume))
- if(O.reagents.total_volume == 0)
- holdingitems -= O
- qdel(O)
- if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
- break
-
-/obj/machinery/reagentgrinder/proc/replace_beaker(mob/living/user, obj/item/weapon/reagent_containers/new_beaker)
- if(!user)
- return FALSE
- if(beaker)
- if(!user.incapacitated() && Adjacent(user))
- user.put_in_hands(beaker)
- else
- beaker.forceMove(drop_location())
- beaker = null
- if(new_beaker)
- beaker = new_beaker
- update_icon()
- return TRUE
-
-///////////////
-///////////////
-// Detects reagents inside most containers, and acts as an infinite identification system for reagent-based unidentified objects.
-
-/obj/machinery/chemical_analyzer
- name = "chem analyzer"
- desc = "Used to precisely scan chemicals and other liquids inside various containers. \
- It may also identify the liquid contents of unknown objects."
- description_info = "This machine will try to tell you what reagents are inside of something capable of holding reagents. \
- It is also used to 'identify' specific reagent-based objects with their properties obscured from inspection by normal means."
- icon = 'icons/obj/chemical.dmi'
- icon_state = "chem_analyzer"
- density = TRUE
- anchored = TRUE
- use_power = TRUE
- idle_power_usage = 20
- clicksound = "button"
- var/analyzing = FALSE
-
-/obj/machinery/chemical_analyzer/update_icon()
- icon_state = "chem_analyzer[analyzing ? "-working":""]"
-
-/obj/machinery/chemical_analyzer/attackby(obj/item/I, mob/living/user)
- if(!istype(I))
- return ..()
-
- if(default_deconstruction_screwdriver(user, I))
- return
- if(default_deconstruction_crowbar(user, I))
- return
-
- if(istype(I,/obj/item/weapon/reagent_containers))
- analyzing = TRUE
- update_icon()
- to_chat(user, span("notice", "Analyzing \the [I], please stand by..."))
-
- if(!do_after(user, 2 SECONDS, src))
- to_chat(user, span("warning", "Sample moved outside of scan range, please try again and remain still."))
- analyzing = FALSE
- update_icon()
- return
-
- // First, identify it if it isn't already.
- if(!I.is_identified(IDENTITY_FULL))
- var/datum/identification/ID = I.identity
- if(ID.identification_type == IDENTITY_TYPE_CHEMICAL) // This only solves chemical-based mysteries.
- I.identify(IDENTITY_FULL, user)
-
- // Now tell us everything that is inside.
- if(I.reagents && I.reagents.reagent_list.len)
- to_chat(user, "
") // To add padding between regular chat and the output.
- for(var/datum/reagent/R in I.reagents.reagent_list)
- if(!R.name)
- continue
- to_chat(user, span("notice", "Contains [R.volume]u of [R.name].
[R.description]
"))
-
- // Last, unseal it if it's an autoinjector.
- if(istype(I,/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector) && !(I.flags & OPENCONTAINER))
- I.flags |= OPENCONTAINER
- to_chat(user, span("notice", "Sample container unsealed.
"))
-
- to_chat(user, span("notice", "Scanning of \the [I] complete."))
- analyzing = FALSE
- update_icon()
- return
-
-#undef MAX_PILL_SPRITE
-#undef MAX_BOTTLE_SPRITE
-#undef MAX_MULTI_AMOUNT
-#undef MAX_UNITS_PER_PILL
-#undef MAX_UNITS_PER_PATCH
-#undef MAX_UNITS_PER_BOTTLE
-#undef MAX_CUSTOM_NAME_LEN
+/obj/machinery/chem_master
+ name = "ChemMaster 3000"
+ desc = "Used to seperate and package chemicals in to patches, pills, or bottles. Warranty void if used to create Space Drugs."
+ density = 1
+ anchored = 1
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "mixer0"
+ circuit = /obj/item/weapon/circuitboard/chem_master
+ use_power = USE_POWER_IDLE
+ idle_power_usage = 20
+ var/obj/item/weapon/reagent_containers/beaker = null
+ var/obj/item/weapon/storage/pill_bottle/loaded_pill_bottle = null
+ var/mode = 0
+ var/condi = 0
+ var/useramount = 15 // Last used amount
+ var/pillamount = 10
+ var/list/bottle_styles
+ var/bottlesprite = 1
+ var/pillsprite = 1
+ var/max_pill_count = 20
+ var/printing = FALSE
+ flags = OPENCONTAINER
+ clicksound = "button"
+
+/obj/machinery/chem_master/New()
+ ..()
+ var/datum/reagents/R = new/datum/reagents(900) //Just a huge random number so the buffer should (probably) never dump your reagents.
+ reagents = R //There should be a nano ui thingy to warn of this.
+ R.my_atom = src
+
+/obj/machinery/chem_master/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ qdel(src)
+ return
+ if(2.0)
+ if (prob(50))
+ qdel(src)
+ return
+
+/obj/machinery/chem_master/update_icon()
+ icon_state = "mixer[beaker ? "1" : "0"]"
+
+/obj/machinery/chem_master/attackby(var/obj/item/weapon/B as obj, var/mob/user as mob)
+
+ if(istype(B, /obj/item/weapon/reagent_containers/glass) || istype(B, /obj/item/weapon/reagent_containers/food))
+
+ if(src.beaker)
+ to_chat(user, "\A [beaker] is already loaded into the machine.")
+ return
+ src.beaker = B
+ user.drop_item()
+ B.loc = src
+ to_chat(user, "You add \the [B] to the machine.")
+ update_icon()
+
+ else if(istype(B, /obj/item/weapon/storage/pill_bottle))
+
+ if(src.loaded_pill_bottle)
+ to_chat(user, "A \the [loaded_pill_bottle] s already loaded into the machine.")
+ return
+
+ src.loaded_pill_bottle = B
+ user.drop_item()
+ B.loc = src
+ to_chat(user, "You add \the [loaded_pill_bottle] into the dispenser slot.")
+
+ else if(default_unfasten_wrench(user, B, 20))
+ return
+ if(default_deconstruction_screwdriver(user, B))
+ return
+ if(default_deconstruction_crowbar(user, B))
+ return
+
+ return
+
+/obj/machinery/chem_master/attack_hand(mob/user as mob)
+ if(stat & BROKEN)
+ return
+ user.set_machine(src)
+ tgui_interact(user)
+
+/obj/machinery/chem_master/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/chem_master),
+ )
+
+/obj/machinery/chem_master/tgui_interact(mob/user, datum/tgui/ui = null)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "ChemMaster", name)
+ ui.open()
+
+/**
+ * Display the NanoUI window for the chem master.
+ *
+ * See NanoUI documentation for details.
+ */
+/obj/machinery/chem_master/tgui_data(mob/user)
+ var/list/data = list()
+
+ data["condi"] = condi
+
+ data["loaded_pill_bottle"] = !!loaded_pill_bottle
+ if(loaded_pill_bottle)
+ data["loaded_pill_bottle_name"] = loaded_pill_bottle.name
+ data["loaded_pill_bottle_contents_len"] = loaded_pill_bottle.contents.len
+ data["loaded_pill_bottle_storage_slots"] = loaded_pill_bottle.max_storage_space
+
+ data["beaker"] = !!beaker
+ if(beaker)
+ var/list/beaker_reagents_list = list()
+ data["beaker_reagents"] = beaker_reagents_list
+ for(var/datum/reagent/R in beaker.reagents.reagent_list)
+ beaker_reagents_list[++beaker_reagents_list.len] = list("name" = R.name, "volume" = R.volume, "description" = R.description, "id" = R.id)
+
+ var/list/buffer_reagents_list = list()
+ data["buffer_reagents"] = buffer_reagents_list
+ for(var/datum/reagent/R in reagents.reagent_list)
+ buffer_reagents_list[++buffer_reagents_list.len] = list("name" = R.name, "volume" = R.volume, "id" = R.id, "description" = R.description)
+
+ data["pillsprite"] = pillsprite
+ data["bottlesprite"] = bottlesprite
+ data["mode"] = mode
+ data["printing"] = printing
+
+ // Transfer modal information if there is one
+ data["modal"] = tgui_modal_data(src)
+
+ return data
+
+/**
+ * Called in tgui_act() to process modal actions
+ *
+ * Arguments:
+ * * action - The action passed by tgui
+ * * params - The params passed by tgui
+ */
+/obj/machinery/chem_master/proc/tgui_act_modal(action, params, datum/tgui/ui, datum/tgui_state/state)
+ . = TRUE
+ var/id = params["id"] // The modal's ID
+ var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
+ switch(tgui_modal_act(src, action, params))
+ if(TGUI_MODAL_OPEN)
+ switch(id)
+ if("analyze")
+ var/idx = text2num(arguments["idx"]) || 0
+ var/from_beaker = text2num(arguments["beaker"]) || FALSE
+ var/reagent_list = from_beaker ? beaker.reagents.reagent_list : reagents.reagent_list
+ if(idx < 1 || idx > length(reagent_list))
+ return
+
+ var/datum/reagent/R = reagent_list[idx]
+ var/list/result = list("idx" = idx, "name" = R.name, "desc" = R.description)
+ if(!condi && istype(R, /datum/reagent/blood))
+ var/datum/reagent/blood/B = R
+ result["blood_type"] = B.data["blood_type"]
+ result["blood_dna"] = B.data["blood_DNA"]
+
+ arguments["analysis"] = result
+ tgui_modal_message(src, id, "", null, arguments)
+ // if("change_pill_bottle_style")
+ // if(!loaded_pill_bottle)
+ // return
+ // if(!pill_bottle_wrappers)
+ // pill_bottle_wrappers = list(
+ // "CLEAR" = "Default",
+ // COLOR_RED = "Red",
+ // COLOR_GREEN = "Green",
+ // COLOR_PALE_BTL_GREEN = "Pale green",
+ // COLOR_BLUE = "Blue",
+ // COLOR_CYAN_BLUE = "Light blue",
+ // COLOR_TEAL = "Teal",
+ // COLOR_YELLOW = "Yellow",
+ // COLOR_ORANGE = "Orange",
+ // COLOR_PINK = "Pink",
+ // COLOR_MAROON = "Brown"
+ // )
+ // var/current = pill_bottle_wrappers[loaded_pill_bottle.wrapper_color] || "Default"
+ // tgui_modal_choice(src, id, "Please select a pill bottle wrapper:", null, arguments, current, pill_bottle_wrappers)
+ if("addcustom")
+ if(!beaker || !beaker.reagents.total_volume)
+ return
+ tgui_modal_input(src, id, "Please enter the amount to transfer to buffer:", null, arguments, useramount)
+ if("removecustom")
+ if(!reagents.total_volume)
+ return
+ tgui_modal_input(src, id, "Please enter the amount to transfer to [mode ? "beaker" : "disposal"]:", null, arguments, useramount)
+ if("create_condi_pack")
+ if(!condi || !reagents.total_volume)
+ return
+ tgui_modal_input(src, id, "Please name your new condiment pack:", null, arguments, reagents.get_master_reagent_name(), MAX_CUSTOM_NAME_LEN)
+ if("create_pill")
+ if(condi || !reagents.total_volume)
+ return
+ var/num = round(text2num(arguments["num"] || 1))
+ if(!num)
+ return
+ arguments["num"] = num
+ var/amount_per_pill = CLAMP(reagents.total_volume / num, 0, MAX_UNITS_PER_PILL)
+ var/default_name = "[reagents.get_master_reagent_name()] ([amount_per_pill]u)"
+ var/pills_text = num == 1 ? "new pill" : "[num] new pills"
+ tgui_modal_input(src, id, "Please name your [pills_text]:", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
+ if("create_pill_multiple")
+ if(condi || !reagents.total_volume)
+ return
+ tgui_modal_input(src, id, "Please enter the amount of pills to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
+ if("change_pill_style")
+ var/list/choices = list()
+ for(var/i = 1 to MAX_PILL_SPRITE)
+ choices += "pill[i].png"
+ tgui_modal_bento(src, id, "Please select the new style for pills:", null, arguments, pillsprite, choices)
+ if("create_patch")
+ if(condi || !reagents.total_volume)
+ return
+ var/num = round(text2num(arguments["num"] || 1))
+ if(!num)
+ return
+ arguments["num"] = num
+ var/amount_per_patch = CLAMP(reagents.total_volume / num, 0, MAX_UNITS_PER_PATCH)
+ var/default_name = "[reagents.get_master_reagent_name()] ([amount_per_patch]u)"
+ var/patches_text = num == 1 ? "new patch" : "[num] new patches"
+ tgui_modal_input(src, id, "Please name your [patches_text]:", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
+ if("create_patch_multiple")
+ if(condi || !reagents.total_volume)
+ return
+ tgui_modal_input(src, id, "Please enter the amount of patches to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
+ if("create_bottle")
+ if(condi || !reagents.total_volume)
+ return
+ var/num = round(text2num(arguments["num"] || 1))
+ if(!num)
+ return
+ arguments["num"] = num
+ var/amount_per_bottle = CLAMP(reagents.total_volume / num, 0, MAX_UNITS_PER_BOTTLE)
+ var/default_name = "[reagents.get_master_reagent_name()]"
+ var/bottles_text = num == 1 ? "new bottle" : "[num] new bottles"
+ tgui_modal_input(src, id, "Please name your [bottles_text] ([amount_per_bottle]u in bottle):", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
+ if("create_bottle_multiple")
+ if(condi || !reagents.total_volume)
+ return
+ tgui_modal_input(src, id, "Please enter the amount of bottles to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
+ if("change_bottle_style")
+ var/list/choices = list()
+ for(var/i = 1 to MAX_BOTTLE_SPRITE)
+ choices += "bottle-[i].png"
+ tgui_modal_bento(src, id, "Please select the new style for bottles:", null, arguments, bottlesprite, choices)
+ else
+ return FALSE
+ if(TGUI_MODAL_ANSWER)
+ var/answer = params["answer"]
+ switch(id)
+ // if("change_pill_bottle_style")
+ // if(!pill_bottle_wrappers || !loaded_pill_bottle) // wat?
+ // return
+ // var/color = "CLEAR"
+ // for(var/col in pill_bottle_wrappers)
+ // var/col_name = pill_bottle_wrappers[col]
+ // if(col_name == answer)
+ // color = col
+ // break
+ // if(length(color) && color != "CLEAR")
+ // loaded_pill_bottle.wrapper_color = color
+ // loaded_pill_bottle.apply_wrap()
+ // else
+ // loaded_pill_bottle.wrapper_color = null
+ // loaded_pill_bottle.cut_overlays()
+ if("addcustom")
+ var/amount = isgoodnumber(text2num(answer))
+ if(!amount || !arguments["id"])
+ return
+ tgui_act("add", list("id" = arguments["id"], "amount" = amount), ui, state)
+ if("removecustom")
+ var/amount = isgoodnumber(text2num(answer))
+ if(!amount || !arguments["id"])
+ return
+ tgui_act("remove", list("id" = arguments["id"], "amount" = amount), ui, state)
+ if("create_condi_pack")
+ if(!condi || !reagents.total_volume)
+ return
+ if(!length(answer))
+ answer = reagents.get_master_reagent_name()
+ var/obj/item/weapon/reagent_containers/pill/P = new(loc)
+ P.name = "[answer] pack"
+ P.desc = "A small condiment pack. The label says it contains [answer]."
+ P.icon_state = "bouilloncube"//Reskinned monkey cube
+ reagents.trans_to_obj(P, 10)
+ if("create_pill")
+ if(condi || !reagents.total_volume)
+ return
+ var/count = CLAMP(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
+ if(!count)
+ return
+
+ if(!length(answer))
+ answer = reagents.get_master_reagent_name()
+ var/amount_per_pill = CLAMP(reagents.total_volume / count, 0, MAX_UNITS_PER_PILL)
+ while(count--)
+ if(reagents.total_volume <= 0)
+ to_chat(usr, "Not enough reagents to create these pills!")
+ return
+
+ var/obj/item/weapon/reagent_containers/pill/P = new(loc)
+ P.name = "[answer] pill"
+ P.pixel_x = rand(-7, 7) // Random position
+ P.pixel_y = rand(-7, 7)
+ P.icon_state = "pill[pillsprite]"
+ if(P.icon_state in list("pill1", "pill2", "pill3", "pill4")) // if using greyscale, take colour from reagent
+ P.color = reagents.get_color()
+ reagents.trans_to_obj(P, amount_per_pill)
+ // Load the pills in the bottle if there's one loaded
+ if(istype(loaded_pill_bottle) && length(loaded_pill_bottle.contents) < loaded_pill_bottle.max_storage_space)
+ P.forceMove(loaded_pill_bottle)
+ if("create_pill_multiple")
+ if(condi || !reagents.total_volume)
+ return
+ tgui_act("modal_open", list("id" = "create_pill", "arguments" = list("num" = answer)), ui, state)
+ if("change_pill_style")
+ var/new_style = CLAMP(text2num(answer) || 0, 0, MAX_PILL_SPRITE)
+ if(!new_style)
+ return
+ pillsprite = new_style
+ if("create_patch")
+ if(condi || !reagents.total_volume)
+ return
+ var/count = CLAMP(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
+ if(!count)
+ return
+
+ if(!length(answer))
+ answer = reagents.get_master_reagent_name()
+ var/amount_per_patch = CLAMP(reagents.total_volume / count, 0, MAX_UNITS_PER_PATCH)
+ // var/is_medical_patch = chemical_safety_check(reagents)
+ while(count--)
+ if(reagents.total_volume <= 0)
+ to_chat(usr, "Not enough reagents to create these patches!")
+ return
+
+ var/obj/item/weapon/reagent_containers/pill/patch/P = new(loc)
+ P.name = "[answer] patch"
+ P.pixel_x = rand(-7, 7) // random position
+ P.pixel_y = rand(-7, 7)
+ reagents.trans_to_obj(P, amount_per_patch)
+ // if(is_medical_patch)
+ // P.instant_application = TRUE
+ // P.icon_state = "bandaid_med"
+ if("create_patch_multiple")
+ if(condi || !reagents.total_volume)
+ return
+ tgui_act("modal_open", list("id" = "create_patch", "arguments" = list("num" = answer)), ui, state)
+ if("create_bottle")
+ if(condi || !reagents.total_volume)
+ return
+ var/count = CLAMP(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
+ if(!count)
+ return
+
+ if(!length(answer))
+ answer = reagents.get_master_reagent_name()
+ var/amount_per_bottle = CLAMP(reagents.total_volume / count, 0, MAX_UNITS_PER_BOTTLE)
+ while(count--)
+ if(reagents.total_volume <= 0)
+ to_chat(usr, "Not enough reagents to create these bottles!")
+ return
+ var/obj/item/weapon/reagent_containers/glass/bottle/P = new(loc)
+ P.name = "[answer] bottle"
+ P.pixel_x = rand(-7, 7) // random position
+ P.pixel_y = rand(-7, 7)
+ P.icon_state = "bottle-[bottlesprite]" || "bottle-1"
+ reagents.trans_to_obj(P, amount_per_bottle)
+ P.update_icon()
+ if("create_bottle_multiple")
+ if(condi || !reagents.total_volume)
+ return
+ tgui_act("modal_open", list("id" = "create_bottle", "arguments" = list("num" = answer)), ui, state)
+ if("change_bottle_style")
+ var/new_style = CLAMP(text2num(answer) || 0, 0, MAX_BOTTLE_SPRITE)
+ if(!new_style)
+ return
+ bottlesprite = new_style
+ else
+ return FALSE
+ else
+ return FALSE
+
+/obj/machinery/chem_master/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state)
+ if(..())
+ return TRUE
+
+ if(tgui_act_modal(action, params, ui, state))
+ return TRUE
+
+ add_fingerprint(usr)
+ usr.set_machine(src)
+
+ . = TRUE
+ switch(action)
+ if("toggle")
+ mode = !mode
+ if("ejectp")
+ if(loaded_pill_bottle)
+ loaded_pill_bottle.forceMove(get_turf(src))
+ if(Adjacent(usr) && !issilicon(usr))
+ usr.put_in_hands(loaded_pill_bottle)
+ loaded_pill_bottle = null
+ if("print")
+ if(printing || condi)
+ return
+
+ var/idx = text2num(params["idx"]) || 0
+ var/from_beaker = text2num(params["beaker"]) || FALSE
+ var/reagent_list = from_beaker ? beaker.reagents.reagent_list : reagents.reagent_list
+ if(idx < 1 || idx > length(reagent_list))
+ return
+
+ var/datum/reagent/R = reagent_list[idx]
+
+ printing = TRUE
+ visible_message("[src] rattles and prints out a sheet of paper.")
+ // playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
+
+ var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(loc)
+ P.info = "Chemical Analysis
"
+ P.info += "Time of analysis: [worldtime2stationtime(world.time)]
"
+ P.info += "Chemical name: [R.name]
"
+ if(istype(R, /datum/reagent/blood))
+ var/datum/reagent/blood/B = R
+ P.info += "Description: N/A
Blood Type: [B.data["blood_type"]]
DNA: [B.data["blood_DNA"]]"
+ else
+ P.info += "Description: [R.description]"
+ P.info += "
Notes:
"
+ P.name = "Chemical Analysis - [R.name]"
+ spawn(50)
+ printing = FALSE
+ else
+ . = FALSE
+
+ if(. || !beaker)
+ return
+
+ . = TRUE
+ var/datum/reagents/R = beaker.reagents
+ switch(action)
+ if("add")
+ var/id = params["id"]
+ var/amount = text2num(params["amount"])
+ if(!id || !amount)
+ return
+ R.trans_id_to(src, id, amount)
+ if("remove")
+ var/id = params["id"]
+ var/amount = text2num(params["amount"])
+ if(!id || !amount)
+ return
+ if(mode)
+ reagents.trans_id_to(beaker, id, amount)
+ else
+ reagents.remove_reagent(id, amount)
+ if("eject")
+ if(!beaker)
+ return
+ beaker.forceMove(get_turf(src))
+ if(Adjacent(usr) && !issilicon(usr))
+ usr.put_in_hands(beaker)
+ beaker = null
+ reagents.clear_reagents()
+ update_icon()
+ if("create_condi_bottle")
+ if(!condi || !reagents.total_volume)
+ return
+ var/obj/item/weapon/reagent_containers/food/condiment/P = new(loc)
+ reagents.trans_to_obj(P, 50)
+ else
+ return FALSE
+
+/obj/machinery/chem_master/attack_ai(mob/user)
+ return attack_hand(user)
+
+/obj/machinery/chem_master/proc/isgoodnumber(num)
+ if(isnum(num))
+ if(num > 200)
+ num = 200
+ else if(num < 0)
+ num = 1
+ return num
+ else
+ return FALSE
+
+// /obj/machinery/chem_master/proc/chemical_safety_check(datum/reagents/R)
+// var/all_safe = TRUE
+// for(var/datum/reagent/A in R.reagent_list)
+// if(!GLOB.safe_chem_list.Find(A.id))
+// all_safe = FALSE
+// return all_safe
+
+/obj/machinery/chem_master/condimaster
+ name = "CondiMaster 3000"
+ condi = 1
diff --git a/code/modules/reagents/Chemistry-Machinery_vr.dm b/code/modules/reagents/machinery/chem_master_vr.dm
similarity index 100%
rename from code/modules/reagents/Chemistry-Machinery_vr.dm
rename to code/modules/reagents/machinery/chem_master_vr.dm
diff --git a/code/modules/reagents/machinery/chemalyzer.dm b/code/modules/reagents/machinery/chemalyzer.dm
new file mode 100644
index 00000000000..ce8b1d6f12d
--- /dev/null
+++ b/code/modules/reagents/machinery/chemalyzer.dm
@@ -0,0 +1,63 @@
+// Detects reagents inside most containers, and acts as an infinite identification system for reagent-based unidentified objects.
+
+/obj/machinery/chemical_analyzer
+ name = "chem analyzer"
+ desc = "Used to precisely scan chemicals and other liquids inside various containers. \
+ It may also identify the liquid contents of unknown objects."
+ description_info = "This machine will try to tell you what reagents are inside of something capable of holding reagents. \
+ It is also used to 'identify' specific reagent-based objects with their properties obscured from inspection by normal means."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "chem_analyzer"
+ density = TRUE
+ anchored = TRUE
+ use_power = TRUE
+ idle_power_usage = 20
+ clicksound = "button"
+ var/analyzing = FALSE
+
+/obj/machinery/chemical_analyzer/update_icon()
+ icon_state = "chem_analyzer[analyzing ? "-working":""]"
+
+/obj/machinery/chemical_analyzer/attackby(obj/item/I, mob/living/user)
+ if(!istype(I))
+ return ..()
+
+ if(default_deconstruction_screwdriver(user, I))
+ return
+ if(default_deconstruction_crowbar(user, I))
+ return
+
+ if(istype(I,/obj/item/weapon/reagent_containers))
+ analyzing = TRUE
+ update_icon()
+ to_chat(user, span("notice", "Analyzing \the [I], please stand by..."))
+
+ if(!do_after(user, 2 SECONDS, src))
+ to_chat(user, span("warning", "Sample moved outside of scan range, please try again and remain still."))
+ analyzing = FALSE
+ update_icon()
+ return
+
+ // First, identify it if it isn't already.
+ if(!I.is_identified(IDENTITY_FULL))
+ var/datum/identification/ID = I.identity
+ if(ID.identification_type == IDENTITY_TYPE_CHEMICAL) // This only solves chemical-based mysteries.
+ I.identify(IDENTITY_FULL, user)
+
+ // Now tell us everything that is inside.
+ if(I.reagents && I.reagents.reagent_list.len)
+ to_chat(user, "
") // To add padding between regular chat and the output.
+ for(var/datum/reagent/R in I.reagents.reagent_list)
+ if(!R.name)
+ continue
+ to_chat(user, span("notice", "Contains [R.volume]u of [R.name].
[R.description]
"))
+
+ // Last, unseal it if it's an autoinjector.
+ if(istype(I,/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector) && !(I.flags & OPENCONTAINER))
+ I.flags |= OPENCONTAINER
+ to_chat(user, span("notice", "Sample container unsealed.
"))
+
+ to_chat(user, span("notice", "Scanning of \the [I] complete."))
+ analyzing = FALSE
+ update_icon()
+ return
\ No newline at end of file
diff --git a/code/modules/reagents/dispenser/_defines.dm b/code/modules/reagents/machinery/dispenser/_defines.dm
similarity index 96%
rename from code/modules/reagents/dispenser/_defines.dm
rename to code/modules/reagents/machinery/dispenser/_defines.dm
index 60c12cdba66..8d52cf5cd07 100644
--- a/code/modules/reagents/dispenser/_defines.dm
+++ b/code/modules/reagents/machinery/dispenser/_defines.dm
@@ -1,8 +1,8 @@
-#define CARTRIDGE_VOLUME_LARGE 500
-#define CARTRIDGE_VOLUME_MEDIUM 250
-#define CARTRIDGE_VOLUME_SMALL 100
-
-// Chemistry dispenser starts with 21
-// ERT dispenser starts with 28
-#define DISPENSER_MAX_CARTRIDGES 30
-
+#define CARTRIDGE_VOLUME_LARGE 500
+#define CARTRIDGE_VOLUME_MEDIUM 250
+#define CARTRIDGE_VOLUME_SMALL 100
+
+// Chemistry dispenser starts with 21
+// ERT dispenser starts with 28
+#define DISPENSER_MAX_CARTRIDGES 30
+
diff --git a/code/modules/reagents/dispenser/cartridge.dm b/code/modules/reagents/machinery/dispenser/cartridge.dm
similarity index 97%
rename from code/modules/reagents/dispenser/cartridge.dm
rename to code/modules/reagents/machinery/dispenser/cartridge.dm
index 444577aaa51..0e2b09eb575 100644
--- a/code/modules/reagents/dispenser/cartridge.dm
+++ b/code/modules/reagents/machinery/dispenser/cartridge.dm
@@ -1,95 +1,95 @@
-/obj/item/weapon/reagent_containers/chem_disp_cartridge
- name = "chemical dispenser cartridge"
- desc = "This goes in a chemical dispenser."
- icon_state = "cartridge"
-
- w_class = ITEMSIZE_NORMAL
-
- volume = CARTRIDGE_VOLUME_LARGE
- amount_per_transfer_from_this = 50
- // Large, but inaccurate. Use a chem dispenser or beaker for accuracy.
- possible_transfer_amounts = list(50, 100, 250, 500)
- unacidable = 1
-
- var/spawn_reagent = null
- var/label = ""
-
-/obj/item/weapon/reagent_containers/chem_disp_cartridge/Initialize()
- . = ..()
- if(spawn_reagent)
- reagents.add_reagent(spawn_reagent, volume)
- var/datum/reagent/R = SSchemistry.chemical_reagents[spawn_reagent]
- setLabel(R.name)
-
-/obj/item/weapon/reagent_containers/chem_disp_cartridge/examine(mob/user)
- . = ..()
- . += "It has a capacity of [volume] units."
- if(reagents.total_volume <= 0)
- . += "It is empty."
- else
- . += "It contains [reagents.total_volume] units of liquid."
- if(!is_open_container())
- . += "The cap is sealed."
-
-/obj/item/weapon/reagent_containers/chem_disp_cartridge/verb/verb_set_label(L as text)
- set name = "Set Cartridge Label"
- set category = "Object"
- set src in view(usr, 1)
-
- setLabel(L, usr)
-
-/obj/item/weapon/reagent_containers/chem_disp_cartridge/proc/setLabel(L, mob/user = null)
- if(L)
- if(user)
- to_chat(user, "You set the label on \the [src] to '[L]'.")
-
- label = L
- name = "[initial(name)] - '[L]'"
- else
- if(user)
- to_chat(user, "You clear the label on \the [src].")
- label = ""
- name = initial(name)
-
-/obj/item/weapon/reagent_containers/chem_disp_cartridge/attack_self()
- ..()
- if (is_open_container())
- to_chat(usr, "You put the cap on \the [src].")
- flags ^= OPENCONTAINER
- else
- to_chat(usr, "You take the cap off \the [src].")
- flags |= OPENCONTAINER
-
-/obj/item/weapon/reagent_containers/chem_disp_cartridge/afterattack(obj/target, mob/user , flag)
- if (!is_open_container() || !flag)
- return
-
- else if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us.
- target.add_fingerprint(user)
-
- if(!target.reagents.total_volume && target.reagents)
- to_chat(user, "\The [target] is empty.")
- return
-
- if(reagents.total_volume >= reagents.maximum_volume)
- to_chat(user, "\The [src] is full.")
- return
-
- var/trans = target.reagents.trans_to(src, target:amount_per_transfer_from_this)
- to_chat(user, "You fill \the [src] with [trans] units of the contents of \the [target].")
-
- else if(target.is_open_container() && target.reagents) //Something like a glass. Player probably wants to transfer TO it.
-
- if(!reagents.total_volume)
- to_chat(user, "\The [src] is empty.")
- return
-
- if(target.reagents.total_volume >= target.reagents.maximum_volume)
- to_chat(user, "\The [target] is full.")
- return
-
- var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this)
- to_chat(user, "You transfer [trans] units of the solution to \the [target].")
-
- else
- return ..()
+/obj/item/weapon/reagent_containers/chem_disp_cartridge
+ name = "chemical dispenser cartridge"
+ desc = "This goes in a chemical dispenser."
+ icon_state = "cartridge"
+
+ w_class = ITEMSIZE_NORMAL
+
+ volume = CARTRIDGE_VOLUME_LARGE
+ amount_per_transfer_from_this = 50
+ // Large, but inaccurate. Use a chem dispenser or beaker for accuracy.
+ possible_transfer_amounts = list(50, 100, 250, 500)
+ unacidable = 1
+
+ var/spawn_reagent = null
+ var/label = ""
+
+/obj/item/weapon/reagent_containers/chem_disp_cartridge/Initialize()
+ . = ..()
+ if(spawn_reagent)
+ reagents.add_reagent(spawn_reagent, volume)
+ var/datum/reagent/R = SSchemistry.chemical_reagents[spawn_reagent]
+ setLabel(R.name)
+
+/obj/item/weapon/reagent_containers/chem_disp_cartridge/examine(mob/user)
+ . = ..()
+ . += "It has a capacity of [volume] units."
+ if(reagents.total_volume <= 0)
+ . += "It is empty."
+ else
+ . += "It contains [reagents.total_volume] units of liquid."
+ if(!is_open_container())
+ . += "The cap is sealed."
+
+/obj/item/weapon/reagent_containers/chem_disp_cartridge/verb/verb_set_label(L as text)
+ set name = "Set Cartridge Label"
+ set category = "Object"
+ set src in view(usr, 1)
+
+ setLabel(L, usr)
+
+/obj/item/weapon/reagent_containers/chem_disp_cartridge/proc/setLabel(L, mob/user = null)
+ if(L)
+ if(user)
+ to_chat(user, "You set the label on \the [src] to '[L]'.")
+
+ label = L
+ name = "[initial(name)] - '[L]'"
+ else
+ if(user)
+ to_chat(user, "You clear the label on \the [src].")
+ label = ""
+ name = initial(name)
+
+/obj/item/weapon/reagent_containers/chem_disp_cartridge/attack_self()
+ ..()
+ if (is_open_container())
+ to_chat(usr, "You put the cap on \the [src].")
+ flags ^= OPENCONTAINER
+ else
+ to_chat(usr, "You take the cap off \the [src].")
+ flags |= OPENCONTAINER
+
+/obj/item/weapon/reagent_containers/chem_disp_cartridge/afterattack(obj/target, mob/user , flag)
+ if (!is_open_container() || !flag)
+ return
+
+ else if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us.
+ target.add_fingerprint(user)
+
+ if(!target.reagents.total_volume && target.reagents)
+ to_chat(user, "\The [target] is empty.")
+ return
+
+ if(reagents.total_volume >= reagents.maximum_volume)
+ to_chat(user, "\The [src] is full.")
+ return
+
+ var/trans = target.reagents.trans_to(src, target:amount_per_transfer_from_this)
+ to_chat(user, "You fill \the [src] with [trans] units of the contents of \the [target].")
+
+ else if(target.is_open_container() && target.reagents) //Something like a glass. Player probably wants to transfer TO it.
+
+ if(!reagents.total_volume)
+ to_chat(user, "\The [src] is empty.")
+ return
+
+ if(target.reagents.total_volume >= target.reagents.maximum_volume)
+ to_chat(user, "\The [target] is full.")
+ return
+
+ var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this)
+ to_chat(user, "You transfer [trans] units of the solution to \the [target].")
+
+ else
+ return ..()
diff --git a/code/modules/reagents/dispenser/cartridge_presets.dm b/code/modules/reagents/machinery/dispenser/cartridge_presets.dm
similarity index 97%
rename from code/modules/reagents/dispenser/cartridge_presets.dm
rename to code/modules/reagents/machinery/dispenser/cartridge_presets.dm
index eea22fff7ea..21b321ad34d 100644
--- a/code/modules/reagents/dispenser/cartridge_presets.dm
+++ b/code/modules/reagents/machinery/dispenser/cartridge_presets.dm
@@ -1,108 +1,108 @@
-/obj/item/weapon/reagent_containers/chem_disp_cartridge
- small
- volume = CARTRIDGE_VOLUME_SMALL
-
- medium
- volume = CARTRIDGE_VOLUME_MEDIUM
-
- // Multiple
- water spawn_reagent = "water"
- sugar spawn_reagent = "sugar"
-
- // Chemistry
- hydrogen spawn_reagent = "hydrogen"
- lithium spawn_reagent = "lithium"
- carbon spawn_reagent = "carbon"
- nitrogen spawn_reagent = "nitrogen"
- oxygen spawn_reagent = "oxygen"
- fluorine spawn_reagent = "fluorine"
- sodium spawn_reagent = "sodium"
- aluminum spawn_reagent = "aluminum"
- silicon spawn_reagent = "silicon"
- phosphorus spawn_reagent = "phosphorus"
- sulfur spawn_reagent = "sulfur"
- chlorine spawn_reagent = "chlorine"
- potassium spawn_reagent = "potassium"
- iron spawn_reagent = "iron"
- copper spawn_reagent = "copper"
- mercury spawn_reagent = "mercury"
- radium spawn_reagent = "radium"
- ethanol spawn_reagent = "ethanol"
- sacid spawn_reagent = "sacid"
- tungsten spawn_reagent = "tungsten"
- calcium spawn_reagent = "calcium"
-
- // Bar, alcoholic
- beer spawn_reagent = "beer"
- kahlua spawn_reagent = "kahlua"
- whiskey spawn_reagent = "whiskey"
- wine spawn_reagent = "wine"
- vodka spawn_reagent = "vodka"
- gin spawn_reagent = "gin"
- rum spawn_reagent = "rum"
- tequila spawn_reagent = "tequilla"
- vermouth spawn_reagent = "vermouth"
- cognac spawn_reagent = "cognac"
- ale spawn_reagent = "ale"
- mead spawn_reagent = "mead"
- bitters spawn_reagent = "bitters"
- cider spawn_reagent = "cider"
-
- // Bar, soft
- ice spawn_reagent = "ice"
- tea spawn_reagent = "tea"
- icetea spawn_reagent = "icetea"
- cola spawn_reagent = "cola"
- smw spawn_reagent = "spacemountainwind"
- dr_gibb spawn_reagent = "dr_gibb"
- spaceup spawn_reagent = "space_up"
- tonic spawn_reagent = "tonic"
- sodawater spawn_reagent = "sodawater"
- lemon_lime spawn_reagent = "lemon_lime"
- orange spawn_reagent = "orangejuice"
- lime spawn_reagent = "limejuice"
- watermelon spawn_reagent = "watermelonjuice"
- lemon spawn_reagent = "lemonjuice"
-
- // Bar, coffee
- coffee spawn_reagent = "coffee"
- cafe_latte spawn_reagent = "cafe_latte"
- soy_latte spawn_reagent = "soy_latte"
- hot_coco spawn_reagent = "hot_coco"
- milk spawn_reagent = "milk"
- cream spawn_reagent = "cream"
- mint spawn_reagent = "mint"
- berry spawn_reagent = "berryjuice"
- greentea spawn_reagent = "greentea"
- decaf spawn_reagent = "decaf"
-
- // ERT
- inaprov spawn_reagent = "inaprovaline"
- ryetalyn spawn_reagent = "ryetalyn"
- paracetamol spawn_reagent = "paracetamol"
- tramadol spawn_reagent = "tramadol"
- oxycodone spawn_reagent = "oxycodone"
- sterilizine spawn_reagent = "sterilizine"
- leporazine spawn_reagent = "leporazine"
- kelotane spawn_reagent = "kelotane"
- dermaline spawn_reagent = "dermaline"
- dexalin spawn_reagent = "dexalin"
- dexalin/small volume = CARTRIDGE_VOLUME_SMALL // For the medicine cartridge crate, so it's not too easy to get large amounts of dexalin
- dexalin_p spawn_reagent = "dexalinp"
- tricord spawn_reagent = "tricordrazine"
- dylovene spawn_reagent = "anti_toxin"
- synaptizine spawn_reagent = "synaptizine"
- hyronalin spawn_reagent = "hyronalin"
- arithrazine spawn_reagent = "arithrazine"
- alkysine spawn_reagent = "alkysine"
- imidazoline spawn_reagent = "imidazoline"
- peridaxon spawn_reagent = "peridaxon"
- bicaridine spawn_reagent = "bicaridine"
- hyperzine spawn_reagent = "hyperzine"
- rezadone spawn_reagent = "rezadone"
- spaceacillin spawn_reagent = "spaceacillin"
- ethylredox spawn_reagent = "ethylredoxrazine"
- sleeptox spawn_reagent = "stoxin"
- chloral spawn_reagent = "chloralhydrate"
- cryoxadone spawn_reagent = "cryoxadone"
- clonexadone spawn_reagent = "clonexadone"
+/obj/item/weapon/reagent_containers/chem_disp_cartridge
+ small
+ volume = CARTRIDGE_VOLUME_SMALL
+
+ medium
+ volume = CARTRIDGE_VOLUME_MEDIUM
+
+ // Multiple
+ water spawn_reagent = "water"
+ sugar spawn_reagent = "sugar"
+
+ // Chemistry
+ hydrogen spawn_reagent = "hydrogen"
+ lithium spawn_reagent = "lithium"
+ carbon spawn_reagent = "carbon"
+ nitrogen spawn_reagent = "nitrogen"
+ oxygen spawn_reagent = "oxygen"
+ fluorine spawn_reagent = "fluorine"
+ sodium spawn_reagent = "sodium"
+ aluminum spawn_reagent = "aluminum"
+ silicon spawn_reagent = "silicon"
+ phosphorus spawn_reagent = "phosphorus"
+ sulfur spawn_reagent = "sulfur"
+ chlorine spawn_reagent = "chlorine"
+ potassium spawn_reagent = "potassium"
+ iron spawn_reagent = "iron"
+ copper spawn_reagent = "copper"
+ mercury spawn_reagent = "mercury"
+ radium spawn_reagent = "radium"
+ ethanol spawn_reagent = "ethanol"
+ sacid spawn_reagent = "sacid"
+ tungsten spawn_reagent = "tungsten"
+ calcium spawn_reagent = "calcium"
+
+ // Bar, alcoholic
+ beer spawn_reagent = "beer"
+ kahlua spawn_reagent = "kahlua"
+ whiskey spawn_reagent = "whiskey"
+ wine spawn_reagent = "wine"
+ vodka spawn_reagent = "vodka"
+ gin spawn_reagent = "gin"
+ rum spawn_reagent = "rum"
+ tequila spawn_reagent = "tequilla"
+ vermouth spawn_reagent = "vermouth"
+ cognac spawn_reagent = "cognac"
+ ale spawn_reagent = "ale"
+ mead spawn_reagent = "mead"
+ bitters spawn_reagent = "bitters"
+ cider spawn_reagent = "cider"
+
+ // Bar, soft
+ ice spawn_reagent = "ice"
+ tea spawn_reagent = "tea"
+ icetea spawn_reagent = "icetea"
+ cola spawn_reagent = "cola"
+ smw spawn_reagent = "spacemountainwind"
+ dr_gibb spawn_reagent = "dr_gibb"
+ spaceup spawn_reagent = "space_up"
+ tonic spawn_reagent = "tonic"
+ sodawater spawn_reagent = "sodawater"
+ lemon_lime spawn_reagent = "lemon_lime"
+ orange spawn_reagent = "orangejuice"
+ lime spawn_reagent = "limejuice"
+ watermelon spawn_reagent = "watermelonjuice"
+ lemon spawn_reagent = "lemonjuice"
+
+ // Bar, coffee
+ coffee spawn_reagent = "coffee"
+ cafe_latte spawn_reagent = "cafe_latte"
+ soy_latte spawn_reagent = "soy_latte"
+ hot_coco spawn_reagent = "hot_coco"
+ milk spawn_reagent = "milk"
+ cream spawn_reagent = "cream"
+ mint spawn_reagent = "mint"
+ berry spawn_reagent = "berryjuice"
+ greentea spawn_reagent = "greentea"
+ decaf spawn_reagent = "decaf"
+
+ // ERT
+ inaprov spawn_reagent = "inaprovaline"
+ ryetalyn spawn_reagent = "ryetalyn"
+ paracetamol spawn_reagent = "paracetamol"
+ tramadol spawn_reagent = "tramadol"
+ oxycodone spawn_reagent = "oxycodone"
+ sterilizine spawn_reagent = "sterilizine"
+ leporazine spawn_reagent = "leporazine"
+ kelotane spawn_reagent = "kelotane"
+ dermaline spawn_reagent = "dermaline"
+ dexalin spawn_reagent = "dexalin"
+ dexalin/small volume = CARTRIDGE_VOLUME_SMALL // For the medicine cartridge crate, so it's not too easy to get large amounts of dexalin
+ dexalin_p spawn_reagent = "dexalinp"
+ tricord spawn_reagent = "tricordrazine"
+ dylovene spawn_reagent = "anti_toxin"
+ synaptizine spawn_reagent = "synaptizine"
+ hyronalin spawn_reagent = "hyronalin"
+ arithrazine spawn_reagent = "arithrazine"
+ alkysine spawn_reagent = "alkysine"
+ imidazoline spawn_reagent = "imidazoline"
+ peridaxon spawn_reagent = "peridaxon"
+ bicaridine spawn_reagent = "bicaridine"
+ hyperzine spawn_reagent = "hyperzine"
+ rezadone spawn_reagent = "rezadone"
+ spaceacillin spawn_reagent = "spaceacillin"
+ ethylredox spawn_reagent = "ethylredoxrazine"
+ sleeptox spawn_reagent = "stoxin"
+ chloral spawn_reagent = "chloralhydrate"
+ cryoxadone spawn_reagent = "cryoxadone"
+ clonexadone spawn_reagent = "clonexadone"
diff --git a/code/modules/reagents/dispenser/cartridge_presets_vr.dm b/code/modules/reagents/machinery/dispenser/cartridge_presets_vr.dm
similarity index 100%
rename from code/modules/reagents/dispenser/cartridge_presets_vr.dm
rename to code/modules/reagents/machinery/dispenser/cartridge_presets_vr.dm
diff --git a/code/modules/reagents/dispenser/cartridge_spawn.dm b/code/modules/reagents/machinery/dispenser/cartridge_spawn.dm
similarity index 100%
rename from code/modules/reagents/dispenser/cartridge_spawn.dm
rename to code/modules/reagents/machinery/dispenser/cartridge_spawn.dm
diff --git a/code/modules/reagents/dispenser/dispenser2.dm b/code/modules/reagents/machinery/dispenser/dispenser2.dm
similarity index 97%
rename from code/modules/reagents/dispenser/dispenser2.dm
rename to code/modules/reagents/machinery/dispenser/dispenser2.dm
index 7f2fb13f404..d53dac4ba53 100644
--- a/code/modules/reagents/dispenser/dispenser2.dm
+++ b/code/modules/reagents/machinery/dispenser/dispenser2.dm
@@ -1,205 +1,205 @@
-/obj/machinery/chemical_dispenser
- name = "chemical dispenser"
- desc = "Automagically fabricates chemicals from electricity."
- icon = 'icons/obj/chemical.dmi'
- icon_state = "dispenser"
- clicksound = "switch"
-
- var/list/spawn_cartridges = null // Set to a list of types to spawn one of each on New()
-
- var/list/cartridges = list() // Associative, label -> cartridge
- var/obj/item/weapon/reagent_containers/container = null
-
- var/ui_title = "Chemical Dispenser"
-
- var/accept_drinking = 0
- var/amount = 30
-
- use_power = USE_POWER_IDLE
- idle_power_usage = 100
- anchored = 1
-
-/obj/machinery/chemical_dispenser/Initialize()
- . = ..()
- if(spawn_cartridges)
- for(var/type in spawn_cartridges)
- add_cartridge(new type(src))
-
-/obj/machinery/chemical_dispenser/examine(mob/user)
- . = ..()
- . += "It has [cartridges.len] cartridges installed, and has space for [DISPENSER_MAX_CARTRIDGES - cartridges.len] more."
-
-/obj/machinery/chemical_dispenser/verb/rotate_clockwise()
- set name = "Rotate Dispenser Clockwise"
- set category = "Object"
- set src in oview(1)
-
- if (src.anchored || usr:stat)
- to_chat(usr, "It is fastened down!")
- return 0
- src.set_dir(turn(src.dir, 270))
- return 1
-
-/obj/machinery/chemical_dispenser/proc/add_cartridge(obj/item/weapon/reagent_containers/chem_disp_cartridge/C, mob/user)
- if(!istype(C))
- if(user)
- to_chat(user, "\The [C] will not fit in \the [src]!")
- return
-
- if(cartridges.len >= DISPENSER_MAX_CARTRIDGES)
- if(user)
- to_chat(user, "\The [src] does not have any slots open for \the [C] to fit into!")
- return
-
- if(!C.label)
- if(user)
- to_chat(user, "\The [C] does not have a label!")
- return
-
- if(cartridges[C.label])
- if(user)
- to_chat(user, "\The [src] already contains a cartridge with that label!")
- return
-
- if(user)
- user.drop_from_inventory(C)
- to_chat(user, "You add \the [C] to \the [src].")
-
- C.loc = src
- cartridges[C.label] = C
- cartridges = sortAssoc(cartridges)
- SStgui.update_uis(src)
-
-/obj/machinery/chemical_dispenser/proc/remove_cartridge(label)
- . = cartridges[label]
- cartridges -= label
- SStgui.update_uis(src)
-
-/obj/machinery/chemical_dispenser/attackby(obj/item/weapon/W, mob/user)
- if(W.is_wrench())
- playsound(src, W.usesound, 50, 1)
- to_chat(user, "You begin to [anchored ? "un" : ""]fasten \the [src].")
- if (do_after(user, 20 * W.toolspeed))
- user.visible_message(
- "\The [user] [anchored ? "un" : ""]fastens \the [src].",
- "You have [anchored ? "un" : ""]fastened \the [src].",
- "You hear a ratchet.")
- anchored = !anchored
- else
- to_chat(user, "You decide not to [anchored ? "un" : ""]fasten \the [src].")
-
- else if(istype(W, /obj/item/weapon/reagent_containers/chem_disp_cartridge))
- add_cartridge(W, user)
-
- else if(W.is_screwdriver())
- var/label = input(user, "Which cartridge would you like to remove?", "Chemical Dispenser") as null|anything in cartridges
- if(!label) return
- var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = remove_cartridge(label)
- if(C)
- to_chat(user, "You remove \the [C] from \the [src].")
- C.loc = loc
- playsound(src, W.usesound, 50, 1)
-
- else if(istype(W, /obj/item/weapon/reagent_containers/glass) || istype(W, /obj/item/weapon/reagent_containers/food))
- if(container)
- to_chat(user, "There is already \a [container] on \the [src]!")
- return
-
- var/obj/item/weapon/reagent_containers/RC = W
-
- if(!accept_drinking && istype(RC,/obj/item/weapon/reagent_containers/food))
- to_chat(user, "This machine only accepts beakers!")
- return
-
- if(!RC.is_open_container())
- to_chat(user, "You don't see how \the [src] could dispense reagents into \the [RC].")
- return
-
- container = RC
- user.drop_from_inventory(RC)
- RC.loc = src
- to_chat(user, "You set \the [RC] on \the [src].")
- else
- return ..()
-
-/obj/machinery/chemical_dispenser/tgui_interact(mob/user, datum/tgui/ui = null)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "ChemDispenser", ui_title) // 390, 655
- ui.open()
-
-/obj/machinery/chemical_dispenser/tgui_data(mob/user)
- var/data[0]
- data["amount"] = amount
- data["isBeakerLoaded"] = container ? 1 : 0
- data["glass"] = accept_drinking
-
- var/beakerContents[0]
- if(container && container.reagents && container.reagents.reagent_list.len)
- for(var/datum/reagent/R in container.reagents.reagent_list)
- beakerContents.Add(list(list("name" = R.name, "id" = R.id, "volume" = R.volume))) // list in a list because Byond merges the first list...
- data["beakerContents"] = beakerContents
-
- if(container)
- data["beakerCurrentVolume"] = container.reagents.total_volume
- data["beakerMaxVolume"] = container.reagents.maximum_volume
- else
- data["beakerCurrentVolume"] = null
- data["beakerMaxVolume"] = null
-
- var/chemicals[0]
- for(var/label in cartridges)
- var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = cartridges[label]
- chemicals.Add(list(list("title" = label, "id" = label, "amount" = C.reagents.total_volume))) // list in a list because Byond merges the first list...
- data["chemicals"] = chemicals
- return data
-
-/obj/machinery/chemical_dispenser/tgui_act(action, params)
- if(..())
- return TRUE
-
- . = TRUE
- switch(action)
- if("amount")
- amount = clamp(round(text2num(params["amount"]), 1), 0, 120) // round to nearest 1 and clamp 0 - 120
- if("dispense")
- var/label = params["reagent"]
- if(cartridges[label] && container && container.is_open_container())
- var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = cartridges[label]
- playsound(src, 'sound/machines/reagent_dispense.ogg', 25, 1)
- C.reagents.trans_to(container, amount)
- if("remove")
- var/amount = text2num(params["amount"])
- if(!container || !amount)
- return
- var/datum/reagents/R = container.reagents
- var/id = params["reagent"]
- if(amount > 0)
- R.remove_reagent(id, amount)
- else if(amount == -1) // Isolate
- R.isolate_reagent(id)
- if("ejectBeaker")
- if(container)
- container.forceMove(get_turf(src))
-
- if(Adjacent(usr)) // So the AI doesn't get a beaker somehow.
- usr.put_in_hands(container)
-
- container = null
- else
- return FALSE
-
- add_fingerprint(usr)
-
-/obj/machinery/chemical_dispenser/attack_ghost(mob/user)
- if(stat & BROKEN)
- return
- tgui_interact(user)
-
-/obj/machinery/chemical_dispenser/attack_ai(mob/user)
- attack_hand(user)
-
-/obj/machinery/chemical_dispenser/attack_hand(mob/user)
- if(stat & BROKEN)
- return
- tgui_interact(user)
+/obj/machinery/chemical_dispenser
+ name = "chemical dispenser"
+ desc = "Automagically fabricates chemicals from electricity."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "dispenser"
+ clicksound = "switch"
+
+ var/list/spawn_cartridges = null // Set to a list of types to spawn one of each on New()
+
+ var/list/cartridges = list() // Associative, label -> cartridge
+ var/obj/item/weapon/reagent_containers/container = null
+
+ var/ui_title = "Chemical Dispenser"
+
+ var/accept_drinking = 0
+ var/amount = 30
+
+ use_power = USE_POWER_IDLE
+ idle_power_usage = 100
+ anchored = 1
+
+/obj/machinery/chemical_dispenser/Initialize()
+ . = ..()
+ if(spawn_cartridges)
+ for(var/type in spawn_cartridges)
+ add_cartridge(new type(src))
+
+/obj/machinery/chemical_dispenser/examine(mob/user)
+ . = ..()
+ . += "It has [cartridges.len] cartridges installed, and has space for [DISPENSER_MAX_CARTRIDGES - cartridges.len] more."
+
+/obj/machinery/chemical_dispenser/verb/rotate_clockwise()
+ set name = "Rotate Dispenser Clockwise"
+ set category = "Object"
+ set src in oview(1)
+
+ if (src.anchored || usr:stat)
+ to_chat(usr, "It is fastened down!")
+ return 0
+ src.set_dir(turn(src.dir, 270))
+ return 1
+
+/obj/machinery/chemical_dispenser/proc/add_cartridge(obj/item/weapon/reagent_containers/chem_disp_cartridge/C, mob/user)
+ if(!istype(C))
+ if(user)
+ to_chat(user, "\The [C] will not fit in \the [src]!")
+ return
+
+ if(cartridges.len >= DISPENSER_MAX_CARTRIDGES)
+ if(user)
+ to_chat(user, "\The [src] does not have any slots open for \the [C] to fit into!")
+ return
+
+ if(!C.label)
+ if(user)
+ to_chat(user, "\The [C] does not have a label!")
+ return
+
+ if(cartridges[C.label])
+ if(user)
+ to_chat(user, "\The [src] already contains a cartridge with that label!")
+ return
+
+ if(user)
+ user.drop_from_inventory(C)
+ to_chat(user, "You add \the [C] to \the [src].")
+
+ C.loc = src
+ cartridges[C.label] = C
+ cartridges = sortAssoc(cartridges)
+ SStgui.update_uis(src)
+
+/obj/machinery/chemical_dispenser/proc/remove_cartridge(label)
+ . = cartridges[label]
+ cartridges -= label
+ SStgui.update_uis(src)
+
+/obj/machinery/chemical_dispenser/attackby(obj/item/weapon/W, mob/user)
+ if(W.is_wrench())
+ playsound(src, W.usesound, 50, 1)
+ to_chat(user, "You begin to [anchored ? "un" : ""]fasten \the [src].")
+ if (do_after(user, 20 * W.toolspeed))
+ user.visible_message(
+ "\The [user] [anchored ? "un" : ""]fastens \the [src].",
+ "You have [anchored ? "un" : ""]fastened \the [src].",
+ "You hear a ratchet.")
+ anchored = !anchored
+ else
+ to_chat(user, "You decide not to [anchored ? "un" : ""]fasten \the [src].")
+
+ else if(istype(W, /obj/item/weapon/reagent_containers/chem_disp_cartridge))
+ add_cartridge(W, user)
+
+ else if(W.is_screwdriver())
+ var/label = input(user, "Which cartridge would you like to remove?", "Chemical Dispenser") as null|anything in cartridges
+ if(!label) return
+ var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = remove_cartridge(label)
+ if(C)
+ to_chat(user, "You remove \the [C] from \the [src].")
+ C.loc = loc
+ playsound(src, W.usesound, 50, 1)
+
+ else if(istype(W, /obj/item/weapon/reagent_containers/glass) || istype(W, /obj/item/weapon/reagent_containers/food))
+ if(container)
+ to_chat(user, "There is already \a [container] on \the [src]!")
+ return
+
+ var/obj/item/weapon/reagent_containers/RC = W
+
+ if(!accept_drinking && istype(RC,/obj/item/weapon/reagent_containers/food))
+ to_chat(user, "This machine only accepts beakers!")
+ return
+
+ if(!RC.is_open_container())
+ to_chat(user, "You don't see how \the [src] could dispense reagents into \the [RC].")
+ return
+
+ container = RC
+ user.drop_from_inventory(RC)
+ RC.loc = src
+ to_chat(user, "You set \the [RC] on \the [src].")
+ else
+ return ..()
+
+/obj/machinery/chemical_dispenser/tgui_interact(mob/user, datum/tgui/ui = null)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "ChemDispenser", ui_title) // 390, 655
+ ui.open()
+
+/obj/machinery/chemical_dispenser/tgui_data(mob/user)
+ var/data[0]
+ data["amount"] = amount
+ data["isBeakerLoaded"] = container ? 1 : 0
+ data["glass"] = accept_drinking
+
+ var/beakerContents[0]
+ if(container && container.reagents && container.reagents.reagent_list.len)
+ for(var/datum/reagent/R in container.reagents.reagent_list)
+ beakerContents.Add(list(list("name" = R.name, "id" = R.id, "volume" = R.volume))) // list in a list because Byond merges the first list...
+ data["beakerContents"] = beakerContents
+
+ if(container)
+ data["beakerCurrentVolume"] = container.reagents.total_volume
+ data["beakerMaxVolume"] = container.reagents.maximum_volume
+ else
+ data["beakerCurrentVolume"] = null
+ data["beakerMaxVolume"] = null
+
+ var/chemicals[0]
+ for(var/label in cartridges)
+ var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = cartridges[label]
+ chemicals.Add(list(list("title" = label, "id" = label, "amount" = C.reagents.total_volume))) // list in a list because Byond merges the first list...
+ data["chemicals"] = chemicals
+ return data
+
+/obj/machinery/chemical_dispenser/tgui_act(action, params)
+ if(..())
+ return TRUE
+
+ . = TRUE
+ switch(action)
+ if("amount")
+ amount = clamp(round(text2num(params["amount"]), 1), 0, 120) // round to nearest 1 and clamp 0 - 120
+ if("dispense")
+ var/label = params["reagent"]
+ if(cartridges[label] && container && container.is_open_container())
+ var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = cartridges[label]
+ playsound(src, 'sound/machines/reagent_dispense.ogg', 25, 1)
+ C.reagents.trans_to(container, amount)
+ if("remove")
+ var/amount = text2num(params["amount"])
+ if(!container || !amount)
+ return
+ var/datum/reagents/R = container.reagents
+ var/id = params["reagent"]
+ if(amount > 0)
+ R.remove_reagent(id, amount)
+ else if(amount == -1) // Isolate
+ R.isolate_reagent(id)
+ if("ejectBeaker")
+ if(container)
+ container.forceMove(get_turf(src))
+
+ if(Adjacent(usr)) // So the AI doesn't get a beaker somehow.
+ usr.put_in_hands(container)
+
+ container = null
+ else
+ return FALSE
+
+ add_fingerprint(usr)
+
+/obj/machinery/chemical_dispenser/attack_ghost(mob/user)
+ if(stat & BROKEN)
+ return
+ tgui_interact(user)
+
+/obj/machinery/chemical_dispenser/attack_ai(mob/user)
+ attack_hand(user)
+
+/obj/machinery/chemical_dispenser/attack_hand(mob/user)
+ if(stat & BROKEN)
+ return
+ tgui_interact(user)
diff --git a/code/modules/reagents/dispenser/dispenser2_energy.dm b/code/modules/reagents/machinery/dispenser/dispenser2_energy.dm
similarity index 100%
rename from code/modules/reagents/dispenser/dispenser2_energy.dm
rename to code/modules/reagents/machinery/dispenser/dispenser2_energy.dm
diff --git a/code/modules/reagents/dispenser/dispenser_presets.dm b/code/modules/reagents/machinery/dispenser/dispenser_presets.dm
similarity index 98%
rename from code/modules/reagents/dispenser/dispenser_presets.dm
rename to code/modules/reagents/machinery/dispenser/dispenser_presets.dm
index 69169030486..6b90357a2c6 100644
--- a/code/modules/reagents/dispenser/dispenser_presets.dm
+++ b/code/modules/reagents/machinery/dispenser/dispenser_presets.dm
@@ -1,144 +1,144 @@
-/obj/machinery/chemical_dispenser/full
- spawn_cartridges = list(
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/hydrogen,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lithium,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/carbon,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/nitrogen,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/oxygen,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/fluorine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodium,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/aluminum,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/silicon,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/phosphorus,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sulfur,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/chlorine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/potassium,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/iron,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/copper,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/mercury,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/radium,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/water,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/ethanol,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sacid,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tungsten,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/calcium
- )
-
-/obj/machinery/chemical_dispenser/ert
- name = "medicine dispenser"
- spawn_cartridges = list(
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/inaprov,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/ryetalyn,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/paracetamol,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tramadol,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/oxycodone,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sterilizine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/leporazine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/kelotane,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/dermaline,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/dexalin,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/dexalin_p,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tricord,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/dylovene,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/synaptizine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/hyronalin,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/arithrazine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/alkysine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/imidazoline,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/peridaxon,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/bicaridine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/hyperzine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/rezadone,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceacillin,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/ethylredox,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sleeptox,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/chloral,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cryoxadone,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/clonexadone
- )
-
-/obj/machinery/chemical_dispenser/bar_soft
- name = "soft drink dispenser"
- desc = "A soda machine."
- icon_state = "soda_dispenser"
- ui_title = "Soda Dispenser"
- accept_drinking = 1
-
-/obj/machinery/chemical_dispenser/bar_soft/full
- spawn_cartridges = list(
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/water,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/icetea,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cola,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/smw,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/dr_gibb,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceup,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/watermelon,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon
- )
-
-/obj/machinery/chemical_dispenser/bar_alc
- name = "booze dispenser"
- desc = "A beer machine. Like a soda machine, but more fun!"
- icon_state = "booze_dispenser"
- ui_title = "Booze Dispenser"
- accept_drinking = 1
-
-/obj/machinery/chemical_dispenser/bar_alc/full
- spawn_cartridges = list(
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/beer,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/kahlua,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/whiskey,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/wine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/vodka,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/gin,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/rum,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tequila,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/vermouth,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cognac,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cider,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/ale,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/mead
- )
-
-/obj/machinery/chemical_dispenser/bar_coffee
- name = "coffee dispenser"
- desc = "Driving crack dealers out of employment since 2280."
- icon_state = "coffee_dispenser"
- ui_title = "Coffee Dispenser"
- accept_drinking = 1
-
-/obj/machinery/chemical_dispenser/bar_coffee/full
- spawn_cartridges = list(
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cafe_latte,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/soy_latte,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/hot_coco,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/milk,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/mint,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/berry,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/greentea,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/decaf
- )
+/obj/machinery/chemical_dispenser/full
+ spawn_cartridges = list(
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/hydrogen,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lithium,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/carbon,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/nitrogen,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/oxygen,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/fluorine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodium,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/aluminum,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/silicon,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/phosphorus,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sulfur,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/chlorine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/potassium,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/iron,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/copper,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/mercury,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/radium,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/water,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/ethanol,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sacid,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tungsten,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/calcium
+ )
+
+/obj/machinery/chemical_dispenser/ert
+ name = "medicine dispenser"
+ spawn_cartridges = list(
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/inaprov,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/ryetalyn,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/paracetamol,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tramadol,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/oxycodone,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sterilizine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/leporazine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/kelotane,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/dermaline,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/dexalin,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/dexalin_p,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tricord,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/dylovene,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/synaptizine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/hyronalin,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/arithrazine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/alkysine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/imidazoline,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/peridaxon,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/bicaridine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/hyperzine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/rezadone,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceacillin,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/ethylredox,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sleeptox,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/chloral,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cryoxadone,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/clonexadone
+ )
+
+/obj/machinery/chemical_dispenser/bar_soft
+ name = "soft drink dispenser"
+ desc = "A soda machine."
+ icon_state = "soda_dispenser"
+ ui_title = "Soda Dispenser"
+ accept_drinking = 1
+
+/obj/machinery/chemical_dispenser/bar_soft/full
+ spawn_cartridges = list(
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/water,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/icetea,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cola,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/smw,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/dr_gibb,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceup,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/watermelon,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon
+ )
+
+/obj/machinery/chemical_dispenser/bar_alc
+ name = "booze dispenser"
+ desc = "A beer machine. Like a soda machine, but more fun!"
+ icon_state = "booze_dispenser"
+ ui_title = "Booze Dispenser"
+ accept_drinking = 1
+
+/obj/machinery/chemical_dispenser/bar_alc/full
+ spawn_cartridges = list(
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/beer,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/kahlua,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/whiskey,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/wine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/vodka,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/gin,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/rum,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tequila,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/vermouth,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cognac,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cider,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/ale,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/mead
+ )
+
+/obj/machinery/chemical_dispenser/bar_coffee
+ name = "coffee dispenser"
+ desc = "Driving crack dealers out of employment since 2280."
+ icon_state = "coffee_dispenser"
+ ui_title = "Coffee Dispenser"
+ accept_drinking = 1
+
+/obj/machinery/chemical_dispenser/bar_coffee/full
+ spawn_cartridges = list(
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cafe_latte,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/soy_latte,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/hot_coco,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/milk,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/mint,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/berry,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/greentea,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/decaf
+ )
diff --git a/code/modules/reagents/dispenser/dispenser_presets_vr.dm b/code/modules/reagents/machinery/dispenser/dispenser_presets_vr.dm
similarity index 100%
rename from code/modules/reagents/dispenser/dispenser_presets_vr.dm
rename to code/modules/reagents/machinery/dispenser/dispenser_presets_vr.dm
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/machinery/dispenser/reagent_tank.dm
similarity index 96%
rename from code/modules/reagents/reagent_dispenser.dm
rename to code/modules/reagents/machinery/dispenser/reagent_tank.dm
index 91352a84981..6444ac85a2c 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/machinery/dispenser/reagent_tank.dm
@@ -1,466 +1,473 @@
-
-
-/obj/structure/reagent_dispensers
- name = "Dispenser"
- desc = "..."
- icon = 'icons/obj/objects.dmi'
- icon_state = "watertank"
- layer = TABLE_LAYER
- density = 1
- anchored = 0
- pressure_resistance = 2*ONE_ATMOSPHERE
-
- var/obj/item/hose_connector/input/active/InputSocket
- var/obj/item/hose_connector/output/active/OutputSocket
-
- var/amount_per_transfer_from_this = 10
- var/possible_transfer_amounts = list(10,25,50,100)
-
-/obj/structure/reagent_dispensers/attackby(obj/item/weapon/W as obj, mob/user as mob)
- return
-
-/obj/structure/reagent_dispensers/Destroy()
- QDEL_NULL(InputSocket)
- QDEL_NULL(OutputSocket)
-
- ..()
-
-/obj/structure/reagent_dispensers/Initialize()
- var/datum/reagents/R = new/datum/reagents(5000)
- reagents = R
- R.my_atom = src
- if (!possible_transfer_amounts)
- src.verbs -= /obj/structure/reagent_dispensers/verb/set_APTFT
-
- InputSocket = new(src)
- InputSocket.carrier = src
- OutputSocket = new(src)
- OutputSocket.carrier = src
-
- . = ..()
-
-/obj/structure/reagent_dispensers/examine(mob/user)
- . = ..()
- if(get_dist(user, src) <= 2)
- . += "It contains:"
- if(reagents && reagents.reagent_list.len)
- for(var/datum/reagent/R in reagents.reagent_list)
- . += "[R.volume] units of [R.name]"
- else
- . += "Nothing."
-
-/obj/structure/reagent_dispensers/verb/set_APTFT() //set amount_per_transfer_from_this
- set name = "Set transfer amount"
- set category = "Object"
- set src in view(1)
- var/N = input("Amount per transfer from this:","[src]") as null|anything in possible_transfer_amounts
- if (N)
- amount_per_transfer_from_this = N
-
-/obj/structure/reagent_dispensers/ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- return
- if(2.0)
- if (prob(50))
- new /obj/effect/effect/water(src.loc)
- qdel(src)
- return
- if(3.0)
- if (prob(5))
- new /obj/effect/effect/water(src.loc)
- qdel(src)
- return
- else
- return
-
-/obj/structure/reagent_dispensers/blob_act()
- qdel(src)
-
-
-
-//Dispensers
-/obj/structure/reagent_dispensers/watertank
- name = "watertank"
- desc = "A watertank."
- icon = 'icons/obj/objects_vr.dmi' //VOREStation Edit
- icon_state = "watertank"
- amount_per_transfer_from_this = 10
-
-/obj/structure/reagent_dispensers/watertank/Initialize()
- . = ..()
- reagents.add_reagent("water", 1000)
-
-/obj/structure/reagent_dispensers/watertank/high
- name = "high-capacity water tank"
- desc = "A highly-pressurized water tank made to hold vast amounts of water.."
- icon_state = "watertank_high"
-
-/obj/structure/reagent_dispensers/watertank/high/Initialize()
- . = ..()
- reagents.add_reagent("water", 4000)
-
-/obj/structure/reagent_dispensers/fueltank
- name = "fueltank"
- desc = "A fueltank."
- icon = 'icons/obj/objects_vr.dmi' //VOREStation Edit
- icon_state = "weldtank"
- amount_per_transfer_from_this = 10
- var/modded = 0
- var/obj/item/device/assembly_holder/rig = null
-
-/obj/structure/reagent_dispensers/fueltank/Initialize()
- . = ..()
- reagents.add_reagent("fuel",1000)
-
-//VOREStation Add
-/obj/structure/reagent_dispensers/fueltank/high
- name = "high-capacity fuel tank"
- desc = "A highly-pressurized fuel tank made to hold vast amounts of fuel."
- icon_state = "weldtank_high"
-
-/obj/structure/reagent_dispensers/fueltank/high/Initialize()
- . = ..()
- reagents.add_reagent("fuel",4000)
-
-/obj/structure/reagent_dispensers/foam
- name = "foamtank"
- desc = "A foam tank."
- icon = 'icons/obj/objects_vr.dmi' //VOREStation Edit
- icon_state = "foamtank"
- amount_per_transfer_from_this = 10
-
-/obj/structure/reagent_dispensers/foam/Initialize()
- . = ..()
- reagents.add_reagent("firefoam",1000)
-
-/obj/structure/reagent_dispensers/fueltank/barrel
- name = "hazardous barrel"
- desc = "An open-topped barrel full of nasty-looking liquid."
- icon_state = "barrel"
- modded = TRUE
-
-/obj/structure/reagent_dispensers/fueltank/barrel/attackby(obj/item/weapon/W as obj, mob/user as mob)
- if (W.is_wrench()) //can't wrench it shut, it's always open
- return
- return ..()
-
-//VOREStation Add End
-
-
-/obj/structure/reagent_dispensers/fueltank/examine(mob/user)
- . = ..()
- if(get_dist(user, src) <= 2)
- if(modded)
- . += "Fuel faucet is wrenched open, leaking the fuel!"
- if(rig)
- . += "There is some kind of device rigged to the tank."
-
-/obj/structure/reagent_dispensers/fueltank/attack_hand()
- if (rig)
- usr.visible_message("[usr] begins to detach [rig] from \the [src].", "You begin to detach [rig] from \the [src]")
- if(do_after(usr, 20))
- usr.visible_message("[usr] detaches [rig] from \the [src].", "You detach [rig] from \the [src]")
- rig.loc = get_turf(usr)
- rig = null
- overlays = new/list()
-
-/obj/structure/reagent_dispensers/fueltank/attackby(obj/item/weapon/W as obj, mob/user as mob)
- src.add_fingerprint(user)
- if (W.is_wrench())
- user.visible_message("[user] wrenches [src]'s faucet [modded ? "closed" : "open"].", \
- "You wrench [src]'s faucet [modded ? "closed" : "open"]")
- modded = modded ? 0 : 1
- playsound(src, W.usesound, 75, 1)
- if (modded)
- message_admins("[key_name_admin(user)] opened fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]), leaking fuel. (JMP)")
- log_game("[key_name(user)] opened fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]), leaking fuel.")
- leak_fuel(amount_per_transfer_from_this)
- if (istype(W,/obj/item/device/assembly_holder))
- if (rig)
- to_chat(user, "There is another device in the way.")
- return ..()
- user.visible_message("[user] begins rigging [W] to \the [src].", "You begin rigging [W] to \the [src]")
- if(do_after(user, 20))
- user.visible_message("[user] rigs [W] to \the [src].", "You rig [W] to \the [src]")
-
- var/obj/item/device/assembly_holder/H = W
- if (istype(H.a_left,/obj/item/device/assembly/igniter) || istype(H.a_right,/obj/item/device/assembly/igniter))
- message_admins("[key_name_admin(user)] rigged fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) for explosion. (JMP)")
- log_game("[key_name(user)] rigged fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) for explosion.")
-
- rig = W
- user.drop_item()
- W.loc = src
-
- var/icon/test = getFlatIcon(W)
- test.Shift(NORTH,1)
- test.Shift(EAST,6)
- overlays += test
-
- return ..()
-
-
-/obj/structure/reagent_dispensers/fueltank/bullet_act(var/obj/item/projectile/Proj)
- if(Proj.get_structure_damage())
- if(istype(Proj.firer))
- message_admins("[key_name_admin(Proj.firer)] shot fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) (JMP).")
- log_game("[key_name(Proj.firer)] shot fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]).")
-
- if(!istype(Proj ,/obj/item/projectile/beam/lasertag) && !istype(Proj ,/obj/item/projectile/beam/practice) )
- explode()
-
-/obj/structure/reagent_dispensers/fueltank/ex_act()
- explode()
-
-/obj/structure/reagent_dispensers/fueltank/blob_act()
- explode()
-
-/obj/structure/reagent_dispensers/fueltank/proc/explode()
- if (reagents.total_volume > 500)
- explosion(src.loc,1,2,4)
- else if (reagents.total_volume > 100)
- explosion(src.loc,0,1,3)
- else if (reagents.total_volume > 50)
- explosion(src.loc,-1,1,2)
- if(src)
- qdel(src)
-
-/obj/structure/reagent_dispensers/fueltank/fire_act(datum/gas_mixture/air, temperature, volume)
- if (modded)
- explode()
- else if (temperature > T0C+500)
- explode()
- return ..()
-
-/obj/structure/reagent_dispensers/fueltank/Move()
- if (..() && modded)
- leak_fuel(amount_per_transfer_from_this/10.0)
-
-/obj/structure/reagent_dispensers/fueltank/proc/leak_fuel(amount)
- if (reagents.total_volume == 0)
- return
-
- amount = min(amount, reagents.total_volume)
- reagents.remove_reagent("fuel",amount)
- new /obj/effect/decal/cleanable/liquid_fuel(src.loc, amount,1)
-
-/obj/structure/reagent_dispensers/peppertank
- name = "Pepper Spray Refiller"
- desc = "Refills pepper spray canisters."
- icon = 'icons/obj/objects.dmi'
- icon_state = "peppertank"
- anchored = 1
- density = 0
- amount_per_transfer_from_this = 45
-
-/obj/structure/reagent_dispensers/peppertank/Initialize()
- . = ..()
- reagents.add_reagent("condensedcapsaicin",1000)
-
-
-/obj/structure/reagent_dispensers/water_cooler
- name = "Water-Cooler"
- desc = "A machine that dispenses water to drink."
- amount_per_transfer_from_this = 5
- icon = 'icons/obj/vending.dmi'
- icon_state = "water_cooler"
- possible_transfer_amounts = null
- anchored = 1
- var/bottle = 0
- var/cups = 0
- var/cupholder = 0
-
-/obj/structure/reagent_dispensers/water_cooler/full
- bottle = 1
- cupholder = 1
- cups = 10
-
-/obj/structure/reagent_dispensers/water_cooler/Initialize()
- . = ..()
- if(bottle)
- reagents.add_reagent("water",120)
- update_icon()
-
-/obj/structure/reagent_dispensers/water_cooler/examine(mob/user)
- . = ..()
- if(cupholder)
- . += "There are [cups] cups in the cup dispenser."
-
-/obj/structure/reagent_dispensers/water_cooler/verb/rotate_clockwise()
- set name = "Rotate Cooler Clockwise"
- set category = "Object"
- set src in oview(1)
-
- if (src.anchored || usr:stat)
- to_chat(usr, "It is fastened to the floor!")
- return 0
- src.set_dir(turn(src.dir, 270))
- return 1
-
-/obj/structure/reagent_dispensers/water_cooler/attackby(obj/item/I as obj, mob/user as mob)
- if(I.is_wrench())
- src.add_fingerprint(user)
- if(bottle)
- playsound(src, I.usesound, 50, 1)
- if(do_after(user, 20) && bottle)
- to_chat(user, "You unfasten the jug.")
- var/obj/item/weapon/reagent_containers/glass/cooler_bottle/G = new /obj/item/weapon/reagent_containers/glass/cooler_bottle( src.loc )
- for(var/datum/reagent/R in reagents.reagent_list)
- var/total_reagent = reagents.get_reagent_amount(R.id)
- G.reagents.add_reagent(R.id, total_reagent)
- reagents.clear_reagents()
- bottle = 0
- update_icon()
- else
- if(anchored)
- user.visible_message("\The [user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
- else
- user.visible_message("\The [user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.")
- if(do_after(user, 20 * I.toolspeed, src))
- if(!src) return
- to_chat(user, "You [anchored? "un" : ""]secured \the [src]!")
- anchored = !anchored
- playsound(src, I.usesound, 50, 1)
- return
-
- if(I.is_screwdriver())
- if(cupholder)
- playsound(src, I.usesound, 50, 1)
- to_chat(user, "You take the cup dispenser off.")
- new /obj/item/stack/material/plastic( src.loc )
- if(cups)
- for(var/i = 0 to cups)
- new /obj/item/weapon/reagent_containers/food/drinks/sillycup(src.loc)
- cups = 0
- cupholder = 0
- update_icon()
- return
- if(!bottle && !cupholder)
- playsound(src, I.usesound, 50, 1)
- to_chat(user, "You start taking the water-cooler apart.")
- if(do_after(user, 20 * I.toolspeed) && !bottle && !cupholder)
- to_chat(user, "You take the water-cooler apart.")
- new /obj/item/stack/material/plastic( src.loc, 4 )
- qdel(src)
- return
-
- if(istype(I, /obj/item/weapon/reagent_containers/glass/cooler_bottle))
- src.add_fingerprint(user)
- if(!bottle)
- if(anchored)
- var/obj/item/weapon/reagent_containers/glass/cooler_bottle/G = I
- to_chat(user, "You start to screw the bottle onto the water-cooler.")
- if(do_after(user, 20) && !bottle && anchored)
- bottle = 1
- update_icon()
- to_chat(user, "You screw the bottle onto the water-cooler!")
- for(var/datum/reagent/R in G.reagents.reagent_list)
- var/total_reagent = G.reagents.get_reagent_amount(R.id)
- reagents.add_reagent(R.id, total_reagent)
- qdel(G)
- else
- to_chat(user, "You need to wrench down the cooler first.")
- else
- to_chat(user, "There is already a bottle there!")
- return 1
-
- if(istype(I, /obj/item/stack/material/plastic))
- if(!cupholder)
- if(anchored)
- var/obj/item/stack/material/plastic/P = I
- src.add_fingerprint(user)
- to_chat(user, "You start to attach a cup dispenser onto the water-cooler.")
- playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 20) && !cupholder && anchored)
- if (P.use(1))
- to_chat(user, "You attach a cup dispenser onto the water-cooler.")
- cupholder = 1
- update_icon()
- else
- to_chat(user, "You need to wrench down the cooler first.")
- else
- to_chat(user, "There is already a cup dispenser there!")
- return
-
-/obj/structure/reagent_dispensers/water_cooler/attack_hand(mob/user)
- if(cups)
- new /obj/item/weapon/reagent_containers/food/drinks/sillycup(src.loc)
- cups--
- flick("[icon_state]-vend", src)
- return
-
-/obj/structure/reagent_dispensers/water_cooler/update_icon()
- icon_state = "water_cooler"
- overlays.Cut()
- var/image/I
- if(bottle)
- I = image(icon, "water_cooler_bottle")
- overlays += I
- return
-
-/obj/structure/reagent_dispensers/beerkeg
- name = "beer keg"
- desc = "A beer keg."
- icon = 'icons/obj/objects.dmi'
- icon_state = "beertankTEMP"
- amount_per_transfer_from_this = 10
-
-/obj/structure/reagent_dispensers/beerkeg/Initialize()
- . = ..()
- reagents.add_reagent("beer",1000)
-
-/obj/structure/reagent_dispensers/beerkeg/fakenuke
- name = "nuclear beer keg"
- desc = "A beer keg in the form of a nuclear bomb! An absolute blast at parties!"
- icon = 'icons/obj/stationobjs.dmi'
- icon_state = "nuclearbomb0"
-
-/obj/structure/reagent_dispensers/virusfood
- name = "Virus Food Dispenser"
- desc = "A dispenser of virus food. Yum."
- icon = 'icons/obj/objects.dmi'
- icon_state = "virusfoodtank"
- amount_per_transfer_from_this = 10
- anchored = 1
-
-/obj/structure/reagent_dispensers/virusfood/Initialize()
- . = ..()
- reagents.add_reagent("virusfood", 1000)
-
-/obj/structure/reagent_dispensers/acid
- name = "Sulphuric Acid Dispenser"
- desc = "A dispenser of acid for industrial processes."
- icon = 'icons/obj/objects.dmi'
- icon_state = "acidtank"
- amount_per_transfer_from_this = 10
- anchored = 1
-
-/obj/structure/reagent_dispensers/acid/Initialize()
- . = ..()
- reagents.add_reagent("sacid", 1000)
-
-//Cooking oil refill tank
-/obj/structure/reagent_dispensers/cookingoil
- name = "cooking oil tank"
- desc = "A fifty-litre tank of commercial-grade corn oil, intended for use in large scale deep fryers. Store in a cool, dark place"
- icon = 'icons/obj/objects.dmi'
- icon_state = "oiltank"
- amount_per_transfer_from_this = 120
-
-/obj/structure/reagent_dispensers/cookingoil/New()
- ..()
- reagents.add_reagent("cornoil",5000)
-
-/obj/structure/reagent_dispensers/cookingoil/bullet_act(var/obj/item/projectile/Proj)
- if(Proj.get_structure_damage())
- explode()
-
-/obj/structure/reagent_dispensers/cookingoil/ex_act()
- explode()
-
-/obj/structure/reagent_dispensers/cookingoil/proc/explode()
- reagents.splash_area(get_turf(src), 3)
- visible_message(span("danger", "The [src] bursts open, spreading oil all over the area."))
- qdel(src)
+/obj/structure/reagent_dispensers
+ name = "Dispenser"
+ desc = "..."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "watertank"
+ layer = TABLE_LAYER
+ density = 1
+ anchored = 0
+ pressure_resistance = 2*ONE_ATMOSPHERE
+
+ var/obj/item/hose_connector/input/active/InputSocket
+ var/obj/item/hose_connector/output/active/OutputSocket
+
+ var/amount_per_transfer_from_this = 10
+ var/possible_transfer_amounts = list(10,25,50,100)
+
+/obj/structure/reagent_dispensers/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ return
+
+/obj/structure/reagent_dispensers/Destroy()
+ QDEL_NULL(InputSocket)
+ QDEL_NULL(OutputSocket)
+
+ ..()
+
+/obj/structure/reagent_dispensers/Initialize()
+ var/datum/reagents/R = new/datum/reagents(5000)
+ reagents = R
+ R.my_atom = src
+ if (!possible_transfer_amounts)
+ src.verbs -= /obj/structure/reagent_dispensers/verb/set_APTFT
+
+ InputSocket = new(src)
+ InputSocket.carrier = src
+ OutputSocket = new(src)
+ OutputSocket.carrier = src
+
+ . = ..()
+
+/obj/structure/reagent_dispensers/examine(mob/user)
+ . = ..()
+ if(get_dist(user, src) <= 2)
+ . += "It contains:"
+ if(reagents && reagents.reagent_list.len)
+ for(var/datum/reagent/R in reagents.reagent_list)
+ . += "[R.volume] units of [R.name]"
+ else
+ . += "Nothing."
+
+/obj/structure/reagent_dispensers/verb/set_APTFT() //set amount_per_transfer_from_this
+ set name = "Set transfer amount"
+ set category = "Object"
+ set src in view(1)
+ var/N = input("Amount per transfer from this:","[src]") as null|anything in possible_transfer_amounts
+ if (N)
+ amount_per_transfer_from_this = N
+
+/obj/structure/reagent_dispensers/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ qdel(src)
+ return
+ if(2.0)
+ if (prob(50))
+ new /obj/effect/effect/water(src.loc)
+ qdel(src)
+ return
+ if(3.0)
+ if (prob(5))
+ new /obj/effect/effect/water(src.loc)
+ qdel(src)
+ return
+ else
+ return
+
+/obj/structure/reagent_dispensers/blob_act()
+ qdel(src)
+
+
+
+//Dispensers
+/obj/structure/reagent_dispensers/watertank
+ name = "watertank"
+ desc = "A watertank."
+ icon = 'icons/obj/objects_vr.dmi' //VOREStation Edit
+ icon_state = "watertank"
+ amount_per_transfer_from_this = 10
+
+/obj/structure/reagent_dispensers/watertank/Initialize()
+ . = ..()
+ reagents.add_reagent("water", 1000)
+
+/obj/structure/reagent_dispensers/watertank/high
+ name = "high-capacity water tank"
+ desc = "A highly-pressurized water tank made to hold vast amounts of water.."
+ icon_state = "watertank_high"
+
+/obj/structure/reagent_dispensers/watertank/high/Initialize()
+ . = ..()
+ reagents.add_reagent("water", 4000)
+
+/obj/structure/reagent_dispensers/fueltank
+ name = "fueltank"
+ desc = "A fueltank."
+ icon = 'icons/obj/objects_vr.dmi' //VOREStation Edit
+ icon_state = "weldtank"
+ amount_per_transfer_from_this = 10
+ var/modded = 0
+ var/obj/item/device/assembly_holder/rig = null
+
+/obj/structure/reagent_dispensers/fueltank/Initialize()
+ . = ..()
+ reagents.add_reagent("fuel",1000)
+
+//VOREStation Add
+/obj/structure/reagent_dispensers/fueltank/high
+ name = "high-capacity fuel tank"
+ desc = "A highly-pressurized fuel tank made to hold vast amounts of fuel."
+ icon_state = "weldtank_high"
+
+/obj/structure/reagent_dispensers/fueltank/high/Initialize()
+ . = ..()
+ reagents.add_reagent("fuel",4000)
+
+/obj/structure/reagent_dispensers/foam
+ name = "foamtank"
+ desc = "A foam tank."
+ icon = 'icons/obj/objects_vr.dmi'
+ icon_state = "foamtank"
+ amount_per_transfer_from_this = 10
+
+/obj/structure/reagent_dispensers/foam/Initialize()
+ . = ..()
+ reagents.add_reagent("firefoam",1000)
+
+/obj/structure/reagent_dispensers/fueltank/barrel
+ name = "hazardous barrel"
+ desc = "An open-topped barrel full of nasty-looking liquid."
+ icon_state = "barrel"
+ modded = TRUE
+
+/obj/structure/reagent_dispensers/fueltank/barrel/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if (W.is_wrench()) //can't wrench it shut, it's always open
+ return
+ return ..()
+//VOREStation Add End
+
+/obj/structure/reagent_dispensers/fueltank/examine(mob/user)
+ . = ..()
+ if(get_dist(user, src) <= 2)
+ if(modded)
+ . += "Fuel faucet is wrenched open, leaking the fuel!"
+ if(rig)
+ . += "There is some kind of device rigged to the tank."
+
+/obj/structure/reagent_dispensers/fueltank/attack_hand()
+ if (rig)
+ usr.visible_message("[usr] begins to detach [rig] from \the [src].", "You begin to detach [rig] from \the [src]")
+ if(do_after(usr, 20))
+ usr.visible_message("[usr] detaches [rig] from \the [src].", "You detach [rig] from \the [src]")
+ rig.loc = get_turf(usr)
+ rig = null
+ overlays = new/list()
+
+/obj/structure/reagent_dispensers/fueltank/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ src.add_fingerprint(user)
+ if (W.is_wrench())
+ user.visible_message("[user] wrenches [src]'s faucet [modded ? "closed" : "open"].", \
+ "You wrench [src]'s faucet [modded ? "closed" : "open"]")
+ modded = modded ? 0 : 1
+ playsound(src, W.usesound, 75, 1)
+ if (modded)
+ message_admins("[key_name_admin(user)] opened fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]), leaking fuel. (JMP)")
+ log_game("[key_name(user)] opened fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]), leaking fuel.")
+ leak_fuel(amount_per_transfer_from_this)
+ if (istype(W,/obj/item/device/assembly_holder))
+ if (rig)
+ to_chat(user, "There is another device in the way.")
+ return ..()
+ user.visible_message("[user] begins rigging [W] to \the [src].", "You begin rigging [W] to \the [src]")
+ if(do_after(user, 20))
+ user.visible_message("[user] rigs [W] to \the [src].", "You rig [W] to \the [src]")
+
+ var/obj/item/device/assembly_holder/H = W
+ if (istype(H.a_left,/obj/item/device/assembly/igniter) || istype(H.a_right,/obj/item/device/assembly/igniter))
+ message_admins("[key_name_admin(user)] rigged fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) for explosion. (JMP)")
+ log_game("[key_name(user)] rigged fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) for explosion.")
+
+ rig = W
+ user.drop_item()
+ W.loc = src
+
+ var/icon/test = getFlatIcon(W)
+ test.Shift(NORTH,1)
+ test.Shift(EAST,6)
+ overlays += test
+
+ return ..()
+
+
+/obj/structure/reagent_dispensers/fueltank/bullet_act(var/obj/item/projectile/Proj)
+ if(Proj.get_structure_damage())
+ if(istype(Proj.firer))
+ message_admins("[key_name_admin(Proj.firer)] shot fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) (JMP).")
+ log_game("[key_name(Proj.firer)] shot fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]).")
+
+ if(!istype(Proj ,/obj/item/projectile/beam/lasertag) && !istype(Proj ,/obj/item/projectile/beam/practice) )
+ explode()
+
+/obj/structure/reagent_dispensers/fueltank/ex_act()
+ explode()
+
+/obj/structure/reagent_dispensers/fueltank/blob_act()
+ explode()
+
+/obj/structure/reagent_dispensers/fueltank/proc/explode()
+ if (reagents.total_volume > 500)
+ explosion(src.loc,1,2,4)
+ else if (reagents.total_volume > 100)
+ explosion(src.loc,0,1,3)
+ else if (reagents.total_volume > 50)
+ explosion(src.loc,-1,1,2)
+ if(src)
+ qdel(src)
+
+/obj/structure/reagent_dispensers/fueltank/fire_act(datum/gas_mixture/air, temperature, volume)
+ if (modded)
+ explode()
+ else if (temperature > T0C+500)
+ explode()
+ return ..()
+
+/obj/structure/reagent_dispensers/fueltank/Move()
+ if (..() && modded)
+ leak_fuel(amount_per_transfer_from_this/10.0)
+
+/obj/structure/reagent_dispensers/fueltank/proc/leak_fuel(amount)
+ if (reagents.total_volume == 0)
+ return
+
+ amount = min(amount, reagents.total_volume)
+ reagents.remove_reagent("fuel",amount)
+ new /obj/effect/decal/cleanable/liquid_fuel(src.loc, amount,1)
+
+/obj/structure/reagent_dispensers/peppertank
+ name = "Pepper Spray Refiller"
+ desc = "Refills pepper spray canisters."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "peppertank"
+ anchored = 1
+ density = 0
+ amount_per_transfer_from_this = 45
+
+/obj/structure/reagent_dispensers/peppertank/Initialize()
+ . = ..()
+ reagents.add_reagent("condensedcapsaicin",1000)
+
+
+/obj/structure/reagent_dispensers/water_cooler
+ name = "Water-Cooler"
+ desc = "A machine that dispenses water to drink."
+ amount_per_transfer_from_this = 5
+ icon = 'icons/obj/vending.dmi'
+ icon_state = "water_cooler"
+ possible_transfer_amounts = null
+ anchored = 1
+ var/bottle = 0
+ var/cups = 0
+ var/cupholder = 0
+
+/obj/structure/reagent_dispensers/water_cooler/full
+ bottle = 1
+ cupholder = 1
+ cups = 10
+
+/obj/structure/reagent_dispensers/water_cooler/Initialize()
+ . = ..()
+ if(bottle)
+ reagents.add_reagent("water",120)
+ update_icon()
+
+/obj/structure/reagent_dispensers/water_cooler/examine(mob/user)
+ . = ..()
+ if(cupholder)
+ . += "There are [cups] cups in the cup dispenser."
+
+/obj/structure/reagent_dispensers/water_cooler/verb/rotate_clockwise()
+ set name = "Rotate Cooler Clockwise"
+ set category = "Object"
+ set src in oview(1)
+
+ if (src.anchored || usr:stat)
+ to_chat(usr, "It is fastened to the floor!")
+ return 0
+ src.set_dir(turn(src.dir, 270))
+ return 1
+
+/obj/structure/reagent_dispensers/water_cooler/attackby(obj/item/I as obj, mob/user as mob)
+ if(I.is_wrench())
+ src.add_fingerprint(user)
+ if(bottle)
+ playsound(src, I.usesound, 50, 1)
+ if(do_after(user, 20) && bottle)
+ to_chat(user, "You unfasten the jug.")
+ var/obj/item/weapon/reagent_containers/glass/cooler_bottle/G = new /obj/item/weapon/reagent_containers/glass/cooler_bottle( src.loc )
+ for(var/datum/reagent/R in reagents.reagent_list)
+ var/total_reagent = reagents.get_reagent_amount(R.id)
+ G.reagents.add_reagent(R.id, total_reagent)
+ reagents.clear_reagents()
+ bottle = 0
+ update_icon()
+ else
+ if(anchored)
+ user.visible_message("\The [user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
+ else
+ user.visible_message("\The [user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.")
+ if(do_after(user, 20 * I.toolspeed, src))
+ if(!src) return
+ to_chat(user, "You [anchored? "un" : ""]secured \the [src]!")
+ anchored = !anchored
+ playsound(src, I.usesound, 50, 1)
+ return
+
+ if(I.is_screwdriver())
+ if(cupholder)
+ playsound(src, I.usesound, 50, 1)
+ to_chat(user, "You take the cup dispenser off.")
+ new /obj/item/stack/material/plastic( src.loc )
+ if(cups)
+ for(var/i = 0 to cups)
+ new /obj/item/weapon/reagent_containers/food/drinks/sillycup(src.loc)
+ cups = 0
+ cupholder = 0
+ update_icon()
+ return
+ if(!bottle && !cupholder)
+ playsound(src, I.usesound, 50, 1)
+ to_chat(user, "You start taking the water-cooler apart.")
+ if(do_after(user, 20 * I.toolspeed) && !bottle && !cupholder)
+ to_chat(user, "You take the water-cooler apart.")
+ new /obj/item/stack/material/plastic( src.loc, 4 )
+ qdel(src)
+ return
+
+ if(istype(I, /obj/item/weapon/reagent_containers/glass/cooler_bottle))
+ src.add_fingerprint(user)
+ if(!bottle)
+ if(anchored)
+ var/obj/item/weapon/reagent_containers/glass/cooler_bottle/G = I
+ to_chat(user, "You start to screw the bottle onto the water-cooler.")
+ if(do_after(user, 20) && !bottle && anchored)
+ bottle = 1
+ update_icon()
+ to_chat(user, "You screw the bottle onto the water-cooler!")
+ for(var/datum/reagent/R in G.reagents.reagent_list)
+ var/total_reagent = G.reagents.get_reagent_amount(R.id)
+ reagents.add_reagent(R.id, total_reagent)
+ qdel(G)
+ else
+ to_chat(user, "You need to wrench down the cooler first.")
+ else
+ to_chat(user, "There is already a bottle there!")
+ return 1
+
+ if(istype(I, /obj/item/stack/material/plastic))
+ if(!cupholder)
+ if(anchored)
+ var/obj/item/stack/material/plastic/P = I
+ src.add_fingerprint(user)
+ to_chat(user, "You start to attach a cup dispenser onto the water-cooler.")
+ playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
+ if(do_after(user, 20) && !cupholder && anchored)
+ if (P.use(1))
+ to_chat(user, "You attach a cup dispenser onto the water-cooler.")
+ cupholder = 1
+ update_icon()
+ else
+ to_chat(user, "You need to wrench down the cooler first.")
+ else
+ to_chat(user, "There is already a cup dispenser there!")
+ return
+
+/obj/structure/reagent_dispensers/water_cooler/attack_hand(mob/user)
+ if(cups)
+ new /obj/item/weapon/reagent_containers/food/drinks/sillycup(src.loc)
+ cups--
+ flick("[icon_state]-vend", src)
+ return
+
+/obj/structure/reagent_dispensers/water_cooler/update_icon()
+ icon_state = "water_cooler"
+ overlays.Cut()
+ var/image/I
+ if(bottle)
+ I = image(icon, "water_cooler_bottle")
+ overlays += I
+ return
+
+/obj/structure/reagent_dispensers/beerkeg
+ name = "beer keg"
+ desc = "A beer keg."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "beertankTEMP"
+ amount_per_transfer_from_this = 10
+
+/obj/structure/reagent_dispensers/beerkeg/Initialize()
+ . = ..()
+ reagents.add_reagent("beer",1000)
+
+/obj/structure/reagent_dispensers/beerkeg/fakenuke
+ name = "nuclear beer keg"
+ desc = "A beer keg in the form of a nuclear bomb! An absolute blast at parties!"
+ icon = 'icons/obj/stationobjs.dmi'
+ icon_state = "nuclearbomb0"
+
+/obj/structure/reagent_dispensers/virusfood
+ name = "Virus Food Dispenser"
+ desc = "A dispenser of virus food. Yum."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "virusfoodtank"
+ amount_per_transfer_from_this = 10
+ anchored = 1
+
+/obj/structure/reagent_dispensers/virusfood/Initialize()
+ . = ..()
+ reagents.add_reagent("virusfood", 1000)
+
+/obj/structure/reagent_dispensers/acid
+ name = "Sulphuric Acid Dispenser"
+ desc = "A dispenser of acid for industrial processes."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "acidtank"
+ amount_per_transfer_from_this = 10
+ anchored = 1
+
+/obj/structure/reagent_dispensers/acid/Initialize()
+ . = ..()
+ reagents.add_reagent("sacid", 1000)
+
+//Cooking oil refill tank
+/obj/structure/reagent_dispensers/cookingoil
+ name = "cooking oil tank"
+ desc = "A fifty-litre tank of commercial-grade corn oil, intended for use in large scale deep fryers. Store in a cool, dark place"
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "oiltank"
+ amount_per_transfer_from_this = 120
+
+/obj/structure/reagent_dispensers/cookingoil/New()
+ ..()
+ reagents.add_reagent("cornoil",5000)
+
+/obj/structure/reagent_dispensers/cookingoil/bullet_act(var/obj/item/projectile/Proj)
+ if(Proj.get_structure_damage())
+ explode()
+
+/obj/structure/reagent_dispensers/cookingoil/ex_act()
+ explode()
+
+/obj/structure/reagent_dispensers/cookingoil/proc/explode()
+ reagents.splash_area(get_turf(src), 3)
+ visible_message(span("danger", "The [src] bursts open, spreading oil all over the area."))
+ qdel(src)
+
+/obj/structure/reagent_dispensers/he3
+ name = "fueltank"
+ desc = "A fueltank."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "weldtank"
+ amount_per_transfer_from_this = 10
+
+/obj/structure/reagent_dispenser/he3/Initialize()
+ ..()
+ reagents.add_reagent("helium3",1000)
diff --git a/code/modules/reagents/dispenser/supply.dm b/code/modules/reagents/machinery/dispenser/supply.dm
similarity index 98%
rename from code/modules/reagents/dispenser/supply.dm
rename to code/modules/reagents/machinery/dispenser/supply.dm
index 228c5dfeeff..30b1c3c0f63 100644
--- a/code/modules/reagents/dispenser/supply.dm
+++ b/code/modules/reagents/machinery/dispenser/supply.dm
@@ -1,238 +1,238 @@
-/datum/supply_pack/chemistry_dispenser
- name = "Reagent dispenser"
- contains = list(
- /obj/machinery/chemical_dispenser{anchored = 0}
- )
- cost = 25
- containertype = /obj/structure/largecrate
- containername = "reagent dispenser crate"
- group = "Reagents"
-
-/datum/supply_pack/beer_dispenser
- name = "Booze dispenser"
- contains = list(
- /obj/machinery/chemical_dispenser/bar_alc{anchored = 0}
- )
- cost = 25
- containertype = /obj/structure/largecrate
- containername = "booze dispenser crate"
- group = "Reagents"
-
-/datum/supply_pack/soda_dispenser
- name = "Soda dispenser"
- contains = list(
- /obj/machinery/chemical_dispenser/bar_soft{anchored = 0}
- )
- cost = 25
- containertype = /obj/structure/largecrate
- containername = "soda dispenser crate"
- group = "Reagents"
-
-/datum/supply_pack/reagents
- name = "Chemistry dispenser refill"
- contains = list(
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/hydrogen,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lithium,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/carbon,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/nitrogen,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/oxygen,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/fluorine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodium,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/aluminum,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/silicon,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/phosphorus,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sulfur,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/chlorine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/potassium,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/iron,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/copper,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/mercury,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/radium,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/water,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/ethanol,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sacid,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tungsten
- )
- cost = 150
- containertype = /obj/structure/closet/crate/secure
- containername = "chemical crate"
- access = list(access_chemistry)
- group = "Reagents"
-
-/datum/supply_pack/alcohol_reagents
- name = "Bar alcoholic dispenser refill"
- contains = list(
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/beer,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/kahlua,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/whiskey,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/wine,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/vodka,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/gin,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/rum,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tequila,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/vermouth,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cognac,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/ale,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/mead,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/bitters
- )
- cost = 50
- containertype = /obj/structure/closet/crate/secure
- containername = "alcoholic drinks crate"
- access = list(access_bar)
- group = "Reagents"
-
-/datum/supply_pack/softdrink_reagents
- name = "Bar soft drink dispenser refill"
- contains = list(
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/water,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/icetea,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cola,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/smw,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/dr_gibb,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceup,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/watermelon,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon
- )
- cost = 50
- containertype = /obj/structure/closet/crate
- containername = "soft drinks crate"
- group = "Reagents"
-
-/datum/supply_pack/coffee_reagents
- name = "Coffee machine dispenser refill"
- contains = list(
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cafe_latte,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/soy_latte,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/hot_coco,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/milk,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice
- )
- cost = 50
- containertype = /obj/structure/closet/crate
- containername = "coffee drinks crate"
- group = "Reagents"
-
-/datum/supply_pack/dispenser_cartridges
- name = "Empty dispenser cartridges"
- contains = list(
- /obj/item/weapon/reagent_containers/chem_disp_cartridge,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge
- )
- cost = 15
- containertype = /obj/structure/closet/crate
- containername = "dispenser cartridge crate"
- group = "Reagents"
-
-#define SEC_PACK(_tname, _type, _name, _cname, _cost, _access)\
- datum/supply_pack/dispenser_cartridges{\
- _tname {\
- name = _name ;\
- containername = _cname ;\
- containertype = /obj/structure/closet/crate/secure;\
- access = list( _access );\
- cost = _cost ;\
- contains = list( _type , _type );\
- group = "Reagent Cartridges"\
- }\
- }
-#define PACK(_tname, _type, _name, _cname, _cost)\
- datum/supply_pack/dispenser_cartridges{\
- _tname {\
- name = _name ;\
- containername = _cname ;\
- containertype = /obj/structure/closet/crate;\
- cost = _cost ;\
- contains = list( _type , _type );\
- group = "Reagent Cartridges"\
- }\
- }
-
-// Chemistry-restricted (raw reagents excluding sugar/water)
-// Datum path Contents type Supply pack name Container name Cost Container access
-SEC_PACK(hydrogen, /obj/item/weapon/reagent_containers/chem_disp_cartridge/hydrogen, "Reagent refill - Hydrogen", "hydrogen reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(lithium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/lithium, "Reagent refill - Lithium", "lithium reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(carbon, /obj/item/weapon/reagent_containers/chem_disp_cartridge/carbon, "Reagent refill - Carbon", "carbon reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(nitrogen, /obj/item/weapon/reagent_containers/chem_disp_cartridge/nitrogen, "Reagent refill - Nitrogen", "nitrogen reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(oxygen, /obj/item/weapon/reagent_containers/chem_disp_cartridge/oxygen, "Reagent refill - Oxygen", "oxygen reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(fluorine, /obj/item/weapon/reagent_containers/chem_disp_cartridge/fluorine, "Reagent refill - Fluorine", "fluorine reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(sodium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodium, "Reagent refill - Sodium", "sodium reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(aluminium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/aluminum, "Reagent refill - Aluminum", "aluminum reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(silicon, /obj/item/weapon/reagent_containers/chem_disp_cartridge/silicon, "Reagent refill - Silicon", "silicon reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(phosphorus,/obj/item/weapon/reagent_containers/chem_disp_cartridge/phosphorus, "Reagent refill - Phosphorus", "phosphorus reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(sulfur, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sulfur, "Reagent refill - Sulfur", "sulfur reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(chlorine, /obj/item/weapon/reagent_containers/chem_disp_cartridge/chlorine, "Reagent refill - Chlorine", "chlorine reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(potassium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/potassium, "Reagent refill - Potassium", "potassium reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(iron, /obj/item/weapon/reagent_containers/chem_disp_cartridge/iron, "Reagent refill - Iron", "iron reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(copper, /obj/item/weapon/reagent_containers/chem_disp_cartridge/copper, "Reagent refill - Copper", "copper reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(mercury, /obj/item/weapon/reagent_containers/chem_disp_cartridge/mercury, "Reagent refill - Mercury", "mercury reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(radium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/radium, "Reagent refill - Radium", "radium reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(ethanol, /obj/item/weapon/reagent_containers/chem_disp_cartridge/ethanol, "Reagent refill - Ethanol", "ethanol reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(sacid, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sacid, "Reagent refill - Sulfuric Acid", "sulfuric acid reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(tungsten, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tungsten, "Reagent refill - Tungsten", "tungsten reagent cartridge crate", 15, access_chemistry)
-SEC_PACK(calcium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/calcium, "Reagent refill - Calcium", "calcium reagent cartridge crate", 15, access_chemistry)
-
-// Bar-restricted (alcoholic drinks)
-// Datum path Contents type Supply pack name Container name Cost Container access
-SEC_PACK(beer, /obj/item/weapon/reagent_containers/chem_disp_cartridge/beer, "Reagent refill - Beer", "beer reagent cartridge crate", 15, access_bar)
-SEC_PACK(kahlua, /obj/item/weapon/reagent_containers/chem_disp_cartridge/kahlua, "Reagent refill - Kahlua", "kahlua reagent cartridge crate", 15, access_bar)
-SEC_PACK(whiskey, /obj/item/weapon/reagent_containers/chem_disp_cartridge/whiskey, "Reagent refill - Whiskey", "whiskey reagent cartridge crate", 15, access_bar)
-SEC_PACK(wine, /obj/item/weapon/reagent_containers/chem_disp_cartridge/wine, "Reagent refill - Wine", "wine reagent cartridge crate", 15, access_bar)
-SEC_PACK(vodka, /obj/item/weapon/reagent_containers/chem_disp_cartridge/vodka, "Reagent refill - Vodka", "vodka reagent cartridge crate", 15, access_bar)
-SEC_PACK(gin, /obj/item/weapon/reagent_containers/chem_disp_cartridge/gin, "Reagent refill - Gin", "gin reagent cartridge crate", 15, access_bar)
-SEC_PACK(rum, /obj/item/weapon/reagent_containers/chem_disp_cartridge/rum, "Reagent refill - Rum", "rum reagent cartridge crate", 15, access_bar)
-SEC_PACK(tequila, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tequila, "Reagent refill - Tequila", "tequila reagent cartridge crate", 15, access_bar)
-SEC_PACK(vermouth, /obj/item/weapon/reagent_containers/chem_disp_cartridge/vermouth, "Reagent refill - Vermouth", "vermouth reagent cartridge crate", 15, access_bar)
-SEC_PACK(cognac, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cognac, "Reagent refill - Cognac", "cognac reagent cartridge crate", 15, access_bar)
-SEC_PACK(ale, /obj/item/weapon/reagent_containers/chem_disp_cartridge/ale, "Reagent refill - Ale", "ale reagent cartridge crate", 15, access_bar)
-SEC_PACK(mead, /obj/item/weapon/reagent_containers/chem_disp_cartridge/mead, "Reagent refill - Mead", "mead reagent cartridge crate", 15, access_bar)
-
-// Unrestricted (water, sugar, non-alcoholic drinks)
-// Datum path Contents type Supply pack name Container name Cost
-PACK(water, /obj/item/weapon/reagent_containers/chem_disp_cartridge/water, "Reagent refill - Water", "water reagent cartridge crate", 15)
-PACK(sugar, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar, "Reagent refill - Sugar", "sugar reagent cartridge crate", 15)
-PACK(ice, /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice, "Reagent refill - Ice", "ice reagent cartridge crate", 15)
-PACK(tea, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea, "Reagent refill - Tea", "tea reagent cartridge crate", 15)
-PACK(icetea, /obj/item/weapon/reagent_containers/chem_disp_cartridge/icetea, "Reagent refill - Iced Tea", "iced tea reagent cartridge crate", 15)
-PACK(cola, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cola, "Reagent refill - Space Cola", "\improper Space Cola reagent cartridge crate", 15)
-PACK(smw, /obj/item/weapon/reagent_containers/chem_disp_cartridge/smw, "Reagent refill - Space Mountain Wind", "\improper Space Mountain Wind reagent cartridge crate", 15)
-PACK(dr_gibb, /obj/item/weapon/reagent_containers/chem_disp_cartridge/dr_gibb, "Reagent refill - Dr. Gibb", "\improper Dr. Gibb reagent cartridge crate", 15)
-PACK(spaceup, /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceup, "Reagent refill - Space-Up", "\improper Space-Up reagent cartridge crate", 15)
-PACK(tonic, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic, "Reagent refill - Tonic Water", "tonic water reagent cartridge crate", 15)
-PACK(sodawater, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater, "Reagent refill - Soda Water", "soda water reagent cartridge crate", 15)
-PACK(lemon_lime, /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime, "Reagent refill - Lemon-Lime Juice", "lemon-lime juice reagent cartridge crate", 15)
-PACK(orange, /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange, "Reagent refill - Orange Juice", "orange juice reagent cartridge crate", 15)
-PACK(lime, /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime, "Reagent refill - Lime Juice", "lime juice reagent cartridge crate", 15)
-PACK(lemon, /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon, "Reagent refill - Lemon Juice", "lemon juice reagent cartridge crate", 15)
-PACK(watermelon, /obj/item/weapon/reagent_containers/chem_disp_cartridge/watermelon, "Reagent refill - Watermelon Juice", "watermelon juice reagent cartridge crate", 15)
-PACK(coffee, /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee, "Reagent refill - Coffee", "coffee reagent cartridge crate", 15)
-PACK(cafe_latte, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cafe_latte, "Reagent refill - Cafe Latte", "cafe latte reagent cartridge crate", 15)
-PACK(soy_latte, /obj/item/weapon/reagent_containers/chem_disp_cartridge/soy_latte, "Reagent refill - Soy Latte", "soy latte reagent cartridge crate", 15)
-PACK(hot_coco, /obj/item/weapon/reagent_containers/chem_disp_cartridge/hot_coco, "Reagent refill - Hot Coco", "hot coco reagent cartridge crate", 15)
-PACK(milk, /obj/item/weapon/reagent_containers/chem_disp_cartridge/milk, "Reagent refill - Milk", "milk reagent cartridge crate", 15)
-PACK(cream, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream, "Reagent refill - Cream", "cream reagent cartridge crate", 15)
-
-#undef SEC_PACK
-#undef PACK
+/datum/supply_pack/chemistry_dispenser
+ name = "Reagent dispenser"
+ contains = list(
+ /obj/machinery/chemical_dispenser{anchored = 0}
+ )
+ cost = 25
+ containertype = /obj/structure/largecrate
+ containername = "reagent dispenser crate"
+ group = "Reagents"
+
+/datum/supply_pack/beer_dispenser
+ name = "Booze dispenser"
+ contains = list(
+ /obj/machinery/chemical_dispenser/bar_alc{anchored = 0}
+ )
+ cost = 25
+ containertype = /obj/structure/largecrate
+ containername = "booze dispenser crate"
+ group = "Reagents"
+
+/datum/supply_pack/soda_dispenser
+ name = "Soda dispenser"
+ contains = list(
+ /obj/machinery/chemical_dispenser/bar_soft{anchored = 0}
+ )
+ cost = 25
+ containertype = /obj/structure/largecrate
+ containername = "soda dispenser crate"
+ group = "Reagents"
+
+/datum/supply_pack/reagents
+ name = "Chemistry dispenser refill"
+ contains = list(
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/hydrogen,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lithium,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/carbon,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/nitrogen,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/oxygen,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/fluorine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodium,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/aluminum,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/silicon,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/phosphorus,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sulfur,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/chlorine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/potassium,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/iron,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/copper,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/mercury,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/radium,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/water,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/ethanol,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sacid,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tungsten
+ )
+ cost = 150
+ containertype = /obj/structure/closet/crate/secure
+ containername = "chemical crate"
+ access = list(access_chemistry)
+ group = "Reagents"
+
+/datum/supply_pack/alcohol_reagents
+ name = "Bar alcoholic dispenser refill"
+ contains = list(
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/beer,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/kahlua,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/whiskey,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/wine,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/vodka,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/gin,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/rum,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tequila,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/vermouth,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cognac,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/ale,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/mead,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/bitters
+ )
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure
+ containername = "alcoholic drinks crate"
+ access = list(access_bar)
+ group = "Reagents"
+
+/datum/supply_pack/softdrink_reagents
+ name = "Bar soft drink dispenser refill"
+ contains = list(
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/water,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/icetea,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cola,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/smw,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/dr_gibb,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceup,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/watermelon,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon
+ )
+ cost = 50
+ containertype = /obj/structure/closet/crate
+ containername = "soft drinks crate"
+ group = "Reagents"
+
+/datum/supply_pack/coffee_reagents
+ name = "Coffee machine dispenser refill"
+ contains = list(
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cafe_latte,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/soy_latte,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/hot_coco,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/milk,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice
+ )
+ cost = 50
+ containertype = /obj/structure/closet/crate
+ containername = "coffee drinks crate"
+ group = "Reagents"
+
+/datum/supply_pack/dispenser_cartridges
+ name = "Empty dispenser cartridges"
+ contains = list(
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge
+ )
+ cost = 15
+ containertype = /obj/structure/closet/crate
+ containername = "dispenser cartridge crate"
+ group = "Reagents"
+
+#define SEC_PACK(_tname, _type, _name, _cname, _cost, _access)\
+ datum/supply_pack/dispenser_cartridges{\
+ _tname {\
+ name = _name ;\
+ containername = _cname ;\
+ containertype = /obj/structure/closet/crate/secure;\
+ access = list( _access );\
+ cost = _cost ;\
+ contains = list( _type , _type );\
+ group = "Reagent Cartridges"\
+ }\
+ }
+#define PACK(_tname, _type, _name, _cname, _cost)\
+ datum/supply_pack/dispenser_cartridges{\
+ _tname {\
+ name = _name ;\
+ containername = _cname ;\
+ containertype = /obj/structure/closet/crate;\
+ cost = _cost ;\
+ contains = list( _type , _type );\
+ group = "Reagent Cartridges"\
+ }\
+ }
+
+// Chemistry-restricted (raw reagents excluding sugar/water)
+// Datum path Contents type Supply pack name Container name Cost Container access
+SEC_PACK(hydrogen, /obj/item/weapon/reagent_containers/chem_disp_cartridge/hydrogen, "Reagent refill - Hydrogen", "hydrogen reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(lithium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/lithium, "Reagent refill - Lithium", "lithium reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(carbon, /obj/item/weapon/reagent_containers/chem_disp_cartridge/carbon, "Reagent refill - Carbon", "carbon reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(nitrogen, /obj/item/weapon/reagent_containers/chem_disp_cartridge/nitrogen, "Reagent refill - Nitrogen", "nitrogen reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(oxygen, /obj/item/weapon/reagent_containers/chem_disp_cartridge/oxygen, "Reagent refill - Oxygen", "oxygen reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(fluorine, /obj/item/weapon/reagent_containers/chem_disp_cartridge/fluorine, "Reagent refill - Fluorine", "fluorine reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(sodium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodium, "Reagent refill - Sodium", "sodium reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(aluminium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/aluminum, "Reagent refill - Aluminum", "aluminum reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(silicon, /obj/item/weapon/reagent_containers/chem_disp_cartridge/silicon, "Reagent refill - Silicon", "silicon reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(phosphorus,/obj/item/weapon/reagent_containers/chem_disp_cartridge/phosphorus, "Reagent refill - Phosphorus", "phosphorus reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(sulfur, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sulfur, "Reagent refill - Sulfur", "sulfur reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(chlorine, /obj/item/weapon/reagent_containers/chem_disp_cartridge/chlorine, "Reagent refill - Chlorine", "chlorine reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(potassium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/potassium, "Reagent refill - Potassium", "potassium reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(iron, /obj/item/weapon/reagent_containers/chem_disp_cartridge/iron, "Reagent refill - Iron", "iron reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(copper, /obj/item/weapon/reagent_containers/chem_disp_cartridge/copper, "Reagent refill - Copper", "copper reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(mercury, /obj/item/weapon/reagent_containers/chem_disp_cartridge/mercury, "Reagent refill - Mercury", "mercury reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(radium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/radium, "Reagent refill - Radium", "radium reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(ethanol, /obj/item/weapon/reagent_containers/chem_disp_cartridge/ethanol, "Reagent refill - Ethanol", "ethanol reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(sacid, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sacid, "Reagent refill - Sulfuric Acid", "sulfuric acid reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(tungsten, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tungsten, "Reagent refill - Tungsten", "tungsten reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(calcium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/calcium, "Reagent refill - Calcium", "calcium reagent cartridge crate", 15, access_chemistry)
+
+// Bar-restricted (alcoholic drinks)
+// Datum path Contents type Supply pack name Container name Cost Container access
+SEC_PACK(beer, /obj/item/weapon/reagent_containers/chem_disp_cartridge/beer, "Reagent refill - Beer", "beer reagent cartridge crate", 15, access_bar)
+SEC_PACK(kahlua, /obj/item/weapon/reagent_containers/chem_disp_cartridge/kahlua, "Reagent refill - Kahlua", "kahlua reagent cartridge crate", 15, access_bar)
+SEC_PACK(whiskey, /obj/item/weapon/reagent_containers/chem_disp_cartridge/whiskey, "Reagent refill - Whiskey", "whiskey reagent cartridge crate", 15, access_bar)
+SEC_PACK(wine, /obj/item/weapon/reagent_containers/chem_disp_cartridge/wine, "Reagent refill - Wine", "wine reagent cartridge crate", 15, access_bar)
+SEC_PACK(vodka, /obj/item/weapon/reagent_containers/chem_disp_cartridge/vodka, "Reagent refill - Vodka", "vodka reagent cartridge crate", 15, access_bar)
+SEC_PACK(gin, /obj/item/weapon/reagent_containers/chem_disp_cartridge/gin, "Reagent refill - Gin", "gin reagent cartridge crate", 15, access_bar)
+SEC_PACK(rum, /obj/item/weapon/reagent_containers/chem_disp_cartridge/rum, "Reagent refill - Rum", "rum reagent cartridge crate", 15, access_bar)
+SEC_PACK(tequila, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tequila, "Reagent refill - Tequila", "tequila reagent cartridge crate", 15, access_bar)
+SEC_PACK(vermouth, /obj/item/weapon/reagent_containers/chem_disp_cartridge/vermouth, "Reagent refill - Vermouth", "vermouth reagent cartridge crate", 15, access_bar)
+SEC_PACK(cognac, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cognac, "Reagent refill - Cognac", "cognac reagent cartridge crate", 15, access_bar)
+SEC_PACK(ale, /obj/item/weapon/reagent_containers/chem_disp_cartridge/ale, "Reagent refill - Ale", "ale reagent cartridge crate", 15, access_bar)
+SEC_PACK(mead, /obj/item/weapon/reagent_containers/chem_disp_cartridge/mead, "Reagent refill - Mead", "mead reagent cartridge crate", 15, access_bar)
+
+// Unrestricted (water, sugar, non-alcoholic drinks)
+// Datum path Contents type Supply pack name Container name Cost
+PACK(water, /obj/item/weapon/reagent_containers/chem_disp_cartridge/water, "Reagent refill - Water", "water reagent cartridge crate", 15)
+PACK(sugar, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar, "Reagent refill - Sugar", "sugar reagent cartridge crate", 15)
+PACK(ice, /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice, "Reagent refill - Ice", "ice reagent cartridge crate", 15)
+PACK(tea, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tea, "Reagent refill - Tea", "tea reagent cartridge crate", 15)
+PACK(icetea, /obj/item/weapon/reagent_containers/chem_disp_cartridge/icetea, "Reagent refill - Iced Tea", "iced tea reagent cartridge crate", 15)
+PACK(cola, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cola, "Reagent refill - Space Cola", "\improper Space Cola reagent cartridge crate", 15)
+PACK(smw, /obj/item/weapon/reagent_containers/chem_disp_cartridge/smw, "Reagent refill - Space Mountain Wind", "\improper Space Mountain Wind reagent cartridge crate", 15)
+PACK(dr_gibb, /obj/item/weapon/reagent_containers/chem_disp_cartridge/dr_gibb, "Reagent refill - Dr. Gibb", "\improper Dr. Gibb reagent cartridge crate", 15)
+PACK(spaceup, /obj/item/weapon/reagent_containers/chem_disp_cartridge/spaceup, "Reagent refill - Space-Up", "\improper Space-Up reagent cartridge crate", 15)
+PACK(tonic, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tonic, "Reagent refill - Tonic Water", "tonic water reagent cartridge crate", 15)
+PACK(sodawater, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sodawater, "Reagent refill - Soda Water", "soda water reagent cartridge crate", 15)
+PACK(lemon_lime, /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon_lime, "Reagent refill - Lemon-Lime Juice", "lemon-lime juice reagent cartridge crate", 15)
+PACK(orange, /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange, "Reagent refill - Orange Juice", "orange juice reagent cartridge crate", 15)
+PACK(lime, /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime, "Reagent refill - Lime Juice", "lime juice reagent cartridge crate", 15)
+PACK(lemon, /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon, "Reagent refill - Lemon Juice", "lemon juice reagent cartridge crate", 15)
+PACK(watermelon, /obj/item/weapon/reagent_containers/chem_disp_cartridge/watermelon, "Reagent refill - Watermelon Juice", "watermelon juice reagent cartridge crate", 15)
+PACK(coffee, /obj/item/weapon/reagent_containers/chem_disp_cartridge/coffee, "Reagent refill - Coffee", "coffee reagent cartridge crate", 15)
+PACK(cafe_latte, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cafe_latte, "Reagent refill - Cafe Latte", "cafe latte reagent cartridge crate", 15)
+PACK(soy_latte, /obj/item/weapon/reagent_containers/chem_disp_cartridge/soy_latte, "Reagent refill - Soy Latte", "soy latte reagent cartridge crate", 15)
+PACK(hot_coco, /obj/item/weapon/reagent_containers/chem_disp_cartridge/hot_coco, "Reagent refill - Hot Coco", "hot coco reagent cartridge crate", 15)
+PACK(milk, /obj/item/weapon/reagent_containers/chem_disp_cartridge/milk, "Reagent refill - Milk", "milk reagent cartridge crate", 15)
+PACK(cream, /obj/item/weapon/reagent_containers/chem_disp_cartridge/cream, "Reagent refill - Cream", "cream reagent cartridge crate", 15)
+
+#undef SEC_PACK
+#undef PACK
diff --git a/code/modules/reagents/distilling/distilling.dm b/code/modules/reagents/machinery/distillery.dm
similarity index 92%
rename from code/modules/reagents/distilling/distilling.dm
rename to code/modules/reagents/machinery/distillery.dm
index 4bd8bd163ee..d64d8b32114 100644
--- a/code/modules/reagents/distilling/distilling.dm
+++ b/code/modules/reagents/machinery/distillery.dm
@@ -53,31 +53,16 @@
var/image/overlay_dumping
var/image/overlay_connected
-// Our unique beaker, used in its unique recipes to ensure things can only react inside this machine and minimize oddities from trying to transfer to a machine and back.
- var/obj/item/weapon/reagent_containers/glass/distilling/Reservoir
-
var/obj/item/weapon/reagent_containers/glass/InputBeaker
var/obj/item/weapon/reagent_containers/glass/OutputBeaker
// A multiplier for the production amount. This should really only ever be lower than one, otherwise you end up with duping.
var/efficiency = 1
-/obj/item/weapon/reagent_containers/glass/distilling
- name = "distilling chamber"
- desc = "You should not be seeing this."
- volume = 600
-
- var/obj/machinery/portable_atmospherics/powered/reagent_distillery/Master
-
-/obj/item/weapon/reagent_containers/glass/distilling/Destroy()
- Master = null
- ..()
-
/obj/machinery/portable_atmospherics/powered/reagent_distillery/Initialize()
. = ..()
- Reservoir = new (src)
- Reservoir.Master = src
+ create_reagents(600, /datum/reagents/distilling)
if(!base_state)
base_state = icon_state
@@ -107,8 +92,6 @@
overlay_connected = image(icon = src.icon, icon_state = "[base_state]-connector")
/obj/machinery/portable_atmospherics/powered/reagent_distillery/Destroy()
- qdel(Reservoir)
- Reservoir = null
if(InputBeaker)
qdel(InputBeaker)
InputBeaker = null
@@ -134,8 +117,8 @@
else
. += "\The [src]'s input beaker is empty!"
- if(Reservoir.reagents.reagent_list.len)
- . += "\The [src]'s internal buffer holds [Reservoir.reagents.total_volume] units of liquid."
+ if(reagents.reagent_list.len)
+ . += "\The [src]'s internal buffer holds [reagents.total_volume] units of liquid."
else
. += "\The [src]'s internal buffer is empty!"
@@ -164,7 +147,7 @@
to_chat(user, "You press \the [src]'s chamber agitator button.")
if(on)
visible_message("\The [src] rattles to life.")
- Reservoir.reagents.handle_reactions()
+ reagents.handle_reactions()
else
spawn(1 SECOND)
to_chat(user, "Nothing happens..")
@@ -341,12 +324,12 @@
visible_message("\The [src]'s motors wind down.")
on = FALSE
- if(InputBeaker && Reservoir.reagents.total_volume < Reservoir.reagents.maximum_volume)
- InputBeaker.reagents.trans_to_holder(Reservoir.reagents, amount = rand(10,20))
+ if(InputBeaker && reagents.total_volume < reagents.maximum_volume)
+ InputBeaker.reagents.trans_to_holder(reagents, amount = rand(10,20))
if(OutputBeaker && OutputBeaker.reagents.total_volume < OutputBeaker.reagents.maximum_volume)
use_power(power_rating * CELLRATE * 0.5)
- Reservoir.reagents.trans_to_holder(OutputBeaker.reagents, amount = rand(1, 5))
+ reagents.trans_to_holder(OutputBeaker.reagents, amount = rand(1, 5))
update_icon()
diff --git a/code/modules/reagents/machinery/grinder.dm b/code/modules/reagents/machinery/grinder.dm
new file mode 100644
index 00000000000..f913f7947b2
--- /dev/null
+++ b/code/modules/reagents/machinery/grinder.dm
@@ -0,0 +1,268 @@
+/obj/machinery/reagentgrinder
+
+ name = "All-In-One Grinder"
+ desc = "Grinds stuff into itty bitty bits."
+ icon = 'icons/obj/kitchen.dmi'
+ icon_state = "juicer1"
+ density = 0
+ anchored = 0
+ use_power = USE_POWER_IDLE
+ idle_power_usage = 5
+ active_power_usage = 100
+ circuit = /obj/item/weapon/circuitboard/grinder
+ var/inuse = 0
+ var/obj/item/weapon/reagent_containers/beaker = null
+ var/limit = 10
+ var/list/holdingitems = list()
+ var/list/sheet_reagents = list( //have a number of reageents divisible by REAGENTS_PER_SHEET (default 20) unless you like decimals,
+ /obj/item/stack/material/iron = list("iron"),
+ /obj/item/stack/material/uranium = list("uranium"),
+ /obj/item/stack/material/phoron = list("phoron"),
+ /obj/item/stack/material/gold = list("gold"),
+ /obj/item/stack/material/silver = list("silver"),
+ /obj/item/stack/material/platinum = list("platinum"),
+ /obj/item/stack/material/mhydrogen = list("hydrogen"),
+ /obj/item/stack/material/steel = list("iron", "carbon"),
+ /obj/item/stack/material/plasteel = list("iron", "iron", "carbon", "carbon", "platinum"), //8 iron, 8 carbon, 4 platinum,
+ /obj/item/stack/material/snow = list("water"),
+ /obj/item/stack/material/sandstone = list("silicon", "oxygen"),
+ /obj/item/stack/material/glass = list("silicon"),
+ /obj/item/stack/material/glass/phoronglass = list("platinum", "silicon", "silicon", "silicon"), //5 platinum, 15 silicon,
+ )
+
+ var/static/radial_examine = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_examine")
+ var/static/radial_eject = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_eject")
+ var/static/radial_grind = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_grind")
+ // var/static/radial_juice = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_juice")
+ // var/static/radial_mix = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_mix")
+
+/obj/machinery/reagentgrinder/Initialize()
+ . = ..()
+ beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
+ default_apply_parts()
+
+/obj/machinery/reagentgrinder/examine(mob/user)
+ . = ..()
+ if(!in_range(user, src) && !issilicon(user) && !isobserver(user))
+ . += "You're too far away to examine [src]'s contents and display!"
+ return
+
+ if(inuse)
+ . += "\The [src] is operating."
+ return
+
+ if(beaker || length(holdingitems))
+ . += "\The [src] contains:"
+ if(beaker)
+ . += "- \A [beaker]."
+ for(var/i in holdingitems)
+ var/obj/item/O = i
+ . += "- \A [O.name]."
+
+ if(!(stat & (NOPOWER|BROKEN)))
+ . += "The status display reads:\n"
+ if(beaker)
+ for(var/datum/reagent/R in beaker.reagents.reagent_list)
+ . += "- [R.volume] units of [R.name]."
+
+/obj/machinery/reagentgrinder/update_icon()
+ icon_state = "juicer"+num2text(!isnull(beaker))
+ return
+
+/obj/machinery/reagentgrinder/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ if(beaker)
+ if(default_deconstruction_screwdriver(user, O))
+ return
+ if(default_deconstruction_crowbar(user, O))
+ return
+
+ //VOREStation edit start - for solargrubs
+ if (istype(O, /obj/item/device/multitool))
+ return ..()
+ //VOREStation edit end
+
+ if (istype(O,/obj/item/weapon/reagent_containers/glass) || \
+ istype(O,/obj/item/weapon/reagent_containers/food/drinks/glass2) || \
+ istype(O,/obj/item/weapon/reagent_containers/food/drinks/shaker))
+
+ if (beaker)
+ return 1
+ else
+ src.beaker = O
+ user.drop_item()
+ O.loc = src
+ update_icon()
+ src.updateUsrDialog()
+ return 0
+
+ if(holdingitems && holdingitems.len >= limit)
+ to_chat(user, "The machine cannot hold anymore items.")
+ return 1
+
+ if(!istype(O))
+ return
+
+ if(istype(O,/obj/item/weapon/storage/bag/plants))
+ var/obj/item/weapon/storage/bag/plants/bag = O
+ var/failed = 1
+ for(var/obj/item/G in O.contents)
+ if(!G.reagents || !G.reagents.total_volume)
+ continue
+ failed = 0
+ bag.remove_from_storage(G, src)
+ holdingitems += G
+ if(holdingitems && holdingitems.len >= limit)
+ break
+
+ if(failed)
+ to_chat(user, "Nothing in the plant bag is usable.")
+ return 1
+
+ if(!O.contents.len)
+ to_chat(user, "You empty \the [O] into \the [src].")
+ else
+ to_chat(user, "You fill \the [src] from \the [O].")
+
+ src.updateUsrDialog()
+ return 0
+
+ if(istype(O,/obj/item/weapon/gripper))
+ var/obj/item/weapon/gripper/B = O //B, for Borg.
+ if(!B.wrapped)
+ to_chat(user, "\The [B] is not holding anything.")
+ return 0
+ else
+ var/B_held = B.wrapped
+ to_chat(user, "You use \the [B] to load \the [src] with \the [B_held].")
+
+ return 0
+
+ if(!sheet_reagents[O.type] && (!O.reagents || !O.reagents.total_volume))
+ to_chat(user, "\The [O] is not suitable for blending.")
+ return 1
+
+ user.remove_from_mob(O)
+ O.loc = src
+ holdingitems += O
+ return 0
+
+/obj/machinery/reagentgrinder/AltClick(mob/user)
+ . = ..()
+ if(user.incapacitated() || !Adjacent(user))
+ return
+ replace_beaker(user)
+
+/obj/machinery/reagentgrinder/attack_hand(mob/user as mob)
+ interact(user)
+
+/obj/machinery/reagentgrinder/interact(mob/user as mob) // The microwave Menu //I am reasonably certain that this is not a microwave
+ if(inuse || user.incapacitated())
+ return
+
+ var/list/options = list()
+
+ if(beaker || length(holdingitems))
+ options["eject"] = radial_eject
+
+ if(isAI(user))
+ if(stat & NOPOWER)
+ return
+ options["examine"] = radial_examine
+
+ // if there is no power or it's broken, the procs will fail but the buttons will still show
+ if(length(holdingitems))
+ options["grind"] = radial_grind
+
+ var/choice
+ if(length(options) < 1)
+ return
+ if(length(options) == 1)
+ for(var/key in options)
+ choice = key
+ else
+ choice = show_radial_menu(user, src, options, require_near = !issilicon(user))
+
+ // post choice verification
+ if(inuse || (isAI(user) && stat & NOPOWER) || user.incapacitated())
+ return
+
+ switch(choice)
+ if("eject")
+ eject(user)
+ if("grind")
+ grind(user)
+ if("examine")
+ examine(user)
+
+/obj/machinery/reagentgrinder/proc/eject(mob/user)
+ if(user.incapacitated())
+ return
+ for(var/obj/item/O in holdingitems)
+ O.loc = src.loc
+ holdingitems -= O
+ holdingitems.Cut()
+ if(beaker)
+ replace_beaker(user)
+
+/obj/machinery/reagentgrinder/proc/grind()
+
+ power_change()
+ if(stat & (NOPOWER|BROKEN))
+ return
+
+ // Sanity check.
+ if (!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume))
+ return
+
+ playsound(src, 'sound/machines/blender.ogg', 50, 1)
+ inuse = 1
+
+ // Reset the machine.
+ spawn(60)
+ inuse = 0
+
+ // Process.
+ for (var/obj/item/O in holdingitems)
+
+ var/remaining_volume = beaker.reagents.maximum_volume - beaker.reagents.total_volume
+ if(remaining_volume <= 0)
+ break
+
+ if(sheet_reagents[O.type])
+ var/obj/item/stack/stack = O
+ if(istype(stack))
+ var/list/sheet_components = sheet_reagents[stack.type]
+ var/amount_to_take = max(0,min(stack.amount,round(remaining_volume/REAGENTS_PER_SHEET)))
+ if(amount_to_take)
+ stack.use(amount_to_take)
+ if(QDELETED(stack))
+ holdingitems -= stack
+ if(islist(sheet_components))
+ amount_to_take = (amount_to_take/(sheet_components.len))
+ for(var/i in sheet_components)
+ beaker.reagents.add_reagent(i, (amount_to_take*REAGENTS_PER_SHEET))
+ else
+ beaker.reagents.add_reagent(sheet_components, (amount_to_take*REAGENTS_PER_SHEET))
+ continue
+
+ if(O.reagents)
+ O.reagents.trans_to_obj(beaker, min(O.reagents.total_volume, remaining_volume))
+ if(O.reagents.total_volume == 0)
+ holdingitems -= O
+ qdel(O)
+ if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
+ break
+
+/obj/machinery/reagentgrinder/proc/replace_beaker(mob/living/user, obj/item/weapon/reagent_containers/new_beaker)
+ if(!user)
+ return FALSE
+ if(beaker)
+ if(!user.incapacitated() && Adjacent(user))
+ user.put_in_hands(beaker)
+ else
+ beaker.forceMove(drop_location())
+ beaker = null
+ if(new_beaker)
+ beaker = new_beaker
+ update_icon()
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/reagents/reactions/_reactions.dm b/code/modules/reagents/reactions/_reactions.dm
new file mode 100644
index 00000000000..d63967d9007
--- /dev/null
+++ b/code/modules/reagents/reactions/_reactions.dm
@@ -0,0 +1,128 @@
+//helper that ensures the reaction rate holds after iterating
+//Ex. REACTION_RATE(0.3) means that 30% of the reagents will react each chemistry tick (~2 seconds by default).
+#define REACTION_RATE(rate) (1.0 - (1.0-rate)**(1.0/PROCESS_REACTION_ITER))
+
+//helper to define reaction rate in terms of half-life
+//Ex.
+//HALF_LIFE(0) -> Reaction completes immediately (default chems)
+//HALF_LIFE(1) -> Half of the reagents react immediately, the rest over the following ticks.
+//HALF_LIFE(2) -> Half of the reagents are consumed after 2 chemistry ticks.
+//HALF_LIFE(3) -> Half of the reagents are consumed after 3 chemistry ticks.
+#define HALF_LIFE(ticks) (ticks? 1.0 - (0.5)**(1.0/(ticks*PROCESS_REACTION_ITER)) : 1.0)
+
+/decl/chemical_reaction
+ var/name = null
+ var/id = null
+ var/result = null
+ var/list/required_reagents = list()
+ var/list/catalysts = list()
+ var/list/inhibitors = list()
+ var/result_amount = 0
+
+ //how far the reaction proceeds each time it is processed. Used with either REACTION_RATE or HALF_LIFE macros.
+ var/reaction_rate = HALF_LIFE(0)
+
+ //if less than 1, the reaction will be inhibited if the ratio of products/reagents is too high.
+ //0.5 = 50% yield -> reaction will only proceed halfway until products are removed.
+ var/yield = 1.0
+
+ //If limits on reaction rate would leave less than this amount of any reagent (adjusted by the reaction ratios),
+ //the reaction goes to completion. This is to prevent reactions from going on forever with tiny reagent amounts.
+ var/min_reaction = 2
+
+ var/mix_message = "The solution begins to bubble."
+ var/reaction_sound = 'sound/effects/bubbles.ogg'
+
+ var/log_is_important = 0 // If this reaction should be considered important for logging. Important recipes message admins when mixed, non-important ones just log to file.
+
+/decl/chemical_reaction/proc/can_happen(var/datum/reagents/holder)
+ //check that all the required reagents are present
+ if(!holder.has_all_reagents(required_reagents))
+ return FALSE
+
+ //check that all the required catalysts are present in the required amount
+ if(!holder.has_all_reagents(catalysts))
+ return FALSE
+
+ //check that none of the inhibitors are present in the required amount
+ if(holder.has_any_reagent(inhibitors))
+ return FALSE
+
+ return TRUE
+
+/decl/chemical_reaction/proc/calc_reaction_progress(var/datum/reagents/holder, var/reaction_limit)
+ var/progress = reaction_limit * reaction_rate //simple exponential progression
+
+ //calculate yield
+ if(1-yield > 0.001) //if yield ratio is big enough just assume it goes to completion
+ /*
+ Determine the max amount of product by applying the yield condition:
+ (max_product/result_amount) / reaction_limit == yield/(1-yield)
+
+ We make use of the fact that:
+ reaction_limit = (holder.get_reagent_amount(reactant) / required_reagents[reactant]) of the limiting reagent.
+ */
+ var/yield_ratio = yield/(1-yield)
+ var/max_product = yield_ratio * reaction_limit * result_amount //rearrange to obtain max_product
+ var/yield_limit = max(0, max_product - holder.get_reagent_amount(result))/result_amount
+
+ progress = min(progress, yield_limit) //apply yield limit
+
+ //apply min reaction progress - wasn't sure if this should go before or after applying yield
+ //I guess people can just have their miniscule reactions go to completion regardless of yield.
+ for(var/reactant in required_reagents)
+ var/remainder = holder.get_reagent_amount(reactant) - progress*required_reagents[reactant]
+ if(remainder <= min_reaction*required_reagents[reactant])
+ progress = reaction_limit
+ break
+
+ return progress
+
+/decl/chemical_reaction/process(var/datum/reagents/holder)
+ //determine how far the reaction can proceed
+ var/list/reaction_limits = list()
+ for(var/reactant in required_reagents)
+ reaction_limits += holder.get_reagent_amount(reactant) / required_reagents[reactant]
+
+ //determine how far the reaction proceeds
+ var/reaction_limit = min(reaction_limits)
+ var/progress_limit = calc_reaction_progress(holder, reaction_limit)
+
+ var/reaction_progress = min(reaction_limit, progress_limit) //no matter what, the reaction progress cannot exceed the stoichiometric limit.
+
+ //need to obtain the new reagent's data before anything is altered
+ var/data = send_data(holder, reaction_progress)
+
+ //remove the reactants
+ for(var/reactant in required_reagents)
+ var/amt_used = required_reagents[reactant] * reaction_progress
+ holder.remove_reagent(reactant, amt_used, safety = 1)
+
+ //add the product
+ var/amt_produced = result_amount * reaction_progress
+ if(result)
+ holder.add_reagent(result, amt_produced, data, safety = 1)
+
+ on_reaction(holder, amt_produced)
+
+ return reaction_progress
+
+//called when a reaction processes
+/decl/chemical_reaction/proc/on_reaction(var/datum/reagents/holder, var/created_volume)
+ return
+
+//called after processing reactions, if they occurred
+/decl/chemical_reaction/proc/post_reaction(var/datum/reagents/holder)
+ var/atom/container = holder.my_atom
+ if(mix_message && container && !ismob(container))
+ var/turf/T = get_turf(container)
+ var/list/seen = viewers(4, T)
+ for(var/mob/M in seen)
+ if(M.client)
+ M.show_message("[bicon(container)] [mix_message]", 1)
+ playsound(T, reaction_sound, 80, 1)
+
+//obtains any special data that will be provided to the reaction products
+//this is called just before reactants are removed.
+/decl/chemical_reaction/proc/send_data(var/datum/reagents/holder, var/reaction_limit)
+ return null
\ No newline at end of file
diff --git a/code/modules/reagents/distilling/Distilling-Recipes.dm b/code/modules/reagents/reactions/distilling/distilling.dm
similarity index 74%
rename from code/modules/reagents/distilling/Distilling-Recipes.dm
rename to code/modules/reagents/reactions/distilling/distilling.dm
index 0736ac7e61d..5944a758462 100644
--- a/code/modules/reagents/distilling/Distilling-Recipes.dm
+++ b/code/modules/reagents/reactions/distilling/distilling.dm
@@ -1,4 +1,4 @@
-/datum/chemical_reaction/distilling
+/decl/chemical_reaction/distilling
// name = null
// id = null
// result = null
@@ -26,32 +26,19 @@
var/list/temp_range = list(T0C, T20C)
var/temp_shift = 0 // How much the temperature changes when the reaction occurs.
-/datum/chemical_reaction/distilling/can_happen(var/datum/reagents/holder)
- //check that all the required reagents are present
- if(!holder.has_all_reagents(required_reagents))
- return 0
+/decl/chemical_reaction/distilling/can_happen(var/datum/reagents/holder)
+ if(!istype(holder, /datum/reagents/distilling) || !istype(holder.my_atom, /obj/machinery/portable_atmospherics/powered/reagent_distillery))
+ return FALSE
- //check that all the required catalysts are present in the required amount
- if(!holder.has_all_reagents(catalysts))
- return 0
+ // Super special temperature check.
+ var/obj/machinery/portable_atmospherics/powered/reagent_distillery/RD = holder.my_atom
+ if(RD.current_temp < temp_range[1] || RD.current_temp > temp_range[2])
+ return FALSE
- //check that none of the inhibitors are present in the required amount
- if(holder.has_any_reagent(inhibitors))
- return 0
-
- if(!istype(holder.my_atom, /obj/item/weapon/reagent_containers/glass/distilling))
- return 0
-
- else // Super special temperature check.
- var/obj/item/weapon/reagent_containers/glass/distilling/D = holder.my_atom
- var/obj/machinery/portable_atmospherics/powered/reagent_distillery/RD = D.Master
- if(RD.current_temp < temp_range[1] || RD.current_temp > temp_range[2])
- return 0
-
- return 1
+ return ..()
/*
-/datum/chemical_reaction/distilling/on_reaction(var/datum/reagents/holder, var/created_volume)
+/decl/chemical_reaction/distilling/on_reaction(var/datum/reagents/holder, var/created_volume)
if(istype(holder.my_atom, /obj/item/weapon/reagent_containers/glass/distilling))
var/obj/item/weapon/reagent_containers/glass/distilling/D = holder.my_atom
var/obj/machinery/portable_atmospherics/powered/reagent_distillery/RD = D.Master
@@ -62,7 +49,7 @@
// Subtypes //
// Biomass
-/datum/chemical_reaction/distilling/biomass
+/decl/chemical_reaction/distilling/biomass
name = "Distilling Biomass"
id = "distill_biomass"
result = "biomass"
@@ -73,7 +60,7 @@
temp_shift = -2
// Medicinal
-/datum/chemical_reaction/distilling/inaprovalaze
+/decl/chemical_reaction/distilling/inaprovalaze
name = "Distilling Inaprovalaze"
id = "distill_inaprovalaze"
result = "inaprovalaze"
@@ -84,7 +71,7 @@
temp_range = list(T0C + 100, T0C + 120)
-/datum/chemical_reaction/distilling/bicaridaze
+/decl/chemical_reaction/distilling/bicaridaze
name = "Distilling Bicaridaze"
id = "distill_bicaridaze"
result = "bicaridaze"
@@ -95,7 +82,7 @@
temp_range = list(T0C + 110, T0C + 130)
-/datum/chemical_reaction/distilling/dermalaze
+/decl/chemical_reaction/distilling/dermalaze
name = "Distilling Dermalaze"
id = "distill_dermalaze"
result = "dermalaze"
@@ -106,7 +93,7 @@
temp_range = list(T0C + 115, T0C + 130)
-/datum/chemical_reaction/distilling/spacomycaze
+/decl/chemical_reaction/distilling/spacomycaze
name = "Distilling Spacomycaze"
id = "distill_spacomycaze"
result = "spacomycaze"
@@ -117,7 +104,7 @@
temp_range = list(T0C + 100, T0C + 120)
-/datum/chemical_reaction/distilling/tricorlidaze
+/decl/chemical_reaction/distilling/tricorlidaze
name = "Distilling Tricorlidaze"
id = "distill_tricorlidaze"
result = "tricorlidaze"
@@ -128,7 +115,7 @@
temp_range = list(T0C + 100, T0C + 120)
-/datum/chemical_reaction/distilling/synthplas
+/decl/chemical_reaction/distilling/synthplas
name = "Distilling Synthplas"
id = "distill_synthplas"
result = "synthblood_dilute"
@@ -140,7 +127,7 @@
temp_range = list(T0C + 110, T0C + 130)
// Alcohol
-/datum/chemical_reaction/distilling/beer
+/decl/chemical_reaction/distilling/beer
name = "Distilling Beer"
id = "distill_beer"
result = "beer"
@@ -151,7 +138,7 @@
temp_range = list(T20C, T20C + 2)
-/datum/chemical_reaction/distilling/ale
+/decl/chemical_reaction/distilling/ale
name = "Distilling Ale"
id = "distill_ale"
result = "ale"
@@ -165,7 +152,7 @@
temp_range = list(T0C + 7, T0C + 13)
// Unique
-/datum/chemical_reaction/distilling/berserkjuice
+/decl/chemical_reaction/distilling/berserkjuice
name = "Distilling Brute Juice"
id = "distill_brutejuice"
result = "berserkmed"
@@ -175,7 +162,7 @@
temp_range = list(T0C + 600, T0C + 700)
temp_shift = 4
-/datum/chemical_reaction/distilling/berserkjuice/on_reaction(var/datum/reagents/holder, var/created_volume)
+/decl/chemical_reaction/distilling/berserkjuice/on_reaction(var/datum/reagents/holder, var/created_volume)
..()
if(prob(1))
@@ -183,7 +170,7 @@
explosion(T, -1, rand(-1, 1), rand(1,2), rand(3,5))
return
-/datum/chemical_reaction/distilling/cryogel
+/decl/chemical_reaction/distilling/cryogel
name = "Distilling Cryogellatin"
id = "distill_cryoslurry"
result = "cryoslurry"
@@ -194,7 +181,7 @@
temp_range = list(0, 15)
temp_shift = 20
-/datum/chemical_reaction/distilling/cryogel/on_reaction(var/datum/reagents/holder, var/created_volume)
+/decl/chemical_reaction/distilling/cryogel/on_reaction(var/datum/reagents/holder, var/created_volume)
..()
if(prob(1))
@@ -204,7 +191,7 @@
F.start()
return
-/datum/chemical_reaction/distilling/lichpowder
+/decl/chemical_reaction/distilling/lichpowder
name = "Distilling Lichpowder"
id = "distill_lichpowder"
result = "lichpowder"
@@ -215,7 +202,7 @@
temp_range = list(T0C + 100, T0C + 150)
-/datum/chemical_reaction/distilling/necroxadone
+/decl/chemical_reaction/distilling/necroxadone
name = "Distilling Necroxadone"
id = "distill_necroxadone"
result = "necroxadone"
diff --git a/code/modules/reagents/reactions/fusion/fusion.dm b/code/modules/reagents/reactions/fusion/fusion.dm
new file mode 100644
index 00000000000..7b0acfec96a
--- /dev/null
+++ b/code/modules/reagents/reactions/fusion/fusion.dm
@@ -0,0 +1,6 @@
+// TDOD: Port R-UST fusion reactions to the chemistry system.
+//They'll operate in a similar manner to distillery reactions,
+// but will have distinct behaviours (mostly relating to the fusion field) that warrants a separate type
+/*
+/decl/chemical_reaction/fusion
+ name = "Fusion"*/
\ No newline at end of file
diff --git a/code/modules/reagents/reactions/instant/drinks.dm b/code/modules/reagents/reactions/instant/drinks.dm
new file mode 100644
index 00000000000..2722d7843bc
--- /dev/null
+++ b/code/modules/reagents/reactions/instant/drinks.dm
@@ -0,0 +1,1223 @@
+/decl/chemical_reaction/instant/drinks/coffee
+ name = "Coffee"
+ id = "coffee"
+ result = "coffee"
+ required_reagents = list("water" = 5, "coffeepowder" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/tea
+ name = "Black tea"
+ id = "tea"
+ result = "tea"
+ required_reagents = list("water" = 5, "teapowder" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/hot_coco
+ name = "Hot Coco"
+ id = "hot_coco"
+ result = "hot_coco"
+ required_reagents = list("water" = 5, "coco" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/grapejuice
+ name = "Grape Juice"
+ id = "grapejuice"
+ result = "grapejuice"
+ required_reagents = list("water" = 3, "instantgrape" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/orangejuice
+ name = "Orange Juice"
+ id = "orangejuice"
+ result = "orangejuice"
+ required_reagents = list("water" = 3, "instantorange" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/watermelonjuice
+ name = "Watermelon Juice"
+ id = "watermelonjuice"
+ result = "watermelonjuice"
+ required_reagents = list("water" = 3, "instantwatermelon" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/applejuice
+ name = "Apple Juice"
+ id = "applejuice"
+ result = "applejuice"
+ required_reagents = list("water" = 3, "instantapple" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/goldschlager
+ name = "Goldschlager"
+ id = "goldschlager"
+ result = "goldschlager"
+ required_reagents = list("vodka" = 10, "gold" = 1)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/patron
+ name = "Patron"
+ id = "patron"
+ result = "patron"
+ required_reagents = list("tequilla" = 10, "silver" = 1)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/bilk
+ name = "Bilk"
+ id = "bilk"
+ result = "bilk"
+ required_reagents = list("milk" = 1, "beer" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/icetea
+ name = "Iced Tea"
+ id = "icetea"
+ result = "icetea"
+ required_reagents = list("ice" = 1, "tea" = 2)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/icecoffee
+ name = "Iced Coffee"
+ id = "icecoffee"
+ result = "icecoffee"
+ required_reagents = list("ice" = 1, "coffee" = 2)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/nuka_cola
+ name = "Nuclear Cola"
+ id = "nuka_cola"
+ result = "nuka_cola"
+ required_reagents = list("uranium" = 1, "cola" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/moonshine
+ name = "Moonshine"
+ id = "moonshine"
+ result = "moonshine"
+ required_reagents = list("nutriment" = 10)
+ catalysts = list("enzyme" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/grenadine
+ name = "Grenadine Syrup"
+ id = "grenadine"
+ result = "grenadine"
+ required_reagents = list("berryjuice" = 10)
+ catalysts = list("enzyme" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/wine
+ name = "Wine"
+ id = "wine"
+ result = "wine"
+ required_reagents = list("grapejuice" = 10)
+ catalysts = list("enzyme" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/pwine
+ name = "Poison Wine"
+ id = "pwine"
+ result = "pwine"
+ required_reagents = list("poisonberryjuice" = 10)
+ catalysts = list("enzyme" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/melonliquor
+ name = "Melon Liquor"
+ id = "melonliquor"
+ result = "melonliquor"
+ required_reagents = list("watermelonjuice" = 10)
+ catalysts = list("enzyme" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/bluecuracao
+ name = "Blue Curacao"
+ id = "bluecuracao"
+ result = "bluecuracao"
+ required_reagents = list("orangejuice" = 10)
+ catalysts = list("enzyme" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/spacebeer
+ name = "Space Beer"
+ id = "spacebeer"
+ result = "beer"
+ required_reagents = list("cornoil" = 10)
+ catalysts = list("enzyme" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/vodka
+ name = "Vodka"
+ id = "vodka"
+ result = "vodka"
+ required_reagents = list("potatojuice" = 10)
+ catalysts = list("enzyme" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/cider
+ name = "Cider"
+ id = "cider"
+ result = "cider"
+ required_reagents = list("applejuice" = 10)
+ catalysts = list("enzyme" = 5)
+ result_amount = 10
+
+
+/decl/chemical_reaction/instant/drinks/sake
+ name = "Sake"
+ id = "sake"
+ result = "sake"
+ required_reagents = list("rice" = 10)
+ catalysts = list("enzyme" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/kahlua
+ name = "Kahlua"
+ id = "kahlua"
+ result = "kahlua"
+ required_reagents = list("coffee" = 5, "sugar" = 5)
+ catalysts = list("enzyme" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/gin_tonic
+ name = "Gin and Tonic"
+ id = "gintonic"
+ result = "gintonic"
+ required_reagents = list("gin" = 2, "tonic" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/cuba_libre
+ name = "Cuba Libre"
+ id = "cubalibre"
+ result = "cubalibre"
+ required_reagents = list("rum" = 2, "cola" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/martini
+ name = "Classic Martini"
+ id = "martini"
+ result = "martini"
+ required_reagents = list("gin" = 2, "vermouth" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/vodkamartini
+ name = "Vodka Martini"
+ id = "vodkamartini"
+ result = "vodkamartini"
+ required_reagents = list("vodka" = 2, "vermouth" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/white_russian
+ name = "White Russian"
+ id = "whiterussian"
+ result = "whiterussian"
+ required_reagents = list("blackrussian" = 2, "cream" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/whiskey_cola
+ name = "Whiskey Cola"
+ id = "whiskeycola"
+ result = "whiskeycola"
+ required_reagents = list("whiskey" = 2, "cola" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/screwdriver
+ name = "Screwdriver"
+ id = "screwdrivercocktail"
+ result = "screwdrivercocktail"
+ required_reagents = list("vodka" = 2, "orangejuice" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/bloody_mary
+ name = "Bloody Mary"
+ id = "bloodymary"
+ result = "bloodymary"
+ required_reagents = list("vodka" = 2, "tomatojuice" = 3, "limejuice" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/gargle_blaster
+ name = "Pan-Galactic Gargle Blaster"
+ id = "gargleblaster"
+ result = "gargleblaster"
+ required_reagents = list("vodka" = 2, "gin" = 1, "whiskey" = 1, "cognac" = 1, "limejuice" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/brave_bull
+ name = "Brave Bull"
+ id = "bravebull"
+ result = "bravebull"
+ required_reagents = list("tequilla" = 2, "kahlua" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/tequilla_sunrise
+ name = "Tequilla Sunrise"
+ id = "tequillasunrise"
+ result = "tequillasunrise"
+ required_reagents = list("tequilla" = 2, "orangejuice" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/phoron_special
+ name = "Toxins Special"
+ id = "phoronspecial"
+ result = "phoronspecial"
+ required_reagents = list("rum" = 2, "vermouth" = 2, "phoron" = 2)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/beepsky_smash
+ name = "Beepksy Smash"
+ id = "beepksysmash"
+ result = "beepskysmash"
+ required_reagents = list("limejuice" = 1, "whiskey" = 1, "iron" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/doctor_delight
+ name = "The Doctor's Delight"
+ id = "doctordelight"
+ result = "doctorsdelight"
+ required_reagents = list("limejuice" = 1, "tomatojuice" = 1, "orangejuice" = 1, "cream" = 2, "tricordrazine" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/irish_cream
+ name = "Irish Cream"
+ id = "irishcream"
+ result = "irishcream"
+ required_reagents = list("whiskey" = 2, "cream" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/manly_dorf
+ name = "The Manly Dorf"
+ id = "manlydorf"
+ result = "manlydorf"
+ required_reagents = list ("beer" = 1, "ale" = 2)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/hooch
+ name = "Hooch"
+ id = "hooch"
+ result = "hooch"
+ required_reagents = list ("sugar" = 1, "ethanol" = 2, "fuel" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/irish_coffee
+ name = "Irish Coffee"
+ id = "irishcoffee"
+ result = "irishcoffee"
+ required_reagents = list("irishcream" = 1, "coffee" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/b52
+ name = "B-52"
+ id = "b52"
+ result = "b52"
+ required_reagents = list("irishcream" = 1, "kahlua" = 1, "cognac" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/atomicbomb
+ name = "Atomic Bomb"
+ id = "atomicbomb"
+ result = "atomicbomb"
+ required_reagents = list("b52" = 10, "uranium" = 1)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/margarita
+ name = "Margarita"
+ id = "margarita"
+ result = "margarita"
+ required_reagents = list("tequilla" = 2, "limejuice" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/longislandicedtea
+ name = "Long Island Iced Tea"
+ id = "longislandicedtea"
+ result = "longislandicedtea"
+ required_reagents = list("vodka" = 1, "gin" = 1, "tequilla" = 1, "cubalibre" = 3)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/icedtea
+ name = "Long Island Iced Tea"
+ id = "longislandicedtea"
+ result = "longislandicedtea"
+ required_reagents = list("vodka" = 1, "gin" = 1, "tequilla" = 1, "cubalibre" = 3)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/threemileisland
+ name = "Three Mile Island Iced Tea"
+ id = "threemileisland"
+ result = "threemileisland"
+ required_reagents = list("longislandicedtea" = 10, "uranium" = 1)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/whiskeysoda
+ name = "Whiskey Soda"
+ id = "whiskeysoda"
+ result = "whiskeysoda"
+ required_reagents = list("whiskey" = 2, "sodawater" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/black_russian
+ name = "Black Russian"
+ id = "blackrussian"
+ result = "blackrussian"
+ required_reagents = list("vodka" = 2, "kahlua" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/manhattan
+ name = "Manhattan"
+ id = "manhattan"
+ result = "manhattan"
+ required_reagents = list("whiskey" = 2, "vermouth" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/manhattan_proj
+ name = "Manhattan Project"
+ id = "manhattan_proj"
+ result = "manhattan_proj"
+ required_reagents = list("manhattan" = 10, "uranium" = 1)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/vodka_tonic
+ name = "Vodka and Tonic"
+ id = "vodkatonic"
+ result = "vodkatonic"
+ required_reagents = list("vodka" = 2, "tonic" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/gin_fizz
+ name = "Gin Fizz"
+ id = "ginfizz"
+ result = "ginfizz"
+ required_reagents = list("gin" = 1, "sodawater" = 1, "limejuice" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/bahama_mama
+ name = "Bahama mama"
+ id = "bahama_mama"
+ result = "bahama_mama"
+ required_reagents = list("rum" = 2, "orangejuice" = 2, "limejuice" = 1, "ice" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/singulo
+ name = "Singulo"
+ id = "singulo"
+ result = "singulo"
+ required_reagents = list("vodka" = 5, "radium" = 1, "wine" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/alliescocktail
+ name = "Allies Cocktail"
+ id = "alliescocktail"
+ result = "alliescocktail"
+ required_reagents = list("martini" = 1, "vodka" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/demonsblood
+ name = "Demons Blood"
+ id = "demonsblood"
+ result = "demonsblood"
+ required_reagents = list("rum" = 3, "spacemountainwind" = 1, "blood" = 1, "dr_gibb" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/booger
+ name = "Booger"
+ id = "booger"
+ result = "booger"
+ required_reagents = list("cream" = 2, "banana" = 1, "rum" = 1, "watermelonjuice" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/antifreeze
+ name = "Anti-freeze"
+ id = "antifreeze"
+ result = "antifreeze"
+ required_reagents = list("vodka" = 1, "cream" = 1, "ice" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/barefoot
+ name = "Barefoot"
+ id = "barefoot"
+ result = "barefoot"
+ required_reagents = list("berryjuice" = 1, "cream" = 1, "vermouth" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/grapesoda
+ name = "Grape Soda"
+ id = "grapesoda"
+ result = "grapesoda"
+ required_reagents = list("grapejuice" = 2, "cola" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/sbiten
+ name = "Sbiten"
+ id = "sbiten"
+ result = "sbiten"
+ required_reagents = list("vodka" = 10, "capsaicin" = 1)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/red_mead
+ name = "Red Mead"
+ id = "red_mead"
+ result = "red_mead"
+ required_reagents = list("blood" = 1, "mead" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/mead
+ name = "Mead"
+ id = "mead"
+ result = "mead"
+ required_reagents = list("sugar" = 1, "water" = 1)
+ catalysts = list("enzyme" = 5)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/iced_beer
+ name = "Iced Beer"
+ id = "iced_beer"
+ result = "iced_beer"
+ required_reagents = list("beer" = 10, "frostoil" = 1)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/iced_beer2
+ name = "Iced Beer"
+ id = "iced_beer"
+ result = "iced_beer"
+ required_reagents = list("beer" = 5, "ice" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/grog
+ name = "Grog"
+ id = "grog"
+ result = "grog"
+ required_reagents = list("rum" = 1, "water" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/soy_latte
+ name = "Soy Latte"
+ id = "soy_latte"
+ result = "soy_latte"
+ required_reagents = list("coffee" = 1, "soymilk" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/cafe_latte
+ name = "Cafe Latte"
+ id = "cafe_latte"
+ result = "cafe_latte"
+ required_reagents = list("coffee" = 1, "milk" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/acidspit
+ name = "Acid Spit"
+ id = "acidspit"
+ result = "acidspit"
+ required_reagents = list("sacid" = 1, "wine" = 5)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/amasec
+ name = "Amasec"
+ id = "amasec"
+ result = "amasec"
+ required_reagents = list("iron" = 1, "wine" = 5, "vodka" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/changelingsting
+ name = "Changeling Sting"
+ id = "changelingsting"
+ result = "changelingsting"
+ required_reagents = list("screwdrivercocktail" = 1, "limejuice" = 1, "lemonjuice" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/aloe
+ name = "Aloe"
+ id = "aloe"
+ result = "aloe"
+ required_reagents = list("cream" = 1, "whiskey" = 1, "watermelonjuice" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/andalusia
+ name = "Andalusia"
+ id = "andalusia"
+ result = "andalusia"
+ required_reagents = list("rum" = 1, "whiskey" = 1, "lemonjuice" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/snowwhite
+ name = "Snow White"
+ id = "snowwhite"
+ result = "snowwhite"
+ required_reagents = list("pineapplejuice" = 1, "rum" = 1, "lemon_lime" = 1, "egg" = 1, "kahlua" = 1, "sugar" = 1) //VoreStation Edit
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/irishcarbomb
+ name = "Irish Car Bomb"
+ id = "irishcarbomb"
+ result = "irishcarbomb"
+ required_reagents = list("ale" = 1, "irishcream" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/syndicatebomb
+ name = "Syndicate Bomb"
+ id = "syndicatebomb"
+ result = "syndicatebomb"
+ required_reagents = list("beer" = 1, "whiskeycola" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/erikasurprise
+ name = "Erika Surprise"
+ id = "erikasurprise"
+ result = "erikasurprise"
+ required_reagents = list("ale" = 2, "limejuice" = 1, "whiskey" = 1, "banana" = 1, "ice" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/devilskiss
+ name = "Devils Kiss"
+ id = "devilskiss"
+ result = "devilskiss"
+ required_reagents = list("blood" = 1, "kahlua" = 1, "rum" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/hippiesdelight
+ name = "Hippies Delight"
+ id = "hippiesdelight"
+ result = "hippiesdelight"
+ required_reagents = list("psilocybin" = 1, "gargleblaster" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/bananahonk
+ name = "Banana Honk"
+ id = "bananahonk"
+ result = "bananahonk"
+ required_reagents = list("banana" = 1, "cream" = 1, "sugar" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/silencer
+ name = "Silencer"
+ id = "silencer"
+ result = "silencer"
+ required_reagents = list("nothing" = 1, "cream" = 1, "sugar" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/driestmartini
+ name = "Driest Martini"
+ id = "driestmartini"
+ result = "driestmartini"
+ required_reagents = list("nothing" = 1, "gin" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/lemonade
+ name = "Lemonade"
+ id = "lemonade"
+ result = "lemonade"
+ required_reagents = list("lemonjuice" = 1, "sugar" = 1, "water" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/melonade
+ name = "Melonade"
+ id = "melonade"
+ result = "melonade"
+ required_reagents = list("watermelonjuice" = 1, "sugar" = 1, "sodawater" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/appleade
+ name = "Appleade"
+ id = "appleade"
+ result = "appleade"
+ required_reagents = list("applejuice" = 1, "sugar" = 1, "sodawater" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/pineappleade
+ name = "Pineappleade"
+ id = "pineappleade"
+ result = "pineappleade"
+ required_reagents = list("pineapplejuice" = 2, "limejuice" = 1, "sodawater" = 2, "honey" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/driverspunch
+ name = "Driver`s Punch"
+ id = "driverspunch"
+ result = "driverspunch"
+ required_reagents = list("appleade" = 2, "orangejuice" = 1, "mint" = 1, "sodawater" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/mintapplesparkle
+ name = "Mint Apple Sparkle"
+ id = "mintapplesparkle"
+ result = "mintapplesparkle"
+ required_reagents = list("appleade" = 2, "mint" = 1)
+ inhibitors = list("sodawater" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/berrycordial
+ name = "Berry Cordial"
+ id = "berrycordial"
+ result = "berrycordial"
+ required_reagents = list("berryjuice" = 4, "sugar" = 1, "lemonjuice" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/tropicalfizz
+ name = "Tropical Fizz"
+ id = "tropicalfizz"
+ result = "tropicalfizz"
+ required_reagents = list("sodawater" = 6, "berryjuice" = 1, "mint" = 1, "limejuice" = 1, "lemonjuice" = 1, "pineapplejuice" = 1)
+ inhibitors = list("sugar" = 1)
+ result_amount = 8
+
+/decl/chemical_reaction/instant/drinks/melonspritzer
+ name = "Melon Spritzer"
+ id = "melonspritzer"
+ result = "melonspritzer"
+ required_reagents = list("watermelonjuice" = 2, "wine" = 2, "applejuice" = 1, "limejuice" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/fauxfizz
+ name = "Faux Fizz"
+ id = "fauxfizz"
+ result = "fauxfizz"
+ required_reagents = list("sodawater" = 2, "berryjuice" = 1, "applejuice" = 1, "limejuice" = 1, "honey" = 1)
+ inhibitors = list("sugar" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/firepunch
+ name = "Fire Punch"
+ id = "firepunch"
+ result = "firepunch"
+ required_reagents = list("sugar" = 1, "rum" = 2)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/kiraspecial
+ name = "Kira Special"
+ id = "kiraspecial"
+ result = "kiraspecial"
+ required_reagents = list("orangejuice" = 1, "limejuice" = 1, "sodawater" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/brownstar
+ name = "Brown Star"
+ id = "brownstar"
+ result = "brownstar"
+ required_reagents = list("orangejuice" = 2, "cola" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/milkshake
+ name = "Milkshake"
+ id = "milkshake"
+ result = "milkshake"
+ required_reagents = list("cream" = 1, "ice" = 2, "milk" = 2)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/peanutmilkshake
+ name = "Peanutbutter Milkshake"
+ id = "peanutmilkshake"
+ result = "peanutmilkshake"
+ required_reagents = list("cream" = 1, "ice" = 1, "peanutbutter" = 2, "milk" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/rewriter
+ name = "Rewriter"
+ id = "rewriter"
+ result = "rewriter"
+ required_reagents = list("spacemountainwind" = 1, "coffee" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/suidream
+ name = "Sui Dream"
+ id = "suidream"
+ result = "suidream"
+ required_reagents = list("space_up" = 1, "bluecuracao" = 1, "melonliquor" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/shirleytemple
+ name = "Shirley Temple"
+ id = "shirley_temple"
+ result = "shirley_temple"
+ required_reagents = list("gingerale" = 4, "grenadine" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/royrogers
+ name = "Roy Rogers"
+ id = "roy_rogers"
+ result = "roy_rogers"
+ required_reagents = list("shirley_temple" = 5, "lemon_lime" = 2)
+ result_amount = 7
+
+/decl/chemical_reaction/instant/drinks/collinsmix
+ name = "Collins Mix"
+ id = "collins_mix"
+ result = "collins_mix"
+ required_reagents = list("lemon_lime" = 3, "sodawater" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/drinks/arnoldpalmer
+ name = "Arnold Palmer"
+ id = "arnold_palmer"
+ result = "arnold_palmer"
+ required_reagents = list("icetea" = 1, "lemonade" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/minttea
+ name = "Mint Tea"
+ id = "minttea"
+ result = "minttea"
+ required_reagents = list("tea" = 5, "mint" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/lemontea
+ name = "Lemon Tea"
+ id = "lemontea"
+ result = "lemontea"
+ required_reagents = list("tea" = 5, "lemonjuice" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/limetea
+ name = "Lime Tea"
+ id = "limetea"
+ result = "limetea"
+ required_reagents = list("tea" = 5, "limejuice" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/orangetea
+ name = "Orange Tea"
+ id = "orangetea"
+ result = "orangetea"
+ required_reagents = list("tea" = 5, "orangejuice" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/berrytea
+ name = "Berry Tea"
+ id = "berrytea"
+ result = "berrytea"
+ required_reagents = list("tea" = 5, "berryjuice" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/sakebomb
+ name = "Sake Bomb"
+ id = "sakebomb"
+ result = "sakebomb"
+ required_reagents = list("beer" = 2, "sake" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/tamagozake
+ name = "Tamagozake"
+ id = "tamagozake"
+ result = "tamagozake"
+ required_reagents = list("sake" = 10, "sugar" = 5, "egg" = 3)
+ result_amount = 15
+
+/decl/chemical_reaction/instant/drinks/ginzamary
+ name = "Ginza Mary"
+ id = "ginzamary"
+ result = "ginzamary"
+ required_reagents = list("sake" = 2, "vodka" = 2, "tomatojuice" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/tokyorose
+ name = "Tokyo Rose"
+ id = "tokyorose"
+ result = "tokyorose"
+ required_reagents = list("sake" = 1, "berryjuice" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/saketini
+ name = "Saketini"
+ id = "saketini"
+ result = "saketini"
+ required_reagents = list("sake" = 1, "gin" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/elysiumfacepunch
+ name = "Elysium Facepunch"
+ id = "elysiumfacepunch"
+ result = "elysiumfacepunch"
+ required_reagents = list("kahlua" = 1, "lemonjuice" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/erebusmoonrise
+ name = "Erebus Moonrise"
+ id = "erebusmoonrise"
+ result = "erebusmoonrise"
+ required_reagents = list("whiskey" = 1, "vodka" = 1, "tequilla" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/balloon
+ name = "Balloon"
+ id = "balloon"
+ result = "balloon"
+ required_reagents = list("cream" = 1, "bluecuracao" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/natunabrandy
+ name = "Natuna Brandy"
+ id = "natunabrandy"
+ result = "natunabrandy"
+ required_reagents = list("beer" = 1, "sodawater" = 2)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/euphoria
+ name = "Euphoria"
+ id = "euphoria"
+ result = "euphoria"
+ required_reagents = list("specialwhiskey" = 1, "cognac" = 2)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/xanaducannon
+ name = "Xanadu Cannon"
+ id = "xanaducannon"
+ result = "xanaducannon"
+ required_reagents = list("ale" = 1, "dr_gibb" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/debugger
+ name = "Debugger"
+ id = "debugger"
+ result = "debugger"
+ required_reagents = list("fuel" = 1, "sugar" = 2, "cornoil" = 2)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/spacersbrew
+ name = "Spacer's Brew"
+ id = "spacersbrew"
+ result = "spacersbrew"
+ required_reagents = list("brownstar" = 4, "ethanol" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/binmanbliss
+ name = "Binman Bliss"
+ id = "binmanbliss"
+ result = "binmanbliss"
+ required_reagents = list("sake" = 1, "tequilla" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/chrysanthemum
+ name = "Chrysanthemum"
+ id = "chrysanthemum"
+ result = "chrysanthemum"
+ required_reagents = list("sake" = 1, "melonliquor" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/deathbell
+ name = "Deathbell"
+ id = "deathbell"
+ result = "deathbell"
+ required_reagents = list("antifreeze" = 1, "gargleblaster" = 1, "syndicatebomb" =1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/bitters
+ name = "Bitters"
+ id = "bitters"
+ result = "bitters"
+ required_reagents = list("mint" = 5)
+ catalysts = list("enzyme" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/soemmerfire
+ name = "Soemmer Fire"
+ id = "soemmerfire"
+ result = "soemmerfire"
+ required_reagents = list("manhattan" = 2, "condensedcapsaicin" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/winebrandy
+ name = "Wine brandy"
+ id = "winebrandy"
+ result = "winebrandy"
+ required_reagents = list("wine" = 10)
+ catalysts = list("enzyme" = 10) //10u enzyme so it requires more than is usually added. Stops overlap with wine recipe
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/lovepotion
+ name = "Love Potion"
+ id = "lovepotion"
+ result = "lovepotion"
+ required_reagents = list("cream" = 1, "berryjuice" = 1, "sugar" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/morningafter
+ name = "Morning After"
+ id = "morningafter"
+ result = "morningafter"
+ required_reagents = list("sbiten" = 1, "coffee" = 5)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/vesper
+ name = "Vesper"
+ id = "vesper"
+ result = "vesper"
+ required_reagents = list("gin" = 3, "vodka" = 1, "wine" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/drinks/rotgut
+ name = "Rotgut Fever Dream"
+ id = "rotgut"
+ result = "rotgut"
+ required_reagents = list("vodka" = 3, "rum" = 1, "whiskey" = 1, "cola" = 3)
+ result_amount = 8
+
+/decl/chemical_reaction/instant/drinks/entdraught
+ name = "Ent's Draught"
+ id = "entdraught"
+ result = "entdraught"
+ required_reagents = list("tonic" = 1, "holywater" = 1, "honey" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/voxdelight
+ name = "Vox's Delight"
+ id = "voxdelight"
+ result = "voxdelight"
+ required_reagents = list("phoron" = 3, "fuel" = 1, "water" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/drinks/screamingviking
+ name = "Screaming Viking"
+ id = "screamingviking"
+ result = "screamingviking"
+ required_reagents = list("martini" = 2, "vodkatonic" = 2, "limejuice" = 1, "rum" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/vilelemon
+ name = "Vile Lemon"
+ id = "vilelemon"
+ result = "vilelemon"
+ required_reagents = list("lemonade" = 5, "spacemountainwind" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/dreamcream
+ name = "Dream Cream"
+ id = "dreamcream"
+ result = "dreamcream"
+ required_reagents = list("milk" = 2, "cream" = 1, "honey" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/drinks/robustin
+ name = "Robustin"
+ id = "robustin"
+ result = "robustin"
+ required_reagents = list("antifreeze" = 1, "phoron" = 1, "fuel" = 1, "vodka" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/drinks/virginsip
+ name = "Virgin Sip"
+ id = "virginsip"
+ result = "virginsip"
+ required_reagents = list("driestmartini" = 1, "water" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/chocoshake
+ name = "Chocolate Milkshake"
+ id = "chocoshake"
+ result = "chocoshake"
+ required_reagents = list("milkshake" = 1, "coco" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/berryshake
+ name = "Berry Milkshake"
+ id = "berryshake"
+ result = "berryshake"
+ required_reagents = list("milkshake" = 1, "berryjuice" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/coffeeshake
+ name = "Coffee Milkshake"
+ id = "coffeeshake"
+ result = "coffeeshake"
+ required_reagents = list("milkshake" = 1, "coffee" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/jellyshot
+ name = "Jelly Shot"
+ id = "jellyshot"
+ result = "jellyshot"
+ required_reagents = list("cherryjelly" = 4, "vodka" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/slimeshot
+ name = "Named Bullet"
+ id = "slimeshot"
+ result = "slimeshot"
+ required_reagents = list("slimejelly" = 4, "vodka" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/negroni
+ name = "Negroni"
+ id = "negroni"
+ result = "negroni"
+ required_reagents = list("gin" = 1, "bitters" = 1, "vermouth" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/cloverclub
+ name = "Clover Club"
+ id = "cloverclub"
+ result = "cloverclub"
+ required_reagents = list("berryjuice" = 1, "lemonjuice" = 1, "gin" = 3)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/oldfashioned
+ name = "Old Fashioned"
+ id = "oldfashioned"
+ result = "oldfashioned"
+ required_reagents = list("whiskey" = 3, "bitters" = 1, "sugar" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/whiskeysour
+ name = "Whiskey Sour"
+ id = "whiskeysour"
+ result = "whiskeysour"
+ required_reagents = list("whiskey" = 2, "lemonjuice" = 1, "sugar" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/drinks/daiquiri
+ name = "Daiquiri"
+ id = "daiquiri"
+ result = "daiquiri"
+ required_reagents = list("rum" = 3, "limejuice" = 2, "sugar" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/mintjulep
+ name = "Mint Julep"
+ id = "mintjulep"
+ result = "mintjulep"
+ required_reagents = list("whiskey" = 2, "water" = 1, "mint" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/drinks/paloma
+ name = "Paloma"
+ id = "paloma"
+ result = "paloma"
+ required_reagents = list("orangejuice" = 1, "sodawater" = 1, "tequilla" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/mojito
+ name = "Mojito"
+ id = "mojito"
+ result = "mojito"
+ required_reagents = list("rum" = 3, "limejuice" = 1, "mint" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/virginmojito
+ name = "Mojito"
+ id = "virginmojito"
+ result = "virginmojito"
+ required_reagents = list("sodawater" = 3, "limejuice" = 1, "mint" = 1, "sugar" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/piscosour
+ name = "Pisco Sour"
+ id = "piscosour"
+ result = "piscosour"
+ required_reagents = list("winebrandy" = 1, "lemonjuice" = 1, "sugar" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/coldfront
+ name = "Cold Front"
+ id = "coldfront"
+ result = "coldfront"
+ required_reagents = list("icecoffee" = 1, "whiskey" = 1, "mint" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/godsake
+ name = "Gods Sake"
+ id = "godsake"
+ result = "godsake"
+ required_reagents = list("sake" = 2, "holywater" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/godka //Why you would put this in your body, I don't know.
+ name = "Godka"
+ id = "godka"
+ result = "godka"
+ required_reagents = list("vodka" = 1, "holywater" = 1, "ethanol" = 1, "carthatoline" = 1)
+ catalysts = list("enzyme" = 5, "holywater" = 5)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/drinks/holywine
+ name = "Angel Ichor"
+ id = "holywine"
+ result = "holywine"
+ required_reagents = list("grapejuice" = 5, "gold" = 5)
+ catalysts = list("holywater" = 5)
+ result_amount = 10
+
+/decl/chemical_reaction/instant/drinks/holy_mary
+ name = "Holy Mary"
+ id = "holymary"
+ result = "holymary"
+ required_reagents = list("vodka" = 2, "holywine" = 3, "limejuice" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/angelskiss
+ name = "Angels Kiss"
+ id = "angelskiss"
+ result = "angelskiss"
+ required_reagents = list("holywine" = 1, "kahlua" = 1, "rum" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/angelswrath
+ name = "Angels Wrath"
+ id = "angelswrath"
+ result = "angelswrath"
+ required_reagents = list("rum" = 3, "spacemountainwind" = 1, "holywine" = 1, "dr_gibb" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/ichor_mead
+ name = "Ichor Mead"
+ id = "ichor_mead"
+ result = "ichor_mead"
+ required_reagents = list("holywine" = 1, "mead" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/oilslick
+ name = "Oil Slick"
+ id = "oilslick"
+ result = "oilslick"
+ required_reagents = list("cornoil" = 2, "honey" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/slimeslam
+ name = "Slick Slime Slammer"
+ id = "slimeslammer"
+ result = "slimeslammer"
+ required_reagents = list("cornoil" = 2, "peanutbutter" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/virginsexonthebeach
+ name = "Virgin Sex On The Beach"
+ id = "virginsexonthebeach"
+ result = "virginsexonthebeach"
+ required_reagents = list("orangejuice" = 3, "grenadine" = 2)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/drinks/sexonthebeach
+ name = "Sex On The Beach"
+ id = "sexonthebeach"
+ result = "sexonthebeach"
+ required_reagents = list("virginsexonthebeach" = 5, "vodka" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/eggnog
+ name = "Eggnog"
+ id = "eggnog"
+ result = "eggnog"
+ required_reagents = list("milk" = 5, "cream" = 5, "sugar" = 5, "egg" = 3)
+ result_amount = 15
+
+/decl/chemical_reaction/instant/drinks/nuclearwaste_radium
+ name = "Nuclear Waste"
+ id = "nuclearwasterad"
+ result = "nuclearwaste"
+ required_reagents = list("oilslick" = 1, "radium" = 1, "limejuice" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/nuclearwaste_uranium
+ name = "Nuclear Waste"
+ id = "nuclearwasteuran"
+ result = "nuclearwaste"
+ required_reagents = list("oilslick" = 2, "uranium" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/sodaoil
+ name = "Soda Oil"
+ id = "sodaoil"
+ result = "sodaoil"
+ required_reagents = list("cornoil" = 4, "sodawater" = 1, "carbon" = 1, "tricordrazine" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/fusionnaire
+ name = "Fusionnaire"
+ id = "fusionnaire"
+ result = "fusionnaire"
+ required_reagents = list("lemonjuice" = 3, "vodka" = 2, "schnapps_pep" = 1, "schnapps_lem" = 1, "rum" = 1, "ice" = 1)
+ result_amount = 9
diff --git a/code/modules/reagents/reactions/instant/drinks_vr.dm b/code/modules/reagents/reactions/instant/drinks_vr.dm
new file mode 100644
index 00000000000..261934c2e62
--- /dev/null
+++ b/code/modules/reagents/reactions/instant/drinks_vr.dm
@@ -0,0 +1,198 @@
+///////////////////////////////////////////////////////////////////////////////////
+/// Special drinks
+/decl/chemical_reaction/instant/drinks/grubshake
+ name = "Grub protein drink"
+ id = "grubshake"
+ result = "grubshake"
+ required_reagents = list("shockchem" = 5, "water" = 25)
+ result_amount = 30
+
+/decl/chemical_reaction/instant/drinks/deathbell
+ name = "Deathbell"
+ id = "deathbell"
+ result = "deathbell"
+ required_reagents = list("antifreeze" = 1, "gargleblaster" = 1, "syndicatebomb" =1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/monstertamer
+ name = "Monster Tamer"
+ id = "monstertamer"
+ result = "monstertamer"
+ required_reagents = list("whiskey" = 1, "protein" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/bigbeer
+ name = "Giant Beer"
+ id = "bigbeer"
+ result = "bigbeer"
+ required_reagents = list("syndicatebomb" = 1, "manlydorf" = 1, "grog" =1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/sweettea
+ name = "Sweetened Tea"
+ id = "sweettea"
+ result = "sweettea"
+ required_reagents = list("icetea" = 2, "sugar" = 1,)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/unsweettea
+ name = "Unsweetened Tea"
+ id = "unsweettea"
+ result = "unsweettea"
+ required_reagents = list("sweettea" = 3, "phoron" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/galacticpanic
+ name = "Galactic Panic Attack"
+ id = "galacticpanic"
+ result = "galacticpanic"
+ required_reagents = list("gargleblaster" = 1, "singulo" = 1, "phoronspecial" =1, "neurotoxin" = 1, "atomicbomb" = 1, "hippiesdelight" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/bulldog
+ name = "Space Bulldog"
+ id = "bulldog"
+ result = "bulldog"
+ required_reagents = list("whiterussian" = 4, "cola" =1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/drinks/sbagliato
+ name = "Negroni Sbagliato"
+ id = "sbagliato"
+ result = "sbagliato"
+ required_reagents = list("wine" = 1, "vermouth" = 1, "sodawater" =1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/italiancrisis
+ name = "Italian Crisis"
+ id = "italiancrisis"
+ result = "italiancrisis"
+ required_reagents = list("bulldog" = 1, "sbagliato" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/sugarrush
+ name = "Sweet Rush"
+ id = "sugarrush"
+ result = "sugarrush"
+ required_reagents = list("sugar" = 1, "sodawater" = 1, "vodka" =1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/lotus
+ name = "Lotus"
+ id = "lotus"
+ result = "lotus"
+ required_reagents = list("sbagliato" = 1, "sugarrush" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/drinks/shroomjuice
+ name = "Dumb Shroom Juice"
+ id = "shroomjuice"
+ result = "shroomjuice"
+ required_reagents = list("psilocybin" = 1, "applejuice" = 1, "limejuice" =1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/russianroulette
+ name = "Russian Roulette"
+ id = "russianroulette"
+ result = "russianroulette"
+ required_reagents = list("whiterussian" = 5, "iron" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/lovemaker
+ name = "The Love Maker"
+ id = "lovemaker"
+ result = "lovemaker"
+ required_reagents = list("honey" = 1, "sexonthebeach" = 5)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/honeyshot
+ name = "Honey Shot"
+ id = "honeyshot"
+ result = "honeyshot"
+ required_reagents = list("honey" = 1, "vodka" = 1, "grenadine" =1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/appletini
+ name = "Appletini"
+ id = "appletini"
+ result = "appletini"
+ required_reagents = list("applejuice" = 2, "vodka" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/glowingappletini
+ name = "Glowing Appletini"
+ id = "glowingappletini"
+ result = "glowingappletini"
+ required_reagents = list("appletini" = 5, "uranium" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/scsatw
+ name = "Slow Comfortable Screw Against the Wall"
+ id = "scsatw"
+ result = "scsatw"
+ required_reagents = list("screwdrivercocktail" = 3, "rum" =1, "whiskey" =1, "gin" =1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/choccymilk
+ name = "Choccy Milk"
+ id = "choccymilk"
+ result = "choccymilk"
+ required_reagents = list("milk" = 3, "coco" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/drinks/redspaceflush
+ name = "Redspace Flush"
+ id = "redspaceflush"
+ result = "redspaceflush"
+ required_reagents = list("rum" = 2, "whiskey" = 2, "blood" =1, "phoron" =1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/graveyard
+ name = "Graveyard"
+ id = "graveyard"
+ result = "graveyard"
+ required_reagents = list("cola" = 1, "spacemountainwind" = 1, "dr_gibb" =1, "space_up" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/drinks/hairoftherat
+ name = "Hair of the Rat"
+ id = "hairoftherat"
+ result = "hairoftherat"
+ required_reagents = list("monstertamer" = 2, "nutriment" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/pink_moo
+ name = "Pink Moo"
+ id = "pinkmoo"
+ result = "pinkmoo"
+ required_reagents = list("blackrussian" = 2, "berryshake" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/drinks/originalsin
+ name = "Original Sin"
+ id = "originalsin"
+ result = "originalsin"
+ required_reagents = list("holywine" = 1)
+ catalysts = list("applejuice" = 1)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/drinks/windgarita
+ name = "WND-Garita"
+ id = "windgarita"
+ result = "windgarita"
+ required_reagents = list("margarita" = 3, "spacemountainwind" = 2, "melonliquor" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/newyorksour
+ name = "New York Sour"
+ id = "newyorksour"
+ result = "newyorksour"
+ required_reagents = list("whiskeysour" = 3, "wine" = 2, "egg" = 1)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/drinks/mudslide
+ name = "Mudslide"
+ id = "mudslide"
+ result = "mudslide"
+ required_reagents = list("blackrussian" = 1, "irishcream" = 1)
+ result_amount = 2
diff --git a/code/modules/reagents/reactions/instant/food.dm b/code/modules/reagents/reactions/instant/food.dm
new file mode 100644
index 00000000000..952af8014b4
--- /dev/null
+++ b/code/modules/reagents/reactions/instant/food.dm
@@ -0,0 +1,183 @@
+/decl/chemical_reaction/instant/food/hot_ramen
+ name = "Hot Ramen"
+ id = "hot_ramen"
+ result = "hot_ramen"
+ required_reagents = list("water" = 1, "dry_ramen" = 3)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/food/hell_ramen
+ name = "Hell Ramen"
+ id = "hell_ramen"
+ result = "hell_ramen"
+ required_reagents = list("capsaicin" = 1, "hot_ramen" = 6)
+ result_amount = 6
+
+/decl/chemical_reaction/instant/food/tofu
+ name = "Tofu"
+ id = "tofu"
+ result = null
+ required_reagents = list("soymilk" = 10)
+ catalysts = list("enzyme" = 5)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/food/tofu/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= created_volume, i++)
+ new /obj/item/weapon/reagent_containers/food/snacks/tofu(location)
+ return
+
+/decl/chemical_reaction/instant/food/chocolate_bar
+ name = "Chocolate Bar"
+ id = "chocolate_bar"
+ result = null
+ required_reagents = list("soymilk" = 2, "coco" = 2, "sugar" = 2)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/food/chocolate_bar/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= created_volume, i++)
+ new /obj/item/weapon/reagent_containers/food/snacks/chocolatebar(location)
+ return
+
+/decl/chemical_reaction/instant/food/chocolate_bar2
+ name = "Chocolate Bar"
+ id = "chocolate_bar"
+ result = null
+ required_reagents = list("milk" = 2, "coco" = 2, "sugar" = 2)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/food/chocolate_bar2/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= created_volume, i++)
+ new /obj/item/weapon/reagent_containers/food/snacks/chocolatebar(location)
+ return
+
+/decl/chemical_reaction/instant/food/soysauce
+ name = "Soy Sauce"
+ id = "soysauce"
+ result = "soysauce"
+ required_reagents = list("soymilk" = 4, "sacid" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/food/ketchup
+ name = "Ketchup"
+ id = "ketchup"
+ result = "ketchup"
+ required_reagents = list("tomatojuice" = 2, "water" = 1, "sugar" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/food/barbecue
+ name = "Barbeque Sauce"
+ id = "barbecue"
+ result = "barbecue"
+ required_reagents = list("tomatojuice" = 2, "applejuice" = 1, "sugar" = 1, "spacespice" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/food/peanutbutter
+ name = "Peanut Butter"
+ id = "peanutbutter"
+ result = "peanutbutter"
+ required_reagents = list("peanutoil" = 2, "sugar" = 1, "sodiumchloride" = 1)
+ catalysts = list("enzyme" = 5)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/food/mayonnaise
+ name = "mayonnaise"
+ id = "mayo"
+ result = "mayo"
+ required_reagents = list("egg" = 9, "cornoil" = 5, "lemonjuice" = 5, "sodiumchloride" = 1)
+ result_amount = 15
+
+/decl/chemical_reaction/instant/food/cheesewheel
+ name = "Cheesewheel"
+ id = "cheesewheel"
+ result = null
+ required_reagents = list("milk" = 40)
+ catalysts = list("enzyme" = 5)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/food/cheesewheel/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= created_volume, i++)
+ new /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesewheel(location)
+ return
+
+/decl/chemical_reaction/instant/food/meatball
+ name = "Meatball"
+ id = "meatball"
+ result = null
+ required_reagents = list("protein" = 3, "flour" = 5)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/food/meatball/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= created_volume, i++)
+ new /obj/item/weapon/reagent_containers/food/snacks/meatball(location)
+ return
+
+/decl/chemical_reaction/instant/food/dough
+ name = "Dough"
+ id = "dough"
+ result = null
+ required_reagents = list("egg" = 3, "flour" = 10)
+ inhibitors = list("water" = 1, "beer" = 1) //To prevent it messing with batter recipes
+ result_amount = 1
+
+/decl/chemical_reaction/instant/food/dough/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= created_volume, i++)
+ new /obj/item/weapon/reagent_containers/food/snacks/dough(location)
+ return
+
+/decl/chemical_reaction/instant/food/syntiflesh
+ name = "Syntiflesh"
+ id = "syntiflesh"
+ result = null
+ required_reagents = list("blood" = 5, "clonexadone" = 5)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/food/syntiflesh/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= created_volume, i++)
+ new /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh(location)
+ return
+
+/*
+====================
+ Aurora Food
+====================
+*/
+
+/decl/chemical_reaction/instant/food/coating/batter
+ name = "Batter"
+ id = "batter"
+ result = "batter"
+ required_reagents = list("egg" = 3, "flour" = 10, "water" = 5, "sodiumchloride" = 2)
+ result_amount = 20
+
+/decl/chemical_reaction/instant/food/coating/beerbatter
+ name = "Beer Batter"
+ id = "beerbatter"
+ result = "beerbatter"
+ required_reagents = list("egg" = 3, "flour" = 10, "beer" = 5, "sodiumchloride" = 2)
+ result_amount = 20
+
+/decl/chemical_reaction/instant/food/browniemix
+ name = "Brownie Mix"
+ id = "browniemix"
+ result = "browniemix"
+ required_reagents = list("flour" = 5, "coco" = 5, "sugar" = 5)
+ result_amount = 15
+
+/decl/chemical_reaction/instant/food/butter
+ name = "Butter"
+ id = "butter"
+ result = null
+ required_reagents = list("cream" = 20, "sodiumchloride" = 1)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/food/butter/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= created_volume, i++)
+ new /obj/item/weapon/reagent_containers/food/snacks/spreads/butter(location)
+ return
\ No newline at end of file
diff --git a/code/modules/reagents/reactions/instant/food_vr.dm b/code/modules/reagents/reactions/instant/food_vr.dm
new file mode 100644
index 00000000000..684c23e9440
--- /dev/null
+++ b/code/modules/reagents/reactions/instant/food_vr.dm
@@ -0,0 +1,2 @@
+/decl/chemical_reaction/instant/food/syntiflesh
+ required_reagents = list("blood" = 5, "clonexadone" = 1)
diff --git a/code/modules/reagents/reactions/instant/instant.dm b/code/modules/reagents/reactions/instant/instant.dm
new file mode 100644
index 00000000000..bb9e443f592
--- /dev/null
+++ b/code/modules/reagents/reactions/instant/instant.dm
@@ -0,0 +1,1135 @@
+// These reactions happen instantaneously, when added to a container that has all other necessary reagents
+// They are a subtype of chemical_reaction so that such containers can iterate over only these reactions, and not have to skip other reaction types
+
+/* Common reactions */
+
+/decl/chemical_reaction/instant/inaprovaline
+ name = "Inaprovaline"
+ id = "inaprovaline"
+ result = "inaprovaline"
+ required_reagents = list("oxygen" = 1, "carbon" = 1, "sugar" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/dylovene
+ name = "Dylovene"
+ id = "anti_toxin"
+ result = "anti_toxin"
+ required_reagents = list("silicon" = 1, "potassium" = 1, "nitrogen" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/carthatoline
+ name = "Carthatoline"
+ id = "carthatoline"
+ result = "carthatoline"
+ required_reagents = list("anti_toxin" = 1, "carbon" = 2, "phoron" = 0.1)
+ catalysts = list("phoron" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/paracetamol
+ name = "Paracetamol"
+ id = "paracetamol"
+ result = "paracetamol"
+ required_reagents = list("inaprovaline" = 1, "nitrogen" = 1, "water" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/tramadol
+ name = "Tramadol"
+ id = "tramadol"
+ result = "tramadol"
+ required_reagents = list("paracetamol" = 1, "ethanol" = 1, "oxygen" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/oxycodone
+ name = "Oxycodone"
+ id = "oxycodone"
+ result = "oxycodone"
+ required_reagents = list("ethanol" = 1, "tramadol" = 1)
+ catalysts = list("phoron" = 5)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/sterilizine
+ name = "Sterilizine"
+ id = "sterilizine"
+ result = "sterilizine"
+ required_reagents = list("ethanol" = 1, "anti_toxin" = 1, "chlorine" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/silicate
+ name = "Silicate"
+ id = "silicate"
+ result = "silicate"
+ required_reagents = list("aluminum" = 1, "silicon" = 1, "oxygen" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/mutagen
+ name = "Unstable mutagen"
+ id = "mutagen"
+ result = "mutagen"
+ required_reagents = list("radium" = 1, "phosphorus" = 1, "chlorine" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/water
+ name = "Water"
+ id = "water"
+ result = "water"
+ required_reagents = list("oxygen" = 1, "hydrogen" = 2)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/thermite
+ name = "Thermite"
+ id = "thermite"
+ result = "thermite"
+ required_reagents = list("aluminum" = 1, "iron" = 1, "oxygen" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/space_drugs
+ name = "Space Drugs"
+ id = "space_drugs"
+ result = "space_drugs"
+ required_reagents = list("mercury" = 1, "sugar" = 1, "lithium" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/lube
+ name = "Space Lube"
+ id = "lube"
+ result = "lube"
+ required_reagents = list("water" = 1, "silicon" = 1, "oxygen" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/pacid
+ name = "Polytrinic acid"
+ id = "pacid"
+ result = "pacid"
+ required_reagents = list("sacid" = 1, "chlorine" = 1, "potassium" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/synaptizine
+ name = "Synaptizine"
+ id = "synaptizine"
+ result = "synaptizine"
+ required_reagents = list("sugar" = 1, "lithium" = 1, "water" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/hyronalin
+ name = "Hyronalin"
+ id = "hyronalin"
+ result = "hyronalin"
+ required_reagents = list("radium" = 1, "anti_toxin" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/arithrazine
+ name = "Arithrazine"
+ id = "arithrazine"
+ result = "arithrazine"
+ required_reagents = list("hyronalin" = 1, "hydrogen" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/impedrezene
+ name = "Impedrezene"
+ id = "impedrezene"
+ result = "impedrezene"
+ required_reagents = list("mercury" = 1, "oxygen" = 1, "sugar" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/kelotane
+ name = "Kelotane"
+ id = "kelotane"
+ result = "kelotane"
+ required_reagents = list("silicon" = 1, "carbon" = 1)
+ result_amount = 2
+ log_is_important = 1
+
+/decl/chemical_reaction/instant/peridaxon
+ name = "Peridaxon"
+ id = "peridaxon"
+ result = "peridaxon"
+ required_reagents = list("bicaridine" = 2, "clonexadone" = 2)
+ catalysts = list("phoron" = 5)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/osteodaxon
+ name = "Osteodaxon"
+ id = "osteodaxon"
+ result = "osteodaxon"
+ required_reagents = list("bicaridine" = 2, "phoron" = 0.1, "carpotoxin" = 1)
+ catalysts = list("phoron" = 5)
+ inhibitors = list("clonexadone" = 1) // Messes with cryox
+ result_amount = 2
+
+/decl/chemical_reaction/instant/respirodaxon
+ name = "Respirodaxon"
+ id = "respirodaxon"
+ result = "respirodaxon"
+ required_reagents = list("dexalinp" = 2, "biomass" = 2, "phoron" = 1)
+ catalysts = list("phoron" = 5)
+ inhibitors = list("dexalin" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/gastirodaxon
+ name = "Gastirodaxon"
+ id = "gastirodaxon"
+ result = "gastirodaxon"
+ required_reagents = list("carthatoline" = 1, "biomass" = 2, "tungsten" = 2)
+ catalysts = list("phoron" = 5)
+ inhibitors = list("lithium" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/hepanephrodaxon
+ name = "Hepanephrodaxon"
+ id = "hepanephrodaxon"
+ result = "hepanephrodaxon"
+ required_reagents = list("carthatoline" = 2, "biomass" = 2, "lithium" = 1)
+ catalysts = list("phoron" = 5)
+ inhibitors = list("tungsten" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/cordradaxon
+ name = "Cordradaxon"
+ id = "cordradaxon"
+ result = "cordradaxon"
+ required_reagents = list("potassium_chlorophoride" = 1, "biomass" = 2, "bicaridine" = 2)
+ catalysts = list("phoron" = 5)
+ inhibitors = list("clonexadone" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/virus_food
+ name = "Virus Food"
+ id = "virusfood"
+ result = "virusfood"
+ required_reagents = list("water" = 1, "milk" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/leporazine
+ name = "Leporazine"
+ id = "leporazine"
+ result = "leporazine"
+ required_reagents = list("silicon" = 1, "copper" = 1)
+ catalysts = list("phoron" = 5)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/cryptobiolin
+ name = "Cryptobiolin"
+ id = "cryptobiolin"
+ result = "cryptobiolin"
+ required_reagents = list("potassium" = 1, "oxygen" = 1, "sugar" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/tricordrazine
+ name = "Tricordrazine"
+ id = "tricordrazine"
+ result = "tricordrazine"
+ required_reagents = list("inaprovaline" = 1, "anti_toxin" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/alkysine
+ name = "Alkysine"
+ id = "alkysine"
+ result = "alkysine"
+ required_reagents = list("chlorine" = 1, "nitrogen" = 1, "anti_toxin" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/dexalin
+ name = "Dexalin"
+ id = "dexalin"
+ result = "dexalin"
+ required_reagents = list("oxygen" = 2, "phoron" = 0.1)
+ catalysts = list("phoron" = 1)
+ inhibitors = list("water" = 1) // Messes with cryox
+ result_amount = 1
+
+/decl/chemical_reaction/instant/dermaline
+ name = "Dermaline"
+ id = "dermaline"
+ result = "dermaline"
+ required_reagents = list("oxygen" = 1, "phosphorus" = 1, "kelotane" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/dexalinp
+ name = "Dexalin Plus"
+ id = "dexalinp"
+ result = "dexalinp"
+ required_reagents = list("dexalin" = 1, "carbon" = 1, "iron" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/bicaridine
+ name = "Bicaridine"
+ id = "bicaridine"
+ result = "bicaridine"
+ required_reagents = list("inaprovaline" = 1, "carbon" = 1)
+ inhibitors = list("sugar" = 1) // Messes up with inaprovaline
+ result_amount = 2
+
+/decl/chemical_reaction/instant/myelamine
+ name = "Myelamine"
+ id = "myelamine"
+ result = "myelamine"
+ required_reagents = list("bicaridine" = 1, "iron" = 2, "spidertoxin" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/hyperzine
+ name = "Hyperzine"
+ id = "hyperzine"
+ result = "hyperzine"
+ required_reagents = list("sugar" = 1, "phosphorus" = 1, "sulfur" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/stimm
+ name = "Stimm"
+ id = "stimm"
+ result = "stimm"
+ required_reagents = list("left4zed" = 1, "fuel" = 1)
+ catalysts = list("fuel" = 5)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/ryetalyn
+ name = "Ryetalyn"
+ id = "ryetalyn"
+ result = "ryetalyn"
+ required_reagents = list("arithrazine" = 1, "carbon" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/cryoxadone
+ name = "Cryoxadone"
+ id = "cryoxadone"
+ result = "cryoxadone"
+ required_reagents = list("dexalin" = 1, "water" = 1, "oxygen" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/clonexadone
+ name = "Clonexadone"
+ id = "clonexadone"
+ result = "clonexadone"
+ required_reagents = list("cryoxadone" = 1, "sodium" = 1, "phoron" = 0.1)
+ catalysts = list("phoron" = 5)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/mortiferin
+ name = "Mortiferin"
+ id = "mortiferin"
+ result = "mortiferin"
+ required_reagents = list("cryptobiolin" = 1, "clonexadone" = 1, "corophizine" = 1)
+ result_amount = 2
+ catalysts = list("phoron" = 5)
+
+/decl/chemical_reaction/instant/spaceacillin
+ name = "Spaceacillin"
+ id = "spaceacillin"
+ result = "spaceacillin"
+ required_reagents = list("cryptobiolin" = 1, "inaprovaline" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/corophizine
+ name = "Corophizine"
+ id = "corophizine"
+ result = "corophizine"
+ required_reagents = list("spaceacillin" = 1, "carbon" = 1, "phoron" = 0.1)
+ catalysts = list("phoron" = 5)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/immunosuprizine
+ name = "Immunosuprizine"
+ id = "immunosuprizine"
+ result = "immunosuprizine"
+ required_reagents = list("corophizine" = 1, "tungsten" = 1, "sacid" = 1)
+ catalysts = list("phoron" = 5)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/imidazoline
+ name = "imidazoline"
+ id = "imidazoline"
+ result = "imidazoline"
+ required_reagents = list("carbon" = 1, "hydrogen" = 1, "anti_toxin" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/ethylredoxrazine
+ name = "Ethylredoxrazine"
+ id = "ethylredoxrazine"
+ result = "ethylredoxrazine"
+ required_reagents = list("oxygen" = 1, "anti_toxin" = 1, "carbon" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/calciumcarbonate
+ name = "Calcium Carbonate"
+ id = "calciumcarbonate"
+ result = "calciumcarbonate"
+ required_reagents = list("oxygen" = 3, "calcium" = 1, "carbon" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/soporific
+ name = "Soporific"
+ id = "stoxin"
+ result = "stoxin"
+ required_reagents = list("chloralhydrate" = 1, "sugar" = 4)
+ inhibitors = list("phosphorus") // Messes with the smoke
+ result_amount = 5
+
+/decl/chemical_reaction/instant/chloralhydrate
+ name = "Chloral Hydrate"
+ id = "chloralhydrate"
+ result = "chloralhydrate"
+ required_reagents = list("ethanol" = 1, "chlorine" = 3, "water" = 1)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/potassium_chloride
+ name = "Potassium Chloride"
+ id = "potassium_chloride"
+ result = "potassium_chloride"
+ required_reagents = list("sodiumchloride" = 1, "potassium" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/potassium_chlorophoride
+ name = "Potassium Chlorophoride"
+ id = "potassium_chlorophoride"
+ result = "potassium_chlorophoride"
+ required_reagents = list("potassium_chloride" = 1, "phoron" = 1, "chloralhydrate" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/zombiepowder
+ name = "Zombie Powder"
+ id = "zombiepowder"
+ result = "zombiepowder"
+ required_reagents = list("carpotoxin" = 5, "stoxin" = 5, "copper" = 5)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/carpotoxin
+ name = "Carpotoxin"
+ id = "carpotoxin"
+ result = "carpotoxin"
+ required_reagents = list("spidertoxin" = 2, "biomass" = 1, "sifsap" = 2)
+ catalysts = list("sifsap" = 10)
+ inhibitors = list("radium" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/mindbreaker
+ name = "Mindbreaker Toxin"
+ id = "mindbreaker"
+ result = "mindbreaker"
+ required_reagents = list("silicon" = 1, "hydrogen" = 1, "anti_toxin" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/lipozine
+ name = "Lipozine"
+ id = "Lipozine"
+ result = "lipozine"
+ required_reagents = list("sodiumchloride" = 1, "ethanol" = 1, "radium" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/surfactant
+ name = "Foam surfactant"
+ id = "foam surfactant"
+ result = "fluorosurfactant"
+ required_reagents = list("fluorine" = 2, "carbon" = 2, "sacid" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/ammonia
+ name = "Ammonia"
+ id = "ammonia"
+ result = "ammonia"
+ required_reagents = list("hydrogen" = 3, "nitrogen" = 1)
+ inhibitors = list("phoron" = 1) // Messes with lexorin
+ result_amount = 3
+
+/decl/chemical_reaction/instant/diethylamine
+ name = "Diethylamine"
+ id = "diethylamine"
+ result = "diethylamine"
+ required_reagents = list ("ammonia" = 1, "ethanol" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/left4zed
+ name = "Left4Zed"
+ id = "left4zed"
+ result = "left4zed"
+ required_reagents = list ("diethylamine" = 2, "mutagen" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/robustharvest
+ name = "RobustHarvest"
+ id = "robustharvest"
+ result = "robustharvest"
+ required_reagents = list ("ammonia" = 1, "calcium" = 1, "neurotoxic_protein" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/space_cleaner
+ name = "Space cleaner"
+ id = "cleaner"
+ result = "cleaner"
+ required_reagents = list("ammonia" = 1, "water" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/plantbgone
+ name = "Plant-B-Gone"
+ id = "plantbgone"
+ result = "plantbgone"
+ required_reagents = list("toxin" = 1, "water" = 4)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/foaming_agent
+ name = "Foaming Agent"
+ id = "foaming_agent"
+ result = "foaming_agent"
+ required_reagents = list("lithium" = 1, "hydrogen" = 1)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/glycerol
+ name = "Glycerol"
+ id = "glycerol"
+ result = "glycerol"
+ required_reagents = list("cornoil" = 3, "sacid" = 1)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/sodiumchloride
+ name = "Sodium Chloride"
+ id = "sodiumchloride"
+ result = "sodiumchloride"
+ required_reagents = list("sodium" = 1, "chlorine" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/condensedcapsaicin
+ name = "Condensed Capsaicin"
+ id = "condensedcapsaicin"
+ result = "condensedcapsaicin"
+ required_reagents = list("capsaicin" = 2)
+ catalysts = list("phoron" = 5)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/coolant
+ name = "Coolant"
+ id = "coolant"
+ result = "coolant"
+ required_reagents = list("tungsten" = 1, "oxygen" = 1, "water" = 1)
+ result_amount = 3
+ log_is_important = 1
+
+/decl/chemical_reaction/instant/rezadone
+ name = "Rezadone"
+ id = "rezadone"
+ result = "rezadone"
+ required_reagents = list("carpotoxin" = 1, "cryptobiolin" = 1, "copper" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/lexorin
+ name = "Lexorin"
+ id = "lexorin"
+ result = "lexorin"
+ required_reagents = list("phoron" = 1, "hydrogen" = 1, "nitrogen" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/methylphenidate
+ name = "Methylphenidate"
+ id = "methylphenidate"
+ result = "methylphenidate"
+ required_reagents = list("mindbreaker" = 1, "hydrogen" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/citalopram
+ name = "Citalopram"
+ id = "citalopram"
+ result = "citalopram"
+ required_reagents = list("mindbreaker" = 1, "carbon" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/paroxetine
+ name = "Paroxetine"
+ id = "paroxetine"
+ result = "paroxetine"
+ required_reagents = list("mindbreaker" = 1, "oxygen" = 1, "inaprovaline" = 1)
+ result_amount = 3
+
+/decl/chemical_reaction/instant/neurotoxin
+ name = "Neurotoxin"
+ id = "neurotoxin"
+ result = "neurotoxin"
+ required_reagents = list("gargleblaster" = 1, "stoxin" = 1)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/luminol
+ name = "Luminol"
+ id = "luminol"
+ result = "luminol"
+ required_reagents = list("hydrogen" = 2, "carbon" = 2, "ammonia" = 2)
+ result_amount = 6
+
+/* Solidification */
+
+/decl/chemical_reaction/instant/solidification
+ name = "Solid Iron"
+ id = "solidiron"
+ result = null
+ required_reagents = list("frostoil" = 5, "iron" = REAGENTS_PER_SHEET)
+ result_amount = 1
+ var/sheet_to_give = /obj/item/stack/material/iron
+
+/decl/chemical_reaction/instant/solidification/on_reaction(var/datum/reagents/holder, var/created_volume)
+ new sheet_to_give(get_turf(holder.my_atom), created_volume)
+ return
+
+
+/decl/chemical_reaction/instant/solidification/phoron
+ name = "Solid Phoron"
+ id = "solidphoron"
+ required_reagents = list("frostoil" = 5, "phoron" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/phoron
+
+
+/decl/chemical_reaction/instant/solidification/silver
+ name = "Solid Silver"
+ id = "solidsilver"
+ required_reagents = list("frostoil" = 5, "silver" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/silver
+
+
+/decl/chemical_reaction/instant/solidification/gold
+ name = "Solid Gold"
+ id = "solidgold"
+ required_reagents = list("frostoil" = 5, "gold" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/gold
+
+
+/decl/chemical_reaction/instant/solidification/platinum
+ name = "Solid Platinum"
+ id = "solidplatinum"
+ required_reagents = list("frostoil" = 5, "platinum" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/platinum
+
+
+/decl/chemical_reaction/instant/solidification/uranium
+ name = "Solid Uranium"
+ id = "soliduranium"
+ required_reagents = list("frostoil" = 5, "uranium" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/uranium
+
+
+/decl/chemical_reaction/instant/solidification/hydrogen
+ name = "Solid Hydrogen"
+ id = "solidhydrogen"
+ required_reagents = list("frostoil" = 100, "hydrogen" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/mhydrogen
+
+
+// These are from Xenobio.
+/decl/chemical_reaction/instant/solidification/steel
+ name = "Solid Steel"
+ id = "solidsteel"
+ required_reagents = list("frostoil" = 5, "steel" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/steel
+
+
+/decl/chemical_reaction/instant/solidification/plasteel
+ name = "Solid Plasteel"
+ id = "solidplasteel"
+ required_reagents = list("frostoil" = 10, "plasteel" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/plasteel
+
+
+/decl/chemical_reaction/instant/plastication
+ name = "Plastic"
+ id = "solidplastic"
+ result = null
+ required_reagents = list("pacid" = 1, "plasticide" = 2)
+ result_amount = 1
+
+/decl/chemical_reaction/instant/plastication/on_reaction(var/datum/reagents/holder, var/created_volume)
+ new /obj/item/stack/material/plastic(get_turf(holder.my_atom), created_volume)
+ return
+
+/* Grenade reactions */
+
+/decl/chemical_reaction/instant/explosion_potassium
+ name = "Explosion"
+ id = "explosion_potassium"
+ result = null
+ required_reagents = list("water" = 1, "potassium" = 1)
+ result_amount = 2
+ mix_message = null
+
+/decl/chemical_reaction/instant/explosion_potassium/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/datum/effect/effect/system/reagents_explosion/e = new()
+ e.set_up(round (created_volume/10, 1), holder.my_atom, 0, 0)
+ if(isliving(holder.my_atom))
+ e.amount *= 0.5
+ var/mob/living/L = holder.my_atom
+ if(L.stat != DEAD)
+ e.amount *= 0.5
+ //VOREStation Add Start
+ else
+ holder.clear_reagents() //No more powergaming by creating a tiny amount of this
+ //VORESTation Add End
+ e.start()
+ //holder.clear_reagents() //VOREStation Removal
+ return
+
+/decl/chemical_reaction/instant/flash_powder
+ name = "Flash powder"
+ id = "flash_powder"
+ result = null
+ required_reagents = list("aluminum" = 1, "potassium" = 1, "sulfur" = 1 )
+ result_amount = null
+
+/decl/chemical_reaction/instant/flash_powder/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(2, 1, location)
+ s.start()
+ for(var/mob/living/carbon/M in viewers(world.view, location))
+ switch(get_dist(M, location))
+ if(0 to 3)
+ if(hasvar(M, "glasses"))
+ if(istype(M:glasses, /obj/item/clothing/glasses/sunglasses))
+ continue
+
+ M.flash_eyes()
+ M.Weaken(15)
+
+ if(4 to 5)
+ if(hasvar(M, "glasses"))
+ if(istype(M:glasses, /obj/item/clothing/glasses/sunglasses))
+ continue
+
+ M.flash_eyes()
+ M.Stun(5)
+
+/decl/chemical_reaction/instant/emp_pulse
+ name = "EMP Pulse"
+ id = "emp_pulse"
+ result = null
+ required_reagents = list("uranium" = 1, "iron" = 1) // Yes, laugh, it's the best recipe I could think of that makes a little bit of sense
+ result_amount = 2
+
+/decl/chemical_reaction/instant/emp_pulse/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+ // 100 created volume = 4 heavy range & 7 light range. A few tiles smaller than traitor EMP grandes.
+ // 200 created volume = 8 heavy range & 14 light range. 4 tiles larger than traitor EMP grenades.
+ empulse(location, round(created_volume / 24), round(created_volume / 20), round(created_volume / 18), round(created_volume / 14), 1)
+ //VOREStation Edit Start
+ if(!isliving(holder.my_atom)) //No more powergaming by creating a tiny amount of this
+ holder.clear_reagents()
+ //VOREStation Edit End
+ return
+
+/decl/chemical_reaction/instant/nitroglycerin
+ name = "Nitroglycerin"
+ id = "nitroglycerin"
+ result = "nitroglycerin"
+ required_reagents = list("glycerol" = 1, "pacid" = 1, "sacid" = 1)
+ result_amount = 2
+ log_is_important = 1
+
+/decl/chemical_reaction/instant/nitroglycerin/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/datum/effect/effect/system/reagents_explosion/e = new()
+ e.set_up(round (created_volume/2, 1), holder.my_atom, 0, 0)
+ if(isliving(holder.my_atom))
+ e.amount *= 0.5
+ var/mob/living/L = holder.my_atom
+ if(L.stat!=DEAD)
+ e.amount *= 0.5
+ //VOREStation Add Start
+ else
+ holder.clear_reagents() //No more powergaming by creating a tiny amount of this
+ //VOREStation Add End
+ e.start()
+
+ //holder.clear_reagents() //VOREStation Removal
+ return
+
+/decl/chemical_reaction/instant/napalm
+ name = "Napalm"
+ id = "napalm"
+ result = null
+ required_reagents = list("aluminum" = 1, "phoron" = 1, "sacid" = 1 )
+ result_amount = 1
+
+/decl/chemical_reaction/instant/napalm/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/turf/location = get_turf(holder.my_atom.loc)
+ for(var/turf/simulated/floor/target_tile in range(0,location))
+ target_tile.assume_gas("volatile_fuel", created_volume, 400+T0C)
+ spawn (0) target_tile.hotspot_expose(700, 400)
+ holder.del_reagent("napalm")
+ return
+
+/decl/chemical_reaction/instant/chemsmoke
+ name = "Chemsmoke"
+ id = "chemsmoke"
+ result = null
+ required_reagents = list("potassium" = 1, "sugar" = 1, "phosphorus" = 1)
+ result_amount = 0.4
+
+/decl/chemical_reaction/instant/chemsmoke/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+ var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem
+ S.attach(location)
+ S.set_up(holder, created_volume, 0, location)
+ playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3)
+ spawn(0)
+ S.start()
+ //VOREStation Edit Start
+ if(!isliving(holder.my_atom)) //No more powergaming by creating a tiny amount of this
+ holder.clear_reagents()
+ //VOREStation Edit End
+ return
+
+/decl/chemical_reaction/instant/foam
+ name = "Foam"
+ id = "foam"
+ result = null
+ required_reagents = list("fluorosurfactant" = 1, "water" = 1)
+ result_amount = 2
+ mix_message = "The solution violently bubbles!"
+
+/decl/chemical_reaction/instant/foam/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+
+ for(var/mob/M in viewers(5, location))
+ to_chat(M, "The solution spews out foam!")
+
+ var/datum/effect/effect/system/foam_spread/s = new()
+ s.set_up(created_volume, location, holder, 0)
+ s.start()
+ //VOREStation Edit Start
+ if(!isliving(holder.my_atom)) //No more powergaming by creating a tiny amount of this
+ holder.clear_reagents()
+ //VOREStation Edit End
+ return
+
+/decl/chemical_reaction/instant/metalfoam
+ name = "Metal Foam"
+ id = "metalfoam"
+ result = null
+ required_reagents = list("aluminum" = 3, "foaming_agent" = 1, "pacid" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/metalfoam/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+
+ for(var/mob/M in viewers(5, location))
+ to_chat(M, "The solution spews out a metalic foam!")
+
+ var/datum/effect/effect/system/foam_spread/s = new()
+ s.set_up(created_volume, location, holder, 1)
+ s.start()
+ return
+
+/decl/chemical_reaction/instant/ironfoam
+ name = "Iron Foam"
+ id = "ironlfoam"
+ result = null
+ required_reagents = list("iron" = 3, "foaming_agent" = 1, "pacid" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/ironfoam/on_reaction(var/datum/reagents/holder, var/created_volume)
+ var/location = get_turf(holder.my_atom)
+
+ for(var/mob/M in viewers(5, location))
+ to_chat(M, "The solution spews out a metalic foam!")
+
+ var/datum/effect/effect/system/foam_spread/s = new()
+ s.set_up(created_volume, location, holder, 2)
+ s.start()
+ return
+
+/* Paint */
+
+/decl/chemical_reaction/instant/red_paint
+ name = "Red paint"
+ id = "red_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_red" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/red_paint/send_data()
+ return "#FE191A"
+
+/decl/chemical_reaction/instant/orange_paint
+ name = "Orange paint"
+ id = "orange_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_orange" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/orange_paint/send_data()
+ return "#FFBE4F"
+
+/decl/chemical_reaction/instant/yellow_paint
+ name = "Yellow paint"
+ id = "yellow_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_yellow" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/yellow_paint/send_data()
+ return "#FDFE7D"
+
+/decl/chemical_reaction/instant/green_paint
+ name = "Green paint"
+ id = "green_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_green" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/green_paint/send_data()
+ return "#18A31A"
+
+/decl/chemical_reaction/instant/blue_paint
+ name = "Blue paint"
+ id = "blue_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_blue" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/blue_paint/send_data()
+ return "#247CFF"
+
+/decl/chemical_reaction/instant/purple_paint
+ name = "Purple paint"
+ id = "purple_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_purple" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/purple_paint/send_data()
+ return "#CC0099"
+
+/decl/chemical_reaction/instant/grey_paint //mime
+ name = "Grey paint"
+ id = "grey_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_grey" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/grey_paint/send_data()
+ return "#808080"
+
+/decl/chemical_reaction/instant/brown_paint
+ name = "Brown paint"
+ id = "brown_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "marker_ink_brown" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/brown_paint/send_data()
+ return "#846F35"
+
+/decl/chemical_reaction/instant/blood_paint
+ name = "Blood paint"
+ id = "blood_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "blood" = 2)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/blood_paint/send_data(var/datum/reagents/T)
+ var/t = T.get_data("blood")
+ if(t && t["blood_colour"])
+ return t["blood_colour"]
+ return "#FE191A" // Probably red
+
+/decl/chemical_reaction/instant/milk_paint
+ name = "Milk paint"
+ id = "milk_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "milk" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/milk_paint/send_data()
+ return "#F0F8FF"
+
+/decl/chemical_reaction/instant/orange_juice_paint
+ name = "Orange juice paint"
+ id = "orange_juice_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "orangejuice" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/orange_juice_paint/send_data()
+ return "#E78108"
+
+/decl/chemical_reaction/instant/tomato_juice_paint
+ name = "Tomato juice paint"
+ id = "tomato_juice_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "tomatojuice" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/tomato_juice_paint/send_data()
+ return "#731008"
+
+/decl/chemical_reaction/instant/lime_juice_paint
+ name = "Lime juice paint"
+ id = "lime_juice_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "limejuice" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/lime_juice_paint/send_data()
+ return "#365E30"
+
+/decl/chemical_reaction/instant/carrot_juice_paint
+ name = "Carrot juice paint"
+ id = "carrot_juice_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "carrotjuice" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/carrot_juice_paint/send_data()
+ return "#973800"
+
+/decl/chemical_reaction/instant/berry_juice_paint
+ name = "Berry juice paint"
+ id = "berry_juice_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "berryjuice" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/berry_juice_paint/send_data()
+ return "#990066"
+
+/decl/chemical_reaction/instant/grape_juice_paint
+ name = "Grape juice paint"
+ id = "grape_juice_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "grapejuice" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/grape_juice_paint/send_data()
+ return "#863333"
+
+/decl/chemical_reaction/instant/poisonberry_juice_paint
+ name = "Poison berry juice paint"
+ id = "poisonberry_juice_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "poisonberryjuice" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/poisonberry_juice_paint/send_data()
+ return "#863353"
+
+/decl/chemical_reaction/instant/watermelon_juice_paint
+ name = "Watermelon juice paint"
+ id = "watermelon_juice_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "watermelonjuice" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/watermelon_juice_paint/send_data()
+ return "#B83333"
+
+/decl/chemical_reaction/instant/lemon_juice_paint
+ name = "Lemon juice paint"
+ id = "lemon_juice_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "lemonjuice" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/lemon_juice_paint/send_data()
+ return "#AFAF00"
+
+/decl/chemical_reaction/instant/banana_juice_paint
+ name = "Banana juice paint"
+ id = "banana_juice_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "banana" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/banana_juice_paint/send_data()
+ return "#C3AF00"
+
+/decl/chemical_reaction/instant/potato_juice_paint
+ name = "Potato juice paint"
+ id = "potato_juice_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "potatojuice" = 5)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/potato_juice_paint/send_data()
+ return "#302000"
+
+/decl/chemical_reaction/instant/carbon_paint
+ name = "Carbon paint"
+ id = "carbon_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "carbon" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/carbon_paint/send_data()
+ return "#333333"
+
+/decl/chemical_reaction/instant/aluminum_paint
+ name = "Aluminum paint"
+ id = "aluminum_paint"
+ result = "paint"
+ required_reagents = list("plasticide" = 1, "water" = 3, "aluminum" = 1)
+ result_amount = 5
+
+/decl/chemical_reaction/instant/aluminum_paint/send_data()
+ return "#F0F8FF"
+
+//R-UST Port
+/decl/chemical_reaction/instant/hydrophoron
+ name = "Hydrophoron"
+ id = "hydrophoron"
+ result = "hydrophoron"
+ required_reagents = list("hydrogen" = 1, "phoron" = 1)
+ inhibitors = list("nitrogen" = 1) //So it doesn't mess with lexorin
+ result_amount = 2
+
+/decl/chemical_reaction/instant/deuterium
+ name = "Deuterium"
+ id = "deuterium"
+ result = "deuterium"
+ required_reagents = list("hydrophoron" = 1, "water" = 2)
+ result_amount = 3
+
+//Skrellian crap.
+/decl/chemical_reaction/instant/talum_quem
+ name = "Talum-quem"
+ id = "talum_quem"
+ result = "talum_quem"
+ required_reagents = list("space_drugs" = 2, "sugar" = 1, "amatoxin" = 1)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/qerr_quem
+ name = "Qerr-quem"
+ id = "qerr_quem"
+ result = "qerr_quem"
+ required_reagents = list("nicotine" = 1, "carbon" = 1, "sugar" = 2)
+ result_amount = 4
+
+/decl/chemical_reaction/instant/malish_qualem
+ name = "Malish-Qualem"
+ id = "malish-qualem"
+ result = "malish-qualem"
+ required_reagents = list("immunosuprizine" = 1, "qerr_quem" = 1, "inaprovaline" = 1)
+ catalysts = list("phoron" = 5)
+ result_amount = 2
+
+// Biomass, for cloning and bioprinters
+/decl/chemical_reaction/instant/biomass
+ name = "Biomass"
+ id = "biomass"
+ result = "biomass"
+ required_reagents = list("protein" = 1, "sugar" = 1, "phoron" = 1)
+ result_amount = 1 // Roughly 20u per phoron sheet
+
+// Neutralization.
+
+/decl/chemical_reaction/instant/neutralize_neurotoxic_protein
+ name = "Neutralize Toxic Proteins"
+ id = "neurotoxic_protein_neutral"
+ result = "protein"
+ required_reagents = list("anti_toxin" = 1, "neurotoxic_protein" = 2)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/neutralize_carpotoxin
+ name = "Neutralize Carpotoxin"
+ id = "carpotoxin_neutral"
+ result = "protein"
+ required_reagents = list("radium" = 1, "carpotoxin" = 1, "sifsap" = 1)
+ catalysts = list("sifsap" = 10)
+ result_amount = 2
+
+/decl/chemical_reaction/instant/neutralize_spidertoxin
+ name = "Neutralize Spidertoxin"
+ id = "spidertoxin_neutral"
+ result = "protein"
+ required_reagents = list("radium" = 1, "spidertoxin" = 1, "sifsap" = 1)
+ catalysts = list("sifsap" = 10)
+ result_amount = 2
\ No newline at end of file
diff --git a/code/modules/reagents/Chemistry-Recipes_vr.dm b/code/modules/reagents/reactions/instant/instant_vr.dm
similarity index 67%
rename from code/modules/reagents/Chemistry-Recipes_vr.dm
rename to code/modules/reagents/reactions/instant/instant_vr.dm
index e08b3bd8f1e..b2fef2977c7 100644
--- a/code/modules/reagents/Chemistry-Recipes_vr.dm
+++ b/code/modules/reagents/reactions/instant/instant_vr.dm
@@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////////
/// Micro/Macro chemicals
-/datum/chemical_reaction/sizeoxadone
+/decl/chemical_reaction/instant/sizeoxadone
name = "sizeoxadone"
id = "sizeoxadone"
result = "sizeoxadone"
@@ -9,7 +9,7 @@
catalysts = list("phoron" = 5)
result_amount = 5
-/datum/chemical_reaction/macrocillin
+/decl/chemical_reaction/instant/macrocillin
name = "Macrocillin"
id = "macrocillin"
result = "macrocillin"
@@ -17,7 +17,7 @@
required_reagents = list("sizeoxadone" = 20, "diethylamine" = 20)
result_amount = 1
-/datum/chemical_reaction/microcillin
+/decl/chemical_reaction/instant/microcillin
name = "Microcillin"
id = "microcillin"
result = "microcillin"
@@ -25,7 +25,7 @@
required_reagents = list("sizeoxadone" = 20, "sodiumchloride" = 20)
result_amount = 1
-/datum/chemical_reaction/normalcillin
+/decl/chemical_reaction/instant/normalcillin
name = "Normalcillin"
id = "normalcillin"
result = "normalcillin"
@@ -33,13 +33,13 @@
required_reagents = list("sizeoxadone" = 20, "leporazine" = 20)
result_amount = 1
-/datum/chemical_reaction/dontcrossthebeams
+/decl/chemical_reaction/instant/dontcrossthebeams
name = "Don't Cross The Beams"
id = "dontcrossthebeams"
result = null
required_reagents = list("microcillin" = 1, "macrocillin" = 1)
-/datum/chemical_reaction/dontcrossthebeams/on_reaction(var/datum/reagents/holder, var/created_volume)
+/decl/chemical_reaction/instant/dontcrossthebeams/on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
playsound(location, 'sound/weapons/gauss_shoot.ogg', 50, 1)
var/datum/effect/effect/system/grav_pull/s = new /datum/effect/effect/system/grav_pull
@@ -50,13 +50,13 @@
///////////////////////////////////////////////////////////////////////////////////
/// Miscellaneous Reactions
-/datum/chemical_reaction/xenolazarus
+/decl/chemical_reaction/instant/xenolazarus
name = "Discount Lazarus"
id = "discountlazarus"
result = null
required_reagents = list("monstertamer" = 5, "clonexadone" = 5)
-/datum/chemical_reaction/xenolazarus/on_reaction(var/datum/reagents/holder, var/created_volume) //literally all this does is mash the regenerate button
+/decl/chemical_reaction/instant/xenolazarus/on_reaction(var/datum/reagents/holder, var/created_volume) //literally all this does is mash the regenerate button
if(ishuman(holder.my_atom))
var/mob/living/carbon/human/H = holder.my_atom
if(H.stat == DEAD && (/mob/living/carbon/human/proc/reconstitute_form in H.verbs)) //no magical regen for non-regenners, and can't force the reaction on live ones
@@ -75,10 +75,10 @@
H.visible_message("[H] twitches for a moment, but remains still.") // no nutriment
-/datum/chemical_reaction/foam/softdrink
+/decl/chemical_reaction/instant/foam/softdrink
required_reagents = list("cola" = 1, "mint" = 1)
-/datum/chemical_reaction/firefightingfoam //TODO: Make it so we can add this to the foam tanks to refill them
+/decl/chemical_reaction/instant/firefightingfoam //TODO: Make it so we can add this to the foam tanks to refill them
name = "Firefighting Foam"
id = "firefighting foam"
result = "firefoam"
@@ -86,7 +86,7 @@
catalysts = list("fluorine" = 10)
result_amount = 1
-/datum/chemical_reaction/firefightingfoamqol //Please don't abuse this and make us remove it. Seriously.
+/decl/chemical_reaction/instant/firefightingfoamqol //Please don't abuse this and make us remove it. Seriously.
name = "Firefighting Foam EZ"
id = "firefighting foam ez"
result = "firefoam"
@@ -98,14 +98,14 @@
///////////////////////////////////////////////////////////////////////////////////
/// Vore Drugs
-/datum/chemical_reaction/ickypak
+/decl/chemical_reaction/instant/ickypak
name = "Ickypak"
id = "ickypak"
result = "ickypak"
required_reagents = list("hyperzine" = 4, "fluorosurfactant" = 1)
result_amount = 5
-/datum/chemical_reaction/unsorbitol
+/decl/chemical_reaction/instant/unsorbitol
name = "Unsorbitol"
id = "unsorbitol"
result = "unsorbitol"
@@ -114,14 +114,14 @@
///////////////////////////////////////////////////////////////////////////////////
/// Other Drugs
-/datum/chemical_reaction/adranol
+/decl/chemical_reaction/instant/adranol
name = "Adranol"
id = "adranol"
result = "adranol"
required_reagents = list("milk" = 2, "hydrogen" = 1, "potassium" = 1)
result_amount = 3
-/datum/chemical_reaction/vermicetol
+/decl/chemical_reaction/instant/vermicetol
name = "Vermicetol"
id = "vermicetol"
result = "vermicetol"
@@ -129,215 +129,16 @@
catalysts = list("phoron" = 5)
result_amount = 3
-///////////////////////////////////////////////////////////////////////////////////
-/// Special drinks
-/datum/chemical_reaction/drinks/grubshake
- name = "Grub protein drink"
- id = "grubshake"
- result = "grubshake"
- required_reagents = list("shockchem" = 5, "water" = 25)
- result_amount = 30
-
-/datum/chemical_reaction/drinks/deathbell
- name = "Deathbell"
- id = "deathbell"
- result = "deathbell"
- required_reagents = list("antifreeze" = 1, "gargleblaster" = 1, "syndicatebomb" =1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/monstertamer
- name = "Monster Tamer"
- id = "monstertamer"
- result = "monstertamer"
- required_reagents = list("whiskey" = 1, "protein" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/bigbeer
- name = "Giant Beer"
- id = "bigbeer"
- result = "bigbeer"
- required_reagents = list("syndicatebomb" = 1, "manlydorf" = 1, "grog" =1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/sweettea
- name = "Sweetened Tea"
- id = "sweettea"
- result = "sweettea"
- required_reagents = list("icetea" = 2, "sugar" = 1,)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/unsweettea
- name = "Unsweetened Tea"
- id = "unsweettea"
- result = "unsweettea"
- required_reagents = list("sweettea" = 3, "phoron" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/galacticpanic
- name = "Galactic Panic Attack"
- id = "galacticpanic"
- result = "galacticpanic"
- required_reagents = list("gargleblaster" = 1, "singulo" = 1, "phoronspecial" =1, "neurotoxin" = 1, "atomicbomb" = 1, "hippiesdelight" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/bulldog
- name = "Space Bulldog"
- id = "bulldog"
- result = "bulldog"
- required_reagents = list("whiterussian" = 4, "cola" =1)
- result_amount = 4
-
-/datum/chemical_reaction/drinks/sbagliato
- name = "Negroni Sbagliato"
- id = "sbagliato"
- result = "sbagliato"
- required_reagents = list("wine" = 1, "vermouth" = 1, "sodawater" =1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/italiancrisis
- name = "Italian Crisis"
- id = "italiancrisis"
- result = "italiancrisis"
- required_reagents = list("bulldog" = 1, "sbagliato" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/sugarrush
- name = "Sweet Rush"
- id = "sugarrush"
- result = "sugarrush"
- required_reagents = list("sugar" = 1, "sodawater" = 1, "vodka" =1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/lotus
- name = "Lotus"
- id = "lotus"
- result = "lotus"
- required_reagents = list("sbagliato" = 1, "sugarrush" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/drinks/shroomjuice
- name = "Dumb Shroom Juice"
- id = "shroomjuice"
- result = "shroomjuice"
- required_reagents = list("psilocybin" = 1, "applejuice" = 1, "limejuice" =1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/russianroulette
- name = "Russian Roulette"
- id = "russianroulette"
- result = "russianroulette"
- required_reagents = list("whiterussian" = 5, "iron" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/lovemaker
- name = "The Love Maker"
- id = "lovemaker"
- result = "lovemaker"
- required_reagents = list("honey" = 1, "sexonthebeach" = 5)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/honeyshot
- name = "Honey Shot"
- id = "honeyshot"
- result = "honeyshot"
- required_reagents = list("honey" = 1, "vodka" = 1, "grenadine" =1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/appletini
- name = "Appletini"
- id = "appletini"
- result = "appletini"
- required_reagents = list("applejuice" = 2, "vodka" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/glowingappletini
- name = "Glowing Appletini"
- id = "glowingappletini"
- result = "glowingappletini"
- required_reagents = list("appletini" = 5, "uranium" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/scsatw
- name = "Slow Comfortable Screw Against the Wall"
- id = "scsatw"
- result = "scsatw"
- required_reagents = list("screwdrivercocktail" = 3, "rum" =1, "whiskey" =1, "gin" =1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/choccymilk
- name = "Choccy Milk"
- id = "choccymilk"
- result = "choccymilk"
- required_reagents = list("milk" = 3, "coco" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/drinks/redspaceflush
- name = "Redspace Flush"
- id = "redspaceflush"
- result = "redspaceflush"
- required_reagents = list("rum" = 2, "whiskey" = 2, "blood" =1, "phoron" =1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/graveyard
- name = "Graveyard"
- id = "graveyard"
- result = "graveyard"
- required_reagents = list("cola" = 1, "spacemountainwind" = 1, "dr_gibb" =1, "space_up" = 1)
- result_amount = 4
-
-/datum/chemical_reaction/drinks/hairoftherat
- name = "Hair of the Rat"
- id = "hairoftherat"
- result = "hairoftherat"
- required_reagents = list("monstertamer" = 2, "nutriment" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/pink_moo
- name = "Pink Moo"
- id = "pinkmoo"
- result = "pinkmoo"
- required_reagents = list("blackrussian" = 2, "berryshake" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/drinks/originalsin
- name = "Original Sin"
- id = "originalsin"
- result = "originalsin"
- required_reagents = list("holywine" = 1)
- catalysts = list("applejuice" = 1)
- result_amount = 1
-
-/datum/chemical_reaction/drinks/windgarita
- name = "WND-Garita"
- id = "windgarita"
- result = "windgarita"
- required_reagents = list("margarita" = 3, "spacemountainwind" = 2, "melonliquor" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/newyorksour
- name = "New York Sour"
- id = "newyorksour"
- result = "newyorksour"
- required_reagents = list("whiskeysour" = 3, "wine" = 2, "egg" = 1)
- result_amount = 6
-
-/datum/chemical_reaction/drinks/mudslide
- name = "Mudslide"
- id = "mudslide"
- result = "mudslide"
- required_reagents = list("blackrussian" = 1, "irishcream" = 1)
- result_amount = 2
-
///////////////////////////////////////////////////////////////////////////////////
/// Reagent colonies.
-/datum/chemical_reaction/meatcolony
+/decl/chemical_reaction/instant/meatcolony
name = "protein"
id = "meatcolony"
result = "protein"
required_reagents = list("meatcolony" = 5, "virusfood" = 5)
result_amount = 60
-/datum/chemical_reaction/plantcolony
+/decl/chemical_reaction/instant/plantcolony
name = "nutriment"
id = "plantcolony"
result = "nutriment"
@@ -350,7 +151,7 @@
-/datum/chemical_reaction/slime_food
+/decl/chemical_reaction/instant/slime_food
name = "Slime Bork"
id = "m_tele2"
result = null
@@ -378,7 +179,7 @@
-/datum/chemical_reaction/materials
+/decl/chemical_reaction/instant/materials
name = "Slime materials"
id = "slimematerial"
result = null
@@ -435,7 +236,7 @@
C.loc = get_turf(holder.my_atom)
-/datum/chemical_reaction/slimelight
+/decl/chemical_reaction/instant/slimelight
name = "Slime Glow"
id = "m_glow"
result = null
@@ -448,7 +249,7 @@
F.loc = get_turf(holder.my_atom)
-/datum/chemical_reaction/slimephoron
+/decl/chemical_reaction/instant/slimephoron
name = "Slime Phoron"
id = "m_plasma"
result = null
@@ -459,7 +260,7 @@
P.amount = 10
P.loc = get_turf(holder.my_atom)
-/datum/chemical_reaction/slimefreeze
+/decl/chemical_reaction/instant/slimefreeze
name = "Slime Freeze"
id = "m_freeze"
result = null
@@ -477,7 +278,7 @@
-/datum/chemical_reaction/slimefrost
+/decl/chemical_reaction/instant/slimefrost
name = "Slime Frost Oil"
id = "m_frostoil"
result = "frostoil"
@@ -487,7 +288,7 @@
-/datum/chemical_reaction/slimefire
+/decl/chemical_reaction/instant/slimefire
name = "Slime fire"
id = "m_fire"
result = null
@@ -503,7 +304,7 @@
spawn (0) target_tile.hotspot_expose(700, 400)
-/datum/chemical_reaction/slimeify
+/decl/chemical_reaction/instant/slimeify
name = "Advanced Mutation Toxin"
id = "advmutationtoxin2"
result = "advmutationtoxin"
@@ -514,7 +315,7 @@
-/datum/chemical_reaction/slimeheal //A slime healing mixture. Why not.
+/decl/chemical_reaction/instant/slimeheal //A slime healing mixture. Why not.
name = "Slime Health"
id = "slimeheal"
result = "null"
@@ -530,14 +331,14 @@
C.adjustCloneLoss(-25)
C.updatehealth()
-/datum/chemical_reaction/slimejelly
+/decl/chemical_reaction/instant/slimejelly
name = "Slime Jam"
id = "m_jam"
result = "slimejelly"
required_reagents = list("phoron" = 20, "sugar" = 50, "lithium" = 50) //In case a xenobiologist is impatient and is willing to drain their dispenser resources, along with plasma!
result_amount = 5
-/datum/chemical_reaction/slimevore
+/decl/chemical_reaction/instant/slimevore
name = "Slime Vore" // Hostile vore mobs only
id = "m_tele"
result = null
@@ -600,9 +401,13 @@
for(var/j = 1, j <= rand(1, 3), j++)
step(C, pick(NORTH,SOUTH,EAST,WEST))
+/decl/chemical_reaction/instant/slime/sapphire_mutation
+ name = "Slime Mutation Toxins"
+ id = "slime_mutation_tox"
+ result = "mutationtoxin"
+ required_reagents = list("blood" = 5)
+ result_amount = 30
+ required = /obj/item/slime_extract/sapphire
-/datum/chemical_reaction/food/syntiflesh
- required_reagents = list("blood" = 5, "clonexadone" = 1)
-
-/datum/chemical_reaction/biomass
+/decl/chemical_reaction/instant/biomass
result_amount = 6 // Roughly 120u per phoron sheet
diff --git a/code/modules/reagents/Chemistry-Readme.dm b/code/modules/reagents/readme.md
similarity index 97%
rename from code/modules/reagents/Chemistry-Readme.dm
rename to code/modules/reagents/readme.md
index 2b7e3a832a3..f9dac66b08d 100644
--- a/code/modules/reagents/Chemistry-Readme.dm
+++ b/code/modules/reagents/readme.md
@@ -1,305 +1,305 @@
-/*
-NOTE: IF YOU UPDATE THE REAGENT-SYSTEM, ALSO UPDATE THIS README.
-
-Structure: /////////////////// //////////////////////////
- // Mob or object // -------> // Reagents var (datum) // Is a reference to the datum that holds the reagents.
- /////////////////// //////////////////////////
- | |
- The object that holds everything. V
- reagent_list var (list) A List of datums, each datum is a reagent.
-
- | | |
- V V V
-
- reagents (datums) Reagents. I.e. Water , antitoxins or mercury.
-
-
-Random important notes:
-
- An objects on_reagent_change will be called every time the objects reagents change.
- Useful if you want to update the objects icon etc.
-
-About the Holder:
-
- The holder (reagents datum) is the datum that holds a list of all reagents
- currently in the object.It also has all the procs needed to manipulate reagents
-
- Vars:
- list/datum/reagent/reagent_list
- List of reagent datums.
-
- total_volume
- Total volume of all reagents.
-
- maximum_volume
- Maximum volume.
-
- atom/my_atom
- Reference to the object that contains this.
-
- Procs:
-
- get_free_space()
- Returns the remaining free volume in the holder.
-
- get_master_reagent()
- Returns the reference to the reagent with the largest volume
-
- get_master_reagent_name()
- Ditto, but returns the name.
-
- get_master_reagent_id()
- Ditto, but returns ID.
-
- update_total()
- Updates total volume, called automatically.
-
- handle_reactions()
- Checks reagents and triggers any reactions that happen. Usually called automatically.
-
- add_reagent(var/id, var/amount, var/data = null, var/safety = 0)
- Adds [amount] units of [id] reagent. [data] will be passed to reagent's mix_data() or initialize_data(). If [safety] is 0, handle_reactions() will be called. Returns 1 if successful, 0 otherwise.
-
- remove_reagent(var/id, var/amount, var/safety = 0)
- Ditto, but removes reagent. Returns 1 if successful, 0 otherwise.
-
- del_reagent(var/id)
- Removes all of the reagent.
-
- has_reagent(var/id, var/amount = 0)
- Checks if holder has at least [amount] of [id] reagent. Returns 1 if the reagent is found and volume is above [amount]. Returns 0 otherwise.
-
- clear_reagents()
- Removes all reagents.
-
- get_reagent_amount(var/id)
- Returns reagent volume. Returns 0 if reagent is not found.
-
- get_data(var/id)
- Returns get_data() of the reagent.
-
- get_reagents()
- Returns a string containing all reagent ids and volumes, e.g. "carbon(4),nittrogen(5)".
-
- remove_any(var/amount = 1)
- Removes up to [amount] of reagents from [src]. Returns actual amount removed.
-
- trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
- Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. Returns actual amount removed from [src] (not amount transferred to [target]). If [copy] is 1, copies reagents instead.
-
- touch(var/atom/target)
- When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent.
- This does not handle transferring reagents to things.
- For example, splashing someone with water will get them wet and extinguish them if they are on fire,
- even if they are wearing an impermeable suit that prevents the reagents from contacting the skin.
- Basically just defers to touch_mob(target), touch_turf(target), or touch_obj(target), depending on target's type.
- Not recommended to use this directly, since trans_to() calls it before attempting to transfer.
-
- touch_mob(var/mob/target)
- Calls each reagent's touch_mob(target).
-
- touch_turf(var/turf/target)
- Calls each reagent's touch_turf(target).
-
- touch_obj(var/obj/target)
- Calls each reagent's touch_obj(target).
-
- trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
- The general proc for applying reagents to things externally (as opposed to directly injected into the contents).
- It first calls touch, then the appropriate trans_to_*() or splash_mob().
- If for some reason you want touch effects to be bypassed (e.g. injecting stuff directly into a reagent container or person), call the appropriate trans_to_*() proc.
-
- Calls touch() before checking the type of [target], calling splash_mob(target, amount), trans_to_turf(target, amount, multiplier, copy), or trans_to_obj(target, amount, multiplier, copy).
-
- trans_id_to(var/atom/target, var/id, var/amount = 1)
- Transfers [amount] of [id] to [target]. Returns amount transferred.
-
- splash_mob(var/mob/target, var/amount = 1, var/clothes = 1)
- Checks mob's clothing if [clothes] is 1 and transfers [amount] reagents to mob's skin.
- Don't call this directly. Call apply_to() instead.
-
- trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_BLOOD, var/multiplier = 1, var/copy = 0)
- Transfers [amount] reagents to the mob's appropriate holder, depending on [type]. Ignores protection.
-
- trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
- Turfs don't currently have any reagents. Puts [amount] reagents into a temporary holder, calls touch_turf(target) from it, and deletes it.
-
- trans_to_obj(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
- If target has reagents, transfers [amount] to it. Otherwise, same as trans_to_turf().
-
- atom/proc/create_reagents(var/max_vol)
- Creates a new reagent datum.
-
-About Reagents:
-
- Reagents are all the things you can mix and fille in bottles etc. This can be anything from
- rejuvs over water to... iron.
-
- Vars:
-
- name
- Name that shows up in-game.
-
- id
- ID that is used for internal tracking. MUST BE UNIQUE.
-
- description
- Description that shows up in-game.
-
- datum/reagents/holder
- Reference to holder.
-
- reagent_state
- Could be GAS, LIQUID, or SOLID. Affects nothing. Reserved for future use.
-
- list/data
- Use varies by reagent. Custom variable. For example, blood stores blood group and viruses.
-
- volume
- Current volume.
-
- metabolism
- How quickly reagent is processed in mob's bloodstream; by default aslo affects ingest and touch metabolism.
-
- ingest_met
- How quickly reagent is processed when ingested; [metabolism] is used if zero.
-
- touch_met
- Ditto when touching.
-
- dose
- How much of the reagent has been processed, limited by [max_dose]. Used for reagents with varying effects (e.g. ethanol or rezadone) and overdosing.
-
- max_dose
- Maximum amount of reagent that has ever been in a mob. Exists so dose won't grow infinitely when small amounts of reagent are added over time.
-
- overdose
- If [dose] is bigger than [overdose], overdose() proc is called every tick.
-
- scannable
- If set to 1, will show up on health analyzers by name.
-
- affects_dead
- If set to 1, will affect dead players. Used by Adminordrazine.
-
- glass_icon_state
- Used by drinks. icon_state of the glass when this reagent is the master reagent.
-
- glass_name
- Ditto for glass name.
-
- glass_desc
- Ditto for glass desciption.
-
- glass_center_of_mass
- Used for glass placement on tables.
-
- color
- "#RRGGBB" or "#RRGGBBAA" where A is alpha channel.
-
- color_weight
- How much reagent affects color of holder. Used by paint.
-
- Procs:
-
- remove_self(var/amount)
- Removes [amount] of itself.
-
- touch_mob(var/mob/M)
- Called when reagent is in another holder and not splashing the mob. Can be used with noncarbons.
-
- touch_obj(var/obj/O)
- How reagent reacts with objects.
-
- touch_turf(var/turf/T)
- How reagent reacts with turfs.
-
- on_mob_life(var/mob/living/carbon/M, var/alien, var/location)
- Makes necessary checks and calls one of affect procs.
-
- affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
- How reagent affects mob when injected. [removed] is the amount of reagent that has been removed this tick. [alien] is the mob's reagent flag.
-
- affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
- Ditto, ingested. Defaults to affect_blood with halved dose.
-
- affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
- Ditto, touching.
-
- overdose(var/mob/living/carbon/M, var/alien)
- Called when dose is above overdose. Defaults to M.adjustToxLoss(REM).
-
- initialize_data(var/newdata)
- Called when reagent is created. Defaults to setting [data] to [newdata].
-
- mix_data(var/newdata, var/newamount)
- Called when [newamount] of reagent with [newdata] data is added to the current reagent. Used by paint.
-
- get_data()
- Returns data. Can be overriden.
-
-About Recipes:
-
- Recipes are simple datums that contain a list of required reagents and a result.
- They also have a proc that is called when the recipe is matched.
-
- Vars:
-
- name
- Name of the reaction, currently unused.
-
- id
- ID of the reaction, must be unique.
-
- result
- ID of the resulting reagent. Can be null.
-
- list/required_reagents
- Reagents that are required for the reaction and are used up during it.
-
- list/catalysts
- Ditto, but not used up.
-
- list/inhibitors
- Opposite, prevent the reaction from happening.
-
- result_amount
- Amount of resulting reagent.
-
- mix_message
- Message that is shown to mobs when reaction happens.
-
- Procs:
-
- can_happen(var/datum/reagents/holder)
- Customizable. If it returns 0, reaction will not happen. Defaults to always returning 1. Used by slime core reactions.
-
- on_reaction(var/datum/reagents/holder, var/created_volume)
- Called when reaction happens. Used by explosives.
-
- send_data(var/datum/reagents/T)
- Sets resulting reagent's data. Used by blood paint.
-
-About the Tools:
-
- By default, all atom have a reagents var - but its empty. if you want to use an object for the chem.
- system you'll need to add something like this in its new proc:
-
- atom/proc/create_reagents(var/max_volume)
-
- Other important stuff:
-
- amount_per_transfer_from_this var
- This var is mostly used by beakers and bottles.
- It simply tells us how much to transfer when
- 'pouring' our reagents into something else.
-
- atom/proc/is_open_container()
- Checks atom/var/flags & OPENCONTAINER.
- If this returns 1 , you can use syringes, beakers etc
- to manipulate the contents of this object.
- If it's 0, you'll need to write your own custom reagent
- transfer code since you will not be able to use the standard
- tools to manipulate it.
-
+/*
+NOTE: IF YOU UPDATE THE REAGENT-SYSTEM, ALSO UPDATE THIS README.
+
+Structure: /////////////////// //////////////////////////
+ // Mob or object // -------> // Reagents var (datum) // Is a reference to the datum that holds the reagents.
+ /////////////////// //////////////////////////
+ | |
+ The object that holds everything. V
+ reagent_list var (list) A List of datums, each datum is a reagent.
+
+ | | |
+ V V V
+
+ reagents (datums) Reagents. I.e. Water , antitoxins or mercury.
+
+
+Random important notes:
+
+ An objects on_reagent_change will be called every time the objects reagents change.
+ Useful if you want to update the objects icon etc.
+
+About the Holder:
+
+ The holder (reagents datum) is the datum that holds a list of all reagents
+ currently in the object.It also has all the procs needed to manipulate reagents
+
+ Vars:
+ list/datum/reagent/reagent_list
+ List of reagent datums.
+
+ total_volume
+ Total volume of all reagents.
+
+ maximum_volume
+ Maximum volume.
+
+ atom/my_atom
+ Reference to the object that contains this.
+
+ Procs:
+
+ get_free_space()
+ Returns the remaining free volume in the holder.
+
+ get_master_reagent()
+ Returns the reference to the reagent with the largest volume
+
+ get_master_reagent_name()
+ Ditto, but returns the name.
+
+ get_master_reagent_id()
+ Ditto, but returns ID.
+
+ update_total()
+ Updates total volume, called automatically.
+
+ handle_reactions()
+ Checks reagents and triggers any reactions that happen. Usually called automatically.
+
+ add_reagent(var/id, var/amount, var/data = null, var/safety = 0)
+ Adds [amount] units of [id] reagent. [data] will be passed to reagent's mix_data() or initialize_data(). If [safety] is 0, handle_reactions() will be called. Returns 1 if successful, 0 otherwise.
+
+ remove_reagent(var/id, var/amount, var/safety = 0)
+ Ditto, but removes reagent. Returns 1 if successful, 0 otherwise.
+
+ del_reagent(var/id)
+ Removes all of the reagent.
+
+ has_reagent(var/id, var/amount = 0)
+ Checks if holder has at least [amount] of [id] reagent. Returns 1 if the reagent is found and volume is above [amount]. Returns 0 otherwise.
+
+ clear_reagents()
+ Removes all reagents.
+
+ get_reagent_amount(var/id)
+ Returns reagent volume. Returns 0 if reagent is not found.
+
+ get_data(var/id)
+ Returns get_data() of the reagent.
+
+ get_reagents()
+ Returns a string containing all reagent ids and volumes, e.g. "carbon(4),nittrogen(5)".
+
+ remove_any(var/amount = 1)
+ Removes up to [amount] of reagents from [src]. Returns actual amount removed.
+
+ trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
+ Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. Returns actual amount removed from [src] (not amount transferred to [target]). If [copy] is 1, copies reagents instead.
+
+ touch(var/atom/target)
+ When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent.
+ This does not handle transferring reagents to things.
+ For example, splashing someone with water will get them wet and extinguish them if they are on fire,
+ even if they are wearing an impermeable suit that prevents the reagents from contacting the skin.
+ Basically just defers to touch_mob(target), touch_turf(target), or touch_obj(target), depending on target's type.
+ Not recommended to use this directly, since trans_to() calls it before attempting to transfer.
+
+ touch_mob(var/mob/target)
+ Calls each reagent's touch_mob(target).
+
+ touch_turf(var/turf/target)
+ Calls each reagent's touch_turf(target).
+
+ touch_obj(var/obj/target)
+ Calls each reagent's touch_obj(target).
+
+ trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
+ The general proc for applying reagents to things externally (as opposed to directly injected into the contents).
+ It first calls touch, then the appropriate trans_to_*() or splash_mob().
+ If for some reason you want touch effects to be bypassed (e.g. injecting stuff directly into a reagent container or person), call the appropriate trans_to_*() proc.
+
+ Calls touch() before checking the type of [target], calling splash_mob(target, amount), trans_to_turf(target, amount, multiplier, copy), or trans_to_obj(target, amount, multiplier, copy).
+
+ trans_id_to(var/atom/target, var/id, var/amount = 1)
+ Transfers [amount] of [id] to [target]. Returns amount transferred.
+
+ splash_mob(var/mob/target, var/amount = 1, var/clothes = 1)
+ Checks mob's clothing if [clothes] is 1 and transfers [amount] reagents to mob's skin.
+ Don't call this directly. Call apply_to() instead.
+
+ trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_BLOOD, var/multiplier = 1, var/copy = 0)
+ Transfers [amount] reagents to the mob's appropriate holder, depending on [type]. Ignores protection.
+
+ trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
+ Turfs don't currently have any reagents. Puts [amount] reagents into a temporary holder, calls touch_turf(target) from it, and deletes it.
+
+ trans_to_obj(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
+ If target has reagents, transfers [amount] to it. Otherwise, same as trans_to_turf().
+
+ atom/proc/create_reagents(var/max_vol)
+ Creates a new reagent datum.
+
+About Reagents:
+
+ Reagents are all the things you can mix and fille in bottles etc. This can be anything from
+ rejuvs over water to... iron.
+
+ Vars:
+
+ name
+ Name that shows up in-game.
+
+ id
+ ID that is used for internal tracking. MUST BE UNIQUE.
+
+ description
+ Description that shows up in-game.
+
+ datum/reagents/holder
+ Reference to holder.
+
+ reagent_state
+ Could be GAS, LIQUID, or SOLID. Affects nothing. Reserved for future use.
+
+ list/data
+ Use varies by reagent. Custom variable. For example, blood stores blood group and viruses.
+
+ volume
+ Current volume.
+
+ metabolism
+ How quickly reagent is processed in mob's bloodstream; by default aslo affects ingest and touch metabolism.
+
+ ingest_met
+ How quickly reagent is processed when ingested; [metabolism] is used if zero.
+
+ touch_met
+ Ditto when touching.
+
+ dose
+ How much of the reagent has been processed, limited by [max_dose]. Used for reagents with varying effects (e.g. ethanol or rezadone) and overdosing.
+
+ max_dose
+ Maximum amount of reagent that has ever been in a mob. Exists so dose won't grow infinitely when small amounts of reagent are added over time.
+
+ overdose
+ If [dose] is bigger than [overdose], overdose() proc is called every tick.
+
+ scannable
+ If set to 1, will show up on health analyzers by name.
+
+ affects_dead
+ If set to 1, will affect dead players. Used by Adminordrazine.
+
+ glass_icon_state
+ Used by drinks. icon_state of the glass when this reagent is the master reagent.
+
+ glass_name
+ Ditto for glass name.
+
+ glass_desc
+ Ditto for glass desciption.
+
+ glass_center_of_mass
+ Used for glass placement on tables.
+
+ color
+ "#RRGGBB" or "#RRGGBBAA" where A is alpha channel.
+
+ color_weight
+ How much reagent affects color of holder. Used by paint.
+
+ Procs:
+
+ remove_self(var/amount)
+ Removes [amount] of itself.
+
+ touch_mob(var/mob/M)
+ Called when reagent is in another holder and not splashing the mob. Can be used with noncarbons.
+
+ touch_obj(var/obj/O)
+ How reagent reacts with objects.
+
+ touch_turf(var/turf/T)
+ How reagent reacts with turfs.
+
+ on_mob_life(var/mob/living/carbon/M, var/alien, var/location)
+ Makes necessary checks and calls one of affect procs.
+
+ affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ How reagent affects mob when injected. [removed] is the amount of reagent that has been removed this tick. [alien] is the mob's reagent flag.
+
+ affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
+ Ditto, ingested. Defaults to affect_blood with halved dose.
+
+ affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
+ Ditto, touching.
+
+ overdose(var/mob/living/carbon/M, var/alien)
+ Called when dose is above overdose. Defaults to M.adjustToxLoss(REM).
+
+ initialize_data(var/newdata)
+ Called when reagent is created. Defaults to setting [data] to [newdata].
+
+ mix_data(var/newdata, var/newamount)
+ Called when [newamount] of reagent with [newdata] data is added to the current reagent. Used by paint.
+
+ get_data()
+ Returns data. Can be overriden.
+
+About Recipes:
+
+ Recipes are simple datums that contain a list of required reagents and a result.
+ They also have a proc that is called when the recipe is matched.
+
+ Vars:
+
+ name
+ Name of the reaction, currently unused.
+
+ id
+ ID of the reaction, must be unique.
+
+ result
+ ID of the resulting reagent. Can be null.
+
+ list/required_reagents
+ Reagents that are required for the reaction and are used up during it.
+
+ list/catalysts
+ Ditto, but not used up.
+
+ list/inhibitors
+ Opposite, prevent the reaction from happening.
+
+ result_amount
+ Amount of resulting reagent.
+
+ mix_message
+ Message that is shown to mobs when reaction happens.
+
+ Procs:
+
+ can_happen(var/datum/reagents/holder)
+ Customizable. If it returns 0, reaction will not happen. Defaults to always returning 1. Used by slime core reactions.
+
+ on_reaction(var/datum/reagents/holder, var/created_volume)
+ Called when reaction happens. Used by explosives.
+
+ send_data(var/datum/reagents/T)
+ Sets resulting reagent's data. Used by blood paint.
+
+About the Tools:
+
+ By default, all atom have a reagents var - but its empty. if you want to use an object for the chem.
+ system you'll need to add something like this in its new proc:
+
+ atom/proc/create_reagents(var/max_volume)
+
+ Other important stuff:
+
+ amount_per_transfer_from_this var
+ This var is mostly used by beakers and bottles.
+ It simply tells us how much to transfer when
+ 'pouring' our reagents into something else.
+
+ atom/proc/is_open_container()
+ Checks atom/var/flags & OPENCONTAINER.
+ If this returns 1 , you can use syringes, beakers etc
+ to manipulate the contents of this object.
+ If it's 0, you'll need to write your own custom reagent
+ transfer code since you will not be able to use the standard
+ tools to manipulate it.
+
*/
\ No newline at end of file
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers/_reagent_containers.dm
similarity index 97%
rename from code/modules/reagents/reagent_containers.dm
rename to code/modules/reagents/reagent_containers/_reagent_containers.dm
index 7a6927f49de..64dd2622d2e 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers/_reagent_containers.dm
@@ -1,145 +1,145 @@
-/obj/item/weapon/reagent_containers
- name = "Container"
- desc = "..."
- icon = 'icons/obj/chemical.dmi'
- icon_state = null
- w_class = ITEMSIZE_SMALL
- var/amount_per_transfer_from_this = 5
- var/possible_transfer_amounts = list(5,10,15,25,30)
- var/volume = 30
-
-/obj/item/weapon/reagent_containers/verb/set_APTFT() //set amount_per_transfer_from_this
- set name = "Set transfer amount"
- set category = "Object"
- set src in range(0)
- var/N = input("Amount per transfer from this:","[src]") as null|anything in possible_transfer_amounts
- if(N)
- amount_per_transfer_from_this = N
-
-/obj/item/weapon/reagent_containers/Initialize()
- . = ..()
- if(!possible_transfer_amounts)
- src.verbs -= /obj/item/weapon/reagent_containers/verb/set_APTFT
- create_reagents(volume)
-
-/obj/item/weapon/reagent_containers/attack_self(mob/user as mob)
- return
-
-/obj/item/weapon/reagent_containers/afterattack(obj/target, mob/user, flag)
- return
-
-/obj/item/weapon/reagent_containers/proc/reagentlist() // For attack logs
- if(reagents)
- return reagents.get_reagents()
- return "No reagent holder"
-
-/obj/item/weapon/reagent_containers/proc/standard_dispenser_refill(var/mob/user, var/obj/structure/reagent_dispensers/target) // This goes into afterattack
- if(!istype(target))
- return 0
-
- if(!target.reagents || !target.reagents.total_volume)
- to_chat(user, "[target] is empty.")
- return 1
-
- if(reagents && !reagents.get_free_space())
- to_chat(user, "[src] is full.")
- return 1
-
- var/trans = target.reagents.trans_to_obj(src, target:amount_per_transfer_from_this)
- to_chat(user, "You fill [src] with [trans] units of the contents of [target].")
- return 1
-
-/obj/item/weapon/reagent_containers/proc/standard_splash_mob(var/mob/user, var/mob/target) // This goes into afterattack
- if(!istype(target))
- return
-
- if(!reagents || !reagents.total_volume)
- to_chat(user, "[src] is empty.")
- return 1
-
- if(target.reagents && !target.reagents.get_free_space())
- to_chat(user, "[target] is full.")
- return 1
-
- var/contained = reagentlist()
- add_attack_logs(user,target,"Splashed with [src.name] containing [contained]")
- user.visible_message("[target] has been splashed with something by [user]!", "You splash the solution onto [target].")
- reagents.splash(target, reagents.total_volume)
- return 1
-
-/obj/item/weapon/reagent_containers/proc/self_feed_message(var/mob/user)
- to_chat(user, "You eat \the [src]")
-
-/obj/item/weapon/reagent_containers/proc/other_feed_message_start(var/mob/user, var/mob/target)
- user.visible_message("[user] is trying to feed [target] \the [src]!")
-
-/obj/item/weapon/reagent_containers/proc/other_feed_message_finish(var/mob/user, var/mob/target)
- user.visible_message("[user] has fed [target] \the [src]!")
-
-/obj/item/weapon/reagent_containers/proc/feed_sound(var/mob/user)
- return
-
-/obj/item/weapon/reagent_containers/proc/standard_feed_mob(var/mob/user, var/mob/target) // This goes into attack
- if(!istype(target))
- return 0
-
- if(!reagents || !reagents.total_volume)
- to_chat(user, "\The [src] is empty.")
- return 1
-
- if(target == user)
- if(istype(user, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = user
- if(!H.check_has_mouth())
- to_chat(user, "Where do you intend to put \the [src]? You don't have a mouth!")
- return
- var/obj/item/blocked = H.check_mouth_coverage()
- if(blocked)
- to_chat(user, "\The [blocked] is in the way!")
- return
-
- user.setClickCooldown(user.get_attack_speed(src)) //puts a limit on how fast people can eat/drink things
- self_feed_message(user)
- reagents.trans_to_mob(user, issmall(user) ? CEILING(amount_per_transfer_from_this/2, 1) : amount_per_transfer_from_this, CHEM_INGEST)
- feed_sound(user)
- return 1
- else
- if(istype(target, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = target
- if(!H.check_has_mouth())
- to_chat(user, "Where do you intend to put \the [src]? \The [H] doesn't have a mouth!")
- return
- var/obj/item/blocked = H.check_mouth_coverage()
- if(blocked)
- to_chat(user, "\The [blocked] is in the way!")
- return
-
- other_feed_message_start(user, target)
-
- user.setClickCooldown(user.get_attack_speed(src))
- if(!do_mob(user, target))
- return
-
- other_feed_message_finish(user, target)
-
- var/contained = reagentlist()
- add_attack_logs(user,target,"Fed from [src.name] containing [contained]")
- reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_INGEST)
- feed_sound(user)
- return 1
-
-/obj/item/weapon/reagent_containers/proc/standard_pour_into(var/mob/user, var/atom/target) // This goes into afterattack and yes, it's atom-level
- if(!target.is_open_container() || !target.reagents)
- return 0
-
- if(!reagents || !reagents.total_volume)
- to_chat(user, "[src] is empty.")
- return 1
-
- if(!target.reagents.get_free_space())
- to_chat(user, "[target] is full.")
- return 1
-
- var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
- to_chat(user, "You transfer [trans] units of the solution to [target].")
- return 1
+/obj/item/weapon/reagent_containers
+ name = "Container"
+ desc = "..."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = null
+ w_class = ITEMSIZE_SMALL
+ var/amount_per_transfer_from_this = 5
+ var/possible_transfer_amounts = list(5,10,15,25,30)
+ var/volume = 30
+
+/obj/item/weapon/reagent_containers/verb/set_APTFT() //set amount_per_transfer_from_this
+ set name = "Set transfer amount"
+ set category = "Object"
+ set src in range(0)
+ var/N = input("Amount per transfer from this:","[src]") as null|anything in possible_transfer_amounts
+ if(N)
+ amount_per_transfer_from_this = N
+
+/obj/item/weapon/reagent_containers/Initialize()
+ . = ..()
+ if(!possible_transfer_amounts)
+ src.verbs -= /obj/item/weapon/reagent_containers/verb/set_APTFT
+ create_reagents(volume)
+
+/obj/item/weapon/reagent_containers/attack_self(mob/user as mob)
+ return
+
+/obj/item/weapon/reagent_containers/afterattack(obj/target, mob/user, flag)
+ return
+
+/obj/item/weapon/reagent_containers/proc/reagentlist() // For attack logs
+ if(reagents)
+ return reagents.get_reagents()
+ return "No reagent holder"
+
+/obj/item/weapon/reagent_containers/proc/standard_dispenser_refill(var/mob/user, var/obj/structure/reagent_dispensers/target) // This goes into afterattack
+ if(!istype(target))
+ return 0
+
+ if(!target.reagents || !target.reagents.total_volume)
+ to_chat(user, "[target] is empty.")
+ return 1
+
+ if(reagents && !reagents.get_free_space())
+ to_chat(user, "[src] is full.")
+ return 1
+
+ var/trans = target.reagents.trans_to_obj(src, target:amount_per_transfer_from_this)
+ to_chat(user, "You fill [src] with [trans] units of the contents of [target].")
+ return 1
+
+/obj/item/weapon/reagent_containers/proc/standard_splash_mob(var/mob/user, var/mob/target) // This goes into afterattack
+ if(!istype(target))
+ return
+
+ if(!reagents || !reagents.total_volume)
+ to_chat(user, "[src] is empty.")
+ return 1
+
+ if(target.reagents && !target.reagents.get_free_space())
+ to_chat(user, "[target] is full.")
+ return 1
+
+ var/contained = reagentlist()
+ add_attack_logs(user,target,"Splashed with [src.name] containing [contained]")
+ user.visible_message("[target] has been splashed with something by [user]!", "You splash the solution onto [target].")
+ reagents.splash(target, reagents.total_volume)
+ return 1
+
+/obj/item/weapon/reagent_containers/proc/self_feed_message(var/mob/user)
+ to_chat(user, "You eat \the [src]")
+
+/obj/item/weapon/reagent_containers/proc/other_feed_message_start(var/mob/user, var/mob/target)
+ user.visible_message("[user] is trying to feed [target] \the [src]!")
+
+/obj/item/weapon/reagent_containers/proc/other_feed_message_finish(var/mob/user, var/mob/target)
+ user.visible_message("[user] has fed [target] \the [src]!")
+
+/obj/item/weapon/reagent_containers/proc/feed_sound(var/mob/user)
+ return
+
+/obj/item/weapon/reagent_containers/proc/standard_feed_mob(var/mob/user, var/mob/target) // This goes into attack
+ if(!istype(target))
+ return 0
+
+ if(!reagents || !reagents.total_volume)
+ to_chat(user, "\The [src] is empty.")
+ return 1
+
+ if(target == user)
+ if(istype(user, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = user
+ if(!H.check_has_mouth())
+ to_chat(user, "Where do you intend to put \the [src]? You don't have a mouth!")
+ return
+ var/obj/item/blocked = H.check_mouth_coverage()
+ if(blocked)
+ to_chat(user, "\The [blocked] is in the way!")
+ return
+
+ user.setClickCooldown(user.get_attack_speed(src)) //puts a limit on how fast people can eat/drink things
+ self_feed_message(user)
+ reagents.trans_to_mob(user, issmall(user) ? CEILING(amount_per_transfer_from_this/2, 1) : amount_per_transfer_from_this, CHEM_INGEST)
+ feed_sound(user)
+ return 1
+ else
+ if(istype(target, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = target
+ if(!H.check_has_mouth())
+ to_chat(user, "Where do you intend to put \the [src]? \The [H] doesn't have a mouth!")
+ return
+ var/obj/item/blocked = H.check_mouth_coverage()
+ if(blocked)
+ to_chat(user, "\The [blocked] is in the way!")
+ return
+
+ other_feed_message_start(user, target)
+
+ user.setClickCooldown(user.get_attack_speed(src))
+ if(!do_mob(user, target))
+ return
+
+ other_feed_message_finish(user, target)
+
+ var/contained = reagentlist()
+ add_attack_logs(user,target,"Fed from [src.name] containing [contained]")
+ reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_INGEST)
+ feed_sound(user)
+ return 1
+
+/obj/item/weapon/reagent_containers/proc/standard_pour_into(var/mob/user, var/atom/target) // This goes into afterattack and yes, it's atom-level
+ if(!target.is_open_container() || !target.reagents)
+ return 0
+
+ if(!reagents || !reagents.total_volume)
+ to_chat(user, "[src] is empty.")
+ return 1
+
+ if(!target.reagents.get_free_space())
+ to_chat(user, "[target] is full.")
+ return 1
+
+ var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
+ to_chat(user, "You transfer [trans] units of the solution to [target].")
+ return 1
diff --git a/code/modules/reagents/Chemistry-Reagents-Helpers.dm b/code/modules/reagents/reagents/_helpers.dm
similarity index 100%
rename from code/modules/reagents/Chemistry-Reagents-Helpers.dm
rename to code/modules/reagents/reagents/_helpers.dm
diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/reagents/_reagents.dm
similarity index 97%
rename from code/modules/reagents/Chemistry-Reagents.dm
rename to code/modules/reagents/reagents/_reagents.dm
index 3d32c006637..00bb509b7f6 100644
--- a/code/modules/reagents/Chemistry-Reagents.dm
+++ b/code/modules/reagents/reagents/_reagents.dm
@@ -1,237 +1,237 @@
-
-
-
-/datum/reagent
- var/name = "Reagent"
- var/id = "reagent"
- var/description = "A non-descript chemical."
- var/taste_description = "bitterness"
- var/taste_mult = 1 //how this taste compares to others. Higher values means it is more noticable
- var/datum/reagents/holder = null
- var/reagent_state = SOLID
- var/list/data = null
- var/volume = 0
- var/metabolism = REM // This would be 0.2 normally
- var/list/filtered_organs = list() // Organs that will slow the processing of this chemical.
- var/mrate_static = FALSE //If the reagent should always process at the same speed, regardless of species, make this TRUE
- var/ingest_met = 0
- var/touch_met = 0
- var/dose = 0
- var/max_dose = 0
- var/overdose = 0 //Amount at which overdose starts
- var/overdose_mod = 1 //Modifier to overdose damage
- var/can_overdose_touch = FALSE // Can the chemical OD when processing on touch?
- var/scannable = 0 // Shows up on health analyzers.
-
- var/affects_dead = 0 // Does this chem process inside a corpse?
- var/affects_robots = 0 // Does this chem process inside a Synth?
-
- var/allergen_type = GENERIC // What potential allergens does this contain?
- var/allergen_factor = 1 // If the potential allergens are mixed and low-volume, they're a bit less dangerous. Needed for drinks because they're a single reagent compared to food which contains multiple seperate reagents.
-
- var/cup_icon_state = null
- var/cup_name = null
- var/cup_desc = null
- var/cup_center_of_mass = null
-
- var/color = "#000000"
- var/color_weight = 1
-
- var/glass_icon = DRINK_ICON_DEFAULT
- var/glass_name = "something"
- var/glass_desc = "It's a glass of... what, exactly?"
- var/list/glass_special = null // null equivalent to list()
-
-/datum/reagent/proc/remove_self(var/amount) // Shortcut
- if(holder)
- holder.remove_reagent(id, amount)
-
-// This doesn't apply to skin contact - this is for, e.g. extinguishers and sprays. The difference is that reagent is not directly on the mob's skin - it might just be on their clothing.
-/datum/reagent/proc/touch_mob(var/mob/M, var/amount)
- return
-
-/datum/reagent/proc/touch_obj(var/obj/O, var/amount) // Acid melting, cleaner cleaning, etc
- return
-
-/datum/reagent/proc/touch_turf(var/turf/T, var/amount) // Cleaner cleaning, lube lubbing, etc, all go here
- return
-
-/datum/reagent/proc/on_mob_life(var/mob/living/carbon/M, var/alien, var/datum/reagents/metabolism/location) // Currently, on_mob_life is called on carbons. Any interaction with non-carbon mobs (lube) will need to be done in touch_mob.
- if(!istype(M))
- return
- if(!affects_dead && M.stat == DEAD)
- return
- if(!affects_robots && M.isSynthetic())
- return
- if(!istype(location))
- return
-
- var/datum/reagents/metabolism/active_metab = location
- var/removed = metabolism
-
- var/ingest_rem_mult = 1
- var/ingest_abs_mult = 1
-
- if(!mrate_static == TRUE)
- // Modifiers
- for(var/datum/modifier/mod in M.modifiers)
- if(!isnull(mod.metabolism_percent))
- removed *= mod.metabolism_percent
- ingest_rem_mult *= mod.metabolism_percent
- // Species
- removed *= M.species.metabolic_rate
- ingest_rem_mult *= M.species.metabolic_rate
- // Metabolism
- removed *= active_metab.metabolism_speed
- ingest_rem_mult *= active_metab.metabolism_speed
-
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(!H.isSynthetic())
- if(H.species.has_organ[O_HEART] && (active_metab.metabolism_class == CHEM_BLOOD))
- var/obj/item/organ/internal/heart/Pump = H.internal_organs_by_name[O_HEART]
- if(!Pump)
- removed *= 0.1
- else if(Pump.standard_pulse_level == PULSE_NONE) // No pulse normally means chemicals process a little bit slower than normal.
- removed *= 0.8
- else // Otherwise, chemicals process as per percentage of your current pulse, or, if you have no pulse but are alive, by a miniscule amount.
- removed *= max(0.1, H.pulse / Pump.standard_pulse_level)
-
- if(H.species.has_organ[O_STOMACH] && (active_metab.metabolism_class == CHEM_INGEST))
- var/obj/item/organ/internal/stomach/Chamber = H.internal_organs_by_name[O_STOMACH]
- if(Chamber)
- ingest_rem_mult *= max(0.1, 1 - (Chamber.damage / Chamber.max_damage))
- else
- ingest_rem_mult = 0.1
-
- if(H.species.has_organ[O_INTESTINE] && (active_metab.metabolism_class == CHEM_INGEST))
- var/obj/item/organ/internal/intestine/Tube = H.internal_organs_by_name[O_INTESTINE]
- if(Tube)
- ingest_abs_mult *= max(0.1, 1 - (Tube.damage / Tube.max_damage))
- else
- ingest_abs_mult = 0.1
-
- else
- var/obj/item/organ/internal/heart/machine/Pump = H.internal_organs_by_name[O_PUMP]
- var/obj/item/organ/internal/stomach/machine/Cycler = H.internal_organs_by_name[O_CYCLER]
-
- if(active_metab.metabolism_class == CHEM_BLOOD)
- if(Pump)
- removed *= 1.1 - Pump.damage / Pump.max_damage
- else
- removed *= 0.1
-
- else if(active_metab.metabolism_class == CHEM_INGEST) // If the pump is damaged, we waste chems from the tank.
- if(Pump)
- ingest_abs_mult *= max(0.25, 1 - Pump.damage / Pump.max_damage)
-
- else
- ingest_abs_mult *= 0.2
-
- if(Cycler) // If we're damaged, we empty our tank slower.
- ingest_rem_mult = max(0.1, 1 - (Cycler.damage / Cycler.max_damage))
-
- else
- ingest_rem_mult = 0.1
-
- else if(active_metab.metabolism_class == CHEM_TOUCH) // Machines don't exactly absorb chemicals.
- removed *= 0.5
-
- if(filtered_organs && filtered_organs.len)
- for(var/organ_tag in filtered_organs)
- var/obj/item/organ/internal/O = H.internal_organs_by_name[organ_tag]
- if(O && !O.is_broken() && prob(max(0, O.max_damage - O.damage)))
- removed *= 0.8
- if(active_metab.metabolism_class == CHEM_INGEST)
- ingest_rem_mult *= 0.8
-
- if(ingest_met && (active_metab.metabolism_class == CHEM_INGEST))
- removed = ingest_met * ingest_rem_mult
- if(touch_met && (active_metab.metabolism_class == CHEM_TOUCH))
- removed = touch_met
- removed = min(removed, volume)
- max_dose = max(volume, max_dose)
- dose = min(dose + removed, max_dose)
- if(removed >= (metabolism * 0.1) || removed >= 0.1) // If there's too little chemical, don't affect the mob, just remove it
- switch(active_metab.metabolism_class)
- if(CHEM_BLOOD)
- affect_blood(M, alien, removed)
- if(CHEM_INGEST)
- affect_ingest(M, alien, removed * ingest_abs_mult)
- if(CHEM_TOUCH)
- affect_touch(M, alien, removed)
- if(overdose && (volume > overdose * M?.species.chemOD_threshold) && (active_metab.metabolism_class != CHEM_TOUCH && !can_overdose_touch))
- overdose(M, alien, removed)
- if(M.species.allergens & allergen_type) //uhoh, we can't handle this!
- var/damage_severity = M.species.allergen_damage_severity*allergen_factor
- var/disable_severity = M.species.allergen_disable_severity*allergen_factor
- if(M.species.allergen_reaction & AG_TOX_DMG)
- M.adjustToxLoss(damage_severity)
- if(M.species.allergen_reaction & AG_OXY_DMG)
- M.adjustOxyLoss(damage_severity)
- if(prob(2.5*disable_severity))
- M.emote(pick("cough","gasp","choke"))
- if(M.species.allergen_reaction & AG_EMOTE)
- if(prob(2.5*disable_severity)) //this has a higher base chance, but not *too* high
- M.emote(pick("pale","shiver","twitch"))
- if(M.species.allergen_reaction & AG_PAIN)
- M.adjustHalLoss(disable_severity)
- if(M.species.allergen_reaction & AG_WEAKEN)
- M.Weaken(disable_severity)
- if(M.species.allergen_reaction & AG_BLURRY)
- M.eye_blurry = max(M.eye_blurry, disable_severity)
- if(M.species.allergen_reaction & AG_SLEEPY)
- M.drowsyness = max(M.drowsyness, disable_severity)
- remove_self(removed)
- return
-
-/datum/reagent/proc/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
- return
-
-/datum/reagent/proc/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
- M.bloodstr.add_reagent(id, removed)
- return
-
-/datum/reagent/proc/affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
- return
-
-/datum/reagent/proc/overdose(var/mob/living/carbon/M, var/alien, var/removed) // Overdose effect.
- if(alien == IS_DIONA)
- return
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- overdose_mod *= H.species.chemOD_mod
- // 6 damage per unit at minimum, scales with excessive reagents. Rounding should help keep damage consistent between ingest / inject, but isn't perfect.
- // Hardcapped at 3.6 damage per tick, or 18 damage per unit at 0.2 metabolic rate so that you can't instakill people with overdoses by feeding them infinite periadaxon.
- // Overall, max damage is slightly less effective than hydrophoron, and 1/5 as effective as cyanide.
- M.adjustToxLoss(min(removed * overdose_mod * round(3 + 3 * volume / overdose), 3.6))
-
-/datum/reagent/proc/initialize_data(var/newdata) // Called when the reagent is created.
- if(!isnull(newdata))
- data = newdata
- return
-
-/datum/reagent/proc/mix_data(var/newdata, var/newamount) // You have a reagent with data, and new reagent with its own data get added, how do you deal with that?
- return
-
-/datum/reagent/proc/get_data() // Just in case you have a reagent that handles data differently.
- if(data && istype(data, /list))
- return data.Copy()
- else if(data)
- return data
- return null
-
-/datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references
- holder = null
- . = ..()
-
-/* DEPRECATED - TODO: REMOVE EVERYWHERE */
-
-/datum/reagent/proc/reaction_turf(var/turf/target)
- touch_turf(target)
-
-/datum/reagent/proc/reaction_obj(var/obj/target)
- touch_obj(target)
-
-/datum/reagent/proc/reaction_mob(var/mob/target)
- touch_mob(target)
+
+
+
+/datum/reagent
+ var/name = "Reagent"
+ var/id = "reagent"
+ var/description = "A non-descript chemical."
+ var/taste_description = "bitterness"
+ var/taste_mult = 1 //how this taste compares to others. Higher values means it is more noticable
+ var/datum/reagents/holder = null
+ var/reagent_state = SOLID
+ var/list/data = null
+ var/volume = 0
+ var/metabolism = REM // This would be 0.2 normally
+ var/list/filtered_organs = list() // Organs that will slow the processing of this chemical.
+ var/mrate_static = FALSE //If the reagent should always process at the same speed, regardless of species, make this TRUE
+ var/ingest_met = 0
+ var/touch_met = 0
+ var/dose = 0
+ var/max_dose = 0
+ var/overdose = 0 //Amount at which overdose starts
+ var/overdose_mod = 1 //Modifier to overdose damage
+ var/can_overdose_touch = FALSE // Can the chemical OD when processing on touch?
+ var/scannable = 0 // Shows up on health analyzers.
+
+ var/affects_dead = 0 // Does this chem process inside a corpse?
+ var/affects_robots = 0 // Does this chem process inside a Synth?
+
+ var/allergen_type = GENERIC // What potential allergens does this contain?
+ var/allergen_factor = 1 // If the potential allergens are mixed and low-volume, they're a bit less dangerous. Needed for drinks because they're a single reagent compared to food which contains multiple seperate reagents.
+
+ var/cup_icon_state = null
+ var/cup_name = null
+ var/cup_desc = null
+ var/cup_center_of_mass = null
+
+ var/color = "#000000"
+ var/color_weight = 1
+
+ var/glass_icon = DRINK_ICON_DEFAULT
+ var/glass_name = "something"
+ var/glass_desc = "It's a glass of... what, exactly?"
+ var/list/glass_special = null // null equivalent to list()
+
+/datum/reagent/proc/remove_self(var/amount) // Shortcut
+ if(holder)
+ holder.remove_reagent(id, amount)
+
+// This doesn't apply to skin contact - this is for, e.g. extinguishers and sprays. The difference is that reagent is not directly on the mob's skin - it might just be on their clothing.
+/datum/reagent/proc/touch_mob(var/mob/M, var/amount)
+ return
+
+/datum/reagent/proc/touch_obj(var/obj/O, var/amount) // Acid melting, cleaner cleaning, etc
+ return
+
+/datum/reagent/proc/touch_turf(var/turf/T, var/amount) // Cleaner cleaning, lube lubbing, etc, all go here
+ return
+
+/datum/reagent/proc/on_mob_life(var/mob/living/carbon/M, var/alien, var/datum/reagents/metabolism/location) // Currently, on_mob_life is called on carbons. Any interaction with non-carbon mobs (lube) will need to be done in touch_mob.
+ if(!istype(M))
+ return
+ if(!affects_dead && M.stat == DEAD)
+ return
+ if(!affects_robots && M.isSynthetic())
+ return
+ if(!istype(location))
+ return
+
+ var/datum/reagents/metabolism/active_metab = location
+ var/removed = metabolism
+
+ var/ingest_rem_mult = 1
+ var/ingest_abs_mult = 1
+
+ if(!mrate_static == TRUE)
+ // Modifiers
+ for(var/datum/modifier/mod in M.modifiers)
+ if(!isnull(mod.metabolism_percent))
+ removed *= mod.metabolism_percent
+ ingest_rem_mult *= mod.metabolism_percent
+ // Species
+ removed *= M.species.metabolic_rate
+ ingest_rem_mult *= M.species.metabolic_rate
+ // Metabolism
+ removed *= active_metab.metabolism_speed
+ ingest_rem_mult *= active_metab.metabolism_speed
+
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(!H.isSynthetic())
+ if(H.species.has_organ[O_HEART] && (active_metab.metabolism_class == CHEM_BLOOD))
+ var/obj/item/organ/internal/heart/Pump = H.internal_organs_by_name[O_HEART]
+ if(!Pump)
+ removed *= 0.1
+ else if(Pump.standard_pulse_level == PULSE_NONE) // No pulse normally means chemicals process a little bit slower than normal.
+ removed *= 0.8
+ else // Otherwise, chemicals process as per percentage of your current pulse, or, if you have no pulse but are alive, by a miniscule amount.
+ removed *= max(0.1, H.pulse / Pump.standard_pulse_level)
+
+ if(H.species.has_organ[O_STOMACH] && (active_metab.metabolism_class == CHEM_INGEST))
+ var/obj/item/organ/internal/stomach/Chamber = H.internal_organs_by_name[O_STOMACH]
+ if(Chamber)
+ ingest_rem_mult *= max(0.1, 1 - (Chamber.damage / Chamber.max_damage))
+ else
+ ingest_rem_mult = 0.1
+
+ if(H.species.has_organ[O_INTESTINE] && (active_metab.metabolism_class == CHEM_INGEST))
+ var/obj/item/organ/internal/intestine/Tube = H.internal_organs_by_name[O_INTESTINE]
+ if(Tube)
+ ingest_abs_mult *= max(0.1, 1 - (Tube.damage / Tube.max_damage))
+ else
+ ingest_abs_mult = 0.1
+
+ else
+ var/obj/item/organ/internal/heart/machine/Pump = H.internal_organs_by_name[O_PUMP]
+ var/obj/item/organ/internal/stomach/machine/Cycler = H.internal_organs_by_name[O_CYCLER]
+
+ if(active_metab.metabolism_class == CHEM_BLOOD)
+ if(Pump)
+ removed *= 1.1 - Pump.damage / Pump.max_damage
+ else
+ removed *= 0.1
+
+ else if(active_metab.metabolism_class == CHEM_INGEST) // If the pump is damaged, we waste chems from the tank.
+ if(Pump)
+ ingest_abs_mult *= max(0.25, 1 - Pump.damage / Pump.max_damage)
+
+ else
+ ingest_abs_mult *= 0.2
+
+ if(Cycler) // If we're damaged, we empty our tank slower.
+ ingest_rem_mult = max(0.1, 1 - (Cycler.damage / Cycler.max_damage))
+
+ else
+ ingest_rem_mult = 0.1
+
+ else if(active_metab.metabolism_class == CHEM_TOUCH) // Machines don't exactly absorb chemicals.
+ removed *= 0.5
+
+ if(filtered_organs && filtered_organs.len)
+ for(var/organ_tag in filtered_organs)
+ var/obj/item/organ/internal/O = H.internal_organs_by_name[organ_tag]
+ if(O && !O.is_broken() && prob(max(0, O.max_damage - O.damage)))
+ removed *= 0.8
+ if(active_metab.metabolism_class == CHEM_INGEST)
+ ingest_rem_mult *= 0.8
+
+ if(ingest_met && (active_metab.metabolism_class == CHEM_INGEST))
+ removed = ingest_met * ingest_rem_mult
+ if(touch_met && (active_metab.metabolism_class == CHEM_TOUCH))
+ removed = touch_met
+ removed = min(removed, volume)
+ max_dose = max(volume, max_dose)
+ dose = min(dose + removed, max_dose)
+ if(removed >= (metabolism * 0.1) || removed >= 0.1) // If there's too little chemical, don't affect the mob, just remove it
+ switch(active_metab.metabolism_class)
+ if(CHEM_BLOOD)
+ affect_blood(M, alien, removed)
+ if(CHEM_INGEST)
+ affect_ingest(M, alien, removed * ingest_abs_mult)
+ if(CHEM_TOUCH)
+ affect_touch(M, alien, removed)
+ if(overdose && (volume > overdose * M?.species.chemOD_threshold) && (active_metab.metabolism_class != CHEM_TOUCH && !can_overdose_touch))
+ overdose(M, alien, removed)
+ if(M.species.allergens & allergen_type) //uhoh, we can't handle this!
+ var/damage_severity = M.species.allergen_damage_severity*allergen_factor
+ var/disable_severity = M.species.allergen_disable_severity*allergen_factor
+ if(M.species.allergen_reaction & AG_TOX_DMG)
+ M.adjustToxLoss(damage_severity)
+ if(M.species.allergen_reaction & AG_OXY_DMG)
+ M.adjustOxyLoss(damage_severity)
+ if(prob(2.5*disable_severity))
+ M.emote(pick("cough","gasp","choke"))
+ if(M.species.allergen_reaction & AG_EMOTE)
+ if(prob(2.5*disable_severity)) //this has a higher base chance, but not *too* high
+ M.emote(pick("pale","shiver","twitch"))
+ if(M.species.allergen_reaction & AG_PAIN)
+ M.adjustHalLoss(disable_severity)
+ if(M.species.allergen_reaction & AG_WEAKEN)
+ M.Weaken(disable_severity)
+ if(M.species.allergen_reaction & AG_BLURRY)
+ M.eye_blurry = max(M.eye_blurry, disable_severity)
+ if(M.species.allergen_reaction & AG_SLEEPY)
+ M.drowsyness = max(M.drowsyness, disable_severity)
+ remove_self(removed)
+ return
+
+/datum/reagent/proc/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ return
+
+/datum/reagent/proc/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
+ M.bloodstr.add_reagent(id, removed)
+ return
+
+/datum/reagent/proc/affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
+ return
+
+/datum/reagent/proc/overdose(var/mob/living/carbon/M, var/alien, var/removed) // Overdose effect.
+ if(alien == IS_DIONA)
+ return
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ overdose_mod *= H.species.chemOD_mod
+ // 6 damage per unit at minimum, scales with excessive reagents. Rounding should help keep damage consistent between ingest / inject, but isn't perfect.
+ // Hardcapped at 3.6 damage per tick, or 18 damage per unit at 0.2 metabolic rate so that you can't instakill people with overdoses by feeding them infinite periadaxon.
+ // Overall, max damage is slightly less effective than hydrophoron, and 1/5 as effective as cyanide.
+ M.adjustToxLoss(min(removed * overdose_mod * round(3 + 3 * volume / overdose), 3.6))
+
+/datum/reagent/proc/initialize_data(var/newdata) // Called when the reagent is created.
+ if(!isnull(newdata))
+ data = newdata
+ return
+
+/datum/reagent/proc/mix_data(var/newdata, var/newamount) // You have a reagent with data, and new reagent with its own data get added, how do you deal with that?
+ return
+
+/datum/reagent/proc/get_data() // Just in case you have a reagent that handles data differently.
+ if(data && istype(data, /list))
+ return data.Copy()
+ else if(data)
+ return data
+ return null
+
+/datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references
+ holder = null
+ . = ..()
+
+/* DEPRECATED - TODO: REMOVE EVERYWHERE */
+
+/datum/reagent/proc/reaction_turf(var/turf/target)
+ touch_turf(target)
+
+/datum/reagent/proc/reaction_obj(var/obj/target)
+ touch_obj(target)
+
+/datum/reagent/proc/reaction_mob(var/mob/target)
+ touch_mob(target)
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm b/code/modules/reagents/reagents/core.dm
similarity index 100%
rename from code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm
rename to code/modules/reagents/reagents/core.dm
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm b/code/modules/reagents/reagents/dispenser.dm
similarity index 100%
rename from code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm
rename to code/modules/reagents/reagents/dispenser.dm
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/reagents/food_drinks.dm
similarity index 100%
rename from code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
rename to code/modules/reagents/reagents/food_drinks.dm
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks_vr.dm b/code/modules/reagents/reagents/food_drinks_vr.dm
similarity index 91%
rename from code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks_vr.dm
rename to code/modules/reagents/reagents/food_drinks_vr.dm
index 246bb05b2c8..55436f295c5 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks_vr.dm
+++ b/code/modules/reagents/reagents/food_drinks_vr.dm
@@ -458,4 +458,62 @@
M.adjustToxLoss(removed) //Equivalent to half as much protein, since it's half protein.
if(M.species.organic_food_coeff)
if(alien == IS_SLIME || alien == IS_CHIMERA) //slimes and chimera can get nutrition from injected nutriment and protein
- M.nutrition += (alt_nutriment_factor * removed)
\ No newline at end of file
+ M.nutrition += (alt_nutriment_factor * removed)
+
+//////////////////////Bepis Drinks (04/29/2021)//////////////////////
+
+/datum/reagent/drink/soda/bepis_cola
+ name = "Bepis"
+ id = "bepis"
+ description = "A weird cola-like beverage."
+ taste_description = "bepsi"
+ reagent_state = LIQUID
+ color = "#100800"
+ adj_drowsy = -3
+ adj_temp = -5
+
+ glass_name = "Bepis Cola"
+ glass_desc = "A glass of weird cola beverage."
+ glass_special = list(DRINK_FIZZ)
+
+/datum/reagent/drink/soda/buzz_fuzz
+ name = "Buzz Fuzz"
+ id = "buzz_fuzz"
+ description = "A delicious frontier beverage that's simply a Hive of Flavour!"
+ taste_description = "carbonated honey and pollen"
+ reagent_state = LIQUID
+ color = "#8CFF00"
+ adj_drowsy = -3
+ adj_temp = -5
+
+ glass_name = "Buzz Fuzz"
+ glass_desc = "A glass that's stinging with flavour."
+ glass_special = list(DRINK_FIZZ)
+
+/datum/reagent/drink/soda/sprited_cranberry
+ name = "Sprited Cranberry"
+ id = "sprited_cranberry"
+ description = "A winter spiced cranberry drink. Perfect for year-round consumption."
+ taste_description = "sweet spiced cranberry"
+ reagent_state = LIQUID
+ color = "#fffafa"
+ adj_drowsy = -3
+ adj_temp = -5
+
+ glass_name = "Sprited Cranberry"
+ glass_desc = "A glass of sprited cranberry"
+ glass_special = list(DRINK_FIZZ)
+
+/datum/reagent/drink/soda/shamblers
+ name = "Shambler's Juice"
+ id = "shamblers"
+ description = "A strange off-brand beverage that's bursting with flavor."
+ taste_description = "carbonated metallic soda"
+ reagent_state = LIQUID
+ color = "#f00060"
+ adj_drowsy = -3
+ adj_temp = -5
+
+ glass_name = "Shambler's Juice"
+ glass_desc = "A glass of something shambly"
+ glass_special = list(DRINK_FIZZ)
\ No newline at end of file
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm b/code/modules/reagents/reagents/medicine.dm
similarity index 100%
rename from code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm
rename to code/modules/reagents/reagents/medicine.dm
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine_vr.dm b/code/modules/reagents/reagents/medicine_vr.dm
similarity index 100%
rename from code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine_vr.dm
rename to code/modules/reagents/reagents/medicine_vr.dm
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Modifiers.dm b/code/modules/reagents/reagents/modifiers.dm
similarity index 100%
rename from code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Modifiers.dm
rename to code/modules/reagents/reagents/modifiers.dm
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm b/code/modules/reagents/reagents/other.dm
similarity index 90%
rename from code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm
rename to code/modules/reagents/reagents/other.dm
index 5c1c9cf4274..9e83c720bc2 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm
+++ b/code/modules/reagents/reagents/other.dm
@@ -238,14 +238,6 @@
reagent_state = SOLID
color = "#D0D0D0"
-/datum/reagent/uranium
- name ="Uranium"
- id = "uranium"
- description = "A silvery-white metallic chemical element in the actinide series, weakly radioactive."
- taste_description = "metal"
- reagent_state = SOLID
- color = "#B8B8C0"
-
/datum/reagent/platinum
name = "Platinum"
id = "platinum"
@@ -254,6 +246,14 @@
reagent_state = SOLID
color = "#777777"
+/datum/reagent/uranium
+ name ="Uranium"
+ id = "uranium"
+ description = "A silvery-white metallic chemical element in the actinide series, weakly radioactive."
+ taste_description = "metal"
+ reagent_state = SOLID
+ color = "#B8B8C0"
+
/datum/reagent/uranium/affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
affect_ingest(M, alien, removed)
@@ -268,6 +268,55 @@
new /obj/effect/decal/cleanable/greenglow(T)
return
+/datum/reagent/hydrogen/deuterium
+ name = "Deuterium"
+ id = "deuterium"
+ description = "A isotope of hydrogen. It has one extra neutron, and shares all chemical characteristics with hydrogen."
+
+/datum/reagent/hydrogen/tritium
+ name = "Tritium"
+ id = "tritium"
+ description = "A radioactive isotope of hydrogen. It has two extra neutrons, and shares all other chemical characteristics with hydrogen."
+
+/datum/reagent/lithium/lithium6
+ name = "Lithium-6"
+ id = "lithium6"
+ description = "An isotope of lithium. It has 3 neutrons, but shares all chemical characteristics with regular lithium."
+
+/datum/reagent/helium/helium3
+ name = "Helium-3"
+ id = "helium3"
+ description = "An isotope of helium. It only has one neutron, but shares all chemical characteristics with regular helium."
+ taste_mult = 0
+ reagent_state = GAS
+ color = "#808080"
+
+/datum/reagent/boron/boron11
+ name = "Boron-11"
+ id = "boron11"
+ description = "An isotope of boron. It has 6 neutrons."
+ taste_description = "metallic" // Apparently noone on the internet knows what boron tastes like. Or at least they won't share
+
+/datum/reagent/supermatter
+ name = "Supermatter"
+ id = "supermatter"
+ description = "The immense power of a supermatter crystal, in liquid form. You're not entirely sure how that's possible, but it's probably best handled with care."
+ taste_description = "taffy" // 0. The supermatter is tasty, tasty taffy.
+
+// Same as if you boop it wrong. It touches you, you die
+/datum/reagent/supermatter/affect_touch(mob/living/carbon/M, alien, removed)
+ . = ..()
+ M.ash()
+
+/datum/reagent/supermatter/affect_ingest(mob/living/carbon/M, alien, removed)
+ . = ..()
+ M.ash()
+
+/datum/reagent/supermatter/affect_blood(mob/living/carbon/M, alien, removed)
+ . = ..()
+ M.ash()
+
+
/datum/reagent/adrenaline
name = "Adrenaline"
id = "adrenaline"
diff --git a/code/modules/reagents/Chemistry-Reagents_vr.dm b/code/modules/reagents/reagents/other_vr.dm
similarity index 95%
rename from code/modules/reagents/Chemistry-Reagents_vr.dm
rename to code/modules/reagents/reagents/other_vr.dm
index f6cd245dee7..b1146960ed9 100644
--- a/code/modules/reagents/Chemistry-Reagents_vr.dm
+++ b/code/modules/reagents/reagents/other_vr.dm
@@ -28,14 +28,6 @@
BI.forceMove(torso)
torso.implants += BI
-/datum/chemical_reaction/slime/sapphire_mutation
- name = "Slime Mutation Toxins"
- id = "slime_mutation_tox"
- result = "mutationtoxin"
- required_reagents = list("blood" = 5)
- result_amount = 30
- required = /obj/item/slime_extract/sapphire
-
/datum/reagent/nif_repair_nanites
name = "Programmed Nanomachines"
id = "nifrepairnanites"
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/reagents/toxins.dm
similarity index 100%
rename from code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm
rename to code/modules/reagents/reagents/toxins.dm
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Vore_vr.dm b/code/modules/reagents/reagents/vore_vr.dm
similarity index 100%
rename from code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Vore_vr.dm
rename to code/modules/reagents/reagents/vore_vr.dm
diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm
index 370a460bc73..3d58a40b16b 100755
--- a/code/modules/research/rdconsole.dm
+++ b/code/modules/research/rdconsole.dm
@@ -70,10 +70,12 @@ won't update every console in existence) but it's more of a hassle to do. Also,
return return_name
/obj/machinery/computer/rdconsole/proc/CallReagentName(var/ID)
- var/datum/reagent/R = SSchemistry.chemical_reagents["[ID]"]
- if(!R)
- return ID
- return R.name
+ var/return_name = ID
+ for(var/datum/reagent/R in SSchemistry.chemical_reagents)
+ if(R.id == ID)
+ return_name = R.name
+ break
+ return return_name
/obj/machinery/computer/rdconsole/proc/SyncRDevices() //Makes sure it is properly sync'ed up with the devices attached to it (if any).
for(var/obj/machinery/r_n_d/D in range(3, src))
diff --git a/code/modules/tgui/modules/appearance_changer.dm b/code/modules/tgui/modules/appearance_changer.dm
index e9478c3c31d..d063d6b41a3 100644
--- a/code/modules/tgui/modules/appearance_changer.dm
+++ b/code/modules/tgui/modules/appearance_changer.dm
@@ -542,7 +542,7 @@
// VOREStation Add - Ears/Tails/Wings
/datum/tgui_module/appearance_changer/proc/can_use_sprite(datum/sprite_accessory/X, mob/living/carbon/human/target, mob/user)
- if(X.apply_restrictions && !(target.species.name in X.species_allowed))
+ if(!isnull(X.species_allowed) && !(target.species.name in X.species_allowed))
return FALSE
if(LAZYLEN(X.ckeys_allowed) && !(user?.ckey in X.ckeys_allowed) && !(target.ckey in X.ckeys_allowed))
diff --git a/code/modules/vore/smoleworld/smoleworld_vr.dm b/code/modules/vore/smoleworld/smoleworld_vr.dm
index 5e84d7cbd1f..50dbacfe1f3 100644
--- a/code/modules/vore/smoleworld/smoleworld_vr.dm
+++ b/code/modules/vore/smoleworld/smoleworld_vr.dm
@@ -60,7 +60,7 @@
recipes += new/datum/stack_recipe("smole houses", /obj/structure/smolebuilding/houses, 2, time = 10)
recipes += new/datum/stack_recipe("smole business", /obj/structure/smolebuilding/business, 2, time = 10)
recipes += new/datum/stack_recipe("smole warehouses", /obj/structure/smolebuilding/warehouses, 2, time = 10)
- recipes += new/datum/stack_recipe("smole musem", /obj/structure/smolebuilding/musem, 2, time = 10)
+ recipes += new/datum/stack_recipe("smole museum", /obj/structure/smolebuilding/museum, 2, time = 10)
/datum/material/smolebricks
name = "smolebricks"
@@ -86,7 +86,7 @@
//smolebrick case to make for easy bricks.
/obj/item/weapon/storage/smolebrickcase
name = "smolebrick case"
- desc = "you feel the power of imagination."
+ desc = "You feel the power of imagination."
icon = 'icons/vore/smoleworld_vr.dmi'
icon_state = "smolestorage"
throw_speed = 1
@@ -152,10 +152,10 @@
anchored = 1
/obj/structure/smoletrack/roadF
- name = "road fourway piece"
+ name = "road four-way piece"
icon = 'icons/vore/smoleworld_vr.dmi'
icon_state = "carfourway"
- desc = "A fourway road piece."
+ desc = "A four-way road piece."
anchored = 1
//buildings code
@@ -279,10 +279,10 @@
icon = 'icons/vore/smoleworld_vr.dmi'
icon_state = "smolewarehouses"
-/obj/structure/smolebuilding/musem
- name = "smole musem"
+/obj/structure/smolebuilding/museum
+ name = "smole museum"
icon = 'icons/vore/smoleworld_vr.dmi'
- icon_state = "smolemusem"
+ icon_state = "smolemuseum"
//
//CAR STUFF < WILL BE MESSED WITH IN A LATER UPDATE COMMENTED OUT FOR NOW
///obj/item/smolecar
@@ -357,8 +357,8 @@
drop_sound = 'sound/items/drop/basketball.ogg'
/obj/item/weapon/reagent_containers/food/snacks/snackplanet/virgo3b
- name = "virgo3bB"
- desc = "A sticky jelly jaw breaker in the shape of Virgo3B, it even has a tiny tether!"
+ name = "Virgo 3B"
+ desc = "A sticky jelly jaw breaker in the shape of Virgo-3B, it even has a tiny tether!"
icon = 'icons/vore/smoleworld_vr.dmi'
icon_state = "sp_Virgo3B"
bitesize = 3
@@ -379,8 +379,8 @@
drop_sound = 'sound/items/drop/basketball.ogg'
/obj/item/weapon/reagent_containers/food/snacks/snackplanet/virgoprime
- name = "virgo prime"
- desc = "Its a orange jaw breaker in the shape Virgo Prime!"
+ name = "Virgo Prime"
+ desc = "It's a orange jaw breaker in the shape of Virgo Prime!"
icon = 'icons/vore/smoleworld_vr.dmi'
icon_state = "sp_virgoprime"
bitesize = 3
@@ -391,7 +391,7 @@
/obj/item/weapon/storage/bagoplanets
name = "bag o' planets"
- desc = "A cosmic bag of fist sized candy planets."
+ desc = "A cosmic bag of fist-sized candy planets."
icon = 'icons/vore/smoleworld_vr.dmi'
icon_state = "sp_storage"
w_class = ITEMSIZE_LARGE
diff --git a/code/modules/xenobio/items/extracts.dm b/code/modules/xenobio/items/extracts.dm
index 159bb0f1516..f810b9f68b8 100644
--- a/code/modules/xenobio/items/extracts.dm
+++ b/code/modules/xenobio/items/extracts.dm
@@ -39,17 +39,17 @@
else
. += "This extract is inert."
-/datum/chemical_reaction/slime
+/decl/chemical_reaction/instant/slime
var/required = null
-/datum/chemical_reaction/slime/can_happen(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/can_happen(var/datum/reagents/holder)
if(holder.my_atom && istype(holder.my_atom, required))
var/obj/item/slime_extract/T = holder.my_atom
if(T.uses > 0)
return ..()
return FALSE
-/datum/chemical_reaction/slime/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/on_reaction(var/datum/reagents/holder)
var/obj/item/slime_extract/T = holder.my_atom
T.uses--
if(T.uses <= 0)
@@ -67,7 +67,7 @@
icon_state = "grey slime extract"
description_info = "This extract will create a new grey baby slime if injected with phoron, or some new monkey cubes if injected with blood."
-/datum/chemical_reaction/slime/grey_new_slime
+/decl/chemical_reaction/instant/slime/grey_new_slime
name = "Slime Spawn"
id = "m_spawn"
result = null
@@ -75,12 +75,12 @@
result_amount = 1
required = /obj/item/slime_extract/grey
-/datum/chemical_reaction/slime/grey_new_slime/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/grey_new_slime/on_reaction(var/datum/reagents/holder)
holder.my_atom.visible_message("Infused with phoron, the core begins to quiver and grow, and soon a new baby slime emerges from it!")
new /mob/living/simple_mob/slime/xenobio(get_turf(holder.my_atom))
..()
-/datum/chemical_reaction/slime/grey_monkey
+/decl/chemical_reaction/instant/slime/grey_monkey
name = "Slime Monkey"
id = "m_monkey"
result = null
@@ -88,12 +88,12 @@
result_amount = 1
required = /obj/item/slime_extract/grey
-/datum/chemical_reaction/slime/grey_monkey/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/grey_monkey/on_reaction(var/datum/reagents/holder)
for(var/i = 1 to 4)
new /obj/item/weapon/reagent_containers/food/snacks/monkeycube(get_turf(holder.my_atom))
..()
-/datum/chemical_reaction/slime/grey_slimejelly
+/decl/chemical_reaction/instant/slime/grey_slimejelly
name = "Slime Jelly"
id = "m_jelly"
result = "slimejelly"
@@ -123,7 +123,7 @@
color = "#666666"
strength = 20
-/datum/chemical_reaction/slime/metal_metamorphic
+/decl/chemical_reaction/instant/slime/metal_metamorphic
name = "Slime Metal"
id = "m_metal"
required_reagents = list("phoron" = 5)
@@ -132,7 +132,7 @@
required = /obj/item/slime_extract/metal
-/datum/chemical_reaction/metamorphic
+/decl/chemical_reaction/instant/metamorphic
result_amount = REAGENTS_PER_SHEET * 2
@@ -145,42 +145,42 @@
// This is kind of a waste since iron is in the chem dispenser but it would be inconsistent if this wasn't here.
-/datum/chemical_reaction/metamorphic/iron
+/decl/chemical_reaction/instant/metamorphic/iron
name = "Morph into Iron"
id = "morph_iron"
required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "iron" = REAGENTS_PER_SHEET)
result = "iron"
-/datum/chemical_reaction/metamorphic/silver
+/decl/chemical_reaction/instant/metamorphic/silver
name = "Morph into Silver"
id = "morph_silver"
required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "silver" = REAGENTS_PER_SHEET)
result = "silver"
-/datum/chemical_reaction/metamorphic/gold
+/decl/chemical_reaction/instant/metamorphic/gold
name = "Morph into Gold"
id = "morph_gold"
required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "gold" = REAGENTS_PER_SHEET)
result = "gold"
-/datum/chemical_reaction/metamorphic/platinum
+/decl/chemical_reaction/instant/metamorphic/platinum
name = "Morph into Platinum"
id = "morph_platinum"
required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "platinum" = REAGENTS_PER_SHEET)
result = "platinum"
-/datum/chemical_reaction/metamorphic/uranium
+/decl/chemical_reaction/instant/metamorphic/uranium
name = "Morph into Uranium"
id = "morph_uranium"
required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "uranium" = REAGENTS_PER_SHEET)
result = "uranium"
-/datum/chemical_reaction/metamorphic/phoron
+/decl/chemical_reaction/instant/metamorphic/phoron
name = "Morph into Phoron"
id = "morph_phoron"
required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "phoron" = REAGENTS_PER_SHEET)
@@ -188,7 +188,7 @@
// Creates 'alloys' which can be finalized with frost oil.
-/datum/chemical_reaction/slime/metal_binding
+/decl/chemical_reaction/instant/slime/metal_binding
name = "Slime Binding"
id = "m_binding"
required_reagents = list("water" = 5)
@@ -215,7 +215,7 @@
prefill = list("binding" = 60)
-/datum/chemical_reaction/binding
+/decl/chemical_reaction/instant/binding
name = "Bind into Steel"
id = "bind_steel"
result = "steel"
@@ -231,7 +231,7 @@
color = "#888888"
-/datum/chemical_reaction/binding/plasteel // Two parts 'steel', one part platnium matches the smelter alloy recipe.
+/decl/chemical_reaction/instant/binding/plasteel // Two parts 'steel', one part platnium matches the smelter alloy recipe.
name = "Bind into Plasteel"
id = "bind_plasteel"
required_reagents = list("binding" = REAGENTS_PER_SHEET, "steel" = REAGENTS_PER_SHEET * 2, "platinum" = REAGENTS_PER_SHEET)
@@ -258,7 +258,7 @@
The extract can also create a slime stability agent when injected with blood, which reduces the odds of newly created slimes mutating into \
a different color when a slime reproduces."
-/datum/chemical_reaction/slime/blue_frostoil
+/decl/chemical_reaction/instant/slime/blue_frostoil
name = "Slime Frost Oil"
id = "m_frostoil"
result = "frostoil"
@@ -267,14 +267,14 @@
required = /obj/item/slime_extract/blue
-/datum/chemical_reaction/slime/blue_stability
+/decl/chemical_reaction/instant/slime/blue_stability
name = "Slime Stability"
id = "m_stability"
required_reagents = list("blood" = 5)
result_amount = 1
required = /obj/item/slime_extract/blue
-/datum/chemical_reaction/slime/blue_stability/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/blue_stability/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/stabilizer(get_turf(holder.my_atom))
..()
@@ -291,14 +291,14 @@
can extract from a slime specimen."
-/datum/chemical_reaction/slime/purple_steroid
+/decl/chemical_reaction/instant/slime/purple_steroid
name = "Slime Steroid"
id = "m_steroid"
required_reagents = list("phoron" = 5)
result_amount = 1
required = /obj/item/slime_extract/purple
-/datum/chemical_reaction/slime/purple_steroid/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/purple_steroid/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/steroid(get_turf(holder.my_atom))
..()
@@ -313,14 +313,14 @@
icon_state = "orange slime extract"
description_info = "This extract creates a fire when injected with phoron, after a five second delay."
-/datum/chemical_reaction/slime/orange_fire
+/decl/chemical_reaction/instant/slime/orange_fire
name = "Slime Fire"
id = "m_fire"
required_reagents = list("phoron" = 5)
result_amount = 1
required = /obj/item/slime_extract/orange
-/datum/chemical_reaction/slime/orange_fire/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/orange_fire/on_reaction(var/datum/reagents/holder)
log_and_message_admins("Orange extract reaction (fire) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]")
holder.my_atom.visible_message("\The [src] begins to vibrate violently!")
playsound(holder.my_atom, 'sound/effects/phasein.ogg', 75, 1)
@@ -350,14 +350,14 @@
description_info = "This extract will create a special 10k capacity power cell that self recharges slowly over time, when injected with phoron. \
When injected with blood, it will create a glob of slime which glows brightly. If injected with water, it will emit a strong EMP, after a five second delay."
-/datum/chemical_reaction/slime/yellow_emp
+/decl/chemical_reaction/instant/slime/yellow_emp
name = "Slime EMP"
id = "m_emp"
required_reagents = list("water" = 5)
result_amount = 1
required = /obj/item/slime_extract/yellow
-/datum/chemical_reaction/slime/yellow_emp/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/yellow_emp/on_reaction(var/datum/reagents/holder)
log_and_message_admins("Yellow extract reaction (emp) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]")
holder.my_atom.visible_message("\The [src] begins to vibrate violently!")
playsound(holder.my_atom, 'sound/effects/phasein.ogg', 75, 1)
@@ -368,26 +368,26 @@
..()
-/datum/chemical_reaction/slime/yellow_battery
+/decl/chemical_reaction/instant/slime/yellow_battery
name = "Slime Cell"
id = "m_cell"
required_reagents = list("phoron" = 5)
result_amount = 1
required = /obj/item/slime_extract/yellow
-/datum/chemical_reaction/slime/yellow_battery/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/yellow_battery/on_reaction(var/datum/reagents/holder)
new /obj/item/weapon/cell/slime(get_turf(holder.my_atom))
..()
-/datum/chemical_reaction/slime/yellow_flashlight
+/decl/chemical_reaction/instant/slime/yellow_flashlight
name = "Slime Flashlight"
id = "m_flashlight"
required_reagents = list("blood" = 5)
result_amount = 1
required = /obj/item/slime_extract/yellow
-/datum/chemical_reaction/slime/yellow_flashlight/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/yellow_flashlight/on_reaction(var/datum/reagents/holder)
new /obj/item/device/flashlight/slime(get_turf(holder.my_atom))
..()
@@ -401,7 +401,7 @@
description_info = "This extract will create 5u liquid gold when injected with phoron."
-/datum/chemical_reaction/slime/gold_gold
+/decl/chemical_reaction/instant/slime/gold_gold
name = "Slime Gold"
id = "m_gold"
result = "gold"
@@ -420,7 +420,7 @@
description_info = "This extract will create 5u liquid silver when injected with phoron."
-/datum/chemical_reaction/slime/silver_silver
+/decl/chemical_reaction/instant/slime/silver_silver
name = "Slime Silver"
id = "m_silver"
result = "silver"
@@ -440,7 +440,7 @@
description_info = "This extract will create 40u liquid phoron when injected with water."
-/datum/chemical_reaction/slime/dark_purple_phoron
+/decl/chemical_reaction/instant/slime/dark_purple_phoron
name = "Slime Phoron"
id = "m_phoron_harvest"
result = "phoron"
@@ -462,7 +462,7 @@
cold-resistant armor like winter coats can protect from this. Note that the user is not immune to the extract's effects."
-/datum/chemical_reaction/slime/dark_blue_cold_snap
+/decl/chemical_reaction/instant/slime/dark_blue_cold_snap
name = "Slime Cold Snap"
id = "m_cold_snap"
required_reagents = list("phoron" = 5)
@@ -470,7 +470,7 @@
required = /obj/item/slime_extract/dark_blue
// This iterates over a ZAS zone's contents, so that things seperated in other zones aren't subjected to the temperature drop.
-/datum/chemical_reaction/slime/dark_blue_cold_snap/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/dark_blue_cold_snap/on_reaction(var/datum/reagents/holder)
var/turf/simulated/T = get_turf(holder.my_atom)
if(!T) // Nullspace lacks zones.
return
@@ -544,14 +544,14 @@
out of control."
-/datum/chemical_reaction/slime/red_enrage
+/decl/chemical_reaction/instant/slime/red_enrage
name = "Slime Enrage"
id = "m_enrage"
required_reagents = list("blood" = 5)
result_amount = 1
required = /obj/item/slime_extract/red
-/datum/chemical_reaction/slime/red_enrage/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/red_enrage/on_reaction(var/datum/reagents/holder)
for(var/mob/living/simple_mob/slime/S in view(get_turf(holder.my_atom)))
if(S.stat)
continue
@@ -580,14 +580,14 @@
-/datum/chemical_reaction/slime/red_mutation
+/decl/chemical_reaction/instant/slime/red_mutation
name = "Slime Mutation"
id = "m_mutation"
required_reagents = list("phoron" = 5)
result_amount = 1
required = /obj/item/slime_extract/red
-/datum/chemical_reaction/slime/red_mutation/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/red_mutation/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/mutator(get_turf(holder.my_atom))
..()
@@ -600,7 +600,7 @@
icon_state = "green slime extract"
description_info = "This extract will create 5u of liquid uranium when injected with phoron."
-/datum/chemical_reaction/slime/green_uranium
+/decl/chemical_reaction/instant/slime/green_uranium
name = "Slime Uranium"
id = "m_uranium"
result = "uranium"
@@ -620,7 +620,7 @@
with phoron. When injected with water, it will create an organ-mending agent. The slime medications have a very low threshold for overdosage, however."
-/datum/chemical_reaction/slime/pink_clotting
+/decl/chemical_reaction/instant/slime/pink_clotting
name = "Slime Clotting Med"
id = "m_clotting"
result = "slime_bleed_fixer"
@@ -629,7 +629,7 @@
required = /obj/item/slime_extract/pink
-/datum/chemical_reaction/slime/pink_bone_fix
+/decl/chemical_reaction/instant/slime/pink_bone_fix
name = "Slime Bone Med"
id = "m_bone_fixer"
result = "slime_bone_fixer"
@@ -638,7 +638,7 @@
required = /obj/item/slime_extract/pink
-/datum/chemical_reaction/slime/pink_organ_fix
+/decl/chemical_reaction/instant/slime/pink_organ_fix
name = "Slime Organ Med"
id = "m_organ_fixer"
result = "slime_organ_fixer"
@@ -680,7 +680,7 @@
increase the power of the explosion instead of allowing for multiple explosions."
-/datum/chemical_reaction/slime/oil_griff
+/decl/chemical_reaction/instant/slime/oil_griff
name = "Slime Explosion"
id = "m_boom"
required_reagents = list("blood" = 5)
@@ -688,7 +688,7 @@
required = /obj/item/slime_extract/oil
-/datum/chemical_reaction/slime/oil_griff/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/oil_griff/on_reaction(var/datum/reagents/holder)
..()
var/obj/item/slime_extract/E = holder.my_atom
var/power = 1
@@ -718,26 +718,26 @@
short ranged, random teleporting. When injected with phoron, it creates one 'greater' slime crystal, which allows for a one time precise teleport to \
a specific area."
-/datum/chemical_reaction/slime/bluespace_lesser
+/decl/chemical_reaction/instant/slime/bluespace_lesser
name = "Slime Lesser Tele"
id = "m_tele_lesser"
required_reagents = list("water" = 5)
result_amount = 1
required = /obj/item/slime_extract/bluespace
-/datum/chemical_reaction/slime/bluespace_lesser/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/bluespace_lesser/on_reaction(var/datum/reagents/holder)
for(var/i = 1 to 5)
new /obj/item/slime_crystal(get_turf(holder.my_atom))
..()
-/datum/chemical_reaction/slime/bluespace_greater
+/decl/chemical_reaction/instant/slime/bluespace_greater
name = "Slime Greater Tele"
id = "m_tele_lesser"
required_reagents = list("phoron" = 5)
result_amount = 1
required = /obj/item/slime_extract/bluespace
-/datum/chemical_reaction/slime/bluespace_greater/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/bluespace_greater/on_reaction(var/datum/reagents/holder)
new /obj/item/weapon/disposable_teleporter/slime(get_turf(holder.my_atom))
..()
@@ -752,14 +752,14 @@
'charges' before it goes inert."
-/datum/chemical_reaction/slime/cerulean_enhancer
+/decl/chemical_reaction/instant/slime/cerulean_enhancer
name = "Slime Enhancer"
id = "m_enhancer"
required_reagents = list("phoron" = 5)
result_amount = 1
required = /obj/item/slime_extract/cerulean
-/datum/chemical_reaction/slime/cerulean_enhancer/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/cerulean_enhancer/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/enhancer(get_turf(holder.my_atom))
..()
@@ -774,26 +774,26 @@
injected with water, it will create a very delicious and filling product."
-/datum/chemical_reaction/slime/amber_slimefood
+/decl/chemical_reaction/instant/slime/amber_slimefood
name = "Slime Feeding"
id = "m_slime_food"
required_reagents = list("phoron" = 5)
result_amount = 1
required = /obj/item/slime_extract/amber
-/datum/chemical_reaction/slime/amber_slimefood/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/amber_slimefood/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/feeding(get_turf(holder.my_atom))
..()
-/datum/chemical_reaction/slime/amber_peoplefood
+/decl/chemical_reaction/instant/slime/amber_peoplefood
name = "Slime Food"
id = "m_people_food"
required_reagents = list("water" = 5)
result_amount = 1
required = /obj/item/slime_extract/amber
-/datum/chemical_reaction/slime/amber_peoplefood/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/amber_peoplefood/on_reaction(var/datum/reagents/holder)
new /obj/item/weapon/reagent_containers/food/snacks/slime(get_turf(holder.my_atom))
..()
@@ -809,14 +809,14 @@
description_info = "This extract will create one 'slime cube' when injected with phoron. The slime cube is needed to create a Promethean."
-/datum/chemical_reaction/slime/sapphire_promethean
+/decl/chemical_reaction/instant/slime/sapphire_promethean
name = "Slime Promethean"
id = "m_promethean"
required_reagents = list("phoron" = 5)
result_amount = 1
required = /obj/item/slime_extract/sapphire
-/datum/chemical_reaction/slime/sapphire_promethean/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/sapphire_promethean/on_reaction(var/datum/reagents/holder)
new /obj/item/slime_cube(get_turf(holder.my_atom))
..()
@@ -830,14 +830,14 @@
description_info = "This extract will cause all entities close to the extract to become stronger for ten minutes, when injected with phoron. \
When injected with blood, makes a slime loyalty agent which will make the slime fight other dangerous entities but not station crew."
-/datum/chemical_reaction/slime/ruby_swole
+/decl/chemical_reaction/instant/slime/ruby_swole
name = "Slime Strength"
id = "m_strength"
required_reagents = list("phoron" = 5)
result_amount = 1
required = /obj/item/slime_extract/ruby
-/datum/chemical_reaction/slime/ruby_swole/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/ruby_swole/on_reaction(var/datum/reagents/holder)
for(var/mob/living/L in range(1, holder.my_atom))
L.add_modifier(/datum/modifier/slime_strength, 10 MINUTES, src)
..()
@@ -858,14 +858,14 @@
incoming_damage_percent = 0.75
-/datum/chemical_reaction/slime/ruby_loyalty
+/decl/chemical_reaction/instant/slime/ruby_loyalty
name = "Slime Loyalty"
id = "m_strength"
required_reagents = list("blood" = 5)
result_amount = 1
required = /obj/item/slime_extract/ruby
-/datum/chemical_reaction/slime/ruby_loyalty/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/ruby_loyalty/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/loyalty(get_turf(holder.my_atom))
..()
@@ -879,14 +879,14 @@
icon_state = "emerald slime extract"
description_info = "This extract will cause all entities close to the extract to become more agile for ten minutes, when injected with phoron."
-/datum/chemical_reaction/slime/emerald_fast
+/decl/chemical_reaction/instant/slime/emerald_fast
name = "Slime Agility"
id = "m_agility"
required_reagents = list("phoron" = 5)
result_amount = 1
required = /obj/item/slime_extract/emerald
-/datum/chemical_reaction/slime/emerald_fast/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/emerald_fast/on_reaction(var/datum/reagents/holder)
for(var/mob/living/L in range(1, holder.my_atom))
L.add_modifier(/datum/modifier/slime_agility, 10 MINUTES, src)
..()
@@ -916,26 +916,26 @@
When injected with phoron, it instead creates a slime friendship agent, which makes the slime consider the user their ally. The agent \
might be useful on other specimens as well."
-/datum/chemical_reaction/slime/light_pink_docility
+/decl/chemical_reaction/instant/slime/light_pink_docility
name = "Slime Docility"
id = "m_docile"
required_reagents = list("water" = 5)
result_amount = 1
required = /obj/item/slime_extract/light_pink
-/datum/chemical_reaction/slime/light_pink_docility/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/light_pink_docility/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/docility(get_turf(holder.my_atom))
..()
-/datum/chemical_reaction/slime/light_pink_friendship
+/decl/chemical_reaction/instant/slime/light_pink_friendship
name = "Slime Friendship"
id = "m_friendship"
required_reagents = list("phoron" = 5)
result_amount = 1
required = /obj/item/slime_extract/light_pink
-/datum/chemical_reaction/slime/light_pink_friendship/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/light_pink_friendship/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/friendship(get_turf(holder.my_atom))
..()
@@ -952,7 +952,7 @@
which makes slimes stop attacking other slime colors."
-/datum/chemical_reaction/slime/rainbow_random_slime
+/decl/chemical_reaction/instant/slime/rainbow_random_slime
name = "Slime Random Slime"
id = "m_rng_slime"
required_reagents = list("phoron" = 5)
@@ -960,7 +960,7 @@
required = /obj/item/slime_extract/rainbow
-/datum/chemical_reaction/slime/rainbow_random_slime/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/rainbow_random_slime/on_reaction(var/datum/reagents/holder)
var/mob/living/simple_mob/slime/xenobio/S
var/list/slime_types = typesof(/mob/living/simple_mob/slime/xenobio)
@@ -976,14 +976,14 @@
new S(get_turf(holder.my_atom))
..()
-/datum/chemical_reaction/slime/rainbow_unity
+/decl/chemical_reaction/instant/slime/rainbow_unity
name = "Slime Unity"
id = "m_unity"
required_reagents = list("water" = 5)
result_amount = 1
required = /obj/item/slime_extract/rainbow
-/datum/chemical_reaction/slime/rainbow_unity/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/slime/rainbow_unity/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/unity(get_turf(holder.my_atom))
..()
diff --git a/config/docker/README.md b/config/docker/README.md
new file mode 100644
index 00000000000..3c1b9b34820
--- /dev/null
+++ b/config/docker/README.md
@@ -0,0 +1,43 @@
+## How to set-up the Docker database
+
+
+First, open `config/docker/mysql.env.example`, open in notepad or N++, change all the values to something else ~~or don't if you are lazy~~ for security sake.
+
+Then proceed to save the changed version to `mysql.env` and save it in the same directory as the `mysql.env.example` file.
+
+In order to get docker to use the database, it's suggested to change the `config/dbconfig.txt` to include the values in `mysql.env` file, to do this, use the hostname `db` as host!
+
+### Example for `config/dbconfig.txt`:
+
+The default database name is `tgstation` by default. Unless you change the SQL schemas, this cannot be changed.
+
+Keep note of the values, `*LOGIN` and `*PASSWORD`
+
+```
+# MySQL Connection Configuration
+
+# Server the MySQL database can be found at
+# Examples: localhost, 200.135.5.43, www.mysqldb.com, etc.
+ADDRESS db
+
+# MySQL server port (default is 3306)
+PORT 3306
+
+# Database the population, death, karma, etc. tables may be found in
+DATABASE tgstation
+
+# Username/Login used to access the database
+LOGIN sillyusername
+
+# Password used to access the database
+PASSWORD somekindofpassword
+
+# The following information is for feedback tracking via the blackbox server
+FEEDBACK_DATABASE tgstation
+FEEDBACK_LOGIN sillyusernane
+FEEDBACK_PASSWORD somekindofpassword
+
+# Track population and death statistics
+# Comment this out to disable
+#ENABLE_STAT_TRACKING
+```
diff --git a/config/docker/mysql.env.example b/config/docker/mysql.env.example
new file mode 100644
index 00000000000..73b37b08fd0
--- /dev/null
+++ b/config/docker/mysql.env.example
@@ -0,0 +1,6 @@
+# MySQL database root password
+MYSQL_ROOT_PASSWORD=SUPERSEKRETOMYGOD
+# MySQL login username
+MYSQL_USERNAME=sillyusername
+# MySQL login password
+MYSQL_PASSWORD=somekindofpassword
diff --git a/config/example/config.txt b/config/example/config.txt
index dd07f7b73d5..735fe805e9e 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -555,3 +555,7 @@ ALLOW_URL_LINKS
# Control which submaps are loaded for the Dynamic Engine system
ENGINE_MAP Supermatter Engine,Edison's Bane
+
+# Controls how strictly the species whitelists on loadout entries are enforced
+# Possible values: 0 (Off), 1 (Lax, user must be whitelisted for the species), 2 (Strict, user must be the species)
+LOADOUT_WHITELIST 1
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 00000000000..b22b1c4ac0c
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,45 @@
+version: '3'
+
+services:
+ # Virgo DM server
+ dreammaker:
+ image: vorestation:latest
+ restart: unless-stopped
+ build:
+ context: .
+ dockerfile: Dockerfile
+ ports:
+ - "2303:2303"
+ depends_on:
+ - db
+ volumes:
+ - ./config/:/vorestation/config
+ - gamedata:/vorestation/data
+ # MariaDB/MySQL database: game
+ # (if you don't really need this, feel free to remove this section.)
+ db:
+ image: mariadb
+ restart: unless-stopped
+ env_file:
+ - ./config/docker/mysql.env
+ volumes:
+ - ./SQL/tgstation_schema.sql:/docker-entrypoint-initdb.d/tgstation_schema.sql:ro
+ - ./SQL/feedback_schema.sql:/docker-entrypoint-initdb.d/feedback_schema.sql:ro
+ - database:/var/lib/mysql
+ # Adminer, for managing the DB, commented out by default but uncomment if you need it I guess.
+ #adminer:
+ # image: wodby/adminer
+ # depends_on:
+ # - db
+ # environment:
+ # ADMINER_DEFAULT_DB_DRIVER: mysql
+ # ADMINER_DEFAULT_DB_HOST: db
+ # ADMINER_DEFAULT_DB_NAME: tgstation
+ # ADMINER_DESIGN: nette
+ # ADMINER_PLUGINS: tables-filter tinymce
+ # ports:
+ # - 8080:9000
+
+volumes:
+ gamedata:
+ database:
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index a20911d4355..b0130e58df5 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ
diff --git a/icons/mob/corgi_back.dmi b/icons/mob/corgi_back.dmi
index 81626df0333..27de68f79c0 100644
Binary files a/icons/mob/corgi_back.dmi and b/icons/mob/corgi_back.dmi differ
diff --git a/icons/mob/corgi_head.dmi b/icons/mob/corgi_head.dmi
index ca62243e79b..d8be15b3bc5 100644
Binary files a/icons/mob/corgi_head.dmi and b/icons/mob/corgi_head.dmi differ
diff --git a/icons/mob/items/lefthand_guns_vr.dmi b/icons/mob/items/lefthand_guns_vr.dmi
index 76ad8ebf311..0d8acb4fbba 100644
Binary files a/icons/mob/items/lefthand_guns_vr.dmi and b/icons/mob/items/lefthand_guns_vr.dmi differ
diff --git a/icons/mob/items/lefthand_material.dmi b/icons/mob/items/lefthand_material.dmi
index 7fbcc1131ff..dec3ab84ea0 100644
Binary files a/icons/mob/items/lefthand_material.dmi and b/icons/mob/items/lefthand_material.dmi differ
diff --git a/icons/mob/items/righthand_guns_vr.dmi b/icons/mob/items/righthand_guns_vr.dmi
index 42d935f7608..73ee95c0a3a 100644
Binary files a/icons/mob/items/righthand_guns_vr.dmi and b/icons/mob/items/righthand_guns_vr.dmi differ
diff --git a/icons/mob/items/righthand_material.dmi b/icons/mob/items/righthand_material.dmi
index ac51aa86f14..d65181cc6a6 100644
Binary files a/icons/mob/items/righthand_material.dmi and b/icons/mob/items/righthand_material.dmi differ
diff --git a/icons/mob/screen_full_vore.dmi b/icons/mob/screen_full_vore.dmi
index 632f413f597..4e5b3a70fdd 100644
Binary files a/icons/mob/screen_full_vore.dmi and b/icons/mob/screen_full_vore.dmi differ
diff --git a/icons/mob/species/teshari/head.dmi b/icons/mob/species/teshari/head.dmi
index 51eff217bb7..038fb9cc3dd 100644
Binary files a/icons/mob/species/teshari/head.dmi and b/icons/mob/species/teshari/head.dmi differ
diff --git a/icons/mob/species/teshari/suit.dmi b/icons/mob/species/teshari/suit.dmi
index 9f6a652c4a5..714b0408a53 100644
Binary files a/icons/mob/species/teshari/suit.dmi and b/icons/mob/species/teshari/suit.dmi differ
diff --git a/icons/mob/species/teshari/ties.dmi b/icons/mob/species/teshari/ties.dmi
index fb49fe444fd..467d0ffa35c 100644
Binary files a/icons/mob/species/teshari/ties.dmi and b/icons/mob/species/teshari/ties.dmi differ
diff --git a/icons/mob/vore/taurs_vr.dmi b/icons/mob/vore/taurs_vr.dmi
index 87f0b32cc2f..54e865150b9 100644
Binary files a/icons/mob/vore/taurs_vr.dmi and b/icons/mob/vore/taurs_vr.dmi differ
diff --git a/icons/obj/clothing/species/teshari/hats.dmi b/icons/obj/clothing/species/teshari/hats.dmi
index c069f66f136..2d7877c0c3e 100644
Binary files a/icons/obj/clothing/species/teshari/hats.dmi and b/icons/obj/clothing/species/teshari/hats.dmi differ
diff --git a/icons/obj/clothing/species/teshari/suits.dmi b/icons/obj/clothing/species/teshari/suits.dmi
index 6679ceb22c8..820649befa7 100644
Binary files a/icons/obj/clothing/species/teshari/suits.dmi and b/icons/obj/clothing/species/teshari/suits.dmi differ
diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi
index 250c191c730..6a05cf1443c 100644
Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ
diff --git a/icons/obj/drinks_vr.dmi b/icons/obj/drinks_vr.dmi
index 280bf84cbd1..f1a34845330 100644
Binary files a/icons/obj/drinks_vr.dmi and b/icons/obj/drinks_vr.dmi differ
diff --git a/icons/obj/gun_vr.dmi b/icons/obj/gun_vr.dmi
index 34c2a2dc6d5..a794ff88a35 100644
Binary files a/icons/obj/gun_vr.dmi and b/icons/obj/gun_vr.dmi differ
diff --git a/icons/obj/vending_vr.dmi b/icons/obj/vending_vr.dmi
index 64c2ad0f5cb..94e2ba1fb67 100644
Binary files a/icons/obj/vending_vr.dmi and b/icons/obj/vending_vr.dmi differ
diff --git a/icons/vore/smoleworld_vr.dmi b/icons/vore/smoleworld_vr.dmi
index 206c0cef32c..035a6d6ce57 100644
Binary files a/icons/vore/smoleworld_vr.dmi and b/icons/vore/smoleworld_vr.dmi differ
diff --git a/interface/skin.dmf b/interface/skin.dmf
index 595a980bf15..4887895627f 100644
--- a/interface/skin.dmf
+++ b/interface/skin.dmf
@@ -603,6 +603,9 @@ macro "hotkeymode"
elem
name = "U"
command = "Rest"
+ elem
+ name = "B"
+ command = "Resist"
elem
name = "NUMPAD1"
command = "body-r-leg"
diff --git a/maps/expedition_vr/beach/beach.dmm b/maps/expedition_vr/beach/beach.dmm
index 3efcfc0c104..c60de785482 100644
--- a/maps/expedition_vr/beach/beach.dmm
+++ b/maps/expedition_vr/beach/beach.dmm
@@ -1973,7 +1973,7 @@
/turf/simulated/floor/tiled/asteroid_steel,
/area/tether_away/beach/resort/lockermed)
"Tg" = (
-/mob/living/simple_mob/animal/passive/fish/solarfish,
+/mob/living/simple_mob/animal/passive/fish/icebass,
/turf/simulated/floor/water/ocean,
/area/tether_away/beach/cavebase)
"Tp" = (
diff --git a/maps/tether/tether-01-surface1.dmm b/maps/tether/tether-01-surface1.dmm
index 3d0af89fe7b..a92a06dc5aa 100644
--- a/maps/tether/tether-01-surface1.dmm
+++ b/maps/tether/tether-01-surface1.dmm
@@ -24363,6 +24363,13 @@
},
/turf/simulated/floor/wood,
/area/crew_quarters/sleep/Dorm_6)
+"aOO" = (
+/obj/machinery/flasher{
+ id = "SurfaceBrigFlash";
+ pixel_y = -20
+ },
+/turf/simulated/floor/tiled/dark,
+/area/tether/surfacebase/security/brig)
"aOP" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
@@ -24669,6 +24676,30 @@
/obj/item/weapon/towel/random,
/turf/simulated/floor/wood,
/area/crew_quarters/sleep/Dorm_6)
+"aPj" = (
+/obj/structure/cable/green{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/obj/structure/cable/green{
+ d1 = 2;
+ d2 = 4;
+ icon_state = "2-4"
+ },
+/obj/effect/floor_decal/corner/lightorange{
+ dir = 5
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 6
+ },
+/obj/machinery/flasher{
+ id = "SurfaceBrigFlash"
+ },
+/obj/effect/floor_decal/industrial/outline/yellow,
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/security/brig)
"aPk" = (
/obj/machinery/shower{
dir = 1
@@ -25527,6 +25558,21 @@
},
/turf/simulated/floor/wood,
/area/crew_quarters/sleep/Dorm_4)
+"aQO" = (
+/obj/structure/cable/green{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/flasher{
+ id = "SurfaceBrigFlash"
+ },
+/obj/effect/floor_decal/industrial/outline/yellow,
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/security/brig)
"aQP" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
@@ -25834,6 +25880,20 @@
/obj/item/weapon/towel/random,
/turf/simulated/floor/wood,
/area/crew_quarters/sleep/Dorm_4)
+"aRs" = (
+/obj/structure/cable/green{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/flasher{
+ id = "SurfaceBrigFlash"
+ },
+/obj/effect/floor_decal/industrial/outline/yellow,
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/security/brig)
"aRt" = (
/obj/machinery/shower{
dir = 1
@@ -26553,6 +26613,13 @@
},
/turf/simulated/floor/wood,
/area/crew_quarters/sleep/Dorm_2)
+"aSZ" = (
+/obj/machinery/flasher{
+ id = "SurfaceBrigFlash"
+ },
+/obj/effect/floor_decal/industrial/outline/yellow,
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/security/brig)
"aTa" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
@@ -26891,6 +26958,19 @@
/obj/item/weapon/towel/random,
/turf/simulated/floor/wood,
/area/crew_quarters/sleep/Dorm_2)
+"aTH" = (
+/obj/effect/floor_decal/steeldecal/steel_decals4{
+ dir = 1
+ },
+/obj/effect/floor_decal/steeldecal/steel_decals4{
+ dir = 6
+ },
+/obj/machinery/button/flasher{
+ id = "SurfaceVisitFlash";
+ pixel_y = -20
+ },
+/turf/simulated/floor/tiled/dark,
+/area/tether/surfacebase/security/brig)
"aTI" = (
/obj/machinery/shower{
dir = 1
@@ -28389,6 +28469,17 @@
},
/turf/simulated/floor/tiled,
/area/crew_quarters/visitor_laundry)
+"aWp" = (
+/obj/effect/floor_decal/steeldecal/steel_decals4,
+/obj/effect/floor_decal/steeldecal/steel_decals4{
+ dir = 10
+ },
+/obj/machinery/flasher{
+ id = "SurfaceVisitFlash";
+ pixel_y = -20
+ },
+/turf/simulated/floor/tiled/dark,
+/area/tether/surfacebase/security/brig)
"aWq" = (
/obj/machinery/atmospherics/pipe/simple/visible/yellow{
dir = 4
@@ -28837,6 +28928,92 @@
/obj/random/junk,
/turf/simulated/floor/wood,
/area/crew_quarters/sleep/maintDorm2)
+"aXo" = (
+/obj/machinery/button/remote/airlock{
+ id = "brigouter";
+ name = "Outer Brig Doors";
+ pixel_x = 24;
+ pixel_y = -4;
+ req_access = list(2)
+ },
+/obj/machinery/button/remote/airlock{
+ id = "briginner";
+ name = "Inner Brig Doors";
+ pixel_x = 34;
+ pixel_y = -4;
+ req_access = list(2)
+ },
+/obj/effect/floor_decal/borderfloor{
+ dir = 4
+ },
+/obj/effect/floor_decal/borderfloor/corner2{
+ dir = 6
+ },
+/obj/effect/floor_decal/borderfloor/corner2{
+ dir = 5
+ },
+/obj/effect/floor_decal/corner/lightorange/bordercorner2{
+ dir = 5
+ },
+/obj/effect/floor_decal/corner/lightorange/bordercorner2{
+ dir = 6
+ },
+/obj/machinery/button/flasher{
+ id = "SurfaceBrigFlash";
+ pixel_x = 30;
+ pixel_y = 5
+ },
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/security/lowerhall)
+"aXp" = (
+/obj/structure/cable/green{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/green{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/effect/floor_decal/steeldecal/steel_decals6{
+ dir = 9
+ },
+/obj/machinery/flasher{
+ id = "SurfaceBrigFlash"
+ },
+/obj/effect/floor_decal/industrial/outline/yellow,
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/security/brig)
+"aXq" = (
+/obj/structure/cable/green{
+ icon_state = "1-8"
+ },
+/obj/structure/cable/green{
+ d1 = 2;
+ d2 = 8;
+ icon_state = "2-8"
+ },
+/obj/effect/floor_decal/corner/lightorange{
+ dir = 6
+ },
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/manifold/hidden/supply,
+/obj/machinery/flasher{
+ id = "SurfaceBrigFlash"
+ },
+/obj/effect/floor_decal/industrial/outline/yellow,
+/turf/simulated/floor/tiled,
+/area/tether/surfacebase/security/brig)
"aXr" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -31619,15 +31796,6 @@
"cGJ" = (
/turf/simulated/floor/plating,
/area/maintenance/lower/mining_eva)
-"cGU" = (
-/obj/effect/floor_decal/steeldecal/steel_decals4{
- dir = 1
- },
-/obj/effect/floor_decal/steeldecal/steel_decals4{
- dir = 6
- },
-/turf/simulated/floor/tiled/dark,
-/area/tether/surfacebase/security/brig)
"cHW" = (
/obj/effect/floor_decal/steeldecal/steel_decals6{
dir = 10
@@ -33005,13 +33173,6 @@
},
/turf/simulated/floor/tiled,
/area/crew_quarters/locker/laundry_arrival)
-"hzx" = (
-/obj/effect/floor_decal/steeldecal/steel_decals4,
-/obj/effect/floor_decal/steeldecal/steel_decals4{
- dir = 10
- },
-/turf/simulated/floor/tiled/dark,
-/area/tether/surfacebase/security/brig)
"hAe" = (
/turf/simulated/floor/looking_glass{
dir = 5
@@ -35005,29 +35166,6 @@
/obj/structure/closet/crate/bin,
/turf/simulated/floor/carpet/bcarpet,
/area/tether/surfacebase/funny/mimeoffice)
-"nmf" = (
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/green{
- dir = 4
- },
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 8
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/effect/floor_decal/steeldecal/steel_decals6{
- dir = 9
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/security/brig)
"nmA" = (
/obj/machinery/door/airlock/silver{
name = "Mime's Office";
@@ -36233,26 +36371,6 @@
},
/turf/simulated/floor/plating,
/area/tether/surfacebase/funny/hideyhole)
-"rzZ" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/structure/cable/green{
- d1 = 2;
- d2 = 4;
- icon_state = "2-4"
- },
-/obj/effect/floor_decal/corner/lightorange{
- dir = 5
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 6
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/security/brig)
"rBG" = (
/obj/structure/closet,
/obj/item/weapon/material/minihoe,
@@ -37089,38 +37207,6 @@
},
/turf/simulated/floor/tiled,
/area/rnd/hallway)
-"uDQ" = (
-/obj/machinery/button/remote/airlock{
- id = "brigouter";
- name = "Outer Brig Doors";
- pixel_x = 24;
- pixel_y = -4;
- req_access = list(2)
- },
-/obj/machinery/button/remote/airlock{
- id = "briginner";
- name = "Inner Brig Doors";
- pixel_x = 34;
- pixel_y = -4;
- req_access = list(2)
- },
-/obj/effect/floor_decal/borderfloor{
- dir = 4
- },
-/obj/effect/floor_decal/borderfloor/corner2{
- dir = 6
- },
-/obj/effect/floor_decal/borderfloor/corner2{
- dir = 5
- },
-/obj/effect/floor_decal/corner/lightorange/bordercorner2{
- dir = 5
- },
-/obj/effect/floor_decal/corner/lightorange/bordercorner2{
- dir = 6
- },
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/security/lowerhall)
"uEK" = (
/obj/effect/floor_decal/borderfloor,
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
@@ -37609,24 +37695,6 @@
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/surface_one_hall)
-"wxV" = (
-/obj/structure/cable/green{
- icon_state = "1-8"
- },
-/obj/structure/cable/green{
- d1 = 2;
- d2 = 8;
- icon_state = "2-8"
- },
-/obj/effect/floor_decal/corner/lightorange{
- dir = 6
- },
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/manifold/hidden/supply,
-/turf/simulated/floor/tiled,
-/area/tether/surfacebase/security/brig)
"wzA" = (
/obj/structure/catwalk,
/obj/machinery/alarm{
@@ -45915,7 +45983,7 @@ vRL
hFq
neZ
diq
-uDQ
+aXo
mvM
fLB
dMu
@@ -46198,9 +46266,9 @@ tiJ
kmb
pCj
kUN
-cGU
+aTH
qwV
-nmf
+aXp
hMu
abT
bbd
@@ -46476,13 +46544,13 @@ wwm
jio
pCj
dju
-kmb
+aOO
pCj
dju
-kmb
+aOO
pCj
jzW
-hzx
+aWp
qwV
wtD
wQS
@@ -46902,15 +46970,15 @@ aad
mYf
rQe
ybc
-rzZ
-hTw
+aPj
hTw
hTw
hTw
+aRs
hTw
uFs
ddU
-wxV
+aXq
nID
iKy
anp
@@ -47470,11 +47538,11 @@ aad
pCj
wjq
wjq
-pKE
+aQO
pmV
loj
plW
-tdh
+aSZ
fqa
fOy
eAd
diff --git a/maps/tether/tether-06-station2.dmm b/maps/tether/tether-06-station2.dmm
index 7b23d5ff7c6..09d88b445ba 100644
--- a/maps/tether/tether-06-station2.dmm
+++ b/maps/tether/tether-06-station2.dmm
@@ -144,30 +144,18 @@
/turf/simulated/floor/tiled,
/area/security/brig/visitation)
"ap" = (
-/obj/effect/floor_decal/borderfloor/shifted{
- dir = 4
+/obj/effect/floor_decal/corner/white/border{
+ dir = 8
},
-/obj/effect/floor_decal/corner/red/border/shifted{
- dir = 4
+/obj/item/weapon/paper/crumpled{
+ name = "basketball"
},
-/obj/effect/floor_decal/corner/red{
- dir = 6
+/obj/effect/floor_decal/industrial/outline/yellow,
+/obj/machinery/flasher{
+ id = "AsteroidSecFlash"
},
-/obj/machinery/atmospherics/unary/vent_pump/on{
- dir = 1
- },
-/obj/machinery/button/remote/airlock{
- id = "visitdoor";
- name = "Visitation Access";
- pixel_y = -24
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/turf/simulated/floor/tiled,
-/area/security/brig/visitation)
+/turf/simulated/floor/tiled/monotile,
+/area/security/brig)
"aq" = (
/obj/machinery/light{
dir = 4
@@ -388,13 +376,11 @@
/turf/simulated/floor/tiled/dark,
/area/security/brig)
"aO" = (
-/obj/effect/floor_decal/corner/white/border{
- dir = 8
+/obj/effect/floor_decal/industrial/outline/yellow,
+/obj/machinery/flasher{
+ id = "AsteroidSecFlash"
},
-/obj/item/weapon/paper/crumpled{
- name = "basketball"
- },
-/turf/simulated/floor/tiled/monotile,
+/turf/simulated/floor/tiled,
/area/security/brig)
"aP" = (
/turf/simulated/mineral/floor/vacuum,
@@ -1833,16 +1819,35 @@
/turf/simulated/floor/tiled/steel_dirty,
/area/security/brig)
"cO" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 5
+/obj/effect/floor_decal/borderfloor/shifted{
+ dir = 4
+ },
+/obj/effect/floor_decal/corner/red/border/shifted{
+ dir = 4
+ },
+/obj/effect/floor_decal/corner/red{
+ dir = 6
+ },
+/obj/machinery/atmospherics/unary/vent_pump/on{
+ dir = 1
+ },
+/obj/machinery/button/remote/airlock{
+ id = "visitdoor";
+ name = "Visitation Access";
+ pixel_y = -24
},
/obj/structure/cable/green{
d1 = 4;
d2 = 8;
icon_state = "4-8"
},
-/turf/simulated/floor/tiled/dark,
-/area/security/brig)
+/obj/machinery/button/flasher{
+ id = "AsteroidVisitingFlash";
+ pixel_x = -10;
+ pixel_y = -20
+ },
+/turf/simulated/floor/tiled,
+/area/security/brig/visitation)
"cP" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/structure/cable/green{
@@ -1948,12 +1953,24 @@
/turf/simulated/floor/tiled/dark,
/area/security/recstorage)
"cW" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/green,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+/obj/effect/floor_decal/borderfloor/shifted{
+ dir = 8
+ },
+/obj/effect/floor_decal/corner/red/border/shifted{
+ dir = 8
+ },
+/obj/effect/floor_decal/corner/red{
dir = 9
},
+/obj/machinery/atmospherics/unary/vent_pump/on{
+ dir = 1
+ },
+/obj/machinery/flasher{
+ id = "AsteroidVisitingFlash";
+ pixel_y = -20
+ },
/turf/simulated/floor/tiled,
-/area/security/brig)
+/area/security/brig/visitation)
"cX" = (
/obj/machinery/door/firedoor/glass,
/obj/structure/cable/green{
@@ -2260,20 +2277,20 @@
/turf/simulated/floor/tiled,
/area/security/security_cell_hallway)
"dt" = (
-/obj/effect/floor_decal/borderfloor/shifted{
- dir = 8
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 5
},
-/obj/effect/floor_decal/corner/red/border/shifted{
- dir = 8
+/obj/structure/cable/green{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
},
-/obj/effect/floor_decal/corner/red{
- dir = 9
+/obj/machinery/flasher{
+ id = "AsteroidSecFlash";
+ pixel_y = -20
},
-/obj/machinery/atmospherics/unary/vent_pump/on{
- dir = 1
- },
-/turf/simulated/floor/tiled,
-/area/security/brig/visitation)
+/turf/simulated/floor/tiled/dark,
+/area/security/brig)
"du" = (
/obj/effect/floor_decal/borderfloorblack{
dir = 8
@@ -2513,12 +2530,14 @@
/turf/simulated/floor/tiled/steel_dirty,
/area/security/brig)
"dQ" = (
-/obj/effect/floor_decal/industrial/warning,
/obj/machinery/atmospherics/pipe/simple/hidden/green,
-/obj/structure/disposalpipe/segment,
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 9
},
+/obj/effect/floor_decal/industrial/outline/yellow,
+/obj/machinery/flasher{
+ id = "AsteroidSecFlash"
+ },
/turf/simulated/floor/tiled,
/area/security/brig)
"dR" = (
@@ -7775,20 +7794,38 @@
/turf/simulated/floor/tiled,
/area/hallway/station/starboard)
"lU" = (
-/obj/structure/shuttle/engine/propulsion{
- dir = 8;
- icon_state = "propulsion_l"
+/obj/effect/floor_decal/industrial/warning,
+/obj/machinery/atmospherics/pipe/simple/hidden/green,
+/obj/structure/disposalpipe/segment,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 9
},
-/turf/space,
-/turf/simulated/shuttle/plating/airless/carry,
-/area/shuttle/large_escape_pod1)
+/obj/effect/floor_decal/industrial/outline/yellow,
+/obj/machinery/flasher{
+ id = "AsteroidSecFlash"
+ },
+/turf/simulated/floor/tiled,
+/area/security/brig)
"lV" = (
-/obj/structure/shuttle/engine/propulsion{
- dir = 8
+/obj/effect/floor_decal/borderfloor{
+ dir = 1
},
-/turf/space,
-/turf/simulated/shuttle/plating/airless/carry,
-/area/shuttle/large_escape_pod1)
+/obj/effect/floor_decal/corner/red/border{
+ dir = 1
+ },
+/obj/effect/floor_decal/borderfloor/corner2{
+ dir = 4
+ },
+/obj/effect/floor_decal/corner/red/bordercorner2{
+ dir = 4
+ },
+/obj/machinery/button/flasher{
+ id = "AsteroidSecFlash";
+ pixel_x = 20;
+ pixel_y = 20
+ },
+/turf/simulated/floor/tiled,
+/area/security/security_cell_hallway)
"lW" = (
/obj/structure/cable/green{
d1 = 4;
@@ -9557,13 +9594,30 @@
/turf/simulated/floor/tiled,
/area/hallway/station/starboard)
"oB" = (
-/obj/structure/shuttle/engine/propulsion{
- dir = 8;
- icon_state = "propulsion_r"
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
},
-/turf/space,
-/turf/simulated/shuttle/plating/airless/carry,
-/area/shuttle/large_escape_pod1)
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/green{
+ dir = 5
+ },
+/obj/structure/cable/green{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 1;
+ icon_state = "pipe-c"
+ },
+/obj/effect/floor_decal/industrial/outline/yellow,
+/obj/machinery/flasher{
+ id = "AsteroidSecFlash"
+ },
+/turf/simulated/floor/tiled,
+/area/security/brig)
"oC" = (
/obj/effect/floor_decal/borderfloor{
dir = 1
@@ -9586,10 +9640,13 @@
/turf/simulated/floor/tiled,
/area/hallway/station/starboard)
"oD" = (
-/obj/structure/stairs/spawner/west,
-/turf/simulated/sky/virgo3b/west,
-/turf/simulated/floor/tiled/white,
-/area/medical/biostorage)
+/obj/structure/shuttle/engine/propulsion{
+ dir = 8;
+ icon_state = "propulsion_l"
+ },
+/turf/space,
+/turf/simulated/shuttle/plating/airless/carry,
+/area/shuttle/large_escape_pod1)
"oE" = (
/obj/structure/toilet{
pixel_y = 6
@@ -9614,6 +9671,26 @@
},
/turf/simulated/floor/tiled/white,
/area/medical/recoveryrestroom)
+"oG" = (
+/obj/structure/shuttle/engine/propulsion{
+ dir = 8
+ },
+/turf/space,
+/turf/simulated/shuttle/plating/airless/carry,
+/area/shuttle/large_escape_pod1)
+"oH" = (
+/obj/structure/shuttle/engine/propulsion{
+ dir = 8;
+ icon_state = "propulsion_r"
+ },
+/turf/space,
+/turf/simulated/shuttle/plating/airless/carry,
+/area/shuttle/large_escape_pod1)
+"oI" = (
+/obj/structure/stairs/spawner/west,
+/turf/simulated/sky/virgo3b/west,
+/turf/simulated/floor/tiled/white,
+/area/medical/biostorage)
"oM" = (
/turf/simulated/open,
/area/engineering/foyer_mezzenine)
@@ -10285,7 +10362,6 @@
/area/ai_monitored/storage/eva)
"qj" = (
/obj/structure/table/woodentable,
-/obj/item/device/binoculars,
/obj/item/weapon/folder/blue,
/obj/structure/cable/green{
d1 = 1;
@@ -18721,27 +18797,6 @@
/obj/item/weapon/book/manual/medical_diagnostics_manual,
/turf/simulated/floor/tiled/white,
/area/maintenance/station/sec_lower)
-"Nc" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/green{
- dir = 5
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/structure/disposalpipe/segment{
- dir = 1;
- icon_state = "pipe-c"
- },
-/turf/simulated/floor/tiled,
-/area/security/brig)
"Nf" = (
/obj/effect/floor_decal/borderfloor{
dir = 8
@@ -18757,21 +18812,6 @@
},
/turf/simulated/floor/tiled,
/area/engineering/locker_room)
-"Ng" = (
-/obj/effect/floor_decal/borderfloor{
- dir = 1
- },
-/obj/effect/floor_decal/corner/red/border{
- dir = 1
- },
-/obj/effect/floor_decal/borderfloor/corner2{
- dir = 4
- },
-/obj/effect/floor_decal/corner/red/bordercorner2{
- dir = 4
- },
-/turf/simulated/floor/tiled,
-/area/security/security_cell_hallway)
"Nm" = (
/obj/structure/bed/chair{
dir = 8
@@ -27170,7 +27210,7 @@ bh
af
ao
dk
-ap
+cO
dj
dL
Tk
@@ -27454,7 +27494,7 @@ Fq
af
cG
do
-dt
+cW
af
XR
UT
@@ -28158,22 +28198,22 @@ UO
Hc
aS
EE
-aO
+ap
ak
bm
-DF
+aO
ar
bb
bt
-cW
+dQ
bv
bB
es
-dQ
+lU
Ye
cn
YK
-Nc
+oB
hQ
YN
jf
@@ -28488,7 +28528,7 @@ vE
wm
ws
xj
-oD
+oI
vT
aP
aP
@@ -28598,7 +28638,7 @@ cd
ce
bK
Zu
-Ng
+lV
JD
TY
aE
@@ -28874,13 +28914,13 @@ XT
GM
aS
aY
-cO
+dt
aS
aY
-cO
+dt
aS
aY
-cO
+dt
aS
PJ
Ph
@@ -35427,11 +35467,11 @@ hl
DI
RX
DL
-lU
-lV
-lV
-lV
-oB
+oD
+oG
+oG
+oG
+oH
oY
sW
ef
diff --git a/maps/tether/tether_things.dm b/maps/tether/tether_things.dm
index 52f999249ed..f511c9e1e82 100644
--- a/maps/tether/tether_things.dm
+++ b/maps/tether/tether_things.dm
@@ -368,6 +368,8 @@ var/global/list/latejoin_tram = list()
..()
for(var/i = 1 to 2)
new /obj/item/weapon/gun/energy/locked/frontier(src)
+ for(var/i = 1 to 2)
+ new /obj/item/weapon/gun/energy/locked/frontier/holdout(src)
// Used at centcomm for the elevator
/obj/machinery/cryopod/robot/door/dorms
diff --git a/maps/tether_better/tether_things.dm b/maps/tether_better/tether_things.dm
index 115f98abbd0..a2a1fdce051 100644
--- a/maps/tether_better/tether_things.dm
+++ b/maps/tether_better/tether_things.dm
@@ -368,6 +368,8 @@ var/global/list/latejoin_tram = list()
..()
for(var/i = 1 to 2)
new /obj/item/weapon/gun/energy/locked/frontier(src)
+ for(var/i = 1 to 2)
+ new /obj/item/weapon/gun/energy/locked/frontier/holdout(src)
// Used at centcomm for the elevator
/obj/machinery/cryopod/robot/door/dorms
diff --git a/sound/voice/Bug.ogg b/sound/voice/Bug.ogg
new file mode 100644
index 00000000000..83486e436f2
Binary files /dev/null and b/sound/voice/Bug.ogg differ
diff --git a/sound/voice/BugBuzz.ogg b/sound/voice/BugBuzz.ogg
new file mode 100644
index 00000000000..43fda8be425
Binary files /dev/null and b/sound/voice/BugBuzz.ogg differ
diff --git a/sound/voice/BugHiss.ogg b/sound/voice/BugHiss.ogg
new file mode 100644
index 00000000000..3ab342f5c9d
Binary files /dev/null and b/sound/voice/BugHiss.ogg differ
diff --git a/sound/voice/cat_purr.ogg b/sound/voice/cat_purr.ogg
new file mode 100644
index 00000000000..1125cb2bbd7
Binary files /dev/null and b/sound/voice/cat_purr.ogg differ
diff --git a/sound/voice/cat_purr_long.ogg b/sound/voice/cat_purr_long.ogg
new file mode 100644
index 00000000000..c74b845250d
Binary files /dev/null and b/sound/voice/cat_purr_long.ogg differ
diff --git a/sound/voice/multichirp.ogg b/sound/voice/multichirp.ogg
new file mode 100644
index 00000000000..2db358e942b
Binary files /dev/null and b/sound/voice/multichirp.ogg differ
diff --git a/sound/voice/teshchirp.ogg b/sound/voice/teshchirp.ogg
new file mode 100644
index 00000000000..f13c80dd335
Binary files /dev/null and b/sound/voice/teshchirp.ogg differ
diff --git a/sound/voice/teshsqueak.ogg b/sound/voice/teshsqueak.ogg
new file mode 100644
index 00000000000..41d205ab9fb
Binary files /dev/null and b/sound/voice/teshsqueak.ogg differ
diff --git a/sound/voice/teshtrill.ogg b/sound/voice/teshtrill.ogg
new file mode 100644
index 00000000000..db30e988e53
Binary files /dev/null and b/sound/voice/teshtrill.ogg differ
diff --git a/vorestation.dme b/vorestation.dme
index 8792701170f..e971212b986 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -55,6 +55,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"
@@ -254,6 +255,7 @@
#include "code\controllers\subsystems\atoms.dm"
#include "code\controllers\subsystems\character_setup.dm"
#include "code\controllers\subsystems\chat.dm"
+#include "code\controllers\subsystems\chemistry.dm"
#include "code\controllers\subsystems\circuits.dm"
#include "code\controllers\subsystems\dcs.dm"
#include "code\controllers\subsystems\events.dm"
@@ -287,7 +289,6 @@
#include "code\controllers\subsystems\vote.dm"
#include "code\controllers\subsystems\xenoarch.dm"
#include "code\controllers\subsystems\processing\bellies_vr.dm"
-#include "code\controllers\subsystems\processing\chemistry.dm"
#include "code\controllers\subsystems\processing\fastprocess.dm"
#include "code\controllers\subsystems\processing\obj.dm"
#include "code\controllers\subsystems\processing\processing.dm"
@@ -852,8 +853,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\vitals_monitor.dm"
#include "code\game\machinery\wall_frames.dm"
@@ -1198,19 +1197,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\tile_types.dm"
#include "code\game\objects\items\toys\balls_vr.dm"
@@ -2060,16 +2056,42 @@
#include "code\modules\economy\ATM.dm"
#include "code\modules\economy\cash.dm"
#include "code\modules\economy\cash_register.dm"
+#include "code\modules\economy\coins.dm"
#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\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\emotes\definitions\audible_furry_vr.dm"
+#include "code\modules\emotes\definitions\helpers_vr.dm"
+#include "code\modules\emotes\definitions\visible_vr.dm"
#include "code\modules\entopics_vr\alternate_appearance.dm"
#include "code\modules\entopics_vr\entopics.dm"
+#include "code\modules\emotes\emote_define.dm"
+#include "code\modules\emotes\emote_mob.dm"
+#include "code\modules\emotes\definitions\_mob.dm"
+#include "code\modules\emotes\definitions\_species.dm"
+#include "code\modules\emotes\definitions\audible.dm"
+#include "code\modules\emotes\definitions\audible_cough.dm"
+#include "code\modules\emotes\definitions\audible_scream.dm"
+#include "code\modules\emotes\definitions\audible_slap.dm"
+#include "code\modules\emotes\definitions\audible_snap.dm"
+#include "code\modules\emotes\definitions\audible_sneeze.dm"
+#include "code\modules\emotes\definitions\audible_whistle.dm"
+#include "code\modules\emotes\definitions\exertion.dm"
+#include "code\modules\emotes\definitions\human.dm"
+#include "code\modules\emotes\definitions\slimes.dm"
+#include "code\modules\emotes\definitions\synthetics.dm"
+#include "code\modules\emotes\definitions\visible.dm"
+#include "code\modules\emotes\definitions\visible_animated.dm"
+#include "code\modules\emotes\definitions\visible_vomit.dm"
#include "code\modules\error_handler\_defines.dm"
#include "code\modules\error_handler\error_handler.dm"
#include "code\modules\error_handler\error_viewer.dm"
@@ -2164,6 +2186,7 @@
#include "code\modules\food\drinkingglass\shaker.dm"
#include "code\modules\food\drinkingglass\shaker_vr.dm"
#include "code\modules\food\food\cans.dm"
+#include "code\modules\food\food\cans_vr.dm"
#include "code\modules\food\food\condiment.dm"
#include "code\modules\food\food\drinks.dm"
#include "code\modules\food\food\lunch.dm"
@@ -2408,14 +2431,57 @@
#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"
-#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"
#include "code\modules\materials\material_synth.dm"
-#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"
#include "code\modules\media\media_machinery.dm"
#include "code\modules\media\media_player_html5.dm"
#include "code\modules\media\media_player_vlc.dm"
@@ -2430,20 +2496,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"
@@ -2452,6 +2511,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"
@@ -3262,7 +3325,6 @@
#include "code\modules\power\fusion\fusion_circuits.dm"
#include "code\modules\power\fusion\fusion_particle_catcher.dm"
#include "code\modules\power\fusion\fusion_reactions.dm"
-#include "code\modules\power\fusion\fusion_reagents.dm"
#include "code\modules\power\fusion\magpower.dm"
#include "code\modules\power\fusion\core\_core.dm"
#include "code\modules\power\fusion\core\core_control.dm"
@@ -3361,6 +3423,7 @@
#include "code\modules\projectiles\guns\projectile\automatic.dm"
#include "code\modules\projectiles\guns\projectile\automatic_vr.dm"
#include "code\modules\projectiles\guns\projectile\boltaction.dm"
+#include "code\modules\projectiles\guns\projectile\boltaction_vr.dm"
#include "code\modules\projectiles\guns\projectile\caseless.dm"
#include "code\modules\projectiles\guns\projectile\contender.dm"
#include "code\modules\projectiles\guns\projectile\dartgun.dm"
@@ -3415,44 +3478,39 @@
#include "code\modules\random_map\noise\ore.dm"
#include "code\modules\random_map\noise\tundra.dm"
#include "code\modules\reagents\Chemistry-Colours.dm"
-#include "code\modules\reagents\Chemistry-Holder.dm"
#include "code\modules\reagents\Chemistry-Logging.dm"
-#include "code\modules\reagents\Chemistry-Machinery.dm"
-#include "code\modules\reagents\Chemistry-Machinery_vr.dm"
#include "code\modules\reagents\Chemistry-Metabolism.dm"
-#include "code\modules\reagents\Chemistry-Readme.dm"
-#include "code\modules\reagents\Chemistry-Reagents-Helpers.dm"
-#include "code\modules\reagents\Chemistry-Reagents.dm"
-#include "code\modules\reagents\Chemistry-Reagents_vr.dm"
-#include "code\modules\reagents\Chemistry-Recipes.dm"
-#include "code\modules\reagents\Chemistry-Recipes_vr.dm"
-#include "code\modules\reagents\reagent_containers.dm"
-#include "code\modules\reagents\reagent_dispenser.dm"
-#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Core.dm"
-#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Dispenser.dm"
-#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Food-Drinks.dm"
-#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Food-Drinks_vr.dm"
-#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Medicine.dm"
-#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Medicine_vr.dm"
-#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Modifiers.dm"
-#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Other.dm"
-#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Toxins.dm"
-#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Vore_vr.dm"
-#include "code\modules\reagents\dispenser\_defines.dm"
-#include "code\modules\reagents\dispenser\cartridge.dm"
-#include "code\modules\reagents\dispenser\cartridge_presets.dm"
-#include "code\modules\reagents\dispenser\cartridge_presets_vr.dm"
-#include "code\modules\reagents\dispenser\cartridge_spawn.dm"
-#include "code\modules\reagents\dispenser\dispenser2.dm"
-#include "code\modules\reagents\dispenser\dispenser2_energy.dm"
-#include "code\modules\reagents\dispenser\dispenser_presets.dm"
-#include "code\modules\reagents\dispenser\dispenser_presets_vr.dm"
-#include "code\modules\reagents\dispenser\supply.dm"
-#include "code\modules\reagents\distilling\Distilling-Recipes.dm"
-#include "code\modules\reagents\distilling\distilling.dm"
+#include "code\modules\reagents\holder\distilling.dm"
+#include "code\modules\reagents\holder\holder.dm"
#include "code\modules\reagents\hoses\connector.dm"
#include "code\modules\reagents\hoses\hose.dm"
#include "code\modules\reagents\hoses\hose_connector.dm"
+#include "code\modules\reagents\machinery\chem_master.dm"
+#include "code\modules\reagents\machinery\chem_master_vr.dm"
+#include "code\modules\reagents\machinery\chemalyzer.dm"
+#include "code\modules\reagents\machinery\distillery.dm"
+#include "code\modules\reagents\machinery\grinder.dm"
+#include "code\modules\reagents\machinery\dispenser\_defines.dm"
+#include "code\modules\reagents\machinery\dispenser\cartridge.dm"
+#include "code\modules\reagents\machinery\dispenser\cartridge_presets.dm"
+#include "code\modules\reagents\machinery\dispenser\cartridge_presets_vr.dm"
+#include "code\modules\reagents\machinery\dispenser\cartridge_spawn.dm"
+#include "code\modules\reagents\machinery\dispenser\dispenser2.dm"
+#include "code\modules\reagents\machinery\dispenser\dispenser2_energy.dm"
+#include "code\modules\reagents\machinery\dispenser\dispenser_presets.dm"
+#include "code\modules\reagents\machinery\dispenser\dispenser_presets_vr.dm"
+#include "code\modules\reagents\machinery\dispenser\reagent_tank.dm"
+#include "code\modules\reagents\machinery\dispenser\supply.dm"
+#include "code\modules\reagents\reactions\_reactions.dm"
+#include "code\modules\reagents\reactions\distilling\distilling.dm"
+#include "code\modules\reagents\reactions\fusion\fusion.dm"
+#include "code\modules\reagents\reactions\instant\drinks.dm"
+#include "code\modules\reagents\reactions\instant\drinks_vr.dm"
+#include "code\modules\reagents\reactions\instant\food.dm"
+#include "code\modules\reagents\reactions\instant\food_vr.dm"
+#include "code\modules\reagents\reactions\instant\instant.dm"
+#include "code\modules\reagents\reactions\instant\instant_vr.dm"
+#include "code\modules\reagents\reagent_containers\_reagent_containers.dm"
#include "code\modules\reagents\reagent_containers\blood_pack.dm"
#include "code\modules\reagents\reagent_containers\blood_pack_vr.dm"
#include "code\modules\reagents\reagent_containers\borghypo.dm"
@@ -3469,6 +3527,19 @@
#include "code\modules\reagents\reagent_containers\syringes.dm"
#include "code\modules\reagents\reagent_containers\syringes_vr.dm"
#include "code\modules\reagents\reagent_containers\unidentified_hypospray.dm"
+#include "code\modules\reagents\reagents\_helpers.dm"
+#include "code\modules\reagents\reagents\_reagents.dm"
+#include "code\modules\reagents\reagents\core.dm"
+#include "code\modules\reagents\reagents\dispenser.dm"
+#include "code\modules\reagents\reagents\food_drinks.dm"
+#include "code\modules\reagents\reagents\food_drinks_vr.dm"
+#include "code\modules\reagents\reagents\medicine.dm"
+#include "code\modules\reagents\reagents\medicine_vr.dm"
+#include "code\modules\reagents\reagents\modifiers.dm"
+#include "code\modules\reagents\reagents\other.dm"
+#include "code\modules\reagents\reagents\other_vr.dm"
+#include "code\modules\reagents\reagents\toxins.dm"
+#include "code\modules\reagents\reagents\vore_vr.dm"
#include "code\modules\recycling\conveyor2.dm"
#include "code\modules\recycling\disposal-construction.dm"
#include "code\modules\recycling\disposal.dm"