diff --git a/code/game/gamemodes/shadowling/shadowling.dm b/code/game/gamemodes/shadowling/shadowling.dm
index a73b8b6afc6..47479f42cb4 100644
--- a/code/game/gamemodes/shadowling/shadowling.dm
+++ b/code/game/gamemodes/shadowling/shadowling.dm
@@ -87,7 +87,7 @@ Made by Xhuis
if(!possible_shadowlings.len)
return 0
- var/shadowlings = max(2, round(num_players()/10)) //How many shadowlings there are; hardcoded to 2
+ var/shadowlings = max(3, round(num_players()/14))
while(shadowlings)
var/datum/mind/shadow = pick(possible_shadowlings)
@@ -114,7 +114,7 @@ Made by Xhuis
/datum/game_mode/proc/greet_shadow(var/datum/mind/shadow)
shadow.current << "Currently, you are disguised as an employee aboard [world.name]."
- shadow.current << "In your limited state, you have three abilities: Enthrall, Hatch, and Shadowling Hivemind (:8)."
+ shadow.current << "In your limited state, you have two abilities: Hatch and Shadowling Hivemind (:8)."
shadow.current << "Any other shadowlings are your allies. You must assist them as they shall assist you."
shadow.current << "If you are new to shadowling, or want to read about abilities, check the wiki page at http://nanotrasen.se/wiki/index.php/Shadowling
"
@@ -132,8 +132,6 @@ Made by Xhuis
/datum/game_mode/proc/finalize_shadowling(var/datum/mind/shadow_mind)
var/mob/living/carbon/human/S = shadow_mind.current
shadow_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_hatch)
- shadow_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/enthrall)
- shadow_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_vision)
spawn(0)
shadow_mind.current.add_language("Shadowling Hivemind")
update_shadow_icons_added(shadow_mind)
@@ -246,6 +244,8 @@ Made by Xhuis
world << "The shadowlings have been killed by the crew!"
else if(!check_shadow_victory() && shuttle_master.emergency.mode >= SHUTTLE_ESCAPE)
world << "The crew escaped the station before the shadowlings could ascend!"
+ else
+ world << "The shadowlings have failed!"
..()
return 1
@@ -300,7 +300,7 @@ Made by Xhuis
blood_color = "#555555"
flesh_color = "#222222"
- flags = NO_BLOOD | NO_BREATHE | RADIMMUNE | NO_INTORGANS
+ flags = NO_BLOOD | NO_BREATHE | RADIMMUNE
burn_mod = 1.5 //1.5x burn damage, 2x is excessive
hot_env_multiplier = 1.5
@@ -327,6 +327,36 @@ Made by Xhuis
H.SetWeakened(0)
H.SetStunned(0)
+
+/datum/species/shadow/ling/lesser //Empowered thralls. Obvious, but powerful
+ name = "Lesser Shadowling"
+
+ icobase = 'icons/mob/human_races/r_lshadowling.dmi'
+ deform = 'icons/mob/human_races/r_lshadowling.dmi'
+
+ blood_color = "#CCCCCC"
+ flesh_color = "#AAAAAA"
+
+ flags = NO_BLOOD | NO_BREATHE | RADIMMUNE
+ burn_mod = 1.1
+ hot_env_multiplier = 1.1
+
+/datum/species/shadow/ling/lesser/handle_life(var/mob/living/carbon/human/H)
+ if(!H.weakeyes)
+ H.weakeyes = 1 //Makes them more vulnerable to flashes and flashbangs
+ var/light_amount = 0
+ H.nutrition = 450 //i aint never get hongry
+ if(isturf(H.loc))
+ var/turf/T = H.loc
+ light_amount = T.get_lumcount() * 10
+ if(light_amount > LIGHT_DAM_THRESHOLD && !H.incorporeal_move)
+ H.take_overall_damage(0, LIGHT_DAMAGE_TAKEN/2)
+ else if (light_amount < LIGHT_HEAL_THRESHOLD)
+ H.heal_overall_damage(2,2)
+ H.adjustToxLoss(-5)
+ H.adjustBrainLoss(-25)
+ H.adjustCloneLoss(-1)
+
/datum/game_mode/proc/update_shadow_icons_added(datum/mind/shadow_mind)
var/datum/atom_hud/antag/shadow_hud = huds[ANTAG_HUD_SHADOW]
shadow_hud.join_hud(shadow_mind.current)
diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm
index 2dfa31cc4a0..a1367fd622c 100644
--- a/code/game/gamemodes/shadowling/shadowling_abilities.dm
+++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm
@@ -1,4 +1,16 @@
-/obj/effect/proc_holder/spell/targeted/glare
+#define EMPOWERED_THRALL_LIMIT 5
+
+/obj/effect/proc_holder/spell/proc/shadowling_check(var/mob/living/carbon/human/H)
+ if(!H || !istype(H)) return
+ if(H.get_species() == "Shadowling" && is_shadow(H)) return 1
+ if(H.get_species() == "Lesser Shadowling" && is_thrall(H)) return 1
+ if(!is_shadow_or_thrall(usr)) usr << "You can't wrap your head around how to do this."
+ else if(is_thrall(usr)) usr << "You aren't powerful enough to do this."
+ else if(is_shadow(usr)) usr << "Your telepathic ability is suppressed. Hatch or use Rapid Re-Hatch first."
+ return 0
+
+
+/obj/effect/proc_holder/spell/targeted/glare //Stuns and mutes a human target for 10 seconds
name = "Glare"
desc = "Stuns and mutes a target for a decent duration."
panel = "Shadowling Abilities"
@@ -9,16 +21,20 @@
/obj/effect/proc_holder/spell/targeted/glare/cast(list/targets)
for(var/mob/living/carbon/human/target in targets)
if(!ishuman(target))
+ usr << "You may only glare at humans!"
+ charge_counter = charge_max
+ return
+ if(!shadowling_check(usr))
charge_counter = charge_max
return
if(target.stat)
+ usr << "[target] must be conscious!"
charge_counter = charge_max
return
if(is_shadow_or_thrall(target))
usr << "You don't see why you would want to paralyze an ally."
charge_counter = charge_max
return
-
var/mob/living/carbon/human/M = target
usr.visible_message("[usr]'s eyes flash a blinding red!")
target.visible_message("[target] freezes in place, their eyes glazing over...")
@@ -29,6 +45,7 @@
target.Stun(10)
M.silent += 10
+
/obj/effect/proc_holder/spell/targeted/lesser_glare
name = "Lesser Glare"
desc = "Stuns and mutes a target for a short duration."
@@ -40,13 +57,15 @@
/obj/effect/proc_holder/spell/targeted/lesser_glare/cast(list/targets)
for(var/mob/living/carbon/human/target in targets)
if(!ishuman(target) || !target)
+ usr << "You nay only glare at humans!"
charge_counter = charge_max
return
if(target.stat)
+ usr << "[target] must be conscious!"
charge_counter = charge_max
return
if(is_shadow_or_thrall(target))
- usr << "You don't see why you would want to paralyze an ally."
+ usr << "You cannot glare at allies!"
charge_counter = charge_max
return
var/mob/living/carbon/human/M = target
@@ -56,14 +75,15 @@
target << "Your gaze is forcibly drawn into [usr]'s eyes, and you are mesmerized by the heavenly lights..."
else
target << "Red lights suddenly dance in your vision, and you are mesmerized by their heavenly beauty..."
- target.Stun(3) //Roughly 30% as long as the normal one
- M.silent += 3
+ target.Stun(5) //Roughly 50% as long as the normal one
+ M.silent += 5
+
/obj/effect/proc_holder/spell/aoe_turf/veil
name = "Veil"
desc = "Extinguishes most nearby light sources."
panel = "Shadowling Abilities"
- charge_max = 250 //Short cooldown because people can just turn the lights back on
+ charge_max = 150 //Short cooldown because people can just turn the lights back on
clothes_req = 0
range = 5
var/blacklisted_lights = list(/obj/item/device/flashlight/flare, /obj/item/device/flashlight/slime)
@@ -143,13 +163,16 @@
name = "Shadow Walk"
desc = "Phases you into the space between worlds for a short time, allowing movement through walls and invisbility."
panel = "Shadowling Abilities"
- charge_max = 600
+ charge_max = 300 //Used to be twice this, buffed
clothes_req = 0
range = -1
include_user = 1
action_icon_state = "shadow_walk"
/obj/effect/proc_holder/spell/targeted/shadow_walk/cast(list/targets)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
for(var/mob/living/user in targets)
playsound(user.loc, 'sound/effects/bamf.ogg', 50, 1)
user.visible_message("[user] vanishes in a puff of black mist!", "You enter the space between worlds as a passageway.")
@@ -157,12 +180,19 @@
user.SetWeakened(0)
user.incorporeal_move = 1
user.alpha = 0
+ user.ExtinguishMob()
+ var/turf/T = get_turf(user)
+ user.forceMove(T) //to properly move the mob out of a potential container
if(user.buckled)
user.buckled.unbuckle_mob()
+ if(user.pulledby)
+ user.pulledby.stop_pulling()
+ user.stop_pulling()
sleep(40) //4 seconds
user.visible_message("[user] suddenly manifests!", "The pressure becomes too much and you vacate the interdimensional darkness.")
user.incorporeal_move = 0
user.alpha = 255
+ user.forceMove(user.loc)
/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk
name = "Guise"
@@ -176,15 +206,8 @@
/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk/cast(list/targets)
for(var/mob/living/user in targets)
- var/lumcount = 0
- var/turf/T = get_turf(user)
- lumcount = T.get_lumcount()*10
- if(lumcount > 5)
- user << "It's too bright to do that!"
- charge_counter = charge_max
- return
user.visible_message("[user] suddenly fades away!", "You veil yourself in darkness, making you harder to see.")
- user.alpha = 20
+ user.alpha = 10
sleep(40)
user.visible_message("[user] appears from nowhere!", "Your shadowy guise slips away.")
user.alpha = initial(user.alpha)
@@ -198,7 +221,8 @@
range = -1
include_user = 1
clothes_req = 0
- var/datum/vision_override/vision_path = /datum/vision_override/nightvision/thermals
+ var/datum/vision_override/vision_path = /datum/vision_override/nightvision
+ action_icon_state = "darksight"
/obj/effect/proc_holder/spell/targeted/shadow_vision/cast(list/targets)
for(var/mob/living/user in targets)
@@ -216,18 +240,20 @@
desc = "Thrall Darksight"
desc = "Gives you night vision."
panel = "Thrall Abilities"
- vision_path = /datum/vision_override/nightvision
/obj/effect/proc_holder/spell/aoe_turf/flashfreeze
name = "Icy Veins"
desc = "Instantly freezes the blood of nearby people, stunning them and causing burn damage."
panel = "Shadowling Abilities"
range = 5
- charge_max = 1200
+ charge_max = 250
clothes_req = 0
action_icon_state = "icy_veins"
/obj/effect/proc_holder/spell/aoe_turf/flashfreeze/cast(list/targets)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
usr << "You freeze the nearby air."
playsound(usr.loc, 'sound/effects/ghost2.ogg', 50, 1)
@@ -239,17 +265,16 @@
else
M << "You feel a blast of paralyzingly cold air wrap around you and flow past, but you are unaffected!"
continue
- M << "You are hit by a blast of paralyzingly cold air and feel goosebumps break out across your body!"
+ M << "A wave of shockingly cold air engulfs you!"
M.Stun(2)
+ M.apply_damage(10, BURN)
if(M.bodytemperature)
M.bodytemperature -= 200 //Extreme amount of initial cold
if(M.reagents)
M.reagents.add_reagent("frostoil", 15) //Half of a cryosting
-
-//Enthrall is the single most important spell
-/obj/effect/proc_holder/spell/targeted/enthrall
+/obj/effect/proc_holder/spell/targeted/enthrall //Turns a target into the shadowling's slave. This overrides all previous loyalties
name = "Enthrall"
desc = "Allows you to enslave a conscious, non-braindead, non-catatonic human to your will. This takes some time to cast."
panel = "Shadowling Abilities"
@@ -262,10 +287,12 @@
/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets)
var/mob/living/carbon/human/user = usr
listclearnulls(ticker.mode.shadowling_thralls)
- if(ticker.mode.shadowling_thralls.len >= 5 && (!istype(user.species, /datum/species/shadow/ling)))
- user << "With your telepathic abilities suppressed, your human form will not allow you to enthrall any others. Hatch first."
- charge_counter = charge_max
+ if(!(user.mind in ticker.mode.shadows))
return
+ if(user.get_species() != "Shadowling")
+ if(ticker.mode.shadowling_thralls.len >= 5)
+ charge_counter = charge_max
+ return
for(var/mob/living/carbon/human/target in targets)
if(!in_range(usr, target))
usr << "You need to be closer to enthrall [target]."
@@ -291,6 +318,8 @@
usr << "You are already enthralling!"
charge_counter = charge_max
return
+ if(!target.client)
+ usr << "[target]'s mind is vacant of activity."
enthralling = 1
usr << "This target is valid. You begin the enthralling."
target << "[usr] stares at you. You feel your head begin to pulse."
@@ -298,32 +327,32 @@
for(var/progress = 0, progress <= 3, progress++)
switch(progress)
if(1)
- usr << "You begin allocating energy for the enthralling."
- usr.visible_message("[usr]'s eyes begin to throb a piercing red.")
+ usr << "You place your hands to [target]'s head..."
+ usr.visible_message("[usr] places their hands onto the sides of [target]'s head!")
if(2)
- usr << "You begin the enthralling of [target]."
- usr.visible_message("[usr] leans over [target], their eyes glowing a deep crimson, and stares into their face.")
- target << "Your gaze is forcibly drawn into a blinding red light. You fall to the floor as conscious thought is wiped away."
+ usr << "You begin preparing [target]'s mind as a blank slate..."
+ usr.visible_message("[usr]'s palms flare a bright red against [target]'s temples!")
+ target << "A terrible red light floods your mind. You collapse as conscious thought is wiped away."
target.Weaken(12)
sleep(20)
if(isloyal(target))
usr << "They are enslaved by Nanotrasen. You begin to shut down the nanobot implant - this will take some time."
- usr.visible_message("[usr] halts for a moment, then begins passing its hand over [target]'s body.")
+ usr.visible_message("[usr] pauses, then dips their head in concentration!")
target << "You feel your loyalties begin to weaken!"
- sleep(150) //15 seconds - not spawn() so the enthralling takes longer
+ sleep(100) //10 seconds - not spawn() so the enthralling takes longer
usr << "The nanobots composing the loyalty implant have been rendered inert. Now to continue."
- usr.visible_message("[usr] halts thier hand and resumes staring into [target]'s face.")
+ usr.visible_message("[usr] relaxes again.")
for(var/obj/item/weapon/implant/loyalty/L in target)
if(L && L.implanted)
qdel(L)
- target << "Your unwavering loyalty to Nanotrasen falters, dims, dies."
+ target << "Your unwavering loyalty to Nanotrasen unexpectedly falters, dims, dies."
if(3)
- usr << "You begin rearranging [target]'s memories."
- usr.visible_message("[usr]'s eyes flare brightly.")
- target << "Your head cries out. The veil of reality begins to crumple and something evil bleeds through." //Ow the edge
- if(!do_mob(usr, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a loyalty implant
- usr << "The enthralling has been interrupted - your target's mind returns to its previous state."
- target << "A spike of pain drives into your head, wiping your memory. You aren't sure what's happened, but you feel a faint sense of revulsion."
+ usr << "You begin planting the tumor that will control the new thrall..."
+ usr.visible_message("A strange energy passes from [usr]'s hands into [target]'s head!")
+ target << "You feel your memories twisting, morphing. A sense of horror dominates your mind."
+ if(!do_mob(usr, target, 70)) //around 21 seconds total for enthralling, 31 for someone with a loyalty implant
+ usr << "The enthralling has been interrupted - your target's mind returns to its previous state."
+ target << "You wrest yourself away from [usr]'s hands and compose yourself"
enthralling = 0
return
@@ -335,7 +364,38 @@
ticker.mode.add_thrall(target.mind)
target.mind.special_role = "shadowling thrall"
-/obj/effect/proc_holder/spell/targeted/collective_mind
+/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor //Resets a shadowling's species to normal, removes genetic defects, and re-equips their armor
+ name = "Rapid Re-Hatch"
+ desc = "Re-forms protective chitin that may be lost during cloning or similar processes."
+ panel = "Shadowling Abilities"
+ charge_max = 600
+ range = -1
+ include_user = 1
+ clothes_req = 0
+ action_icon_state = "regen_armor"
+
+/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor/cast(list/targets)
+ if(!is_shadow(usr))
+ usr << "You must be a shadowling to do this!"
+ charge_counter = charge_max
+ return
+ for(var/mob/living/user in targets)
+ if(!istype(user) || !ishuman(user))
+ return
+ var/mob/living/carbon/human/H = user
+ H.visible_message("[H]'s skin suddenly bubbles and shifts around their body!", \
+ "You regenerate your protective armor and cleanse your form of defects.")
+ H.adjustCloneLoss(user.getCloneLoss())
+ H.equip_to_slot_or_del(new /obj/item/clothing/under/shadowling(H), slot_w_uniform)
+ H.equip_to_slot_or_del(new /obj/item/clothing/shoes/shadowling(H), slot_shoes)
+ H.equip_to_slot_or_del(new /obj/item/clothing/suit/space/shadowling(H), slot_wear_suit)
+ H.equip_to_slot_or_del(new /obj/item/clothing/head/shadowling(H), slot_head)
+ H.equip_to_slot_or_del(new /obj/item/clothing/gloves/shadowling(H), slot_gloves)
+ H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(H), slot_wear_mask)
+ H.equip_to_slot_or_del(new /obj/item/clothing/glasses/shadowling(H), slot_glasses)
+ H.set_species("Shadowling")
+
+/obj/effect/proc_holder/spell/targeted/collective_mind //Lets a shadowling bring together their thralls' strength, granting new abilities and a headcount
name = "Collective Hivemind"
desc = "Gathers the power of all of your thralls and compares it to what is needed for ascendance. Also gains you new abilities."
panel = "Shadowling Abilities"
@@ -350,6 +410,9 @@
action_icon_state = "collective_mind"
/obj/effect/proc_holder/spell/targeted/collective_mind/cast(list/targets)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
for(var/mob/living/user in targets)
var/thralls = 0
var/victory_threshold = 15
@@ -366,22 +429,22 @@
user << "Your concentration has been broken. The mental hooks you have sent out now retract into your mind."
return
- if(thralls >= 3 && !blind_smoke_acquired)
+ if(thralls >= 3 && !screech_acquired)
+ screech_acquired = 1
+ user << "The power of your thralls has granted you the Sonic Screech ability. This ability will shatter nearby windows and deafen enemies, plus stunning silicon lifeforms."
+ user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/unearthly_screech)
+
+ if(thralls >= 5 && !blind_smoke_acquired)
blind_smoke_acquired = 1
user << "The power of your thralls has granted you the Blinding Smoke ability. It will create a choking cloud that will blind any non-thralls who enter. \
"
user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/blindness_smoke)
- if(thralls >= 5 && !drainLifeAcquired)
+ if(thralls >= 7 && !drainLifeAcquired)
drainLifeAcquired = 1
user << "The power of your thralls has granted you the Drain Life ability. You can now drain the health of nearby humans to heal yourself."
user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/drainLife)
- if(thralls >= 7 && !screech_acquired)
- screech_acquired = 1
- user << "The power of your thralls has granted you the Sonic Screech ability. This ability will shatter nearby windows and deafen enemies, plus stunning silicon lifeforms."
- user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/unearthly_screech)
-
if(thralls >= 9 && !reviveThrallAcquired)
reviveThrallAcquired = 1
user << "The power of your thralls has granted you the Black Recuperation ability. This will, after a short time, bring a dead thrall completely back to life \
@@ -420,6 +483,9 @@
action_icon_state = "black_smoke"
/obj/effect/proc_holder/spell/targeted/blindness_smoke/cast(list/targets) //Extremely hacky
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
for(var/mob/living/user in targets)
user.visible_message("[user] suddenly bends over and coughs out a cloud of black smoke, which begins to spread rapidly!")
user << "You regurgitate a vast cloud of blinding smoke."
@@ -471,6 +537,9 @@ datum/reagent/shadowling_blindness_smoke/on_mob_life(var/mob/living/M as mob)
action_icon_state = "screech"
/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech/cast(list/targets)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
usr.audible_message("[usr] lets out a horrible scream!")
playsound(usr.loc, 'sound/effects/screech.ogg', 100, 1)
@@ -484,7 +553,6 @@ datum/reagent/shadowling_blindness_smoke/on_mob_life(var/mob/living/M as mob)
if(iscarbon(target))
var/mob/living/carbon/M = target
M << "A spike of pain drives into your head and scrambles your thoughts!"
- M.Weaken(2)
M.confused += 10
M.ear_damage += 3
else if(issilicon(target))
@@ -497,7 +565,7 @@ datum/reagent/shadowling_blindness_smoke/on_mob_life(var/mob/living/M as mob)
sp.start()
S.Weaken(6)
for(var/obj/structure/window/W in T.contents)
- W.hit(rand(80,100))
+ W.hit(rand(80, 100))
@@ -513,6 +581,9 @@ datum/reagent/shadowling_blindness_smoke/on_mob_life(var/mob/living/M as mob)
action_icon_state = "drain_life"
/obj/effect/proc_holder/spell/aoe_turf/drainLife/cast(list/targets, var/mob/living/carbon/human/U = usr)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
targetsDrained = 0
nearbyTargets = list()
for(var/turf/T in targets)
@@ -541,46 +612,143 @@ datum/reagent/shadowling_blindness_smoke/on_mob_life(var/mob/living/M as mob)
/obj/effect/proc_holder/spell/targeted/reviveThrall
name = "Black Recuperation"
- desc = "Brings a dead thrall back to life."
+ desc = "Revives or empowers a thrall."
panel = "Shadowling Abilities"
range = 1
- charge_max = 3000
+ charge_max = 600
clothes_req = 0
include_user = 0
- var/list/thralls_in_world = list()
action_icon_state = "revive_thrall"
/obj/effect/proc_holder/spell/targeted/reviveThrall/cast(list/targets)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
for(var/mob/living/carbon/human/thrallToRevive in targets)
- if(!is_thrall(thrallToRevive))
- usr << "[thrallToRevive] is not a thrall."
+ var/choice = alert(usr,"Empower a living thrall or revive a dead one?",,"Empower","Revive","Cancel")
+ switch(choice)
+ if("Empower")
+ if(!is_thrall(thrallToRevive))
+ usr << "[thrallToRevive] is not a thrall."
+ charge_counter = charge_max
+ return
+ if(thrallToRevive.stat != CONSCIOUS)
+ usr << "[thrallToRevive] must be conscious to become empowered."
+ charge_counter = charge_max
+ return
+ var/empowered_thralls = 0
+ for(var/datum/mind/M in ticker.mode.shadowling_thralls)
+ if(!ishuman(M.current))
+ return
+ var/mob/living/carbon/human/H = M.current
+ if(H.get_species() == "Lesser Shadowling")
+ empowered_thralls++
+ if(empowered_thralls >= EMPOWERED_THRALL_LIMIT)
+ usr << "You cannot spare this much energy. There are too many empowered thralls."
+ charge_counter = charge_max
+ return
+ usr.visible_message("[usr] places their hands over [thrallToRevive]'s face, red light shining from beneath.", \
+ "You place your hands on [thrallToRevive]'s face and begin gathering energy...")
+ thrallToRevive << "[usr] places their hands over your face. You feel energy gathering. Stand still..."
+ if(!do_mob(usr, thrallToRevive, 80))
+ usr << "Your concentration snaps. The flow of energy ebbs."
+ charge_counter = charge_max
+ return
+ usr << "You release a massive surge of power into [thrallToRevive]!"
+ usr.visible_message("Red lightning surges into [thrallToRevive]'s face!")
+ playsound(thrallToRevive, 'sound/weapons/Egloves.ogg', 50, 1)
+ playsound(thrallToRevive, 'sound/machines/defib_zap.ogg', 50, 1)
+ usr.Beam(thrallToRevive,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1)
+ thrallToRevive.Weaken(5)
+ thrallToRevive.visible_message("[thrallToRevive] collapses, their skin and face distorting!", \
+ "AAAAAAAAAAAAAAAAAAAGH-")
+ sleep(20)
+ thrallToRevive.visible_message("[thrallToRevive] slowly rises, no longer recognizable as human.", \
+ "You feel new power flow into you. You have been gifted by your masters. You now closely resemble them. You are empowered in \
+ darkness but wither slowly in light. In addition, Lesser Glare and Guise have been upgraded into their true forms.")
+ thrallToRevive.set_species("Lesser Shadowling")
+ thrallToRevive.mind.remove_spell(/obj/effect/proc_holder/spell/targeted/lesser_glare)
+ thrallToRevive.mind.remove_spell(/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk)
+ thrallToRevive.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/glare)
+ thrallToRevive.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_walk)
+ if("Revive")
+ if(!is_thrall(thrallToRevive))
+ usr << "[thrallToRevive] is not a thrall."
+ charge_counter = charge_max
+ return
+ if(thrallToRevive.stat != DEAD)
+ usr << "[thrallToRevive] is not dead."
+ charge_counter = charge_max
+ return
+ usr.visible_message("[usr] kneels over [thrallToRevive], placing their hands on \his chest.", \
+ "You crouch over the body of your thrall and begin gathering energy...")
+ thrallToRevive.notify_ghost_cloning("Your masters are resuscitating you! Re-enter your corpse if you wish to be brought to life.", source = thrallToRevive)
+ if(!do_mob(usr, thrallToRevive, 30))
+ usr << "Your concentration snaps. The flow of energy ebbs."
+ charge_counter = charge_max
+ return
+ usr << "You release a massive surge of power into [thrallToRevive]!"
+ usr.visible_message("Red lightning surges from [usr]'s hands into [thrallToRevive]'s chest!")
+ playsound(thrallToRevive, 'sound/weapons/Egloves.ogg', 50, 1)
+ playsound(thrallToRevive, 'sound/machines/defib_zap.ogg', 50, 1)
+ usr.Beam(thrallToRevive,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1)
+ sleep(10)
+ if(thrallToRevive.revive(full_heal = 1))
+ thrallToRevive.visible_message("[thrallToRevive] heaves in breath, dim red light shining in their eyes.", \
+ "You have returned. One of your masters has brought you from the darkness beyond.")
+ thrallToRevive.Weaken(4)
+ thrallToRevive.emote("gasp")
+ playsound(thrallToRevive, "bodyfall", 50, 1)
+ else
+ charge_counter = charge_max
+ return
+
+/obj/effect/proc_holder/spell/targeted/shadowling_extend_shuttle
+ name = "Destroy Engines"
+ desc = "Extends the time of the emergency shuttle's arrival by fifteen minutes. This can only be used once."
+ panel = "Shadowling Abilities"
+ range = 1
+ clothes_req = 0
+ charge_max = 600
+ action_icon_state = "extend_shuttle"
+
+/obj/effect/proc_holder/spell/targeted/shadowling_extend_shuttle/cast(list/targets)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
+ for(var/mob/living/carbon/human/target in targets)
+ if(target.stat)
charge_counter = charge_max
return
- if(thrallToRevive.stat != DEAD)
- usr << "[thrallToRevive] is not dead."
+ if(!is_thrall(target))
+ usr << "[target] must be a thrall."
charge_counter = charge_max
return
- usr.visible_message("[usr] kneels over [thrallToRevive], placing their hands on \his chest.", \
- "You crouch over the body of your thrall and begin gathering energy...")
- var/mob/dead/observer/ghost = thrallToRevive.get_ghost()
- if(ghost)
- ghost << "Your masters are resuscitating you! Return to your corpse if you wish to be brought to life. (Verbs -> Ghost -> Re-enter corpse)"
- ghost << 'sound/effects/genetics.ogg'
- if(!do_mob(usr, thrallToRevive, 30))
- usr << "Your concentration snaps. The flow of energy ebbs."
- charge_counter= charge_max
+ if(shuttle_master.emergency.mode != SHUTTLE_CALL)
+ usr << "The shuttle must be inbound only to the station."
+ charge_counter = charge_max
return
- usr << "You release a massive surge of power into [thrallToRevive]!"
- usr.visible_message("Red lightning surges from [usr]'s hands into [thrallToRevive]'s chest!")
- playsound(thrallToRevive, 'sound/weapons/Egloves.ogg', 50, 1)
- playsound(thrallToRevive, 'sound/machines/defib_zap.ogg', 50, 1)
- sleep(10)
- thrallToRevive.revive()
- thrallToRevive.visible_message("[thrallToRevive] draws in a huge breath, blinding violet light shining from their eyes.", \
- "You have returned. One of your masters has brought you from the darkness beyond.")
- thrallToRevive.Weaken(4)
- thrallToRevive.emote("gasp")
- playsound(thrallToRevive, "bodyfall", 50, 1)
+ var/mob/living/carbon/human/M = target
+ usr.visible_message("[usr]'s eyes flash a bright red!", \
+ "You begin to draw [M]'s life force.")
+ M.visible_message("[M]'s face falls slack, their jaw slightly distending.", \
+ "You are suddenly transported... far, far away...")
+ if(!do_after(usr, 50, target = M))
+ M << "You are snapped back to reality, your haze dissipating!"
+ usr << "You have been interrupted. The draw has failed."
+ return
+ usr << "You project [M]'s life force toward the approaching shuttle, extending its arrival duration!"
+ M.visible_message("[M]'s eyes suddenly flare red. They proceed to collapse on the floor, not breathing.", \
+ "...speeding by... ...pretty blue glow... ...touch it... ...no glow now... ...no light... ...nothing at all...")
+ M.death()
+ if(shuttle_master.emergency.mode == SHUTTLE_CALL)
+ var/more_minutes = 9000
+ var/timer = shuttle_master.emergency.timeLeft()
+ timer += more_minutes
+ command_announcement.Announce("Major system failure aboard the emergency shuttle. This will extend its arrival time by approximately 15 minutes..", "System Failure", 'sound/misc/notice1.ogg')
+ shuttle_master.emergency.setTimer(timer)
+ usr.mind.spell_list.Remove(src) //Can only be used once!
+ qdel(src)
// ASCENDANT ABILITIES BEYOND THIS POINT //
@@ -600,15 +768,17 @@ datum/reagent/shadowling_blindness_smoke/on_mob_life(var/mob/living/M as mob)
charge_counter = charge_max
return
+ playsound(usr.loc, 'sound/magic/Staff_Chaos.ogg', 100, 1)
for(var/mob/living/boom in targets)
- if(is_shadow_or_thrall(boom))
+ if(is_shadow(boom)) //Used to not work on thralls. Now it does so you can PUNISH THEM LIKE THE WRATHFUL GOD YOU ARE.
usr << "Making an ally explode seems unwise."
charge_counter = charge_max
return
usr.visible_message("[usr]'s markings flare as they gesture at [boom]!", \
"You direct a lance of telekinetic energy at [boom].")
- playsound(usr, 'sound/effects/supermatter.ogg', 100, 1)
sleep(4)
+ if(iscarbon(boom))
+ playsound(boom, 'sound/magic/Disintegrate.ogg', 100, 1)
boom.visible_message("[boom] explodes!")
boom.gib()
@@ -701,7 +871,7 @@ datum/reagent/shadowling_blindness_smoke/on_mob_life(var/mob/living/M as mob)
usr.visible_message("A massive ball of lightning appears in [usr]'s hands and flares out!", \
"You conjure a ball of lightning and release it.")
-
+ playsound(usr.loc, 'sound/magic/lightningbolt.ogg', 100, 1)
for(var/turf/T in targets)
for(var/mob/living/carbon/human/target in T.contents)
if(is_shadow_or_thrall(target))
diff --git a/code/game/gamemodes/shadowling/shadowling_items.dm b/code/game/gamemodes/shadowling/shadowling_items.dm
index 6af78895077..500c3ee25c5 100644
--- a/code/game/gamemodes/shadowling/shadowling_items.dm
+++ b/code/game/gamemodes/shadowling/shadowling_items.dm
@@ -1,12 +1,13 @@
/obj/item/clothing/under/shadowling
name = "blackened flesh"
- desc = "Black, chitonous skin."
+ desc = "Black, chitinous skin."
item_state = "golem"
origin_tech = null
icon_state = "golem"
item_color = "golem"
flags = ABSTRACT | NODROP
has_sensor = 0
+ displays_id = 0
unacidable = 1
@@ -19,11 +20,12 @@
cold_protection = FULL_BODY
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
flags_inv = HIDEGLOVES | HIDESHOES | HIDEJUMPSUIT
- flags = ABSTRACT | NODROP | THICKMATERIAL
slowdown = 0
unacidable = 1
heat_protection = null //You didn't expect a light-sensitive creature to have heat resistance, did you?
max_heat_protection_temperature = null
+ armor = list(melee = 25, bullet = 0, laser = 0, energy = 0, bomb = 25, bio = 100, rad = 100)
+ flags = ABSTRACT | NODROP | THICKMATERIAL | STOPSPRESSUREDMAGE
/obj/item/clothing/shoes/shadowling
@@ -61,10 +63,13 @@
desc = "A helmet-like enclosure of the head."
icon_state = "golem"
item_state = null
+ cold_protection = HEAD
+ min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
+ heat_protection = HEAD
+ max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT
origin_tech = null
unacidable = 1
- flags = ABSTRACT | NODROP
-
+ flags = ABSTRACT | NODROP | STOPSPRESSUREDMAGE
/obj/item/clothing/glasses/shadowling
name = "crimson eyes"
@@ -75,25 +80,5 @@
origin_tech = null
unacidable = 1
flash_protect = -1
- flags = ABSTRACT | NODROP
-
-/obj/structure/shadow_vortex
- name = "vortex"
- desc = "A swirling hole in the fabric of reality. Eye-watering chimes sound from its depths."
- density = 0
- anchored = 1
- icon = 'icons/effects/genetics.dmi'
- icon_state = "shadow_portal"
-
-/obj/structure/shadow_vortex/New()
- src.audible_message("\The [src] lets out a dismaying screech as dimensional barriers are torn apart!")
- playsound(loc, 'sound/effects/eleczap.ogg', 100, 1)
- sleep(100)
- qdel(src)
-
-/obj/structure/shadow_vortex/Crossed(var/td)
- ..()
- if(ismob(td))
- td << "You enter the rift. Deafening chimes jingle in your ears. You are swallowed in darkness."
- playsound(loc, 'sound/effects/EMPulse.ogg', 25, 1)
- qdel(td)
+ vision_flags = SEE_MOBS
+ flags = ABSTRACT | NODROP
\ No newline at end of file
diff --git a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
index 0b33c2f2451..52c50e0c193 100644
--- a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
+++ b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
@@ -1,5 +1,5 @@
//In here: Hatch and Ascendance
-var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "Noaey'gief", "Mii`mahza", "Amerziox", "Gyrg-mylin", "Kanet'pruunance")
+var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "Noaey'gief", "Mii`mahza", "Amerziox", "Gyrg-mylin", "Kanet'pruunance", "Vigistaezian") //Unpronouncable 2: electric boogalo)
/obj/effect/proc_holder/spell/targeted/shadowling_hatch
name = "Hatch"
desc = "Casts off your disguise."
@@ -11,7 +11,7 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N
action_icon_state = "hatch"
/obj/effect/proc_holder/spell/targeted/shadowling_hatch/cast(list/targets)
- if(usr.stat || !ishuman(usr) || !usr)
+ if(usr.stat || !ishuman(usr) || !usr || !is_shadow(usr || isinspace(usr)))
return
if(!isturf(usr.loc))
usr << "You can't hatch here!"
@@ -39,10 +39,11 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N
for(var/obj/structure/alien/resin/wall/shadowling/R in shadowturf) //extremely hacky
qdel(R)
new /obj/structure/alien/weeds/node(shadowturf) //Dim lighting in the chrysalis -- removes itself afterwards
+ var/temp_flags = H.status_flags
+ H.status_flags |= GODMODE //Can't die while hatching
H.visible_message("A chrysalis forms around [H], sealing them inside.", \
"You create your chrysalis and begin to contort within.")
- usr.Weaken(30)
sleep(100)
H.visible_message("The skin on [H]'s back begins to split apart. Black spines slowly emerge from the divide.", \
@@ -61,7 +62,7 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N
sleep(10)
playsound(H.loc, 'sound/weapons/slice.ogg', 25, 1)
H << "You are free!"
-
+ H.status_flags = temp_flags
sleep(10)
playsound(H.loc, 'sound/effects/ghost.ogg', 100, 1)
var/newNameId = pick(possibleShadowlingNames)
@@ -77,7 +78,6 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N
for(var/obj/structure/alien/weeds/node/N in shadowturf)
qdel(N)
H.visible_message("The chrysalis explodes in a shower of purple flesh and fluid!")
-
H.underwear = "None"
H.undershirt = "None"
H.socks = "None"
@@ -90,16 +90,21 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/shadowling(usr), slot_gloves)
H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(usr), slot_wear_mask)
H.equip_to_slot_or_del(new /obj/item/clothing/glasses/shadowling(usr), slot_glasses)
- H.set_species("Shadowling")
+ H.set_species("Shadowling") //can't be a shadowling without being a shadowling
+
+ H.mind.remove_spell(src)
sleep(10)
H << "Your powers are awoken. You may now live to your fullest extent. Remember your goal. Cooperate with your thralls and allies."
- H.mind.remove_spell(/obj/effect/proc_holder/spell/targeted/shadowling_hatch)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_vision)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/enthrall)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/glare)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/veil)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_walk)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/flashfreeze)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/collective_mind)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_regenarmor)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_extend_shuttle)
/obj/effect/proc_holder/spell/targeted/shadowling_ascend
name = "Ascend"
@@ -112,9 +117,10 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N
action_icon_state = "ascend"
/obj/effect/proc_holder/spell/targeted/shadowling_ascend/cast(list/targets)
- if(usr.stat || !ishuman(usr) || !usr)
+ var/mob/living/carbon/human/H = usr
+ if(!shadowling_check(H))
return
- for(var/mob/living/carbon/human/H in targets)
+ for(H in targets)
var/hatch_or_no = alert(H,"It is time to ascend. Are you sure about this?",,"Yes","No")
switch(hatch_or_no)
if("No")
@@ -151,7 +157,7 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N
M << "An immense pressure slams you onto the ground!"
world << "\"VYSHA NERADA YEKHEZET U'RUU!!\""
world << 'sound/hallucinations/veryfar_noise.ogg'
- for(var/obj/machinery/power/apc/A in range(200, H))
+ for(var/obj/machinery/power/apc/A in apcs)
A.overload_lighting()
var/mob/A = new /mob/living/simple_animal/ascendant_shadowling(H.loc)
for(var/obj/effect/proc_holder/spell/S in H.mind.spell_list)
@@ -168,7 +174,6 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N
if(A.real_name)
A.real_name = H.real_name
H.invisibility = 60 //This is pretty bad, but is also necessary for the shuttle call to function properly
- H.flags |= GODMODE
H.loc = A
sleep(50)
if(!ticker.mode.shadowling_ascended)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 2c0ae7ef779..16d826b55f5 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -257,6 +257,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return 1
+/mob/dead/observer/proc/notify_cloning(var/message, var/sound, var/atom/source)
+ if(message)
+ src << "[message]"
+ src << "(Click to re-enter)"
+ if(sound)
+ src << sound(sound)
+
/mob/dead/observer/proc/show_me_the_hud(hud_index)
var/datum/atom_hud/H = huds[hud_index]
H.add_hud_to(src)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index f8152ee0f96..3451da45d3f 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1364,6 +1364,11 @@ mob/proc/yank_out_object()
return G
break
+/mob/proc/notify_ghost_cloning(var/message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", var/sound = 'sound/effects/genetics.ogg', var/atom/source = null)
+ var/mob/dead/observer/ghost = get_ghost()
+ if(ghost)
+ ghost.notify_cloning(message, sound, source)
+ return ghost
/mob/proc/fakevomit(green=0) //for aesthetic vomits that need to be instant and do not stun. -Fox
if(stat==DEAD)
diff --git a/code/modules/surgery/other.dm b/code/modules/surgery/other.dm
index 42c35dd5106..85d8ca95e86 100644
--- a/code/modules/surgery/other.dm
+++ b/code/modules/surgery/other.dm
@@ -219,7 +219,7 @@
/datum/surgery/remove_thrall/can_start(mob/user, mob/living/carbon/target)
- return is_thrall(target)//would this be too meta?
+ return is_thrall(target) //would this be too meta?
/datum/surgery/remove_thrall/synth/can_start(mob/user, mob/living/carbon/target)
return is_thrall(target) && target.get_species() == "Machine"
@@ -244,22 +244,27 @@
..()
/datum/surgery_step/internal/dethrall/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
+ if(target.get_species() == "Lesser Shadowling") //Empowered thralls cannot be deconverted
+ target << "NOT LIKE THIS!"
+ user.visible_message("[target] suddenly slams upward and knocks down [user]!", \
+ "[target] suddenly bolts up and slams you with tremendous force!")
+ user.resting = 0 //Remove all stuns
+ user.SetSleeping(0)
+ user.SetStunned(0)
+ user.SetWeakened(0)
+ user.SetParalysis(0)
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ C.Weaken(6)
+ C.apply_damage(20, "brute", "chest")
+ else if(issilicon(user))
+ var/mob/living/silicon/S = user
+ S.Weaken(8)
+ S.apply_damage(20, "brute")
+ playsound(S, 'sound/effects/bang.ogg', 50, 1)
+ return 0
user.visible_message("[user] shines light onto the tumor in [target]'s head!", "You cleanse the contamination from [target]'s brain!")
- ticker.mode.remove_thrall(target.mind,0)
+ ticker.mode.remove_thrall(target.mind, 0)
target.visible_message("A strange black mass falls from [target]'s head!")
new /obj/item/organ/internal/shadowtumor(get_turf(target))
-
return 1
-
-/datum/surgery_step/internal/dethrall/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
- var/braincase = target.named_organ_parent("brain")
- if(prob(50))
- user.visible_message("[user] slips and rips the tumor out from [target]'s [braincase]!", \
- "You fumble and tear out [target]'s tumor!")
- target.adjustBrainLoss(110) // This is so you can't just defib'n go
- ticker.mode.remove_thrall(target.mind,1)
-
- return 0
- else
- user.visible_message("[user]'s hand slips and fumbles! Luckily, they didn't damage anything!")
- return 0
diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi
index 5e7b65eb543..79144d6c4bb 100644
Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ
diff --git a/icons/mob/human_races/r_lshadowling.dmi b/icons/mob/human_races/r_lshadowling.dmi
new file mode 100644
index 00000000000..0e955e5bd97
Binary files /dev/null and b/icons/mob/human_races/r_lshadowling.dmi differ
diff --git a/sound/magic/Staff_Chaos.ogg b/sound/magic/Staff_Chaos.ogg
new file mode 100644
index 00000000000..e8b1c0e6adf
Binary files /dev/null and b/sound/magic/Staff_Chaos.ogg differ