diff --git a/citadel.dme b/citadel.dme
index ba2f4c655c1..275bc1b82d1 100644
--- a/citadel.dme
+++ b/citadel.dme
@@ -192,6 +192,7 @@
#include "code\__DEFINES\inventory\procs.dm"
#include "code\__DEFINES\inventory\rendering.dm"
#include "code\__DEFINES\inventory\slots.dm"
+#include "code\__DEFINES\items\hypospray.dm"
#include "code\__DEFINES\items\inducer.dm"
#include "code\__DEFINES\items\nifs.dm"
#include "code\__DEFINES\items\clothing\uniforms.dm"
@@ -307,6 +308,7 @@
#include "code\__HELPERS\path.dm"
#include "code\__HELPERS\piping_colors_lists.dm"
#include "code\__HELPERS\qdel.dm"
+#include "code\__HELPERS\reagents.dm"
#include "code\__HELPERS\ref.dm"
#include "code\__HELPERS\sanitize_values.dm"
#include "code\__HELPERS\shell.dm"
@@ -1583,7 +1585,6 @@
#include "code\game\objects\items\storage\boxes.dm"
#include "code\game\objects\items\storage\briefcase.dm"
#include "code\game\objects\items\storage\fancy.dm"
-#include "code\game\objects\items\storage\firstaid.dm"
#include "code\game\objects\items\storage\internal.dm"
#include "code\game\objects\items\storage\laundry_basket.dm"
#include "code\game\objects\items\storage\lockbox.dm"
@@ -1593,6 +1594,8 @@
#include "code\game\objects\items\storage\toolbox.dm"
#include "code\game\objects\items\storage\uplink_kits.dm"
#include "code\game\objects\items\storage\wallets.dm"
+#include "code\game\objects\items\storage\medical\firstaid.dm"
+#include "code\game\objects\items\storage\medical\hypokit.dm"
#include "code\game\objects\items\storage\single_use\_single_use.dm"
#include "code\game\objects\items\storage\single_use\med_pouch.dm"
#include "code\game\objects\items\storage\single_use\mre.dm"
@@ -4036,8 +4039,11 @@
#include "code\modules\reagents\chemistry\reagents\Chemistry-Topical.dm"
#include "code\modules\reagents\chemistry\reagents\other\cleaner.dm"
#include "code\modules\reagents\chemistry\reagents\pyrotechnics\thermite.dm"
+#include "code\modules\reagents\chemistry\recipes\medicine.dm"
#include "code\modules\reagents\distilling\Distilling-Recipes.dm"
#include "code\modules\reagents\distilling\distilling.dm"
+#include "code\modules\reagents\items\hypospray.dm"
+#include "code\modules\reagents\items\hypovial.dm"
#include "code\modules\reagents\machinery\chem_master.dm"
#include "code\modules\reagents\machinery\reagent_dispenser.dm"
#include "code\modules\reagents\machinery\dispenser\cartridge.dm"
diff --git a/code/__DEFINES/_flags/item_flags.dm b/code/__DEFINES/_flags/item_flags.dm
index dfebc51bc87..ef8f75fa367 100644
--- a/code/__DEFINES/_flags/item_flags.dm
+++ b/code/__DEFINES/_flags/item_flags.dm
@@ -31,49 +31,40 @@ DEFINE_BITFIELD(item_flags, list(
))
//! Flags for the clothing_flags var on /obj/item
-/*
-#define LAVAPROTECT (1<<0)
-/// SUIT and HEAD items which stop pressure damage. To stop you taking all pressure damage you must have both a suit and head item with this flag.
-#define STOPSPRESSUREDAMAGE (1<<1)
-*/
/// Blocks the effect that chemical clouds would have on a mob --glasses, mask and helmets ONLY! (NOTE: flag shared with ONESIZEFITSALL)
-#define BLOCK_GAS_SMOKE_EFFECT (1<<2)
-/// Mask allows internals
-#define ALLOWINTERNALS (1<<3)
-/// Prevents from slipping on wet floors, in space etc
-#define NOSLIP (1<<4)
-/*
-/// Prevents from slipping on frozen floors
-#define NOSLIP_ICE (1<<5)
-*/
-/// Prevents syringes, parapens and hyposprays if equipped to slot_suit or SLOT_ID_HEAD.
-#define THICKMATERIAL (1<<6)
-/*
-/// The voicebox in this clothing can be toggled.
-#define VOICEBOX_TOGGLABLE (1<<7)
-/// The voicebox is currently turned off.
-#define VOICEBOX_DISABLED (1<<8)
-/// Hats with negative effects when worn (i.e the tinfoil hat).
-#define IGNORE_HAT_TOSS (1<<9)
-*/
-/// Allows helmets and glasses to scan reagents.
-#define SCAN_REAGENTS (1<<10)
-/// At the moment, masks with this flag will not prevent eating even if they are covering your face.
-#define FLEXIBLEMATERIAL (1<<11)
-/// Allows special survival food items to be eaten through it
-#define ALLOW_SURVIVALFOOD (1<<12)
/// ignores "is this limb here" for equip.
-#define CLOTHING_IGNORE_DELIMB (1<<13)
+#define CLOTHING_IGNORE_DELIMB (1<<1)
/// ignores "do we have a jumpsuit" for belt
-#define CLOTHING_IGNORE_BELTLINK (1<<14)
+#define CLOTHING_IGNORE_BELTLINK (1<<2)
/// for plural limbs, wearable with just one
-#define CLOTHING_ALLOW_SINGLE_LIMB (1<<15)
+#define CLOTHING_ALLOW_SINGLE_LIMB (1<<3)
+/// Prevents syringes, parapens and hyposprays if equipped to slot_suit or SLOT_ID_HEAD.
+#define CLOTHING_THICK_MATERIAL (1<<4)
+/// Syringes / hyposprays / etc can get through, but need to pass through an injection port.
+#define CLOTHING_INJECTION_PORT (1<<5)
+// todo: audit
+#define BLOCK_GAS_SMOKE_EFFECT (1<<6)
+/// Mask allows internals
+// todo: audit
+#define ALLOWINTERNALS (1<<7)
+/// Prevents from slipping on wet floors, in space etc
+// todo: audit
+#define NOSLIP (1<<8)
+/// Allows helmets and glasses to scan reagents.
+// todo: audit
+#define SCAN_REAGENTS (1<<9)
+/// At the moment, masks with this flag will not prevent eating even if they are covering your face.
+// todo: audit
+#define FLEXIBLEMATERIAL (1<<10)
+/// Allows special survival food items to be eaten through it
+// todo: audit
+#define ALLOW_SURVIVALFOOD (1<<11)
DEFINE_BITFIELD(clothing_flags, list(
BITFIELD(BLOCK_GAS_SMOKE_EFFECT),
BITFIELD(ALLOWINTERNALS),
BITFIELD(NOSLIP),
- BITFIELD(THICKMATERIAL),
+ BITFIELD(CLOTHING_THICK_MATERIAL),
BITFIELD(SCAN_REAGENTS),
BITFIELD(FLEXIBLEMATERIAL),
BITFIELD(ALLOW_SURVIVALFOOD),
diff --git a/code/__DEFINES/chemistry.dm b/code/__DEFINES/chemistry.dm
index e10191ec149..3a6a2341909 100644
--- a/code/__DEFINES/chemistry.dm
+++ b/code/__DEFINES/chemistry.dm
@@ -1,3 +1,18 @@
+//* Reagent exposure methods.
+//* These are flags for combined checks, but are often passed as an one-bit-value enum to procs.
+
+/// Splashed, touched, sprayed, etc
+#define CHEM_TOUCH (1<<0)
+/// Eaten, drunk, etc
+#define CHEM_INGEST (1<<1)
+/// Injected into bloodstream or equivalent
+#define CHEM_INJECT (1<<2)
+/// Inhaled or immersed in gas
+// todo: this is currently unimplemented.
+#define CHEM_VAPOR (1<<3)
+
+//* Unsorted
+
/// Factor of how fast mob nutrition decreases
#define DEFAULT_HUNGER_FACTOR 0.03
/// Factor of how fast mob hydration decreases
@@ -5,21 +20,6 @@
/// Means 'Reagent Effect Multiplier'. This is how many units of reagent are consumed per tick
#define REM 0.2
-//! Reagent exposure methods.
-/// Used for splashing.
-#define CHEM_TOUCH (1<<0)
-/// Used for ingesting the reagents. Food, drinks, inhaling smoke.
-#define CHEM_INGEST (1<<1)
-/// Used by foams, sprays, and blob attacks.
-#define CHEM_VAPOR (1<<2)
-/// Used by medical patches and gels.
-#define CHEM_PATCH (1<<3)
-/// Used for direct injection of reagents.
-#define CHEM_INJECT (1<<4)
-/// Used for blood contamination.
-#define CHEM_BLOOD (1<<5)
-
-
#define MINIMUM_CHEMICAL_VOLUME 0.01
// states of matter
diff --git a/code/__DEFINES/items/hypospray.dm b/code/__DEFINES/items/hypospray.dm
new file mode 100644
index 00000000000..36c8c868dfd
--- /dev/null
+++ b/code/__DEFINES/items/hypospray.dm
@@ -0,0 +1,2 @@
+#define HYPOSPRAY_MODE_INJECT 1
+#define HYPOSPRAY_MODE_SPRAY 2
diff --git a/code/__DEFINES/misc/message_ranges.dm b/code/__DEFINES/misc/message_ranges.dm
index ac904468230..90fdf16e693 100644
--- a/code/__DEFINES/misc/message_ranges.dm
+++ b/code/__DEFINES/misc/message_ranges.dm
@@ -1,8 +1,10 @@
-/// message range for silenced combat actions
+/// message range for silenced combat actions. for stuff like id swipes, etc
#define MESSAGE_RANGE_COMBAT_SILENCED 1
-/// message range for subtle combat actions
+/// message range for moderately silenced combat actions. for most things like syringe injections, etc.
+#define MESSAGE_RANGE_COMBAT_SUPPRESSED 2
+/// message range for subtle combat actions. for things like subtle hits in melee
#define MESSAGE_RANGE_COMBAT_SUBTLE 3
-/// message range for loud combat actions
+/// message range for loud combat actions. for things like obvious melee / ranged fire
#define MESSAGE_RANGE_COMBAT_LOUD 7
/// message range for most construction / deconstruction actions
diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index 501ab7a5f42..eec8baaef4d 100644
--- a/code/__HELPERS/_logging.dm
+++ b/code/__HELPERS/_logging.dm
@@ -207,6 +207,12 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global"))
/proc/log_qdel(text)
WRITE_LOG(GLOB.world_qdel_log, "QDEL: [text]")
+/proc/log_reagent(text)
+ WRITE_LOG(GLOB.world_reagent_log, text)
+
+/proc/log_reagent_transfer(text)
+ log_reagent("TRANSFER: [text]")
+
/proc/log_subsystem(subsystem, text)
WRITE_LOG(GLOB.subsystem_log, "[subsystem]: [text]")
diff --git a/code/__HELPERS/reagents.dm b/code/__HELPERS/reagents.dm
new file mode 100644
index 00000000000..3857d459ce9
--- /dev/null
+++ b/code/__HELPERS/reagents.dm
@@ -0,0 +1,52 @@
+// todo: this doesn't entirely work. see recipe for peridaxon requiring priority.
+/proc/chem_recipes_do_conflict(datum/chemical_reaction/r1, datum/chemical_reaction/r2)
+ // do the non-list tests first, because they are cheaper
+ if(r1.required_container != r2.required_container)
+ return FALSE
+ // if(r1.is_cold_recipe == r2.is_cold_recipe)
+ // if(r1.required_temp != r2.required_temp)
+ // //one reaction requires a more extreme temperature than the other, so there is no conflict
+ // return FALSE
+ // else
+ // var/datum/chemical_reaction/cold_one = r1.is_cold_recipe ? r1 : r2
+ // var/datum/chemical_reaction/warm_one = r1.is_cold_recipe ? r2 : r1
+ // if(cold_one.required_temp < warm_one.required_temp)
+ // //the range of temperatures does not overlap, so there is no conflict
+ // return FALSE
+
+ //find the reactions with the shorter and longer required_reagents list
+ var/datum/chemical_reaction/long_req
+ var/datum/chemical_reaction/short_req
+ if(r1.required_reagents.len > r2.required_reagents.len)
+ long_req = r1
+ short_req = r2
+ else if(r1.required_reagents.len < r2.required_reagents.len)
+ long_req = r2
+ short_req = r1
+ else
+ //if they are the same length, sort instead by the length of the catalyst list
+ //this is important if the required_reagents lists are the same
+ if(r1.catalysts.len > r2.catalysts.len)
+ long_req = r1
+ short_req = r2
+ else
+ long_req = r2
+ short_req = r1
+
+
+ //check if the shorter reaction list is a subset of the longer one
+ var/list/overlap = r1.required_reagents & r2.required_reagents
+ if(overlap.len != short_req.required_reagents.len)
+ //there is at least one reagent in the short list that is not in the long list, so there is no conflict
+ return FALSE
+
+ //check to see if the shorter reaction's catalyst list is also a subset of the longer reaction's catalyst list
+ //if the longer reaction's catalyst list is a subset of the shorter ones, that is fine
+ //if the reaction lists are the same, the short reaction will have the shorter required_catalysts list, so it will register as a conflict
+ var/list/short_minus_long_catalysts = short_req.catalysts - long_req.catalysts
+ if(short_minus_long_catalysts.len)
+ //there is at least one unique catalyst for the short reaction, so there is no conflict
+ return FALSE
+
+ //if we got this far, the longer reaction will be impossible to create if the shorter one is earlier in GLOB.chemical_reactions_list, and will require the reagents to be added in a particular order otherwise
+ return TRUE
diff --git a/code/_globals/logging.dm b/code/_globals/logging.dm
index b1f043ed3c8..7758b1c2711 100644
--- a/code/_globals/logging.dm
+++ b/code/_globals/logging.dm
@@ -30,6 +30,9 @@ GLOBAL_PROTECT(sql_error_log)
/// Map error logging
GLOBAL_VAR(world_map_error_log)
GLOBAL_PROTECT(world_map_error_log)
+GLOBAL_VAR(world_reagent_log)
+GLOBAL_PROTECT(world_reagent_log)
+/// Reagent logging
/// datum/controller/subsystem logging in general
GLOBAL_VAR(subsystem_log)
GLOBAL_PROTECT(subsystem_log)
@@ -39,13 +42,6 @@ GLOBAL_PROTECT(tgui_log)
SIMPLE_LOG_BOILERPLATE(inventory_log, inventory)
SIMPLE_LOG_BOILERPLATE(click_log, click)
-/// Picture logging
-GLOBAL_VAR(picture_log_directory)
-GLOBAL_PROTECT(picture_log_directory)
-GLOBAL_VAR_INIT(picture_logging_id, 1)
-GLOBAL_PROTECT(picture_logging_id)
-GLOBAL_VAR(picture_logging_prefix)
-GLOBAL_PROTECT(picture_logging_prefix)
/// Log associated with [/proc/log_suspicious_login()]
/// Intended to hold all logins that failed due to suspicious circumstances such as ban detection, CID randomisation etc.
GLOBAL_VAR(world_suspicious_login_log)
diff --git a/code/controllers/subsystem/processing/chemistry.dm b/code/controllers/subsystem/processing/chemistry.dm
index d42a5d360a4..60b0d6725df 100644
--- a/code/controllers/subsystem/processing/chemistry.dm
+++ b/code/controllers/subsystem/processing/chemistry.dm
@@ -30,21 +30,24 @@ PROCESSING_SUBSYSTEM_DEF(chemistry)
* - 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
+ var/paths = subtypesof(/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
+ tim_sort(chemical_reactions, /proc/cmp_chemical_reaction_priority)
+ for(var/datum/chemical_reaction/D as anything in chemical_reactions)
+ if(!length(D.required_reagents))
+ continue
+ 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
+ var/paths = subtypesof(/datum/reagent)
reagent_lookup = list()
for(var/datum/reagent/path as anything in paths)
if(initial(path.abstract_type) == path)
diff --git a/code/datums/autolathe/medical.dm b/code/datums/autolathe/medical.dm
index 60c6332c24a..fe7f74203f2 100644
--- a/code/datums/autolathe/medical.dm
+++ b/code/datums/autolathe/medical.dm
@@ -33,6 +33,13 @@
/datum/category_item/autolathe/medical/vial
name = "glass vial"
path =/obj/item/reagent_containers/glass/beaker/vial
+/datum/category_item/autolathe/medical/hypovial
+ name = "hypovial"
+ path =/obj/item/reagent_containers/glass/hypovial
+
+/datum/category_item/autolathe/medical/hypovial_large
+ name = "large hypovial"
+ path =/obj/item/reagent_containers/glass/hypovial/large
/datum/category_item/autolathe/medical/syringe
name = "syringe"
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index b828d07e91d..6909f279a40 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -47,7 +47,7 @@
if(("name" in vars) && !isatom(src))
. += "[vars["name"]]
"
-/datum/proc/on_reagent_change(changetype)
+/datum/proc/on_reagent_change()
return
// todo: proper way to mark things immutable & provide a method to make a mutable clone for editing.
diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm
index 00ce70a3195..2727789cdf6 100644
--- a/code/game/dna/dna_modifier.dm
+++ b/code/game/dna/dna_modifier.dm
@@ -598,7 +598,7 @@
inject_amount = 0
if (inject_amount > 50)
inject_amount = 50
- connected.beaker.reagents.trans_to_mob(connected.occupant, inject_amount, CHEM_BLOOD)
+ connected.beaker.reagents.trans_to_mob(connected.occupant, inject_amount, CHEM_INJECT)
return 1 // return 1 forces an update to all Nano uis attached to src
////////////////////////////////////////////////////////
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index 0e6de4e1690..bea8fe774fe 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -248,7 +248,7 @@
var/has_clonexa = occupant.reagents.get_reagent_amount("clonexadone") >= 1
var/has_cryo_medicine = has_cryo || has_clonexa
if(beaker && !has_cryo_medicine)
- beaker.reagents.trans_to_mob(occupant, 1, CHEM_BLOOD, 10)
+ beaker.reagents.trans_to_mob(occupant, 1, CHEM_INJECT, 10)
/obj/machinery/atmospherics/component/unary/cryo_cell/proc/heat_gas_contents()
if(air_contents.total_moles < 1)
diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm
index aa68329b3a8..18aeb9da9c9 100644
--- a/code/game/machinery/iv_drip.dm
+++ b/code/game/machinery/iv_drip.dm
@@ -196,7 +196,7 @@
if(istype(reagent_container, /obj/item/reagent_containers/blood))
// speed up transfer on blood packs
real_transfer_amount *= 2
- target_reagents.trans_to_mob(attached_victim, real_transfer_amount * delta_time * 0.5, type = CHEM_BLOOD)
+ target_reagents.trans_to_mob(attached_victim, real_transfer_amount * delta_time * 0.5, type = CHEM_INJECT)
update_appearance()
// Take blood
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index a97e406144a..089ff5c0f01 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -968,6 +968,7 @@
/obj/item/storage/single_use/med_pouch/oxyloss = 3,
/obj/item/storage/single_use/med_pouch/burn = 3,
/obj/item/storage/single_use/med_pouch/trauma = 3,
+ /obj/item/storage/hypokit = 6,
)
contraband = list(
/obj/item/reagent_containers/pill/tox = 3,
diff --git a/code/game/mecha/equipment/tools/syringe_gun.dm b/code/game/mecha/equipment/tools/syringe_gun.dm
index fce149846fd..9c04e46be03 100644
--- a/code/game/mecha/equipment/tools/syringe_gun.dm
+++ b/code/game/mecha/equipment/tools/syringe_gun.dm
@@ -83,7 +83,7 @@
if(M)
S.icon_state = initial(S.icon_state)
S.icon = initial(S.icon)
- S.reagents.trans_to_mob(M, S.reagents.total_volume, CHEM_BLOOD)
+ S.reagents.trans_to_mob(M, S.reagents.total_volume, CHEM_INJECT)
M.take_organ_damage(2)
S.visible_message(" [M] was hit by the syringe!")
break
diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm
index bad4a3d29ad..d66f9e2cd3b 100644
--- a/code/game/objects/items/bodybag.dm
+++ b/code/game/objects/items/bodybag.dm
@@ -218,7 +218,7 @@
return
if(H.reagents)
- syringe.reagents.trans_to_mob(H, 30, CHEM_BLOOD)
+ syringe.reagents.trans_to_mob(H, 30, CHEM_INJECT)
/obj/structure/closet/body_bag/cryobag/examine(mob/user)
. = ..()
diff --git a/code/game/objects/items/devices/defib.dm b/code/game/objects/items/devices/defib.dm
index 49ddd6783db..209782d42fa 100644
--- a/code/game/objects/items/devices/defib.dm
+++ b/code/game/objects/items/devices/defib.dm
@@ -296,7 +296,7 @@
/obj/item/shockpaddles/proc/check_contact(mob/living/carbon/human/H)
if(!combat)
for(var/obj/item/clothing/cloth in list(H.wear_suit, H.w_uniform))
- if((cloth.body_cover_flags & UPPER_TORSO) && (cloth.clothing_flags & THICKMATERIAL))
+ if((cloth.body_cover_flags & UPPER_TORSO) && (cloth.clothing_flags & CLOTHING_THICK_MATERIAL))
return FALSE
return TRUE
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 47b02eea6c0..c07bde49c14 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -139,6 +139,7 @@
/obj/item/clothing/head/surgery,
/obj/item/clothing/gloves,
/obj/item/reagent_containers/hypospray,
+ /obj/item/hypospray,
/obj/item/clothing/glasses,
/obj/item/tool/crowbar,
/obj/item/flashlight,
@@ -271,6 +272,7 @@
/obj/item/reagent_containers/glass/bottle,
/obj/item/reagent_containers/syringe,
/obj/item/reagent_containers/hypospray,
+ /obj/item/hypospray,
/obj/item/storage/pill_bottle,
/obj/item/stack/medical,
/obj/item/stack/marker_beacon,
@@ -346,6 +348,7 @@
/obj/item/clothing/head/surgery,
/obj/item/clothing/gloves,
/obj/item/reagent_containers/hypospray,
+ /obj/item/hypospray,
/obj/item/clothing/glasses,
/obj/item/tool/crowbar,
/obj/item/flashlight,
diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/medical/firstaid.dm
similarity index 99%
rename from code/game/objects/items/storage/firstaid.dm
rename to code/game/objects/items/storage/medical/firstaid.dm
index dc01f10598e..e7f2dbb161f 100644
--- a/code/game/objects/items/storage/firstaid.dm
+++ b/code/game/objects/items/storage/medical/firstaid.dm
@@ -19,9 +19,6 @@
drop_sound = 'sound/items/drop/cardboardbox.ogg'
pickup_sound = 'sound/items/pickup/cardboardbox.ogg'
-/obj/item/storage/firstaid/Initialize(mapload)
- . = ..()
-
/obj/item/storage/firstaid/fire
name = "fire first aid kit"
desc = "It's an emergency medical kit, loaded with everything you would need to treat burns of any kind."
diff --git a/code/game/objects/items/storage/medical/hypokit.dm b/code/game/objects/items/storage/medical/hypokit.dm
new file mode 100644
index 00000000000..84b17b1860b
--- /dev/null
+++ b/code/game/objects/items/storage/medical/hypokit.dm
@@ -0,0 +1,105 @@
+/obj/item/storage/hypokit
+ name = "hypospray kit"
+ desc = "A standard issue storage case and assorted vials for a prototype subdermal hypospray."
+ icon = 'icons/items/storage/firstaid_small.dmi'
+ inhand_icon = 'icons/items/storage/firstaid.dmi'
+ icon_state = "normal"
+ max_storage_space = INVENTORY_BOX_SPACE
+ can_hold = list(
+ /obj/item/reagent_containers/glass/hypovial,
+ /obj/item/hypospray,
+ )
+
+ var/hypospray_path = /obj/item/hypospray
+ var/vial_path = /obj/item/reagent_containers/glass/hypovial
+ var/vial_amount = 6
+
+/obj/item/storage/hypokit/PopulateContents()
+ . = ..()
+ new hypospray_path(src)
+ spawn_hypovials()
+
+/obj/item/storage/hypokit/proc/spawn_hypovials()
+ for(var/i in 1 to vial_amount)
+ new vial_path(src)
+
+/obj/item/storage/hypokit/combat
+ name = "combat hypospray kit"
+ icon_state = "tactical"
+ hypospray_path = /obj/item/hypospray/combat/loaded
+ vial_path = /obj/item/reagent_containers/glass/hypovial/large
+ max_storage_space = INVENTORY_BOX_SPACE * 2
+ storage_cost = ITEMSIZE_COST_NORMAL * 1.5
+
+/obj/item/storage/hypokit/combat/loaded/spawn_hypovials()
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/large/bicaridine(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/large/dylovene(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/large/kelotane(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/large/dexalin_plus(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/inaprovaline(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/peridaxon(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/tramadol(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/arithrazine(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/spaceacillin(src)
+
+/obj/item/storage/hypokit/advanced
+ name = "advanced hypospray kit"
+ icon = 'icons/items/storage/firstaid.dmi'
+ icon_state = "briefcase"
+ inhand_state = "normal"
+ hypospray_path = /obj/item/hypospray/advanced/loaded
+ vial_path = /obj/item/reagent_containers/glass/hypovial/large
+ max_storage_space = INVENTORY_BOX_SPACE * 2
+ storage_cost = ITEMSIZE_COST_NORMAL * 1.5
+
+/obj/item/storage/hypokit/advanced/loaded/spawn_hypovials()
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/large/bicaridine(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/large/dylovene(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/large/kelotane(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/large/dexalin_plus(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/inaprovaline(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/peridaxon(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/tramadol(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/arithrazine(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/spaceacillin(src)
+
+/obj/item/storage/hypokit/advanced/cmo
+ hypospray_path = /obj/item/hypospray/advanced/cmo/loaded
+
+/obj/item/storage/hypokit/advanced/cmo/loaded/spawn_hypovials()
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/large/bicaridine(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/large/dylovene(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/large/kelotane(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/dexalin_plus(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/inaprovaline(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/peridaxon(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/tramadol(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/arithrazine(src)
+ new /obj/item/reagent_containers/glass/hypovial/large/spaceacillin(src)
+
+/obj/item/storage/hypokit/loaded
+
+/obj/item/storage/hypokit/loaded/spawn_hypovials()
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/bicaridine(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/dylovene(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/kelotane(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/dexalin(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/tricordrazine(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_containers/glass/hypovial/inaprovaline(src)
diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm
index 19969897f0b..5418de66bf4 100644
--- a/code/game/objects/items/weapons/implants/implant.dm
+++ b/code/game/objects/items/weapons/implants/implant.dm
@@ -376,7 +376,7 @@ the implant may become unstable and either pre-maturely inject the subject or si
/obj/item/implant/chem/activate(var/cause)
if((!cause) || (!src.imp_in)) return 0
var/mob/living/carbon/R = src.imp_in
- src.reagents.trans_to_mob(R, cause, CHEM_BLOOD)
+ src.reagents.trans_to_mob(R, cause, CHEM_INJECT)
to_chat(R, "You hear a faint *beep*.")
if(!src.reagents.total_volume)
to_chat(R, "You hear a faint click from your chest.")
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
index ade6bf960e8..fbd71b7f764 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
@@ -169,7 +169,7 @@
/obj/item/radio/headset/heads/cmo,
/obj/item/radio/headset/heads/cmo/alt,
/obj/item/flash,
- /obj/item/reagent_containers/hypospray/vial,
+ /obj/item/storage/hypokit/advanced/cmo,
/obj/item/clothing/suit/storage/hooded/wintercoat/medical/cmo,
/obj/item/clothing/shoes/boots/winter/medical,
/obj/item/storage/box/freezer,
@@ -179,7 +179,6 @@
/obj/item/clothing/head/bio_hood/cmo,
/obj/item/gps/medical/cmo,
/obj/item/clothing/shoes/white,
- /obj/item/reagent_containers/glass/beaker/vial,
/obj/item/clothing/under/rank/chief_medical_officer/turtleneck)
/obj/structure/closet/secure_closet/CMO/Initialize(mapload)
diff --git a/code/game/objects/structures/medical_stand_vr.dm b/code/game/objects/structures/medical_stand_vr.dm
index 8e7d87d4180..2fb5f1f0f6e 100644
--- a/code/game/objects/structures/medical_stand_vr.dm
+++ b/code/game/objects/structures/medical_stand_vr.dm
@@ -400,7 +400,7 @@
if(beaker)
if(mode) // Give blood
if(beaker.volume > 0)
- beaker.reagents.trans_to_mob(attached, transfer_amount, CHEM_BLOOD)
+ beaker.reagents.trans_to_mob(attached, transfer_amount, CHEM_INJECT)
update_icon()
else // Take blood
var/amount = beaker.reagents.maximum_volume - beaker.reagents.total_volume
diff --git a/code/game/world.dm b/code/game/world.dm
index dab7c370e12..38b5675d35b 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -141,21 +141,13 @@ GLOBAL_LIST(topic_status_cache)
var/realtime = world.realtime
var/texttime = time2text(realtime, "YYYY/MM/DD")
GLOB.log_directory = "data/logs/[texttime]/round-"
- GLOB.picture_logging_prefix = "L_[time2text(realtime, "YYYYMMDD")]_"
- GLOB.picture_log_directory = "data/picture_logs/[texttime]/round-"
if(GLOB.round_id)
GLOB.log_directory += "[GLOB.round_id]"
- GLOB.picture_logging_prefix += "R_[GLOB.round_id]_"
- GLOB.picture_log_directory += "[GLOB.round_id]"
else
var/timestamp = replacetext(TIME_STAMP("hh:mm:ss", FALSE), ":", ".")
GLOB.log_directory += "[timestamp]"
- GLOB.picture_log_directory += "[timestamp]"
- GLOB.picture_logging_prefix += "T_[timestamp]_"
else
GLOB.log_directory = "data/logs/[override_dir]"
- GLOB.picture_logging_prefix = "O_[override_dir]_"
- GLOB.picture_log_directory = "data/picture_logs/[override_dir]"
GLOB.world_game_log = "[GLOB.log_directory]/game.log"
GLOB.world_asset_log = "[GLOB.log_directory]/asset.log"
@@ -166,6 +158,7 @@ GLOBAL_LIST(topic_status_cache)
GLOB.world_map_error_log = "[GLOB.log_directory]/map_errors.log"
GLOB.world_runtime_log = "[GLOB.log_directory]/runtime.log"
GLOB.tgui_log = "[GLOB.log_directory]/tgui.log"
+ GLOB.world_reagent_log = "[GLOB.log_directory]/reagents.log"
GLOB.subsystem_log = "[GLOB.log_directory]/subsystem.log"
#ifdef UNIT_TESTS
diff --git a/code/modules/cargo/supplypacks/medical.dm b/code/modules/cargo/supplypacks/medical.dm
index 22c5bd8ffe7..c5d1ce98766 100644
--- a/code/modules/cargo/supplypacks/medical.dm
+++ b/code/modules/cargo/supplypacks/medical.dm
@@ -119,7 +119,7 @@
/obj/item/storage/belt/medical,
/obj/item/radio/headset/heads/cmo,
/obj/item/clothing/under/rank/chief_medical_officer,
- /obj/item/reagent_containers/hypospray/vial,
+ /obj/item/storage/hypokit/advanced/cmo,
/obj/item/clothing/accessory/stethoscope,
/obj/item/clothing/glasses/hud/health,
/obj/item/clothing/suit/storage/toggle/labcoat/cmo,
@@ -176,7 +176,8 @@
/obj/item/reagent_containers/dropper,
/obj/item/healthanalyzer,
/obj/item/storage/box/pillbottles,
- /obj/item/reagent_containers/syringe
+ /obj/item/storage/box/syringes,
+ /obj/item/storage/hypokit,
)
cost = 20
container_type = /obj/structure/closet/crate/secure/nanomed
@@ -203,8 +204,8 @@
/obj/item/healthanalyzer,
/obj/item/cartridge/medical,
/obj/item/flashlight/pen,
- /obj/item/reagent_containers/syringe,
- /obj/item/clothing/accessory/storage/white_vest
+ /obj/item/clothing/accessory/storage/white_vest,
+ /obj/item/storage/hypokit,
)
cost = 20
container_type = /obj/structure/closet/crate/secure/nanomed
diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm
index fffdb756b30..26a4d44c245 100644
--- a/code/modules/clothing/gloves/_gloves.dm
+++ b/code/modules/clothing/gloves/_gloves.dm
@@ -68,7 +68,7 @@
if(!istype(I, /obj/item/clothing/gloves))
return FALSE
- if(clothing_flags & THICKMATERIAL)
+ if(clothing_flags & CLOTHING_THICK_MATERIAL)
return FALSE
var/obj/item/clothing/gloves/G = I
@@ -81,7 +81,7 @@
if(!istype(I, /obj/item/clothing/gloves))
return FALSE
- if(clothing_flags & THICKMATERIAL)
+ if(clothing_flags & CLOTHING_THICK_MATERIAL)
return FALSE
var/obj/item/clothing/gloves/G = I
diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm
index dbcc462ce53..20feab1a510 100644
--- a/code/modules/clothing/gloves/miscellaneous.dm
+++ b/code/modules/clothing/gloves/miscellaneous.dm
@@ -133,7 +133,7 @@
icon_state = "knuckledusters"
matter = list("brass" = 500)
attack_verb = list("punched", "beaten", "struck")
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
siemens_coefficient = 1
fingerprint_chance = 100
overgloves = 1
diff --git a/code/modules/clothing/gloves/rings/rings.dm b/code/modules/clothing/gloves/rings/rings.dm
index 99df5ffa840..e56bf23c277 100644
--- a/code/modules/clothing/gloves/rings/rings.dm
+++ b/code/modules/clothing/gloves/rings/rings.dm
@@ -67,7 +67,7 @@
to_chat(H, "You feel a prick as you slip on \the [src].")
if(H.reagents)
var/contained = reagents.get_reagents()
- var/trans = reagents.trans_to_mob(H, 15, CHEM_BLOOD)
+ var/trans = reagents.trans_to_mob(H, 15, CHEM_INJECT)
add_attack_logs(usr, H, "Injected with [name] containing [contained] transferred [trans] units")
return
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index 818c695a115..808e94c4bcd 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -2,9 +2,9 @@
name = "helmet"
desc = "Standard headgear. Protects well enough against a wide range of attacks."
icon_state = "helmet"
+ clothing_flags = CLOTHING_THICK_MATERIAL
valid_accessory_slots = ACCESSORY_SLOT_HELM_C|ACCESSORY_SLOT_HELM_R
restricted_accessory_slots = ACCESSORY_SLOT_HELM_C|ACCESSORY_SLOT_HELM_R
- clothing_flags = THICKMATERIAL
armor_type = /datum/armor/station/medium
inv_hide_flags = HIDEEARS|BLOCKHEADHAIR
cold_protection = HEAD
diff --git a/code/modules/clothing/head/hood.dm b/code/modules/clothing/head/hood.dm
index bede9fc90b7..c0bc7cfdf91 100644
--- a/code/modules/clothing/head/hood.dm
+++ b/code/modules/clothing/head/hood.dm
@@ -130,7 +130,7 @@
name = "explorer hood"
desc = "An armoured hood for exploring harsh environments."
icon_state = "explorer"
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.9
armor_type = /datum/armor/exploration/soft
@@ -140,7 +140,7 @@
desc = "An armoured hood for mining in harsh environments."
icon = 'icons/clothing/suit/mining.dmi'
icon_state = "minehood"
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
worn_render_flags = WORN_RENDER_SLOT_ONE_FOR_ALL
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.9
@@ -151,7 +151,7 @@
name = "eldritch hood"
desc = "A baggy hood smeared with some kind of waxy substance. Up close, what appeared to be burlap is revealed to actually be tanned skin."
icon_state = "eldritch"
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
siemens_coefficient = 0.9
armor_type = /datum/armor/lavaland/eldritch
@@ -234,7 +234,7 @@
icon = 'icons/obj/clothing/spacesuits.dmi'
icon_state = "deathsquad"
armor_type = /datum/armor/station/heavy
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
inv_hide_flags = BLOCKHAIR
siemens_coefficient = 0.7
@@ -245,7 +245,7 @@
icon_state = "helmet"
valid_accessory_slots = (ACCESSORY_SLOT_HELM_C)
restricted_accessory_slots = (ACCESSORY_SLOT_HELM_C)
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
armor_type = /datum/armor/station/medium
siemens_coefficient = 0.7
@@ -256,7 +256,7 @@
icon_state = "helmet"
valid_accessory_slots = (ACCESSORY_SLOT_HELM_C)
restricted_accessory_slots = (ACCESSORY_SLOT_HELM_C)
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
armor_type = /datum/armor/station/medium
siemens_coefficient = 0.7
starting_accessories = list(/obj/item/clothing/accessory/armor/helmcover/navy)
diff --git a/code/modules/clothing/head/pilot_helmet.dm b/code/modules/clothing/head/pilot_helmet.dm
index 512676753ac..b2031fb6d58 100644
--- a/code/modules/clothing/head/pilot_helmet.dm
+++ b/code/modules/clothing/head/pilot_helmet.dm
@@ -5,7 +5,7 @@
desc = "Standard pilot gear. Protects the head from impacts."
icon_state = "pilot_helmet1"
item_icons = list(SLOT_ID_HEAD = 'icons/mob/clothing/pilot_helmet.dmi')
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
armor_type = /datum/armor/exploration/space/pilot
inv_hide_flags = HIDEEARS
cold_protection = HEAD
diff --git a/code/modules/clothing/spacesuits/alien.dm b/code/modules/clothing/spacesuits/alien.dm
index 7689c4b2df4..d5a4de6ec22 100644
--- a/code/modules/clothing/spacesuits/alien.dm
+++ b/code/modules/clothing/spacesuits/alien.dm
@@ -32,7 +32,7 @@
/obj/item/clothing/suit/space/vox
w_class = ITEMSIZE_NORMAL
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
allowed = list(/obj/item/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/melee/baton,/obj/item/melee/energy/sword,/obj/item/handcuffs,/obj/item/tank)
armor_type = /datum/armor/vox/space/armored
siemens_coefficient = 0.2
@@ -44,7 +44,7 @@
armor_type = /datum/armor/vox/space/armored
siemens_coefficient = 0.2
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL | ALLOWINTERNALS
+ clothing_flags = CLOTHING_THICK_MATERIAL | ALLOWINTERNALS
inv_hide_flags = 0
species_restricted = list(SPECIES_VOX)
diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm
index 14b32b2af18..1825aea103b 100644
--- a/code/modules/clothing/spacesuits/miscellaneous.dm
+++ b/code/modules/clothing/spacesuits/miscellaneous.dm
@@ -39,7 +39,7 @@
icon_state = "deathsquad"
item_state_slots = list(SLOT_ID_RIGHT_HAND = "syndicate-helm-black-red", SLOT_ID_LEFT_HAND = "syndicate-helm-black-red")
armor_type = /datum/armor/centcom/deathsquad
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
inv_hide_flags = BLOCKHAIR
siemens_coefficient = 0.6
diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm
index ec2a0ad00d1..df8a64f17e6 100644
--- a/code/modules/clothing/spacesuits/spacesuits.dm
+++ b/code/modules/clothing/spacesuits/spacesuits.dm
@@ -7,7 +7,7 @@
icon_state = "space"
desc = "A special helmet designed for work in a hazardous, low-pressure environment."
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL | ALLOWINTERNALS | ALLOW_SURVIVALFOOD
+ clothing_flags = CLOTHING_THICK_MATERIAL | CLOTHING_INJECTION_PORT | ALLOWINTERNALS | ALLOW_SURVIVALFOOD
permeability_coefficient = 0.01
armor_type = /datum/armor/general/space
inv_hide_flags = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR
@@ -70,7 +70,7 @@
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.02
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL | CLOTHING_INJECTION_PORT
body_cover_flags = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/flashlight,/obj/item/tank/emergency/oxygen,/obj/item/suit_cooling_unit)
slowdown = 1
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index 5d65ac5efcd..dbe25654c5d 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -1,7 +1,7 @@
/obj/item/clothing/suit/armor
allowed = list(/obj/item/gun/ballistic/sec/flash, /obj/item/gun/energy,/obj/item/reagent_containers/spray/pepper,/obj/item/gun/ballistic,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/melee/baton,/obj/item/handcuffs,/obj/item/flashlight/maglight,/obj/item/clothing/head/helmet)
body_cover_flags = UPPER_TORSO|LOWER_TORSO
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
valid_accessory_slots = (\
ACCESSORY_SLOT_OVER\
|ACCESSORY_SLOT_MEDAL\
@@ -138,7 +138,7 @@
item_state_slots = list(SLOT_ID_RIGHT_HAND = "swat", SLOT_ID_LEFT_HAND = "swat")
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
body_cover_flags = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS
allowed = list(/obj/item/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/melee/baton,/obj/item/handcuffs,/obj/item/tank/emergency/oxygen,/obj/item/clothing/head/helmet)
slowdown = 1
@@ -304,7 +304,7 @@
allowed = list(/obj/item/gun,/obj/item/reagent_containers/spray/pepper,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/melee/baton,/obj/item/handcuffs,/obj/item/flashlight/maglight,/obj/item/clothing/head/helmet)
body_cover_flags = UPPER_TORSO|LOWER_TORSO
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
cold_protection = UPPER_TORSO|LOWER_TORSO
min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE
diff --git a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm
index 7a1ada49a0e..58777abcd83 100644
--- a/code/modules/clothing/suits/bio.dm
+++ b/code/modules/clothing/suits/bio.dm
@@ -9,7 +9,7 @@
body_cover_flags = HEAD|FACE|EYES
siemens_coefficient = 0.9
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL | ALLOW_SURVIVALFOOD
+ clothing_flags = CLOTHING_THICK_MATERIAL | ALLOW_SURVIVALFOOD
/obj/item/clothing/suit/bio_suit
name = "bio suit"
@@ -25,7 +25,7 @@
inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER
siemens_coefficient = 0.9
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
//Standard biosuit, orange stripe
/obj/item/clothing/head/bio_hood/general
@@ -103,7 +103,7 @@
body_cover_flags = HEAD|FACE|EYES
siemens_coefficient = 0.9
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL | ALLOW_SURVIVALFOOD
+ clothing_flags = CLOTHING_THICK_MATERIAL | ALLOW_SURVIVALFOOD
/obj/item/clothing/suit/beekeeper
name = "beekeeping suit"
@@ -119,4 +119,4 @@
inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER
siemens_coefficient = 0.9
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
diff --git a/code/modules/clothing/suits/hooded.dm b/code/modules/clothing/suits/hooded.dm
index fc302235a2f..bde0b3b5f05 100644
--- a/code/modules/clothing/suits/hooded.dm
+++ b/code/modules/clothing/suits/hooded.dm
@@ -430,7 +430,7 @@
icon_state = "explorer"
item_state = "explorer"
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
body_cover_flags = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
@@ -456,7 +456,7 @@
icon_state = "miner"
atom_flags = PHORONGUARD
worn_render_flags = WORN_RENDER_SLOT_ONE_FOR_ALL
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
body_cover_flags = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
@@ -482,7 +482,7 @@
name = "eldritch garment"
desc = "A billowing garment that seeps a thick, waxy substance. Upon closer inspection this outfit is crafted out of tanned skin, the ritual icons and spells drawn onto it having been tattooed before removal."
icon_state = "eldritch_armor"
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
inv_hide_flags = HIDEHOLSTER
item_state_slots = list(SLOT_ID_RIGHT_HAND = "brown_jacket", SLOT_ID_LEFT_HAND = "brown_jacket")
action_button_name = "Toggle Eldritch Hood"
diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm
index 5bd57769374..fe85ebfac38 100644
--- a/code/modules/clothing/suits/utility.dm
+++ b/code/modules/clothing/suits/utility.dm
@@ -82,7 +82,7 @@
icon_state = "rad"
desc = "A hood with radiation protective properties. Label: Made with lead, do not eat insulation"
inv_hide_flags = BLOCKHAIR
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
body_cover_flags = HEAD|FACE|EYES
armor_type = /datum/armor/general/radsuit
@@ -98,4 +98,4 @@
slowdown = 1.5
armor_type = /datum/armor/general/radsuit
inv_hide_flags = HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
diff --git a/code/modules/detectivework/tools/rag.dm b/code/modules/detectivework/tools/rag.dm
index 56046b2aeb7..51825b1e590 100644
--- a/code/modules/detectivework/tools/rag.dm
+++ b/code/modules/detectivework/tools/rag.dm
@@ -135,8 +135,8 @@
SPAN_WARNING("You smother [L] with [src]!"),
"You hear some struggling and muffled cries of surprise"
)
- //it's inhaled, so... maybe CHEM_BLOOD doesn't make a whole lot of sense but it's the best we can do for now
- reagents.trans_to_mob(L, amount_per_transfer_from_this, CHEM_BLOOD)
+ //it's inhaled, so... maybe CHEM_INJECT doesn't make a whole lot of sense but it's the best we can do for now
+ reagents.trans_to_mob(L, amount_per_transfer_from_this, CHEM_INJECT)
update_name()
else
to_chat(user, SPAN_WARNING("You can't smother this creature."))
diff --git a/code/modules/examine/descriptions/armor.dm b/code/modules/examine/descriptions/armor.dm
index d7434a032fd..304969d7397 100644
--- a/code/modules/examine/descriptions/armor.dm
+++ b/code/modules/examine/descriptions/armor.dm
@@ -18,7 +18,7 @@
if(max_pressure_protection != null)
armor_stats += "Wearing this will protect you from high pressures.
"
- if(clothing_flags & THICKMATERIAL)
+ if(clothing_flags & CLOTHING_THICK_MATERIAL)
armor_stats += "The material is exceptionally thick.
"
if(max_heat_protection_temperature == FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE)
diff --git a/code/modules/food/glass/bottle.dm b/code/modules/food/glass/bottle.dm
index 2077cff92c7..76736ada995 100644
--- a/code/modules/food/glass/bottle.dm
+++ b/code/modules/food/glass/bottle.dm
@@ -7,6 +7,7 @@
icon = 'icons/obj/medical/chemical.dmi'
icon_state = null
item_state = "atoxinbottle"
+ w_class = WEIGHT_CLASS_SMALL
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,25,30,60)
atom_flags = 0
diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm
index b90c5aa4cdc..1553cfa6920 100644
--- a/code/modules/hydroponics/seed.dm
+++ b/code/modules/hydroponics/seed.dm
@@ -156,7 +156,7 @@
for(var/obj/item/clothing/clothes in target)
if(target.is_holding(clothes))
return
- if(clothes.clothing_flags & THICKMATERIAL)
+ if(clothes.clothing_flags & CLOTHING_THICK_MATERIAL)
body_coverage &= ~(clothes.body_cover_flags)
if(!body_coverage)
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index b8c2ee6715c..7cb1ce93b46 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -297,7 +297,7 @@
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.clothing_flags & THICKMATERIAL && prob(70)) || istype(G, /obj/item/clothing/gloves/gauntlets)))
+ if(istype(G) && ((G.clothing_flags & CLOTHING_THICK_MATERIAL && prob(70)) || istype(G, /obj/item/clothing/gloves/gauntlets)))
burn_user = FALSE
if(burn_user)
diff --git a/code/modules/mob/action_feedback.dm b/code/modules/mob/action_feedback.dm
index 19d5b55a7f2..92c19d3c0d5 100644
--- a/code/modules/mob/action_feedback.dm
+++ b/code/modules/mob/action_feedback.dm
@@ -53,11 +53,17 @@
visible_message(others, self, blind, range)
/**
- * gives feedback for something a mob can innately feel
+ * gives feedback for something a mob can innately feel, body or not.
*/
/mob/proc/innate_feedback(msg)
to_chat(src, msg)
+/**
+ * gives feedback for something a mob can physically feel on their body.
+ */
+/mob/proc/tactile_feedback(msg)
+ to_chat(src, msg)
+
/**
* gives feedback for an ui click
*/
diff --git a/code/modules/mob/inventory/hands.dm b/code/modules/mob/inventory/hands.dm
index c6f1f81b3b3..67c8d278b1d 100644
--- a/code/modules/mob/inventory/hands.dm
+++ b/code/modules/mob/inventory/hands.dm
@@ -1,3 +1,5 @@
+// todo: we need a set of 'core' procs subtypes need to override, and the rest are composites of those procs.
+
/mob/proc/put_in_hands(obj/item/I, flags)
if(is_holding(I))
return TRUE
@@ -169,6 +171,12 @@
/mob/proc/is_holding(obj/item/I)
return !!get_held_index(I)
+/**
+ * returns if we're holding something in inactive hand slots
+ */
+/mob/proc/is_holding_inactive(obj/item/I)
+ return is_holding(I) && (get_active_held_item() != I)
+
/**
* drops all our held items
*
diff --git a/code/modules/mob/living/bot/medibot.dm b/code/modules/mob/living/bot/medibot.dm
index d57139e2a2a..a3167ab0358 100644
--- a/code/modules/mob/living/bot/medibot.dm
+++ b/code/modules/mob/living/bot/medibot.dm
@@ -186,7 +186,7 @@
update_appearance()
if(do_mob(src, victim, 30))
if(t == 1)
- reagent_glass.reagents.trans_to_mob(victim, injection_amount, CHEM_BLOOD)
+ reagent_glass.reagents.trans_to_mob(victim, injection_amount, CHEM_INJECT)
else
victim.reagents.add_reagent(t, injection_amount)
visible_message(SPAN_WARNING("[src] injects [victim] with the syringe!"))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 53b709f4a28..ef95cf34191 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1285,10 +1285,10 @@
else
switch(target_zone)
if(BP_HEAD) //If targeting head, check helmets
- if(head && (head.clothing_flags & THICKMATERIAL) && !ignore_thickness && !istype(head, /obj/item/clothing/head/helmet/space)) //If they're wearing a head piece, if that head piece is thick, the injector doesn't bypass thickness, and that headpiece isn't a space helmet with an injection port - it fails
+ if(head && (head.clothing_flags & CLOTHING_THICK_MATERIAL) && !ignore_thickness && !istype(head, /obj/item/clothing/head/helmet/space)) //If they're wearing a head piece, if that head piece is thick, the injector doesn't bypass thickness, and that headpiece isn't a space helmet with an injection port - it fails
. = 0
else //Otherwise, if not targeting head, check the suit
- if(wear_suit && (wear_suit.clothing_flags & THICKMATERIAL) && !ignore_thickness&& !istype(wear_suit, /obj/item/clothing/suit/space)) //If they're wearing a suit piece, if that suit piece is thick, the injector doesn't bypass thickness, and that suit isn't a space suit with an injection port - it fails
+ if(wear_suit && (wear_suit.clothing_flags & CLOTHING_THICK_MATERIAL) && !ignore_thickness&& !istype(wear_suit, /obj/item/clothing/suit/space)) //If they're wearing a suit piece, if that suit piece is thick, the injector doesn't bypass thickness, and that suit isn't a space suit with an injection port - it fails
. = 0
if(!. && error_msg && user)
if(!fail_msg)
diff --git a/code/modules/organs/internal/subtypes/brain.dm b/code/modules/organs/internal/subtypes/brain.dm
index 7109b0269cd..312f65a176a 100644
--- a/code/modules/organs/internal/subtypes/brain.dm
+++ b/code/modules/organs/internal/subtypes/brain.dm
@@ -277,13 +277,11 @@
name = "Promethean Revival"
id = "prom_revival"
result = null
- required_reagents = list(MAT_PHORON = 40)
+ required_reagents = list(
+ /datum/reagent/toxin/phoron = 40,
+ )
result_amount = 1
-
-/datum/chemical_reaction/promethean_brain_revival/can_happen(datum/reagents/holder)
- if(holder.my_atom && istype(holder.my_atom, /obj/item/organ/internal/brain/slime))
- return ..()
- return FALSE
+ required_container = /obj/item/organ/internal/brain/slime
/datum/chemical_reaction/promethean_brain_revival/on_reaction(datum/reagents/holder)
var/obj/item/organ/internal/brain/slime/brain = holder.my_atom
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index e2a0ba9485b..dc34db77f48 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -125,7 +125,7 @@
if(reagents.total_volume)
if(target.reagents)
var/contained = reagents.get_reagents()
- var/trans = reagents.trans_to_mob(target, 30, CHEM_BLOOD)
+ var/trans = reagents.trans_to_mob(target, 30, CHEM_INJECT)
add_attack_logs(user,target,"Injected with [src.name] containing [contained], trasferred [trans] units")
/*
diff --git a/code/modules/projectiles/guns/launcher/syringe_gun.dm b/code/modules/projectiles/guns/launcher/syringe_gun.dm
index 4c30191b72d..494f5587aa6 100644
--- a/code/modules/projectiles/guns/launcher/syringe_gun.dm
+++ b/code/modules/projectiles/guns/launcher/syringe_gun.dm
@@ -55,7 +55,7 @@
//unfortuately we don't know where the dart will actually hit, since that's done by the parent.
if(L.can_inject() && syringe.reagents)
var/contained = syringe.reagents.get_reagents()
- var/trans = syringe.reagents.trans_to_mob(L, 15, CHEM_BLOOD)
+ var/trans = syringe.reagents.trans_to_mob(L, 15, CHEM_INJECT)
add_attack_logs(TT.thrower,L,"Shot with [src.name] containing [contained], trasferred [trans] units")
syringe.break_syringe(iscarbon(A)? A : null)
diff --git a/code/modules/projectiles/guns/projectile/dartgun.dm b/code/modules/projectiles/guns/projectile/dartgun.dm
index 04d259c011c..29864fe4560 100644
--- a/code/modules/projectiles/guns/projectile/dartgun.dm
+++ b/code/modules/projectiles/guns/projectile/dartgun.dm
@@ -15,7 +15,7 @@
if(blocked < 2 && isliving(target))
var/mob/living/L = target
if(L.can_inject(target_zone=def_zone))
- reagents.trans_to_mob(L, reagent_amount, CHEM_BLOOD)
+ reagents.trans_to_mob(L, reagent_amount, CHEM_INJECT)
/obj/item/ammo_casing/chemdart
name = "chemical dart"
diff --git a/code/modules/reagents/chemistry/_readme.dm b/code/modules/reagents/chemistry/_readme.dm
index 5d07cb8b43d..5572cce78fe 100644
--- a/code/modules/reagents/chemistry/_readme.dm
+++ b/code/modules/reagents/chemistry/_readme.dm
@@ -118,7 +118,7 @@ About the Holder:
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(mob/target, amount = 1, type = CHEM_BLOOD, multiplier = 1, copy = 0)
+ trans_to_mob(mob/target, amount = 1, type = CHEM_INJECT, multiplier = 1, copy = 0)
Transfers [amount] reagents to the mob's appropriate holder, depending on [type]. Ignores protection.
trans_to_turf(turf/target, amount = 1, multiplier = 1, copy = 0)
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 4e3651a471e..c0f9ad14a0e 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -147,7 +147,7 @@
current.volume += amount
if(!isnull(data)) // For all we know, it could be zero or empty string and meaningful
- current.mix_data(data, amount)
+ current.mix_data(src, current.data, current.volume, data, amount)
update_total()
if(!safety)
handle_reactions()
@@ -397,12 +397,12 @@
perm = L.reagent_permeability()
return trans_to_mob(target, amount, CHEM_TOUCH, perm, copy)
-/datum/reagents/proc/trans_to_mob(mob/target, amount = 1, type = CHEM_BLOOD, multiplier = 1, copy = 0) // Transfer after checking into which holder...
+/datum/reagents/proc/trans_to_mob(mob/target, amount = 1, type = CHEM_INJECT, multiplier = 1, 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)
+ if(type == CHEM_INJECT)
var/datum/reagents/R = C.reagents
return trans_to_holder(R, amount, multiplier, copy)
if(type == CHEM_INGEST)
diff --git a/code/modules/reagents/chemistry/metabolism.dm b/code/modules/reagents/chemistry/metabolism.dm
index a6878785735..4de7a6acc4b 100644
--- a/code/modules/reagents/chemistry/metabolism.dm
+++ b/code/modules/reagents/chemistry/metabolism.dm
@@ -1,5 +1,5 @@
/datum/reagents/metabolism
- var/metabolism_class //CHEM_TOUCH, CHEM_INGEST, or CHEM_BLOOD
+ var/metabolism_class //CHEM_TOUCH, CHEM_INGEST, or CHEM_INJECT
var/metabolism_speed = 1 // Multiplicative, 1 is full speed, 0.5 is half, etc.
var/mob/living/carbon/parent
@@ -24,7 +24,7 @@
// "Specialized" metabolism datums
/datum/reagents/metabolism/bloodstream
- metabolism_class = CHEM_BLOOD
+ metabolism_class = CHEM_INJECT
/datum/reagents/metabolism/ingested
metabolism_class = CHEM_INGEST
diff --git a/code/modules/reagents/chemistry/reaction.dm b/code/modules/reagents/chemistry/reaction.dm
index 29ebc9f5cdb..a5b41f0c714 100644
--- a/code/modules/reagents/chemistry/reaction.dm
+++ b/code/modules/reagents/chemistry/reaction.dm
@@ -1,17 +1,30 @@
+/proc/cmp_chemical_reaction_priority(datum/chemical_reaction/A, datum/chemical_reaction/B)
+ return B.priority - A.priority
+
/datum/chemical_reaction
- //? core
+ abstract_type = /datum/chemical_reaction
+ //* core *//
/// id - must be unique and in CamelCase.
var/id
/// reagent reaction flags - see [code/__DEFINES/reagents/flags.dm]
var/chemical_reaction_flags = NONE
+ //* reaction *//
+ /// required reagents as ratios. path or id is supported, prefer paths for compile time checking.
+ var/list/required_reagents = list()
+ /// result reagent path or id. prefer path for compile time checking.
+ var/result
+ /// how much of the result is made per 1 ratio of required_reagents consumed.
+ var/result_amount = 0
+ /// priority - higher is checked first when reacting.
+ var/priority = 0
+ /// required container typepath of holder my_atom
+ var/required_container
+
//? legacy / unsorted
var/name = 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)
@@ -29,7 +42,40 @@
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/New()
+ for(var/i in 1 to length(required_reagents))
+ var/datum/reagent/path = required_reagents[i]
+ if(!ispath(path))
+ continue
+ var/amt = required_reagents[path]
+ var/id = initial(path.id)
+ required_reagents[i] = id
+ required_reagents[id] = amt
+ for(var/i in 1 to length(catalysts))
+ var/datum/reagent/path = catalysts[i]
+ if(!ispath(path))
+ continue
+ var/amt = catalysts[path]
+ var/id = initial(path.id)
+ catalysts[i] = id
+ catalysts[id] = amt
+ for(var/i in 1 to length(inhibitors))
+ var/datum/reagent/path = inhibitors[i]
+ if(!ispath(path))
+ continue
+ var/amt = inhibitors[path]
+ var/id = initial(path.id)
+ inhibitors[i] = id
+ inhibitors[id] = amt
+ if(ispath(result, /datum/reagent))
+ var/datum/reagent/result_initial = result
+ result = initial(result_initial.id)
+
/datum/chemical_reaction/proc/can_happen(datum/reagents/holder)
+ // check container
+ if(!isnull(required_container) && !istype(holder.my_atom, required_container))
+ return FALSE
+
//check that all the required reagents are present
if(!holder.has_all_reagents(required_reagents))
return 0
@@ -124,30 +170,6 @@
//Standard First Aid Medication
-/datum/chemical_reaction/inaprovaline
- //Helps the patient breath in shock, very weak painkiller, and reduces bleeding
- name = "Inaprovaline"
- id = "inaprovaline"
- result = "inaprovaline"
- required_reagents = list("oxygen" = 1, MAT_CARBON = 1, "sugar" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/tricordrazine
- //Heals the four standards slowly
- name = "Tricordrazine"
- id = "tricordrazine"
- result = "tricordrazine"
- required_reagents = list("inaprovaline" = 1, "anti_toxin" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/dylovene
- //Heals toxin
- name = "Dylovene"
- id = "anti_toxin"
- result = "anti_toxin"
- required_reagents = list("silicon" = 1, "potassium" = 1, "nitrogen" = 1)
- result_amount = 3
-
/datum/chemical_reaction/carthatoline
//heals toxin
name = "Carthatoline"
@@ -210,8 +232,6 @@
required_reagents = list("dexalin" = 1, MAT_CARBON = 1, MAT_IRON = 1)
result_amount = 3
-
-
//Painkiller
/datum/chemical_reaction/paracetamol
@@ -256,20 +276,12 @@
//The Daxon Family
-/datum/chemical_reaction/peridaxon
- //Heals all organs
- name = "Peridaxon"
- id = "peridaxon"
- result = "peridaxon"
- required_reagents = list("bicaridine" = 2, "clonexadone" = 2)
- catalysts = list(MAT_PHORON = 5)
- result_amount = 2
-
/datum/chemical_reaction/nanoperidaxon
//Heals ALL organs
name = "Nano-Peridaxon"
id = "nanoperidaxon"
result = "nanoperidaxon"
+ priority = 100
required_reagents = list("peridaxon" = 2, "nifrepairnanites" = 2)
result_amount = 2
@@ -278,6 +290,7 @@
name = "Osteodaxon"
id = "osteodaxon"
result = "osteodaxon"
+ priority = 100
required_reagents = list("bicaridine" = 2, MAT_PHORON = 0.1, "carpotoxin" = 1)
catalysts = list(MAT_PHORON = 5)
inhibitors = list("clonexadone" = 1) // Messes with cryox
@@ -288,6 +301,7 @@
name = "Respirodaxon"
id = "respirodaxon"
result = "respirodaxon"
+ priority = 100
required_reagents = list("dexalinp" = 2, "biomass" = 2, MAT_PHORON = 1)
catalysts = list(MAT_PHORON = 5)
inhibitors = list("dexalin" = 1)
@@ -298,6 +312,7 @@
name = "Gastirodaxon"
id = "gastirodaxon"
result = "gastirodaxon"
+ priority = 100
required_reagents = list("carthatoline" = 1, "biomass" = 2, "tungsten" = 2)
catalysts = list(MAT_PHORON = 5)
inhibitors = list("lithium" = 1)
@@ -308,6 +323,7 @@
name = "Hepanephrodaxon"
id = "hepanephrodaxon"
result = "hepanephrodaxon"
+ priority = 100
required_reagents = list("carthatoline" = 2, "biomass" = 2, "lithium" = 1)
catalysts = list(MAT_PHORON = 5)
inhibitors = list("tungsten" = 1)
@@ -318,6 +334,7 @@
name = "Cordradaxon"
id = "cordradaxon"
result = "cordradaxon"
+ priority = 100
required_reagents = list("potassium_chlorophoride" = 1, "biomass" = 2, "bicaridine" = 2)
catalysts = list(MAT_PHORON = 5)
inhibitors = list("clonexadone" = 1)
diff --git a/code/modules/reagents/chemistry/reagent.dm b/code/modules/reagents/chemistry/reagent.dm
index d3ba6810349..ccb2844468f 100644
--- a/code/modules/reagents/chemistry/reagent.dm
+++ b/code/modules/reagents/chemistry/reagent.dm
@@ -132,7 +132,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
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))
+ if(H.species.has_organ[O_HEART] && (active_metab.metabolism_class == CHEM_INJECT))
var/obj/item/organ/internal/heart/Pump = H.internal_organs_by_name[O_HEART]
// todo: completely optimize + refactor metabolism, none of these checks should be in here
if(mechanical_circulation)
@@ -162,7 +162,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
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(active_metab.metabolism_class == CHEM_INJECT)
if(Pump)
removed *= 1.1 - Pump.damage / Pump.max_damage
else
@@ -201,7 +201,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
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)
+ if(CHEM_INJECT)
affect_blood(M, alien, removed)
if(CHEM_INGEST)
affect_ingest(M, alien, removed * ingest_abs_mult)
@@ -212,13 +212,21 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
remove_self(removed)
return
+// todo: on_mob_life with method of CHEM_INJECT, or tick_mob_blood
/datum/reagent/proc/affect_blood(mob/living/carbon/M, alien, removed)
return
+// todo: on_mob_life with method of CHEM_INGEST, or tick_mob_ingest
/datum/reagent/proc/affect_ingest(mob/living/carbon/M, alien, removed)
M.bloodstr.add_reagent(id, removed)
return
+// todo: on_mob_life with method of CHEM_TOUCH, or tick_mob_touch
+/datum/reagent/proc/affect_touch(mob/living/carbon/M, alien, removed)
+ return
+
+// todo: fourth apply method of CHEM_VAPOR implementation?
+
/datum/reagent/proc/handle_vampire(var/mob/living/carbon/M, var/alien, var/removed, var/is_vampire)
if(blood_content > 0 && is_vampire)
#define blud_warn_timer 3000
@@ -230,9 +238,6 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
return
M.nutrition += removed * blood_content //We should always be able to process real blood.
-/datum/reagent/proc/affect_touch(mob/living/carbon/M, alien, removed)
- return
-
/datum/reagent/proc/overdose(var/mob/living/carbon/M, var/alien, var/removed) // Overdose effect.
if(alien == IS_DIONA)
return
@@ -246,9 +251,6 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
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()
@@ -276,3 +278,60 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
/datum/reagent/proc/on_update(atom/A)
return
+
+/**
+ * called when we first get applied to a mob
+ *
+ * @params
+ * * target - target mob
+ * * holder - the holder on the target mob
+ * * method - an enum of how we're applied from [code/__DEFINES/chemistry.dm]
+ * * amount - how much is being applied
+ * * data - data. not necessarily a list, but casted as one. this is before mix_data is called.
+ *
+ * @return amount to inject into the mob side holder. defaults to amount. this can be overriden by the mob / transfer procs.
+ */
+// todo: implement this proc, replace reaction mob and similar with it.
+// /datum/reagent/proc/apply_to_mob(mob/target, datum/reagents/holder, amount, list/data)
+// return amount
+
+/**
+ * called when we first get sprayed/splashed on a non-mob
+ *
+ * not called if we're transferred into a holder on the obj
+ *
+ * @params
+ * * target - the target.
+ * * amount - how much is being applied
+ * * data - data. not necessarily a list, but casted as one. this is before mix_data is caled.
+ */
+// todo: implement this proc, replace touch_obj/reaction_obj and similar with it.
+// /datum/reagent/proc/apply_to_obj(obj/target, amount, list/data)
+
+/**
+ * called when we first get sprayed/splashed on a turf
+ *
+ * not called if we're transferred into a holder on the turf, somehow
+ *
+ * @params
+ * * target - the target.
+ * * amount - how much is being applied
+ * * data - data. not necessarily a list, but casted as one. this is before mix_data is caled.
+ */
+// todo: implement this proc, replace touch_turf/reaction_turf and similar with it.
+// /datum/reagent/proc/apply_to_turf(turf/target, amount, list/data)
+
+/**
+ * called when a new reagent is being mixed with this one to mix our data lists.
+ *
+ * this may not be called if the data is the exact same!
+ *
+ * @params
+ * * holder - (optional) the holder we're mixing in, if any.
+ * * current_data - our current data. not necessarily a list, only typecasted to one.
+ * * current_amount - our current amount
+ * * new_data - new inbound data. not necessarily a list, only typedcasted to one.
+ * * new_amount - the amount that's coming in, not what we will be at after mixing.
+ */
+/datum/reagent/proc/mix_data(datum/reagents/holder, list/current_data, current_amount, list/new_data, new_amount)
+ return
diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm
new file mode 100644
index 00000000000..e3c8d12e03c
--- /dev/null
+++ b/code/modules/reagents/chemistry/recipes/medicine.dm
@@ -0,0 +1,46 @@
+/datum/chemical_reaction/dylovene
+ name = "Dylovene"
+ id = "anti_toxin"
+ result = /datum/reagent/dylovene
+ required_reagents = list(
+ /datum/reagent/silicon = 1,
+ /datum/reagent/potassium = 1,
+ /datum/reagent/nitrogen = 1,
+ )
+ result_amount = 3
+
+/datum/chemical_reaction/inaprovaline
+ name = "Inaprovaline"
+ id = "inaprovaline"
+ result = /datum/reagent/inaprovaline
+ required_reagents = list(
+ /datum/reagent/oxygen = 1,
+ /datum/reagent/carbon = 1,
+ /datum/reagent/sugar = 1,
+ )
+ result_amount = 3
+ priority = 50
+
+/datum/chemical_reaction/tricordrazine
+ name = "Tricordrazine"
+ id = "tricordrazine"
+ result = /datum/reagent/tricordrazine
+ required_reagents = list(
+ /datum/reagent/inaprovaline = 1,
+ /datum/reagent/dylovene = 1,
+ )
+ result_amount = 2
+
+/datum/chemical_reaction/peridaxon
+ name = "Peridaxon"
+ id = "peridaxon"
+ result = /datum/reagent/peridaxon
+ required_reagents = list(
+ /datum/reagent/bicaridine = 2,
+ /datum/reagent/clonexadone = 2,
+ )
+ catalysts = list(
+ /datum/reagent/toxin/phoron = 5,
+ )
+ result_amount = 2
+ priority = 100
diff --git a/code/modules/reagents/items/hypospray.dm b/code/modules/reagents/items/hypospray.dm
new file mode 100644
index 00000000000..1af01a93897
--- /dev/null
+++ b/code/modules/reagents/items/hypospray.dm
@@ -0,0 +1,243 @@
+/obj/item/hypospray
+ name = "hypospray"
+ desc = "A standard issue prototype hypospray that allows for the quick, sterile application of medications both dermally and directly to the bloodstream."
+ description_fluff = "While technically still a prototype due to its unique two-mode applicator, this model - and others like it - have been floating around space for almost a century.\n \
+ Hardened, low-power electronics allow for it to optimize an injection sequence when the trigger is pulled on the fly, avoiding the need to directly aim for a vein - though a skilled user still tends to have faster operation cycles by far.\n \
+ Initially developed in a joint venture between Nanotrasen and Vey-Med, the designs quickly proliferated due to their immense usefulness - and were subsequently leaked. \
+ Nowadays, one can expect this model to be on all but the most backwater colonies and installations."
+ icon = 'icons/modules/reagents/items/hypospray.dmi'
+ icon_state = "hypo"
+ inhand_state = "hypo"
+ w_class = WEIGHT_CLASS_SMALL
+ drop_sound = 'sound/items/drop/gun.ogg'
+ pickup_sound = 'sound/items/pickup/gun.ogg'
+ worn_render_flags = NONE
+
+ /// loaded vial
+ var/obj/item/reagent_containers/glass/hypovial/loaded
+ /// allow large vials
+ var/allow_large = FALSE
+ /// standard injection delay
+ var/injection_time = 1 SECONDS
+ /// delay add if person is resisting. null to disallow inject.
+ var/resist_add_time = 2 SECONDS
+ /// delay add to injection port items (like hardsuits). null to disallow inject. overriden by thick_add_time.
+ var/port_add_time = 1 SECONDS
+ /// delay add to thickmaterial suits. null to disallow inject. overrides port_add_time.
+ var/thick_add_time = null
+ /// injection amount
+ var/inject_amount = 5
+ /// max injection level
+ var/inject_max = 10
+ /// injection mode
+ var/inject_mode = HYPOSPRAY_MODE_INJECT
+ /// can people change how much to inject?
+ var/inject_adjustable = TRUE
+
+/obj/item/hypospray/Initialize(mapload)
+ . = ..()
+ if(ispath(loaded))
+ loaded = new loaded(src)
+ update_icon()
+
+/obj/item/hypospray/examine(mob/user)
+ . = ..()
+ if(get_dist(get_turf(src), user) <= 1)
+ if(!isnull(loaded))
+ . += SPAN_NOTICE("Its vial has [loaded.reagents.total_volume] units remaining.")
+ else
+ . += SPAN_NOTICE("It's unloaded.")
+
+/obj/item/hypospray/update_icon_state()
+ var/vial_state
+ if(!isnull(loaded))
+ if(istype(loaded, /obj/item/reagent_containers/glass/hypovial/bluespace))
+ vial_state = "-l-bs"
+ else
+ vial_state = "-l"
+ icon_state = "[initial(icon_state)][vial_state]"
+ return ..()
+
+/obj/item/hypospray/attack_hand(mob/user, list/params)
+ if(user.is_holding_inactive(src))
+ if(isnull(loaded))
+ user.action_feedback(SPAN_WARNING("[src] has no vial loaded."), src)
+ return CLICKCHAIN_DO_NOT_PROPAGATE
+ user.put_in_hands_or_drop(loaded)
+ user.action_feedback(SPAN_NOTICE("You remove [loaded] from [src]."), src)
+ loaded = null
+ playsound(src, 'sound/weapons/empty.ogg', 50, FALSE)
+ update_icon()
+ return CLICKCHAIN_DO_NOT_PROPAGATE | CLICKCHAIN_DID_SOMETHING
+ return ..()
+
+/obj/item/hypospray/attackby(obj/item/I, mob/living/user, list/params, clickchain_flags, damage_multiplier)
+ if(istype(I, /obj/item/reagent_containers/glass/hypovial))
+ var/obj/item/reagent_containers/glass/hypovial/vial = I
+ if(!user.transfer_item_to_loc(vial, src))
+ user.action_feedback(SPAN_WARNING("[vial] is stuck to your hand!"), src)
+ return CLICKCHAIN_DO_NOT_PROPAGATE
+ var/obj/item/reagent_containers/glass/hypovial/old_vial = loaded
+ loaded = vial
+ if(!isnull(old_vial))
+ user.action_feedback(SPAN_NOTICE("You quickly swap [old_vial] with [vial]."), src)
+ user.put_in_hands_or_drop(old_vial)
+ else
+ user.action_feedback(SPAN_NOTICE("You insert [vial] into [src]."), src)
+ playsound(src, 'sound/weapons/autoguninsert.ogg', 50, FALSE)
+ update_icon()
+ return CLICKCHAIN_DO_NOT_PROPAGATE | CLICKCHAIN_DID_SOMETHING
+ return ..()
+
+// todo: alt click context radials?
+/obj/item/hypospray/verb/set_transfer_amount()
+ set name = "Set Injection Amount"
+ set category = "Object"
+
+ if(!inject_adjustable)
+ usr.action_feedback(SPAN_WARNING("[src] can't have its injection thresholds changed."), src)
+ return
+ var/amount = input(usr, "Set how much you want to inject per use.", "Injection Amount", inject_amount) as num|null
+ if(isnull(amount))
+ return
+ amount = round(amount, 1)
+ amount = clamp(amount, 1, inject_max)
+ inject_amount = amount
+ usr.action_feedback(SPAN_NOTICE("[src] is now set to inject [amount] per use."), src)
+
+/obj/item/hypospray/attack_self(mob/user)
+ switch(inject_mode)
+ if(HYPOSPRAY_MODE_INJECT)
+ inject_mode = HYPOSPRAY_MODE_SPRAY
+ if(HYPOSPRAY_MODE_SPRAY)
+ inject_mode = HYPOSPRAY_MODE_INJECT
+ switch(inject_mode)
+ if(HYPOSPRAY_MODE_INJECT)
+ user.action_feedback(SPAN_NOTICE("[src] is now set to subdermal injection."), src)
+ if(HYPOSPRAY_MODE_SPRAY)
+ user.action_feedback(SPAN_NOTICE("[src] is now set to surface spray."), src)
+ playsound(src, 'sound/effects/pop.ogg', 50, 0)
+
+// todo: alt click context radials?
+/obj/item/hypospray/AltClick(mob/user)
+ if(!inject_adjustable)
+ user.action_feedback(SPAN_WARNING("[src] can't have its injection thresholds changed."), src)
+ return
+ inject_amount = (inject_amount + 5 > inject_max)? min(5, inject_max) : inject_amount + 5
+ user.action_feedback(SPAN_NOTICE("[src] is now set to inject [inject_amount] per use."), src)
+
+/obj/item/hypospray/attack_mob(mob/target, mob/user, clickchain_flags, list/params, mult, target_zone, intent)
+ if(injection_checks(target, user, target_zone))
+ do_inject(target, user)
+ return CLICKCHAIN_DID_SOMETHING | CLICKCHAIN_DO_NOT_PROPAGATE
+ return CLICKCHAIN_DO_NOT_PROPAGATE
+
+/obj/item/hypospray/proc/injection_checks(mob/target, mob/user, target_zone, speed_mult = 1, silent = FALSE)
+ // todo: legacy cast, get organ/etc should be on mob level maybe.
+ var/mob/living/L = target
+ if(!istype(L))
+ user.action_feedback(SPAN_WARNING("[target] isn't injectable."), src)
+ return FALSE
+ if(!loaded?.reagents?.total_volume)
+ user.action_feedback(SPAN_WARNING("[src]'s vial is empty."), src)
+ return FALSE
+ var/obj/item/organ/external/limb = L.get_organ(target_zone || BP_HEAD)
+ if(isnull(limb))
+ user.action_feedback(SPAN_WARNING("[target] doesn't have that limb."), src)
+ return FALSE
+ var/inject_verb
+ var/inject_message
+ switch(inject_mode)
+ if(HYPOSPRAY_MODE_INJECT)
+ inject_verb = "inject"
+ if(HYPOSPRAY_MODE_SPRAY)
+ inject_verb = "spray"
+ inject_message = "[user] starts to [inject_verb] [target] with \the [src]."
+ var/block_flags = NONE
+ for(var/obj/item/I as anything in target.inventory.items_that_cover(limb.body_part_flags))
+ block_flags |= (I.clothing_flags & (CLOTHING_THICK_MATERIAL | CLOTHING_INJECTION_PORT))
+ // got all coverage, proceed.
+ var/delay = injection_time
+ if(block_flags & CLOTHING_THICK_MATERIAL)
+ if(isnull(thick_add_time))
+ user.action_feedback(SPAN_WARNING("[src] can't [inject_verb] through something that thick!"), src)
+ return FALSE
+ delay += thick_add_time
+ // todo: 'friendly name' so limbs can stay concealed of their true names while under clothing?
+ inject_message = SPAN_WARNING("[user] starts to dig [src] up against [target]'s [limb]!")
+ else if(block_flags & CLOTHING_INJECTION_PORT)
+ if(isnull(thick_add_time))
+ user.action_feedback(SPAN_WARNING("[src] is not compatible with injection ports!"), src)
+ return FALSE
+ delay += port_add_time
+ // todo: 'friendly name' so limbs can stay concealed of their true names while under clothing?
+ inject_message = SPAN_NOTICE("[user] starts to search for an injection port on [target]'s [limb].")
+ if(target.a_intent != INTENT_HELP)
+ if(isnull(resist_add_time))
+ user.action_feedback(SPAN_WARNING("[src] is not capable of aligning while [target] is resisting! (Non-help intent)"), src)
+ return FALSE
+ delay += resist_add_time
+ // todo: 'friendly name' so limbs can stay concealed of their true names while under clothing?
+ inject_message = SPAN_WARNING("[user] starts to intrusively align [src] up against [target]'s [limb]!")
+ if(!silent)
+ user.visible_action_feedback(inject_message, target, MESSAGE_RANGE_COMBAT_SUPPRESSED)
+ if(!do_after(user, delay, target, mobility_flags = MOBILITY_CAN_USE))
+ return FALSE
+ if(!loaded?.reagents?.total_volume)
+ return FALSE
+ return TRUE
+
+/obj/item/hypospray/proc/do_inject(mob/target, mob/user, mode = inject_mode, silent = FALSE)
+ if(!loaded.reagents.total_volume)
+ return
+ var/logstr = "[inject_amount] of [loaded.reagents.log_list()]"
+ if(user)
+ add_attack_logs(user, target, "injected with [logstr]")
+ log_reagent("hypospray: [user] -> [target] using [mode]: [logstr]")
+ var/where_str
+ switch(mode)
+ if(HYPOSPRAY_MODE_INJECT)
+ loaded.reagents.trans_to_mob(target, inject_amount, CHEM_INJECT)
+ where_str = "rushing into your veins"
+ if(HYPOSPRAY_MODE_SPRAY)
+ loaded.reagents.trans_to_mob(target, inject_amount, CHEM_TOUCH)
+ where_str = "on your skin"
+ playsound(src, 'sound/items/hypospray2.ogg', 50, TRUE, -1)
+ target.tactile_feedback(SPAN_WARNING("You feel a tiny prick, and a cool sensation [where_str]."))
+ if(!isnull(user))
+ user.action_feedback("You inject [target] with [src]. [loaded.reagents.total_volume] units remaining.", src)
+
+/obj/item/hypospray/loaded
+ loaded = /obj/item/reagent_containers/glass/hypovial/tricordrazine
+
+/obj/item/hypospray/advanced
+ name = "advanced hypospray"
+ desc = "An upgraded hypospray with faster injection protocols. Supports large vials."
+ icon_state = "hypo-cmo"
+ allow_large = TRUE
+ injection_time = 0.5 SECONDS
+ resist_add_time = 1 SECONDS
+ port_add_time = 0.5 SECONDS
+
+/obj/item/hypospray/advanced/loaded
+ loaded = /obj/item/reagent_containers/glass/hypovial/large/tricordrazine
+
+/obj/item/hypospray/advanced/cmo
+ port_add_time = 0 SECONDS
+
+/obj/item/hypospray/advanced/cmo/loaded
+ loaded = /obj/item/reagent_containers/glass/hypovial/large/tricordrazine
+
+/obj/item/hypospray/combat
+ name = "combat hypospray"
+ desc = "An upgraded variant of the regular hypospray, this one sports quickened injection - allowing for the faster incapacitation of vic- er, medication of allies. Supports large vials."
+ icon_state = "hypo-combat"
+ inhand_state = "hypo-combat"
+ allow_large = TRUE
+ injection_time = 0.5 SECONDS
+ resist_add_time = 1 SECONDS
+ port_add_time = 0.5 SECONDS
+ thick_add_time = 3 SECONDS
+
+/obj/item/hypospray/combat/loaded
+ loaded = /obj/item/reagent_containers/glass/hypovial/large/tricordrazine
diff --git a/code/modules/reagents/items/hypovial.dm b/code/modules/reagents/items/hypovial.dm
new file mode 100644
index 00000000000..7a2edc1a0d8
--- /dev/null
+++ b/code/modules/reagents/items/hypovial.dm
@@ -0,0 +1,118 @@
+
+/obj/item/reagent_containers/glass/hypovial
+ name = "hypospray vial"
+ desc = "A standard issue vial used for hyposprays."
+ icon = 'icons/modules/reagents/items/hypospray.dmi'
+ icon_state = "vial"
+ w_class = WEIGHT_CLASS_TINY // 14 fits in a box, not 7
+ volume = 60
+ start_rename = TRUE
+ /// how many [state][#] overlays we have for reagents remaining
+ var/overlay_count = 3
+
+/obj/item/reagent_containers/glass/hypovial/update_icon(updates)
+ cut_overlays()
+ . = ..()
+ if(overlay_count)
+ var/num = clamp(round((reagents.total_volume / reagents.maximum_volume) * overlay_count, 1), 0, overlay_count)
+ if(num)
+ var/mutable_appearance/overlay = mutable_appearance(icon, "[icon_state][num]")
+ overlay.color = reagents.get_color()
+ add_overlay(overlay)
+
+/obj/item/reagent_containers/glass/hypovial/large
+ name = "large hypospray vial"
+ desc = "A larger variant of the common hypospray vial. Only compatible with advanced units."
+ icon_state = "vial-l"
+ w_class = WEIGHT_CLASS_SMALL
+ volume = 120
+ overlay_count = 4
+
+/obj/item/reagent_containers/glass/hypovial/bluespace
+ name = "bluespace hypospray vial"
+ desc = "A prototype hypospray vial with the ability to hold reagents in a quasi-compressed state."
+ icon_state = "vial-bs"
+ volume = 120
+ overlay_count = 0
+
+//* subtypes - regular
+
+/obj/item/reagent_containers/glass/hypovial/bicaridine
+ start_reagent = /datum/reagent/bicaridine
+
+/obj/item/reagent_containers/glass/hypovial/kelotane
+ start_reagent = /datum/reagent/kelotane
+
+/obj/item/reagent_containers/glass/hypovial/dylovene
+ start_reagent = /datum/reagent/dylovene
+
+/obj/item/reagent_containers/glass/hypovial/dexalin
+ start_reagent = /datum/reagent/dexalin
+
+/obj/item/reagent_containers/glass/hypovial/tricordrazine
+ start_reagent = /datum/reagent/tricordrazine
+
+/obj/item/reagent_containers/glass/hypovial/peridaxon
+ start_reagent = /datum/reagent/peridaxon
+
+/obj/item/reagent_containers/glass/hypovial/tramadol
+ start_reagent = /datum/reagent/tramadol
+
+/obj/item/reagent_containers/glass/hypovial/inaprovaline
+ start_reagent = /datum/reagent/inaprovaline
+
+/obj/item/reagent_containers/glass/hypovial/imidalky
+ start_with = list(
+ /datum/reagent/imidazoline = 30,
+ /datum/reagent/alkysine = 30,
+ )
+
+/obj/item/reagent_containers/glass/hypovial/arithrazine
+ start_reagent = /datum/reagent/arithrazine
+
+/obj/item/reagent_containers/glass/hypovial/spaceacillin
+ start_reagent = /datum/reagent/spaceacillin
+
+/obj/item/reagent_containers/glass/hypovial/dexalin_plus
+ start_reagent = /datum/reagent/dexalinp
+
+//* subtypes - large
+
+/obj/item/reagent_containers/glass/hypovial/large/bicaridine
+ start_reagent = /datum/reagent/bicaridine
+
+/obj/item/reagent_containers/glass/hypovial/large/kelotane
+ start_reagent = /datum/reagent/kelotane
+
+/obj/item/reagent_containers/glass/hypovial/large/dylovene
+ start_reagent = /datum/reagent/dylovene
+
+/obj/item/reagent_containers/glass/hypovial/large/dexalin
+ start_reagent = /datum/reagent/dexalin
+
+/obj/item/reagent_containers/glass/hypovial/large/tricordrazine
+ start_reagent = /datum/reagent/tricordrazine
+
+/obj/item/reagent_containers/glass/hypovial/large/peridaxon
+ start_reagent = /datum/reagent/peridaxon
+
+/obj/item/reagent_containers/glass/hypovial/large/tramadol
+ start_reagent = /datum/reagent/tramadol
+
+/obj/item/reagent_containers/glass/hypovial/large/inaprovaline
+ start_reagent = /datum/reagent/inaprovaline
+
+/obj/item/reagent_containers/glass/hypovial/large/imidalky
+ start_with = list(
+ /datum/reagent/imidazoline = 30,
+ /datum/reagent/alkysine = 30,
+ )
+
+/obj/item/reagent_containers/glass/hypovial/large/arithrazine
+ start_reagent = /datum/reagent/arithrazine
+
+/obj/item/reagent_containers/glass/hypovial/large/spaceacillin
+ start_reagent = /datum/reagent/spaceacillin
+
+/obj/item/reagent_containers/glass/hypovial/large/dexalin_plus
+ start_reagent = /datum/reagent/dexalinp
diff --git a/code/modules/reagents/machinery/chem_master.dm b/code/modules/reagents/machinery/chem_master.dm
index ddf1025ed9b..bf6379db1b9 100644
--- a/code/modules/reagents/machinery/chem_master.dm
+++ b/code/modules/reagents/machinery/chem_master.dm
@@ -1,7 +1,8 @@
//TODO: We don't have check_reactions or something like it, so we can't prevent idiot transfers. @Zandario
+// todo: this is horrifying and needs refactored. ESPECIALLY ITS TGUI. ~silicons
/obj/machinery/chem_master
name = "ChemMaster 3000"
- desc = "Used to seperate and package chemicals in to autoinjectors, lollipops, patches, pills, or bottles. Warranty void if used to create Space Drugs."
+ desc = "Used to seperate and package chemicals in to autoinjectors, patches, pills, or bottles. Warranty void if used to create Space Drugs."
density = TRUE
anchored = TRUE
icon = 'icons/obj/medical/chemical.dmi'
@@ -19,10 +20,8 @@
var/obj/item/storage/pill_bottle/pill_bottle = null
var/useramount = 15 // Last used amount
var/pillamount = 10
- var/lolliamount = 5
var/autoamount = 5
var/max_pill_count = 20
- var/max_lolli_count = 10
var/max_auto_count = 5
var/printing = FALSE
var/autosprite = TRUE
@@ -361,6 +360,8 @@
else
style = styles[chosen_condi_style]
vol_each_max = min(50, vol_each_max)
+ else if(item_type == "hypovial")
+ vol_each_max = min(vol_each_max, 60)
else
return FALSE
if(vol_each_text == "auto")
@@ -393,6 +394,9 @@
return FALSE
//! Start filling
+ var/atom/where = drop_location()
+ name = trim(name)
+
if(item_type == "pill")
var/obj/item/reagent_containers/pill/P
var/target_loc = drop_location()
@@ -448,6 +452,15 @@
reagents.trans_to_obj(P, vol_each,/* transfered_by = usr*/)
return TRUE
+ if(item_type == "hypovial")
+ var/obj/item/reagent_containers/glass/hypovial/P
+ for(var/i in 1 to amount)
+ P = new(where)
+ P.name = "[initial(P.name)] ([name])"
+ P.renamed_by_player = TRUE
+ reagents.trans_to_obj(P, vol_each)
+ return TRUE
+
// if(item_type == "condiment_pack")
// var/obj/item/reagent_containers/condiment/pack/P
// for(var/i in 1 to amount)
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 7901aa80a2d..cba898a73b2 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -4,9 +4,34 @@
icon = 'icons/obj/medical/chemical.dmi'
icon_state = null
w_class = ITEMSIZE_SMALL
+
+ /// start reagent list. overrides reagent/volume. list(id = volume); volume must be specified.
+ var/list/start_with
+ /// start reagent id or path
+ var/start_reagent
+ /// start reagent amount. null for max.
+ var/start_volume
+ /// volume of our default reagents holder
+ var/volume = 30
+ /// automatically rename to [[start_reagent]]
+ var/start_rename = FALSE
+
var/amount_per_transfer_from_this = 5
var/possible_transfer_amounts = list(5,10,15,25,30)
- var/volume = 30
+
+/obj/item/reagent_containers/Initialize(mapload)
+ . = ..()
+ if(!possible_transfer_amounts)
+ remove_obj_verb(src, /obj/item/reagent_containers/verb/set_APTFT)
+ create_reagents(volume)
+ if(!isnull(start_with))
+ for(var/id in start_with)
+ reagents.add_reagent(id, start_with[id])
+ else if(!isnull(start_reagent))
+ reagents.add_reagent(start_reagent, isnull(start_volume)? volume : start_volume)
+ if(start_rename)
+ var/datum/reagent/R = start_reagent
+ name = "[name] ([initial(R.name)])"
/obj/item/reagent_containers/verb/set_APTFT() //set amount_per_transfer_from_this
set name = "Set transfer amount"
@@ -16,12 +41,6 @@
if(N)
amount_per_transfer_from_this = N
-/obj/item/reagent_containers/Initialize(mapload)
- . = ..()
- if(!possible_transfer_amounts)
- remove_obj_verb(src, /obj/item/reagent_containers/verb/set_APTFT)
- create_reagents(volume)
-
/obj/item/reagent_containers/attack_self(mob/user)
. = ..()
if(.)
diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm
index 491bf949c33..c4b971787a3 100644
--- a/code/modules/reagents/reagent_containers/dropper.dm
+++ b/code/modules/reagents/reagent_containers/dropper.dm
@@ -68,7 +68,7 @@
add_attack_logs(user,target,"Used [src.name] containing [contained]")
trans += reagents.trans_to_mob(target, min(amount_per_transfer_from_this, reagents.total_volume)/2, CHEM_INGEST) //Half injected, half ingested
- trans += reagents.trans_to_mob(target, min(amount_per_transfer_from_this, reagents.total_volume), CHEM_BLOOD) //I guess it gets into the bloodstream through the eyes or something
+ trans += reagents.trans_to_mob(target, min(amount_per_transfer_from_this, reagents.total_volume), CHEM_INJECT) //I guess it gets into the bloodstream through the eyes or something
user.visible_message("[user] squirts something into [target]'s eyes!", "You transfer [trans] units of the solution.")
return
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index 6a1041b472c..6b410e7b4c2 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -140,6 +140,10 @@
name = "[base_name] ([label_text])"
desc = "[base_desc] It is labeled \"[label_text]\"."
+/obj/item/reagent_containers/glass/on_reagent_change()
+ . = ..()
+ update_icon()
+
/obj/item/reagent_containers/glass/beaker
name = "beaker"
desc = "A beaker."
@@ -147,6 +151,7 @@
icon_state = "beaker"
base_icon_state = "beaker"
item_state = "beaker"
+ w_class = WEIGHT_CLASS_TINY
matter = list(MAT_GLASS = 500)
drop_sound = 'sound/items/drop/glass.ogg'
pickup_sound = 'sound/items/pickup/glass.ogg'
@@ -155,9 +160,6 @@
. = ..()
desc += " Can hold up to [volume] units."
-/obj/item/reagent_containers/glass/beaker/on_reagent_change()
- update_icon()
-
/obj/item/reagent_containers/glass/beaker/pickup(mob/user, flags, atom/oldLoc)
. = ..()
update_icon()
@@ -201,6 +203,7 @@
desc = "A large beaker."
icon_state = "beakerlarge"
base_icon_state = "beakerlarge"
+ w_class = WEIGHT_CLASS_SMALL
matter = list(MAT_GLASS = 1000)
volume = 120
amount_per_transfer_from_this = 10
@@ -212,6 +215,7 @@
desc = "A cryostasis beaker that allows for chemical storage without reactions."
icon_state = "beakernoreact"
base_icon_state = "beakernoreact"
+ w_class = WEIGHT_CLASS_SMALL
matter = list(MAT_GLASS = 500)
volume = 60
amount_per_transfer_from_this = 10
@@ -222,6 +226,7 @@
desc = "A bluespace beaker, powered by experimental bluespace technology."
icon_state = "beakerbluespace"
base_icon_state = "beakerbluespace"
+ w_class = WEIGHT_CLASS_SMALL
matter = list(MAT_GLASS = 5000)
volume = 300
amount_per_transfer_from_this = 10
diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm
index 18c8b6c4167..647017af01f 100644
--- a/code/modules/reagents/reagent_containers/hypospray.dm
+++ b/code/modules/reagents/reagent_containers/hypospray.dm
@@ -75,7 +75,7 @@
if(H.reagents)
var/contained = reagentlist()
- var/trans = reagents.trans_to_mob(H, amount_per_transfer_from_this, CHEM_BLOOD)
+ var/trans = reagents.trans_to_mob(H, amount_per_transfer_from_this, CHEM_INJECT)
add_attack_logs(user,H,"Injected with [src.name] containing [contained], trasferred [trans] units")
to_chat(user, SPAN_NOTICE("[trans] units injected. [reagents.total_volume] units remaining in \the [src]."))
return TRUE
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 61b123d5e02..d68e68da638 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -208,7 +208,7 @@
var/contained = reagentlist()
if(ismob(target))
while(reagents.total_volume)
- trans += reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_BLOOD)
+ trans += reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_INJECT)
update_icon()
if(!reagents.total_volume || !do_after(user,cycle_time,target))
break
@@ -267,7 +267,7 @@
var/syringestab_amount_transferred = rand(0, (reagents.total_volume - 5)) //nerfed by popular demand
var/contained = reagents.get_reagents()
- var/trans = reagents.trans_to_mob(target, syringestab_amount_transferred, CHEM_BLOOD)
+ var/trans = reagents.trans_to_mob(target, syringestab_amount_transferred, CHEM_INJECT)
if(isnull(trans)) trans = 0
add_attack_logs(user,target,"Stabbed with [src.name] containing [contained], trasferred [trans] units")
break_syringe(target, user)
diff --git a/code/modules/research/designs/medical.dm b/code/modules/research/designs/medical.dm
index e744c9f8527..85195c01c45 100644
--- a/code/modules/research/designs/medical.dm
+++ b/code/modules/research/designs/medical.dm
@@ -148,12 +148,12 @@
// sort_string = "KCAVA"
/datum/design/item/medical/protohypospray
- name = "prototype hypospray"
+ name = "advanced hypospray"
desc = "This prototype hypospray is a sterile, air-needle autoinjector for rapid administration of drugs to patients."
id = "protohypospray"
req_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 3, TECH_POWER = 2, TECH_BIO = 4, TECH_ILLEGAL = 2)
materials = list(MAT_STEEL = 500, MAT_GLASS = 1500, MAT_SILVER = 2000, MAT_GOLD = 1500, MAT_URANIUM = 1000)
- build_path = /obj/item/reagent_containers/hypospray/science
+ build_path = /obj/item/hypospray/advanced
sort_string = "KCAVB"
// ML-3M medigun and cells
diff --git a/code/modules/rigsuits/pieces.dm b/code/modules/rigsuits/pieces.dm
index 3fd46e6ea65..6615b424065 100644
--- a/code/modules/rigsuits/pieces.dm
+++ b/code/modules/rigsuits/pieces.dm
@@ -17,7 +17,7 @@
/obj/item/clothing/head/hardsuit
name = "helmet"
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL | ALLOW_SURVIVALFOOD | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB | ALLOWINTERNALS
+ clothing_flags = CLOTHING_THICK_MATERIAL | CLOTHING_INJECTION_PORT | ALLOW_SURVIVALFOOD | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB | ALLOWINTERNALS
inv_hide_flags = HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR
body_cover_flags = HEAD|FACE|EYES
heat_protection = HEAD|FACE|EYES
@@ -52,7 +52,7 @@
//Flags
body_cover_flags = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
- clothing_flags = THICKMATERIAL | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
+ clothing_flags = CLOTHING_THICK_MATERIAL | CLOTHING_INJECTION_PORT | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
atom_flags = PHORONGUARD
inv_hide_flags = HIDEJUMPSUIT|HIDETAIL
@@ -110,7 +110,7 @@
/obj/item/clothing/gloves/hardsuit
name = "gauntlets"
- clothing_flags = THICKMATERIAL | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
+ clothing_flags = CLOTHING_THICK_MATERIAL | CLOTHING_INJECTION_PORT | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
atom_flags = PHORONGUARD
body_cover_flags = HANDS
heat_protection = HANDS
@@ -153,7 +153,7 @@
/obj/item/clothing/shoes/hardsuit
name = "boots"
atom_flags = PHORONGUARD
- clothing_flags = CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
+ clothing_flags = CLOTHING_IGNORE_BELTLINK | CLOTHING_INJECTION_PORT | CLOTHING_THICK_MATERIAL | CLOTHING_IGNORE_DELIMB
body_cover_flags = FEET
cold_protection = FEET
heat_protection = FEET
diff --git a/code/modules/rigsuits/rig_pieces.dm b/code/modules/rigsuits/rig_pieces.dm
index 0ea9613f0f0..f06fd025829 100644
--- a/code/modules/rigsuits/rig_pieces.dm
+++ b/code/modules/rigsuits/rig_pieces.dm
@@ -5,7 +5,7 @@
/obj/item/clothing/head/helmet/space/hardsuit
name = "helmet"
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL | ALLOW_SURVIVALFOOD | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB | ALLOWINTERNALS
+ clothing_flags = CLOTHING_THICK_MATERIAL | ALLOW_SURVIVALFOOD | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB | ALLOWINTERNALS
inv_hide_flags = HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR
body_cover_flags = HEAD|FACE|EYES
heat_protection = HEAD|FACE|EYES
@@ -44,7 +44,7 @@
/obj/item/clothing/gloves/gauntlets/hardsuit
name = "gauntlets"
- clothing_flags = THICKMATERIAL | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
+ clothing_flags = CLOTHING_THICK_MATERIAL | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
atom_flags = PHORONGUARD
body_cover_flags = HANDS
heat_protection = HANDS
@@ -119,7 +119,7 @@
//Flags
body_cover_flags = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
- clothing_flags = THICKMATERIAL | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
+ clothing_flags = CLOTHING_THICK_MATERIAL | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
atom_flags = PHORONGUARD
inv_hide_flags = HIDEJUMPSUIT|HIDETAIL
@@ -215,7 +215,7 @@
/obj/item/clothing/head/lightrig
name = "mask"
- clothing_flags = THICKMATERIAL | ALLOWINTERNALS | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
+ clothing_flags = CLOTHING_THICK_MATERIAL | ALLOWINTERNALS | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
atom_flags = PHORONGUARD
body_cover_flags = HEAD|FACE|EYES
heat_protection = HEAD|FACE|EYES
@@ -225,7 +225,7 @@
name = "suit"
allowed = list(/obj/item/flashlight)
inv_hide_flags = HIDEJUMPSUIT
- clothing_flags = THICKMATERIAL | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
+ clothing_flags = CLOTHING_THICK_MATERIAL | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
atom_flags = PHORONGUARD
body_cover_flags = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
@@ -242,7 +242,7 @@
/obj/item/clothing/gloves/gauntlets/lightrig
name = "gloves"
- clothing_flags = THICKMATERIAL | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
+ clothing_flags = CLOTHING_THICK_MATERIAL | CLOTHING_IGNORE_BELTLINK | CLOTHING_IGNORE_DELIMB
atom_flags = PHORONGUARD
species_restricted = null
body_cover_flags = HANDS
diff --git a/code/modules/rigsuits/suits/light.dm b/code/modules/rigsuits/suits/light.dm
index 2ecd0468827..da0613ba826 100644
--- a/code/modules/rigsuits/suits/light.dm
+++ b/code/modules/rigsuits/suits/light.dm
@@ -15,7 +15,7 @@
armor_type = /datum/armor/hardsuit/light
emp_protection = 10
slowdown = 0
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
offline_slowdown = 0
offline_vision_restriction = 0
diff --git a/code/modules/rigsuits/suits/species/vox.dm b/code/modules/rigsuits/suits/species/vox.dm
index 878c7b41d5c..900e92d94fe 100644
--- a/code/modules/rigsuits/suits/species/vox.dm
+++ b/code/modules/rigsuits/suits/species/vox.dm
@@ -5,7 +5,7 @@
icon_state = "vox_rig"
armor_type = /datum/armor/hardsuit/vox
atom_flags = PHORONGUARD
- clothing_flags = THICKMATERIAL
+ clothing_flags = CLOTHING_THICK_MATERIAL
siemens_coefficient = 0.2
offline_slowdown = 5
allowed = list(
diff --git a/code/modules/surgery/other.dm b/code/modules/surgery/other.dm
index 93c7b37a29e..97a01af469d 100644
--- a/code/modules/surgery/other.dm
+++ b/code/modules/surgery/other.dm
@@ -163,7 +163,7 @@
var/obj/item/reagent_containers/container = tool
- var/trans = container.reagents.trans_to_mob(target, container.amount_per_transfer_from_this, CHEM_BLOOD) //technically it's contact, but the reagents are being applied to internal tissue
+ var/trans = container.reagents.trans_to_mob(target, container.amount_per_transfer_from_this, CHEM_INJECT) //technically it's contact, but the reagents are being applied to internal tissue
if (trans > 0)
affected.status &= ~ORGAN_DEAD
affected.owner.update_icons_body()
@@ -179,7 +179,7 @@
var/obj/item/reagent_containers/container = tool
- var/trans = container.reagents.trans_to_mob(target, container.amount_per_transfer_from_this, CHEM_BLOOD)
+ var/trans = container.reagents.trans_to_mob(target, container.amount_per_transfer_from_this, CHEM_INJECT)
user.visible_message("[user]'s hand slips, applying [trans] units of the solution to the wrong place in [target]'s [affected.name] with the [tool]!" , \
"Your hand slips, applying [trans] units of the solution to the wrong place in [target]'s [affected.name] with the [tool]!")
diff --git a/code/modules/unit_tests/reagents/reagent_id_typos.dm b/code/modules/unit_tests/reagents/reagent_id_typos.dm
deleted file mode 100644
index d6548852fa5..00000000000
--- a/code/modules/unit_tests/reagents/reagent_id_typos.dm
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-/datum/unit_test/reagent_id_typos
-
-/datum/unit_test/reagent_id_typos/Run()
- build_chemical_reactions_list()
- build_chemical_reagent_list()
-
- for(var/I in GLOB.chemical_reactions_list)
- for(var/V in GLOB.chemical_reactions_list[I])
- var/datum/chemical_reaction/R = V
- for(var/id in (R.required_reagents + R.required_catalysts))
- if(!GLOB.chemical_reagents_list[id])
- Fail("Unknown chemical id \"[id]\" in recipe [R.type]")
diff --git a/code/modules/unit_tests/reagents/reagent_recipe_collisions.dm b/code/modules/unit_tests/reagents/reagent_recipe_collisions.dm
index 20e875422f2..fa537ceffa9 100644
--- a/code/modules/unit_tests/reagents/reagent_recipe_collisions.dm
+++ b/code/modules/unit_tests/reagents/reagent_recipe_collisions.dm
@@ -3,13 +3,18 @@
/datum/unit_test/reagent_recipe_collisions
/datum/unit_test/reagent_recipe_collisions/Run()
- build_chemical_reactions_list()
- var/list/reactions = list()
- for(var/V in GLOB.chemical_reactions_list)
- reactions += GLOB.chemical_reactions_list[V]
+ var/list/reactions = SSchemistry.chemical_reactions.Copy()
for(var/i in 1 to (reactions.len-1))
+ var/datum/chemical_reaction/r1 = reactions[i]
+ //! LEGACY PATCH - we don't have abstract types / skipovers properly set up.
+ if(!length(r1.required_reagents))
+ continue
+ //! LEGACY PATCH END
for(var/i2 in (i+1) to reactions.len)
- var/datum/chemical_reaction/r1 = reactions[i]
var/datum/chemical_reaction/r2 = reactions[i2]
+ //! LEGACY PATCH - we don't have abstract types / skipovers properly set up.
+ if(!length(r2.required_reagents))
+ continue
+ //! LEGACY PATCH END
if(chem_recipes_do_conflict(r1, r2))
Fail("Chemical recipe conflict between [r1.type] and [r2.type]")
diff --git a/code/modules/xenobio/items/extracts.dm b/code/modules/xenobio/items/extracts.dm
index 6c9b752f87a..cff78d327da 100644
--- a/code/modules/xenobio/items/extracts.dm
+++ b/code/modules/xenobio/items/extracts.dm
@@ -40,14 +40,15 @@
. += "This extract is inert."
/datum/chemical_reaction/slime
- var/required = null
+ abstract_type = /datum/chemical_reaction/slime
/datum/chemical_reaction/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
+ if(!istype(holder.my_atom, /obj/item/slime_extract))
+ return FALSE
+ var/obj/item/slime_extract/T = holder.my_atom
+ if(T.uses <= 0)
+ return FALSE
+ return ..()
/datum/chemical_reaction/slime/on_reaction(var/datum/reagents/holder)
var/obj/item/slime_extract/T = holder.my_atom
@@ -56,12 +57,10 @@
T.visible_message("[icon2html(thing = T, target = world)] \The [T] goes inert.")
T.name = "inert [initial(T.name)]"
-
// ***************
// * Grey slimes *
// ***************
-
/obj/item/slime_extract/grey
name = "grey slime extract"
icon_state = "grey slime extract"
@@ -73,7 +72,7 @@
result = null
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/grey
+ required_container = /obj/item/slime_extract/grey
/datum/chemical_reaction/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!")
@@ -87,7 +86,7 @@
result = null
required_reagents = list("blood" = 5)
result_amount = 1
- required = /obj/item/slime_extract/grey
+ required_container = /obj/item/slime_extract/grey
/datum/chemical_reaction/slime/grey_monkey/on_reaction(var/datum/reagents/holder)
for(var/i = 1 to 4)
@@ -100,7 +99,7 @@
result = "slimejelly"
required_reagents = list("peridaxon" = 5)
result_amount = 15
- required = /obj/item/slime_extract/grey
+ required_container = /obj/item/slime_extract/grey
// ****************
// * Metal slimes *
@@ -130,7 +129,7 @@
required_reagents = list(MAT_PHORON = 5)
result = "metamorphic"
result_amount = REAGENTS_PER_SHEET // Makes enough to make one sheet of any metal.
- required = /obj/item/slime_extract/metal
+ required_container = /obj/item/slime_extract/metal
/datum/chemical_reaction/metamorphic
@@ -195,7 +194,7 @@
required_reagents = list("water" = 5)
result = "binding"
result_amount = REAGENTS_PER_SHEET // Makes enough to make one sheet of any metal.
- required = /obj/item/slime_extract/metal
+ required_container = /obj/item/slime_extract/metal
/datum/reagent/toxin/binding_metal
@@ -265,7 +264,7 @@
result = "frostoil"
required_reagents = list(MAT_PHORON = 5)
result_amount = 20
- required = /obj/item/slime_extract/blue
+ required_container = /obj/item/slime_extract/blue
/datum/chemical_reaction/slime/blue_stability
@@ -273,7 +272,7 @@
id = "m_stability"
required_reagents = list("blood" = 5)
result_amount = 1
- required = /obj/item/slime_extract/blue
+ required_container = /obj/item/slime_extract/blue
/datum/chemical_reaction/slime/blue_stability/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/stabilizer(get_turf(holder.my_atom))
@@ -297,7 +296,7 @@
id = "m_steroid"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/purple
+ required_container = /obj/item/slime_extract/purple
/datum/chemical_reaction/slime/purple_steroid/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/steroid(get_turf(holder.my_atom))
@@ -319,7 +318,7 @@
id = "m_fire"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/orange
+ required_container = /obj/item/slime_extract/orange
/datum/chemical_reaction/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]")
@@ -356,7 +355,7 @@
id = "m_emp"
required_reagents = list("water" = 5)
result_amount = 1
- required = /obj/item/slime_extract/yellow
+ required_container = /obj/item/slime_extract/yellow
/datum/chemical_reaction/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]")
@@ -374,7 +373,7 @@
id = "m_cell"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/yellow
+ required_container = /obj/item/slime_extract/yellow
/datum/chemical_reaction/slime/yellow_battery/on_reaction(var/datum/reagents/holder)
new /obj/item/cell/slime(get_turf(holder.my_atom))
@@ -386,7 +385,7 @@
id = "m_flashlight"
required_reagents = list("blood" = 5)
result_amount = 1
- required = /obj/item/slime_extract/yellow
+ required_container = /obj/item/slime_extract/yellow
/datum/chemical_reaction/slime/yellow_flashlight/on_reaction(var/datum/reagents/holder)
new /obj/item/flashlight/slime(get_turf(holder.my_atom))
@@ -408,7 +407,7 @@
result = "gold"
required_reagents = list(MAT_PHORON = 5)
result_amount = 5
- required = /obj/item/slime_extract/gold
+ required_container = /obj/item/slime_extract/gold
// *****************
@@ -427,7 +426,7 @@
result = "silver"
required_reagents = list(MAT_PHORON = 5)
result_amount = 5
- required = /obj/item/slime_extract/silver
+ required_container = /obj/item/slime_extract/silver
// **********************
@@ -447,7 +446,7 @@
result = "phoron"
required_reagents = list("water" = 5)
result_amount = REAGENTS_PER_SHEET * 2
- required = /obj/item/slime_extract/dark_purple
+ required_container = /obj/item/slime_extract/dark_purple
// ********************
@@ -468,7 +467,7 @@
id = "m_cold_snap"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/dark_blue
+ required_container = /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)
@@ -550,7 +549,7 @@
id = "m_enrage"
required_reagents = list("blood" = 5)
result_amount = 1
- required = /obj/item/slime_extract/red
+ required_container = /obj/item/slime_extract/red
/datum/chemical_reaction/slime/red_enrage/on_reaction(var/datum/reagents/holder)
for(var/mob/living/simple_mob/slime/S in view(get_turf(holder.my_atom)))
@@ -586,7 +585,7 @@
id = "m_mutation"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/red
+ required_container = /obj/item/slime_extract/red
/datum/chemical_reaction/slime/red_mutation/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/mutator(get_turf(holder.my_atom))
@@ -607,7 +606,7 @@
result = "uranium"
required_reagents = list(MAT_PHORON = 5)
result_amount = 5
- required = /obj/item/slime_extract/green
+ required_container = /obj/item/slime_extract/green
// ***************
@@ -627,7 +626,7 @@
result = "slime_bleed_fixer"
required_reagents = list("blood" = 5)
result_amount = 30
- required = /obj/item/slime_extract/pink
+ required_container = /obj/item/slime_extract/pink
/datum/chemical_reaction/slime/pink_bone_fix
@@ -636,7 +635,7 @@
result = "slime_bone_fixer"
required_reagents = list(MAT_PHORON = 5)
result_amount = 30
- required = /obj/item/slime_extract/pink
+ required_container = /obj/item/slime_extract/pink
/datum/chemical_reaction/slime/pink_organ_fix
@@ -645,7 +644,7 @@
result = "slime_organ_fixer"
required_reagents = list("water" = 5)
result_amount = 30
- required = /obj/item/slime_extract/pink
+ required_container = /obj/item/slime_extract/pink
/datum/reagent/myelamine/slime
@@ -686,7 +685,7 @@
id = "m_boom"
required_reagents = list("blood" = 5)
result_amount = 1
- required = /obj/item/slime_extract/oil
+ required_container = /obj/item/slime_extract/oil
/datum/chemical_reaction/slime/oil_griff/on_reaction(var/datum/reagents/holder)
@@ -724,7 +723,7 @@
id = "m_tele_lesser"
required_reagents = list("water" = 5)
result_amount = 1
- required = /obj/item/slime_extract/bluespace
+ required_container = /obj/item/slime_extract/bluespace
/datum/chemical_reaction/slime/bluespace_lesser/on_reaction(var/datum/reagents/holder)
for(var/i = 1 to 5)
@@ -736,7 +735,7 @@
id = "m_tele_lesser"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/bluespace
+ required_container = /obj/item/slime_extract/bluespace
/datum/chemical_reaction/slime/bluespace_greater/on_reaction(var/datum/reagents/holder)
new /obj/item/disposable_teleporter/slime(get_turf(holder.my_atom))
@@ -747,7 +746,7 @@
id = "bloodcrystal"
required_reagents = list("blood" = 5)
result_amount = 1
- required = /obj/item/slime_extract/bluespace
+ required_container = /obj/item/slime_extract/bluespace
/datum/chemical_reaction/slime/bloodcrystal/on_reaction(var/datum/reagents/holder)
new /obj/item/ore/bluespace_crystal(get_turf(holder.my_atom))
@@ -769,7 +768,7 @@
id = "m_enhancer"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/cerulean
+ required_container = /obj/item/slime_extract/cerulean
/datum/chemical_reaction/slime/cerulean_enhancer/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/enhancer(get_turf(holder.my_atom))
@@ -791,7 +790,7 @@
id = "m_slime_food"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/amber
+ required_container = /obj/item/slime_extract/amber
/datum/chemical_reaction/slime/amber_slimefood/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/feeding(get_turf(holder.my_atom))
@@ -803,7 +802,7 @@
id = "m_people_food"
required_reagents = list("water" = 5)
result_amount = 1
- required = /obj/item/slime_extract/amber
+ required_container = /obj/item/slime_extract/amber
/datum/chemical_reaction/slime/amber_peoplefood/on_reaction(var/datum/reagents/holder)
new /obj/item/reagent_containers/food/snacks/slime(get_turf(holder.my_atom))
@@ -826,7 +825,7 @@
id = "m_promethean"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/sapphire
+ required_container = /obj/item/slime_extract/sapphire
/datum/chemical_reaction/slime/sapphire_promethean/on_reaction(var/datum/reagents/holder)
new /obj/item/slime_cube(get_turf(holder.my_atom))
@@ -847,7 +846,7 @@
id = "m_strength"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/ruby
+ required_container = /obj/item/slime_extract/ruby
/datum/chemical_reaction/slime/ruby_swole/on_reaction(var/datum/reagents/holder)
for(var/mob/living/L in range(1, holder.my_atom))
@@ -875,7 +874,7 @@
id = "m_strength"
required_reagents = list("blood" = 5)
result_amount = 1
- required = /obj/item/slime_extract/ruby
+ required_container = /obj/item/slime_extract/ruby
/datum/chemical_reaction/slime/ruby_loyalty/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/loyalty(get_turf(holder.my_atom))
@@ -896,7 +895,7 @@
id = "m_agility"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/emerald
+ required_container = /obj/item/slime_extract/emerald
/datum/chemical_reaction/slime/emerald_fast/on_reaction(var/datum/reagents/holder)
for(var/mob/living/L in range(1, holder.my_atom))
@@ -933,7 +932,7 @@
id = "m_docile"
required_reagents = list("water" = 5)
result_amount = 1
- required = /obj/item/slime_extract/light_pink
+ required_container = /obj/item/slime_extract/light_pink
/datum/chemical_reaction/slime/light_pink_docility/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/docility(get_turf(holder.my_atom))
@@ -945,7 +944,7 @@
id = "m_friendship"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/light_pink
+ required_container = /obj/item/slime_extract/light_pink
/datum/chemical_reaction/slime/light_pink_friendship/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/friendship(get_turf(holder.my_atom))
@@ -969,7 +968,7 @@
id = "m_rng_slime"
required_reagents = list(MAT_PHORON = 5)
result_amount = 1
- required = /obj/item/slime_extract/rainbow
+ required_container = /obj/item/slime_extract/rainbow
/datum/chemical_reaction/slime/rainbow_random_slime/on_reaction(var/datum/reagents/holder)
@@ -993,7 +992,7 @@
id = "m_unity"
required_reagents = list("water" = 5)
result_amount = 1
- required = /obj/item/slime_extract/rainbow
+ required_container = /obj/item/slime_extract/rainbow
/datum/chemical_reaction/slime/rainbow_unity/on_reaction(var/datum/reagents/holder)
new /obj/item/slimepotion/unity(get_turf(holder.my_atom))
@@ -1005,4 +1004,4 @@
result = "mutationtoxin"
required_reagents = list("blood" = 5)
result_amount = 30
- required = /obj/item/slime_extract/sapphire
+ required_container = /obj/item/slime_extract/sapphire
diff --git a/code/modules/xenobio2/mob/xeno procs.dm b/code/modules/xenobio2/mob/xeno procs.dm
index 9c1e560b30c..167e7046f48 100644
--- a/code/modules/xenobio2/mob/xeno procs.dm
+++ b/code/modules/xenobio2/mob/xeno procs.dm
@@ -54,7 +54,7 @@ Divergence proc, used in mutation to make unique datums.
//Let's handle some chemical smoke, for scientific smoke bomb purposes.
for(var/obj/effect/particle_effect/smoke/chem/smoke in view(1, src))
if(smoke.reagents.total_volume)
- smoke.reagents.trans_to_mob(src, 10, CHEM_BLOOD, copy = 1)
+ smoke.reagents.trans_to_mob(src, 10, CHEM_INJECT, copy = 1)
reagents.trans_to_obj(temp_chem_holder, min(reagents.total_volume,rand(1,4)))
var/reagent_total
diff --git a/icons/items/storage/firstaid.dmi b/icons/items/storage/firstaid.dmi
new file mode 100644
index 00000000000..6962ec92221
Binary files /dev/null and b/icons/items/storage/firstaid.dmi differ
diff --git a/icons/items/storage/firstaid_small.dmi b/icons/items/storage/firstaid_small.dmi
new file mode 100644
index 00000000000..a794c09f90f
Binary files /dev/null and b/icons/items/storage/firstaid_small.dmi differ
diff --git a/icons/modules/reagents/items/hypospray.dmi b/icons/modules/reagents/items/hypospray.dmi
new file mode 100644
index 00000000000..3ff6118ef59
Binary files /dev/null and b/icons/modules/reagents/items/hypospray.dmi differ
diff --git a/icons/screen/atom_hud/health.dmi b/icons/screen/atom_hud/health.dmi
index 752829fba26..152af8331e8 100644
Binary files a/icons/screen/atom_hud/health.dmi and b/icons/screen/atom_hud/health.dmi differ
diff --git a/maps/map_files/rift/rift-05-surface2.dmm b/maps/map_files/rift/rift-05-surface2.dmm
index 80f4a203839..9f03715c56c 100644
--- a/maps/map_files/rift/rift-05-surface2.dmm
+++ b/maps/map_files/rift/rift-05-surface2.dmm
@@ -10075,7 +10075,6 @@
/area/rnd/outpost/xenobiology/outpost_slimepens)
"gra" = (
/obj/structure/table/standard,
-/obj/machinery/recharger,
/obj/effect/floor_decal/corner/paleblue{
dir = 10
},
@@ -10086,6 +10085,28 @@
desc = null;
pixel_y = 24
},
+/obj/item/storage/hypokit{
+ pixel_x = -8;
+ pixel_y = -8
+ },
+/obj/item/storage/hypokit{
+ pixel_x = -8
+ },
+/obj/item/storage/hypokit{
+ pixel_x = -8;
+ pixel_y = 8
+ },
+/obj/item/storage/hypokit{
+ pixel_x = 8;
+ pixel_y = 8
+ },
+/obj/item/storage/hypokit{
+ pixel_x = 8;
+ pixel_y = -8
+ },
+/obj/item/storage/hypokit{
+ pixel_x = 8
+ },
/turf/simulated/floor/tiled/white,
/area/medical/medbay_primary_storage)
"grT" = (
@@ -18859,6 +18880,7 @@
/obj/item/cane,
/obj/item/cane/crutch,
/obj/item/cane/crutch,
+/obj/machinery/recharger,
/turf/simulated/floor/tiled/white,
/area/medical/medbay_primary_storage)
"lLU" = (
diff --git a/sound/items/hypospray.ogg b/sound/items/hypospray.ogg
new file mode 100644
index 00000000000..b70d3fd5b58
Binary files /dev/null and b/sound/items/hypospray.ogg differ
diff --git a/sound/items/hypospray2.ogg b/sound/items/hypospray2.ogg
new file mode 100644
index 00000000000..14835e9bb6a
Binary files /dev/null and b/sound/items/hypospray2.ogg differ
diff --git a/sound/items/hypospray_long.ogg b/sound/items/hypospray_long.ogg
new file mode 100644
index 00000000000..d7da6c839f3
Binary files /dev/null and b/sound/items/hypospray_long.ogg differ
diff --git a/sound/weapons/autoguninsert.ogg b/sound/weapons/autoguninsert.ogg
new file mode 100644
index 00000000000..f68139968e0
Binary files /dev/null and b/sound/weapons/autoguninsert.ogg differ
diff --git a/tgui/packages/tgui/interfaces/ChemMaster.tsx b/tgui/packages/tgui/interfaces/ChemMaster.tsx
index 9de38db10b3..7f594ef85a8 100644
--- a/tgui/packages/tgui/interfaces/ChemMaster.tsx
+++ b/tgui/packages/tgui/interfaces/ChemMaster.tsx
@@ -310,6 +310,7 @@ const PackagingControls = (props, context) => {
'bottleAmount',
1
);
+ const [vialAmount, setVialAmount] = useSharedState(context, "vialAmount", 1);
const [packAmount, setPackAmount] = useSharedState(context, 'packAmount', 1);
const {
condi,
@@ -417,6 +418,21 @@ const PackagingControls = (props, context) => {
})}
/>
)}
+ {!condi && (
+ setVialAmount(value)}
+ onCreate={() =>
+ act('create', {
+ type: 'hypovial',
+ amount: vialAmount,
+ volume: 'auto',
+ })}
+ />
+ )}
{!!condi && (