diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index 4fe0c1fd7db..2fdda2ee188 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -164,3 +164,5 @@
/// Status effect given when someone uses the Give Item command to offer an item to another player.
#define STATUS_EFFECT_OFFERING_ITEM /datum/status_effect/offering_item
+
+#define STATUS_EFFECT_STARING /datum/status_effect/staring //Used in ../human/examine() proc
diff --git a/code/datums/spells/mimic.dm b/code/datums/spells/mimic.dm
index 2a6ba9263c1..cd6fb7e5c29 100644
--- a/code/datums/spells/mimic.dm
+++ b/code/datums/spells/mimic.dm
@@ -196,18 +196,29 @@
/datum/mimic_form
+ /// What the visible species of the form is (Only for human forms)?
+ var/examine_species = "Unknown"
+ /// What the visible gender of the form is (Only for human forms)?
+ var/examine_gender
+ /// What is the examine text paired with this form?
+ var/examine_text
+ /// What is the examine time paired with this form?
+ var/examine_time
/// How does the form look like?
var/appearance
- /// What is the examine text paired with this form
- var/examine_text
- /// What the name of the form is
+ /// What the name of the form is?
var/name
/datum/mimic_form/New(atom/movable/form, mob/user)
- appearance = form.appearance
+ examine_gender = form.get_visible_gender()
examine_text = form.examine(user)
+ examine_time = form.get_examine_time()
+ appearance = form.appearance
name = form.name
+ if(isliving(form))
+ var/mob/living/form_living = form
+ examine_species = form_living.get_visible_species()
/obj/effect/proc_holder/spell/mimic/morph
diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm
index 247b06abb0e..dffbc4157c6 100644
--- a/code/datums/status_effects/neutral.dm
+++ b/code/datums/status_effects/neutral.dm
@@ -43,6 +43,36 @@
get_kill()
. = ..()
+/datum/status_effect/staring
+ id = "staring"
+ alert_type = null
+ status_type = STATUS_EFFECT_UNIQUE
+ var/mob/living/target
+ var/target_gender
+ var/target_species
+
+/datum/status_effect/staring/on_creation(mob/living/new_owner, new_duration, new_target, new_target_gender, new_target_species)
+ if(!new_duration)
+ qdel(src)
+ return
+ duration = new_duration
+ . = ..()
+ target = new_target
+ target_gender = new_target_gender
+ target_species = new_target_species
+
+/datum/status_effect/staring/proc/catch_look(mob/living/opponent)
+ if(target == opponent)
+ to_chat(owner, span_notice("[opponent.name] catch your look!"))
+ to_chat(opponent, span_notice("[owner.name] catch your look!"))
+ var/list/loved_ones = list(MALE, FEMALE)
+ if(!ishuman(owner) || !(target_gender in loved_ones) || !(owner.gender in loved_ones))
+ return
+ var/mob/living/carbon/human/human_owner = owner
+ if(target_gender != human_owner.gender && target_species == human_owner.dna.species.name && prob(5))
+ owner.emote("blush")
+ to_chat(owner, span_danger("You feel something burning in your chest..."))
+
/datum/status_effect/high_five
id = "high_five"
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 06b48a8511a..a78ae6fc560 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1295,3 +1295,11 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
return TRUE
. = !density
+
+/atom/proc/get_examine_time() // Used only in /mob/living/carbon/human and /mob/living/simple_animal/hostile/morph
+ return 0 SECONDS
+
+
+/atom/proc/get_visible_gender() // Used only in /mob/living/carbon/human and /mob/living/simple_animal/hostile/morph
+ return gender
+
diff --git a/code/game/gamemodes/miniantags/morph/morph.dm b/code/game/gamemodes/miniantags/morph/morph.dm
index 51e98f457a1..ef9d680af3a 100644
--- a/code/game/gamemodes/miniantags/morph/morph.dm
+++ b/code/game/gamemodes/miniantags/morph/morph.dm
@@ -393,6 +393,19 @@
to_chat(src, chat_box_red(messages.Join("
")))
+
+/mob/living/simple_animal/hostile/morph/get_examine_time()
+ return morphed ? mimic_spell.selected_form.examine_time : ..()
+
+
+/mob/living/simple_animal/hostile/morph/get_visible_gender()
+ return morphed ? mimic_spell.selected_form.examine_gender : ..()
+
+
+/mob/living/simple_animal/hostile/morph/get_visible_species()
+ return morphed ? mimic_spell.selected_form.examine_species : ..()
+
+
#undef MORPHED_SPEED
#undef ITEM_EAT_COST
#undef MORPHS_ANNOUNCE_THRESHOLD
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 3f561ea3cec..1d8a1b58801 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -33,12 +33,8 @@
msg += "[bicon(icon(icon, dir=SOUTH))] " //fucking BYOND: this should stop dreamseeker crashing if we -somehow- examine somebody before their icon is generated
msg += "[name]"
- var/displayed_species = dna.species.name
+ var/displayed_species = get_visible_species()
var/examine_color = dna.species.flesh_color
- for(var/obj/item/clothing/C in src) //Disguise checks
- if(C == src.head || C == src.wear_suit || C == src.wear_mask || C == src.w_uniform || C == src.belt || C == src.back)
- if(C.species_disguise)
- displayed_species = C.species_disguise
if(skipjumpsuit && skipface || (NO_EXAMINE in dna.species.species_traits)) //either obscured or on the nospecies list
msg += "!\n" //omit the species when examining
else if(displayed_species == "Slime People") //snowflakey because Slime People are defined as a plural
@@ -428,6 +424,11 @@
. = list(msg)
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
+
+/mob/living/carbon/human/get_examine_time()
+ return 1 SECONDS
+
+
//Helper procedure. Called by /mob/living/carbon/human/examine() and /mob/living/carbon/human/Topic() to determine HUD access to security and medical records.
/proc/hasHUD(mob/M, hudtype)
if(istype(M, /mob/living/carbon/human))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 8a99c7a2941..cf7473f68f1 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1094,13 +1094,21 @@
return 0
return 1
-/mob/living/carbon/human/proc/get_visible_gender()
+/mob/living/carbon/human/get_visible_gender()
var/list/obscured = check_obscured_slots()
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDENAME)) || (head && (head.flags_inv & HIDENAME))
if((slot_w_uniform in obscured) && skipface)
return PLURAL
return gender
+/mob/living/carbon/human/get_visible_species()
+ var/displayed_species = dna.species.name
+ for(var/obj/item/clothing/C in src) //Disguise checks
+ if(C == head || C == wear_suit || C == wear_mask || C == w_uniform || C == belt || C == back)
+ if(C.species_disguise)
+ displayed_species = C.species_disguise
+ return displayed_species
+
/mob/living/carbon/human/proc/increase_germ_level(n)
if(gloves)
gloves.germ_level += n
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index e572c94c6f2..210c0a4738e 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1379,3 +1379,44 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
if(target_move)
remove_ventcrawl()
add_ventcrawl(loc, target_move)
+
+
+/mob/living/proc/get_visible_species() // Used only in /mob/living/carbon/human and /mob/living/simple_animal/hostile/morph
+ return "Unknown"
+
+
+/mob/living/run_examinate(atom/target)
+ var/datum/status_effect/staring/user_staring_effect = has_status_effect(STATUS_EFFECT_STARING)
+ if(user_staring_effect || hindered_inspection(target))
+ return
+
+ var/examine_time = target.get_examine_time()
+ face_atom(target)
+ if(examine_time && target != src)
+ var/visible_gender = target.get_visible_gender()
+ var/visible_species = "Unknown"
+
+ if(isliving(target))
+ var/mob/living/target_living = target
+ visible_species = target_living.get_visible_species()
+
+ if(ishuman(target)) // Yep. Only humans affected by catched looks.
+ var/datum/status_effect/staring/target_staring_effect = target_living.has_status_effect(STATUS_EFFECT_STARING)
+ if(target_staring_effect)
+ target_staring_effect.catch_look(src)
+
+ user_staring_effect = apply_status_effect(STATUS_EFFECT_STARING, examine_time, target, visible_gender, visible_species)
+ if(do_mob(src, target, examine_time, FALSE, list(CALLBACK(src, PROC_REF(hindered_inspection), target)), TRUE))
+ ..()
+ else
+ ..()
+
+
+/mob/living/proc/hindered_inspection(atom/target)
+ if(QDELETED(src) || QDELETED(target))
+ return TRUE
+ if(!has_vision(information_only = TRUE))
+ to_chat(src, span_notice("Здесь что-то есть, но вы не видите — что именно."))
+ return TRUE
+ return FALSE
+
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index e65e901721a..acbc42a4e38 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -306,11 +306,6 @@
DEFAULT_QUEUE_OR_CALL_VERB(VERB_CALLBACK(src, PROC_REF(run_examinate), A))
/mob/proc/run_examinate(atom/A)
- if(!has_vision(information_only = TRUE) && !isobserver(src))
- to_chat(src, chat_box_regular("Здесь что-то есть, но вы не видите — что именно."))
- return TRUE
-
- face_atom(A)
var/list/result = A.examine(src)
to_chat(src, chat_box_examine(result.Join("\n")))