New Investigator QoL/Features (#13422)

This commit is contained in:
mikomyazaki
2022-04-10 11:57:05 +01:00
committed by GitHub
parent 3d937e6ff9
commit a0992e257e
6 changed files with 248 additions and 189 deletions

View File

@@ -19,205 +19,188 @@
req_access = list(access_tcomsat) req_access = list(access_tcomsat)
attack_hand(mob/user as mob) var/last_print_time
if(stat & (BROKEN|NOPOWER))
return
user.set_machine(src)
var/dat = "<TITLE>Telecommunication Server Monitor</TITLE><center><b>Telecommunications Server Monitor</b></center>"
switch(screen) /obj/machinery/computer/telecomms/server/attack_hand(mob/user)
if(stat & (BROKEN|NOPOWER))
// --- Main Menu ---
if(0)
dat += "<br>[temp]<br>"
dat += "<br>Current Network: <a href='?src=\ref[src];network=1'>[network]</a><br>"
if(servers.len)
dat += "<br>Detected Telecommunication Servers:<ul>"
for(var/obj/machinery/telecomms/T in servers)
dat += "<li><a href='?src=\ref[src];viewserver=[T.id]'>\ref[T] [T.name]</a> ([T.id])</li>"
dat += "</ul>"
dat += "<br><a href='?src=\ref[src];operation=release'>\[Flush Buffer\]</a>"
else
dat += "<br>No servers detected. Scan for servers: <a href='?src=\ref[src];operation=scan'>\[Scan\]</a>"
// --- Viewing Server ---
if(1)
dat += "<br>[temp]<br>"
dat += "<center><a href='?src=\ref[src];operation=mainmenu'>\[Main Menu\]</a> <a href='?src=\ref[src];operation=refresh'>\[Refresh\]</a></center>"
dat += "<br>Current Network: [network]"
dat += "<br>Selected Server: [SelectedServer.id]"
if(SelectedServer.totaltraffic >= 1024)
dat += "<br>Total recorded traffic: [round(SelectedServer.totaltraffic / 1024)] Terrabytes<br><br>"
else
dat += "<br>Total recorded traffic: [SelectedServer.totaltraffic] Gigabytes<br><br>"
dat += "Stored Logs: <ol>"
var/i = 0
for(var/datum/comm_log_entry/C in SelectedServer.log_entries)
i++
// If the log is a speech file
if(C.input_type == "Speech File")
dat += "<li><font color = #008F00>[C.name]</font> <font color = #FF0000><a href='?src=\ref[src];delete=[i]'>\[X\]</a></font><br>"
// -- Determine race of orator --
var/race = C.parameters["race"] // The actual race of the mob
var/language = C.parameters["language"] // The language spoken, or null/""
// -- If the orator is a human, or universal translate is active, OR mob has universal speech on --
if(universal_translate || C.parameters["uspeech"] || C.parameters["intelligible"])
dat += "<u><font color = #18743E>Data type</font></u>: [C.input_type]<br>"
dat += "<u><font color = #18743E>Source</font></u>: [C.parameters["name"]] (Job: [C.parameters["job"]])<br>"
dat += "<u><font color = #18743E>Class</font></u>: [race]<br>"
dat += "<u><font color = #18743E>Contents</font></u>: \"[C.parameters["message"]]\"<br>"
if(language)
dat += "<u><font color = #18743E>Language</font></u>: [language]<br/>"
// -- Orator is not human and universal translate not active --
else
dat += "<u><font color = #18743E>Data type</font></u>: Audio File<br>"
dat += "<u><font color = #18743E>Source</font></u>: <i>Unidentifiable</i><br>"
dat += "<u><font color = #18743E>Class</font></u>: [race]<br>"
dat += "<u><font color = #18743E>Contents</font></u>: <i>Unintelligble</i><br>"
dat += "</li><br>"
else if(C.input_type == "Execution Error")
dat += "<li><font color = #990000>[C.name]</font> <font color = #FF0000><a href='?src=\ref[src];delete=[i]'>\[X\]</a></font><br>"
dat += "<u><font color = #787700>Output</font></u>: \"[C.parameters["message"]]\"<br>"
dat += "</li><br>"
dat += "</ol>"
user << browse(dat, "window=comm_monitor;size=575x400")
onclose(user, "server_control")
temp = ""
return return
user.set_machine(src)
var/dat = "<TITLE>Telecommunication Server Monitor</TITLE><center><b>Telecommunications Server Monitor</b></center>"
switch(screen)
Topic(href, href_list) // --- Main Menu ---
if(..())
return
if(0)
add_fingerprint(usr) dat += "<br>[temp]<br>"
usr.set_machine(src) dat += "<br>Current Network: <a href='?src=\ref[src];network=1'>[network]</a><br>"
if(servers.len)
if(href_list["viewserver"]) dat += "<br>Detected Telecommunication Servers:<ul>"
screen = 1 for(var/obj/machinery/telecomms/T in servers)
for(var/obj/machinery/telecomms/T in servers) dat += "<li><a href='?src=\ref[src];viewserver=[T.id]'>\ref[T] [T.name]</a> ([T.id])</li>"
if(T.id == href_list["viewserver"]) dat += "</ul>"
SelectedServer = T dat += "<br><a href='?src=\ref[src];operation=release'>\[Flush Buffer\]</a>"
break
if(href_list["operation"])
switch(href_list["operation"])
if("release")
servers = list()
screen = 0
if("mainmenu")
screen = 0
if("scan")
if(servers.len > 0)
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font>"
else
for(var/obj/machinery/telecomms/server/T in range(25, src))
if(T.network == network)
servers.Add(T)
if(!servers.len)
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -</font>"
else
temp = "<font color = #336699>- [servers.len] SERVERS PROBED & BUFFERED -</font>"
screen = 0
if(href_list["delete"])
if(!src.allowed(usr) && !emagged)
to_chat(usr, "<span class='warning'>ACCESS DENIED.</span>")
return
if(SelectedServer)
var/datum/comm_log_entry/D = SelectedServer.log_entries[text2num(href_list["delete"])]
temp = "<font color = #336699>- DELETED ENTRY: [D.name] -</font>"
SelectedServer.log_entries.Remove(D)
qdel(D)
else else
temp = "<font color = #D70B00>- FAILED: NO SELECTED MACHINE -</font>" dat += "<br>No servers detected. Scan for servers: <a href='?src=\ref[src];operation=scan'>\[Scan\]</a>"
if(href_list["network"])
var/newnet = sanitize(input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text) // --- Viewing Server ---
if(newnet && ((usr in range(1, src) || issilicon(usr)))) if(1)
if(length(newnet) > 15) dat += "<br>[temp]<br>"
temp = "<font color = #D70B00>- FAILED: NETWORK TAG STRING TOO LENGHTLY -</font>" dat += "<center><a href='?src=\ref[src];operation=mainmenu'>\[Main Menu\]</a> <a href='?src=\ref[src];operation=refresh'>\[Refresh\]</a> <a href='?src=\ref[src];operation=printlog'>\[Print Logs\]</a></center>"
dat += "<br>Current Network: [network]"
dat += "<br>Selected Server: [SelectedServer.id]"
if(SelectedServer.totaltraffic >= 1024)
dat += "<br>Total recorded traffic: [round(SelectedServer.totaltraffic / 1024)] Terrabytes<br><br>"
else
dat += "<br>Total recorded traffic: [SelectedServer.totaltraffic] Gigabytes<br><br>"
dat += log_entries_to_text(SelectedServer)
user << browse(dat, "window=comm_monitor;size=575x400")
onclose(user, "server_control")
temp = ""
return
/obj/machinery/computer/telecomms/server/Topic(href, href_list)
if(..())
return
add_fingerprint(usr)
usr.set_machine(src)
if(href_list["viewserver"])
screen = 1
for(var/obj/machinery/telecomms/T in servers)
if(T.id == href_list["viewserver"])
SelectedServer = T
break
if(href_list["operation"])
switch(href_list["operation"])
if("release")
servers = list()
screen = 0
if("mainmenu")
screen = 0
if("scan")
if(servers.len > 0)
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font>"
else else
for(var/obj/machinery/telecomms/server/T in range(25, src))
if(T.network == network)
servers.Add(T)
if(!servers.len)
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -</font>"
else
temp = "<font color = #336699>- [servers.len] SERVERS PROBED & BUFFERED -</font>"
network = newnet
screen = 0 screen = 0
servers = list()
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font>"
updateUsrDialog() if("printlog")
return var/start_point = 1
var/end_point = SelectedServer.log_entries.len
attackby(var/obj/item/D as obj, var/mob/user as mob) if(SelectedServer)
if(D.isscrewdriver()) if(SelectedServer.log_entries.len)
playsound(src.loc, D.usesound, 50, 1) start_point = input(usr, "Type the start address to print from, cancel to print full log.", "Start Address") as null|num
if(do_after(user, 20/D.toolspeed)) if(!isnum(start_point))
if (src.stat & BROKEN) start_point = 1
to_chat(user, "<span class='notice'>The broken glass falls out.</span>") else
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) end_point = input(usr, "Type the end address to print to, cancel to print full log.", "End Address") as null|num
new /obj/item/material/shard( src.loc ) if(!isnum(end_point))
var/obj/item/circuitboard/comm_server/M = new /obj/item/circuitboard/comm_server( A ) end_point = 0
for (var/obj/C in src) else
C.forceMove(src.loc) to_chat(usr, SPAN_WARNING("Cannot print from server that has no logs."))
A.circuit = M return
A.state = 3
A.icon_state = "3"
A.anchored = 1
qdel(src)
else else
to_chat(user, "<span class='notice'>You disconnect the monitor.</span>") to_chat(usr, SPAN_WARNING("Select a server before trying to print logs."))
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) return
var/obj/item/circuitboard/comm_server/M = new /obj/item/circuitboard/comm_server( A )
for (var/obj/C in src) if(!last_print_time || (last_print_time + 2 SECONDS < world.time))
C.forceMove(src.loc) last_print_time = world.time
A.circuit = M var/obj/item/paper/P = new /obj/item/paper(get_turf(src), log_entries_to_text(SelectedServer, start_point, end_point), "[SelectedServer.id] Logs ([start_point] - [end_point])")
A.state = 4 var/mob/M = usr
A.icon_state = "4" if(M)
A.anchored = 1 M.put_in_hands(P)
qdel(src) else
src.updateUsrDialog() to_chat(usr, SPAN_WARNING("Please wait before trying to print more logs."))
return
if(href_list["delete"])
if(!src.allowed(usr) && !emagged)
to_chat(usr, "<span class='warning'>ACCESS DENIED.</span>")
return
if(SelectedServer)
var/datum/comm_log_entry/D = SelectedServer.log_entries[text2num(href_list["delete"])]
temp = "<font color = #336699>- DELETED ENTRY: [D.name] -</font>"
SelectedServer.log_entries.Remove(D)
qdel(D)
else
temp = "<font color = #D70B00>- FAILED: NO SELECTED MACHINE -</font>"
if(href_list["network"])
var/newnet = sanitize(input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text)
if(newnet && ((usr in range(1, src) || issilicon(usr))))
if(length(newnet) > 15)
temp = "<font color = #D70B00>- FAILED: NETWORK TAG STRING TOO LENGHTLY -</font>"
else
network = newnet
screen = 0
servers = list()
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font>"
updateUsrDialog()
return
/obj/machinery/computer/telecomms/server/attackby(var/obj/item/D, var/mob/user)
if(D.isscrewdriver())
playsound(src.loc, D.usesound, 50, 1)
if(do_after(user, 20/D.toolspeed))
if (src.stat & BROKEN)
to_chat(user, "<span class='notice'>The broken glass falls out.</span>")
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
new /obj/item/material/shard( src.loc )
var/obj/item/circuitboard/comm_server/M = new /obj/item/circuitboard/comm_server( A )
for (var/obj/C in src)
C.forceMove(src.loc)
A.circuit = M
A.state = 3
A.icon_state = "3"
A.anchored = 1
qdel(src)
else
to_chat(user, "<span class='notice'>You disconnect the monitor.</span>")
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
var/obj/item/circuitboard/comm_server/M = new /obj/item/circuitboard/comm_server( A )
for (var/obj/C in src)
C.forceMove(src.loc)
A.circuit = M
A.state = 4
A.icon_state = "4"
A.anchored = 1
qdel(src)
src.updateUsrDialog()
return
/obj/machinery/computer/telecomms/server/emag_act(var/remaining_charges, var/mob/user) /obj/machinery/computer/telecomms/server/emag_act(var/remaining_charges, var/mob/user)
if(!emagged) if(!emagged)
@@ -226,3 +209,55 @@
to_chat(user, "<span class='notice'>You you disable the security protocols</span>") to_chat(user, "<span class='notice'>You you disable the security protocols</span>")
src.updateUsrDialog() src.updateUsrDialog()
return 1 return 1
/obj/machinery/computer/telecomms/server/proc/log_entries_to_text(var/obj/machinery/telecomms/server/SelectedServer, start = 1, end = SelectedServer.log_entries.len)
if(!end)
end = SelectedServer.log_entries.len
start = between(1, start, SelectedServer.log_entries.len)
end = between(0, end, SelectedServer.log_entries.len)
var/list/log_entries = SelectedServer.log_entries.Copy(start, end + 1)
. += "Stored Logs: <ol>"
var/i = start - 1
for(var/datum/comm_log_entry/C as anything in log_entries)
i++
// If the log is a speech file
if(C.input_type == "Speech File")
. += "<li><font color = #008F00>[C.name]</font> <font color = #FF0000><a href='?src=\ref[src];delete=[i]'>\[X\]</a></font><br>"
// -- Determine race of orator --
var/race = C.parameters["race"] // The actual race of the mob
var/language = C.parameters["language"] // The language spoken, or null/""
// -- If the orator is a human, or universal translate is active, OR mob has universal speech on --
if(universal_translate || C.parameters["uspeech"] || C.parameters["intelligible"])
. += "<u><font color = #18743E>Data type</font></u>: [C.input_type]<br>"
. += "<u><font color = #18743E>Source</font></u>: [C.parameters["name"]] (Job: [C.parameters["job"]])<br>"
. += "<u><font color = #18743E>Class</font></u>: [race]<br>"
. += "<u><font color = #18743E>Contents</font></u>: \"[C.parameters["message"]]\"<br>"
if(language)
. += "<u><font color = #18743E>Language</font></u>: [language]<br/>"
// -- Orator is not human and universal translate not active --
else
. += "<u><font color = #18743E>Data type</font></u>: Audio File<br>"
. += "<u><font color = #18743E>Source</font></u>: <i>Unidentifiable</i><br>"
. += "<u><font color = #18743E>Class</font></u>: [race]<br>"
. += "<u><font color = #18743E>Contents</font></u>: <i>Unintelligble</i><br>"
. += "</li><br>"
else if(C.input_type == "Execution Error")
. += "<li><font color = #990000>[C.name]</font> <font color = #FF0000><a href='?src=\ref[src];delete=[i]'>\[X\]</a></font><br>"
. += "<u><font color = #787700>Output</font></u>: \"[C.parameters["message"]]\"<br>"
. += "</li><br>"
. += "</ol>"

