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