/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.\
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.\
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()
. = ..()
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 = mapping_units
debug_beacons_list = mapping_beacons
/obj/item/mapping_unit/Destroy()
mapping_units -= src
last_run()
map_image_cache.Cut()
icon_image_cache.Cut()
qdel_null(extras_holder)
return ..()
/obj/item/mapping_unit/dropped(mob/dropper)
if(loc != dropper) // 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()
mapping_units += src
updating = TRUE
START_PROCESSING(SSobj, src)
process()
/obj/item/mapping_unit/proc/stop_updates()
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 holomap_markers)
var/datum/holomap_marker/holomarker = 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 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 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()
. = ..()
if(in_list) // mapped in turned on
in_list = TRUE
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
mapping_beacons += src
else
in_list = FALSE
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)
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