diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 9404b57df8f..f8ed791c3f4 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -410,9 +410,6 @@ GLOBAL_LIST_INIT(pda_styles, sortList(list(MONO, VT, ORBITRON, SHARE)))
#define MAX_PROC_DEPTH 195 // 200 proc calls deep and shit breaks, this is a bit lower to give some safety room
-#define SYRINGE_DRAW 0
-#define SYRINGE_INJECT 1
-
//gold slime core spawning
#define NO_SPAWN 0
#define HOSTILE_SPAWN 1
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 08714ae174a..be938ea3a18 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -520,12 +520,6 @@
if(IS_EDIBLE(O) || istype(O, /obj/item/reagent_containers)) // Syringe stuff (and other reagent containers now too)
var/obj/item/reagent_containers/reagent_source = O
- if(istype(reagent_source, /obj/item/reagent_containers/syringe))
- var/obj/item/reagent_containers/syringe/syr = reagent_source
- if(syr.mode != 1)
- to_chat(user, "You can't get any extract out of this plant." )
- return
-
if(!reagent_source.reagents.total_volume)
to_chat(user, "[reagent_source] is empty!")
return 1
@@ -548,8 +542,6 @@
if(istype(reagent_source, /obj/item/reagent_containers/syringe/))
var/obj/item/reagent_containers/syringe/syr = reagent_source
visi_msg="[user] injects [target] with [syr]"
- if(syr.reagents.total_volume <= syr.amount_per_transfer_from_this)
- syr.mode = 0
// Beakers, bottles, buckets, etc.
if(reagent_source.is_drainable())
playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE)
@@ -741,6 +733,12 @@
else
return ..()
+/obj/machinery/hydroponics/attackby_secondary(obj/item/weapon, mob/user, params)
+ if (istype(weapon, /obj/item/reagent_containers/syringe))
+ to_chat(user, "You can't get any extract out of this plant.")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ return SECONDARY_ATTACK_CALL_NORMAL
+
/obj/machinery/hydroponics/can_be_unfasten_wrench(mob/user, silent)
if (!unwrenchable) // case also covered by NODECONSTRUCT checks in default_unfasten_wrench
return CANT_UNFASTEN
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 6ccfb9729c8..36c4982b97c 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -35,6 +35,11 @@
/obj/item/reagent_containers/Destroy()
return ..()
+/obj/item/reagent_containers/attack(mob/living/M, mob/living/user, params)
+ if (!user.combat_mode)
+ return
+ return ..()
+
/obj/item/reagent_containers/proc/on_reagents_del(datum/reagents/reagents)
SIGNAL_HANDLER
UnregisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT, COMSIG_PARENT_QDELETING))
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index a13f550ac3e..417d42a605a 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -8,9 +8,8 @@
icon_state = "0"
worn_icon_state = "pen"
amount_per_transfer_from_this = 5
- possible_transfer_amounts = list()
+ possible_transfer_amounts = list(5, 10, 15)
volume = 15
- var/mode = SYRINGE_DRAW
var/busy = FALSE // needed for delayed drawing of blood
var/proj_piercing = 0 //does it pierce through thick clothes when shot with syringe gun
custom_materials = list(/datum/material/iron=10, /datum/material/glass=20)
@@ -18,138 +17,109 @@
custom_price = PAYCHECK_EASY * 0.5
sharpness = SHARP_POINTY
-/obj/item/reagent_containers/syringe/Initialize()
- . = ..()
- if(list_reagents) //syringe starts in inject mode if its already got something inside
- mode = SYRINGE_INJECT
- update_icon()
-
-/obj/item/reagent_containers/syringe/ComponentInitialize()
- . = ..()
- AddElement(/datum/element/update_icon_updates_onmob)
-
-/obj/item/reagent_containers/syringe/pickup(mob/user)
- ..()
- update_icon()
-
-/obj/item/reagent_containers/syringe/dropped(mob/user)
- ..()
- update_icon()
-
-/obj/item/reagent_containers/syringe/attack_self(mob/user)
- mode = !mode
- update_icon()
-
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/reagent_containers/syringe/attack_hand()
- . = ..()
- update_icon()
-
-/obj/item/reagent_containers/syringe/attack_paw(mob/user)
- return attack_hand(user)
-
/obj/item/reagent_containers/syringe/attackby(obj/item/I, mob/user, params)
return
-/obj/item/reagent_containers/syringe/afterattack(atom/target, mob/user , proximity)
- . = ..()
+/obj/item/reagent_containers/syringe/proc/try_syringe(atom/target, mob/user, proximity)
if(busy)
- return
+ return FALSE
if(!proximity)
- return
+ return FALSE
if(!target.reagents)
- return
+ return FALSE
- var/mob/living/L
if(isliving(target))
- L = target
- if(!L.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE))
- return
+ var/mob/living/living_target = target
+ if(!living_target.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE))
+ return FALSE
// chance of monkey retaliation
SEND_SIGNAL(target, COMSIG_LIVING_TRY_SYRINGE, user)
+ return TRUE
- switch(mode)
- if(SYRINGE_DRAW)
+/obj/item/reagent_containers/syringe/afterattack(atom/target, mob/user, proximity)
+ . = ..()
- if(reagents.total_volume >= reagents.maximum_volume)
- to_chat(user, "The syringe is full.")
+ if (!try_syringe(target, user, proximity))
+ return
+
+ var/contained = reagents.log_list()
+ log_combat(user, target, "attempted to inject", src, addition="which had [contained]")
+
+ if(!reagents.total_volume)
+ to_chat(user, "[src] is empty! Right-click to draw.")
+ return
+
+ if(!isliving(target) && !target.is_injectable(user))
+ to_chat(user, "You cannot directly fill [target]!")
+ return
+
+ if(target.reagents.total_volume >= target.reagents.maximum_volume)
+ to_chat(user, "[target] is full.")
+ return
+
+ if(isliving(target))
+ var/mob/living/living_target = target
+ if(!living_target.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE))
+ return
+ if(living_target != user)
+ living_target.visible_message("[user] is trying to inject [living_target]!", \
+ "[user] is trying to inject you!")
+ if(!do_mob(user, living_target, 3 SECONDS, extra_checks = CALLBACK(living_target, /mob/living/proc/try_inject, user, null, INJECT_TRY_SHOW_ERROR_MESSAGE)))
return
-
- if(L) //living mob
- var/drawn_amount = reagents.maximum_volume - reagents.total_volume
- if(target != user)
- target.visible_message("[user] is trying to take a blood sample from [target]!", \
- "[user] is trying to take a blood sample from you!")
- busy = TRUE
- if(!do_mob(user, target, extra_checks=CALLBACK(L, /mob/living/proc/try_inject, user, null, INJECT_TRY_SHOW_ERROR_MESSAGE)))
- busy = FALSE
- return
- if(reagents.total_volume >= reagents.maximum_volume)
- return
- busy = FALSE
- if(L.transfer_blood_to(src, drawn_amount))
- user.visible_message("[user] takes a blood sample from [L].")
- else
- to_chat(user, "You are unable to draw any blood from [L]!")
-
- else //if not mob
- if(!target.reagents.total_volume)
- to_chat(user, "[target] is empty!")
- return
-
- if(!target.is_drawable(user))
- to_chat(user, "You cannot directly remove reagents from [target]!")
- return
-
- var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transfered_by = user) // transfer from, transfer to - who cares?
-
- to_chat(user, "You fill [src] with [trans] units of the solution. It now contains [reagents.total_volume] units.")
- if (reagents.total_volume >= reagents.maximum_volume)
- mode=!mode
- update_icon()
-
- if(SYRINGE_INJECT)
- // Always log attemped injections for admins
- var/contained = reagents.log_list()
- log_combat(user, target, "attempted to inject", src, addition="which had [contained]")
-
if(!reagents.total_volume)
- to_chat(user, "[src] is empty!")
return
-
- if(!L && !target.is_injectable(user)) //only checks on non-living mobs, due to how can_inject() handles
- to_chat(user, "You cannot directly fill [target]!")
+ if(living_target.reagents.total_volume >= living_target.reagents.maximum_volume)
return
+ living_target.visible_message("[user] injects [living_target] with the syringe!", \
+ "[user] injects you with the syringe!")
- if(target.reagents.total_volume >= target.reagents.maximum_volume)
- to_chat(user, "[target] is full.")
- return
+ if (living_target == user)
+ living_target.log_message("injected themselves ([contained]) with [name]", LOG_ATTACK, color="orange")
+ else
+ log_combat(user, living_target, "injected", src, addition="which had [contained]")
+ reagents.trans_to(target, amount_per_transfer_from_this, transfered_by = user, methods = INJECT)
+ to_chat(user, "You inject [amount_per_transfer_from_this] units of the solution. The syringe now contains [reagents.total_volume] units.")
- if(L) //living mob
- if(!L.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE))
- return
- if(L != user)
- L.visible_message("[user] is trying to inject [L]!", \
- "[user] is trying to inject you!")
- if(!do_mob(user, L, extra_checks=CALLBACK(L, /mob/living/proc/try_inject, user, null, INJECT_TRY_SHOW_ERROR_MESSAGE)))
- return
- if(!reagents.total_volume)
- return
- if(L.reagents.total_volume >= L.reagents.maximum_volume)
- return
- L.visible_message("[user] injects [L] with the syringe!", \
- "[user] injects you with the syringe!")
+/obj/item/reagent_containers/syringe/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
+ if (!try_syringe(target, user, proximity_flag))
+ return SECONDARY_ATTACK_CONTINUE_CHAIN
- if(L != user)
- log_combat(user, L, "injected", src, addition="which had [contained]")
- else
- L.log_message("injected themselves ([contained]) with [src.name]", LOG_ATTACK, color="orange")
- reagents.trans_to(target, amount_per_transfer_from_this, transfered_by = user, methods = INJECT)
- to_chat(user, "You inject [amount_per_transfer_from_this] units of the solution. The syringe now contains [reagents.total_volume] units.")
- if (reagents.total_volume <= 0 && mode==SYRINGE_INJECT)
- mode = SYRINGE_DRAW
- update_icon()
+ if(reagents.total_volume >= reagents.maximum_volume)
+ to_chat(user, "[src] is full.")
+ return SECONDARY_ATTACK_CONTINUE_CHAIN
+
+ if(isliving(target))
+ var/mob/living/living_target = target
+ var/drawn_amount = reagents.maximum_volume - reagents.total_volume
+ if(target != user)
+ target.visible_message("[user] is trying to take a blood sample from [target]!", \
+ "[user] is trying to take a blood sample from you!")
+ busy = TRUE
+ if(!do_mob(user, target, 3 SECONDS, extra_checks = CALLBACK(living_target, /mob/living/proc/try_inject, user, null, INJECT_TRY_SHOW_ERROR_MESSAGE)))
+ busy = FALSE
+ return SECONDARY_ATTACK_CONTINUE_CHAIN
+ if(reagents.total_volume >= reagents.maximum_volume)
+ return SECONDARY_ATTACK_CONTINUE_CHAIN
+ busy = FALSE
+ if(living_target.transfer_blood_to(src, drawn_amount))
+ user.visible_message("[user] takes a blood sample from [living_target].")
+ else
+ to_chat(user, "You are unable to draw any blood from [living_target]!")
+ else
+ if(!target.reagents.total_volume)
+ to_chat(user, "[target] is empty!")
+ return SECONDARY_ATTACK_CONTINUE_CHAIN
+
+ if(!target.is_drawable(user))
+ to_chat(user, "You cannot directly remove reagents from [target]!")
+ return SECONDARY_ATTACK_CONTINUE_CHAIN
+
+ var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transfered_by = user) // transfer from, transfer to - who cares?
+
+ to_chat(user, "You fill [src] with [trans] units of the solution. It now contains [reagents.total_volume] units.")
+
+ return SECONDARY_ATTACK_CONTINUE_CHAIN
/*
* On accidental consumption, inject the eater with 2/3rd of the syringe and reveal it
@@ -177,14 +147,6 @@
var/mutable_appearance/filling_overlay = mutable_appearance('icons/obj/reagentfillings.dmi', "syringe[rounded_vol]")
filling_overlay.color = mix_color_from_reagents(reagents.reagent_list)
. += filling_overlay
- if(ismob(loc))
- var/injoverlay
- switch(mode)
- if (SYRINGE_DRAW)
- injoverlay = "draw"
- if (SYRINGE_INJECT)
- injoverlay = "inject"
- . += injoverlay
///Used by update_icon() and update_overlays()
/obj/item/reagent_containers/syringe/proc/get_rounded_vol()
@@ -258,12 +220,14 @@
name = "bluespace syringe"
desc = "An advanced syringe that can hold 60 units of chemicals."
amount_per_transfer_from_this = 20
+ possible_transfer_amounts = list(10, 20, 30, 40, 50, 60)
volume = 60
/obj/item/reagent_containers/syringe/piercing
name = "piercing syringe"
desc = "A diamond-tipped syringe that pierces armor when launched at high velocity. It can hold up to 10 units."
volume = 10
+ possible_transfer_amounts = list(5, 10)
proj_piercing = 1
/obj/item/reagent_containers/syringe/spider_extract
diff --git a/code/modules/unit_tests/metabolizing.dm b/code/modules/unit_tests/metabolizing.dm
index f7b689574c6..36c12693426 100644
--- a/code/modules/unit_tests/metabolizing.dm
+++ b/code/modules/unit_tests/metabolizing.dm
@@ -72,10 +72,7 @@
syringe.volume = meth.addiction_threshold
syringe.amount_per_transfer_from_this = meth.addiction_threshold
syringe.reagents.add_reagent(meth.type, meth.addiction_threshold)
-
- syringe.mode = SYRINGE_INJECT
- syringe_user.set_combat_mode(TRUE)
- syringe.afterattack(syringe_user, syringe_user, TRUE)
+ syringe.melee_attack_chain(syringe_user, syringe_user)
syringe_user.Life()
@@ -90,10 +87,7 @@
// One half pill
pill_two.reagents.add_reagent(meth.type, (meth.addiction_threshold * 0.5) + 1)
pill_two.attack(pill_syringe_user, pill_syringe_user)
-
- pill_syringe_user.set_combat_mode(TRUE)
- syringe.mode = SYRINGE_INJECT
- syringe.afterattack(pill_syringe_user, pill_syringe_user, TRUE)
+ syringe.melee_attack_chain(pill_syringe_user, pill_syringe_user)
// Set the metabolism efficiency to 1.0 so it transfers all reagents to the body in one go.
pill_belly = pill_syringe_user.getorganslot(ORGAN_SLOT_STOMACH)
diff --git a/code/modules/unit_tests/reagent_mod_expose.dm b/code/modules/unit_tests/reagent_mod_expose.dm
index 3fe02e044d4..d893fef405f 100644
--- a/code/modules/unit_tests/reagent_mod_expose.dm
+++ b/code/modules/unit_tests/reagent_mod_expose.dm
@@ -50,8 +50,7 @@
// INJECT
syringe.reagents.add_reagent(/datum/reagent/method_patch_test, 1)
- syringe.mode = SYRINGE_INJECT
- syringe.afterattack(human, human, TRUE)
+ syringe.melee_attack_chain(human, human)
TEST_ASSERT_EQUAL(human.health, 80, "Human health did not update after injection from syringe")
/datum/unit_test/reagent_mob_expose/Destroy()
diff --git a/icons/obj/syringe.dmi b/icons/obj/syringe.dmi
index df2e20cf5f1..2981293d1a8 100644
Binary files a/icons/obj/syringe.dmi and b/icons/obj/syringe.dmi differ