Overmap sensors overhaul (#15666)

This commit is contained in:
Fluffy
2023-02-03 23:39:18 +01:00
committed by GitHub
parent 9b197fde5b
commit 14d41d1e84
23 changed files with 673 additions and 25 deletions

View File

@@ -8,6 +8,7 @@ var/global/list/map_sectors = list()
icon_state = "start"
requires_power = 0
base_turf = /turf/unsimulated/map
dynamic_lighting = 0
/turf/unsimulated/map
icon = 'icons/turf/space.dmi'

View File

@@ -0,0 +1,111 @@
#define SENSOR_TIME_DELAY 0.2 SECONDS
/datum/overmap_contact
var/name = "Unknown" // Contact name.
var/image/marker // Image overlay attached to the contact.
var/pinged = FALSE // Used to animate overmap effects.
var/list/images = list() // Our list of images to cast to users.
var/image/radar // Radar image for sonar esque effect
// The sensor console holding this data.
var/obj/machinery/computer/ship/sensors/owner
// The actual overmap effect associated with this.
var/obj/effect/overmap/effect
/datum/overmap_contact/New(var/obj/machinery/computer/ship/sensors/creator, var/obj/effect/overmap/source)
// Update local tracking information.
owner = creator
effect = source
name = effect.name
owner.contact_datums[effect] = src
marker = new(loc = effect)
update_marker_icon()
marker.alpha = 0 // Marker fades in on detection.
marker.appearance_flags |= RESET_TRANSFORM
images += marker
radar = image(loc = effect, icon = 'icons/obj/overmap.dmi', icon_state = "sensor_range")
radar.color = source.color
radar.tag = "radar"
radar.add_filter("blur", 1, list("blur", size = 1))
/datum/overmap_contact/proc/update_marker_icon()
marker.appearance = effect
marker.appearance_flags |= RESET_TRANSFORM
// Pixel offsets are included in appearance but since this marker's loc
// is the effect, it's already offset and we don't want to double it.
marker.pixel_x = 0
marker.pixel_y = 0
marker.transform = effect.transform
marker.dir = effect.dir
marker.overlays.Cut()
/datum/overmap_contact/proc/ping_radar(var/range = 0)
radar.transform = null
radar.alpha = 255
if(range > 1)
images |= radar
var/matrix/M = matrix()
M.Scale(range*2.6)
animate(radar, transform = M, alpha = 0, time = (SENSOR_TIME_DELAY*range), 1, SINE_EASING)
else
images -= radar
/datum/overmap_contact/proc/show()
if(!owner)
return
var/list/showing = owner.linked?.navigation_viewers || owner.viewers
if(length(showing))
for(var/datum/weakref/W in showing)
var/mob/M = W.resolve()
if(istype(M) && M.client)
M.client.images |= images
/datum/overmap_contact/proc/ping()
if(pinged)
return
pinged = TRUE
effect.opacity = 1
show()
animate(marker, alpha=255, 0.5 SECOND, 1, LINEAR_EASING)
addtimer(CALLBACK(src, PROC_REF(unping)), 1 SECOND)
/datum/overmap_contact/proc/unping()
animate(marker, alpha=75, 2 SECOND, 1, LINEAR_EASING)
pinged = FALSE
/datum/overmap_contact/Destroy()
if(owner)
// If we have a lock on what was lost, remove the lock from the targeting consoles
if(owner.connected.targeting == effect)
for(var/obj/machinery/computer/ship/targeting/console in owner.connected.consoles)
owner.connected.detarget(effect, console)
// Removes the client images from the client of the mobs that are looking at this contact
var/list/showing = owner.linked?.navigation_viewers || owner.viewers
if(length(showing))
for(var/datum/weakref/W in showing)
var/mob/M = W.resolve()
if(istype(M) && M.client)
M.client.images -= images
// Removes the effect from the contact datums of the owner, and null the owner
if(effect)
owner.contact_datums -= effect
owner = null
// Remove the effect opacity and null the effect
effect.opacity = 0
effect = null
QDEL_NULL_LIST(images)
. = ..()

View File

@@ -0,0 +1,292 @@
#define SENSORS_DISTANCE_COEFFICIENT 5
/obj/machinery/computer/ship/sensors
var/list/objects_in_view = list() // Associative list of objects in view -> identification process
var/list/contact_datums = list() // Associate an /obj/effect -> /datum/overmap_contact
var/list/trackers = list()
var/list/datalink_contacts = list() // A list of the datalink contacts we're receiving from the datalinks
var/tmp/muted = FALSE
/obj/machinery/computer/ship/sensors/Destroy()
objects_in_view.Cut()
trackers.Cut()
for(var/key in contact_datums)
var/datum/overmap_contact/record = contact_datums[key]
qdel(record)
contact_datums.Cut()
. = ..()
/obj/machinery/computer/ship/sensors/attempt_hook_up(obj/effect/overmap/visitable/ship/sector)
. = ..()
if(. && linked && !contact_datums[linked])
var/datum/overmap_contact/record = new(src, linked)
contact_datums[linked] = record
record.marker.alpha = 255
/obj/machinery/computer/ship/sensors/proc/reveal_contacts(var/mob/user)
if(user && user.client)
for(var/key in contact_datums)
var/datum/overmap_contact/record = contact_datums[key]
if(record)
user.client.images |= record.marker
/obj/machinery/computer/ship/sensors/proc/hide_contacts(var/mob/user)
if(user && user.client)
for(var/key in contact_datums)
var/datum/overmap_contact/record = contact_datums[key]
if(record)
user.client.images -= record.marker
/obj/machinery/computer/ship/sensors/process()
..()
update_sound()
if(!linked)
return
// Update our own marker icon regardless of power or sensor connections.
var/sensor_range = 0
var/obj/machinery/shipsensors/sensors = get_sensors()
if(sensors?.use_power)
sensor_range = round(sensors.range,1)
var/datum/overmap_contact/self_record = contact_datums[linked]
self_record.update_marker_icon()
self_record.ping_radar(sensor_range)
self_record.show()
// Update our 'sensor range' (ie. overmap lighting)
if(!sensors || !sensors.use_power || (stat & (NOPOWER|BROKEN)))
datalink_remove_all_ships_datalink()
for(var/key in contact_datums)
var/datum/overmap_contact/record = contact_datums[key]
if(record.effect == linked)
continue
qdel(record) // Immediately cut records if power is lost.
objects_in_view.Cut()
return
// What can we see?
var/list/objects_in_current_view = list()
// Find all sectors with a tracker on their z-level. Only works on ships when they are in space.
for(var/obj/item/ship_tracker/tracker in trackers)
if(tracker.enabled)
var/obj/effect/overmap/visitable/tracked_effect = overmap_sectors["[GET_Z(tracker)]"]
if(tracked_effect && istype(tracked_effect) && tracked_effect != linked && tracked_effect.requires_contact)
objects_in_current_view[tracked_effect] = TRUE
objects_in_view[tracked_effect] = 100
// Handle datalinked view
datalink_process()
for(var/obj/effect/overmap/contact in view(sensor_range, linked))
if(contact == linked)
continue
if(!contact.requires_contact) // Only some effects require contact for visibility.
continue
objects_in_current_view[contact] = TRUE
if(contact.instant_contact) // Instantly identify the object in range.
objects_in_view[contact] = 100
else if(!(contact in objects_in_view))
objects_in_view[contact] = 0
for(var/obj/effect/overmap/contact in objects_in_view) //Update everything.
// Are we already aware of this object?
var/datum/overmap_contact/record = contact_datums[contact]
// Fade out and remove anything that is out of range.
if(QDELETED(contact) || !objects_in_current_view[contact]) // Object has exited sensor range.
if(record)
animate(record.marker, alpha=0, 2 SECOND, 1, LINEAR_EASING)
QDEL_IN(record, 2 SECOND) // Need to restart the search if you've lost contact with the object.
if(contact.scannable) // Scannable objects are the only ones that give off notifications to prevent spam
visible_message(SPAN_NOTICE("\The [src] states, \"Contact lost with [record.name].\""))
playsound(loc, "sound/machines/sensors/contact_lost.ogg", 30, 1)
objects_in_view -= contact
continue
// Generate contact information for this overmap object.
var/bearing = round(90 - Atan2(contact.x - linked.x, contact.y - linked.y),5)
if(bearing < 0)
bearing += 360
if(!record) // Begin attempting to identify ship.
// The chance of detection decreases with distance to the target ship.
if(contact.scannable && prob((SENSORS_DISTANCE_COEFFICIENT * contact.sensor_visibility)/max(get_dist(linked, contact), 0.5)))
var/bearing_variability = round(30/sensors.sensor_strength, 5)
var/bearing_estimate = round(rand(bearing-bearing_variability, bearing+bearing_variability), 5)
if(bearing_estimate < 0)
bearing_estimate += 360
// Give the player an idea of where the ship is in relation to the ship.
if(objects_in_view[contact] <= 0)
if(!muted)
visible_message(SPAN_NOTICE("<b>\The [src]</b> states, \"Unknown contact designation '[contact.unknown_id]' detected nearby, bearing [bearing_estimate], error +/- [bearing_variability]. Beginning trace.\""))
objects_in_view[contact] = round(sensors.sensor_strength**2)
else
objects_in_view[contact] += round(sensors.sensor_strength**2)
if(!muted)
visible_message(SPAN_NOTICE("<b>\The [src]</b> states, \"Contact '[contact.unknown_id]' tracing [objects_in_view[contact]]% complete, bearing [bearing_estimate], error +/- [bearing_variability].\""))
playsound(loc, "sound/machines/sensors/contactgeneric.ogg", 10, 1) //Let players know there's something nearby.
if(objects_in_view[contact] >= 100) // Identification complete.
record = new /datum/overmap_contact(src, contact)
contact_datums[contact] = record
if(contact.scannable)
playsound(loc, "sound/machines/sensors/newcontact.ogg", 30, 1)
visible_message(SPAN_NOTICE("<b>\The [src]</b> states, \"New contact identified, designation [record.name], bearing [bearing].\""))
record.show()
animate(record.marker, alpha=255, 2 SECOND, 1, LINEAR_EASING)
continue
// Update identification information for this record.
record.update_marker_icon()
var/time_delay = max((SENSOR_TIME_DELAY * get_dist(linked, contact)),1)
if(!record.pinged)
addtimer(CALLBACK(record, PROC_REF(ping)), time_delay)
/obj/machinery/computer/ship/sensors/attackby(var/obj/item/I, var/mob/user)
. = ..()
var/obj/item/device/multitool/P = I
if(!istype(P))
return
var/obj/item/ship_tracker/tracker = P.get_buffer()
if(!tracker || !istype(tracker))
return
if(tracker in trackers)
trackers -= tracker
destroyed_event.unregister(tracker, src, PROC_REF(remove_tracker))
to_chat(user, SPAN_NOTICE("You unlink the tracker in \the [P]'s buffer from \the [src]."))
return
trackers += tracker
destroyed_event.register(tracker, src, PROC_REF(remove_tracker))
to_chat(user, SPAN_NOTICE("You link the tracker in \the [P]'s buffer to \the [src]."))
/obj/machinery/computer/ship/sensors/proc/remove_tracker(var/obj/item/ship_tracker/tracker)
trackers -= tracker
/obj/machinery/computer/ship/sensors/proc/datalink_process()
for(var/obj/effect/overmap/visitable/datalink_ship in src.connected.datalinked) // Get ships that are datalinked with us
for(var/obj/machinery/computer/ship/sensors/sensor_console in datalink_ship.consoles) // Pick one sensor console
var/list/diff_datalink_contacts = list()
// If it's not a known datalinked ship already, initalize its list of supplied contacts
if(!length(datalink_contacts[datalink_ship]))
datalink_contacts[datalink_ship] = list()
datalink_process_all_contacts_of_console(sensor_console, datalink_ship)
// If it's a known datalink, compute the lost contacts to remove
if(datalink_contacts[datalink_ship])
diff_datalink_contacts = datalink_contacts[datalink_ship] - (sensor_console.objects_in_view + list(datalink_ship))
for(var/obj/effect/overmap/datalink_contact in diff_datalink_contacts)
datalink_remove_contact(datalink_contact, datalink_ship)
continue
// Handle the datalinked ship's own contact
var/datum/overmap_contact/ship_contact_record = contact_datums[datalink_ship]
if(!ship_contact_record)
datalink_add_contact(datalink_ship, datalink_ship, force = TRUE)
ship_contact_record = contact_datums[datalink_ship]
ship_contact_record.ping()
ship_contact_record.update_marker_icon()
/obj/machinery/computer/ship/sensors/proc/datalink_process_all_contacts_of_console(var/obj/machinery/computer/ship/sensors/sensor_console, var/obj/effect/overmap/visitable/datalink_ship)
for(var/obj/effect/overmap/datalink_contact in sensor_console.objects_in_view) // Pick one contact that the sensor console has
if(datalink_contact != src.connected)
if(!(datalink_contact in datalink_contacts[datalink_ship])) // This is a new datalink contact
if(!(contact_datums[datalink_contact]))
datalink_add_contact(datalink_contact, datalink_ship)
else
var/datum/overmap_contact/datalink_contact_record = contact_datums[datalink_contact]
if(datalink_contact_record && !QDELING(datalink_contact_record))
datalink_contact_record.ping()
/obj/machinery/computer/ship/sensors/proc/datalink_remove_all_contacts_of_console(var/obj/machinery/computer/ship/sensors/sensor_console, var/obj/effect/overmap/visitable/datalink_ship)
for(var/obj/effect/overmap/datalink_contact in sensor_console.objects_in_view)
if(datalink_contact != src.connected)
datalink_remove_contact(datalink_contact, datalink_ship)
/obj/machinery/computer/ship/sensors/proc/datalink_add_contact(var/obj/effect/overmap/datalink_contact, var/obj/effect/overmap/visitable/datalink_ship, var/force = FALSE)
if(!(datalink_contact in datalink_contacts[datalink_ship]) && !(objects_in_view[datalink_contact]) || force) // This is a new datalink contact
var/datum/overmap_contact/datalink_contact_record = contact_datums[datalink_contact] // Is it already in the contact_datums?
if(!datalink_contact_record) // If not, create it
datalink_contact_record = new /datum/overmap_contact(src, datalink_contact)
contact_datums[datalink_contact] = datalink_contact_record // And add it with its associated effect
if(!QDELING(datalink_contact_record))
// Show the new contact
datalink_contact_record.show()
datalink_contact_record.ping()
animate(datalink_contact_record.marker, alpha=255, 2 SECOND, 1, LINEAR_EASING)
datalink_contact_record.update_marker_icon()
// Add it to the contact datum
if(!datalink_contacts[datalink_ship])
datalink_contacts[datalink_ship] = list()
datalink_contacts[datalink_ship] |= list(datalink_contact)
/obj/machinery/computer/ship/sensors/proc/datalink_remove_contact(var/obj/effect/overmap/datalink_contact, var/obj/effect/overmap/visitable/datalink_ship)
var/datum/overmap_contact/datalink_contact_record = contact_datums[datalink_contact] // Retrieve the contact record
if(!datalink_contact_record)
return
animate(datalink_contact_record.marker, alpha=0, 2 SECOND, 1, LINEAR_EASING)
QDEL_IN(datalink_contact_record, 2 SECOND)
if(datalink_contacts[datalink_ship])
datalink_contacts[datalink_ship] -= list(datalink_contact)
/obj/machinery/computer/ship/sensors/proc/datalink_add_ship_datalink(var/obj/effect/overmap/visitable/datalink_ship)
datalink_ship.datalinked |= src.connected
src.connected.datalinked |= datalink_ship
/obj/machinery/computer/ship/sensors/proc/datalink_remove_ship_datalink(var/obj/effect/overmap/visitable/datalink_ship)
if(datalink_contacts[datalink_ship])
for(var/obj/machinery/computer/ship/sensors/sensor_console in datalink_ship.consoles)
// Remove the two ships from each other's datalinked list
src.connected.datalinked -= datalink_ship
datalink_ship.datalinked -= src.connected
// Removes the ship contact itself from the contacts
var/datum/overmap_contact/ship_contact_record = contact_datums[datalink_ship]
if(ship_contact_record)
animate(ship_contact_record.marker, alpha=0, 2 SECOND, 1, LINEAR_EASING)
QDEL_IN(ship_contact_record, 2 SECOND)
//contact_datums[datalink_ship] -= ship_contact_record
// Remove all contacts
datalink_remove_all_contacts_of_console(sensor_console, datalink_ship)
datalink_contacts.Remove(datalink_ship)
// Recurse the function on the other ship's instance
sensor_console.datalink_remove_ship_datalink(src.connected)
visible_message(SPAN_NOTICE("<b>\The [src]</b> states, \"A datalink contact was sewered! Recalibration...\""))
/obj/machinery/computer/ship/sensors/proc/datalink_remove_all_ships_datalink()
for(var/obj/effect/overmap/visitable/datalink_ship in linked.datalinked)
for(var/obj/machinery/computer/ship/sensors/sensor_console in datalink_ship.consoles)
sensor_console.datalink_remove_ship_datalink(linked)
break
#undef SENSORS_DISTANCE_COEFFICIENT

View File

@@ -0,0 +1,23 @@
/obj/item/ship_tracker
name = "long range tracker"
desc = "A complex device that transmits conspicuous signals, easily locked onto by modern sensors hardware."
icon = 'icons/obj/ship_tracker.dmi'
icon_state = "disabled"
origin_tech = "{'magnets':3, 'programming':2}"
var/enabled = FALSE
/obj/item/ship_tracker/Initialize()
. = ..()
/obj/item/ship_tracker/attack_self(var/mob/user)
enabled = !enabled
to_chat(user, SPAN_NOTICE("You [enabled ? "enable" : "disable"] \the [src]"))
update_icon()
/obj/item/ship_tracker/proc/on_update_icon()
icon_state = enabled ? "enabled" : "disabled"
/obj/item/ship_tracker/examine(var/mob/user)
. = ..()
to_chat(user, "It appears to be [enabled ? "enabled" : "disabled"]")

View File

@@ -168,14 +168,18 @@
/obj/effect/overmap/event
name = "event"
icon = 'icons/obj/overmap.dmi'
icon_state = "event"
opacity = 1
icon_state = "blank"
opacity = 0
var/list/events
var/list/event_icon_states = list("event")
var/difficulty = EVENT_LEVEL_MODERATE
var/list/victims //basically cached events on which Z level
var/can_be_destroyed = TRUE //Can this event be destroyed by ship guns?
// Events must be detected by sensors, but are otherwise instantly visible.
requires_contact = TRUE
instant_contact = TRUE
// Vars that determine movability, current moving direction, and moving speed //
/// Whether this event can move or not
var/movable_event = FALSE
@@ -194,6 +198,8 @@
/// Ticks up each process until move speed is matched, at which point the event will move
var/ship_delay_counter = 0
var/list/colors = list() //Pick a color from this list on init
/obj/effect/overmap/event/Initialize()
. = ..()
icon_state = pick(event_icon_states)
@@ -202,6 +208,8 @@
start_moving()
else if(prob(movable_event_chance))
make_movable()
if(LAZYLEN(colors))
color = pick(colors)
/obj/effect/overmap/event/proc/make_movable()
movable_event = TRUE
@@ -258,6 +266,7 @@
events = list(/datum/event/meteor_wave/overmap)
event_icon_states = list("meteor1", "meteor2", "meteor3", "meteor4")
difficulty = EVENT_LEVEL_MAJOR
colors = list("#fc1100", "#b5251b", "#be1e12")
/obj/effect/overmap/event/electric
name = "electrical storm"
@@ -266,6 +275,7 @@
event_icon_states = list("electrical1", "electrical2")
difficulty = EVENT_LEVEL_MAJOR
can_be_destroyed = FALSE
colors = list("#f5ed0c", "#d9d323", "#faf450")
/obj/effect/overmap/event/dust
name = "dust cloud"
@@ -280,6 +290,7 @@
event_icon_states = list("ion1", "ion2", "ion3", "ion4")
difficulty = EVENT_LEVEL_MAJOR
can_be_destroyed = FALSE
colors = list("#02faee", "#34d1c9", "#1b9ce7")
/obj/effect/overmap/event/carp
name = "carp shoal"
@@ -288,10 +299,12 @@
difficulty = EVENT_LEVEL_MODERATE
event_icon_states = list("carp")
movable_event_chance = 5
colors = list("#c25bc7", "#ea50f2", "#f67efc")
/obj/effect/overmap/event/carp/major
name = "carp school"
difficulty = EVENT_LEVEL_MAJOR
colors = list("#a709db", "#c228c7", "#c444e4")
/obj/effect/overmap/event/gravity
name = "dark matter influx"

View File

@@ -8,6 +8,14 @@
var/known = 0 //shows up on nav computers automatically
var/scannable //if set to TRUE will show up on ship sensors for detailed scans
var/unknown_id // A unique identifier used when this entity is scanned. Assigned in Initialize().
var/requires_contact = TRUE //whether or not the effect must be identified by ship sensors before being seen.
var/instant_contact = FALSE //do we instantly identify ourselves to any ship in sensors range?
var/sensor_visibility = 10 //how likely it is to increase identification process each scan.
var/vessel_mass = 10000 // metric tonnes, very rough number, affects acceleration provided by engines
var/image/targeted_overlay
//Overlay of how this object should look on other skyboxes
@@ -49,6 +57,9 @@
H.get_known_sectors()
update_icon()
if(requires_contact)
invisibility = INVISIBILITY_OVERMAP // Effects that require identification have their images cast to the client via sensors.
/obj/effect/overmap/Crossed(var/obj/effect/overmap/visitable/other)
if(istype(other))
for(var/obj/effect/overmap/visitable/O in loc)

View File

@@ -8,6 +8,7 @@ var/global/area/overmap/map_overmap // Global object used to locate the overmap
scannable = TRUE
var/designation //Actual name of the object.
var/class //Imagine a ship or station's class. "NTCC" Odin, "SCCV" Horizon, ...
unknown_id = "Bogey"
var/obfuscated_name = "unidentified object"
var/obfuscated_desc = "This object is not displaying its IFF signature."
var/obfuscated = FALSE //Whether we hide our name and class or not.
@@ -40,6 +41,11 @@ var/global/area/overmap/map_overmap // Global object used to locate the overmap
var/comms_name = "shipboard"
/// Whether away ship comms have access to the common channel / PUB_FREQ
var/use_common = FALSE
var/list/navigation_viewers // list of weakrefs to people viewing the overmap via this ship
var/list/consoles
var/list/datalink_requests = list()// A list of datalink requests that we received
var/list/datalinked = list()// Other effects that we are datalinked with
/obj/effect/overmap/visitable/Initialize()
. = ..()

View File

@@ -9,6 +9,16 @@
circuit = /obj/item/circuitboard/ship/sensors
linked_type = /obj/effect/overmap/visitable
var/working_sound = 'sound/machines/sensors/dradis.ogg'
var/datum/sound_token/sound_token
var/sound_id
var/datum/weakref/sensor_ref
var/list/last_scan
/obj/machinery/computer/ship/sensors/proc/get_sensors()
return sensors
/obj/machinery/computer/ship/sensors/attempt_hook_up(var/obj/effect/overmap/visitable/sector)
. = ..()
if(!.)
@@ -27,6 +37,21 @@
identification = IB
break
/obj/machinery/computer/ship/sensors/proc/update_sound()
if(!working_sound)
return
if(!sound_id)
sound_id = "[type]_[sequential_id(/obj/machinery/computer/ship/sensors)]"
var/obj/machinery/shipsensors/sensors = get_sensors()
if(linked && sensors?.use_power && !(sensors.stat & NOPOWER))
var/volume = 10
if(!sound_token)
sound_token = sound_player.PlayLoopingSound(src, sound_id, working_sound, volume = volume, range = 10)
sound_token.SetVolume(volume)
else if(sound_token)
QDEL_NULL(sound_token)
/obj/machinery/computer/ship/sensors/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(!linked)
display_reconnect_dialog(user, "sensors")
@@ -35,6 +60,7 @@
var/data[0]
data["viewing"] = viewing_overmap(user)
data["muted"] = muted
if(sensors)
data["on"] = sensors.use_power
data["range"] = sensors.range
@@ -62,8 +88,22 @@
distress_beacons.Add(list(list("caller" = vessel.name, "sender" = "[job_string][H.name]", "bearing" = bearing)))
if(length(distress_beacons))
data["distress_beacons"] = distress_beacons
var/list/contacts = list()
for(var/obj/effect/overmap/O in view(7,linked))
var/list/potential_contacts = list()
for(var/obj/effect/overmap/nearby in view(7,linked))
if(nearby.requires_contact) // Some ships require.
continue
potential_contacts |= nearby
// Effects that require contact are only added to the contacts if they have been identified.
// Allows for coord tracking out of range of the player's view.
for(var/obj/effect/overmap/visitable/identified_contact in contact_datums)
potential_contacts |= identified_contact
for(var/obj/effect/overmap/O in potential_contacts)
if(linked == O)
continue
if(!O.scannable)
@@ -74,6 +114,21 @@
contacts.Add(list(list("name"=O.name, "ref"="\ref[O]", "bearing"=bearing)))
if(length(contacts))
data["contacts"] = contacts
// Add datalink requests
if(length(connected.datalink_requests))
var/list/local_datalink_requests = list()
for(var/obj/effect/overmap/visitable/requestor in connected.datalink_requests)
local_datalink_requests.Add(list(list("name"=requestor.name, "ref"="\ref[requestor]")))
data["datalink_requests"] = local_datalink_requests
if(length(connected.datalinked))
var/list/local_datalinked = list()
for(var/obj/effect/overmap/visitable/datalinked_ship in connected.datalinked)
local_datalinked.Add(list(list("name"=datalinked_ship.name, "ref"="\ref[datalinked_ship]")))
data["datalinked"] = local_datalinked
data["last_scan"] = last_scan
else
data["status"] = "MISSING"
data["range"] = "N/A"
@@ -168,11 +223,43 @@
if (href_list["scan"])
var/obj/effect/overmap/O = locate(href_list["scan"])
if(istype(O) && !QDELETED(O) && (O in view(7,linked)))
playsound(loc, "sound/machines/dotprinter.ogg", 30, 1)
new/obj/item/paper/(get_turf(src), O.get_scan_data(usr), "paper (Sensor Scan - [O])")
if(istype(O) && !QDELETED(O))
if((O in view(7,linked))|| (O in contact_datums))
playsound(loc, "sound/machines/dotprinter.ogg", 30, 1)
LAZYSET(last_scan, "data", O.get_scan_data(usr))
LAZYSET(last_scan, "location", "[O.x],[O.y]")
LAZYSET(last_scan, "name", "[O]")
to_chat(usr, SPAN_NOTICE("Successfully scanned [O]."))
new/obj/item/paper/(get_turf(src), O.get_scan_data(usr), "paper (Sensor Scan - [O])")
return TOPIC_HANDLED
if (href_list["request_datalink"])
var/obj/effect/overmap/visitable/O = locate(href_list["request_datalink"])
if(istype(O) && !QDELETED(O))
if((O in view(7,linked)) || (O in contact_datums))
for(var/obj/machinery/computer/ship/sensors/sensor_console in O.consoles)
sensor_console.connected.datalink_requests |= src.connected
return TOPIC_HANDLED
if (href_list["accept_datalink_requests"])
var/obj/effect/overmap/visitable/O = locate(href_list["accept_datalink_requests"])
for(var/obj/machinery/computer/ship/sensors/sensor_console in src.connected.consoles)
sensor_console.datalink_add_ship_datalink(O)
break
src.connected.datalink_requests -= O // Remove the request
return TOPIC_HANDLED
if (href_list["decline_datalink_requests"])
var/obj/effect/overmap/visitable/O = locate(href_list["decline_datalink_requests"])
src.connected.datalink_requests -= O // Remove the request
if (href_list["remove_datalink"])
var/obj/effect/overmap/visitable/O = locate(href_list["remove_datalink"])
for(var/obj/machinery/computer/ship/sensors/rescinder_sensor_console in src.connected.consoles) // Get sensor console from the rescinder
rescinder_sensor_console.datalink_remove_ship_datalink(O)
return TOPIC_HANDLED
if (href_list["play_message"])
var/caller = href_list["play_message"]
var/datum/distress_beacon/beacon = SSdistress.active_distress_beacons[caller]
@@ -192,18 +279,6 @@
security_announcement.Announce("No fire is incoming at the current moment, resume damage control.", "Space clear!", sound('sound/misc/announcements/security_level_old.ogg'), 0)
return TOPIC_HANDLED
/obj/machinery/computer/ship/sensors/process()
..()
if(!linked)
return
if(sensors && sensors.use_power && sensors.powered())
var/sensor_range = round(sensors.range*1.5) + 1
linked.set_light(sensor_range, sensor_range+1, light_color)
linked.handle_sensor_state_change(TRUE)
else
linked.set_light(0)
linked.handle_sensor_state_change(FALSE)
/obj/machinery/shipsensors
name = "sensors suite"
desc = "Long range gravity scanner with various other sensors, used to detect irregularities in surrounding space. Can only run in vacuum to protect delicate quantum BS elements."
@@ -216,6 +291,7 @@
var/heat_reduction = 0.5 // mitigates this much heat per tick - can sustain range 2
var/heat = 0
var/range = 1
var/sensor_strength = 5//used for detecting ships via contacts
idle_power_usage = 5000
var/base_icon_state

View File

@@ -56,6 +56,8 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
if(user.eyeobj)
moved_event.register(user.eyeobj, src, PROC_REF(unlook))
LAZYDISTINCTADD(viewers, WEAKREF(user))
if(linked)
LAZYDISTINCTADD(linked.navigation_viewers, WEAKREF(user))
/obj/machinery/computer/ship/proc/unlook(var/mob/user)
user.reset_view()
@@ -78,9 +80,15 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
moved_event.unregister(E.owner, src, PROC_REF(unlook))
LAZYREMOVE(viewers, WEAKREF(E.owner))
LAZYREMOVE(viewers, WEAKREF(user))
if(linked)
LAZYREMOVE(linked.navigation_viewers, WEAKREF(user))
if(linked)
for(var/obj/machinery/computer/ship/sensors/sensor in linked.consoles)
sensor.hide_contacts(user)
/obj/machinery/computer/ship/proc/viewing_overmap(mob/user)
return (WEAKREF(user) in viewers)
return (WEAKREF(user) in viewers) || (linked && (WEAKREF(user) in linked.navigation_viewers))
/obj/machinery/computer/ship/CouldNotUseTopic(mob/user)
. = ..()
@@ -102,6 +110,8 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
return 0
/obj/machinery/computer/ship/Destroy()
if(linked)
linked = null
if(connected)
LAZYREMOVE(connected.consoles, src)
. = ..()
@@ -114,6 +124,8 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
var/M = W.resolve()
if(M)
unlook(M)
if(linked)
LAZYREMOVE(linked.navigation_viewers, W)
. = ..()
/obj/machinery/computer/ship/on_user_login(mob/M)

View File

@@ -14,10 +14,14 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND)
name = "generic ship"
desc = "Space faring vessel."
icon_state = "ship"
requires_contact = TRUE
obfuscated_name = "unidentified vessel"
var/moving_state = "ship_moving"
var/vessel_mass = 10000 //tonnes, arbitrary number, affects acceleration provided by engines
var/list/known_ships = list() //List of ships known at roundstart - put types here.
var/base_sensor_visibility
vessel_mass = 10000 //tonnes, arbitrary number, affects acceleration provided by engines
var/vessel_size = SHIP_SIZE_LARGE //arbitrary number, affects how likely are we to evade meteors
var/max_speed = 1/(1 SECOND) //"speed of light" for the ship, in turfs/tick.
var/min_speed = 1/(2 MINUTES) // Below this, we round speed to 0 to avoid math errors.
@@ -35,8 +39,6 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND)
var/thrust_limit = 1 //global thrust limit for all engines, 0..1
var/halted = 0 //admin halt or other stop.
var/list/consoles
comms_support = TRUE
/obj/effect/overmap/visitable/ship/Initialize()
@@ -44,6 +46,7 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND)
glide_size = world.icon_size
min_speed = round(min_speed, SHIP_MOVE_RESOLUTION)
max_speed = round(max_speed, SHIP_MOVE_RESOLUTION)
base_sensor_visibility = round((vessel_mass/SENSOR_COEFFICENT),1)
SSshuttle.ships += src
/obj/effect/overmap/visitable/ship/find_z_levels(var/fore_direction)
@@ -68,8 +71,11 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND)
/obj/effect/overmap/visitable/ship/get_scan_data(mob/user)
. = ..()
. += "<br>Mass: [vessel_mass] tons."
if(!is_still())
. += "<br>Heading: [dir2angle(get_heading())], speed [get_speed() * 1000]"
if(instant_contact)
. += "<br>It is broadcasting a distress signal."
//Projected acceleration based on information from engines
/obj/effect/overmap/visitable/ship/proc/get_acceleration()
@@ -165,6 +171,7 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND)
if(newloc && loc != newloc)
Move(newloc)
handle_wraparound()
sensor_visibility = min(round(base_sensor_visibility + get_speed_sensor_increase(), 1), 100)
/obj/effect/overmap/visitable/ship/update_icon()
pixel_x = position[1] * (world.icon_size/2)
@@ -306,6 +313,9 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND)
for(var/obj/machinery/computer/ship/targeting/TR in consoles)
TR.visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(TR)))] Hit confirmed on [hit_data["target_name"]] in [hit_data["target_area"]] at coordinates [hit_data["coordinates"]]."), range = 2)
/obj/effect/overmap/visitable/ship/proc/get_speed_sensor_increase()
return min(get_speed() * 1000, 50) //Engines should never increase sensor visibility by more than 50.
#undef MOVING
#undef SANITIZE_SPEED
#undef CHANGE_SPEED_BY