diff --git a/code/__defines/gamemode.dm b/code/__defines/gamemode.dm
index 8115790c50..cd0c9955c1 100644
--- a/code/__defines/gamemode.dm
+++ b/code/__defines/gamemode.dm
@@ -123,4 +123,6 @@ var/list/be_special_flags = list(
//casting costs
#define Sp_RECHARGE "recharge"
#define Sp_CHARGES "charges"
-#define Sp_HOLDVAR "holdervar"
\ No newline at end of file
+#define Sp_HOLDVAR "holdervar"
+
+#define CHANGELING_STASIS_COST 20
\ No newline at end of file
diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm
index 1531a67d5b..b59857c8f6 100644
--- a/code/_helpers/game.dm
+++ b/code/_helpers/game.dm
@@ -284,7 +284,7 @@
if(M.loc && M.locs[1] in hearturfs)
mobs |= M
- else if(M.stat == DEAD)
+ else if(M.stat == DEAD && !M.forbid_seeing_deadchat)
switch(type)
if(1) //Audio messages use ghost_ears
if(M.is_preference_enabled(/datum/client_preference/ghost_ears))
diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm
index 2234e0a540..c7a95e551d 100644
--- a/code/game/gamemodes/changeling/changeling_powers.dm
+++ b/code/game/gamemodes/changeling/changeling_powers.dm
@@ -21,6 +21,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
var/armor_deployed = 0 //This is only used for changeling_generic_equip_all_slots() at the moment.
var/recursive_enhancement = 0 //Used to power up other abilities from the ling power with the same name.
var/list/purchased_powers_history = list() //Used for round-end report, includes respec uses too.
+ var/last_shriek = null // world.time when the ling last used a shriek.
/datum/changeling/New(var/gender=FEMALE)
..()
diff --git a/code/game/gamemodes/changeling/generic_equip_procs.dm b/code/game/gamemodes/changeling/generic_equip_procs.dm
index e8ed12a446..9c73a4e3d2 100644
--- a/code/game/gamemodes/changeling/generic_equip_procs.dm
+++ b/code/game/gamemodes/changeling/generic_equip_procs.dm
@@ -32,7 +32,7 @@
return 1
if(M.head || M.wear_suit) //Make sure our slots aren't full
- src << "We require nothing to be on our head, and we cannot wear any external suits."
+ src << "We require nothing to be on our head, and we cannot wear any external suits, or shoes."
return 0
var/obj/item/clothing/suit/A = new armor_type(src)
@@ -140,7 +140,7 @@
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["w_uniform"]
if(!M.w_uniform && t)
@@ -150,7 +150,7 @@
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["gloves"]
if(!M.gloves && t)
@@ -160,7 +160,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["shoes"]
if(!M.shoes && t)
@@ -170,7 +170,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["belt"]
if(!M.belt && t)
@@ -180,7 +180,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["glasses"]
if(!M.glasses && t)
@@ -190,7 +190,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["wear_mask"]
if(!M.wear_mask && t)
@@ -200,7 +200,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["back"]
if(!M.back && t)
@@ -210,7 +210,7 @@
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["wear_suit"]
if(!M.wear_suit && t)
@@ -220,7 +220,7 @@
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["wear_id"]
if(!M.wear_id && t)
@@ -230,7 +230,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
var/feedback = english_list(grown_items_list, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
diff --git a/code/game/gamemodes/changeling/powers/fabricate_clothing.dm b/code/game/gamemodes/changeling/powers/fabricate_clothing.dm
index f106d9167f..138cd156e3 100644
--- a/code/game/gamemodes/changeling/powers/fabricate_clothing.dm
+++ b/code/game/gamemodes/changeling/powers/fabricate_clothing.dm
@@ -18,7 +18,7 @@ var/global/list/changeling_fabricated_clothing = list(
helptext = "The disguise we create offers no defensive ability. Each equipment slot that is empty will be filled with fabricated equipment. \
To remove our new fabricated clothing, use this ability again."
ability_icon_state = "ling_fabricate_clothing"
- genomecost = 2
+ genomecost = 1
verbpath = /mob/proc/changeling_fabricate_clothing
//Grows biological versions of chameleon clothes.
diff --git a/code/game/gamemodes/changeling/powers/fake_death.dm b/code/game/gamemodes/changeling/powers/fake_death.dm
index dee603fc4a..765dbb51e6 100644
--- a/code/game/gamemodes/changeling/powers/fake_death.dm
+++ b/code/game/gamemodes/changeling/powers/fake_death.dm
@@ -12,7 +12,7 @@
set category = "Changeling"
set name = "Regenerative Stasis (20)"
- var/datum/changeling/changeling = changeling_power(20,1,100,DEAD)
+ var/datum/changeling/changeling = changeling_power(CHANGELING_STASIS_COST,1,100,DEAD)
if(!changeling)
return
@@ -28,6 +28,7 @@
C.update_canmove()
C.remove_changeling_powers()
+ changeling.chem_charges -= CHANGELING_STASIS_COST
if(C.suiciding)
C.suiciding = 0
@@ -35,7 +36,9 @@
if(C.stat != DEAD)
C.adjustOxyLoss(C.maxHealth * 2)
- spawn(rand(800,2000))
+ C.forbid_seeing_deadchat = TRUE
+
+ spawn(rand(2 MINUTES, 4 MINUTES))
//The ling will now be able to choose when to revive
src.verbs += /mob/proc/changeling_revive
src << "We are ready to rise. Use the Revive verb when you are ready."
diff --git a/code/game/gamemodes/changeling/powers/respec.dm b/code/game/gamemodes/changeling/powers/respec.dm
index d984083aba..66f13e720f 100644
--- a/code/game/gamemodes/changeling/powers/respec.dm
+++ b/code/game/gamemodes/changeling/powers/respec.dm
@@ -29,6 +29,3 @@
src << "We have removed our evolutions from this form, and are now ready to readapt."
ling_datum.purchased_powers_history.Add("Re-adapt (Reset to [ling_datum.max_geneticpoints])")
-
- //Now to lose the verb, so no unlimited resets.
-
diff --git a/code/game/gamemodes/changeling/powers/revive.dm b/code/game/gamemodes/changeling/powers/revive.dm
index 2f0b9c57e7..bbfce11415 100644
--- a/code/game/gamemodes/changeling/powers/revive.dm
+++ b/code/game/gamemodes/changeling/powers/revive.dm
@@ -48,6 +48,7 @@
C.mind.changeling.purchased_powers -= C
feedback_add_details("changeling_powers","CR")
C.stat = CONSCIOUS
+ C.forbid_seeing_deadchat = FALSE
C.timeofdeath = null
src.verbs -= /mob/proc/changeling_revive
// re-add our changeling powers
diff --git a/code/game/gamemodes/changeling/powers/shriek.dm b/code/game/gamemodes/changeling/powers/shriek.dm
index ded66148fa..37e7f67fe0 100644
--- a/code/game/gamemodes/changeling/powers/shriek.dm
+++ b/code/game/gamemodes/changeling/powers/shriek.dm
@@ -35,6 +35,14 @@
src << "You can't speak!"
return 0
+ if(world.time < (changeling.last_shriek + 10 SECONDS) )
+ to_chat(src, "We are still recovering from our last shriek...")
+ return 0
+
+ if(!isturf(loc))
+ to_chat(src, "Shrieking here would be a bad idea.")
+ return 0
+
src.break_cloak() //No more invisible shrieking
changeling.chem_charges -= 20
@@ -47,6 +55,8 @@
message_admins("[key_name(src)] used Resonant Shriek ([src.x],[src.y],[src.z]) (JMP).")
log_game("[key_name(src)] used Resonant Shriek.")
+ visible_message("[src] appears to shout.")
+
for(var/mob/living/M in range(range, src))
if(iscarbon(M))
if(!M.mind || !M.mind.changeling)
@@ -73,11 +83,7 @@
L.on = 1
L.broken()
-/* src.verbs -= /mob/proc/changeling_resonant_shriek
- spawn(30 SECONDS)
- src << "We are ready to use our resonant shriek once more."
- src.verbs |= /mob/proc/changeling_resonant_shriek
-Ability Cooldowns don't work properly right now, need to redo this when they are */
+ changeling.last_shriek = world.time
feedback_add_details("changeling_powers","RS")
return 1
@@ -101,6 +107,14 @@ Ability Cooldowns don't work properly right now, need to redo this when they are
src << "You can't speak!"
return 0
+ if(world.time < (changeling.last_shriek + 10 SECONDS) )
+ to_chat(src, "We are still recovering from our last shriek...")
+ return 0
+
+ if(!isturf(loc))
+ to_chat(src, "Shrieking here would be a bad idea.")
+ return 0
+
src.break_cloak() //No more invisible shrieking
changeling.chem_charges -= 20
@@ -117,6 +131,8 @@ Ability Cooldowns don't work properly right now, need to redo this when they are
src << "We are extra loud."
src.mind.changeling.recursive_enhancement = 0
+ visible_message("[src] appears to shout.")
+
src.attack_log += text("\[[time_stamp()]\] Used Dissonant Shriek.")
message_admins("[key_name(src)] used Dissonant Shriek ([src.x],[src.y],[src.z]) (JMP).")
log_game("[key_name(src)] used Dissonant Shriek.")
@@ -126,9 +142,6 @@ Ability Cooldowns don't work properly right now, need to redo this when they are
L.broken()
empulse(get_turf(src), range_heavy, range_light, 1)
-/* src.verbs -= /mob/proc/changeling_dissonant_shriek
- spawn(30 SECONDS)
- src << "We are ready to use our dissonant shriek once more."
- src.verbs |= /mob/proc/changeling_dissonant_shriek
-Ability Cooldowns don't work properly right now, need to redo this when they are */
+ changeling.last_shriek = world.time
+
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm
index 236af69f5f..37a9945210 100644
--- a/code/game/gamemodes/changeling/powers/transform.dm
+++ b/code/game/gamemodes/changeling/powers/transform.dm
@@ -13,6 +13,10 @@
var/datum/changeling/changeling = changeling_power(5,1,0)
if(!changeling) return
+ if(!isturf(loc))
+ to_chat(src, "Transforming here would be a bad idea.")
+ return 0
+
var/list/names = list()
for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna)
names += "[DNA.name]"
diff --git a/code/game/gamemodes/changeling/powers/visible_camouflage.dm b/code/game/gamemodes/changeling/powers/visible_camouflage.dm
index 00e31cc932..167f6f41b9 100644
--- a/code/game/gamemodes/changeling/powers/visible_camouflage.dm
+++ b/code/game/gamemodes/changeling/powers/visible_camouflage.dm
@@ -3,7 +3,7 @@
desc = "We rapidly shape the color of our skin and secrete easily reversible dye on our clothes, to blend in with our surroundings. \
We are undetectable, so long as we move slowly.(Toggle)"
helptext = "Running, and performing most acts will reveal us. Our chemical regeneration is halted while we are hidden."
- enhancedtext = "True invisiblity while cloaked."
+ enhancedtext = "Can run while hidden."
ability_icon_state = "ling_camoflage"
genomecost = 3
verbpath = /mob/proc/changeling_visible_camouflage
@@ -31,20 +31,35 @@
var/old_regen_rate = H.mind.changeling.chem_recharge_rate
H << "We vanish from sight, and will remain hidden, so long as we move carefully."
- H.set_m_intent("walk")
H.mind.changeling.cloaked = 1
H.mind.changeling.chem_recharge_rate = 0
animate(src,alpha = 255, alpha = 10, time = 10)
+ var/must_walk = TRUE
if(src.mind.changeling.recursive_enhancement)
- H.invisibility = INVISIBILITY_OBSERVER
- src << "We are now truly invisible."
+ must_walk = FALSE
+ to_chat(src, "We may move at our normal speed while hidden.")
+
+ if(must_walk)
+ H.set_m_intent("walk")
+
+ var/remain_cloaked = TRUE
+ while(remain_cloaked) //This loop will keep going until the player uncloaks.
+ sleep(1 SECOND) // Sleep at the start so that if something invalidates a cloak, it will drop immediately after the check and not in one second.
+
+ if(H.m_intent != "walk" && must_walk) // Moving too fast uncloaks you.
+ remain_cloaked = 0
+ if(!H.mind.changeling.cloaked)
+ remain_cloaked = 0
+ if(H.stat) // Dead or unconscious lings can't stay cloaked.
+ remain_cloaked = 0
+ if(H.incapacitated(INCAPACITATION_DISABLED)) // Stunned lings also can't stay cloaked.
+ remain_cloaked = 0
- while(H.m_intent == "walk" && H.mind.changeling.cloaked && !H.stat) //This loop will keep going until the player uncloaks.
if(mind.changeling.chem_recharge_rate != 0) //Without this, there is an exploit that can be done, if one buys engorged chem sacks while cloaked.
old_regen_rate += mind.changeling.chem_recharge_rate //Unfortunately, it has to occupy this part of the proc. This fixes it while at the same time
mind.changeling.chem_recharge_rate = 0 //making sure nobody loses out on their bonus regeneration after they're done hiding.
- sleep(10)
+
H.invisibility = initial(invisibility)
diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm
index 31c8fe7819..1aadf981c4 100644
--- a/code/game/machinery/camera/tracking.dm
+++ b/code/game/machinery/camera/tracking.dm
@@ -232,6 +232,8 @@ mob/living/proc/near_camera()
return TRACKING_TERMINATE
if(digitalcamo)
return TRACKING_TERMINATE
+ if(alpha < 127) // For lings and possible future alpha-based cloaks.
+ return TRACKING_TERMINATE
if(istype(loc,/obj/effect/dummy))
return TRACKING_TERMINATE
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 674e746c28..667adfc712 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -1105,6 +1105,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
if(M.stat == DEAD && M.client && (M.is_preference_enabled(/datum/client_preference/ghost_ears))) // src.client is so that ghosts don't have to listen to mice
if(istype(M, /mob/new_player))
continue
+ if(M.forbid_seeing_deadchat)
+ continue
M.show_message("PDA Message - [owner] -> [P.owner]: [t]")
if(!conversations.Find("\ref[P]"))
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 07562ad190..4384151cbd 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -212,7 +212,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Ghost"
set desc = "Relinquish your life and enter the land of the dead."
- if(stat == DEAD)
+ if(stat == DEAD && !forbid_seeing_deadchat)
announce_ghost_joinleave(ghostize(1))
else
var/response
@@ -223,7 +223,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return
src.client.admin_ghost()
else
- response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost, you won't be able to play this round for another 30 minutes! You can't change your mind so choose wisely!)", "Are you sure you want to ghost?", "Ghost", "Stay in body")
+ response = alert(src, "Are you -sure- you want to ghost?\n(You are alive, or otherwise have the potential to become alive. If you ghost, you won't be able to play this round until you respawn as a new character! You can't change your mind so choose wisely!)", "Are you sure you want to ghost?", "Ghost", "Stay in body")
if(response != "Ghost")
return
resting = 1
diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm
index fdb0b012ef..3a451bff44 100644
--- a/code/modules/mob/hear_say.dm
+++ b/code/modules/mob/hear_say.dm
@@ -101,7 +101,7 @@
/mob/living/silicon/ai/special_mentions()
return list("AI") // AI door!
-// Converts specific characters, like *, |, and _ to formatted output.
+// Converts specific characters, like +, |, and _ to formatted output.
/mob/proc/say_emphasis(var/message)
message = encode_html_emphasis(message, "|", "i")
message = encode_html_emphasis(message, "+", "b")
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index ee0c867ffb..b4a47d2e47 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -41,6 +41,13 @@
species.handle_death(src)
animate_tail_stop()
+ //Handle snowflake ling stuff.
+ if(mind && mind.changeling)
+ // If the ling is capable of revival, don't allow them to see deadchat.
+ if(mind.changeling.chem_charges >= CHANGELING_STASIS_COST)
+ if(mind.changeling.max_geneticpoints >= 0) // Absorbed lings don't count, as they can't revive.
+ forbid_seeing_deadchat = TRUE
+
//Handle brain slugs.
var/obj/item/organ/external/Hd = get_organ(BP_HEAD)
var/mob/living/simple_animal/borer/B
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 1aef4eca81..80c0dbc505 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -141,7 +141,7 @@ proc/get_radio_key_from_channel(var/channel)
//Redirect to say_dead if talker is dead
if(stat)
- if(stat == DEAD)
+ if(stat == DEAD && !forbid_seeing_deadchat)
return say_dead(message)
return
@@ -308,7 +308,7 @@ proc/get_radio_key_from_channel(var/channel)
if(M && src) //If we still exist, when the spawn processes
var/dst = get_dist(get_turf(M),get_turf(src))
- if(dst <= message_range || M.stat == DEAD) //Inside normal message range, or dead with ears (handled in the view proc)
+ if(dst <= message_range || (M.stat == DEAD && !forbid_seeing_deadchat)) //Inside normal message range, or dead with ears (handled in the view proc)
M << speech_bubble
M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol)
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 1901902c80..a63590acf8 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -207,3 +207,4 @@
var/list/active_genes=list()
var/mob_size = MOB_MEDIUM
+ var/forbid_seeing_deadchat = FALSE // Used for lings to not see deadchat, and to have ghosting behave as if they were not really dead.
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 4327840a47..ba5b24dbe7 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -390,10 +390,16 @@ proc/is_blind(A)
else
name = realname
+ if(subject && subject.forbid_seeing_deadchat && !subject.client.holder)
+ return // Can't talk in deadchat if you can't see it.
+
for(var/mob/M in player_list)
if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || (M.client.holder && !is_mentor(M.client))) && M.is_preference_enabled(/datum/client_preference/show_dsay))
var/follow
var/lname
+ if(M.forbid_seeing_deadchat && !M.client.holder)
+ continue
+
if(subject)
if(M.is_key_ignored(subject.client.key)) // If we're ignored, do nothing.
continue
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 476a8b6810..a553d4309c 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -199,7 +199,7 @@
if(S.victim == mob)
return
- if(mob.stat==DEAD && isliving(mob))
+ if(mob.stat==DEAD && isliving(mob) && !mob.forbid_seeing_deadchat)
mob.ghostize()
return
diff --git a/icons/mob/screen1.dmi b/icons/mob/screen1.dmi
index 9a326ac8a4..809046036d 100644
Binary files a/icons/mob/screen1.dmi and b/icons/mob/screen1.dmi differ