diff --git a/code/defines/procs/helpers.dm b/code/defines/procs/helpers.dm
index 4b51fe23d9..84a2d016ca 100644
--- a/code/defines/procs/helpers.dm
+++ b/code/defines/procs/helpers.dm
@@ -246,6 +246,31 @@
/proc/capitalize(var/t as text)
return uppertext(copytext(t, 1, 2)) + copytext(t, 2)
+//Sorts Atoms by their name property.
+//Sorry for the copy+pasta, I doubt quick sorting will change anytime soon though.
+// Order 1 = Ascending / Order -1 = Descending
+/proc/sortAtom(var/list/atom/L, var/order = 1)
+ if(isnull(L) || L.len < 2)
+ return L
+ var/middle = L.len / 2 + 1
+ return mergeAtoms(sortAtom(L.Copy(0,middle)), sortAtom(L.Copy(middle)), order)
+
+/proc/mergeAtoms(var/list/atom/L, var/list/atom/R, var/order = 1)
+ var/Li=1
+ var/Ri=1
+ var/list/result = new()
+ while(Li <= L.len && Ri <= R.len)
+ var/atom/rL = L[Li]
+ var/atom/rR = R[Ri]
+ if(sorttext(rL.name, rR.name) == order)
+ result += L[Li++]
+ else
+ result += R[Ri++]
+
+ if(Li <= L.len)
+ return (result + L.Copy(Li, 0))
+ return (result + R.Copy(Ri, 0))
+
/proc/sortRecord(var/list/datum/data/record/L, var/field = "name", var/order = 1)
if(isnull(L) || L.len < 2)
return L
diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm
index 20188d3dd6..f125fc41e2 100644
--- a/code/game/machinery/computer/message.dm
+++ b/code/game/machinery/computer/message.dm
@@ -25,6 +25,8 @@
var/hacking = 0 // Is it being hacked into by the AI/Cyborg
var/emag = 0 // When it is emagged.
var/message = "System bootup complete. Please select an option." // The message that shows on the main menu.
+ var/auth = 0 // Are they authenticated?
+ var/optioncount = 7
// Custom Message Properties
var/customsender = "System Administrator"
var/obj/item/device/pda/customrecepient = null
@@ -32,26 +34,29 @@
var/custommessage = "This is a test, please ignore."
-/obj/machinery/computer/message_monitor/attackby(obj/item/weapon/O as obj, mob/user as mob)
+/obj/machinery/computer/message_monitor/attackby(obj/item/weapon/O as obj, mob/living/user as mob)
if(stat & (NOPOWER|BROKEN))
return
- if(!istype(user, /mob/living))
+ if(!istype(user))
return
if(istype(O,/obj/item/weapon/card/emag/))
// Will create sparks and print out the console's password. You will then have to wait a while for the console to be back online.
// It'll take more time if there's more characters in the password..
if(!emag)
- icon_state = hack_icon // An error screen I made in the computers.dmi
- emag = 1
- screen = 2
- spark_system.set_up(5, 0, src)
- src.spark_system.start()
- var/obj/item/weapon/paper/monitorkey/MK = new/obj/item/weapon/paper/monitorkey
- MK.loc = src.loc
- // Will help make emagging the console not so easy to get away with.
- MK.info += "
£%@%(*$%&(£&?*(%&£/{}"
- spawn(100*length(src.linkedServer.decryptkey)) UnmagConsole()
- message = rebootmsg
+ if(!isnull(src.linkedServer))
+ icon_state = hack_icon // An error screen I made in the computers.dmi
+ emag = 1
+ screen = 2
+ spark_system.set_up(5, 0, src)
+ src.spark_system.start()
+ var/obj/item/weapon/paper/monitorkey/MK = new/obj/item/weapon/paper/monitorkey
+ MK.loc = src.loc
+ // Will help make emagging the console not so easy to get away with.
+ MK.info += "
£%@%(*$%&(£&?*(%&£/{}"
+ spawn(100*length(src.linkedServer.decryptkey)) UnmagConsole()
+ message = rebootmsg
+ else
+ user << "A no server error appears on the screen."
if(isscrewdriver(O) && emag)
//Stops people from just unscrewing the monitor and putting it back to get the console working again.
user << "It is too hot to mess with!"
@@ -76,10 +81,10 @@
linkedServer = message_servers[1]
return
-/obj/machinery/computer/message_monitor/attack_hand(var/mob/user as mob)
+/obj/machinery/computer/message_monitor/attack_hand(var/mob/living/user as mob)
if(stat & (NOPOWER|BROKEN))
return
- if(!istype(user, /mob/living))
+ if(!istype(user))
return
//If the computer is being hacked or is emagged, display the reboot message.
if(hacking || emag)
@@ -87,39 +92,53 @@
var/dat = "
Message Monitor Console"
dat += "Message Monitor Console
"
dat += ""
+
+ if(auth)
+ dat += ""
+ else
+ dat += " \[Unauthenticated\] /"
+ dat += " Server Power: [src.linkedServer && src.linkedServer.active ? "\[On\]":"\[Off\]"]
"
+
+ if(hacking || emag)
+ screen = 2
+ else if(!auth || !linkedServer || (linkedServer.stat & (NOPOWER|BROKEN)))
+ if(!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN))) message = noserver
+ screen = 0
+
switch(screen)
//Main menu
if(0)
- if(hacking || emag)
- screen = 2
- return src.attack_hand(user)
// = TAB
- if(!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN)))
- dat += " ERROR: Server not found
"
+ var/i = 0
+ dat += " [++i]. Link To A Server"
+ if(auth)
+ if(!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN)))
+ dat += " ERROR: Server not found!
"
+ else
+ dat += " [++i]. View Message Logs
"
+ dat += " [++i]. View Request Console Logs "
+ dat += " [++i]. Clear Message Logs
"
+ dat += " [++i]. Clear Request Console Logs
"
+ dat += " [++i]. Set Custom Key
"
+ dat += " [++i]. Send Admin Message
"
else
- dat += " 1. Toggle Power: [src.linkedServer.active ? "\[On\]":"\[Off\]"]
"
- dat += " 2. Link To A Server
"
- dat += " KEY REQUIRED
"
- dat += " 3. View Message Logs
"
- dat += " 4. View Request Console Logs "
- dat += " 5. Clear Message Logs
"
- dat += " 6. Clear Request Console Logs
"
- dat += " 7. Set Custom Key
"
- dat += " 8. Send Admin Message
"
- //Malf/Traitor AIs can bruteforce into the system to gain the Key.
+ for(var/n = ++i; n <= optioncount; n++)
+ dat += " [n]. ---------------
"
if((istype(user, /mob/living/silicon/ai) || istype(user, /mob/living/silicon/robot)) && (user.mind.special_role && user.mind.original == user))
+ //Malf/Traitor AIs can bruteforce into the system to gain the Key.
dat += "*&@#. Bruteforce Key
"
+ else
+ dat += "
"
+
+ //Bottom message
+ if(!auth)
+ dat += "
Please authenticate with the server in order to show additional options."
+ else
+ dat += "
Reg, #514 forbids sending messages to a Head of Staff containing Erotic Rendering Properties."
//Message Logs
if(1)
- if(hacking || emag)
- screen = 2
- return src.attack_hand(user)
- if(!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN)))
- message = noserver
- screen = 0
- return src.attack_hand(user)
-
var/index = 0
//var/recipient = "Unspecified" //name of the person
//var/sender = "Unspecified" //name of the sender
@@ -136,9 +155,6 @@
dat += ""
//Hacking screen.
if(2)
- if(!hacking && !emag)
- screen = 0
- return src.attack_hand(user)
if(istype(user, /mob/living/silicon/ai) || istype(user, /mob/living/silicon/robot))
dat += "Brute-forcing for server key.
It will take 20 seconds for every character that the password has."
dat += "In the meantime, this console can reveal your true intentions if you let someone access it. Make sure no humans enter the room during that time."
@@ -182,9 +198,6 @@
//Fake messages
if(3)
- if(hacking || emag)
- screen = 2
- return src.attack_hand(user)
dat += "Back - Reset
"
dat += {"
@@ -203,13 +216,6 @@
//Request Console Logs
if(4)
- if(hacking || emag)
- screen = 2
- return src.attack_hand(user)
- if(!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN)))
- message = noserver
- screen = 0
- return src.attack_hand(user)
var/index = 0
/* data_rc_msg
@@ -245,8 +251,11 @@
return src.attack_hand(user)
/obj/machinery/computer/message_monitor/proc/BruteForce(mob/user as mob)
- var/currentKey = src.linkedServer.decryptkey
- user << "Brute-force completed! The key is '[currentKey]'."
+ if(isnull(linkedServer))
+ user << "Could not complete brute-force: Linked Server Disconnected!"
+ else
+ var/currentKey = src.linkedServer.decryptkey
+ user << "Brute-force completed! The key is '[currentKey]'."
src.hacking = 0
src.icon_state = normal_icon
src.screen = 0 // Return the screen back to normal
@@ -269,9 +278,22 @@
if(!istype(usr, /mob/living))
return
if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
+ //Authenticate
+ if (href_list["auth"])
+ if(auth)
+ auth = 0
+ screen = 0
+ else
+ var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null)
+ if(dkey && dkey != "")
+ if(src.linkedServer.decryptkey == dkey)
+ auth = 1
+ else
+ message = incorrectkey
+
//Turn the server on/off.
if (href_list["active"])
- linkedServer.active = !linkedServer.active
+ if(auth) linkedServer.active = !linkedServer.active
//Find a server
if (href_list["find"])
if(message_servers && message_servers.len > 1)
@@ -288,56 +310,39 @@
if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN)))
message = noserver
else
- var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null)
- if(dkey && dkey != "")
- if(src.linkedServer.decryptkey == dkey)
- src.screen = 1
- else
- message = incorrectkey
+ if(auth)
+ src.screen = 1
//Clears the logs - KEY REQUIRED
if (href_list["clear"])
if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN)))
message = noserver
else
- var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null)
- if(dkey && dkey != "")
- if(src.linkedServer.decryptkey == dkey)
- src.linkedServer.pda_msgs = list()
- message = "NOTICE: Logs cleared."
- else
- message = incorrectkey
+ if(auth)
+ src.linkedServer.pda_msgs = list()
+ message = "NOTICE: Logs cleared."
//Clears the request console logs - KEY REQUIRED
if (href_list["clearr"])
if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN)))
message = noserver
else
- var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null)
- if(dkey && dkey != "")
- if(src.linkedServer.decryptkey == dkey)
- src.linkedServer.rc_msgs = list()
- message = "NOTICE: Logs cleared."
- else
- message = incorrectkey
+ if(auth)
+ src.linkedServer.rc_msgs = list()
+ message = "NOTICE: Logs cleared."
//Change the password - KEY REQUIRED
if (href_list["pass"])
if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN)))
message = noserver
else
- var/dkey = trim(input(usr,"Please enter the decryption key:") as text|null)
- if(dkey && dkey != "")
- if(dkey == src.linkedServer.decryptkey)
- var/newkey = trim(input(usr,"Please enter the new key (3 - 16 characters max):"))
- if(length(newkey) <= 3)
- message = "NOTICE: Decryption key too short!"
- else if(length(newkey) > 16)
- message = "NOTICE: Decryption key too long!"
- else if(newkey && newkey != "")
- src.linkedServer.decryptkey = newkey
- message = "NOTICE: Decryption key set."
-
- else
- message = incorrectkey
+ if(auth)
+ var/newkey = trim(input(usr,"Please enter the new key (3 - 16 characters max):"))
+ if(length(newkey) <= 3)
+ message = "NOTICE: Decryption key too short!"
+ else if(length(newkey) > 16)
+ message = "NOTICE: Decryption key too long!"
+ else if(newkey && newkey != "")
+ src.linkedServer.decryptkey = newkey
+ message = "NOTICE: Decryption key set."
//Hack the Console to get the password
if (href_list["hack"])
if((istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot)) && (usr.mind.special_role && usr.mind.original == usr))
@@ -371,12 +376,8 @@
if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN)))
message = noserver
else
- var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null)
- if(dkey && dkey != "")
- if(src.linkedServer.decryptkey == dkey)
- src.screen = 3
- else
- message = incorrectkey
+ if(auth)
+ src.screen = 3
//Fake messaging selection - KEY REQUIRED
if (href_list["select"])
if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN)))
@@ -401,7 +402,7 @@
if(!P.owner || P.toff) continue
sendPDAs += P
if(PDAs && PDAs.len > 0)
- customrecepient = input(usr, "Select a PDA from the list.") as null|anything in sortList(sendPDAs)
+ customrecepient = input(usr, "Select a PDA from the list.") as null|anything in sortNames(sendPDAs)
else
customrecepient = null
@@ -469,12 +470,8 @@
if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN)))
message = noserver
else
- var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null)
- if(dkey && dkey != "")
- if(src.linkedServer.decryptkey == dkey)
- src.screen = 4
- else
- message = incorrectkey
+ if(auth)
+ src.screen = 4
//usr << href_list["select"]
diff --git a/code/game/objects/devices/PDA/PDA.dm b/code/game/objects/devices/PDA/PDA.dm
index f1937bbc4f..f046bb2c25 100644
--- a/code/game/objects/devices/PDA/PDA.dm
+++ b/code/game/objects/devices/PDA/PDA.dm
@@ -356,7 +356,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
var/count = 0
if (!toff)
- for (var/obj/item/device/pda/P in sortList(PDAs))
+ for (var/obj/item/device/pda/P in sortAtom(PDAs))
if (!P.owner||P.toff||P == src) continue
dat += "[P]"
if (istype(cartridge, /obj/item/weapon/cartridge/syndicate) && P.detonate)
diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm
index bb12bd39af..0793154c60 100644
--- a/code/modules/mob/living/silicon/pai/software.dm
+++ b/code/modules/mob/living/silicon/pai/software.dm
@@ -638,7 +638,7 @@
[(pda.silent) ? " \[Off\]" : " \[On\]"]
"}
dat += ""
if(!pda.toff)
- for (var/obj/item/device/pda/P in sortList(PDAs))
+ for (var/obj/item/device/pda/P in sortAtom(PDAs))
if (!P.owner||P.toff||P == src.pda) continue
dat += "- [P]"
dat += "
"
diff --git a/maps/tgstation.2.0.9.dmm b/maps/tgstation.2.0.9.dmm
index 9fa804369e..fc7d6f55bf 100644
--- a/maps/tgstation.2.0.9.dmm
+++ b/maps/tgstation.2.0.9.dmm
@@ -1381,7 +1381,7 @@
"aAC" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/obj/machinery/requests_console{department = "Tech storage"; pixel_x = -30},/turf/simulated/floor/plating,/area/storage/tech)
"aAD" = (/obj/machinery/light,/obj/machinery/light_switch{pixel_y = -23},/turf/simulated/floor/plating,/area/storage/tech)
"aAE" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = "90Curve"},/turf/simulated/floor/plating,/area/storage/tech)
-"aAF" = (/obj/machinery/light,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0; tag = "Streight"},/turf/simulated/floor/plating,/area/storage/tech)
+"aAF" = (/obj/machinery/light,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0; tag = "Streight"},/obj/item/weapon/circuitboard/message_monitor{step_x = 3; step_y = 29},/turf/simulated/floor/plating,/area/storage/tech)
"aAG" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = "90Curve"},/turf/simulated/floor/plating,/area/storage/tech)
"aAH" = (/obj/machinery/atmospherics/unary/vent_pump{on = 1},/obj/machinery/camera{c_tag = "Tech Storage South"; dir = 1; network = "SS13"},/turf/simulated/floor/plating,/area/storage/tech)
"aAI" = (/obj/machinery/camera{c_tag = "Secure Construction Area"; dir = 4; network = "SS13"},/obj/item/weapon/crowbar,/obj/item/weapon/extinguisher,/obj/machinery/atmospherics/pipe/simple/supply/hidden,/obj/structure/table/reinforced,/turf/simulated/floor/plating,/area/teleporter/gateway)