diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 16e3fb56d23..5f79c5e62b5 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -149,15 +149,7 @@ Class Procs:
if(use_power && stat == 0)
use_power(7500/severity)
- var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( src.loc )
- pulse2.icon = 'icons/effects/effects.dmi'
- pulse2.icon_state = "empdisable"
- pulse2.name = "emp sparks"
- pulse2.anchored = 1
- pulse2.dir = pick(cardinal)
-
- spawn(10)
- pulse2.delete()
+ new/obj/effect/overlay/temp/emp(src.loc)
..()
/obj/machinery/ex_act(severity)
diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm
index e20010d0c2a..5fcdefe6215 100644
--- a/code/game/objects/effects/overlays.dm
+++ b/code/game/objects/effects/overlays.dm
@@ -19,6 +19,41 @@
..()
spawn(10) qdel(src)
+
+/obj/effect/overlay/temp
+ anchored = 1
+ layer = 4.1
+ mouse_opacity = 0
+ var/duration = 10
+ var/randomdir = 1
+
+/obj/effect/overlay/temp/New()
+ if(randomdir)
+ dir = pick(cardinal)
+ spawn(duration)
+ qdel(src)
+
+/obj/effect/overlay/temp/revenant
+ name = "spooky lights"
+ icon = 'icons/effects/effects.dmi'
+ 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 = 'icons/effects/effects.dmi'
+ icon_state = "empdisable"
+
+/obj/effect/overlay/temp/emp/pulse
+ name = "emp pulse"
+ icon_state = "emp pulse"
+ duration = 20
+ randomdir = 0
+
/obj/effect/overlay/palmtree_r
name = "Palm tree"
icon = 'icons/misc/beach2.dmi'
diff --git a/code/game/objects/empulse.dm b/code/game/objects/empulse.dm
index 8bff463e445..ed5bbadeadd 100644
--- a/code/game/objects/empulse.dm
+++ b/code/game/objects/empulse.dm
@@ -9,13 +9,7 @@ proc/empulse(turf/epicenter, heavy_range, light_range, log=0)
log_game("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ")
if(heavy_range > 1)
- var/obj/effect/overlay/pulse = new/obj/effect/overlay ( epicenter )
- pulse.icon = 'icons/effects/effects.dmi'
- pulse.icon_state = "emppulse"
- pulse.name = "emp pulse"
- pulse.anchored = 1
- spawn(20)
- pulse.delete()
+ new/obj/effect/overlay/temp/emp/pulse(epicenter)
if(heavy_range > light_range)
light_range = heavy_range
diff --git a/code/modules/mob/living/simple_animal/revenant/revenant.dm b/code/modules/mob/living/simple_animal/revenant/revenant.dm
index 6ba32e69f5c..70edbc27dd3 100644
--- a/code/modules/mob/living/simple_animal/revenant/revenant.dm
+++ b/code/modules/mob/living/simple_animal/revenant/revenant.dm
@@ -2,17 +2,22 @@
//"Ghosts" that are invisible and move like ghosts, cannot take damage while invsible
//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_OBSERVER
- health = 25
- maxHealth = 25
- see_invisible = SEE_INVISIBLE_OBSERVER
+ invisibility = INVISIBILITY_REVENANT
+ health = INFINITY //Revenants don't use health, they use essence instead
+ maxHealth = INFINITY
+ see_invisible = INVISIBILITY_REVENANT
universal_understand = 1
response_help = "passes through"
response_disarm = "swings at"
@@ -23,16 +28,16 @@
harm_intent_damage = 0
friendly = "touches"
status_flags = 0
+ see_in_dark = 8
wander = 0
density = 0
flying = 1
anchored = 1
- var/essence = 25 //The resource of revenants. Max health is equal to three times this amount
- var/essence_regen_cap = 25 //The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount.
+ var/essence = 75 //The resource of revenants. Max health is equal to three times this amount
+ 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 = 2 //How much essence regenerates
- var/essence_min = 1 //The minimum amount of essence a revenant can have; by default, it never drops below one
+ 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.
@@ -41,27 +46,24 @@
var/essence_drained = 0 //How much essence the revenant has drained.
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.
+ var/image/ghostimage = null //Visible to ghost with darkness off
/mob/living/simple_animal/revenant/Life()
..()
- if(essence < essence_min)
- essence = essence_min
+ if(revealed && essence <= 0)
+ death()
if(essence_regenerating && !inhibited && essence < essence_regen_cap) //While inhibited, essence will not regenerate
- essence += essence_regen_amount
- if(essence > essence_regen_cap)
- essence = essence_regen_cap
- maxHealth = essence * 3
+ essence = min(essence_regen_cap, essence+essence_regen_amount)
if(unreveal_time && world.time >= unreveal_time)
unreveal_time = 0
revealed = 0
- invisibility = INVISIBILITY_OBSERVER
+ invisibility = INVISIBILITY_REVENANT
src << "You are once more concealed."
if(unstun_time && world.time >= unstun_time)
unstun_time = 0
notransform = 0
src << "You can move again!"
- if(!revealed)
- health = maxHealth //Heals to full when not revealed
update_spooky_icon()
/mob/living/simple_animal/revenant/ex_act(severity)
@@ -70,6 +72,19 @@
/mob/living/simple_animal/revenant/blob_act()
return 1 //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.
+
+/mob/living/simple_animal/revenant/adjustBruteLoss(amount)
+ if(!revealed)
+ return
+ essence = max(0, essence-amount)
+ if(essence == 0)
+ src << "You feel your essence fraying!"
+
/mob/living/simple_animal/revenant/ClickOn(var/atom/A, var/params) //Copypaste from ghost code - revenants can't interact with the world directly.
if(client.buildmode)
build_click(src, client.buildmode, params, A)
@@ -99,62 +114,78 @@
if(!castcheck(0))
return
if(draining)
- src << "You are already siphoning the essence of a soul!"
+ src << "You are already siphoning the essence of a soul!"
return
if(target in drained_mobs)
- src << "[target]'s soul is dead and empty."
+ src << "[target]'s soul is dead and empty."
return
if(!target.stat)
- src << "This being's soul is too strong to harvest."
+ src << "This being's soul is too strong to harvest."
if(prob(10))
target << "You feel as if you are being watched."
return
draining = 1
- essence_drained = 2
- src << "You search for the soul of [target]."
+ essence_drained = rand(15, 20)
+ src << "You search for the soul of [target]."
if(do_after(src, 10, 3, 0, target = target)) //did they get deleted in that second?
if(target.ckey)
- src << "Their soul burns with intelligence."
- essence_drained += 2
+ src << "Their soul burns with intelligence."
+ essence_drained += rand(20, 30)
if(target.stat != DEAD)
- src << "Their soul blazes with life!"
- essence_drained += 2
+ src << "Their soul blazes with life!"
+ essence_drained += rand(40, 50)
else
- src << "Their soul is weak and faltering."
+ src << "Their soul is weak and faltering."
if(do_after(src, 20, 6, 0, target = target)) //did they get deleted NOW?
switch(essence_drained)
- if(1 to 2)
- src << "[target] will not yield much essence. Still, every bit counts."
- if(3 to 4)
- src << "[target] will yield an average amount of essence."
- if(5 to INFINITY)
- src << "Such a feast! [target] will yield much essence to you."
- if(do_after(src, 30, 9, 0, target = target)) //how about now
+ if(1 to 30)
+ src << "[target] will not yield much essence. Still, every bit counts."
+ if(30 to 70)
+ src << "[target] will yield an average amount of essence."
+ if(70 to 90)
+ src << "Such a feast! [target] will yield much essence to you."
+ if(90 to INFINITY)
+ src << "Ah, the perfect soul. [target] will yield massive amounts of essence to you."
+ if(do_after(src, 20, 6, 0, target = target)) //how about now
if(!target.stat)
- src << "They are now powerful enough to fight off your draining."
+ src << "They are now powerful enough to fight off your draining."
target << "You feel something tugging across your body before subsiding."
draining = 0
return //hey, wait a minute...
- src << "You begin siphoning essence from [target]'s soul."
+ src << "You begin siphoning essence from [target]'s soul."
if(target.stat != DEAD)
target << "You feel a horribly unpleasant draining sensation as your grip on life weakens..."
icon_state = "revenant_draining"
- reveal(65)
- stun(65)
+ reveal(27)
+ stun(27)
target.visible_message("[target] suddenly rises slightly into the air, their skin turning an ashy gray.")
- target.Beam(src,icon_state="drain_life",icon='icons/effects/effects.dmi',time=60)
- if(target) //As one cannot prove the existance of ghosts, ghosts cannot prove the existance of the target they were draining.
- change_essence_amount(essence_drained * 5, 0, target)
- src << "[target]'s soul has been considerably weakened and will yield no more essence for the time being."
- target.visible_message("[target] gently slumps back onto the ground.")
+ target.Beam(src,icon_state="drain_life",icon='icons/effects/effects.dmi',time=26)
+ if(do_after(src, 30, 9, 0, target)) //As one cannot prove the existance of ghosts, ghosts cannot prove the existance of the target they were draining.
+ change_essence_amount(essence_drained, 0, target)
+ if(essence_drained > 90)
+ essence_regen_cap += 25
+ perfectsouls += 1
+ src << "The perfection of [target]'s soul has increased your maximum essence level. Your new maximum essence is [essence_regen_cap]."
+ src << "[target]'s soul has been considerably weakened and will yield no more essence for the time being."
+ target.visible_message("[target] slumps onto the ground.", \
+ "Violets lights, dancing in your vision, getting clo--")
drained_mobs.Add(target)
target.death(0)
- icon_state = "revenant_idle"
+ else
+ src << "[target ? "[target] has":"They have"] been drawn out of your grasp. The link has been broken."
+ draining = 0
+ essence_drained = 0
+ if(target) //Wait, target is WHERE NOW?
+ target.visible_message("[target] slumps onto the ground.", \
+ "Violets lights, dancing in your vision, receding--")
+ return
else
- src << "You are not close enough to siphon [target]'s soul. The link has been broken."
+ src << "You are not close enough to siphon [target ? "[target]'s":"their"] soul. The link has been broken."
draining = 0
+ essence_drained = 0
return
draining = 0
+ essence_drained = 0
return
/mob/living/simple_animal/revenant/say(message)
@@ -163,11 +194,17 @@
/mob/living/simple_animal/revenant/Stat()
..()
if(statpanel("Status"))
- stat(null, "Current essence: [essence]E")
+ 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/New()
..()
+
+ ghostimage = image(src.icon,src,src.icon_state)
+ ghost_darkness_images |= ghostimage
+ updateallghostimages()
+
spawn(5)
if(src.mind)
src.mind.wipe_memory()
@@ -176,8 +213,8 @@
src << "You are a revenant."
src << "Your formerly mundane spirit has been infused with alien energies and empowered into a revenant."
src << "You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds."
- src << "You are invincible and invisible to everyone but other ghosts. Some abilities may change this."
- src << "To function, you are to drain the life essence from humans. This essence is a resource and will power all of your abilities."
+ src << "You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable."
+ src << "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."
src << "You do not remember anything of your past lives, nor will you remember anything about this one after your death."
src << "Be sure to read the wiki page at http://nanotrasen.se/wiki/index.php/Revenant to learn more."
var/datum/objective/revenant/objective = new
@@ -198,17 +235,21 @@
/mob/living/simple_animal/revenant/proc/giveSpells()
if(src.mind)
- src.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/revenant_harvest
- src.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/revenant_transmit
- src.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/revenant_light
- src.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/revenant_defile
- src.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/revenant_malf
+ src.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null))
+ src.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/overload(null))
+ src.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null))
+ src.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction(null))
return 1
return 0
/mob/living/simple_animal/revenant/death()
..()
- src << "NO! No... it's too late, you can feel yourself fading..."
+ if(!revealed) //Revenants cannot die if they aren't revealed
+ return
+ ghost_darkness_images -= ghostimage
+ updateallghostimages()
+
+ src << "NO! No... it's too late, you can feel your essence breaking apart..."
notransform = 1
revealed = 1
invisibility = 0
@@ -218,8 +259,9 @@
for(var/i = alpha, i > 0, i -= 10)
sleep(0.1)
alpha = i
- visible_message("[src]'s body breaks apart into blue dust.")
- new /obj/item/weapon/ectoplasm/revenant(get_turf(src))
+ visible_message("[src]'s body breaks apart into a fine pile of blue dust.")
+ var/obj/item/weapon/ectoplasm/revenant/R = new (get_turf(src))
+ R.client_to_revive = src.client //If the essence reforms, the old revenant is put back in the body
ghostize()
qdel(src)
return
@@ -228,8 +270,8 @@
/mob/living/simple_animal/revenant/attackby(obj/item/W, mob/living/user, params)
if(istype(W, /obj/item/weapon/nullrod))
visible_message("[src] violently flinches!", \
- "As the null rod passes through you, you feel your essence draining away!")
- essence -= 25 //hella effective
+ "As the null rod passes through you, you feel your essence draining away!")
+ adjustBruteLoss(25) //hella effective
inhibited = 1
spawn(30)
inhibited = 0
@@ -241,13 +283,13 @@
return
var/turf/T = get_turf(src)
if(istype(T, /turf/simulated/wall))
- src << "You cannot use abilities from inside of a wall."
+ src << "You cannot use abilities from inside of a wall."
return 0
if(src.inhibited)
- src << "Your powers have been suppressed by nulling energy!"
+ src << "Your powers have been suppressed by nulling energy!"
return 0
if(!src.change_essence_amount(essence_cost, 1))
- src << "You lack the essence to use that ability."
+ src << "You lack the essence to use that ability."
return 0
return 1
@@ -256,16 +298,14 @@
return
if(essence + essence_amt <= 0)
return
- essence += essence_amt
- essence = max(0, essence)
+ essence = max(0, essence+essence_amt)
if(essence_amt > 0)
- essence_accumulated += essence_amt
- essence_accumulated = max(0, essence_accumulated)
+ essence_accumulated = max(0, essence_accumulated+essence_amt)
if(!silent)
if(essence_amt > 0)
- src << "Gained [essence_amt]E from [source]."
+ src << "Gained [essence_amt]E from [source]."
else
- src << "Lost [essence_amt]E from [source]."
+ src << "Lost [essence_amt]E from [source]."
return 1
/mob/living/simple_animal/revenant/proc/reveal(time)
@@ -276,11 +316,12 @@
revealed = 1
invisibility = 0
if(!unreveal_time)
- src << "You have been revealed!"
+ src << "You have been revealed!"
unreveal_time = world.time + time
else
- src << "You have been revealed!"
+ src << "You have been revealed!"
unreveal_time = unreveal_time + time
+ update_spooky_icon()
/mob/living/simple_animal/revenant/proc/stun(time)
if(!src)
@@ -289,30 +330,30 @@
return
notransform = 1
if(!unstun_time)
- src << "You cannot move!"
+ src << "You cannot move!"
unstun_time = world.time + time
else
- src << "You cannot move!"
+ src << "You cannot move!"
unstun_time = unstun_time + time
update_spooky_icon()
/mob/living/simple_animal/revenant/proc/update_spooky_icon()
- if(unreveal_time)
- if(draining)
- icon_state = "revenant_draining"
- return
- if(unstun_time)
- icon_state = "revenant_stun"
- return
- icon_state = "revenant_revealed"
- return
- icon_state = "revenant_idle"
+ 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
/datum/objective/revenant
var/targetAmount = 100
/datum/objective/revenant/New()
- targetAmount = rand(100,200)
+ targetAmount = rand(200,500)
explanation_text = "Absorb [targetAmount] points of essence from humans."
..()
@@ -349,27 +390,23 @@
icon = 'icons/effects/effects.dmi'
icon_state = "revenantEctoplasm"
w_class = 2
- var/reforming = 0
- var/reformed = 0
+ var/reforming = 1
+ var/inert = 0
+ var/client/client_to_revive
/obj/item/weapon/ectoplasm/revenant/New()
..()
- reforming = 1
+ reforming = 0
spawn(600) //1 minutes
if(src && reforming)
return reform()
- if(src && !reforming)
+ else
+ inert = 1
visible_message("[src] settles down and seems lifeless.")
return
-/obj/item/weapon/ectoplasm/revenant/attack_hand(mob/user)
- if(reformed)
- user << "[src] keeps slipping out of your hands, you can't get a hold on it!"
- return
- ..()
-
/obj/item/weapon/ectoplasm/revenant/attack_self(mob/user)
- if(!reforming)
+ if(!reforming || inert)
return ..()
user.visible_message("[user] scatters [src] in all directions.", \
"You scatter [src] across the area. The particles slowly fade away.")
@@ -378,39 +415,58 @@
/obj/item/weapon/ectoplasm/revenant/throw_impact(atom/hit_atom)
..()
+ if(inert)
+ return
visible_message("[src] breaks into particles upon impact, which fade away to nothingness.")
qdel(src)
/obj/item/weapon/ectoplasm/revenant/examine(mob/user)
..(user)
- if(reforming)
- user << "It is shifting and distorted. It would be wise to destroy this."
- else if(!reforming)
- user << "It seems inert."
+ if(inert)
+ user << "It seems inert."
+ else if(reforming)
+ user << "It is shifting and distorted. It would be wise to destroy this."
/obj/item/weapon/ectoplasm/revenant/proc/reform()
- if(!reforming || !src)
+ if(inert || !src)
return
- message_admins("Revenant ectoplasm was left undestroyed for 1 minute and has reformed into a new revenant.")
+ 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
- visible_message("[src] suddenly rises into the air before fading away.")
var/mob/living/simple_animal/revenant/R = new(get_turf(src))
- qdel(src)
- var/list/candidates = get_candidates(BE_REVENANT)
- if(!candidates.len)
- message_admins("No candidates were found for the new revenant. Oh well!")
- return 0
- var/client/C = pick(candidates)
- var/key_of_revenant = C.key
+ 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("No ckey was found for the new revenant. Oh well!")
- return 0
+ 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(BE_REVENANT)
+ if(!candidates.len)
+ qdel(R)
+ message_admins("No candidates were found for the new revenant. Oh well!")
+ inert = 1
+ visible_message("[src] settles down and seems lifeless.")
+ 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("[src] settles down and seems lifeless.")
+ return 0
var/datum/mind/player_mind = new /datum/mind(key_of_revenant)
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 made into a revenant by reforming ectoplasm.")
- log_game("[key_of_revenant] was spawned as a revenant by reforming ectoplasm.")
+ 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("[src] suddenly rises into the air before fading away.")
+ qdel(src)
+ if(src) //Should never happen, but just in case
+ inert = 1
return 1
diff --git a/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm b/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm
index 016b8171113..632078194a3 100644
--- a/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm
+++ b/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm
@@ -1,18 +1,4 @@
-//Harvest Essence: The bread and butter of the revenant. The basic way of harvesting additional essence.
-/obj/effect/proc_holder/spell/targeted/revenant_harvest
- name = "Harvest"
- desc = "Siphons the lingering spectral essence from a human, empowering yourself."
- panel = "Revenant Abilities"
- charge_max = 0 //Short cooldown
- clothes_req = 0
- range = 1
-
-/obj/effect/proc_holder/spell/targeted/revenant_harvest/cast(list/targets, var/mob/living/simple_animal/revenant/user = usr)
- for(var/mob/living/carbon/human/target in targets)
- spawn(0)
- user.Harvest(target)
-
-//Transmit: the revemant's only direct way to communicate. Sends a single message silently to a single mob for 5E.
+//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."
@@ -21,155 +7,184 @@
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, var/mob/living/simple_animal/revenant/user = usr)
+/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("Revenant Transmit: [key_name(usr)]->[key_name(M)]: [msg]")
- usr << "You transmit to [M]: [msg]"
- M << "A strange voice resonates in your head... [msg]"
- for(var/mob/dead/observer/G in player_list)
- G.show_message("Revenant message from [usr] ([ghost_follow_link(usr, ghost=G)]) to [M] ([ghost_follow_link(M, ghost=G)]): [msg]")
+ usr << "You transmit to [M]: [msg]"
+ M << "An alien voice resonates from all around... [msg]"
+/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(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(locked)
+ if(!user.castcheck(-unlock_amount))
+ charge_counter = charge_max
+ return 0
+ name = "[initial(name)] ([cast_amount]E)"
+ user << "You have unlocked [initial(name)]!"
+ 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)
+ user.update_action_buttons()
+ 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_light
- name = "Overload Light (30E)"
+/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."
- panel = "Revenant Abilities (Locked)"
charge_max = 200
- clothes_req = 0
- range = 1
- var/reveal = 80
- var/stun = 20
- var/locked = 1
+ range = 5
+ stun = 30
+ cast_amount = 45
+ var/shock_range = 2
+ var/shock_damage = 18
+ action_icon_state = "overload_lights"
-/obj/effect/proc_holder/spell/aoe_turf/revenant_light/cast(list/targets, var/mob/living/simple_animal/revenant/user = usr)
- if(locked)
- if(!user.castcheck(-30))
- charge_counter = charge_max
- return
- user << "You have unlocked Overload Lights!"
- name = "Overload Lights (20E)"
- panel = "Revenant Abilities"
- locked = 0
- range = 6
- charge_counter = charge_max
- return
- if(!user.castcheck(-20))
- charge_counter = charge_max
- return
- 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("\The [L] suddenly flares brightly and begins to spark!")
- sleep(10)
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(4, 1, L)
- s.start()
- sleep(10)
- for(var/mob/living/M in orange(4, L))
- if(M == user)
+/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
- M.Beam(L,icon_state="lightning",icon='icons/effects/effects.dmi',time=5)
- M.electrocute_act(25, "[L.name]")
- var/datum/effect/effect/system/spark_spread/z = new /datum/effect/effect/system/spark_spread
- z.set_up(4, 1, M)
- z.start()
- playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
- user.reveal(reveal)
- user.stun(stun)
+ L.visible_message("\The [L] suddenly flares brightly and begins to spark!")
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread/
+ s.set_up(4, 0, L)
+ s.start()
+ new/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)
+ return
+ M.Beam(L,icon_state="purple_lightning",icon='icons/effects/effects.dmi',time=5)
+ M.electrocute_act(shock_damage, "[L.name]")
+ var/datum/effect/effect/system/spark_spread/z = new /datum/effect/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 (35E)"
- desc = "Twists and corrupts the nearby area. Also dispels holy auras on floors, but not salt lines."
- panel = "Revenant Abilities (Locked)"
- charge_max = 200
- clothes_req = 0
- range = 1
- var/reveal = 100
- var/stun = 20
- var/locked = 1
-
-/obj/effect/proc_holder/spell/aoe_turf/revenant_defile/cast(list/targets, var/mob/living/simple_animal/revenant/user = usr)
- if(locked)
- if(!user.castcheck(-35))
- charge_counter = charge_max
- return
- user << "You have unlocked Defile!"
- name = "Defile (20E)"
- panel = "Revenant Abilities"
- locked = 0
- range = 3
- charge_counter = charge_max
- return
- if(!user.castcheck(-20))
- charge_counter = charge_max
- return
- for(var/turf/T in targets)
- spawn(0)
- if(T.flags & NOJAUNT)
- T.flags -= NOJAUNT
- if(!istype(T, /turf/simulated/wall/cult) && istype(T, /turf/simulated/wall) && prob(40))
- T.ChangeTurf(/turf/simulated/wall/cult)
- if(!istype(T, /turf/simulated/floor/engine/cult) && istype(T, /turf/simulated/floor) && prob(40))
- T.ChangeTurf(/turf/simulated/floor/engine/cult)
- for(var/mob/living/carbon/human/human in T.contents)
- human << "You suddenly feel tired."
- human.adjustStaminaLoss(35)
- for(var/obj/structure/window/window in T.contents)
- window.hit(rand(50,125))
- for(var/obj/machinery/light/light in T.contents)
- light.flicker() //spooky
- user.reveal(reveal)
- user.stun(stun)
-
-//Malfunction: Makes bad stuff happen to robots and machines.
-/obj/effect/proc_holder/spell/aoe_turf/revenant_malf
- name = "Malfunction (50E)"
- desc = "Corrupts and damages nearby machines and mechanical objects."
- panel = "Revenant Abilities (Locked)"
+/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
- clothes_req = 0
- range = 1
- var/reveal = 60
- var/stun = 30
- var/locked = 1
+ range = 3
+ unlock_amount = 75
+ cast_amount = 40
+ action_icon_state = "defile"
+ var/stamdamage= 25
+ var/toxdamage = 5
+ var/confusion = 50
-/obj/effect/proc_holder/spell/aoe_turf/revenant_malf/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
- if(locked)
- if(!user.castcheck(-50))
- charge_counter = charge_max
- return
- user << "You have unlocked Malfunction!"
- name = "Malfunction (15E)"
- panel = "Revenant Abilities"
- locked = 0
- range = 4
- charge_counter = charge_max
- return
- if(!user.castcheck(-15))
- charge_counter = charge_max
- return
- for(var/turf/T in targets)
- spawn(0)
- for(var/obj/machinery/bot/bot in T.contents)
- if(!bot.emagged)
- bot.locked = 0
- bot.open = 1
- bot.Emag(null)
- for(var/obj/machinery/mach in T.contents)
- if(prob(10))
- mach.emag_act(null)
-
- empulse(user.loc, 3, 5)
- user.reveal(reveal)
- user.stun(stun)
+/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
+ new/obj/effect/overlay/temp/revenant(T)
+ for(var/mob/living/carbon/human/human in T.contents)
+ human << "You suddenly feel [pick("sick and tired", "tired and confused", "nauseated", "dizzy")]."
+ human.adjustStaminaLoss(stamdamage)
+ human.adjustToxLoss(toxdamage)
+ human.confused += confusion
+ new/obj/effect/overlay/temp/revenant(human.loc)
+ if(!istype(T, /turf/simulated/shuttle) && !istype(T, /turf/simulated/wall/rust) && !istype(T, /turf/simulated/wall/r_wall) && istype(T, /turf/simulated/wall) && prob(15))
+ new/obj/effect/overlay/temp/revenant(T)
+ T.ChangeTurf(/turf/simulated/wall/rust)
+ if(!istype(T, /turf/simulated/wall/r_wall/rust) && istype(T, /turf/simulated/wall/r_wall) && prob(15))
+ new/obj/effect/overlay/temp/revenant(T)
+ T.ChangeTurf(/turf/simulated/wall/r_wall/rust)
+ for(var/obj/structure/window/window in T.contents)
+ window.hit(rand(50,90))
+ if(window && window.is_fulltile())
+ new/obj/effect/overlay/temp/revenant/cracks(window.loc)
+ for(var/obj/machinery/light/light in T.contents)
+ light.flicker(30) //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
+ 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/obj/machinery/bot/bot in T.contents)
+ if(!bot.emagged)
+ new/obj/effect/overlay/temp/revenant(bot.loc)
+ bot.locked = 0
+ bot.open = 1
+ bot.Emag(null)
+ for(var/mob/living/carbon/human/human in T.contents)
+ human << "You feel [pick("your sense of direction flicker out", "a stabbing pain in your head", "your mind fill with static")]."
+ new/obj/effect/overlay/temp/revenant(human.loc)
+ human.emp_act(1)
+ for(var/obj/thing in T.contents)
+ if(istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes) || istype(thing, /obj/machinery/bot)) //Doesn't work on dominators, SMES and APCs, to prevent kekkery
+ continue
+ if(prob(20))
+ if(prob(50))
+ new/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)
+ new/obj/effect/overlay/temp/revenant(S.loc)
+ S.spark_system.start()
+ S.emp_act(1)
\ No newline at end of file
diff --git a/code/stylesheet.dm b/code/stylesheet.dm
index dbfc30ca3b5..caa1f6950af 100644
--- a/code/stylesheet.dm
+++ b/code/stylesheet.dm
@@ -105,6 +105,10 @@ h1.alert, h2.alert {color: #000000;}
.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;}
.memo {color: #638500; text-align: center;}
.memoedit {text-align: center; font-size: 2;}
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 9648275ce43..0557b16cdf3 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi
index ca86e3b6814..8b1add2756b 100644
Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ
diff --git a/icons/obj/lighting.dmi b/icons/obj/lighting.dmi
index 3beee849e02..779903709c9 100644
Binary files a/icons/obj/lighting.dmi and b/icons/obj/lighting.dmi differ