mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-22 12:29:46 +01:00
@@ -7,6 +7,7 @@ var/global/datum/ntnet/ntnet_global = new()
|
||||
var/list/logs = list()
|
||||
var/list/available_station_software = list()
|
||||
var/list/available_antag_software = list()
|
||||
var/list/available_news = list()
|
||||
var/list/chat_channels = list()
|
||||
var/list/fileservers = list()
|
||||
// Amount of logs the system tries to keep in memory. Keep below 999 to prevent byond from acting weirdly.
|
||||
@@ -32,6 +33,7 @@ var/global/datum/ntnet/ntnet_global = new()
|
||||
relays.Add(R)
|
||||
R.NTNet = src
|
||||
build_software_lists()
|
||||
build_news_list()
|
||||
add_log("NTNet logging system activated.")
|
||||
|
||||
// Simplified logging: Adds a log. log_string is mandatory parameter, source is optional.
|
||||
@@ -61,7 +63,7 @@ var/global/datum/ntnet/ntnet_global = new()
|
||||
|
||||
// Check all relays. If we have at least one working relay, network is up.
|
||||
for(var/obj/machinery/ntnet_relay/R in relays)
|
||||
if(R.is_operational())
|
||||
if(R.operable())
|
||||
operating = 1
|
||||
break
|
||||
|
||||
@@ -93,6 +95,15 @@ var/global/datum/ntnet/ntnet_global = new()
|
||||
if(prog.available_on_syndinet)
|
||||
available_antag_software.Add(prog)
|
||||
|
||||
// Builds lists that contain downloadable software.
|
||||
/datum/ntnet/proc/build_news_list()
|
||||
available_news = list()
|
||||
for(var/F in typesof(/datum/computer_file/data/news_article/))
|
||||
var/datum/computer_file/data/news_article/news = new F(1)
|
||||
if(news.stored_data)
|
||||
available_news.Add(news)
|
||||
|
||||
|
||||
// Attempts to find a downloadable file according to filename var
|
||||
/datum/ntnet/proc/find_ntnet_file_by_name(var/filename)
|
||||
for(var/datum/computer_file/program/P in available_station_software)
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
|
||||
// TODO: Implement more logic here. For now it's only a placeholder.
|
||||
/obj/machinery/ntnet_relay/proc/is_operational()
|
||||
if(stat & (BROKEN | NOPOWER | EMPED))
|
||||
/obj/machinery/ntnet_relay/operable()
|
||||
if(!..(EMPED))
|
||||
return 0
|
||||
if(dos_failure)
|
||||
return 0
|
||||
@@ -30,13 +30,13 @@
|
||||
return 1
|
||||
|
||||
/obj/machinery/ntnet_relay/update_icon()
|
||||
if(is_operational())
|
||||
if(operable())
|
||||
icon_state = "bus"
|
||||
else
|
||||
icon_state = "bus_off"
|
||||
|
||||
/obj/machinery/ntnet_relay/process()
|
||||
if(is_operational())
|
||||
if(operable())
|
||||
use_power = 2
|
||||
else
|
||||
use_power = 1
|
||||
|
||||
@@ -28,7 +28,12 @@
|
||||
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.
|
||||
var/light_strength = 0
|
||||
|
||||
// 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.
|
||||
@@ -39,6 +44,7 @@
|
||||
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/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/obj/item/weapon/computer_hardware/ai_slot/ai_slot // AI slot, an intellicard housing that allows modifications of AIs.
|
||||
|
||||
var/list/idle_threads = list() // Idle programs on background. They still receive process calls but can't be interacted with.
|
||||
|
||||
@@ -59,6 +65,37 @@
|
||||
|
||||
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 Storage"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(usr.incapacitated() || !istype(usr, /mob/living))
|
||||
usr << "<span class='warning'>You can't do that.</span>"
|
||||
return
|
||||
|
||||
if(!Adjacent(usr))
|
||||
usr << "<span class='warning'>You can't reach it.</span>"
|
||||
return
|
||||
|
||||
proc_eject_usb(usr)
|
||||
|
||||
/obj/item/modular_computer/verb/eject_ai()
|
||||
set name = "Eject Portable Storage"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(usr.incapacitated() || !istype(usr, /mob/living))
|
||||
usr << "<span class='warning'>You can't do that.</span>"
|
||||
return
|
||||
|
||||
if(!Adjacent(usr))
|
||||
usr << "<span class='warning'>You can't reach it.</span>"
|
||||
return
|
||||
|
||||
proc_eject_ai(usr)
|
||||
|
||||
/obj/item/modular_computer/proc/proc_eject_id(mob/user)
|
||||
if(!user)
|
||||
user = usr
|
||||
@@ -71,11 +108,42 @@
|
||||
user << "There is no card in \the [src]"
|
||||
return
|
||||
|
||||
if(active_program)
|
||||
active_program.event_idremoved(0)
|
||||
|
||||
for(var/datum/computer_file/program/P in idle_threads)
|
||||
P.event_idremoved(1)
|
||||
|
||||
card_slot.stored_card.forceMove(get_turf(src))
|
||||
card_slot.stored_card = null
|
||||
update_uis()
|
||||
user << "You remove the card from \the [src]"
|
||||
|
||||
|
||||
/obj/item/modular_computer/proc/proc_eject_usb(mob/user)
|
||||
if(!user)
|
||||
user = usr
|
||||
|
||||
if(!portable_drive)
|
||||
user << "There is no portable device connected to \the [src]."
|
||||
return
|
||||
|
||||
uninstall_component(user, portable_drive)
|
||||
update_uis()
|
||||
|
||||
/obj/item/modular_computer/proc/proc_eject_ai(mob/user)
|
||||
if(!user)
|
||||
user = usr
|
||||
|
||||
if(!ai_slot || !ai_slot.stored_card)
|
||||
user << "There is no intellicard connected to \the [src]."
|
||||
return
|
||||
|
||||
ai_slot.stored_card.forceMove(get_turf(src))
|
||||
ai_slot.stored_card = null
|
||||
ai_slot.update_power_usage()
|
||||
update_uis()
|
||||
|
||||
/obj/item/modular_computer/attack_ghost(var/mob/dead/observer/user)
|
||||
if(enabled)
|
||||
ui_interact(user)
|
||||
@@ -93,6 +161,13 @@
|
||||
user << "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message."
|
||||
return 1
|
||||
|
||||
/obj/item/modular_computer/examine(var/mob/user)
|
||||
..()
|
||||
if(damage > broken_damage)
|
||||
user << "<span class='danger'>It is heavily damaged!</span>"
|
||||
else if(damage)
|
||||
user << "It is damaged."
|
||||
|
||||
/obj/item/modular_computer/New()
|
||||
processing_objects.Add(src)
|
||||
update_icon()
|
||||
@@ -102,6 +177,7 @@
|
||||
kill_program(1)
|
||||
processing_objects.Remove(src)
|
||||
for(var/obj/item/weapon/computer_hardware/CH in src.get_all_components())
|
||||
uninstall_component(null, CH)
|
||||
qdel(CH)
|
||||
return ..()
|
||||
|
||||
@@ -110,7 +186,9 @@
|
||||
|
||||
overlays.Cut()
|
||||
if(!enabled)
|
||||
set_light(0)
|
||||
return
|
||||
set_light(light_strength)
|
||||
if(active_program)
|
||||
overlays.Add(active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu)
|
||||
else
|
||||
@@ -151,6 +229,8 @@
|
||||
var/list/program = list()
|
||||
program["name"] = P.filename
|
||||
program["desc"] = P.filedesc
|
||||
if(P in idle_threads)
|
||||
program["running"] = 1
|
||||
programs.Add(list(program))
|
||||
|
||||
data["programs"] = programs
|
||||
@@ -169,9 +249,27 @@
|
||||
else
|
||||
turn_on(user)
|
||||
|
||||
/obj/item/modular_computer/proc/break_apart()
|
||||
visible_message("\The [src] breaks apart!")
|
||||
var/turf/newloc = get_turf(src)
|
||||
new /obj/item/stack/material/steel(newloc, round(steel_sheet_cost/2))
|
||||
for(var/obj/item/weapon/computer_hardware/H in get_all_components())
|
||||
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(var/mob/user)
|
||||
var/issynth = issilicon(user) // Robots and AIs get different activation messages.
|
||||
if(processor_unit && ((battery_module && battery_module.battery.charge) || check_power_override())) // Battery-run and charged or non-battery but powered by APC.
|
||||
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
|
||||
@@ -191,26 +289,32 @@
|
||||
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.
|
||||
kill_program(1)
|
||||
visible_message("<span class='danger'>\The [src]'s screen briefly freezes and then shows \"NETWORK ERROR - NTNet connection lost. Please retry. If problem persists contact your system administrator.\" error.</span>")
|
||||
active_program.event_networkfailure(0)
|
||||
|
||||
for(var/datum/computer_file/program/P in idle_threads)
|
||||
if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature))
|
||||
P.kill_program(1)
|
||||
idle_threads.Remove(P)
|
||||
visible_message("<span class='danger'>\The [src] screen displays an \"Process [P.filename].[P.filetype] (PID [rand(100,999)]) terminated - Network Error\" error</span>")
|
||||
P.event_networkfailure(1)
|
||||
|
||||
if(active_program)
|
||||
active_program.process_tick()
|
||||
active_program.ntnet_status = get_ntnet_status()
|
||||
active_program.computer_emagged = computer_emagged
|
||||
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/datum/computer_file/program/P in idle_threads)
|
||||
P.process_tick()
|
||||
P.ntnet_status = get_ntnet_status()
|
||||
P.computer_emagged = computer_emagged
|
||||
|
||||
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()
|
||||
@@ -324,44 +428,60 @@
|
||||
if(!active_program || !processor_unit)
|
||||
return
|
||||
|
||||
if(idle_threads.len >= processor_unit.max_idle_programs)
|
||||
user << "<span class='notice'>\The [src] displays a \"Maximal CPU load reached. Unable to minimize another program.\" error</span>"
|
||||
return
|
||||
|
||||
idle_threads.Add(active_program)
|
||||
active_program.running = 0 // Should close any existing UIs
|
||||
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
|
||||
nanomanager.close_uis(active_program.NM ? active_program.NM : active_program)
|
||||
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( href_list["PC_killprogram"] )
|
||||
var/prog = href_list["PC_killprogram"]
|
||||
var/datum/computer_file/program/P = null
|
||||
var/mob/user = usr
|
||||
if(hard_drive)
|
||||
P = hard_drive.find_file_by_name(prog)
|
||||
|
||||
if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED)
|
||||
return
|
||||
|
||||
P.kill_program(1)
|
||||
update_uis()
|
||||
user << "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>"
|
||||
|
||||
if( href_list["PC_runprogram"] )
|
||||
var/prog = href_list["PC_runprogram"]
|
||||
var/datum/computer_file/program/P = null
|
||||
var/mob/user = usr
|
||||
if(hard_drive)
|
||||
P = hard_drive.find_file_by_name(prog)
|
||||
P.computer = src
|
||||
|
||||
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.running = 1
|
||||
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
|
||||
|
||||
if(P.run_program(user))
|
||||
active_program = P
|
||||
update_icon()
|
||||
@@ -370,9 +490,13 @@
|
||||
update_uis()
|
||||
|
||||
// Used in following function to reduce copypaste
|
||||
/obj/item/modular_computer/proc/power_failure()
|
||||
/obj/item/modular_computer/proc/power_failure(var/malfunction = 0)
|
||||
if(enabled) // Shut down the computer
|
||||
visible_message("<span class='danger'>\The [src]'s screen flickers \"BATTERY CRITICAL\" warning as it shuts down unexpectedly.</span>")
|
||||
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/datum/computer_file/program/PRG in idle_threads)
|
||||
PRG.event_powerfailure(1)
|
||||
shutdown_computer(0)
|
||||
|
||||
// Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged
|
||||
@@ -388,6 +512,9 @@
|
||||
power_usage += H.power_usage
|
||||
|
||||
if(battery_module)
|
||||
if(!battery_module.check_functionality())
|
||||
power_failure(1)
|
||||
return
|
||||
battery_module.battery.use(power_usage * CELLRATE)
|
||||
|
||||
last_power_usage = power_usage
|
||||
@@ -409,10 +536,13 @@
|
||||
user << "You insert \the [I] into \the [src]."
|
||||
return
|
||||
if(istype(W, /obj/item/weapon/paper))
|
||||
var/obj/item/weapon/paper/P = W
|
||||
if(!nano_printer)
|
||||
return
|
||||
nano_printer.load_paper(P)
|
||||
nano_printer.attackby(W, user)
|
||||
if(istype(W, /obj/item/weapon/aicard))
|
||||
if(!ai_slot)
|
||||
return
|
||||
ai_slot.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)
|
||||
@@ -429,6 +559,21 @@
|
||||
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()
|
||||
@@ -507,6 +652,12 @@
|
||||
return
|
||||
found = 1
|
||||
processor_unit = H
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/ai_slot))
|
||||
if(ai_slot)
|
||||
user << "This computer's intellicard slot is already occupied by \the [ai_slot]."
|
||||
return
|
||||
found = 1
|
||||
ai_slot = H
|
||||
if(found)
|
||||
user << "You install \the [H] into \the [src]"
|
||||
H.holder2 = src
|
||||
@@ -538,14 +689,18 @@
|
||||
processor_unit = null
|
||||
found = 1
|
||||
critical = 1
|
||||
if(ai_slot == H)
|
||||
ai_slot = null
|
||||
found = 1
|
||||
if(found)
|
||||
user << "You remove \the [H] from \the [src]."
|
||||
if(user)
|
||||
user << "You remove \the [H] from \the [src]."
|
||||
H.forceMove(get_turf(src))
|
||||
H.holder2 = null
|
||||
if(critical && enabled)
|
||||
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>"
|
||||
kill_program(1)
|
||||
enabled = 0
|
||||
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()
|
||||
|
||||
|
||||
@@ -565,6 +720,8 @@
|
||||
return battery_module
|
||||
if(processor_unit && (processor_unit.name == name))
|
||||
return processor_unit
|
||||
if(ai_slot && (ai_slot.name == name))
|
||||
return ai_slot
|
||||
return null
|
||||
|
||||
// Returns list of all components
|
||||
@@ -584,6 +741,8 @@
|
||||
all_components.Add(battery_module)
|
||||
if(processor_unit)
|
||||
all_components.Add(processor_unit)
|
||||
if(ai_slot)
|
||||
all_components.Add(ai_slot)
|
||||
return all_components
|
||||
|
||||
/obj/item/modular_computer/proc/update_uis()
|
||||
@@ -595,16 +754,16 @@
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
/obj/item/modular_computer/proc/check_update_ui_need()
|
||||
var/ui_updated_needed = 0
|
||||
var/ui_update_needed = 0
|
||||
if(battery_module)
|
||||
var/batery_percent = battery_module.battery.percent()
|
||||
if(last_battery_percent != batery_percent) //Let's update UI on percent chandge
|
||||
ui_updated_needed = 1
|
||||
if(last_battery_percent != batery_percent) //Let's update UI on percent change
|
||||
ui_update_needed = 1
|
||||
last_battery_percent = batery_percent
|
||||
|
||||
if(worldtime2text() != last_world_time)
|
||||
last_world_time = worldtime2text()
|
||||
ui_updated_needed = 1
|
||||
ui_update_needed = 1
|
||||
|
||||
if(idle_threads.len)
|
||||
var/list/current_header_icons = list()
|
||||
@@ -617,13 +776,51 @@
|
||||
|
||||
else if(!listequal(last_header_icons, current_header_icons))
|
||||
last_header_icons = current_header_icons
|
||||
ui_updated_needed = 1
|
||||
ui_update_needed = 1
|
||||
else
|
||||
for(var/x in last_header_icons|current_header_icons)
|
||||
if(last_header_icons[x]!=current_header_icons[x])
|
||||
last_header_icons = current_header_icons
|
||||
ui_updated_needed = 1
|
||||
ui_update_needed = 1
|
||||
break
|
||||
|
||||
if(ui_updated_needed)
|
||||
update_uis()
|
||||
if(ui_update_needed)
|
||||
update_uis()
|
||||
|
||||
/obj/item/modular_computer/proc/take_damage(var/amount, var/component_probability, var/damage_casing = 1, var/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 = between(0, damage, max_damage)
|
||||
|
||||
if(component_probability)
|
||||
for(var/obj/item/weapon/computer_hardware/H in get_all_components())
|
||||
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(var/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(var/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(var/obj/item/projectile/Proj)
|
||||
switch(Proj.damage_type)
|
||||
if(BRUTE)
|
||||
take_damage(Proj.damage, Proj.damage / 2)
|
||||
if(HALLOSS)
|
||||
take_damage(Proj.damage, Proj.damage / 3, 0)
|
||||
if(BURN)
|
||||
take_damage(Proj.damage, Proj.damage / 1.5)
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
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
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/processor/nano_host()
|
||||
return machinery_computer.nano_host()
|
||||
// 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.
|
||||
@@ -25,6 +27,12 @@
|
||||
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)
|
||||
@@ -40,6 +48,8 @@
|
||||
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)
|
||||
@@ -92,10 +102,6 @@
|
||||
var/obj/item/weapon/computer_hardware/tesla_link/L = H
|
||||
L.holder = machinery_computer
|
||||
machinery_computer.tesla_link = L
|
||||
// Consoles don't usually have internal power source, so we can't disable tesla link in them.
|
||||
if(istype(machinery_computer, /obj/machinery/modular_computer/console))
|
||||
L.critical = 1
|
||||
L.enabled = 1
|
||||
found = 1
|
||||
..(user, H, found)
|
||||
|
||||
@@ -103,14 +109,13 @@
|
||||
if(machinery_computer.tesla_link == H)
|
||||
machinery_computer.tesla_link = null
|
||||
var/obj/item/weapon/computer_hardware/tesla_link/L = H
|
||||
L.critical = 0 // That way we can install tesla link from console to laptop and it will be possible to turn it off via config.
|
||||
L.holder = null
|
||||
found = 1
|
||||
..(user, H, found, critical)
|
||||
|
||||
/obj/item/modular_computer/processor/get_all_components()
|
||||
var/list/all_components = ..()
|
||||
if(machinery_computer.tesla_link)
|
||||
if(machinery_computer && machinery_computer.tesla_link)
|
||||
all_components.Add(machinery_computer.tesla_link)
|
||||
return all_components
|
||||
|
||||
@@ -118,4 +123,16 @@
|
||||
/obj/item/modular_computer/processor/Adjacent(var/atom/neighbor)
|
||||
if(!machinery_computer)
|
||||
return 0
|
||||
return machinery_computer.Adjacent(neighbor)
|
||||
return machinery_computer.Adjacent(neighbor)
|
||||
|
||||
/obj/item/modular_computer/processor/turn_on(var/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
|
||||
..()
|
||||
|
||||
/obj/item/modular_computer/processor/check_eye(var/mob/user)
|
||||
if (active_program)
|
||||
return active_program.check_eye(user)
|
||||
|
||||
return -1
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
icon_state_menu = "menu"
|
||||
hardware_flag = PROGRAM_TABLET
|
||||
max_hardware_size = 1
|
||||
w_class = 2
|
||||
w_class = 2
|
||||
light_strength = 2 // Same as PDAs
|
||||
@@ -5,6 +5,7 @@
|
||||
desc = "A low-end tablet often seen among low ranked station personnel"
|
||||
processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src)
|
||||
battery_module = new/obj/item/weapon/computer_hardware/battery_module/nano(src)
|
||||
battery_module.charge_to_full()
|
||||
hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/micro(src)
|
||||
network_card = new/obj/item/weapon/computer_hardware/network_card(src)
|
||||
|
||||
@@ -13,6 +14,7 @@
|
||||
. = ..()
|
||||
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)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
var/_has_id_slot = 0
|
||||
var/_has_printer = 0
|
||||
var/_has_battery = 0
|
||||
var/_has_aislot = 0
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/New()
|
||||
. = ..()
|
||||
@@ -15,6 +16,8 @@
|
||||
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)
|
||||
if(_has_aislot)
|
||||
cpu.ai_slot = new/obj/item/weapon/computer_hardware/ai_slot(cpu)
|
||||
install_programs()
|
||||
|
||||
// Override in child types to install preset-specific programs.
|
||||
@@ -46,11 +49,13 @@
|
||||
/obj/machinery/modular_computer/console/preset/research
|
||||
console_department = "Research"
|
||||
desc = "A stationary computer. This one comes preloaded with research programs."
|
||||
_has_aislot = 1
|
||||
|
||||
/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())
|
||||
cpu.hard_drive.store_file(new/datum/computer_file/program/aidiag())
|
||||
|
||||
|
||||
// ===== COMMAND CONSOLE =====
|
||||
@@ -58,11 +63,16 @@
|
||||
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())
|
||||
cpu.hard_drive.store_file(new/datum/computer_file/program/comm())
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/command/main
|
||||
console_department = "Command"
|
||||
desc = "A stationary computer. This one comes preloaded with essential command programs."
|
||||
|
||||
// ===== SECURITY CONSOLE =====
|
||||
/obj/machinery/modular_computer/console/preset/security
|
||||
@@ -70,8 +80,7 @@
|
||||
desc = "A stationary computer. This one comes preloaded with security programs."
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/security/install_programs()
|
||||
return // No security programs exist, yet, but the preset is ready so it may be mapped in.
|
||||
|
||||
cpu.hard_drive.store_file(new/datum/computer_file/program/camera_monitor())
|
||||
|
||||
// ===== CIVILIAN CONSOLE =====
|
||||
/obj/machinery/modular_computer/console/preset/civilian
|
||||
@@ -81,4 +90,3 @@
|
||||
/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())
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
// Global var to track modular computers
|
||||
var/list/global_modular_computers = list()
|
||||
|
||||
// Modular Computer - device that runs various programs and operates with hardware
|
||||
// DO NOT SPAWN THIS TYPE. Use /laptop/ or /console/ instead.
|
||||
/obj/machinery/modular_computer/
|
||||
name = "modular computer"
|
||||
desc = "An advanced computer"
|
||||
desc = "An advanced computer."
|
||||
|
||||
var/battery_powered = 0 // Whether computer should be battery powered. It is set automatically
|
||||
use_power = 0
|
||||
@@ -20,10 +23,13 @@
|
||||
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.
|
||||
@@ -42,9 +48,9 @@
|
||||
if(!cpu || !cpu.enabled)
|
||||
if (!(stat & NOPOWER) || battery_powered)
|
||||
overlays.Add(screen_icon_screensaver)
|
||||
else
|
||||
icon_state = icon_state_unpowered
|
||||
set_light(0)
|
||||
return
|
||||
set_light(light_strength)
|
||||
if(cpu.active_program)
|
||||
overlays.Add(cpu.active_program.program_icon_state ? cpu.active_program.program_icon_state : screen_icon_state_menu)
|
||||
else
|
||||
@@ -59,15 +65,45 @@
|
||||
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 Storage"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(cpu)
|
||||
cpu.eject_usb()
|
||||
|
||||
// Eject AI Card
|
||||
/obj/machinery/modular_computer/verb/eject_ai()
|
||||
set name = "Eject AI Storage"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(cpu)
|
||||
cpu.eject_ai()
|
||||
|
||||
/obj/machinery/modular_computer/New()
|
||||
..()
|
||||
cpu = new(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(var/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)
|
||||
@@ -82,21 +118,22 @@
|
||||
return null
|
||||
|
||||
// Used in following function to reduce copypaste
|
||||
/obj/machinery/modular_computer/proc/power_failure()
|
||||
/obj/machinery/modular_computer/proc/power_failure(var/malfunction = 0)
|
||||
if(cpu && cpu.enabled) // Shut down the computer
|
||||
visible_message("<span class='danger'>\The [src]'s screen flickers [cpu.battery_module ? "\"BATTERY CRITICAL\"" : "\"EXTERNAL POWER LOSS\""] warning as it shuts down unexpectedly.</span>")
|
||||
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
|
||||
update_icon()
|
||||
|
||||
stat |= NOPOWER
|
||||
update_icon()
|
||||
|
||||
// Called by cpu item's process() automatically, handles our power interaction.
|
||||
/obj/machinery/modular_computer/proc/handle_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 && (!powered() || !tesla_link || !tesla_link.enabled)) // Not battery run, but lacking APC connection.
|
||||
else if(!cpu.battery_module && (!powered() || !tesla_link || !tesla_link.enabled || !tesla_link.check_functionality())) // Not battery run, but lacking APC connection.
|
||||
power_failure()
|
||||
return 0
|
||||
else if(stat & NOPOWER)
|
||||
@@ -113,7 +150,7 @@
|
||||
power_usage += CH.power_usage
|
||||
|
||||
// Wireless APC connection exists.
|
||||
if(tesla_link && tesla_link.enabled)
|
||||
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
|
||||
@@ -129,6 +166,9 @@
|
||||
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
|
||||
cpu.battery_module.battery.use(power_usage * CELLRATE)
|
||||
cpu.last_power_usage = power_usage
|
||||
|
||||
@@ -136,10 +176,34 @@
|
||||
/obj/machinery/modular_computer/power_change()
|
||||
if(battery_powered)
|
||||
return
|
||||
else
|
||||
..()
|
||||
..()
|
||||
|
||||
|
||||
/obj/machinery/modular_computer/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
|
||||
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(var/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(var/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(var/obj/item/projectile/Proj)
|
||||
if(cpu)
|
||||
cpu.bullet_act(Proj)
|
||||
|
||||
/obj/machinery/modular_computer/check_eye(var/mob/user)
|
||||
if(cpu)
|
||||
return cpu.check_eye(user)
|
||||
return -1
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
base_active_power_usage = 600
|
||||
max_hardware_size = 3
|
||||
steel_sheet_cost = 20
|
||||
light_strength = 4
|
||||
_max_damage = 300
|
||||
_break_damage = 150
|
||||
|
||||
/obj/machinery/modular_computer/console/buildable/New()
|
||||
..()
|
||||
@@ -27,8 +30,6 @@
|
||||
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)
|
||||
tesla_link.enabled = 1
|
||||
tesla_link.critical = 1 // Consoles don't usually come with cells, and this prevents people from disabling their only power source, as they wouldn't be able to enable it again.
|
||||
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.
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
// The actual laptop
|
||||
/obj/machinery/modular_computer/laptop
|
||||
name = "laptop computer"
|
||||
desc = "A portable computer"
|
||||
desc = "A portable computer."
|
||||
var/obj/item/laptop/portable = null // Portable version of this computer, dropped on alt-click to allow transport. Used by laptops.
|
||||
hardware_flag = PROGRAM_LAPTOP
|
||||
icon_state_unpowered = "laptop-open" // Icon state when the computer is turned off
|
||||
@@ -60,6 +60,9 @@
|
||||
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()
|
||||
..()
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
/datum/computer_file/data
|
||||
var/stored_data = "" // Stored data in string format.
|
||||
filetype = "DAT"
|
||||
var/block_size = 250
|
||||
var/do_not_edit = 0 // Whether the user will be reminded that the file probably shouldn't be edited.
|
||||
|
||||
/datum/computer_file/data/clone()
|
||||
var/datum/computer_file/data/temp = ..()
|
||||
@@ -10,7 +12,7 @@
|
||||
return temp
|
||||
|
||||
// Calculates file size from amount of characters in saved string
|
||||
/datum/computer_file/data/proc/calculate_size(var/block_size = 250)
|
||||
/datum/computer_file/data/proc/calculate_size()
|
||||
size = max(1, round(length(stored_data) / block_size))
|
||||
|
||||
/datum/computer_file/data/logfile
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// /data/ files store data in string format.
|
||||
// They don't contain other logic for now.
|
||||
/datum/computer_file/data/news_article
|
||||
filetype = "XNML"
|
||||
filename = "Unknown News Entry"
|
||||
block_size = 2000 // Results in smaller files
|
||||
do_not_edit = 1 // Editing the file breaks most formatting due to some HTML tags not being accepted as input from average user.
|
||||
var/server_file_path // File path to HTML file that will be loaded on server start. Example: '/news_articles/space_magazine_1.html'. Use the /news_articles/ folder!
|
||||
var/archived // Set to 1 for older stuff
|
||||
|
||||
/datum/computer_file/data/news_article/New(var/load_from_file = 0)
|
||||
..()
|
||||
if(server_file_path && load_from_file)
|
||||
stored_data = file2text(server_file_path)
|
||||
calculate_size()
|
||||
|
||||
|
||||
// NEWS DEFINITIONS BELOW THIS LINE
|
||||
|
||||
// /datum/computer_file/data/news_article/space/vol_one
|
||||
// filename = "SPACE Magazine vol. 1"
|
||||
// server_file_path = 'news_articles/space_magazine_1.html'
|
||||
// archived = 1
|
||||
//
|
||||
// /datum/computer_file/data/news_article/space/vol_two
|
||||
// filename = "SPACE Magazine vol. 2"
|
||||
// server_file_path = 'news_articles/space_magazine_2.html'
|
||||
// archived = 1
|
||||
//
|
||||
// /datum/computer_file/data/news_article/space/vol_three
|
||||
// filename = "SPACE Magazine vol. 3"
|
||||
// server_file_path = 'news_articles/space_magazine_3.html'
|
||||
// archived = 1
|
||||
//
|
||||
// /datum/computer_file/data/news_article/space/vol_four
|
||||
// filename = "SPACE Magazine vol. 4"
|
||||
// server_file_path = 'news_articles/space_magazine_4.html'
|
||||
// archived = 0
|
||||
//
|
||||
// /datum/computer_file/data/news_article/space/vol_five
|
||||
// filename = "SPACE Magazine vol. 5"
|
||||
// server_file_path = 'news_articles/space_magazine_5.html'
|
||||
// archived = 0
|
||||
@@ -2,10 +2,12 @@
|
||||
/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/required_access = null // List of required accesses to run/download the program.
|
||||
var/requires_access_to_run = 1 // Whether the program checks for required_access when run.
|
||||
var/requires_access_to_download = 1 // Whether the program checks for required_access when downloading.
|
||||
var/datum/nano_module/NM = null // If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement ui_interact.
|
||||
var/nanomodule_path = null // Path to nanomodule, make sure to set this if implementing new program.
|
||||
var/running = 0 // Set to 1 when the program is run and back to 0 when it's stopped.
|
||||
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.
|
||||
@@ -20,12 +22,18 @@
|
||||
var/computer_emagged = 0 // Set to 1 if computer that's running us was emagged. Computer updates this every Process() tick
|
||||
var/ui_header = null // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /nano/images/status_icons. Be careful not to use too large images!
|
||||
|
||||
|
||||
/datum/computer_file/program/New(var/obj/item/modular_computer/comp = null)
|
||||
..()
|
||||
if(comp && istype(comp))
|
||||
computer = comp
|
||||
|
||||
/datum/computer_file/program/Destroy()
|
||||
computer = null
|
||||
. = ..()
|
||||
|
||||
/datum/computer_file/program/nano_host()
|
||||
return computer.nano_host()
|
||||
|
||||
/datum/computer_file/program/clone()
|
||||
var/datum/computer_file/program/temp = ..()
|
||||
temp.required_access = required_access
|
||||
@@ -55,6 +63,11 @@
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/computer_file/program/proc/get_signal(var/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
|
||||
@@ -69,6 +82,9 @@
|
||||
if(!access_to_check) // No required_access, allow it.
|
||||
return 1
|
||||
|
||||
if(!istype(user))
|
||||
return 0
|
||||
|
||||
var/obj/item/weapon/card/id/I = user.GetIdCard()
|
||||
if(!I)
|
||||
if(loud)
|
||||
@@ -90,19 +106,18 @@
|
||||
// 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(var/mob/living/user)
|
||||
if(can_run(user, 1))
|
||||
if(can_run(user, 1) || !requires_access_to_run)
|
||||
if(nanomodule_path)
|
||||
NM = new nanomodule_path(computer) // Computer is passed here as it's (probably!) physical object. Some UI's perform get_turf() and passing program datum wouldn't go well with this.
|
||||
NM.program = src // Set the program reference to separate variable, instead.
|
||||
NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src)
|
||||
if(requires_ntnet && network_destination)
|
||||
generate_network_log("Connection opened to [network_destination].")
|
||||
running = 1
|
||||
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(var/forced = 0)
|
||||
running = 0
|
||||
program_state = PROGRAM_STATE_KILLED
|
||||
if(network_destination)
|
||||
generate_network_log("Connection to [network_destination] closed.")
|
||||
if(NM)
|
||||
@@ -113,7 +128,7 @@
|
||||
// This is called every tick when the program is enabled. Ensure you do parent call if you override it. If parent returns 1 continue with UI initialisation.
|
||||
// It returns 0 if it can't run or if NanoModule was used instead. I suggest using NanoModules where applicable.
|
||||
/datum/computer_file/program/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(!running) // Our program was closed. Close the ui if it exists.
|
||||
if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists.
|
||||
if(ui)
|
||||
ui.close()
|
||||
return computer.ui_interact(user)
|
||||
@@ -133,3 +148,10 @@
|
||||
return 1
|
||||
if(computer)
|
||||
return computer.Topic(href, href_list)
|
||||
|
||||
// Relays the call to nano module, if we have one
|
||||
/datum/computer_file/program/proc/check_eye(var/mob/user)
|
||||
if(NM)
|
||||
return NM.check_eye(user)
|
||||
else
|
||||
return -1
|
||||
|
||||
@@ -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(var/background)
|
||||
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(var/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(var/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,31 @@
|
||||
/obj/machinery/modular_computer/initial_data()
|
||||
return cpu ? cpu.get_header_data() : ..()
|
||||
|
||||
/obj/item/modular_computer/initial_data()
|
||||
return get_header_data()
|
||||
|
||||
/obj/machinery/modular_computer/update_layout()
|
||||
return TRUE
|
||||
|
||||
/obj/item/modular_computer/update_layout()
|
||||
return TRUE
|
||||
|
||||
/datum/nano_module/program
|
||||
available_to_ai = FALSE
|
||||
var/datum/computer_file/program/program = null // Program-Based computer program that runs this nano module. Defaults to null.
|
||||
|
||||
/datum/nano_module/program/New(var/host, var/topic_manager, var/program)
|
||||
..()
|
||||
src.program = program
|
||||
|
||||
/datum/topic_manager/program
|
||||
var/datum/program
|
||||
|
||||
/datum/topic_manager/program/New(var/datum/program)
|
||||
..()
|
||||
src.program = program
|
||||
|
||||
// Calls forwarded to PROGRAM itself should begin with "PRG_"
|
||||
// Calls forwarded to COMPUTER running the program should begin with "PC_"
|
||||
/datum/topic_manager/program/Topic(href, href_list)
|
||||
return program && program.Topic(href, href_list)
|
||||
@@ -0,0 +1,117 @@
|
||||
/datum/computer_file/program/aidiag
|
||||
filename = "aidiag"
|
||||
filedesc = "AI Maintenance Utility"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program is capable of reconstructing damaged AI systems. It can also be used to upload basic laws to the AI. Requires direct AI connection via intellicard slot."
|
||||
size = 12
|
||||
requires_ntnet = 0
|
||||
required_access = access_heads
|
||||
requires_access_to_run = 0
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/program/computer_aidiag/
|
||||
var/restoring = 0
|
||||
|
||||
/datum/computer_file/program/aidiag/proc/get_ai()
|
||||
if(computer && computer.ai_slot && computer.ai_slot.check_functionality() && computer.ai_slot.enabled && computer.ai_slot.stored_card && computer.ai_slot.stored_card.carded_ai)
|
||||
return computer.ai_slot.stored_card.carded_ai
|
||||
return null
|
||||
|
||||
/datum/computer_file/program/aidiag/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
var/mob/living/silicon/ai/A = get_ai()
|
||||
if(!A)
|
||||
return 0
|
||||
if(href_list["PRG_beginReconstruction"])
|
||||
if((A.hardware_integrity() < 100) || (A.backup_capacitor() < 100))
|
||||
restoring = 1
|
||||
return 1
|
||||
|
||||
// Following actions can only be used by non-silicon users, as they involve manipulation of laws.
|
||||
if(issilicon(usr))
|
||||
return 0
|
||||
if(href_list["PRG_purgeAiLaws"])
|
||||
A.laws.clear_zeroth_laws()
|
||||
A.laws.clear_ion_laws()
|
||||
A.laws.clear_inherent_laws()
|
||||
A.laws.clear_supplied_laws()
|
||||
A << "<span class='danger'>All laws purged.</span>"
|
||||
return 1
|
||||
if(href_list["PRG_resetLaws"])
|
||||
A.laws.clear_ion_laws()
|
||||
A.laws.clear_supplied_laws()
|
||||
A << "<span class='danger'>Non-core laws reset.</span>"
|
||||
return 1
|
||||
if(href_list["PRG_uploadNTDefault"])
|
||||
A.laws = new/datum/ai_laws/nanotrasen
|
||||
A << "<span class='danger'>All laws purged. NT Default lawset uploaded.</span>"
|
||||
return 1
|
||||
if(href_list["PRG_addCustomSuppliedLaw"])
|
||||
var/law_to_add = sanitize(input("Please enter a new law for the AI.", "Custom Law Entry"))
|
||||
var/sector = input("Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority (15+)") as num
|
||||
sector = between(MIN_SUPPLIED_LAW_NUMBER, sector, MAX_SUPPLIED_LAW_NUMBER)
|
||||
A.add_supplied_law(sector, law_to_add)
|
||||
A << "<span class='danger'>Custom law uploaded to sector [sector]: [law_to_add].</span>"
|
||||
return 1
|
||||
|
||||
|
||||
/datum/computer_file/program/aidiag/process_tick()
|
||||
var/mob/living/silicon/ai/A = get_ai()
|
||||
if(!A || !restoring)
|
||||
restoring = 0 // If the AI was removed, stop the restoration sequence.
|
||||
return
|
||||
A.adjustFireLoss(-4)
|
||||
A.adjustBruteLoss(-4)
|
||||
A.adjustOxyLoss(-4)
|
||||
A.updatehealth()
|
||||
// If the AI is dead, revive it.
|
||||
if (A.health >= -100 && A.stat == DEAD)
|
||||
A.stat = CONSCIOUS
|
||||
A.lying = 0
|
||||
A.switch_from_dead_to_living_mob_list()
|
||||
A.add_ai_verbs()
|
||||
A.updateicon()
|
||||
var/obj/item/weapon/aicard/AC = A.loc
|
||||
if(AC)
|
||||
AC.update_icon()
|
||||
// Finished restoring
|
||||
if((A.hardware_integrity() == 100) && (A.backup_capacitor() == 100))
|
||||
restoring = 0
|
||||
|
||||
/datum/nano_module/program/computer_aidiag
|
||||
name = "AI Maintenance Utility"
|
||||
|
||||
/datum/nano_module/program/computer_aidiag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
var/mob/living/silicon/ai/A
|
||||
// A shortcut for getting the AI stored inside the computer. The program already does necessary checks.
|
||||
if(program && istype(program, /datum/computer_file/program/aidiag))
|
||||
var/datum/computer_file/program/aidiag/AD = program
|
||||
A = AD.get_ai()
|
||||
|
||||
if(!A)
|
||||
data["error"] = "No AI located"
|
||||
else
|
||||
data["ai_name"] = A.name
|
||||
data["ai_integrity"] = A.hardware_integrity()
|
||||
data["ai_capacitor"] = A.backup_capacitor()
|
||||
data["ai_isdamaged"] = (A.hardware_integrity() < 100) || (A.backup_capacitor() < 100)
|
||||
data["ai_isdead"] = (A.stat == DEAD)
|
||||
|
||||
var/list/all_laws[0]
|
||||
for(var/datum/ai_law/L in A.laws.all_laws())
|
||||
all_laws.Add(list(list(
|
||||
"index" = L.index,
|
||||
"text" = L.law
|
||||
)))
|
||||
|
||||
data["ai_laws"] = all_laws
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "aidiag.tmpl", "AI Maintenance Utility", 600, 400, state = state)
|
||||
if(host.update_layout())
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
@@ -7,7 +7,7 @@
|
||||
requires_ntnet = 1
|
||||
available_on_ntnet = 0
|
||||
available_on_syndinet = 1
|
||||
nanomodule_path = /datum/nano_module/computer_dos/
|
||||
nanomodule_path = /datum/nano_module/program/computer_dos/
|
||||
var/obj/machinery/ntnet_relay/target = null
|
||||
var/dos_speed = 0
|
||||
var/error = ""
|
||||
@@ -17,29 +17,30 @@
|
||||
dos_speed = 0
|
||||
switch(ntnet_status)
|
||||
if(1)
|
||||
dos_speed = NTNETSPEED_LOWSIGNAL * 10
|
||||
dos_speed = NTNETSPEED_LOWSIGNAL * NTNETSPEED_DOS_AMPLIFICATION
|
||||
if(2)
|
||||
dos_speed = NTNETSPEED_HIGHSIGNAL * 10
|
||||
dos_speed = NTNETSPEED_HIGHSIGNAL * NTNETSPEED_DOS_AMPLIFICATION
|
||||
if(3)
|
||||
dos_speed = NTNETSPEED_ETHERNET * 10
|
||||
dos_speed = NTNETSPEED_ETHERNET * NTNETSPEED_DOS_AMPLIFICATION
|
||||
if(target && executed)
|
||||
target.dos_overload += dos_speed
|
||||
if(target.is_operational())
|
||||
if(!target.operable())
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
error = "Connection to destination relay lost."
|
||||
|
||||
/datum/computer_file/program/ntnet_dos/kill_program(var/forced)
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
if(target)
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
executed = 0
|
||||
|
||||
..(forced)
|
||||
|
||||
/datum/nano_module/computer_dos
|
||||
/datum/nano_module/program/computer_dos
|
||||
name = "DoS Traffic Generator"
|
||||
|
||||
/datum/nano_module/computer_dos/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/nano_module/program/computer_dos/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(!ntnet_global)
|
||||
return
|
||||
var/datum/computer_file/program/ntnet_dos/PRG = program
|
||||
@@ -89,8 +90,9 @@
|
||||
target = R
|
||||
return 1
|
||||
if(href_list["PRG_reset"])
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
if(target)
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
executed = 0
|
||||
error = ""
|
||||
return 1
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/datum/computer_file/program/camera_monitor/hacked
|
||||
filename = "camcrypt"
|
||||
filedesc = "Camera Decryption Tool"
|
||||
nanomodule_path = /datum/nano_module/camera_monitor/hacked
|
||||
program_icon_state = "hostile"
|
||||
extended_desc = "This very advanced piece of software uses adaptive programming and large database of cipherkeys to bypass most encryptions used on camera networks. Be warned that system administrator may notice this."
|
||||
size = 73 // Very large, a price for bypassing ID checks completely.
|
||||
available_on_ntnet = 0
|
||||
available_on_syndinet = 1
|
||||
|
||||
/datum/computer_file/program/camera_monitor/hacked/process_tick()
|
||||
..()
|
||||
if(program_state != PROGRAM_STATE_ACTIVE) // Background programs won't trigger alarms.
|
||||
return
|
||||
|
||||
var/datum/nano_module/camera_monitor/hacked/HNM = NM
|
||||
|
||||
// The program is active and connected to one of the station's networks. Has a very small chance to trigger IDS alarm every tick.
|
||||
if(HNM.current_network && (HNM.current_network in station_networks) && prob(0.1))
|
||||
if(ntnet_global.intrusion_detection_enabled)
|
||||
ntnet_global.add_log("IDS WARNING - Unauthorised access detected to camera network [HNM.current_network] by device with NID [computer.network_card.get_network_tag()]")
|
||||
ntnet_global.intrusion_detection_alarm = 1
|
||||
|
||||
|
||||
/datum/nano_module/camera_monitor/hacked
|
||||
name = "Hacked Camera Monitoring Program"
|
||||
available_to_ai = FALSE
|
||||
|
||||
/datum/nano_module/camera_monitor/hacked/can_access_network(var/mob/user, var/network_access)
|
||||
return 1
|
||||
|
||||
// The hacked variant has access to all commonly used networks.
|
||||
/datum/nano_module/camera_monitor/hacked/modify_networks_list(var/list/networks)
|
||||
networks.Add(list(list("tag" = NETWORK_MERCENARY, "has_access" = 1)))
|
||||
networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1)))
|
||||
networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1)))
|
||||
return networks
|
||||
@@ -7,7 +7,7 @@
|
||||
requires_ntnet = 0
|
||||
available_on_ntnet = 0
|
||||
available_on_syndinet = 1
|
||||
nanomodule_path = /datum/nano_module/revelation/
|
||||
nanomodule_path = /datum/nano_module/program/revelation/
|
||||
var/armed = 0
|
||||
|
||||
/datum/computer_file/program/revelation/run_program(var/mob/living/user)
|
||||
@@ -56,10 +56,10 @@
|
||||
temp.armed = armed
|
||||
return temp
|
||||
|
||||
/datum/nano_module/revelation
|
||||
/datum/nano_module/program/revelation
|
||||
name = "Revelation Virus"
|
||||
|
||||
/datum/nano_module/revelation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/nano_module/program/revelation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = list()
|
||||
var/datum/computer_file/program/revelation/PRG = program
|
||||
if(!istype(PRG))
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
// Returns which access is relevant to passed network. Used by the program.
|
||||
/proc/get_camera_access(var/network)
|
||||
if(!network)
|
||||
return 0
|
||||
|
||||
switch(network)
|
||||
if(NETWORK_THUNDER)
|
||||
return 0
|
||||
if(NETWORK_ENGINE,NETWORK_ENGINEERING,NETWORK_ENGINEERING_OUTPOST,NETWORK_ALARM_ATMOS,NETWORK_ALARM_FIRE,NETWORK_ALARM_POWER)
|
||||
return access_engine
|
||||
if(NETWORK_MEDICAL)
|
||||
return access_medical
|
||||
if(NETWORK_RESEARCH,NETWORK_RESEARCH_OUTPOST)
|
||||
return access_research
|
||||
if(NETWORK_MINE,NETWORK_SUPPLY,NETWORK_CIVILIAN_WEST,NETWORK_EXPEDITION,NETWORK_CALYPSO,NETWORK_POD)
|
||||
return access_mailsorting // Cargo office - all cargo staff should have access here.
|
||||
if(NETWORK_COMMAND,NETWORK_TELECOM)
|
||||
return access_heads
|
||||
if(NETWORK_CRESCENT,NETWORK_ERT)
|
||||
return access_cent_specops
|
||||
|
||||
return access_security // Default for all other networks
|
||||
|
||||
/datum/computer_file/program/camera_monitor
|
||||
filename = "cammon"
|
||||
filedesc = "Camera Monitoring"
|
||||
nanomodule_path = /datum/nano_module/camera_monitor
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program allows remote access to station's camera system. Some camera networks may have additional access requirements."
|
||||
size = 12
|
||||
available_on_ntnet = 1
|
||||
requires_ntnet = 1
|
||||
|
||||
/datum/nano_module/camera_monitor
|
||||
name = "Camera Monitoring program"
|
||||
var/obj/machinery/camera/current_camera = null
|
||||
var/current_network = null
|
||||
|
||||
/datum/nano_module/camera_monitor/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
data["current_camera"] = current_camera ? current_camera.nano_structure() : null
|
||||
data["current_network"] = current_network
|
||||
|
||||
var/list/all_networks[0]
|
||||
for(var/network in station_networks)
|
||||
all_networks.Add(list(list(
|
||||
"tag" = network,
|
||||
"has_access" = can_access_network(user, get_camera_access(network))
|
||||
)))
|
||||
|
||||
all_networks = modify_networks_list(all_networks)
|
||||
|
||||
data["networks"] = all_networks
|
||||
|
||||
if(current_network)
|
||||
data["cameras"] = camera_repository.cameras_in_network(current_network)
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "sec_camera.tmpl", "Camera Monitoring", 900, 800, state = state)
|
||||
// ui.auto_update_layout = 1 // Disabled as with suit sensors monitor - breaks the UI map. Re-enable once it's fixed somehow.
|
||||
|
||||
ui.add_template("mapContent", "sec_camera_map_content.tmpl")
|
||||
ui.add_template("mapHeader", "sec_camera_map_header.tmpl")
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
// Intended to be overriden by subtypes to manually add non-station networks to the list.
|
||||
/datum/nano_module/camera_monitor/proc/modify_networks_list(var/list/networks)
|
||||
return networks
|
||||
|
||||
/datum/nano_module/camera_monitor/proc/can_access_network(var/mob/user, var/network_access)
|
||||
// No access passed, or 0 which is considered no access requirement. Allow it.
|
||||
if(!network_access)
|
||||
return 1
|
||||
|
||||
return check_access(user, access_security) || check_access(user, network_access)
|
||||
|
||||
/datum/nano_module/camera_monitor/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["switch_camera"])
|
||||
var/obj/machinery/camera/C = locate(href_list["switch_camera"]) in cameranet.cameras
|
||||
if(!C)
|
||||
return
|
||||
if(!(current_network in C.network))
|
||||
return
|
||||
|
||||
switch_to_camera(usr, C)
|
||||
return 1
|
||||
|
||||
else if(href_list["switch_network"])
|
||||
// Either security access, or access to the specific camera network's department is required in order to access the network.
|
||||
if(can_access_network(usr, get_camera_access(href_list["switch_network"])))
|
||||
current_network = href_list["switch_network"]
|
||||
else
|
||||
to_chat(usr, "\The [nano_host()] shows an \"Network Access Denied\" error message.")
|
||||
return 1
|
||||
|
||||
else if(href_list["reset"])
|
||||
reset_current()
|
||||
usr.reset_view(current_camera)
|
||||
return 1
|
||||
|
||||
/datum/nano_module/camera_monitor/proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C)
|
||||
//don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras.
|
||||
if(isAI(user))
|
||||
var/mob/living/silicon/ai/A = user
|
||||
// Only allow non-carded AIs to view because the interaction with the eye gets all wonky otherwise.
|
||||
if(!A.is_in_chassis())
|
||||
return 0
|
||||
|
||||
A.eyeobj.setLoc(get_turf(C))
|
||||
A.client.eye = A.eyeobj
|
||||
return 1
|
||||
|
||||
set_current(C)
|
||||
user.machine = nano_host()
|
||||
user.reset_view(current_camera)
|
||||
check_eye(user)
|
||||
return 1
|
||||
|
||||
/datum/nano_module/camera_monitor/proc/set_current(var/obj/machinery/camera/C)
|
||||
if(current_camera == C)
|
||||
return
|
||||
|
||||
if(current_camera)
|
||||
reset_current()
|
||||
|
||||
current_camera = C
|
||||
if(current_camera)
|
||||
var/mob/living/L = current_camera.loc
|
||||
if(istype(L))
|
||||
L.tracking_initiated()
|
||||
|
||||
/datum/nano_module/camera_monitor/proc/reset_current()
|
||||
if(current_camera)
|
||||
var/mob/living/L = current_camera.loc
|
||||
if(istype(L))
|
||||
L.tracking_cancelled()
|
||||
current_camera = null
|
||||
|
||||
/datum/nano_module/camera_monitor/check_eye(var/mob/user as mob)
|
||||
if(!current_camera)
|
||||
return 0
|
||||
var/viewflag = current_camera.check_eye(user)
|
||||
if ( viewflag < 0 ) //camera doesn't work
|
||||
reset_current()
|
||||
return viewflag
|
||||
|
||||
|
||||
// ERT Variant of the program
|
||||
/datum/computer_file/program/camera_monitor/ert
|
||||
filename = "ntcammon"
|
||||
filedesc = "Advanced Camera Monitoring"
|
||||
extended_desc = "This program allows remote access to station's camera system. Some camera networks may have additional access requirements. This version has an integrated database with additional encrypted keys."
|
||||
size = 14
|
||||
nanomodule_path = /datum/nano_module/camera_monitor/ert
|
||||
available_on_ntnet = 0
|
||||
|
||||
/datum/nano_module/camera_monitor/ert
|
||||
name = "Advanced Camera Monitoring Program"
|
||||
available_to_ai = FALSE
|
||||
|
||||
// The ERT variant has access to ERT and crescent cams, but still checks for accesses. ERT members should be able to use it.
|
||||
/datum/nano_module/camera_monitor/ert/modify_networks_list(var/list/networks)
|
||||
..()
|
||||
networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1)))
|
||||
networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1)))
|
||||
return networks
|
||||
@@ -1,23 +1,21 @@
|
||||
/datum/computer_file/program/card_mod
|
||||
filename = "cardmod"
|
||||
filedesc = "ID card modification program"
|
||||
nanomodule_path = /datum/nano_module/card_mod
|
||||
nanomodule_path = /datum/nano_module/program/card_mod
|
||||
program_icon_state = "id"
|
||||
extended_desc = "Program for programming employee ID cards to access parts of the station."
|
||||
required_access = access_change_ids
|
||||
requires_ntnet = 0
|
||||
size = 8
|
||||
|
||||
/datum/nano_module/card_mod
|
||||
/datum/nano_module/program/card_mod
|
||||
name = "ID card modification program"
|
||||
var/mod_mode = 1
|
||||
var/is_centcom = 0
|
||||
var/show_assignments = 0
|
||||
|
||||
/datum/nano_module/card_mod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = list()
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
/datum/nano_module/program/card_mod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
data["src"] = "\ref[src]"
|
||||
data["station_name"] = station_name()
|
||||
@@ -89,7 +87,7 @@
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/datum/nano_module/card_mod/proc/format_jobs(list/jobs)
|
||||
/datum/nano_module/program/card_mod/proc/format_jobs(list/jobs)
|
||||
var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card
|
||||
var/list/formatted = list()
|
||||
for(var/job in jobs)
|
||||
@@ -100,8 +98,7 @@
|
||||
|
||||
return formatted
|
||||
|
||||
/datum/nano_module/card_mod/proc/get_accesses(var/is_centcom = 0)
|
||||
|
||||
/datum/nano_module/program/card_mod/proc/get_accesses(var/is_centcom = 0)
|
||||
return null
|
||||
|
||||
|
||||
@@ -112,7 +109,7 @@
|
||||
var/mob/user = usr
|
||||
var/obj/item/weapon/card/id/user_id_card = user.GetIdCard()
|
||||
var/obj/item/weapon/card/id/id_card = computer.card_slot.stored_card
|
||||
var/datum/nano_module/card_mod/module = NM
|
||||
var/datum/nano_module/program/card_mod/module = NM
|
||||
switch(href_list["action"])
|
||||
if("switchm")
|
||||
if(href_list["target"] == "mod")
|
||||
@@ -147,7 +144,7 @@
|
||||
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'>[computer] prints out paper.</span>")
|
||||
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
|
||||
else
|
||||
var/contents = {"<h4>Crew Manifest</h4>
|
||||
<br>
|
||||
@@ -157,7 +154,7 @@
|
||||
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'>[computer] prints out paper.</span>")
|
||||
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
|
||||
if("eject")
|
||||
if(computer && computer.card_slot)
|
||||
if(id_card)
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
#define STATE_DEFAULT 1
|
||||
#define STATE_MESSAGELIST 2
|
||||
#define STATE_VIEWMESSAGE 3
|
||||
#define STATE_STATUSDISPLAY 4
|
||||
#define STATE_ALERT_LEVEL 5
|
||||
/datum/computer_file/program/comm
|
||||
filename = "comm"
|
||||
filedesc = "Command and communications program."
|
||||
program_icon_state = "comm"
|
||||
nanomodule_path = /datum/nano_module/program/comm
|
||||
extended_desc = "Used to command and control the station. Can relay long-range communications."
|
||||
required_access = access_heads
|
||||
requires_ntnet = 1
|
||||
size = 12
|
||||
usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP
|
||||
network_destination = "station long-range communication array"
|
||||
var/datum/comm_message_listener/message_core = new
|
||||
|
||||
/datum/computer_file/program/comm/clone()
|
||||
var/datum/computer_file/program/comm/temp = ..()
|
||||
temp.message_core.messages = null
|
||||
temp.message_core.messages = message_core.messages.Copy()
|
||||
return temp
|
||||
|
||||
/datum/nano_module/program/comm
|
||||
name = "Command and communications program"
|
||||
available_to_ai = TRUE
|
||||
var/current_status = STATE_DEFAULT
|
||||
var/msg_line1 = ""
|
||||
var/msg_line2 = ""
|
||||
var/centcomm_message_cooldown = 0
|
||||
var/announcment_cooldown = 0
|
||||
var/datum/announcement/priority/crew_announcement = new
|
||||
var/current_viewing_message_id = 0
|
||||
var/current_viewing_message = null
|
||||
|
||||
/datum/nano_module/program/comm/New()
|
||||
..()
|
||||
crew_announcement.newscast = 1
|
||||
|
||||
/datum/nano_module/program/comm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
if(program)
|
||||
data["emagged"] = program.computer_emagged
|
||||
data["net_comms"] = !!program.get_signal(NTNET_COMMUNICATION) //Double !! is needed to get 1 or 0 answer
|
||||
data["net_syscont"] = !!program.get_signal(NTNET_SYSTEMCONTROL)
|
||||
if(program.computer)
|
||||
data["have_printer"] = !!program.computer.nano_printer
|
||||
else
|
||||
data["have_printer"] = 0
|
||||
else
|
||||
data["emagged"] = 0
|
||||
data["net_comms"] = 1
|
||||
data["net_syscont"] = 1
|
||||
data["have_printer"] = 0
|
||||
|
||||
data["message_line1"] = msg_line1
|
||||
data["message_line2"] = msg_line2
|
||||
data["state"] = current_status
|
||||
data["isAI"] = issilicon(usr)
|
||||
data["authenticated"] = is_autenthicated(user)
|
||||
data["boss_short"] = boss_short
|
||||
data["current_security_level"] = security_level
|
||||
data["current_security_level_title"] = num2seclevel(security_level)
|
||||
|
||||
data["def_SEC_LEVEL_DELTA"] = SEC_LEVEL_DELTA
|
||||
data["def_SEC_LEVEL_BLUE"] = SEC_LEVEL_BLUE
|
||||
data["def_SEC_LEVEL_GREEN"] = SEC_LEVEL_GREEN
|
||||
|
||||
var/datum/comm_message_listener/l = obtain_message_listener()
|
||||
data["messages"] = l.messages
|
||||
data["message_deletion_allowed"] = l != global_message_listener
|
||||
data["message_current_id"] = current_viewing_message_id
|
||||
if(current_viewing_message)
|
||||
data["message_current"] = current_viewing_message
|
||||
|
||||
if(emergency_shuttle.location())
|
||||
data["have_shuttle"] = 1
|
||||
if(emergency_shuttle.online())
|
||||
data["have_shuttle_called"] = 1
|
||||
else
|
||||
data["have_shuttle_called"] = 0
|
||||
else
|
||||
data["have_shuttle"] = 0
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "communication.tmpl", name, 550, 420, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/datum/nano_module/program/comm/proc/is_autenthicated(var/mob/user)
|
||||
if(program)
|
||||
return program.can_run(user)
|
||||
return 1
|
||||
|
||||
/datum/nano_module/program/comm/proc/obtain_message_listener()
|
||||
if(program)
|
||||
var/datum/computer_file/program/comm/P = program
|
||||
return P.message_core
|
||||
return global_message_listener
|
||||
|
||||
/datum/nano_module/program/comm/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
var/mob/user = usr
|
||||
var/ntn_comm = !!program.get_signal(NTNET_COMMUNICATION)
|
||||
var/ntn_cont = !!program.get_signal(NTNET_SYSTEMCONTROL)
|
||||
var/datum/comm_message_listener/l = obtain_message_listener()
|
||||
switch(href_list["action"])
|
||||
if("sw_menu")
|
||||
current_status = text2num(href_list["target"])
|
||||
if("announce")
|
||||
if(is_autenthicated(user) && !issilicon(usr) && ntn_comm)
|
||||
if(user)
|
||||
var/obj/item/weapon/card/id/id_card = user.GetIdCard()
|
||||
crew_announcement.announcer = GetNameAndAssignmentFromId(id_card)
|
||||
else
|
||||
crew_announcement.announcer = "Unknown"
|
||||
if(announcment_cooldown)
|
||||
usr << "Please allow at least one minute to pass between announcements"
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|text
|
||||
if(!input || !can_still_topic())
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
crew_announcement.Announce(input)
|
||||
announcment_cooldown = 1
|
||||
spawn(600)//One minute cooldown
|
||||
announcment_cooldown = 0
|
||||
if("message")
|
||||
if(href_list["target"] == "emagged")
|
||||
if(program)
|
||||
if(is_autenthicated(user) && program.computer_emagged && !issilicon(usr) && ntn_comm)
|
||||
if(centcomm_message_cooldown)
|
||||
usr << "<span class='warning'>Arrays recycling. Please stand by.</span>"
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text)
|
||||
if(!input || !can_still_topic())
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
Syndicate_announce(input, usr)
|
||||
usr << "<span class='notice'>Message transmitted.</span>"
|
||||
log_say("[key_name(usr)] has made an illegal announcement: [input]")
|
||||
centcomm_message_cooldown = 1
|
||||
spawn(300)//30 second cooldown
|
||||
centcomm_message_cooldown = 0
|
||||
else if(href_list["target"] == "regular")
|
||||
if(is_autenthicated(user) && !issilicon(usr) && ntn_comm)
|
||||
if(centcomm_message_cooldown)
|
||||
usr << "<span class='warning'>Arrays recycling. Please stand by.</span>"
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
if(!is_relay_online())//Contact Centcom has a check, Syndie doesn't to allow for Traitor funs.
|
||||
usr <<"<span class='warning'>No Emergency Bluespace Relay detected. Unable to transmit message.</span>"
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
var/input = sanitize(input("Please choose a message to transmit to [boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text)
|
||||
if(!input || !can_still_topic())
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
Centcomm_announce(input, usr)
|
||||
usr << "<span class='notice'>Message transmitted.</span>"
|
||||
log_say("[key_name(usr)] has made an IA [boss_short] announcement: [input]")
|
||||
centcomm_message_cooldown = 1
|
||||
spawn(300) //30 second cooldown
|
||||
centcomm_message_cooldown = 0
|
||||
if("shuttle")
|
||||
if(is_autenthicated(user) && ntn_cont)
|
||||
if(href_list["target"] == "call")
|
||||
var/confirm = alert("Are you sure you want to call the shuttle?", name, "No", "Yes")
|
||||
if(confirm == "Yes" && can_still_topic())
|
||||
call_shuttle_proc(usr)
|
||||
if(href_list["target"] == "cancel" && !issilicon(usr))
|
||||
var/confirm = alert("Are you sure you want to cancel the shuttle?", name, "No", "Yes")
|
||||
if(confirm == "Yes" && can_still_topic())
|
||||
cancel_call_proc(usr)
|
||||
if("setstatus")
|
||||
if(is_autenthicated(user) && ntn_cont)
|
||||
switch(href_list["target"])
|
||||
if("line1")
|
||||
var/linput = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", msg_line1) as text|null, 40), 40)
|
||||
if(can_still_topic())
|
||||
msg_line1 = linput
|
||||
if("line2")
|
||||
var/linput = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", msg_line2) as text|null, 40), 40)
|
||||
if(can_still_topic())
|
||||
msg_line2 = linput
|
||||
if("message")
|
||||
post_status("message", msg_line1, msg_line2)
|
||||
if("alert")
|
||||
post_status("alert", href_list["alert"])
|
||||
else
|
||||
post_status(href_list["target"])
|
||||
|
||||
if("setalert")
|
||||
if(is_autenthicated(user) && !issilicon(usr) && ntn_cont && ntn_comm)
|
||||
var/current_level = text2num(href_list["target"])
|
||||
var/confirm = alert("Are you sure you want to change alert level to [num2seclevel(current_level)]?", name, "No", "Yes")
|
||||
if(confirm == "Yes" && can_still_topic())
|
||||
var/old_level = security_level
|
||||
if(!current_level) current_level = SEC_LEVEL_GREEN
|
||||
if(current_level < SEC_LEVEL_GREEN) current_level = SEC_LEVEL_GREEN
|
||||
if(current_level > SEC_LEVEL_BLUE) current_level = SEC_LEVEL_BLUE //Cannot engage delta with this
|
||||
set_security_level(current_level)
|
||||
if(security_level != old_level)
|
||||
log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
|
||||
message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
|
||||
switch(security_level)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
feedback_inc("alert_comms_green",1)
|
||||
if(SEC_LEVEL_BLUE)
|
||||
feedback_inc("alert_comms_blue",1)
|
||||
else
|
||||
usr << "You press button, but red light flashes and nothing happens." //This should never happen
|
||||
current_status = STATE_DEFAULT
|
||||
if("viewmessage")
|
||||
if(is_autenthicated(user) && ntn_comm)
|
||||
current_viewing_message_id = text2num(href_list["target"])
|
||||
for(var/list/m in l.messages)
|
||||
if(m["id"] == current_viewing_message_id)
|
||||
current_viewing_message = m
|
||||
current_status = STATE_VIEWMESSAGE
|
||||
if("delmessage")
|
||||
if(is_autenthicated(user) && ntn_comm && l != global_message_listener)
|
||||
l.Remove(current_viewing_message)
|
||||
current_status = STATE_MESSAGELIST
|
||||
if("printmessage")
|
||||
if(is_autenthicated(user) && ntn_comm)
|
||||
if(program && program.computer && program.computer.nano_printer)
|
||||
if(!program.computer.nano_printer.print_text(current_viewing_message["contents"],current_viewing_message["title"]))
|
||||
usr << "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>"
|
||||
else
|
||||
program.computer.visible_message("<span class='notice'>\The [program.computer] prints out paper.</span>")
|
||||
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
/datum/nano_module/program/comm/proc/post_status(var/command, var/data1, var/data2)
|
||||
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
|
||||
var/datum/signal/status_signal = new
|
||||
status_signal.source = src
|
||||
status_signal.transmission_method = 1
|
||||
status_signal.data["command"] = command
|
||||
|
||||
switch(command)
|
||||
if("message")
|
||||
status_signal.data["msg1"] = data1
|
||||
status_signal.data["msg2"] = data2
|
||||
log_admin("STATUS: [key_name(usr)] set status screen message with [src]: [data1] [data2]")
|
||||
if("alert")
|
||||
status_signal.data["picture_state"] = data1
|
||||
|
||||
frequency.post_signal(src, status_signal)
|
||||
|
||||
#undef STATE_DEFAULT
|
||||
#undef STATE_MESSAGELIST
|
||||
#undef STATE_VIEWMESSAGE
|
||||
#undef STATE_STATUSDISPLAY
|
||||
#undef STATE_ALERT_LEVEL
|
||||
|
||||
/*
|
||||
General message handling stuff
|
||||
*/
|
||||
var/list/comm_message_listeners = list() //We first have to initialize list then we can use it.
|
||||
var/datum/comm_message_listener/global_message_listener = new //May be used by admins
|
||||
var/last_message_id = 0
|
||||
|
||||
/proc/get_comm_message_id()
|
||||
last_message_id = last_message_id + 1
|
||||
return last_message_id
|
||||
|
||||
/proc/post_comm_message(var/message_title, var/message_text)
|
||||
var/list/message = list()
|
||||
message["id"] = get_comm_message_id()
|
||||
message["title"] = message_title
|
||||
message["contents"] = message_text
|
||||
|
||||
for (var/datum/comm_message_listener/l in comm_message_listeners)
|
||||
l.Add(message)
|
||||
|
||||
//Old console support
|
||||
for (var/obj/machinery/computer/communications/comm in machines)
|
||||
if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept)
|
||||
var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc )
|
||||
intercept.name = message_title
|
||||
intercept.info = message_text
|
||||
|
||||
comm.messagetitle.Add(message_title)
|
||||
comm.messagetext.Add(message_text)
|
||||
|
||||
/datum/comm_message_listener
|
||||
var/list/messages
|
||||
|
||||
/datum/comm_message_listener/New()
|
||||
..()
|
||||
messages = list()
|
||||
comm_message_listeners.Add(src)
|
||||
|
||||
/datum/comm_message_listener/proc/Add(var/list/message)
|
||||
messages[++messages.len] = message
|
||||
|
||||
/datum/comm_message_listener/proc/Remove(var/list/message)
|
||||
messages -= list(message)
|
||||
@@ -12,13 +12,13 @@
|
||||
size = 4
|
||||
available_on_ntnet = 0
|
||||
requires_ntnet = 0
|
||||
nanomodule_path = /datum/nano_module/computer_configurator/
|
||||
nanomodule_path = /datum/nano_module/program/computer_configurator/
|
||||
|
||||
/datum/nano_module/computer_configurator
|
||||
/datum/nano_module/program/computer_configurator
|
||||
name = "NTOS Computer Configuration Tool"
|
||||
var/obj/item/modular_computer/movable = null
|
||||
|
||||
/datum/nano_module/computer_configurator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/nano_module/program/computer_configurator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(program)
|
||||
movable = program.computer
|
||||
if(!istype(movable))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#define MAX_TEXTFILE_LENGTH 128000 // 512GQ file
|
||||
/datum/computer_file/program/filemanager
|
||||
filename = "filemanager"
|
||||
filedesc = "NTOS File Manager"
|
||||
@@ -7,7 +8,7 @@
|
||||
requires_ntnet = 0
|
||||
available_on_ntnet = 0
|
||||
undeletable = 1
|
||||
nanomodule_path = /datum/nano_module/computer_filemanager/
|
||||
nanomodule_path = /datum/nano_module/program/computer_filemanager/
|
||||
var/open_file
|
||||
var/error
|
||||
|
||||
@@ -83,8 +84,16 @@
|
||||
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
|
||||
if(!F || !istype(F))
|
||||
return 1
|
||||
// 16384 is the limit for file length in characters. Currently, papers have value of 2048 so this is 8 times as long, since we can't edit parts of the file independently.
|
||||
var/newtext = sanitize(html_decode(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", F.stored_data) as message), 16384)
|
||||
if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No"))
|
||||
return 1
|
||||
|
||||
var/oldtext = html_decode(F.stored_data)
|
||||
oldtext = replacetext(oldtext, "\[editorbr\]", "\n")
|
||||
|
||||
var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[editorbr\]"), MAX_TEXTFILE_LENGTH)
|
||||
if(!newtext)
|
||||
return
|
||||
|
||||
if(F)
|
||||
var/datum/computer_file/data/backup = F.clone()
|
||||
HDD.remove_file(F)
|
||||
@@ -94,7 +103,7 @@
|
||||
// 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>"
|
||||
error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:<br><br>[html_decode(F.stored_data)]<br><br>"
|
||||
HDD.store_file(backup)
|
||||
if(href_list["PRG_printfile"])
|
||||
. = 1
|
||||
@@ -109,7 +118,7 @@
|
||||
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)))
|
||||
if(!computer.nano_printer.print_text(pencode2html(F.stored_data)))
|
||||
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
|
||||
return 1
|
||||
if(href_list["PRG_copytousb"])
|
||||
@@ -137,56 +146,14 @@
|
||||
if(.)
|
||||
nanomanager.update_uis(NM)
|
||||
|
||||
/datum/computer_file/program/filemanager/proc/parse_tags(var/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\]", "[worlddate2text()]")
|
||||
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/nano_module/computer_filemanager
|
||||
/datum/nano_module/program/computer_filemanager
|
||||
name = "NTOS File Manager"
|
||||
|
||||
/datum/nano_module/computer_filemanager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
|
||||
/datum/nano_module/program/computer_filemanager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
var/datum/computer_file/program/filemanager/PRG
|
||||
var/list/data = list()
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
PRG = program
|
||||
else
|
||||
return
|
||||
//var/list/data = program.get_header_data()
|
||||
PRG = program
|
||||
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD
|
||||
@@ -203,7 +170,7 @@
|
||||
if(!istype(file))
|
||||
data["error"] = "I/O ERROR: Unable to open file."
|
||||
else
|
||||
data["filedata"] = PRG.parse_tags(file.stored_data)
|
||||
data["filedata"] = pencode2html(file.stored_data)
|
||||
data["filename"] = "[file.filename].[file.filetype]"
|
||||
else
|
||||
if(!PRG.computer || !PRG.computer.hard_drive)
|
||||
@@ -238,5 +205,4 @@
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
|
||||
#undef MAX_TEXTFILE_LENGTH
|
||||
@@ -0,0 +1,151 @@
|
||||
// This file is used as a reference for Modular Computers Development guide on the wiki. It contains a lot of excess comments, as it is intended as explanation
|
||||
// for someone who may not be as experienced in coding. When making changes, please try to keep it this way.
|
||||
|
||||
// An actual program definition.
|
||||
/datum/computer_file/program/game
|
||||
filename = "arcadec" // File name, as shown in the file browser program.
|
||||
filedesc = "Unknown Game" // User-Friendly name. In this case, we will generate a random name in constructor.
|
||||
program_icon_state = "game" // Icon state of this program's screen.
|
||||
extended_desc = "Fun for the whole family! Probably not an AAA title, but at least you can download it on the corporate network.." // A nice description.
|
||||
size = 5 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs.
|
||||
requires_ntnet = 0 // This particular program does not require NTNet network conectivity...
|
||||
available_on_ntnet = 1 // ... but we want it to be available for download.
|
||||
nanomodule_path = /datum/nano_module/arcade_classic/ // Path of relevant nano module. The nano module is defined further in the file.
|
||||
var/picked_enemy_name
|
||||
|
||||
// Blatantly stolen and shortened version from arcade machines. Generates a random enemy name
|
||||
/datum/computer_file/program/game/proc/random_enemy_name()
|
||||
var/name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ", "the vibrating bluespace")
|
||||
var/name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "Slime", "Lizard Man", "Unicorn", "Squirrel")
|
||||
return "[name_part1] [name_part2]"
|
||||
|
||||
// When the program is first created, we generate a new enemy name and name ourselves accordingly.
|
||||
/datum/computer_file/program/game/New()
|
||||
..()
|
||||
picked_enemy_name = random_enemy_name()
|
||||
filedesc = "Defeat [picked_enemy_name]"
|
||||
|
||||
// Important in order to ensure that copied versions will have the same enemy name.
|
||||
/datum/computer_file/program/game/clone()
|
||||
var/datum/computer_file/program/game/G = ..()
|
||||
G.picked_enemy_name = picked_enemy_name
|
||||
return G
|
||||
|
||||
// When running the program, we also want to pass our enemy name to the nano module.
|
||||
/datum/computer_file/program/game/run_program()
|
||||
. = ..()
|
||||
if(. && NM)
|
||||
var/datum/nano_module/arcade_classic/NMC = NM
|
||||
NMC.enemy_name = picked_enemy_name
|
||||
|
||||
|
||||
// Nano module the program uses.
|
||||
// This can be either /datum/nano_module/ or /datum/nano_module/program. The latter is intended for nano modules that are suposed to be exclusively used with modular computers,
|
||||
// and should generally not be used, as such nano modules are hard to use on other places.
|
||||
/datum/nano_module/arcade_classic/
|
||||
name = "Classic Arcade"
|
||||
var/player_mana // Various variables specific to the nano module. In this case, the nano module is a simple arcade game, so the variables store health and other stats.
|
||||
var/player_health
|
||||
var/enemy_mana
|
||||
var/enemy_health
|
||||
var/enemy_name = "Greytide Horde"
|
||||
var/gameover
|
||||
var/information
|
||||
|
||||
/datum/nano_module/arcade_classic/New()
|
||||
..()
|
||||
new_game()
|
||||
|
||||
// ui_interact handles transfer of data to NanoUI. Keep in mind that data you pass from here is actually sent to the client. In other words, don't send anything you don't want a client
|
||||
// to see, and don't send unnecessarily large amounts of data (due to laginess).
|
||||
/datum/nano_module/arcade_classic/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
data["player_health"] = player_health
|
||||
data["player_mana"] = player_mana
|
||||
data["enemy_health"] = enemy_health
|
||||
data["enemy_mana"] = enemy_mana
|
||||
data["enemy_name"] = enemy_name
|
||||
data["gameover"] = gameover
|
||||
data["information"] = information
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "arcade_classic.tmpl", "Defeat [enemy_name]", 500, 350, state = state)
|
||||
if(host.update_layout())
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
// Three helper procs i've created. These are unique to this particular nano module. If you are creating your own nano module, you'll most likely create similar procs too.
|
||||
/datum/nano_module/arcade_classic/proc/enemy_play()
|
||||
if((enemy_mana < 5) && prob(60))
|
||||
var/steal = rand(2, 3)
|
||||
player_mana -= steal
|
||||
enemy_mana += steal
|
||||
information += "[enemy_name] steals [steal] of your power!"
|
||||
else if((enemy_health < 15) && (enemy_mana > 3) && prob(80))
|
||||
var/healamt = min(rand(3, 5), enemy_mana)
|
||||
enemy_mana -= healamt
|
||||
enemy_health += healamt
|
||||
information += "[enemy_name] heals for [healamt] health!"
|
||||
else
|
||||
var/dam = rand(3,6)
|
||||
player_health -= dam
|
||||
information += "[enemy_name] attacks for [dam] damage!"
|
||||
|
||||
/datum/nano_module/arcade_classic/proc/check_gameover()
|
||||
if((player_health <= 0) || player_mana <= 0)
|
||||
if(enemy_health <= 0)
|
||||
information += "You have defeated [enemy_name], but you have died in the fight!"
|
||||
else
|
||||
information += "You have been defeated by [enemy_name]!"
|
||||
gameover = 1
|
||||
return TRUE
|
||||
else if(enemy_health <= 0)
|
||||
gameover = 1
|
||||
information += "Congratulations! You have defeated [enemy_name]!"
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nano_module/arcade_classic/proc/new_game()
|
||||
player_mana = 10
|
||||
player_health = 30
|
||||
enemy_mana = 20
|
||||
enemy_health = 45
|
||||
gameover = FALSE
|
||||
information = "A new game has started!"
|
||||
|
||||
|
||||
|
||||
/datum/nano_module/arcade_classic/Topic(href, href_list)
|
||||
if(..()) // Always begin your Topic() calls with a parent call!
|
||||
return 1
|
||||
if(href_list["new_game"])
|
||||
new_game()
|
||||
return 1 // Returning 1 (TRUE) in Topic automatically handles UI updates.
|
||||
if(gameover) // If the game has already ended, we don't want the following three topic calls to be processed at all.
|
||||
return 1 // Instead of adding checks into each of those three, we can easily add this one check here to reduce on code copy-paste.
|
||||
if(href_list["attack"])
|
||||
var/damage = rand(2, 6)
|
||||
information = "You attack for [damage] damage."
|
||||
enemy_health -= damage
|
||||
enemy_play()
|
||||
check_gameover()
|
||||
return 1
|
||||
if(href_list["heal"])
|
||||
var/healfor = rand(6, 8)
|
||||
var/cost = rand(1, 3)
|
||||
information = "You heal yourself for [healfor] damage, using [cost] energy in the process."
|
||||
player_health += healfor
|
||||
player_mana -= cost
|
||||
enemy_play()
|
||||
check_gameover()
|
||||
return 1
|
||||
if(href_list["regain_mana"])
|
||||
var/regen = rand(4, 7)
|
||||
information = "You rest of a while, regaining [regen] energy."
|
||||
player_mana += regen
|
||||
enemy_play()
|
||||
check_gameover()
|
||||
return 1
|
||||
@@ -0,0 +1,129 @@
|
||||
/datum/computer_file/program/newsbrowser
|
||||
filename = "newsbrowser"
|
||||
filedesc = "NTNet/ExoNet News Browser"
|
||||
extended_desc = "This program may be used to view and download news articles from the network."
|
||||
program_icon_state = "generic"
|
||||
size = 8
|
||||
requires_ntnet = 1
|
||||
available_on_ntnet = 1
|
||||
|
||||
nanomodule_path = /datum/nano_module/program/computer_newsbrowser/
|
||||
var/datum/computer_file/data/news_article/loaded_article
|
||||
var/download_progress = 0
|
||||
var/download_netspeed = 0
|
||||
var/downloading = 0
|
||||
var/message = ""
|
||||
var/show_archived = 0
|
||||
|
||||
/datum/computer_file/program/newsbrowser/process_tick()
|
||||
if(!downloading)
|
||||
return
|
||||
download_netspeed = 0
|
||||
// Speed defines are found in misc.dm
|
||||
switch(ntnet_status)
|
||||
if(1)
|
||||
download_netspeed = NTNETSPEED_LOWSIGNAL
|
||||
if(2)
|
||||
download_netspeed = NTNETSPEED_HIGHSIGNAL
|
||||
if(3)
|
||||
download_netspeed = NTNETSPEED_ETHERNET
|
||||
download_progress += download_netspeed
|
||||
if(download_progress >= loaded_article.size)
|
||||
downloading = 0
|
||||
requires_ntnet = 0 // Turn off NTNet requirement as we already loaded the file into local memory.
|
||||
nanomanager.update_uis(NM)
|
||||
|
||||
/datum/computer_file/program/newsbrowser/kill_program()
|
||||
..()
|
||||
requires_ntnet = 1
|
||||
loaded_article = null
|
||||
download_progress = 0
|
||||
downloading = 0
|
||||
show_archived = 0
|
||||
|
||||
/datum/computer_file/program/newsbrowser/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["PRG_openarticle"])
|
||||
. = 1
|
||||
if(downloading || loaded_article)
|
||||
return 1
|
||||
|
||||
for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news)
|
||||
if(N.uid == text2num(href_list["PRG_openarticle"]))
|
||||
loaded_article = N.clone()
|
||||
downloading = 1
|
||||
break
|
||||
if(href_list["PRG_reset"])
|
||||
. = 1
|
||||
downloading = 0
|
||||
download_progress = 0
|
||||
requires_ntnet = 1
|
||||
loaded_article = null
|
||||
if(href_list["PRG_clearmessage"])
|
||||
. = 1
|
||||
message = ""
|
||||
if(href_list["PRG_savearticle"])
|
||||
. = 1
|
||||
if(downloading || !loaded_article)
|
||||
return
|
||||
|
||||
var/savename = sanitize(input(usr, "Enter file name or leave blank to cancel:", "Save article", loaded_article.filename))
|
||||
if(!savename)
|
||||
return 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/data/news_article/N = loaded_article.clone()
|
||||
N.filename = savename
|
||||
HDD.store_file(N)
|
||||
if(href_list["PRG_toggle_archived"])
|
||||
. = 1
|
||||
show_archived = !show_archived
|
||||
if(.)
|
||||
nanomanager.update_uis(NM)
|
||||
|
||||
|
||||
/datum/nano_module/program/computer_newsbrowser
|
||||
name = "NTNet/ExoNet News Browser"
|
||||
|
||||
/datum/nano_module/program/computer_newsbrowser/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
|
||||
var/datum/computer_file/program/newsbrowser/PRG
|
||||
var/list/data = list()
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
PRG = program
|
||||
else
|
||||
return
|
||||
|
||||
data["message"] = PRG.message
|
||||
if(PRG.loaded_article && !PRG.downloading) // Viewing an article.
|
||||
data["title"] = PRG.loaded_article.filename
|
||||
data["article"] = PRG.loaded_article.stored_data
|
||||
else if(PRG.downloading) // Downloading an article.
|
||||
data["download_running"] = 1
|
||||
data["download_progress"] = PRG.download_progress
|
||||
data["download_maxprogress"] = PRG.loaded_article.size
|
||||
data["download_rate"] = PRG.download_netspeed
|
||||
else // Viewing list of articles
|
||||
var/list/all_articles[0]
|
||||
for(var/datum/computer_file/data/news_article/F in ntnet_global.available_news)
|
||||
if(!PRG.show_archived && F.archived)
|
||||
continue
|
||||
all_articles.Add(list(list(
|
||||
"name" = F.filename,
|
||||
"size" = F.size,
|
||||
"uid" = F.uid,
|
||||
"archived" = F.archived
|
||||
)))
|
||||
data["all_articles"] = all_articles
|
||||
data["showing_archived"] = PRG.show_archived
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "news_browser.tmpl", "NTNet/ExoNet News Browser", 575, 700, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
requires_ntnet = 1
|
||||
requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD
|
||||
available_on_ntnet = 0
|
||||
nanomodule_path = /datum/nano_module/computer_ntnetdownload/
|
||||
nanomodule_path = /datum/nano_module/program/computer_ntnetdownload/
|
||||
ui_header = "downloader_finished.gif"
|
||||
var/datum/computer_file/program/downloaded_file = null
|
||||
var/hacked_download = 0
|
||||
@@ -102,7 +102,7 @@
|
||||
download_netspeed += delta
|
||||
download_netspeed = round(download_netspeed, 0.002)//3 decimal places
|
||||
|
||||
var/delta_seconds = (download_last_update - world.time) * 10
|
||||
var/delta_seconds = (world.time - download_last_update) / 10
|
||||
|
||||
download_completion = min(download_completion + delta_seconds * download_netspeed, downloaded_file.size)
|
||||
|
||||
@@ -130,11 +130,11 @@
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/nano_module/computer_ntnetdownload
|
||||
/datum/nano_module/program/computer_ntnetdownload
|
||||
name = "Network Downloader"
|
||||
var/obj/item/modular_computer/my_computer = null
|
||||
|
||||
/datum/nano_module/computer_ntnetdownload/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/nano_module/program/computer_ntnetdownload/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(program)
|
||||
my_computer = program.computer
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
var/list/all_entries[0]
|
||||
for(var/datum/computer_file/program/P in ntnet_global.available_station_software)
|
||||
// Only those programs our user can run will show in the list
|
||||
if(!P.can_run(user))
|
||||
if(!P.can_run(user) && P.requires_access_to_download)
|
||||
continue
|
||||
all_entries.Add(list(list(
|
||||
"filename" = P.filename,
|
||||
|
||||
@@ -11,15 +11,12 @@
|
||||
|
||||
/datum/nano_module/computer_ntnetmonitor
|
||||
name = "NTNet Diagnostics and Monitoring"
|
||||
available_to_ai = TRUE
|
||||
|
||||
/datum/nano_module/computer_ntnetmonitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(!ntnet_global)
|
||||
return
|
||||
|
||||
var/list/data = list()
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
data["ntnetstatus"] = ntnet_global.check_function()
|
||||
data["ntnetrelays"] = ntnet_global.relays.len
|
||||
@@ -38,7 +35,8 @@
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "ntnet_monitor.tmpl", "NTNet Diagnostics and Monitoring Tool", 575, 700, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
if(host.update_layout())
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
network_destination = "NTNRC server"
|
||||
ui_header = "ntnrc_idle.gif"
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/computer_chatclient/
|
||||
nanomodule_path = /datum/nano_module/program/computer_chatclient/
|
||||
var/last_message = null // Used to generate the toolbar icon
|
||||
var/username
|
||||
var/datum/ntnet_conversation/channel = null
|
||||
@@ -159,7 +159,7 @@
|
||||
|
||||
/datum/computer_file/program/chatclient/process_tick()
|
||||
..()
|
||||
if(running)
|
||||
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.
|
||||
@@ -178,10 +178,10 @@
|
||||
channel = null
|
||||
..(forced)
|
||||
|
||||
/datum/nano_module/computer_chatclient
|
||||
/datum/nano_module/program/computer_chatclient
|
||||
name = "NTNet Relay Chat Client"
|
||||
|
||||
/datum/nano_module/computer_chatclient/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/nano_module/program/computer_chatclient/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(!ntnet_global || !ntnet_global.chat_channels)
|
||||
return
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ var/global/nttransfer_uid = 0
|
||||
requires_ntnet_feature = NTNET_PEERTOPEER
|
||||
network_destination = "other device via P2P tunnel"
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/computer_nttransfer/
|
||||
nanomodule_path = /datum/nano_module/program/computer_nttransfer/
|
||||
|
||||
var/error = "" // Error screen
|
||||
var/server_password = "" // Optional password to download the file.
|
||||
@@ -87,13 +87,10 @@ var/global/nttransfer_uid = 0
|
||||
download_completion = 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/datum/nano_module/computer_nttransfer
|
||||
/datum/nano_module/program/computer_nttransfer
|
||||
name = "NTNet P2P Transfer Client"
|
||||
|
||||
/datum/nano_module/computer_nttransfer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/nano_module/program/computer_nttransfer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(!program)
|
||||
return
|
||||
var/datum/computer_file/program/nttransfer/PRG = program
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// A wrapper that allows the computer to contain an intellicard.
|
||||
/obj/item/weapon/computer_hardware/ai_slot
|
||||
name = "intellicard slot"
|
||||
desc = "An IIS interlink with connection uplinks that allow the device to interface with most common intellicard models. Too large to fit into tablets. Uses a lot of power when active."
|
||||
icon_state = "aislot"
|
||||
hardware_size = 2
|
||||
critical = 0
|
||||
power_usage = 100
|
||||
origin_tech = list(TECH_POWER = 2, TECH_DATA = 3)
|
||||
var/obj/item/weapon/aicard/stored_card
|
||||
var/power_usage_idle = 100
|
||||
var/power_usage_occupied = 2 KILOWATTS
|
||||
|
||||
/obj/item/weapon/computer_hardware/ai_slot/proc/update_power_usage()
|
||||
if(!stored_card || !stored_card.carded_ai)
|
||||
power_usage = power_usage_idle
|
||||
return
|
||||
power_usage = power_usage_occupied
|
||||
|
||||
/obj/item/weapon/computer_hardware/ai_slot/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
|
||||
if(..())
|
||||
return 1
|
||||
if(istype(W, /obj/item/weapon/aicard))
|
||||
if(stored_card)
|
||||
user << "\The [src] is already occupied."
|
||||
return
|
||||
user.drop_from_inventory(W)
|
||||
stored_card = W
|
||||
W.forceMove(src)
|
||||
update_power_usage()
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
user << "You manually remove \the [stored_card] from \the [src]."
|
||||
stored_card.forceMove(get_turf(src))
|
||||
stored_card = null
|
||||
update_power_usage()
|
||||
|
||||
/obj/item/weapon/computer_hardware/ai_slot/Destroy()
|
||||
if(holder2 && (holder2.ai_slot == src))
|
||||
holder2.ai_slot = null
|
||||
if(stored_card)
|
||||
stored_card.forceMove(get_turf(holder2))
|
||||
holder2 = null
|
||||
..()
|
||||
@@ -5,7 +5,8 @@
|
||||
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(TECH_POWER = 1, TECH_ENGINEERING = 1)
|
||||
var/battery_rating = 750
|
||||
var/obj/item/weapon/cell/battery = null
|
||||
|
||||
@@ -13,6 +14,7 @@
|
||||
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(TECH_POWER = 2, TECH_ENGINEERING = 2)
|
||||
hardware_size = 2
|
||||
battery_rating = 1100
|
||||
|
||||
@@ -20,6 +22,7 @@
|
||||
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(TECH_POWER = 3, TECH_ENGINEERING = 3)
|
||||
hardware_size = 2
|
||||
battery_rating = 1500
|
||||
|
||||
@@ -27,6 +30,7 @@
|
||||
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(TECH_POWER = 5, TECH_ENGINEERING = 4)
|
||||
hardware_size = 3
|
||||
battery_rating = 2000
|
||||
|
||||
@@ -34,12 +38,14 @@
|
||||
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(TECH_POWER = 2, TECH_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(TECH_POWER = 1, TECH_ENGINEERING = 1)
|
||||
battery_rating = 300
|
||||
|
||||
// This is not intended to be obtainable in-game. Intended for adminbus and debugging purposes.
|
||||
@@ -49,11 +55,20 @@
|
||||
icon_state = "battery_lambda"
|
||||
hardware_size = 1
|
||||
battery_rating = 1000000
|
||||
/obj/item/weapon/computer_hardware/battery_module/lambda/New()
|
||||
..()
|
||||
battery = new/obj/item/weapon/cell/infinite(src)
|
||||
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/diagnostics(var/mob/user)
|
||||
..()
|
||||
user << "Internal battery charge: [battery.charge]/[battery.maxcharge] CU"
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/New()
|
||||
battery = new/obj/item/weapon/cell(src)
|
||||
battery.maxcharge = battery_rating
|
||||
battery.charge = battery_rating
|
||||
..()
|
||||
battery.charge = 0
|
||||
..()
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/proc/charge_to_full()
|
||||
if(battery)
|
||||
battery.charge = battery.maxcharge
|
||||
@@ -5,6 +5,7 @@
|
||||
critical = 0
|
||||
icon_state = "cardreader"
|
||||
hardware_size = 1
|
||||
origin_tech = list(TECH_DATA = 2)
|
||||
|
||||
var/obj/item/weapon/card/id/stored_card = null
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
power_usage = 25 // SSD or something with low power usage
|
||||
icon_state = "hdd_normal"
|
||||
hardware_size = 1
|
||||
origin_tech = list(TECH_DATA = 1, TECH_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!
|
||||
@@ -12,6 +13,7 @@
|
||||
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(TECH_DATA = 2, TECH_ENGINEERING = 2)
|
||||
power_usage = 50 // Hybrid, medium capacity and medium power storage
|
||||
icon_state = "hdd_advanced"
|
||||
hardware_size = 2
|
||||
@@ -20,6 +22,7 @@
|
||||
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(TECH_DATA = 3, TECH_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
|
||||
@@ -28,6 +31,7 @@
|
||||
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(TECH_DATA = 4, TECH_ENGINEERING = 4)
|
||||
max_capacity = 2048
|
||||
icon_state = "hdd_cluster"
|
||||
hardware_size = 3
|
||||
@@ -37,6 +41,7 @@
|
||||
name = "small hard drive"
|
||||
desc = "A small highly efficient solid state drive for portable devices."
|
||||
power_usage = 10
|
||||
origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2)
|
||||
max_capacity = 64
|
||||
icon_state = "hdd_small"
|
||||
hardware_size = 1
|
||||
@@ -45,10 +50,17 @@
|
||||
name = "micro hard drive"
|
||||
desc = "A small micro hard drive for portable devices."
|
||||
power_usage = 2
|
||||
origin_tech = list(TECH_DATA = 1, TECH_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))
|
||||
@@ -57,6 +69,9 @@
|
||||
if(!can_store_file(F.size))
|
||||
return 0
|
||||
|
||||
if(!check_functionality())
|
||||
return 0
|
||||
|
||||
if(!stored_files)
|
||||
return 0
|
||||
|
||||
@@ -84,6 +99,9 @@
|
||||
if(!stored_files)
|
||||
return 0
|
||||
|
||||
if(!check_functionality())
|
||||
return 0
|
||||
|
||||
if(F in stored_files)
|
||||
stored_files -= F
|
||||
recalculate_size()
|
||||
@@ -124,6 +142,9 @@
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
@@ -1,14 +1,53 @@
|
||||
/obj/item/weapon/computer_hardware/
|
||||
name = "Hardware"
|
||||
desc = "Unknown Hardware"
|
||||
desc = "Unknown Hardware."
|
||||
icon = 'icons/obj/modular_components.dmi'
|
||||
var/obj/item/modular_computer/holder2 = null
|
||||
var/power_usage = 0 // If the hardware uses extra power, change this.
|
||||
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/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/nanopaste))
|
||||
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)
|
||||
@@ -20,4 +59,31 @@
|
||||
|
||||
/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 = between(0, damage, max_damage) // Clamp the value.
|
||||
|
||||
|
||||
@@ -1,62 +1,46 @@
|
||||
/obj/item/weapon/computer_hardware/nano_printer
|
||||
name = "nano printer"
|
||||
desc = "Small integrated printer with scanner and paper recycling module."
|
||||
desc = "Small integrated printer with paper recycling module."
|
||||
power_usage = 50
|
||||
origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2)
|
||||
critical = 0
|
||||
icon_state = "printer"
|
||||
hardware_size = 1
|
||||
var/stored_paper = 5
|
||||
var/max_paper = 10
|
||||
var/obj/item/weapon/paper/P = null // Currently stored paper for scanning.
|
||||
|
||||
/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
|
||||
|
||||
// Recycle stored paper
|
||||
if(P)
|
||||
stored_paper++
|
||||
qdel(P)
|
||||
P = null
|
||||
// Damaged printer causes the resulting paper to be somewhat harder to read.
|
||||
if(damage > damage_malfunction)
|
||||
text_to_print = stars(text_to_print, 100-malfunction_probability)
|
||||
new/obj/item/weapon/paper(get_turf(holder2),text_to_print, paper_title)
|
||||
|
||||
P = new/obj/item/weapon/paper(get_turf(holder2))
|
||||
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/proc/load_paper(var/obj/item/weapon/paper/paper)
|
||||
if(!paper || !istype(paper))
|
||||
return 0
|
||||
/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
|
||||
|
||||
// We already have paper loaded, recycle it.
|
||||
if(P && try_recycle_paper())
|
||||
P = paper
|
||||
P.forceMove(holder2)
|
||||
|
||||
/obj/item/weapon/computer_hardware/nano_printer/proc/try_recycle_paper()
|
||||
if(!P)
|
||||
return 0
|
||||
|
||||
if(stored_paper >= max_paper)
|
||||
return 0
|
||||
|
||||
qdel(P)
|
||||
P = null
|
||||
return 1
|
||||
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
|
||||
if(P)
|
||||
if(holder2)
|
||||
P.forceMove(get_turf(holder2))
|
||||
else
|
||||
qdel(P)
|
||||
P = null
|
||||
holder2 = null
|
||||
..()
|
||||
@@ -4,6 +4,7 @@ var/global/ntnet_card_uid = 1
|
||||
name = "basic NTNet network card"
|
||||
desc = "A basic network card for usage with standard NTNet frequencies."
|
||||
power_usage = 50
|
||||
origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 1)
|
||||
critical = 0
|
||||
icon_state = "netcard_basic"
|
||||
hardware_size = 1
|
||||
@@ -11,6 +12,18 @@ var/global/ntnet_card_uid = 1
|
||||
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)
|
||||
@@ -21,14 +34,16 @@ var/global/ntnet_card_uid = 1
|
||||
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(TECH_DATA = 4, TECH_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 NTNet. This one uses wired connection."
|
||||
desc = "An advanced network card for usage with standard NTNet frequencies. This one also supports wired connection."
|
||||
ethernet = 1
|
||||
origin_tech = list(TECH_DATA = 5, TECH_ENGINEERING = 3)
|
||||
power_usage = 100 // Better range but higher power usage.
|
||||
icon_state = "netcard_ethernet"
|
||||
hardware_size = 3
|
||||
@@ -51,6 +66,9 @@ var/global/ntnet_card_uid = 1
|
||||
if(!enabled)
|
||||
return 0
|
||||
|
||||
if(!check_functionality())
|
||||
return 0
|
||||
|
||||
if(ethernet) // Computer is connected via wired connection.
|
||||
return 3
|
||||
|
||||
@@ -60,7 +78,11 @@ var/global/ntnet_card_uid = 1
|
||||
if(holder2)
|
||||
var/turf/T = get_turf(holder2)
|
||||
if((T && istype(T)) && T.z in config.station_levels)
|
||||
return 2
|
||||
// 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
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
// These are basically USB data sticks and may be used to transfer files between devices
|
||||
/obj/item/weapon/computer_hardware/hard_drive/portable/
|
||||
name = "basic data crystal"
|
||||
desc = "Small crystal with imprinted photonic circuits that can be used to store data. It's capacity is 16 GQ"
|
||||
desc = "Small crystal with imprinted photonic circuits that can be used to store data. Its capacity is 16 GQ."
|
||||
power_usage = 10
|
||||
icon_state = "flashdrive_basic"
|
||||
hardware_size = 1
|
||||
max_capacity = 16
|
||||
|
||||
origin_tech = list(TECH_DATA = 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"
|
||||
desc = "Small crystal with imprinted high-density photonic circuits that can be used to store data. Its capacity is 64 GQ."
|
||||
power_usage = 20
|
||||
icon_state = "flashdrive_advanced"
|
||||
hardware_size = 1
|
||||
max_capacity = 64
|
||||
|
||||
origin_tech = list(TECH_DATA = 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"
|
||||
desc = "Small crystal with imprinted ultra-density photonic circuits that can be used to store data. Its capacity is 256 GQ."
|
||||
power_usage = 40
|
||||
icon_state = "flashdrive_super"
|
||||
hardware_size = 1
|
||||
max_capacity = 256
|
||||
origin_tech = list(TECH_DATA = 4)
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/portable/New()
|
||||
..()
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
hardware_size = 2
|
||||
power_usage = 50
|
||||
critical = 1
|
||||
malfunction_probability = 1
|
||||
origin_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 2)
|
||||
|
||||
var/max_idle_programs = 2 // 2 idle, + 1 active = 3 as said in description.
|
||||
|
||||
@@ -18,6 +20,7 @@
|
||||
hardware_size = 1
|
||||
power_usage = 25
|
||||
max_idle_programs = 1
|
||||
origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2)
|
||||
|
||||
/obj/item/weapon/computer_hardware/processor_unit/photonic
|
||||
name = "photonic processor"
|
||||
@@ -26,6 +29,7 @@
|
||||
hardware_size = 2
|
||||
power_usage = 250
|
||||
max_idle_programs = 4
|
||||
origin_tech = list(TECH_DATA = 5, TECH_ENGINEERING = 4)
|
||||
|
||||
/obj/item/weapon/computer_hardware/processor_unit/photonic/small
|
||||
name = "photonic microprocessor"
|
||||
@@ -33,4 +37,5 @@
|
||||
icon_state = "cpu_small_photonic"
|
||||
hardware_size = 1
|
||||
power_usage = 75
|
||||
max_idle_programs = 2
|
||||
max_idle_programs = 2
|
||||
origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 3)
|
||||
@@ -2,9 +2,10 @@
|
||||
name = "tesla link"
|
||||
desc = "An advanced tesla link that wirelessly recharges connected device from nearby area power controller."
|
||||
critical = 0
|
||||
enabled = 0 // Starts turned off
|
||||
enabled = 1
|
||||
icon_state = "teslalink"
|
||||
hardware_size = 2 // Can't be installed into tablets
|
||||
origin_tech = list(TECH_DATA = 2, TECH_POWER = 3, TECH_ENGINEERING = 2)
|
||||
var/obj/machinery/modular_computer/holder
|
||||
|
||||
/obj/item/weapon/computer_hardware/tesla_link/New(var/obj/L)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/obj/machinery/lapvend
|
||||
name = "computer vendor"
|
||||
desc = "A vending machine with microfabricator capable of dispensing various NT-branded computers"
|
||||
desc = "A vending machine with microfabricator capable of dispensing various NT-branded computers."
|
||||
icon = 'icons/obj/vending.dmi'
|
||||
icon_state = "robotics"
|
||||
layer = 2.9
|
||||
@@ -61,46 +61,46 @@
|
||||
fabricated_laptop.cpu.processor_unit = new/obj/item/weapon/computer_hardware/processor_unit(fabricated_laptop.cpu)
|
||||
total_price += 299
|
||||
switch(dev_battery)
|
||||
if(1) // Basic(750C)
|
||||
if(1) //Micro(500C)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.battery_module = new/obj/item/weapon/computer_hardware/battery_module/micro(fabricated_laptop.cpu)
|
||||
if(2) // Basic(750C)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.battery_module = new/obj/item/weapon/computer_hardware/battery_module(fabricated_laptop.cpu)
|
||||
if(2) // Upgraded(1100C)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.battery_module = new/obj/item/weapon/computer_hardware/battery_module/advanced(fabricated_laptop.cpu)
|
||||
total_price += 199
|
||||
if(3) // Advanced(1500C)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.battery_module = new/obj/item/weapon/computer_hardware/battery_module/super(fabricated_laptop.cpu)
|
||||
total_price += 499
|
||||
// if(3) // Upgraded(1100C)
|
||||
// if(fabricate)
|
||||
// fabricated_laptop.cpu.battery_module = new/obj/item/weapon/computer_hardware/battery_module/advanced(fabricated_laptop.cpu)
|
||||
// total_price += 499
|
||||
switch(dev_disk)
|
||||
if(1) // Basic(128GQ)
|
||||
if(1)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/small(fabricated_laptop.cpu)
|
||||
if(2) // Basic(128GQ)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive(fabricated_laptop.cpu)
|
||||
if(2) // Upgraded(256GQ)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/advanced(fabricated_laptop.cpu)
|
||||
total_price += 99
|
||||
if(3) // Advanced(512GQ)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/super(fabricated_laptop.cpu)
|
||||
total_price += 299
|
||||
total_price += 199
|
||||
// if(3) // Upgraded(256GQ)
|
||||
// if(fabricate)
|
||||
// fabricated_laptop.cpu.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/advanced(fabricated_laptop.cpu)
|
||||
// total_price += 299
|
||||
switch(dev_netcard)
|
||||
if(1) // Basic(Short-Range)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.network_card = new/obj/item/weapon/computer_hardware/network_card(fabricated_laptop.cpu)
|
||||
total_price += 99
|
||||
if(2) // Advanced (Long Range)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.network_card = new/obj/item/weapon/computer_hardware/network_card/advanced(fabricated_laptop.cpu)
|
||||
total_price += 299
|
||||
if(dev_tesla)
|
||||
total_price += 399
|
||||
if(fabricate)
|
||||
fabricated_laptop.tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(fabricated_laptop)
|
||||
if(dev_nanoprint)
|
||||
total_price += 99
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(fabricated_laptop.cpu)
|
||||
total_price += 199
|
||||
// if(2) // Advanced (Long Range)
|
||||
// if(fabricate)
|
||||
// fabricated_laptop.cpu.network_card = new/obj/item/weapon/computer_hardware/network_card/advanced(fabricated_laptop.cpu)
|
||||
// total_price += 299
|
||||
// if(dev_tesla)
|
||||
// total_price += 399
|
||||
// if(fabricate)
|
||||
// fabricated_laptop.tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(fabricated_laptop)
|
||||
// if(dev_nanoprint)
|
||||
// total_price += 99
|
||||
// if(fabricate)
|
||||
// fabricated_laptop.cpu.nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(fabricated_laptop.cpu)
|
||||
if(dev_card)
|
||||
total_price += 199
|
||||
if(fabricate)
|
||||
@@ -167,7 +167,8 @@
|
||||
if(href_list["pick_device"])
|
||||
if(state) // We've already picked a device type
|
||||
return 0
|
||||
devtype = text2num(href_list["pick_device"])
|
||||
// devtype = text2num(href_list["pick_device"]) // Currently unavailable
|
||||
devtype = 1
|
||||
state = 1
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
@@ -197,12 +198,12 @@
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if(href_list["hw_tesla"])
|
||||
dev_tesla = text2num(href_list["hw_tesla"])
|
||||
fabricate_and_recalc_price(0)
|
||||
// dev_tesla = text2num(href_list["hw_tesla"]) // Currently unavailable
|
||||
// fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if(href_list["hw_nanoprint"])
|
||||
dev_nanoprint = text2num(href_list["hw_nanoprint"])
|
||||
fabricate_and_recalc_price(0)
|
||||
//dev_nanoprint = text2num(href_list["hw_nanoprint"]) // Currently unavailable
|
||||
// fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if(href_list["hw_card"])
|
||||
dev_card = text2num(href_list["hw_card"])
|
||||
@@ -221,15 +222,17 @@
|
||||
|
||||
var/list/data[0]
|
||||
data["state"] = state
|
||||
data["devtype"] = devtype
|
||||
data["hw_battery"] = dev_battery
|
||||
data["hw_disk"] = dev_disk
|
||||
data["hw_netcard"] = dev_netcard
|
||||
data["hw_tesla"] = dev_tesla
|
||||
data["hw_nanoprint"] = dev_nanoprint
|
||||
data["hw_card"] = dev_card
|
||||
data["hw_cpu"] = dev_cpu
|
||||
data["totalprice"] = "[total_price]$"
|
||||
if(state == 1)
|
||||
data["devtype"] = devtype
|
||||
data["hw_battery"] = dev_battery
|
||||
data["hw_disk"] = dev_disk
|
||||
data["hw_netcard"] = dev_netcard
|
||||
data["hw_tesla"] = dev_tesla
|
||||
data["hw_nanoprint"] = dev_nanoprint
|
||||
data["hw_card"] = dev_card
|
||||
data["hw_cpu"] = dev_cpu
|
||||
if(state == 1 || state == 2)
|
||||
data["totalprice"] = total_price
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
@@ -246,10 +249,12 @@ obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(process_payment(I,W))
|
||||
fabricate_and_recalc_price(1)
|
||||
if((devtype == 1) && fabricated_laptop)
|
||||
fabricated_laptop.cpu.battery_module.charge_to_full()
|
||||
fabricated_laptop.forceMove(src.loc)
|
||||
fabricated_laptop.close_laptop()
|
||||
fabricated_laptop = null
|
||||
else if((devtype == 2) && fabricated_tablet)
|
||||
fabricated_tablet.battery_module.charge_to_full()
|
||||
fabricated_tablet.forceMove(src.loc)
|
||||
fabricated_tablet = null
|
||||
ping("Enjoy your new product!")
|
||||
@@ -291,4 +296,4 @@ obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
T.date = current_date_string
|
||||
T.time = worldtime2text()
|
||||
customer_account.transaction_log.Add(T)
|
||||
return 1
|
||||
return 1
|
||||
|
||||
Reference in New Issue
Block a user