diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 0abed5f6e6f..b4555beff0b 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -53,7 +53,6 @@
var/list/antag_datums
var/datum/changeling/changeling //changeling holder
var/linglink
- var/datum/vampire/vampire //vampire holder
var/antag_hud_icon_state = null //this mind's ANTAG_HUD should have this icon_state
var/datum/atom_hud/antag/antag_hud = null //this mind's antag HUD
@@ -116,8 +115,6 @@
for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body
var/datum/antagonist/A = a
A.on_body_transfer(old_current, current)
- if(vampire)
- vampire.update_owner(new_character)
transfer_antag_huds(hud_to_transfer) //inherit the antag HUD
transfer_actions(new_character)
if(martial_art)
@@ -294,7 +291,7 @@
/datum/mind/proc/memory_edit_vampire(mob/living/carbon/human/H)
. = _memory_edit_header("vampire", list("traitorvamp"))
- if(src in SSticker.mode.vampires)
+ if(has_antag_datum(/datum/antagonist/vampire))
. += "VAMPIRE|no"
if(objectives.len==0)
. += "
Objectives are empty! Randomize!"
@@ -304,7 +301,7 @@
. += _memory_edit_role_enabled(ROLE_VAMPIRE)
/** Enthralled ***/
. += "
enthralled: "
- if(src in SSticker.mode.vampire_enthralled)
+ if(has_antag_datum(/datum/antagonist/mindslave/thrall))
. += "THRALL|no"
else
. += "thrall|NO"
@@ -404,7 +401,7 @@
. += "NO"
// Mindslave
. += "
mindslaved: "
- if(has_antag_datum(/datum/antagonist/mindslave))
+ if(has_antag_datum(/datum/antagonist/mindslave, FALSE))
. += "MINDSLAVE|no"
else
. += "mindslave|NO"
@@ -1005,33 +1002,21 @@
else if(href_list["vampire"])
switch(href_list["vampire"])
if("clear")
- if(src in SSticker.mode.vampires)
- SSticker.mode.vampires -= src
- special_role = null
- if(vampire)
- vampire.remove_vampire_powers()
- qdel(vampire)
- vampire = null
- SSticker.mode.update_vampire_icons_removed(src)
+ if(has_antag_datum(/datum/antagonist/vampire))
+ remove_antag_datum(/datum/antagonist/vampire)
to_chat(current, "You grow weak and lose your powers! You are no longer a vampire and are stuck in your current form!")
log_admin("[key_name(usr)] has de-vampired [key_name(current)]")
message_admins("[key_name_admin(usr)] has de-vampired [key_name_admin(current)]")
if("vampire")
- if(!(src in SSticker.mode.vampires))
- SSticker.mode.vampires += src
- SSticker.mode.grant_vampire_powers(current)
- SSticker.mode.update_vampire_icons_added(src)
- var/datum/mindslaves/slaved = new()
- slaved.masters += src
- som = slaved //we MIGT want to mindslave someone
- special_role = SPECIAL_ROLE_VAMPIRE
- SEND_SOUND(current, sound('sound/ambience/antag/vampalert.ogg'))
+ if(!has_antag_datum(/datum/antagonist/vampire))
+ add_antag_datum(/datum/antagonist/vampire)
to_chat(current, "Your powers have awoken. Your lust for blood grows... You are a Vampire!")
log_admin("[key_name(usr)] has vampired [key_name(current)]")
message_admins("[key_name_admin(usr)] has vampired [key_name_admin(current)]")
if("autoobjectives")
- SSticker.mode.forge_vampire_objectives(src)
+ var/datum/antagonist/vampire/V = has_antag_datum(/datum/antagonist/vampire)
+ V.give_objectives()
to_chat(usr, "The objectives for vampire [key] have been generated. You can edit them and announce manually.")
log_admin("[key_name(usr)] has automatically forged objectives for [key_name(current)]")
message_admins("[key_name_admin(usr)] has automatically forged objectives for [key_name_admin(current)]")
@@ -1039,8 +1024,8 @@
else if(href_list["vampthrall"])
switch(href_list["vampthrall"])
if("clear")
- if(src in SSticker.mode.vampire_enthralled)
- SSticker.mode.remove_vampire_mind(src)
+ if(has_antag_datum(/datum/antagonist/mindslave/thrall))
+ remove_antag_datum(/datum/antagonist/mindslave/thrall)
log_admin("[key_name(usr)] has de-vampthralled [key_name(current)]")
message_admins("[key_name_admin(usr)] has de-vampthralled [key_name_admin(current)]")
@@ -1345,7 +1330,7 @@
else if(href_list["mindslave"])
switch(href_list["mindslave"])
if("clear")
- if(has_antag_datum(/datum/antagonist/mindslave))
+ if(has_antag_datum(/datum/antagonist/mindslave, FALSE))
var/mob/living/carbon/human/H = current
for(var/i in H.contents)
if(istype(i, /obj/item/implant/traitor))
@@ -1530,7 +1515,7 @@
/datum/mind/proc/has_antag_datum(datum_type, check_subtypes = TRUE)
if(!datum_type)
- return
+ return FALSE
. = FALSE
for(var/a in antag_datums)
var/datum/antagonist/A = a
@@ -1592,15 +1577,9 @@
SSticker.mode.equip_syndicate(current)
-/datum/mind/proc/make_vampire(ancient_vampire = FALSE)
- if(!(src in SSticker.mode.vampires))
- SSticker.mode.vampires += src
- SSticker.mode.grant_vampire_powers(current)
- special_role = SPECIAL_ROLE_VAMPIRE
- SSticker.mode.greet_vampire(src)
- SSticker.mode.update_vampire_icons_added(src)
- if(!ancient_vampire)
- SSticker.mode.forge_vampire_objectives(src)
+/datum/mind/proc/make_vampire()
+ if(!has_antag_datum(/datum/antagonist/vampire))
+ add_antag_datum(/datum/antagonist/vampire)
/datum/mind/proc/make_Changeling()
if(!(src in SSticker.mode.changelings))
diff --git a/code/datums/outfits/outfit_admin.dm b/code/datums/outfits/outfit_admin.dm
index 84f870384cf..645a31023b1 100644
--- a/code/datums/outfits/outfit_admin.dm
+++ b/code/datums/outfits/outfit_admin.dm
@@ -1095,12 +1095,13 @@
apply_to_card(I, H, get_all_accesses(), "Ancient One", "data")
if(H.mind)
- if(!H.mind.vampire)
+ if(!H.mind.has_antag_datum(/datum/antagonist/vampire))
H.mind.make_vampire(TRUE)
- H.mind.vampire.bloodusable = 9999
- H.mind.vampire.bloodtotal = 9999
+ var/datum/antagonist/vampire/V = H.mind.has_antag_datum(/datum/antagonist/vampire)
+ V.bloodusable = 9999
+ V.bloodtotal = 9999
H.mind.offstation_role = TRUE
- H.mind.vampire.add_subclass(SUBCLASS_ANCIENT, FALSE)
+ V.add_subclass(SUBCLASS_ANCIENT, FALSE)
H.dna.SetSEState(GLOB.jumpblock, TRUE)
singlemutcheck(H, GLOB.jumpblock, MUTCHK_FORCED)
H.update_mutations()
diff --git a/code/datums/spell_handler/vampire.dm b/code/datums/spell_handler/vampire.dm
index 76f7c908393..200abf54433 100644
--- a/code/datums/spell_handler/vampire.dm
+++ b/code/datums/spell_handler/vampire.dm
@@ -4,7 +4,7 @@
var/deduct_blood_on_cast = TRUE
/datum/spell_handler/vampire/can_cast(mob/user, charge_check, show_message, obj/effect/proc_holder/spell/spell)
- var/datum/vampire/vampire = user.mind.vampire
+ var/datum/antagonist/vampire/vampire = user.mind.has_antag_datum(/datum/antagonist/vampire)
if(!vampire)
return FALSE
@@ -35,11 +35,11 @@
if(!required_blood || !deduct_blood_on_cast) //don't take the blood yet if this is false!
return
- var/datum/vampire/vampire = user.mind.vampire
+ var/datum/antagonist/vampire/vampire = user.mind.has_antag_datum(/datum/antagonist/vampire)
vampire.bloodusable -= calculate_blood_cost(vampire)
-/datum/spell_handler/vampire/proc/calculate_blood_cost(datum/vampire/vampire)
+/datum/spell_handler/vampire/proc/calculate_blood_cost(datum/antagonist/vampire/vampire)
var/blood_cost_modifier = 1 + vampire.nullified / 100
var/blood_cost = round(required_blood * blood_cost_modifier)
return blood_cost
@@ -47,7 +47,7 @@
/datum/spell_handler/vampire/after_cast(list/targets, mob/user, obj/effect/proc_holder/spell/spell)
if(!required_blood)
return
- var/datum/vampire/vampire = user.mind.vampire
+ var/datum/antagonist/vampire/vampire = user.mind.has_antag_datum(/datum/antagonist/vampire)
to_chat(user, "You have [vampire.bloodusable] left to use.")
SSblackbox.record_feedback("tally", "vampire_powers_used", 1, "[spell]") // Only log abilities which require blood
diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm
index 5694b0d1bc0..e40bf271ac9 100644
--- a/code/datums/status_effects/buffs.dm
+++ b/code/datums/status_effects/buffs.dm
@@ -157,7 +157,8 @@
H.physiology.burn_mod *= 0.8
H.physiology.stamina_mod *= 0.5
H.physiology.stun_mod *= 0.5
- if(owner.mind.vampire.get_ability(/datum/vampire_passive/blood_swell_upgrade))
+ var/datum/antagonist/vampire/V = owner.mind.has_antag_datum(/datum/antagonist/vampire)
+ if(V.get_ability(/datum/vampire_passive/blood_swell_upgrade))
bonus_damage_applied = TRUE
H.physiology.melee_bonus += 10
H.dna.species.punchstunthreshold += 8 //higher chance to stun but not 100%
diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm
index 6854399a95b..3d7a3ff83fd 100644
--- a/code/datums/uplink_item.dm
+++ b/code/datums/uplink_item.dm
@@ -1745,7 +1745,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
else if(!AT)
to_chat(usr, "Error: Embedded Syndicate credentials not found.")
return
- else if(mind.changeling || mind.vampire)
+ else if(mind.changeling || mind.has_antag_datum(/datum/antagonist/vampire))
to_chat(usr, "Error: Embedded Syndicate credentials contain an abnormal signature. Aborting.")
return
diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm
index beea65ec465..a4317cfce1e 100644
--- a/code/game/gamemodes/miniantags/guardian/guardian.dm
+++ b/code/game/gamemodes/miniantags/guardian/guardian.dm
@@ -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)
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 9f47adb4568..18cb6cfd9e2 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -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
diff --git a/code/game/gamemodes/vampire/traitor_vamp.dm b/code/game/gamemodes/vampire/traitor_vamp.dm
index ea42cf54720..71931b83a04 100644
--- a/code/game/gamemodes/vampire/traitor_vamp.dm
+++ b/code/game/gamemodes/vampire/traitor_vamp.dm
@@ -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, "The current game mode is - Traitor+Vampire!")
@@ -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)
..()
diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm
deleted file mode 100644
index 9cd494c3705..00000000000
--- a/code/game/gamemodes/vampire/vampire.dm
+++ /dev/null
@@ -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, "The current game mode is - Vampires!")
- to_chat(world, "There are Bluespace Vampires infesting your fellow crewmates, keep your blood close and neck safe!")
-
-/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 = "The vampires were:"
- for(var/datum/mind/vampire in vampires)
- var/traitorwin = 1
-
- text += "
[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 += "
Objective #[count]: [objective.explanation_text] Success!"
- SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
- else
- text += "
Objective #[count]: [objective.explanation_text] Fail."
- 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 += "
The [special_role_text] was successful!"
- SSblackbox.record_feedback("tally", "traitor_success", 1, "SUCCESS")
- else
- text += "
The [special_role_text] has failed!"
- 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 = "The Enthralled were:"
- for(var/datum/mind/mind in vampire_enthralled)
- text += "
[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 = "You are a Vampire!
"
- 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, "You must complete the following tasks:")
-
- 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, "Objective #[obj_count]: [objective.explanation_text]")
- obj_count++
- to_chat(vampire.current, "For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Vampire)")
- 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, "[owner.wear_mask] prevents you from biting [H]!")
- draining = null
- return
- add_attack_logs(owner, H, "vampirebit & is draining their blood.", ATKLOG_ALMOSTALL)
- owner.visible_message("[owner] grabs [H]'s neck harshly and sinks in [owner.p_their()] fangs!", "You sink your fangs into [H] and begin to drain [H.p_their()] blood.", "You hear a soft puncture and a wet sucking noise.")
- 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, "Your fangs have disappeared!")
- 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, "You have drained most of the life force from [H]'s blood, and you will get no more useable blood from them!")
- 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, "You have accumulated [bloodtotal] unit\s of blood, and have [bloodusable] left to use.")
- 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, "Your victim's blood volume is dangerously low.")
- else if(H.blood_volume <= BLOOD_VOLUME_OKAY && blood_volume_warning > BLOOD_VOLUME_OKAY)
- to_chat(owner, "Your victim's blood is at an unsafe level.")
- blood_volume_warning = H.blood_volume //Set to blood volume, so that you only get the message once
- else
- to_chat(owner, "You have bled your victim dry!")
- 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, "Feeding on [H] reduces your thirst, but you get no usable blood from them.")
- 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, "You stop draining [H.name] of blood.")
-
-#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, "[power.gain_desc]")
- else if(istype(p, /datum/vampire_passive))
- var/datum/vampire_passive/power = p
- to_chat(owner, "[power.gain_desc]")
-
-/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("De-vampired")
- 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, "You have been turned into a robot! You can feel your powers fading away...")
- else
- to_chat(vampire_mind.current, "You have been brainwashed! You are no longer a vampire.")
- 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("[vampire_mind.current] looks as though a burden has been lifted!", "The dark fog in your mind clears as you regain control of your own faculties, you are no longer a vampire thrall!")
- 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, "The starlight saps your strength!")
- bloodusable -= 10
- vamp_burn(10)
- else //You're in trouble, get out of the sun NOW
- to_chat(owner, "Your body is turning to ash, get out of the light now!")
- 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 = "
[bloodusable]
"
- 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, "Your skin flakes away...")
- if(50 to 75)
- to_chat(owner, "Your skin sizzles!")
- owner.adjustFireLoss(3)
- else if(owner.health < 50)
- if(!owner.on_fire)
- to_chat(owner, "Your skin catches fire!")
- owner.emote("scream")
- else
- to_chat(owner, "You continue to burn!")
- 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)
diff --git a/code/game/gamemodes/vampire/vampire_gamemode.dm b/code/game/gamemodes/vampire/vampire_gamemode.dm
new file mode 100644
index 00000000000..0cc14812d47
--- /dev/null
+++ b/code/game/gamemodes/vampire/vampire_gamemode.dm
@@ -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, "The current game mode is - Vampires!")
+ to_chat(world, "There are Bluespace Vampires infesting your fellow crewmates, keep your blood close and neck safe!")
+
+/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 = "The vampires were:"
+ for(var/datum/mind/vampire in vampires)
+ var/traitorwin = TRUE
+ var/datum/antagonist/vampire/V = vampire.has_antag_datum(/datum/antagonist/vampire)
+ text += "
[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 += "
Objective #[count]: [objective.explanation_text] Success!"
+ SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
+ else
+ text += "
Objective #[count]: [objective.explanation_text] Fail."
+ 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 += "
The [special_role_text] was successful!"
+ SSblackbox.record_feedback("tally", "traitor_success", 1, "SUCCESS")
+ else
+ text += "
The [special_role_text] has failed!"
+ 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 = "The Enthralled were:"
+ for(var/datum/mind/mind in vampire_enthralled)
+ text += "
[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
+
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index e67e51813c4..39eb2a982d2 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -444,10 +444,6 @@ GLOBAL_LIST_INIT(cloner_biomass_items, list(\
SSticker.mode.rise(H)
if(SSticker.mode.cult_ascendant)
SSticker.mode.ascend(H)
- if(H.mind.vampire)
- H.mind.vampire.update_owner(H)
- if((H.mind in SSticker.mode.vampire_thralls) || (H.mind in SSticker.mode.vampire_enthralled))
- SSticker.mode.update_vampire_icons_added(H.mind)
if(H.mind in SSticker.mode.changelings)
SSticker.mode.update_change_icons_added(H.mind)
if((H.mind in SSticker.mode.shadowling_thralls) || (H.mind in SSticker.mode.shadows))
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index da60b23504e..5617aa35d00 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -150,8 +150,10 @@
else
do_animate("deny")
if(HAS_TRAIT(user, TRAIT_FORCE_DOORS))
- if(user.mind?.vampire && HAS_TRAIT_FROM(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT))
- if(!user.mind.vampire.bloodusable)
+ var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire)
+
+ if(V && HAS_TRAIT_FROM(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT))
+ if(!V.bloodusable)
REMOVE_TRAIT(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT)
return
if(welded)
@@ -164,8 +166,8 @@
visible_message("[user] forces the door open!")
playsound(loc, "sparks", 100, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
open(TRUE)
- if(user.mind?.vampire && HAS_TRAIT_FROM(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT))
- user.mind.vampire.bloodusable = max(user.mind.vampire.bloodusable - 5, 0)
+ if(V && HAS_TRAIT_FROM(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT))
+ V.bloodusable = max(V.bloodusable - 5, 0)
/obj/machinery/door/attack_ai(mob/user)
return attack_hand(user)
diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm
index 680bac78ecb..fa53459f055 100644
--- a/code/game/objects/items/weapons/holy_weapons.dm
+++ b/code/game/objects/items/weapons/holy_weapons.dm
@@ -36,10 +36,11 @@
/obj/item/nullrod/attack(mob/M, mob/living/carbon/user)
..()
- if(ishuman(M) && M.mind?.vampire && user.mind.isholy)
- if(!M.mind.vampire.get_ability(/datum/vampire_passive/full))
+ var/datum/antagonist/vampire/V = M.mind?.has_antag_datum(/datum/antagonist/vampire)
+ if(ishuman(M) && V && user.mind.isholy)
+ if(!V.get_ability(/datum/vampire_passive/full))
to_chat(M, "The nullrod's power interferes with your own!")
- M.mind.vampire.adjust_nullification(30 + sanctify_force, 15 + sanctify_force)
+ V.adjust_nullification(30 + sanctify_force, 15 + sanctify_force)
/obj/item/nullrod/pickup(mob/living/user)
. = ..()
@@ -477,9 +478,9 @@
SSticker.mode.remove_cultist(target.mind, TRUE, TRUE) // This proc will handle message generation.
praying = FALSE
return
-
- if(target.mind.vampire && !target.mind.vampire.get_ability(/datum/vampire_passive/full)) // Getting a full prayer off on a vampire will interrupt their powers for a large duration.
- target.mind.vampire.adjust_nullification(120, 50)
+ var/datum/antagonist/vampire/V = M.mind?.has_antag_datum(/datum/antagonist/vampire)
+ if(V?.get_ability(/datum/vampire_passive/full)) // Getting a full prayer off on a vampire will interrupt their powers for a large duration.
+ V.adjust_nullification(120, 50)
to_chat(target, "[user]'s prayer to [SSticker.Bible_deity_name] has interfered with your power!")
praying = FALSE
return
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index fca3a4fb476..d346aec4358 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -651,9 +651,9 @@ GLOBAL_VAR_INIT(nologevent, 0)
antag_list += "Changeling"
if(M.mind in SSticker.mode.abductors)
antag_list += "Abductor"
- if(M.mind in SSticker.mode.vampires)
+ if(M.mind.has_antag_datum(/datum/antagonist/vampire))
antag_list += "Vampire"
- if(M.mind in SSticker.mode.vampire_enthralled)
+ if(M.mind.has_antag_datum(/datum/antagonist/mindslave/thrall))
antag_list += "Vampire Thrall"
if(M.mind in SSticker.mode.shadows)
antag_list += "Shadowling"
diff --git a/code/modules/antagonists/traitor/datum_mindslave.dm b/code/modules/antagonists/traitor/datum_mindslave.dm
index bad6e398980..4efa9ddaa56 100644
--- a/code/modules/antagonists/traitor/datum_mindslave.dm
+++ b/code/modules/antagonists/traitor/datum_mindslave.dm
@@ -38,7 +38,7 @@
// Update our master's HUD to give him the "M" icon.
// Basically a copy and paste of what's in [/datum/antagonist/proc/add_antag_hud] in case the master doesn't have a traitor datum.
- var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_TRAITOR]
+ var/datum/atom_hud/antag/hud = GLOB.huds[antag_hud_type]
hud.join_hud(master.current)
set_antag_hud(master.current, "hudmaster")
slaved.add_serv_hud(master, "master")
diff --git a/code/modules/antagonists/vampire/vamp_datum.dm b/code/modules/antagonists/vampire/vamp_datum.dm
new file mode 100644
index 00000000000..184c61601c1
--- /dev/null
+++ b/code/modules/antagonists/vampire/vamp_datum.dm
@@ -0,0 +1,322 @@
+/datum/antagonist/vampire
+ name = "Vampire"
+ antag_hud_type = ANTAG_HUD_VAMPIRE
+ antag_hud_name = "hudvampire"
+ special_role = SPECIAL_ROLE_VAMPIRE
+ wiki_page_name = "Vampire"
+ var/bloodtotal = 0
+ var/bloodusable = 0
+ /// 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/antagonist/mindslave/thrall
+ name = "Vampire Thrall"
+ antag_hud_type = ANTAG_HUD_VAMPIRE
+ antag_hud_name = "vampthrall"
+
+/datum/antagonist/mindslave/thrall/on_gain()
+ SSticker.mode.vampire_enthralled += owner
+ ..()
+
+/datum/antagonist/mindslave/thrall/on_removal()
+ SSticker.mode.vampire_enthralled -= owner
+ ..()
+
+/datum/antagonist/vampire/Destroy(force, ...)
+ draining = null
+ QDEL_NULL(subclass)
+ QDEL_LIST(powers)
+ return ..()
+
+/datum/antagonist/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/antagonist/vampire/proc/force_add_ability(path)
+ var/spell = new path(owner)
+ if(istype(spell, /obj/effect/proc_holder/spell))
+ owner.AddSpell(spell)
+ if(istype(spell, /datum/vampire_passive))
+ var/datum/vampire_passive/passive = spell
+ passive.owner = owner.current
+ powers += spell
+ owner.current.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/antagonist/vampire/proc/get_ability(path)
+ for(var/datum/power as anything in powers)
+ if(power.type == path)
+ return power
+ return null
+
+/datum/antagonist/vampire/proc/add_ability(path)
+ if(!get_ability(path))
+ force_add_ability(path)
+
+/datum/antagonist/vampire/proc/remove_ability(ability)
+ if(ability && (ability in powers))
+ powers -= ability
+ owner.spell_list.Remove(ability)
+ qdel(ability)
+ owner.current.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/antagonist/vampire/remove_innate_effects(mob/living/old_body)
+ var/mob/living/L = old_body || owner.current
+ for(var/P in powers)
+ remove_ability(P)
+ var/datum/hud/hud = L.hud_used
+ if(hud?.vampire_blood_display)
+ hud.remove_vampire_hud()
+ owner.current.alpha = 255
+ REMOVE_TRAITS_IN(owner.current, "vampire")
+ return ..()
+
+#define BLOOD_GAINED_MODIFIER 0.5
+
+/datum/antagonist/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.current.is_muzzled())
+ to_chat(owner.current, "[owner.current.wear_mask] prevents you from biting [H]!")
+ draining = null
+ return
+ add_attack_logs(owner.current, H, "vampirebit & is draining their blood.", ATKLOG_ALMOSTALL)
+ owner.current.visible_message("[owner] grabs [H]'s neck harshly and sinks in [owner.current.p_their()] fangs!", "You sink your fangs into [H] and begin to drain [H.p_their()] blood.", "You hear a soft puncture and a wet sucking noise.")
+ if(!iscarbon(owner.current))
+ H.LAssailant = null
+ else
+ H.LAssailant = owner
+ while(do_mob(owner.current, H, suck_rate))
+ owner.current.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.current, "You have drained most of the life force from [H]'s blood, and you will get no more useable blood from them!")
+ H.blood_volume = max(H.blood_volume - 25, 0)
+ owner.current.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.current.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.current, "You have accumulated [bloodtotal] unit\s of blood, and have [bloodusable] left to use.")
+ 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.current, "Your victim's blood volume is dangerously low.")
+ else if(H.blood_volume <= BLOOD_VOLUME_OKAY && blood_volume_warning > BLOOD_VOLUME_OKAY)
+ to_chat(owner.current, "Your victim's blood is at an unsafe level.")
+ blood_volume_warning = H.blood_volume //Set to blood volume, so that you only get the message once
+ else
+ to_chat(owner.current, "You have bled your victim dry!")
+ 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.current, "Feeding on [H] reduces your thirst, but you get no usable blood from them.")
+ owner.current.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.current.nutrition + 5))
+ else
+ owner.current.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.current.nutrition + (blood / 2)))
+
+ draining = null
+ to_chat(owner.current, "You stop draining [H.name] of blood.")
+
+#undef BLOOD_GAINED_MODIFIER
+
+/datum/antagonist/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/antagonist/vampire/proc/check_full_power_upgrade()
+ if(length(drained_humans) >= FULLPOWER_DRAINED_REQUIREMENT && bloodtotal >= FULLPOWER_BLOODTOTAL_REQUIREMENT)
+ subclass.add_full_power_abilities(src)
+
+
+/datum/antagonist/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.current, "[power.gain_desc]")
+ else if(istype(p, /datum/vampire_passive))
+ var/datum/vampire_passive/power = p
+ to_chat(owner.current, "[power.gain_desc]")
+
+/datum/antagonist/vampire/on_removal()
+ SSticker.mode.vampires -= owner
+ owner.current.create_log(CONVERSION_LOG, "De-vampired")
+ ..()
+
+/datum/antagonist/vampire/on_gain()
+ SSticker.mode.vampires += owner
+ ..()
+
+/datum/antagonist/vampire/proc/check_sun()
+ var/ax = owner.current.x
+ var/ay = owner.current.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.current.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.current, "The starlight saps your strength!")
+ bloodusable -= 10
+ vamp_burn(10)
+ else //You're in trouble, get out of the sun NOW
+ to_chat(owner.current, "Your body is turning to ash, get out of the light now!")
+ owner.current.adjustCloneLoss(10) //I'm melting!
+ vamp_burn(85)
+ if(owner.current.cloneloss >= 100)
+ owner.current.dust()
+
+/datum/antagonist/vampire/proc/handle_vampire()
+ if(owner.current.hud_used)
+ var/datum/hud/hud = owner.current.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 = "[bloodusable]
"
+ handle_vampire_cloak()
+ if(istype(get_turf(owner.current), /turf/space))
+ check_sun()
+ if(istype(get_area(owner.current), /area/chapel) && !get_ability(/datum/vampire_passive/full))
+ vamp_burn(7)
+ nullified = max(0, nullified - 2)
+
+/datum/antagonist/vampire/proc/handle_vampire_cloak()
+ if(!ishuman(owner.current))
+ owner.current.alpha = 255
+ return
+ var/turf/simulated/T = get_turf(owner.current)
+ var/light_available = T.get_lumcount() * 10
+
+ if(!istype(T))
+ return
+
+ if(!iscloaking || owner.current.on_fire)
+ owner.current.alpha = 255
+ REMOVE_TRAIT(owner.current, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
+ return
+
+ if(light_available <= 2)
+ owner.current.alpha = 38 // round(255 * 0.15)
+ ADD_TRAIT(owner.current, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
+ return
+
+ REMOVE_TRAIT(owner.current, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
+ owner.current.alpha = 204 // 255 * 0.80
+
+/datum/antagonist/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/antagonist/vampire/proc/vamp_burn(burn_chance)
+ if(prob(burn_chance) && owner.current.health >= 50)
+ switch(owner.current.health)
+ if(75 to 100)
+ to_chat(owner.current, "Your skin flakes away...")
+ if(50 to 75)
+ to_chat(owner.current, "Your skin sizzles!")
+ owner.current.adjustFireLoss(3)
+ else if(owner.current.health < 50)
+ if(!owner.current.on_fire)
+ to_chat(owner.current, "Your skin catches fire!")
+ owner.current.emote("scream")
+ else
+ to_chat(owner.current, "You continue to burn!")
+ owner.current.adjust_fire_stacks(5)
+ owner.current.IgniteMob()
+
+/datum/antagonist/vampire/vv_edit_var(var_name, var_value)
+ . = ..()
+ check_vampire_upgrade(TRUE)
+
+/datum/antagonist/vampire/give_objectives()
+ add_objective(/datum/objective/blood)
+ add_objective(/datum/objective/assassinate)
+ add_objective(/datum/objective/steal)
+
+ switch(rand(1, 100))
+ if(1 to 80)
+ add_objective(/datum/objective/survive)
+ else
+ add_objective(/datum/objective/escape)
+
+/datum/antagonist/vampire/greet()
+ var/dat
+ SEND_SOUND(owner.current, sound('sound/ambience/antag/vampalert.ogg'))
+ dat = "You are a Vampire!
"
+ 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(owner.current, dat)
+
+/datum/antagonist/vampire/apply_innate_effects(mob/living/new_body)
+ . = ..()
+ if(!owner.som) //thralls and mindslaves
+ owner.som = new()
+ owner.som.masters += owner
+
+ check_vampire_upgrade(FALSE)
+
+/datum/hud/proc/remove_vampire_hud()
+ static_inventory -= vampire_blood_display
+ QDEL_NULL(vampire_blood_display)
diff --git a/code/game/gamemodes/vampire/vampire_powers/gargantua_powers.dm b/code/modules/antagonists/vampire/vampire_powers/gargantua_powers.dm
similarity index 99%
rename from code/game/gamemodes/vampire/vampire_powers/gargantua_powers.dm
rename to code/modules/antagonists/vampire/vampire_powers/gargantua_powers.dm
index f60d71c76f9..dc6a4082533 100644
--- a/code/game/gamemodes/vampire/vampire_powers/gargantua_powers.dm
+++ b/code/modules/antagonists/vampire/vampire_powers/gargantua_powers.dm
@@ -65,7 +65,6 @@
return FALSE
return ..()
-
/obj/effect/proc_holder/spell/vampire/charge/cast(list/targets, mob/user)
var/target = targets[1]
if(isliving(user))
diff --git a/code/game/gamemodes/vampire/vampire_powers/hemomancer_powers.dm b/code/modules/antagonists/vampire/vampire_powers/hemomancer_powers.dm
similarity index 93%
rename from code/game/gamemodes/vampire/vampire_powers/hemomancer_powers.dm
rename to code/modules/antagonists/vampire/vampire_powers/hemomancer_powers.dm
index 77df8021812..cf65da1b8ea 100644
--- a/code/game/gamemodes/vampire/vampire_powers/hemomancer_powers.dm
+++ b/code/modules/antagonists/vampire/vampire_powers/hemomancer_powers.dm
@@ -43,13 +43,16 @@
var/blood_absorbed_amount = 5
/obj/item/twohanded/required/vamp_claws/afterattack(atom/target, mob/user, proximity)
- if(!user.mind?.vampire)
+ var/datum/antagonist/vampire/V = user.mind?.has_antag_datum(/datum/antagonist/vampire)
+
+ if(!V)
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)
+ V.adjust_blood(C, blood_absorbed_amount)
durability -= 1
if(durability <= 0)
qdel(src)
@@ -89,9 +92,6 @@
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
@@ -105,7 +105,6 @@
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
@@ -174,6 +173,7 @@
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)
@@ -198,12 +198,12 @@
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)
+ var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire)
+ if(!V.get_ability(/datum/vampire_passive/blood_spill))
+ V.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)
+ for(var/datum/vampire_passive/blood_spill/B in V.powers)
+ V.remove_ability(B)
/datum/vampire_passive/blood_spill
var/max_beams = 10
@@ -219,6 +219,7 @@
/datum/vampire_passive/blood_spill/process()
var/beam_number = 0
var/turf/T = get_turf(owner)
+ var/datum/antagonist/vampire/V = owner.mind.has_antag_datum(/datum/antagonist/vampire)
for(var/mob/living/carbon/human/H in view(7, T))
if(NO_BLOOD in H.dna.species.species_traits)
continue
@@ -240,6 +241,6 @@
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)
+ V.bloodusable = max(V.bloodusable - 10, 0)
+ if(!V.bloodusable || owner.stat == DEAD)
+ V.remove_ability(src)
diff --git a/code/game/gamemodes/vampire/vampire_powers/umbrae_powers.dm b/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm
similarity index 87%
rename from code/game/gamemodes/vampire/vampire_powers/umbrae_powers.dm
rename to code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm
index e16950b37f4..13cbf223740 100644
--- a/code/game/gamemodes/vampire/vampire_powers/umbrae_powers.dm
+++ b/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm
@@ -11,12 +11,15 @@
/obj/effect/proc_holder/spell/vampire/self/cloak/proc/update_name()
var/mob/living/user = loc
- if(!ishuman(user) || !user.mind || !user.mind.vampire)
+ if(!ishuman(user) || !user.mind)
return
- action.button.name = "[initial(name)] ([user.mind.vampire.iscloaking ? "Deactivate" : "Activate"])"
+ var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire)
+ if(!V)
+ return
+ action.button.name = "[initial(name)] ([V.iscloaking ? "Deactivate" : "Activate"])"
/obj/effect/proc_holder/spell/vampire/self/cloak/cast(list/targets, mob/user = usr)
- var/datum/vampire/V = user.mind.vampire
+ var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire)
V.iscloaking = !V.iscloaking
if(ishuman(user))
var/mob/living/carbon/human/H = user
@@ -32,7 +35,8 @@
/mob/living/proc/update_vampire_cloak()
SIGNAL_HANDLER
- mind.vampire.handle_vampire_cloak()
+ var/datum/antagonist/vampire/V = mind.has_antag_datum(/datum/antagonist/vampire)
+ V.handle_vampire_cloak()
/obj/effect/proc_holder/spell/vampire/shadow_snare
name = "Shadow Snare (20)"
@@ -140,9 +144,6 @@
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()
@@ -159,13 +160,14 @@
var/shroud_power = -4
/obj/effect/proc_holder/spell/vampire/self/eternal_darkness/cast(list/targets, mob/user)
+ var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire)
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)
+ if(!V.get_ability(/datum/vampire_passive/eternal_darkness))
+ V.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)
+ for(var/datum/vampire_passive/eternal_darkness/E in V.powers)
+ V.remove_ability(E)
/datum/vampire_passive/eternal_darkness
gain_desc = "You surround yourself in a unnatural darkness, freezing those around you."
@@ -180,14 +182,16 @@
return ..()
/datum/vampire_passive/eternal_darkness/process()
+ var/datum/antagonist/vampire/V = owner.mind.has_antag_datum(/datum/antagonist/vampire)
+
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)
+ V.bloodusable = max(V.bloodusable - 5, 0)
- if(!owner.mind.vampire.bloodusable || owner.stat == DEAD)
- owner.mind.vampire.remove_ability(src)
+ if(!V.bloodusable || owner.stat == DEAD)
+ V.remove_ability(src)
/datum/vampire_passive/xray
gain_desc = "You can now see through walls, incase you hadn't noticed."
diff --git a/code/game/gamemodes/vampire/vampire_powers/vampire_powers.dm b/code/modules/antagonists/vampire/vampire_powers/vampire_powers.dm
similarity index 86%
rename from code/game/gamemodes/vampire/vampire_powers/vampire_powers.dm
rename to code/modules/antagonists/vampire/vampire_powers/vampire_powers.dm
index 11ddfbb6857..51d600ea8db 100644
--- a/code/game/gamemodes/vampire/vampire_powers/vampire_powers.dm
+++ b/code/modules/antagonists/vampire/vampire_powers/vampire_powers.dm
@@ -1,10 +1,11 @@
//This should hold all the vampire related powers
/mob/living/proc/affects_vampire(mob/user)
//Other vampires aren't affected
- if(mind?.vampire)
+ if(mind?.has_antag_datum(/datum/antagonist/vampire))
return FALSE
//Vampires who have reached their full potential can affect nearly everything
- if(user?.mind.vampire.get_ability(/datum/vampire_passive/full))
+ var/datum/antagonist/vampire/V = user?.mind.has_antag_datum(/datum/antagonist/vampire)
+ if(V?.get_ability(/datum/vampire_passive/full))
return TRUE
//Holy characters are resistant to vampire powers
if(mind?.isholy)
@@ -21,15 +22,12 @@
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
@@ -46,12 +44,11 @@
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
+ charge_max = 20 SECONDS
stat_allowed = 1
/obj/effect/proc_holder/spell/vampire/self/rejuvenate/cast(list/targets, mob/user = usr)
@@ -64,7 +61,8 @@
U.SetConfused(0)
U.adjustStaminaLoss(-100)
to_chat(user, "You instill your body with clean blood and remove any incapacitating effects.")
- var/rejuv_bonus = U.mind.vampire.get_rejuv_bonus()
+ var/datum/antagonist/vampire/V = U.mind.has_antag_datum(/datum/antagonist/vampire)
+ var/rejuv_bonus = V.get_rejuv_bonus()
if(rejuv_bonus)
INVOKE_ASYNC(src, .proc/heal, U, rejuv_bonus)
@@ -79,13 +77,13 @@
user.reagents.remove_reagent(R.id, 2 * rejuv_bonus)
sleep(35)
-/datum/vampire/proc/get_rejuv_bonus()
+/datum/antagonist/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
+ rejuv_multiplier = clamp((100 - owner.current.health) / 20, 1, 5) // brute and burn healing between 5 and 50
return rejuv_multiplier
return 1
@@ -109,14 +107,14 @@
ui.open()
/obj/effect/proc_holder/spell/vampire/self/specialize/ui_data(mob/user)
- var/datum/vampire/vamp = user.mind.vampire
+ var/datum/antagonist/vampire/vamp = user.mind.has_antag_datum(/datum/antagonist/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
+ var/datum/antagonist/vampire/vamp = usr.mind.has_antag_datum(/datum/antagonist/vampire)
if(vamp.subclass)
vamp.upgrade_tiers -= type
@@ -138,7 +136,7 @@
vamp.remove_ability(src)
-/datum/vampire/proc/add_subclass(subclass_to_add, announce = TRUE)
+/datum/antagonist/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)
@@ -281,7 +279,7 @@
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)
+ if(H.mind.has_antag_datum(/datum/antagonist/vampire) || H.mind.special_role == SPECIAL_ROLE_VAMPIRE || H.mind.special_role == SPECIAL_ROLE_VAMPIRE_THRALL)
visible_message("[H] looks refreshed!")
H.adjustBruteLoss(-60)
H.adjustFireLoss(-60)
@@ -321,7 +319,7 @@
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
+ charge_max = 2 SECONDS
clothes_req = FALSE
centcom_cancast = FALSE
include_space = FALSE
@@ -345,7 +343,7 @@
// pure adminbus at the moment
/proc/isvampirethrall(mob/living/M)
- return istype(M) && M.mind && SSticker.mode && (M.mind in SSticker.mode.vampire_enthralled)
+ return istype(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/mindslave/thrall)
/obj/effect/proc_holder/spell/vampire/enthrall
name = "Enthrall (150)"
@@ -365,7 +363,7 @@
return T
/obj/effect/proc_holder/spell/vampire/enthrall/cast(list/targets, mob/user = usr)
- var/datum/vampire/vampire = user.mind.vampire
+ var/datum/antagonist/vampire/vampire = user.mind.has_antag_datum(/datum/antagonist/vampire)
for(var/mob/living/target in targets)
user.visible_message("[user] bites [target]'s neck!", "You bite [target]'s neck and begin the flow of power.")
to_chat(target, "You feel the tendrils of evil invade your mind.")
@@ -395,7 +393,7 @@
if(!C.mind)
to_chat(user, "[C.name]'s mind is not there for you to enthrall.")
return FALSE
- if(enthrall_safe || (C.mind in SSticker.mode.vampires) || (C.mind.vampire) || (C.mind in SSticker.mode.vampire_enthralled))
+ if(enthrall_safe || (C.mind.has_antag_datum(/datum/antagonist/vampire)) || (isvampirethrall(C)))
C.visible_message("[C] seems to resist the takeover!", "You feel a familiar sensation in your skull that quickly dissipates.")
return FALSE
if(!C.affects_vampire(user))
@@ -411,34 +409,9 @@
/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")
+ return FALSE
- 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, "You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command.")
- to_chat(user, "You have successfully Enthralled [H]. If [H.p_they()] refuse[H.p_s()] to do as you say just adminhelp.")
+ var/greet_text = "You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command."
+ H.mind.add_antag_datum(new /datum/antagonist/mindslave/thrall(user.mind, greet_text))
H.Stun(2)
add_attack_logs(user, H, "Vampire-thralled")
diff --git a/code/game/gamemodes/vampire/vampire_subclasses.dm b/code/modules/antagonists/vampire/vampire_subclasses.dm
similarity index 95%
rename from code/game/gamemodes/vampire/vampire_subclasses.dm
rename to code/modules/antagonists/vampire/vampire_subclasses.dm
index 0747d0a32c0..f0e3281bd48 100644
--- a/code/game/gamemodes/vampire/vampire_subclasses.dm
+++ b/code/modules/antagonists/vampire/vampire_subclasses.dm
@@ -8,12 +8,12 @@
/// 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)
+/datum/vampire_subclass/proc/add_subclass_ability(datum/antagonist/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)
+/datum/vampire_subclass/proc/add_full_power_abilities(datum/antagonist/vampire/vamp)
for(var/thing in fully_powered_abilities)
vamp.add_ability(thing)
diff --git a/code/modules/martial_arts/martial.dm b/code/modules/martial_arts/martial.dm
index d7128a5ab51..9157ae67815 100644
--- a/code/modules/martial_arts/martial.dm
+++ b/code/modules/martial_arts/martial.dm
@@ -272,7 +272,7 @@
if(user.mind.changeling) //Changelings
to_chat(user, "We try multiple times, but we are not able to comprehend the contents of the scroll!")
return
- else if(user.mind.vampire) //Vampires
+ else if(user.mind.has_antag_datum(/datum/antagonist/vampire)) //Vampires
to_chat(user, "Your blood lust distracts you too much to be able to concentrate on the contents of the scroll!")
return
@@ -296,7 +296,7 @@
if(user.mind.changeling) //Changelings
to_chat(user, "We try multiple times, but we simply cannot grasp the basics of CQC!")
return
- else if(user.mind.vampire) //Vampires
+ else if(user.mind.has_antag_datum(/datum/antagonist/vampire)) //Vampires
to_chat(user, "Your blood lust distracts you from the basics of CQC!")
return
else if(HAS_TRAIT(user, TRAIT_PACIFISM))
diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm
index 7ce371c6733..6a6534cca94 100644
--- a/code/modules/mob/dead/observer/orbit.dm
+++ b/code/modules/mob/dead/observer/orbit.dm
@@ -76,11 +76,16 @@
var/datum/mind/mind = M.mind
if(user.antagHUD)
- // If a mind is many antags at once, we'll display all of them, each
- // under their own antag sub-section.
- // This is arguably better, than picking one of the antag datums at random.
+ /*
+ If a mind is many antags at once, we'll display all of them, each
+ under their own antag sub-section.
+ This is arguably better, than picking one of the antag datums at random.
- // Traitors - the only antags in `.antag_datums` at the time of writing.
+ list of antags that are datumised:
+ - traitor
+ - mindslaves/vampire thralls
+ - vampire
+ */
for(var/_A in mind.antag_datums)
var/datum/antagonist/A = _A
var/antag_serialized = serialized.Copy()
@@ -90,8 +95,7 @@
// Not-very-datumized antags follow
// Associative list of antag name => whether this mind is this antag
var/other_antags = list(
- "Changeling" = (mind.changeling != null),
- "Vampire" = (mind.vampire != null),
+ "Changeling" = (mind.changeling != null)
)
if(SSticker && SSticker.mode)
other_antags += list(
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 5db4c5a9338..05125331d6a 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -207,9 +207,10 @@
stat("Chemical Storage", "[mind.changeling.chem_charges]/[mind.changeling.chem_storage]")
stat("Absorbed DNA", mind.changeling.absorbedcount)
- if(mind.vampire)
- stat("Total Blood", "[mind.vampire.bloodtotal]")
- stat("Usable Blood", "[mind.vampire.bloodusable]")
+ var/datum/antagonist/vampire/V = mind.has_antag_datum(/datum/antagonist/vampire)
+ if(V)
+ stat("Total Blood", "[V.bloodtotal]")
+ stat("Usable Blood", "[V.bloodusable]")
/mob/living/carbon/human/ex_act(severity)
if(status_flags & GODMODE)
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 6a6aa7700c8..a387758fb6a 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -36,8 +36,9 @@
name = get_visible_name()
pulse = handle_pulse(times_fired)
- if(mind?.vampire)
- mind.vampire.handle_vampire()
+ var/datum/antagonist/vampire/V = mind?.has_antag_datum(/datum/antagonist/vampire)
+ if(V)
+ V.handle_vampire()
if(life_tick == 1)
regenerate_icons() // Make sure the inventory updates
@@ -363,8 +364,9 @@
bodytemperature += 11
else
bodytemperature += (BODYTEMP_HEATING_MAX + (fire_stacks * 12))
- if(mind?.vampire && !mind.vampire.get_ability(/datum/vampire_passive/full) && stat != DEAD)
- mind.vampire.bloodusable = max(mind.vampire.bloodusable - 5, 0)
+ var/datum/antagonist/vampire/V = mind?.has_antag_datum(/datum/antagonist/vampire)
+ if(V && !V.get_ability(/datum/vampire_passive/full) && stat != DEAD) // V?. doesn't work here because `has_antag_datum` return FALSE if there is no datum and ?. doesn't like that
+ V.bloodusable = max(V.bloodusable - 5, 0)
/mob/living/carbon/human/proc/get_thermal_protection()
if(HAS_TRAIT(src, TRAIT_RESISTHEAT))
@@ -788,7 +790,7 @@
/mob/living/carbon/human/proc/handle_nutrition_alerts() //This is a terrible abuse of the alert system; something like this should be a HUD element
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
return
- if(mind?.vampire && (mind in SSticker.mode.vampires)) //Vampires
+ if(mind?.has_antag_datum(/datum/antagonist/vampire)) //Vampires
switch(nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
throw_alert("nutrition", /obj/screen/alert/fat/vampire)
diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm
index fc0335976e6..af8ffeca7be 100644
--- a/code/modules/mob/living/carbon/human/species/_species.dm
+++ b/code/modules/mob/living/carbon/human/species/_species.dm
@@ -434,18 +434,19 @@
to_chat(user, "You don't want to harm [target]!")
return FALSE
//Vampire code
- if(user.mind && user.mind.vampire && (user.mind in SSticker.mode.vampires) && !user.mind.vampire.draining && user.zone_selected == "head" && target != user)
+ var/datum/antagonist/vampire/V = user?.mind?.has_antag_datum(/datum/antagonist/vampire)
+ if(V && !V.draining && user.zone_selected == "head" && target != user)
if((NO_BLOOD in target.dna.species.species_traits) || target.dna.species.exotic_blood || !target.blood_volume)
to_chat(user, "They have no blood!")
return
- if(target.mind && target.mind.vampire && (target.mind in SSticker.mode.vampires))
+ if(target.mind && target.mind.has_antag_datum(/datum/antagonist/vampire))
to_chat(user, "Your fangs fail to pierce [target.name]'s cold flesh")
return
if(HAS_TRAIT(target, TRAIT_SKELETONIZED))
to_chat(user, "There is no blood in a skeleton!")
return
//we're good to suck the blood, blaah
- user.mind.vampire.handle_bloodsucking(target)
+ V.handle_bloodsucking(target)
add_attack_logs(user, target, "vampirebit")
return
//end vampire codes
@@ -856,16 +857,17 @@ It'll return null if the organ doesn't correspond, so include null checks when u
if(A.update_remote_sight(H)) //returns 1 if we override all other sight updates.
return
- if(H.mind?.vampire)
- if(H.mind.vampire.get_ability(/datum/vampire_passive/xray))
+ var/datum/antagonist/vampire/V = H.mind?.has_antag_datum(/datum/antagonist/vampire)
+ if(V)
+ if(V.get_ability(/datum/vampire_passive/xray))
H.sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS
H.see_in_dark += 8
H.lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
- else if(H.mind.vampire.get_ability(/datum/vampire_passive/full))
+ else if(V.get_ability(/datum/vampire_passive/full))
H.sight |= SEE_MOBS
H.see_in_dark += 8
H.lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
- else if(H.mind.vampire.get_ability(/datum/vampire_passive/vision))
+ else if(V.get_ability(/datum/vampire_passive/vision))
H.sight |= SEE_MOBS
H.see_in_dark += 1 // base of 2, 2+1 is 3
H.lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
diff --git a/code/modules/mob/living/carbon/human/species/diona.dm b/code/modules/mob/living/carbon/human/species/diona.dm
index 769b6b36d7e..a5289341eca 100644
--- a/code/modules/mob/living/carbon/human/species/diona.dm
+++ b/code/modules/mob/living/carbon/human/species/diona.dm
@@ -85,7 +85,7 @@
/datum/species/diona/handle_life(mob/living/carbon/human/H)
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
- var/is_vamp = H.mind?.vampire != null
+ var/is_vamp = H.mind && H.mind.has_antag_datum(/datum/antagonist/vampire)
if(isturf(H.loc)) //else, there's considered to be no light
var/turf/T = H.loc
light_amount = min(1, T.get_lumcount()) - 0.5
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 2b5b0bdddd5..4ce0e83aec5 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -322,7 +322,7 @@
/mob/living/carbon/handle_sleeping()
if(..())
- if(mind?.vampire)
+ if(mind?.has_antag_datum(/datum/antagonist/vampire))
if(istype(loc, /obj/structure/closet/coffin))
adjustBruteLoss(-1, FALSE)
adjustFireLoss(-1, FALSE)
diff --git a/code/modules/mob/living/silicon/login.dm b/code/modules/mob/living/silicon/login.dm
index 80b9fb46053..d5d0cfe7086 100644
--- a/code/modules/mob/living/silicon/login.dm
+++ b/code/modules/mob/living/silicon/login.dm
@@ -5,7 +5,7 @@
SSticker.mode.remove_cultist(mind, 1)
SSticker.mode.remove_wizard(mind)
SSticker.mode.remove_changeling(mind)
- SSticker.mode.remove_vampire(mind)
+ mind.remove_antag_datum(/datum/antagonist/vampire)
SSticker.mode.remove_thrall(mind, 0)
SSticker.mode.remove_shadowling(mind)
SSticker.mode.remove_abductor(mind)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index c1c983b191d..9932d597be3 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1499,11 +1499,6 @@ GLOBAL_LIST_INIT(holy_areas, typecacheof(list(
if(!mind)
return FALSE
- //Allows fullpower vampires to bypass holy areas
- var/datum/vampire/vampire = mind.vampire
- if(vampire && vampire.get_ability(/datum/vampire_passive/full))
- return FALSE
-
//Allows cult to bypass holy areas once they summon
var/datum/game_mode/gamemode = SSticker.mode
if(iscultist(src) && gamemode.cult_objs.cult_status == NARSIE_HAS_RISEN)
diff --git a/code/modules/reagents/chemistry/reagents/food.dm b/code/modules/reagents/chemistry/reagents/food.dm
index c6b486c7075..cb5a615135b 100644
--- a/code/modules/reagents/chemistry/reagents/food.dm
+++ b/code/modules/reagents/chemistry/reagents/food.dm
@@ -12,11 +12,11 @@
var/diet_flags = DIET_OMNI | DIET_HERB | DIET_CARN
/datum/reagent/consumable/on_mob_life(mob/living/M)
- if(!(M.mind in SSticker.mode.vampires))
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.can_eat(diet_flags)) //Make sure the species has it's dietflag set, otherwise it can't digest any nutrients
- H.adjust_nutrition(nutriment_factor) // For hunger and fatness
+ var/is_vamp = M.mind?.has_antag_datum(/datum/antagonist/vampire)
+ if(ishuman(M) && !is_vamp)
+ var/mob/living/carbon/human/H = M
+ if(H.can_eat(diet_flags)) //Make sure the species has it's dietflag set, otherwise it can't digest any nutrients
+ H.adjust_nutrition(nutriment_factor) // For hunger and fatness
return ..()
/datum/reagent/consumable/nutriment // Pure nutriment, universally digestable and thus slightly less effective
@@ -31,13 +31,13 @@
/datum/reagent/consumable/nutriment/on_mob_life(mob/living/M)
var/update_flags = STATUS_UPDATE_NONE
- if(!(M.mind in SSticker.mode.vampires))
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.can_eat(diet_flags)) //Make sure the species has it's dietflag set, otherwise it can't digest any nutrients
- if(prob(50))
- update_flags |= M.adjustBruteLoss(-brute_heal, FALSE)
- update_flags |= M.adjustFireLoss(-burn_heal, FALSE)
+ var/is_vamp = M.mind?.has_antag_datum(/datum/antagonist/vampire)
+ if(ishuman(M) && !is_vamp)
+ var/mob/living/carbon/human/H = M
+ if(H.can_eat(diet_flags)) //Make sure the species has it's dietflag set, otherwise it can't digest any nutrients
+ if(prob(50))
+ update_flags |= M.adjustBruteLoss(-brute_heal, FALSE)
+ update_flags |= M.adjustFireLoss(-burn_heal, FALSE)
return ..() | update_flags
/datum/reagent/consumable/nutriment/on_new(list/supplied_data)
@@ -354,7 +354,8 @@
var/update_flags = STATUS_UPDATE_NONE
if(ishuman(M))
var/mob/living/carbon/human/H = M
- if(H.mind && H.mind.vampire && !H.mind.vampire.get_ability(/datum/vampire_passive/full)) //incapacitating but not lethal.
+ var/datum/antagonist/vampire/V = H.mind?.has_antag_datum(/datum/antagonist/vampire)
+ if(V && !V.get_ability(/datum/vampire_passive/full)) //incapacitating but not lethal.
if(prob(min(25, current_cycle)))
to_chat(H, "You can't get the scent of garlic out of your nose! You can barely think...")
H.Weaken(1)
diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm
index fff03b6e162..d7eea24f35b 100644
--- a/code/modules/reagents/chemistry/reagents/water.dm
+++ b/code/modules/reagents/chemistry/reagents/water.dm
@@ -107,7 +107,7 @@
C.reagents.add_reagent("toxin", volume * 0.5)
else
C.blood_volume = min(C.blood_volume + round(volume, 0.1), BLOOD_VOLUME_NORMAL)
- if(C.mind?.vampire)
+ if(C.mind?.has_antag_datum(/datum/antagonist/vampire))
C.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, C.nutrition + 10))
/datum/reagent/blood/on_new(list/data)
@@ -249,7 +249,7 @@
if(current_cycle >= 75 && prob(33)) // 30 units, 150 seconds
M.AdjustConfused(3)
if(isvampirethrall(M))
- SSticker.mode.remove_vampire_mind(M.mind)
+ M.mind.remove_antag_datum(/datum/antagonist/mindslave/thrall)
holder.remove_reagent(id, volume)
M.SetJitter(0)
M.SetStuttering(0)
@@ -262,17 +262,18 @@
M.SetStuttering(0)
M.SetConfused(0)
return
- if(ishuman(M) && M.mind && M.mind.vampire && !M.mind.vampire.get_ability(/datum/vampire_passive/full) && prob(80))
+ var/datum/antagonist/vampire/vamp = M.mind?.has_antag_datum(/datum/antagonist/vampire)
+ if(ishuman(M) && vamp && !vamp.get_ability(/datum/vampire_passive/full) && prob(80))
var/mob/living/carbon/V = M
- if(M.mind.vampire.bloodusable)
+ if(vamp.bloodusable)
M.Stuttering(1)
M.Jitter(30)
update_flags |= M.adjustStaminaLoss(5, FALSE)
if(prob(20))
M.emote("scream")
- M.mind.vampire.adjust_nullification(20, 4)
- M.mind.vampire.bloodusable = max(M.mind.vampire.bloodusable - 3,0)
- if(M.mind.vampire.bloodusable)
+ vamp.adjust_nullification(20, 4)
+ vamp.bloodusable = max(vamp.bloodusable - 3,0)
+ if(vamp.bloodusable)
V.vomit(0, TRUE, FALSE)
V.adjustBruteLoss(3)
else
@@ -283,7 +284,7 @@
switch(current_cycle)
if(1 to 4)
to_chat(M, "Something sizzles in your veins!")
- M.mind.vampire.adjust_nullification(20, 4)
+ vamp.adjust_nullification(20, 4)
if(5 to 12)
to_chat(M, "You feel an intense burning inside of you!")
update_flags |= M.adjustFireLoss(1, FALSE)
@@ -291,7 +292,7 @@
M.Jitter(20)
if(prob(20))
M.emote("scream")
- M.mind.vampire.adjust_nullification(20, 4)
+ vamp.adjust_nullification(20, 4)
if(13 to INFINITY)
M.visible_message("[M] suddenly bursts into flames!",
"You suddenly ignite in a holy fire!")
@@ -302,14 +303,15 @@
M.Jitter(30)
if(prob(40))
M.emote("scream")
- M.mind.vampire.adjust_nullification(20, 4)
+ vamp.adjust_nullification(20, 4)
return ..() | update_flags
/datum/reagent/holywater/reaction_mob(mob/living/M, method=REAGENT_TOUCH, volume)
// Vampires have their powers weakened by holy water applied to the skin.
- if(ishuman(M) && M.mind && M.mind.vampire && !M.mind.vampire.get_ability(/datum/vampire_passive/full))
- var/mob/living/carbon/human/H=M
+ var/datum/antagonist/vampire/V = M.mind?.has_antag_datum(/datum/antagonist/vampire)
+ if(ishuman(M) && V && !V.get_ability(/datum/vampire_passive/full))
+ var/mob/living/carbon/human/H = M
if(method == REAGENT_TOUCH)
if(H.wear_mask)
to_chat(H, "Your mask protects you from the holy water!")
@@ -319,7 +321,7 @@
return
else
to_chat(M, "Something holy interferes with your powers!")
- M.mind.vampire.adjust_nullification(5, 2)
+ V.adjust_nullification(5, 2)
/datum/reagent/holywater/reaction_turf(turf/simulated/T, volume)
diff --git a/paradise.dme b/paradise.dme
index a94fcc6ae8b..27b3d09221b 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -635,12 +635,7 @@
#include "code\game\gamemodes\shadowling\special_shadowling_abilities.dm"
#include "code\game\gamemodes\traitor\traitor.dm"
#include "code\game\gamemodes\vampire\traitor_vamp.dm"
-#include "code\game\gamemodes\vampire\vampire.dm"
-#include "code\game\gamemodes\vampire\vampire_subclasses.dm"
-#include "code\game\gamemodes\vampire\vampire_powers\gargantua_powers.dm"
-#include "code\game\gamemodes\vampire\vampire_powers\hemomancer_powers.dm"
-#include "code\game\gamemodes\vampire\vampire_powers\umbrae_powers.dm"
-#include "code\game\gamemodes\vampire\vampire_powers\vampire_powers.dm"
+#include "code\game\gamemodes\vampire\vampire_gamemode.dm"
#include "code\game\gamemodes\wizard\artefact.dm"
#include "code\game\gamemodes\wizard\godhand.dm"
#include "code\game\gamemodes\wizard\raginmages.dm"
@@ -1293,6 +1288,12 @@
#include "code\modules\antagonists\traitor\contractor\items\contractor_pinpointer.dm"
#include "code\modules\antagonists\traitor\contractor\items\contractor_uplink.dm"
#include "code\modules\antagonists\traitor\contractor\items\extraction_items.dm"
+#include "code\modules\antagonists\vampire\vamp_datum.dm"
+#include "code\modules\antagonists\vampire\vampire_subclasses.dm"
+#include "code\modules\antagonists\vampire\vampire_powers\gargantua_powers.dm"
+#include "code\modules\antagonists\vampire\vampire_powers\hemomancer_powers.dm"
+#include "code\modules\antagonists\vampire\vampire_powers\umbrae_powers.dm"
+#include "code\modules\antagonists\vampire\vampire_powers\vampire_powers.dm"
#include "code\modules\antagonists\wishgranter\wishgranter.dm"
#include "code\modules\arcade\arcade_base.dm"
#include "code\modules\arcade\arcade_prize.dm"