Datumized vampires (#17166)

Co-authored-by: Farie82 <farie82@users.noreply.github.com>
Co-authored-by: dearmochi <1496804+dearmochi@users.noreply.github.com>
This commit is contained in:
Charlie
2022-01-18 21:16:09 +01:00
committed by GitHub
co-authored by Farie82 dearmochi
parent b2704e06b2
commit a0e5d6df44
33 changed files with 626 additions and 759 deletions
@@ -253,7 +253,7 @@
if(has_guardian(user))
to_chat(user, "You already have a [mob_name]!")
return
if(user.mind && (user.mind.changeling || user.mind.vampire))
if(user.mind && (user.mind.changeling || user.mind.has_antag_datum(/datum/antagonist/vampire)))
to_chat(user, "[ling_failure]")
return
if(used == TRUE)
+9 -3
View File
@@ -607,6 +607,11 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
return stolen_count >= 5
/datum/objective/blood
/datum/objective/blood/New()
gen_amount_goal()
. = ..()
/datum/objective/blood/proc/gen_amount_goal(low = 150, high = 400)
target_amount = rand(low,high)
target_amount = round(round(target_amount/5)*5)
@@ -614,10 +619,11 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
return target_amount
/datum/objective/blood/check_completion()
if(owner && owner.vampire && owner.vampire.bloodtotal && owner.vampire.bloodtotal >= target_amount)
return 1
var/datum/antagonist/vampire/V = owner.has_antag_datum(/datum/antagonist/vampire)
if(V.bloodtotal >= target_amount)
return TRUE
else
return 0
return FALSE
// Traders
+7 -16
View File
@@ -10,6 +10,7 @@
recommended_enemies = 3
secondary_enemies_scaling = 0.025
secondary_protected_species = list("Machine")
var/list/datum/mind/pre_vampires = list()
/datum/game_mode/traitor/vampire/announce()
to_chat(world, "<B>The current game mode is - Traitor+Vampire!</B>")
@@ -29,28 +30,18 @@
if(possible_vampires.len > 0)
for(var/I in possible_vampires)
if(length(vampires) >= secondary_enemies)
if(length(pre_vampires) >= secondary_enemies)
break
var/datum/mind/vampire = pick(possible_vampires)
vampires += vampire
modePlayer += vampires
possible_vampires -= vampire
var/datum/mindslaves/slaved = new()
slaved.masters += vampire
vampire.som = slaved //we MIGHT want to mindslave someone
vampire.restricted_roles = (restricted_jobs + secondary_restricted_jobs)
var/datum/mind/vampire = pick_n_take(possible_vampires)
pre_vampires += vampire
vampire.special_role = SPECIAL_ROLE_VAMPIRE
vampire.restricted_roles = (restricted_jobs + secondary_restricted_jobs)
..()
return 1
else
return 0
/datum/game_mode/traitor/vampire/post_setup()
for(var/datum/mind/vampire in vampires)
grant_vampire_powers(vampire.current)
vampire.special_role = SPECIAL_ROLE_VAMPIRE
forge_vampire_objectives(vampire)
greet_vampire(vampire)
update_vampire_icons_added(vampire)
for(var/datum/mind/vampire in pre_vampires)
vampire.add_antag_datum(/datum/antagonist/vampire)
..()
-535
View File
@@ -1,535 +0,0 @@
/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() //vampires controlling somebody
/datum/game_mode/vampire
name = "vampire"
config_tag = "vampire"
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Blueshield", "Nanotrasen Representative", "Magistrate", "Chaplain", "Internal Affairs Agent", "Nanotrasen Navy Officer", "Special Operations Officer", "Syndicate Officer", "Solar Federation General")
protected_species = list("Machine")
required_players = 15
required_enemies = 1
recommended_enemies = 4
var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time
var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target
var/const/prob_right_murder_target_h = 50 // upper bound on probability of naimg the right assassination target
var/const/prob_int_item = 50 // intercept names the theft target half the time
var/const/prob_right_item_l = 25 // lower bound on probability of naming right theft target
var/const/prob_right_item_h = 50 // upper bound on probability of naming the right theft target
var/const/prob_int_sab_target = 50 // intercept names the sabotage target half the time
var/const/prob_right_sab_target_l = 25 // lower bound on probability of naming right sabotage target
var/const/prob_right_sab_target_h = 50 // upper bound on probability of naming right sabotage target
var/const/prob_right_killer_l = 25 //lower bound on probability of naming the right operative
var/const/prob_right_killer_h = 50 //upper bound on probability of naming the right operative
var/const/prob_right_objective_l = 25 //lower bound on probability of determining the objective correctly
var/const/prob_right_objective_h = 50 //upper bound on probability of determining the objective correctly
var/vampire_amount = 4
/datum/game_mode/vampire/announce()
to_chat(world, "<B>The current game mode is - Vampires!</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()
if(GLOB.configuration.gamemode.prevent_mindshield_antags)
restricted_jobs += protected_jobs
var/list/datum/mind/possible_vampires = get_players_for_role(ROLE_VAMPIRE)
vampire_amount = 1 + round(num_players() / 10)
if(possible_vampires.len>0)
for(var/i = 0, i < vampire_amount, i++)
if(!possible_vampires.len) break
var/datum/mind/vampire = pick(possible_vampires)
possible_vampires -= vampire
vampires += vampire
vampire.restricted_roles = restricted_jobs
modePlayer += vampires
var/datum/mindslaves/slaved = new()
slaved.masters += vampire
vampire.som = slaved //we MIGT want to mindslave someone
vampire.special_role = SPECIAL_ROLE_VAMPIRE
..()
return 1
else
return 0
/datum/game_mode/vampire/post_setup()
for(var/datum/mind/vampire in vampires)
grant_vampire_powers(vampire.current)
forge_vampire_objectives(vampire)
greet_vampire(vampire)
update_vampire_icons_added(vampire)
..()
/datum/game_mode/proc/auto_declare_completion_vampire()
if(vampires.len)
var/text = "<FONT size = 2><B>The vampires were:</B></FONT>"
for(var/datum/mind/vampire in vampires)
var/traitorwin = 1
text += "<br>[vampire.key] was [vampire.name] ("
if(vampire.current)
if(vampire.current.stat == DEAD)
text += "died"
else
text += "survived"
if(vampire.vampire.subclass)
text += " as a [vampire.vampire.subclass.name]"
else
text += "body destroyed"
text += ")"
var/list/all_objectives = vampire.get_all_objectives()
if(length(all_objectives))//If the traitor had no objectives, don't need to process this.
var/count = 1
for(var/datum/objective/objective in all_objectives)
if(objective.check_completion())
text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='green'><B>Success!</B></font>"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
else
text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='red'>Fail.</font>"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "FAIL"))
traitorwin = 0
count++
var/special_role_text
if(vampire.special_role)
special_role_text = lowertext(vampire.special_role)
else
special_role_text = "antagonist"
if(traitorwin)
text += "<br><font color='green'><B>The [special_role_text] was successful!</B></font>"
SSblackbox.record_feedback("tally", "traitor_success", 1, "SUCCESS")
else
text += "<br><font color='red'><B>The [special_role_text] has failed!</B></font>"
SSblackbox.record_feedback("tally", "traitor_success", 1, "FAIL")
to_chat(world, text)
return 1
/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)
text += "died"
else
text += "survived"
if(mind.current.real_name != mind.name)
text += " as [mind.current.real_name]"
else
text += "body destroyed"
text += ")"
to_chat(world, text)
return 1
/datum/game_mode/proc/forge_vampire_objectives(datum/mind/vampire)
//Objectives are traitor objectives plus blood objectives
var/datum/objective/blood/blood_objective = new
blood_objective.owner = vampire
blood_objective.gen_amount_goal(150, 400)
vampire.objectives += blood_objective
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = vampire
kill_objective.find_target()
vampire.objectives += kill_objective
var/datum/objective/steal/steal_objective = new
steal_objective.owner = vampire
steal_objective.find_target()
vampire.objectives += steal_objective
switch(rand(1,100))
if(1 to 80)
if(!(locate(/datum/objective/escape) in vampire.objectives))
var/datum/objective/escape/escape_objective = new
escape_objective.owner = vampire
vampire.objectives += escape_objective
else
if(!(locate(/datum/objective/survive) in vampire.objectives))
var/datum/objective/survive/survive_objective = new
survive_objective.owner = vampire
vampire.objectives += survive_objective
return
/datum/game_mode/proc/grant_vampire_powers(mob/living/carbon/vampire_mob)
if(!istype(vampire_mob) || !vampire_mob.mind)
return
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
if(you_are)
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, 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>")
if(vampire.current.mind)
if(vampire.current.mind.assigned_role == "Clown")
to_chat(vampire.current, "Your lust for blood has allowed you to overcome your clumsy nature allowing you to wield weapons without harming yourself.")
vampire.current.dna.SetSEState(GLOB.clumsyblock, FALSE)
singlemutcheck(vampire.current, GLOB.clumsyblock, MUTCHK_FORCED)
var/datum/action/innate/toggle_clumsy/A = new
A.Grant(vampire.current)
var/obj_count = 1
for(var/datum/objective/objective in vampire.objectives)
to_chat(vampire.current, "<B>Objective #[obj_count]</B>: [objective.explanation_text]")
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
var/bloodusable = 0
/// the mob tied to the vampire
var/mob/living/owner = null
/// 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/vampire/self/rejuvenate = 0,
/obj/effect/proc_holder/spell/vampire/glare = 0,
/datum/vampire_passive/vision = 100,
/obj/effect/proc_holder/spell/vampire/self/specialize = 150,
/datum/vampire_passive/regen = 200,
/obj/effect/proc_holder/spell/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 = 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.
/datum/vampire/proc/get_ability(path)
for(var/P in powers)
var/datum/power = P
if(power.type == path)
return power
return null
/datum/vampire/proc/add_ability(path)
if(!get_ability(path))
force_add_ability(path)
/datum/vampire/proc/remove_ability(ability)
if(ability && (ability in powers))
powers -= ability
owner.mind.spell_list.Remove(ability)
qdel(ability)
owner.update_sight() // Life updates conditionally, so we need to update sight here in case the vamp loses his vision based powers. Maybe one day refactor to be more OOP and on the vampire's ability datum.
/datum/vampire/proc/update_owner(mob/living/carbon/human/current) //Called when a vampire gets cloned. This updates vampire.owner to the new body.
if(current.mind && current.mind.vampire && current.mind.vampire.owner && (current.mind.vampire.owner != current))
current.mind.vampire.owner = current
/datum/vampire/proc/remove_vampire_powers()
for(var/P in powers)
remove_ability(P)
if(owner.hud_used)
var/datum/hud/hud = owner.hud_used
if(hud.vampire_blood_display)
hud.remove_vampire_hud()
owner.alpha = 255
REMOVE_TRAITS_IN(owner, "vampire")
#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/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>")
draining = null
return
add_attack_logs(owner, H, "vampirebit & is draining their blood.", ATKLOG_ALMOSTALL)
owner.visible_message("<span class='danger'>[owner] grabs [H]'s neck harshly and sinks in [owner.p_their()] fangs!</span>", "<span class='danger'>You sink your fangs into [H] and begin to drain [H.p_their()] blood.</span>", "<span class='notice'>You hear a soft puncture and a wet sucking noise.</span>")
if(!iscarbon(owner))
H.LAssailant = null
else
H.LAssailant = owner
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
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)
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)
if(H.blood_volume <= BLOOD_VOLUME_BAD && blood_volume_warning > BLOOD_VOLUME_BAD)
to_chat(owner, "<span class='danger'>Your victim's blood volume is dangerously low.</span>")
else if(H.blood_volume <= BLOOD_VOLUME_OKAY && blood_volume_warning > BLOOD_VOLUME_OKAY)
to_chat(owner, "<span class='warning'>Your victim's blood is at an unsafe level.</span>")
blood_volume_warning = H.blood_volume //Set to blood volume, so that you only get the message once
else
to_chat(owner, "<span class='warning'>You have bled your victim dry!</span>")
break
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>")
#undef BLOOD_GAINED_MODIFIER
/datum/vampire/proc/check_vampire_upgrade(announce = TRUE)
var/list/old_powers = powers.Copy()
for(var/ptype in upgrade_tiers)
var/level = upgrade_tiers[ptype]
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))
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='boldnotice'>[power.gain_desc]</span>")
/datum/game_mode/proc/remove_vampire(datum/mind/vampire_mind)
if(vampire_mind in vampires)
SSticker.mode.vampires -= vampire_mind
vampire_mind.special_role = null
vampire_mind.current.create_attack_log("<span class='danger'>De-vampired</span>")
vampire_mind.current.create_log(CONVERSION_LOG, "De-vampired")
if(vampire_mind.vampire)
vampire_mind.vampire.remove_vampire_powers()
QDEL_NULL(vampire_mind.vampire)
if(issilicon(vampire_mind.current))
to_chat(vampire_mind.current, "<span class='userdanger'>You have been turned into a robot! You can feel your powers fading away...</span>")
else
to_chat(vampire_mind.current, "<span class='userdanger'>You have been brainwashed! You are no longer a vampire.</span>")
SSticker.mode.update_vampire_icons_removed(vampire_mind)
//prepare for copypaste
/datum/game_mode/proc/update_vampire_icons_added(datum/mind/vampire_mind)
var/datum/atom_hud/antag/vamp_hud = GLOB.huds[ANTAG_HUD_VAMPIRE]
vamp_hud.join_hud(vampire_mind.current)
set_antag_hud(vampire_mind.current, ((vampire_mind in vampires) ? "hudvampire" : "hudvampirethrall"))
/datum/game_mode/proc/update_vampire_icons_removed(datum/mind/vampire_mind)
var/datum/atom_hud/antag/vampire_hud = GLOB.huds[ANTAG_HUD_VAMPIRE]
vampire_hud.leave_hud(vampire_mind.current)
set_antag_hud(vampire_mind.current, null)
/datum/game_mode/proc/remove_vampire_mind(datum/mind/vampire_mind, datum/mind/head)
//var/list/removal
if(!istype(head))
head = vampire_mind //workaround for removing a thrall's control over the enthralled
var/ref = "\ref[head]"
if(ref in vampire_thralls)
vampire_thralls[ref] -= vampire_mind
vampire_enthralled -= vampire_mind
vampire_mind.special_role = null
var/datum/mindslaves/slaved = vampire_mind.som
slaved.serv -= vampire_mind
vampire_mind.som = null
slaved.leave_serv_hud(vampire_mind)
update_vampire_icons_removed(vampire_mind)
vampire_mind.current.visible_message("<span class='userdanger'>[vampire_mind.current] looks as though a burden has been lifted!</span>", "<span class='userdanger'>The dark fog in your mind clears as you regain control of your own faculties, you are no longer a vampire thrall!</span>")
if(vampire_mind.current.hud_used)
vampire_mind.current.hud_used.remove_vampire_hud()
/datum/vampire/proc/check_sun()
var/ax = owner.x
var/ay = owner.y
for(var/i = 1 to 20)
ax += SSsun.dx
ay += SSsun.dy
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
if(T.density)
return
if(bloodusable >= 10) //burn through your blood to tank the light for a little while
to_chat(owner, "<span class='warning'>The starlight saps your strength!</span>")
bloodusable -= 10
vamp_burn(10)
else //You're in trouble, get out of the sun NOW
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)
var/datum/hud/hud = owner.hud_used
if(!hud.vampire_blood_display)
hud.vampire_blood_display = new /obj/screen()
hud.vampire_blood_display.name = "Usable Blood"
hud.vampire_blood_display.icon_state = "blood_display"
hud.vampire_blood_display.screen_loc = "WEST:6,CENTER-1:15"
hud.static_inventory += hud.vampire_blood_display
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(get_turf(owner), /turf/space))
check_sun()
if(istype(get_area(owner), /area/chapel) && !get_ability(/datum/vampire_passive/full))
vamp_burn(7)
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() * 10
if(!istype(T))
return
if(!iscloaking || owner.on_fire)
owner.alpha = 255
REMOVE_TRAIT(owner, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
return
if(light_available <= 2)
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)
switch(owner.health)
if(75 to 100)
to_chat(owner, "<span class='warning'>Your skin flakes away...</span>")
if(50 to 75)
to_chat(owner, "<span class='warning'>Your skin sizzles!</span>")
owner.adjustFireLoss(3)
else if(owner.health < 50)
if(!owner.on_fire)
to_chat(owner, "<span class='danger'>Your skin catches fire!</span>")
owner.emote("scream")
else
to_chat(owner, "<span class='danger'>You continue to burn!</span>")
owner.adjust_fire_stacks(5)
owner.IgniteMob()
return
/datum/hud/proc/remove_vampire_hud()
if(!vampire_blood_display)
return
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)
@@ -0,0 +1,118 @@
/datum/game_mode
var/list/datum/mind/vampires = list()
var/list/datum/mind/vampire_enthralled = list() //those controlled by a vampire
/datum/game_mode/vampire
name = "vampire"
config_tag = "vampire"
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Blueshield", "Nanotrasen Representative", "Magistrate", "Chaplain", "Internal Affairs Agent", "Nanotrasen Navy Officer", "Special Operations Officer", "Syndicate Officer", "Solar Federation General")
protected_species = list("Machine")
required_players = 15
required_enemies = 1
recommended_enemies = 4
///list of minds of soon to be vampires
var/list/datum/mind/pre_vampires = list()
/datum/game_mode/vampire/announce()
to_chat(world, "<B>The current game mode is - Vampires!</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()
if(GLOB.configuration.gamemode.prevent_mindshield_antags)
restricted_jobs += protected_jobs
var/list/datum/mind/possible_vampires = get_players_for_role(ROLE_VAMPIRE)
var/vampire_amount = 1 + round(num_players() / 10)
if(length(possible_vampires))
for(var/i in 1 to vampire_amount)
if(!length(possible_vampires))
break
var/datum/mind/vampire = pick_n_take(possible_vampires)
pre_vampires += vampire
vampire.special_role = SPECIAL_ROLE_VAMPIRE
vampire.restricted_roles = restricted_jobs
..()
return TRUE
else
return FALSE
/datum/game_mode/vampire/post_setup()
for(var/datum/mind/vampire in pre_vampires)
vampire.add_antag_datum(/datum/antagonist/vampire)
..()
/datum/game_mode/proc/auto_declare_completion_vampire()
if(!length(vampires))
return
var/text = "<FONT size = 2><B>The vampires were:</B></FONT>"
for(var/datum/mind/vampire in vampires)
var/traitorwin = TRUE
var/datum/antagonist/vampire/V = vampire.has_antag_datum(/datum/antagonist/vampire)
text += "<br>[vampire.key] was [vampire.name] ("
if(vampire.current)
if(vampire.current.stat == DEAD)
text += "died"
else
text += "survived"
if(V.subclass)
text += " as a [V.subclass.name]"
else
text += "body destroyed"
text += ")"
var/list/all_objectives = vampire.get_all_objectives()
if(length(all_objectives))//If the traitor had no objectives, don't need to process this.
var/count = 1
for(var/datum/objective/objective in all_objectives)
if(objective.check_completion())
text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='green'><B>Success!</B></font>"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
else
text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='red'>Fail.</font>"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "FAIL"))
traitorwin = FALSE
count++
var/special_role_text
if(vampire.special_role)
special_role_text = lowertext(vampire.special_role)
else
special_role_text = "antagonist"
if(traitorwin)
text += "<br><font color='green'><B>The [special_role_text] was successful!</B></font>"
SSblackbox.record_feedback("tally", "traitor_success", 1, "SUCCESS")
else
text += "<br><font color='red'><B>The [special_role_text] has failed!</B></font>"
SSblackbox.record_feedback("tally", "traitor_success", 1, "FAIL")
to_chat(world, text)
return TRUE
/datum/game_mode/proc/auto_declare_completion_enthralled()
if(!length(vampire_enthralled))
return
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)
text += "died"
else
text += "survived"
if(mind.current.real_name != mind.name)
text += " as [mind.current.real_name]"
else
text += "body destroyed"
text += ")"
to_chat(world, text)
return TRUE
@@ -1,74 +0,0 @@
/obj/effect/proc_holder/spell/vampire/self/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/vampire/self/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/vampire/self/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/vampire/self/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/vampire/self/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/vampire/self/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/vampire/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
action_icon_state = "vampire_charge"
/obj/effect/proc_holder/spell/vampire/charge/create_new_targeting()
return new /datum/spell_targeting/clicked_atom
/obj/effect/proc_holder/spell/vampire/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/vampire/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, targeting.range, 1, L, FALSE, callback = CALLBACK(L, /mob/living/.proc/remove_status_effect, STATUS_EFFECT_CHARGING))
@@ -1,245 +0,0 @@
/obj/effect/proc_holder/spell/vampire/self/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/vampire/self/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/vampire/self/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/vampire/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
charge_max = 30 SECONDS
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/vampire/blood_tendrils/create_new_targeting()
var/datum/spell_targeting/click/T = new
T.allowed_type = /atom
T.try_auto_target = FALSE
return T
/obj/effect/proc_holder/spell/vampire/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/vampire/blood_tendrils/proc/apply_slowdown(turf/T, distance, slowed_amount, mob/user)
for(var/mob/living/L in range(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/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."
jaunt_duration = 3 SECONDS
clothes_req = FALSE
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/ethereal_jaunt/blood_pool/create_new_handler()
var/datum/spell_handler/vampire/H = new
H.required_blood = 50
return H
/obj/effect/proc_holder/spell/vampire/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."
required_blood = 100
charge_max = 200 SECONDS
action_icon_state = "blood_spikes"
/obj/effect/proc_holder/spell/vampire/blood_eruption/create_new_targeting()
var/datum/spell_targeting/aoe/T = new
T.range = 4
T.allowed_type = /mob/living
return T
/obj/effect/proc_holder/spell/vampire/blood_eruption/valid_target(mob/living/target, user)
var/turf/T = get_turf(target)
if(locate(/obj/effect/decal/cleanable/blood) in T)
if(target.affects_vampire(user) && !isLivingSSD(target))
return TRUE
return FALSE
/obj/effect/proc_holder/spell/vampire/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/temp_visual/blood_spike
icon = 'icons/effects/vampire_effects.dmi'
icon_state = "bloodspike_white"
duration = 0.3 SECONDS
/obj/effect/proc_holder/spell/vampire/self/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/vampire/self/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)
@@ -1,193 +0,0 @@
/obj/effect/proc_holder/spell/vampire/self/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/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
action.button.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
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/vampire/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
action_icon_state = "shadow_snare"
/obj/effect/proc_holder/spell/vampire/shadow_snare/create_new_targeting()
var/datum/spell_targeting/click/T = new
T.allowed_type = /turf/simulated
T.click_radius = -1
return T
/obj/effect/proc_holder/spell/vampire/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/vampire/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
centcom_cancast = FALSE
action_icon_state = "dark_passage"
/obj/effect/proc_holder/spell/vampire/dark_passage/create_new_targeting()
var/datum/spell_targeting/click/T = new
T.click_radius = 0
T.allowed_type = /turf/simulated
return T
/obj/effect/proc_holder/spell/vampire/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/vampire/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
action_icon_state = "vampire_extinguish"
create_attack_logs = FALSE
create_custom_logs = TRUE
/obj/effect/proc_holder/spell/vampire/vamp_extinguish/create_new_targeting()
var/datum/spell_targeting/aoe/turf/T = new
return T
/obj/effect/proc_holder/spell/vampire/write_custom_logs(list/targets, mob/user)
add_attack_logs(user, null, "Extinguished all lights around them using [src]", ATKLOG_ALL)
/obj/effect/proc_holder/spell/vampire/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/vampire/self/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/vampire/self/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."
@@ -1,444 +0,0 @@
//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/vampire
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
human_req = TRUE
clothes_req = FALSE
/// How much blood this ability costs to use
var/required_blood
var/deduct_blood_on_cast = TRUE
/obj/effect/proc_holder/spell/vampire/create_new_handler()
var/datum/spell_handler/vampire/H = new
H.required_blood = required_blood
H.deduct_blood_on_cast = deduct_blood_on_cast
return H
/obj/effect/proc_holder/spell/vampire/self
/obj/effect/proc_holder/spell/vampire/self/create_new_targeting()
return new /datum/spell_targeting/self
/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/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
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/vampire/self/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/vampire/self/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/vampire/self/specialize/cast(mob/user)
ui_interact(user)
/obj/effect/proc_holder/spell/vampire/self/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/vampire/self/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/vampire/self/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/vampire/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 = TRUE
/obj/effect/proc_holder/spell/vampire/glare/create_new_targeting()
var/datum/spell_targeting/aoe/T = new
T.allowed_type = /mob/living
T.range = 1
return T
/// 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/vampire/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/vampire/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/vampire/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"
cooldown_min = 20
action_icon_state = "revive_thrall"
sound = 'sound/magic/wandodeath.ogg'
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/vampire/raise_vampires/create_new_targeting()
var/datum/spell_targeting/aoe/T = new
T.range = 3
return T
/obj/effect/proc_holder/spell/vampire/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/vampire/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.fix_internal_bleeding()
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/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
clothes_req = FALSE
centcom_cancast = FALSE
include_space = FALSE
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
/obj/effect/proc_holder/spell/turf_teleport/shadow_step/create_new_handler()
var/datum/spell_handler/vampire/H = new
H.required_blood = 30
return H
// 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/vampire/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
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
/obj/effect/proc_holder/spell/vampire/enthrall/create_new_targeting()
var/datum/spell_targeting/click/T = new
T.range = 1
T.click_radius = 0
return T
/obj/effect/proc_holder/spell/vampire/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/datum/spell_handler/vampire/V = custom_handler
var/blood_cost = V.calculate_blood_cost(vampire)
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/vampire/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/vampire/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")
@@ -1,70 +0,0 @@
/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/vampire/self/cloak = 150,
/obj/effect/proc_holder/spell/vampire/shadow_snare = 250,
/obj/effect/proc_holder/spell/vampire/dark_passage = 400,
/obj/effect/proc_holder/spell/vampire/vamp_extinguish = 600)
fully_powered_abilities = list(/datum/vampire_passive/full,
/obj/effect/proc_holder/spell/vampire/self/eternal_darkness,
/datum/vampire_passive/xray)
/datum/vampire_subclass/hemomancer
name = "hemomancer"
standard_powers = list(/obj/effect/proc_holder/spell/vampire/self/vamp_claws = 150,
/obj/effect/proc_holder/spell/vampire/blood_tendrils = 250,
/obj/effect/proc_holder/spell/ethereal_jaunt/blood_pool = 400,
/obj/effect/proc_holder/spell/vampire/blood_eruption = 600)
fully_powered_abilities = list(/datum/vampire_passive/full,
/obj/effect/proc_holder/spell/vampire/self/blood_spill)
/datum/vampire_subclass/gargantua
name = "gargantua"
standard_powers = list(/obj/effect/proc_holder/spell/vampire/self/blood_swell = 150,
/obj/effect/proc_holder/spell/vampire/self/blood_rush = 250,
/datum/vampire_passive/blood_swell_upgrade = 400,
/obj/effect/proc_holder/spell/vampire/self/overwhelming_force = 600)
fully_powered_abilities = list(/datum/vampire_passive/full,
/obj/effect/proc_holder/spell/vampire/charge)
improved_rejuv_healing = TRUE
/datum/vampire_subclass/ancient
name = "ancient"
standard_powers = list(/obj/effect/proc_holder/spell/vampire/self/vamp_claws,
/obj/effect/proc_holder/spell/vampire/self/blood_swell,
/obj/effect/proc_holder/spell/vampire/self/cloak,
/obj/effect/proc_holder/spell/vampire/blood_tendrils,
/obj/effect/proc_holder/spell/vampire/self/blood_rush,
/obj/effect/proc_holder/spell/vampire/shadow_snare,
/obj/effect/proc_holder/spell/ethereal_jaunt/blood_pool,
/datum/vampire_passive/blood_swell_upgrade,
/obj/effect/proc_holder/spell/vampire/dark_passage,
/obj/effect/proc_holder/spell/vampire/blood_eruption,
/obj/effect/proc_holder/spell/vampire/self/overwhelming_force,
/obj/effect/proc_holder/spell/vampire/vamp_extinguish,
/obj/effect/proc_holder/spell/vampire/raise_vampires,
/obj/effect/proc_holder/spell/vampire/enthrall,
/datum/vampire_passive/full,
/obj/effect/proc_holder/spell/vampire/self/blood_spill,
/obj/effect/proc_holder/spell/vampire/charge,
/obj/effect/proc_holder/spell/vampire/self/eternal_darkness,
/datum/vampire_passive/xray)
improved_rejuv_healing = TRUE