diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm
index ddc0709a62c..a1681641ae8 100644
--- a/code/game/objects/items/weapons/storage/boxes.dm
+++ b/code/game/objects/items/weapons/storage/boxes.dm
@@ -79,7 +79,7 @@
/obj/item/weapon/storage/box/syringes
name = "box of syringes"
desc = "A box full of syringes."
- desc = "A biohazard alert warning is printed on the box"
+// desc = "A biohazard alert warning is printed on the box"
icon_state = "syringe"
New()
@@ -92,6 +92,22 @@
new /obj/item/weapon/reagent_containers/syringe( src )
new /obj/item/weapon/reagent_containers/syringe( src )
+/obj/item/weapon/storage/box/syringegun
+ name = "box of compressed gas cartridges"
+ desc = "A box full of compressed gas cartridges."
+ icon_state = "syringe"
+
+ New()
+ ..()
+ new /obj/item/ammo_casing/gas_cartridge( src )
+ new /obj/item/ammo_casing/gas_cartridge( src )
+ new /obj/item/ammo_casing/gas_cartridge( src )
+ new /obj/item/ammo_casing/gas_cartridge( src )
+ new /obj/item/ammo_casing/gas_cartridge( src )
+ new /obj/item/ammo_casing/gas_cartridge( src )
+ new /obj/item/ammo_casing/gas_cartridge( src )
+
+
/obj/item/weapon/storage/box/beakers
name = "box of beakers"
icon_state = "beaker"
diff --git a/code/modules/admin/verbs/vox_raiders.dm b/code/modules/admin/verbs/vox_raiders.dm
index 6676acec327..6c34bb92c61 100644
--- a/code/modules/admin/verbs/vox_raiders.dm
+++ b/code/modules/admin/verbs/vox_raiders.dm
@@ -37,7 +37,7 @@ var/global/vox_tick = 1
equip_to_slot_or_del(new /obj/item/weapon/storage/belt/utility/full(src), slot_belt)
equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/monocle(src), slot_glasses) // REPLACE WITH CODED VOX ALTERNATIVE.
equip_to_slot_or_del(new /obj/item/weapon/card/emag(src), slot_l_store)
- equip_to_slot_or_del(new /obj/item/weapon/gun/dartgun/vox/raider(src), slot_r_hand)
+ equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/dartgun/vox/raider(src), slot_r_hand)
equip_to_slot_or_del(new /obj/item/device/multitool(src), slot_l_hand)
if(4) // Vox medic!
@@ -46,7 +46,7 @@ var/global/vox_tick = 1
equip_to_slot_or_del(new /obj/item/weapon/storage/belt/utility/full(src), slot_belt) // Who needs actual surgical tools?
equip_to_slot_or_del(new /obj/item/clothing/glasses/hud/health(src), slot_glasses) // REPLACE WITH CODED VOX ALTERNATIVE.
equip_to_slot_or_del(new /obj/item/weapon/circular_saw(src), slot_l_store)
- equip_to_slot_or_del(new /obj/item/weapon/gun/dartgun/vox/medical, slot_r_hand)
+ equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/dartgun/vox/medical, slot_r_hand)
equip_to_slot_or_del(new /obj/item/clothing/mask/breath(src), slot_wear_mask)
equip_to_slot_or_del(new /obj/item/weapon/tank/nitrogen(src), slot_back)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index dd5bfe7d594..38ffc73f4e8 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1220,10 +1220,11 @@
/mob/living/carbon/human/can_inject(var/mob/user, var/error_msg, var/target_zone)
. = 1
- if(!user)
- target_zone = pick("chest","chest","chest","left leg","right leg","left arm", "right arm", "head")
- else if(!target_zone)
- target_zone = user.zone_sel.selecting
+ if(!target_zone)
+ if(!user)
+ target_zone = pick("chest","chest","chest","left leg","right leg","left arm", "right arm", "head")
+ else
+ target_zone = user.zone_sel.selecting
switch(target_zone)
if("head")
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index a45a11f4533..858bee60c17 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -389,6 +389,13 @@ emp_act
src.anchored = 1
src.pinned += O
+/mob/living/carbon/human/embed(var/obj/O, var/def_zone=null)
+ if(!def_zone) ..()
+
+ var/datum/organ/external/affecting = get_organ(def_zone)
+ if(affecting)
+ affecting.embed(O)
+
/mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2)
if (gloves)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 1783bad912b..2fa9cdc4b60 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -148,8 +148,7 @@
if(W.sharp) //Projectile is suitable for pinning.
//Handles embedding for non-humans and simple_animals.
- O.loc = src
- src.embedded += O
+ embed(O)
var/turf/T = near_wall(dir,2)
@@ -158,7 +157,11 @@
visible_message("[src] is pinned to the wall by [O]!","You are pinned to the wall by [O]!")
src.anchored = 1
src.pinned += O
- src.verbs += /mob/proc/yank_out_object
+
+/mob/living/proc/embed(var/obj/O, var/def_zone=null)
+ O.loc = src
+ src.embedded += O
+ src.verbs += /mob/proc/yank_out_object
//This is called when the mob is thrown into a dense turf
/mob/living/proc/turf_collision(var/turf/T, var/speed)
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index d0158816ca5..dd7aec246fc 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -165,6 +165,7 @@
if(recoil)
spawn()
shake_camera(user, recoil + 1, recoil)
+ update_icon()
//does the actual shooting
/obj/item/weapon/gun/proc/process_projectile(obj/projectile, mob/user, atom/target, var/target_zone, var/params=null, var/pointblank=0, var/reflex=0)
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index b467b31a1e1..26b42308ad7 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -1,4 +1,4 @@
-#define HOLD_CASINGS 0 //do not do anything after firing. Manual action, like pump shotguns
+#define HOLD_CASINGS 0 //do not do anything after firing. Manual action, like pump shotguns, or guns that want to define custom behaviour
#define EJECT_CASINGS 1 //drop spent casings on the ground after firing
#define CYCLE_CASINGS 2 //experimental: cycle casings, like a revolver. Also works for multibarrelled guns
@@ -53,16 +53,19 @@
..()
if(chambered)
chambered.expend()
+
+ //check chambered again in case it deleted itself
+ if(chambered && handle_casings != HOLD_CASINGS)
switch(handle_casings)
if(EJECT_CASINGS) //eject casing onto ground.
chambered.loc = get_turf(src)
- chambered = null
if(CYCLE_CASINGS) //cycle the casing back to the end.
if(ammo_magazine)
ammo_magazine.stored_ammo += chambered
else
loaded += chambered
- chambered = null
+ chambered = null
+
//Attempts to load A into src, depending on the type of thing being loaded and the load_method
//Maybe this should be broken up into separate procs for each load method?
@@ -81,6 +84,7 @@
AM.loc = src
ammo_magazine = AM
user.visible_message("[user] inserts [AM] into [src].", "You insert [AM] into [src]!")
+ playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1)
if(SPEEDLOADER)
if(loaded.len >= max_shells)
user << "[src] is full!"
@@ -96,6 +100,7 @@
count++
if(count)
user.visible_message("[user] reloads [src].", "You load [count] round\s into [src]!")
+ playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
AM.update_icon()
else if(istype(A, /obj/item/ammo_casing))
var/obj/item/ammo_casing/C = A
@@ -109,20 +114,22 @@
C.loc = src
loaded.Insert(1, C) //add to the head of the list
user.visible_message("[user] inserts \a [C] into [src].", "You insert \a [C] into [src]!")
+ playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
update_icon()
-//attempts to unload src
-/obj/item/weapon/gun/projectile/proc/unload_ammo(mob/user)
+//attempts to unload src. If allow_dump is set to 0, the speedloader unloading method will be disabled
+/obj/item/weapon/gun/projectile/proc/unload_ammo(mob/user, var/allow_dump=1)
if(ammo_magazine)
user.put_in_hands(ammo_magazine)
user.visible_message("[user] removes [ammo_magazine] from [src].", "You remove [ammo_magazine] from [src]!")
+ playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
ammo_magazine.update_icon()
ammo_magazine = null
else if(loaded.len)
//presumably, if it can be speed-loaded, it can be speed-unloaded.
- if(load_method & SPEEDLOADER)
+ if(allow_dump && load_method & SPEEDLOADER)
var/count = 0
var/turf/T = get_turf(user)
if(T)
@@ -145,17 +152,11 @@
load_ammo(A, user)
/obj/item/weapon/gun/projectile/attack_self(mob/user as mob)
- if (aim_targets) //TODO replace untargeting with a hotkey
- return ..()
unload_ammo(user)
/obj/item/weapon/gun/projectile/attack_hand(mob/user as mob)
- //allow guns with both SPEEDLOADER and SINGLE_CASING a way to remove casings without dumping everything on the floor
- if((load_method & SINGLE_CASING) && loaded.len && (src in user))
- var/obj/item/ammo_casing/C = loaded[loaded.len]
- loaded.len--
- user.put_in_hands(C)
- user.visible_message("[user] removes \a [C] from [src].", "You remove \a [C] from [src]!")
+ if(src in user)
+ unload_ammo(user, allow_dump=0)
else
return ..()
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 131e1523544..f16359ad4bb 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -229,6 +229,7 @@
/obj/item/projectile/process()
spawn while(src)
if(kill_count-- < 1)
+ on_impact(src.loc) //for any final impact behaviours
del(src)
if((!( current ) || loc == current))
current = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z)
diff --git a/code/modules/reagents/dartgun.dm b/code/modules/reagents/dartgun.dm
index d256f4f5f3c..7fa6d52e2e7 100644
--- a/code/modules/reagents/dartgun.dm
+++ b/code/modules/reagents/dartgun.dm
@@ -1,66 +1,94 @@
-/obj/item/weapon/dart_cartridge
+/obj/item/projectile/bullet/chemdart
+ name = "dart"
+ icon_state = "cbbolt"
+ damage = 3
+ sharp = 1
+ embed = 1
+ var/reagent_amount = 15
+ kill_count = 10 //short range
+
+/obj/item/projectile/bullet/chemdart/New()
+ reagents = new/datum/reagents(reagent_amount)
+ reagents.my_atom = src
+
+/obj/item/projectile/bullet/chemdart/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null)
+ if(blocked < 2 && isliving(target))
+ var/mob/living/L = target
+ if(L.can_inject(target_zone=def_zone))
+ reagents.trans_to(L, reagent_amount)
+
+/obj/item/ammo_casing/chemdart
+ name = "chemical dart"
+ desc = "A small hollow dart."
+ icon_state = "dart"
+ caliber = "dart"
+ projectile_type = /obj/item/projectile/bullet/chemdart
+
+/obj/item/ammo_magazine/chemdart
name = "dart cartridge"
desc = "A rack of hollow darts."
- icon = 'icons/obj/ammo.dmi'
- icon_state = "darts-5"
+ icon_state = "darts"
item_state = "rcdammo"
- opacity = 0
- density = 0
- anchored = 0.0
origin_tech = "materials=2"
- var/darts = 5
+ mag_type = MAGAZINE
+ caliber = "dart"
+ max_ammo = 5
+ multiple_sprites = 1
-/obj/item/weapon/dart_cartridge/update_icon()
- if(!darts)
- icon_state = "darts-0"
- else if(darts > 5)
- icon_state = "darts-5"
- else
- icon_state = "darts-[darts]"
- return 1
-
-/obj/item/weapon/gun/dartgun
+/obj/item/weapon/gun/projectile/dartgun
name = "dart gun"
desc = "A small gas-powered dartgun, capable of delivering chemical cocktails swiftly across short distances."
icon_state = "dartgun-empty"
+ caliber = "dart"
+ fire_sound = 'sound/weapons/empty.ogg'
+ fire_sound_text = "a metallic click"
+ recoil = 0
+ silenced = 1
+ load_method = MAGAZINE
+ magazine_type = /obj/item/ammo_magazine/chemdart
+ auto_eject = 0
+
var/list/beakers = list() //All containers inside the gun.
var/list/mixing = list() //Containers being used for mixing.
- var/obj/item/weapon/dart_cartridge/cartridge = null //Container of darts.
var/max_beakers = 3
var/dart_reagent_amount = 15
var/container_type = /obj/item/weapon/reagent_containers/glass/beaker
var/list/starting_chems = null
-/obj/item/weapon/gun/dartgun/update_icon()
-
- if(!cartridge)
- icon_state = "dartgun-empty"
- return 1
-
- if(!cartridge.darts)
- icon_state = "dartgun-0"
- else if(cartridge.darts > 5)
- icon_state = "dartgun-5"
- else
- icon_state = "dartgun-[cartridge.darts]"
- return 1
-
-/obj/item/weapon/gun/dartgun/New()
-
+/obj/item/weapon/gun/projectile/dartgun/dartgun/New()
..()
if(starting_chems)
for(var/chem in starting_chems)
var/obj/B = new container_type(src)
- B.reagents.add_reagent(chem, 50)
+ B.reagents.add_reagent(chem, 60)
beakers += B
- cartridge = new /obj/item/weapon/dart_cartridge(src)
update_icon()
-/obj/item/weapon/gun/dartgun/examine(mob/user)
- update_icon()
- if (!..(user, 2))
- return
+/obj/item/weapon/gun/projectile/dartgun/update_icon()
+ if(!ammo_magazine)
+ icon_state = "dartgun-empty"
+ return 1
+
+ if(!ammo_magazine.stored_ammo || ammo_magazine.stored_ammo.len)
+ icon_state = "dartgun-0"
+ else if(ammo_magazine.stored_ammo.len > 5)
+ icon_state = "dartgun-5"
+ else
+ icon_state = "dartgun-[ammo_magazine.stored_ammo.len]"
+ return 1
+
+/obj/item/weapon/gun/projectile/dartgun/consume_next_projectile()
+ . = ..()
+ var/obj/item/projectile/bullet/chemdart/dart = .
+ if(istype(dart))
+ fill_dart(dart)
+
+/obj/item/weapon/gun/projectile/dartgun/examine(mob/user)
+ //update_icon()
+ //if (!..(user, 2))
+ // return
+ ..()
if (beakers.len)
user << "\blue [src] contains:"
for(var/obj/item/weapon/reagent_containers/glass/beaker/B in beakers)
@@ -68,28 +96,7 @@
for(var/datum/reagent/R in B.reagents.reagent_list)
user << "\blue [R.volume] units of [R.name]"
-/obj/item/weapon/gun/dartgun/attackby(obj/item/I as obj, mob/user as mob)
- if(istype(I, /obj/item/weapon/dart_cartridge))
-
- var/obj/item/weapon/dart_cartridge/D = I
-
- if(!D.darts)
- user << "\blue [D] is empty."
- return 0
-
- if(cartridge)
- if(cartridge.darts <= 0)
- src.remove_cartridge()
- else
- user << "\blue There's already a cartridge in [src]."
- return 0
-
- user.drop_item()
- cartridge = D
- D.loc = src
- user << "\blue You slot [D] into [src]."
- update_icon()
- return
+/obj/item/weapon/gun/projectile/dartgun/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/weapon/reagent_containers/glass))
if(!istype(I, container_type))
user << "\blue [I] doesn't seem to fit into [src]."
@@ -103,112 +110,16 @@
beakers += B
user << "\blue You slot [B] into [src]."
src.updateUsrDialog()
-
-/obj/item/weapon/gun/dartgun/can_fire()
- if(!cartridge)
- return 0
- else
- return cartridge.darts
-
-/obj/item/weapon/gun/dartgun/proc/has_selected_beaker_reagents()
- return 0
-
-/obj/item/weapon/gun/dartgun/proc/remove_cartridge()
- if(cartridge)
- usr << "\blue You pop the cartridge out of [src]."
- var/obj/item/weapon/dart_cartridge/C = cartridge
- C.loc = get_turf(src)
- C.update_icon()
- cartridge = null
- src.update_icon()
-
-/obj/item/weapon/gun/dartgun/proc/get_mixed_syringe()
- if (!cartridge)
- return 0
- if(!cartridge.darts)
- return 0
-
- var/obj/item/weapon/reagent_containers/syringe/dart = new(src)
-
- if(mixing.len)
- var/mix_amount = dart_reagent_amount/mixing.len
- for(var/obj/item/weapon/reagent_containers/glass/beaker/B in mixing)
- B.reagents.trans_to(dart,mix_amount)
-
- return dart
-
-/obj/item/weapon/gun/dartgun/proc/fire_dart(atom/target, mob/user)
- if (locate (/obj/structure/table, src.loc))
- return
- else
- var/turf/trg = get_turf(target)
- var/obj/effect/syringe_gun_dummy/D = new/obj/effect/syringe_gun_dummy(get_turf(src))
- var/obj/item/weapon/reagent_containers/syringe/S = get_mixed_syringe()
- if(!S)
- user << "\red There are no darts in [src]!"
- return
- if(!S.reagents)
- user << "\red There are no reagents available!"
- return
- cartridge.darts--
- src.update_icon()
- S.reagents.trans_to(D, S.reagents.total_volume)
- del(S)
- D.icon_state = "syringeproj"
- D.name = "syringe"
- D.flags |= NOREACT
- playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1)
-
- for(var/i=0, i<6, i++)
- if(!D) break
- if(D.loc == trg) break
- step_towards(D,trg)
-
- if(D)
- for(var/mob/living/carbon/M in D.loc)
- if(!istype(M,/mob/living/carbon)) continue
- if(M == user) continue
- //Syringe gun attack logging by Yvarov
- var/R
- if(D.reagents)
- for(var/datum/reagent/A in D.reagents.reagent_list)
- R += A.id + " ("
- R += num2text(A.volume) + "),"
- if (istype(M, /mob))
- M.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] shot [M]/[M.ckey] with a dartgun ([R])"
- user.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] shot [M]/[M.ckey] with a dartgun ([R])"
- msg_admin_attack("[user] ([user.ckey]) shot [M] ([M.ckey]) with a dartgun ([R]) (JMP)")
-
- else
- M.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [M]/[M.ckey] with a dartgun ([R])"
- msg_admin_attack("UNKNOWN shot [M] ([M.ckey]) with a dartgun ([R]) (JMP)")
-
- if(D.reagents)
- D.reagents.trans_to(M, 15)
- M << "You feel a slight prick."
-
- del(D)
- break
- if(D)
- for(var/atom/A in D.loc)
- if(A == user) continue
- if(A.density) del(D)
-
- sleep(1)
-
- if (D) spawn(10) del(D)
-
- return
-
-/obj/item/weapon/gun/dartgun/afterattack(obj/target, mob/user , flag)
- if(!isturf(target.loc) || target == user) return
..()
-/obj/item/weapon/gun/dartgun/can_hit(var/mob/living/target as mob, var/mob/living/user as mob)
- return 1
-
-/obj/item/weapon/gun/dartgun/attack_self(mob/user)
+//fills the given dart with reagents
+/obj/item/weapon/gun/projectile/dartgun/proc/fill_dart(var/obj/item/projectile/bullet/chemdart/dart)
+ if(mixing.len)
+ var/mix_amount = dart.reagent_amount/mixing.len
+ for(var/obj/item/weapon/reagent_containers/glass/beaker/B in mixing)
+ B.reagents.trans_to(dart, mix_amount)
+/obj/item/weapon/gun/projectile/dartgun/attack_self(mob/user)
user.set_machine(src)
var/dat = "[src] mixing control:
"
@@ -230,9 +141,9 @@
else
dat += "There are no beakers inserted!
"
- if(cartridge)
- if(cartridge.darts)
- dat += "The dart cartridge has [cartridge.darts] shots remaining."
+ if(ammo_magazine)
+ if(ammo_magazine.stored_ammo && ammo_magazine.stored_ammo.len)
+ dat += "The dart cartridge has [ammo_magazine.stored_ammo.len] shots remaining."
else
dat += "The dart cartridge is empty!"
dat += " \[Eject\]"
@@ -240,7 +151,7 @@
user << browse(dat, "window=dartgun")
onclose(user, "dartgun", src)
-/obj/item/weapon/gun/dartgun/proc/check_beaker_mixing(var/obj/item/B)
+/obj/item/weapon/gun/projectile/dartgun/proc/check_beaker_mixing(var/obj/item/B)
if(!mixing || !beakers)
return 0
for(var/obj/item/M in mixing)
@@ -248,7 +159,7 @@
return 1
return 0
-/obj/item/weapon/gun/dartgun/Topic(href, href_list)
+/obj/item/weapon/gun/projectile/dartgun/Topic(href, href_list)
src.add_fingerprint(usr)
if(href_list["stop_mix"])
var/index = text2num(href_list["stop_mix"])
@@ -271,23 +182,16 @@
beakers -= B
B.loc = get_turf(src)
else if (href_list["eject_cart"])
- remove_cartridge()
+ unload_ammo(usr)
src.updateUsrDialog()
return
-/obj/item/weapon/gun/dartgun/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
- if(cartridge)
- spawn(0) fire_dart(target,user)
- else
- usr << "\red [src] is empty."
-
-
-/obj/item/weapon/gun/dartgun/vox
+/obj/item/weapon/gun/projectile/dartgun/vox
name = "alien dart gun"
desc = "A small gas-powered dartgun, fitted for nonhuman hands."
-/obj/item/weapon/gun/dartgun/vox/medical
+/obj/item/weapon/gun/projectile/dartgun/vox/medical
starting_chems = list("kelotane","bicaridine","anti_toxin")
-/obj/item/weapon/gun/dartgun/vox/raider
+/obj/item/weapon/gun/projectile/dartgun/vox/raider
starting_chems = list("space_drugs","stoxin","impedrezene")
\ No newline at end of file
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index c1d9b0fdec8..8aa34a7dcab 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -18,6 +18,7 @@
w_class = 1
sharp = 1
var/mode = SYRINGE_DRAW
+ var/image/filling //holds a reference to the current filling overlay
on_reagent_change()
update_icon()
@@ -217,7 +218,7 @@
item_state = "syringe_[rounded_vol]"
if(reagents.total_volume)
- var/image/filling = image('icons/obj/reagentfillings.dmi', src, "syringe10")
+ filling = image('icons/obj/reagentfillings.dmi', src, "syringe10")
filling.icon_state = "syringe[rounded_vol]"
@@ -225,7 +226,7 @@
overlays += filling
- /obj/item/weapon/reagent_containers/syringe/proc/syringestab(mob/living/carbon/target as mob, mob/living/carbon/user as mob)
+ proc/syringestab(mob/living/carbon/target as mob, mob/living/carbon/user as mob)
user.attack_log += "\[[time_stamp()]\] Attacked [target.name] ([target.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])"
target.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])"
@@ -268,13 +269,19 @@
src.reagents.reaction(target, INGEST)
var/syringestab_amount_transferred = rand(0, (reagents.total_volume - 5)) //nerfed by popular demand
src.reagents.trans_to(target, syringestab_amount_transferred)
+ src.break_syringe(target, user)
+
+ proc/break_syringe(mob/living/carbon/target, mob/living/carbon/user)
src.desc += " It is broken."
src.mode = SYRINGE_BROKEN
- src.add_blood(target)
- src.add_fingerprint(usr)
+ if(target)
+ src.add_blood(target)
+ if(user)
+ src.add_fingerprint(user)
src.update_icon()
+
/obj/item/weapon/reagent_containers/ld50_syringe
name = "Lethal Injection Syringe"
desc = "A syringe used for lethal injections."
diff --git a/code/modules/reagents/syringe_gun.dm b/code/modules/reagents/syringe_gun.dm
index faecb798681..23a9eaa36b0 100644
--- a/code/modules/reagents/syringe_gun.dm
+++ b/code/modules/reagents/syringe_gun.dm
@@ -1,137 +1,130 @@
+/obj/item/ammo_casing/gas_cartridge
+ name = "compressed gas cartridge"
+ desc = "An impact-triggered compressed gas cartridge that can fitted to a syringe for rapid injection. It's not very useful until primed though." //i.e. only works when shot out of a syringe gun.
+ icon_state = "syringe-cartridge"
+ caliber = "syringe"
+ projectile_type = /obj/item/projectile/bullet/syringe
+ w_class = 2 //mainly so that they can be yanked out
+ var/obj/item/weapon/reagent_containers/syringe/syringe
+/obj/item/ammo_casing/gas_cartridge/update_icon()
+ underlays.Cut()
+ if(syringe)
+ underlays += image(syringe.icon, src, syringe.icon_state)
+ underlays += syringe.filling
+/obj/item/ammo_casing/gas_cartridge/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/weapon/reagent_containers/syringe))
+ syringe = I
+ user << "You carefully insert [syringe] into [src]."
+ user.remove_from_mob(syringe)
+ syringe.loc = src
+ var/obj/item/projectile/bullet/syringe/S = BB
+ if(istype(S))
+ S.damage = 1
+ S.sharp = 1
+ update_icon()
-/obj/item/weapon/gun/syringe
+/obj/item/ammo_casing/gas_cartridge/attack_self(mob/user)
+ if(syringe)
+ user << "You remove [syringe] from [src]."
+ user.put_in_hands(syringe)
+ syringe = null
+ var/obj/item/projectile/bullet/syringe/S = BB
+ if(istype(S))
+ S.damage = initial(S.damage)
+ S.sharp = initial(S.sharp)
+ update_icon()
+
+//This was kind of rushed, there may very well be a simpler way to implement this.
+//Sort of hacky, though nearly not as bad as the previous implementation:
+//Basically the syringe gun is supposed to launch the entire syringe+cartrige assemby, but hitby() isn't powerfull enough to do what we need.
+//Instead, we fire a projectile that transfers the reagents, and teleport the cartridge once we impact something.
+/obj/item/projectile/bullet/syringe
+ name = "syringe dart"
+ icon_state = "cbbolt"
+ damage = 3
+ check_armour = "bullet"
+ sharp = 0
+ embed = 0 //we handle this ourselves
+ var/obj/item/ammo_casing/gas_cartridge/cartridge
+ var/embedded = 0
+ kill_count = 10 //short range
+
+/obj/item/projectile/bullet/syringe/New(newloc)
+ ..()
+ //ensure that cartridge is always set
+ cartridge = newloc
+ if(!istype(cartridge))
+ del(src)
+
+/obj/item/projectile/bullet/syringe/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null)
+ //..() //not really necessary
+ if(blocked < 2 && cartridge.syringe && isliving(target))
+ var/mob/living/L = target
+
+ //inject
+ if(L.can_inject(target_zone=def_zone))
+ if(cartridge.syringe.reagents)
+ cartridge.syringe.reagents.trans_to(L, 15)
+ cartridge.syringe.update_icon()
+ cartridge.update_icon()
+
+ //embed
+ L.embed(cartridge, def_zone)
+ embedded = 1
+
+/obj/item/projectile/bullet/syringe/on_impact(atom/A)
+ if(!embedded)
+ cartridge.loc = src.loc
+ if(cartridge.syringe)
+ cartridge.syringe.break_syringe(iscarbon(A)? A : null)
+ cartridge.update_icon()
+
+
+
+/obj/item/weapon/gun/projectile/syringe
name = "syringe gun"
desc = "A spring loaded rifle designed to fit syringes, designed to incapacitate unruly patients from a distance."
icon = 'icons/obj/gun.dmi'
icon_state = "syringegun"
item_state = "syringegun"
- w_class = 3.0
- throw_speed = 2
- throw_range = 10
- force = 4.0
- var/list/syringes = new/list()
- var/max_syringes = 1
+ w_class = 3
+ force = 7
matter = list("metal" = 2000)
+ slot_flags = SLOT_BELT
+
+ caliber = "syringe"
+ fire_sound = 'sound/weapons/empty.ogg'
+ fire_sound_text = "a metallic thunk"
+ recoil = 0
+ handle_casings = HOLD_CASINGS
+ load_method = SINGLE_CASING
+ max_shells = 1
+ var/drawn = 0
-/obj/item/weapon/gun/syringe/examine(mob/user)
- if(..(user, 2))
- user << "\blue [syringes.len] / [max_syringes] syringes."
+/obj/item/weapon/gun/projectile/syringe/consume_next_projectile()
+ if(chambered)
+ return chambered.BB
+ return null
-/obj/item/weapon/gun/syringe/attackby(obj/item/I as obj, mob/user as mob)
- if(istype(I, /obj/item/weapon/reagent_containers/syringe))
- var/obj/item/weapon/reagent_containers/syringe/S = I
- if(S.mode != 2)//SYRINGE_BROKEN in syringes.dm
- if(syringes.len < max_syringes)
- user.drop_item()
- I.loc = src
- syringes += I
- user << "\blue You put the syringe in [src]."
- user << "\blue [syringes.len] / [max_syringes] syringes."
- else
- usr << "\red [src] cannot hold more syringes."
- else
- usr << "\red This syringe is broken!"
+/obj/item/weapon/gun/projectile/syringe/attack_self(mob/living/user as mob)
+ if(!chambered && loaded.len)
+ playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1)
+ user.visible_message("[user] draws back the bolt on [src], clicking it into place.", "You draw back the bolt on the [src], loading the spring!")
+ var/obj/item/ammo_casing/AC = loaded[1] //load next casing.
+ loaded -= AC //Remove casing from loaded list.
+ chambered = AC
+ max_shells -= 1 //to prevent people from storing an extra syringe
+ update_icon()
-
-/obj/item/weapon/gun/syringe/afterattack(obj/target, mob/user , flag)
- if(!isturf(target.loc) || target == user) return
+/obj/item/weapon/gun/projectile/syringe/handle_post_fire()
..()
+ chambered = null
+ max_shells = initial(max_shells)
-/obj/item/weapon/gun/syringe/can_fire()
- return syringes.len
-
-/obj/item/weapon/gun/syringe/can_hit(var/mob/living/target as mob, var/mob/living/user as mob)
- return 1 //SHOOT AND LET THE GOD GUIDE IT (probably will hit a wall anyway)
-
-/obj/item/weapon/gun/syringe/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
- if(syringes.len)
- spawn(0) fire_syringe(target,user)
- else
- usr << "\red [src] is empty."
-
-/obj/item/weapon/gun/syringe/proc/fire_syringe(atom/target, mob/user)
- if (locate (/obj/structure/table, src.loc))
- return
- else
- var/turf/trg = get_turf(target)
- var/obj/effect/syringe_gun_dummy/D = new/obj/effect/syringe_gun_dummy(get_turf(src))
- var/obj/item/weapon/reagent_containers/syringe/S = syringes[1]
- if((!S) || (!S.reagents)) //ho boy! wot runtimes!
- return
- S.reagents.trans_to(D, S.reagents.total_volume)
- syringes -= S
- del(S)
- D.icon_state = "syringeproj"
- D.name = "syringe"
- playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1)
-
- for(var/i=0, i<6, i++)
- if(!D) break
- if(D.loc == trg) break
- step_towards(D,trg)
-
- if(D)
- for(var/mob/living/carbon/M in D.loc)
- if(!istype(M,/mob/living/carbon)) continue
- if(M == user) continue
- //Syringe gun attack logging by Yvarov
- var/R
- if(D.reagents)
- for(var/datum/reagent/A in D.reagents.reagent_list)
- R += A.id + " ("
- R += num2text(A.volume) + "),"
- if (istype(M, /mob))
- M.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] shot [M]/[M.ckey] with a syringegun ([R])"
- user.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] shot [M]/[M.ckey] with a syringegun ([R])"
- msg_admin_attack("[user] ([user.ckey]) shot [M] ([M.ckey]) with a syringegun ([R]) (JMP)")
-
- else
- M.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [M]/[M.ckey] with a syringegun ([R])"
- msg_admin_attack("UNKNOWN shot [M] ([M.ckey]) with a syringegun ([R]) (JMP)")
-
- var/mob/living/T
- if(istype(M,/mob/living))
- T = M
-
- M.visible_message("[M] is hit by the syringe!")
-
- if(T && istype(T) && T.can_inject())
- if(D.reagents)
- D.reagents.trans_to(M, 15)
- else
- M.visible_message("The syringe bounces off [M]!")
-
- del(D)
- break
- if(D)
- for(var/atom/A in D.loc)
- if(A == user) continue
- if(A.density) del(D)
-
- sleep(1)
-
- if (D) spawn(10) del(D)
-
- return
-
-/obj/item/weapon/gun/syringe/rapidsyringe
+/obj/item/weapon/gun/projectile/syringe/rapid
name = "rapid syringe gun"
- desc = "A modification of the syringe gun design, using a rotating cylinder to store up to four syringes."
+ desc = "A modification of the syringe gun design, using a rotating cylinder to store up to four syringes. The spring still needs to be drawn between shots."
icon_state = "rapidsyringegun"
- max_syringes = 4
-
-
-/obj/effect/syringe_gun_dummy
- name = ""
- desc = ""
- icon = 'icons/obj/chemical.dmi'
- icon_state = "null"
- anchored = 1
- density = 0
-
- New()
- var/datum/reagents/R = new/datum/reagents(15)
- reagents = R
- R.my_atom = src
\ No newline at end of file
+ max_shells = 4
diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm
index e04618cf208..faf7e34d98d 100644
--- a/code/modules/research/designs.dm
+++ b/code/modules/research/designs.dm
@@ -451,7 +451,7 @@ datum/design/circuit/tcom/server
name = "server mainframe"
id = "tcom-server"
build_path = /obj/item/weapon/circuitboard/telecomms/server
-
+
datum/design/circuit/tcom/processor
name = "processor unit"
id = "tcom-processor"
@@ -1312,7 +1312,7 @@ datum/design/item/weapon/rapidsyringe
id = "rapidsyringe"
req_tech = list("combat" = 3, "materials" = 3, "engineering" = 3, "biotech" = 2)
materials = list("$metal" = 5000, "$glass" = 1000)
- build_path = /obj/item/weapon/gun/syringe/rapidsyringe
+ build_path = /obj/item/weapon/gun/projectile/syringe/rapid
/*
datum/design/item/weapon/largecrossbow
name = "Energy Crossbow"
@@ -1567,7 +1567,7 @@ datum/design/item/mesons
req_tech = list("magnets" = 2, "engineering" = 2)
materials = list("$metal" = 50, "$glass" = 50)
build_path = /obj/item/clothing/glasses/meson
-
+
datum/design/item/binaryencrypt
name = "Binary encryption key"
desc = "Allows for deciphering the binary channel on-the-fly."
diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi
index c1e14968f80..acade2ce1b2 100644
Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ
diff --git a/icons/obj/syringe.dmi b/icons/obj/syringe.dmi
index 2adc34b05be..a9a46f6046d 100644
Binary files a/icons/obj/syringe.dmi and b/icons/obj/syringe.dmi differ
diff --git a/maps/exodus-1.dmm b/maps/exodus-1.dmm
index 73cb64ef9eb..93792aea278 100644
--- a/maps/exodus-1.dmm
+++ b/maps/exodus-1.dmm
@@ -5795,7 +5795,7 @@
"chw" = (/obj/structure/sign/biohazard,/turf/simulated/wall,/area/medical/virologyaccess)
"chx" = (/obj/structure/disposaloutlet,/obj/structure/disposalpipe/trunk{dir = 1},/turf/simulated/floor/plating/airless,/area/medical/virology)
"chy" = (/obj/structure/bedsheetbin,/obj/structure/table,/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/green,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor{icon_state = "dark"},/area/medical/biostorage)
-"chz" = (/obj/structure/table,/obj/item/bodybag/cryobag{pixel_x = -3},/obj/item/bodybag/cryobag{pixel_x = -3},/obj/item/weapon/gun/syringe,/turf/simulated/floor{icon_state = "dark"},/area/medical/biostorage)
+"chz" = (/obj/structure/table,/obj/item/bodybag/cryobag{pixel_x = -3},/obj/item/bodybag/cryobag{pixel_x = -3},/obj/item/weapon/gun/projectile/syringe,/obj/item/weapon/storage/box/syringegun,/turf/simulated/floor{icon_state = "dark"},/area/medical/biostorage)
"chA" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/maintenance/research_port)
"chB" = (/turf/simulated/floor/plating,/area/maintenance/research_port)
"chC" = (/obj/machinery/door/airlock/medical{autoclose = 0; icon_state = "door_open"; id_tag = "cubicle1"; name = "Cubicle 1"},/turf/simulated/floor{icon_state = "freezerfloor"},/area/medical/patient_wing)
diff --git a/maps/exodus-2.dmm b/maps/exodus-2.dmm
index 944bc52a02d..79dafb5423f 100644
--- a/maps/exodus-2.dmm
+++ b/maps/exodus-2.dmm
@@ -1912,7 +1912,7 @@
"KN" = (/obj/machinery/atmospherics/pipe/tank/nitrogen{dir = 1; initialize_directions = 1; start_pressure = 493.6},/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
"KO" = (/obj/machinery/portable_atmospherics/canister/phoron,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
"KP" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
-"KQ" = (/obj/structure/table/rack,/obj/item/weapon/gun/dartgun/vox/raider,/obj/item/weapon/gun/dartgun/vox/medical,/obj/item/weapon/dart_cartridge,/obj/item/weapon/dart_cartridge,/obj/item/weapon/dart_cartridge,/obj/item/weapon/dart_cartridge,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
+"KQ" = (/obj/structure/table/rack,/obj/item/weapon/gun/projectile/dartgun/vox/raider,/obj/item/weapon/gun/projectile/dartgun/vox/medical,/obj/item/ammo_magazine/chemdart,/obj/item/ammo_magazine/chemdart,/obj/item/ammo_magazine/chemdart,/obj/item/ammo_magazine/chemdart,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
"KR" = (/obj/structure/table/rack,/obj/item/clothing/accessory/storage/black_vest,/obj/item/clothing/suit/space/vox/medic,/obj/item/clothing/head/helmet/space/vox/medic,/obj/item/clothing/mask/breath,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
"KS" = (/obj/structure/table/rack,/obj/item/weapon/gun/launcher/pneumatic,/obj/item/weapon/harpoon,/obj/item/weapon/harpoon,/obj/item/weapon/harpoon,/obj/item/weapon/harpoon,/obj/item/weapon/tank/nitrogen,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
"KT" = (/obj/structure/table/rack,/obj/item/clothing/accessory/storage/black_vest,/obj/item/clothing/suit/space/vox/pressure,/obj/item/clothing/head/helmet/space/vox/pressure,/obj/item/clothing/mask/breath,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)