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