Files
Alexis 21b4095dfd [MDB IGNORE] [IDB IGNORE] Upstream Sync - 04/17/2026 (#5453)
Upstream 04/17/2026

fixes https://github.com/Bubberstation/Bubberstation/issues/5549

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com>
Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com>
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com>
Co-authored-by: rageguy505 <54517726+rageguy505@users.noreply.github.com>
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Co-authored-by: Aliceee2ch <160794176+Aliceee2ch@users.noreply.github.com>
Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com>
Co-authored-by: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com>
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
Co-authored-by: Maxipat <108554989+Maxipat112@users.noreply.github.com>
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: SimplyLogan <47579821+loganuk@users.noreply.github.com>
Co-authored-by: loganuk <fakeemail123@aol.com>
Co-authored-by: Leland Kemble <70413276+lelandkemble@users.noreply.github.com>
Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com>
Co-authored-by: Roxy <75404941+TealSeer@users.noreply.github.com>
Co-authored-by: Lucy <lucy@absolucy.moe>
Co-authored-by: siliconOpossum <138069572+siliconOpossum@users.noreply.github.com>
Co-authored-by: Isratosh <Isratosh@hotmail.com>
Co-authored-by: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com>
Co-authored-by: Neocloudy <88008002+Neocloudy@users.noreply.github.com>
Co-authored-by: Alexander V. <volas@ya.ru>
Co-authored-by: ElGitificador <168473461+ElGitificador@users.noreply.github.com>
Co-authored-by: Twaticus <46540570+Twaticus@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
Co-authored-by: Tim <timothymtorres@gmail.com>
Co-authored-by: Iamgoofball <iamgoofball@gmail.com>
Co-authored-by: Layzu666 <121319428+Layzu666@users.noreply.github.com>
Co-authored-by: Arturlang <24881678+Arturlang@users.noreply.github.com>
Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com>
Co-authored-by: mrmanlikesbt <99309552+mrmanlikesbt@users.noreply.github.com>
Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
Co-authored-by: John F. Kennedy <54908920+MacaroniCritter@users.noreply.github.com>
Co-authored-by: Cursor <102828457+theselfish@users.noreply.github.com>
Co-authored-by: Josh <josh.adam.powell@gmail.com>
Co-authored-by: Josh Powell <josh.powell@softwire.com>
Co-authored-by: Yobrocharlie <Charliemiller5617@gmail.com>
Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com>
Co-authored-by: shayoki <96078776+shayoki@users.noreply.github.com>
Co-authored-by: LT3 <83487515+lessthnthree@users.noreply.github.com>
2026-05-16 00:56:00 +02:00

239 lines
7.9 KiB
Plaintext

/obj/item/implant/circuit
name = "circuit implant"
actions_types = null
implant_info = "Functions as a shell for integrated circuits. Activation conditions and effects are defined by the installed circuit."
implant_lore = "The Subdermal Circuit Housing is a common implant design manufactured primarily by DIY electronics enthusiasts. \
Similar in concept to Brain-Computer Interfaces, these devices accept an integrated circuit, and support components that allow the \
user to trigger other installed components. What it gains in the ability to be implanted in non-humanoid hosts, it loses in physical \
capacity and support for various neural interfacing capabilities."
/obj/item/implant/circuit/Initialize(mapload)
. = ..()
AddComponent(/datum/component/shell, list(/obj/item/circuit_component/implant_core), SHELL_CAPACITY_TINY)
RegisterSignal(src, COMSIG_CIRCUIT_ACTION_COMPONENT_REGISTERED, PROC_REF(action_comp_registered))
RegisterSignal(src, COMSIG_CIRCUIT_ACTION_COMPONENT_UNREGISTERED, PROC_REF(action_comp_unregistered))
RegisterSignal(src, COMSIG_IMPLANT_OTHER, PROC_REF(on_new_implant))
/obj/item/implant/circuit/proc/action_comp_registered(datum/source, obj/item/circuit_component/equipment_action/action_comp)
SIGNAL_HANDLER
LAZYADD(actions, new/datum/action/innate/circuit_equipment_action(src, action_comp))
/obj/item/implant/circuit/proc/action_comp_unregistered(datum/source, obj/item/circuit_component/equipment_action/action_comp)
SIGNAL_HANDLER
var/datum/action/innate/circuit_equipment_action/action = action_comp.granted_to[REF(src)]
if(!istype(action))
return
LAZYREMOVE(actions, action)
QDEL_LIST_ASSOC_VAL(action_comp.granted_to)
/obj/item/implant/circuit/proc/on_new_implant(obj/item/implant/source, list/arguments, obj/item/implant/other_implant)
SIGNAL_HANDLER
if(!istype(other_implant, /obj/item/implant/circuit))
return
var/mob/living/user = arguments[2]
var/force = arguments[4]
if(!force)
source.balloon_alert(user, "duplicate implant present!")
return COMPONENT_STOP_IMPLANTING
/obj/item/implant/circuit/ui_host(mob/user)
if(istype(loc, /obj/item/implantcase))
return loc
return ..()
/obj/item/circuit_component/implant_core
display_name = "Implant Core"
desc = "Controls the core operations of the implant."
/// A reference to the action button to look at charge/get info
var/datum/action/innate/implant_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/obj/item/implant/implant
/obj/item/circuit_component/implant_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_BOOLEAN, trigger = PROC_REF(update_charge_action))
user_port = add_output_port("User", PORT_TYPE_USER)
/obj/item/circuit_component/implant_core/Destroy()
QDEL_NULL(charge_action)
return ..()
/obj/item/circuit_component/implant_core/proc/update_charge_action()
CIRCUIT_TRIGGER
if (show_charge_meter.value)
if (charge_action)
return
charge_action = new(src)
if (implant.imp_in)
charge_action.Grant(implant.imp_in)
implant.actions += charge_action
else
if (!charge_action)
return
if (implant.imp_in)
charge_action.Remove(implant.imp_in)
implant.actions -= charge_action
QDEL_NULL(charge_action)
/obj/item/circuit_component/implant_core/register_shell(atom/movable/shell)
implant = shell
show_charge_meter.set_value(TRUE)
RegisterSignal(shell, COMSIG_IMPLANT_IMPLANTED, PROC_REF(on_implanted))
RegisterSignal(shell, COMSIG_IMPLANT_REMOVED, PROC_REF(on_removed))
/obj/item/circuit_component/implant_core/unregister_shell(atom/movable/shell)
implant = null
if (charge_action)
if (implant.imp_in)
charge_action.Remove(implant.imp_in)
implant.actions -= charge_action
QDEL_NULL(charge_action)
UnregisterSignal(shell, list(
COMSIG_IMPLANT_IMPLANTED,
COMSIG_IMPLANT_REMOVED,
))
/obj/item/circuit_component/implant_core/proc/on_implanted(datum/source, mob/living/owner)
SIGNAL_HANDLER
update_charge_action()
user_port.set_output(owner)
RegisterSignal(owner, COMSIG_ATOM_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/implant_core/proc/on_removed(datum/source, mob/living/owner)
SIGNAL_HANDLER
user_port.set_output(null)
UnregisterSignal(owner, list(
COMSIG_ATOM_EXAMINE,
COMSIG_PROCESS_BORGCHARGER_OCCUPANT,
COMSIG_LIVING_ELECTROCUTE_ACT,
))
/obj/item/circuit_component/implant_core/input_received(datum/port/input/port)
if (!COMPONENT_TRIGGERED_BY(send_message_signal, port))
return
var/sent_message = trim(message.value)
if (!sent_message)
return
if (isnull(implant.imp_in))
return
if (implant.imp_in.stat == DEAD)
return
to_chat(implant.imp_in, "<i>You hear a strange, robotic voice in your head...</i> \"[span_robot("[html_encode(sent_message)]")]\"")
/obj/item/circuit_component/implant_core/proc/on_borg_charge(datum/source, datum/callback/charge_cell, seconds_per_tick)
SIGNAL_HANDLER
if (isnull(parent.cell))
return
charge_cell.Invoke(parent.cell, seconds_per_tick)
/obj/item/circuit_component/implant_core/proc/on_electrocute(datum/source, shock_damage, shock_source, 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/implant_core/proc/on_examine(datum/source, mob/mob, list/examine_text)
SIGNAL_HANDLER
if (isobserver(mob))
examine_text += span_notice("[source.p_They()] [source.p_have()] <a href='byond://?src=[REF(src)];open_implant=1'>\a [parent] implanted in [source.p_them()]</a>.")
/obj/item/circuit_component/implant_core/Topic(href, list/href_list)
..()
if (!isobserver(usr))
return
if (href_list["open_implant"])
parent.attack_ghost(usr)
/datum/action/innate/implant_charge_action
name = "Check Implant Charge"
check_flags = NONE
button_icon = 'icons/obj/machines/cell_charger.dmi'
button_icon_state = "cell"
var/obj/item/circuit_component/implant_core/circuit_component
/datum/action/innate/implant_charge_action/New(obj/item/circuit_component/implant_core/circuit_component)
..()
src.circuit_component = circuit_component
build_all_button_icons()
START_PROCESSING(SSobj, src)
/datum/action/innate/implant_charge_action/create_button(mob/viewer)
var/atom/movable/screen/movable/action_button/button = ..()
button.maptext_x = 2
button.maptext_y = 0
return button
/datum/action/innate/implant_charge_action/Destroy()
circuit_component.charge_action = null
circuit_component = null
STOP_PROCESSING(SSobj, src)
return ..()
/datum/action/innate/implant_charge_action/Trigger(mob/clicker, trigger_flags)
if(!..())
return
var/obj/item/stock_parts/power_store/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/implant_charge_action/process(seconds_per_tick)
build_all_button_icons(UPDATE_BUTTON_STATUS)
/datum/action/innate/implant_charge_action/update_button_status(atom/movable/screen/movable/action_button/button, force = FALSE)
. = ..()
var/obj/item/stock_parts/power_store/cell/cell = circuit_component.parent.cell
button.maptext = cell ? MAPTEXT("[cell.percent()]%") : ""
/obj/item/implantcase/circuit
name = "implant case - 'Circuit'"
desc = "A glass case containing a circuit implant shell."
imp_type = /obj/item/implant/circuit