mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-11 23:23:28 +01:00
Revenant
This commit is contained in:
@@ -134,7 +134,8 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Vermin Infestation",/datum/event/infestation, 100, list(ASSIGNMENT_JANITOR = 100)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Wallrot", /datum/event/wallrot, 0, list(ASSIGNMENT_ENGINEER = 30, ASSIGNMENT_GARDENER = 50)),
|
||||
// NON-BAY EVENTS
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Cargo Bonus", /datum/event/cargo_bonus, 100)
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Cargo Bonus", /datum/event/cargo_bonus, 100),
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Revenant", /datum/event/revenant, 50)
|
||||
)
|
||||
|
||||
/datum/event_container/moderate
|
||||
|
||||
@@ -50,6 +50,7 @@ var/global/list/possibleEvents = list()
|
||||
//possibleEvents[/datum/event/mundane_news] = 300
|
||||
|
||||
possibleEvents[/datum/event/cargo_bonus] = 150
|
||||
possibleEvents[/datum/event/revenant] = 75
|
||||
|
||||
possibleEvents[/datum/event/pda_spam] = max(min(25, player_list.len) * 4, 200)
|
||||
possibleEvents[/datum/event/money_lotto] = max(min(5, player_list.len), 50)
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
//Revenants: based off of wraiths from Goon
|
||||
//"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
|
||||
|
||||
/mob/living/simple_animal/revenant
|
||||
name = "revenant"
|
||||
desc = "A malevolent spirit."
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "revenant_idle"
|
||||
incorporeal_move = 1
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
health = 25
|
||||
maxHealth = 25
|
||||
see_in_dark = 255
|
||||
see_invisible = SEE_INVISIBLE_OBSERVER
|
||||
universal_understand = 1
|
||||
response_help = "passes through"
|
||||
response_disarm = "swings at"
|
||||
response_harm = "punches"
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
harm_intent_damage = 5
|
||||
speak_emote = list("hisses", "spits", "growls")
|
||||
friendly = "touches"
|
||||
status_flags = 0
|
||||
wander = 0
|
||||
density = 0
|
||||
|
||||
var/essence = 25 //The resource of revenants. Max health is equal to twice this amount
|
||||
var/essence_regen_cap = 25 //The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount.
|
||||
var/essence_regen = 1 //If the revenant regenerates essence or not; 1 for yes, 0 for no
|
||||
var/essence_min = 1 //The minimum amount of essence a revenant can have; by default, it never drops below one
|
||||
var/strikes = 3 //How many times a revenant can die before dying for good
|
||||
var/revealed = 0 //If the revenant can take damage from normal sources.
|
||||
var/inhibited = 0 //If the revenant's abilities are blocked by a chaplain's power.
|
||||
|
||||
/mob/living/simple_animal/revenant/Life()
|
||||
..()
|
||||
if(essence < essence_min)
|
||||
essence = essence_min
|
||||
if(strikes > 0)
|
||||
strikes--
|
||||
src << "<span class='boldannounce'>Your essence has dropped below critical levels. You barely manage to save yourself - [strikes ? "you can't keep this up!" : "next time, it's death."]</span>"
|
||||
else if(strikes <= 0)
|
||||
src << "<span class='userdanger'><b>NO! No... it's too late, you can feel yourself fading...</b></span>"
|
||||
src.notransform = 1
|
||||
src.revealed = 1
|
||||
src.invisibility = 0
|
||||
playsound(src, 'sound/effects/screech.ogg', 100, 1)
|
||||
src.visible_message("<b>The revenant</b> lets out a waning screech as violet mist swirls around its dissolving body!")
|
||||
src.icon_state = "revenant_draining"
|
||||
sleep(30)
|
||||
src.death()
|
||||
maxHealth = essence * 2
|
||||
if(!revealed)
|
||||
health = maxHealth //Heals to full when not revealed
|
||||
if(essence_regen && !inhibited && essence < essence_regen_cap) //While inhibited, essence will not regenerate
|
||||
essence++
|
||||
|
||||
/mob/living/simple_animal/revenant/Process_Spacemove(var/check_drift = 0)
|
||||
return 1 //Mainly to prevent the no-grav effect
|
||||
|
||||
/mob/living/simple_animal/revenant/ex_act(severity)
|
||||
return 1 //Immune to the effects of explosions.
|
||||
|
||||
/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)
|
||||
return
|
||||
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["middle"])
|
||||
MiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"])
|
||||
ShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["alt"])
|
||||
AltClickOn(A)
|
||||
return
|
||||
if(modifiers["ctrl"])
|
||||
CtrlClickOn(A)
|
||||
return
|
||||
|
||||
if(world.time <= next_move)
|
||||
return
|
||||
A.attack_ghost(src)
|
||||
|
||||
/mob/living/simple_animal/revenant/say(message)
|
||||
return 0 //Revenants cannot speak out loud.
|
||||
|
||||
/mob/living/simple_animal/revenant/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Current essence: [essence]E")
|
||||
|
||||
/mob/living/simple_animal/revenant/New()
|
||||
..()
|
||||
spawn(5)
|
||||
if(src.mind)
|
||||
src << 'sound/effects/ghost.ogg'
|
||||
src.store_memory("<span class='deadsay'>I am a revenant. My spectral form has been empowered. My only goal is to gather essence from the humans of [world.name].</span>")
|
||||
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 very limited interaction with both worlds.</b>"
|
||||
src << "<b>You are invincible and invisible to everyone but other ghosts. Some abilities may change this.</b>"
|
||||
src << "<b>Your goal is to gather essence from humans. Your essence passively regenerates up to 25E over time. You can use the Harvest abilities to gather more from corpses.</b>"
|
||||
src << "<b>Be sure to read the wiki page at https://tgstation13.org/wiki/Revenant !</b>"
|
||||
src << "<br>"
|
||||
if(!src.giveSpells())
|
||||
message_admins("Revenant was created but has no mind. Trying again in five seconds.")
|
||||
spawn(50)
|
||||
if(!src.giveSpells())
|
||||
message_admins("Revenant still has no mind. Deleting...")
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/giveSpells()
|
||||
if(src.mind)
|
||||
src.mind.spell_list += new /obj/effect/proc_holder/spell/wizard/targeted/revenant_harvest
|
||||
src.mind.spell_list += new /obj/effect/proc_holder/spell/wizard/targeted/revenant_transmit
|
||||
src.mind.spell_list += new /obj/effect/proc_holder/spell/wizard/aoe_turf/revenant_light
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/revenant/death()
|
||||
if(!strikes)
|
||||
return 0 //Impossible to die with strikes still active
|
||||
..(1)
|
||||
reveal(10, 1)
|
||||
visible_message("<span class='danger'>[src] pulses with an eldritch purple light as its form unwinds into smoke.</span>")
|
||||
ghostize()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/revenant/attackby(obj/item/W, mob/living/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/weapon/nullrod))
|
||||
src.visible_message("<b>The revenant</b> screeches and flails!", \
|
||||
"<span class='boldannounce'>The null rod invokes agony in you! You feel your essence draining away!</span>")
|
||||
src.essence -= 25 //hella effective
|
||||
src.inhibited = 1
|
||||
spawn(30)
|
||||
src.inhibited = 0
|
||||
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/proc/essence_check(var/essence_cost, var/silent = 0)
|
||||
var/mob/living/simple_animal/revenant/W = usr
|
||||
if(!istype(usr) || !usr)
|
||||
return
|
||||
if(W.essence < essence_cost)
|
||||
if(!silent)
|
||||
W << "<span class='warning'>You need [essence_cost]E to use [name] but you only have [W.essence]E available. Harvest some more things.</span>"
|
||||
return 0
|
||||
W.essence -= essence_cost
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/wallcheck()
|
||||
var/turf/T = get_turf(usr)
|
||||
if(!istype(T, /turf/simulated/wall))
|
||||
return 1
|
||||
usr << "<span class='warning'>You can't use abilities from a wall. What did you expect?</span>"
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/change_essence_amount(var/essence_amt, var/silent = 0, var/source = null)
|
||||
var/mob/living/simple_animal/revenant/user = usr
|
||||
if(!istype(usr) || !usr)
|
||||
return
|
||||
if(!essence_amt)
|
||||
return
|
||||
user.essence += essence_amt
|
||||
if(!silent)
|
||||
if(essence_amt >= 0)
|
||||
user << "<span class='info'>Gained [essence_amt]E from [source].</span>"
|
||||
else
|
||||
user << "<span class='info'>Lost [essence_amt]E from [source].</span>"
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/reveal(var/time, var/stun)
|
||||
var/mob/living/simple_animal/revenant/R = usr
|
||||
if(!istype(usr) || !usr)
|
||||
return
|
||||
R.revealed = 1
|
||||
R.invisibility = 0
|
||||
if(stun)
|
||||
R.notransform = 1
|
||||
spawn(time)
|
||||
R.revealed = 0
|
||||
R.invisibility = INVISIBILITY_OBSERVER
|
||||
if(stun)
|
||||
R.notransform = 0
|
||||
@@ -0,0 +1,167 @@
|
||||
//Harvest Essence: The bread and butter of the revenant. The basic way of harvesting additional essence.
|
||||
/obj/effect/proc_holder/spell/wizard/targeted/revenant_harvest
|
||||
name = "Harvest (0E)"
|
||||
desc = "Siphons the lingering spectral essence from a human, empowering yourself."
|
||||
panel = "Revenant Abilities"
|
||||
charge_max = 100 //Short cooldown
|
||||
clothes_req = 0
|
||||
range = 5
|
||||
var/essence_drained = 0
|
||||
var/draining
|
||||
var/list/drained_mobs = list() //Cannot harvest the same mob twice
|
||||
|
||||
/obj/effect/proc_holder/spell/wizard/targeted/revenant_harvest/cast(list/targets, var/mob/living/simple_animal/revenant/user = usr)
|
||||
if(user.inhibited)
|
||||
user << "<span class='warning'>Something is blocking the use of [src]!</span>"
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(!user.wallcheck())
|
||||
charge_counter = charge_max
|
||||
return
|
||||
for(var/mob/living/carbon/human/target in targets)
|
||||
spawn(0)
|
||||
if(draining)
|
||||
user << "<span class='warning'>You are already siphoning the essence of a soul!</span>"
|
||||
return
|
||||
if(target in drained_mobs)
|
||||
user << "<span class='warning'>[target]'s soul is dead and empty.</span>"
|
||||
return
|
||||
if(target.stat != DEAD)
|
||||
user << "<span class='notice'>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 = 1
|
||||
user << "<span class='notice'>You search for the still-living soul of [target].</span>"
|
||||
sleep(10)
|
||||
if(target.ckey)
|
||||
user << "<span class='notice'>Their soul burns with intelligence.</span>"
|
||||
essence_drained += 3
|
||||
sleep(20)
|
||||
switch(essence_drained)
|
||||
if(1 to 2)
|
||||
user << "<span class='info'>[target] will not yield much essence. Still, every bit counts.</span>"
|
||||
if(3 to 4)
|
||||
user << "<span class='info'>[target] will yield an average amount of essence.</span>"
|
||||
if(5 to INFINITY)
|
||||
user << "<span class='info'>Such a feast! [target] will yield much essence to you.</span>"
|
||||
sleep(30)
|
||||
if(!in_range(user, target))
|
||||
user << "<span class='warning'>You are not close enough to siphon [target]'s soul. The link has been broken.</span>"
|
||||
draining = 0
|
||||
return
|
||||
if(!target.stat)
|
||||
user << "<span class='warning'>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>"
|
||||
user << "<span class='danger'>You begin siphoning essence from [target]'s soul. You can not move while this is happening.</span>"
|
||||
if(target.stat != DEAD)
|
||||
target << "<span class='warning'>You feel a horribly unpleasant draining sensation as your grip on life weakens...</span>"
|
||||
user.icon_state = "revenant_draining"
|
||||
user.notransform = 1
|
||||
user.revealed = 1
|
||||
user.invisibility = 0
|
||||
target.visible_message("<span class='warning'>[target] suddenly rises slightly into the air, their skin turning an ashy gray.</span>")
|
||||
target.Beam(user,icon_state="drain_life",icon='icons/effects/effects.dmi',time=80)
|
||||
target.death(0)
|
||||
target.visible_message("<span class='warning'>[target] gently slumps back onto the ground.</span>")
|
||||
user.icon_state = "revenant_idle"
|
||||
user.change_essence_amount(essence_drained * 5, 0, target)
|
||||
user << "<span class='info'>[target]'s soul has been considerably weakened and will yield no more essence for the time being.</span>"
|
||||
user.revealed = 0
|
||||
user.notransform = 0
|
||||
user.invisibility = INVISIBILITY_OBSERVER
|
||||
drained_mobs.Add(target)
|
||||
draining = 0
|
||||
|
||||
|
||||
//Transmit: the revemant's only direct way to communicate. Sends a single message silently to a single mob for 5E.
|
||||
/obj/effect/proc_holder/spell/wizard/targeted/revenant_transmit
|
||||
name = "Transmit (5E)"
|
||||
desc = "Telepathically transmits a message to the target."
|
||||
panel = "Revenant Abilities (Locked)"
|
||||
charge_max = 50
|
||||
clothes_req = 0
|
||||
range = -1
|
||||
include_user = 1
|
||||
var/locked = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/wizard/targeted/revenant_transmit/cast(list/targets, var/mob/living/simple_animal/revenant/user = usr)
|
||||
if(user.inhibited)
|
||||
user << "<span class='warning'>Something is blocking the use of [src]!</span>"
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(locked && essence_check(5, 1))
|
||||
usr << "<span class='info'>You have unlocked Transmit!</span>"
|
||||
locked = 0
|
||||
charge_counter = charge_max
|
||||
panel = "Revenant Abilities"
|
||||
range = 7
|
||||
include_user = 0
|
||||
return
|
||||
if(locked)
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(!user.wallcheck())
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(!essence_check(5))
|
||||
charge_counter = charge_max
|
||||
return
|
||||
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
|
||||
usr << "<span class='info'><b>You transmit to [M]:</b> [msg]</span>"
|
||||
M << "<span class='deadsay'><b>A strange voice resonates in your head...</b></span><i> [msg]</I>"
|
||||
|
||||
|
||||
//Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people.
|
||||
/obj/effect/proc_holder/spell/wizard/aoe_turf/revenant_light
|
||||
name = "Overload Light (25E)"
|
||||
desc = "Directs a large amount of essence into an electrical light, causing an impressive light show."
|
||||
panel = "Revenant Abilities (Locked)"
|
||||
charge_max = 300
|
||||
clothes_req = 0
|
||||
range = 1
|
||||
var/locked = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/wizard/aoe_turf/revenant_light/cast(list/targets, var/mob/living/simple_animal/revenant/user = usr)
|
||||
if(user.inhibited)
|
||||
user << "<span class='warning'>Something is blocking the use of [src]!</span>"
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(locked && essence_check(25, 1))
|
||||
user << "<span class='info'>You have unlocked Overload Light!</span>"
|
||||
name = "Overload Light (25E)"
|
||||
panel = "Revenant Abilities"
|
||||
locked = 0
|
||||
range = 5
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(locked)
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(!user.wallcheck())
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(!essence_check(25))
|
||||
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("<span class='warning'><b>\The [L] suddenly flares brightly and begins to spark!</span>")
|
||||
sleep(20)
|
||||
for(var/mob/living/M in orange(4, L))
|
||||
if(M == user)
|
||||
return
|
||||
M.Beam(L,icon_state="lightning",icon='icons/effects/effects.dmi',time=5)
|
||||
M.electrocute_act(25, "[L.name]")
|
||||
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
|
||||
user.reveal(50, 1)
|
||||
@@ -0,0 +1,54 @@
|
||||
/datum/event/revenant
|
||||
var/key_of_revenant
|
||||
|
||||
|
||||
|
||||
/datum/event/revenant/proc/get_revenant(var/end_if_fail = 0)
|
||||
key_of_revenant = null
|
||||
if(!key_of_revenant)
|
||||
var/list/candidates = get_candidates(BE_REVENANT)
|
||||
if(!candidates.len)
|
||||
if(end_if_fail)
|
||||
return 0
|
||||
return find_revenant()
|
||||
var/client/C = pick(candidates)
|
||||
key_of_revenant = C.key
|
||||
if(!key_of_revenant)
|
||||
if(end_if_fail)
|
||||
return 0
|
||||
return find_revenant()
|
||||
var/datum/mind/player_mind = new /datum/mind(key_of_revenant)
|
||||
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("carpspawn")
|
||||
spawn_locs += L.loc
|
||||
if(!spawn_locs)
|
||||
return find_revenant()
|
||||
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("[key_of_revenant] has been made into a Revenant by an event.")
|
||||
log_game("[key_of_revenant] was spawned as a Revenant by an event.")
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
/datum/event/revenant/start()
|
||||
get_revenant()
|
||||
|
||||
|
||||
|
||||
/datum/event/revenant/proc/find_revenant()
|
||||
message_admins("Attempted to spawn a Revenant but there was no players available. Will try again momentarily, bear with me...")
|
||||
spawn(50)
|
||||
if(get_revenant(1))
|
||||
message_admins("Hooray! Situation has been resolved, [key_of_revenant] has been spawned as a Revenant.")
|
||||
log_game("[key_of_revenant] was spawned as a Revenant by an event.")
|
||||
return 0
|
||||
message_admins("Unfortunately, no candidates were available for becoming a Revenant. Shutting down. :(")
|
||||
return kill()
|
||||
Reference in New Issue
Block a user