diff --git a/code/__DEFINES/fov.dm b/code/__DEFINES/fov.dm
index 164dd1ead99..d35d30cdfea 100644
--- a/code/__DEFINES/fov.dm
+++ b/code/__DEFINES/fov.dm
@@ -10,6 +10,9 @@
/// Range at which FOV effects treat nearsightness as blind and play
#define NEARSIGHTNESS_FOV_BLINDNESS 2
+/// Range in tiles that a mob can see in the dark (used to determine if a mob has night_vision)
+#define NIGHTVISION_FOV_RANGE 8
+
//Fullscreen overlay resolution in tiles for the clients view.
/// The fullscreen overlay in tiles for x axis
#define FULLSCREEN_OVERLAY_RESOLUTION_X 15
diff --git a/code/modules/antagonists/blob/blob_mobs.dm b/code/modules/antagonists/blob/blob_mobs.dm
index 4a6aaecda03..457da47373f 100644
--- a/code/modules/antagonists/blob/blob_mobs.dm
+++ b/code/modules/antagonists/blob/blob_mobs.dm
@@ -15,7 +15,7 @@
maxbodytemp = INFINITY
unique_name = 1
combat_mode = TRUE
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
initial_language_holder = /datum/language_holder/empty
retreat_distance = null //! retreat doesn't obey pass_flags, so won't work on blob mobs.
diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm
index c0c92f1d986..f2d28f9c6f1 100644
--- a/code/modules/antagonists/blob/overmind.dm
+++ b/code/modules/antagonists/blob/overmind.dm
@@ -13,7 +13,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
icon_state = "marker"
mouse_opacity = MOUSE_OPACITY_ICON
move_on_shuttle = 1
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
invisibility = INVISIBILITY_OBSERVER
layer = FLY_LAYER
plane = ABOVE_GAME_PLANE
diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm
index 5b2513dd6b1..60410a9fcc4 100644
--- a/code/modules/antagonists/disease/disease_mob.dm
+++ b/code/modules/antagonists/disease/disease_mob.dm
@@ -15,7 +15,7 @@ the new instance inside the host to be updated to the template's stats.
icon_state = "marker"
mouse_opacity = MOUSE_OPACITY_ICON
move_on_shuttle = FALSE
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
invisibility = INVISIBILITY_OBSERVER
see_invisible = SEE_INVISIBLE_LIVING
layer = BELOW_MOB_LAYER
diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm
index 1016c0b64db..112c73bcfcf 100644
--- a/code/modules/antagonists/morph/morph.dm
+++ b/code/modules/antagonists/morph/morph.dm
@@ -20,7 +20,7 @@
obj_damage = 50
melee_damage_lower = 20
melee_damage_upper = 20
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
vision_range = 1 // Only attack when target is close
wander = FALSE
diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm
index f72a5716eb0..4b24727df6f 100644
--- a/code/modules/antagonists/revenant/revenant.dm
+++ b/code/modules/antagonists/revenant/revenant.dm
@@ -26,7 +26,7 @@
sight = SEE_SELF
throwforce = 0
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
response_help_continuous = "passes through"
response_help_simple = "pass through"
diff --git a/code/modules/antagonists/slaughter/slaughter.dm b/code/modules/antagonists/slaughter/slaughter.dm
index d9dabfe9e85..b1414bdefb2 100644
--- a/code/modules/antagonists/slaughter/slaughter.dm
+++ b/code/modules/antagonists/slaughter/slaughter.dm
@@ -35,7 +35,7 @@
obj_damage = 40
melee_damage_lower = 10
melee_damage_upper = 15
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
del_on_death = TRUE
deathmessage = "screams in agony as it sublimates into a sulfurous smoke."
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 0f56092ba62..8df343607cb 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -22,7 +22,7 @@
status_flags = CANSTUN|CANPUSH
combat_mode = TRUE //so we always get pushed instead of trying to swap
sight = SEE_TURFS | SEE_MOBS | SEE_OBJS
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
hud_type = /datum/hud/ai
med_hud = DATA_HUD_MEDICAL_BASIC
sec_hud = DATA_HUD_SECURITY_BASIC
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 69e28e45cab..d13a4b92f41 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -6,7 +6,7 @@
verb_exclaim = "declares"
verb_yell = "alarms"
initial_language_holder = /datum/language_holder/synthetic
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
bubble_icon = "machine"
mob_biotypes = MOB_ROBOTIC
deathsound = 'sound/voice/borg_deathsound.ogg'
diff --git a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm
index 2bc9517b8d1..1a481faa2b7 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm
@@ -24,7 +24,7 @@
carp_fluff_string = "CARP CARP CARP! Caught one, it's a ranged carp. This fishy can watch people pee in the ocean."
miner_fluff_string = "You encounter... Diamond, a powerful projectile thrower."
see_invisible = SEE_INVISIBLE_LIVING
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
toggle_button_type = /atom/movable/screen/guardian/toggle_mode
var/list/snares = list()
var/toggle = FALSE
diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm
index 5bc63d3fd7a..e37b89e7062 100644
--- a/code/modules/mob/living/simple_animal/hostile/alien.dm
+++ b/code/modules/mob/living/simple_animal/hostile/alien.dm
@@ -28,7 +28,7 @@
status_flags = CANPUSH
minbodytemp = 0
unsuitable_heat_damage = 20
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
unique_name = 1
gold_core_spawnable = NO_SPAWN
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index bee7adcdee7..52fe48915c0 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -44,7 +44,7 @@
unique_name = 1
gold_core_spawnable = HOSTILE_SPAWN
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
footstep_type = FOOTSTEP_MOB_CLAW
///How much of a reagent the mob injects on attack
var/poison_per_bite = 0
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
index 6491af064aa..9c6b6432c93 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
@@ -276,7 +276,7 @@
weather_immunities = list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE)
obj_damage = 30
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
diff --git a/code/modules/mob/living/simple_animal/hostile/skeleton.dm b/code/modules/mob/living/simple_animal/hostile/skeleton.dm
index c4ee66f3efa..e0241f672c7 100644
--- a/code/modules/mob/living/simple_animal/hostile/skeleton.dm
+++ b/code/modules/mob/living/simple_animal/hostile/skeleton.dm
@@ -29,7 +29,7 @@
robust_searching = 1
stat_attack = HARD_CRIT
faction = list("skeleton")
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
deathmessage = "collapses into a pile of bones!"
del_on_death = 1
diff --git a/code/modules/mob/living/simple_animal/hostile/smspider.dm b/code/modules/mob/living/simple_animal/hostile/smspider.dm
index 32651a43946..91b65eac315 100644
--- a/code/modules/mob/living/simple_animal/hostile/smspider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/smspider.dm
@@ -25,7 +25,7 @@
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
robust_searching = 1
faction = list("hostile")
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
deathmessage = "falls to the ground, its shard dulling to a miserable grey!"
footstep_type = FOOTSTEP_MOB_CLAW
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 8ccb075e757..3c419ae671c 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -555,7 +555,7 @@
sight = initial(sight)
else
sight = (SEE_TURFS|SEE_MOBS|SEE_OBJS)
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
see_invisible = SEE_INVISIBLE_OBSERVER
return
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 4c1dadf6063..eb34b11844c 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -30,7 +30,7 @@
healable = 0
melee_damage_lower = 5
melee_damage_upper = 25
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
verb_say = "blorbles"
verb_ask = "inquisitively blorbles"
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index bd271909050..93e12e45289 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1087,11 +1087,20 @@
if(client.mouse_override_icon)
client.mouse_pointer_icon = client.mouse_override_icon
+/**
+ * Can this mob see in the dark
+ *
+ * This checks all traits, glasses, and robotic eyeball implants to see if the mob can see in the dark
+ * this does NOT check if the mob is missing it's eyeballs. Also see_in_dark is a BYOND mob var (that defaults to 2)
+**/
+/mob/proc/has_nightvision()
+ return see_in_dark >= NIGHTVISION_FOV_RANGE
///This mob is abile to read books
/mob/proc/is_literate()
return FALSE
-///Can this mob read (is literate and not blind)
+
+/// Can this mob read
/mob/proc/can_read(obj/O)
if(is_blind())
to_chat(src, span_warning("As you are trying to read [O], you suddenly feel very stupid!"))
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index 86c73e8c6a4..ba1a6fced74 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -108,7 +108,7 @@
/obj/item/organ/eyes/night_vision
name = "shadow eyes"
desc = "A spooky set of eyes that can see in the dark."
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
actions_types = list(/datum/action/item_action/organ_action/use)
var/night_vision = TRUE
@@ -183,7 +183,7 @@
name = "\improper X-ray eyes"
desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile."
eye_color = "000"
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
sight_flags = SEE_MOBS | SEE_OBJS | SEE_TURFS
/obj/item/organ/eyes/robotic/thermals
@@ -193,7 +193,7 @@
sight_flags = SEE_MOBS
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
flash_protect = FLASH_PROTECTION_SENSITIVE
- see_in_dark = 8
+ see_in_dark = NIGHTVISION_FOV_RANGE
/obj/item/organ/eyes/robotic/flashlight
name = "flashlight eyes"