diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index e5cfa74f2a0..c2a1ea6c21d 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -629,3 +629,17 @@ datum/projectile_data
if (!client_or_usr)
return
winset(client_or_usr, "mainwindow", "flash=5")
+
+// used for the multiz camera console stolen from vorestatiobn
+/proc/get_bbox_of_atoms(list/atoms)
+ var/list/list_x = list()
+ var/list/list_y = list()
+ for(var/_a in atoms)
+ var/atom/a = _a
+ list_x += a.x
+ list_y += a.y
+ return list(
+ min(list_x),
+ min(list_y),
+ max(list_x),
+ max(list_y))
\ No newline at end of file
diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm
index 7060451b275..67fc0086f2d 100644
--- a/code/_onclick/hud/fullscreen.dm
+++ b/code/_onclick/hud/fullscreen.dm
@@ -122,9 +122,5 @@
layer = FULLSCREEN_LAYER
/obj/screen/fullscreen/fishbed
- icon_state = "fishbed"
+ icon_state = "fishbed"
-#undef FULLSCREEN_LAYER
-#undef BLIND_LAYER
-#undef DAMAGE_LAYER
-#undef CRIT_LAYER
\ No newline at end of file
diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm
new file mode 100644
index 00000000000..aae5c808c97
--- /dev/null
+++ b/code/_onclick/hud/map_popups.dm
@@ -0,0 +1,171 @@
+/client
+ /**
+ * Assoc list with all the active maps - when a screen obj is added to
+ * a map, it's put in here as well.
+ *
+ * Format: list( "+e+"AI System Integrity Restorer
"
+ switch(action)
+ if("PRG_beginReconstruction")
+ if(occupier?.health < 100)
+ to_chat(usr, "Reconstruction in progress. This will take several minutes.")
+ playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE)
+ restoring = TRUE
+ var/mob/observer/dead/ghost = occupier.get_ghost()
+ if(ghost)
+ ghost.notify_revive("Your core files are being restored!", source = src)
+ . = TRUE
- if (src.occupant)
- var/laws
- dat += "Stored AI: [src.occupant.name]
System integrity: [src.occupant.hardware_integrity()]%
Backup Capacitor: [src.occupant.backup_capacitor()]%
"
+/obj/machinery/computer/aifixer/proc/Fix()
+ use_power(active_power_usage)
+ occupier.adjustOxyLoss(-5, 0, FALSE)
+ occupier.adjustFireLoss(-5, 0, FALSE)
+ occupier.adjustBruteLoss(-5, 0)
+ if(occupier.health >= 0 && occupier.stat == DEAD)
+ occupier.revive()
- for (var/datum/ai_law/law in occupant.laws.all_laws())
- laws += "[law.get_index()]: [law.law]
"
-
- dat += "Laws:
[laws]
"
-
- if (src.occupant.stat == 2)
- dat += "AI nonfunctional"
- else
- dat += "AI functional"
- if (!src.active)
- dat += {"
Begin Reconstruction"}
- else
- dat += "
Reconstruction in process, please wait.
"
- dat += {" Close"}
-
- user << browse(dat, "window=computer;size=400x500")
- onclose(user, "computer")
- return
+ return occupier.health < 100
/obj/machinery/computer/aifixer/process()
if(..())
- src.updateDialog()
- return
-
-/obj/machinery/computer/aifixer/Topic(href, href_list)
- if(..())
- return 1
- if (href_list["fix"])
- src.active = 1
- src.overlays += image(icon, "ai-fixer-on")
- while (src.occupant.getOxyLoss() > 0 || src.occupant.getFireLoss() > 0 || src.occupant.getToxLoss() > 0 || src.occupant.getBruteLoss() > 0)
- src.occupant.adjustOxyLoss(-1)
- src.occupant.adjustFireLoss(-1)
- src.occupant.adjustToxLoss(-1)
- src.occupant.adjustBruteLoss(-1)
- src.occupant.updatehealth()
- if (src.occupant.health >= 0 && src.occupant.stat == DEAD)
- src.occupant.stat = CONSCIOUS
- src.occupant.lying = 0
- dead_mob_list -= src.occupant
- living_mob_list += src.occupant
- src.overlays -= image(icon, "ai-fixer-404")
- src.overlays += image(icon, "ai-fixer-full")
- src.occupant.add_ai_verbs()
- src.updateUsrDialog()
- sleep(10)
- src.active = 0
- src.overlays -= image(icon, "ai-fixer-on")
-
-
- src.add_fingerprint(usr)
- src.updateUsrDialog()
- return
-
+ if(restoring)
+ var/oldstat = occupier.stat
+ restoring = Fix()
+ if(oldstat != occupier.stat)
+ update_icon()
/obj/machinery/computer/aifixer/update_icon()
- ..()
- if((stat & BROKEN) || (stat & NOPOWER))
+ . = ..()
+ if(stat & (NOPOWER|BROKEN))
return
- if(occupant)
- if(occupant.stat)
- overlays += image(icon, "ai-fixer-404", overlay_layer)
- else
- overlays += image(icon, "ai-fixer-full", overlay_layer)
+ if(restoring)
+ . += "ai-fixer-on"
+ if (occupier)
+ switch (occupier.stat)
+ if (CONSCIOUS)
+ . += "ai-fixer-full"
+ if (UNCONSCIOUS)
+ . += "ai-fixer-404"
else
- overlays += image(icon, "ai-fixer-empty", overlay_layer)
+ . += "ai-fixer-empty"
diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm
index 829a27bf97f..7904a2a228a 100644
--- a/code/game/machinery/computer/camera.dm
+++ b/code/game/machinery/computer/camera.dm
@@ -3,204 +3,46 @@
/obj/machinery/computer/security
name = "security camera monitor"
desc = "Used to access the various cameras on the station."
+
icon_keyboard = "security_key"
icon_screen = "cameras"
light_color = "#a91515"
- var/current_network = null
- var/obj/machinery/camera/current_camera = null
- var/last_pic = 1.0
- var/list/network
- var/mapping = 0//For the overview file, interesting bit of code.
- var/cache_id = 0
circuit = /obj/item/circuitboard/security
-/obj/machinery/computer/security/New()
- if(!network)
+ var/mapping = 0//For the overview file, interesting bit of code.
+ var/list/network = list()
+
+ var/datum/tgui_module/camera/camera
+
+/obj/machinery/computer/security/Initialize()
+ . = ..()
+ if(!LAZYLEN(network))
network = GLOB.using_map.station_networks.Copy()
- ..()
- if(network.len)
- current_network = network[1]
+ camera = new(src, network)
-/obj/machinery/computer/security/attack_ai(var/mob/user as mob)
- return attack_hand(user)
+/obj/machinery/computer/security/Destroy()
+ QDEL_NULL(camera)
+ return ..()
-/obj/machinery/computer/security/check_eye(var/mob/user as mob)
- if (user.stat || ((get_dist(user, src) > 1 || !( user.canmove ) || user.blinded) && !istype(user, /mob/living/silicon))) //user can't see - not sure why canmove is here.
- return -1
- if(!current_camera)
- return 0
- var/viewflag = current_camera.check_eye(user)
- if ( viewflag < 0 ) //camera doesn't work
- reset_current()
- return viewflag
+/obj/machinery/computer/security/ui_interact(mob/user, datum/tgui/ui = null)
+ camera.ui_interact(user, ui)
-/obj/machinery/computer/security/nano_ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
- if(stat & (NOPOWER|BROKEN)) return
- if(user.stat) return
-
- var/data[0]
-
- data["current_camera"] = current_camera ? current_camera.nano_structure() : null
- data["current_network"] = current_network
- data["networks"] = network ? network : list()
- if(current_network)
- data["cameras"] = camera_repository.cameras_in_network(current_network)
- if(current_camera)
- switch_to_camera(user, current_camera)
- data["map_levels"] = GLOB.using_map.get_map_levels(src.z)
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "sec_camera.tmpl", "Camera Console", 900, 800)
-
- // adding a template with the key "mapContent" enables the map ui functionality
- ui.add_template("mapContent", "sec_camera_map_content.tmpl")
- // adding a template with the key "mapHeader" replaces the map header content
- ui.add_template("mapHeader", "sec_camera_map_header.tmpl")
-
- ui.set_initial_data(data)
- ui.open()
-
-/obj/machinery/computer/security/Topic(href, href_list)
- if(..())
- return 1
- if(href_list["switch_camera"])
- if(stat&(NOPOWER|BROKEN)) return //VOREStation Edit - Removed zlevel check
- if(usr.stat || ((get_dist(usr, src) > 1 || !( usr.canmove ) || usr.blinded) && !istype(usr, /mob/living/silicon))) return
- var/obj/machinery/camera/C = locate(href_list["switch_camera"]) in cameranet.cameras
- if(!C)
- return
- if(!(current_network in C.network))
- return
-
- switch_to_camera(usr, C)
- return 1
- else if(href_list["switch_network"])
- if(stat&(NOPOWER|BROKEN)) return //VOREStation Edit - Removed zlevel check
- if(usr.stat || ((get_dist(usr, src) > 1 || !( usr.canmove ) || usr.blinded) && !istype(usr, /mob/living/silicon))) return
- if(href_list["switch_network"] in network)
- current_network = href_list["switch_network"]
- return 1
- else if(href_list["reset"])
- if(stat&(NOPOWER|BROKEN)) return //VOREStation Edit - Removed zlevel check
- if(usr.stat || ((get_dist(usr, src) > 1 || !( usr.canmove ) || usr.blinded) && !istype(usr, /mob/living/silicon))) return
- reset_current()
- usr.reset_view(current_camera)
- return 1
- else
- . = ..()
-
-/obj/machinery/computer/security/attack_hand(var/mob/user as mob)
- if (GLOB.using_map && !(src.z in GLOB.using_map.contact_levels))
- to_chat(user, "Unable to establish a connection: You're too far away from the station!")
+/obj/machinery/computer/security/attack_hand(mob/user)
+ add_fingerprint(user)
+ if(stat & (BROKEN|NOPOWER))
return
- if(stat & (NOPOWER|BROKEN)) return
+ ui_interact(user)
- if(!isAI(user))
- user.set_machine(src)
- nano_ui_interact(user)
+/obj/machinery/computer/security/attack_ai(mob/user)
+ to_chat(user, "You realise its kind of stupid to access a camera console when you have the entire camera network at your metaphorical fingertips")
+ return
-/obj/machinery/computer/security/proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C)
- //don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras.
- if(isAI(user))
- var/mob/living/silicon/ai/A = user
- // Only allow non-carded AIs to view because the interaction with the eye gets all wonky otherwise.
- if(!A.is_in_chassis())
- return 0
+/obj/machinery/computer/security/proc/set_network(list/new_network)
+ network = new_network
+ camera.network = network
+ camera.access_based = FALSE
- A.eyeobj.setLoc(get_turf(C))
- A.client.eye = A.eyeobj
- return 1
-
- if (!C.can_use() || user.stat || (get_dist(user, src) > 1 || user.machine != src || user.blinded || !( user.canmove ) && !istype(user, /mob/living/silicon)))
- return 0
- set_current(C)
- user.reset_view(current_camera)
- check_eye(user)
- return 1
-
-//Camera control: moving.
-/obj/machinery/computer/security/proc/jump_on_click(var/mob/user,var/A)
- if(user.machine != src)
- return
- var/obj/machinery/camera/jump_to
- if(istype(A,/obj/machinery/camera))
- jump_to = A
- else if(ismob(A))
- if(ishuman(A))
- jump_to = locate() in A:head
- else if(isrobot(A))
- jump_to = A:camera
- else if(isobj(A))
- jump_to = locate() in A
- else if(isturf(A))
- var/best_dist = INFINITY
- for(var/obj/machinery/camera/camera in get_area(A))
- if(!camera.can_use())
- continue
- if(!can_access_camera(camera))
- continue
- var/dist = get_dist(camera,A)
- if(dist < best_dist)
- best_dist = dist
- jump_to = camera
- if(isnull(jump_to))
- return
- if(can_access_camera(jump_to))
- switch_to_camera(user,jump_to)
-
-/obj/machinery/computer/security/process()
- if(cache_id != camera_repository.camera_cache_id)
- cache_id = camera_repository.camera_cache_id
- SSnanoui.update_uis(src)
-
-/obj/machinery/computer/security/proc/can_access_camera(var/obj/machinery/camera/C)
- var/list/shared_networks = src.network & C.network
- if(shared_networks.len)
- return 1
- return 0
-
-/obj/machinery/computer/security/proc/set_current(var/obj/machinery/camera/C)
- if(current_camera == C)
- return
-
- if(current_camera)
- reset_current()
-
- src.current_camera = C
- if(current_camera)
- current_camera.camera_computers_using_this.Add(src)
- update_use_power(USE_POWER_ACTIVE)
- var/mob/living/L = current_camera.loc
- if(istype(L))
- L.tracking_initiated()
-
-/obj/machinery/computer/security/proc/reset_current()
- if(current_camera)
- current_camera.camera_computers_using_this.Remove(src)
- var/mob/living/L = current_camera.loc
- if(istype(L))
- L.tracking_cancelled()
- current_camera = null
- use_power = USE_POWER_IDLE
-
-//Camera control: mouse.
-/atom/DblClick()
- ..()
- if(istype(usr.machine,/obj/machinery/computer/security))
- var/obj/machinery/computer/security/console = usr.machine
- console.jump_on_click(usr,src)
//Camera control: arrow keys.
-/mob/Move(n,direct)
- if(istype(machine,/obj/machinery/computer/security))
- var/obj/machinery/computer/security/console = machine
- var/turf/T = get_turf(console.current_camera)
- for(var/i;i<10;i++)
- T = get_step(T,direct)
- console.jump_on_click(src,T)
- return
- return ..(n,direct)
-
/obj/machinery/computer/security/telescreen
name = "Telescreen"
desc = "Used for watching an empty arena."
@@ -244,7 +86,7 @@
/obj/machinery/computer/security/wooden_tv
name = "security camera monitor"
- desc = "An old TV hooked into the stations camera network."
+ desc = "An old TV hooked into the station's camera network."
icon_state = "television"
icon_keyboard = null
icon_screen = "detective_tv"
@@ -252,20 +94,9 @@
light_color = "#3848B3"
light_power_on = 0.5
-/obj/machinery/computer/security/wooden_tv/service
- name = "security camera monitor"
- desc = "An old TV hooked into the stations entertainment network."
- icon_state = "television"
- icon_keyboard = null
- icon_screen = "detective_tv"
- network = list(NETWORK_THUNDER)
- circuit = /obj/item/circuitboard/security/telescreen/entertainment
- light_color = "#3848B3"
- light_power_on = 0.9
-
/obj/machinery/computer/security/mining
name = "outpost camera monitor"
- desc = "Used to access the various cameras on the outpost."
+ desc = "Used to watch over mining operations."
icon_keyboard = "mining_key"
icon_screen = "mining"
network = list("Mining Outpost")
diff --git a/code/game/machinery/computer/camera_circuit.dm b/code/game/machinery/computer/camera_circuit.dm
deleted file mode 100644
index c27aa77a6d3..00000000000
--- a/code/game/machinery/computer/camera_circuit.dm
+++ /dev/null
@@ -1,116 +0,0 @@
-
-//the researchable camera circuit that can connect to any camera network
-
-/obj/item/circuitboard/camera
- //name = "Circuit board (Camera)"
- var/secured = 1
- var/authorised = 0
- var/possibleNets[0]
- var/network = ""
- build_path = null
-
-//when adding a new camera network, you should only need to update these two procs
- New()
- possibleNets["Engineering"] = access_ce
- possibleNets["SS13"] = access_hos
- possibleNets["Mining"] = access_mining
- possibleNets["Cargo"] = access_qm
- possibleNets["Research"] = access_rd
- possibleNets["Medbay"] = access_cmo
- ..()
-
- proc/updateBuildPath()
- build_path = null
- if(authorised && secured)
- switch(network)
- if("SS13")
- build_path = /obj/machinery/computer/security
- if("Engineering")
- build_path = /obj/machinery/computer/security/engineering
- if("Mining")
- build_path = /obj/machinery/computer/security/mining
- if("Research")
- build_path = /obj/machinery/computer/security/research
- if("Medbay")
- build_path = /obj/machinery/computer/security/medbay
- if("Cargo")
- build_path = /obj/machinery/computer/security/cargo
-
- attackby(var/obj/item/I, var/mob/user)//if(health > 50)
- ..()
- else if(I.is_screwdriver())
- secured = !secured
- user.visible_message("The [src] can [secured ? "no longer" : "now"] be modified.")
- playsound(src, I.usesound, 50, 1)
- updateBuildPath()
- return
-
- attack_self(var/mob/user)
- if(!secured && ishuman(user))
- user.machine = src
- interact(user, 0)
-
- proc/interact(var/mob/user, var/ai=0)
- if(secured)
- return
- if (!ishuman(user))
- return ..(user)
- var/t = "Circuitboard Console - Camera Monitoring Computer
"
- t += "Close
"
- t += "
Please select a camera network:
"
-
- for(var/curNet in possibleNets)
- if(network == curNet)
- t += "- [curNet]
"
- else
- t += "- [curNet]
"
- t += "
"
- if(network)
- if(authorised)
- t += "Authenticated (Clear Auth)
"
- else
- t += "*Authenticate* (Requires an appropriate access ID)
"
- else
- t += "*Authenticate* (Requires an appropriate access ID)
"
- t += "Close
"
- user << browse(t, "window=camcircuit;size=500x400")
- onclose(user, "camcircuit")
-
- Topic(href, href_list)
- ..()
- if( href_list["close"] )
- usr << browse(null, "window=camcircuit")
- usr.machine = null
- return
- else if(href_list["net"])
- network = href_list["net"]
- authorised = 0
- else if( href_list["auth"] )
- var/mob/M = usr
- var/obj/item/card/id/I = M.equipped()
- if (istype(I, /obj/item/pda))
- var/obj/item/pda/pda = I
- I = pda.id
- if (I && istype(I))
- if(access_captain in I.access)
- authorised = 1
- else if (possibleNets[network] in I.access)
- authorised = 1
- if(istype(I,/obj/item/card/emag))
- I.resolve_attackby(src, usr)
- else if( href_list["removeauth"] )
- authorised = 0
- updateDialog()
-
- updateDialog()
- if(istype(src.loc,/mob))
- attack_self(src.loc)
-
-/obj/item/circuitboard/camera/emag_act(var/remaining_charges, var/mob/user)
- if(network)
- authorised = 1
- to_chat(user, "You authorised the circuit network!")
- updateDialog()
- return 1
- else
- to_chat(user, "You must select a camera network circuit!")
diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm
index aac32a03a81..54241800ee9 100644
--- a/code/game/machinery/computer/crew.dm
+++ b/code/game/machinery/computer/crew.dm
@@ -8,7 +8,7 @@
idle_power_usage = 250
active_power_usage = 500
circuit = /obj/item/circuitboard/crew
- var/datum/nano_module/crew_monitor/crew_monitor
+ var/datum/tgui_module/crew_monitor/crew_monitor
/obj/machinery/computer/crew/New()
crew_monitor = new(src)
@@ -20,16 +20,16 @@
..()
/obj/machinery/computer/crew/attack_ai(mob/user)
- nano_ui_interact(user)
+ attack_hand(user)
/obj/machinery/computer/crew/attack_hand(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
- nano_ui_interact(user)
+ ui_interact(user)
-/obj/machinery/computer/crew/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- crew_monitor.nano_ui_interact(user, ui_key, ui, force_open)
+/obj/machinery/computer/crew/ui_interact(mob/user, datum/tgui/ui = null)
+ crew_monitor.ui_interact(user, ui)
/obj/machinery/computer/crew/interact(mob/user)
- crew_monitor.nano_ui_interact(user)
+ crew_monitor.ui_interact(user)
diff --git a/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm b/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm
index b715d7ef070..498a5a978ab 100644
--- a/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm
+++ b/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm
@@ -45,7 +45,7 @@
/obj/item/circuitboard/security/construct(var/obj/machinery/computer/security/C)
if (..(C))
- C.network = network.Copy()
+ C.set_network(network.Copy())
/obj/item/circuitboard/security/deconstruct(var/obj/machinery/computer/security/C)
if (..(C))
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index 433a1781fcb..91b407efcf2 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -28,7 +28,7 @@
AC = new(src, user)
AC.name = "SalonPro Nano-Mirror™"
ui_users[user] = AC
- AC.ui_interact(user)
+ AC.nano_ui_interact(user)
/obj/structure/mirror/proc/shatter()
if(!glass) return
@@ -142,6 +142,7 @@
qdel(user)
..()
+
//Long mirrors.
/obj/structure/mirror/long
name = "mirror"
@@ -193,4 +194,3 @@
icon_state = "long_mir_r_broke"
density = 0
anchored = 1
- shattered = 1
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 03153dacd26..298f2a8f1bb 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -259,6 +259,11 @@ GLOBAL_VAR_INIT(sound_distance_offscreen, 7)
if("smdelam")
soundin = pick('sound/machines/sm/accent/delam/1.ogg', 'sound/machines/sm/accent/normal/2.ogg', 'sound/machines/sm/accent/normal/3.ogg', 'sound/machines/sm/accent/normal/4.ogg', 'sound/machines/sm/accent/normal/5.ogg', 'sound/machines/sm/accent/normal/6.ogg', 'sound/machines/sm/accent/normal/7.ogg', 'sound/machines/sm/accent/normal/8.ogg', 'sound/machines/sm/accent/normal/9.ogg', 'sound/machines/sm/accent/normal/10.ogg', 'sound/machines/sm/accent/normal/11.ogg', 'sound/machines/sm/accent/normal/12.ogg', 'sound/machines/sm/accent/normal/13.ogg', 'sound/machines/sm/accent/normal/14.ogg', 'sound/machines/sm/accent/normal/15.ogg', 'sound/machines/sm/accent/normal/16.ogg', 'sound/machines/sm/accent/normal/17.ogg', 'sound/machines/sm/accent/normal/18.ogg', 'sound/machines/sm/accent/normal/19.ogg', 'sound/machines/sm/accent/normal/20.ogg', 'sound/machines/sm/accent/normal/21.ogg', 'sound/machines/sm/accent/normal/22.ogg', 'sound/machines/sm/accent/normal/23.ogg', 'sound/machines/sm/accent/normal/24.ogg', 'sound/machines/sm/accent/normal/25.ogg', 'sound/machines/sm/accent/normal/26.ogg', 'sound/machines/sm/accent/normal/27.ogg', 'sound/machines/sm/accent/normal/28.ogg', 'sound/machines/sm/accent/normal/29.ogg', 'sound/machines/sm/accent/normal/30.ogg', 'sound/machines/sm/accent/normal/31.ogg', 'sound/machines/sm/accent/normal/32.ogg', 'sound/machines/sm/accent/normal/33.ogg', 'sound/machines/sm/supermatter1.ogg', 'sound/machines/sm/supermatter2.ogg', 'sound/machines/sm/supermatter3.ogg')
+ if ("terminal_type")
+ soundin = pick('sound/machines/terminal_button01.ogg', 'sound/machines/terminal_button02.ogg', 'sound/machines/terminal_button03.ogg', \
+ 'sound/machines/terminal_button04.ogg', 'sound/machines/terminal_button05.ogg', 'sound/machines/terminal_button06.ogg', \
+ 'sound/machines/terminal_button07.ogg', 'sound/machines/terminal_button08.ogg')
+
//END VORESTATION EDIT
return soundin
diff --git a/code/modules/alarm/alarm.dm b/code/modules/alarm/alarm.dm
index ac9b103b560..3ad1df433f9 100644
--- a/code/modules/alarm/alarm.dm
+++ b/code/modules/alarm/alarm.dm
@@ -18,7 +18,6 @@
var/list/sources = new() //List of sources triggering the alarm. Used to determine when the alarm should be cleared.
var/list/sources_assoc = new() //Associative list of source triggers. Used to efficiently acquire the alarm source.
var/list/cameras //List of cameras that can be switched to, if the player has that capability.
- var/cache_id //ID for camera cache, changed by invalidateCameraCache().
var/area/last_area //The last acquired area, used should origin be lost (for example a destroyed borg containing an alarming camera).
var/area/last_name //The last acquired name, used should origin be lost
var/area/last_camera_area //The last area in which cameras where fetched, used to see if the camera list should be updated.
@@ -78,15 +77,10 @@
return last_name
/datum/alarm/proc/cameras()
- // reset camera cache
- if(camera_repository.camera_cache_id != cache_id)
- cameras = null
- cache_id = camera_repository.camera_cache_id
// If the alarm origin has changed area, for example a borg containing an alarming camera, reset the list of cameras
- else if(cameras && (last_camera_area != alarm_area()))
+ if(cameras && (last_camera_area != alarm_area()))
cameras = null
- // The list of cameras is also reset by /proc/invalidateCameraCache()
if(!cameras)
cameras = origin ? origin.get_alarm_cameras() : last_area.get_alarm_cameras()
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index 782a76a6d5f..7fad7dd8697 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -53,6 +53,8 @@
icon_state = "glasses"
var/datum/nano_module/arscreen
var/arscreen_path
+ var/datum/tgui_module/tgarscreen
+ var/tgarscreen_path
var/flash_prot = 0 //0 for none, 1 for flash weapon protection, 2 for welder protection
enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_AUGMENTED,VIS_CH_BACKUP)
plane_slots = list(slot_glasses)
@@ -61,21 +63,29 @@
..()
if(arscreen_path)
arscreen = new arscreen_path(src)
+ if(tgarscreen_path)
+ tgarscreen = new tgarscreen_path(src)
/obj/item/clothing/glasses/omnihud/Destroy()
QDEL_NULL(arscreen)
+ QDEL_NULL(tgarscreen)
. = ..()
/obj/item/clothing/glasses/omnihud/dropped()
if(arscreen)
SSnanoui.close_uis(src)
+ if(tgarscreen)
+ SStgui.close_uis(src)
..()
/obj/item/clothing/glasses/omnihud/emp_act(var/severity)
var/disconnect_ar = arscreen
arscreen = null
+ var/disconnect_tgar = tgarscreen
+ tgarscreen = null
spawn(20 SECONDS)
arscreen = disconnect_ar
+ tgarscreen = disconnect_tgar
..()
/obj/item/clothing/glasses/omnihud/proc/flashed()
@@ -116,13 +126,13 @@
These have been upgraded with medical records access and virus database integration."
mode = "med"
action_button_name = "AR Console (Crew Monitor)"
- arscreen_path = /datum/nano_module/crew_monitor
+ tgarscreen_path = /datum/tgui_module/crew_monitor/glasses
enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_STATUS_R,VIS_CH_BACKUP,VIS_AUGMENTED)
- ar_interact(var/mob/living/carbon/human/user)
- if(arscreen)
- arscreen.nano_ui_interact(user,"main",null,1,glasses_state)
- return 1
+/obj/item/clothing/glasses/omnihud/med/ar_interact(var/mob/living/carbon/human/user)
+ if(tgarscreen)
+ tgarscreen.ui_interact(user)
+ return 1
/obj/item/clothing/glasses/omnihud/sec
name = "\improper AR-S glasses"
@@ -134,10 +144,10 @@
arscreen_path = /datum/nano_module/alarm_monitor/security
enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_WANTED,VIS_AUGMENTED)
- ar_interact(var/mob/living/carbon/human/user)
- if(arscreen)
- arscreen.nano_ui_interact(user,"main",null,1,glasses_state)
- return 1
+/obj/item/clothing/glasses/omnihud/sec/ar_interact(var/mob/living/carbon/human/user)
+ if(arscreen)
+ arscreen.nano_ui_interact(user,"main",null,1,glasses_state)
+ return 1
/obj/item/clothing/glasses/omnihud/eng
name = "\improper AR-E glasses"
@@ -148,10 +158,10 @@
action_button_name = "AR Console (Station Alerts)"
arscreen_path = /datum/nano_module/alarm_monitor/engineering
- ar_interact(var/mob/living/carbon/human/user)
- if(arscreen)
- arscreen.nano_ui_interact(user,"main",null,1,glasses_state)
- return 1
+/obj/item/clothing/glasses/omnihud/eng/ar_interact(var/mob/living/carbon/human/user)
+ if(arscreen)
+ arscreen.nano_ui_interact(user,"main",null,1,glasses_state)
+ return 1
/obj/item/clothing/glasses/omnihud/rnd
name = "\improper AR-R glasses"
diff --git a/code/modules/mob/freelook/ai/update_triggers.dm b/code/modules/mob/freelook/ai/update_triggers.dm
index 045d0522efe..797e5cc23b5 100644
--- a/code/modules/mob/freelook/ai/update_triggers.dm
+++ b/code/modules/mob/freelook/ai/update_triggers.dm
@@ -39,7 +39,6 @@
/obj/machinery/camera/deactivate(user as mob, var/choice = 1)
..(user, choice)
- invalidateCameraCache()
if(src.can_use())
cameranet.addCamera(src)
else
diff --git a/code/modules/mob/living/silicon/subystems.dm b/code/modules/mob/living/silicon/subystems.dm
index a143dacb6fc..bdbd90a1f89 100644
--- a/code/modules/mob/living/silicon/subystems.dm
+++ b/code/modules/mob/living/silicon/subystems.dm
@@ -2,7 +2,7 @@
var/register_alarms = 1
var/datum/nano_module/alarm_monitor/all/alarm_monitor
var/datum/nano_module/atmos_control/atmos_control
- var/datum/nano_module/crew_monitor/crew_monitor
+ var/datum/tgui_module/crew_monitor/robot/crew_monitor
var/datum/nano_module/law_manager/law_manager
var/datum/nano_module/power_monitor/power_monitor
var/datum/nano_module/rcon/rcon
@@ -67,7 +67,7 @@
set category = "Subystems"
set name = "Crew Monitor"
- crew_monitor.nano_ui_interact(usr, state = self_state)
+ crew_monitor.ui_interact(usr, state = self_state)
/****************
* Law Manager *
diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm
index 573c55f1740..ec5f059d311 100644
--- a/code/modules/mob/logout.dm
+++ b/code/modules/mob/logout.dm
@@ -1,6 +1,7 @@
/mob/Logout()
SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGOUT, client)
SSnanoui.user_logout(src) // this is used to clean up (remove) this user's Nano UIs
+ SStgui.on_logout(src) // Cleanup any TGUIs the user has open
player_list -= src
disconnect_time = world.realtime //VOREStation Addition: logging when we disappear.
update_client_z(null)
@@ -14,4 +15,4 @@
send2irc("LOGOUT", "[key_name(src)] logged out - no more admins online.")
..()
- return 1
\ No newline at end of file
+ return 1
diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm
index e2660d3a777..7ceb2c59481 100644
--- a/code/modules/modular_computers/computers/modular_computer/core.dm
+++ b/code/modules/modular_computers/computers/modular_computer/core.dm
@@ -163,6 +163,7 @@
idle_threads.Add(active_program)
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
SSnanoui.close_uis(active_program.NM ? active_program.NM : active_program)
+ SStgui.close_uis(active_program.TM ? active_program.TM : active_program)
active_program = null
update_icon()
if(istype(user))
@@ -202,7 +203,6 @@
minimize_program(user)
if(P.run_program(user))
- active_program = P
update_icon()
return 1
diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm
index 8d1419537cc..d9e3e3d78b6 100644
--- a/code/modules/modular_computers/file_system/program.dm
+++ b/code/modules/modular_computers/file_system/program.dm
@@ -5,8 +5,13 @@
var/required_access = null // List of required accesses to run/download the program.
var/requires_access_to_run = 1 // Whether the program checks for required_access when run.
var/requires_access_to_download = 1 // Whether the program checks for required_access when downloading.
+ //nanoui
var/datum/nano_module/NM = null // If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement nano_ui_interact.
var/nanomodule_path = null // Path to nanomodule, make sure to set this if implementing new program.
+ // t gui
+ var/datum/tgui_module/TM = null // If the program uses TGUIModule, put it here and it will be automagically opened. Otherwise implement ui_interact.
+ var/tguimodule_path = null // Path to tguimodule, make sure to set this if implementing new program.
+ // misc program stuff
var/program_state = PROGRAM_STATE_KILLED// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running.
var/obj/item/modular_computer/computer // Device that runs this program.
var/filedesc = "Unknown Program" // User-friendly name of this program.
@@ -125,9 +130,14 @@
// When implementing new program based device, use this to run the program.
/datum/computer_file/program/proc/run_program(var/mob/living/user)
if(can_run(user, 1) || !requires_access_to_run)
+ computer.active_program = src
if(nanomodule_path)
NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src)
NM.using_access = user.GetAccess()
+ if(tguimodule_path)
+ TM = new tguimodule_path(src)
+ TM.using_access = user.GetAccess()
+ TM.ui_interact(user)
if(requires_ntnet && network_destination)
generate_network_log("Connection opened to [network_destination].")
program_state = PROGRAM_STATE_ACTIVE
@@ -139,9 +149,11 @@
program_state = PROGRAM_STATE_KILLED
if(network_destination)
generate_network_log("Connection to [network_destination] closed.")
- if(NM)
- qdel(NM)
- NM = null
+ QDEL_NULL(NM)
+ if(TM)
+ SStgui.close_uis(TM)
+ qdel(TM)
+ TM = null
return 1
// This is called every tick when the program is enabled. Ensure you do parent call if you override it. If parent returns 1 continue with UI initialisation.
@@ -154,6 +166,9 @@
if(istype(NM))
NM.nano_ui_interact(user, ui_key, null, force_open)
return 0
+ if(istype(TM))
+ TM.ui_interact(user)
+ return 0
return 1
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm b/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm
index 4a5d158d90e..ba38e00ef25 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm
@@ -1,7 +1,7 @@
/datum/computer_file/program/camera_monitor/hacked
filename = "camcrypt"
filedesc = "Camera Decryption Tool"
- nanomodule_path = /datum/nano_module/camera_monitor/hacked
+ tguimodule_path = /datum/tgui_module/camera/ntos/hacked
program_icon_state = "hostile"
program_key_state = "security_key"
program_menu_icon = "zoomin"
@@ -15,25 +15,9 @@
if(program_state != PROGRAM_STATE_ACTIVE) // Background programs won't trigger alarms.
return
- var/datum/nano_module/camera_monitor/hacked/HNM = NM
// The program is active and connected to one of the station's networks. Has a very small chance to trigger IDS alarm every tick.
- if(HNM && HNM.current_network && (HNM.current_network in GLOB.using_map.station_networks) && prob(0.1))
+ if(prob(0.1))
if(ntnet_global.intrusion_detection_enabled)
- ntnet_global.add_log("IDS WARNING - Unauthorised access detected to camera network [HNM.current_network] by device with NID [computer.network_card.get_network_tag()]")
+ ntnet_global.add_log("IDS WARNING - Unauthorised access detected to camera network by device with NID [computer.network_card.get_network_tag()]")
ntnet_global.intrusion_detection_alarm = 1
-
-
-/datum/nano_module/camera_monitor/hacked
- name = "Hacked Camera Monitoring Program"
- //available_to_ai = FALSE
-
-/datum/nano_module/camera_monitor/hacked/can_access_network(var/mob/user, var/network_access)
- return 1
-
-// The hacked variant has access to all commonly used networks.
-/datum/nano_module/camera_monitor/hacked/modify_networks_list(var/list/networks)
- networks.Add(list(list("tag" = NETWORK_MERCENARY, "has_access" = 1)))
- networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1)))
- networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1)))
- return networks
\ No newline at end of file
diff --git a/code/modules/modular_computers/file_system/programs/generic/camera.dm b/code/modules/modular_computers/file_system/programs/generic/camera.dm
index f589301da3a..4ec7667d80e 100644
--- a/code/modules/modular_computers/file_system/programs/generic/camera.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/camera.dm
@@ -24,7 +24,7 @@
/datum/computer_file/program/camera_monitor
filename = "cammon"
filedesc = "Camera Monitoring"
- nanomodule_path = /datum/nano_module/camera_monitor
+ tguimodule_path = /datum/tgui_module/camera/ntos
program_icon_state = "cameras"
program_key_state = "generic_key"
program_menu_icon = "search"
@@ -33,161 +33,11 @@
available_on_ntnet = 1
requires_ntnet = 1
-/datum/nano_module/camera_monitor
- name = "Camera Monitoring program"
- var/obj/machinery/camera/current_camera = null
- var/current_network = null
-
-/datum/nano_module/camera_monitor/nano_ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = default_state)
- var/list/data = host.initial_data()
-
- data["current_camera"] = current_camera ? current_camera.nano_structure() : null
- data["current_network"] = current_network
-
- var/list/all_networks[0]
- for(var/network in GLOB.using_map.station_networks)
- if(can_access_network(user, get_camera_access(network), 1))
- all_networks.Add(list(list(
- "tag" = network,
- "has_access" = 1
- )))
- for(var/network in GLOB.using_map.secondary_networks)
- if(can_access_network(user, get_camera_access(network), 0))
- all_networks.Add(list(list(
- "tag" = network,
- "has_access" = 1
- )))
-
- all_networks = modify_networks_list(all_networks)
-
- data["networks"] = all_networks
-
- if(current_network)
- data["cameras"] = camera_repository.cameras_in_network(current_network)
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "mod_sec_camera.tmpl", "Camera Monitoring", 900, 800)
- // ui.auto_update_layout = 1 // Disabled as with suit sensors monitor - breaks the UI map. Re-enable once it's fixed somehow.
-
- ui.add_template("mapContent", "sec_camera_map_content.tmpl")
- ui.add_template("mapHeader", "mod_sec_camera_map_header.tmpl")
- ui.set_initial_data(data)
- ui.open()
-
-// Intended to be overriden by subtypes to manually add non-station networks to the list.
-/datum/nano_module/camera_monitor/proc/modify_networks_list(var/list/networks)
- return networks
-
-/datum/nano_module/camera_monitor/proc/can_access_network(var/mob/user, var/network_access, var/station_network = 0)
- // No access passed, or 0 which is considered no access requirement. Allow it.
- if(!network_access)
- return 1
-
- if(station_network)
- return check_access(user, network_access) || check_access(user, access_security) || check_access(user, access_heads)
- else
- return check_access(user, network_access)
-
-/datum/nano_module/camera_monitor/Topic(href, href_list)
- if(..())
- return 1
-
- if(href_list["switch_camera"])
- var/obj/machinery/camera/C = locate(href_list["switch_camera"]) in cameranet.cameras
- if(!C)
- return
- if(!(current_network in C.network))
- return
-
- switch_to_camera(usr, C)
- return 1
-
- else if(href_list["switch_network"])
- // Either security access, or access to the specific camera network's department is required in order to access the network.
- if(can_access_network(usr, get_camera_access(href_list["switch_network"]), (href_list["switch_network"] in GLOB.using_map.station_networks)))
- current_network = href_list["switch_network"]
- else
- to_chat(usr, "\The [nano_host()] shows an \"Network Access Denied\" error message.")
- return 1
-
- else if(href_list["reset"])
- reset_current()
- usr.reset_view(current_camera)
- return 1
-
-/datum/nano_module/camera_monitor/proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C)
- //don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras.
- if(isAI(user))
- var/mob/living/silicon/ai/A = user
- // Only allow non-carded AIs to view because the interaction with the eye gets all wonky otherwise.
- if(!A.is_in_chassis())
- return 0
-
- A.eyeobj.setLoc(get_turf(C))
- A.client.eye = A.eyeobj
- return 1
-
- set_current(C)
- user.machine = nano_host()
- user.reset_view(C)
- return 1
-
-/datum/nano_module/camera_monitor/proc/set_current(var/obj/machinery/camera/C)
- if(current_camera == C)
- return
-
- if(current_camera)
- reset_current()
-
- current_camera = C
- if(current_camera)
- var/mob/living/L = current_camera.loc
- if(istype(L))
- L.tracking_initiated()
-
-/datum/nano_module/camera_monitor/proc/reset_current()
- if(current_camera)
- var/mob/living/L = current_camera.loc
- if(istype(L))
- L.tracking_cancelled()
- current_camera = null
-
-/datum/nano_module/camera_monitor/check_eye(var/mob/user as mob)
- if(!current_camera)
- return 0
- var/viewflag = current_camera.check_eye(user)
- if ( viewflag < 0 ) //camera doesn't work
- reset_current()
- return viewflag
-
-
// ERT Variant of the program
/datum/computer_file/program/camera_monitor/ert
filename = "ntcammon"
filedesc = "Advanced Camera Monitoring"
extended_desc = "This program allows remote access to the camera system. Some camera networks may have additional access requirements. This version has an integrated database with additional encrypted keys."
size = 14
- nanomodule_path = /datum/nano_module/camera_monitor/ert
+ tguimodule_path = /datum/tgui_module/camera/ntos/ert
available_on_ntnet = 0
-
-/datum/nano_module/camera_monitor/ert
- name = "Advanced Camera Monitoring Program"
- //available_to_ai = FALSE
-
-// The ERT variant has access to ERT and crescent cams, but still checks for accesses. ERT members should be able to use it.
-/datum/nano_module/camera_monitor/ert/modify_networks_list(var/list/networks)
- ..()
- networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1)))
- networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1)))
- return networks
-
-/datum/nano_module/camera_monitor/apply_visual(mob/M)
- if(current_camera)
- current_camera.apply_visual(M)
- else
- remove_visual(M)
-
-/datum/nano_module/camera_monitor/remove_visual(mob/M)
- if(current_camera)
- current_camera.remove_visual(M)
diff --git a/code/modules/modular_computers/file_system/programs/medical/suit_sensors.dm b/code/modules/modular_computers/file_system/programs/medical/suit_sensors.dm
index b96cba454ae..9b94707eb22 100644
--- a/code/modules/modular_computers/file_system/programs/medical/suit_sensors.dm
+++ b/code/modules/modular_computers/file_system/programs/medical/suit_sensors.dm
@@ -1,7 +1,7 @@
/datum/computer_file/program/suit_sensors
filename = "sensormonitor"
filedesc = "Suit Sensors Monitoring"
- nanomodule_path = /datum/nano_module/crew_monitor
+ tguimodule_path = /datum/tgui_module/crew_monitor/ntos
program_icon_state = "crew"
program_key_state = "med_key"
program_menu_icon = "heart"
@@ -10,66 +10,3 @@
requires_ntnet = 1
network_destination = "crew lifesigns monitoring system"
size = 11
-
-
-
-
-
-/datum/nano_module/crew_monitor
- name = "Crew monitor"
-
-/datum/nano_module/crew_monitor/Topic(href, href_list)
- if(..()) return 1
- var/turf/T = get_turf(nano_host()) // TODO: Allow setting any GLOB.using_map.contact_levels from the interface.
- if (!T || !(T.z in GLOB.using_map.player_levels))
- to_chat(usr, "Unable to establish a connection: You're too far away from the station!")
- return 0
- if(href_list["track"])
- if(isAI(usr))
- var/mob/living/silicon/ai/AI = usr
- var/mob/living/carbon/human/H = locate(href_list["track"]) in mob_list
- if(hassensorlevel(H, SUIT_SENSOR_TRACKING))
- AI.ai_actual_track(H)
- return 1
-
-/datum/nano_module/crew_monitor/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- var/list/data = host.initial_data()
- var/turf/T = get_turf(nano_host())
-
- data["isAI"] = isAI(user)
- data["map_levels"] = GLOB.using_map.get_map_levels(T.z, FALSE)
- data["crewmembers"] = list()
- for(var/z in data["map_levels"]) // VOREStation Edit
- data["crewmembers"] += crew_repository.health_data(z)
-
- if(!data["map_levels"].len)
- to_chat(user, "The crew monitor doesn't seem like it'll work here.")
- if(ui) // VOREStation Addition
- ui.close() // VOREStation Addition
- return
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800, state = state)
-
- // adding a template with the key "mapContent" enables the map ui functionality
- ui.add_template("mapContent", "crew_monitor_map_content.tmpl")
- // adding a template with the key "mapHeader" replaces the map header content
- ui.add_template("mapHeader", "crew_monitor_map_header.tmpl")
- if(!(ui.map_z_level in data["map_levels"]))
- ui.set_map_z_level(data["map_levels"][1])
-
- ui.set_initial_data(data)
- ui.open()
-
- // should make the UI auto-update; doesn't seem to?
- ui.set_auto_update(1)
-
-/*/datum/nano_module/crew_monitor/proc/scan()
- for(var/mob/living/carbon/human/H in mob_list)
- if(istype(H.w_uniform, /obj/item/clothing/under))
- var/obj/item/clothing/under/C = H.w_uniform
- if (C.has_sensor)
- tracked |= C
- return 1
-*/
diff --git a/code/modules/nifsoft/software/06_screens.dm b/code/modules/nifsoft/software/06_screens.dm
index 787430008f1..487745f9efd 100644
--- a/code/modules/nifsoft/software/06_screens.dm
+++ b/code/modules/nifsoft/software/06_screens.dm
@@ -5,23 +5,23 @@
access = access_medical
cost = 625
p_drain = 0.025
- var/datum/nano_module/crew_monitor/arscreen
+ var/datum/tgui_module/crew_monitor/nif/arscreen
- New()
- ..()
- arscreen = new(nif)
+/datum/nifsoft/crewmonitor/New()
+ ..()
+ arscreen = new(nif)
- Destroy()
+/datum/nifsoft/crewmonitor/Destroy()
QDEL_NULL(arscreen)
return ..()
- activate()
- if((. = ..()))
- arscreen.nano_ui_interact(nif.human,"main",null,1,nif_state)
- return TRUE
+/datum/nifsoft/crewmonitor/activate()
+ if((. = ..()))
+ arscreen.ui_interact(nif.human)
+ return TRUE
- stat_text()
- return "Show Monitor"
+/datum/nifsoft/crewmonitor/stat_text()
+ return "Show Monitor"
/datum/nifsoft/alarmmonitor
name = "Alarm Monitor"
@@ -32,18 +32,18 @@
p_drain = 0.025
var/datum/nano_module/alarm_monitor/engineering/arscreen
- New()
- ..()
- arscreen = new(nif)
+/datum/nifsoft/alarmmonitor/New()
+ ..()
+ arscreen = new(nif)
- Destroy()
+/datum/nifsoft/alarmmonitor/Destroy()
QDEL_NULL(arscreen)
return ..()
- activate()
- if((. = ..()))
- arscreen.nano_ui_interact(nif.human,"main",null,1,nif_state)
- return TRUE
+/datum/nifsoft/alarmmonitor/activate()
+ if((. = ..()))
+ arscreen.nano_ui_interact(nif.human,"main",null,1,nif_state)
+ return TRUE
- stat_text()
- return "Show Monitor"
+/datum/nifsoft/alarmmonitor/stat_text()
+ return "Show Monitor"
diff --git a/code/modules/tgui/modules/_base.dm b/code/modules/tgui/modules/_base.dm
new file mode 100644
index 00000000000..c85ba2751ef
--- /dev/null
+++ b/code/modules/tgui/modules/_base.dm
@@ -0,0 +1,46 @@
+/*
+TGUI MODULES
+
+This allows for datum-based TGUIs that can be hooked into objects.
+This is useful for things such as the power monitor, which needs to exist on a physical console in the world, but also as a virtual device the AI can use
+
+Code is pretty much ripped verbatim from nano modules, but with un-needed stuff removed
+*/
+/datum/tgui_module
+ var/name
+ var/datum/host
+ var/list/using_access
+
+ var/tgui_id
+
+/datum/tgui_module/New(var/host)
+ src.host = host
+
+/datum/tgui_module/ui_host()
+ return host ? host : src
+
+/datum/tgui_module/ui_close(mob/user)
+ if(host)
+ host.ui_close(user)
+
+/datum/tgui_module/proc/check_access(mob/user, access)
+ if(!access)
+ return 1
+
+ if(using_access)
+ if(access in using_access)
+ return 1
+ else
+ return 0
+
+ if(!istype(user))
+ return 0
+
+ var/obj/item/card/id/I = user.GetIdCard()
+ if(!I)
+ return 0
+
+ if(access in I.access)
+ return 1
+
+ return 0
\ No newline at end of file
diff --git a/code/modules/tgui/modules/camera.dm b/code/modules/tgui/modules/camera.dm
new file mode 100644
index 00000000000..72521648513
--- /dev/null
+++ b/code/modules/tgui/modules/camera.dm
@@ -0,0 +1,295 @@
+/datum/tgui_module/camera
+ name = "Security Cameras"
+ tgui_id = "CameraConsole"
+
+ var/access_based = FALSE
+ var/list/network = list()
+ var/list/additional_networks = list()
+
+ var/obj/machinery/camera/active_camera
+ var/list/concurrent_users = list()
+
+ // Stuff needed to render the map
+ var/map_name
+ var/const/default_map_size = 15
+ var/obj/screen/map_view/cam_screen
+ /// All the plane masters that need to be applied.
+ var/list/cam_plane_masters
+ var/obj/screen/background/cam_background
+ var/obj/screen/background/cam_foreground
+ var/obj/screen/skybox/local_skybox
+ // Needed for moving camera support
+ var/camera_diff_x = -1
+ var/camera_diff_y = -1
+ var/camera_diff_z = -1
+
+/datum/tgui_module/camera/New(host, list/network_computer)
+ . = ..()
+ if(!LAZYLEN(network_computer))
+ access_based = TRUE
+ else
+ network = network_computer
+ map_name = "camera_console_[REF(src)]_map"
+ // Initialize map objects
+ cam_screen = new
+ cam_screen.name = "screen"
+ cam_screen.assigned_map = map_name
+ cam_screen.del_on_map_removal = FALSE
+ cam_screen.screen_loc = "[map_name]:1,1"
+ cam_plane_masters = list()
+
+ for(var/plane in subtypesof(/obj/screen/plane_master))
+ var/obj/screen/instance = new plane()
+ instance.assigned_map = map_name
+ instance.del_on_map_removal = FALSE
+ instance.screen_loc = "[map_name]:CENTER"
+ cam_plane_masters += instance
+
+ local_skybox = new()
+ local_skybox.assigned_map = map_name
+ local_skybox.del_on_map_removal = FALSE
+ local_skybox.screen_loc = "[map_name]:CENTER,CENTER"
+ cam_plane_masters += local_skybox
+
+ cam_background = new
+ cam_background.assigned_map = map_name
+ cam_background.del_on_map_removal = FALSE
+
+ var/mutable_appearance/scanlines = mutable_appearance('icons/effects/static.dmi', "scanlines")
+ scanlines.alpha = 50
+ scanlines.layer = FULLSCREEN_LAYER
+
+ var/mutable_appearance/noise = mutable_appearance('icons/effects/static.dmi', "1 light")
+ noise.layer = FULLSCREEN_LAYER
+
+ cam_foreground = new
+ cam_foreground.assigned_map = map_name
+ cam_foreground.del_on_map_removal = FALSE
+ cam_foreground.plane = PLANE_FULLSCREEN
+ cam_foreground.add_overlay(scanlines)
+ cam_foreground.add_overlay(noise)
+
+/datum/tgui_module/camera/Destroy()
+ qdel(cam_screen)
+ QDEL_LIST(cam_plane_masters)
+ qdel(cam_background)
+ qdel(cam_foreground)
+ return ..()
+
+/datum/tgui_module/camera/ui_interact(mob/user, datum/tgui/ui = null)
+ // Update UI
+ ui = SStgui.try_update_ui(user, src, ui)
+ // Show static if can't use the camera
+ if(!active_camera?.can_use())
+ show_camera_static()
+ if(!ui)
+ var/user_ref = REF(user)
+ var/is_living = isliving(user)
+ // Ghosts shouldn't count towards concurrent users, which produces
+ // an audible terminal_on click.
+ if(is_living)
+ concurrent_users += user_ref
+ // Turn on the console
+ if(length(concurrent_users) == 1 && is_living)
+ playsound(ui_host(), 'sound/machines/terminal_on.ogg', 25, FALSE)
+ // Register map objects
+ user.client.register_map_obj(cam_screen)
+ for(var/plane in cam_plane_masters)
+ user.client.register_map_obj(plane)
+ user.client.register_map_obj(cam_background)
+ user.client.register_map_obj(cam_foreground)
+ // Open UI
+ ui = new(user, src, tgui_id, name)
+ ui.open()
+
+/datum/tgui_module/camera/ui_data()
+ var/list/data = list()
+ data["activeCamera"] = null
+ if(active_camera)
+ differential_check()
+ data["activeCamera"] = list(
+ name = active_camera.c_tag,
+ status = active_camera.status,
+ )
+ return data
+
+/datum/tgui_module/camera/ui_static_data(mob/user)
+ var/list/data = list()
+ data["mapRef"] = map_name
+ var/list/cameras = get_available_cameras(user)
+ data["cameras"] = list()
+ data["allNetworks"] = list()
+ for(var/i in cameras)
+ var/obj/machinery/camera/C = cameras[i]
+ data["cameras"] += list(list(
+ name = C.c_tag,
+ networks = C.network
+ ))
+ data["allNetworks"] |= C.network
+ return data
+
+/datum/tgui_module/camera/ui_act(action, params)
+ if(..())
+ return
+
+ if(action == "switch_camera")
+ var/c_tag = params["name"]
+ var/list/cameras = get_available_cameras(usr)
+ var/obj/machinery/camera/C = cameras["[ckey(c_tag)]"]
+ active_camera = C
+ playsound(ui_host(), get_sfx("terminal_type"), 25, FALSE)
+
+ reload_cameraview()
+
+ return TRUE
+
+/datum/tgui_module/camera/proc/differential_check()
+ var/turf/T = get_turf(active_camera)
+ if(T)
+ var/new_x = T.x
+ var/new_y = T.y
+ var/new_z = T.z
+ if((new_x != camera_diff_x) || (new_y != camera_diff_y) || (new_z != camera_diff_z))
+ reload_cameraview()
+
+/datum/tgui_module/camera/proc/reload_cameraview()
+ // Show static if can't use the camera
+ if(!active_camera?.can_use())
+ show_camera_static()
+ return TRUE
+
+ var/turf/camTurf = get_turf(active_camera)
+
+ camera_diff_x = camTurf.x
+ camera_diff_y = camTurf.y
+ camera_diff_z = camTurf.z
+
+ var/list/visible_turfs = list()
+ for(var/turf/T in (active_camera.isXRay() \
+ ? range(active_camera.view_range, camTurf) \
+ : view(active_camera.view_range, camTurf)))
+ visible_turfs += T
+
+ var/list/bbox = get_bbox_of_atoms(visible_turfs)
+ var/size_x = bbox[3] - bbox[1] + 1
+ var/size_y = bbox[4] - bbox[2] + 1
+
+ cam_screen.vis_contents = visible_turfs
+ cam_background.icon_state = "clear"
+ cam_background.fill_rect(1, 1, size_x, size_y)
+
+ cam_foreground.fill_rect(1, 1, size_x, size_y)
+
+ local_skybox.cut_overlays()
+ local_skybox.add_overlay(SSskybox.get_skybox(get_z(camTurf)))
+ local_skybox.scale_to_view(size_x)
+ local_skybox.set_position("CENTER", "CENTER", (world.maxx>>1) - camTurf.x, (world.maxy>>1) - camTurf.y)
+
+// Returns the list of cameras accessible from this computer
+// This proc operates in two distinct ways depending on the context in which the module is created.
+// It can either return a list of cameras sharing the same the internal `network` variable, or
+// It can scan all station networks and determine what cameras to show based on the access of the user.
+/datum/tgui_module/camera/proc/get_available_cameras(mob/user)
+ var/list/all_networks = list()
+ // Access Based
+ if(access_based)
+ for(var/network in GLOB.using_map.station_networks)
+ if(can_access_network(user, get_camera_access(network), 1))
+ all_networks.Add(network)
+ for(var/network in GLOB.using_map.secondary_networks)
+ if(can_access_network(user, get_camera_access(network), 0))
+ all_networks.Add(network)
+ // Network Based
+ else
+ all_networks = network.Copy()
+
+ if(additional_networks)
+ all_networks += additional_networks
+
+ var/list/D = list()
+ for(var/obj/machinery/camera/C in cameranet.cameras)
+ if(!C.network)
+ stack_trace("Camera in a cameranet has no camera network")
+ continue
+ if(!(islist(C.network)))
+ stack_trace("Camera in a cameranet has a non-list camera network")
+ continue
+ var/list/tempnetwork = C.network & all_networks
+ if(tempnetwork.len)
+ D["[ckey(C.c_tag)]"] = C
+ return D
+
+/datum/tgui_module/camera/proc/can_access_network(mob/user, network_access, station_network = 0)
+ // No access passed, or 0 which is considered no access requirement. Allow it.
+ if(!network_access)
+ return 1
+
+ if(station_network)
+ return check_access(user, network_access) || check_access(user, access_security) || check_access(user, access_heads)
+ else
+ return check_access(user, network_access)
+
+/datum/tgui_module/camera/proc/show_camera_static()
+ cam_screen.vis_contents.Cut()
+ cam_background.icon_state = "scanline2"
+ cam_background.fill_rect(1, 1, default_map_size, default_map_size)
+ local_skybox.cut_overlays()
+
+/datum/tgui_module/camera/ui_close(mob/user)
+ . = ..()
+ var/user_ref = REF(user)
+ var/is_living = isliving(user)
+ // living creature or not, we remove you anyway.
+ concurrent_users -= user_ref
+ // Unregister map objects
+ if(user.client)
+ user.client.clear_map(map_name)
+ // Turn off the console
+ if(length(concurrent_users) == 0 && is_living)
+ active_camera = null
+ playsound(ui_host(), 'sound/machines/terminal_off.ogg', 25, FALSE)
+
+// NTOS Version
+// Please note, this isn't a very good replacement for converting modular computers 100% to TGUI
+// If/when that is done, just move all the PC_ specific data and stuff to the modular computers themselves
+// instead of copying this approach here.
+/datum/tgui_module/camera/ntos
+ tgui_id = "NtosCameraConsole"
+
+/datum/tgui_module/camera/ntos/ui_state()
+ return GLOB.ntos_state
+
+/datum/tgui_module/camera/ntos/ui_static_data()
+ . = ..()
+
+ var/datum/computer_file/program/host = ui_host()
+ if(istype(host) && host.computer)
+ . += host.computer.get_header_data()
+
+/datum/tgui_module/camera/ntos/ui_act(action, params)
+ if(..())
+ return
+
+ var/datum/computer_file/program/host = ui_host()
+ if(istype(host) && host.computer)
+ if(action == "PC_exit")
+ host.computer.kill_program()
+ return TRUE
+ if(action == "PC_shutdown")
+ host.computer.shutdown_computer()
+ return TRUE
+ if(action == "PC_minimize")
+ host.computer.minimize_program(usr)
+ return TRUE
+
+// ERT Version provides some additional networks.
+/datum/tgui_module/camera/ntos/ert
+ additional_networks = list(NETWORK_ERT, NETWORK_CRESCENT)
+
+// Hacked version also provides some additional networks,
+// but we want it to show *all* the networks 24/7, so we convert it into a non-access-based UI.
+/datum/tgui_module/camera/ntos/hacked
+ additional_networks = list(NETWORK_MERCENARY, NETWORK_ERT, NETWORK_CRESCENT)
+
+/datum/tgui_module/camera/ntos/hacked/New(host)
+ . = ..(host, GLOB.using_map.station_networks.Copy())
diff --git a/code/modules/tgui/modules/crew_monitor.dm b/code/modules/tgui/modules/crew_monitor.dm
new file mode 100644
index 00000000000..f9684b7f70a
--- /dev/null
+++ b/code/modules/tgui/modules/crew_monitor.dm
@@ -0,0 +1,103 @@
+/datum/tgui_module/crew_monitor
+ name = "Crew monitor"
+ tgui_id = "CrewMonitor"
+
+/datum/tgui_module/crew_monitor/ui_act(action, params, datum/tgui/ui)
+ if(..())
+ return TRUE
+
+ var/turf/T = get_turf(usr)
+ if(!T || !(T.z in GLOB.using_map.player_levels))
+ to_chat(usr, "Unable to establish a connection: You're too far away from the station!")
+ return FALSE
+
+ switch(action)
+ if("track")
+ if(isAI(usr))
+ var/mob/living/silicon/ai/AI = usr
+ var/mob/living/carbon/human/H = locate(params["track"]) in mob_list
+ if(hassensorlevel(H, SUIT_SENSOR_TRACKING))
+ AI.ai_actual_track(H)
+ return TRUE
+ if("setZLevel")
+ ui.set_map_z_level(params["mapZLevel"])
+ SStgui.update_uis(src)
+
+/datum/tgui_module/crew_monitor/ui_interact(mob/user, datum/tgui/ui = null)
+ var/z = get_z(user)
+ var/list/map_levels = GLOB.using_map.get_map_levels(z, TRUE, om_range = DEFAULT_OVERMAP_RANGE)
+
+ if(!map_levels.len)
+ to_chat(user, "The crew monitor doesn't seem like it'll work here.")
+ if(ui)
+ ui.close()
+ return null
+
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, tgui_id, name)
+ ui.autoupdate = TRUE
+ ui.open()
+
+
+/datum/tgui_module/crew_monitor/ui_data(mob/user, ui_key = "main", datum/tgui_state/state = GLOB.default_state)
+ var/data[0]
+
+ data["isAI"] = isAI(user)
+
+ var/z = get_z(user)
+ var/list/map_levels = uniqueList(GLOB.using_map.get_map_levels(z, TRUE, om_range = DEFAULT_OVERMAP_RANGE))
+ data["map_levels"] = map_levels
+
+ data["crewmembers"] = list()
+ for(var/zlevel in map_levels)
+ data["crewmembers"] += crew_repository.health_data(zlevel)
+
+ return data
+
+/datum/tgui_module/crew_monitor/ntos
+ tgui_id = "NtosCrewMonitor"
+
+/datum/tgui_module/crew_monitor/ntos/ui_state(mob/user)
+ return GLOB.ntos_state
+
+/datum/tgui_module/crew_monitor/ntos/ui_static_data()
+ . = ..()
+
+ var/datum/computer_file/program/host = ui_host()
+ if(istype(host) && host.computer)
+ . += host.computer.get_header_data()
+
+/datum/tgui_module/crew_monitor/ntos/ui_act(action, params)
+ if(..())
+ return
+
+ var/datum/computer_file/program/host = ui_host()
+ if(istype(host) && host.computer)
+ if(action == "PC_exit")
+ host.computer.kill_program()
+ return TRUE
+ if(action == "PC_shutdown")
+ host.computer.shutdown_computer()
+ return TRUE
+ if(action == "PC_minimize")
+ host.computer.minimize_program(usr)
+ return TRUE
+
+// Subtype for glasses_state
+/datum/tgui_module/crew_monitor/glasses
+
+/datum/tgui_module/crew_monitor/glasses/ui_state(mob/user)
+ return GLOB.ui_glasses_state
+
+// Subtype for self_state
+/datum/tgui_module/crew_monitor/robot
+
+/datum/tgui_module/crew_monitor/robot/ui_state(mob/user)
+ return GLOB.self_state
+
+// Subtype for nif_state
+/datum/tgui_module/crew_monitor/nif
+
+/datum/tgui_module/crew_monitor/nif/ui_state(mob/user)
+ return GLOB.ui_nif_state
diff --git a/code/modules/tgui/states/inventory.dm b/code/modules/tgui/states/inventory.dm
index dc5dd0d57e6..56afbd2addd 100644
--- a/code/modules/tgui/states/inventory.dm
+++ b/code/modules/tgui/states/inventory.dm
@@ -14,3 +14,33 @@ GLOBAL_DATUM_INIT(inventory_state, /datum/ui_state/inventory_state, new)
if(!(src_object in user))
return UI_CLOSE
return user.shared_ui_interaction(src_object)
+
+GLOBAL_DATUM_INIT(ui_glasses_state, /datum/ui_state/glasses_state, new)
+
+/datum/ui_state/glasses_state/can_use_topic(var/src_object, var/mob/user)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.glasses == src_object)
+ return user.shared_ui_interaction()
+
+ return STATUS_CLOSE
+
+GLOBAL_DATUM_INIT(ui_nif_state, /datum/ui_state/nif_state, new)
+
+/datum/ui_state/nif_state/can_use_topic(var/src_object, var/mob/user)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.nif && H.nif.stat == NIF_WORKING && src_object == H.nif)
+ return user.shared_ui_interaction()
+
+ return STATUS_CLOSE
+
+GLOBAL_DATUM_INIT(ui_commlink_state, /datum/ui_state/commlink_state, new)
+
+/datum/ui_state/commlink_state/can_use_topic(var/src_object, var/mob/user)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.nif && H.nif.stat == NIF_WORKING && H.nif.comm == src_object)
+ return user.shared_ui_interaction()
+
+ return STATUS_CLOSE
diff --git a/code/modules/tgui/states/ntos.dm b/code/modules/tgui/states/ntos.dm
new file mode 100644
index 00000000000..dd29544225e
--- /dev/null
+++ b/code/modules/tgui/states/ntos.dm
@@ -0,0 +1,15 @@
+/**
+ * tgui state: ntos_state
+ *
+ * Checks a number of things -- mostly physical distance for humans and view for robots.
+ * This is basically the same as default, except instead of src_object, it uses the computer
+ * it's attached to.
+ **/
+
+GLOBAL_DATUM_INIT(ntos_state, /datum/ui_state/ntos, new)
+
+/datum/ui_state/ntos/can_use_topic(src_object, mob/user)
+ var/datum/computer_file/program/P = src_object
+ if(!istype(P) || !P.computer)
+ return FALSE
+ return user.default_can_use_ui_topic(P.computer) // Call the individual mob-overridden procs.
\ No newline at end of file
diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm
index 7322c4179bb..9f0eae08080 100644
--- a/code/modules/tgui/tgui.dm
+++ b/code/modules/tgui/tgui.dm
@@ -33,6 +33,8 @@
var/status = UI_INTERACTIVE
/// Topic state used to determine status/interactability.
var/datum/ui_state/state = null
+ // The map z-level to display.
+ var/map_z_level = 1
/**
* public
@@ -268,6 +270,15 @@
if(needs_update)
window.send_message("update", get_payload())
+
+/**
+ Sets the current map z level of the tgui window (so we know which Z we need to be interacting with.)
+ */
+
+/datum/tgui/proc/set_map_z_level(nz)
+ map_z_level = nz
+
+
/**
* private
*
diff --git a/icons/mob/map_backgrounds.dmi b/icons/mob/map_backgrounds.dmi
new file mode 100644
index 00000000000..dc6e3e46b16
Binary files /dev/null and b/icons/mob/map_backgrounds.dmi differ
diff --git a/modular_citadel/code/modules/clothing/glasses/hud_vr.dm b/modular_citadel/code/modules/clothing/glasses/hud_vr.dm
deleted file mode 100644
index d525035330d..00000000000
--- a/modular_citadel/code/modules/clothing/glasses/hud_vr.dm
+++ /dev/null
@@ -1,23 +0,0 @@
-/obj/item/clothing/glasses/omnihud
- name = "\improper AR glasses"
- desc = "The Nerd Glasses are a design from Nerd Co. Made in Montreal, China. For when reality just isn't cutting it, Nerd Glasses are a cut above the rest."
-
-/obj/item/clothing/glasses/omnihud/med
- desc = "The Nurse Glasses are a design from Nerd Co. \
- These have been upgraded with medical records access and virus database integration."
-
-/obj/item/clothing/glasses/omnihud/sec
- desc = "The Bully Glasses are a design from Nerd Co. \
- These have been upgraded with security records integration and flash protection."
-
-/obj/item/clothing/glasses/omnihud/eng
- desc = "The Genius Glasses are a design from Nerd Co. \
- These have been upgraded with advanced electrochromic lenses to protect your eyes during welding."
-
-/obj/item/clothing/glasses/omnihud/rnd
- desc = "The Geek Glasses are a design from Nerd Co. \
- These have been modified to fit a different frame."
-
-/obj/item/clothing/glasses/omnihud/all
- desc = "The Super Dork Glasses are a design from Nerd Co. \
- These have been stocked with every feature from the entire Nerd Co. lineup of AR Specs. Jocks beware."
diff --git a/sound/machines/terminal_alert.ogg b/sound/machines/terminal_alert.ogg
new file mode 100644
index 00000000000..a790c03ebdf
Binary files /dev/null and b/sound/machines/terminal_alert.ogg differ
diff --git a/sound/machines/terminal_button01.ogg b/sound/machines/terminal_button01.ogg
new file mode 100644
index 00000000000..88b10c88912
Binary files /dev/null and b/sound/machines/terminal_button01.ogg differ
diff --git a/sound/machines/terminal_button02.ogg b/sound/machines/terminal_button02.ogg
new file mode 100644
index 00000000000..8b30fd892ee
Binary files /dev/null and b/sound/machines/terminal_button02.ogg differ
diff --git a/sound/machines/terminal_button03.ogg b/sound/machines/terminal_button03.ogg
new file mode 100644
index 00000000000..7a00168cfc3
Binary files /dev/null and b/sound/machines/terminal_button03.ogg differ
diff --git a/sound/machines/terminal_button04.ogg b/sound/machines/terminal_button04.ogg
new file mode 100644
index 00000000000..c56b23919cc
Binary files /dev/null and b/sound/machines/terminal_button04.ogg differ
diff --git a/sound/machines/terminal_button05.ogg b/sound/machines/terminal_button05.ogg
new file mode 100644
index 00000000000..e660ecf154c
Binary files /dev/null and b/sound/machines/terminal_button05.ogg differ
diff --git a/sound/machines/terminal_button06.ogg b/sound/machines/terminal_button06.ogg
new file mode 100644
index 00000000000..bef143ac521
Binary files /dev/null and b/sound/machines/terminal_button06.ogg differ
diff --git a/sound/machines/terminal_button07.ogg b/sound/machines/terminal_button07.ogg
new file mode 100644
index 00000000000..91a31a1156a
Binary files /dev/null and b/sound/machines/terminal_button07.ogg differ
diff --git a/sound/machines/terminal_button08.ogg b/sound/machines/terminal_button08.ogg
new file mode 100644
index 00000000000..fc0131f5f4e
Binary files /dev/null and b/sound/machines/terminal_button08.ogg differ
diff --git a/sound/machines/terminal_insert_disc.ogg b/sound/machines/terminal_insert_disc.ogg
new file mode 100644
index 00000000000..dd226c1ebde
Binary files /dev/null and b/sound/machines/terminal_insert_disc.ogg differ
diff --git a/sound/machines/terminal_off.ogg b/sound/machines/terminal_off.ogg
new file mode 100644
index 00000000000..90da8d75daf
Binary files /dev/null and b/sound/machines/terminal_off.ogg differ
diff --git a/sound/machines/terminal_on.ogg b/sound/machines/terminal_on.ogg
new file mode 100644
index 00000000000..3c69d85de54
Binary files /dev/null and b/sound/machines/terminal_on.ogg differ
diff --git a/sound/machines/terminal_prompt.ogg b/sound/machines/terminal_prompt.ogg
new file mode 100644
index 00000000000..74de1c9a298
Binary files /dev/null and b/sound/machines/terminal_prompt.ogg differ
diff --git a/sound/machines/terminal_prompt_confirm.ogg b/sound/machines/terminal_prompt_confirm.ogg
new file mode 100644
index 00000000000..897fec28e9a
Binary files /dev/null and b/sound/machines/terminal_prompt_confirm.ogg differ
diff --git a/sound/machines/terminal_prompt_deny.ogg b/sound/machines/terminal_prompt_deny.ogg
new file mode 100644
index 00000000000..fda065f0d46
Binary files /dev/null and b/sound/machines/terminal_prompt_deny.ogg differ
diff --git a/tgui/docs/migration-to-v4-from-v3.md b/tgui/docs/migration-to-v4-from-v3.md
index 6f047a6cc7e..6e019c148c3 100644
--- a/tgui/docs/migration-to-v4-from-v3.md
+++ b/tgui/docs/migration-to-v4-from-v3.md
@@ -14,7 +14,7 @@
- `code/__HELPERS/_logging.dm`
If you have a dual nano/tgui setup, then make sure to rename all ui procs
-on `/datum`, such as `ui_interact` to `tgui_interact`, to avoid namespace
+on `/datum`, such as `ui_interact` to `ui_interact`, to avoid namespace
clashing. Usual stuff.
## Update `ui_interact` proc signatures
diff --git a/tgui/packages/tgui/interfaces/CrewMonitor.js b/tgui/packages/tgui/interfaces/CrewMonitor.js
new file mode 100644
index 00000000000..e5d8dff2ba8
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/CrewMonitor.js
@@ -0,0 +1,173 @@
+import { sortBy } from 'common/collections';
+import { useBackend, useLocalState } from "../backend";
+import { Window } from "../layouts";
+import { NanoMap, Box, Table, Button, Tabs, Icon, NumberInput } from "../components";
+import { TableCell } from '../components/Table';
+import { COLORS } from '../constants.js';
+import { Fragment } from 'inferno';
+
+export const CrewMonitor = () => {
+ return (
+
+
+ );
+ } else if (tabIndex === 1) {
+ body = (
+
/gi,"\n").replace(/<\/?[a-z0-9-_]+[^>]*>/gi,"").replace(/&(nbsp|amp|quot|lt|gt|apos);/g,(function(e,n){return t[n]})).replace(/?([0-9]+);/gi,(function(e,t){var n=parseInt(t,10);return String.fromCharCode(n)})).replace(/?([0-9a-f]+);/gi,(function(e,t){var n=parseInt(t,16);return String.fromCharCode(n)}))};t.buildQueryString=function(e){return Object.keys(e).map((function(t){return encodeURIComponent(t)+"="+encodeURIComponent(e[t])})).join("&")}},function(e,t,n){"use strict";t.__esModule=!0,t.Box=t.computeBoxClassName=t.computeBoxProps=t.halfUnit=t.unit=void 0;var r=n(6),o=n(0),i=n(466),a=n(36);var c=function(e){return"string"==typeof e?e.endsWith("px")&&!Byond.IS_LTE_IE8?parseFloat(e)/12+"rem":e:"number"==typeof e?Byond.IS_LTE_IE8?12*e+"px":e+"rem":void 0};t.unit=c;var u=function(e){return"string"==typeof e?c(e):"number"==typeof e?c(.5*e):void 0};t.halfUnit=u;var s=function(e){return"string"==typeof e&&a.CSS_COLORS.includes(e)},l=function(e){return function(t,n){"number"!=typeof n&&"string"!=typeof n||(t[e]=n)}},f=function(e,t){return function(n,r){"number"!=typeof r&&"string"!=typeof r||(n[e]=t(r))}},d=function(e,t){return function(n,r){r&&(n[e]=t)}},p=function(e,t,n){return function(r,o){if("number"==typeof o||"string"==typeof o)for(var i=0;iu||n!=n?l*Infinity:l*n}},function(e,t,n){"use strict";var r=n(4),o=Math.hypot,i=Math.abs,a=Math.sqrt;r({target:"Math",stat:!0,forced:!!o&&o(Infinity,NaN)!==Infinity},{hypot:function(e,t){for(var n,r,o=0,c=0,u=arguments.length,s=0;c0?(r=n/s)*r:n;return s===Infinity?Infinity:s*a(o)}})},function(e,t,n){"use strict";var r=n(4),o=n(5),i=Math.imul;r({target:"Math",stat:!0,forced:o((function(){return-5!=i(4294967295,5)||2!=i.length}))},{imul:function(e,t){var n=+e,r=+t,o=65535&n,i=65535&r;return 0|o*i+((65535&n>>>16)*i+o*(65535&r>>>16)<<16>>>0)}})},function(e,t,n){"use strict";var r=n(4),o=Math.log,i=Math.LOG10E;r({target:"Math",stat:!0},{log10:function(e){return o(e)*i}})},function(e,t,n){"use strict";n(4)({target:"Math",stat:!0},{log1p:n(172)})},function(e,t,n){"use strict";var r=n(4),o=Math.log,i=Math.LN2;r({target:"Math",stat:!0},{log2:function(e){return o(e)/i}})},function(e,t,n){"use strict";n(4)({target:"Math",stat:!0},{sign:n(126)})},function(e,t,n){"use strict";var r=n(4),o=n(5),i=n(91),a=Math.abs,c=Math.exp,u=Math.E;r({target:"Math",stat:!0,forced:o((function(){return-2e-17!=Math.sinh(-2e-17)}))},{sinh:function(e){return a(e=+e)<1?(i(e)-i(-e))/2:(c(e-1)-c(-e-1))*(u/2)}})},function(e,t,n){"use strict";var r=n(4),o=n(91),i=Math.exp;r({target:"Math",stat:!0},{tanh:function(e){var t=o(e=+e),n=o(-e);return t==Infinity?1:n==Infinity?-1:(t-n)/(i(e)+i(-e))}})},function(e,t,n){"use strict";n(49)(Math,"Math",!0)},function(e,t,n){"use strict";var r=n(4),o=Math.ceil,i=Math.floor;r({target:"Math",stat:!0},{trunc:function(e){return(e>0?i:o)(e)}})},function(e,t,n){"use strict";var r=n(10),o=n(7),i=n(70),a=n(27),c=n(20),u=n(37),s=n(90),l=n(40),f=n(5),d=n(48),p=n(52).f,h=n(23).f,g=n(16).f,v=n(63).trim,m=o.Number,y=m.prototype,b="Number"==u(d(y)),x=function(e){var t,n,r,o,i,a,c,u,s=l(e,!1);if("string"==typeof s&&s.length>2)if(43===(t=(s=v(s)).charCodeAt(0))||45===t){if(88===(n=s.charCodeAt(2))||120===n)return NaN}else if(48===t){switch(s.charCodeAt(1)){case 66:case 98:r=2,o=49;break;case 79:case 111:r=8,o=55;break;default:return+s}for(a=(i=s.slice(2)).length,c=0;co)return NaN;return parseInt(i,r)}return+s};if(i("Number",!m(" 0o1")||!m("0b1")||m("+0x1"))){for(var w,_=function(e){var t=arguments.length<1?0:e,n=this;return n instanceof _&&(b?f((function(){y.valueOf.call(n)})):"Number"!=u(n))?s(new m(x(t)),n,_):x(t)},E=r?p(m):"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger".split(","),k=0;E.length>k;k++)c(m,w=E[k])&&!c(_,w)&&g(_,w,h(m,w));_.prototype=y,y.constructor=_,a(o,"Number",_)}},function(e,t,n){"use strict";n(4)({target:"Number",stat:!0},{EPSILON:Math.pow(2,-52)})},function(e,t,n){"use strict";n(4)({target:"Number",stat:!0},{isFinite:n(309)})},function(e,t,n){"use strict";var r=n(7).isFinite;e.exports=Number.isFinite||function(e){return"number"==typeof e&&r(e)}},function(e,t,n){"use strict";n(4)({target:"Number",stat:!0},{isInteger:n(173)})},function(e,t,n){"use strict";n(4)({target:"Number",stat:!0},{isNaN:function(e){return e!=e}})},function(e,t,n){"use strict";var r=n(4),o=n(173),i=Math.abs;r({target:"Number",stat:!0},{isSafeInteger:function(e){return o(e)&&i(e)<=9007199254740991}})},function(e,t,n){"use strict";n(4)({target:"Number",stat:!0},{MAX_SAFE_INTEGER:9007199254740991})},function(e,t,n){"use strict";n(4)({target:"Number",stat:!0},{MIN_SAFE_INTEGER:-9007199254740991})},function(e,t,n){"use strict";var r=n(4),o=n(316);r({target:"Number",stat:!0,forced:Number.parseFloat!=o},{parseFloat:o})},function(e,t,n){"use strict";var r=n(7),o=n(63).trim,i=n(92),a=r.parseFloat,c=1/a(i+"-0")!=-Infinity;e.exports=c?function(e){var t=o(String(e)),n=a(t);return 0===n&&"-"==t.charAt(0)?-0:n}:a},function(e,t,n){"use strict";var r=n(4),o=n(174);r({target:"Number",stat:!0,forced:Number.parseInt!=o},{parseInt:o})},function(e,t,n){"use strict";var r=n(4),o=n(38),i=n(319),a=n(125),c=n(5),u=1..toFixed,s=Math.floor,l=function f(e,t,n){return 0===t?n:t%2==1?f(e,t-1,n*e):f(e*e,t/2,n)};r({target:"Number",proto:!0,forced:u&&("0.000"!==8e-5.toFixed(3)||"1"!==.9.toFixed(0)||"1.25"!==1.255.toFixed(2)||"1000000000000000128"!==(0xde0b6b3a7640080).toFixed(0))||!c((function(){u.call({})}))},{toFixed:function(e){var t,n,r,c,u=i(this),f=o(e),d=[0,0,0,0,0,0],p="",h="0",g=function(e,t){for(var n=-1,r=t;++n<6;)r+=e*d[n],d[n]=r%1e7,r=s(r/1e7)},v=function(e){for(var t=6,n=0;--t>=0;)n+=d[t],d[t]=s(n/e),n=n%e*1e7},m=function(){for(var e=6,t="";--e>=0;)if(""!==t||0===e||0!==d[e]){var n=String(d[e]);t=""===t?n:t+a.call("0",7-n.length)+n}return t};if(f<0||f>20)throw RangeError("Incorrect fraction digits");if(u!=u)return"NaN";if(u<=-1e21||u>=1e21)return String(u);if(u<0&&(p="-",u=-u),u>1e-21)if(n=(t=function(e){for(var t=0,n=e;n>=4096;)t+=12,n/=4096;for(;n>=2;)t+=1,n/=2;return t}(u*l(2,69,1))-69)<0?u*l(2,-t,1):u/l(2,t,1),n*=4503599627370496,(t=52-t)>0){for(g(0,n),r=f;r>=7;)g(1e7,0),r-=7;for(g(l(10,r,1),0),r=t-1;r>=23;)v(1<<23),r-=23;v(1<
\n":"'+(n?e:U(e,!0))+"
\n"},t.blockquote=function(e){return""+(n?e:U(e,!0))+"\n"+e+"
\n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"
\n":"
\n"},t.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+""+r+">\n"},t.listitem=function(e){return"\n\n"+e+"\n"+t+"
\n"},t.tablerow=function(e){return"\n"+e+" \n"},t.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+""+n+">\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
":"
"},t.del=function(e){return""+e+""},t.link=function(e,t,n){if(null===(e=Y(this.options.sanitize,this.options.baseUrl,e)))return n;var r='"+n+""},t.image=function(e,t,n){if(null===(e=Y(this.options.sanitize,this.options.baseUrl,e)))return n;var r='":">"},t.text=function(e){return e},e}(),H=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,n){return""+n},t.image=function(e,t,n){return""+n},t.br=function(){return""},e}(),W=function(){function e(){this.seen={}}var t=e.prototype;return t.serialize=function(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")},t.getNextSafeSlug=function(e,t){var n=e,r=0;if(this.seen.hasOwnProperty(n)){r=this.seen[e];do{n=e+"-"+ ++r}while(this.seen.hasOwnProperty(n))}return t||(this.seen[e]=r,this.seen[n]=0),n},t.slug=function(e,t){void 0===t&&(t={});var n=this.serialize(e);return this.getNextSafeSlug(n,t.dryrun)},e}(),q=r.defaults,G=w.unescape,X=function(){function e(e){this.options=e||q,this.options.renderer=this.options.renderer||new $,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new H,this.slugger=new W}e.parse=function(t,n){return new e(n).parse(t)},e.parseInline=function(t,n){return new e(n).parseInline(t)};var t=e.prototype;return t.parse=function(e,t){void 0===t&&(t=!0);var n,r,o,i,a,c,u,s,l,f,d,p,h,g,v,m,y,b,x="",w=e.length;for(n=0;n
"+J(u.message+"",!0)+"";throw u}}return re.options=re.setOptions=function(e){return Z(re.defaults,e),te(re.defaults),re},re.getDefaults=ee,re.defaults=ne,re.use=function(e){var t=Z({},e);if(e.renderer&&function(){var n=re.defaults.renderer||new $,r=function(t){var r=n[t];n[t]=function(){for(var o=arguments.length,i=new Array(o),a=0;a
"+J(r.message+"",!0)+"";throw r}},re.Parser=X,re.parser=X.parse,re.Renderer=$,re.TextRenderer=H,re.Lexer=K,re.lexer=K.lex,re.Tokenizer=A,re.Slugger=W,re.parse=re,re}()}]]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[function(e,t,n){"use strict";t.__esModule=!0;var r=n(449);Object.keys(r).forEach((function(e){"default"!==e&&"__esModule"!==e&&(t[e]=r[e])}))},function(e,t,n){"use strict";t.__esModule=!0,t.TimeDisplay=t.Tooltip=t.Tabs=t.TextArea=t.Table=t.Slider=t.Section=t.ProgressBar=t.NumberInput=t.NoticeBox=t.Modal=t.LabeledList=t.LabeledControls=t.Knob=t.Input=t.Icon=t.Grid=t.Flex=t.Dropdown=t.DraggableControl=t.Divider=t.Dimmer=t.ColorBox=t.Collapsible=t.Chart=t.ByondUi=t.Button=t.Box=t.BlockQuote=t.AnimatedNumber=void 0;var r=n(138);t.AnimatedNumber=r.AnimatedNumber;var o=n(465);t.BlockQuote=o.BlockQuote;var i=n(18);t.Box=i.Box;var a=n(193);t.Button=a.Button;var c=n(467);t.ByondUi=c.ByondUi;var u=n(469);t.Chart=u.Chart;var s=n(470);t.Collapsible=s.Collapsible;var l=n(471);t.ColorBox=l.ColorBox;var f=n(195);t.Dimmer=f.Dimmer;var d=n(196);t.Divider=d.Divider;var p=n(139);t.DraggableControl=p.DraggableControl;var h=n(472);t.Dropdown=h.Dropdown;var g=n(197);t.Flex=g.Flex;var v=n(473);t.Grid=v.Grid;var m=n(104);t.Icon=m.Icon;var y=n(198);t.Input=y.Input;var b=n(474);t.Knob=b.Knob;var x=n(475);t.LabeledControls=x.LabeledControls;var w=n(199);t.LabeledList=w.LabeledList;var _=n(476);t.Modal=_.Modal;var E=n(477);t.NoticeBox=E.NoticeBox;var k=n(141);t.NumberInput=k.NumberInput;var S=n(478);t.ProgressBar=S.ProgressBar;var C=n(479);t.Section=C.Section;var N=n(480);t.Slider=N.Slider;var A=n(140);t.Table=A.Table;var T=n(481);t.TextArea=T.TextArea;var O=n(482);t.Tabs=O.Tabs;var I=n(194);t.Tooltip=I.Tooltip;var M=n(483);t.TimeDisplay=M.TimeDisplay},function(e,t,n){"use strict";(function(e){t.__esModule=!0,t.useSharedState=t.useLocalState=t.useBackend=t.selectBackend=t.sendAct=t.sendMessage=t.backendMiddleware=t.backendReducer=t.backendSuspendSuccess=t.backendSuspendStart=t.backendSetSharedState=t.backendUpdate=void 0;var r=n(100),o=n(190),i=n(191),a=n(24),c=n(136);var u=(0,a.createLogger)("backend"),s=function(e){return{type:"backend/update",payload:e}};t.backendUpdate=s;var l=function(e,t){return{type:"backend/setSharedState",payload:{key:e,nextState:t}}};t.backendSetSharedState=l;t.backendSuspendStart=function(){return{type:"backend/suspendStart"}};var f=function(){return{type:"backend/suspendSuccess",payload:{timestamp:Date.now()}}};t.backendSuspendSuccess=f;var d={config:{},data:{},shared:{},suspended:Date.now(),suspending:!1};t.backendReducer=function(e,t){void 0===e&&(e=d);var n=t.type,r=t.payload;if("backend/update"===n){var o=Object.assign({},e.config,r.config),i=Object.assign({},e.data,r.static_data,r.data),a=Object.assign({},e.shared);if(r.shared)for(var c=0,u=Object.keys(r.shared);c
'+(n?e:U(e,!0))+"\n":""+(n?e:U(e,!0))+"\n"},t.blockquote=function(e){return"\n"+e+"\n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"
"+e+"
\n"},t.table=function(e,t){return t&&(t=""+t+""),""+e+""},t.br=function(){return this.options.xhtml?""+J(u.message+"",!0)+"";throw u}}return re.options=re.setOptions=function(e){return Z(re.defaults,e),te(re.defaults),re},re.getDefaults=ee,re.defaults=ne,re.use=function(e){var t=Z({},e);if(e.renderer&&function(){var n=re.defaults.renderer||new $,r=function(t){var r=n[t];n[t]=function(){for(var o=arguments.length,i=new Array(o),a=0;a
"+J(r.message+"",!0)+"";throw r}},re.Parser=X,re.parser=X.parse,re.Renderer=$,re.TextRenderer=H,re.Lexer=K,re.lexer=K.lex,re.Tokenizer=A,re.Slugger=W,re.parse=re,re}()}]]); \ No newline at end of file diff --git a/tgui/public/tgui-panel.bundle.js b/tgui/public/tgui-panel.bundle.js index ff481b0966f..026d9b5e2c1 100644 --- a/tgui/public/tgui-panel.bundle.js +++ b/tgui/public/tgui-panel.bundle.js @@ -1 +1 @@ -!function(e){function t(t){for(var o,i,c=t[0],s=t[1],l=t[2],d=0,g=[];d