Files
BatrachophrenoandGitHub 4ecb0bc21c Repath obj/machinery to obj/structure/machinery [MDB Ignore] (#22500)
Repaths obj/machinery to obj/structure/machinery. **Note for
reviewers:** the only meaningful changed code exists within
**code/game/objects/structures.dm** and
**code/game/objects/structures/_machinery.dm**, largely concerning
damage procs. With the exception of moving airlock defines to their own
file, ALL OTHER CHANGES ARE STRICTLY PATH CHANGES.

Objects, _categorically_, are largely divided between those you can hold
in your hand/inventory and those you can't. Machinery objects are
already subtypes of Structures behaviorally, this PR just makes their
pathing reflect that, and allows for future work (tool actions, more
health/destruction functionality) to be developed without unnecessary
code duplication.

I have tested this PR by loading up the Horizon and dismantling various
machines and structures with tools, shooting guns of various types
throughout the ship, and detonating a bunch of explosions throughout the
ship.
2026-05-26 19:35:48 +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/structure/machinery/atmospherics/pipe))
var/obj/structure/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