Copy-Paste Port of /tg/station's Shadowlings

Ports tgstation/-tg-station#8157

This won't compile, needs to be bugfixed and tested. The only reason I
am PRing  this right now is so that we don't have multiple people
working on the same thing.

@ZomgPonies This will require PROBABILITY SHADOWLING # to be added to
game_options.txt, and will likely require SQL database additions for the
BE_SHADOWLING antag preference.
This commit is contained in:
DZD
2015-04-12 13:15:40 -04:00
parent dfaad7168d
commit 0ab3a54fcb
14 changed files with 1227 additions and 1 deletions
+63
View File
@@ -312,6 +312,25 @@ datum/mind
sections["traitor"] = text
/** SHADOWLING **/
text = "shadowling"
if(ticker.mode.config_tag == "shadowling")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(src in ticker.mode.shadows)
text += "<b>SHADOWLING</b>|thrall|<a href='?src=\ref[src];shadowling=clear'>human</a>"
else if(src in ticker.mode.thralls)
text += "shadowling|<b>THRALL</b>|<a href='?src=\ref[src];shadowling=clear'>human</a>"
else
text += "<a href='?src=\ref[src];shadowling=shadowling'>shadowling</a>|<a href='?src=\ref[src];shadowling=thrall'>thrall</a>|<b>HUMAN</b>"
if(current && current.client && current.client.prefs.be_special & BE_SHADOWLING)
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["shadowling"] = text
/** MONKEY ***/
if (istype(current, /mob/living/carbon))
text = "monkey"
@@ -943,6 +962,50 @@ datum/mind
ticker.mode.forge_traitor_objectives(src)
usr << "\blue The objectives for traitor [key] have been generated. You can edit them and anounce manually."
else if(href_list["shadowling"])
switch(href_list["shadowling"])
if("clear")
src.spell_list = null
if(src in ticker.mode.shadows)
ticker.mode.shadows -= src
special_role = null
current << "<span class='userdanger'>Your powers have been quenched! You are no longer a shadowling!</span>"
src.spell_list = null
message_admins("[key_name_admin(usr)] has de-shadowling'ed [current].")
log_admin("[key_name(usr)] has de-shadowling'ed [current].")
current.verbs -= /mob/living/carbon/human/proc/shadowling_hatch
current.verbs -= /mob/living/carbon/human/proc/shadowling_ascendance
else if(src in ticker.mode.thralls)
ticker.mode.thralls -= src
special_role = null
current << "<span class='userdanger'>You have been brainwashed! You are no longer a thrall!</span>"
message_admins("[key_name_admin(usr)] has de-thrall'ed [current].")
log_admin("[key_name(usr)] has de-thrall'ed [current].")
if("shadowling")
if(!ishuman(current))
usr << "<span class='warning'>This only works on humans!</span>"
return
ticker.mode.shadows += src
special_role = "shadowling"
current << "<span class='deadsay'><b>You notice a brightening around you. No, it isn't that. The shadows grow, darken, swirl. The darkness has a new welcome for you, and you realize with a \
start that you can't be human. No, you are a shadowling, a harbringer of the shadows! Your alien abilities have been unlocked from within, and you may both commune with your allies and use \
a chrysalis to reveal your true form. You are to ascend at all costs.</b></span>"
src.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
src.spell_list += new /obj/effect/proc_holder/spell/targeted/enthrall
current.verbs += /mob/living/carbon/human/proc/shadowling_hatch
if("thrall")
if(!ishuman(current))
usr << "<span class='warning'>This only works on humans!</span>"
return
ticker.mode.add_thrall(src)
special_role = "thrall"
current << "<span class='deadsay'>All at once it becomes clear to you. Where others see darkness, you see an ally. You realize that the shadows are not dead and dark as one would think, but \
living, and breathing, and <b>eating</b>. Their children, the Shadowlings, are to be obeyed and protected at all costs.</span>"
current << "<span class='danger'>You may use the Hivemind Commune ability to communicate with your fellow enlightened ones.</span>"
message_admins("[key_name_admin(usr)] has thrall'ed [current].")
log_admin("[key_name(usr)] has thrall'ed [current].")
src.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
else if (href_list["monkey"])
var/mob/living/L = current
if (L.monkeyizing)
@@ -0,0 +1,235 @@
/*
SHADOWLING: A gamemode based on previously-run events
Aliens called shadowlings are on the station.
These shadowlings can 'enthrall' crew members and enslave them.
They also burn in the light but heal rapidly whilst in the dark.
The game will end under two conditions:
1. The shadowlings die
2. The emergency shuttle docks at CentCom
Shadowling strengths:
- The dark
- Hard vacuum (They are not affected by it)
- Their thralls who are not harmed by the light
- Stealth
Shadowling weaknesses:
- The light
- Fire
- Enemy numbers
- Lasers (Lasers are concentrated light and do more damage)
- Flashbangs (High stun and high burn damage; if the light stuns humans, you bet your ass it'll hurt the shadowling very much!)
Shadowlings start off disguised as normal crew members, and they only have two abilities: Hatch and Enthrall.
They can still enthrall and perhaps complete their objectives in this form.
Hatch will, after a short time, cast off the human disguise and assume the shadowling's true identity.
They will then assume the normal shadowling form and gain their abilities.
The shadowling will seem OP, and that's because it kinda is. Being restricted to the dark while being alone most of the time is extremely difficult and as such the shadowling needs powerful abilities.
Made by Xhuis
*/
/*
GAMEMODE
*/
/datum/game_mode
var/list/datum/mind/shadows = list()
var/list/datum/mind/thralls = list()
var/list/shadow_objectives = list()
var/required_thralls = 15 //How many thralls are needed (hardcoded for now)
var/shadowling_ascended = 0 //If at least one shadowling has ascended
var/shadowling_dead = 0 //is shadowling kill
/proc/is_thrall(var/mob/living/M)
return istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.thralls)
/proc/is_shadow_or_thrall(var/mob/living/M)
return istype(M) && M.mind && ticker && ticker.mode && ((M.mind in ticker.mode.thralls) || (M.mind in ticker.mode.shadows))
/proc/is_shadow(var/mob/living/M)
return istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.shadows)
/datum/game_mode/shadowling
name = "shadowling"
config_tag = "shadowling"
antag_flag = BE_SHADOWLING
required_players = 30
required_enemies = 2
recommended_enemies = 2
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")
/datum/game_mode/shadowling/announce()
world << "<b>The current game mode is - Shadowling!</b>"
world << "<b>There are alien <span class='userdanger'>shadowlings</span> on the station. Crew: Kill the shadowlings before they can eat or enthrall the crew. Shadowlings: Enthrall the crew while remaining in hiding.</b>"
/datum/game_mode/shadowling/pre_setup()
if(config.protect_roles_from_antagonist)
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
restricted_jobs += "Assistant"
for(var/datum/mind/player in antag_candidates)
for(var/job in restricted_jobs)
if(player.assigned_role == job)
antag_candidates -= player
var/shadowlings = 2 //How many shadowlings there are; hardcoded to 2
while(shadowlings)
var/datum/mind/shadow = pick(antag_candidates)
shadows += shadow
antag_candidates -= shadow
modePlayer += shadow
shadow.special_role = "Shadowling"
shadowlings--
return 1
/datum/game_mode/shadowling/post_setup()
for(var/datum/mind/shadow in shadows)
log_game("[shadow.key] (ckey) has been selected as a Shadowling.")
sleep(10)
shadow.current << "<br>"
shadow.current << "<span class='deadsay'><b><font size=3>You are a shadowling!</font></b></span>"
greet_shadow(shadow)
finalize_shadowling(shadow)
process_shadow_objectives(shadow)
//give_shadowling_abilities(shadow)
..()
return
/datum/game_mode/proc/greet_shadow(var/datum/mind/shadow)
shadow.current << "<b>Currently, you are disguised as an employee aboard [world.name].</b>"
shadow.current << "<b>In your limited state, you have three abilities: Enthrall, Hatch, and Hivemind Commune.</b>"
shadow.current << "<b>If you are new to shadowling, or want to read about abilities, check the wiki page at https://tgstation13.org/wiki/Shadowling</b><br>"
/datum/game_mode/proc/process_shadow_objectives(var/datum/mind/shadow_mind)
var/objective = "enthrall" //may be devour later, but for now it seems murderbone-y
if(objective == "enthrall")
var/objective_explanation = "Ascend to your true form by use of the Ascendance ability. This may only be used with [required_thralls] collective thralls, while hatched, and is unlocked with the Collective Mind ability."
shadow_objectives += "enthrall"
shadow_mind.memory += "<b>Objective #1</b>: [objective_explanation]"
shadow_mind.current << "<b>Objective #1</b>: [objective_explanation]<br>"
/datum/game_mode/proc/finalize_shadowling(var/datum/mind/shadow_mind)
var/mob/living/carbon/human/S = shadow_mind.current
shadow_mind.current.verbs += /mob/living/carbon/human/proc/shadowling_hatch
shadow_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/enthrall
shadow_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
if(shadow_mind.assigned_role == "Clown")
S << "<span class='notice'>Your alien nature has allowed you to overcome your clownishness.</span>"
S.dna.remove_mutation(CLOWNMUT)
/datum/game_mode/proc/add_thrall(datum/mind/new_thrall_mind)
if (!istype(new_thrall_mind))
return 0
if(!(new_thrall_mind in thralls))
thralls += new_thrall_mind
new_thrall_mind.current.attack_log += "\[[time_stamp()]\] <span class='danger'>Became a thrall</span>"
return 1
/*
GAME FINISH CHECKS
*/
/datum/game_mode/shadowling/check_finished()
var/shadows_alive = 0 //and then shadowling was kill
for(var/datum/mind/shadow in shadows) //but what if shadowling was not kill?
if(!istype(shadow.current,/mob/living/carbon/human) && !istype(shadow.current,/mob/living/simple_animal/ascendant_shadowling))
continue
if(shadow.current.stat == DEAD)
continue
shadows_alive++
if(shadows_alive)
return ..()
else
shadowling_dead = 1 //but shadowling was kill :(
return 1
/datum/game_mode/shadowling/proc/check_shadow_victory()
var/success = 0 //Did they win?
if(shadow_objectives.Find("enthrall"))
success = shadowling_ascended
return success
/datum/game_mode/shadowling/declare_completion()
if(check_shadow_victory() && SSshuttle.emergency.mode >= SHUTTLE_ESCAPE) //Doesn't end instantly - this is hacky and I don't know of a better way ~X
world << "<font size=3 color=green><b>The shadowlings have ascended and taken over the station!</FONT></b></span>"
else if(shadowling_dead && !check_shadow_victory()) //If the shadowlings have ascended, they can not lose the round
world << "<span class='danger'><font size=3><b>The shadowlings have been killed by the crew!</b></FONT></span>"
else if(!check_shadow_victory() && SSshuttle.emergency.mode >= SHUTTLE_ESCAPE)
world << "<span class='danger'><font size=3><b>The crew has escaped the station before the shadowlings could ascend!</b></FONT></span>"
..()
return 1
/datum/game_mode/proc/auto_declare_completion_shadowling()
var/text = ""
if(shadows.len)
text += "<br><font size=2><b>The shadowlings were:</b></font>"
for(var/datum/mind/shadow in shadows)
text += printplayer(shadow)
if(thralls.len)
text += "<br><font size=2><b>The thralls were:</b></font>"
for(var/datum/mind/thrall in thralls)
text += printplayer(thrall)
else
world << "<font size=3>Round-end code broke! Please report this and its circumstances on GitHub at https://github.com/tgstation/-tg-station/issues</font>"
text += "<br>"
world << text
/*
MISCELLANEOUS
*/
/datum/species/shadow/ling
//Normal shadowpeople but with enhanced effects
name = "Shadowling"
id = "shadowling"
say_mod = "chitters"
specflags = list(NOBREATH,NOBLOOD,RADIMMUNE,NOGUNS) //Can't use guns due to muzzle flash
burnmod = 2 //2x burn damage lel
heatmod = 2
/datum/species/shadow/ling/spec_life(mob/living/carbon/human/H)
//H.shadowling_status = 1 //If they are affected more strongly by flashes and stuff
var/light_amount = 0
H.nutrition = NUTRITION_LEVEL_WELL_FED //i aint never get hongry
if(isturf(H.loc)) //Copypasta
var/turf/T = H.loc
var/area/A = T.loc
if(A)
if(A.lighting_use_dynamic) light_amount = T.lighting_lumcount
else light_amount = 10
if(light_amount > 2) //Rapid death while in the light, countered by...
H.take_overall_damage(0,6)
H << "<span class='userdanger'>The light burns you!</span>"
H << 'sound/weapons/sear.ogg'
else if (light_amount < 2) //...extreme benefits while in the dark
H.heal_overall_damage(5,3)
H.adjustToxLoss(-3)
H.SetWeakened(0)
H.SetStunned(0)
@@ -0,0 +1,613 @@
/obj/effect/proc_holder/spell/targeted/glare
name = "Glare"
desc = "Stuns and mutes a target for a decent duration."
panel = "Shadowling Abilities"
charge_max = 300
clothes_req = 0
/obj/effect/proc_holder/spell/targeted/glare/cast(list/targets)
for(var/mob/living/carbon/human/target in targets)
if(!ishuman(target))
charge_counter = charge_max
return
if(target.stat)
charge_counter = charge_max
return
if(is_shadow_or_thrall(target))
usr << "<span class='danger'>You don't see why you would want to paralyze an ally.</span>"
charge_counter = charge_max
return
usr.visible_message("<span class='warning'><b>[usr]'s eyes flash a blinding red!</b></span>")
target.visible_message("<span class='danger'>[target] freezes in place, their eyes glazing over...</span>")
if(in_range(target, usr))
target << "<span class='userdanger'>Your gaze is forcibly drawn into [src]'s eyes, and you are mesmerized by the heavenly lights...</span>"
else //Only alludes to the shadowling if the target is close by
target << "<span class='userdanger'>Red lights suddenly dance in your vision, and you are mesmerized by the heavenly lights...</span>"
target.Stun(10)
if(target.reagents)
target.reagents.add_reagent("mutetoxin", 4) //This is really bad but it's the only way it works.
/obj/effect/proc_holder/spell/aoe_turf/veil
name = "Veil"
desc = "Extinguishes all electronic lights in a decent radius."
panel = "Shadowling Abilities"
charge_max = 250 //Short cooldown because people can just turn the lights back on
clothes_req = 0
range = 5
/obj/effect/proc_holder/spell/aoe_turf/veil/cast(list/targets)
usr << "<span class='deadsay'>You silently disable all nearby lights.</span>"
var/list/blacklisted_lights = list(/obj/item/device/flashlight/flare, /obj/item/device/flashlight/slime)
for(var/turf/T in targets)
for(var/obj/item/device/flashlight/F in T.contents)
if(is_type_in_list(F, blacklisted_lights))
F.visible_message("<span class='danger'>[F] goes slightly dim for a moment.</span>")
return
F.on = 0
F.visible_message("<span class='danger'>[F] gutters and falls dark.</span>")
F.update_brightness()
for(var/obj/machinery/light/L in T.contents)
L.on = 0
L.visible_message("<span class='danger'>[L] flickers and falls dark.</span>")
L.update(0)
for(var/obj/item/device/pda/P in orange(5, usr))
P.fon = 0
P.SetLuminosity(0) //failsafe
/obj/effect/proc_holder/spell/targeted/shadow_walk
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
clothes_req = 0
range = -1
include_user = 1
/obj/effect/proc_holder/spell/targeted/shadow_walk/cast(list/targets)
for(var/mob/living/user in targets)
playsound(user.loc, 'sound/effects/bamf.ogg', 50, 1)
user.visible_message("<span class='danger'>[user] vanishes into thin air!</span>", "<span class='deadsay'>You enter the space between worlds as a passageway.</span>")
user.SetStunned(0)
user.SetWeakened(0)
user.incorporeal_move = 1
user.alpha = 0
if(user.buckled)
user.buckled.unbuckle_mob()
sleep(40) //4 seconds
user.visible_message("<span class='danger'>[user] appears out of nowhere!</span>", "<span class='deadsay'>The pressure becomes too much and you vacate the interdimensional darkness.</span>")
user.incorporeal_move = 0
user.alpha = 255
/obj/effect/proc_holder/spell/aoe_turf/flashfreeze
name = "Flash Freeze"
desc = "Instantly freezes the blood of nearby people, stunning them and causing burn damage."
panel = "Shadowling Abilities"
range = 5
charge_max = 1200
clothes_req = 0
/obj/effect/proc_holder/spell/aoe_turf/flashfreeze/cast(list/targets)
usr << "<span class='deadsay'>You freeze the nearby air.</span>"
playsound(usr.loc, 'sound/effects/ghost2.ogg', 50, 1)
for(var/turf/T in targets)
for(var/mob/living/carbon/human/target in T.contents)
if(is_shadow_or_thrall(target))
if(target == usr) //No message for the user, of course
continue
else
target << "<span class='danger'>You feel a blast of paralyzingly cold air wrap around you and flow past, but you are unaffected!</span>"
continue
target << "<span class='userdanger'>You are hit by a blast of paralyzingly cold air and feel goosebumps break out across your body!</span>"
target.Stun(2)
if(target.bodytemperature)
target.bodytemperature -= 200 //Extreme amount of initial cold
if(target.reagents)
target.reagents.add_reagent("frostoil", 15) //Half of a cryosting
//Enthrall is the single most important spell
/obj/effect/proc_holder/spell/targeted/enthrall
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"
charge_max = 450
clothes_req = 0
range = 1 //Adjacent to user
var/enthralling = 0
/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets)
for(var/mob/living/carbon/human/target in targets)
if(!in_range(usr, target))
usr << "<span class='warning'>You need to be closer to enthrall [target].</span>"
charge_counter = charge_max
return
if(!target.ckey)
usr << "<span class='warning'>The target has no mind.</span>"
charge_counter = charge_max
return
if(target.stat)
usr << "<span class='warning'>The target must be conscious.</span>"
charge_counter = charge_max
return
if(is_shadow_or_thrall(target))
usr << "<span class='warning'>You can not enthrall allies.</span>"
charge_counter = charge_max
return
if(!ishuman(target))
usr << "<span class='warning'>You can only enthrall humans.</span>"
charge_counter = charge_max
return
if(enthralling)
usr << "<span class='danger'>You are already enthralling!</span>"
charge_counter = charge_max
return
enthralling = 1
usr << "<span class='danger'>This target is valid. You begin the enthralling.</span>"
target << "<span class='userdanger'>[usr] focuses in concentration. Your head begins to ache.</span>"
for(var/progress = 0, progress <= 3, progress++)
switch(progress)
if(1)
usr << "<span class='notice'>You begin allocating energy for the enthralling.</span>"
usr.visible_message("<span class='danger'>[usr]'s eyes begin to throb a piercing red.</span>")
if(2)
usr << "<span class='notice'>You begin the enthralling of [target].</span>"
usr.visible_message("<span class='danger'>[usr] leans over [target], their eyes glowing a deep crimson, and stares into their face.</span>")
target << "<span class='danger'>Your gaze is forcibly drawn into a blinding red light. You fall to the floor as conscious thought is wiped away.</span>"
target.Weaken(12)
if(3)
usr << "<span class='notice'>You begin rearranging [target]'s memories.</span>"
usr.visible_message("<span class='danger'>[usr]'s eyes flare brightly, and a horrible grin begins to spread across [target]'s face...</span>")
target << "<span class='danger'>Your head cries out. The veil of reality begins to crumple and something evil bleeds through.</span>" //Ow the edge
if(!do_mob(usr, target, 100)) //around 30 seconds total for enthralling
usr << "<span class='danger'>The enthralling has been interrupted - your target's mind returns to its previous state.</span>"
target << "<span class='warning'>Your thoughts become coherent once more. Already you can barely remember what's happened to you.</span>"
enthralling = 0
return
enthralling = 0
usr << "<span class='notice'>You have enthralled <b>[target]</b>!</span>"
target << "<span class='deadsay'><b>You see the Truth. Reality has been torn away and you realize what a fool you've been.</b></span>"
target << "<span class='deadsay'><b>The shadowlings are your masters.</b> Serve them above all else and ensure they complete their goals.</span>"
target << "<span class='deadsay'>You may not harm other thralls or the shadowlings. However, you do not need to obey other thralls.</span>"
target << "<span class='deadsay'>You can communicate with the other enlightened ones by using the Hivemind Commune ability.</span>"
target.adjustOxyLoss(-200) //In case the shadowling was choking them out
ticker.mode.add_thrall(target.mind)
target.mind.special_role = "Thrall"
var/datum/mind/thrall_mind = target.mind
thrall_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind //Lets thralls hive-chat
/obj/effect/proc_holder/spell/targeted/shadowling_hivemind
name = "Hivemind Commune"
desc = "Allows you to silently communicate with all other shadowlings and thralls."
panel = "Shadowling Abilities"
charge_max = 25
clothes_req = 0
range = -1
include_user = 1
/obj/effect/proc_holder/spell/targeted/shadowling_hivemind/cast(list/targets)
for(var/mob/living/user in targets)
var/text = stripped_input(user, "What do you want to say to fellow thralls and shadowlings?.", "Hive Chat", "")
if(!text)
return
for(var/mob/M in mob_list)
if(is_shadow_or_thrall(M) || (M in dead_mob_list))
M << "<span class='shadowling'><b>\[Hive Chat\]</b><i> [usr.real_name]</i>: [text]</span>"
/obj/effect/proc_holder/spell/targeted/collective_mind
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"
charge_max = 300 //30 second cooldown to prevent spam
clothes_req = 0
range = -1
include_user = 1
var/blind_smoke_acquired
var/screech_acquired
var/drain_thrall_acquired
var/thrall_swap_acquired
/obj/effect/proc_holder/spell/targeted/collective_mind/cast(list/targets)
for(var/mob/living/user in targets)
var/thralls = 0
var/victory_threshold = 15
var/mob/M
user << "<span class='shadowling'><b>You focus your telepathic energies abound, harnessing and drawing together the strength of your thralls.</b></span>"
for(M in living_mob_list)
if(is_thrall(M))
thralls++
M << "<span class='deadsay'>You feel hooks sink into your mind and pull.</span>"
if(!do_after(user, 30))
user << "<span class='warning'>Your concentration has been broken. The mental hooks you have sent out now retract into your mind.</span>"
return
if(thralls >= 3 && !blind_smoke_acquired)
blind_smoke_acquired = 1
user << "<span class='shadowling'><i>The power of your thralls has granted you the <b>Blinding Smoke</b> ability. It will create a choking cloud that will blind any non-thralls who enter. \
</i></span>"
user.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/blindness_smoke
if(thralls >= 5 && !drain_thrall_acquired)
drain_thrall_acquired = 1
user << "<span class='shadowling'><i>The power of your thralls has granted you the <b>Drain Thrall</b> ability. You can now drain nearby thralls to heal yourself.</i></span>"
user.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/drain_thralls
if(thralls >= 7 && !screech_acquired)
screech_acquired = 1
user << "<span class='shadowling'><i>The power of your thralls has granted you the <b>Sonic Screech</b> ability. This ability will shatter nearby windows and deafen enemies.</span>"
user.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/unearthly_screech
if(thralls >= 10 && !thrall_swap_acquired)
thrall_swap_acquired = 1
user << "<span class='shadowling'><i>The power of your thralls has granted you the <b>Spatial Relocation</b> ability. This will, allow you to instantly swap places with one of your thralls in \
addition to shattering nearby lights.</i></span>"
user.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/spatial_relocation
if(thralls < victory_threshold)
user << "<span class='shadowling'>You do not have the power to ascend. You require [victory_threshold] thralls, but only [thralls] living thralls are present.</span>"
else if(thralls >= victory_threshold)
usr << "<span class='shadowling'><b>You are now powerful enough to ascend. Use the Ascendance ability when you are ready. <i>This will kill all of your thralls.</i></span>"
usr << "<span class='shadowling'><b>You may find Ascendance in the Shadowling Evolution tab.</b></span>"
for(M in living_mob_list)
if(is_shadow(M))
M.mind.spell_list -= /obj/effect/proc_holder/spell/targeted/collective_mind
M.mind.current.verbs -= /mob/living/carbon/human/proc/shadowling_hatch //In case a shadowling hasn't hatched
M.mind.current.verbs += /mob/living/carbon/human/proc/shadowling_ascendance
if(M == usr)
return
M << "<span class='shadowling'><b>[user.real_name] has coalesced the strength of the thralls. You can draw upon it at any time to ascend.</span>" //Tells all the other shadowlings
/obj/effect/proc_holder/spell/targeted/blindness_smoke
name = "Blindness Smoke"
desc = "Spews a cloud of smoke which will blind enemies."
panel = "Shadowling Abilities"
charge_max = 600
clothes_req = 0
range = -1
include_user = 1
/obj/effect/proc_holder/spell/targeted/blindness_smoke/cast(list/targets) //Extremely hacky
for(var/mob/living/user in targets)
user.visible_message("<span class='warning'>[user] suddenly bends over and coughs out a cloud of black smoke, which begins to spread rapidly!</span>")
user << "<span class='deadsay'>You regurgitate a vast cloud of blinding smoke.</span>"
playsound(user, 'sound/effects/bamf.ogg', 50, 1)
var/obj/item/weapon/reagent_containers/glass/beaker/large/B = new /obj/item/weapon/reagent_containers/glass/beaker/large(user.loc)
B.reagents.clear_reagents() //Just in case!
B.icon_state = null //Invisible
B.reagents.add_reagent("blindness_smoke", 10)
var/datum/effect/effect/system/chem_smoke_spread/S = new /datum/effect/effect/system/chem_smoke_spread
S.attach(B)
if(S)
S.set_up(B.reagents, 10, 0, B.loc)
S.start()
sleep(10)
S.start()
qdel(B)
datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowlings/thralls
name = "!(%@ ERROR )!@$"
id = "blindness_smoke"
description = "<::ERROR::> CANNOT ANALYZE REAGENT <::ERROR::>"
color = "#000000" //Complete black (RGB: 0, 0, 0)
metabolization_rate = 100 //lel
datum/reagent/shadowling_blindness_smoke/on_mob_life(var/mob/living/M as mob)
if(!M) M = holder.my_atom
if(!is_shadow_or_thrall(M))
M << "<span class='warning'><b>You breathe in the black smoke, and your eyes burn horribly!</b></span>"
M.eye_blind = 5
if(prob(25))
M.visible_message("<b>[M]</b> screams and claws at their eyes!")
M.Stun(2)
else
M << "<span class='notice'><b>You breathe in the black smoke, and you feel revitalized!</b></span>"
M.heal_organ_damage(2,2)
M.adjustOxyLoss(-2)
M.adjustToxLoss(-2)
..()
return
/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech
name = "Sonic Screech"
desc = "Deafens, stuns, and confuses nearby people. Also shatters windows."
panel = "Shadowling Abilities"
range = 7
charge_max = 300
clothes_req = 0
/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech/cast(list/targets)
usr.audible_message("<span class='warning'><b>[usr] lets out a horrible scream!</b></span>")
playsound(usr.loc, 'sound/effects/screech.ogg', 100, 1)
for(var/turf/T in targets)
for(var/mob/target in T.contents)
if(is_shadow_or_thrall(target))
if(target == usr) //No message for the user, of course
continue
else
continue
if(iscarbon(target))
var/mob/living/carbon/M = target
M << "<span class='danger'><b>A spike of pain drives into your head and scrambles your thoughts!</b></span>"
M.Weaken(2)
M.confused += 10
M.setEarDamage(M.ear_damage + 3)
else if(issilicon(target))
var/mob/living/silicon/S = target
S << "<span class='warning'><b>ERROR $!(@ ERROR )#^! SENSOR INTERFERENCE DETECTED</b></span>"
S << 'sound/misc/interference.ogg'
playsound(S, 'sound/machines/warning-buzzer.ogg', 50, 1)
var/datum/effect/effect/system/spark_spread/sp = new /datum/effect/effect/system/spark_spread
sp.set_up(5, 1, S)
sp.start()
S.Weaken(6)
for(var/obj/structure/window/W in T.contents)
W.hit(rand(25,50))
/obj/effect/proc_holder/spell/aoe_turf/drain_thralls
name = "Drain Thralls"
desc = "Damages nearby thralls, draining their life and healing yourself."
panel = "Shadowling Abilities"
range = 3
charge_max = 100
clothes_req = 0
var/thralls_drained = 0
var/list/nearby_thralls = list()
/obj/effect/proc_holder/spell/aoe_turf/drain_thralls/cast(list/targets)
thralls_drained = 0
nearby_thralls = list()
for(var/turf/T in targets)
for(var/mob/living/carbon/M in T.contents)
if(is_thrall(M))
thralls_drained++
nearby_thralls.Add(M)
M << "<span class='warning'>You feel a curious draining sensation and a wave of exhaustion washes over you.</span>"
for(var/mob/living/carbon/M in nearby_thralls)
nearby_thralls.Remove(M) //To prevent someone dying like a zillion times
M.take_organ_damage(25/thralls_drained,25/thralls_drained) //For every nearby thrall, the damage to each is reduced - 1 thrall = 50 for him, 2 thralls = 25 for each, etc.
usr << "<span class='deadsay'>You draw the life from [M] to heal your wounds.</span>"
if(thralls_drained)
var/mob/living/carbon/U = usr
U.heal_organ_damage(25, 25)
else
charge_counter = charge_max
usr << "<span class='warning'>There were no nearby thralls for you to drain.</span>"
/obj/effect/proc_holder/spell/targeted/spatial_relocation
name = "Spatial Relocation"
desc = "Swaps places with a thrall and breaks nearby lights."
panel = "Shadowling Abilities"
range = -1
charge_max = 3000
clothes_req = 0
include_user = 1
var/list/thralls_in_world = list()
/obj/effect/proc_holder/spell/targeted/spatial_relocation/cast(list/targets, distanceoverride)
for(var/mob/living/carbon/human/M in world)
if(is_thrall(M))
thralls_in_world += M
if(!thralls_in_world)
charge_counter = charge_max
return
var/mob/living/carbon/thrall_to_swap = input("Who do you wish to swap places with?", "Available Thralls") as null|anything in (thralls_in_world)
var/turf/shadowturf = get_turf(usr)
var/turf/thrallturf = get_turf(thrall_to_swap)
thrall_to_swap.visible_message("<span class='danger'>[thrall_to_swap] suddenly vanishes in a puff of black smoke!</span>")
thrall_to_swap << "<span class='warning'><b>You feel a brief sense of nausea before finding yourself in an entirely new place!</b></span>"
usr.visible_message("<span class='danger'>[usr] suddenly goes transparent and vanishes!</span>")
usr << "<span class='deadsay'>You experience vertigo as you swap your location with [thrall_to_swap]'s.</span>"
thrall_to_swap.loc = shadowturf
usr.loc = thrallturf
thrall_to_swap.Weaken(4)
usr.Weaken(4)
usr.regenerate_icons()
thrall_to_swap.regenerate_icons()
// ASCENDANT ABILITIES BEYOND THIS POINT //
/obj/effect/proc_holder/spell/targeted/annihilate
name = "Annihilate"
desc = "Gibs a human after a short time."
panel = "Ascendant"
range = 7
charge_max = 300
clothes_req = 0
/obj/effect/proc_holder/spell/targeted/annihilate/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
if(SHA.phasing)
usr << "<span class='warning'>You are not in the same plane of existence. Unphase first.</span>"
charge_counter = charge_max
return
for(var/mob/boom in targets)
if(is_shadow_or_thrall(boom))
usr << "<span class='warning'>Making an ally explode seems unwise.<span>"
charge_counter = charge_max
return
usr.visible_message("<span class='danger'>[usr]'s eyes flare as they gesture at [boom]!</span>", \
"<span class='shadowling'>You direct a lance of telekinetic energy at [boom].</span>")
boom << "<span class='userdanger'><font size=3>You feel an immense pressure building all across your body!</span></font>"
boom.Stun(10)
boom.audible_message("<b>[boom]</b> screams!")
sleep(20)
playsound(boom, 'sound/effects/splat.ogg', 100, 1)
boom.visible_message("<span class='userdanger'>[boom] explodes!</span>")
boom.gib()
/obj/effect/proc_holder/spell/targeted/hypnosis
name = "Hypnosis"
desc = "Instantly enthralls a human."
panel = "Ascendant"
range = 7
charge_max = 450
clothes_req = 0
/obj/effect/proc_holder/spell/targeted/hypnosis/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
if(SHA.phasing)
charge_counter = charge_max
usr << "<span class='warning'>You are not in the same plane of existence. Unphase first.</span>"
return
for(var/mob/living/carbon/human/target in targets)
if(is_shadow_or_thrall(target))
usr << "<span class='warning'>You cannot enthrall an ally.<span>"
charge_counter = charge_max
return
if(!target.ckey)
usr << "<span class='warning'>The target has no mind.</span>"
charge_counter = charge_max
return
if(target.stat)
usr << "<span class='warning'>The target must be conscious.</span>"
charge_counter = charge_max
return
if(!ishuman(target))
usr << "<span class='warning'>You can only enthrall humans.</span>"
charge_counter = charge_max
return
usr << "<span class='shadowling'>You instantly rearrange <b>[target]</b>'s memories, hyptonitizing them into a thrall.</span>"
target << "<span class='userdanger'><font size=3>An agonizing spike of pain drives into your mind, and--</font></span>"
target << "<span class='deadsay'><b>And you see the Truth. Reality has been torn away and you realize what a fool you've been.</b></span>"
target << "<span class='deadsay'><b>The shadowlings are your masters.</b> Serve them above all else and ensure they complete their goals.</span>"
target << "<span class='deadsay'>You may not harm other thralls or the shadowlings. However, you do not need to obey other thralls.</span>"
target << "<span class='deadsay'>You can communicate with the other enlightened ones by using the Hivemind Commune ability.</span>"
ticker.mode.add_thrall(target.mind)
target.mind.special_role = "Thrall"
var/datum/mind/thrall_mind = target.mind
thrall_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift
name = "Phase Shift"
desc = "Phases you into the space between worlds at will, allowing you to move through walls and become invisible."
panel = "Ascendant"
range = -1
include_user = 1
charge_max = 15
clothes_req = 0
/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
for(SHA in targets)
SHA.phasing = !SHA.phasing
if(SHA.phasing)
SHA.visible_message("<span class='danger'>[SHA] suddenly vanishes!</span>", \
"<span class='shadowling'>You begin phasing through planes of existence. Use the ability again to return.</span>")
SHA.incorporeal_move = 1
SHA.alpha = 0
else
SHA.visible_message("<span class='danger'>[SHA] suddenly appears from nowhere!</span>", \
"<span class='shadowling'>You return from the space between worlds.</span>")
SHA.incorporeal_move = 0
SHA.alpha = 255
/obj/effect/proc_holder/spell/aoe_turf/glacial_blast
name = "Glacial Blast"
desc = "Extremely empowered version of Flash Freeze."
panel = "Ascendant"
range = 5
charge_max = 600
clothes_req = 0
/obj/effect/proc_holder/spell/aoe_turf/glacial_blast/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
if(SHA.phasing)
usr << "<span class='warning'>You are not in the same plane of existence. Unphase first.</span>"
return
usr << "<span class='deadsay'>You freeze the nearby air.</span>"
playsound(usr.loc, 'sound/effects/ghost2.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))
if(target == usr) //No message for the user, of course
continue
else
target << "<span class='danger'>You feel a blast of paralyzingly cold air wrap around you and flow past, but you are unaffected!</span>"
continue
target << "<span class='userdanger'>You are hit by a blast of cold unlike anything you have ever felt. Your limbs instantly lock in place and you feel ice burns across your body!</span>"
target.Weaken(15)
if(target.bodytemperature)
target.bodytemperature -= INFINITY //:^)
target.take_organ_damage(0,80)
/obj/effect/proc_holder/spell/targeted/vortex
name = "Vortex"
desc = "Tears open a hole in reality. Anyone, INCLUDING YOU, walking through it will be trapped there for eternity."
panel = "Ascendant"
range = -1
include_user = 1
charge_max = 1200
clothes_req = 0
/obj/effect/proc_holder/spell/targeted/vortex/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
if(SHA.phasing)
usr << "<span class='warning'>You are not in the same plane of existence. Unphase first.</span>"
return
for(SHA in targets)
SHA.visible_message("<span class='userdanger'>[SHA] raises their arms upward as the markings on their body flare a blinding red!</span>", \
"<span class='shadowling'>You tear open a rift to the black space between worlds. <b><font size=3>It would be wise to avoid it.</font></b></span>")
new /obj/structure/shadow_vortex(SHA.loc)
/obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant
name = "Ascendant Commune"
desc = "Allows you to silently communicate with all other shadowlings and thralls."
panel = "Ascendant"
charge_max = 20
clothes_req = 0
range = -1
include_user = 1
/obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant/cast(list/targets)
for(var/mob/living/user in targets)
var/text = stripped_input(user, "What do you want to say to fellow thralls and shadowlings?.", "Hive Chat", "")
if(!text)
return
text = "<font size=3>[text]</font>"
for(var/mob/M in mob_list)
if(is_shadow_or_thrall(M) || (M in dead_mob_list))
M << "<span class='shadowling'><b>\[Hive Chat\]<i> [usr.real_name] (ASCENDANT)</i>: [text]</b></span>" //Bigger text for ascendants.
@@ -0,0 +1,102 @@
/obj/item/clothing/under/shadowling
name = "blackened flesh"
desc = "Black, chitonous skin."
item_state = "golem"
origin_tech = null
icon_state = "golem"
flags = ABSTRACT | NODROP
has_sensor = 0
unacidable = 1
/obj/item/clothing/suit/space/shadowling
name = "chitin shell"
desc = "Dark, semi-transparent shell. Protects against vacuum, but not against the light of the stars." //Still takes damage from spacewalking but is immune to space itself
icon_state = "golem"
item_state = "golem"
body_parts_covered = FULL_BODY //Shadowlings are immune to space
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
/obj/item/clothing/shoes/shadowling
name = "chitin feet"
desc = "Charred-looking feet. They have minature hooks that latch onto flooring."
icon_state = "golem"
unacidable = 1
flags = NOSLIP | ABSTRACT | NODROP
/obj/item/clothing/mask/gas/shadowling
name = "chitin mask"
desc = "A mask-like formation with slots for facial features. A red film covers the eyes."
icon_state = "golem"
item_state = "golem"
origin_tech = null
siemens_coefficient = 0
unacidable = 1
flags = ABSTRACT | NODROP
/obj/item/clothing/gloves/shadowling
name = "chitin hands"
desc = "An electricity-resistant yet thin covering of the hands."
icon_state = "golem"
item_state = null
origin_tech = null
siemens_coefficient = 0
unacidable = 1
flags = ABSTRACT | NODROP
/obj/item/clothing/head/shadowling
name = "chitin helm"
desc = "A helmet-like enclosure of the head."
icon_state = "golem"
item_state = null
origin_tech = null
unacidable = 1
flags = ABSTRACT | NODROP
/obj/item/clothing/glasses/night/shadowling
name = "crimson eyes"
desc = "A shadowling's eyes. Very light-sensitive and can detect body heat through walls."
icon = null
icon_state = null
item_state = null
origin_tech = null
vision_flags = SEE_MOBS
darkness_view = 3
invis_view = 2
flash_protect = 2
unacidable = 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("<span class='warning'><b>\The [src] lets out a dismaying screech as dimensional barriers are torn apart!</span>")
playsound(loc, 'sound/effects/supermatter.ogg', 100, 1)
sleep(100)
qdel(src)
/obj/structure/shadow_vortex/Crossed(var/td)
..()
if(ismob(td))
td << "<span class='userdanger'><font size=3>You enter the rift. Sickening chimes begin to jangle in your ears. \
All around you is endless blackness. After you see something moving, you realize it isn't entirely lifeless.</font></span>" //A bit of spooking before they die
playsound(loc, 'sound/effects/EMPulse.ogg', 25, 1)
qdel(td)
@@ -0,0 +1,161 @@
//In here: Hatch and Ascendance
/mob/living/carbon/human/proc/shadowling_hatch()
set category = "Shadowling Evolution"
set name = "Hatch"
if(usr.stat)
return
usr.verbs -= /mob/living/carbon/human/proc/shadowling_hatch
switch(alert("Are you sure you want to hatch? You cannot undo this!",,"Yes","No"))
if("No")
usr << "<span class='warning'>You decide against hatching for now."
usr.verbs += /mob/living/carbon/human/proc/shadowling_hatch
return
if("Yes")
usr.notransform = 1
usr.visible_message("<span class='warning'>[usr]'s things suddenly slip off. They hunch over and vomit up a copious amount of purple goo which begins to shape around them!</span>", \
"<span class='shadowling'>You remove any equipment which would hinder your hatching and begin regurgitating the resin which will protect you.</span>")
for(var/obj/item/I in usr) //drops all items
usr.unEquip(I)
sleep(50)
var/turf/simulated/floor/F
var/turf/shadowturf = get_turf(usr)
for(F in orange(1, usr))
new /obj/structure/alien/resin/wall/shadowling(F)
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 with the chrysalis
usr.visible_message("<span class='warning'>A chrysalis forms around [usr], sealing them inside.</span>", \
"<span class='shadowling'>You create your chrysalis and begin to contort within.</span>")
sleep(100)
usr.visible_message("<span class='warning'><b>The skin on [usr]'s back begins to split apart. Black spines slowly emerge from the divide.</b></span>", \
"<span class='shadowling'>Spines pierce your back. Your claws break apart your fingers. You feel excruciating pain as your true form begins its exit.</span>")
sleep(90)
usr.visible_message("<span class='warning'><b>[usr], now no longer recognizable as human, begins clawing at the resin walls around them.</b></span>", \
"<span class='shadowling'>Your false skin slips away. You begin tearing at the fragile membrane protecting you.</span>")
sleep(80)
playsound(usr.loc, 'sound/weapons/slash.ogg', 25, 1)
usr << "<i><b>You rip and slice.</b></i>"
sleep(10)
playsound(usr.loc, 'sound/weapons/slashmiss.ogg', 25, 1)
usr << "<i><b>The chrysalis falls like water before you.</b></i>"
sleep(10)
playsound(usr.loc, 'sound/weapons/slice.ogg', 25, 1)
usr << "<i><b>You are free!</b></i>"
sleep(10)
playsound(usr.loc, 'sound/effects/ghost.ogg', 100, 1)
usr.real_name = "Shadowling ([rand(1,1000)])"
usr.name = usr.real_name
usr.notransform = 0
usr << "<i><b><font size=3>YOU LIVE!!!</i></b></font>"
for(var/obj/structure/alien/resin/wall/shadowling/W in orange(usr, 1))
playsound(W, 'sound/effects/splat.ogg', 50, 1)
qdel(W)
for(var/obj/structure/alien/weeds/node/N in shadowturf)
qdel(N)
usr.visible_message("<span class='warning'>The chrysalis explodes in a shower of purple flesh and fluid!</span>")
var/mob/living/carbon/human/M = usr
M.underwear = "Nude"
M.undershirt = "Nude"
M.socks = "Nude"
M.faction |= "faithless"
usr.equip_to_slot_or_del(new /obj/item/clothing/under/shadowling(usr), slot_w_uniform)
usr.equip_to_slot_or_del(new /obj/item/clothing/shoes/shadowling(usr), slot_shoes)
usr.equip_to_slot_or_del(new /obj/item/clothing/suit/space/shadowling(usr), slot_wear_suit)
usr.equip_to_slot_or_del(new /obj/item/clothing/head/shadowling(usr), slot_head)
usr.equip_to_slot_or_del(new /obj/item/clothing/gloves/shadowling(usr), slot_gloves)
usr.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(usr), slot_wear_mask)
usr.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/shadowling(usr), slot_glasses)
hardset_dna(usr, null, null, null, null, /datum/species/shadow/ling) //can't be a shadowling without being a shadowling
sleep(10)
usr << "<span class='shadowling'><b><i>Your powers are awoken. You may now live to your fullest extent. Remember your goal. Cooperate with your thralls and allies.</b></i></span>"
usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/glare
usr.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/veil
usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadow_walk
usr.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/flashfreeze
usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/collective_mind
/mob/living/carbon/human/proc/shadowling_ascendance()
set category = "Shadowling Evolution"
set name = "Ascendance"
if(usr.stat)
return
usr.verbs -= /mob/living/carbon/human/proc/shadowling_ascendance
switch(alert("It is time to ascend. Are you completely sure about this? You cannot undo this!",,"Yes","No"))
if("No")
usr << "<span class='warning'>You decide against ascending for now."
usr.verbs += /mob/living/carbon/human/proc/shadowling_ascendance
return
if("Yes")
usr.notransform = 1
usr.visible_message("<span class='warning'>[usr] rapidly bends and contorts, their eyes flaring a deep crimson!</span>", \
"<span class='shadowling'>You begin unlocking the genetic vault within you and prepare yourself for the power to come.</span>")
sleep(30)
usr.visible_message("<span class='danger'>[usr] suddenly shoots up a few inches in the air and begins hovering there, still twisting.</span>", \
"<span class='shadowling'>You hover into the air to make room for your new form.</span>")
sleep(60)
usr.visible_message("<span class='danger'>[usr]'s skin begins to pulse red in sync with their eyes. Their form slowly expands outward.</span>", \
"<span class='shadowling'>You feel yourself beginning to mutate.</span>")
sleep(20)
if(!ticker.mode.shadowling_ascended)
usr << "<span class='shadowling'>It isn't enough. Time to draw upon your thralls.</span>"
else
usr << "<span class='shadowling'>After some telepathic searching, you find the reservoir of life energy from the thralls and tap into it.</span>"
sleep(50)
for(var/mob/M in mob_list)
if(is_thrall(M) && !ticker.mode.shadowling_ascended)
M.visible_message("<span class='userdanger'>[M] trembles minutely as their form turns to ash, black smoke pouring from their disintegrating face.</span>", \
"<span class='userdanger'><font size=3>It's time! Your masters are ascending! Your last thoughts are happy as your body is drained of life.</span>")
ticker.mode.thralls -= M.mind //To prevent message spam
M.death(0)
M.dust()
usr << "<span class='userdanger'>Drawing upon your thralls, you find the strength needed to finish and rend apart the final barriers to godhood.</b></span>"
sleep(40)
for(var/mob/living/M in orange(7, src))
M.Weaken(10)
M << "<span class='userdanger'>An immense pressure slams you onto the ground!</span>"
usr << "<font size=3.5><span class='shadowling'>YOU LIVE!!!</font></span>"
world << "<br><br><font size=4><span class='shadowling'><b>A horrible wail echoes in your mind as the world plunges into blackness.</font></span><br><br>"
world << 'sound/hallucinations/veryfar_noise.ogg'
for(var/obj/machinery/power/apc/A in world)
A.overload_lighting()
var/mob/A = new /mob/living/simple_animal/ascendant_shadowling(usr.loc)
usr.mind.spell_list = list()
usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/annihilate
usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/hypnosis
usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_phase_shift
usr.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/glacial_blast
usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/vortex
usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant
usr.mind.transfer_to(A)
A.name = usr.real_name
if(A.real_name)
A.real_name = usr.real_name
usr.alpha = 0 //This is pretty bad, but is also necessary for the shuttle call to function properly
usr.flags |= GODMODE
usr.notransform = 1
sleep(50)
if(!ticker.mode.shadowling_ascended)
SSshuttle.emergency.request(null, 0.3)
qdel(usr)
+5
View File
@@ -47,6 +47,11 @@
relativewall_neighbours()
..()
/obj/structure/alien/resin/wall/shadowling //For chrysalis
name = "chrysalis wall"
desc = "Some sort of purple substance in an egglike shape. It pulses and throbs from within and seems impenetrable."
health = INFINITY
/obj/structure/alien/resin/membrane
name = "resin membrane"
desc = "Resin just thin enough to let light pass through."
+6
View File
@@ -501,6 +501,12 @@
if(ticker.mode.traitors.len)
dat += check_role_table("Traitors", ticker.mode.traitors, src)
if(ticker.mode.shadows.len)
dat += check_role_table("Shadowlings", ticker.mode.shadowlings, src)
if(ticker.mode.thralls.len)
dat += check_role_table("Shadowling Thralls", ticker.thralls, src)
if(ticker.mode.vampires.len)
dat += check_role_table("Vampires", ticker.mode.vampires, src)
+2 -1
View File
@@ -17,7 +17,8 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set
"raider" = IS_MODE_COMPILED("heist"), // 1024 / 11
"vampire" = IS_MODE_COMPILED("vampire"), // 2048 / 12
"mutineer" = IS_MODE_COMPILED("mutiny"), // 4096 / 13
"blob" = IS_MODE_COMPILED("blob") // 8192 / 14
"blob" = IS_MODE_COMPILED("blob") // 8192 / 14
"shadowling" = IS_MODE_COMPILED("shadowling") //16384 / 15
)
var/global/list/special_role_times = list( //minimum age (in days) for accounts to play these roles
num2text(BE_PAI) = 0,
@@ -0,0 +1,33 @@
/mob/living/simple_animal/ascendant_shadowling
name = "Ascendant Shadowling"
desc = "A large, floating eldritch horror. It has pulsing markings all about its body and large horns. It seems to be floating without any form of support."
icon = 'icons/mob/mob.dmi'
icon_state = "shadowling_ascended"
icon_living = "shadowling_ascended"
speak_emote = list("telepathically thunders", "telepathically booms")
force_threshold = INFINITY //Can't die by normal means
health = 100000
maxHealth = 100000
speed = 0
var/phasing = 0
see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
response_help = "stares at"
response_disarm = "flails at"
response_harm = "flails at"
harm_intent_damage = 0
melee_damage_lower = 35
melee_damage_upper = 35
attacktext = "claws at"
attack_sound = 'sound/weapons/slash.ogg'
minbodytemp = 0
maxbodytemp = INFINITY
environment_smash = 2
faction = list("faithless")
/mob/living/simple_animal/ascendant_shadowling/Process_Spacemove(var/movement_dir = 0)
return 1 //copypasta from carp code
+1
View File
@@ -751,6 +751,7 @@ var/list/TAGGERLOCATIONS = list("Disposals",
#define BE_VAMPIRE 2048
#define BE_MUTINEER 4096
#define BE_BLOB 8192
#define BE_SHADOWLING 16384
var/list/be_special_flags = list(
"traitor" = BE_TRAITOR,
+1
View File
@@ -61,6 +61,7 @@ h1.alert, h2.alert {color: #000000;}
.notice {color: #000099;}
.boldnotice {color: #000099; font-weight: bold;}
.suicide {color: #ff5050; font-style: italic;}
.shadowling {color: #311648;}
.newscaster {color: #800000;}