diff --git a/code/defines/procs/helpers.dm b/code/defines/procs/helpers.dm
index 6378c4d4582e..6c019395f00e 100644
--- a/code/defines/procs/helpers.dm
+++ b/code/defines/procs/helpers.dm
@@ -867,11 +867,21 @@ Turf and target are seperate in case you want to teleport some distance from a t
if (!the_key)
text += "*no client*"
else
+ var/linked = 1
if (include_link && !isnull(the_mob))
if (istext(include_link))
- text += ""
+ text += ""
else
- text += ""
+ if(ismob(include_link))
+ var/mob/MM = include_link
+ if(MM.client)
+ text += ""
+ else
+ linked = 0
+ else if (istype(include_link, /client))
+ text += ""
+ else
+ linked = 0
if (the_client && the_client.holder && the_client.stealth && !include_name)
text += "Administrator"
@@ -879,7 +889,10 @@ Turf and target are seperate in case you want to teleport some distance from a t
text += "[the_key]"
if (!isnull(include_link) && !isnull(the_mob))
- text += ""
+ if(linked)
+ text += ""
+ else
+ text += " (DC)"
if (include_name && !isnull(the_mob))
if (the_mob.real_name)
diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm
index 75098de01d07..ed389c44ebef 100644
--- a/code/modules/admin/verbs/adminsay.dm
+++ b/code/modules/admin/verbs/adminsay.dm
@@ -25,5 +25,5 @@
if (src.holder.rank == "Admin Observer")
M << "ADMIN: [key_name(usr, M)]: [msg]"
else
- M << "ADMIN: [key_name(usr, M)]X: [msg]"
+ M << "ADMIN: [key_name(usr, M)] (JMP): [msg]"
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index d157614f8160..ee6df8120bc8 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -80,6 +80,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(NewLoc)
loc = NewLoc
return
+ loc = get_turf(src) //Get out of closets and such as a ghost
if((direct & NORTH) && y < world.maxy)
y++
if((direct & SOUTH) && y > 1)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index de04d7dc74ce..89e63239fa42 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -604,42 +604,62 @@
src:cameraFollow = null
-/mob/Topic(href, href_list)
- if(href_list["mach_close"])
- var/t1 = text("window=[href_list["mach_close"]]")
- machine = null
- src << browse(null, t1)
+/client/Topic(href, href_list)
+ if(href_list["priv_msg"]) //All PM links have clients as their SRC-s (So that you always PM the same client even if they change mob (ghost, observe, etc.)), but PM code is in mob/topic() So this redirects the call.
+ if(mob)
+ mob.Topic(href, href_list)
+ else
+ ..()
+/mob/Topic(href, href_list)
if(href_list["priv_msg"])
- var/mob/M = locate(href_list["priv_msg"])
- if(M)
+ var/client/C = locate(href_list["priv_msg"])
+
+ if(ismob(C)) //Old stuff can pass in mobs instead of clients
+ var/mob/M = C
+ C = M.client
+
+ if(C)
if(src.client && client.muted_complete)
src << "You are muted have a nice day"
return
- if (!ismob(M))
+ if (!istype(C,/client))
+ src << "\red not a client."
return
- //This should have a check to prevent the player to player chat but I am too tired atm to add it.
- var/t = input("Message:", text("Private message to [M.key]")) as text|null
- if (!t || !usr || !M)
- return
- if (usr.client && usr.client.holder)
- M << "\red Admin PM from-[key_name(usr, M, 0)]: [t]"
- usr << "\blue Admin PM to-[key_name(M, usr, 1)]: [t]"
- else
- if (M)
- if (M.client && M.client.holder)
- M << "\blue Reply PM from-[key_name(usr, M, 1)]: [t]"
- else
- M << "\red Reply PM from-[key_name(usr, M, 0)]: [t]"
- usr << "\blue Reply PM to-[key_name(M, usr, 0)]: [t]"
- log_admin("PM: [key_name(usr)]->[key_name(M)] : [t]")
+ if ( !( src.client.holder || C.holder ) ) //neither of the two is an admin.
+ src.client << "\red Admin-player or player-admin conversation only!"
+ return.
+
+ var/t = input("Message:", text("Private message to [C.key]")) as text|null
+ if (!t || !usr || !C)
+ return
+ if (usr.client && usr.client.holder) //Admin is messaging a player
+ C << "\red -- Administrator private message --"
+ C << "[key_name(usr.client, C, 0)] [t]"
+ C << "Click on the administrator's name to reply."
+ usr << "\blue Admin PM to [key_name(C, usr.client, 1)]: [t]"
+ else
+ if (C)
+ if (C.holder)
+ C << "\blue Reply PM from [key_name(usr.client, C, 1)]: [t]"
+ else
+ C << "\red Reply PM from [key_name(usr.client, C, 0)]: [t]"
+ usr.client << "\blue Reply PM to [key_name(C, usr.client, 0)]: [t]"
+
+ log_admin("PM: [usr.client.key]->[C.key] : [t]")
//we don't use message_admins here because the sender/receiver might get it too
for (var/mob/K in world)
if(K && usr)
- if(K.client && K.client.holder && K.key != usr.key && K.key != M.key)
- K << "PM: [key_name(usr, K)]->[key_name(M, K)]: \blue [t]"
+ if(K.client && K.client.holder && K.key != usr.key && K.key != C.key)
+ K << "PM: [key_name(usr.client, K.client)]->[key_name(C, K.client)]: \blue [t]"
+ else
+ client << "\red Client disconnected"
+ if(href_list["mach_close"])
+ var/t1 = text("window=[href_list["mach_close"]]")
+ machine = null
+ src << browse(null, t1)
..()
return
diff --git a/tgstation.dme b/tgstation.dme
index 3edf3f543d0c..d171f4649aad 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -163,6 +163,7 @@
#define FILE_DIR "icons/vending_icons"
#define FILE_DIR "interface"
#define FILE_DIR "maps"
+#define FILE_DIR "maps/backup"
#define FILE_DIR "sound"
#define FILE_DIR "sound/ambience"
#define FILE_DIR "sound/announcer"