diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm
index 5b38b592ac6..35701e7f5b3 100644
--- a/code/__DEFINES/machines.dm
+++ b/code/__DEFINES/machines.dm
@@ -81,4 +81,14 @@
#define TARGET_DEPT_SEC 2
#define TARGET_DEPT_MED 3
#define TARGET_DEPT_SCI 4
-#define TARGET_DEPT_ENG 5
\ No newline at end of file
+#define TARGET_DEPT_ENG 5
+
+// These are used by supermatter and supermatter monitor program, mostly for UI updating purposes. Higher should always be worse!
+#define SUPERMATTER_ERROR -1 // Unknown status, shouldn't happen but just in case.
+#define SUPERMATTER_INACTIVE 0 // No or minimal energy
+#define SUPERMATTER_NORMAL 1 // Normal operation
+#define SUPERMATTER_NOTIFY 2 // Ambient temp > 80% of CRITICAL_TEMPERATURE
+#define SUPERMATTER_WARNING 3 // Ambient temp > CRITICAL_TEMPERATURE OR integrity damaged
+#define SUPERMATTER_DANGER 4 // Integrity < 50%
+#define SUPERMATTER_EMERGENCY 5 // Integrity < 25%
+#define SUPERMATTER_DELAMINATING 6 // Pretty obvious.
diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm
index 6e0be3b385f..5dd324945fa 100644
--- a/code/modules/modular_computers/computers/machinery/console_presets.dm
+++ b/code/modules/modular_computers/computers/machinery/console_presets.dm
@@ -36,6 +36,7 @@
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/power_monitor())
hard_drive.store_file(new/datum/computer_file/program/alarm_monitor())
+ hard_drive.store_file(new/datum/computer_file/program/supermatter_monitor())
// ===== RESEARCH CONSOLE =====
/obj/machinery/modular_computer/console/preset/research
diff --git a/code/modules/modular_computers/file_system/programs/engineering/sm_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/sm_monitor.dm
new file mode 100644
index 00000000000..b05783e2bcb
--- /dev/null
+++ b/code/modules/modular_computers/file_system/programs/engineering/sm_monitor.dm
@@ -0,0 +1,137 @@
+/datum/computer_file/program/supermatter_monitor
+ filename = "smmonitor"
+ filedesc = "Supermatter Monitoring"
+ ui_header = "smmon_0.gif"
+ program_icon_state = "smmon_0"
+ extended_desc = "This program connects to specially calibrated supermatter sensors to provide information on the status of supermatter-based engines."
+ requires_ntnet = TRUE
+ transfer_access = access_engine
+ network_destination = "supermatter monitoring system"
+ size = 5
+ requires_ntnet = 1
+ var/last_status = SUPERMATTER_INACTIVE
+ var/list/supermatters
+ var/obj/machinery/power/supermatter_shard/active // Currently selected supermatter crystal.
+
+
+/datum/computer_file/program/supermatter_monitor/process_tick()
+ ..()
+ var/new_status = get_status()
+ if(last_status != new_status)
+ last_status = new_status
+ ui_header = "smmon_[last_status].gif"
+ program_icon_state = "smmon_[last_status]"
+ update_computer_icon()
+
+/datum/computer_file/program/supermatter_monitor/run_program(mob/living/user)
+ . = ..(user)
+ refresh()
+
+/datum/computer_file/program/supermatter_monitor/kill_program(forced = FALSE)
+ active = null
+ supermatters = null
+ ..()
+
+// Refreshes list of active supermatter crystals
+/datum/computer_file/program/supermatter_monitor/proc/refresh()
+ supermatters = list()
+ var/turf/T = get_turf(nano_host())
+ if(!T)
+ return
+ for(var/obj/machinery/power/supermatter_shard/S in atmos_machinery)
+ // Delaminating, not within coverage, not on a tile.
+ if(!(S.z == 1 || S.z == 5 || S.z == T.z) || !istype(S.loc, /turf/simulated/))
+ continue
+ supermatters.Add(S)
+
+ if(!(active in supermatters))
+ active = null
+
+/datum/computer_file/program/supermatter_monitor/proc/get_status()
+ . = SUPERMATTER_INACTIVE
+ for(var/obj/machinery/power/supermatter_shard/S in supermatters)
+ . = max(., S.get_status())
+
+/datum/computer_file/program/supermatter_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
+ assets.send(user)
+ ui = new(user, src, ui_key, "supermatter_monitor.tmpl", "Supermatter Monitoring", 600, 400)
+ ui.set_auto_update(TRUE)
+ ui.set_layout_key("program")
+ ui.open()
+
+/datum/computer_file/program/supermatter_monitor/ui_data()
+ var/list/data = get_header_data()
+
+ if(istype(active))
+ var/turf/T = get_turf(active)
+ if(!T)
+ active = null
+ refresh()
+ return
+ var/datum/gas_mixture/air = T.return_air()
+ if(!air)
+ active = null
+ return
+
+ data["active"] = TRUE
+ data["SM_integrity"] = active.get_integrity()
+ data["SM_power"] = active.power
+ data["SM_ambienttemp"] = air.temperature
+ data["SM_ambientpressure"] = air.return_pressure()
+ //data["SM_EPR"] = round((air.total_moles / air.group_multiplier) / 23.1, 0.01)
+ var/other_moles = 0.0
+ for(var/datum/gas/G in air.trace_gases)
+ other_moles+=G.moles
+ var/TM = air.total_moles()
+ if(TM)
+ data["SM_gas_O2"] = round(100*air.oxygen/TM,0.01)
+ data["SM_gas_CO2"] = round(100*air.carbon_dioxide/TM,0.01)
+ data["SM_gas_N2"] = round(100*air.nitrogen/TM,0.01)
+ data["SM_gas_PL"] = round(100*air.toxins/TM,0.01)
+ if(other_moles)
+ data["SM_gas_OTHER"] = round(100*other_moles/TM,0.01)
+ else
+ data["SM_gas_OTHER"] = 0
+ else
+ data["SM_gas_O2"] = 0
+ data["SM_gas_CO2"] = 0
+ data["SM_gas_N2"] = 0
+ data["SM_gas_PH"] = 0
+ data["SM_gas_OTHER"] = 0
+ else
+ var/list/SMS = list()
+ for(var/obj/machinery/power/supermatter_shard/S in supermatters)
+ var/area/A = get_area(S)
+ if(!A)
+ continue
+
+ SMS.Add(list(list(
+ "area_name" = A.name,
+ "integrity" = S.get_integrity(),
+ "uid" = S.uid
+ )))
+
+ data["active"] = FALSE
+ data["supermatters"] = SMS
+
+ return data
+
+
+/datum/computer_file/program/supermatter_monitor/Topic(href, href_list)
+ if(..())
+ return 1
+ if( href_list["clear"] )
+ active = null
+ return 1
+ if( href_list["refresh"] )
+ refresh()
+ return 1
+ if( href_list["set"] )
+ var/newuid = text2num(href_list["set"])
+ for(var/obj/machinery/power/supermatter_shard/S in supermatters)
+ if(S.uid == newuid)
+ active = S
+ return 1
\ No newline at end of file
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 43d418aadf7..c6cce90a278 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -16,6 +16,12 @@
#define WARNING_DELAY 30 //seconds between warnings.
+//If integrity percent remaining is less than these values, the monitor sets off the relevant alarm.
+#define SUPERMATTER_DELAM_PERCENT 5
+#define SUPERMATTER_EMERGENCY_PERCENT 25
+#define SUPERMATTER_DANGER_PERCENT 50
+#define SUPERMATTER_WARNING_PERCENT 100
+
/obj/machinery/power/supermatter_shard
name = "supermatter shard"
desc = "A strangely translucent and iridescent crystal that looks like it used to be part of a larger structure. You get headaches just from looking at it."
@@ -62,9 +68,23 @@
var/has_been_powered = 0
var/has_reached_emergency = 0
+/obj/machinery/power/supermatter_shard/crystal
+ name = "supermatter crystal"
+ desc = "A strangely translucent and iridescent crystal."
+ base_icon_state = "darkmatter"
+ icon_state = "darkmatter"
+ anchored = TRUE
+ warning_point = 200
+ emergency_point = 2000
+ explosion_point = 3600
+ gasefficency = 0.15
+ explosion_power = 35
+
+
/obj/machinery/power/supermatter_shard/New()
. = ..()
poi_list |= src
+ atmos_machinery += src
radio = new(src)
radio.listening = 0
investigate_log("has been created.", "supermatter")
@@ -74,15 +94,16 @@
investigate_log("has been destroyed.", "supermatter")
QDEL_NULL(radio)
poi_list.Remove(src)
+ atmos_machinery -= src
return ..()
/obj/machinery/power/supermatter_shard/proc/explode()
investigate_log("has exploded.", "supermatter")
- explosion(get_turf(src), explosion_power, explosion_power * 2, explosion_power * 3, explosion_power * 4, 1)
+ explosion(get_turf(src), explosion_power, explosion_power * 1.2, explosion_power * 1.5, explosion_power * 2, 1, 1)
qdel(src)
return
-/obj/machinery/power/supermatter_shard/process()
+/obj/machinery/power/supermatter_shard/process_atmos()
var/turf/L = loc
if(isnull(L)) // We have a null turf...something is wrong, stop processing this entity.
@@ -96,6 +117,7 @@
if(damage > warning_point) // while the core is still damaged and it's still worth noting its status
if((world.timeofday - lastwarning) / 10 >= WARNING_DELAY)
+ alarm()
var/stability = num2text(round((damage / explosion_point) * 100))
if(damage > emergency_point)
@@ -136,12 +158,12 @@
var/datum/gas_mixture/removed = env.remove(gasefficency * env.total_moles())
if(!removed || !removed.total_moles())
- damage += max((power-1600)/10, 0)
+ damage += max((power-1600)/2, 0)
power = min(power, 1600)
return 1
damage_archived = damage
- damage = max( damage + ( (removed.temperature - 800) / 150 ) , 0 )
+ damage = max( damage + ( (removed.temperature - 800) / 50 ) , 0 )
//Ok, 100% oxygen atmosphere = best reaction
//Maxes out at 100% oxygen pressure
oxygen = max(min((removed.oxygen - (removed.nitrogen * NITROGEN_RETARDATION_FACTOR)) / MOLES_CELLSTANDARD, 1), 0)
@@ -181,6 +203,8 @@
env.merge(removed)
+ air_update_turf()
+
for(var/mob/living/carbon/human/l in view(src, min(7, round(sqrt(power/6)))))
// If they can see it without mesons on. Bad on them.
if(l.glasses && istype(l.glasses, /obj/item/clothing/glasses/meson))
@@ -306,7 +330,6 @@
user.apply_effect(150, IRRADIATE)
-
/obj/machinery/power/supermatter_shard/Bumped(atom/AM as mob|obj)
if(istype(AM, /mob/living))
AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... [AM.p_their(TRUE)] body starts to glow and catch flame before flashing into ash.",\
@@ -346,3 +369,44 @@
"The unearthly ringing subsides and you notice you have new radiation burns.", 2)
else
L.show_message("You hear an uneartly ringing and notice your skin is covered in fresh radiation burns.", 2)
+
+#define CRITICAL_TEMPERATURE 10000
+
+/obj/machinery/power/supermatter_shard/proc/get_status()
+ var/turf/T = get_turf(src)
+ if(!T)
+ return SUPERMATTER_ERROR
+ var/datum/gas_mixture/air = T.return_air()
+ if(!air)
+ return SUPERMATTER_ERROR
+
+ if(get_integrity() < SUPERMATTER_DELAM_PERCENT)
+ return SUPERMATTER_DELAMINATING
+
+ if(get_integrity() < SUPERMATTER_EMERGENCY_PERCENT)
+ return SUPERMATTER_EMERGENCY
+
+ if(get_integrity() < SUPERMATTER_DANGER_PERCENT)
+ return SUPERMATTER_DANGER
+
+ if((get_integrity() < SUPERMATTER_WARNING_PERCENT) || (air.temperature > CRITICAL_TEMPERATURE))
+ return SUPERMATTER_WARNING
+
+ if(air.temperature > (CRITICAL_TEMPERATURE * 0.8))
+ return SUPERMATTER_NOTIFY
+
+ if(power > 5)
+ return SUPERMATTER_NORMAL
+ return SUPERMATTER_INACTIVE
+
+/obj/machinery/power/supermatter_shard/proc/alarm()
+ switch(get_status())
+ if(SUPERMATTER_DELAMINATING)
+ playsound(src, 'sound/misc/bloblarm.ogg', 100)
+ if(SUPERMATTER_EMERGENCY)
+ playsound(src, 'sound/machines/engine_alert1.ogg', 100)
+ if(SUPERMATTER_DANGER)
+ playsound(src, 'sound/machines/engine_alert2.ogg', 100)
+ if(SUPERMATTER_WARNING)
+ playsound(src, 'sound/machines/terminal_alert.ogg', 75)
+
diff --git a/icons/obj/modular_console.dmi b/icons/obj/modular_console.dmi
index 85d6026617f..fba8ad59431 100644
Binary files a/icons/obj/modular_console.dmi and b/icons/obj/modular_console.dmi differ
diff --git a/icons/obj/modular_laptop.dmi b/icons/obj/modular_laptop.dmi
index 2daeee0c7a4..d04e68c2041 100644
Binary files a/icons/obj/modular_laptop.dmi and b/icons/obj/modular_laptop.dmi differ
diff --git a/icons/obj/modular_tablet.dmi b/icons/obj/modular_tablet.dmi
index 2438f375f65..d1357a58406 100644
Binary files a/icons/obj/modular_tablet.dmi and b/icons/obj/modular_tablet.dmi differ
diff --git a/icons/program_icons/smmon_0.gif b/icons/program_icons/smmon_0.gif
new file mode 100644
index 00000000000..7b716c4e1c5
Binary files /dev/null and b/icons/program_icons/smmon_0.gif differ
diff --git a/icons/program_icons/smmon_1.gif b/icons/program_icons/smmon_1.gif
new file mode 100644
index 00000000000..bbe319b820f
Binary files /dev/null and b/icons/program_icons/smmon_1.gif differ
diff --git a/icons/program_icons/smmon_2.gif b/icons/program_icons/smmon_2.gif
new file mode 100644
index 00000000000..9c58edd340e
Binary files /dev/null and b/icons/program_icons/smmon_2.gif differ
diff --git a/icons/program_icons/smmon_3.gif b/icons/program_icons/smmon_3.gif
new file mode 100644
index 00000000000..dc7c8734eed
Binary files /dev/null and b/icons/program_icons/smmon_3.gif differ
diff --git a/icons/program_icons/smmon_4.gif b/icons/program_icons/smmon_4.gif
new file mode 100644
index 00000000000..8a75e6e1184
Binary files /dev/null and b/icons/program_icons/smmon_4.gif differ
diff --git a/icons/program_icons/smmon_5.gif b/icons/program_icons/smmon_5.gif
new file mode 100644
index 00000000000..59356beda0a
Binary files /dev/null and b/icons/program_icons/smmon_5.gif differ
diff --git a/icons/program_icons/smmon_6.gif b/icons/program_icons/smmon_6.gif
new file mode 100644
index 00000000000..aea2f87921d
Binary files /dev/null and b/icons/program_icons/smmon_6.gif differ
diff --git a/nano/templates/supermatter_monitor.tmpl b/nano/templates/supermatter_monitor.tmpl
new file mode 100644
index 00000000000..3bc87984d79
--- /dev/null
+++ b/nano/templates/supermatter_monitor.tmpl
@@ -0,0 +1,111 @@
+{{if data.active}}
+ {{:helper.link('Back to Menu', null, {'clear' : 1})}}
+