mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-18 19:44:58 +01:00
[MIRROR] Integrated circuits for modular computers (#26196)
Integrated circuits for modular computers (#80530) 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. 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. 🆑 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. /🆑 Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
@@ -81,3 +81,8 @@
|
||||
|
||||
/// Called when an equipment action component is removed from a shell (/obj/item/circuit_component/equipment_action/action_comp)
|
||||
#define COMSIG_CIRCUIT_ACTION_COMPONENT_UNREGISTERED "circuit_action_component_unregistered"
|
||||
|
||||
///Sent to the shell component when a circuit is attached.
|
||||
#define COMSIG_SHELL_CIRCUIT_ATTACHED "shell_circuit_attached"
|
||||
///Sent to the shell component when a circuit is removed.
|
||||
#define COMSIG_SHELL_CIRCUIT_REMOVED "shell_circuit_removed"
|
||||
|
||||
@@ -9,7 +9,33 @@
|
||||
/// From /obj/item/modular_computer/proc/store_file: ()
|
||||
#define COMSIG_COMPUTER_FILE_DELETE "comsig_computer_file_delete"
|
||||
|
||||
/// From /datum/computer_file/program/on_start: (user)
|
||||
#define COMSIG_COMPUTER_PROGRAM_START "computer_program_start"
|
||||
|
||||
/// From /datum/computer_file/program/kill_program: (user)
|
||||
#define COMSIG_COMPUTER_PROGRAM_KILL "computer_program_kill"
|
||||
|
||||
/// From /datum/computer_file/program/nt_pay/make_payment: (payment_result)
|
||||
#define COMSIG_MODULAR_COMPUTER_NT_PAY_RESULT "comsig_modular_computer_nt_pay_result"
|
||||
|
||||
/// From /datum/computer_file/program/nt_pay/make_payment: (spookiness, manual)
|
||||
#define COMSIG_MODULAR_COMPUTER_SPECTRE_SCAN "comsig_modular_computer_spectre_scan"
|
||||
|
||||
/// From /datum/computer_file/program/radar/trackable: (atom/signal, turf/signal_turf, turf/computer_turf)
|
||||
#define COMSIG_MODULAR_COMPUTER_RADAR_TRACKABLE "comsig_modular_computer_radar_trackable"
|
||||
#define COMPONENT_RADAR_TRACK_ANYWAY (1<<0)
|
||||
#define COMPONENT_RADAR_DONT_TRACK (1<<1)
|
||||
/// From /datum/computer_file/program/radar/find_atom: (list/atom_container)
|
||||
#define COMSIG_MODULAR_COMPUTER_RADAR_FIND_ATOM "comsig_modular_computer_radar_find_atom"
|
||||
/// From /datum/computer_file/program/radar/ui_act, when action is "selecttarget": (selected_ref)
|
||||
#define COMSIG_MODULAR_COMPUTER_RADAR_SELECTED "comsig_modular_computer_radar_selected"
|
||||
|
||||
/// from /obj/item/modular_computer/imprint_id(): (name, job)
|
||||
#define COMSIG_MODULAR_PDA_IMPRINT_UPDATED "comsig_modular_pda_imprint_updated"
|
||||
/// from /obj/item/modular_computer/reset_id(): ()
|
||||
#define COMSIG_MODULAR_PDA_IMPRINT_RESET "comsig_modular_pda_imprint_reset"
|
||||
|
||||
/// From /datum/computer_file/program/messenger/receive_message, sent to the computer: (signal/subspace/messaging/tablet_message/signal, sender_job, sender_name)
|
||||
#define COMSIG_MODULAR_PDA_MESSAGE_RECEIVED "comsig_modular_pda_message_received"
|
||||
/// From /datum/computer_file/program/messenger/send_message_signal, sent to the computer: (atom/origin, datum/signal/subspace/messaging/tablet_message/signal)
|
||||
#define COMSIG_MODULAR_PDA_MESSAGE_SENT "comsig_modular_pda_message_sent"
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#define PROGRAM_HEADER (1<<4)
|
||||
///The program will run despite the ModPC not having any power in it.
|
||||
#define PROGRAM_RUNS_WITHOUT_POWER (1<<5)
|
||||
///The circuit ports of this program can be triggered even if the program is not open
|
||||
#define PROGRAM_CIRCUITS_RUN_WHEN_CLOSED (1<<6)
|
||||
|
||||
//Program categories
|
||||
#define PROGRAM_CATEGORY_DEVICE "Device Tools"
|
||||
|
||||
@@ -796,6 +796,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
#define TRAIT_PDA_CAN_EXPLODE "pda_can_explode"
|
||||
///The download speeds of programs from the dowloader is halved.
|
||||
#define TRAIT_MODPC_HALVED_DOWNLOAD_SPEED "modpc_halved_download_speed"
|
||||
///Dictates whether a user (source) is interacting with the frame of a stationary modular computer or the pc inside it. Needed for circuits I guess.
|
||||
#define TRAIT_MODPC_INTERACTING_WITH_FRAME "modpc_interacting_with_frame"
|
||||
|
||||
/// If present on a [/mob/living/carbon], will make them appear to have a medium level disease on health HUDs.
|
||||
#define TRAIT_DISEASELIKE_SEVERITY_MEDIUM "diseaselike_severity_medium"
|
||||
|
||||
@@ -563,6 +563,9 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
/obj/item/reagent_containers = list(
|
||||
"TRAIT_MAY_CONTAIN_BLENDED_DUST" = TRAIT_MAY_CONTAIN_BLENDED_DUST,
|
||||
),
|
||||
/obj/machinery/modular_computer = list(
|
||||
"TRAIT_MODPC_INTERACTING_WITH_FRAME" = TRAIT_MODPC_INTERACTING_WITH_FRAME,
|
||||
),
|
||||
/obj/projectile = list(
|
||||
"TRAIT_ALWAYS_HIT_ZONE" = TRAIT_ALWAYS_HIT_ZONE,
|
||||
),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// Makes an atom a shell that is able to take in an attached circuit.
|
||||
/datum/component/shell
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
||||
|
||||
/// The circuitboard attached to this shell
|
||||
var/obj/item/integrated_circuit/attached_circuit
|
||||
@@ -60,12 +60,15 @@
|
||||
unremovable_circuit_components = list()
|
||||
|
||||
for(var/obj/item/circuit_component/circuit_component as anything in components)
|
||||
if(ispath(circuit_component))
|
||||
circuit_component = new circuit_component()
|
||||
circuit_component.removable = FALSE
|
||||
circuit_component.set_circuit_size(0)
|
||||
RegisterSignal(circuit_component, COMSIG_CIRCUIT_COMPONENT_SAVE, PROC_REF(save_component))
|
||||
unremovable_circuit_components += circuit_component
|
||||
add_unremovable_circuit_component(circuit_component)
|
||||
|
||||
/datum/component/shell/proc/add_unremovable_circuit_component(obj/item/circuit_component/component)
|
||||
if(ispath(component))
|
||||
component = new component()
|
||||
component.removable = FALSE
|
||||
component.set_circuit_size(0)
|
||||
RegisterSignal(component, COMSIG_CIRCUIT_COMPONENT_SAVE, PROC_REF(save_component))
|
||||
unremovable_circuit_components += component
|
||||
|
||||
/datum/component/shell/proc/save_component(datum/source, list/objects)
|
||||
SIGNAL_HANDLER
|
||||
@@ -305,6 +308,7 @@
|
||||
return
|
||||
locked = FALSE
|
||||
attached_circuit = circuitboard
|
||||
SEND_SIGNAL(src, COMSIG_SHELL_CIRCUIT_ATTACHED)
|
||||
if(!(shell_flags & SHELL_FLAG_CIRCUIT_UNREMOVABLE) && !circuitboard.admin_only)
|
||||
RegisterSignal(circuitboard, COMSIG_MOVABLE_MOVED, PROC_REF(on_circuit_moved))
|
||||
if(shell_flags & SHELL_FLAG_REQUIRE_ANCHOR)
|
||||
@@ -348,6 +352,7 @@
|
||||
attached_circuit.remove_component(to_remove)
|
||||
to_remove.moveToNullspace()
|
||||
attached_circuit.set_locked(FALSE)
|
||||
SEND_SIGNAL(src, COMSIG_SHELL_CIRCUIT_REMOVED)
|
||||
attached_circuit = null
|
||||
|
||||
/datum/component/shell/proc/on_atom_usb_cable_try_attach(atom/source, obj/item/usb_cable/usb_cable, mob/user)
|
||||
|
||||
@@ -384,17 +384,18 @@
|
||||
|
||||
// PDA signal responses
|
||||
|
||||
/datum/component/uplink/proc/new_ringtone(datum/source, mob/living/user, new_ring_text)
|
||||
/datum/component/uplink/proc/new_ringtone(datum/source, atom/source, new_ring_text)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(trim(lowertext(new_ring_text)) != trim(lowertext(unlock_code)))
|
||||
if(trim(lowertext(new_ring_text)) == trim(lowertext(failsafe_code)))
|
||||
failsafe(user)
|
||||
failsafe(source)
|
||||
return COMPONENT_STOP_RINGTONE_CHANGE
|
||||
return
|
||||
locked = FALSE
|
||||
interact(null, user)
|
||||
to_chat(user, span_hear("The computer softly beeps."))
|
||||
if(ismob(source))
|
||||
interact(null, source)
|
||||
to_chat(source, span_hear("The computer softly beeps."))
|
||||
return COMPONENT_STOP_RINGTONE_CHANGE
|
||||
|
||||
/datum/component/uplink/proc/check_detonate()
|
||||
@@ -500,14 +501,22 @@
|
||||
locked = FALSE
|
||||
replacement_uplink.balloon_alert_to_viewers("beep", vision_distance = COMBAT_MESSAGE_RANGE)
|
||||
|
||||
/datum/component/uplink/proc/failsafe(mob/living/carbon/user)
|
||||
/datum/component/uplink/proc/failsafe(atom/source)
|
||||
if(!parent)
|
||||
return
|
||||
var/turf/T = get_turf(parent)
|
||||
if(!T)
|
||||
return
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] has triggered an uplink failsafe explosion at [AREACOORD(T)] The owner of the uplink was [ADMIN_LOOKUPFLW(owner)].")
|
||||
user.log_message("triggered an uplink failsafe explosion. Uplink owner: [key_name(owner)].", LOG_ATTACK)
|
||||
var/user_deets = "an uplink failsafe explosion has been triggered"
|
||||
if(ismob(source))
|
||||
user_deets = "[ADMIN_LOOKUPFLW(source)] has triggered an uplink failsafe explosion"
|
||||
source.log_message("triggered an uplink failsafe explosion. Uplink owner: [key_name(owner)].", LOG_ATTACK)
|
||||
else if(istype(source, /obj/item/circuit_component))
|
||||
var/obj/item/circuit_component/circuit = source
|
||||
user_deets = "[circuit.parent.get_creator_admin()] has triggered an uplink failsafe explosion"
|
||||
else
|
||||
source?.log_message("somehow triggered an uplink failsafe explosion. Uplink owner: [key_name(owner)].", LOG_ATTACK)
|
||||
message_admins("[user_deets] at [AREACOORD(T)] The owner of the uplink was [ADMIN_LOOKUPFLW(owner)].")
|
||||
|
||||
explosion(parent, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3)
|
||||
qdel(parent) //Alternatively could brick the uplink.
|
||||
|
||||
@@ -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)
|
||||
@@ -60,8 +61,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
|
||||
|
||||
@@ -337,6 +339,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)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#define CPU_INTERACTABLE(user) (cpu && !HAS_TRAIT_FROM(src, TRAIT_MODPC_INTERACTING_WITH_FRAME, REF(user)))
|
||||
|
||||
// Modular Computer - A machinery that is mostly just a host to the Modular Computer item.
|
||||
/obj/machinery/modular_computer
|
||||
name = "modular computer"
|
||||
@@ -9,8 +11,6 @@
|
||||
max_integrity = 300
|
||||
integrity_failure = 0.5
|
||||
|
||||
///The power cell, null by default as we use the APC we're in
|
||||
var/internal_cell = null
|
||||
///A flag that describes this device type
|
||||
var/hardware_flag = PROGRAM_CONSOLE
|
||||
/// Amount of programs that can be ran at once
|
||||
@@ -41,23 +41,42 @@
|
||||
. = ..()
|
||||
cpu = new(src)
|
||||
cpu.screen_on = TRUE
|
||||
cpu.add_shell_component(SHELL_CAPACITY_LARGE, SHELL_FLAG_USB_PORT)
|
||||
update_appearance()
|
||||
register_context()
|
||||
|
||||
/obj/machinery/modular_computer/Destroy()
|
||||
QDEL_NULL(cpu)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/modular_computer/add_context(atom/source, list/context, obj/item/held_item, mob/user)
|
||||
. = ..()
|
||||
if(isnull(held_item))
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Toggle processor interaction"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
/obj/machinery/modular_computer/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(HAS_TRAIT_FROM(src, TRAIT_MODPC_INTERACTING_WITH_FRAME, REF(user)))
|
||||
REMOVE_TRAIT(src, TRAIT_MODPC_INTERACTING_WITH_FRAME, REF(user))
|
||||
balloon_alert(user, "now interacting with computer")
|
||||
else
|
||||
ADD_TRAIT(src, TRAIT_MODPC_INTERACTING_WITH_FRAME, REF(user))
|
||||
balloon_alert(user, "now interacting with frame")
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/machinery/modular_computer/examine(mob/user)
|
||||
if(cpu)
|
||||
return cpu.examine(user)
|
||||
return ..()
|
||||
. = cpu?.examine(user) || ..()
|
||||
. += span_info("You can toggle interaction between computer and its machinery frame with [EXAMINE_HINT("Right-Click")] while empty-handed.")
|
||||
. += span_info("Currently interacting with [EXAMINE_HINT(HAS_TRAIT_FROM(src, TRAIT_MODPC_INTERACTING_WITH_FRAME, REF(user)) ? "frame" : "computer")].")
|
||||
|
||||
/obj/machinery/modular_computer/attack_ghost(mob/dead/observer/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(cpu)
|
||||
cpu.attack_ghost(user)
|
||||
cpu?.attack_ghost(user)
|
||||
|
||||
/obj/machinery/modular_computer/emag_act(mob/user, obj/item/card/emag/emag_card)
|
||||
if(!cpu)
|
||||
@@ -98,17 +117,14 @@
|
||||
|
||||
/obj/machinery/modular_computer/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!can_interact(user))
|
||||
if(CPU_INTERACTABLE(user) || !can_interact(user))
|
||||
return
|
||||
if(cpu)
|
||||
cpu.AltClick(user)
|
||||
cpu.AltClick(user)
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
// On-click handling. Turns on the computer if it's off and opens the GUI.
|
||||
/obj/machinery/modular_computer/interact(mob/user)
|
||||
if(cpu)
|
||||
return cpu.interact(user)
|
||||
return ..()
|
||||
return CPU_INTERACTABLE(user) ? cpu.interact(user) : ..()
|
||||
|
||||
// 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()
|
||||
@@ -118,30 +134,33 @@
|
||||
return
|
||||
return ..()
|
||||
|
||||
///Try to recharge our internal cell if it isn't fully charged.
|
||||
/obj/machinery/modular_computer/process(seconds_per_tick)
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(isnull(cell) || cell.percent() >= 100)
|
||||
return
|
||||
var/power_to_draw = idle_power_usage * seconds_per_tick * 0.5
|
||||
if(!use_power_from_net(power_to_draw))
|
||||
return
|
||||
cell.give(power_to_draw)
|
||||
|
||||
/obj/machinery/modular_computer/get_cell()
|
||||
return cpu?.internal_cell
|
||||
|
||||
/obj/machinery/modular_computer/screwdriver_act(mob/user, obj/item/tool)
|
||||
if(cpu)
|
||||
return cpu.screwdriver_act(user, tool)
|
||||
return ..()
|
||||
return CPU_INTERACTABLE(user) ? cpu.screwdriver_act(user, tool) : ..()
|
||||
|
||||
/obj/machinery/modular_computer/wrench_act_secondary(mob/user, obj/item/tool)
|
||||
if(cpu)
|
||||
return cpu.wrench_act_secondary(user, tool)
|
||||
return ..()
|
||||
return CPU_INTERACTABLE(user) ? cpu.wrench_act_secondary(user, tool) : ..()
|
||||
|
||||
/obj/machinery/modular_computer/welder_act(mob/user, obj/item/tool)
|
||||
if(cpu)
|
||||
return cpu.welder_act(user, tool)
|
||||
return ..()
|
||||
return CPU_INTERACTABLE(user) ? cpu.welder_act(user, tool) : ..()
|
||||
|
||||
/obj/machinery/modular_computer/attackby(obj/item/W as obj, mob/living/user)
|
||||
if (cpu && !user.combat_mode && !(obj_flags & NO_DECONSTRUCTION))
|
||||
return cpu.attackby(W, user)
|
||||
return ..()
|
||||
/obj/machinery/modular_computer/attackby(obj/item/weapon, mob/living/user)
|
||||
return (CPU_INTERACTABLE(user) && !user.combat_mode) ? cpu.attackby(weapon, user) : ..()
|
||||
|
||||
/obj/machinery/modular_computer/attacked_by(obj/item/attacking_item, mob/living/user)
|
||||
if (cpu)
|
||||
return cpu.attacked_by(attacking_item, user)
|
||||
return ..()
|
||||
return CPU_INTERACTABLE(user) ? cpu.attacked_by(attacking_item, user) : ..()
|
||||
|
||||
// Stronger explosions cause serious damage to internal components
|
||||
// Minor explosions are mostly mitigitated by casing.
|
||||
@@ -170,6 +189,6 @@
|
||||
// "Burn" damage is equally strong against internal components and exterior casing
|
||||
// "Brute" damage mostly damages the casing.
|
||||
/obj/machinery/modular_computer/bullet_act(obj/projectile/Proj)
|
||||
if(cpu)
|
||||
return cpu.bullet_act(Proj)
|
||||
return ..()
|
||||
return cpu?.bullet_act(Proj) || ..()
|
||||
|
||||
#undef CPU_INTERACTABLE
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
///Called post-installation of an application in a computer, after 'computer' var is set.
|
||||
/datum/computer_file/proc/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
|
||||
SIGNAL_HANDLER
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
computer_installing.stored_files.Add(src)
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,6 +44,40 @@
|
||||
var/alert_pending = FALSE
|
||||
/// How well this program will help combat detomatix viruses.
|
||||
var/detomatix_resistance = NONE
|
||||
/// Unremovable circuit componentn added to the physical computer while the program is installed
|
||||
var/obj/item/circuit_component/mod_program/circuit_comp_type
|
||||
|
||||
/datum/computer_file/program/New()
|
||||
..()
|
||||
///We need to ensure that different programs (subtypes mostly) won't try to load in the same circuit comps into the shell or usb port of the modpc.
|
||||
if(circuit_comp_type && initial(circuit_comp_type.associated_program) != type)
|
||||
stack_trace("circuit comp type mismatch: [type] has circuit comp type \[[circuit_comp_type]\], while \[[circuit_comp_type]\] has associated program \[[initial(circuit_comp_type.associated_program)]\].")
|
||||
|
||||
/**
|
||||
* Here we deal with peculiarity of adding unremovable components to the computer shell.
|
||||
* It probably doesn't look badass, but it's a decent way of doing it without taining the component with
|
||||
* oddities like this.
|
||||
*/
|
||||
/datum/computer_file/program/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
|
||||
. = ..()
|
||||
if(isnull(circuit_comp_type) || isnull(computer.shell))
|
||||
return
|
||||
if(!(locate(circuit_comp_type) in computer.shell.unremovable_circuit_components))
|
||||
var/obj/item/circuit_component/mod_program/comp = new circuit_comp_type()
|
||||
computer.shell.add_unremovable_circuit_component(comp)
|
||||
if(computer.shell.attached_circuit)
|
||||
comp.forceMove(computer.shell.attached_circuit)
|
||||
computer.shell.attached_circuit.add_component(comp)
|
||||
|
||||
///Here we deal with killing the associated components instead.
|
||||
/datum/computer_file/program/Destroy()
|
||||
if(isnull(circuit_comp_type) || isnull(computer?.shell))
|
||||
return ..()
|
||||
for(var/obj/item/circuit_component/mod_program/comp in computer.shell.unremovable_circuit_components)
|
||||
if(comp.associated_program == src)
|
||||
computer.shell.unremovable_circuit_components -= comp
|
||||
qdel(comp)
|
||||
return ..()
|
||||
|
||||
/datum/computer_file/program/clone()
|
||||
var/datum/computer_file/program/temp = ..()
|
||||
@@ -67,10 +101,6 @@
|
||||
/datum/computer_file/program/ui_interact(mob/user, datum/tgui/ui)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
|
||||
///We are not calling parent as it's handled by the computer itself, this is only called after.
|
||||
/datum/computer_file/program/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
|
||||
// Relays icon update to the computer.
|
||||
/datum/computer_file/program/proc/update_computer_icon()
|
||||
if(computer)
|
||||
@@ -167,12 +197,13 @@
|
||||
**/
|
||||
/datum/computer_file/program/proc/on_start(mob/living/user)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(can_run(user, loud = TRUE))
|
||||
if(program_flags & PROGRAM_REQUIRES_NTNET)
|
||||
var/obj/item/card/id/ID = computer.computer_id_slot?.GetID()
|
||||
generate_network_log("Connection opened -- Program ID:[filename] User:[ID?"[ID.registered_name]":"None"]")
|
||||
return TRUE
|
||||
return FALSE
|
||||
if(!can_run(user, loud = TRUE))
|
||||
return FALSE
|
||||
if(program_flags & PROGRAM_REQUIRES_NTNET)
|
||||
var/obj/item/card/id/ID = computer.computer_id_slot?.GetID()
|
||||
generate_network_log("Connection opened -- Program ID:[filename] User:[ID?"[ID.registered_name]":"None"]")
|
||||
SEND_SIGNAL(src, COMSIG_COMPUTER_PROGRAM_START, user)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Kills the running program
|
||||
@@ -189,25 +220,29 @@
|
||||
computer.active_program = null
|
||||
if(!QDELETED(computer) && computer.enabled)
|
||||
INVOKE_ASYNC(computer, TYPE_PROC_REF(/obj/item/modular_computer, update_tablet_open_uis), user)
|
||||
if(src in computer.idle_threads)
|
||||
else if(src in computer.idle_threads)
|
||||
computer.idle_threads.Remove(src)
|
||||
else //The program wasn't running to begin with.
|
||||
return FALSE
|
||||
|
||||
if(program_flags & PROGRAM_REQUIRES_NTNET)
|
||||
var/obj/item/card/id/ID = computer.computer_id_slot?.GetID()
|
||||
generate_network_log("Connection closed -- Program ID: [filename] User:[ID ? "[ID.registered_name]" : "None"]")
|
||||
|
||||
computer.update_appearance(UPDATE_ICON)
|
||||
SEND_SIGNAL(src, COMSIG_COMPUTER_PROGRAM_KILL, user)
|
||||
return TRUE
|
||||
|
||||
///Sends the running program to the background/idle threads. Header programs can't be minimized and will kill instead.
|
||||
/datum/computer_file/program/proc/background_program()
|
||||
/datum/computer_file/program/proc/background_program(mob/user)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(program_flags & PROGRAM_HEADER)
|
||||
if(program_flags & PROGRAM_HEADER || length(computer.idle_threads) > computer.max_idle_programs)
|
||||
return kill_program()
|
||||
|
||||
computer.idle_threads.Add(src)
|
||||
computer.active_program = null
|
||||
|
||||
computer.update_tablet_open_uis(usr)
|
||||
if(user)
|
||||
INVOKE_ASYNC(computer, TYPE_PROC_REF(/obj/item/modular_computer, update_tablet_open_uis), user)
|
||||
computer.update_appearance(UPDATE_ICON)
|
||||
return TRUE
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Circuit components of modular programs are special.
|
||||
* They're added to the unremovable components of the shell when the prog is installed and deleted if uninstalled.
|
||||
* This means they don't work like normal unremovable comps that live and die along with their shell.
|
||||
*/
|
||||
/obj/item/circuit_component/mod_program
|
||||
display_name = "Abstract Modular Program"
|
||||
desc = "I've spent lot of time thinking how to get this to work. If you see this, I either failed or someone else did, so report it."
|
||||
/**
|
||||
* The program that installed us into the shell/usb_port comp. Needed to avoid having too many signals for every program.
|
||||
* This is also the program we need to install on the modular computer if the circuit is admin-loaded.
|
||||
* Just make sure each of these components is associated to one and only type of program, no subtypes of anything.
|
||||
*/
|
||||
var/datum/computer_file/program/associated_program
|
||||
|
||||
///Starts the program if possible, placing it in the background if another's active.
|
||||
var/datum/port/input/start
|
||||
///kills the program.
|
||||
var/datum/port/input/kill
|
||||
///binary for whether the program is running or not
|
||||
var/datum/port/output/running
|
||||
|
||||
/obj/item/circuit_component/mod_program/Initialize(mapload)
|
||||
if(associated_program)
|
||||
display_name = initial(associated_program.filedesc)
|
||||
desc = initial(associated_program.extended_desc)
|
||||
return ..() // Set the name correctly
|
||||
|
||||
/obj/item/circuit_component/mod_program/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
var/obj/item/modular_computer/computer
|
||||
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
|
||||
|
||||
///Find the associated program in the computer's stored_files (install it otherwise) and store a reference to it.
|
||||
var/datum/computer_file/program/found_program = locate(associated_program) in computer.stored_files
|
||||
///The integrated circuit was loaded/duplicated
|
||||
if(isnull(found_program))
|
||||
associated_program = new associated_program()
|
||||
computer.store_file(associated_program)
|
||||
else
|
||||
associated_program = found_program
|
||||
|
||||
RegisterSignal(associated_program, COMSIG_COMPUTER_PROGRAM_START, PROC_REF(on_start))
|
||||
RegisterSignal(associated_program, COMSIG_COMPUTER_PROGRAM_KILL, PROC_REF(on_kill))
|
||||
|
||||
/obj/item/circuit_component/mod_program/unregister_shell()
|
||||
UnregisterSignal(associated_program, list(COMSIG_COMPUTER_PROGRAM_START, COMSIG_COMPUTER_PROGRAM_KILL))
|
||||
associated_program = initial(associated_program)
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mod_program/populate_ports()
|
||||
. = ..()
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
start = add_input_port("Start", PORT_TYPE_SIGNAL, trigger = PROC_REF(start_prog))
|
||||
kill = add_input_port("Kill", PORT_TYPE_SIGNAL, trigger = PROC_REF(kill_prog))
|
||||
running = add_output_port("Running", PORT_TYPE_NUMBER)
|
||||
|
||||
///For most programs, triggers only work if they're open (either active or idle).
|
||||
/obj/item/circuit_component/mod_program/should_receive_input(datum/port/input/port)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(isnull(associated_program))
|
||||
return FALSE
|
||||
if(associated_program.program_flags & PROGRAM_CIRCUITS_RUN_WHEN_CLOSED || COMPONENT_TRIGGERED_BY(start, port))
|
||||
return TRUE
|
||||
var/obj/item/modular_computer/computer = associated_program.computer
|
||||
if(computer.active_program == associated_program || (associated_program in computer.idle_threads))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/circuit_component/mod_program/proc/start_prog(datum/port/input/port)
|
||||
associated_program.computer.open_program(program = associated_program)
|
||||
|
||||
/obj/item/circuit_component/mod_program/proc/on_start(mob/living/user)
|
||||
SIGNAL_HANDLER
|
||||
running.set_value(TRUE)
|
||||
|
||||
/obj/item/circuit_component/mod_program/proc/kill_prog(datum/port/input/port)
|
||||
associated_program.kill_program()
|
||||
|
||||
/obj/item/circuit_component/mod_program/proc/on_kill(mob/living/user)
|
||||
SIGNAL_HANDLER
|
||||
running.set_value(FALSE)
|
||||
|
||||
/obj/item/circuit_component/mod_program/get_ui_notices()
|
||||
. = ..()
|
||||
if(!(associated_program.program_flags & PROGRAM_CIRCUITS_RUN_WHEN_CLOSED))
|
||||
. += create_ui_notice("Requires program to be running", "purple")
|
||||
@@ -97,6 +97,7 @@
|
||||
|
||||
|
||||
/datum/computer_file/program/ai_restorer/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("PRG_beginReconstruction")
|
||||
if(!stored_card || !stored_card.AI)
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
traitor_data = null
|
||||
return ..()
|
||||
|
||||
/datum/computer_file/program/contract_uplink/ui_act(action, params)
|
||||
/datum/computer_file/program/contract_uplink/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
return ..()
|
||||
|
||||
/datum/computer_file/program/ntnet_dos/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("PRG_target_relay")
|
||||
for(var/obj/machinery/ntnet_relay/relays as anything in SSmachines.get_machines_by_type(/obj/machinery/ntnet_relay))
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
spark_system.start()
|
||||
|
||||
/datum/computer_file/program/revelation/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("PRG_arm")
|
||||
armed = !armed
|
||||
|
||||
@@ -107,7 +107,8 @@
|
||||
data["BossID"] = "boss[boss_id].gif"
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/arcade/ui_act(action, list/params)
|
||||
/datum/computer_file/program/arcade/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
usr.played_game()
|
||||
var/gamerSkillLevel = 0
|
||||
var/gamerSkill = 0
|
||||
|
||||
@@ -67,7 +67,8 @@
|
||||
data["gasmixes"] = last_gasmix_data
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/atmosscan/ui_act(action, list/params)
|
||||
/datum/computer_file/program/atmosscan/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("scantoggle")
|
||||
if(atmozphere_mode == ATMOZPHERE_SCAN_CLICK)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
size = 5
|
||||
tgui_id = "NtosCyborgRemoteMonitor"
|
||||
program_icon = "project-diagram"
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/borg_monitor
|
||||
var/list/loglist = list() ///A list to copy a borg's IC log list into
|
||||
var/mob/living/silicon/robot/DL_source ///reference of a borg if we're downloading a log, or null if not.
|
||||
var/DL_progress = -1 ///Progress of current download, 0 to 100, -1 for no current download
|
||||
@@ -105,29 +106,46 @@
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/borg_monitor/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("messagebot")
|
||||
var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs
|
||||
if(!istype(R))
|
||||
return TRUE
|
||||
var/ID = checkID()
|
||||
if(!ID)
|
||||
return TRUE
|
||||
if(R.stat == DEAD) //Dead borgs will listen to you no longer
|
||||
to_chat(usr, span_warning("Error -- Could not open a connection to unit:[R]"))
|
||||
var/message = tgui_input_text(usr, "Message to be sent to remote cyborg", "Send Message")
|
||||
if(!message)
|
||||
return TRUE
|
||||
to_chat(R, "<br><br>[span_notice("Message from [ID] -- \"[message]\"")]<br>")
|
||||
to_chat(usr, "Message sent to [R]: [message]")
|
||||
R.logevent("Message from [ID] -- \"[message]\"")
|
||||
SEND_SOUND(R, 'sound/machines/twobeep_high.ogg')
|
||||
if(R.connected_ai)
|
||||
to_chat(R.connected_ai, "<br><br>[span_notice("Message from [ID] to [R] -- \"[message]\"")]<br>")
|
||||
SEND_SOUND(R.connected_ai, 'sound/machines/twobeep_high.ogg')
|
||||
usr.log_talk(message, LOG_PDA, tag="Cyborg Monitor Program: ID name \"[ID]\" to [R]")
|
||||
var/mob/living/silicon/robot/robot = locate(params["ref"]) in GLOB.silicon_mobs
|
||||
message_robot(robot, usr)
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/borg_monitor/proc/message_robot(mob/living/silicon/robot/robot, mob/user)
|
||||
if(!istype(robot))
|
||||
return TRUE
|
||||
var/ID = checkID()
|
||||
if(!ID)
|
||||
return FALSE
|
||||
if(robot.stat == DEAD) //Dead borgs will listen to you no longer
|
||||
to_chat(user, span_warning("Error -- Could not open a connection to unit:[robot]"))
|
||||
return FALSE
|
||||
var/message = tgui_input_text(user, "Message to be sent to remote cyborg", "Send Message")
|
||||
if(!message)
|
||||
return FALSE
|
||||
send_message(message, robot, user)
|
||||
|
||||
/datum/computer_file/program/borg_monitor/proc/send_message(message, mob/living/silicon/robot/robot, mob/user)
|
||||
var/ID = checkID()
|
||||
if(!ID)
|
||||
return FALSE
|
||||
if(robot.stat == DEAD) //Dead borgs will listen to you no longer
|
||||
if(user)
|
||||
to_chat(user, span_warning("Error -- Could not open a connection to unit:[robot]"))
|
||||
return FALSE
|
||||
to_chat(robot, "<br><br>[span_notice("Message from [ID] -- \"[message]\"")]<br>")
|
||||
if(user)
|
||||
to_chat(user, "Message sent to [robot]: [message]")
|
||||
robot.logevent("Message from [ID] -- \"[message]\"")
|
||||
SEND_SOUND(robot, 'sound/machines/twobeep_high.ogg')
|
||||
if(robot.connected_ai)
|
||||
to_chat(robot.connected_ai, "<br><br>[span_notice("Message from [ID] to [robot] -- \"[message]\"")]<br>")
|
||||
SEND_SOUND(robot.connected_ai, 'sound/machines/twobeep_high.ogg')
|
||||
user?.log_talk(message, LOG_PDA, tag = "Cyborg Monitor Program: ID name \"[ID]\" to [robot]")
|
||||
return TRUE
|
||||
|
||||
///This proc is used to determin if a borg should be shown in the list (based on the borg's scrambledcodes var). Syndicate version overrides this to show only syndicate borgs.
|
||||
/datum/computer_file/program/borg_monitor/proc/evaluate_borg(mob/living/silicon/robot/R)
|
||||
if(!is_valid_z_level(get_turf(computer), get_turf(R)))
|
||||
@@ -154,6 +172,7 @@
|
||||
extended_desc = "This program allows for remote monitoring of mission-assigned cyborgs."
|
||||
program_flags = PROGRAM_ON_SYNDINET_STORE
|
||||
download_access = list()
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/borg_monitor/syndie
|
||||
|
||||
/datum/computer_file/program/borg_monitor/syndicate/evaluate_borg(mob/living/silicon/robot/R)
|
||||
if(!is_valid_z_level(get_turf(computer), get_turf(R)))
|
||||
@@ -164,3 +183,31 @@
|
||||
|
||||
/datum/computer_file/program/borg_monitor/syndicate/checkID()
|
||||
return "\[CLASSIFIED\]" //no ID is needed for the syndicate version's message function, and the borg will see "[CLASSIFIED]" as the message sender.
|
||||
|
||||
/obj/item/circuit_component/mod_program/borg_monitor
|
||||
associated_program = /datum/computer_file/program/borg_monitor
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL
|
||||
|
||||
///Circuit input for the robot we want to message
|
||||
var/datum/port/input/target_robot
|
||||
///The message we want to send
|
||||
var/datum/port/input/set_message
|
||||
|
||||
/obj/item/circuit_component/mod_program/borg_monitor/populate_ports()
|
||||
. = ..()
|
||||
target_robot = add_input_port("Receiver", PORT_TYPE_ATOM)
|
||||
set_message = add_input_port("Set Message", PORT_TYPE_STRING, trigger = PROC_REF(sanitize_borg_message))
|
||||
|
||||
/obj/item/circuit_component/mod_program/borg_monitor/proc/sanitize_borg_message(datum/port/port)
|
||||
set_message.set_value(trim(html_encode(set_message.value), MAX_MESSAGE_LEN))
|
||||
|
||||
/obj/item/circuit_component/mod_program/borg_monitor/input_received(datum/port/port)
|
||||
if(!length(set_message.value) || !iscyborg(target_robot.value))
|
||||
return
|
||||
var/mob/living/silicon/robot/robot = target_robot.value
|
||||
var/datum/computer_file/program/borg_monitor/monitor = associated_program
|
||||
if(monitor.send_message(set_message.value, robot))
|
||||
monitor.computer.log_talk("Cyborg Monitor message (ID name \"[monitor.checkID()]\") sent to [key_name(robot)] by [parent.get_creator()]: [set_message.value]")
|
||||
|
||||
/obj/item/circuit_component/mod_program/borg_monitor/syndie
|
||||
associated_program = /datum/computer_file/program/borg_monitor/syndicate
|
||||
|
||||
@@ -57,7 +57,8 @@
|
||||
data["bountyText"] = bounty_text
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/bounty_board/ui_act(action, list/params)
|
||||
/datum/computer_file/program/bounty_board/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
var/current_ref_num = params["request"]
|
||||
var/current_app_num = params["applicant"]
|
||||
var/datum/bank_account/request_target
|
||||
|
||||
@@ -166,7 +166,8 @@
|
||||
data["max_order"] = CARGO_MAX_ORDER
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/budgetorders/ui_act(action, params, datum/tgui/ui)
|
||||
/datum/computer_file/program/budgetorders/ui_act(action, params, datum/tgui/ui, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("send")
|
||||
if(!SSshuttle.supply.canMove())
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
return ..()
|
||||
|
||||
/datum/computer_file/program/card_mod/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
var/mob/user = usr
|
||||
var/obj/item/card/id/inserted_auth_card = computer.computer_id_slot
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
data["barcode_split"] = cut_multiplier * 100
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/shipping/ui_act(action, list/params)
|
||||
/datum/computer_file/program/shipping/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
if(!computer.computer_id_slot) //We need an ID to successfully run
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
return new_converstaion
|
||||
|
||||
/datum/computer_file/program/chatclient/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
var/datum/ntnet_conversation/channel = SSmodular_computers.get_chat_channel_by_id(active_channel)
|
||||
var/authed = FALSE
|
||||
if(channel && ((channel.channel_operator == src) || netadmin_mode))
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
data["valid_id"] = TRUE
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/coupon/ui_act(action, params, datum/tgui/ui)
|
||||
/datum/computer_file/program/coupon/ui_act(action, params, datum/tgui/ui, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
var/obj/item/card/id/user_id = computer.computer_id_slot
|
||||
if(!(user_id?.registered_account.add_to_accounts))
|
||||
return TRUE
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
data["manifest"] = GLOB.manifest.get_manifest()
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/crew_manifest/ui_act(action, params, datum/tgui/ui)
|
||||
/datum/computer_file/program/crew_manifest/ui_act(action, params, datum/tgui/ui, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("PRG_print")
|
||||
if(computer) //This option should never be called if there is no printer
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
var/error
|
||||
|
||||
/datum/computer_file/program/filemanager/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("PRG_deletefile")
|
||||
var/datum/computer_file/file = computer.find_file_by_name(params["name"])
|
||||
|
||||
@@ -162,6 +162,7 @@
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/scipaper_program/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("et_alia")
|
||||
paper_to_be.et_alia = !paper_to_be.et_alia
|
||||
|
||||
@@ -53,7 +53,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
return FALSE
|
||||
|
||||
|
||||
/datum/computer_file/program/job_management/ui_act(action, params, datum/tgui/ui)
|
||||
/datum/computer_file/program/job_management/ui_act(action, params, datum/tgui/ui, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
var/obj/item/card/id/user_id = computer.computer_id_slot
|
||||
if(!user_id || !(ACCESS_CHANGE_IDS in user_id.access))
|
||||
return TRUE
|
||||
|
||||
@@ -49,7 +49,8 @@
|
||||
data += game.ui_assets(user)
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/mafia/ui_act(mob/user, params, datum/tgui/ui, datum/ui_state/state)
|
||||
/datum/computer_file/program/mafia/ui_act(mob/user, params, datum/tgui/ui, datum/ui_state/state, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
var/datum/mafia_controller/game = GLOB.mafia_game
|
||||
if(!game)
|
||||
game = create_mafia_game()
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
can_run_on_flags = PROGRAM_PDA
|
||||
tgui_id = "NtosCamera"
|
||||
program_icon = "camera"
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/camera
|
||||
|
||||
/// Camera built-into the tablet.
|
||||
var/obj/item/camera/internal_camera
|
||||
@@ -16,6 +17,48 @@
|
||||
/// How many pictures were taken already, used for the camera's TGUI photo display
|
||||
var/picture_number = 1
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera
|
||||
associated_program = /datum/computer_file/program/maintenance/camera
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL
|
||||
|
||||
///A target to take a picture of.
|
||||
var/datum/port/input/picture_target
|
||||
///The photographed target
|
||||
var/datum/port/output/photographed
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera/populate_ports()
|
||||
. = ..()
|
||||
picture_target = add_input_port("Picture Target", PORT_TYPE_ATOM)
|
||||
photographed = add_output_port("Photographed Entity", PORT_TYPE_ATOM)
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
var/datum/computer_file/program/maintenance/camera/cam = associated_program
|
||||
RegisterSignal(cam.internal_camera, COMSIG_CAMERA_IMAGE_CAPTURED, PROC_REF(on_image_captured))
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera/unregister_shell()
|
||||
var/datum/computer_file/program/maintenance/camera/cam = associated_program
|
||||
UnregisterSignal(cam.internal_camera, COMSIG_CAMERA_IMAGE_CAPTURED)
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera/input_received(datum/port/input/port)
|
||||
var/atom/target = picture_target.value
|
||||
if(!target)
|
||||
var/turf/our_turf = get_location()
|
||||
target = locate(our_turf.x, our_turf.y, our_turf.z)
|
||||
if(!target)
|
||||
return
|
||||
var/datum/computer_file/program/maintenance/camera/cam = associated_program
|
||||
if(!cam.internal_camera.can_target(target))
|
||||
return
|
||||
var/pic_size_x = cam.internal_camera.picture_size_x - 1
|
||||
var/pic_size_y = cam.internal_camera.picture_size_y - 1
|
||||
INVOKE_ASYNC(cam.internal_camera, TYPE_PROC_REF(/obj/item/camera, captureimage), target, null, pic_size_x, pic_size_y)
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera/proc/on_image_captured(obj/item/camera/source, atom/target, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
photographed.set_output(target)
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/on_install()
|
||||
. = ..()
|
||||
internal_camera = new(computer)
|
||||
@@ -50,13 +93,13 @@
|
||||
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/ui_act(action, params, datum/tgui/ui)
|
||||
var/mob/living/user = usr
|
||||
/datum/computer_file/program/maintenance/camera/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("print_photo")
|
||||
if(computer.stored_paper <= 0)
|
||||
to_chat(usr, span_notice("Hardware error: Printer out of paper."))
|
||||
return
|
||||
internal_camera.printpicture(user, internal_picture)
|
||||
internal_camera.printpicture(usr, internal_picture)
|
||||
computer.stored_paper--
|
||||
computer.visible_message(span_notice("\The [computer] prints out a paper."))
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
size = 2
|
||||
tgui_id = "NtosMODsuit"
|
||||
program_icon = "user-astronaut"
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/modsuit_control
|
||||
|
||||
///The suit we have control over.
|
||||
var/obj/item/mod/control/controlled_suit
|
||||
@@ -20,12 +21,15 @@
|
||||
. = ..()
|
||||
if(!istype(attacking_item, /obj/item/mod/control))
|
||||
return FALSE
|
||||
sync_modsuit(attacking_item, user)
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/maintenance/modsuit_control/proc/sync_modsuit(obj/item/mod/control/new_modsuit, mob/living/user)
|
||||
if(controlled_suit)
|
||||
unsync_modsuit()
|
||||
controlled_suit = attacking_item
|
||||
controlled_suit = new_modsuit
|
||||
RegisterSignal(controlled_suit, COMSIG_QDELETING, PROC_REF(unsync_modsuit))
|
||||
user.balloon_alert(user, "suit updated")
|
||||
return TRUE
|
||||
user?.balloon_alert(user, "suit updated")
|
||||
|
||||
/datum/computer_file/program/maintenance/modsuit_control/proc/unsync_modsuit(atom/source)
|
||||
SIGNAL_HANDLER
|
||||
@@ -43,4 +47,26 @@
|
||||
return controlled_suit?.ui_static_data()
|
||||
|
||||
/datum/computer_file/program/maintenance/modsuit_control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
return controlled_suit?.ui_act(action, params, ui, state)
|
||||
|
||||
|
||||
/obj/item/circuit_component/mod_program/modsuit_control
|
||||
associated_program = /datum/computer_file/program/maintenance/modsuit_control
|
||||
|
||||
///Circuit port for loading a new suit to control
|
||||
var/datum/port/input/suit_port
|
||||
|
||||
/obj/item/circuit_component/mod_program/modsuit_control/populate_ports()
|
||||
. = ..()
|
||||
suit_port = add_input_port("MODsuit Controlled", PORT_TYPE_ATOM)
|
||||
|
||||
/obj/item/circuit_component/mod_program/modsuit_control/input_received(datum/port/port)
|
||||
var/datum/computer_file/program/maintenance/modsuit_control/control = associated_program
|
||||
var/obj/item/mod/control/mod = suit_port.value
|
||||
if(isnull(mod) && control.controlled_suit)
|
||||
control.unsync_modsuit()
|
||||
return
|
||||
if(!istype(mod))
|
||||
return
|
||||
control.sync_modsuit(mod)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
#define SPOOK_VALUE_SAME_TURF_MULT 1.5
|
||||
#define SPOOK_VALUE_LIVING_MULT 6
|
||||
#define SPOOK_VALUE_DEF_MOB 10
|
||||
#define SPOOK_VALUE_ICON_STATE_MAX 120
|
||||
#define SPOOK_VALUE_SEGMENT 15
|
||||
#define SPOOK_COOLDOWN 2 SECONDS
|
||||
|
||||
/datum/computer_file/program/maintenance/spectre_meter
|
||||
filename = "spectre_meter"
|
||||
@@ -16,6 +16,7 @@
|
||||
tgui_id = "NtosSpectreMeter"
|
||||
program_icon = "ghost"
|
||||
program_open_overlay = "spectre_meter_0"
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/spectre_meter
|
||||
/// The cooldown for manual scans
|
||||
COOLDOWN_DECLARE(manual_scan_cd)
|
||||
/// Whether the automatic scan mode is active or not
|
||||
@@ -46,13 +47,11 @@
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/maintenance/spectre_meter/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("manual_scan")
|
||||
if(COOLDOWN_FINISHED(src, manual_scan_cd))
|
||||
INVOKE_ASYNC(src, PROC_REF(scan_surroundings))
|
||||
COOLDOWN_START(src, manual_scan_cd, 2 SECONDS)
|
||||
playsound(computer, 'sound/effects/ping_hit.ogg', vol = 40, vary = TRUE)
|
||||
return TRUE
|
||||
INVOKE_ASYNC(src, PROC_REF(scan_surroundings))
|
||||
return TRUE
|
||||
if("toggle_mode")
|
||||
auto_mode = !auto_mode
|
||||
if(auto_mode)
|
||||
@@ -67,10 +66,13 @@
|
||||
|
||||
/datum/computer_file/program/maintenance/spectre_meter/process(seconds_per_tick)
|
||||
if(auto_mode)
|
||||
INVOKE_ASYNC(src, PROC_REF(scan_surroundings))
|
||||
INVOKE_ASYNC(src, PROC_REF(scan_surroundings), FALSE)
|
||||
|
||||
///Return the "spook level" of the area the computer is in.
|
||||
/datum/computer_file/program/maintenance/spectre_meter/proc/scan_surroundings()
|
||||
/datum/computer_file/program/maintenance/spectre_meter/proc/scan_surroundings(manual = TRUE)
|
||||
if(manual && !COOLDOWN_FINISHED(src, manual_scan_cd))
|
||||
return
|
||||
|
||||
var/spook_value = 0
|
||||
var/turf/turf = get_turf(computer)
|
||||
|
||||
@@ -103,6 +105,12 @@
|
||||
if(program_open_overlay != old_open_overlay)
|
||||
computer.update_appearance(UPDATE_OVERLAYS)
|
||||
|
||||
if(manual)
|
||||
COOLDOWN_START(src, manual_scan_cd, SPOOK_COOLDOWN)
|
||||
playsound(computer, 'sound/effects/ping_hit.ogg', vol = 40, vary = TRUE)
|
||||
|
||||
SEND_SIGNAL(computer, COMSIG_MODULAR_COMPUTER_SPECTRE_SCAN, last_spook_value)
|
||||
|
||||
/datum/looping_sound/spectre_meter
|
||||
mid_sounds = /datum/looping_sound/geiger::mid_sounds
|
||||
mid_length = 2
|
||||
@@ -128,8 +136,41 @@
|
||||
last_spook_value = 0
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/circuit_component/mod_program/spectre_meter
|
||||
associated_program = /datum/computer_file/program/maintenance/spectre_meter
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL
|
||||
|
||||
/// Returns the spookiness of each scan.
|
||||
var/datum/port/output/scan_results
|
||||
|
||||
/obj/item/circuit_component/mod_program/spectre_meter/populate_ports()
|
||||
. = ..()
|
||||
scan_results = add_output_port("Scan Results", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/mod_program/spectre_meter/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
RegisterSignal(associated_program.computer, COMSIG_MODULAR_COMPUTER_SPECTRE_SCAN, PROC_REF(on_scan))
|
||||
|
||||
/obj/item/circuit_component/mod_program/spectre_meter/unregister_shell()
|
||||
UnregisterSignal(associated_program.computer, COMSIG_MODULAR_COMPUTER_SPECTRE_SCAN)
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mod_program/spectre_meter/get_ui_notices()
|
||||
. = ..()
|
||||
. += create_ui_notice("Scan Coooldown: [SPOOK_COOLDOWN]", "orange", "stopwatch")
|
||||
|
||||
/obj/item/circuit_component/mod_program/spectre_meter/input_received(datum/port/port)
|
||||
var/datum/computer_file/program/maintenance/spectre_meter/meter = associated_program
|
||||
INVOKE_ASYNC(meter, TYPE_PROC_REF(/datum/computer_file/program/maintenance/spectre_meter, scan_surroundings))
|
||||
|
||||
/obj/item/circuit_component/mod_program/spectre_meter/proc/on_scan(datum/source, spook_value)
|
||||
SIGNAL_HANDLER
|
||||
scan_results.set_value(spook_value)
|
||||
|
||||
#undef SPOOK_VALUE_SAME_TURF_MULT
|
||||
#undef SPOOK_VALUE_LIVING_MULT
|
||||
#undef SPOOK_VALUE_DEF_MOB
|
||||
#undef SPOOK_VALUE_ICON_STATE_MAX
|
||||
#undef SPOOK_VALUE_SEGMENT
|
||||
#undef SPOOK_COOLDOWN
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
///Called post-installation of an application in a computer, after 'computer' var is set.
|
||||
/datum/computer_file/program/maintenance/theme/on_install()
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
//add the theme to the computer and increase its size to match
|
||||
var/datum/computer_file/program/themeify/theme_app = locate() in computer.stored_files
|
||||
if(theme_app)
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
#define MESSENGER_CIRCUIT_MIN_COOLDOWN 5 SECONDS
|
||||
#define MESSENGER_CIRCUIT_MAX_COOLDOWN 45 SECONDS
|
||||
#define MESSENGER_CIRCUIT_CD_PER_RECIPIENT 1.5 SECONDS
|
||||
|
||||
/obj/item/circuit_component/mod_program/messenger
|
||||
associated_program = /datum/computer_file/program/messenger
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL
|
||||
|
||||
///Contents of the last received message
|
||||
var/datum/port/output/received_message
|
||||
///Name of the sender of the above
|
||||
var/datum/port/output/sender_name
|
||||
///Job title of the sender of the above
|
||||
var/datum/port/output/sender_job
|
||||
///Reference to the device that sent the message. Usually a PDA.
|
||||
var/datum/port/output/sender_device
|
||||
|
||||
///A message to be sent when triggered
|
||||
var/datum/port/input/message
|
||||
///A list of PDA targets for the message to be sent
|
||||
var/datum/port/input/targets
|
||||
|
||||
///Plays the ringtone when the input is received
|
||||
var/datum/port/input/ring
|
||||
///Set the ringtone to the input
|
||||
var/datum/port/input/set_ring
|
||||
|
||||
/obj/item/circuit_component/mod_program/messenger/populate_ports()
|
||||
. = ..()
|
||||
received_message = add_output_port("Received Message", PORT_TYPE_STRING)
|
||||
sender_name = add_output_port("Sender Name", PORT_TYPE_STRING)
|
||||
sender_job = add_output_port("Sender Job", PORT_TYPE_STRING)
|
||||
sender_device = add_output_port("Sender Device", PORT_TYPE_ATOM)
|
||||
|
||||
message = add_input_port("Message", PORT_TYPE_STRING)
|
||||
targets = add_input_port("Targets", PORT_TYPE_LIST(PORT_TYPE_ATOM))
|
||||
|
||||
ring = add_input_port("Play Ringtone", PORT_TYPE_SIGNAL, trigger = PROC_REF(play_ringtone))
|
||||
set_ring = add_input_port("Set Ringtone", PORT_TYPE_STRING, trigger = PROC_REF(set_ringtone))
|
||||
|
||||
///Sanitize the targets list so it doesn't contain duplicate targets and our own computer.
|
||||
/obj/item/circuit_component/mod_program/messenger/pre_input_received(datum/port/port)
|
||||
if(COMPONENT_TRIGGERED_BY(targets, port))
|
||||
targets.value = unique_list(targets.value) - associated_program.computer
|
||||
|
||||
/obj/item/circuit_component/mod_program/messenger/input_received(datum/port/port)
|
||||
var/list/messenger_targets = list()
|
||||
for(var/obj/item/modular_computer/modpc in targets.value)
|
||||
var/datum/computer_file/program/messenger/messenger = locate() in modpc.stored_files
|
||||
if(messenger)
|
||||
messenger_targets |= messenger
|
||||
var/messenger_length = length(messenger_targets)
|
||||
if(!messenger_length)
|
||||
return
|
||||
var/datum/computer_file/program/messenger/messenger = associated_program
|
||||
if(is_ic_filtered_for_pdas(message.value) || is_soft_ic_filtered_for_pdas(message.value))
|
||||
return
|
||||
///We need to async send_message() because some tcomms devices might sleep. Also because of (non-existent) user tgui alerts.
|
||||
INVOKE_ASYNC(messenger, TYPE_PROC_REF(/datum/computer_file/program/messenger, send_message), src, message.value, messenger_targets)
|
||||
|
||||
/obj/item/circuit_component/mod_program/messenger/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
RegisterSignal(associated_program.computer, COMSIG_MODULAR_PDA_MESSAGE_RECEIVED, PROC_REF(message_received))
|
||||
RegisterSignal(associated_program.computer, COMSIG_MODULAR_PDA_MESSAGE_SENT, PROC_REF(message_sent))
|
||||
|
||||
/obj/item/circuit_component/mod_program/messenger/unregister_shell()
|
||||
UnregisterSignal(associated_program.computer, list(COMSIG_MODULAR_PDA_MESSAGE_RECEIVED, COMSIG_MODULAR_PDA_MESSAGE_SENT))
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mod_program/messenger/get_ui_notices()
|
||||
. = ..()
|
||||
. += create_ui_notice("Cooldown per recipient: [DisplayTimeText(MESSENGER_CIRCUIT_CD_PER_RECIPIENT)]", "orange", "stopwatch")
|
||||
. += create_ui_notice("Minimum cooldown: [DisplayTimeText(MESSENGER_CIRCUIT_MIN_COOLDOWN)]", "orange", "stopwatch")
|
||||
. += create_ui_notice("Maximum cooldown: [DisplayTimeText(MESSENGER_CIRCUIT_MAX_COOLDOWN)]", "orange", "stopwatch")
|
||||
|
||||
/obj/item/circuit_component/mod_program/messenger/proc/message_received(datum/source, datum/signal/subspace/messaging/tablet_message/signal, message_job, message_name)
|
||||
SIGNAL_HANDLER
|
||||
received_message.set_value(signal.data["message"])
|
||||
sender_name.set_value(message_name)
|
||||
sender_job.set_value(message_job)
|
||||
|
||||
var/atom/source_device
|
||||
if(istype(signal.source, /datum/computer_file/program/messenger))
|
||||
var/datum/computer_file/program/messenger/sender_messenger = source
|
||||
source_device = sender_messenger.computer
|
||||
else if(isatom(signal.source))
|
||||
source_device = signal.source
|
||||
|
||||
sender_device.set_value(source_device)
|
||||
|
||||
///Set the cooldown after the message was sent (by us)
|
||||
/obj/item/circuit_component/mod_program/messenger/proc/message_sent(datum/source, atom/origin, datum/signal/subspace/messaging/tablet_message/signal)
|
||||
SIGNAL_HANDLER
|
||||
if(origin != src)
|
||||
return
|
||||
var/targets_length = length(signal.data["targets"])
|
||||
var/datum/computer_file/program/messenger/messenger = associated_program
|
||||
var/cool = clamp(targets_length * MESSENGER_CIRCUIT_CD_PER_RECIPIENT, MESSENGER_CIRCUIT_MIN_COOLDOWN, MESSENGER_CIRCUIT_MAX_COOLDOWN)
|
||||
COOLDOWN_START(messenger, last_text, cool)
|
||||
|
||||
/obj/item/circuit_component/mod_program/messenger/proc/set_ringtone(datum/port/port)
|
||||
var/datum/computer_file/program/messenger/messenger = associated_program
|
||||
messenger.set_ringtone(set_ring.value)
|
||||
|
||||
/obj/item/circuit_component/mod_program/messenger/proc/play_ringtone(datum/port/port)
|
||||
var/datum/computer_file/program/messenger/messenger = associated_program
|
||||
messenger.computer.ring(messenger.ringtone)
|
||||
|
||||
#undef MESSENGER_CIRCUIT_MIN_COOLDOWN
|
||||
#undef MESSENGER_CIRCUIT_MAX_COOLDOWN
|
||||
#undef MESSENGER_CIRCUIT_CD_PER_RECIPIENT
|
||||
+60
-30
@@ -14,12 +14,13 @@
|
||||
size = 0
|
||||
undeletable = TRUE // It comes by default in tablets, can't be downloaded, takes no space and should obviously not be able to be deleted.
|
||||
power_cell_use = NONE
|
||||
program_flags = PROGRAM_HEADER | PROGRAM_RUNS_WITHOUT_POWER
|
||||
program_flags = PROGRAM_HEADER | PROGRAM_RUNS_WITHOUT_POWER | PROGRAM_CIRCUITS_RUN_WHEN_CLOSED
|
||||
can_run_on_flags = PROGRAM_PDA
|
||||
ui_header = "ntnrc_idle.gif"
|
||||
tgui_id = "NtosMessenger"
|
||||
program_icon = "comment-alt"
|
||||
alert_able = TRUE
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/messenger
|
||||
|
||||
/// Whether the user is invisible to the message list.
|
||||
var/invisible = FALSE
|
||||
@@ -138,6 +139,18 @@
|
||||
for(var/datum/tgui/window as anything in computer.open_uis)
|
||||
SSassets.transport.send_assets(window.user, data)
|
||||
|
||||
/// Set the ringtone if possible. Also handles encoding.
|
||||
/datum/computer_file/program/messenger/proc/set_ringtone(new_ringtone, mob/user)
|
||||
new_ringtone = trim(html_encode(new_ringtone), MESSENGER_RINGTONE_MAX_LENGTH)
|
||||
if(!new_ringtone)
|
||||
return FALSE
|
||||
|
||||
if(SEND_SIGNAL(computer, COMSIG_TABLET_CHANGE_ID, user, new_ringtone) & COMPONENT_STOP_RINGTONE_CHANGE)
|
||||
return FALSE
|
||||
|
||||
ringtone = ringtone
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/messenger/ui_interact(mob/user, datum/tgui/ui)
|
||||
var/list/data = get_picture_assets()
|
||||
SSassets.transport.send_assets(user, data)
|
||||
@@ -147,19 +160,15 @@
|
||||
return GLOB.reverse_contained_state
|
||||
return GLOB.default_state
|
||||
|
||||
/datum/computer_file/program/messenger/ui_act(action, list/params, datum/tgui/ui)
|
||||
/datum/computer_file/program/messenger/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("PDA_ringSet")
|
||||
var/new_ringtone = tgui_input_text(usr, "Enter a new ringtone", "Ringtone", ringtone, MESSENGER_RINGTONE_MAX_LENGTH)
|
||||
var/mob/living/usr_mob = usr
|
||||
if(!new_ringtone || !in_range(computer, usr_mob) || computer.loc != usr_mob)
|
||||
var/mob/living/user = usr
|
||||
var/new_ringtone = tgui_input_text(user, "Enter a new ringtone", "Ringtone", ringtone, encode = FALSE)
|
||||
if(!in_range(computer, user) || computer.loc != user)
|
||||
return FALSE
|
||||
|
||||
if(SEND_SIGNAL(computer, COMSIG_TABLET_CHANGE_ID, usr_mob, new_ringtone) & COMPONENT_STOP_RINGTONE_CHANGE)
|
||||
return FALSE
|
||||
|
||||
ringtone = new_ringtone
|
||||
return TRUE
|
||||
return set_ringtone(new_ringtone, user)
|
||||
|
||||
if("PDA_toggleAlerts")
|
||||
alert_silenced = !alert_silenced
|
||||
@@ -451,18 +460,23 @@
|
||||
message = emoji_sanitize(message)
|
||||
|
||||
// check message against filter
|
||||
if(!check_pda_message_against_filter(message, sender))
|
||||
if(sender && !check_pda_message_against_filter(message, sender))
|
||||
return null
|
||||
|
||||
return message
|
||||
|
||||
/// Sends a message to targets via PDA. When sending to everyone, set `everyone` to true so the message is formatted accordingly
|
||||
/datum/computer_file/program/messenger/proc/send_message(mob/living/sender, message, list/targets, everyone = FALSE)
|
||||
/datum/computer_file/program/messenger/proc/send_message(atom/source, message, list/targets, everyone = FALSE)
|
||||
var/mob/living/sender
|
||||
if(isliving(source))
|
||||
sender = source
|
||||
else if(is_ic_filtered_for_pdas(message) || is_soft_ic_filtered_for_pdas(message))
|
||||
return FALSE
|
||||
message = sanitize_pda_message(message, sender)
|
||||
|
||||
if(!message)
|
||||
return FALSE
|
||||
|
||||
|
||||
// upgrade the image asset to a permanent key
|
||||
var/photo_asset_key = selected_image
|
||||
if(photo_asset_key == TEMP_IMAGE_PATH(REF(src)))
|
||||
@@ -474,7 +488,7 @@
|
||||
var/list/datum/computer_file/program/messenger/target_messengers = list()
|
||||
var/list/datum/pda_chat/target_chats = list()
|
||||
|
||||
var/should_alert = length(targets) == 1
|
||||
var/should_alert = length(targets) == 1 && sender
|
||||
|
||||
// filter out invalid targets
|
||||
for(var/target in targets)
|
||||
@@ -523,7 +537,7 @@
|
||||
target_chats += target_chat
|
||||
target_messengers += target_messenger
|
||||
|
||||
if(!send_message_signal(sender, message, target_messengers, photo_asset_key, everyone))
|
||||
if(!send_message_signal(source, message, target_messengers, photo_asset_key, everyone))
|
||||
return FALSE
|
||||
|
||||
// Log it in our logs
|
||||
@@ -553,8 +567,11 @@
|
||||
|
||||
return send_message_signal(sender, message, targets, fake_photo, FALSE, TRUE, fake_name, fake_job)
|
||||
|
||||
/datum/computer_file/program/messenger/proc/send_message_signal(mob/sender, message, list/datum/computer_file/program/messenger/targets, photo_path = null, everyone = FALSE, rigged = FALSE, fake_name = null, fake_job = null)
|
||||
if(!sender.can_perform_action(computer, ALLOW_RESTING))
|
||||
/datum/computer_file/program/messenger/proc/send_message_signal(atom/source, message, list/datum/computer_file/program/messenger/targets, photo_path = null, everyone = FALSE, rigged = FALSE, fake_name = null, fake_job = null)
|
||||
var/mob/sender
|
||||
if(ismob(source))
|
||||
sender = source
|
||||
if(sender && !sender.can_perform_action(computer, ALLOW_RESTING))
|
||||
return FALSE
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, last_text))
|
||||
@@ -566,7 +583,8 @@
|
||||
// check for jammers
|
||||
if(is_within_radio_jammer_range(computer) && !rigged)
|
||||
// different message so people know it's a radio jammer
|
||||
to_chat(sender, span_notice("ERROR: Network unavailable, please try again later."))
|
||||
if(sender)
|
||||
to_chat(sender, span_notice("ERROR: Network unavailable, please try again later."))
|
||||
if(alert_able && !alert_silenced)
|
||||
playsound(computer, 'sound/machines/terminal_error.ogg', 15, TRUE)
|
||||
return FALSE
|
||||
@@ -596,38 +614,46 @@
|
||||
|
||||
// If it didn't reach, note that fact
|
||||
if (!signal.data["done"])
|
||||
to_chat(sender, span_notice("ERROR: Server is not responding."))
|
||||
if(sender)
|
||||
to_chat(sender, span_notice("ERROR: Server is not responding."))
|
||||
if(alert_able && !alert_silenced)
|
||||
playsound(computer, 'sound/machines/terminal_error.ogg', 15, TRUE)
|
||||
return FALSE
|
||||
|
||||
|
||||
// SKYRAT EDIT BEGIN - PDA messages show a visible message; again!
|
||||
sender.visible_message(span_notice("[sender]'s PDA rings out with the soft sound of keypresses"), vision_distance = COMBAT_MESSAGE_RANGE)
|
||||
// SKYRAT EDIT END
|
||||
|
||||
var/shell_addendum = ""
|
||||
if(istype(source, /obj/item/circuit_component))
|
||||
var/obj/item/circuit_component/circuit = source
|
||||
shell_addendum = "[circuit.parent.get_creator()] "
|
||||
|
||||
// Log in the talk log
|
||||
sender.log_talk(message, LOG_PDA, tag="[rigged ? "Rigged" : ""] PDA: [computer.saved_identification] to [signal.format_target()]")
|
||||
source.log_talk(message, LOG_PDA, tag="[shell_addendum][rigged ? "Rigged" : ""] PDA: [computer.saved_identification] to [signal.format_target()]")
|
||||
if(rigged)
|
||||
log_bomber(sender, "sent a rigged PDA message (Name: [fake_name]. Job: [fake_job]) to [english_list(stringified_targets)] [!is_special_character(sender) ? "(SENT BY NON-ANTAG)" : ""]")
|
||||
|
||||
message = emoji_parse(message) //already sent- this just shows the sent emoji as one to the sender in the to_chat
|
||||
|
||||
// Show it to ghosts
|
||||
var/ghost_message = span_game_say("[span_name("[sender]")] [rigged ? "(as [span_name(fake_name)]) Rigged " : ""]PDA Message --> [span_name("[signal.format_target()]")]: \"[signal.format_message()]\"")
|
||||
var/ghost_message = span_game_say("[span_name("[source]")] [rigged ? "(as [span_name(fake_name)]) Rigged " : ""]PDA Message --> [span_name("[signal.format_target()]")]: \"[signal.format_message()]\"")
|
||||
var/list/message_listeners = GLOB.dead_player_list + GLOB.current_observers_list
|
||||
for(var/mob/listener as anything in message_listeners)
|
||||
if(!(get_chat_toggles(listener) & CHAT_GHOSTPDA))
|
||||
continue
|
||||
to_chat(listener, "[FOLLOW_LINK(listener, sender)] [ghost_message]")
|
||||
to_chat(listener, "[FOLLOW_LINK(listener, source)] [ghost_message]")
|
||||
|
||||
to_chat(sender, span_info("PDA message sent to [signal.format_target()]: \"[message]\""))
|
||||
if(sender)
|
||||
to_chat(sender, span_info("PDA message sent to [signal.format_target()]: \"[message]\""))
|
||||
|
||||
if (alert_able && !alert_silenced)
|
||||
computer.send_sound()
|
||||
|
||||
COOLDOWN_START(src, last_text, 1 SECONDS)
|
||||
|
||||
SEND_SIGNAL(computer, COMSIG_MODULAR_PDA_MESSAGE_SENT, source, signal)
|
||||
|
||||
selected_image = null
|
||||
return TRUE
|
||||
|
||||
@@ -642,6 +668,7 @@
|
||||
|
||||
var/sender_ref = signal.data["ref"]
|
||||
|
||||
|
||||
// don't create a new chat for rigged messages, make it a one off notif
|
||||
if(!is_rigged)
|
||||
var/datum/pda_message/message = new(signal.data["message"], FALSE, station_time_timestamp(PDA_MESSAGE_TIMESTAMP_FORMAT), signal.data["photo"], signal.data["everyone"])
|
||||
@@ -662,6 +689,14 @@
|
||||
if(computer.loc && isliving(computer.loc))
|
||||
receievers += computer.loc
|
||||
|
||||
// resolving w/o nullcheck here, assume the messenger exists if a real person sent a message
|
||||
var/datum/computer_file/program/messenger/sender_messenger = chat.recipient?.resolve()
|
||||
|
||||
var/sender_title = is_fake_user ? STRINGIFY_PDA_TARGET(fake_name, fake_job) : get_messenger_name(sender_messenger)
|
||||
var/sender_name = is_fake_user ? fake_name : sender_messenger.computer.saved_identification
|
||||
|
||||
SEND_SIGNAL(computer, COMSIG_MODULAR_PDA_MESSAGE_RECEIVED, signal, fake_job || sender_messenger?.computer.saved_job , sender_name)
|
||||
|
||||
for(var/mob/living/messaged_mob as anything in receievers)
|
||||
if(messaged_mob.stat >= UNCONSCIOUS)
|
||||
continue
|
||||
@@ -675,11 +710,6 @@
|
||||
else
|
||||
reply = "(<a href='byond://?src=[REF(src)];choice=[reply_href];skiprefresh=1;target=[REF(chat)]'>Reply</a>)"
|
||||
|
||||
// resolving w/o nullcheck here, assume the messenger exists if a real person sent a message
|
||||
var/datum/computer_file/program/messenger/sender_messenger = chat.recipient?.resolve()
|
||||
|
||||
var/sender_title = is_fake_user ? STRINGIFY_PDA_TARGET(fake_name, fake_job) : get_messenger_name(sender_messenger)
|
||||
var/sender_name = is_fake_user ? fake_name : sender_messenger.computer.saved_identification
|
||||
|
||||
if (isAI(messaged_mob))
|
||||
sender_title = "<a href='?src=[REF(messaged_mob)];track=[html_encode(sender_name)]'>[sender_title]</a>"
|
||||
|
||||
@@ -27,4 +27,5 @@
|
||||
return newscaster_ui.ui_static_data(user)
|
||||
|
||||
/datum/computer_file/program/newscaster/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
return newscaster_ui.ui_act(action, params, ui, state)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
tgui_id = "NtosNotepad"
|
||||
program_icon = "book"
|
||||
can_run_on_flags = PROGRAM_ALL
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/notepad
|
||||
|
||||
var/written_note = "Congratulations on your station upgrading to the new NtOS and Thinktronic based collaboration effort, \
|
||||
bringing you the best in electronics and software since 2467!\n\
|
||||
@@ -19,7 +20,8 @@
|
||||
Quarter - Either sides of Aft\n\
|
||||
Bow - Either sides of Fore"
|
||||
|
||||
/datum/computer_file/program/notepad/ui_act(action, list/params, datum/tgui/ui)
|
||||
/datum/computer_file/program/notepad/ui_act(action, list/params, datum/tgui/ui, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("UpdateNote")
|
||||
written_note = params["newnote"]
|
||||
@@ -31,3 +33,34 @@
|
||||
data["note"] = written_note
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/circuit_component/mod_program/notepad
|
||||
associated_program = /datum/computer_file/program/notepad
|
||||
///When the input is received, the written note will be set to its value.
|
||||
var/datum/port/input/set_text
|
||||
///The written note output, sent everytime notes are updated.
|
||||
var/datum/port/output/updated_text
|
||||
|
||||
/obj/item/circuit_component/mod_program/notepad/populate_ports()
|
||||
. = ..()
|
||||
set_text = add_input_port("Set Notes", PORT_TYPE_STRING)
|
||||
updated_text = add_output_port("Updated Notes", PORT_TYPE_STRING)
|
||||
|
||||
/obj/item/circuit_component/mod_program/notepad/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
RegisterSignal(associated_program, COMSIG_UI_ACT, PROC_REF(on_note_updated))
|
||||
|
||||
/obj/item/circuit_component/mod_program/notepad/unregister_shell()
|
||||
UnregisterSignal(associated_program, COMSIG_UI_ACT)
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mod_program/notepad/proc/on_note_updated(datum/source, mob/user, action, list/params)
|
||||
SIGNAL_HANDLER
|
||||
if(action == "UpdateNote")
|
||||
updated_text.set_output(params["newnote"])
|
||||
|
||||
/obj/item/circuit_component/mod_program/notepad/input_received(datum/port/port)
|
||||
var/datum/computer_file/program/notepad/pad = associated_program
|
||||
pad.written_note = set_text.value
|
||||
SStgui.update_uis(pad.computer)
|
||||
updated_text.set_output(pad.written_note)
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
#define NT_PAY_STATUS_NO_ACCOUNT 0
|
||||
#define NT_PAY_STATUS_DEPT_ACCOUNT 1
|
||||
#define NT_PAY_STATUS_INVALID_TOKEN 2
|
||||
#define NT_PAY_SATUS_SENDER_IS_RECEIVER 3
|
||||
#define NT_PAY_STATUS_INVALID_MONEY 4
|
||||
#define NT_PAY_STATUS_SUCCESS 5
|
||||
|
||||
/datum/computer_file/program/nt_pay
|
||||
filename = "ntpay"
|
||||
filedesc = "Nanotrasen Pay System"
|
||||
@@ -8,45 +15,19 @@
|
||||
tgui_id = "NtosPay"
|
||||
program_icon = "money-bill-wave"
|
||||
can_run_on_flags = PROGRAM_ALL
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/nt_pay
|
||||
///Reference to the currently logged in user.
|
||||
var/datum/bank_account/current_user
|
||||
///Pay token, by which we can send credits
|
||||
var/token
|
||||
///Amount of credits, which we sends
|
||||
var/money_to_send = 0
|
||||
///Pay token what we want to find
|
||||
var/wanted_token
|
||||
|
||||
/datum/computer_file/program/nt_pay/ui_act(action, list/params, datum/tgui/ui)
|
||||
/datum/computer_file/program/nt_pay/ui_act(action, list/params, datum/tgui/ui, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("Transaction")
|
||||
if(IS_DEPARTMENTAL_ACCOUNT(current_user))
|
||||
return to_chat(usr, span_notice("The app is unable to withdraw from that card."))
|
||||
|
||||
token = params["token"]
|
||||
money_to_send = params["amount"]
|
||||
var/datum/bank_account/recipient
|
||||
if(!token)
|
||||
return to_chat(usr, span_notice("You need to enter your transfer target's pay token."))
|
||||
if(!money_to_send)
|
||||
return to_chat(usr, span_notice("You need to specify how much you're sending."))
|
||||
if(token == current_user.pay_token)
|
||||
return to_chat(usr, span_notice("You can't send credits to yourself."))
|
||||
|
||||
for(var/account as anything in SSeconomy.bank_accounts_by_id)
|
||||
var/datum/bank_account/acc = SSeconomy.bank_accounts_by_id[account]
|
||||
if(acc.pay_token == token)
|
||||
recipient = acc
|
||||
break
|
||||
|
||||
if(!recipient)
|
||||
return to_chat(usr, span_notice("The app can't find who you're trying to pay. Did you enter the pay token right?"))
|
||||
if(!current_user.has_money(money_to_send) || money_to_send < 1)
|
||||
return current_user.bank_card_talk("You cannot afford it.")
|
||||
|
||||
recipient.bank_card_talk("You received [money_to_send] credit(s). Reason: transfer from [current_user.account_holder]")
|
||||
recipient.transfer_money(current_user, money_to_send)
|
||||
current_user.bank_card_talk("You send [money_to_send] credit(s) to [recipient.account_holder]. Now you have [current_user.account_balance] credit(s)")
|
||||
var/token = params["token"]
|
||||
var/money_to_send = params["amount"]
|
||||
make_payment(token, money_to_send, usr)
|
||||
|
||||
if("GetPayToken")
|
||||
wanted_token = null
|
||||
@@ -58,8 +39,6 @@
|
||||
if(!wanted_token)
|
||||
return wanted_token = "Account \"[params["wanted_name"]]\" not found."
|
||||
|
||||
|
||||
|
||||
/datum/computer_file/program/nt_pay/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
@@ -74,3 +53,99 @@
|
||||
data["transaction_list"] = current_user.transaction_history
|
||||
|
||||
return data
|
||||
|
||||
///Wrapper and signal for the main payment function of this program
|
||||
/datum/computer_file/program/nt_pay/proc/make_payment(token, money_to_send, mob/user)
|
||||
var/payment_result = _pay(token, money_to_send, user)
|
||||
SEND_SIGNAL(computer, COMSIG_MODULAR_COMPUTER_NT_PAY_RESULT, payment_result)
|
||||
|
||||
/datum/computer_file/program/nt_pay/proc/_pay(token, money_to_send, mob/user)
|
||||
if(IS_DEPARTMENTAL_ACCOUNT(current_user))
|
||||
if(user)
|
||||
to_chat(user, span_notice("The app is unable to withdraw from that card."))
|
||||
return NT_PAY_STATUS_DEPT_ACCOUNT
|
||||
|
||||
var/datum/bank_account/recipient
|
||||
if(!token)
|
||||
if(user)
|
||||
to_chat(user, span_notice("You need to enter your transfer target's pay token."))
|
||||
return NT_PAY_STATUS_INVALID_TOKEN
|
||||
if(money_to_send <= 0)
|
||||
if(user)
|
||||
to_chat(user, span_notice("You need to specify how much you're sending."))
|
||||
return NT_PAY_STATUS_INVALID_MONEY
|
||||
if(token == current_user.pay_token)
|
||||
if(user)
|
||||
to_chat(user, span_notice("You can't send credits to yourself."))
|
||||
return NT_PAY_SATUS_SENDER_IS_RECEIVER
|
||||
|
||||
for(var/account as anything in SSeconomy.bank_accounts_by_id)
|
||||
var/datum/bank_account/acc = SSeconomy.bank_accounts_by_id[account]
|
||||
if(acc.pay_token == token)
|
||||
recipient = acc
|
||||
break
|
||||
|
||||
if(!recipient)
|
||||
if(user)
|
||||
to_chat(user, span_notice("The app can't find who you're trying to pay. Did you enter the pay token right?"))
|
||||
return NT_PAY_STATUS_INVALID_TOKEN
|
||||
if(!current_user.has_money(money_to_send) || money_to_send < 1)
|
||||
current_user.bank_card_talk("You cannot afford it.")
|
||||
return NT_PAY_STATUS_INVALID_MONEY
|
||||
|
||||
recipient.bank_card_talk("You received [money_to_send] credit(s). Reason: transfer from [current_user.account_holder]")
|
||||
recipient.transfer_money(current_user, money_to_send)
|
||||
current_user.bank_card_talk("You send [money_to_send] credit(s) to [recipient.account_holder]. Now you have [current_user.account_balance] credit(s)")
|
||||
|
||||
return NT_PAY_STATUS_SUCCESS
|
||||
|
||||
|
||||
/obj/item/circuit_component/mod_program/nt_pay
|
||||
associated_program = /datum/computer_file/program/nt_pay
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL
|
||||
|
||||
///Circuit variables. This one is for the token we want to pay
|
||||
var/datum/port/input/token_port
|
||||
///The port for the money to send
|
||||
var/datum/port/input/money_port
|
||||
///Let's us know if the payment has gone through or not.
|
||||
var/datum/port/output/payment_status
|
||||
|
||||
/obj/item/circuit_component/mod_program/nt_pay/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
RegisterSignal(associated_program.computer, COMSIG_MODULAR_COMPUTER_NT_PAY_RESULT, PROC_REF(on_payment_result))
|
||||
|
||||
/obj/item/circuit_component/mod_program/nt_pay/unregister_shell()
|
||||
UnregisterSignal(associated_program.computer, COMSIG_MODULAR_COMPUTER_NT_PAY_RESULT)
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mod_program/nt_pay/populate_ports()
|
||||
. = ..()
|
||||
token_port = add_input_port("Token", PORT_TYPE_STRING)
|
||||
money_port = add_input_port("Amount", PORT_TYPE_NUMBER)
|
||||
payment_status = add_output_port("Status", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/mod_program/nt_pay/get_ui_notices()
|
||||
. = ..()
|
||||
. += create_ui_notice("NT-Pay Statuses:")
|
||||
. += create_ui_notice("Fail (No Account) - [NT_PAY_STATUS_NO_ACCOUNT]", "red")
|
||||
. += create_ui_notice("Fail (Dept Account) - [NT_PAY_STATUS_DEPT_ACCOUNT]", "red")
|
||||
. += create_ui_notice("Fail (Invalid Token) - [NT_PAY_STATUS_INVALID_TOKEN]", "red")
|
||||
. += create_ui_notice("Fail (Sender = Receiver) - [NT_PAY_SATUS_SENDER_IS_RECEIVER]", "red")
|
||||
. += create_ui_notice("Fail (Invalid Amount) - [NT_PAY_STATUS_INVALID_MONEY]", "red")
|
||||
. += create_ui_notice("Success - [NT_PAY_STATUS_SUCCESS]", "green")
|
||||
|
||||
/obj/item/circuit_component/mod_program/nt_pay/input_received(datum/port/port)
|
||||
var/datum/computer_file/program/nt_pay/program = associated_program
|
||||
program.make_payment(token_port.value, money_port.value)
|
||||
|
||||
/obj/item/circuit_component/mod_program/nt_pay/proc/on_payment_result(datum/source, payment_result)
|
||||
SIGNAL_HANDLER
|
||||
payment_status.set_output(payment_result)
|
||||
|
||||
#undef NT_PAY_STATUS_NO_ACCOUNT
|
||||
#undef NT_PAY_STATUS_DEPT_ACCOUNT
|
||||
#undef NT_PAY_STATUS_INVALID_TOKEN
|
||||
#undef NT_PAY_SATUS_SENDER_IS_RECEIVER
|
||||
#undef NT_PAY_STATUS_INVALID_MONEY
|
||||
#undef NT_PAY_STATUS_SUCCESS
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
download_completion += download_netspeed
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("PRG_downloadfile")
|
||||
if(!downloaded_file)
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
)
|
||||
|
||||
/datum/computer_file/program/portrait_printer/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("search")
|
||||
if(search_string != params["to_search"])
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
///The selected target is not trackable
|
||||
#define RADAR_NOT_TRACKABLE 0
|
||||
///The selected target is trackable
|
||||
#define RADAR_TRACKABLE 1
|
||||
///The selected target is trackable, even if subtypes would normally consider it untrackable.
|
||||
#define RADAR_TRACKABLE_ANYWAY 2
|
||||
|
||||
///If the target is something it shouldn't be normally tracking, this is the maximum distance within with it an be tracked.
|
||||
#define MAX_RADAR_CIRCUIT_DISTANCE 18
|
||||
|
||||
/datum/computer_file/program/radar //generic parent that handles most of the process
|
||||
filename = "genericfinder"
|
||||
filedesc = "debug_finder"
|
||||
@@ -58,12 +68,13 @@
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/radar/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("selecttarget")
|
||||
var/selected_new_ref = params["ref"]
|
||||
if(selected_new_ref in trackable_object_refs())
|
||||
selected = selected_new_ref
|
||||
SEND_SIGNAL(computer, COMSIG_MODULAR_COMPUTER_RADAR_SELECTED, selected)
|
||||
return TRUE
|
||||
|
||||
if("scan")
|
||||
@@ -133,13 +144,22 @@
|
||||
**arg1 is the atom being evaluated.
|
||||
*/
|
||||
/datum/computer_file/program/radar/proc/trackable(atom/movable/signal)
|
||||
if(!signal || !computer)
|
||||
return FALSE
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(isnull(signal) || isnull(computer))
|
||||
return RADAR_NOT_TRACKABLE
|
||||
var/turf/here = get_turf(computer)
|
||||
var/turf/there = get_turf(signal)
|
||||
if(!here || !there)
|
||||
return FALSE //I was still getting a runtime even after the above check while scanning, so fuck it
|
||||
return (there.z == here.z) || (is_station_level(here.z) && is_station_level(there.z))
|
||||
return RADAR_NOT_TRACKABLE //I was still getting a runtime even after the above check while scanning, so fuck it
|
||||
if(there.z != here.z && (!is_station_level(here.z) || !is_station_level(there.z)))
|
||||
return RADAR_NOT_TRACKABLE
|
||||
var/trackable_signal = SEND_SIGNAL(computer, COMSIG_MODULAR_COMPUTER_RADAR_TRACKABLE, signal, here, there)
|
||||
switch(trackable_signal)
|
||||
if(COMPONENT_RADAR_TRACK_ANYWAY)
|
||||
return RADAR_TRACKABLE_ANYWAY
|
||||
if(COMPONENT_RADAR_DONT_TRACK)
|
||||
return RADAR_NOT_TRACKABLE
|
||||
return RADAR_TRACKABLE
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -168,7 +188,10 @@
|
||||
*return an atom reference.
|
||||
*/
|
||||
/datum/computer_file/program/radar/proc/find_atom()
|
||||
return
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
var/list/atom_container = list(null)
|
||||
SEND_SIGNAL(computer, COMSIG_MODULAR_COMPUTER_RADAR_FIND_ATOM, atom_container)
|
||||
return atom_container[1]
|
||||
|
||||
//We use SSfastprocess for the program icon state because it runs faster than process_tick() does.
|
||||
/datum/computer_file/program/radar/process()
|
||||
@@ -221,9 +244,10 @@
|
||||
program_flags = PROGRAM_ON_NTNET_STORE | PROGRAM_REQUIRES_NTNET
|
||||
download_access = list(ACCESS_MEDICAL)
|
||||
program_icon = "heartbeat"
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/radar/medical
|
||||
|
||||
/datum/computer_file/program/radar/lifeline/find_atom()
|
||||
return locate(selected) in GLOB.human_list
|
||||
return ..() || (locate(selected) in GLOB.human_list)
|
||||
|
||||
/datum/computer_file/program/radar/lifeline/scan()
|
||||
objects = list()
|
||||
@@ -243,14 +267,16 @@
|
||||
objects += list(crewinfo)
|
||||
|
||||
/datum/computer_file/program/radar/lifeline/trackable(mob/living/carbon/human/humanoid)
|
||||
. = ..()
|
||||
if(. == RADAR_TRACKABLE_ANYWAY)
|
||||
return RADAR_TRACKABLE_ANYWAY
|
||||
if(!humanoid || !istype(humanoid))
|
||||
return FALSE
|
||||
if(..())
|
||||
if (istype(humanoid.w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/uniform = humanoid.w_uniform
|
||||
if(uniform.has_sensor && uniform.sensor_mode >= SENSOR_COORDS) // Suit sensors must be on maximum
|
||||
return TRUE
|
||||
return FALSE
|
||||
return RADAR_NOT_TRACKABLE
|
||||
if(!istype(humanoid.w_uniform, /obj/item/clothing/under))
|
||||
return RADAR_NOT_TRACKABLE
|
||||
var/obj/item/clothing/under/uniform = humanoid.w_uniform
|
||||
if(uniform.has_sensor && uniform.sensor_mode >= SENSOR_COORDS) // Suit sensors must be on maximum
|
||||
return RADAR_TRACKABLE
|
||||
|
||||
///Tracks all janitor equipment
|
||||
/datum/computer_file/program/radar/custodial_locator
|
||||
@@ -262,9 +288,10 @@
|
||||
program_icon = "broom"
|
||||
size = 2
|
||||
detomatix_resistance = DETOMATIX_RESIST_MINOR
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/radar/janitor
|
||||
|
||||
/datum/computer_file/program/radar/custodial_locator/find_atom()
|
||||
return locate(selected) in GLOB.janitor_devices
|
||||
return ..() || (locate(selected) in GLOB.janitor_devices)
|
||||
|
||||
/datum/computer_file/program/radar/custodial_locator/scan()
|
||||
objects = list()
|
||||
@@ -306,6 +333,7 @@
|
||||
program_icon = "bomb"
|
||||
arrowstyle = "ntosradarpointerS.png"
|
||||
pointercolor = "red"
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/radar/nukie
|
||||
|
||||
/datum/computer_file/program/radar/fission360/on_start(mob/living/user)
|
||||
. = ..()
|
||||
@@ -323,7 +351,7 @@
|
||||
return ..()
|
||||
|
||||
/datum/computer_file/program/radar/fission360/find_atom()
|
||||
return SSpoints_of_interest.get_poi_atom_by_ref(selected)
|
||||
return ..() || SSpoints_of_interest.get_poi_atom_by_ref(selected)
|
||||
|
||||
/datum/computer_file/program/radar/fission360/scan()
|
||||
objects = list()
|
||||
@@ -379,3 +407,129 @@
|
||||
span_danger("[computer] vibrates and lets out an ominous alarm. Uh oh."),
|
||||
span_notice("[computer] begins to vibrate rapidly. Wonder what that means..."),
|
||||
)
|
||||
|
||||
|
||||
/**
|
||||
* Base circuit for the radar program.
|
||||
* The abstract radar doesn't have this, nor this one is associated to it, so
|
||||
* make sure to specify the associate_program and circuit_comp_type of subtypes,
|
||||
*/
|
||||
/obj/item/circuit_component/mod_program/radar
|
||||
|
||||
///The target to track
|
||||
var/datum/port/input/target
|
||||
///The selected target, from the app
|
||||
var/datum/port/output/selected_by_app
|
||||
/// The result from the output
|
||||
var/datum/port/output/x_pos
|
||||
var/datum/port/output/y_pos
|
||||
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
|
||||
|
||||
/obj/item/circuit_component/mod_program/radar/populate_ports()
|
||||
. = ..()
|
||||
target = add_input_port("Target", PORT_TYPE_ATOM)
|
||||
selected_by_app = add_output_port("Selected From Program", PORT_TYPE_ATOM)
|
||||
x_pos = add_output_port("X", PORT_TYPE_NUMBER)
|
||||
y_pos = add_output_port("Y", PORT_TYPE_NUMBER)
|
||||
|
||||
/obj/item/circuit_component/mod_program/radar/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
RegisterSignal(associated_program.computer, COMSIG_MODULAR_COMPUTER_RADAR_TRACKABLE, PROC_REF(can_track))
|
||||
RegisterSignal(associated_program.computer, COMSIG_MODULAR_COMPUTER_RADAR_FIND_ATOM, PROC_REF(get_atom))
|
||||
RegisterSignal(associated_program.computer, COMSIG_MODULAR_COMPUTER_RADAR_SELECTED, PROC_REF(on_selected))
|
||||
|
||||
/obj/item/circuit_component/mod_program/radar/unregister_shell()
|
||||
UnregisterSignal(associated_program.computer, list(
|
||||
COMSIG_MODULAR_COMPUTER_RADAR_TRACKABLE,
|
||||
COMSIG_MODULAR_COMPUTER_RADAR_FIND_ATOM,
|
||||
COMSIG_MODULAR_COMPUTER_RADAR_SELECTED,
|
||||
))
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mod_program/radar/get_ui_notices()
|
||||
. = ..()
|
||||
. += create_ui_notice("Max range for unsupported entities: [MAX_RADAR_CIRCUIT_DISTANCE] tiles", "orange", FA_ICON_BULLSEYE)
|
||||
|
||||
///Set the selected ref of the program to the target (if it exists) and update the x/y pos ports (if trackable) when triggered.
|
||||
/obj/item/circuit_component/mod_program/radar/input_received(datum/port/port)
|
||||
var/datum/computer_file/program/radar/radar = associated_program
|
||||
var/atom/radar_atom = radar.find_atom()
|
||||
if(target.value != radar_atom)
|
||||
radar.selected = REF(target.value)
|
||||
SStgui.update_uis(radar.computer)
|
||||
if(radar.trackable(radar_atom))
|
||||
var/turf/turf = get_turf(radar_atom)
|
||||
x_pos.set_value(turf.x)
|
||||
y_pos.set_value(turf.y)
|
||||
else
|
||||
x_pos.set_value(null)
|
||||
y_pos.set_value(null)
|
||||
|
||||
/**
|
||||
* Check if we can track the object. When making different definitions of this proc for subtypes, include typical
|
||||
* targets as an exception to this (e.g humans for lifeline) so that even if they're coming from a circuit input
|
||||
* they won't get filtered by the maximum distance, because they're "supported entities".
|
||||
*/
|
||||
/obj/item/circuit_component/mod_program/radar/proc/can_track(datum/source, atom/signal, signal_turf, computer_turf)
|
||||
SIGNAL_HANDLER
|
||||
if(target.value && get_dist_euclidian(computer_turf, signal_turf) > MAX_RADAR_CIRCUIT_DISTANCE)
|
||||
return COMPONENT_RADAR_DONT_TRACK
|
||||
return COMPONENT_RADAR_TRACK_ANYWAY
|
||||
|
||||
///Return the value of the target port.
|
||||
/obj/item/circuit_component/mod_program/radar/proc/get_atom(datum/source, list/atom_container)
|
||||
SIGNAL_HANDLER
|
||||
atom_container[1] = target.value
|
||||
|
||||
/**
|
||||
* When a target is selected by the app, reset the target port, update the x/pos ports (if trackable)
|
||||
* and set selected_by_app port to the target atom.
|
||||
*/
|
||||
/obj/item/circuit_component/mod_program/radar/proc/on_selected(datum/source, selected_ref)
|
||||
SIGNAL_HANDLER
|
||||
target.set_value(null)
|
||||
var/datum/computer_file/program/radar/radar = associated_program
|
||||
var/atom/selected_atom = radar.find_atom()
|
||||
selected_by_app.set_value(selected_atom)
|
||||
if(radar.trackable(selected_atom))
|
||||
var/turf/turf = get_turf(radar.selected)
|
||||
x_pos.set_value(turf.x)
|
||||
y_pos.set_value(turf.y)
|
||||
else
|
||||
x_pos.set_value(null)
|
||||
y_pos.set_value(null)
|
||||
|
||||
|
||||
/obj/item/circuit_component/mod_program/radar/medical
|
||||
associated_program = /datum/computer_file/program/radar/lifeline
|
||||
|
||||
/obj/item/circuit_component/mod_program/radar/medical/can_track(datum/source, atom/signal, signal_turf, computer_turf)
|
||||
if(target.value in GLOB.human_list)
|
||||
return NONE
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mod_program/radar/janitor
|
||||
associated_program = /datum/computer_file/program/radar/custodial_locator
|
||||
|
||||
/obj/item/circuit_component/mod_program/radar/janitor/can_track(datum/source, atom/signal, signal_turf, computer_turf)
|
||||
if(target.value in GLOB.janitor_devices)
|
||||
return NONE
|
||||
return ..()
|
||||
/obj/item/circuit_component/mod_program/radar/nukie
|
||||
associated_program = /datum/computer_file/program/radar/fission360
|
||||
|
||||
/obj/item/circuit_component/mod_program/radar/nukie/can_track(datum/source, atom/signal, signal_turf, computer_turf)
|
||||
if(target.value in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/nuclearbomb))
|
||||
return NONE
|
||||
if(target.value in SSpoints_of_interest.real_nuclear_disks)
|
||||
return NONE
|
||||
if(target.value == SSshuttle.getShuttle("syndicate"))
|
||||
return NONE
|
||||
return ..()
|
||||
|
||||
#undef MAX_RADAR_CIRCUIT_DISTANCE
|
||||
|
||||
#undef RADAR_NOT_TRACKABLE
|
||||
#undef RADAR_TRACKABLE
|
||||
#undef RADAR_TRACKABLE_ANYWAY
|
||||
|
||||
@@ -83,7 +83,8 @@
|
||||
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/robocontrol/ui_act(action, list/params, datum/tgui/ui)
|
||||
/datum/computer_file/program/robocontrol/ui_act(action, list/params, datum/tgui/ui, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
var/mob/current_user = ui.user
|
||||
var/obj/item/card/id/id_card = computer?.computer_id_slot
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/robotact/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
//Implied type, memes
|
||||
var/obj/item/modular_computer/pda/silicon/tablet = computer
|
||||
var/mob/living/silicon/robot/cyborg = tablet.silicon_owner
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
tgui_id = "NtosSignaler"
|
||||
program_icon = "satellite-dish"
|
||||
can_run_on_flags = PROGRAM_PDA | PROGRAM_LAPTOP
|
||||
program_flags = /datum/computer_file/program::program_flags | PROGRAM_CIRCUITS_RUN_WHEN_CLOSED
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/signaler
|
||||
///What is the saved signal frequency?
|
||||
var/signal_frequency = FREQ_SIGNALER
|
||||
/// What is the saved signal code?
|
||||
@@ -36,10 +38,11 @@
|
||||
data["maxFrequency"] = MAX_FREE_FREQ
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/signal_commander/ui_act(action, list/params)
|
||||
/datum/computer_file/program/signal_commander/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("signal")
|
||||
INVOKE_ASYNC(src, PROC_REF(signal))
|
||||
INVOKE_ASYNC(src, PROC_REF(signal), usr)
|
||||
. = TRUE
|
||||
if("freq")
|
||||
var/new_signal_frequency = sanitize_frequency(unformat_frequency(params["freq"]), TRUE)
|
||||
@@ -56,27 +59,65 @@
|
||||
signal_code = initial(signal_code)
|
||||
. = TRUE
|
||||
|
||||
/datum/computer_file/program/signal_commander/proc/signal()
|
||||
/datum/computer_file/program/signal_commander/proc/signal(atom/source)
|
||||
if(!radio_connection)
|
||||
return
|
||||
|
||||
var/mob/user
|
||||
var/obj/item/circuit_component/signaling
|
||||
if(ismob(source))
|
||||
user = source
|
||||
else if(istype(source, /obj/item/circuit_component))
|
||||
signaling = source
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, signal_cooldown))
|
||||
computer.balloon_alert(usr, "cooling down!")
|
||||
if(user)
|
||||
computer.balloon_alert(user, "cooling down!")
|
||||
return
|
||||
|
||||
COOLDOWN_START(src, signal_cooldown, signal_cooldown_time)
|
||||
computer.balloon_alert(usr, "signaled")
|
||||
if(user)
|
||||
computer.balloon_alert(user, "signaled")
|
||||
|
||||
var/time = time2text(world.realtime,"hh:mm:ss")
|
||||
var/turf/T = get_turf(computer)
|
||||
|
||||
var/logging_data = "[time] <B>:</B> [key_name(usr)] used the computer '[initial(computer.name)]' @ location ([T.x],[T.y],[T.z]) <B>:</B> [format_frequency(signal_frequency)]/[signal_code]"
|
||||
var/user_deets
|
||||
if(signaling)
|
||||
user_deets = "[signaling.parent.get_creator()]"
|
||||
else
|
||||
user_deets = "[key_name(usr)]"
|
||||
var/logging_data = "[time] <B>:</B> [user_deets] used the computer '[initial(computer.name)]' @ location ([T.x],[T.y],[T.z]) <B>:</B> [format_frequency(signal_frequency)]/[signal_code]"
|
||||
add_to_signaler_investigate_log(logging_data)
|
||||
|
||||
var/datum/signal/signal = new(list("code" = signal_code), logging_data = logging_data)
|
||||
var/datum/signal/signal = new(list("code" = signal_code, "key" = signaling?.parent.owner_id), logging_data = logging_data)
|
||||
radio_connection.post_signal(computer, signal)
|
||||
|
||||
/datum/computer_file/program/signal_commander/proc/set_frequency(new_frequency)
|
||||
SSradio.remove_object(computer, signal_frequency)
|
||||
signal_frequency = new_frequency
|
||||
radio_connection = SSradio.add_object(computer, signal_frequency, RADIO_SIGNALER)
|
||||
|
||||
/obj/item/circuit_component/mod_program/signaler
|
||||
associated_program = /datum/computer_file/program/signal_commander
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL
|
||||
|
||||
/// Frequency input
|
||||
var/datum/port/input/freq
|
||||
/// Signal input
|
||||
var/datum/port/input/code
|
||||
|
||||
/obj/item/circuit_component/mod_program/signaler/populate_ports()
|
||||
. = ..()
|
||||
freq = add_input_port("Frequency", PORT_TYPE_NUMBER, trigger = PROC_REF(set_freq), default = FREQ_SIGNALER)
|
||||
code = add_input_port("Code", PORT_TYPE_NUMBER, trigger = PROC_REF(set_code), default = DEFAULT_SIGNALER_CODE)
|
||||
|
||||
/obj/item/circuit_component/mod_program/signaler/proc/set_freq(datum/port/port)
|
||||
var/datum/computer_file/program/signal_commander/signaler = associated_program
|
||||
signaler.set_frequency(clamp(freq.value, MIN_FREE_FREQ, MAX_FREE_FREQ))
|
||||
|
||||
/obj/item/circuit_component/mod_program/signaler/proc/set_code(datum/port/port)
|
||||
var/datum/computer_file/program/signal_commander/signaler = associated_program
|
||||
signaler.signal_code = round(clamp(code.value, 1, 100))
|
||||
|
||||
/obj/item/circuit_component/mod_program/signaler/input_received(datum/port/port)
|
||||
INVOKE_ASYNC(associated_program, TYPE_PROC_REF(/datum/computer_file/program/signal_commander, signal), src)
|
||||
|
||||
@@ -50,7 +50,8 @@
|
||||
|
||||
return null
|
||||
|
||||
/datum/computer_file/program/skill_tracker/ui_act(action, params, datum/tgui/ui)
|
||||
/datum/computer_file/program/skill_tracker/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("PRG_reward")
|
||||
var/skill_type = find_skilltype(params["skill"])
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/supermatter_monitor/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("PRG_refresh")
|
||||
refresh()
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
program_icon = "signal"
|
||||
program_open_overlay = "generic"
|
||||
size = 1
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/status
|
||||
|
||||
extended_desc = "An app used to change the message on the station status displays."
|
||||
tgui_id = "NtosStatus"
|
||||
@@ -42,16 +43,16 @@
|
||||
* * upper - Top text
|
||||
* * lower - Bottom text
|
||||
*/
|
||||
/datum/computer_file/program/status/proc/post_message(upper, lower)
|
||||
/datum/computer_file/program/status/proc/post_message(upper, lower, log_usr = key_name(usr))
|
||||
post_status("message", upper, lower)
|
||||
log_game("[key_name(usr)] has changed the station status display message to \"[upper] [lower]\" [loc_name(usr)]")
|
||||
log_game("[log_usr] has changed the station status display message to \"[upper] [lower]\" [loc_name(usr)]")
|
||||
|
||||
/**
|
||||
* Post a picture to status displays
|
||||
* Arguments:
|
||||
* * picture - The picture name
|
||||
*/
|
||||
/datum/computer_file/program/status/proc/post_picture(picture)
|
||||
/datum/computer_file/program/status/proc/post_picture(picture, log_usr = key_name(usr))
|
||||
if (!(picture in GLOB.status_display_approved_pictures))
|
||||
return
|
||||
if(picture in GLOB.status_display_state_pictures)
|
||||
@@ -80,9 +81,10 @@
|
||||
else
|
||||
post_status("alert", picture)
|
||||
|
||||
log_game("[key_name(usr)] has changed the station status display message to \"[picture]\" [loc_name(usr)]")
|
||||
log_game("[log_usr] has changed the station status display message to \"[picture]\" [loc_name(usr)]")
|
||||
|
||||
/datum/computer_file/program/status/ui_act(action, list/params, datum/tgui/ui)
|
||||
/datum/computer_file/program/status/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("setStatusMessage")
|
||||
upper_text = reject_bad_text(params["upperText"] || "", MAX_STATUS_LINE_LENGTH)
|
||||
@@ -104,3 +106,26 @@
|
||||
data["lowerText"] = lower_text
|
||||
|
||||
return data
|
||||
|
||||
|
||||
/obj/item/circuit_component/mod_program/status
|
||||
associated_program = /datum/computer_file/program/status
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL
|
||||
|
||||
///When the trigger is signaled, this will be the upper text of status displays.
|
||||
var/datum/port/input/upper_text
|
||||
///When the trigger is signaled, this will be the bottom text.
|
||||
var/datum/port/input/bottom_text
|
||||
///A list port that, when signaled, will set the status image to one of its values
|
||||
var/datum/port/input/status_display_pics
|
||||
|
||||
/obj/item/circuit_component/mod_program/status/populate_options()
|
||||
status_display_pics = add_option_port("Set Status Display Picture", GLOB.status_display_approved_pictures, trigger = PROC_REF(set_picture))
|
||||
|
||||
/obj/item/circuit_component/mod_program/status/proc/set_picture(datum/port/port)
|
||||
var/datum/computer_file/program/status/status = associated_program
|
||||
INVOKE_ASYNC(status, TYPE_PROC_REF(/datum/computer_file/program/status, post_picture), status_display_pics.value, parent.get_creator())
|
||||
|
||||
/obj/item/circuit_component/mod_program/status/input_received(datum/port/port)
|
||||
var/datum/computer_file/program/status/status = associated_program
|
||||
INVOKE_ASYNC(status, TYPE_PROC_REF(/datum/computer_file/program/status, post_message), upper_text.value, bottom_text.value, parent.get_creator())
|
||||
|
||||
@@ -88,7 +88,8 @@
|
||||
)
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/science/ui_act(action, list/params)
|
||||
/datum/computer_file/program/science/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
// Check if the console is locked to block any actions occuring
|
||||
if (locked && action != "toggleLock")
|
||||
computer.say("Console is locked, cannot perform further actions.")
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/themeify/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("PRG_change_theme")
|
||||
var/selected_theme = params["selected_theme"]
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
program_flags = PROGRAM_ON_NTNET_STORE | PROGRAM_REQUIRES_NTNET
|
||||
tgui_id = "NtosNetMonitor"
|
||||
program_icon = "network-wired"
|
||||
circuit_comp_type = /obj/item/circuit_component/mod_program/ntnetmonitor
|
||||
|
||||
/datum/computer_file/program/ntnetmonitor/ui_act(action, list/params, datum/tgui/ui)
|
||||
/datum/computer_file/program/ntnetmonitor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("resetIDS")
|
||||
SSmodular_computers.intrusion_detection_alarm = FALSE
|
||||
@@ -66,3 +68,64 @@
|
||||
data["tablets"] += list(tablet_data)
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/circuit_component/mod_program/ntnetmonitor
|
||||
associated_program = /datum/computer_file/program/ntnetmonitor
|
||||
///The stored NTnet relay or PDA to be used as the target of triggers
|
||||
var/datum/port/input/target
|
||||
///Sets `intrusion_detection_alarm` when triggered
|
||||
var/datum/port/input/toggle_ids
|
||||
///Toggles the target ntnet relay on/off when triggered
|
||||
var/datum/port/input/toggle_relay
|
||||
///Purges modpc logs when triggered
|
||||
var/datum/port/input/purge_logs
|
||||
///Toggles the spam mode of the target PDA when triggered
|
||||
var/datum/port/input/toggle_mass_pda
|
||||
///Toggle mime mode of the target PDA when triggered
|
||||
var/datum/port/input/toggle_mime_mode
|
||||
///Returns a list of all PDA Messengers when the "Get Messengers" input is pinged
|
||||
var/datum/port/output/all_messengers
|
||||
///See above
|
||||
var/datum/port/input/get_pdas
|
||||
|
||||
/obj/item/circuit_component/mod_program/ntnetmonitor/populate_ports()
|
||||
. = ..()
|
||||
target = add_input_port("Target Messenger/Relay", PORT_TYPE_DATUM, order = 0.5)
|
||||
toggle_ids = add_input_port("Toggle IDS Status", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_ids))
|
||||
toggle_relay = add_input_port("Toggle NTnet Relay", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_relay))
|
||||
purge_logs = add_input_port("Purge Logs", PORT_TYPE_SIGNAL, trigger = PROC_REF(purge_logs))
|
||||
toggle_mass_pda = add_input_port("Toggle Mass Messenger", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_pda_stuff))
|
||||
toggle_mime_mode = add_input_port("Toggle Mime Mode", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_pda_stuff))
|
||||
get_pdas = add_input_port("Get PDAs", PORT_TYPE_SIGNAL, trigger = PROC_REF(get_pdas))
|
||||
all_messengers = add_output_port("List of PDAs", PORT_TYPE_LIST(PORT_TYPE_ATOM))
|
||||
|
||||
/obj/item/circuit_component/mod_program/ntnetmonitor/proc/get_pdas(datum/port/port)
|
||||
var/list/computers_with_messenger = list()
|
||||
for(var/messenger_ref as anything in GLOB.pda_messengers)
|
||||
var/datum/computer_file/program/messenger/messenger = GLOB.pda_messengers[messenger_ref]
|
||||
computers_with_messenger += messenger.computer
|
||||
all_messengers.set_value(computers_with_messenger)
|
||||
|
||||
/obj/item/circuit_component/mod_program/ntnetmonitor/proc/toggle_ids(datum/port/port)
|
||||
SSmodular_computers.intrusion_detection_enabled = !SSmodular_computers.intrusion_detection_enabled
|
||||
|
||||
/obj/item/circuit_component/mod_program/ntnetmonitor/proc/toggle_relay(datum/port/port)
|
||||
var/obj/machinery/ntnet_relay/target_relay = target.value
|
||||
if(!istype(target_relay))
|
||||
return
|
||||
target_relay.set_relay_enabled(!target_relay.relay_enabled)
|
||||
|
||||
/obj/item/circuit_component/mod_program/ntnetmonitor/proc/purge_logs(datum/port/port)
|
||||
SSmodular_computers.purge_logs()
|
||||
|
||||
/obj/item/circuit_component/mod_program/ntnetmonitor/proc/toggle_pda_stuff(datum/port/port)
|
||||
var/obj/item/modular_computer/computer = target.value
|
||||
if(!istype(computer))
|
||||
return
|
||||
var/datum/computer_file/program/messenger/target_messenger = locate() in computer.stored_files
|
||||
if(isnull(target_messenger))
|
||||
return
|
||||
if(COMPONENT_TRIGGERED_BY(toggle_mass_pda, port))
|
||||
target_messenger.spam_mode = !target_messenger.spam_mode
|
||||
if(COMPONENT_TRIGGERED_BY(toggle_mime_mode, port))
|
||||
target_messenger.mime_mode = !target_messenger.mime_mode
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
*/
|
||||
/datum/proc/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
SEND_SIGNAL(src, COMSIG_UI_ACT, usr, action)
|
||||
SEND_SIGNAL(src, COMSIG_UI_ACT, usr, action, params)
|
||||
// If UI is not interactive or usr calling Topic is not the UI user, bail.
|
||||
if(!ui || ui.status != UI_INTERACTIVE)
|
||||
return TRUE
|
||||
|
||||
@@ -174,6 +174,7 @@
|
||||
qdel(input_port)
|
||||
if(parent)
|
||||
SStgui.update_uis(parent)
|
||||
return null //explicitly set the port to null if used like this: `port = remove_input_port(port)`
|
||||
|
||||
/**
|
||||
* Adds an output port and returns it
|
||||
@@ -203,6 +204,7 @@
|
||||
qdel(output_port)
|
||||
if(parent)
|
||||
SStgui.update_uis(parent)
|
||||
return null //explicitly set the port to null if used like this: `port = remove_output_port(port)`
|
||||
|
||||
|
||||
/**
|
||||
@@ -340,6 +342,7 @@
|
||||
if(length(input_ports))
|
||||
. += create_ui_notice("Power Usage Per Input: [power_usage_per_input]", "orange", "bolt")
|
||||
|
||||
|
||||
/**
|
||||
* Called when a special button is pressed on this component in the UI.
|
||||
*
|
||||
|
||||
@@ -271,3 +271,4 @@ You can use a machine in the vault to deposit cash or rob Cargo's department fun
|
||||
You can use an upgraded microwave to charge your PDA!
|
||||
You'll quickly lose your interest in the game if you play to win and kill. If you find yourself doing this, take a step back and talk to people - it's a much better experience!
|
||||
Some areas of the station use simple nautical directions to indicate their respective locations, like Fore (Front of the ship), Aft (Back), Port (Left side), Starboard (Right), Quarter and Bow (Either sides of Aft and Fore, respectively). You can review these terms on the Notepad App of your PDA.
|
||||
Modular computers are compatible with integrated circuits, but most of the program-dependent circuits require them to be open/backgrounded to work. To install circuits on stationary consoles, you need to toggle interaction with the frame with right-click first.
|
||||
|
||||
@@ -5104,6 +5104,7 @@
|
||||
#include "code\modules\mod\modules\modules_timeline.dm"
|
||||
#include "code\modules\mod\modules\modules_visor.dm"
|
||||
#include "code\modules\modular_computers\computers\item\computer.dm"
|
||||
#include "code\modules\modular_computers\computers\item\computer_circuit.dm"
|
||||
#include "code\modules\modular_computers\computers\item\computer_files.dm"
|
||||
#include "code\modules\modular_computers\computers\item\computer_power.dm"
|
||||
#include "code\modules\modular_computers\computers\item\computer_ui.dm"
|
||||
@@ -5123,6 +5124,7 @@
|
||||
#include "code\modules\modular_computers\file_system\data.dm"
|
||||
#include "code\modules\modular_computers\file_system\picture_file.dm"
|
||||
#include "code\modules\modular_computers\file_system\program.dm"
|
||||
#include "code\modules\modular_computers\file_system\program_circuit.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\airestorer.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\alarm.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\arcade.dm"
|
||||
@@ -5168,6 +5170,7 @@
|
||||
#include "code\modules\modular_computers\file_system\programs\maintenance\phys_scanner.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\maintenance\spectre_meter.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\maintenance\themes.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\messenger\messenger_circuit.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\messenger\messenger_data.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\messenger\messenger_program.dm"
|
||||
#include "code\modules\movespeed\_movespeed_modifier.dm"
|
||||
|
||||
Reference in New Issue
Block a user