Updates Part Nine

This commit is contained in:
Unknown
2019-04-11 19:14:25 -04:00
parent 30474e627f
commit e62eb3b068
33 changed files with 537 additions and 167 deletions
+13 -1
View File
@@ -7,6 +7,7 @@ var/global/datum/ntnet/ntnet_global = new()
var/list/logs = list()
var/list/available_station_software = list()
var/list/available_antag_software = list()
var/list/available_news = list()
var/list/chat_channels = list()
var/list/fileservers = list()
// Amount of logs the system tries to keep in memory. Keep below 999 to prevent byond from acting weirdly.
@@ -32,6 +33,7 @@ var/global/datum/ntnet/ntnet_global = new()
relays.Add(R)
R.NTNet = src
build_software_lists()
build_news_list()
add_log("NTNet logging system activated.")
// Simplified logging: Adds a log. log_string is mandatory parameter, source is optional.
@@ -61,7 +63,7 @@ var/global/datum/ntnet/ntnet_global = new()
// Check all relays. If we have at least one working relay, network is up.
for(var/obj/machinery/ntnet_relay/R in relays)
if(R.is_operational())
if(R.operable())
operating = 1
break
@@ -93,6 +95,15 @@ var/global/datum/ntnet/ntnet_global = new()
if(prog.available_on_syndinet)
available_antag_software.Add(prog)
// Builds lists that contain downloadable software.
/datum/ntnet/proc/build_news_list()
available_news = list()
for(var/F in typesof(/datum/computer_file/data/news_article/))
var/datum/computer_file/data/news_article/news = new F(1)
if(news.stored_data)
available_news.Add(news)
// Attempts to find a downloadable file according to filename var
/datum/ntnet/proc/find_ntnet_file_by_name(var/filename)
for(var/datum/computer_file/program/P in available_station_software)
@@ -145,3 +156,4 @@ var/global/datum/ntnet/ntnet_global = new()
@@ -20,8 +20,8 @@
// TODO: Implement more logic here. For now it's only a placeholder.
/obj/machinery/ntnet_relay/proc/is_operational()
if(stat & (BROKEN | NOPOWER | EMPED))
/obj/machinery/ntnet_relay/operable()
if(!..(EMPED))
return 0
if(dos_failure)
return 0
@@ -30,13 +30,13 @@
return 1
/obj/machinery/ntnet_relay/update_icon()
if(is_operational())
if(operable())
icon_state = "bus"
else
icon_state = "bus_off"
/obj/machinery/ntnet_relay/process()
if(is_operational())
if(operable())
use_power = 2
else
use_power = 1
@@ -113,14 +113,14 @@
if(W.is_screwdriver())
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
panel_open = !panel_open
user << "You [panel_open ? "open" : "close"] the maintenance hatch"
to_chat(user, "You [panel_open ? "open" : "close"] the maintenance hatch")
return
if(W.is_crowbar())
if(!panel_open)
user << "Open the maintenance panel first."
to_chat(user, "Open the maintenance panel first.")
return
playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1)
user << "You disassemble \the [src]!"
to_chat(user, "You disassemble \the [src]!")
for(var/atom/movable/A in component_parts)
A.forceMove(src.loc)
@@ -3,7 +3,7 @@
// consoles and laptops use "procssor" item that is held inside machinery piece
/obj/item/modular_computer
name = "Modular Microcomputer"
desc = "A small portable microcomputer"
desc = "A small portable microcomputer."
var/enabled = 0 // Whether the computer is turned on.
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
@@ -55,27 +55,27 @@
set src in view(1)
if(usr.incapacitated() || !istype(usr, /mob/living))
usr << "<span class='warning'>You can't do that.</span>"
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
if(!Adjacent(usr))
usr << "<span class='warning'>You can't reach it.</span>"
to_chat(usr, "<span class='warning'>You can't reach it.</span>")
return
proc_eject_id(usr)
// Eject ID card from computer, if it has ID slot with card inside.
/obj/item/modular_computer/verb/eject_usb()
set name = "Eject Portable Device"
set name = "Eject Portable Storage"
set category = "Object"
set src in view(1)
if(usr.incapacitated() || !istype(usr, /mob/living))
usr << "<span class='warning'>You can't do that.</span>"
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
if(!Adjacent(usr))
usr << "<span class='warning'>You can't reach it.</span>"
to_chat(usr, "<span class='warning'>You can't reach it.</span>")
return
proc_eject_usb(usr)
@@ -85,11 +85,11 @@
user = usr
if(!card_slot)
user << "\The [src] does not have an ID card slot"
to_chat(user, "\The [src] does not have an ID card slot")
return
if(!card_slot.stored_card)
user << "There is no card in \the [src]"
to_chat(user, "There is no card in \the [src]")
return
if(active_program)
@@ -101,14 +101,15 @@
card_slot.stored_card.forceMove(get_turf(src))
card_slot.stored_card = null
update_uis()
user << "You remove the card from \the [src]"
to_chat(user, "You remove the card from \the [src]")
/obj/item/modular_computer/proc/proc_eject_usb(mob/user)
if(!user)
user = usr
if(!portable_drive)
user << "There is no portable device connected to \the [src]."
to_chat(user, "There is no portable device connected to \the [src].")
return
uninstall_component(user, portable_drive)
@@ -124,19 +125,19 @@
/obj/item/modular_computer/emag_act(var/remaining_charges, var/mob/user)
if(computer_emagged)
user << "\The [src] was already emagged."
to_chat(user, "\The [src] was already emagged.")
return
else
computer_emagged = 1
user << "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message."
to_chat(user, "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.")
return 1
/obj/item/modular_computer/examine(var/mob/user)
..()
if(damage > broken_damage)
user << "<span class='danger'>It is heavily damaged!</span>"
to_chat(user, "<span class='danger'>It is heavily damaged!</span>")
else if(damage)
user << "It is damaged."
to_chat(user, "It is damaged.")
/obj/item/modular_computer/New()
START_PROCESSING(SSobj, src)
@@ -235,23 +236,23 @@
var/issynth = issilicon(user) // Robots and AIs get different activation messages.
if(damage > broken_damage)
if(issynth)
user << "You send an activation signal to \the [src], but it responds with an error code. It must be damaged."
to_chat(user, "You send an activation signal to \the [src], but it responds with an error code. It must be damaged.")
else
user << "You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again."
to_chat(user, "You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again.")
return
if(processor_unit && ((battery_module && battery_module.battery.charge && battery_module.check_functionality()) || check_power_override())) // Battery-run and charged or non-battery but powered by APC.
if(issynth)
user << "You send an activation signal to \the [src], turning it on"
to_chat(user, "You send an activation signal to \the [src], turning it on")
else
user << "You press the power button and start up \the [src]"
to_chat(user, "You press the power button and start up \the [src]")
enabled = 1
update_icon()
ui_interact(user)
else // Unpowered
if(issynth)
user << "You send an activation signal to \the [src] but it does not respond"
to_chat(user, "You send an activation signal to \the [src] but it does not respond")
else
user << "You press the power button but \the [src] does not respond"
to_chat(user, "You press the power button but \the [src] does not respond")
// Process currently calls handle_power(), may be expanded in future if more things are added.
/obj/item/modular_computer/process()
@@ -418,7 +419,7 @@
P.kill_program(1)
update_uis()
user << "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>"
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"] )
var/prog = href_list["PC_runprogram"]
@@ -428,7 +429,7 @@
P = hard_drive.find_file_by_name(prog)
if(!P || !istype(P)) // Program not found or it's not executable program.
user << "<span class='danger'>\The [src]'s screen shows \"I/O ERROR - Unable to run program\" warning.</span>"
to_chat(user, "<span class='danger'>\The [src]'s screen shows \"I/O ERROR - Unable to run program\" warning.</span>")
return
P.computer = src
@@ -445,11 +446,11 @@
return
if(idle_threads.len >= processor_unit.max_idle_programs+1)
user << "<span class='notice'>\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error</span>"
to_chat(user, "<span class='notice'>\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error</span>")
return
if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature)) // The program requires NTNet connection, but we are not connected to NTNet.
user << "<span class='danger'>\The [src]'s screen shows \"NETWORK ERROR - Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning.</span>"
to_chat(user, "<span class='danger'>\The [src]'s screen shows \"NETWORK ERROR - Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning.</span>")
return
if(P.run_program(user))
@@ -493,17 +494,17 @@
if(istype(W, /obj/item/weapon/card/id)) // ID Card, try to insert it.
var/obj/item/weapon/card/id/I = W
if(!card_slot)
user << "You try to insert \the [I] into \the [src], but it does not have an ID card slot installed."
to_chat(user, "You try to insert \the [I] into \the [src], but it does not have an ID card slot installed.")
return
if(card_slot.stored_card)
user << "You try to insert \the [I] into \the [src], but it's ID card slot is occupied."
to_chat(user, "You try to insert \the [I] into \the [src], but it's ID card slot is occupied.")
return
user.drop_from_inventory(I)
card_slot.stored_card = I
I.forceMove(src)
update_uis()
user << "You insert \the [I] into \the [src]."
to_chat(user, "You insert \the [I] into \the [src].")
return
if(istype(W, /obj/item/weapon/paper))
if(!nano_printer)
@@ -514,11 +515,11 @@
if(C.hardware_size <= max_hardware_size)
try_install_component(user, C)
else
user << "This component is too large for \the [src]."
to_chat(user, "This component is too large for \the [src].")
if(W.is_wrench())
var/list/components = get_all_components()
if(components.len)
user << "Remove all components from \the [src] before disassembling it."
to_chat(user, "Remove all components from \the [src] before disassembling it.")
return
new /obj/item/stack/material/steel( get_turf(src.loc), steel_sheet_cost )
src.visible_message("\The [src] has been disassembled by [user].")
@@ -528,23 +529,23 @@
if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(!WT.isOn())
user << "\The [W] is off."
to_chat(user, "\The [W] is off.")
return
if(!damage)
user << "\The [src] does not require repairs."
to_chat(user, "\The [src] does not require repairs.")
return
user << "You begin repairing damage to \the [src]..."
to_chat(user, "You begin repairing damage to \the [src]...")
if(WT.remove_fuel(round(damage/75)) && do_after(usr, damage/10))
damage = 0
user << "You repair \the [src]."
to_chat(user, "You repair \the [src].")
return
if(W.is_screwdriver())
var/list/all_components = get_all_components()
if(!all_components.len)
user << "This device doesn't have any components installed."
to_chat(user, "This device doesn't have any components installed.")
return
var/list/component_names = list()
for(var/obj/item/weapon/computer_hardware/H in all_components)
@@ -578,48 +579,48 @@
// "USB" flash drive.
if(istype(H, /obj/item/weapon/computer_hardware/hard_drive/portable))
if(portable_drive)
user << "This computer's portable drive slot is already occupied by \the [portable_drive]."
to_chat(user, "This computer's portable drive slot is already occupied by \the [portable_drive].")
return
found = 1
portable_drive = H
else if(istype(H, /obj/item/weapon/computer_hardware/hard_drive))
if(hard_drive)
user << "This computer's hard drive slot is already occupied by \the [hard_drive]."
to_chat(user, "This computer's hard drive slot is already occupied by \the [hard_drive].")
return
found = 1
hard_drive = H
else if(istype(H, /obj/item/weapon/computer_hardware/network_card))
if(network_card)
user << "This computer's network card slot is already occupied by \the [network_card]."
to_chat(user, "This computer's network card slot is already occupied by \the [network_card].")
return
found = 1
network_card = H
else if(istype(H, /obj/item/weapon/computer_hardware/nano_printer))
if(nano_printer)
user << "This computer's nano printer slot is already occupied by \the [nano_printer]."
to_chat(user, "This computer's nano printer slot is already occupied by \the [nano_printer].")
return
found = 1
nano_printer = H
else if(istype(H, /obj/item/weapon/computer_hardware/card_slot))
if(card_slot)
user << "This computer's card slot is already occupied by \the [card_slot]."
to_chat(user, "This computer's card slot is already occupied by \the [card_slot].")
return
found = 1
card_slot = H
else if(istype(H, /obj/item/weapon/computer_hardware/battery_module))
if(battery_module)
user << "This computer's battery slot is already occupied by \the [battery_module]."
to_chat(user, "This computer's battery slot is already occupied by \the [battery_module].")
return
found = 1
battery_module = H
else if(istype(H, /obj/item/weapon/computer_hardware/processor_unit))
if(processor_unit)
user << "This computer's processor slot is already occupied by \the [processor_unit]."
to_chat(user, "This computer's processor slot is already occupied by \the [processor_unit].")
return
found = 1
processor_unit = H
if(found)
user << "You install \the [H] into \the [src]"
to_chat(user, "You install \the [H] into \the [src]")
H.holder2 = src
user.drop_from_inventory(H)
H.forceMove(src)
@@ -651,12 +652,12 @@
critical = 1
if(found)
if(user)
user << "You remove \the [H] from \the [src]."
to_chat(user, "You remove \the [H] from \the [src].")
H.forceMove(get_turf(src))
H.holder2 = null
if(critical && enabled)
if(user)
user << "<span class='danger'>\The [src]'s screen freezes for few seconds and then displays an \"HARDWARE ERROR: Critical component disconnected. Please verify component connection and reboot the device. If the problem persists contact technical support for assistance.\" warning.</span>"
to_chat(user, "<span class='danger'>\The [src]'s screen freezes for few seconds and then displays an \"HARDWARE ERROR: Critical component disconnected. Please verify component connection and reboot the device. If the problem persists contact technical support for assistance.\" warning.</span>")
shutdown_computer()
update_icon()
@@ -783,4 +784,4 @@
if(active_program)
return active_program.check_eye(user)
else
return ..()
return ..()
@@ -30,9 +30,9 @@
/obj/item/modular_computer/processor/examine(var/mob/user)
if(damage > broken_damage)
user << "<span class='danger'>It is heavily damaged!</span>"
to_chat(user, "<span class='danger'>It is heavily damaged!</span>")
else if(damage)
user << "It is damaged."
to_chat(user, "It is damaged.")
// Power interaction is handled by our machinery part, due to machinery having APC connection.
/obj/item/modular_computer/processor/handle_power()
@@ -98,7 +98,7 @@
/obj/item/modular_computer/processor/try_install_component(var/mob/living/user, var/obj/item/weapon/computer_hardware/H, var/found = 0)
if(istype(H, /obj/item/weapon/computer_hardware/tesla_link))
if(machinery_computer.tesla_link)
user << "This computer's tesla link slot is already occupied by \the [machinery_computer.tesla_link]."
to_chat(user, "This computer's tesla link slot is already occupied by \the [machinery_computer.tesla_link].")
return
var/obj/item/weapon/computer_hardware/tesla_link/L = H
L.holder = machinery_computer
@@ -130,4 +130,4 @@
// If we have a tesla link on our machinery counterpart, enable it automatically. Lets computer without a battery work.
if(machinery_computer && machinery_computer.tesla_link)
machinery_computer.tesla_link.enabled = 1
..()
..()
@@ -6,5 +6,5 @@
icon_state_menu = "menu"
hardware_flag = PROGRAM_TABLET
max_hardware_size = 1
w_class = 2
light_strength = 2 // Same as PDAs
w_class = ITEMSIZE_SMALL
light_strength = 2 // Same as PDAs
@@ -2,7 +2,7 @@
// Available as custom loadout item, this is literally the worst possible cheap tablet
/obj/item/modular_computer/tablet/preset/custom_loadout/cheap/New()
. = ..()
desc = "A low-end tablet often seen among low ranked station personnel"
desc = "A low-end tablet often seen among low ranked station personnel."
processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src)
battery_module = new/obj/item/weapon/computer_hardware/battery_module/nano(src)
battery_module.charge_to_full()
@@ -1,8 +1,11 @@
// Global var to track modular computers
var/list/global_modular_computers = list()
// Modular Computer - device that runs various programs and operates with hardware
// DO NOT SPAWN THIS TYPE. Use /laptop/ or /console/ instead.
/obj/machinery/modular_computer/
name = "modular computer"
desc = "An advanced computer"
desc = "An advanced computer."
var/battery_powered = 0 // Whether computer should be battery powered. It is set automatically
use_power = 0
@@ -64,7 +67,7 @@
// Eject ID card from computer, if it has ID slot with card inside.
/obj/machinery/modular_computer/verb/eject_usb()
set name = "Eject Portable Device"
set name = "Eject Portable Storage"
set category = "Object"
set src in view(1)
@@ -74,6 +77,7 @@
/obj/machinery/modular_computer/New()
..()
cpu = new(src)
global_modular_computers.Add(src)
/obj/machinery/modular_computer/Destroy()
if(cpu)
@@ -162,9 +166,7 @@
/obj/machinery/modular_computer/power_change()
if(battery_powered)
return
else
..()
update_icon()
..()
/obj/machinery/modular_computer/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if(cpu)
@@ -194,3 +196,4 @@
if(cpu)
return cpu.check_eye(user)
return -1
@@ -15,22 +15,22 @@
set src in view(1)
if(usr.stat || usr.restrained() || usr.lying || !istype(usr, /mob/living))
usr << "<span class='warning'>You can't do that.</span>"
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
if(!Adjacent(usr))
usr << "You can't reach it."
to_chat(usr, "You can't reach it.")
return
if(!istype(loc,/turf))
usr << "[src] is too bulky! You'll have to set it down."
to_chat(usr, "[src] is too bulky! You'll have to set it down.")
return
if(!stored_computer)
if(contents.len)
for(var/obj/O in contents)
O.forceMove(src.loc)
usr << "\The [src] crumbles to pieces."
to_chat(usr, "\The [src] crumbles to pieces.")
spawn(5)
qdel(src)
return
@@ -41,7 +41,7 @@
if(stored_computer.cpu)
stored_computer.cpu.screen_on = 1
loc = stored_computer
usr << "You open \the [src]."
to_chat(usr, "You open \the [src].")
/obj/item/laptop/AltClick()
@@ -51,7 +51,7 @@
// The actual laptop
/obj/machinery/modular_computer/laptop
name = "laptop computer"
desc = "A portable computer"
desc = "A portable computer."
var/obj/item/laptop/portable = null // Portable version of this computer, dropped on alt-click to allow transport. Used by laptops.
hardware_flag = PROGRAM_LAPTOP
icon_state_unpowered = "laptop-open" // Icon state when the computer is turned off
@@ -78,11 +78,11 @@
set src in view(1)
if(usr.stat || usr.restrained() || usr.lying || !istype(usr, /mob/living))
usr << "<span class='warning'>You can't do that.</span>"
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
if(!Adjacent(usr))
usr << "<span class='warning'>You can't reach it.</span>"
to_chat(usr, "<span class='warning'>You can't reach it.</span>")
return
close_laptop(usr)
@@ -101,10 +101,10 @@
src.forceMove(portable)
stat |= MAINT
if(user)
user << "You close \the [src]."
to_chat(user, "You close \the [src].")
if(cpu)
cpu.screen_on = 0
/obj/machinery/modular_computer/laptop/AltClick()
if(Adjacent(usr))
close_laptop()
close_laptop()
@@ -3,6 +3,8 @@
/datum/computer_file/data
var/stored_data = "" // Stored data in string format.
filetype = "DAT"
var/block_size = 250
var/do_not_edit = 0 // Whether the user will be reminded that the file probably shouldn't be edited.
/datum/computer_file/data/clone()
var/datum/computer_file/data/temp = ..()
@@ -10,7 +12,7 @@
return temp
// Calculates file size from amount of characters in saved string
/datum/computer_file/data/proc/calculate_size(var/block_size = 250)
/datum/computer_file/data/proc/calculate_size()
size = max(1, round(length(stored_data) / block_size))
/datum/computer_file/data/logfile
@@ -0,0 +1,21 @@
// /data/ files store data in string format.
// They don't contain other logic for now.
/datum/computer_file/data/news_article
filetype = "XNML"
filename = "Unknown News Entry"
block_size = 1000 // Results in smaller files
do_not_edit = 1 // Editing the file breaks most formatting due to some HTML tags not being accepted as input from average user.
var/server_file_path // File path to HTML file that will be loaded on server start. Example: '/news_articles/space_magazine_1.html'. Use the /news_articles/ folder!
/datum/computer_file/data/news_article/New(var/load_from_file = 0)
..()
if(server_file_path && load_from_file)
stored_data = file2text(server_file_path)
calculate_size()
// NEWS DEFINITIONS BELOW THIS LINE
/datum/computer_file/data/news_article/space/vol_one
filename = "SPACE Magazine vol. 1"
server_file_path = 'news_articles/space_magazine_1.html'
@@ -59,7 +59,7 @@
/datum/computer_file/program/proc/is_supported_by_hardware(var/hardware_flag = 0, var/loud = 0, var/mob/user = null)
if(!(hardware_flag & usage_flags))
if(loud && computer && user)
user << "<span class='danger'>\The [computer] flashes an \"Hardware Error - Incompatible software\" warning.</span>"
to_chat(user, "<span class='danger'>\The [computer] flashes an \"Hardware Error - Incompatible software\" warning.</span>")
return 0
return 1
@@ -88,13 +88,13 @@
var/obj/item/weapon/card/id/I = user.GetIdCard()
if(!I)
if(loud)
user << "<span class='danger'>\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.</span>"
to_chat(user, "<span class='danger'>\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.</span>")
return 0
if(access_to_check in I.access)
return 1
else if(loud)
user << "<span class='danger'>\The [computer] flashes an \"Access Denied\" warning.</span>"
to_chat(user, "<span class='danger'>\The [computer] flashes an \"Access Denied\" warning.</span>")
// This attempts to retrieve header data for NanoUIs. 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.
@@ -154,4 +154,4 @@
if(NM)
return NM.check_eye(user)
else
return -1
return -1
@@ -7,7 +7,7 @@
/obj/item/modular_computer/initial_data()
return get_header_data()
/obj/item/modular_computer/update_layout()
/obj/machinery/modular_computer/update_layout()
return TRUE
/datum/nano_module/program
@@ -24,14 +24,15 @@
dos_speed = NTNETSPEED_ETHERNET * NTNETSPEED_DOS_AMPLIFICATION
if(target && executed)
target.dos_overload += dos_speed
if(!target.is_operational())
if(!target.operable())
target.dos_sources.Remove(src)
target = null
error = "Connection to destination relay lost."
/datum/computer_file/program/ntnet_dos/kill_program(var/forced)
target.dos_sources.Remove(src)
target = null
if(target)
target.dos_sources.Remove(src)
target = null
executed = 0
..(forced)
@@ -24,6 +24,7 @@
/datum/nano_module/camera_monitor/hacked
name = "Hacked Camera Monitoring Program"
//available_to_ai = FALSE
/datum/nano_module/camera_monitor/hacked/can_access_network(var/mob/user, var/network_access)
return 1
@@ -33,4 +34,4 @@
networks.Add(list(list("tag" = NETWORK_MERCENARY, "has_access" = 1)))
networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1)))
networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1)))
return networks
return networks
@@ -36,7 +36,7 @@
var/obj/machinery/camera/current_camera = null
var/current_network = null
/datum/nano_module/camera_monitor/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
/datum/nano_module/camera_monitor/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = default_state)
var/list/data = host.initial_data()
data["current_camera"] = current_camera ? current_camera.nano_structure() : null
@@ -92,14 +92,11 @@
return 1
else if(href_list["switch_network"])
if(!(href_list["switch_network"] in using_map.station_networks))
return
// Either security access, or access to the specific camera network's department is required in order to access the network.
if(can_access_network(usr, get_camera_access(href_list["switch_network"])))
current_network = href_list["switch_network"]
else
usr << "\The [nano_host()] shows an \"Network Access Denied\" error message."
to_chat(usr, "\The [nano_host()] shows an \"Network Access Denied\" error message.")
return 1
else if(href_list["reset"])
@@ -164,9 +161,10 @@
/datum/nano_module/camera_monitor/ert
name = "Advanced Camera Monitoring Program"
//available_to_ai = FALSE
// The ERT variant has access to ERT and crescent cams, but still checks for accesses. ERT members should be able to use it.
/datum/nano_module/camera_monitor/hacked/modify_networks_list(var/list/networks)
/datum/nano_module/camera_monitor/ert/modify_networks_list(var/list/networks)
..()
networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1)))
networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1)))
@@ -141,7 +141,7 @@
contents += " [get_access_desc(A)]"
if(!computer.nano_printer.print_text(contents,"access report"))
usr << "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>"
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>")
@@ -151,7 +151,7 @@
[data_core ? data_core.get_manifest(0) : ""]
"}
if(!computer.nano_printer.print_text(contents,text("crew manifest ([])", stationtime2text())))
usr << "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>"
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>")
@@ -196,7 +196,7 @@
jobdatum = J
break
if(!jobdatum)
usr << "<span class='warning'>No log exists for this job: [t1]</span>"
to_chat(usr, "<span class='warning'>No log exists for this job: [t1]</span>")
return
access = jobdatum.get_access()
@@ -8,7 +8,7 @@
filedesc = "Command and communications program."
program_icon_state = "comm"
nanomodule_path = /datum/nano_module/program/comm
extended_desc = "Used to command and control the station. Can relay long-range communications."
extended_desc = "Used to command and control the station. Can relay long-range communications. This program can not be run on tablet computers."
required_access = access_heads
requires_ntnet = 1
size = 12
@@ -24,6 +24,7 @@
/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 = ""
@@ -104,13 +105,15 @@
if(..())
return 1
var/mob/user = usr
var/ntn_comm = !!program.get_signal(NTNET_COMMUNICATION)
var/ntn_cont = !!program.get_signal(NTNET_SYSTEMCONTROL)
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(is_autenthicated(user) && !issilicon(usr) && ntn_comm)
if(user)
var/obj/item/weapon/card/id/id_card = user.GetIdCard()
@@ -118,31 +121,29 @@
else
crew_announcement.announcer = "Unknown"
if(announcment_cooldown)
usr << "Please allow at least one minute to pass between announcements"
SSnanoui.update_uis(src)
return
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|text
if(!input || !can_still_topic())
SSnanoui.update_uis(src)
return
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(is_autenthicated(user) && program.computer_emagged && !issilicon(usr) && ntn_comm)
if(centcomm_message_cooldown)
usr << "<span class='warning'>Arrays recycling. Please stand by.</span>"
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())
SSnanoui.update_uis(src)
return
return 1
Syndicate_announce(input, usr)
usr << "<span class='notice'>Message transmitted.</span>"
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
@@ -150,34 +151,35 @@
else if(href_list["target"] == "regular")
if(is_autenthicated(user) && !issilicon(usr) && ntn_comm)
if(centcomm_message_cooldown)
usr << "<span class='warning'>Arrays recycling. Please stand by.</span>"
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.
usr <<"<span class='warning'>No Emergency Bluespace Relay detected. Unable to transmit message.</span>"
SSnanoui.update_uis(src)
return
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.", "To abort, send an empty message.", "") as null|text)
if(!input || !can_still_topic())
SSnanoui.update_uis(src)
return
return 1
CentCom_announce(input, usr)
usr << "<span class='notice'>Message transmitted.</span>"
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(is_autenthicated(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(is_autenthicated(user) && ntn_cont)
switch(href_list["target"])
if("line1")
@@ -194,8 +196,8 @@
post_status("alert", href_list["alert"])
else
post_status(href_list["target"])
if("setalert")
. = 1
if(is_autenthicated(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")
@@ -214,9 +216,11 @@
if(SEC_LEVEL_BLUE)
feedback_inc("alert_comms_blue",1)
else
usr << "You press button, but red light flashes and nothing happens." //This should never happen
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(is_autenthicated(user) && ntn_comm)
current_viewing_message_id = text2num(href_list["target"])
for(var/list/m in l.messages)
@@ -224,18 +228,19 @@
current_viewing_message = m
current_status = STATE_VIEWMESSAGE
if("delmessage")
. = 1
if(is_autenthicated(user) && ntn_comm && l != global_message_listener)
l.Remove(current_viewing_message)
current_status = STATE_MESSAGELIST
if("printmessage")
. = 1
if(is_autenthicated(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"]))
usr << "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>"
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>")
SSnanoui.update_uis(src)
/datum/nano_module/program/comm/proc/post_status(var/command, var/data1, var/data2)
@@ -85,8 +85,16 @@
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
if(!F || !istype(F))
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 = sanitize(html_decode(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", F.stored_data) as message), 16384)
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
var/oldtext = html_decode(F.stored_data)
oldtext = replacetext(oldtext, "\[editorbr\]", "\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", "\[editorbr\]"), MAX_TEXTFILE_LENGTH)
if(!newtext)
return
if(F)
var/datum/computer_file/data/backup = F.clone()
HDD.remove_file(F)
@@ -235,5 +243,4 @@
ui.auto_update_layout = 1
ui.set_initial_data(data)
ui.open()
#undef MAX_TEXTFILE_LENGTH
@@ -69,7 +69,7 @@
data["gameover"] = gameover
data["information"] = information
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
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())
@@ -148,4 +148,4 @@
player_mana += regen
enemy_play()
check_gameover()
return 1
return 1
@@ -0,0 +1,119 @@
/datum/computer_file/program/newsbrowser
filename = "newsbrowser"
filedesc = "NTNet/ExoNet News Browser"
extended_desc = "This program may be used to view and download news articles from the network."
program_icon_state = "generic"
size = 8
requires_ntnet = 1
available_on_ntnet = 1
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/message = ""
/datum/computer_file/program/newsbrowser/process_tick()
if(!downloading)
return
download_netspeed = 0
// Speed defines are found in misc.dm
switch(ntnet_status)
if(1)
download_netspeed = NTNETSPEED_LOWSIGNAL
if(2)
download_netspeed = NTNETSPEED_HIGHSIGNAL
if(3)
download_netspeed = NTNETSPEED_ETHERNET
download_progress += download_netspeed
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)
/datum/computer_file/program/newsbrowser/kill_program()
..()
requires_ntnet = 1
loaded_article = null
download_progress = 0
downloading = 0
/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(.)
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["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
else // Viewing list of articles
var/list/all_articles[0]
for(var/datum/computer_file/data/news_article/F in ntnet_global.available_news)
all_articles.Add(list(list(
"name" = F.filename,
"size" = F.size,
"uid" = F.uid
)))
data["all_articles"] = all_articles
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, 700, state = state)
ui.auto_update_layout = 1
ui.set_initial_data(data)
ui.open()
@@ -11,6 +11,7 @@
/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)
if(!ntnet_global)
@@ -51,14 +51,18 @@
// This is not intended to be obtainable in-game. Intended for adminbus and debugging purposes.
/obj/item/weapon/computer_hardware/battery_module/lambda
name = "lambda coil"
desc = "A very complex device that creates it's own bluespace dimension. This dimension may be used to store massive amounts of energy."
desc = "A very complex power source compatible with various computers. It is capable of providing power for nearly unlimited duration."
icon_state = "battery_lambda"
hardware_size = 1
battery_rating = 1000000
battery_rating = 30000
/obj/item/weapon/computer_hardware/battery_module/lambda/New()
..()
battery = new/obj/item/weapon/cell/infinite(src)
/obj/item/weapon/computer_hardware/battery_module/diagnostics(var/mob/user)
..()
user << "Internal battery charge: [battery.charge]/[battery.maxcharge] CU"
to_chat(user, "Internal battery charge: [battery.charge]/[battery.maxcharge] CU")
/obj/item/weapon/computer_hardware/battery_module/New()
battery = new/obj/item/weapon/cell(src)
@@ -68,4 +72,4 @@
/obj/item/weapon/computer_hardware/battery_module/proc/charge_to_full()
if(battery)
battery.charge = battery.maxcharge
battery.charge = battery.maxcharge
@@ -58,8 +58,8 @@
/obj/item/weapon/computer_hardware/hard_drive/diagnostics(var/mob/user)
..()
// 999 is a byond limit that is in place. It's unlikely someone will reach that many files anyway, since you would sooner run out of space.
user << "NT-NFS File Table Status: [stored_files.len]/999"
user << "Storage capacity: [used_capacity]/[max_capacity]GQ"
to_chat(user, "NT-NFS File Table Status: [stored_files.len]/999")
to_chat(user, "Storage capacity: [used_capacity]/[max_capacity]GQ")
// Use this proc to add file to the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks.
/obj/item/weapon/computer_hardware/hard_drive/proc/store_file(var/datum/computer_file/F)
@@ -164,4 +164,4 @@
/obj/item/weapon/computer_hardware/hard_drive/New()
install_default_programs()
..()
..()
@@ -1,6 +1,6 @@
/obj/item/weapon/computer_hardware/
name = "Hardware"
desc = "Unknown Hardware"
desc = "Unknown Hardware."
icon = 'icons/obj/modular_components.dmi'
var/obj/item/modular_computer/holder2 = null
var/power_usage = 0 // If the hardware uses extra power, change this.
@@ -16,27 +16,27 @@
/obj/item/weapon/computer_hardware/attackby(var/obj/item/W as obj, var/mob/living/user as mob)
// Multitool. Runs diagnostics
if(istype(W, /obj/item/device/multitool))
user << "***** DIAGNOSTICS REPORT *****"
to_chat(user, "***** DIAGNOSTICS REPORT *****")
diagnostics(user)
user << "******************************"
to_chat(user, "******************************")
return 1
// Nanopaste. Repair all damage if present for a single unit.
var/obj/item/stack/S = W
if(istype(S, /obj/item/stack/nanopaste))
if(!damage)
user << "\The [src] doesn't seem to require repairs."
to_chat(user, "\The [src] doesn't seem to require repairs.")
return 1
if(S.use(1))
user << "You apply a bit of \the [W] to \the [src]. It immediately repairs all damage."
to_chat(user, "You apply a bit of \the [W] to \the [src]. It immediately repairs all damage.")
damage = 0
return 1
// Cable coil. Works as repair method, but will probably require multiple applications and more cable.
if(istype(S, /obj/item/stack/cable_coil))
if(!damage)
user << "\The [src] doesn't seem to require repairs."
to_chat(user, "\The [src] doesn't seem to require repairs.")
return 1
if(S.use(1))
user << "You patch up \the [src] with a bit of \the [W]."
to_chat(user, "You patch up \the [src] with a bit of \the [W].")
take_damage(-10)
return 1
return ..()
@@ -44,7 +44,7 @@
// Called on multitool click, prints diagnostic information to the user.
/obj/item/weapon/computer_hardware/proc/diagnostics(var/mob/user)
user << "Hardware Integrity Test... (Corruption: [damage]/[max_damage]) [damage > damage_failure ? "FAIL" : damage > damage_malfunction ? "WARN" : "PASS"]"
to_chat(user, "Hardware Integrity Test... (Corruption: [damage]/[max_damage]) [damage > damage_failure ? "FAIL" : damage > damage_malfunction ? "WARN" : "PASS"]")
/obj/item/weapon/computer_hardware/New(var/obj/L)
w_class = hardware_size
@@ -76,13 +76,14 @@
/obj/item/weapon/computer_hardware/examine(var/mob/user)
. = ..()
if(damage > damage_failure)
user << "<span class='danger'>It seems to be severely damaged!</span>"
to_chat(user, "<span class='danger'>It seems to be severely damaged!</span>")
else if(damage > damage_malfunction)
user << "<span class='notice'>It seems to be damaged!</span>"
to_chat(user, "<span class='notice'>It seems to be damaged!</span>")
else if(damage)
user << "It seems to be slightly damaged."
to_chat(user, "It seems to be slightly damaged.")
// Damages the component. Contains necessary checks. Negative damage "heals" the component.
/obj/item/weapon/computer_hardware/proc/take_damage(var/amount)
damage += round(amount) // We want nice rounded numbers here.
damage = between(0, damage, max_damage) // Clamp the value.
@@ -2,6 +2,7 @@
name = "nano printer"
desc = "Small integrated printer with paper recycling module."
power_usage = 50
origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2)
critical = 0
icon_state = "printer"
hardware_size = 1
@@ -10,7 +11,7 @@
/obj/item/weapon/computer_hardware/nano_printer/diagnostics(var/mob/user)
..()
user << "Paper buffer level: [stored_paper]/[max_paper]"
to_chat(user, "Paper buffer level: [stored_paper]/[max_paper]")
/obj/item/weapon/computer_hardware/nano_printer/proc/print_text(var/text_to_print, var/paper_title = null)
if(!stored_paper)
@@ -20,27 +21,21 @@
if(!check_functionality())
return 0
var/obj/item/weapon/paper/P = new/obj/item/weapon/paper(get_turf(holder2))
// Damaged printer causes the resulting paper to be somewhat harder to read.
if(damage > damage_malfunction)
P.info = stars(text_to_print, 100-malfunction_probability)
else
P.info = text_to_print
if(paper_title)
P.name = paper_title
P.update_icon()
text_to_print = stars(text_to_print, 100-malfunction_probability)
new/obj/item/weapon/paper(get_turf(holder2),text_to_print, paper_title)
stored_paper--
P = null
return 1
/obj/item/weapon/computer_hardware/nano_printer/attackby(obj/item/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/paper))
if(stored_paper >= max_paper)
user << "You try to add \the [W] into [src], but it's paper bin is full"
to_chat(user, "You try to add \the [W] into [src], but it's paper bin is full")
return
user << "You insert \the [W] into [src]."
to_chat(user, "You insert \the [W] into [src].")
qdel(W)
stored_paper++
@@ -48,4 +43,4 @@
if(holder2 && (holder2.nano_printer == src))
holder2.nano_printer = null
holder2 = null
..()
..()
@@ -16,14 +16,14 @@ var/global/ntnet_card_uid = 1
/obj/item/weapon/computer_hardware/network_card/diagnostics(var/mob/user)
..()
user << "NIX Unique ID: [identification_id]"
user << "NIX User Tag: [identification_string]"
user << "Supported protocols:"
user << "511.m SFS (Subspace) - Standard Frequency Spread"
to_chat(user, "NIX Unique ID: [identification_id]")
to_chat(user, "NIX User Tag: [identification_string]")
to_chat(user, "Supported protocols:")
to_chat(user, "511.m SFS (Subspace) - Standard Frequency Spread")
if(long_range)
user << "511.n WFS/HB (Subspace) - Wide Frequency Spread/High Bandiwdth"
to_chat(user, "511.n WFS/HB (Subspace) - Wide Frequency Spread/High Bandiwdth")
if(ethernet)
user << "OpenEth (Physical Connection) - Physical network connection port"
to_chat(user, "OpenEth (Physical Connection) - Physical network connection port")
/obj/item/weapon/computer_hardware/network_card/New(var/l)
..(l)
@@ -1,7 +1,7 @@
// These are basically USB data sticks and may be used to transfer files between devices
/obj/item/weapon/computer_hardware/hard_drive/portable/
name = "basic data crystal"
desc = "Small crystal with imprinted photonic circuits that can be used to store data. It's capacity is 16 GQ"
desc = "Small crystal with imprinted photonic circuits that can be used to store data. Its capacity is 16 GQ."
power_usage = 10
icon_state = "flashdrive_basic"
hardware_size = 1
@@ -10,7 +10,7 @@
/obj/item/weapon/computer_hardware/hard_drive/portable/advanced
name = "advanced data crystal"
desc = "Small crystal with imprinted high-density photonic circuits that can be used to store data. It's capacity is 64 GQ"
desc = "Small crystal with imprinted high-density photonic circuits that can be used to store data. Its capacity is 64 GQ."
power_usage = 20
icon_state = "flashdrive_advanced"
hardware_size = 1
@@ -19,7 +19,7 @@
/obj/item/weapon/computer_hardware/hard_drive/portable/super
name = "super data crystal"
desc = "Small crystal with imprinted ultra-density photonic circuits that can be used to store data. It's capacity is 256 GQ"
desc = "Small crystal with imprinted ultra-density photonic circuits that can be used to store data. Its capacity is 256 GQ."
power_usage = 40
icon_state = "flashdrive_super"
hardware_size = 1
@@ -29,4 +29,4 @@
/obj/item/weapon/computer_hardware/hard_drive/portable/New()
..()
stored_files = list()
recalculate_size()
recalculate_size()
@@ -38,4 +38,4 @@
hardware_size = 1
power_usage = 75
max_idle_programs = 2
origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 3)
origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 3)
@@ -17,4 +17,4 @@
/obj/item/weapon/computer_hardware/tesla_link/Destroy()
if(holder && (holder.tesla_link == src))
holder.tesla_link = null
..()
..()
@@ -5,7 +5,7 @@
desc = "A vending machine with microfabricator capable of dispensing various NT-branded computers"
icon = 'icons/obj/vending.dmi'
icon_state = "robotics"
layer = 2.9
layer = OBJ_LAYER - 0.1
anchored = 1
density = 1