[MIRROR] Invisibility refactor [MDB IGNORE] (#24405)

* Invisibility refactor (#78908)

This adds a tracker for sources of invisibility and a priority system. I
needed this for another thing so I'm doing this first since it touches a
lot of code. As for the bugs fixed in the changelog, it's only what I
noticed while going through everything and there's likely a few more
things fixed with this. This should be testmerged for a while, I'll
bring this out of draft when it feels safe.

🆑
admin: Invisimin can now be used on mobs that are already invisible,
whether through temporary or permanent effects.
fix: Monkeyize/Humanize mob transformations no longer permanently reveal
invisible mobs if they had effects making them invisible otherwise.
fix: Objects with the undertile element that have been made invisible
through other means are no longer revealed by being uncovered.
/🆑

* Invisibility refactor

---------

Co-authored-by: Emmett Gaines <ninjanomnom@gmail.com>
This commit is contained in:
SkyratBot
2023-10-18 06:36:09 +02:00
committed by GitHub
parent 2aafba9975
commit 6e677a2bbd
40 changed files with 195 additions and 89 deletions

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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))

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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"

View File

@@ -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()

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -391,16 +391,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("<b>Invisimin on. You are now as invisible as a ghost.</b>"), 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("<b>Invisimin on. You are now as invisible as a ghost.</b>"), confidential = TRUE)
/client/proc/check_antagonists()
set name = "Check Antagonists"
@@ -546,7 +546,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
@@ -560,7 +560,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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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))

View File

@@ -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)

View File

@@ -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 -

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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)

View File

@@ -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

View File

@@ -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."))

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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 ..()

View File

@@ -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!"))

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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