diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index b7bcd047fdf..1b304283d63 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -198,6 +198,8 @@
#define COMSIG_LIVING_STATUS_UNCONSCIOUS "living_unconscious" //from base of mob/living/Unconscious() (amount, update, ignore)
#define COMSIG_LIVING_STATUS_SLEEP "living_sleeping" //from base of mob/living/Sleeping() (amount, update, ignore)
#define COMPONENT_NO_STUN 1 //For all of them
+#define COMSIG_LIVING_CAN_TRACK "mob_cantrack" //from base of /mob/living/can_track(): (mob/user)
+ #define COMPONENT_CANT_TRACK "mob_cant_track"
// /mob/living/carbon signals
#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity))
diff --git a/code/datums/elements/digitalcamo.dm b/code/datums/elements/digitalcamo.dm
new file mode 100644
index 00000000000..ebb51ec8a55
--- /dev/null
+++ b/code/datums/elements/digitalcamo.dm
@@ -0,0 +1,35 @@
+/datum/element/digitalcamo
+ element_flags = ELEMENT_DETACH
+ var/list/attached_mobs = list()
+
+/datum/element/digitalcamo/New()
+ . = ..()
+ START_PROCESSING(SSdcs, src)
+
+/datum/element/digitalcamo/Attach(datum/target)
+ . = ..()
+ if(!isliving(target) || target in attached_mobs)
+ return ELEMENT_INCOMPATIBLE
+ RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/on_examine)
+ RegisterSignal(target, COMSIG_LIVING_CAN_TRACK, .proc/can_track)
+ var/image/img = image(loc = target)
+ img.override = TRUE
+ attached_mobs[target] = img
+
+/datum/element/digitalcamo/Detach(datum/target)
+ . = ..()
+ UnregisterSignal(target, list(COMSIG_PARENT_EXAMINE, COMSIG_LIVING_CAN_TRACK))
+ for(var/mob/living/silicon/ai/AI in GLOB.player_list)
+ AI.client.images -= attached_mobs[target]
+ attached_mobs -= target
+
+/datum/element/digitalcamo/proc/on_examine(datum/source, mob/M)
+ to_chat(M, "[source.p_their()] skin seems to be shifting and morphing like is moving around below it.")
+
+/datum/element/digitalcamo/proc/can_track(datum/source)
+ return COMPONENT_CANT_TRACK
+
+/datum/element/digitalcamo/process()
+ for(var/mob/living/silicon/ai/AI in GLOB.player_list)
+ for(var/mob in attached_mobs)
+ AI.client.images |= attached_mobs[mob]
diff --git a/code/modules/antagonists/changeling/powers/digitalcamo.dm b/code/modules/antagonists/changeling/powers/digitalcamo.dm
index f193ceb105d..028f85b83e8 100644
--- a/code/modules/antagonists/changeling/powers/digitalcamo.dm
+++ b/code/modules/antagonists/changeling/powers/digitalcamo.dm
@@ -4,21 +4,20 @@
helptext = "We cannot be tracked by camera or seen by AI units while using this skill. However, humans looking at us will find us... uncanny."
button_icon_state = "digital_camo"
dna_cost = 1
+ active = FALSE
//Prevents AIs tracking you but makes you easily detectable to the human-eye.
/datum/action/changeling/digitalcamo/sting_action(mob/user)
..()
- if(user.digitalcamo)
+ if(active)
to_chat(user, "We return to normal.")
- user.digitalinvis = 0
- user.digitalcamo = 0
+ user.RemoveElement(/datum/element/digitalcamo)
else
to_chat(user, "We distort our form to hide from the AI.")
- user.digitalcamo = 1
- user.digitalinvis = 1
+ user.AddElement(/datum/element/digitalcamo)
+ active = !active
return TRUE
/datum/action/changeling/digitalcamo/Remove(mob/user)
- user.digitalcamo = FALSE
- user.digitalinvis = FALSE
+ user.RemoveElement(/datum/element/digitalcamo)
..()
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index 93a7ed02e8e..bbd797608bc 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -89,9 +89,6 @@
else if(InCritical())
. += "[t_His] breathing is shallow and labored."
- if(digitalcamo)
- . += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly unsimian manner."
-
var/trait_exam = common_trait_examine()
if (!isnull(trait_exam))
. += trait_exam
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index e8e7c37e162..b69eeae5afc 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -291,9 +291,6 @@
else if(!client)
msg += "[t_He] [t_has] a blank, absent-minded stare and appears completely unresponsive to anything. [t_He] may snap out of it soon.\n"
- if(digitalcamo)
- msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly inhuman manner.\n"
-
if (length(msg))
. += "[msg.Join("")]"
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 0d40c75d80b..8db38369dad 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -2,9 +2,6 @@
set waitfor = FALSE
set invisibility = 0
- if(digitalinvis)
- handle_diginvis() //AI becomes unable to see mob
-
if((movement_type & FLYING) && !(movement_type & FLOATING)) //TODO: Better floating
float(on = TRUE)
@@ -83,14 +80,6 @@
/mob/living/proc/handle_diseases()
return
-/mob/living/proc/handle_diginvis()
- if(!digitaldisguise)
- src.digitaldisguise = image(loc = src)
- src.digitaldisguise.override = 1
- for(var/mob/living/silicon/ai/AI in GLOB.player_list)
- AI.client.images |= src.digitaldisguise
-
-
/mob/living/proc/handle_random_events()
return
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index af3d29544b8..91b170a090c 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -878,25 +878,23 @@
/mob/living/proc/can_track(mob/living/user)
//basic fast checks go first. When overriding this proc, I recommend calling ..() at the end.
+ if(SEND_SIGNAL(src, COMSIG_LIVING_CAN_TRACK, args) & COMPONENT_CANT_TRACK)
+ return FALSE
var/turf/T = get_turf(src)
if(!T)
- return 0
+ return FALSE
if(is_centcom_level(T.z)) //dont detect mobs on centcom
- return 0
+ return FALSE
if(is_away_level(T.z))
- return 0
+ return FALSE
if(user != null && src == user)
- return 0
+ return FALSE
if(invisibility || alpha == 0)//cloaked
- return 0
- if(digitalcamo || digitalinvis)
- return 0
-
+ return FALSE
// Now, are they viewable by a camera? (This is last because it's the most intensive check)
if(!near_camera(src))
- return 0
-
- return 1
+ return FALSE
+ return TRUE
//used in datum/reagents/reaction() proc
/mob/living/proc/get_permeability_protection(list/target_zones)
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index fa7b062f068..845cb8dd411 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -54,7 +54,7 @@
/**
* Magic var that stops you moving and interacting with anything
- *
+ *
* Set when you're being turned into something else and also used in a bunch of places
* it probably shouldn't really be
*/
@@ -72,7 +72,7 @@
/**
* back up of the real name during admin possession
- *
+ *
* If an admin possesses an object it's real name is set to the admin name and this
* stores whatever the real name was previously. When possession ends, the real name
* is reset to this value
@@ -115,12 +115,12 @@
var/active_hand_index = 1
/**
* list of items held in hands
- *
+ *
* len = number of hands, eg: 2 nulls is 2 empty hands, 1 item and 1 null is 1 full hand
* and 1 empty hand.
- *
+ *
* NB: contains nulls!
- *
+ *
* held_items[active_hand_index] is the actively held item, but please use
* get_active_held_item() instead, because OOP
*/
@@ -158,17 +158,10 @@
*/
var/list/mob_spell_list = list()
-
+
/// bitflags defining which status effects can be inflicted (replaces canknockdown, canstun, etc)
var/status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH
- /// Can they be tracked by the AI?
- var/digitalcamo = 0
- ///Are they ivisible to the AI?
- var/digitalinvis = 0
- ///what does the AI see instead of them?
- var/image/digitaldisguise = null
-
/// Can they interact with station electronics
var/has_unlimited_silicon_privilege = 0
@@ -199,5 +192,5 @@
///THe z level this mob is currently registered in
var/registered_z = null
-
+
var/memory_throttle_time = 0
diff --git a/tgstation.dme b/tgstation.dme
index 0e80db2c934..5e16b98e399 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -488,6 +488,7 @@
#include "code\datums\diseases\advance\symptoms\youth.dm"
#include "code\datums\elements\_element.dm"
#include "code\datums\elements\cleaning.dm"
+#include "code\datums\elements\digitalcamo.dm"
#include "code\datums\elements\earhealing.dm"
#include "code\datums\elements\firestacker.dm"
#include "code\datums\elements\snail_crawl.dm"