Files
Aurora.3/code/game/objects/items/devices/t_scanner.dm
T
VMSolidusandGitHub a290281d14 Fix Improper Destroys (#22166)
We think the culprit behind this one was VSCode autofilling Destroy()
with . = ..()
which is improper. There's a **surprising** number of improper order
Destroy() procs in the repo, so I might as well get all of them in one
pass. Several of these files are associated with currently known hard
dels, such as the modular computer and organ related dels. More than a
couple were my own mistakes, since the Destroy() or Removed() . = ..()
behavior on signal registering objects also prevents the signal from
being unregistered, which similarly creates a hard del.

Signed-off-by: VMSolidus <evilexecutive@gmail.com>
2026-04-08 15:52:13 +00:00

161 lines
4.4 KiB
Plaintext

#define OVERLAY_CACHE_LEN 50
/obj/item/t_scanner
name = "\improper T-ray scanner"
desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes."
icon = 'icons/obj/item/scanner.dmi'
icon_state = "t-ray0"
item_state = "t-ray"
contained_sprite = TRUE
slot_flags = SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
matter = list(MATERIAL_PLASTIC = 100, MATERIAL_ALUMINIUM = 50)
origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1)
action_button_name = "Toggle T-Ray scanner"
var/scan_range = 3
var/on = 0
/// Assoc list of objects being scanned, mapped to their overlay.
var/list/active_scanned = list()
/// Since making sure overlays are properly added and removed is pretty important, so we track the current user explicitly.
var/client/user_client
/// Cache recent overlays.
var/global/list/overlay_cache = list()
/obj/item/t_scanner/Destroy()
if(on)
set_active(FALSE)
return ..()
/obj/item/t_scanner/update_icon()
icon_state = "t-ray[on]"
/obj/item/t_scanner/emp_act(severity)
. = ..()
audible_message(src, SPAN_NOTICE("\The [src] buzzes oddly."))
set_active(FALSE)
/obj/item/t_scanner/attack_self(mob/user)
set_active(!on)
user.update_action_buttons()
/obj/item/t_scanner/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
var/obj/structure/disposalpipe/D = target
if(istype(D))
to_chat(user, SPAN_INFO("Pipe segment integrity: [(D.health / 10) * 100]%"))
/obj/item/t_scanner/proc/set_active(var/active)
on = active
if(on)
START_PROCESSING(SSprocessing, src)
else
STOP_PROCESSING(SSprocessing, src)
set_user_client(null)
update_icon()
/// If reset is set, then assume the client has none of our overlays, otherwise we only send new overlays.
/obj/item/t_scanner/process()
if(!on)
return
//handle clients changing
var/client/loc_client = null
if(ismob(loc))
var/mob/M = loc
loc_client = M.client
set_user_client(loc_client)
//no sense processing if no-one is going to see it.
if(!user_client)
return
//get all objects in scan range
var/list/scanned = get_scanned_objects(scan_range)
var/list/update_add = scanned - active_scanned
var/list/update_remove = active_scanned - scanned
//Add new overlays
for(var/thing in update_add)
var/obj/O = thing
var/image/overlay = get_overlay(O)
active_scanned[O] = overlay
user_client.images += overlay
//Remove stale overlays
for(var/thing in update_remove)
var/obj/O = thing
user_client.images -= active_scanned[O]
active_scanned -= O
/// Creates a new overlay for a scanned object
/obj/item/t_scanner/proc/get_overlay(obj/scanned)
//Use a cache so we don't create a whole bunch of new images just because someone's walking back and forth in a room.
//Also means that images are reused if multiple people are using t-rays to look at the same objects.
if(scanned in overlay_cache)
. = overlay_cache[scanned]
else
var/image/I = image(scanned.icon, scanned.loc, scanned.icon_state, UNDER_HUD_LAYER, scanned.dir)
I.plane = HUD_PLANE
//Pipes are special
if(istype(scanned, /obj/machinery/atmospherics/pipe))
var/obj/machinery/atmospherics/pipe/P = scanned
I.color = P.pipe_color
I.overlays += P.overlays
I.underlays += P.underlays
else if(istype(scanned, /obj/structure/cable))
var/obj/structure/cable/C = scanned
I.color = C.color
I.alpha = 100
I.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
. = I
// Add it to cache, cutting old entries if the list is too long
overlay_cache[scanned] = .
if(overlay_cache.len > OVERLAY_CACHE_LEN)
overlay_cache.Cut(1, overlay_cache.len-OVERLAY_CACHE_LEN-1)
/obj/item/t_scanner/proc/get_scanned_objects(var/scan_dist)
. = list()
var/turf/center = get_turf(src.loc)
if(!center)
return
for(var/thing in RANGE_TURFS(scan_range, center))
var/turf/T = thing
if(!!T.is_plating())
continue
for(var/obj/O in T.contents)
if(O.level != 1)
continue
if(!O.invisibility)
continue //if it's already visible don't need an overlay for it
. += O
/obj/item/t_scanner/proc/set_user_client(var/client/new_client)
if(new_client == user_client)
return
if(user_client)
for(var/scanned in active_scanned)
user_client.images -= active_scanned[scanned]
if(new_client)
for(var/scanned in active_scanned)
new_client.images += active_scanned[scanned]
else
active_scanned.Cut()
user_client = new_client
/obj/item/t_scanner/dropped(mob/user)
set_user_client(null)
..()
#undef OVERLAY_CACHE_LEN