mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-26 17:11:52 +00:00
* Machines can now be pried open multiple times and maintain their initial densities (#74163) ## About The Pull Request These changes fix how machines are pried open with crowbars. Currently, most machines can be pried open, but many of them have no method for being closed again. This means they can be pried once, and then never again (as their internal logic has them stuck in an "open" state). Additionally, the densities of these machines is also inconsistent, as density is tied to the procs for opening/closing machines (open = non-dense, closed = dense). Thus, these new changes allow desired densities to be passed to `open_machine()` and `close_machine()`, as well as `default_pry_open()`, meaning that atypical machine densities can be maintained (e.g. machines that should remain dense when open, or non-dense when closed). I've also added a `close_after_pry` boolean parameter to the `default_pry_open()` proc, which determines whether to immediately close a machine after opening it. This is useful for machines that don't really have a use case for remaining open, often lacking a sprite to represent this state as well. * Note: Opening and immediately closing machines with this boolean will still drop their contents onto the floor, but will now immediately "close" in their logic, allowing for further prying attempts in the future. It's worth noting that this implements default density values for these procs, which match the existing behavior for machines, so as to (hopefully) not disrupt existing or expected machine behavior. Two caveats to these changes currently exist: 1. On machines that immediately close after prying, the prying action can now be spammed to the chat with repeated clicking. I'm uncertain if this needs some sort of spam protection or if it's fine as is. 2. I've only been able to manually test this code. I'd love to write unit tests for it, as it affects a lot of different machines, but don't know where to begin with DM Unit Testing (or which files would be good examples to reference in the code base). * Note: I did manually test each and every machine that calls `default_pry_open()` and they all seem to be working correctly. (Except for `obj/machinery/plumbing/sender`, but that doesn't seem to need prying, as it has no contents to drop, only reagents.) As always, let me know if any improvements/changes should be made. This closes #26833. ## Why It's Good For The Game These changes allow crowbar prying to correctly occur multiple times on any machine, which is intended behavior. It prevents player confusion that could occur when a machine couldn't be pried open a second time during a shift, even though it had previously been pried before, forcing players to question themselves. (Are they missing something? Did they perform the action a different way last time? Is the machine actually still powered on instead of off? Etc.) These changes also maintain the correct density for machines after prying, preventing scenarios where a machine might behave differently once it had been pried open. (An example of this was being able to walk through a smartfridge after prying it open.) Additionally, players are no longer required to know/use workarounds (such as machine disassembly) to retrieve a powered-off machine's contents. Overall, these changes improve consistency around machines, creating more scenarios where they behave as players would expect. ## Changelog 🆑 fix: machines can now be pried open more than once. fix: machines now have the correct density when pried open. /🆑 --------- Co-authored-by: san7890 <the@ san7890.com> * Machines can now be pried open multiple times and maintain their initial densities * wew --------- Co-authored-by: Antonio Tosti <5588048+atosti@users.noreply.github.com> Co-authored-by: san7890 <the@ san7890.com> Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com>
531 lines
16 KiB
Plaintext
531 lines
16 KiB
Plaintext
/obj/item/organ/internal/cyberimp/bci
|
|
name = "brain-computer interface"
|
|
desc = "An implant that can be placed in a user's head to control circuits using their brain."
|
|
icon = 'icons/obj/wiremod.dmi'
|
|
icon_state = "bci"
|
|
visual = FALSE
|
|
zone = BODY_ZONE_HEAD
|
|
w_class = WEIGHT_CLASS_TINY
|
|
|
|
/obj/item/organ/internal/cyberimp/bci/Initialize(mapload)
|
|
. = ..()
|
|
|
|
var/obj/item/integrated_circuit/circuit = new(src)
|
|
circuit.add_component(new /obj/item/circuit_component/equipment_action/bci(null, "One"))
|
|
|
|
AddComponent(/datum/component/shell, list(
|
|
new /obj/item/circuit_component/bci_core,
|
|
), SHELL_CAPACITY_SMALL, starting_circuit = circuit)
|
|
|
|
/obj/item/organ/internal/cyberimp/bci/Insert(mob/living/carbon/receiver, special, drop_if_replaced)
|
|
. = ..()
|
|
|
|
// Organs are put in nullspace, but this breaks circuit interactions
|
|
forceMove(receiver)
|
|
|
|
/obj/item/organ/internal/cyberimp/bci/say(message, bubble_type, list/spans, sanitize, datum/language/language, ignore_spam, forced = null, filterproof = null, message_range = 7, datum/saymode/saymode = null)
|
|
if (owner)
|
|
// Otherwise say_dead will be called.
|
|
// It's intentional that a circuit for a dead person does not speak from the shell.
|
|
if (owner.stat == DEAD)
|
|
return
|
|
|
|
owner.say(message, forced = "circuit speech")
|
|
else
|
|
return ..()
|
|
|
|
/obj/item/circuit_component/equipment_action/bci
|
|
display_name = "BCI Action"
|
|
desc = "Represents an action the user can take when implanted with the brain-computer interface."
|
|
required_shells = list(/obj/item/organ/internal/cyberimp/bci)
|
|
|
|
/// A reference to the action button itself
|
|
var/datum/action/innate/bci_action/bci_action
|
|
|
|
/obj/item/circuit_component/equipment_action/bci/Destroy()
|
|
QDEL_NULL(bci_action)
|
|
return ..()
|
|
|
|
/obj/item/circuit_component/equipment_action/bci/register_shell(atom/movable/shell)
|
|
. = ..()
|
|
var/obj/item/organ/internal/cyberimp/bci/bci = shell
|
|
if(istype(bci))
|
|
bci_action = new(src)
|
|
update_action()
|
|
|
|
bci.actions += list(bci_action)
|
|
|
|
/obj/item/circuit_component/equipment_action/bci/unregister_shell(atom/movable/shell)
|
|
var/obj/item/organ/internal/cyberimp/bci/bci = shell
|
|
if(istype(bci))
|
|
bci.actions -= bci_action
|
|
QDEL_NULL(bci_action)
|
|
return ..()
|
|
|
|
/obj/item/circuit_component/equipment_action/bci/input_received(datum/port/input/port)
|
|
if (!isnull(bci_action))
|
|
update_action()
|
|
|
|
/obj/item/circuit_component/equipment_action/bci/update_action()
|
|
bci_action.name = button_name.value
|
|
bci_action.button_icon_state = "bci_[replacetextEx(lowertext(icon_options.value), " ", "_")]"
|
|
|
|
/datum/action/innate/bci_action
|
|
name = "Action"
|
|
button_icon = 'icons/mob/actions/actions_items.dmi'
|
|
check_flags = AB_CHECK_CONSCIOUS
|
|
button_icon_state = "bci_power"
|
|
|
|
var/obj/item/circuit_component/equipment_action/bci/circuit_component
|
|
|
|
/datum/action/innate/bci_action/New(obj/item/circuit_component/equipment_action/bci/circuit_component)
|
|
..()
|
|
|
|
src.circuit_component = circuit_component
|
|
|
|
/datum/action/innate/bci_action/Destroy()
|
|
circuit_component.bci_action = null
|
|
circuit_component = null
|
|
|
|
return ..()
|
|
|
|
/datum/action/innate/bci_action/Activate()
|
|
circuit_component.signal.set_output(COMPONENT_SIGNAL)
|
|
|
|
/obj/item/circuit_component/bci_core
|
|
display_name = "BCI Core"
|
|
desc = "Controls the core operations of the BCI."
|
|
|
|
/// A reference to the action button to look at charge/get info
|
|
var/datum/action/innate/bci_charge_action/charge_action
|
|
|
|
var/datum/port/input/message
|
|
var/datum/port/input/send_message_signal
|
|
var/datum/port/input/show_charge_meter
|
|
|
|
var/datum/port/output/user_port
|
|
|
|
var/datum/weakref/user
|
|
|
|
var/obj/item/organ/internal/cyberimp/bci/bci
|
|
|
|
/obj/item/circuit_component/bci_core/populate_ports()
|
|
|
|
message = add_input_port("Message", PORT_TYPE_STRING, trigger = null)
|
|
send_message_signal = add_input_port("Send Message", PORT_TYPE_SIGNAL)
|
|
show_charge_meter = add_input_port("Show Charge Meter", PORT_TYPE_NUMBER, trigger = PROC_REF(update_charge_action))
|
|
|
|
user_port = add_output_port("User", PORT_TYPE_ATOM)
|
|
|
|
/obj/item/circuit_component/bci_core/Destroy()
|
|
QDEL_NULL(charge_action)
|
|
return ..()
|
|
|
|
/obj/item/circuit_component/bci_core/proc/update_charge_action()
|
|
CIRCUIT_TRIGGER
|
|
var/mob/living/carbon/resolved_owner = user?.resolve()
|
|
if (show_charge_meter.value)
|
|
if (charge_action)
|
|
return
|
|
charge_action = new(src)
|
|
if (resolved_owner)
|
|
charge_action.Grant(resolved_owner)
|
|
bci.actions += charge_action
|
|
else
|
|
if (!charge_action)
|
|
return
|
|
if (resolved_owner)
|
|
charge_action.Remove(resolved_owner)
|
|
bci.actions -= charge_action
|
|
QDEL_NULL(charge_action)
|
|
|
|
/obj/item/circuit_component/bci_core/register_shell(atom/movable/shell)
|
|
bci = shell
|
|
|
|
show_charge_meter.set_value(TRUE)
|
|
|
|
RegisterSignal(shell, COMSIG_ORGAN_IMPLANTED, PROC_REF(on_organ_implanted))
|
|
RegisterSignal(shell, COMSIG_ORGAN_REMOVED, PROC_REF(on_organ_removed))
|
|
|
|
/obj/item/circuit_component/bci_core/unregister_shell(atom/movable/shell)
|
|
bci = shell
|
|
|
|
if (charge_action)
|
|
var/mob/living/carbon/resolved_owner = user?.resolve()
|
|
if (resolved_owner)
|
|
charge_action.Remove(resolved_owner)
|
|
bci.actions -= charge_action
|
|
QDEL_NULL(charge_action)
|
|
|
|
UnregisterSignal(shell, list(
|
|
COMSIG_ORGAN_IMPLANTED,
|
|
COMSIG_ORGAN_REMOVED,
|
|
))
|
|
|
|
/obj/item/circuit_component/bci_core/input_received(datum/port/input/port)
|
|
var/sent_message = trim(message.value)
|
|
if (!sent_message)
|
|
return
|
|
|
|
var/mob/living/carbon/resolved_owner = user?.resolve()
|
|
if (isnull(resolved_owner))
|
|
return
|
|
|
|
if (resolved_owner.stat == DEAD)
|
|
return
|
|
|
|
to_chat(resolved_owner, "<i>You hear a strange, robotic voice in your head...</i> \"[span_robot("[html_encode(sent_message)]")]\"")
|
|
|
|
/obj/item/circuit_component/bci_core/proc/on_organ_implanted(datum/source, mob/living/carbon/owner)
|
|
SIGNAL_HANDLER
|
|
|
|
update_charge_action()
|
|
|
|
user_port.set_output(owner)
|
|
user = WEAKREF(owner)
|
|
|
|
RegisterSignal(owner, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
|
|
RegisterSignal(owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, PROC_REF(on_borg_charge))
|
|
RegisterSignal(owner, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(on_electrocute))
|
|
|
|
/obj/item/circuit_component/bci_core/proc/on_organ_removed(datum/source, mob/living/carbon/owner)
|
|
SIGNAL_HANDLER
|
|
|
|
user_port.set_output(null)
|
|
user = null
|
|
|
|
UnregisterSignal(owner, list(
|
|
COMSIG_PARENT_EXAMINE,
|
|
COMSIG_PROCESS_BORGCHARGER_OCCUPANT,
|
|
COMSIG_LIVING_ELECTROCUTE_ACT,
|
|
))
|
|
|
|
/obj/item/circuit_component/bci_core/proc/on_borg_charge(datum/source, amount)
|
|
SIGNAL_HANDLER
|
|
|
|
if (isnull(parent.cell))
|
|
return
|
|
|
|
parent.cell.give(amount)
|
|
|
|
/obj/item/circuit_component/bci_core/proc/on_electrocute(datum/source, shock_damage, siemens_coefficient, flags)
|
|
SIGNAL_HANDLER
|
|
|
|
if (isnull(parent.cell))
|
|
return
|
|
|
|
if (flags & SHOCK_ILLUSION)
|
|
return
|
|
|
|
parent.cell.give(shock_damage * 2)
|
|
to_chat(source, span_notice("You absorb some of the shock into your [parent.name]!"))
|
|
|
|
/obj/item/circuit_component/bci_core/proc/on_examine(datum/source, mob/mob, list/examine_text)
|
|
SIGNAL_HANDLER
|
|
|
|
if (isobserver(mob))
|
|
examine_text += span_notice("[source.p_they(capitalized = TRUE)] [source.p_have()] <a href='?src=[REF(src)];open_bci=1'>\a [parent] implanted in [source.p_them()]</a>.")
|
|
|
|
/obj/item/circuit_component/bci_core/Topic(href, list/href_list)
|
|
..()
|
|
|
|
if (!isobserver(usr))
|
|
return
|
|
|
|
if (href_list["open_bci"])
|
|
parent.attack_ghost(usr)
|
|
|
|
/datum/action/innate/bci_charge_action
|
|
name = "Check BCI Charge"
|
|
check_flags = NONE
|
|
button_icon = 'icons/obj/power.dmi'
|
|
button_icon_state = "cell"
|
|
|
|
var/obj/item/circuit_component/bci_core/circuit_component
|
|
|
|
/datum/action/innate/bci_charge_action/New(obj/item/circuit_component/bci_core/circuit_component)
|
|
..()
|
|
|
|
src.circuit_component = circuit_component
|
|
|
|
build_all_button_icons()
|
|
|
|
START_PROCESSING(SSobj, src)
|
|
|
|
/datum/action/innate/bci_charge_action/create_button()
|
|
var/atom/movable/screen/movable/action_button/button = ..()
|
|
button.maptext_x = 2
|
|
button.maptext_y = 0
|
|
return button
|
|
|
|
/datum/action/innate/bci_charge_action/Destroy()
|
|
circuit_component.charge_action = null
|
|
circuit_component = null
|
|
|
|
STOP_PROCESSING(SSobj, src)
|
|
|
|
return ..()
|
|
|
|
/datum/action/innate/bci_charge_action/Trigger(trigger_flags)
|
|
var/obj/item/stock_parts/cell/cell = circuit_component.parent.cell
|
|
|
|
if (isnull(cell))
|
|
to_chat(owner, span_boldwarning("[circuit_component.parent] has no power cell."))
|
|
else
|
|
to_chat(owner, span_info("[circuit_component.parent]'s [cell.name] has <b>[cell.percent()]%</b> charge left."))
|
|
to_chat(owner, span_info("You can recharge it by using a cyborg recharging station."))
|
|
|
|
/datum/action/innate/bci_charge_action/process(delta_time)
|
|
build_all_button_icons(UPDATE_BUTTON_STATUS)
|
|
|
|
/datum/action/innate/bci_charge_action/update_button_status(atom/movable/screen/movable/action_button/button, force = FALSE)
|
|
. = ..()
|
|
var/obj/item/stock_parts/cell/cell = circuit_component.parent.cell
|
|
button.maptext = cell ? MAPTEXT("[cell.percent()]%") : ""
|
|
|
|
/obj/machinery/bci_implanter
|
|
name = "brain-computer interface manipulation chamber"
|
|
desc = "A machine that, when given a brain-computer interface, will implant it into an occupant. Otherwise, will remove any brain-computer interfaces they already have."
|
|
circuit = /obj/item/circuitboard/machine/bci_implanter
|
|
icon = 'icons/obj/machines/bci_implanter.dmi'
|
|
icon_state = "bci_implanter"
|
|
base_icon_state = "bci_implanter"
|
|
layer = ABOVE_WINDOW_LAYER
|
|
anchored = TRUE
|
|
density = TRUE
|
|
obj_flags = NO_BUILD // Becomes undense when the door is open
|
|
|
|
var/busy = FALSE
|
|
var/busy_icon_state
|
|
var/locked = FALSE
|
|
|
|
var/obj/item/organ/internal/cyberimp/bci/bci_to_implant
|
|
|
|
COOLDOWN_DECLARE(message_cooldown)
|
|
|
|
/obj/machinery/bci_implanter/Initialize(mapload)
|
|
. = ..()
|
|
occupant_typecache = typecacheof(/mob/living/carbon)
|
|
|
|
/obj/machinery/bci_implanter/on_deconstruction()
|
|
drop_stored_bci()
|
|
|
|
/obj/machinery/bci_implanter/Destroy()
|
|
qdel(bci_to_implant)
|
|
return ..()
|
|
|
|
/obj/machinery/bci_implanter/examine(mob/user)
|
|
. = ..()
|
|
if (isnull(bci_to_implant))
|
|
. += span_notice("There is no BCI inserted.")
|
|
else
|
|
. += span_notice("Right-click to remove current BCI.")
|
|
|
|
/obj/machinery/bci_implanter/proc/set_busy(status, working_icon)
|
|
busy = status
|
|
busy_icon_state = working_icon
|
|
update_appearance()
|
|
|
|
/obj/machinery/bci_implanter/update_icon_state()
|
|
if (occupant)
|
|
icon_state = busy ? busy_icon_state : "[base_icon_state]_occupied"
|
|
return ..()
|
|
icon_state = "[base_icon_state][state_open ? "_open" : null]"
|
|
return ..()
|
|
|
|
/obj/machinery/bci_implanter/update_overlays()
|
|
var/list/overlays = ..()
|
|
|
|
if ((machine_stat & MAINT) || panel_open)
|
|
overlays += "maint"
|
|
return overlays
|
|
|
|
if (machine_stat & (NOPOWER|BROKEN))
|
|
return overlays
|
|
|
|
if (busy || locked)
|
|
overlays += "red"
|
|
if (locked)
|
|
overlays += "bolted"
|
|
return overlays
|
|
|
|
overlays += "green"
|
|
|
|
return overlays
|
|
|
|
/obj/machinery/bci_implanter/attack_hand_secondary(mob/user, list/modifiers)
|
|
. = ..()
|
|
if (. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
|
return .
|
|
|
|
if(!user.Adjacent(src))
|
|
return
|
|
|
|
if (locked)
|
|
balloon_alert(user, "it's locked!")
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
if (isnull(bci_to_implant))
|
|
balloon_alert(user, "no bci inserted!")
|
|
else
|
|
user.put_in_hands(bci_to_implant)
|
|
balloon_alert(user, "ejected bci")
|
|
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
/obj/machinery/bci_implanter/attackby(obj/item/weapon, mob/user, params)
|
|
var/obj/item/organ/internal/cyberimp/bci/new_bci = weapon
|
|
if (istype(new_bci))
|
|
if (!(locate(/obj/item/integrated_circuit) in new_bci))
|
|
balloon_alert(user, "bci has no circuit!")
|
|
return
|
|
|
|
var/obj/item/organ/internal/cyberimp/bci/previous_bci_to_implant = bci_to_implant
|
|
|
|
user.transferItemToLoc(weapon, src)
|
|
bci_to_implant = weapon
|
|
|
|
if (isnull(previous_bci_to_implant))
|
|
balloon_alert(user, "inserted bci")
|
|
else
|
|
balloon_alert(user, "swapped bci")
|
|
user.put_in_hands(previous_bci_to_implant)
|
|
|
|
return
|
|
|
|
return ..()
|
|
|
|
/obj/machinery/bci_implanter/attackby_secondary(obj/item/weapon, mob/user, params)
|
|
if (!occupant && default_deconstruction_screwdriver(user, icon_state, icon_state, weapon))
|
|
update_appearance()
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
if (default_pry_open(weapon, close_after_pry = FALSE, open_density = FALSE, closed_density = TRUE))
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
if (default_deconstruction_crowbar(weapon))
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
/obj/machinery/bci_implanter/proc/start_process()
|
|
if (machine_stat & (NOPOWER|BROKEN))
|
|
return
|
|
if ((machine_stat & MAINT) || panel_open)
|
|
return
|
|
if (!occupant || busy)
|
|
return
|
|
|
|
update_use_power(ACTIVE_POWER_USE)
|
|
|
|
var/locked_state = locked
|
|
locked = TRUE
|
|
|
|
set_busy(TRUE, "[initial(icon_state)]_raising")
|
|
addtimer(CALLBACK(src, PROC_REF(set_busy), TRUE, "[initial(icon_state)]_active"), 1 SECONDS)
|
|
addtimer(CALLBACK(src, PROC_REF(set_busy), TRUE, "[initial(icon_state)]_falling"), 2 SECONDS)
|
|
addtimer(CALLBACK(src, PROC_REF(complete_process), locked_state), 3 SECONDS)
|
|
|
|
/obj/machinery/bci_implanter/proc/complete_process(locked_state)
|
|
update_use_power(IDLE_POWER_USE)
|
|
locked = locked_state
|
|
set_busy(FALSE)
|
|
|
|
var/mob/living/carbon/carbon_occupant = occupant
|
|
if (!istype(carbon_occupant))
|
|
return
|
|
|
|
playsound(loc, 'sound/machines/ping.ogg', 30, FALSE)
|
|
|
|
var/obj/item/organ/internal/cyberimp/bci/bci_organ = carbon_occupant.getorgan(/obj/item/organ/internal/cyberimp/bci)
|
|
|
|
if (bci_organ)
|
|
bci_organ.Remove(carbon_occupant)
|
|
|
|
if (isnull(bci_to_implant))
|
|
say("Occupant's previous brain-computer interface has been transferred to internal storage unit.")
|
|
carbon_occupant.transferItemToLoc(bci_organ, src)
|
|
bci_to_implant = bci_organ
|
|
else
|
|
say("Occupant's previous brain-computer interface has been ejected.")
|
|
bci_organ.forceMove(drop_location())
|
|
else if (!isnull(bci_to_implant))
|
|
say("Occupant has been injected with [bci_to_implant].")
|
|
bci_to_implant.Insert(carbon_occupant)
|
|
|
|
/obj/machinery/bci_implanter/open_machine(drop = TRUE, density_to_set = FALSE)
|
|
if(state_open)
|
|
return FALSE
|
|
|
|
..()
|
|
|
|
return TRUE
|
|
|
|
/obj/machinery/bci_implanter/close_machine(mob/living/carbon/user, density_to_set = TRUE)
|
|
if(!state_open)
|
|
return FALSE
|
|
|
|
..()
|
|
|
|
var/mob/living/carbon/carbon_occupant = occupant
|
|
if (istype(occupant))
|
|
var/obj/item/organ/internal/cyberimp/bci/bci_organ = carbon_occupant.getorgan(/obj/item/organ/internal/cyberimp/bci)
|
|
if (isnull(bci_organ) && isnull(bci_to_implant))
|
|
say("No brain-computer interface inserted, and occupant does not have one. Insert a BCI to implant one.")
|
|
playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE)
|
|
return FALSE
|
|
|
|
addtimer(CALLBACK(src, PROC_REF(start_process)), 1 SECONDS)
|
|
return TRUE
|
|
|
|
/obj/machinery/bci_implanter/relaymove(mob/living/user, direction)
|
|
var/message
|
|
|
|
if (locked)
|
|
message = "it won't budge!"
|
|
else if (user.stat != CONSCIOUS)
|
|
message = "you don't have the energy!"
|
|
|
|
if (!isnull(message))
|
|
if (COOLDOWN_FINISHED(src, message_cooldown))
|
|
COOLDOWN_START(src, message_cooldown, 5 SECONDS)
|
|
balloon_alert(user, message)
|
|
|
|
return
|
|
|
|
open_machine()
|
|
|
|
/obj/machinery/bci_implanter/interact(mob/user)
|
|
if (state_open)
|
|
close_machine(null, user)
|
|
return
|
|
else if (locked)
|
|
balloon_alert(user, "it's locked!")
|
|
return
|
|
|
|
open_machine()
|
|
|
|
/obj/machinery/bci_implanter/proc/drop_stored_bci()
|
|
if (isnull(bci_to_implant))
|
|
return
|
|
bci_to_implant.forceMove(drop_location())
|
|
|
|
/obj/machinery/bci_implanter/dump_inventory_contents(list/subset)
|
|
// Prevents opening the machine dropping the BCI.
|
|
// "dump_contents()" still drops the BCI.
|
|
return ..(contents - bci_to_implant)
|
|
|
|
/obj/machinery/bci_implanter/Exited(atom/movable/gone, direction)
|
|
if (gone == bci_to_implant)
|
|
bci_to_implant = null
|
|
return ..()
|
|
|
|
/obj/item/circuitboard/machine/bci_implanter
|
|
name = "Brain-Computer Interface Manipulation Chamber (Machine Board)"
|
|
greyscale_colors = CIRCUIT_COLOR_SCIENCE
|
|
build_path = /obj/machinery/bci_implanter
|
|
req_components = list(
|
|
/obj/item/stock_parts/micro_laser = 2,
|
|
/obj/item/stock_parts/manipulator = 1,
|
|
)
|