diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index 95f1cb283c..27f366f7f8 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -24458,7 +24458,7 @@
/area/crew_quarters/heads/captain)
"bfE" = (
/obj/structure/table/wood,
-/obj/item/pinpointer,
+/obj/item/pinpointer/nuke,
/obj/item/disk/nuclear,
/obj/item/storage/secure/safe{
pixel_x = 35;
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 5e0ded4416..0484d95b79 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -53210,7 +53210,7 @@
/area/tcommsat/server)
"bYo" = (
/obj/structure/table/wood,
-/obj/item/pinpointer,
+/obj/item/pinpointer/nuke,
/obj/item/disk/nuclear,
/obj/item/device/radio/intercom{
name = "Station Intercom";
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index ec76a564d5..a60e43dd83 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -29108,7 +29108,7 @@
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/table/wood,
-/obj/item/pinpointer,
+/obj/item/pinpointer/nuke,
/obj/item/disk/nuclear,
/turf/open/floor/carpet,
/area/crew_quarters/heads/captain/private)
diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm
index 207a64fe5d..419737682f 100644
--- a/_maps/map_files/OmegaStation/OmegaStation.dmm
+++ b/_maps/map_files/OmegaStation/OmegaStation.dmm
@@ -1187,7 +1187,7 @@
pixel_x = 32;
pixel_y = 24
},
-/obj/item/pinpointer,
+/obj/item/pinpointer/nuke,
/obj/item/disk/nuclear,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 10
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index 502f7ba293..66a9216882 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -13917,7 +13917,7 @@
/area/storage/primary)
"aEx" = (
/obj/structure/table/wood,
-/obj/item/pinpointer,
+/obj/item/pinpointer/nuke,
/obj/item/disk/nuclear,
/obj/machinery/light{
dir = 8
diff --git a/code/__DEFINES/pinpointers.dm b/code/__DEFINES/pinpointers.dm
index 80403e54de..75f0452ea9 100644
--- a/code/__DEFINES/pinpointers.dm
+++ b/code/__DEFINES/pinpointers.dm
@@ -2,6 +2,3 @@
#define TRACK_NUKE_DISK 1 //We track the nuclear authentication disk, either to protect it or steal it
#define TRACK_MALF_AI 2 //We track the malfunctioning AI, so we can prevent it from blowing us all up
#define TRACK_INFILTRATOR 3 //We track the Syndicate infiltrator, so we can get back to ship when the nuke's armed
-#define TRACK_OPERATIVES 4 //We track the closest operative, so we can regroup when we need to
-#define TRACK_ATOM 5 //We track a specified atom, so admins can make us function for events
-#define TRACK_COORDINATES 6 //We point towards the specified coordinates on our z-level, so we can navigate
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index 24d5311af3..8b16b2b0d5 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -309,8 +309,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
owner_AI.nuking = TRUE
owner_AI.doomsday_device = DOOM
owner_AI.doomsday_device.start()
- for(var/pinpointer in GLOB.pinpointer_list)
- var/obj/item/pinpointer/P = pinpointer
+ for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list)
P.switch_mode_to(TRACK_MALF_AI) //Pinpointers start tracking the AI wherever it goes
qdel(src)
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm.rej b/code/game/gamemodes/malfunction/Malf_Modules.dm.rej
new file mode 100644
index 0000000000..97dbe2bbdb
--- /dev/null
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm.rej
@@ -0,0 +1,11 @@
+diff a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm (rejected hunks)
+@@ -309,8 +309,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
+ owner_AI.nuking = TRUE
+ owner_AI.doomsday_device = DOOM
+ owner_AI.doomsday_device.start()
+- for(var/pinpointer in GLOB.pinpointer_list)
+- var/obj/item/weapon/pinpointer/P = pinpointer
++ for(var/obj/item/weapon/pinpointer/nuke/P in GLOB.pinpointer_list)
+ P.switch_mode_to(TRACK_MALF_AI) //Pinpointers start tracking the AI wherever it goes
+ qdel(src)
+
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 59650561a6..1b1bec68c1 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -325,7 +325,7 @@
gloves = /obj/item/clothing/gloves/combat
back = /obj/item/storage/backpack
ears = /obj/item/device/radio/headset/syndicate/alt
- l_pocket = /obj/item/pinpointer/syndicate
+ l_pocket = /obj/item/pinpointer/nuke/syndicate
id = /obj/item/card/id/syndicate
belt = /obj/item/gun/ballistic/automatic/pistol
backpack_contents = list(/obj/item/storage/box/syndie=1)
diff --git a/code/game/gamemodes/nuclear/nuclear.dm.rej b/code/game/gamemodes/nuclear/nuclear.dm.rej
new file mode 100644
index 0000000000..19648547c7
--- /dev/null
+++ b/code/game/gamemodes/nuclear/nuclear.dm.rej
@@ -0,0 +1,10 @@
+diff a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm (rejected hunks)
+@@ -325,7 +325,7 @@
+ gloves = /obj/item/clothing/gloves/combat
+ back = /obj/item/weapon/storage/backpack
+ ears = /obj/item/device/radio/headset/syndicate/alt
+- l_pocket = /obj/item/weapon/pinpointer/syndicate
++ l_pocket = /obj/item/weapon/pinpointer/nuke/syndicate
+ id = /obj/item/weapon/card/id/syndicate
+ belt = /obj/item/weapon/gun/ballistic/automatic/pistol
+ backpack_contents = list(/obj/item/weapon/storage/box/syndie=1)
diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index ee611349f8..95fc735ec6 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -362,9 +362,9 @@
if(safety)
if(timing)
set_security_level(previous_level)
- for(var/obj/item/pinpointer/syndicate/S in GLOB.pinpointer_list)
+ for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
S.switch_mode_to(initial(S.mode))
- S.nuke_warning = FALSE
+ S.alert = FALSE
timing = FALSE
bomb_set = TRUE
detonation_timer = null
@@ -381,16 +381,16 @@
bomb_set = TRUE
set_security_level("delta")
detonation_timer = world.time + (timer_set * 10)
- for(var/obj/item/pinpointer/syndicate/S in GLOB.pinpointer_list)
+ for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
S.switch_mode_to(TRACK_INFILTRATOR)
countdown.start()
else
bomb_set = FALSE
detonation_timer = null
set_security_level(previous_level)
- for(var/obj/item/pinpointer/syndicate/S in GLOB.pinpointer_list)
+ for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
S.switch_mode_to(initial(S.mode))
- S.nuke_warning = FALSE
+ S.alert = FALSE
countdown.stop()
update_icon()
diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm.rej b/code/game/gamemodes/nuclear/nuclearbomb.dm.rej
new file mode 100644
index 0000000000..6a35e91cde
--- /dev/null
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm.rej
@@ -0,0 +1,33 @@
+diff a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm (rejected hunks)
+@@ -362,9 +362,9 @@
+ if(safety)
+ if(timing)
+ set_security_level(previous_level)
+- for(var/obj/item/weapon/pinpointer/syndicate/S in GLOB.pinpointer_list)
++ for(var/obj/item/weapon/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
+ S.switch_mode_to(initial(S.mode))
+- S.nuke_warning = FALSE
++ S.alert = FALSE
+ timing = FALSE
+ bomb_set = TRUE
+ detonation_timer = null
+@@ -381,16 +381,16 @@
+ bomb_set = TRUE
+ set_security_level("delta")
+ detonation_timer = world.time + (timer_set * 10)
+- for(var/obj/item/weapon/pinpointer/syndicate/S in GLOB.pinpointer_list)
++ for(var/obj/item/weapon/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
+ S.switch_mode_to(TRACK_INFILTRATOR)
+ countdown.start()
+ else
+ bomb_set = FALSE
+ detonation_timer = null
+ set_security_level(previous_level)
+- for(var/obj/item/weapon/pinpointer/syndicate/S in GLOB.pinpointer_list)
++ for(var/obj/item/weapon/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
+ S.switch_mode_to(initial(S.mode))
+- S.nuke_warning = FALSE
++ S.alert = FALSE
+ countdown.stop()
+ update_icon()
+
diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm
index 9f63309643..461ef78ef3 100644
--- a/code/game/gamemodes/nuclear/pinpointer.dm
+++ b/code/game/gamemodes/nuclear/pinpointer.dm
@@ -1,56 +1,7 @@
-//Pinpointers are used to track atoms from a distance as long as they're on the same z-level. The captain and nuke ops have ones that track the nuclear authentication disk.
-/obj/item/pinpointer
- name = "pinpointer"
- desc = "A handheld tracking device that locks onto certain signals."
- icon = 'icons/obj/device.dmi'
- icon_state = "pinoff"
- flags_1 = CONDUCT_1
- slot_flags = SLOT_BELT
- w_class = WEIGHT_CLASS_SMALL
- item_state = "electronic"
- lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
- throw_speed = 3
- throw_range = 7
- materials = list(MAT_METAL = 500, MAT_GLASS = 250)
- resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
- var/active = FALSE
- var/atom/movable/target = null //The thing we're searching for
- var/atom/movable/constant_target = null //The thing we're always focused on, if we're in the right mode
- var/target_x = 0 //The target coordinates if we're tracking those
- var/target_y = 0
- var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
- var/nuke_warning = FALSE // If we've set off a miniature alarm about an armed nuke
- var/mode = TRACK_NUKE_DISK //What are we looking for?
+/obj/item/pinpointer/nuke
+ var/mode = TRACK_NUKE_DISK
-/obj/item/pinpointer/New()
- ..()
- GLOB.pinpointer_list += src
-
-/obj/item/pinpointer/Destroy()
- STOP_PROCESSING(SSfastprocess, src)
- GLOB.pinpointer_list -= src
- return ..()
-
-/obj/item/pinpointer/attack_self(mob/living/user)
- active = !active
- user.visible_message("[user] [active ? "" : "de"]activates their pinpointer.", "You [active ? "" : "de"]activate your pinpointer.")
- playsound(user, 'sound/items/screwdriver2.ogg', 50, 1)
- icon_state = "pin[active ? "onnull" : "off"]"
- if(active)
- START_PROCESSING(SSfastprocess, src)
- else
- target = null //Restarting the pinpointer forces a target reset
- STOP_PROCESSING(SSfastprocess, src)
-
-/obj/item/pinpointer/attackby(obj/item/I, mob/living/user, params)
- if(mode != TRACK_ATOM)
- return ..()
- user.visible_message("[user] tunes [src] to [I].", "You fine-tune [src]'s tracking to track [I].")
- playsound(src, 'sound/machines/click.ogg', 50, 1)
- constant_target = I
-
-/obj/item/pinpointer/examine(mob/user)
+/obj/item/pinpointer/nuke/examine(mob/user)
..()
var/msg = "Its tracking indicator reads "
switch(mode)
@@ -60,12 +11,6 @@
msg += "\"01000001 01001001\"."
if(TRACK_INFILTRATOR)
msg += "\"vasvygengbefuvc\"."
- if(TRACK_OPERATIVES)
- msg += "\"[target ? "Operative [target]" : "friends"]\"."
- if(TRACK_ATOM)
- msg += "\"[initial(constant_target.name)]\"."
- if(TRACK_COORDINATES)
- msg += "\"([target_x], [target_y])\"."
else
msg = "Its tracking indicator is blank."
to_chat(user, msg)
@@ -73,22 +18,20 @@
if(bomb.timing)
to_chat(user, "Extreme danger. Arming signal detected. Time remaining: [bomb.get_time_left()]")
-/obj/item/pinpointer/process()
- if(!active)
- STOP_PROCESSING(SSfastprocess, src)
- return
- scan_for_target()
- point_to_target()
- my_god_jc_a_bomb()
- addtimer(CALLBACK(src, .proc/refresh_target), 50, TIMER_UNIQUE)
+/obj/item/pinpointer/nuke/process()
+ ..()
+ if(active) // If shit's going down
+ for(var/obj/machinery/nuclearbomb/bomb in GLOB.nuke_list)
+ if(bomb.timing)
+ if(!alert)
+ alert = TRUE
+ playsound(src, 'sound/items/nuke_toy_lowpower.ogg', 50, 0)
+ if(isliving(loc))
+ var/mob/living/L = loc
+ to_chat(L, "Your [name] vibrates and lets out a tinny alarm. Uh oh.")
-/obj/item/pinpointer/proc/scan_for_target() //Looks for whatever it's tracking
- if(target)
- if(isliving(target))
- var/mob/living/L = target
- if(L.stat == DEAD)
- target = null
- return
+/obj/item/pinpointer/nuke/scan_for_target()
+ target = null
switch(mode)
if(TRACK_NUKE_DISK)
var/obj/item/disk/nuclear/N = locate() in GLOB.poi_list
@@ -104,76 +47,36 @@
target = A
if(TRACK_INFILTRATOR)
target = SSshuttle.getShuttle("syndicate")
- if(TRACK_OPERATIVES)
- var/list/possible_targets = list()
- var/turf/here = get_turf(src)
- for(var/V in SSticker.mode.syndicates)
- var/datum/mind/M = V
- if(M.current && M.current.stat != DEAD)
- possible_targets |= M.current
- var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here)
- if(closest_operative)
- target = closest_operative
- if(TRACK_ATOM)
- if(constant_target)
- target = constant_target
- if(TRACK_COORDINATES)
- var/turf/T = get_turf(src)
- target = locate(target_x, target_y, T.z)
+ ..()
-/obj/item/pinpointer/proc/point_to_target() //If we found what we're looking for, show the distance and direction
- if(!active)
- return
- if(!target || (mode == TRACK_ATOM && !constant_target))
- icon_state = "pinon[nuke_warning ? "alert" : ""]null"
- return
- var/turf/here = get_turf(src)
- var/turf/there = get_turf(target)
- if(here.z != there.z)
- icon_state = "pinon[nuke_warning ? "alert" : ""]null"
- return
- if(get_dist_euclidian(here,there)<=minimum_range)
- icon_state = "pinon[nuke_warning ? "alert" : ""]direct"
- else
- setDir(get_dir(here, there))
- switch(get_dist(here, there))
- if(1 to 8)
- icon_state = "pinon[nuke_warning ? "alert" : "close"]"
- if(9 to 16)
- icon_state = "pinon[nuke_warning ? "alert" : "medium"]"
- if(16 to INFINITY)
- icon_state = "pinon[nuke_warning ? "alert" : "far"]"
-
-/obj/item/pinpointer/proc/my_god_jc_a_bomb() //If we should get the hell back to the ship
- for(var/obj/machinery/nuclearbomb/bomb in GLOB.nuke_list)
- if(bomb.timing)
- if(!nuke_warning)
- nuke_warning = TRUE
- playsound(src, 'sound/items/nuke_toy_lowpower.ogg', 50, 0)
- if(isliving(loc))
- var/mob/living/L = loc
- to_chat(L, "Your [name] vibrates and lets out a tinny alarm. Uh oh.")
-
-/obj/item/pinpointer/proc/switch_mode_to(new_mode) //If we shouldn't be tracking what we are
+/obj/item/pinpointer/nuke/proc/switch_mode_to(new_mode)
if(isliving(loc))
var/mob/living/L = loc
to_chat(L, "Your [name] beeps as it reconfigures its tracking algorithms.")
playsound(L, 'sound/machines/triple_beep.ogg', 50, 1)
mode = new_mode
- target = null //Switch modes so we can find the new target
+ scan_for_target()
-/obj/item/pinpointer/proc/refresh_target() //Periodically removes the target to allow the pinpointer to update (i.e. malf AI shunts, an operative dies)
- target = null
-
-/obj/item/pinpointer/syndicate //Syndicate pinpointers automatically point towards the infiltrator once the nuke is active.
+/obj/item/pinpointer/nuke/syndicate // Syndicate pinpointers automatically point towards the infiltrator once the nuke is active.
name = "syndicate pinpointer"
desc = "A handheld tracking device that locks onto certain signals. It's configured to switch tracking modes once it detects the activation signal of a nuclear device."
+ icon_state = "pinpointer_syndicate"
-/obj/item/pinpointer/syndicate/cyborg //Cyborg pinpointers just look for a random operative.
+/obj/item/pinpointer/syndicate_cyborg // Cyborg pinpointers just look for a random operative.
name = "cyborg syndicate pinpointer"
desc = "An integrated tracking device, jury-rigged to search for living Syndicate operatives."
- mode = TRACK_OPERATIVES
flags_1 = NODROP_1
-
+/obj/item/pinpointer/syndicate_cyborg/scan_for_target()
+ target = null
+ var/list/possible_targets = list()
+ var/turf/here = get_turf(src)
+ for(var/V in SSticker.mode.syndicates)
+ var/datum/mind/M = V
+ if(M.current && M.current.stat != DEAD)
+ possible_targets |= M.current
+ var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here)
+ if(closest_operative)
+ target = closest_operative
+ ..()
diff --git a/code/game/gamemodes/nuclear/pinpointer.dm.rej b/code/game/gamemodes/nuclear/pinpointer.dm.rej
new file mode 100644
index 0000000000..79d652af9b
--- /dev/null
+++ b/code/game/gamemodes/nuclear/pinpointer.dm.rej
@@ -0,0 +1,21 @@
+diff a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm (rejected hunks)
+@@ -30,7 +30,6 @@
+ var/mob/living/L = loc
+ to_chat(L, "Your [name] vibrates and lets out a tinny alarm. Uh oh.")
+
+-
+ /obj/item/pinpointer/nuke/scan_for_target()
+ target = null
+ switch(mode)
+@@ -58,10 +57,10 @@
+ mode = new_mode
+ scan_for_target()
+
+-
+ /obj/item/pinpointer/nuke/syndicate // Syndicate pinpointers automatically point towards the infiltrator once the nuke is active.
+ name = "syndicate pinpointer"
+ desc = "A handheld tracking device that locks onto certain signals. It's configured to switch tracking modes once it detects the activation signal of a nuclear device."
++ icon_state = "pinpointer_syndicate"
+
+ /obj/item/pinpointer/syndicate_cyborg // Cyborg pinpointers just look for a random operative.
+ name = "cyborg syndicate pinpointer"
diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm
index ba0f727203..c0aee8bb76 100644
--- a/code/game/gamemodes/objective_items.dm
+++ b/code/game/gamemodes/objective_items.dm
@@ -186,7 +186,7 @@
return ..()
//Old ninja objectives.
-/datum/objective_item/special/pinpointer
+/datum/objective_item/special/pinpointer/nuke
name = "the captain's pinpointer."
targetitem = /obj/item/pinpointer
difficulty = 10
diff --git a/code/game/gamemodes/objective_items.dm.rej b/code/game/gamemodes/objective_items.dm.rej
new file mode 100644
index 0000000000..3770d7eea9
--- /dev/null
+++ b/code/game/gamemodes/objective_items.dm.rej
@@ -0,0 +1,10 @@
+diff a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm (rejected hunks)
+@@ -158,7 +158,7 @@
+ difficulty = 10
+
+ //Old ninja objectives.
+-/datum/objective_item/special/pinpointer
++/datum/objective_item/special/pinpointer/nuke
+ name = "the captain's pinpointer."
+ targetitem = /obj/item/pinpointer
+ difficulty = 10
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 427bc95253..bf879f84da 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -869,7 +869,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
products = list(/obj/item/reagent_containers/syringe = 12, /obj/item/reagent_containers/dropper = 3, /obj/item/stack/medical/gauze = 8, /obj/item/reagent_containers/pill/patch/styptic = 5, /obj/item/reagent_containers/pill/insulin = 10,
/obj/item/reagent_containers/pill/patch/silver_sulf = 5, /obj/item/reagent_containers/glass/bottle/charcoal = 4, /obj/item/reagent_containers/spray/medical/sterilizer = 1,
/obj/item/reagent_containers/glass/bottle/epinephrine = 4, /obj/item/reagent_containers/glass/bottle/morphine = 4, /obj/item/reagent_containers/glass/bottle/salglu_solution = 3,
- /obj/item/reagent_containers/glass/bottle/toxin = 3, /obj/item/reagent_containers/syringe/antiviral = 6, /obj/item/reagent_containers/pill/salbutamol = 2, /obj/item/device/healthanalyzer = 4, /obj/item/device/sensor_device = 2)
+ /obj/item/reagent_containers/glass/bottle/toxin = 3, /obj/item/reagent_containers/syringe/antiviral = 6, /obj/item/reagent_containers/pill/salbutamol = 2, /obj/item/device/healthanalyzer = 4, /obj/item/device/sensor_device = 2, /obj/item/pinpointer/crew = 2)
contraband = list(/obj/item/reagent_containers/pill/tox = 3, /obj/item/reagent_containers/pill/morphine = 4, /obj/item/reagent_containers/pill/charcoal = 6)
premium = list(/obj/item/storage/box/hug/medical = 1, /obj/item/reagent_containers/hypospray/medipen = 3, /obj/item/storage/belt/medical = 3, /obj/item/wrench/medical = 1)
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50)
diff --git a/code/game/objects/items/devices/pinpointer.dm b/code/game/objects/items/devices/pinpointer.dm
new file mode 100644
index 0000000000..1d11f312a4
--- /dev/null
+++ b/code/game/objects/items/devices/pinpointer.dm
@@ -0,0 +1,152 @@
+//Pinpointers are used to track atoms from a distance as long as they're on the same z-level. The captain and nuke ops have ones that track the nuclear authentication disk.
+/obj/item/weapon/pinpointer
+ name = "pinpointer"
+ desc = "A handheld tracking device that locks onto certain signals."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "pinpointer"
+ flags = CONDUCT
+ slot_flags = SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
+ item_state = "electronic"
+ lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
+ throw_speed = 3
+ throw_range = 7
+ materials = list(MAT_METAL = 500, MAT_GLASS = 250)
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+ var/active = FALSE
+ var/atom/movable/target = null //The thing we're searching for
+ var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
+ var/alert = FALSE // TRUE to display things more seriously
+
+/obj/item/weapon/pinpointer/New()
+ ..()
+ GLOB.pinpointer_list += src
+
+/obj/item/weapon/pinpointer/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ GLOB.pinpointer_list -= src
+ return ..()
+
+/obj/item/weapon/pinpointer/attack_self(mob/living/user)
+ active = !active
+ user.visible_message("[user] [active ? "" : "de"]activates their pinpointer.", "You [active ? "" : "de"]activate your pinpointer.")
+ playsound(user, 'sound/items/screwdriver2.ogg', 50, 1)
+ if(active)
+ START_PROCESSING(SSfastprocess, src)
+ else
+ target = null
+ STOP_PROCESSING(SSfastprocess, src)
+ update_pointer_overlay()
+
+/obj/item/weapon/pinpointer/process()
+ if(!active)
+ STOP_PROCESSING(SSfastprocess, src)
+ return
+ scan_for_target()
+ update_pointer_overlay()
+
+/obj/item/weapon/pinpointer/proc/scan_for_target()
+ return
+
+/obj/item/weapon/pinpointer/proc/update_pointer_overlay()
+ cut_overlays()
+ if(!active)
+ return
+ if(!target)
+ add_overlay("pinon[alert ? "alert" : ""]null")
+ var/turf/here = get_turf(src)
+ var/turf/there = get_turf(target)
+ if(here.z != there.z)
+ add_overlay("pinon[alert ? "alert" : ""]null")
+ return
+ if(get_dist_euclidian(here,there) <= minimum_range)
+ add_overlay("pinon[alert ? "alert" : ""]direct")
+ else
+ setDir(get_dir(here, there))
+ switch(get_dist(here, there))
+ if(1 to 8)
+ add_overlay("pinon[alert ? "alert" : "close"]")
+ if(9 to 16)
+ add_overlay("pinon[alert ? "alert" : "medium"]")
+ if(16 to INFINITY)
+ add_overlay("pinon[alert ? "alert" : "far"]")
+
+/obj/item/weapon/pinpointer/crew // A replacement for the old crew monitoring consoles
+ name = "crew pinpointer"
+ desc = "A handheld tracking device that points to crew suit sensors."
+ icon_state = "pinpointer_crew"
+
+/obj/item/weapon/pinpointer/crew/proc/trackable(mob/living/carbon/human/H)
+ var/turf/here = get_turf(src)
+ if((H.z == 0 || H.z == here.z) && istype(H.w_uniform, /obj/item/clothing/under))
+ var/obj/item/clothing/under/U = H.w_uniform
+
+ // Suit sensors must be on maximum.
+ if(!U.has_sensor || U.sensor_mode < SENSOR_COORDS)
+ return FALSE
+
+ var/turf/there = get_turf(H)
+ return (H.z != 0 || (there && there.z == H.z))
+
+ return FALSE
+
+/obj/item/weapon/pinpointer/crew/attack_self(mob/living/user)
+ if(active)
+ active = FALSE
+ user.visible_message("[user] deactivates their pinpointer.", "You deactivate your pinpointer.")
+ playsound(user, 'sound/items/screwdriver2.ogg', 50, 1)
+ target = null //Restarting the pinpointer forces a target reset
+ STOP_PROCESSING(SSfastprocess, src)
+ update_pointer_overlay()
+ return
+
+ var/list/name_counts = list()
+ var/list/names = list()
+
+ for(var/mob/living/carbon/human/H in GLOB.mob_list)
+ if(!trackable(H))
+ continue
+
+ var/name = "Unknown"
+ if(H.wear_id)
+ var/obj/item/weapon/card/id/I = H.wear_id.GetID()
+ name = I.registered_name
+
+ while(name in name_counts)
+ name_counts[name]++
+ name = text("[] ([])", name, name_counts[name])
+ names[name] = H
+ name_counts[name] = 1
+
+ if(!names.len)
+ user.visible_message("[user]'s pinpointer fails to detect a signal.", "Your pinpointer fails to detect a signal.")
+ return
+
+ var/A = input(user, "Person to track", "Pinpoint") in names
+ if(!src || QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !A)
+ return
+
+ target = names[A]
+ active = TRUE
+ user.visible_message("[user] activates their pinpointer.", "You activate your pinpointer.")
+ playsound(user, 'sound/items/screwdriver2.ogg', 50, 1)
+ START_PROCESSING(SSfastprocess, src)
+ update_pointer_overlay()
+
+/obj/item/weapon/pinpointer/crew/scan_for_target()
+ if(target)
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ if(!trackable(H))
+ target = null
+ if(!target)
+ active = FALSE
+
+/obj/item/weapon/pinpointer/process()
+ if(!active)
+ STOP_PROCESSING(SSfastprocess, src)
+ return
+ scan_for_target()
+ update_pointer_overlay()
+
diff --git a/code/game/objects/items/pinpointer.dm b/code/game/objects/items/pinpointer.dm
new file mode 100644
index 0000000000..28488a231f
--- /dev/null
+++ b/code/game/objects/items/pinpointer.dm
@@ -0,0 +1,150 @@
+//Pinpointers are used to track atoms from a distance as long as they're on the same z-level. The captain and nuke ops have ones that track the nuclear authentication disk.
+/obj/item/pinpointer
+ name = "pinpointer"
+ desc = "A handheld tracking device that locks onto certain signals."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "pinpointer"
+ flags_1 = CONDUCT_1
+ slot_flags = SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
+ item_state = "electronic"
+ lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
+ throw_speed = 3
+ throw_range = 7
+ materials = list(MAT_METAL = 500, MAT_GLASS = 250)
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+ var/active = FALSE
+ var/atom/movable/target //The thing we're searching for
+ var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
+ var/alert = FALSE // TRUE to display things more seriously
+
+/obj/item/pinpointer/Initialize()
+ . = ..()
+ GLOB.pinpointer_list += src
+
+/obj/item/pinpointer/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ GLOB.pinpointer_list -= src
+ return ..()
+
+/obj/item/pinpointer/attack_self(mob/living/user)
+ active = !active
+ user.visible_message("[user] [active ? "" : "de"]activates their pinpointer.", "You [active ? "" : "de"]activate your pinpointer.")
+ playsound(src, 'sound/items/screwdriver2.ogg', 50, 1)
+ if(active)
+ START_PROCESSING(SSfastprocess, src)
+ else
+ target = null
+ STOP_PROCESSING(SSfastprocess, src)
+ update_icon()
+
+/obj/item/pinpointer/process()
+ if(!active)
+ return PROCESS_KILL
+ scan_for_target()
+ update_icon()
+
+/obj/item/pinpointer/proc/scan_for_target()
+ return
+
+/obj/item/pinpointer/update_icon()
+ cut_overlays()
+ if(!active)
+ return
+ if(!target)
+ add_overlay("pinon[alert ? "alert" : ""]null")
+ var/turf/here = get_turf(src)
+ var/turf/there = get_turf(target)
+ if(here.z != there.z)
+ add_overlay("pinon[alert ? "alert" : ""]null")
+ return
+ if(get_dist_euclidian(here,there) <= minimum_range)
+ add_overlay("pinon[alert ? "alert" : ""]direct")
+ else
+ setDir(get_dir(here, there))
+ switch(get_dist(here, there))
+ if(1 to 8)
+ add_overlay("pinon[alert ? "alert" : "close"]")
+ if(9 to 16)
+ add_overlay("pinon[alert ? "alert" : "medium"]")
+ if(16 to INFINITY)
+ add_overlay("pinon[alert ? "alert" : "far"]")
+
+/obj/item/pinpointer/crew // A replacement for the old crew monitoring consoles
+ name = "crew pinpointer"
+ desc = "A handheld tracking device that points to crew suit sensors."
+ icon_state = "pinpointer_crew"
+
+/obj/item/pinpointer/crew/proc/trackable(mob/living/carbon/human/H)
+ var/turf/here = get_turf(src)
+ if((H.z == 0 || H.z == here.z) && istype(H.w_uniform, /obj/item/clothing/under))
+ var/obj/item/clothing/under/U = H.w_uniform
+
+ // Suit sensors must be on maximum.
+ if(!U.has_sensor || U.sensor_mode < SENSOR_COORDS)
+ return FALSE
+
+ var/turf/there = get_turf(H)
+ return (H.z != 0 || (there && there.z == H.z))
+
+ return FALSE
+
+/obj/item/pinpointer/crew/attack_self(mob/living/user)
+ if(active)
+ active = FALSE
+ user.visible_message("[user] deactivates their pinpointer.", "You deactivate your pinpointer.")
+ playsound(src, 'sound/items/screwdriver2.ogg', 50, 1)
+ target = null //Restarting the pinpointer forces a target reset
+ STOP_PROCESSING(SSfastprocess, src)
+ update_icon()
+ return
+
+ var/list/name_counts = list()
+ var/list/names = list()
+
+ for(var/mob/living/carbon/human/H in GLOB.mob_list)
+ if(!trackable(H))
+ continue
+
+ var/crewmember_name = "Unknown"
+ if(H.wear_id)
+ var/obj/item/card/id/I = H.wear_id.GetID()
+ crewmember_name = I.registered_name
+
+ while(crewmember_name in name_counts)
+ name_counts[crewmember_name]++
+ crewmember_name = text("[] ([])", crewmember_name, name_counts[crewmember_name])
+ names[crewmember_name] = H
+ name_counts[crewmember_name] = 1
+
+ if(!names.len)
+ user.visible_message("[user]'s pinpointer fails to detect a signal.", "Your pinpointer fails to detect a signal.")
+ return
+
+ var/A = input(user, "Person to track", "Pinpoint") in names
+ if(!A || QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated())
+ return
+
+ target = names[A]
+ active = TRUE
+ user.visible_message("[user] activates their pinpointer.", "You activate your pinpointer.")
+ playsound(src, 'sound/items/screwdriver2.ogg', 50, 1)
+ START_PROCESSING(SSfastprocess, src)
+ update_icon()
+
+/obj/item/pinpointer/crew/scan_for_target()
+ if(target)
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ if(!trackable(H))
+ target = null
+ if(!target) //target can be set to null from above code, or elsewhere
+ active = FALSE
+
+/obj/item/pinpointer/process()
+ if(!active)
+ return PROCESS_KILL
+ scan_for_target()
+ update_icon()
+
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index cefd972aaf..aeacf17598 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -83,7 +83,7 @@
new /obj/item/storage/belt/security/full(src)
new /obj/item/gun/energy/e_gun/hos(src)
new /obj/item/device/flashlight/seclite(src)
- new /obj/item/pinpointer(src)
+ new /obj/item/pinpointer/nuke(src)
/obj/structure/closet/secure_closet/warden
name = "\proper warden's locker"
@@ -108,6 +108,7 @@
new /obj/item/clothing/gloves/krav_maga/sec(src)
new /obj/item/door_remote/head_of_security(src)
new /obj/item/gun/ballistic/shotgun/automatic/combat/compact(src)
+ new /obj/item/pinpointer/crew(src)
/obj/structure/closet/secure_closet/security
name = "security officer's locker"
@@ -183,6 +184,7 @@
new /obj/item/reagent_containers/spray/pepper(src)
new /obj/item/clothing/suit/armor/vest/det_suit(src)
new /obj/item/storage/belt/holster/full(src)
+ new /obj/item/pinpointer/crew(src)
new /obj/item/device/mass_spectrometer(src)
/obj/structure/closet/secure_closet/injection
diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm
index 7301724eb6..abb87a4235 100644
--- a/code/modules/admin/verbs/onlyone.dm
+++ b/code/modules/admin/verbs/onlyone.dm
@@ -50,8 +50,8 @@ GLOBAL_VAR_INIT(highlander, FALSE)
equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/captain(src), slot_ears)
equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(src), slot_head)
equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(src), slot_shoes)
- equip_to_slot_or_del(new /obj/item/pinpointer(src), slot_l_store)
- for(var/obj/item/pinpointer/P in src)
+ equip_to_slot_or_del(new /obj/item/pinpointer/nuke(src), slot_l_store)
+ for(var/obj/item/pinpointer/nuke/P in src)
P.attack_self(src)
var/obj/item/card/id/W = new(src)
W.icon_state = "centcom"
diff --git a/code/modules/jobs/job_types/medical.dm b/code/modules/jobs/job_types/medical.dm
index 94d2753fc5..9a33e1e759 100644
--- a/code/modules/jobs/job_types/medical.dm
+++ b/code/modules/jobs/job_types/medical.dm
@@ -33,6 +33,7 @@ Chief Medical Officer
id = /obj/item/card/id/silver
belt = /obj/item/device/pda/heads/cmo
+ l_pocket = /obj/item/pinpointer/crew
ears = /obj/item/device/radio/headset/heads/cmo
uniform = /obj/item/clothing/under/rank/chief_medical_officer
shoes = /obj/item/clothing/shoes/sneakers/brown
diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm
index 52c06439fb..d41b6f5f29 100644
--- a/code/modules/mob/living/silicon/ai/death.dm
+++ b/code/modules/mob/living/silicon/ai/death.dm
@@ -35,9 +35,9 @@
if(nuking)
set_security_level("red")
nuking = FALSE
- for(var/obj/item/pinpointer/P in GLOB.pinpointer_list)
+ for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list)
P.switch_mode_to(TRACK_NUKE_DISK) //Party's over, back to work, everyone
- P.nuke_warning = FALSE
+ P.alert = FALSE
if(doomsday_device)
doomsday_device.timing = FALSE
diff --git a/code/modules/mob/living/silicon/ai/death.dm.rej b/code/modules/mob/living/silicon/ai/death.dm.rej
new file mode 100644
index 0000000000..40b5625e8c
--- /dev/null
+++ b/code/modules/mob/living/silicon/ai/death.dm.rej
@@ -0,0 +1,13 @@
+diff a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm (rejected hunks)
+@@ -35,9 +35,9 @@
+ if(nuking)
+ set_security_level("red")
+ nuking = FALSE
+- for(var/obj/item/weapon/pinpointer/P in GLOB.pinpointer_list)
++ for(var/obj/item/weapon/pinpointer/nuke/P in GLOB.pinpointer_list)
+ P.switch_mode_to(TRACK_NUKE_DISK) //Party's over, back to work, everyone
+- P.nuke_warning = FALSE
++ P.alert = FALSE
+
+ if(doomsday_device)
+ doomsday_device.timing = FALSE
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 41fbc69180..af6f3daf92 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -599,7 +599,7 @@
/obj/item/gun/ballistic/revolver/grenadelauncher/cyborg,
/obj/item/card/emag,
/obj/item/crowbar/cyborg,
- /obj/item/pinpointer/syndicate/cyborg)
+ /obj/item/pinpointer/syndicate_cyborg)
ratvar_modules = list(
/obj/item/clockwork/slab/cyborg/security,
@@ -625,7 +625,7 @@
/obj/item/roller/robo,
/obj/item/card/emag,
/obj/item/crowbar/cyborg,
- /obj/item/pinpointer/syndicate/cyborg,
+ /obj/item/pinpointer/syndicate_cyborg,
/obj/item/stack/medical/gauze/cyborg,
/obj/item/gun/medbeam)
ratvar_modules = list(
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm.rej b/code/modules/mob/living/silicon/robot/robot_modules.dm.rej
new file mode 100644
index 0000000000..b0f0812dc4
--- /dev/null
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm.rej
@@ -0,0 +1,19 @@
+diff a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm (rejected hunks)
+@@ -519,7 +519,7 @@
+ /obj/item/weapon/gun/ballistic/revolver/grenadelauncher/cyborg,
+ /obj/item/weapon/card/emag,
+ /obj/item/weapon/crowbar/cyborg,
+- /obj/item/weapon/pinpointer/syndicate/cyborg)
++ /obj/item/weapon/pinpointer/syndicate_cyborg)
+
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg/security,
+@@ -545,7 +545,7 @@
+ /obj/item/roller/robo,
+ /obj/item/weapon/card/emag,
+ /obj/item/weapon/crowbar/cyborg,
+- /obj/item/weapon/pinpointer/syndicate/cyborg,
++ /obj/item/weapon/pinpointer/syndicate_cyborg,
+ /obj/item/stack/medical/gauze/cyborg,
+ /obj/item/weapon/gun/medbeam)
+ ratvar_modules = list(
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 3b070f1384..b0212e6155 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -874,9 +874,9 @@
occupier.loc = src.loc
occupier.death()
occupier.gib()
- for(var/obj/item/pinpointer/P in GLOB.pinpointer_list)
+ for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list)
P.switch_mode_to(TRACK_NUKE_DISK) //Pinpointers go back to tracking the nuke disk
- P.nuke_warning = FALSE
+ P.alert = FALSE
/obj/machinery/power/apc/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card)
if(card.AI)
diff --git a/code/modules/power/apc.dm.rej b/code/modules/power/apc.dm.rej
new file mode 100644
index 0000000000..9e432f503c
--- /dev/null
+++ b/code/modules/power/apc.dm.rej
@@ -0,0 +1,13 @@
+diff a/code/modules/power/apc.dm b/code/modules/power/apc.dm (rejected hunks)
+@@ -867,9 +867,9 @@
+ occupier.loc = src.loc
+ occupier.death()
+ occupier.gib()
+- for(var/obj/item/weapon/pinpointer/P in GLOB.pinpointer_list)
++ for(var/obj/item/weapon/pinpointer/nuke/P in GLOB.pinpointer_list)
+ P.switch_mode_to(TRACK_NUKE_DISK) //Pinpointers go back to tracking the nuke disk
+- P.nuke_warning = FALSE
++ P.alert = FALSE
+
+ /obj/machinery/power/apc/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card)
+ if(card.AI)
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 808de69446..79f0a207d4 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index c38210b6b7..ab1e866b8d 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -798,6 +798,7 @@
#include "code\game\objects\items\mop.dm"
#include "code\game\objects\items\paint.dm"
#include "code\game\objects\items\paiwire.dm"
+#include "code\game\objects\items\pinpointer.dm"
#include "code\game\objects\items\pneumaticCannon.dm"
#include "code\game\objects\items\powerfist.dm"
#include "code\game\objects\items\RCD.dm"