Complete Revenant Rewrite (#18522)
I'm unhappy with the way revenants are right now, and my code for them is pretty unsatisfactory in comparison to what I know now. Although revenants will still fill the same role of just being spookier ghosts, they'll be a bit more passive - incapable, for instance, of giving diseases to people. The new revenants will be called umbras and will use vitae instead of essence.
Total change list:
Revenants have been renamed to umbras. Essence has been renamed to vitae. This may be temporary.
Umbra spawn events are now weighted higher and spawn an unoccupied umbra. Ghosts are alerted to the umbra's position and may interact with it to take control of it.
Umbras' health is not based on vitae but has a hard cap at 100.
Umbras have a passive vitae drain each tick, defaulting at 0.01. If the umbra runs out of vitae, they will die irrevocably. They also slowly regenerate health by doing this.
When an umbra dies, they leave behind umbral ashes that reform after one minute. They're difficult to see and can be scattered by activating them, although they also have high research levels if you're fast enough.
Harvesting vitae from critical targets no longer kills them. Harvesting a target in general prohibits them from being harvested until five minutes later, but they can be drained again after that.
EMPs revitalize umbras and give them hefty amounts of vitae due to their physical nature.
Umbras have four abilities: Toggle Nightvision, Discordant Whisper, Possess, and Thoughtsteal.
Toggle Nightvision is self-explanatory.
Discordant Whisper is identical to the original revenant's transmit.
Possess allows the umbra to slip into a human's body unnoticed. While in their body, umbras will slowly drain vitae from the human at a tiny rate - not enough to cause harm, but enough to induce adverse effects in the clueless human. These effects intensify over time and eventually lead to the umbra being forced out of their host.
Thoughtsteal paralyzes a living human for several seconds while the umbra steals their memories. After several seconds, the umbra copies the notes of the target's memories and turns invisible - the hapless victim is stunned for several seconds afterwards and can't be Thoughtstolen by the same umbra again. Umbras have an objective to steal the memories of 25% of the station's population.
Salt piles have been added, created by salt shaker or just by splashing salt. These piles will prevent an umbra from passing and reveal them briefly if they try.
@@ -72,6 +72,8 @@
|
||||
|
||||
#define isguardian(A) (istype(A, /mob/living/simple_animal/hostile/guardian))
|
||||
|
||||
#define isumbra(A) (istype(A, /mob/living/simple_animal/umbra))
|
||||
|
||||
#define islimb(A) (istype(A, /obj/item/bodypart))
|
||||
|
||||
#define isbot(A) (istype(A, /mob/living/simple_animal/bot))
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#define ROLE_GANG "gangster"
|
||||
#define ROLE_SHADOWLING "shadowling"
|
||||
#define ROLE_ABDUCTOR "abductor"
|
||||
#define ROLE_REVENANT "revenant"
|
||||
#define ROLE_HOG_GOD "hand of god: god"
|
||||
#define ROLE_HOG_CULTIST "hand of god: cultist"
|
||||
#define ROLE_DEVIL "devil"
|
||||
@@ -45,7 +44,6 @@ var/global/list/special_roles = list(
|
||||
ROLE_MONKEY = /datum/game_mode/monkey,
|
||||
ROLE_GANG = /datum/game_mode/gang,
|
||||
ROLE_SHADOWLING = /datum/game_mode/shadowling,
|
||||
ROLE_REVENANT,
|
||||
ROLE_ABDUCTOR = /datum/game_mode/abduction,
|
||||
ROLE_HOG_GOD = /datum/game_mode/hand_of_god,
|
||||
ROLE_HOG_CULTIST = /datum/game_mode/hand_of_god,
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
/datum/hud/revenant/New(mob/owner)
|
||||
..()
|
||||
|
||||
healths = new /obj/screen/healths/revenant()
|
||||
infodisplay += healths
|
||||
|
||||
/mob/living/simple_animal/revenant/create_mob_hud()
|
||||
if(client && !hud_used)
|
||||
hud_used = new /datum/hud/revenant(src)
|
||||
@@ -455,13 +455,6 @@
|
||||
screen_loc = ui_health
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/screen/healths/revenant
|
||||
name = "essence"
|
||||
icon = 'icons/mob/actions.dmi'
|
||||
icon_state = "bg_revenant"
|
||||
screen_loc = ui_health
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/screen/healthdoll
|
||||
name = "health doll"
|
||||
screen_loc = ui_healthdoll
|
||||
|
||||
@@ -2,8 +2,10 @@ This folder contains all "mini-antagonists" - antagonists that can still spice u
|
||||
Currently, that list consists of:
|
||||
-Abductors
|
||||
-Swarmers
|
||||
-Prophets of sin
|
||||
-The Jungle Fever virus (infected monkey bites human, human becomes another infected monkey)
|
||||
-Morphs
|
||||
-Revenants
|
||||
-Sintouched crewmembers
|
||||
-Slaughter demons
|
||||
-Umbras (formerly revenants)
|
||||
Please update this if you add another mini-antagonist.
|
||||
|
||||
@@ -1,442 +0,0 @@
|
||||
//Revenants: based off of wraiths from Goon
|
||||
//"Ghosts" that are invisible and move like ghosts, cannot take damage while invisible
|
||||
//Don't hear deadchat and are NOT normal ghosts
|
||||
//Admin-spawn or random event
|
||||
|
||||
#define INVISIBILITY_REVENANT 50
|
||||
|
||||
/mob/living/simple_animal/revenant
|
||||
name = "revenant"
|
||||
desc = "A malevolent spirit."
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "revenant_idle"
|
||||
var/icon_idle = "revenant_idle"
|
||||
var/icon_reveal = "revenant_revealed"
|
||||
var/icon_stun = "revenant_stun"
|
||||
var/icon_drain = "revenant_draining"
|
||||
incorporeal_move = 3
|
||||
invisibility = INVISIBILITY_REVENANT
|
||||
health = INFINITY //Revenants don't use health, they use essence instead
|
||||
maxHealth = INFINITY
|
||||
layer = GHOST_LAYER
|
||||
healable = 0
|
||||
sight = SEE_SELF
|
||||
see_invisible = SEE_INVISIBLE_NOLIGHTING
|
||||
see_in_dark = 8
|
||||
languages = ALL
|
||||
response_help = "passes through"
|
||||
response_disarm = "swings through"
|
||||
response_harm = "punches through"
|
||||
unsuitable_atmos_damage = 0
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) //I don't know how you'd apply those, but revenants no-sell them anyway.
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
harm_intent_damage = 0
|
||||
friendly = "touches"
|
||||
status_flags = 0
|
||||
wander = 0
|
||||
density = 0
|
||||
flying = 1
|
||||
anchored = 1
|
||||
mob_size = MOB_SIZE_TINY
|
||||
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
|
||||
speed = 1
|
||||
unique_name = 1
|
||||
hud_possible = list(ANTAG_HUD)
|
||||
|
||||
var/essence = 75 //The resource, and health, of revenants.
|
||||
var/essence_regen_cap = 75 //The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount.
|
||||
var/essence_regenerating = 1 //If the revenant regenerates essence or not; 1 for yes, 0 for no
|
||||
var/essence_regen_amount = 5 //How much essence regenerates
|
||||
var/essence_accumulated = 0 //How much essence the revenant has stolen
|
||||
var/revealed = 0 //If the revenant can take damage from normal sources.
|
||||
var/unreveal_time = 0 //How long the revenant is revealed for, is about 2 seconds times this var.
|
||||
var/unstun_time = 0 //How long the revenant is stunned for, is about 2 seconds times this var.
|
||||
var/inhibited = 0 //If the revenant's abilities are blocked by a chaplain's power.
|
||||
var/essence_drained = 0 //How much essence the revenant will drain from the corpse it's feasting on.
|
||||
var/draining = 0 //If the revenant is draining someone.
|
||||
var/list/drained_mobs = list() //Cannot harvest the same mob twice
|
||||
var/perfectsouls = 0 //How many perfect, regen-cap increasing souls the revenant has. //TODO, add objective for getting a perfect soul(s?)
|
||||
var/image/ghostimage = null //Visible to ghost with darkness off
|
||||
|
||||
/mob/living/simple_animal/revenant/New()
|
||||
..()
|
||||
|
||||
ghostimage = image(src.icon,src,src.icon_state)
|
||||
ghost_darkness_images |= ghostimage
|
||||
updateallghostimages()
|
||||
|
||||
spawn(5)
|
||||
if(src.mind)
|
||||
src.mind.remove_all_antag()
|
||||
src.mind.wipe_memory()
|
||||
src << 'sound/effects/ghost.ogg'
|
||||
src << "<br>"
|
||||
src << "<span class='deadsay'><font size=3><b>You are a revenant.</b></font></span>"
|
||||
src << "<b>Your formerly mundane spirit has been infused with alien energies and empowered into a revenant.</b>"
|
||||
src << "<b>You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds.</b>"
|
||||
src << "<b>You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.</b>"
|
||||
src << "<b>To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities.</b>"
|
||||
src << "<b><i>You do not remember anything of your past lives, nor will you remember anything about this one after your death.</i></b>"
|
||||
src << "<b>Be sure to read the wiki page at https://tgstation13.org/wiki/Revenant to learn more.</b>"
|
||||
var/datum/objective/revenant/objective = new
|
||||
objective.owner = src.mind
|
||||
src.mind.objectives += objective
|
||||
src << "<b>Objective #1</b>: [objective.explanation_text]"
|
||||
var/datum/objective/revenantFluff/objective2 = new
|
||||
objective2.owner = src.mind
|
||||
src.mind.objectives += objective2
|
||||
src << "<b>Objective #2</b>: [objective2.explanation_text]"
|
||||
ticker.mode.traitors |= src.mind //Necessary for announcing
|
||||
AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision/revenant(null))
|
||||
AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null))
|
||||
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null))
|
||||
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/overload(null))
|
||||
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction(null))
|
||||
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/blight(null))
|
||||
|
||||
|
||||
//Life, Stat, Hud Updates, and Say
|
||||
/mob/living/simple_animal/revenant/Life()
|
||||
if(revealed && essence <= 0)
|
||||
death()
|
||||
if(unreveal_time && world.time >= unreveal_time)
|
||||
unreveal_time = 0
|
||||
revealed = 0
|
||||
incorporeal_move = 3
|
||||
invisibility = INVISIBILITY_REVENANT
|
||||
src << "<span class='revenboldnotice'>You are once more concealed.</span>"
|
||||
if(unstun_time && world.time >= unstun_time)
|
||||
unstun_time = 0
|
||||
notransform = 0
|
||||
src << "<span class='revenboldnotice'>You can move again!</span>"
|
||||
if(essence_regenerating && !inhibited && essence < essence_regen_cap) //While inhibited, essence will not regenerate
|
||||
essence = min(essence_regen_cap, essence+essence_regen_amount)
|
||||
update_action_buttons_icon() //because we update something required by our spells in life, we need to update our buttons
|
||||
update_spooky_icon()
|
||||
update_health_hud()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/revenant/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Current essence: [essence]/[essence_regen_cap]E")
|
||||
stat(null, "Stolen essence: [essence_accumulated]E")
|
||||
stat(null, "Stolen perfect souls: [perfectsouls]")
|
||||
|
||||
/mob/living/simple_animal/revenant/update_health_hud()
|
||||
if(hud_used)
|
||||
var/essencecolor = "#8F48C6"
|
||||
if(essence > essence_regen_cap)
|
||||
essencecolor = "#9A5ACB" //oh boy you've got a lot of essence
|
||||
else if(essence == 0)
|
||||
essencecolor = "#1D2953" //oh jeez you're dying
|
||||
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='[essencecolor]'>[essence]E</font></div>"
|
||||
|
||||
/mob/living/simple_animal/revenant/med_hud_set_health()
|
||||
return //we use no hud
|
||||
|
||||
/mob/living/simple_animal/revenant/med_hud_set_status()
|
||||
return //we use no hud
|
||||
|
||||
/mob/living/simple_animal/revenant/say(message)
|
||||
if(!message)
|
||||
return
|
||||
log_say("[key_name(src)] : [message]")
|
||||
var/rendered = "<span class='revennotice'><b>[src]</b> says, \"[message]\"</span>"
|
||||
for(var/mob/M in mob_list)
|
||||
if(istype(M, /mob/living/simple_animal/revenant))
|
||||
M << rendered
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
M << "[link] [rendered]"
|
||||
return
|
||||
|
||||
|
||||
//Immunities
|
||||
/mob/living/simple_animal/revenant/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/revenant/ex_act(severity, target)
|
||||
return 1 //Immune to the effects of explosions.
|
||||
|
||||
/mob/living/simple_animal/revenant/blob_act(obj/effect/blob/B)
|
||||
return //blah blah blobs aren't in tune with the spirit world, or something.
|
||||
|
||||
/mob/living/simple_animal/revenant/singularity_act()
|
||||
return //don't walk into the singularity expecting to find corpses, okay?
|
||||
|
||||
/mob/living/simple_animal/revenant/narsie_act()
|
||||
return //most humans will now be either bones or harvesters, but we're still un-alive.
|
||||
|
||||
|
||||
//damage, gibbing, and dying
|
||||
/mob/living/simple_animal/revenant/attackby(obj/item/W, mob/living/user, params)
|
||||
. = ..()
|
||||
if(istype(W, /obj/item/weapon/nullrod))
|
||||
visible_message("<span class='warning'>[src] violently flinches!</span>", \
|
||||
"<span class='revendanger'>As \the [W] passes through you, you feel your essence draining away!</span>")
|
||||
adjustBruteLoss(25) //hella effective
|
||||
inhibited = 1
|
||||
update_action_buttons_icon()
|
||||
spawn(30)
|
||||
inhibited = 0
|
||||
update_action_buttons_icon()
|
||||
|
||||
/mob/living/simple_animal/revenant/adjustHealth(amount)
|
||||
if(!revealed)
|
||||
return 0
|
||||
. = amount
|
||||
essence = max(0, essence-amount)
|
||||
update_health_hud()
|
||||
if(essence == 0)
|
||||
src << "<span class='revendanger'>You feel your essence fraying!</span>"
|
||||
|
||||
/mob/living/simple_animal/revenant/dust()
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/revenant/gib()
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/revenant/death()
|
||||
if(!revealed || stat == DEAD) //Revenants cannot die if they aren't revealed //or are already dead
|
||||
return 0
|
||||
..(1)
|
||||
ghost_darkness_images -= ghostimage
|
||||
updateallghostimages()
|
||||
src << "<span class='revendanger'>NO! No... it's too late, you can feel your essence [pick("breaking apart", "drifting away")]...</span>"
|
||||
notransform = 1
|
||||
revealed = 1
|
||||
invisibility = 0
|
||||
playsound(src, 'sound/effects/screech.ogg', 100, 1)
|
||||
visible_message("<span class='warning'>[src] lets out a waning screech as violet mist swirls around its dissolving body!</span>")
|
||||
icon_state = "revenant_draining"
|
||||
for(var/i = alpha, i > 0, i -= 10)
|
||||
stoplag()
|
||||
alpha = i
|
||||
visible_message("<span class='danger'>[src]'s body breaks apart into a fine pile of blue dust.</span>")
|
||||
var/reforming_essence = essence_regen_cap //retain the gained essence capacity
|
||||
var/obj/item/weapon/ectoplasm/revenant/R = new(get_turf(src))
|
||||
R.essence = max(reforming_essence - 15 * perfectsouls, 75) //minus any perfect souls
|
||||
R.client_to_revive = src.client //If the essence reforms, the old revenant is put back in the body
|
||||
ghostize()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
//reveal, stun, icon updates, cast checks, and essence changing
|
||||
/mob/living/simple_animal/revenant/proc/reveal(time)
|
||||
if(!src)
|
||||
return
|
||||
if(time <= 0)
|
||||
return
|
||||
revealed = 1
|
||||
invisibility = 0
|
||||
incorporeal_move = 0
|
||||
if(!unreveal_time)
|
||||
src << "<span class='revendanger'>You have been revealed!</span>"
|
||||
unreveal_time = world.time + time
|
||||
else
|
||||
src << "<span class='revenwarning'>You have been revealed!</span>"
|
||||
unreveal_time = unreveal_time + time
|
||||
update_spooky_icon()
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/stun(time)
|
||||
if(!src)
|
||||
return
|
||||
if(time <= 0)
|
||||
return
|
||||
notransform = 1
|
||||
if(!unstun_time)
|
||||
src << "<span class='revendanger'>You cannot move!</span>"
|
||||
unstun_time = world.time + time
|
||||
else
|
||||
src << "<span class='revenwarning'>You cannot move!</span>"
|
||||
unstun_time = unstun_time + time
|
||||
update_spooky_icon()
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/update_spooky_icon()
|
||||
if(revealed)
|
||||
if(notransform)
|
||||
if(draining)
|
||||
icon_state = icon_drain
|
||||
else
|
||||
icon_state = icon_stun
|
||||
else
|
||||
icon_state = icon_reveal
|
||||
else
|
||||
icon_state = icon_idle
|
||||
if(ghostimage)
|
||||
ghostimage.icon_state = src.icon_state
|
||||
updateallghostimages()
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/castcheck(essence_cost)
|
||||
if(!src)
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if(istype(T, /turf/closed))
|
||||
src << "<span class='revenwarning'>You cannot use abilities from inside of a wall.</span>"
|
||||
return 0
|
||||
for(var/obj/O in T)
|
||||
if(O.density && !O.CanPass(src, T, 5))
|
||||
src << "<span class='revenwarning'>You cannot use abilities inside of a dense object.</span>"
|
||||
return 0
|
||||
if(src.inhibited)
|
||||
src << "<span class='revenwarning'>Your powers have been suppressed by nulling energy!</span>"
|
||||
return 0
|
||||
if(!src.change_essence_amount(essence_cost, 1))
|
||||
src << "<span class='revenwarning'>You lack the essence to use that ability.</span>"
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/change_essence_amount(essence_amt, silent = 0, source = null)
|
||||
if(!src)
|
||||
return
|
||||
if(essence + essence_amt <= 0)
|
||||
return
|
||||
essence = max(0, essence+essence_amt)
|
||||
update_action_buttons_icon()
|
||||
update_health_hud()
|
||||
if(essence_amt > 0)
|
||||
essence_accumulated = max(0, essence_accumulated+essence_amt)
|
||||
if(!silent)
|
||||
if(essence_amt > 0)
|
||||
src << "<span class='revennotice'>Gained [essence_amt]E from [source].</span>"
|
||||
else
|
||||
src << "<span class='revenminor'>Lost [essence_amt]E from [source].</span>"
|
||||
return 1
|
||||
|
||||
|
||||
//reforming
|
||||
/obj/item/weapon/ectoplasm/revenant
|
||||
name = "glimmering residue"
|
||||
desc = "A pile of fine blue dust. Small tendrils of violet mist swirl around it."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "revenantEctoplasm"
|
||||
w_class = 2
|
||||
var/essence = 75 //the maximum essence of the reforming revenant
|
||||
var/reforming = 1
|
||||
var/inert = 0
|
||||
var/client/client_to_revive
|
||||
|
||||
/obj/item/weapon/ectoplasm/revenant/New()
|
||||
..()
|
||||
spawn(600) //1 minute
|
||||
if(src && reforming)
|
||||
reforming = 0
|
||||
return reform()
|
||||
else
|
||||
inert = 1
|
||||
visible_message("<span class='warning'>[src] settles down and seems lifeless.</span>")
|
||||
return
|
||||
|
||||
/obj/item/weapon/ectoplasm/revenant/attack_self(mob/user)
|
||||
if(!reforming || inert)
|
||||
return ..()
|
||||
user.visible_message("<span class='notice'>[user] scatters [src] in all directions.</span>", \
|
||||
"<span class='notice'>You scatter [src] across the area. The particles slowly fade away.</span>")
|
||||
user.drop_item()
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/ectoplasm/revenant/throw_impact(atom/hit_atom)
|
||||
..()
|
||||
if(inert)
|
||||
return
|
||||
visible_message("<span class='notice'>[src] breaks into particles upon impact, which fade away to nothingness.</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/ectoplasm/revenant/examine(mob/user)
|
||||
..()
|
||||
if(inert)
|
||||
user << "<span class='revennotice'>It seems inert.</span>"
|
||||
else if(reforming)
|
||||
user << "<span class='revenwarning'>It is shifting and distorted. It would be wise to destroy this.</span>"
|
||||
|
||||
/obj/item/weapon/ectoplasm/revenant/proc/reform()
|
||||
if(!src || qdeleted(src) || inert)
|
||||
return
|
||||
var/key_of_revenant
|
||||
message_admins("Revenant ectoplasm was left undestroyed for 1 minute and is reforming into a new revenant.")
|
||||
loc = get_turf(src) //In case it's in a backpack or someone's hand
|
||||
var/mob/living/simple_animal/revenant/R = new(get_turf(src))
|
||||
if(client_to_revive)
|
||||
for(var/mob/M in dead_mob_list)
|
||||
if(M.client == client_to_revive) //Only recreates the mob if the mob the client is in is dead
|
||||
R.client = client_to_revive
|
||||
key_of_revenant = client_to_revive.key
|
||||
if(!key_of_revenant)
|
||||
message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...")
|
||||
var/list/candidates = get_candidates(ROLE_REVENANT)
|
||||
if(!candidates.len)
|
||||
qdel(R)
|
||||
message_admins("No candidates were found for the new revenant. Oh well!")
|
||||
inert = 1
|
||||
visible_message("<span class='revenwarning'>[src] settles down and seems lifeless.</span>")
|
||||
return 0
|
||||
var/client/C = pick(candidates)
|
||||
key_of_revenant = C.key
|
||||
if(!key_of_revenant)
|
||||
qdel(R)
|
||||
message_admins("No ckey was found for the new revenant. Oh well!")
|
||||
inert = 1
|
||||
visible_message("<span class='revenwarning'>[src] settles down and seems lifeless.</span>")
|
||||
return 0
|
||||
var/datum/mind/player_mind = new /datum/mind(key_of_revenant)
|
||||
R.essence_regen_cap = essence
|
||||
R.essence = R.essence_regen_cap
|
||||
player_mind.active = 1
|
||||
player_mind.transfer_to(R)
|
||||
player_mind.assigned_role = "revenant"
|
||||
player_mind.special_role = "Revenant"
|
||||
ticker.mode.traitors |= player_mind
|
||||
message_admins("[key_of_revenant] has been [client_to_revive ? "re":""]made into a revenant by reforming ectoplasm.")
|
||||
log_game("[key_of_revenant] was [client_to_revive ? "re":""]made as a revenant by reforming ectoplasm.")
|
||||
visible_message("<span class='revenboldnotice'>[src] suddenly rises into the air before fading away.</span>")
|
||||
qdel(src)
|
||||
if(src) //Should never happen, but just in case
|
||||
inert = 1
|
||||
return 1
|
||||
|
||||
|
||||
//objectives
|
||||
/datum/objective/revenant
|
||||
dangerrating = 10
|
||||
var/targetAmount = 100
|
||||
|
||||
/datum/objective/revenant/New()
|
||||
targetAmount = rand(350,600)
|
||||
explanation_text = "Absorb [targetAmount] points of essence from humans."
|
||||
..()
|
||||
|
||||
/datum/objective/revenant/check_completion()
|
||||
if(!istype(owner.current, /mob/living/simple_animal/revenant))
|
||||
return 0
|
||||
var/mob/living/simple_animal/revenant/R = owner.current
|
||||
if(!R || R.stat == DEAD)
|
||||
return 0
|
||||
var/essence_stolen = R.essence_accumulated
|
||||
if(essence_stolen < targetAmount)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/objective/revenantFluff
|
||||
dangerrating = 0
|
||||
|
||||
/datum/objective/revenantFluff/New()
|
||||
var/list/explanationTexts = list("Assist and exacerbate existing threats at critical moments.", \
|
||||
"Avoid killing in plain sight.", \
|
||||
"Cause as much chaos and anger as you can without being killed.", \
|
||||
"Damage and render as much of the station rusted and unusable as possible.", \
|
||||
"Disable and cause malfunctions in as many machines as possible.", \
|
||||
"Ensure that any holy weapons are rendered unusable.", \
|
||||
"Hinder the crew while attempting to avoid being noticed.", \
|
||||
"Make the crew as miserable as possible.", \
|
||||
"Make the clown as miserable as possible.", \
|
||||
"Make the captain as miserable as possible.", \
|
||||
"Prevent the use of energy weapons where possible.")
|
||||
explanation_text = pick(explanationTexts)
|
||||
..()
|
||||
|
||||
/datum/objective/revenantFluff/check_completion()
|
||||
return 1
|
||||
@@ -1,385 +0,0 @@
|
||||
|
||||
//Harvest; activated ly clicking the target, will try to drain their essence.
|
||||
/mob/living/simple_animal/revenant/ClickOn(atom/A, params) //revenants can't interact with the world directly.
|
||||
A.examine(src)
|
||||
if(ishuman(A))
|
||||
if(A in drained_mobs)
|
||||
src << "<span class='revenwarning'>[A]'s soul is dead and empty.</span>" //feedback at any range
|
||||
else if(in_range(src, A))
|
||||
Harvest(A)
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/Harvest(mob/living/carbon/human/target)
|
||||
if(!castcheck(0))
|
||||
return
|
||||
if(draining)
|
||||
src << "<span class='revenwarning'>You are already siphoning the essence of a soul!</span>"
|
||||
return
|
||||
if(!target.stat)
|
||||
src << "<span class='revennotice'>This being's soul is too strong to harvest.</span>"
|
||||
if(prob(10))
|
||||
target << "You feel as if you are being watched."
|
||||
return
|
||||
draining = 1
|
||||
essence_drained += rand(15, 20)
|
||||
src << "<span class='revennotice'>You search for the soul of [target].</span>"
|
||||
if(do_after(src, rand(10, 20), 0, target)) //did they get deleted in that second?
|
||||
if(target.ckey)
|
||||
src << "<span class='revennotice'>Their soul burns with intelligence.</span>"
|
||||
essence_drained += rand(20, 30)
|
||||
if(target.stat != DEAD)
|
||||
src << "<span class='revennotice'>Their soul blazes with life!</span>"
|
||||
essence_drained += rand(40, 50)
|
||||
else
|
||||
src << "<span class='revennotice'>Their soul is weak and faltering.</span>"
|
||||
if(do_after(src, rand(15, 20), 0, target)) //did they get deleted NOW?
|
||||
switch(essence_drained)
|
||||
if(1 to 30)
|
||||
src << "<span class='revennotice'>[target] will not yield much essence. Still, every bit counts.</span>"
|
||||
if(30 to 70)
|
||||
src << "<span class='revennotice'>[target] will yield an average amount of essence.</span>"
|
||||
if(70 to 90)
|
||||
src << "<span class='revenboldnotice'>Such a feast! [target] will yield much essence to you.</span>"
|
||||
if(90 to INFINITY)
|
||||
src << "<span class='revenbignotice'>Ah, the perfect soul. [target] will yield massive amounts of essence to you.</span>"
|
||||
if(do_after(src, rand(15, 25), 0, target)) //how about now
|
||||
if(!target.stat)
|
||||
src << "<span class='revenwarning'>They are now powerful enough to fight off your draining.</span>"
|
||||
target << "<span class='boldannounce'>You feel something tugging across your body before subsiding.</span>"
|
||||
draining = 0
|
||||
essence_drained = 0
|
||||
return //hey, wait a minute...
|
||||
src << "<span class='revenminor'>You begin siphoning essence from [target]'s soul.</span>"
|
||||
if(target.stat != DEAD)
|
||||
target << "<span class='warning'>You feel a horribly unpleasant draining sensation as your grip on life weakens...</span>"
|
||||
reveal(46)
|
||||
stun(46)
|
||||
target.visible_message("<span class='warning'>[target] suddenly rises slightly into the air, their skin turning an ashy gray.</span>")
|
||||
var/datum/beam/B = Beam(target,icon_state="drain_life",icon='icons/effects/effects.dmi',time=46)
|
||||
if(do_after(src, 46, 0, target)) //As one cannot prove the existance of ghosts, ghosts cannot prove the existance of the target they were draining.
|
||||
qdel(B)
|
||||
change_essence_amount(essence_drained, 0, target)
|
||||
if(essence_drained <= 90 && target.stat != DEAD)
|
||||
essence_regen_cap += 5
|
||||
src << "<span class='revenboldnotice'>The absorption of [target]'s living soul has increased your maximum essence level. Your new maximum essence is [essence_regen_cap].</span>"
|
||||
if(essence_drained > 90)
|
||||
essence_regen_cap += 15
|
||||
perfectsouls += 1
|
||||
src << "<span class='revenboldnotice'>The perfection of [target]'s soul has increased your maximum essence level. Your new maximum essence is [essence_regen_cap].</span>"
|
||||
src << "<span class='revennotice'>[target]'s soul has been considerably weakened and will yield no more essence for the time being.</span>"
|
||||
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
|
||||
"<span class='revenwarning'>Violets lights, dancing in your vision, getting clo--</span>")
|
||||
drained_mobs.Add(target)
|
||||
target.death(0)
|
||||
else
|
||||
qdel(B)
|
||||
src << "<span class='revenwarning'>[target ? "[target] has":"They have"] been drawn out of your grasp. The link has been broken.</span>"
|
||||
draining = 0
|
||||
essence_drained = 0
|
||||
if(target) //Wait, target is WHERE NOW?
|
||||
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
|
||||
"<span class='revenwarning'>Violets lights, dancing in your vision, receding--</span>")
|
||||
return
|
||||
else
|
||||
src << "<span class='revenwarning'>You are not close enough to siphon [target ? "[target]'s":"their"] soul. The link has been broken.</span>"
|
||||
draining = 0
|
||||
essence_drained = 0
|
||||
return
|
||||
draining = 0
|
||||
essence_drained = 0
|
||||
return
|
||||
|
||||
//Toggle night vision: lets the revenant toggle its night vision
|
||||
/obj/effect/proc_holder/spell/targeted/night_vision/revenant
|
||||
charge_max = 0
|
||||
panel = "Revenant Abilities"
|
||||
message = "<span class='revennotice'>You toggle your night vision.</span>"
|
||||
action_icon_state = "r_nightvision"
|
||||
action_background_icon_state = "bg_revenant"
|
||||
|
||||
//Transmit: the revemant's only direct way to communicate. Sends a single message silently to a single mob
|
||||
/obj/effect/proc_holder/spell/targeted/revenant_transmit
|
||||
name = "Transmit"
|
||||
desc = "Telepathically transmits a message to the target."
|
||||
panel = "Revenant Abilities"
|
||||
charge_max = 0
|
||||
clothes_req = 0
|
||||
range = 7
|
||||
include_user = 0
|
||||
action_icon_state = "r_transmit"
|
||||
action_background_icon_state = "bg_revenant"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/revenant_transmit/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
for(var/mob/living/M in targets)
|
||||
spawn(0)
|
||||
var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "")
|
||||
if(!msg)
|
||||
charge_counter = charge_max
|
||||
return
|
||||
log_say("RevenantTransmit: [key_name(user)]->[key_name(M)] : [msg]")
|
||||
user << "<span class='revenboldnotice'>You transmit to [M]:</span> <span class='revennotice'>[msg]</span>"
|
||||
M << "<span class='revenboldnotice'>An alien voice resonates from all around...</span> <span class='revennotice'>[msg]</span>"
|
||||
for(var/ded in dead_mob_list)
|
||||
if(!isobserver(ded))
|
||||
continue
|
||||
var/follow_rev = FOLLOW_LINK(ded, user)
|
||||
var/follow_whispee = FOLLOW_LINK(ded, M)
|
||||
ded << "[follow_rev] \
|
||||
<span class='name'>[user]</span> \
|
||||
<span class='revenboldnotice'>Revenant Transmit --></span> \
|
||||
[follow_whispee] \
|
||||
<span class='name'>[M]</span> \
|
||||
<span class='revennotice'>[msg]</span>"
|
||||
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant
|
||||
clothes_req = 0
|
||||
action_background_icon_state = "bg_revenant"
|
||||
panel = "Revenant Abilities (Locked)"
|
||||
name = "Report this to a coder"
|
||||
var/reveal = 80 //How long it reveals the revenant in deciseconds
|
||||
var/stun = 20 //How long it stuns the revenant in deciseconds
|
||||
var/locked = 1 //If it's locked and needs to be unlocked before use
|
||||
var/unlock_amount = 100 //How much essence it costs to unlock
|
||||
var/cast_amount = 50 //How much essence it costs to use
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/New()
|
||||
..()
|
||||
if(locked)
|
||||
name = "[initial(name)] ([unlock_amount]E)"
|
||||
else
|
||||
name = "[initial(name)] ([cast_amount]E)"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr)
|
||||
if(!istype(user)) //Badmins, no. Badmins, don't do it.
|
||||
if(charge_counter < charge_max)
|
||||
return 0
|
||||
return 1
|
||||
if(user.inhibited)
|
||||
return 0
|
||||
if(charge_counter < charge_max)
|
||||
return 0
|
||||
if(locked)
|
||||
if(user.essence <= unlock_amount)
|
||||
return 0
|
||||
if(user.essence <= cast_amount)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/proc/attempt_cast(mob/living/simple_animal/revenant/user = usr)
|
||||
if(!istype(user)) //If you're not a revenant, it works. Please, please, please don't give this to a non-revenant.
|
||||
name = "[initial(name)]"
|
||||
if(locked)
|
||||
panel = "Revenant Abilities"
|
||||
locked = 0
|
||||
return 1
|
||||
if(locked)
|
||||
if(!user.castcheck(-unlock_amount))
|
||||
charge_counter = charge_max
|
||||
return 0
|
||||
name = "[initial(name)] ([cast_amount]E)"
|
||||
user << "<span class='revennotice'>You have unlocked [initial(name)]!</span>"
|
||||
panel = "Revenant Abilities"
|
||||
locked = 0
|
||||
charge_counter = charge_max
|
||||
return 0
|
||||
if(!user.castcheck(-cast_amount))
|
||||
charge_counter = charge_max
|
||||
return 0
|
||||
name = "[initial(name)] ([cast_amount]E)"
|
||||
user.reveal(reveal)
|
||||
user.stun(stun)
|
||||
if(action)
|
||||
action.UpdateButtonIcon()
|
||||
return 1
|
||||
|
||||
//Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload
|
||||
name = "Overload Lights"
|
||||
desc = "Directs a large amount of essence into nearby electrical lights, causing lights to shock those nearby."
|
||||
charge_max = 200
|
||||
range = 5
|
||||
stun = 30
|
||||
cast_amount = 40
|
||||
var/shock_range = 2
|
||||
var/shock_damage = 20
|
||||
action_icon_state = "overload_lights"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
for(var/obj/machinery/light/L in T.contents)
|
||||
spawn(0)
|
||||
if(!L.on)
|
||||
return
|
||||
L.visible_message("<span class='warning'><b>\The [L] suddenly flares brightly and begins to spark!</span>")
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(4, 0, L)
|
||||
s.start()
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, L.loc)
|
||||
sleep(20)
|
||||
if(!L.on) //wait, wait, don't shock me
|
||||
return
|
||||
flick("[L.base_state]2", L)
|
||||
for(var/mob/living/carbon/human/M in view(shock_range, L))
|
||||
if(M == user)
|
||||
continue
|
||||
L.Beam(M,icon_state="purple_lightning",icon='icons/effects/effects.dmi',time=5)
|
||||
M.electrocute_act(shock_damage, L, safety=1)
|
||||
var/datum/effect_system/spark_spread/z = new /datum/effect_system/spark_spread
|
||||
z.set_up(4, 0, M)
|
||||
z.start()
|
||||
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
|
||||
|
||||
//Defile: Corrupts nearby stuff, unblesses floor tiles.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile
|
||||
name = "Defile"
|
||||
desc = "Twists and corrupts the nearby area as well as dispelling holy auras on floors."
|
||||
charge_max = 150
|
||||
range = 4
|
||||
stun = 10
|
||||
reveal = 40
|
||||
unlock_amount = 75
|
||||
cast_amount = 30
|
||||
action_icon_state = "defile"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
if(T.flags & NOJAUNT)
|
||||
T.flags -= NOJAUNT
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, T)
|
||||
if(!istype(T, /turf/open/floor/plating) && !istype(T, /turf/open/floor/engine/cult) && istype(T, /turf/open/floor) && prob(15))
|
||||
var/turf/open/floor/floor = T
|
||||
if(floor.intact)
|
||||
floor.builtin_tile.loc = floor
|
||||
floor.broken = 0
|
||||
floor.burnt = 0
|
||||
floor.make_plating(1)
|
||||
if(T.type == /turf/closed/wall && prob(15))
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, T)
|
||||
T.ChangeTurf(/turf/closed/wall/rust)
|
||||
if(T.type == /turf/closed/wall/r_wall && prob(10))
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, T)
|
||||
T.ChangeTurf(/turf/closed/wall/r_wall/rust)
|
||||
for(var/obj/structure/closet/closet in T.contents)
|
||||
closet.open()
|
||||
for(var/obj/structure/bodycontainer/corpseholder in T.contents)
|
||||
if(corpseholder.connected.loc == corpseholder)
|
||||
corpseholder.open()
|
||||
for(var/obj/machinery/dna_scannernew/dna in T.contents)
|
||||
dna.open_machine()
|
||||
for(var/obj/structure/window/window in T.contents)
|
||||
window.take_damage(rand(30,80))
|
||||
if(window && window.fulltile)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant/cracks, window.loc)
|
||||
for(var/obj/machinery/light/light in T.contents)
|
||||
light.flicker(20) //spooky
|
||||
|
||||
//Malfunction: Makes bad stuff happen to robots and machines.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction
|
||||
name = "Malfunction"
|
||||
desc = "Corrupts and damages nearby machines and mechanical objects."
|
||||
charge_max = 200
|
||||
range = 4
|
||||
cast_amount = 45
|
||||
unlock_amount = 150
|
||||
action_icon_state = "malfunction"
|
||||
|
||||
//A note to future coders: do not replace this with an EMP because it will wreck malf AIs and gang dominators and everyone will hate you.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
for(var/mob/living/simple_animal/bot/bot in T.contents)
|
||||
if(!bot.emagged)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, bot.loc)
|
||||
bot.locked = 0
|
||||
bot.open = 1
|
||||
bot.emag_act()
|
||||
for(var/mob/living/carbon/human/human in T.contents)
|
||||
if(human == user)
|
||||
continue
|
||||
human << "<span class='revenwarning'>You feel [pick("your sense of direction flicker out", "a stabbing pain in your head", "your mind fill with static")].</span>"
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, human.loc)
|
||||
human.emp_act(1)
|
||||
for(var/obj/thing in T.contents)
|
||||
if(istype(thing, /obj/machinery/dominator) || istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes)) //Doesn't work on dominators, SMES and APCs, to prevent kekkery
|
||||
continue
|
||||
if(prob(20))
|
||||
if(prob(50))
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, thing.loc)
|
||||
thing.emag_act(null)
|
||||
else
|
||||
if(!istype(thing, /obj/machinery/clonepod)) //I hate everything but mostly the fact there's no better way to do this without just not affecting it at all
|
||||
thing.emp_act(1)
|
||||
for(var/mob/living/silicon/robot/S in T.contents) //Only works on cyborgs, not AI
|
||||
playsound(S, 'sound/machines/warning-buzzer.ogg', 50, 1)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, S.loc)
|
||||
S.spark_system.start()
|
||||
S.emp_act(1)
|
||||
|
||||
//Blight: Infects nearby humans and in general messes living stuff up.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/blight
|
||||
name = "Blight"
|
||||
desc = "Causes nearby living things to waste away."
|
||||
charge_max = 200
|
||||
range = 3
|
||||
reveal = 50
|
||||
cast_amount = 50
|
||||
unlock_amount = 200
|
||||
action_icon_state = "blight"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/blight/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
for(var/mob/living/mob in T.contents)
|
||||
if(mob == user)
|
||||
continue
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, mob.loc)
|
||||
if(iscarbon(mob))
|
||||
if(ishuman(mob))
|
||||
var/mob/living/carbon/human/H = mob
|
||||
if(H.dna && H.dna.species)
|
||||
H.dna.species.handle_mutant_bodyparts(H,"#1d2953")
|
||||
H.dna.species.handle_hair(H,"#1d2953")
|
||||
var/old_color = H.color
|
||||
H.color = "#1d2953"
|
||||
spawn(20)
|
||||
if(H && H.dna && H.dna.species)
|
||||
H.dna.species.handle_mutant_bodyparts(H)
|
||||
H.dna.species.handle_hair(H)
|
||||
H.color = old_color
|
||||
var/blightfound = 0
|
||||
for(var/datum/disease/revblight/blight in H.viruses)
|
||||
blightfound = 1
|
||||
if(blight.stage < 5)
|
||||
blight.stage++
|
||||
if(!blightfound)
|
||||
H.AddDisease(new /datum/disease/revblight)
|
||||
H << "<span class='revenminor'>You feel [pick("suddenly sick", "a surge of nausea", "like your skin is <span class='italics'>wrong</span>")].</span>"
|
||||
else
|
||||
if(mob.reagents)
|
||||
mob.reagents.add_reagent("plasma", 5)
|
||||
else
|
||||
mob.adjustToxLoss(5)
|
||||
for(var/obj/effect/spacevine/vine in T.contents) //Fucking with botanists, the ability.
|
||||
vine.color = "#823abb"
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, vine.loc)
|
||||
spawn(10)
|
||||
if(vine)
|
||||
qdel(vine)
|
||||
for(var/obj/effect/glowshroom/shroom in T.contents)
|
||||
shroom.color = "#823abb"
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, shroom.loc)
|
||||
spawn(10)
|
||||
if(shroom)
|
||||
qdel(shroom)
|
||||
for(var/obj/machinery/hydroponics/tray in T.contents)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, tray.loc)
|
||||
tray.pestlevel = rand(8, 10)
|
||||
tray.weedlevel = rand(8, 10)
|
||||
tray.toxic = rand(45, 55)
|
||||
@@ -1,68 +0,0 @@
|
||||
/datum/disease/revblight
|
||||
name = "Unnatural Wasting"
|
||||
max_stages = 5
|
||||
stage_prob = 10
|
||||
spread_flags = NON_CONTAGIOUS
|
||||
cure_text = "Holy water or extensive rest."
|
||||
spread_text = "A burst of unholy energy"
|
||||
cures = list("holywater")
|
||||
cure_chance = 50 //higher chance to cure, because revenants are assholes
|
||||
agent = "Unholy Forces"
|
||||
viable_mobtypes = list(/mob/living/carbon/human)
|
||||
disease_flags = CURABLE
|
||||
permeability_mod = 1
|
||||
severity = BIOHAZARD
|
||||
var/stagedamage = 0 //Highest stage reached.
|
||||
var/finalstage = 0 //Because we're spawning off the cure in the final stage, we need to check if we've done the final stage's effects.
|
||||
|
||||
/datum/disease/revblight/cure()
|
||||
if(affected_mob)
|
||||
affected_mob << "<span class='notice'>You feel better.</span>"
|
||||
if(affected_mob.dna && affected_mob.dna.species)
|
||||
affected_mob.dna.species.handle_mutant_bodyparts(affected_mob)
|
||||
..()
|
||||
|
||||
/datum/disease/revblight/stage_act()
|
||||
if(!finalstage && affected_mob.lying && prob(stage*5))
|
||||
cure()
|
||||
return
|
||||
if(!finalstage && prob(stage*3))
|
||||
affected_mob << "<span class='revennotice'>You suddenly feel [pick("sick and tired", "disoriented", "tired and confused", "nauseated", "faint", "dizzy")]...</span>"
|
||||
affected_mob.confused += 10
|
||||
affected_mob.adjustStaminaLoss(10)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, affected_mob.loc)
|
||||
if(!finalstage && stagedamage < stage)
|
||||
stagedamage++
|
||||
affected_mob.adjustToxLoss(stage*3) //should, normally, do about 45 toxin damage.
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, affected_mob.loc)
|
||||
if(!finalstage && prob(45))
|
||||
affected_mob.adjustStaminaLoss(stage*2)
|
||||
..() //So we don't increase a stage before applying the stage damage.
|
||||
switch(stage)
|
||||
if(2)
|
||||
if(prob(5))
|
||||
affected_mob.emote("pale")
|
||||
if(3)
|
||||
if(prob(10))
|
||||
affected_mob.emote(pick("pale","shiver"))
|
||||
if(4)
|
||||
if(prob(15))
|
||||
affected_mob.emote(pick("pale","shiver","cries"))
|
||||
if(5)
|
||||
if(!finalstage)
|
||||
finalstage = 1
|
||||
affected_mob << "<span class='revenbignotice'>You feel like [pick("nothing's worth it anymore", "nobody ever needed your help", "nothing you did mattered", "everything you tried to do was worthless")].</span>"
|
||||
affected_mob.adjustStaminaLoss(45)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, affected_mob.loc)
|
||||
if(affected_mob.dna && affected_mob.dna.species)
|
||||
affected_mob.dna.species.handle_mutant_bodyparts(affected_mob,"#1d2953")
|
||||
affected_mob.dna.species.handle_hair(affected_mob,"#1d2953")
|
||||
affected_mob.visible_message("<span class='warning'>[affected_mob] looks terrifyingly gaunt...</span>", "<span class='revennotice'>You suddenly feel like your skin is <span class='italics'>wrong</span>...</span>")
|
||||
var/old_color = affected_mob.color
|
||||
affected_mob.color = "#1d2953"
|
||||
spawn(100)
|
||||
if(affected_mob)
|
||||
affected_mob = old_color
|
||||
cure()
|
||||
else
|
||||
return
|
||||
@@ -1,63 +0,0 @@
|
||||
#define REVENANT_SPAWN_THRESHOLD 20
|
||||
|
||||
/datum/round_event_control/revenant
|
||||
name = "Spawn Revenant" // Did you mean 'griefghost'?
|
||||
typepath = /datum/round_event/ghost_role/revenant
|
||||
weight = 7
|
||||
max_occurrences = 1
|
||||
earliest_start = 12000 //Meant to mix things up early-game.
|
||||
min_players = 5
|
||||
|
||||
|
||||
/datum/round_event/ghost_role/revenant
|
||||
var/force_spawn
|
||||
role_name = "revenant"
|
||||
|
||||
/datum/round_event/ghost_role/revenant/New(my_force_spawn = FALSE)
|
||||
..()
|
||||
force_spawn = my_force_spawn
|
||||
|
||||
/datum/round_event/ghost_role/revenant/spawn_role()
|
||||
if(!force_spawn)
|
||||
var/deadMobs = 0
|
||||
for(var/mob/M in dead_mob_list)
|
||||
deadMobs++
|
||||
if(deadMobs < REVENANT_SPAWN_THRESHOLD)
|
||||
message_admins("Event attempted to spawn a revenant, but there were only [deadMobs]/[REVENANT_SPAWN_THRESHOLD] dead mobs.")
|
||||
return WAITING_FOR_SOMETHING
|
||||
|
||||
var/list/mob/dead/observer/candidates = get_candidates("revenant", null, ROLE_REVENANT)
|
||||
if(!candidates.len)
|
||||
return NOT_ENOUGH_PLAYERS
|
||||
|
||||
var/mob/dead/observer/selected = popleft(candidates)
|
||||
|
||||
var/datum/mind/player_mind = new /datum/mind(selected.key)
|
||||
player_mind.active = 1
|
||||
var/list/spawn_locs = list()
|
||||
|
||||
for(var/obj/effect/landmark/L in landmarks_list)
|
||||
if(isturf(L.loc))
|
||||
switch(L.name)
|
||||
if("revenantspawn")
|
||||
spawn_locs += L.loc
|
||||
if(!spawn_locs) //If we can't find any revenant spawns, try the carp spawns
|
||||
for(var/obj/effect/landmark/L in landmarks_list)
|
||||
if(isturf(L.loc))
|
||||
switch(L.name)
|
||||
if("carpspawn")
|
||||
spawn_locs += L.loc
|
||||
if(!spawn_locs) //If we can't find either, just spawn the revenant at the player's location
|
||||
spawn_locs += get_turf(player_mind.current)
|
||||
if(!spawn_locs) //If we can't find THAT, then just give up and cry
|
||||
return MAP_ERROR
|
||||
|
||||
var/mob/living/simple_animal/revenant/revvie = new /mob/living/simple_animal/revenant/(pick(spawn_locs))
|
||||
player_mind.transfer_to(revvie)
|
||||
player_mind.assigned_role = "revenant"
|
||||
player_mind.special_role = "Revenant"
|
||||
ticker.mode.traitors |= player_mind
|
||||
message_admins("[player_mind.key] has been made into a revenant by an event.")
|
||||
log_game("[player_mind.key] was spawned as a revenant by an event.")
|
||||
spawned_mobs += revvie
|
||||
return SUCCESSFUL_SPAWN
|
||||
369
code/game/gamemodes/miniantags/umbra/umbra.dm
Normal file
@@ -0,0 +1,369 @@
|
||||
#define UMBRA_INVISIBILITY 50
|
||||
#define UMBRA_VITAE_DRAIN_RATE 0.01 //How much vitae is drained per tick to sustain the umbra. Set this to higher values to make umbras need to harvest vitae more often.
|
||||
#define UMBRA_MAX_HARVEST_COOLDOWN 3000 //In deciseconds, how long it takes for a harvested target to become eligible for draining again.
|
||||
#define UMBRA_POSSESSION_THRESHOLD_WARNING 60 //In ticks, how long it takes before a possessed human starts showing signs of possession
|
||||
#define UMBRA_POSSESSION_THRESHOLD_DANGER 150 //In ticks, how long it takes before a possessed human starts forcing out the umbra
|
||||
#define UMBRA_POSSESSION_THRESHOLD_FORCED_OUT 155 //In ticks, how long it takes before a possessed human forces out the umbra
|
||||
|
||||
/*
|
||||
|
||||
Umbras are residual entities created by the dying who possess enough anger or determination that they never fully pass on.
|
||||
Physically, they're incorporeal and invisible. Umbras are formed of a steadily-decaying electromagnetic field with a drive to sustain itself.
|
||||
Umbras do this by feeding on a substance, found in the dead or dying, known as vitae.
|
||||
|
||||
Vitae is most closely comparable to adrenaline in that is produced by creatures at times of distress. For this reason, almost all dead creatures have vitae in one way or another.
|
||||
Biologically, it's indistinguishable from normal blood, but vitae is what allows creatures to survive grievous wounds or cling to life in critical condition. It provides a large amount of energy.
|
||||
It's for this reason that umbras desire it. Vitae serves as a potent energy source to a living thing, and umbras can use the energy of this vitae to sustain themselves.
|
||||
Without enough vitae, the field that sustains an umbra will break down and weaken. If the umbra has no vitae at all, it will permanently dissipate.
|
||||
|
||||
Umbras are not without their weaknesses. Despite being invisible to the naked eye and untouchable, certain things can restrict, weaken, or outright harm them.
|
||||
Piles of salt on the ground will prevent an umbra's passage, making areas encircled in it completely inaccessible to even the most determined umbra.
|
||||
In addition, objects and artifacts of a holy nature can force an umbra to manifest or draw away some of the energy that it's gleaned through vitae.
|
||||
|
||||
When an umbra dies, two things can occur. If the umbra died from passive vitae drain, it will be dead forever, with no way to bring it back.
|
||||
However, if the umbra is slain forcibly and still has vitae, the vitae possesses enough power to coalesce a part of the umbra into umbral ashes.
|
||||
These "ashes" will, given around a full minute, re-form into another umbra. This umbra typically possesses the memories and consciousness of the old one, but may be a completely new mind as well.
|
||||
Although these umbral ashes make umbras resilient, they can be killed permanently by scattering the ashes or destroying them, thus separating the vitae from the umbra's remains.
|
||||
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/umbra
|
||||
name = "umbra"
|
||||
real_name = "umbra"
|
||||
desc = "A translucent, cobalt-blue apparition floating several feet in the air."
|
||||
invisibility = UMBRA_INVISIBILITY
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "umbra"
|
||||
icon_living = "umbra"
|
||||
layer = GHOST_LAYER
|
||||
alpha = 175 //To show invisibility
|
||||
health = 100
|
||||
maxHealth = 100
|
||||
healable = 0
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
healable = FALSE
|
||||
friendly = "passes through"
|
||||
speak_emote = list("murmurs")
|
||||
emote_hear = list("murmurs")
|
||||
languages = ALL
|
||||
incorporeal_move = 3
|
||||
flying = TRUE
|
||||
stop_automated_movement = TRUE
|
||||
wander = FALSE
|
||||
sight = SEE_SELF
|
||||
see_invisible = SEE_INVISIBLE_NOLIGHTING
|
||||
see_in_dark = 8
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
var/vitae = 10 //The amount of vitae captured by the umbra
|
||||
var/vitae_cap = 100 //How much vitae a single umbra can hold
|
||||
var/breaking_apart = FALSE //If the umbra is currently dying
|
||||
var/harvesting = FALSE //If the umbra is harvesting a soul
|
||||
var/list/recently_drained = list() //Mobs that have been drained in the last five minutes by the umbra
|
||||
var/list/total_drained = list() //Mobs that have been drained, period
|
||||
var/mob/living/carbon/human/possessed //The human that an umbra is inside of, if applicable
|
||||
var/time_possessing = 0 //How long an umbra has been in possession of a single target.
|
||||
var/list/lobotomized = list() //Mobs that have had their memories stolen by the umbra
|
||||
var/playstyle_string = "<span class='umbra_large'><b>You are an umbra,</b></span><b> and you aren't quite sure how you're alive. You don't remember much, but you remember slipping away, \
|
||||
lsoing your hold on life. You died, but here you are... somehow. You can't be quite sure how this happened, but you're pretty sure that it won't last long. Already you feel this strange \
|
||||
form of life weakening. You need to find a way to sustain yourself, and you think you might have an idea.\n\
|
||||
\n\
|
||||
You seem to be invisible and incorporeal, so you don't think that anyone can see, feel, or otherwise perceive you right now, but there has to be some way that you managed not to just fully \
|
||||
die and instead ended up like this. You think that if you find a corpse, or perhaps someone still alive but in critical condition, you'd be able to drain whatever kept you in this state \
|
||||
from them. At first the idea sounds horrible - stealing their very life force - but as you continue to weaken it sounds more and more appealing... you think it'd be as simple as interacting \
|
||||
with them. Something in the back of your mind tells you to call this life force <i>vitae</i>.\n\
|
||||
\n\
|
||||
In any case, you can definitely feel something else. You feel partially alive, but partially dead. Perhaps somewhere in between. Nonetheless, you might be able to influence both realms. \
|
||||
You can see clearly in the dark, and you seem to have a sort of limited telepathic capabilities, plus some other things. You'll have to experiment with your new form to find out what you \
|
||||
exactly you can do."
|
||||
|
||||
|
||||
//Creation, destruction, life, and death
|
||||
/mob/living/simple_animal/umbra/New()
|
||||
..()
|
||||
if(prob(1))
|
||||
name = "grief ghost"
|
||||
real_name = "grief ghost"
|
||||
desc = "You wonder how something that produces so much salt can be weak to it."
|
||||
AddSpell(new/obj/effect/proc_holder/spell/targeted/night_vision/umbra(null))
|
||||
AddSpell(new/obj/effect/proc_holder/spell/targeted/discordant_whisper(null))
|
||||
AddSpell(new/obj/effect/proc_holder/spell/targeted/possess(null))
|
||||
AddSpell(new/obj/effect/proc_holder/spell/targeted/thoughtsteal(null))
|
||||
|
||||
/mob/living/simple_animal/umbra/Life()
|
||||
..()
|
||||
if(!possessed)
|
||||
adjust_vitae(-UMBRA_VITAE_DRAIN_RATE, TRUE, "passive drain")
|
||||
time_possessing = 0
|
||||
else
|
||||
if(possessed.reagents && possessed.reagents.has_reagent("sodiumchloride"))
|
||||
unpossess(TRUE)
|
||||
visible_message("<span class='warning'>[src] appears from nowhere, twitching and flickering!</span>", "<span class='userdanger'>AAAH! SALT!</span>")
|
||||
immobilize(30)
|
||||
reveal(50)
|
||||
return
|
||||
if(possessed.stat == DEAD)
|
||||
unpossess()
|
||||
return
|
||||
adjust_vitae(UMBRA_VITAE_DRAIN_RATE, TRUE, "passive gain")
|
||||
time_possessing++
|
||||
switch(time_possessing)
|
||||
if(0 to UMBRA_POSSESSION_THRESHOLD_WARNING)
|
||||
if(prob(1))
|
||||
possessed << "<span class='warning'>You feel [pick("watched", "not wholly yourself", "an intense craving for salt", "singularly odd", \
|
||||
"a horrible dread in your heart")].</span>"
|
||||
if(UMBRA_POSSESSION_THRESHOLD_WARNING to UMBRA_POSSESSION_THRESHOLD_DANGER)
|
||||
if(prob(2))
|
||||
possessed << "<span class='warning'>[pick("Another mind briefly touches yours, then fades", "Your vision briefly flares violet", "You feel a brief pain in your chest", \
|
||||
"A murmur from within your mind, too quiet to understand", "You become uneasy for no explainable reason")].</span>"
|
||||
if(prob(5))
|
||||
possessed.emote("twitch")
|
||||
if(UMBRA_POSSESSION_THRESHOLD_DANGER to UMBRA_POSSESSION_THRESHOLD_FORCED_OUT)
|
||||
possessed << "<span class='userdanger'>GET OUT GET OUT GET OUT</span>"
|
||||
possessed.confused = max(3, possessed.confused)
|
||||
possessed.emote(pick("moan", "groan", "shiver", "twitch", "cry"))
|
||||
flash_color(possessed, flash_color = "#5000A0", flash_time = 10)
|
||||
if(UMBRA_POSSESSION_THRESHOLD_FORCED_OUT to INFINITY)
|
||||
src << "<span class='userdanger'>You can't stay any longer - you retreat from [possessed]'s body!</span>"
|
||||
unpossess(TRUE)
|
||||
return
|
||||
if(time_possessing == UMBRA_POSSESSION_THRESHOLD_WARNING)
|
||||
src << "<span class='warning'>[possessed] is starting to catch on to your presence. Be wary.</span>"
|
||||
else if(time_possessing == UMBRA_POSSESSION_THRESHOLD_DANGER)
|
||||
src << "<span class='userdanger'>[possessed] has noticed your presence and is forcing you out!</span>"
|
||||
possessed << "<span class='userdanger'>There's something in your head! You start trying to force it out--</span>"
|
||||
else if(time_possessing == UMBRA_POSSESSION_THRESHOLD_FORCED_OUT)
|
||||
src << "<span class='userdanger'>You can't stay any longer! You flee from [possessed]...</span>"
|
||||
unpossess()
|
||||
adjustBruteLoss(-1) //Vitae slowly heals the umbra as well
|
||||
adjustFireLoss(-1)
|
||||
if(!vitae)
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/umbra/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Vitae: [vitae]/[vitae_cap]")
|
||||
stat(null, "Vitae Cost/Tick: [UMBRA_VITAE_DRAIN_RATE]")
|
||||
var/drained_mobs = ""
|
||||
var/length = recently_drained.len
|
||||
for(var/mob/living/L in recently_drained)
|
||||
if(!L)
|
||||
recently_drained -= L
|
||||
length--
|
||||
else
|
||||
drained_mobs += "[L.real_name][length > 1 ? ", " : ""]"
|
||||
length--
|
||||
stat(null, "Recently Drained Creatures: [drained_mobs ? "[drained_mobs]" : "None"]")
|
||||
if(possessed)
|
||||
stat(null, "Time in [possessed]: [time_possessing]/[UMBRA_POSSESSION_THRESHOLD_FORCED_OUT]")
|
||||
|
||||
/mob/living/simple_animal/umbra/death()
|
||||
if(breaking_apart)
|
||||
return
|
||||
..(1)
|
||||
unpossess(TRUE)
|
||||
breaking_apart = TRUE
|
||||
notransform = TRUE
|
||||
invisibility = FALSE
|
||||
visible_message("<span class='warning'>An [name] appears from nowhere and begins to disintegrate!</span>", \
|
||||
"<span class='userdanger'>You feel your will faltering, and your form begins to break apart!</span>")
|
||||
flick("umbra_disintegrate", src)
|
||||
sleep(12)
|
||||
if(vitae)
|
||||
visible_message("<span class='warning'>[src] breaks apart into a pile of ashes!</span>", \
|
||||
"<span class='umbra_emphasis'><font size=3>You'll</font> be <font size=1>back...</font></span>")
|
||||
var/obj/item/umbral_ashes/P = new(get_turf(src))
|
||||
P.umbra_key = key
|
||||
P.umbra_vitae = vitae
|
||||
else
|
||||
visible_message("<span class='warning'>[src] breaks apart and fades away!</span>")
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/reveal(time, silent) //Makes the umbra visible for the designated amount of deciseconds
|
||||
if(!time)
|
||||
return
|
||||
if(!silent)
|
||||
src << "<span class='warning'>You've become visible!</span>"
|
||||
alpha = 255
|
||||
invisibility = FALSE
|
||||
spawn(time)
|
||||
alpha = initial(alpha)
|
||||
if(!silent)
|
||||
src << "<span class='umbra'>You've become invisible again!</span>"
|
||||
invisibility = UMBRA_INVISIBILITY
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/immobilize(time, silent) //Immobilizes the umbra for the designated amount of deciseconds
|
||||
if(!time)
|
||||
return
|
||||
if(!silent)
|
||||
src << "<span class='warning'>You can't move!</span>"
|
||||
notransform = TRUE
|
||||
spawn(time)
|
||||
if(!silent)
|
||||
src << "<span class='umbra'>You can move again!</span>"
|
||||
notransform = FALSE
|
||||
|
||||
|
||||
//Actions and interaction
|
||||
/mob/living/simple_animal/umbra/say() //Umbras can't directly speak
|
||||
src << "<span class='warning'>You lack the power to speak out loud! Use Discordant Whisper instead.</span>"
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/attack_ghost(mob/dead/observer/O)
|
||||
if(key)
|
||||
return
|
||||
if(alert(O, "Become an umbra? You won't be clonable!",,"Yes", "No") == "No" || !O)
|
||||
return
|
||||
occupy(O)
|
||||
notify_ghosts("The umbra at [get_area(src)] has been taken control of by [O].", source = src, action = NOTIFY_ORBIT)
|
||||
src << playstyle_string
|
||||
|
||||
/mob/living/simple_animal/umbra/ClickOn(atom/A, params)
|
||||
A.examine(src)
|
||||
if(isliving(A) && Adjacent(A))
|
||||
var/mob/living/L = A
|
||||
if(L.health > 0 && L.stat != DEAD)
|
||||
src << "<span class='warning'>[L] has no vitae to drain!</span>"
|
||||
return
|
||||
else if(L in recently_drained)
|
||||
src << "<span class='warning'>[L]'s body is still recuperating! You can't risk draining any more vitae!</span>"
|
||||
return
|
||||
else if(harvesting)
|
||||
src << "<span class='warning'>You're already trying to harvest vitae!</span>"
|
||||
return
|
||||
harvest_vitae(L)
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/harvest_vitae(mob/living/L) //How umbras drain vitae from their targets
|
||||
if(!L || L.health || L in recently_drained)
|
||||
return
|
||||
harvesting = TRUE
|
||||
src << "<span class='umbra'>You search for any vitae in [L]...</span>"
|
||||
if(!do_after(src, 30, target = L))
|
||||
harvesting = FALSE
|
||||
return
|
||||
if(L.hellbound)
|
||||
src << "<span class='warning'>[L] seems to be incapable of producing vitae!</span>"
|
||||
harvesting = FALSE
|
||||
return
|
||||
if(!L.stat)
|
||||
src << "<span class='warning'>[L] is conscious again and their vitae is receding!</span>"
|
||||
L << "<span class='warning'>You're being watched.</span>"
|
||||
harvesting = FALSE
|
||||
return
|
||||
var/vitae_yield = 1 //A bit of essence even if it's a weak soul
|
||||
var/vitae_information = "<span class='umbra'>[L]'s vitae is "
|
||||
if(ishuman(L))
|
||||
vitae_information += "of the highest quality, "
|
||||
vitae_yield += rand(10, 15)
|
||||
if(L.mind)
|
||||
if(!(L.mind in ticker.mode.devils))
|
||||
vitae_information += "in copious amounts, "
|
||||
else
|
||||
vitae_information += "coming from multiple sources, "
|
||||
for(var/i in 1 to (L.mind.devilinfo.soulsOwned.len))
|
||||
vitae_yield += rand(5, 10) //You can drain all the souls that a devil has stolen!
|
||||
vitae_yield += rand(10, 15)
|
||||
if(L.stat == UNCONSCIOUS)
|
||||
vitae_information += "still being produced, "
|
||||
vitae_yield += rand(20, 25) //Significant bonus if the target is in critical condition instead of dead
|
||||
else if(L.stat == DEAD)
|
||||
vitae_information += "stagnant, "
|
||||
vitae_yield += rand(1, 10)
|
||||
vitae_information += "and ready for harvest. You'll absorb around [vitae_yield] vitae - "
|
||||
switch(vitae_yield)
|
||||
if(0 to 15)
|
||||
vitae_information += "not much, but everything counts."
|
||||
if(15 to 30)
|
||||
vitae_information += "decent, but not great."
|
||||
if(30 to 45)
|
||||
vitae_information += "about what you could expect."
|
||||
if(45 to 60)
|
||||
vitae_information += "a good bit, more than you've come to expect."
|
||||
if(75 to vitae_cap)
|
||||
vitae_information += "<i>a bounty, more than you could ever dream of!</i>"
|
||||
vitae_information += " Now, then...</span>"
|
||||
src << vitae_information
|
||||
if(!do_after(src, 30, target = L))
|
||||
harvesting = FALSE
|
||||
return
|
||||
if(L.hellbound)
|
||||
src << "<span class='warning'>[L] seems to have lost their vitae!</span>"
|
||||
harvesting = FALSE
|
||||
return
|
||||
if(!L.stat)
|
||||
src << "<span class='warning'>[L] is conscious again and their vitae is receding!</span>"
|
||||
L << "<span class='warning'>A chill runs across your body.</span>"
|
||||
harvesting = FALSE
|
||||
return
|
||||
immobilize(50)
|
||||
reveal(50)
|
||||
visible_message("<span class='warning'>[src] flickers into existence and reaches out towards [L]...</span>")
|
||||
L.visible_message("<span class='warning'>...who rises into the air, shuddering as purple light streams out of their body!</span>")
|
||||
animate(L, pixel_y = 5, time = 10)
|
||||
Beam(L, icon_state = "drain_life", icon = 'icons/effects/effects.dmi', time = 50)
|
||||
sleep(50)
|
||||
adjust_vitae(vitae_yield, FALSE, "[L]. They won't yield any more for the time being")
|
||||
recently_drained |= L
|
||||
total_drained |= L
|
||||
visible_message("<span class='warning'>[src] winks out of existence, releasing its hold on [L]...</span>")
|
||||
L.visible_message("<span class='warning'>...who falls unceremoniously back to the ground.</span>")
|
||||
animate(L, pixel_y = 0, time = 10)
|
||||
addtimer(src, "harvest_cooldown", rand(UMBRA_MAX_HARVEST_COOLDOWN - 600, UMBRA_MAX_HARVEST_COOLDOWN), L)
|
||||
harvesting = FALSE
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/harvest_cooldown(mob/living/L) //After a while, mobs that have already been drained can be harvested again
|
||||
if(!L)
|
||||
return
|
||||
src << "<span class='umbra'>You think that [L]'s body should be strong enough to produce vitae again.</span>"
|
||||
recently_drained -= L
|
||||
|
||||
/mob/living/simple_animal/umbra/singularity_act() //Umbras are immune to most things that are catastrophic to normal humans
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/narsie_act()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/ratvar_act()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/blob_act(obj/effect/blob/B)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/ex_act(severity)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/umbra/emp_act(severity)
|
||||
src << "<span class='umbra_bold'>You feel the energy of an electromagnetic pulse revitalizing you!</span>" //As they're composed of an EM field, umbras are strengthened by EMPs
|
||||
adjust_vitae(50 - (severity * 10), TRUE)
|
||||
|
||||
|
||||
//Helper procs
|
||||
/mob/living/simple_animal/umbra/proc/adjust_vitae(amount, silent, source)
|
||||
vitae = min(max(0, vitae + amount), vitae_cap)
|
||||
if(!silent)
|
||||
src << "<span class='umbra'>[amount > 0 ? "Gained" : "Lost"] [amount] vitae[source ? " from [source]" : ""].</span>"
|
||||
return vitae
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/unpossess(silent)
|
||||
if(!possessed)
|
||||
return
|
||||
if(!silent)
|
||||
src << "<span class='umbra'>You free yourself from [possessed]'s body.</span>"
|
||||
if(time_possessing >= UMBRA_POSSESSION_THRESHOLD_WARNING)
|
||||
possessed << "<span class='warning'>You feel a horrible presence depart from you...</span>"
|
||||
loc = get_turf(possessed)
|
||||
possessed = null
|
||||
time_possessing = 0
|
||||
notransform = FALSE
|
||||
|
||||
/mob/living/simple_animal/umbra/proc/occupy(mob/dead/observer/O)
|
||||
if(!O)
|
||||
return
|
||||
key = O.key
|
||||
mind.special_role = "Umbra"
|
||||
var/datum/objective/umbra/lobotomize/L = new
|
||||
mind.objectives += L
|
||||
src << "<b>Objective #1:</b> [L.explanation_text]"
|
||||
117
code/game/gamemodes/miniantags/umbra/umbra_abilities.dm
Normal file
@@ -0,0 +1,117 @@
|
||||
//Unlike revenants, abilities used by umbras generally don't cost any vitae.
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/night_vision/umbra //Toggle Nightvision: Self-explanatory
|
||||
panel = "Umbral Evocation"
|
||||
message = "<span class='umbra'>You toggle your night vision.</span>"
|
||||
charge_max = 0
|
||||
action_icon_state = "umbral_sight"
|
||||
action_background_icon_state = "bg_umbra"
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/discordant_whisper //Discordant Whisper: Sends a single, silent message to a creature that the umbra can see. Doesn't work on dead targets.
|
||||
name = "Discordant Whisper"
|
||||
desc = "Telepathically sends a single message to a target within range. Nobody else can perceive this message, and it works on unconscious and deafened targets."
|
||||
panel = "Umbral Evocation"
|
||||
range = 7
|
||||
charge_max = 50
|
||||
clothes_req = FALSE
|
||||
include_user = FALSE
|
||||
action_icon_state = "discordant_whisper"
|
||||
action_background_icon_state = "bg_umbra"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/discordant_whisper/cast(list/targets, mob/living/simple_animal/umbra/user)
|
||||
if(!isumbra(user))
|
||||
revert_cast()
|
||||
return
|
||||
var/mob/living/target = targets[1]
|
||||
if(target.stat == DEAD)
|
||||
user << "<span class='warning'>You can't send thoughts to the dead!</span>"
|
||||
revert_cast()
|
||||
return
|
||||
var/message = stripped_input(user, "Enter a message to transmit to [target].", "Discordant Whisper")
|
||||
if(!message || !target)
|
||||
revert_cast()
|
||||
return
|
||||
log_say("UmbraWhisper: [key_name(user)] -> [key_name(target)]: [message]")
|
||||
user << "<span class='umbra_bold'>You whisper to [target]:</span> <span class='umbra'>\"[message]\"</span>"
|
||||
target << "<span class='umbra_emphasis'>You hear an otherworldly voice...</span> <span class='umbra'>\"[message]\"</span>"
|
||||
for(var/mob/dead/observer/O in dead_mob_list)
|
||||
var/f1 = FOLLOW_LINK(O, user)
|
||||
var/f2 = FOLLOW_LINK(O, target)
|
||||
O << "[f1] <span class='umbra_bold'>[user] (Umbra Whisper):</span> <span class='umbra'>\"[message]\"</span> to [f2] <span class='name'>[target]</span>"
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/possess //Possess: Occupies the body of a sapient and living human, slowly training vitae while they're conscious.
|
||||
name = "Possess/Unpossess"
|
||||
desc = "Enters and merges with the body of a nearby human. While inside of this human, you will very slowly generate vitae."
|
||||
panel = "Umbral Evocation"
|
||||
range = 1
|
||||
charge_max = 600
|
||||
clothes_req = FALSE
|
||||
include_user = FALSE
|
||||
action_icon_state = "possess"
|
||||
action_background_icon_state = "bg_umbra"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/possess/cast(list/targets, mob/living/simple_animal/umbra/user)
|
||||
if(!isumbra(user))
|
||||
revert_cast()
|
||||
return
|
||||
if(!user.possessed)
|
||||
var/mob/living/carbon/human/target = targets[1]
|
||||
if(!ishuman(target))
|
||||
user << "<span class='warning'>Only humans can produce enough vitae to sustain you in this manner!</span>"
|
||||
revert_cast()
|
||||
return
|
||||
user.possessed = target
|
||||
user.loc = target
|
||||
user << "<span class='umbra_emphasis'>You silently enter [user.possessed]'s body and begin leeching vitae. You won't be able to do this for very long.</span>"
|
||||
user.notransform = TRUE
|
||||
else
|
||||
user.unpossess()
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/thoughtsteal //Thoughtsteal: Paralyzes and deals temporary brain damage to a target as the umbra drains it of vitae.
|
||||
name = "Thoughtsteal"
|
||||
desc = "Immobilizes a target as you copy their memories, gaining the knowledge of whatever they know."
|
||||
panel = "Umbral Evocation"
|
||||
range = 1
|
||||
charge_max = 450
|
||||
clothes_req = FALSE
|
||||
include_user = FALSE
|
||||
action_icon_state = "thoughtsteal"
|
||||
action_background_icon_state = "bg_umbra"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/thoughtsteal/cast(list/targets, mob/living/simple_animal/umbra/user)
|
||||
if(!isumbra(user))
|
||||
revert_cast()
|
||||
return
|
||||
var/mob/living/target = targets[1]
|
||||
if(target in user.lobotomized)
|
||||
user << "<span class='warning'>You've already stolen [target]'s memories!</span>"
|
||||
revert_cast()
|
||||
return
|
||||
if(target.stat == DEAD)
|
||||
user << "<span class='warning'>You can't glean any knowledge from a dead brain!</span>"
|
||||
revert_cast()
|
||||
return
|
||||
if(!target.mind)
|
||||
user << "<span class='warning'>[target] is mindless and incapable of higher thought!</span>"
|
||||
revert_cast()
|
||||
return
|
||||
user.visible_message("<span class='warning'>[user] appears from nowhere, stretching out towards [target]!</span>", "<span class='umbra'>You try to copy [target]'s memories...</span>")
|
||||
target.visible_message("<span class='warning'>A blue beam arcs into [target]'s head, immobilizing them!</span>", "<span class='userdanger'>Your mind freezes. You can't move. \
|
||||
You can't think.</span>")
|
||||
user.Beam(target, icon = 'icons/effects/beam.dmi', icon_state = "b_beam", time = 50)
|
||||
user.immobilize(50)
|
||||
user.reveal(50)
|
||||
target.Stun(5)
|
||||
if(!do_after(user, 50, target = target))
|
||||
return
|
||||
user.visible_message("<span class='warning'>A chunk of biomatter travels along the beam and into [user]!</span>", \
|
||||
"<span class='umbra_bold'>Sweet, sweet thoughts. A lifetime of memories surges through you.</span>")
|
||||
target.visible_message("<span class='warning'>[target] silently collapses, motionless.</span>", "<span class='userdanger'>Your mind blanks. Your thoughts have fled. Slowly, they begin to \
|
||||
return... but you feel <i>wrong.</i></span>")
|
||||
target.mind.show_memory(user, 0)
|
||||
user.mind.memory += "<b><i>[target.real_name]'s Memories:</i></b>\n[target.mind.memory]\n\n"
|
||||
target.Weaken(5)
|
||||
user.lobotomized |= target
|
||||
28
code/game/gamemodes/miniantags/umbra/umbra_objectives.dm
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
|
||||
Possible objectives:
|
||||
1. Steal the memories of # humans. (# = round population / 4)
|
||||
|
||||
*/
|
||||
|
||||
/datum/objective/umbra
|
||||
explanation_text = "Be an umbra."
|
||||
|
||||
/datum/objective/umbra/check_completion()
|
||||
return 1
|
||||
|
||||
/datum/objective/umbra/lobotomize
|
||||
explanation_text = "Steal the memories of several humans."
|
||||
|
||||
/datum/objective/umbra/lobotomize/New()
|
||||
target_amount = round(ticker.mode.num_players() / 4)
|
||||
explanation_text = "Steal the memories of [target_amount] humans."
|
||||
..()
|
||||
|
||||
/datum/objective/umbra/lobotomize/check_completion()
|
||||
if(!isumbra(owner.current))
|
||||
return 0
|
||||
var/mob/living/simple_animal/umbra/U = owner.current
|
||||
if(U.lobotomized.len >= target_amount)
|
||||
return 1
|
||||
return 0
|
||||
17
code/game/gamemodes/miniantags/umbra/umbra_spawn_event.dm
Normal file
@@ -0,0 +1,17 @@
|
||||
/datum/round_event_control/spawn_umbra
|
||||
name = "Spawn Umbra"
|
||||
typepath = /datum/round_event/ghost_role/umbra
|
||||
weight = 15
|
||||
earliest_start = 6000
|
||||
max_occurrences = 3
|
||||
|
||||
/datum/round_event/ghost_role/umbra
|
||||
minimum_required = 1
|
||||
role_name = "umbra"
|
||||
|
||||
/datum/round_event/ghost_role/umbra/spawn_role()
|
||||
message_admins("An unoccupied umbra was created by a random event.")
|
||||
var/mob/living/simple_animal/umbra/U = new(pick(xeno_spawn))
|
||||
var/image/alert_overlay = image('icons/mob/mob.dmi', "umbra")
|
||||
notify_ghosts("An umbra has formed in [get_area(U)]. Interact with it to take control of it.", null, source = U, alert_overlay = alert_overlay)
|
||||
return SUCCESSFUL_SPAWN
|
||||
44
code/game/gamemodes/miniantags/umbra/umbral_ashes.dm
Normal file
@@ -0,0 +1,44 @@
|
||||
#define UMBRA_ASHES_REFORM_TIME 600 //In deciseconds, how long ashes take to reform
|
||||
|
||||
/obj/item/umbral_ashes
|
||||
name = "umbral ashes"
|
||||
desc = "A shimmering pile of blue ashes with a glowing purple core."
|
||||
icon = 'icons/obj/magic.dmi'
|
||||
icon_state = "umbral_ashes"
|
||||
w_class = 2
|
||||
gender = PLURAL
|
||||
origin_tech = "materials=6;bluespace=4;biotech=6" //Good origin tech if you think you have enough time to get them to research
|
||||
var/umbra_key //The key of the umbra that these ashes came from
|
||||
var/umbra_vitae //The vitae of the umbra that these ashes came from
|
||||
|
||||
/obj/item/umbral_ashes/New()
|
||||
..()
|
||||
addtimer(src, "reform", UMBRA_ASHES_REFORM_TIME)
|
||||
|
||||
/obj/item/umbral_ashes/attack_self(mob/living/user)
|
||||
user.visible_message("<span class='warning'>[user] scatters [src]!</span>", "<span class='notice'>You scatter [src], which tremble and fade away.</span>")
|
||||
user.drop_item()
|
||||
qdel(src)
|
||||
return 1
|
||||
|
||||
/obj/item/umbral_ashes/proc/reform()
|
||||
if(!src)
|
||||
return
|
||||
visible_message("<span class='warning'>[src] hover into the air and reform!</span>")
|
||||
flick("umbral_ashes_reforming", src)
|
||||
animate(src, alpha = 0, time = 12)
|
||||
sleep(12)
|
||||
var/mob/living/simple_animal/umbra/U = new(get_turf(src))
|
||||
U.key = umbra_key
|
||||
if(!U.client)
|
||||
U.key = null
|
||||
var/image/alert_overlay = image('icons/mob/mob.dmi', "umbra")
|
||||
notify_ghosts("An umbra has re-formed in [get_area(U)]. Interact with it to take control of it.", null, source = U, alert_overlay = alert_overlay)
|
||||
else
|
||||
U << "<span class='umbra_emphasis'>Back... you're back. You can't remember what you were supposed to be doing here. Now... where were we?</span>"
|
||||
if(umbra_vitae)
|
||||
U.vitae = umbra_vitae
|
||||
U.alpha = 0
|
||||
animate(U, alpha = initial(U.alpha), time = 10) //To give a fade-in effect for the newly-spawned
|
||||
qdel(src)
|
||||
return 1
|
||||
@@ -158,4 +158,10 @@
|
||||
/obj/effect/decal/cleanable/shreds/New()
|
||||
pixel_x = rand(-5, 5)
|
||||
pixel_y = rand(-5, 5)
|
||||
..()
|
||||
..()
|
||||
|
||||
/obj/effect/decal/cleanable/salt
|
||||
name = "salt pile"
|
||||
desc = "A sizable pile of table salt. Someone must be upset."
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
icon_state = "salt_pile"
|
||||
|
||||
@@ -254,17 +254,10 @@
|
||||
icon_state = "sigilactiveoverlay"
|
||||
alpha = 0
|
||||
|
||||
|
||||
/obj/effect/overlay/temp/revenant
|
||||
/obj/effect/overlay/temp/purple_sparkles
|
||||
name = "spooky lights"
|
||||
icon_state = "purplesparkles"
|
||||
|
||||
/obj/effect/overlay/temp/revenant/cracks
|
||||
name = "glowing cracks"
|
||||
icon_state = "purplecrack"
|
||||
duration = 6
|
||||
|
||||
|
||||
/obj/effect/overlay/temp/emp
|
||||
name = "emp sparks"
|
||||
icon_state = "empdisable"
|
||||
|
||||
@@ -119,13 +119,6 @@
|
||||
else
|
||||
message_admins("[key_name_admin(usr)] tried to create an abductor team. Unfortunatly there were not enough candidates available.")
|
||||
log_admin("[key_name(usr)] failed to create an abductor team.")
|
||||
if("15")
|
||||
if(src.makeRevenant())
|
||||
message_admins("[key_name(usr)] created a revenant.")
|
||||
log_admin("[key_name(usr)] created a revenant.")
|
||||
else
|
||||
message_admins("[key_name_admin(usr)] tried to create a revenant. Unfortunately, there were no candidates available.")
|
||||
log_admin("[key_name(usr)] failed to create a revenant.")
|
||||
if("16")
|
||||
if(src.makeShadowling())
|
||||
message_admins("[key_name(usr)] created a shadowling.")
|
||||
@@ -1608,7 +1601,7 @@
|
||||
|
||||
else if(href_list["adminchecklaws"])
|
||||
output_ai_laws()
|
||||
|
||||
|
||||
else if(href_list["admincheckdevilinfo"])
|
||||
output_devil_info()
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
<a href='?src=\ref[src];makeAntag=7'>Make Nuke Team (Requires Ghosts)</a><br>
|
||||
<a href='?src=\ref[src];makeAntag=13'>Make Centcom Response Team (Requires Ghosts)</a><br>
|
||||
<a href='?src=\ref[src];makeAntag=14'>Make Abductor Team (Requires Ghosts)</a><br>
|
||||
<a href='?src=\ref[src];makeAntag=15'>Make Revenant (Requires Ghost)</a><br>
|
||||
"}
|
||||
|
||||
var/datum/browser/popup = new(usr, "oneclickantag", "Quick-Create Antagonist", 400, 400)
|
||||
@@ -514,9 +513,6 @@
|
||||
new /datum/round_event/ghost_role/abductor
|
||||
return 1
|
||||
|
||||
/datum/admins/proc/makeRevenant()
|
||||
new /datum/round_event/ghost_role/revenant
|
||||
|
||||
//Shadowling
|
||||
/datum/admins/proc/makeShadowling()
|
||||
var/datum/game_mode/shadowling/temp = new
|
||||
|
||||
@@ -49,9 +49,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
var/B_gang = 4096
|
||||
var/B_shadowling = 8192
|
||||
var/B_abductor = 16384
|
||||
var/B_revenant = 32768
|
||||
|
||||
var/list/archived = list(B_traitor,B_operative,B_changeling,B_wizard,B_malf,B_rev,B_alien,B_pai,B_cultist,B_blob,B_ninja,B_monkey,B_gang,B_shadowling,B_abductor,B_revenant)
|
||||
var/list/archived = list(B_traitor,B_operative,B_changeling,B_wizard,B_malf,B_rev,B_alien,B_pai,B_cultist,B_blob,B_ninja,B_monkey,B_gang,B_shadowling,B_abductor)
|
||||
|
||||
be_special = list()
|
||||
|
||||
@@ -89,8 +88,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
be_special += ROLE_SHADOWLING
|
||||
if(16384)
|
||||
be_special += ROLE_ABDUCTOR
|
||||
if(32768)
|
||||
be_special += ROLE_REVENANT
|
||||
|
||||
|
||||
/datum/preferences/proc/update_preferences(current_version)
|
||||
|
||||
@@ -133,6 +133,16 @@
|
||||
desc = "Salt. From dead crew, presumably."
|
||||
return (TOXLOSS)
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/condiment/saltshaker/afterattack(obj/target, mob/living/user, proximity)
|
||||
if(!proximity || !isturf(target))
|
||||
return
|
||||
if(!reagents.has_reagent("sodiumchloride", 2))
|
||||
user << "<span class='warning'>You don't have enough salt to make a pile!</span>"
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user] shakes some salt onto [target].</span>", "<span class='notice'>You shake some salt onto [target].</span>")
|
||||
reagents.remove_reagent("sodiumchloride", 2)
|
||||
new/obj/effect/decal/cleanable/salt(target)
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/condiment/peppermill
|
||||
name = "pepper mill"
|
||||
desc = "Often used to flavor food or make people sneeze."
|
||||
|
||||
@@ -445,8 +445,9 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
|
||||
|
||||
/proc/offer_control(mob/M)
|
||||
M << "Control of your mob has been offered to dead players."
|
||||
log_admin("[key_name(usr)] has offered control of ([key_name(M)]) to ghosts.")
|
||||
message_admins("[key_name_admin(usr)] has offered control of ([key_name_admin(M)]) to ghosts")
|
||||
if(usr)
|
||||
log_admin("[key_name(usr)] has offered control of ([key_name(M)]) to ghosts.")
|
||||
message_admins("[key_name_admin(usr)] has offered control of ([key_name_admin(M)]) to ghosts")
|
||||
var/poll_message = "Do you want to play as [M.real_name]?"
|
||||
if(M.mind && M.mind.assigned_role)
|
||||
poll_message = "[poll_message] Job:[M.mind.assigned_role]."
|
||||
|
||||
@@ -224,16 +224,23 @@
|
||||
anim(mobloc,mob,'icons/mob/mob.dmi',,"shadow",,L.dir)
|
||||
L.loc = get_step(L, direct)
|
||||
L.setDir(direct)
|
||||
if(3) //Incorporeal move, but blocked by holy-watered tiles
|
||||
if(3) //Incorporeal move, but blocked by holy-watered tiles and salt piles. Used by umbras.
|
||||
if(!isumbra(L))
|
||||
L.incorporeal_move = 1
|
||||
return
|
||||
var/mob/living/simple_animal/umbra/U = L
|
||||
var/turf/open/floor/stepTurf = get_step(L, direct)
|
||||
for(var/obj/effect/decal/cleanable/salt/S in stepTurf)
|
||||
U << "<span class='warning'>[S] bars your passage!</span>"
|
||||
U.reveal(2, TRUE)
|
||||
U.immobilize(2, TRUE)
|
||||
return
|
||||
if(stepTurf.flags & NOJAUNT)
|
||||
L << "<span class='warning'>Holy energies block your path.</span>"
|
||||
L.notransform = 1
|
||||
spawn(2)
|
||||
L.notransform = 0
|
||||
U << "<span class='warning'>Holy energies block your path!</span>"
|
||||
U.immobilize(2, TRUE)
|
||||
else
|
||||
L.loc = get_step(L, direct)
|
||||
L.setDir(direct)
|
||||
U.loc = get_step(L, direct)
|
||||
U.setDir(direct)
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
@@ -539,7 +539,7 @@
|
||||
/datum/reagent/blob/adaptive_nexuses/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
|
||||
reac_volume = ..()
|
||||
if(O && ishuman(M) && M.stat == UNCONSCIOUS)
|
||||
PoolOrNew(/obj/effect/overlay/temp/revenant, get_turf(M))
|
||||
PoolOrNew(/obj/effect/overlay/temp/purple_sparkles, get_turf(M))
|
||||
var/points = rand(5, 10)
|
||||
O.add_points(points)
|
||||
O << "<span class='notice'>Gained [points] resources from the death of [M].</span>"
|
||||
|
||||
@@ -247,12 +247,19 @@
|
||||
reagent_state = SOLID
|
||||
color = "#FFFFFF" // rgb: 255,255,255
|
||||
|
||||
/datum/reagent/consumable/sodiumchloride/reaction_mob(mob/living/M, method=TOUCH, reac_volume)//Splashing people with welding fuel to make them easy to ignite!
|
||||
/datum/reagent/consumable/sodiumchloride/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
|
||||
if(!istype(M))
|
||||
return
|
||||
if(M.has_bane(BANE_SALT))
|
||||
M.mind.disrupt_spells(-200)
|
||||
|
||||
/datum/reagent/consumable/sodiumchloride/reaction_turf(turf/T, reac_volume) //Creates an umbra-blocking salt pile
|
||||
if(!istype(T))
|
||||
return
|
||||
if(reac_volume < 1)
|
||||
return
|
||||
new/obj/effect/decal/cleanable/salt(T)
|
||||
|
||||
/datum/reagent/consumable/blackpepper
|
||||
name = "Black Pepper"
|
||||
id = "blackpepper"
|
||||
|
||||
@@ -63,14 +63,6 @@
|
||||
if(created_volume >= 150)
|
||||
playsound(get_turf(holder.my_atom), 'sound/effects/pray.ogg', 80, 0, round(created_volume/48))
|
||||
strengthdiv = 8
|
||||
for(var/mob/living/simple_animal/revenant/R in get_hearers_in_view(7,get_turf(holder.my_atom)))
|
||||
var/diety = ticker.Bible_deity_name
|
||||
if(!ticker.Bible_deity_name)
|
||||
diety = "Christ"
|
||||
R << "<span class='userdanger'>The power of [diety] compels you!</span>"
|
||||
R.stun(20)
|
||||
R.reveal(100)
|
||||
sleep(20)
|
||||
for(var/mob/living/carbon/C in get_hearers_in_view(round(created_volume/48,1),get_turf(holder.my_atom)))
|
||||
if(iscultist(C) || is_handofgod_cultist(C) || C.dna.species.id == "shadowling" || C.dna.species.id == "l_shadowling")
|
||||
C << "<span class='userdanger'>The divine explosion sears you!</span>"
|
||||
|
||||
|
Before Width: | Height: | Size: 421 KiB After Width: | Height: | Size: 418 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 252 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 18 KiB |
@@ -73,6 +73,18 @@ h1.alert, h2.alert {color: #000000;}
|
||||
.holoparasite {color: #35333a;}
|
||||
.holoparasitebold {color: #35333a; font-weight: bold;}
|
||||
|
||||
.revennotice {color: #1d2953;}
|
||||
.revenboldnotice {color: #1d2953; font-weight: bold;}
|
||||
.revenbignotice {color: #1d2953; font-weight: bold; font-size: 3;}
|
||||
.revenminor {color: #823abb}
|
||||
.revenwarning {color: #760fbb; font-style: italic;}
|
||||
.revendanger {color: #760fbb; font-weight: bold; font-size: 3;}
|
||||
.umbra {color: #5000A0;}
|
||||
.umbra_bold {color: #5000A0; font-weight: bold;}
|
||||
.umbra_italics {color: #5000A0; font-style: italic;}
|
||||
.umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;}
|
||||
.umbra_large {color: #5000A0; font-size: 3;}
|
||||
|
||||
.brass {color: #BE8700;}
|
||||
.heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;}
|
||||
.large_brass {color: #BE8700; font-size: 3;}
|
||||
@@ -91,13 +103,6 @@ h1.alert, h2.alert {color: #000000;}
|
||||
.neovgre {color: #13143F; font-weight: bold; font-style: italic;}
|
||||
.neovgre_small {color: #13143F;}
|
||||
|
||||
.revennotice {color: #1d2953;}
|
||||
.revenboldnotice {color: #1d2953; font-weight: bold;}
|
||||
.revenbignotice {color: #1d2953; font-weight: bold; font-size: 3;}
|
||||
.revenminor {color: #823abb}
|
||||
.revenwarning {color: #760fbb; font-style: italic;}
|
||||
.revendanger {color: #760fbb; font-weight: bold; font-size: 3;}
|
||||
|
||||
.newscaster {color: #800000;}
|
||||
.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;}
|
||||
|
||||
|
||||
@@ -120,7 +120,6 @@
|
||||
#include "code\_onclick\hud\monkey.dm"
|
||||
#include "code\_onclick\hud\movable_screen_objects.dm"
|
||||
#include "code\_onclick\hud\other_mobs.dm"
|
||||
#include "code\_onclick\hud\revenanthud.dm"
|
||||
#include "code\_onclick\hud\robot.dm"
|
||||
#include "code\_onclick\hud\screen_objects.dm"
|
||||
#include "code\_onclick\hud\swarmer.dm"
|
||||
@@ -366,13 +365,14 @@
|
||||
#include "code\game\gamemodes\miniantags\hades\hades.dm"
|
||||
#include "code\game\gamemodes\miniantags\monkey\monkey.dm"
|
||||
#include "code\game\gamemodes\miniantags\morph\morph.dm"
|
||||
#include "code\game\gamemodes\miniantags\revenant\revenant.dm"
|
||||
#include "code\game\gamemodes\miniantags\revenant\revenant_abilities.dm"
|
||||
#include "code\game\gamemodes\miniantags\revenant\revenant_blight.dm"
|
||||
#include "code\game\gamemodes\miniantags\revenant\revenant_spawn_event.dm"
|
||||
#include "code\game\gamemodes\miniantags\sintouched\objectives.dm"
|
||||
#include "code\game\gamemodes\miniantags\slaughter\slaughter.dm"
|
||||
#include "code\game\gamemodes\miniantags\slaughter\slaughterevent.dm"
|
||||
#include "code\game\gamemodes\miniantags\umbra\umbra.dm"
|
||||
#include "code\game\gamemodes\miniantags\umbra\umbra_abilities.dm"
|
||||
#include "code\game\gamemodes\miniantags\umbra\umbra_objectives.dm"
|
||||
#include "code\game\gamemodes\miniantags\umbra\umbra_spawn_event.dm"
|
||||
#include "code\game\gamemodes\miniantags\umbra\umbral_ashes.dm"
|
||||
#include "code\game\gamemodes\nuclear\nuclear.dm"
|
||||
#include "code\game\gamemodes\nuclear\nuclear_challenge.dm"
|
||||
#include "code\game\gamemodes\nuclear\nuclearbomb.dm"
|
||||
|
||||