Skip to content

Commit

Permalink
Allow multiple cloaking sources.
Browse files Browse the repository at this point in the history
Can now have rig cloaking, several magic rings, be a GAS, etc. without breaking cloaking.
Cloaking and uncloaking now has consistent messages for all sources.
  • Loading branch information
PsiOmegaDelta committed Oct 10, 2017
1 parent f56f930 commit e40213a
Show file tree
Hide file tree
Showing 14 changed files with 140 additions and 70 deletions.
5 changes: 5 additions & 0 deletions code/_helpers/functional.dm
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,8 @@

if(all_predicates_true(predicate_input, predicates))
. += entry

/proc/map(var/list/list_to_map, var/map_proc)
. = list()
for(var/entry in list_to_map)
. += call(map_proc)(entry)
4 changes: 4 additions & 0 deletions code/_macros.dm
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,16 @@
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } }
// Adds I to L, initalizing L if necessary
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
// Adds I to L, initalizing L if necessary, if I is not already in L
#define LAZYDISTINCTADD(L, I) if(!L) { L = list(); } L |= I;
// Sets L[A] to I, initalizing L if necessary
#define LAZYSET(L, A, I) if(!L) { L = list(); } L[A] = I;
// Reads I from L safely - Works with both associative and traditional lists.
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
// Reads the length of L, returning 0 if null
#define LAZYLEN(L) length(L)
// Safely checks if I is in L
#define LAZYISIN(L, I) (L ? (I in L) : FALSE)
// Null-safe L.Cut()
#define LAZYCLEARLIST(L) if(L) L.Cut()
// Reads L or an empty list if L is not a list. Note: Does NOT assign, L may be an expression.
Expand Down
11 changes: 10 additions & 1 deletion code/datums/weakref.dm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/datum
var/weakref/weakref
var/tmp/weakref/weakref

/datum/Destroy()
weakref = null // Clear this reference to ensure it's kept for as brief duration as possible.
Expand All @@ -18,8 +18,14 @@
/weakref
var/ref

// Handy info for debugging
var/tmp/ref_name
var/tmp/ref_type

/weakref/New(datum/D)
ref = "\ref[D]"
ref_name = "[D]"
ref_type = D.type

/weakref/Destroy()
// A weakref datum should not be manually destroyed as it is a shared resource,
Expand All @@ -31,3 +37,6 @@
if(D && D.weakref == src)
return D
return null

/weakref/get_log_info_line()
return "[ref_name] ([ref_type]) ([ref]) (WEAKREF)"
3 changes: 1 addition & 2 deletions code/game/machinery/camera/tracking.dm
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ mob/living/proc/near_camera()

/mob/living/proc/tracking_status()
// Easy checks first.
// Don't detect mobs on Centcom. Since the wizard den is on Centcomm, we only need this.
var/obj/item/weapon/card/id/id = GetIdCard()
if(id && id.prevent_tracking())
return TRACKING_TERMINATE
Expand All @@ -242,7 +241,7 @@ mob/living/proc/near_camera()
return camera && camera.can_use() ? TRACKING_POSSIBLE : TRACKING_NO_COVERAGE

/mob/living/carbon/human/tracking_status()
if(cloaked)
if(is_cloaked())
. = TRACKING_TERMINATE
else
. = ..()
Expand Down
14 changes: 5 additions & 9 deletions code/modules/clothing/rings/rings.dm
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,17 @@
desc = "A strange ring with symbols carved on it in some arcane language."
icon_state = "magic"

/obj/item/clothing/ring/magic/equipped(var/mob/living/carbon/human/H)
/obj/item/clothing/ring/magic/equipped(var/mob/living/carbon/human/H, var/slot)
..()
if(istype(H) && H.gloves==src)
H.cloaked = TRUE
H.update_icons()
H.visible_message("<span class='warning'>\[H.name] seems to disappear before your eyes!</span>", "<span class='notice'>You feel completely invisible.</span>")
if(istype(H) && slot == SLOT_GLOVES)
H.add_cloaking_source(src)

