mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-24 20:47:10 +01:00
Merge branch 'master' into Clinging-to-hope
This commit is contained in:
@@ -501,7 +501,7 @@
|
||||
log_game("Teleport spell failed - no other teleport runes")
|
||||
return
|
||||
if(!is_level_reachable(user.z))
|
||||
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
|
||||
to_chat(user, "<span class='cultitalic'>You are too far away from the station to teleport!</span>")
|
||||
log_game("Teleport spell failed - user in away mission")
|
||||
return
|
||||
|
||||
|
||||
@@ -139,6 +139,11 @@
|
||||
to_chat(user, "<span class='cultitalic'>The veil is not weak enough here to summon a cultist, you must be on station!</span>")
|
||||
return
|
||||
|
||||
if(ispath(rune, /obj/effect/rune/teleport))
|
||||
if(!is_level_reachable(user.z))
|
||||
to_chat(user, "<span class='cultitalic'>You are too far away from the station to teleport!</span>")
|
||||
return
|
||||
|
||||
var/old_color = user.color // we'll temporarily redden the user for better feedback to fellow cultists. Store this to revert them back.
|
||||
if(narsie_rune)
|
||||
if(!narsie_rune_check(user, A))
|
||||
|
||||
@@ -461,7 +461,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
return
|
||||
|
||||
if(!is_level_reachable(user.z))
|
||||
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
|
||||
to_chat(user, "<span class='cultitalic'>You are too far away from the station to teleport!</span>")
|
||||
log_game("Teleport rune failed - user in away mission")
|
||||
fail_invoke()
|
||||
return
|
||||
|
||||
@@ -786,3 +786,24 @@
|
||||
/datum/AI_Module/large/cameracrack/upgrade(mob/living/silicon/ai/AI)
|
||||
if(AI.builtInCamera)
|
||||
QDEL_NULL(AI.builtInCamera)
|
||||
|
||||
/datum/AI_Module/large/engi_upgrade
|
||||
module_name = "Engineering Cyborg Emitter Upgrade"
|
||||
mod_pick_name = "emitter"
|
||||
description = "Downloads firmware that activates the built in emitter in all engineering cyborgs linked to you. Cyborgs built after this upgrade will have it pre-installed."
|
||||
cost = 50 // IDK look into this
|
||||
one_purchase = TRUE
|
||||
upgrade = TRUE
|
||||
unlock_text = "<span class='notice'>Firmware downloaded. Bugs removed. Built in emitters operating at 73% efficiency.</span>"
|
||||
unlock_sound = 'sound/items/rped.ogg'
|
||||
|
||||
/datum/AI_Module/large/engi_upgrade/upgrade(mob/living/silicon/ai/AI)
|
||||
AI.purchased_modules += /obj/item/robot_module/engineering
|
||||
log_game("[key_name(usr)] purchased emitters for all engineering cyborgs.")
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] purchased emitters for all engineering cyborgs!</span>")
|
||||
for(var/mob/living/silicon/robot/R in AI.connected_robots)
|
||||
if(!istype(R.module, /obj/item/robot_module/engineering))
|
||||
continue
|
||||
R.module.malfhacked = TRUE
|
||||
R.module.rebuild_modules()
|
||||
to_chat(R, "<span class='notice'>New firmware downloaded. Emitter is now online.</span>")
|
||||
|
||||
@@ -736,7 +736,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
desc = "Contains secrets of the universe."
|
||||
icon_state = "abductor"
|
||||
icon_closed = "abductor"
|
||||
icon_opened = "abductoropen"
|
||||
icon_opened = "abductor_open"
|
||||
material_drop = /obj/item/stack/sheet/mineral/abductor
|
||||
|
||||
/obj/structure/door_assembly/door_assembly_abductor
|
||||
|
||||
@@ -42,19 +42,32 @@
|
||||
speed = 1
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
|
||||
var/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 = 5 //How much essence regenerates
|
||||
var/essence_accumulated = 0 //How much essence the revenant has stolen
|
||||
var/revealed = 0 //If the revenant can take damage from normal sources.
|
||||
var/unreveal_time = 0 //How long the revenant is revealed for, is about 2 seconds times this var.
|
||||
var/unstun_time = 0 //How long the revenant is stunned for, is about 2 seconds times this var.
|
||||
var/inhibited = 0 //If the revenant's abilities are blocked by a chaplain's power.
|
||||
var/essence_drained = 0 //How much essence the revenant 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.
|
||||
///The resource of revenants. Max health is equal to three times this amount
|
||||
var/essence = 75
|
||||
///The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount.
|
||||
var/essence_regen_cap = 75
|
||||
///If the revenant regenerates essence or not; 1 for yes, 0 for no
|
||||
var/essence_regenerating = TRUE
|
||||
///How much essence regenerates
|
||||
var/essence_regen_amount = 5
|
||||
///How much essence the revenant has stolen
|
||||
var/essence_accumulated = 0
|
||||
///If the revenant can take damage from normal sources.
|
||||
var/revealed = FALSE
|
||||
///How long the revenant is revealed for, is about 2 seconds times this var.
|
||||
var/unreveal_time = 0
|
||||
///How long the revenant is stunned for, is about 2 seconds times this var.
|
||||
var/unstun_time = 0
|
||||
///If the revenant's abilities are blocked by a chaplain's power.
|
||||
var/inhibited = FALSE
|
||||
///How much essence the revenant has drained.
|
||||
var/essence_drained = 0
|
||||
///If the revenant is draining someone.
|
||||
var/draining = FALSE
|
||||
/// contains a list of UIDs of mobs who have been drained. cannot drain the same mob twice.
|
||||
var/list/drained_mobs = list()
|
||||
///How many perfect, regen-cap increasing souls the revenant has.
|
||||
var/perfectsouls = 0
|
||||
|
||||
|
||||
/mob/living/simple_animal/revenant/Life(seconds, times_fired)
|
||||
@@ -232,25 +245,21 @@
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/castcheck(essence_cost)
|
||||
if(!src)
|
||||
return
|
||||
if(holy_check(src))
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if(istype(T, /turf/simulated/wall))
|
||||
to_chat(src, "<span class='revenwarning'>You cannot use abilities from inside of a wall.</span>")
|
||||
return 0
|
||||
if(src.inhibited)
|
||||
if(inhibited)
|
||||
to_chat(src, "<span class='revenwarning'>Your powers have been suppressed by nulling energy!</span>")
|
||||
return 0
|
||||
if(!src.change_essence_amount(essence_cost, 1))
|
||||
if(!change_essence_amount(essence_cost, 1))
|
||||
to_chat(src, "<span class='revenwarning'>You lack the essence to use that ability.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/change_essence_amount(essence_amt, silent = 0, source = null)
|
||||
if(!src)
|
||||
return
|
||||
if(essence + essence_amt <= 0)
|
||||
return
|
||||
essence = max(0, essence+essence_amt)
|
||||
@@ -264,8 +273,6 @@
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/reveal(time)
|
||||
if(!src)
|
||||
return
|
||||
if(time <= 0)
|
||||
return
|
||||
revealed = 1
|
||||
@@ -280,8 +287,6 @@
|
||||
update_spooky_icon()
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/stun(time)
|
||||
if(!src)
|
||||
return
|
||||
if(time <= 0)
|
||||
return
|
||||
notransform = 1
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
if(draining)
|
||||
to_chat(src, "<span class='revenwarning'>You are already siphoning the essence of a soul!</span>")
|
||||
return
|
||||
if(target in drained_mobs)
|
||||
var/mob_UID = target.UID()
|
||||
if(mob_UID in drained_mobs)
|
||||
to_chat(src, "<span class='revenwarning'>[target]'s soul is dead and empty.</span>")
|
||||
return
|
||||
if(!target.stat)
|
||||
@@ -39,7 +40,7 @@
|
||||
if(prob(10))
|
||||
to_chat(target, "You feel as if you are being watched.")
|
||||
return
|
||||
draining = 1
|
||||
draining = TRUE
|
||||
essence_drained = rand(15, 20)
|
||||
to_chat(src, "<span class='revennotice'>You search for the soul of [target].</span>")
|
||||
if(do_after(src, 10, 0, target = target)) //did they get deleted in that second?
|
||||
@@ -65,7 +66,7 @@
|
||||
if(!target.stat)
|
||||
to_chat(src, "<span class='revenwarning'>They are now powerful enough to fight off your draining.</span>")
|
||||
to_chat(target, "<span class='boldannounce'>You feel something tugging across your body before subsiding.</span>")
|
||||
draining = 0
|
||||
draining = FALSE
|
||||
return //hey, wait a minute...
|
||||
to_chat(src, "<span class='revenminor'>You begin siphoning essence from [target]'s soul.</span>")
|
||||
if(target.stat != DEAD)
|
||||
@@ -84,7 +85,8 @@
|
||||
to_chat(src, "<span class='revennotice'>[target]'s soul has been considerably weakened and will yield no more essence for the time being.</span>")
|
||||
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
|
||||
"<span class='revenwarning'>Violets lights, dancing in your vision, getting clo--</span>")
|
||||
drained_mobs.Add(target)
|
||||
drained_mobs.Add(mob_UID)
|
||||
add_attack_logs(src, target, "revenant harvested soul")
|
||||
target.death(0)
|
||||
else
|
||||
to_chat(src, "<span class='revenwarning'>[target ? "[target] has":"They have"] been drawn out of your grasp. The link has been broken.</span>")
|
||||
@@ -96,10 +98,10 @@
|
||||
return
|
||||
else
|
||||
to_chat(src, "<span class='revenwarning'>You are not close enough to siphon [target ? "[target]'s":"their"] soul. The link has been broken.</span>")
|
||||
draining = 0
|
||||
draining = FALSE
|
||||
essence_drained = 0
|
||||
return
|
||||
draining = 0
|
||||
draining = FALSE
|
||||
essence_drained = 0
|
||||
return
|
||||
|
||||
@@ -142,7 +144,7 @@
|
||||
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/locked = TRUE //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
|
||||
|
||||
@@ -155,36 +157,36 @@
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr, charge_check = TRUE, show_message = FALSE)
|
||||
if(user.inhibited)
|
||||
return 0
|
||||
return FALSE
|
||||
if(charge_counter < charge_max)
|
||||
return 0
|
||||
return FALSE
|
||||
if(locked)
|
||||
if(user.essence <= unlock_amount)
|
||||
return 0
|
||||
return FALSE
|
||||
if(user.essence <= cast_amount)
|
||||
return 0
|
||||
return 1
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/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
|
||||
return FALSE
|
||||
name = "[initial(name)] ([cast_amount]E)"
|
||||
to_chat(user, "<span class='revennotice'>You have unlocked [initial(name)]!</span>")
|
||||
panel = "Revenant Abilities"
|
||||
locked = 0
|
||||
locked = FALSE
|
||||
charge_counter = charge_max
|
||||
return 0
|
||||
return FALSE
|
||||
if(!user.castcheck(-cast_amount))
|
||||
charge_counter = charge_max
|
||||
return 0
|
||||
return FALSE
|
||||
name = "[initial(name)] ([cast_amount]E)"
|
||||
user.reveal(reveal)
|
||||
user.stun(stun)
|
||||
if(action)
|
||||
action.UpdateButtonIcon()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
//Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload
|
||||
@@ -201,25 +203,29 @@
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
for(var/obj/machinery/light/L in T.contents)
|
||||
spawn(0)
|
||||
if(!L.on)
|
||||
return
|
||||
L.visible_message("<span class='warning'><b>\The [L] suddenly flares brightly and begins to spark!</span>")
|
||||
do_sparks(4, 0, L)
|
||||
new/obj/effect/temp_visual/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/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, flags = SHOCK_NOGLOVES)
|
||||
do_sparks(4, 0, M)
|
||||
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
|
||||
select_lights(T, user)
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/proc/select_lights(turf/T, mob/living/simple_animal/revenant/user)
|
||||
for(var/obj/machinery/light/L in T.contents)
|
||||
INVOKE_ASYNC(src, .proc/shock_lights, L, user)
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/proc/shock_lights(obj/machinery/light/L, mob/living/simple_animal/revenant/user)
|
||||
if(!L.on)
|
||||
return
|
||||
L.visible_message("<span class='warning'><b>\The [L] suddenly flares brightly and begins to spark!</span>")
|
||||
do_sparks(4, 0, L)
|
||||
new /obj/effect/temp_visual/revenant(L.loc)
|
||||
sleep(2 SECONDS)
|
||||
if(!L.on) //wait, wait, don't shock me
|
||||
return
|
||||
flick("[L.base_state]2", L)
|
||||
for(var/mob/living/M in view(shock_range, L))
|
||||
if(M == user)
|
||||
continue
|
||||
M.Beam(L, icon_state = "purple_lightning", icon = 'icons/effects/effects.dmi', time = 0.5 SECONDS)
|
||||
M.electrocute_act(shock_damage, L, flags = SHOCK_NOGLOVES)
|
||||
do_sparks(4, 0, M)
|
||||
playsound(M, 'sound/machines/defib_zap.ogg', 50, TRUE, -1)
|
||||
|
||||
//Defile: Corrupts nearby stuff, unblesses floor tiles.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile
|
||||
@@ -232,46 +238,14 @@
|
||||
unlock_amount = 75
|
||||
cast_amount = 30
|
||||
action_icon_state = "defile"
|
||||
var/stamdamage= 25
|
||||
var/toxdamage = 5
|
||||
var/confusion = 20
|
||||
var/maxconfusion = 30
|
||||
|
||||
/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/temp_visual/revenant(T)
|
||||
for(var/mob/living/carbon/human/human in T.contents)
|
||||
to_chat(human, "<span class='warning'>You suddenly feel [pick("sick and tired", "tired and confused", "nauseated", "dizzy")].</span>")
|
||||
human.adjustStaminaLoss(stamdamage)
|
||||
human.adjustToxLoss(toxdamage)
|
||||
human.AdjustConfused(confusion, bound_lower = 0, bound_upper = maxconfusion)
|
||||
new/obj/effect/temp_visual/revenant(human.loc)
|
||||
if(!istype(T, /turf/simulated/wall/indestructible) && !istype(T, /turf/simulated/wall/rust) && !istype(T, /turf/simulated/wall/r_wall) && istype(T, /turf/simulated/wall) && prob(15))
|
||||
new/obj/effect/temp_visual/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/temp_visual/revenant(T)
|
||||
T.ChangeTurf(/turf/simulated/wall/r_wall/rust)
|
||||
for(var/obj/structure/window/window in T.contents)
|
||||
window.take_damage(rand(30,80))
|
||||
if(window && window.fulltile)
|
||||
new/obj/effect/temp_visual/revenant/cracks(window.loc)
|
||||
for(var/obj/structure/closet/closet in T.contents)
|
||||
closet.open()
|
||||
|
||||
if(!istype(T, /turf/simulated/floor/plating) && !istype(T, /turf/simulated/floor/engine/cult) && istype(T, /turf/simulated/floor) && prob(15))
|
||||
var/turf/simulated/floor/floor = T
|
||||
if(floor.intact && floor.floor_tile)
|
||||
new floor.floor_tile(floor)
|
||||
floor.broken = 0
|
||||
floor.burnt = 0
|
||||
floor.make_plating(1)
|
||||
for(var/obj/machinery/light/light in T.contents)
|
||||
light.flicker(30) //spooky
|
||||
if(!attempt_cast(user))
|
||||
return
|
||||
for(var/turf/T in targets)
|
||||
T.defile()
|
||||
for(var/atom/A in T.contents)
|
||||
A.defile()
|
||||
|
||||
//Malfunction: Makes bad stuff happen to robots and machines.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction
|
||||
@@ -287,29 +261,107 @@
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
for(var/mob/living/simple_animal/bot/bot in T.contents)
|
||||
if(!bot.emagged)
|
||||
new/obj/effect/temp_visual/revenant(bot.loc)
|
||||
bot.locked = 0
|
||||
bot.open = 1
|
||||
bot.emag_act(null)
|
||||
for(var/mob/living/carbon/human/human in T.contents)
|
||||
to_chat(human, "<span class='warning'>You feel [pick("your sense of direction flicker out", "a stabbing pain in your head", "your mind fill with static")].</span>")
|
||||
new/obj/effect/temp_visual/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)) //Doesn't work on dominators, SMES and APCs, to prevent kekkery
|
||||
continue
|
||||
if(prob(20))
|
||||
if(prob(50))
|
||||
new/obj/effect/temp_visual/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/temp_visual/revenant(S.loc)
|
||||
S.spark_system.start()
|
||||
S.emp_act(1)
|
||||
INVOKE_ASYNC(src, .proc/effect, user, T)
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/proc/effect(mob/living/simple_animal/revenant/user, turf/T)
|
||||
T.rev_malfunction()
|
||||
for(var/atom/A in T.contents)
|
||||
A.rev_malfunction()
|
||||
|
||||
|
||||
/atom/proc/defile()
|
||||
return
|
||||
|
||||
/atom/proc/rev_malfunction()
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/rev_malfunction()
|
||||
to_chat(src, "<span class='warning'>You feel [pick("your sense of direction flicker out", "a stabbing pain in your head", "your mind fill with static")].</span>")
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
emp_act(1)
|
||||
|
||||
/mob/living/simple_animal/bot/rev_malfunction()
|
||||
if(!emagged)
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
locked = FALSE
|
||||
open = TRUE
|
||||
emag_act(null)
|
||||
|
||||
/obj/rev_malfunction()
|
||||
if(prob(20))
|
||||
if(prob(50))
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
emag_act(null)
|
||||
|
||||
/obj/machinery/clonepod/rev_malfunction()
|
||||
emag_act(null)
|
||||
|
||||
/obj/machinery/power/apc/rev_malfunction()
|
||||
return
|
||||
|
||||
/obj/machinery/power/smes/rev_malfunction()
|
||||
return
|
||||
|
||||
/mob/living/silicon/robot/rev_malfunction()
|
||||
playsound(src, 'sound/machines/warning-buzzer.ogg', 50, 1)
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
spark_system.start()
|
||||
emp_act(1)
|
||||
|
||||
/turf/defile()
|
||||
if(flags & NOJAUNT)
|
||||
flags &= ~NOJAUNT
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
|
||||
/turf/simulated/wall/defile()
|
||||
..()
|
||||
if(prob(15))
|
||||
new/obj/effect/temp_visual/revenant(loc)
|
||||
ChangeTurf(/turf/simulated/wall/rust)
|
||||
|
||||
/turf/simulated/wall/indestructible/defile()
|
||||
return
|
||||
|
||||
/turf/simulated/wall/r_wall/defile()
|
||||
..()
|
||||
if(prob(15))
|
||||
new/obj/effect/temp_visual/revenant(loc)
|
||||
ChangeTurf(/turf/simulated/wall/r_wall/rust)
|
||||
|
||||
/mob/living/carbon/human/defile()
|
||||
to_chat(src, "<span class='warning'>You suddenly feel [pick("sick and tired", "tired and confused", "nauseated", "dizzy")].</span>")
|
||||
adjustStaminaLoss(25)
|
||||
adjustToxLoss(5)
|
||||
AdjustConfused(20, bound_lower = 0, bound_upper = 30)
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
|
||||
/obj/structure/window/defile()
|
||||
take_damage(rand(30,80))
|
||||
if(fulltile)
|
||||
new /obj/effect/temp_visual/revenant/cracks(loc)
|
||||
|
||||
/obj/structure/closet/defile()
|
||||
open()
|
||||
|
||||
/turf/simulated/floor/defile()
|
||||
..()
|
||||
if(prob(15))
|
||||
if(intact && floor_tile)
|
||||
new floor_tile(src)
|
||||
broken = 0
|
||||
burnt = 0
|
||||
make_plating(1)
|
||||
|
||||
/turf/simulated/floor/plating/defile()
|
||||
if(flags & NOJAUNT)
|
||||
flags &= ~NOJAUNT
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
|
||||
/turf/simulated/floor/engine/cult/defile()
|
||||
if(flags & NOJAUNT)
|
||||
flags &= ~NOJAUNT
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
|
||||
/obj/machinery/light/defile()
|
||||
flicker(30)
|
||||
|
||||
|
||||
@@ -115,6 +115,12 @@
|
||||
speed = 0
|
||||
boost = world.time + 60
|
||||
|
||||
// Midround slaughter demon, less tanky
|
||||
|
||||
/mob/living/simple_animal/slaughter/lesser
|
||||
maxHealth = 130
|
||||
health = 130
|
||||
|
||||
// Cult slaughter demon
|
||||
/mob/living/simple_animal/slaughter/cult //Summoned as part of the cult objective "Bring the Slaughter"
|
||||
name = "harbinger of the slaughter"
|
||||
|
||||
@@ -205,6 +205,15 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
|
||||
/datum/objective/protect/mindslave //subytpe for mindslave implants
|
||||
|
||||
/datum/objective/protect/mindslave/on_target_cryo()
|
||||
if(owner?.current)
|
||||
to_chat(owner.current, "<BR><span class='userdanger'>You notice that your master has entered cryogenic storage, and revert to your normal self, until they return again. You are no longer a mindslave!</span>")
|
||||
SEND_SOUND(owner.current, sound('sound/ambience/alarm4.ogg'))
|
||||
owner.remove_antag_datum(/datum/antagonist/mindslave)
|
||||
SSticker.mode.implanted.Remove(owner)
|
||||
log_admin("[key_name(owner.current)]'s mindslave master has cryo'd, and is no longer a mindslave.")
|
||||
message_admins("[key_name_admin(owner.current)]'s mindslave master has cryo'd, and is no longer a mindslave.") //Since they were on antag hud earlier, this feels important to log
|
||||
qdel(src)
|
||||
|
||||
/datum/objective/hijack
|
||||
martyr_compatible = 0 //Technically you won't get both anyway.
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
|
||||
var/list/possible_traitors = get_players_for_role(ROLE_TRAITOR)
|
||||
|
||||
for(var/datum/mind/candidate in possible_traitors)
|
||||
if(candidate.special_role == SPECIAL_ROLE_VAMPIRE) // no traitor vampires
|
||||
possible_traitors.Remove(candidate)
|
||||
|
||||
// stop setup if no possible traitors
|
||||
if(!possible_traitors.len)
|
||||
return 0
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
/datum/game_mode/traitor/vampire/announce()
|
||||
to_chat(world, "<B>The current game mode is - Traitor+Vampire!</B>")
|
||||
to_chat(world, "<B>There is a Vampire from Space Transylvania on the station along with some syndicate operatives out for their own gain! Do not let the vampire and the traitors succeed!</B>")
|
||||
to_chat(world, "<B>There are Bluespace Vampires infesting your fellow crew on the station along with some syndicate operatives out for their own gain! Do not let the vampires and the traitors succeed!</B>")
|
||||
|
||||
|
||||
/datum/game_mode/traitor/vampire/pre_setup()
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
//This is the gamemode file for the ported goon gamemode vampires.
|
||||
//They get a traitor objective and a blood sucking objective
|
||||
/datum/game_mode
|
||||
var/list/datum/mind/vampires = list()
|
||||
var/list/datum/mind/vampire_enthralled = list() //those controlled by a vampire
|
||||
var/list/vampire_thralls = list() //vammpires controlling somebody
|
||||
var/list/vampire_thralls = list() //vampires controlling somebody
|
||||
|
||||
/datum/game_mode/vampire
|
||||
name = "vampire"
|
||||
@@ -36,7 +34,7 @@
|
||||
|
||||
/datum/game_mode/vampire/announce()
|
||||
to_chat(world, "<B>The current game mode is - Vampires!</B>")
|
||||
to_chat(world, "<B>There are Vampires from Space Transylvania on the station, keep your blood close and neck safe!</B>")
|
||||
to_chat(world, "<B>There are Bluespace Vampires infesting your fellow crewmates, keep your blood close and neck safe!</B>")
|
||||
|
||||
/datum/game_mode/vampire/pre_setup()
|
||||
|
||||
@@ -84,8 +82,8 @@
|
||||
text += "died"
|
||||
else
|
||||
text += "survived"
|
||||
if(vampire.current.real_name != vampire.name)
|
||||
text += " as [vampire.current.real_name]"
|
||||
if(vampire.vampire.subclass)
|
||||
text += " as a [vampire.vampire.subclass.name]"
|
||||
else
|
||||
text += "body destroyed"
|
||||
text += ")"
|
||||
@@ -120,15 +118,15 @@
|
||||
/datum/game_mode/proc/auto_declare_completion_enthralled()
|
||||
if(vampire_enthralled.len)
|
||||
var/text = "<FONT size = 2><B>The Enthralled were:</B></FONT>"
|
||||
for(var/datum/mind/Mind in vampire_enthralled)
|
||||
text += "<br>[Mind.key] was [Mind.name] ("
|
||||
if(Mind.current)
|
||||
if(Mind.current.stat == DEAD)
|
||||
for(var/datum/mind/mind in vampire_enthralled)
|
||||
text += "<br>[mind.key] was [mind.name] ("
|
||||
if(mind.current)
|
||||
if(mind.current.stat == DEAD)
|
||||
text += "died"
|
||||
else
|
||||
text += "survived"
|
||||
if(Mind.current.real_name != Mind.name)
|
||||
text += " as [Mind.current.real_name]"
|
||||
if(mind.current.real_name != mind.name)
|
||||
text += " as [mind.current.real_name]"
|
||||
else
|
||||
text += "body destroyed"
|
||||
text += ")"
|
||||
@@ -168,9 +166,18 @@
|
||||
return
|
||||
|
||||
/datum/game_mode/proc/grant_vampire_powers(mob/living/carbon/vampire_mob)
|
||||
if(!istype(vampire_mob))
|
||||
if(!istype(vampire_mob) || !vampire_mob.mind)
|
||||
return
|
||||
vampire_mob.make_vampire()
|
||||
var/datum/vampire/vamp
|
||||
if(!vampire_mob.mind.vampire)
|
||||
vamp = new /datum/vampire()
|
||||
vamp.owner = vampire_mob
|
||||
vampire_mob.mind.vampire = vamp
|
||||
else
|
||||
vamp = vampire_mob.mind.vampire
|
||||
QDEL_LIST(vamp.powers)
|
||||
|
||||
vamp.check_vampire_upgrade(FALSE)
|
||||
|
||||
/datum/game_mode/proc/greet_vampire(datum/mind/vampire, you_are=1)
|
||||
var/dat
|
||||
@@ -178,7 +185,7 @@
|
||||
SEND_SOUND(vampire.current, sound('sound/ambience/antag/vampalert.ogg'))
|
||||
dat = "<span class='danger'>You are a Vampire!</span><br>"
|
||||
dat += {"To bite someone, target the head and use harm intent with an empty hand. Drink blood to gain new powers.
|
||||
You are weak to holy things and starlight. Don't go into space and avoid the Chaplain, the chapel and especially Holy Water."}
|
||||
You are weak to holy things, starlight and fire. Don't go into space and avoid the Chaplain, the chapel and especially Holy Water."}
|
||||
to_chat(vampire.current, dat)
|
||||
to_chat(vampire.current, "<B>You must complete the following tasks:</B>")
|
||||
|
||||
@@ -195,42 +202,51 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
obj_count++
|
||||
to_chat(vampire.current, "<span class='motd'>For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Vampire)</span>")
|
||||
return
|
||||
|
||||
/datum/vampire
|
||||
var/bloodtotal = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS
|
||||
var/bloodusable = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS
|
||||
var/bloodtotal = 0
|
||||
var/bloodusable = 0
|
||||
/// the mob tied to the vampire
|
||||
var/mob/living/owner = null
|
||||
var/gender = FEMALE
|
||||
var/iscloaking = 0 // handles the vampire cloak toggle
|
||||
var/list/powers = list() // list of available powers and passives
|
||||
var/mob/living/carbon/human/draining // who the vampire is draining of blood
|
||||
var/nullified = 0 //Nullrod makes them useless for a short while.
|
||||
var/list/upgrade_tiers = list(
|
||||
/obj/effect/proc_holder/spell/vampire/self/rejuvenate = 0,
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/hypnotise = 0,
|
||||
/obj/effect/proc_holder/spell/vampire/mob_aoe/glare = 0,
|
||||
/datum/vampire_passive/vision = 100,
|
||||
/obj/effect/proc_holder/spell/vampire/self/shapeshift = 100,
|
||||
/obj/effect/proc_holder/spell/vampire/self/cloak = 150,
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/disease = 150,
|
||||
/obj/effect/proc_holder/spell/vampire/bats = 200,
|
||||
/obj/effect/proc_holder/spell/vampire/self/screech = 200,
|
||||
/datum/vampire_passive/regen = 200,
|
||||
/obj/effect/proc_holder/spell/vampire/shadowstep = 250,
|
||||
/obj/effect/proc_holder/spell/vampire/self/jaunt = 300,
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/enthrall = 300,
|
||||
/datum/vampire_passive/full = 500)
|
||||
/// what vampire subclass the vampire is.
|
||||
var/datum/vampire_subclass/subclass
|
||||
/// handles the vampire cloak toggle
|
||||
var/iscloaking = FALSE
|
||||
/// list of available powers and passives
|
||||
var/list/powers = list()
|
||||
/// who the vampire is draining of blood
|
||||
var/mob/living/carbon/human/draining
|
||||
/// Nullrods and holywater make their abilities cost more
|
||||
var/nullified = 0
|
||||
/// a list of powers that all vampires unlock and at what blood level they unlock them, the rest of their powers are found in the vampire_subclass datum
|
||||
var/list/upgrade_tiers = list(/obj/effect/proc_holder/spell/self/vampire/rejuvenate = 0,
|
||||
/obj/effect/proc_holder/spell/mob_aoe/glare = 0,
|
||||
/datum/vampire_passive/vision = 100,
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize = 150,
|
||||
/datum/vampire_passive/regen = 200,
|
||||
/obj/effect/proc_holder/spell/targeted/turf_teleport/shadow_step = 250)
|
||||
|
||||
/// list of the peoples UIDs that we have drained, and how much blood from each one
|
||||
var/list/drained_humans = list()
|
||||
|
||||
/datum/vampire/Destroy(force, ...)
|
||||
owner = null
|
||||
draining = null
|
||||
QDEL_NULL(subclass)
|
||||
QDEL_LIST(powers)
|
||||
return ..()
|
||||
|
||||
/datum/vampire/proc/adjust_nullification(base, extra)
|
||||
// First hit should give full nullification, while subsequent hits increase the value slower
|
||||
nullified = max(nullified + extra, base)
|
||||
|
||||
/datum/vampire/New(gend = FEMALE)
|
||||
gender = gend
|
||||
nullified = clamp(nullified + extra, base, VAMPIRE_NULLIFICATION_CAP)
|
||||
|
||||
/datum/vampire/proc/force_add_ability(path)
|
||||
var/spell = new path(owner)
|
||||
if(istype(spell, /obj/effect/proc_holder/spell))
|
||||
owner.mind.AddSpell(spell)
|
||||
if(istype(spell, /datum/vampire_passive))
|
||||
var/datum/vampire_passive/passive = spell
|
||||
passive.owner = owner
|
||||
powers += spell
|
||||
owner.update_sight() // Life updates conditionally, so we need to update sight here in case the vamp gets new vision based on his powers. Maybe one day refactor to be more OOP and on the vampire's ability datum.
|
||||
|
||||
@@ -256,20 +272,6 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
if(current.mind && current.mind.vampire && current.mind.vampire.owner && (current.mind.vampire.owner != current))
|
||||
current.mind.vampire.owner = current
|
||||
|
||||
/mob/proc/make_vampire()
|
||||
if(!mind)
|
||||
return
|
||||
var/datum/vampire/vamp
|
||||
if(!mind.vampire)
|
||||
vamp = new /datum/vampire(gender)
|
||||
vamp.owner = src
|
||||
mind.vampire = vamp
|
||||
else
|
||||
vamp = mind.vampire
|
||||
vamp.powers.Cut()
|
||||
|
||||
vamp.check_vampire_upgrade(0)
|
||||
|
||||
/datum/vampire/proc/remove_vampire_powers()
|
||||
for(var/P in powers)
|
||||
remove_ability(P)
|
||||
@@ -278,12 +280,14 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
if(hud.vampire_blood_display)
|
||||
hud.remove_vampire_hud()
|
||||
owner.alpha = 255
|
||||
REMOVE_TRAITS_IN(owner, "vampire")
|
||||
|
||||
/datum/vampire/proc/handle_bloodsucking(mob/living/carbon/human/H)
|
||||
#define BLOOD_GAINED_MODIFIER 0.5
|
||||
|
||||
/datum/vampire/proc/handle_bloodsucking(mob/living/carbon/human/H, suck_rate = 5 SECONDS)
|
||||
draining = H
|
||||
var/unique_suck_id = H.UID()
|
||||
var/blood = 0
|
||||
var/old_bloodtotal = 0 //used to see if we increased our blood total
|
||||
var/old_bloodusable = 0 //used to see if we increased our blood usable
|
||||
var/blood_volume_warning = 9999 //Blood volume threshold for warnings
|
||||
if(owner.is_muzzled())
|
||||
to_chat(owner, "<span class='warning'>[owner.wear_mask] prevents you from biting [H]!</span>")
|
||||
@@ -295,25 +299,24 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
H.LAssailant = null
|
||||
else
|
||||
H.LAssailant = owner
|
||||
while(do_mob(owner, H, 50))
|
||||
while(do_mob(owner, H, suck_rate))
|
||||
if(!(owner.mind in SSticker.mode.vampires))
|
||||
to_chat(owner, "<span class='userdanger'>Your fangs have disappeared!</span>")
|
||||
return
|
||||
old_bloodtotal = bloodtotal
|
||||
old_bloodusable = bloodusable
|
||||
owner.do_attack_animation(H, ATTACK_EFFECT_BITE)
|
||||
if(unique_suck_id in drained_humans)
|
||||
if(drained_humans[unique_suck_id] >= BLOOD_DRAIN_LIMIT)
|
||||
to_chat(owner, "<span class='warning'>You have drained most of the life force from [H]'s blood, and you will get no more useable blood from them!</span>")
|
||||
H.blood_volume = max(H.blood_volume - 25, 0)
|
||||
owner.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.nutrition + 5))
|
||||
continue
|
||||
|
||||
|
||||
if(H.stat < DEAD)
|
||||
if(H.ckey || H.player_ghosted) //Requires ckey regardless if monkey or humanoid, or the body has been ghosted before it died
|
||||
blood = min(20, H.blood_volume) // if they have less than 20 blood, give them the remnant else they get 20 blood
|
||||
bloodtotal += blood / 2 //divide by 2 to counted the double suction since removing cloneloss -Melandor0
|
||||
bloodusable += blood / 2
|
||||
else
|
||||
if(H.ckey || H.player_ghosted)
|
||||
blood = min(5, H.blood_volume) // The dead only give 5 blood
|
||||
bloodtotal += blood
|
||||
if(old_bloodtotal != bloodtotal)
|
||||
if(H.ckey || H.player_ghosted) // Requires ckey regardless if monkey or human, and has not ghosted, otherwise no power
|
||||
to_chat(owner, "<span class='notice'><b>You have accumulated [bloodtotal] [bloodtotal > 1 ? "units" : "unit"] of blood[bloodusable != old_bloodusable ? ", and have [bloodusable] left to use" : ""].</b></span>")
|
||||
check_vampire_upgrade()
|
||||
blood = min(20, H.blood_volume)
|
||||
adjust_blood(H, blood * BLOOD_GAINED_MODIFIER)
|
||||
to_chat(owner, "<span class='notice'><b>You have accumulated [bloodtotal] unit\s of blood, and have [bloodusable] left to use.</b></span>")
|
||||
H.blood_volume = max(H.blood_volume - 25, 0)
|
||||
//Blood level warnings (Code 'borrowed' from Fulp)
|
||||
if(H.blood_volume)
|
||||
@@ -325,20 +328,18 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
else
|
||||
to_chat(owner, "<span class='warning'>You have bled your victim dry!</span>")
|
||||
break
|
||||
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/V = owner
|
||||
if(!H.ckey && !H.player_ghosted)//Only runs if there is no ckey and the body has not being ghosted while alive
|
||||
to_chat(V, "<span class='notice'><b>Feeding on [H] reduces your thirst, but you get no usable blood from them.</b></span>")
|
||||
V.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, V.nutrition + 5))
|
||||
else
|
||||
V.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, V.nutrition + (blood / 2)))
|
||||
|
||||
if(!H.ckey && !H.player_ghosted)//Only runs if there is no ckey and the body has not being ghosted while alive
|
||||
to_chat(owner, "<span class='notice'><b>Feeding on [H] reduces your thirst, but you get no usable blood from them.</b></span>")
|
||||
owner.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.nutrition + 5))
|
||||
else
|
||||
owner.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.nutrition + (blood / 2)))
|
||||
|
||||
draining = null
|
||||
to_chat(owner, "<span class='notice'>You stop draining [H.name] of blood.</span>")
|
||||
|
||||
/datum/vampire/proc/check_vampire_upgrade(announce = 1)
|
||||
#undef BLOOD_GAINED_MODIFIER
|
||||
|
||||
/datum/vampire/proc/check_vampire_upgrade(announce = TRUE)
|
||||
var/list/old_powers = powers.Copy()
|
||||
|
||||
for(var/ptype in upgrade_tiers)
|
||||
@@ -346,18 +347,30 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
if(bloodtotal >= level)
|
||||
add_ability(ptype)
|
||||
|
||||
if(!subclass)
|
||||
return
|
||||
subclass.add_subclass_ability(src)
|
||||
|
||||
check_full_power_upgrade()
|
||||
|
||||
if(announce)
|
||||
announce_new_power(old_powers)
|
||||
|
||||
|
||||
/datum/vampire/proc/check_full_power_upgrade()
|
||||
if(length(drained_humans) >= FULLPOWER_DRAINED_REQUIREMENT && bloodtotal >= FULLPOWER_BLOODTOTAL_REQUIREMENT)
|
||||
subclass.add_full_power_abilities(src)
|
||||
|
||||
|
||||
/datum/vampire/proc/announce_new_power(list/old_powers)
|
||||
for(var/p in powers)
|
||||
if(!(p in old_powers))
|
||||
if(istype(p, /obj/effect/proc_holder/spell/vampire))
|
||||
var/obj/effect/proc_holder/spell/vampire/power = p
|
||||
to_chat(owner, "<span class='notice'>[power.gain_desc]</span>")
|
||||
if(istype(p, /obj/effect/proc_holder/spell))
|
||||
var/obj/effect/proc_holder/spell/power = p
|
||||
to_chat(owner, "<span class='boldnotice'>[power.gain_desc]</span>")
|
||||
else if(istype(p, /datum/vampire_passive))
|
||||
var/datum/vampire_passive/power = p
|
||||
to_chat(owner, "<span class='notice'>[power.gain_desc]</span>")
|
||||
to_chat(owner, "<span class='boldnotice'>[power.gain_desc]</span>")
|
||||
|
||||
/datum/game_mode/proc/remove_vampire(datum/mind/vampire_mind)
|
||||
if(vampire_mind in vampires)
|
||||
@@ -414,6 +427,9 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
|
||||
var/turf/T = locate(round(ax, 0.5), round(ay, 0.5), owner.z)
|
||||
|
||||
if(!T)
|
||||
return
|
||||
|
||||
if(T.x == 1 || T.x == world.maxx || T.y == 1 || T.y == world.maxy)
|
||||
break
|
||||
|
||||
@@ -427,6 +443,8 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
to_chat(owner, "<span class='userdanger'>Your body is turning to ash, get out of the light now!</span>")
|
||||
owner.adjustCloneLoss(10) //I'm melting!
|
||||
vamp_burn(85)
|
||||
if(owner.cloneloss >= 100)
|
||||
owner.dust()
|
||||
|
||||
/datum/vampire/proc/handle_vampire()
|
||||
if(owner.hud_used)
|
||||
@@ -440,31 +458,49 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
hud.show_hud(hud.hud_version)
|
||||
hud.vampire_blood_display.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font face='Small Fonts' color='#ce0202'>[bloodusable]</font></div>"
|
||||
handle_vampire_cloak()
|
||||
if(istype(owner.loc, /turf/space))
|
||||
if(istype(get_turf(owner), /turf/space))
|
||||
check_sun()
|
||||
if(istype(owner.loc.loc, /area/chapel) && !get_ability(/datum/vampire_passive/full))
|
||||
if(istype(get_area(owner), /area/chapel) && !get_ability(/datum/vampire_passive/full))
|
||||
vamp_burn(7)
|
||||
nullified = max(0, nullified - 1)
|
||||
nullified = max(0, nullified - 2)
|
||||
|
||||
/datum/vampire/proc/handle_vampire_cloak()
|
||||
if(!ishuman(owner))
|
||||
owner.alpha = 255
|
||||
return
|
||||
var/turf/simulated/T = get_turf(owner)
|
||||
var/light_available = T.get_lumcount(0.5) * 10
|
||||
var/light_available = T.get_lumcount() * 10
|
||||
|
||||
if(!istype(T))
|
||||
return 0
|
||||
return
|
||||
|
||||
if(!iscloaking)
|
||||
if(!iscloaking || owner.on_fire)
|
||||
owner.alpha = 255
|
||||
return 0
|
||||
REMOVE_TRAIT(owner, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
|
||||
return
|
||||
|
||||
if(light_available <= 2)
|
||||
owner.alpha = round((255 * 0.15))
|
||||
return 1
|
||||
else
|
||||
owner.alpha = round((255 * 0.80))
|
||||
owner.alpha = 38 // round(255 * 0.15)
|
||||
ADD_TRAIT(owner, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
|
||||
return
|
||||
|
||||
REMOVE_TRAIT(owner, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
|
||||
owner.alpha = 204 // 255 * 0.80
|
||||
|
||||
/datum/vampire/proc/adjust_blood(mob/living/carbon/C, blood_amount = 0)
|
||||
if(C)
|
||||
var/unique_suck_id = C.UID()
|
||||
if(!(unique_suck_id in drained_humans))
|
||||
drained_humans[unique_suck_id] = 0
|
||||
if(drained_humans[unique_suck_id] >= BLOOD_DRAIN_LIMIT)
|
||||
return
|
||||
drained_humans[unique_suck_id] += blood_amount
|
||||
bloodtotal += blood_amount
|
||||
bloodusable += blood_amount
|
||||
check_vampire_upgrade(TRUE)
|
||||
for(var/obj/effect/proc_holder/spell/S in powers)
|
||||
if(S.action)
|
||||
S.action.UpdateButtonIcon()
|
||||
|
||||
/datum/vampire/proc/vamp_burn(burn_chance)
|
||||
if(prob(burn_chance) && owner.health >= 50)
|
||||
@@ -491,3 +527,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
static_inventory -= vampire_blood_display
|
||||
QDEL_NULL(vampire_blood_display)
|
||||
show_hud(hud_version)
|
||||
|
||||
/datum/vampire/vv_edit_var(var_name, var_value)
|
||||
. = ..()
|
||||
check_vampire_upgrade(TRUE)
|
||||
|
||||
@@ -1,611 +0,0 @@
|
||||
//This should hold all the vampire related powers
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
clothes_req = 0
|
||||
range = 1
|
||||
charge_max = 1800
|
||||
action_background_icon_state = "bg_vampire"
|
||||
holy_area_cancast = FALSE //Stops cult magic from working on holy ground eg: chapel
|
||||
var/required_blood = 0
|
||||
var/gain_desc = null
|
||||
var/deduct_blood_on_cast = TRUE //Do we want to take the blood when this is cast, or at a later point?
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/New()
|
||||
..()
|
||||
if(!gain_desc)
|
||||
gain_desc = "You have gained \the [src] ability."
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
|
||||
if(!user.mind)
|
||||
return 0
|
||||
if(!ishuman(user))
|
||||
to_chat(user, "<span class='warning'>You are in too weak of a form to do this!</span>")
|
||||
return 0
|
||||
|
||||
var/datum/vampire/vampire = user.mind.vampire
|
||||
|
||||
if(!vampire)
|
||||
return 0
|
||||
|
||||
var/fullpower = vampire.get_ability(/datum/vampire_passive/full)
|
||||
|
||||
if(user.stat >= DEAD)
|
||||
to_chat(user, "<span class='warning'>Not when you're dead!</span>")
|
||||
return 0
|
||||
|
||||
if(vampire.nullified && !fullpower)
|
||||
to_chat(user, "<span class='warning'>Something is blocking your powers!</span>")
|
||||
return 0
|
||||
if(vampire.bloodusable < required_blood)
|
||||
to_chat(user, "<span class='warning'>You require at least [required_blood] units of usable blood to do that!</span>")
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
|
||||
if(!user.mind)
|
||||
return 0
|
||||
if(!ishuman(user))
|
||||
return 0
|
||||
|
||||
var/datum/vampire/vampire = user.mind.vampire
|
||||
|
||||
if(!vampire)
|
||||
return 0
|
||||
|
||||
var/fullpower = vampire.get_ability(/datum/vampire_passive/full)
|
||||
|
||||
if(user.stat >= DEAD)
|
||||
return 0
|
||||
|
||||
if(vampire.nullified && !fullpower)
|
||||
return 0
|
||||
if(vampire.bloodusable < required_blood)
|
||||
return 0
|
||||
if(istype(loc.loc, /area/chapel) && !fullpower)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/proc/affects(mob/target, mob/user = usr)
|
||||
//Other vampires aren't affected
|
||||
if(target.mind && target.mind.vampire)
|
||||
return 0
|
||||
//Vampires who have reached their full potential can affect nearly everything
|
||||
if(user.mind.vampire.get_ability(/datum/vampire_passive/full))
|
||||
return 1
|
||||
//Holy characters are resistant to vampire powers
|
||||
if(target.mind && target.mind.isholy)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/proc/can_reach(mob/M as mob)
|
||||
if(M.loc == usr.loc)
|
||||
return 1 //target and source are in the same thing
|
||||
return M in oview_or_orange(range, usr, selection_type)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/before_cast(list/targets)
|
||||
// sanity check before we cast
|
||||
if(!usr.mind || !usr.mind.vampire)
|
||||
targets.Cut()
|
||||
return
|
||||
|
||||
if(!required_blood)
|
||||
return
|
||||
|
||||
// enforce blood
|
||||
var/datum/vampire/vampire = usr.mind.vampire
|
||||
|
||||
if(required_blood <= vampire.bloodusable)
|
||||
if(!deduct_blood_on_cast) //don't take the blood yet if this is false!
|
||||
return
|
||||
vampire.bloodusable -= required_blood
|
||||
else
|
||||
// stop!!
|
||||
targets.Cut()
|
||||
|
||||
if(targets.len)
|
||||
to_chat(usr, "<span class='notice'><b>You have [vampire.bloodusable] left to use.</b></span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/choose_targets(mob/user = usr)
|
||||
var/list/possible_targets[0]
|
||||
for(var/mob/living/carbon/C in oview_or_orange(range, user, selection_type))
|
||||
possible_targets += C
|
||||
var/mob/living/carbon/T = input(user, "Choose your victim.", name) as null|mob in possible_targets
|
||||
|
||||
if(!T || !can_reach(T))
|
||||
revert_cast(user)
|
||||
return
|
||||
|
||||
perform(list(T), user = user)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/choose_targets(mob/user = usr)
|
||||
perform(list(user))
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/mob_aoe/choose_targets(mob/user = usr)
|
||||
var/list/targets[0]
|
||||
for(var/mob/living/carbon/C in oview_or_orange(range, user, selection_type))
|
||||
targets += C
|
||||
|
||||
if(!targets.len)
|
||||
revert_cast(user)
|
||||
return
|
||||
|
||||
perform(targets, user = user)
|
||||
|
||||
/datum/vampire_passive
|
||||
var/gain_desc
|
||||
|
||||
/datum/vampire_passive/New()
|
||||
..()
|
||||
if(!gain_desc)
|
||||
gain_desc = "You have gained \the [src] ability."
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/rejuvenate
|
||||
name = "Rejuvenate"
|
||||
desc= "Use reserve blood to enliven your body, removing any incapacitating effects."
|
||||
action_icon_state = "vampire_rejuvinate"
|
||||
charge_max = 200
|
||||
stat_allowed = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/rejuvenate/cast(list/targets, mob/user = usr)
|
||||
var/mob/living/U = user
|
||||
|
||||
user.SetWeakened(0)
|
||||
user.SetStunned(0)
|
||||
user.SetParalysis(0)
|
||||
user.SetSleeping(0)
|
||||
U.adjustStaminaLoss(-75)
|
||||
to_chat(user, "<span class='notice'>You instill your body with clean blood and remove any incapacitating effects.</span>")
|
||||
spawn(1)
|
||||
if(usr.mind.vampire.get_ability(/datum/vampire_passive/regen))
|
||||
for(var/i = 1 to 5)
|
||||
U.adjustBruteLoss(-2)
|
||||
U.adjustOxyLoss(-5)
|
||||
U.adjustToxLoss(-2)
|
||||
U.adjustFireLoss(-2)
|
||||
sleep(35)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/hypnotise
|
||||
name = "Hypnotise (20)"
|
||||
desc= "A piercing stare that incapacitates your victim for a good length of time."
|
||||
action_icon_state = "vampire_hypnotise"
|
||||
required_blood = 20
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/hypnotise/cast(list/targets, mob/user = usr)
|
||||
for(var/mob/living/target in targets)
|
||||
user.visible_message("<span class='warning'>[user]'s eyes flash briefly as [user.p_they()] stare[user.p_s()] into [target]'s eyes</span>")
|
||||
if(do_mob(user, target, 50))
|
||||
if(!affects(target))
|
||||
to_chat(user, "<span class='warning'>Your piercing gaze fails to knock out [target].</span>")
|
||||
to_chat(target, "<span class='notice'>[user]'s feeble gaze is ineffective.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Your piercing gaze knocks out [target].</span>")
|
||||
to_chat(target, "<span class='warning'>You find yourself unable to move and barely able to speak.</span>")
|
||||
target.Weaken(10)
|
||||
target.Stun(10)
|
||||
target.stuttering = 10
|
||||
else
|
||||
revert_cast(usr)
|
||||
to_chat(usr, "<span class='warning'>You broke your gaze.</span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/disease
|
||||
name = "Diseased Touch (100)"
|
||||
desc = "Touches your victim with infected blood giving them Grave Fever, which will, left untreated, causes toxic building and frequent collapsing."
|
||||
gain_desc = "You have gained the Diseased Touch ability which causes those you touch to become weak unless treated medically."
|
||||
action_icon_state = "vampire_disease"
|
||||
required_blood = 100
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/disease/cast(list/targets, mob/user = usr)
|
||||
for(var/mob/living/carbon/target in targets)
|
||||
to_chat(user, "<span class='warning'>You stealthily infect [target] with your diseased touch.</span>")
|
||||
target.help_shake_act(user)
|
||||
if(!affects(target))
|
||||
to_chat(user, "<span class='warning'>They seem to be unaffected.</span>")
|
||||
continue
|
||||
var/datum/disease/D = new /datum/disease/vampire
|
||||
target.ForceContractDisease(D)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/mob_aoe/glare
|
||||
name = "Glare"
|
||||
desc = "A scary glare that incapacitates people for a short while around you."
|
||||
action_icon_state = "vampire_glare"
|
||||
charge_max = 300
|
||||
stat_allowed = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/mob_aoe/glare/cast(list/targets, mob/user = usr)
|
||||
user.visible_message("<span class='warning'>[user]'s eyes emit a blinding flash!</span>")
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/sunglasses/blindfold))
|
||||
var/obj/item/clothing/glasses/sunglasses/blindfold/B = H.glasses
|
||||
if(B.tint)
|
||||
to_chat(user, "<span class='warning'>You're blindfolded!</span>")
|
||||
return
|
||||
for(var/mob/living/target in targets)
|
||||
if(!affects(target))
|
||||
continue
|
||||
target.Stun(5)
|
||||
target.Weaken(5)
|
||||
target.stuttering = 20
|
||||
to_chat(target, "<span class='warning'>You are blinded by [user]'s glare.</span>")
|
||||
add_attack_logs(user, target, "(Vampire) Glared at")
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/shapeshift
|
||||
name = "Shapeshift (50)"
|
||||
desc = "Changes your name and appearance at the cost of 50 blood and has a cooldown of 3 minutes."
|
||||
gain_desc = "You have gained the shapeshifting ability, at the cost of stored blood you can change your form permanently."
|
||||
action_icon_state = "genetic_poly"
|
||||
required_blood = 50
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/shapeshift/cast(list/targets, mob/user = usr)
|
||||
user.visible_message("<span class='warning'>[user] transforms!</span>")
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
scramble(1, H, 100)
|
||||
H.real_name = random_name(H.gender, H.dna.species.name) //Give them a name that makes sense for their species.
|
||||
H.sync_organ_dna(assimilate = 1)
|
||||
H.update_body()
|
||||
H.reset_hair() //No more winding up with hairstyles you're not supposed to have, and blowing your cover.
|
||||
H.reset_markings() //...Or markings.
|
||||
H.dna.ResetUIFrom(H)
|
||||
H.flavor_text = ""
|
||||
user.update_icons()
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/screech
|
||||
name = "Chiropteran Screech (30)"
|
||||
desc = "An extremely loud shriek that stuns nearby humans and breaks windows as well."
|
||||
gain_desc = "You have gained the Chiropteran Screech ability which stuns anything with ears in a large radius and shatters glass in the process."
|
||||
action_icon_state = "vampire_screech"
|
||||
required_blood = 30
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/screech/cast(list/targets, mob/user = usr)
|
||||
user.visible_message("<span class='warning'>[user] lets out an ear piercing shriek!</span>", "<span class='warning'>You let out a loud shriek.</span>", "<span class='warning'>You hear a loud painful shriek!</span>")
|
||||
for(var/mob/living/carbon/C in hearers(4))
|
||||
if(C == user)
|
||||
continue
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(H.check_ear_prot() >= HEARING_PROTECTION_TOTAL)
|
||||
continue
|
||||
if(!affects(C))
|
||||
continue
|
||||
to_chat(C, "<span class='warning'><font size='3'><b>You hear a ear piercing shriek and your senses dull!</font></b></span>")
|
||||
C.Weaken(4)
|
||||
C.AdjustEarDamage(0, 20)
|
||||
C.Stuttering(20)
|
||||
C.Stun(4)
|
||||
C.Jitter(150)
|
||||
for(var/obj/structure/window/W in view(4))
|
||||
W.deconstruct(FALSE)
|
||||
playsound(user.loc, 'sound/effects/creepyshriek.ogg', 100, 1)
|
||||
|
||||
|
||||
/proc/isvampirethrall(mob/living/M as mob)
|
||||
return istype(M) && M.mind && SSticker && SSticker.mode && (M.mind in SSticker.mode.vampire_enthralled)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/enthrall
|
||||
name = "Enthrall (300)"
|
||||
desc = "You use a large portion of your power to sway those loyal to none to be loyal to you only."
|
||||
gain_desc = "You have gained the Enthrall ability which at a heavy blood cost allows you to enslave a human that is not loyal to any other for a random period of time."
|
||||
action_icon_state = "vampire_enthrall"
|
||||
required_blood = 300
|
||||
deduct_blood_on_cast = FALSE
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/enthrall/cast(list/targets, mob/user = usr)
|
||||
var/datum/vampire/vampire = user.mind.vampire
|
||||
for(var/mob/living/target in targets)
|
||||
user.visible_message("<span class='warning'>[user] bites [target]'s neck!</span>", "<span class='warning'>You bite [target]'s neck and begin the flow of power.</span>")
|
||||
to_chat(target, "<span class='warning'>You feel the tendrils of evil invade your mind.</span>")
|
||||
if(!ishuman(target))
|
||||
to_chat(user, "<span class='warning'>You can only enthrall humans.</span>")
|
||||
break
|
||||
if(do_mob(user, target, 50))
|
||||
if(can_enthrall(user, target))
|
||||
handle_enthrall(user, target)
|
||||
vampire.bloodusable -= required_blood //we take the blood after enthralling, not before
|
||||
else
|
||||
revert_cast(user)
|
||||
to_chat(user, "<span class='warning'>You or your target either moved or you dont have enough usable blood.</span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/enthrall/proc/can_enthrall(mob/living/user, mob/living/carbon/C)
|
||||
var/enthrall_safe = 0
|
||||
for(var/obj/item/implant/mindshield/L in C)
|
||||
if(L && L.implanted)
|
||||
enthrall_safe = 1
|
||||
break
|
||||
for(var/obj/item/implant/traitor/T in C)
|
||||
if(T && T.implanted)
|
||||
enthrall_safe = 1
|
||||
break
|
||||
if(!C)
|
||||
log_runtime(EXCEPTION("something bad happened on enthralling a mob, attacker is [user] [user.key] \ref[user]"), user)
|
||||
return 0
|
||||
if(!C.mind)
|
||||
to_chat(user, "<span class='warning'>[C.name]'s mind is not there for you to enthrall.</span>")
|
||||
return 0
|
||||
if(enthrall_safe || ( C.mind in SSticker.mode.vampires )||( C.mind.vampire )||( C.mind in SSticker.mode.vampire_enthralled ))
|
||||
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>You feel a familiar sensation in your skull that quickly dissipates.</span>")
|
||||
return 0
|
||||
if(!affects(C))
|
||||
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>Your faith of [SSticker.Bible_deity_name] has kept your mind clear of all evil.</span>")
|
||||
return 0
|
||||
if(!ishuman(C))
|
||||
to_chat(user, "<span class='warning'>You can only enthrall humans!</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/enthrall/proc/handle_enthrall(mob/living/user, mob/living/carbon/human/H as mob)
|
||||
if(!istype(H))
|
||||
return 0
|
||||
var/ref = "\ref[user.mind]"
|
||||
if(!(ref in SSticker.mode.vampire_thralls))
|
||||
SSticker.mode.vampire_thralls[ref] = list(H.mind)
|
||||
else
|
||||
SSticker.mode.vampire_thralls[ref] += H.mind
|
||||
|
||||
SSticker.mode.update_vampire_icons_added(H.mind)
|
||||
SSticker.mode.update_vampire_icons_added(user.mind)
|
||||
var/datum/mindslaves/slaved = user.mind.som
|
||||
H.mind.som = slaved
|
||||
slaved.serv += H
|
||||
slaved.add_serv_hud(user.mind, "vampire")//handles master servent icons
|
||||
slaved.add_serv_hud(H.mind, "vampthrall")
|
||||
|
||||
SSticker.mode.vampire_enthralled.Add(H.mind)
|
||||
SSticker.mode.vampire_enthralled[H.mind] = user.mind
|
||||
H.mind.special_role = SPECIAL_ROLE_VAMPIRE_THRALL
|
||||
|
||||
var/datum/objective/protect/serve_objective = new
|
||||
serve_objective.owner = user.mind
|
||||
serve_objective.target = H.mind
|
||||
serve_objective.explanation_text = "You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command."
|
||||
H.mind.objectives += serve_objective
|
||||
|
||||
to_chat(H, "<span class='biggerdanger'>You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command.</span>")
|
||||
to_chat(user, "<span class='warning'>You have successfully Enthralled [H]. <i>If [H.p_they()] refuse[H.p_s()] to do as you say just adminhelp.</i></span>")
|
||||
H.Stun(2)
|
||||
add_attack_logs(user, H, "Vampire-thralled")
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/cloak
|
||||
name = "Cloak of Darkness"
|
||||
desc = "Toggles whether you are currently cloaking yourself in darkness."
|
||||
gain_desc = "You have gained the Cloak of Darkness ability which when toggled makes you near invisible in the shroud of darkness."
|
||||
action_icon_state = "vampire_cloak"
|
||||
charge_max = 10
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/cloak/New()
|
||||
..()
|
||||
update_name()
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/cloak/proc/update_name()
|
||||
var/mob/living/user = loc
|
||||
if(!ishuman(user) || !user.mind || !user.mind.vampire)
|
||||
return
|
||||
name = "[initial(name)] ([user.mind.vampire.iscloaking ? "Deactivate" : "Activate"])"
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/cloak/cast(list/targets, mob/user = usr)
|
||||
var/datum/vampire/V = user.mind.vampire
|
||||
V.iscloaking = !V.iscloaking
|
||||
update_name()
|
||||
to_chat(user, "<span class='notice'>You will now be [V.iscloaking ? "hidden" : "seen"] in darkness.</span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/bats
|
||||
name = "Summon Bats (75)"
|
||||
desc = "You summon a pair of space bats who attack nearby targets until they or their target is dead."
|
||||
gain_desc = "You have gained the Summon Bats ability."
|
||||
action_icon_state = "vampire_bats"
|
||||
charge_max = 1200
|
||||
required_blood = 75
|
||||
var/num_bats = 2
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/bats/choose_targets(mob/user = usr)
|
||||
var/list/turf/locs = new
|
||||
for(var/direction in GLOB.alldirs) //looking for bat spawns
|
||||
if(locs.len == num_bats) //we found 2 locations and thats all we need
|
||||
break
|
||||
var/turf/T = get_step(usr, direction) //getting a loc in that direction
|
||||
if(AStar(user, T, /turf/proc/Distance, 1, simulated_only = 0)) // if a path exists, so no dense objects in the way its valid salid
|
||||
locs += T
|
||||
|
||||
// pad with player location
|
||||
for(var/i = locs.len + 1 to num_bats)
|
||||
locs += user.loc
|
||||
|
||||
perform(locs, user = user)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/bats/cast(list/targets, mob/user = usr)
|
||||
for(var/T in targets)
|
||||
new /mob/living/simple_animal/hostile/scarybat(T, user)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/jaunt
|
||||
name = "Mist Form (30)"
|
||||
desc = "You take on the form of mist for a short period of time."
|
||||
gain_desc = "You have gained the Mist Form ability which allows you to take on the form of mist for a short period and pass over any obstacle in your path."
|
||||
action_icon_state = "mist"
|
||||
charge_max = 600
|
||||
required_blood = 30
|
||||
centcom_cancast = 0
|
||||
var/jaunt_duration = 50 //in deciseconds
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/jaunt/cast(list/targets, mob/user = usr)
|
||||
spawn(0)
|
||||
var/mob/living/U = user
|
||||
var/originalloc = get_turf(user.loc)
|
||||
var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt(originalloc)
|
||||
var/atom/movable/overlay/animation = new /atom/movable/overlay(originalloc)
|
||||
animation.name = "blood"
|
||||
animation.density = 0
|
||||
animation.anchored = 1
|
||||
animation.icon = 'icons/mob/mob.dmi'
|
||||
animation.icon_state = "empty"
|
||||
animation.layer = 5
|
||||
animation.master = holder
|
||||
U.ExtinguishMob()
|
||||
flick("mist", animation)
|
||||
user.forceMove(holder)
|
||||
user.client.eye = holder
|
||||
sleep(jaunt_duration)
|
||||
var/mobloc = get_turf(user.loc)
|
||||
animation.loc = mobloc
|
||||
user.canmove = 0
|
||||
sleep(20)
|
||||
flick("mist_reappear", animation)
|
||||
sleep(5)
|
||||
if(!user.Move(mobloc))
|
||||
for(var/turf/T in orange(7, mobloc))
|
||||
if(T)
|
||||
if(user.Move(T))
|
||||
break
|
||||
user.canmove = 1
|
||||
user.client.eye = user
|
||||
qdel(animation)
|
||||
qdel(holder)
|
||||
|
||||
// Blink for vamps
|
||||
// Less smoke spam.
|
||||
/obj/effect/proc_holder/spell/vampire/shadowstep
|
||||
name = "Shadowstep (30)"
|
||||
desc = "Vanish into the shadows."
|
||||
gain_desc = "You have gained the ability to shadowstep, which makes you disappear into nearby shadows at the cost of blood."
|
||||
action_icon_state = "shadowblink"
|
||||
charge_max = 20
|
||||
required_blood = 30
|
||||
centcom_cancast = 0
|
||||
|
||||
// Teleport radii
|
||||
var/inner_tele_radius = 0
|
||||
var/outer_tele_radius = 6
|
||||
// Maximum lighting_lumcount.
|
||||
var/max_lum = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/shadowstep/choose_targets(mob/user = usr)
|
||||
var/list/turfs = new/list()
|
||||
for(var/turf/T in range(user, outer_tele_radius))
|
||||
if(T in range(user, inner_tele_radius))
|
||||
continue
|
||||
if(istype(T, /turf/space))
|
||||
continue
|
||||
if(T.density)
|
||||
continue
|
||||
if(T.x > world.maxx-outer_tele_radius || T.x < outer_tele_radius)
|
||||
continue //putting them at the edge is dumb
|
||||
if(T.y > world.maxy-outer_tele_radius || T.y < outer_tele_radius)
|
||||
continue
|
||||
|
||||
var/lightingcount = T.get_lumcount(0.5) * 10
|
||||
|
||||
// LIGHTING CHECK
|
||||
if(lightingcount > max_lum)
|
||||
continue
|
||||
turfs += T
|
||||
|
||||
if(!turfs.len)
|
||||
revert_cast(user)
|
||||
to_chat(user, "<span class='warning'>You cannot find darkness to step to.</span>")
|
||||
return
|
||||
|
||||
turfs = list(pick(turfs)) // Pick a single turf for the vampire to jump to.
|
||||
perform(turfs, user = user)
|
||||
|
||||
// `targets` should only ever contain the 1 valid turf we're jumping to, even though its a list, that's just how the cast() proc works.
|
||||
/obj/effect/proc_holder/spell/vampire/shadowstep/cast(list/targets, mob/user = usr)
|
||||
spawn(0)
|
||||
if(!LAZYLEN(targets)) // If for some reason the turf got deleted.
|
||||
return
|
||||
var/mob/living/U = user
|
||||
U.ExtinguishMob()
|
||||
var/atom/movable/overlay/animation = new /atom/movable/overlay(get_turf(user))
|
||||
animation.name = user.name
|
||||
animation.density = 0
|
||||
animation.anchored = 1
|
||||
animation.icon = user.icon
|
||||
animation.alpha = 127
|
||||
animation.layer = 5
|
||||
//animation.master = src
|
||||
user.forceMove(targets[1])
|
||||
spawn(10)
|
||||
qdel(animation)
|
||||
|
||||
/datum/vampire_passive/regen
|
||||
gain_desc = "Your rejuvination abilities have improved and will now heal you over time when used."
|
||||
|
||||
/datum/vampire_passive/vision
|
||||
gain_desc = "Your vampiric vision has improved."
|
||||
|
||||
/datum/vampire_passive/full
|
||||
gain_desc = "You have reached your full potential and are no longer weak to the effects of anything holy and your vision has been improved greatly."
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires
|
||||
name = "Raise Vampires"
|
||||
desc = "Summons deadly vampires from bluespace."
|
||||
school = "transmutation"
|
||||
charge_max = 100
|
||||
clothes_req = 0
|
||||
human_req = 1
|
||||
invocation = "none"
|
||||
invocation_type = "none"
|
||||
max_targets = 0
|
||||
range = 3
|
||||
cooldown_min = 20
|
||||
action_icon_state = "revive_thrall"
|
||||
sound = 'sound/magic/wandodeath.ogg'
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires/cast(list/targets, mob/user = usr)
|
||||
new /obj/effect/temp_visual/cult/sparks(user.loc)
|
||||
var/turf/T = get_turf(user)
|
||||
to_chat(user, "<span class='warning'>You call out within bluespace, summoning more vampiric spirits to aid you!</span>")
|
||||
for(var/mob/living/carbon/human/H in targets)
|
||||
T.Beam(H, "sendbeam", 'icons/effects/effects.dmi', time=30, maxdistance=7, beam_type=/obj/effect/ebeam)
|
||||
new /obj/effect/temp_visual/cult/sparks(H.loc)
|
||||
H.raise_vampire(user)
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/raise_vampire(mob/M)
|
||||
if(!istype(M))
|
||||
log_debug("human/proc/raise_vampire called with invalid argument.")
|
||||
return
|
||||
if(!mind)
|
||||
visible_message("[src] looks to be too stupid to understand what is going on.")
|
||||
return
|
||||
if(dna && (NO_BLOOD in dna.species.species_traits) || dna.species.exotic_blood || !blood_volume)
|
||||
visible_message("[src] looks unfazed!")
|
||||
return
|
||||
if(mind.vampire || mind.special_role == SPECIAL_ROLE_VAMPIRE || mind.special_role == SPECIAL_ROLE_VAMPIRE_THRALL)
|
||||
visible_message("<span class='notice'>[src] looks refreshed!</span>")
|
||||
adjustBruteLoss(-60)
|
||||
adjustFireLoss(-60)
|
||||
for(var/obj/item/organ/external/E in bodyparts)
|
||||
if(prob(25))
|
||||
E.mend_fracture()
|
||||
|
||||
return
|
||||
if(stat != DEAD)
|
||||
if(IsWeakened())
|
||||
visible_message("<span class='warning'>[src] looks to be in pain!</span>")
|
||||
adjustBrainLoss(60)
|
||||
else
|
||||
visible_message("<span class='warning'>[src] looks to be stunned by the energy!</span>")
|
||||
Weaken(20)
|
||||
return
|
||||
for(var/obj/item/implant/mindshield/L in src)
|
||||
if(L && L.implanted)
|
||||
qdel(L)
|
||||
for(var/obj/item/implant/traitor/T in src)
|
||||
if(T && T.implanted)
|
||||
qdel(T)
|
||||
visible_message("<span class='warning'>[src] gets an eerie red glow in their eyes!</span>")
|
||||
var/datum/objective/protect/protect_objective = new
|
||||
protect_objective.owner = mind
|
||||
protect_objective.target = M.mind
|
||||
protect_objective.explanation_text = "Protect [M.real_name]."
|
||||
mind.objectives += protect_objective
|
||||
add_attack_logs(M, src, "Vampire-sired")
|
||||
mind.make_Vampire()
|
||||
revive()
|
||||
Weaken(20)
|
||||
@@ -0,0 +1,79 @@
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_swell
|
||||
name = "Blood Swell (30)"
|
||||
desc = "You infuse your body with blood, making you highly resistant to stuns and physical damage. However, this makes you unable to fire ranged weapons while it is active."
|
||||
gain_desc = "You have gained the ability to temporarly resist large amounts of stuns and physical damage."
|
||||
charge_max = 40 SECONDS
|
||||
required_blood = 30
|
||||
action_icon_state = "blood_swell"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_swell/cast(list/targets, mob/user)
|
||||
var/mob/living/target = targets[1]
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.apply_status_effect(STATUS_EFFECT_BLOOD_SWELL)
|
||||
|
||||
/datum/vampire_passive/blood_swell_upgrade
|
||||
gain_desc = "While blood swell is active all of your melee attacks deal increased damage."
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force
|
||||
name = "Overwhelming Force"
|
||||
desc = "When toggled you will automatically pry open doors that you bump into if you do not have access."
|
||||
gain_desc = "You have gained the ability to force open doors at a small blood cost."
|
||||
charge_max = 2 SECONDS
|
||||
action_icon_state = "OH_YEAAAAH"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force/cast(list/targets, mob/user)
|
||||
if(!HAS_TRAIT_FROM(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT))
|
||||
to_chat(user, "<span class='warning'>You feel MIGHTY!</span>")
|
||||
ADD_TRAIT(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT)
|
||||
user.status_flags &= ~CANPUSH
|
||||
user.move_resist = MOVE_FORCE_STRONG
|
||||
else
|
||||
REMOVE_TRAIT(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT)
|
||||
user.move_resist = MOVE_FORCE_DEFAULT
|
||||
user.status_flags |= CANPUSH
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_rush
|
||||
name = "Blood Rush (30)"
|
||||
desc = "Infuse yourself with blood magic to boost your movement speed."
|
||||
gain_desc = "You have gained the ability to temporarily move at high speeds."
|
||||
charge_max = 30 SECONDS
|
||||
required_blood = 30
|
||||
action_icon_state = "blood_rush"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_rush/cast(list/targets, mob/user)
|
||||
var/mob/living/target = targets[1]
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
to_chat(H, "<span class='notice'>You feel a rush of energy!</span>")
|
||||
H.apply_status_effect(STATUS_EFFECT_BLOOD_RUSH)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/charge
|
||||
name = "Charge (30)"
|
||||
desc = "You charge at wherever you click on screen, dealing large amounts of damage, stunning and destroying walls and other objects."
|
||||
gain_desc = "You can now charge at a target on screen, dealing massive damage and destroying structures."
|
||||
required_blood = 30
|
||||
charge_max = 30 SECONDS
|
||||
vampire_ability = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "vampire_charge"
|
||||
allowed_type = /atom
|
||||
range = 7
|
||||
auto_target_single = FALSE
|
||||
click_radius = -1
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/charge/can_cast(mob/user, charge_check, show_message)
|
||||
var/mob/living/L = user
|
||||
if(L.IsWeakened() || L.resting)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/charge/cast(list/targets, mob/user)
|
||||
var/target = targets[1]
|
||||
if(isliving(user))
|
||||
var/mob/living/L = user
|
||||
L.apply_status_effect(STATUS_EFFECT_CHARGING)
|
||||
L.throw_at(target, range, 1, L, FALSE, callback = CALLBACK(L, /mob/living/.proc/remove_status_effect, STATUS_EFFECT_CHARGING))
|
||||
@@ -0,0 +1,243 @@
|
||||
/obj/effect/proc_holder/spell/self/vampire/vamp_claws
|
||||
name = "Vampiric Claws (30)"
|
||||
desc = "You channel blood magics to forge deadly vampiric claws that leech blood and strike rapidly. Cannot be used if you are holding something that cannot be dropped."
|
||||
gain_desc = "You have gained the ability to forge your hands into vampiric claws."
|
||||
charge_max = 30 SECONDS
|
||||
required_blood = 30
|
||||
action_icon_state = "vampire_claws"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/vamp_claws/cast(mob/user)
|
||||
if(user.l_hand || user.r_hand)
|
||||
to_chat(user, "<span class='notice'>You drop what was in your hands as large blades spring from your fingers!</span>")
|
||||
user.drop_l_hand()
|
||||
user.drop_r_hand()
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Large blades of blood spring from your fingers!</span>")
|
||||
var/obj/item/twohanded/required/vamp_claws/claws = new /obj/item/twohanded/required/vamp_claws(user.loc)
|
||||
user.put_in_hands(claws)
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/vamp_claws/can_cast(mob/user, charge_check, show_message)
|
||||
var/mob/living/L = user
|
||||
if(L.canUnEquip(L.l_hand) && L.canUnEquip(L.r_hand))
|
||||
return ..()
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws
|
||||
name = "vampiric claws"
|
||||
desc = "A pair of eldritch claws made of living blood, they seem to flow yet they are solid"
|
||||
icon = 'icons/effects/vampire_effects.dmi'
|
||||
icon_state = "vamp_claws"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
flags = ABSTRACT | NODROP | DROPDEL
|
||||
force = 10
|
||||
force_wielded = 10
|
||||
armour_penetration = 20
|
||||
block_chance = 50
|
||||
sharp = TRUE
|
||||
attack_effect_override = ATTACK_EFFECT_CLAW
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut", "savaged", "clawed")
|
||||
sprite_sheets_inhand = list("Vox" = 'icons/mob/clothing/species/vox/held.dmi', "Drask" = 'icons/mob/clothing/species/drask/held.dmi')
|
||||
var/durability = 20
|
||||
var/blood_drain_amount = 15
|
||||
var/blood_absorbed_amount = 5
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/afterattack(atom/target, mob/user, proximity)
|
||||
if(!user.mind?.vampire)
|
||||
return
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
if(C.ckey && C.stat != DEAD && C.affects_vampire() && !(NO_BLOOD in C.dna.species.species_traits))
|
||||
C.bleed(blood_drain_amount)
|
||||
user.mind.vampire.adjust_blood(C, blood_absorbed_amount)
|
||||
durability -= 1
|
||||
if(durability <= 0)
|
||||
qdel(src)
|
||||
to_chat(user, "<span class='warning'>Your claws shatter!</span>")
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/process()
|
||||
durability -= 1
|
||||
if(durability <= 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text, final_block_chance, damage, attack_type)
|
||||
if(attack_type == PROJECTILE_ATTACK)
|
||||
final_block_chance = 0
|
||||
return ..()
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/melee_attack_chain(mob/user, atom/target, params)
|
||||
..()
|
||||
if(wielded)
|
||||
user.changeNext_move(CLICK_CD_MELEE * 0.5)
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/attack_self(mob/user)
|
||||
to_chat(user, "<span class='notice'>You dispel your claws!</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils
|
||||
name = "Blood Tendrils (10)"
|
||||
desc = "You summon blood tendrils from bluespace after a delay to ensnare people in an area, slowing them down."
|
||||
gain_desc = "You have gained the ability to summon blood tendrils to slow people down in an area that you target."
|
||||
required_blood = 10
|
||||
|
||||
vampire_ability = TRUE
|
||||
click_radius = 1
|
||||
charge_max = 30 SECONDS
|
||||
allowed_type = /atom
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "blood_tendrils"
|
||||
sound = 'sound/misc/enter_blood.ogg'
|
||||
var/area_of_affect = 1
|
||||
|
||||
selection_activated_message = "<span class='notice'>You channel blood magics to weaken the bluespace veil. <B>Left-click to cast at a target area!</B></span>"
|
||||
selection_deactivated_message = "<span class='notice'>Your magics subside.</span>"
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils/cast(list/targets, mob/user)
|
||||
var/turf/T = get_turf(targets[1]) // there should only ever be one entry in targets for this spell
|
||||
|
||||
for(var/turf/simulated/blood_turf in view(area_of_affect, T))
|
||||
if(blood_turf.density)
|
||||
continue
|
||||
new /obj/effect/temp_visual/blood_tendril(blood_turf)
|
||||
|
||||
addtimer(CALLBACK(src, .proc/apply_slowdown, T, area_of_affect, 3, user), 0.5 SECONDS)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils/proc/apply_slowdown(turf/T, distance, slowed_amount, mob/user)
|
||||
for(var/mob/living/L in view(distance, T))
|
||||
if(L.affects_vampire(user))
|
||||
L.AdjustSlowed(slowed_amount)
|
||||
L.visible_message("<span class='warning'>[L] gets ensared in blood tendrils, restricting [L.p_their()] movement!</span>")
|
||||
new /obj/effect/temp_visual/blood_tendril/long(get_turf(L))
|
||||
|
||||
/obj/effect/temp_visual/blood_tendril
|
||||
icon = 'icons/effects/vampire_effects.dmi'
|
||||
icon_state = "blood_tendril"
|
||||
duration = 1 SECONDS
|
||||
|
||||
/obj/effect/temp_visual/blood_tendril/long
|
||||
duration = 2 SECONDS
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool
|
||||
name = "Sanguine Pool (50)"
|
||||
desc = "You shift your form into a pool of blood, making you invulnerable and able to move through anything that's not a wall or space. You leave a trail of blood behind you when you do this."
|
||||
gain_desc = "You have gained the ability to shift into a pool of blood, allowing you to evade pursuers with great mobility."
|
||||
vampire_ability = TRUE
|
||||
required_blood = 50
|
||||
jaunt_duration = 3 SECONDS
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "blood_pool"
|
||||
jaunt_type_path = /obj/effect/dummy/spell_jaunt/blood_pool
|
||||
jaunt_water_effect = FALSE
|
||||
jaunt_out_type = /obj/effect/temp_visual/dir_setting/cult/phase/out
|
||||
jaunt_in_type = /obj/effect/temp_visual/dir_setting/cult/phase
|
||||
jaunt_in_time = 0
|
||||
sound1 = 'sound/misc/enter_blood.ogg'
|
||||
|
||||
/obj/effect/proc_holder/spell/blood_eruption
|
||||
name = "Blood Eruption (100)"
|
||||
desc = "Every pool of blood in 4 tiles erupts with a spike of living blood, damaging anyone stood on it."
|
||||
gain_desc = "You have gained the ability to weaponise pools of blood to damage those stood on them."
|
||||
vampire_ability = TRUE
|
||||
required_blood = 100
|
||||
charge_max = 200 SECONDS
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "blood_spikes"
|
||||
|
||||
/obj/effect/proc_holder/spell/blood_eruption/cast(list/targets, mob/user)
|
||||
for(var/mob/living/L in targets)
|
||||
var/turf/T = get_turf(L)
|
||||
var/obj/effect/decal/cleanable/blood/B = locate(/obj/effect/decal/cleanable/blood) in T
|
||||
var/obj/effect/temp_visual/blood_spike/spike = new /obj/effect/temp_visual/blood_spike(T)
|
||||
spike.color = B.basecolor
|
||||
playsound(L, 'sound/misc/demon_attack1.ogg', 50, TRUE)
|
||||
L.apply_damage(50, BRUTE, BODY_ZONE_CHEST)
|
||||
L.visible_message("<span class='warning'><b>[L] gets impaled by a spike of living blood!</b></span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/blood_eruption/choose_targets(mob/user)
|
||||
var/list/targets = list()
|
||||
for(var/mob/living/L in view(4, user))
|
||||
var/turf/T = get_turf(L)
|
||||
if(locate(/obj/effect/decal/cleanable/blood) in T)
|
||||
if(L.affects_vampire(user) && !isLivingSSD(L))
|
||||
targets.Add(L)
|
||||
|
||||
if(!length(targets))
|
||||
revert_cast(user)
|
||||
return
|
||||
|
||||
perform(targets)
|
||||
|
||||
/obj/effect/temp_visual/blood_spike
|
||||
icon = 'icons/effects/vampire_effects.dmi'
|
||||
icon_state = "bloodspike_white"
|
||||
duration = 0.3 SECONDS
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_spill
|
||||
name = "The Blood Bringers Rite"
|
||||
desc = "When toggled, everyone around you begins to bleed profusely."
|
||||
gain_desc = "You have gained the ability to rip the very life force out of people and absorb it, healing you."
|
||||
charge_max = 10 SECONDS
|
||||
action_icon_state = "blood_bringers_rite"
|
||||
required_blood = 10
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_spill/cast(list/targets, mob/user)
|
||||
var/mob/target = targets[1]
|
||||
if(!target.mind.vampire.get_ability(/datum/vampire_passive/blood_spill))
|
||||
target.mind.vampire.force_add_ability(/datum/vampire_passive/blood_spill)
|
||||
else
|
||||
for(var/datum/vampire_passive/blood_spill/B in target.mind.vampire.powers)
|
||||
target.mind.vampire.remove_ability(B)
|
||||
|
||||
/datum/vampire_passive/blood_spill
|
||||
var/max_beams = 10
|
||||
|
||||
/datum/vampire_passive/blood_spill/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/datum/vampire_passive/blood_spill/Destroy(force, ...)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/datum/vampire_passive/blood_spill/process()
|
||||
var/beam_number = 0
|
||||
var/turf/T = get_turf(owner)
|
||||
for(var/mob/living/carbon/human/H in view(7, T))
|
||||
if(NO_BLOOD in H.dna.species.species_traits)
|
||||
continue
|
||||
|
||||
if(!H.affects_vampire(owner) || H.stat)
|
||||
continue
|
||||
|
||||
var/drain_amount = rand(5, 10)
|
||||
beam_number++
|
||||
H.bleed(drain_amount)
|
||||
H.Beam(owner, icon_state = "drainbeam", time = 2 SECONDS)
|
||||
H.adjustBruteLoss(2)
|
||||
owner.heal_overall_damage(8, 2, TRUE)
|
||||
owner.adjustStaminaLoss(-15)
|
||||
owner.AdjustStunned(-1)
|
||||
owner.AdjustWeakened(-1)
|
||||
if(drain_amount == 10)
|
||||
to_chat(H, "<span class='warning'>You feel your life force draining!</b></span>")
|
||||
|
||||
if(beam_number >= max_beams)
|
||||
break
|
||||
owner.mind.vampire.bloodusable = max(owner.mind.vampire.bloodusable - 10, 0)
|
||||
if(!owner.mind.vampire.bloodusable || owner.stat == DEAD)
|
||||
owner.mind.vampire.remove_ability(src)
|
||||
@@ -0,0 +1,188 @@
|
||||
/obj/effect/proc_holder/spell/self/vampire/cloak
|
||||
name = "Cloak of Darkness"
|
||||
desc = "Toggles whether you are currently cloaking yourself in darkness. When in darkness and toggled on, you move at increased speeds."
|
||||
gain_desc = "You have gained the Cloak of Darkness ability, which when toggled makes you nearly invisible and highly agile in the shroud of darkness."
|
||||
action_icon_state = "vampire_cloak"
|
||||
charge_max = 2 SECONDS
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/cloak/New()
|
||||
..()
|
||||
update_name()
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/cloak/proc/update_name()
|
||||
var/mob/living/user = loc
|
||||
if(!ishuman(user) || !user.mind || !user.mind.vampire)
|
||||
return
|
||||
action.button.name = "[initial(name)] ([user.mind.vampire.iscloaking ? "Deactivate" : "Activate"])"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/cloak/cast(list/targets, mob/user = usr)
|
||||
var/datum/vampire/V = user.mind.vampire
|
||||
V.iscloaking = !V.iscloaking
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(V.iscloaking)
|
||||
H.physiology.burn_mod *= 1.3
|
||||
user.RegisterSignal(user, COMSIG_LIVING_IGNITED, /mob/living.proc/update_vampire_cloak)
|
||||
else
|
||||
user.UnregisterSignal(user, COMSIG_LIVING_IGNITED)
|
||||
H.physiology.burn_mod /= 1.3
|
||||
|
||||
update_name()
|
||||
to_chat(user, "<span class='notice'>You will now be [V.iscloaking ? "hidden" : "seen"] in darkness.</span>")
|
||||
|
||||
/mob/living/proc/update_vampire_cloak()
|
||||
SIGNAL_HANDLER
|
||||
mind.vampire.handle_vampire_cloak()
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/shadow_snare
|
||||
name = "Shadow Snare (20)"
|
||||
desc = "You summon a trap on the ground. When crossed it will blind the target, extinguish any lights they may have, and ensnare them."
|
||||
gain_desc = "You have gained the ability to summon a trap that will blind, ensnare, and turn off the lights of anyone who crosses it."
|
||||
charge_max = 20 SECONDS
|
||||
required_blood = 20
|
||||
vampire_ability = TRUE
|
||||
allowed_type = /turf/simulated
|
||||
click_radius = -1
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "shadow_snare"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/shadow_snare/cast(list/targets, mob/user)
|
||||
var/turf/target = targets[1]
|
||||
new /obj/item/restraints/legcuffs/beartrap/shadow_snare(target)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare
|
||||
name = "shadow snare"
|
||||
desc = "An almost transparent trap that melts into the shadows."
|
||||
alpha = 60
|
||||
armed = TRUE
|
||||
anchored = TRUE
|
||||
breakouttime = 5 SECONDS
|
||||
flags = DROPDEL
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/Crossed(AM, oldloc)
|
||||
if(!iscarbon(AM) || !armed)
|
||||
return
|
||||
var/mob/living/carbon/C = AM
|
||||
if(!C.affects_vampire()) // no parameter here so holy always protects
|
||||
return
|
||||
C.extinguish_light()
|
||||
C.EyeBlind(10)
|
||||
STOP_PROCESSING(SSobj, src) // won't wither away once you are trapped
|
||||
..()
|
||||
if(!iscarbon(loc)) // if it fails to latch onto someone for whatever reason, delete itself, we don't want unarmed ones lying around.
|
||||
qdel(src)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/attack_hand(mob/user)
|
||||
Crossed(user)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/attack_tk(mob/user)
|
||||
if(iscarbon(user))
|
||||
to_chat(user, "<span class='userdanger'>The snare sends a psychic backlash!</span>")
|
||||
user.EyeBlind(10)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/process()
|
||||
var/turf/T = get_turf(src)
|
||||
var/lighting_count = T.get_lumcount() * 10
|
||||
if(lighting_count > 2)
|
||||
obj_integrity -= 50
|
||||
|
||||
if(obj_integrity <= 0)
|
||||
visible_message("<span class='notice'>[src] withers away.</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/dark_passage
|
||||
name = "Dark Passage (30)"
|
||||
desc = "You teleport to a targeted turf."
|
||||
gain_desc = "You have gained the ability to blink a short distance towards a targeted turf."
|
||||
charge_max = 40 SECONDS
|
||||
required_blood = 30
|
||||
vampire_ability = TRUE
|
||||
allowed_type = /turf/simulated
|
||||
click_radius = 0
|
||||
centcom_cancast = FALSE
|
||||
action_icon_state = "dark_passage"
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/dark_passage/cast(list/targets, mob/user)
|
||||
var/turf/target = get_turf(targets[1])
|
||||
|
||||
new /obj/effect/temp_visual/vamp_mist_out(get_turf(user))
|
||||
|
||||
user.forceMove(target)
|
||||
|
||||
/obj/effect/temp_visual/vamp_mist_out
|
||||
duration = 2 SECONDS
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "mist"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish
|
||||
name = "Extinguish"
|
||||
desc = "You extinguish any light source in an area around you."
|
||||
gain_desc = "You have gained the ability to extinguish nearby light sources."
|
||||
charge_max = 20 SECONDS
|
||||
vampire_ability = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "vampire_extinguish"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish/cast(list/targets, mob/user = usr)
|
||||
for(var/turf/T in targets)
|
||||
T.extinguish_light()
|
||||
for(var/atom/A in T.contents)
|
||||
A.extinguish_light()
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness
|
||||
name = "Eternal Darkness"
|
||||
desc = "When toggled, you shroud the area around you in darkness and slowly lower the body temperature of people nearby."
|
||||
gain_desc = "You have gained the ability to shroud the area around you in darkness, only the strongest of lights can pierce your unholy powers."
|
||||
charge_max = 10 SECONDS
|
||||
action_icon_state = "eternal_darkness"
|
||||
required_blood = 5
|
||||
var/shroud_power = -4
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness/cast(list/targets, mob/user)
|
||||
var/mob/target = targets[1]
|
||||
if(!target.mind.vampire.get_ability(/datum/vampire_passive/eternal_darkness))
|
||||
target.mind.vampire.force_add_ability(/datum/vampire_passive/eternal_darkness)
|
||||
target.set_light(6, shroud_power, "#AAD84B")
|
||||
else
|
||||
for(var/datum/vampire_passive/eternal_darkness/E in target.mind.vampire.powers)
|
||||
target.mind.vampire.remove_ability(E)
|
||||
|
||||
/datum/vampire_passive/eternal_darkness
|
||||
gain_desc = "You surround yourself in a unnatural darkness, freezing those around you."
|
||||
|
||||
/datum/vampire_passive/eternal_darkness/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/datum/vampire_passive/eternal_darkness/Destroy(force, ...)
|
||||
owner.remove_light()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/datum/vampire_passive/eternal_darkness/process()
|
||||
for(var/mob/living/L in view(6, owner))
|
||||
if(L.affects_vampire(owner))
|
||||
L.adjust_bodytemperature(-20 * TEMPERATURE_DAMAGE_COEFFICIENT)
|
||||
|
||||
owner.mind.vampire.bloodusable = max(owner.mind.vampire.bloodusable - 5, 0)
|
||||
|
||||
if(!owner.mind.vampire.bloodusable || owner.stat == DEAD)
|
||||
owner.mind.vampire.remove_ability(src)
|
||||
|
||||
/datum/vampire_passive/xray
|
||||
gain_desc = "You can now see through walls, incase you hadn't noticed."
|
||||
@@ -0,0 +1,464 @@
|
||||
//This should hold all the vampire related powers
|
||||
/mob/living/proc/affects_vampire(mob/user)
|
||||
//Other vampires aren't affected
|
||||
if(mind?.vampire)
|
||||
return FALSE
|
||||
//Vampires who have reached their full potential can affect nearly everything
|
||||
if(user?.mind.vampire.get_ability(/datum/vampire_passive/full))
|
||||
return TRUE
|
||||
//Holy characters are resistant to vampire powers
|
||||
if(mind?.isholy)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/self/choose_targets(mob/user = usr)
|
||||
perform(list(user))
|
||||
|
||||
/obj/effect/proc_holder/spell/mob_aoe/choose_targets(mob/user = usr)
|
||||
var/list/targets[0]
|
||||
for(var/mob/living/L in view(range, user))
|
||||
if(L == user)
|
||||
continue
|
||||
targets += L
|
||||
|
||||
if(!length(targets))
|
||||
revert_cast(user)
|
||||
return
|
||||
|
||||
perform(targets, user = user)
|
||||
|
||||
/obj/effect/proc_holder/spell/proc/before_cast_vampire(list/targets)
|
||||
// sanity check before we cast
|
||||
if(!usr.mind || !usr.mind.vampire)
|
||||
targets.Cut()
|
||||
return FALSE
|
||||
|
||||
if(!required_blood)
|
||||
return
|
||||
|
||||
// enforce blood
|
||||
var/datum/vampire/vampire = usr.mind.vampire
|
||||
var/blood_cost_modifier = 1 + vampire.nullified / 100
|
||||
var/blood_cost = round(required_blood * blood_cost_modifier)
|
||||
|
||||
if(blood_cost <= vampire.bloodusable)
|
||||
if(!deduct_blood_on_cast) //don't take the blood yet if this is false!
|
||||
return
|
||||
vampire.bloodusable -= blood_cost
|
||||
SSblackbox.record_feedback("tally", "vampire_powers_used", 1, "[name]")
|
||||
to_chat(usr, "<span class='boldnotice'>You have [vampire.bloodusable] left to use.</span>")
|
||||
return TRUE
|
||||
else
|
||||
// stop!!
|
||||
targets.Cut()
|
||||
return FALSE
|
||||
|
||||
/datum/vampire_passive
|
||||
var/gain_desc
|
||||
var/mob/living/owner = null
|
||||
|
||||
/datum/vampire_passive/New()
|
||||
..()
|
||||
if(!gain_desc)
|
||||
gain_desc = "You can now use [src]."
|
||||
|
||||
/datum/vampire_passive/Destroy(force, ...)
|
||||
owner = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire
|
||||
vampire_ability = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/rejuvenate
|
||||
name = "Rejuvenate"
|
||||
desc = "Use reserve blood to enliven your body, removing any incapacitating effects."
|
||||
action_icon_state = "vampire_rejuvinate"
|
||||
charge_max = 200
|
||||
stat_allowed = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/rejuvenate/cast(list/targets, mob/user = usr)
|
||||
var/mob/living/U = user
|
||||
|
||||
U.SetWeakened(0)
|
||||
U.SetStunned(0)
|
||||
U.SetParalysis(0)
|
||||
U.SetSleeping(0)
|
||||
U.SetConfused(0)
|
||||
U.adjustStaminaLoss(-100)
|
||||
to_chat(user, "<span class='notice'>You instill your body with clean blood and remove any incapacitating effects.</span>")
|
||||
var/rejuv_bonus = U.mind.vampire.get_rejuv_bonus()
|
||||
if(rejuv_bonus)
|
||||
INVOKE_ASYNC(src, .proc/heal, U, rejuv_bonus)
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/rejuvenate/proc/heal(mob/living/user, rejuv_bonus)
|
||||
for(var/i in 1 to 5)
|
||||
user.adjustBruteLoss(-2 * rejuv_bonus)
|
||||
user.adjustOxyLoss(-5 * rejuv_bonus)
|
||||
user.adjustToxLoss(-2 * rejuv_bonus)
|
||||
user.adjustFireLoss(-2 * rejuv_bonus)
|
||||
for(var/datum/reagent/R in user.reagents.reagent_list)
|
||||
if(!R.harmless)
|
||||
user.reagents.remove_reagent(R.id, 2 * rejuv_bonus)
|
||||
sleep(35)
|
||||
|
||||
/datum/vampire/proc/get_rejuv_bonus()
|
||||
var/rejuv_multiplier = 0
|
||||
if(!get_ability(/datum/vampire_passive/regen))
|
||||
return rejuv_multiplier
|
||||
|
||||
if(subclass?.improved_rejuv_healing)
|
||||
rejuv_multiplier = clamp((100 - owner.health) / 20, 1, 5) // brute and burn healing between 5 and 50
|
||||
return rejuv_multiplier
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize
|
||||
name = "Choose Specialization"
|
||||
desc = "Choose what sub-class of vampire you want to evolve into."
|
||||
gain_desc = "You can now choose what specialization of vampire you want to evolve into."
|
||||
charge_max = 2 SECONDS
|
||||
action_icon_state = "select_class"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize/cast(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "SpecMenu", "Specialisation Menu", 900, 600, master_ui, state)
|
||||
ui.set_autoupdate(FALSE)
|
||||
ui.open()
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize/ui_data(mob/user)
|
||||
var/datum/vampire/vamp = user.mind.vampire
|
||||
var/list/data = list("subclasses" = vamp.subclass)
|
||||
return data
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize/ui_act(action, list/params)
|
||||
if(..())
|
||||
return
|
||||
var/datum/vampire/vamp = usr.mind.vampire
|
||||
|
||||
if(vamp.subclass)
|
||||
vamp.upgrade_tiers -= type
|
||||
vamp.remove_ability(src)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("umbrae")
|
||||
vamp.add_subclass(SUBCLASS_UMBRAE)
|
||||
vamp.upgrade_tiers -= type
|
||||
vamp.remove_ability(src)
|
||||
if("hemomancer")
|
||||
vamp.add_subclass(SUBCLASS_HEMOMANCER)
|
||||
vamp.upgrade_tiers -= type
|
||||
vamp.remove_ability(src)
|
||||
if("gargantua")
|
||||
vamp.add_subclass(SUBCLASS_GARGANTUA)
|
||||
vamp.upgrade_tiers -= type
|
||||
vamp.remove_ability(src)
|
||||
|
||||
|
||||
/datum/vampire/proc/add_subclass(subclass_to_add, announce = TRUE)
|
||||
var/datum/vampire_subclass/new_subclass = new subclass_to_add
|
||||
subclass = new_subclass
|
||||
check_vampire_upgrade(announce)
|
||||
SSblackbox.record_feedback("nested tally", "vampire_subclasses", 1, list("[new_subclass.name]"))
|
||||
|
||||
/obj/effect/proc_holder/spell/mob_aoe/glare
|
||||
name = "Glare"
|
||||
desc = "Your eyes flash, stunning and silencing anyone infront of you. It has lesser effects for those around you."
|
||||
action_icon_state = "vampire_glare"
|
||||
charge_max = 30 SECONDS
|
||||
stat_allowed = 1
|
||||
range = 1
|
||||
vampire_ability = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
|
||||
/// No deviation at all. Flashed from the front or front-left/front-right. Alternatively, flashed in direct view.
|
||||
#define DEVIATION_NONE 3
|
||||
/// Partial deviation. Flashed from the side. Alternatively, flashed out the corner of your eyes.
|
||||
#define DEVIATION_PARTIAL 2
|
||||
/// Full deviation. Flashed from directly behind or behind-left/behind-rack. Not flashed at all.
|
||||
#define DEVIATION_FULL 1
|
||||
|
||||
/obj/effect/proc_holder/spell/mob_aoe/glare/cast(list/targets, mob/living/user = usr)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/sunglasses/blindfold))
|
||||
var/obj/item/clothing/glasses/sunglasses/blindfold/B = H.glasses
|
||||
if(B.tint)
|
||||
to_chat(user, "<span class='warning'>You're blindfolded!</span>")
|
||||
return
|
||||
user.mob_light(LIGHT_COLOR_BLOOD_MAGIC, 3, _duration = 2)
|
||||
user.visible_message("<span class='warning'>[user]'s eyes emit a blinding flash!</span>")
|
||||
|
||||
for(var/mob/living/target in targets)
|
||||
if(!target.affects_vampire(user))
|
||||
continue
|
||||
|
||||
var/deviation
|
||||
if(user.weakened || user.resting)
|
||||
deviation = DEVIATION_PARTIAL
|
||||
else
|
||||
deviation = calculate_deviation(target, user)
|
||||
|
||||
if(deviation == DEVIATION_FULL)
|
||||
target.AdjustConfused(3)
|
||||
target.adjustStaminaLoss(40)
|
||||
else if(deviation == DEVIATION_PARTIAL)
|
||||
target.Weaken(1)
|
||||
target.AdjustConfused(3)
|
||||
target.adjustStaminaLoss(40)
|
||||
else
|
||||
target.adjustStaminaLoss(120)
|
||||
target.Weaken(6)
|
||||
target.AdjustSilence(3)
|
||||
target.flash_eyes(1, TRUE, TRUE)
|
||||
to_chat(target, "<span class='warning'>You are blinded by [user]'s glare.</span>")
|
||||
add_attack_logs(user, target, "(Vampire) Glared at")
|
||||
|
||||
/obj/effect/proc_holder/spell/mob_aoe/glare/proc/calculate_deviation(mob/victim, mob/attacker)
|
||||
// Are they on the same tile? We'll return partial deviation. This may be someone flashing while lying down
|
||||
if(victim.loc == attacker.loc)
|
||||
return DEVIATION_PARTIAL
|
||||
|
||||
// If the victim was looking at the attacker, this is the direction they'd have to be facing.
|
||||
var/attacker_to_victim = get_dir(attacker, victim)
|
||||
// The victim's dir is necessarily a cardinal value.
|
||||
var/attacker_dir = attacker.dir
|
||||
|
||||
// - - -
|
||||
// - V - Attacker facing south
|
||||
// # # #
|
||||
// Attacker within 45 degrees of where the victim is facing.
|
||||
if(attacker_dir & attacker_to_victim)
|
||||
return DEVIATION_NONE
|
||||
|
||||
// # # #
|
||||
// - V - Attacker facing south
|
||||
// - - -
|
||||
// Victim at 135 or more degrees of where the victim is facing.
|
||||
if(attacker_dir & GetOppositeDir(attacker_to_victim))
|
||||
return DEVIATION_FULL
|
||||
|
||||
// - - -
|
||||
// # V # Attacker facing south
|
||||
// - - -
|
||||
// Victim lateral to the victim.
|
||||
return DEVIATION_PARTIAL
|
||||
|
||||
#undef DEVIATION_NONE
|
||||
#undef DEVIATION_PARTIAL
|
||||
#undef DEVIATION_FULL
|
||||
|
||||
/datum/vampire_passive/regen
|
||||
gain_desc = "Your rejuvenation abilities have improved and will now heal you over time when used."
|
||||
|
||||
/datum/vampire_passive/vision
|
||||
gain_desc = "Your vampiric vision has improved."
|
||||
|
||||
/datum/vampire_passive/full
|
||||
gain_desc = "You have reached your full potential. You are no longer weak to the effects of anything holy and your vision has improved greatly."
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires
|
||||
name = "Raise Vampires"
|
||||
desc = "Summons deadly vampires from bluespace."
|
||||
school = "transmutation"
|
||||
charge_max = 100
|
||||
clothes_req = 0
|
||||
human_req = 1
|
||||
invocation = "none"
|
||||
invocation_type = "none"
|
||||
max_targets = 0
|
||||
range = 3
|
||||
cooldown_min = 20
|
||||
action_icon_state = "revive_thrall"
|
||||
vampire_ability = TRUE
|
||||
sound = 'sound/magic/wandodeath.ogg'
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
gain_desc = "You have gained the ability to Raise Vampires. This extremely powerful AOE ability affects all humans near you. Vampires/thralls are healed. Corpses are raised as vampires. Others are stunned, then brain damaged, then killed."
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires/cast(list/targets, mob/user = usr)
|
||||
new /obj/effect/temp_visual/cult/sparks(user.loc)
|
||||
var/turf/T = get_turf(user)
|
||||
to_chat(user, "<span class='warning'>You call out within bluespace, summoning more vampiric spirits to aid you!</span>")
|
||||
for(var/mob/living/carbon/human/H in targets)
|
||||
T.Beam(H, "sendbeam", 'icons/effects/effects.dmi', time = 30, maxdistance = 7, beam_type = /obj/effect/ebeam)
|
||||
new /obj/effect/temp_visual/cult/sparks(H.loc)
|
||||
raise_vampire(user, H)
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires/proc/raise_vampire(mob/M, mob/living/carbon/human/H)
|
||||
if(!istype(M) || !istype(H))
|
||||
return
|
||||
if(!H.mind)
|
||||
visible_message("[H] looks to be too stupid to understand what is going on.")
|
||||
return
|
||||
if(H.dna && (NO_BLOOD in H.dna.species.species_traits) || H.dna.species.exotic_blood || !H.blood_volume)
|
||||
visible_message("[H] looks unfazed!")
|
||||
return
|
||||
if(H.mind.vampire || H.mind.special_role == SPECIAL_ROLE_VAMPIRE || H.mind.special_role == SPECIAL_ROLE_VAMPIRE_THRALL)
|
||||
visible_message("<span class='notice'>[H] looks refreshed!</span>")
|
||||
H.adjustBruteLoss(-60)
|
||||
H.adjustFireLoss(-60)
|
||||
for(var/obj/item/organ/external/E in H.bodyparts)
|
||||
if(prob(25))
|
||||
E.mend_fracture()
|
||||
E.internal_bleeding = FALSE
|
||||
|
||||
return
|
||||
if(H.stat != DEAD)
|
||||
if(H.IsWeakened())
|
||||
visible_message("<span class='warning'>[H] looks to be in pain!</span>")
|
||||
H.adjustBrainLoss(60)
|
||||
else
|
||||
visible_message("<span class='warning'>[H] looks to be stunned by the energy!</span>")
|
||||
H.Weaken(20)
|
||||
return
|
||||
for(var/obj/item/implant/mindshield/L in H)
|
||||
if(L && L.implanted)
|
||||
qdel(L)
|
||||
for(var/obj/item/implant/traitor/T in H)
|
||||
if(T && T.implanted)
|
||||
qdel(T)
|
||||
visible_message("<span class='warning'>[H] gets an eerie red glow in their eyes!</span>")
|
||||
var/datum/objective/protect/protect_objective = new
|
||||
protect_objective.owner = H.mind
|
||||
protect_objective.target = M.mind
|
||||
protect_objective.explanation_text = "Protect [M.real_name]."
|
||||
H.mind.objectives += protect_objective
|
||||
add_attack_logs(M, H, "Vampire-sired")
|
||||
H.mind.make_vampire()
|
||||
H.revive()
|
||||
H.Weaken(20)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/turf_teleport/shadow_step
|
||||
name = "Shadow Step (30)"
|
||||
desc = "Teleport to a nearby dark region"
|
||||
gain_desc = "You have gained the ability to shadowstep, which makes you disappear into nearby shadows at the cost of blood."
|
||||
action_icon_state = "shadowblink"
|
||||
charge_max = 20
|
||||
required_blood = 30
|
||||
centcom_cancast = FALSE
|
||||
vampire_ability = TRUE
|
||||
include_space = FALSE
|
||||
range = -1
|
||||
include_user = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
|
||||
// Teleport radii
|
||||
inner_tele_radius = 0
|
||||
outer_tele_radius = 6
|
||||
|
||||
include_light_turfs = FALSE
|
||||
|
||||
sound1 = null
|
||||
sound2 = null
|
||||
|
||||
// pure adminbus at the moment
|
||||
/proc/isvampirethrall(mob/living/M)
|
||||
return istype(M) && M.mind && SSticker.mode && (M.mind in SSticker.mode.vampire_enthralled)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/enthrall
|
||||
name = "Enthrall (150)"
|
||||
desc = "You use a large portion of your power to sway those loyal to none to be loyal to you only."
|
||||
gain_desc = "You have gained the ability to thrall people to your will."
|
||||
action_icon_state = "vampire_enthrall"
|
||||
required_blood = 150
|
||||
deduct_blood_on_cast = FALSE
|
||||
vampire_ability = TRUE
|
||||
humans_only = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets, mob/user = usr)
|
||||
var/datum/vampire/vampire = user.mind.vampire
|
||||
for(var/mob/living/target in targets)
|
||||
user.visible_message("<span class='warning'>[user] bites [target]'s neck!</span>", "<span class='warning'>You bite [target]'s neck and begin the flow of power.</span>")
|
||||
to_chat(target, "<span class='warning'>You feel the tendrils of evil invade your mind.</span>")
|
||||
if(do_mob(user, target, 50))
|
||||
if(can_enthrall(user, target))
|
||||
handle_enthrall(user, target)
|
||||
var/blood_cost_modifier = 1 + vampire.nullified/100
|
||||
var/blood_cost = round(required_blood * blood_cost_modifier)
|
||||
vampire.bloodusable -= blood_cost //we take the blood after enthralling, not before
|
||||
else
|
||||
revert_cast(user)
|
||||
to_chat(user, "<span class='warning'>You or your target either moved or you dont have enough usable blood.</span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/enthrall/proc/can_enthrall(mob/living/user, mob/living/carbon/C)
|
||||
var/enthrall_safe = 0
|
||||
for(var/obj/item/implant/mindshield/L in C)
|
||||
if(L && L.implanted)
|
||||
enthrall_safe = 1
|
||||
break
|
||||
for(var/obj/item/implant/traitor/T in C)
|
||||
if(T && T.implanted)
|
||||
enthrall_safe = 1
|
||||
break
|
||||
if(!C)
|
||||
log_runtime(EXCEPTION("something bad happened on enthralling a mob, attacker is [user] [user.key] \ref[user]"), user)
|
||||
return FALSE
|
||||
if(!C.mind)
|
||||
to_chat(user, "<span class='warning'>[C.name]'s mind is not there for you to enthrall.</span>")
|
||||
return FALSE
|
||||
if(enthrall_safe || (C.mind in SSticker.mode.vampires) || (C.mind.vampire) || (C.mind in SSticker.mode.vampire_enthralled))
|
||||
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>You feel a familiar sensation in your skull that quickly dissipates.</span>")
|
||||
return FALSE
|
||||
if(!C.affects_vampire(user))
|
||||
if(C.mind.isholy)
|
||||
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>Your faith in [SSticker.Bible_deity_name] has kept your mind clear of all evil.</span>")
|
||||
else
|
||||
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>You resist the attack on your mind.</span>")
|
||||
return FALSE
|
||||
if(!ishuman(C))
|
||||
to_chat(user, "<span class='warning'>You can only enthrall sentient humanoids!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/enthrall/proc/handle_enthrall(mob/living/user, mob/living/carbon/human/H)
|
||||
if(!istype(H))
|
||||
return 0
|
||||
var/ref = "\ref[user.mind]"
|
||||
if(!(ref in SSticker.mode.vampire_thralls))
|
||||
SSticker.mode.vampire_thralls[ref] = list(H.mind)
|
||||
else
|
||||
SSticker.mode.vampire_thralls[ref] += H.mind
|
||||
SSticker.mode.update_vampire_icons_added(H.mind)
|
||||
SSticker.mode.update_vampire_icons_added(user.mind)
|
||||
var/datum/mindslaves/slaved = user.mind.som
|
||||
if(!slaved)
|
||||
slaved = new()
|
||||
slaved.masters = user.mind
|
||||
H.mind.som = slaved
|
||||
slaved.serv += H
|
||||
slaved.add_serv_hud(user.mind, "vampire")//handles master servent icons
|
||||
slaved.add_serv_hud(H.mind, "vampthrall")
|
||||
|
||||
SSticker.mode.vampire_enthralled.Add(H.mind)
|
||||
SSticker.mode.vampire_enthralled[H.mind] = user.mind
|
||||
H.mind.special_role = SPECIAL_ROLE_VAMPIRE_THRALL
|
||||
|
||||
var/datum/objective/protect/serve_objective = new
|
||||
serve_objective.owner = user.mind
|
||||
serve_objective.target = H.mind
|
||||
serve_objective.explanation_text = "You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command."
|
||||
H.mind.objectives += serve_objective
|
||||
|
||||
to_chat(H, "<span class='biggerdanger'>You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command.</span>")
|
||||
to_chat(user, "<span class='warning'>You have successfully Enthralled [H]. <i>If [H.p_they()] refuse[H.p_s()] to do as you say just adminhelp.</i></span>")
|
||||
H.Stun(2)
|
||||
add_attack_logs(user, H, "Vampire-thralled")
|
||||
@@ -0,0 +1,70 @@
|
||||
/datum/vampire_subclass
|
||||
/// The subclass' name. Used for blackbox logging.
|
||||
var/name = "yell at coderbus"
|
||||
/// A list of powers that a vampire unlocks. The value of the list entry is equal to the blood total required for the vampire to unlock it.
|
||||
var/list/standard_powers
|
||||
/// A list of the powers a vampire unlocks when it reaches full power.
|
||||
var/list/fully_powered_abilities
|
||||
/// Whether or not a vampire heals more based on damage taken.
|
||||
var/improved_rejuv_healing = FALSE
|
||||
|
||||
/datum/vampire_subclass/proc/add_subclass_ability(datum/vampire/vamp)
|
||||
for(var/thing in standard_powers)
|
||||
if(vamp.bloodtotal >= standard_powers[thing])
|
||||
vamp.add_ability(thing)
|
||||
|
||||
/datum/vampire_subclass/proc/add_full_power_abilities(datum/vampire/vamp)
|
||||
for(var/thing in fully_powered_abilities)
|
||||
vamp.add_ability(thing)
|
||||
|
||||
/datum/vampire_subclass/umbrae
|
||||
name = "umbrae"
|
||||
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/cloak = 150,
|
||||
/obj/effect/proc_holder/spell/targeted/click/shadow_snare = 250,
|
||||
/obj/effect/proc_holder/spell/targeted/click/dark_passage = 400,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish = 600)
|
||||
fully_powered_abilities = list(/datum/vampire_passive/full,
|
||||
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness,
|
||||
/datum/vampire_passive/xray)
|
||||
|
||||
/datum/vampire_subclass/hemomancer
|
||||
name = "hemomancer"
|
||||
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/vamp_claws = 150,
|
||||
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils = 250,
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool = 400,
|
||||
/obj/effect/proc_holder/spell/blood_eruption = 600)
|
||||
fully_powered_abilities = list(/datum/vampire_passive/full,
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_spill)
|
||||
|
||||
/datum/vampire_subclass/gargantua
|
||||
name = "gargantua"
|
||||
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/blood_swell = 150,
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_rush = 250,
|
||||
/datum/vampire_passive/blood_swell_upgrade = 400,
|
||||
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force = 600)
|
||||
fully_powered_abilities = list(/datum/vampire_passive/full,
|
||||
/obj/effect/proc_holder/spell/targeted/click/charge)
|
||||
improved_rejuv_healing = TRUE
|
||||
|
||||
/datum/vampire_subclass/ancient
|
||||
name = "ancient"
|
||||
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/vamp_claws,
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_swell,
|
||||
/obj/effect/proc_holder/spell/self/vampire/cloak,
|
||||
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils,
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_rush,
|
||||
/obj/effect/proc_holder/spell/targeted/click/shadow_snare,
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool,
|
||||
/datum/vampire_passive/blood_swell_upgrade,
|
||||
/obj/effect/proc_holder/spell/targeted/click/dark_passage,
|
||||
/obj/effect/proc_holder/spell/blood_eruption,
|
||||
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish,
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires,
|
||||
/obj/effect/proc_holder/spell/targeted/enthrall,
|
||||
/datum/vampire_passive/full,
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_spill,
|
||||
/obj/effect/proc_holder/spell/targeted/click/charge,
|
||||
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness,
|
||||
/datum/vampire_passive/xray)
|
||||
improved_rejuv_healing = TRUE
|
||||
@@ -83,6 +83,10 @@
|
||||
if(!ishuman(M)) //If target is not a human
|
||||
return ..()
|
||||
|
||||
if(!M.mind)
|
||||
to_chat(user, "<span class='warning'>This being has no soul!</span>")
|
||||
return ..()
|
||||
|
||||
if(M.has_brain_worms()) //Borer stuff - RR
|
||||
to_chat(user, "<span class='warning'>This being is corrupted by an alien intelligence and cannot be soul trapped.</span>")
|
||||
return ..()
|
||||
|
||||
@@ -343,6 +343,21 @@
|
||||
playsound(get_turf(user), 'sound/effects/ghost2.ogg', 50, 1)
|
||||
return TRUE
|
||||
|
||||
/datum/spellbook_entry/summon/slience_ghosts
|
||||
name = "Silence Ghosts"
|
||||
desc = "Tired of people talking behind your back, and spooking you? Why not silence them, and make the dead deader."
|
||||
cost = 2
|
||||
log_name = "SLG"
|
||||
is_ragin_restricted = TRUE //Salt needs to flow here, to be honest
|
||||
|
||||
/datum/spellbook_entry/summon/slience_ghosts/Buy(mob/living/carbon/human/user, obj/item/spellbook/book)
|
||||
new /datum/event/wizard/ghost_mute()
|
||||
active = TRUE
|
||||
to_chat(user, "<span class='notice'>You have silenced all ghosts!</span>")
|
||||
playsound(get_turf(user), 'sound/effects/ghost.ogg', 50, 1)
|
||||
message_admins("[key_name_admin(usr)] silenced all ghosts as a wizard! (Deadchat is now DISABLED)")
|
||||
return TRUE
|
||||
|
||||
/datum/spellbook_entry/summon/guns
|
||||
name = "Summon Guns"
|
||||
desc = "Nothing could possibly go wrong with arming a crew of lunatics just itching for an excuse to kill you. There is a good chance that they will shoot each other first."
|
||||
|
||||
Reference in New Issue
Block a user