Files
Bubberstation/code/datums/components/usb_port.dm
SkyratBot e7a6101af9 [MIRROR] Make USB cables attached to locked circuits unable to be modified [MDB IGNORE] (#9882)
* Make USB cables attached to locked circuits unable to be modified (#63084)

Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com>

* Make USB cables attached to locked circuits unable to be modified

Co-authored-by: RandomGamer123 <31096837+RandomGamer123@users.noreply.github.com>
Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com>
2021-12-05 10:07:43 -05:00

243 lines
7.8 KiB
Plaintext

/// Opens up a USB port that can be connected to by circuits, creating registerable circuit components
/datum/component/usb_port
/// The component types to create when something plugs in
var/list/circuit_component_types
/// The currently connected circuit
var/obj/item/integrated_circuit/attached_circuit
/// The currently connected USB cable
var/datum/weakref/usb_cable_ref
/// The components inside the parent
var/list/obj/item/circuit_component/circuit_components
/// The beam connecting the USB cable to the machine
var/datum/beam/usb_cable_beam
/// The current physical object that the beam is connected to and listens to.
var/atom/movable/physical_object
/datum/component/usb_port/Initialize(list/circuit_component_types)
if (!isatom(parent))
return COMPONENT_INCOMPATIBLE
circuit_components = list()
set_circuit_components(circuit_component_types)
/datum/component/usb_port/proc/set_circuit_components(list/components)
var/should_register = FALSE
if(length(circuit_components))
UnregisterFromParent()
should_register = TRUE
QDEL_LIST(circuit_components)
for(var/circuit_component in components)
var/obj/item/circuit_component/component = circuit_component
if(ispath(circuit_component))
component = new circuit_component(null)
RegisterSignal(component, COMSIG_CIRCUIT_COMPONENT_SAVE, .proc/save_component)
circuit_components += component
if(should_register)
RegisterWithParent()
/datum/component/usb_port/RegisterWithParent()
RegisterSignal(parent, COMSIG_ATOM_USB_CABLE_TRY_ATTACH, .proc/on_atom_usb_cable_try_attach)
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_moved)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine)
RegisterSignal(parent, COMSIG_MOVABLE_CIRCUIT_LOADED, .proc/on_load)
for(var/obj/item/circuit_component/component as anything in circuit_components)
component.register_usb_parent(parent)
/datum/component/usb_port/UnregisterFromParent()
UnregisterSignal(parent, list(
COMSIG_ATOM_USB_CABLE_TRY_ATTACH,
COMSIG_MOVABLE_MOVED,
COMSIG_PARENT_EXAMINE,
COMSIG_MOVABLE_CIRCUIT_LOADED,
))
for(var/obj/item/circuit_component/component as anything in circuit_components)
component.unregister_usb_parent(parent)
unregister_circuit_signals()
unregister_physical_signals()
attached_circuit = null
/datum/component/usb_port/proc/save_component(datum/source, list/objects)
SIGNAL_HANDLER
objects += parent
/datum/component/usb_port/proc/on_load(datum/source, obj/item/integrated_circuit/circuit, list/components)
SIGNAL_HANDLER
var/list/components_in_list = list()
for(var/obj/item/circuit_component/component as anything in components)
components_in_list += component.type
for(var/obj/item/circuit_component/component as anything in circuit_components)
if(component.type in components_in_list)
continue
components += component.type
set_circuit_components(components)
var/obj/item/usb_cable/cable = new(circuit.drop_location())
cable.attached_circuit = circuit
on_atom_usb_cable_try_attach(src, cable, null)
/datum/component/usb_port/Destroy()
QDEL_LIST(circuit_components)
QDEL_NULL(usb_cable_beam)
attached_circuit = null
usb_cable_ref = null
return ..()
/datum/component/usb_port/proc/unregister_circuit_signals()
if (isnull(attached_circuit))
return
UnregisterSignal(attached_circuit, list(
COMSIG_CIRCUIT_SHELL_REMOVED,
COMSIG_PARENT_QDELETING,
COMSIG_CIRCUIT_SET_SHELL,
))
/datum/component/usb_port/proc/unregister_physical_signals()
if (isnull(physical_object))
return
UnregisterSignal(physical_object, list(
COMSIG_MOVABLE_MOVED,
COMSIG_PARENT_EXAMINE,
))
/datum/component/usb_port/proc/attach_circuit_components(obj/item/integrated_circuit/circuitboard)
for(var/obj/item/circuit_component/component as anything in circuit_components)
circuitboard.add_component(component)
RegisterSignal(component, COMSIG_CIRCUIT_COMPONENT_REMOVED, .proc/on_circuit_component_removed)
/datum/component/usb_port/proc/on_examine(datum/source, mob/user, list/examine_text)
SIGNAL_HANDLER
if (isnull(attached_circuit))
examine_text += span_notice("There is a USB port on the front.")
else
examine_text += span_notice("[attached_circuit.shell || attached_circuit] is connected to [parent.p_them()] by a USB port.")
/datum/component/usb_port/proc/on_examine_shell(datum/source, mob/user, list/examine_text)
SIGNAL_HANDLER
examine_text += span_notice("[source.p_they(TRUE)] [source.p_are()] attached to [parent] with a USB cable.")
/datum/component/usb_port/proc/on_atom_usb_cable_try_attach(datum/source, obj/item/usb_cable/connecting_cable, mob/user)
SIGNAL_HANDLER
var/atom/atom_parent = parent
if (!isnull(attached_circuit))
if(user)
atom_parent.balloon_alert(user, "usb already connected")
return COMSIG_CANCEL_USB_CABLE_ATTACK
if (isnull(connecting_cable.attached_circuit))
if(user)
connecting_cable.balloon_alert(user, "connect to a shell first")
return COMSIG_CANCEL_USB_CABLE_ATTACK
if (!IN_GIVEN_RANGE(connecting_cable.attached_circuit, parent, USB_CABLE_MAX_RANGE))
if(user)
connecting_cable.balloon_alert(user, "too far away")
return COMSIG_CANCEL_USB_CABLE_ATTACK
if (connecting_cable.attached_circuit.locked)
connecting_cable.balloon_alert(user, "shell is locked!")
return COMSIG_CANCEL_USB_CABLE_ATTACK
usb_cable_ref = WEAKREF(connecting_cable)
attached_circuit = connecting_cable.attached_circuit
connecting_cable.forceMove(attached_circuit)
attach_circuit_components(attached_circuit)
if(user)
attached_circuit.interact(user)
var/new_physical_object = attached_circuit.shell
if(!new_physical_object)
new_physical_object = attached_circuit
RegisterSignal(attached_circuit, COMSIG_CIRCUIT_SHELL_REMOVED, .proc/on_circuit_shell_removed)
RegisterSignal(attached_circuit, COMSIG_PARENT_QDELETING, .proc/on_circuit_deleting)
RegisterSignal(attached_circuit, COMSIG_CIRCUIT_SET_SHELL, .proc/on_set_shell)
set_physical_object(new_physical_object)
return COMSIG_USB_CABLE_ATTACHED
/datum/component/usb_port/proc/set_physical_object(atom/movable/new_physical_object)
if(physical_object)
unregister_physical_signals()
if(usb_cable_beam)
QDEL_NULL(usb_cable_beam)
var/atom/atom_parent = parent
usb_cable_beam = atom_parent.Beam(new_physical_object, "usb_cable_beam", 'icons/obj/wiremod.dmi')
RegisterSignal(new_physical_object, COMSIG_MOVABLE_MOVED, .proc/on_moved)
RegisterSignal(new_physical_object, COMSIG_PARENT_EXAMINE, .proc/on_examine_shell)
physical_object = new_physical_object
// Adds support for loading circuits without shells but with usb cables, or loading circuits with shells because the shells might not load first.
/datum/component/usb_port/proc/on_set_shell(datum/source, atom/movable/new_shell)
SIGNAL_HANDLER
set_physical_object(new_shell)
/datum/component/usb_port/proc/on_moved()
SIGNAL_HANDLER
if (isnull(attached_circuit))
return
if (IN_GIVEN_RANGE(attached_circuit, parent, USB_CABLE_MAX_RANGE))
return
detach()
/datum/component/usb_port/proc/on_circuit_deleting()
SIGNAL_HANDLER
detach()
qdel(usb_cable_ref)
/datum/component/usb_port/proc/on_circuit_component_removed(datum/source)
SIGNAL_HANDLER
detach()
/datum/component/usb_port/proc/on_circuit_shell_removed()
SIGNAL_HANDLER
detach()
/datum/component/usb_port/proc/detach()
var/obj/item/usb_cable/usb_cable = usb_cable_ref?.resolve()
if (isnull(usb_cable))
return
for(var/obj/item/circuit_component/component as anything in circuit_components)
UnregisterSignal(component, COMSIG_CIRCUIT_COMPONENT_REMOVED)
attached_circuit.remove_component(component)
component.moveToNullspace()
unregister_circuit_signals()
unregister_physical_signals()
var/atom/atom_parent = parent
usb_cable.forceMove(atom_parent.drop_location())
usb_cable.balloon_alert_to_viewers("snap")
physical_object = null
attached_circuit = null
usb_cable_ref = null
QDEL_NULL(usb_cable_beam)