Revert "PLASE"

This reverts commit 8af225e6e3.
This commit is contained in:
Fermi
2019-11-24 03:06:08 +00:00
parent aeb8606ce0
commit ba4fa1ef67
2145 changed files with 1387321 additions and 5257 deletions
@@ -0,0 +1,197 @@
// /program/ files are executable programs that do things.
/datum/computer_file/program
filetype = "PRG"
filename = "UnknownProgram" // File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NTNET!
var/required_access = null // List of required accesses to *run* the program.
var/transfer_access = null // List of required access to download or file host the program
var/program_state = PROGRAM_STATE_KILLED// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running.
var/obj/item/modular_computer/computer // Device that runs this program.
var/filedesc = "Unknown Program" // User-friendly name of this program.
var/extended_desc = "N/A" // Short description of this program's function.
var/program_icon_state = null // Program-specific screen icon state
var/requires_ntnet = 0 // Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes.
var/requires_ntnet_feature = 0 // Optional, if above is set to 1 checks for specific function of NTNet (currently NTNET_SOFTWAREDOWNLOAD, NTNET_PEERTOPEER, NTNET_SYSTEMCONTROL and NTNET_COMMUNICATION)
var/ntnet_status = 1 // NTNet status, updated every tick by computer running this program. Don't use this for checks if NTNet works, computers do that. Use this for calculations, etc.
var/usage_flags = PROGRAM_ALL // Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL
var/network_destination = null // Optional string that describes what NTNet server/system this program connects to. Used in default logging.
var/available_on_ntnet = 1 // Whether the program can be downloaded from NTNet. Set to 0 to disable.
var/available_on_syndinet = 0 // Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable.
var/tgui_id // ID of TG UI interface
var/ui_style // ID of custom TG UI style (optional)
var/ui_x = 575 // Default size of TG UI window, in pixels
var/ui_y = 700
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 /icons/program_icons. Be careful not to use too large images!
/datum/computer_file/program/New(obj/item/modular_computer/comp = null)
..()
if(comp && istype(comp))
computer = comp
/datum/computer_file/program/Destroy()
computer = null
. = ..()
/datum/computer_file/program/clone()
var/datum/computer_file/program/temp = ..()
temp.required_access = required_access
temp.filedesc = filedesc
temp.program_icon_state = program_icon_state
temp.requires_ntnet = requires_ntnet
temp.requires_ntnet_feature = requires_ntnet_feature
temp.usage_flags = usage_flags
return temp
// Relays icon update to the computer.
/datum/computer_file/program/proc/update_computer_icon()
if(computer)
computer.update_icon()
// Attempts to create a log in global ntnet datum. Returns 1 on success, 0 on fail.
/datum/computer_file/program/proc/generate_network_log(text)
if(computer)
return computer.add_log(text)
return 0
/datum/computer_file/program/proc/is_supported_by_hardware(hardware_flag = 0, loud = 0, mob/user = null)
if(!(hardware_flag & usage_flags))
if(loud && computer && user)
to_chat(user, "<span class='danger'>\The [computer] flashes an \"Hardware Error - Incompatible software\" warning.</span>")
return 0
return 1
/datum/computer_file/program/proc/get_signal(specific_action = 0)
if(computer)
return computer.get_ntnet_status(specific_action)
return 0
// Called by Process() on device that runs us, once every tick.
/datum/computer_file/program/proc/process_tick()
return 1
// Check if the user can run program. Only humans can operate computer. Automatically called in run_program()
// User has to wear their ID for ID Scan to work.
// Can also be called manually, with optional parameter being access_to_check to scan the user's ID
/datum/computer_file/program/proc/can_run(mob/user, loud = 0, access_to_check, transfer = 0)
// Defaults to required_access
if(!access_to_check)
if(transfer && transfer_access)
access_to_check = transfer_access
else
access_to_check = required_access
if(!access_to_check) // No required_access, allow it.
return 1
if(!transfer && computer && (computer.obj_flags & EMAGGED)) //emags can bypass the execution locks but not the download ones.
return 1
if(IsAdminGhost(user))
return 1
if(issilicon(user))
return 1
if(ishuman(user))
var/obj/item/card/id/D
var/obj/item/computer_hardware/card_slot/card_slot
if(computer && card_slot)
card_slot = computer.all_components[MC_CARD]
D = card_slot.GetID()
var/mob/living/carbon/human/h = user
var/obj/item/card/id/I = h.get_idcard(TRUE)
if(!I && !D)
if(loud)
to_chat(user, "<span class='danger'>\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.</span>")
return 0
if(I)
if(access_to_check in I.GetAccess())
return 1
else if(D)
if(access_to_check in D.GetAccess())
return 1
if(loud)
to_chat(user, "<span class='danger'>\The [computer] flashes an \"Access Denied\" warning.</span>")
return 0
// This attempts to retrieve header data for UIs. If implementing completely new device of different type than existing ones
// always include the device here in this proc. This proc basically relays the request to whatever is running the program.
/datum/computer_file/program/proc/get_header_data()
if(computer)
return computer.get_header_data()
return list()
// This is performed on program startup. May be overridden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure.
// When implementing new program based device, use this to run the program.
/datum/computer_file/program/proc/run_program(mob/living/user)
if(can_run(user, 1))
if(requires_ntnet && network_destination)
generate_network_log("Connection opened to [network_destination].")
program_state = PROGRAM_STATE_ACTIVE
return 1
return 0
// Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client.
/datum/computer_file/program/proc/kill_program(forced = FALSE)
program_state = PROGRAM_STATE_KILLED
if(network_destination)
generate_network_log("Connection to [network_destination] closed.")
return 1
/datum/computer_file/program/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui && tgui_id)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, tgui_id, filedesc, ui_x, ui_y, state = state)
if(ui_style)
ui.set_style(ui_style)
ui.set_autoupdate(state = 1)
ui.open()
// 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/ui_act(action,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 || !computer.all_components[MC_CPU])
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.ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
/datum/computer_file/program/ui_host()
if(computer.physical)
return computer.physical
else
return computer
/datum/computer_file/program/ui_status(mob/user)
if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists.
return UI_CLOSE
return ..()
@@ -0,0 +1,481 @@
/datum/computer_file/program/card_mod
filename = "cardmod"
filedesc = "ID Card Modification"
program_icon_state = "id"
extended_desc = "Program for programming employee ID cards to access parts of the station."
transfer_access = ACCESS_HEADS
requires_ntnet = 0
size = 8
tgui_id = "ntos_card"
ui_x = 600
ui_y = 700
var/mod_mode = 1
var/is_centcom = 0
var/show_assignments = 0
var/minor = 0
var/authenticated = 0
var/list/reg_ids = list()
var/list/region_access = null
var/list/head_subordinates = null
var/target_dept = 0 //Which department this computer has access to. 0=all departments
var/change_position_cooldown = 30
//Jobs you cannot open new positions for
var/list/blacklisted = list(
"AI",
"Assistant",
"Cyborg",
"Captain",
"Head of Personnel",
"Head of Security",
"Chief Engineer",
"Research Director",
"Chief Medical Officer")
//The scaling factor of max total positions in relation to the total amount of people on board the station in %
var/max_relative_positions = 30 //30%: Seems reasonable, limit of 6 @ 20 players
//This is used to keep track of opened positions for jobs to allow instant closing
//Assoc array: "JobName" = (int)<Opened Positions>
var/list/opened_positions = list();
/datum/computer_file/program/card_mod/New()
..()
addtimer(CALLBACK(src, .proc/SetConfigCooldown), 0)
/datum/computer_file/program/card_mod/proc/SetConfigCooldown()
change_position_cooldown = CONFIG_GET(number/id_console_jobslot_delay)
/datum/computer_file/program/card_mod/event_idremoved(background, slot)
if(!slot || slot == 2)// slot being false means both are removed
minor = 0
authenticated = 0
head_subordinates = null
region_access = null
/datum/computer_file/program/card_mod/proc/job_blacklisted(jobtitle)
return (jobtitle in blacklisted)
//Logic check for if you can open the job
/datum/computer_file/program/card_mod/proc/can_open_job(datum/job/job)
if(job)
if(!job_blacklisted(job.title))
if((job.total_positions <= GLOB.player_list.len * (max_relative_positions / 100)))
var/delta = (world.time / 10) - GLOB.time_last_changed_position
if((change_position_cooldown < delta) || (opened_positions[job.title] < 0))
return 1
return -2
return 0
return 0
//Logic check for if you can close the job
/datum/computer_file/program/card_mod/proc/can_close_job(datum/job/job)
if(job)
if(!job_blacklisted(job.title))
if(job.total_positions > job.current_positions)
var/delta = (world.time / 10) - GLOB.time_last_changed_position
if((change_position_cooldown < delta) || (opened_positions[job.title] > 0))
return 1
return -2
return 0
return 0
/datum/computer_file/program/card_mod/proc/format_jobs(list/jobs)
var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
var/obj/item/card/id/id_card = card_slot.stored_card
var/list/formatted = list()
for(var/job in jobs)
formatted.Add(list(list(
"display_name" = replacetext(job, "&nbsp", " "),
"target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned",
"job" = job)))
return formatted
/datum/computer_file/program/card_mod/ui_act(action, params)
if(..())
return 1
var/obj/item/computer_hardware/card_slot/card_slot
var/obj/item/computer_hardware/printer/printer
if(computer)
card_slot = computer.all_components[MC_CARD]
printer = computer.all_components[MC_PRINT]
if(!card_slot)
return
var/obj/item/card/id/user_id_card = null
var/mob/user = usr
var/obj/item/card/id/id_card = card_slot.stored_card
var/obj/item/card/id/auth_card = card_slot.stored_card2
if(auth_card)
user_id_card = auth_card
else
if(ishuman(user))
var/mob/living/carbon/human/h = user
user_id_card = h.get_idcard(TRUE)
switch(action)
if("PRG_switchm")
if(params["target"] == "mod")
mod_mode = 1
else if (params["target"] == "manifest")
mod_mode = 0
else if (params["target"] == "manage")
mod_mode = 2
if("PRG_togglea")
if(show_assignments)
show_assignments = 0
else
show_assignments = 1
if("PRG_print")
if(computer && printer) //This option should never be called if there is no printer
if(mod_mode)
if(authorized())
var/contents = {"<h4>Access Report</h4>
<u>Prepared By:</u> [user_id_card && 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>Access:</u><br>
"}
var/known_access_rights = get_all_accesses()
for(var/A in id_card.access)
if(A in known_access_rights)
contents += " [get_access_desc(A)]"
if(!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>
[GLOB.data_core ? GLOB.data_core.get_manifest(0) : ""]
"}
if(!printer.print_text(contents,text("crew manifest ([])", STATION_TIME_TIMESTAMP("hh:mm:ss"))))
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("PRG_eject")
if(computer && card_slot)
var/select = params["target"]
switch(select)
if("id")
if(id_card)
GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment)
card_slot.try_eject(1, user)
else
var/obj/item/I = usr.get_active_held_item()
if (istype(I, /obj/item/card/id))
if(!usr.transferItemToLoc(I, computer))
return
card_slot.stored_card = I
if("auth")
if(auth_card)
if(id_card)
GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment)
head_subordinates = null
region_access = null
authenticated = 0
minor = 0
card_slot.try_eject(2, user)
else
var/obj/item/I = usr.get_active_held_item()
if (istype(I, /obj/item/card/id))
if(!usr.transferItemToLoc(I, computer))
return
card_slot.stored_card2 = I
if("PRG_terminate")
if(computer && ((id_card.assignment in head_subordinates) || id_card.assignment == "Assistant"))
id_card.assignment = "Unassigned"
remove_nt_access(id_card)
if("PRG_edit")
if(computer && authorized())
if(params["name"])
var/temp_name = reject_bad_name(input("Enter name.", "Name", id_card.registered_name))
if(temp_name)
id_card.registered_name = temp_name
else
computer.visible_message("<span class='notice'>[computer] buzzes rudely.</span>")
//else if(params["account"])
// var/account_num = text2num(input("Enter account number.", "Account", id_card.associated_account_number))
// id_card.associated_account_number = account_num
if("PRG_assign")
if(computer && authorized() && id_card)
var/t1 = params["assign_target"]
if(t1 == "Custom")
var/temp_t = reject_bad_text(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()
remove_nt_access(id_card)
apply_access(id_card, access)
id_card.assignment = t1
if("PRG_access")
if(params["allowed"] && computer && authorized())
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_accesses()))
id_card.access -= access_type
if(!access_allowed)
id_card.access += access_type
if("PRG_open_job")
var/edit_job_target = params["target"]
var/datum/job/j = SSjob.GetJob(edit_job_target)
if(!j)
return 0
if(can_open_job(j) != 1)
return 0
if(opened_positions[edit_job_target] >= 0)
GLOB.time_last_changed_position = world.time / 10
j.total_positions++
opened_positions[edit_job_target]++
if("PRG_close_job")
var/edit_job_target = params["target"]
var/datum/job/j = SSjob.GetJob(edit_job_target)
if(!j)
return 0
if(can_close_job(j) != 1)
return 0
//Allow instant closing without cooldown if a position has been opened before
if(opened_positions[edit_job_target] <= 0)
GLOB.time_last_changed_position = world.time / 10
j.total_positions--
opened_positions[edit_job_target]--
if("PRG_regsel")
if(!reg_ids)
reg_ids = list()
var/regsel = text2num(params["region"])
if(regsel in reg_ids)
reg_ids -= regsel
else
reg_ids += regsel
if(id_card)
id_card.name = text("[id_card.registered_name]'s ID Card ([id_card.assignment])")
return 1
/datum/computer_file/program/card_mod/proc/remove_nt_access(obj/item/card/id/id_card)
id_card.access -= get_all_accesses()
id_card.access -= get_all_centcom_access()
/datum/computer_file/program/card_mod/proc/apply_access(obj/item/card/id/id_card, list/accesses)
id_card.access |= accesses
/datum/computer_file/program/card_mod/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/computer_hardware/card_slot/card_slot
var/obj/item/computer_hardware/printer/printer
if(computer)
card_slot = computer.all_components[MC_CARD]
printer = computer.all_components[MC_PRINT]
data["mmode"] = mod_mode
var/authed = 0
if(computer)
if(card_slot)
var/obj/item/card/id/auth_card = card_slot.stored_card2
data["auth_name"] = auth_card ? strip_html_simple(auth_card.name) : "-----"
authed = authorized()
if(mod_mode == 2)
data["slots"] = list()
var/list/pos = list()
for(var/datum/job/job in SSjob.occupations)
if(job.title in blacklisted)
continue
var/list/status_open = build_manage(job,1)
var/list/status_close = build_manage(job,0)
pos.Add(list(list(
"title" = job.title,
"current" = job.current_positions,
"total" = job.total_positions,
"status_open" = (authed && !minor) ? status_open["enable"]: 0,
"status_close" = (authed && !minor) ? status_close["enable"] : 0,
"desc_open" = status_open["desc"],
"desc_close" = status_close["desc"])))
data["slots"] = pos
data["src"] = "[REF(src)]"
data["station_name"] = station_name()
if(!mod_mode)
data["manifest"] = list()
var/list/crew = list()
for(var/datum/data/record/t in sortRecord(GLOB.data_core.general))
crew.Add(list(list(
"name" = t.fields["name"],
"rank" = t.fields["rank"])))
data["manifest"] = crew
data["assignments"] = show_assignments
if(computer)
data["have_id_slot"] = !!card_slot
data["have_printer"] = !!printer
if(!card_slot && mod_mode == 1)
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["centcom_access"] = is_centcom
data["authenticated"] = authed
if(mod_mode == 1 && computer)
if(card_slot)
var/obj/item/card/id/id_card = card_slot.stored_card
data["has_id"] = !!id_card
data["id_rank"] = id_card && id_card.assignment ? html_encode(id_card.assignment) : "Unassigned"
data["id_owner"] = id_card && id_card.registered_name ? html_encode(id_card.registered_name) : "-----"
data["id_name"] = id_card ? strip_html_simple(id_card.name) : "-----"
if(show_assignments)
data["engineering_jobs"] = format_jobs(GLOB.engineering_positions)
data["medical_jobs"] = format_jobs(GLOB.medical_positions)
data["science_jobs"] = format_jobs(GLOB.science_positions)
data["security_jobs"] = format_jobs(GLOB.security_positions)
data["cargo_jobs"] = format_jobs(GLOB.supply_positions)
data["civilian_jobs"] = format_jobs(GLOB.civilian_positions)
data["centcom_jobs"] = format_jobs(get_all_centcom_jobs())
if(card_slot.stored_card)
var/obj/item/card/id/id_card = 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), "&nbsp", " "),
"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++)
if((minor || target_dept) && !(i in region_access))
continue
var/list/accesses = list()
if(i in reg_ids)
for(var/access in get_region_accesses(i))
if (get_access_desc(access))
accesses.Add(list(list(
"desc" = replacetext(get_access_desc(access), "&nbsp", " "),
"ref" = access,
"allowed" = (access in id_card.access) ? 1 : 0)))
regions.Add(list(list(
"name" = get_region_accesses_name(i),
"regid" = i,
"selected" = (i in reg_ids) ? 1 : null,
"accesses" = accesses)))
data["regions"] = regions
data["minor"] = target_dept || minor ? 1 : 0
return data
/datum/computer_file/program/card_mod/proc/build_manage(datum/job,open = FALSE)
var/out = "Denied"
var/can_change= 0
if(open)
can_change = can_open_job(job)
else
can_change = can_close_job(job)
var/enable = 0
if(can_change == 1)
out = "[open ? "Open Position" : "Close Position"]"
enable = 1
else if(can_change == -2)
var/time_to_wait = round(change_position_cooldown - ((world.time / 10) - GLOB.time_last_changed_position), 1)
var/mins = round(time_to_wait / 60)
var/seconds = time_to_wait - (60*mins)
out = "Cooldown ongoing: [mins]:[(seconds < 10) ? "0[seconds]" : "[seconds]"]"
else
out = "Denied"
return list("enable" = enable, "desc" = out)
/datum/computer_file/program/card_mod/proc/authorized()
if(!authenticated && computer)
var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
if(card_slot)
var/obj/item/card/id/auth_card = card_slot.stored_card2
if(auth_card)
region_access = list()
if(ACCESS_CHANGE_IDS in auth_card.GetAccess())
minor = 0
authenticated = 1
return 1
else
if((ACCESS_HOP in auth_card.access) && ((target_dept==1) || !target_dept))
region_access |= 1
region_access |= 6
get_subordinates("Head of Personnel")
if((ACCESS_HOS in auth_card.access) && ((target_dept==2) || !target_dept))
region_access |= 2
get_subordinates("Head of Security")
if((ACCESS_CMO in auth_card.access) && ((target_dept==3) || !target_dept))
region_access |= 3
get_subordinates("Chief Medical Officer")
if((ACCESS_RD in auth_card.access) && ((target_dept==4) || !target_dept))
region_access |= 4
get_subordinates("Research Director")
if((ACCESS_CE in auth_card.access) && ((target_dept==5) || !target_dept))
region_access |= 5
get_subordinates("Chief Engineer")
if(region_access.len)
minor = 1
authenticated = 1
return 1
else
return authenticated
/datum/computer_file/program/card_mod/proc/get_subordinates(rank)
head_subordinates = list()
for(var/datum/job/job in SSjob.occupations)
if(rank in job.department_head)
head_subordinates += job.title
@@ -0,0 +1,232 @@
/datum/computer_file/program/filemanager
filename = "filemanager"
filedesc = "File Manager"
extended_desc = "This program allows management of files."
program_icon_state = "generic"
size = 8
requires_ntnet = 0
available_on_ntnet = 0
undeletable = 1
tgui_id = "ntos_file_manager"
var/open_file
var/error
/datum/computer_file/program/filemanager/ui_act(action, params)
if(..())
return 1
var/obj/item/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD]
var/obj/item/computer_hardware/hard_drive/RHDD = computer.all_components[MC_SDD]
var/obj/item/computer_hardware/printer/printer = computer.all_components[MC_PRINT]
switch(action)
if("PRG_openfile")
. = 1
open_file = params["name"]
if("PRG_newtextfile")
. = 1
var/newname = stripped_input(usr, "Enter file name or leave blank to cancel:", "File rename", max_length=50)
if(!newname)
return 1
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("PRG_deletefile")
. = 1
if(!HDD)
return 1
var/datum/computer_file/file = HDD.find_file_by_name(params["name"])
if(!file || file.undeletable)
return 1
HDD.remove_file(file)
if("PRG_usbdeletefile")
. = 1
if(!RHDD)
return 1
var/datum/computer_file/file = RHDD.find_file_by_name(params["name"])
if(!file || file.undeletable)
return 1
RHDD.remove_file(file)
if("PRG_closefile")
. = 1
open_file = null
error = null
if("PRG_clone")
. = 1
if(!HDD)
return 1
var/datum/computer_file/F = HDD.find_file_by_name(params["name"])
if(!F || !istype(F))
return 1
var/datum/computer_file/C = F.clone(1)
HDD.store_file(C)
if("PRG_rename")
. = 1
if(!HDD)
return 1
var/datum/computer_file/file = HDD.find_file_by_name(params["name"])
if(!file || !istype(file))
return 1
var/newname = stripped_input(usr, "Enter new file name:", "File rename", file.filename, max_length=50)
if(file && newname)
file.filename = newname
if("PRG_edit")
. = 1
if(!open_file)
return 1
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
// 16384 is the limit for file length in characters. Currently, papers have value of 2048 so this is 8 times as long, since we can't edit parts of the file independently.
var/newtext = stripped_multiline_input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", html_decode(F.stored_data), 16384, TRUE)
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>[F.stored_data]<br><br>"
HDD.store_file(backup)
if("PRG_printfile")
. = 1
if(!open_file)
return 1
if(!HDD)
return 1
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
if(!F || !istype(F))
return 1
if(!printer)
error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
return 1
if(!printer.print_text("<font face=\"[(computer.obj_flags & EMAGGED) ? CRAYON_FONT : PRINTER_FONT]\">" + prepare_printjob(F.stored_data) + "</font>", open_file))
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
return 1
if("PRG_copytousb")
. = 1
if(!HDD || !RHDD)
return 1
var/datum/computer_file/F = HDD.find_file_by_name(params["name"])
if(!F || !istype(F))
return 1
var/datum/computer_file/C = F.clone(0)
RHDD.store_file(C)
if("PRG_copyfromusb")
. = 1
if(!HDD || !RHDD)
return 1
var/datum/computer_file/F = RHDD.find_file_by_name(params["name"])
if(!F || !istype(F))
return 1
var/datum/computer_file/C = F.clone(0)
HDD.store_file(C)
/datum/computer_file/program/filemanager/proc/parse_tags(t)
t = replacetext(t, "\[center\]", "<center>")
t = replacetext(t, "\[/center\]", "</center>")
t = replacetext(t, "\[br\]", "<BR>")
t = replacetext(t, "\n", "<BR>")
t = replacetext(t, "\[b\]", "<B>")
t = replacetext(t, "\[/b\]", "</B>")
t = replacetext(t, "\[i\]", "<I>")
t = replacetext(t, "\[/i\]", "</I>")
t = replacetext(t, "\[u\]", "<U>")
t = replacetext(t, "\[/u\]", "</U>")
t = replacetext(t, "\[time\]", "[STATION_TIME_TIMESTAMP("hh:mm:ss")]")
t = replacetext(t, "\[date\]", "[time2text(world.realtime, "MMM DD")] [GLOB.year_integer]")
t = replacetext(t, "\[large\]", "<font size=\"4\">")
t = replacetext(t, "\[/large\]", "</font>")
t = replacetext(t, "\[h1\]", "<H1>")
t = replacetext(t, "\[/h1\]", "</H1>")
t = replacetext(t, "\[h2\]", "<H2>")
t = replacetext(t, "\[/h2\]", "</H2>")
t = replacetext(t, "\[h3\]", "<H3>")
t = replacetext(t, "\[/h3\]", "</H3>")
t = replacetext(t, "\[*\]", "<li>")
t = replacetext(t, "\[hr\]", "<HR>")
t = replacetext(t, "\[small\]", "<font size = \"1\">")
t = replacetext(t, "\[/small\]", "</font>")
t = replacetext(t, "\[list\]", "<ul>")
t = replacetext(t, "\[/list\]", "</ul>")
t = replacetext(t, "\[table\]", "<table border=1 cellspacing=0 cellpadding=3 style='border: 1px solid black;'>")
t = replacetext(t, "\[/table\]", "</td></tr></table>")
t = replacetext(t, "\[grid\]", "<table>")
t = replacetext(t, "\[/grid\]", "</td></tr></table>")
t = replacetext(t, "\[row\]", "</td><tr>")
t = replacetext(t, "\[tr\]", "</td><tr>")
t = replacetext(t, "\[td\]", "<td>")
t = replacetext(t, "\[cell\]", "<td>")
t = replacetext(t, "\[tab\]", "&nbsp;&nbsp;&nbsp;&nbsp;")
t = parsemarkdown_basic(t)
return t
/datum/computer_file/program/filemanager/proc/prepare_printjob(t) // Additional stuff to parse if we want to print it and make a happy Head of Personnel. Forms FTW.
t = replacetext(t, "\[field\]", "<span class=\"paper_field\"></span>")
t = replacetext(t, "\[sign\]", "<span class=\"paper_field\"></span>")
t = parse_tags(t)
t = replacetext(t, regex("(?:%s(?:ign)|%f(?:ield))(?=\\s|$)", "ig"), "<span class=\"paper_field\"></span>")
return t
/datum/computer_file/program/filemanager/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD]
var/obj/item/computer_hardware/hard_drive/portable/RHDD = computer.all_components[MC_SDD]
if(error)
data["error"] = error
if(open_file)
var/datum/computer_file/data/file
if(!computer || !HDD)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
file = HDD.find_file_by_name(open_file)
if(!istype(file))
data["error"] = "I/O ERROR: Unable to open file."
else
data["filedata"] = parse_tags(file.stored_data)
data["filename"] = "[file.filename].[file.filetype]"
else
if(!computer || !HDD)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
var/list/files[0]
for(var/datum/computer_file/F in HDD.stored_files)
files.Add(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
return data