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)