New chat client / messenger (#10654)

This commit is contained in:
Karolis
2021-01-11 10:04:16 +01:00
committed by GitHub
parent f99e4a29c0
commit 339c531ad7
31 changed files with 858 additions and 846 deletions
@@ -2,9 +2,9 @@ var/global/ntnrc_uid = 0
/datum/ntnet_conversation
var/id
var/title = "Untitled Conversation"
var/datum/computer_file/program/chatclient/operator // "Administrator" of this channel. Creator starts as channel's operator,
var/datum/ntnet_user/operator // "Administrator" of this channel. Creator starts as channel's operator,
var/list/messages = list()
var/list/clients = list()
var/list/users = list()
var/direct = FALSE
var/password
@@ -19,25 +19,32 @@ var/global/ntnrc_uid = 0
operator = "NanoTrasen Information Technology Division" // assign a fake operator
..()
/datum/ntnet_conversation/proc/add_message(var/message, var/username, var/mob/user, var/reply_ref)
log_ntirc("[user.client.ckey]/([username]) : [message]", ckey=key_name(user), conversation=title)
/datum/ntnet_conversation/proc/process_message(var/datum/ntnet_message/message, var/update_ui = TRUE)
var/admin_log = message.format_admin_log()
if (admin_log)
log_ntirc("[message.user.client.ckey]/([message.nuser.username]): [admin_log]", ckey=key_name(message.user), conversation=title)
for(var/datum/computer_file/program/chatclient/C in clients)
if(C.program_state > PROGRAM_STATE_KILLED)
C.computer.output_message("<b>([get_title(C)]) <i>[username]</i>:</b> [message] (<a href='byond://?src=\ref[C];Reply=\ref[src]'>Reply</a>)", 0)
if(!C.silent && C.username != username && C.program_state == PROGRAM_STATE_BACKGROUND)
playsound(C.computer, 'sound/machines/twobeep.ogg', 50, 1)
C.computer.output_message("*[C.ringtone]*")
else if(C.username == username)
ntnet_global.add_log(message, C.computer.network_card, TRUE)
for(var/datum/ntnet_user/U in users)
for(var/datum/computer_file/program/chat_client/Cl in U.clients)
var/notification_text = message.format_chat_notification(src, Cl)
if(notification_text && Cl.can_receive_notification(message.client))
Cl.computer.output_message(notification_text, 0)
if(message.play_sound)
Cl.play_notification_sound(message.client)
message = "[worldtime2text()] [username]: [message]"
messages.Add(message)
trim_message_list()
var/ntnet_log = message.format_ntnet_log(src)
if(ntnet_log)
ntnet_global.add_log(ntnet_log, message.client.computer.network_card, TRUE)
/datum/ntnet_conversation/proc/add_status_message(var/message)
messages.Add("[worldtime2text()] -!- [message]")
trim_message_list()
var/chat_log = message.format_chat_log(src)
if(chat_log)
messages.Add(chat_log)
trim_message_list()
if(update_ui)
for(var/datum/ntnet_user/U in users)
for(var/datum/computer_file/program/chat_client/Cl)
SSvueui.check_uis_for_change(Cl)
/datum/ntnet_conversation/proc/trim_message_list()
if(messages.len <= 50)
@@ -47,89 +54,119 @@ var/global/ntnrc_uid = 0
if(messages.len <= 50)
return
/datum/ntnet_conversation/proc/add_client(var/datum/computer_file/program/chatclient/C)
if(!istype(C))
return
if (C in clients)
return
clients.Add(C)
// No operator, so we assume the channel was empty. Assign this user as operator.
if(!operator)
changeop(C)
for(var/datum/computer_file/program/chatclient/CC in clients)
if(CC.program_state > PROGRAM_STATE_KILLED && CC != C)
if(!direct)
CC.computer.output_message(FONT_SMALL("<b>([get_title(CC)]) <i>[C.username]</i> has entered the chat.</b>"), 0)
/// EXTERNAL PROCs
/datum/ntnet_conversation/proc/begin_direct(var/datum/computer_file/program/chatclient/CA, var/datum/computer_file/program/chatclient/CB)
if(!istype(CA) || !istype(CB))
return
direct = TRUE
clients.Add(CA)
clients.Add(CB)
add_status_message("[CA.username] has opened direct conversation.")
if(CB.program_state > PROGRAM_STATE_KILLED)
CB.computer.output_message(FONT_SMALL("<b>([get_title(CB)]) <i>[CA.username]</i> has opened direct conversation with you.</b>"), 0)
/datum/ntnet_conversation/proc/remove_client(var/datum/computer_file/program/chatclient/C)
if(!istype(C) || !(C in clients))
return
clients.Remove(C)
// Channel operator left, pick new operator
if(C == operator)
operator = null
if(clients.len)
var/datum/computer_file/program/chatclient/newop = pick(clients)
changeop(newop)
for(var/datum/computer_file/program/chatclient/CC in clients)
if(CC.program_state > PROGRAM_STATE_KILLED && CC != C)
CC.computer.output_message(FONT_SMALL("<b>([get_title(CC)]) <i>[C.username]</i> has left the chat.</b>"), 0)
/datum/ntnet_conversation/proc/changeop(var/datum/computer_file/program/chatclient/newop)
if(istype(newop))
operator = newop
add_status_message("Channel operator status transferred to [newop.username].")
/datum/ntnet_conversation/proc/change_title(var/newtitle, var/datum/computer_file/program/chatclient/client)
if(operator != client)
return 0 // Not Authorised
add_status_message("[client.username] has changed channel title from [get_title(client)] to [newtitle]")
for(var/datum/computer_file/program/chatclient/C in clients)
if(C.program_state > PROGRAM_STATE_KILLED && C != client)
C.computer.output_message(FONT_SMALL("([get_title(C)]) <i>[client.username]</i> has changed the channel title to <b>[newtitle]</b>."), 0)
title = newtitle
/datum/ntnet_conversation/proc/get_title(var/datum/computer_file/program/chatclient/cl = null)
/datum/ntnet_conversation/proc/get_title(var/datum/computer_file/program/chat_client/cl = null)
if(direct)
var/names = list()
for(var/datum/computer_file/program/chatclient/C in clients)
names += C.username
if(cl)
names -= cl.username
for(var/datum/ntnet_user/U in users)
names += U.username
if(istype(cl) && istype(cl.my_user))
names -= cl.my_user.username
return "\[DM] [english_list(names)]"
else
return title
/datum/ntnet_conversation/proc/get_dead_title()
if(direct)
var/names = list()
for(var/datum/computer_file/program/chatclient/C in clients)
names += C.username
return "\[DM] [english_list(names)]"
else
return title
/datum/ntnet_conversation/proc/can_see(var/datum/computer_file/program/chatclient/cl)
if(cl in clients)
return TRUE
/datum/ntnet_conversation/proc/can_see(var/datum/computer_file/program/chat_client/cl)
if(cl.netadmin_mode)
return TRUE
if(istype(cl.my_user))
if(cl.my_user in users)
return TRUE
else
for(var/datum/ntnet_user/user in users)
if(cl in user.clients)
return TRUE
if(!direct)
return TRUE
return FALSE
/datum/ntnet_conversation/proc/can_interact(var/datum/computer_file/program/chat_client/cl)
if(cl.netadmin_mode)
return TRUE
if(istype(cl.my_user))
if(cl.my_user in users)
return TRUE
else
for(var/datum/ntnet_user/user in users)
if(cl in user.clients)
return TRUE
return FALSE
/datum/ntnet_conversation/proc/can_manage(var/datum/computer_file/program/chat_client/cl)
if(cl.netadmin_mode)
return TRUE
if(cl.my_user == operator)
return TRUE
return FALSE
/datum/ntnet_conversation/proc/cl_send(var/datum/computer_file/program/chat_client/Cl, var/message, var/mob/user)
if(!istype(Cl) || !can_interact(Cl))
return
var/datum/ntnet_message/message/msg = new(Cl)
msg.message = message
msg.user = user
process_message(msg)
/datum/ntnet_conversation/proc/cl_join(var/datum/computer_file/program/chat_client/Cl)
if(!istype(Cl) || !can_see(Cl) || direct)
return
var/datum/ntnet_message/join/msg = new(Cl)
Cl.my_user.channels.Add(src)
users.Add(Cl.my_user)
if(!operator)
operator = Cl.my_user
var/datum/ntnet_message/new_op/msg2 = new(Cl)
process_message(msg, FALSE)
process_message(msg2)
return
process_message(msg)
/datum/ntnet_conversation/proc/cl_leave(var/datum/computer_file/program/chat_client/Cl)
if(!istype(Cl) || !istype(Cl.my_user) || !(Cl.my_user in users) || !can_interact(Cl) || direct)
return
var/datum/ntnet_message/leave/msg = new(Cl)
Cl.my_user.channels.Remove(src)
users.Remove(Cl.my_user)
if(operator == Cl.my_user)
if(users.len)
operator = pick(users)
var/datum/ntnet_message/new_op/msg2 = new()
msg2.nuser = operator
process_message(msg, FALSE)
process_message(msg2)
return
process_message(msg)
/datum/ntnet_conversation/proc/cl_change_title(var/datum/computer_file/program/chat_client/Cl, var/newTitle)
if(!istype(Cl) || !istype(Cl.my_user) || !can_manage(Cl) || direct)
return
var/datum/ntnet_message/new_title/msg = new(Cl)
msg.title = newTitle
process_message(msg)
title = newTitle
/datum/ntnet_conversation/proc/cl_set_password(var/datum/computer_file/program/chat_client/Cl, var/newPassword)
if(!istype(Cl) || !istype(Cl.my_user) || !can_manage(Cl) || direct)
return
if(newPassword)
password = newPassword
else
password = FALSE
/datum/ntnet_conversation/proc/cl_kick(var/datum/computer_file/program/chat_client/Cl, var/datum/ntnet_user/target)
if(!istype(Cl) || !istype(Cl.my_user) || !can_manage(Cl) || !(target in users) || direct)
return
var/datum/ntnet_message/kick/msg = new(Cl)
msg.target = target
target.channels.Remove(src)
users.Remove(target)
if(operator == target)
if(users.len)
operator = pick(users)
var/datum/ntnet_message/new_op/msg2 = new()
msg2.nuser = operator
process_message(msg, FALSE)
process_message(msg2)
return
process_message(msg)
@@ -0,0 +1,96 @@
// Container for all essesal state for NTRC message while it's proccessed
/datum/ntnet_message
var/mob/user
var/datum/computer_file/program/chat_client/client
var/datum/ntnet_user/nuser
var/play_sound = FALSE
/datum/ntnet_message/New(var/datum/computer_file/program/chat_client/Pr = null, var/mob/user = null)
if(user)
src.user = user
if(Pr)
client = Pr
nuser = Pr.my_user
// Should be sanitized
/datum/ntnet_message/proc/format_chat_notification(var/datum/ntnet_conversation/Conv, var/datum/computer_file/program/chat_client/Cl)
return FALSE
/datum/ntnet_message/proc/format_admin_log(var/datum/ntnet_conversation/Conv)
return FALSE
// Should be sanitized
/datum/ntnet_message/proc/format_ntnet_log(var/datum/ntnet_conversation/Conv)
return FALSE
/datum/ntnet_message/proc/format_chat_log(var/datum/ntnet_conversation/Conv)
return FALSE
/datum/ntnet_message/message
play_sound = TRUE
var/message = ""
/datum/ntnet_message/message/format_chat_notification(var/datum/ntnet_conversation/Conv, var/datum/computer_file/program/chat_client/Cl)
. = "<b>([sanitize(Conv.get_title(Cl))]) <i>[nuser.username]</i>:</b> [sanitize(message)] (<a href='byond://?src=\ref[Cl]&Reply=\ref[Conv]'>Reply</a>)"
/datum/ntnet_message/message/format_chat_log(var/datum/ntnet_conversation/Conv)
. = "[worldtime2text()] [nuser.username]: [message]"
/datum/ntnet_message/message/format_admin_log(var/datum/ntnet_conversation/Conv)
. = message
/datum/ntnet_message/message/format_ntnet_log(var/datum/ntnet_conversation/Conv)
. = "[sanitize(Conv.get_title())] [nuser.username]: [sanitize(message)]"
/datum/ntnet_message/join/format_chat_notification(var/datum/ntnet_conversation/Conv, var/datum/computer_file/program/chat_client/Cl)
. = FONT_SMALL("<b>([sanitize(Conv.get_title(Cl))]) <i>[nuser.username]</i> has entered the chat.</b>")
/datum/ntnet_message/join/format_chat_log(var/datum/ntnet_conversation/Conv)
. = "[worldtime2text()] -!- [nuser.username] has entered the chat."
/datum/ntnet_message/leave/format_chat_notification(var/datum/ntnet_conversation/Conv, var/datum/computer_file/program/chat_client/Cl)
. = FONT_SMALL("<b>([sanitize(Conv.get_title(Cl))]) <i>[nuser.username]</i> has left the chat.</b>")
/datum/ntnet_message/leave/format_chat_log(var/datum/ntnet_conversation/Conv)
. = "[worldtime2text()] -!- [nuser.username] has left the chat."
/datum/ntnet_message/new_op/format_chat_log(var/datum/ntnet_conversation/Conv)
. = "[worldtime2text()] -!- [nuser.username] has become operator."
/datum/ntnet_message/new_title
var/title = ""
/datum/ntnet_message/new_title/format_chat_log(var/datum/ntnet_conversation/Conv)
. = "[worldtime2text()] -!- [nuser.username] has changed channel title from [Conv.get_title()] to [title]"
/datum/ntnet_message/new_title/format_chat_notification(var/datum/ntnet_conversation/Conv, var/datum/computer_file/program/chat_client/Cl)
. = FONT_SMALL("<b>([sanitize(Conv.get_title(Cl))]) <i>[nuser.username]</i> has changed the channel title to <i>[sanitize(title)].</i></b>")
/datum/ntnet_message/kick
var/datum/ntnet_user/target
/datum/ntnet_message/kick/format_chat_log(var/datum/ntnet_conversation/Conv)
. = "[worldtime2text()] -!- [nuser.username] has kicked [target.username] from conversation."
/datum/ntnet_message/kick/format_chat_notification(var/datum/ntnet_conversation/Conv, var/datum/computer_file/program/chat_client/Cl)
. = FONT_SMALL("<b>([sanitize(Conv.get_title(Cl))]) <i>[nuser.username]</i> has kicked <i>[target.username]</i> from conversation.</b>")
/datum/ntnet_message/direct/format_chat_log(var/datum/ntnet_conversation/Conv)
. = "[worldtime2text()] -!- [nuser.username] has opened direct conversation."
/datum/ntnet_message/direct/format_chat_notification(var/datum/ntnet_conversation/Conv, var/datum/computer_file/program/chat_client/Cl)
. = FONT_SMALL("<b>([sanitize(Conv.get_title(Cl))]) <i>[nuser.username]</i> has opened direct conversation with you.</b>")
@@ -0,0 +1,28 @@
/datum/ntnet
var/list/chat_channels = list()
var/list/chat_clients = list()
var/list/chat_users = list()
/datum/ntnet/proc/begin_conversation(var/datum/computer_file/program/chat_client/Cl, var/title)
if(!istype(Cl) || !istype(Cl.my_user))
return
var/datum/ntnet_conversation/Conv = new(title)
Conv.cl_join(Cl)
return Conv
/datum/ntnet/proc/begin_direct(var/datum/computer_file/program/chat_client/Cl, var/datum/ntnet_user/target)
if(!istype(Cl) || !istype(Cl.my_user) || !istype(target) || istype(Cl.my_user.dm_channels[target], /datum/ntnet_conversation))
return
var/datum/ntnet_conversation/Conv = new()
Conv.direct = TRUE
Conv.users.Add(Cl.my_user)
Conv.users.Add(target)
target.dm_channels[Cl.my_user] = Conv
Cl.my_user.dm_channels[target] = Conv
var/datum/ntnet_message/direct/msg = new(Cl)
Conv.process_message(msg)
@@ -0,0 +1,21 @@
/datum/ntnet_user
var/username
var/list/channels = list()
var/list/dm_channels = list()
var/list/clients = list()
/datum/ntnet_user/New()
. = ..()
ntnet_global.chat_users.Add(src)
/datum/ntnet_user/Destroy(force)
. = ..()
ntnet_global.chat_users.Remove(src)
/datum/ntnet_user/proc/generateUsernameIdCard(var/obj/item/card/id/card)
if(!card)
return "Unknown"
return "[card.registered_name] ([card.assignment])"
/datum/ntnet_user/proc/generateUsernameSilicon(var/mob/living/silicon/silicon)
return silicon.name
@@ -11,8 +11,6 @@ var/global/datum/ntnet/ntnet_global = new()
var/list/available_software = list()
var/list/available_software_presets = list()
var/list/available_news = list()
var/list/chat_channels = list()
var/list/chat_clients = list()
var/list/fileservers = list()
var/list/datum/ntnet_account/users = list()
// Amount of logs the system tries to keep in memory. Keep below 999 to prevent byond from acting weirdly.
@@ -98,7 +98,6 @@
/obj/item/modular_computer/Destroy()
kill_program(TRUE)
if(registered_id)
registered_id.chat_registered = FALSE
registered_id = null
for(var/obj/item/computer_hardware/CH in src.get_all_components())
uninstall_component(null, CH)
@@ -197,7 +196,7 @@
if(network_card)
return network_card.get_signal(specific_action)
else
return 0
return FALSE
/obj/item/modular_computer/proc/add_log(var/text)
if(!get_ntnet_status())
@@ -366,6 +365,7 @@
/obj/item/modular_computer/proc/enable_service(service, mob/user, var/datum/computer_file/program/S = null)
. = FALSE
if(!S)
S = hard_drive?.find_file_by_name(service)
@@ -382,9 +382,11 @@
return
// Start service
if(S.service_activate())
if(S.service_enable())
enabled_services += S
S.service_state = PROGRAM_STATE_ACTIVE
return TRUE
/obj/item/modular_computer/proc/disable_service(service, mob/user, var/datum/computer_file/program/S = null)
@@ -399,8 +401,8 @@
enabled_services -= S
// Stop service
S.service_deactivate()
S.service_state = PROGRAM_STATE_KILLED
S.service_disable()
S.service_state = PROGRAM_STATE_DISABLED
/obj/item/modular_computer/proc/output_message(var/message, var/message_range)
message_range += message_output_range
@@ -434,12 +436,13 @@
if(!istype(id))
output_error("No ID card found!")
return FALSE
if(id.chat_registered)
output_error("This card is already registered to another account!")
return FALSE
id.chat_registered = TRUE
registered_id = id
if(hard_drive)
for(var/datum/computer_file/program/P in hard_drive.stored_files)
P.event_registered()
output_notice("Registration successful!")
playsound(get_turf(src), 'sound/machines/ping.ogg', 10, 0)
return registered_id
@@ -448,12 +451,11 @@
if(!registered_id)
return FALSE
registered_id.chat_registered = FALSE
registered_id = null
if(hard_drive)
var/datum/computer_file/program/P = hard_drive.find_file_by_name("ntnrc_client")
P.event_unregistered()
for(var/datum/computer_file/program/P in hard_drive.stored_files)
P.event_unregistered()
registered_id = null
output_message(SPAN_NOTICE("\The [src] beeps: \"Successfully unregistered ID!\""))
playsound(get_turf(src), 'sound/machines/ping.ogg', 20, 0)
@@ -476,7 +478,6 @@
return TRUE
/obj/item/modular_computer/proc/silence_notifications()
for (var/datum/computer_file/program/P in hard_drive.stored_files)
if (istype(P))
P.event_silentmode()
silent = !silent
for (var/datum/computer_file/program/P in hard_drive.stored_files)
P.event_silentmode()
@@ -3,8 +3,9 @@
visible_message(SPAN_WARNING("\The [src]'s screen flickers briefly and then goes dark."))
if(active_program)
active_program.event_powerfailure(FALSE)
for(var/datum/computer_file/program/PRG in idle_threads)
PRG.event_powerfailure(TRUE)
for(var/datum/computer_file/program/PRG in hard_drive.stored_files)
if(PRG != active_program)
PRG.event_powerfailure(TRUE)
shutdown_computer(FALSE)
power_has_failed = TRUE
update_icon()
@@ -4,6 +4,7 @@
name = "Modular Computer"
desc = "A modular computer. You shouldn't see this."
var/lexical_name = "computer"
var/enabled = FALSE // Whether the computer is turned on.
var/screen_on = TRUE // Whether the computer is active/opened/it's screen is on.
var/working = TRUE // Whether the computer is working.
@@ -1,5 +1,6 @@
/obj/item/modular_computer/handheld
name = "tablet computer"
lexical_name = "tablet"
desc = "A portable device for your needs on the go."
desc_info = "To deploy the charging cable on this device, either drag and drop it over a nearby APC, or click on the APC with the computer in hand."
icon = 'icons/obj/modular_tablet.dmi'
@@ -1,6 +1,7 @@
/obj/item/modular_computer/laptop
anchored = TRUE
name = "laptop computer"
lexical_name = "laptop"
desc = "A portable computer."
desc_info = "You can alt-click the laptop while it's set down on surface to open it up and work with it. Left clicking while it is open will allow you to operate it."
hardware_flag = PROGRAM_LAPTOP
@@ -1,5 +1,6 @@
/obj/item/modular_computer/handheld/pda
name = "PDA"
lexical_name = "tablet"
desc = "The latest in portable microcomputer solutions from Thinktronic Systems, LTD."
icon = 'icons/obj/pda.dmi'
icon_state = "pda"
@@ -53,7 +53,7 @@
/obj/item/modular_computer/silicon/install_default_programs()
hard_drive.store_file(new /datum/computer_file/program/filemanager(src))
hard_drive.store_file(new /datum/computer_file/program/ntnetdownload(src))
hard_drive.store_file(new /datum/computer_file/program/chatclient(src))
hard_drive.store_file(new /datum/computer_file/program/chat_client(src))
hard_drive.remove_file(hard_drive.find_file_by_name("clientmanager"))
addtimer(CALLBACK(src, .proc/register_chat), 1 SECOND)
@@ -62,24 +62,6 @@
enable_computer(null, TRUE) // passing null because we don't want the UI to open
minimize_program()
/obj/item/modular_computer/silicon/verb/send_pda_message()
set category = "AI IM"
set name = "Send Direct Message"
set src in usr
if (usr.stat == DEAD)
to_chat(usr, "You can't send PDA messages because you are dead!")
return
var/datum/computer_file/program/chatclient/CL = hard_drive.find_file_by_name("ntnrc_client")
if(!istype(CL))
output_error("Chat client not installed!")
return
else if(CL.program_state == PROGRAM_STATE_KILLED)
run_program("ntnrc_client")
CL.direct_message()
if(CL.channel)
CL.add_message(CL.send_message())
/obj/item/modular_computer/silicon/robot/drone/install_default_programs()
hard_drive.store_file(new /datum/computer_file/program/filemanager(src))
hard_drive.store_file(new /datum/computer_file/program/ntnetdownload(src))
@@ -1,5 +1,6 @@
/obj/item/modular_computer/handheld/wristbound
name = "wristbound computer"
lexical_name = "wristbound"
desc = "A portable wristbound device for your needs on the go. Quite comfortable."
desc_fluff = "A NanoTrasen design, this wristbound computer allows the user to quickly and safely access critical info, without taking their hands out of the equation."
icon = 'icons/obj/modular_wristbound.dmi'
@@ -24,7 +24,7 @@
var/computer_emagged = FALSE // Set to TRUE if computer that's running us was emagged. Computer updates this every Process() tick
var/ui_header // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /nano/images/status_icons. Be careful not to use too large images!
var/color = "#FFFFFF" // The color of light the computer should emit when this program is open.
var/service_state = PROGRAM_STATE_KILLED // PROGRAM_STATE_KILLED or PROGRAM_STATE_ACTIVE - specifies whether this program's service is running.
var/service_state = PROGRAM_STATE_DISABLED // PROGRAM_STATE_KILLED or PROGRAM_STATE_ACTIVE - specifies whether this program's service is running.
var/silent = FALSE
/datum/computer_file/program/New(var/obj/item/modular_computer/comp)
@@ -196,27 +196,6 @@
if(computer)
return computer.get_header_data()
// This is performed on program startup. May be overriden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure.
// When implementing new program based device, use this to run the program.
/datum/computer_file/program/proc/run_program(var/mob/user)
if(can_run(user, 1) || !requires_access_to_run)
if(nanomodule_path)
NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src)
if(requires_ntnet && network_destination)
generate_network_log("Connection opened to [network_destination].")
program_state = PROGRAM_STATE_ACTIVE
return TRUE
return FALSE
// Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client.
/datum/computer_file/program/proc/kill_program(var/forced = 0)
program_state = PROGRAM_STATE_KILLED
if(network_destination)
generate_network_log("Connection to [network_destination] closed.")
if(NM)
qdel(NM)
NM = null
return TRUE
// 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.
// It returns 0 if it can't run or if NanoModule was used instead. I suggest using NanoModules where applicable.
@@ -248,18 +227,9 @@
else
return -1
// Is called when program service is being activated
// Returns 1 if service startup was sucessfull
/datum/computer_file/program/proc/service_activate()
return FALSE
// Is called when program service is being deactivated
/datum/computer_file/program/proc/service_deactivate()
return
/datum/computer_file/program/proc/message_dead(var/message)
for(var/mob/M in player_list)
if(M.stat == DEAD && (M.client && M.client.prefs.toggles & CHAT_GHOSTEARS))
if(isnewplayer(M))
continue
to_chat(M, message)
to_chat(M, message)
@@ -1,6 +1,47 @@
// Events are sent to the program by the computer.
// Always include a parent call when overriding an event.
// This is performed on program startup. May be overriden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure.
// When implementing new program based device, use this to run the program.
/datum/computer_file/program/proc/run_program(var/mob/user)
if(can_run(user, 1) || !requires_access_to_run)
if(nanomodule_path)
NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src)
if(requires_ntnet && network_destination)
generate_network_log("Connection opened to [network_destination].")
program_state = PROGRAM_STATE_ACTIVE
return TRUE
return FALSE
// Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client.
/datum/computer_file/program/proc/kill_program(var/forced = 0)
program_state = PROGRAM_STATE_KILLED
if(network_destination)
generate_network_log("Connection to [network_destination] closed.")
if(NM)
qdel(NM)
NM = null
return TRUE
// Is called when program service is being activated
// Returns 1 if service startup was sucessfull
/datum/computer_file/program/proc/service_activate()
return FALSE
// Is called when program service is being deactivated
/datum/computer_file/program/proc/service_deactivate()
return
// Is called when program service is being activated for first time.
/datum/computer_file/program/proc/service_enable()
return service_activate()
// Is called when program service is being deactivated without
/datum/computer_file/program/proc/service_disable()
return service_deactivate()
/// SECOND ORDER EVENTS
// Called when the ID card is removed from computer. ID is removed AFTER this proc.
/datum/computer_file/program/proc/event_idremoved(var/background)
return
@@ -9,12 +50,17 @@
return
// Called when an ID is unregistered from the device.
/datum/computer_file/program/proc/event_unregistered(var/background)
/datum/computer_file/program/proc/event_unregistered()
return
// Called when an ID is unregistered from the device.
/datum/computer_file/program/proc/event_registered()
return
// Called when the computer fails due to power loss. Override when program wants to specifically react to power loss.
/datum/computer_file/program/proc/event_powerfailure(var/background)
kill_program(TRUE)
if(program_state > PROGRAM_STATE_KILLED)
kill_program(TRUE)
// Called when the network connectivity fails. Computer does necessary checks and only calls this when requires_ntnet_feature and similar variables are not met.
/datum/computer_file/program/proc/event_networkfailure(var/background)
@@ -32,7 +32,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/power_monitor(comp),
new /datum/computer_file/program/alarm_monitor(comp),
@@ -56,7 +56,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/power_monitor(comp),
new /datum/computer_file/program/alarm_monitor(comp),
@@ -81,7 +81,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/comm(comp, FALSE),
new /datum/computer_file/program/game/sudoku(comp),
@@ -108,7 +108,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/suit_sensors(comp),
new /datum/computer_file/program/records/medical(comp),
@@ -130,7 +130,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/comm(comp, FALSE),
new /datum/computer_file/program/suit_sensors(comp),
@@ -155,7 +155,7 @@
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/ntnetmonitor(comp),
new /datum/computer_file/program/aidiag(comp),
@@ -178,7 +178,7 @@
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/ntnetmonitor(comp),
new /datum/computer_file/program/aidiag(comp),
@@ -201,7 +201,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/comm(comp, FALSE),
new /datum/computer_file/program/ntnetmonitor(comp),
@@ -225,7 +225,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/card_mod(comp),
new /datum/computer_file/program/comm(comp, FALSE),
@@ -246,7 +246,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/civilian/cargocontrol(comp),
new /datum/computer_file/program/card_mod(comp),
@@ -269,7 +269,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/card_mod(comp),
new /datum/computer_file/program/comm(comp, FALSE),
new /datum/computer_file/program/camera_monitor(comp),
@@ -317,7 +317,7 @@
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/camera_monitor(comp),
new /datum/computer_file/program/comm(comp),
@@ -341,7 +341,7 @@
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/camera_monitor(comp),
new /datum/computer_file/program/comm(comp),
@@ -367,7 +367,7 @@
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/camera_monitor(comp),
new /datum/computer_file/program/digitalwarrant(comp),
new /datum/computer_file/program/penal_mechs(comp),
@@ -391,7 +391,7 @@
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/comm(comp, FALSE),
new /datum/computer_file/program/camera_monitor(comp),
@@ -415,7 +415,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/game/arcade(comp),
new /datum/computer_file/program/game/sudoku(comp),
@@ -435,7 +435,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/civilian/janitor(comp),
new /datum/computer_file/program/game/arcade(comp),
@@ -468,7 +468,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargocontrol(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/civilian/cargodelivery(comp),
@@ -488,7 +488,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargodelivery(comp),
new /datum/computer_file/program/ntsl2_interpreter(comp)
)
@@ -506,7 +506,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/game/sudoku(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/records/employment(comp),
@@ -525,7 +525,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/civilian/cargoorder(comp),
new /datum/computer_file/program/camera_monitor(comp),
new /datum/computer_file/program/alarm_monitor(comp),
@@ -594,7 +594,7 @@
new /datum/computer_file/program/filemanager(comp),
new /datum/computer_file/program/manifest(comp),
new /datum/computer_file/program/newsbrowser(comp),
new /datum/computer_file/program/chatclient(comp),
new /datum/computer_file/program/chat_client(comp),
new /datum/computer_file/program/merchant(comp)
)
return _prg_list
@@ -1,381 +1,253 @@
/datum/computer_file/program/chatclient
/datum/computer_file/program/chat_client
filename = "ntnrc_client"
filedesc = "Chat Client"
program_icon_state = "command"
extended_desc = "This program allows communication over the NTNRC network."
extended_desc = "This program allows communication over the NTRC network."
size = 2
requires_ntnet = TRUE
requires_ntnet_feature = NTNET_COMMUNICATION
network_destination = "NTNRC server"
ui_header = "ntnrc_idle.gif"
program_type = PROGRAM_TYPE_ALL
network_destination = "NTRC server"
available_on_ntnet = TRUE
nanomodule_path = /datum/nano_module/program/computer_chatclient
color = LIGHT_COLOR_GREEN
silent = FALSE
var/last_message // Used to generate the toolbar icon
var/username
var/datum/ntnet_conversation/channel
var/operator_mode = FALSE // Channel operator mode
var/datum/ntnet_user/my_user
var/netadmin_mode = FALSE // Administrator mode (invisible to other users + bypasses passwords)
var/set_offline = FALSE // appear "invisible"
var/list/directmessagechannels = list()
var/set_offline = FALSE // appear "invisible"
var/ringtone = "beep"
var/syndi_auth = FALSE
/datum/computer_file/program/chatclient/New(var/obj/item/modular_computer/comp)
..(comp)
if(!comp)
return
/datum/computer_file/program/chatclient/Destroy()
ntnet_global.chat_clients -= src
/datum/computer_file/program/chat_client/Destroy()
return ..()
/datum/computer_file/program/chatclient/Topic(href, href_list)
/datum/computer_file/program/chat_client/proc/can_receive_notification(var/datum/computer_file/program/chat_client/from)
return ((program_state > PROGRAM_STATE_KILLED || service_state > PROGRAM_STATE_KILLED) && from != src && get_signal(NTNET_COMMUNICATION))
/datum/computer_file/program/chat_client/proc/play_notification_sound(var/datum/computer_file/program/chat_client/from)
if(!silent && src != from && program_state == PROGRAM_STATE_BACKGROUND)
playsound(computer, 'sound/machines/twobeep.ogg', 50, 1)
computer.output_message("[icon2html(computer, world)] *[ringtone]*", 2)
/datum/computer_file/program/chat_client/Topic(href, href_list)
if(..())
return TRUE
if(href_list["PRG_toggleringer"])
. = TRUE
silent = !silent
if(href_list["PRG_setringtone"])
. = TRUE
var/t = input(usr, "Please enter new ringtone", filedesc, ringtone) as text|null
if(!usr.Adjacent(computer) || !t)
return
if(href_list["ringtone"])
var/newRingtone = href_list["ringtone"]
var/obj/item/device/uplink/hidden/H = computer.hidden_uplink
if(istype(H) && H.check_trigger(usr, lowertext(t), lowertext(H.pda_code)))
if(istype(H) && H.check_trigger(usr, lowertext(newRingtone), lowertext(H.pda_code)))
to_chat(usr, SPAN_NOTICE("\The [computer] softly beeps."))
syndi_auth = TRUE
SSnanoui.close_uis(NM)
SSvueui.close_uis(src)
else
t = sanitize(t, 20)
ringtone = t
if(href_list["PRG_speak"])
. = TRUE
add_message(send_message())
if(href_list["Reply"])
. = TRUE
var/datum/ntnet_conversation/C = locate(href_list["Reply"]) in ntnet_global.chat_channels
if(!istype(C))
to_chat(usr, SPAN_WARNING("The target channel couldn't be found and has likely been deleted!"))
return
var/message = send_message()
if(!(C in ntnet_global.chat_channels))
to_chat(usr, SPAN_WARNING("The target channel couldn't be found and has likely been deleted!"))
return
add_message(message, C)
if(href_list["PRG_joinchannel"])
. = TRUE
var/datum/ntnet_conversation/C
for(var/datum/ntnet_conversation/chan in ntnet_global.chat_channels)
if(chan.id == text2num(href_list["PRG_joinchannel"]))
C = chan
break
if(!C)
return TRUE
if(netadmin_mode)
channel = C // Bypasses normal leave/join and passwords. Technically makes the user invisible to others.
return TRUE
if(C.password)
var/mob/living/user = usr
var/password = sanitize(input(user, "Access Denied. Enter password:"))
if(C?.password == password)
C.add_client(src)
channel = C
return TRUE
C.add_client(src)
message_dead(FONT_SMALL("<b>([C.get_dead_title()]) A new client ([username]) has entered the chat.</b>"))
channel = C
if(href_list["PRG_leavechannel"])
. = TRUE
if(channel && !channel.direct)
channel.remove_client(src)
message_dead(FONT_SMALL(FONT_SMALL("<b>([channel.get_dead_title()]) A client ([username]) has left the chat.</b>")))
channel = null
if(href_list["PRG_backtomain"])
. = TRUE
channel = null
if(href_list["PRG_newchannel"])
. = TRUE
newRingtone = sanitize(newRingtone, 20)
ringtone = newRingtone
SSvueui.check_uis_for_change(src)
// User only commands
if(!istype(my_user))
return
// Following actions require signal
if(!get_signal(NTNET_COMMUNICATION))
return
if(href_list["send"])
var/mob/living/user = usr
var/channel_title = sanitize(input(user, "Enter channel name or leave blank to cancel:"))
if(!channel_title)
return
var/datum/ntnet_conversation/C = new /datum/ntnet_conversation(channel_title)
C.add_client(src)
C.operator = src
channel = C
message_dead(FONT_SMALL("<b>([channel.get_dead_title()]) A new channel has been made by [username].</b>"))
if(href_list["PRG_toggleadmin"])
. = TRUE
var/datum/ntnet_conversation/conv = locate(href_list["send"]["target"])
var/message = href_list["send"]["message"]
if(istype(conv) && message)
if(ishuman(user))
user.visible_message("[SPAN_BOLD("\The [user]")] taps on [user.get_pronoun("his")] [computer.lexical_name]'s screen.")
conv.cl_send(src, message, user)
if(href_list["join"])
var/datum/ntnet_conversation/conv = locate(href_list["join"]["target"])
var/password = href_list["join"]["password"]
if(istype(conv))
if(conv.password)
if(conv.password == password)
conv.cl_join(src)
else
// How do I alert of password invalid?
else
conv.cl_join(src)
if(href_list["leave"])
var/datum/ntnet_conversation/conv = locate(href_list["leave"])
if(istype(conv))
conv.cl_leave(src)
SSvueui.check_uis_for_change(src)
if(href_list["kick"])
var/datum/ntnet_conversation/conv = locate(href_list["kick"]["target"])
var/datum/ntnet_user/tUser = locate(href_list["kick"]["user"])
if(istype(conv) && istype(tUser))
conv.cl_kick(src, tUser)
if(href_list["set_password"])
var/datum/ntnet_conversation/conv = locate(href_list["set_password"]["target"])
var/password = href_list["set_password"]["password"]
if(istype(conv))
conv.cl_set_password(src, password)
if(href_list["change_title"])
var/datum/ntnet_conversation/conv = locate(href_list["change_title"]["target"])
var/newTitle = href_list["change_title"]["title"]
if(istype(conv))
conv.cl_change_title(src, newTitle)
if(href_list["new_channel"])
ntnet_global.begin_conversation(src, sanitize(href_list["new_channel"]))
if(href_list["delete"])
var/datum/ntnet_conversation/conv = locate(href_list["delete"])
if(istype(conv) && conv.can_manage(src))
ntnet_global.chat_channels.Remove(conv)
qdel(conv)
SSvueui.check_uis_for_change(src)
if(href_list["direct"])
var/datum/ntnet_user/tUser = locate(href_list["direct"])
ntnet_global.begin_direct(src, tUser)
if(href_list["toggleadmin"])
if(netadmin_mode)
netadmin_mode = FALSE
if(channel)
channel.remove_client(src) // We shouldn't be in channel's user list, but just in case...
channel = null
return TRUE
var/mob/living/user = usr
if(can_run(usr, 1, access_network))
if(channel)
var/response = alert(user, "Really engage admin-mode? You will be disconnected from your current channel!", "NTNRC Admin mode", "Yes", "No")
if(response == "Yes")
if(channel)
channel.remove_client(src)
channel = null
else
return
netadmin_mode = TRUE
if(href_list["PRG_changename"])
. = TRUE
var/mob/living/user = usr
var/new_name = sanitize(input(user, "Enter new nickname or leave blank to cancel:"))
if(!new_name)
return TRUE
var/comp_name = ckey(new_name)
for(var/cl in ntnet_global.chat_clients)
var/datum/computer_file/program/chatclient/C = cl
if(ckey(C.username) == comp_name || comp_name == "cancel")
alert(user, "This nickname is already taken.")
return TRUE
for(var/datum/ntnet_conversation/channel in ntnet_global.chat_channels)
if(src in channel.clients)
channel.add_status_message("[username] is now known as [new_name].")
username = new_name
if(href_list["PRG_savelog"])
. = TRUE
if(!channel)
return
var/mob/living/user = usr
var/logname = input(user, "Enter desired logfile name (.log) or leave blank to cancel:")
if(!logname || !channel)
return TRUE
var/datum/computer_file/data/logfile = new /datum/computer_file/data/logfile()
// Now we will generate HTML-compliant file that can actually be viewed/printed.
logfile.filename = logname
logfile.stored_data = "\[b\]Logfile dump from NTNRC channel [channel.title]\[/b\]\[BR\]"
for(var/logstring in channel.messages)
logfile.stored_data += "[logstring]\[BR\]"
logfile.stored_data += "\[b\]Logfile dump completed.\[/b\]"
logfile.calculate_size()
if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(logfile))
if(!computer)
// This program shouldn't even be runnable without computer.
crash_with("Var computer is null!")
return TRUE
if(!computer.hard_drive)
computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.")
else // In 99.9% cases this will mean our HDD is full
computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.")
if(href_list["PRG_renamechannel"])
. = TRUE
if(!operator_mode || !channel)
return TRUE
var/mob/living/user = usr
var/newname = sanitize(input(user, "Enter new channel name or leave blank to cancel:"))
if(!newname || !channel)
return
channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.")
channel.title = newname
if(href_list["PRG_deletechannel"])
. = TRUE
if(channel && ((channel.operator == src) || netadmin_mode))
qdel(channel)
channel = null
if(href_list["PRG_setpassword"])
. = TRUE
if(!channel || ((channel.operator != src) && !netadmin_mode))
return TRUE
var/mob/living/user = usr
var/newpassword = sanitize(input(user, "Enter new password for this channel. Leave blank to cancel, enter 'nopassword' to remove password completely:"))
if(!channel || !newpassword || ((channel.operator != src) && !netadmin_mode))
return TRUE
if(newpassword == "nopassword")
channel.password = ""
else
channel.password = newpassword
if(href_list["PRG_directmessage"])
. = TRUE
direct_message(usr)
/datum/computer_file/program/chatclient/proc/send_message()
var/mob/living/user = usr
if(ishuman(user))
user.visible_message("[SPAN_BOLD("\The [user]")] taps on [user.get_pronoun("his")] computer's screen.")
var/message = sanitize(input(user, "Enter a message to send: ") as null|text)
if(!message)
return
return message
/datum/computer_file/program/chatclient/proc/add_message(var/message, var/datum/ntnet_conversation/specific_channel)
if(!message)
return
var/datum/ntnet_conversation/sent_channel
if(specific_channel)
sent_channel = specific_channel
var/mob/living/user = usr
if(can_run(user, TRUE, access_network))
netadmin_mode = TRUE
SSvueui.check_uis_for_change(src)
if(href_list["Reply"])
var/mob/living/user = usr
var/datum/ntnet_conversation/conv = locate(href_list["Reply"])
var/message = input(user, "Enter message or leave blank to cancel: ")
if(istype(conv) && message)
if(ishuman(user))
user.visible_message("[SPAN_BOLD("\The [user]")] taps on [user.get_pronoun("his")] [computer.lexical_name]'s screen.")
conv.cl_send(src, message, user)
/datum/computer_file/program/chat_client/service_activate()
. = ..()
if(istype(my_user) && get_signal(NTNET_COMMUNICATION))
activate_chat_client()
return TRUE
else
sent_channel = channel
if(!sent_channel) // panikk - geeves
return
sent_channel.add_message(message, username, usr)
message_dead(FONT_SMALL("<b>([sent_channel.get_dead_title()]) [username]:</b> [message]"))
return FALSE
/datum/computer_file/program/chatclient/proc/direct_message(var/mob/user)
var/clients = list()
var/names = list()
for(var/cl in ntnet_global.chat_clients - src)
var/datum/computer_file/program/chatclient/C = cl
if(C.set_offline)
continue
clients[C.username] = C
names += C.username
if(!length(names))
to_chat(user, SPAN_WARNING("You are the only user with an active account!"))
return
var/picked = input(user, "Select with whom you would like to start a conversation.") as null|anything in names
if(!picked)
return
var/datum/computer_file/program/chatclient/otherClient = clients[picked]
if(picked)
if(directmessagechannels[otherClient])
channel = directmessagechannels[otherClient]
return
var/datum/ntnet_conversation/C = new /datum/ntnet_conversation("", TRUE)
C.begin_direct(src, otherClient)
channel = C
directmessagechannels[otherClient] = C
otherClient.directmessagechannels[src] = C
/datum/computer_file/program/chat_client/service_deactivate()
. = ..()
deactivate_chat_client()
/datum/computer_file/program/chat_client/process_tick()
. = ..()
/datum/computer_file/program/chatclient/process_tick()
..()
if(program_state != PROGRAM_STATE_KILLED)
ui_header = "ntnrc_idle.gif"
if(channel)
// Remember the last message. If there is no message in the channel remember null.
if(length(channel.messages) > 1) // len - 1 = 0 and that's array out of bounds
last_message = channel.messages[channel.messages.len - 1]
else
last_message = null
/datum/computer_file/program/chat_client/kill_program(var/forced = FALSE)
return ..(forced)
/datum/computer_file/program/chat_client/run_program(var/mob/user)
if(!istype(my_user))
if(istype(computer, /obj/item/modular_computer/silicon))
var/obj/item/modular_computer/silicon/SC = computer
var/mob/living/silicon/S = SC.computer_host
S.id_card.InitializeChatUser()
my_user = S.id_card.chat_user
else
last_message = null
return 1
if(channel?.messages?.len)
ui_header = last_message == channel.messages[channel.messages.len - 1] ? "ntnrc_idle.gif" : "ntnrc_new.gif"
else
ui_header = "ntnrc_idle.gif"
/datum/computer_file/program/chatclient/kill_program(var/forced = FALSE)
if(!forced)
var/confirm = alert("Are you sure you want to close the NTNRC Client? You will not be reachable via messaging if you do so.", "Close?", "Yes", "No")
if((confirm != "Yes") || (CanUseTopic(usr) != STATUS_INTERACTIVE))
return FALSE
ntnet_global.chat_clients -= src
channel = null
..(forced)
return TRUE
/datum/computer_file/program/chatclient/run_program(var/mob/user)
if(!computer)
return
if(!istype(computer, /obj/item/modular_computer/silicon))
if((!computer.registered_id && !computer.register_account(src)))
if((!computer.registered_id && !computer.register_account(src)))
return
if(service_state == PROGRAM_STATE_DISABLED)
if(!computer.enable_service(null, user, src))
return
if(!(src in ntnet_global.chat_clients))
ntnet_global.chat_clients += src
if(!username)
username = username_from_id()
return ..(user)
/datum/computer_file/program/chatclient/proc/username_from_id()
if(istype(computer, /obj/item/modular_computer/silicon))
var/obj/item/modular_computer/silicon/SC = computer
return SC.computer_host.name
if(!computer.registered_id)
return "Unknown"
/datum/computer_file/program/chat_client/event_registered()
. = ..()
computer.registered_id.InitializeChatUser()
my_user = computer.registered_id.chat_user
if(service_state > PROGRAM_STATE_KILLED)
activate_chat_client()
return "[computer.registered_id.registered_name] ([computer.registered_id.assignment])"
/datum/computer_file/program/chat_client/event_unregistered()
. = ..()
if(service_state > PROGRAM_STATE_KILLED)
deactivate_chat_client()
my_user = null
/datum/computer_file/program/chatclient/event_unregistered()
..()
computer.set_autorun(filename)
ntnet_global.chat_clients -= src
kill_program(TRUE)
/datum/computer_file/program/chat_client/event_silentmode()
. = ..()
silent = computer.silent
/datum/computer_file/program/chatclient/event_silentmode()
..()
if(computer.silent != silent)
silent = computer.silent
/datum/nano_module/program/computer_chatclient
name = "Chat Client"
/datum/nano_module/program/computer_chatclient/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
if(!ntnet_global || !ntnet_global.chat_channels)
return
var/datum/computer_file/program/chatclient/C = program
if(C.computer.hidden_uplink && C.syndi_auth)
if(alert(user, "Resume or close and secure?", name, "Resume", "Close") == "Resume")
C.computer.hidden_uplink.trigger(user)
/datum/computer_file/program/chat_client/ui_interact(var/mob/user)
if(computer.hidden_uplink && syndi_auth)
if(alert(user, "Resume or close and secure?", filedesc, "Resume", "Close") == "Resume")
computer.hidden_uplink.trigger(user)
return
else
C.syndi_auth = FALSE
syndi_auth = FALSE
var/list/data = list()
if(program)
data = list("_PC" = program.get_header_data())
if(!istype(C))
return
data["adminmode"] = C.netadmin_mode
if(C.channel)
data["title"] = C.channel.get_title(C)
var/list/messages[0]
for(var/M in C.channel.messages)
messages.Add(list(list(
"msg" = M
)))
data["messages"] = messages
var/list/clients[0]
for(var/datum/computer_file/program/chatclient/cl in C.channel.clients)
clients.Add(list(list(
"name" = cl.username,
"active" = cl.program_state > PROGRAM_STATE_KILLED
)))
data["clients"] = clients
C.operator_mode = (C.channel.operator == C) ? 1 : 0
data["is_operator"] = C.operator_mode || C.netadmin_mode
data["is_direct"] = C.channel.direct
else // Channel selection screen
var/list/all_channels[0]
for(var/datum/ntnet_conversation/conv in ntnet_global.chat_channels)
if(conv && conv.title && conv.can_see(program))
all_channels.Add(list(list(
"chan" = conv.get_title(C),
"id" = conv.id,
"con" = (program in conv.clients)
)))
data["all_channels"] = all_channels
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
if (!ui)
ui = new(user, src, ui_key, "ntnet_chat.tmpl", "NTNet Relay Chat Client", 575, 700, state = state)
ui.auto_update_layout = 1
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(TRUE)
ui = new /datum/vueui/modularcomputer(user, src, "mcomputer-chat-index", 600, 500, capitalize(filedesc))
ui.open()
/datum/computer_file/program/chat_client/vueui_transfer(oldobj)
SSvueui.transfer_uis(oldobj, src, "mcomputer-chat-index", 600, 500, capitalize(filedesc))
return TRUE
/datum/computer_file/program/chat_client/vueui_data_change(var/list/data, var/mob/user, var/datum/vueui/ui)
. = ..()
data = . || data || list()
// Gather data for computer header
var/headerdata = get_header_data(data["_PC"])
if(headerdata)
data["_PC"] = headerdata
. = data
data["service"] = service_state > PROGRAM_STATE_KILLED
data["registered"] = istype(my_user)
data["signal"] = get_signal(NTNET_COMMUNICATION)
data["ringtone"] = ringtone
data["netadmin_mode"] = netadmin_mode
data["can_netadmin_mode"] = can_run(user, FALSE, access_network)
if(data["registered"] && data["service"] && data["signal"])
data["channels"] = list()
for(var/c in ntnet_global.chat_channels)
var/datum/ntnet_conversation/Channel = c
if(istype(Channel) && Channel.can_see(src))
var/ref = ref(Channel)
var/can_interact = Channel.can_interact(src)
var/can_manage = Channel.can_manage(src)
data["channels"][ref] = list(
"title" = Channel.get_title(src),
"direct" = Channel.direct,
"password" = !!Channel.password,
"can_interact" = can_interact,
"can_manage" = can_manage
)
if(can_interact)
data["channels"][ref]["msg"] = Channel.messages
data["channels"][ref]["users"] = list()
for(var/datum/ntnet_user/U in Channel.users)
var/uref = ref(U)
data["channels"][ref]["users"][uref] = U.username
data["users"] = list()
for(var/u in ntnet_global.chat_users)
var/datum/ntnet_user/nUser = u
if(nUser != my_user)
var/ref = ref(nUser)
data["users"][ref] = nUser.username
return data
/datum/computer_file/program/chat_client/proc/activate_chat_client()
if(!istype(my_user))
return
if(!(src in my_user.clients))
my_user.clients.Add(src)
if(!(src in ntnet_global.chat_clients))
ntnet_global.chat_clients.Add(src)
/datum/computer_file/program/chat_client/proc/deactivate_chat_client()
if(!istype(my_user))
return
if(src in my_user.clients)
my_user.clients.Remove(src)
if(src in ntnet_global.chat_clients)
ntnet_global.chat_clients.Remove(src)
@@ -70,7 +70,7 @@
computer.enrolled = 2 // private devices
computer.hard_drive.store_file(new /datum/computer_file/program/filemanager(computer))
computer.hard_drive.store_file(new /datum/computer_file/program/ntnetdownload(computer))
computer.hard_drive.store_file(new /datum/computer_file/program/chatclient(computer))
computer.hard_drive.store_file(new /datum/computer_file/program/chat_client(computer))
return TRUE
//Set´s up the programs from the preset