/obj/item/clothing/ring/magic/dropped(var/mob/living/carbon/human/H)
if(!..())
return 0

if(istype(H) && H.cloaked)
H.cloaked = FALSE
H.update_icons()
H.visible_message("<span class='warning'>\The [H] appears from thin air!</span>", "<span class='notice'>You have re-appeared.</span>")
if(istype(H))
H.remove_cloaking_source(src)

/////////////////////////////////////////
//Reagent Rings
Expand Down
4 changes: 4 additions & 0 deletions code/modules/clothing/spacesuits/rig/modules/modules.dm
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@
stat_modules += new/stat_rig_module/select(src)
stat_modules += new/stat_rig_module/charge(src)

/obj/item/rig_module/Destroy()
deactivate()
. = ..()

// Called when the module is installed into a suit.
/obj/item/rig_module/proc/installed(var/obj/item/weapon/rig/new_holder)
holder = new_holder
Expand Down
23 changes: 7 additions & 16 deletions code/modules/clothing/spacesuits/rig/modules/ninja.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,8 @@

var/mob/living/carbon/human/H = holder.wearer

to_chat(H, "<font color='blue'><b>You are now invisible to normal detection.</b></font>")
H.cloaked = TRUE
H.update_icons()

anim(get_turf(H), H, 'icons/effects/effects.dmi', "electricity",null,20,null)

H.visible_message("[H.name] vanishes into thin air!",1)
if(H.add_cloaking_source(src))
anim(get_turf(H), H, 'icons/effects/effects.dmi', "electricity",null,20,null)

/obj/item/rig_module/stealth_field/deactivate()

Expand All @@ -52,15 +47,11 @@

var/mob/living/carbon/human/H = holder.wearer

to_chat(H, "<span class='danger'>You are now visible.</span>")
H.cloaked = FALSE
H.update_icons()

anim(get_turf(H), H,'icons/mob/mob.dmi',,"uncloak",,H.dir)
anim(get_turf(H), H, 'icons/effects/effects.dmi', "electricity",null,20,null)

for(var/mob/O in oviewers(H))
O.show_message("[H.name] appears from thin air!",1)
if(H.remove_cloaking_source(src))
anim(get_turf(H), H,'icons/mob/mob.dmi',,"uncloak",,H.dir)
anim(get_turf(H), H, 'icons/effects/effects.dmi', "electricity",null,20,null)

// We still play the sound, even if not visibly uncloaking. Ninjas are not that stealthy.
playsound(get_turf(H), 'sound/effects/stealthoff.ogg', 75, 1)


Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/carbon/human/human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1429,7 +1429,7 @@
return ..() * (species ? species.metabolism_mod : 1)

/mob/living/carbon/human/is_invisible_to(var/mob/viewer)
return (cloaked || ..())
return (is_cloaked() || ..())

/mob/living/carbon/human/help_shake_act(mob/living/carbon/M)
if(src != M)
Expand Down
1 change: 0 additions & 1 deletion code/modules/mob/living/carbon/human/human_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@
var/datum/mil_rank/char_rank = null

var/stance_damage = 0 //Whether this mob's ability to stand has been affected
var/cloaked // If set, mob will only render its inhands, no other icons will be shown.

var/obj/machinery/machine_visual //machine that is currently applying visual effects to this mob. Only used for camera monitors currently.

Expand Down
63 changes: 63 additions & 0 deletions code/modules/mob/living/carbon/human/human_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,66 @@
else
qdel(G)
return 0

/mob/living/carbon/human
var/list/cloaking_sources

// Returns true if, and only if, the human has gone from uncloaked to cloaked
/mob/living/carbon/human/proc/add_cloaking_source(var/datum/cloaking_source)
var/has_uncloaked = clean_cloaking_sources()
LAZYDISTINCTADD(cloaking_sources, weakref(cloaking_source))

