mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-15 17:15:25 +01:00
TGUI NTOS - Total Conversion
This commit is contained in:
@@ -14,51 +14,4 @@
|
||||
size = 4
|
||||
available_on_ntnet = 0
|
||||
requires_ntnet = 0
|
||||
nanomodule_path = /datum/nano_module/program/computer_configurator/
|
||||
|
||||
/datum/nano_module/program/computer_configurator
|
||||
name = "NTOS Computer Configuration Tool"
|
||||
var/obj/item/modular_computer/movable = null
|
||||
|
||||
/datum/nano_module/program/computer_configurator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(program)
|
||||
movable = program.computer
|
||||
if(!istype(movable))
|
||||
movable = null
|
||||
|
||||
// No computer connection, we can't get data from that.
|
||||
if(!movable)
|
||||
return 0
|
||||
|
||||
var/list/data = list()
|
||||
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
|
||||
var/list/hardware = movable.get_all_components()
|
||||
|
||||
data["disk_size"] = movable.hard_drive.max_capacity
|
||||
data["disk_used"] = movable.hard_drive.used_capacity
|
||||
data["power_usage"] = movable.last_power_usage
|
||||
data["battery_exists"] = movable.battery_module ? 1 : 0
|
||||
if(movable.battery_module)
|
||||
data["battery_rating"] = movable.battery_module.battery.maxcharge
|
||||
data["battery_percent"] = round(movable.battery_module.battery.percent())
|
||||
|
||||
var/list/all_entries[0]
|
||||
for(var/obj/item/weapon/computer_hardware/H in hardware)
|
||||
all_entries.Add(list(list(
|
||||
"name" = H.name,
|
||||
"desc" = H.desc,
|
||||
"enabled" = H.enabled,
|
||||
"critical" = H.critical,
|
||||
"powerusage" = H.power_usage
|
||||
)))
|
||||
|
||||
data["hardware"] = all_entries
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "laptop_configuration.tmpl", "NTOS Configuration Utility", 575, 700, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
tguimodule_path = /datum/tgui_module/computer_configurator
|
||||
|
||||
@@ -11,15 +11,15 @@
|
||||
var/stored_login = ""
|
||||
var/stored_password = ""
|
||||
|
||||
nanomodule_path = /datum/nano_module/email_client
|
||||
tguimodule_path = /datum/tgui_module/email_client
|
||||
|
||||
// Persistency. Unless you log out, or unless your password changes, this will pre-fill the login data when restarting the program
|
||||
/datum/computer_file/program/email_client/kill_program()
|
||||
if(NM)
|
||||
var/datum/nano_module/email_client/NME = NM
|
||||
if(NME.current_account)
|
||||
stored_login = NME.stored_login
|
||||
stored_password = NME.stored_password
|
||||
if(TM)
|
||||
var/datum/tgui_module/email_client/TME = TM
|
||||
if(TME.current_account)
|
||||
stored_login = TME.stored_login
|
||||
stored_password = TME.stored_password
|
||||
else
|
||||
stored_login = ""
|
||||
stored_password = ""
|
||||
@@ -27,473 +27,31 @@
|
||||
|
||||
/datum/computer_file/program/email_client/run_program()
|
||||
. = ..()
|
||||
if(NM)
|
||||
var/datum/nano_module/email_client/NME = NM
|
||||
NME.stored_login = stored_login
|
||||
NME.stored_password = stored_password
|
||||
NME.log_in()
|
||||
NME.error = ""
|
||||
NME.check_for_new_messages(1)
|
||||
if(TM)
|
||||
var/datum/tgui_module/email_client/TME = TM
|
||||
TME.stored_login = stored_login
|
||||
TME.stored_password = stored_password
|
||||
TME.log_in()
|
||||
TME.error = ""
|
||||
TME.check_for_new_messages(1)
|
||||
|
||||
/datum/computer_file/program/email_client/proc/new_mail_notify()
|
||||
computer.visible_message("\The [computer] beeps softly, indicating a new email has been received.", 1)
|
||||
var/turf/T = get_turf(computer) // Because visible_message is being a butt
|
||||
if(T)
|
||||
T.visible_message("<span class='notice'>[computer] beeps softly, indicating a new email has been received.</span>")
|
||||
playsound(computer, 'sound/misc/server-ready.ogg', 100, 0)
|
||||
|
||||
/datum/computer_file/program/email_client/process_tick()
|
||||
..()
|
||||
var/datum/nano_module/email_client/NME = NM
|
||||
if(!istype(NME))
|
||||
var/datum/tgui_module/email_client/TME = TM
|
||||
if(!istype(TME))
|
||||
return
|
||||
NME.relayed_process(ntnet_speed)
|
||||
TME.relayed_process(ntnet_speed)
|
||||
|
||||
var/check_count = NME.check_for_new_messages()
|
||||
var/check_count = TME.check_for_new_messages()
|
||||
if(check_count)
|
||||
if(check_count == 2)
|
||||
new_mail_notify()
|
||||
ui_header = "ntnrc_new.gif"
|
||||
else
|
||||
ui_header = "ntnrc_idle.gif"
|
||||
|
||||
/datum/nano_module/email_client/
|
||||
name = "Email Client"
|
||||
var/stored_login = ""
|
||||
var/stored_password = ""
|
||||
var/error = ""
|
||||
|
||||
var/msg_title = ""
|
||||
var/msg_body = ""
|
||||
var/msg_recipient = ""
|
||||
var/datum/computer_file/msg_attachment = null
|
||||
var/folder = "Inbox"
|
||||
var/addressbook = FALSE
|
||||
var/new_message = FALSE
|
||||
|
||||
var/last_message_count = 0 // How many messages were there during last check.
|
||||
var/read_message_count = 0 // How many messages were there when user has last accessed the UI.
|
||||
|
||||
var/datum/computer_file/downloading = null
|
||||
var/download_progress = 0
|
||||
var/download_speed = 0
|
||||
|
||||
var/datum/computer_file/data/email_account/current_account = null
|
||||
var/datum/computer_file/data/email_message/current_message = null
|
||||
|
||||
/datum/nano_module/email_client/proc/log_in()
|
||||
for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts)
|
||||
if(!account.can_login)
|
||||
continue
|
||||
if(account.login == stored_login)
|
||||
if(account.password == stored_password)
|
||||
if(account.suspended)
|
||||
error = "This account has been suspended. Please contact the system administrator for assistance."
|
||||
return 0
|
||||
current_account = account
|
||||
return 1
|
||||
else
|
||||
error = "Invalid Password"
|
||||
return 0
|
||||
error = "Invalid Login"
|
||||
return 0
|
||||
|
||||
// Returns 0 if no new messages were received, 1 if there is an unread message but notification has already been sent.
|
||||
// and 2 if there is a new message that appeared in this tick (and therefore notification should be sent by the program).
|
||||
/datum/nano_module/email_client/proc/check_for_new_messages(var/messages_read = FALSE)
|
||||
if(!current_account)
|
||||
return 0
|
||||
|
||||
var/list/allmails = current_account.all_emails()
|
||||
|
||||
if(allmails.len > last_message_count)
|
||||
. = 2
|
||||
else if(allmails.len > read_message_count)
|
||||
. = 1
|
||||
else
|
||||
. = 0
|
||||
|
||||
last_message_count = allmails.len
|
||||
if(messages_read)
|
||||
read_message_count = allmails.len
|
||||
|
||||
|
||||
/datum/nano_module/email_client/proc/log_out()
|
||||
current_account = null
|
||||
downloading = null
|
||||
download_progress = 0
|
||||
last_message_count = 0
|
||||
read_message_count = 0
|
||||
|
||||
/datum/nano_module/email_client/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
// Password has been changed by other client connected to this email account
|
||||
if(current_account)
|
||||
if(current_account.password != stored_password)
|
||||
log_out()
|
||||
error = "Invalid Password"
|
||||
// Banned.
|
||||
if(current_account.suspended)
|
||||
log_out()
|
||||
error = "This account has been suspended. Please contact the system administrator for assistance."
|
||||
|
||||
if(error)
|
||||
data["error"] = error
|
||||
else if(downloading)
|
||||
data["downloading"] = 1
|
||||
data["down_filename"] = "[downloading.filename].[downloading.filetype]"
|
||||
data["down_progress"] = download_progress
|
||||
data["down_size"] = downloading.size
|
||||
data["down_speed"] = download_speed
|
||||
|
||||
else if(istype(current_account))
|
||||
data["current_account"] = current_account.login
|
||||
if(addressbook)
|
||||
var/list/all_accounts = list()
|
||||
for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts)
|
||||
if(!account.can_login)
|
||||
continue
|
||||
all_accounts.Add(list(list(
|
||||
"login" = account.login
|
||||
)))
|
||||
data["addressbook"] = 1
|
||||
data["accounts"] = all_accounts
|
||||
else if(new_message)
|
||||
data["new_message"] = 1
|
||||
data["msg_title"] = msg_title
|
||||
data["msg_body"] = pencode2html(msg_body)
|
||||
data["msg_recipient"] = msg_recipient
|
||||
if(msg_attachment)
|
||||
data["msg_hasattachment"] = 1
|
||||
data["msg_attachment_filename"] = "[msg_attachment.filename].[msg_attachment.filetype]"
|
||||
data["msg_attachment_size"] = msg_attachment.size
|
||||
else if (current_message)
|
||||
data["cur_title"] = current_message.title
|
||||
data["cur_body"] = pencode2html(current_message.stored_data)
|
||||
data["cur_timestamp"] = current_message.timestamp
|
||||
data["cur_source"] = current_message.source
|
||||
data["cur_uid"] = current_message.uid
|
||||
if(istype(current_message.attachment))
|
||||
data["cur_hasattachment"] = 1
|
||||
data["cur_attachment_filename"] = "[current_message.attachment.filename].[current_message.attachment.filetype]"
|
||||
data["cur_attachment_size"] = current_message.attachment.size
|
||||
else
|
||||
data["label_inbox"] = "Inbox ([current_account.inbox.len])"
|
||||
data["label_spam"] = "Spam ([current_account.spam.len])"
|
||||
data["label_deleted"] = "Deleted ([current_account.deleted.len])"
|
||||
var/list/message_source
|
||||
if(folder == "Inbox")
|
||||
message_source = current_account.inbox
|
||||
else if(folder == "Spam")
|
||||
message_source = current_account.spam
|
||||
else if(folder == "Deleted")
|
||||
message_source = current_account.deleted
|
||||
|
||||
if(message_source)
|
||||
data["folder"] = folder
|
||||
var/list/all_messages = list()
|
||||
for(var/datum/computer_file/data/email_message/message in message_source)
|
||||
all_messages.Add(list(list(
|
||||
"title" = message.title,
|
||||
"body" = pencode2html(message.stored_data),
|
||||
"source" = message.source,
|
||||
"timestamp" = message.timestamp,
|
||||
"uid" = message.uid
|
||||
)))
|
||||
data["messages"] = all_messages
|
||||
data["messagecount"] = all_messages.len
|
||||
else
|
||||
data["stored_login"] = stored_login
|
||||
data["stored_password"] = stars(stored_password, 0)
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "email_client.tmpl", "Email Client", 600, 450, state = state)
|
||||
if(host.update_layout())
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_auto_update(1)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/datum/nano_module/email_client/proc/find_message_by_fuid(var/fuid)
|
||||
if(!istype(current_account))
|
||||
return
|
||||
|
||||
// href_list works with strings, so this makes it a bit easier for us
|
||||
if(istext(fuid))
|
||||
fuid = text2num(fuid)
|
||||
|
||||
for(var/datum/computer_file/data/email_message/message in current_account.all_emails())
|
||||
if(message.uid == fuid)
|
||||
return message
|
||||
|
||||
/datum/nano_module/email_client/proc/clear_message()
|
||||
new_message = FALSE
|
||||
msg_title = ""
|
||||
msg_body = ""
|
||||
msg_recipient = ""
|
||||
msg_attachment = null
|
||||
current_message = null
|
||||
|
||||
/datum/nano_module/email_client/proc/relayed_process(var/netspeed)
|
||||
download_speed = netspeed
|
||||
if(!downloading)
|
||||
return
|
||||
download_progress = min(download_progress + netspeed, downloading.size)
|
||||
if(download_progress >= downloading.size)
|
||||
var/obj/item/modular_computer/MC = nano_host()
|
||||
if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality())
|
||||
error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?"
|
||||
downloading = null
|
||||
download_progress = 0
|
||||
return 1
|
||||
|
||||
if(MC.hard_drive.store_file(downloading))
|
||||
error = "File successfully downloaded to local device."
|
||||
else
|
||||
error = "Error saving file: I/O Error: The hard drive may be full or nonfunctional."
|
||||
downloading = null
|
||||
download_progress = 0
|
||||
return 1
|
||||
|
||||
|
||||
/datum/nano_module/email_client/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
var/mob/living/user = usr
|
||||
check_for_new_messages(1) // Any actual interaction (button pressing) is considered as acknowledging received message, for the purpose of notification icons.
|
||||
if(href_list["login"])
|
||||
log_in()
|
||||
return 1
|
||||
|
||||
if(href_list["logout"])
|
||||
log_out()
|
||||
return 1
|
||||
|
||||
if(href_list["reset"])
|
||||
error = ""
|
||||
return 1
|
||||
|
||||
if(href_list["new_message"])
|
||||
new_message = TRUE
|
||||
return 1
|
||||
|
||||
if(href_list["cancel"])
|
||||
if(addressbook)
|
||||
addressbook = FALSE
|
||||
else
|
||||
clear_message()
|
||||
return 1
|
||||
|
||||
if(href_list["addressbook"])
|
||||
addressbook = TRUE
|
||||
return 1
|
||||
|
||||
if(href_list["set_recipient"])
|
||||
msg_recipient = sanitize(href_list["set_recipient"])
|
||||
addressbook = FALSE
|
||||
return 1
|
||||
|
||||
if(href_list["edit_title"])
|
||||
var/newtitle = sanitize(input(user,"Enter title for your message:", "Message title", msg_title), 100)
|
||||
if(newtitle)
|
||||
msg_title = newtitle
|
||||
return 1
|
||||
|
||||
// This uses similar editing mechanism as the FileManager program, therefore it supports various paper tags and remembers formatting.
|
||||
if(href_list["edit_body"])
|
||||
var/oldtext = html_decode(msg_body)
|
||||
oldtext = replacetext(oldtext, "\[editorbr\]", "\n")
|
||||
|
||||
var/newtext = sanitize(replacetext(input(usr, "Enter your message. You may use most tags from paper formatting", "Message Editor", oldtext) as message|null, "\n", "\[editorbr\]"), 20000)
|
||||
if(newtext)
|
||||
msg_body = newtext
|
||||
return 1
|
||||
|
||||
if(href_list["edit_recipient"])
|
||||
var/newrecipient = sanitize(input(user,"Enter recipient's email address:", "Recipient", msg_recipient), 100)
|
||||
if(newrecipient)
|
||||
msg_recipient = newrecipient
|
||||
return 1
|
||||
|
||||
if(href_list["edit_login"])
|
||||
var/newlogin = sanitize(input(user,"Enter login", "Login", stored_login), 100)
|
||||
if(newlogin)
|
||||
stored_login = newlogin
|
||||
return 1
|
||||
|
||||
if(href_list["edit_password"])
|
||||
var/newpass = sanitize(input(user,"Enter password", "Password"), 100)
|
||||
if(newpass)
|
||||
stored_password = newpass
|
||||
return 1
|
||||
|
||||
if(href_list["delete"])
|
||||
if(!istype(current_account))
|
||||
return 1
|
||||
var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["delete"])
|
||||
if(!istype(M))
|
||||
return 1
|
||||
if(folder == "Deleted")
|
||||
current_account.deleted.Remove(M)
|
||||
qdel(M)
|
||||
else
|
||||
current_account.deleted.Add(M)
|
||||
current_account.inbox.Remove(M)
|
||||
current_account.spam.Remove(M)
|
||||
if(current_message == M)
|
||||
current_message = null
|
||||
return 1
|
||||
|
||||
if(href_list["send"])
|
||||
if(!current_account)
|
||||
return 1
|
||||
if((msg_title == "") || (msg_body == "") || (msg_recipient == ""))
|
||||
error = "Error sending mail: Title or message body is empty!"
|
||||
return 1
|
||||
|
||||
var/datum/computer_file/data/email_message/message = new()
|
||||
message.title = msg_title
|
||||
message.stored_data = msg_body
|
||||
message.source = current_account.login
|
||||
message.attachment = msg_attachment
|
||||
if(!current_account.send_mail(msg_recipient, message))
|
||||
error = "Error sending email: this address doesn't exist."
|
||||
return 1
|
||||
else
|
||||
error = "Email successfully sent."
|
||||
clear_message()
|
||||
return 1
|
||||
|
||||
if(href_list["set_folder"])
|
||||
folder = href_list["set_folder"]
|
||||
return 1
|
||||
|
||||
if(href_list["reply"])
|
||||
var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["reply"])
|
||||
if(!istype(M))
|
||||
return 1
|
||||
|
||||
new_message = TRUE
|
||||
msg_recipient = M.source
|
||||
msg_title = "Re: [M.title]"
|
||||
msg_body = "\[editorbr\]\[editorbr\]\[editorbr\]\[br\]==============================\[br\]\[editorbr\]"
|
||||
msg_body += "Received by [current_account.login] at [M.timestamp]\[br\]\[editorbr\][M.stored_data]"
|
||||
return 1
|
||||
|
||||
if(href_list["view"])
|
||||
var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["view"])
|
||||
if(istype(M))
|
||||
current_message = M
|
||||
return 1
|
||||
|
||||
if(href_list["changepassword"])
|
||||
var/oldpassword = sanitize(input(user,"Please enter your old password:", "Password Change"), 100)
|
||||
if(!oldpassword)
|
||||
return 1
|
||||
var/newpassword1 = sanitize(input(user,"Please enter your new password:", "Password Change"), 100)
|
||||
if(!newpassword1)
|
||||
return 1
|
||||
var/newpassword2 = sanitize(input(user,"Please re-enter your new password:", "Password Change"), 100)
|
||||
if(!newpassword2)
|
||||
return 1
|
||||
|
||||
if(!istype(current_account))
|
||||
error = "Please log in before proceeding."
|
||||
return 1
|
||||
|
||||
if(current_account.password != oldpassword)
|
||||
error = "Incorrect original password"
|
||||
return 1
|
||||
|
||||
if(newpassword1 != newpassword2)
|
||||
error = "The entered passwords do not match."
|
||||
return 1
|
||||
|
||||
current_account.password = newpassword1
|
||||
stored_password = newpassword1
|
||||
error = "Your password has been successfully changed!"
|
||||
return 1
|
||||
|
||||
// The following entries are Modular Computer framework only, and therefore won't do anything in other cases (like AI View)
|
||||
|
||||
if(href_list["save"])
|
||||
// Fully dependant on modular computers here.
|
||||
var/obj/item/modular_computer/MC = nano_host()
|
||||
|
||||
if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality())
|
||||
error = "Error exporting file. Are you using a functional and NTOS-compliant device?"
|
||||
return 1
|
||||
|
||||
var/filename = sanitize(input(user,"Please specify file name:", "Message export"), 100)
|
||||
if(!filename)
|
||||
return 1
|
||||
|
||||
var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["save"])
|
||||
var/datum/computer_file/data/mail = istype(M) ? M.export() : null
|
||||
if(!istype(mail))
|
||||
return 1
|
||||
mail.filename = filename
|
||||
if(!MC.hard_drive || !MC.hard_drive.store_file(mail))
|
||||
error = "Internal I/O error when writing file, the hard drive may be full."
|
||||
else
|
||||
error = "Email exported successfully"
|
||||
return 1
|
||||
|
||||
if(href_list["addattachment"])
|
||||
var/obj/item/modular_computer/MC = nano_host()
|
||||
msg_attachment = null
|
||||
|
||||
if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality())
|
||||
error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?"
|
||||
return 1
|
||||
|
||||
var/list/filenames = list()
|
||||
for(var/datum/computer_file/CF in MC.hard_drive.stored_files)
|
||||
if(CF.unsendable)
|
||||
continue
|
||||
filenames.Add(CF.filename)
|
||||
var/picked_file = input(user, "Please pick a file to send as attachment (max 32GQ)") as null|anything in filenames
|
||||
|
||||
if(!picked_file)
|
||||
return 1
|
||||
|
||||
if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality())
|
||||
error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?"
|
||||
return 1
|
||||
|
||||
for(var/datum/computer_file/CF in MC.hard_drive.stored_files)
|
||||
if(CF.unsendable)
|
||||
continue
|
||||
if(CF.filename == picked_file)
|
||||
msg_attachment = CF.clone()
|
||||
break
|
||||
if(!istype(msg_attachment))
|
||||
msg_attachment = null
|
||||
error = "Unknown error when uploading attachment."
|
||||
return 1
|
||||
|
||||
if(msg_attachment.size > 32)
|
||||
error = "Error uploading attachment: File exceeds maximal permitted file size of 32GQ."
|
||||
msg_attachment = null
|
||||
else
|
||||
error = "File [msg_attachment.filename].[msg_attachment.filetype] has been successfully uploaded."
|
||||
return 1
|
||||
|
||||
if(href_list["downloadattachment"])
|
||||
if(!current_account || !current_message || !current_message.attachment)
|
||||
return 1
|
||||
var/obj/item/modular_computer/MC = nano_host()
|
||||
if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality())
|
||||
error = "Error downloading file. Are you using a functional and NTOSv2-compliant device?"
|
||||
return 1
|
||||
|
||||
downloading = current_message.attachment.clone()
|
||||
download_progress = 0
|
||||
return 1
|
||||
|
||||
if(href_list["canceldownload"])
|
||||
downloading = null
|
||||
download_progress = 0
|
||||
return 1
|
||||
|
||||
if(href_list["remove_attachment"])
|
||||
msg_attachment = null
|
||||
return 1
|
||||
@@ -6,202 +6,190 @@
|
||||
program_key_state = "generic_key"
|
||||
program_menu_icon = "folder-collapsed"
|
||||
size = 8
|
||||
requires_ntnet = 0
|
||||
available_on_ntnet = 0
|
||||
undeletable = 1
|
||||
nanomodule_path = /datum/nano_module/program/computer_filemanager/
|
||||
requires_ntnet = FALSE
|
||||
available_on_ntnet = FALSE
|
||||
undeletable = TRUE
|
||||
tgui_id = "NtosFileManager"
|
||||
|
||||
var/open_file
|
||||
var/error
|
||||
|
||||
/datum/computer_file/program/filemanager/Topic(href, href_list)
|
||||
/datum/computer_file/program/filemanager/tgui_act(action, list/params, datum/tgui/ui)
|
||||
if(..())
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_openfile"])
|
||||
. = 1
|
||||
open_file = href_list["PRG_openfile"]
|
||||
if(href_list["PRG_newtextfile"])
|
||||
. = 1
|
||||
var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename"))
|
||||
if(!newname)
|
||||
return 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/data/F = new/datum/computer_file/data()
|
||||
F.filename = newname
|
||||
F.filetype = "TXT"
|
||||
HDD.store_file(F)
|
||||
if(href_list["PRG_deletefile"])
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/file = HDD.find_file_by_name(href_list["PRG_deletefile"])
|
||||
if(!file || file.undeletable)
|
||||
return 1
|
||||
HDD.remove_file(file)
|
||||
if(href_list["PRG_usbdeletefile"])
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.portable_drive
|
||||
if(!RHDD)
|
||||
return 1
|
||||
var/datum/computer_file/file = RHDD.find_file_by_name(href_list["PRG_usbdeletefile"])
|
||||
if(!file || file.undeletable)
|
||||
return 1
|
||||
RHDD.remove_file(file)
|
||||
if(href_list["PRG_closefile"])
|
||||
. = 1
|
||||
open_file = null
|
||||
error = null
|
||||
if(href_list["PRG_clone"])
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(href_list["PRG_clone"])
|
||||
if(!F || !istype(F))
|
||||
return 1
|
||||
var/datum/computer_file/C = F.clone(1)
|
||||
HDD.store_file(C)
|
||||
if(href_list["PRG_rename"])
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/file = HDD.find_file_by_name(href_list["PRG_rename"])
|
||||
if(!file || !istype(file))
|
||||
return 1
|
||||
var/newname = sanitize(input(usr, "Enter new file name:", "File rename", file.filename))
|
||||
if(file && newname)
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.portable_drive
|
||||
|
||||
switch(action)
|
||||
if("PRG_openfile")
|
||||
open_file = params["name"]
|
||||
return TRUE
|
||||
if("PRG_newtextfile")
|
||||
if(!HDD)
|
||||
return
|
||||
var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename"))
|
||||
if(!newname)
|
||||
return
|
||||
var/datum/computer_file/data/F = new/datum/computer_file/data()
|
||||
F.filename = newname
|
||||
F.filetype = "TXT"
|
||||
HDD.store_file(F)
|
||||
return TRUE
|
||||
if("PRG_closefile")
|
||||
open_file = null
|
||||
error = null
|
||||
return TRUE
|
||||
if("PRG_clone")
|
||||
if(!HDD)
|
||||
return
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params["name"])
|
||||
if(!F || !istype(F))
|
||||
return
|
||||
var/datum/computer_file/C = F.clone(1)
|
||||
HDD.store_file(C)
|
||||
return TRUE
|
||||
if("PRG_edit")
|
||||
if(!HDD)
|
||||
return
|
||||
if(!open_file)
|
||||
return
|
||||
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
|
||||
if(!F || !istype(F))
|
||||
return
|
||||
if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No"))
|
||||
return
|
||||
|
||||
var/oldtext = html_decode(F.stored_data)
|
||||
oldtext = replacetext(oldtext, "\[br\]", "\n")
|
||||
|
||||
var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH)
|
||||
if(!newtext)
|
||||
return
|
||||
|
||||
if(F)
|
||||
var/datum/computer_file/data/backup = F.clone()
|
||||
HDD.remove_file(F)
|
||||
F.stored_data = newtext
|
||||
F.calculate_size()
|
||||
// We can't store the updated file, it's probably too large. Print an error and restore backed up version.
|
||||
// This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space.
|
||||
// They will be able to copy-paste the text from error screen and store it in notepad or something.
|
||||
if(!HDD.store_file(F))
|
||||
error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:<br><br>[html_decode(F.stored_data)]<br><br>"
|
||||
HDD.store_file(backup)
|
||||
return TRUE
|
||||
if("PRG_printfile")
|
||||
if(!HDD)
|
||||
return
|
||||
if(!open_file)
|
||||
return
|
||||
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
|
||||
if(!F || !istype(F))
|
||||
return
|
||||
if(!computer.nano_printer)
|
||||
error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
|
||||
return
|
||||
if(!computer.nano_printer.print_text(pencode2html(F.stored_data)))
|
||||
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
|
||||
return
|
||||
return TRUE
|
||||
if("PRG_deletefile")
|
||||
if(!HDD)
|
||||
return
|
||||
var/datum/computer_file/file = HDD.find_file_by_name(params["name"])
|
||||
if(!file || file.undeletable)
|
||||
return
|
||||
HDD.remove_file(file)
|
||||
return TRUE
|
||||
if("PRG_usbdeletefile")
|
||||
if(!RHDD)
|
||||
return
|
||||
var/datum/computer_file/file = RHDD.find_file_by_name(params["name"])
|
||||
if(!file || file.undeletable)
|
||||
return
|
||||
RHDD.remove_file(file)
|
||||
return TRUE
|
||||
if("PRG_rename")
|
||||
if(!HDD)
|
||||
return
|
||||
var/datum/computer_file/file = HDD.find_file_by_name(params["name"])
|
||||
if(!file)
|
||||
return
|
||||
var/newname = params["new_name"]
|
||||
if(!newname)
|
||||
return
|
||||
file.filename = newname
|
||||
if(href_list["PRG_edit"])
|
||||
. = 1
|
||||
if(!open_file)
|
||||
return 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
|
||||
if(!F || !istype(F))
|
||||
return 1
|
||||
if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No"))
|
||||
return 1
|
||||
return TRUE
|
||||
if("PRG_copytousb")
|
||||
if(!HDD || !RHDD)
|
||||
return
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params["name"])
|
||||
if(!F)
|
||||
return
|
||||
var/datum/computer_file/C = F.clone(FALSE)
|
||||
RHDD.store_file(C)
|
||||
return TRUE
|
||||
if("PRG_copyfromusb")
|
||||
if(!HDD || !RHDD)
|
||||
return
|
||||
var/datum/computer_file/F = RHDD.find_file_by_name(params["name"])
|
||||
if(!F || !istype(F))
|
||||
return
|
||||
var/datum/computer_file/C = F.clone(FALSE)
|
||||
HDD.store_file(C)
|
||||
return TRUE
|
||||
|
||||
var/oldtext = html_decode(F.stored_data)
|
||||
oldtext = replacetext(oldtext, "\[br\]", "\n")
|
||||
/datum/computer_file/program/filemanager/tgui_data(mob/user)
|
||||
var/list/data = get_header_data()
|
||||
|
||||
var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH)
|
||||
if(!newtext)
|
||||
return
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
|
||||
|
||||
if(F)
|
||||
var/datum/computer_file/data/backup = F.clone()
|
||||
HDD.remove_file(F)
|
||||
F.stored_data = newtext
|
||||
F.calculate_size()
|
||||
// We can't store the updated file, it's probably too large. Print an error and restore backed up version.
|
||||
// This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space.
|
||||
// They will be able to copy-paste the text from error screen and store it in notepad or something.
|
||||
if(!HDD.store_file(F))
|
||||
error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:<br><br>[html_decode(F.stored_data)]<br><br>"
|
||||
HDD.store_file(backup)
|
||||
if(href_list["PRG_printfile"])
|
||||
. = 1
|
||||
if(!open_file)
|
||||
return 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
|
||||
if(!F || !istype(F))
|
||||
return 1
|
||||
if(!computer.nano_printer)
|
||||
error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
|
||||
return 1
|
||||
if(!computer.nano_printer.print_text(pencode2html(F.stored_data)))
|
||||
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
|
||||
return 1
|
||||
if(href_list["PRG_copytousb"])
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
|
||||
if(!HDD || !RHDD)
|
||||
return 1
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(href_list["PRG_copytousb"])
|
||||
if(!F || !istype(F))
|
||||
return 1
|
||||
var/datum/computer_file/C = F.clone(0)
|
||||
RHDD.store_file(C)
|
||||
if(href_list["PRG_copyfromusb"])
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
|
||||
if(!HDD || !RHDD)
|
||||
return 1
|
||||
var/datum/computer_file/F = RHDD.find_file_by_name(href_list["PRG_copyfromusb"])
|
||||
if(!F || !istype(F))
|
||||
return 1
|
||||
var/datum/computer_file/C = F.clone(0)
|
||||
HDD.store_file(C)
|
||||
if(.)
|
||||
SSnanoui.update_uis(NM)
|
||||
data["error"] = null
|
||||
if(error)
|
||||
data["error"] = error
|
||||
if(!computer || !HDD)
|
||||
data["error"] = "I/O ERROR: Unable to access hard drive."
|
||||
|
||||
data["filedata"] = null
|
||||
data["filename"] = null
|
||||
data["files"] = list()
|
||||
data["usbconnected"] = FALSE
|
||||
data["usbfiles"] = list()
|
||||
|
||||
/datum/nano_module/program/computer_filemanager
|
||||
name = "NTOS File Manager"
|
||||
|
||||
/datum/nano_module/program/computer_filemanager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
var/datum/computer_file/program/filemanager/PRG
|
||||
PRG = program
|
||||
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD
|
||||
if(PRG.error)
|
||||
data["error"] = PRG.error
|
||||
if(PRG.open_file)
|
||||
if(open_file)
|
||||
var/datum/computer_file/data/file
|
||||
|
||||
if(!PRG.computer || !PRG.computer.hard_drive)
|
||||
if(!computer || !computer.hard_drive)
|
||||
data["error"] = "I/O ERROR: Unable to access hard drive."
|
||||
else
|
||||
HDD = PRG.computer.hard_drive
|
||||
file = HDD.find_file_by_name(PRG.open_file)
|
||||
file = HDD.find_file_by_name(open_file)
|
||||
if(!istype(file))
|
||||
data["error"] = "I/O ERROR: Unable to open file."
|
||||
else
|
||||
data["filedata"] = pencode2html(file.stored_data)
|
||||
data["filename"] = "[file.filename].[file.filetype]"
|
||||
else
|
||||
if(!PRG.computer || !PRG.computer.hard_drive)
|
||||
data["error"] = "I/O ERROR: Unable to access hard drive."
|
||||
else
|
||||
HDD = PRG.computer.hard_drive
|
||||
RHDD = PRG.computer.portable_drive
|
||||
var/list/files[0]
|
||||
for(var/datum/computer_file/F in HDD.stored_files)
|
||||
files.Add(list(list(
|
||||
var/list/files = list()
|
||||
for(var/datum/computer_file/F in HDD.stored_files)
|
||||
files += list(list(
|
||||
"name" = F.filename,
|
||||
"type" = F.filetype,
|
||||
"size" = F.size,
|
||||
"undeletable" = F.undeletable
|
||||
))
|
||||
data["files"] = files
|
||||
if(RHDD)
|
||||
data["usbconnected"] = TRUE
|
||||
var/list/usbfiles = list()
|
||||
for(var/datum/computer_file/F in RHDD.stored_files)
|
||||
usbfiles += list(list(
|
||||
"name" = F.filename,
|
||||
"type" = F.filetype,
|
||||
"size" = F.size,
|
||||
"undeletable" = F.undeletable
|
||||
)))
|
||||
data["files"] = files
|
||||
if(RHDD)
|
||||
data["usbconnected"] = 1
|
||||
var/list/usbfiles[0]
|
||||
for(var/datum/computer_file/F in RHDD.stored_files)
|
||||
usbfiles.Add(list(list(
|
||||
"name" = F.filename,
|
||||
"type" = F.filetype,
|
||||
"size" = F.size,
|
||||
"undeletable" = F.undeletable
|
||||
)))
|
||||
data["usbfiles"] = usbfiles
|
||||
))
|
||||
data["usbfiles"] = usbfiles
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "file_manager.tmpl", "NTOS File Manager", 575, 700, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
return data
|
||||
|
||||
@@ -1,152 +1,188 @@
|
||||
// This file is used as a reference for Modular Computers Development guide on the wiki. It contains a lot of excess comments, as it is intended as explanation
|
||||
// for someone who may not be as experienced in coding. When making changes, please try to keep it this way.
|
||||
|
||||
// An actual program definition.
|
||||
/datum/computer_file/program/game
|
||||
filename = "arcadec" // File name, as shown in the file browser program.
|
||||
filedesc = "Unknown Game" // User-Friendly name. In this case, we will generate a random name in constructor.
|
||||
program_icon_state = "game" // Icon state of this program's screen.
|
||||
program_menu_icon = "script"
|
||||
extended_desc = "Fun for the whole family! Probably not an AAA title, but at least you can download it on the corporate network.." // A nice description.
|
||||
size = 5 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs.
|
||||
requires_ntnet = 0 // This particular program does not require NTNet network conectivity...
|
||||
available_on_ntnet = 1 // ... but we want it to be available for download.
|
||||
nanomodule_path = /datum/nano_module/arcade_classic/ // Path of relevant nano module. The nano module is defined further in the file.
|
||||
var/picked_enemy_name
|
||||
filename = "dsarcade" // File name, as shown in the file browser program.
|
||||
filedesc = "Donksoft Micro Arcade" // User-Friendly name.
|
||||
program_icon_state = "arcade" // Icon state of this program's screen.
|
||||
extended_desc = "This is a port of the classic game 'Outbomb Cuban Pete', redesigned to run on tablets; Now with thrilling graphics and chilling storytelling." // A nice description.
|
||||
size = 6 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs.
|
||||
requires_ntnet = FALSE // This particular program does not require NTNet network conectivity...
|
||||
available_on_ntnet = TRUE // ... but we want it to be available for download.
|
||||
tgui_id = "NtosArcade" // Path of relevant tgui template.js file.
|
||||
|
||||
// Blatantly stolen and shortened version from arcade machines. Generates a random enemy name
|
||||
/datum/computer_file/program/game/proc/random_enemy_name()
|
||||
var/name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ")
|
||||
var/name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "Slime", "Lizard Man", "Unicorn")
|
||||
return "[name_part1] [name_part2]"
|
||||
///Returns TRUE if the game is being played.
|
||||
var/game_active = TRUE
|
||||
///This disables buttom actions from having any impact if TRUE. Resets to FALSE when the player is allowed to make an action again.
|
||||
var/pause_state = FALSE
|
||||
var/boss_hp = 45
|
||||
var/boss_mp = 15
|
||||
var/player_hp = 30
|
||||
var/player_mp = 10
|
||||
var/ticket_count = 0
|
||||
///Shows what text is shown on the app, usually showing the log of combat actions taken by the player.
|
||||
var/heads_up = "Nanotrasen says, winners make us money."
|
||||
var/boss_name = "Cuban Pete's Minion"
|
||||
///Determines which boss image to use on the UI.
|
||||
var/boss_id = 1
|
||||
|
||||
// When the program is first created, we generate a new enemy name and name ourselves accordingly.
|
||||
/datum/computer_file/program/game/New()
|
||||
..()
|
||||
picked_enemy_name = random_enemy_name()
|
||||
filedesc = "Defeat [picked_enemy_name]"
|
||||
// This is the primary game loop, which handles the logic of being defeated or winning.
|
||||
/datum/computer_file/program/game/proc/game_check(mob/user)
|
||||
sleep(5)
|
||||
if(boss_hp <= 0)
|
||||
heads_up = "You have crushed [boss_name]! Rejoice!"
|
||||
playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3, falloff = 10)
|
||||
game_active = FALSE
|
||||
program_icon_state = "arcade_off"
|
||||
if(istype(computer))
|
||||
computer.update_icon()
|
||||
ticket_count += 1
|
||||
// user?.mind?.adjust_experience(/datum/skill/gaming, 50)
|
||||
sleep(10)
|
||||
else if(player_hp <= 0 || player_mp <= 0)
|
||||
heads_up = "You have been defeated... how will the station survive?"
|
||||
playsound(computer.loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3, falloff = 10)
|
||||
game_active = FALSE
|
||||
program_icon_state = "arcade_off"
|
||||
if(istype(computer))
|
||||
computer.update_icon()
|
||||
// user?.mind?.adjust_experience(/datum/skill/gaming, 10)
|
||||
sleep(10)
|
||||
|
||||
// Important in order to ensure that copied versions will have the same enemy name.
|
||||
/datum/computer_file/program/game/clone()
|
||||
var/datum/computer_file/program/game/G = ..()
|
||||
G.picked_enemy_name = picked_enemy_name
|
||||
return G
|
||||
|
||||
// When running the program, we also want to pass our enemy name to the nano module.
|
||||
/datum/computer_file/program/game/run_program()
|
||||
. = ..()
|
||||
if(. && NM)
|
||||
var/datum/nano_module/arcade_classic/NMC = NM
|
||||
NMC.enemy_name = picked_enemy_name
|
||||
|
||||
|
||||
// Nano module the program uses.
|
||||
// This can be either /datum/nano_module/ or /datum/nano_module/program. The latter is intended for nano modules that are suposed to be exclusively used with modular computers,
|
||||
// and should generally not be used, as such nano modules are hard to use on other places.
|
||||
/datum/nano_module/arcade_classic/
|
||||
name = "Classic Arcade"
|
||||
var/player_mana // Various variables specific to the nano module. In this case, the nano module is a simple arcade game, so the variables store health and other stats.
|
||||
var/player_health
|
||||
var/enemy_mana
|
||||
var/enemy_health
|
||||
var/enemy_name = "Greytide Horde"
|
||||
var/gameover
|
||||
var/information
|
||||
|
||||
/datum/nano_module/arcade_classic/New()
|
||||
..()
|
||||
new_game()
|
||||
|
||||
// ui_interact handles transfer of data to NanoUI. Keep in mind that data you pass from here is actually sent to the client. In other words, don't send anything you don't want a client
|
||||
// to see, and don't send unnecessarily large amounts of data (due to laginess).
|
||||
/datum/nano_module/arcade_classic/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
data["player_health"] = player_health
|
||||
data["player_mana"] = player_mana
|
||||
data["enemy_health"] = enemy_health
|
||||
data["enemy_mana"] = enemy_mana
|
||||
data["enemy_name"] = enemy_name
|
||||
data["gameover"] = gameover
|
||||
data["information"] = information
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "arcade_classic.tmpl", "Defeat [enemy_name]", 500, 350, state = state)
|
||||
if(host.update_layout())
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
// Three helper procs i've created. These are unique to this particular nano module. If you are creating your own nano module, you'll most likely create similar procs too.
|
||||
/datum/nano_module/arcade_classic/proc/enemy_play()
|
||||
if((enemy_mana < 5) && prob(60))
|
||||
var/steal = rand(2, 3)
|
||||
player_mana -= steal
|
||||
enemy_mana += steal
|
||||
information += "[enemy_name] steals [steal] of your power!"
|
||||
else if((enemy_health < 15) && (enemy_mana > 3) && prob(80))
|
||||
var/healamt = min(rand(3, 5), enemy_mana)
|
||||
enemy_mana -= healamt
|
||||
enemy_health += healamt
|
||||
information += "[enemy_name] heals for [healamt] health!"
|
||||
// This handles the boss "AI".
|
||||
/datum/computer_file/program/game/proc/enemy_check(mob/user)
|
||||
var/boss_attackamt = 0 //Spam protection from boss attacks as well.
|
||||
var/boss_mpamt = 0
|
||||
var/bossheal = 0
|
||||
if(pause_state == TRUE)
|
||||
boss_attackamt = rand(3,6)
|
||||
boss_mpamt = rand (2,4)
|
||||
bossheal = rand (4,6)
|
||||
if(game_active == FALSE)
|
||||
return
|
||||
if(boss_mp <= 5)
|
||||
heads_up = "[boss_mpamt] magic power has been stolen from you!"
|
||||
playsound(computer.loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3, falloff = 10)
|
||||
player_mp -= boss_mpamt
|
||||
boss_mp += boss_mpamt
|
||||
else if(boss_mp > 5 && boss_hp <12)
|
||||
heads_up = "[boss_name] heals for [bossheal] health!"
|
||||
playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10)
|
||||
boss_hp += bossheal
|
||||
boss_mp -= boss_mpamt
|
||||
else
|
||||
var/dam = rand(3,6)
|
||||
player_health -= dam
|
||||
information += "[enemy_name] attacks for [dam] damage!"
|
||||
heads_up = "[boss_name] attacks you for [boss_attackamt] damage!"
|
||||
playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10)
|
||||
player_hp -= boss_attackamt
|
||||
|
||||
/datum/nano_module/arcade_classic/proc/check_gameover()
|
||||
if((player_health <= 0) || player_mana <= 0)
|
||||
if(enemy_health <= 0)
|
||||
information += "You have defeated [enemy_name], but you have died in the fight!"
|
||||
else
|
||||
information += "You have been defeated by [enemy_name]!"
|
||||
gameover = 1
|
||||
pause_state = FALSE
|
||||
game_check()
|
||||
|
||||
/**
|
||||
* UI assets define a list of asset datums to be sent with the UI.
|
||||
* In this case, it's a bunch of cute enemy sprites.
|
||||
*/
|
||||
/datum/computer_file/program/game/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/simple/arcade),
|
||||
)
|
||||
|
||||
/**
|
||||
* This provides all of the relevant data to the UI in a list().
|
||||
*/
|
||||
/datum/computer_file/program/game/tgui_data(mob/user)
|
||||
var/list/data = get_header_data()
|
||||
data["Hitpoints"] = boss_hp
|
||||
data["PlayerHitpoints"] = player_hp
|
||||
data["PlayerMP"] = player_mp
|
||||
data["TicketCount"] = ticket_count
|
||||
data["GameActive"] = game_active
|
||||
data["PauseState"] = pause_state
|
||||
data["Status"] = heads_up
|
||||
data["BossID"] = "boss[boss_id].gif"
|
||||
return data
|
||||
|
||||
/**
|
||||
* This is tgui's replacement for Topic(). It handles any user input from the UI.
|
||||
*/
|
||||
/datum/computer_file/program/game/tgui_act(action, list/params)
|
||||
if(..()) // Always call parent in tgui_act, it handles making sure the user is allowed to interact with the UI.
|
||||
return TRUE
|
||||
else if(enemy_health <= 0)
|
||||
gameover = 1
|
||||
information += "Congratulations! You have defeated [enemy_name]!"
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nano_module/arcade_classic/proc/new_game()
|
||||
player_mana = 10
|
||||
player_health = 30
|
||||
enemy_mana = 20
|
||||
enemy_health = 45
|
||||
gameover = FALSE
|
||||
information = "A new game has started!"
|
||||
var/obj/item/weapon/computer_hardware/nano_printer/printer
|
||||
if(computer)
|
||||
printer = computer.nano_printer
|
||||
|
||||
|
||||
|
||||
/datum/nano_module/arcade_classic/Topic(href, href_list)
|
||||
if(..()) // Always begin your Topic() calls with a parent call!
|
||||
return 1
|
||||
if(href_list["new_game"])
|
||||
new_game()
|
||||
return 1 // Returning 1 (TRUE) in Topic automatically handles UI updates.
|
||||
if(gameover) // If the game has already ended, we don't want the following three topic calls to be processed at all.
|
||||
return 1 // Instead of adding checks into each of those three, we can easily add this one check here to reduce on code copy-paste.
|
||||
if(href_list["attack"])
|
||||
var/damage = rand(2, 6)
|
||||
information = "You attack for [damage] damage."
|
||||
enemy_health -= damage
|
||||
enemy_play()
|
||||
check_gameover()
|
||||
return 1
|
||||
if(href_list["heal"])
|
||||
var/healfor = rand(6, 8)
|
||||
var/cost = rand(1, 3)
|
||||
information = "You heal yourself for [healfor] damage, using [cost] energy in the process."
|
||||
player_health += healfor
|
||||
player_mana -= cost
|
||||
enemy_play()
|
||||
check_gameover()
|
||||
return 1
|
||||
if(href_list["regain_mana"])
|
||||
var/regen = rand(4, 7)
|
||||
information = "You rest of a while, regaining [regen] energy."
|
||||
player_mana += regen
|
||||
enemy_play()
|
||||
check_gameover()
|
||||
return 1
|
||||
// var/gamerSkillLevel = usr.mind?.get_skill_level(/datum/skill/gaming)
|
||||
// var/gamerSkill = usr.mind?.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER)
|
||||
switch(action)
|
||||
if("Attack")
|
||||
var/attackamt = 0 //Spam prevention.
|
||||
if(pause_state == FALSE)
|
||||
attackamt = rand(2,6) // + rand(0, gamerSkill)
|
||||
pause_state = TRUE
|
||||
heads_up = "You attack for [attackamt] damage."
|
||||
playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10)
|
||||
boss_hp -= attackamt
|
||||
sleep(10)
|
||||
game_check()
|
||||
enemy_check()
|
||||
return TRUE
|
||||
if("Heal")
|
||||
var/healamt = 0 //More Spam Prevention.
|
||||
var/healcost = 0
|
||||
if(pause_state == FALSE)
|
||||
healamt = rand(6,8) // + rand(0, gamerSkill)
|
||||
var/maxPointCost = 3
|
||||
// if(gamerSkillLevel >= SKILL_LEVEL_JOURNEYMAN)
|
||||
// maxPointCost = 2
|
||||
healcost = rand(1, maxPointCost)
|
||||
pause_state = TRUE
|
||||
heads_up = "You heal for [healamt] damage."
|
||||
playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10)
|
||||
player_hp += healamt
|
||||
player_mp -= healcost
|
||||
sleep(10)
|
||||
game_check()
|
||||
enemy_check()
|
||||
return TRUE
|
||||
if("Recharge_Power")
|
||||
var/rechargeamt = 0 //As above.
|
||||
if(pause_state == FALSE)
|
||||
rechargeamt = rand(4,7) // + rand(0, gamerSkill)
|
||||
pause_state = TRUE
|
||||
heads_up = "You regain [rechargeamt] magic power."
|
||||
playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3, falloff = 10)
|
||||
player_mp += rechargeamt
|
||||
sleep(10)
|
||||
game_check()
|
||||
enemy_check()
|
||||
return TRUE
|
||||
if("Dispense_Tickets")
|
||||
if(!printer)
|
||||
to_chat(usr, "<span class='notice'>Hardware error: A printer is required to redeem tickets.</span>")
|
||||
return
|
||||
if(printer.stored_paper <= 0)
|
||||
to_chat(usr, "<span class='notice'>Hardware error: Printer is out of paper.</span>")
|
||||
return
|
||||
else
|
||||
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
|
||||
if(ticket_count >= 1)
|
||||
new /obj/item/stack/arcadeticket((get_turf(computer)), 1)
|
||||
to_chat(usr, "<span class='notice'>[src] dispenses a ticket!</span>")
|
||||
ticket_count -= 1
|
||||
printer.stored_paper -= 1
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You don't have any stored tickets!</span>")
|
||||
return TRUE
|
||||
if("Start_Game")
|
||||
game_active = TRUE
|
||||
boss_hp = 45
|
||||
player_hp = 30
|
||||
player_mp = 10
|
||||
heads_up = "You stand before [boss_name]! Prepare for battle!"
|
||||
program_icon_state = "arcade"
|
||||
boss_id = rand(1,6)
|
||||
pause_state = FALSE
|
||||
if(istype(computer))
|
||||
computer.update_icon()
|
||||
|
||||
@@ -6,16 +6,17 @@
|
||||
program_key_state = "generic_key"
|
||||
program_menu_icon = "contact"
|
||||
size = 4
|
||||
requires_ntnet = 1
|
||||
available_on_ntnet = 1
|
||||
requires_ntnet = TRUE
|
||||
available_on_ntnet = TRUE
|
||||
|
||||
tgui_id = "NtosNewsBrowser"
|
||||
|
||||
nanomodule_path = /datum/nano_module/program/computer_newsbrowser/
|
||||
var/datum/computer_file/data/news_article/loaded_article
|
||||
var/download_progress = 0
|
||||
var/download_netspeed = 0
|
||||
var/downloading = 0
|
||||
var/downloading = FALSE
|
||||
var/message = ""
|
||||
var/show_archived = 0
|
||||
var/show_archived = FALSE
|
||||
|
||||
/datum/computer_file/program/newsbrowser/process_tick()
|
||||
if(!downloading)
|
||||
@@ -33,86 +34,31 @@
|
||||
if(download_progress >= loaded_article.size)
|
||||
downloading = 0
|
||||
requires_ntnet = 0 // Turn off NTNet requirement as we already loaded the file into local memory.
|
||||
SSnanoui.update_uis(NM)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/datum/computer_file/program/newsbrowser/kill_program()
|
||||
..()
|
||||
requires_ntnet = 1
|
||||
loaded_article = null
|
||||
download_progress = 0
|
||||
downloading = 0
|
||||
show_archived = 0
|
||||
/datum/computer_file/program/newsbrowser/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = get_header_data()
|
||||
|
||||
/datum/computer_file/program/newsbrowser/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["PRG_openarticle"])
|
||||
. = 1
|
||||
if(downloading || loaded_article)
|
||||
return 1
|
||||
|
||||
for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news)
|
||||
if(N.uid == text2num(href_list["PRG_openarticle"]))
|
||||
loaded_article = N.clone()
|
||||
downloading = 1
|
||||
break
|
||||
if(href_list["PRG_reset"])
|
||||
. = 1
|
||||
downloading = 0
|
||||
download_progress = 0
|
||||
requires_ntnet = 1
|
||||
loaded_article = null
|
||||
if(href_list["PRG_clearmessage"])
|
||||
. = 1
|
||||
message = ""
|
||||
if(href_list["PRG_savearticle"])
|
||||
. = 1
|
||||
if(downloading || !loaded_article)
|
||||
return
|
||||
|
||||
var/savename = sanitize(input(usr, "Enter file name or leave blank to cancel:", "Save article", loaded_article.filename))
|
||||
if(!savename)
|
||||
return 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/data/news_article/N = loaded_article.clone()
|
||||
N.filename = savename
|
||||
HDD.store_file(N)
|
||||
if(href_list["PRG_toggle_archived"])
|
||||
. = 1
|
||||
show_archived = !show_archived
|
||||
if(.)
|
||||
SSnanoui.update_uis(NM)
|
||||
|
||||
|
||||
/datum/nano_module/program/computer_newsbrowser
|
||||
name = "NTNet/ExoNet News Browser"
|
||||
|
||||
/datum/nano_module/program/computer_newsbrowser/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
|
||||
var/datum/computer_file/program/newsbrowser/PRG
|
||||
var/list/data = list()
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
PRG = program
|
||||
else
|
||||
return
|
||||
|
||||
data["message"] = PRG.message
|
||||
if(PRG.loaded_article && !PRG.downloading) // Viewing an article.
|
||||
data["title"] = PRG.loaded_article.filename
|
||||
data["cover"] = PRG.loaded_article.cover
|
||||
data["article"] = PRG.loaded_article.stored_data
|
||||
else if(PRG.downloading) // Downloading an article.
|
||||
data["download_running"] = 1
|
||||
data["download_progress"] = PRG.download_progress
|
||||
data["download_maxprogress"] = PRG.loaded_article.size
|
||||
data["download_rate"] = PRG.download_netspeed
|
||||
var/list/all_articles = list()
|
||||
data["message"] = message
|
||||
data["showing_archived"] = show_archived
|
||||
data["download"] = null
|
||||
data["article"] = null
|
||||
if(loaded_article && !downloading) // Viewing an article.
|
||||
data["article"] = list(
|
||||
"title" = loaded_article.filename,
|
||||
"cover" = loaded_article.cover,
|
||||
"content" = loaded_article.stored_data,
|
||||
)
|
||||
else if(downloading) // Downloading an article.
|
||||
data["download"] = list(
|
||||
"download_progress" = download_progress,
|
||||
"download_maxprogress" = loaded_article.size,
|
||||
"download_rate" = download_netspeed
|
||||
)
|
||||
else // Viewing list of articles
|
||||
var/list/all_articles[0]
|
||||
for(var/datum/computer_file/data/news_article/F in ntnet_global.available_news)
|
||||
if(!PRG.show_archived && F.archived)
|
||||
if(!show_archived && F.archived)
|
||||
continue
|
||||
all_articles.Add(list(list(
|
||||
"name" = F.filename,
|
||||
@@ -120,12 +66,56 @@
|
||||
"uid" = F.uid,
|
||||
"archived" = F.archived
|
||||
)))
|
||||
data["all_articles"] = all_articles
|
||||
data["showing_archived"] = PRG.show_archived
|
||||
data["all_articles"] = all_articles
|
||||
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/newsbrowser/kill_program()
|
||||
..()
|
||||
requires_ntnet = TRUE
|
||||
loaded_article = null
|
||||
download_progress = 0
|
||||
downloading = FALSE
|
||||
show_archived = FALSE
|
||||
|
||||
/datum/computer_file/program/newsbrowser/tgui_act(action, list/params, datum/tgui/ui)
|
||||
if(..())
|
||||
return TRUE
|
||||
switch(action)
|
||||
if("PRG_openarticle")
|
||||
. = TRUE
|
||||
if(downloading || loaded_article)
|
||||
return TRUE
|
||||
|
||||
for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news)
|
||||
if(N.uid == text2num(params["uid"]))
|
||||
loaded_article = N.clone()
|
||||
downloading = 1
|
||||
break
|
||||
if("PRG_reset")
|
||||
. = TRUE
|
||||
downloading = 0
|
||||
download_progress = 0
|
||||
requires_ntnet = 1
|
||||
loaded_article = null
|
||||
if("PRG_clearmessage")
|
||||
. = TRUE
|
||||
message = ""
|
||||
if("PRG_savearticle")
|
||||
. = TRUE
|
||||
if(downloading || !loaded_article)
|
||||
return
|
||||
|
||||
var/savename = sanitize(input(usr, "Enter file name or leave blank to cancel:", "Save article", loaded_article.filename))
|
||||
if(!savename)
|
||||
return TRUE
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return TRUE
|
||||
var/datum/computer_file/data/news_article/N = loaded_article.clone()
|
||||
N.filename = savename
|
||||
HDD.store_file(N)
|
||||
if("PRG_toggle_archived")
|
||||
. = TRUE
|
||||
show_archived = !show_archived
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "news_browser.tmpl", "NTNet/ExoNet News Browser", 575, 750, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
@@ -5,29 +5,26 @@
|
||||
program_key_state = "generic_key"
|
||||
program_menu_icon = "arrowthickstop-1-s"
|
||||
extended_desc = "This program allows downloads of software from official NT repositories"
|
||||
unsendable = 1
|
||||
undeletable = 1
|
||||
unsendable = TRUE
|
||||
undeletable = TRUE
|
||||
size = 4
|
||||
requires_ntnet = 1
|
||||
requires_ntnet = TRUE
|
||||
requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD
|
||||
available_on_ntnet = 0
|
||||
nanomodule_path = /datum/nano_module/program/computer_ntnetdownload/
|
||||
available_on_ntnet = FALSE
|
||||
ui_header = "downloader_finished.gif"
|
||||
tgui_id = "NtosNetDownloader"
|
||||
|
||||
var/datum/computer_file/program/downloaded_file = null
|
||||
var/hacked_download = 0
|
||||
var/download_completion = 0 //GQ of downloaded data.
|
||||
var/download_netspeed = 0
|
||||
var/downloaderror = ""
|
||||
var/obj/item/modular_computer/my_computer = null
|
||||
var/list/downloads_queue[0]
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/kill_program()
|
||||
..()
|
||||
downloaded_file = null
|
||||
download_completion = 0
|
||||
download_netspeed = 0
|
||||
downloaderror = ""
|
||||
ui_header = "downloader_finished.gif"
|
||||
|
||||
abort_file_download()
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(var/filename)
|
||||
if(downloaded_file)
|
||||
@@ -108,93 +105,85 @@
|
||||
download_netspeed = NTNETSPEED_ETHERNET
|
||||
download_completion += download_netspeed
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/Topic(href, href_list)
|
||||
/datum/computer_file/program/ntnetdownload/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["PRG_downloadfile"])
|
||||
if(!downloaded_file)
|
||||
begin_file_download(href_list["PRG_downloadfile"])
|
||||
else if(check_file_download(href_list["PRG_downloadfile"]) && !downloads_queue.Find(href_list["PRG_downloadfile"]) && downloaded_file.filename != href_list["PRG_downloadfile"])
|
||||
downloads_queue += href_list["PRG_downloadfile"]
|
||||
return 1
|
||||
if(href_list["PRG_removequeued"])
|
||||
downloads_queue.Remove(href_list["PRG_removequeued"])
|
||||
return 1
|
||||
if(href_list["PRG_reseterror"])
|
||||
if(downloaderror)
|
||||
download_completion = 0
|
||||
download_netspeed = 0
|
||||
downloaded_file = null
|
||||
downloaderror = ""
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/nano_module/program/computer_ntnetdownload
|
||||
name = "Network Downloader"
|
||||
var/obj/item/modular_computer/my_computer = null
|
||||
|
||||
/datum/nano_module/program/computer_ntnetdownload/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(program)
|
||||
my_computer = program.computer
|
||||
return TRUE
|
||||
switch(action)
|
||||
if("PRG_downloadfile")
|
||||
if(!downloaded_file)
|
||||
begin_file_download(params["filename"])
|
||||
else if(check_file_download(params["filename"]) && !downloads_queue.Find(params["filename"]) && downloaded_file.filename != params["filename"])
|
||||
downloads_queue += params["filename"]
|
||||
return TRUE
|
||||
if("PRG_removequeued")
|
||||
downloads_queue.Remove(params["filename"])
|
||||
return TRUE
|
||||
if("PRG_reseterror")
|
||||
if(downloaderror)
|
||||
download_completion = 0
|
||||
download_netspeed = 0
|
||||
downloaded_file = null
|
||||
downloaderror = ""
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/tgui_data(mob/user)
|
||||
my_computer = computer
|
||||
if(!istype(my_computer))
|
||||
return
|
||||
|
||||
var/list/data = list()
|
||||
var/datum/computer_file/program/ntnetdownload/prog = program
|
||||
// For now limited to execution by the downloader program
|
||||
if(!prog || !istype(prog))
|
||||
return
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
var/list/data = get_header_data()
|
||||
|
||||
// This IF cuts on data transferred to client, so i guess it's worth it.
|
||||
if(prog.downloaderror) // Download errored. Wait until user resets the program.
|
||||
data["error"] = prog.downloaderror
|
||||
if(prog.downloaded_file) // Download running. Wait please..
|
||||
data["downloadname"] = prog.downloaded_file.filename
|
||||
data["downloaddesc"] = prog.downloaded_file.filedesc
|
||||
data["downloadsize"] = prog.downloaded_file.size
|
||||
data["downloadspeed"] = prog.download_netspeed
|
||||
data["downloadcompletion"] = round(prog.download_completion, 0.1)
|
||||
data["downloading"] = !!downloaded_file
|
||||
data["error"] = downloaderror || FALSE
|
||||
|
||||
if(downloaded_file) // Download running. Wait please..
|
||||
data["downloadname"] = downloaded_file.filename
|
||||
data["downloaddesc"] = downloaded_file.filedesc
|
||||
data["downloadsize"] = downloaded_file.size
|
||||
data["downloadspeed"] = download_netspeed
|
||||
data["downloadcompletion"] = round(download_completion, 0.1)
|
||||
|
||||
data["disk_size"] = my_computer.hard_drive.max_capacity
|
||||
data["disk_used"] = my_computer.hard_drive.used_capacity
|
||||
var/list/all_entries[0]
|
||||
for(var/datum/computer_file/program/P in ntnet_global.available_station_software)
|
||||
// Only those programs our user can run will show in the list
|
||||
if(!P.can_run(user) && P.requires_access_to_download)
|
||||
if(!P.can_run(user) && P.requires_access_to_download || my_computer.hard_drive.find_file_by_name(P.filename))
|
||||
continue
|
||||
all_entries.Add(list(list(
|
||||
"filename" = P.filename,
|
||||
"filedesc" = P.filedesc,
|
||||
"fileinfo" = P.extended_desc,
|
||||
"size" = P.size,
|
||||
"icon" = P.program_menu_icon
|
||||
)))
|
||||
data["hackedavailable"] = 0
|
||||
if(prog.computer_emagged) // If we are running on emagged computer we have access to some "bonus" software
|
||||
var/list/hacked_programs[0]
|
||||
for(var/datum/computer_file/program/P in ntnet_global.available_antag_software)
|
||||
data["hackedavailable"] = 1
|
||||
hacked_programs.Add(list(list(
|
||||
"filename" = P.filename,
|
||||
"filedesc" = P.filedesc,
|
||||
"fileinfo" = P.extended_desc,
|
||||
"compatibility" = check_compatibility(P),
|
||||
"size" = P.size,
|
||||
"icon" = P.program_menu_icon
|
||||
)))
|
||||
data["hackedavailable"] = FALSE
|
||||
if(computer_emagged) // If we are running on emagged computer we have access to some "bonus" software
|
||||
var/list/hacked_programs[0]
|
||||
for(var/datum/computer_file/program/P in ntnet_global.available_antag_software)
|
||||
if(my_computer.hard_drive.find_file_by_name(P.filename))
|
||||
continue
|
||||
data["hackedavailable"] = TRUE
|
||||
hacked_programs.Add(list(list(
|
||||
"filename" = P.filename,
|
||||
"filedesc" = P.filedesc,
|
||||
"fileinfo" = P.extended_desc,
|
||||
"compatibility" = check_compatibility(P),
|
||||
"size" = P.size,
|
||||
"icon" = P.program_menu_icon
|
||||
)))
|
||||
data["hacked_programs"] = hacked_programs
|
||||
|
||||
data["downloadable_programs"] = all_entries
|
||||
data["downloads_queue"] = downloads_queue
|
||||
|
||||
if(prog.downloads_queue.len > 0)
|
||||
data["downloads_queue"] = prog.downloads_queue
|
||||
return data
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "ntnet_downloader.tmpl", "NTNet Download Program", 575, 700, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
/datum/computer_file/program/ntnetdownload/proc/check_compatibility(datum/computer_file/program/P)
|
||||
var/hardflag = computer.hardware_flag
|
||||
|
||||
if(P && P.is_supported_by_hardware(hardflag,0))
|
||||
return "Compatible"
|
||||
return "Incompatible!"
|
||||
|
||||
@@ -11,222 +11,220 @@
|
||||
network_destination = "NTNRC server"
|
||||
ui_header = "ntnrc_idle.gif"
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/program/computer_chatclient/
|
||||
var/last_message = null // Used to generate the toolbar icon
|
||||
tgui_id = "NtosNetChat"
|
||||
var/last_message // Used to generate the toolbar icon
|
||||
var/username
|
||||
var/datum/ntnet_conversation/channel = null
|
||||
var/operator_mode = 0 // Channel operator mode
|
||||
var/netadmin_mode = 0 // Administrator mode (invisible to other users + bypasses passwords)
|
||||
var/active_channel
|
||||
var/list/channel_history = list()
|
||||
var/operator_mode = FALSE // Channel operator mode
|
||||
var/netadmin_mode = FALSE // Administrator mode (invisible to other users + bypasses passwords)
|
||||
|
||||
/datum/computer_file/program/chatclient/New()
|
||||
username = "DefaultUser[rand(100, 999)]"
|
||||
|
||||
/datum/computer_file/program/chatclient/Topic(href, href_list)
|
||||
/datum/computer_file/program/chatclient/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
|
||||
if(href_list["PRG_speak"])
|
||||
. = 1
|
||||
if(!channel)
|
||||
return 1
|
||||
var/mob/living/user = usr
|
||||
var/message = sanitize(input(user, "Enter message or leave blank to cancel: "), 512)
|
||||
if(!message || !channel)
|
||||
return
|
||||
channel.add_message(message, username)
|
||||
var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel)
|
||||
var/authed = FALSE
|
||||
if(channel && ((channel.operator == src) || netadmin_mode))
|
||||
authed = TRUE
|
||||
switch(action)
|
||||
if("PRG_speak")
|
||||
if(!channel || isnull(active_channel))
|
||||
return
|
||||
var/message = reject_bad_text(params["message"])
|
||||
if(!message)
|
||||
return
|
||||
if(channel.password && !(src in channel.clients))
|
||||
if(channel.password == message)
|
||||
channel.add_client(src)
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_joinchannel"])
|
||||
. = 1
|
||||
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
|
||||
channel.add_message(message, username)
|
||||
// var/mob/living/user = usr
|
||||
// user.log_talk(message, LOG_CHAT, tag="as [username] to channel [channel.title]")
|
||||
return TRUE
|
||||
if("PRG_joinchannel")
|
||||
var/new_target = text2num(params["id"])
|
||||
if(isnull(new_target) || new_target == active_channel)
|
||||
return
|
||||
|
||||
if(!C)
|
||||
return 1
|
||||
if(netadmin_mode)
|
||||
active_channel = new_target // Bypasses normal leave/join and passwords. Technically makes the user invisible to others.
|
||||
return TRUE
|
||||
|
||||
if(netadmin_mode)
|
||||
channel = C // Bypasses normal leave/join and passwords. Technically makes the user invisible to others.
|
||||
return 1
|
||||
|
||||
if(C.password)
|
||||
active_channel = new_target
|
||||
channel = ntnet_global.get_chat_channel_by_id(new_target)
|
||||
if(!(src in channel.clients) && !channel.password)
|
||||
channel.add_client(src)
|
||||
return TRUE
|
||||
if("PRG_leavechannel")
|
||||
if(channel)
|
||||
channel.remove_client(src)
|
||||
active_channel = null
|
||||
return TRUE
|
||||
if("PRG_newchannel")
|
||||
var/channel_title = reject_bad_text(params["new_channel_name"])
|
||||
if(!channel_title)
|
||||
return
|
||||
var/datum/ntnet_conversation/C = new /datum/ntnet_conversation()
|
||||
C.add_client(src)
|
||||
C.operator = src
|
||||
C.title = channel_title
|
||||
active_channel = C.id
|
||||
return TRUE
|
||||
if("PRG_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...
|
||||
return TRUE
|
||||
var/mob/living/user = usr
|
||||
var/password = sanitize(input(user,"Access Denied. Enter password:"))
|
||||
if(C && (password == C.password))
|
||||
C.add_client(src)
|
||||
channel = C
|
||||
return 1
|
||||
C.add_client(src)
|
||||
channel = C
|
||||
if(href_list["PRG_leavechannel"])
|
||||
. = 1
|
||||
if(channel)
|
||||
channel.remove_client(src)
|
||||
channel = null
|
||||
if(href_list["PRG_newchannel"])
|
||||
. = 1
|
||||
var/mob/living/user = usr
|
||||
var/channel_title = sanitizeSafe(input(user,"Enter channel name or leave blank to cancel:"), 64)
|
||||
if(!channel_title)
|
||||
return
|
||||
var/datum/ntnet_conversation/C = new/datum/ntnet_conversation()
|
||||
C.add_client(src)
|
||||
C.operator = src
|
||||
channel = C
|
||||
C.title = channel_title
|
||||
if(href_list["PRG_toggleadmin"])
|
||||
. = 1
|
||||
if(netadmin_mode)
|
||||
netadmin_mode = 0
|
||||
if(channel)
|
||||
channel.remove_client(src) // We shouldn't be in channel's user list, but just in case...
|
||||
channel = null
|
||||
return 1
|
||||
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 = 1
|
||||
if(href_list["PRG_changename"])
|
||||
. = 1
|
||||
var/mob/living/user = usr
|
||||
var/newname = sanitize(input(user,"Enter new nickname or leave blank to cancel:"), 20)
|
||||
if(!newname)
|
||||
return 1
|
||||
if(channel)
|
||||
channel.add_status_message("[username] is now known as [newname].")
|
||||
username = newname
|
||||
if(can_run(user, TRUE, access_network))
|
||||
for(var/C in ntnet_global.chat_channels)
|
||||
var/datum/ntnet_conversation/chan = C
|
||||
chan.remove_client(src)
|
||||
netadmin_mode = TRUE
|
||||
return TRUE
|
||||
if("PRG_changename")
|
||||
var/newname = sanitize(params["new_name"])
|
||||
if(!newname)
|
||||
return
|
||||
for(var/C in ntnet_global.chat_channels)
|
||||
var/datum/ntnet_conversation/chan = C
|
||||
if(src in chan.clients)
|
||||
chan.add_status_message("[username] is now known as [newname].")
|
||||
username = newname
|
||||
return TRUE
|
||||
if("PRG_savelog")
|
||||
if(!channel)
|
||||
return
|
||||
var/logname = stripped_input(params["log_name"])
|
||||
if(!logname)
|
||||
return
|
||||
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 = "[logfile.stored_data][logstring]\[BR\]"
|
||||
logfile.stored_data = "[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("Var computer is null!")
|
||||
if(!computer.hard_drive)
|
||||
computer.visible_message("<span class='warning'>\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.</span>")
|
||||
else // In 99.9% cases this will mean our HDD is full
|
||||
computer.visible_message("<span class='warning'>\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.</span>")
|
||||
return TRUE
|
||||
if("PRG_renamechannel")
|
||||
if(!authed)
|
||||
return
|
||||
var/newname = reject_bad_text(params["new_name"])
|
||||
if(!newname || !channel)
|
||||
return
|
||||
channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.")
|
||||
channel.title = newname
|
||||
return TRUE
|
||||
if("PRG_deletechannel")
|
||||
if(authed)
|
||||
qdel(channel)
|
||||
active_channel = null
|
||||
return TRUE
|
||||
if("PRG_setpassword")
|
||||
if(!authed)
|
||||
return
|
||||
|
||||
if(href_list["PRG_savelog"])
|
||||
. = 1
|
||||
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 1
|
||||
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("Var computer is null!")
|
||||
return 1
|
||||
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"])
|
||||
. = 1
|
||||
if(!operator_mode || !channel)
|
||||
return 1
|
||||
var/mob/living/user = usr
|
||||
var/newname = sanitize(input(user, "Enter new channel name or leave blank to cancel:"), 64)
|
||||
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"])
|
||||
. = 1
|
||||
if(channel && ((channel.operator == src) || netadmin_mode))
|
||||
qdel(channel)
|
||||
channel = null
|
||||
if(href_list["PRG_setpassword"])
|
||||
. = 1
|
||||
if(!channel || ((channel.operator != src) && !netadmin_mode))
|
||||
return 1
|
||||
var/new_password = sanitize(params["new_password"])
|
||||
if(!authed)
|
||||
return
|
||||
|
||||
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 1
|
||||
|
||||
if(newpassword == "nopassword")
|
||||
channel.password = ""
|
||||
else
|
||||
channel.password = newpassword
|
||||
channel.password = new_password
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/chatclient/process_tick()
|
||||
..()
|
||||
var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel)
|
||||
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.
|
||||
last_message = channel.messages.len ? channel.messages[channel.messages.len - 1] : null
|
||||
last_message = length(channel.messages) ? channel.messages[channel.messages.len - 1] : null
|
||||
else
|
||||
last_message = null
|
||||
return 1
|
||||
if(channel && channel.messages && channel.messages.len)
|
||||
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 = 0)
|
||||
if(channel)
|
||||
/datum/computer_file/program/chatclient/kill_program(forced = FALSE)
|
||||
for(var/C in ntnet_global.chat_channels)
|
||||
var/datum/ntnet_conversation/channel = C
|
||||
channel.remove_client(src)
|
||||
channel = null
|
||||
..(forced)
|
||||
|
||||
/datum/nano_module/program/computer_chatclient
|
||||
name = "NTNet Relay 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
|
||||
..()
|
||||
|
||||
/datum/computer_file/program/chatclient/tgui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
data["can_admin"] = can_run(user, FALSE, access_network)
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/chatclient/tgui_data(mob/user)
|
||||
if(!ntnet_global || !ntnet_global.chat_channels)
|
||||
return list()
|
||||
|
||||
var/datum/computer_file/program/chatclient/C = program
|
||||
if(!istype(C))
|
||||
return
|
||||
var/list/data = get_header_data()
|
||||
|
||||
data["adminmode"] = C.netadmin_mode
|
||||
if(C.channel)
|
||||
data["title"] = C.channel.title
|
||||
var/list/messages[0]
|
||||
for(var/M in C.channel.messages)
|
||||
messages.Add(list(list(
|
||||
"msg" = M
|
||||
var/list/all_channels = list()
|
||||
for(var/C in ntnet_global.chat_channels)
|
||||
var/datum/ntnet_conversation/conv = C
|
||||
if(conv && conv.title)
|
||||
all_channels.Add(list(list(
|
||||
"chan" = conv.title,
|
||||
"id" = conv.id
|
||||
)))
|
||||
data["messages"] = messages
|
||||
var/list/clients[0]
|
||||
for(var/datum/computer_file/program/chatclient/cl in C.channel.clients)
|
||||
data["all_channels"] = all_channels
|
||||
|
||||
data["active_channel"] = active_channel
|
||||
data["username"] = username
|
||||
data["adminmode"] = netadmin_mode
|
||||
var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel)
|
||||
if(channel)
|
||||
data["title"] = channel.title
|
||||
var/authed = FALSE
|
||||
if(!channel.password)
|
||||
authed = TRUE
|
||||
if(netadmin_mode)
|
||||
authed = TRUE
|
||||
var/list/clients = list()
|
||||
for(var/C in channel.clients)
|
||||
if(C == src)
|
||||
authed = TRUE
|
||||
var/datum/computer_file/program/chatclient/cl = C
|
||||
clients.Add(list(list(
|
||||
"name" = cl.username
|
||||
)))
|
||||
data["clients"] = clients
|
||||
C.operator_mode = (C.channel.operator == C) ? 1 : 0
|
||||
data["is_operator"] = C.operator_mode || C.netadmin_mode
|
||||
|
||||
else // Channel selection screen
|
||||
var/list/all_channels[0]
|
||||
for(var/datum/ntnet_conversation/conv in ntnet_global.chat_channels)
|
||||
if(conv && conv.title)
|
||||
all_channels.Add(list(list(
|
||||
"chan" = conv.title,
|
||||
"id" = conv.id
|
||||
data["authed"] = authed
|
||||
//no fishing for ui data allowed
|
||||
if(authed)
|
||||
data["clients"] = clients
|
||||
var/list/messages = list()
|
||||
for(var/M in channel.messages)
|
||||
messages.Add(list(list(
|
||||
"msg" = M
|
||||
)))
|
||||
data["all_channels"] = all_channels
|
||||
data["messages"] = messages
|
||||
data["is_operator"] = (channel.operator == src) || netadmin_mode
|
||||
else
|
||||
data["clients"] = list()
|
||||
data["messages"] = list()
|
||||
else
|
||||
data["clients"] = list()
|
||||
data["authed"] = FALSE
|
||||
data["messages"] = list()
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
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(1)
|
||||
return data
|
||||
@@ -12,7 +12,7 @@ var/global/nttransfer_uid = 0
|
||||
requires_ntnet_feature = NTNET_PEERTOPEER
|
||||
network_destination = "other device via P2P tunnel"
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/program/computer_nttransfer/
|
||||
tgui_id = "NtosNetTransfer"
|
||||
|
||||
var/error = "" // Error screen
|
||||
var/server_password = "" // Optional password to download the file.
|
||||
@@ -75,111 +75,101 @@ var/global/nttransfer_uid = 0
|
||||
remote = null
|
||||
download_completion = 0
|
||||
|
||||
/datum/computer_file/program/nttransfer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = get_header_data()
|
||||
|
||||
/datum/nano_module/program/computer_nttransfer
|
||||
name = "NTNet P2P Transfer Client"
|
||||
data["error"] = error
|
||||
|
||||
/datum/nano_module/program/computer_nttransfer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(!program)
|
||||
return
|
||||
var/datum/computer_file/program/nttransfer/PRG = program
|
||||
if(!istype(PRG))
|
||||
return
|
||||
|
||||
var/list/data = program.get_header_data()
|
||||
|
||||
if(PRG.error)
|
||||
data["error"] = PRG.error
|
||||
else if(PRG.downloaded_file)
|
||||
data["downloading"] = 1
|
||||
data["download_size"] = PRG.downloaded_file.size
|
||||
data["download_progress"] = PRG.download_completion
|
||||
data["download_netspeed"] = PRG.actual_netspeed
|
||||
data["download_name"] = "[PRG.downloaded_file.filename].[PRG.downloaded_file.filetype]"
|
||||
else if (PRG.provided_file)
|
||||
data["uploading"] = 1
|
||||
data["upload_uid"] = PRG.unique_token
|
||||
data["upload_clients"] = PRG.connected_clients.len
|
||||
data["upload_haspassword"] = PRG.server_password ? 1 : 0
|
||||
data["upload_filename"] = "[PRG.provided_file.filename].[PRG.provided_file.filetype]"
|
||||
else if (PRG.upload_menu)
|
||||
var/list/all_files[0]
|
||||
for(var/datum/computer_file/F in PRG.computer.hard_drive.stored_files)
|
||||
data["downloading"] = !!downloaded_file
|
||||
if(downloaded_file)
|
||||
data["download_size"] = downloaded_file.size
|
||||
data["download_progress"] = download_completion
|
||||
data["download_netspeed"] = actual_netspeed
|
||||
data["download_name"] = "[downloaded_file.filename].[downloaded_file.filetype]"
|
||||
|
||||
data["uploading"] = !!provided_file
|
||||
if(provided_file)
|
||||
data["upload_uid"] = unique_token
|
||||
data["upload_clients"] = connected_clients.len
|
||||
data["upload_haspassword"] = server_password ? 1 : 0
|
||||
data["upload_filename"] = "[provided_file.filename].[provided_file.filetype]"
|
||||
|
||||
data["upload_filelist"] = list()
|
||||
if(upload_menu)
|
||||
var/list/all_files = list()
|
||||
for(var/datum/computer_file/F in computer.hard_drive.stored_files)
|
||||
all_files.Add(list(list(
|
||||
"uid" = F.uid,
|
||||
"filename" = "[F.filename].[F.filetype]",
|
||||
"size" = F.size
|
||||
)))
|
||||
data["upload_filelist"] = all_files
|
||||
else
|
||||
var/list/all_servers[0]
|
||||
|
||||
data["servers"] = list()
|
||||
if(!(downloaded_file || provided_file || upload_menu))
|
||||
var/list/all_servers = list()
|
||||
for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers)
|
||||
if(!P.provided_file)
|
||||
continue
|
||||
all_servers.Add(list(list(
|
||||
"uid" = P.unique_token,
|
||||
"filename" = "[P.provided_file.filename].[P.provided_file.filetype]",
|
||||
"size" = P.provided_file.size,
|
||||
"haspassword" = P.server_password ? 1 : 0
|
||||
"uid" = P.unique_token,
|
||||
"filename" = "[P.provided_file.filename].[P.provided_file.filetype]",
|
||||
"size" = P.provided_file.size,
|
||||
"haspassword" = P.server_password ? 1 : 0
|
||||
)))
|
||||
data["servers"] = all_servers
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "ntnet_transfer.tmpl", "NTNet P2P Transfer Client", 575, 700, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/nttransfer/Topic(href, href_list)
|
||||
/datum/computer_file/program/nttransfer/tgui_act(action, list/params, datum/tgui/ui)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["PRG_downloadfile"])
|
||||
for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers)
|
||||
if("[P.unique_token]" == href_list["PRG_downloadfile"])
|
||||
remote = P
|
||||
break
|
||||
if(!remote || !remote.provided_file)
|
||||
return
|
||||
if(remote.server_password)
|
||||
var/pass = sanitize(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required"))
|
||||
if(pass != remote.server_password)
|
||||
error = "Incorrect Password"
|
||||
return TRUE
|
||||
switch(action)
|
||||
if("PRG_downloadfile")
|
||||
for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers)
|
||||
if(P.unique_token == text2num(params["uid"]))
|
||||
remote = P
|
||||
break
|
||||
if(!remote || !remote.provided_file)
|
||||
return
|
||||
downloaded_file = remote.provided_file.clone()
|
||||
remote.connected_clients.Add(src)
|
||||
return 1
|
||||
if(href_list["PRG_reset"])
|
||||
error = ""
|
||||
upload_menu = 0
|
||||
finalize_download()
|
||||
if(src in ntnet_global.fileservers)
|
||||
ntnet_global.fileservers.Remove(src)
|
||||
for(var/datum/computer_file/program/nttransfer/T in connected_clients)
|
||||
T.crash_download("Remote server has forcibly closed the connection")
|
||||
provided_file = null
|
||||
return 1
|
||||
if(href_list["PRG_setpassword"])
|
||||
var/pass = sanitize(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none"))
|
||||
if(!pass)
|
||||
return
|
||||
if(pass == "none")
|
||||
server_password = ""
|
||||
return
|
||||
server_password = pass
|
||||
return 1
|
||||
if(href_list["PRG_uploadfile"])
|
||||
for(var/datum/computer_file/F in computer.hard_drive.stored_files)
|
||||
if("[F.uid]" == href_list["PRG_uploadfile"])
|
||||
if(F.unsendable)
|
||||
error = "I/O Error: File locked."
|
||||
if(remote.server_password)
|
||||
var/pass = sanitize(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required"))
|
||||
if(pass != remote.server_password)
|
||||
error = "Incorrect Password"
|
||||
return
|
||||
provided_file = F
|
||||
ntnet_global.fileservers.Add(src)
|
||||
downloaded_file = remote.provided_file.clone()
|
||||
remote.connected_clients.Add(src)
|
||||
return TRUE
|
||||
if("PRG_reset")
|
||||
error = ""
|
||||
upload_menu = 0
|
||||
finalize_download()
|
||||
if(src in ntnet_global.fileservers)
|
||||
ntnet_global.fileservers.Remove(src)
|
||||
for(var/datum/computer_file/program/nttransfer/T in connected_clients)
|
||||
T.crash_download("Remote server has forcibly closed the connection")
|
||||
provided_file = null
|
||||
return TRUE
|
||||
if("PRG_setpassword")
|
||||
var/pass = sanitize(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none"))
|
||||
if(!pass)
|
||||
return
|
||||
error = "I/O Error: Unable to locate file on hard drive."
|
||||
return 1
|
||||
if(href_list["PRG_uploadmenu"])
|
||||
upload_menu = 1
|
||||
return 0
|
||||
if(pass == "none")
|
||||
server_password = ""
|
||||
return
|
||||
server_password = pass
|
||||
return TRUE
|
||||
if("PRG_uploadfile")
|
||||
for(var/datum/computer_file/F in computer.hard_drive.stored_files)
|
||||
if(F.uid == text2num(params["uid"]))
|
||||
if(F.unsendable)
|
||||
error = "I/O Error: File locked."
|
||||
return
|
||||
provided_file = F
|
||||
ntnet_global.fileservers |= src
|
||||
return
|
||||
error = "I/O Error: Unable to locate file on hard drive."
|
||||
return TRUE
|
||||
if("PRG_uploadmenu")
|
||||
upload_menu = 1
|
||||
return TRUE
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/datum/computer_file/program/uav
|
||||
filename = "rigger"
|
||||
filedesc = "UAV Control"
|
||||
nanomodule_path = /datum/nano_module/uav
|
||||
tguimodule_path = /datum/tgui_module/uav
|
||||
program_icon_state = "comm_monitor"
|
||||
program_key_state = "generic_key"
|
||||
program_menu_icon = "link"
|
||||
@@ -12,255 +12,3 @@
|
||||
size = 12
|
||||
available_on_ntnet = 1
|
||||
//requires_ntnet = 1
|
||||
|
||||
/datum/nano_module/uav
|
||||
name = "UAV Control program"
|
||||
var/obj/item/device/uav/current_uav = null //The UAV we're watching
|
||||
var/signal_strength = 0 //Our last signal strength report (cached for a few seconds)
|
||||
var/signal_test_counter = 0 //How long until next signal strength check
|
||||
var/list/viewers //Who's viewing a UAV through us
|
||||
var/adhoc_range = 30 //How far we can operate on a UAV without NTnet
|
||||
|
||||
/datum/nano_module/uav/Destroy()
|
||||
if(LAZYLEN(viewers))
|
||||
for(var/weakref/W in viewers)
|
||||
var/M = W.resolve()
|
||||
if(M)
|
||||
unlook(M)
|
||||
. = ..()
|
||||
|
||||
/datum/nano_module/uav/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
if(current_uav)
|
||||
if(QDELETED(current_uav))
|
||||
set_current(null)
|
||||
else if(signal_test_counter-- <= 0)
|
||||
signal_strength = get_signal_to(current_uav)
|
||||
if(!signal_strength)
|
||||
set_current(null)
|
||||
else // Don't reset counter until we find a UAV that's actually in range we can stay connected to
|
||||
signal_test_counter = 20
|
||||
|
||||
data["current_uav"] = null
|
||||
if(current_uav)
|
||||
data["current_uav"] = list("status" = current_uav.get_status_string(), "power" = current_uav.state == 1 ? 1 : null)
|
||||
data["signal_strength"] = signal_strength ? signal_strength >= 2 ? "High" : "Low" : "None"
|
||||
data["in_use"] = LAZYLEN(viewers)
|
||||
|
||||
var/list/paired_map = list()
|
||||
var/obj/item/modular_computer/mc_host = nano_host()
|
||||
if(istype(mc_host))
|
||||
for(var/puav in mc_host.paired_uavs)
|
||||
var/weakref/wr = puav
|
||||
var/obj/item/device/uav/U = wr.resolve()
|
||||
paired_map[++paired_map.len] = list("name" = "[U ? U.nickname : "!!Missing!!"]", "uavref" = "\ref[U]")
|
||||
|
||||
data["paired_uavs"] = paired_map
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "mod_uav.tmpl", "UAV Control", 600, 500, state = state)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/datum/nano_module/uav/Topic(var/href, var/href_list = list(), var/datum/topic_state/state)
|
||||
if((. = ..()))
|
||||
return
|
||||
state = state || DefaultTopicState() || global.default_state
|
||||
if(CanUseTopic(usr, state, href_list) == STATUS_INTERACTIVE)
|
||||
CouldUseTopic(usr)
|
||||
return OnTopic(usr, href_list, state)
|
||||
CouldNotUseTopic(usr)
|
||||
return TRUE
|
||||
|
||||
/datum/nano_module/uav/proc/OnTopic(var/mob/user, var/list/href_list)
|
||||
if(href_list["switch_uav"])
|
||||
var/obj/item/device/uav/U = locate(href_list["switch_uav"]) //This is a \ref to the UAV itself
|
||||
if(!istype(U))
|
||||
to_chat(usr,"<span class='warning'>Something is blocking the connection to that UAV. In-person investigation is required.</span>")
|
||||
return TOPIC_NOACTION
|
||||
|
||||
if(!get_signal_to(U))
|
||||
to_chat(usr,"<span class='warning'>The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.</span>")
|
||||
return TOPIC_NOACTION
|
||||
|
||||
set_current(U)
|
||||
return TOPIC_REFRESH
|
||||
|
||||
if(href_list["del_uav"])
|
||||
var/refstring = href_list["del_uav"] //This is a \ref to the UAV itself
|
||||
var/obj/item/modular_computer/mc_host = nano_host()
|
||||
//This is so we can really scrape up any weakrefs that can't resolve
|
||||
for(var/weakref/wr in mc_host.paired_uavs)
|
||||
if(wr.ref == refstring)
|
||||
if(current_uav?.weakref == wr)
|
||||
set_current(null)
|
||||
LAZYREMOVE(mc_host.paired_uavs, wr)
|
||||
|
||||
else if(href_list["view_uav"])
|
||||
if(!current_uav)
|
||||
return TOPIC_NOACTION
|
||||
|
||||
if(current_uav.check_eye(user) < 0)
|
||||
to_chat(usr,"<span class='warning'>The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.</span>")
|
||||
else
|
||||
viewing_uav(user) ? unlook(user) : look(user)
|
||||
return TOPIC_NOACTION
|
||||
|
||||
else if(href_list["power_uav"])
|
||||
if(!current_uav)
|
||||
return TOPIC_NOACTION
|
||||
else if(current_uav.toggle_power())
|
||||
//Clean up viewers faster
|
||||
if(LAZYLEN(viewers))
|
||||
for(var/weakref/W in viewers)
|
||||
var/M = W.resolve()
|
||||
if(M)
|
||||
unlook(M)
|
||||
return TOPIC_REFRESH
|
||||
|
||||
/datum/nano_module/uav/proc/DefaultTopicState()
|
||||
return global.default_state
|
||||
|
||||
/datum/nano_module/uav/proc/CouldNotUseTopic(mob/user)
|
||||
. = ..()
|
||||
unlook(user)
|
||||
|
||||
/datum/nano_module/uav/proc/CouldUseTopic(mob/user)
|
||||
. = ..()
|
||||
if(viewing_uav(user))
|
||||
look(user)
|
||||
|
||||
/datum/nano_module/uav/proc/set_current(var/obj/item/device/uav/U)
|
||||
if(current_uav == U)
|
||||
return
|
||||
|
||||
signal_strength = 0
|
||||
current_uav = U
|
||||
|
||||
if(LAZYLEN(viewers))
|
||||
for(var/weakref/W in viewers)
|
||||
var/M = W.resolve()
|
||||
if(M)
|
||||
if(current_uav)
|
||||
to_chat(M, "<span class='warning'>You're disconnected from the UAV's camera!</span>")
|
||||
unlook(M)
|
||||
else
|
||||
look(M)
|
||||
|
||||
////
|
||||
//// Finding signal strength between us and the UAV
|
||||
////
|
||||
/datum/nano_module/uav/proc/get_signal_to(var/atom/movable/AM)
|
||||
// Following roughly the ntnet signal levels
|
||||
// 0 is none
|
||||
// 1 is weak
|
||||
// 2 is strong
|
||||
var/obj/item/modular_computer/host = nano_host() //Better not add this to anything other than modular computers.
|
||||
if(!istype(host))
|
||||
return
|
||||
var/our_signal = host.get_ntnet_status() //1 low, 2 good, 3 wired, 0 none
|
||||
var/their_z = get_z(AM)
|
||||
|
||||
//If we have no NTnet connection don't bother getting theirs
|
||||
if(!our_signal)
|
||||
if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range))
|
||||
return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs
|
||||
else
|
||||
return 0
|
||||
|
||||
var/list/zlevels_in_range = using_map.get_map_levels(their_z, FALSE)
|
||||
var/list/zlevels_in_long_range = using_map.get_map_levels(their_z, TRUE, om_range = DEFAULT_OVERMAP_RANGE) - zlevels_in_range
|
||||
var/their_signal = 0
|
||||
for(var/relay in ntnet_global.relays)
|
||||
var/obj/machinery/ntnet_relay/R = relay
|
||||
if(!R.operable())
|
||||
continue
|
||||
if(R.z == their_z)
|
||||
their_signal = 2
|
||||
break
|
||||
if(R.z in zlevels_in_range)
|
||||
their_signal = 2
|
||||
break
|
||||
if(R.z in zlevels_in_long_range)
|
||||
their_signal = 1
|
||||
break
|
||||
|
||||
if(!their_signal) //They have no NTnet at all
|
||||
if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range))
|
||||
return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs
|
||||
else
|
||||
return 0
|
||||
else
|
||||
return max(our_signal, their_signal)
|
||||
|
||||
////
|
||||
//// UAV viewer handling
|
||||
////
|
||||
/datum/nano_module/uav/proc/viewing_uav(mob/user)
|
||||
return (weakref(user) in viewers)
|
||||
|
||||
/datum/nano_module/uav/proc/look(var/mob/user)
|
||||
if(issilicon(user)) //Too complicated for me to want to mess with at the moment
|
||||
to_chat(user, "<span class='warning'>Regulations prevent you from controlling several corporeal forms at the same time!</span>")
|
||||
return
|
||||
|
||||
if(!current_uav)
|
||||
return
|
||||
|
||||
user.set_machine(nano_host())
|
||||
user.reset_view(current_uav)
|
||||
current_uav.add_master(user)
|
||||
LAZYDISTINCTADD(viewers, weakref(user))
|
||||
|
||||
/datum/nano_module/uav/proc/unlook(var/mob/user)
|
||||
user.unset_machine()
|
||||
user.reset_view()
|
||||
if(current_uav)
|
||||
current_uav.remove_master(user)
|
||||
LAZYREMOVE(viewers, weakref(user))
|
||||
|
||||
/datum/nano_module/uav/check_eye(var/mob/user)
|
||||
if(get_dist(user, nano_host()) > 1 || user.blinded || !current_uav)
|
||||
unlook(user)
|
||||
return -1
|
||||
|
||||
var/viewflag = current_uav.check_eye(user)
|
||||
if (viewflag < 0) //camera doesn't work
|
||||
unlook(user)
|
||||
return -1
|
||||
|
||||
return viewflag
|
||||
|
||||
////
|
||||
//// Relaying movements to the UAV
|
||||
////
|
||||
/datum/nano_module/uav/relaymove(var/mob/user, direction)
|
||||
if(current_uav)
|
||||
return current_uav.relaymove(user, direction, signal_strength)
|
||||
|
||||
////
|
||||
//// The effects when looking through a UAV
|
||||
////
|
||||
/datum/nano_module/uav/apply_visual(var/mob/M)
|
||||
if(!M.client)
|
||||
return
|
||||
if(weakref(M) in viewers)
|
||||
M.overlay_fullscreen("fishbed",/obj/screen/fullscreen/fishbed)
|
||||
M.overlay_fullscreen("scanlines",/obj/screen/fullscreen/scanline)
|
||||
|
||||
if(signal_strength <= 1)
|
||||
M.overlay_fullscreen("whitenoise",/obj/screen/fullscreen/noise)
|
||||
else
|
||||
M.clear_fullscreen("whitenoise", 0)
|
||||
else
|
||||
remove_visual(M)
|
||||
|
||||
/datum/nano_module/uav/remove_visual(mob/M)
|
||||
if(!M.client)
|
||||
return
|
||||
M.clear_fullscreen("fishbed",0)
|
||||
M.clear_fullscreen("scanlines",0)
|
||||
M.clear_fullscreen("whitenoise",0)
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
program_icon_state = "word"
|
||||
program_key_state = "atmos_key"
|
||||
size = 4
|
||||
requires_ntnet = 0
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/program/computer_wordprocessor/
|
||||
requires_ntnet = FALSE
|
||||
available_on_ntnet = TRUE
|
||||
tgui_id = "NtosWordProcessor"
|
||||
|
||||
var/browsing
|
||||
var/open_file
|
||||
var/loaded_data
|
||||
@@ -28,7 +29,7 @@
|
||||
if(F)
|
||||
open_file = F.filename
|
||||
loaded_data = F.stored_data
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/wordprocessor/proc/save_file(var/filename)
|
||||
var/datum/computer_file/data/F = get_file(filename)
|
||||
@@ -46,7 +47,7 @@
|
||||
HDD.store_file(backup)
|
||||
return 0
|
||||
is_edited = 0
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/wordprocessor/proc/create_file(var/newname, var/data = "")
|
||||
if(!newname)
|
||||
@@ -64,142 +65,144 @@
|
||||
if(HDD.store_file(F))
|
||||
return F
|
||||
|
||||
/datum/computer_file/program/wordprocessor/Topic(href, href_list)
|
||||
/datum/computer_file/program/wordprocessor/tgui_act(action, list/params, datum/tgui/ui)
|
||||
if(..())
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_txtrpeview"])
|
||||
show_browser(usr,"<HTML><HEAD><TITLE>[open_file]</TITLE></HEAD>[pencode2html(loaded_data)]</BODY></HTML>", "window=[open_file]")
|
||||
return 1
|
||||
switch(action)
|
||||
if("PRG_txtrpeview")
|
||||
show_browser(usr,"<HTML><HEAD><TITLE>[open_file]</TITLE></HEAD>[pencode2html(loaded_data)]</BODY></HTML>", "window=[open_file]")
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_taghelp"])
|
||||
to_chat(usr, "<span class='notice'>The hologram of a googly-eyed paper clip helpfully tells you:</span>")
|
||||
var/help = {"
|
||||
\[br\] : Creates a linebreak.
|
||||
\[center\] - \[/center\] : Centers the text.
|
||||
\[h1\] - \[/h1\] : First level heading.
|
||||
\[h2\] - \[/h2\] : Second level heading.
|
||||
\[h3\] - \[/h3\] : Third level heading.
|
||||
\[b\] - \[/b\] : Bold.
|
||||
\[i\] - \[/i\] : Italic.
|
||||
\[u\] - \[/u\] : Underlined.
|
||||
\[small\] - \[/small\] : Decreases the size of the text.
|
||||
\[large\] - \[/large\] : Increases the size of the text.
|
||||
\[field\] : Inserts a blank text field, which can be filled later. Useful for forms.
|
||||
\[date\] : Current station date.
|
||||
\[time\] : Current station time.
|
||||
\[list\] - \[/list\] : Begins and ends a list.
|
||||
\[*\] : A list item.
|
||||
\[hr\] : Horizontal rule.
|
||||
\[table\] - \[/table\] : Creates table using \[row\] and \[cell\] tags.
|
||||
\[grid\] - \[/grid\] : Table without visible borders, for layouts.
|
||||
\[row\] - New table row.
|
||||
\[cell\] - New table cell.
|
||||
\[logo\] - Inserts NT logo image.
|
||||
\[redlogo\] - Inserts red NT logo image.
|
||||
\[sglogo\] - Inserts Solgov insignia image."}
|
||||
if("PRG_taghelp")
|
||||
to_chat(usr, "<span class='notice'>The hologram of a googly-eyed paper clip helpfully tells you:</span>")
|
||||
var/help = {"
|
||||
\[br\] : Creates a linebreak.
|
||||
\[center\] - \[/center\] : Centers the text.
|
||||
\[h1\] - \[/h1\] : First level heading.
|
||||
\[h2\] - \[/h2\] : Second level heading.
|
||||
\[h3\] - \[/h3\] : Third level heading.
|
||||
\[b\] - \[/b\] : Bold.
|
||||
\[i\] - \[/i\] : Italic.
|
||||
\[u\] - \[/u\] : Underlined.
|
||||
\[small\] - \[/small\] : Decreases the size of the text.
|
||||
\[large\] - \[/large\] : Increases the size of the text.
|
||||
\[field\] : Inserts a blank text field, which can be filled later. Useful for forms.
|
||||
\[date\] : Current station date.
|
||||
\[time\] : Current station time.
|
||||
\[list\] - \[/list\] : Begins and ends a list.
|
||||
\[*\] : A list item.
|
||||
\[hr\] : Horizontal rule.
|
||||
\[table\] - \[/table\] : Creates table using \[row\] and \[cell\] tags.
|
||||
\[grid\] - \[/grid\] : Table without visible borders, for layouts.
|
||||
\[row\] - New table row.
|
||||
\[cell\] - New table cell.
|
||||
\[logo\] - Inserts NT logo image.
|
||||
\[redlogo\] - Inserts red NT logo image.
|
||||
\[sglogo\] - Inserts Solgov insignia image."}
|
||||
|
||||
to_chat(usr, help)
|
||||
return 1
|
||||
to_chat(usr, help)
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_closebrowser"])
|
||||
browsing = 0
|
||||
return 1
|
||||
if("PRG_closebrowser")
|
||||
browsing = 0
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_backtomenu"])
|
||||
error = null
|
||||
return 1
|
||||
if("PRG_backtomenu")
|
||||
error = null
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_loadmenu"])
|
||||
browsing = 1
|
||||
return 1
|
||||
if("PRG_loadmenu")
|
||||
browsing = 1
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_openfile"])
|
||||
. = 1
|
||||
if(is_edited)
|
||||
if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes")
|
||||
save_file(open_file)
|
||||
browsing = 0
|
||||
if(!open_file(href_list["PRG_openfile"]))
|
||||
error = "I/O error: Unable to open file '[href_list["PRG_openfile"]]'."
|
||||
if("PRG_openfile")
|
||||
if(is_edited)
|
||||
if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes")
|
||||
save_file(open_file)
|
||||
browsing = 0
|
||||
if(!open_file(params["PRG_openfile"]))
|
||||
error = "I/O error: Unable to open file '[params["PRG_openfile"]]'."
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_newfile"])
|
||||
. = 1
|
||||
if(is_edited)
|
||||
if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes")
|
||||
save_file(open_file)
|
||||
if("PRG_newfile")
|
||||
if(is_edited)
|
||||
if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes")
|
||||
save_file(open_file)
|
||||
|
||||
var/newname = sanitize(input(usr, "Enter file name:", "New File") as text|null)
|
||||
if(!newname)
|
||||
return 1
|
||||
var/datum/computer_file/data/F = create_file(newname)
|
||||
if(F)
|
||||
open_file = F.filename
|
||||
loaded_data = ""
|
||||
return 1
|
||||
else
|
||||
error = "I/O error: Unable to create file '[href_list["PRG_saveasfile"]]'."
|
||||
var/newname = sanitize(input(usr, "Enter file name:", "New File") as text|null)
|
||||
if(!newname)
|
||||
return TRUE
|
||||
var/datum/computer_file/data/F = create_file(newname)
|
||||
if(F)
|
||||
open_file = F.filename
|
||||
loaded_data = ""
|
||||
return TRUE
|
||||
else
|
||||
error = "I/O error: Unable to create file '[params["PRG_saveasfile"]]'."
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_saveasfile"])
|
||||
. = 1
|
||||
var/newname = sanitize(input(usr, "Enter file name:", "Save As") as text|null)
|
||||
if(!newname)
|
||||
return 1
|
||||
var/datum/computer_file/data/F = create_file(newname, loaded_data)
|
||||
if(F)
|
||||
open_file = F.filename
|
||||
else
|
||||
error = "I/O error: Unable to create file '[href_list["PRG_saveasfile"]]'."
|
||||
return 1
|
||||
if("PRG_saveasfile")
|
||||
var/newname = sanitize(input(usr, "Enter file name:", "Save As") as text|null)
|
||||
if(!newname)
|
||||
return TRUE
|
||||
var/datum/computer_file/data/F = create_file(newname, loaded_data)
|
||||
if(F)
|
||||
open_file = F.filename
|
||||
else
|
||||
error = "I/O error: Unable to create file '[params["PRG_saveasfile"]]'."
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_savefile"])
|
||||
. = 1
|
||||
if(!open_file)
|
||||
open_file = sanitize(input(usr, "Enter file name:", "Save As") as text|null)
|
||||
if("PRG_savefile")
|
||||
if(!open_file)
|
||||
return 0
|
||||
if(!save_file(open_file))
|
||||
error = "I/O error: Unable to save file '[open_file]'."
|
||||
return 1
|
||||
open_file = sanitize(input(usr, "Enter file name:", "Save As") as text|null)
|
||||
if(!open_file)
|
||||
return 0
|
||||
if(!save_file(open_file))
|
||||
error = "I/O error: Unable to save file '[open_file]'."
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_editfile"])
|
||||
var/oldtext = html_decode(loaded_data)
|
||||
oldtext = replacetext(oldtext, "\[br\]", "\n")
|
||||
if("PRG_editfile")
|
||||
var/oldtext = html_decode(loaded_data)
|
||||
oldtext = replacetext(oldtext, "\[br\]", "\n")
|
||||
|
||||
var/newtext = sanitize(replacetext(input(usr, "Editing file '[open_file]'. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH)
|
||||
if(!newtext)
|
||||
return
|
||||
loaded_data = newtext
|
||||
is_edited = 1
|
||||
return 1
|
||||
var/newtext = sanitize(replacetext(input(usr, "Editing file '[open_file]'. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH)
|
||||
if(!newtext)
|
||||
return
|
||||
loaded_data = newtext
|
||||
is_edited = 1
|
||||
return TRUE
|
||||
|
||||
if(href_list["PRG_printfile"])
|
||||
. = 1
|
||||
if(!computer.nano_printer)
|
||||
error = "Missing Hardware: Your computer does not have the required hardware to complete this operation."
|
||||
return 1
|
||||
if(!computer.nano_printer.print_text(pencode2html(loaded_data)))
|
||||
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
|
||||
return 1
|
||||
if("PRG_printfile")
|
||||
if(!computer.nano_printer)
|
||||
error = "Missing Hardware: Your computer does not have the required hardware to complete this operation."
|
||||
return TRUE
|
||||
if(!computer.nano_printer.print_text(pencode2html(loaded_data)))
|
||||
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/nano_module/program/computer_wordprocessor
|
||||
name = "Word Processor"
|
||||
/datum/computer_file/program/wordprocessor/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = get_header_data()
|
||||
|
||||
/datum/nano_module/program/computer_wordprocessor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
var/datum/computer_file/program/wordprocessor/PRG
|
||||
PRG = program
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
|
||||
data["error"] = null
|
||||
if(error)
|
||||
data["error"] = error
|
||||
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD
|
||||
if(PRG.error)
|
||||
data["error"] = PRG.error
|
||||
if(PRG.browsing)
|
||||
data["browsing"] = PRG.browsing
|
||||
if(!PRG.computer || !PRG.computer.hard_drive)
|
||||
data["browsing"] = null
|
||||
data["files"] = list()
|
||||
data["usbconnected"] = FALSE
|
||||
data["usbfiles"] = list()
|
||||
data["filedata"] = null
|
||||
data["filename"] = null
|
||||
|
||||
if(browsing)
|
||||
data["browsing"] = browsing
|
||||
if(!computer || !HDD)
|
||||
data["error"] = "I/O ERROR: Unable to access hard drive."
|
||||
else
|
||||
HDD = PRG.computer.hard_drive
|
||||
var/list/files[0]
|
||||
for(var/datum/computer_file/F in HDD.stored_files)
|
||||
if(F.filetype == "TXT")
|
||||
@@ -209,7 +212,6 @@
|
||||
)))
|
||||
data["files"] = files
|
||||
|
||||
RHDD = PRG.computer.portable_drive
|
||||
if(RHDD)
|
||||
data["usbconnected"] = 1
|
||||
var/list/usbfiles[0]
|
||||
@@ -220,16 +222,11 @@
|
||||
"size" = F.size,
|
||||
)))
|
||||
data["usbfiles"] = usbfiles
|
||||
else if(PRG.open_file)
|
||||
data["filedata"] = pencode2html(PRG.loaded_data)
|
||||
data["filename"] = PRG.is_edited ? "[PRG.open_file]*" : PRG.open_file
|
||||
else if(open_file)
|
||||
data["filedata"] = pencode2html(loaded_data)
|
||||
data["filename"] = is_edited ? "[open_file]*" : open_file
|
||||
else
|
||||
data["filedata"] = pencode2html(PRG.loaded_data)
|
||||
data["filedata"] = pencode2html(loaded_data)
|
||||
data["filename"] = "UNNAMED"
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "word_processor.tmpl", "Word Processor", 575, 700, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
return data
|
||||
Reference in New Issue
Block a user