Merge pull request #19729 from Shadowlight213/bayputers

[Review Ready] Ports baystation's modular computers
This commit is contained in:
oranges
2016-08-17 13:23:51 +12:00
committed by GitHub
100 changed files with 6167 additions and 34 deletions
@@ -2066,6 +2066,7 @@
/obj/machinery/light{
dir = 1
},
/obj/machinery/ntnet_relay,
/turf/open/floor/plasteel/black,
/area/turret_protected/tcomeast{
name = "\improper Telecommunications Chamber"
@@ -25112,6 +25112,7 @@
pixel_x = -22;
tag = "icon-alarm0 (EAST)"
},
/obj/machinery/ntnet_relay,
/turf/open/floor/plasteel/darkyellow{
name = "Mainframe Floor";
initial_gas_mix = "n2=100;TEMP=80"
@@ -55719,6 +55719,7 @@
/area/tcommsat/server)
"cib" = (
/obj/machinery/power/terminal,
/obj/machinery/ntnet_relay,
/turf/open/floor/bluegrid{
name = "Mainframe Base";
initial_gas_mix = "n2=100;TEMP=80"
@@ -54567,6 +54567,7 @@
network = list("SS13","tcomm")
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/ntnet_relay,
/turf/open/floor/plasteel/black{
name = "Mainframe Floor";
initial_gas_mix = "n2=100;TEMP=80"
@@ -19381,7 +19381,7 @@
},
/area/bridge)
"aRo" = (
/obj/machinery/computer/card,
/obj/machinery/modular_computer/console/preset/command,
/turf/open/floor/plasteel/green/side{
dir = 10
},
@@ -35121,6 +35121,7 @@
},
/area/crew_quarters/hor)
"bzN" = (
/obj/machinery/modular_computer/console/preset/research,
/turf/open/floor/plasteel/warnwhite{
dir = 6
},
@@ -47453,6 +47454,7 @@
/obj/machinery/power/terminal{
dir = 4
},
/obj/machinery/ntnet_relay,
/turf/open/floor/bluegrid{
name = "Mainframe Base";
initial_gas_mix = "n2=100;TEMP=80"
@@ -49048,13 +49050,11 @@
/turf/open/floor/plating,
/area/maintenance/aft)
"cdk" = (
/obj/machinery/computer/monitor{
name = "primary power monitoring console"
},
/obj/structure/cable{
icon_state = "0-2";
d2 = 2
},
/obj/machinery/modular_computer/console/preset/engineering,
/turf/open/floor/plasteel,
/area/engine/engineering)
"cdl" = (
+29 -1
View File
@@ -498,4 +498,32 @@ var/global/list/ghost_others_options = list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define BUBBLEGUM_SCORE "Bubblegum Killed"
#define DRAKE_SCORE "Drakes Killed"
#define BOSS_SCORE "Bosses Killed"
#define TENDRIL_CLEAR_SCORE "Tendrils Killed"
#define TENDRIL_CLEAR_SCORE "Tendrils Killed"
// NTNet module-configuration values. Do not change these. If you need to add another use larger number (5..6..7 etc)
#define NTNET_SOFTWAREDOWNLOAD 1 // Downloads of software from NTNet
#define NTNET_PEERTOPEER 2 // P2P transfers of files between devices
#define NTNET_COMMUNICATION 3 // Communication (messaging)
#define NTNET_SYSTEMCONTROL 4 // Control of various systems, RCon, air alarm control, etc.
// NTNet transfer speeds, used when downloading/uploading a file/program.
#define NTNETSPEED_LOWSIGNAL 0.5 // GQ/s transfer speed when the device is wirelessly connected and on Low signal
#define NTNETSPEED_HIGHSIGNAL 1 // GQ/s transfer speed when the device is wirelessly connected and on High signal
#define NTNETSPEED_ETHERNET 2 // GQ/s transfer speed when the device is using wired connection
// Program bitflags
#define PROGRAM_ALL 7
#define PROGRAM_CONSOLE 1
#define PROGRAM_LAPTOP 2
#define PROGRAM_TABLET 4
#define PROGRAM_STATE_KILLED 0
#define PROGRAM_STATE_BACKGROUND 1
#define PROGRAM_STATE_ACTIVE 2
// Caps for NTNet logging. Less than 10 would make logging useless anyway, more than 500 may make the log browser too laggy. Defaults to 100 unless user changes it.
#define MAX_NTNET_LOGS 300
#define MIN_NTNET_LOGS 10
+4 -1
View File
@@ -22,7 +22,7 @@
/proc/log_adminsay(text)
if (config.log_adminchat)
log_admin("ASAY: [text]")
/proc/log_dsay(text)
if (config.log_adminchat)
log_admin("DSAY: [text]")
@@ -76,3 +76,6 @@
//reusing the PDA option because I really don't think news comments are worth a config option
diary << "\[[time_stamp()]]COMMENT: [text]"
/proc/log_chat(text)
if (config.log_pda)
diary << "\[[time_stamp()]]CHAT: [text]"
+1
View File
@@ -10,6 +10,7 @@ var/global/list/deliverybeacons = list() //list of all MULEbot delivery beacon
var/global/list/deliverybeacontags = list() //list of all tags associated with delivery beacons.
var/global/list/nuke_list = list()
var/global/list/nuke_tiles = list() //list of all turfs that turn to animated red grids when a nuke is triggered
var/global/list/alarmdisplay = list() //list of all machines or programs that can display station alerts
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions
var/global/list/chemical_reagents_list //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
+13
View File
@@ -74,6 +74,11 @@
D.cancelAlarm("Power", src, source)
else
D.triggerAlarm("Power", src, cameras, source)
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
if(state == 1)
p.cancelAlarm("Power", src, source)
else
p.triggerAlarm("Power", src, cameras, source)
/area/proc/atmosalert(danger_level, obj/source)
if(danger_level != atmosalm)
@@ -89,6 +94,8 @@
a.triggerAlarm("Atmosphere", src, cameras, source)
for(var/mob/living/simple_animal/drone/D in mob_list)
D.triggerAlarm("Atmosphere", src, cameras, source)
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
p.triggerAlarm("Atmosphere", src, cameras, source)
else if (src.atmosalm == 2)
for(var/mob/living/silicon/aiPlayer in player_list)
@@ -97,6 +104,8 @@
a.cancelAlarm("Atmosphere", src, source)
for(var/mob/living/simple_animal/drone/D in mob_list)
D.cancelAlarm("Atmosphere", src, source)
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
p.cancelAlarm("Atmosphere", src, source)
src.atmosalm = danger_level
return 1
@@ -128,6 +137,8 @@
aiPlayer.triggerAlarm("Fire", src, cameras, source)
for (var/mob/living/simple_animal/drone/D in mob_list)
D.triggerAlarm("Fire", src, cameras, source)
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
p.triggerAlarm("Fire", src, cameras, source)
/area/proc/firereset(obj/source)
for(var/area/RA in related)
@@ -150,6 +161,8 @@
a.cancelAlarm("Fire", src, source)
for (var/mob/living/simple_animal/drone/D in mob_list)
D.cancelAlarm("Fire", src, source)
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
p.cancelAlarm("Fire", src, source)
/area/proc/burglaralert(obj/trigger)
if(always_unpowered == 1) //no burglar alarms in space/asteroid
+34 -1
View File
@@ -8,6 +8,7 @@
idle_power_usage = 4
active_power_usage = 250
var/obj/item/weapon/charging = null
var/list/allowed_devices = list(/obj/item/weapon/gun/energy,/obj/item/weapon/melee/baton,/obj/item/ammo_box/magazine/recharge,/obj/item/weapon/computer_hardware/battery_module,/obj/item/laptop,/obj/item/modular_computer/)
var/recharge_coeff = 1
/obj/machinery/recharger/New()
@@ -36,7 +37,11 @@
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
return
if(istype(G, /obj/item/weapon/gun/energy) || istype(G, /obj/item/weapon/melee/baton) || istype(G, /obj/item/ammo_box/magazine/recharge))
var/allowed = 0
for (var/allowed_type in allowed_devices)
if (istype(G, allowed_type)) allowed = 1
if(allowed)
if(anchored)
if(charging || panel_open)
return 1
@@ -127,6 +132,34 @@
use_power(200 * recharge_coeff)
using_power = 1
if(istype(charging, /obj/item/laptop))
var/obj/item/laptop/L = charging
if(L.stored_computer.cpu.battery_module)
var/obj/item/weapon/computer_hardware/battery_module/B = L.stored_computer.cpu.battery_module
if(B.battery)
if(B.battery.charge < B.battery.maxcharge)
B.battery.give(B.battery.chargerate * recharge_coeff)
use_power(200 * recharge_coeff)
using_power = 1
if(istype(charging, /obj/item/weapon/computer_hardware/battery_module))
var/obj/item/weapon/computer_hardware/battery_module/B = charging
if(B.battery)
if(B.battery.charge < B.battery.maxcharge)
B.battery.give(B.battery.chargerate * recharge_coeff)
use_power(200 * recharge_coeff)
using_power = 1
if(istype(charging, /obj/item/modular_computer))
var/obj/item/modular_computer/C = charging
if(C.battery_module)
var/obj/item/weapon/computer_hardware/battery_module/B = C.battery_module
if(B.battery)
if(B.battery.charge < B.battery.maxcharge)
B.battery.give(B.battery.chargerate * recharge_coeff)
use_power(200 * recharge_coeff)
using_power = 1
update_icon(using_power)
/obj/machinery/recharger/power_change()
@@ -30,6 +30,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \
new/datum/stack_recipe("wall girders", /obj/structure/girder, 2, time = 40, one_per_turf = 1, on_floor = 1), \
null, \
new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 25, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("modular console", /obj/machinery/modular_computer/console/buildable/, 10, time = 25, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("machine frame", /obj/structure/frame/machine, 5, time = 25, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("airlock assembly", /obj/structure/door_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("firelock frame", /obj/structure/firelock_frame, 3, time = 50, one_per_turf = 1, on_floor = 1), \
+30
View File
@@ -179,6 +179,36 @@ You can set verify to TRUE if you want send() to sleep until the client has the
"tgui.js" = 'tgui/assets/tgui.js'
)
/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',
)
/datum/asset/simple/pda
assets = list(
"pda_atmos.png" = 'icons/pda_icons/pda_atmos.png',
+5 -2
View File
@@ -64,6 +64,7 @@
/var/const/access_mineral_storeroom = 64
/var/const/access_minisat = 65
/var/const/access_weapons = 66 //Weapon authorization for secbots
/var/const/access_network = 67
//BEGIN CENTCOM ACCESS
/*Should leave plenty of room if we need to add more access levels.
@@ -237,7 +238,7 @@
access_hydroponics, access_library, access_lawyer, access_virology, access_cmo, access_qm, access_surgery,
access_theatre, access_research, access_mining, access_mailsorting, access_weapons,
access_heads_vault, access_mining_station, access_xenobiology, access_ce, access_hop, access_hos, access_RC_announce,
access_keycard_auth, access_tcomsat, access_gateway, access_mineral_storeroom, access_minisat)
access_keycard_auth, access_tcomsat, access_gateway, access_mineral_storeroom, access_minisat, access_network)
/proc/get_all_centcom_access()
return list(access_cent_general, access_cent_thunder, access_cent_specops, access_cent_medical, access_cent_living, access_cent_storage, access_cent_teleporter, access_cent_captain)
@@ -267,7 +268,7 @@
if(3) //medbay
return list(access_medical, access_genetics, access_morgue, access_chemistry, access_virology, access_surgery, access_cmo)
if(4) //research
return list(access_research, access_tox, access_tox_storage, access_genetics, access_robotics, access_xenobiology, access_minisat, access_rd)
return list(access_research, access_tox, access_tox_storage, access_genetics, access_robotics, access_xenobiology, access_minisat, access_rd, access_network)
if(5) //engineering and maintenance
return list(access_construction, access_maint_tunnels, access_engine, access_engine_equip, access_external_airlocks, access_tech_storage, access_atmospherics, access_tcomsat, access_minisat, access_ce)
if(6) //supply
@@ -424,6 +425,8 @@
return "AI Satellite"
if(access_weapons)
return "Weapon Permit"
if(access_network)
return "Network Access"
/proc/get_centcom_access_desc(A)
switch(A)
+1
View File
@@ -14,6 +14,7 @@ Assistant
minimal_access = list() //See /datum/job/assistant/get_access()
outfit = /datum/outfit/job/assistant
/datum/job/assistant/get_access()
if((config.jobs_have_maint_access & ASSISTANTS_HAVE_MAINT_ACCESS) || !config.jobs_have_minimal_access) //Config has assistant maint access set
. = ..()
+1 -1
View File
@@ -99,7 +99,7 @@ Head of Personnel
shoes = /obj/item/clothing/shoes/sneakers/brown
head = /obj/item/clothing/head/hopcap
backpack_contents = list(/obj/item/weapon/storage/box/ids=1,\
/obj/item/weapon/melee/classic_baton/telescopic=1)
/obj/item/weapon/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced = 1)
/datum/outfit/job/hop/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
..()
+6 -2
View File
@@ -52,6 +52,7 @@ Cargo Technician
belt = /obj/item/device/pda/cargo
ears = /obj/item/device/radio/headset/headset_cargo
uniform = /obj/item/clothing/under/rank/cargotech
backpack_contents = list(/obj/item/modular_computer/tablet/preset/cheap=1)
/*
@@ -86,7 +87,7 @@ Shaft Miner
backpack_contents = list(
/obj/item/weapon/storage/bag/ore=1,\
/obj/item/weapon/kitchen/knife/combat/survival=1,\
/obj/item/weapon/mining_voucher=1)
/obj/item/weapon/mining_voucher=1,/obj/item/modular_computer/tablet/preset/cheap=1)
backpack = /obj/item/weapon/storage/backpack/explorer
satchel = /obj/item/weapon/storage/backpack/satchel/explorer
@@ -121,7 +122,7 @@ Bartender
ears = /obj/item/device/radio/headset/headset_srv
uniform = /obj/item/clothing/under/rank/bartender
suit = /obj/item/clothing/suit/armor/vest
backpack_contents = list(/obj/item/weapon/storage/box/beanbag=1)
backpack_contents = list(/obj/item/weapon/storage/box/beanbag=1,/obj/item/modular_computer/tablet/preset/cheap=1)
shoes = /obj/item/clothing/shoes/laceup
/*
@@ -152,6 +153,7 @@ Cook
uniform = /obj/item/clothing/under/rank/chef
suit = /obj/item/clothing/suit/toggle/chef
head = /obj/item/clothing/head/chefhat
backpack_contents = list(/obj/item/modular_computer/tablet/preset/cheap=1)
/datum/outfit/job/cook/pre_equip(mob/living/carbon/human/H)
..()
@@ -200,6 +202,7 @@ Botanist
backpack = /obj/item/weapon/storage/backpack/botany
satchel = /obj/item/weapon/storage/backpack/satchel/hyd
backpack_contents = list(/obj/item/modular_computer/tablet/preset/cheap=1)
/*
@@ -228,3 +231,4 @@ Janitor
belt = /obj/item/device/pda/janitor
ears = /obj/item/device/radio/headset/headset_srv
uniform = /obj/item/clothing/under/rank/janitor
backpack_contents = list(/obj/item/modular_computer/tablet/preset/cheap=1)
+3 -3
View File
@@ -20,12 +20,12 @@ Research Director
access_tox_storage, access_teleporter, access_sec_doors,
access_research, access_robotics, access_xenobiology, access_ai_upload,
access_RC_announce, access_keycard_auth, access_gateway, access_mineral_storeroom,
access_tech_storage, access_minisat, access_maint_tunnels)
access_tech_storage, access_minisat, access_maint_tunnels, access_network)
minimal_access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue,
access_tox_storage, access_teleporter, access_sec_doors,
access_research, access_robotics, access_xenobiology, access_ai_upload,
access_RC_announce, access_keycard_auth, access_gateway, access_mineral_storeroom,
access_tech_storage, access_minisat, access_maint_tunnels)
access_tech_storage, access_minisat, access_maint_tunnels, access_network)
/datum/outfit/job/rd
name = "Research Director"
@@ -38,7 +38,7 @@ Research Director
suit = /obj/item/clothing/suit/toggle/labcoat
l_hand = /obj/item/weapon/clipboard
l_pocket = /obj/item/device/laser_pointer
backpack_contents = list(/obj/item/weapon/melee/classic_baton/telescopic=1)
backpack_contents = list(/obj/item/weapon/melee/classic_baton/telescopic=1,/obj/item/modular_computer/tablet/preset/advanced=1)
backpack = /obj/item/weapon/storage/backpack/science
satchel = /obj/item/weapon/storage/backpack/satchel/tox
+1 -1
View File
@@ -158,7 +158,7 @@ Detective
backpack_contents = list(/obj/item/weapon/storage/box/evidence=1,\
/obj/item/device/detective_scanner=1,\
/obj/item/weapon/melee/classic_baton=1,\
/obj/item/weapon/reagent_containers/food/drinks/flask/det)
/obj/item/weapon/reagent_containers/food/drinks/flask/det=1)
mask = /obj/item/clothing/mask/cigarette
/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
@@ -0,0 +1,65 @@
var/global/static/ntnrc_uid = 0
/datum/ntnet_conversation/
var/id = null
var/title = "Untitled Conversation"
var/datum/computer_file/program/chatclient/operator // "Administrator" of this channel. Creator starts as channel's operator,
var/list/messages = list()
var/list/clients = list()
var/password
/datum/ntnet_conversation/New()
id = ntnrc_uid
ntnrc_uid++
if(ntnet_global)
ntnet_global.chat_channels.Add(src)
..()
/datum/ntnet_conversation/proc/add_message(message, username)
message = "[worldtime2text()] [username]: [message]"
messages.Add(message)
trim_message_list()
/datum/ntnet_conversation/proc/add_status_message(message)
messages.Add("[worldtime2text()] -!- [message]")
trim_message_list()
/datum/ntnet_conversation/proc/trim_message_list()
if(messages.len <= 50)
return
messages = messages.Copy(messages.len-50 ,0)
/datum/ntnet_conversation/proc/add_client(datum/computer_file/program/chatclient/C)
if(!istype(C))
return
clients.Add(C)
add_status_message("[C.username] has joined the channel.")
// No operator, so we assume the channel was empty. Assign this user as operator.
if(!operator)
changeop(C)
/datum/ntnet_conversation/proc/remove_client(datum/computer_file/program/chatclient/C)
if(!istype(C) || !(C in clients))
return
clients.Remove(C)
add_status_message("[C.username] has left the channel.")
// Channel operator left, pick new operator
if(C == operator)
operator = null
if(clients.len)
var/datum/computer_file/program/chatclient/newop = pick(clients)
changeop(newop)
/datum/ntnet_conversation/proc/changeop(datum/computer_file/program/chatclient/newop)
if(istype(newop))
operator = newop
add_status_message("Channel operator status transferred to [newop.username].")
/datum/ntnet_conversation/proc/change_title(newtitle, datum/computer_file/program/chatclient/client)
if(operator != client)
return 0 // Not Authorised
add_status_message("[client.username] has changed channel title from [title] to [newtitle]")
title = newtitle
@@ -0,0 +1,145 @@
var/global/datum/ntnet/ntnet_global = new()
// This is the NTNet datum. There can be only one NTNet datum in game at once. Modular computers read data from this.
/datum/ntnet/
var/list/relays = list()
var/list/logs = list()
var/list/available_station_software = list()
var/list/available_antag_software = 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.
// High values make displaying logs much laggier.
var/setting_maxlogcount = 100
// These only affect wireless. LAN (consoles) are unaffected since it would be possible to create scenario where someone turns off NTNet, and is unable to turn it back on since it refuses connections
var/setting_softwaredownload = 1
var/setting_peertopeer = 1
var/setting_communication = 1
var/setting_systemcontrol = 1
var/setting_disabled = 0 // Setting to 1 will disable all wireless, independently on relays status.
var/intrusion_detection_enabled = 1 // Whether the IDS warning system is enabled
var/intrusion_detection_alarm = 0 // Set when there is an IDS warning due to malicious (antag) software.
// If new NTNet datum is spawned, it replaces the old one.
/datum/ntnet/New()
if(ntnet_global && (ntnet_global != src))
ntnet_global = src // There can be only one.
for(var/obj/machinery/ntnet_relay/R in machines)
relays.Add(R)
R.NTNet = src
build_software_lists()
add_log("NTNet logging system activated.")
// Simplified logging: Adds a log. log_string is mandatory parameter, source is optional.
/datum/ntnet/proc/add_log(log_string, obj/item/weapon/computer_hardware/network_card/source = null)
var/log_text = "[worldtime2text()] - "
if(source)
log_text += "[source.get_network_tag()] - "
else
log_text += "*SYSTEM* - "
log_text += log_string
logs.Add(log_text)
// We have too many logs, remove the oldest entries until we get into the limit
if(logs.len > setting_maxlogcount)
logs = logs.Copy(logs.len-setting_maxlogcount,0)
// Checks whether NTNet operates. If parameter is passed checks whether specific function is enabled.
/datum/ntnet/proc/check_function(specific_action = 0)
if(!relays || !relays.len) // No relays found. NTNet is down
return 0
var/operating = 0
// Check all relays. If we have at least one working relay, network is up.
for(var/M in relays)
var/obj/machinery/ntnet_relay/R = M
if(R.is_operational())
operating = 1
break
if(setting_disabled)
return 0
switch(specific_action)
if(NTNET_SOFTWAREDOWNLOAD)
return (operating && setting_softwaredownload)
if(NTNET_PEERTOPEER)
return (operating && setting_peertopeer)
if(NTNET_COMMUNICATION)
return (operating && setting_communication)
if(NTNET_SYSTEMCONTROL)
return (operating && setting_systemcontrol)
return operating
// Builds lists that contain downloadable software.
/datum/ntnet/proc/build_software_lists()
available_station_software = list()
available_antag_software = list()
for(var/F in typesof(/datum/computer_file/program))
var/datum/computer_file/program/prog = new F
// Invalid type (shouldn't be possible but just in case), invalid filetype (not executable program) or invalid filename (unset program)
if(!prog || prog.filename == "UnknownProgram" || prog.filetype != "PRG")
continue
// Check whether the program should be available for station/antag download, if yes, add it to lists.
if(prog.available_on_ntnet)
available_station_software.Add(prog)
if(prog.available_on_syndinet)
available_antag_software.Add(prog)
// Attempts to find a downloadable file according to filename var
/datum/ntnet/proc/find_ntnet_file_by_name(filename)
for(var/N in available_station_software)
var/datum/computer_file/program/P = N
if(filename == P.filename)
return P
for(var/N in available_antag_software)
var/datum/computer_file/program/P = N
if(filename == P.filename)
return P
// Resets the IDS alarm
/datum/ntnet/proc/resetIDS()
intrusion_detection_alarm = 0
/datum/ntnet/proc/toggleIDS()
resetIDS()
intrusion_detection_enabled = !intrusion_detection_enabled
// Removes all logs
/datum/ntnet/proc/purge_logs()
logs = list()
add_log("-!- LOGS DELETED BY SYSTEM OPERATOR -!-")
// Updates maximal amount of stored logs. Use this instead of setting the number, it performs required checks.
/datum/ntnet/proc/update_max_log_count(lognumber)
if(!lognumber)
return 0
// Trim the value if necessary
lognumber = max(MIN_NTNET_LOGS, min(lognumber, MAX_NTNET_LOGS))
setting_maxlogcount = lognumber
add_log("Configuration Updated. Now keeping [setting_maxlogcount] logs in system memory.")
/datum/ntnet/proc/toggle_function(function)
if(!function)
return
function = text2num(function)
switch(function)
if(NTNET_SOFTWAREDOWNLOAD)
setting_softwaredownload = !setting_softwaredownload
add_log("Configuration Updated. Wireless network firewall now [setting_softwaredownload ? "allows" : "disallows"] connection to software repositories.")
if(NTNET_PEERTOPEER)
setting_peertopeer = !setting_peertopeer
add_log("Configuration Updated. Wireless network firewall now [setting_peertopeer ? "allows" : "disallows"] peer to peer network traffic.")
if(NTNET_COMMUNICATION)
setting_communication = !setting_communication
add_log("Configuration Updated. Wireless network firewall now [setting_communication ? "allows" : "disallows"] instant messaging and similar communication services.")
if(NTNET_SYSTEMCONTROL)
setting_systemcontrol = !setting_systemcontrol
add_log("Configuration Updated. Wireless network firewall now [setting_systemcontrol ? "allows" : "disallows"] remote control of station's systems.")
@@ -0,0 +1,127 @@
// Relays don't handle any actual communication. Global NTNet datum does that, relays only tell the datum if it should or shouldn't work.
/obj/machinery/ntnet_relay
name = "NTNet Quantum Relay"
desc = "A very complex router and transmitter capable of connecting electronic devices together. Looks fragile."
use_power = 2
active_power_usage = 20000 //20kW, apropriate for machine that keeps massive cross-Zlevel wireless network operational.
idle_power_usage = 100
icon = 'icons/obj/machines/telecomms.dmi'
icon_state = "bus"
anchored = 1
density = 1
var/datum/ntnet/NTNet = null // This is mostly for backwards reference and to allow varedit modifications from ingame.
var/enabled = 1 // Set to 0 if the relay was turned off
var/dos_failure = 0 // Set to 1 if the relay failed due to (D)DoS attack
var/list/dos_sources = list() // Backwards reference for qdel() stuff
// Denial of Service attack variables
var/dos_overload = 0 // Amount of DoS "packets" in this relay's buffer
var/dos_capacity = 500 // Amount of DoS "packets" in buffer required to crash the relay
var/dos_dissipate = 1 // Amount of DoS "packets" dissipated over time.
// TODO: Implement more logic here. For now it's only a placeholder.
/obj/machinery/ntnet_relay/is_operational()
if(stat & (BROKEN | NOPOWER | EMPED))
return 0
if(dos_failure)
return 0
if(!enabled)
return 0
return 1
/obj/machinery/ntnet_relay/update_icon()
if(is_operational())
icon_state = "bus"
else
icon_state = "bus_off"
/obj/machinery/ntnet_relay/process()
if(is_operational())
use_power = 2
else
use_power = 1
if(dos_overload)
dos_overload = max(0, dos_overload - dos_dissipate)
// If DoS traffic exceeded capacity, crash.
if((dos_overload > dos_capacity) && !dos_failure)
dos_failure = 1
update_icon()
ntnet_global.add_log("Quantum relay switched from normal operation mode to overload recovery mode.")
// If the DoS buffer reaches 0 again, restart.
if((dos_overload == 0) && dos_failure)
dos_failure = 0
update_icon()
ntnet_global.add_log("Quantum relay switched from overload recovery mode to normal operation mode.")
..()
/obj/machinery/ntnet_relay/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "ntnet_relay", "NTNet Quantum Relay", 500, 300, master_ui, state)
ui.open()
/obj/machinery/ntnet_relay/ui_data(mob/user)
var/list/data = list()
data["enabled"] = enabled
data["dos_capacity"] = dos_capacity
data["dos_overload"] = dos_overload
data["dos_crashed"] = dos_failure
return data
/obj/machinery/ntnet_relay/ui_act(action, params)
if(..())
return
switch(action)
if("restart")
dos_overload = 0
dos_failure = 0
update_icon()
ntnet_global.add_log("Quantum relay manually restarted from overload recovery mode to normal operation mode.")
if("toggle")
enabled = !enabled
ntnet_global.add_log("Quantum relay manually [enabled ? "enabled" : "disabled"].")
update_icon()
/obj/machinery/ntnet_relay/attack_hand(mob/living/user)
ui_interact(user)
/obj/machinery/ntnet_relay/New()
uid = gl_uid
gl_uid++
component_parts = list()
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/ntnet_relay(null)
B.apply_default_parts(src)
if(ntnet_global)
ntnet_global.relays.Add(src)
NTNet = ntnet_global
ntnet_global.add_log("New quantum relay activated. Current amount of linked relays: [NTNet.relays.len]")
..()
/obj/machinery/ntnet_relay/Destroy()
if(ntnet_global)
ntnet_global.relays.Remove(src)
ntnet_global.add_log("Quantum relay connection severed. Current amount of linked relays: [NTNet.relays.len]")
NTNet = null
for(var/datum/computer_file/program/ntnet_dos/D in dos_sources)
D.target = null
D.error = "Connection to quantum relay severed"
..()
/obj/item/weapon/circuitboard/machine/ntnet_relay
name = "circuit board (NTNet Relay)"
build_path = /obj/machinery/ntnet_relay
origin_tech = "programming=3;bluespace=3;magnets=2"
req_components = list(
/obj/item/stack/cable_coil = 2,
/obj/item/weapon/stock_parts/subspace/filter = 1)
@@ -0,0 +1,704 @@
// This is the base type that does all the hardware stuff.
// Other types expand it - tablets use a direct subtypes, and
// consoles and laptops use "procssor" item that is held inside machinery piece
/obj/item/modular_computer
name = "Modular 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.
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
var/last_battery_percent = 0 // Used for deciding if battery percentage has chandged
var/last_world_time = "00:00"
var/list/last_header_icons
var/computer_emagged = 0 // Whether the computer is emagged.
var/base_active_power_usage = 50 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
var/base_idle_power_usage = 5 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
// Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..)
// must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently
// If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example.
icon = 'icons/obj/computer.dmi'
icon_state = "laptop-open"
var/icon_state_unpowered = null // Icon state when the computer is turned off
var/icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
var/max_hardware_size = 0 // Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed.
var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
// Damage of the chassis. If the chassis takes too much damage it will break apart.
var/damage = 0 // Current damage level
var/broken_damage = 50 // Damage level at which the computer ceases to operate
var/max_damage = 100 // Damage level at which the computer breaks apart.
// Important hardware (must be installed for computer to work)
var/obj/item/weapon/computer_hardware/processor_unit/processor_unit // CPU. Without it the computer won't run. Better CPUs can run more programs at once.
var/obj/item/weapon/computer_hardware/network_card/network_card // Network Card component of this computer. Allows connection to NTNet
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive // Hard Drive component of this computer. Stores programs and files.
var/obj/item/weapon/computer_hardware/battery_module/battery_module // An internal power source for this computer. Can be recharged.
// Optional hardware (improves functionality, but is not critical for computer to work)
var/obj/item/weapon/computer_hardware/card_slot/card_slot // ID Card slot component of this computer. Mostly for HoP modification console that needs ID slot for modification.
var/obj/item/weapon/computer_hardware/card_slot/card_slot2 // second slot. popular demand requested the hop need to insert 2 ids.
var/obj/item/weapon/computer_hardware/nano_printer/nano_printer // Nano Printer component of this computer, for your everyday paperwork needs.
var/obj/item/weapon/computer_hardware/hard_drive/portable/portable_drive // Portable data storage
var/list/idle_threads = list() // Idle programs on background. They still receive process calls but can't be interacted with.
var/obj/physical = null
// Eject ID card from computer, if it has ID slot with card inside.
/obj/item/modular_computer/verb/eject_id()
set name = "Eject ID"
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>"
return
if(!Adjacent(usr))
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 category = "Object"
set src in view(1)
if(usr.incapacitated() || !istype(usr, /mob/living))
usr << "<span class='warning'>You can't do that.</span>"
return
if(!Adjacent(usr))
usr << "<span class='warning'>You can't reach it.</span>"
return
proc_eject_usb(usr)
/obj/item/modular_computer/proc/proc_eject_id(mob/user, slot)
if(!user)
user = usr
if(!card_slot)
user << "\The [src] does not have an ID card slot"
return
if(!card_slot.stored_card && !card_slot.stored_card2)
user << "There is no card in \the [src]"
return
if(active_program)
active_program.event_idremoved(0, slot)
for(var/I in idle_threads)
var/datum/computer_file/program/P = I
P.event_idremoved(1, slot)
if(card_slot.stored_card && (!slot || slot == 1))
card_slot.stored_card.forceMove(get_turf(src))
card_slot.stored_card = null
if(card_slot.stored_card2 && (!slot || slot == 2))
card_slot.stored_card2.forceMove(get_turf(src))
card_slot.stored_card2 = null
user << "You remove the card[card_slot.stored_card && card_slot.stored_card2 && !slot ? "s" : ""] 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]."
return
uninstall_component(user, portable_drive)
/obj/item/modular_computer/attack_ghost(mob/dead/observer/user)
if(enabled)
ui_interact(user)
else if(check_rights_for(user.client, R_ADMIN))
var/response = alert(user, "This computer is turned off. Would you like to turn it on?", "Admin Override", "Yes", "No")
if(response == "Yes")
turn_on(user)
/obj/item/modular_computer/emag_act(mob/user)
if(computer_emagged)
user << "\The [src] was already emagged."
return 0
else
computer_emagged = 1
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(mob/user)
..()
if(damage > broken_damage)
user << "<span class='danger'>It is heavily damaged!</span>"
else if(damage)
user << "It is damaged."
/obj/item/modular_computer/New()
START_PROCESSING(SSmachine, src)
update_icon()
if(!physical)
physical = src
..()
/obj/item/modular_computer/Destroy()
kill_program(1)
STOP_PROCESSING(SSmachine, src)
for(var/H in get_all_components())
var/obj/item/weapon/computer_hardware/CH = H
uninstall_component(null, CH)
qdel(CH)
return ..()
/obj/item/modular_computer/update_icon()
icon_state = icon_state_unpowered
cut_overlays()
if(!enabled)
return
if(active_program)
add_overlay(active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu)
else
add_overlay(icon_state_menu)
// Used by child types if they have other power source than battery
/obj/item/modular_computer/proc/check_power_override()
return 0
// Operates NanoUI
/obj/item/modular_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
if(!screen_on || !enabled)
if(ui)
ui.close()
return 0
if((!battery_module || !battery_module.battery.charge) && !check_power_override())
if(ui)
ui.close()
return 0
// If we have an active program switch to it now.
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)
return
// We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it.
// This screen simply lists available programs and user may select them.
if(!hard_drive || !hard_drive.stored_files || !hard_drive.stored_files.len)
physical.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.
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "computer_main", "NTOS Main menu", 400, 500, master_ui, state)
ui.open()
ui.set_autoupdate(state = 1)
/obj/item/modular_computer/ui_data(mob/user)
var/list/data = get_header_data()
data["programs"] = list()
for(var/datum/computer_file/program/P in hard_drive.stored_files)
var/running = 0
if(P in idle_threads)
running = 1
data["programs"] += list(list("name" = P.filename, "desc" = P.filedesc, "running" = running))
return data
// On-click handling. Turns on the computer if it's off and opens the GUI.
/obj/item/modular_computer/attack_self(mob/user)
if(enabled)
ui_interact(user)
else
turn_on(user)
/obj/item/modular_computer/proc/break_apart()
physical.visible_message("\The [src] breaks apart!")
var/turf/newloc = get_turf(src)
new /obj/item/stack/sheet/metal(newloc, round(steel_sheet_cost/2))
for(var/C in get_all_components())
var/obj/item/weapon/computer_hardware/H = C
uninstall_component(null, H)
H.forceMove(newloc)
if(prob(25))
H.take_damage(rand(10,30))
relay_qdel()
qdel()
/obj/item/modular_computer/proc/turn_on(mob/user)
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."
else
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"
else
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"
else
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()
if(!enabled) // The computer is turned off
last_power_usage = 0
return 0
if(damage > broken_damage)
shutdown_computer()
return 0
if(active_program && active_program.requires_ntnet && !get_ntnet_status(active_program.requires_ntnet_feature)) // Active program requires NTNet to run but we've just lost connection. Crash.
active_program.event_networkfailure(0)
for(var/I in idle_threads)
var/datum/computer_file/program/P = I
if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature))
P.event_networkfailure(1)
if(active_program)
if(active_program.program_state != PROGRAM_STATE_KILLED)
active_program.process_tick()
active_program.ntnet_status = get_ntnet_status()
active_program.computer_emagged = computer_emagged
else
active_program = null
for(var/I in idle_threads)
var/datum/computer_file/program/P = I
if(P.program_state != PROGRAM_STATE_KILLED)
P.process_tick()
P.ntnet_status = get_ntnet_status()
P.computer_emagged = computer_emagged
else
idle_threads.Remove(P)
handle_power() // Handles all computer power interaction
//check_update_ui_need()
// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_"
/obj/item/modular_computer/proc/get_header_data()
var/list/data = list()
if(battery_module)
switch(battery_module.battery.percent())
if(80 to 200) // 100 should be maximal but just in case..
data["PC_batteryicon"] = "batt_100.gif"
if(60 to 80)
data["PC_batteryicon"] = "batt_80.gif"
if(40 to 60)
data["PC_batteryicon"] = "batt_60.gif"
if(20 to 40)
data["PC_batteryicon"] = "batt_40.gif"
if(5 to 20)
data["PC_batteryicon"] = "batt_20.gif"
else
data["PC_batteryicon"] = "batt_5.gif"
data["PC_batterypercent"] = "[round(battery_module.battery.percent())] %"
data["PC_showbatteryicon"] = 1
else
data["PC_batteryicon"] = "batt_5.gif"
data["PC_batterypercent"] = "N/C"
data["PC_showbatteryicon"] = battery_module ? 1 : 0
switch(get_ntnet_status())
if(0)
data["PC_ntneticon"] = "sig_none.gif"
if(1)
data["PC_ntneticon"] = "sig_low.gif"
if(2)
data["PC_ntneticon"] = "sig_high.gif"
if(3)
data["PC_ntneticon"] = "sig_lan.gif"
if(idle_threads.len)
var/list/program_headers = list()
for(var/I in idle_threads)
var/datum/computer_file/program/P = I
if(!P.ui_header)
continue
program_headers.Add(list(list(
"icon" = P.ui_header
)))
data["PC_programheaders"] = program_headers
data["PC_stationtime"] = worldtime2text()
data["PC_hasheader"] = 1
data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen
return data
// Relays kill program request to currently active program. Use this to quit current program.
/obj/item/modular_computer/proc/kill_program(forced = 0)
if(active_program)
active_program.kill_program(forced)
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.
update_icon()
// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on)
/obj/item/modular_computer/proc/get_ntnet_status(specific_action = 0)
if(network_card)
return network_card.get_signal(specific_action)
else
return 0
/obj/item/modular_computer/proc/add_log(text)
if(!get_ntnet_status())
return 0
return ntnet_global.add_log(text, network_card)
/obj/item/modular_computer/proc/shutdown_computer(loud = 1)
kill_program(1)
for(var/datum/computer_file/program/P in idle_threads)
P.kill_program(1)
idle_threads.Remove(P)
if(loud)
physical.visible_message("\The [src] shuts down.")
enabled = 0
update_icon()
return
// Handles user's GUI input
/obj/item/modular_computer/ui_act(action, params)
if(..())
return
switch(action)
if("PC_exit")
kill_program()
return 1
if("PC_shutdown")
shutdown_computer()
return 1
if("PC_minimize")
var/mob/user = usr
if(!active_program || !processor_unit)
return
idle_threads.Add(active_program)
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
active_program = null
update_icon()
if(user && istype(user))
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
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(!istype(P) || P.program_state == PROGRAM_STATE_KILLED)
return
P.kill_program(1)
user << "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>"
if("PC_runprogram")
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(!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>"
return
P.computer = src
if(!P.is_supported_by_hardware(hardware_flag, 1, user))
return
// The program is already running. Resume it.
if(P in idle_threads)
P.program_state = PROGRAM_STATE_ACTIVE
active_program = P
idle_threads.Remove(P)
update_icon()
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>"
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>"
return
P.computer_emagged = computer_emagged
if(P.run_program(user))
active_program = P
update_icon()
return 1
else
return
// Used in following function to reduce copypaste
/obj/item/modular_computer/proc/power_failure(malfunction = 0)
if(enabled) // Shut down the computer
physical.visible_message("<span class='danger'>\The [src]'s screen flickers \"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\" warning as it shuts down unexpectedly.</span>")
if(active_program)
active_program.event_powerfailure(0)
for(var/I in idle_threads)
var/datum/computer_file/program/PRG = I
PRG.event_powerfailure(1)
shutdown_computer(0)
// Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged
/obj/item/modular_computer/proc/handle_power()
if(!battery_module || battery_module.battery.charge <= 0) // Battery-run but battery is depleted.
power_failure()
return 0
var/power_usage = screen_on ? base_active_power_usage : base_idle_power_usage
for(var/obj/item/weapon/computer_hardware/H in get_all_components())
if(H.enabled)
power_usage += H.power_usage
if(battery_module)
if(!battery_module.check_functionality())
power_failure(1)
return
if(!battery_module.battery.use(power_usage * CELLRATE))
battery_module.battery.charge = 0
power_failure()
return 0
last_power_usage = power_usage
/obj/item/modular_computer/attackby(obj/item/weapon/W as obj, mob/user as mob)
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."
return
if(card_slot.stored_card && card_slot.stored_card2)
user << "You try to insert \the [I] into \the [src], but it's ID card slots are occupied."
return
if(!user.drop_item(I))
return
if(!card_slot.stored_card)
card_slot.stored_card = I
else
card_slot.stored_card2 = I
I.forceMove(src)
// update_uis()
user << "You insert \the [I] into \the [src]."
return
if(istype(W, /obj/item/weapon/paper))
if(!nano_printer)
return
nano_printer.attackby(W, user)
if(istype(W, /obj/item/weapon/computer_hardware))
var/obj/item/weapon/computer_hardware/C = W
if(C.hardware_size <= max_hardware_size)
C.try_install_component(user, src)
else
user << "This component is too large for \the [src]."
if(istype(W, /obj/item/weapon/wrench))
var/list/components = get_all_components()
if(components.len)
user << "Remove all components from \the [src] before disassembling it."
return
new /obj/item/stack/sheet/metal( get_turf(src.loc), steel_sheet_cost )
physical.visible_message("\The [src] has been disassembled by [user].")
relay_qdel()
qdel(src)
return
if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(!WT.isOn())
user << "\The [W] is off."
return
if(!damage)
user << "\The [src] does not require repairs."
return
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]."
return
if(istype(W, /obj/item/weapon/screwdriver))
var/list/all_components = get_all_components()
if(!all_components.len)
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)
component_names.Add(H.name)
var/choice = input(usr, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in component_names
if(!choice)
return
if(!Adjacent(usr))
return
var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(choice)
if(!H)
return
uninstall_component(user, H)
return
..()
// Used by processor to relay qdel() to machinery type.
/obj/item/modular_computer/proc/relay_qdel()
return
// Uninstalls component. Found and Critical vars may be passed by parent types, if they have additional hardware.
/obj/item/modular_computer/proc/uninstall_component(mob/living/user, obj/item/weapon/computer_hardware/H, found = 0, critical = 0)
if(portable_drive == H)
portable_drive = null
found = 1
if(hard_drive == H)
hard_drive = null
found = 1
critical = 1
if(network_card == H)
network_card = null
found = 1
if(nano_printer == H)
nano_printer = null
found = 1
if(card_slot == H)
card_slot = null
found = 1
if(battery_module == H)
battery_module = null
found = 1
if(processor_unit == H)
processor_unit = null
found = 1
critical = 1
if(found)
if(user)
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>"
shutdown_computer()
update_icon()
// Checks all hardware pieces to determine if name matches, if yes, returns the hardware piece, otherwise returns null
/obj/item/modular_computer/proc/find_hardware_by_name(name)
if(portable_drive && (portable_drive.name == name))
return portable_drive
if(hard_drive && (hard_drive.name == name))
return hard_drive
if(network_card && (network_card.name == name))
return network_card
if(nano_printer && (nano_printer.name == name))
return nano_printer
if(card_slot && (card_slot.name == name))
return card_slot
if(battery_module && (battery_module.name == name))
return battery_module
if(processor_unit && (processor_unit.name == name))
return processor_unit
return null
// Returns list of all components
/obj/item/modular_computer/proc/get_all_components()
var/list/all_components = list()
if(hard_drive)
all_components.Add(hard_drive)
if(network_card)
all_components.Add(network_card)
if(portable_drive)
all_components.Add(portable_drive)
if(nano_printer)
all_components.Add(nano_printer)
if(card_slot)
all_components.Add(card_slot)
if(battery_module)
all_components.Add(battery_module)
if(processor_unit)
all_components.Add(processor_unit)
return all_components
/obj/item/modular_computer/proc/take_damage(amount, component_probability, damage_casing = 1, randomize = 1)
if(randomize)
// 75%-125%, rand() works with integers, apparently.
amount *= (rand(75, 125) / 100.0)
amount = round(amount)
if(damage_casing)
damage += amount
damage = max(0,min(max_damage,damage))
if(component_probability)
for(var/I in get_all_components())
var/obj/item/weapon/computer_hardware/H = I
if(prob(component_probability))
H.take_damage(round(amount / 2))
if(damage >= max_damage)
break_apart()
// Stronger explosions cause serious damage to internal components
// Minor explosions are mostly mitigitated by casing.
/obj/item/modular_computer/ex_act(severity)
take_damage(rand(100,200) / severity, 30 / severity)
// EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components
/obj/item/modular_computer/emp_act(severity)
take_damage(rand(100,200) / severity, 50 / severity, 0)
// "Stun" weapons can cause minor damage to components (short-circuits?)
// "Burn" damage is equally strong against internal components and exterior casing
// "Brute" damage mostly damages the casing.
/obj/item/modular_computer/bullet_act(obj/item/projectile/Proj)
switch(Proj.damage_type)
if(BRUTE)
take_damage(Proj.damage, Proj.damage / 2)
if(BURN)
take_damage(Proj.damage, Proj.damage / 1.5)
/obj/item/modular_computer/ui_host()
if(physical)
return physical
else
return src
@@ -0,0 +1,119 @@
// Held by /obj/machinery/modular_computer to reduce amount of copy-pasted code.
/obj/item/modular_computer/processor
name = "processing unit"
desc = "You shouldn't see this. If you do, report it."
icon = null
icon_state = null
icon_state_unpowered = null
icon_state_menu = null
hardware_flag = 0
var/obj/machinery/modular_computer/machinery_computer = null
/obj/item/modular_computer/processor/Destroy()
. = ..()
if(machinery_computer && (machinery_computer.cpu == src))
machinery_computer.cpu = null
machinery_computer = null
// Due to how processes work, we'd receive two process calls - one from machinery type and one from our own type.
// Since we want this to be in-sync with machinery (as it's hidden type for machinery-based computers) we'll ignore
// non-relayed process calls.
/obj/item/modular_computer/processor/process(relayed = 0)
if(relayed)
..()
else
return
/obj/item/modular_computer/processor/examine(var/mob/user)
if(damage > broken_damage)
user << "<span class='danger'>It is heavily damaged!</span>"
else if(damage)
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()
if(machinery_computer)
machinery_computer.handle_power()
/obj/item/modular_computer/processor/New(comp)
if(!comp || !istype(comp, /obj/machinery/modular_computer))
CRASH("Inapropriate type passed to obj/item/modular_computer/processor/New()! Aborting.")
return
// Obtain reference to machinery computer
machinery_computer = comp
machinery_computer.cpu = src
hardware_flag = machinery_computer.hardware_flag
max_hardware_size = machinery_computer.max_hardware_size
steel_sheet_cost = machinery_computer.steel_sheet_cost
max_damage = machinery_computer._max_damage
broken_damage = machinery_computer._break_damage
/obj/item/modular_computer/processor/relay_qdel()
qdel(machinery_computer)
/obj/item/modular_computer/processor/find_hardware_by_name(N)
var/obj/item/weapon/computer_hardware/H = machinery_computer.find_hardware_by_name(N)
if(H)
return H
else
return ..()
/obj/item/modular_computer/processor/update_icon()
if(machinery_computer)
return machinery_computer.update_icon()
/obj/item/modular_computer/processor/get_header_data()
var/list/L = ..()
if(machinery_computer.tesla_link && machinery_computer.tesla_link.enabled && machinery_computer.powered())
L["PC_apclinkicon"] = "charging.gif"
return L
// Checks whether the machinery computer doesn't take power from APC network
/obj/item/modular_computer/processor/check_power_override()
if(!machinery_computer)
return 0
if(!machinery_computer.tesla_link || !machinery_computer.tesla_link.enabled)
return 0
return machinery_computer.powered()
// This thing is not meant to be used on it's own, get topic data from our machinery owner.
//obj/item/modular_computer/processor/canUseTopic(user, state)
// if(!machinery_computer)
// return 0
// return machinery_computer.canUseTopic(user, state)
/obj/item/modular_computer/processor/shutdown_computer()
if(!machinery_computer)
return
..()
machinery_computer.update_icon()
machinery_computer.use_power = 0
return
/obj/item/modular_computer/processor/uninstall_component(mob/living/user, obj/item/weapon/computer_hardware/H, found = 0, critical = 0)
if(machinery_computer.tesla_link == H)
machinery_computer.tesla_link = null
var/obj/item/weapon/computer_hardware/tesla_link/L = H
L.holder = null
found = 1
..(user, H, found, critical)
/obj/item/modular_computer/processor/get_all_components()
var/list/all_components = ..()
if(machinery_computer && machinery_computer.tesla_link)
all_components.Add(machinery_computer.tesla_link)
return all_components
// Perform adjacency checks on our machinery counterpart, rather than on ourselves.
/obj/item/modular_computer/processor/Adjacent(atom/neighbor)
if(!machinery_computer)
return 0
return machinery_computer.Adjacent(neighbor)
/obj/item/modular_computer/processor/turn_on(mob/user)
// 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
..()
@@ -0,0 +1,10 @@
/obj/item/modular_computer/tablet
name = "tablet computer"
icon = 'icons/obj/modular_tablet.dmi'
icon_state = "tablet"
icon_state_unpowered = "tablet"
icon_state_menu = "menu"
hardware_flag = PROGRAM_TABLET
max_hardware_size = 1
w_class = 2
var/use_power = 0
@@ -0,0 +1,21 @@
// Available as custom loadout item, this is literally the worst possible cheap tablet
/obj/item/modular_computer/tablet/preset/cheap/New()
. = ..()
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/micro(src)
battery_module.charge_to_full()
hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/micro(src)
network_card = new/obj/item/weapon/computer_hardware/network_card(src)
// Alternative version, an average one, for higher ranked positions mostly
/obj/item/modular_computer/tablet/preset/advanced/New()
. = ..()
processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src)
battery_module = new/obj/item/weapon/computer_hardware/battery_module(src)
battery_module.charge_to_full()
hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/small(src)
network_card = new/obj/item/weapon/computer_hardware/network_card(src)
nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src)
card_slot = new/obj/item/weapon/computer_hardware/card_slot(src)
@@ -0,0 +1,65 @@
/obj/machinery/modular_computer/console/preset/
// Can be changed to give devices specific hardware
var/_has_id_slot = 0
var/_has_printer = 0
var/_has_battery = 0
/obj/machinery/modular_computer/console/preset/New()
. = ..()
if(!cpu)
return
cpu.processor_unit = new/obj/item/weapon/computer_hardware/processor_unit(cpu)
if(_has_id_slot)
cpu.card_slot = new/obj/item/weapon/computer_hardware/card_slot(cpu)
if(_has_printer)
cpu.nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(cpu)
if(_has_battery)
cpu.battery_module = new/obj/item/weapon/computer_hardware/battery_module/super(cpu)
install_programs()
// Override in child types to install preset-specific programs.
/obj/machinery/modular_computer/console/preset/proc/install_programs()
return
// ===== ENGINEERING CONSOLE =====
/obj/machinery/modular_computer/console/preset/engineering
console_department = "Engineering"
desc = "A stationary computer. This one comes preloaded with engineering programs."
/obj/machinery/modular_computer/console/preset/engineering/install_programs()
cpu.hard_drive.store_file(new/datum/computer_file/program/power_monitor())
cpu.hard_drive.store_file(new/datum/computer_file/program/alarm_monitor())
// ===== RESEARCH CONSOLE =====
/obj/machinery/modular_computer/console/preset/research
console_department = "Research"
desc = "A stationary computer. This one comes preloaded with research programs."
/obj/machinery/modular_computer/console/preset/research/install_programs()
cpu.hard_drive.store_file(new/datum/computer_file/program/ntnetmonitor())
cpu.hard_drive.store_file(new/datum/computer_file/program/nttransfer())
cpu.hard_drive.store_file(new/datum/computer_file/program/chatclient())
// ===== COMMAND CONSOLE =====
/obj/machinery/modular_computer/console/preset/command
console_department = "Command"
desc = "A stationary computer. This one comes preloaded with command programs."
_has_id_slot = 1
_has_printer = 1
/obj/machinery/modular_computer/console/preset/command/install_programs()
cpu.hard_drive.store_file(new/datum/computer_file/program/chatclient())
cpu.hard_drive.store_file(new/datum/computer_file/program/card_mod())
// ===== CIVILIAN CONSOLE =====
/obj/machinery/modular_computer/console/preset/civilian
console_department = "Civilian"
desc = "A stationary computer. This one comes preloaded with generic programs."
/obj/machinery/modular_computer/console/preset/civilian/install_programs()
cpu.hard_drive.store_file(new/datum/computer_file/program/chatclient())
cpu.hard_drive.store_file(new/datum/computer_file/program/nttransfer())
@@ -0,0 +1,207 @@
// 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."
var/battery_powered = 0 // Whether computer should be battery powered. It is set automatically
use_power = 0
var/hardware_flag = 0 // A flag that describes this device type
var/last_power_usage = 0 // Power usage during last tick
// Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..)
// must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently
// If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example.
icon = null
icon_state = null
var/icon_state_unpowered = null // Icon state when the computer is turned off
var/screen_icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
var/screen_icon_screensaver = "standby" // Icon state overlay when the computer is powered, but not 'switched on'.
var/max_hardware_size = 0 // Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed.
var/steel_sheet_cost = 10 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
var/light_strength = 0 // Light luminosity when turned on
var/base_active_power_usage = 100 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
var/base_idle_power_usage = 10 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
var/_max_damage = 100
var/_break_damage = 50
var/obj/item/weapon/computer_hardware/tesla_link/tesla_link // Tesla Link component of this computer. Allows remote charging from nearest APC.
var/obj/item/modular_computer/processor/cpu = null // CPU that handles most logic while this type only handles power and other specific things.
/obj/machinery/modular_computer/attack_ghost(mob/dead/observer/user)
if(cpu)
cpu.attack_ghost(user)
/obj/machinery/modular_computer/emag_act(mob/user)
return cpu ? cpu.emag_act(user) : 1
/obj/machinery/modular_computer/update_icon()
icon_state = icon_state_unpowered
cut_overlays()
if(!cpu || !cpu.enabled)
if (!(stat & NOPOWER) || battery_powered)
add_overlay(screen_icon_screensaver)
SetLuminosity(0)
return
SetLuminosity(light_strength)
if(cpu.active_program)
add_overlay(cpu.active_program.program_icon_state ? cpu.active_program.program_icon_state : screen_icon_state_menu)
else
overlays.Add(screen_icon_state_menu)
// Eject ID card from computer, if it has ID slot with card inside.
/obj/machinery/modular_computer/verb/eject_id()
set name = "Eject ID"
set category = "Object"
set src in view(1)
if(cpu)
cpu.eject_id()
// 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 category = "Object"
set src in view(1)
if(cpu)
cpu.eject_usb()
/obj/machinery/modular_computer/New()
..()
cpu = new(src)
cpu.physical = src
global_modular_computers.Add(src)
/obj/machinery/modular_computer/Destroy()
if(cpu)
qdel(cpu)
cpu = null
return ..()
// On-click handling. Turns on the computer if it's off and opens the GUI.
/obj/machinery/modular_computer/attack_hand(mob/user)
if(cpu)
cpu.attack_self(user) // CPU is an item, that's why we route attack_hand to attack_self
/obj/machinery/modular_computer/examine(mob/user)
. = ..()
if(cpu)
cpu.examine(user)
// Process currently calls handle_power(), may be expanded in future if more things are added.
/obj/machinery/modular_computer/process()
if(cpu)
// Keep names in sync.
cpu.name = src.name
cpu.process(1)
// Checks all hardware pieces to determine if name matches, if yes, returns the hardware piece, otherwise returns null
/obj/machinery/modular_computer/proc/find_hardware_by_name(N)
if(tesla_link && (tesla_link.name == N))
return tesla_link
return null
// Used in following function to reduce copypaste
/obj/machinery/modular_computer/proc/power_failure(malfunction = 0)
if(cpu && cpu.enabled) // Shut down the computer
visible_message("<span class='danger'>\The [src]'s screen flickers [cpu.battery_module ? "\"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\"" : "\"EXTERNAL POWER LOSS\""] warning as it shuts down unexpectedly.</span>")
if(cpu)
cpu.shutdown_computer(0)
battery_powered = 0
stat |= NOPOWER
update_icon()
// Called by cpu item's process() automatically, handles our power interaction.
/obj/machinery/modular_computer/proc/handle_power()
if(!check_external_power())
if(cpu.battery_module && cpu.battery_module.battery.charge <= 0)// Battery-run but battery is depleted.
power_failure()
return 0
else if(!cpu.battery_module) // Not battery run, but lacking APC connection.
power_failure()
return 0
else if(stat & NOPOWER)
stat &= ~NOPOWER
if(cpu.battery_module && cpu.battery_module.battery.charge)
battery_powered = 1
else
battery_powered = 0
var/power_usage = cpu.screen_on ? base_active_power_usage : base_idle_power_usage
for(var/C in src.cpu.get_all_components())
var/obj/item/weapon/computer_hardware/CH = C
if(CH.enabled)
power_usage += CH.power_usage
// Wireless APC connection exists.
if(tesla_link && tesla_link.enabled && tesla_link.check_functionality())
idle_power_usage = power_usage
active_power_usage = idle_power_usage + 100 // APCLink only charges at 100W rate, but covers any power usage.
use_power = 1
// Battery is not fully charged. Begin slowly recharging.
if(cpu.battery_module && (cpu.battery_module.battery.charge < cpu.battery_module.battery.maxcharge))
use_power = 2
if(cpu.battery_module && powered() && (use_power == 2)) // Battery charging itself
cpu.battery_module.battery.give(100 * CELLRATE)
else if(cpu.battery_module && !powered()) // Unpowered, but battery covers the usage.
if(!cpu.battery_module.battery.use(idle_power_usage * CELLRATE))
cpu.battery_module.battery.charge = 0
power_failure()
else // No wireless connection run only on battery.
use_power = 0
if (cpu.battery_module)
if(!cpu.battery_module.check_functionality())
power_failure(1)
return
if(!cpu.battery_module.battery.use(power_usage * CELLRATE))
cpu.battery_module.battery.charge = 0
power_failure()
cpu.last_power_usage = power_usage
// Modular computers can have battery in them, we handle power in previous proc, so prevent this from messing it up for us.
/obj/machinery/modular_computer/power_change()
if(battery_powered)
return
..()
/obj/machinery/modular_computer/attackby(var/obj/item/weapon/W as obj, mob/user)
if(cpu)
return cpu.attackby(W, user)
return ..()
// Stronger explosions cause serious damage to internal components
// Minor explosions are mostly mitigitated by casing.
/obj/machinery/modular_computer/ex_act(severity)
if(cpu)
cpu.ex_act(severity)
// EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components
/obj/machinery/modular_computer/emp_act(severity)
if(cpu)
cpu.emp_act(severity)
// "Stun" weapons can cause minor damage to components (short-circuits?)
// "Burn" damage is equally strong against internal components and exterior casing
// "Brute" damage mostly damages the casing.
/obj/machinery/modular_computer/bullet_act(obj/item/projectile/Proj)
if(cpu)
cpu.bullet_act(Proj)
/obj/machinery/modular_computer/proc/check_external_power()
if((!powered() || !tesla_link || !tesla_link.enabled || !tesla_link.check_functionality()))
return 0
else
return 1
@@ -0,0 +1,46 @@
/obj/machinery/modular_computer/console/
name = "console"
desc = "A stationary computer."
icon = 'icons/obj/modular_console.dmi'
icon_state = "console"
icon_state_unpowered = "console"
screen_icon_state_menu = "menu"
hardware_flag = PROGRAM_CONSOLE
var/console_department = "" // Used in New() to set network tag according to our area.
anchored = 1
density = 1
base_idle_power_usage = 100
base_active_power_usage = 500
max_hardware_size = 3
steel_sheet_cost = 20
light_strength = 2
_max_damage = 300
_break_damage = 150
/obj/machinery/modular_computer/console/buildable/New()
..()
// User-built consoles start as empty frames.
qdel(tesla_link)
qdel(cpu.network_card)
qdel(cpu.hard_drive)
/obj/machinery/modular_computer/console/New()
..()
cpu.battery_module = null
cpu.network_card = new/obj/item/weapon/computer_hardware/network_card/wired(src)
tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src)
cpu.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/super(src) // Consoles generally have better HDDs due to lower space limitations
var/area/A = get_area(src)
// Attempts to set this console's tag according to our area. Since some areas have stuff like "XX - YY" in their names we try to remove that too.
if(A && console_department)
cpu.network_card.identification_string = replacetext(replacetext(replacetext("[A.name] [console_department] Console", " ", "_"), "-", ""), "__", "_") // Replace spaces with "_"
else if(A)
cpu.network_card.identification_string = replacetext(replacetext(replacetext("[A.name] Console", " ", "_"), "-", ""), "__", "_")
else if(console_department)
cpu.network_card.identification_string = replacetext(replacetext(replacetext("[console_department] Console", " ", "_"), "-", ""), "__", "_")
else
cpu.network_card.identification_string = "Unknown Console"
if(cpu)
cpu.screen_on = 1
update_icon()
@@ -0,0 +1,110 @@
// Laptop in it's item state, can be carried around.
/obj/item/laptop
name = "laptop computer"
desc = "A portable computer. It is closed."
icon = 'icons/obj/modular_laptop.dmi'
icon_state = "laptop-closed"
item_state = "laptop-inhand"
w_class = 3
var/obj/machinery/modular_computer/laptop/stored_computer = null
/obj/item/laptop/verb/open_computer()
set name = "Open Laptop"
set category = "Object"
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>"
return
if(!Adjacent(usr))
usr << "You can't reach it."
return
if(!istype(loc,/turf))
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."
spawn(5)
qdel(src)
return
stored_computer.forceMove(src.loc)
stored_computer.stat &= ~MAINT
stored_computer.update_icon()
if(stored_computer.cpu)
stored_computer.cpu.screen_on = 1
loc = stored_computer
usr << "You open \the [src]."
/obj/item/laptop/AltClick()
if(Adjacent(usr))
open_computer()
// The actual laptop
/obj/machinery/modular_computer/laptop
name = "laptop 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
icon = 'icons/obj/modular_laptop.dmi'
icon_state = "laptop-open"
base_idle_power_usage = 25
base_active_power_usage = 200
max_hardware_size = 2
light_strength = 3
_max_damage = 200
_break_damage = 100
/obj/machinery/modular_computer/laptop/buildable/New()
..()
// User-built consoles start as empty frames.
qdel(tesla_link)
qdel(cpu.network_card)
qdel(cpu.hard_drive)
// Close the computer. collapsing it into movable item that can't be used.
/obj/machinery/modular_computer/laptop/verb/close_computer()
set name = "Close Laptop"
set category = "Object"
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>"
return
if(!Adjacent(usr))
usr << "<span class='warning'>You can't reach it.</span>"
return
close_laptop(usr)
/obj/machinery/modular_computer/laptop/proc/close_laptop(mob/user = null)
if(istype(loc,/obj/item/laptop))
return
if(!istype(loc,/turf))
return
if(!portable)
portable=new
portable.stored_computer = src
portable.forceMove(src.loc)
src.forceMove(portable)
stat |= MAINT
if(user)
user << "You close \the [src]."
if(cpu)
cpu.screen_on = 0
/obj/machinery/modular_computer/laptop/AltClick()
if(Adjacent(usr))
close_laptop()
Binary file not shown.

After

Width:  |  Height:  |  Size: 818 B

@@ -0,0 +1,39 @@
var/global/file_uid = 0
/datum/computer_file/
var/filename = "NewFile" // Placeholder. No spacebars
var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case
var/size = 1 // File size in GQ. Integers only!
var/obj/item/weapon/computer_hardware/hard_drive/holder // Holder that contains this file.
var/unsendable = 0 // Whether the file may be sent to someone via NTNet transfer or other means.
var/undeletable = 0 // Whether the file may be deleted. Setting to 1 prevents deletion/renaming/etc.
var/uid // UID of this file
/datum/computer_file/New()
..()
uid = file_uid
file_uid++
/datum/computer_file/Destroy()
if(!holder)
return ..()
holder.remove_file(src)
// holder.holder is the computer that has drive installed. If we are Destroy()ing program that's currently running kill it.
if(holder.holder2 && holder.holder2.active_program == src)
holder.holder2.kill_program(1)
holder = null
..()
// Returns independent copy of this file.
/datum/computer_file/proc/clone(rename = 0)
var/datum/computer_file/temp = new type
temp.unsendable = unsendable
temp.undeletable = undeletable
temp.size = size
if(rename)
temp.filename = filename + "(Copy)"
else
temp.filename = filename
temp.filetype = filetype
return temp
@@ -0,0 +1,20 @@
// /data/ files store data in string format.
// They don't contain other logic for now.
/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 = ..()
temp.stored_data = stored_data
return temp
// Calculates file size from amount of characters in saved string
/datum/computer_file/data/proc/calculate_size()
size = max(1, round(length(stored_data) / block_size))
/datum/computer_file/data/logfile
filetype = "LOG"
@@ -0,0 +1,190 @@
// /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/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 /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)
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(computer_emagged && !transfer) //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/mob/living/carbon/human/h = user
var/obj/item/weapon/card/id/I = h.get_idcard()
var/obj/item/weapon/card/id/C = h.get_active_hand()
if (istype(C, /obj/item/device/pda))
var/obj/item/device/pda/pda = C
C = pda.id
if(!(C && istype(C)))
C = null
if(!I && !C)
if(loud)
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(C)
if(access_to_check in C.GetAccess())
return 1
if(loud)
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 overriden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure.
// When implementing new program based device, use this to run the program.
/datum/computer_file/program/proc/run_program(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 = 0)
program_state = PROGRAM_STATE_KILLED
if(network_destination)
generate_network_log("Connection to [network_destination] closed.")
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.
/datum/computer_file/program/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists.
return computer.ui_interact(user)
return 1
// 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.processor_unit)
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,18 @@
// Events are sent to the program by the computer.
// Always include a parent call when overriding an event.
// Called when the ID card is removed from computer. ID is removed AFTER this proc.
/datum/computer_file/program/proc/event_idremoved(background, slot)
return
// Called when the computer fails due to power loss. Override when program wants to specifically react to power loss.
/datum/computer_file/program/proc/event_powerfailure(background)
kill_program(1)
// Called when the network connectivity fails. Computer does necessary checks and only calls this when requires_ntnet_feature and similar variables are not met.
/datum/computer_file/program/proc/event_networkfailure(background)
kill_program(1)
if(background)
computer.visible_message("<span class='danger'>\The [computer]'s screen displays an \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error</span>")
else
computer.visible_message("<span class='danger'>\The [computer]'s screen briefly freezes and then shows \"NETWORK ERROR - NTNet connection lost. Please retry. If problem persists contact your system administrator.\" error.</span>")
@@ -0,0 +1,106 @@
/datum/computer_file/program/alarm_monitor
filename = "alarmmonitor"
filedesc = "Alarm Monitoring"
ui_header = "alarm_green.gif"
program_icon_state = "alert-green"
extended_desc = "This program provides visual interface for station's alarm system."
requires_ntnet = 1
network_destination = "alarm monitoring network"
size = 5
var/has_alert = 0
var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
/datum/computer_file/program/alarm_monitor/process_tick()
..()
if(has_alert)
program_icon_state = "alert-red"
ui_header = "alarm_red.gif"
update_computer_icon()
else
if(!has_alert)
program_icon_state = "alert-green"
ui_header = "alarm_green.gif"
update_computer_icon()
return 1
/datum/computer_file/program/alarm_monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "station_alert_prog", "Alarm Monitoring", 300, 500, master_ui, state)
ui.open()
/datum/computer_file/program/alarm_monitor/ui_data(mob/user)
var/list/data = get_header_data()
data["alarms"] = list()
for(var/class in alarms)
data["alarms"][class] = list()
for(var/area in alarms[class])
data["alarms"][class] += area
return data
/datum/computer_file/program/alarm_monitor/proc/triggerAlarm(class, area/A, O, obj/source)
var/list/L = alarms[class]
for(var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/sources = alarm[3]
if (!(source in sources))
sources += source
return 1
var/obj/machinery/camera/C = null
var/list/CL = null
if(O && istype(O, /list))
CL = O
if (CL.len == 1)
C = CL[1]
else if(O && istype(O, /obj/machinery/camera))
C = O
L[A.name] = list(A, (C ? C : O), list(source))
update_alarm_display()
return 1
/datum/computer_file/program/alarm_monitor/proc/cancelAlarm(class, area/A, obj/origin)
var/list/L = alarms[class]
var/cleared = 0
for (var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/srcs = alarm[3]
if (origin in srcs)
srcs -= origin
if (srcs.len == 0)
cleared = 1
L -= I
update_alarm_display()
return !cleared
/datum/computer_file/program/alarm_monitor/proc/update_alarm_display()
has_alert = FALSE
for(var/cat in alarms)
var/list/L = alarms[cat]
if(L.len)
has_alert = TRUE
/datum/computer_file/program/alarm_monitor/run_program(mob/user)
. = ..(user)
alarmdisplay += src
/datum/computer_file/program/alarm_monitor/kill_program(forced = 0)
alarmdisplay -= src
..(forced)
@@ -0,0 +1,106 @@
/datum/computer_file/program/ntnet_dos
filename = "ntn_dos"
filedesc = "DoS Traffic Generator"
program_icon_state = "hostile"
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
var/obj/machinery/ntnet_relay/target = null
var/dos_speed = 0
var/error = ""
var/executed = 0
/datum/computer_file/program/ntnet_dos/process_tick()
dos_speed = 0
switch(ntnet_status)
if(1)
dos_speed = NTNETSPEED_LOWSIGNAL * 10
if(2)
dos_speed = NTNETSPEED_HIGHSIGNAL * 10
if(3)
dos_speed = NTNETSPEED_ETHERNET * 10
if(target && executed)
target.dos_overload += dos_speed
if(!target.is_operational())
target.dos_sources.Remove(src)
target = null
error = "Connection to destination relay lost."
/datum/computer_file/program/ntnet_dos/kill_program(var/forced)
if(target)
target.dos_sources.Remove(src)
target = null
executed = 0
..(forced)
/datum/computer_file/program/ntnet_dos/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
ui = new(user, src, ui_key, "ntnet_dos", "DoS Traffic Generator", 400, 250, state = state)
ui.set_style("syndicate")
ui.set_autoupdate(state = 1)
ui.open()
/datum/computer_file/program/ntnet_dos/ui_act(action, params)
if(..())
return 1
switch(action)
if("PRG_target_relay")
for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays)
if("[R.uid]" == params["targid"])
target = R
return 1
if("PRG_reset")
if(target)
target.dos_sources.Remove(src)
target = null
executed = 0
error = ""
return 1
if("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
/datum/computer_file/program/ntnet_dos/ui_data(mob/user)
if(!ntnet_global)
return
var/list/data = list()
data = get_header_data()
if(error)
data["error"] = error
else if(target && executed)
data["target"] = 1
data["speed"] = dos_speed
// 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 = target.dos_overload * 100 / target.dos_capacity
data["dos_strings"] = list()
for(var/j, j<10, j++)
var/string = ""
for(var/i, i<20, i++)
string = "[string][prob(percentage)]"
data["dos_strings"] += list(list("nums" = string))
else
data["relays"] = list()
for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays)
data["relays"] += list(list("id" = R.uid))
data["focus"] = target ? target.uid : null
return data
@@ -0,0 +1,73 @@
/datum/computer_file/program/revelation
filename = "revelation"
filedesc = "Revelation"
program_icon_state = "hostile"
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
var/armed = 0
/datum/computer_file/program/revelation/run_program(var/mob/living/user)
. = ..(user)
if(armed)
activate()
/datum/computer_file/program/revelation/proc/activate()
if(computer)
computer.visible_message("<span class='notice'>\The [computer]'s screen brightly flashes and loud electrical buzzing is heard.</span>")
computer.enabled = 0
computer.update_icon()
qdel(computer.hard_drive)
computer.take_damage(25, 10, 1, 1)
if(computer.battery_module && prob(25))
qdel(computer.battery_module)
computer.visible_message("<span class='notice'>\The [computer]'s battery explodes in rain of sparks.</span>")
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
spark_system.start()
if(istype(computer, /obj/item/modular_computer/processor))
var/obj/item/modular_computer/processor/P = computer
if(P.machinery_computer.tesla_link && prob(50))
qdel(P.machinery_computer.tesla_link)
computer.visible_message("<span class='notice'>\The [computer]'s tesla link explodes in rain of sparks.</span>")
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
spark_system.start()
/datum/computer_file/program/revelation/ui_act(action, params)
if(..())
return 1
switch(action)
if("PRG_arm")
armed = !armed
if("PRG_activate")
activate()
if("PRG_obfuscate")
var/mob/living/user = usr
var/newname = sanitize(input(user, "Enter new program name: "))
if(!newname)
return
filedesc = newname
/datum/computer_file/program/revelation/clone()
var/datum/computer_file/program/revelation/temp = ..()
temp.armed = armed
return temp
/datum/computer_file/program/revelation/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
ui = new(user, src, ui_key, "revelation", "Revelation Virus", 400, 250, state = state)
ui.set_style("syndicate")
ui.set_autoupdate(state = 1)
ui.open()
/datum/computer_file/program/revelation/ui_data(mob/user)
var/list/data = get_header_data()
data["armed"] = armed
return data
@@ -0,0 +1,471 @@
/datum/computer_file/program/card_mod
filename = "cardmod"
filedesc = "ID card modification program"
program_icon_state = "id"
extended_desc = "Program for programming employee ID cards to access parts of the station."
transfer_access = access_change_ids
requires_ntnet = 0
size = 8
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 = 60
//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",
"Chaplain")
//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/event_idremoved(background, slot)
if(slot == 2)
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 <= player_list.len * (max_relative_positions / 100)))
var/delta = (world.time / 10) - 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) - 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/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "identification_computer", "ID card modification program", 600, 700, state = state)
ui.open()
ui.set_autoupdate(state = 1)
/datum/computer_file/program/card_mod/proc/format_jobs(list/jobs)
var/obj/item/weapon/card/id/id_card = computer.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/weapon/card/id/user_id_card = null
var/mob/user = usr
var/obj/item/weapon/card/id/id_card = computer.card_slot.stored_card
var/obj/item/weapon/card/id/auth_card = computer.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()
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 && computer.nano_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(!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>"
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 ([])", worldtime2text())))
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 && computer.card_slot)
var/select = params["target"]
switch(select)
if("id")
if(id_card)
data_core.manifest_modify(id_card.registered_name, id_card.assignment)
computer.proc_eject_id(user, 1)
else
var/obj/item/I = usr.get_active_hand()
if (istype(I, /obj/item/weapon/card/id))
if(!usr.drop_item())
return
I.forceMove(computer)
computer.card_slot.stored_card = I
if("auth")
if(auth_card)
if(id_card)
data_core.manifest_modify(id_card.registered_name, id_card.assignment)
head_subordinates = null
region_access = null
authenticated = 0
minor = 0
computer.proc_eject_id(user, 2)
else
var/obj/item/I = usr.get_active_hand()
if (istype(I, /obj/item/weapon/card/id))
if(!usr.drop_item())
return
I.forceMove(computer)
computer.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)
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)
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)
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/weapon/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/weapon/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()
data["mmode"] = mod_mode
var/authed = 0
if(computer && computer.card_slot)
var/obj/item/weapon/card/id/auth_card = computer.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 ? status_open["enable"]: 0,
"status_close" = authed ? 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(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"] = !!computer.card_slot
data["have_printer"] = !!computer.nano_printer
if(!computer.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)
if(computer && computer.card_slot)
var/obj/item/weapon/card/id/id_card = computer.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(engineering_positions)
data["medical_jobs"] = format_jobs(medical_positions)
data["science_jobs"] = format_jobs(science_positions)
data["security_jobs"] = format_jobs(security_positions)
data["cargo_jobs"] = format_jobs(supply_positions)
data["civilian_jobs"] = format_jobs(civilian_positions)
data["centcom_jobs"] = format_jobs(get_all_centcom_jobs())
if(computer.card_slot.stored_card)
var/obj/item/weapon/card/id/id_card = 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), "&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 = 0)
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) - 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)
if(computer && computer.card_slot)
var/obj/item/weapon/card/id/auth_card = computer.card_slot.stored_card2
if(auth_card)
region_access = list()
if(transfer_access 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)
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,81 @@
// This is special hardware configuration program.
// It is to be used only with modular computers.
// It allows you to toggle components of your device.
/datum/computer_file/program/computerconfig
filename = "compconfig"
filedesc = "Computer Configuration Tool"
extended_desc = "This program allows configuration of computer's hardware"
program_icon_state = "generic"
unsendable = 1
undeletable = 1
size = 4
available_on_ntnet = 0
requires_ntnet = 0
var/obj/item/modular_computer/movable = null
/datum/computer_file/program/computerconfig/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "laptop_configuration", "NTOS Configuration Utility", 575, 700, state = state)
ui.open()
ui.set_autoupdate(state = 1)
/datum/computer_file/program/computerconfig/ui_data(mob/user)
movable = computer
if(!istype(movable))
movable = null
// No computer connection, we can't get data from that.
if(!movable)
return 0
var/list/data = list()
data = 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())
if(movable.battery_module)
data["battery"] = list("max" = movable.battery_module.battery.maxcharge, "charge" = round(movable.battery_module.battery.charge))
var/list/all_entries[0]
for(var/I in hardware)
var/obj/item/weapon/computer_hardware/H = I
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/computer_file/program/computerconfig/ui_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
@@ -0,0 +1,240 @@
/datum/computer_file/program/filemanager
filename = "filemanager"
filedesc = "NTOS 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
var/open_file
var/error
/datum/computer_file/program/filemanager/ui_act(action, params)
if(..())
return 1
switch(action)
if("PRG_openfile")
. = 1
open_file = params["name"]
if("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("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(params["name"])
if(!file || file.undeletable)
return 1
HDD.remove_file(file)
if("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(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
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(params["name"])
if(!F || !istype(F))
return 1
var/datum/computer_file/C = F.clone(1)
HDD.store_file(C)
if("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(params["name"])
if(!file || !istype(file))
return 1
var/newname = sanitize(input(usr, "Enter new file name:", "File rename", file.filename))
if(file && newname)
file.filename = newname
if("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
// 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|null), 16384)
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
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(parse_tags(F.stored_data)))
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
return 1
if("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(params)
if(!F || !istype(F))
return 1
var/datum/computer_file/C = F.clone(0)
RHDD.store_file(C)
if("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(params)
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, "\[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\]", "[worldtime2text()]")
t = replacetext(t, "\[date\]", "[time2text(world.realtime, "MMM DD")] [year_integer+540]")
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, "\[logo\]", "<img src = ntlogo.png>")
return t
/datum/computer_file/program/filemanager/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "file_manager", "NTOS File Manage", 575, 700, state = state)
ui.open()
ui.set_autoupdate(state = 1)
/datum/computer_file/program/filemanager/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/weapon/computer_hardware/hard_drive/HDD
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD
if(error)
data["error"] = error
if(open_file)
var/datum/computer_file/data/file
if(!computer || !computer.hard_drive)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
HDD = computer.hard_drive
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 || !computer.hard_drive)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
HDD = computer.hard_drive
RHDD = computer.portable_drive
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
@@ -0,0 +1,164 @@
/datum/computer_file/program/ntnetdownload
filename = "ntndownloader"
filedesc = "NTNet Software Download Tool"
program_icon_state = "generic"
extended_desc = "This program allows downloads of software from official NT repositories"
unsendable = 1
undeletable = 1
size = 4
requires_ntnet = 1
requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD
available_on_ntnet = 0
ui_header = "downloader_finished.gif"
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
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(filename)
if(downloaded_file)
return 0
var/datum/computer_file/program/PRG = ntnet_global.find_ntnet_file_by_name(filename)
if(!PRG || !istype(PRG))
return 0
// Attempting to download antag only program, but without having emagged computer. No.
if(PRG.available_on_syndinet && !computer_emagged)
return 0
if(!computer || !computer.hard_drive || !computer.hard_drive.try_store_file(PRG))
return 0
ui_header = "downloader_running.gif"
if(PRG in ntnet_global.available_station_software)
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from NTNet Software Repository.")
hacked_download = 0
else if(PRG in ntnet_global.available_antag_software)
generate_network_log("Began downloading file **ENCRYPTED**.[PRG.filetype] from unspecified server.")
hacked_download = 1
else
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from unspecified server.")
hacked_download = 0
downloaded_file = PRG.clone()
/datum/computer_file/program/ntnetdownload/proc/abort_file_download()
if(!downloaded_file)
return
generate_network_log("Aborted download of file [hacked_download ? "**ENCRYPTED**" : downloaded_file.filename].[downloaded_file.filetype].")
downloaded_file = null
download_completion = 0
ui_header = "downloader_finished.gif"
/datum/computer_file/program/ntnetdownload/proc/complete_file_download()
if(!downloaded_file)
return
generate_network_log("Completed download of file [hacked_download ? "**ENCRYPTED**" : downloaded_file.filename].[downloaded_file.filetype].")
if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(downloaded_file))
// The download failed
downloaderror = "I/O ERROR - Unable to save file. Check whether you have enough free space on your hard drive and whether your hard drive is properly connected. If the issue persists contact your system administrator for assistance."
downloaded_file = null
download_completion = 0
ui_header = "downloader_finished.gif"
/datum/computer_file/program/ntnetdownload/process_tick()
if(!downloaded_file)
return
if(download_completion >= downloaded_file.size)
complete_file_download()
// Download speed according to connectivity state. NTNet server is assumed to be on unlimited speed so we're limited by our local connectivity
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_completion += download_netspeed
/datum/computer_file/program/ntnetdownload/ui_act(action, params)
if(..())
return 1
switch(action)
if("PRG_downloadfile")
if(!downloaded_file)
begin_file_download(params["filename"])
return 1
if("PRG_reseterror")
if(downloaderror)
download_completion = 0
download_netspeed = 0
downloaded_file = null
downloaderror = ""
return 1
return 0
/datum/computer_file/program/ntnetdownload/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "ntnet_downloader", "NTNet Download Program", 575, 700, state = state)
ui.open()
ui.set_autoupdate(state = 1)
/datum/computer_file/program/ntnetdownload/ui_data(mob/user)
my_computer = computer
if(!istype(my_computer))
return
var/list/data = get_header_data()
// This IF cuts on data transferred to client, so i guess it's worth it.
if(downloaderror) // Download errored. Wait until user resets the program.
data["error"] = downloaderror
else 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)
else // No download running, pick file.
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/A in ntnet_global.available_station_software)
var/datum/computer_file/program/P = A
// Only those programs our user can run will show in the list
if(!P.can_run(user,transfer = 1))
continue
all_entries.Add(list(list(
"filename" = P.filename,
"filedesc" = P.filedesc,
"fileinfo" = P.extended_desc,
"size" = P.size
)))
data["hackedavailable"] = 0
if(computer_emagged) // If we are running on emagged computer we have access to some "bonus" software
var/list/hacked_programs[0]
for(var/S in ntnet_global.available_antag_software)
var/datum/computer_file/program/P = S
data["hackedavailable"] = 1
hacked_programs.Add(list(list(
"filename" = P.filename,
"filedesc" = P.filedesc,
"fileinfo" = P.extended_desc,
"size" = P.size
)))
data["hacked_programs"] = hacked_programs
data["downloadable_programs"] = all_entries
return data
@@ -0,0 +1,94 @@
/datum/computer_file/program/ntnetmonitor
filename = "ntmonitor"
filedesc = "NTNet Diagnostics and Monitoring"
program_icon_state = "comm_monitor"
extended_desc = "This program monitors stationwide NTNet network, provides access to logging systems, and allows for configuration changes"
size = 12
requires_ntnet = 1
required_access = access_network //Network control is a more secure program.
available_on_ntnet = 1
/datum/computer_file/program/ntnetmonitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "ntnet_monitor", "NTNet Diagnostics and Monitoring Tool", 575, 700, state = state)
ui.open()
ui.set_autoupdate(state = 1)
/datum/computer_file/program/ntnetmonitor/ui_act(action, params)
if(..())
return 1
switch(action)
if("resetIDS")
. = 1
if(ntnet_global)
ntnet_global.resetIDS()
return 1
if("toggleIDS")
. = 1
if(ntnet_global)
ntnet_global.toggleIDS()
return 1
if("toggleWireless")
. = 1
if(!ntnet_global)
return 1
// NTNet is disabled. Enabling can be done without user prompt
if(ntnet_global.setting_disabled)
ntnet_global.setting_disabled = 0
return 1
// 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)
var/mob/user = usr
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("purgelogs")
. = 1
if(ntnet_global)
ntnet_global.purge_logs()
if("updatemaxlogs")
. = 1
var/mob/user = usr
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)
if("toggle_function")
. = 1
if(!ntnet_global)
return 1
ntnet_global.toggle_function(text2num(params["id"]))
/datum/computer_file/program/ntnetmonitor/ui_data(mob/user)
if(!ntnet_global)
return
var/list/data = get_header_data()
data["ntnetstatus"] = ntnet_global.check_function()
data["ntnetrelays"] = ntnet_global.relays.len
data["idsstatus"] = ntnet_global.intrusion_detection_enabled
data["idsalarm"] = ntnet_global.intrusion_detection_alarm
data["config_softwaredownload"] = ntnet_global.setting_softwaredownload
data["config_peertopeer"] = ntnet_global.setting_peertopeer
data["config_communication"] = ntnet_global.setting_communication
data["config_systemcontrol"] = ntnet_global.setting_systemcontrol
data["ntnetlogs"] = list()
for(var/i in ntnet_global.logs)
data["ntnetlogs"] += list(list("entry" = i))
data["ntnetmaxlogs"] = ntnet_global.setting_maxlogcount
return data
@@ -0,0 +1,236 @@
/datum/computer_file/program/chatclient
filename = "ntnrc_client"
filedesc = "NTNet Relay Chat Client"
program_icon_state = "command"
extended_desc = "This program allows communication over NTNRC network"
size = 8
requires_ntnet = 1
requires_ntnet_feature = NTNET_COMMUNICATION
network_destination = "NTNRC server"
ui_header = "ntnrc_idle.gif"
available_on_ntnet = 1
var/last_message = null // 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)
/datum/computer_file/program/chatclient/New()
username = "DefaultUser[rand(100, 999)]"
/datum/computer_file/program/chatclient/ui_act(action, params)
if(..())
return 1
switch(action)
if("PRG_speak")
. = 1
if(!channel)
return 1
var/mob/living/user = usr
var/message = sanitize(input(user, "Enter message or leave blank to cancel: "))
if(!message || !channel)
return
channel.add_message(message, username)
log_chat("[user]/([user.ckey]) as [username] sent to [channel.title]: [message]")
if("PRG_joinchannel")
. = 1
var/datum/ntnet_conversation/C
for(var/datum/ntnet_conversation/chan in ntnet_global.chat_channels)
if(chan.id == text2num(params["id"]))
C = chan
break
if(!C)
return 1
if(netadmin_mode)
channel = C // Bypasses normal leave/join and passwords. Technically makes the user invisible to others.
return 1
if(C.password)
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("PRG_leavechannel")
. = 1
if(channel)
channel.remove_client(src)
channel = null
if("PRG_newchannel")
. = 1
var/mob/living/user = usr
var/channel_title = sanitize(input(user,"Enter channel name or leave blank to cancel:"))
if(!channel_title)
return
var/datum/ntnet_conversation/C = new/datum/ntnet_conversation()
C.add_client(src)
C.operator = src
channel = C
C.title = channel_title
if("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("PRG_changename")
. = 1
var/mob/living/user = usr
var/newname = sanitize(input(user,"Enter new nickname or leave blank to cancel:"))
if(!newname)
return 1
if(channel)
channel.add_status_message("[username] is now known as [newname].")
username = newname
if("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("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:"))
if(!newname || !channel)
return
channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.")
channel.title = newname
if("PRG_deletechannel")
. = 1
if(channel && ((channel.operator == src) || netadmin_mode))
qdel(channel)
channel = null
if("PRG_setpassword")
. = 1
if(!channel || ((channel.operator != src) && !netadmin_mode))
return 1
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
/datum/computer_file/program/chatclient/process_tick()
..()
if(program_state != PROGRAM_STATE_KILLED)
ui_header = "ntnrc_idle.gif"
if(channel)
// Remember the last message. If there is no message in the channel remember null.
last_message = channel.messages.len ? channel.messages[channel.messages.len - 1] : null
else
last_message = null
return 1
if(channel && channel.messages && 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(forced = 0)
if(channel)
channel.remove_client(src)
channel = null
..(forced)
/datum/computer_file/program/chatclient/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "ntnet_chat", "NTNet Relay Chat Client", 575, 700, state = state)
ui.open()
ui.set_autoupdate(state = 1)
/datum/computer_file/program/chatclient/ui_data(mob/user)
if(!ntnet_global || !ntnet_global.chat_channels)
return
var/list/data = list()
data = get_header_data()
data["adminmode"] = netadmin_mode
if(channel)
data["title"] = channel.title
var/list/messages[0]
for(var/M in channel.messages)
messages.Add(list(list(
"msg" = M
)))
data["messages"] = messages
var/list/clients[0]
for(var/C in channel.clients)
var/datum/computer_file/program/chatclient/cl = C
clients.Add(list(list(
"name" = cl.username
)))
data["clients"] = clients
operator_mode = (channel.operator == src) ? 1 : 0
data["is_operator"] = operator_mode || netadmin_mode
else // Channel selection screen
var/list/all_channels[0]
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["all_channels"] = all_channels
return data
@@ -0,0 +1,195 @@
var/global/nttransfer_uid = 0
/datum/computer_file/program/nttransfer
filename = "nttransfer"
filedesc = "NTNet P2P Transfer Client"
extended_desc = "This program allows for simple file transfer via direct peer to peer connection."
program_icon_state = "comm_logs"
size = 7
requires_ntnet = 1
requires_ntnet_feature = NTNET_PEERTOPEER
network_destination = "other device via P2P tunnel"
available_on_ntnet = 1
var/error = "" // Error screen
var/server_password = "" // Optional password to download the file.
var/datum/computer_file/provided_file = null // File which is provided to clients.
var/datum/computer_file/downloaded_file = null // File which is being downloaded
var/list/connected_clients = list() // List of connected clients.
var/datum/computer_file/program/nttransfer/remote // Client var, specifies who are we downloading from.
var/download_completion = 0 // Download progress in GQ
var/download_netspeed = 0 // Our connectivity speed in GQ/s
var/actual_netspeed = 0 // Displayed in the UI, this is the actual transfer speed.
var/unique_token // UID of this program
var/upload_menu = 0 // Whether we show the program list and upload menu
/datum/computer_file/program/nttransfer/New()
unique_token = nttransfer_uid
nttransfer_uid++
..()
/datum/computer_file/program/nttransfer/process_tick()
// Server mode
update_netspeed()
if(provided_file)
for(var/datum/computer_file/program/nttransfer/C in connected_clients)
// Transfer speed is limited by device which uses slower connectivity.
// We can have multiple clients downloading at same time, but let's assume we use some sort of multicast transfer
// so they can all run on same speed.
C.actual_netspeed = min(C.download_netspeed, download_netspeed)
C.download_completion += C.actual_netspeed
if(C.download_completion >= provided_file.size)
C.finish_download()
else if(downloaded_file) // Client mode
if(!remote)
crash_download("Connection to remote server lost")
/datum/computer_file/program/nttransfer/kill_program(forced = 0)
if(downloaded_file) // Client mode, clean up variables for next use
finalize_download()
if(provided_file) // Server mode, disconnect all clients
for(var/datum/computer_file/program/nttransfer/P in connected_clients)
P.crash_download("Connection terminated by remote server")
downloaded_file = null
..(forced)
/datum/computer_file/program/nttransfer/proc/update_netspeed()
download_netspeed = 0
switch(ntnet_status)
if(1)
download_netspeed = NTNETSPEED_LOWSIGNAL
if(2)
download_netspeed = NTNETSPEED_HIGHSIGNAL
if(3)
download_netspeed = NTNETSPEED_ETHERNET
// Finishes download and attempts to store the file on HDD
/datum/computer_file/program/nttransfer/proc/finish_download()
if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(downloaded_file))
error = "I/O Error: Unable to save file. Check your hard drive and try again."
finalize_download()
// Crashes the download and displays specific error message
/datum/computer_file/program/nttransfer/proc/crash_download(var/message)
error = message ? message : "An unknown error has occured during download"
finalize_download()
// Cleans up variables for next use
/datum/computer_file/program/nttransfer/proc/finalize_download()
if(remote)
remote.connected_clients.Remove(src)
downloaded_file = null
remote = null
download_completion = 0
/datum/computer_file/program/nttransfer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "ntnet_transfer", "NTNet P2P Transfer Client", 575, 700, state = state)
ui.open()
ui.set_autoupdate(state = 1)
/datum/computer_file/program/nttransfer/ui_act(action, params)
if(..())
return 1
switch(action)
if("PRG_downloadfile")
for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers)
if("[P.unique_token]" == params["id"])
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
downloaded_file = remote.provided_file.clone()
remote.connected_clients.Add(src)
return 1
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 1
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
if(pass == "none")
server_password = ""
return
server_password = pass
return 1
if("PRG_uploadfile")
for(var/datum/computer_file/F in computer.hard_drive.stored_files)
if("[F.uid]" == params["id"])
if(F.unsendable)
error = "I/O Error: File locked."
return
if(istype(F, /datum/computer_file/program))
var/datum/computer_file/program/P = F
if(!P.can_run(usr,transfer = 1))
error = "Access Error: Insufficient rights to upload file."
provided_file = F
ntnet_global.fileservers.Add(src)
return
error = "I/O Error: Unable to locate file on hard drive."
return 1
if("PRG_uploadmenu")
upload_menu = 1
/datum/computer_file/program/nttransfer/ui_data(mob/user)
var/list/data = get_header_data()
if(error)
data["error"] = error
else if(downloaded_file)
data["downloading"] = 1
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]"
else if (provided_file)
data["uploading"] = 1
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]"
else if (upload_menu)
var/list/all_files[0]
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]
for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers)
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
)))
data["servers"] = all_servers
return data
@@ -0,0 +1,93 @@
/datum/computer_file/program/power_monitor
filename = "powermonitor"
filedesc = "Power Monitoring"
program_icon_state = "power_monitor"
extended_desc = "This program connects to sensors around the station to provide information about electrical systems"
ui_header = "power_norm.gif"
transfer_access = access_engine
usage_flags = PROGRAM_CONSOLE
requires_ntnet = 0
network_destination = "power monitoring system"
size = 9
var/has_alert = 0
var/obj/structure/cable/attached
var/list/history = list()
var/record_size = 60
var/record_interval = 50
var/next_record = 0
/datum/computer_file/program/power_monitor/run_program(mob/living/user)
. = ..(user)
search()
history["supply"] = list()
history["demand"] = list()
/datum/computer_file/program/power_monitor/process_tick()
if(!attached)
search()
else
record()
/datum/computer_file/program/power_monitor/proc/search()
var/turf/T = get_turf(computer)
attached = locate() in T
/datum/computer_file/program/power_monitor/proc/record()
if(world.time >= next_record)
next_record = world.time + record_interval
var/list/supply = history["supply"]
supply += attached.powernet.viewavail
if(supply.len > record_size)
supply.Cut(1, 2)
var/list/demand = history["demand"]
demand += attached.powernet.viewload
if(demand.len > record_size)
demand.Cut(1, 2)
/datum/computer_file/program/power_monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "power_monitor_prog", "Power Monitoring", 1200, 1000, master_ui, state)
ui.open()
/datum/computer_file/program/power_monitor/ui_data()
var/list/data = get_header_data()
data["stored"] = record_size
data["interval"] = record_interval / 10
data["attached"] = attached ? TRUE : FALSE
if(attached)
data["supply"] = attached.powernet.viewavail
data["demand"] = attached.powernet.viewload
data["history"] = history
data["areas"] = list()
if(attached)
for(var/obj/machinery/power/terminal/term in attached.powernet.nodes)
var/obj/machinery/power/apc/A = term.master
if(istype(A))
data["areas"] += list(list(
"name" = A.area.name,
"charge" = A.cell.percent(),
"load" = A.lastused_total,
"charging" = A.charging,
"eqp" = A.equipment,
"lgt" = A.lighting,
"env" = A.environ
))
return data
@@ -0,0 +1,79 @@
// This device is wrapper for actual power cell. I have decided to not use power cells directly as even low-end cells available on station
// have tremendeous capacity in comparsion. Higher tier cells would provide your device with nearly infinite battery life, which is something i want to avoid.
/obj/item/weapon/computer_hardware/battery_module
name = "standard battery"
desc = "A standard power cell, commonly seen in high-end portable microcomputers or low-end laptops. It's rating is 750."
icon_state = "battery_normal"
critical = 1
malfunction_probability = 1
origin_tech = list("powerstorage" = 1, "engineering" = 1)
var/battery_rating = 750
var/obj/item/weapon/stock_parts/cell/battery = null
/obj/item/weapon/computer_hardware/battery_module/advanced
name = "advanced battery"
desc = "An advanced power cell, often used in most laptops. It is too large to be fitted into smaller devices. It's rating is 1100."
icon_state = "battery_advanced"
origin_tech = list("powerstorage" = 2, "engineering" = 2)
hardware_size = 2
battery_rating = 1100
/obj/item/weapon/computer_hardware/battery_module/super
name = "super battery"
desc = "A very advanced power cell, often used in high-end devices, or as uninterruptable power supply for important consoles or servers. It's rating is 1500."
icon_state = "battery_super"
origin_tech = list("powerstorage" = 3, "engineering" = 3)
hardware_size = 2
battery_rating = 1500
/obj/item/weapon/computer_hardware/battery_module/ultra
name = "ultra battery"
desc = "A very advanced large power cell. It's often used as uninterruptable power supply for critical consoles or servers. It's rating is 2000."
icon_state = "battery_ultra"
origin_tech = list("powerstorage" = 5, "engineering" = 4)
hardware_size = 3
battery_rating = 2000
/obj/item/weapon/computer_hardware/battery_module/micro
name = "micro battery"
desc = "A small power cell, commonly seen in most portable microcomputers. It's rating is 500."
icon_state = "battery_micro"
origin_tech = list("powerstorage" = 2, "engineering" = 2)
battery_rating = 500
/obj/item/weapon/computer_hardware/battery_module/nano
name = "nano battery"
desc = "A tiny power cell, commonly seen in low-end portable microcomputers. It's rating is 300."
icon_state = "battery_nano"
origin_tech = list("powerstorage" = 1, "engineering" = 1)
battery_rating = 300
// 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."
icon_state = "battery_lambda"
hardware_size = 1
battery_rating = 1000000
/obj/item/weapon/computer_hardware/battery_module/diagnostics(var/mob/user)
..()
user << "Internal battery charge: [battery.charge]/[battery.maxcharge] CU"
/obj/item/weapon/computer_hardware/battery_module/New()
battery = new/obj/item/weapon/stock_parts/cell(src)
battery.maxcharge = battery_rating
battery.charge = battery.maxcharge/2
..()
/obj/item/weapon/computer_hardware/battery_module/proc/charge_to_full()
if(battery)
battery.charge = battery.maxcharge
/obj/item/weapon/computer_hardware/battery_module/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
if(M.battery_module)
user << "This computer's battery slot is already occupied by \the [M.battery_module]."
return
found = 1
M.battery_module = src
..(user, M, found)
@@ -0,0 +1,29 @@
/obj/item/weapon/computer_hardware/card_slot
name = "RFID card slot"
desc = "Slot that allows this computer to write data on RFID cards. Necessary for some programs to run properly."
power_usage = 10 //W
critical = 0
icon_state = "cardreader"
hardware_size = 1
origin_tech = list("programming" = 2)
var/obj/item/weapon/card/id/stored_card = null
var/obj/item/weapon/card/id/stored_card2 = null
/obj/item/weapon/computer_hardware/card_slot/Destroy()
if(holder2 && (holder2.card_slot == src))
holder2.card_slot = null
if(stored_card)
stored_card.forceMove(get_turf(holder2))
if(stored_card2)
stored_card2.forceMove(get_turf(holder2))
holder2 = null
..()
/obj/item/weapon/computer_hardware/card_slot/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
if(M.card_slot)
user << "This computer's card slot is already occupied by \the [M.card_slot]."
return
found = 1
M.card_slot = src
..(user, M, found)
@@ -0,0 +1,175 @@
/obj/item/weapon/computer_hardware/hard_drive/
name = "basic hard drive"
desc = "A small power efficient solid state drive, with 128GQ of storage capacity for use in basic computers where power efficiency is desired."
power_usage = 25 // SSD or something with low power usage
icon_state = "hdd_normal"
hardware_size = 1
origin_tech = list("programming" = 1, "engineering" = 1)
var/max_capacity = 128
var/used_capacity = 0
var/list/stored_files = list() // List of stored files on this drive. DO NOT MODIFY DIRECTLY!
/obj/item/weapon/computer_hardware/hard_drive/advanced
name = "advanced hard drive"
desc = "A small hybrid hard drive with 256GQ of storage capacity for use in higher grade computers where balance between power efficiency and capacity is desired."
max_capacity = 256
origin_tech = list("programming" = 2, "engineering" = 2)
power_usage = 50 // Hybrid, medium capacity and medium power storage
icon_state = "hdd_advanced"
hardware_size = 2
/obj/item/weapon/computer_hardware/hard_drive/super
name = "super hard drive"
desc = "A small hard drive with 512GQ of storage capacity for use in cluster storage solutions where capacity is more important than power efficiency."
max_capacity = 512
origin_tech = list("programming" = 3, "engineering" = 3)
power_usage = 100 // High-capacity but uses lots of power, shortening battery life. Best used with APC link.
icon_state = "hdd_super"
hardware_size = 2
/obj/item/weapon/computer_hardware/hard_drive/cluster
name = "cluster hard drive"
desc = "A large storage cluster consisting of multiple hard drives for usage in high capacity storage systems. Has capacity of 2048 GQ."
power_usage = 500
origin_tech = list("programming" = 4, "engineering" = 4)
max_capacity = 2048
icon_state = "hdd_cluster"
hardware_size = 3
// For tablets, etc. - highly power efficient.
/obj/item/weapon/computer_hardware/hard_drive/small
name = "small hard drive"
desc = "A small highly efficient solid state drive for portable devices."
power_usage = 10
origin_tech = list("programming" = 2, "engineering" = 2)
max_capacity = 64
icon_state = "hdd_small"
hardware_size = 1
/obj/item/weapon/computer_hardware/hard_drive/micro
name = "micro hard drive"
desc = "A small micro hard drive for portable devices."
power_usage = 2
origin_tech = list("programming" = 1, "engineering" = 1)
max_capacity = 32
icon_state = "hdd_micro"
hardware_size = 1
/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"
// 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)
if(!F || !istype(F))
return 0
if(!can_store_file(F.size))
return 0
if(!check_functionality())
return 0
if(!stored_files)
return 0
// This file is already stored. Don't store it again.
if(F in stored_files)
return 0
F.holder = src
stored_files.Add(F)
recalculate_size()
return 1
// 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/install_default_programs()
store_file(new/datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
store_file(new/datum/computer_file/program/ntnetdownload(src)) // NTNet Downloader Utility, allows users to download more software from NTNet repository
store_file(new/datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation.
// Use this proc to remove file from the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks.
/obj/item/weapon/computer_hardware/hard_drive/proc/remove_file(var/datum/computer_file/F)
if(!F || !istype(F))
return 0
if(!stored_files)
return 0
if(!check_functionality())
return 0
if(F in stored_files)
stored_files -= F
recalculate_size()
return 1
else
return 0
// Loops through all stored files and recalculates used_capacity of this drive
/obj/item/weapon/computer_hardware/hard_drive/proc/recalculate_size()
var/total_size = 0
for(var/datum/computer_file/F in stored_files)
total_size += F.size
used_capacity = total_size
// Checks whether file can be stored on the hard drive.
/obj/item/weapon/computer_hardware/hard_drive/proc/can_store_file(var/size = 1)
// In the unlikely event someone manages to create that many files.
// BYOND is acting weird with numbers above 999 in loops (infinite loop prevention)
if(stored_files.len >= 999)
return 0
if(used_capacity + size > max_capacity)
return 0
else
return 1
// Checks whether we can store the file. We can only store unique files, so this checks whether we wouldn't get a duplicity by adding a file.
/obj/item/weapon/computer_hardware/hard_drive/proc/try_store_file(var/datum/computer_file/F)
if(!F || !istype(F))
return 0
var/name = F.filename + "." + F.filetype
for(var/datum/computer_file/file in stored_files)
if((file.filename + "." + file.filetype) == name)
return 0
return can_store_file(F.size)
// Tries to find the file by filename. Returns null on failure
/obj/item/weapon/computer_hardware/hard_drive/proc/find_file_by_name(var/filename)
if(!check_functionality())
return null
if(!filename)
return null
if(!stored_files)
return null
for(var/datum/computer_file/F in stored_files)
if(F.filename == filename)
return F
return null
/obj/item/weapon/computer_hardware/hard_drive/Destroy()
if(holder2 && (holder2.hard_drive == src))
holder2.hard_drive = null
stored_files = null
..()
/obj/item/weapon/computer_hardware/hard_drive/New()
install_default_programs()
..()
/obj/item/weapon/computer_hardware/hard_drive/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
if(M.hard_drive)
user << "This computer's hard drive slot is already occupied by \the [M.hard_drive]."
return
found = 1
M.hard_drive = src
..(user, M, found)
@@ -0,0 +1,99 @@
/obj/item/weapon/computer_hardware/
name = "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.
var/enabled = 1 // If the hardware is turned off set this to 0.
var/critical = 1 // Prevent disabling for important component, like the HDD.
var/hardware_size = 1 // Limits which devices can contain this component. 1: Tablets/Laptops/Consoles, 2: Laptops/Consoles, 3: Consoles only
var/damage = 0 // Current damage level
var/max_damage = 100 // Maximal damage level.
var/damage_malfunction = 20 // "Malfunction" threshold. When damage exceeds this value the hardware piece will semi-randomly fail and do !!FUN!! things
var/damage_failure = 50 // "Failure" threshold. When damage exceeds this value the hardware piece will not work at all.
var/malfunction_probability = 10// Chance of malfunction when the component is damaged
/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 *****"
diagnostics(user)
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/sheet/glass))
if(!damage)
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."
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."
return 1
if(S.use(1))
user << "You patch up \the [src] with a bit of \the [W]."
take_damage(-10)
return 1
return ..()
// 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"]"
/obj/item/weapon/computer_hardware/New(var/obj/L)
w_class = hardware_size
if(istype(L, /obj/machinery/modular_computer))
var/obj/machinery/modular_computer/C = L
if(C.cpu)
holder2 = C.cpu
return
if(istype(L, /obj/item/modular_computer))
holder2 = L
return
/obj/item/weapon/computer_hardware/Destroy()
holder2 = null
return ..()
// Handles damage checks
/obj/item/weapon/computer_hardware/proc/check_functionality()
// Too damaged to work at all.
if(damage > damage_failure)
return 0
// Still working. Well, sometimes...
if(damage > damage_malfunction)
if(prob(malfunction_probability))
return 0
// Good to go.
return 1
/obj/item/weapon/computer_hardware/examine(var/mob/user)
. = ..()
if(damage > damage_failure)
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>"
else if(damage)
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 = max(0, min(damage, max_damage)) // Clamp the value.
// Attempts to install the hardware into apropriate slot.
/obj/item/weapon/computer_hardware/proc/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
if(found)
user << "You install \the [src] into \the [M]"
holder2 = M
if(!user.drop_item(src))
return
forceMove(M)
@@ -0,0 +1,60 @@
/obj/item/weapon/computer_hardware/nano_printer
name = "nano printer"
desc = "Small integrated printer with paper recycling module."
power_usage = 50
origin_tech = list("programming" = 2, "engineering" = 2)
critical = 0
icon_state = "printer"
hardware_size = 1
var/stored_paper = 5
var/max_paper = 10
/obj/item/weapon/computer_hardware/nano_printer/diagnostics(var/mob/user)
..()
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)
return 0
if(!enabled)
return 0
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()
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"
return
user << "You insert \the [W] into [src]."
qdel(W)
stored_paper++
/obj/item/weapon/computer_hardware/nano_printer/Destroy()
if(holder2 && (holder2.nano_printer == src))
holder2.nano_printer = null
holder2 = null
..()
/obj/item/weapon/computer_hardware/nano_printer/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
if(M.nano_printer)
user << "This computer's nano printer slot is already occupied by \the [M.nano_printer]."
return
found = 1
M.nano_printer = src
..(user, M, found)
@@ -0,0 +1,104 @@
var/global/ntnet_card_uid = 1
/obj/item/weapon/computer_hardware/network_card/
name = "basic NTNet network card"
desc = "A basic network card for usage with standard NTNet frequencies."
power_usage = 50
origin_tech = list("programming" = 2, TECH_ENGINEERING = 1)
critical = 0
icon_state = "netcard_basic"
hardware_size = 1
var/identification_id = null // Identification ID. Technically MAC address of this device. Can't be changed by user.
var/identification_string = "" // Identification string, technically nickname seen in the network. Can be set by user.
var/long_range = 0
var/ethernet = 0 // Hard-wired, therefore always on, ignores NTNet wireless checks.
malfunction_probability = 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"
if(long_range)
user << "511.n WFS/HB (Subspace) - Wide Frequency Spread/High Bandiwdth"
if(ethernet)
user << "OpenEth (Physical Connection) - Physical network connection port"
/obj/item/weapon/computer_hardware/network_card/New(var/l)
..(l)
identification_id = ntnet_card_uid
ntnet_card_uid++
/obj/item/weapon/computer_hardware/network_card/advanced
name = "advanced NTNet network card"
desc = "An advanced network card for usage with standard NTNet frequencies. It's transmitter is strong enough to connect even off-station."
long_range = 1
origin_tech = list("programming" = 4, "engineering" = 2)
power_usage = 100 // Better range but higher power usage.
icon_state = "netcard_advanced"
hardware_size = 1
/obj/item/weapon/computer_hardware/network_card/wired
name = "wired NTNet network card"
desc = "An advanced network card for usage with standard NTNet frequencies. This one also supports wired connection."
ethernet = 1
origin_tech = list("programming" = 5, "engineering" = 3)
power_usage = 100 // Better range but higher power usage.
icon_state = "netcard_ethernet"
hardware_size = 3
/obj/item/weapon/computer_hardware/network_card/Destroy()
if(holder2 && (holder2.network_card == src))
holder2.network_card = null
holder2 = null
..()
// Returns a string identifier of this network card
/obj/item/weapon/computer_hardware/network_card/proc/get_network_tag()
return "[identification_string] (NID [identification_id])"
// 0 - No signal, 1 - Low signal, 2 - High signal. 3 - Wired Connection
/obj/item/weapon/computer_hardware/network_card/proc/get_signal(var/specific_action = 0)
if(!holder2) // Hardware is not installed in anything. No signal. How did this even get called?
return 0
if(!enabled)
return 0
if(!check_functionality())
return 0
if(ethernet) // Computer is connected via wired connection.
return 3
if(!ntnet_global || !ntnet_global.check_function(specific_action)) // NTNet is down and we are not connected via wired connection. No signal.
return 0
if(holder2)
var/turf/T = get_turf(holder2)
if((T && istype(T)) && (T.z == ZLEVEL_STATION || T.z == ZLEVEL_MINING))
// Computer is on station. Low/High signal depending on what type of network card you have
if(long_range)
return 2
else
return 1
if(long_range) // Computer is not on station, but it has upgraded network card. Low signal.
return 1
return 0 // Computer is not on station and does not have upgraded network card. No signal.
/obj/item/weapon/computer_hardware/network_card/Destroy()
if(holder2 && (holder2.network_card == src))
holder2.network_card = null
..()
/obj/item/weapon/computer_hardware/network_card/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
if(M.network_card)
user << "This computer's network card slot is already occupied by \the [M.network_card]."
return
found = 1
M.network_card = src
..(user, M, found)
@@ -0,0 +1,41 @@
// 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."
power_usage = 10
icon_state = "flashdrive_basic"
hardware_size = 1
max_capacity = 16
origin_tech = list("programming" = 1)
/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."
power_usage = 20
icon_state = "flashdrive_advanced"
hardware_size = 1
max_capacity = 64
origin_tech = list("programming" = 2)
/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."
power_usage = 40
icon_state = "flashdrive_super"
hardware_size = 1
max_capacity = 256
origin_tech = list("programming" = 4)
/obj/item/weapon/computer_hardware/hard_drive/portable/New()
..()
stored_files = list()
recalculate_size()
/obj/item/weapon/computer_hardware/hard_drive/portable/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
if(M.portable_drive)
user << "This computer's portable drive slot is already occupied by \the [M.portable_drive]."
return
found = 1
M.portable_drive = src
..(user, M, found)
@@ -0,0 +1,49 @@
// CPU that allows the computer to run programs.
// Better CPUs are obtainable via research and can run more programs on background.
/obj/item/weapon/computer_hardware/processor_unit
name = "standard processor"
desc = "A standard CPU used in most computers. It can run up to three programs simultaneously."
icon_state = "cpu_normal"
hardware_size = 2
power_usage = 50
critical = 1
malfunction_probability = 1
origin_tech = list("programming" = 3, "engineering" = 2)
var/max_idle_programs = 2 // 2 idle, + 1 active = 3 as said in description.
/obj/item/weapon/computer_hardware/processor_unit/small
name = "standard microprocessor"
desc = "A standard miniaturised CPU used in portable devices. It can run up to two programs simultaneously."
icon_state = "cpu_small"
hardware_size = 1
power_usage = 25
max_idle_programs = 1
origin_tech = list("programming" = 2, "engineering" = 2)
/obj/item/weapon/computer_hardware/processor_unit/photonic
name = "photonic processor"
desc = "An advanced experimental CPU that uses photonic core instead of regular circuitry. It can run up to five programs simultaneously, but uses a lot of power."
icon_state = "cpu_normal_photonic"
hardware_size = 2
power_usage = 250
max_idle_programs = 4
origin_tech = list("programming" = 5, "engineering" = 4)
/obj/item/weapon/computer_hardware/processor_unit/photonic/small
name = "photonic microprocessor"
desc = "An advanced miniaturised CPU for use in portable devices. It uses photonic core instead of regular circuitry. It can run up to three programs simultaneously."
icon_state = "cpu_small_photonic"
hardware_size = 1
power_usage = 75
max_idle_programs = 2
origin_tech = list("programming" = 4, "engineering" = 3)
/obj/item/weapon/computer_hardware/processor_unit/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
if(M.processor_unit)
user << "This computer's processor slot is already occupied by \the [M.processor_unit]."
return
found = 1
M.processor_unit = src
..(user, M, found)
@@ -0,0 +1,31 @@
/obj/item/weapon/computer_hardware/tesla_link
name = "tesla link"
desc = "An advanced tesla link that wirelessly recharges connected device from nearby area power controller."
critical = 0
enabled = 1
icon_state = "teslalink"
hardware_size = 2 // Can't be installed into tablets
origin_tech = list("programming" = 2, "powerstorage" = 3, "engineering" = 2)
var/obj/machinery/modular_computer/holder
/obj/item/weapon/computer_hardware/tesla_link/New(var/obj/L)
if(istype(L, /obj/machinery/modular_computer))
holder = L
return
..(L)
/obj/item/weapon/computer_hardware/tesla_link/Destroy()
if(holder && (holder.tesla_link == src))
holder.tesla_link = null
..()
/obj/item/weapon/computer_hardware/tesla_link/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
if(istype(M, /obj/item/modular_computer/processor))
var/obj/item/modular_computer/processor/P = M
if(P.machinery_computer.tesla_link)
user << "This computer's tesla link slot is already occupied by \the [P.machinery_computer.tesla_link]."
return
holder = P.machinery_computer
P.machinery_computer.tesla_link = src
found = 1
..(user, M, found)
+3 -2
View File
@@ -23,12 +23,13 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis).
"Hydroponics Machinery",
"Subspace Telecomms",
"Research Machinery",
"Misc. Machinery"
"Misc. Machinery",
"Computer Parts"
)
/obj/machinery/r_n_d/circuit_imprinter/New()
..()
materials = new(src, list(MAT_GLASS, MAT_GOLD, MAT_DIAMOND))
materials = new(src, list(MAT_GLASS, MAT_GOLD, MAT_DIAMOND, MAT_METAL))
create_reagents(0)
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/circuit_imprinter(null)
B.apply_default_parts(src)
@@ -728,3 +728,18 @@
build_path = /obj/item/conveyor_switch_construct
category = list("initial", "Construction")
/datum/design/laptop
name = "Laptop Frame"
id = "laptop"
build_type = AUTOLATHE
materials = list(MAT_METAL = 1200, MAT_GLASS = 200)
build_path = /obj/machinery/modular_computer/laptop/buildable
category = list("initial","Misc")
/datum/design/tablet
name = "Tablet Frame"
id = "tablet"
build_type = AUTOLATHE
materials = list(MAT_METAL = 500, MAT_GLASS = 1000)
build_path = /obj/item/modular_computer/tablet
category = list("initial","Misc")
@@ -0,0 +1,245 @@
////////////////////////////////////////
///////////Computer Parts///////////////
////////////////////////////////////////
/datum/design/disk/normal
name = "basic hard drive"
id = "hdd_basic"
req_tech = list("programming" = 1, "engineering" = 1)
build_type = PROTOLATHE
materials = list(MAT_METAL = 400, MAT_GLASS = 100)
build_path = /obj/item/weapon/computer_hardware/hard_drive/
category = list("Computer Parts")
/datum/design/disk/advanced
name = "advanced hard drive"
id = "hdd_advanced"
req_tech = list("programming" = 2, "engineering" = 2)
build_type = PROTOLATHE
materials = list(MAT_METAL = 800, MAT_GLASS = 200)
build_path = /obj/item/weapon/computer_hardware/hard_drive/advanced
category = list("Computer Parts")
/datum/design/disk/super
name = "super hard drive"
id = "hdd_super"
req_tech = list("programming" = 3, "engineering" = 3)
build_type = PROTOLATHE
materials = list(MAT_METAL = 1600, MAT_GLASS = 400)
build_path = /obj/item/weapon/computer_hardware/hard_drive/super
category = list("Computer Parts")
/datum/design/disk/cluster
name = "cluster hard drive"
id = "hdd_cluster"
req_tech = list("programming" = 4, "engineering" = 4)
build_type = PROTOLATHE
materials = list(MAT_METAL = 3200, MAT_GLASS = 800)
build_path = /obj/item/weapon/computer_hardware/hard_drive/cluster
category = list("Computer Parts")
/datum/design/disk/small
name = "small hard drive"
id = "hdd_small"
req_tech = list("programming" = 2, "engineering" = 2)
build_type = PROTOLATHE
materials = list(MAT_METAL = 800, MAT_GLASS = 200)
build_path = /obj/item/weapon/computer_hardware/hard_drive/small
category = list("Computer Parts")
/datum/design/disk/micro
name = "micro hard drive"
id = "hdd_micro"
req_tech = list("programming" = 1, "engineering" = 1)
build_type = PROTOLATHE
materials = list(MAT_METAL = 400, MAT_GLASS = 100)
build_path = /obj/item/weapon/computer_hardware/hard_drive/micro
category = list("Computer Parts")
// Network cards
/datum/design/netcard/basic
name = "basic network card"
id = "netcard_basic"
req_tech = list("programming" = 2, "engineering" = 1)
build_type = IMPRINTER
materials = list(MAT_METAL = 250, MAT_GLASS = 100)
reagents = list("sacid" = 20)
build_path = /obj/item/weapon/computer_hardware/network_card
category = list("Computer Parts")
/datum/design/netcard/advanced
name = "advanced network card"
id = "netcard_advanced"
req_tech = list("programming" = 4, "engineering" = 2)
build_type = IMPRINTER
materials = list(MAT_METAL = 500, MAT_GLASS = 200)
reagents = list("sacid" = 20)
build_path = /obj/item/weapon/computer_hardware/network_card/advanced
category = list("Computer Parts")
/datum/design/netcard/wired
name = "wired network card"
id = "netcard_wired"
req_tech = list("programming" = 5, "engineering" = 3)
build_type = IMPRINTER
materials = list(MAT_METAL = 2500, MAT_GLASS = 400)
reagents = list("sacid" = 20)
build_path = /obj/item/weapon/computer_hardware/network_card/wired
category = list("Computer Parts")
// Data crystals (USB flash drives)
/datum/design/portabledrive/basic
name = "basic data crystal"
id = "portadrive_basic"
req_tech = list("programming" = 1)
build_type = IMPRINTER
materials = list(MAT_GLASS = 800)
reagents = list("sacid" = 20)
build_path = /obj/item/weapon/computer_hardware/hard_drive/portable
category = list("Computer Parts")
/datum/design/portabledrive/advanced
name = "advanced data crystal"
id = "portadrive_advanced"
req_tech = list("programming" = 2)
build_type = IMPRINTER
materials = list(MAT_GLASS = 1600)
reagents = list("sacid" = 20)
build_path = /obj/item/weapon/computer_hardware/hard_drive/portable/advanced
category = list("Computer Parts")
/datum/design/portabledrive/super
name = "super data crystal"
id = "portadrive_super"
req_tech = list("programming" = 4)
build_type = IMPRINTER
materials = list(MAT_GLASS = 3200)
reagents = list("sacid" = 20)
build_path = /obj/item/weapon/computer_hardware/hard_drive/portable/super
category = list("Computer Parts")
// Card slot
/datum/design/cardslot
name = "RFID card slot"
id = "cardslot"
req_tech = list("programming" = 2)
build_type = PROTOLATHE
materials = list(MAT_METAL = 600)
build_path = /obj/item/weapon/computer_hardware/card_slot
category = list("Computer Parts")
// Nano printer
/datum/design/nanoprinter
name = "nano printer"
id = "nanoprinter"
req_tech = list("programming" = 2, "engineering" = 2)
build_type = PROTOLATHE
materials = list(MAT_METAL = 600)
build_path = /obj/item/weapon/computer_hardware/nano_printer
category = list("Computer Parts")
// Tesla Link
/datum/design/teslalink
name = "tesla link"
id = "teslalink"
req_tech = list("programming" = 2, "powerstorage" = 3, "engineering" = 2)
build_type = PROTOLATHE
materials = list(MAT_METAL = 2000)
build_path = /obj/item/weapon/computer_hardware/tesla_link
category = list("Computer Parts")
// Batteries
/datum/design/battery/normal
name = "standard battery module"
id = "bat_normal"
req_tech = list("powerstorage" = 1, "engineering" = 1)
build_type = PROTOLATHE
materials = list(MAT_METAL = 400)
build_path = /obj/item/weapon/computer_hardware/battery_module
category = list("Computer Parts")
/datum/design/battery/advanced
name = "advanced battery module"
id = "bat_advanced"
req_tech = list("powerstorage" = 2, "engineering" = 2)
build_type = PROTOLATHE
materials = list(MAT_METAL = 800)
build_path = /obj/item/weapon/computer_hardware/battery_module/advanced
category = list("Computer Parts")
/datum/design/battery/super
name = "super battery module"
id = "bat_super"
req_tech = list("powerstorage" = 3, "engineering" = 3)
build_type = PROTOLATHE
materials = list(MAT_METAL = 1600)
build_path = /obj/item/weapon/computer_hardware/battery_module/super
category = list("Computer Parts")
/datum/design/battery/ultra
name = "ultra battery module"
id = "bat_ultra"
req_tech = list("powerstorage" = 5, "engineering" = 4)
build_type = PROTOLATHE
materials = list(MAT_METAL = 3200)
build_path = /obj/item/weapon/computer_hardware/battery_module/ultra
category = list("Computer Parts")
/datum/design/battery/nano
name = "nano battery module"
id = "bat_nano"
req_tech = list("powerstorage" = 1, "engineering" = 1)
build_type = PROTOLATHE
materials = list(MAT_METAL = 200)
build_path = /obj/item/weapon/computer_hardware/battery_module/nano
category = list("Computer Parts")
/datum/design/battery/micro
name = "micro battery module"
id = "bat_micro"
req_tech = list("powerstorage" = 2, "engineering" = 2)
build_type = PROTOLATHE
materials = list(MAT_METAL = 400)
build_path = /obj/item/weapon/computer_hardware/battery_module/micro
category = list("Computer Parts")
// Processor unit
/datum/design/cpu
name = "computer processor unit"
id = "cpu_normal"
req_tech = list("programming" = 3, "engineering" = 2)
build_type = IMPRINTER
materials = list(MAT_GLASS = 1600)
reagents = list("sacid" = 20)
build_path = /obj/item/weapon/computer_hardware/processor_unit
category = list("Computer Parts")
/datum/design/cpu/small
name = "computer microprocessor unit"
id = "cpu_small"
req_tech = list("programming" = 2, "engineering" = 2)
build_type = IMPRINTER
materials = list(MAT_GLASS = 800)
reagents = list("sacid" = 20)
build_path = /obj/item/weapon/computer_hardware/processor_unit/small
category = list("Computer Parts")
/datum/design/cpu/photonic
name = "computer photonic processor unit"
id = "pcpu_normal"
req_tech = list("programming" = 5, "engineering" = 4)
build_type = IMPRINTER
materials = list(MAT_GLASS= 6400, MAT_GOLD = 2000)
reagents = list("sacid" = 40)
build_path = /obj/item/weapon/computer_hardware/processor_unit/photonic
category = list("Computer Parts")
/datum/design/cpu/photonic/small
name = "computer photonic microprocessor unit"
id = "pcpu_small"
req_tech = list("programming" = 4, "engineering" = 3)
build_type = IMPRINTER
materials = list(MAT_GLASS = 3200, MAT_GOLD = 1000)
reagents = list("sacid" = 20)
build_path = /obj/item/weapon/computer_hardware/processor_unit/photonic/small
category = list("Computer Parts")
@@ -386,3 +386,11 @@
req_tech = list("programming" = 4, "biotech" = 3)
build_path = /obj/item/weapon/circuitboard/machine/plantgenes
category = list ("Misc. Machinery")
/datum/design/board/ntnet_relay
name = "Machine Design (NTNet Relay Board)"
desc = "The circuit board for a wireless network relay."
id = "ntnet_relay"
req_tech = list("programming" = 2, "engineering" = 2, "bluespace" = 2)
build_path = /obj/item/weapon/circuitboard/machine/ntnet_relay
category = list("Subspace Telecomms")
+2 -1
View File
@@ -26,7 +26,8 @@ Note: Must be placed west/left of and R&D console to function.
"Electronics",
"Weapons",
"Ammo",
"Firing Pins"
"Firing Pins",
"Computer Parts"
)
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

+36
View File
@@ -1519,6 +1519,41 @@
#include "code\modules\mob\new_player\poll.dm"
#include "code\modules\mob\new_player\preferences_setup.dm"
#include "code\modules\mob\new_player\sprite_accessories.dm"
#include "code\modules\modular_computers\computers\item\modular_computer.dm"
#include "code\modules\modular_computers\computers\item\processor.dm"
#include "code\modules\modular_computers\computers\item\tablet.dm"
#include "code\modules\modular_computers\computers\item\tablet_presets.dm"
#include "code\modules\modular_computers\computers\machinery\console_presets.dm"
#include "code\modules\modular_computers\computers\machinery\modular_computer.dm"
#include "code\modules\modular_computers\computers\machinery\modular_console.dm"
#include "code\modules\modular_computers\computers\machinery\modular_laptop.dm"
#include "code\modules\modular_computers\file_system\computer_file.dm"
#include "code\modules\modular_computers\file_system\data.dm"
#include "code\modules\modular_computers\file_system\program.dm"
#include "code\modules\modular_computers\file_system\program_events.dm"
#include "code\modules\modular_computers\file_system\programs\alarm.dm"
#include "code\modules\modular_computers\file_system\programs\card.dm"
#include "code\modules\modular_computers\file_system\programs\configurator.dm"
#include "code\modules\modular_computers\file_system\programs\file_browser.dm"
#include "code\modules\modular_computers\file_system\programs\ntdownloader.dm"
#include "code\modules\modular_computers\file_system\programs\ntmonitor.dm"
#include "code\modules\modular_computers\file_system\programs\ntnrc_client.dm"
#include "code\modules\modular_computers\file_system\programs\nttransfer.dm"
#include "code\modules\modular_computers\file_system\programs\powermonitor.dm"
#include "code\modules\modular_computers\file_system\programs\antagonist\dos.dm"
#include "code\modules\modular_computers\file_system\programs\antagonist\revelation.dm"
#include "code\modules\modular_computers\hardware\battery_module.dm"
#include "code\modules\modular_computers\hardware\card_slot.dm"
#include "code\modules\modular_computers\hardware\hard_drive.dm"
#include "code\modules\modular_computers\hardware\hardware.dm"
#include "code\modules\modular_computers\hardware\nano_printer.dm"
#include "code\modules\modular_computers\hardware\network_card.dm"
#include "code\modules\modular_computers\hardware\portable_hard_drive.dm"
#include "code\modules\modular_computers\hardware\processor_unit.dm"
#include "code\modules\modular_computers\hardware\tesla_link.dm"
#include "code\modules\modular_computers\NTNet\NTNet.dm"
#include "code\modules\modular_computers\NTNet\NTNet_relay.dm"
#include "code\modules\modular_computers\NTNet\NTNRC\conversation.dm"
#include "code\modules\ninja\__ninjaDefines.dm"
#include "code\modules\ninja\admin_ninja_verbs.dm"
#include "code\modules\ninja\energy_katana.dm"
@@ -1704,6 +1739,7 @@
#include "code\modules\research\designs\autolathe_designs.dm"
#include "code\modules\research\designs\biogenerator_designs.dm"
#include "code\modules\research\designs\comp_board_designs.dm"
#include "code\modules\research\designs\computer_part_designs.dm"
#include "code\modules\research\designs\machine_designs.dm"
#include "code\modules\research\designs\mecha_designs.dm"
#include "code\modules\research\designs\mechfabricator_designs.dm"
+1 -1
View File
File diff suppressed because one or more lines are too long
+15 -13
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -5,7 +5,7 @@
component.exports = {
computed: {
clickable () {
if (this.get('enabled') && !this.get('state')) {
if (this.get('enabled') && (!this.get('state') || this.get('state') == "toggle")) {
return true
}
return false
+1
View File
@@ -27,6 +27,7 @@ span.button
buttoncolor(normal, button-color-normal)
buttoncolor(disabled, button-color-disabled)
buttoncolor(selected, button-color-selected)
buttoncolor(toggle, button-color-selected)
buttoncolor(caution, button-color-caution)
buttoncolor(danger, button-color-danger)
+47
View File
@@ -0,0 +1,47 @@
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
<ui-display>
<i>No program loaded. Please select program from list below.</i>
<table>
{{#each data.programs}}
<tr><td><ui-button action='PC_runprogram' params='{"name": "{{name}}"}'>
{{desc}}
</ui-button>
<td><ui-button state='{{running ? null : "disabled"}}' icon='close' action='PC_killprogram' params='{"name": "{{name}}"}'></ui-button>
{{/each}}
</table>
</ui-display>
+98
View File
@@ -0,0 +1,98 @@
<ui-display>
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
{{#if data.error}}
<h2>An error has occured and this program can not continue.</h2>
Additional information: {{data.error}}<br>
<i>Please try again. If the problem persists contact your system administrator for assistance.</i>
<ui-button action='PRG_closefile'>Restart program</ui-button>
{{else}}
{{#if data.filename}}
<h2>Viewing file {{data.filename}}</h2>
<div class='item'>
<ui-button action='PRG_closefile'>CLOSE</ui-button>
<ui-button action='PRG_edit'>EDIT</ui-button>
<ui-button action='PRG_printfile'>PRINT</ui-button>
</div><hr>
{{data.filedata}}
{{else}}
<h2>Available files (local):</h2>
<table>
<tr><th>File name
<th>File type
<th>File size (GQ)
<th>Operations
{{#each data.files}}
<tr><td>{{name}}
<td>.{{type}}
<td>{{size}}GQ
<td>
<ui-button action='PRG_openfile' params='{"name": "{{name}}"}'>VIEW</ui-button>
<ui-button state='{{undeletable ? "disabled" : null}}' action='PRG_deletefile' params='{"name": "{{name}}"}'>DELETE</ui-button>
<ui-button state='{{undeletable ? "disabled" : null}}' action='PRG_rename' params='{"name": "{{name}}"}'>RENAME</ui-button>
<ui-button state='{{undeletable ? "disabled" : null}}' action='PRG_clone' params='{"name": "{{name}}"}'>CLONE</ui-button>
{{#if data.usbconnected}}
<ui-button state='{{undeletable ? "disabled" : null}}' action='PRG_copytousb' params='{"name": "{{name}}"}'>EXPORT</ui-button>
{{/if}}
{{/each}}
</table>
{{#if data.usbconnected}}
<h2>Available files (portable device):</h2>
<table>
<tr><th>File name
<th>File type
<th>File size (GQ)
<th>Operations
{{#each data.usbfiles}}
<tr><td>{{name}}
<td>.{{type}}
<td>{{size}}GQ
<td>
<ui-button state='{{undeletable ? "disabled" : null}}' action='PRG_usbdeletefile' params='{"name": "{{name}}"}'>DELETE</ui-button>
{{#if data.usbconnected}}
<ui-button state='{{undeletable ? "disabled" : null}}' action='PRG_copyfromusb' params='{"name": "{{name}}"}'>IMPORT</ui-button>
{{/if}}
{{/each}}
</table>
{{/if}}
<ui-button action='PRG_newtextfile'>NEW DATA FILE</ui-button>
{{/if}}
{{/if}}
</ui-display>
@@ -0,0 +1,259 @@
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
{{#if data.have_id_slot}}
<ui-button action='PRG_switchm' icon='home' params='{"target" : "mod"}' state='{{data.mmode == 1 ? "disabled" : null}}'>Access Modification</ui-button>
{{/if}}
<ui-button action='PRG_switchm' icon='folder-open' params='{"target" : "manage"}' state='{{data.mmode == 2 ? "disabled" : null}}'>Job Management</ui-button>
<ui-button action='PRG_switchm' icon='folder-open' params='{"target" : "manifest"}' state='{{!data.mmode ? "disabled" : null}}'>Crew Manifest</ui-button>
{{#if data.have_printer}}
<ui-button action='PRG_print' icon='print' state='{{!data.mmode || data.has_id && data.mmode == 1 ? null : "disabled"}}'>Print</ui-button>
{{/if}}
{{#if !data.mmode}}
<div class='item'>
<h2>Crew Manifest</h2>
<br>Please use security record computer to modify entries.<br><br>
</div>
{{#each data.manifest}}
<div class='item'>
{{name}} - {{rank}}
</div>
{{/each}}
{{elseif data.mmode == 2}}
<div class='item'>
<h2>Job Management</h2>
</div>
<table>
<tr><td style='width:25%'><b>Job</b></td><td style='width:25%'><b>Slots</b></td><td style='width:25%'><b>Open job</b></td><td style='width:25%'><b>Close job</b></td></tr>
{{#each data.slots}}
<tr><td>{{title}}</td><td>{{current}}/{{total}}</td><td><ui-button action='PRG_open_job' params='{"target" : "{{title}}"}' state='{{status_open ? null : "disabled"}}'>{{desc_open}}</ui-button><br></td><td><ui-button action='PRG_close_job' params='{"target" : "{{title}}"}' state='{{status_close ? null : "disabled"}}'>{{desc_close}}</ui-button>
</td></tr>
{{/each}}
</table>
{{else}}
<div class='item'>
<h2>Access Modification</h2>
</div>
{{#if !data.has_id}}
<span class='alert'><i>Please insert the ID into the terminal to proceed.</i></span><br>
{{/if}}
<div class='item'>
<div class='itemLabel'>
Target Identity:
</div>
<div class='itemContent'>
<ui-button icon='eject' action='PRG_eject' params='{"target" : "id"}'>{{data.id_name}}</ui-button>
</div>
</div>
<div class='item'>
<div class='itemLabel'>
Auth Identity:
</div>
<div class='itemContent'>
<ui-button icon='eject' action='PRG_eject' params='{"target" : "auth"}'>{{data.auth_name}}</ui-button>
</div>
</div>
<hr>
{{#if data.authenticated}}
{{#if data.has_id}}
<div class='item'>
<h2>Details</h2>
</div>
{{#if data.minor}}
<div class='item'>
<div class='itemLabel'>
Registered Name:
</div>
<div class='itemContent'>
{{data.id_owner}}
</div>
</div>
<div class='item'>
<div class='itemLabel'>
Rank:
</div>
<div class='itemContent'>
{{data.id_rank}}
</div>
</div>
<div class='item'>
<div class='itemLabel'>
Demote:
</div>
<div class='itemContent'>
<ui-button action='PRG_terminate' icon='gear' state='{{data.id_rank == "Unassigned" ? "disabled" : null}}'>Demote {{data.id_owner}}</ui-button>
</div>
</div>
{{else}}
<div class='item'>
<div class='itemLabel'>
Registered Name:
</div>
<div class='itemContent'>
<ui-button action='PRG_edit' icon='pencil' params='{"name" : "1"}'>{{data.id_owner}}</ui-button>
</div>
</div>
<div class='item'>
<h2>Assignment</h2>
</div>
<ui-button action='PRG_togglea' icon='gear'>{{data.assignments ? "Hide assignments" : "Show assignments"}}</ui-button>
<div class='item'>
<span id='allvalue.jobsslot'>
</span>
</div>
<div class='item'>
{{#if data.assignments}}
<div id="all-value.jobs">
<table>
<tr>
<th></th><th>Command</th>
</tr>
<tr>
<th>Special</th>
<td>
<ui-button action='PRG_assign' params='{"assign_target" : "Captain"}' state='{{data.id_rank == "Captain" ? "selected" : null}}'>Captain</ui-button>
<ui-button action='PRG_assign' params='{"assign_target" : "Custom"}'>Custom</ui-button>
</td>
</tr>
<tr>
<th style="color: '#FFA500';">Engineering</th>
<td>
{{#each data.engineering_jobs}}
<ui-button action='PRG_assign' params='{"assign_target" : "{{job}}"}' state='{{data.id_rank == job ? "selected" : null}}'>{{display_name}}</ui-button>
{{/each}}
</td>
</tr>
<tr>
<th style="color: '#008000';">Medical</th>
<td>
{{#each data.medical_jobs}}
<ui-button action='PRG_assign' params='{"assign_target" : "{{job}}"}' state='{{data.id_rank == job ? "selected" : null}}'>{{display_name}}</ui-button>
{{/each}}
</td>
</tr>
<tr>
<th style="color: '#800080';">Science</th>
<td>
{{#each data.science_jobs}}
<ui-button action='PRG_assign' params='{"assign_target" : "{{job}}"}' state='{{data.id_rank == job ? "selected" : null}}'>{{display_name}}</ui-button>
{{/each}}
</td>
</tr>
<tr>
<th style="color: '#DD0000';">Security</th>
<td>
{{#each data.security_jobs}}
<ui-button action='PRG_assign' params='{"assign_target" : "{{job}}"}' state='{{data.id_rank == job ? "selected" : null}}'>{{display_name}}</ui-button>
{{/each}}
</td>
</tr>
<tr>
<th style="color: '#cc6600';">Cargo</th>
<td>
{{#each data.cargo_jobs}}
<ui-button action='PRG_assign' params='{"assign_target" : "{{job}}"}' state='{{data.id_rank == job ? "selected" : null}}'>{{display_name}}</ui-button>
{{/each}}
</td>
</tr>
<tr>
<th style="color: '#808080';">Civilian</th>
<td>
{{#each data.civilian_jobs}}
<ui-button action='PRG_assign' params='{"assign_target" : "{{job}}"}' state='{{data.id_rank == job ? "selected" : null}}'>{{display_name}}</ui-button>
{{/each}}
</td>
</tr>
{{#if data.centcom_access}}
<tr>
<th style="color: '#A52A2A';">CentCom</th>
<td>
{{#each data.centcom_jobs}}
<ui-button action='PRG_assign' params='{"assign_target" : "{{job}}"}' state='{{data.id_rank == job ? "selected" : null}}'>{{display_name}}</ui-button>
{{/each}}
</td>
</tr>
{{/if}}
</table>
</div>
{{/if}}
</div>
{{/if}}
{{#if data.centcom_access}}
<div class='item'>
<h2>Central Command</h2>
</div>
<div class='item' style='width: 100%'>
{{#each data.all_centcom_access}}
<div class='itemContentWide'>
<ui-button action='PRG_access' params='{"access_target" : "{{ref}}", "allowed" : "{{allowed}}"}' state='{{allowed ? "toggle" : null}}'>{{desc}}</ui-button>
</div>
{{/each}}
</div>
{{else}}
<div class='item'>
<h2>{{data.station_name}}</h2>
</div>
<div class='item' style='width: 100%'>
{{#each data.regions}}
<div style='float: left; width: 175px; min-height: 250px'>
<div class='average'><ui-button action='PRG_regsel' state='{{selected ? "toggle" : null}}' params='{"region" : "{{regid}}"}'><b>{{name}}</b></ui-button></div>
<br>
{{#each accesses}}
<div class='itemContentWide'>
<ui-button action='PRG_access' params='{"access_target" : "{{ref}}", "allowed" : "{{allowed}}"}' state='{{allowed ? "toggle" : null}}'>{{desc}}</ui-button>
</div>
{{/each}}
</div>
{{/each}}
</div>
{{/if}}
{{/if}}
{{/if}}
{{/if}}
@@ -0,0 +1,104 @@
<script>
component.exports = {
data: {
chargeState(charge) {
let max = this.get('data.battery.max')
if(charge > (max/2)) return 'good'
else if(charge > (max/4)) return 'average'
else return 'bad'
}
}
}
</script>
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
<ui-display>
<i>Welcome to computer configuration utility. Please consult your system administrator if you have any questions about your device.</i><hr>
<ui-display title='Power Supply'>
{{#if data.battery}}
<ui-section label='Battery Status'>
Active
</ui-section>
<ui-section label='Battery Rating'>
{{data.battery.max}}
</ui-section>
<ui-section label='Battery Charge'>
<ui-bar min='0' max='{{adata.battery.max}}' value='{{adata.battery.charge}}' state='{{chargeState(adata.battery.charge)}}'>{{Math.round(adata.battery.charge)}}/{{adata.battery.max}}</ui-bar>
</ui-section>
{{else}}
<ui-section label='Battery Status'>
Not Available
</ui-section>
{{/if}}
<ui-section label='Power Usage'>
{{data.power_usage}}W
</ui-section>
</ui-display>
<ui-display title='File System'>
<ui-section label='Used Capacity'>
<ui-bar min='0' max='{{adata.disk_size}}' value='{{adata.disk_used}}' state='good'>{{Math.round(adata.disk_used)}}GQ/{{adata.disk_size}}GQ</ui-bar>
</ui-section>
</ui-display>
<ui-display title='Computer Components'>
{{#each data.hardware}}
<ui-subdisplay title='{{name}}'>
<i>{{desc}}</i><br>
<ui-section label='State'>
{{enabled ? "Enabled" : "Disabled"}}
</ui-section>
<ui-section Label='Power Usage'>
{{powerusage}}W
</ui-section>
{{#if !critical}}
<ui-section label='Toggle Component'>
<ui-button icon='{{enabled ? "power-off" : "close"}}' action='PC_toggle_component' params='{"name": "{{name}}"}'>
{{enabled ? "On" : "Off"}}
</ui-button>
</ui-section>
{{/if}}
<br><br>
{{/each}}
</ui-display>
</ui-display>
+103
View File
@@ -0,0 +1,103 @@
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
<ui-display>
{{#if data.adminmode}}
<h1>ADMINISTRATIVE MODE</h1>
{{/if}}
{{#if data.title}}
<div class="itemLabel">
Current channel:
</div>
<div class="itemContent">
{{data.title}}
</div>
<div class="itemLabel">
Operator access:
</div>
<div class="itemContent">
{{#if data.is_operator}}
<b>Enabled</b>
{{else}}
<b>Disabled</b>
{{/if}}
</div>
<div class="itemLabel">
Controls:
</div>
<div class="itemContent">
<table>
<tr><td><ui-button action='PRG_speak'>Send message</ui-button>
<tr><td><ui-button action='PRG_changename'>Change nickname</ui-button>
<tr><td><ui-button action='PRG_toggleadmin'>Toggle administration mode</ui-button>
<tr><td><ui-button action='PRG_leavechannel'>Leave channel</ui-button>
<tr><td><ui-button action='PRG_savelog'>Save log to local drive</ui-button>
{{#if data.is_operator}}
<tr><td><ui-button action='PRG_renamechannel'>Rename channel</ui-button>
<tr><td><ui-button action='PRG_setpassword'>Set password</ui-button>
<tr><td><ui-button action='PRG_deletechannel'>Delete channel</ui-button>
{{/if}}
</table>
</div>
<b>Chat Window</b>
<div class="statusDisplay" style="overflow: auto;">
<div class="item">
<div class="itemContent" style="width: 100%;">
{{#each data.messages}}
{{msg}}<br>
{{/each}}
</div>
</div>
</div>
<b>Connected Users</b><br>
{{#each data.clients}}
{{name}}<br>
{{/each}}
{{else}}
<b>Controls:</b>
<table>
<tr><td><ui-button action='PRG_changename'>Change nickname</ui-button>
<tr><td><ui-button action='PRG_newchannel'>New Channel</ui-button>
<tr><td><ui-button action='PRG_toggleadmin'>Toggle administration mode</ui-button>
</table>
<b>Available channels:</b>
<table>
{{#each data.all_channels}}
<tr><td><ui-button action='PRG_joinchannel' params='{"id": "{{id}}"}'>{{chan}}</ui-button><br>
{{/each}}
</table>
{{/if}}
</ui-display>
+58
View File
@@ -0,0 +1,58 @@
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
<ui-display>
{{#if data.error}}
##SYSTEM ERROR: {{data.error}}<ui-button action='PRG_reset'>RESET</ui-button>
{{elseif data.target}}
##DoS traffic generator active. Tx: {{data.speed}}GQ/s<br>
{{#each data.dos_strings}}
{{nums}}<br>
{{/each}}
<ui-button action='PRG_reset'>ABORT</ui-button>
{{else}}
##DoS traffic generator ready. Select target device.<br>
{{#if data.focus}}
Targeted device ID: {{data.focus}}
{{else}}
Targeted device ID: None
{{/if}}
<ui-button action='PRG_execute'>EXECUTE</ui-button><div style="clear:both"></div>
Detected devices on network:<br>
{{#each data.relays}}
<ui-button action='PRG_target_relay' params='{"targid": "{{id}}"}'>{{id}}</ui-button>
{{/each}}
{{/if}}
</ui-display>
+119
View File
@@ -0,0 +1,119 @@
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
<ui-display>
<i>Welcome to software download utility. Please select which software you wish to download.</i><hr>
{{#if data.error}}
<ui-display title='Download Error'>
<ui-section label='Information'>
{{data.error}}
</ui-section>
<ui-section label='Reset Program'>
<ui-button icon='times' action='PRG_reseterror'>
RESET
</ui-button>
</ui-section>
</ui-display>
{{else}}
{{#if data.downloadname}}
<ui-display title='Download Running'>
<i>Please wait...</i>
<ui-section label='File name'>
{{data.downloadname}}
</ui-section>
<ui-section label='File description'>
{{data.downloaddesc}}
</ui-section>
<ui-section label='File size'>
{{data.downloadcompletion}}GQ / {{data.downloadsize}}GQ
</ui-section>
<ui-section label='Transfer Rate'>
{{data.downloadspeed}} GQ/s
</ui-section>
<ui-section label='Download progress'>
<ui-bar min='0' max='{{adata.downloadsize}}' value='{{adata.downloadcompletion}}' state='good'>{{Math.round(adata.downloadcompletion)}}/{{adata.downloadsize}}</ui-bar>
</ui-section>
</ui-display>
{{/if}}
{{/if}}
{{#if !data.downloadname}}
{{#if !data.error}}
<ui-display title='Primary software repository'>
<ui-section label='Hard drive'>
<ui-bar min='0' max='{{adata.disk_size}}' value='{{adata.disk_used}}' state='good'>{{Math.round(adata.disk_used)}}GQ/{{adata.disk_size}}GQ</ui-bar>
</ui-section>
{{#each data.downloadable_programs}}
<ui-section label='File name'>
{{filename}} ({{size}} GQ)
</ui-section>
<ui-section label='Program name'>
{{filedesc}}
</ui-section>
<ui-section label='Description'>
{{fileinfo}}
</ui-section>
<ui-section label='File controls'>
<ui-button icon='signal' action='PRG_downloadfile' params='{"filename": "{{filename}}"}'>
DOWNLOAD
</ui-button>
</ui-section>
{{/each}}
</ui-display>
{{#if data.hackedavailable}}
<ui-display title='UNKNOWN software repository'>
<i>Please note that NanoTrasen does not recommend download of software from non-official servers.</i>
{{#each data.hacked_programs}}
<ui-section label='File name'>
{{filename}} ({{size}} GQ)
</ui-section>
<ui-section label='Program name'>
{{filedesc}}
</ui-section>
<ui-section label='Description'>
{{fileinfo}}
</ui-section>
<ui-section label='File controls'>
<ui-button icon='signal' action='PRG_downloadfile' params='{"filename": "{{filename}}"}'>
DOWNLOAD
</ui-button>
</ui-section>
{{/each}}
</ui-display>
{{/if}}
{{/if}}
{{/if}}
<br><br><hr><i>NTOS v2.0.4b Copyright NanoTrasen 2557 - 2559</i>
</ui-display>
+126
View File
@@ -0,0 +1,126 @@
<ui-display>
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
<ui-display title='WIRELESS CONNECTIVITY'>
<ui-section label='Active NTNetRelays'>
<b>{{data.ntnetrelays}}</b>
</ui-section>
{{#if data.ntnetrelays}}
<ui-section label='System status'>
<b>{{data.ntnetstatus ? "ENABLED" : "DISABLED"}}</b>
</ui-section>
<ui-section label='Control'>
<ui-button icon='plus' action='toggleWireless'>
TOGGLE
</ui-button>
</ui-section>
<br><br>
<i>Caution - Disabling wireless transmitters when using wireless device may prevent you from re-enabling them again!</i>
{{else}}
<br><p>Wireless coverage unavailable, no relays are connected.</p>
{{/if}}
</ui-display>
<ui-display title='FIREWALL CONFIGURATION'>
<table>
<tr>
<th>PROTOCOL
<th>STATUS
<th>CONTROL
<tr>
<td>Software Downloads
<td>{{data.config_softwaredownload ? 'ENABLED' : 'DISABLED'}}
<td> <ui-button action='toggle_function' params='{"id": "1"}'>TOGGLE</ui-button>
<tr>
<td>Peer to Peer Traffic
<td>{{data.config_peertopeer ? 'ENABLED' : 'DISABLED'}}
<td><ui-button action='toggle_function' params='{"id": "2"}'>TOGGLE</ui-button>
<tr>
<td>Communication Systems
<td>{{data.config_communication ? 'ENABLED' : 'DISABLED'}}
<td><ui-button action='toggle_function' params='{"id": "3"}'>TOGGLE</ui-button>
<tr>
<td>Remote System Control
<td>{{data.config_systemcontrol ? 'ENABLED' : 'DISABLED'}}
<td><ui-button action='toggle_function' params='{"id": "4"}'>TOGGLE</ui-button>
</table>
</ui-display>
<ui-display title='SECURITY SYSTEMS'>
{{#if data.idsalarm}}
<ui-notice>
<h1>NETWORK INCURSION DETECTED</h1>
</ui-notice>
<i>An abnormal activity has been detected in the network. Please verify system logs for more information</i>
{{/if}}
<ui-section label='Intrusion Detection System'>
<b>{{data.idsstatus ? 'ENABLED' : 'DISABLED'}}</b>
</ui-section>
<ui-section label='Maximal Log Count'>
<b>{{data.ntnetmaxlogs}}</b>
</ui-section>
<ui-section label='Controls'>
</ui-section>
<table>
<tr><td><ui-button action='resetIDS'>RESET IDS</ui-button>
<tr><td><ui-button action='toggleIDS'>TOGGLE IDS</ui-button>
<tr><td><ui-button action='updatemaxlogs'>SET LOG LIMIT</ui-button>
<tr><td><ui-button action='purgelogs'>PURGE LOGS</ui-button>
</table>
<ui-subdisplay title='System Logs'>
<div class="statusDisplay" style="overflow: auto;">
<div class="item">
<div class="itemContent" style="width: 100%;">
{{#each data.ntnetlogs}}
{{entry}}<br>
{{/each}}
</div>
</div>
</div>
</ui-display>
</ui-display>
+22
View File
@@ -0,0 +1,22 @@
<ui-display title='Relay'>
{{#if data.dos_crashed}}
<h2>NETWORK BUFFERS OVERLOADED</h2>
<h3>Overload Recovery Mode</h3>
<i>This system is suffering temporary outage due to overflow of traffic buffers. Until buffered traffic is processed, all further requests will be dropped. Frequent occurences of this error may indicate insufficient hardware capacity of your network. Please contact your network planning department for instructions on how to resolve this issue.</i>
<h3>ADMINISTRATIVE OVERRIDE</h3>
<b> CAUTION - Data loss may occur </b>
<ui-button icon='signal' action='restart'>
Purge buffered traffic
</ui-button>
{{else}}
<ui-section label='Relay status'>
<ui-button icon='power-off' action='toggle'>
{{data.enabled ? "ENABLED" : "DISABLED"}}
</ui-button>
</ui-section>
<ui-section label='Network buffer status'>
{{data.dos_overload}} / {{data.dos_capacity}} GQ
</ui-section>
{{/if}}
</ui-display>
+136
View File
@@ -0,0 +1,136 @@
<ui-display>
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
{{#if data.error}}
<div class='item'>
<h2>An error has occured during operation...</h2>
<b>Additional information: </b>{{data.error}}<br>
<ui-button action='PRG_reset'>Clear</ui-button>
</div>
{{elseif data.downloading}}
<h2>Download in progress...</h2>
<div class="itemLabel">
Downloaded file:
</div>
<div class="itemContent">
{{data.download_name}}
</div>
<div class="itemLabel">
Download progress:
</div>
<div class="itemContent">
{{data.download_progress}} / {{data.download_size}} GQ
</div>
<div class="itemLabel">
Transfer speed:
</div>
<div class="itemContent">
{{data.download_netspeed}}GQ/s
</div>
<div class="itemLabel">
Controls:
</div>
<div class="itemContent">
<ui-button action='PRG_reset'>Abort download</ui-button>
</div>
{{elseif data.uploading}}
<h2>Server enabled</h2>
<div class="itemLabel">
Connected clients:
</div>
<div class="itemContent">
{{data.upload_clients}}
</div>
<div class="itemLabel">
Provided file:
</div>
<div class="itemContent">
{{data.upload_filename}}
</div>
<div class="itemLabel">
Server password:
</div>
<div class="itemContent">
{{#if data.haspassword}}
ENABLED
{{else}}
DISABLED
{{/if}}
</div>
<div class="itemLabel">
Commands:
</div>
<div class="itemContent">
<ui-button action='PRG_setpassword'>Set password</ui-button>
<ui-button action='PRG_reset'>Exit server</ui-button>
</div>
{{elseif data.upload_filelist}}
<h2>File transfer server ready. Select file to upload: </h2>
<table>
<tr><th>File name<th>File size<th>Controls
{{#each data.upload_filelist}}
<tr><td>{{filename}}
<td>{{size}}GQ
<td><ui-button action='PRG_uploadfile' params='{"id": "{{uid}}"}'>Select</ui-button>
{{/each}}
</table>
<hr>
<ui-button action='PRG_setpassword'>Set password</ui-button>
<ui-button action='PRG_reset'>Return</ui-button>
{{else}}
<h2>Available files:</h2>
<table border="1" style="border-collapse: collapse"><tr><th>Server UID<th>File Name<th>File Size<th>Password Protection<th>Operations
{{#each data.servers}}
<tr><td>{{uid}}
<td>{{filename}}
<td>{{size}}GQ
{{#if haspassword}}
<td>Enabled
{{/if}}
{{#if !haspassword}}
<td>Disabled
{{/if}}
<td><ui-button action='PRG_downloadfile' params='{"id": "{{uid}}"}'>Download</ui-button>
{{/each}}
</table>
<hr>
<ui-button action='PRG_uploadmenu'>Send file</ui-button>
{{/if}}
</ui-display>
+112
View File
@@ -0,0 +1,112 @@
<script>
component.exports = {
data: {
chargingState (status) {
switch (status) {
case 2: return 'good'
case 1: return 'average'
default: return 'bad'
}
},
chargingMode (status) {
if (status == 2) return 'Full'
else if (status == 1) return 'Charging'
else return 'Draining'
},
channelState (status) {
if (status >= 2) return 'good'
else return 'bad'
},
channelPower (status) {
if (status >= 2) return 'On'
else return 'Off'
},
channelMode (status) {
if (status == 1 || status == 3) return 'Auto'
else return 'Manual'
}
},
computed: {
graphData () {
const history = this.get('data.history')
return Object.keys(history).map(key => {
return history[key].map((point, index) => {
return { x: index, y: point }
})
})
}
}
}
</script>
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
<ui-display title='Network'>
{{#if config.fancy}}
<ui-linegraph points='{{graphData}}' height='500'
legend='["Available", "Load"]' colors='["rgb(0, 102, 0)", "rgb(153, 0, 0)"]'
xunit='seconds ago' xfactor='{{data.interval}}' yunit='W' yfactor='1'
xinc='{{data.stored / 10}}' yinc='9'/>
{{else}}
<ui-section label='Available'>
<span>{{data.supply}} W</span>
</ui-section>
<ui-section label='Load'>
<span>{{data.demand}} W</span>
</ui-section>
{{/if}}
</ui-display>
<ui-display title='Areas'>
<ui-section nowrap>
<div class='content'>Area</div>
<div class='content'>Charge</div>
<div class='content'>Load</div>
<div class='content'>Status</div>
<div class='content'>Equipment</div>
<div class='content'>Lighting</div>
<div class='content'>Environment</div>
</ui-section>
{{#each data.areas}}
<ui-section label='{{name}}' nowrap>
<div class='content'>{{Math.round(adata.areas[@index].charge)}} %</div>
<div class='content'>{{Math.round(adata.areas[@index].load)}} W</div>
<div class='content'><span class='{{chargingState(charging)}}'>{{chargingMode(charging)}}</span></div>
<div class='content'><span class='{{channelState(eqp)}}'>{{channelPower(eqp)}} [<span>{{channelMode(eqp)}}</span>]</span></div>
<div class='content'><span class='{{channelState(lgt)}}'>{{channelPower(lgt)}} [<span>{{channelMode(lgt)}}</span>]</span></div>
<div class='content'><span class='{{channelState(env)}}'>{{channelPower(env)}} [<span>{{channelMode(env)}}</span>]</span></div>
</ui-section>
{{/each}}
</ui-display>
+60
View File
@@ -0,0 +1,60 @@
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
<ui-display>
<div class='item'>
<div class='itemLabel'>
Payload status:
</div>
<div class='itemContent'>
{{#if data.armed}}
ARMED
{{else}}
DISARMED
{{/if}}
</div>
<div class='itemLabel'>
Controls:
</div>
<div class='itemContent'>
<table>
<tr><td><ui-button action='PRG_obfuscate'>OBFUSCATE PROGRAM NAME</ui-button>
<tr><td><ui-button action='PRG_arm' state='{{data.armed ? "danger" : null}}'>{{data.armed ? "DISARM" : "ARM"}}</ui-button>
<ui-button icon='radiation' state='{{data.armed ? null : "disabled"}}' action='PRG_activate'>ACTIVATE</ui-button>
</table>
</div>
</div>
</ui-display>
@@ -0,0 +1,47 @@
<div style="float: left">
<div class='item'>
<table><tr>
{{#if data.PC_batteryicon && data.PC_showbatteryicon}}
<td><img src='{{data.PC_batteryicon}}'>
{{/if}}
{{#if data.PC_batterypercent && data.PC_showbatteryicon}}
<td><b>{{data.PC_batterypercent}}</b>
{{/if}}
{{#if data.PC_ntneticon}}
<td><img src='{{data.PC_ntneticon}}'>
{{/if}}
{{#if data.PC_apclinkicon}}
<td><img src='{{data.PC_apclinkicon}}'>
{{/if}}
{{#if data.PC_stationtime}}
<td><b>{{data.PC_stationtime}}<b>
{{/if}}
{{#each data.PC_programheaders}}
<td><img src='{{icon}}'>
{{/each}}
</table>
</div>
</div>
<div style="float: right">
<table><tr>
<td><ui-button action='PC_shutdown'>Shutdown</ui-button>
{{#if data.PC_showexitprogram}}
<td><ui-button action='PC_exit'>EXIT PROGRAM</ui-button>
<td><ui-button action='PC_minimize'>Minimize Program</ui-button>
{{/if}}
</table>
</div>
<div style="clear: both">
{{#each data.alarms:class}}
<ui-display title='{{class}} Alarms'>
<ul>
{{#each .}}
<li>{{.}}</li>
{{else}}
<li>System Nominal</li>
{{/each}}
</ul>
</ui-display>
{{/each}}