diff --git a/code/__DEFINES/sight.dm b/code/__DEFINES/sight.dm
index ab70cb9895b..ae5f4e48352 100644
--- a/code/__DEFINES/sight.dm
+++ b/code/__DEFINES/sight.dm
@@ -1,3 +1,5 @@
+#define INVISIBILITY_NONE 0
+
#define SEE_INVISIBLE_MINIMUM 5
#define INVISIBILITY_LIGHTING 20
@@ -57,3 +59,19 @@
/// Bitfield of sight flags that show THINGS but no lighting
/// Since lighting is an underlay on turfs, this is everything but that
#define SEE_AVOID_TURF_BLACKNESS (SEE_MOBS|SEE_OBJS)
+
+//------------------------
+// INVISIBILITY PRIORITIES
+
+#define INVISIBILITY_PRIORITY_ADMIN 100
+#define INVISIBILITY_PRIORITY_BASIC_ANTI_INVISIBILITY 1
+#define INVISIBILITY_PRIORITY_NONE 0
+
+//------------------------
+// INVISIBILITY SOURCE IDS
+// Though don't feel the need to add one here if you have a simple effect that
+// gets added and/or removed in only one place near eachother in the code.
+
+#define INVISIBILITY_SOURCE_INVISIMIN "invisimin"
+#define INVISIBILITY_SOURCE_STEALTHMODE "stealthmode"
+
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index aa161690ceb..df98ab953fa 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -779,7 +779,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
/mob/dview
name = "INTERNAL DVIEW MOB"
- invisibility = 101
+ invisibility = INVISIBILITY_ABSTRACT
density = FALSE
move_resist = INFINITY
var/ready_to_die = FALSE
diff --git a/code/__HELPERS/spatial_info.dm b/code/__HELPERS/spatial_info.dm
index 033d5a60b79..5a0d5c3f002 100644
--- a/code/__HELPERS/spatial_info.dm
+++ b/code/__HELPERS/spatial_info.dm
@@ -18,7 +18,7 @@
icon_state = null
density = FALSE
move_resist = INFINITY
- invisibility = 0
+ invisibility = INVISIBILITY_NONE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
logging = null
held_items = null //all of these are list objects that should not exist for something like us
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 667611f1075..98c5c4d94a7 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -260,7 +260,7 @@
if(2 to INFINITY)
var/obj/dummy = new(get_turf(here))
dummy.pass_flags |= PASSTABLE
- dummy.invisibility = INVISIBILITY_ABSTRACT
+ dummy.SetInvisibility(INVISIBILITY_ABSTRACT)
for(var/i in 1 to reach) //Limit it to that many tries
var/turf/T = get_step(dummy, get_dir(dummy, there))
if(dummy.CanReach(there))
diff --git a/code/_onclick/hud/parallax/parallax.dm b/code/_onclick/hud/parallax/parallax.dm
index 8d4e68c911d..506226b41ea 100755
--- a/code/_onclick/hud/parallax/parallax.dm
+++ b/code/_onclick/hud/parallax/parallax.dm
@@ -360,7 +360,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_layer)
var/turf/posobj = get_turf(boss?.eye)
if(!posobj)
return
- invisibility = is_station_level(posobj.z) ? 0 : INVISIBILITY_ABSTRACT
+ SetInvisibility(is_station_level(posobj.z) ? INVISIBILITY_NONE : INVISIBILITY_ABSTRACT, id=type)
/atom/movable/screen/parallax_layer/planet/update_o()
return //Shit won't move
diff --git a/code/datums/elements/undertile.dm b/code/datums/elements/undertile.dm
index e1fdef4d413..ecc621a57e4 100644
--- a/code/datums/elements/undertile.dm
+++ b/code/datums/elements/undertile.dm
@@ -31,12 +31,14 @@
src.use_alpha = use_alpha
src.use_anchor = use_anchor
-
///called when a tile has been covered or uncovered
/datum/element/undertile/proc/hide(atom/movable/source, underfloor_accessibility)
SIGNAL_HANDLER
- source.invisibility = underfloor_accessibility < UNDERFLOOR_VISIBLE ? invisibility_level : 0
+ if(underfloor_accessibility < UNDERFLOOR_VISIBLE)
+ source.SetInvisibility(invisibility_level, id=type)
+ else
+ source.RemoveInvisibility(type)
var/turf/T = get_turf(source)
@@ -73,11 +75,10 @@
if(use_anchor)
source.set_anchored(FALSE)
-
/datum/element/undertile/Detach(atom/movable/source, visibility_trait, invisibility_level = INVISIBILITY_MAXIMUM)
. = ..()
hide(source, UNDERFLOOR_INTERACTABLE)
-
+ source.RemoveInvisibility(type)
#undef ALPHA_UNDERTILE
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index aafeb699ea7..e590fb66019 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -187,6 +187,9 @@
/// How this atom should react to having its astar blocking checked
var/can_astar_pass = CANASTARPASS_DENSITY
+ VAR_PRIVATE/list/invisibility_sources
+ VAR_PRIVATE/current_invisibility_priority = -INFINITY
+
/**
* Called when an atom is created in byond (built in engine proc)
*
@@ -2195,3 +2198,71 @@
segment = -segment
SEND_SIGNAL(src, COMSIG_ATOM_SPIN_ANIMATION, speed, loops, segments, segment)
do_spin_animation(speed, loops, segments, segment, parallel)
+
+#define INVISIBILITY_VALUE 1
+#define INVISIBILITY_PRIORITY 2
+
+/atom/proc/RecalculateInvisibility()
+ PRIVATE_PROC(TRUE)
+
+ if(!invisibility_sources)
+ current_invisibility_priority = -INFINITY
+ invisibility = initial(invisibility)
+ return
+
+ var/highest_priority
+ var/list/highest_priority_invisibility_data
+ for(var/entry in invisibility_sources)
+ var/list/priority_data
+ if(islist(entry))
+ priority_data = entry
+ else
+ priority_data = invisibility_sources[entry]
+
+ var/priority = priority_data[INVISIBILITY_PRIORITY]
+ if(highest_priority > priority) // In the case of equal priorities, we use the last thing in the list so that more recent changes apply first
+ continue
+
+ highest_priority = priority
+ highest_priority_invisibility_data = priority_data
+
+ current_invisibility_priority = highest_priority
+ invisibility = highest_priority_invisibility_data[INVISIBILITY_VALUE]
+
+/**
+ * Sets invisibility according to priority.
+ * If you want to be able to undo the value you set back to what it would be otherwise,
+ * you should provide an id here and remove it using RemoveInvisibility(id)
+ */
+/atom/proc/SetInvisibility(desired_value, id, priority=0)
+ if(!invisibility_sources)
+ invisibility_sources = list()
+
+ if(id)
+ invisibility_sources[id] = list(desired_value, priority)
+ else
+ invisibility_sources += list(list(desired_value, priority))
+
+ if(current_invisibility_priority > priority)
+ return
+
+ RecalculateInvisibility()
+
+/// Removes the specified invisibility source from the tracker
+/atom/proc/RemoveInvisibility(source_id)
+ if(!invisibility_sources)
+ return
+
+ var/list/priority_data = invisibility_sources[source_id]
+ invisibility_sources -= source_id
+
+ if(length(invisibility_sources) == 0)
+ invisibility_sources = null
+
+ if(current_invisibility_priority > priority_data[INVISIBILITY_PRIORITY])
+ return
+
+ RecalculateInvisibility()
+
+#undef INVISIBILITY_VALUE
+#undef INVISIBILITY_PRIORITY
diff --git a/code/game/machinery/gigabeacon.dm b/code/game/machinery/gigabeacon.dm
index b1e3b2f7cda..2154abffc11 100644
--- a/code/game/machinery/gigabeacon.dm
+++ b/code/game/machinery/gigabeacon.dm
@@ -13,7 +13,7 @@
. = ..()
var/turf/T = loc
Beacon = new(T)
- Beacon.invisibility = INVISIBILITY_MAXIMUM
+ Beacon.SetInvisibility(INVISIBILITY_MAXIMUM)
AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE)
@@ -25,6 +25,6 @@
if(QDELETED(Beacon)) //Don't move it out of nullspace BACK INTO THE GAME for the love of god
var/turf/T = loc
Beacon = new(T)
- Beacon.invisibility = INVISIBILITY_MAXIMUM
+ Beacon.SetInvisibility(INVISIBILITY_MAXIMUM)
else if (Beacon.loc != loc)
Beacon.forceMove(loc)
diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm
index cacecb6a684..cf4e4d1e7e7 100644
--- a/code/game/machinery/porta_turret/portable_turret.dm
+++ b/code/game/machinery/porta_turret/portable_turret.dm
@@ -326,7 +326,7 @@ DEFINE_BITFIELD(turret_flags, list(
//This code handles moving the turret around. After all, it's a portable turret!
if(!anchored && !isinspace())
set_anchored(TRUE)
- invisibility = INVISIBILITY_MAXIMUM
+ SetInvisibility(INVISIBILITY_MAXIMUM, id=type)
update_appearance()
to_chat(user, span_notice("You secure the exterior bolts on the turret."))
if(has_cover)
@@ -336,7 +336,7 @@ DEFINE_BITFIELD(turret_flags, list(
set_anchored(FALSE)
to_chat(user, span_notice("You unsecure the exterior bolts on the turret."))
power_change()
- invisibility = 0
+ RemoveInvisibility(type)
qdel(cover) //deletes the cover, and the turret instance itself becomes its own cover.
else if(I.GetID())
@@ -407,7 +407,7 @@ DEFINE_BITFIELD(turret_flags, list(
. = ..()
if(.)
power_change()
- invisibility = 0
+ RemoveInvisibility(type)
spark_system.start() //creates some sparks because they look cool
qdel(cover) //deletes the cover - no need on keeping it there!
@@ -514,7 +514,7 @@ DEFINE_BITFIELD(turret_flags, list(
return
if(machine_stat & BROKEN)
return
- invisibility = 0
+ RemoveInvisibility(type)
raising = 1
if(cover)
flick("popup", cover)
@@ -539,7 +539,7 @@ DEFINE_BITFIELD(turret_flags, list(
if(cover)
cover.icon_state = "turretCover"
raised = 0
- invisibility = 2
+ SetInvisibility(2, id=type)
update_appearance()
/obj/machinery/porta_turret/proc/assess_perp(mob/living/carbon/human/perp)
diff --git a/code/game/machinery/porta_turret/portable_turret_cover.dm b/code/game/machinery/porta_turret/portable_turret_cover.dm
index 86b1df20e7f..a4582875574 100644
--- a/code/game/machinery/porta_turret/portable_turret_cover.dm
+++ b/code/game/machinery/porta_turret/portable_turret_cover.dm
@@ -16,7 +16,7 @@
/obj/machinery/porta_turret_cover/Destroy()
if(parent_turret)
parent_turret.cover = null
- parent_turret.invisibility = 0
+ parent_turret.RemoveInvisibility(type)
parent_turret = null
return ..()
@@ -43,12 +43,12 @@
if(!parent_turret.anchored)
parent_turret.set_anchored(TRUE)
to_chat(user, span_notice("You secure the exterior bolts on the turret."))
- parent_turret.invisibility = 0
+ parent_turret.RemoveInvisibility(type)
parent_turret.update_appearance()
else
parent_turret.set_anchored(FALSE)
to_chat(user, span_notice("You unsecure the exterior bolts on the turret."))
- parent_turret.invisibility = INVISIBILITY_MAXIMUM
+ parent_turret.SetInvisibility(INVISIBILITY_MAXIMUM, id=type)
parent_turret.update_appearance()
qdel(src)
return
diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm
index f1cbc110a3e..ad6adae767c 100644
--- a/code/game/machinery/shieldgen.dm
+++ b/code/game/machinery/shieldgen.dm
@@ -130,9 +130,10 @@
/obj/structure/emergency_shield/cult/barrier/proc/Toggle()
set_density(!density)
air_update_turf(TRUE, !density)
- invisibility = initial(invisibility)
if(!density)
- invisibility = INVISIBILITY_OBSERVER
+ SetInvisibility(INVISIBILITY_OBSERVER, id=type)
+ else
+ RemoveInvisibility(type)
/obj/machinery/shieldgen
name = "anti-breach shielding projector"
diff --git a/code/game/objects/effects/countdown.dm b/code/game/objects/effects/countdown.dm
index f820397c0d9..1c7377bd50a 100644
--- a/code/game/objects/effects/countdown.dm
+++ b/code/game/objects/effects/countdown.dm
@@ -157,7 +157,7 @@
return round(time_left)
/obj/effect/countdown/arena
- invisibility = 0
+ invisibility = INVISIBILITY_NONE
name = "arena countdown"
/obj/effect/countdown/arena/get_value()
diff --git a/code/game/objects/effects/spawners/random/maintenance.dm b/code/game/objects/effects/spawners/random/maintenance.dm
index 5481123bbff..242613e403d 100644
--- a/code/game/objects/effects/spawners/random/maintenance.dm
+++ b/code/game/objects/effects/spawners/random/maintenance.dm
@@ -13,7 +13,7 @@
return ..()
/obj/effect/spawner/random/maintenance/proc/hide()
- invisibility = INVISIBILITY_OBSERVER
+ SetInvisibility(INVISIBILITY_OBSERVER)
alpha = 100
/obj/effect/spawner/random/maintenance/proc/get_effective_lootcount()
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index c42145ff2a7..3f698c5c08f 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -292,7 +292,7 @@
O.laws = M.laws
M.laws.associate(O)
- O.invisibility = 0
+ O.SetInvisibility(INVISIBILITY_NONE)
//Transfer debug settings to new mob
O.custom_name = created_name
O.locked = panel_locked
diff --git a/code/game/objects/structures/construction_console/construction_console.dm b/code/game/objects/structures/construction_console/construction_console.dm
index 5cf4a9bfd85..d33c91f7c07 100644
--- a/code/game/objects/structures/construction_console/construction_console.dm
+++ b/code/game/objects/structures/construction_console/construction_console.dm
@@ -80,12 +80,12 @@
/obj/machinery/computer/camera_advanced/base_construction/GrantActions(mob/living/user)
..()
//When the eye is in use, make it visible to players so they know when someone is building.
- eyeobj.invisibility = 0
+ SetInvisibility(INVISIBILITY_NONE, id=type)
/obj/machinery/computer/camera_advanced/base_construction/remove_eye_control(mob/living/user)
..()
- //Hide the eye when not in use.
- eyeobj.invisibility = INVISIBILITY_MAXIMUM
+ //Set back to default invisibility when not in use.
+ RemoveInvisibility(type)
/**
* A mob used by [/obj/machinery/computer/camera_advanced/base_construction] for building in specific areas.
@@ -101,6 +101,7 @@
move_on_shuttle = TRUE
icon = 'icons/obj/mining.dmi'
icon_state = "construction_drone"
+ invisibility = INVISIBILITY_MAXIMUM
///Reference to the camera console controlling this drone
var/obj/machinery/computer/camera_advanced/base_construction/linked_console
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 15297383a7b..3635c108cfd 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -395,16 +395,16 @@ GLOBAL_PROTECT(admin_verbs_poll)
set name = "Invisimin"
set category = "Admin.Game"
set desc = "Toggles ghost-like invisibility (Don't abuse this)"
- if(holder && mob)
- if(initial(mob.invisibility) == INVISIBILITY_OBSERVER)
- to_chat(mob, span_boldannounce("Invisimin toggle failed. You are already an invisible mob like a ghost."), confidential = TRUE)
- return
- if(mob.invisibility == INVISIBILITY_OBSERVER)
- mob.invisibility = initial(mob.invisibility)
- to_chat(mob, span_boldannounce("Invisimin off. Invisibility reset."), confidential = TRUE)
- else
- mob.invisibility = INVISIBILITY_OBSERVER
- to_chat(mob, span_adminnotice("Invisimin on. You are now as invisible as a ghost."), confidential = TRUE)
+ if(isnull(holder) || isnull(mob))
+ return
+ if(mob.invisimin)
+ mob.invisimin = FALSE
+ mob.RemoveInvisibility(INVISIBILITY_SOURCE_INVISIMIN)
+ to_chat(mob, span_boldannounce("Invisimin off. Invisibility reset."), confidential = TRUE)
+ else
+ mob.invisimin = TRUE
+ mob.SetInvisibility(INVISIBILITY_OBSERVER, INVISIBILITY_SOURCE_INVISIMIN, INVISIBILITY_PRIORITY_ADMIN)
+ to_chat(mob, span_adminnotice("Invisimin on. You are now as invisible as a ghost."), confidential = TRUE)
/client/proc/check_antagonists()
set name = "Check Antagonists"
@@ -550,7 +550,7 @@ GLOBAL_PROTECT(admin_verbs_poll)
holder.fakekey = new_key
createStealthKey()
if(isobserver(mob))
- mob.invisibility = INVISIBILITY_MAXIMUM //JUST IN CASE
+ mob.SetInvisibility(INVISIBILITY_ABSTRACT, INVISIBILITY_SOURCE_STEALTHMODE, INVISIBILITY_PRIORITY_ADMIN)
mob.alpha = 0 //JUUUUST IN CASE
mob.name = " "
mob.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
@@ -564,7 +564,7 @@ GLOBAL_PROTECT(admin_verbs_poll)
/client/proc/disable_stealth_mode()
holder.fakekey = null
if(isobserver(mob))
- mob.invisibility = initial(mob.invisibility)
+ mob.RemoveInvisibility(INVISIBILITY_SOURCE_STEALTHMODE)
mob.alpha = initial(mob.alpha)
if(mob.mind)
if(mob.mind.ghostname)
diff --git a/code/modules/antagonists/abductor/machinery/camera.dm b/code/modules/antagonists/abductor/machinery/camera.dm
index 685ae2d12db..36618e62269 100644
--- a/code/modules/antagonists/abductor/machinery/camera.dm
+++ b/code/modules/antagonists/abductor/machinery/camera.dm
@@ -25,7 +25,7 @@
eyeobj.visible_icon = TRUE
eyeobj.icon = 'icons/mob/silicon/cameramob.dmi'
eyeobj.icon_state = "abductor_camera"
- eyeobj.invisibility = INVISIBILITY_OBSERVER
+ eyeobj.SetInvisibility(INVISIBILITY_OBSERVER)
/obj/machinery/computer/camera_advanced/abductor/GrantActions(mob/living/carbon/user)
if(!abduct_created)
diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm
index d87574c092d..e56426a89ad 100644
--- a/code/modules/antagonists/blob/overmind.dm
+++ b/code/modules/antagonists/blob/overmind.dm
@@ -220,7 +220,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
check_area.icon = 'icons/mob/nonhuman-player/blob.dmi'
check_area.icon_state = "blob_shield"
check_area.layer = BELOW_MOB_LAYER
- check_area.invisibility = 0
+ check_area.SetInvisibility(INVISIBILITY_NONE)
check_area.blend_mode = 0
var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm
index 83dc308022c..eb6ccccd8b5 100644
--- a/code/modules/antagonists/changeling/powers/tiny_prick.dm
+++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm
@@ -21,7 +21,7 @@
changeling.chosen_sting = src
changeling.lingstingdisplay.icon_state = button_icon_state
- changeling.lingstingdisplay.invisibility = 0
+ changeling.lingstingdisplay.SetInvisibility(0, id=type)
/datum/action/changeling/sting/proc/unset_sting(mob/user)
to_chat(user, span_warning("We retract our sting, we can't sting anyone for now."))
@@ -29,7 +29,7 @@
changeling.chosen_sting = null
changeling.lingstingdisplay.icon_state = null
- changeling.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
+ changeling.lingstingdisplay.RemoveInvisibility(type)
/mob/living/carbon/proc/unset_sting()
if(mind)
diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm
index 0dd0d941aad..8ba039564da 100644
--- a/code/modules/antagonists/cult/cult_structures.dm
+++ b/code/modules/antagonists/cult/cult_structures.dm
@@ -63,7 +63,7 @@
/obj/structure/destructible/cult/proc/conceal()
set_density(FALSE)
visible_message(span_danger("[src] fades away."))
- invisibility = INVISIBILITY_OBSERVER
+ SetInvisibility(INVISIBILITY_OBSERVER, id=type)
alpha = 100
set_light_power(0)
set_light_range(0)
@@ -74,7 +74,7 @@
*/
/obj/structure/destructible/cult/proc/reveal()
set_density(initial(density))
- invisibility = 0
+ RemoveInvisibility(type)
visible_message(span_danger("[src] suddenly appears!"))
alpha = initial(alpha)
set_light_range(initial(light_range))
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index d343e331fad..1359a391043 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -118,11 +118,11 @@ Runes can either be invoked by one's self or with many different cultists. Each
/obj/effect/rune/proc/conceal() //for talisman of revealing/hiding
visible_message(span_danger("[src] fades away."))
- invisibility = INVISIBILITY_OBSERVER
+ SetInvisibility(INVISIBILITY_OBSERVER, id=type)
alpha = 100 //To help ghosts distinguish hidden runes
/obj/effect/rune/proc/reveal() //for talisman of revealing/hiding
- invisibility = 0
+ RemoveInvisibility(type)
visible_message(span_danger("[src] suddenly appears!"))
alpha = initial(alpha)
diff --git a/code/modules/antagonists/heretic/transmutation_rune.dm b/code/modules/antagonists/heretic/transmutation_rune.dm
index cd49feb3f17..f625e809432 100644
--- a/code/modules/antagonists/heretic/transmutation_rune.dm
+++ b/code/modules/antagonists/heretic/transmutation_rune.dm
@@ -171,7 +171,7 @@
// Some rituals may remove atoms from the selected_atoms list, and not consume them.
var/list/initial_selected_atoms = selected_atoms.Copy()
for(var/atom/to_disappear as anything in selected_atoms)
- to_disappear.invisibility = INVISIBILITY_ABSTRACT
+ to_disappear.SetInvisibility(INVISIBILITY_ABSTRACT, id=type)
// All the components have been invisibled, time to actually do the ritual. Call on_finished_recipe
// (Note: on_finished_recipe may sleep in the case of some rituals like summons, which expect ghost candidates.)
@@ -185,7 +185,7 @@
for(var/atom/to_appear as anything in initial_selected_atoms)
if(QDELETED(to_appear))
continue
- to_appear.invisibility = initial(to_appear.invisibility)
+ to_appear.RemoveInvisibility(type)
// And finally, give some user feedback
// No feedback is given on failure here -
diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm
index 3fc1de43b3c..a7a641bb884 100644
--- a/code/modules/assembly/infrared.dm
+++ b/code/modules/assembly/infrared.dm
@@ -113,7 +113,8 @@
beams += I
I.master = src
I.setDir(_dir)
- I.invisibility = visible? 0 : INVISIBILITY_ABSTRACT
+ if(!visible)
+ I.SetInvisibility(INVISIBILITY_ABSTRACT)
T = _T
_T = get_step(_T, _dir)
CHECK_TICK
diff --git a/code/modules/awaymissions/away_props.dm b/code/modules/awaymissions/away_props.dm
index 920287dd51e..f6d1a830a91 100644
--- a/code/modules/awaymissions/away_props.dm
+++ b/code/modules/awaymissions/away_props.dm
@@ -80,7 +80,10 @@
if(!istype(T))
return
//Simple way to keep plane conflicts away, could probably be upgraded to something less nuclear with 513
- T.invisibility = open ? 0 : INVISIBILITY_MAXIMUM
+ if(!open)
+ T.SetInvisibility(INVISIBILITY_MAXIMUM, id=type)
+ else
+ T.RemoveInvisibility(type)
/obj/structure/pitgrate/proc/toggle()
open = !open
diff --git a/code/modules/awaymissions/super_secret_room.dm b/code/modules/awaymissions/super_secret_room.dm
index 78d0b78150c..556a9fd63ad 100644
--- a/code/modules/awaymissions/super_secret_room.dm
+++ b/code/modules/awaymissions/super_secret_room.dm
@@ -28,7 +28,7 @@
if(0)
SpeakPeace(list("Welcome to the error handling room.","Something's goofed up bad to send you here.","You should probably tell an admin what you were doing, or make a bug report."))
for(var/obj/structure/signpost/salvation/sign in orange(7))
- sign.invisibility = 0
+ sign.SetInvisibility(INVISIBILITY_NONE)
var/datum/effect_system/fluid_spread/smoke/smoke = new
smoke.set_up(1, holder = src, location = sign.loc)
smoke.start()
diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm
index 8a10a058341..48621abfd1a 100644
--- a/code/modules/library/bibles.dm
+++ b/code/modules/library/bibles.dm
@@ -289,7 +289,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
make_new_altar(bible_smacked, user)
return
for(var/obj/effect/rune/nearby_runes in range(2, user))
- nearby_runes.invisibility = 0
+ nearby_runes.SetInvisibility(INVISIBILITY_NONE, id=type, priority=INVISIBILITY_PRIORITY_BASIC_ANTI_INVISIBILITY)
bible_smacked.balloon_alert(user, "floor smacked!")
if(user.mind?.holy_role)
diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm
index 20cbec1444b..64414f10501 100644
--- a/code/modules/mining/lavaland/megafauna_loot.dm
+++ b/code/modules/mining/lavaland/megafauna_loot.dm
@@ -651,7 +651,7 @@
/obj/item/melee/ghost_sword/Destroy()
for(var/mob/dead/observer/G in spirits)
- G.invisibility = GLOB.observer_default_invisibility
+ G.RemoveInvisibility(type)
spirits.Cut()
STOP_PROCESSING(SSobj, src)
. = ..()
@@ -690,10 +690,10 @@
continue
var/mob/dead/observer/G = i
ghost_counter++
- G.invisibility = 0
+ G.SetInvisibility(INVISIBILITY_NONE, id=type, priority=INVISIBILITY_PRIORITY_BASIC_ANTI_INVISIBILITY)
current_spirits |= G
for(var/mob/dead/observer/G in spirits - current_spirits)
- G.invisibility = GLOB.observer_default_invisibility
+ G.RemoveInvisibility(type)
spirits = current_spirits
return ghost_counter
diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm
index a6684a221ae..07079516fc1 100644
--- a/code/modules/mining/lavaland/tendril_loot.dm
+++ b/code/modules/mining/lavaland/tendril_loot.dm
@@ -1052,7 +1052,7 @@
/obj/item/cursed_katana/proc/cloak(mob/living/target, mob/user)
user.alpha = 150
- user.invisibility = INVISIBILITY_OBSERVER // so hostile mobs cant see us or target us
+ user.SetInvisibility(INVISIBILITY_OBSERVER, id=type) // so hostile mobs cant see us or target us
user.add_sight(SEE_SELF) // so we can see us
user.visible_message(span_warning("[user] vanishes into thin air!"),
span_notice("You enter the dark cloak."))
@@ -1066,7 +1066,7 @@
/obj/item/cursed_katana/proc/uncloak(mob/user)
user.alpha = 255
- user.invisibility = 0
+ user.RemoveInvisibility(type)
user.clear_sight(SEE_SELF)
user.visible_message(span_warning("[user] appears from thin air!"),
span_notice("You exit the dark cloak."))
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 8033d465a90..307e0f60261 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -1010,7 +1010,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/proc/set_invisibility(value)
- invisibility = value
+ SetInvisibility(value, id=type)
set_light_on(!value ? TRUE : FALSE)
diff --git a/code/modules/mob/living/basic/lavaland/bileworm/bileworm_actions.dm b/code/modules/mob/living/basic/lavaland/bileworm/bileworm_actions.dm
index b6f7468697a..9c5e2697f63 100644
--- a/code/modules/mob/living/basic/lavaland/bileworm/bileworm_actions.dm
+++ b/code/modules/mob/living/basic/lavaland/bileworm/bileworm_actions.dm
@@ -20,14 +20,14 @@
playsound(burrower, 'sound/effects/break_stone.ogg', 50, TRUE)
new /obj/effect/temp_visual/mook_dust(get_turf(burrower))
burrower.status_flags |= GODMODE
- burrower.invisibility = INVISIBILITY_MAXIMUM
+ burrower.SetInvisibility(INVISIBILITY_MAXIMUM, id=type)
burrower.forceMove(unburrow_turf)
//not that it's gonna die with godmode but still
SLEEP_CHECK_DEATH(rand(0.7 SECONDS, 1.2 SECONDS), burrower)
playsound(burrower, 'sound/effects/break_stone.ogg', 50, TRUE)
new /obj/effect/temp_visual/mook_dust(unburrow_turf)
burrower.status_flags &= ~GODMODE
- burrower.invisibility = 0
+ burrower.RemoveInvisibility(type)
/datum/action/cooldown/mob_cooldown/resurface/proc/get_unburrow_turf(mob/living/burrower, atom/target)
//we want the worm to try guaranteeing a hit on a living target if it thinks it can
@@ -105,14 +105,14 @@
playsound(devourer, 'sound/effects/break_stone.ogg', 50, TRUE)
new /obj/effect/temp_visual/mook_dust(get_turf(devourer))
devourer.status_flags |= GODMODE
- devourer.invisibility = INVISIBILITY_MAXIMUM
+ devourer.SetInvisibility(INVISIBILITY_MAXIMUM, id=type)
devourer.forceMove(devour_turf)
//not that it's gonna die with godmode but still
SLEEP_CHECK_DEATH(rand(0.7 SECONDS, 1.2 SECONDS), devourer)
playsound(devourer, 'sound/effects/break_stone.ogg', 50, TRUE)
new /obj/effect/temp_visual/mook_dust(devour_turf)
devourer.status_flags &= ~GODMODE
- devourer.invisibility = 0
+ devourer.RemoveInvisibility(type)
if(!(target in devour_turf))
to_chat(devourer, span_warning("Someone stole your dinner!"))
return
diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
index 526d268df03..856b5820b98 100644
--- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
+++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
@@ -302,7 +302,7 @@
span_revendanger("NO! No... it's too late, you can feel your essence [pick("breaking apart", "drifting away")]..."),
)
- invisibility = 0
+ SetInvisibility(INVISIBILITY_NONE, id=type)
icon_state = "revenant_draining"
playsound(src, 'sound/effects/screech.ogg', 100, TRUE)
@@ -428,7 +428,7 @@
draining = FALSE
dormant = FALSE
incorporeal_move = INCORPOREAL_MOVE_JAUNT
- invisibility = INVISIBILITY_REVENANT
+ RemoveInvisibility(type)
alpha = 255
/mob/living/basic/revenant/proc/change_essence_amount(essence_to_change_by, silent = FALSE, source = null)
diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm
index 0eeec231973..b7bc6e34dcf 100644
--- a/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm
+++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm
@@ -16,7 +16,7 @@
owner.orbiting?.end_orbit(src)
ADD_TRAIT(owner, TRAIT_REVENANT_REVEALED, TRAIT_STATUS_EFFECT(id))
- owner.invisibility = 0
+ owner.SetInvisibility(INVISIBILITY_NONE, id=type, priority=INVISIBILITY_PRIORITY_BASIC_ANTI_INVISIBILITY)
owner.incorporeal_move = FALSE
owner.update_appearance(UPDATE_ICON)
owner.update_mob_action_buttons()
@@ -25,7 +25,7 @@
REMOVE_TRAIT(owner, TRAIT_REVENANT_REVEALED, TRAIT_STATUS_EFFECT(id))
owner.incorporeal_move = INCORPOREAL_MOVE_JAUNT
- owner.invisibility = INVISIBILITY_REVENANT
+ owner.RemoveInvisibility(type)
owner.update_appearance(UPDATE_ICON)
owner.update_mob_action_buttons()
return ..()
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index 5a6746ec6fa..3f3809c89b2 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -112,7 +112,7 @@
new_xeno.key = ghost.key
SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention
new_xeno.add_traits(list(TRAIT_HANDS_BLOCKED, TRAIT_IMMOBILIZED, TRAIT_NO_TRANSFORM), type) //so we don't move during the bursting animation
- new_xeno.invisibility = INVISIBILITY_MAXIMUM
+ new_xeno.SetInvisibility(INVISIBILITY_MAXIMUM, id=type)
sleep(0.6 SECONDS)
@@ -122,7 +122,7 @@
if(!isnull(new_xeno))
new_xeno.remove_traits(list(TRAIT_HANDS_BLOCKED, TRAIT_IMMOBILIZED, TRAIT_NO_TRANSFORM), type)
- new_xeno.invisibility = 0
+ new_xeno.RemoveInvisibility(type)
if(gib_on_success)
new_xeno.visible_message(span_danger("[new_xeno] bursts out of [owner] in a shower of gore!"), span_userdanger("You exit [owner], your previous host."), span_hear("You hear organic matter ripping and tearing!"))
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index c409b84c4e2..d29c24021ff 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1399,7 +1399,7 @@
add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_NO_TRANSFORM), MAGIC_TRAIT)
icon = null
cut_overlays()
- invisibility = INVISIBILITY_ABSTRACT
+ SetInvisibility(INVISIBILITY_ABSTRACT)
var/list/item_contents = list()
@@ -1449,7 +1449,7 @@
if(issilicon(new_mob))
var/mob/living/silicon/robot/created_robot = new_mob
new_mob.gender = gender
- new_mob.invisibility = 0
+ new_mob.SetInvisibility(INVISIBILITY_NONE)
new_mob.job = JOB_CYBORG
created_robot.lawupdate = FALSE
created_robot.connected_ai = null
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index 6204ecdea60..416bbb19912 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -218,7 +218,10 @@
if(!eyeobj)
return
eyeobj.mouse_opacity = state ? MOUSE_OPACITY_ICON : initial(eyeobj.mouse_opacity)
- eyeobj.invisibility = state ? INVISIBILITY_OBSERVER : initial(eyeobj.invisibility)
+ if(state)
+ eyeobj.SetInvisibility(INVISIBILITY_OBSERVER, id=type)
+ else
+ eyeobj.RemoveInvisibility(type)
/mob/living/silicon/ai/verb/toggle_acceleration()
set category = "AI Commands"
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index c5aac5f526e..6808728a833 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -214,3 +214,6 @@
var/active_thinking_indicator
/// User is thinking in character. Used to revert to thinking state after stop_typing
var/thinking_IC = FALSE
+
+ /// Whether invisimin is enabled on this mob
+ var/invisimin = FALSE
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 290177f5baf..1caf5e9f1ea 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -20,9 +20,11 @@
Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE)
icon = null
cut_overlays()
- invisibility = INVISIBILITY_MAXIMUM
- new /obj/effect/temp_visual/monkeyify(loc)
+ var/obj/effect = new /obj/effect/temp_visual/monkeyify(loc)
+ effect.SetInvisibility(invisibility)
+ SetInvisibility(INVISIBILITY_MAXIMUM, id=type)
+
transformation_timer = addtimer(CALLBACK(src, PROC_REF(finish_monkeyize)), TRANSFORMATION_DURATION, TIMER_UNIQUE)
/mob/living/carbon/proc/finish_monkeyize()
@@ -30,7 +32,7 @@
to_chat(src, span_boldnotice("You are now a monkey."))
REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT)
icon = initial(icon)
- invisibility = 0
+ RemoveInvisibility(type)
set_species(/datum/species/monkey)
name = "monkey"
set_name()
@@ -57,9 +59,11 @@
Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE)
icon = null
cut_overlays()
- invisibility = INVISIBILITY_MAXIMUM
- new /obj/effect/temp_visual/monkeyify/humanify(loc)
+ var/obj/effect = new /obj/effect/temp_visual/monkeyify/humanify(loc)
+ effect.SetInvisibility(invisibility)
+ SetInvisibility(INVISIBILITY_MAXIMUM, id=type)
+
transformation_timer = addtimer(CALLBACK(src, PROC_REF(finish_humanize), species), TRANSFORMATION_DURATION, TIMER_UNIQUE)
/mob/living/carbon/proc/finish_humanize(species = /datum/species/human)
@@ -67,7 +71,7 @@
to_chat(src, span_boldnotice("You are now a human."))
REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT)
icon = initial(icon)
- invisibility = 0
+ RemoveInvisibility(type)
set_species(species)
SEND_SIGNAL(src, COMSIG_MONKEY_HUMANIZE)
return src
@@ -117,7 +121,7 @@
dropItemToGround(W)
regenerate_icons()
icon = null
- invisibility = INVISIBILITY_MAXIMUM
+ SetInvisibility(INVISIBILITY_MAXIMUM)
return ..()
/mob/living/carbon/human/AIize(client/preference_source, transfer_after = TRUE)
@@ -135,7 +139,7 @@
var/mob/living/silicon/robot/new_borg = new /mob/living/silicon/robot(loc)
new_borg.gender = gender
- new_borg.invisibility = 0
+ new_borg.SetInvisibility(INVISIBILITY_NONE)
if(client)
new_borg.updatename(client)
@@ -176,7 +180,7 @@
dropItemToGround(W)
regenerate_icons()
icon = null
- invisibility = INVISIBILITY_MAXIMUM
+ SetInvisibility(INVISIBILITY_MAXIMUM)
REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT)
return ..()
@@ -201,7 +205,7 @@
dropItemToGround(W)
regenerate_icons()
icon = null
- invisibility = INVISIBILITY_MAXIMUM
+ SetInvisibility(INVISIBILITY_MAXIMUM)
for(var/t in bodyparts)
qdel(t)
@@ -231,7 +235,7 @@
dropItemToGround(W)
regenerate_icons()
icon = null
- invisibility = INVISIBILITY_MAXIMUM
+ SetInvisibility(INVISIBILITY_MAXIMUM)
for(var/t in bodyparts)
qdel(t)
@@ -270,7 +274,7 @@
dropItemToGround(W)
regenerate_icons()
icon = null
- invisibility = INVISIBILITY_MAXIMUM
+ SetInvisibility(INVISIBILITY_MAXIMUM)
for(var/t in bodyparts) //this really should not be necessary
qdel(t)
@@ -297,7 +301,7 @@
regenerate_icons()
icon = null
- invisibility = INVISIBILITY_MAXIMUM
+ SetInvisibility(INVISIBILITY_MAXIMUM)
var/mob/living/basic/gorilla/new_gorilla = new (get_turf(src))
new_gorilla.set_combat_mode(TRUE)
if(mind)
@@ -328,7 +332,7 @@
regenerate_icons()
icon = null
- invisibility = INVISIBILITY_MAXIMUM
+ SetInvisibility(INVISIBILITY_MAXIMUM)
for(var/t in bodyparts)
qdel(t)
diff --git a/code/modules/point/point.dm b/code/modules/point/point.dm
index 3a3d97e2565..6e61b1154d5 100644
--- a/code/modules/point/point.dm
+++ b/code/modules/point/point.dm
@@ -77,7 +77,7 @@
abstract_move(get_turf(src))
pixel_x = old_loc.pixel_x
pixel_y = old_loc.pixel_y
- invisibility = set_invis
+ SetInvisibility(set_invis)
#undef POINT_TIME
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index e11e6bf9156..1f9348ffa4b 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -149,7 +149,7 @@
#ifdef DOCKING_PORT_HIGHLIGHT
//Debug proc used to highlight bounding area
/obj/docking_port/proc/highlight(_color = "#f00")
- invisibility = 0
+ SetInvisibility(INVISIBILITY_NONE)
SET_PLANE_IMPLICIT(src, GHOST_PLANE)
var/list/L = return_coords()
var/turf/T0 = locate(L[1],L[2],z)
diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm
index 4ac13b8dd64..f1c7bac4f81 100644
--- a/code/modules/vehicles/mecha/combat/durand.dm
+++ b/code/modules/vehicles/mecha/combat/durand.dm
@@ -233,7 +233,7 @@ own integrity back to max. Shield is automatically dropped if we run out of powe
set_light_on(chassis.defense_mode)
if(chassis.defense_mode)
- invisibility = 0
+ SetInvisibility(INVISIBILITY_NONE, id=type)
flick("shield_raise", src)
playsound(src, 'sound/mecha/mech_shield_raise.ogg', 50, FALSE)
icon_state = "shield"
@@ -256,7 +256,7 @@ own integrity back to max. Shield is automatically dropped if we run out of powe
*/
/obj/durand_shield/proc/make_invisible()
if(!chassis.defense_mode)
- invisibility = INVISIBILITY_MAXIMUM
+ RemoveInvisibility(type)
/obj/durand_shield/proc/resetdir(datum/source, olddir, newdir)
SIGNAL_HANDLER