diff --git a/code/__DEFINES/bloodsuckers.dm b/code/__DEFINES/bloodsuckers.dm
index 8fa47c24a876..c4b0c967dd46 100644
--- a/code/__DEFINES/bloodsuckers.dm
+++ b/code/__DEFINES/bloodsuckers.dm
@@ -10,9 +10,9 @@
/// Deals with constant processes off of LifeTick()
#define COMSIG_LIVING_BIOLOGICAL_LIFE "biological_life"
/// Once blood is this low, will enter Frenzy
-#define FRENZY_THRESHOLD_ENTER 25
+#define FRENZY_THRESHOLD_ENTER 112
/// Once blood is this high, will exit Frenzy
-#define FRENZY_THRESHOLD_EXIT 250
+#define FRENZY_THRESHOLD_EXIT 560
/// You have special interactions with Bloodsuckers
#define TRAIT_BLOODSUCKER_HUNTER "bloodsucker_hunter"
@@ -36,7 +36,12 @@
#define CLAN_TOREADOR "Toreador Clan"
#define CLAN_GANGREL "Gangrel Clan"
#define CLAN_LASOMBRA "Lasombra Clan"
+#define CLAN_TZIMISCE "Tzimisce Clan"
+#define TRIPLECHEST_MONSTER "Triple Chest (300 Blood)"
+#define ARMMY_MONSTER "Armmy (100 Blood)"
+#define CALCIUM_MONSTER "Calcium (150 Blood)"
+#define HUSK_MONSTER "Husk"
/**
* Power defines
*/
@@ -53,12 +58,16 @@
/// This Power can be purchased by Bloodsuckers
#define BLOODSUCKER_CAN_BUY (1<<0)
-/// This Power can be purchased by Tremere Bloodsuckers
-#define TREMERE_CAN_BUY (1<<1)
+/// This Power can be purchased by Lasombra Bloodsuckers
+#define LASOMBRA_CAN_BUY (1<<1)
+/// This Power can be purchased by Gangrel Bloodsuckers
+#define GANGREL_CAN_BUY (1<<2)
/// This Power can be purchased by Vassals
-#define VASSAL_CAN_BUY (1<<2)
+#define VASSAL_CAN_BUY (1<<3)
/// This Power can be purchased by Monster Hunters
-#define HUNTER_CAN_BUY (1<<3)
+#define HUNTER_CAN_BUY (1<<4)
+/// This Power can be purchased by Tzimisce Bloodsuckers
+#define TZIMISCE_CAN_BUY (1<<5)
/// This Power is a Toggled Power
#define BP_AM_TOGGLE (1<<0)
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index ad37bb80e11d..7759f4403d79 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -79,6 +79,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isethereal(A) (is_species(A, /datum/species/ethereal))
#define isvampire(A) (is_species(A,/datum/species/vampire))
#define ispreternis(A) (is_species(A,/datum/species/preternis))
+#define isszlachta(A) (is_species(A, /datum/species/szlachta))
//more carbon mobs
#define ismonkey(A) (istype(A, /mob/living/carbon/monkey))
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index 47274a1edd1e..4afbccca45e9 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -80,6 +80,8 @@
#define STATUS_EFFECT_SUMMONEDGHOST /datum/status_effect/cultghost //is a cult ghost and can't use manifest runes
+#define STATUS_EFFECT_SHADOWAFFLICTED /datum/status_effect/the_shadow //Heavy hallucinations + ear damage with a shadowman overlay
+
#define STATUS_EFFECT_CRUSHERMARK /datum/status_effect/crusher_mark //if struck with a proto-kinetic crusher, takes a ton of damage
#define STATUS_EFFECT_KNUCKLED /datum/status_effect/knuckled //if struck with bloody knuckles or their ability, gets rooted
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index 7afd26b82220..16292d53a452 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -358,6 +358,41 @@
if(owner.reagents)
owner.reagents.del_reagent(/datum/reagent/water/holywater) //can't be deconverted
+/datum/status_effect/the_shadow
+ id = "the_shadow"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = -1
+ var/mutable_appearance/shadow
+
+/datum/status_effect/the_shadow/on_apply()
+ if(ishuman(owner))
+ shadow = mutable_appearance('icons/effects/effects.dmi', "curse")
+ shadow.pixel_x = -owner.pixel_x
+ shadow.pixel_y = -owner.pixel_y
+ owner.add_overlay(shadow)
+ to_chat(owner, span_boldwarning("The shadows invade your mind, MUST. GET. THEM. OUT"))
+ return TRUE
+ return FALSE
+
+/datum/status_effect/the_shadow/tick()
+ var/turf/T = get_turf(owner)
+ var/light_amount = T.get_lumcount()
+ if(light_amount > 0.2)
+ to_chat(owner, span_notice("As the light reaches the shadows, they dissipate!"))
+ qdel(src)
+ if(owner.stat == DEAD)
+ qdel(src)
+ owner.hallucination += 2
+ owner.confused += 2
+ owner.adjustEarDamage(0, 5)
+
+/datum/status_effect/the_shadow/Destroy()
+ if(owner)
+ owner.cut_overlay(shadow)
+ QDEL_NULL(shadow)
+ return ..()
+
/datum/status_effect/crusher_mark
id = "crusher_mark"
duration = 300 //if you leave for 30 seconds you lose the mark, deal with it
diff --git a/code/game/gamemodes/bloodsuckers/bloodsucker.dm b/code/game/gamemodes/bloodsuckers/bloodsucker.dm
index d515604c9a31..72f5f83cc326 100644
--- a/code/game/gamemodes/bloodsuckers/bloodsucker.dm
+++ b/code/game/gamemodes/bloodsuckers/bloodsucker.dm
@@ -28,6 +28,7 @@
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
+
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
@@ -54,8 +55,8 @@
/datum/game_mode/bloodsucker/generate_report()
return "There's been a report of the undead roaming around the sector, especially those that display Vampiric abilities.\
- They've displayed the ability to disguise themselves as anyone and brainwash the minds of people they capture alive.\
- Please take care of the crew and their health, as it is impossible to tell if one is lurking in the darkness behind."
+ They've displayed the ability to disguise themselves as anyone and brainwash the minds of people they capture alive.\
+ Please take care of the crew and their health, as it is impossible to tell if one is lurking in the darkness behind."
/datum/game_mode/bloodsucker/make_antag_chance(mob/living/carbon/human/character)
var/bloodsuckercap = min(round(GLOB.joined_player_list.len / (3 * 4)) + 2, round(GLOB.joined_player_list.len / 2))
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index cf6a369ffc6c..67e48d32754f 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -1249,7 +1249,7 @@
if(istype(I, /obj/item/jawsoflife))
if(isElectrified())
- shock(user,100)//it's like sticking a forck in a power socket
+ shock(user,100)//it's like sticking a fork in a power socket
return
if(!density)//already open
diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_daylight.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_daylight.dm
index 59106c57902f..5960ff7569ba 100644
--- a/code/modules/antagonists/bloodsuckers/bloodsucker_daylight.dm
+++ b/code/modules/antagonists/bloodsuckers/bloodsucker_daylight.dm
@@ -1,7 +1,7 @@
-/// 1 minute
-#define TIME_BLOODSUCKER_DAY 60
-/// 10 minutes
-#define TIME_BLOODSUCKER_NIGHT 600
+/// 45 seconds
+#define TIME_BLOODSUCKER_DAY 45
+/// 15 minutes
+#define TIME_BLOODSUCKER_NIGHT 900
/// 1.5 minutes
#define TIME_BLOODSUCKER_DAY_WARN 90
/// 30 seconds
@@ -88,17 +88,15 @@
var/datum/antagonist/bloodsucker/bloodsuckerdatum = bloodsucker_minds.has_antag_datum(/datum/antagonist/bloodsucker)
if(!istype(bloodsuckerdatum))
continue
- if(bloodsuckerdatum.my_clan == CLAN_GANGREL)
+ if(bloodsuckerdatum.my_clan == CLAN_GANGREL)
give_transform_power()
- if(!iscarbon(bloodsucker_minds.current))
- qdel(bloodsucker_minds.current)
if(bloodsuckerdatum.altar_uses > 0)
to_chat(bloodsuckerdatum, span_notice("Your Altar uses have been reset!"))
bloodsuckerdatum.altar_uses = 0
- warn_daylight(4, span_userdanger("Solar flares bombard the station with deadly UV light!
Stay in cover for the next [TIME_BLOODSUCKER_DAY / 60] minutes or risk Final Death!"), \
+ warn_daylight(4, span_userdanger("Solar flares bombard the station with deadly UV light!
Stay in cover for the next [TIME_BLOODSUCKER_DAY] seconds or risk Final Death!"), \
span_userdanger("Solar flares bombard the station with UV light!"), \
span_userdanger("The sunlight is visible throughout the station, the Bloodsuckers must be asleep by now!"))
- message_admins("BLOODSUCKER NOTICE: Daylight Beginning (Lasts for [TIME_BLOODSUCKER_DAY / 60] minutes.)")
+ message_admins("BLOODSUCKER NOTICE: Daylight Beginning (Lasts for [TIME_BLOODSUCKER_DAY] seconds.)")
/obj/effect/sunlight/proc/warn_daylight(danger_level = 0, vampwarn = "", vassalwarn = "", hunteralert = "")
for(var/datum/mind/bloodsucker_minds as anything in get_antag_minds(/datum/antagonist/bloodsucker))
@@ -181,13 +179,14 @@
var/datum/antagonist/bloodsucker/bloodsuckerdatum = bloodsucker_minds.has_antag_datum(/datum/antagonist/bloodsucker)
for(var/datum/action/bloodsucker/power in bloodsuckerdatum.powers)
if(istype(power, /datum/action/bloodsucker/gohome))
- bloodsuckerdatum.powers -= power
- power.Remove(bloodsucker_minds.current)
+ bloodsuckerdatum.RemovePower(power)
/obj/effect/sunlight/proc/give_transform_power()
for(var/datum/mind/bloodsucker_minds as anything in get_antag_minds(/datum/antagonist/bloodsucker))
if(!istype(bloodsucker_minds) || !istype(bloodsucker_minds.current))
continue
var/datum/antagonist/bloodsucker/bloodsuckerdatum = bloodsucker_minds.has_antag_datum(/datum/antagonist/bloodsucker)
+ if(bloodsuckerdatum.my_clan != CLAN_GANGREL)
+ continue
if(!(locate(/datum/action/bloodsucker/gangrel/transform) in bloodsuckerdatum.powers))
bloodsuckerdatum.BuyPower(new /datum/action/bloodsucker/gangrel/transform)
diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_flaws.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_flaws.dm
index db44af151235..21dfc2d05144 100644
--- a/code/modules/antagonists/bloodsuckers/bloodsucker_flaws.dm
+++ b/code/modules/antagonists/bloodsuckers/bloodsucker_flaws.dm
@@ -1,53 +1,79 @@
/////////////////////////////////////////////////////////////////////////////////////////
// Any changes to clans have to be reflected in '/obj/item/book/kindred' /search proc. //
/////////////////////////////////////////////////////////////////////////////////////////
-/datum/antagonist/bloodsucker/proc/AssignClanAndBane()
+/datum/antagonist/bloodsucker/proc/AssignClanAndBane(tzimisce = FALSE)
+ var/mob/living/carbon/human/bloodsucker = owner.current
+ if(tzimisce)
+ my_clan = CLAN_TZIMISCE
+ to_chat(owner, span_announce("As you arrive near the station, you recall all you know and why you are here.\n\
+ * As a part of the Tzimisce Clan, you are able to Dice corpses into muscle pieces.\n\
+ * With muscles pieces you are able to mutilate dead husked vassals into greater beings,\n\
+ * The more you climb up the Ranks the more research you gather about fleshcrafting and beings you can make.\n\
+ * Remember to fuel a vassalrack with the muscles to be able to toy with those dead vassals, you are also able to ressurect people this way.\n\
+ * Finally, your Favorite Vassal will turn into a battle monster to help you in combat."))
+ AddHumanityLost(5.6)
+ BuyPower(new /datum/action/bloodsucker/targeted/dice)
+ bloodsucker.faction |= "bloodhungry" //flesh monster's clan
+ var/list/powerstoremove = list(/datum/action/bloodsucker/veil, /datum/action/bloodsucker/masquerade)
+ for(var/datum/action/bloodsucker/P in powers)
+ if(is_type_in_list(P, powerstoremove))
+ RemovePower(P)
+ return
var/static/list/clans = list(
CLAN_GANGREL,
- //CLAN_LASOMBRA,
- "None",
+ CLAN_LASOMBRA,
)
var/list/options = list()
options = clans
// Brief descriptions in case they don't read the Wiki.
to_chat(owner, span_announce("List of all Clans:\n\
- Gangrel - Prone to Frenzy, special power.\n\
- None - Continue living without a clan."))
+ Gangrel - Prone to Frenzy, strange outcomes from being on frenzy, special power.\n\
+ Lasombra - Life in the shadows, very weak to fire but no brute damage, upgradable abilities through tasks."))
var/answer = input("You have Ranked up far enough to remember your clan. Which clan are you part of?", "Our mind feels luxurious...") in options
- if(!answer || answer == "None")
+ if(!answer)
to_chat(owner, span_warning("You have wilingfully decided to stay ignorant."))
return
- var/mob/living/carbon/human/bloodsucker = owner.current
- //switch(answer)
- if(answer == CLAN_GANGREL)
- my_clan = CLAN_GANGREL
- to_chat(owner, span_announce("You have Ranked up enough to learn: You are part of the Gangrel Clan!\n\
- * As part of the Gangrel Clan, your inner beast has a stronger impact in your undead life.\n\
- * You are prone to falling into a frenzy, and will unleash a wild beast form when doing so,\n\
- * Though once per night you are able to unleash your inner beast to help you in combat.\n\
- * Due to growing more feral you've also strayed away from other bloodsuckers and will only be able to maintain one vassal.\n\
- * Finally, your Favorite Vassal will gain the Minor Beast Form ability to help you in combat."))
- AddHumanityLost(22.4)
- BuyPower(new /datum/action/bloodsucker/gangrel/transform)
- bloodsucker.faction |= "bloodhungry" //i love animals i love animals
- /*if(CLAN_LASOMBRA)
+ switch(answer)
+ if(CLAN_GANGREL)
+ my_clan = CLAN_GANGREL
+ to_chat(owner, span_announce("You have Ranked up enough to learn: You are part of the Gangrel Clan!\n\
+ * As part of the Gangrel Clan, your inner beast has a stronger impact in your undead life.\n\
+ * You are prone to falling into a frenzy, and will unleash a wild beast form when doing so,\n\
+ * Though once per night you are able to unleash your inner beast to help you in combat.\n\
+ * Due to growing more feral you've also strayed away from other bloodsuckers and will only be able to maintain one vassal.\n\
+ * Finally, your Favorite Vassal will gain the Minor Beast Form ability to help you in combat."))
+ AddHumanityLost(16.8)
+ BuyPower(new /datum/action/bloodsucker/gangrel/transform)
+ bloodsucker.faction |= "bloodhungry" //i love animals i love animals
+ RemovePower(/datum/action/bloodsucker/masquerade)
+ var/datum/objective/bloodsucker/frenzy/gangrel_objective = new
+ gangrel_objective.owner = owner
+ objectives += gangrel_objective
+ if(CLAN_LASOMBRA)
my_clan = CLAN_LASOMBRA
to_chat(owner, span_announce("You have Ranked up enough to learn: You are part of the Lasombra Clan!\n\
- * As part of the Lasombra Clan, your past teachings have taught you how to become in touch with the Abyss and practice it's prophecies.\n\
+ * As part of the Lasombra Clan, your past teachings have shown you how to become in touch with the Abyss and practice it's prophecies.\n\
* It'll take long before the Abyss can break through this plane's veil, but you'll try to salvage any of the energy that comes through,\n\
- * To harness it's energy a ritual must be done each night to gain a shadowpoint, shadowpoints let's you upgrades normal abilities into upgraded ones.\n\
+ * To harness it's energy you must first find an influence and make a Resting Place altar to feed the harvested essence to.\n\
+ * On the Resting Place you can give ranks or blood in exchange for shadowpoints, that can be spent on the table to ascend your abilities.\n\
* The Abyss has blackened your veins and made you immune to brute damage but highly receptive to burn, so you might need to be extra careful when on Torpor.\n\
- * Finally, your Favorite Vassal will gain the Minor Glare and Shadow Walk abilities to help you in combat."))
- ADD_TRAIT(bloodsucker, TRAIT_BRUTEIMMUNE, BLOODSUCKER_TRAIT)
- ADD_TRAIT(bloodsucker, TRAIT_SCORCHED, BLOODSUCKER_TRAIT)
+ * Finally, your Favorite Vassal will gain the Lesser Glare and Shadow Walk abilities to help you in combat."))
+ bloodsucker.physiology.burn_mod *= 2
+ bloodsucker.physiology.brute_mod *= 0
+ bloodsucker.eye_color = "f00"
ADD_TRAIT(bloodsucker, CULT_EYES, BLOODSUCKER_TRAIT)
+ bloodsucker.update_body()
var/obj/item/organ/heart/nightmare/nightmarish_heart = new
nightmarish_heart.Insert(bloodsucker)
nightmarish_heart.Stop()
for(var/obj/item/light_eater/blade in bloodsucker.held_items)
QDEL_NULL(blade)
- owner.teach_crafting_recipe(/datum/crafting_recipe/meatcoffin)*/
-
-
+ GLOB.reality_smash_track.AddMind(owner)
+ var/datum/objective/bloodsucker/hierarchy/lasombra_objective = new
+ lasombra_objective.owner = owner
+ objectives += lasombra_objective
+ to_chat(owner, span_notice("You have also learned how to channel the abyss's power into an iron knight's armor that can be build in the structure ta and activated as a trap for your lair."))
+ owner.teach_crafting_recipe(/datum/crafting_recipe/possessedarmor)
+ owner.teach_crafting_recipe(/datum/crafting_recipe/restingplace)
owner.announce_objectives()
\ No newline at end of file
diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_frenzy.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_frenzy.dm
index 4d4dd980aad3..eb605ff68e7d 100644
--- a/code/modules/antagonists/bloodsuckers/bloodsucker_frenzy.dm
+++ b/code/modules/antagonists/bloodsuckers/bloodsucker_frenzy.dm
@@ -28,20 +28,20 @@
status_type = STATUS_EFFECT_UNIQUE
duration = -1
tick_interval = 10
- examine_text = "They seem... inhumane, and feral!"
- alert_type = /atom/movable/screen/alert/status_effect/frenzy
+ examine_text = span_notice("They seem... inhumane, and feral!")
+ alert_type = /obj/screen/alert/status_effect/frenzy
/// Store whether they were an advancedtooluser, to give the trait back upon exiting.
var/was_tooluser = FALSE
/// The stored Bloodsucker antag datum
var/datum/antagonist/bloodsucker/bloodsuckerdatum
-/atom/movable/screen/alert/status_effect/frenzy
+/obj/screen/alert/status_effect/frenzy
name = "Frenzy"
desc = "You are in a Frenzy! You are entirely Feral and, depending on your Clan, fighting for your life!"
icon = 'icons/mob/actions/actions_bloodsucker.dmi'
icon_state = "power_recover"
-/atom/movable/screen/alert/status_effect/masquerade/MouseEntered(location,control,params)
+/obj/screen/alert/status_effect/masquerade/MouseEntered(location,control,params)
desc = initial(desc)
return ..()
@@ -51,7 +51,7 @@
// Disable ALL Powers and notify their entry
bloodsuckerdatum.DisableAllPowers()
- to_chat(owner, span_userdanger("Blood! You need Blood, now! You enter a total Frenzy!"))
+ to_chat(owner, span_userdanger("Blood! You need Blood, now! You enter a total Frenzy! Your skin starts sizzling...."))
to_chat(owner, span_announce("* Bloodsucker Tip: While in Frenzy, you instantly Aggresively grab, have stun resistance, cannot speak, hear, or use any powers outside of Feed and Trespass (If you have it)."))
// Stamina resistances
user.physiology.stamina_mod *= 0.4
@@ -71,7 +71,7 @@
user.clear_cuffs(cuffs, TRUE)
user.clear_cuffs(legcuffs, TRUE)
// Keep track of how many times we've entered a Frenzy.
- bloodsuckerdatum.frenzies += 1
+ bloodsuckerdatum.frenzies++
bloodsuckerdatum.frenzied = TRUE
return ..()
@@ -97,4 +97,4 @@
var/mob/living/carbon/human/user = owner
if(!bloodsuckerdatum.frenzied)
return
- user.adjustFireLoss(1.5 + (bloodsuckerdatum.humanity_lost / 10))
+ user.adjustFireLoss(0.5 + (bloodsuckerdatum.humanity_lost / 15))
diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_integration.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_integration.dm
index 18fc9fdd7d12..30b560a9db34 100644
--- a/code/modules/antagonists/bloodsuckers/bloodsucker_integration.dm
+++ b/code/modules/antagonists/bloodsuckers/bloodsucker_integration.dm
@@ -16,15 +16,6 @@
return
. = ..()
-/// Prevents Bloodsuckers from naturally regenerating Blood - Even while on masquerade
-/mob/living/carbon/human/handle_blood(delta_time, times_fired)
- if(mind && IS_BLOODSUCKER(src))
- return
- /// For Vassals -- Bloodsuckers get this removed while on Masquerade, so we don't want to remove the check above.
- if(HAS_TRAIT(src, TRAIT_NOPULSE))
- return
- . = ..()
-
/mob/living/carbon/human/natural_bodytemperature_stabilization(datum/gas_mixture/environment, delta_time, times_fired)
// Return 0 as your natural temperature. Species proc handle_environment() will adjust your temperature based on this.
if(HAS_TRAIT(src, TRAIT_COLDBLOODED))
@@ -53,6 +44,8 @@
if(bloodsuckerdatum)
. += ""
. += "Blood Drank: [bloodsuckerdatum.total_blood_drank]"
+ if(bloodsuckerdatum.current_task)
+ . += "Task Blood Drank: [bloodsuckerdatum.task_blood_drank]"
// INTEGRATION: Adding Procs and Datums to existing "classes" //
diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm
new file mode 100644
index 000000000000..783cd72a3f9c
--- /dev/null
+++ b/code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm
@@ -0,0 +1,253 @@
+/mob/living/simple_animal/hostile/bloodsucker
+ icon = 'icons/mob/bloodsucker_mobs.dmi'
+ harm_intent_damage = 20
+ melee_damage_lower = 20
+ melee_damage_upper = 20
+ see_in_dark = 10
+ speak_chance = 0
+ mob_size = MOB_SIZE_LARGE
+ gold_core_spawnable = FALSE
+ movement_type = GROUND
+ attack_sound = 'sound/weapons/slash.ogg'
+ faction = list("hostile", "bloodhungry")
+ response_help = "touches"
+ response_disarm = "flails at"
+ response_harm = "punches"
+ var/mob/living/bloodsucker
+
+/mob/living/simple_animal/hostile/bloodsucker/werewolf
+ name = "werewolf"
+ desc = "Who could imagine this things 'were' actually real?"
+ icon_state = "wolfform"
+ icon_living = "wolfform"
+ icon_dead = "wolf_dead"
+ icon_gib = "wolf_dead"
+ speed = -1.5
+ maxHealth = 450
+ health = 450
+ harm_intent_damage = 25
+ melee_damage_lower = 20
+ melee_damage_upper = 25
+ attacktext = "violently mawls"
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 5)
+ obj_damage = 50
+ environment_smash = ENVIRONMENT_SMASH_WALLS
+ speak_emote = list("gnashes")
+ var/satiation = 0
+
+/mob/living/simple_animal/hostile/bloodsucker/giantbat
+ name = "giant bat"
+ desc = "That's a fat ass bat."
+ icon_state = "batform"
+ icon_living = "batform"
+ icon_dead = "bat_dead"
+ icon_gib = "bat_dead"
+ maxHealth = 350
+ health = 350
+ attacktext = "bites"
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 3)
+ attack_sound = 'sound/weapons/bite.ogg'
+ obj_damage = 35
+ pass_flags = PASSTABLE | PASSCOMPUTER
+ environment_smash = ENVIRONMENT_SMASH_STRUCTURES
+ movement_type = FLYING
+ speak_emote = list("loudly squeaks")
+
+/mob/living/simple_animal/hostile/bloodsucker/possessedarmor
+ name = "possessed armor"
+ desc = "Whatever possessed this suit of armor to suddenly walk about and start killing everyone?"
+ icon_state = "posarmor"
+ icon_living = "posarmor"
+ response_help = "pokes"
+ response_disarm = "pushes"
+ response_harm = "punches"
+ maxHealth = 250
+ health = 250
+ attacktext = "rends"
+ obj_damage = 50
+ environment_smash = ENVIRONMENT_SMASH_STRUCTURES
+ speak_emote = list("manifests")
+ var/upgraded = FALSE
+
+/mob/living/simple_animal/hostile/bloodsucker/possessedarmor/upgraded
+ name = "armed possessed armor"
+ icon_state = "posarmor_sword"
+ icon_living = "posarmor_sword"
+ upgraded = TRUE
+ obj_damage = 55
+ harm_intent_damage = 25
+ melee_damage_lower = 25
+ melee_damage_upper = 25
+
+/////////////////////////////////////////////////////
+/// TZIMISCE BLOODSUCKER MOBS ///
+/////////////////////////////////////////////////////
+
+/mob/living/simple_animal/hostile/bloodsucker/tzimisce
+
+/mob/living/simple_animal/hostile/bloodsucker/tzimisce/triplechest
+ name = "gigantous monstrosity"
+ desc = "You wouldn't think a being so messed up like this would be able to even breathe."
+ icon_state = "triplechest"
+ icon_living = "triplechest"
+ icon_dead = "triplechest_dead"
+ speed = 1
+ maxHealth = 175
+ health = 175
+ environment_smash = ENVIRONMENT_SMASH_WALLS
+ harm_intent_damage = 25
+ melee_damage_lower = 25
+ melee_damage_upper = 25
+ obj_damage = 50
+
+/mob/living/simple_animal/hostile/bloodsucker/tzimisce/calcium
+ name = "boney monstrosity"
+ desc = "Heretical being beyond comprehesion, now with bones free of charge!"
+ icon_state = "calcium"
+ icon_living = "calcium"
+ icon_dead = "calcium_dead"
+ speed = -1
+ maxHealth = 110
+ health = 110
+ mob_size = MOB_SIZE_SMALL
+ ventcrawler = VENTCRAWLER_ALWAYS
+ harm_intent_damage = 7
+ melee_damage_lower = 7
+ melee_damage_upper = 7
+ obj_damage = 20
+
+/mob/living/simple_animal/hostile/bloodsucker/tzimisce/armmy
+ name = "tiny monstrosity"
+ desc = "Is that a head?!"
+ icon_state = "armmy"
+ icon_living = "armmy"
+ icon_dead = "armmy_dead"
+ speed = -2
+ maxHealth = 75
+ health = 75
+ mob_size = MOB_SIZE_TINY
+ ventcrawler = VENTCRAWLER_ALWAYS
+ pass_flags = PASSTABLE
+ harm_intent_damage = 5
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+ attack_sound = 'sound/weapons/bite.ogg'
+ obj_damage = 10
+
+///////////////////////////////
+/// Inheritances ///
+///////////////////////////////
+
+/mob/living/simple_animal/hostile/bloodsucker/Destroy() //makes us alive again
+ if(bloodsucker && mind)
+ visible_message(span_warning("[src] rapidly transforms into a humanoid figure!"), span_warning("You forcefully return to your normal form."))
+ playsound(src, 'sound/weapons/slash.ogg', 50, 1)
+ if(mind)
+ mind.transfer_to(bloodsucker)
+ bloodsucker.forceMove(get_turf(src))
+ if(istype(src, /mob/living/simple_animal/hostile/bloodsucker/werewolf) || istype(src, /mob/living/simple_animal/hostile/bloodsucker/possessedarmor))
+ STOP_PROCESSING(SSprocessing, src)
+ return ..()
+
+/mob/living/simple_animal/hostile/bloodsucker/death()
+ if(bloodsucker && mind)
+ mind.transfer_to(bloodsucker)
+ bloodsucker.death()
+ qdel(src)
+ ..()
+
+/mob/living/simple_animal/hostile/bloodsucker/proc/devour(mob/living/target)
+ health += target.maxHealth / 4
+ var/mob/living/carbon/human/H = target
+ var/foundorgans = 0
+ for(var/obj/item/organ/O in H.internal_organs)
+ if(O.zone == "chest")
+ foundorgans++
+ qdel(O)
+ if(foundorgans)
+ if(istype(src, /mob/living/simple_animal/hostile/bloodsucker/werewolf))
+ var/mob/living/simple_animal/hostile/bloodsucker/werewolf/ww = src
+ ww.satiation++
+ src.visible_message(span_danger("[src] devours [target]'s organs!"), \
+ span_userdanger("As you devour [target]'s organs you feel as if the beast inside you has calmed itself down, you'll need to feast [3 - ww.satiation] more times to become human again."))
+ for(var/obj/item/bodypart/B in H.bodyparts)
+ if(B.body_zone == "chest")
+ B.dismember()
+ else
+ to_chat(src, span_warning("There are no organs left in this corpse."))
+
+///////////////////////////
+/// Tzimisce ///
+///////////////////////////
+
+////////////////////////////
+/// Werewolf ///
+///////////////////////////
+
+/mob/living/simple_animal/hostile/bloodsucker/werewolf/Initialize()
+ . = ..()
+ START_PROCESSING(SSprocessing, src)
+
+/mob/living/simple_animal/hostile/bloodsucker/werewolf/process()
+ if(bloodsucker)
+ if(ishuman(bloodsucker))
+ var/mob/living/carbon/human/user = bloodsucker
+ if(user.blood_volume < 560)
+ user.blood_volume += 10
+ health -= 0.25 //3 minutes to die
+ if(satiation >= 3)
+ to_chat(src, span_notice("It has been fed. You turn back to normal."))
+ qdel(src)
+ return
+
+/mob/living/simple_animal/hostile/bloodsucker/werewolf/Destroy()
+ . = ..()
+ if(ishuman(bloodsucker))
+ var/mob/living/carbon/human/user = bloodsucker
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ var/datum/species/user_species = user.dna.species
+ var/mutation = ""
+ var/slot = ""
+ var/additionalmessage = ""
+ bloodsuckerdatum.clanprogress++
+ switch(bloodsuckerdatum.clanprogress)
+ if(1)
+ additionalmessage = "You have mutated a collar made out of fur!"
+ user_species.armor += 10
+ mutation = /obj/item/clothing/neck/wolfcollar
+ slot = SLOT_NECK
+ if(2)
+ additionalmessage = "You have mutated werewolf ears!"
+ mutation = /obj/item/radio/headset/wolfears
+ slot = SLOT_EARS
+ if(3)
+ additionalmessage = "You have mutated werewolf claws!"
+ user_species.punchdamagelow += 2.5
+ user_species.punchdamagehigh += 2.5
+ mutation = /obj/item/clothing/gloves/wolfclaws
+ slot = SLOT_GLOVES
+ if(4)
+ additionalmessage = "You have mutated werewolf legs!"
+ mutation = /obj/item/clothing/shoes/wolflegs
+ slot = SLOT_SHOES
+ if(DIGITIGRADE in user.dna.species.species_traits)
+ mutation = /obj/item/clothing/shoes/xeno_wraps/wolfdigilegs
+ if(5 to INFINITY)
+ to_chat(user, span_danger("The beast inside of you seems satisfied with your current form."))
+ return
+ to_chat(user, span_danger("After returning to normal, you feel strange. [additionalmessage]"))
+ var/obj/item/pastdrip = user.get_item_by_slot(slot)
+ user.dropItemToGround(pastdrip)
+ user.equip_to_slot_or_del(new mutation(user), slot)
+
+////////////////////////
+/// Armor ///
+////////////////////////
+
+/mob/living/simple_animal/hostile/bloodsucker/possessedarmor/death()
+ if(upgraded)
+ new /obj/structure/bloodsucker/possessedarmor/upgraded(src.loc)
+ else
+ new /obj/structure/bloodsucker/possessedarmor(src.loc)
+ qdel(src)
+ ..()
\ No newline at end of file
diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm
index 95961642552d..4ebd20744c2f 100644
--- a/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm
+++ b/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm
@@ -217,7 +217,7 @@
// GENERATE!
/datum/objective/bloodsucker/gourmand/New()
- target_amount = rand(1250,2000)
+ target_amount = rand(750, 1250)
..()
// EXPLANATION
@@ -252,17 +252,17 @@
// WIN CONDITIONS?
/datum/objective/bloodsucker/monsterhunter/check_completion()
var/list/datum/mind/monsters = list()
- for(var/mob/living/players in GLOB.alive_mob_list)
- if(IS_HERETIC(players) || IS_BLOODSUCKER(players) || iscultist(players) || is_wizard(players) || is_servant_of_ratvar(players))
- monsters += players
- if(players?.mind?.has_antag_datum(/datum/antagonist/changeling))
- monsters += players
- if(players?.mind?.has_antag_datum(/datum/antagonist/wizard/apprentice))
- monsters += players
- for(var/datum/mind/monster_minds in monsters)
- if(monster_minds && monster_minds != owner && monster_minds.current.stat != DEAD)
- return FALSE
- return TRUE
+ for(var/datum/antagonist/monster in GLOB.antagonists)
+ var/datum/mind/brain = monster.owner
+ if(!brain || brain == owner)
+ continue
+ if(brain.current.stat == DEAD)
+ continue
+ if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || is_servant_of_ratvar(brain.current) || is_wizard(brain.current))
+ monsters += brain
+ if(brain.has_antag_datum(/datum/antagonist/changeling))
+ monsters += brain
+ return completed || !monsters.len
@@ -365,6 +365,25 @@
return TRUE
return FALSE
+/datum/objective/bloodsucker/hierarchy
+ name = "hierarchy"
+
+/datum/objective/bloodsucker/hierarchy/New()
+ target_amount = rand(4,5)
+ ..()
+
+/datum/objective/bloodsucker/hierarchy/update_explanation_text()
+ . = ..()
+ explanation_text = "Ascend [target_amount] abilities using a Resting Place altar."
+
+/datum/objective/bloodsucker/hierarchy/check_completion()
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.current.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ if(!bloodsuckerdatum)
+ return FALSE
+ if(bloodsuckerdatum.clanprogress >= target_amount)
+ return TRUE
+ return FALSE
+
//////////////////////////////////////////////////////////////////////////////////////
/// Mutilate a certain amount of Vassals
diff --git a/code/modules/antagonists/bloodsuckers/bloodsuckers.dm b/code/modules/antagonists/bloodsuckers/bloodsuckers.dm
index 7b6ed4ee7c02..cc8f58d1a9e5 100644
--- a/code/modules/antagonists/bloodsuckers/bloodsuckers.dm
+++ b/code/modules/antagonists/bloodsuckers/bloodsuckers.dm
@@ -41,6 +41,10 @@
var/datum/martial_art/frenzygrab/frenzygrab = new
///You get assigned a Clan once you Rank up enough
var/my_clan = NONE
+ ///How many clan points you have -> Used in clans in order to assert certain limits // Upgrades and stuff
+ var/clanpoints = 0
+ ///How much progress have you done on your clan
+ var/clanprogress = 0
///Vassals under my control. Periodically remove the dead ones.
var/list/datum/antagonist/vassal/vassals = list()
@@ -186,7 +190,7 @@
/datum/antagonist/bloodsucker/admin_add(datum/mind/new_owner, mob/admin)
var/levels = input("How many unspent Ranks would you like [new_owner] to have?","Bloodsucker Rank", bloodsucker_level_unspent) as null | num
var/msg = " made [key_name_admin(new_owner)] into \a [name]"
- if(!isnull(levels))
+ if(levels > 1)
bloodsucker_level_unspent = levels
msg += " with [levels] extra unspent Ranks."
message_admins("[key_name_admin(usr)][msg]")
@@ -376,7 +380,7 @@
var/datum/antagonist/vassal/vassaldatum = IS_VASSAL(owner.current)
if(!owner || !owner.current || vassaldatum)
return
- bloodsucker_level_unspent++ //same thing as below
+ bloodsucker_level_unspent++
passive_blood_drain -= 0.03 * bloodsucker_level //do something. It's here because if you are gaining points through other means you are doing good
// Spend Rank Immediately?
if(istype(owner.current.loc, /obj/structure/closet/crate/coffin))
@@ -428,6 +432,10 @@
if(!choice || !options[choice])
to_chat(owner.current, span_notice("You prevent your blood from thickening just yet, but you may try again later."))
return
+ if((locate(options[choice]) in powers))
+ to_chat(owner.current, span_notice("You prevent your blood from thickening just yet, but you may try again later."))
+ return
+ // Prevent Bloodsuckers from purchasing a power while outside of their Coffin.
if(!istype(owner.current.loc, /obj/structure/closet/crate/coffin))
to_chat(owner.current, span_warning("You must be in your Coffin to purchase Powers."))
return
@@ -455,7 +463,7 @@
if(spend_rank)
bloodsucker_level_unspent--
// Ranked up enough? Let them join a Clan.
- if(bloodsucker_level == 3)
+ if(bloodsucker_level == 3 && my_clan == NONE) //updated for tzimisce
AssignClanAndBane()
// Ranked up enough to get your true Reputation?
@@ -487,19 +495,13 @@
switch(rand(1, 3))
if(1) // Protege and Drink Objective
rolled_objectives = list(new /datum/objective/bloodsucker/protege, new /datum/objective/bloodsucker/gourmand)
- for(var/datum/objective/bloodsucker/objective in rolled_objectives)
- objective.owner = owner
- objectives += objective
if(2) // Heart Thief and Protege Objective
rolled_objectives = list(new /datum/objective/bloodsucker/protege, new /datum/objective/bloodsucker/heartthief)
- for(var/datum/objective/bloodsucker/objective in rolled_objectives)
- objective.owner = owner
- objectives += objective
- if(3) // All of them
- rolled_objectives = list(new /datum/objective/bloodsucker/protege, new /datum/objective/bloodsucker/heartthief, new /datum/objective/bloodsucker/gourmand)
- for(var/datum/objective/bloodsucker/objective in rolled_objectives)
- objective.owner = owner
- objectives += objective
+ if(3) // Heart Thief and Drink Objective
+ rolled_objectives = list(new /datum/objective/bloodsucker/heartthief, new /datum/objective/bloodsucker/gourmand)
+ for(var/datum/objective/bloodsucker/objective in rolled_objectives)
+ objective.owner = owner
+ objectives += objective
/// Name shown on antag list
/datum/antagonist/bloodsucker/antag_listing_name()
diff --git a/code/modules/antagonists/bloodsuckers/bloodsuckers_objects.dm b/code/modules/antagonists/bloodsuckers/bloodsuckers_objects.dm
index b2aabbabcacb..53a44d7f0d84 100644
--- a/code/modules/antagonists/bloodsuckers/bloodsuckers_objects.dm
+++ b/code/modules/antagonists/bloodsuckers/bloodsuckers_objects.dm
@@ -357,5 +357,16 @@
Favorite Vassal: Unknown. \
Strength: Unknown.
\
Weakness: Unknown."
+ if(clan == CLAN_LASOMBRA)
+ dat += "This Clan seems to adore living in the Shadows and worshipping it's secrets.
\
+ They take their research and vanity seriously, they are always very proud of themselves after even minor achievements.
\
+ They appear to be in search of a station with a veil weakness to be able to channel their shadow's abyssal powers.
\
+ Their research into this sector has lead them to adopt red eyes as to view better in the shadows, which leads unmasked Lasombras to be easily identifiable.
\
+ Homewer they have appeared to have also evolved a hard chintin in their veins, which makes them invulnerable to brute damage.
\
+ Favorite Vassal: Their Favorite Vassal appears to have been imbued with abyssal essence and is able to blend in with the shadows. \
+ Strength: They are able to slowly advance their abilities.
\
+ Weakness: Immensely weak to burn damage."
+ if(clan == CLAN_TZIMISCE)
+ dat += "The page is covered in blood. It seems like it will need time to vanish..."
reader << browse("Penned by [author].
" + "[dat]", "window=book[window_size != null ? ";size=[window_size]" : ""]")
diff --git a/code/modules/antagonists/bloodsuckers/powers/_powers.dm b/code/modules/antagonists/bloodsuckers/powers/_powers.dm
index 66225e2fa896..cf3e472a378b 100644
--- a/code/modules/antagonists/bloodsuckers/powers/_powers.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/_powers.dm
@@ -22,7 +22,7 @@
/// Requirement flags for checks
check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_CANT_USE_WHILE_STAKED|BP_CANT_USE_WHILE_INCAPACITATED|BP_CANT_USE_WHILE_UNCONSCIOUS
/// Who can purchase the Power
- var/purchase_flags = NONE // BLOODSUCKER_CAN_BUY|TREMERE_CAN_BUY|VASSAL_CAN_BUY|HUNTER_CAN_BUY
+ var/purchase_flags = NONE // BLOODSUCKER_CAN_BUY|LASOMBRA_CAN_BUY|GANGREL_CAN_BUY|VASSAL_CAN_BUY|HUNTER_CAN_BUY
// COOLDOWNS //
///Timer between Power uses.
@@ -39,6 +39,8 @@
var/bloodcost = 0
///The cost to MAINTAIN this Power - Only used for Constant Cost Powers
var/constant_bloodcost = 0
+ ///If the Power has any additional descriptions coming from either 3rd partys or the power itself
+ var/additional_text = ""
// Modify description to add cost.
/datum/action/bloodsucker/New(Target)
@@ -47,6 +49,8 @@
/datum/action/bloodsucker/proc/UpdateDesc()
desc = initial(desc)
+ if(length(additional_text) > 0)
+ desc += "
ASCENDED: [additional_text]"
if(bloodcost > 0)
desc += "
COST: [bloodcost] Blood"
if(constant_bloodcost > 0)
@@ -55,6 +59,8 @@
desc += "
SINGLE USE: [name] can only be used once per night."
if(level_current > 0)
desc += "
LEVEL: [name] is currently level [level_current]."
+ if(cooldown > 0)
+ desc += "
COOLDOWN: [name] has a cooldown of [cooldown / 10] seconds."
/datum/action/bloodsucker/Destroy()
bloodsuckerdatum_power = null
@@ -175,16 +181,19 @@
user.blood_volume -= bloodcost
bloodsuckerdatum_power?.update_hud()
-/datum/action/bloodsucker/proc/ActivatePower()
+/datum/action/bloodsucker/proc/ActivatePower(process = TRUE)
active = TRUE
- if(power_flags & BP_AM_TOGGLE)
+ if(power_flags & BP_AM_TOGGLE && process == TRUE)
RegisterSignal(owner, COMSIG_LIVING_BIOLOGICAL_LIFE, .proc/UsePower)
- owner.log_message("used [src].", LOG_ATTACK, color="red")
+ owner.log_message("used [src][bloodcost != 0 ? " at the cost of [bloodcost]" : ""].", LOG_ATTACK, color="red")
UpdateButtonIcon()
-/datum/action/bloodsucker/proc/DeactivatePower()
- if(power_flags & BP_AM_TOGGLE)
+/datum/action/bloodsucker/proc/DeactivatePower(process = TRUE)
+ if(power_flags & BP_AM_TOGGLE && process == TRUE)
UnregisterSignal(owner, COMSIG_LIVING_BIOLOGICAL_LIFE)
+ if(power_flags & BP_AM_SINGLEUSE)
+ RemoveAfterUse()
+ return
active = FALSE
UpdateButtonIcon()
StartCooldown()
@@ -203,8 +212,6 @@
/// Checks to make sure this power can stay active
/datum/action/bloodsucker/proc/ContinueActive(mob/living/user, mob/living/target)
- if(!active)
- return FALSE
if(!user)
return FALSE
if(!constant_bloodcost > 0 || user.blood_volume > 0)
diff --git a/code/modules/antagonists/bloodsuckers/powers/cloak.dm b/code/modules/antagonists/bloodsuckers/powers/cloak.dm
index 1f9dba8f2301..7d119a9a9bf6 100644
--- a/code/modules/antagonists/bloodsuckers/powers/cloak.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/cloak.dm
@@ -14,6 +14,7 @@
constant_bloodcost = 0.2
cooldown = 5 SECONDS
var/was_running
+ var/runbound = TRUE
/// Must have nobody around to see the cloak
/datum/action/bloodsucker/cloak/CheckCanUse(mob/living/carbon/user)
@@ -29,8 +30,9 @@
. = ..()
var/mob/living/user = owner
was_running = (user.m_intent == MOVE_INTENT_RUN)
- if(was_running)
- user.toggle_move_intent()
+ if(runbound)
+ if(was_running)
+ user.toggle_move_intent()
user.digitalinvis = 1
user.digitalcamo = 1
to_chat(user, span_notice("You put your Cloak of Darkness on."))
@@ -42,10 +44,11 @@
return
animate(user, alpha = max(25, owner.alpha - min(75, 10 + 5 * level_current)), time = 1.5 SECONDS)
// Prevents running while on Cloak of Darkness
- if(user.m_intent != MOVE_INTENT_WALK)
- to_chat(owner, span_warning("You attempt to run, crushing yourself."))
- user.toggle_move_intent()
- user.adjustBruteLoss(rand(5,15))
+ if(runbound)
+ if(user.m_intent != MOVE_INTENT_WALK)
+ to_chat(owner, span_warning("You attempt to run, crushing yourself."))
+ user.toggle_move_intent()
+ user.adjustBruteLoss(rand(5,15))
/datum/action/bloodsucker/cloak/ContinueActive(mob/living/user, mob/living/target)
. = ..()
@@ -63,6 +66,56 @@
animate(user, alpha = 255, time = 1 SECONDS)
user.digitalinvis = 0
user.digitalcamo = 0
- if(was_running && user.m_intent == MOVE_INTENT_WALK)
- user.toggle_move_intent()
+ if(runbound)
+ if(was_running && user.m_intent == MOVE_INTENT_WALK)
+ user.toggle_move_intent()
to_chat(user, span_notice("You take your Cloak of Darkness off."))
+
+/datum/action/bloodsucker/cloak/shadow
+ name = "Cloak of Shadows"
+ desc = "Empowered to the abyss, fortitude will now grant you a shadow armor, making your grip harder to escape and reduce projectile damage while in darkness."
+ button_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ background_icon_state_on = "lasombra_power_on"
+ background_icon_state_off = "lasombra_power_off"
+ icon_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ button_icon_state = "power_state"
+ additional_text = "Additionally allows you to run during cloak and gain a physical cloak while in darkness."
+ purchase_flags = LASOMBRA_CAN_BUY
+ constant_bloodcost = 0.3
+ runbound = FALSE
+
+/obj/item/clothing/neck/yogs/sith_cloak/cloak
+ name = "cloak of shadows"
+ desc = "Fancy stuff."
+ icon = 'icons/obj/vamp_obj.dmi'
+ alternate_worn_icon = 'icons/obj/vamp_obj.dmi'
+ icon_state = "cloak"
+ item_state = "cloak"
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 10, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 10, "acid" = 100) //good if you haven nothing
+
+/obj/item/clothing/neck/yogs/sith_cloak/cloak/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, BLOODSUCKER_TRAIT)
+ START_PROCESSING(SSobj, src)
+
+/obj/item/clothing/neck/yogs/sith_cloak/cloak/process()
+ var/turf/T = get_turf(src)
+ var/light_amount = T.get_lumcount()
+ if(light_amount > 0.2)
+ qdel(src)
+ STOP_PROCESSING(SSobj, src)
+ src.visible_message(span_warning("The cape desintegrates as the light contacts it's surface!"))
+
+/datum/action/bloodsucker/cloak/shadow/ActivatePower()
+ . = ..()
+ var/turf/T = get_turf(owner)
+ var/light_amount = T.get_lumcount()
+ if(light_amount <= 0.2)
+ if(!owner.get_item_by_slot(SLOT_NECK))
+ owner.equip_to_slot_or_del( new /obj/item/clothing/neck/yogs/sith_cloak/cloak(null), SLOT_NECK)
+
+/datum/action/bloodsucker/cloak/shadow/DeactivatePower()
+ . = ..()
+ var/obj/item/I = owner.get_item_by_slot(SLOT_NECK)
+ if(istype(I, /obj/item/clothing/neck/yogs/sith_cloak/cloak))
+ qdel(I)
\ No newline at end of file
diff --git a/code/modules/antagonists/bloodsuckers/powers/fortitude.dm b/code/modules/antagonists/bloodsuckers/powers/fortitude.dm
index a981d84df7c4..6c4c7522347c 100644
--- a/code/modules/antagonists/bloodsuckers/powers/fortitude.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/fortitude.dm
@@ -80,3 +80,52 @@
name = "Flow"
desc = "Use the arts to Flow, giving shove and stun immunity, as well as brute, burn, dismember and pierce resistance. You cannot run while this is active."
purchase_flags = HUNTER_CAN_BUY
+
+/datum/action/bloodsucker/fortitude/shadow
+ name = "Shadow Armor"
+ desc = "Empowered to the abyss, fortitude will now grant you a shadow armor, making your grip harder to escape and reduce projectile damage while in darkness."
+ button_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ background_icon_state_on = "lasombra_power_on"
+ background_icon_state_off = "lasombra_power_off"
+ icon_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ button_icon_state = "power_armor"
+ additional_text = "Additionally gives you extra damage while fortitude'd and agro grab while in darkness."
+ purchase_flags = LASOMBRA_CAN_BUY
+ constant_bloodcost = 0.3
+ var/mutable_appearance/armor_overlay
+
+/datum/action/bloodsucker/fortitude/shadow/ActivatePower()
+ . = ..()
+ var/mob/living/carbon/human/user = owner
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ armor_overlay = mutable_appearance('icons/obj/vamp_obj.dmi', "fortarmor")
+ var/turf/T = get_turf(owner)
+ var/light_amount = T.get_lumcount()
+ if(light_amount <= 0.2)
+ owner.add_overlay(armor_overlay)
+ bloodsuckerdatum.frenzygrab.teach(user, TRUE)
+ to_chat(user, span_notice("Shadow tentacles form and attach themselves to your body, you feel as if your muscles have merged with the shadows!"))
+ var/datum/species/user_species = user.dna.species
+ user_species.punchdamagelow += 0.5 * level_current
+ user_species.punchdamagehigh += 0.5 * level_current
+
+/datum/action/bloodsucker/fortitude/shadow/process()
+ . = ..()
+ var/turf/T = owner.loc
+ var/light_amount = T.get_lumcount()
+ var/mob/living/carbon/user = owner
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ if(light_amount > 0.2)
+ owner.cut_overlay(armor_overlay)
+ bloodsuckerdatum.frenzygrab.remove(user)
+ to_chat(user, span_warning("As you enter in contact with the light, the tentacles dissipate!"))
+
+/datum/action/bloodsucker/fortitude/shadow/DeactivatePower()
+ . = ..()
+ var/mob/living/carbon/human/user = owner
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ owner.cut_overlay(armor_overlay)
+ bloodsuckerdatum.frenzygrab.remove(user)
+ var/datum/species/user_species = user.dna.species
+ user_species.punchdamagelow -= 0.5 / level_current
+ user_species.punchdamagehigh -= 0.5 / level_current
\ No newline at end of file
diff --git a/code/modules/antagonists/bloodsuckers/powers/gangrel.dm b/code/modules/antagonists/bloodsuckers/powers/gangrel.dm
index 7a69094ecdf8..46269cd1abbd 100644
--- a/code/modules/antagonists/bloodsuckers/powers/gangrel.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/gangrel.dm
@@ -4,6 +4,10 @@
background_icon_state = "gangrel_power_off"
background_icon_state_on = "gangrel_power_on"
background_icon_state_off = "gangrel_power_off"
+ purchase_flags = GANGREL_CAN_BUY
+ power_flags = BP_AM_TOGGLE|BP_AM_STATIC_COOLDOWN
+ check_flags = BP_AM_COSTLESS_UNCONSCIOUS
+ cooldown = 10 SECONDS
/datum/action/bloodsucker/gangrel/transform
name = "Transform"
@@ -15,125 +19,56 @@
Some forms have special abilites to them depending on what abilites you have.\n\
Be wary of your blood status when using it, takes 10 seconds of standing still to transform!"
power_flags = BP_AM_SINGLEUSE|BP_AM_STATIC_COOLDOWN
- check_flags = BP_AM_COSTLESS_UNCONSCIOUS
- purchase_flags = NONE
bloodcost = 100
- cooldown = 10 SECONDS
-
-/mob/living/simple_animal/hostile/bloodsucker
- var/mob/living/controller
-
-/mob/living/simple_animal/hostile/bloodsucker/werewolf
- name = "werewolf"
- desc = "Who could imagine this things 'were' actually real?"
- icon = 'icons/mob/bloodsucker_mobs.dmi'
- icon_state = "wolfform"
- icon_living = "wolfform"
- icon_dead = "batform"
- icon_gib = "batform"
- speed = -2
- response_help = "touches"
- response_disarm = "flails at"
- response_harm = "punches"
- speak_chance = 0
- maxHealth = 800
- health = 800
- see_in_dark = 10
- harm_intent_damage = 20
- melee_damage_lower = 20
- melee_damage_upper = 20
- attacktext = "violently mawls"
- butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 5)
- faction = list("hostile", "bloodhungry")
- attack_sound = 'sound/weapons/slash.ogg'
- obj_damage = 50
- environment_smash = ENVIRONMENT_SMASH_WALLS
- mob_size = MOB_SIZE_LARGE
- movement_type = GROUND
- gold_core_spawnable = FALSE
- speak_emote = list("gnashes")
-
-/mob/living/simple_animal/hostile/bloodsucker/giantbat
- name = "giant bat"
- desc = "That's a fat ass bat."
- icon = 'icons/mob/bloodsucker_mobs.dmi'
- icon_state = "batform"
- icon_living = "batform"
- icon_dead = "bat_dead"
- icon_gib = "bat_dead"
- move_to_delay = 2
- response_help = "touches"
- response_disarm = "flails at"
- response_harm = "punches"
- speak_chance = 0
- maxHealth = 700
- health = 700
- see_in_dark = 10
- harm_intent_damage = 20
- melee_damage_lower = 20
- melee_damage_upper = 20
- attacktext = "bites"
- butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 3)
- faction = list("hostile", "bloodhungry")
- attack_sound = 'sound/weapons/bite.ogg'
- obj_damage = 35
- pass_flags = PASSTABLE | PASSCOMPUTER
- environment_smash = ENVIRONMENT_SMASH_STRUCTURES
- mob_size = MOB_SIZE_LARGE
- movement_type = FLYING
- gold_core_spawnable = FALSE
- speak_emote = list("loudly squeaks")
-
-/mob/living/simple_animal/hostile/bloodsucker/Destroy() //makes us alive again
- if(controller && mind)
- visible_message(span_warning("[src] rapidly transforms into a humanoid figure!"), span_warning("You forcefully return to your normal form."))
- playsound(src, 'sound/weapons/slash.ogg', 50, 1)
- if(mind)
- mind.transfer_to(controller)
- controller.forceMove(get_turf(src))
- return ..()
-
-/mob/living/simple_animal/hostile/bloodsucker/death()
- if(controller)
- mind.transfer_to(controller)
- controller.death()
- addtimer(CALLBACK(src, .proc/gib), 20 SECONDS)
- ..()
/datum/action/bloodsucker/gangrel/transform/ActivatePower()
var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.mind.has_antag_datum(/datum/antagonist/bloodsucker)
var/mob/living/carbon/human/user = owner
var/datum/species/user_species = user.dna.species
+ var/minortransformdone = FALSE
+ var/mediumtransformdone = FALSE
user.Immobilize(10 SECONDS)
if(!do_mob(user, user, 10 SECONDS, 1))
return
switch(bloodsuckerdatum.total_blood_drank)
if(0 to 500)
- if(iscatperson(user))
- user.set_species(/datum/species/lizard)
- playsound(user.loc, 'sound/voice/lizard/hiss.ogg', 50)
+ if(!minortransformdone)
+ if(iscatperson(user))
+ user.set_species(/datum/species/lizard)
+ playsound(user.loc, 'sound/voice/lizard/hiss.ogg', 50)
+ else
+ user.set_species(/datum/species/human/felinid)
+ playsound(user.loc, 'sound/voice/feline/meow1.ogg', 50)
+ if(DIGITIGRADE in user_species.species_traits)
+ user_species.species_traits -= DIGITIGRADE
+ minortransformdone = TRUE
+ user_species.punchdamagelow += 5.0
+ user_species.punchdamagehigh += 5.0 //stronk
+ user_species.armor += 30
+ to_chat(user, span_notice("You aren't strong enough to morph into something stronger! But you do certainly feel more feral and stronger than before."))
else
- user.set_species(/datum/species/human/felinid)
- playsound(user.loc, 'sound/voice/feline/meow1.ogg', 50)
+ to_chat(user, span_notice("You still haven't evolved your ability yet."))
+ bloodsuckerdatum.AddBloodVolume(75)
+ if(500 to 1000)
+ if(!mediumtransformdone)
+ user.set_species(/datum/species/gorilla)
+ playsound(user.loc, 'sound/creatures/gorilla.ogg', 50)
if(DIGITIGRADE in user_species.species_traits)
user_species.species_traits -= DIGITIGRADE
- user_species.punchdamagehigh += 5.0 //stronk
- user_species.armor += 30
- to_chat(user, span_notice("You aren't strong enough to morph into something stronger! But you do certainly feel more feral and stronger than before."))
- if(500 to 1000)
- user.set_species(/datum/species/gorilla)
- to_chat(owner, span_notice("You transform into a gorrila-ey beast, you feel stronger!"))
- playsound(user.loc, 'sound/creatures/gorilla.ogg', 50)
- if(DIGITIGRADE in user_species.species_traits)
- user_species.species_traits -= DIGITIGRADE
- user_species.punchdamagehigh += 7.5 //very stronk
- user_species.armor += 35
+ mediumtransformdone = TRUE
+ user_species.punchdamagelow += 7.5
+ user_species.punchdamagehigh += 7.5 //very stronk
+ user_species.armor += 35
+ to_chat(owner, span_notice("You transform into a gorrila-ey beast, you feel stronger!"))
+ else
+ to_chat(owner, span_notice("You still haven't evolved your ability yet."))
+ bloodsuckerdatum.AddBloodVolume(50)
if(1500 to INFINITY)
var/mob/living/simple_animal/hostile/bloodsucker/giantbat/gb
if(!gb || gb.stat == DEAD)
gb = new /mob/living/simple_animal/hostile/bloodsucker/giantbat(user.loc)
user.forceMove(gb)
- gb.controller = user
+ gb.bloodsucker = user
user.mind.transfer_to(gb)
var/list/bat_powers = list(new /datum/action/bloodsucker/gangrel/transform_back,)
for(var/datum/action/bloodsucker/power in bloodsuckerdatum.powers)
@@ -148,17 +83,6 @@
QDEL_IN(gb, 2 MINUTES)
playsound(gb.loc, 'sound/items/toysqueak1.ogg', 50, 1)
to_chat(owner, span_notice("You transform into a fatty beast!"))
- /*if(2000 to INFINITY)
- var/mob/living/simple_animal/hostile/bloodsucker/werewolf/ww
- if(!ww || ww.stat == DEAD)
- ww = new /mob/living/simple_animal/hostile/bloodsucker/werewolf(user.loc)
- user.forceMove(ww)
- ww.controller = user
- user.mind.transfer_to(ww)
- var/datum/action/bloodsucker/gangrel/transform_back/E = new
- E.Grant(ww)
- playsound(ww.loc, 'sound/weapons/slash.ogg', 50, 1)
- to_chat(owner, span_notice("You transform into a feral beast!"))*/
. = ..()
/datum/action/bloodsucker/gangrel/transform_back
@@ -168,11 +92,7 @@
power_explanation = "Transform:\n\
Regress back to your humanoid form early, requires you to stand still.\n\
Beware you will not be able to transform again until the night passes!"
- power_flags = BP_AM_TOGGLE|BP_AM_STATIC_COOLDOWN
- check_flags = BP_AM_COSTLESS_UNCONSCIOUS
- purchase_flags = NONE
- cooldown = 10 SECONDS
-
+
/datum/action/bloodsucker/gangrel/transform_back/ActivatePower()
var/mob/living/user = owner
if(!do_mob(user, user, 10 SECONDS))
@@ -181,7 +101,12 @@
qdel(owner)
qdel(bs)
. = ..()
-
+/*
+////////////////||\\\\\\\\\\\\\\\\
+\\ Bat Only //
+// Powers \\
+\\\\\\\\\\\\\\\\||////////////////
+*/
/datum/action/bloodsucker/targeted/haste/batdash
name = "Flying Haste"
desc = "Propulse yourself into a position of advantage."
@@ -196,7 +121,7 @@
Created from your Immortal Haste ability."
power_flags = BP_AM_TOGGLE|BP_AM_STATIC_COOLDOWN
check_flags = NONE
- purchase_flags = NONE
+ purchase_flags = GANGREL_CAN_BUY
bloodcost = 0
cooldown = 15 SECONDS
@@ -224,7 +149,7 @@
Created from your Mesmerize ability."
power_flags = BP_AM_TOGGLE|BP_AM_STATIC_COOLDOWN
check_flags = NONE
- purchase_flags = NONE
+ purchase_flags = GANGREL_CAN_BUY
bloodcost = 0
cooldown = 12.5 SECONDS
@@ -236,7 +161,6 @@
/datum/action/bloodsucker/targeted/bloodbolt/FireTargetedPower(atom/target_atom)
. = ..()
-
var/mob/living/user = owner
to_chat(user, span_warning("You fire a blood bolt!"))
user.changeNext_move(CLICK_CD_RANGE)
@@ -276,11 +200,8 @@
Knocksback and immobilizes people adjacent to you.\n\
Has a low recharge time and may be helpful in meelee situations!\n\
Created from your Brawn ability."
- power_flags = BP_AM_TOGGLE|BP_AM_STATIC_COOLDOWN
check_flags = NONE
- purchase_flags = NONE
bloodcost = 0
- cooldown = 10 SECONDS
/datum/action/bloodsucker/gangrel/wingslam/ActivatePower()
var/mob/living/user = owner
@@ -307,4 +228,406 @@
user.do_attack_animation(M, ATTACK_EFFECT_SMASH)
var/send_dir = get_dir(user, M)
var/turf/turf_thrown_at = get_ranged_target_turf(M, send_dir, 5)
- M.throw_at(turf_thrown_at, 5, TRUE, user)
\ No newline at end of file
+ M.throw_at(turf_thrown_at, 5, TRUE, user)
+
+/* //\\ //\\
+////////////////||\\\\\\\\\\\\\\\\
+\\ Wolf Only //
+// Powers \\
+\\\\\\\\\\\\\\\\||////////////////
+*/
+
+/datum/action/bloodsucker/targeted/feast
+ name = "Feast"
+ desc = "DEVOUR THE WEAKLINGS, CAUSE THEM HARM. FEED. ME."
+ button_icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ icon_icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ button_icon_state = "power_feast"
+ background_icon_state_on = "wolf_power_on"
+ background_icon_state_off = "wolf_power_off"
+ power_explanation = "Feast:\n\
+ Feasting on a dead person will give you a satiation point and gib them.\n\
+ Satiation points are essential for overcoming frenzy, after gathering 3 you'll turn back to normal.\n\
+ Feasting on someone while they are alive will bite them and make them bleed.\n\
+ Has a medium recharge time to be helpful in combat.\n\
+ There might be some consequences after coming back from frenzy though.."
+ power_flags = BP_AM_TOGGLE
+ check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_AM_COSTLESS_UNCONSCIOUS
+ purchase_flags = GANGREL_CAN_BUY
+ bloodcost = 0
+ cooldown = 10 SECONDS
+ target_range = 1
+ power_activates_immediately = TRUE
+ prefire_message = "WHOM SHALL BE DEVOURED."
+
+/datum/action/bloodsucker/targeted/feast/FireTargetedPower(atom/target_atom)
+ if(isturf(target_atom))
+ return
+ owner.face_atom(target_atom)
+ var/mob/living/simple_animal/hostile/bloodsucker/werewolf/user = owner
+ var/mob/living/carbon/human/target = target_atom
+ if(target.stat == DEAD)
+ user.devour(target)
+ PowerActivatedSuccessfully()
+ return
+ user.do_attack_animation(target, ATTACK_EFFECT_BITE)
+ var/affecting = pick(BODY_ZONE_CHEST, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+ playsound(get_turf(target), 'sound/weapons/bite.ogg', 60, 1, -1)
+ target.apply_damage(35, BRUTE, affecting, target.run_armor_check(affecting, "melee", armour_penetration = 10), sharpness = SHARP_EDGED)
+ target.visible_message(span_danger("[user] takes a large bite out of [target]!"), \
+ span_userdanger("[user] takes a large bite out of you!"))
+ PowerActivatedSuccessfully()
+
+/datum/action/bloodsucker/gangrel/wolfortitude
+ name = "Wolftitude"
+ desc = "Withstand egregious physical wounds and walk away from attacks that would stun, pierce, and dismember lesser beings."
+ button_icon_state = "power_wort"
+ background_icon_state_on = "wolf_power_on"
+ background_icon_state_off = "wolf_power_off"
+ power_explanation = "Fortitude:\n\
+ Activating Wolftitude will provide more attack damage, and more overall health.\n\
+ It will give you a minor health buff while it stands, but slow you down severely.\n\
+ It has a decent cooldown time to allow yourself to turn it off and run away for a while.\n\
+ Created from your Fortitude ability."
+ power_flags = BP_AM_TOGGLE
+ check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_AM_COSTLESS_UNCONSCIOUS
+ purchase_flags = GANGREL_CAN_BUY
+ bloodcost = 0
+ cooldown = 8 SECONDS
+
+/datum/action/bloodsucker/gangrel/wolfortitude/ActivatePower()
+ . = ..()
+ to_chat(owner, span_notice("Your fur and claws harden, becoming as hard as steel."))
+ var/mob/living/simple_animal/hostile/A = owner
+ A.maxHealth *= 1.2
+ A.health *= 1.2
+ A.set_varspeed(initial(A.speed) + 2) // slower
+ A.harm_intent_damage += 10
+ A.melee_damage_lower += 10
+ A.melee_damage_upper += 10
+
+/datum/action/bloodsucker/gangrel/wolfortitude/DeactivatePower()
+ . = ..()
+ var/mob/living/simple_animal/hostile/A = owner
+ A.maxHealth /= 1.2
+ A.health /= 1.2
+ A.set_varspeed(initial(A.speed))
+ A.harm_intent_damage -= 10
+ A.melee_damage_lower -= 10
+ A.melee_damage_upper -= 10
+
+/datum/action/bloodsucker/targeted/pounce
+ name = "Pounce"
+ desc = "GRAPPLE THEM TO THE GROUND AND BITE THEIR ORGANS OUT."
+ button_icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ icon_icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ button_icon_state = "power_pounce"
+ background_icon_state_on = "wolf_power_on"
+ background_icon_state_off = "wolf_power_off"
+ power_explanation = "Pounce:\n\
+ Click any player to instantly dash at them, knocking them down and paralyzing them for a short while.\n\
+ Additionally if they are dead you'll consume their corpse to gain satiation and get closer to leaving frenzy.\n\
+ Created from your Predatory Lunge ability."
+ power_flags = BP_AM_TOGGLE
+ check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_CANT_USE_WHILE_INCAPACITATED|BP_CANT_USE_WHILE_UNCONSCIOUS
+ purchase_flags = GANGREL_CAN_BUY
+ bloodcost = 0
+ cooldown = 10 SECONDS
+ target_range = 6
+ power_activates_immediately = FALSE
+
+/datum/action/bloodsucker/targeted/pounce/ActivatePower()
+ . = ..()
+ var/mob/living/simple_animal/hostile/bloodsucker/werewolf/A = owner
+ A.icon_state = initial(A.icon_state) + "_pounce"
+ A.icon_living = initial(A.icon_state) + "_pounce"
+ A.update_body()
+
+/datum/action/bloodsucker/targeted/pounce/DeactivatePower()
+ . = ..()
+ var/mob/living/simple_animal/hostile/bloodsucker/werewolf/A = owner
+ A.icon_state = initial(A.icon_state)
+ A.icon_living = initial(A.icon_state)
+ A.update_body()
+
+/datum/action/bloodsucker/targeted/pounce/FireTargetedPower(atom/target_atom)
+ . = ..()
+ var/mob/living/simple_animal/hostile/bloodsucker/werewolf/user = owner
+ owner.face_atom(target_atom)
+ if(iscarbon(target_atom))
+ var/mob/living/carbon/target = target_atom
+ var/turf/targeted_turf = get_turf(target)
+ var/safety = get_dist(user, targeted_turf) * 3 + 1
+ var/consequetive_failures = 0
+ while(--safety && !target.Adjacent(user))
+ if(!step_to(user, targeted_turf))
+ consequetive_failures++
+ if(consequetive_failures >= 3) // If 3 steps don't work, just stop.
+ break
+ if(target.stat == DEAD)
+ if(!user.Adjacent(target))
+ return
+ user.devour(target)
+ PowerActivatedSuccessfully()
+ return
+ target.Knockdown(6 SECONDS)
+ target.Paralyze(1 SECONDS)
+ PowerActivatedSuccessfully()
+
+/datum/action/bloodsucker/targeted/pounce/CheckValidTarget(atom/target_atom)
+ . = ..()
+ if(!.)
+ return FALSE
+ return isliving(target_atom)
+
+/datum/action/bloodsucker/targeted/pounce/CheckCanTarget(atom/target_atom)
+ // DEFAULT CHECKS (Distance)
+ . = ..()
+ // Target Type: Living
+ if(isliving(target_atom))
+ return TRUE
+ return FALSE
+
+/datum/action/bloodsucker/gangrel/howl
+ name = "Howl"
+ desc = "BREATHE IN AND BREATH OUT AS MUCH AS POSSIBLE. KNOCKDOWNS AND CONFUSES NEARBY WEAKLINGS."
+ button_icon_state = "power_howl"
+ background_icon_state_on = "wolf_power_on"
+ background_icon_state_off = "wolf_power_off"
+ power_explanation = "Howl:\n\
+ Activating Howl will start up a 2 and a half second charge up.\n\
+ After the charge up you'll knockdown anyone adjacent to you.\n\
+ Additionally, you'll confuse and deafen anyone in a 3 tile range.\n\
+ Created from your Cloak of Darkness ability."
+ power_flags = BP_AM_TOGGLE
+ check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_AM_COSTLESS_UNCONSCIOUS
+ purchase_flags = GANGREL_CAN_BUY
+ bloodcost = 0
+ cooldown = 15 SECONDS
+
+/datum/action/bloodsucker/gangrel/howl/ActivatePower()
+ . = ..()
+ var/mob/living/simple_animal/hostile/bloodsucker/werewolf/A = owner
+ A.visible_message(span_danger("[A] inhales a ton of air!"), span_warning("You prepare to howl!"))
+ if(!do_mob(A, A, 2.5 SECONDS, TRUE))
+ return
+ playsound(A.loc, 'yogstation/sound/creatures/darkspawn_howl.ogg', 50, 1)
+ A.visible_message(span_userdanger("[A] let's out a chilling howl!"), span_boldwarning("You howl, confusing and deafening nearby mortals."))
+ for(var/mob/target in range(3, A))
+ if(target == A && target == A.bloodsucker)
+ continue
+ if(IS_BLOODSUCKER(target) || IS_VASSAL(target))
+ continue
+ if(iscarbon(target))
+ var/mob/living/carbon/M = target
+ M.confused += 15
+ M.adjustEarDamage(0, 50)
+ if(target.Adjacent(A))
+ M.Knockdown(4 SECONDS)
+ M.Paralyze(0.1)
+ DeactivatePower()
+
+/datum/action/bloodsucker/gangrel/rabidism
+ name = "Rabidism"
+ desc = "UNLEASHES YOUR POTENTIAL OF AREA DAMAGE, BUT HURTS YOURSELF IN THE PROCESS, DEALS MORE DAMAGE TO STRUCTURES."
+ button_icon_state = "power_rabid"
+ background_icon_state_on = "wolf_power_on"
+ background_icon_state_off = "wolf_power_off"
+ power_explanation = "Rabidism:\n\
+ Rabidism will deal reduced damage to everyone in range including you.\n\
+ During Rabidism's ten second rage you'll deal alot more damage to structures.\n\
+ Be aware of it's long cooldown time.\n\
+ Created from your Tresspass ability"
+ power_flags = BP_AM_TOGGLE
+ check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_AM_COSTLESS_UNCONSCIOUS
+ purchase_flags = GANGREL_CAN_BUY
+ bloodcost = 0
+ cooldown = 20 SECONDS
+
+/datum/action/bloodsucker/gangrel/rabidism/ActivatePower()
+ . = ..()
+ var/mob/living/simple_animal/hostile/bloodsucker/werewolf/A = owner
+ A.environment_smash = ENVIRONMENT_SMASH_RWALLS
+ A.harm_intent_damage -= 10
+ A.melee_damage_lower -= 10
+ A.melee_damage_upper -= 10
+ A.obj_damage *= 3
+ START_PROCESSING(SSprocessing, src)
+ addtimer(CALLBACK(src, .proc/DeactivatePower), 10 SECONDS)
+
+/datum/action/bloodsucker/gangrel/rabidism/process()
+ var/mob/living/simple_animal/hostile/bloodsucker/werewolf/A = owner
+ for(var/mob/living/all_targets in dview(1, get_turf(A)))
+ if(all_targets == A && all_targets == A.bloodsucker)
+ continue
+ A.UnarmedAttack(all_targets) //byongcontrol
+
+/datum/action/bloodsucker/gangrel/rabidism/DeactivatePower()
+ . = ..()
+ var/mob/living/simple_animal/hostile/bloodsucker/werewolf/A = owner
+ A.environment_smash = initial(A.environment_smash)
+ A.harm_intent_damage = initial(A.harm_intent_damage)
+ A.melee_damage_lower = initial(A.melee_damage_lower)
+ A.melee_damage_upper = initial(A.melee_damage_upper)
+ A.obj_damage = initial(A.obj_damage)
+ STOP_PROCESSING(SSprocessing, src)
+
+/datum/action/bloodsucker/targeted/tear
+ name = "Tear"
+ desc = "Tear in specific areas of a mortal's body and inflict great pain on them."
+ button_icon_state = "power_tear"
+ button_icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ icon_icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ background_icon_state_on = "gangrel_power_on"
+ background_icon_state_off = "gangrel_power_off"
+ power_explanation = "Tear:\n\
+ Tear will make your first attack start up a bleeding process.\n\
+ Bleeding process will only work if the target stands still.\n\
+ When it's done it will damage the target severely."
+ power_flags = BP_AM_TOGGLE
+ check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_AM_COSTLESS_UNCONSCIOUS
+ purchase_flags = GANGREL_CAN_BUY
+ bloodcost = 10
+ cooldown = 20 SECONDS
+ var/mob/living/mauled
+
+/datum/action/bloodsucker/targeted/tear/FireTargetedPower(atom/target_atom)
+ . = ..()
+ var/mob/living/carbon/human/user = owner
+ mauled = target_atom
+ user.do_attack_animation(mauled, ATTACK_EFFECT_CLAW)
+ var/obj/item/bodypart/affecting = mauled.get_bodypart(ran_zone(user.zone_selected))
+ playsound(get_turf(mauled), 'sound/weapons/slash.ogg', 60, 1, -1)
+ mauled.apply_damage(15, BRUTE, affecting, mauled.run_armor_check(affecting, "melee", armour_penetration = 10), sharpness = SHARP_EDGED)
+ START_PROCESSING(SSprocessing, src)
+
+/datum/action/bloodsucker/targeted/tear/process()
+ var/mob/living/carbon/human/user = owner
+ for(var/mob/living/victims in dview(1, get_turf(user)))
+ spawn(10)
+ if(!(victims == mauled))
+ continue
+ if(IS_BLOODSUCKER(mauled))
+ continue
+ if(!do_mob(user, victims, 1 SECONDS))
+ STOP_PROCESSING(SSprocessing, src)
+ continue
+ var/datum/status_effect/saw_bleed/B = victims.has_status_effect(STATUS_EFFECT_SAWBLEED)
+ user.do_attack_animation(mauled, ATTACK_EFFECT_CLAW)
+ playsound(get_turf(mauled), 'sound/weapons/slash.ogg', 60, 1, -1)
+ if(!B)
+ victims.apply_status_effect(STATUS_EFFECT_SAWBLEED)
+ else
+ B.add_bleed(B.bleed_buildup)
+
+/datum/action/bloodsucker/targeted/tear/CheckValidTarget(atom/target_atom)
+ . = ..()
+ if(!.)
+ return FALSE
+ return isliving(target_atom)
+
+/datum/action/bloodsucker/targeted/tear/CheckCanTarget(atom/target_atom)
+ // DEFAULT CHECKS (Distance)
+ . = ..()
+ // Target Type: Living
+ if(isliving(target_atom))
+ return TRUE
+ return FALSE
+
+/obj/item/clothing/neck/wolfcollar
+ name = "Wolf Collar"
+ desc = "Hopefully no more neck snaps!"
+ icon_state = "collar"
+ item_state = "collar"
+ icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ alternate_worn_icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 10, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 10, "acid" = 100)
+ body_parts_covered = NECK
+
+/obj/item/radio/headset/wolfears
+ name = "Wolf Ears"
+ desc = "If only you had a encoder to speak through the channels."
+ icon_state = "ears"
+ item_state = "ears"
+ icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ alternate_worn_icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 10, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 10, "acid" = 100)
+ flags_inv = HIDEHAIR|HIDEFACE
+ alternate_worn_layer = ABOVE_BODY_FRONT_LAYER
+
+/obj/item/clothing/gloves/wolfclaws
+ name = "Wolf Claws"
+ desc = "Tear them to shreds!"
+ icon_state = "claws"
+ item_state = "claws"
+ icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ alternate_worn_icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ body_parts_covered = ARMS|HANDS
+ flags_inv = HIDEJUMPSUIT
+ var/datum/action/bloodsucker/targeted/tear/tearaction = new
+
+/obj/item/clothing/shoes/wolflegs
+ name = "Wolf Legs"
+ desc = "Atleast they make you go faster."
+ icon_state = "legs"
+ item_state = "legs"
+ icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ alternate_worn_icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ slowdown = SHOES_SLOWDOWN - 0.5
+ body_parts_covered = GROIN|LEGS|FEET
+
+/obj/item/clothing/shoes/xeno_wraps/wolfdigilegs
+ name = "Wolf Legs"
+ desc = "Atleast they make you go faster. Oh wait you probably didn't mind anyways..."
+ icon_state = "digilegs"
+ item_state = "digilegs"
+ icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ alternate_worn_icon = 'icons/mob/actions/actions_gangrel_bloodsucker.dmi'
+ slowdown = SHOES_SLOWDOWN - 0.5
+ xenoshoe = YES_DIGIT
+ body_parts_covered = GROIN|LEGS|FEET
+
+/obj/item/clothing/neck/wolfcollar/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, BLOODSUCKER_TRAIT)
+
+/obj/item/radio/headset/wolfears/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, BLOODSUCKER_TRAIT)
+ make_syndie()
+
+/obj/item/radio/headset/wolfears/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/wearertargeting/earprotection, list(SLOT_EARS))
+
+/obj/item/clothing/gloves/wolfclaws/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, BLOODSUCKER_TRAIT)
+
+/obj/item/clothing/shoes/wolflegs/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, BLOODSUCKER_TRAIT)
+
+/obj/item/clothing/shoes/xeno_wraps/wolfdigilegs/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, BLOODSUCKER_TRAIT)
+
+/obj/item/clothing/gloves/wolfclaws/equipped(mob/user, slot)
+ . = ..()
+ if(!ishuman(user))
+ return
+ if(!IS_BLOODSUCKER(user))
+ return
+ if(slot == SLOT_GLOVES)
+ var/mob/living/carbon/human/H = user
+ tearaction.Grant(H)
+
+/obj/item/clothing/gloves/wolfclaws/dropped(mob/user)
+ . = ..()
+ if(!ishuman(user))
+ return
+ if(!IS_BLOODSUCKER(user))
+ return
+ var/mob/living/carbon/human/H = user
+ if(H.get_item_by_slot(SLOT_GLOVES) == src)
+ tearaction.Remove(H)
diff --git a/code/modules/antagonists/bloodsuckers/powers/gohome.dm b/code/modules/antagonists/bloodsuckers/powers/gohome.dm
index da45d8e9cdd3..e82d4475b61b 100644
--- a/code/modules/antagonists/bloodsuckers/powers/gohome.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/gohome.dm
@@ -1,3 +1,8 @@
+#define GOHOME_START 0
+#define GOHOME_FLICKER_ONE 2
+#define GOHOME_FLICKER_TWO 4
+#define GOHOME_TELEPORT 6
+
/datum/action/bloodsucker/gohome
name = "Vanishing Act"
desc = "As dawn aproaches, disperse into mist and return directly to your Lair.
WARNING: You will drop ALL of your possessions if observed by mortals."
@@ -9,12 +14,19 @@
The power will cancel out if the Claimed Coffin is somehow destroyed. \n\
Immediately after activating, lights around the user will begin to flicker. \n\
Once the user teleports to their coffin, in their place will be a Rat or Bat."
- power_flags = BP_AM_SINGLEUSE|BP_AM_STATIC_COOLDOWN
+ power_flags = BP_AM_TOGGLE|BP_AM_SINGLEUSE|BP_AM_STATIC_COOLDOWN
check_flags = BP_CANT_USE_IN_FRENZY|BP_CANT_USE_WHILE_STAKED|BP_CANT_USE_WHILE_INCAPACITATED
// You only get this once you've claimed a lair and Sol is near.
purchase_flags = NONE
+ constant_bloodcost = 2
bloodcost = 100
cooldown = 100 SECONDS
+ ///What stage of the teleportation are we in
+ var/teleporting_stage = GOHOME_START
+ var/list/spawning_mobs = list(
+ /mob/living/simple_animal/mouse = 3,
+ /mob/living/simple_animal/hostile/retaliate/bat = 1,
+ )
/datum/action/bloodsucker/gohome/CheckCanUse(mob/living/carbon/user)
. = ..()
@@ -26,92 +38,94 @@
return FALSE
return TRUE
-/datum/action/bloodsucker/gohome/proc/flicker_lights(flicker_range, beat_volume)
- for(var/obj/machinery/light/nearby_lights in view(flicker_range, get_turf(owner)))
- nearby_lights.flicker(5)
- playsound(get_turf(owner), 'sound/effects/singlebeat.ogg', beat_volume, 1)
-
-/// IMPORTANT: Check for lair at every step! It might get destroyed.
/datum/action/bloodsucker/gohome/ActivatePower()
. = ..()
to_chat(owner, span_notice("You focus on separating your consciousness from your physical form..."))
- /// STEP ONE: Flicker Lights
- flicker_lights(3, 20)
- sleep(50)
- flicker_lights(4, 40)
- sleep(50)
- flicker_lights(4, 60)
- for(var/obj/machinery/light/nearby_lights in view(6, get_turf(owner)))
- nearby_lights.flicker(5)
- playsound(get_turf(owner), 'sound/effects/singlebeat.ogg', 60, 1)
- /// STEP TWO: Lights OFF?
- /// CHECK: Still have Coffin?
+
+/datum/action/bloodsucker/gohome/UsePower(mob/living/user)
+ . = ..()
+ if(!.)
+ return FALSE
if(!bloodsuckerdatum_power.coffin)
to_chat(owner, span_warning("Your coffin has been destroyed! You no longer have a destination."))
return FALSE
- if(!owner)
- return
- /// SEEN?: (effects ONLY if there are witnesses! Otherwise you just POOF)
+ switch(teleporting_stage)
+ if(GOHOME_START)
+ INVOKE_ASYNC(src, .proc/flicker_lights, 3, 20)
+ if(GOHOME_FLICKER_ONE)
+ INVOKE_ASYNC(src, .proc/flicker_lights, 4, 40)
+ if(GOHOME_FLICKER_TWO)
+ INVOKE_ASYNC(src, .proc/flicker_lights, 4, 60)
+ if(GOHOME_TELEPORT)
+ INVOKE_ASYNC(src, .proc/teleport_to_coffin, user)
+ teleporting_stage++
- /// Do Effects (seen by anyone)
- var/am_seen = FALSE
- /// Drop Stuff (seen by non-vamp)
- var/drop_item = FALSE
- // Only check if I'm not in a Locker or something.
+/datum/action/bloodsucker/gohome/ContinueActive(mob/living/user, mob/living/target)
+ . = ..()
+ if(!.)
+ return FALSE
if(!isturf(owner.loc))
- return
- // A) Check for Darkness (we can just leave)
+ return FALSE
+ if(!bloodsuckerdatum_power.coffin)
+ to_chat(owner, span_warning("Your coffin has been destroyed! You no longer have a destination."))
+ return FALSE
+ return TRUE
+
+/datum/action/bloodsucker/gohome/proc/flicker_lights(flicker_range, beat_volume)
+ for(var/obj/machinery/light/nearby_lights in view(flicker_range, get_turf(owner)))
+ nearby_lights.flicker(5)
+ playsound(get_turf(owner), 'sound/effects/singlebeat.ogg', beat_volume, 1)
+
+/datum/action/bloodsucker/gohome/proc/teleport_to_coffin(mob/living/carbon/user)
+ var/drop_item = FALSE
var/turf/current_turf = get_turf(owner)
- if(current_turf && current_turf.lighting_object && current_turf.get_lumcount()>= 0.1)
- // B) Check for Viewers
+ // If we aren't in the dark, anyone watching us will cause us to drop out stuff
+ if(current_turf && current_turf.lighting_object && current_turf.get_lumcount() >= 0.2)
for(var/mob/living/watchers in viewers(world.view, get_turf(owner)) - owner)
- if(watchers.client && !watchers.has_unlimited_silicon_privilege && !watchers.eye_blind)
- am_seen = TRUE
- if(!IS_BLOODSUCKER(watchers) && !IS_VASSAL(watchers))
- drop_item = TRUE
- break
- /// LOSE CUFFS
- var/mob/living/carbon/user = owner
+ if(!watchers.client)
+ continue
+ if(watchers.has_unlimited_silicon_privilege)
+ continue
+ if(watchers.eye_blind)
+ continue
+ if(!IS_BLOODSUCKER(watchers) && !IS_VASSAL(watchers))
+ drop_item = TRUE
+ break
+ // Drop all necessary items (handcuffs, legcuffs, items if seen)
if(user.handcuffed)
- var/obj/handcuffs = user.handcuffed
+ var/obj/item/handcuffs = user.handcuffed
user.dropItemToGround(handcuffs)
if(user.legcuffed)
- var/obj/legcuffs = user.legcuffed
+ var/obj/item/legcuffs = user.legcuffed
user.dropItemToGround(legcuffs)
- /// SEEN!
if(drop_item)
- // DROP: Clothes, held items, and cuffs etc
- // NOTE: Taken from unequip_everything() in inventory.dm. We need to
- // *force* all items to drop, so we had to just gut the code out of it.
- var/list/items = list()
- items |= user.get_equipped_items()
- for(var/belongings in items)
- user.dropItemToGround(belongings, TRUE)
- for(var/obj/item/held_posessions in owner.held_items) //drop_all_held_items()
- user.dropItemToGround(held_posessions, TRUE)
- /// POOF EFFECTS
- if(am_seen)
- playsound(get_turf(owner), 'sound/magic/summon_karp.ogg', 60, 1)
- var/datum/effect_system/steam_spread/puff = new /datum/effect_system/steam_spread()
- puff.effect_type = /obj/effect/particle_effect/smoke/vampsmoke
- puff.set_up(3, 0, get_turf(owner))
- puff.start()
+ for(var/obj/item/literally_everything in owner)
+ owner.dropItemToGround(literally_everything, TRUE)
+
+ playsound(current_turf, 'sound/magic/summon_karp.ogg', 60, 1)
+ var/datum/effect_system/steam_spread/bloodsucker/puff = new /datum/effect_system/steam_spread/bloodsucker()
+ puff.set_up(3, 0, current_turf)
+ puff.start()
/// STEP FIVE: Create animal at prev location
- var/mob/living/simple_animal/SA = pick(/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse, /mob/living/simple_animal/hostile/retaliate/bat) //prob(300) /mob/living/simple_animal/mouse,
- new SA (owner.loc)
+ var/mob/living/simple_animal/new_mob = pick(spawning_mobs)
+ new new_mob(current_turf)
/// TELEPORT: Move to Coffin & Close it!
user.set_resting(TRUE, TRUE, FALSE)
do_teleport(owner, bloodsuckerdatum_power.coffin, no_effects = TRUE, forced = TRUE, channel = TELEPORT_CHANNEL_QUANTUM)
user.Stun(3 SECONDS, TRUE)
- /// CLOSE LID: If fail, force me in.
- if(!bloodsuckerdatum_power.coffin.close(owner))
- /// Puts me inside.
- bloodsuckerdatum_power.coffin.insert(owner)
+ // Puts me inside.
+ if(!bloodsuckerdatum_power.coffin.insert(owner))
+ // CLOSE LID: If fail, force me in.
+ bloodsuckerdatum_power.coffin.close(owner)
playsound(bloodsuckerdatum_power.coffin.loc, bloodsuckerdatum_power.coffin.close_sound, 15, 1, -3)
- bloodsuckerdatum_power.coffin.opened = FALSE
- bloodsuckerdatum_power.coffin.density = TRUE
- bloodsuckerdatum_power.coffin.update_icon()
- // Lock Coffin
- bloodsuckerdatum_power.coffin.LockMe(owner)
- bloodsuckerdatum_power.Check_Begin_Torpor(FALSE) // Are we meant to enter Torpor here?
+
+ DeactivatePower()
+
+/datum/effect_system/steam_spread/bloodsucker
+ effect_type = /obj/effect/particle_effect/smoke/vampsmoke
+
+#undef GOHOME_START
+#undef GOHOME_FLICKER_ONE
+#undef GOHOME_FLICKER_TWO
+#undef GOHOME_TELEPORT
diff --git a/code/modules/antagonists/bloodsuckers/powers/masquerade.dm b/code/modules/antagonists/bloodsuckers/powers/masquerade.dm
index 207d05cad116..b162b239932f 100644
--- a/code/modules/antagonists/bloodsuckers/powers/masquerade.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/masquerade.dm
@@ -27,13 +27,36 @@
bloodcost = 10
cooldown = 5 SECONDS
constant_bloodcost = 0.1
+ var/list/theqdeld = list()
/datum/action/bloodsucker/masquerade/ActivatePower()
. = ..()
var/mob/living/carbon/user = owner
to_chat(user, span_notice("Your heart beats falsely within your lifeless chest. You may yet pass for a mortal."))
to_chat(user, span_warning("Your vampiric healing is halted while imitating life."))
-
+ // Remove Clan-specific stuff
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ switch(bloodsuckerdatum.my_clan)
+ if(CLAN_TZIMISCE)
+ set_antag_hud(user, "bloodsucker")
+ if(CLAN_GANGREL)
+ if(bloodsuckerdatum.clanprogress >= 1) // change this if we get more stuff to include other clans
+ var/obj/item/clothing/neck/neckdrip = user.get_item_by_slot(SLOT_NECK)
+ if(istype(neckdrip, /obj/item/clothing/neck/wolfcollar))
+ theqdeld += neckdrip
+ if(bloodsuckerdatum.clanprogress >= 2)
+ var/obj/item/earsdrip = user.get_item_by_slot(SLOT_EARS)
+ if(istype(earsdrip, /obj/item/radio/headset/wolfears))
+ theqdeld += earsdrip
+ if(bloodsuckerdatum.clanprogress >= 3)
+ var/obj/item/clothing/gloves/glovesdrip = user.get_item_by_slot(SLOT_GLOVES)
+ if(istype(glovesdrip, /obj/item/clothing/gloves/wolfclaws))
+ theqdeld += glovesdrip
+ if(bloodsuckerdatum.clanprogress >= 4)
+ var/obj/item/clothing/shoes/shoesdrip = user.get_item_by_slot(SLOT_SHOES)
+ if(istype(shoesdrip , /obj/item/clothing/shoes/wolflegs))
+ theqdeld += shoesdrip
+ QDEL_LIST(theqdeld)
// Remove Bloodsucker traits
REMOVE_TRAIT(user, TRAIT_NOHARDCRIT, BLOODSUCKER_TRAIT)
REMOVE_TRAIT(user, TRAIT_NOSOFTCRIT, BLOODSUCKER_TRAIT)
@@ -85,6 +108,28 @@
for(var/thing in user.diseases)
var/datum/disease/disease = thing
disease.cure()
+ // Adds Clan-specific stuff
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ switch(bloodsuckerdatum.my_clan)
+ if(CLAN_TZIMISCE)
+ set_antag_hud(user, "tzimisce")
+ if(CLAN_GANGREL)
+ if(bloodsuckerdatum.clanprogress >= 1) // change this if we get more stuff to include other clans
+ var/obj/item/clothing/neck/previousdrip = user.get_item_by_slot(SLOT_NECK)
+ user.dropItemToGround(previousdrip)
+ user.equip_to_slot_or_del(new /obj/item/clothing/neck/wolfcollar(user), SLOT_NECK)
+ if(bloodsuckerdatum.clanprogress >= 2)
+ var/obj/item/clothing/ears/previousdrip = user.get_item_by_slot(SLOT_EARS)
+ user.dropItemToGround(previousdrip)
+ user.equip_to_slot_or_del(new /obj/item/radio/headset/wolfears(user), SLOT_EARS)
+ if(bloodsuckerdatum.clanprogress >= 3)
+ var/obj/item/clothing/gloves/previousdrip = user.get_item_by_slot(SLOT_GLOVES)
+ user.dropItemToGround(previousdrip)
+ user.equip_to_slot_or_del(new /obj/item/clothing/gloves/wolfclaws(user), SLOT_GLOVES)
+ if(bloodsuckerdatum.clanprogress >= 4)
+ var/obj/item/clothing/shoes/previousdrip = user.get_item_by_slot(SLOT_SHOES)
+ user.dropItemToGround(previousdrip)
+ user.equip_to_slot_or_del(new /obj/item/clothing/shoes/wolflegs(user), SLOT_SHOES)
to_chat(user, span_notice("Your heart beats one final time, while your skin dries out and your icy pallor returns."))
/**
@@ -97,14 +142,14 @@
id = "masquerade"
duration = -1
tick_interval = -1
- alert_type = /atom/movable/screen/alert/status_effect/masquerade
+ alert_type = /obj/screen/alert/status_effect/masquerade
-/atom/movable/screen/alert/status_effect/masquerade
+/obj/screen/alert/status_effect/masquerade
name = "Masquerade"
desc = "You are currently hiding your identity using the Masquerade power. This halts Vampiric healing."
icon = 'icons/mob/actions/actions_bloodsucker.dmi'
icon_state = "power_human"
-/atom/movable/screen/alert/status_effect/masquerade/MouseEntered(location,control,params)
+/obj/screen/alert/status_effect/masquerade/MouseEntered(location,control,params)
desc = initial(desc)
return ..()
diff --git a/code/modules/antagonists/bloodsuckers/powers/recuperate.dm b/code/modules/antagonists/bloodsuckers/powers/recuperate.dm
index 875c149eab4c..51a7a0bc0d4b 100644
--- a/code/modules/antagonists/bloodsuckers/powers/recuperate.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/recuperate.dm
@@ -27,7 +27,7 @@
. = ..()
to_chat(owner, span_notice("Your muscles clench as your master's immortal blood mixes with your own, knitting your wounds."))
-/datum/action/bloodsucker/recuperate/UsePower(mob/living/carbon/human/user)
+/datum/action/bloodsucker/recuperate/UsePower(mob/living/carbon/user)
. = ..()
if(!.)
return
diff --git a/code/modules/antagonists/bloodsuckers/powers/targeted/brawn.dm b/code/modules/antagonists/bloodsuckers/powers/targeted/brawn.dm
index c6a2b6dfeee1..184677fb6b00 100644
--- a/code/modules/antagonists/bloodsuckers/powers/targeted/brawn.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/targeted/brawn.dm
@@ -184,8 +184,51 @@
return TRUE
// Target Type: Door
else if(istype(target_atom, /obj/machinery/door))
+ if(level_current < 4)
+ to_chat(owner, span_warning("You need [4 - level_current] more levels to be able to break open the [target_atom]!"))
+ return FALSE
return TRUE
// Target Type: Locker
else if(istype(target_atom, /obj/structure/closet))
+ if(level_current < 3)
+ to_chat(owner, span_warning("You need [3 - level_current] more levels to be able to break open the [target_atom]!"))
+ return FALSE
return TRUE
return FALSE
+
+/datum/action/bloodsucker/targeted/brawn/shadow
+ name = "Obliterate"
+ button_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ background_icon_state_on = "lasombra_power_on"
+ background_icon_state_off = "lasombra_power_off"
+ icon_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ button_icon_state = "power_obliterate"
+ additional_text = "Additionally afflicts the target with a shadow curse while in darkness and disables any lights they may possess."
+ purchase_flags = LASOMBRA_CAN_BUY
+
+/datum/action/bloodsucker/targeted/brawn/shadow/FireTargetedPower(atom/target_atom)
+ var/mob/living/carbon/human/H = target_atom
+ H.apply_status_effect(STATUS_EFFECT_SHADOWAFFLICTED)
+ var/turf/T = get_turf(H)
+ for(var/datum/light_source/LS in T.affecting_lights)
+ var/atom/LO = LS.source_atom
+ if(isitem(LO))
+ var/obj/item/I = LO
+ if(istype(I, /obj/item/clothing/head/helmet/space/hardsuit))
+ var/obj/item/clothing/head/helmet/space/hardsuit/HA = I
+ if(HA.on)
+ HA.on = FALSE
+ if(istype(I, /obj/item/clothing/head/helmet/space/plasmaman))
+ var/obj/item/clothing/head/helmet/space/plasmaman/PA = I
+ if(PA.on)
+ PA.on = FALSE
+ if(istype(I, /obj/item/flashlight))
+ var/obj/item/flashlight/F = I
+ if(F.on)
+ F.on = FALSE
+ F.update_brightness()
+ if(istype(LO, /mob/living/silicon/robot))
+ var/mob/living/silicon/robot/borg = LO
+ if(!borg.lamp_cooldown)
+ borg.smash_headlamp()
+ . = ..()
\ No newline at end of file
diff --git a/code/modules/antagonists/bloodsuckers/powers/targeted/haste.dm b/code/modules/antagonists/bloodsuckers/powers/targeted/haste.dm
index 795e92399276..d17c4f75f2b1 100644
--- a/code/modules/antagonists/bloodsuckers/powers/targeted/haste.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/targeted/haste.dm
@@ -97,3 +97,31 @@
all_targets.confused = max(8, all_targets.confused)
all_targets.stuttering = max(8, all_targets.stuttering)
all_targets.Knockdown(10 + level_current * 5) // Re-knock them down, the first one didn't work due to stunimmunity
+
+/datum/action/bloodsucker/targeted/haste/shadow
+ name = "Blow"
+ button_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ background_icon_state_on = "lasombra_power_on"
+ background_icon_state_off = "lasombra_power_off"
+ icon_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ button_icon_state = "power_bomb"
+ additional_text = "Additionally disables lightframes in range and confuses nearby mortals."
+ purchase_flags = LASOMBRA_CAN_BUY
+
+/datum/action/bloodsucker/targeted/haste/shadow/on_move()
+ . = ..()
+ var/mob/living/carbon/human/user = owner
+ for(var/obj/machinery/light/L in range(5, user))
+ L.on = FALSE
+ L.update(0)
+ L.set_light(0)
+ for(var/mob/target in range(5, user))
+ if(target == user)
+ continue
+ if(IS_BLOODSUCKER(target) || IS_VASSAL(target))
+ continue
+ if(iscarbon(target))
+ var/mob/living/carbon/M = target
+ to_chat(M, span_danger("As a figure passes by, you feel your head spike up!"))
+ M.confused += 4
+ M.adjustEarDamage(0, 15)
\ No newline at end of file
diff --git a/code/modules/antagonists/bloodsuckers/powers/targeted/lunge.dm b/code/modules/antagonists/bloodsuckers/powers/targeted/lunge.dm
index b4c29f467852..2ca8ec15649b 100644
--- a/code/modules/antagonists/bloodsuckers/powers/targeted/lunge.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/targeted/lunge.dm
@@ -3,7 +3,8 @@
desc = "Spring at a humanoid to grapple them without warning, or tear the dead's heart out. Attacks from concealment or the rear may even knock them down if strong enough."
button_icon_state = "power_lunge"
power_explanation = "Predatory Lunge:\n\
- Click any player to instantly dash at them, aggressively grabbing them.\n\
+ Click any player to instantly dash at them if above power level 3, aggressively grabbing them.\n\
+ If not on level 3, you will have to charge your lunge for a while. During this time you'll have to stand still for lunge to work\n\
You cannot use the Power if you are aggressively grabbed.\n\
If the target is wearing riot gear or is a Monster Hunter, you will merely passively grab them.\n\
If grabbed from behind or from the darkness (Cloak of Darkness counts) with a power level at or above 4, will additionally knock the target down.\n\
@@ -22,6 +23,12 @@
* Level 3: Grapple 3 from Shadows
*/
+/datum/action/bloodsucker/targeted/lunge/ActivatePower(process = FALSE)
+ . = ..()
+
+/datum/action/bloodsucker/targeted/lunge/DeactivatePower(process = FALSE)
+ . = ..()
+
/datum/action/bloodsucker/targeted/lunge/CheckCanUse(mob/living/carbon/user)
. = ..()
if(!.)
@@ -152,3 +159,19 @@
var/mob/living/O = owner
O.SetImmobilized(0)
return ..()
+
+/datum/action/bloodsucker/targeted/lunge/shadow
+ name = "Dark Embrace"
+ button_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ background_icon_state_on = "lasombra_power_on"
+ background_icon_state_off = "lasombra_power_off"
+ icon_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ button_icon_state = "power_embrace"
+ additional_text = "Additionally makes the target walk."
+ purchase_flags = LASOMBRA_CAN_BUY
+
+/datum/action/bloodsucker/targeted/lunge/shadow/lunge_end(atom/hit_atom)
+ . = ..()
+ var/mob/living/carbon/target = hit_atom
+ if(target.m_intent != MOVE_INTENT_WALK)
+ target.toggle_move_intent()
\ No newline at end of file
diff --git a/code/modules/antagonists/bloodsuckers/powers/targeted/mesmerize.dm b/code/modules/antagonists/bloodsuckers/powers/targeted/mesmerize.dm
index 23cd24603133..88a0bebd43e9 100644
--- a/code/modules/antagonists/bloodsuckers/powers/targeted/mesmerize.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/targeted/mesmerize.dm
@@ -30,6 +30,7 @@
target_range = 8
power_activates_immediately = FALSE
prefire_message = "Whom will you subvert to your will?"
+ var/mesmerizingtime = 5 SECONDS
/datum/action/bloodsucker/targeted/mesmerize/CheckCanUse(mob/living/carbon/user)
. = ..()
@@ -90,8 +91,9 @@
var/mob/living/target = target_atom
var/mob/living/user = owner
to_chat(owner, span_notice("Attempting to hypnotically gaze [target]..."))
- if(!do_mob(user, target, 5 SECONDS, NONE, TRUE))
- return
+ if(!power_activates_immediately)
+ if(!do_mob(user, target, mesmerizingtime, NONE, TRUE))
+ return
PowerActivatedSuccessfully() // PAY COST! BEGIN COOLDOWN!
var/power_time = 90 + level_current * 15
@@ -125,3 +127,22 @@
if(istype(user) && target.stat == CONSCIOUS && (target in view(6, get_turf(user))))
to_chat(owner, span_warning("[target] snapped out of their trance."))
+/datum/action/bloodsucker/targeted/mesmerize/shadow
+ name = "Glare"
+ button_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ background_icon_state_on = "lasombra_power_on"
+ background_icon_state_off = "lasombra_power_off"
+ icon_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ button_icon_state = "power_glare"
+ additional_text = "Additionally makes the stun downtime based on distance, being instant when adjacent."
+ purchase_flags = LASOMBRA_CAN_BUY
+
+/datum/action/bloodsucker/targeted/mesmerize/shadow/FireTargetedPower(atom/target_atom)
+ var/mob/living/target = target_atom
+ var/mob/living/user = owner
+ if(target.Adjacent(user))
+ power_activates_immediately = TRUE
+ else
+ mesmerizingtime = initial(mesmerizingtime) - ((-get_dist(target, user) + 8 )/2) SECONDS //won't screw you up that bad if you miss it barely
+ power_activates_immediately = FALSE
+ . = ..()
\ No newline at end of file
diff --git a/code/modules/antagonists/bloodsuckers/powers/targeted/trespass.dm b/code/modules/antagonists/bloodsuckers/powers/targeted/trespass.dm
index d673450ee8f2..a3dfba53991a 100644
--- a/code/modules/antagonists/bloodsuckers/powers/targeted/trespass.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/targeted/trespass.dm
@@ -10,10 +10,12 @@
check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_WHILE_INCAPACITATED|BP_CANT_USE_WHILE_UNCONSCIOUS
purchase_flags = BLOODSUCKER_CAN_BUY|VASSAL_CAN_BUY
bloodcost = 10
- cooldown = 8 SECONDS
+ cooldown = 7 SECONDS
prefire_message = "Select a destination."
//target_range = 2
var/turf/target_turf // We need to decide where we're going based on where we clicked. It's not actually the tile we clicked.
+ var/wallbound = TRUE
+ var/soliddelay = 1
/datum/action/bloodsucker/targeted/trespass/CheckCanUse(mob/living/carbon/user)
. = ..()
@@ -50,9 +52,13 @@
from_turf = get_step(from_turf, this_dir)
// ERROR! Wall!
if(iswallturf(from_turf))
- var/wallwarning = (i == 1) ? "in the way" : "at your destination"
- to_chat(owner, "There is a wall [wallwarning].")
- return FALSE
+ if(wallbound)
+ var/wallwarning = (i == 1) ? "in the way" : "at your destination"
+ to_chat(owner, span_warning("There is a wall [wallwarning]."))
+ return FALSE
+ if(!wallbound)
+ to_chat(owner, span_notice("You begin passing through the wall, this will take a while and take more energy."))
+ soliddelay = 2
// Done
target_turf = from_turf
@@ -67,7 +73,7 @@
user.visible_message(
span_warning("[user]'s form dissipates into a cloud of mist!"),
- span_notice("You disspiate into formless mist."),
+ span_notice("You dissipate into formless mist."),
)
// Effect Origin
var/sound_strength = max(60, 70 - level_current * 10)
@@ -77,7 +83,7 @@
puff.set_up(3, 0, my_turf)
puff.start()
- var/mist_delay = max(5, 20 - level_current * 2.5) // Level up and do this faster.
+ var/mist_delay = max(5, 20 * soliddelay - level_current * 2.5) // Level up and do this faster.
// Freeze Me
user.Stun(mist_delay, ignore_canstun = TRUE)
@@ -105,3 +111,14 @@
puff.effect_type = /obj/effect/particle_effect/smoke/vampsmoke
puff.set_up(3, 0, target_turf)
puff.start()
+
+/datum/action/bloodsucker/targeted/trespass/shadow
+ name = "Manifest"
+ button_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ background_icon_state_on = "lasombra_power_on"
+ background_icon_state_off = "lasombra_power_off"
+ icon_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
+ button_icon_state = "power_manifest"
+ additional_text = "Additionally allows you pass through walls, albeit at a slower rate."
+ purchase_flags = LASOMBRA_CAN_BUY
+ wallbound = FALSE
\ No newline at end of file
diff --git a/code/modules/antagonists/bloodsuckers/powers/targeted/tzimisce.dm b/code/modules/antagonists/bloodsuckers/powers/targeted/tzimisce.dm
new file mode 100644
index 000000000000..98f7bb400f1e
--- /dev/null
+++ b/code/modules/antagonists/bloodsuckers/powers/targeted/tzimisce.dm
@@ -0,0 +1,182 @@
+#define SIZE_SMALL 1
+#define SIZE_MEDIUM 2
+#define SIZE_BIG 4
+
+/datum/action/bloodsucker/targeted/dice
+ name = "Dice"
+ desc = "Slice, cut, sever. The Flesh obeys as my fingers lay touch on it."
+ button_icon_state = "power_dice"
+ power_explanation = "Dice:\n\
+ Use on a dead corpse to extract muscle from it to be able to feed it to a vassalrack.\n\
+ This won't take long and is your primary source of muscle acquiring, necessary for future endeavours.\n\
+ This ability takes well to leveling up, higher levels will increase your mastery over a person's flesh while using the ability for it's combat purpose.\n\
+ You shouldn't use this on your allies.."
+ power_flags = BP_AM_TOGGLE|BP_AM_STATIC_COOLDOWN
+ bloodcost = 10
+ button_icon = 'icons/mob/actions/actions_tzimisce_bloodsucker.dmi'
+ icon_icon = 'icons/mob/actions/actions_tzimisce_bloodsucker.dmi'
+ background_icon_state = "tzimisce_power_off"
+ background_icon_state_on = "tzimisce_power_on"
+ background_icon_state_off = "tzimisce_power_off"
+ purchase_flags = TZIMISCE_CAN_BUY
+ power_flags = BP_AM_TOGGLE|BP_AM_STATIC_COOLDOWN
+ check_flags = BP_AM_COSTLESS_UNCONSCIOUS
+ target_range = 1
+ cooldown = 10 SECONDS
+
+/obj/item/muscle
+ name = "muscle"
+ desc = "Weird flex but ok"
+ icon = 'icons/mob/actions/actions_tzimisce_bloodsucker.dmi'
+ icon_state = "muscle_all"
+ var/size
+
+/obj/item/muscle/small
+ name = "small muscle piece"
+ desc = "This one sure wasn't important to it's owner."
+ icon_state = "muscle_small"
+ size = SIZE_SMALL
+ w_class = WEIGHT_CLASS_TINY
+
+/obj/item/muscle/medium
+ name = "medium muscle piece"
+ desc = "This would make for a great meal if it wasn't still twitching."
+ icon_state = "muscle_medium"
+ size = SIZE_MEDIUM
+ w_class = WEIGHT_CLASS_SMALL
+
+/obj/item/muscle/big
+ name = "big muscle piece"
+ desc = "I'm pretty sure it's owner needed this to live."
+ icon_state = "muscle_big"
+ size = SIZE_BIG
+
+/obj/item/muscle/examine(mob/user)
+ . = ..()
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ if(IS_BLOODSUCKER(user) && bloodsuckerdatum.my_clan == CLAN_TZIMISCE)
+ . += span_cult("By looking at it you comprehend that it would yield [size] points for ritual usage.")
+
+/obj/item/muscle/attackby(obj/item/I, mob/user, params) // handles muscle crafting
+ var/newsize = 0
+ var/quantity = 1
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ if(!(IS_BLOODSUCKER(user) && bloodsuckerdatum.my_clan == CLAN_TZIMISCE))
+ return
+ if(istype(I, /obj/item/muscle))
+ var/obj/item/muscle/muscle2 = I
+ newsize = size + muscle2.size
+ if(newsize > SIZE_BIG) //so you only have to change defines if you want to balance muscles
+ to_chat(user, span_warning("You can't make [src] any bigger!"))
+ return
+ to_chat(user, span_notice("You merge [src] and [muscle2] into a bigger piece."))
+ qdel(muscle2)
+ if(I.sharpness == SHARP_EDGED)
+ newsize = size / 2
+ quantity = 2
+ if(newsize < SIZE_SMALL)
+ to_chat(user, span_warning("You can't cut [src] anymore!"))
+ return
+ to_chat(user, span_notice("You cut [src] into smaller pieces."))
+ switch(newsize)
+ if(0)
+ return ..()
+ if(SIZE_SMALL)
+ new /obj/item/muscle/small(user.drop_location())
+ if(quantity == 2) // don't want to make it stackable
+ new /obj/item/muscle/small(user.drop_location())
+ if(SIZE_SMALL + 0.5)
+ new /obj/item/muscle/small(user.drop_location())
+ new /obj/item/muscle/medium(user.drop_location())
+ if(SIZE_MEDIUM)
+ new /obj/item/muscle/medium(user.drop_location())
+ if(quantity == 2)
+ new /obj/item/muscle/medium(user.drop_location())
+ if(SIZE_MEDIUM + 1)
+ size += 1
+ return
+ if(SIZE_BIG)
+ new /obj/item/muscle/big(user.drop_location())
+ qdel(src)
+
+/datum/action/bloodsucker/targeted/dice/FireTargetedPower(atom/target_atom)
+ var/mob/living/target = target_atom
+ var/mob/living/carbon/user = owner
+ user.face_atom(target)
+ if(target.stat != DEAD)
+ if(iscarbon(target))
+ var/mob/living/carbon/Ctarget = target
+ var/selected_zone = user.zone_selected
+ var/list/viable_zones = list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)
+ if(!viable_zones.Find(selected_zone))
+ selected_zone = pick(viable_zones)
+ var/obj/item/bodypart/target_part = Ctarget.get_bodypart(selected_zone)
+ user.do_attack_animation(Ctarget, ATTACK_EFFECT_PUNCH)
+ playsound(usr.loc, "sound/weapons/slice.ogg", 50, TRUE)
+ if(!target_part)
+ to_chat(user, span_warning("[Ctarget] has no limb there!"))
+ Ctarget.adjustBruteLoss(15 * level_current / 2)
+ return
+ switch(level_current)
+ if(0 to 3)
+ Ctarget.apply_damage(50, STAMINA, selected_zone)
+ to_chat(user, span_warning("You swiftly disable the nerves in [Ctarget]'s [target_part] with a precise strike."))
+ if(3 to 6)
+ Ctarget.apply_damage(25, STAMINA, selected_zone)
+ Ctarget.apply_damage(25, BRUTE, selected_zone)
+ Ctarget.drop_all_held_items()
+ to_chat(user, span_warning("You hastly damage the ligaments in [Ctarget]'s [target_part] with a fierce blow."))
+ if(6 to INFINITY)
+ if(target_part.dismemberable)
+ target_part.dismember()
+ to_chat(user, span_warning("You sever [Ctarget]'s [target_part] with a clean swipe."))
+ else
+ Ctarget.apply_damage(30, BRUTE, selected_zone)
+ Ctarget.drop_all_held_items()
+ to_chat(user, span_warning("As [Ctarget]'s [target_part] is too tough to chop in a single action!"))
+ else
+ target.adjustBruteLoss(25)
+ return
+ playsound(usr.loc, "sound/weapons/slice.ogg", 50, TRUE)
+ if(!do_mob(usr, target, 2.5 SECONDS))
+ return
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ for(var/obj/item/bodypart/bodypart in H.bodyparts)
+ if(bodypart.body_part != HEAD && bodypart.body_part != CHEST)
+ if(bodypart.dismemberable)
+ bodypart.dismember()
+ qdel(bodypart)
+ new /obj/item/muscle/medium(H.loc)
+ else
+ to_chat(user, span_warning("You can't dismember this [bodypart] of [target]"))
+ return
+ if(iscarbon(target))
+ var/mob/living/carbon/C = target
+ for(var/obj/item/bodypart/bodypart in C.bodyparts)
+ if(bodypart.body_part != HEAD && bodypart.body_part != CHEST)
+ if(bodypart.dismemberable)
+ bodypart.dismember()
+ qdel(bodypart)
+ new /obj/item/muscle/small(C.loc)
+ return
+ target.gib()
+ new /obj/item/muscle/medium(target.loc)
+
+/datum/action/bloodsucker/targeted/dice/CheckValidTarget(atom/target_atom)
+ . = ..()
+ if(!.)
+ return FALSE
+ return isliving(target_atom)
+
+/datum/action/bloodsucker/targeted/dice/CheckCanTarget(atom/target_atom)
+ . = ..()
+ if(!.)
+ return FALSE
+ if(isliving(target_atom))
+ return TRUE
+ return FALSE
+
+#undef SIZE_SMALL
+#undef SIZE_MEDIUM
+#undef SIZE_BIG
\ No newline at end of file
diff --git a/code/modules/antagonists/bloodsuckers/powers/veil.dm b/code/modules/antagonists/bloodsuckers/powers/veil.dm
index 3f079df784d2..09538a1f7a41 100644
--- a/code/modules/antagonists/bloodsuckers/powers/veil.dm
+++ b/code/modules/antagonists/bloodsuckers/powers/veil.dm
@@ -8,7 +8,7 @@
Clothes, gear, and Security/Medical HUD status is kept the same while this power is active."
power_flags = BP_AM_TOGGLE
check_flags = BP_CANT_USE_IN_FRENZY
- purchase_flags = VASSAL_CAN_BUY
+ purchase_flags = VASSAL_CAN_BUY|BLOODSUCKER_CAN_BUY
bloodcost = 15
constant_bloodcost = 0.1
cooldown = 10 SECONDS
diff --git a/code/modules/antagonists/bloodsuckers/structures/bloodsucker_coffin.dm b/code/modules/antagonists/bloodsuckers/structures/bloodsucker_coffin.dm
index e9bbbf30cb94..9cee00d12b88 100644
--- a/code/modules/antagonists/bloodsuckers/structures/bloodsucker_coffin.dm
+++ b/code/modules/antagonists/bloodsuckers/structures/bloodsucker_coffin.dm
@@ -2,9 +2,9 @@
// ALREADY CLAIMED
if(claimed.resident)
if(claimed.resident == owner.current)
- to_chat(owner, "This is your [src].")
+ to_chat(owner, "This is your [claimed].")
else
- to_chat(owner, "This [src] has already been claimed by another.")
+ to_chat(owner, "This [claimed] has already been claimed by another.")
return FALSE
if(!(/datum/crafting_recipe/vassalrack in owner?.learned_recipes))
owner.teach_crafting_recipe(/datum/crafting_recipe/vassalrack)
@@ -13,13 +13,14 @@
owner.teach_crafting_recipe(/datum/crafting_recipe/meatcoffin)
owner.teach_crafting_recipe(/datum/crafting_recipe/staketrap)
owner.teach_crafting_recipe(/datum/crafting_recipe/woodenducky)
- owner.teach_crafting_recipe(/datum/crafting_recipe/bloodaltar)
+ if(my_clan != CLAN_TZIMISCE) // better things to do
+ owner.teach_crafting_recipe(/datum/crafting_recipe/bloodaltar)
to_chat(owner, span_danger("You learned new recipes - You can view them in the Structure and Weaponry section of the crafting menu!"))
// This is my Lair
coffin = claimed
lair = get_area(claimed)
to_chat(owner, span_userdanger("You have claimed the [claimed] as your place of immortal rest! Your lair is now [lair]."))
- to_chat(owner, span_announce("Bloodsucker Tip: Find new lair recipes in the tribal tab of the Crafting Menu, including the Persuasion Rack for converting crew into Vassals."))
+ to_chat(owner, span_announce("Bloodsucker Tip: Find new lair recipes in the structure tab of the Crafting Menu, including the Persuasion Rack for converting crew into Vassals and the Blood Altar which lets you gain two tasks per night to Rank Up."))
return TRUE
/// From crate.dm
@@ -41,14 +42,12 @@
desc = "For those departed who are not so dear."
icon_state = "coffin"
icon = 'icons/obj/vamp_obj.dmi'
- open_sound = 'sound/effects/coffin_open.ogg'
- close_sound = 'sound/effects/coffin_close.ogg'
breakout_time = 30 SECONDS
pryLidTimer = 20 SECONDS
resistance_flags = NONE
material_drop = /obj/item/stack/sheet/metal
material_drop_amount = 2
- armor = list(MELEE = 50, BULLET = 20, LASER = 30, ENERGY = 0, BOMB = 50, BIO = 0, FIRE = 70, ACID = 60)
+ armor = list("melee" = 50, "bullet" = 20, "laser" = 30, "energy" = 0, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
/obj/structure/closet/crate/coffin/securecoffin
name = "secure coffin"
@@ -62,7 +61,7 @@
resistance_flags = FIRE_PROOF | LAVA_PROOF | ACID_PROOF
material_drop = /obj/item/stack/sheet/metal
material_drop_amount = 2
- armor = list(MELEE = 35, BULLET = 20, LASER = 20, ENERGY = 0, BOMB = 100, BIO = 0, FIRE = 100, ACID = 100)
+ armor = list("melee" = 35, "bullet" = 20, "laser" = 20, "energy" = 0, "bomb" = 100, "bio" = 0, "rad" = 100, "fire" = 100, "acid" = 100)
/obj/structure/closet/crate/coffin/meatcoffin
name = "meat coffin"
@@ -76,7 +75,7 @@
pryLidTimer = 20 SECONDS
material_drop = /obj/item/reagent_containers/food/snacks/meat/slab
material_drop_amount = 3
- armor = list(MELEE = 70, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 70, BIO = 0, FIRE = 70, ACID = 60)
+ armor = list("melee" = 70, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 70, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
/obj/structure/closet/crate/coffin/metalcoffin
name = "metal coffin"
@@ -89,7 +88,7 @@
breakout_time = 25 SECONDS
pryLidTimer = 30 SECONDS
material_drop = /obj/item/stack/sheet/metal
- armor = list(MELEE = 40, BULLET = 15, LASER = 50, ENERGY = 0, BOMB = 10, BIO = 0, FIRE = 70, ACID = 60)
+ armor = list("melee" = 40, "bullet" = 15, "laser" = 50, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 50, "fire" = 70, "acid" = 60)
//////////////////////////////////////////////
diff --git a/code/modules/antagonists/bloodsuckers/structures/bloodsucker_crypt.dm b/code/modules/antagonists/bloodsuckers/structures/bloodsucker_crypt.dm
index 5af90f75b7ee..fc7c8727b4b3 100644
--- a/code/modules/antagonists/bloodsuckers/structures/bloodsucker_crypt.dm
+++ b/code/modules/antagonists/bloodsuckers/structures/bloodsucker_crypt.dm
@@ -1,4 +1,5 @@
/obj/structure/bloodsucker
+ icon = 'icons/obj/vamp_obj.dmi'
///Who owns this structure?
var/mob/living/owner
/*
@@ -74,11 +75,12 @@
if("Yes")
unbolt(user)
+////////////////////////////////////////////////////
+
#define ALTAR_RANKS_PER_DAY 2
/obj/structure/bloodsucker/bloodaltar
name = "blood altar"
desc = "It is made of marble, lined with basalt, and radiates an unnerving chill that puts your skin on edge."
- icon = 'icons/obj/vamp_obj.dmi'
icon_state = "bloodaltar"
density = TRUE
anchored = FALSE
@@ -87,14 +89,15 @@
can_buckle = FALSE
var/task_completed = FALSE
var/sacrifices = 0
- var/taskheart = FALSE
+ var/sacrificialtask = FALSE
+ var/organ_name = ""
Ghost_desc = "This is a Blood Altar, where bloodsuckers can get two tasks per night to get more ranks."
Vamp_desc = "This is a Blood Altar, which allows you to do two tasks per day to advance your ranks.\n\
- Interact with the Altar by clicking on it after it's bolted to get a a task.\n\
+ Interact with the Altar by clicking on it after it's bolted to get a task.\n\
By checking your notes or the chat you can see what task needs to be done.\n\
Remember you only get two tasks per night."
Vassal_desc = "This is the blood altar, where your master does bounties to advanced their bloodsucking powers.\n\
- Aid your master by bringing them what they need for these bounties or by helping get them."
+ Aid your master by bringing them what they need for these bounties or help getting them."
Hunter_desc = "This is a blood altar, where monsters usually practice a sort of bounty system to advanced their powers.\n\
They normally sacrifice hearts or blood in exchange for these ranks, forcing them to move out of their lair.\n\
It can only be used twice per night and it needs to be interacted it to be claimed, making bloodsuckers come back twice a night."
@@ -118,7 +121,7 @@
if(bloodsuckerdatum.altar_uses >= ALTAR_RANKS_PER_DAY)
to_chat(user, span_notice("You have done all tasks for the night, come back tomorrow for more."))
return
- var/task
+ var/task //just like amongus
var/suckamount = 0
var/heartamount = 0
switch(bloodsuckerdatum.bloodsucker_level + bloodsuckerdatum.bloodsucker_level_unspent)
@@ -142,7 +145,7 @@
sacrifices = 0
to_chat(user, span_notice("You have sucessfully done a task and gained a rank!"))
task_completed = FALSE
- taskheart = FALSE
+ sacrificialtask = FALSE
return
if(bloodsuckerdatum.current_task)
to_chat(user, span_warning("You already have a rank up task!"))
@@ -158,29 +161,31 @@
C.blood_volume -= 100
switch(rand(1, 3))
if(1,2)
- task = "suck [suckamount] units of blood."
+ task = "Suck [suckamount] units of pure blood."
if(3)
- task = "sacrifice [heartamount] hearts by using them on the altar."
- taskheart = TRUE
+ task = "Sacrifice [heartamount] hearts by using them on the altar."
+ sacrificialtask = TRUE
bloodsuckerdatum.task_memory += "Current Rank Up Task: [task]
"
bloodsuckerdatum.current_task = TRUE
- to_chat(user, span_boldnotice("You have gained a new Task! Your task is to [task] Remember to collect it by using the blood altar!"))
+ to_chat(user, span_boldnotice("You have gained a new Task! [task] Remember to collect it by using the blood altar!"))
/obj/structure/bloodsucker/bloodaltar/examine(mob/user)
. = ..()
- if(taskheart)
- . += span_boldnotice("It currently contains [sacrifices] hearts.")
+ if(sacrificialtask)
+ if(sacrifices > 0)
+ . += span_boldnotice("It currently contains [sacrifices] [organ_name].")
else
return ..()
/obj/structure/bloodsucker/bloodaltar/attackby(obj/item/H, mob/user, params)
if(!IS_BLOODSUCKER(user) && !IS_VASSAL(user))
return ..()
- if(taskheart)
+ if(sacrificialtask)
if(istype(H, /obj/item/organ/heart))
if(istype(H, /obj/item/organ/heart/gland))
to_chat(usr, span_warning("This type of organ doesn't have blood to sustain the altar!"))
return ..()
+ organ_name = H.name
to_chat(usr, span_notice("You feed the heart to the altar!"))
qdel(H)
sacrifices++
@@ -188,6 +193,147 @@
return ..()
#undef ALTAR_RANKS_PER_DAY
+////////////////////////////////////////////////////
+
+/obj/structure/bloodsucker/bloodaltar/restingplace
+ name = "resting place"
+ desc = "This seem to hold a bit of significance."
+ icon_state = "restingplace"
+ var/awoken = FALSE
+ Ghost_desc = "This is a Resting Place, where Lasombra bloodsucker can ascend their powers."
+ Vamp_desc = "This is a Resting Place, which allows you to ascend your powers by gaining points using your ranks or blood.\n\
+ Interact with the Altar by clicking on it after you have fed it a abyssal essence, acquirable through influences.\n\
+ Remember most ascended powers have benefits if used in the dark.\n\
+ It only seems to speak to elders of 4 or higher ranks."
+ Vassal_desc = "This is the resting place, where your master does rituals to ascend their bloodsucking powers.\n\
+ Aid your master by bringing them what they need for these or by help getting them."
+ Hunter_desc = "This is a blood altar, where monsters ascend their powers to shadowy levels.\n\
+ They normally need ranks or blood in exchange for power, forcing them to move out of their lair and weakening them."
+
+/obj/item/abyssal_essence
+ name = "abyssal essence"
+ desc = "As you glare at the abyssal essence, you feel it glaring back."
+ icon = 'icons/obj/vamp_obj.dmi'
+ icon_state = "abyssal_essence"
+ item_state = "abyssal_essence"
+ throwforce = 0
+ w_class = WEIGHT_CLASS_TINY
+ throw_speed = 3
+ throw_range = 7
+ pressure_resistance = 10
+
+/obj/structure/bloodsucker/bloodaltar/restingplace/deconstruct(disassembled = TRUE)
+ . = ..()
+ new /obj/item/abyssal_essence(src.loc)
+ qdel(src)
+
+/obj/structure/bloodsucker/bloodaltar/restingplace/attackby(obj/item/H, mob/user, params)
+ if(!IS_BLOODSUCKER(user) && !IS_VASSAL(user))
+ return ..()
+ if(!awoken)
+ if(istype(H, /obj/item/abyssal_essence))
+ to_chat(usr, span_notice("As you touch [src] with the [H], you start sensing something different coming from [src]!"))
+ qdel(H)
+ awoken = TRUE
+ else
+ to_chat(user, span_cult("Seems like you need a direct link to the abyss to awaken [src]. Maybe searching a spacial influence would yield something."))
+ return
+ . = ..()
+
+/obj/effect/reality_smash/attack_hand(mob/user, list/modifiers) // this is important
+ if(!IS_BLOODSUCKER(user)) //only bloodsucker will attack this with their hand
+ return
+ if(INTERACTING_WITH(user, src))
+ return
+ if(user.mind in src.siphoners)
+ to_chat(user, span_danger("You have already harvested this shard!"))
+ return
+ to_chat(user, span_danger("You start to harvest the energy of [src]..."))
+ if(do_after(user,10 SECONDS,TRUE,src))
+ user.put_in_hands(new /obj/item/abyssal_essence)
+ to_chat(user, span_notice("You finish harvesting the energy of [src]!"))
+ src.siphoners |= user.mind
+
+/obj/structure/bloodsucker/bloodaltar/restingplace/attack_hand(mob/user, list/modifiers)
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ if(!IS_BLOODSUCKER(user))
+ return ..()
+ if(bloodsuckerdatum.my_clan == CLAN_LASOMBRA)
+ if(bloodsuckerdatum.clanpoints > 0)
+ var/list/upgradablepowers = list()
+ var/list/unupgradablepowers = list(/datum/action/bloodsucker/feed, /datum/action/bloodsucker/masquerade, /datum/action/bloodsucker/veil)
+ for(var/datum/action/bloodsucker/power as anything in bloodsuckerdatum.powers)
+ if(initial(power.purchase_flags) & BLOODSUCKER_CAN_BUY)
+ upgradablepowers += power
+ if(is_type_in_list(power, unupgradablepowers))
+ upgradablepowers -= power
+ var/choice = input(usr, "What Power do you wish to ascend? This resets the powers level.", "Darkness Manager") in upgradablepowers
+ if(!choice)
+ return
+ if((locate(upgradablepowers[choice]) in bloodsuckerdatum.powers))
+ return
+ if(istype(choice, /datum/action/bloodsucker/targeted/brawn))
+ bloodsuckerdatum.BuyPower(new /datum/action/bloodsucker/targeted/brawn/shadow)
+ if(istype(choice, /datum/action/bloodsucker/targeted/haste))
+ bloodsuckerdatum.BuyPower(new /datum/action/bloodsucker/targeted/haste/shadow)
+ if(istype(choice, /datum/action/bloodsucker/fortitude))
+ bloodsuckerdatum.BuyPower(new /datum/action/bloodsucker/fortitude/shadow) // i hate this
+ if(istype(choice, /datum/action/bloodsucker/targeted/mesmerize))
+ bloodsuckerdatum.BuyPower(new /datum/action/bloodsucker/targeted/mesmerize/shadow)
+ if(istype(choice, /datum/action/bloodsucker/targeted/trespass))
+ bloodsuckerdatum.BuyPower(new /datum/action/bloodsucker/targeted/trespass/shadow)
+ if(istype(choice, /datum/action/bloodsucker/targeted/lunge))
+ bloodsuckerdatum.BuyPower(new /datum/action/bloodsucker/targeted/lunge/shadow)
+ if(istype(choice, /datum/action/bloodsucker/cloak/))
+ bloodsuckerdatum.BuyPower(new /datum/action/bloodsucker/cloak/shadow)
+ bloodsuckerdatum.powers -= choice
+ qdel(choice)
+ to_chat(user, span_boldnotice("You have ascended [choice]!"))
+ bloodsuckerdatum.clanpoints--
+ return
+ if(bloodsuckerdatum.bloodsucker_level >= 4 )
+ if(!awoken) //don't want this to affect power upgrading if you make another one
+ to_chat(user, span_cult("Seems like you need a direct link to the abyss to awaken [src]. Maybe searching a spacial influence would yield something."))
+ return
+ icon_state = initial(icon_state) + (awoken ? "_idle" : "_awaken")
+ update_icon()
+ var/rankspent
+ switch(bloodsuckerdatum.clanprogress)
+ if(0)
+ bloodsuckerdatum.clanprogress++
+ bloodsuckerdatum.clanpoints++
+ to_chat(user, span_notice("As you touch the [src] you feel the a slight abyssal pulse flow through you... You have gained a point!"))
+ return
+ if(1 to 3)
+ rankspent = 1
+ if(4 to 6)
+ rankspent = 2
+ if(7)
+ rankspent = 3
+ if(8 to INFINITY)
+ to_chat(user, span_notice("You have evolved all abilities possible."))
+ return
+ var/want_clantask = alert("Do you want to spend a rank to gain a shadowpoint? This will cost [rankspent] ranks.", "Dark Manager", "Yes", "No")
+ if(want_clantask == "No" || QDELETED(src))
+ return
+ if(bloodsuckerdatum.bloodsucker_level_unspent < rankspent)
+ var/another_shot = alert("It seems like you don't have enough ranks, spend 550 blood instead?", "Dark Manager", "Yes", "No")
+ if(another_shot == "No" || QDELETED(src))
+ return
+ var/mob/living/carbon/C = user
+ if(C.blood_volume < 550)
+ to_chat(user, span_danger("You don't have enough blood to gain a shadowpoint!"))
+ return
+ C.blood_volume -= 550
+ else
+ bloodsuckerdatum.bloodsucker_level_unspent -= rankspent
+ bloodsuckerdatum.clanpoints++
+ bloodsuckerdatum.clanprogress++
+ return
+ return ..()
+
+////////////////////////////////////////////////////
+
/*/obj/structure/bloodsucker/bloodstatue
name = "bloody countenance"
desc = "It looks upsettingly familiar..."
@@ -201,10 +347,81 @@
name = "faded mirror"
desc = "You get the sense that the foggy reflection looking back at you has an alien intelligence to it."*/
+////////////////////////////////////////////////////
+
+/obj/structure/bloodsucker/possessedarmor
+ name = "knight's armor"
+ desc = "I swear i saw it's eyes move..."
+ icon_state = "posarmor"
+ anchored = FALSE
+ density = TRUE
+ Ghost_desc = "This Knight's armor will come alive once non-bloodsuckers get close to it."
+ Vamp_desc = "This is a possesed knight's armor, it will come alive once mortals get close to it.\n\
+ You don't care about it's attack's since you are brute immune.\n\
+ You can reinforce it with 5 silver bars.\n\
+ Good for immediate defense of your lair."
+ Vassal_desc = "This is a possesed knight's armor, it will protect your master if people get too close to it."
+ Hunter_desc = "This is a suspicious knight's armor. These things shouldn't be here, i shouldn't get too close."
+ var/upgraded = FALSE
+
+/obj/structure/bloodsucker/possessedarmor/upgraded
+ name = "shiny knight's armor"
+ upgraded = TRUE
+
+/obj/structure/bloodsucker/possessedarmor/bolt()
+ . = ..()
+ anchored = TRUE
+ START_PROCESSING(SSprocessing, src)
+
+/obj/structure/bloodsucker/possessedarmor/unbolt()
+ . = ..()
+ anchored = FALSE
+ STOP_PROCESSING(SSprocessing, src)
+
+/obj/structure/bloodsucker/possessedarmor/AltClick(mob/user)
+ if(!anchored)
+ setDir(turn(dir,-90))
+ else
+ return ..()
+
+/obj/structure/bloodsucker/possessedarmor/attackby(obj/item/I, mob/user, params)
+ if(upgraded)
+ to_chat(user, span_warning("[src] is already reinforced!"))
+ return
+ if(istype(I, /obj/item/stack/sheet/mineral/silver))
+ var/obj/item/stack/sheet/mineral/silver/S = I
+ if(S.amount < 5)
+ to_chat(user, span_warning("You need at least five silver bars to reinforce [src]!"))
+ return
+ else
+ to_chat(user, span_notice("You start adding [I] to [src]..."))
+ if(do_after(user, 5 SECONDS, target=src))
+ S.use(5)
+ new /obj/structure/bloodsucker/possessedarmor/upgraded(src.loc)
+ qdel(src)
+ return
+ return ..()
+
+/obj/structure/bloodsucker/possessedarmor/Destroy()
+ . = ..()
+ STOP_PROCESSING(SSprocessing, src)
+
+/obj/structure/bloodsucker/possessedarmor/process()
+ for(var/mob/living/passerby in dview(1, get_turf(src)))
+ if(IS_BLOODSUCKER(passerby) || IS_VASSAL(passerby))
+ continue
+ to_chat(passerby, span_warning("The armor starts moving!"))
+ if(upgraded)
+ new /mob/living/simple_animal/hostile/bloodsucker/possessedarmor/upgraded(src.loc)
+ else
+ new /mob/living/simple_animal/hostile/bloodsucker/possessedarmor(src.loc)
+ qdel(src)
+
+////////////////////////////////////////////////////
+
/obj/structure/bloodsucker/vassalrack
name = "persuasion rack"
desc = "If this wasn't meant for torture, then someone has some fairly horrifying hobbies."
- icon = 'icons/obj/vamp_obj.dmi'
icon_state = "vassalrack"
anchored = FALSE
/// Start dense. Once fixed in place, go non-dense.
@@ -233,6 +450,13 @@
var/disloyalty_confirm = FALSE
/// Prevents popup spam.
var/disloyalty_offered = FALSE
+ /// For Tzimisce bloodsuckers' rituals
+ var/meat_points = 0
+ var/bigmeat = 0
+ var/intermeat = 0
+ var/mediummeat = 0
+ var/smallmeat = 0
+ var/meat_amount = 0
/obj/structure/bloodsucker/vassalrack/deconstruct(disassembled = TRUE)
. = ..()
@@ -240,6 +464,16 @@
new /obj/item/stack/rods(loc, 4)
qdel(src)
+/obj/structure/bloodsucker/vassalrack/examine(mob/user)
+ . = ..()
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ if(bloodsuckerdatum.my_clan == CLAN_TZIMISCE)
+ if(meat_amount > 0)
+ . += span_boldnotice("It currently contains [meat_points] points to use in rituals.")
+ . += span_boldnotice("You can add meat points to the rack by using muscle, acquired from Dicing corpses, on it.")
+ else
+ return ..()
+
/obj/structure/bloodsucker/vassalrack/bolt()
. = ..()
density = FALSE
@@ -341,17 +575,90 @@
/// If I'm not a Bloodsucker, try to unbuckle them.
var/datum/antagonist/vassal/vassaldatum = IS_VASSAL(buckled_carbons)
// Are they our Vassal, or Dead?
- if(istype(vassaldatum) && vassaldatum.master == bloodsuckerdatum || buckled_carbons.stat >= DEAD)
+ if(buckled_carbons.stat == DEAD)
+ if(bloodsuckerdatum.my_clan != CLAN_TZIMISCE)
+ to_chat(user, span_warning("[buckled_carbons] is dead!"))
+ return
+ do_ritual(user, buckled_carbons)
+ return
+ if(istype(vassaldatum) && vassaldatum.master == bloodsuckerdatum)
// Can we assign a Favorite Vassal?
if(istype(vassaldatum) && !bloodsuckerdatum.has_favorite_vassal)
- if(buckled_carbons.mind.can_make_bloodsucker(buckled_carbons.mind))
- offer_favorite_vassal(user, buckled_carbons)
+ offer_favorite_vassal(user, buckled_carbons)
+ else if(bloodsuckerdatum.my_clan == CLAN_TZIMISCE)
+ do_ritual(user, buckled_carbons)
use_lock = FALSE
return
// Not our Vassal, but Alive & We're a Bloodsucker, good to torture!
torture_victim(user, buckled_carbons)
+#define MEATLIMIT 3
+/obj/structure/bloodsucker/vassalrack/attackby(obj/item/I, mob/user, params) //Tzimisce stuff
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ if(bloodsuckerdatum.my_clan != CLAN_TZIMISCE)
+ return ..() // only gamers
+ if(istype(I, /obj/item/muscle))
+ if(meat_amount >= MEATLIMIT)
+ to_chat(user, span_warning("You can't fit more meat into [src]"))
+ return
+ var/obj/item/muscle/M = I
+ meat_points += M.size
+ switch(M.size)
+ if(4)
+ bigmeat++
+ if(3)
+ intermeat++
+ if(2)
+ mediummeat++
+ if(1)
+ smallmeat++
+ meat_amount = bigmeat + intermeat + mediummeat + smallmeat
+ qdel(I)
+ update_icon()
+#undef MEATLIMIT
+
+/obj/structure/bloodsucker/vassalrack/update_icon()
+ cut_overlays()
+ if(bigmeat > 0)
+ add_overlay("bigmeat_[bigmeat]")
+ if(intermeat > 0)
+ add_overlay("mediummeat_[intermeat]")
+ add_overlay("smallmeat_[intermeat]")
+ if(mediummeat > 0)
+ add_overlay("mediummeat_[mediummeat + intermeat]")
+ if(smallmeat > 0)
+ add_overlay("smallmeat_[smallmeat + intermeat]")
+
+/obj/structure/bloodsucker/vassalrack/CtrlClick(mob/user)
+ if(!anchored)
+ return ..()
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ if(bloodsuckerdatum.my_clan != CLAN_TZIMISCE)
+ return ..()
+ if(meat_amount > 0)
+ if(smallmeat > 0)
+ new /obj/item/muscle/small(user.drop_location())
+ smallmeat--
+ meat_points -= 1
+ if(mediummeat > 0)
+ new /obj/item/muscle/medium(user.drop_location())
+ mediummeat--
+ meat_points -= 2
+ if(intermeat > 0)
+ new /obj/item/muscle/medium(user.drop_location())
+ new /obj/item/muscle/small(user.drop_location())
+ intermeat--
+ meat_points -= 3
+ if(bigmeat > 0)
+ new /obj/item/muscle/big(user.drop_location())
+ bigmeat--
+ meat_points -= 4
+ else
+ to_chat(user, span_warning("There's no meat to retrieve in [src]"))
+ meat_amount = bigmeat + intermeat + mediummeat + smallmeat
+ update_icon()
+
/**
* Step One: Tick Down Conversion from 3 to 0
* Step Two: Break mindshielding/antag (on approve)
@@ -528,13 +835,168 @@
to_chat(user, span_danger("You decide not to turn [target] into your Favorite Vassal."))
use_lock = FALSE
+/obj/structure/bloodsucker/vassalrack/proc/do_ritual(mob/living/user, mob/living/target)
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ if(!target.mind)
+ to_chat(user, span_warning("[target] is catatonic!"))
+ /// To deal with Blood
+ var/mob/living/carbon/human/B = user
+ var/mob/living/carbon/human/H = target
+
+ /// Due to the checks leding up to this, if they fail this, they're dead & Not our vassal.
+ if(!IS_VASSAL(target))
+ to_chat(user, span_notice("Do you wish to rebuild this body? This will remove any restraints they might have, and will cost 150 Blood!"))
+ var/revive_response = alert(usr, "Would you like to revive [target]?", "Ghetto Medbay", "Yes", "No")
+ switch(revive_response)
+ if("Yes")
+ if(!do_mob(user, src, 7 SECONDS))
+ to_chat(user, span_danger("The ritual has been interrupted!"))
+ return
+ if(prob(15) && bloodsuckerdatum.bloodsucker_level <= 2)
+ to_chat(user, span_danger("Something has gone terribly wrong! You have accidentally turned [target] into a High-Functioning Zombie!"))
+ to_chat(target, span_announce("As Blood drips over your body, your heart fails to beat... But you still wake up."))
+ H.set_species(/datum/species/zombie)
+ else
+ to_chat(user, span_danger("You have brought [target] back from the Dead!"))
+ to_chat(target, span_announce("As Blood drips over your body, your heart begins to beat... You live again!"))
+ B.blood_volume -= 150
+ target.revive(full_heal = TRUE, admin_revive = FALSE)
+ return
+ to_chat(user, span_danger("You decide not to revive [target]."))
+ // Unbuckle them now.
+ unbuckle_mob(B)
+ use_lock = FALSE
+ return
+ var/list/races = list(HUSK_MONSTER)
+ switch(bloodsuckerdatum.bloodsucker_level)
+ if(1 to 3)
+ races += ARMMY_MONSTER
+ if(3 to 5)
+ races += ARMMY_MONSTER
+ races += CALCIUM_MONSTER
+ if(5 to INFINITY)
+ races += ARMMY_MONSTER
+ races += CALCIUM_MONSTER
+ races += TRIPLECHEST_MONSTER
+ var/list/options = list()
+ options = races
+ var/answer = input(user, "We have the chance to mutate our Vassal, how should we mutilate their corpse? This will cost us blood.", "What do we do with our Vassal?") in options
+ var/meat_cost = 0
+ var/blood_gained
+ if(!answer)
+ to_chat(user, span_notice("You decide to leave your Vassal just the way they are."))
+ return
+ to_chat(user, span_warning("You start mutating your Vassal into a [answer]..."))
+ if(!do_mob(user, src, 5 SECONDS))
+ to_chat(user, span_danger("The ritual has been interrupted!"))
+ return
+ playsound(target.loc, 'sound/weapons/slash.ogg', 50, TRUE, -1)
+ switch(answer)
+ if(HUSK_MONSTER)
+ if(HAS_TRAIT(target, TRAIT_HUSK))
+ to_chat(user, span_warning("[target] is already a Husk!"))
+ return
+ if(!do_mob(user, target, 1 SECONDS))
+ return
+ playsound(target.loc, 'sound/weapons/slash.ogg', 50, TRUE, -1)
+ if(!do_mob(user, target, 1 SECONDS))
+ return
+ to_chat(user, span_notice("You suck all the blood out of [target], turning them into a Living Husk!"))
+ to_chat(target, span_notice("Your master has mutated you into a Living Husk!"))
+ playsound(target.loc, 'sound/magic/mutate.ogg', 50, TRUE, -1)
+ /// Just take it all
+ blood_gained = 250
+ target.remove_all_languages()
+ target.grant_language(/datum/language/vampiric)
+ H.become_husk()
+ bloodsuckerdatum.bloodsucker_level_unspent++
+ if(ARMMY_MONSTER)
+ meat_cost = 4
+ var/mob/living/simple_animal/hostile/bloodsucker/tzimisce/armmy/A
+ if(!(HAS_TRAIT(target, TRAIT_HUSK)))
+ to_chat(user, span_warning("You need to mutilate [target] into a husk first before doing this."))
+ return
+ if(meat_points < meat_cost)
+ to_chat(user, span_warning("You need atleast [meat_cost - meat_points] more meat points to do this."))
+ return
+ if(!do_mob(user, target, 1 SECONDS))
+ return
+ playsound(target.loc, 'sound/weapons/slash.ogg', 50, TRUE, -1)
+ to_chat(user, span_notice("You transfer your blood and toy with [target]'s flesh, leaving their body as a head and arm almalgam."))
+ to_chat(target, span_notice("Your master has mutated you into a tiny arm monster!"))
+ B.blood_volume -= 100
+ A = new /mob/living/simple_animal/hostile/bloodsucker/tzimisce/armmy(target.loc)
+ target.forceMove(A)
+ target.mind.transfer_to(A)
+ A.bloodsucker = target
+ /// Chance to give Bat form, or turn them into a bat.
+ if(CALCIUM_MONSTER)
+ meat_cost = 8
+ var/mob/living/simple_animal/hostile/bloodsucker/tzimisce/calcium/C
+ if(!(HAS_TRAIT(target, TRAIT_HUSK)))
+ to_chat(user, span_warning("You need to mutilate [target] into a husk first before doing this."))
+ return
+ if(meat_points < meat_cost)
+ to_chat(user, span_warning("You need atleast [meat_cost - meat_points] more meat points to do this."))
+ return
+ if(!do_mob(user, target, 1 SECONDS))
+ return
+ playsound(target.loc, 'sound/weapons/slash.ogg', 50, TRUE, -1)
+ to_chat(user, span_notice("You transfer your blood and toy with [target]'s flesh and bones, leaving their body as a boney and flesh amalgam."))
+ to_chat(target, span_notice("Your master has mutated you into a fractured monster!"))
+ B.blood_volume -= 150
+ C = new /mob/living/simple_animal/hostile/bloodsucker/tzimisce/calcium(target.loc)
+ target.forceMove(C)
+ target.mind.transfer_to(C)
+ C.bloodsucker = target
+ if(TRIPLECHEST_MONSTER)
+ meat_cost = 12
+ var/mob/living/simple_animal/hostile/bloodsucker/tzimisce/triplechest/T
+ if(!(HAS_TRAIT(target, TRAIT_HUSK)))
+ to_chat(user, span_warning("You need to mutilate [target] into a husk first before doing this."))
+ return
+ if(meat_points < meat_cost)
+ to_chat(user, span_warning("You need atleast [meat_cost - meat_points] more meat points to do this."))
+ return
+ if(!do_mob(user, target, 1 SECONDS))
+ return
+ playsound(target.loc, 'sound/weapons/slash.ogg', 50, TRUE, -1)
+ if(!do_mob(user, target, 1 SECONDS))
+ return
+ to_chat(user, span_notice("You transfer your blood and toy with [target]'s flesh and bones, leaving their body as a huge pile of flesh and organs."))
+ to_chat(target, span_notice("Your master has mutated you into a gigartuan monster!"))
+ B.blood_volume -= 300
+ T = new /mob/living/simple_animal/hostile/bloodsucker/tzimisce/triplechest(target.loc)
+ target.forceMove(T)
+ target.mind.transfer_to(T)
+ T.bloodsucker = target
+ if(blood_gained)
+ user.blood_volume += blood_gained
+ var/meatlost = 0
+ while(meat_cost)
+ meat_points--
+ meat_cost--
+ meatlost++
+ if(smallmeat && meatlost == 1)
+ smallmeat--
+ meatlost--
+ if(mediummeat && meatlost == 2)
+ mediummeat--
+ meatlost -= 2
+ if(intermeat && meatlost == 3)
+ intermeat--
+ meatlost -= 3
+ if(bigmeat && meatlost == 4)
+ bigmeat--
+ meatlost -= 4
+ update_icon()
+ meat_amount = bigmeat + intermeat + mediummeat + smallmeat
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/obj/structure/bloodsucker/candelabrum
name = "candelabrum"
desc = "It burns slowly, but doesn't radiate any heat."
- icon = 'icons/obj/vamp_obj.dmi'
icon_state = "candelabrum"
light_color = "#66FFFF"//LIGHT_COLOR_BLUEGREEN // lighting.dm
light_power = 3
@@ -551,6 +1013,12 @@
Hunter_desc = "This is a blue Candelabrum, which causes insanity to those near it while active."
var/lit = FALSE
+/obj/structure/bloodsucker/candelabrum/deconstruct(disassembled = TRUE)
+ . = ..()
+ new /obj/item/candle(loc, 1)
+ new /obj/item/stack/rods(loc, 4)
+ qdel(src)
+
/obj/structure/bloodsucker/candelabrum/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
diff --git a/code/modules/antagonists/bloodsuckers/structures/bloodsucker_life.dm b/code/modules/antagonists/bloodsuckers/structures/bloodsucker_life.dm
index 98f923202ae7..31feda4c345d 100644
--- a/code/modules/antagonists/bloodsuckers/structures/bloodsucker_life.dm
+++ b/code/modules/antagonists/bloodsuckers/structures/bloodsucker_life.dm
@@ -1,6 +1,8 @@
/// Runs from COMSIG_LIVING_BIOLOGICAL_LIFE, handles Bloodsucker constant proccesses.
/datum/antagonist/bloodsucker/proc/LifeTick()
+ if(isbrain(owner.current))
+ return
if(!owner)
INVOKE_ASYNC(src, .proc/HandleDeath)
return
@@ -51,9 +53,11 @@
///////////
// Reduce Value Quantity
if(target.stat == DEAD) // Penalty for Dead Blood
- blood_taken /= 3
+ blood_taken /= 4
if(!ishuman(target)) // Penalty for Non-Human Blood
- blood_taken /= 2
+ blood_taken /= 3
+ if(!target.mind && !target.client)
+ blood_taken /= 5 // Penalty for Catatonics / Braindead
//if (!iscarbon(target)) // Penalty for Animals (they're junk food)
// Apply to Volume
AddBloodVolume(blood_taken)
@@ -65,7 +69,10 @@
if(frenzied)
frenzy_blood_drank += blood_taken
if(current_task)
- task_blood_drank += blood_taken
+ if(target.mind)
+ task_blood_drank += blood_taken
+ else
+ to_chat(owner, span_warning("[target] is catatonic and won't yield any usable blood for tasks!"))
return blood_taken
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -161,6 +168,9 @@
current_eyes.sight_flags = SEE_MOBS
current_eyes.see_in_dark = 8
current_eyes.lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
+ if(my_clan == CLAN_LASOMBRA && ishuman(bloodsuckeruser))
+ var/mob/living/carbon/human/bloodsucker = bloodsuckeruser
+ bloodsucker.eye_color = "f00"
bloodsuckeruser.update_sight()
// Step 3
@@ -191,15 +201,9 @@
/// FINAL DEATH
/datum/antagonist/bloodsucker/proc/HandleDeath()
// Not "Alive"?
- var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.has_antag_datum(/datum/antagonist/bloodsucker)
- if(bloodsuckerdatum.my_clan == CLAN_GANGREL)
- if(!owner.current || !isliving(owner.current) || isbrain(owner.current) || !get_turf(owner.current))
- FinalDeath()
- return
- else
- if(!owner.current || !iscarbon(owner.current) || isbrain(owner.current) || !get_turf(owner.current))
- FinalDeath()
- return
+ if(!owner.current || !get_turf(owner.current))
+ FinalDeath()
+ return
// Fire Damage? (above double health)
if(owner.current.getFireLoss() >= owner.current.maxHealth * 2.5)
FinalDeath()
@@ -225,8 +229,7 @@
// BLOOD_VOLUME_GOOD: [336] - Pale
// handled in bloodsucker_integration.dm
-
- // BLOOD_VOLUME_EXIT: [250] - Exit Frenzy (If in one) This is high because we want enough to kill the poor soul they feed off of.
+ // BLOOD_VOLUME_EXIT: [560] - Exit Frenzy (If in one) This is high because we want enough to kill the poor soul they feed off of.
if(owner.current.blood_volume >= FRENZY_THRESHOLD_EXIT && frenzied)
owner.current.remove_status_effect(STATUS_EFFECT_FRENZY)
// BLOOD_VOLUME_BAD: [224] - Jitter
@@ -240,6 +243,9 @@
if(owner.current.blood_volume < (FRENZY_THRESHOLD_ENTER + (humanity_lost * 10)) && !frenzied)
if(!iscarbon(owner.current))
return
+ if(owner.current.stat == DEAD)
+ HandleDeath()
+ return
enter_frenzy()
else if(owner.current.blood_volume < BLOOD_VOLUME_BAD(owner.current))
additional_regen = 0.1
@@ -253,7 +259,51 @@
additional_regen = 0.5
/datum/antagonist/bloodsucker/proc/enter_frenzy()
- owner.current.apply_status_effect(STATUS_EFFECT_FRENZY)
+ if(my_clan == CLAN_GANGREL)
+ var/mob/living/carbon/user = owner.current
+ switch(frenzies)
+ if(0)
+ owner.current.apply_status_effect(STATUS_EFFECT_FRENZY)
+ return
+ if(1)
+ to_chat(owner, span_warning("You start feeling hungrier, you feel like a normal frenzy won't satiate it enough anymore."))
+ owner.current.apply_status_effect(STATUS_EFFECT_FRENZY)
+ return
+ if(2 to INFINITY)
+ AddBloodVolume(560 - user.blood_volume) //so it doesn't happen multiple times and refills your blood when you get out again
+ if(!do_mob(user, user, 2 SECONDS, TRUE))
+ return
+ playsound(user.loc, 'sound/weapons/slash.ogg', 25, 1)
+ to_chat(user, span_warning("You skin rips and tears."))
+ if(!do_mob(user, user, 1 SECONDS, TRUE))
+ return
+ playsound(user.loc, 'sound/weapons/slashmiss.ogg', 25, 1)
+ to_chat(user, span_warning("You heart pumps blackened blood into your veins as your skin turns into fur."))
+ if(!do_mob(user, user, 1 SECONDS, TRUE))
+ return
+ playsound(user.loc, 'sound/weapons/slice.ogg', 25, 1)
+ to_chat(user, span_boldnotice("YOU HAVE AWOKEN."))
+ var/mob/living/simple_animal/hostile/bloodsucker/werewolf/ww
+ if(!ww || ww.stat == DEAD)
+ ww = new /mob/living/simple_animal/hostile/bloodsucker/werewolf(user.loc)
+ user.forceMove(ww)
+ ww.bloodsucker = user
+ user.mind.transfer_to(ww)
+ var/list/wolf_powers = list(new /datum/action/bloodsucker/targeted/feast,)
+ for(var/datum/action/bloodsucker/power in powers)
+ if(istype(power, /datum/action/bloodsucker/fortitude))
+ wolf_powers += new /datum/action/bloodsucker/gangrel/wolfortitude
+ if(istype(power, /datum/action/bloodsucker/targeted/lunge))
+ wolf_powers += new /datum/action/bloodsucker/targeted/pounce
+ if(istype(power, /datum/action/bloodsucker/cloak))
+ wolf_powers += new /datum/action/bloodsucker/gangrel/howl
+ if(istype(power, /datum/action/bloodsucker/targeted/trespass))
+ wolf_powers += new /datum/action/bloodsucker/gangrel/rabidism
+ for(var/datum/action/bloodsucker/power in wolf_powers)
+ power.Grant(ww)
+ frenzies++
+ else
+ owner.current.apply_status_effect(STATUS_EFFECT_FRENZY)
/**
* # Torpor
@@ -317,6 +367,7 @@
Torpor_End()
/datum/antagonist/bloodsucker/proc/Torpor_Begin()
+ var/mob/living/carbon/human/bloodsucker = owner.current
to_chat(owner.current, span_notice("You enter the horrible slumber of deathless Torpor. You will heal until you are renewed."))
/// Force them to go to sleep
REMOVE_TRAIT(owner.current, TRAIT_SLEEPIMMUNE, BLOODSUCKER_TRAIT)
@@ -325,15 +376,16 @@
ADD_TRAIT(owner.current, TRAIT_FAKEDEATH, BLOODSUCKER_TRAIT)
ADD_TRAIT(owner.current, TRAIT_DEATHCOMA, BLOODSUCKER_TRAIT)
ADD_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, BLOODSUCKER_TRAIT)
- //ADD_TRAIT(owner.current, TRAIT_BRUTEIMMUNE, BLOODSUCKER_TRAIT)
+ bloodsucker.physiology.brute_mod *= 0
owner.current.Jitter(0)
/// Disable ALL Powers
DisableAllPowers()
/datum/antagonist/bloodsucker/proc/Torpor_End()
+ var/mob/living/carbon/human/bloodsucker = owner.current
owner.current.grab_ghost()
to_chat(owner.current, span_warning("You have recovered from Torpor."))
- //REMOVE_TRAIT(owner.current, TRAIT_BRUTEIMMUNE, BLOODSUCKER_TRAIT)
+ bloodsucker.physiology.brute_mod = initial(bloodsucker.physiology.brute_mod)
REMOVE_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, BLOODSUCKER_TRAIT)
REMOVE_TRAIT(owner.current, TRAIT_DEATHCOMA, BLOODSUCKER_TRAIT)
REMOVE_TRAIT(owner.current, TRAIT_FAKEDEATH, BLOODSUCKER_TRAIT)
@@ -396,7 +448,7 @@
timeout = 8 MINUTES
/datum/mood_event/drankkilled
- description = "I drank from my victim until they died. I feel... less human.\n"
+ description = "I fed off of a dead person. I feel... less human.\n"
mood_change = -15
timeout = 10 MINUTES
diff --git a/code/modules/antagonists/bloodsuckers/structures/bloodsucker_recipes.dm b/code/modules/antagonists/bloodsuckers/structures/bloodsucker_recipes.dm
index c3ae4856c046..6062ab02c38c 100644
--- a/code/modules/antagonists/bloodsuckers/structures/bloodsucker_recipes.dm
+++ b/code/modules/antagonists/bloodsuckers/structures/bloodsucker_recipes.dm
@@ -1,5 +1,8 @@
/// From recipes.dm
+/////////////////////////
+/// Coffins ///
+/////////////////////////
/datum/crafting_recipe/blackcoffin
name = "Black Coffin"
result = /obj/structure/closet/crate/coffin/blackcoffin
@@ -46,20 +49,35 @@
time = 10 SECONDS
category = CAT_STRUCTURES
+////////////////////////////
+/// Structures ///
+////////////////////////////
/datum/crafting_recipe/bloodaltar
name = "Blood Altar"
result = /obj/structure/bloodsucker/bloodaltar
- tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WRENCH)
+ tools = list(TOOL_WELDER, TOOL_WRENCH)
reqs = list(
/obj/item/stack/rods = 5,
- /obj/item/stack/sheet/metal = 2,
- /obj/item/stack/sheet/plasteel = 5,
+ /obj/item/stack/sheet/metal = 5,
/datum/reagent/ash = 30,
)
time = 13 SECONDS
category = CAT_STRUCTURES
always_availible = FALSE
+/datum/crafting_recipe/restingplace
+ name = "Resting Place"
+ result = /obj/structure/bloodsucker/bloodaltar/restingplace
+ tools = list(TOOL_WRENCH, TOOL_SCREWDRIVER)
+ reqs = list(
+ /obj/item/stack/rods = 5,
+ /obj/item/stack/sheet/metal = 5,
+ /obj/item/stack/sheet/cloth = 2, //that's right it comes with bones FREE OF CHARGE
+ )
+ time = 15 SECONDS
+ category = CAT_STRUCTURES
+ always_availible = FALSE
+
/datum/crafting_recipe/vassalrack
name = "Persuasion Rack"
result = /obj/structure/bloodsucker/vassalrack
@@ -79,7 +97,6 @@
tools = list(TOOL_SCREWDRIVER, TOOL_HATCHET)
reqs = list(
/obj/item/stake = 2,
- /obj/item/reagent_containers/blood = 1,
/obj/item/stack/sheet/mineral/wood = 2,
/obj/item/restraints/handcuffs/cable = 1,
)
@@ -113,6 +130,21 @@
category = CAT_STRUCTURES
always_availible = FALSE
+/datum/crafting_recipe/possessedarmor
+ name = "Subservent Armor"
+ result = /obj/structure/bloodsucker/possessedarmor
+ tools = list(TOOL_WRENCH, TOOL_WELDER, TOOL_SCREWDRIVER)
+ reqs = list(
+ /obj/item/stack/rods = 5,
+ /obj/item/stack/sheet/metal = 15,
+ )
+ time = 10 SECONDS
+ category = CAT_STRUCTURES
+ always_availible = FALSE
+
+////////////////////////
+/// Stakes ///
+////////////////////////
/datum/crafting_recipe/stake
name = "Stake"
result = /obj/item/stake
diff --git a/code/modules/antagonists/bloodsuckers/vassal.dm b/code/modules/antagonists/bloodsuckers/vassal.dm
index f07f3ea76753..ba6180271ea9 100644
--- a/code/modules/antagonists/bloodsuckers/vassal.dm
+++ b/code/modules/antagonists/bloodsuckers/vassal.dm
@@ -15,7 +15,7 @@
var/datum/game_mode/blooodsucker
/// List of all Purchased Powers, like Bloodsuckers.
var/list/datum/action/powers = list()
- /// The favorite vassal gets unique features, and Ventrue can upgrade theirs
+ /// The favorite vassal gets unique features.
var/favorite_vassal = FALSE
/// Bloodsucker levels, but for Vassals.
var/vassal_level
@@ -25,6 +25,14 @@
/datum/antagonist/vassal/apply_innate_effects(mob/living/mob_override)
. = ..()
+ var/mob/living/current_mob = mob_override || owner.current
+ current_mob.apply_status_effect(/datum/status_effect/agent_pinpointer/vassal_edition)
+
+/datum/antagonist/vassal/remove_innate_effects(mob/living/mob_override)
+ . = ..()
+ var/mob/living/current_mob = mob_override || owner.current
+ current_mob.remove_status_effect(/datum/status_effect/agent_pinpointer/vassal_edition)
+
/datum/antagonist/vassal/on_gain()
/// Enslave them to their Master
@@ -34,8 +42,6 @@
bloodsuckerdatum.vassals |= src
owner.enslave_mind_to_creator(master.owner.current)
owner.current.log_message("has been vassalized by [master.owner.current]!", LOG_ATTACK, color="#960000")
- /// Give Vassal Pinpointer
- owner.current.apply_status_effect(/datum/status_effect/agent_pinpointer/vassal_edition)
/// Give Recuperate Power
BuyPower(new /datum/action/bloodsucker/recuperate)
/// Give Objectives
@@ -49,25 +55,29 @@
. = ..()
/datum/antagonist/vassal/on_removal()
- /// Free them from their Master
+ //Free them from their Master
if(master && master.owner)
master.vassals -= src
owner.enslaved_to = null
- /// Remove Pinpointer
- owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer/vassal_edition)
- /// Remove ALL Traits, as long as its from BLOODSUCKER_TRAIT's source.
for(var/all_status_traits in owner.current.status_traits)
REMOVE_TRAIT(owner.current, all_status_traits, BLOODSUCKER_TRAIT)
- /// Remove Recuperate Power
+ //Remove Recuperate Power
while(powers.len)
var/datum/action/bloodsucker/power = pick(powers)
powers -= power
power.Remove(owner.current)
- /// Remove Language & Hud
+ //Remove Language & Hud
owner.current.remove_language(/datum/language/vampiric)
update_vassal_icons_removed(owner.current)
return ..()
+/datum/antagonist/vassal/on_body_transfer(mob/living/old_body, mob/living/new_body)
+ . = ..()
+ for(var/datum/action/bloodsucker/all_powers as anything in powers)
+ all_powers.Remove(old_body)
+ all_powers.Grant(new_body)
+
+
/datum/antagonist/vassal/proc/add_objective(datum/objective/added_objective)
objectives += added_objective
@@ -104,9 +114,27 @@
to_chat(master, span_danger("You have turned [owner.current] into your Favorite Vassal! They will no longer be deconverted upon Mindshielding!"))
to_chat(owner, span_notice("As Blood drips over your body, you feel closer to your Master... You are now the Favorite Vassal!"))
var/datum/antagonist/bloodsucker/bloodsuckerdatum = master.mind.has_antag_datum(/datum/antagonist/bloodsucker)
- if(bloodsuckerdatum.my_clan == CLAN_GANGREL)
- var/obj/effect/proc_holder/spell/targeted/shapeshift/bat/batform = new
- owner.current.AddSpell(batform)
+ var/mob/living/carbon/human/vassal = owner.current
+ switch(bloodsuckerdatum.my_clan)
+ if(CLAN_GANGREL)
+ var/obj/effect/proc_holder/spell/targeted/shapeshift/bat/batform = new
+ owner.AddSpell(batform)
+ if(CLAN_LASOMBRA)
+ if(ishuman(owner.current))
+ vassal.see_in_dark = 8
+ vassal.eye_color = "f00"
+ var/list/powers = list(new /obj/effect/proc_holder/spell/targeted/lesser_glare, new /obj/effect/proc_holder/spell/targeted/shadowwalk)
+ for(var/obj/effect/proc_holder/spell/targeted/power in powers)
+ owner.AddSpell(power)
+ if(CLAN_TZIMISCE)
+ if(!do_mob(master, owner.current, 1 SECONDS, TRUE))
+ return
+ playsound(vassal.loc, 'sound/weapons/slash.ogg', 50, TRUE, -1)
+ if(!do_mob(master, owner.current, 1 SECONDS, TRUE))
+ return
+ playsound(vassal.loc, 'sound/effects/splat.ogg', 50, TRUE)
+ vassal.set_species(/datum/species/szlachta)
+
/// If we weren't created by a bloodsucker, then we cannot be a vassal (assigned from antag panel)
/datum/antagonist/vassal/can_be_owned(datum/mind/new_owner)
if(!master)
@@ -147,13 +175,13 @@
* Unlike the Monster hunter one, this one is permanently active, and has no power needed to activate it.
*/
-/atom/movable/screen/alert/status_effect/agent_pinpointer/vassal_edition
+/obj/screen/alert/status_effect/agent_pinpointer/vassal_edition
name = "Blood Bond"
desc = "You always know where your master is."
/datum/status_effect/agent_pinpointer/vassal_edition
id = "agent_pinpointer"
- alert_type = /atom/movable/screen/alert/status_effect/agent_pinpointer/vassal_edition
+ alert_type = /obj/screen/alert/status_effect/agent_pinpointer/vassal_edition
minimum_range = VASSAL_SCAN_MIN_DISTANCE
tick_interval = VASSAL_SCAN_PING_TIME
duration = -1
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_effects.dm b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm
index d70eda99a810..4a94ff8456b5 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_effects.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm
@@ -202,8 +202,11 @@
if(!ishuman(user))
return ..()
var/mob/living/carbon/human/human_user = user
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
if(IS_HERETIC(human_user))
- to_chat(human_user,span_boldwarning("You know better than to tempt forces out of your control!"))
+ to_chat(human_user, span_boldwarning("You know better than to tempt forces out of your control!"))
+ if(IS_BLOODSUCKER(human_user) || bloodsuckerdatum.my_clan == CLAN_LASOMBRA)
+ to_chat(human_user, span_boldwarning("This shard has already been harvested!"))
else
var/obj/item/bodypart/arm = human_user.get_active_hand()
if(prob(25))
diff --git a/code/modules/antagonists/monsterhunter/monsterhunter.dm b/code/modules/antagonists/monsterhunter/monsterhunter.dm
index 71ab566efe34..5bc9a6113641 100644
--- a/code/modules/antagonists/monsterhunter/monsterhunter.dm
+++ b/code/modules/antagonists/monsterhunter/monsterhunter.dm
@@ -2,8 +2,6 @@
#define HUNTER_SCAN_MAX_DISTANCE 15
/// 5s update time
#define HUNTER_SCAN_PING_TIME 20
-/// Used for the pinpointer
-#define STATUS_EFFECT_HUNTERPINPOINTER /datum/status_effect/agent_pinpointer/hunter_edition
/datum/antagonist/monsterhunter
name = "\improper Monster Hunter"
@@ -13,55 +11,66 @@
var/list/datum/action/powers = list()
var/datum/martial_art/hunterfu/my_kungfu = new
var/give_objectives = TRUE
- var/datum/action/bloodsucker/trackvamp = new/datum/action/bloodsucker/trackvamp()
- var/datum/action/bloodsucker/fortitude = new/datum/action/bloodsucker/fortitude/hunter()
+ var/datum/action/bloodsucker/trackvamp = new /datum/action/bloodsucker/trackvamp()
+ var/datum/action/bloodsucker/fortitude = new /datum/action/bloodsucker/fortitude/hunter()
-/datum/antagonist/monsterhunter/on_gain()
- /// Buffs Monster Hunters
+/datum/antagonist/monsterhunter/apply_innate_effects(mob/living/mob_override)
+ . = ..()
+ var/mob/living/current_mob = mob_override || owner.current
+ ADD_TRAIT(current_mob, TRAIT_NOSOFTCRIT, BLOODSUCKER_TRAIT)
+ ADD_TRAIT(current_mob, TRAIT_NOCRITDAMAGE, BLOODSUCKER_TRAIT)
owner.unconvertable = TRUE
- ADD_TRAIT(owner.current, TRAIT_NOSOFTCRIT, BLOODSUCKER_TRAIT)
- ADD_TRAIT(owner.current, TRAIT_NOCRITDAMAGE, BLOODSUCKER_TRAIT)
- /// Give Monster Hunter powers
+ my_kungfu.teach(current_mob, make_temporary = FALSE)
+
+/datum/antagonist/monsterhunter/remove_innate_effects(mob/living/mob_override)
+ . = ..()
+ var/mob/living/current_mob = mob_override || owner.current
+ REMOVE_TRAIT(current_mob, TRAIT_NOSOFTCRIT, BLOODSUCKER_TRAIT)
+ REMOVE_TRAIT(current_mob, TRAIT_NOCRITDAMAGE, BLOODSUCKER_TRAIT)
+ owner.unconvertable = FALSE
+ if(my_kungfu)
+ my_kungfu.remove(current_mob)
+
+
+/datum/antagonist/monsterhunter/on_gain()
+ //Give Monster Hunter powers
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_MHUNTER]
trackvamp.Grant(owner.current)
fortitude.Grant(owner.current)
hud.join_hud(owner.current)
set_antag_hud(owner.current, "monsterhunter")
if(give_objectives)
- /// Give Hunter Objective
+ //Give Hunter Objective
var/datum/objective/bloodsucker/monsterhunter/monsterhunter_objective = new
monsterhunter_objective.owner = owner
objectives += monsterhunter_objective
- /// Give Theft Objective
+ //Give Theft Objective
var/datum/objective/steal/steal_objective = new
steal_objective.owner = owner
steal_objective.find_target()
objectives += steal_objective
- /// Give Martial Arts
- my_kungfu.teach(owner.current, 0)
- /// Teach Stake crafting
+ //Teach Stake crafting
owner.teach_crafting_recipe(/datum/crafting_recipe/hardened_stake)
owner.teach_crafting_recipe(/datum/crafting_recipe/silver_stake)
- . = ..()
+ return ..()
/datum/antagonist/monsterhunter/on_removal()
- /// Remove buffs
- owner.unconvertable = FALSE
- /// Remove ALL Traits, as long as its from BLOODSUCKER_TRAIT's source.
- for(var/all_status_traits in owner.current.status_traits)
- REMOVE_TRAIT(owner.current, all_status_traits, BLOODSUCKER_TRAIT)
- /// Remove Monster Hunter powers
+ //Remove Monster Hunter powers
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_MHUNTER]
trackvamp.Remove(owner.current)
fortitude.Remove(owner.current)
hud.leave_hud(owner.current)
set_antag_hud(owner.current, null)
- /// Remove Martial Arts
- if(my_kungfu)
- my_kungfu.remove(owner.current)
to_chat(owner.current, span_userdanger("Your hunt has ended: You enter retirement once again, and are no longer a Monster Hunter."))
return ..()
+
+/datum/antagonist/monsterhunter/on_body_transfer(mob/living/old_body, mob/living/new_body)
+ . = ..()
+ for(var/datum/action/bloodsucker/all_powers as anything in powers)
+ all_powers.Remove(old_body)
+ all_powers.Grant(new_body)
+
/// Mind version
/datum/mind/proc/make_monsterhunter()
@@ -112,13 +121,13 @@
/// TAKEN FROM: /datum/action/changeling/pheromone_receptors // pheromone_receptors.dm for a version of tracking that Changelings have!
/datum/status_effect/agent_pinpointer/hunter_edition
- alert_type = /atom/movable/screen/alert/status_effect/agent_pinpointer/hunter_edition
+ alert_type = /obj/screen/alert/status_effect/agent_pinpointer/hunter_edition
minimum_range = HUNTER_SCAN_MIN_DISTANCE
tick_interval = HUNTER_SCAN_PING_TIME
duration = 10 SECONDS
range_fuzz_factor = 5 //PINPOINTER_EXTRA_RANDOM_RANGE
-/atom/movable/screen/alert/status_effect/agent_pinpointer/hunter_edition
+/obj/screen/alert/status_effect/agent_pinpointer/hunter_edition
name = "Monster Tracking"
desc = "You always know where the hellspawn are."
@@ -126,22 +135,16 @@
var/turf/my_loc = get_turf(owner)
var/list/mob/living/carbon/monsters = list()
- for(var/mob/living/carbon/all_carbons in GLOB.alive_mob_list)
- if(all_carbons != owner && all_carbons.mind)
- var/datum/mind/carbon_minds = all_carbons.mind
- if(IS_HERETIC(all_carbons) || IS_BLOODSUCKER(all_carbons) || iscultist(all_carbons) || is_servant_of_ratvar(all_carbons) || is_wizard(all_carbons))
- monsters += carbon_minds
- if(carbon_minds.has_antag_datum(/datum/antagonist/changeling))
- monsters += carbon_minds
- if(carbon_minds.has_antag_datum(/datum/antagonist/ashwalker))
- monsters += carbon_minds
- if(carbon_minds.has_antag_datum(/datum/antagonist/wizard/apprentice))
- monsters += carbon_minds
- if(istype(monsters))
- var/their_loc = get_turf(all_carbons)
- var/distance = get_dist_euclidian(my_loc, their_loc)
- if(distance < HUNTER_SCAN_MAX_DISTANCE)
- monsters[all_carbons] = (HUNTER_SCAN_MAX_DISTANCE ** 2) - (distance ** 2)
+ for(var/datum/antagonist/monster in GLOB.antagonists)
+ var/datum/mind/brain = monster.owner
+ if(brain == owner || !brain)
+ continue
+ if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || is_servant_of_ratvar(brain.current) || is_wizard(brain.current))
+ monsters += brain
+ if(brain.has_antag_datum(/datum/antagonist/changeling))
+ monsters += brain
+ if(brain.has_antag_datum(/datum/antagonist/ashwalker))
+ monsters += brain
if(monsters.len)
/// Point at a 'random' monster, biasing heavily towards closer ones.
diff --git a/code/modules/antagonists/monsterhunter/monstertrack.dm b/code/modules/antagonists/monsterhunter/monstertrack.dm
index 68906a260aa6..8fe48ab29bc9 100644
--- a/code/modules/antagonists/monsterhunter/monstertrack.dm
+++ b/code/modules/antagonists/monsterhunter/monstertrack.dm
@@ -18,11 +18,11 @@
. = ..()
/// Return text indicating direction
to_chat(owner, span_notice("You look around, scanning your environment and discerning signs of any filthy, wretched affronts to the natural order."))
- if(!do_after(owner, 6 SECONDS, src))
+ if(!do_after(owner, 6 SECONDS, owner))
return
if(give_pinpointer)
var/mob/living/user = owner
- user.apply_status_effect(STATUS_EFFECT_HUNTERPINPOINTER)
+ user.apply_status_effect(/datum/status_effect/agent_pinpointer/hunter_edition)
display_proximity()
/datum/action/bloodsucker/trackvamp/proc/display_proximity()
diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm
index ab8a8ad56890..a99c4aa11767 100644
--- a/code/modules/clothing/neck/_neck.dm
+++ b/code/modules/clothing/neck/_neck.dm
@@ -75,9 +75,9 @@
if(!(M.stat == DEAD || (HAS_TRAIT(M, TRAIT_FAKEDEATH))))
if(heart && istype(heart))
- heart_strength = span_danger("an unstable")
+ heart_strength = heart.HeartStrengthMessage()
if(heart.beating)
- heart_strength = "a healthy"
+ heart_strength = heart.HeartStrengthMessage()
if(lungs && istype(lungs))
lung_strength = span_danger("strained")
if(!(M.failed_last_breath || M.losebreath))
diff --git a/code/modules/events/monsterhunter.dm b/code/modules/events/monsterhunter.dm
index f5bb32146f5f..5089974fb140 100644
--- a/code/modules/events/monsterhunter.dm
+++ b/code/modules/events/monsterhunter.dm
@@ -17,7 +17,6 @@
weight = 2000
min_players = 10
earliest_start = 35 MINUTES
- alert_observers = FALSE
gamemode_whitelist = list("bloodsucker","traitorsucker","dynamic")
/datum/round_event/bloodsucker_hunters
@@ -36,6 +35,8 @@
for(var/mob/living/carbon/human/all_players in shuffle(GLOB.player_list))
if(!all_players.client || !all_players.mind || !(ROLE_MONSTERHUNTER in all_players.client.prefs.be_special))
continue
+ if(all_players.client.prefs.yogtoggles & QUIET_ROUND)
+ continue
if(all_players.stat == DEAD)
continue
if(!SSjob.GetJob(all_players.mind.assigned_role) || (all_players.mind.assigned_role in GLOB.nonhuman_positions)) // Only crewmembers on-station.
@@ -61,7 +62,6 @@
weight = 7
min_players = 10
earliest_start = 25 MINUTES
- alert_observers = TRUE
gamemode_whitelist = list("traitorchan","changeling","heresy","cult","clockwork_cult","dynamic")
/datum/round_event/monster_hunters
diff --git a/code/modules/events/tzimisce.dm b/code/modules/events/tzimisce.dm
new file mode 100644
index 000000000000..76fca9507cd7
--- /dev/null
+++ b/code/modules/events/tzimisce.dm
@@ -0,0 +1,90 @@
+/datum/round_event_control/tzimisce/bloodsucker
+ name = "Spawn Tzimisce - Bloodsucker"
+ max_occurrences = 1
+ weight = 5
+ typepath = /datum/round_event/ghost_role/tzimisce/bloodsucker
+ min_players = 25
+ earliest_start = 30 MINUTES
+ gamemode_whitelist = list("bloodsucker","traitorsucker","dynamic")
+
+/datum/round_event/ghost_role/tzimisce/bloodsucker
+ fakeable = FALSE
+ var/cancel_me = TRUE
+
+/datum/round_event/ghost_role/tzimisce/bloodsucker/start()
+ for(var/mob/living/carbon/human/all_players in GLOB.player_list)
+ if(IS_BLOODSUCKER(all_players) || IS_MONSTERHUNTER(all_players))
+ message_admins("BLOODSUCKER NOTICE: Tzimisces have found a valid Target.")
+ cancel_me = FALSE
+ break
+ if(cancel_me)
+ kill()
+ return
+
+/datum/round_event_control/tzimisce
+ name = "Spawn Tzimisce"
+ typepath = /datum/round_event/ghost_role/tzimisce
+ max_occurrences = 1
+ min_players = 15
+ earliest_start = 45 MINUTES
+
+/datum/round_event/ghost_role/tzimisce
+ var/success_spawn = 0
+ minimum_required = 1
+ role_name = "Tzimisce"
+ fakeable = FALSE
+
+/datum/round_event/ghost_role/tzimisce/kill()
+ if(!success_spawn && control)
+ control.occurrences--
+ return ..()
+
+/datum/round_event/ghost_role/tzimisce/spawn_role()
+ //selecting a spawn_loc
+ if(!SSjob.latejoin_trackers.len)
+ return MAP_ERROR
+
+ //selecting a candidate player
+ var/list/candidates = get_candidates(ROLE_BLOODSUCKER, null, ROLE_BLOODSUCKER)
+ if(!candidates.len)
+ return NOT_ENOUGH_PLAYERS
+
+ var/mob/dead/selected_candidate = pick_n_take(candidates)
+ var/key = selected_candidate.key
+
+ var/datum/mind/Mind = create_tzimisce_mind(key)
+ Mind.active = TRUE
+
+ var/mob/living/carbon/human/tzimisce = spawn_event_tzimisce()
+ Mind.transfer_to(tzimisce)
+ Mind.add_antag_datum(/datum/antagonist/bloodsucker)
+ var/datum/antagonist/bloodsucker/bloodsuckerdatum = tzimisce.mind.has_antag_datum(/datum/antagonist/bloodsucker)
+ bloodsuckerdatum.bloodsucker_level_unspent += round(world.time / (15 MINUTES), 1)
+ bloodsuckerdatum.AssignClanAndBane(tzimisce = TRUE)
+
+ spawned_mobs += tzimisce
+ message_admins("[ADMIN_LOOKUPFLW(tzimisce)] has been made into a tzimisce bloodsucker an event.")
+ log_game("[key_name(tzimisce)] was spawned as a tzimisce bloodsucker by an event.")
+ var/datum/job/jobdatum = SSjob.GetJob(pick("Assistant", "Botanist", "Station Engineer", "Medical Doctor", "Scientist", "Cargo Technician", "Cook"))
+ set_antag_hud(tzimisce, "tzimisce")
+ tzimisce.job = jobdatum
+ tzimisce.update_internals_hud_icon(TRUE)
+ jobdatum.equip(tzimisce)
+ tzimisce.update_move_intent_slowdown() //prevents you from going super duper fast
+ return SUCCESSFUL_SPAWN
+
+
+/proc/spawn_event_tzimisce(spawn_loc)
+ var/mob/living/carbon/human/new_tzimisce = new(spawn_loc)
+ if(!spawn_loc)
+ SSjob.SendToLateJoin(new_tzimisce)
+ var/datum/preferences/A = new() //Randomize appearance.
+ A.copy_to(new_tzimisce)
+ new_tzimisce.dna.update_dna_identity()
+ return new_tzimisce
+
+/proc/create_tzimisce_mind(key)
+ var/datum/mind/Mind = new /datum/mind(key)
+ Mind.assigned_role = ROLE_BLOODSUCKER
+ Mind.special_role = ROLE_BLOODSUCKER
+ return Mind
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index e10fd12c1ca0..2d30c1107d6c 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -27,6 +27,10 @@
if(NOBLOOD in dna.species.species_traits || bleedsuppress || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
return
+
+ if(mind && IS_BLOODSUCKER(src)) // Prevents Bloodsuckers from naturally regenerating Blood - Even while on masquerade
+ return
+
if(HAS_TRAIT(src, TRAIT_NOPULSE)) // Fulpstation Bloodsuckers edit - Dont regenerate blood, damnmit!
return
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index d50d0b015d39..324beccad878 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -90,7 +90,7 @@
if(!(SLOT_GLASSES in obscured))
if(glasses)
. += "[t_He] [t_has] [glasses.get_examine_string(user)] covering [t_his] eyes."
- else if(eye_color == BLOODCULT_EYE && iscultist(src) && HAS_TRAIT(src, CULT_EYES))
+ else if(eye_color == BLOODCULT_EYE && HAS_TRAIT(src, CULT_EYES))
. += span_warning("[t_His] eyes are glowing an unnatural red!")
//ears
@@ -512,7 +512,7 @@
if(!(SLOT_GLASSES in obscured))
if(glasses)
. += "[t_He] [t_has] [glasses.get_examine_string(user)] covering [t_his] eyes."
- else if(eye_color == BLOODCULT_EYE && iscultist(src) && HAS_TRAIT(src, CULT_EYES))
+ else if(eye_color == BLOODCULT_EYE && HAS_TRAIT(src, CULT_EYES))
. += span_warning("[t_His] eyes are glowing an unnatural red!")
//ears
diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm
index 7498c510ecc6..7767872265e4 100644
--- a/code/modules/surgery/bodyparts/_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/_bodyparts.dm
@@ -715,6 +715,10 @@
no_update = FALSE
if(HAS_TRAIT(C, TRAIT_HUSK) && is_organic_limb())
+ if(ishuman(C))
+ var/mob/living/carbon/human/S = C
+ if(isszlachta(S))
+ return
species_id = "husk" //overrides species_id
dmg_overlay_type = "" //no damage overlay shown when husked
should_draw_gender = FALSE
diff --git a/config/game_options.txt b/config/game_options.txt
index 3d1817a2ef79..10d857d15c1a 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -107,11 +107,13 @@ ALERT_DELTA Destruction of the station is imminent. All crew are instructed to o
PROBABILITY DARKSPAWN 6
PROBABILITY HERESY 4
PROBABILITY INFILTRATION 4
+PROBABILITY BLOODSUCKER 4
# Lowpop
PROBABILITY TRAITOR 5
PROBABILITY TRAITORBRO 5
PROBABILITY TRAITORCHAN 6
+PROBABILITY TRAITORSUCKER 3
PROBABILITY TRAITORVAMP 4
PROBABILITY INTERNAL_AFFAIRS 3
PROBABILITY CHANGELING 4
diff --git a/icons/mob/actions/actions_bloodsucker.dmi b/icons/mob/actions/actions_bloodsucker.dmi
index 901589214ea2..ac96186a200c 100644
Binary files a/icons/mob/actions/actions_bloodsucker.dmi and b/icons/mob/actions/actions_bloodsucker.dmi differ
diff --git a/icons/mob/actions/actions_gangrel_bloodsucker.dmi b/icons/mob/actions/actions_gangrel_bloodsucker.dmi
index aef8d3b6f05f..30b9532502d8 100644
Binary files a/icons/mob/actions/actions_gangrel_bloodsucker.dmi and b/icons/mob/actions/actions_gangrel_bloodsucker.dmi differ
diff --git a/icons/mob/actions/actions_lasombra_bloodsucker.dmi b/icons/mob/actions/actions_lasombra_bloodsucker.dmi
index 95b93602f039..bc6c89bb0dfe 100644
Binary files a/icons/mob/actions/actions_lasombra_bloodsucker.dmi and b/icons/mob/actions/actions_lasombra_bloodsucker.dmi differ
diff --git a/icons/mob/actions/actions_tzimisce_bloodsucker.dmi b/icons/mob/actions/actions_tzimisce_bloodsucker.dmi
new file mode 100644
index 000000000000..e7f504f9baad
Binary files /dev/null and b/icons/mob/actions/actions_tzimisce_bloodsucker.dmi differ
diff --git a/icons/mob/bloodsucker_mobs.dmi b/icons/mob/bloodsucker_mobs.dmi
index ac3de343fd91..20276e91d0cb 100644
Binary files a/icons/mob/bloodsucker_mobs.dmi and b/icons/mob/bloodsucker_mobs.dmi differ
diff --git a/icons/obj/vamp_obj.dmi b/icons/obj/vamp_obj.dmi
index 647a984e22c8..7818e30ed392 100644
Binary files a/icons/obj/vamp_obj.dmi and b/icons/obj/vamp_obj.dmi differ
diff --git a/yogstation.dme b/yogstation.dme
index 4275dbf6124a..3000ba118a1c 100644
--- a/yogstation.dme
+++ b/yogstation.dme
@@ -1403,6 +1403,7 @@
#include "code\modules\antagonists\bloodsuckers\bloodsucker_flaws.dm"
#include "code\modules\antagonists\bloodsuckers\bloodsucker_frenzy.dm"
#include "code\modules\antagonists\bloodsuckers\bloodsucker_integration.dm"
+#include "code\modules\antagonists\bloodsuckers\bloodsucker_mobs.dm"
#include "code\modules\antagonists\bloodsuckers\bloodsucker_objectives.dm"
#include "code\modules\antagonists\bloodsuckers\bloodsuckers.dm"
#include "code\modules\antagonists\bloodsuckers\bloodsuckers_objects.dm"
@@ -1423,6 +1424,7 @@
#include "code\modules\antagonists\bloodsuckers\powers\targeted\lunge.dm"
#include "code\modules\antagonists\bloodsuckers\powers\targeted\mesmerize.dm"
#include "code\modules\antagonists\bloodsuckers\powers\targeted\trespass.dm"
+#include "code\modules\antagonists\bloodsuckers\powers\targeted\tzimisce.dm"
#include "code\modules\antagonists\bloodsuckers\structures\bloodsucker_coffin.dm"
#include "code\modules\antagonists\bloodsuckers\structures\bloodsucker_crypt.dm"
#include "code\modules\antagonists\bloodsuckers\structures\bloodsucker_life.dm"
@@ -1933,6 +1935,7 @@
#include "code\modules\events\stray_cargo.dm"
#include "code\modules\events\supermatter_surge.dm"
#include "code\modules\events\swarmer.dm"
+#include "code\modules\events\tzimisce.dm"
#include "code\modules\events\vent_clog.dm"
#include "code\modules\events\wormholes.dm"
#include "code\modules\events\zombie_infection.dm"
@@ -3680,6 +3683,7 @@
#include "yogstation\code\modules\mob\living\carbon\human\species_types\jellypeople.dm"
#include "yogstation\code\modules\mob\living\carbon\human\species_types\lizard.dm"
#include "yogstation\code\modules\mob\living\carbon\human\species_types\plantpeople.dm"
+#include "yogstation\code\modules\mob\living\carbon\human\species_types\szlachta.dm"
#include "yogstation\code\modules\mob\living\carbon\human\species_types\preternis\organs.dm"
#include "yogstation\code\modules\mob\living\carbon\human\species_types\preternis\power_suck.dm"
#include "yogstation\code\modules\mob\living\carbon\human\species_types\preternis\preternis.dm"
diff --git a/yogstation/code/modules/mob/living/carbon/human/species_types/szlachta.dm b/yogstation/code/modules/mob/living/carbon/human/species_types/szlachta.dm
new file mode 100644
index 000000000000..ded78feaf206
--- /dev/null
+++ b/yogstation/code/modules/mob/living/carbon/human/species_types/szlachta.dm
@@ -0,0 +1,26 @@
+/datum/species/szlachta
+ name = "Szlachta"
+ id = "szlachta"
+ limbs_id = "szlachta"
+ sexes = FALSE
+ nojumpsuit = TRUE
+ changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN
+ siemens_coeff = 0
+ brutemod = 0.8
+ heatmod = 0.8
+ punchdamagehigh = 17 //hardcore
+ punchstunthreshold = 17
+ no_equip = list(SLOT_WEAR_MASK, SLOT_WEAR_SUIT, SLOT_GLOVES, SLOT_SHOES, SLOT_W_UNIFORM, SLOT_S_STORE, SLOT_HEAD)
+ species_traits = list(NO_UNDERWEAR,NO_DNA_COPY,NOTRANSSTING,NOEYESPRITES,NOFLASH)
+ inherent_traits = list(TRAIT_NOGUNS, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,
+ TRAIT_NOBREATH, TRAIT_RADIMMUNE, TRAIT_VIRUSIMMUNE, TRAIT_PIERCEIMMUNE, TRAIT_NODISMEMBER,
+ TRAIT_MONKEYLIKE, TRAIT_NOCRITDAMAGE, TRAIT_GENELESS, TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_HARDLY_WOUNDED, TRAIT_HUSK)
+ mutanteyes = /obj/item/organ/eyes/night_vision/alien
+
+/datum/species/szlachta/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ . = ..()
+ C.real_name = "towering monstrocity"
+ C.name = C.real_name
+ if(C.mind)
+ C.mind.name = C.real_name
+ C.dna.real_name = C.real_name
diff --git a/yogstation/icons/mob/hud.dmi b/yogstation/icons/mob/hud.dmi
index 3ff39cf9fdb4..a800423a878b 100644
Binary files a/yogstation/icons/mob/hud.dmi and b/yogstation/icons/mob/hud.dmi differ
diff --git a/yogstation/icons/mob/human_parts.dmi b/yogstation/icons/mob/human_parts.dmi
index cabcc54f678f..757ba9aa420d 100644
Binary files a/yogstation/icons/mob/human_parts.dmi and b/yogstation/icons/mob/human_parts.dmi differ