mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 16:18:01 +01:00
Integrated circuits for modular computers (#80530)
## About The Pull Request This PR integrates circuits for modular computers and a good bits of their programs. The peculiarity here is that modular computers have no fixed amount of unremovable components (except the base one with just a couple ports for now), instead, they're added and removed along with programs. With a few exceptions (such as the messenger and signaler), for these program circuits to work, their associated program has to be either open or in the background. For a reason or another, not all programs have a circuit associated to them, still, however the programs with a circuit are still a handful. They are: - Nanotrasen Pay System - Notepad - SiliConnect - WireCarp - MODsuit Control - Spectre Meter - Direct Messenger* - LifeConnect - Custodial Locator - Fission360 - Camera - Status Display - SignalCommander *By the by, sending messages has a cooldown, so it shouldn't be as spammy. If it turns out to not be enough, I can make it so messages from circuit will be ignored by other messenger circuits. The PR is no longer WIP. ## Why It's Good For The Game I believe modular computers could make for some interesting setups with circuits, since they're fairly flexible and stocked with features unlike many other appliances, therefore also a speck more abusable, though limits, cooldowns, logging and sanitization have been implemented to keep it in check. ## Changelog 🆑 add: Modular Computers now support integrated circuits. What can be done with them depends on the programs installed and whether they're running (open or background). add: Modular Consoles (the machinery) now have a small backup cell they draw power from if the power goes out. /🆑
This commit is contained in:
@@ -110,6 +110,15 @@
|
||||
///The max amount of paper that can be held at once.
|
||||
var/max_paper = 30
|
||||
|
||||
/// The capacity of the circuit shell component of this item
|
||||
var/shell_capacity = SHELL_CAPACITY_MEDIUM
|
||||
|
||||
/**
|
||||
* Reference to the circuit shell component, because we're special and do special things with it,
|
||||
* such as creating and deleting unremovable circuit comps based on the programs installed.
|
||||
*/
|
||||
var/datum/component/shell/shell
|
||||
|
||||
/datum/armor/item_modular_computer
|
||||
bullet = 20
|
||||
laser = 20
|
||||
@@ -120,6 +129,7 @@
|
||||
START_PROCESSING(SSobj, src)
|
||||
if(!physical)
|
||||
physical = src
|
||||
add_shell_component(shell_capacity)
|
||||
set_light_color(comp_light_color)
|
||||
set_light_range(comp_light_luminosity)
|
||||
if(looping_sound)
|
||||
@@ -137,6 +147,26 @@
|
||||
register_context()
|
||||
update_appearance()
|
||||
|
||||
///Initialize the shell for this item, or the physical machinery it belongs to.
|
||||
/obj/item/modular_computer/proc/add_shell_component(capacity = SHELL_CAPACITY_MEDIUM, shell_flags = NONE)
|
||||
shell = physical.AddComponent(/datum/component/shell, list(new /obj/item/circuit_component/modpc), capacity, shell_flags)
|
||||
RegisterSignal(shell, COMSIG_SHELL_CIRCUIT_ATTACHED, PROC_REF(on_circuit_attached))
|
||||
RegisterSignal(shell, COMSIG_SHELL_CIRCUIT_REMOVED, PROC_REF(on_circuit_removed))
|
||||
|
||||
/obj/item/modular_computer/proc/on_circuit_attached(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
RegisterSignal(shell.attached_circuit, COMSIG_CIRCUIT_PRE_POWER_USAGE, PROC_REF(use_power_for_circuits))
|
||||
|
||||
///Try to draw power from our internal cell first, before switching to that of the circuit.
|
||||
/obj/item/modular_computer/proc/use_power_for_circuits(datum/source, power_usage_per_input)
|
||||
SIGNAL_HANDLER
|
||||
if(use_power(power_usage_per_input, check_programs = FALSE))
|
||||
return COMPONENT_OVERRIDE_POWER_USAGE
|
||||
|
||||
/obj/item/modular_computer/proc/on_circuit_removed(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
UnregisterSignal(shell.attached_circuit, COMSIG_CIRCUIT_PRE_POWER_USAGE)
|
||||
|
||||
/obj/item/modular_computer/proc/install_default_programs()
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
for(var/programs in default_programs + starting_programs)
|
||||
@@ -158,6 +188,7 @@
|
||||
if(computer_id_slot)
|
||||
QDEL_NULL(computer_id_slot)
|
||||
|
||||
shell = null
|
||||
physical = null
|
||||
return ..()
|
||||
|
||||
@@ -438,29 +469,32 @@
|
||||
/obj/item/modular_computer/proc/turn_on(mob/user, open_ui = TRUE)
|
||||
var/issynth = issilicon(user) // Robots and AIs get different activation messages.
|
||||
if(atom_integrity <= integrity_failure * max_integrity)
|
||||
if(issynth)
|
||||
to_chat(user, span_warning("You send an activation signal to \the [src], but it responds with an error code. It must be damaged."))
|
||||
else
|
||||
to_chat(user, span_warning("You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again."))
|
||||
if(user)
|
||||
if(issynth)
|
||||
to_chat(user, span_warning("You send an activation signal to \the [src], but it responds with an error code. It must be damaged."))
|
||||
else
|
||||
to_chat(user, span_warning("You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again."))
|
||||
return FALSE
|
||||
|
||||
if(use_power()) // checks if the PC is powered
|
||||
if(issynth)
|
||||
to_chat(user, span_notice("You send an activation signal to \the [src], turning it on."))
|
||||
else
|
||||
to_chat(user, span_notice("You press the power button and start up \the [src]."))
|
||||
if(looping_sound)
|
||||
soundloop.start()
|
||||
enabled = TRUE
|
||||
update_appearance()
|
||||
if(open_ui)
|
||||
update_tablet_open_uis(user)
|
||||
if(user)
|
||||
if(issynth)
|
||||
to_chat(user, span_notice("You send an activation signal to \the [src], turning it on."))
|
||||
else
|
||||
to_chat(user, span_notice("You press the power button and start up \the [src]."))
|
||||
if(open_ui)
|
||||
update_tablet_open_uis(user)
|
||||
return TRUE
|
||||
else // Unpowered
|
||||
if(issynth)
|
||||
to_chat(user, span_warning("You send an activation signal to \the [src] but it does not respond."))
|
||||
else
|
||||
to_chat(user, span_warning("You press the power button but \the [src] does not respond."))
|
||||
if(user)
|
||||
if(issynth)
|
||||
to_chat(user, span_warning("You send an activation signal to \the [src] but it does not respond."))
|
||||
else
|
||||
to_chat(user, span_warning("You press the power button but \the [src] does not respond."))
|
||||
return FALSE
|
||||
|
||||
// Process currently calls handle_power(), may be expanded in future if more things are added.
|
||||
@@ -572,18 +606,22 @@
|
||||
if(program.computer != src)
|
||||
CRASH("tried to open program that does not belong to this computer")
|
||||
|
||||
if(!program || !istype(program)) // Program not found or it's not executable program.
|
||||
if(isnull(program) || !istype(program)) // Program not found or it's not executable program.
|
||||
if(user)
|
||||
to_chat(user, span_danger("\The [src]'s screen shows \"I/O ERROR - Unable to run program\" warning."))
|
||||
return FALSE
|
||||
|
||||
if(active_program == program)
|
||||
return FALSE
|
||||
|
||||
// The program is already running. Resume it.
|
||||
if(program in idle_threads)
|
||||
active_program?.background_program()
|
||||
active_program = program
|
||||
program.alert_pending = FALSE
|
||||
idle_threads.Remove(program)
|
||||
if(open_ui)
|
||||
update_tablet_open_uis(user)
|
||||
INVOKE_ASYNC(src, PROC_REF(update_tablet_open_uis), user)
|
||||
update_appearance(UPDATE_ICON)
|
||||
return TRUE
|
||||
|
||||
@@ -603,10 +641,12 @@
|
||||
if(!program.on_start(user))
|
||||
return FALSE
|
||||
|
||||
active_program?.background_program()
|
||||
|
||||
active_program = program
|
||||
program.alert_pending = FALSE
|
||||
if(open_ui)
|
||||
update_tablet_open_uis(user)
|
||||
INVOKE_ASYNC(src, PROC_REF(update_tablet_open_uis), user)
|
||||
update_appearance(UPDATE_ICON)
|
||||
return TRUE
|
||||
|
||||
@@ -682,10 +722,11 @@
|
||||
* It is separated from ui_act() to be overwritten as needed.
|
||||
*/
|
||||
/obj/item/modular_computer/proc/toggle_flashlight(mob/user)
|
||||
if(!has_light || !internal_cell || !internal_cell.charge)
|
||||
if(!has_light || !internal_cell?.charge)
|
||||
return FALSE
|
||||
if(!COOLDOWN_FINISHED(src, disabled_time))
|
||||
balloon_alert(user, "disrupted!")
|
||||
if(user)
|
||||
balloon_alert(user, "disrupted!")
|
||||
return FALSE
|
||||
set_light_on(!light_on)
|
||||
update_appearance()
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
///A simple circuit component compatible with stationary consoles, laptops and PDAs, independent from programs.
|
||||
/obj/item/circuit_component/modpc
|
||||
display_name = "Modular Computer"
|
||||
desc = "Circuit for basic functions of a modular computer."
|
||||
var/obj/item/modular_computer/computer
|
||||
///Turns the PC on/off
|
||||
var/datum/port/input/on_off
|
||||
///When set, will print a piece of paper with the value as text.
|
||||
var/datum/port/input/print
|
||||
|
||||
///Toggles lights on and off. Also RGB.
|
||||
var/datum/port/input/lights
|
||||
var/datum/port/input/red
|
||||
var/datum/port/input/green
|
||||
var/datum/port/input/blue
|
||||
|
||||
/obj/item/circuit_component/modpc/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
if(istype(shell, /obj/item/modular_computer))
|
||||
computer = shell
|
||||
else if(istype(shell, /obj/machinery/modular_computer))
|
||||
var/obj/machinery/modular_computer/console = shell
|
||||
computer = console.cpu
|
||||
|
||||
/**
|
||||
* Some mod pc have lights while some don't, but populate_ports()
|
||||
* is called before we get to know which object this has attahed to,
|
||||
* I hope you're cool with me doing it here.
|
||||
*/
|
||||
if(computer?.has_light)
|
||||
lights = add_input_port("Toggle Lights", PORT_TYPE_SIGNAL)
|
||||
red = add_input_port("Red", PORT_TYPE_NUMBER)
|
||||
green = add_input_port("Green", PORT_TYPE_NUMBER)
|
||||
blue = add_input_port("Blue", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/modpc/unregister_shell(atom/movable/shell)
|
||||
computer = null
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/modpc/populate_ports()
|
||||
on_off = add_input_port("Turn On/Off", PORT_TYPE_SIGNAL)
|
||||
print = add_input_port("Print Text", PORT_TYPE_STRING)
|
||||
|
||||
/obj/item/circuit_component/modpc/pre_input_received(datum/port/input/port)
|
||||
if(isnull(computer))
|
||||
return
|
||||
if(COMPONENT_TRIGGERED_BY(print, port))
|
||||
print.set_value(html_encode(trim(print.value, MAX_PAPER_LENGTH)))
|
||||
else if(COMPONENT_TRIGGERED_BY(red, port))
|
||||
red.set_value(clamp(red.value, 0, 255))
|
||||
else if(COMPONENT_TRIGGERED_BY(blue, port))
|
||||
blue.set_value(clamp(blue.value, 0, 255))
|
||||
else if(COMPONENT_TRIGGERED_BY(green, port))
|
||||
green.set_value(clamp(green.value, 0, 255))
|
||||
|
||||
/obj/item/circuit_component/modpc/input_received(datum/port/input/port)
|
||||
if(isnull(computer))
|
||||
return
|
||||
if(COMPONENT_TRIGGERED_BY(on_off, port))
|
||||
if(computer.enabled)
|
||||
INVOKE_ASYNC(computer, TYPE_PROC_REF(/obj/item/modular_computer, shutdown_computer))
|
||||
else
|
||||
INVOKE_ASYNC(computer, TYPE_PROC_REF(/obj/item/modular_computer, turn_on))
|
||||
return
|
||||
|
||||
if(!computer.enabled)
|
||||
return
|
||||
|
||||
if(COMPONENT_TRIGGERED_BY(print, port))
|
||||
computer.print_text(print.value)
|
||||
|
||||
if(lights)
|
||||
if(COMPONENT_TRIGGERED_BY(lights, port))
|
||||
computer.toggle_flashlight()
|
||||
if(COMPONENT_TRIGGERED_BY(red, port) || COMPONENT_TRIGGERED_BY(green, port) || COMPONENT_TRIGGERED_BY(blue, port))
|
||||
computer.set_flashlight_color(rgb(red.value || 0, green.value || 0, blue.value || 0))
|
||||
@@ -3,23 +3,24 @@
|
||||
|
||||
///Draws power from its rightful source (area if its a computer, the cell otherwise)
|
||||
///Takes into account special cases, like silicon PDAs through override, and nopower apps.
|
||||
/obj/item/modular_computer/proc/use_power(amount = 0)
|
||||
if(check_power_override())
|
||||
/obj/item/modular_computer/proc/use_power(amount = 0, check_programs = TRUE)
|
||||
if(check_power_override(amount))
|
||||
return TRUE
|
||||
|
||||
if(!internal_cell)
|
||||
return FALSE
|
||||
if(!internal_cell.charge && (isnull(active_program) || !(active_program.program_flags & PROGRAM_RUNS_WITHOUT_POWER)))
|
||||
close_all_programs()
|
||||
for(var/datum/computer_file/program/programs as anything in stored_files)
|
||||
if((programs.program_flags & PROGRAM_RUNS_WITHOUT_POWER) && open_program(program = programs))
|
||||
return TRUE
|
||||
if(internal_cell.use(amount JOULES))
|
||||
return TRUE
|
||||
if(!check_programs)
|
||||
return FALSE
|
||||
|
||||
if(!internal_cell.use(amount JOULES))
|
||||
internal_cell.use(min(amount JOULES, internal_cell.charge)) //drain it anyways.
|
||||
return FALSE
|
||||
return TRUE
|
||||
internal_cell.use(min(amount JOULES, internal_cell.charge)) //drain it anyways.
|
||||
if(active_program?.program_flags & PROGRAM_RUNS_WITHOUT_POWER)
|
||||
return TRUE
|
||||
INVOKE_ASYNC(src, PROC_REF(close_all_programs))
|
||||
for(var/datum/computer_file/program/programs as anything in stored_files)
|
||||
if((programs.program_flags & PROGRAM_RUNS_WITHOUT_POWER) && open_program(program = programs))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/modular_computer/proc/give_power(amount)
|
||||
if(internal_cell)
|
||||
@@ -59,8 +60,8 @@
|
||||
|
||||
///Returns TRUE if the PC should not be using any power, FALSE otherwise.
|
||||
///Checks to see if the current app allows to be ran without power, if so we'll run with it.
|
||||
/obj/item/modular_computer/proc/check_power_override()
|
||||
return (!internal_cell?.charge && (active_program?.program_flags & PROGRAM_RUNS_WITHOUT_POWER))
|
||||
/obj/item/modular_computer/proc/check_power_override(amount)
|
||||
return !amount && !internal_cell?.charge && (active_program?.program_flags & PROGRAM_RUNS_WITHOUT_POWER)
|
||||
|
||||
//Integrated (Silicon) tablets don't drain power, because the tablet is required to state laws, so it being disabled WILL cause problems.
|
||||
/obj/item/modular_computer/pda/silicon/check_power_override()
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
if("PC_minimize")
|
||||
if(!active_program || (!isnull(internal_cell) && !internal_cell.charge))
|
||||
return
|
||||
active_program.background_program()
|
||||
active_program.background_program(usr)
|
||||
return TRUE
|
||||
|
||||
if("PC_killprogram")
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
comp_light_luminosity = 2.3 //this is what old PDAs were set to
|
||||
looping_sound = FALSE
|
||||
|
||||
shell_capacity = SHELL_CAPACITY_SMALL
|
||||
|
||||
///The item currently inserted into the PDA, starts with a pen.
|
||||
var/obj/item/inserted_item = /obj/item/pen
|
||||
|
||||
@@ -331,6 +333,10 @@
|
||||
silicon_owner = null
|
||||
return ..()
|
||||
|
||||
///Silicons don't have the tools (or hands) to make circuits setups with their own PDAs.
|
||||
/obj/item/modular_computer/pda/silicon/add_shell_component(capacity)
|
||||
return
|
||||
|
||||
/obj/item/modular_computer/pda/silicon/turn_on(mob/user, open_ui = FALSE)
|
||||
if(silicon_owner?.stat != DEAD)
|
||||
return ..()
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
icon_state = null
|
||||
icon_state_unpowered = null
|
||||
icon_state_menu = null
|
||||
hardware_flag = 0
|
||||
hardware_flag = NONE
|
||||
internal_cell = /obj/item/stock_parts/cell/crap
|
||||
|
||||
///The modular computer MACHINE that hosts us.
|
||||
var/obj/machinery/modular_computer/machinery_computer
|
||||
@@ -25,7 +26,6 @@
|
||||
physical = loc
|
||||
machinery_computer = loc
|
||||
machinery_computer.cpu = src
|
||||
internal_cell = machinery_computer.internal_cell
|
||||
hardware_flag = machinery_computer.hardware_flag
|
||||
steel_sheet_cost = machinery_computer.steel_sheet_cost
|
||||
max_idle_programs = machinery_computer.max_idle_programs
|
||||
@@ -44,12 +44,12 @@
|
||||
machinery_computer = null
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/processor/use_power(amount = 0)
|
||||
/obj/item/modular_computer/processor/use_power(amount = 0, check_programs = TRUE)
|
||||
var/obj/machinery/machine_holder = physical
|
||||
if(machine_holder.powered())
|
||||
machine_holder.use_power(amount)
|
||||
return TRUE
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/processor/relay_qdel()
|
||||
qdel(machinery_computer)
|
||||
|
||||
Reference in New Issue
Block a user