diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm
index a9e4a3b82f9..5e084e4dc83 100644
--- a/code/datums/components/gps.dm
+++ b/code/datums/components/gps.dm
@@ -23,11 +23,21 @@ GLOBAL_LIST_EMPTY(GPS_list)
/datum/component/gps/kheiral_cuffs/Initialize(_gpstag = "COM0")
. = ..()
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(deactivate_kheiral_cuffs))
+ RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(deactivate_if_station))
/datum/component/gps/kheiral_cuffs/proc/deactivate_kheiral_cuffs(datum/source)
SIGNAL_HANDLER
qdel(src)
+/datum/component/gps/kheiral_cuffs/proc/deactivate_if_station(atom/movable/moved_atom, turf/old_turf, turf/new_turf)
+ SIGNAL_HANDLER
+ if(!isturf(new_turf))
+ return
+
+ if(is_station_level(new_turf.z))
+ qdel(src)
+ return
+
///GPS component subtype. Only gps/item's can be used to open the UI.
/datum/component/gps/item
var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user.
diff --git a/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm b/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm
index 79e82ac954b..b298eb9f96d 100644
--- a/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm
+++ b/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm
@@ -42,6 +42,10 @@
purchase_path = /obj/item/storage/box/minertracker
cost_per_order = 600
+/datum/orderable_item/consumables/deathrattle_implants
+ purchase_path = /obj/item/storage/box/minerdeathrattle
+ cost_per_order = 900
+
/datum/orderable_item/consumables/space_cash
purchase_path = /obj/item/stack/spacecash/c1000
desc = "A stack of space cash worth 1000 credits."
diff --git a/code/game/machinery/computer/orders/order_items/mining/order_mining.dm b/code/game/machinery/computer/orders/order_items/mining/order_mining.dm
index f9247d039ce..cf33d3bd8e5 100644
--- a/code/game/machinery/computer/orders/order_items/mining/order_mining.dm
+++ b/code/game/machinery/computer/orders/order_items/mining/order_mining.dm
@@ -92,7 +92,7 @@
cost_per_order = 7000
/datum/orderable_item/mining/kheiralcuffs
- purchase_path = /obj/item/kheiral_cuffs
+ purchase_path = /obj/item/clothing/accessory/kheiral_cuffs
cost_per_order = 675
/datum/orderable_item/mining/bhop
diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm
index 4541bbdbdad..c13881fbabd 100644
--- a/code/game/objects/items/implants/implant.dm
+++ b/code/game/objects/items/implants/implant.dm
@@ -24,6 +24,10 @@
///what icon state will we represent ourselves with on the hud?
var/hud_icon_state = null
+ /// What's the most important info that we really, really care about, e.g. name, lifespan-after-death, utility?
+ var/implant_info = "No information available."
+ /// What's the extended lore for this implant that we might not care that much about, e.g. descriptions, flavortext?
+ var/implant_lore = "No information available."
/obj/item/implant/proc/activate()
SEND_SIGNAL(src, COMSIG_IMPLANT_ACTIVATED)
@@ -141,10 +145,16 @@
return ..()
/**
- * Gets implant specifications for the implant pad
+ * Gets the implant's info, for the implant pad.
*/
/obj/item/implant/proc/get_data()
- return "No information available"
+ return implant_info
+
+/**
+ * Gets the implant's lore info, also for the implant pad.
+ */
+/obj/item/implant/proc/get_lore()
+ return implant_lore
/obj/item/implant/dropped(mob/user)
. = TRUE
diff --git a/code/game/objects/items/implants/implant_battle_royale.dm b/code/game/objects/items/implants/implant_battle_royale.dm
index 11f68ec9345..87d5b5d2d15 100644
--- a/code/game/objects/items/implants/implant_battle_royale.dm
+++ b/code/game/objects/items/implants/implant_battle_royale.dm
@@ -23,16 +23,13 @@
/// We will explode if we're not in here after a set time
var/list/limited_areas = list()
-/obj/item/implant/explosive/battle_royale/get_data()
- return "Implant Specifications: \
- Name: Donk Co. 'Rumble Royale' Contestant Motivation Implant \
- Life: Activates upon death, or expiry of an internal timer. \
- Important Notes: Explodes. \
-
\
- Implant Details: \
- Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death. \
- Upon triggering the timer, the implant will begin to broadcast the surrounding area for the purposes of televised entertainment. This signal can be detected by GPS trackers. \
- Special Features: Exploding. "
+ implant_info = "Forcibly inducts the host into televised bloodsport by threatening their life via electrically-detonated microexplosive. \
+ Detonates upon death, expiry of an internal timer, or attempted removal."
+
+ implant_lore = "The Donk Co. 'Rumble Royale' Contestant Motivation Implant is a licensed copy of the Robust Corp RX-78 Employee Management Implant, \
+ featuring the very same microbomb that has provided plausible deniability, evidence disposal, and equipment denial for numerous non-state actors. \
+ The Rumble Royale variant also features additional nervous system interception functionality, allowing for broadcasting the host's field of view \
+ to compatible entertainment monitors, and a GPS-compatible tracking beacon for the sake of allowing contestants to locate each other more easily."
/obj/item/implant/explosive/battle_royale/on_death(datum/source, gibbed)
if (!battle_started)
diff --git a/code/game/objects/items/implants/implant_clown.dm b/code/game/objects/items/implants/implant_clown.dm
index 515a1b4d312..adcd272b8c2 100644
--- a/code/game/objects/items/implants/implant_clown.dm
+++ b/code/game/objects/items/implants/implant_clown.dm
@@ -1,12 +1,16 @@
-///A passive implant that plays sound/misc/sadtrombone.ogg when you deathgasp for any reason
+/// A passive implant that plays a funny noise (defaults to sound/misc/sadtrombone.ogg) when you deathgasp for any reason
/obj/item/implant/sad_trombone
name = "sad trombone implant"
actions_types = null
-/obj/item/implant/sad_trombone/get_data()
- return "Implant Specifications: \
- Name: Honk Co. Sad Trombone Implant \
- Life: Activates upon death. "
+ /// What do we play when the implantee deathgasps?
+ var/death_noise = 'sound/misc/sadtrombone.ogg'
+
+ implant_info = "Activates upon death. Plays a sad trombone sound."
+
+ implant_lore = "The Honk Co. Sad Trombone Implant is a subdermal vitals analyzer and \
+ sound synthesizer with exactly one sound effect pre-loaded: a sad trombone. \
+ Upon dying (or pretending to die via convincing-enough death gasp), plays a sad trombone sound."
/obj/item/implant/sad_trombone/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE)
. = ..()
@@ -20,7 +24,7 @@
/obj/item/implant/sad_trombone/proc/on_deathgasp(mob/source)
SIGNAL_HANDLER
- playsound(loc, 'sound/misc/sadtrombone.ogg', 50, FALSE)
+ playsound(loc, death_noise, 50, FALSE)
///Implanter that spawns with a sad trombone implant, as well as an appropriate name
/obj/item/implanter/sad_trombone
diff --git a/code/game/objects/items/implants/implant_deathrattle.dm b/code/game/objects/items/implants/implant_deathrattle.dm
index f26eb4ab947..6d4d7f16af6 100644
--- a/code/game/objects/items/implants/implant_deathrattle.dm
+++ b/code/game/objects/items/implants/implant_deathrattle.dm
@@ -1,6 +1,21 @@
+/// This deathrattle group does not care about the area someone dies in.
+#define DEATHRATTLE_AREA_NOLIST 0
+/// This deathrattle group uses its `area_list` as a blacklist: if someone dies in these areas, they DO NOT cause an alert.
+#define DEATHRATTLE_AREA_BLACKLIST 1
+/// This deathrattle group uses its `area_list` as a whitelist: if someone dies in these areas, they DO cause an alert.
+#define DEATHRATTLE_AREA_WHITELIST 2
+
/datum/deathrattle_group
+ /// The name of our deathrattle group.
var/name
+ /// The associated implants in this deathrattle group.
var/list/implants = list()
+ /// The area list mode.
+ var/area_list_mode = DEATHRATTLE_AREA_NOLIST
+ /// The area list. See `area_list_mode` for how this gets used.
+ var/list/area/area_list = list()
+ /// The prefix for this deathrattle group.
+ var/prefix
/datum/deathrattle_group/New(name)
if(name)
@@ -8,7 +23,20 @@
else
// Give the group a unique name for debugging, and possible future
// use for making custom linked groups.
- src.name = "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]"
+ src.name = "[prefix ? "[prefix]-" : ""][rand(100,999)] [pick(GLOB.phonetic_alphabet)]"
+
+/datum/deathrattle_group/standard
+ prefix = "STD"
+
+/// A deathrattle group subtype specifically for alerting people who die in the Lavaland or Icemoon Wastes.
+/// As per maintainer request, excludes... basically everything that isn't raw wasteland.
+/datum/deathrattle_group/lavaland
+ area_list_mode = DEATHRATTLE_AREA_WHITELIST
+ area_list = list(
+ /area/lavaland,
+ /area/icemoon,
+ )
+ prefix = "MIN"
/*
* Proc called by new implant being added to the group. Listens for the
@@ -25,6 +53,7 @@
RegisterSignal(implant, COMSIG_QDELETING, PROC_REF(on_implant_destruction))
implants += implant
+ implant.current_group = src
if(implant.imp_in)
on_implant_implantation(implant.imp_in)
@@ -51,7 +80,14 @@
return
var/name = owner.mind ? owner.mind.name : owner.real_name
- var/area = get_area_name(get_turf(owner))
+ var/area/death_area = get_area(owner)
+ // don't alert for a death if it's in in the area list AND we're on blacklist mode
+ if(is_type_in_list(death_area, area_list) && area_list_mode == DEATHRATTLE_AREA_BLACKLIST)
+ return
+ // don't alert a death if it's not in the area list AND we're on whitelist mode
+ if(!is_type_in_list(death_area, area_list) && area_list_mode == DEATHRATTLE_AREA_WHITELIST)
+ return
+ var/area_name = get_area_name(get_turf(owner))
// All "hearers" hear the same sound.
var/sound = pick(
'sound/items/knell/knell1.ogg',
@@ -70,7 +106,7 @@
// Deliberately the same message framing as ghost deathrattle
var/mob/living/recipient = implant.imp_in
- to_chat(recipient, "You hear a strange, robotic voice in your head... \"[span_robot("[name] has died at [area].")]\"")
+ to_chat(recipient, "You hear a strange, robotic voice in your head... \"[span_robot("[name] has died at [area_name].")]\"")
recipient.playsound_local(get_turf(recipient), sound, vol = 75, vary = FALSE, pressure_affected = FALSE, use_reverb = FALSE)
/obj/item/implant/deathrattle
@@ -78,12 +114,49 @@
desc = "Hope no one else dies, prepare for when they do."
actions_types = null
+ allow_multiple = TRUE
+
+ implant_info = "Requires configuration before implanting. Automatically activates upon implantation. \
+ Notifies the host of deaths that occur in other deathrattle implant hosts linked to the same deathrattle group."
+
+ implant_lore = "The Robust Corp Fatality Notification System, colloquially the \"deathrattle\" implant, \
+ is a subcutaneous hybrid vitals tracker and encrypted transmitter, \
+ designed to communicate with other FNS units implanted within other hosts. Upon detecting a lack of vital signs, \
+ the FNS will relay the fatality and its rough estimated location to the other hosts. How it can communicate \
+ over such long distances is a trade secret that both Nanotrasen and the Syndicate are quite curious about."
+
+ /// What deathrattle group type do we create? Group types dictate area whitelisting/blacklisting.
+ var/deathrattle_group_type = /datum/deathrattle_group/standard
+
+ /// Associated deathrattle group, for future configuration.
+ var/datum/deathrattle_group/current_group
/obj/item/implant/deathrattle/can_be_implanted_in(mob/living/target)
+ if(!current_group)
+ balloon_alert(target, "deathrattle needs configuration!")
+ return FALSE
// Can be implanted in anything that's a mob. Syndicate cyborgs, talking fish, humans...
return TRUE
+/obj/item/implant/deathrattle/lavaland
+ name = "expeditionary deathrattle implant"
+
+ deathrattle_group_type = /datum/deathrattle_group/lavaland
+
+ implant_info = "ONLY TRIGGERS ON NON-STATION DEATHS. \
+ Requires configuration before implanting. Automatically activates upon implantation. \
+ Notifies the host of deaths that occur in other deathrattle implant hosts linked to the same deathrattle group."
+
/obj/item/implantcase/deathrattle
name = "implant case - 'Deathrattle'"
desc = "A glass case containing a deathrattle implant."
imp_type = /obj/item/implant/deathrattle
+
+/obj/item/implantcase/deathrattle/lavaland
+ name = "implant case - 'Expeditionary Deathrattle'"
+ desc = "A glass case containing an expeditionary deathrattle implant. Only alerts to deaths that occur on Lavaland."
+ imp_type = /obj/item/implant/deathrattle/lavaland
+
+#undef DEATHRATTLE_AREA_NOLIST
+#undef DEATHRATTLE_AREA_BLACKLIST
+#undef DEATHRATTLE_AREA_WHITELIST
diff --git a/code/game/objects/items/implants/implant_explosive.dm b/code/game/objects/items/implants/implant_explosive.dm
index 832eca03a78..0a70215fa46 100644
--- a/code/game/objects/items/implants/implant_explosive.dm
+++ b/code/game/objects/items/implants/implant_explosive.dm
@@ -40,6 +40,16 @@
///Do we tell people when they activated it?
var/announce_activation = TRUE
+ implant_info = "Activates upon death or encoded signal. Triggers an electrically-detonated microexplosive. \
+ Can sync with other microbombs to increase explosive yield, but this makes detonation non-instant."
+
+ implant_lore = "The Robust Corp RX-78 Employee Management Implant is an electrically-detonated microexplosive, \
+ designed to motivate employees (for organizations with questionable ethics) and/or prevent recovery of \
+ equipment and/or evidence (for non-state actors). \
+ The microexplosive arms upon cessation of vital signs or manual activation. \
+ Upon arming, attempts to sync with any other detected microexplosives for increased detonation yield; \
+ the handshake process between microbombs, however, takes a bit, and only gets longer as more microbombs are detected."
+
/obj/item/implant/explosive/proc/on_death(datum/source, gibbed)
SIGNAL_HANDLER
@@ -49,16 +59,6 @@
// uses sleeps, which is bad for signal handlers to do.
INVOKE_ASYNC(src, PROC_REF(activate), "death")
-/obj/item/implant/explosive/get_data()
- return "Implant Specifications: \
- Name: Robust Corp RX-78 Employee Management Implant \
- Life: Activates upon death. \
- Important Notes: Explodes \
- \
- Implant Details: \
- Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death. \
- Special Features: Explodes "
-
/obj/item/implant/explosive/activate(cause)
. = ..()
if(!cause || !imp_in || active)
@@ -182,6 +182,12 @@
explosion_light = 10 * MICROBOMB_EXPLOSION_LIGHT
explosion_heavy = 10 * MICROBOMB_EXPLOSION_HEAVY
explosion_devastate = 10 * MICROBOMB_EXPLOSION_DEVASTATE
+ implant_lore = "The Robust Corp RX-78/M Employee Management Implant is an electrically-detonated explosive, \
+ designed to maximize the prevention of recovery of equipment and/or evidence by virtue of being ten microbombs all connected to one implant. \
+ Unfortunately, the handshake sequence between microbombs remains an issue. \
+ The microexplosives arm upon cessation of vital signs or manual activation. \
+ Upon arming, attempts to sync with any other detected microexplosives for increased detonation yield; \
+ the handshake process between microbombs, however, takes a bit, and only gets longer as more microbombs are detected."
///Microbomb which prevents you from going into critical condition but also explodes after a timer when you reach critical condition in the first place.
/obj/item/implant/explosive/deniability
@@ -192,6 +198,18 @@
no_paralyze = TRUE
master_implant = TRUE
+ implant_info = parent_type::implant_info + "While implanted, prevents unconsciousness from excessive trauma. \
+ Does not prevent death from excessive trauma, nor being stunned. \
+ Also delays detonation of other implanted microbombs by ten seconds."
+
+ implant_lore = "The Robust Corp RX-78/T Tactical Deniability Implant is an electrically-detonated microexplosive and \
+ paired neural override lattice, designed to prevent recovery of equipment and/or evidence for non-state actors, \
+ and prevent the reception of pain signals upon excessive trauma (colloquially, \"entering critical condition\"). \
+ The microexplosive arms upon cessation of vital signs or manual activation. \
+ Upon arming, attempts to sync with any other detected microexplosives for increased detonation yield; \
+ the handshake process between microbombs, however, takes a bit, and only gets longer as more microbombs are detected. \
+ The tactical deniability implant introduces a ten-second delay by itself in order to allow operators one last hurrah before death."
+
/obj/item/implant/explosive/deniability/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE)
. = ..()
if(.)
diff --git a/code/game/objects/items/implants/implant_freedom.dm b/code/game/objects/items/implants/implant_freedom.dm
index 827cc8216a5..4d7cff4211c 100644
--- a/code/game/objects/items/implants/implant_freedom.dm
+++ b/code/game/objects/items/implants/implant_freedom.dm
@@ -5,6 +5,15 @@
implant_color = "r"
uses = FREEDOM_IMPLANT_CHARGES
+ implant_info = "Activated manually. \
+ Unlocks bindings on arms and legs when activated, but not larger ones e.g. straightjackets."
+
+ implant_lore = "The CSMD Freedom Beacon is a hybrid signal transmitter and specialized nanite manufactory \
+ designed to defeat handcuffs, legcuffs, and other equivalent arm and leg bindings by both transmitting \
+ unlock signals for electrical cuff lock systems and, in the event of failure, generating thin nanite tendrils \
+ to nondestructively unsecure relevant bindings. Unfortunately, this only works for bindings on the arms and legs; \
+ larger restraints, such as straightjackets are too complex for the nanites to deal with."
+
/obj/item/implant/freedom/implant(mob/living/target, mob/user, silent, force)
. = ..()
if(!.)
@@ -42,16 +51,6 @@
return FALSE
-/obj/item/implant/freedom/get_data()
- return "Implant Specifications: \
- Name: Freedom Beacon \
- Life: Optimum [initial(uses)] uses \
- Important Notes: Illegal \
- \
- Implant Details: \
- Function: Transmits a specialized cluster of signals to override handcuff locking \
- mechanisms. These signals will release any bindings on both the arms and legs. \
- Disclaimer: Heavy-duty restraints such as straightjackets are deemed \"too complex\" to release from."
/obj/item/implanter/freedom
name = "implanter (freedom)"
diff --git a/code/game/objects/items/implants/implant_kaza_ruk.dm b/code/game/objects/items/implants/implant_kaza_ruk.dm
index ce26fb1b678..dced80f46b1 100644
--- a/code/game/objects/items/implants/implant_kaza_ruk.dm
+++ b/code/game/objects/items/implants/implant_kaza_ruk.dm
@@ -6,13 +6,11 @@
/// The martial art style this implant teaches.
var/datum/martial_art/kaza_ruk/style
-/obj/item/implant/kaza_ruk/get_data()
- var/dat = {"Implant Specifications:
- Name: Kaza Ruk Implant
- Life: 4 hours after death of host
- Implant Details:
- Function: Teaches even the clumsiest host the arts of Kaza Ruk."}
- return dat
+ implant_info = "Automatically activates upon implantation. Teaches the Tiziran martial arts of Kaza Ruk."
+
+ implant_lore = "The Kaza Ruk Implant is an integrated training database consisting of five short instructional videos \
+ beamed directly into the eyeballs, capable of being replayed on demand in order to review the fundamentals of the Tiziran \
+ martial arts of Kaza Ruk, regardless of the host's previous martial arts skills or a distinct lack thereof."
/obj/item/implant/kaza_ruk/Initialize(mapload)
. = ..()
diff --git a/code/game/objects/items/implants/implant_mindshield.dm b/code/game/objects/items/implants/implant_mindshield.dm
index 9f7e507f1c3..331912df825 100644
--- a/code/game/objects/items/implants/implant_mindshield.dm
+++ b/code/game/objects/items/implants/implant_mindshield.dm
@@ -3,17 +3,11 @@
desc = "Protects against brainwashing."
actions_types = null
-/obj/item/implant/mindshield/get_data()
- return "Implant Specifications: \
- Name: Nanotrasen Employee Management Implant \
- Life: Ten years. \
- Important Notes: Personnel injected with this device are much more resistant to brainwashing. \
- \
- Implant Details: \
- Function: Contains a small pod of nanobots that protects the host's mental functions from manipulation. \
- Special Features: Will prevent and cure most forms of brainwashing. \
- Integrity: Implant will last so long as the nanobots are inside the bloodstream."
+ implant_info = "Automatically activates upon implantation. Provides protection against brainwashing."
+ implant_lore = "The Nanotrasen Employee Management Implant is a specialized subdermal nanite manufactory that \
+ both protects the host's mental faculties from, and reverses, external forms of manipulation, \
+ such as reprogrammed flashbulbs, hypnotic suggestion, and, theoretically, magical induction into cults."
/obj/item/implant/mindshield/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE)
. = ..()
diff --git a/code/game/objects/items/implants/implant_misc.dm b/code/game/objects/items/implants/implant_misc.dm
index 6e053a1a44b..393df069ffe 100644
--- a/code/game/objects/items/implants/implant_misc.dm
+++ b/code/game/objects/items/implants/implant_misc.dm
@@ -4,12 +4,15 @@
icon_state = "auth"
actions_types = null
-/obj/item/implant/weapons_auth/get_data()
- return "Implant Specifications: \
- Name: Firearms Authentication Implant \
- Life: 4 hours after death of host \
- Implant Details: \
- Function: Allows operation of implant-locked weaponry, preventing equipment from falling into enemy hands."
+ implant_info = "Automatically activates upon implantation. Provides authentication for weapons with \
+ appropriate security systems, typically in the firing pin."
+
+ implant_lore = "The Cybersun Equipment Authentication Implant is a subdermal RFID authentication module \
+ and paired transmitter, designed to interface with equipment that has appropriate security systems, \
+ such as implant-locked firing pins popular with associated covert operatives and non-state actors. \
+ Equipment with such authentication systems is noteworthy for inconveniencing those trying to \
+ pilfer equipment from fallen enemies' hands, preventing their equipment from easily being used. \
+ However, it should be noted that the weakest link in a digital authentication scheme is oftentimes the physical layer."
/obj/item/implant/emp
name = "\improper EMP implant"
@@ -17,6 +20,14 @@
icon_state = "emp"
uses = 3
+ implant_info = "Activated manually. Generates an indiscriminate electromagnetic pulse of moderate size when triggered."
+
+ implant_lore = "The Cybersun Subdermal Electromagnetic Pulse Generator is, true to its name, \
+ a subdermal implant designed to generate indiscriminate electromagnetic pulses when triggered, \
+ disrupting electronic equipment, such as energy weaponry, and lifeforms, \
+ such as stationbound silicon units, within the user's radius. \
+ Prospective users are reminded that the S-EPG does not protect the host from their own electromagnetic pulses."
+
/obj/item/implant/emp/activate()
. = ..()
uses--
@@ -34,6 +45,14 @@
icon_state = "smoke"
uses = 3
+ implant_info = "Activated manually. Generates an indiscriminate cloud of smoke of moderate size when triggered."
+
+ implant_lore = "The Cybersun Subdermal Visual Obstruction Generator is, true to its name, \
+ a subdermal implant designed to generate visual obstructions in the form of smoke clouds when triggered, \
+ disrupting lines of sight to the user. \
+ Prospective users are reminded that the S-VOG does not protect the host particularly well from \
+ thermal imaging, nor does it actually stop blind fire into the smoke, nor does it stop movement."
+
/obj/item/implant/smoke/activate()
. = ..()
uses--
@@ -55,6 +74,13 @@
icon = 'icons/obj/devices/voice.dmi'
icon_state = "walkietalkie"
+ implant_info = "Automatically activates upon implantation. Provides radio transmission and reception capabilities."
+
+ implant_lore = "The Internal Radio Implant, a long open-sourced design manufactured by \
+ just about everyone from Nanotrasen to Cybersun, is a subdermal two-way radio system designed \
+ to interface with telecommunications networks. It's mainly useful for those who expect either \
+ equipment loss or lack the ability to use standalone radio equipment easily."
+
/obj/item/implant/radio/activate()
. = ..()
// needs to be GLOB.deep_inventory_state otherwise it won't open
@@ -92,12 +118,6 @@
radio_key = /obj/item/encryptionkey/headset_sci
subspace_transmission = TRUE
-/obj/item/implant/radio/get_data()
- return "Implant Specifications: \
- Name: Internal Radio Implant \
- Life: 24 hours \
- Implant Details: Allows user to use an internal radio, useful if user expects equipment loss, or cannot equip conventional radios."
-
/obj/item/implanter/radio
name = "implanter (internal radio)"
imp_type = /obj/item/implant/radio
diff --git a/code/game/objects/items/implants/implant_spell.dm b/code/game/objects/items/implants/implant_spell.dm
index a758cb72ac0..fefd2810286 100644
--- a/code/game/objects/items/implants/implant_spell.dm
+++ b/code/game/objects/items/implants/implant_spell.dm
@@ -10,6 +10,16 @@
/// The actual spell we give to the person on implant
var/datum/action/cooldown/spell/spell_to_give
+ implant_info = "Automatically activates upon implantation. If not inert, theoretically provides spellcasting ability. \
+ Unfortunately, is inert."
+
+ implant_lore = "The Thaumic Accumulation/Instruction Matrix is an exotic thaumic accumulator designed for \
+ subdermal implantation, and meant to provide an interface between magic spells \
+ like those used by the Wizard's Federation, which have notoriously been uncooperative with technology, \
+ and mundane users who lack innate magical aptitude. Very little is known about how it works, especially \
+ because thaumic matrices, especially those designed for cross-disciplinary interaction, are hard to recover \
+ intact."
+
/obj/item/implant/spell/Initialize(mapload)
. = ..()
if(!spell_type)
@@ -20,17 +30,13 @@
if(make_robeless && (spell_to_give.spell_requirements & SPELL_REQUIRES_WIZARD_GARB))
spell_to_give.spell_requirements &= ~SPELL_REQUIRES_WIZARD_GARB
+ implant_info = "Automatically activates upon implantation. Allows an implantee to cast [spell_to_give], \
+ [make_robeless ? ", without needing appropriate wizard garb" : " if dressed in appropriate garb"]."
+
/obj/item/implant/spell/Destroy()
QDEL_NULL(spell_to_give)
return ..()
-/obj/item/implant/spell/get_data()
- return "Implant Specifications: \
- Name: Spell Implant \
- Life: 4 hours after death of host \
- Implant Details: \
- Function: [spell_to_give ? "Allows a non-wizard to cast [spell_to_give] as if they were a wizard." : "None."]"
-
/obj/item/implant/spell/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE)
. = ..()
if (!.)
diff --git a/code/game/objects/items/implants/implant_stealth.dm b/code/game/objects/items/implants/implant_stealth.dm
index f8377a11a32..beb907a706b 100644
--- a/code/game/objects/items/implants/implant_stealth.dm
+++ b/code/game/objects/items/implants/implant_stealth.dm
@@ -3,6 +3,15 @@
desc = "Allows you to be hidden in plain sight."
actions_types = list(/datum/action/item_action/agent_box)
+ implant_info = "Activated manually. \
+ Fabricates a horrifically fragile cardboard box around the user that has integrated gradual optical camouflage."
+
+ implant_lore = "The Cybersun S3 Implant, colloquially the \"stealth\" implant, allows users to fabricate, \
+ on the spot, a \"stealth\" box around them, which sacrifices most of its (miniscule) strength as a cardboard box \
+ in order to support an optical camouflage weave. Unfortunately, the optical camouflage cannot instantly initialize; \
+ bumping into living beings will disrupt the camouflage, and after disruption or upon initial activation, \
+ the camouflage system has to recalibrate to its surroundings. However, once calibrated, it is invisible to the naked eye."
+
/obj/item/implanter/stealth
name = "implanter (stealth)"
imp_type = /obj/item/implant/stealth
diff --git a/code/game/objects/items/implants/implantpad.dm b/code/game/objects/items/implants/implantpad.dm
index 94f4a68f998..094e8d51676 100644
--- a/code/game/objects/items/implants/implantpad.dm
+++ b/code/game/objects/items/implants/implantpad.dm
@@ -15,6 +15,9 @@
///The implant case currently inserted into the pad.
var/obj/item/implantcase/inserted_case
+ /// The deathrattle group currently saved to the implantpad.
+ var/datum/deathrattle_group/saved_deathrattle_group
+
/obj/item/implantpad/update_icon_state()
icon_state = "[base_icon_state]-[!isnull(inserted_case)]"
return ..()
@@ -57,14 +60,21 @@
ui = new(user, src, "ImplantPad", name)
ui.open()
-/obj/item/implantpad/ui_static_data(mob/user)
+/obj/item/implantpad/ui_data(mob/user)
var/list/data = list()
+ data["saved_deathrattle_group"] = saved_deathrattle_group ? saved_deathrattle_group.name : null
+ data["current_deathrattle_group"] = null
data["has_case"] = !!inserted_case
if(!inserted_case)
return data
data["has_implant"] = !!inserted_case.imp
if(inserted_case.imp)
data["case_information"] = inserted_case.imp.get_data()
+ data["case_lore"] = inserted_case.imp.get_lore()
+ if(istype(inserted_case.imp, /obj/item/implant/deathrattle))
+ var/obj/item/implant/deathrattle/inserted_deathrattle = inserted_case.imp
+ if(inserted_deathrattle.current_group)
+ data["current_deathrattle_group"] = inserted_deathrattle.current_group
return data
/obj/item/implantpad/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
@@ -73,6 +83,12 @@
if(action == "eject_implant")
remove_implant(user)
return
+ if(action == "save_deathrattle_group")
+ save_deathrattle_group(user)
+ if(action == "set_deathrattle_group")
+ set_deathrattle_group(user)
+ if(action == "init_deathrattle_group")
+ init_deathrattle_group(user)
///Removes the implant from the pad and puts it in the user's hands if possible.
/obj/item/implantpad/proc/remove_implant(mob/user)
@@ -86,3 +102,63 @@
update_appearance(UPDATE_ICON)
update_static_data_for_all_viewers()
return TRUE
+
+/// Saves the currently inserted implant's deathrattle group.
+/obj/item/implantpad/proc/save_deathrattle_group(mob/user)
+ if(!inserted_case)
+ user.balloon_alert(user, "no case inside!")
+ return FALSE
+ if(!istype(inserted_case.imp, /obj/item/implant/deathrattle))
+ user.balloon_alert(user, "incompatible implant!")
+ return FALSE
+ var/obj/item/implant/deathrattle/inserted_implant = inserted_case.imp
+ var/datum/deathrattle_group/current_group = inserted_implant.current_group
+ if(!current_group)
+ user.balloon_alert(user, "no active group!")
+ return FALSE
+ saved_deathrattle_group = current_group
+ user.balloon_alert(user, "saved group [current_group.name]")
+ update_static_data_for_all_viewers()
+ return TRUE
+
+/// Sets the currently inserted implant's deathrattle group to saved.
+/obj/item/implantpad/proc/set_deathrattle_group(mob/user)
+ if(!inserted_case)
+ user.balloon_alert(user, "no case inside!")
+ return FALSE
+ if(!saved_deathrattle_group)
+ user.balloon_alert(user, "no saved deathrattle group!")
+ return FALSE
+ if(!istype(inserted_case.imp, /obj/item/implant/deathrattle))
+ user.balloon_alert(user, "incompatible implant!")
+ return FALSE
+ var/obj/item/implant/deathrattle/inserted_implant = inserted_case.imp
+ if(!istype(saved_deathrattle_group, inserted_implant.deathrattle_group_type))
+ user.balloon_alert(user, "incompatible deathrattle group!")
+ return FALSE
+ saved_deathrattle_group.register(inserted_implant)
+ user.balloon_alert(user, "registered to group [saved_deathrattle_group.name]")
+ inserted_case.name = "[initial(inserted_case.name)] - [saved_deathrattle_group.name]"
+ update_static_data_for_all_viewers()
+ return TRUE
+
+/// Initializes and saves a new deathrattle group, then registers the current implant to it.
+/obj/item/implantpad/proc/init_deathrattle_group(mob/user)
+ if(!inserted_case)
+ user.balloon_alert(user, "no case inside!")
+ return FALSE
+ if(!istype(inserted_case.imp, /obj/item/implant/deathrattle))
+ user.balloon_alert(user, "incompatible implant!")
+ return FALSE
+ var/obj/item/implant/deathrattle/inserted_implant = inserted_case.imp
+ if(inserted_implant.current_group)
+ user.balloon_alert(user, "group already set!")
+ return FALSE
+ // init and save new group
+ saved_deathrattle_group = new inserted_implant.deathrattle_group_type
+ // register current implant
+ saved_deathrattle_group.register(inserted_implant)
+ user.balloon_alert(user, "registered to new group [saved_deathrattle_group.name]")
+ inserted_case.name += " - [saved_deathrattle_group.name]"
+ update_static_data_for_all_viewers()
+ return TRUE
diff --git a/code/game/objects/items/implants/security/implant_beacon.dm b/code/game/objects/items/implants/security/implant_beacon.dm
index e6b3e3571c7..95840516bee 100644
--- a/code/game/objects/items/implants/security/implant_beacon.dm
+++ b/code/game/objects/items/implants/security/implant_beacon.dm
@@ -8,17 +8,17 @@
///How long will the implant be teleportable to after death?
var/lifespan_postmortem = 10 MINUTES
-/obj/item/implant/beacon/get_data()
- return "Implant Specifications: \
- Name: Robust Corp JMP-21 Fugitive Retrieval Implant \
- Life: Deactivates upon death after ten minutes, but remains within the body. \
- Important Notes: N/A \
- \
- Implant Details: \
- Function: Acts as a teleportation beacon that can be tracked by any standard bluespace transponder. \
- Using this, you can teleport directly to whoever has this implant inside of them."
+ implant_info = "Automatically activates upon implantation. Acts as a dedicated, teleport-only bluespace beacon. \
+ Deactivates ten minutes after host's death, but remains within the body."
+
+ implant_lore = "The Robust Corp JMP-21 Fugitive Retrieval Implant is a subdermal bluespace transponder \
+ designed for interfacing with common bluespace teleporting technology and serving as a beacon that can \
+ be teleported directly onto. Unfortunately, it only serves as a beacon-transponder that can be locked onto, \
+ providing no tracking functionality. Automatically deactivates ten minutes after the host's death."
/obj/item/implant/beacon/is_shown_on_console(obj/machinery/computer/prisoner/management/console)
+ if(imp_in.stat == DEAD && imp_in.timeofdeath + lifespan_postmortem < world.time)
+ return FALSE
return TRUE
/obj/item/implant/beacon/get_management_console_data()
diff --git a/code/game/objects/items/implants/security/implant_chem.dm b/code/game/objects/items/implants/security/implant_chem.dm
index d957100ce70..426604daf11 100644
--- a/code/game/objects/items/implants/security/implant_chem.dm
+++ b/code/game/objects/items/implants/security/implant_chem.dm
@@ -8,18 +8,15 @@
/// All possible injection sizes for the implant shown in the prisoner management console.
var/list/implant_sizes = list(1, 5, 10)
-/obj/item/implant/chem/get_data()
- return "Implant Specifications: \
- Name: Robust Corp MJ-420 Prisoner Management Implant \
- Life: Deactivates upon death but remains within the body. \
- Important Notes: Due to the system functioning off of nutrients in the implanted subject's body, the subject \
- will suffer from an increased appetite. \
- Implant Details: \
- Function: Contains a small capsule that can contain various chemicals. Upon receiving a specially encoded signal \
- the implant releases the chemicals directly into the blood stream. \
- Micro-Capsule- Can be loaded with any sort of chemical agent via the common syringe and can hold 50 units. \
- Can only be loaded while still in its original case. \
- Integrity: Implant will last so long as the subject is alive, breaking down and releasing all contents on death."
+ implant_info = "Requires filling via syringe while in an implant case. Automatically activates upon implantation. \
+ Allows for remote release of reagents directly into implantee's bloodstream."
+
+ implant_lore = "The Robust Corp MJ-420 Remote Chemical Release Implant is a remotely-controlled \
+ microcapsule network designed to be filled via syringe while still within an implant case. After implantation, \
+ the MJ-420 can be accessed via prisoner management console to release controlled amounts of reagents directly \
+ into the implantee's bloodstream, which is useful for controlled release of sedatives, antipsychotics, or, for \
+ particularly dangerous prisoners, lethal injections. Upon implantee's death, breaks down and releases all reagents \
+ into their bloodstream."
/obj/item/implant/chem/is_shown_on_console(obj/machinery/computer/prisoner/management/console)
return is_valid_z_level(get_turf(console), get_turf(imp_in))
diff --git a/code/game/objects/items/implants/security/implant_exile.dm b/code/game/objects/items/implants/security/implant_exile.dm
index 9c04f1f9d37..588c8a17b45 100644
--- a/code/game/objects/items/implants/security/implant_exile.dm
+++ b/code/game/objects/items/implants/security/implant_exile.dm
@@ -8,22 +8,32 @@
implant_flags = IMPLANT_TYPE_SECURITY
hud_icon_state = "hud_imp_exile"
-/obj/item/implant/exile/get_data()
- return "Implant Specifications: \
- Name: Nanotrasen Employee Exile Implant \
- Implant Details: The onboard gateway system has been modified to reject entry by individuals containing this implant. \
- Additionally, station mining shuttles will lock their controls if handled by someone with this implant. "
+ implant_info = "Automatically activates upon implantation. \
+ Prevents returning through Nanotrasen gateway systems, and prevents usage of Nanotrasen mining shuttle controls."
+ implant_lore = "The Nanotrasen Employee Exile Implant is an RFID transponder \
+ designed to facilitate one-way traversal through Nanotrasen Gateway Project gateways. \
+ It allows implantees to enter, but not exit, gateway locales, automatically rejecting traversal attempts if an attempt is made, \
+ effectively exiling them to the gateway's locale. \
+ Alongside this, the exile implant interfaces with Nanotrasen mining shuttle control systems, automatically locking \
+ themselves down if implantees attempt to use them."
///Used to help the staff of the space hotel resist the urge to use the space hotel's incredibly alluring roundstart teleporter to ignore their flavor/greeting text and come to the station.
/obj/item/implant/exile/noteleport
name = "anti-teleportation implant"
- desc = "Uses impressive bluespace grounding techniques to deny the person implanted by this implant the ability to teleport (or be teleported). Used by certain slavers (or particularly strict employers) to keep their slaves from using teleporters to escape their grasp."
+ desc = "Uses impressive bluespace grounding techniques to deny the person implanted by this implant the ability to teleport or be teleported. \
+ Used by certain slavers, or particularly strict employers, to keep their slaves or employees from using teleporters to escape their grasp."
-/obj/item/implant/exile/noteleport/get_data()
- return "Implant Specifications: \
- Name: Anti-Teleportation Implant \
- Implant Details: Keeps the implantee from using most teleportation devices. In addition, it spoofs the implant signature of an exile implant to keep the implantee from using certain gateway systems. "
+ implant_info = "Automatically activates upon implantation. \
+ Mimics an exile implant, preventing returning from a gateway locale and locking down Nanotrasen mining shuttles, \
+ while also preventing teleportation."
+
+ implant_lore = "The Sunken Anchor anti-teleportation implant is a subdermal anti-teleportation device that prevents usage of \
+ conventional and unconventional methods of teleporting, in order to prevent employees \
+ or slaves from using unauthorized means of teleportation to abandon their posts. \
+ In addition, the Sunken Anchor mimics the signature of Nanotrasen's exile implant, \
+ preventing returning through Nanotrasen Gateway Project gateways and locking implantees out of using Nanotrasen's mining shuttles. \
+ The ethics behind having this implant are questionable. The efficacy of the implant itself is not."
/obj/item/implant/exile/noteleport/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE)
. = ..()
diff --git a/code/game/objects/items/implants/security/implant_noteleport.dm b/code/game/objects/items/implants/security/implant_noteleport.dm
index a246738608e..36fd56aa1d4 100644
--- a/code/game/objects/items/implants/security/implant_noteleport.dm
+++ b/code/game/objects/items/implants/security/implant_noteleport.dm
@@ -6,11 +6,16 @@
implant_flags = IMPLANT_TYPE_SECURITY
hud_icon_state = "hud_imp_noteleport"
-/obj/item/implant/teleport_blocker/get_data()
- return "Implant Specifications: \
- Name: Robust Corp EXP-001 'Bluespace Grounder' \
- Implant Details: Upon implantation, grounds the user's bluespace signature to their currently occupied plane of existence. \
- Most, if not all forms of teleportation on the implantee will be rendered ineffective. Useful for keeping especially slippery prisoners in place. "
+ implant_info = "Automatically activates upon implantation. \
+ Grounds users' bluespace signatures, preventing jaunting and/or teleportation."
+
+ implant_lore = "The Robust Corp BG-001-EXP is a subcutaneous, experimental bluespace counter-resonance \
+ frequency generator, designed to firmly ground an implantee's bluespace signature in baseline reality. \
+ In layman's terms, it counteracts attempts to slip into bluespace or similar gaps in reality, \
+ generating a dissonant frequency that interferes with the attempt, resulting in temporary paralysis. \
+ Test subjects report that the interference feels like slamming into a wall, with none of the \
+ physical trauma of actually slamming into a wall. Preliminary reports indicate that this \
+ would likely be useful for keeping especially slippery prisoners in place."
/obj/item/implant/teleport_blocker/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE)
. = ..()
diff --git a/code/game/objects/items/implants/security/implant_track.dm b/code/game/objects/items/implants/security/implant_track.dm
index 9b8050d7dad..17fa6c4cef8 100644
--- a/code/game/objects/items/implants/security/implant_track.dm
+++ b/code/game/objects/items/implants/security/implant_track.dm
@@ -8,17 +8,15 @@
///How long will the implant continue to function after death?
var/lifespan_postmortem = 10 MINUTES
-/obj/item/implant/tracking/get_data()
- return "Implant Specifications: \
- Name: Robust Corp EYE-5 Convict Parole Implant \
- Life: 10 minutes after death of host. \
- \
- Implant Details: \
- Function: Continuously transmits low power signal. Can be tracked from a prisoner management console. \
- Special Features: \
- Neuro-Safe- Specialized shell absorbs excess voltages self-destructing the chip if \
- a malfunction occurs thereby securing safety of subject. The implant will melt and \
- disintegrate into bio-safe elements. "
+ implant_info = "Automatically activates upon implantation. Acts as a dedicated, tracking-only beacon \
+ and direct-to-brain prisoner messaging system. \
+ Deactivates ten minutes after host's death, but remains within the body."
+
+ implant_lore = "The Robust Corp EYE-5 Convict Parole Monitoring Implant is a subdermal tracking beacon \
+ designed for interfacing with prisoner management equipment, serving as both a beacon that can \
+ be tracked via locator equipment, and a provider of one-way communication from prisoner management staff \
+ to implanted subjects, relaying messages directly to subjects' brains. \
+ Automatically deactivates ten minutes after the host's death."
/obj/item/implant/tracking/is_shown_on_console(obj/machinery/computer/prisoner/management/console)
if(imp_in.stat == DEAD && imp_in.timeofdeath + lifespan_postmortem < world.time)
@@ -67,6 +65,18 @@
///The id of the timer that's qdeleting us
var/timerid
+ implant_info = "Automatically activates upon implantation, typically via firearm. \
+ Acts as a dedicated, tracking-only beacon and direct-to-brain prisoner messaging system. \
+ Dissolves into absorbable elements after 5 minutes."
+
+ implant_lore = "The Robust Corp EYE-5/TRAC Fugitive Monitoring Implant is a subdermal tracking beacon \
+ designed to be delivered via high-velocity projectile. \
+ Much like the original EYE-5 Convict Parole Monitoring Implant, \
+ interfaces with prisoner management equipment, serving as both a beacon that can \
+ be tracked via locator equipment, and a provider of one-way communication from prisoner management staff \
+ to implanted targets, relaying messages directly to targets' brains. \
+ Dissolves into bio-safe elements after five minutes."
+
/obj/item/implant/tracking/c38/implant(mob/living/target, mob/user, silent, force)
. = ..()
timerid = QDEL_IN_STOPPABLE(src, lifespan)
diff --git a/code/game/objects/items/storage/boxes/implant_boxes.dm b/code/game/objects/items/storage/boxes/implant_boxes.dm
index b3f1db2e457..56bfaf53384 100644
--- a/code/game/objects/items/storage/boxes/implant_boxes.dm
+++ b/code/game/objects/items/storage/boxes/implant_boxes.dm
@@ -28,6 +28,20 @@
)
generate_items_inside(items_inside,src)
+/obj/item/storage/box/minerdeathrattle
+ name = "boxed expeditionary deathrattle implant kit"
+ desc = "For realizing that your coworkers are dead instead of actively ignoring comms. Requires manual setup. \
+ Only works for deaths in raw Lavaland or Icemoon wastelands."
+ illustration = "implant"
+
+/obj/item/storage/box/minerdeathrattle/PopulateContents()
+ var/static/items_inside = list(
+ /obj/item/implantcase/deathrattle/lavaland = 5, // 3 miners 1 QM/paramed/etc, 1 for saving config, presumably
+ /obj/item/implanter = 1,
+ /obj/item/implantpad = 1,
+ )
+ generate_items_inside(items_inside,src)
+
/obj/item/storage/box/chemimp
name = "boxed chemical implant kit"
desc = "Box of stuff used to implant chemicals."
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index c42e33b9a68..f25006bd992 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -706,7 +706,7 @@
/obj/item/storage/box/syndie_kit/imp_deathrattle/PopulateContents()
new /obj/item/implanter(src)
- var/datum/deathrattle_group/group = new
+ var/datum/deathrattle_group/standard/group = new
var/implants = list()
for(var/j in 1 to 8)
@@ -773,13 +773,6 @@
desc = "Registers you as a member of a Syndicate nuclear operative team."
implant_color = "r"
-/obj/item/implant/nuclear_operative/get_data()
- return "Implant Specifications: \
- Name: Suspicious Implant \
- Life: UNKNOWN \
- Implant Details: \
- Function: Strange implant that seems to resist any attempts at scanning it."
-
/obj/item/implant/nuclear_operative/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE)
. = ..()
if(!. || !ishuman(target) || !(target.mind))
diff --git a/code/modules/clothing/under/accessories/_accessories.dm b/code/modules/clothing/under/accessories/_accessories.dm
index 993771e4888..00a2e39834b 100644
--- a/code/modules/clothing/under/accessories/_accessories.dm
+++ b/code/modules/clothing/under/accessories/_accessories.dm
@@ -19,6 +19,8 @@
slot_flags = NONE
w_class = WEIGHT_CLASS_SMALL
item_flags = NOBLUDGEON
+ /// Whether the icon_state is also the worn_icon_state. If false, don't forget to set worn_icon_state.
+ var/icon_state_is_worn = TRUE
/// Whether or not the accessory displays through suits and the like.
var/above_suit = TRUE
/// TRUE if shown as a small icon in corner, FALSE if overlayed
@@ -119,7 +121,8 @@
/obj/item/clothing/accessory/proc/generate_accessory_overlay(obj/item/clothing/under/attached_to)
SHOULD_CALL_PARENT(TRUE)
- var/mutable_appearance/appearance = mutable_appearance(worn_icon, icon_state)
+ var/mutable_appearance/appearance = mutable_appearance(worn_icon, (icon_state_is_worn ? icon_state : worn_icon_state))
+ appearance.overlays += worn_overlays(appearance, FALSE, worn_icon) // we're assuming it's being worn.
appearance.alpha = alpha
appearance.color = color
return appearance
diff --git a/code/modules/mining/equipment/kheiral_cuffs.dm b/code/modules/mining/equipment/kheiral_cuffs.dm
index 65feee0f1e5..79264731c88 100644
--- a/code/modules/mining/equipment/kheiral_cuffs.dm
+++ b/code/modules/mining/equipment/kheiral_cuffs.dm
@@ -1,10 +1,12 @@
/**********************Kheiral Cuffs**********************/
/// Acts as a GPS beacon & connects to station crew monitors from lavaland
-/obj/item/kheiral_cuffs
+/obj/item/clothing/accessory/kheiral_cuffs
name = "\improper Kheiral cuffs"
- desc = "A prototype wrist communicator powered by Kheiral Matter. When both ends are clamped to one wrist, acts as a signal range booster for your suit sensors.\nA small engraving on the inside reads, \"NOT HANDCUFFS\""
+ desc = "A prototype wrist communicator powered by Kheiral Matter. When both ends are clamped to one wrist, acts as a signal range booster for your suit sensors.\n\
+ A small engraving on the inside reads, \"NOT HANDCUFFS\"."
icon = 'icons/obj/mining.dmi'
icon_state = "strand"
+ worn_icon = 'icons/mob/clothing/hands.dmi'
worn_icon_state = "strandcuff"
slot_flags = ITEM_SLOT_GLOVES
throwforce = 0
@@ -15,6 +17,8 @@
attack_verb_continuous = list("connects")
attack_verb_simple = list("connect")
resistance_flags = FIRE_PROOF
+ attachment_slot = NONE // fits as accessory as long as there's an undersuit
+ icon_state_is_worn = FALSE
/// If we're in the glove slot
var/on_wrist = FALSE
/// If the GPS is already on
@@ -22,27 +26,27 @@
/// If we're off the station's Z-level
var/far_from_home = FALSE
-/obj/item/kheiral_cuffs/Initialize(mapload)
+/obj/item/clothing/accessory/kheiral_cuffs/Initialize(mapload)
. = ..()
update_icon(UPDATE_OVERLAYS)
RegisterSignal(src, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(check_z))
check_z(new_turf = loc)
-/obj/item/kheiral_cuffs/examine(mob/user)
+/obj/item/clothing/accessory/kheiral_cuffs/examine(mob/user)
. = ..()
if(gps_enabled)
. += span_notice("The cuff's GPS signal is on.")
-/obj/item/kheiral_cuffs/equipped(mob/user, slot, initial)
+/obj/item/clothing/accessory/kheiral_cuffs/equipped(mob/user, slot, initial)
. = ..()
- if(!(slot & ITEM_SLOT_GLOVES))
+ if(!(slot & ITEM_SLOT_GLOVES) && !(slot & ITEM_SLOT_ICLOTHING))
return
on_wrist = TRUE
playsound(loc, 'sound/items/weapons/handcuffs.ogg', 30, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
connect_kheiral_network(user)
-/obj/item/kheiral_cuffs/dropped(mob/user, silent)
+/obj/item/clothing/accessory/kheiral_cuffs/dropped(mob/user, silent)
. = ..()
if(on_wrist)
playsound(loc, 'sound/items/weapons/handcuffs.ogg', 30, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
@@ -50,7 +54,7 @@
remove_kheiral_network(user)
/// Enables the GPS and adds the multiz trait
-/obj/item/kheiral_cuffs/proc/connect_kheiral_network(mob/living/user)
+/obj/item/clothing/accessory/kheiral_cuffs/proc/connect_kheiral_network(mob/living/user)
if(gps_enabled)
return
if(!on_wrist || !far_from_home)
@@ -65,17 +69,17 @@
gps_enabled = TRUE
/// Disables the GPS and removes the multiz trait
-/obj/item/kheiral_cuffs/proc/remove_kheiral_network(mob/user)
+/obj/item/clothing/accessory/kheiral_cuffs/proc/remove_kheiral_network(mob/user)
if(!gps_enabled)
return
if(on_wrist && far_from_home)
return
- balloon_alert(user, "gps de-activated")
+ balloon_alert(user, "gps de-activated") // GPS component deletes itself when we get on-Z
REMOVE_TRAIT(user, TRAIT_MULTIZ_SUIT_SENSORS, REF(src))
gps_enabled = FALSE
/// If we're off the Z-level, set far_from_home = TRUE. If being worn, trigger kheiral_network proc
-/obj/item/kheiral_cuffs/proc/check_z(datum/source, turf/old_turf, turf/new_turf)
+/obj/item/clothing/accessory/kheiral_cuffs/proc/check_z(datum/source, turf/old_turf, turf/new_turf)
SIGNAL_HANDLER
if(!isturf(new_turf))
@@ -83,23 +87,29 @@
if(is_station_level(new_turf.z))
far_from_home = FALSE
+ // for the "worn on glove slot" case
if(isliving(loc))
remove_kheiral_network(loc)
+ else if(isliving(loc.loc)) // for the "worn as accessory" case
+ remove_kheiral_network(loc.loc)
else
far_from_home = TRUE
+ // for the "worn on glove slot" case
if(isliving(loc))
connect_kheiral_network(loc)
+ else if(isliving(loc.loc)) // for the "worn as accessory" case
+ connect_kheiral_network(loc.loc)
-/obj/item/kheiral_cuffs/worn_overlays(mutable_appearance/standing, isinhands, icon_file)
+/obj/item/clothing/accessory/kheiral_cuffs/worn_overlays(mutable_appearance/standing, isinhands, icon_file)
. = ..()
if(!isinhands)
. += emissive_appearance(icon_file, "strandcuff_emissive", src, alpha = src.alpha)
-/obj/item/kheiral_cuffs/update_overlays()
+/obj/item/clothing/accessory/kheiral_cuffs/update_overlays()
. = ..()
. += emissive_appearance(icon, "strand_light", src, alpha = src.alpha)
-/obj/item/kheiral_cuffs/suicide_act(mob/living/carbon/user)
+/obj/item/clothing/accessory/kheiral_cuffs/suicide_act(mob/living/carbon/user)
if(!ishuman(user))
return
diff --git a/code/modules/mod/modules/module_pathfinder.dm b/code/modules/mod/modules/module_pathfinder.dm
index 55263aa332d..657aa42b084 100644
--- a/code/modules/mod/modules/module_pathfinder.dm
+++ b/code/modules/mod/modules/module_pathfinder.dm
@@ -198,6 +198,11 @@
allow_multiple = TRUE // Surgrey is annoying if you loose your MOD
/// The pathfinder module we are linked to.
var/obj/item/mod/module/pathfinder/module
+ implant_info = "Activated manually. Allows for the recall of a Modular Outerwear Device by the implant owner at any time."
+ implant_lore = "Designed by Nakamura Industries, the MOD Pathfinder implant is the receiving end of the MOD pathfinder module, \
+ designed to be fabricated with its associated host module. It's designed to be implanted near the base of the spine: \
+ installing it anywhere else may result in the associated suit deploying incorrectly or failing to engage its airbrakes, \
+ which Nakamura Industries promises are actually present."
/obj/item/implant/mod/Initialize(mapload)
. = ..()
@@ -209,11 +214,6 @@
module = null
return ..()
-/obj/item/implant/mod/get_data()
- return "Implant Specifications: \
- Name: Nakamura Engineering Pathfinder Implant \
- Implant Details: Allows for the recall of a Modular Outerwear Device by the implant owner at any time. "
-
/datum/action/item_action/mod_recall
name = "Recall MOD"
desc = "Recall a MODsuit anyplace, anytime."
diff --git a/tgui/packages/tgui/interfaces/ImplantPad.tsx b/tgui/packages/tgui/interfaces/ImplantPad.tsx
index e36d745c766..de096e06766 100644
--- a/tgui/packages/tgui/interfaces/ImplantPad.tsx
+++ b/tgui/packages/tgui/interfaces/ImplantPad.tsx
@@ -1,30 +1,42 @@
-import { Box, Button, Divider, Flex } from 'tgui-core/components';
+import {
+ Button,
+ Collapsible,
+ Divider,
+ Section,
+ Stack,
+} from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import { useBackend } from '../backend';
import { Window } from '../layouts';
-import { sanitizeText } from '../sanitize';
type Data = {
has_case: BooleanLike;
has_implant: BooleanLike;
case_information: string;
+ case_lore: string;
+ saved_deathrattle_group?: string;
+ current_deathrattle_group?: string;
};
export const ImplantPad = (props) => {
const { act, data } = useBackend();
- const { has_case, has_implant, case_information } = data;
- const textHtml = {
- __html: sanitizeText(case_information),
- };
+ const {
+ has_case,
+ has_implant,
+ case_information,
+ case_lore,
+ saved_deathrattle_group,
+ current_deathrattle_group,
+ } = data;
return (
-
+
-
-
+
+
Implant Mini-Computer
-
-
+
+
-
-
+
+
-
-
- {!has_case &&
- 'No implant case detected. Please insert one to see its contents.'}
- {!!has_case &&
- !has_implant &&
- 'Implant case does not have an implant. Please insert one to continue.'}
- {!!has_case && !!has_implant && (
-
- )}
-
-
+
+ Saved Deathrattle Group: {saved_deathrattle_group || 'None'}
+
+ Current Deathrattle Group: {current_deathrattle_group || 'None'}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {!has_case && (
+
+ No implant case detected. Please insert one to see its contents.
+
+ )}
+ {!!has_case && !has_implant && (
+
+ Implant case does not have an implant. Please insert an implant to
+ continue.
+
+ )}
+ {!!has_case && !!has_implant && {case_information}}
+
+
+ {!has_case && (
+
+ No implant case detected. Please insert one to see its contents.
+
+ )}
+ {!!has_case && !has_implant && (
+
+ Implant case does not have an implant. Please insert an implant to
+ continue.
+
+ )}
+ {!!has_case && !!has_implant && {case_lore}}
+
);
diff --git a/tools/UpdatePaths/Scripts/94209_kheiral_repath.txt b/tools/UpdatePaths/Scripts/94209_kheiral_repath.txt
new file mode 100644
index 00000000000..0903302fd52
--- /dev/null
+++ b/tools/UpdatePaths/Scripts/94209_kheiral_repath.txt
@@ -0,0 +1 @@
+/obj/item/kheiral_cuffs : /obj/item/clothing/accessory/kheiral_cuffs
\ No newline at end of file