TGUI NTOS - Total Conversion
@@ -25,16 +25,7 @@
|
||||
return list("title" = title, "message" = message)
|
||||
|
||||
/datum/uplink_item/abstract/announcements/fake_centcom/get_goods(var/obj/item/device/uplink/U, var/loc, var/mob/user, var/list/args)
|
||||
for (var/obj/machinery/computer/communications/C in machines)
|
||||
if(! (C.stat & (BROKEN|NOPOWER) ) )
|
||||
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc )
|
||||
P.name = "'[command_name()] Update.'"
|
||||
P.info = replacetext(args["message"], "\n", "<br/>")
|
||||
P.update_space(P.info)
|
||||
P.update_icon()
|
||||
C.messagetitle.Add(args["title"])
|
||||
C.messagetext.Add(P.info)
|
||||
|
||||
post_comm_message(args["title"], replacetext(args["message"], "\n", "<br/>"))
|
||||
command_announcement.Announce(args["message"], args["title"])
|
||||
return 1
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
|
||||
/proc/get_access_by_id(id)
|
||||
var/list/AS = get_all_access_datums_by_id()
|
||||
return AS[id]
|
||||
return AS["[id]"]
|
||||
|
||||
/proc/get_all_jobs()
|
||||
var/list/all_jobs = list()
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
var/list/formatted = list()
|
||||
for(var/job in jobs)
|
||||
formatted.Add(list(list(
|
||||
"display_name" = replacetext(job, " ", " "),
|
||||
"display_name" = replacetext(job, " ", " "),
|
||||
"target_rank" = get_target_rank(),
|
||||
"job" = job)))
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
id_card.forceMove(src)
|
||||
modify = id_card
|
||||
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
attack_hand(user)
|
||||
|
||||
/obj/machinery/computer/card/attack_ai(var/mob/user as mob)
|
||||
@@ -77,20 +77,27 @@
|
||||
/obj/machinery/computer/card/attack_hand(mob/user as mob)
|
||||
if(..()) return
|
||||
if(stat & (NOPOWER|BROKEN)) return
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/card/ui_interact(mob/user, ui_key="main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
user.set_machine(src)
|
||||
/obj/machinery/computer/card/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "IdentificationComputer", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/card/tgui_static_data(mob/user)
|
||||
var/list/data = ..()
|
||||
if(data_core)
|
||||
data_core.get_manifest_list()
|
||||
data["manifest"] = PDA_Manifest
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/card/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = ..()
|
||||
|
||||
var/data[0]
|
||||
data["src"] = "\ref[src]"
|
||||
data["station_name"] = station_name()
|
||||
data["mode"] = mode
|
||||
data["printing"] = printing
|
||||
data["manifest"] = PDA_Manifest
|
||||
data["target_name"] = modify ? modify.name : "-----"
|
||||
data["target_owner"] = modify && modify.registered_name ? modify.registered_name : "-----"
|
||||
data["target_rank"] = get_target_rank()
|
||||
@@ -110,27 +117,27 @@
|
||||
continue
|
||||
if(dept.centcom_only && !is_centcom())
|
||||
continue
|
||||
departments[++departments.len] = list("department_name" = dept.name, "jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name)) )
|
||||
|
||||
departments.Add(list(list(
|
||||
"department_name" = dept.name,
|
||||
"jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name))
|
||||
)))
|
||||
data["departments"] = departments
|
||||
|
||||
if (modify && is_centcom())
|
||||
var/list/all_centcom_access = list()
|
||||
var/list/all_centcom_access = list()
|
||||
var/list/regions = list()
|
||||
if(modify && is_centcom())
|
||||
for(var/access in get_all_centcom_access())
|
||||
all_centcom_access.Add(list(list(
|
||||
"desc" = replacetext(get_centcom_access_desc(access), " ", " "),
|
||||
"desc" = replacetext(get_centcom_access_desc(access), " ", " "),
|
||||
"ref" = access,
|
||||
"allowed" = (access in modify.access) ? 1 : 0)))
|
||||
|
||||
data["all_centcom_access"] = all_centcom_access
|
||||
else if (modify)
|
||||
var/list/regions = list()
|
||||
for(var/i = 1; i <= 7; i++)
|
||||
else if(modify)
|
||||
for(var/i in ACCESS_REGION_SECURITY to ACCESS_REGION_SUPPLY)
|
||||
var/list/accesses = list()
|
||||
for(var/access in get_region_accesses(i))
|
||||
if (get_access_desc(access))
|
||||
accesses.Add(list(list(
|
||||
"desc" = replacetext(get_access_desc(access), " ", " "),
|
||||
"desc" = replacetext(get_access_desc(access), " ", " "),
|
||||
"ref" = access,
|
||||
"allowed" = (access in modify.access) ? 1 : 0)))
|
||||
|
||||
@@ -138,23 +145,20 @@
|
||||
"name" = get_region_accesses_name(i),
|
||||
"accesses" = accesses)))
|
||||
|
||||
data["regions"] = regions
|
||||
data["regions"] = regions
|
||||
data["all_centcom_access"] = all_centcom_access
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "identification_computer.tmpl", src.name, 600, 700)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/card/Topic(href, href_list)
|
||||
/obj/machinery/computer/card/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
switch(href_list["choice"])
|
||||
if ("modify")
|
||||
if (modify)
|
||||
switch(action)
|
||||
if("modify")
|
||||
if(modify)
|
||||
data_core.manifest_modify(modify.registered_name, modify.assignment)
|
||||
modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])")
|
||||
modify.name = "[modify.registered_name]'s ID Card ([modify.assignment])"
|
||||
if(ishuman(usr))
|
||||
modify.forceMove(get_turf(src))
|
||||
if(!usr.get_active_hand())
|
||||
@@ -165,12 +169,13 @@
|
||||
modify = null
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I))
|
||||
if(istype(I, /obj/item/weapon/card/id) && usr.unEquip(I))
|
||||
I.forceMove(src)
|
||||
modify = I
|
||||
. = TRUE
|
||||
|
||||
if ("scan")
|
||||
if (scan)
|
||||
if("scan")
|
||||
if(scan)
|
||||
if(ishuman(usr))
|
||||
scan.forceMove(get_turf(src))
|
||||
if(!usr.get_active_hand())
|
||||
@@ -181,25 +186,26 @@
|
||||
scan = null
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if (istype(I, /obj/item/weapon/card/id))
|
||||
if(istype(I, /obj/item/weapon/card/id))
|
||||
usr.drop_item()
|
||||
I.forceMove(src)
|
||||
scan = I
|
||||
. = TRUE
|
||||
|
||||
if("access")
|
||||
if(href_list["allowed"])
|
||||
if(is_authenticated())
|
||||
var/access_type = text2num(href_list["access_target"])
|
||||
var/access_allowed = text2num(href_list["allowed"])
|
||||
if(access_type in (is_centcom() ? get_all_centcom_access() : get_all_station_access()))
|
||||
modify.access -= access_type
|
||||
if(!access_allowed)
|
||||
modify.access += access_type
|
||||
modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications
|
||||
if(is_authenticated())
|
||||
var/access_type = text2num(params["access_target"])
|
||||
var/access_allowed = text2num(params["allowed"])
|
||||
if(access_type in (is_centcom() ? get_all_centcom_access() : get_all_station_access()))
|
||||
modify.access -= access_type
|
||||
if(!access_allowed)
|
||||
modify.access += access_type
|
||||
modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications
|
||||
. = TRUE
|
||||
|
||||
if ("assign")
|
||||
if (is_authenticated() && modify)
|
||||
var/t1 = href_list["assign_target"]
|
||||
if("assign")
|
||||
if(is_authenticated() && modify)
|
||||
var/t1 = params["assign_target"]
|
||||
if(t1 == "Custom")
|
||||
var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment"), 45)
|
||||
//let custom jobs function as an impromptu alt title, mainly for sechuds
|
||||
@@ -222,44 +228,42 @@
|
||||
modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications
|
||||
|
||||
callHook("reassign_employee", list(modify))
|
||||
. = TRUE
|
||||
|
||||
if ("reg")
|
||||
if (is_authenticated())
|
||||
var/t2 = modify
|
||||
if ((modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf)))
|
||||
var/temp_name = sanitizeName(href_list["reg"])
|
||||
if(temp_name)
|
||||
modify.registered_name = temp_name
|
||||
else
|
||||
src.visible_message("<span class='notice'>[src] buzzes rudely.</span>")
|
||||
SSnanoui.update_uis(src)
|
||||
if("reg")
|
||||
if(is_authenticated())
|
||||
var/temp_name = sanitizeName(params["reg"])
|
||||
if(temp_name)
|
||||
modify.registered_name = temp_name
|
||||
else
|
||||
visible_message("<span class='notice'>[src] buzzes rudely.</span>")
|
||||
. = TRUE
|
||||
|
||||
if ("account")
|
||||
if (is_authenticated())
|
||||
var/t2 = modify
|
||||
if ((modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf)))
|
||||
var/account_num = text2num(href_list["account"])
|
||||
modify.associated_account_number = account_num
|
||||
SSnanoui.update_uis(src)
|
||||
if("account")
|
||||
if(is_authenticated())
|
||||
var/account_num = text2num(params["account"])
|
||||
modify.associated_account_number = account_num
|
||||
. = TRUE
|
||||
|
||||
if ("mode")
|
||||
mode = text2num(href_list["mode_target"])
|
||||
if("mode")
|
||||
mode = text2num(params["mode_target"])
|
||||
. = TRUE
|
||||
|
||||
if ("print")
|
||||
if (!printing)
|
||||
if("print")
|
||||
if(!printing)
|
||||
printing = 1
|
||||
spawn(50)
|
||||
printing = null
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
var/obj/item/weapon/paper/P = new(loc)
|
||||
if (mode)
|
||||
if(mode)
|
||||
P.name = text("crew manifest ([])", stationtime2text())
|
||||
P.info = {"<h4>Crew Manifest</h4>
|
||||
<br>
|
||||
[data_core ? data_core.get_manifest(0) : ""]
|
||||
"}
|
||||
else if (modify)
|
||||
else if(modify)
|
||||
P.name = "access report"
|
||||
P.info = {"<h4>Access Report</h4>
|
||||
<u>Prepared By:</u> [scan.registered_name ? scan.registered_name : "Unknown"]<br>
|
||||
@@ -273,19 +277,20 @@
|
||||
|
||||
for(var/A in modify.access)
|
||||
P.info += " [get_access_desc(A)]"
|
||||
. = TRUE
|
||||
|
||||
if ("terminate")
|
||||
if (is_authenticated())
|
||||
if("terminate")
|
||||
if(is_authenticated())
|
||||
modify.assignment = "Dismissed" //VOREStation Edit: setting adjustment
|
||||
modify.access = list()
|
||||
modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications
|
||||
|
||||
callHook("terminate_employee", list(modify))
|
||||
|
||||
if (modify)
|
||||
modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])")
|
||||
. = TRUE
|
||||
|
||||
return 1
|
||||
if(modify)
|
||||
modify.name = "[modify.registered_name]'s ID Card ([modify.assignment])"
|
||||
|
||||
/obj/machinery/computer/card/centcom
|
||||
name = "\improper CentCom ID card modification console"
|
||||
|
||||
@@ -9,553 +9,24 @@
|
||||
light_color = "#0099ff"
|
||||
req_access = list(access_heads)
|
||||
circuit = /obj/item/weapon/circuitboard/communications
|
||||
var/prints_intercept = 1
|
||||
var/authenticated = 0
|
||||
var/list/messagetitle = list()
|
||||
var/list/messagetext = list()
|
||||
var/currmsg = 0
|
||||
var/aicurrmsg = 0
|
||||
var/state = STATE_DEFAULT
|
||||
var/aistate = STATE_DEFAULT
|
||||
var/message_cooldown = 0
|
||||
var/centcomm_message_cooldown = 0
|
||||
var/tmp_alertlevel = 0
|
||||
var/const/STATE_DEFAULT = 1
|
||||
var/const/STATE_CALLSHUTTLE = 2
|
||||
var/const/STATE_CANCELSHUTTLE = 3
|
||||
var/const/STATE_MESSAGELIST = 4
|
||||
var/const/STATE_VIEWMESSAGE = 5
|
||||
var/const/STATE_DELMESSAGE = 6
|
||||
var/const/STATE_STATUSDISPLAY = 7
|
||||
var/const/STATE_ALERT_LEVEL = 8
|
||||
var/const/STATE_CONFIRM_LEVEL = 9
|
||||
var/const/STATE_CREWTRANSFER = 10
|
||||
|
||||
var/status_display_freq = "1435"
|
||||
var/stat_msg1
|
||||
var/stat_msg2
|
||||
var/datum/tgui_module/communications/communications
|
||||
|
||||
var/datum/lore/atc_controller/ATC
|
||||
var/datum/announcement/priority/crew_announcement = new
|
||||
|
||||
/obj/machinery/computer/communications/New()
|
||||
..()
|
||||
ATC = atc
|
||||
crew_announcement.newscast = 1
|
||||
|
||||
/obj/machinery/computer/communications/process()
|
||||
if(..())
|
||||
if(state != STATE_STATUSDISPLAY)
|
||||
src.updateDialog()
|
||||
|
||||
|
||||
/obj/machinery/computer/communications/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
if (using_map && !(src.z in using_map.contact_levels))
|
||||
to_chat(usr, "<font color='red'><b>Unable to establish a connection:</b></font> <font color='black'>You're too far away from the station!</font>")
|
||||
return
|
||||
usr.set_machine(src)
|
||||
|
||||
if(!href_list["operation"])
|
||||
return
|
||||
switch(href_list["operation"])
|
||||
// main interface
|
||||
if("main")
|
||||
src.state = STATE_DEFAULT
|
||||
if("login")
|
||||
var/mob/M = usr
|
||||
var/obj/item/weapon/card/id/I = M.GetIdCard()
|
||||
if (I && istype(I))
|
||||
if(src.check_access(I))
|
||||
authenticated = 1
|
||||
if(access_captain in I.access)
|
||||
authenticated = 2
|
||||
crew_announcement.announcer = GetNameAndAssignmentFromId(I)
|
||||
if("logout")
|
||||
authenticated = 0
|
||||
crew_announcement.announcer = ""
|
||||
|
||||
if("swipeidseclevel")
|
||||
if(src.authenticated) //Let heads change the alert level.
|
||||
var/old_level = security_level
|
||||
if(!tmp_alertlevel) tmp_alertlevel = SEC_LEVEL_GREEN
|
||||
if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN
|
||||
if(tmp_alertlevel > SEC_LEVEL_BLUE) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this
|
||||
set_security_level(tmp_alertlevel)
|
||||
if(security_level != old_level)
|
||||
//Only notify the admins if an actual change happened
|
||||
log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
|
||||
message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
|
||||
switch(security_level)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
feedback_inc("alert_comms_green",1)
|
||||
if(SEC_LEVEL_YELLOW)
|
||||
feedback_inc("alert_comms_yellow",1)
|
||||
if(SEC_LEVEL_VIOLET)
|
||||
feedback_inc("alert_comms_violet",1)
|
||||
if(SEC_LEVEL_ORANGE)
|
||||
feedback_inc("alert_comms_orange",1)
|
||||
if(SEC_LEVEL_BLUE)
|
||||
feedback_inc("alert_comms_blue",1)
|
||||
tmp_alertlevel = 0
|
||||
state = STATE_DEFAULT
|
||||
|
||||
if("announce")
|
||||
if(src.authenticated==2)
|
||||
if(message_cooldown)
|
||||
to_chat(usr, "Please allow at least one minute to pass between announcements")
|
||||
return
|
||||
var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|message
|
||||
if(!input || !(usr in view(1,src)))
|
||||
return
|
||||
crew_announcement.Announce(input)
|
||||
message_cooldown = 1
|
||||
spawn(600)//One minute cooldown
|
||||
message_cooldown = 0
|
||||
|
||||
if("callshuttle")
|
||||
src.state = STATE_DEFAULT
|
||||
if(src.authenticated)
|
||||
src.state = STATE_CALLSHUTTLE
|
||||
if("callshuttle2")
|
||||
if(src.authenticated)
|
||||
call_shuttle_proc(usr)
|
||||
if(emergency_shuttle.online())
|
||||
post_status("shuttle")
|
||||
src.state = STATE_DEFAULT
|
||||
if("cancelshuttle")
|
||||
src.state = STATE_DEFAULT
|
||||
if(src.authenticated)
|
||||
src.state = STATE_CANCELSHUTTLE
|
||||
if("cancelshuttle2")
|
||||
if(src.authenticated)
|
||||
cancel_call_proc(usr)
|
||||
src.state = STATE_DEFAULT
|
||||
if("messagelist")
|
||||
src.currmsg = 0
|
||||
src.state = STATE_MESSAGELIST
|
||||
if("toggleatc")
|
||||
src.ATC.squelched = !src.ATC.squelched
|
||||
if("viewmessage")
|
||||
src.state = STATE_VIEWMESSAGE
|
||||
if (!src.currmsg)
|
||||
if(href_list["message-num"])
|
||||
src.currmsg = text2num(href_list["message-num"])
|
||||
else
|
||||
src.state = STATE_MESSAGELIST
|
||||
if("delmessage")
|
||||
src.state = (src.currmsg) ? STATE_DELMESSAGE : STATE_MESSAGELIST
|
||||
if("delmessage2")
|
||||
if(src.authenticated)
|
||||
if(src.currmsg)
|
||||
var/title = src.messagetitle[src.currmsg]
|
||||
var/text = src.messagetext[src.currmsg]
|
||||
src.messagetitle.Remove(title)
|
||||
src.messagetext.Remove(text)
|
||||
if(src.currmsg == src.aicurrmsg)
|
||||
src.aicurrmsg = 0
|
||||
src.currmsg = 0
|
||||
src.state = STATE_MESSAGELIST
|
||||
else
|
||||
src.state = STATE_VIEWMESSAGE
|
||||
if("status")
|
||||
src.state = STATE_STATUSDISPLAY
|
||||
|
||||
// Status display stuff
|
||||
if("setstat")
|
||||
switch(href_list["statdisp"])
|
||||
if("message")
|
||||
post_status("message", stat_msg1, stat_msg2)
|
||||
if("alert")
|
||||
post_status("alert", href_list["alert"])
|
||||
else
|
||||
post_status(href_list["statdisp"])
|
||||
|
||||
if("setmsg1")
|
||||
stat_msg1 = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", stat_msg1) as text|null, 40), 40)
|
||||
src.updateDialog()
|
||||
if("setmsg2")
|
||||
stat_msg2 = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", stat_msg2) as text|null, 40), 40)
|
||||
src.updateDialog()
|
||||
|
||||
// OMG CENTCOMM LETTERHEAD
|
||||
if("MessageCentCom")
|
||||
if(src.authenticated==2)
|
||||
if(centcomm_message_cooldown)
|
||||
to_chat(usr, "<font color='red'>Arrays recycling. Please stand by.</font>")
|
||||
return
|
||||
var/input = sanitize(input("Please choose a message to transmit to [using_map.boss_short] via quantum entanglement. \
|
||||
Please be aware that this process is very expensive, and abuse will lead to... termination. \
|
||||
Transmission does not guarantee a response. \
|
||||
There is a 30 second delay before you may send another message, be clear, full and concise.", "Central Command Quantum Messaging") as null|message)
|
||||
if(!input || !(usr in view(1,src)))
|
||||
return
|
||||
CentCom_announce(input, usr)
|
||||
to_chat(usr, "<font color='blue'>Message transmitted.</font>")
|
||||
log_game("[key_name(usr)] has made an IA [using_map.boss_short] announcement: [input]")
|
||||
centcomm_message_cooldown = 1
|
||||
spawn(300)//10 minute cooldown
|
||||
centcomm_message_cooldown = 0
|
||||
|
||||
|
||||
// OMG SYNDICATE ...LETTERHEAD
|
||||
if("MessageSyndicate")
|
||||
if((src.authenticated==2) && (src.emagged))
|
||||
if(centcomm_message_cooldown)
|
||||
to_chat(usr, "<font color='red'>Arrays recycling. Please stand by.</font>")
|
||||
return
|
||||
var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", ""))
|
||||
if(!input || !(usr in view(1,src)))
|
||||
return
|
||||
Syndicate_announce(input, usr)
|
||||
to_chat(usr, "<font color='blue'>Message transmitted.</font>")
|
||||
log_game("[key_name(usr)] has made an illegal announcement: [input]")
|
||||
centcomm_message_cooldown = 1
|
||||
spawn(300)//10 minute cooldown
|
||||
centcomm_message_cooldown = 0
|
||||
|
||||
if("RestoreBackup")
|
||||
to_chat(usr, "Backup routing data restored!")
|
||||
src.emagged = 0
|
||||
src.updateDialog()
|
||||
|
||||
|
||||
|
||||
// AI interface
|
||||
if("ai-main")
|
||||
src.aicurrmsg = 0
|
||||
src.aistate = STATE_DEFAULT
|
||||
if("ai-callshuttle")
|
||||
src.aistate = STATE_CALLSHUTTLE
|
||||
if("ai-callshuttle2")
|
||||
call_shuttle_proc(usr)
|
||||
src.aistate = STATE_DEFAULT
|
||||
if("ai-messagelist")
|
||||
src.aicurrmsg = 0
|
||||
src.aistate = STATE_MESSAGELIST
|
||||
if("ai-viewmessage")
|
||||
src.aistate = STATE_VIEWMESSAGE
|
||||
if (!src.aicurrmsg)
|
||||
if(href_list["message-num"])
|
||||
src.aicurrmsg = text2num(href_list["message-num"])
|
||||
else
|
||||
src.aistate = STATE_MESSAGELIST
|
||||
if("ai-delmessage")
|
||||
src.aistate = (src.aicurrmsg) ? STATE_DELMESSAGE : STATE_MESSAGELIST
|
||||
if("ai-delmessage2")
|
||||
if(src.aicurrmsg)
|
||||
var/title = src.messagetitle[src.aicurrmsg]
|
||||
var/text = src.messagetext[src.aicurrmsg]
|
||||
src.messagetitle.Remove(title)
|
||||
src.messagetext.Remove(text)
|
||||
if(src.currmsg == src.aicurrmsg)
|
||||
src.currmsg = 0
|
||||
src.aicurrmsg = 0
|
||||
src.aistate = STATE_MESSAGELIST
|
||||
if("ai-status")
|
||||
src.aistate = STATE_STATUSDISPLAY
|
||||
|
||||
if("securitylevel")
|
||||
src.tmp_alertlevel = text2num( href_list["newalertlevel"] )
|
||||
if(!tmp_alertlevel) tmp_alertlevel = 0
|
||||
state = STATE_CONFIRM_LEVEL
|
||||
|
||||
if("changeseclevel")
|
||||
state = STATE_ALERT_LEVEL
|
||||
|
||||
|
||||
|
||||
src.updateUsrDialog()
|
||||
/obj/machinery/computer/communications/Initialize()
|
||||
. = ..()
|
||||
communications = new(src)
|
||||
|
||||
/obj/machinery/computer/communications/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(!emagged)
|
||||
src.emagged = 1
|
||||
emagged = TRUE
|
||||
communications.emagged = TRUE
|
||||
to_chat(user, "You scramble the communication routing circuits!")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/communications/attack_ai(var/mob/user as mob)
|
||||
return src.attack_hand(user)
|
||||
/obj/machinery/computer/communications/attack_ai(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/computer/communications/attack_hand(var/mob/user as mob)
|
||||
/obj/machinery/computer/communications/attack_hand(mob/user)
|
||||
if(..())
|
||||
return
|
||||
if (using_map && !(src.z in using_map.contact_levels))
|
||||
to_chat(user, "<font color='red'><b>Unable to establish a connection:</b></font> <font color='black'>You're too far away from the station!</font>")
|
||||
return
|
||||
|
||||
user.set_machine(src)
|
||||
var/dat = "<head><title>Communications Console</title></head><body>"
|
||||
if (emergency_shuttle.has_eta())
|
||||
var/timeleft = emergency_shuttle.estimate_arrival_time()
|
||||
dat += "<B>Emergency shuttle</B>\n<BR>\nETA: [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]<BR>"
|
||||
|
||||
if (istype(user, /mob/living/silicon))
|
||||
var/dat2 = src.interact_ai(user) // give the AI a different interact proc to limit its access
|
||||
if(dat2)
|
||||
dat += dat2
|
||||
user << browse(dat, "window=communications;size=400x500")
|
||||
onclose(user, "communications")
|
||||
return
|
||||
|
||||
switch(src.state)
|
||||
if(STATE_DEFAULT)
|
||||
if (src.authenticated)
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=logout'>Log Out</A> \]"
|
||||
if (src.authenticated==2)
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=announce'>Make An Announcement</A> \]"
|
||||
if(src.emagged == 0)
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=MessageCentCom'>Send an emergency message to [using_map.boss_short]</A> \]"
|
||||
else
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=MessageSyndicate'>Send an emergency message to \[UNKNOWN\]</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=RestoreBackup'>Restore Backup Routing Data</A> \]"
|
||||
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=changeseclevel'>Change alert level</A> \]"
|
||||
if(emergency_shuttle.location())
|
||||
if (emergency_shuttle.online())
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=cancelshuttle'>Cancel Shuttle Call</A> \]"
|
||||
else
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=callshuttle'>Call Emergency Shuttle</A> \]"
|
||||
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=status'>Set Status Display</A> \]"
|
||||
else
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=login'>Log In</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=messagelist'>Message List</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=toggleatc'>[ATC.squelched ? "Enable" : "Disable"] ATC Relay</A> \]"
|
||||
if(STATE_CALLSHUTTLE)
|
||||
dat += "Are you sure you want to call the shuttle? \[ <A HREF='?src=\ref[src];operation=callshuttle2'>OK</A> | <A HREF='?src=\ref[src];operation=main'>Cancel</A> \]"
|
||||
if(STATE_CANCELSHUTTLE)
|
||||
dat += "Are you sure you want to cancel the shuttle? \[ <A HREF='?src=\ref[src];operation=cancelshuttle2'>OK</A> | <A HREF='?src=\ref[src];operation=main'>Cancel</A> \]"
|
||||
if(STATE_MESSAGELIST)
|
||||
dat += "Messages:"
|
||||
for(var/i = 1; i<=src.messagetitle.len; i++)
|
||||
dat += "<BR><A HREF='?src=\ref[src];operation=viewmessage;message-num=[i]'>[src.messagetitle[i]]</A>"
|
||||
if(STATE_VIEWMESSAGE)
|
||||
if (src.currmsg)
|
||||
dat += "<B>[src.messagetitle[src.currmsg]]</B><BR><BR>[src.messagetext[src.currmsg]]"
|
||||
if (src.authenticated)
|
||||
dat += "<BR><BR>\[ <A HREF='?src=\ref[src];operation=delmessage'>Delete \]"
|
||||
else
|
||||
src.state = STATE_MESSAGELIST
|
||||
src.attack_hand(user)
|
||||
return
|
||||
if(STATE_DELMESSAGE)
|
||||
if (src.currmsg)
|
||||
dat += "Are you sure you want to delete this message? \[ <A HREF='?src=\ref[src];operation=delmessage2'>OK</A> | <A HREF='?src=\ref[src];operation=viewmessage'>Cancel</A> \]"
|
||||
else
|
||||
src.state = STATE_MESSAGELIST
|
||||
src.attack_hand(user)
|
||||
return
|
||||
if(STATE_STATUSDISPLAY)
|
||||
dat += "Set Status Displays<BR>"
|
||||
dat += "\[ <A HREF='?src=\ref[src];operation=setstat;statdisp=blank'>Clear</A> \]<BR>"
|
||||
dat += "\[ <A HREF='?src=\ref[src];operation=setstat;statdisp=time'>Station Time</A> \]<BR>"
|
||||
dat += "\[ <A HREF='?src=\ref[src];operation=setstat;statdisp=shuttle'>Shuttle ETA</A> \]<BR>"
|
||||
dat += "\[ <A HREF='?src=\ref[src];operation=setstat;statdisp=message'>Message</A> \]"
|
||||
dat += "<ul><li> Line 1: <A HREF='?src=\ref[src];operation=setmsg1'>[ stat_msg1 ? stat_msg1 : "(none)"]</A>"
|
||||
dat += "<li> Line 2: <A HREF='?src=\ref[src];operation=setmsg2'>[ stat_msg2 ? stat_msg2 : "(none)"]</A></ul><br>"
|
||||
dat += "\[ Alert: <A HREF='?src=\ref[src];operation=setstat;statdisp=alert;alert=default'>None</A> |"
|
||||
dat += " <A HREF='?src=\ref[src];operation=setstat;statdisp=alert;alert=redalert'>Red Alert</A> |"
|
||||
dat += " <A HREF='?src=\ref[src];operation=setstat;statdisp=alert;alert=lockdown'>Lockdown</A> |"
|
||||
dat += " <A HREF='?src=\ref[src];operation=setstat;statdisp=alert;alert=biohazard'>Biohazard</A> \]<BR><HR>"
|
||||
if(STATE_ALERT_LEVEL)
|
||||
dat += "Current alert level: [get_security_level()]<BR>"
|
||||
if(security_level == SEC_LEVEL_DELTA)
|
||||
dat += "<font color='red'><b>The self-destruct mechanism is active. Find a way to deactivate the mechanism to lower the alert level or evacuate.</b></font>"
|
||||
else
|
||||
dat += "<A HREF='?src=\ref[src];operation=securitylevel;newalertlevel=[SEC_LEVEL_BLUE]'>Blue</A><BR>"
|
||||
dat += "<A HREF='?src=\ref[src];operation=securitylevel;newalertlevel=[SEC_LEVEL_ORANGE]'>Orange</A><BR>"
|
||||
dat += "<A HREF='?src=\ref[src];operation=securitylevel;newalertlevel=[SEC_LEVEL_VIOLET]'>Violet</A><BR>"
|
||||
dat += "<A HREF='?src=\ref[src];operation=securitylevel;newalertlevel=[SEC_LEVEL_YELLOW]'>Yellow</A><BR>"
|
||||
dat += "<A HREF='?src=\ref[src];operation=securitylevel;newalertlevel=[SEC_LEVEL_GREEN]'>Green</A>"
|
||||
if(STATE_CONFIRM_LEVEL)
|
||||
dat += "Current alert level: [get_security_level()]<BR>"
|
||||
dat += "Confirm the change to: [num2seclevel(tmp_alertlevel)]<BR>"
|
||||
dat += "<A HREF='?src=\ref[src];operation=swipeidseclevel'>OK</A> to confirm change.<BR>"
|
||||
|
||||
dat += "<BR>\[ [(src.state != STATE_DEFAULT) ? "<A HREF='?src=\ref[src];operation=main'>Main Menu</A> | " : ""]<A HREF='?src=\ref[user];mach_close=communications'>Close</A> \]"
|
||||
user << browse(dat, "window=communications;size=400x500")
|
||||
onclose(user, "communications")
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/machinery/computer/communications/proc/interact_ai(var/mob/living/silicon/ai/user as mob)
|
||||
var/dat = ""
|
||||
switch(src.aistate)
|
||||
if(STATE_DEFAULT)
|
||||
if(emergency_shuttle.location() && !emergency_shuttle.online())
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=ai-callshuttle'>Call Emergency Shuttle</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=ai-messagelist'>Message List</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=ai-status'>Set Status Display</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=toggleatc'>[ATC.squelched ? "Enable" : "Disable"] ATC Relay</A> \]"
|
||||
if(STATE_CALLSHUTTLE)
|
||||
dat += "Are you sure you want to call the shuttle? \[ <A HREF='?src=\ref[src];operation=ai-callshuttle2'>OK</A> | <A HREF='?src=\ref[src];operation=ai-main'>Cancel</A> \]"
|
||||
if(STATE_MESSAGELIST)
|
||||
dat += "Messages:"
|
||||
for(var/i = 1; i<=src.messagetitle.len; i++)
|
||||
dat += "<BR><A HREF='?src=\ref[src];operation=ai-viewmessage;message-num=[i]'>[src.messagetitle[i]]</A>"
|
||||
if(STATE_VIEWMESSAGE)
|
||||
if (src.aicurrmsg)
|
||||
dat += "<B>[src.messagetitle[src.aicurrmsg]]</B><BR><BR>[src.messagetext[src.aicurrmsg]]"
|
||||
dat += "<BR><BR>\[ <A HREF='?src=\ref[src];operation=ai-delmessage'>Delete</A> \]"
|
||||
else
|
||||
src.aistate = STATE_MESSAGELIST
|
||||
src.attack_hand(user)
|
||||
return null
|
||||
if(STATE_DELMESSAGE)
|
||||
if(src.aicurrmsg)
|
||||
dat += "Are you sure you want to delete this message? \[ <A HREF='?src=\ref[src];operation=ai-delmessage2'>OK</A> | <A HREF='?src=\ref[src];operation=ai-viewmessage'>Cancel</A> \]"
|
||||
else
|
||||
src.aistate = STATE_MESSAGELIST
|
||||
src.attack_hand(user)
|
||||
return
|
||||
|
||||
if(STATE_STATUSDISPLAY)
|
||||
dat += "Set Status Displays<BR>"
|
||||
dat += "\[ <A HREF='?src=\ref[src];operation=setstat;statdisp=blank'>Clear</A> \]<BR>"
|
||||
dat += "\[ <A HREF='?src=\ref[src];operation=setstat;statdisp=time'>Station Time</A> \]<BR>"
|
||||
dat += "\[ <A HREF='?src=\ref[src];operation=setstat;statdisp=shuttle'>Shuttle ETA</A> \]<BR>"
|
||||
dat += "\[ <A HREF='?src=\ref[src];operation=setstat;statdisp=message'>Message</A> \]"
|
||||
dat += "<ul><li> Line 1: <A HREF='?src=\ref[src];operation=setmsg1'>[ stat_msg1 ? stat_msg1 : "(none)"]</A>"
|
||||
dat += "<li> Line 2: <A HREF='?src=\ref[src];operation=setmsg2'>[ stat_msg2 ? stat_msg2 : "(none)"]</A></ul><br>"
|
||||
dat += "\[ Alert: <A HREF='?src=\ref[src];operation=setstat;statdisp=alert;alert=default'>None</A> |"
|
||||
dat += " <A HREF='?src=\ref[src];operation=setstat;statdisp=alert;alert=redalert'>Red Alert</A> |"
|
||||
dat += " <A HREF='?src=\ref[src];operation=setstat;statdisp=alert;alert=lockdown'>Lockdown</A> |"
|
||||
dat += " <A HREF='?src=\ref[src];operation=setstat;statdisp=alert;alert=biohazard'>Biohazard</A> \]<BR><HR>"
|
||||
|
||||
|
||||
dat += "<BR>\[ [(src.aistate != STATE_DEFAULT) ? "<A HREF='?src=\ref[src];operation=ai-main'>Main Menu</A> | " : ""]<A HREF='?src=\ref[user];mach_close=communications'>Close</A> \]"
|
||||
return dat
|
||||
|
||||
/proc/enable_prison_shuttle(var/mob/user)
|
||||
for(var/obj/machinery/computer/prison_shuttle/PS in machines)
|
||||
PS.allowedtocall = !(PS.allowedtocall)
|
||||
|
||||
/proc/call_shuttle_proc(var/mob/user)
|
||||
if ((!( ticker ) || !emergency_shuttle.location()))
|
||||
return
|
||||
|
||||
if(!universe.OnShuttleCall(usr))
|
||||
to_chat(user, "<span class='notice'>Cannot establish a bluespace connection.</span>")
|
||||
return
|
||||
|
||||
if(deathsquad.deployed)
|
||||
to_chat(user, "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated.")
|
||||
return
|
||||
|
||||
if(emergency_shuttle.deny_shuttle)
|
||||
to_chat(user, "The emergency shuttle may not be sent at this time. Please try again later.")
|
||||
return
|
||||
|
||||
if(world.time < 6000) // Ten minute grace period to let the game get going without lolmetagaming. -- TLE
|
||||
to_chat(user, "The emergency shuttle is refueling. Please wait another [round((6000-world.time)/600)] minute\s before trying again.")
|
||||
return
|
||||
|
||||
if(emergency_shuttle.going_to_centcom())
|
||||
to_chat(user, "The emergency shuttle may not be called while returning to [using_map.boss_short].")
|
||||
return
|
||||
|
||||
if(emergency_shuttle.online())
|
||||
to_chat(user, "The emergency shuttle is already on its way.")
|
||||
return
|
||||
|
||||
if(ticker.mode.name == "blob")
|
||||
to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.")
|
||||
return
|
||||
|
||||
emergency_shuttle.call_evac()
|
||||
log_game("[key_name(user)] has called the shuttle.")
|
||||
message_admins("[key_name_admin(user)] has called the shuttle.", 1)
|
||||
admin_chat_message(message = "Emergency evac beginning! Called by [key_name(user)]!", color = "#CC2222") //VOREStation Add
|
||||
|
||||
|
||||
return
|
||||
|
||||
/proc/init_shift_change(var/mob/user, var/force = 0)
|
||||
if ((!( ticker ) || !emergency_shuttle.location()))
|
||||
return
|
||||
|
||||
if(emergency_shuttle.going_to_centcom())
|
||||
to_chat(user, "The shuttle may not be called while returning to [using_map.boss_short].")
|
||||
return
|
||||
|
||||
if(emergency_shuttle.online())
|
||||
to_chat(user, "The shuttle is already on its way.")
|
||||
return
|
||||
|
||||
// if force is 0, some things may stop the shuttle call
|
||||
if(!force)
|
||||
if(emergency_shuttle.deny_shuttle)
|
||||
to_chat(user, "[using_map.boss_short] does not currently have a shuttle available in your sector. Please try again later.")
|
||||
return
|
||||
|
||||
if(deathsquad.deployed == 1)
|
||||
to_chat(user, "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated.")
|
||||
return
|
||||
|
||||
if(world.time < 54000) // 30 minute grace period to let the game get going
|
||||
to_chat(user, "The shuttle is refueling. Please wait another [round((54000-world.time)/60)] minutes before trying again.")
|
||||
return
|
||||
|
||||
if(ticker.mode.auto_recall_shuttle)
|
||||
//New version pretends to call the shuttle but cause the shuttle to return after a random duration.
|
||||
emergency_shuttle.auto_recall = 1
|
||||
|
||||
if(ticker.mode.name == "blob" || ticker.mode.name == "epidemic")
|
||||
to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.")
|
||||
return
|
||||
|
||||
emergency_shuttle.call_transfer()
|
||||
|
||||
//delay events in case of an autotransfer
|
||||
if (isnull(user))
|
||||
SSevents.delay_events(EVENT_LEVEL_MODERATE, 9000) //15 minutes
|
||||
SSevents.delay_events(EVENT_LEVEL_MAJOR, 9000)
|
||||
|
||||
log_game("[user? key_name(user) : "Autotransfer"] has called the shuttle.")
|
||||
message_admins("[user? key_name_admin(user) : "Autotransfer"] has called the shuttle.", 1)
|
||||
admin_chat_message(message = "Autotransfer shuttle dispatched, shift ending soon.", color = "#2277BB") //VOREStation Add
|
||||
|
||||
return
|
||||
|
||||
/proc/cancel_call_proc(var/mob/user)
|
||||
if (!( ticker ) || !emergency_shuttle.can_recall())
|
||||
return
|
||||
if((ticker.mode.name == "blob")||(ticker.mode.name == "Meteor"))
|
||||
return
|
||||
|
||||
if(!emergency_shuttle.going_to_centcom()) //check that shuttle isn't already heading to CentCom
|
||||
emergency_shuttle.recall()
|
||||
log_game("[key_name(user)] has recalled the shuttle.")
|
||||
message_admins("[key_name_admin(user)] has recalled the shuttle.", 1)
|
||||
return
|
||||
|
||||
|
||||
/proc/is_relay_online()
|
||||
for(var/obj/machinery/telecomms/relay/M in world)
|
||||
if(M.stat == 0)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/machinery/computer/communications/proc/post_status(var/command, var/data1, var/data2)
|
||||
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
var/datum/signal/status_signal = new
|
||||
status_signal.source = src
|
||||
status_signal.transmission_method = TRANSMISSION_RADIO
|
||||
status_signal.data["command"] = command
|
||||
|
||||
switch(command)
|
||||
if("message")
|
||||
status_signal.data["msg1"] = data1
|
||||
status_signal.data["msg2"] = data2
|
||||
log_admin("STATUS: [src.fingerprintslast] set status screen message with [src]: [data1] [data2]")
|
||||
//message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]")
|
||||
if("alert")
|
||||
status_signal.data["picture_state"] = data1
|
||||
|
||||
frequency.post_signal(src, status_signal)
|
||||
communications.tgui_interact(user)
|
||||
|
||||
32
code/game/objects/items/stacks/tickets.dm
Normal file
@@ -0,0 +1,32 @@
|
||||
/obj/item/stack/arcadeticket
|
||||
name = "arcade tickets"
|
||||
desc = "Wow! With enough of these, you could buy a bike! ...Pssh, yeah right."
|
||||
singular_name = "arcade ticket"
|
||||
icon_state = "arcade-ticket"
|
||||
item_state = "tickets"
|
||||
w_class = ITEMSIZE_TINY
|
||||
max_amount = 30
|
||||
|
||||
/obj/item/stack/arcadeticket/New(loc, amount = null)
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/item/stack/arcadeticket/update_icon()
|
||||
var/amount = get_amount()
|
||||
switch(amount)
|
||||
if(12 to INFINITY)
|
||||
icon_state = "arcade-ticket_4"
|
||||
if(6 to 12)
|
||||
icon_state = "arcade-ticket_3"
|
||||
if(2 to 6)
|
||||
icon_state = "arcade-ticket_2"
|
||||
else
|
||||
icon_state = "arcade-ticket"
|
||||
|
||||
/obj/item/stack/arcadeticket/proc/pay_tickets()
|
||||
amount -= 2
|
||||
if(amount == 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/stack/arcadeticket/thirty
|
||||
amount = 30
|
||||
@@ -6,36 +6,36 @@
|
||||
"tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css',
|
||||
)
|
||||
|
||||
// /datum/asset/simple/headers
|
||||
// assets = list(
|
||||
// "alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
|
||||
// "alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
|
||||
// "batt_5.gif" = 'icons/program_icons/batt_5.gif',
|
||||
// "batt_20.gif" = 'icons/program_icons/batt_20.gif',
|
||||
// "batt_40.gif" = 'icons/program_icons/batt_40.gif',
|
||||
// "batt_60.gif" = 'icons/program_icons/batt_60.gif',
|
||||
// "batt_80.gif" = 'icons/program_icons/batt_80.gif',
|
||||
// "batt_100.gif" = 'icons/program_icons/batt_100.gif',
|
||||
// "charging.gif" = 'icons/program_icons/charging.gif',
|
||||
// "downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
|
||||
// "downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
|
||||
// "ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
|
||||
// "ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
|
||||
// "power_norm.gif" = 'icons/program_icons/power_norm.gif',
|
||||
// "power_warn.gif" = 'icons/program_icons/power_warn.gif',
|
||||
// "sig_high.gif" = 'icons/program_icons/sig_high.gif',
|
||||
// "sig_low.gif" = 'icons/program_icons/sig_low.gif',
|
||||
// "sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
|
||||
// "sig_none.gif" = 'icons/program_icons/sig_none.gif',
|
||||
// "smmon_0.gif" = 'icons/program_icons/smmon_0.gif',
|
||||
// "smmon_1.gif" = 'icons/program_icons/smmon_1.gif',
|
||||
// "smmon_2.gif" = 'icons/program_icons/smmon_2.gif',
|
||||
// "smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
|
||||
// "smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
|
||||
// "smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
|
||||
// "smmon_6.gif" = 'icons/program_icons/smmon_6.gif',
|
||||
// "borg_mon.gif" = 'icons/program_icons/borg_mon.gif'
|
||||
// )
|
||||
/datum/asset/simple/headers
|
||||
assets = list(
|
||||
"alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
|
||||
"alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
|
||||
"batt_5.gif" = 'icons/program_icons/batt_5.gif',
|
||||
"batt_20.gif" = 'icons/program_icons/batt_20.gif',
|
||||
"batt_40.gif" = 'icons/program_icons/batt_40.gif',
|
||||
"batt_60.gif" = 'icons/program_icons/batt_60.gif',
|
||||
"batt_80.gif" = 'icons/program_icons/batt_80.gif',
|
||||
"batt_100.gif" = 'icons/program_icons/batt_100.gif',
|
||||
"charging.gif" = 'icons/program_icons/charging.gif',
|
||||
"downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
|
||||
"downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
|
||||
"ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
|
||||
"ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
|
||||
"power_norm.gif" = 'icons/program_icons/power_norm.gif',
|
||||
"power_warn.gif" = 'icons/program_icons/power_warn.gif',
|
||||
"sig_high.gif" = 'icons/program_icons/sig_high.gif',
|
||||
"sig_low.gif" = 'icons/program_icons/sig_low.gif',
|
||||
"sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
|
||||
"sig_none.gif" = 'icons/program_icons/sig_none.gif',
|
||||
"smmon_0.gif" = 'icons/program_icons/smmon_0.gif',
|
||||
"smmon_1.gif" = 'icons/program_icons/smmon_1.gif',
|
||||
"smmon_2.gif" = 'icons/program_icons/smmon_2.gif',
|
||||
"smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
|
||||
"smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
|
||||
"smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
|
||||
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif',
|
||||
// "borg_mon.gif" = 'icons/program_icons/borg_mon.gif'
|
||||
)
|
||||
|
||||
// /datum/asset/simple/radar_assets
|
||||
// assets = list(
|
||||
@@ -206,15 +206,15 @@
|
||||
// "none_button.png" = 'html/none_button.png',
|
||||
// )
|
||||
|
||||
// /datum/asset/simple/arcade
|
||||
// assets = list(
|
||||
// "boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif',
|
||||
// "boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif',
|
||||
// "boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif',
|
||||
// "boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif',
|
||||
// "boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
|
||||
// "boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
|
||||
// )
|
||||
/datum/asset/simple/arcade
|
||||
assets = list(
|
||||
"boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif',
|
||||
"boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif',
|
||||
"boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif',
|
||||
"boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif',
|
||||
"boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
|
||||
"boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
|
||||
)
|
||||
|
||||
// /datum/asset/spritesheet/simple/achievements
|
||||
// name ="achievements"
|
||||
|
||||
@@ -84,17 +84,9 @@
|
||||
var/datum/supply_demand_order/random = pick(required_items)
|
||||
command_announcement.Announce("What happened? Accounting is here right now and they're already asking where that [random.name] is. Damn, I gotta go", my_department)
|
||||
var/message = "The delivery deadline was reached with the following needs outstanding:<hr>"
|
||||
for (var/datum/supply_demand_order/req in required_items)
|
||||
for(var/datum/supply_demand_order/req in required_items)
|
||||
message += req.describe() + "<br>"
|
||||
for (var/obj/machinery/computer/communications/C in machines)
|
||||
if(C.operable())
|
||||
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc )
|
||||
P.name = "'[my_department] Mission Summary'"
|
||||
P.info = message
|
||||
P.update_space(P.info)
|
||||
P.update_icon()
|
||||
C.messagetitle.Add("[my_department] Mission Summary")
|
||||
C.messagetext.Add(P.info)
|
||||
post_comm_message("'[my_department] Mission Summary'", message)
|
||||
/**
|
||||
* Event Handler for responding to the supply shuttle arriving at centcom.
|
||||
*/
|
||||
|
||||
@@ -399,9 +399,7 @@ var/list/ai_verbs_default = list(
|
||||
|
||||
// hack to display shuttle timer
|
||||
if(emergency_shuttle.online())
|
||||
var/obj/machinery/computer/communications/C = locate() in machines
|
||||
if(C)
|
||||
C.post_status("shuttle")
|
||||
post_status(src, "shuttle", user = src)
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_recall_shuttle()
|
||||
set category = "AI Commands"
|
||||
|
||||
@@ -181,5 +181,8 @@ var/global/datum/ntnet/ntnet_global = new()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/datum/ntnet/proc/get_chat_channel_by_id(id)
|
||||
for(var/datum/ntnet_conversation/chan in chat_channels)
|
||||
if(chan.id == id)
|
||||
return chan
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
active_program = null
|
||||
var/mob/user = usr
|
||||
if(user && istype(user))
|
||||
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
tgui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
update_icon()
|
||||
|
||||
// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on)
|
||||
@@ -154,7 +154,7 @@
|
||||
run_program(autorun.stored_data)
|
||||
|
||||
if(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/item/modular_computer/proc/minimize_program(mob/user)
|
||||
if(!active_program || !processor_unit)
|
||||
@@ -162,12 +162,11 @@
|
||||
|
||||
idle_threads.Add(active_program)
|
||||
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
|
||||
SSnanoui.close_uis(active_program.NM ? active_program.NM : active_program)
|
||||
SStgui.close_uis(active_program.TM ? active_program.TM : active_program)
|
||||
active_program = null
|
||||
update_icon()
|
||||
if(istype(user))
|
||||
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
tgui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
|
||||
|
||||
/obj/item/modular_computer/proc/run_program(prog)
|
||||
@@ -207,12 +206,12 @@
|
||||
return 1
|
||||
|
||||
/obj/item/modular_computer/proc/update_uis()
|
||||
if(active_program) //Should we update program ui or computer ui?
|
||||
SSnanoui.update_uis(active_program)
|
||||
if(active_program.NM)
|
||||
SSnanoui.update_uis(active_program.NM)
|
||||
if(active_program)
|
||||
SStgui.update_uis(active_program)
|
||||
if(active_program.TM)
|
||||
SStgui.update_uis(active_program.TM)
|
||||
else
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/item/modular_computer/proc/check_update_ui_need()
|
||||
var/ui_update_needed = 0
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
|
||||
/obj/item/modular_computer/attack_ghost(var/mob/observer/ghost/user)
|
||||
if(enabled)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
else if(check_rights(R_ADMIN|R_EVENT, 0, user))
|
||||
var/response = alert(user, "This computer is turned off. Would you like to turn it on?", "Admin Override", "Yes", "No")
|
||||
if(response == "Yes")
|
||||
@@ -116,7 +116,7 @@
|
||||
// On-click handling. Turns on the computer if it's off and opens the GUI.
|
||||
/obj/item/modular_computer/attack_self(var/mob/user)
|
||||
if(enabled && screen_on)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
else if(!enabled && screen_on)
|
||||
turn_on(user)
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
// Operates NanoUI
|
||||
/obj/item/modular_computer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
// Operates TGUI
|
||||
/obj/item/modular_computer/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/simple/headers)
|
||||
)
|
||||
|
||||
/obj/item/modular_computer/tgui_interact(mob/user, datum/tgui/ui)
|
||||
if(!screen_on || !enabled)
|
||||
if(ui)
|
||||
ui.close()
|
||||
@@ -13,7 +18,7 @@
|
||||
if(active_program)
|
||||
if(ui) // This is the main laptop screen. Since we are switching to program's UI close it for now.
|
||||
ui.close()
|
||||
active_program.ui_interact(user)
|
||||
active_program.tgui_interact(user)
|
||||
return
|
||||
|
||||
// We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it.
|
||||
@@ -22,80 +27,100 @@
|
||||
visible_message("\The [src] beeps three times, it's screen displaying \"DISK ERROR\" warning.")
|
||||
return // No HDD, No HDD files list or no stored files. Something is very broken.
|
||||
|
||||
var/datum/computer_file/data/autorun = hard_drive.find_file_by_name("autorun")
|
||||
|
||||
var/list/data = get_header_data()
|
||||
|
||||
var/list/programs = list()
|
||||
for(var/datum/computer_file/program/P in hard_drive.stored_files)
|
||||
var/list/program = list()
|
||||
program["name"] = P.filename
|
||||
program["desc"] = P.filedesc
|
||||
program["icon"] = P.program_menu_icon
|
||||
program["autorun"] = (istype(autorun) && (autorun.stored_data == P.filename)) ? 1 : 0
|
||||
if(P in idle_threads)
|
||||
program["running"] = 1
|
||||
programs.Add(list(program))
|
||||
|
||||
data["programs"] = programs
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "laptop_mainscreen.tmpl", "NTOS Main Menu", 400, 500)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "NtosMain")
|
||||
ui.set_autoupdate(TRUE)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/item/modular_computer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = get_header_data()
|
||||
data["device_theme"] = device_theme
|
||||
|
||||
data["login"] = list()
|
||||
var/obj/item/weapon/computer_hardware/card_slot/cardholder = card_slot
|
||||
if(cardholder)
|
||||
var/obj/item/weapon/card/id/stored_card = cardholder.stored_card
|
||||
if(stored_card)
|
||||
var/stored_name = stored_card.registered_name
|
||||
var/stored_title = stored_card.assignment
|
||||
if(!stored_name)
|
||||
stored_name = "Unknown"
|
||||
if(!stored_title)
|
||||
stored_title = "Unknown"
|
||||
data["login"] = list(
|
||||
IDName = stored_name,
|
||||
IDJob = stored_title,
|
||||
)
|
||||
|
||||
data["removable_media"] = list()
|
||||
|
||||
var/datum/computer_file/data/autorun = hard_drive.find_file_by_name("autorun")
|
||||
data["programs"] = list()
|
||||
for(var/datum/computer_file/program/P in hard_drive.stored_files)
|
||||
var/running = FALSE
|
||||
if(P in idle_threads)
|
||||
running = TRUE
|
||||
|
||||
data["programs"] += list(list(
|
||||
"name" = P.filename,
|
||||
"desc" = P.filedesc,
|
||||
"icon" = P.program_menu_icon,
|
||||
"running" = running,
|
||||
"autorun" = (istype(autorun) && (autorun.stored_data == P.filename)) ? 1 : 0
|
||||
))
|
||||
|
||||
data["has_light"] = FALSE // has_light
|
||||
data["light_on"] = FALSE // light_on
|
||||
data["comp_light_color"] = null // comp_light_color
|
||||
|
||||
return data
|
||||
|
||||
// Handles user's GUI input
|
||||
/obj/item/modular_computer/Topic(href, href_list)
|
||||
/obj/item/modular_computer/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return 1
|
||||
if( href_list["PC_exit"] )
|
||||
kill_program()
|
||||
return 1
|
||||
if( href_list["PC_enable_component"] )
|
||||
var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(href_list["PC_enable_component"])
|
||||
if(H && istype(H) && !H.enabled)
|
||||
H.enabled = 1
|
||||
. = 1
|
||||
if( href_list["PC_disable_component"] )
|
||||
var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(href_list["PC_disable_component"])
|
||||
if(H && istype(H) && H.enabled)
|
||||
H.enabled = 0
|
||||
. = 1
|
||||
if( href_list["PC_shutdown"] )
|
||||
shutdown_computer()
|
||||
return 1
|
||||
if( href_list["PC_minimize"] )
|
||||
var/mob/user = usr
|
||||
minimize_program(user)
|
||||
return TRUE
|
||||
|
||||
switch(action)
|
||||
if("PC_exit")
|
||||
kill_program()
|
||||
return TRUE
|
||||
if("PC_shutdown")
|
||||
shutdown_computer()
|
||||
return TRUE
|
||||
if("PC_minimize")
|
||||
var/mob/user = usr
|
||||
minimize_program(user)
|
||||
if("PC_killprogram")
|
||||
var/prog = params["name"]
|
||||
var/datum/computer_file/program/P = null
|
||||
var/mob/user = usr
|
||||
if(hard_drive)
|
||||
P = hard_drive.find_file_by_name(prog)
|
||||
|
||||
if( href_list["PC_killprogram"] )
|
||||
var/prog = href_list["PC_killprogram"]
|
||||
var/datum/computer_file/program/P = null
|
||||
var/mob/user = usr
|
||||
if(hard_drive)
|
||||
P = hard_drive.find_file_by_name(prog)
|
||||
if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED)
|
||||
return
|
||||
|
||||
if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED)
|
||||
P.kill_program(1)
|
||||
to_chat(user, "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>")
|
||||
return TRUE
|
||||
if("PC_runprogram")
|
||||
return run_program(params["name"])
|
||||
if("PC_setautorun")
|
||||
if(!hard_drive)
|
||||
return
|
||||
set_autorun(params["name"])
|
||||
return TRUE
|
||||
if("PC_Eject_Disk")
|
||||
var/param = params["name"]
|
||||
switch(param)
|
||||
if("ID")
|
||||
proc_eject_id(usr)
|
||||
return TRUE
|
||||
else
|
||||
return
|
||||
|
||||
P.kill_program(1)
|
||||
update_uis()
|
||||
to_chat(user, "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>")
|
||||
|
||||
if( href_list["PC_runprogram"] )
|
||||
return run_program(href_list["PC_runprogram"])
|
||||
|
||||
if( href_list["PC_setautorun"] )
|
||||
if(!hard_drive)
|
||||
return
|
||||
set_autorun(href_list["PC_setautorun"])
|
||||
|
||||
if(.)
|
||||
update_uis()
|
||||
|
||||
// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_"
|
||||
// Function used by TGUI's to obtain data for header. All relevant entries begin with "PC_"
|
||||
/obj/item/modular_computer/proc/get_header_data()
|
||||
var/list/data = list()
|
||||
|
||||
@@ -152,4 +177,4 @@
|
||||
data["PC_stationtime"] = stationtime2text()
|
||||
data["PC_hasheader"] = 1
|
||||
data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen
|
||||
return data
|
||||
return data
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
var/enabled = 0 // Whether the computer is turned on.
|
||||
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
|
||||
var/device_theme = "ntos" // Sets the theme for the main menu, hardware config, and file browser apps. Overridden by certain non-NT devices.
|
||||
var/datum/computer_file/program/active_program = null // A currently active program running on the computer.
|
||||
var/hardware_flag = 0 // A flag that describes this device type
|
||||
var/last_power_usage = 0 // Last tick power usage of this computer
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
// NEWS DEFINITIONS BELOW THIS LINE
|
||||
/* KEPT HERE AS AN EXAMPLE
|
||||
/*
|
||||
/datum/computer_file/data/news_article/space/vol_one
|
||||
filename = "SPACE Magazine vol. 1"
|
||||
server_file_path = 'news_articles/space_magazine_1.html'
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
var/required_access = null // List of required accesses to run/download the program.
|
||||
var/requires_access_to_run = 1 // Whether the program checks for required_access when run.
|
||||
var/requires_access_to_download = 1 // Whether the program checks for required_access when downloading.
|
||||
// NanoModule
|
||||
var/datum/nano_module/NM = null // If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement ui_interact.
|
||||
var/nanomodule_path = null // Path to nanomodule, make sure to set this if implementing new program.
|
||||
// TGUIModule
|
||||
var/datum/tgui_module/TM = null // If the program uses TGUIModule, put it here and it will be automagically opened. Otherwise implement tgui_interact.
|
||||
var/tguimodule_path = null // Path to tguimodule, make sure to set this if implementing new program.
|
||||
@@ -29,6 +26,8 @@
|
||||
var/computer_emagged = 0 // Set to 1 if computer that's running us was emagged. Computer updates this every Process() tick
|
||||
var/ui_header = null // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /nano/images/status_icons. Be careful not to use too large images!
|
||||
var/ntnet_speed = 0 // GQ/s - current network connectivity transfer rate
|
||||
/// Name of the tgui interface
|
||||
var/tgui_id
|
||||
|
||||
/datum/computer_file/program/New(var/obj/item/modular_computer/comp = null)
|
||||
..()
|
||||
@@ -39,16 +38,12 @@
|
||||
computer = null
|
||||
. = ..()
|
||||
|
||||
/datum/computer_file/program/nano_host()
|
||||
return computer.nano_host()
|
||||
|
||||
/datum/computer_file/program/tgui_host()
|
||||
return computer.tgui_host()
|
||||
|
||||
/datum/computer_file/program/clone()
|
||||
var/datum/computer_file/program/temp = ..()
|
||||
temp.required_access = required_access
|
||||
temp.nanomodule_path = nanomodule_path
|
||||
temp.filedesc = filedesc
|
||||
temp.program_icon_state = program_icon_state
|
||||
temp.requires_ntnet = requires_ntnet
|
||||
@@ -134,13 +129,9 @@
|
||||
/datum/computer_file/program/proc/run_program(var/mob/living/user)
|
||||
if(can_run(user, 1) || !requires_access_to_run)
|
||||
computer.active_program = src
|
||||
if(nanomodule_path)
|
||||
NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src)
|
||||
NM.using_access = user.GetAccess()
|
||||
if(tguimodule_path)
|
||||
TM = new tguimodule_path(src)
|
||||
TM.using_access = user.GetAccess()
|
||||
TM.tgui_interact(user)
|
||||
if(requires_ntnet && network_destination)
|
||||
generate_network_log("Connection opened to [network_destination].")
|
||||
program_state = PROGRAM_STATE_ACTIVE
|
||||
@@ -152,26 +143,28 @@
|
||||
program_state = PROGRAM_STATE_KILLED
|
||||
if(network_destination)
|
||||
generate_network_log("Connection to [network_destination] closed.")
|
||||
QDEL_NULL(NM)
|
||||
if(TM)
|
||||
SStgui.close_uis(TM)
|
||||
qdel(TM)
|
||||
TM = null
|
||||
QDEL_NULL(TM)
|
||||
return 1
|
||||
|
||||
// This is called every tick when the program is enabled. Ensure you do parent call if you override it. If parent returns 1 continue with UI initialisation.
|
||||
// It returns 0 if it can't run or if NanoModule was used instead. I suggest using NanoModules where applicable.
|
||||
/datum/computer_file/program/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists.
|
||||
/datum/computer_file/program/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/simple/headers)
|
||||
)
|
||||
|
||||
/datum/computer_file/program/tgui_interact(mob/user, datum/tgui/ui)
|
||||
if(program_state != PROGRAM_STATE_ACTIVE)
|
||||
if(ui)
|
||||
ui.close()
|
||||
return computer.ui_interact(user)
|
||||
if(istype(NM))
|
||||
NM.ui_interact(user, ui_key, null, force_open)
|
||||
return 0
|
||||
return computer.tgui_interact(user)
|
||||
if(istype(TM))
|
||||
TM.tgui_interact(user)
|
||||
return 0
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui && tgui_id)
|
||||
ui = new(user, src, tgui_id, filedesc)
|
||||
ui.open()
|
||||
return 1
|
||||
|
||||
// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC:
|
||||
@@ -185,10 +178,43 @@
|
||||
if(computer)
|
||||
return computer.Topic(href, href_list)
|
||||
|
||||
// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC:
|
||||
// Topic calls are automagically forwarded from NanoModule this program contains.
|
||||
// Calls beginning with "PRG_" are reserved for programs handling.
|
||||
// Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program)
|
||||
// ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE.
|
||||
/datum/computer_file/program/tgui_act(action,list/params, datum/tgui/ui)
|
||||
if(..())
|
||||
return 1
|
||||
if(computer)
|
||||
switch(action)
|
||||
if("PC_exit")
|
||||
computer.kill_program()
|
||||
ui.close()
|
||||
return 1
|
||||
if("PC_shutdown")
|
||||
computer.shutdown_computer()
|
||||
ui.close()
|
||||
return 1
|
||||
if("PC_minimize")
|
||||
var/mob/user = usr
|
||||
if(!computer.active_program)
|
||||
return
|
||||
|
||||
computer.idle_threads.Add(computer.active_program)
|
||||
program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
|
||||
|
||||
computer.active_program = null
|
||||
computer.update_icon()
|
||||
ui.close()
|
||||
|
||||
if(user && istype(user))
|
||||
computer.tgui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
|
||||
|
||||
|
||||
// Relays the call to nano module, if we have one
|
||||
/datum/computer_file/program/proc/check_eye(var/mob/user)
|
||||
if(NM)
|
||||
return NM.check_eye(user)
|
||||
if(TM)
|
||||
return TM.check_eye(user)
|
||||
else
|
||||
@@ -200,34 +226,14 @@
|
||||
/obj/item/modular_computer/update_layout()
|
||||
return TRUE
|
||||
|
||||
/datum/nano_module/program
|
||||
//available_to_ai = FALSE
|
||||
var/datum/computer_file/program/program = null // Program-Based computer program that runs this nano module. Defaults to null.
|
||||
|
||||
/datum/nano_module/program/New(var/host, var/topic_manager, var/program)
|
||||
..()
|
||||
src.program = program
|
||||
|
||||
/datum/topic_manager/program
|
||||
var/datum/program
|
||||
|
||||
/datum/topic_manager/program/New(var/datum/program)
|
||||
..()
|
||||
src.program = program
|
||||
|
||||
// Calls forwarded to PROGRAM itself should begin with "PRG_"
|
||||
// Calls forwarded to COMPUTER running the program should begin with "PC_"
|
||||
/datum/topic_manager/program/Topic(href, href_list)
|
||||
return program && program.Topic(href, href_list)
|
||||
|
||||
/datum/computer_file/program/apply_visual(mob/M)
|
||||
if(NM)
|
||||
return NM.apply_visual(M)
|
||||
if(TM)
|
||||
return TM.apply_visual(M)
|
||||
|
||||
/datum/computer_file/program/remove_visual(mob/M)
|
||||
if(NM)
|
||||
return NM.remove_visual(M)
|
||||
if(TM)
|
||||
return TM.remove_visual(M)
|
||||
|
||||
/datum/computer_file/program/proc/relaymove(var/mob/M, direction)
|
||||
if(NM)
|
||||
return NM.relaymove(M, direction)
|
||||
if(TM)
|
||||
return TM.relaymove(M, direction)
|
||||
@@ -6,15 +6,17 @@
|
||||
program_menu_icon = "unlocked"
|
||||
extended_desc = "This highly advanced script can very slowly decrypt operational codes used in almost any network. These codes can be downloaded to an ID card to expand the available access. The system administrator will probably notice this."
|
||||
size = 34
|
||||
requires_ntnet = 1
|
||||
available_on_ntnet = 0
|
||||
available_on_syndinet = 1
|
||||
nanomodule_path = /datum/nano_module/program/access_decrypter/
|
||||
requires_ntnet = TRUE
|
||||
available_on_ntnet = FALSE
|
||||
available_on_syndinet = TRUE
|
||||
tgui_id = "NtosAccessDecrypter"
|
||||
|
||||
var/message = ""
|
||||
var/running = FALSE
|
||||
var/progress = 0
|
||||
var/target_progress = 300
|
||||
var/datum/access/target_access = null
|
||||
var/list/restricted_access_codes = list(access_change_ids, access_network) // access codes that are not hackable due to balance reasons
|
||||
|
||||
/datum/computer_file/program/access_decrypter/kill_program(var/forced)
|
||||
reset()
|
||||
@@ -48,82 +50,63 @@
|
||||
message = "Successfully decrypted and saved operational key codes. Downloaded access codes for: [target_access.desc]"
|
||||
target_access = null
|
||||
|
||||
/datum/computer_file/program/access_decrypter/Topic(href, href_list)
|
||||
/datum/computer_file/program/access_decrypter/tgui_act(action, list/params, datum/tgui/ui)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["PRG_reset"])
|
||||
reset()
|
||||
return 1
|
||||
if(href_list["PRG_execute"])
|
||||
if(running)
|
||||
return 1
|
||||
if(text2num(href_list["allowed"]))
|
||||
return 1
|
||||
var/obj/item/weapon/computer_hardware/processor_unit/CPU = computer.processor_unit
|
||||
var/obj/item/weapon/computer_hardware/card_slot/RFID = computer.card_slot
|
||||
if(!istype(CPU) || !CPU.check_functionality() || !istype(RFID) || !RFID.check_functionality())
|
||||
message = "A fatal hardware error has been detected."
|
||||
return
|
||||
if(!istype(RFID.stored_card))
|
||||
message = "RFID card is not present in the device. Operation aborted."
|
||||
return
|
||||
running = TRUE
|
||||
target_access = get_access_by_id(href_list["PRG_execute"])
|
||||
if(ntnet_global.intrusion_detection_enabled)
|
||||
ntnet_global.add_log("IDS WARNING - Unauthorised access attempt to primary keycode database from device: [computer.network_card.get_network_tag()]")
|
||||
ntnet_global.intrusion_detection_alarm = 1
|
||||
return 1
|
||||
return TRUE
|
||||
switch(action)
|
||||
if("PRG_reset")
|
||||
reset()
|
||||
return TRUE
|
||||
if("PRG_execute")
|
||||
if(running)
|
||||
return TRUE
|
||||
if(text2num(params["allowed"]))
|
||||
return TRUE
|
||||
var/obj/item/weapon/computer_hardware/processor_unit/CPU = computer.processor_unit
|
||||
var/obj/item/weapon/computer_hardware/card_slot/RFID = computer.card_slot
|
||||
if(!istype(CPU) || !CPU.check_functionality() || !istype(RFID) || !RFID.check_functionality())
|
||||
message = "A fatal hardware error has been detected."
|
||||
return
|
||||
if(!istype(RFID.stored_card))
|
||||
message = "RFID card is not present in the device. Operation aborted."
|
||||
return
|
||||
running = TRUE
|
||||
target_access = get_access_by_id("[params["access_target"]]")
|
||||
if(ntnet_global.intrusion_detection_enabled)
|
||||
ntnet_global.add_log("IDS WARNING - Unauthorised access attempt to primary keycode database from device: [computer.network_card.get_network_tag()]")
|
||||
ntnet_global.intrusion_detection_alarm = TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/nano_module/program/access_decrypter
|
||||
name = "NTNet Access Decrypter"
|
||||
var/list/restricted_access_codes = list(access_change_ids, access_network) // access codes that are not hackable due to balance reasons
|
||||
|
||||
/datum/nano_module/program/access_decrypter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/computer_file/program/access_decrypter/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(!ntnet_global)
|
||||
return
|
||||
var/datum/computer_file/program/access_decrypter/PRG = program
|
||||
var/list/data = list()
|
||||
if(!istype(PRG))
|
||||
return
|
||||
data = PRG.get_header_data()
|
||||
var/list/data = get_header_data()
|
||||
|
||||
if(PRG.message)
|
||||
data["message"] = PRG.message
|
||||
else if(PRG.running)
|
||||
var/list/regions = list()
|
||||
data["message"] = null
|
||||
data["running"] = running
|
||||
if(message)
|
||||
data["message"] = message
|
||||
else if(running)
|
||||
data["running"] = 1
|
||||
data["rate"] = PRG.computer.processor_unit.max_idle_programs
|
||||
|
||||
// Stolen from DOS traffic generator, generates strings of 1s and 0s
|
||||
var/percentage = (PRG.progress / PRG.target_progress) * 100
|
||||
var/list/strings[0]
|
||||
for(var/j, j<10, j++)
|
||||
var/string = ""
|
||||
for(var/i, i<20, i++)
|
||||
string = "[string][prob(percentage)]"
|
||||
strings.Add(string)
|
||||
data["dos_strings"] = strings
|
||||
else if(program.computer.card_slot && program.computer.card_slot.stored_card)
|
||||
var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card
|
||||
var/list/regions = list()
|
||||
data["rate"] = computer.processor_unit.max_idle_programs
|
||||
data["factor"] = (progress / target_progress)
|
||||
else if(computer?.card_slot?.stored_card)
|
||||
var/obj/item/weapon/card/id/id_card = computer.card_slot.stored_card
|
||||
for(var/i = 1; i <= 7; i++)
|
||||
var/list/accesses = list()
|
||||
for(var/access in get_region_accesses(i))
|
||||
if (get_access_desc(access))
|
||||
if(get_access_desc(access) && !(access in restricted_access_codes))
|
||||
accesses.Add(list(list(
|
||||
"desc" = replacetext(get_access_desc(access), " ", " "),
|
||||
"desc" = replacetext(get_access_desc(access), " ", " "),
|
||||
"ref" = access,
|
||||
"allowed" = (access in id_card.access) ? 1 : 0,
|
||||
"blocked" = (access in restricted_access_codes) ? 1 : 0)))
|
||||
"allowed" = (access in id_card.access) ? 1 : 0
|
||||
)))
|
||||
|
||||
regions.Add(list(list(
|
||||
"name" = get_region_accesses_name(i),
|
||||
"accesses" = accesses)))
|
||||
data["regions"] = regions
|
||||
"accesses" = accesses
|
||||
)))
|
||||
data["regions"] = regions
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "access_decrypter.tmpl", "NTNet Access Decrypter", 550, 400, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
return data
|
||||
@@ -6,10 +6,11 @@
|
||||
program_menu_icon = "arrow-4-diag"
|
||||
extended_desc = "This advanced script can perform denial of service attacks against NTNet quantum relays. The system administrator will probably notice this. Multiple devices can run this program together against same relay for increased effect"
|
||||
size = 20
|
||||
requires_ntnet = 1
|
||||
available_on_ntnet = 0
|
||||
available_on_syndinet = 1
|
||||
nanomodule_path = /datum/nano_module/program/computer_dos/
|
||||
requires_ntnet = TRUE
|
||||
available_on_ntnet = FALSE
|
||||
available_on_syndinet = TRUE
|
||||
tgui_id = "NtosNetDos"
|
||||
|
||||
var/obj/machinery/ntnet_relay/target = null
|
||||
var/dos_speed = 0
|
||||
var/error = ""
|
||||
@@ -39,70 +40,51 @@
|
||||
|
||||
..(forced)
|
||||
|
||||
/datum/nano_module/program/computer_dos
|
||||
name = "DoS Traffic Generator"
|
||||
|
||||
/datum/nano_module/program/computer_dos/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/computer_file/program/ntnet_dos/tgui_data(mob/user)
|
||||
if(!ntnet_global)
|
||||
return
|
||||
var/datum/computer_file/program/ntnet_dos/PRG = program
|
||||
var/list/data = list()
|
||||
if(!istype(PRG))
|
||||
return
|
||||
data = PRG.get_header_data()
|
||||
|
||||
if(PRG.error)
|
||||
data["error"] = PRG.error
|
||||
else if(PRG.target && PRG.executed)
|
||||
data["target"] = 1
|
||||
data["speed"] = PRG.dos_speed
|
||||
var/list/data = get_header_data()
|
||||
|
||||
// This is mostly visual, generate some strings of 1s and 0s
|
||||
// Probability of 1 is equal of completion percentage of DoS attack on this relay.
|
||||
// Combined with UI updates this adds quite nice effect to the UI
|
||||
var/percentage = PRG.target.dos_overload * 100 / PRG.target.dos_capacity
|
||||
var/list/strings[0]
|
||||
for(var/j, j<10, j++)
|
||||
var/string = ""
|
||||
for(var/i, i<20, i++)
|
||||
string = "[string][prob(percentage)]"
|
||||
strings.Add(string)
|
||||
data["dos_strings"] = strings
|
||||
data["error"] = error
|
||||
if(target && executed)
|
||||
data["target"] = TRUE
|
||||
data["speed"] = dos_speed
|
||||
|
||||
data["overload"] = target.dos_overload
|
||||
data["capacity"] = target.dos_capacity
|
||||
else
|
||||
var/list/relays[0]
|
||||
data["target"] = FALSE
|
||||
data["relays"] = list()
|
||||
for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays)
|
||||
relays.Add(R.uid)
|
||||
data["relays"] = relays
|
||||
data["focus"] = PRG.target ? PRG.target.uid : null
|
||||
data["relays"] += list(list("id" = R.uid))
|
||||
data["focus"] = target ? target.uid : null
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "ntnet_dos.tmpl", "DoS Traffic Generator", 400, 250, 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/ntnet_dos/Topic(href, href_list)
|
||||
/datum/computer_file/program/ntnet_dos/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["PRG_target_relay"])
|
||||
for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays)
|
||||
if("[R.uid]" == href_list["PRG_target_relay"])
|
||||
target = R
|
||||
return 1
|
||||
if(href_list["PRG_reset"])
|
||||
if(target)
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
executed = 0
|
||||
error = ""
|
||||
return 1
|
||||
if(href_list["PRG_execute"])
|
||||
if(target)
|
||||
executed = 1
|
||||
target.dos_sources.Add(src)
|
||||
if(ntnet_global.intrusion_detection_enabled)
|
||||
ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [computer.network_card.get_network_tag()]")
|
||||
ntnet_global.intrusion_detection_alarm = 1
|
||||
return 1
|
||||
return TRUE
|
||||
switch(action)
|
||||
if("PRG_target_relay")
|
||||
for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays)
|
||||
if(R.uid == text2num(params["targid"]))
|
||||
target = R
|
||||
break
|
||||
return TRUE
|
||||
if("PRG_reset")
|
||||
if(target)
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
executed = FALSE
|
||||
error = ""
|
||||
return TRUE
|
||||
if("PRG_execute")
|
||||
if(target)
|
||||
executed = TRUE
|
||||
target.dos_sources.Add(src)
|
||||
if(ntnet_global.intrusion_detection_enabled)
|
||||
var/obj/item/weapon/computer_hardware/network_card/network_card = computer.network_card
|
||||
ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [network_card.get_network_tag()]")
|
||||
ntnet_global.intrusion_detection_alarm = TRUE
|
||||
return TRUE
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
program_menu_icon = "home"
|
||||
extended_desc = "This virus can destroy hard drive of system it is executed on. It may be obfuscated to look like another non-malicious program. Once armed, it will destroy the system upon next execution."
|
||||
size = 13
|
||||
requires_ntnet = 0
|
||||
available_on_ntnet = 0
|
||||
available_on_syndinet = 1
|
||||
nanomodule_path = /datum/nano_module/program/revelation/
|
||||
requires_ntnet = FALSE
|
||||
available_on_ntnet = FALSE
|
||||
available_on_syndinet = TRUE
|
||||
tgui_id = "NtosRevelation"
|
||||
var/armed = 0
|
||||
|
||||
/datum/computer_file/program/revelation/run_program(var/mob/living/user)
|
||||
@@ -37,48 +37,31 @@
|
||||
if(computer.tesla_link && prob(50))
|
||||
qdel(computer.tesla_link)
|
||||
|
||||
/datum/computer_file/program/revelation/Topic(href, href_list)
|
||||
/datum/computer_file/program/revelation/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
else if(href_list["PRG_arm"])
|
||||
armed = !armed
|
||||
else if(href_list["PRG_activate"])
|
||||
activate()
|
||||
else if(href_list["PRG_obfuscate"])
|
||||
var/mob/living/user = usr
|
||||
var/newname = sanitize(input(user, "Enter new program name: "))
|
||||
if(!newname)
|
||||
return
|
||||
filedesc = newname
|
||||
for(var/datum/computer_file/program/P in ntnet_global.available_station_software)
|
||||
if(filedesc == P.filedesc)
|
||||
program_menu_icon = P.program_menu_icon
|
||||
break
|
||||
return 1
|
||||
return
|
||||
switch(action)
|
||||
if("PRG_arm")
|
||||
armed = !armed
|
||||
return TRUE
|
||||
if("PRG_activate")
|
||||
activate()
|
||||
return TRUE
|
||||
if("PRG_obfuscate")
|
||||
var/newname = params["new_name"]
|
||||
if(!newname)
|
||||
return
|
||||
filedesc = newname
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/revelation/clone()
|
||||
var/datum/computer_file/program/revelation/temp = ..()
|
||||
temp.armed = armed
|
||||
return temp
|
||||
|
||||
/datum/nano_module/program/revelation
|
||||
name = "Revelation Virus"
|
||||
/datum/computer_file/program/revelation/tgui_data(mob/user)
|
||||
var/list/data = get_header_data()
|
||||
|
||||
/datum/nano_module/program/revelation/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 = list()
|
||||
var/datum/computer_file/program/revelation/PRG = program
|
||||
if(!istype(PRG))
|
||||
return
|
||||
|
||||
data = PRG.get_header_data()
|
||||
|
||||
data["armed"] = PRG.armed
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "revelation.tmpl", "Revelation Virus", 400, 250, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
data["armed"] = armed
|
||||
|
||||
return data
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/computer_file/program/card_mod
|
||||
filename = "cardmod"
|
||||
filedesc = "ID card modification program"
|
||||
nanomodule_path = /datum/nano_module/program/card_mod
|
||||
tguimodule_path = /datum/tgui_module/cardmod
|
||||
program_icon_state = "id"
|
||||
program_key_state = "id_key"
|
||||
program_menu_icon = "key"
|
||||
@@ -9,220 +9,3 @@
|
||||
required_access = access_change_ids
|
||||
requires_ntnet = 0
|
||||
size = 8
|
||||
|
||||
/datum/nano_module/program/card_mod
|
||||
name = "ID card modification program"
|
||||
var/mod_mode = 1
|
||||
var/is_centcom = 0
|
||||
var/show_assignments = 0
|
||||
|
||||
/datum/nano_module/program/card_mod/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["src"] = "\ref[src]"
|
||||
data["station_name"] = station_name()
|
||||
data["manifest"] = data_core ? data_core.get_manifest(0) : null
|
||||
data["assignments"] = show_assignments
|
||||
if(program && program.computer)
|
||||
data["have_id_slot"] = !!program.computer.card_slot
|
||||
data["have_printer"] = !!program.computer.nano_printer
|
||||
data["authenticated"] = program.can_run(user)
|
||||
if(!program.computer.card_slot)
|
||||
mod_mode = 0 //We can't modify IDs when there is no card reader
|
||||
else
|
||||
data["have_id_slot"] = 0
|
||||
data["have_printer"] = 0
|
||||
data["authenticated"] = 0
|
||||
data["mmode"] = mod_mode
|
||||
data["centcom_access"] = is_centcom
|
||||
|
||||
if(program && program.computer && program.computer.card_slot)
|
||||
var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card
|
||||
data["has_id"] = !!id_card
|
||||
data["id_account_number"] = id_card ? id_card.associated_account_number : null
|
||||
data["id_rank"] = id_card && id_card.assignment ? id_card.assignment : "Unassigned"
|
||||
data["id_owner"] = id_card && id_card.registered_name ? id_card.registered_name : "-----"
|
||||
data["id_name"] = id_card ? id_card.name : "-----"
|
||||
|
||||
var/list/departments = list()
|
||||
for(var/D in SSjob.get_all_department_datums())
|
||||
var/datum/department/dept = D
|
||||
if(!dept.assignable) // No AI ID cards for you.
|
||||
continue
|
||||
if(dept.centcom_only && !is_centcom)
|
||||
continue
|
||||
departments[++departments.len] = list("department_name" = dept.name, "jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name)) )
|
||||
|
||||
data["departments"] = departments
|
||||
|
||||
data["all_centcom_access"] = is_centcom ? get_accesses(1) : null
|
||||
data["regions"] = get_accesses()
|
||||
|
||||
if(program.computer.card_slot && program.computer.card_slot.stored_card)
|
||||
var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card
|
||||
if(is_centcom)
|
||||
var/list/all_centcom_access = list()
|
||||
for(var/access in get_all_centcom_access())
|
||||
all_centcom_access.Add(list(list(
|
||||
"desc" = replacetext(get_centcom_access_desc(access), " ", " "),
|
||||
"ref" = access,
|
||||
"allowed" = (access in id_card.access) ? 1 : 0)))
|
||||
data["all_centcom_access"] = all_centcom_access
|
||||
else
|
||||
var/list/regions = list()
|
||||
for(var/i = 1; i <= 7; i++)
|
||||
var/list/accesses = list()
|
||||
for(var/access in get_region_accesses(i))
|
||||
if (get_access_desc(access))
|
||||
accesses.Add(list(list(
|
||||
"desc" = replacetext(get_access_desc(access), " ", " "),
|
||||
"ref" = access,
|
||||
"allowed" = (access in id_card.access) ? 1 : 0)))
|
||||
|
||||
regions.Add(list(list(
|
||||
"name" = get_region_accesses_name(i),
|
||||
"accesses" = accesses)))
|
||||
data["regions"] = regions
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "mod_identification_computer.tmpl", name, 600, 700, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/datum/nano_module/program/card_mod/proc/format_jobs(list/jobs)
|
||||
var/obj/item/weapon/card/id/id_card = program.computer.card_slot ? program.computer.card_slot.stored_card : null
|
||||
var/list/formatted = list()
|
||||
for(var/job in jobs)
|
||||
formatted.Add(list(list(
|
||||
"display_name" = replacetext(job, " ", " "),
|
||||
"target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned",
|
||||
"job" = job)))
|
||||
|
||||
return formatted
|
||||
|
||||
/datum/nano_module/program/card_mod/proc/get_accesses(var/is_centcom = 0)
|
||||
return null
|
||||
|
||||
|
||||
/datum/computer_file/program/card_mod/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
var/mob/user = usr
|
||||
var/obj/item/weapon/card/id/user_id_card = user.GetIdCard()
|
||||
var/obj/item/weapon/card/id/id_card
|
||||
if (computer.card_slot)
|
||||
id_card = computer.card_slot.stored_card
|
||||
|
||||
var/datum/nano_module/program/card_mod/module = NM
|
||||
switch(href_list["action"])
|
||||
if("switchm")
|
||||
if(href_list["target"] == "mod")
|
||||
module.mod_mode = 1
|
||||
else if (href_list["target"] == "manifest")
|
||||
module.mod_mode = 0
|
||||
if("togglea")
|
||||
if(module.show_assignments)
|
||||
module.show_assignments = 0
|
||||
else
|
||||
module.show_assignments = 1
|
||||
if("print")
|
||||
if(computer && computer.nano_printer) //This option should never be called if there is no printer
|
||||
if(module.mod_mode)
|
||||
if(can_run(user, 1))
|
||||
var/contents = {"<h4>Access Report</h4>
|
||||
<u>Prepared By:</u> [user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]<br>
|
||||
<u>For:</u> [id_card.registered_name ? id_card.registered_name : "Unregistered"]<br>
|
||||
<hr>
|
||||
<u>Assignment:</u> [id_card.assignment]<br>
|
||||
<u>Account Number:</u> #[id_card.associated_account_number]<br>
|
||||
<u>Blood Type:</u> [id_card.blood_type]<br><br>
|
||||
<u>Access:</u><br>
|
||||
"}
|
||||
|
||||
var/known_access_rights = get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM)
|
||||
for(var/A in id_card.access)
|
||||
if(A in known_access_rights)
|
||||
contents += " [get_access_desc(A)]"
|
||||
|
||||
if(!computer.nano_printer.print_text(contents,"access report"))
|
||||
to_chat(usr, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
|
||||
return
|
||||
else
|
||||
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
|
||||
else
|
||||
var/contents = {"<h4>Crew Manifest</h4>
|
||||
<br>
|
||||
[data_core ? data_core.get_manifest(0) : ""]
|
||||
"}
|
||||
if(!computer.nano_printer.print_text(contents,text("crew manifest ([])", stationtime2text())))
|
||||
to_chat(usr, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
|
||||
return
|
||||
else
|
||||
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
|
||||
if("eject")
|
||||
if(computer && computer.card_slot)
|
||||
if(id_card)
|
||||
data_core.manifest_modify(id_card.registered_name, id_card.assignment)
|
||||
computer.proc_eject_id(user)
|
||||
if("terminate")
|
||||
if(computer && can_run(user, 1))
|
||||
id_card.assignment = "Dismissed" //VOREStation Edit: setting adjustment
|
||||
id_card.access = list()
|
||||
callHook("terminate_employee", list(id_card))
|
||||
if("edit")
|
||||
if(computer && can_run(user, 1))
|
||||
if(href_list["name"])
|
||||
var/temp_name = sanitizeName(input("Enter name.", "Name", id_card.registered_name),allow_numbers=TRUE)
|
||||
if(temp_name)
|
||||
id_card.registered_name = temp_name
|
||||
else
|
||||
computer.visible_message("<span class='notice'>[computer] buzzes rudely.</span>")
|
||||
else if(href_list["account"])
|
||||
var/account_num = text2num(input("Enter account number.", "Account", id_card.associated_account_number))
|
||||
id_card.associated_account_number = account_num
|
||||
if("assign")
|
||||
if(computer && can_run(user, 1) && id_card)
|
||||
var/t1 = href_list["assign_target"]
|
||||
if(t1 == "Custom")
|
||||
var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment", id_card.assignment), 45)
|
||||
//let custom jobs function as an impromptu alt title, mainly for sechuds
|
||||
if(temp_t)
|
||||
id_card.assignment = temp_t
|
||||
else
|
||||
var/list/access = list()
|
||||
if(module.is_centcom)
|
||||
access = get_centcom_access(t1)
|
||||
else
|
||||
var/datum/job/jobdatum
|
||||
for(var/jobtype in typesof(/datum/job))
|
||||
var/datum/job/J = new jobtype
|
||||
if(ckey(J.title) == ckey(t1))
|
||||
jobdatum = J
|
||||
break
|
||||
if(!jobdatum)
|
||||
to_chat(usr, "<span class='warning'>No log exists for this job: [t1]</span>")
|
||||
return
|
||||
|
||||
access = jobdatum.get_access()
|
||||
|
||||
id_card.access = access
|
||||
id_card.assignment = t1
|
||||
id_card.rank = t1
|
||||
|
||||
callHook("reassign_employee", list(id_card))
|
||||
if("access")
|
||||
if(href_list["allowed"] && computer && can_run(user, 1))
|
||||
var/access_type = text2num(href_list["access_target"])
|
||||
var/access_allowed = text2num(href_list["allowed"])
|
||||
if(access_type in get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM))
|
||||
id_card.access -= access_type
|
||||
if(!access_allowed)
|
||||
id_card.access += access_type
|
||||
if(id_card)
|
||||
id_card.name = text("[id_card.registered_name]'s ID Card ([id_card.assignment])")
|
||||
|
||||
SSnanoui.update_uis(NM)
|
||||
return 1
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
program_icon_state = "comm"
|
||||
program_key_state = "med_key"
|
||||
program_menu_icon = "flag"
|
||||
nanomodule_path = /datum/nano_module/program/comm
|
||||
tguimodule_path = /datum/tgui_module/communications/ntos
|
||||
extended_desc = "Used to command and control. Can relay long-range communications. This program can not be run on tablet computers."
|
||||
required_access = access_heads
|
||||
requires_ntnet = 1
|
||||
@@ -24,269 +24,6 @@
|
||||
temp.message_core.messages = message_core.messages.Copy()
|
||||
return temp
|
||||
|
||||
/datum/nano_module/program/comm
|
||||
name = "Command and Communications Program"
|
||||
//available_to_ai = TRUE
|
||||
var/current_status = STATE_DEFAULT
|
||||
var/msg_line1 = ""
|
||||
var/msg_line2 = ""
|
||||
var/centcomm_message_cooldown = 0
|
||||
var/announcment_cooldown = 0
|
||||
var/datum/announcement/priority/crew_announcement = new
|
||||
var/current_viewing_message_id = 0
|
||||
var/current_viewing_message = null
|
||||
|
||||
/datum/nano_module/program/comm/New()
|
||||
..()
|
||||
crew_announcement.newscast = 1
|
||||
|
||||
/datum/nano_module/program/comm/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()
|
||||
|
||||
if(program)
|
||||
data["emagged"] = program.computer_emagged
|
||||
data["net_comms"] = !!program.get_signal(NTNET_COMMUNICATION) //Double !! is needed to get 1 or 0 answer
|
||||
data["net_syscont"] = !!program.get_signal(NTNET_SYSTEMCONTROL)
|
||||
if(program.computer)
|
||||
data["have_printer"] = !!program.computer.nano_printer
|
||||
else
|
||||
data["have_printer"] = 0
|
||||
else
|
||||
data["emagged"] = 0
|
||||
data["net_comms"] = 1
|
||||
data["net_syscont"] = 1
|
||||
data["have_printer"] = 0
|
||||
|
||||
data["message_line1"] = msg_line1
|
||||
data["message_line2"] = msg_line2
|
||||
data["state"] = current_status
|
||||
data["isAI"] = issilicon(usr)
|
||||
data["authenticated"] = get_authentication_level(user)
|
||||
data["current_security_level"] = security_level
|
||||
data["current_security_level_title"] = num2seclevel(security_level)
|
||||
|
||||
data["def_SEC_LEVEL_DELTA"] = SEC_LEVEL_DELTA
|
||||
data["def_SEC_LEVEL_YELLOW"] = SEC_LEVEL_YELLOW
|
||||
data["def_SEC_LEVEL_ORANGE"] = SEC_LEVEL_ORANGE
|
||||
data["def_SEC_LEVEL_VIOLET"] = SEC_LEVEL_VIOLET
|
||||
data["def_SEC_LEVEL_BLUE"] = SEC_LEVEL_BLUE
|
||||
data["def_SEC_LEVEL_GREEN"] = SEC_LEVEL_GREEN
|
||||
|
||||
var/datum/comm_message_listener/l = obtain_message_listener()
|
||||
data["messages"] = l.messages
|
||||
data["message_deletion_allowed"] = l != global_message_listener
|
||||
data["message_current_id"] = current_viewing_message_id
|
||||
if(current_viewing_message)
|
||||
data["message_current"] = current_viewing_message
|
||||
|
||||
if(emergency_shuttle.location())
|
||||
data["have_shuttle"] = 1
|
||||
if(emergency_shuttle.online())
|
||||
data["have_shuttle_called"] = 1
|
||||
else
|
||||
data["have_shuttle_called"] = 0
|
||||
else
|
||||
data["have_shuttle"] = 0
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "mod_communication.tmpl", name, 550, 420, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/datum/nano_module/program/comm/proc/get_authentication_level(var/mob/user)
|
||||
if(program)
|
||||
if(program.can_run(user, 0, access_captain))
|
||||
return 2
|
||||
else
|
||||
return program.can_run(user)
|
||||
return 1
|
||||
|
||||
/datum/nano_module/program/comm/proc/obtain_message_listener()
|
||||
if(program)
|
||||
var/datum/computer_file/program/comm/P = program
|
||||
return P.message_core
|
||||
return global_message_listener
|
||||
|
||||
/datum/nano_module/program/comm/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
var/mob/user = usr
|
||||
var/ntn_comm = program ? !!program.get_signal(NTNET_COMMUNICATION) : 1
|
||||
var/ntn_cont = program ? !!program.get_signal(NTNET_SYSTEMCONTROL) : 1
|
||||
var/datum/comm_message_listener/l = obtain_message_listener()
|
||||
switch(href_list["action"])
|
||||
if("sw_menu")
|
||||
. = 1
|
||||
current_status = text2num(href_list["target"])
|
||||
if("announce")
|
||||
. = 1
|
||||
if(get_authentication_level(user) == 2 && !issilicon(usr) && ntn_comm)
|
||||
if(user)
|
||||
var/obj/item/weapon/card/id/id_card = user.GetIdCard()
|
||||
crew_announcement.announcer = GetNameAndAssignmentFromId(id_card)
|
||||
else
|
||||
crew_announcement.announcer = "Unknown"
|
||||
if(announcment_cooldown)
|
||||
to_chat(usr, "Please allow at least one minute to pass between announcements")
|
||||
return TRUE
|
||||
var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|message
|
||||
if(!input || !can_still_topic())
|
||||
return 1
|
||||
crew_announcement.Announce(input)
|
||||
announcment_cooldown = 1
|
||||
spawn(600)//One minute cooldown
|
||||
announcment_cooldown = 0
|
||||
if("message")
|
||||
. = 1
|
||||
if(href_list["target"] == "emagged")
|
||||
if(program)
|
||||
if(get_authentication_level(user) == 2 && program.computer_emagged && !issilicon(usr) && ntn_comm)
|
||||
if(centcomm_message_cooldown)
|
||||
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text)
|
||||
if(!input || !can_still_topic())
|
||||
return 1
|
||||
Syndicate_announce(input, usr)
|
||||
to_chat(usr, "<span class='notice'>Message transmitted.</span>")
|
||||
log_say("[key_name(usr)] has made an illegal announcement: [input]")
|
||||
centcomm_message_cooldown = 1
|
||||
spawn(300)//30 second cooldown
|
||||
centcomm_message_cooldown = 0
|
||||
else if(href_list["target"] == "regular")
|
||||
if(get_authentication_level(user) == 2 && !issilicon(usr) && ntn_comm)
|
||||
if(centcomm_message_cooldown)
|
||||
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
if(!is_relay_online())//Contact Centcom has a check, Syndie doesn't to allow for Traitor funs.
|
||||
to_chat(usr, "<span class='warning'>No Emergency Bluespace Relay detected. Unable to transmit message.</span>")
|
||||
return 1
|
||||
var/input = sanitize(input("Please choose a message to transmit to Centcomm via quantum entanglement. \
|
||||
Please be aware that this process is very expensive, and abuse will lead to... termination. \
|
||||
Transmission does not guarantee a response. There is a 30 second delay before you may send another message, \
|
||||
be clear, full and concise.", "Central Command Quantum Messaging") as null|message)
|
||||
if(!input || !can_still_topic())
|
||||
return 1
|
||||
CentCom_announce(input, usr)
|
||||
to_chat(usr, "<span class='notice'>Message transmitted.</span>")
|
||||
log_say("[key_name(usr)] has made an IA Centcomm announcement: [input]")
|
||||
centcomm_message_cooldown = 1
|
||||
spawn(300) //30 second cooldown
|
||||
centcomm_message_cooldown = 0
|
||||
if("shuttle")
|
||||
. = 1
|
||||
if(get_authentication_level(user) && ntn_cont)
|
||||
if(href_list["target"] == "call")
|
||||
var/confirm = alert("Are you sure you want to call the shuttle?", name, "No", "Yes")
|
||||
if(confirm == "Yes" && can_still_topic())
|
||||
call_shuttle_proc(usr)
|
||||
|
||||
if(href_list["target"] == "cancel" && !issilicon(usr))
|
||||
var/confirm = alert("Are you sure you want to cancel the shuttle?", name, "No", "Yes")
|
||||
if(confirm == "Yes" && can_still_topic())
|
||||
cancel_call_proc(usr)
|
||||
if("setstatus")
|
||||
. = 1
|
||||
if(get_authentication_level(user) && ntn_cont)
|
||||
switch(href_list["target"])
|
||||
if("line1")
|
||||
var/linput = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", msg_line1) as text|null, 40), 40)
|
||||
if(can_still_topic())
|
||||
msg_line1 = linput
|
||||
if("line2")
|
||||
var/linput = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", msg_line2) as text|null, 40), 40)
|
||||
if(can_still_topic())
|
||||
msg_line2 = linput
|
||||
if("message")
|
||||
post_status("message", msg_line1, msg_line2)
|
||||
if("alert")
|
||||
post_status("alert", href_list["alert"])
|
||||
else
|
||||
post_status(href_list["target"])
|
||||
if("setalert")
|
||||
. = 1
|
||||
if(get_authentication_level(user) && !issilicon(usr) && ntn_cont && ntn_comm)
|
||||
var/current_level = text2num(href_list["target"])
|
||||
var/confirm = alert("Are you sure you want to change alert level to [num2seclevel(current_level)]?", name, "No", "Yes")
|
||||
if(confirm == "Yes" && can_still_topic())
|
||||
var/old_level = security_level
|
||||
if(!current_level) current_level = SEC_LEVEL_GREEN
|
||||
if(current_level < SEC_LEVEL_GREEN) current_level = SEC_LEVEL_GREEN
|
||||
if(current_level > SEC_LEVEL_BLUE) current_level = SEC_LEVEL_BLUE //Cannot engage delta with this
|
||||
set_security_level(current_level)
|
||||
if(security_level != old_level)
|
||||
log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
|
||||
message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
|
||||
switch(security_level)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
feedback_inc("alert_comms_green",1)
|
||||
if(SEC_LEVEL_YELLOW)
|
||||
feedback_inc("alert_comms_yellow",1)
|
||||
if(SEC_LEVEL_ORANGE)
|
||||
feedback_inc("alert_comms_orange",1)
|
||||
if(SEC_LEVEL_VIOLET)
|
||||
feedback_inc("alert_comms_violet",1)
|
||||
if(SEC_LEVEL_BLUE)
|
||||
feedback_inc("alert_comms_blue",1)
|
||||
else
|
||||
to_chat(usr, "You press button, but red light flashes and nothing happens.")//This should never happen
|
||||
|
||||
current_status = STATE_DEFAULT
|
||||
if("viewmessage")
|
||||
. = 1
|
||||
if(get_authentication_level(user) && ntn_comm)
|
||||
current_viewing_message_id = text2num(href_list["target"])
|
||||
for(var/list/m in l.messages)
|
||||
if(m["id"] == current_viewing_message_id)
|
||||
current_viewing_message = m
|
||||
current_status = STATE_VIEWMESSAGE
|
||||
if("delmessage")
|
||||
. = 1
|
||||
if(get_authentication_level(user) && ntn_comm && l != global_message_listener)
|
||||
l.Remove(current_viewing_message)
|
||||
current_status = STATE_MESSAGELIST
|
||||
if("printmessage")
|
||||
. = 1
|
||||
if(get_authentication_level(user) && ntn_comm)
|
||||
if(program && program.computer && program.computer.nano_printer)
|
||||
if(!program.computer.nano_printer.print_text(current_viewing_message["contents"],current_viewing_message["title"]))
|
||||
to_chat(usr, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
|
||||
else
|
||||
program.computer.visible_message("<span class='notice'>\The [program.computer] prints out paper.</span>")
|
||||
|
||||
|
||||
/datum/nano_module/program/comm/proc/post_status(var/command, var/data1, var/data2)
|
||||
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
|
||||
var/datum/signal/status_signal = new
|
||||
status_signal.source = src
|
||||
status_signal.transmission_method = TRANSMISSION_RADIO
|
||||
status_signal.data["command"] = command
|
||||
|
||||
switch(command)
|
||||
if("message")
|
||||
status_signal.data["msg1"] = data1
|
||||
status_signal.data["msg2"] = data2
|
||||
log_admin("STATUS: [key_name(usr)] set status screen message with [src]: [data1] [data2]")
|
||||
if("alert")
|
||||
status_signal.data["picture_state"] = data1
|
||||
|
||||
frequency.post_signal(src, status_signal)
|
||||
|
||||
#undef STATE_DEFAULT
|
||||
#undef STATE_MESSAGELIST
|
||||
#undef STATE_VIEWMESSAGE
|
||||
#undef STATE_STATUSDISPLAY
|
||||
#undef STATE_ALERT_LEVEL
|
||||
|
||||
/*
|
||||
General message handling stuff
|
||||
*/
|
||||
@@ -304,19 +41,9 @@ proc/post_comm_message(var/message_title, var/message_text)
|
||||
message["title"] = message_title
|
||||
message["contents"] = message_text
|
||||
|
||||
for (var/datum/comm_message_listener/l in comm_message_listeners)
|
||||
for(var/datum/comm_message_listener/l in comm_message_listeners)
|
||||
l.Add(message)
|
||||
|
||||
//Old console support
|
||||
for (var/obj/machinery/computer/communications/comm in machines)
|
||||
if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept)
|
||||
var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc )
|
||||
intercept.name = message_title
|
||||
intercept.info = message_text
|
||||
|
||||
comm.messagetitle.Add(message_title)
|
||||
comm.messagetext.Add(message_text)
|
||||
|
||||
/datum/comm_message_listener
|
||||
var/list/messages
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -8,29 +8,34 @@
|
||||
size = 12
|
||||
requires_ntnet = 1
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/email_administration
|
||||
tgui_id = "NtosEmailAdministration"
|
||||
required_access = access_network
|
||||
|
||||
|
||||
|
||||
|
||||
/datum/nano_module/email_administration/
|
||||
name = "Email Client"
|
||||
var/datum/computer_file/data/email_account/current_account = null
|
||||
var/datum/computer_file/data/email_message/current_message = null
|
||||
var/error = ""
|
||||
|
||||
/datum/nano_module/email_administration/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()
|
||||
/datum/computer_file/program/email_administration/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = get_header_data()
|
||||
|
||||
if(error)
|
||||
data["error"] = error
|
||||
else if(istype(current_message))
|
||||
data["msg_title"] = current_message.title
|
||||
data["msg_body"] = pencode2html(current_message.stored_data)
|
||||
data["msg_timestamp"] = current_message.timestamp
|
||||
data["msg_source"] = current_message.source
|
||||
else if(istype(current_account))
|
||||
data["error"] = error
|
||||
|
||||
data["cur_title"] = null
|
||||
data["cur_body"] = null
|
||||
data["cur_timestamp"] = null
|
||||
data["cur_source"] = null
|
||||
|
||||
if(istype(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["current_account"] = null
|
||||
data["cur_suspended"] = null
|
||||
data["messages"] = null
|
||||
|
||||
if(istype(current_account))
|
||||
data["current_account"] = current_account.login
|
||||
data["cur_suspended"] = current_account.suspended
|
||||
var/list/all_messages = list()
|
||||
@@ -42,103 +47,90 @@
|
||||
"uid" = message.uid
|
||||
)))
|
||||
data["messages"] = all_messages
|
||||
data["messagecount"] = all_messages.len
|
||||
else
|
||||
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,
|
||||
"uid" = account.uid
|
||||
)))
|
||||
data["accounts"] = all_accounts
|
||||
data["accountcount"] = all_accounts.len
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "email_administration.tmpl", "Email Administration Utility", 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()
|
||||
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,
|
||||
"uid" = account.uid
|
||||
)))
|
||||
data["accounts"] = all_accounts
|
||||
|
||||
return data
|
||||
|
||||
/datum/nano_module/email_administration/Topic(href, href_list)
|
||||
/datum/computer_file/program/email_administration/tgui_act(action, list/params, datum/tgui/ui)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
var/mob/user = usr
|
||||
if(!istype(user))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
// High security - can only be operated when the user has an ID with access on them.
|
||||
var/obj/item/weapon/card/id/I = user.GetIdCard()
|
||||
var/obj/item/weapon/card/id/I = usr.GetIdCard()
|
||||
if(!istype(I) || !(access_network in I.access))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(href_list["back"])
|
||||
if(error)
|
||||
error = ""
|
||||
else if(current_message)
|
||||
current_message = null
|
||||
else
|
||||
current_account = null
|
||||
return 1
|
||||
switch(action)
|
||||
if("back")
|
||||
if(error)
|
||||
error = ""
|
||||
else if(current_message)
|
||||
current_message = null
|
||||
else
|
||||
current_account = null
|
||||
return TRUE
|
||||
|
||||
if(href_list["ban"])
|
||||
if(!current_account)
|
||||
return 1
|
||||
if("ban")
|
||||
if(!current_account)
|
||||
return TRUE
|
||||
|
||||
current_account.suspended = !current_account.suspended
|
||||
ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended by SA [I.registered_name] ([I.assignment]).")
|
||||
error = "Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended."
|
||||
return 1
|
||||
current_account.suspended = !current_account.suspended
|
||||
ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended by SA [I.registered_name] ([I.assignment]).")
|
||||
error = "Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended."
|
||||
return TRUE
|
||||
|
||||
if(href_list["changepass"])
|
||||
if(!current_account)
|
||||
return 1
|
||||
if("changepass")
|
||||
if(!current_account)
|
||||
return TRUE
|
||||
|
||||
var/newpass = sanitize(input(user,"Enter new password for account [current_account.login]", "Password"), 100)
|
||||
if(!newpass)
|
||||
return 1
|
||||
current_account.password = newpass
|
||||
ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Password for account [current_account.login] has been changed by SA [I.registered_name] ([I.assignment]).")
|
||||
return 1
|
||||
var/newpass = sanitize(input(usr,"Enter new password for account [current_account.login]", "Password"), 100)
|
||||
if(!newpass)
|
||||
return TRUE
|
||||
current_account.password = newpass
|
||||
ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Password for account [current_account.login] has been changed by SA [I.registered_name] ([I.assignment]).")
|
||||
return TRUE
|
||||
|
||||
if(href_list["viewmail"])
|
||||
if(!current_account)
|
||||
return 1
|
||||
if("viewmail")
|
||||
if(!current_account)
|
||||
return TRUE
|
||||
|
||||
for(var/datum/computer_file/data/email_message/received_message in (current_account.inbox | current_account.spam | current_account.deleted))
|
||||
if(received_message.uid == text2num(href_list["viewmail"]))
|
||||
current_message = received_message
|
||||
break
|
||||
return 1
|
||||
for(var/datum/computer_file/data/email_message/received_message in (current_account.inbox | current_account.spam | current_account.deleted))
|
||||
if(received_message.uid == text2num(params["viewmail"]))
|
||||
current_message = received_message
|
||||
break
|
||||
return TRUE
|
||||
|
||||
if(href_list["viewaccount"])
|
||||
for(var/datum/computer_file/data/email_account/email_account in ntnet_global.email_accounts)
|
||||
if(email_account.uid == text2num(href_list["viewaccount"]))
|
||||
current_account = email_account
|
||||
break
|
||||
return 1
|
||||
if("viewaccount")
|
||||
for(var/datum/computer_file/data/email_account/email_account in ntnet_global.email_accounts)
|
||||
if(email_account.uid == text2num(params["viewaccount"]))
|
||||
current_account = email_account
|
||||
break
|
||||
return TRUE
|
||||
|
||||
if(href_list["newaccount"])
|
||||
var/newdomain = sanitize(input(user,"Pick domain:", "Domain name") as null|anything in using_map.usable_email_tlds)
|
||||
if(!newdomain)
|
||||
return 1
|
||||
var/newlogin = sanitize(input(user,"Pick account name (@[newdomain]):", "Account name"), 100)
|
||||
if(!newlogin)
|
||||
return 1
|
||||
if("newaccount")
|
||||
var/newdomain = sanitize(input(usr,"Pick domain:", "Domain name") as null|anything in using_map.usable_email_tlds)
|
||||
if(!newdomain)
|
||||
return TRUE
|
||||
var/newlogin = sanitize(input(usr,"Pick account name (@[newdomain]):", "Account name"), 100)
|
||||
if(!newlogin)
|
||||
return TRUE
|
||||
|
||||
var/complete_login = "[newlogin]@[newdomain]"
|
||||
if(ntnet_global.does_email_exist(complete_login))
|
||||
error = "Error creating account: An account with same address already exists."
|
||||
return 1
|
||||
var/complete_login = "[newlogin]@[newdomain]"
|
||||
if(ntnet_global.does_email_exist(complete_login))
|
||||
error = "Error creating account: An account with same address already exists."
|
||||
return TRUE
|
||||
|
||||
var/datum/computer_file/data/email_account/new_account = new/datum/computer_file/data/email_account()
|
||||
new_account.login = complete_login
|
||||
new_account.password = GenerateKey()
|
||||
error = "Email [new_account.login] has been created, with generated password [new_account.password]"
|
||||
return 1
|
||||
var/datum/computer_file/data/email_account/new_account = new/datum/computer_file/data/email_account()
|
||||
new_account.login = complete_login
|
||||
new_account.password = GenerateKey()
|
||||
error = "Email [new_account.login] has been created, with generated password [new_account.password]"
|
||||
return TRUE
|
||||
|
||||
@@ -6,19 +6,15 @@
|
||||
program_menu_icon = "wrench"
|
||||
extended_desc = "This program monitors the local NTNet network, provides access to logging systems, and allows for configuration changes"
|
||||
size = 12
|
||||
requires_ntnet = 1
|
||||
requires_ntnet = TRUE
|
||||
required_access = access_network
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/computer_ntnetmonitor/
|
||||
available_on_ntnet = TRUE
|
||||
tgui_id = "NtosNetMonitor"
|
||||
|
||||
/datum/nano_module/computer_ntnetmonitor
|
||||
name = "NTNet Diagnostics and Monitoring"
|
||||
//available_to_ai = TRUE
|
||||
|
||||
/datum/nano_module/computer_ntnetmonitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/computer_file/program/ntnetmonitor/tgui_data(mob/user)
|
||||
if(!ntnet_global)
|
||||
return
|
||||
var/list/data = host.initial_data()
|
||||
var/list/data = get_header_data()
|
||||
|
||||
data["ntnetstatus"] = ntnet_global.check_function()
|
||||
data["ntnetrelays"] = ntnet_global.relays.len
|
||||
@@ -30,73 +26,68 @@
|
||||
data["config_communication"] = ntnet_global.setting_communication
|
||||
data["config_systemcontrol"] = ntnet_global.setting_systemcontrol
|
||||
|
||||
data["ntnetlogs"] = ntnet_global.logs
|
||||
data["ntnetmaxlogs"] = ntnet_global.setting_maxlogcount
|
||||
data["ntnetlogs"] = list()
|
||||
data["minlogs"] = MIN_NTNET_LOGS
|
||||
data["maxlogs"] = MAX_NTNET_LOGS
|
||||
|
||||
data["banned_nids"] = list(ntnet_global.banned_nids)
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "ntnet_monitor.tmpl", "NTNet Diagnostics and Monitoring Tool", 575, 700, state = state)
|
||||
if(host.update_layout())
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
for(var/i in ntnet_global.logs)
|
||||
data["ntnetlogs"] += list(list("entry" = i))
|
||||
data["ntnetmaxlogs"] = ntnet_global.setting_maxlogcount
|
||||
|
||||
/datum/nano_module/computer_ntnetmonitor/Topic(href, href_list, state)
|
||||
var/mob/user = usr
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/ntnetmonitor/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["resetIDS"])
|
||||
if(ntnet_global)
|
||||
ntnet_global.resetIDS()
|
||||
return 1
|
||||
if(href_list["toggleIDS"])
|
||||
if(ntnet_global)
|
||||
ntnet_global.toggleIDS()
|
||||
return 1
|
||||
if(href_list["toggleWireless"])
|
||||
if(!ntnet_global)
|
||||
return 1
|
||||
return
|
||||
switch(action)
|
||||
if("resetIDS")
|
||||
if(ntnet_global)
|
||||
ntnet_global.resetIDS()
|
||||
return TRUE
|
||||
if("toggleIDS")
|
||||
if(ntnet_global)
|
||||
ntnet_global.toggleIDS()
|
||||
return TRUE
|
||||
if("toggleWireless")
|
||||
if(!ntnet_global)
|
||||
return
|
||||
|
||||
// NTNet is disabled. Enabling can be done without user prompt
|
||||
if(ntnet_global.setting_disabled)
|
||||
ntnet_global.setting_disabled = 0
|
||||
return 1
|
||||
// NTNet is disabled. Enabling can be done without user prompt
|
||||
if(ntnet_global.setting_disabled)
|
||||
ntnet_global.setting_disabled = FALSE
|
||||
return TRUE
|
||||
|
||||
// NTNet is enabled and user is about to shut it down. Let's ask them if they really want to do it, as wirelessly connected computers won't connect without NTNet being enabled (which may prevent people from turning it back on)
|
||||
if(!user)
|
||||
return 1
|
||||
var/response = alert(user, "Really disable NTNet wireless? If your computer is connected wirelessly you won't be able to turn it back on! This will affect all connected wireless devices.", "NTNet shutdown", "Yes", "No")
|
||||
if(response == "Yes")
|
||||
ntnet_global.setting_disabled = 1
|
||||
return 1
|
||||
if(href_list["purgelogs"])
|
||||
if(ntnet_global)
|
||||
ntnet_global.purge_logs()
|
||||
return 1
|
||||
if(href_list["updatemaxlogs"])
|
||||
var/logcount = text2num(input(user,"Enter amount of logs to keep in memory ([MIN_NTNET_LOGS]-[MAX_NTNET_LOGS]):"))
|
||||
if(ntnet_global)
|
||||
ntnet_global.update_max_log_count(logcount)
|
||||
return 1
|
||||
if(href_list["toggle_function"])
|
||||
if(!ntnet_global)
|
||||
return 1
|
||||
ntnet_global.toggle_function(href_list["toggle_function"])
|
||||
return 1
|
||||
if(href_list["ban_nid"])
|
||||
if(!ntnet_global)
|
||||
return 1
|
||||
var/nid = input(user,"Enter NID of device which you want to block from the network:", "Enter NID") as null|num
|
||||
if(nid && CanUseTopic(user, state))
|
||||
ntnet_global.banned_nids |= nid
|
||||
return 1
|
||||
if(href_list["unban_nid"])
|
||||
if(!ntnet_global)
|
||||
return 1
|
||||
var/nid = input(user,"Enter NID of device which you want to unblock from the network:", "Enter NID") as null|num
|
||||
if(nid && CanUseTopic(user, state))
|
||||
ntnet_global.banned_nids -= nid
|
||||
return 1
|
||||
var/response = alert(usr, "Really disable NTNet wireless? If your computer is connected wirelessly you won't be able to turn it back on! This will affect all connected wireless devices.", "NTNet shutdown", "Yes", "No")
|
||||
if(response == "Yes" && tgui_status(usr, state) == STATUS_INTERACTIVE)
|
||||
ntnet_global.setting_disabled = TRUE
|
||||
return TRUE
|
||||
if("purgelogs")
|
||||
if(ntnet_global)
|
||||
ntnet_global.purge_logs()
|
||||
return TRUE
|
||||
if("updatemaxlogs")
|
||||
var/logcount = params["new_number"]
|
||||
if(ntnet_global)
|
||||
ntnet_global.update_max_log_count(logcount)
|
||||
return TRUE
|
||||
if("toggle_function")
|
||||
if(!ntnet_global)
|
||||
return
|
||||
ntnet_global.toggle_function(text2num(params["id"]))
|
||||
return TRUE
|
||||
if("ban_nid")
|
||||
if(!ntnet_global)
|
||||
return
|
||||
var/nid = input(usr,"Enter NID of device which you want to block from the network:", "Enter NID") as null|num
|
||||
if(nid && tgui_status(usr, state) == STATUS_INTERACTIVE)
|
||||
ntnet_global.banned_nids |= nid
|
||||
return TRUE
|
||||
if("unban_nid")
|
||||
if(!ntnet_global)
|
||||
return
|
||||
var/nid = input(usr,"Enter NID of device which you want to unblock from the network:", "Enter NID") as null|num
|
||||
if(nid && tgui_status(usr, state) == STATUS_INTERACTIVE)
|
||||
ntnet_global.banned_nids -= nid
|
||||
return TRUE
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
var/warrant_uid = 0
|
||||
/datum/datacore/var/list/warrants[] = list()
|
||||
/datum/datacore
|
||||
var/list/warrants = list()
|
||||
|
||||
/datum/data/record/warrant
|
||||
var/warrant_id
|
||||
|
||||
@@ -7,7 +9,6 @@ var/warrant_uid = 0
|
||||
..()
|
||||
warrant_id = warrant_uid++
|
||||
|
||||
|
||||
/datum/computer_file/program/digitalwarrant
|
||||
filename = "digitalwarrant"
|
||||
filedesc = "Warrant Assistant"
|
||||
@@ -20,126 +21,119 @@ var/warrant_uid = 0
|
||||
available_on_ntnet = 1
|
||||
required_access = access_security
|
||||
usage_flags = PROGRAM_ALL
|
||||
nanomodule_path = /datum/nano_module/program/digitalwarrant/
|
||||
tgui_id = "NtosDigitalWarrant"
|
||||
|
||||
/datum/nano_module/program/digitalwarrant/
|
||||
name = "Warrant Assistant"
|
||||
var/datum/data/record/warrant/activewarrant
|
||||
|
||||
/datum/nano_module/program/digitalwarrant/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()
|
||||
/datum/computer_file/program/digitalwarrant/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = get_header_data()
|
||||
|
||||
data["warrantname"] = null
|
||||
data["warrantcharges"] = null
|
||||
data["warrantauth"] = null
|
||||
data["type"] = null
|
||||
|
||||
if(activewarrant)
|
||||
data["warrantname"] = activewarrant.fields["namewarrant"]
|
||||
data["warrantcharges"] = activewarrant.fields["charges"]
|
||||
data["warrantauth"] = activewarrant.fields["auth"]
|
||||
data["type"] = activewarrant.fields["arrestsearch"]
|
||||
else
|
||||
var/list/allwarrants = list()
|
||||
for(var/datum/data/record/warrant/W in data_core.warrants)
|
||||
allwarrants.Add(list(list(
|
||||
|
||||
var/list/allwarrants = list()
|
||||
for(var/datum/data/record/warrant/W in data_core.warrants)
|
||||
allwarrants.Add(list(list(
|
||||
"warrantname" = W.fields["namewarrant"],
|
||||
"charges" = "[copytext(W.fields["charges"],1,min(length(W.fields["charges"]) + 1, 50))]...",
|
||||
"auth" = W.fields["auth"],
|
||||
"id" = W.warrant_id,
|
||||
"arrestsearch" = W.fields["arrestsearch"]
|
||||
)))
|
||||
data["allwarrants"] = allwarrants
|
||||
data["allwarrants"] = allwarrants
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "digitalwarrant.tmpl", name, 500, 350, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
return data
|
||||
|
||||
/datum/nano_module/program/digitalwarrant/Topic(href, href_list)
|
||||
/datum/computer_file/program/digitalwarrant/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(href_list["sw_menu"])
|
||||
activewarrant = null
|
||||
switch(action)
|
||||
if("back")
|
||||
. = TRUE
|
||||
activewarrant = null
|
||||
|
||||
if(href_list["editwarrant"])
|
||||
. = 1
|
||||
for(var/datum/data/record/warrant/W in data_core.warrants)
|
||||
if(W.warrant_id == text2num(href_list["editwarrant"]))
|
||||
activewarrant = W
|
||||
break
|
||||
if("editwarrant")
|
||||
. = TRUE
|
||||
for(var/datum/data/record/warrant/W in data_core.warrants)
|
||||
if(W.warrant_id == text2num(params["id"]))
|
||||
activewarrant = W
|
||||
break
|
||||
|
||||
// The following actions will only be possible if the user has an ID with security access equipped. This is in line with modular computer framework's authentication methods,
|
||||
// which also use RFID scanning to allow or disallow access to some functions. Anyone can view warrants, editing requires ID. This also prevents situations where you show a tablet
|
||||
// to someone who is to be arrested, which allows them to change the stuff there.
|
||||
|
||||
var/mob/user = usr
|
||||
if(!istype(user))
|
||||
return
|
||||
var/obj/item/weapon/card/id/I = user.GetIdCard()
|
||||
var/obj/item/weapon/card/id/I = usr.GetIdCard()
|
||||
if(!istype(I) || !I.registered_name || !(access_security in I.access))
|
||||
to_chat(user, "Authentication error: Unable to locate ID with apropriate access to allow this operation.")
|
||||
to_chat(usr, "Authentication error: Unable to locate ID with appropriate access to allow this operation.")
|
||||
return
|
||||
|
||||
if(href_list["addwarrant"])
|
||||
. = 1
|
||||
var/datum/data/record/warrant/W = new()
|
||||
var/temp = sanitize(input(usr, "Do you want to create a search-, or an arrest warrant?") as null|anything in list("search","arrest"))
|
||||
if(CanInteract(user, default_state))
|
||||
if(temp == "arrest")
|
||||
W.fields["namewarrant"] = "Unknown"
|
||||
W.fields["charges"] = "No charges present"
|
||||
W.fields["auth"] = "Unauthorized"
|
||||
W.fields["arrestsearch"] = "arrest"
|
||||
if(temp == "search")
|
||||
W.fields["namewarrant"] = "No suspect/location given" // VOREStation edit
|
||||
W.fields["charges"] = "No reason given"
|
||||
W.fields["auth"] = "Unauthorized"
|
||||
W.fields["arrestsearch"] = "search"
|
||||
activewarrant = W
|
||||
switch(action)
|
||||
if("addwarrant")
|
||||
. = TRUE
|
||||
var/datum/data/record/warrant/W = new()
|
||||
var/temp = sanitize(input(usr, "Do you want to create a search-, or an arrest warrant?") as null|anything in list("search","arrest"))
|
||||
if(tgui_status(usr, state) == STATUS_INTERACTIVE)
|
||||
if(temp == "arrest")
|
||||
W.fields["namewarrant"] = "Unknown"
|
||||
W.fields["charges"] = "No charges present"
|
||||
W.fields["auth"] = "Unauthorized"
|
||||
W.fields["arrestsearch"] = "arrest"
|
||||
if(temp == "search")
|
||||
W.fields["namewarrant"] = "No suspect/location given" // VOREStation edit
|
||||
W.fields["charges"] = "No reason given"
|
||||
W.fields["auth"] = "Unauthorized"
|
||||
W.fields["arrestsearch"] = "search"
|
||||
activewarrant = W
|
||||
|
||||
if(href_list["savewarrant"])
|
||||
. = 1
|
||||
data_core.warrants |= activewarrant
|
||||
activewarrant = null
|
||||
if("savewarrant")
|
||||
. = TRUE
|
||||
data_core.warrants |= activewarrant
|
||||
activewarrant = null
|
||||
|
||||
if(href_list["deletewarrant"])
|
||||
. = 1
|
||||
data_core.warrants -= activewarrant
|
||||
activewarrant = null
|
||||
if("deletewarrant")
|
||||
. = TRUE
|
||||
data_core.warrants -= activewarrant
|
||||
activewarrant = null
|
||||
|
||||
if(href_list["editwarrantname"])
|
||||
. = 1
|
||||
var/namelist = list()
|
||||
for(var/datum/data/record/t in data_core.general)
|
||||
namelist += t.fields["name"]
|
||||
var/new_name = sanitize(input(usr, "Please input name") as null|anything in namelist)
|
||||
if(CanInteract(user, default_state))
|
||||
if (!new_name)
|
||||
return
|
||||
activewarrant.fields["namewarrant"] = new_name
|
||||
if("editwarrantname")
|
||||
. = TRUE
|
||||
var/namelist = list()
|
||||
for(var/datum/data/record/t in data_core.general)
|
||||
namelist += t.fields["name"]
|
||||
var/new_name = sanitize(input(usr, "Please input name") as null|anything in namelist)
|
||||
if(tgui_status(usr, state) == STATUS_INTERACTIVE)
|
||||
if (!new_name)
|
||||
return
|
||||
activewarrant.fields["namewarrant"] = new_name
|
||||
|
||||
if(href_list["editwarrantnamecustom"])
|
||||
. = 1
|
||||
var/new_name = sanitize(input("Please input name") as null|text)
|
||||
if(CanInteract(user, default_state))
|
||||
if (!new_name)
|
||||
return
|
||||
activewarrant.fields["namewarrant"] = new_name
|
||||
if("editwarrantnamecustom")
|
||||
. = TRUE
|
||||
var/new_name = sanitize(input("Please input name") as null|text)
|
||||
if(tgui_status(usr, state) == STATUS_INTERACTIVE)
|
||||
if (!new_name)
|
||||
return
|
||||
activewarrant.fields["namewarrant"] = new_name
|
||||
|
||||
if(href_list["editwarrantcharges"])
|
||||
. = 1
|
||||
var/new_charges = sanitize(input("Please input charges", "Charges", activewarrant.fields["charges"]) as null|text)
|
||||
if(CanInteract(user, default_state))
|
||||
if (!new_charges)
|
||||
return
|
||||
activewarrant.fields["charges"] = new_charges
|
||||
if("editwarrantcharges")
|
||||
. = TRUE
|
||||
var/new_charges = sanitize(input("Please input charges", "Charges", activewarrant.fields["charges"]) as null|text)
|
||||
if(tgui_status(usr, state) == STATUS_INTERACTIVE)
|
||||
if (!new_charges)
|
||||
return
|
||||
activewarrant.fields["charges"] = new_charges
|
||||
|
||||
if(href_list["editwarrantauth"])
|
||||
. = 1
|
||||
if(!(access_hos in I.access)) // VOREStation edit begin
|
||||
to_chat(user, "<span class='warning'>You don't have the access to do this!</span>")
|
||||
return // VOREStation edit end
|
||||
activewarrant.fields["auth"] = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]"
|
||||
|
||||
if(href_list["back"])
|
||||
. = 1
|
||||
activewarrant = null
|
||||
if("editwarrantauth")
|
||||
. = TRUE
|
||||
if(!(access_hos in I.access)) // VOREStation edit begin
|
||||
to_chat(usr, "<span class='warning'>You don't have the access to do this!</span>")
|
||||
return // VOREStation edit end
|
||||
activewarrant.fields["auth"] = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]"
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
icon = 'icons/obj/vending.dmi'
|
||||
icon_state = "robotics"
|
||||
layer = OBJ_LAYER - 0.1
|
||||
anchored = 1
|
||||
density = 1
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
|
||||
// The actual laptop/tablet
|
||||
var/obj/item/modular_computer/laptop/fabricated_laptop = null
|
||||
@@ -160,70 +160,77 @@
|
||||
return total_price
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/machinery/lapvend/Topic(href, href_list)
|
||||
/obj/machinery/lapvend/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(href_list["pick_device"])
|
||||
if(state) // We've already picked a device type
|
||||
return 0
|
||||
devtype = text2num(href_list["pick_device"])
|
||||
state = 1
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if(href_list["clean_order"])
|
||||
reset_order()
|
||||
return 1
|
||||
switch(action)
|
||||
if("pick_device")
|
||||
if(state) // We've already picked a device type
|
||||
return FALSE
|
||||
devtype = text2num(params["pick"])
|
||||
state = 1
|
||||
fabricate_and_recalc_price(FALSE)
|
||||
return TRUE
|
||||
if("clean_order")
|
||||
reset_order()
|
||||
return TRUE
|
||||
if((state != 1) && devtype) // Following IFs should only be usable when in the Select Loadout mode
|
||||
return 0
|
||||
if(href_list["confirm_order"])
|
||||
state = 2 // Wait for ID swipe for payment processing
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if(href_list["hw_cpu"])
|
||||
dev_cpu = text2num(href_list["hw_cpu"])
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if(href_list["hw_battery"])
|
||||
dev_battery = text2num(href_list["hw_battery"])
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if(href_list["hw_disk"])
|
||||
dev_disk = text2num(href_list["hw_disk"])
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if(href_list["hw_netcard"])
|
||||
dev_netcard = text2num(href_list["hw_netcard"])
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if(href_list["hw_tesla"])
|
||||
dev_tesla = text2num(href_list["hw_tesla"])
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if(href_list["hw_nanoprint"])
|
||||
dev_nanoprint = text2num(href_list["hw_nanoprint"])
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if(href_list["hw_card"])
|
||||
dev_card = text2num(href_list["hw_card"])
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
return 0
|
||||
return FALSE
|
||||
switch(action)
|
||||
if("confirm_order")
|
||||
state = 2 // Wait for ID swipe for payment processing
|
||||
fabricate_and_recalc_price(FALSE)
|
||||
return TRUE
|
||||
if("hw_cpu")
|
||||
dev_cpu = text2num(params["cpu"])
|
||||
fabricate_and_recalc_price(FALSE)
|
||||
return TRUE
|
||||
if("hw_battery")
|
||||
dev_battery = text2num(params["battery"])
|
||||
fabricate_and_recalc_price(FALSE)
|
||||
return TRUE
|
||||
if("hw_disk")
|
||||
dev_disk = text2num(params["disk"])
|
||||
fabricate_and_recalc_price(FALSE)
|
||||
return TRUE
|
||||
if("hw_netcard")
|
||||
dev_netcard = text2num(params["netcard"])
|
||||
fabricate_and_recalc_price(FALSE)
|
||||
return TRUE
|
||||
if("hw_tesla")
|
||||
dev_tesla = text2num(params["tesla"])
|
||||
fabricate_and_recalc_price(FALSE)
|
||||
return TRUE
|
||||
if("hw_nanoprint")
|
||||
dev_nanoprint = text2num(params["print"])
|
||||
fabricate_and_recalc_price(FALSE)
|
||||
return TRUE
|
||||
if("hw_card")
|
||||
dev_card = text2num(params["card"])
|
||||
fabricate_and_recalc_price(FALSE)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
|
||||
/obj/machinery/lapvend/attack_hand(var/mob/user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/lapvend/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
/obj/machinery/lapvend/tgui_interact(mob/user, datum/tgui/ui)
|
||||
if(stat & (BROKEN | NOPOWER | MAINT))
|
||||
if(ui)
|
||||
ui.close()
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "ComputerFabricator")
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/lapvend/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
var/list/data[0]
|
||||
data["state"] = state
|
||||
if(state == 1)
|
||||
data["devtype"] = devtype
|
||||
@@ -237,13 +244,7 @@
|
||||
if(state == 1 || state == 2)
|
||||
data["totalprice"] = total_price
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "computer_fabricator.tmpl", "Personal Computer Vendor", 500, 400)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
return data
|
||||
|
||||
obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
var/obj/item/weapon/card/id/I = W.GetID()
|
||||
@@ -272,7 +273,6 @@ obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
|
||||
// Simplified payment processing, returns 1 on success.
|
||||
/obj/machinery/lapvend/proc/process_payment(var/obj/item/weapon/card/id/I, var/obj/item/ID_container)
|
||||
if(I==ID_container || ID_container == null)
|
||||
@@ -305,4 +305,4 @@ obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
T.date = current_date_string
|
||||
T.time = stationtime2text()
|
||||
customer_account.transaction_log.Add(T)
|
||||
return 1
|
||||
return 1
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
/datum/nano_module
|
||||
var/name
|
||||
var/datum/host
|
||||
var/datum/topic_manager/topic_manager
|
||||
var/list/using_access
|
||||
|
||||
/datum/nano_module/New(var/datum/host, var/topic_manager)
|
||||
/datum/nano_module/New(var/datum/host)
|
||||
..()
|
||||
src.host = host.nano_host()
|
||||
src.topic_manager = topic_manager
|
||||
|
||||
/datum/nano_module/nano_host()
|
||||
return host ? host : src
|
||||
@@ -40,11 +38,6 @@
|
||||
|
||||
return 0
|
||||
|
||||
/datum/nano_module/Topic(href, href_list)
|
||||
if(topic_manager && topic_manager.Topic(href, href_list))
|
||||
return TRUE
|
||||
. = ..()
|
||||
|
||||
/datum/nano_module/proc/print_text(var/text, var/mob/user)
|
||||
var/obj/item/modular_computer/MC = nano_host()
|
||||
if(istype(MC))
|
||||
|
||||
@@ -123,4 +123,7 @@ Code is pretty much ripped verbatim from nano modules, but with un-needed stuff
|
||||
. += new /obj/screen/plane_master{plane = PLANE_CH_BACKUP} //Backup implant status
|
||||
. += new /obj/screen/plane_master{plane = PLANE_CH_VANTAG} //Vore Antags
|
||||
. += new /obj/screen/plane_master{plane = PLANE_AUGMENTED} //Augmented reality
|
||||
//VOREStation Add End
|
||||
//VOREStation Add End
|
||||
|
||||
/datum/tgui_module/proc/relaymove(mob/user, direction)
|
||||
return FALSE
|
||||
|
||||
486
code/modules/tgui/modules/communications.dm
Normal file
@@ -0,0 +1,486 @@
|
||||
#define COMM_SCREEN_MAIN 1
|
||||
#define COMM_SCREEN_STAT 2
|
||||
#define COMM_SCREEN_MESSAGES 3
|
||||
|
||||
#define COMM_AUTHENTICATION_NONE 0
|
||||
#define COMM_AUTHENTICATION_MIN 1
|
||||
#define COMM_AUTHENTICATION_MAX 2
|
||||
|
||||
#define COMM_MSGLEN_MINIMUM 6
|
||||
#define COMM_CCMSGLEN_MINIMUM 20
|
||||
|
||||
/datum/tgui_module/communications
|
||||
name = "Command & Communications"
|
||||
tgui_id = "CommunicationsConsole"
|
||||
|
||||
var/emagged = FALSE
|
||||
|
||||
var/current_viewing_message_id = 0
|
||||
var/current_viewing_message = null
|
||||
|
||||
var/authenticated = COMM_AUTHENTICATION_NONE
|
||||
var/menu_state = COMM_SCREEN_MAIN
|
||||
var/ai_menu_state = COMM_SCREEN_MAIN
|
||||
var/aicurrmsg
|
||||
|
||||
var/message_cooldown
|
||||
var/centcomm_message_cooldown
|
||||
var/tmp_alertlevel = 0
|
||||
|
||||
var/stat_msg1
|
||||
var/stat_msg2
|
||||
var/display_type = "blank"
|
||||
|
||||
var/datum/announcement/priority/crew_announcement
|
||||
|
||||
var/datum/lore/atc_controller/ATC
|
||||
|
||||
var/list/req_access = list()
|
||||
|
||||
/datum/tgui_module/communications/New(host)
|
||||
. = ..()
|
||||
ATC = atc
|
||||
crew_announcement = new()
|
||||
crew_announcement.newscast = TRUE
|
||||
|
||||
/datum/tgui_module/communications/tgui_interact(mob/user, datum/tgui/ui)
|
||||
if(using_map && !(get_z(user) in using_map.contact_levels))
|
||||
to_chat(user, "<span class='danger'>Unable to establish a connection: You're too far away from the station!</span>")
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/datum/tgui_module/communications/proc/is_authenticated(mob/user, message = TRUE)
|
||||
if(authenticated == COMM_AUTHENTICATION_MAX)
|
||||
return COMM_AUTHENTICATION_MAX
|
||||
else if(isobserver(user))
|
||||
var/mob/observer/dead/D = user
|
||||
if(D.can_admin_interact())
|
||||
return COMM_AUTHENTICATION_MAX
|
||||
else if(authenticated)
|
||||
return COMM_AUTHENTICATION_MIN
|
||||
else
|
||||
if(message)
|
||||
to_chat(user, "<span class='warning'>Access denied.</span>")
|
||||
return COMM_AUTHENTICATION_NONE
|
||||
|
||||
/datum/tgui_module/communications/proc/change_security_level(new_level)
|
||||
tmp_alertlevel = new_level
|
||||
var/old_level = security_level
|
||||
if(!tmp_alertlevel) tmp_alertlevel = SEC_LEVEL_GREEN
|
||||
if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN
|
||||
if(tmp_alertlevel > SEC_LEVEL_BLUE) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this
|
||||
set_security_level(tmp_alertlevel)
|
||||
if(security_level != old_level)
|
||||
//Only notify the admins if an actual change happened
|
||||
log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
|
||||
message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
|
||||
switch(security_level)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
feedback_inc("alert_comms_green",1)
|
||||
if(SEC_LEVEL_YELLOW)
|
||||
feedback_inc("alert_comms_yellow",1)
|
||||
if(SEC_LEVEL_VIOLET)
|
||||
feedback_inc("alert_comms_violet",1)
|
||||
if(SEC_LEVEL_ORANGE)
|
||||
feedback_inc("alert_comms_orange",1)
|
||||
if(SEC_LEVEL_BLUE)
|
||||
feedback_inc("alert_comms_blue",1)
|
||||
tmp_alertlevel = 0
|
||||
|
||||
/datum/tgui_module/communications/tgui_data(mob/user)
|
||||
var/list/data = ..()
|
||||
data["is_ai"] = isAI(user) || isrobot(user)
|
||||
data["menu_state"] = data["is_ai"] ? ai_menu_state : menu_state
|
||||
data["emagged"] = emagged
|
||||
data["authenticated"] = is_authenticated(user, 0)
|
||||
data["authmax"] = data["authenticated"] == COMM_AUTHENTICATION_MAX ? TRUE : FALSE
|
||||
data["atcsquelch"] = ATC.squelched
|
||||
data["boss_short"] = using_map.boss_short
|
||||
|
||||
data["stat_display"] = list(
|
||||
"type" = display_type,
|
||||
// "icon" = display_icon,
|
||||
"line_1" = (stat_msg1 ? stat_msg1 : "-----"),
|
||||
"line_2" = (stat_msg2 ? stat_msg2 : "-----"),
|
||||
|
||||
"presets" = list(
|
||||
list("name" = "blank", "label" = "Clear", "desc" = "Blank slate"),
|
||||
list("name" = "shuttle", "label" = "Shuttle ETA", "desc" = "Display how much time is left."),
|
||||
list("name" = "message", "label" = "Message", "desc" = "A custom message.")
|
||||
),
|
||||
)
|
||||
|
||||
data["security_level"] = security_level
|
||||
switch(security_level)
|
||||
if(SEC_LEVEL_BLUE)
|
||||
data["security_level_color"] = "blue";
|
||||
if(SEC_LEVEL_ORANGE)
|
||||
data["security_level_color"] = "orange";
|
||||
if(SEC_LEVEL_VIOLET)
|
||||
data["security_level_color"] = "violet";
|
||||
if(SEC_LEVEL_YELLOW)
|
||||
data["security_level_color"] = "yellow";
|
||||
if(SEC_LEVEL_GREEN)
|
||||
data["security_level_color"] = "green";
|
||||
if(SEC_LEVEL_RED)
|
||||
data["security_level_color"] = "red";
|
||||
else
|
||||
data["security_level_color"] = "purple";
|
||||
data["str_security_level"] = capitalize(get_security_level())
|
||||
data["levels"] = list(
|
||||
list("id" = SEC_LEVEL_GREEN, "name" = "Green", "icon" = "dove"),
|
||||
list("id" = SEC_LEVEL_YELLOW, "name" = "Yellow", "icon" = "exclamation-triangle"),
|
||||
list("id" = SEC_LEVEL_BLUE, "name" = "Blue", "icon" = "eye"),
|
||||
list("id" = SEC_LEVEL_ORANGE, "name" = "Orange", "icon" = "wrench"),
|
||||
list("id" = SEC_LEVEL_VIOLET, "name" = "Violet", "icon" = "biohazard"),
|
||||
)
|
||||
|
||||
var/datum/comm_message_listener/l = obtain_message_listener()
|
||||
data["messages"] = l.messages
|
||||
data["message_deletion_allowed"] = l != global_message_listener
|
||||
data["message_current_id"] = current_viewing_message_id
|
||||
data["message_current"] = current_viewing_message
|
||||
|
||||
// data["lastCallLoc"] = SSshuttle.emergencyLastCallLoc ? format_text(SSshuttle.emergencyLastCallLoc.name) : null
|
||||
data["msg_cooldown"] = message_cooldown ? (round((message_cooldown - world.time) / 10)) : 0
|
||||
data["cc_cooldown"] = centcomm_message_cooldown ? (round((centcomm_message_cooldown - world.time) / 10)) : 0
|
||||
|
||||
data["esc_callable"] = emergency_shuttle.location() && !emergency_shuttle.online() ? TRUE : FALSE
|
||||
data["esc_recallable"] = emergency_shuttle.location() && emergency_shuttle.online() ? TRUE : FALSE
|
||||
data["esc_status"] = FALSE
|
||||
if(emergency_shuttle.has_eta())
|
||||
var/timeleft = emergency_shuttle.estimate_arrival_time()
|
||||
data["esc_status"] = emergency_shuttle.online() ? "ETA:" : "RECALLING:"
|
||||
data["esc_status"] += " [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]"
|
||||
return data
|
||||
|
||||
/datum/tgui_module/communications/proc/setCurrentMessage(mob/user, value)
|
||||
current_viewing_message_id = value
|
||||
|
||||
var/datum/comm_message_listener/l = obtain_message_listener()
|
||||
for(var/list/m in l.messages)
|
||||
if(m["id"] == current_viewing_message_id)
|
||||
current_viewing_message = m
|
||||
|
||||
/datum/tgui_module/communications/proc/setMenuState(mob/user, value)
|
||||
if(isAI(user) || isrobot(user))
|
||||
ai_menu_state = value
|
||||
else
|
||||
menu_state = value
|
||||
|
||||
/datum/tgui_module/communications/proc/obtain_message_listener()
|
||||
if(istype(host, /datum/computer_file/program/comm))
|
||||
var/datum/computer_file/program/comm/P = host
|
||||
return P.message_core
|
||||
return global_message_listener
|
||||
|
||||
/proc/post_status(atom/source, command, data1, data2, mob/user = null)
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
|
||||
|
||||
if(!frequency)
|
||||
return
|
||||
|
||||
var/datum/signal/status_signal = new
|
||||
status_signal.source = source
|
||||
status_signal.transmission_method = TRANSMISSION_RADIO
|
||||
status_signal.data["command"] = command
|
||||
|
||||
switch(command)
|
||||
if("message")
|
||||
status_signal.data["msg1"] = data1
|
||||
status_signal.data["msg2"] = data2
|
||||
log_admin("STATUS: [user] set status screen message: [data1] [data2]")
|
||||
//message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]")
|
||||
if("alert")
|
||||
status_signal.data["picture_state"] = data1
|
||||
|
||||
frequency.post_signal(null, status_signal)
|
||||
|
||||
/datum/tgui_module/communications/tgui_act(action, params)
|
||||
if(..())
|
||||
return TRUE
|
||||
if(using_map && !(get_z(usr) in using_map.contact_levels))
|
||||
to_chat(usr, "<span class='danger'>Unable to establish a connection: You're too far away from the station!</span>")
|
||||
return FALSE
|
||||
|
||||
. = TRUE
|
||||
if(action == "auth")
|
||||
if(!ishuman(usr))
|
||||
to_chat(usr, "<span class='warning'>Access denied.</span>")
|
||||
return FALSE
|
||||
// Logout function.
|
||||
if(authenticated != COMM_AUTHENTICATION_NONE)
|
||||
authenticated = COMM_AUTHENTICATION_NONE
|
||||
crew_announcement.announcer = null
|
||||
setMenuState(usr, COMM_SCREEN_MAIN)
|
||||
return
|
||||
// Login function.
|
||||
if(check_access(usr, access_heads))
|
||||
authenticated = COMM_AUTHENTICATION_MIN
|
||||
if(check_access(usr, access_captain))
|
||||
authenticated = COMM_AUTHENTICATION_MAX
|
||||
var/mob/M = usr
|
||||
var/obj/item/weapon/card/id = M.GetIdCard()
|
||||
if(istype(id))
|
||||
crew_announcement.announcer = GetNameAndAssignmentFromId(id)
|
||||
if(authenticated == COMM_AUTHENTICATION_NONE)
|
||||
to_chat(usr, "<span class='warning'>You need to wear your ID.</span>")
|
||||
|
||||
// All functions below this point require authentication.
|
||||
if(!is_authenticated(usr))
|
||||
return FALSE
|
||||
|
||||
switch(action)
|
||||
// main interface
|
||||
if("main")
|
||||
setMenuState(usr, COMM_SCREEN_MAIN)
|
||||
|
||||
if("newalertlevel")
|
||||
if(isAI(usr) || isrobot(usr))
|
||||
to_chat(usr, "<span class='warning'>Firewalls prevent you from changing the alert level.</span>")
|
||||
return
|
||||
else if(isobserver(usr))
|
||||
var/mob/observer/dead/D = usr
|
||||
if(D.can_admin_interact())
|
||||
change_security_level(text2num(params["level"]))
|
||||
return TRUE
|
||||
else if(!ishuman(usr))
|
||||
to_chat(usr, "<span class='warning'>Security measures prevent you from changing the alert level.</span>")
|
||||
return
|
||||
|
||||
if(check_access(usr, access_captain))
|
||||
change_security_level(text2num(params["level"]))
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>You are not authorized to do this.</span>")
|
||||
setMenuState(usr, COMM_SCREEN_MAIN)
|
||||
|
||||
if("announce")
|
||||
if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)
|
||||
if(message_cooldown > world.time)
|
||||
to_chat(usr, "<span class='warning'>Please allow at least one minute to pass between announcements.</span>")
|
||||
return
|
||||
var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|message
|
||||
if(!input || message_cooldown > world.time || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
|
||||
return
|
||||
if(length(input) < COMM_MSGLEN_MINIMUM)
|
||||
to_chat(usr, "<span class='warning'>Message '[input]' is too short. [COMM_MSGLEN_MINIMUM] character minimum.</span>")
|
||||
return
|
||||
crew_announcement.Announce(input)
|
||||
message_cooldown = world.time + 600 //One minute
|
||||
|
||||
if("callshuttle")
|
||||
if(!is_authenticated(usr))
|
||||
return
|
||||
|
||||
call_shuttle_proc(usr)
|
||||
if(emergency_shuttle.online())
|
||||
post_status(src, "shuttle", user = usr)
|
||||
setMenuState(usr, COMM_SCREEN_MAIN)
|
||||
|
||||
if("cancelshuttle")
|
||||
if(isAI(usr) || isrobot(usr))
|
||||
to_chat(usr, "<span class='warning'>Firewalls prevent you from recalling the shuttle.</span>")
|
||||
return
|
||||
var/response = alert("Are you sure you wish to recall the shuttle?", "Confirm", "Yes", "No")
|
||||
if(response == "Yes")
|
||||
cancel_call_proc(usr)
|
||||
setMenuState(usr, COMM_SCREEN_MAIN)
|
||||
|
||||
if("messagelist")
|
||||
current_viewing_message = null
|
||||
current_viewing_message_id = null
|
||||
if(params["msgid"])
|
||||
setCurrentMessage(usr, text2num(params["msgid"]))
|
||||
setMenuState(usr, COMM_SCREEN_MESSAGES)
|
||||
|
||||
if("toggleatc")
|
||||
ATC.squelched = !ATC.squelched
|
||||
|
||||
if("delmessage")
|
||||
var/datum/comm_message_listener/l = obtain_message_listener()
|
||||
if(params["msgid"])
|
||||
setCurrentMessage(usr, text2num(params["msgid"]))
|
||||
var/response = alert("Are you sure you wish to delete this message?", "Confirm", "Yes", "No")
|
||||
if(response == "Yes")
|
||||
if(current_viewing_message)
|
||||
if(l != global_message_listener)
|
||||
l.Remove(current_viewing_message)
|
||||
current_viewing_message = null
|
||||
setMenuState(usr, COMM_SCREEN_MESSAGES)
|
||||
|
||||
if("status")
|
||||
setMenuState(usr, COMM_SCREEN_STAT)
|
||||
|
||||
// Status display stuff
|
||||
if("setstat")
|
||||
display_type = params["statdisp"]
|
||||
switch(display_type)
|
||||
if("message")
|
||||
post_status(src, "message", stat_msg1, stat_msg2, user = usr)
|
||||
if("alert")
|
||||
post_status(src, "alert", params["alert"], user = usr)
|
||||
else
|
||||
post_status(src, params["statdisp"], user = usr)
|
||||
|
||||
if("setmsg1")
|
||||
stat_msg1 = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", stat_msg1) as text|null, 40), 40)
|
||||
setMenuState(usr, COMM_SCREEN_STAT)
|
||||
|
||||
if("setmsg2")
|
||||
stat_msg2 = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", stat_msg2) as text|null, 40), 40)
|
||||
setMenuState(usr, COMM_SCREEN_STAT)
|
||||
|
||||
// OMG CENTCOMM LETTERHEAD
|
||||
if("MessageCentCom")
|
||||
if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)
|
||||
if(centcomm_message_cooldown > world.time)
|
||||
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
|
||||
return
|
||||
var/input = sanitize(input("Please choose a message to transmit to [using_map.boss_short] via quantum entanglement. \
|
||||
Please be aware that this process is very expensive, and abuse will lead to... termination. \
|
||||
Transmission does not guarantee a response. \
|
||||
There is a 30 second delay before you may send another message, be clear, full and concise.", "Central Command Quantum Messaging") as null|message)
|
||||
if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
|
||||
return
|
||||
if(length(input) < COMM_CCMSGLEN_MINIMUM)
|
||||
to_chat(usr, "<span class='warning'>Message '[input]' is too short. [COMM_CCMSGLEN_MINIMUM] character minimum.</span>")
|
||||
return
|
||||
CentCom_announce(input, usr)
|
||||
to_chat(usr, "<font color='blue'>Message transmitted.</font>")
|
||||
log_game("[key_name(usr)] has made an IA [using_map.boss_short] announcement: [input]")
|
||||
centcomm_message_cooldown = world.time + 300 // 30 seconds
|
||||
setMenuState(usr, COMM_SCREEN_MAIN)
|
||||
|
||||
// OMG SYNDICATE ...LETTERHEAD
|
||||
if("MessageSyndicate")
|
||||
if((is_authenticated(usr) == COMM_AUTHENTICATION_MAX) && (emagged))
|
||||
if(centcomm_message_cooldown > world.time)
|
||||
to_chat(usr, "Arrays recycling. Please stand by.")
|
||||
return
|
||||
var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", ""))
|
||||
if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
|
||||
return
|
||||
if(length(input) < COMM_CCMSGLEN_MINIMUM)
|
||||
to_chat(usr, "<span class='warning'>Message '[input]' is too short. [COMM_CCMSGLEN_MINIMUM] character minimum.</span>")
|
||||
return
|
||||
Syndicate_announce(input, usr)
|
||||
to_chat(usr, "<font color='blue'>Message transmitted.</font>")
|
||||
log_game("[key_name(usr)] has made an illegal announcement: [input]")
|
||||
centcomm_message_cooldown = world.time + 300 // 30 seconds
|
||||
|
||||
if("RestoreBackup")
|
||||
to_chat(usr, "Backup routing data restored!")
|
||||
emagged = FALSE
|
||||
setMenuState(usr, COMM_SCREEN_MAIN)
|
||||
|
||||
/datum/tgui_module/communications/ntos
|
||||
ntos = TRUE
|
||||
|
||||
/* Etc global procs */
|
||||
/proc/enable_prison_shuttle(var/mob/user)
|
||||
for(var/obj/machinery/computer/prison_shuttle/PS in machines)
|
||||
PS.allowedtocall = !(PS.allowedtocall)
|
||||
|
||||
/proc/call_shuttle_proc(var/mob/user)
|
||||
if ((!( ticker ) || !emergency_shuttle.location()))
|
||||
return
|
||||
|
||||
if(!universe.OnShuttleCall(usr))
|
||||
to_chat(user, "<span class='notice'>Cannot establish a bluespace connection.</span>")
|
||||
return
|
||||
|
||||
if(deathsquad.deployed)
|
||||
to_chat(user, "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated.")
|
||||
return
|
||||
|
||||
if(emergency_shuttle.deny_shuttle)
|
||||
to_chat(user, "The emergency shuttle may not be sent at this time. Please try again later.")
|
||||
return
|
||||
|
||||
if(world.time < 6000) // Ten minute grace period to let the game get going without lolmetagaming. -- TLE
|
||||
to_chat(user, "The emergency shuttle is refueling. Please wait another [round((6000-world.time)/600)] minute\s before trying again.")
|
||||
return
|
||||
|
||||
if(emergency_shuttle.going_to_centcom())
|
||||
to_chat(user, "The emergency shuttle may not be called while returning to [using_map.boss_short].")
|
||||
return
|
||||
|
||||
if(emergency_shuttle.online())
|
||||
to_chat(user, "The emergency shuttle is already on its way.")
|
||||
return
|
||||
|
||||
if(ticker.mode.name == "blob")
|
||||
to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.")
|
||||
return
|
||||
|
||||
emergency_shuttle.call_evac()
|
||||
log_game("[key_name(user)] has called the shuttle.")
|
||||
message_admins("[key_name_admin(user)] has called the shuttle.", 1)
|
||||
admin_chat_message(message = "Emergency evac beginning! Called by [key_name(user)]!", color = "#CC2222") //VOREStation Add
|
||||
|
||||
return
|
||||
|
||||
/proc/init_shift_change(var/mob/user, var/force = 0)
|
||||
if ((!( ticker ) || !emergency_shuttle.location()))
|
||||
return
|
||||
|
||||
if(emergency_shuttle.going_to_centcom())
|
||||
to_chat(user, "The shuttle may not be called while returning to [using_map.boss_short].")
|
||||
return
|
||||
|
||||
if(emergency_shuttle.online())
|
||||
to_chat(user, "The shuttle is already on its way.")
|
||||
return
|
||||
|
||||
// if force is 0, some things may stop the shuttle call
|
||||
if(!force)
|
||||
if(emergency_shuttle.deny_shuttle)
|
||||
to_chat(user, "[using_map.boss_short] does not currently have a shuttle available in your sector. Please try again later.")
|
||||
return
|
||||
|
||||
if(deathsquad.deployed == 1)
|
||||
to_chat(user, "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated.")
|
||||
return
|
||||
|
||||
if(world.time < 54000) // 30 minute grace period to let the game get going
|
||||
to_chat(user, "The shuttle is refueling. Please wait another [round((54000-world.time)/60)] minutes before trying again.")
|
||||
return
|
||||
|
||||
if(ticker.mode.auto_recall_shuttle)
|
||||
//New version pretends to call the shuttle but cause the shuttle to return after a random duration.
|
||||
emergency_shuttle.auto_recall = 1
|
||||
|
||||
if(ticker.mode.name == "blob" || ticker.mode.name == "epidemic")
|
||||
to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.")
|
||||
return
|
||||
|
||||
emergency_shuttle.call_transfer()
|
||||
|
||||
//delay events in case of an autotransfer
|
||||
if (isnull(user))
|
||||
SSevents.delay_events(EVENT_LEVEL_MODERATE, 9000) //15 minutes
|
||||
SSevents.delay_events(EVENT_LEVEL_MAJOR, 9000)
|
||||
|
||||
log_game("[user? key_name(user) : "Autotransfer"] has called the shuttle.")
|
||||
message_admins("[user? key_name_admin(user) : "Autotransfer"] has called the shuttle.", 1)
|
||||
admin_chat_message(message = "Autotransfer shuttle dispatched, shift ending soon.", color = "#2277BB") //VOREStation Add
|
||||
|
||||
return
|
||||
|
||||
/proc/cancel_call_proc(var/mob/user)
|
||||
if (!( ticker ) || !emergency_shuttle.can_recall())
|
||||
return
|
||||
if((ticker.mode.name == "blob")||(ticker.mode.name == "Meteor"))
|
||||
return
|
||||
|
||||
if(!emergency_shuttle.going_to_centcom()) //check that shuttle isn't already heading to CentCom
|
||||
emergency_shuttle.recall()
|
||||
log_game("[key_name(user)] has recalled the shuttle.")
|
||||
message_admins("[key_name_admin(user)] has recalled the shuttle.", 1)
|
||||
return
|
||||
|
||||
/proc/is_relay_online()
|
||||
for(var/obj/machinery/telecomms/relay/M in world)
|
||||
if(M.stat == 0)
|
||||
return 1
|
||||
return 0
|
||||
235
code/modules/tgui/modules/ntos-only/cardmod.dm
Normal file
@@ -0,0 +1,235 @@
|
||||
// This really should be used for both regular ID computers and NTOS, but
|
||||
// the data structures are just different enough right now that I can't be assed
|
||||
/datum/tgui_module/cardmod
|
||||
name = "ID card modification program"
|
||||
ntos = TRUE
|
||||
tgui_id = "IdentificationComputer"
|
||||
var/mod_mode = 1
|
||||
var/is_centcom = 0
|
||||
|
||||
/datum/tgui_module/cardmod/tgui_static_data(mob/user)
|
||||
var/list/data = ..()
|
||||
if(data_core)
|
||||
data_core.get_manifest_list()
|
||||
data["manifest"] = PDA_Manifest
|
||||
return data
|
||||
|
||||
/datum/tgui_module/cardmod/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/datum/computer_file/program/card_mod/program = host
|
||||
if(!istype(program))
|
||||
return 0
|
||||
var/list/data = ..()
|
||||
data["station_name"] = station_name()
|
||||
data["mode"] = mod_mode
|
||||
data["printing"] = FALSE
|
||||
if(program && program.computer)
|
||||
data["have_id_slot"] = !!program.computer.card_slot
|
||||
data["have_printer"] = !!program.computer.nano_printer
|
||||
data["authenticated"] = program.can_run(user)
|
||||
if(!program.computer.card_slot)
|
||||
mod_mode = 0 //We can't modify IDs when there is no card reader
|
||||
else
|
||||
data["have_id_slot"] = 0
|
||||
data["have_printer"] = 0
|
||||
data["authenticated"] = 0
|
||||
data["centcom_access"] = is_centcom
|
||||
|
||||
|
||||
data["has_modify"] = null
|
||||
data["account_number"] = null
|
||||
data["id_rank"] = null
|
||||
data["target_owner"] = null
|
||||
data["target_name"] = null
|
||||
if(program && program.computer && program.computer.card_slot)
|
||||
var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card
|
||||
data["has_modify"] = !!id_card
|
||||
data["account_number"] = id_card ? id_card.associated_account_number : null
|
||||
data["id_rank"] = id_card && id_card.assignment ? id_card.assignment : "Unassigned"
|
||||
data["target_owner"] = id_card && id_card.registered_name ? id_card.registered_name : "-----"
|
||||
data["target_name"] = id_card ? id_card.name : "-----"
|
||||
|
||||
var/list/departments = list()
|
||||
for(var/D in SSjob.get_all_department_datums())
|
||||
var/datum/department/dept = D
|
||||
if(!dept.assignable) // No AI ID cards for you.
|
||||
continue
|
||||
if(dept.centcom_only && !is_centcom)
|
||||
continue
|
||||
departments.Add(list(list(
|
||||
"department_name" = dept.name,
|
||||
"jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name)),
|
||||
)))
|
||||
|
||||
data["departments"] = departments
|
||||
|
||||
var/list/all_centcom_access = list()
|
||||
var/list/regions = list()
|
||||
if(program.computer.card_slot && program.computer.card_slot.stored_card)
|
||||
var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card
|
||||
if(is_centcom)
|
||||
for(var/access in get_all_centcom_access())
|
||||
all_centcom_access.Add(list(list(
|
||||
"desc" = replacetext(get_centcom_access_desc(access), " ", " "),
|
||||
"ref" = access,
|
||||
"allowed" = (access in id_card.access) ? 1 : 0)))
|
||||
data["all_centcom_access"] = all_centcom_access
|
||||
else
|
||||
for(var/i in ACCESS_REGION_SECURITY to ACCESS_REGION_SUPPLY)
|
||||
var/list/accesses = list()
|
||||
for(var/access in get_region_accesses(i))
|
||||
if(get_access_desc(access))
|
||||
accesses.Add(list(list(
|
||||
"desc" = replacetext(get_access_desc(access), " ", " "),
|
||||
"ref" = access,
|
||||
"allowed" = (access in id_card.access) ? 1 : 0)))
|
||||
|
||||
regions.Add(list(list(
|
||||
"name" = get_region_accesses_name(i),
|
||||
"accesses" = accesses)))
|
||||
data["regions"] = regions
|
||||
|
||||
data["regions"] = regions
|
||||
data["all_centcom_access"] = all_centcom_access
|
||||
|
||||
return data
|
||||
|
||||
/datum/tgui_module/cardmod/proc/format_jobs(list/jobs)
|
||||
var/datum/computer_file/program/card_mod/program = host
|
||||
if(!istype(program))
|
||||
return null
|
||||
|
||||
var/obj/item/weapon/card/id/id_card = program.computer.card_slot ? program.computer.card_slot.stored_card : null
|
||||
var/list/formatted = list()
|
||||
for(var/job in jobs)
|
||||
formatted.Add(list(list(
|
||||
"display_name" = replacetext(job, " ", " "),
|
||||
"target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned",
|
||||
"job" = job)))
|
||||
|
||||
return formatted
|
||||
|
||||
/datum/tgui_module/cardmod/tgui_act(action, list/params, datum/tgui/ui)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
|
||||
var/datum/computer_file/program/card_mod/program = host
|
||||
if(!istype(program))
|
||||
return TRUE
|
||||
var/obj/item/modular_computer/computer = tgui_host()
|
||||
if(!istype(computer))
|
||||
return TRUE
|
||||
|
||||
var/obj/item/weapon/card/id/user_id_card = usr.GetIdCard()
|
||||
var/obj/item/weapon/card/id/id_card
|
||||
if(computer.card_slot)
|
||||
id_card = computer.card_slot.stored_card
|
||||
|
||||
switch(action)
|
||||
if("mode")
|
||||
mod_mode = clamp(text2num(params["mode_target"]), 0, 1)
|
||||
. = TRUE
|
||||
if("print")
|
||||
if(computer && computer.nano_printer) //This option should never be called if there is no printer
|
||||
if(!mod_mode)
|
||||
if(program.can_run(usr, 1))
|
||||
var/contents = {"<h4>Access Report</h4>
|
||||
<u>Prepared By:</u> [user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]<br>
|
||||
<u>For:</u> [id_card.registered_name ? id_card.registered_name : "Unregistered"]<br>
|
||||
<hr>
|
||||
<u>Assignment:</u> [id_card.assignment]<br>
|
||||
<u>Account Number:</u> #[id_card.associated_account_number]<br>
|
||||
<u>Blood Type:</u> [id_card.blood_type]<br><br>
|
||||
<u>Access:</u><br>
|
||||
"}
|
||||
|
||||
var/known_access_rights = get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM)
|
||||
for(var/A in id_card.access)
|
||||
if(A in known_access_rights)
|
||||
contents += " [get_access_desc(A)]"
|
||||
|
||||
if(!computer.nano_printer.print_text(contents,"access report"))
|
||||
to_chat(usr, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
|
||||
return
|
||||
else
|
||||
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
|
||||
else
|
||||
var/contents = {"<h4>Crew Manifest</h4>
|
||||
<br>
|
||||
[data_core ? data_core.get_manifest(0) : ""]
|
||||
"}
|
||||
if(!computer.nano_printer.print_text(contents,text("crew manifest ([])", stationtime2text())))
|
||||
to_chat(usr, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
|
||||
return
|
||||
else
|
||||
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
|
||||
. = TRUE
|
||||
if("modify")
|
||||
if(computer && computer.card_slot)
|
||||
if(id_card)
|
||||
data_core.manifest_modify(id_card.registered_name, id_card.assignment)
|
||||
computer.proc_eject_id(usr)
|
||||
. = TRUE
|
||||
if("terminate")
|
||||
if(computer && program.can_run(usr, 1))
|
||||
id_card.assignment = "Dismissed" //VOREStation Edit: setting adjustment
|
||||
id_card.access = list()
|
||||
callHook("terminate_employee", list(id_card))
|
||||
. = TRUE
|
||||
if("reg")
|
||||
if(computer && program.can_run(usr, 1))
|
||||
var/temp_name = sanitizeName(params["reg"], allow_numbers = TRUE)
|
||||
if(temp_name)
|
||||
id_card.registered_name = temp_name
|
||||
else
|
||||
computer.visible_message("<span class='notice'>[computer] buzzes rudely.</span>")
|
||||
. = TRUE
|
||||
if("account")
|
||||
if(computer && program.can_run(usr, 1))
|
||||
var/account_num = text2num(params["account"])
|
||||
id_card.associated_account_number = account_num
|
||||
. = TRUE
|
||||
if("assign")
|
||||
if(computer && program.can_run(usr, 1) && id_card)
|
||||
var/t1 = params["assign_target"]
|
||||
if(t1 == "Custom")
|
||||
var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment", id_card.assignment), 45)
|
||||
//let custom jobs function as an impromptu alt title, mainly for sechuds
|
||||
if(temp_t)
|
||||
id_card.assignment = temp_t
|
||||
else
|
||||
var/list/access = list()
|
||||
if(is_centcom)
|
||||
access = get_centcom_access(t1)
|
||||
else
|
||||
var/datum/job/jobdatum
|
||||
for(var/jobtype in typesof(/datum/job))
|
||||
var/datum/job/J = new jobtype
|
||||
if(ckey(J.title) == ckey(t1))
|
||||
jobdatum = J
|
||||
break
|
||||
if(!jobdatum)
|
||||
to_chat(usr, "<span class='warning'>No log exists for this job: [t1]</span>")
|
||||
return
|
||||
|
||||
access = jobdatum.get_access()
|
||||
|
||||
id_card.access = access
|
||||
id_card.assignment = t1
|
||||
id_card.rank = t1
|
||||
|
||||
callHook("reassign_employee", list(id_card))
|
||||
. = TRUE
|
||||
if("access")
|
||||
if(computer && program.can_run(usr, 1))
|
||||
var/access_type = text2num(params["access_target"])
|
||||
var/access_allowed = text2num(params["allowed"])
|
||||
if(access_type in get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM))
|
||||
id_card.access -= access_type
|
||||
if(!access_allowed)
|
||||
id_card.access += access_type
|
||||
. = TRUE
|
||||
|
||||
if(id_card)
|
||||
id_card.name = text("[id_card.registered_name]'s ID Card ([id_card.assignment])")
|
||||
|
||||
48
code/modules/tgui/modules/ntos-only/configurator.dm
Normal file
@@ -0,0 +1,48 @@
|
||||
/datum/tgui_module/computer_configurator
|
||||
name = "NTOS Computer Configuration Tool"
|
||||
ntos = TRUE
|
||||
tgui_id = "Configuration"
|
||||
var/obj/item/modular_computer/movable = null
|
||||
|
||||
/datum/tgui_module/computer_configurator/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
movable = tgui_host()
|
||||
// No computer connection, we can't get data from that.
|
||||
if(!istype(movable))
|
||||
return 0
|
||||
|
||||
var/list/data = ..()
|
||||
|
||||
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())
|
||||
|
||||
if(movable.battery_module && movable.battery_module.battery)
|
||||
data["battery"] = list("max" = movable.battery_module.battery.maxcharge, "charge" = round(movable.battery_module.battery.charge))
|
||||
|
||||
var/list/hardware = movable.get_all_components()
|
||||
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
|
||||
return data
|
||||
|
||||
/datum/tgui_module/computer_configurator/tgui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("PC_toggle_component")
|
||||
var/obj/item/weapon/computer_hardware/H = movable.find_hardware_by_name(params["name"])
|
||||
if(H && istype(H))
|
||||
H.enabled = !H.enabled
|
||||
. = TRUE
|
||||
476
code/modules/tgui/modules/ntos-only/email.dm
Normal file
@@ -0,0 +1,476 @@
|
||||
/datum/tgui_module/email_client
|
||||
name = "Email Client"
|
||||
tgui_id = "NtosEmailClient"
|
||||
|
||||
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/tgui_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/tgui_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/tgui_module/email_client/proc/log_out()
|
||||
current_account = null
|
||||
downloading = null
|
||||
download_progress = 0
|
||||
last_message_count = 0
|
||||
read_message_count = 0
|
||||
|
||||
/datum/tgui_module/email_client/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/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."
|
||||
|
||||
// So, TGUI has a bug/feature where it just conveniently doesn't bother to clear out old data if it only gets
|
||||
// a partial data update; as such, we have to make sure to null all of these out ourselves so the UI works properly.
|
||||
data["accounts"] = null
|
||||
data["addressbook"] = null
|
||||
data["cur_attachment_filename"] = null
|
||||
data["cur_attachment_size"] = null
|
||||
data["cur_body"] = null
|
||||
data["cur_hasattachment"] = null
|
||||
data["cur_source"] = null
|
||||
data["cur_timestamp"] = null
|
||||
data["cur_title"] = null
|
||||
data["cur_uid"] = null
|
||||
data["current_account"] = null
|
||||
data["down_filename"] = null
|
||||
data["down_progress"] = null
|
||||
data["down_size"] = null
|
||||
data["down_speed"] = null
|
||||
data["downloading"] = null
|
||||
data["error"] = null
|
||||
data["folder"] = null
|
||||
data["label_deleted"] = null
|
||||
data["label_inbox"] = null
|
||||
data["label_spam"] = null
|
||||
data["messagecount"] = null
|
||||
data["messages"] = null
|
||||
data["msg_attachment_filename"] = null
|
||||
data["msg_attachment_size"] = null
|
||||
data["msg_body"] = null
|
||||
data["msg_hasattachment"] = null
|
||||
data["msg_recipient"] = null
|
||||
data["msg_title"] = null
|
||||
data["new_message"] = null
|
||||
data["stored_login"] = null
|
||||
data["stored_password"] = null
|
||||
|
||||
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)
|
||||
|
||||
return data
|
||||
|
||||
/datum/tgui_module/email_client/proc/find_message_by_fuid(var/fuid)
|
||||
if(!istype(current_account))
|
||||
return
|
||||
|
||||
// params 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/tgui_module/email_client/proc/clear_message()
|
||||
new_message = FALSE
|
||||
msg_title = ""
|
||||
msg_body = ""
|
||||
msg_recipient = ""
|
||||
msg_attachment = null
|
||||
current_message = null
|
||||
|
||||
/datum/tgui_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 = tgui_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/tgui_module/email_client/tgui_act(action, params)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
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.
|
||||
|
||||
switch(action)
|
||||
if("login")
|
||||
log_in()
|
||||
return 1
|
||||
|
||||
if("logout")
|
||||
log_out()
|
||||
return 1
|
||||
|
||||
if("reset")
|
||||
error = ""
|
||||
return 1
|
||||
|
||||
if("new_message")
|
||||
new_message = TRUE
|
||||
return 1
|
||||
|
||||
if("cancel")
|
||||
if(addressbook)
|
||||
addressbook = FALSE
|
||||
else
|
||||
clear_message()
|
||||
return 1
|
||||
|
||||
if("addressbook")
|
||||
addressbook = TRUE
|
||||
return 1
|
||||
|
||||
if("set_recipient")
|
||||
msg_recipient = sanitize(params["set_recipient"])
|
||||
addressbook = FALSE
|
||||
return 1
|
||||
|
||||
if("edit_title")
|
||||
var/newtitle = sanitize(params["val"], 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("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("edit_recipient")
|
||||
var/newrecipient = sanitize(params["val"], 100)
|
||||
if(newrecipient)
|
||||
msg_recipient = newrecipient
|
||||
return 1
|
||||
|
||||
if("edit_login")
|
||||
var/newlogin = sanitize(params["val"], 100)
|
||||
if(newlogin)
|
||||
stored_login = newlogin
|
||||
return 1
|
||||
|
||||
if("edit_password")
|
||||
var/newpass = sanitize(params["val"], 100)
|
||||
if(newpass)
|
||||
stored_password = newpass
|
||||
return 1
|
||||
|
||||
if("delete")
|
||||
if(!istype(current_account))
|
||||
return 1
|
||||
var/datum/computer_file/data/email_message/M = find_message_by_fuid(params["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("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("set_folder")
|
||||
folder = params["set_folder"]
|
||||
return 1
|
||||
|
||||
if("reply")
|
||||
var/datum/computer_file/data/email_message/M = find_message_by_fuid(params["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("view")
|
||||
var/datum/computer_file/data/email_message/M = find_message_by_fuid(params["view"])
|
||||
if(istype(M))
|
||||
current_message = M
|
||||
return 1
|
||||
|
||||
if("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("save")
|
||||
// Fully dependant on modular computers here.
|
||||
var/obj/item/modular_computer/MC = tgui_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(params["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("addattachment")
|
||||
var/obj/item/modular_computer/MC = tgui_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("downloadattachment")
|
||||
if(!current_account || !current_message || !current_message.attachment)
|
||||
return 1
|
||||
var/obj/item/modular_computer/MC = tgui_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("canceldownload")
|
||||
downloading = null
|
||||
download_progress = 0
|
||||
return 1
|
||||
|
||||
if("remove_attachment")
|
||||
msg_attachment = null
|
||||
return 1
|
||||
241
code/modules/tgui/modules/ntos-only/uav.dm
Normal file
@@ -0,0 +1,241 @@
|
||||
/datum/tgui_module/uav
|
||||
name = "UAV Control"
|
||||
tgui_id = "UAV"
|
||||
ntos = TRUE
|
||||
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/tgui_module/uav/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/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 = tgui_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.Add(list(list("name" = "[U ? U.nickname : "!!Missing!!"]", "uavref" = "\ref[U]")))
|
||||
|
||||
data["paired_uavs"] = paired_map
|
||||
return data
|
||||
|
||||
/datum/tgui_module/uav/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
switch(action)
|
||||
if("switch_uav")
|
||||
var/obj/item/device/uav/U = locate(params["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 FALSE
|
||||
|
||||
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 FALSE
|
||||
|
||||
set_current(U)
|
||||
return TRUE
|
||||
|
||||
if("del_uav")
|
||||
var/refstring = params["del_uav"] //This is a \ref to the UAV itself
|
||||
var/obj/item/modular_computer/mc_host = tgui_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)
|
||||
return TRUE
|
||||
|
||||
if("view_uav")
|
||||
if(!current_uav)
|
||||
return FALSE
|
||||
|
||||
if(current_uav.check_eye(usr) < 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(usr) ? unlook(usr) : look(usr)
|
||||
return TRUE
|
||||
|
||||
if("power_uav")
|
||||
if(!current_uav)
|
||||
return FALSE
|
||||
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 TRUE
|
||||
|
||||
/datum/tgui_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/tgui_module/uav/proc/get_signal_to(atom/movable/AM)
|
||||
// Following roughly the ntnet signal levels
|
||||
// 0 is none
|
||||
// 1 is weak
|
||||
// 2 is strong
|
||||
var/obj/item/modular_computer/host = tgui_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)
|
||||
|
||||
/* All handling viewers */
|
||||
/datum/tgui_module/uav/Destroy()
|
||||
if(LAZYLEN(viewers))
|
||||
for(var/weakref/W in viewers)
|
||||
var/M = W.resolve()
|
||||
if(M)
|
||||
unlook(M)
|
||||
. = ..()
|
||||
|
||||
/datum/tgui_module/uav/tgui_status(mob/user)
|
||||
. = ..()
|
||||
if(. > STATUS_DISABLED)
|
||||
if(viewing_uav(user))
|
||||
look(user)
|
||||
return
|
||||
unlook(user)
|
||||
|
||||
/datum/tgui_module/uav/tgui_close(mob/user)
|
||||
. = ..()
|
||||
unlook(user)
|
||||
|
||||
/datum/tgui_module/uav/proc/viewing_uav(mob/user)
|
||||
return (weakref(user) in viewers)
|
||||
|
||||
/datum/tgui_module/uav/proc/look(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
|
||||
|
||||
if(user.machine != tgui_host())
|
||||
user.set_machine(tgui_host())
|
||||
user.reset_view(current_uav)
|
||||
current_uav.add_master(user)
|
||||
LAZYDISTINCTADD(viewers, weakref(user))
|
||||
|
||||
/datum/tgui_module/uav/proc/unlook(mob/user)
|
||||
user.unset_machine()
|
||||
user.reset_view()
|
||||
if(current_uav)
|
||||
current_uav.remove_master(user)
|
||||
LAZYREMOVE(viewers, weakref(user))
|
||||
|
||||
/datum/tgui_module/uav/check_eye(mob/user)
|
||||
if(get_dist(user, tgui_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/tgui_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/tgui_module/uav/apply_visual(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/tgui_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)
|
||||
BIN
icons/UI_Icons/Achievements/Boss/bbgum.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
icons/UI_Icons/Achievements/Boss/colossus.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
icons/UI_Icons/Achievements/Boss/drake.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
icons/UI_Icons/Achievements/Boss/hierophant.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Boss/legion.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
icons/UI_Icons/Achievements/Boss/miner.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
icons/UI_Icons/Achievements/Boss/swarmer.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
icons/UI_Icons/Achievements/Boss/tendril.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/assistant.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/changeling.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/chaplain.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/clown.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/detective.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/fugitive.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/hated.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/hop.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/lawyer.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/md.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/nightmare.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/obsessed.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/psychologist.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/thoughtfeeder.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/traitor.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Misc/ascension.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
icons/UI_Icons/Achievements/Misc/clownking.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
icons/UI_Icons/Achievements/Misc/clownthanks.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
icons/UI_Icons/Achievements/Misc/featofstrength.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
icons/UI_Icons/Achievements/Misc/helbital.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
icons/UI_Icons/Achievements/Misc/jackpot.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
icons/UI_Icons/Achievements/Misc/longshift.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
icons/UI_Icons/Achievements/Misc/meteors.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
icons/UI_Icons/Achievements/Misc/rule8.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
icons/UI_Icons/Achievements/Misc/snail.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
icons/UI_Icons/Achievements/Misc/timewaste.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
icons/UI_Icons/Achievements/Misc/upgrade.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
icons/UI_Icons/Achievements/Skills/mining.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
icons/UI_Icons/Achievements/baseboss.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
icons/UI_Icons/Achievements/basemafia.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
icons/UI_Icons/Achievements/basemisc.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
icons/UI_Icons/Achievements/baseskill.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
icons/UI_Icons/Achievements/default.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
icons/UI_Icons/Arcade/boss1.gif
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
icons/UI_Icons/Arcade/boss2.gif
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
icons/UI_Icons/Arcade/boss3.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
icons/UI_Icons/Arcade/boss4.gif
Normal file
|
After Width: | Height: | Size: 922 B |
BIN
icons/UI_Icons/Arcade/boss5.gif
Normal file
|
After Width: | Height: | Size: 568 B |
BIN
icons/UI_Icons/Arcade/boss6.gif
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
icons/UI_Icons/chat/chat_icons.dmi
Normal file
|
After Width: | Height: | Size: 337 B |
BIN
icons/UI_Icons/tgui/ntosradar_background.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
icons/UI_Icons/tgui/ntosradar_pointer.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
icons/UI_Icons/tgui/ntosradar_pointer_S.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 107 B After Width: | Height: | Size: 107 B |
|
Before Width: | Height: | Size: 163 B After Width: | Height: | Size: 163 B |
|
Before Width: | Height: | Size: 173 B After Width: | Height: | Size: 173 B |
|
Before Width: | Height: | Size: 284 B After Width: | Height: | Size: 284 B |
|
Before Width: | Height: | Size: 185 B After Width: | Height: | Size: 185 B |