// We don't present the cloaking message if the human was already cloaked just before cleanup.
if(!has_uncloaked && LAZYLEN(cloaking_sources) == 1)
update_icons()
src.visible_message("<span class='warning'>\The [src] seems to disappear before your eyes!</span>", "<span class='notice'>You feel completely invisible.</span>")
return TRUE
return FALSE

#define CLOAK_APPEAR_OTHER "<span class='warning'>\The [src] appears from thin air!</span>"
#define CLOAK_APPEAR_SELF "<span class='notice'>You have re-appeared.</span>"

// Returns true if, and only if, the human has gone from cloaked to uncloaked
/mob/living/carbon/human/proc/remove_cloaking_source(var/datum/cloaking_source)
var/was_cloaked = LAZYLEN(cloaking_sources)
clean_cloaking_sources()
LAZYREMOVE(cloaking_sources, weakref(cloaking_source))

if(was_cloaked && !LAZYLEN(cloaking_sources))
update_icons()
visible_message(CLOAK_APPEAR_OTHER, CLOAK_APPEAR_SELF)
return TRUE
return FALSE

// Returns true if the human is cloaked, otherwise false (technically returns the number of cloaking sources)
/mob/living/carbon/human/proc/is_cloaked()
if(clean_cloaking_sources())
update_icons()
visible_message(CLOAK_APPEAR_OTHER, CLOAK_APPEAR_SELF)
return LAZYLEN(cloaking_sources)

#undef CLOAK_APPEAR_OTHER
#undef CLOAK_APPEAR_SELF

// Returns true if the human is cloaked by the given source
/mob/living/carbon/human/proc/is_cloaked_by(var/cloaking_source)
return LAZYISIN(cloaking_sources, weakref(cloaking_source))

// Returns true if this operation caused the mob to go from cloaked to uncloaked
/mob/living/carbon/human/proc/clean_cloaking_sources()
if(!cloaking_sources)
return FALSE

var/list/rogue_entries = list()
for(var/entry in cloaking_sources)
var/weakref/W = entry
if(!W.resolve())
cloaking_sources -= W
rogue_entries += W

if(rogue_entries.len) // These entries did not cleanup after themselves before being destroyed
var/rogue_entries_as_string = jointext(map(rogue_entries, /proc/log_info_line), ", ")
crash_with("[log_info_line(src)] - Following cloaking entries were removed during cleanup: [rogue_entries_as_string]")

UNSETEMPTY(cloaking_sources)
return !cloaking_sources // If cloaking_sources wasn't initially null but is now, we've uncloaked
69 changes: 37 additions & 32 deletions code/modules/mob/living/carbon/human/human_powers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -217,20 +217,37 @@
visible_message("<span class='warning'>\The [src] quivers slightly, then splits apart with a wet slithering noise.</span>")
qdel(src)

/mob/living/carbon/human/proc/nab()
set category = "Abilities"
set name = "Nab"
set desc = "Nab someone."
/mob/living/carbon/human/proc/can_nab(var/mob/living/target)
if(QDELETED(src))
return FALSE

if(last_special > world.time)
return
to_chat(src, "<span class='warning'>It is too soon to make another nab attempt.</span>")
return FALSE

if(incapacitated(INCAPACITATION_DISABLED) || buckled || pinned.len)
if(incapacitated())
to_chat(src, "<span class='warning'>You cannot nab in your current state.</span>")
return
return FALSE

if(!cloaked || pulling_punches)
if(!is_cloaked() || pulling_punches)
to_chat(src, "<span class='warning'>You can only nab people when you are well hidden and ready to hunt.</span>")
return FALSE

if(target)
if(!istype(target) || issilicon(target))
return FALSE
if(!Adjacent(target))
to_chat(src, "<span class='warning'>\The [target] has to be adjacent to you.</span>")
return FALSE

return TRUE

/mob/living/carbon/human/proc/nab()
set category = "Abilities"
set name = "Nab"
set desc = "Nab someone."

if(!can_nab())
return

var/list/choices = list()
Expand All @@ -239,18 +256,8 @@
choices += M
choices -= src

