/datum/abilityHolder/wraith
topBarRendered = 1
pointName = "Wraith Points"
cast_while_dead = 1
var/corpsecount = 0
/obj/screen/ability/topBar/wraith
tens_offset_x = 19
tens_offset_y = 7
secs_offset_x = 23
secs_offset_y = 7
MouseEntered(location, control, params)
if (usr.client.tooltipHolder && control == "mapwindow.map")
if (!istype(owner, /datum/targetable/wraithAbility/poltergeist))
var/theme = src.owner.theme
usr.client.tooltipHolder.showHover(src, list(
"params" = params,
"title" = src.name,
"content" = (src.desc ? src.desc : null),
"theme" = theme
))
/datum/targetable/wraithAbility
icon = 'icons/mob/wraith_ui.dmi'
icon_state = "template"
cooldown = 0
last_cast = 0
targeted = 1
target_anything = 1
preferred_holder_type = /datum/abilityHolder/wraith
theme = "wraith"
New()
var/obj/screen/ability/topBar/wraith/B = new /obj/screen/ability/topBar/wraith(null)
B.icon = src.icon
B.icon_state = src.icon_state
B.owner = src
B.name = src.name
B.desc = src.desc
src.object = B
cast(atom/target)
if (!holder || !holder.owner)
return 1
//if (!iswraith(holder.owner))
// boutput(holder.owner, "Yo, you're not a wraith, stop that. (like how the hell did you get this. report this to a coder asap)")
// return 1
return 0
doCooldown()
if (!holder)
return
last_cast = world.time + cooldown
holder.updateButtons()
SPAWN_DBG(cooldown + 5)
holder.updateButtons()
/datum/targetable/wraithAbility/help
name = "Toggle Help Mode"
desc = "Enter or exit help mode."
icon_state = "help0"
targeted = 0
cooldown = 0
helpable = 0
special_screen_loc = "SOUTH,EAST"
cast(atom/target)
if (..())
return 1
if (holder.help_mode)
holder.help_mode = 0
else
holder.help_mode = 1
boutput(holder.owner, "Help Mode has been activated To disable it, click on this button again.")
boutput(holder.owner, "Hold down Shift, Ctrl or Alt while clicking the button to set it to that key.")
boutput(holder.owner, "You will then be able to use it freely by holding that button and left-clicking a tile.")
boutput(holder.owner, "Alternatively, you can click with your middle mouse button to use the ability on your current tile.")
src.object.icon_state = "help[holder.help_mode]"
holder.updateButtons()
/datum/targetable/wraithAbility/absorbCorpse
name = "Absorb Corpse"
icon_state = "absorbcorpse"
desc = "Steal life essence from a corpse. You cannot use this on a skeleton!"
targeted = 1
target_anything = 1
pointCost = 20
cooldown = 450 //Starts at 45 seconds and scales upward exponentially
cast(atom/T)
if (..())
return 1
if (!T)
T = get_turf(holder.owner)
//Find a suitable corpse
var/error = 0
var/mob/living/carbon/human/M
if (isturf(T))
for (var/mob/living/carbon/human/target in T.contents)
if (isdead(target))
error = 1
if (target:decomp_stage != 4)
M = target
break
else if (ishuman(T))
M = T
if (!isdead(M))
boutput(holder.owner, "The living consciousness controlling this body shields it from being absorbed.")
return 1
else if (M.decomp_stage == 4)
M = null
error = 1
else
M = T
else
boutput(holder.owner, "Absorbing [src] does not satisfy your ethereal taste.")
return 1
if (!M && !error)
boutput(holder.owner, "There are no usable corpses here!")
return 1
if (!M && error)
boutput(holder.owner, "[pick("This body is too decrepit to be of any use.", "This corpse has already been run through the wringer.", "There's nothing useful left.", "This corpse is worthless now.")]")
return 1
logTheThing("combat", usr, null, "absorbs the corpse of [key_name(M)] as a wraith.")
//Make the corpse all grody and skeleton-y
M.decomp_stage = 4
if (M.organHolder && M.organHolder.brain)
qdel(M.organHolder.brain)
M.set_face_icon_dirty()
M.set_body_icon_dirty()
particleMaster.SpawnSystem(new /datum/particleSystem/localSmoke("#000000", 5, locate(M.x, M.y, M.z)))
holder.regenRate *= 2.0
holder.owner:onAbsorb(M)
//Messages for everyone!
boutput(holder.owner, "[pick("You draw the essence of death out of [M]'s corpse!", "You drain the last scraps of life out of [M]'s corpse!")]")
for (var/mob/living/V in viewers(7, holder.owner))
boutput(V, "[pick("Black smoke rises from [M]'s corpse! Freaky!", "[M]'s corpse suddenly rots to nothing but bone in moments!")]")
return 0
doCooldown() //This makes it so wraith early game is much faster but hits a wall of high absorb cooldowns after ~5 corpses
if (!holder) //so wraiths don't hit scientific notation rates of regen without playing perfectly for a million years
return
var/datum/abilityHolder/wraith/W = holder
if (istype(W))
if (W.corpsecount == 0)
cooldown = 450
W.corpsecount += 1
else
cooldown += W.corpsecount * 150
W.corpsecount += 1
last_cast = world.time + cooldown
holder.updateButtons()
SPAWN_DBG(cooldown + 5)
holder.updateButtons()
/datum/targetable/wraithAbility/possessObject
name = "Possess Object"
icon_state = "possessobject"
desc = "Possess and control an everyday object. Freakout level: high."
targeted = 1
target_anything = 1
pointCost = 300
cooldown = 1500 //Tweaked this down from 3 minutes to 2 1/2, let's see if that ruins anything
cast(atom/T)
if (..())
return 1
if (src.holder.owner.density)
boutput(usr, "You cannot force your consciousness into a body while corporeal.")
return 1
if (!isitem(T) || istype(T, /obj/item/storage/bible))
boutput(holder.owner, "You cannot possess this!")
return 1
boutput(holder.owner, "[pick("You extend your will into [T].", "You force [T] to do your bidding.")]")
var/mob/living/object/O = new/mob/living/object(T, holder.owner)
SPAWN_DBG (450)
if (O)
boutput(O, "You feel your control of this vessel slipping away!")
SPAWN_DBG (600) //time limit on possession: 1 minute
if (O)
boutput(O, "Your control is wrested away! The item is no longer yours.")
O.death(0)
return 0
/datum/targetable/wraithAbility/makeRevenant
name = "Raise Revenant"
icon_state = "revenant"
desc = "Take control of an intact corpse as a powerful Revenant! You will not be able to absorb this corpse later. As a revenant, you gain increased point generation, but your revenant abilities cost much more points than normal."
targeted = 1
target_anything = 1
pointCost = 1000
cooldown = 5000 //5 minutes
cast(atom/T)
if (..())
return 1
if (src.holder.owner.density)
boutput(usr, "You cannot force your consciousness into a body while corporeal.")
return 1
//If you targeted a turf for some reason, find a corpse on it
if (istype(T, /turf))
for (var/mob/living/carbon/human/target in T.contents)
if (isdead(target) && target:decomp_stage != 4)
T = target
break
if (ishuman(T))
var/mob/wraith/W = holder.owner
return W.makeRevenant(T)
//return 0
else
boutput(usr, "There are no corpses here to possess!")
return 1
/datum/targetable/wraithAbility/decay
name = "Decay"
icon_state = "decay"
desc = "Cause a human to lose stamina, or an object to malfunction."
targeted = 1
target_anything = 1
pointCost = 30
cooldown = 600 //1 minute
cast(atom/T)
if (..())
return 1
//If you targeted a turf for some reason, find a valid target on it
var/atom/target = null
if (istype(T, /turf))
for (var/mob/living/carbon/human/M in T.contents)
if (!isdead(M))
target = M
break
if (!target)
for (var/obj/O in T.contents)
target = O //todo: emaggable check
break
else
target = T
if (ishuman(T))
var/mob/living/carbon/H = T
if (H.traitHolder.hasTrait("training_chaplain"))
boutput(usr, "Some mysterious force protects [T] from your influence.")
return 1
else
boutput(usr, "[pick("You sap [T]'s energy.", "You suck the breath out of [T].")]")
boutput(T, "You feel really tired all of a sudden!")
H.emote("pale")
H.remove_stamina( rand(100, 120) )//might be nice if decay was useful.
H.changeStatus("stunned", 4 SECONDS)
return 0
else if (isobj(T))
var/obj/O = T
if(istype(O, /obj/machinery/computer/shuttle/embedded))
boutput(usr, "You cannot seem to alter the energy off [O]." )
return 0
// go to jail, do not pass src, do not collect pushed messages
if (O.emag_act(null, null))
boutput(usr, "You alter the energy of [O].")
return 0
else
boutput(usr, "You fail to alter the energy of the [O].")
return 1
else
boutput(usr, "There is nothing to decay here!")
return 1
/datum/targetable/wraithAbility/command
name = "Command"
icon_state = "command"
desc = "Command a few objects to hurl themselves at the target location."
targeted = 1
target_anything = 1
pointCost = 50
cooldown = 200 // 20 seconds
cast(atom/T)
var/list/thrown = list()
var/current_prob = 100
if (ishuman(T))
var/mob/living/carbon/H = T
if (H.traitHolder.hasTrait("training_chaplain"))
boutput(usr, "Some mysterious force protects [T] from your influence.")
return 1
else
H.setStatus("stunned", max(H.getStatusDuration("weakened"), max(H.getStatusDuration("stunned"), 3))) // change status "stunned" to max(stunned,weakened,3)
// T:stunned = max(max(T:weakened, T:stunned), 3)
H.delStatus("weakened")
H.lying = 0
H.show_message("A ghostly force compels you to be still on your feet.")
for (var/obj/O in view(7, holder.owner))
if (!O.anchored && isturf(O.loc))
if (prob(current_prob))
current_prob *= 0.35 // very steep. probably grabs 3 or 4 objects per cast -- much less effective than revenant command
thrown += O
animate_float(O)
SPAWN_DBG(1 SECOND)
for (var/obj/O in thrown)
O.throw_at(T, 32, 2)
return 0
/datum/targetable/wraithAbility/raiseSkeleton
name = "Raise Skeleton"
icon_state = "skeleton"
desc = "Raise a skeletonized dead body as an indurable skeletal servant."
targeted = 1
target_anything = 1
pointCost = 150
cooldown = 600 // 1 minute
cast(atom/T)
if (..())
return 1
//If you targeted a turf for some reason, find a corpse on it
if (istype(T, /turf))
for (var/mob/living/carbon/human/target in T.contents)
if (isdead(target) && target:decomp_stage == 4)
T = target
break
if (ishuman(T))
var/mob/living/carbon/human/H = T
if (!isdead(H) || H.decomp_stage != 4)
boutput(usr, "That body refuses to submit its skeleton to your will.")
return 1
var/personname = H.real_name
var/obj/critter/wraithskeleton/S = new /obj/critter/wraithskeleton(get_turf(T))
S.name = "[personname]'s skeleton"
S.health = 1
H.gib()
return 0
else
boutput(usr, "There are no skeletonized corpses here to raise!")
return 1
/datum/targetable/wraithAbility/animateObject
name = "Animate Object"
icon_state = "animobject"
desc = "Animate an inanimate object to attack nearby humans."
targeted = 1
target_anything = 1
pointCost = 100
cooldown = 300 //30 seconds
cast(atom/T)
if (..())
return 1
var/obj/O = T
//If you targeted a turf for some reason, find an object on it
if (istype(T, /turf))
for (var/obj/target in T.contents)
if (istype(target, /obj/critter) || istype(target, /obj/machinery/bot) || istype(target, /obj/decal) || target.anchored || target.invisibility)
continue
O = target
break
if (istype(O))
if(istype(O, /obj/critter) || istype(O, /obj/machinery/bot) || istype(O, /obj/decal) || O.anchored || O.invisibility)
boutput(usr, "That is not a valid target for animation!")
return 1
O.visible_message("The [O] comes to life!")
var/obj/critter/livingobj/L = new/obj/critter/livingobj(O.loc)
O.loc = L
L.name = "Living [O.name]"
L.desc = "[O.desc]. It appears to be alive!"
L.overlays += O
L.health = rand(10, 50)
L.atk_brute_amt = rand(5, 20)
L.defensive = 1
L.aggressive = 1
L.atkcarbon = 1
L.atksilicon = 1
L.opensdoors = 1
L.stunprob = 15
L.original_object = O
animate_levitate(L, -1, 30)
return 0
else
boutput(usr, "There is no object here to animate!")
return 1
/datum/targetable/wraithAbility/haunt
name = "Haunt"
icon_state = "haunt"
desc = "Become corporeal for 30 seconds. During this time, you gain additional biopoints, depending on the amount of humans in your vicinity. You cannot use this ability while already corporeal."
targeted = 0
pointCost = 0
cooldown = 600 //1 minute
cast()
if (..())
return 1
var/mob/wraith/W = src.holder.owner
return W.haunt()
/obj/poltergeistMarker
name = "Spooky Marker"
desc = "What is this? You feel like you shouldn't be able to see it."
icon = 'icons/effects/particles.dmi'
icon_state = "32x32circle"
color = "#222222"
// invisibility = 101
invisibility = 16
anchored = 1
density = 0
opacity = 0
mouse_opacity = 0
alpha = 100
New()
..()
var/matrix/M = matrix()
M.Scale(0.5,0.5)
animate(src, transform = M, time = 3 SECONDS, loop = -1,easing = ELASTIC_EASING)
/datum/targetable/wraithAbility/poltergeist
name = "Poltergeist - Mark Location"
icon_state = "poltergeist"
desc = "Cause freaky, weird, creepy or spooky stuff to happen in an area around you. Use this ability to mark your current tile as the origin of these events, then activate it by using this ability again."
targeted = 0
pointCost = 0
cooldown = 200
special_screen_loc="NORTH,EAST"
var/datum/radio_frequency/pda_connection
var/obj/poltergeistMarker/marker = new /obj/poltergeistMarker() //removed for now
var/status = 0
var/static/list/effects = list("Flip light switches" = 1, "Burn out lights" = 2, "Create smoke" = 3, "Create ectoplasm" = 4, "Sap APC" = 5, "Haunt PDAs" = 6, "Open doors, lockers, crates" = 7, "Random" = 8)
var/list/effects_buttons = list()
New()
..()
pda_connection = radio_controller.return_frequency("1149")
object.contextLayout = new /datum/contextLayout/screen_HUD_default(2, 16, 16)//, -32, -32)
if (!object.contextActions)
object.contextActions = list()
for(var/i=1, i<=8, i++)
var/datum/contextAction/wraith_poltergeist_button/newcontext = new /datum/contextAction/wraith_poltergeist_button(i)
object.contextActions += newcontext
disposing()
radio_controller.remove_object(src,"1149")
..()
proc/haunt_pda(var/obj/item/device/pda2/pda)
if (!pda_connection)
return
var/message = pick("boo", "git spooked", "BOOM", "there's a skeleton inside of you", "DEHUMANIZE YOURSELF AND FACE TO BLOODSHED", "ICARUS HAS FOUND YOU!!!!! RUN WHILE YOU CAN!!!!!!!!!!!")
var/datum/signal/signal = get_free_signal()
signal.source = src.holder.owner
signal.transmission_method = TRANSMISSION_RADIO
signal.data["command"] = "text_message"
signal.data["sender_name"] = holder.owner.name
signal.data["message"] = "[message]" // (?)
signal.data["sender"] = "00000000" // surely this isn't going to be a problem
signal.data["address_1"] = pda.net_id
pda_connection.post_signal(src, signal)
cast()
if (..())
return 1
proc/do_poltergeist_ability(var/effect as text)
if (effect == 8)
effect = rand(1, 7)
switch (effect)
if (1)
boutput(holder.owner, "You flip some light switches near the designated location!!")
for (var/obj/machinery/light_switch/L in range(10, holder.owner))
L.attack_hand(holder.owner)
return 0
if (2)
boutput(holder.owner, "You cause a few lights to burn out near the designated location!.")
var/c_prob = 100
for (var/obj/machinery/light/L in range(10, holder.owner))
if (L.status == 2 || L.status == 1)
continue
if (prob(c_prob))
L.broken()
c_prob *= 0.5
return 0
if (3)
boutput(holder.owner, "Smoke rises in the designated location.")
var/turf/trgloc = get_turf(holder.owner)
var/list/affected = block(locate(trgloc.x - 3,trgloc.y - 3,trgloc.z), locate(trgloc.x + 3,trgloc.y + 3,trgloc.z))
if(!affected.len) return
var/list/centerview = view(4, trgloc)
for(var/atom/A in affected)
if(!(A in centerview)) continue
//if (A == holder.owner) continue
var/obj/smokeDummy/D = new(A)
SPAWN_DBG(15 SECONDS)
qdel(D)
particleMaster.SpawnSystem(new/datum/particleSystem/areaSmoke("#ffffff", 30, trgloc))
return 0
if (4)
boutput(holder.owner, "Matter from your realm appears near the designated location!")
var/count = rand(5,9)
var/turf/trgloc = get_turf(holder.owner)
var/list/affected = block(locate(trgloc.x - 8,trgloc.y - 8,trgloc.z), locate(trgloc.x + 8,trgloc.y + 8,trgloc.z))
for (var/i = 0, i < count, i++)
new/obj/item/reagent_containers/food/snacks/ectoplasm(pick(affected))
return 0
if (5)
var/sapped_amt = src.holder.regenRate * 100
var/obj/machinery/power/apc/apc = locate() in get_area(holder.owner)
if (!apc)
boutput(holder.owner, "Power sap failed: local APC not found.")
return 0
boutput(holder.owner, "You sap the power of the chamber's power source.")
var/obj/item/cell/cell = apc.cell
if (cell)
cell.use(sapped_amt)
return 0
if (6)
boutput(holder.owner, "Mysterious messages haunt PDAs near the designated location!")
for (var/mob/living/L in range(10, holder.owner))
var/obj/item/device/pda2/pda = locate() in L
if (pda)
src.haunt_pda(pda)
for (var/obj/item/device/pda2/pda in range(10, holder.owner))
src.haunt_pda(pda)
if (7)
boutput(holder.owner, "Crates, lockers and doors mysteriously open and close in the designated area!")
var/c_prob = 100
for(var/obj/machinery/door/G in range(10, holder.owner))
if (prob(c_prob))
c_prob *= 0.4
SPAWN_DBG(1 DECI SECOND)
if (G.density)
G.open()
else
G.close()
c_prob = 100
for(var/obj/storage/F in range(10, holder.owner))
if (prob(c_prob))
c_prob *= 0.4
SPAWN_DBG(1 DECI SECOND)
if (F.open)
F.close()
else
F.open()
return 0
afterCast()
if (status == 0)
name = "Poltergeist - Cast"
pointCost = 0
cooldown = 300
status = 1
icon_state = "poltergeist1"
else
name = "Poltergeist - Mark Location"
pointCost = 20
cooldown = 0
status = 0
icon_state = "poltergeist"
// holder.owner.contents += marker
/datum/targetable/wraithAbility/whisper
name = "Whisper"
icon_state = "whisper"
desc = "Send an ethereal message to a living being."
targeted = 1
target_anything = 1
pointCost = 1
cooldown = 2 SECONDS
proc/ghostify_message(var/message)
return message
cast(atom/target)
if (..())
return 1
if (ishuman(target))
var/mob/living/carbon/human/H = target
if (isdead(H))
boutput(usr, "They can hear you just fine without the use of your abilities.")
return 1
else
var/message = html_encode(input("What would you like to whisper to [target]?", "Whisper", "") as text)
logTheThing("say", usr, target, "WRAITH WHISPER TO %target%: [message]")
message = ghostify_message(trim(copytext(sanitize(message), 1, 255)))
boutput(usr, "You whisper to [target]: [message]")
boutput(target, "A netherworldly voice whispers into your ears... [message]")
else
boutput(usr, "It would be futile to attempt to force your voice to the consciousness of that.")
return 1
//this is the spooky_writing ability from spooktober ghosts
/datum/targetable/wraithAbility/blood_writing
name = "Blood Writing"
desc = "Write a spooky character on the ground."
icon_state = "bloodwriting"
targeted = 1
target_anything = 1
pointCost = 10
cooldown = 5 SECONDS
var/in_use = 0
// cast(turf/target, params)
cast(atom/target, params)
if (..())
return 1
var/turf/T = get_turf(target)
if (isturf(T))
write_on_turf(T, holder.owner, params)
proc/write_on_turf(var/turf/T as turf, var/mob/user as mob, params)
if (!T || !user || src.in_use)
return
src.in_use = 1
var/list/c_default = list("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Exclamation Point", "Question Mark", "Period", "Comma", "Colon", "Semicolon", "Ampersand", "Left Parenthesis", "Right Parenthesis",
"Left Bracket", "Right Bracket", "Percent", "Plus", "Minus", "Times", "Divided", "Equals", "Less Than", "Greater Than")
var/list/c_symbol = list("Dollar", "Euro", "Arrow North", "Arrow East", "Arrow South", "Arrow West",
"Square", "Circle", "Triangle", "Heart", "Star", "Smile", "Frown", "Neutral Face", "Bee", "Pentagram")
var/t = input(user, "What do you want to write?", null, null) as null|anything in (c_default + c_symbol)
if (!t)
src.in_use = 0
return 1
var/obj/decal/cleanable/writing/spooky/G = make_cleanable(/obj/decal/cleanable/writing/spooky,T)
G.artist = user.key
logTheThing("station", user, null, "writes on [T] with [src] [log_loc(T)]: [t]")
G.icon_state = t
G.words = t
if (islist(params) && params["icon-y"] && params["icon-x"])
// playsound(src.loc, "sound/impact_sounds/Slimy_Splat_1.ogg", 50, 1)
G.pixel_x = text2num(params["icon-x"]) - 16
G.pixel_y = text2num(params["icon-y"]) - 16
else
G.pixel_x = rand(-4,4)
G.pixel_y = rand(-4,4)
src.in_use = 0