diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index 8f02e79eb..18a11e9cb 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -499,7 +499,7 @@
///called on implants being implanted into someone with an uplink implant: (datum/component/uplink)
#define COMSIG_IMPLANT_EXISTING_UPLINK "implant_uplink_exists"
//This uses all return values of COMSIG_IMPLANT_OTHER
-
+#define COMSIG_IMPLANT_REMOVING "implant_removing" //from base of /obj/item/implant/proc/removed() (list/args)
// /obj/item/pda signals
///called on pda when the user changes the ringtone: (mob/living/user, new_ringtone)
diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm
index 8982530ab..2c3b7518b 100644
--- a/code/datums/components/uplink.dm
+++ b/code/datums/components/uplink.dm
@@ -24,8 +24,9 @@ GLOBAL_LIST_EMPTY(uplinks)
var/unlock_note
var/unlock_code
var/failsafe_code
+ var/datum/ui_state/checkstate
-/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20)
+/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate)
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
@@ -57,6 +58,7 @@ GLOBAL_LIST_EMPTY(uplinks)
active = _enabled
gamemode = _gamemode
telecrystals = starting_tc
+ checkstate = _checkstate
if(!lockable)
active = TRUE
locked = FALSE
@@ -115,6 +117,7 @@ GLOBAL_LIST_EMPTY(uplinks)
/datum/component/uplink/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
+ state = checkstate ? checkstate : state
active = TRUE
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
@@ -123,6 +126,12 @@ GLOBAL_LIST_EMPTY(uplinks)
ui.set_style("syndicate")
ui.open()
+/datum/component/uplink/ui_host(mob/user)
+ if(istype(parent, /obj/item/implant)) //implants are like organs, not really located inside mobs codewise.
+ var/obj/item/implant/I = parent
+ return I.imp_in
+ return ..()
+
/datum/component/uplink/ui_data(mob/user)
if(!user.mind)
return
diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm
index 1f5c28d3c..3bb752b55 100644
--- a/code/datums/outfit.dm
+++ b/code/datums/outfit.dm
@@ -104,7 +104,7 @@
H.update_action_buttons_icon()
if(implants)
for(var/implant_type in implants)
- var/obj/item/implant/I = new implant_type(H)
+ var/obj/item/implant/I = new implant_type
I.implant(H, null, TRUE)
H.update_body()
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 615d55a81..1767d468e 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -155,9 +155,9 @@
var/obj/item/U = new uplink_type(H, H.key, tc)
H.equip_to_slot_or_del(U, SLOT_IN_BACKPACK)
- var/obj/item/implant/weapons_auth/W = new/obj/item/implant/weapons_auth(H)
+ var/obj/item/implant/weapons_auth/W = new
W.implant(H)
- var/obj/item/implant/explosive/E = new/obj/item/implant/explosive(H)
+ var/obj/item/implant/explosive/E = new
E.implant(H)
H.faction |= ROLE_SYNDICATE
H.update_icons()
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 05486a4c5..e541bda1f 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -231,7 +231,7 @@
dat += "
[src.active_record.fields["name"]]
"
dat += "Scan ID [src.active_record.fields["id"]] Clone
"
- var/obj/item/implant/health/H = locate(src.active_record.fields["imp"])
+ var/obj/item/implant/health/H = locate(active_record.fields["imp"])
if ((H) && (istype(H)))
dat += "Health Implant Data:
[H.sensehealth()]
"
diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm
index 795ea34c9..e4af7acd7 100644
--- a/code/game/machinery/computer/medical.dm
+++ b/code/game/machinery/computer/medical.dm
@@ -573,7 +573,7 @@
if(user)
if(message)
if(authenticated)
- if(user.canUseTopic(src, BE_CLOSE))
+ if(user.canUseTopic(src, !issilicon(user)))
if(!record1 || record1 == active1)
if(!record2 || record2 == active2)
return 1
diff --git a/code/game/machinery/computer/prisoner.dm b/code/game/machinery/computer/prisoner.dm
deleted file mode 100644
index a852612d9..000000000
--- a/code/game/machinery/computer/prisoner.dm
+++ /dev/null
@@ -1 +0,0 @@
-/obj/machinery/computer/prisoner
diff --git a/code/game/machinery/computer/prisoner/management.dm b/code/game/machinery/computer/prisoner/management.dm
index e231a1748..653f6bf48 100644
--- a/code/game/machinery/computer/prisoner/management.dm
+++ b/code/game/machinery/computer/prisoner/management.dm
@@ -35,11 +35,11 @@
dat += "
Chemical Implants
"
var/turf/Tr = null
for(var/obj/item/implant/chem/C in GLOB.tracked_chem_implants)
- Tr = get_turf(C)
- if((Tr) && (Tr.z != src.z))
- continue//Out of range
if(!C.imp_in)
continue
+ Tr = get_turf(C.imp_in)
+ if((Tr) && (Tr.z != src.z))
+ continue//Out of range
dat += "ID: [C.imp_in.name] | Remaining Units: [C.reagents.total_volume]
"
dat += "| Inject: "
dat += "((1))"
@@ -48,9 +48,9 @@
dat += "********************************
"
dat += "
Tracking Implants
"
for(var/obj/item/implant/tracking/T in GLOB.tracked_implants)
- if(!isliving(T.imp_in))
+ if(!T.imp_in || !isliving(T.imp_in))
continue
- Tr = get_turf(T)
+ Tr = get_turf(T.imp_in)
if((Tr) && (Tr.z != src.z))
continue//Out of range
diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm
index 99947bb4f..2e80aab62 100644
--- a/code/game/machinery/computer/security.dm
+++ b/code/game/machinery/computer/security.dm
@@ -800,7 +800,7 @@ What a mess.*/
/obj/machinery/computer/secure_data/proc/canUseSecurityRecordsConsole(mob/user, message1 = 0, record1, record2)
if(user)
if(authenticated)
- if(user.canUseTopic(src, BE_CLOSE))
+ if(user.canUseTopic(src, !issilicon(user)))
if(!trim(message1))
return 0
if(!record1 || record1 == active1)
diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm
index e53e3cb4b..667cf2f1b 100644
--- a/code/game/machinery/computer/teleporter.dm
+++ b/code/game/machinery/computer/teleporter.dm
@@ -10,6 +10,7 @@
var/obj/machinery/teleport/station/power_station
var/calibrating
var/turf/target
+ var/obj/item/implant/imp_t
/obj/machinery/computer/teleporter/Initialize()
. = ..()
@@ -109,6 +110,9 @@
/obj/machinery/computer/teleporter/proc/reset_regime()
target = null
+ if(imp_t)
+ UnregisterSignal(imp_t, COMSIG_IMPLANT_REMOVING)
+ imp_t = null
if(regime_set == "Teleporter")
regime_set = "Gate"
else
@@ -127,15 +131,29 @@
if(!I.imp_in || !I.allow_teleport || !isliving(I.imp_in))
continue
else
- var/mob/living/M = I.loc
+ var/mob/living/M = I.imp_in
if(M.stat == DEAD)
if(M.timeofdeath + I.lifespan_postmortem < world.time)
continue
- if(is_eligible(I))
- L[avoid_assoc_duplicate_keys(M.real_name, areaindex)] = I
+ if(is_eligible(M))
+ L[avoid_assoc_duplicate_keys(M.real_name, areaindex)] = M
var/desc = input("Please select a location to lock in.", "Locking Computer") as null|anything in L
+ if(!user.canUseTopic(src, !issilicon(user), NO_DEXTERY)) //check if we are still around
+ return
target = L[desc]
+ if(imp_t)
+ UnregisterSignal(imp_t, COMSIG_IMPLANT_REMOVING)
+ imp_t = null
+ if(isliving(target)) //make sure the living mob is still implanted to be a valid target
+ var/mob/living/M = target
+ var/obj/item/implant/tracking/I = locate() in M.implants
+ if(I)
+ RegisterSignal(I, COMSIG_IMPLANT_REMOVING, .proc/untarget_implant)
+ imp_t = I
+ else
+ target = null
+ return
var/turf/T = get_turf(target)
log_game("[key_name(user)] has set the teleporter target to [target] at [AREACOORD(T)]")
@@ -149,6 +167,8 @@
to_chat(user, "No active connected stations located.")
return
var/desc = input("Please select a station to lock in.", "Locking Computer") as null|anything in L
+ if(!user.canUseTopic(src, !issilicon(user), NO_DEXTERY)) //again, check if we are still around
+ return
var/obj/machinery/teleport/station/target_station = L[desc]
if(!target_station || !target_station.teleporter_hub)
return
@@ -164,6 +184,14 @@
target_station.teleporter_console.stat &= ~NOPOWER
target_station.teleporter_console.update_icon()
+/obj/machinery/computer/teleporter/proc/untarget_implant() //untargets from mob the racker was once implanted in to prevent issues.
+ target = null
+ if(power_station)
+ power_station.engaged = FALSE
+ power_station.teleporter_hub?.update_icon()
+ UnregisterSignal(imp_t, COMSIG_IMPLANT_REMOVING)
+ imp_t = null
+
/obj/machinery/computer/teleporter/proc/is_eligible(atom/movable/AM)
var/turf/T = get_turf(AM)
if(!T)
diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm
index 7675e913e..d7df08533 100644
--- a/code/game/objects/items/devices/gps.dm
+++ b/code/game/objects/items/devices/gps.dm
@@ -167,8 +167,19 @@ GLOBAL_LIST_EMPTY(GPS_list)
gpstag = "Eerie Signal"
desc = "Report to a coder immediately."
invisibility = INVISIBILITY_MAXIMUM
+ var/obj/item/implant/gps/implant
-/obj/item/gps/mining/internal
+/obj/item/gps/internal/Initialize(mapload, obj/item/implant/gps/_implant)
+ . = ..()
+ implant = _implant
+
+/obj/item/gps/internal/Destroy()
+ if(implant?.imp_in)
+ qdel(implant)
+ else
+ return ..()
+
+/obj/item/gps/internal/mining
icon_state = "gps-m"
gpstag = "MINER"
desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life."
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index a1d032a20..8c3003603 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -413,3 +413,16 @@
/obj/item/radio/off // Station bounced radios, their only difference is spawning with the speakers off, this was made to help the lag.
listening = 0 // And it's nice to have a subtype too for future features.
dog_fashion = /datum/dog_fashion/back
+
+/obj/item/radio/internal
+ var/obj/item/implant/radio/implant
+
+/obj/item/radio/internal/Initialize(mapload, obj/item/implant/radio/_implant)
+ . = ..()
+ implant = _implant
+
+/obj/item/radio/internal/Destroy()
+ if(implant?.imp_in)
+ qdel(implant)
+ else
+ return ..()
diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm
index 06be71cd9..2e25b4874 100644
--- a/code/game/objects/items/implants/implant.dm
+++ b/code/game/objects/items/implants/implant.dm
@@ -72,7 +72,7 @@
else
return FALSE
- forceMove(target)
+ moveToNullspace()
imp_in = target
target.implants += src
if(activated)
@@ -89,12 +89,12 @@
return TRUE
/obj/item/implant/proc/removed(mob/living/source, silent = FALSE, special = 0)
- moveToNullspace()
+ SEND_SIGNAL(src, COMSIG_IMPLANT_REMOVING, args)
imp_in = null
source.implants -= src
for(var/X in actions)
var/datum/action/A = X
- A.Grant(source)
+ A.Remove(source)
if(ishuman(source))
var/mob/living/carbon/human/H = source
H.sec_hud_set_implants()
diff --git a/code/game/objects/items/implants/implant_chem.dm b/code/game/objects/items/implants/implant_chem.dm
index c6c8be1a8..8da1d1e47 100644
--- a/code/game/objects/items/implants/implant_chem.dm
+++ b/code/game/objects/items/implants/implant_chem.dm
@@ -3,6 +3,7 @@
desc = "Injects things."
icon_state = "reagents"
activated = FALSE
+ var/obj/item/imp_chemholder/chemholder
/obj/item/implant/chem/get_data()
var/dat = {"Implant Specifications:
@@ -29,6 +30,26 @@
GLOB.tracked_chem_implants -= src
return ..()
+/obj/item/implant/chem/implant(mob/living/target, mob/user, silent = FALSE)
+ . = ..()
+ if(!.)
+ return
+ if(chemholder)
+ chemholder.forceMove(target)
+ return
+ chemholder = new(imp_in, src)
+ reagents.trans_to(chemholder, reagents.total_volume)
+
+/obj/item/implant/chem/removed(mob/target, silent = FALSE, special = 0)
+ . = ..()
+ if(!.)
+ return
+ if(!special)
+ chemholder.reagents.trans_to(src, chemholder.reagents.total_volume)
+ QDEL_NULL(chemholder)
+ else
+ chemholder?.moveToNullspace()
+
/obj/item/implant/chem/trigger(emote, mob/living/source)
if(emote == "deathgasp")
if(istype(source) && !(source.stat == DEAD))
@@ -45,13 +66,12 @@
injectamount = reagents.total_volume
else
injectamount = cause
- reagents.trans_to(R, injectamount)
+ chemholder.reagents.trans_to(R, injectamount)
to_chat(R, "You hear a faint beep.")
- if(!reagents.total_volume)
+ if(!chemholder.reagents.total_volume)
to_chat(R, "You hear a faint click from your chest.")
qdel(src)
-
/obj/item/implantcase/chem
name = "implant case - 'Remote Chemical'"
desc = "A glass case containing a remote chemical implant."
@@ -63,3 +83,17 @@
return TRUE
else
return ..()
+
+/obj/item/imp_chemholder
+ var/obj/item/implant/chem/implant
+
+/obj/item/imp_chemholder/Initialize(mapload, obj/item/implant/chem/_implant)
+ . = ..()
+ create_reagents(50)
+ implant = _implant
+
+/obj/item/imp_chemholder/Destroy()
+ if(implant?.imp_in)
+ qdel(implant)
+ else
+ return ..()
\ No newline at end of file
diff --git a/code/game/objects/items/implants/implant_clown.dm b/code/game/objects/items/implants/implant_clown.dm
index ae1fef109..bb98e72b3 100644
--- a/code/game/objects/items/implants/implant_clown.dm
+++ b/code/game/objects/items/implants/implant_clown.dm
@@ -11,7 +11,7 @@
/obj/item/implant/sad_trombone/trigger(emote, mob/source)
if(emote == "deathgasp")
- playsound(loc, 'sound/misc/sadtrombone.ogg', 50, 0)
+ playsound(source.loc, 'sound/misc/sadtrombone.ogg', 50, 0)
/obj/item/implanter/sad_trombone
name = "implanter (sad trombone)"
diff --git a/code/game/objects/items/implants/implant_explosive.dm b/code/game/objects/items/implants/implant_explosive.dm
index e749a6c4b..b93c9419a 100644
--- a/code/game/objects/items/implants/implant_explosive.dm
+++ b/code/game/objects/items/implants/implant_explosive.dm
@@ -11,8 +11,9 @@
var/popup = FALSE // is the DOUWANNABLOWUP window open?
var/active = FALSE
-/obj/item/implant/explosive/on_mob_death(mob/living/L, gibbed)
- activate("death")
+/obj/item/implant/explosive/trigger(emote, mob/source)
+ if(emote == "deathgasp")
+ activate("death")
/obj/item/implant/explosive/get_data()
var/dat = {"Implant Specifications:
@@ -29,32 +30,18 @@
/obj/item/implant/explosive/activate(cause)
. = ..()
if(!cause || !imp_in || active)
- return 0
+ return FALSE
if(cause == "action_button" && !popup)
popup = TRUE
var/response = alert(imp_in, "Are you sure you want to activate your [name]? This will cause you to explode!", "[name] Confirmation", "Yes", "No")
popup = FALSE
if(response == "No")
- return 0
- heavy = round(heavy)
- medium = round(medium)
- weak = round(weak)
- to_chat(imp_in, "You activate your [name].")
- active = TRUE
- var/turf/boomturf = get_turf(imp_in)
- message_admins("[ADMIN_LOOKUPFLW(imp_in)] has activated their [name] at [ADMIN_VERBOSEJMP(boomturf)], with cause of [cause].")
-//If the delay is short, just blow up already jeez
- if(delay <= 7)
- explosion(src,heavy,medium,weak,weak, flame_range = weak)
- if(imp_in)
- imp_in.gib(1)
- qdel(src)
- return
- timed_explosion()
+ return FALSE
+ addtimer(CALLBACK(src, .proc/timed_explosion, cause), 1)
/obj/item/implant/explosive/implant(mob/living/target)
for(var/X in target.implants)
- if(istype(X, type))
+ if(istype(X, /obj/item/implant/explosive))
var/obj/item/implant/explosive/imp_e = X
imp_e.heavy += heavy
imp_e.medium += medium
@@ -65,22 +52,37 @@
return ..()
-/obj/item/implant/explosive/proc/timed_explosion()
- imp_in.visible_message("[imp_in] starts beeping ominously!")
- playsound(loc, 'sound/items/timer.ogg', 30, 0)
- sleep(delay*0.25)
- if(imp_in && !imp_in.stat)
+/obj/item/implant/explosive/proc/timed_explosion(cause)
+ if(cause == "death" && imp_in.stat != DEAD)
+ return FALSE
+ heavy = round(heavy)
+ medium = round(medium)
+ weak = round(weak)
+ to_chat(imp_in, "You activate your [name].")
+ active = TRUE
+ var/turf/boomturf = get_turf(imp_in)
+ message_admins("[ADMIN_LOOKUPFLW(imp_in)] has activated their [name] at [ADMIN_VERBOSEJMP(boomturf)], with cause of [cause].")
+ if(delay > 7)
+ imp_in?.visible_message("[imp_in] starts beeping ominously!")
+ playsound(get_turf(imp_in ? imp_in : src), 'sound/items/timer.ogg', 30, 0)
+ addtimer(CALLBACK(src, .proc/double_pain, TRUE), delay * 0.25)
+ addtimer(CALLBACK(src, .proc/double_pain), delay * 0.5)
+ addtimer(CALLBACK(src, .proc/double_pain), delay * 0.75)
+ addtimer(CALLBACK(src, .proc/boom_goes_the_weasel), delay)
+ else //If the delay is short, just blow up already jeez
+ boom_goes_the_weasel()
+
+/obj/item/implant/explosive/proc/double_pain(message = FALSE)
+ playsound(get_turf(imp_in ? imp_in : src), 'sound/items/timer.ogg', 30, 0)
+ if(!imp_in)
+ return
+ if(message && imp_in.stat == CONSCIOUS)
imp_in.visible_message("[imp_in] doubles over in pain!")
- imp_in.Knockdown(140)
- playsound(loc, 'sound/items/timer.ogg', 30, 0)
- sleep(delay*0.25)
- playsound(loc, 'sound/items/timer.ogg', 30, 0)
- sleep(delay*0.25)
- playsound(loc, 'sound/items/timer.ogg', 30, 0)
- sleep(delay*0.25)
- explosion(src,heavy,medium,weak,weak, flame_range = weak)
- if(imp_in)
- imp_in.gib(1)
+ imp_in.Knockdown(140)
+
+/obj/item/implant/explosive/proc/boom_goes_the_weasel()
+ explosion(get_turf(imp_in ? imp_in : src), heavy, medium, weak, weak, flame_range = weak)
+ imp_in?.gib(TRUE)
qdel(src)
/obj/item/implant/explosive/macro
@@ -95,17 +97,7 @@
/obj/item/implant/explosive/macro/implant(mob/living/target)
for(var/X in target.implants)
if(istype(X, type))
- return 0
-
- for(var/Y in target.implants)
- if(istype(Y, /obj/item/implant/explosive))
- var/obj/item/implant/explosive/imp_e = Y
- heavy += imp_e.heavy
- medium += imp_e.medium
- weak += imp_e.weak
- delay += imp_e.delay
- qdel(imp_e)
- break
+ return FALSE
return ..()
diff --git a/code/game/objects/items/implants/implant_mindshield.dm b/code/game/objects/items/implants/implant_mindshield.dm
index b9907cbfc..2a99c6e1e 100644
--- a/code/game/objects/items/implants/implant_mindshield.dm
+++ b/code/game/objects/items/implants/implant_mindshield.dm
@@ -1,7 +1,6 @@
/obj/item/implant/mindshield
name = "mindshield implant"
desc = "Protects against brainwashing."
- resistance_flags = INDESTRUCTIBLE
activated = 0
/obj/item/implant/mindshield/get_data()
diff --git a/code/game/objects/items/implants/implant_misc.dm b/code/game/objects/items/implants/implant_misc.dm
index 3a4295c61..75b0c6779 100644
--- a/code/game/objects/items/implants/implant_misc.dm
+++ b/code/game/objects/items/implants/implant_misc.dm
@@ -69,62 +69,4 @@
healthstring = "Oxygen Deprivation Damage => [round(L.getOxyLoss())]
Fire Damage => [round(L.getFireLoss())]
Toxin Damage => [round(L.getToxLoss())]
Brute Force Damage => [round(L.getBruteLoss())]"
if (!healthstring)
healthstring = "ERROR"
- return healthstring
-
-/obj/item/implant/radio
- name = "internal radio implant"
- activated = TRUE
- var/obj/item/radio/radio
- var/radio_key
- var/subspace_transmission = FALSE
- icon = 'icons/obj/radio.dmi'
- icon_state = "walkietalkie"
-
-/obj/item/implant/radio/activate()
- . = ..()
- // needs to be GLOB.deep_inventory_state otherwise it won't open
- radio.ui_interact(usr, "main", null, FALSE, null, GLOB.deep_inventory_state)
-
-/obj/item/implant/radio/Initialize(mapload)
- . = ..()
-
- radio = new(src)
- // almost like an internal headset, but without the
- // "must be in ears to hear" restriction.
- radio.name = "internal radio"
- radio.subspace_transmission = subspace_transmission
- radio.canhear_range = 0
- if(radio_key)
- radio.keyslot = new radio_key
- radio.recalculateChannels()
-
-/obj/item/implant/radio/mining
- radio_key = /obj/item/encryptionkey/headset_cargo
-
-/obj/item/implant/radio/syndicate
- desc = "Are you there God? It's me, Syndicate Comms Agent."
- radio_key = /obj/item/encryptionkey/syndicate
- subspace_transmission = TRUE
-
-/obj/item/implant/radio/slime
- name = "slime radio"
- icon = 'icons/obj/surgery.dmi'
- icon_state = "adamantine_resonator"
- radio_key = /obj/item/encryptionkey/headset_sci
- subspace_transmission = TRUE
-
-/obj/item/implant/radio/get_data()
- var/dat = {"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."}
- return dat
-
-/obj/item/implanter/radio
- name = "implanter (internal radio)"
- imp_type = /obj/item/implant/radio
-
-/obj/item/implanter/radio/syndicate
- name = "implanter (internal syndicate radio)"
- imp_type = /obj/item/implant/radio/syndicate
-
+ return healthstring
\ No newline at end of file
diff --git a/code/game/objects/items/implants/implant_radio.dm b/code/game/objects/items/implants/implant_radio.dm
new file mode 100644
index 000000000..5d3d579a4
--- /dev/null
+++ b/code/game/objects/items/implants/implant_radio.dm
@@ -0,0 +1,69 @@
+/obj/item/implant/radio
+ name = "internal radio implant"
+ activated = TRUE
+ var/obj/item/radio/internal/radio
+ var/radio_key
+ var/subspace_transmission = FALSE
+ icon = 'icons/obj/radio.dmi'
+ icon_state = "walkietalkie"
+
+/obj/item/implant/radio/activate()
+ . = ..()
+ // needs to be GLOB.deep_inventory_state otherwise it won't open
+ radio.ui_interact(usr, "main", null, FALSE, null, GLOB.deep_inventory_state)
+
+/obj/item/implant/radio/implant(mob/living/target, mob/user, silent = FALSE)
+ . = ..()
+ if(!.)
+ return
+ if(radio)
+ radio.forceMove(target)
+ return
+ radio = new(target)
+ // almost like an internal headset, but without the
+ // "must be in ears to hear" restriction.
+ radio.name = "internal radio"
+ radio.subspace_transmission = subspace_transmission
+ radio.canhear_range = 0
+ if(radio_key)
+ radio.keyslot = new radio_key
+ radio.recalculateChannels()
+
+/obj/item/implant/radio/removed(mob/target, silent = FALSE, special = 0)
+ . = ..()
+ if(!.)
+ return
+ if(!special)
+ qdel(radio)
+ else
+ radio?.moveToNullspace()
+
+/obj/item/implant/radio/mining
+ radio_key = /obj/item/encryptionkey/headset_cargo
+
+/obj/item/implant/radio/syndicate
+ desc = "Are you there God? It's me, Syndicate Comms Agent."
+ radio_key = /obj/item/encryptionkey/syndicate
+ subspace_transmission = TRUE
+
+/obj/item/implant/radio/slime
+ name = "slime radio"
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "adamantine_resonator"
+ radio_key = /obj/item/encryptionkey/headset_sci
+ subspace_transmission = TRUE
+
+/obj/item/implant/radio/get_data()
+ var/dat = {"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."}
+ return dat
+
+/obj/item/implanter/radio
+ name = "implanter (internal radio)"
+ imp_type = /obj/item/implant/radio
+
+/obj/item/implanter/radio/syndicate
+ name = "implanter (internal syndicate radio)"
+ imp_type = /obj/item/implant/radio/syndicate
\ No newline at end of file
diff --git a/code/game/objects/items/implants/implant_storage.dm b/code/game/objects/items/implants/implant_storage.dm
index 2a224e9ce..eadadbe0c 100644
--- a/code/game/objects/items/implants/implant_storage.dm
+++ b/code/game/objects/items/implants/implant_storage.dm
@@ -4,16 +4,18 @@
icon_state = "storage"
item_color = "r"
var/max_slot_stacking = 4
+ var/obj/item/storage/bluespace_pocket/pocket
/obj/item/implant/storage/activate()
. = ..()
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SHOW, imp_in, TRUE)
+ SEND_SIGNAL(pocket, COMSIG_TRY_STORAGE_SHOW, imp_in, TRUE)
/obj/item/implant/storage/removed(source, silent = FALSE, special = 0)
- . = ..()
- if(.)
- if(!special)
- qdel(GetComponent(/datum/component/storage/concrete/implant))
+ if(!special)
+ QDEL_NULL(pocket)
+ else
+ pocket?.moveToNullspace()
+ return ..()
/obj/item/implant/storage/implant(mob/living/target, mob/user, silent = FALSE)
for(var/X in target.implants)
@@ -21,13 +23,24 @@
var/obj/item/implant/storage/imp_e = X
var/datum/component/storage/STR = imp_e.GetComponent(/datum/component/storage)
if(!STR || (STR && STR.max_items < max_slot_stacking))
- imp_e.AddComponent(/datum/component/storage/concrete/implant)
+ imp_e.pocket.AddComponent(/datum/component/storage/concrete/implant)
qdel(src)
return TRUE
return FALSE
- AddComponent(/datum/component/storage/concrete/implant)
+ . = ..()
+ if(.)
+ if(!QDELETED(pocket))
+ pocket.forceMove(target)
+ else
+ pocket = new(target)
- return ..()
+/obj/item/storage/bluespace_pocket
+ name = "internal bluespace pocket"
+ icon_state = "pillbox"
+ w_class = WEIGHT_CLASS_TINY
+ desc = "A tiny yet spacious pocket, usually found implanted inside sneaky syndicate agents and nowhere else."
+ component_type = /datum/component/storage/concrete/implant
+ resistance_flags = INDESTRUCTIBLE //A bomb!
/obj/item/implanter/storage
name = "implanter (storage)"
diff --git a/code/game/objects/items/implants/implant_track.dm b/code/game/objects/items/implants/implant_track.dm
index 4398688ce..4f81432a3 100644
--- a/code/game/objects/items/implants/implant_track.dm
+++ b/code/game/objects/items/implants/implant_track.dm
@@ -15,8 +15,8 @@
. = ..()
QDEL_IN(src, lifespan)
-/obj/item/implant/tracking/New()
- ..()
+/obj/item/implant/tracking/Initialize()
+ . = ..()
GLOB.tracked_implants += src
/obj/item/implant/tracking/Destroy()
@@ -27,7 +27,31 @@
imp_type = /obj/item/implant/tracking
/obj/item/implanter/tracking/gps
- imp_type = /obj/item/gps/mining/internal
+ imp_type = /obj/item/implant/gps
+
+/obj/item/implant/gps
+ name = "\improper GPS implant"
+ desc = "Track with this and a GPS."
+ activated = FALSE
+ var/obj/item/gps/internal/mining/real_gps
+
+/obj/item/implant/gps/implant(mob/living/target, mob/user, silent = FALSE)
+ . = ..()
+ if(!.)
+ return
+ if(real_gps)
+ real_gps.forceMove(target)
+ else
+ real_gps = new(target)
+
+/obj/item/implant/gps/removed(mob/living/source, silent = FALSE, special = 0)
+ . = ..()
+ if(!.)
+ return
+ if(!special)
+ qdel(real_gps)
+ else
+ real_gps?.moveToNullspace()
/obj/item/implant/tracking/get_data()
var/dat = {"Implant Specifications:
diff --git a/code/game/objects/items/implants/implantuplink.dm b/code/game/objects/items/implants/implant_uplink.dm
similarity index 93%
rename from code/game/objects/items/implants/implantuplink.dm
rename to code/game/objects/items/implants/implant_uplink.dm
index 0cac8f838..9895c1e34 100644
--- a/code/game/objects/items/implants/implantuplink.dm
+++ b/code/game/objects/items/implants/implant_uplink.dm
@@ -9,7 +9,7 @@
/obj/item/implant/uplink/Initialize(mapload, _owner)
. = ..()
- AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, starting_tc)
+ AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, starting_tc, GLOB.not_incapacitated_state)
/obj/item/implanter/uplink
name = "implanter (uplink)"
diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm
index dd64c6716..0129eeb3e 100644
--- a/code/game/objects/items/teleportation.dm
+++ b/code/game/objects/items/teleportation.dm
@@ -237,4 +237,4 @@
itemUser.visible_message("The portal snaps closed taking [user]'s head with it!")
else
itemUser.visible_message("[user] looks even further depressed as they realize they do not have a head...and suddenly dies of shame!")
- return (BRUTELOSS)
\ No newline at end of file
+ return (BRUTELOSS)
diff --git a/code/modules/antagonists/abductor/equipment/abduction_outfits.dm b/code/modules/antagonists/abductor/equipment/abduction_outfits.dm
index a69c8fdef..7e03bbf57 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_outfits.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_outfits.dm
@@ -52,5 +52,5 @@
/datum/outfit/abductor/scientist/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
..()
if(!visualsOnly)
- var/obj/item/implant/abductor/beamplant = new /obj/item/implant/abductor(H)
+ var/obj/item/implant/abductor/beamplant = new
beamplant.implant(H)
diff --git a/code/modules/antagonists/overthrow/overthrow.dm b/code/modules/antagonists/overthrow/overthrow.dm
index 2f08824c0..075b9f13b 100644
--- a/code/modules/antagonists/overthrow/overthrow.dm
+++ b/code/modules/antagonists/overthrow/overthrow.dm
@@ -107,9 +107,9 @@
/datum/antagonist/overthrow/proc/equip_overthrow()
if(!owner || !owner.current || !ishuman(owner.current)) // only equip existing human overthrow members. This excludes the AI, in particular.
return
- var/obj/item/implant/storage/S = locate(/obj/item/implant/storage) in owner.current
+ var/obj/item/implant/storage/S = locate(/obj/item/implant/storage) in owner.current.implants
if(!S)
- S = new(owner.current)
+ S = new
S.implant(owner.current)
var/I = pick(possible_useful_items)
if(ispath(I)) // in case some admin decides to fuck the list up for fun
diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm
index e6cae518b..8a20a8155 100644
--- a/code/modules/antagonists/wizard/wizard.dm
+++ b/code/modules/antagonists/wizard/wizard.dm
@@ -245,7 +245,7 @@
if(!istype(M))
return
- var/obj/item/implant/exile/Implant = new/obj/item/implant/exile(M)
+ var/obj/item/implant/exile/Implant = new
Implant.implant(M)
/datum/antagonist/wizard/academy/create_objectives()
diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm
index b1db4a484..962b850e0 100644
--- a/code/modules/awaymissions/mission_code/Academy.dm
+++ b/code/modules/awaymissions/mission_code/Academy.dm
@@ -210,8 +210,6 @@
if(4)
//Destroy Equipment
for (var/obj/item/I in user)
- if (istype(I, /obj/item/implant))
- continue
qdel(I)
if(5)
//Monkeying
diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm
index 86c8f5335..e8cb13138 100644
--- a/code/modules/clothing/outfits/ert.dm
+++ b/code/modules/clothing/outfits/ert.dm
@@ -10,7 +10,7 @@
if(visualsOnly)
return
- var/obj/item/implant/mindshield/L = new/obj/item/implant/mindshield(H)
+ var/obj/item/implant/mindshield/L = new
L.implant(H, null, 1)
var/obj/item/radio/R = H.ears
diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm
index ae5da9133..377ac910f 100644
--- a/code/modules/clothing/outfits/standard.dm
+++ b/code/modules/clothing/outfits/standard.dm
@@ -401,7 +401,7 @@
R.set_frequency(FREQ_CENTCOM)
R.freqlock = TRUE
- var/obj/item/implant/mindshield/L = new/obj/item/implant/mindshield(H)//Here you go Deuryn
+ var/obj/item/implant/mindshield/L = new //Here you go Deuryn
L.implant(H, null, 1)
@@ -428,7 +428,7 @@
/datum/outfit/debug //Debug objs plus hardsuit
name = "Debug outfit"
- uniform = /obj/item/clothing/under/patriotsuit
+ uniform = /obj/item/clothing/under/patriotsuit
suit = /obj/item/clothing/suit/space/hardsuit/syndi/elite
shoes = /obj/item/clothing/shoes/magboots/advance
suit_store = /obj/item/tank/internals/oxygen
diff --git a/code/modules/clothing/outfits/vr.dm b/code/modules/clothing/outfits/vr.dm
index cd8930641..cd8115ac7 100644
--- a/code/modules/clothing/outfits/vr.dm
+++ b/code/modules/clothing/outfits/vr.dm
@@ -29,9 +29,9 @@
. = ..()
var/obj/item/uplink/U = new /obj/item/uplink/nuclear_restricted(H, H.key, 80)
H.equip_to_slot_or_del(U, SLOT_IN_BACKPACK)
- var/obj/item/implant/weapons_auth/W = new/obj/item/implant/weapons_auth(H)
+ var/obj/item/implant/weapons_auth/W = new
W.implant(H)
- var/obj/item/implant/explosive/E = new/obj/item/implant/explosive(H)
+ var/obj/item/implant/explosive/E = new
E.implant(H)
H.faction |= ROLE_SYNDICATE
H.update_icons()
diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm
index 3834ffea9..0c8aef51a 100644
--- a/code/modules/mining/minebot.dm
+++ b/code/modules/mining/minebot.dm
@@ -49,7 +49,7 @@
toggle_mode_action.Grant(src)
var/datum/action/innate/minedrone/dump_ore/dump_ore_action = new()
dump_ore_action.Grant(src)
- var/obj/item/implant/radio/mining/imp = new(src)
+ var/obj/item/implant/radio/mining/imp = new
imp.implant(src)
access_card = new /obj/item/card/id(src)
diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm
index 4a29f2b14..ca505bc87 100644
--- a/code/modules/mob/living/death.dm
+++ b/code/modules/mob/living/death.dm
@@ -13,6 +13,10 @@
if(!no_bodyparts)
spread_bodyparts(no_brain, no_organs)
+ for(var/X in implants)
+ var/obj/item/implant/I = X
+ qdel(I)
+
spawn_gibs(no_bodyparts)
qdel(src)
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 7021c1fd7..f33363448 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -371,8 +371,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return message
/mob/living/proc/radio(message, message_mode, list/spans, language)
- var/obj/item/implant/radio/imp = locate() in src
- if(imp && imp.radio.on)
+ var/obj/item/implant/radio/imp = locate() in implants
+ if(imp?.radio.on)
if(message_mode == MODE_HEADSET)
imp.radio.talk_into(src, message, , spans, language)
return ITALICS | REDUCE_RANGE
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
index fdb709fc9..521f458e2 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
@@ -49,7 +49,7 @@
. = ..()
var/datum/component/uplink/hidden_uplink = internal_storage.GetComponent(/datum/component/uplink)
hidden_uplink.telecrystals = 30
- var/obj/item/implant/weapons_auth/W = new/obj/item/implant/weapons_auth(src)
+ var/obj/item/implant/weapons_auth/W = new
W.implant(src)
/mob/living/simple_animal/drone/snowflake
diff --git a/code/modules/mob/living/simple_animal/hostile/wizard.dm b/code/modules/mob/living/simple_animal/hostile/wizard.dm
index a946cbf45..f047a7aed 100644
--- a/code/modules/mob/living/simple_animal/hostile/wizard.dm
+++ b/code/modules/mob/living/simple_animal/hostile/wizard.dm
@@ -46,7 +46,8 @@
fireball.human_req = 0
fireball.player_lock = 0
AddSpell(fireball)
- implants += new /obj/item/implant/exile(src)
+ var/obj/item/implant/exile/I = new
+ I.implant(src, null, TRUE)
mm = new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile
mm.clothes_req = 0
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 2299d5f59..7fe7fc978 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -704,7 +704,7 @@
desc = "A miraculous chemical mix that grants human like intelligence to living beings. It has been modified with Syndicate technology to also grant an internal radio implant to the target and authenticate with identification systems."
/obj/item/slimepotion/slime/sentience/nuclear/after_success(mob/living/user, mob/living/simple_animal/SM)
- var/obj/item/implant/radio/syndicate/imp = new(src)
+ var/obj/item/implant/radio/syndicate/imp = new
imp.implant(SM, user)
SM.access_card = new /obj/item/card/id/syndicate(SM)
@@ -968,7 +968,7 @@
to_chat(user, "You feed the potion to [M].")
to_chat(M, "Your mind tingles as you are fed the potion. You can hear radio waves now!")
- var/obj/item/implant/radio/slime/imp = new(src)
+ var/obj/item/implant/radio/slime/imp = new
imp.implant(M, user)
qdel(src)
diff --git a/tgstation.dme b/tgstation.dme
index 4e0863b41..6b3c3a07b 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -671,7 +671,6 @@
#include "code\game\machinery\computer\medical.dm"
#include "code\game\machinery\computer\Operating.dm"
#include "code\game\machinery\computer\pod.dm"
-#include "code\game\machinery\computer\prisoner.dm"
#include "code\game\machinery\computer\robot.dm"
#include "code\game\machinery\computer\security.dm"
#include "code\game\machinery\computer\station_alert.dm"
@@ -945,16 +944,17 @@
#include "code\game\objects\items\implants\implant_krav_maga.dm"
#include "code\game\objects\items\implants\implant_mindshield.dm"
#include "code\game\objects\items\implants\implant_misc.dm"
+#include "code\game\objects\items\implants\implant_radio.dm"
#include "code\game\objects\items\implants\implant_slave.dm"
#include "code\game\objects\items\implants\implant_spell.dm"
#include "code\game\objects\items\implants\implant_stealth.dm"
#include "code\game\objects\items\implants\implant_storage.dm"
#include "code\game\objects\items\implants\implant_track.dm"
+#include "code\game\objects\items\implants\implant_uplink.dm"
#include "code\game\objects\items\implants\implantcase.dm"
#include "code\game\objects\items\implants\implantchair.dm"
#include "code\game\objects\items\implants\implanter.dm"
#include "code\game\objects\items\implants\implantpad.dm"
-#include "code\game\objects\items\implants\implantuplink.dm"
#include "code\game\objects\items\melee\energy.dm"
#include "code\game\objects\items\melee\misc.dm"
#include "code\game\objects\items\melee\transforming.dm"