View File

@@ -367,6 +367,7 @@
new /obj/item/device/laser_pointer/blue(src) new /obj/item/device/laser_pointer/blue(src)
new /obj/item/device/camera/detective(src) new /obj/item/device/camera/detective(src)
new /obj/item/device/camera_film(src) new /obj/item/device/camera_film(src)
new /obj/item/stamp/investigations(src)
//Belts //Belts
new /obj/item/clothing/accessory/holster/waist(src) new /obj/item/clothing/accessory/holster/waist(src)
new /obj/item/clothing/accessory/storage/pouches/black(src) new /obj/item/clothing/accessory/storage/pouches/black(src)

View File

@@ -51,11 +51,16 @@
active_warrant = null active_warrant = null
if(href_list["editwarrant"]) if(href_list["editwarrant"])
. = TRUE
for(var/datum/record/warrant/W in SSrecords.warrants) for(var/datum/record/warrant/W in SSrecords.warrants)
if(W.id == text2num(href_list["editwarrant"])) if(W.id == text2num(href_list["editwarrant"]))
active_warrant = W active_warrant = W
break break
return TRUE
if(href_list["back"])
. = TRUE
active_warrant = null
return TRUE
// The following actions will only be possible if the user has an ID with security access equipped. This is in line with modular computer framework's authentication methods, // The following actions will only be possible if the user has an ID with security access equipped. This is in line with modular computer framework's authentication methods,
// which also use RFID scanning to allow or disallow access to some functions. Anyone can view warrants, editing requires ID. // which also use RFID scanning to allow or disallow access to some functions. Anyone can view warrants, editing requires ID.
@@ -64,10 +69,15 @@
if(!istype(user)) if(!istype(user))
return return
var/obj/item/card/id/I = user.GetIdCard() var/obj/item/card/id/I = user.GetIdCard()
if(!istype(I) || !I.registered_name || !(access_armory in I.access) || issilicon(user)) if(!istype(I) || !I.registered_name || !(access_security in I.access) || issilicon(user))
to_chat(user, SPAN_WARNING("Authentication error: Unable to locate ID with appropriate access to allow this operation.")) to_chat(user, SPAN_WARNING("Authentication error: Unable to locate ID with appropriate access to allow this operation."))
return return
// Require higher access to edit warrants that have already been authorized
if(active_warrant && active_warrant.authorization != "Unauthorized" && !(access_armory in I.access))
to_chat(user, SPAN_WARNING("Authentication error: Unable to locate ID with appropriate access to adjust an authorized warrant."))
return
if(href_list["addwarrant"]) if(href_list["addwarrant"])
. = TRUE . = TRUE
var/datum/record/warrant/W = new() var/datum/record/warrant/W = new()
@@ -83,6 +93,8 @@
W.notes = "No reason given" W.notes = "No reason given"
W.authorization = "Unauthorized" W.authorization = "Unauthorized"
W.wtype = "search" W.wtype = "search"
if(isnull(temp))
return
active_warrant = W active_warrant = W
if(href_list["savewarrant"]) if(href_list["savewarrant"])
@@ -123,10 +135,9 @@
active_warrant.notes = new_charges active_warrant.notes = new_charges
if(href_list["editwarrantauth"]) if(href_list["editwarrantauth"])
if(!(access_armory in I.access))
to_chat(user, SPAN_WARNING("Authentication error: Unable to locate ID with appropriate access to allow this operation."))
return
. = TRUE . = TRUE
active_warrant.authorization = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]" active_warrant.authorization = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]"
if(href_list["back"])
. = TRUE
active_warrant = null

View File

@@ -35,6 +35,10 @@
name = "chief medical officer's rubber stamp" name = "chief medical officer's rubber stamp"
icon_state = "stamp-cmo" icon_state = "stamp-cmo"
/obj/item/stamp/investigations
name = "case closed stamp"
icon_state = "stamp-investigator"
/obj/item/stamp/denied /obj/item/stamp/denied
name = "\improper DENIED rubber stamp" name = "\improper DENIED rubber stamp"
icon_state = "stamp-deny" icon_state = "stamp-deny"

View File

@@ -0,0 +1,8 @@
author: mikomyazaki
delete-after: True
changes:
- tweak: "Security Officers, Investigators and Security Cadets can now submit warrants for approval using the warrant program. They cannot authorize warrants or edit authorized warrants."
- rscadd: "Investigators now have a 'Case Closed' stamp in their lockers."
- rscadd: "The Telecomms Server Monitor can now print channel logs."

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 29 KiB