var/mob/living/T = input(src,"Who do you wish to nab?") as null|anything in choices

if(!T || !src || src.stat) return

if(!Adjacent(T)) return

//check again because we waited for user input
if(last_special > world.time)
return

if(incapacitated(INCAPACITATION_DISABLED) || buckled || pinned.len)
to_chat(src, "<span class='warning'>You cannot nab in your current state.</span>")
var/mob/living/T = input(src, "Who do you wish to nab?") as null|anything in choices
if(!T || !can_nab(T))
return

last_special = world.time + 50
Expand All @@ -260,33 +267,30 @@
to_chat(src, "<span class='warning'>You drop everything as you spring out to nab someone!.</span>")

playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
cloaked = 0
update_icons()
remove_cloaking_source(species)

if(prob(90) && src.make_grab(src, T, GRAB_NAB_SPECIAL))
T.Weaken(rand(1,3))
visible_message("<span class='danger'>[src] suddenly appears, lunging out and grabbing [T]!</span>")
visible_message("<span class='danger'>\The [src] suddenly lunges out and grabs \the [T]!</span>")
LAssailant = src

src.do_attack_animation(T)
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
return 1

else
visible_message("<span class='danger'>[src] suddenly appears, lunging and almost grabbing [T]!</span>")
visible_message("<span class='danger'>\The [src] suddenly lunges out, almost grabbing \the [T]!</span>")

/mob/living/carbon/human/proc/active_camo()
set category = "Abilities"
set name = "Active Camo"
set desc = "Camouflage yourself"
cloaked = !cloaked
if(cloaked)
apply_effect(2, STUN, 0)
to_chat(src, "<span class='notice'>You hold perfectly still, shifting your exterior to match the things around you.</span>")
else
visible_message("<span class='danger'>[src] suddenly appears!</span>")
update_icons()

if(is_cloaked_by(species))
remove_cloaking_source(species)
else
add_cloaking_source(species)
apply_effect(2, STUN, 0)

/mob/living/carbon/human/proc/switch_stance()
set category = "Abilities"
Expand All @@ -296,14 +300,15 @@
if(stat) return

to_chat(src, "<span class='notice'>You begin to adjust the fluids in your arms, dropping everything and getting ready to swap which set you're using.</span>")
var/hidden = cloaked
var/hidden = is_cloaked()
if(!hidden)
visible_message("[src] shifts \his arms.")

if(l_hand) unEquip(l_hand)
if(r_hand) unEquip(r_hand)

if(do_after(src, 30))
hidden = is_cloaked()
pulling_punches = !pulling_punches
nabbing = !pulling_punches

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,7 @@
/datum/species/nabber/handle_movement_delay_special(var/mob/living/carbon/human/H)
var/tally = 0

if(H.cloaked)
H.visible_message("<span class='danger'>[H] suddenly appears!</span>")
H.cloaked = 0

H.update_icons()
H.remove_cloaking_source(src)

var/obj/item/organ/internal/B = H.internal_organs_by_name[BP_BRAIN]
if(istype(B,/obj/item/organ/internal/brain/nabber))
Expand Down
3 changes: 1 addition & 2 deletions code/modules/mob/living/carbon/human/update_icons.dm
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,7 @@ Please contact me on #coderbus IRC. ~Carn x
overlays.Cut()

if (icon_update)

if(cloaked)
if(is_cloaked())

icon = 'icons/mob/human.dmi'
icon_state = "blank"
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
if ((incapacitation_flags & INCAPACITATION_STUNNED) && stunned)
return 1

if ((incapacitation_flags & INCAPACITATION_FORCELYING) && (weakened || resting))
if ((incapacitation_flags & INCAPACITATION_FORCELYING) && (weakened || resting || pinned.len))
return 1

if ((incapacitation_flags & INCAPACITATION_KNOCKOUT) && (stat || paralysis || sleeping || (status_flags & FAKEDEATH)))
Expand Down

0 comments on commit e40213a

Please sign in to comment.