mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 20:48:56 +01:00
You can install B.O.R.I.S. in circuits with MMI components (+other MMI component changes) (#92002)
## About The Pull Request This PR adds the ability to install a B.O.R.I.S. in a circuit that contains an MMI component. These circuits can then be remotely connected to by an AI by clicking on them or anything they are inside of. To indicate that a circuit allows remote AI connection, an indicator is given to the circuit and anything containing it. Additionally: - Refactors the MMI component to use `item_interaction`, since it was pertinent. - You cannot insert an MMI/B.O.R.I.S. into a locked circuit. - You can no longer hotswap MMIs/B.O.R.I.S.es - you must manually eject the inserted one. Let me know what changelog labels I should use for the hotswap removal and the prevention of insertion into locked circuits. ## Why It's Good For The Game If you can put an MMI or posibrain in a circuit, why not allow an AI to use it using a B.O.R.I.S.? ## Changelog 🆑 add: B.O.R.I.S.es can be installed inside of integrated circuits with MMI components, allowing an AI to remotely interface with them the same way an MMI or posibrain could. refactor: The MMI component now uses item interaction behavior for inserting MMIs/B.O.R.I.S.es. /🆑 --------- Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,18 @@
|
||||
#define MMI_MESSAGE_COOLDOWN (0.1 SECONDS)
|
||||
|
||||
/datum/action/innate/mmi_comp_disconnect
|
||||
name = "Disconnect from remote circuit"
|
||||
desc = "Stop controlling an integrated circuit"
|
||||
button_icon = 'icons/mob/actions/actions_AI.dmi'
|
||||
button_icon_state = "ai_core"
|
||||
|
||||
/datum/action/innate/mmi_comp_disconnect/Trigger(trigger_flags)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/obj/item/circuit_component/mmi/mmi_comp = target
|
||||
mmi_comp.remove_occupant()
|
||||
|
||||
/**
|
||||
* # Man-Machine Interface Component
|
||||
*
|
||||
@@ -7,7 +20,7 @@
|
||||
*/
|
||||
/obj/item/circuit_component/mmi
|
||||
display_name = "Man-Machine Interface"
|
||||
desc = "A component that allows MMI to enter shells to send output signals."
|
||||
desc = "A component that allows an MMI or B.O.R.I.S. module to be inserted into the shell, allowing a brain or artificial intelligence to output signals."
|
||||
category = "Action"
|
||||
circuit_flags = CIRCUIT_FLAG_REFUSE_MODULE
|
||||
|
||||
@@ -34,15 +47,36 @@
|
||||
/// Called when the MMI right clicks.
|
||||
var/datum/port/output/secondary_attack
|
||||
|
||||
/// The current MMI card
|
||||
/// The current MMI/posibrain
|
||||
var/obj/item/mmi/brain
|
||||
|
||||
/// The current B.O.R.I.S. module
|
||||
var/obj/item/borg/upgrade/ai/boris
|
||||
|
||||
/// The brainmob or AI currently controlling to the circuit
|
||||
var/mob/living/occupant
|
||||
|
||||
/// The action used to allow a connected AI to disconnect
|
||||
var/datum/action/innate/mmi_comp_disconnect/disconnect_action
|
||||
|
||||
/// Maximum length of the message that can be sent to the MMI
|
||||
var/max_length = 300
|
||||
|
||||
/// Cooldown for when the next message can be sent to the MMI.
|
||||
COOLDOWN_DECLARE(message_cooldown)
|
||||
|
||||
/// These two component weakrefs are needed because GetComponent is not reliable for components that are DUPE_ALLOWED or DUPE_SELECTED
|
||||
|
||||
/// A reference to the connect_containers component that handles making boris circuits and things containing them clickable by AIs to connect
|
||||
var/datum/weakref/boris_circuit_container_connections
|
||||
|
||||
/// A reference to the connect_containers component that handles when a connected AI or something containing it moves
|
||||
var/datum/weakref/connected_ai_container_connections
|
||||
|
||||
/obj/item/circuit_component/mmi/Initialize(mapload)
|
||||
. = ..()
|
||||
disconnect_action = new(src)
|
||||
|
||||
/obj/item/circuit_component/mmi/populate_ports()
|
||||
message = add_input_port("Message", PORT_TYPE_STRING)
|
||||
send = add_input_port("Send Message", PORT_TYPE_SIGNAL)
|
||||
@@ -58,90 +92,214 @@
|
||||
clicked_atom = add_output_port("Target Entity", PORT_TYPE_ATOM)
|
||||
|
||||
/obj/item/circuit_component/mmi/Destroy()
|
||||
remove_current_brain()
|
||||
remove_occupant_item()
|
||||
QDEL_NULL(disconnect_action)
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mmi/input_received(datum/port/input/port)
|
||||
|
||||
if(!brain)
|
||||
if(!brain && !boris)
|
||||
return
|
||||
|
||||
if(COMPONENT_TRIGGERED_BY(eject, port))
|
||||
remove_current_brain()
|
||||
remove_occupant_item()
|
||||
if(COMPONENT_TRIGGERED_BY(send, port))
|
||||
if(!message.value || !COOLDOWN_FINISHED(src, message_cooldown))
|
||||
return
|
||||
|
||||
var/msg_str = copytext(html_encode(message.value), 1, max_length)
|
||||
|
||||
var/mob/living/target = brain.brainmob
|
||||
if(!target)
|
||||
if(!occupant)
|
||||
return
|
||||
|
||||
to_chat(target, "[span_bold("You hear a message in your ear: ")][msg_str]")
|
||||
if(isAI(occupant))
|
||||
to_chat(occupant, "[span_boldnotice("Message from remote circuit: ")][span_notice(msg_str)]")
|
||||
else
|
||||
to_chat(occupant, "[span_bold("You hear a message: ")][msg_str]")
|
||||
COOLDOWN_START(src, message_cooldown, MMI_MESSAGE_COOLDOWN)
|
||||
|
||||
|
||||
/obj/item/circuit_component/mmi/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
RegisterSignal(shell, COMSIG_ATOM_ATTACKBY, PROC_REF(handle_attack_by))
|
||||
RegisterSignal(shell, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(handle_interaction))
|
||||
|
||||
/obj/item/circuit_component/mmi/unregister_shell(atom/movable/shell)
|
||||
UnregisterSignal(shell, COMSIG_ATOM_ATTACKBY)
|
||||
remove_current_brain()
|
||||
UnregisterSignal(shell, list(COMSIG_ATOM_ITEM_INTERACTION))
|
||||
remove_occupant_item()
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/handle_attack_by(atom/movable/shell, obj/item/item, mob/living/attacker)
|
||||
/obj/item/circuit_component/mmi/proc/handle_interaction(atom/movable/shell, mob/living/user, obj/item/item)
|
||||
SIGNAL_HANDLER
|
||||
var/obj/item/mmi/target_mmi
|
||||
var/mob/living/new_occupant
|
||||
var/obj/item/borg/upgrade/ai/target_boris
|
||||
if(istype(item, /obj/item/mmi))
|
||||
var/obj/item/mmi/target_mmi = item
|
||||
target_mmi = item
|
||||
if(!target_mmi.brainmob)
|
||||
return
|
||||
add_mmi(item)
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/add_mmi(obj/item/mmi/to_add)
|
||||
remove_current_brain()
|
||||
|
||||
to_add.forceMove(src)
|
||||
if(to_add.brainmob)
|
||||
update_mmi_mob(to_add, null, to_add.brainmob)
|
||||
brain = to_add
|
||||
RegisterSignal(to_add, COMSIG_QDELETING, PROC_REF(remove_current_brain))
|
||||
RegisterSignal(to_add, COMSIG_MOVABLE_MOVED, PROC_REF(mmi_moved))
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/mmi_moved(atom/movable/mmi)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(mmi.loc != src)
|
||||
remove_current_brain()
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/remove_current_brain()
|
||||
SIGNAL_HANDLER
|
||||
if(!brain)
|
||||
shell.balloon_alert(user, "no consciousness detected!")
|
||||
return ITEM_INTERACT_FAILURE
|
||||
new_occupant = target_mmi.brainmob
|
||||
else if(istype(item, /obj/item/borg/upgrade/ai))
|
||||
target_boris = item
|
||||
else
|
||||
return
|
||||
var/datum/component/shell/shell_comp = shell.GetComponent(/datum/component/shell)
|
||||
if(shell_comp.locked)
|
||||
shell.balloon_alert(user, "locked!")
|
||||
return ITEM_INTERACT_FAILURE
|
||||
if(brain || boris)
|
||||
shell.balloon_alert(user, "already has brain!")
|
||||
return ITEM_INTERACT_FAILURE
|
||||
if(!user.transferItemToLoc(item, src))
|
||||
return ITEM_INTERACT_FAILURE
|
||||
if(target_mmi)
|
||||
brain = target_mmi
|
||||
set_occupant(new_occupant)
|
||||
if(target_boris)
|
||||
boris = target_boris
|
||||
register_boris_circuit(shell)
|
||||
RegisterSignal(item, COMSIG_QDELETING, PROC_REF(remove_occupant_item))
|
||||
RegisterSignal(item, COMSIG_MOVABLE_MOVED, PROC_REF(occupant_item_moved))
|
||||
|
||||
if(brain.brainmob)
|
||||
update_mmi_mob(brain, brain.brainmob)
|
||||
UnregisterSignal(brain, list(
|
||||
/obj/item/circuit_component/mmi/proc/register_boris_circuit(atom/movable/shell)
|
||||
var/static/list/connections = list(COMSIG_MOVABLE_MOVED = PROC_REF(boris_shell_or_container_moved))
|
||||
boris_circuit_container_connections = WEAKREF(AddComponent(/datum/component/connect_containers, src, connections))
|
||||
for(var/atom/movable/location as anything in get_nested_locs(shell) + shell)
|
||||
location.AddComponentFrom(REF(src), /datum/component/boris_circuit_container)
|
||||
AddComponentFrom(REF(location), /datum/component/shuttle_move_deferred_checks, PROC_REF(post_movement_checks))
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/unregister_boris_circuit(atom/movable/shell)
|
||||
QDEL_NULL(boris_circuit_container_connections)
|
||||
for(var/atom/movable/location as anything in get_nested_locs(shell) + shell)
|
||||
location.RemoveComponentSource(REF(src), /datum/component/boris_circuit_container)
|
||||
RemoveComponentSource(REF(location), /datum/component/shuttle_move_deferred_checks)
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/boris_shell_or_container_moved(atom/movable/shell_or_container, atom/old_loc)
|
||||
SIGNAL_HANDLER
|
||||
if(isturf(old_loc) && isturf(shell_or_container.loc))
|
||||
return
|
||||
var/list/old_locs = list()
|
||||
if(ismovable(old_loc))
|
||||
old_locs = get_nested_locs(old_loc) + old_loc
|
||||
var/list/new_locs = get_nested_locs(shell_or_container)
|
||||
for(var/atom/movable/loc_exited as anything in old_locs - new_locs)
|
||||
loc_exited.RemoveComponentSource(REF(src), /datum/component/boris_circuit_container)
|
||||
RemoveComponentSource(REF(loc_exited), /datum/component/shuttle_move_deferred_checks)
|
||||
for(var/atom/movable/loc_entered as anything in new_locs - old_locs)
|
||||
loc_entered.AddComponentFrom(REF(src), /datum/component/boris_circuit_container)
|
||||
AddComponentFrom(REF(loc_entered), /datum/component/shuttle_move_deferred_checks, PROC_REF(post_movement_checks))
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/occupant_item_moved(atom/movable/occupant_item)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(occupant_item.loc != src)
|
||||
remove_occupant_item(occupant_item)
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/remove_occupant_item(obj/item/removing)
|
||||
SIGNAL_HANDLER
|
||||
if(!removing)
|
||||
removing = brain
|
||||
if(!removing)
|
||||
removing = boris
|
||||
if(!removing)
|
||||
return
|
||||
if(istype(removing, /obj/item/mmi))
|
||||
brain = null
|
||||
if(istype(removing, /obj/item/borg/upgrade/ai))
|
||||
boris = null
|
||||
unregister_boris_circuit(parent.shell)
|
||||
remove_occupant()
|
||||
|
||||
UnregisterSignal(removing, list(
|
||||
COMSIG_QDELETING,
|
||||
COMSIG_MOVABLE_MOVED
|
||||
))
|
||||
if(brain.loc == src)
|
||||
brain.forceMove(drop_location())
|
||||
brain = null
|
||||
if(removing.loc == src)
|
||||
removing.forceMove(drop_location())
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/update_mmi_mob(datum/source, mob/living/old_mmi, mob/living/new_mmi)
|
||||
/obj/item/circuit_component/mmi/proc/confirm_ai_connect(mob/living/silicon/ai/user, atom/movable/shell)
|
||||
var/confirmation = tgui_alert(user, "Connect to [shell]?", buttons = list("Yes", "No"))
|
||||
if(confirmation != "Yes")
|
||||
return
|
||||
if(QDELETED(src) || QDELETED(user) || QDELETED(shell) || !parent?.shell || !user.can_interact_with(shell) || !boris)
|
||||
return
|
||||
do_ai_connect(user, shell)
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/do_ai_connect(mob/living/silicon/ai/user, atom/movable/shell)
|
||||
if(occupant)
|
||||
if(occupant != user)
|
||||
shell.balloon_alert(user, "occupied!")
|
||||
return
|
||||
set_occupant(user)
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/set_occupant(mob/living/new_occupant)
|
||||
new_occupant.remote_control = src
|
||||
RegisterSignal(new_occupant, COMSIG_MOB_CLICKON, PROC_REF(handle_occupant_attack))
|
||||
RegisterSignal(new_occupant, COMSIG_QDELETING, PROC_REF(remove_occupant))
|
||||
occupant = new_occupant
|
||||
if(!isAI(new_occupant))
|
||||
return
|
||||
ADD_TRAIT(new_occupant, TRAIT_CONNECTED_TO_CIRCUIT, REF(src))
|
||||
var/mob/living/silicon/ai = new_occupant
|
||||
ai.reset_perspective(src)
|
||||
// Perspective gets reset whenever multicam is ended, which happens whenever an AI gets incapacitated or carded.
|
||||
// This could change in the future, so we also register other signal handlers.
|
||||
RegisterSignals(ai, list(COMSIG_MOB_RESET_PERSPECTIVE, SIGNAL_ADDTRAIT(TRAIT_INCAPACITATED)), PROC_REF(remove_occupant))
|
||||
RegisterSignal(ai, COMSIG_SILICON_AI_SET_CONTROL_DISABLED, PROC_REF(on_control_toggled))
|
||||
var/static/list/connections = list(COMSIG_MOVABLE_MOVED = PROC_REF(occupant_or_container_moved))
|
||||
connected_ai_container_connections = WEAKREF(AddComponent(/datum/component/connect_containers, ai, connections))
|
||||
for(var/atom/movable/location as anything in get_nested_locs(ai) + ai)
|
||||
AddComponentFrom(REF(location), /datum/component/shuttle_move_deferred_checks, PROC_REF(post_movement_checks))
|
||||
disconnect_action.Grant(ai)
|
||||
to_chat(ai, span_notice("Established connection with remote circuit."))
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/occupant_or_container_moved(atom/movable/occupant_or_container, atom/old_loc)
|
||||
SIGNAL_HANDLER
|
||||
if(old_mmi)
|
||||
old_mmi.remote_control = null
|
||||
UnregisterSignal(old_mmi, COMSIG_MOB_CLICKON)
|
||||
if(new_mmi)
|
||||
new_mmi.remote_control = src
|
||||
RegisterSignal(new_mmi, COMSIG_MOB_CLICKON, PROC_REF(handle_mmi_attack))
|
||||
if(isturf(old_loc) && isturf(occupant_or_container.loc))
|
||||
return
|
||||
var/list/old_locs = list()
|
||||
if(ismovable(old_loc))
|
||||
old_locs = get_nested_locs(old_loc) + old_loc
|
||||
var/list/new_locs = get_nested_locs(occupant_or_container)
|
||||
for(var/atom/movable/loc_exited as anything in old_locs - new_locs)
|
||||
RemoveComponentSource(REF(loc_exited), /datum/component/shuttle_move_deferred_checks)
|
||||
for(var/atom/movable/loc_entered as anything in new_locs - old_locs)
|
||||
AddComponentFrom(REF(loc_entered), /datum/component/shuttle_move_deferred_checks, PROC_REF(post_movement_checks))
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/post_movement_checks()
|
||||
SIGNAL_HANDLER
|
||||
var/mob/living/silicon/ai/ai = occupant
|
||||
if(!istype(ai))
|
||||
return
|
||||
if(!ai.can_interact_with(parent.shell))
|
||||
remove_occupant()
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/on_control_toggled(datum/_source, control_disabled)
|
||||
SIGNAL_HANDLER
|
||||
if(control_disabled)
|
||||
remove_occupant()
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/remove_occupant()
|
||||
SIGNAL_HANDLER
|
||||
if(!occupant)
|
||||
return
|
||||
if(isAI(occupant))
|
||||
REMOVE_TRAIT(occupant, TRAIT_CONNECTED_TO_CIRCUIT, REF(src))
|
||||
var/mob/living/silicon/ai/ai = occupant
|
||||
if(!ai.eyeobj)
|
||||
ai.create_eye()
|
||||
disconnect_action.Remove(ai)
|
||||
UnregisterSignal(ai, list(COMSIG_MOB_RESET_PERSPECTIVE, SIGNAL_ADDTRAIT(TRAIT_INCAPACITATED), COMSIG_SILICON_AI_SET_CONTROL_DISABLED))
|
||||
QDEL_NULL(connected_ai_container_connections)
|
||||
for(var/atom/movable/location as anything in get_nested_locs(ai) + ai)
|
||||
RemoveComponentSource(REF(location), /datum/component/shuttle_move_deferred_checks)
|
||||
ai.reset_perspective(null)
|
||||
to_chat(ai, span_notice("Disconnected from remote circuit."))
|
||||
occupant.remote_control = null
|
||||
UnregisterSignal(occupant, list(COMSIG_MOB_CLICKON, COMSIG_QDELETING))
|
||||
occupant = null
|
||||
|
||||
/obj/item/circuit_component/mmi/relaymove(mob/living/user, direct)
|
||||
if(user != brain.brainmob)
|
||||
if(user != occupant)
|
||||
return ..()
|
||||
|
||||
if(direct & NORTH)
|
||||
@@ -155,7 +313,7 @@
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/circuit_component/mmi/proc/handle_mmi_attack(mob/living/source, atom/target, list/modifiers, list/attack_modifiers)
|
||||
/obj/item/circuit_component/mmi/proc/handle_occupant_attack(mob/living/source, atom/target, list/modifiers, list/attack_modifiers)
|
||||
SIGNAL_HANDLER
|
||||
if(modifiers[RIGHT_CLICK])
|
||||
clicked_atom.set_output(target)
|
||||
@@ -174,7 +332,7 @@
|
||||
|
||||
/obj/item/circuit_component/mmi/removed_from(obj/item/integrated_circuit/removed_from)
|
||||
REMOVE_TRAIT(removed_from, TRAIT_COMPONENT_MMI, REF(src))
|
||||
remove_current_brain()
|
||||
remove_occupant_item()
|
||||
return ..()
|
||||
|
||||
#undef MMI_MESSAGE_COOLDOWN
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/datum/component/boris_circuit_container
|
||||
dupe_mode = COMPONENT_DUPE_SOURCES
|
||||
var/list/obj/item/circuit_component/mmi/mmi_components
|
||||
var/datum/weakref/indicator_weakref
|
||||
|
||||
/datum/component/boris_circuit_container/Initialize()
|
||||
. = ..()
|
||||
if(!ismovable(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
/datum/component/boris_circuit_container/Destroy(force)
|
||||
mmi_components = null
|
||||
return ..()
|
||||
|
||||
/datum/component/boris_circuit_container/RegisterWithParent()
|
||||
. = ..()
|
||||
RegisterSignal(parent, COMSIG_ATOM_ATTACK_AI, PROC_REF(on_ai_click))
|
||||
var/atom/parent_atom = parent
|
||||
var/image/indicator_image = image('icons/mob/huds/hud.dmi', parent_atom, "hudtracking", pixel_x = 8)
|
||||
SET_PLANE_EXPLICIT(indicator_image, ABOVE_LIGHTING_PLANE, parent_atom)
|
||||
indicator_weakref = WEAKREF(parent_atom.add_alt_appearance(
|
||||
/datum/atom_hud/alternate_appearance/basic/ais,
|
||||
"boris_circuit_container_[REF(src)]",
|
||||
indicator_image,
|
||||
NONE
|
||||
))
|
||||
|
||||
/datum/component/boris_circuit_container/UnregisterFromParent()
|
||||
QDEL_NULL(indicator_weakref)
|
||||
return ..()
|
||||
|
||||
/datum/component/boris_circuit_container/on_source_add(source)
|
||||
. = ..()
|
||||
var/obj/item/circuit_component/mmi/source_comp = locate(source)
|
||||
if(!istype(source_comp))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
LAZYADD(mmi_components, source)
|
||||
|
||||
/datum/component/boris_circuit_container/on_source_remove(source)
|
||||
var/obj/item/circuit_component/mmi/source_comp = locate(source)
|
||||
if(source_comp)
|
||||
LAZYREMOVE(mmi_components, source_comp)
|
||||
return ..()
|
||||
|
||||
/datum/component/boris_circuit_container/proc/on_ai_click(atom/movable/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
if(!length(mmi_components))
|
||||
return
|
||||
if(HAS_TRAIT(user, TRAIT_CONNECTED_TO_CIRCUIT))
|
||||
return
|
||||
if(length(mmi_components) == 1)
|
||||
var/obj/item/circuit_component/mmi/mmi_comp = mmi_components[1]
|
||||
if(mmi_comp.parent.shell == source)
|
||||
INVOKE_ASYNC(mmi_comp, TYPE_PROC_REF(/obj/item/circuit_component/mmi, confirm_ai_connect), user, source)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
INVOKE_ASYNC(src, PROC_REF(select_circuit), source, user)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/datum/component/boris_circuit_container/proc/select_circuit(atom/movable/source, mob/user)
|
||||
var/list/choices = list()
|
||||
var/list/choice_map = list()
|
||||
var/source_in_choices = FALSE
|
||||
for(var/obj/item/circuit_component/mmi/mmi_component as anything in mmi_components)
|
||||
if(mmi_component.occupant)
|
||||
continue
|
||||
var/atom/movable/shell = mmi_component.parent.shell
|
||||
choices[shell] = shell
|
||||
choice_map[shell] = mmi_component
|
||||
if(shell == source)
|
||||
source_in_choices = TRUE
|
||||
if(!source_in_choices)
|
||||
choices[source] = source
|
||||
var/atom/movable/choice = show_radial_menu(user, source, choices, user_space = TRUE)
|
||||
if(QDELETED(choice) || QDELETED(user) || !user.can_interact_with(choice))
|
||||
return
|
||||
if(choice == source && !source_in_choices)
|
||||
choice.attack_ai(user)
|
||||
return
|
||||
var/obj/item/circuit_component/mmi/choice_comp = choice_map[choice]
|
||||
if(QDELETED(choice_comp) || choice_comp.parent?.shell != choice || !choice_comp.boris)
|
||||
return
|
||||
choice_comp.do_ai_connect(user, choice)
|
||||
Reference in New Issue
Block a user