diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index 03265398796..8a81f7992ca 100644
--- a/code/__HELPERS/_logging.dm
+++ b/code/__HELPERS/_logging.dm
@@ -70,4 +70,8 @@
/proc/log_pda(text)
if (config.log_pda)
- diary << "\[[time_stamp()]]PDA: [text]"
\ No newline at end of file
+ diary << "\[[time_stamp()]]PDA: [text]"
+
+/proc/log_chat(text)
+ if (config.log_pda) //reusing this for now, can change if needed
+ diary << "\[[time_stamp()]]CHAT: [text]"
\ No newline at end of file
diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm
index 04226b689d2..0790775530f 100644
--- a/code/game/machinery/computer/message.dm
+++ b/code/game/machinery/computer/message.dm
@@ -114,8 +114,10 @@
else
dat += "
[++i]. View Message Logs
"
dat += " [++i]. View Request Console Logs "
+ dat += " [++i]. View Chatroom Logs "
dat += " [++i]. Clear Message Logs
"
dat += " [++i]. Clear Request Console Logs
"
+ dat += " [++i]. Clear Chatroom Logs
"
dat += " [++i]. Set Custom Key
"
dat += " [++i]. Send Admin Message
"
else
@@ -236,6 +238,24 @@
[rc.rec_dpt] | [rc.message] | [rc.stamp] | [rc.id_auth] | [rc.priority] | "}
dat += ""
+ //Chatroom Logs
+ if(5)
+
+ var/index = 0
+ //var/sender = "Anon"
+ //var/channel = "ss13"
+ //var/message = "Blank"
+ dat += "Back - Refresh
"
+ dat += "| X | Channel | Nick | Message |
"
+ for(var/datum/data_chat_msg/msg in src.linkedServer.chat_msgs)
+ index++
+ if(index > 3000)
+ break
+ // Del - Channel - Sender - Message
+ // X - #ss13 - bigdik - hi asl
+ dat += "| X | [msg.channel] | [msg.sender] | [msg.message] |
"
+ dat += "
"
+
message = defaultmsg
//user << browse(dat, "window=message;size=700x700")
//onclose(user, "message")
@@ -321,6 +341,14 @@
if(auth)
src.linkedServer.rc_msgs = list()
message = "NOTICE: Logs cleared."
+ //Clears the chatroom logs - KEY REQUIRED
+ if (href_list["clearc"])
+ if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN)))
+ message = noserver
+ else
+ if(auth)
+ src.linkedServer.chat_msgs = list()
+ message = "NOTICE: Logs cleared."
//Change the password - KEY REQUIRED
if (href_list["pass"])
if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN)))
@@ -464,6 +492,13 @@
else
if(auth)
src.screen = 4
+ //Chatroom Logs - KEY REQUIRED
+ if(href_list["viewc"])
+ if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN)))
+ message = noserver
+ else
+ if(auth)
+ src.screen = 5
//usr << href_list["select"]
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 8542b19e0d5..ac5181f751f 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -44,6 +44,12 @@ var/global/list/obj/item/device/pda/PDAs = list()
var/obj/item/device/paicard/pai = null // A slot for a personal AI device
+ var/chat_channel = "#ss13" //name of our current NTRC channel
+ var/nick = "" //our NTRC nick
+ var/list/ntrclog = list() //NTRC message log
+
+ var/noreturn = 0 //whether the PDA can use the Return button, used for the aiPDA chatroom
+
/obj/item/device/pda/medical
default_cartridge = /obj/item/weapon/cartridge/medical
icon_state = "pda-medical"
@@ -186,13 +192,15 @@ var/global/list/obj/item/device/pda/PDAs = list()
/obj/item/device/pda/ai
icon_state = "NONE"
ttone = "data"
+ mode = 5
+ noreturn = 1
detonate = 0
/obj/item/device/pda/ai/attack_self(mob/user as mob)
if ((honkamt > 0) && (prob(60)))//For clown virus.
honkamt--
playsound(loc, 'sound/items/bikehorn.ogg', 30, 1)
- return
+ ..()
/obj/item/device/pda/ai/pai
ttone = "assist"
@@ -257,7 +265,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
if ((!isnull(cartridge)) && (mode == 0))
dat += " |
Eject [cartridge]"
- if (mode)
+ if (mode && !noreturn)
dat += " |
Return"
dat += " |
Refresh"
@@ -283,7 +291,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
dat += ""
dat += "
Notekeeper "
dat += "
Messenger "
- //dat += "
Nanotrasen Relay Chat "
+ dat += "
Nanotrasen Relay Chat "
if (cartridge)
if (cartridge.access_clown)
@@ -433,16 +441,18 @@ var/global/list/obj/item/device/pda/PDAs = list()
dat += "
"
if (5)
- dat += "
Nanotrasen Relay Chat
"
-
- dat += "
Detected Channels
: - "
- for(var/datum/chatroom/C in chatrooms)
- dat += "#[html_encode(lowertext(C.name))]"
- if(C.password != "")
- dat += "
"
- dat += " "
-
+ if(!nick) //first time join
+ nick = copytext(sanitize(owner), 1, 9)
+ var/datum/chatroom/C = chatchannels[chat_channel]
+ C.parse_msg(src, nick, "/join [chat_channel]")
+ dat += "
SS13 Nanotrasen Relay Chat Network
"
+ dat += "[nick] | "
+ dat += "[chat_channel] | "
+ dat += "Write message | "
+ dat += "Help
"
+ if(chat_channel)
+ dat += ntrclog[chat_channel]
else//Else it links to the cart menu proc. Although, it really uses menu hub 4--menu 4 doesn't really exist as it simply redirects to hub.
dat += cart
@@ -510,7 +520,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
mode = 3
if("4")//Redirects to hub
mode = 0
- if("chatroom") // chatroom hub
+ if("5")//Chatroom
mode = 5
@@ -615,6 +625,53 @@ var/global/list/obj/item/device/pda/PDAs = list()
return
+//CHATROOM FUNCTIONS====================================
+
+ if("Set Nick")
+ var/t = stripped_input(U, "Please enter nickname", name, null) as text
+ nick = copytext(sanitize(t), 1, 9)
+
+ if("Set Channel")
+ var/t = stripped_input(U, "Please enter channel", name, (chat_channel)) as text
+
+ if(t)
+ ntrclog[chat_channel] = "
" + ntrclog[chat_channel]
+ var/datum/chatroom/C = chatchannels[chat_channel]
+ if(!findtext(t,"#",1,2))
+ t = "#" + t
+ chat_channel = t
+ C.parse_msg(src, nick, "/join [chat_channel]")
+
+ if("NTRC Message")
+ var/t = msg_input(U) as text
+ var/datum/chatroom/C = chatchannels[chat_channel]
+ if(C)
+ var/lt = text2list(t, " ")
+ if(lt[1] == "/join")
+ if(!findtext(lt[2],"#",1,2))
+ lt[2] = "#" + lt[2]
+ var/ret = C.parse_msg(src,nick,t)
+ if(findtextEx(ret,"ERR_",1,5))
+ ntrclog[chat_channel] = "[ret]
" + ntrclog[chat_channel]
+ else
+ if(ret == 0)
+ ntrclog[chat_channel] = "Failure
" + ntrclog[chat_channel]
+ else
+ if(lt[1] == "/join")
+ chat_channel = lt[2]
+
+ if("NTRC Help")
+ var/helptext = "NTRC reference:
"
+ helptext += "General commands
"
+ helptext += "/join #channel
/part
/log amountoflines
/who
/topic
/register
"
+ helptext += "Moderation commands
"
+ helptext += "/ban targetnick
/unban targetnick
/kick targetnick
/mute targetnick
"
+ helptext += "Management commands
"
+ helptext += "/topic topictext
/op targetnick
/deop targetnick
/delchannel"
+ usr << browse(helptext, "window=ntrchelp;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0")
+
+
+
//SYNDICATE FUNCTIONS===================================
if("Toggle Door")
@@ -675,8 +732,9 @@ var/global/list/obj/item/device/pda/PDAs = list()
else//Cartridge menu linking
mode = text2num(href_list["choice"])
- cartridge.mode = mode
- cartridge.unlock()
+ if(cartridge)
+ cartridge.mode = mode
+ cartridge.unlock()
else//If not in range, can't interact or not using the pda.
U.unset_machine()
U << browse(null, "window=pda")
@@ -708,40 +766,39 @@ var/global/list/obj/item/device/pda/PDAs = list()
id.loc = get_turf(src)
id = null
-/obj/item/device/pda/proc/create_message(var/mob/living/U = usr, var/obj/item/device/pda/P)
-
+/obj/item/device/pda/proc/msg_input(var/mob/living/U = usr)
var/t = input(U, "Please enter message", name, null) as text
t = copytext(sanitize(t), 1, MAX_MESSAGE_LEN)
- if (!t || !istype(P))
+ if (!t || toff)
return
if (!in_range(src, U) && loc != U)
return
-
- if (isnull(P)||P.toff || toff)
+ if(!can_use(U))
return
+ if(emped)
+ t = Gibberish(t, 100)
+ return t
+
+/obj/item/device/pda/proc/create_message(var/mob/living/U = usr, var/obj/item/device/pda/P)
+
+ var/t = msg_input(U)
if (last_text && world.time < last_text + 5)
return
- if(!can_use(U))
+ if (isnull(P) || P.toff || !istype(P))
return
last_text = world.time
- // check if telecomms I/O route 1459 is stable
- //var/telecomms_intact = telecomms_process(P.owner, owner, t)
var/obj/machinery/message_server/useMS = null
if(message_servers)
for (var/obj/machinery/message_server/MS in message_servers)
//PDAs are now dependant on the Message Server.
if(MS.active)
useMS = MS
- break
var/datum/signal/signal = src.telecomms_process()
- if(emped)
- t = Gibberish(t, 100)
-
var/useTC = 0
if(signal)
if(signal.data["done"])
@@ -782,7 +839,6 @@ var/global/list/obj/item/device/pda/PDAs = list()
else
U << "ERROR: Server isn't responding."
-
/obj/item/device/pda/verb/verb_remove_id()
set category = "Object"
set name = "Remove id"
@@ -1045,6 +1101,18 @@ var/global/list/obj/item/device/pda/PDAs = list()
else
usr << "You do not have a PDA. You should make an issue report about this."
+/mob/living/silicon/ai/verb/cmd_use_chatroom()
+ set category = "AI Commands"
+ set name = "PDA - Chatrooms"
+ if(usr.stat == 2)
+ usr << "You can't do that because you are dead!"
+ return
+ if(!isnull(aiPDA))
+ aiPDA.mode = 5
+ aiPDA.attack_self(src)
+ else
+ usr << "You do not have a PDA. You should make an issue report about this."
+
/mob/living/silicon/ai/proc/cmd_show_message_log(mob/user as mob)
if(user.stat == 2)
user << "You can't do that because you are dead!"
@@ -1085,6 +1153,17 @@ var/global/list/obj/item/device/pda/PDAs = list()
spawn(200 * severity)
emped -= 1
+//ntrc handler proc
+/obj/item/device/pda/proc/msg_chat(channel as text, sender as text, message as text)
+ var/msg = "[strip_html_properly(sender)]| [strip_html_properly(message)]
"
+ if(!channel)
+ for(var/C in ntrclog)
+ ntrclog[C] = msg + ntrclog[C]
+ else
+ ntrclog[channel] = msg + ntrclog[channel]
+ if (!silent)
+ loc.audible_message("\icon[src] *[ttone]*", null, 3)
+
/proc/get_viewable_pdas()
. = list()
// Returns a list of PDAs which can be viewed from another PDA/message monitor.
diff --git a/code/game/objects/items/devices/PDA/chatroom.dm b/code/game/objects/items/devices/PDA/chatroom.dm
index 007d3892c20..1ba6a4c5813 100644
--- a/code/game/objects/items/devices/PDA/chatroom.dm
+++ b/code/game/objects/items/devices/PDA/chatroom.dm
@@ -1,16 +1,212 @@
-var/list/chatrooms = list()
+var/datum/chatroom/default_ntrc_chatroom = new("")
+var/list/chatchannels = list(default_ntrc_chatroom.name = default_ntrc_chatroom)
+
+//procs that can be used directly:
+//channel.parse_msg
/datum/chatroom
- var/name = "Generic Chatroom"
- var/list/logged_in = list()
+ var/name = "#ss13"
+ var/topic = "Welcome to the best NTRC channel in this sector of the galaxy!" // topic message for the chatroom
+ var/list/operators = list() // chat operators
var/list/logs = list() // chat logs
+ var/list/muted = list() // muted users
var/list/banned = list() // banned users
- var/list/whitelist = list() // whitelisted users
- var/list/muted = list()
- var/topic = "" // topic message for the chatroom
- var/password = "" // blank for no password.
- var/operator = "" // name of the operator
+ var/list/auth = list() // authenticated clients
+ var/list/users = list() // current users
+ var/datum/events/events = new ()
+ var/list/datum/event/evlist = list()
-/datum/chatroom/proc/attempt_connect(var/obj/item/device/pda/device, var/obj/password)
- if(!device)
- return
+//parse_msg() is the exposed interface chat
+//clients should interact with parse_msg() and parse_msg() only
+
+/datum/chatroom/proc/parse_msg(client,nick,message)
+ var/obj/machinery/message_server/MS = check_server(client)
+ if(!MS)
+ return "ERR_TCOM"
+
+ if(!nick || length(nick) > 8)
+ return "ERR_NICK"
+
+ MS.send_chat_message(nick,name,message)
+
+ if(findtext(message,"/",1,2))
+ return handle_command(client,nick,copytext(message,2))
+
+ else
+ return send_message(client,nick,message)
+
+//the following are for internal use only
+
+/datum/chatroom/proc/check_server(client)
+ var/atom/C = client
+ var/turf/CT = get_turf(C)
+ if(message_servers)
+ for (var/obj/machinery/message_server/MS in message_servers)
+ var/turf/T = get_turf(MS)
+ if(MS.active && (T.z == CT.z))
+ return MS
+ return 0
+
+/datum/chatroom/proc/handle_command(client,nick,command) //command parser
+ var/list/cmd=text2list(command, " ")
+
+ if(!get_auth(client,nick))
+ return "ERR_AUTH"
+
+ switch(cmd[1]) //argument-less commmands
+ if("topic")
+ if(cmd.len == 1)
+ return get_topic(client)
+ else
+ return set_topic(client,nick,cmd[2])
+ if("part")
+ return channel_part(client,nick)
+ if("delchannel")
+ return delete_channel(client,nick)
+ if("who")
+ return get_who(client, nick)
+ if("register")
+ return register_auth(client,nick)
+
+ if(cmd.len == 1)
+ return "ERR_ARGS"
+
+ switch(cmd[1]) //commands with 1 arg
+ if("join")
+ return channel_join(client,nick,cmd[2])
+ if("log")
+ return get_log(client,nick,cmd[2])
+ if("op")
+ return make_op(client,nick,cmd[2])
+ if("deop")
+ return deop(client,nick,cmd[2])
+ if("ban")
+ return ban(client,nick,cmd[2])
+ if("unban")
+ return unban(client,nick,cmd[2])
+ if("kick")
+ return kick(client,nick,cmd[2])
+ if("mute")
+ return mute_nick(client,nick,cmd[2])
+
+ return "ERR_WCMD"
+
+/datum/chatroom/proc/send_message(client,nick,message) //standard message
+ if(nick in muted)
+ return "ERR_MUTE"
+ if(!message)
+ return "ERR_BLNK"
+ logs += "[strip_html_properly(nick)]> [strip_html_properly(message)]"
+ log_chat("[usr]/([usr.ckey]) as [nick] sent to [name]: [message]")
+ events.fireEvent("msg_chat",name,nick,message)
+ return 1
+
+/datum/chatroom/proc/get_auth(client,nick) //check auth
+ if((!(nick in auth)) || (auth[nick] == client))
+ return 1
+ return 0
+
+//chat commands go here
+/datum/chatroom/proc/register_auth(client,nick) //register
+ if(!get_auth(client,nick))
+ return 0
+ auth[nick] = client
+ return 1
+
+/datum/chatroom/proc/delete_channel(client,nick) //delchannel
+ if(nick in operators)
+ for(var/event in events.events)
+ events.clearEvent("msg_chat",event)
+ qdel(src)
+ return 1
+ return 0
+
+/datum/chatroom/proc/channel_join(client,nick,channel) //join
+ if(!findtext(channel,"#",1,2))
+ channel = "#" + channel
+ if(channel == name)
+ if((nick in banned) || (nick in users))
+ return 0
+ users += nick
+ get_topic(client,nick)
+ evlist[nick] = events.addEvent("msg_chat",client,"msg_chat")
+ return 1
+ else
+ if(!(channel in chatchannels))
+ var/ret = new_channel(client,nick,channel)
+ if(!ret)
+ return 0
+ channel_part(client,nick)
+ var/datum/chatroom/C = chatchannels[channel]
+ return C.parse_msg(client,nick,"/join [channel]")
+
+/datum/chatroom/proc/channel_part(client,nick) //part
+ users -= nick
+ events.clearEvent("msg_chat",evlist[nick])
+ return 1
+
+/datum/chatroom/proc/make_op(client,nick,target) //op
+ if(nick in operators)
+ operators += target
+ return 1
+ return 0
+
+/datum/chatroom/proc/deop(client,nick,target) //deop
+ if(nick in operators)
+ operators -= target
+ return 1
+ return 0
+
+/datum/chatroom/proc/ban(client,nick,target) //ban
+ if(nick in operators)
+ banned += target
+ return 1
+ return 0
+
+/datum/chatroom/proc/unban(client,nick,target) //unban
+ if(nick in operators)
+ banned -= target
+ return 1
+ return 0
+
+/datum/chatroom/proc/kick(client,nick,target) //kick
+ if(nick in operators)
+ channel_part(null,nick)
+ return 1
+ return 0
+
+/datum/chatroom/proc/set_topic(client,nick,newtopic) //topic
+ if(nick in operators)
+ topic = strip_html_properly(newtopic)
+ return 1
+ return 0
+
+/datum/chatroom/proc/get_topic(client,nick) //topic
+ call(client,"msg_chat")(name,"NTbot","TOPIC: [topic]")
+ return 1
+
+/datum/chatroom/proc/get_who(client,nick) //who
+ for(var/user in users)
+ call(client,"msg_chat")(name,"NTbot","WHO: [user]")
+ return 1
+
+/datum/chatroom/proc/get_log(client,nick,lines) //log
+ for(var/i=0;iDigital Messenger
"
+ if(s == "chatroom client")
+ dat += "Chatroom Client
"
if(s == "crew manifest")
dat += "Crew Manifest
"
if(s == "medical records")
@@ -631,4 +636,9 @@
dat += "
"
dat += "
"
dat += "Messages:
[pda.tnote]"
- return dat
\ No newline at end of file
+ return dat
+
+/mob/living/silicon/pai/proc/chatroom()
+
+ pda.mode = 5
+ pda.attack_self()
\ No newline at end of file
diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm
index 9bcc805b2c6..7ee1436f18c 100644
--- a/code/modules/research/message_server.dm
+++ b/code/modules/research/message_server.dm
@@ -1,5 +1,18 @@
var/global/list/obj/machinery/message_server/message_servers = list()
+/datum/data_chat_msg
+ var/sender = "Anon"
+ var/channel = "ss13"
+ var/message = "Blank"
+
+/datum/data_chat_msg/New(var/param_sen = "", var/param_chan = "", var/param_msg = "")
+ if(param_sen)
+ sender = param_sen
+ if(param_chan)
+ channel = param_chan
+ if(param_msg)
+ message = param_msg
+
/datum/data_pda_msg
var/recipient = "Unspecified" //name of the person
var/sender = "Unspecified" //name of the sender
@@ -54,6 +67,7 @@ var/global/list/obj/machinery/message_server/message_servers = list()
idle_power_usage = 10
active_power_usage = 100
+ var/list/datum/data_chat_msg/chat_msgs = list()
var/list/datum/data_pda_msg/pda_msgs = list()
var/list/datum/data_rc_msg/rc_msgs = list()
var/active = 1
@@ -88,6 +102,9 @@ var/global/list/obj/machinery/message_server/message_servers = list()
update_icon()
return
+/obj/machinery/message_server/proc/send_chat_message(var/sender = "", var/channel = "", var/message = "")
+ chat_msgs += new/datum/data_chat_msg(sender,channel,message)
+
/obj/machinery/message_server/proc/send_pda_message(var/recipient = "",var/sender = "",var/message = "")
pda_msgs += new/datum/data_pda_msg(recipient,sender,message)
@@ -240,10 +257,13 @@ var/obj/machinery/blackbox_recorder/blackbox
/obj/machinery/blackbox_recorder/proc/round_end_data_gathering()
+ var/chat_msg_amt = 0
var/pda_msg_amt = 0
var/rc_msg_amt = 0
for (var/obj/machinery/message_server/MS in world)
+ if (MS.chat_msgs.len > chat_msg_amt)
+ chat_msg_amt = MS.chat_msgs.len
if (MS.pda_msgs.len > pda_msg_amt)
pda_msg_amt = MS.pda_msgs.len
if (MS.rc_msgs.len > rc_msg_amt)
@@ -262,6 +282,7 @@ var/obj/machinery/blackbox_recorder/blackbox
feedback_add_details("radio_usage","SRV-[msg_service.len]")
feedback_add_details("radio_usage","CAR-[msg_cargo.len]")
feedback_add_details("radio_usage","OTH-[messages.len]")
+ feedback_add_details("radio_usage","CHA-[chat_msg_amt]")
feedback_add_details("radio_usage","PDA-[pda_msg_amt]")
feedback_add_details("radio_usage","RC-[rc_msg_amt]")
@@ -346,4 +367,4 @@ proc/feedback_add_details(var/variable,var/details)
if (!FV) return
- FV.add_details(details)
\ No newline at end of file
+ FV.add_details(details)
diff --git a/html/changelogs/Tkdrg-chatrooms.yml b/html/changelogs/Tkdrg-chatrooms.yml
new file mode 100644
index 00000000000..207891b2727
--- /dev/null
+++ b/html/changelogs/Tkdrg-chatrooms.yml
@@ -0,0 +1,4 @@
+author: Tkdrg
+delete-after: true
+changes:
+ - rscadd: "Cutting-edge research in a secret Nanotransen lab has shed light into a revolutionary form of communication technology known as 'chat'. The Personal Data Assistants of Space Station 13 have been deployed with an experimental module implementing this system, dubbed 'Nanotransen Relay Chat'."