diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index 498e9c70a2d..5cc0070658c 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -656,6 +656,23 @@
if(dreamer.mind?.has_antag_datum(/datum/antagonist/vampire))
var/mob/living/carbon/human/V = owner
+ if(istype(V.loc, /obj/structure/closet/coffin/vampire))
+ var/obj/structure/closet/coffin/vampire/C = V.loc
+ if(C.vampire == V)
+ V.adjustBruteLoss(-3)
+ V.adjustFireLoss(-3)
+ V.adjustToxLoss(-3)
+ V.adjustOxyLoss(-3)
+ V.adjustCloneLoss(-1.5)
+ if(!isnull(V.viruses) && prob(25))
+ for(var/datum/disease/virus in V.viruses)
+ virus.cure()
+ for(var/obj/item/organ/external/E in V.bodyparts)
+ if(E.status & (ORGAN_INT_BLEEDING | ORGAN_BROKEN | ORGAN_SPLINTED | ORGAN_BURNT))
+ E.rejuvenate()
+ break // just one limb per sleep tick because vampires can just Rejuvenate out of sleep
+ for(var/obj/item/organ/internal/I in V.internal_organs)
+ I.heal_internal_damage(2, TRUE)
if(istype(V.loc, /obj/structure/closet/coffin))
V.adjustBruteLoss(-1)
V.adjustFireLoss(-1)
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 4386166e1ef..39253590e53 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -1196,6 +1196,20 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/download/check_completion()
return TRUE
+/datum/objective/lair
+ name = "Build a lair"
+ explanation_text = "Build a lair by placing a coffin in the middle of an unoccupied 3x3 area. This requires at least 150 total units of blood."
+ needs_target = FALSE
+
+/datum/objective/lair/check_completion()
+ if(..())
+ return TRUE
+ for(var/datum/mind/M in get_owners())
+ var/datum/antagonist/vampire/V = M.has_antag_datum(/datum/antagonist/vampire)
+ if(V.has_lair)
+ return TRUE
+ return FALSE
+
// Traders
// These objectives have no check_completion, they exist only to tell Sol Traders what to aim for.
diff --git a/code/game/objects/structures/crates_lockers/closets/coffin.dm b/code/game/objects/structures/crates_lockers/closets/coffin.dm
index 2f132f3e2d0..86195d140f0 100644
--- a/code/game/objects/structures/crates_lockers/closets/coffin.dm
+++ b/code/game/objects/structures/crates_lockers/closets/coffin.dm
@@ -17,3 +17,71 @@
open_sound = 'sound/effects/stonedoor_openclose.ogg'
close_sound = 'sound/effects/stonedoor_openclose.ogg'
material_drop = /obj/item/stack/sheet/mineral/sandstone
+
+/obj/structure/closet/coffin/vampire
+ max_integrity = 500
+ anchored = TRUE
+ armor = list(MELEE = 200, BULLET = 200, LASER = 80, ENERGY = 200, BOMB = 200, RAD = 200, FIRE = 80, ACID = 200) // just burn it
+ custom_fire_overlay = " " // gets rid of regular SSfires overlay, setting it on fire uses something completely different
+ /// Owner of the coffin
+ var/mob/vampire
+ /// Is the coffin being set on fire?
+ var/igniting = FALSE
+ /// Last time the vampire was warned of the attack
+ COOLDOWN_DECLARE(fire_act_cooldown)
+
+/obj/structure/closet/coffin/vampire/Initialize(mapload, mob/user)
+ . = ..()
+ name = "\proper the coffin of [user]"
+ desc += "
This coffin's owner may not actually have been dear to anyone, or even departed quite yet.
\
+ It appears impervious to everything but lasers and fire! Especially fire!"
+ vampire = user
+
+/obj/structure/closet/coffin/vampire/welder_act(mob/user, obj/item/I)
+ if(igniting)
+ return ITEM_INTERACT_COMPLETE
+ if(!I.tool_use_check(user, 30)) // it's a cursed coffin, you will need something better than a maintenance welder to ignite it
+ return ITEM_INTERACT_COMPLETE
+ igniting = TRUE
+ to_chat(user, "You attempt to set [src] on fire with [I].")
+ to_chat(vampire, "Your lair is being attacked!")
+ if(do_after(user, 15 SECONDS, target = src))
+ fire_act()
+ igniting = FALSE
+ return ITEM_INTERACT_COMPLETE
+
+/obj/structure/closet/coffin/vampire/bullet_act(obj/item/projectile/P)
+ if(!P.immolate)
+ return ..()
+ fire_act()
+ return ..()
+
+/obj/structure/closet/coffin/vampire/fire_act()
+ . = ..()
+ if(!COOLDOWN_FINISHED(src, fire_act_cooldown))
+ return
+ to_chat(vampire, "Your lair is being attacked!")
+ switch(rand(1, 4))
+ if(1)
+ visible_message("The wood howls as fire bursts out from seemingly nowhere!")
+ playsound(src, "sound/goonstation/voice/howl.ogg", 30)
+ if(2 to 3)
+ visible_message("The wood hisses as fire bursts out from seemingly nowhere!")
+ if(prob(50))
+ playsound(src, "sound/effects/unathihiss.ogg", 30)
+ else
+ playsound(src, "sound/effects/tajaranhiss.ogg", 30)
+ if(4)
+ visible_message("The wood growls as fire bursts out from seemingly nowhere!")
+ playsound(src, 'sound/goonstation/voice/growl3.ogg', 30)
+ var/turf/new_fire = pick(oview(2, src))
+ new /obj/effect/fire(get_turf(new_fire), T20C, 30 SECONDS, 1)
+ new /obj/effect/fire(loc, T20C, 30 SECONDS, 1)
+ COOLDOWN_START(src, fire_act_cooldown, 10 SECONDS)
+
+/obj/structure/closet/coffin/vampire/burn()
+ playsound(src, 'sound/hallucinations/wail.ogg', 20, extrarange = SOUND_RANGE_SET(5))
+ visible_message("Fire bursts out from [name] as it falls apart!")
+ for(var/turf/T in range(1, src))
+ new /obj/effect/fire(T, T20C, 30 SECONDS, 1)
+ ..()
diff --git a/code/modules/antagonists/vampire/vamp_datum.dm b/code/modules/antagonists/vampire/vamp_datum.dm
index ff54031d582..5adbe339dcf 100644
--- a/code/modules/antagonists/vampire/vamp_datum.dm
+++ b/code/modules/antagonists/vampire/vamp_datum.dm
@@ -25,11 +25,14 @@ RESTRICT_TYPE(/datum/antagonist/vampire)
/datum/vampire_passive/vision = 100,
/datum/spell/vampire/self/specialize = 150,
/datum/spell/vampire/self/exfiltrate = 150,
+ /datum/spell/vampire/lair = 150,
/datum/vampire_passive/regen = 200,
/datum/vampire_passive/vision/advanced = 500)
/// list of the peoples UIDs that we have drained, and how much blood from each one
var/list/drained_humans = list()
+ /// did the vampire build a lair?
+ var/has_lair = FALSE
blurb_text_color = COLOR_RED
blurb_r = 255
blurb_g = 221
@@ -363,6 +366,7 @@ RESTRICT_TYPE(/datum/antagonist/vampire)
add_antag_objective(/datum/objective/protect)
else
add_antag_objective(/datum/objective/steal)
+ add_antag_objective(/datum/objective/lair)
if(prob(20)) // 20% chance of getting survive. 80% chance of getting escape.
add_antag_objective(/datum/objective/survive)
diff --git a/code/modules/antagonists/vampire/vampire_powers/vampire_powers.dm b/code/modules/antagonists/vampire/vampire_powers/vampire_powers.dm
index 0852be171d5..b584ccf6649 100644
--- a/code/modules/antagonists/vampire/vampire_powers/vampire_powers.dm
+++ b/code/modules/antagonists/vampire/vampire_powers/vampire_powers.dm
@@ -206,6 +206,65 @@
C.charge_duration = 2 SECONDS
return C
+/datum/spell/vampire/lair
+ name = "Lair"
+ desc = "Pick a coffin for yourself, the centrepiece of your new lair."
+ gain_desc = "You can now start a lair."
+ action_icon = 'icons/obj/closet.dmi'
+ action_icon_state = "coffin"
+ base_cooldown = 2 SECONDS
+
+/datum/spell/vampire/lair/create_new_targeting()
+ var/datum/spell_targeting/click/T = new
+ T.range = 1
+ T.allowed_type = /obj/structure/closet/coffin
+ return T
+
+/datum/spell/vampire/lair/cast(list/targets, mob/user)
+ var/obj/structure/closet/coffin/C = targets[1] // this spell will basically always target a singular coffin unless you stack multiple on the same tile
+ if(!istype(C, /obj/structure/closet/coffin))
+ to_chat(user, "This only works on coffins!")
+ return
+ if(istype(C, /obj/structure/closet/coffin/vampire))
+ to_chat(user, "This coffin serves another and refuses to bend to your will!")
+ return
+ if(istype(C, /obj/structure/closet/coffin/sarcophagus))
+ to_chat(user, "Making such a lavish lair would likely upset an ancient. You should really use a wooden coffin for now.")
+ return
+ for(var/turf/T in range(1, C))
+ if(T.density)
+ to_chat(user, "You need more space around the coffin for the ritual!")
+ return
+ to_chat(user, "You begin marking the coffin!")
+ C.Beam(user, icon_state = "drainbeam", maxdistance = 1, time = 10 SECONDS)
+ playsound(C, 'sound/misc/enter_blood.ogg', 20)
+ for(var/obj/machinery/light/L in range(5, user))
+ L.forced_flicker()
+ var/obj/effect/lair_rune/rune = new /obj/effect/lair_rune(get_turf(C), user)
+ if(!do_after(user, 10 SECONDS, target = C))
+ qdel(rune)
+ return
+ playsound(user, 'sound/hallucinations/im_here1.ogg', 30)
+ new /obj/structure/closet/coffin/vampire(get_turf(C), user)
+ qdel(C)
+ var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire)
+ V.has_lair = TRUE
+ user.mind.RemoveSpell(src)
+
+/obj/effect/lair_rune
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ plane = FLOOR_PLANE
+ layer = SIGIL_LAYER
+ icon = 'icons/effects/96x96.dmi'
+ icon_state = "vampiric_rune"
+ pixel_x = -34
+ pixel_y = -38
+
+/obj/effect/lair_rune/Initialize(mapload, mob/user)
+ . = ..()
+ if(user)
+ color = user.dna.species.blood_color
+
/// 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.
diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi
index b2f55cbbbee..d4f3711d6fa 100644
Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