Files
CHOMPStation2/code/modules/holomap/mapper.dm
CHOMPStation2StaffMirrorBot f46d700e64 [MIRROR] some more grep checks (#11414)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
2025-08-14 20:22:06 +02:00

451 lines
13 KiB
Plaintext

/obj/item/mapping_unit
name = "mapping unit"
desc = "A portable mapping unit, capable of locating other similar units on a map. Also has a short-range sonar mapping system."
description_info = "Use the device in your hand to add the mapping HUD to your screen. You can then power it on and change mapping modes.\
<br>The device will show other powered-on mapping units on the map, as well as activated mapping beacons, but only of the same 'type' mapping unit.\
<br>Normal mapping units can only display other normal beacons and mapping units, ERT mapping units can display other ERT, etc."
icon = 'icons/obj/device.dmi'
icon_state = "mapping_unit"
item_state = null
w_class = ITEMSIZE_SMALL
//Holomap stuff
var/marker_prefix = "basic"
var/base_prefix = "basic"
var/map_color = null
var/mapper_filter = HOLOMAP_FILTER_STATIONMAP
var/list/prefix_update_head
var/list/prefix_update_rig
// These are local because they are different for every holochip.
// The maps and icons are all pixel_x and pixel_y'd so we're in the center.
var/list/map_image_cache = list()
var/list/icon_image_cache = list()
var/pinging = FALSE
var/updating = FALSE
var/global/icon/mask_icon
var/obj/screen/mapper/extras_holder/extras_holder
var/hud_frame_hint
var/datum/mini_hud/mapper/hud_datum
var/obj/screen/movable/mapper_holder/hud_item
var/obj/item/cell/cell
var/cell_type = /obj/item/cell/device
var/power_usage = 0.5 // Usage per map scan (doubled for ping mode)
var/uses_power = 1 // If it uses power at all
var/list/debug_mappers_list
var/list/debug_beacons_list
pickup_sound = 'sound/items/pickup/device.ogg'
drop_sound = 'sound/items/drop/device.ogg'
/obj/item/mapping_unit/deathsquad
name = "deathsquad mapping unit"
icon_state = "mapping_unit_ds"
marker_prefix = "ds"
mapper_filter = HOLOMAP_FILTER_DEATHSQUAD
//map_color = "#0B74B4"
hud_frame_hint = "_ds"
/obj/item/mapping_unit/operative
name = "nuclear operative mapping unit"
icon_state = "mapping_unit_op"
marker_prefix = "op"
mapper_filter = HOLOMAP_FILTER_NUKEOPS
//map_color = "#13B40B"
hud_frame_hint = "_op"
/obj/item/mapping_unit/ert
name = "emergency response team mapping unit"
icon_state = "mapping_unit_ert"
marker_prefix = "ert"
mapper_filter = HOLOMAP_FILTER_ERT
//map_color = "#5FFF28"
hud_frame_hint = "_ert"
prefix_update_head = list(
"/obj/item/clothing/head/helmet/ert/command" = "ertc",
"/obj/item/clothing/head/helmet/ert/security" = "erts",
"/obj/item/clothing/head/helmet/ert/engineer" = "erte",
"/obj/item/clothing/head/helmet/ert/medical" = "ertm",
)
prefix_update_rig = list(
"/obj/item/rig/ert" = "ertc",
"/obj/item/rig/ert/security" = "erts",
"/obj/item/rig/ert/engineer" = "erte",
"/obj/item/rig/ert/medical" = "ertm"
)
/obj/item/mapping_unit/Initialize(mapload)
. = ..()
base_prefix = marker_prefix
if(!mask_icon)
mask_icon = icon('icons/effects/64x64.dmi', "mapper_mask")
extras_holder = new()
var/obj/screen/mapper/marker/mark = new()
mark.icon = 'icons/effects/64x64.dmi'
mark.icon_state = "mapper_none"
mark.layer = 10
icon_image_cache["bad"] = mark
var/obj/screen/mapper/map/tmp = new()
var/icon/canvas = icon(HOLOMAP_ICON, "blank")
canvas.Crop(1,1,world.maxx,world.maxy)
canvas.DrawBox("#A7BE97",1,1,world.maxx,world.maxy)
tmp.icon = icon
map_image_cache["bad"] = tmp
if(uses_power && cell_type)
cell = new cell_type(src)
debug_mappers_list = GLOB.mapping_units
debug_beacons_list = GLOB.mapping_beacons
/obj/item/mapping_unit/Destroy()
GLOB.mapping_units -= src
last_run()
map_image_cache.Cut()
icon_image_cache.Cut()
QDEL_NULL(extras_holder)
return ..()
/obj/item/mapping_unit/dropped(mob/user)
..()
if(loc != user) // Not just a juggle
hide_device()
/obj/item/mapping_unit/attack_self(mob/user)
if(user.stat != CONSCIOUS)
return
if(!ishuman(user))
to_chat(user, span_warning("Only humanoids can use this device."))
return
var/mob/living/carbon/human/H = user
if(!ishuman(loc) || user != loc)
to_chat(H, span_warning("This device needs to be on your person."))
if(hud_datum?.main_hud)
hide_device()
to_chat(H, span_notice("You put \the [src] away."))
else
show_device(H)
to_chat(H, span_notice("You hold \the [src] where you can see it."))
/obj/item/mapping_unit/attack_hand(mob/user)
if(cell && user.get_inactive_hand() == src) // click with empty off hand
to_chat(user,span_notice("You eject \the [cell] from \the [src]."))
user.put_in_hands(cell)
cell = null
if(updating)
stop_updates()
else
return ..()
/obj/item/mapping_unit/attackby(obj/W, mob/user)
if(istype(W,cell_type) && !cell)
cell = W
cell.update_icon() //Why doesn't a cell do this already? :|
user.unEquip(cell)
cell.forceMove(src)
to_chat(user,span_notice("You insert \the [cell] into \the [src]."))
/obj/item/mapping_unit/proc/first_run(mob/user)
hud_datum = new(user.hud_used, src)
hud_item = hud_datum.screenobjs[1]
/obj/item/mapping_unit/proc/show_device(mob/user)
if(!hud_datum)
first_run(user)
else
hud_datum.apply_to_hud(user.hud_used)
/obj/item/mapping_unit/proc/start_updates()
GLOB.mapping_units += src
updating = TRUE
START_PROCESSING(SSobj, src)
process()
/obj/item/mapping_unit/proc/stop_updates()
GLOB.mapping_units -= src
STOP_PROCESSING(SSobj, src)
updating = FALSE
if(hud_item)
hud_item.off(FALSE)
/obj/item/mapping_unit/proc/hide_device()
hud_datum?.unapply_to_hud()
/obj/item/mapping_unit/proc/last_run()
stop_updates()
if(!QDELETED(hud_datum))
qdel(hud_datum)
hud_datum = null
hud_item = null
/obj/item/mapping_unit/process()
if(!updating || (uses_power && !cell))
stop_updates()
return
if(uses_power)
var/power_to_use = pinging ? power_usage*2 : power_usage
if(cell.use(power_to_use) != power_to_use) // we weren't able to use our full power_usage amount!
visible_message(span_warning("\The [src] flickers before going dull."))
stop_updates()
return
if(!hud_item || !hud_datum)
log_error("Mapping device tried to update with missing hud_item or hud_datum")
stop_updates()
last_run()
return
update_holomap()
#define HOLOMAP_ERROR 0
#define HOLOMAP_YOU 1
#define HOLOMAP_OTHER 2
#define HOLOMAP_DEAD 3
/obj/item/mapping_unit/proc/update_holomap()
var/turf/T = get_turf(src)
if(!T)//nullspace begone!
stop_updates()
return
var/T_x = T.x // Used many times, just grab it to avoid derefs
var/T_y = T.y
var/T_z = T.z
var/obj/screen/mapper/map/bgmap
var/list/extras = list()
var/map_cache_key = "[T_z]"
var/badmap = FALSE
if(!pinging && using_map && !(T_z in using_map.mappable_levels))
map_cache_key = "bad"
badmap = TRUE
// Cache miss
if(!(map_cache_key in map_image_cache))
var/mutable_appearance/map_app = new()
map_app.appearance_flags = PIXEL_SCALE
map_app.plane = PLANE_HOLOMAP
map_app.layer = HUD_LAYER
map_app.color = map_color
if(!SSholomaps.holoMiniMaps[T_z])
var/obj/screen/mapper/map/baddo = map_image_cache["bad"]
map_app.icon = icon(baddo.icon)
badmap = TRUE
// SSholomaps did map it and we're allowed to see it
else
map_app.icon = icon(SSholomaps.holoMiniMaps[T.z])
// Apply markers
for(var/marker in GLOB.holomap_markers)
var/datum/holomap_marker/holomarker = GLOB.holomap_markers[marker]
if(holomarker.z == T_z && holomarker.filter & mapper_filter)
var/image/markerImage = image(holomarker.icon,holomarker.id)
markerImage.plane = FLOAT_PLANE
markerImage.layer = FLOAT_LAYER
markerImage.appearance_flags = RESET_COLOR|PIXEL_SCALE
markerImage.pixel_x = holomarker.x+holomarker.offset_x
markerImage.pixel_y = holomarker.y+holomarker.offset_y
map_app.add_overlay(markerImage)
var/obj/screen/mapper/map/tmp = new()
tmp.appearance = map_app
map_image_cache[map_cache_key] = tmp
bgmap = map_image_cache[map_cache_key]
// The holomap moves around, the user is always in the center. This slides the holomap.
var/offset_x = bgmap.offset_x
var/offset_y = bgmap.offset_y
extras_holder.pixel_x = bgmap.pixel_x = -1*T_x + offset_x
extras_holder.pixel_y = bgmap.pixel_y = -1*T_y + offset_y
// Populate other mapper icons
for(var/obj/item/mapping_unit/HC as anything in GLOB.mapping_units)
if(HC.mapper_filter != mapper_filter)
continue
var/mob_indicator = HOLOMAP_ERROR
var/turf/TU = get_turf(HC)
// Mapper not on a turf or elsewhere
if(!TU || (TU.z != T_z))
continue
// We're the marker
if(HC == src)
mob_indicator = HOLOMAP_YOU
// The marker is held by a borg
else if(isrobot(HC.loc))
var/mob/living/silicon/robot/R = HC.loc
if(R.stat == DEAD)
mob_indicator = HOLOMAP_DEAD
else
mob_indicator = HOLOMAP_OTHER
// The marker is worn by a human
else if(ishuman(loc))
var/mob/living/carbon/human/H = loc
if(H.stat == DEAD)
mob_indicator = HOLOMAP_DEAD
else
mob_indicator = HOLOMAP_OTHER
// It's not attached to anything useful
else
mob_indicator = HOLOMAP_DEAD
// Ask it to update it's icon based on helmet (or whatever)
HC.update_marker()
// Generate the icon and apply it to the list of images to show the client
if(mob_indicator != HOLOMAP_ERROR)
// This is so specific because the icons are pixel_x and pixel_y only relative to OUR view of where THEY are relative to us
var/marker_cache_key = "\ref[HC]_[HC.marker_prefix]_[mob_indicator]"
if(!(marker_cache_key in icon_image_cache))
var/obj/screen/mapper/marker/mark = new()
mark.icon_state = "[HC.marker_prefix][mob_indicator]"
icon_image_cache[marker_cache_key] = mark
switch(mob_indicator)
if(HOLOMAP_YOU)
mark.layer = 3 // Above the other markers
if(HOLOMAP_DEAD)
mark.layer = 2
else
mark.layer = 1
var/obj/screen/mapper/marker/mark = icon_image_cache[marker_cache_key]
handle_marker(mark,TU.x,TU.y)
extras += mark
// Marker beacon items
for(var/obj/item/holomap_beacon/HB as anything in GLOB.mapping_beacons)
if(HB.mapper_filter != mapper_filter)
continue
var/turf/TB = get_turf(HB)
// Marker beacon not on a turf or elsewhere
if(!TB || (TB.z != T_z))
continue
var/marker_cache_key = "\ref[HB]_marker"
if(!(marker_cache_key in icon_image_cache))
var/obj/screen/mapper/marker/mark = new()
mark.icon_state = "beacon"
mark.layer = 1
icon_image_cache[marker_cache_key] = mark
var/obj/screen/mapper/marker/mark = icon_image_cache[marker_cache_key]
handle_marker(mark,TB.x,TB.y)
extras += mark
if(badmap)
var/obj/O = icon_image_cache["bad"]
O.pixel_x = T_x - offset_x
O.pixel_y = T_y - offset_y
extras += O
extras_holder.filters = filter(type = "alpha", icon = mask_icon, x = T_x-(offset_x*0.5), y = T_y-(offset_y*0.5))
extras_holder.vis_contents = extras
hud_item.update(bgmap, extras_holder, badmap ? FALSE : pinging)
/obj/item/mapping_unit/proc/update_marker()
marker_prefix = base_prefix
if (prefix_update_head)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
var/obj/item/helmet = H.get_equipped_item(slot_head)
if(helmet && ("[helmet.type]" in prefix_update_head))
marker_prefix = prefix_update_head["[helmet.type]"]
return
if (prefix_update_rig)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
var/obj/item/rig = H.get_rig()
if(rig && ("[rig.type]" in prefix_update_rig))
marker_prefix = prefix_update_rig["[rig.type]"]
return
/obj/item/mapping_unit/proc/handle_marker(var/atom/movable/marker,var/TU_x,var/TU_y)
marker.pixel_x = TU_x - 8 //16x16 icons, so to center.
marker.pixel_y = TU_y - 8
animate(marker, alpha = 0, time = 5, easing = SINE_EASING)
animate(alpha = 255, time = 2, easing = SINE_EASING)
/obj/item/holomap_beacon
name = "holomap beacon"
desc = "When active, the beacon will show itself on mapping units of the same type."
icon_state = "holochip"
w_class = ITEMSIZE_TINY
var/mapper_filter = HOLOMAP_FILTER_STATIONMAP
var/in_list = FALSE
/obj/item/holomap_beacon/Initialize(mapload)
. = ..()
if(in_list) // mapped in turned on
in_list = TRUE
GLOB.mapping_beacons += src
icon_state = initial(icon_state) + in_list ? "_on" : ""
/obj/item/holomap_beacon/attack_self(mob/user)
if(!in_list)
in_list = TRUE
GLOB.mapping_beacons += src
else
in_list = FALSE
GLOB.mapping_beacons -= src
icon_state = "[initial(icon_state)][in_list ? "_on" : ""]"
to_chat(user,span_notice("The [src] is now [in_list ? "broadcasting" : "disabled"]."))
/obj/item/holomap_beacon/Destroy()
if(in_list)
GLOB.mapping_beacons -= src
return ..()
/obj/item/holomap_beacon/deathsquad
name = "deathsquad holomap beacon"
icon_state = "holochip_ds"
mapper_filter = HOLOMAP_FILTER_DEATHSQUAD
/obj/item/holomap_beacon/operative
name = "operative holomap beacon"
icon_state = "holochip_op"
mapper_filter = HOLOMAP_FILTER_NUKEOPS
/obj/item/holomap_beacon/ert
name = "ert holomap beacon"
icon_state = "holochip_ert"
mapper_filter = HOLOMAP_FILTER_ERT
#undef HOLOMAP_ERROR
#undef HOLOMAP_YOU
#undef HOLOMAP_OTHER
#undef HOLOMAP_DEAD