mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 13:38:41 +01:00
Modular PCs rewrite (#20003)
* Modular computers rework, part A * tweaks&fixes * Adds component-side compatibility checks * Moves computers to SSobj * Fixes stationary computers not using power usage vars * Changes icon generation a bit, adds icons to broken computers * Moves UI into it's own file * Laptop refactor + sprite replacement * Modular console's keyboard now lights up when powered * minor fixes * fixes * bonus: wired connector, new type of recharger * Modular computers are now devices * code quality ocd
This commit is contained in:
@@ -42,6 +42,8 @@
|
||||
else
|
||||
use_power = 1
|
||||
|
||||
update_icon()
|
||||
|
||||
if(dos_overload)
|
||||
dos_overload = max(0, dos_overload - dos_dissipate)
|
||||
|
||||
|
||||
@@ -0,0 +1,418 @@
|
||||
// This is the base type that does all the hardware stuff.
|
||||
// Other types expand it - tablets use a direct subtypes, and
|
||||
// consoles and laptops use "procssor" item that is held inside machinery piece
|
||||
/obj/item/device/modular_computer
|
||||
name = "modular microcomputer"
|
||||
desc = "A small portable microcomputer."
|
||||
|
||||
var/enabled = 0 // Whether the computer is turned on.
|
||||
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
|
||||
var/datum/computer_file/program/active_program = null // A currently active program running on the computer.
|
||||
var/hardware_flag = 0 // A flag that describes this device type
|
||||
var/last_power_usage = 0
|
||||
var/last_battery_percent = 0 // Used for deciding if battery percentage has chandged
|
||||
var/last_world_time = "00:00"
|
||||
var/list/last_header_icons
|
||||
var/emagged = 0 // Whether the computer is emagged.
|
||||
|
||||
var/base_active_power_usage = 50 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
|
||||
var/base_idle_power_usage = 5 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
|
||||
|
||||
// Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..)
|
||||
// must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently
|
||||
// If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example.
|
||||
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
icon_state = "laptop-open"
|
||||
var/icon_state_unpowered = null // Icon state when the computer is turned off.
|
||||
var/icon_state_powered = null // Icon state when the computer is turned on.
|
||||
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 w_class. Tablets/PDAs have 1, laptops 2, consoles 4.
|
||||
var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
|
||||
|
||||
// Damage of the chassis. If the chassis takes too much damage it will break apart.
|
||||
var/damage = 0 // Current damage level
|
||||
var/broken_damage = 50 // Damage level at which the computer ceases to operate
|
||||
var/max_damage = 100 // Damage level at which the computer breaks apart.
|
||||
|
||||
// Important hardware (must be installed for computer to work)
|
||||
var/obj/item/weapon/computer_hardware/processor_unit/processor_unit // CPU. Without it the computer won't run. Better CPUs can run more programs at once.
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive // Hard Drive component of this computer. Stores programs and files.
|
||||
|
||||
var/obj/item/weapon/computer_hardware/battery/battery_module // Power cell connector. Power cell can be recharged.
|
||||
// OR
|
||||
var/obj/item/weapon/computer_hardware/recharger/recharger // Recharger. Can be used to recharge power cell or power the PC without it.
|
||||
|
||||
// Optional hardware (improves functionality, but is not critical for computer to work)
|
||||
var/obj/item/weapon/computer_hardware/network_card/network_card // Network Card component of this computer. Allows connection to NTNet.
|
||||
var/obj/item/weapon/computer_hardware/card_slot/card_slot // ID Card slot component of this computer.
|
||||
var/obj/item/weapon/computer_hardware/printer/printer // Printer component of this computer, for your everyday paperwork needs.
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/portable_drive // Portable data storage
|
||||
|
||||
var/list/all_components = list()
|
||||
|
||||
var/list/idle_threads = list() // Idle programs on background. They still receive process calls but can't be interacted with.
|
||||
var/obj/physical = null // Object that represents our computer. It's used for Adjacent() and UI visibility checks.
|
||||
|
||||
|
||||
|
||||
/obj/item/device/modular_computer/New()
|
||||
START_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
if(!physical)
|
||||
physical = src
|
||||
..()
|
||||
|
||||
/obj/item/device/modular_computer/Destroy()
|
||||
kill_program(forced = TRUE)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
for(var/H in all_components)
|
||||
qdel(H)
|
||||
return ..()
|
||||
|
||||
// Eject ID card from computer, if it has ID slot with card inside.
|
||||
/obj/item/device/modular_computer/verb/eject_id()
|
||||
set name = "Eject ID"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(issilicon(usr))
|
||||
return
|
||||
|
||||
if (usr.canUseTopic(src))
|
||||
proc_eject_id(usr)
|
||||
|
||||
// Eject ID card from computer, if it has ID slot with card inside.
|
||||
/obj/item/device/modular_computer/verb/eject_disk()
|
||||
set name = "Eject Data Disk"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(issilicon(usr))
|
||||
return
|
||||
|
||||
if (usr.canUseTopic(src))
|
||||
proc_eject_disk(usr)
|
||||
|
||||
/obj/item/device/modular_computer/proc/proc_eject_id(mob/user, slot)
|
||||
if(!user)
|
||||
user = usr
|
||||
|
||||
if(!card_slot)
|
||||
user << "<span class='warning'>\The [src] does not have an ID card slot!</span>"
|
||||
return
|
||||
|
||||
card_slot.try_eject(slot, user)
|
||||
|
||||
/obj/item/device/modular_computer/proc/proc_eject_disk(mob/user)
|
||||
if(!user)
|
||||
user = usr
|
||||
|
||||
if(!portable_drive)
|
||||
user << "<span class='warning'>There is no data disk in \the [src]!</span>"
|
||||
return
|
||||
|
||||
var/obj/item/I = portable_drive
|
||||
if(uninstall_component(portable_drive, user))
|
||||
I.verb_pickup()
|
||||
|
||||
/obj/item/device/modular_computer/AltClick(mob/user)
|
||||
..()
|
||||
if(issilicon(user))
|
||||
return
|
||||
|
||||
if(user.canUseTopic(src))
|
||||
if(portable_drive)
|
||||
proc_eject_disk(user)
|
||||
else if(card_slot)
|
||||
proc_eject_id(user)
|
||||
|
||||
|
||||
// Gets IDs/access levels from card slot. Would be useful when/if PDAs would become modular PCs.
|
||||
/obj/item/device/modular_computer/GetAccess()
|
||||
if(card_slot)
|
||||
return card_slot.GetAccess()
|
||||
return ..()
|
||||
|
||||
/obj/item/device/modular_computer/GetID()
|
||||
if(card_slot)
|
||||
return card_slot.GetID()
|
||||
return ..()
|
||||
|
||||
/obj/item/device/modular_computer/MouseDrop(obj/over_object, src_location, over_location)
|
||||
var/mob/M = usr
|
||||
if((!istype(over_object, /obj/screen)) && usr.canUseTopic(src))
|
||||
return attack_self(M)
|
||||
return
|
||||
|
||||
/obj/item/device/modular_computer/attack_ghost(mob/dead/observer/user)
|
||||
if(enabled)
|
||||
ui_interact(user)
|
||||
else if(IsAdminGhost(user))
|
||||
var/response = alert(user, "This computer is turned off. Would you like to turn it on?", "Admin Override", "Yes", "No")
|
||||
if(response == "Yes")
|
||||
turn_on(user)
|
||||
|
||||
/obj/item/device/modular_computer/emag_act(mob/user)
|
||||
if(emagged)
|
||||
user << "<span class='warning'>\The [src] was already emagged.</span>"
|
||||
return 0
|
||||
else
|
||||
emagged = 1
|
||||
user << "<span class='notice'>You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.</span>"
|
||||
return 1
|
||||
|
||||
/obj/item/device/modular_computer/examine(mob/user)
|
||||
..()
|
||||
if(damage > broken_damage)
|
||||
user << "<span class='danger'>It is heavily damaged!</span>"
|
||||
else if(damage)
|
||||
user << "<span class='warning'>It is damaged.</span>"
|
||||
|
||||
/obj/item/device/modular_computer/update_icon()
|
||||
cut_overlays()
|
||||
if(!enabled)
|
||||
icon_state = icon_state_unpowered
|
||||
else
|
||||
icon_state = icon_state_powered
|
||||
if(active_program)
|
||||
add_overlay(active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu)
|
||||
else
|
||||
add_overlay(icon_state_menu)
|
||||
|
||||
if(damage > broken_damage)
|
||||
add_overlay("bsod")
|
||||
add_overlay("broken")
|
||||
|
||||
|
||||
// On-click handling. Turns on the computer if it's off and opens the GUI.
|
||||
/obj/item/device/modular_computer/attack_self(mob/user)
|
||||
if(enabled)
|
||||
ui_interact(user)
|
||||
else
|
||||
turn_on(user)
|
||||
|
||||
/obj/item/device/modular_computer/proc/turn_on(mob/user)
|
||||
var/issynth = issilicon(user) // Robots and AIs get different activation messages.
|
||||
if(damage > broken_damage)
|
||||
if(issynth)
|
||||
user << "<span class='warning'>You send an activation signal to \the [src], but it responds with an error code. It must be damaged.</span>"
|
||||
else
|
||||
user << "<span class='warning'>You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again.</span>"
|
||||
return
|
||||
|
||||
// If we have a recharger, enable it automatically. Lets computer without a battery work.
|
||||
if(recharger)
|
||||
recharger.enabled = 1
|
||||
|
||||
if(processor_unit && use_power()) // use_power() checks if the PC is powered
|
||||
if(issynth)
|
||||
user << "<span class='notice'>You send an activation signal to \the [src], turning it on.</span>"
|
||||
else
|
||||
user << "<span class='notice'>You press the power button and start up \the [src].</span>"
|
||||
enabled = 1
|
||||
update_icon()
|
||||
ui_interact(user)
|
||||
else // Unpowered
|
||||
if(issynth)
|
||||
user << "<span class='warning'>You send an activation signal to \the [src] but it does not respond.</span>"
|
||||
else
|
||||
user << "<span class='warning'>You press the power button but \the [src] does not respond.</span>"
|
||||
|
||||
// Process currently calls handle_power(), may be expanded in future if more things are added.
|
||||
/obj/item/device/modular_computer/process()
|
||||
if(!enabled) // The computer is turned off
|
||||
last_power_usage = 0
|
||||
return 0
|
||||
|
||||
if(damage > broken_damage)
|
||||
shutdown_computer()
|
||||
return 0
|
||||
|
||||
if(active_program && active_program.requires_ntnet && !get_ntnet_status(active_program.requires_ntnet_feature))
|
||||
active_program.event_networkfailure(0) // Active program requires NTNet to run but we've just lost connection. Crash.
|
||||
|
||||
for(var/I in idle_threads)
|
||||
var/datum/computer_file/program/P = I
|
||||
if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature))
|
||||
P.event_networkfailure(1)
|
||||
|
||||
if(active_program)
|
||||
if(active_program.program_state != PROGRAM_STATE_KILLED)
|
||||
active_program.process_tick()
|
||||
active_program.ntnet_status = get_ntnet_status()
|
||||
else
|
||||
active_program = null
|
||||
|
||||
for(var/I in idle_threads)
|
||||
var/datum/computer_file/program/P = I
|
||||
if(P.program_state != PROGRAM_STATE_KILLED)
|
||||
P.process_tick()
|
||||
P.ntnet_status = get_ntnet_status()
|
||||
else
|
||||
idle_threads.Remove(P)
|
||||
|
||||
handle_power() // Handles all computer power interaction
|
||||
//check_update_ui_need()
|
||||
|
||||
// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_"
|
||||
/obj/item/device/modular_computer/proc/get_header_data()
|
||||
var/list/data = list()
|
||||
|
||||
if(battery_module && battery_module.battery)
|
||||
switch(battery_module.battery.percent())
|
||||
if(80 to 200) // 100 should be maximal but just in case..
|
||||
data["PC_batteryicon"] = "batt_100.gif"
|
||||
if(60 to 80)
|
||||
data["PC_batteryicon"] = "batt_80.gif"
|
||||
if(40 to 60)
|
||||
data["PC_batteryicon"] = "batt_60.gif"
|
||||
if(20 to 40)
|
||||
data["PC_batteryicon"] = "batt_40.gif"
|
||||
if(5 to 20)
|
||||
data["PC_batteryicon"] = "batt_20.gif"
|
||||
else
|
||||
data["PC_batteryicon"] = "batt_5.gif"
|
||||
data["PC_batterypercent"] = "[round(battery_module.battery.percent())] %"
|
||||
data["PC_showbatteryicon"] = 1
|
||||
else
|
||||
data["PC_batteryicon"] = "batt_5.gif"
|
||||
data["PC_batterypercent"] = "N/C"
|
||||
data["PC_showbatteryicon"] = battery_module ? 1 : 0
|
||||
|
||||
if(recharger && recharger.enabled && recharger.check_functionality() && recharger.use_power(0))
|
||||
data["PC_apclinkicon"] = "charging.gif"
|
||||
|
||||
switch(get_ntnet_status())
|
||||
if(0)
|
||||
data["PC_ntneticon"] = "sig_none.gif"
|
||||
if(1)
|
||||
data["PC_ntneticon"] = "sig_low.gif"
|
||||
if(2)
|
||||
data["PC_ntneticon"] = "sig_high.gif"
|
||||
if(3)
|
||||
data["PC_ntneticon"] = "sig_lan.gif"
|
||||
|
||||
if(idle_threads.len)
|
||||
var/list/program_headers = list()
|
||||
for(var/I in idle_threads)
|
||||
var/datum/computer_file/program/P = I
|
||||
if(!P.ui_header)
|
||||
continue
|
||||
program_headers.Add(list(list(
|
||||
"icon" = P.ui_header
|
||||
)))
|
||||
|
||||
data["PC_programheaders"] = program_headers
|
||||
|
||||
data["PC_stationtime"] = worldtime2text()
|
||||
data["PC_hasheader"] = 1
|
||||
data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen
|
||||
return data
|
||||
|
||||
// Relays kill program request to currently active program. Use this to quit current program.
|
||||
/obj/item/device/modular_computer/proc/kill_program(forced = FALSE)
|
||||
if(active_program)
|
||||
active_program.kill_program(forced)
|
||||
active_program = null
|
||||
var/mob/user = usr
|
||||
if(user && istype(user))
|
||||
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
update_icon()
|
||||
|
||||
// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on)
|
||||
/obj/item/device/modular_computer/proc/get_ntnet_status(specific_action = 0)
|
||||
if(network_card)
|
||||
return network_card.get_signal(specific_action)
|
||||
else
|
||||
return 0
|
||||
|
||||
/obj/item/device/modular_computer/proc/add_log(text)
|
||||
if(!get_ntnet_status())
|
||||
return FALSE
|
||||
return ntnet_global.add_log(text, network_card)
|
||||
|
||||
/obj/item/device/modular_computer/proc/shutdown_computer(loud = 1)
|
||||
kill_program(forced = TRUE)
|
||||
for(var/datum/computer_file/program/P in idle_threads)
|
||||
P.kill_program(forced = TRUE)
|
||||
idle_threads.Remove(P)
|
||||
if(loud)
|
||||
physical.visible_message("<span class='notice'>\The [src] shuts down.</span>")
|
||||
enabled = 0
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/item/device/modular_computer/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
// Insert items into the components
|
||||
for(var/h in all_components)
|
||||
var/obj/item/weapon/computer_hardware/H = h
|
||||
if(H.try_insert(W, user))
|
||||
return
|
||||
|
||||
// Insert new hardware
|
||||
if(istype(W, /obj/item/weapon/computer_hardware))
|
||||
if(install_component(W, user))
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/wrench))
|
||||
if(all_components.len)
|
||||
user << "<span class='warning'>Remove all components from \the [src] before disassembling it.</span>"
|
||||
return
|
||||
new /obj/item/stack/sheet/metal( get_turf(src.loc), steel_sheet_cost )
|
||||
physical.visible_message("\The [src] has been disassembled by [user].")
|
||||
relay_qdel()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(!WT.isOn())
|
||||
user << "<span class='warning'>\The [W] is off.</span>"
|
||||
return
|
||||
|
||||
if(!damage)
|
||||
user << "<span class='warning'>\The [src] does not require repairs.</span>"
|
||||
return
|
||||
|
||||
user << "<span class='notice'>You begin repairing damage to \the [src]...</span>"
|
||||
if(WT.remove_fuel(round(damage/75)) && do_after(usr, damage/10))
|
||||
damage = 0
|
||||
user << "<span class='notice'>You repair \the [src].</span>"
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
if(!all_components.len)
|
||||
user << "<span class='warning'>This device doesn't have any components installed.</span>"
|
||||
return
|
||||
var/list/component_names = list()
|
||||
for(var/obj/item/weapon/computer_hardware/H in all_components)
|
||||
component_names.Add(H.name)
|
||||
|
||||
var/choice = input(usr, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in component_names
|
||||
|
||||
if(!choice)
|
||||
return
|
||||
|
||||
if(!Adjacent(usr))
|
||||
return
|
||||
|
||||
var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(choice)
|
||||
|
||||
if(!H)
|
||||
return
|
||||
|
||||
uninstall_component(H, user)
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
// Used by processor to relay qdel() to machinery type.
|
||||
/obj/item/device/modular_computer/proc/relay_qdel()
|
||||
return
|
||||
|
||||
// Perform adjacency checks on our physical counterpart, if any.
|
||||
/obj/item/device/modular_computer/Adjacent(atom/neighbor)
|
||||
if(physical && physical != src)
|
||||
return physical.Adjacent(neighbor)
|
||||
return ..()
|
||||
@@ -0,0 +1,117 @@
|
||||
/obj/item/device/modular_computer/proc/can_install_component(obj/item/weapon/computer_hardware/H, mob/living/user = null)
|
||||
if(!H.can_install(src, user))
|
||||
return FALSE
|
||||
|
||||
if(H.w_class > max_hardware_size)
|
||||
user << "<span class='warning'>This component is too large for \the [src]!</span>"
|
||||
return FALSE
|
||||
|
||||
if(istype(H, /obj/item/weapon/computer_hardware/hard_drive/portable) && portable_drive)
|
||||
user << "<span class='warning'>This computer's FDD is already occupied by \the [portable_drive].</span>"
|
||||
return FALSE
|
||||
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/processor_unit) && processor_unit)
|
||||
user << "<span class='warning'>This computer's CPU slot is already occupied by \the [processor_unit].</span>"
|
||||
return FALSE
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/hard_drive) && hard_drive)
|
||||
user << "<span class='warning'>This computer's data port is already occupied by \the [hard_drive].</span>"
|
||||
return FALSE
|
||||
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/battery) && battery_module)
|
||||
user << "<span class='warning'>This computer's power converter slot is already occupied by \the [battery_module].</span>"
|
||||
return FALSE
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/recharger) && recharger)
|
||||
user << "<span class='warning'>This computer's recharger slot is already occupied by \the [recharger].</span>"
|
||||
return FALSE
|
||||
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/card_slot) && card_slot)
|
||||
user << "<span class='warning'>This computer's card reader slot is already occupied by \the [card_slot].</span>"
|
||||
return FALSE
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/network_card) && network_card)
|
||||
user << "<span class='warning'>This computer's network card is already occupied by \the [network_card].</span>"
|
||||
return FALSE
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/printer) && printer)
|
||||
user << "<span class='warning'>This computer's printer slot is already occupied by \the [printer].</span>"
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
// Installs component.
|
||||
/obj/item/device/modular_computer/proc/install_component(obj/item/weapon/computer_hardware/H, mob/living/user = null)
|
||||
if(!can_install_component(H, user))
|
||||
return FALSE
|
||||
|
||||
if(user && !user.unEquip(H))
|
||||
return FALSE
|
||||
|
||||
if(istype(H, /obj/item/weapon/computer_hardware/hard_drive/portable))
|
||||
portable_drive = H
|
||||
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/processor_unit))
|
||||
processor_unit = H
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/hard_drive))
|
||||
hard_drive = H
|
||||
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/battery))
|
||||
battery_module = H
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/recharger))
|
||||
recharger = H
|
||||
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/card_slot))
|
||||
card_slot = H
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/network_card))
|
||||
network_card = H
|
||||
else if(istype(H, /obj/item/weapon/computer_hardware/printer))
|
||||
printer = H
|
||||
|
||||
user << "<span class='notice'>You install \the [H] into \the [src].</span>"
|
||||
H.forceMove(src)
|
||||
H.holder = src
|
||||
all_components |= H
|
||||
H.on_install(src, user)
|
||||
return TRUE
|
||||
|
||||
|
||||
// Uninstalls component.
|
||||
/obj/item/device/modular_computer/proc/uninstall_component(obj/item/weapon/computer_hardware/H, mob/living/user = null)
|
||||
if(H.holder != src) // Not our component at all.
|
||||
return FALSE
|
||||
|
||||
if(processor_unit == H)
|
||||
processor_unit = null
|
||||
if(hard_drive == H)
|
||||
hard_drive = null
|
||||
|
||||
if(battery_module == H)
|
||||
battery_module = null
|
||||
if(recharger == H)
|
||||
recharger = null
|
||||
|
||||
if(card_slot == H)
|
||||
card_slot = null
|
||||
if(network_card == H)
|
||||
network_card = null
|
||||
if(printer == H)
|
||||
printer = null
|
||||
if(portable_drive == H)
|
||||
portable_drive = null
|
||||
|
||||
user << "<span class='notice'>You remove \the [H] from \the [src].</span>"
|
||||
|
||||
H.forceMove(get_turf(src))
|
||||
H.holder = null
|
||||
all_components -= H
|
||||
H.on_remove(src, user)
|
||||
if(enabled && (!processor_unit || !hard_drive || !use_power()))
|
||||
shutdown_computer()
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
|
||||
// Checks all hardware pieces to determine if name matches, if yes, returns the hardware piece, otherwise returns null
|
||||
/obj/item/device/modular_computer/proc/find_hardware_by_name(name)
|
||||
for(var/i in all_components)
|
||||
var/obj/O = i
|
||||
if(O.name == name)
|
||||
return O
|
||||
return null
|
||||
@@ -0,0 +1,49 @@
|
||||
/obj/item/device/modular_computer/proc/take_damage(amount, component_probability, damage_casing = 1, randomize = 1)
|
||||
if(randomize)
|
||||
// 75%-125%, rand() works with integers, apparently.
|
||||
amount *= (rand(75, 125) / 100.0)
|
||||
amount = round(amount)
|
||||
if(damage_casing)
|
||||
damage += amount
|
||||
damage = max(0,min(max_damage,damage))
|
||||
|
||||
if(component_probability)
|
||||
for(var/I in all_components)
|
||||
var/obj/item/weapon/computer_hardware/H = I
|
||||
if(prob(component_probability))
|
||||
H.take_damage(round(amount / 2))
|
||||
|
||||
if(damage >= max_damage)
|
||||
break_apart()
|
||||
|
||||
// Stronger explosions cause serious damage to internal components
|
||||
// Minor explosions are mostly mitigitated by casing.
|
||||
/obj/item/device/modular_computer/ex_act(severity)
|
||||
take_damage(rand(100,200)/severity, component_probability = 30/severity)
|
||||
|
||||
// EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components
|
||||
/obj/item/device/modular_computer/emp_act(severity)
|
||||
take_damage(rand(100,200)/severity, component_probability = 50/severity, damage_casing = 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/device/modular_computer/bullet_act(obj/item/projectile/Proj)
|
||||
switch(Proj.damage_type)
|
||||
if(BRUTE)
|
||||
take_damage(Proj.damage, component_probability = Proj.damage/2)
|
||||
if(BURN)
|
||||
take_damage(Proj.damage, component_probability = Proj.damage/1.5)
|
||||
|
||||
/obj/item/device/modular_computer/proc/break_apart()
|
||||
physical.visible_message("\The [src] breaks apart!")
|
||||
var/turf/newloc = get_turf(src)
|
||||
new /obj/item/stack/sheet/metal(newloc, round(steel_sheet_cost/2))
|
||||
for(var/C in all_components)
|
||||
var/obj/item/weapon/computer_hardware/H = C
|
||||
uninstall_component(H)
|
||||
H.forceMove(newloc)
|
||||
if(prob(25))
|
||||
H.take_damage(rand(10,30))
|
||||
relay_qdel()
|
||||
qdel()
|
||||
@@ -0,0 +1,55 @@
|
||||
// Tries to draw power from charger or, if no operational charger is present, from power cell.
|
||||
/obj/item/device/modular_computer/proc/use_power(amount = 0)
|
||||
if(check_power_override())
|
||||
return TRUE
|
||||
|
||||
if(recharger && recharger.check_functionality())
|
||||
if(recharger.use_power(amount))
|
||||
return TRUE
|
||||
|
||||
if(battery_module && battery_module.battery && battery_module.battery.charge)
|
||||
var/obj/item/weapon/stock_parts/cell/cell = battery_module.battery
|
||||
if(cell.use(amount * CELLRATE))
|
||||
return TRUE
|
||||
else // Discharge the cell anyway.
|
||||
cell.use(min(amount*CELLRATE, cell.charge))
|
||||
return FALSE
|
||||
return FALSE
|
||||
|
||||
/obj/item/device/modular_computer/proc/give_power(amount)
|
||||
if(battery_module && battery_module.battery)
|
||||
return battery_module.battery.give(amount)
|
||||
return 0
|
||||
|
||||
|
||||
// Used in following function to reduce copypaste
|
||||
/obj/item/device/modular_computer/proc/power_failure()
|
||||
if(enabled) // Shut down the computer
|
||||
if(active_program)
|
||||
active_program.event_powerfailure(0)
|
||||
for(var/I in idle_threads)
|
||||
var/datum/computer_file/program/PRG = I
|
||||
PRG.event_powerfailure(1)
|
||||
shutdown_computer(0)
|
||||
|
||||
// Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged
|
||||
/obj/item/device/modular_computer/proc/handle_power()
|
||||
if(recharger)
|
||||
recharger.process()
|
||||
|
||||
var/power_usage = screen_on ? base_active_power_usage : base_idle_power_usage
|
||||
|
||||
for(var/obj/item/weapon/computer_hardware/H in all_components)
|
||||
if(H.enabled)
|
||||
power_usage += H.power_usage
|
||||
|
||||
if(use_power(power_usage))
|
||||
last_power_usage = power_usage
|
||||
return TRUE
|
||||
else
|
||||
power_failure()
|
||||
return FALSE
|
||||
|
||||
// Used by child types if they have other power source than battery or recharger
|
||||
/obj/item/device/modular_computer/proc/check_power_override()
|
||||
return FALSE
|
||||
@@ -0,0 +1,132 @@
|
||||
// Operates TGUI
|
||||
/obj/item/device/modular_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
|
||||
if(!enabled)
|
||||
if(ui)
|
||||
ui.close()
|
||||
return 0
|
||||
if(!use_power())
|
||||
if(ui)
|
||||
ui.close()
|
||||
return 0
|
||||
|
||||
// Robots don't really need to see the screen, their wireless connection works as long as computer is on.
|
||||
if(!screen_on && !issilicon(user))
|
||||
if(ui)
|
||||
ui.close()
|
||||
return 0
|
||||
|
||||
// If we have an active program switch to it now.
|
||||
if(active_program)
|
||||
if(ui) // This is the main laptop screen. Since we are switching to program's UI close it for now.
|
||||
ui.close()
|
||||
active_program.ui_interact(user)
|
||||
return
|
||||
|
||||
// We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it.
|
||||
// This screen simply lists available programs and user may select them.
|
||||
if(!hard_drive || !hard_drive.stored_files || !hard_drive.stored_files.len)
|
||||
physical.visible_message("<span class='danger'>\The [src] beeps three times, it's screen displaying \"DISK ERROR\" warning.</span>")
|
||||
return // No HDD, No HDD files list or no stored files. Something is very broken.
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if (!ui)
|
||||
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
|
||||
assets.send(user)
|
||||
|
||||
ui = new(user, src, ui_key, "computer_main", "NTOS Main menu", 400, 500, master_ui, state)
|
||||
ui.open()
|
||||
ui.set_autoupdate(state = 1)
|
||||
|
||||
|
||||
/obj/item/device/modular_computer/ui_data(mob/user)
|
||||
var/list/data = get_header_data()
|
||||
data["programs"] = list()
|
||||
for(var/datum/computer_file/program/P in hard_drive.stored_files)
|
||||
var/running = 0
|
||||
if(P in idle_threads)
|
||||
running = 1
|
||||
|
||||
data["programs"] += list(list("name" = P.filename, "desc" = P.filedesc, "running" = running))
|
||||
|
||||
return data
|
||||
|
||||
|
||||
// Handles user's GUI input
|
||||
/obj/item/device/modular_computer/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("PC_exit")
|
||||
kill_program()
|
||||
return 1
|
||||
if("PC_shutdown")
|
||||
shutdown_computer()
|
||||
return 1
|
||||
if("PC_minimize")
|
||||
var/mob/user = usr
|
||||
if(!active_program || !processor_unit)
|
||||
return
|
||||
|
||||
idle_threads.Add(active_program)
|
||||
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
|
||||
|
||||
active_program = null
|
||||
update_icon()
|
||||
if(user && istype(user))
|
||||
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
|
||||
if("PC_killprogram")
|
||||
var/prog = params["name"]
|
||||
var/datum/computer_file/program/P = null
|
||||
var/mob/user = usr
|
||||
if(hard_drive)
|
||||
P = hard_drive.find_file_by_name(prog)
|
||||
|
||||
if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED)
|
||||
return
|
||||
|
||||
P.kill_program(forced = TRUE)
|
||||
user << "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>"
|
||||
|
||||
if("PC_runprogram")
|
||||
var/prog = params["name"]
|
||||
var/datum/computer_file/program/P = null
|
||||
var/mob/user = usr
|
||||
if(hard_drive)
|
||||
P = hard_drive.find_file_by_name(prog)
|
||||
|
||||
if(!P || !istype(P)) // Program not found or it's not executable program.
|
||||
user << "<span class='danger'>\The [src]'s screen shows \"I/O ERROR - Unable to run program\" warning.</span>"
|
||||
return
|
||||
|
||||
P.computer = src
|
||||
|
||||
if(!P.is_supported_by_hardware(hardware_flag, 1, user))
|
||||
return
|
||||
|
||||
// The program is already running. Resume it.
|
||||
if(P in idle_threads)
|
||||
P.program_state = PROGRAM_STATE_ACTIVE
|
||||
active_program = P
|
||||
idle_threads.Remove(P)
|
||||
update_icon()
|
||||
return
|
||||
|
||||
if(idle_threads.len >= processor_unit.max_idle_programs+1)
|
||||
user << "<span class='danger'>\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 \"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()
|
||||
return 1
|
||||
else
|
||||
return
|
||||
|
||||
/obj/item/device/modular_computer/ui_host()
|
||||
if(physical)
|
||||
return physical
|
||||
return src
|
||||
@@ -0,0 +1,106 @@
|
||||
/obj/item/device/modular_computer/laptop
|
||||
name = "laptop"
|
||||
desc = "A portable laptop computer."
|
||||
|
||||
icon = 'icons/obj/modular_laptop.dmi'
|
||||
icon_state = "laptop-closed"
|
||||
icon_state_powered = "laptop"
|
||||
icon_state_unpowered = "laptop-off"
|
||||
icon_state_menu = "menu"
|
||||
|
||||
hardware_flag = PROGRAM_LAPTOP
|
||||
max_hardware_size = 2
|
||||
w_class = 3
|
||||
|
||||
flags = HANDSLOW // No running around with open laptops in hands.
|
||||
|
||||
screen_on = 0 // Starts closed
|
||||
var/start_open = 1 // unless this var is set to 1
|
||||
var/icon_state_closed = "laptop-closed"
|
||||
var/w_class_open = 4
|
||||
var/slowdown_open = 1
|
||||
|
||||
/obj/item/device/modular_computer/laptop/New()
|
||||
..()
|
||||
if(start_open && !screen_on)
|
||||
toggle_open()
|
||||
|
||||
/obj/item/device/modular_computer/laptop/update_icon()
|
||||
if(screen_on)
|
||||
..()
|
||||
else
|
||||
cut_overlays()
|
||||
icon_state = icon_state_closed
|
||||
|
||||
/obj/item/device/modular_computer/laptop/attack_self(mob/user)
|
||||
if(!screen_on)
|
||||
try_toggle_open(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/device/modular_computer/laptop/verb/open_computer()
|
||||
set name = "Toggle Open"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
try_toggle_open(usr)
|
||||
|
||||
/obj/item/device/modular_computer/laptop/MouseDrop(obj/over_object, src_location, over_location)
|
||||
if(over_object == usr || over_object == src)
|
||||
try_toggle_open(usr)
|
||||
else if(istype(over_object, /obj/screen/inventory/hand))
|
||||
var/obj/screen/inventory/hand/H = over_object
|
||||
var/mob/M = usr
|
||||
|
||||
if(!M.restrained() && !M.stat)
|
||||
if(!isturf(loc) || !Adjacent(M))
|
||||
return
|
||||
|
||||
switch(H.slot_id)
|
||||
if(slot_r_hand)
|
||||
M.put_in_r_hand(src)
|
||||
if(slot_l_hand)
|
||||
M.put_in_l_hand(src)
|
||||
|
||||
/obj/item/device/modular_computer/laptop/attack_hand(mob/user)
|
||||
if(screen_on && isturf(loc))
|
||||
return attack_self(user)
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/device/modular_computer/laptop/proc/try_toggle_open(mob/living/user)
|
||||
if(issilicon(user))
|
||||
return
|
||||
if(!isturf(loc) && !ismob(loc)) // No opening it in backpack.
|
||||
return
|
||||
if(!user.canUseTopic(src))
|
||||
return
|
||||
|
||||
toggle_open(user)
|
||||
|
||||
|
||||
/obj/item/device/modular_computer/laptop/AltClick(mob/user)
|
||||
if(screen_on) // Close it.
|
||||
try_toggle_open(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/device/modular_computer/laptop/proc/toggle_open(mob/living/user=null)
|
||||
if(screen_on)
|
||||
user << "<span class='notice'>You close \the [src].</span>"
|
||||
slowdown = initial(slowdown)
|
||||
w_class = initial(w_class)
|
||||
else
|
||||
user << "<span class='notice'>You open \the [src].</span>"
|
||||
slowdown = slowdown_open
|
||||
w_class = w_class_open
|
||||
|
||||
screen_on = !screen_on
|
||||
update_icon()
|
||||
|
||||
|
||||
|
||||
// Laptop frame, starts empty and closed.
|
||||
/obj/item/device/modular_computer/laptop/buildable
|
||||
start_open = 0
|
||||
@@ -1,704 +0,0 @@
|
||||
// This is the base type that does all the hardware stuff.
|
||||
// Other types expand it - tablets use a direct subtypes, and
|
||||
// consoles and laptops use "procssor" item that is held inside machinery piece
|
||||
/obj/item/modular_computer
|
||||
name = "Modular Microcomputer"
|
||||
desc = "A small portable microcomputer."
|
||||
|
||||
var/enabled = 0 // Whether the computer is turned on.
|
||||
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
|
||||
var/datum/computer_file/program/active_program = null // A currently active program running on the computer.
|
||||
var/hardware_flag = 0 // A flag that describes this device type
|
||||
var/last_power_usage = 0
|
||||
var/last_battery_percent = 0 // Used for deciding if battery percentage has chandged
|
||||
var/last_world_time = "00:00"
|
||||
var/list/last_header_icons
|
||||
var/computer_emagged = 0 // Whether the computer is emagged.
|
||||
|
||||
var/base_active_power_usage = 50 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
|
||||
var/base_idle_power_usage = 5 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
|
||||
|
||||
// Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..)
|
||||
// must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently
|
||||
// If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example.
|
||||
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
icon_state = "laptop-open"
|
||||
var/icon_state_unpowered = null // Icon state when the computer is turned off
|
||||
var/icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
|
||||
var/max_hardware_size = 0 // Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed.
|
||||
var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
|
||||
|
||||
// Damage of the chassis. If the chassis takes too much damage it will break apart.
|
||||
var/damage = 0 // Current damage level
|
||||
var/broken_damage = 50 // Damage level at which the computer ceases to operate
|
||||
var/max_damage = 100 // Damage level at which the computer breaks apart.
|
||||
|
||||
// Important hardware (must be installed for computer to work)
|
||||
var/obj/item/weapon/computer_hardware/processor_unit/processor_unit // CPU. Without it the computer won't run. Better CPUs can run more programs at once.
|
||||
var/obj/item/weapon/computer_hardware/network_card/network_card // Network Card component of this computer. Allows connection to NTNet
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive // Hard Drive component of this computer. Stores programs and files.
|
||||
var/obj/item/weapon/computer_hardware/battery_module/battery_module // An internal power source for this computer. Can be recharged.
|
||||
// Optional hardware (improves functionality, but is not critical for computer to work)
|
||||
var/obj/item/weapon/computer_hardware/card_slot/card_slot // ID Card slot component of this computer. Mostly for HoP modification console that needs ID slot for modification.
|
||||
var/obj/item/weapon/computer_hardware/card_slot/card_slot2 // second slot. popular demand requested the hop need to insert 2 ids.
|
||||
var/obj/item/weapon/computer_hardware/nano_printer/nano_printer // Nano Printer component of this computer, for your everyday paperwork needs.
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/portable_drive // Portable data storage
|
||||
|
||||
var/list/idle_threads = list() // Idle programs on background. They still receive process calls but can't be interacted with.
|
||||
var/obj/physical = null
|
||||
|
||||
|
||||
|
||||
// Eject ID card from computer, if it has ID slot with card inside.
|
||||
/obj/item/modular_computer/verb/eject_id()
|
||||
set name = "Eject ID"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(usr.incapacitated() || !istype(usr, /mob/living))
|
||||
usr << "<span class='warning'>You can't do that.</span>"
|
||||
return
|
||||
|
||||
if(!Adjacent(usr))
|
||||
usr << "<span class='warning'>You can't reach it.</span>"
|
||||
return
|
||||
|
||||
proc_eject_id(usr)
|
||||
|
||||
// Eject ID card from computer, if it has ID slot with card inside.
|
||||
/obj/item/modular_computer/verb/eject_usb()
|
||||
set name = "Eject Portable Device"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(usr.incapacitated() || !istype(usr, /mob/living))
|
||||
usr << "<span class='warning'>You can't do that.</span>"
|
||||
return
|
||||
|
||||
if(!Adjacent(usr))
|
||||
usr << "<span class='warning'>You can't reach it.</span>"
|
||||
return
|
||||
|
||||
proc_eject_usb(usr)
|
||||
|
||||
/obj/item/modular_computer/proc/proc_eject_id(mob/user, slot)
|
||||
if(!user)
|
||||
user = usr
|
||||
|
||||
if(!card_slot)
|
||||
user << "\The [src] does not have an ID card slot"
|
||||
return
|
||||
|
||||
if(!card_slot.stored_card && !card_slot.stored_card2)
|
||||
user << "There is no card in \the [src]"
|
||||
return
|
||||
|
||||
if(active_program)
|
||||
active_program.event_idremoved(0, slot)
|
||||
|
||||
for(var/I in idle_threads)
|
||||
var/datum/computer_file/program/P = I
|
||||
P.event_idremoved(1, slot)
|
||||
if(card_slot.stored_card && (!slot || slot == 1))
|
||||
card_slot.stored_card.forceMove(get_turf(src))
|
||||
card_slot.stored_card = null
|
||||
if(card_slot.stored_card2 && (!slot || slot == 2))
|
||||
card_slot.stored_card2.forceMove(get_turf(src))
|
||||
card_slot.stored_card2 = null
|
||||
user << "You remove the card[card_slot.stored_card && card_slot.stored_card2 && !slot ? "s" : ""] from \the [src]"
|
||||
|
||||
/obj/item/modular_computer/proc/proc_eject_usb(mob/user)
|
||||
if(!user)
|
||||
user = usr
|
||||
|
||||
if(!portable_drive)
|
||||
user << "There is no portable device connected to \the [src]."
|
||||
return
|
||||
|
||||
uninstall_component(user, portable_drive)
|
||||
|
||||
/obj/item/modular_computer/attack_ghost(mob/dead/observer/user)
|
||||
if(enabled)
|
||||
ui_interact(user)
|
||||
else if(IsAdminGhost(user))
|
||||
var/response = alert(user, "This computer is turned off. Would you like to turn it on?", "Admin Override", "Yes", "No")
|
||||
if(response == "Yes")
|
||||
turn_on(user)
|
||||
|
||||
/obj/item/modular_computer/emag_act(mob/user)
|
||||
if(computer_emagged)
|
||||
user << "\The [src] was already emagged."
|
||||
return 0
|
||||
else
|
||||
computer_emagged = 1
|
||||
user << "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message."
|
||||
return 1
|
||||
|
||||
/obj/item/modular_computer/examine(mob/user)
|
||||
..()
|
||||
if(damage > broken_damage)
|
||||
user << "<span class='danger'>It is heavily damaged!</span>"
|
||||
else if(damage)
|
||||
user << "It is damaged."
|
||||
|
||||
/obj/item/modular_computer/New()
|
||||
START_PROCESSING(SSmachine, src)
|
||||
update_icon()
|
||||
if(!physical)
|
||||
physical = src
|
||||
..()
|
||||
|
||||
/obj/item/modular_computer/Destroy()
|
||||
kill_program(1)
|
||||
STOP_PROCESSING(SSmachine, src)
|
||||
for(var/H in get_all_components())
|
||||
var/obj/item/weapon/computer_hardware/CH = H
|
||||
uninstall_component(null, CH)
|
||||
qdel(CH)
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/update_icon()
|
||||
icon_state = icon_state_unpowered
|
||||
cut_overlays()
|
||||
if(!enabled)
|
||||
return
|
||||
if(active_program)
|
||||
add_overlay(active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu)
|
||||
else
|
||||
add_overlay(icon_state_menu)
|
||||
|
||||
// Used by child types if they have other power source than battery
|
||||
/obj/item/modular_computer/proc/check_power_override()
|
||||
return 0
|
||||
|
||||
// Operates NanoUI
|
||||
/obj/item/modular_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
|
||||
|
||||
|
||||
if(!screen_on || !enabled)
|
||||
if(ui)
|
||||
ui.close()
|
||||
return 0
|
||||
if((!battery_module || !battery_module.battery.charge) && !check_power_override())
|
||||
if(ui)
|
||||
ui.close()
|
||||
return 0
|
||||
|
||||
// If we have an active program switch to it now.
|
||||
if(active_program)
|
||||
if(ui) // This is the main laptop screen. Since we are switching to program's UI close it for now.
|
||||
ui.close()
|
||||
active_program.ui_interact(user)
|
||||
return
|
||||
|
||||
// We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it.
|
||||
// This screen simply lists available programs and user may select them.
|
||||
if(!hard_drive || !hard_drive.stored_files || !hard_drive.stored_files.len)
|
||||
physical.visible_message("\The [src] beeps three times, it's screen displaying \"DISK ERROR\" warning.")
|
||||
return // No HDD, No HDD files list or no stored files. Something is very broken.
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if (!ui)
|
||||
|
||||
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
|
||||
assets.send(user)
|
||||
|
||||
ui = new(user, src, ui_key, "computer_main", "NTOS Main menu", 400, 500, master_ui, state)
|
||||
ui.open()
|
||||
ui.set_autoupdate(state = 1)
|
||||
|
||||
|
||||
/obj/item/modular_computer/ui_data(mob/user)
|
||||
|
||||
var/list/data = get_header_data()
|
||||
data["programs"] = list()
|
||||
for(var/datum/computer_file/program/P in hard_drive.stored_files)
|
||||
var/running = 0
|
||||
if(P in idle_threads)
|
||||
running = 1
|
||||
|
||||
data["programs"] += list(list("name" = P.filename, "desc" = P.filedesc, "running" = running))
|
||||
|
||||
return data
|
||||
|
||||
|
||||
// On-click handling. Turns on the computer if it's off and opens the GUI.
|
||||
/obj/item/modular_computer/attack_self(mob/user)
|
||||
if(enabled)
|
||||
ui_interact(user)
|
||||
else
|
||||
turn_on(user)
|
||||
|
||||
/obj/item/modular_computer/proc/break_apart()
|
||||
physical.visible_message("\The [src] breaks apart!")
|
||||
var/turf/newloc = get_turf(src)
|
||||
new /obj/item/stack/sheet/metal(newloc, round(steel_sheet_cost/2))
|
||||
for(var/C in get_all_components())
|
||||
var/obj/item/weapon/computer_hardware/H = C
|
||||
uninstall_component(null, H)
|
||||
H.forceMove(newloc)
|
||||
if(prob(25))
|
||||
H.take_damage(rand(10,30))
|
||||
relay_qdel()
|
||||
qdel()
|
||||
|
||||
/obj/item/modular_computer/proc/turn_on(mob/user)
|
||||
var/issynth = issilicon(user) // Robots and AIs get different activation messages.
|
||||
if(damage > broken_damage)
|
||||
if(issynth)
|
||||
user << "You send an activation signal to \the [src], but it responds with an error code. It must be damaged."
|
||||
else
|
||||
user << "You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again."
|
||||
return
|
||||
if(processor_unit && ((battery_module && battery_module.battery.charge && battery_module.check_functionality()) || check_power_override())) // Battery-run and charged or non-battery but powered by APC.
|
||||
if(issynth)
|
||||
user << "You send an activation signal to \the [src], turning it on"
|
||||
else
|
||||
user << "You press the power button and start up \the [src]"
|
||||
enabled = 1
|
||||
update_icon()
|
||||
ui_interact(user)
|
||||
else // Unpowered
|
||||
if(issynth)
|
||||
user << "You send an activation signal to \the [src] but it does not respond"
|
||||
else
|
||||
user << "You press the power button but \the [src] does not respond"
|
||||
|
||||
// Process currently calls handle_power(), may be expanded in future if more things are added.
|
||||
/obj/item/modular_computer/process()
|
||||
if(!enabled) // The computer is turned off
|
||||
last_power_usage = 0
|
||||
return 0
|
||||
|
||||
if(damage > broken_damage)
|
||||
shutdown_computer()
|
||||
return 0
|
||||
|
||||
if(active_program && active_program.requires_ntnet && !get_ntnet_status(active_program.requires_ntnet_feature)) // Active program requires NTNet to run but we've just lost connection. Crash.
|
||||
active_program.event_networkfailure(0)
|
||||
|
||||
for(var/I in idle_threads)
|
||||
var/datum/computer_file/program/P = I
|
||||
if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature))
|
||||
P.event_networkfailure(1)
|
||||
|
||||
if(active_program)
|
||||
if(active_program.program_state != PROGRAM_STATE_KILLED)
|
||||
active_program.process_tick()
|
||||
active_program.ntnet_status = get_ntnet_status()
|
||||
active_program.computer_emagged = computer_emagged
|
||||
else
|
||||
active_program = null
|
||||
|
||||
for(var/I in idle_threads)
|
||||
var/datum/computer_file/program/P = I
|
||||
if(P.program_state != PROGRAM_STATE_KILLED)
|
||||
P.process_tick()
|
||||
P.ntnet_status = get_ntnet_status()
|
||||
P.computer_emagged = computer_emagged
|
||||
else
|
||||
idle_threads.Remove(P)
|
||||
|
||||
handle_power() // Handles all computer power interaction
|
||||
//check_update_ui_need()
|
||||
|
||||
// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_"
|
||||
/obj/item/modular_computer/proc/get_header_data()
|
||||
var/list/data = list()
|
||||
|
||||
if(battery_module)
|
||||
switch(battery_module.battery.percent())
|
||||
if(80 to 200) // 100 should be maximal but just in case..
|
||||
data["PC_batteryicon"] = "batt_100.gif"
|
||||
if(60 to 80)
|
||||
data["PC_batteryicon"] = "batt_80.gif"
|
||||
if(40 to 60)
|
||||
data["PC_batteryicon"] = "batt_60.gif"
|
||||
if(20 to 40)
|
||||
data["PC_batteryicon"] = "batt_40.gif"
|
||||
if(5 to 20)
|
||||
data["PC_batteryicon"] = "batt_20.gif"
|
||||
else
|
||||
data["PC_batteryicon"] = "batt_5.gif"
|
||||
data["PC_batterypercent"] = "[round(battery_module.battery.percent())] %"
|
||||
data["PC_showbatteryicon"] = 1
|
||||
else
|
||||
data["PC_batteryicon"] = "batt_5.gif"
|
||||
data["PC_batterypercent"] = "N/C"
|
||||
data["PC_showbatteryicon"] = battery_module ? 1 : 0
|
||||
|
||||
switch(get_ntnet_status())
|
||||
if(0)
|
||||
data["PC_ntneticon"] = "sig_none.gif"
|
||||
if(1)
|
||||
data["PC_ntneticon"] = "sig_low.gif"
|
||||
if(2)
|
||||
data["PC_ntneticon"] = "sig_high.gif"
|
||||
if(3)
|
||||
data["PC_ntneticon"] = "sig_lan.gif"
|
||||
|
||||
if(idle_threads.len)
|
||||
var/list/program_headers = list()
|
||||
for(var/I in idle_threads)
|
||||
var/datum/computer_file/program/P = I
|
||||
if(!P.ui_header)
|
||||
continue
|
||||
program_headers.Add(list(list(
|
||||
"icon" = P.ui_header
|
||||
)))
|
||||
|
||||
data["PC_programheaders"] = program_headers
|
||||
|
||||
data["PC_stationtime"] = worldtime2text()
|
||||
data["PC_hasheader"] = 1
|
||||
data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen
|
||||
return data
|
||||
|
||||
// Relays kill program request to currently active program. Use this to quit current program.
|
||||
/obj/item/modular_computer/proc/kill_program(forced = 0)
|
||||
if(active_program)
|
||||
active_program.kill_program(forced)
|
||||
active_program = null
|
||||
var/mob/user = usr
|
||||
if(user && istype(user))
|
||||
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
update_icon()
|
||||
|
||||
// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on)
|
||||
/obj/item/modular_computer/proc/get_ntnet_status(specific_action = 0)
|
||||
if(network_card)
|
||||
return network_card.get_signal(specific_action)
|
||||
else
|
||||
return 0
|
||||
|
||||
/obj/item/modular_computer/proc/add_log(text)
|
||||
if(!get_ntnet_status())
|
||||
return 0
|
||||
return ntnet_global.add_log(text, network_card)
|
||||
|
||||
/obj/item/modular_computer/proc/shutdown_computer(loud = 1)
|
||||
kill_program(1)
|
||||
for(var/datum/computer_file/program/P in idle_threads)
|
||||
P.kill_program(1)
|
||||
idle_threads.Remove(P)
|
||||
if(loud)
|
||||
physical.visible_message("\The [src] shuts down.")
|
||||
enabled = 0
|
||||
update_icon()
|
||||
return
|
||||
|
||||
// Handles user's GUI input
|
||||
/obj/item/modular_computer/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("PC_exit")
|
||||
kill_program()
|
||||
return 1
|
||||
if("PC_shutdown")
|
||||
shutdown_computer()
|
||||
return 1
|
||||
if("PC_minimize")
|
||||
var/mob/user = usr
|
||||
if(!active_program || !processor_unit)
|
||||
return
|
||||
|
||||
idle_threads.Add(active_program)
|
||||
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
|
||||
|
||||
active_program = null
|
||||
update_icon()
|
||||
if(user && istype(user))
|
||||
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
|
||||
if("PC_killprogram")
|
||||
var/prog = params["name"]
|
||||
var/datum/computer_file/program/P = null
|
||||
var/mob/user = usr
|
||||
if(hard_drive)
|
||||
P = hard_drive.find_file_by_name(prog)
|
||||
|
||||
if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED)
|
||||
return
|
||||
|
||||
P.kill_program(1)
|
||||
user << "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>"
|
||||
|
||||
if("PC_runprogram")
|
||||
var/prog = params["name"]
|
||||
var/datum/computer_file/program/P = null
|
||||
var/mob/user = usr
|
||||
if(hard_drive)
|
||||
P = hard_drive.find_file_by_name(prog)
|
||||
|
||||
if(!P || !istype(P)) // Program not found or it's not executable program.
|
||||
user << "<span class='danger'>\The [src]'s screen shows \"I/O ERROR - Unable to run program\" warning.</span>"
|
||||
return
|
||||
|
||||
P.computer = src
|
||||
|
||||
if(!P.is_supported_by_hardware(hardware_flag, 1, user))
|
||||
return
|
||||
|
||||
// The program is already running. Resume it.
|
||||
if(P in idle_threads)
|
||||
P.program_state = PROGRAM_STATE_ACTIVE
|
||||
active_program = P
|
||||
idle_threads.Remove(P)
|
||||
update_icon()
|
||||
return
|
||||
|
||||
if(idle_threads.len >= processor_unit.max_idle_programs+1)
|
||||
user << "<span class='notice'>\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error</span>"
|
||||
return
|
||||
|
||||
if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature)) // The program requires NTNet connection, but we are not connected to NTNet.
|
||||
user << "<span class='danger'>\The [src]'s screen shows \"NETWORK ERROR - Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning.</span>"
|
||||
return
|
||||
P.computer_emagged = computer_emagged
|
||||
if(P.run_program(user))
|
||||
active_program = P
|
||||
update_icon()
|
||||
return 1
|
||||
else
|
||||
return
|
||||
|
||||
// Used in following function to reduce copypaste
|
||||
/obj/item/modular_computer/proc/power_failure(malfunction = 0)
|
||||
if(enabled) // Shut down the computer
|
||||
physical.visible_message("<span class='danger'>\The [src]'s screen flickers \"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\" warning as it shuts down unexpectedly.</span>")
|
||||
if(active_program)
|
||||
active_program.event_powerfailure(0)
|
||||
for(var/I in idle_threads)
|
||||
var/datum/computer_file/program/PRG = I
|
||||
PRG.event_powerfailure(1)
|
||||
shutdown_computer(0)
|
||||
|
||||
// Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged
|
||||
/obj/item/modular_computer/proc/handle_power()
|
||||
if(!battery_module || battery_module.battery.charge <= 0) // Battery-run but battery is depleted.
|
||||
power_failure()
|
||||
return 0
|
||||
|
||||
var/power_usage = screen_on ? base_active_power_usage : base_idle_power_usage
|
||||
|
||||
for(var/obj/item/weapon/computer_hardware/H in get_all_components())
|
||||
if(H.enabled)
|
||||
power_usage += H.power_usage
|
||||
|
||||
if(battery_module)
|
||||
if(!battery_module.check_functionality())
|
||||
power_failure(1)
|
||||
return
|
||||
if(!battery_module.battery.use(power_usage * CELLRATE))
|
||||
battery_module.battery.charge = 0
|
||||
power_failure()
|
||||
return 0
|
||||
|
||||
last_power_usage = power_usage
|
||||
|
||||
/obj/item/modular_computer/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(istype(W, /obj/item/weapon/card/id)) // ID Card, try to insert it.
|
||||
var/obj/item/weapon/card/id/I = W
|
||||
if(!card_slot)
|
||||
user << "You try to insert \the [I] into \the [src], but it does not have an ID card slot installed."
|
||||
return
|
||||
|
||||
if(card_slot.stored_card && card_slot.stored_card2)
|
||||
user << "You try to insert \the [I] into \the [src], but it's ID card slots are occupied."
|
||||
return
|
||||
if(!user.drop_item(I))
|
||||
return
|
||||
if(!card_slot.stored_card)
|
||||
card_slot.stored_card = I
|
||||
else
|
||||
card_slot.stored_card2 = I
|
||||
I.forceMove(src)
|
||||
// update_uis()
|
||||
user << "You insert \the [I] into \the [src]."
|
||||
return
|
||||
if(istype(W, /obj/item/weapon/paper))
|
||||
if(!nano_printer)
|
||||
return
|
||||
nano_printer.attackby(W, user)
|
||||
if(istype(W, /obj/item/weapon/computer_hardware))
|
||||
var/obj/item/weapon/computer_hardware/C = W
|
||||
if(C.hardware_size <= max_hardware_size)
|
||||
C.try_install_component(user, src)
|
||||
else
|
||||
user << "This component is too large for \the [src]."
|
||||
if(istype(W, /obj/item/weapon/wrench))
|
||||
var/list/components = get_all_components()
|
||||
if(components.len)
|
||||
user << "Remove all components from \the [src] before disassembling it."
|
||||
return
|
||||
new /obj/item/stack/sheet/metal( get_turf(src.loc), steel_sheet_cost )
|
||||
physical.visible_message("\The [src] has been disassembled by [user].")
|
||||
relay_qdel()
|
||||
qdel(src)
|
||||
return
|
||||
if(istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(!WT.isOn())
|
||||
user << "\The [W] is off."
|
||||
return
|
||||
|
||||
if(!damage)
|
||||
user << "\The [src] does not require repairs."
|
||||
return
|
||||
|
||||
user << "You begin repairing damage to \the [src]..."
|
||||
if(WT.remove_fuel(round(damage/75)) && do_after(usr, damage/10))
|
||||
damage = 0
|
||||
user << "You repair \the [src]."
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
var/list/all_components = get_all_components()
|
||||
if(!all_components.len)
|
||||
user << "This device doesn't have any components installed."
|
||||
return
|
||||
var/list/component_names = list()
|
||||
for(var/obj/item/weapon/computer_hardware/H in all_components)
|
||||
component_names.Add(H.name)
|
||||
|
||||
var/choice = input(usr, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in component_names
|
||||
|
||||
if(!choice)
|
||||
return
|
||||
|
||||
if(!Adjacent(usr))
|
||||
return
|
||||
|
||||
var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(choice)
|
||||
|
||||
if(!H)
|
||||
return
|
||||
|
||||
uninstall_component(user, H)
|
||||
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
// Used by processor to relay qdel() to machinery type.
|
||||
/obj/item/modular_computer/proc/relay_qdel()
|
||||
return
|
||||
|
||||
// Uninstalls component. Found and Critical vars may be passed by parent types, if they have additional hardware.
|
||||
/obj/item/modular_computer/proc/uninstall_component(mob/living/user, obj/item/weapon/computer_hardware/H, found = 0, critical = 0)
|
||||
if(portable_drive == H)
|
||||
portable_drive = null
|
||||
found = 1
|
||||
if(hard_drive == H)
|
||||
hard_drive = null
|
||||
found = 1
|
||||
critical = 1
|
||||
if(network_card == H)
|
||||
network_card = null
|
||||
found = 1
|
||||
if(nano_printer == H)
|
||||
nano_printer = null
|
||||
found = 1
|
||||
if(card_slot == H)
|
||||
card_slot = null
|
||||
found = 1
|
||||
if(battery_module == H)
|
||||
battery_module = null
|
||||
found = 1
|
||||
if(processor_unit == H)
|
||||
processor_unit = null
|
||||
found = 1
|
||||
critical = 1
|
||||
if(found)
|
||||
if(user)
|
||||
user << "You remove \the [H] from \the [src]."
|
||||
H.forceMove(get_turf(src))
|
||||
H.holder2 = null
|
||||
if(critical && enabled)
|
||||
if(user)
|
||||
user << "<span class='danger'>\The [src]'s screen freezes for few seconds and then displays an \"HARDWARE ERROR: Critical component disconnected. Please verify component connection and reboot the device. If the problem persists contact technical support for assistance.\" warning.</span>"
|
||||
shutdown_computer()
|
||||
update_icon()
|
||||
|
||||
|
||||
// Checks all hardware pieces to determine if name matches, if yes, returns the hardware piece, otherwise returns null
|
||||
/obj/item/modular_computer/proc/find_hardware_by_name(name)
|
||||
if(portable_drive && (portable_drive.name == name))
|
||||
return portable_drive
|
||||
if(hard_drive && (hard_drive.name == name))
|
||||
return hard_drive
|
||||
if(network_card && (network_card.name == name))
|
||||
return network_card
|
||||
if(nano_printer && (nano_printer.name == name))
|
||||
return nano_printer
|
||||
if(card_slot && (card_slot.name == name))
|
||||
return card_slot
|
||||
if(battery_module && (battery_module.name == name))
|
||||
return battery_module
|
||||
if(processor_unit && (processor_unit.name == name))
|
||||
return processor_unit
|
||||
return null
|
||||
|
||||
// Returns list of all components
|
||||
/obj/item/modular_computer/proc/get_all_components()
|
||||
var/list/all_components = list()
|
||||
if(hard_drive)
|
||||
all_components.Add(hard_drive)
|
||||
if(network_card)
|
||||
all_components.Add(network_card)
|
||||
if(portable_drive)
|
||||
all_components.Add(portable_drive)
|
||||
if(nano_printer)
|
||||
all_components.Add(nano_printer)
|
||||
if(card_slot)
|
||||
all_components.Add(card_slot)
|
||||
if(battery_module)
|
||||
all_components.Add(battery_module)
|
||||
if(processor_unit)
|
||||
all_components.Add(processor_unit)
|
||||
return all_components
|
||||
|
||||
/obj/item/modular_computer/proc/take_damage(amount, component_probability, damage_casing = 1, randomize = 1)
|
||||
if(randomize)
|
||||
// 75%-125%, rand() works with integers, apparently.
|
||||
amount *= (rand(75, 125) / 100.0)
|
||||
amount = round(amount)
|
||||
if(damage_casing)
|
||||
damage += amount
|
||||
damage = max(0,min(max_damage,damage))
|
||||
|
||||
if(component_probability)
|
||||
for(var/I in get_all_components())
|
||||
var/obj/item/weapon/computer_hardware/H = I
|
||||
if(prob(component_probability))
|
||||
H.take_damage(round(amount / 2))
|
||||
|
||||
if(damage >= max_damage)
|
||||
break_apart()
|
||||
|
||||
// Stronger explosions cause serious damage to internal components
|
||||
// Minor explosions are mostly mitigitated by casing.
|
||||
/obj/item/modular_computer/ex_act(severity)
|
||||
take_damage(rand(100,200) / severity, 30 / severity)
|
||||
|
||||
// EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components
|
||||
/obj/item/modular_computer/emp_act(severity)
|
||||
take_damage(rand(100,200) / severity, 50 / severity, 0)
|
||||
|
||||
// "Stun" weapons can cause minor damage to components (short-circuits?)
|
||||
// "Burn" damage is equally strong against internal components and exterior casing
|
||||
// "Brute" damage mostly damages the casing.
|
||||
/obj/item/modular_computer/bullet_act(obj/item/projectile/Proj)
|
||||
switch(Proj.damage_type)
|
||||
if(BRUTE)
|
||||
take_damage(Proj.damage, Proj.damage / 2)
|
||||
if(BURN)
|
||||
take_damage(Proj.damage, Proj.damage / 1.5)
|
||||
|
||||
/obj/item/modular_computer/ui_host()
|
||||
if(physical)
|
||||
return physical
|
||||
else
|
||||
return src
|
||||
@@ -1,5 +1,5 @@
|
||||
// Held by /obj/machinery/modular_computer to reduce amount of copy-pasted code.
|
||||
/obj/item/modular_computer/processor
|
||||
/obj/item/device/modular_computer/processor
|
||||
name = "processing unit"
|
||||
desc = "You shouldn't see this. If you do, report it."
|
||||
icon = null
|
||||
@@ -10,35 +10,17 @@
|
||||
|
||||
var/obj/machinery/modular_computer/machinery_computer = null
|
||||
|
||||
/obj/item/modular_computer/processor/Destroy()
|
||||
/obj/item/device/modular_computer/processor/Destroy()
|
||||
. = ..()
|
||||
if(machinery_computer && (machinery_computer.cpu == src))
|
||||
machinery_computer.cpu = null
|
||||
machinery_computer = null
|
||||
|
||||
// Due to how processes work, we'd receive two process calls - one from machinery type and one from our own type.
|
||||
// Since we want this to be in-sync with machinery (as it's hidden type for machinery-based computers) we'll ignore
|
||||
// non-relayed process calls.
|
||||
/obj/item/modular_computer/processor/process(relayed = 0)
|
||||
if(relayed)
|
||||
..()
|
||||
else
|
||||
return
|
||||
/obj/item/device/modular_computer/processor/New(comp)
|
||||
STOP_PROCESSING(SSobj, src) // Processed by its machine
|
||||
|
||||
/obj/item/modular_computer/processor/examine(var/mob/user)
|
||||
if(damage > broken_damage)
|
||||
user << "<span class='danger'>It is heavily damaged!</span>"
|
||||
else if(damage)
|
||||
user << "It is damaged."
|
||||
|
||||
// Power interaction is handled by our machinery part, due to machinery having APC connection.
|
||||
/obj/item/modular_computer/processor/handle_power()
|
||||
if(machinery_computer)
|
||||
machinery_computer.handle_power()
|
||||
|
||||
/obj/item/modular_computer/processor/New(comp)
|
||||
if(!comp || !istype(comp, /obj/machinery/modular_computer))
|
||||
CRASH("Inapropriate type passed to obj/item/modular_computer/processor/New()! Aborting.")
|
||||
CRASH("Inapropriate type passed to obj/item/device/modular_computer/processor/New()! Aborting.")
|
||||
return
|
||||
// Obtain reference to machinery computer
|
||||
machinery_computer = comp
|
||||
@@ -48,72 +30,26 @@
|
||||
steel_sheet_cost = machinery_computer.steel_sheet_cost
|
||||
max_damage = machinery_computer._max_damage
|
||||
broken_damage = machinery_computer._break_damage
|
||||
base_active_power_usage = machinery_computer.base_active_power_usage
|
||||
base_idle_power_usage = machinery_computer.base_idle_power_usage
|
||||
|
||||
/obj/item/modular_computer/processor/relay_qdel()
|
||||
/obj/item/device/modular_computer/processor/relay_qdel()
|
||||
qdel(machinery_computer)
|
||||
|
||||
/obj/item/modular_computer/processor/find_hardware_by_name(N)
|
||||
var/obj/item/weapon/computer_hardware/H = machinery_computer.find_hardware_by_name(N)
|
||||
if(H)
|
||||
return H
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/processor/update_icon()
|
||||
/obj/item/device/modular_computer/processor/update_icon()
|
||||
if(machinery_computer)
|
||||
return machinery_computer.update_icon()
|
||||
|
||||
/obj/item/modular_computer/processor/get_header_data()
|
||||
var/list/L = ..()
|
||||
if(machinery_computer.tesla_link && machinery_computer.tesla_link.enabled && machinery_computer.powered())
|
||||
L["PC_apclinkicon"] = "charging.gif"
|
||||
return L
|
||||
|
||||
// Checks whether the machinery computer doesn't take power from APC network
|
||||
/obj/item/modular_computer/processor/check_power_override()
|
||||
if(!machinery_computer)
|
||||
return 0
|
||||
if(!machinery_computer.tesla_link || !machinery_computer.tesla_link.enabled)
|
||||
return 0
|
||||
return machinery_computer.powered()
|
||||
|
||||
// This thing is not meant to be used on it's own, get topic data from our machinery owner.
|
||||
//obj/item/modular_computer/processor/canUseTopic(user, state)
|
||||
//obj/item/device/modular_computer/processor/canUseTopic(user, state)
|
||||
// if(!machinery_computer)
|
||||
// return 0
|
||||
|
||||
// return machinery_computer.canUseTopic(user, state)
|
||||
|
||||
/obj/item/modular_computer/processor/shutdown_computer()
|
||||
/obj/item/device/modular_computer/processor/shutdown_computer()
|
||||
if(!machinery_computer)
|
||||
return
|
||||
..()
|
||||
machinery_computer.update_icon()
|
||||
machinery_computer.use_power = 0
|
||||
return
|
||||
|
||||
/obj/item/modular_computer/processor/uninstall_component(mob/living/user, obj/item/weapon/computer_hardware/H, found = 0, critical = 0)
|
||||
if(machinery_computer.tesla_link == H)
|
||||
machinery_computer.tesla_link = null
|
||||
var/obj/item/weapon/computer_hardware/tesla_link/L = H
|
||||
L.holder = null
|
||||
found = 1
|
||||
..(user, H, found, critical)
|
||||
|
||||
/obj/item/modular_computer/processor/get_all_components()
|
||||
var/list/all_components = ..()
|
||||
if(machinery_computer && machinery_computer.tesla_link)
|
||||
all_components.Add(machinery_computer.tesla_link)
|
||||
return all_components
|
||||
|
||||
// Perform adjacency checks on our machinery counterpart, rather than on ourselves.
|
||||
/obj/item/modular_computer/processor/Adjacent(atom/neighbor)
|
||||
if(!machinery_computer)
|
||||
return 0
|
||||
return machinery_computer.Adjacent(neighbor)
|
||||
|
||||
/obj/item/modular_computer/processor/turn_on(mob/user)
|
||||
// If we have a tesla link on our machinery counterpart, enable it automatically. Lets computer without a battery work.
|
||||
if(machinery_computer && machinery_computer.tesla_link)
|
||||
machinery_computer.tesla_link.enabled = 1
|
||||
..()
|
||||
@@ -1,10 +1,11 @@
|
||||
/obj/item/modular_computer/tablet
|
||||
/obj/item/device/modular_computer/tablet
|
||||
name = "tablet computer"
|
||||
icon = 'icons/obj/modular_tablet.dmi'
|
||||
icon_state = "tablet"
|
||||
icon_state_unpowered = "tablet"
|
||||
icon_state_powered = "tablet"
|
||||
icon_state_menu = "menu"
|
||||
hardware_flag = PROGRAM_TABLET
|
||||
max_hardware_size = 1
|
||||
w_class = 2
|
||||
var/use_power = 0
|
||||
steel_sheet_cost = 1
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
|
||||
// Available as custom loadout item, this is literally the worst possible cheap tablet
|
||||
/obj/item/modular_computer/tablet/preset/cheap/New()
|
||||
. = ..()
|
||||
// This is literally the worst possible cheap tablet
|
||||
/obj/item/device/modular_computer/tablet/preset/cheap
|
||||
desc = "A low-end tablet often seen among low ranked station personnel."
|
||||
processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src)
|
||||
battery_module = new/obj/item/weapon/computer_hardware/battery_module/micro(src)
|
||||
battery_module.charge_to_full()
|
||||
hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/micro(src)
|
||||
network_card = new/obj/item/weapon/computer_hardware/network_card(src)
|
||||
|
||||
/obj/item/device/modular_computer/tablet/preset/cheap/New()
|
||||
. = ..()
|
||||
install_component(new /obj/item/weapon/computer_hardware/processor_unit/small)
|
||||
install_component(new /obj/item/weapon/computer_hardware/battery(src, /obj/item/weapon/stock_parts/cell/computer/micro))
|
||||
install_component(new /obj/item/weapon/computer_hardware/hard_drive/small)
|
||||
install_component(new /obj/item/weapon/computer_hardware/network_card)
|
||||
|
||||
// Alternative version, an average one, for higher ranked positions mostly
|
||||
/obj/item/modular_computer/tablet/preset/advanced/New()
|
||||
/obj/item/device/modular_computer/tablet/preset/advanced/New()
|
||||
. = ..()
|
||||
processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src)
|
||||
battery_module = new/obj/item/weapon/computer_hardware/battery_module(src)
|
||||
battery_module.charge_to_full()
|
||||
hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/small(src)
|
||||
network_card = new/obj/item/weapon/computer_hardware/network_card(src)
|
||||
nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src)
|
||||
card_slot = new/obj/item/weapon/computer_hardware/card_slot(src)
|
||||
install_component(new /obj/item/weapon/computer_hardware/processor_unit/small)
|
||||
install_component(new /obj/item/weapon/computer_hardware/battery(src, /obj/item/weapon/stock_parts/cell/computer))
|
||||
install_component(new /obj/item/weapon/computer_hardware/hard_drive/small)
|
||||
install_component(new /obj/item/weapon/computer_hardware/network_card)
|
||||
install_component(new /obj/item/weapon/computer_hardware/card_slot)
|
||||
install_component(new /obj/item/weapon/computer_hardware/printer/mini)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/machinery/modular_computer/console/preset/
|
||||
/obj/machinery/modular_computer/console/preset
|
||||
// Can be changed to give devices specific hardware
|
||||
var/_has_id_slot = 0
|
||||
var/_has_printer = 0
|
||||
@@ -8,13 +8,14 @@
|
||||
. = ..()
|
||||
if(!cpu)
|
||||
return
|
||||
cpu.processor_unit = new/obj/item/weapon/computer_hardware/processor_unit(cpu)
|
||||
cpu.install_component(new /obj/item/weapon/computer_hardware/processor_unit)
|
||||
|
||||
if(_has_id_slot)
|
||||
cpu.card_slot = new/obj/item/weapon/computer_hardware/card_slot(cpu)
|
||||
cpu.install_component(new /obj/item/weapon/computer_hardware/card_slot)
|
||||
if(_has_printer)
|
||||
cpu.nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(cpu)
|
||||
cpu.install_component(new /obj/item/weapon/computer_hardware/printer)
|
||||
if(_has_battery)
|
||||
cpu.battery_module = new/obj/item/weapon/computer_hardware/battery_module/super(cpu)
|
||||
cpu.install_component(new /obj/item/weapon/computer_hardware/battery(cpu, /obj/item/weapon/stock_parts/cell/computer/super))
|
||||
install_programs()
|
||||
|
||||
// Override in child types to install preset-specific programs.
|
||||
|
||||
@@ -3,14 +3,14 @@ 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/
|
||||
/obj/machinery/modular_computer
|
||||
name = "modular computer"
|
||||
desc = "An advanced computer."
|
||||
|
||||
var/battery_powered = 0 // Whether computer should be battery powered. It is set automatically
|
||||
use_power = 0
|
||||
var/hardware_flag = 0 // A flag that describes this device type
|
||||
var/last_power_usage = 0 // Power usage during last tick
|
||||
use_power = 1
|
||||
idle_power_usage = 5
|
||||
var/hardware_flag = 0 // A flag that describes this device type
|
||||
var/last_power_usage = 0 // Power usage during last tick
|
||||
|
||||
// Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..)
|
||||
// must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently
|
||||
@@ -18,61 +18,20 @@ var/list/global_modular_computers = list()
|
||||
|
||||
icon = null
|
||||
icon_state = null
|
||||
var/icon_state_unpowered = null // Icon state when the computer is turned off
|
||||
var/screen_icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
|
||||
var/screen_icon_screensaver = "standby" // Icon state overlay when the computer is powered, but not 'switched on'.
|
||||
var/max_hardware_size = 0 // Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed.
|
||||
var/steel_sheet_cost = 10 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
|
||||
var/light_strength = 0 // Light luminosity when turned on
|
||||
var/base_active_power_usage = 100 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
|
||||
var/base_idle_power_usage = 10 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
|
||||
var/icon_state_unpowered = null // Icon state when the computer is turned off.
|
||||
var/icon_state_powered = null // Icon state when the computer is turned on.
|
||||
var/screen_icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
|
||||
var/screen_icon_screensaver = "standby" // Icon state overlay when the computer is powered, but not 'switched on'.
|
||||
var/max_hardware_size = 0 // Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed.
|
||||
var/steel_sheet_cost = 10 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
|
||||
var/light_strength = 0 // Light luminosity when turned on
|
||||
var/base_active_power_usage = 100 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
|
||||
var/base_idle_power_usage = 10 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
|
||||
|
||||
var/_max_damage = 100
|
||||
var/_break_damage = 50
|
||||
|
||||
var/obj/item/weapon/computer_hardware/tesla_link/tesla_link // Tesla Link component of this computer. Allows remote charging from nearest APC.
|
||||
|
||||
var/obj/item/modular_computer/processor/cpu = null // CPU that handles most logic while this type only handles power and other specific things.
|
||||
|
||||
/obj/machinery/modular_computer/attack_ghost(mob/dead/observer/user)
|
||||
if(cpu)
|
||||
cpu.attack_ghost(user)
|
||||
|
||||
/obj/machinery/modular_computer/emag_act(mob/user)
|
||||
return cpu ? cpu.emag_act(user) : 1
|
||||
|
||||
/obj/machinery/modular_computer/update_icon()
|
||||
icon_state = icon_state_unpowered
|
||||
cut_overlays()
|
||||
|
||||
if(!cpu || !cpu.enabled)
|
||||
if (!(stat & NOPOWER) || battery_powered)
|
||||
add_overlay(screen_icon_screensaver)
|
||||
SetLuminosity(0)
|
||||
return
|
||||
SetLuminosity(light_strength)
|
||||
if(cpu.active_program)
|
||||
add_overlay(cpu.active_program.program_icon_state ? cpu.active_program.program_icon_state : screen_icon_state_menu)
|
||||
else
|
||||
overlays.Add(screen_icon_state_menu)
|
||||
|
||||
// Eject ID card from computer, if it has ID slot with card inside.
|
||||
/obj/machinery/modular_computer/verb/eject_id()
|
||||
set name = "Eject ID"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(cpu)
|
||||
cpu.eject_id()
|
||||
|
||||
// Eject ID card from computer, if it has ID slot with card inside.
|
||||
/obj/machinery/modular_computer/verb/eject_usb()
|
||||
set name = "Eject Portable Device"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(cpu)
|
||||
cpu.eject_usb()
|
||||
var/obj/item/device/modular_computer/processor/cpu = null // CPU that handles most logic while this type only handles power and other specific things.
|
||||
|
||||
/obj/machinery/modular_computer/New()
|
||||
..()
|
||||
@@ -86,28 +45,67 @@ var/list/global_modular_computers = list()
|
||||
cpu = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/modular_computer/attack_ghost(mob/dead/observer/user)
|
||||
if(cpu)
|
||||
cpu.attack_ghost(user)
|
||||
|
||||
/obj/machinery/modular_computer/emag_act(mob/user)
|
||||
return cpu ? cpu.emag_act(user) : 1
|
||||
|
||||
/obj/machinery/modular_computer/update_icon()
|
||||
cut_overlays()
|
||||
icon_state = icon_state_powered
|
||||
|
||||
if(!cpu || !cpu.enabled)
|
||||
if (!(stat & NOPOWER) && (cpu && cpu.use_power()))
|
||||
add_overlay(screen_icon_screensaver)
|
||||
else
|
||||
icon_state = icon_state_unpowered
|
||||
SetLuminosity(0)
|
||||
else
|
||||
SetLuminosity(light_strength)
|
||||
if(cpu.active_program)
|
||||
add_overlay(cpu.active_program.program_icon_state ? cpu.active_program.program_icon_state : screen_icon_state_menu)
|
||||
else
|
||||
overlays.Add(screen_icon_state_menu)
|
||||
|
||||
if(cpu && cpu.damage > cpu.broken_damage)
|
||||
add_overlay("bsod")
|
||||
add_overlay("broken")
|
||||
|
||||
// Eject ID card from computer, if it has ID slot with card inside.
|
||||
/obj/machinery/modular_computer/verb/eject_id()
|
||||
set name = "Eject ID"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(cpu)
|
||||
cpu.eject_id()
|
||||
|
||||
// Eject ID card from computer, if it has ID slot with card inside.
|
||||
/obj/machinery/modular_computer/verb/eject_disk()
|
||||
set name = "Eject Data Disk"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(cpu)
|
||||
cpu.eject_disk()
|
||||
|
||||
/obj/machinery/modular_computer/AltClick(mob/user)
|
||||
if(cpu)
|
||||
cpu.AltClick(user)
|
||||
|
||||
// On-click handling. Turns on the computer if it's off and opens the GUI.
|
||||
/obj/machinery/modular_computer/attack_hand(mob/user)
|
||||
if(cpu)
|
||||
cpu.attack_self(user) // CPU is an item, that's why we route attack_hand to attack_self
|
||||
|
||||
/obj/machinery/modular_computer/examine(mob/user)
|
||||
. = ..()
|
||||
if(cpu)
|
||||
cpu.examine(user)
|
||||
|
||||
// Process currently calls handle_power(), may be expanded in future if more things are added.
|
||||
/obj/machinery/modular_computer/process()
|
||||
if(cpu)
|
||||
// Keep names in sync.
|
||||
cpu.name = src.name
|
||||
cpu.process(1)
|
||||
|
||||
// Checks all hardware pieces to determine if name matches, if yes, returns the hardware piece, otherwise returns null
|
||||
/obj/machinery/modular_computer/proc/find_hardware_by_name(N)
|
||||
if(tesla_link && (tesla_link.name == N))
|
||||
return tesla_link
|
||||
return null
|
||||
cpu.process()
|
||||
|
||||
// Used in following function to reduce copypaste
|
||||
/obj/machinery/modular_computer/proc/power_failure(malfunction = 0)
|
||||
@@ -115,65 +113,18 @@ var/list/global_modular_computers = list()
|
||||
visible_message("<span class='danger'>\The [src]'s screen flickers [cpu.battery_module ? "\"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\"" : "\"EXTERNAL POWER LOSS\""] warning as it shuts down unexpectedly.</span>")
|
||||
if(cpu)
|
||||
cpu.shutdown_computer(0)
|
||||
battery_powered = 0
|
||||
stat |= NOPOWER
|
||||
update_icon()
|
||||
|
||||
// Called by cpu item's process() automatically, handles our power interaction.
|
||||
/obj/machinery/modular_computer/proc/handle_power()
|
||||
if(!check_external_power())
|
||||
if(cpu.battery_module && cpu.battery_module.battery.charge <= 0)// Battery-run but battery is depleted.
|
||||
power_failure()
|
||||
return 0
|
||||
else if(!cpu.battery_module) // Not battery run, but lacking APC connection.
|
||||
power_failure()
|
||||
return 0
|
||||
else if(stat & NOPOWER)
|
||||
stat &= ~NOPOWER
|
||||
|
||||
if(cpu.battery_module && cpu.battery_module.battery.charge)
|
||||
battery_powered = 1
|
||||
else
|
||||
battery_powered = 0
|
||||
|
||||
var/power_usage = cpu.screen_on ? base_active_power_usage : base_idle_power_usage
|
||||
for(var/C in src.cpu.get_all_components())
|
||||
var/obj/item/weapon/computer_hardware/CH = C
|
||||
if(CH.enabled)
|
||||
power_usage += CH.power_usage
|
||||
|
||||
// Wireless APC connection exists.
|
||||
if(tesla_link && tesla_link.enabled && tesla_link.check_functionality())
|
||||
idle_power_usage = power_usage
|
||||
active_power_usage = idle_power_usage + 100 // APCLink only charges at 100W rate, but covers any power usage.
|
||||
use_power = 1
|
||||
// Battery is not fully charged. Begin slowly recharging.
|
||||
if(cpu.battery_module && (cpu.battery_module.battery.charge < cpu.battery_module.battery.maxcharge))
|
||||
use_power = 2
|
||||
|
||||
if(cpu.battery_module && powered() && (use_power == 2)) // Battery charging itself
|
||||
cpu.battery_module.battery.give(100 * CELLRATE)
|
||||
else if(cpu.battery_module && !powered()) // Unpowered, but battery covers the usage.
|
||||
if(!cpu.battery_module.battery.use(idle_power_usage * CELLRATE))
|
||||
cpu.battery_module.battery.charge = 0
|
||||
power_failure()
|
||||
|
||||
else // No wireless connection run only on battery.
|
||||
use_power = 0
|
||||
if (cpu.battery_module)
|
||||
if(!cpu.battery_module.check_functionality())
|
||||
power_failure(1)
|
||||
return
|
||||
if(!cpu.battery_module.battery.use(power_usage * CELLRATE))
|
||||
cpu.battery_module.battery.charge = 0
|
||||
power_failure()
|
||||
cpu.last_power_usage = power_usage
|
||||
|
||||
// Modular computers can have battery in them, we handle power in previous proc, so prevent this from messing it up for us.
|
||||
/obj/machinery/modular_computer/power_change()
|
||||
if(battery_powered)
|
||||
if(cpu && cpu.use_power()) // If "CPU" still has a power source, PC wouldn't go offline.
|
||||
stat &= ~NOPOWER
|
||||
update_icon()
|
||||
return
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/modular_computer/attackby(var/obj/item/weapon/W as obj, mob/user)
|
||||
if(cpu)
|
||||
@@ -197,11 +148,4 @@ var/list/global_modular_computers = list()
|
||||
// "Brute" damage mostly damages the casing.
|
||||
/obj/machinery/modular_computer/bullet_act(obj/item/projectile/Proj)
|
||||
if(cpu)
|
||||
cpu.bullet_act(Proj)
|
||||
|
||||
|
||||
/obj/machinery/modular_computer/proc/check_external_power()
|
||||
if((!powered() || !tesla_link || !tesla_link.enabled || !tesla_link.check_functionality()))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
cpu.bullet_act(Proj)
|
||||
@@ -1,10 +1,11 @@
|
||||
/obj/machinery/modular_computer/console/
|
||||
/obj/machinery/modular_computer/console
|
||||
name = "console"
|
||||
desc = "A stationary computer."
|
||||
|
||||
icon = 'icons/obj/modular_console.dmi'
|
||||
icon_state = "console"
|
||||
icon_state_unpowered = "console"
|
||||
icon_state_powered = "console"
|
||||
icon_state_unpowered = "console-off"
|
||||
screen_icon_state_menu = "menu"
|
||||
hardware_flag = PROGRAM_CONSOLE
|
||||
var/console_department = "" // Used in New() to set network tag according to our area.
|
||||
@@ -12,7 +13,7 @@
|
||||
density = 1
|
||||
base_idle_power_usage = 100
|
||||
base_active_power_usage = 500
|
||||
max_hardware_size = 3
|
||||
max_hardware_size = 4
|
||||
steel_sheet_cost = 10
|
||||
light_strength = 2
|
||||
_max_damage = 300
|
||||
@@ -21,16 +22,19 @@
|
||||
/obj/machinery/modular_computer/console/buildable/New()
|
||||
..()
|
||||
// User-built consoles start as empty frames.
|
||||
qdel(tesla_link)
|
||||
qdel(cpu.recharger)
|
||||
qdel(cpu.network_card)
|
||||
qdel(cpu.hard_drive)
|
||||
|
||||
/obj/machinery/modular_computer/console/New()
|
||||
..()
|
||||
cpu.battery_module = null
|
||||
cpu.network_card = new/obj/item/weapon/computer_hardware/network_card/wired(src)
|
||||
tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src)
|
||||
cpu.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/super(src) // Consoles generally have better HDDs due to lower space limitations
|
||||
if(cpu.battery_module)
|
||||
qdel(cpu.battery_module)
|
||||
|
||||
cpu.install_component(new /obj/item/weapon/computer_hardware/network_card/wired)
|
||||
cpu.install_component(new /obj/item/weapon/computer_hardware/recharger/APC)
|
||||
cpu.install_component(new /obj/item/weapon/computer_hardware/hard_drive/super) // Consoles generally have better HDDs due to lower space limitations
|
||||
|
||||
var/area/A = get_area(src)
|
||||
// Attempts to set this console's tag according to our area. Since some areas have stuff like "XX - YY" in their names we try to remove that too.
|
||||
if(A && console_department)
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
// Laptop in it's item state, can be carried around.
|
||||
|
||||
/obj/item/laptop
|
||||
name = "laptop computer"
|
||||
desc = "A portable computer. It is closed."
|
||||
icon = 'icons/obj/modular_laptop.dmi'
|
||||
icon_state = "laptop-closed"
|
||||
item_state = "laptop-inhand"
|
||||
w_class = 3
|
||||
var/obj/machinery/modular_computer/laptop/stored_computer = null
|
||||
|
||||
/obj/item/laptop/verb/open_computer()
|
||||
set name = "Open Laptop"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(usr.stat || usr.restrained() || usr.lying || !istype(usr, /mob/living))
|
||||
usr << "<span class='warning'>You can't do that.</span>"
|
||||
return
|
||||
|
||||
if(!Adjacent(usr))
|
||||
usr << "You can't reach it."
|
||||
return
|
||||
|
||||
if(!istype(loc,/turf))
|
||||
usr << "[src] is too bulky! You'll have to set it down."
|
||||
return
|
||||
|
||||
if(!stored_computer)
|
||||
if(contents.len)
|
||||
for(var/obj/O in contents)
|
||||
O.forceMove(src.loc)
|
||||
usr << "\The [src] crumbles to pieces."
|
||||
spawn(5)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
stored_computer.forceMove(src.loc)
|
||||
stored_computer.stat &= ~MAINT
|
||||
stored_computer.update_icon()
|
||||
if(stored_computer.cpu)
|
||||
stored_computer.cpu.screen_on = 1
|
||||
loc = stored_computer
|
||||
usr << "You open \the [src]."
|
||||
|
||||
|
||||
/obj/item/laptop/AltClick()
|
||||
if(Adjacent(usr))
|
||||
open_computer()
|
||||
|
||||
// The actual laptop
|
||||
/obj/machinery/modular_computer/laptop
|
||||
name = "laptop computer"
|
||||
desc = "A portable computer."
|
||||
var/obj/item/laptop/portable = null // Portable version of this computer, dropped on alt-click to allow transport. Used by laptops.
|
||||
hardware_flag = PROGRAM_LAPTOP
|
||||
icon_state_unpowered = "laptop-open" // Icon state when the computer is turned off
|
||||
icon = 'icons/obj/modular_laptop.dmi'
|
||||
icon_state = "laptop-open"
|
||||
base_idle_power_usage = 25
|
||||
base_active_power_usage = 200
|
||||
max_hardware_size = 2
|
||||
light_strength = 3
|
||||
_max_damage = 200
|
||||
_break_damage = 100
|
||||
|
||||
/obj/machinery/modular_computer/laptop/buildable/New()
|
||||
..()
|
||||
// User-built consoles start as empty frames.
|
||||
qdel(tesla_link)
|
||||
qdel(cpu.network_card)
|
||||
qdel(cpu.hard_drive)
|
||||
|
||||
// Close the computer. collapsing it into movable item that can't be used.
|
||||
/obj/machinery/modular_computer/laptop/verb/close_computer()
|
||||
set name = "Close Laptop"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(usr.stat || usr.restrained() || usr.lying || !istype(usr, /mob/living))
|
||||
usr << "<span class='warning'>You can't do that.</span>"
|
||||
return
|
||||
|
||||
if(!Adjacent(usr))
|
||||
usr << "<span class='warning'>You can't reach it.</span>"
|
||||
return
|
||||
|
||||
close_laptop(usr)
|
||||
|
||||
/obj/machinery/modular_computer/laptop/proc/close_laptop(mob/user = null)
|
||||
if(istype(loc,/obj/item/laptop))
|
||||
return
|
||||
if(!istype(loc,/turf))
|
||||
return
|
||||
|
||||
if(!portable)
|
||||
portable=new
|
||||
portable.stored_computer = src
|
||||
|
||||
portable.forceMove(src.loc)
|
||||
src.forceMove(portable)
|
||||
stat |= MAINT
|
||||
if(user)
|
||||
user << "You close \the [src]."
|
||||
if(cpu)
|
||||
cpu.screen_on = 0
|
||||
|
||||
/obj/machinery/modular_computer/laptop/AltClick()
|
||||
if(Adjacent(usr))
|
||||
close_laptop()
|
||||
@@ -20,8 +20,8 @@ var/global/file_uid = 0
|
||||
|
||||
holder.remove_file(src)
|
||||
// holder.holder is the computer that has drive installed. If we are Destroy()ing program that's currently running kill it.
|
||||
if(holder.holder2 && holder.holder2.active_program == src)
|
||||
holder.holder2.kill_program(1)
|
||||
if(holder.holder && holder.holder.active_program == src)
|
||||
holder.holder.kill_program(forced = TRUE)
|
||||
holder = null
|
||||
..()
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
var/required_access = null // List of required accesses to *run* the program.
|
||||
var/transfer_access = null // List of required access to download or file host the program
|
||||
var/program_state = PROGRAM_STATE_KILLED// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running.
|
||||
var/obj/item/modular_computer/computer // Device that runs this program.
|
||||
var/obj/item/device/modular_computer/computer // Device that runs this program.
|
||||
var/filedesc = "Unknown Program" // User-friendly name of this program.
|
||||
var/extended_desc = "N/A" // Short description of this program's function.
|
||||
var/program_icon_state = null // Program-specific screen icon state
|
||||
@@ -16,10 +16,9 @@
|
||||
var/network_destination = null // Optional string that describes what NTNet server/system this program connects to. Used in default logging.
|
||||
var/available_on_ntnet = 1 // Whether the program can be downloaded from NTNet. Set to 0 to disable.
|
||||
var/available_on_syndinet = 0 // Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable.
|
||||
var/computer_emagged = 0 // Set to 1 if computer that's running us was emagged. Computer updates this every Process() tick
|
||||
var/ui_header = null // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /icons/program_icons. Be careful not to use too large images!
|
||||
|
||||
/datum/computer_file/program/New(obj/item/modular_computer/comp = null)
|
||||
/datum/computer_file/program/New(obj/item/device/modular_computer/comp = null)
|
||||
..()
|
||||
if(comp && istype(comp))
|
||||
computer = comp
|
||||
@@ -78,7 +77,7 @@
|
||||
if(!access_to_check) // No required_access, allow it.
|
||||
return 1
|
||||
|
||||
if(computer_emagged && !transfer) //emags can bypass the execution locks but not the download ones.
|
||||
if(computer.emagged && !transfer) //emags can bypass the execution locks but not the download ones.
|
||||
return 1
|
||||
|
||||
if(IsAdminGhost(user))
|
||||
@@ -91,9 +90,8 @@
|
||||
var/mob/living/carbon/human/h = user
|
||||
var/obj/item/weapon/card/id/I = h.get_idcard()
|
||||
var/obj/item/weapon/card/id/C = h.get_active_hand()
|
||||
if (istype(C, /obj/item/device/pda))
|
||||
var/obj/item/device/pda/pda = C
|
||||
C = pda.id
|
||||
if(C)
|
||||
C = C.GetID()
|
||||
if(!(C && istype(C)))
|
||||
C = null
|
||||
|
||||
@@ -130,7 +128,7 @@
|
||||
return 0
|
||||
|
||||
// Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client.
|
||||
/datum/computer_file/program/proc/kill_program(forced = 0)
|
||||
/datum/computer_file/program/proc/kill_program(forced = FALSE)
|
||||
program_state = PROGRAM_STATE_KILLED
|
||||
if(network_destination)
|
||||
generate_network_log("Connection to [network_destination] closed.")
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
// Called when the computer fails due to power loss. Override when program wants to specifically react to power loss.
|
||||
/datum/computer_file/program/proc/event_powerfailure(background)
|
||||
kill_program(1)
|
||||
kill_program(forced = TRUE)
|
||||
|
||||
// Called when the network connectivity fails. Computer does necessary checks and only calls this when requires_ntnet_feature and similar variables are not met.
|
||||
/datum/computer_file/program/proc/event_networkfailure(background)
|
||||
kill_program(1)
|
||||
kill_program(forced = TRUE)
|
||||
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
|
||||
|
||||
@@ -101,6 +101,6 @@
|
||||
. = ..(user)
|
||||
alarmdisplay += src
|
||||
|
||||
/datum/computer_file/program/alarm_monitor/kill_program(forced = 0)
|
||||
/datum/computer_file/program/alarm_monitor/kill_program(forced = FALSE)
|
||||
alarmdisplay -= src
|
||||
..(forced)
|
||||
..()
|
||||
@@ -28,13 +28,13 @@
|
||||
target = null
|
||||
error = "Connection to destination relay lost."
|
||||
|
||||
/datum/computer_file/program/ntnet_dos/kill_program(var/forced)
|
||||
/datum/computer_file/program/ntnet_dos/kill_program(forced = FALSE)
|
||||
if(target)
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
executed = 0
|
||||
|
||||
..(forced)
|
||||
..()
|
||||
|
||||
|
||||
/datum/computer_file/program/ntnet_dos/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
|
||||
|
||||
@@ -26,13 +26,13 @@
|
||||
computer.visible_message("<span class='notice'>\The [computer]'s battery explodes in rain of sparks.</span>")
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
|
||||
spark_system.start()
|
||||
if(istype(computer, /obj/item/modular_computer/processor))
|
||||
var/obj/item/modular_computer/processor/P = computer
|
||||
if(P.machinery_computer.tesla_link && prob(50))
|
||||
qdel(P.machinery_computer.tesla_link)
|
||||
computer.visible_message("<span class='notice'>\The [computer]'s tesla link explodes in rain of sparks.</span>")
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
|
||||
spark_system.start()
|
||||
|
||||
if(computer.recharger && prob(50))
|
||||
qdel(computer.recharger)
|
||||
computer.visible_message("<span class='notice'>\The [computer]'s recharger explodes in rain of sparks.</span>")
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
|
||||
spark_system.start()
|
||||
|
||||
|
||||
/datum/computer_file/program/revelation/ui_act(action, params)
|
||||
if(..())
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
else
|
||||
show_assignments = 1
|
||||
if("PRG_print")
|
||||
if(computer && computer.nano_printer) //This option should never be called if there is no printer
|
||||
if(computer && computer.printer) //This option should never be called if there is no printer
|
||||
if(mod_mode)
|
||||
if(authorized())
|
||||
var/contents = {"<h4>Access Report</h4>
|
||||
@@ -145,7 +145,7 @@
|
||||
if(A in known_access_rights)
|
||||
contents += " [get_access_desc(A)]"
|
||||
|
||||
if(!computer.nano_printer.print_text(contents,"access report"))
|
||||
if(!computer.printer.print_text(contents,"access report"))
|
||||
usr << "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>"
|
||||
return
|
||||
else
|
||||
@@ -155,7 +155,7 @@
|
||||
<br>
|
||||
[data_core ? data_core.get_manifest(0) : ""]
|
||||
"}
|
||||
if(!computer.nano_printer.print_text(contents,text("crew manifest ([])", worldtime2text())))
|
||||
if(!computer.printer.print_text(contents,text("crew manifest ([])", worldtime2text())))
|
||||
usr << "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>"
|
||||
return
|
||||
else
|
||||
@@ -337,7 +337,7 @@
|
||||
data["assignments"] = show_assignments
|
||||
if(computer)
|
||||
data["have_id_slot"] = !!computer.card_slot
|
||||
data["have_printer"] = !!computer.nano_printer
|
||||
data["have_printer"] = !!computer.printer
|
||||
if(!computer.card_slot && mod_mode == 1)
|
||||
mod_mode = 0 //We can't modify IDs when there is no card reader
|
||||
else
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
size = 4
|
||||
available_on_ntnet = 0
|
||||
requires_ntnet = 0
|
||||
var/obj/item/modular_computer/movable = null
|
||||
var/obj/item/device/modular_computer/movable = null
|
||||
|
||||
|
||||
/datum/computer_file/program/computerconfig/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
|
||||
@@ -28,7 +28,6 @@
|
||||
ui.set_autoupdate(state = 1)
|
||||
|
||||
/datum/computer_file/program/computerconfig/ui_data(mob/user)
|
||||
|
||||
movable = computer
|
||||
if(!istype(movable))
|
||||
movable = null
|
||||
@@ -37,26 +36,21 @@
|
||||
if(!movable)
|
||||
return 0
|
||||
|
||||
var/list/data = list()
|
||||
|
||||
|
||||
data = get_header_data()
|
||||
|
||||
var/list/hardware = movable.get_all_components()
|
||||
var/list/data = get_header_data()
|
||||
|
||||
data["disk_size"] = movable.hard_drive.max_capacity
|
||||
data["disk_used"] = movable.hard_drive.used_capacity
|
||||
data["power_usage"] = movable.last_power_usage
|
||||
data["battery_exists"] = movable.battery_module ? 1 : 0
|
||||
if(movable.battery_module)
|
||||
if(movable.battery_module && movable.battery_module.battery)
|
||||
data["battery_rating"] = movable.battery_module.battery.maxcharge
|
||||
data["battery_percent"] = round(movable.battery_module.battery.percent())
|
||||
|
||||
if(movable.battery_module)
|
||||
if(movable.battery_module && movable.battery_module.battery)
|
||||
data["battery"] = list("max" = movable.battery_module.battery.maxcharge, "charge" = round(movable.battery_module.battery.charge))
|
||||
|
||||
var/list/all_entries[0]
|
||||
for(var/I in hardware)
|
||||
for(var/I in movable.all_components)
|
||||
var/obj/item/weapon/computer_hardware/H = I
|
||||
all_entries.Add(list(list(
|
||||
"name" = H.name,
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.portable_drive
|
||||
|
||||
switch(action)
|
||||
if("PRG_openfile")
|
||||
. = 1
|
||||
@@ -23,7 +26,6 @@
|
||||
var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename"))
|
||||
if(!newname)
|
||||
return 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/data/F = new/datum/computer_file/data()
|
||||
@@ -32,7 +34,6 @@
|
||||
HDD.store_file(F)
|
||||
if("PRG_deletefile")
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/file = HDD.find_file_by_name(params["name"])
|
||||
@@ -41,7 +42,6 @@
|
||||
HDD.remove_file(file)
|
||||
if("PRG_usbdeletefile")
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.portable_drive
|
||||
if(!RHDD)
|
||||
return 1
|
||||
var/datum/computer_file/file = RHDD.find_file_by_name(params["name"])
|
||||
@@ -54,7 +54,6 @@
|
||||
error = null
|
||||
if("PRG_clone")
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params["name"])
|
||||
@@ -64,7 +63,6 @@
|
||||
HDD.store_file(C)
|
||||
if("PRG_rename")
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/file = HDD.find_file_by_name(params["name"])
|
||||
@@ -77,7 +75,6 @@
|
||||
. = 1
|
||||
if(!open_file)
|
||||
return 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
|
||||
@@ -104,36 +101,31 @@
|
||||
. = 1
|
||||
if(!open_file)
|
||||
return 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
|
||||
if(!F || !istype(F))
|
||||
return 1
|
||||
if(!computer.nano_printer)
|
||||
if(!computer.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.printer.print_text(parse_tags(F.stored_data)))
|
||||
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
|
||||
return 1
|
||||
if("PRG_copytousb")
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
|
||||
if(!HDD || !RHDD)
|
||||
return 1
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params)
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params["name"])
|
||||
if(!F || !istype(F))
|
||||
return 1
|
||||
var/datum/computer_file/C = F.clone(0)
|
||||
RHDD.store_file(C)
|
||||
if("PRG_copyfromusb")
|
||||
. = 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
|
||||
if(!HDD || !RHDD)
|
||||
return 1
|
||||
var/datum/computer_file/F = RHDD.find_file_by_name(params)
|
||||
var/datum/computer_file/F = RHDD.find_file_by_name(params["name"])
|
||||
if(!F || !istype(F))
|
||||
return 1
|
||||
var/datum/computer_file/C = F.clone(0)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
var/download_completion = 0 //GQ of downloaded data.
|
||||
var/download_netspeed = 0
|
||||
var/downloaderror = ""
|
||||
var/obj/item/modular_computer/my_computer = null
|
||||
var/obj/item/device/modular_computer/my_computer = null
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(filename)
|
||||
if(downloaded_file)
|
||||
@@ -27,10 +27,10 @@
|
||||
return 0
|
||||
|
||||
// Attempting to download antag only program, but without having emagged computer. No.
|
||||
if(PRG.available_on_syndinet && !computer_emagged)
|
||||
if(PRG.available_on_syndinet && !computer.emagged)
|
||||
return 0
|
||||
|
||||
if(!computer || !computer.hard_drive || !computer.hard_drive.try_store_file(PRG))
|
||||
if(!computer || !computer.hard_drive || !computer.hard_drive.can_store_file(PRG))
|
||||
return 0
|
||||
|
||||
ui_header = "downloader_running.gif"
|
||||
@@ -50,7 +50,7 @@
|
||||
/datum/computer_file/program/ntnetdownload/proc/abort_file_download()
|
||||
if(!downloaded_file)
|
||||
return
|
||||
generate_network_log("Aborted download of file [hacked_download ? "**ENCRYPTED**" : downloaded_file.filename].[downloaded_file.filetype].")
|
||||
generate_network_log("Aborted download of file [hacked_download ? "**ENCRYPTED**" : "[downloaded_file.filename].[downloaded_file.filetype]"].")
|
||||
downloaded_file = null
|
||||
download_completion = 0
|
||||
ui_header = "downloader_finished.gif"
|
||||
@@ -58,7 +58,7 @@
|
||||
/datum/computer_file/program/ntnetdownload/proc/complete_file_download()
|
||||
if(!downloaded_file)
|
||||
return
|
||||
generate_network_log("Completed download of file [hacked_download ? "**ENCRYPTED**" : downloaded_file.filename].[downloaded_file.filetype].")
|
||||
generate_network_log("Completed download of file [hacked_download ? "**ENCRYPTED**" : "[downloaded_file.filename].[downloaded_file.filetype]"].")
|
||||
if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(downloaded_file))
|
||||
// The download failed
|
||||
downloaderror = "I/O ERROR - Unable to save file. Check whether you have enough free space on your hard drive and whether your hard drive is properly connected. If the issue persists contact your system administrator for assistance."
|
||||
@@ -101,7 +101,6 @@
|
||||
return 0
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if (!ui)
|
||||
|
||||
@@ -113,7 +112,6 @@
|
||||
ui.set_autoupdate(state = 1)
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/ui_data(mob/user)
|
||||
|
||||
my_computer = computer
|
||||
|
||||
if(!istype(my_computer))
|
||||
@@ -146,7 +144,7 @@
|
||||
"size" = P.size
|
||||
)))
|
||||
data["hackedavailable"] = 0
|
||||
if(computer_emagged) // If we are running on emagged computer we have access to some "bonus" software
|
||||
if(computer.emagged) // If we are running on emagged computer we have access to some "bonus" software
|
||||
var/list/hacked_programs[0]
|
||||
for(var/S in ntnet_global.available_antag_software)
|
||||
var/datum/computer_file/program/P = S
|
||||
@@ -161,4 +159,4 @@
|
||||
|
||||
data["downloadable_programs"] = all_entries
|
||||
|
||||
return data
|
||||
return data
|
||||
|
||||
@@ -173,11 +173,11 @@
|
||||
else
|
||||
ui_header = "ntnrc_idle.gif"
|
||||
|
||||
/datum/computer_file/program/chatclient/kill_program(forced = 0)
|
||||
/datum/computer_file/program/chatclient/kill_program(forced = FALSE)
|
||||
if(channel)
|
||||
channel.remove_client(src)
|
||||
channel = null
|
||||
..(forced)
|
||||
..()
|
||||
|
||||
/datum/computer_file/program/chatclient/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ var/global/nttransfer_uid = 0
|
||||
if(!remote)
|
||||
crash_download("Connection to remote server lost")
|
||||
|
||||
/datum/computer_file/program/nttransfer/kill_program(forced = 0)
|
||||
/datum/computer_file/program/nttransfer/kill_program(forced = FALSE)
|
||||
if(downloaded_file) // Client mode, clean up variables for next use
|
||||
finalize_download()
|
||||
|
||||
@@ -170,7 +170,7 @@ var/global/nttransfer_uid = 0
|
||||
data["uploading"] = 1
|
||||
data["upload_uid"] = unique_token
|
||||
data["upload_clients"] = connected_clients.len
|
||||
data["upload_haspassword"] = server_password ? 1 : 0
|
||||
data["haspassword"] = server_password ? 1 : 0
|
||||
data["upload_filename"] = "[provided_file.filename].[provided_file.filetype]"
|
||||
else if (upload_menu)
|
||||
var/list/all_files[0]
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// CPU that allows the computer to run programs.
|
||||
// Better CPUs are obtainable via research and can run more programs on background.
|
||||
|
||||
/obj/item/weapon/computer_hardware/processor_unit
|
||||
name = "processor board"
|
||||
desc = "A standard CPU board used in most computers. It can run up to three programs simultaneously."
|
||||
icon_state = "cpuboard"
|
||||
w_class = 2
|
||||
power_usage = 50
|
||||
critical = 1
|
||||
malfunction_probability = 1
|
||||
origin_tech = "programming=3;engineering=2"
|
||||
var/max_idle_programs = 2 // 2 idle, + 1 active = 3 as said in description.
|
||||
|
||||
/obj/item/weapon/computer_hardware/processor_unit/small
|
||||
name = "microprocessor"
|
||||
desc = "A miniaturised CPU used in portable devices. It can run up to two programs simultaneously."
|
||||
icon_state = "cpu"
|
||||
w_class = 1
|
||||
power_usage = 25
|
||||
max_idle_programs = 1
|
||||
origin_tech = "programming=2;engineering=2"
|
||||
|
||||
/obj/item/weapon/computer_hardware/processor_unit/photonic
|
||||
name = "photonic processor board"
|
||||
desc = "An advanced experimental CPU board that uses photonic core instead of regular circuitry. It can run up to five programs simultaneously, but uses a lot of power."
|
||||
icon_state = "cpuboard_super"
|
||||
w_class = 2
|
||||
power_usage = 250
|
||||
max_idle_programs = 4
|
||||
origin_tech = "programming=5;engineering=4"
|
||||
|
||||
/obj/item/weapon/computer_hardware/processor_unit/photonic/small
|
||||
name = "photonic microprocessor"
|
||||
desc = "An advanced miniaturised CPU for use in portable devices. It uses photonic core instead of regular circuitry. It can run up to three programs simultaneously."
|
||||
icon_state = "cpu_super"
|
||||
w_class = 1
|
||||
power_usage = 75
|
||||
max_idle_programs = 2
|
||||
origin_tech = "programming=4;engineering=3"
|
||||
@@ -0,0 +1,108 @@
|
||||
/obj/item/weapon/computer_hardware
|
||||
name = "hardware"
|
||||
desc = "Unknown Hardware."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "std_mod"
|
||||
|
||||
w_class = 1 // w_class limits which devices can contain this component.
|
||||
// 1: PDAs/Tablets, 2: Laptops, 3-4: Consoles only
|
||||
var/obj/item/device/modular_computer/holder = null
|
||||
// Computer that holds this hardware, if any.
|
||||
|
||||
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 = 0 // Prevent disabling for important component, like the CPU.
|
||||
var/can_install = 1 // Prevents direct installation of removable media.
|
||||
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/New(var/obj/L)
|
||||
..()
|
||||
pixel_x = rand(-8, 8)
|
||||
pixel_y = rand(-8, 8)
|
||||
|
||||
/obj/item/weapon/computer_hardware/Destroy()
|
||||
if(holder)
|
||||
holder.uninstall_component(src)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/weapon/computer_hardware/attackby(obj/item/I, mob/living/user)
|
||||
// Multitool. Runs diagnostics
|
||||
if(istype(I, /obj/item/device/multitool))
|
||||
user << "***** DIAGNOSTICS REPORT *****"
|
||||
diagnostics(user)
|
||||
user << "******************************"
|
||||
return 1
|
||||
|
||||
// Cable coil. Works as repair method, but will probably require multiple applications and more cable.
|
||||
if(istype(I, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/S = I
|
||||
if(!damage)
|
||||
user << "<span class='warning'>\The [src] doesn't seem to require repairs.</span>"
|
||||
return 1
|
||||
if(S.use(1))
|
||||
user << "<span class='notice'>You patch up \the [src] with a bit of \the [I].</span>"
|
||||
take_damage(-10)
|
||||
return 1
|
||||
|
||||
if(try_insert(I, user))
|
||||
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"]"
|
||||
|
||||
// Handles damage checks
|
||||
/obj/item/weapon/computer_hardware/proc/check_functionality()
|
||||
if(!enabled) // Disabled.
|
||||
return FALSE
|
||||
|
||||
if(damage > damage_failure) // Too damaged to work at all.
|
||||
return FALSE
|
||||
|
||||
if(damage > damage_malfunction) // Still working. Well, sometimes...
|
||||
if(prob(malfunction_probability))
|
||||
return FALSE
|
||||
|
||||
return TRUE // Good to go.
|
||||
|
||||
/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='warning'>It seems to be damaged!</span>"
|
||||
else if(damage)
|
||||
user << "<span class='notice'>It seems to be slightly damaged.</span>"
|
||||
|
||||
// Damages the component. Contains necessary checks. Negative damage "heals" the component.
|
||||
/obj/item/weapon/computer_hardware/proc/take_damage(var/amount)
|
||||
damage += round(amount) // We want nice rounded numbers here.
|
||||
damage = max(0, min(damage, max_damage)) // Clamp the value.
|
||||
|
||||
|
||||
// Component-side compatibility check.
|
||||
/obj/item/weapon/computer_hardware/proc/can_install(obj/item/device/modular_computer/M, mob/living/user = null)
|
||||
return can_install
|
||||
|
||||
// Called when component is installed into PC.
|
||||
/obj/item/weapon/computer_hardware/proc/on_install(obj/item/device/modular_computer/M, mob/living/user = null)
|
||||
return
|
||||
|
||||
// Called when component is removed from PC.
|
||||
/obj/item/weapon/computer_hardware/proc/on_remove(obj/item/device/modular_computer/M, mob/living/user = null)
|
||||
try_eject()
|
||||
|
||||
// Called when someone tries to insert something in it - paper in printer, card in card reader, etc.
|
||||
/obj/item/weapon/computer_hardware/proc/try_insert(obj/item/I, mob/living/user = null)
|
||||
return FALSE
|
||||
|
||||
// Called when someone tries to eject something from it - card from card reader, etc.
|
||||
/obj/item/weapon/computer_hardware/proc/try_eject(slot=0, mob/living/user = null)
|
||||
return FALSE
|
||||
@@ -1,81 +1,98 @@
|
||||
// This device is wrapper for actual power cell. I have decided to not use power cells directly as even low-end cells available on station
|
||||
// have tremendeous capacity in comparsion. Higher tier cells would provide your device with nearly infinite battery life, which is something i want to avoid.
|
||||
/obj/item/weapon/computer_hardware/battery_module
|
||||
name = "standard battery"
|
||||
desc = "A standard power cell, commonly seen in high-end portable microcomputers or low-end laptops. It's rating is 750."
|
||||
icon_state = "battery_normal"
|
||||
/obj/item/weapon/computer_hardware/battery
|
||||
name = "power cell controller"
|
||||
desc = "A charge controller for standard power cells, used in all kinds of modular computers."
|
||||
icon_state = "cell_con"
|
||||
critical = 1
|
||||
malfunction_probability = 1
|
||||
origin_tech = list("powerstorage" = 1, "engineering" = 1)
|
||||
var/battery_rating = 750
|
||||
origin_tech = "powerstorage=1;engineering=1"
|
||||
var/obj/item/weapon/stock_parts/cell/battery = null
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/advanced
|
||||
name = "advanced battery"
|
||||
desc = "An advanced power cell, often used in most laptops. It is too large to be fitted into smaller devices. It's rating is 1100."
|
||||
icon_state = "battery_advanced"
|
||||
origin_tech = list("powerstorage" = 2, "engineering" = 2)
|
||||
hardware_size = 2
|
||||
battery_rating = 1100
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/super
|
||||
name = "super battery"
|
||||
desc = "A very advanced power cell, often used in high-end devices, or as uninterruptable power supply for important consoles or servers. It's rating is 1500."
|
||||
icon_state = "battery_super"
|
||||
origin_tech = list("powerstorage" = 3, "engineering" = 3)
|
||||
hardware_size = 2
|
||||
battery_rating = 1500
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/ultra
|
||||
name = "ultra battery"
|
||||
desc = "A very advanced large power cell. It's often used as uninterruptable power supply for critical consoles or servers. It's rating is 2000."
|
||||
icon_state = "battery_ultra"
|
||||
origin_tech = list("powerstorage" = 5, "engineering" = 4)
|
||||
hardware_size = 3
|
||||
battery_rating = 2000
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/micro
|
||||
name = "micro battery"
|
||||
desc = "A small power cell, commonly seen in most portable microcomputers. It's rating is 500."
|
||||
icon_state = "battery_micro"
|
||||
origin_tech = list("powerstorage" = 2, "engineering" = 2)
|
||||
battery_rating = 500
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/nano
|
||||
name = "nano battery"
|
||||
desc = "A tiny power cell, commonly seen in low-end portable microcomputers. It's rating is 300."
|
||||
icon_state = "battery_nano"
|
||||
origin_tech = list("powerstorage" = 1, "engineering" = 1)
|
||||
battery_rating = 300
|
||||
|
||||
// This is not intended to be obtainable in-game. Intended for adminbus and debugging purposes.
|
||||
/obj/item/weapon/computer_hardware/battery_module/lambda
|
||||
name = "lambda coil"
|
||||
desc = "A very complex device that creates it's own bluespace dimension. This dimension may be used to store massive amounts of energy."
|
||||
icon_state = "battery_lambda"
|
||||
hardware_size = 1
|
||||
battery_rating = 1000000
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/diagnostics(var/mob/user)
|
||||
..()
|
||||
user << "Internal battery charge: [battery.charge]/[battery.maxcharge] CU"
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/New()
|
||||
battery = new/obj/item/weapon/stock_parts/cell(src)
|
||||
battery.maxcharge = battery_rating
|
||||
battery.charge = battery.maxcharge/2
|
||||
/obj/item/weapon/computer_hardware/battery/New(loc, battery_type = null)
|
||||
if(battery_type)
|
||||
battery = new battery_type(src)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/proc/charge_to_full()
|
||||
/obj/item/weapon/computer_hardware/battery/try_insert(obj/item/I, mob/living/user = null)
|
||||
if(!holder)
|
||||
return FALSE
|
||||
|
||||
if(!istype(I, /obj/item/weapon/stock_parts/cell))
|
||||
return FALSE
|
||||
|
||||
if(battery)
|
||||
battery.charge = battery.maxcharge
|
||||
user << "<span class='warning'>You try to connect \the [I] to \the [src], but it's connectors are occupied.</span>"
|
||||
return FALSE
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery_module/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
|
||||
if(!user.drop_item(src))
|
||||
return
|
||||
if(M.battery_module)
|
||||
user << "This computer's battery slot is already occupied by \the [M.battery_module]."
|
||||
return
|
||||
found = 1
|
||||
M.battery_module = src
|
||||
..(user, M, found)
|
||||
if(I.w_class > holder.max_hardware_size)
|
||||
user << "<span class='warning'>This power cell is too large for \the [holder]!</span>"
|
||||
return FALSE
|
||||
|
||||
if(user && !user.unEquip(I))
|
||||
return FALSE
|
||||
|
||||
battery = I
|
||||
I.forceMove(src)
|
||||
user << "<span class='notice'>You connect \the [I] to \the [src].</span>"
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/weapon/computer_hardware/battery/try_eject(slot=0, mob/living/user = null)
|
||||
if(!battery)
|
||||
user << "<span class='warning'>There is no power cell connected to \the [src].</span>"
|
||||
return FALSE
|
||||
else
|
||||
battery.forceMove(get_turf(src))
|
||||
user << "<span class='notice'>You detach \the [battery] from \the [src].</span>"
|
||||
battery = null
|
||||
|
||||
if(holder)
|
||||
if(holder.enabled && !holder.use_power())
|
||||
holder.shutdown_computer()
|
||||
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/computer
|
||||
name = "standard battery"
|
||||
desc = "A standard power cell, commonly seen in high-end portable microcomputers or low-end laptops."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "cell_mini"
|
||||
origin_tech = "powerstorage=2;engineering=1"
|
||||
w_class = 1
|
||||
maxcharge = 750
|
||||
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/computer/advanced
|
||||
name = "advanced battery"
|
||||
desc = "An advanced power cell, often used in most laptops. It is too large to be fitted into smaller devices."
|
||||
icon_state = "cell"
|
||||
origin_tech = "powerstorage=2;engineering=2"
|
||||
w_class = 2
|
||||
maxcharge = 1500
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/computer/super
|
||||
name = "super battery"
|
||||
desc = "An advanced power cell, often used in high-end laptops."
|
||||
icon_state = "cell"
|
||||
origin_tech = "powerstorage=3;engineering=3"
|
||||
w_class = 2
|
||||
maxcharge = 2000
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/computer/micro
|
||||
name = "micro battery"
|
||||
desc = "A small power cell, commonly seen in most portable microcomputers."
|
||||
icon_state = "cell_micro"
|
||||
maxcharge = 500
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/computer/nano
|
||||
name = "nano battery"
|
||||
desc = "A tiny power cell, commonly seen in low-end portable microcomputers."
|
||||
icon_state = "cell_micro"
|
||||
maxcharge = 300
|
||||
@@ -1,31 +1,84 @@
|
||||
/obj/item/weapon/computer_hardware/card_slot
|
||||
name = "RFID card slot"
|
||||
desc = "Slot that allows this computer to write data on RFID cards. Necessary for some programs to run properly."
|
||||
name = "\improper ID authentication module"
|
||||
desc = "A module allowing this computer to read or write data on ID cards. Necessary for some programs to run properly."
|
||||
power_usage = 10 //W
|
||||
critical = 0
|
||||
icon_state = "cardreader"
|
||||
hardware_size = 1
|
||||
origin_tech = list("programming" = 2)
|
||||
icon_state = "card_mini"
|
||||
w_class = 1
|
||||
origin_tech = "programming=2"
|
||||
|
||||
var/obj/item/weapon/card/id/stored_card = null
|
||||
var/obj/item/weapon/card/id/stored_card2 = null
|
||||
|
||||
/obj/item/weapon/computer_hardware/card_slot/Destroy()
|
||||
if(holder2 && (holder2.card_slot == src))
|
||||
holder2.card_slot = null
|
||||
if(stored_card)
|
||||
stored_card.forceMove(get_turf(holder2))
|
||||
if(stored_card2)
|
||||
stored_card2.forceMove(get_turf(holder2))
|
||||
holder2 = null
|
||||
..()
|
||||
try_eject()
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/computer_hardware/card_slot/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
|
||||
if(!user.drop_item(src))
|
||||
return
|
||||
if(M.card_slot)
|
||||
user << "This computer's card slot is already occupied by \the [M.card_slot]."
|
||||
return
|
||||
found = 1
|
||||
M.card_slot = src
|
||||
..(user, M, found)
|
||||
/obj/item/weapon/computer_hardware/card_slot/GetAccess()
|
||||
if(stored_card && stored_card2) // Best of both worlds
|
||||
return (stored_card.GetAccess() | stored_card2.GetAccess())
|
||||
else if(stored_card)
|
||||
return stored_card.GetAccess()
|
||||
else if(stored_card2)
|
||||
return stored_card2.GetAccess()
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/computer_hardware/card_slot/GetID()
|
||||
if(stored_card)
|
||||
return stored_card
|
||||
else if(stored_card2)
|
||||
return stored_card2
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/computer_hardware/card_slot/try_insert(obj/item/I, mob/living/user = null)
|
||||
if(!holder)
|
||||
return FALSE
|
||||
|
||||
if(!istype(I, /obj/item/weapon/card/id))
|
||||
return FALSE
|
||||
|
||||
if(stored_card && stored_card2)
|
||||
user << "<span class='warning'>You try to insert \the [I] into \the [src], but it's slots are occupied.</span>"
|
||||
return FALSE
|
||||
if(user && !user.unEquip(I))
|
||||
return FALSE
|
||||
|
||||
if(!stored_card)
|
||||
stored_card = I
|
||||
else
|
||||
stored_card2 = I
|
||||
I.forceMove(src)
|
||||
user << "<span class='notice'>You insert \the [I] into \the [src].</span>"
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/weapon/computer_hardware/card_slot/try_eject(slot=0, mob/living/user = null)
|
||||
if(!stored_card && !stored_card2)
|
||||
user << "<span class='warning'>There are no cards in \the [src].</span>"
|
||||
return FALSE
|
||||
|
||||
var/ejected = 0
|
||||
if(stored_card && (!slot || slot == 1))
|
||||
stored_card.forceMove(get_turf(src))
|
||||
stored_card.verb_pickup()
|
||||
stored_card = null
|
||||
ejected++
|
||||
|
||||
if(stored_card2 && (!slot || slot == 2))
|
||||
stored_card2.forceMove(get_turf(src))
|
||||
stored_card2.verb_pickup()
|
||||
stored_card2 = null
|
||||
ejected++
|
||||
|
||||
if(ejected)
|
||||
if(holder)
|
||||
if(holder.active_program)
|
||||
holder.active_program.event_idremoved(0, slot)
|
||||
|
||||
for(var/I in holder.idle_threads)
|
||||
var/datum/computer_file/program/P = I
|
||||
P.event_idremoved(1, slot)
|
||||
|
||||
user << "<span class='notice'>You remove the card[ejected>1 ? "s" : ""] from \the [src].</span>"
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -1,59 +1,23 @@
|
||||
/obj/item/weapon/computer_hardware/hard_drive/
|
||||
name = "basic hard drive"
|
||||
desc = "A small power efficient solid state drive, with 128GQ of storage capacity for use in basic computers where power efficiency is desired."
|
||||
power_usage = 25 // SSD or something with low power usage
|
||||
icon_state = "hdd_normal"
|
||||
hardware_size = 1
|
||||
origin_tech = list("programming" = 1, "engineering" = 1)
|
||||
/obj/item/weapon/computer_hardware/hard_drive
|
||||
name = "hard disk drive"
|
||||
desc = "A small HDD, for use in basic computers where power efficiency is desired."
|
||||
power_usage = 25
|
||||
icon_state = "harddisk_mini"
|
||||
critical = 1
|
||||
w_class = 1
|
||||
origin_tech = "programming=1;engineering=1"
|
||||
var/max_capacity = 128
|
||||
var/used_capacity = 0
|
||||
var/list/stored_files = list() // List of stored files on this drive. DO NOT MODIFY DIRECTLY!
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/advanced
|
||||
name = "advanced hard drive"
|
||||
desc = "A small hybrid hard drive with 256GQ of storage capacity for use in higher grade computers where balance between power efficiency and capacity is desired."
|
||||
max_capacity = 256
|
||||
origin_tech = list("programming" = 2, "engineering" = 2)
|
||||
power_usage = 50 // Hybrid, medium capacity and medium power storage
|
||||
icon_state = "hdd_advanced"
|
||||
hardware_size = 2
|
||||
/obj/item/weapon/computer_hardware/hard_drive/proc/install_default_programs()
|
||||
store_file(new/datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
|
||||
store_file(new/datum/computer_file/program/ntnetdownload(src)) // NTNet Downloader Utility, allows users to download more software from NTNet repository
|
||||
store_file(new/datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation.
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/super
|
||||
name = "super hard drive"
|
||||
desc = "A small hard drive with 512GQ of storage capacity for use in cluster storage solutions where capacity is more important than power efficiency."
|
||||
max_capacity = 512
|
||||
origin_tech = list("programming" = 3, "engineering" = 3)
|
||||
power_usage = 100 // High-capacity but uses lots of power, shortening battery life. Best used with APC link.
|
||||
icon_state = "hdd_super"
|
||||
hardware_size = 2
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/cluster
|
||||
name = "cluster hard drive"
|
||||
desc = "A large storage cluster consisting of multiple hard drives for usage in high capacity storage systems. Has capacity of 2048 GQ."
|
||||
power_usage = 500
|
||||
origin_tech = list("programming" = 4, "engineering" = 4)
|
||||
max_capacity = 2048
|
||||
icon_state = "hdd_cluster"
|
||||
hardware_size = 3
|
||||
|
||||
// For tablets, etc. - highly power efficient.
|
||||
/obj/item/weapon/computer_hardware/hard_drive/small
|
||||
name = "small hard drive"
|
||||
desc = "A small highly efficient solid state drive for portable devices."
|
||||
power_usage = 10
|
||||
origin_tech = list("programming" = 2, "engineering" = 2)
|
||||
max_capacity = 64
|
||||
icon_state = "hdd_small"
|
||||
hardware_size = 1
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/micro
|
||||
name = "micro hard drive"
|
||||
desc = "A small micro hard drive for portable devices."
|
||||
power_usage = 2
|
||||
origin_tech = list("programming" = 1, "engineering" = 1)
|
||||
max_capacity = 32
|
||||
icon_state = "hdd_micro"
|
||||
hardware_size = 1
|
||||
/obj/item/weapon/computer_hardware/hard_drive/examine(user)
|
||||
..()
|
||||
user << "<span class='notice'>It has [max_capacity] GQ of storage capacity.</span>"
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/diagnostics(var/mob/user)
|
||||
..()
|
||||
@@ -66,7 +30,7 @@
|
||||
if(!F || !istype(F))
|
||||
return 0
|
||||
|
||||
if(!can_store_file(F.size))
|
||||
if(!can_store_file(F))
|
||||
return 0
|
||||
|
||||
if(!check_functionality())
|
||||
@@ -84,13 +48,6 @@
|
||||
recalculate_size()
|
||||
return 1
|
||||
|
||||
// Use this proc to add file to the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks.
|
||||
/obj/item/weapon/computer_hardware/hard_drive/proc/install_default_programs()
|
||||
store_file(new/datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
|
||||
store_file(new/datum/computer_file/program/ntnetdownload(src)) // NTNet Downloader Utility, allows users to download more software from NTNet repository
|
||||
store_file(new/datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation.
|
||||
|
||||
|
||||
// Use this proc to remove file from the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks.
|
||||
/obj/item/weapon/computer_hardware/hard_drive/proc/remove_file(var/datum/computer_file/F)
|
||||
if(!F || !istype(F))
|
||||
@@ -117,27 +74,27 @@
|
||||
|
||||
used_capacity = total_size
|
||||
|
||||
// Checks whether file can be stored on the hard drive.
|
||||
/obj/item/weapon/computer_hardware/hard_drive/proc/can_store_file(var/size = 1)
|
||||
// In the unlikely event someone manages to create that many files.
|
||||
// BYOND is acting weird with numbers above 999 in loops (infinite loop prevention)
|
||||
if(stored_files.len >= 999)
|
||||
return 0
|
||||
if(used_capacity + size > max_capacity)
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
|
||||
// Checks whether we can store the file. We can only store unique files, so this checks whether we wouldn't get a duplicity by adding a file.
|
||||
/obj/item/weapon/computer_hardware/hard_drive/proc/try_store_file(var/datum/computer_file/F)
|
||||
// Checks whether file can be stored on the hard drive. We can only store unique files, so this checks whether we wouldn't get a duplicity by adding a file.
|
||||
/obj/item/weapon/computer_hardware/hard_drive/proc/can_store_file(var/datum/computer_file/F)
|
||||
if(!F || !istype(F))
|
||||
return 0
|
||||
|
||||
if(F in stored_files)
|
||||
return 0
|
||||
|
||||
var/name = F.filename + "." + F.filetype
|
||||
for(var/datum/computer_file/file in stored_files)
|
||||
if((file.filename + "." + file.filetype) == name)
|
||||
return 0
|
||||
return can_store_file(F.size)
|
||||
|
||||
// In the unlikely event someone manages to create that many files.
|
||||
// BYOND is acting weird with numbers above 999 in loops (infinite loop prevention)
|
||||
if(stored_files.len >= 999)
|
||||
return 0
|
||||
if((used_capacity + F.size) > max_capacity)
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
|
||||
|
||||
// Tries to find the file by filename. Returns null on failure
|
||||
@@ -157,21 +114,56 @@
|
||||
return null
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/Destroy()
|
||||
if(holder2 && (holder2.hard_drive == src))
|
||||
holder2.hard_drive = null
|
||||
stored_files = null
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/New()
|
||||
install_default_programs()
|
||||
..()
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
|
||||
if(!user.drop_item(src))
|
||||
return
|
||||
if(M.hard_drive)
|
||||
user << "This computer's hard drive slot is already occupied by \the [M.hard_drive]."
|
||||
return
|
||||
found = 1
|
||||
M.hard_drive = src
|
||||
..(user, M, found)
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/advanced
|
||||
name = "advanced hard disk drive"
|
||||
desc = "A hybrid HDD, for use in higher grade computers where balance between power efficiency and capacity is desired."
|
||||
max_capacity = 256
|
||||
origin_tech = "programming=2;engineering=2"
|
||||
power_usage = 50 // Hybrid, medium capacity and medium power storage
|
||||
icon_state = "harddisk_mini"
|
||||
w_class = 2
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/super
|
||||
name = "super hard disk drive"
|
||||
desc = "A high capacity HDD, for use in cluster storage solutions where capacity is more important than power efficiency."
|
||||
max_capacity = 512
|
||||
origin_tech = "programming=3;engineering=3"
|
||||
power_usage = 100 // High-capacity but uses lots of power, shortening battery life. Best used with APC link.
|
||||
icon_state = "harddisk_mini"
|
||||
w_class = 2
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/cluster
|
||||
name = "cluster hard disk drive"
|
||||
desc = "A large storage cluster consisting of multiple HDDs for usage in dedicated storage systems."
|
||||
power_usage = 500
|
||||
origin_tech = "programming=4;engineering=4"
|
||||
max_capacity = 2048
|
||||
icon_state = "harddisk"
|
||||
w_class = 3
|
||||
|
||||
// For tablets, etc. - highly power efficient.
|
||||
/obj/item/weapon/computer_hardware/hard_drive/small
|
||||
name = "solid state drive"
|
||||
desc = "An efficient SSD for portable devices."
|
||||
power_usage = 10
|
||||
origin_tech = "programming=2;engineering=2"
|
||||
max_capacity = 64
|
||||
icon_state = "ssd_mini"
|
||||
w_class = 1
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/micro
|
||||
name = "micro solid state drive"
|
||||
desc = "A highly efficient SSD chip for portable devices."
|
||||
power_usage = 2
|
||||
origin_tech = "programming=1;engineering=1"
|
||||
max_capacity = 32
|
||||
icon_state = "ssd_micro"
|
||||
w_class = 1
|
||||
@@ -1,99 +0,0 @@
|
||||
/obj/item/weapon/computer_hardware/
|
||||
name = "Hardware"
|
||||
desc = "Unknown Hardware."
|
||||
icon = 'icons/obj/modular_components.dmi'
|
||||
var/obj/item/modular_computer/holder2 = null
|
||||
var/power_usage = 0 // If the hardware uses extra power, change this.
|
||||
var/enabled = 1 // If the hardware is turned off set this to 0.
|
||||
var/critical = 1 // Prevent disabling for important component, like the HDD.
|
||||
var/hardware_size = 1 // Limits which devices can contain this component. 1: Tablets/Laptops/Consoles, 2: Laptops/Consoles, 3: Consoles only
|
||||
var/damage = 0 // Current damage level
|
||||
var/max_damage = 100 // Maximal damage level.
|
||||
var/damage_malfunction = 20 // "Malfunction" threshold. When damage exceeds this value the hardware piece will semi-randomly fail and do !!FUN!! things
|
||||
var/damage_failure = 50 // "Failure" threshold. When damage exceeds this value the hardware piece will not work at all.
|
||||
var/malfunction_probability = 10// Chance of malfunction when the component is damaged
|
||||
|
||||
/obj/item/weapon/computer_hardware/attackby(var/obj/item/W as obj, var/mob/living/user as mob)
|
||||
// Multitool. Runs diagnostics
|
||||
if(istype(W, /obj/item/device/multitool))
|
||||
user << "***** DIAGNOSTICS REPORT *****"
|
||||
diagnostics(user)
|
||||
user << "******************************"
|
||||
return 1
|
||||
// Nanopaste. Repair all damage if present for a single unit.
|
||||
var/obj/item/stack/S = W
|
||||
/*
|
||||
if(istype(S, /obj/item/stack/sheet/glass))
|
||||
if(!damage)
|
||||
user << "\The [src] doesn't seem to require repairs."
|
||||
return 1
|
||||
if(S.use(1))
|
||||
user << "You apply a bit of \the [W] to \the [src]. It immediately repairs all damage."
|
||||
damage = 0
|
||||
return 1
|
||||
*/
|
||||
// Cable coil. Works as repair method, but will probably require multiple applications and more cable.
|
||||
if(istype(S, /obj/item/stack/cable_coil))
|
||||
if(!damage)
|
||||
user << "\The [src] doesn't seem to require repairs."
|
||||
return 1
|
||||
if(S.use(1))
|
||||
user << "You patch up \the [src] with a bit of \the [W]."
|
||||
take_damage(-10)
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
|
||||
// Called on multitool click, prints diagnostic information to the user.
|
||||
/obj/item/weapon/computer_hardware/proc/diagnostics(var/mob/user)
|
||||
user << "Hardware Integrity Test... (Corruption: [damage]/[max_damage]) [damage > damage_failure ? "FAIL" : damage > damage_malfunction ? "WARN" : "PASS"]"
|
||||
|
||||
/obj/item/weapon/computer_hardware/New(var/obj/L)
|
||||
w_class = hardware_size
|
||||
if(istype(L, /obj/machinery/modular_computer))
|
||||
var/obj/machinery/modular_computer/C = L
|
||||
if(C.cpu)
|
||||
holder2 = C.cpu
|
||||
return
|
||||
if(istype(L, /obj/item/modular_computer))
|
||||
holder2 = L
|
||||
return
|
||||
|
||||
/obj/item/weapon/computer_hardware/Destroy()
|
||||
holder2 = null
|
||||
return ..()
|
||||
|
||||
// Handles damage checks
|
||||
/obj/item/weapon/computer_hardware/proc/check_functionality()
|
||||
// Too damaged to work at all.
|
||||
if(damage > damage_failure)
|
||||
return 0
|
||||
// Still working. Well, sometimes...
|
||||
if(damage > damage_malfunction)
|
||||
if(prob(malfunction_probability))
|
||||
return 0
|
||||
// Good to go.
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/computer_hardware/examine(var/mob/user)
|
||||
. = ..()
|
||||
if(damage > damage_failure)
|
||||
user << "<span class='danger'>It seems to be severely damaged!</span>"
|
||||
else if(damage > damage_malfunction)
|
||||
user << "<span class='notice'>It seems to be damaged!</span>"
|
||||
else if(damage)
|
||||
user << "It seems to be slightly damaged."
|
||||
|
||||
// Damages the component. Contains necessary checks. Negative damage "heals" the component.
|
||||
/obj/item/weapon/computer_hardware/proc/take_damage(var/amount)
|
||||
damage += round(amount) // We want nice rounded numbers here.
|
||||
damage = max(0, min(damage, max_damage)) // Clamp the value.
|
||||
|
||||
// Attempts to install the hardware into apropriate slot.
|
||||
/obj/item/weapon/computer_hardware/proc/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
|
||||
if(found)
|
||||
user << "You install \the [src] into \the [M]"
|
||||
holder2 = M
|
||||
if(!user.drop_item(src))
|
||||
return
|
||||
forceMove(M)
|
||||
@@ -1,62 +0,0 @@
|
||||
/obj/item/weapon/computer_hardware/nano_printer
|
||||
name = "nano printer"
|
||||
desc = "Small integrated printer with paper recycling module."
|
||||
power_usage = 50
|
||||
origin_tech = list("programming" = 2, "engineering" = 2)
|
||||
critical = 0
|
||||
icon_state = "printer"
|
||||
hardware_size = 1
|
||||
var/stored_paper = 5
|
||||
var/max_paper = 10
|
||||
|
||||
/obj/item/weapon/computer_hardware/nano_printer/diagnostics(var/mob/user)
|
||||
..()
|
||||
user << "Paper buffer level: [stored_paper]/[max_paper]"
|
||||
|
||||
/obj/item/weapon/computer_hardware/nano_printer/proc/print_text(var/text_to_print, var/paper_title = null)
|
||||
if(!stored_paper)
|
||||
return 0
|
||||
if(!enabled)
|
||||
return 0
|
||||
if(!check_functionality())
|
||||
return 0
|
||||
|
||||
var/obj/item/weapon/paper/P = new/obj/item/weapon/paper(get_turf(holder2))
|
||||
|
||||
// Damaged printer causes the resulting paper to be somewhat harder to read.
|
||||
if(damage > damage_malfunction)
|
||||
P.info = stars(text_to_print, 100-malfunction_probability)
|
||||
else
|
||||
P.info = text_to_print
|
||||
if(paper_title)
|
||||
P.name = paper_title
|
||||
P.update_icon()
|
||||
stored_paper--
|
||||
P = null
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/computer_hardware/nano_printer/attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(istype(W, /obj/item/weapon/paper))
|
||||
if(stored_paper >= max_paper)
|
||||
user << "You try to add \the [W] into [src], but it's paper bin is full"
|
||||
return
|
||||
|
||||
user << "You insert \the [W] into [src]."
|
||||
qdel(W)
|
||||
stored_paper++
|
||||
|
||||
/obj/item/weapon/computer_hardware/nano_printer/Destroy()
|
||||
if(holder2 && (holder2.nano_printer == src))
|
||||
holder2.nano_printer = null
|
||||
holder2 = null
|
||||
..()
|
||||
|
||||
/obj/item/weapon/computer_hardware/nano_printer/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
|
||||
if(!user.drop_item(src))
|
||||
return
|
||||
if(M.nano_printer)
|
||||
user << "This computer's nano printer slot is already occupied by \the [M.nano_printer]."
|
||||
return
|
||||
found = 1
|
||||
M.nano_printer = src
|
||||
..(user, M, found)
|
||||
@@ -1,13 +1,11 @@
|
||||
var/global/ntnet_card_uid = 1
|
||||
|
||||
/obj/item/weapon/computer_hardware/network_card/
|
||||
name = "basic NTNet network card"
|
||||
desc = "A basic network card for usage with standard NTNet frequencies."
|
||||
/obj/item/weapon/computer_hardware/network_card
|
||||
name = "network card"
|
||||
desc = "A basic wireless network card for usage with standard NTNet frequencies."
|
||||
power_usage = 50
|
||||
origin_tech = list("programming" = 2, TECH_ENGINEERING = 1)
|
||||
critical = 0
|
||||
icon_state = "netcard_basic"
|
||||
hardware_size = 1
|
||||
origin_tech = "programming=2;engineering=1"
|
||||
icon_state = "radio_mini"
|
||||
var/identification_id = null // Identification ID. Technically MAC address of this device. Can't be changed by user.
|
||||
var/identification_string = "" // Identification string, technically nickname seen in the network. Can be set by user.
|
||||
var/long_range = 0
|
||||
@@ -30,40 +28,13 @@ var/global/ntnet_card_uid = 1
|
||||
identification_id = ntnet_card_uid
|
||||
ntnet_card_uid++
|
||||
|
||||
/obj/item/weapon/computer_hardware/network_card/advanced
|
||||
name = "advanced NTNet network card"
|
||||
desc = "An advanced network card for usage with standard NTNet frequencies. It's transmitter is strong enough to connect even off-station."
|
||||
long_range = 1
|
||||
origin_tech = list("programming" = 4, "engineering" = 2)
|
||||
power_usage = 100 // Better range but higher power usage.
|
||||
icon_state = "netcard_advanced"
|
||||
hardware_size = 1
|
||||
|
||||
/obj/item/weapon/computer_hardware/network_card/wired
|
||||
name = "wired NTNet network card"
|
||||
desc = "An advanced network card for usage with standard NTNet frequencies. This one also supports wired connection."
|
||||
ethernet = 1
|
||||
origin_tech = list("programming" = 5, "engineering" = 3)
|
||||
power_usage = 100 // Better range but higher power usage.
|
||||
icon_state = "netcard_ethernet"
|
||||
hardware_size = 3
|
||||
|
||||
/obj/item/weapon/computer_hardware/network_card/Destroy()
|
||||
if(holder2 && (holder2.network_card == src))
|
||||
holder2.network_card = null
|
||||
holder2 = null
|
||||
..()
|
||||
|
||||
// Returns a string identifier of this network card
|
||||
/obj/item/weapon/computer_hardware/network_card/proc/get_network_tag()
|
||||
return "[identification_string] (NID [identification_id])"
|
||||
|
||||
// 0 - No signal, 1 - Low signal, 2 - High signal. 3 - Wired Connection
|
||||
/obj/item/weapon/computer_hardware/network_card/proc/get_signal(var/specific_action = 0)
|
||||
if(!holder2) // Hardware is not installed in anything. No signal. How did this even get called?
|
||||
return 0
|
||||
|
||||
if(!enabled)
|
||||
if(!holder) // Hardware is not installed in anything. No signal. How did this even get called?
|
||||
return 0
|
||||
|
||||
if(!check_functionality())
|
||||
@@ -75,9 +46,9 @@ var/global/ntnet_card_uid = 1
|
||||
if(!ntnet_global || !ntnet_global.check_function(specific_action)) // NTNet is down and we are not connected via wired connection. No signal.
|
||||
return 0
|
||||
|
||||
if(holder2)
|
||||
if(holder)
|
||||
|
||||
var/turf/T = get_turf(holder2)
|
||||
var/turf/T = get_turf(holder)
|
||||
if((T && istype(T)) && (T.z == ZLEVEL_STATION || T.z == ZLEVEL_MINING))
|
||||
// Computer is on station. Low/High signal depending on what type of network card you have
|
||||
if(long_range)
|
||||
@@ -90,17 +61,21 @@ var/global/ntnet_card_uid = 1
|
||||
|
||||
return 0 // Computer is not on station and does not have upgraded network card. No signal.
|
||||
|
||||
/obj/item/weapon/computer_hardware/network_card/Destroy()
|
||||
if(holder2 && (holder2.network_card == src))
|
||||
holder2.network_card = null
|
||||
..()
|
||||
|
||||
/obj/item/weapon/computer_hardware/network_card/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
|
||||
if(!user.drop_item(src))
|
||||
return
|
||||
if(M.network_card)
|
||||
user << "This computer's network card slot is already occupied by \the [M.network_card]."
|
||||
return
|
||||
found = 1
|
||||
M.network_card = src
|
||||
..(user, M, found)
|
||||
/obj/item/weapon/computer_hardware/network_card/advanced
|
||||
name = "advanced 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 = "programming=4;engineering=2"
|
||||
power_usage = 100 // Better range but higher power usage.
|
||||
icon_state = "radio"
|
||||
w_class = 1
|
||||
|
||||
/obj/item/weapon/computer_hardware/network_card/wired
|
||||
name = "wired network card"
|
||||
desc = "An advanced network card for usage with standard NTNet frequencies. This one also supports wired connection."
|
||||
ethernet = 1
|
||||
origin_tech = "programming=5;engineering=3"
|
||||
power_usage = 100 // Better range but higher power usage.
|
||||
icon_state = "net_wired"
|
||||
w_class = 3
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/obj/item/weapon/computer_hardware/hard_drive/portable
|
||||
name = "data disk"
|
||||
desc = "Removable disk used to store data."
|
||||
power_usage = 10
|
||||
icon_state = "datadisk6"
|
||||
w_class = 1
|
||||
critical = 0
|
||||
max_capacity = 16
|
||||
origin_tech = "programming=1"
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/portable/install_default_programs()
|
||||
return // Empty by default
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/portable/advanced
|
||||
name = "advanced data disk"
|
||||
power_usage = 20
|
||||
icon_state = "datadisk5"
|
||||
max_capacity = 64
|
||||
origin_tech = "programming=2"
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/portable/super
|
||||
name = "super data disk"
|
||||
desc = "Removable disk used to store large amounts of data."
|
||||
power_usage = 40
|
||||
icon_state = "datadisk3"
|
||||
max_capacity = 256
|
||||
origin_tech = "programming=4"
|
||||
@@ -1,43 +0,0 @@
|
||||
// These are basically USB data sticks and may be used to transfer files between devices
|
||||
/obj/item/weapon/computer_hardware/hard_drive/portable/
|
||||
name = "basic data crystal"
|
||||
desc = "Small crystal with imprinted photonic circuits that can be used to store data. It's capacity is 16 GQ."
|
||||
power_usage = 10
|
||||
icon_state = "flashdrive_basic"
|
||||
hardware_size = 1
|
||||
max_capacity = 16
|
||||
origin_tech = list("programming" = 1)
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/portable/advanced
|
||||
name = "advanced data crystal"
|
||||
desc = "Small crystal with imprinted high-density photonic circuits that can be used to store data. It's capacity is 64 GQ."
|
||||
power_usage = 20
|
||||
icon_state = "flashdrive_advanced"
|
||||
hardware_size = 1
|
||||
max_capacity = 64
|
||||
origin_tech = list("programming" = 2)
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/portable/super
|
||||
name = "super data crystal"
|
||||
desc = "Small crystal with imprinted ultra-density photonic circuits that can be used to store data. It's capacity is 256 GQ."
|
||||
power_usage = 40
|
||||
icon_state = "flashdrive_super"
|
||||
hardware_size = 1
|
||||
max_capacity = 256
|
||||
origin_tech = list("programming" = 4)
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/portable/New()
|
||||
..()
|
||||
stored_files = list()
|
||||
recalculate_size()
|
||||
|
||||
|
||||
/obj/item/weapon/computer_hardware/hard_drive/portable/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
|
||||
if(!user.drop_item(src))
|
||||
return
|
||||
if(M.portable_drive)
|
||||
user << "This computer's portable drive slot is already occupied by \the [M.portable_drive]."
|
||||
return
|
||||
found = 1
|
||||
M.portable_drive = src
|
||||
..(user, M, found)
|
||||
@@ -0,0 +1,62 @@
|
||||
/obj/item/weapon/computer_hardware/printer
|
||||
name = "printer"
|
||||
desc = "Computer-integrated printer with paper recycling module."
|
||||
power_usage = 100
|
||||
origin_tech = "programming=2;engineering=2"
|
||||
icon_state = "printer"
|
||||
w_class = 3
|
||||
var/stored_paper = 20
|
||||
var/max_paper = 30
|
||||
|
||||
/obj/item/weapon/computer_hardware/printer/diagnostics(mob/living/user)
|
||||
..()
|
||||
user << "Paper level: [stored_paper]/[max_paper]"
|
||||
|
||||
/obj/item/weapon/computer_hardware/printer/examine(mob/user)
|
||||
..()
|
||||
user << "<span class='notice'>Paper level: [stored_paper]/[max_paper]</span>"
|
||||
|
||||
|
||||
/obj/item/weapon/computer_hardware/printer/proc/print_text(var/text_to_print, var/paper_title = "")
|
||||
if(!stored_paper)
|
||||
return FALSE
|
||||
if(!check_functionality())
|
||||
return FALSE
|
||||
|
||||
var/obj/item/weapon/paper/P = new/obj/item/weapon/paper(get_turf(holder))
|
||||
|
||||
// Damaged printer causes the resulting paper to be somewhat harder to read.
|
||||
if(damage > damage_malfunction)
|
||||
P.info = stars(text_to_print, 100-malfunction_probability)
|
||||
else
|
||||
P.info = text_to_print
|
||||
if(paper_title)
|
||||
P.name = paper_title
|
||||
P.update_icon()
|
||||
stored_paper--
|
||||
P = null
|
||||
return TRUE
|
||||
|
||||
/obj/item/weapon/computer_hardware/printer/try_insert(obj/item/I, mob/living/user = null)
|
||||
if(istype(I, /obj/item/weapon/paper))
|
||||
if(user && !user.unEquip(I))
|
||||
return FALSE
|
||||
|
||||
if(stored_paper >= max_paper)
|
||||
user << "<span class='warning'>You try to add \the [I] into [src], but it's paper bin is full!</span>"
|
||||
return FALSE
|
||||
|
||||
user << "<span class='notice'>You insert \the [I] into [src]'s paper recycler.</span>"
|
||||
qdel(I)
|
||||
stored_paper++
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/weapon/computer_hardware/printer/mini
|
||||
name = "miniprinter"
|
||||
desc = "A small printer with paper recycling module."
|
||||
power_usage = 50
|
||||
icon_state = "printer_mini"
|
||||
w_class = 1
|
||||
stored_paper = 5
|
||||
max_paper = 15
|
||||
@@ -1,51 +0,0 @@
|
||||
// CPU that allows the computer to run programs.
|
||||
// Better CPUs are obtainable via research and can run more programs on background.
|
||||
|
||||
/obj/item/weapon/computer_hardware/processor_unit
|
||||
name = "standard processor"
|
||||
desc = "A standard CPU used in most computers. It can run up to three programs simultaneously."
|
||||
icon_state = "cpu_normal"
|
||||
hardware_size = 2
|
||||
power_usage = 50
|
||||
critical = 1
|
||||
malfunction_probability = 1
|
||||
origin_tech = list("programming" = 3, "engineering" = 2)
|
||||
|
||||
var/max_idle_programs = 2 // 2 idle, + 1 active = 3 as said in description.
|
||||
|
||||
/obj/item/weapon/computer_hardware/processor_unit/small
|
||||
name = "standard microprocessor"
|
||||
desc = "A standard miniaturised CPU used in portable devices. It can run up to two programs simultaneously."
|
||||
icon_state = "cpu_small"
|
||||
hardware_size = 1
|
||||
power_usage = 25
|
||||
max_idle_programs = 1
|
||||
origin_tech = list("programming" = 2, "engineering" = 2)
|
||||
|
||||
/obj/item/weapon/computer_hardware/processor_unit/photonic
|
||||
name = "photonic processor"
|
||||
desc = "An advanced experimental CPU that uses photonic core instead of regular circuitry. It can run up to five programs simultaneously, but uses a lot of power."
|
||||
icon_state = "cpu_normal_photonic"
|
||||
hardware_size = 2
|
||||
power_usage = 250
|
||||
max_idle_programs = 4
|
||||
origin_tech = list("programming" = 5, "engineering" = 4)
|
||||
|
||||
/obj/item/weapon/computer_hardware/processor_unit/photonic/small
|
||||
name = "photonic microprocessor"
|
||||
desc = "An advanced miniaturised CPU for use in portable devices. It uses photonic core instead of regular circuitry. It can run up to three programs simultaneously."
|
||||
icon_state = "cpu_small_photonic"
|
||||
hardware_size = 1
|
||||
power_usage = 75
|
||||
max_idle_programs = 2
|
||||
origin_tech = list("programming" = 4, "engineering" = 3)
|
||||
|
||||
/obj/item/weapon/computer_hardware/processor_unit/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
|
||||
if(!user.drop_item(src))
|
||||
return
|
||||
if(M.processor_unit)
|
||||
user << "This computer's processor slot is already occupied by \the [M.processor_unit]."
|
||||
return
|
||||
found = 1
|
||||
M.processor_unit = src
|
||||
..(user, M, found)
|
||||
@@ -0,0 +1,91 @@
|
||||
/obj/item/weapon/computer_hardware/recharger
|
||||
critical = 1
|
||||
enabled = 1
|
||||
var/charge_rate = 100
|
||||
|
||||
/obj/item/weapon/computer_hardware/recharger/proc/use_power(amount, charging=0)
|
||||
if(charging)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/computer_hardware/recharger/process()
|
||||
..()
|
||||
if(!holder || !holder.battery_module || !holder.battery_module.battery)
|
||||
return
|
||||
|
||||
var/obj/item/weapon/stock_parts/cell/cell = holder.battery_module.battery
|
||||
if(cell.charge >= cell.maxcharge)
|
||||
return
|
||||
|
||||
if(use_power(charge_rate, charging=1))
|
||||
holder.give_power(charge_rate * CELLRATE)
|
||||
|
||||
|
||||
/obj/item/weapon/computer_hardware/recharger/APC
|
||||
name = "area power connector"
|
||||
desc = "A device that wirelessly recharges connected device from nearby APC."
|
||||
icon_state = "charger_APC"
|
||||
w_class = 2 // Can't be installed into tablets/PDAs
|
||||
origin_tech = "programming=2;engineering=2;powerstorage=3"
|
||||
|
||||
/obj/item/weapon/computer_hardware/recharger/APC/use_power(amount, charging=0)
|
||||
if(istype(holder.physical, /obj/machinery))
|
||||
var/obj/machinery/M = holder.physical
|
||||
if(M.powered())
|
||||
M.use_power(amount)
|
||||
return 1
|
||||
|
||||
else
|
||||
var/area/A = get_area(src)
|
||||
if(!A || !isarea(A) || !A.master)
|
||||
return 0
|
||||
|
||||
if(A.master.powered(EQUIP))
|
||||
A.master.use_power(amount, EQUIP)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/computer_hardware/recharger/wired
|
||||
name = "wired power connector"
|
||||
desc = "A power connector that recharges connected device from nearby power wire. Incompatible with portable computers."
|
||||
icon_state = "charger_wire"
|
||||
w_class = 3
|
||||
origin_tech = "engineering=2;powerstorage=1"
|
||||
|
||||
/obj/item/weapon/computer_hardware/recharger/wired/can_install(obj/item/device/modular_computer/M, mob/living/user = null)
|
||||
if(istype(M.physical, /obj/machinery) && M.physical.anchored)
|
||||
return ..()
|
||||
user << "<span class='warning'>\The [src] is incompatible with portable computers!</span>"
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/computer_hardware/recharger/wired/use_power(amount, charging=0)
|
||||
if(istype(holder.physical, /obj/machinery) && holder.physical.anchored)
|
||||
var/obj/machinery/M = holder.physical
|
||||
var/turf/T = M.loc
|
||||
if(!T || !istype(T))
|
||||
return 0
|
||||
|
||||
var/obj/structure/cable/C = T.get_cable_node()
|
||||
if(!C || !C.powernet)
|
||||
return 0
|
||||
|
||||
var/power_in_net = C.powernet.avail-C.powernet.load
|
||||
|
||||
if(power_in_net && power_in_net > amount)
|
||||
C.powernet.load += amount
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
// This is not intended to be obtainable in-game. Intended for adminbus and debugging purposes.
|
||||
/obj/item/weapon/computer_hardware/recharger/lambda
|
||||
name = "lambda coil"
|
||||
desc = "A very complex device that draws power from it's own bluespace dimension."
|
||||
icon_state = "charger_lambda"
|
||||
w_class = 1
|
||||
charge_rate = 100000
|
||||
|
||||
/obj/item/weapon/computer_hardware/recharger/lambda/use_power(amount, charging=0)
|
||||
return 1
|
||||
@@ -1,33 +0,0 @@
|
||||
/obj/item/weapon/computer_hardware/tesla_link
|
||||
name = "tesla link"
|
||||
desc = "An advanced tesla link that wirelessly recharges connected device from nearby area power controller."
|
||||
critical = 0
|
||||
enabled = 1
|
||||
icon_state = "teslalink"
|
||||
hardware_size = 2 // Can't be installed into tablets
|
||||
origin_tech = list("programming" = 2, "powerstorage" = 3, "engineering" = 2)
|
||||
var/obj/machinery/modular_computer/holder
|
||||
|
||||
/obj/item/weapon/computer_hardware/tesla_link/New(var/obj/L)
|
||||
if(istype(L, /obj/machinery/modular_computer))
|
||||
holder = L
|
||||
return
|
||||
..(L)
|
||||
|
||||
/obj/item/weapon/computer_hardware/tesla_link/Destroy()
|
||||
if(holder && (holder.tesla_link == src))
|
||||
holder.tesla_link = null
|
||||
..()
|
||||
|
||||
/obj/item/weapon/computer_hardware/tesla_link/try_install_component(mob/living/user, obj/item/modular_computer/M, found = 0)
|
||||
if(!user.drop_item(src))
|
||||
return
|
||||
if(istype(M, /obj/item/modular_computer/processor))
|
||||
var/obj/item/modular_computer/processor/P = M
|
||||
if(P.machinery_computer.tesla_link)
|
||||
user << "This computer's tesla link slot is already occupied by \the [P.machinery_computer.tesla_link]."
|
||||
return
|
||||
holder = P.machinery_computer
|
||||
P.machinery_computer.tesla_link = src
|
||||
found = 1
|
||||
..(user, M, found)
|
||||
@@ -10,8 +10,8 @@
|
||||
density = 1
|
||||
|
||||
// The actual laptop/tablet
|
||||
var/obj/machinery/modular_computer/laptop/fabricated_laptop = null
|
||||
var/obj/item/modular_computer/tablet/fabricated_tablet = null
|
||||
var/obj/item/device/modular_computer/laptop/fabricated_laptop = null
|
||||
var/obj/item/device/modular_computer/tablet/fabricated_tablet = null
|
||||
|
||||
// Utility vars
|
||||
var/state = 0 // 0: Select device type, 1: Select loadout, 2: Payment, 3: Thankyou screen
|
||||
@@ -24,8 +24,8 @@
|
||||
var/dev_battery = 1 // 1: Default, 2: Upgraded, 3: Advanced
|
||||
var/dev_disk = 1 // 1: Default, 2: Upgraded, 3: Advanced
|
||||
var/dev_netcard = 0 // 0: None, 1: Basic, 2: Long-Range
|
||||
var/dev_tesla = 0 // 0: None, 1: Standard (LAPTOP ONLY)
|
||||
var/dev_nanoprint = 0 // 0: None, 1: Standard
|
||||
var/dev_apc_recharger = 0 // 0: None, 1: Standard (LAPTOP ONLY)
|
||||
var/dev_printer = 0 // 0: None, 1: Standard
|
||||
var/dev_card = 0 // 0: None, 1: Standard
|
||||
|
||||
// Removes all traces of old order and allows you to begin configuration from scratch.
|
||||
@@ -42,8 +42,8 @@
|
||||
dev_battery = 1
|
||||
dev_disk = 1
|
||||
dev_netcard = 0
|
||||
dev_tesla = 0
|
||||
dev_nanoprint = 0
|
||||
dev_apc_recharger = 0
|
||||
dev_printer = 0
|
||||
dev_card = 0
|
||||
|
||||
// Recalculates the price and optionally even fabricates the device.
|
||||
@@ -51,109 +51,111 @@
|
||||
total_price = 0
|
||||
if(devtype == 1) // Laptop, generally cheaper to make it accessible for most station roles
|
||||
if(fabricate)
|
||||
fabricated_laptop = new(src)
|
||||
fabricated_laptop = new /obj/item/device/modular_computer/laptop/buildable(src)
|
||||
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/battery)
|
||||
total_price = 99
|
||||
switch(dev_cpu)
|
||||
if(1)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(fabricated_laptop.cpu)
|
||||
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/processor_unit/small)
|
||||
if(2)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.processor_unit = new/obj/item/weapon/computer_hardware/processor_unit(fabricated_laptop.cpu)
|
||||
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/processor_unit)
|
||||
total_price += 299
|
||||
switch(dev_battery)
|
||||
if(1) // Basic(750C)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.battery_module = new/obj/item/weapon/computer_hardware/battery_module(fabricated_laptop.cpu)
|
||||
fabricated_laptop.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer)
|
||||
if(2) // Upgraded(1100C)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.battery_module = new/obj/item/weapon/computer_hardware/battery_module/advanced(fabricated_laptop.cpu)
|
||||
fabricated_laptop.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/advanced)
|
||||
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)
|
||||
fabricated_laptop.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/super)
|
||||
total_price += 499
|
||||
switch(dev_disk)
|
||||
if(1) // Basic(128GQ)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive(fabricated_laptop.cpu)
|
||||
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/hard_drive)
|
||||
if(2) // Upgraded(256GQ)
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/advanced(fabricated_laptop.cpu)
|
||||
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/hard_drive/advanced)
|
||||
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)
|
||||
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/hard_drive/super)
|
||||
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)
|
||||
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/network_card)
|
||||
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)
|
||||
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/network_card/advanced)
|
||||
total_price += 299
|
||||
if(dev_tesla)
|
||||
if(dev_apc_recharger)
|
||||
total_price += 399
|
||||
if(fabricate)
|
||||
fabricated_laptop.tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(fabricated_laptop)
|
||||
if(dev_nanoprint)
|
||||
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/recharger/APC)
|
||||
if(dev_printer)
|
||||
total_price += 99
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(fabricated_laptop.cpu)
|
||||
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/printer/mini)
|
||||
if(dev_card)
|
||||
total_price += 199
|
||||
if(fabricate)
|
||||
fabricated_laptop.cpu.card_slot = new/obj/item/weapon/computer_hardware/card_slot(fabricated_laptop.cpu)
|
||||
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/card_slot)
|
||||
|
||||
return total_price
|
||||
else if(devtype == 2) // Tablet, more expensive, not everyone could probably afford this.
|
||||
if(fabricate)
|
||||
fabricated_tablet = new(src)
|
||||
fabricated_tablet.processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(fabricated_tablet)
|
||||
fabricated_tablet.install_component(new /obj/item/weapon/computer_hardware/battery)
|
||||
fabricated_tablet.install_component(new /obj/item/weapon/computer_hardware/processor_unit/small)
|
||||
total_price = 199
|
||||
switch(dev_battery)
|
||||
if(1) // Basic(300C)
|
||||
if(fabricate)
|
||||
fabricated_tablet.battery_module = new/obj/item/weapon/computer_hardware/battery_module/nano(fabricated_tablet)
|
||||
fabricated_tablet.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/nano)
|
||||
if(2) // Upgraded(500C)
|
||||
if(fabricate)
|
||||
fabricated_tablet.battery_module = new/obj/item/weapon/computer_hardware/battery_module/micro(fabricated_tablet)
|
||||
fabricated_tablet.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/micro)
|
||||
total_price += 199
|
||||
if(3) // Advanced(750C)
|
||||
if(fabricate)
|
||||
fabricated_tablet.battery_module = new/obj/item/weapon/computer_hardware/battery_module(fabricated_tablet)
|
||||
fabricated_tablet.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer)
|
||||
total_price += 499
|
||||
switch(dev_disk)
|
||||
if(1) // Basic(32GQ)
|
||||
if(fabricate)
|
||||
fabricated_tablet.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/micro(fabricated_tablet)
|
||||
fabricated_tablet.install_component(new /obj/item/weapon/computer_hardware/hard_drive/micro)
|
||||
if(2) // Upgraded(64GQ)
|
||||
if(fabricate)
|
||||
fabricated_tablet.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/small(fabricated_tablet)
|
||||
fabricated_tablet.install_component(new /obj/item/weapon/computer_hardware/hard_drive/small)
|
||||
total_price += 99
|
||||
if(3) // Advanced(128GQ)
|
||||
if(fabricate)
|
||||
fabricated_tablet.hard_drive = new/obj/item/weapon/computer_hardware/hard_drive(fabricated_tablet)
|
||||
fabricated_tablet.install_component(new /obj/item/weapon/computer_hardware/hard_drive)
|
||||
total_price += 299
|
||||
switch(dev_netcard)
|
||||
if(1) // Basic(Short-Range)
|
||||
if(fabricate)
|
||||
fabricated_tablet.network_card = new/obj/item/weapon/computer_hardware/network_card(fabricated_tablet)
|
||||
fabricated_tablet.install_component(new/obj/item/weapon/computer_hardware/network_card)
|
||||
total_price += 99
|
||||
if(2) // Advanced (Long Range)
|
||||
if(fabricate)
|
||||
fabricated_tablet.network_card = new/obj/item/weapon/computer_hardware/network_card/advanced(fabricated_tablet)
|
||||
fabricated_tablet.install_component(new/obj/item/weapon/computer_hardware/network_card/advanced)
|
||||
total_price += 299
|
||||
if(dev_nanoprint)
|
||||
if(dev_printer)
|
||||
total_price += 99
|
||||
if(fabricate)
|
||||
fabricated_tablet.nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(fabricated_tablet)
|
||||
fabricated_tablet.install_component(new/obj/item/weapon/computer_hardware/printer)
|
||||
if(dev_card)
|
||||
total_price += 199
|
||||
if(fabricate)
|
||||
fabricated_tablet.card_slot = new/obj/item/weapon/computer_hardware/card_slot(fabricated_tablet)
|
||||
fabricated_tablet.install_component(new/obj/item/weapon/computer_hardware/card_slot)
|
||||
return total_price
|
||||
return 0
|
||||
|
||||
@@ -200,11 +202,11 @@
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if("hw_tesla")
|
||||
dev_tesla = text2num(params["tesla"])
|
||||
dev_apc_recharger = text2num(params["tesla"])
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if("hw_nanoprint")
|
||||
dev_nanoprint = text2num(params["print"])
|
||||
dev_printer = text2num(params["print"])
|
||||
fabricate_and_recalc_price(0)
|
||||
return 1
|
||||
if("hw_card")
|
||||
@@ -232,7 +234,6 @@
|
||||
|
||||
|
||||
obj/machinery/lapvend/attackby(obj/item/I as obj, mob/user as mob)
|
||||
|
||||
if(istype(I,/obj/item/stack/spacecash))
|
||||
var/obj/item/stack/spacecash/c = I
|
||||
|
||||
@@ -249,12 +250,9 @@ obj/machinery/lapvend/attackby(obj/item/I as obj, mob/user as mob)
|
||||
if(process_payment(D,I))
|
||||
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
|
||||
say("Enjoy your new product!")
|
||||
@@ -283,8 +281,8 @@ obj/machinery/lapvend/attackby(obj/item/I as obj, mob/user as mob)
|
||||
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_tesla"] = dev_apc_recharger
|
||||
data["hw_nanoprint"] = dev_printer
|
||||
data["hw_card"] = dev_card
|
||||
data["hw_cpu"] = dev_cpu
|
||||
if(state == 1 || state == 2)
|
||||
|
||||
Reference in New Issue
Block a user