mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-10 06:34:45 +01:00
528 lines
20 KiB
Plaintext
528 lines
20 KiB
Plaintext
/obj/item/jammer
|
|
name = "radio jammer"
|
|
desc = "Fog of war that fits your pocket. Flicking the switch and extending the antenna will scramble nearby radio comms, making outgoing messages hard to understand."
|
|
icon = 'icons/obj/device.dmi'
|
|
icon_state = "jammer"
|
|
item_state = "jammer"
|
|
w_class = WEIGHT_CLASS_TINY
|
|
actions_types = list(/datum/action/item_action/toggle_radio_jammer)
|
|
var/active = FALSE
|
|
var/range = 15
|
|
|
|
/obj/item/jammer/Destroy()
|
|
GLOB.active_jammers -= src
|
|
return ..()
|
|
|
|
/obj/item/jammer/update_icon_state()
|
|
if(active)
|
|
icon_state = "[initial(icon_state)]-on"
|
|
else
|
|
icon_state = "[initial(icon_state)]"
|
|
|
|
/obj/item/jammer/attack_self(mob/user)
|
|
to_chat(user, "<span class='notice'>You [active ? "deactivate [src]. It goes quiet with a small click." : "activate [src]. It starts to hum softly."]</span>")
|
|
active = !active
|
|
update_icon(UPDATE_ICON_STATE)
|
|
if(active)
|
|
GLOB.active_jammers |= src
|
|
else
|
|
GLOB.active_jammers -= src
|
|
for(var/datum/action/item_action/toggle_radio_jammer/A in actions)
|
|
A.UpdateButtons()
|
|
|
|
/obj/item/teleporter
|
|
name = "syndicate teleporter"
|
|
desc = "A strange syndicate version of a cult veil shifter. Warranty voided if exposed to EMP."
|
|
icon = 'icons/obj/device.dmi'
|
|
icon_state = "syndi-tele-4"
|
|
throwforce = 5
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
throw_speed = 4
|
|
throw_range = 10
|
|
flags = CONDUCT
|
|
item_state = "electronic"
|
|
origin_tech = "magnets=3;combat=3;syndicate=3"
|
|
var/list/icons_charges = list(
|
|
"syndi-tele-0",
|
|
"syndi-tele-1",
|
|
"syndi-tele-2",
|
|
"syndi-tele-3",
|
|
"syndi-tele-4",
|
|
)
|
|
var/tp_range = 8
|
|
var/inner_tp_range = 3
|
|
var/charges = 4
|
|
var/max_charges = 4
|
|
var/saving_throw_distance = 3
|
|
var/flawless = FALSE
|
|
|
|
/obj/item/teleporter/Initialize(mapload, ...)
|
|
. = ..()
|
|
START_PROCESSING(SSobj, src)
|
|
|
|
/obj/item/teleporter/Destroy()
|
|
STOP_PROCESSING(SSobj, src)
|
|
return ..()
|
|
|
|
/obj/item/teleporter/examine(mob/user)
|
|
. = ..()
|
|
. += "<span class='notice'>[src] has [charges] out of [max_charges] charges left.</span>"
|
|
|
|
/obj/item/teleporter/attack_self(mob/user)
|
|
attempt_teleport(user, FALSE)
|
|
|
|
/obj/item/teleporter/process()
|
|
if(prob(10) && charges < max_charges)
|
|
charges++
|
|
update_icon_charges()
|
|
|
|
/obj/item/teleporter/emp_act(severity)
|
|
var/teleported_something = FALSE
|
|
if(prob(50 / severity))
|
|
if(ishuman(loc))
|
|
var/mob/living/carbon/human/user = loc
|
|
to_chat(user, "<span class='userdanger'>[src] buzzes and activates!</span>")
|
|
attempt_teleport(user, TRUE)
|
|
else //Well, it either is on a floor / locker, and won't teleport someone, OR it's in someones bag. As such, we need to check the turf to see if people are there.
|
|
var/turf/teleport_turf = get_turf(src)
|
|
for(var/mob/living/user in teleport_turf)
|
|
if(!teleported_something)
|
|
teleport_turf.visible_message("<span class='danger'>[src] activates sporadically, teleporting everyone around it!</span>")
|
|
teleported_something = TRUE
|
|
attempt_teleport(user, TRUE)
|
|
if(!teleported_something)
|
|
visible_message("<span class='danger'>[src] activates and blinks out of existence!</span>")
|
|
do_sparks(2, 1, src)
|
|
qdel(src)
|
|
|
|
/obj/item/teleporter/proc/update_icon_charges()
|
|
if(charges + 1 > length(icons_charges))
|
|
icon_state = initial(icon_state)
|
|
return
|
|
icon_state = icons_charges[charges + 1]
|
|
|
|
/obj/item/teleporter/proc/attempt_teleport(mob/user, EMP_D = FALSE)
|
|
for(var/obj/item/grab/G in user)
|
|
qdel(G)
|
|
dir_correction(user)
|
|
if(!charges && !EMP_D) //If it's empd, you are moving no matter what.
|
|
to_chat(user, "<span class='warning'>[src] is still recharging.</span>")
|
|
return
|
|
var/turf/starting = get_turf(src)
|
|
var/area/starting_area = get_area(starting)
|
|
if(!is_teleport_allowed(starting.z) || starting_area.tele_proof)
|
|
to_chat(user, "<span class='danger'>[src] will not work here!</span>")
|
|
return
|
|
var/mob/living/M = user
|
|
var/turf/mobloc = get_turf(M)
|
|
var/list/turfs = list()
|
|
var/found_turf = FALSE
|
|
var/list/bagholding = user.search_contents_for(/obj/item/storage/backpack/holding)
|
|
for(var/turf/T in range(user, tp_range))
|
|
var/area/dropping_area = get_area(T)
|
|
if(dropping_area.tele_proof) //There might be some valid turfs before / after you reach such an area, so we continue, not break.
|
|
continue
|
|
if(!(length(bagholding) && !flawless)) //Chaos if you have a bag of holding
|
|
if(get_dir(M, T) != M.dir)
|
|
continue
|
|
if(T in range(user, inner_tp_range))
|
|
continue
|
|
if(T.x > world.maxx-tp_range || T.x < tp_range)
|
|
continue //putting them at the edge is dumb
|
|
if(T.y > world.maxy-tp_range || T.y < tp_range)
|
|
continue
|
|
|
|
turfs += T
|
|
found_turf = TRUE
|
|
|
|
if(found_turf)
|
|
if(user.loc != mobloc) // No locker / mech / sleeper teleporting, that breaks stuff
|
|
to_chat(M, "<span class='danger'>[src] will not work here!</span>")
|
|
if(charges > 0) //While we want EMP triggered teleports to drain charge, we also do not want it to go negative charge, as such we need this check here
|
|
charges--
|
|
update_icon_charges()
|
|
var/turf/destination = pick(turfs)
|
|
if(tile_check(destination) || flawless) // Why is there so many bloody floor types
|
|
var/turf/fragging_location = destination
|
|
telefrag(fragging_location, user)
|
|
M.forceMove(destination)
|
|
playsound(mobloc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
|
new/obj/effect/temp_visual/teleport_abductor/syndi_teleporter(mobloc)
|
|
playsound(destination, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
|
new/obj/effect/temp_visual/teleport_abductor/syndi_teleporter(destination)
|
|
else if(!EMP_D && !(length(bagholding) && !flawless)) // This is where the fun begins
|
|
var/direction = get_dir(user, destination)
|
|
panic_teleport(user, destination, direction)
|
|
else // Emp activated? Bag of holding? No saving throw for you
|
|
get_fragged(user, destination)
|
|
else
|
|
to_chat(M, "<span class='danger'>[src] will not work here!</span>")
|
|
|
|
/obj/item/teleporter/proc/tile_check(turf/T)
|
|
if(isfloorturf(T) || isspaceturf(T))
|
|
return TRUE
|
|
|
|
/obj/item/teleporter/proc/dir_correction(mob/user) //Direction movement, screws with teleport distance and saving throw, and thus must be removed first
|
|
var/temp_direction = user.dir
|
|
switch(temp_direction)
|
|
if(NORTHEAST, SOUTHEAST)
|
|
user.dir = EAST
|
|
if(NORTHWEST, SOUTHWEST)
|
|
user.dir = WEST
|
|
|
|
/obj/item/teleporter/proc/panic_teleport(mob/user, turf/destination, direction = NORTH)
|
|
var/saving_throw
|
|
switch(direction)
|
|
if(NORTH, SOUTH)
|
|
if(prob(50))
|
|
saving_throw = EAST
|
|
else
|
|
saving_throw = WEST
|
|
if(EAST, WEST)
|
|
if(prob(50))
|
|
saving_throw = NORTH
|
|
else
|
|
saving_throw = SOUTH
|
|
else
|
|
saving_throw = NORTH // just in case
|
|
|
|
var/mob/living/M = user
|
|
var/turf/mobloc = get_turf(M)
|
|
var/list/turfs = list()
|
|
var/found_turf = FALSE
|
|
for(var/turf/T in range(destination, saving_throw_distance))
|
|
if(get_dir(destination, T) != saving_throw)
|
|
continue
|
|
if(T.x > world.maxx-saving_throw_distance || T.x < saving_throw_distance)
|
|
continue //putting them at the edge is dumb
|
|
if(T.y > world.maxy-saving_throw_distance || T.y < saving_throw_distance)
|
|
continue
|
|
if(!tile_check(T))
|
|
continue // We are only looking for safe tiles on the saving throw, since we are nice
|
|
turfs += T
|
|
found_turf = TRUE
|
|
|
|
if(found_turf)
|
|
var/turf/new_destination = pick(turfs)
|
|
var/turf/fragging_location = new_destination
|
|
telefrag(fragging_location, user)
|
|
M.forceMove(new_destination)
|
|
playsound(mobloc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
|
new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(mobloc)
|
|
new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(new_destination)
|
|
playsound(new_destination, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
|
else //We tried to save. We failed. Death time.
|
|
get_fragged(user, destination)
|
|
|
|
|
|
/obj/item/teleporter/proc/get_fragged(mob/user, turf/destination)
|
|
var/turf/mobloc = get_turf(user)
|
|
user.forceMove(destination)
|
|
playsound(mobloc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
|
new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(mobloc)
|
|
new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(destination)
|
|
playsound(destination, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
|
playsound(destination, "sound/magic/disintegrate.ogg", 50, TRUE)
|
|
destination.ex_act(rand(1,2))
|
|
to_chat(user, "<span class='biggerdanger'>You teleport into the wall, the teleporter tries to save you, but--</span>")
|
|
user.gib()
|
|
|
|
/obj/item/teleporter/proc/telefrag(turf/fragging_location, mob/user)
|
|
for(var/mob/living/M in fragging_location)//Hit everything in the turf
|
|
M.apply_damage(20, BRUTE)
|
|
M.Weaken(6 SECONDS)
|
|
to_chat(M, "<span_class='warning'>[user] teleports into you, knocking you to the floor with the bluespace wave!</span>")
|
|
|
|
/obj/item/paper/teleporter
|
|
name = "Teleporter Guide"
|
|
icon_state = "paper"
|
|
info = {"<b>Instructions on your new prototype syndicate teleporter</b><br>
|
|
<br>
|
|
This teleporter will teleport the user 4-8 meters in the direction they are facing. Unlike the cult veil shifter, you can not drag people with you.<br>
|
|
<br>
|
|
It has 4 charges, and will recharge uses over time. No, sticking the teleporter into the tesla, an APC, a microwave, or an electrified door, will not make it charge faster.<br>
|
|
<br>
|
|
<b>Warning:</b> Teleporting into walls will activate a failsafe teleport parallel up to 3 meters, but the user will be ripped apart and gibbed in a wall if it fails.<br>
|
|
<br>
|
|
Do not expose the teleporter to electromagnetic pulses or attempt to use with a bag of holding, unwanted malfunctions may occur.
|
|
<br><hr>
|
|
<font size =\"1\">Comes with free chameleon mesons, to help you stay stylish while seeing through walls.</font>
|
|
"}
|
|
/obj/item/storage/box/syndie_kit/teleporter
|
|
name = "syndicate teleporter kit"
|
|
|
|
/obj/item/storage/box/syndie_kit/teleporter/populate_contents()
|
|
new /obj/item/teleporter(src)
|
|
new /obj/item/clothing/glasses/meson/chameleon(src)
|
|
new /obj/item/paper/teleporter(src)
|
|
|
|
/obj/effect/temp_visual/teleport_abductor/syndi_teleporter
|
|
duration = 5
|
|
|
|
/obj/item/teleporter/admin
|
|
desc = "A strange syndicate version of a cult veil shifter. \n This one seems EMP proof, and with much better safety protocols."
|
|
charges = 8
|
|
max_charges = 8
|
|
flawless = TRUE
|
|
|
|
/obj/item/fireproofing_injector
|
|
name = "fireproofing injector"
|
|
desc = "It contains an alien nanoswarm created by the technomancers of boron. Through near sorcerous feats via use of nanomachines, it enables its user to become fully fireproof."
|
|
icon = 'icons/obj/hypo.dmi'
|
|
icon_state = "combat_hypo"
|
|
var/used = FALSE
|
|
|
|
/obj/item/fireproofing_injector/attack_self(mob/living/user)
|
|
if(HAS_TRAIT(user, TRAIT_RESISTHEAT))
|
|
to_chat(user, "<span class='warning'>You are already fireproof!</span>")
|
|
return
|
|
if(user.mind && (IS_CHANGELING(user) || user.mind.has_antag_datum(/datum/antagonist/vampire)) || (user.dna && user.dna.species.name != "Plasmaman"))
|
|
to_chat(user, "<span class='warning'>The injector is not compatable with your biology!</span>")
|
|
return
|
|
if(used)
|
|
to_chat(user, "<span class='notice'>The injector is empty!</span>")
|
|
return
|
|
used = TRUE // Set this BEFORE the popup to prevent people using the injector more than once.
|
|
var/choice = tgui_alert(user, "The injector is still unused. Do you wish to use it?", "Fireproofing injector", list("Yes", "No"))
|
|
if(choice != "Yes")
|
|
to_chat(user, "<span class='notice'>You decide against using [src].</span>")
|
|
used = FALSE
|
|
return
|
|
to_chat(user, "<span class='notice'>You inject yourself with the nanites!</span>")
|
|
ADD_TRAIT(user, TRAIT_RESISTHEAT, "fireproof_injector")
|
|
|
|
/obj/item/cryoregenerative_enhancer
|
|
name = "cryoregenerative enhancer"
|
|
desc = "Specially designed nanomachines that enhance the low-temperature regenerative capabilities of drask. Requires supercooled air in the enviroment or internals to function."
|
|
icon = 'icons/obj/hypo.dmi'
|
|
icon_state = "combat_hypo"
|
|
var/used = FALSE
|
|
|
|
/obj/item/cryoregenerative_enhancer/examine_more(mob/user)
|
|
. = ..()
|
|
. += "Designed by Viim-vaarooomunnm's prestigious polytechnic university, these experimental nanomachines infiltrate the cells of the drask host and integrate into the specialised cryoregenerative organelles that facilitate low-temperature healing and work to boost enzymatic activity, massively improving the efficiency of the associated metabolic processes."
|
|
. += ""
|
|
. += "Clinical trials have shown a four times increase in the rate of healing compared to a placebo. Whilst the product is technically not yet available to the public, the right connections with the right people allow interested parties to obtain samples early..."
|
|
|
|
/obj/item/cryoregenerative_enhancer/attack_self(mob/living/user)
|
|
if(HAS_TRAIT(user, TRAIT_DRASK_SUPERCOOL))
|
|
to_chat(user, "<span class='warning'>Your regeneration is already enhanced!</span>")
|
|
return
|
|
if(user.mind && (IS_CHANGELING(user) || user.mind.has_antag_datum(/datum/antagonist/vampire)) || user.dna?.species.name != "Drask")
|
|
to_chat(user, "<span class='warning'>The injector is not compatable with your biology!</span>")
|
|
return
|
|
if(used)
|
|
to_chat(user, "<span class='notice'>The injector is empty!</span>")
|
|
return
|
|
var/choice = tgui_alert(user, "The injector is still unused. Do you wish to use it?", "Cryoregenerative enhancer", list("Yes", "No"))
|
|
if(choice != "Yes")
|
|
to_chat(user, "<span class='notice'>You decide against using [src].</span>")
|
|
return
|
|
if(used)
|
|
to_chat(user, "<span class='warning'>The injector is empty!</span>")
|
|
return
|
|
used = TRUE
|
|
to_chat(user, "<span class='notice'>You inject yourself with the enhancer!</span>")
|
|
ADD_TRAIT(user, TRAIT_DRASK_SUPERCOOL, "cryoregenerative_enhancer")
|
|
|
|
/obj/item/batterer
|
|
name = "mind batterer"
|
|
desc = "A dangerous syndicate device focused on crowd control and escapes. Causes brain damage, confusion, and other nasty effects to those surrounding the user."
|
|
icon = 'icons/obj/device.dmi'
|
|
icon_state = "batterer"
|
|
throwforce = 5
|
|
w_class = WEIGHT_CLASS_TINY
|
|
throw_speed = 4
|
|
throw_range = 10
|
|
flags = CONDUCT
|
|
item_state = "electronic"
|
|
origin_tech = "magnets=3;combat=3;syndicate=3"
|
|
|
|
/// How many times the mind batter has been used
|
|
var/times_used = 0
|
|
var/max_uses = 5
|
|
/// Is this item on cooldown from being thrown
|
|
var/on_throwing_cooldown = FALSE
|
|
/// How many SSobj ticks have passed (Roughly 2 seconds of in game time), used to see when to recharge a use on this item
|
|
var/recharge_ticks = 0
|
|
|
|
/obj/item/batterer/Initialize(mapload)
|
|
. = ..()
|
|
START_PROCESSING(SSobj, src)
|
|
|
|
/obj/item/batterer/examine(mob/user)
|
|
. = ..()
|
|
. += "<span class='warning'>A little label on the side reads: \"Warning: Using this item in quick succession may cause fatigue to the user!\"</span>"
|
|
if(times_used >= max_uses)
|
|
. += "<span class='notice'>[src] is out of charge.</span>"
|
|
if(times_used < max_uses)
|
|
. += "<span class='notice'>[src] has [max_uses-times_used] charges left.</span>"
|
|
|
|
/obj/item/batterer/process()
|
|
if(times_used)
|
|
recharge_ticks++
|
|
if(recharge_ticks >= 10) // recharges one use after around 20 seconds
|
|
recharge_ticks = initial(recharge_ticks)
|
|
times_used--
|
|
icon_state = "batterer"
|
|
|
|
/obj/item/batterer/attack_self(mob/living/carbon/user)
|
|
activate_batterer(user)
|
|
|
|
/obj/item/batterer/proc/activate_batterer(mob/user)
|
|
times_used++
|
|
if(user)
|
|
if(times_used > max_uses)
|
|
to_chat(user, "<span class='danger'>The mind batterer has been burnt out!</span>")
|
|
times_used--
|
|
return
|
|
if(!do_after_once(user, 2 SECONDS, target = src, allow_moving = TRUE, attempt_cancel_message = "You think it's best to save this for later."))
|
|
times_used--
|
|
return
|
|
to_chat(user, "<span class='notice'>You trigger [src]. It has [max_uses-times_used] charges left.</span>")
|
|
|
|
for(var/mob/living/M in oview(7, get_turf(src)))
|
|
if(!M.client)
|
|
continue
|
|
if(issilicon(M))
|
|
var/mob/living/silicon/robot/R = M
|
|
R.flash_eyes(3, affect_silicon = TRUE) //Enough stamina damage to instantly force a reboot
|
|
else
|
|
M.Confused(45 SECONDS)
|
|
M.adjustBrainLoss(10)
|
|
to_chat(M, "<span class='danger'>You feel a sudden, electric jolt travel through yourself,</span>")
|
|
switch(rand(1, 10))
|
|
if(1)
|
|
M.Immobilize(7 SECONDS)
|
|
to_chat(M, "<span class='warning'>and your legs lock up for a moment!</span>")
|
|
if(2)
|
|
M.apply_status_effect(STATUS_EFFECT_PACIFIED_BATTERER)
|
|
to_chat(M, "<span class='warning'>and you feel an innate love for life for a fleeting moment!</span>")
|
|
if(3)
|
|
new /obj/effect/hallucination/delusion(get_turf(M), M)
|
|
to_chat(M, "<span class='warning'>and the people around you morph in appearance!</span>")
|
|
if(4)
|
|
if(prob(80))
|
|
M.EyeBlurry(25 SECONDS)
|
|
to_chat(M, "<span class='warning'>and something in the back of your head stings like hell!</span>")
|
|
else
|
|
M.EyeBlind(15 SECONDS)
|
|
to_chat(M, "<span class='warning'>and you can't see a goddamn thing!</span>")
|
|
if(5)
|
|
M.apply_damage(40, STAMINA)
|
|
to_chat(M, "<span class='warning'>and a wave of tiredness washes over you!</span>")
|
|
else
|
|
to_chat(M, "<span class='danger'>but as soon as it arrives, it fades.</span>")
|
|
add_attack_logs(user, M, "Mind battered with [src]")
|
|
|
|
playsound(get_turf(src), 'sound/misc/interference.ogg', 50, TRUE)
|
|
if(times_used >= max_uses)
|
|
icon_state = "battererburnt"
|
|
|
|
/obj/item/batterer/throw_impact(atom/hit_atom)
|
|
..()
|
|
if(times_used >= max_uses || on_throwing_cooldown)
|
|
return
|
|
addtimer(CALLBACK(src, PROC_REF(end_throwing_delay)), 3 SECONDS)
|
|
visible_message("<span class='notice'>[src] suddenly triggers, sending a shower of sparks everywhere!</span>")
|
|
do_sparks(4, FALSE, get_turf(src))
|
|
activate_batterer()
|
|
on_throwing_cooldown = TRUE
|
|
|
|
/obj/item/batterer/proc/end_throwing_delay()
|
|
on_throwing_cooldown = FALSE
|
|
|
|
/obj/item/batterer/emp_act(severity)
|
|
if(times_used >= max_uses)
|
|
return
|
|
visible_message("<span class='notice'>[src] explodes into a light show of colors!</span>")
|
|
if(severity == EMP_HEAVY)
|
|
activate_batterer()
|
|
|
|
times_used = max_uses - 1
|
|
activate_batterer()
|
|
|
|
/obj/item/handheld_mirror
|
|
name = "hand mirror"
|
|
desc = "Style, on the go!"
|
|
icon = 'icons/obj/hhmirror.dmi'
|
|
icon_state = "hhmirror"
|
|
w_class = WEIGHT_CLASS_TINY
|
|
var/datum/ui_module/appearance_changer/appearance_changer_holder
|
|
|
|
/obj/item/handheld_mirror/ui_state(mob/user)
|
|
return GLOB.hands_state
|
|
|
|
/obj/item/handheld_mirror/ui_interact(mob/user, datum/tgui/ui = null)
|
|
appearance_changer_holder.ui_interact(user, ui)
|
|
|
|
/obj/item/handheld_mirror/attack_self(mob/user)
|
|
if(ishuman(user))
|
|
appearance_changer_holder = new(src, user)
|
|
appearance_changer_holder.flags = APPEARANCE_ALL_BODY
|
|
ui_interact(user)
|
|
|
|
/obj/item/handheld_mirror/Initialize(mapload)
|
|
. = ..()
|
|
GLOB.mirrors += src
|
|
|
|
/obj/item/handheld_mirror/Destroy()
|
|
GLOB.mirrors -= src
|
|
QDEL_NULL(appearance_changer_holder)
|
|
return ..()
|
|
|
|
/// An admin-spawn item that will tell you roughly how close the nearest loyal Nanotrasen crewmember is.
|
|
/obj/item/syndi_scanner
|
|
name = "syndicate scanner"
|
|
desc = "The Syndicate seem to have modified this T-ray scanner for a more nefarious purpose, allowing it to detect all loyal Nanotrasen crew."
|
|
icon = 'icons/obj/device.dmi'
|
|
icon_state = "syndi-scanner"
|
|
throwforce = 5
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
throw_speed = 4
|
|
throw_range = 10
|
|
flags = CONDUCT
|
|
item_state = "electronic"
|
|
/// Split points for range_messages.
|
|
var/list/ranges = list(5, 15, 30)
|
|
/// Messages to output to the user.
|
|
var/list/range_messages = list(
|
|
"Very strong signal detected. Range: Within 5 meters.",
|
|
"Strong signal detected. Range: Within 15 meters.",
|
|
"Weak signal detected. Range: Within 30 meters.",
|
|
"No signal detected."
|
|
)
|
|
var/cooldown_length = 10 SECONDS
|
|
COOLDOWN_DECLARE(scan_cooldown)
|
|
var/on_hit_sound = 'sound/effects/ping_hit.ogg'
|
|
|
|
/obj/item/syndi_scanner/attack_self(mob/user)
|
|
if(!COOLDOWN_FINISHED(src, scan_cooldown))
|
|
to_chat(user, "<span class='warning'>[src] is recharging!</span>")
|
|
return
|
|
|
|
COOLDOWN_START(src, scan_cooldown, cooldown_length)
|
|
var/turf/user_turf = get_turf(user)
|
|
var/min_dist = INFINITY
|
|
for(var/mob/living/player in GLOB.player_list)
|
|
if(player.stat == DEAD || isnull(player.mind))
|
|
continue
|
|
if(!isnull(player.mind.special_role))
|
|
continue
|
|
var/turf/target_turf = get_turf(player)
|
|
if(target_turf.z != user_turf.z)
|
|
continue
|
|
min_dist = min(min_dist, get_dist(target_turf, user_turf))
|
|
|
|
// By default, we're in the first range, less than any split point.
|
|
var/range_index = 1
|
|
for(var/test_range in ranges)
|
|
if(min_dist > test_range)
|
|
// Past this split point, move to the next.
|
|
range_index++
|
|
else
|
|
// Found the right split point, and we're not past all of them, so play the on-hit sound effect.
|
|
playsound(user, on_hit_sound, 75, TRUE)
|
|
break
|
|
to_chat(user, "<span class='notice'>[range_messages[range_index]]</span>")
|