[Ready][Until ANOTHER FUCKIMNG MERGE CREATES CONFLICTS GOD FUCK] Reflavors a lot of Bloodsucker stuff to be more in line with it's source (#2104)

## About The Pull Request

Title.

## Why It's Good For The Game

My love of VTM cannot stand things such as 'blah-sucker', 'vassels' or
'archive of the kindred'.

The Blah-Sucker language has been renamed to Enochian, reflecting the
First City of Vampires, Enoch, in the land of Nod east of Eden where the
Dark Father Caine was exiled from.

(Front facing) mentions of vassels have been replaced with the accurate
Ghoul. They drink vitae to establish a bond with their master, not
blood, vampires do not produce blood, they drink vitae.

The Archive of the Kindred has been replaced with the Book of Nod. Well,
a version of it. Cainites are protective of the hidden knowledge kept
within and would be unhappy with the mortals (you) having a copy.

Objectives have been re-written to mention lore aspects.

## Proof Of Testing

🆑
spellcheck: Various Bloodsucker things have been renamed after the
Inconnu paid a visit.
/🆑

---------

Co-authored-by: Waterpig <wtryoutube@seznam.cz>
Co-authored-by: Waterpig <49160555+Majkl-J@users.noreply.github.com>
This commit is contained in:
Cursor
2024-10-10 14:05:24 -06:00
committed by GitHub
co-authored by Waterpig Waterpig
parent c70539e462
commit 0077be5e32
52 changed files with 685 additions and 667 deletions
+1 -1
View File
@@ -142,7 +142,7 @@
#define ROLE_VAMPIRICACCIDENT "Bloodsucker (Midround)"
#define ROLE_BLOODSUCKERBREAKOUT "Bloodsucker (Latejoin)"
#define ROLE_MONSTERHUNTER "Monster Hunter"
#define ROLE_VASSAL "Vassal"
#define ROLE_VASSAL "Ghoul"
#define ROLE_CHANGELING_ZOMBIE "Changeling Zombie"
//BUBBER EDIT END
@@ -1,4 +1,4 @@
///Uncomment this to enable testing of Bloodsucker features (such as vassalizing people with a mind instead of a client).
///Uncomment this to enable testing of Bloodsucker features (such as ghoulizing people with a mind instead of a client).
// #define BLOODSUCKER_TESTING // if this isn't commented out, someone is a dumbfuck
/// You have special interactions with Bloodsuckers
@@ -18,8 +18,8 @@
#define TORTURE_BLOOD_HALF_COST 4
/// Cost to convert someone after successful torture, in blood
#define TORTURE_CONVERSION_COST 10
/// How much blood it costs you to make a vassal into a special vassal
#define SPECIAL_VASSAL_COST 150
/// How much blood it costs you to make a ghoul into a special ghoul
#define SPECIAL_GHOUL_COST 150
/// Minimum and maximum frenzy blood thresholds
/// Once blood is this low, will enter Frenzy
#define FRENZY_THRESHOLD_ENTER 25
@@ -57,14 +57,14 @@
#define TIME_BLOODSUCKER_SOL_DELAY 90
/**
* Vassal defines
* Ghoul defines
*/
///If someone passes all checks and can be vassalized
#define VASSALIZATION_ALLOWED 0
///If someone has to accept vassalization
#define VASSALIZATION_DISLOYAL 1
///If someone is not allowed under any circimstances to become a Vassal
#define VASSALIZATION_BANNED 2
///If someone passes all checks and can be ghoulized
#define GHOULIZATION_ALLOWED 0
///If someone has to accept ghoulization
#define GHOULIZATION_DISLOYAL 1
///If someone is not allowed under any circimstances to become a Ghoul
#define GHOULIZATION_BANNED 2
/**
* Cooldown defines
@@ -92,9 +92,9 @@
#define CLAN_MALKAVIAN "Malkavian Clan"
#define CLAN_TZIMISCE "Tzimisce Clan"
#define TREMERE_VASSAL "tremere_vassal"
#define FAVORITE_VASSAL "favorite_vassal"
#define REVENGE_VASSAL "revenge_vassal"
#define TREMERE_GHOUL "tremere_ghoul"
#define FAVORITE_GHOUL "favorite_ghoul"
#define REVENGE_GHOUL "revenge_ghoul"
/**
* Power defines
@@ -116,11 +116,14 @@
#define BLOODSUCKER_DEFAULT_POWER (1<<1)
/// This Power can be purchased by Tremere Bloodsuckers
#define TREMERE_CAN_BUY (1<<2)
/// This Power can be purchased by Vassals
#define VASSAL_CAN_BUY (1<<3)
/// This Power can be purchased by Ghouls
#define GHOUL_CAN_BUY (1<<3)
/// If this Power can be bought if you already own it
#define CAN_BUY_OWNED (1<<4)
/// This Power is a Continuous Effect, processing every tick
#define BP_CONTINUOUS_EFFECT (1<<0)
/// This Power is a Single-Use Power
@@ -134,7 +137,7 @@
#define DEACTIVATE_POWER_NO_COOLDOWN (1<<1)
// ability levels that are used cross-file
#define DOMINATE_VASSALIZE_LEVEL 2
#define DOMINATE_GHOULIZE_LEVEL 2
#define TREMERE_OBJECTIVE_POWER_LEVEL 4
#define COFFIN_HEAL_COST_MULT 0.5
@@ -152,14 +155,14 @@
*/
///Called when a Bloodsucker ranks up: (datum/bloodsucker_datum, mob/owner, mob/target)
#define COMSIG_BLOODSUCKER_RANK_UP "bloodsucker_rank_up"
///Called when a Bloodsucker interacts with a Vassal on their persuasion rack.
#define COMSIG_BLOODSUCKER_INTERACT_WITH_VASSAL "bloodsucker_interact_with_vassal"
///Called when a Bloodsucker makes a Vassal into their Favorite Vassal: (datum/vassal_datum, mob/master)
///Called when a Bloodsucker interacts with a Ghoul on their persuasion rack.
#define COMSIG_BLOODSUCKER_INTERACT_WITH_GHOUL "bloodsucker_interact_with_ghoul"
///Called when a Bloodsucker makes a Ghoul into their Favorite Ghoul: (datum/ghoul_datum, mob/master)
#define COMSIG_BLOODSUCKER_MAKE_FAVORITE "bloodsucker_make_favorite"
// called when a bloodsucker looses their favorite vassal, cleaning up whatever they gained
// called when a bloodsucker looses their favorite ghoul, cleaning up whatever they gained
#define COMSIG_BLOODSUCKER_LOOSE_FAVORITE "bloodsucker_loose_favorite"
///Called when a new Vassal is successfully made: (datum/bloodsucker_datum)
#define COMSIG_BLOODSUCKER_MADE_VASSAL "bloodsucker_made_vassal"
///Called when a new Ghoul is successfully made: (datum/bloodsucker_datum)
#define COMSIG_BLOODSUCKER_MADE_GHOUL "bloodsucker_made_ghoul"
///Called when a Bloodsucker exits Torpor.
#define COMSIG_BLOODSUCKER_EXIT_TORPOR "bloodsucker_exit_torpor"
///Called when a Bloodsucker reaches Final Death.
@@ -188,7 +191,7 @@
#define COMSIG_SOL_RISE_TICK "comsig_sol_rise_tick"
#define COMSIG_SOL_NEAR_START "comsig_sol_near_start"
#define COMSIG_SOL_END "comsig_sol_end"
///Sent when a warning for Sol is meant to go out: (danger_level, vampire_warning_message, vassal_warning_message)
///Sent when a warning for Sol is meant to go out: (danger_level, vampire_warning_message, ghoul_warning_message)
#define COMSIG_SOL_WARNING_GIVEN "comsig_sol_warning_given"
///Called on a Bloodsucker's Lifetick.
#define COMSIG_BLOODSUCKER_ON_LIFETICK "comsig_bloodsucker_on_lifetick"
@@ -228,7 +231,7 @@
/// Source trait for Bloodsuckers-related traits
#define BLOODSUCKER_TRAIT "bloodsucker_trait"
#define VASSAL_TRAIT "vassal_trait"
#define GHOUL_TRAIT "ghoul_trait"
/// Source trait for dominate related traits
#define MESMERIZE_TRAIT "meserize_trait"
@@ -243,13 +246,13 @@
///Whether a mob is a Bloodsucker
#define IS_BLOODSUCKER(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/bloodsucker))
///Whether a mob is a Vassal
#define IS_VASSAL(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/vassal))
///Whether a mob is a Favorite Vassal
#define IS_FAVORITE_VASSAL(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/vassal/favorite))
///Whether a mob is a Revenge Vassal
#define IS_REVENGE_VASSAL(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/vassal/revenge))
#define IS_EX_VASSAL(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/ex_vassal))
///Whether a mob is a Ghoul
#define IS_GHOUL(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/ghoul))
///Whether a mob is a Favorite Ghoul
#define IS_FAVORITE_GHOUL(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/ghoul/favorite))
///Whether a mob is a Revenge Ghoul
#define IS_REVENGE_GHOUL(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/ghoul/revenge))
#define IS_EX_GHOUL(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/ex_ghoul))
///Whether a mob is a Monster Hunter-NOT NEEDED RIGHT NOW
// #define IS_MONSTERHUNTER(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/monsterhunter))
@@ -257,7 +260,7 @@
#define IS_MONSTERHUNTER(mob) (FALSE)
#define BLOODSUCKER_SIGHT_COLOR_CUTOFF list(25, 8, 5)
#define POLL_IGNORE_VASSAL "vassal"
#define POLL_IGNORE_GHOUL "ghoul"
// Why waste memory on a dynamic global list if we can just bake it in on compile time?
#define BLOODSUCKER_PROTECTED_ROLES list( \
@@ -34,7 +34,7 @@ PROCESSING_SUBSYSTEM_DEF(sunlight)
warn_daylight(
danger_level = DANGER_LEVEL_SOL_ENDED,
vampire_warning_message = span_announce("The solar flare has ended, and the daylight danger has passed... for now."),
vassal_warning_message = span_announce("The solar flare has ended, and the daylight danger has passed... for now."),
ghoul_warning_message = span_announce("The solar flare has ended, and the daylight danger has passed... for now."),
)
return ..()
@@ -50,7 +50,7 @@ PROCESSING_SUBSYSTEM_DEF(sunlight)
warn_daylight(
danger_level = DANGER_LEVEL_SECOND_WARNING,
vampire_warning_message = span_userdanger("Solar Flares are about to bombard the station! You have [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds to find cover!"),
vassal_warning_message = span_danger("In [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds, your master will be at risk of a Solar Flare. Make sure they find cover!"),
ghoul_warning_message = span_danger("In [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds, your master will be at risk of a Solar Flare. Make sure they find cover!"),
)
if(TIME_BLOODSUCKER_BURN_INTERVAL)
warn_daylight(
@@ -65,12 +65,12 @@ PROCESSING_SUBSYSTEM_DEF(sunlight)
warn_daylight(
danger_level = DANGER_LEVEL_SOL_ROSE,
vampire_warning_message = 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!"),
vassal_warning_message = span_userdanger("Solar flares bombard the station with UV light!"),
ghoul_warning_message = span_userdanger("Solar flares bombard the station with UV light!"),
)
..()
/datum/controller/subsystem/processing/sunlight/proc/warn_daylight(danger_level, vampire_warning_message, vassal_warning_message)
SEND_SIGNAL(src, COMSIG_SOL_WARNING_GIVEN, danger_level, vampire_warning_message, vassal_warning_message)
/datum/controller/subsystem/processing/sunlight/proc/warn_daylight(danger_level, vampire_warning_message, ghoul_warning_message)
SEND_SIGNAL(src, COMSIG_SOL_WARNING_GIVEN, danger_level, vampire_warning_message, ghoul_warning_message)
/datum/controller/subsystem/processing/sunlight/proc/add_sun_sufferer(mob/victim)
if(is_sufferer(victim))
@@ -44,9 +44,9 @@
time = 10 SECONDS
category = CAT_FURNITURE
/datum/crafting_recipe/vassalrack
/datum/crafting_recipe/ghoulrack
name = "Persuasion Rack"
result = /obj/structure/bloodsucker/vassalrack
result = /obj/structure/bloodsucker/ghoulrack
tool_behaviors = list(TOOL_WELDER, TOOL_WRENCH)
reqs = list(
/obj/item/stack/sheet/mineral/wood = 3,
@@ -46,7 +46,7 @@
mood_change = -6
timeout = 6 MINUTES
///Candelabrum's mood event to non Bloodsucker/Vassals
///Candelabrum's mood event to non Bloodsucker/Ghouls
/datum/mood_event/vampcandle
description = "<span class='boldwarning'>Something is making your mind feel... loose.</span>\n"
mood_change = -15
@@ -48,10 +48,10 @@
///ALL Powers currently owned
var/list/datum/action/cooldown/bloodsucker/powers = list()
///Vassals under my control. Periodically remove the dead ones.
var/list/datum/antagonist/vassal/vassals = list()
///Special vassals I own, to not have double of the same type.
var/list/datum/antagonist/vassal/special_vassals = list()
///Ghouls under my control. Periodically remove the dead ones.
var/list/datum/antagonist/ghoul/ghouls = list()
///Special ghouls I own, to not have double of the same type.
var/list/datum/antagonist/ghoul/special_ghouls = list()
///How many ranks we have, don't modify this directly, use AdjustRank() and use GetRank() to get the current value.
VAR_PRIVATE/bloodsucker_level = 0
@@ -62,7 +62,7 @@
var/bloodsucker_regen_rate = 0.3
// Used for Bloodsucker Objectives
var/area/bloodsucker_lair_area
var/area/bloodsucker_haven_area
var/obj/structure/closet/crate/coffin
var/total_blood_drank = 0
@@ -78,8 +78,8 @@
/// Static typecache of all bloodsucker powers.
var/static/list/all_bloodsucker_powers = typecacheof(/datum/action/cooldown/bloodsucker, ignore_root_path = TRUE)
/// Antagonists that cannot be Vassalized no matter what
var/static/list/vassal_banned_antags = list(
/// Antagonists that cannot be Ghoulized no matter what
var/static/list/ghoul_banned_antags = list(
/datum/antagonist/bloodsucker,
// /datum/antagonist/monsterhunter,
/datum/antagonist/changeling,
@@ -137,7 +137,7 @@
#ifdef BLOODSUCKER_TESTING
var/turf/user_loc = get_turf(current_mob)
new /obj/structure/closet/crate/coffin(user_loc)
new /obj/structure/bloodsucker/vassalrack(user_loc)
new /obj/structure/bloodsucker/ghoulrack(user_loc)
#endif
/**
@@ -237,7 +237,7 @@
/// Called by the remove_antag_datum() and remove_all_antag_datums() mind procs for the antag datum to handle its own removal and deletion.
/datum/antagonist/bloodsucker/on_removal()
free_all_vassals()
free_all_ghouls()
if(!owner?.current)
return
unregister_sol_signals()
@@ -387,22 +387,22 @@
objectives_complete = FALSE
break
// Now list their vassals
if(vassals.len)
report += "<span class='header'>Their Vassals were...</span>"
for(var/datum/antagonist/vassal/all_vassals as anything in vassals)
if(!all_vassals.owner)
// Now list their ghouls
if(ghouls.len)
report += "<span class='header'>Their Ghouls were...</span>"
for(var/datum/antagonist/ghoul/all_ghouls as anything in ghouls)
if(!all_ghouls.owner)
continue
var/list/vassal_report = list()
vassal_report += "<b>[all_vassals.owner.name]</b>"
var/list/ghoul_report = list()
ghoul_report += "<b>[all_ghouls.owner.name]</b>"
if(all_vassals.owner.assigned_role)
vassal_report += " the [all_vassals.owner.assigned_role.title]"
if(IS_FAVORITE_VASSAL(all_vassals.owner.current))
vassal_report += " and was the <b>Favorite Vassal</b>"
else if(IS_REVENGE_VASSAL(all_vassals.owner.current))
vassal_report += " and was the <b>Revenge Vassal</b>"
report += vassal_report.Join()
if(all_ghouls.owner.assigned_role)
ghoul_report += " the [all_ghouls.owner.assigned_role.title]"
if(IS_FAVORITE_GHOUL(all_ghouls.owner.current))
ghoul_report += " and was the <b>Favorite Ghoul</b>"
else if(IS_REVENGE_GHOUL(all_ghouls.owner.current))
ghoul_report += " and was the <b>Revenge Ghoul</b>"
report += ghoul_report.Join()
if(objectives.len == 0 || objectives_complete)
report += "<span class='greentext big'>The [name] was successful!</span>"
@@ -522,16 +522,16 @@
return TRUE
/datum/antagonist/bloodsucker/proc/forge_bloodsucker_objectives()
// Claim a Lair Objective
var/datum/objective/bloodsucker/lair/lair_objective = new
lair_objective.owner = owner
objectives += lair_objective
// Claim a haven Objective
var/datum/objective/bloodsucker/haven/haven_objective = new
haven_objective.owner = owner
objectives += haven_objective
// Survive Objective
var/datum/objective/survive/bloodsucker/survive_objective = new
survive_objective.owner = owner
objectives += survive_objective
// Objective 1: Vassalize a Head/Command, or a specific target
// Objective 1: Ghoulize a Head/Command, or a specific target
switch(rand(1, 3))
if(1) // Conversion Objective
var/datum/objective/bloodsucker/conversion/chosen_subtype = pick(subtypesof(/datum/objective/bloodsucker/conversion))
@@ -1,37 +1,37 @@
/**
* Checks if the target has antag datums and, if so,
* are they allowed to be Vassalized, or not, or banned.
* are they allowed to be Ghoulized, or not, or banned.
* Args:
* target - The person we check for antag datums.
*/
/datum/antagonist/bloodsucker/proc/AmValidAntag(mob/target)
if(HAS_TRAIT(target, TRAIT_UNCONVERTABLE))
return VASSALIZATION_BANNED
return GHOULIZATION_BANNED
var/vassalization_status = VASSALIZATION_ALLOWED
var/ghoulization_status = GHOULIZATION_ALLOWED
for(var/datum/antagonist/antag_datum as anything in target.mind.antag_datums)
if(antag_datum.type in vassal_banned_antags)
return VASSALIZATION_BANNED
vassalization_status = VASSALIZATION_DISLOYAL
return vassalization_status
if(antag_datum.type in ghoul_banned_antags)
return GHOULIZATION_BANNED
ghoulization_status = GHOULIZATION_DISLOYAL
return ghoulization_status
/**
* # can_make_vassal
* # can_make_ghoul
* Checks if the person is allowed to turn into the Bloodsucker's
* Vassal, ensuring they are a player and valid.
* If they are a Vassal themselves, will check if their master
* Ghoul, ensuring they are a player and valid.
* If they are a Ghoul themselves, will check if their master
* has broken the Masquerade, to steal them.
* Args:
* conversion_target - Person being vassalized
* conversion_target - Person being ghoulized
*/
/datum/antagonist/bloodsucker/proc/can_make_vassal(mob/living/conversion_target)
/datum/antagonist/bloodsucker/proc/can_make_ghoul(mob/living/conversion_target)
if(!iscarbon(conversion_target) || (conversion_target.stat < CONSCIOUS))
return FALSE
// No Mind!
if(!conversion_target.mind)
to_chat(owner.current, span_danger("[conversion_target] isn't self-aware enough to be made into a Vassal."))
to_chat(owner.current, span_danger("[conversion_target] isn't self-aware enough to be made into a Ghoul."))
return FALSE
if(AmValidAntag(conversion_target) == VASSALIZATION_BANNED)
if(AmValidAntag(conversion_target) == GHOULIZATION_BANNED)
to_chat(owner.current, span_danger("[conversion_target] resists the power of your blood to dominate their mind!"))
return FALSE
var/mob/living/master = conversion_target.mind.enslaved_to?.resolve()
@@ -39,45 +39,45 @@
return TRUE
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(master)
if(bloodsuckerdatum && bloodsuckerdatum.broke_masquerade)
//vassal stealing
//ghoul stealing
return TRUE
to_chat(owner.current, span_danger("[conversion_target]'s mind is overwhelmed with too much external force to put your own!"))
return FALSE
/**
* First will check if the target can be turned into a Vassal, if so then it will
* First will check if the target can be turned into a Ghoul, if so then it will
* turn them into one, log it, sync their minds, then updates the Rank
* Args:
* conversion_target - The person converted.
*/
/datum/antagonist/bloodsucker/proc/make_vassal(mob/living/conversion_target)
/datum/antagonist/bloodsucker/proc/make_ghoul(mob/living/conversion_target)
#ifndef BLOODSUCKER_TESTING
if(!can_make_vassal(conversion_target))
if(!can_make_ghoul(conversion_target))
return FALSE
#endif
//Check if they used to be a Vassal and was stolen.
var/datum/antagonist/vassal/old_vassal = IS_VASSAL(conversion_target)
if(old_vassal)
conversion_target.mind.remove_antag_datum(/datum/antagonist/vassal)
//Check if they used to be a Ghoul and was stolen.
var/datum/antagonist/ghoul/old_ghoul = IS_GHOUL(conversion_target)
if(old_ghoul)
conversion_target.mind.remove_antag_datum(/datum/antagonist/ghoul)
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(owner.current)
bloodsuckerdatum.SelectTitle(am_fledgling = FALSE)
//set the master, then give the datum.
var/datum/antagonist/vassal/vassaldatum = new(conversion_target.mind)
vassaldatum.master = bloodsuckerdatum
conversion_target.mind.add_antag_datum(vassaldatum)
var/datum/antagonist/ghoul/ghouldatum = new(conversion_target.mind)
ghouldatum.master = bloodsuckerdatum
conversion_target.mind.add_antag_datum(ghouldatum)
message_admins("[conversion_target] has become a Vassal, and is enslaved to [owner.current].")
log_admin("[conversion_target] has become a Vassal, and is enslaved to [owner.current].")
message_admins("[conversion_target] has become a Ghoul, and is enslaved to [owner.current].")
log_admin("[conversion_target] has become a Ghoul, and is enslaved to [owner.current].")
return TRUE
/*
* # can_make_special
*
* MIND Helper proc that ensures the person can be a Special Vassal,
* MIND Helper proc that ensures the person can be a Special Ghoul,
* without actually giving the antag datum to them.
* This is because Special Vassals get special abilities, without the unique Bloodsucker blood tracking,
* This is because Special Ghouls get special abilities, without the unique Bloodsucker blood tracking,
* and we don't want this to be infinite.
* Args:
* creator - Person attempting to convert them.
@@ -107,13 +107,14 @@
target.reagents.trans_to(owner.current, INGEST, 1) // Run transfer of 1 unit of reagent from them to me.
owner.current.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
if(target.mind) // Checks if the target has a mind
// closer it is to max, the less level up blood you get
var/blood_for_leveling = blood_taken
if(already_drunk > BLOOD_VOLUME_NORMAL)
var/max_threshold = BLOOD_VOLUME_NORMAL * 2
var/modify_blood_gain = 1 - (already_drunk / max_threshold)
blood_for_leveling = max(blood_taken * modify_blood_gain, 0)
if(IS_VASSAL(target)) // Checks if the target is a vassal
if(IS_GHOUL(target)) // Checks if the target is a ghoul
blood_level_gain += blood_for_leveling / 4
else
blood_level_gain += blood_for_leveling
@@ -281,9 +282,9 @@
/// FINAL DEATH
/datum/antagonist/bloodsucker/proc/HandleDeath()
if(QDELETED(owner.current))
if(length(vassals))
free_all_vassals()
vassals = list()
if(length(ghouls))
free_all_ghouls()
ghouls = list()
return
// Fire Damage? (above double health)
if(owner.current.getFireLoss() >= owner.current.maxHealth * FINAL_DEATH_HEALTH_TO_BURN) // 337.5 burn with 135 maxHealth
@@ -399,7 +400,7 @@
return
unregister_body_signals()
unregister_sol_signals()
free_all_vassals()
free_all_ghouls()
DisableAllPowers(forced = TRUE)
if(!iscarbon(owner.current))
owner.current.gib(DROP_ITEMS)
@@ -29,29 +29,29 @@
return possible_targets
/// Check Vassals and get their occupations
/datum/objective/bloodsucker/proc/get_vassal_occupations()
/// Check Ghouls and get their occupations
/datum/objective/bloodsucker/proc/get_ghoul_occupations()
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(owner.current)
if(!bloodsuckerdatum || !bloodsuckerdatum.vassals.len)
if(!bloodsuckerdatum || !bloodsuckerdatum.ghouls.len)
return FALSE
var/list/all_vassal_jobs = list()
var/vassal_job
for(var/datum/antagonist/vassal/bloodsucker_vassals in bloodsuckerdatum.vassals)
if(!bloodsucker_vassals || !bloodsucker_vassals.owner) // Must exist somewhere, and as a vassal.
var/list/all_ghoul_jobs = list()
var/ghoul_job
for(var/datum/antagonist/ghoul/bloodsucker_ghouls in bloodsuckerdatum.ghouls)
if(!bloodsucker_ghouls || !bloodsucker_ghouls.owner) // Must exist somewhere, and as a ghoul.
continue
// Mind Assigned
if(bloodsucker_vassals.owner?.assigned_role)
vassal_job = bloodsucker_vassals.owner.assigned_role
if(bloodsucker_ghouls.owner?.assigned_role)
ghoul_job = bloodsucker_ghouls.owner.assigned_role
// Mob Assigned
else if(bloodsucker_vassals.owner?.current?.job)
vassal_job = SSjob.GetJob(bloodsucker_vassals.owner.current.job)
else if(bloodsucker_ghouls.owner?.current?.job)
ghoul_job = SSjob.GetJob(bloodsucker_ghouls.owner.current.job)
// PDA Assigned
else if(bloodsucker_vassals.owner?.current && ishuman(bloodsucker_vassals.owner.current))
var/mob/living/carbon/human/vassal = bloodsucker_vassals.owner.current
vassal_job = SSjob.GetJob(vassal.get_assignment())
if(vassal_job)
all_vassal_jobs += vassal_job
return all_vassal_jobs
else if(bloodsucker_ghouls.owner?.current && ishuman(bloodsucker_ghouls.owner.current))
var/mob/living/carbon/human/ghoul = bloodsucker_ghouls.owner.current
ghoul_job = SSjob.GetJob(ghoul.get_assignment())
if(ghoul_job)
all_ghoul_jobs += ghoul_job
return all_ghoul_jobs
//////////////////////////////////////////////////////////////////////////////////////
// // OBJECTIVES // //
@@ -61,17 +61,17 @@
// DEFAULT OBJECTIVES //
//////////////////////////////
/datum/objective/bloodsucker/lair
name = "claimlair"
/datum/objective/bloodsucker/haven
name = "claimhaven"
// EXPLANATION
/datum/objective/bloodsucker/lair/update_explanation_text()
explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift."// Make sure to keep it safe!"
/datum/objective/bloodsucker/haven/update_explanation_text()
explanation_text = "Create a haven by claiming a coffin, and protect it until the end of the shift."// Make sure to keep it safe!"
// WIN CONDITIONS?
/datum/objective/bloodsucker/lair/check_completion()
/datum/objective/bloodsucker/haven/check_completion()
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(owner.current)
if(bloodsuckerdatum && bloodsuckerdatum.coffin && bloodsuckerdatum.bloodsucker_lair_area)
if(bloodsuckerdatum && bloodsuckerdatum.coffin && bloodsuckerdatum.bloodsucker_haven_area)
return TRUE
return FALSE
@@ -96,36 +96,36 @@
//////////////////////////////////////////////////////////////////////////////////////
/// Vassalize a certain person / people
/// Ghoulify a certain person / people
/datum/objective/bloodsucker/conversion
name = "vassalization"
name = "ghoulization"
/////////////////////////////////
// Vassalize a head of staff
// Ghoulify a head of staff
/datum/objective/bloodsucker/conversion/command
name = "vassalizationcommand"
name = "ghoulizationcommand"
target_amount = 1
// EXPLANATION
/datum/objective/bloodsucker/conversion/command/update_explanation_text()
explanation_text = "Guarantee a Vassal ends up as a Department Head or in a Leadership role."
explanation_text = "Guarantee a Ghoul ends up as a Department Head or in a Leadership role."
// WIN CONDITIONS?
/datum/objective/bloodsucker/conversion/command/check_completion()
var/list/vassal_jobs = get_vassal_occupations()
for(var/datum/job/checked_job in vassal_jobs)
var/list/ghoul_jobs = get_ghoul_occupations()
for(var/datum/job/checked_job in ghoul_jobs)
if(checked_job.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND)
return TRUE // We only need one, so we stop as soon as we get a match
return FALSE
/////////////////////////////////
// Vassalize crewmates in a department
// Ghoulify crewmates in a department
/datum/objective/bloodsucker/conversion/department
name = "vassalize department"
name = "ghoulify department"
///The selected department we have to vassalize.
///The selected department we have to ghoulify.
var/datum/job_department/target_department
///List of all departments that can be selected for the objective.
var/static/list/possible_departments = list(
@@ -146,14 +146,14 @@
// EXPLANATION
/datum/objective/bloodsucker/conversion/department/update_explanation_text()
explanation_text = "Have [target_amount] Vassal[target_amount == 1 ? "" : "s"] in the [target_department.department_name] department."
explanation_text = "Have [target_amount] Ghoul[target_amount == 1 ? "" : "s"] in the [target_department.department_name] department."
return ..()
// WIN CONDITIONS?
/datum/objective/bloodsucker/conversion/department/check_completion()
var/list/vassal_jobs = get_vassal_occupations()
var/list/ghoul_jobs = get_ghoul_occupations()
var/converted_count = 0
for(var/datum/job/checked_job in vassal_jobs)
for(var/datum/job/checked_job in ghoul_jobs)
if(checked_job.departments_bitflags & target_department.department_bitflags)
converted_count++
if(converted_count >= target_amount)
@@ -223,14 +223,14 @@
// CLAN OBJECTIVES //
//////////////////////////////
/// Steal the Archive of the Kindred - Nosferatu Clan objective
/// Steal the Book of Nod - Nosferatu Clan objective
/datum/objective/bloodsucker/kindred
name = "steal kindred"
name = "steal the Book of Nod"
// EXPLANATION
/datum/objective/bloodsucker/kindred/update_explanation_text()
. = ..()
explanation_text = "Ensure Nosferatu steals and keeps control over the Archive of the Kindred."
explanation_text = "A Noddist Scholar has posted a bounty on SchreckNet for a scrap of the Book of Nod located in your sector. Their advise? Read a book."
// WIN CONDITIONS?
/datum/objective/bloodsucker/kindred/check_completion()
@@ -255,7 +255,7 @@
// EXPLANATION
/datum/objective/bloodsucker/tremere_power/update_explanation_text()
explanation_text = "Upgrade a Blood Magic power to level [power_level], remember that Vassalizing gives more Ranks!"
explanation_text = "Your Regent is doubting your abilities, level some Blood Magic to [power_level] to prove them wrong! Remember that Ghoulifying gives more Ranks!"
// WIN CONDITIONS?
/datum/objective/bloodsucker/tremere_power/check_completion()
@@ -276,7 +276,7 @@
// EXPLANATION
/datum/objective/bloodsucker/embrace/update_explanation_text()
. = ..()
explanation_text = "Use the vassal rack to Rank your Favorite Vassal up enough to become a Bloodsucker."
explanation_text = "Your Strategoi has granted you permission to embrace your favourite ghoul , use the Rack to 'level' them up."
// WIN CONDITIONS?
/datum/objective/bloodsucker/embrace/check_completion()
@@ -321,19 +321,19 @@
//////////////////////////////
// VASSAL OBJECTIVES //
// GHOUL OBJECTIVES //
//////////////////////////////
/datum/objective/bloodsucker/vassal
/datum/objective/bloodsucker/ghoul
// EXPLANATION
/datum/objective/bloodsucker/vassal/update_explanation_text()
/datum/objective/bloodsucker/ghoul/update_explanation_text()
. = ..()
explanation_text = "Guarantee the success of your Master's mission!"
// WIN CONDITIONS?
/datum/objective/bloodsucker/vassal/check_completion()
var/datum/antagonist/vassal/antag_datum = owner.has_antag_datum(/datum/antagonist/vassal)
/datum/objective/bloodsucker/ghoul/check_completion()
var/datum/antagonist/ghoul/antag_datum = owner.has_antag_datum(/datum/antagonist/ghoul)
return antag_datum.master?.owner?.current?.stat != DEAD
@@ -344,29 +344,29 @@
//////////////////////////////
// NOTE: Look up /assassinate in objective.dm for inspiration.
/// Vassalize a target.
/datum/objective/bloodsucker/vassalhim
name = "vassalhim"
/// Ghoulify a target.
/datum/objective/bloodsucker/ghoulhim
name = "ghoulhim"
var/target_department_type = FALSE
/datum/objective/bloodsucker/vassalhim/New()
/datum/objective/bloodsucker/ghoulhim/New()
var/list/possible_targets = return_possible_targets()
find_target(possible_targets)
..()
// EXPLANATION
/datum/objective/bloodsucker/vassalhim/update_explanation_text()
/datum/objective/bloodsucker/ghoulhim/update_explanation_text()
. = ..()
if(target?.current)
explanation_text = "Ensure [target.name], the [!target_department_type ? target.assigned_role.title : target.special_role], is Vassalized via the Persuasion Rack."
explanation_text = "Ensure [target.name], the [!target_department_type ? target.assigned_role.title : target.special_role], is Ghoulifyd via the Persuasion Rack."
else
explanation_text = "Free Objective"
/datum/objective/bloodsucker/vassalhim/admin_edit(mob/admin)
/datum/objective/bloodsucker/ghoulhim/admin_edit(mob/admin)
admin_simple_target_pick(admin)
// WIN CONDITIONS?
/datum/objective/bloodsucker/vassalhim/check_completion()
if(!target || target.has_antag_datum(/datum/antagonist/vassal))
/datum/objective/bloodsucker/ghoulhim/check_completion()
if(!target || target.has_antag_datum(/datum/antagonist/ghoul))
return TRUE
return FALSE
@@ -41,7 +41,7 @@
return
owner.current.playsound_local(null, 'modular_zubbers/sound/bloodsucker/lunge_warn.ogg', 100, FALSE, pressure_affected = FALSE)
to_chat(owner.current, span_cult_bold_italic("You have broken the Masquerade!"))
to_chat(owner.current, span_warning("Bloodsucker Tip: When you break the Masquerade, you become open for termination by fellow Bloodsuckers, and your Vassals are no longer completely loyal to you, as other Bloodsuckers can steal them for themselves!"))
to_chat(owner.current, span_warning("Bloodsucker Tip: When you break the Masquerade, you become open for termination by fellow Bloodsuckers, and your Ghouls are no longer completely loyal to you, as other Bloodsuckers can steal them for themselves!"))
broke_masquerade = TRUE
antag_hud_name = "masquerade_broken"
add_team_hud(owner.current)
@@ -74,7 +74,7 @@
return
// Spend Rank Immediately?
if(!is_valid_coffin())
to_chat(owner, span_notice("<EM>You have grown more ancient! Sleep in a coffin (or put your Favorite Vassal on a persuasion rack for Ventrue) that you have claimed to thicken your blood and become more powerful.</EM>"))
to_chat(owner, span_notice("<EM>You have grown more ancient! Sleep in a coffin (or put your Favorite Ghoul on a persuasion rack for Ventrue) that you have claimed to thicken your blood and become more powerful.</EM>"))
if(bloodsucker_level_unspent >= 2)
to_chat(owner, span_announce("Bloodsucker Tip: If you cannot find or steal a coffin to use, you can build one from wood or metal."))
return
@@ -124,18 +124,18 @@
update_rank_hud()
/**
* Called when a Bloodsucker reaches Final Death
* Releases all Vassals and gives them the ex_vassal datum.
* Releases all Ghouls and gives them the ex_ghoul datum.
*/
/datum/antagonist/bloodsucker/proc/free_all_vassals()
for(var/datum/antagonist/vassal/all_vassals in vassals)
// Skip over any Bloodsucker Vassals, they're too far gone to have all their stuff taken away from them
if(IS_BLOODSUCKER(all_vassals.owner.current))
all_vassals.owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer/vassal_edition)
/datum/antagonist/bloodsucker/proc/free_all_ghouls()
for(var/datum/antagonist/ghoul/all_ghouls in ghouls)
// Skip over any Bloodsucker Ghouls, they're too far gone to have all their stuff taken away from them
if(IS_BLOODSUCKER(all_ghouls.owner.current))
all_ghouls.owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer/ghoul_edition)
continue
if(all_vassals.special_type == REVENGE_VASSAL || !all_vassals.owner)
if(all_ghouls.special_type == REVENGE_GHOUL || !all_ghouls.owner)
continue
all_vassals.owner.add_antag_datum(/datum/antagonist/ex_vassal)
all_vassals.owner.remove_antag_datum(/datum/antagonist/vassal)
all_ghouls.owner.add_antag_datum(/datum/antagonist/ex_ghoul)
all_ghouls.owner.remove_antag_datum(/datum/antagonist/ghoul)
/**
* Returns a Vampire's examine strings.
@@ -145,14 +145,14 @@
/datum/antagonist/bloodsucker/proc/return_vamp_examine(mob/living/viewer)
if(!viewer.mind && !isobserver(viewer))
return FALSE
// Viewer is Target's Vassal?
if(!isobserver(viewer) && (viewer.mind.has_antag_datum(/datum/antagonist/vassal) in vassals))
// Viewer is Target's Ghoul?
if(!isobserver(viewer) && (viewer.mind.has_antag_datum(/datum/antagonist/ghoul) in ghouls))
var/returnString = "\[<span class='warning'><EM>This is your Master!</EM></span>\]"
var/returnIcon = "[icon2html('modular_zubbers/icons/misc/language.dmi', world, "bloodsucker")]"
returnString += "\n"
return returnIcon + returnString
// Viewer not a Vamp AND not the target's vassal?
if(!isobserver(viewer) && !viewer.mind.has_antag_datum((/datum/antagonist/bloodsucker)) && !(viewer in vassals))
// Viewer not a Vamp AND not the target's ghoul?
if(!isobserver(viewer) && !viewer.mind.has_antag_datum((/datum/antagonist/bloodsucker)) && !(viewer in ghouls))
if(!(HAS_TRAIT(viewer.mind, TRAIT_BLOODSUCKER_HUNTER) && broke_masquerade))
return FALSE
// Default String
@@ -197,11 +197,11 @@
var/percentage_needed = my_clan ? my_clan.level_cost : BLOODSUCKER_LEVELUP_PERCENTAGE
return max_blood_volume * percentage_needed
/datum/antagonist/bloodsucker/proc/max_vassals()
/datum/antagonist/bloodsucker/proc/max_ghouls()
return round(bloodsucker_level * 0.5)
/datum/antagonist/bloodsucker/proc/free_vassal_slots()
return max(max_vassals() - length(vassals), 0)
/datum/antagonist/bloodsucker/proc/free_ghoul_slots()
return max(max_ghouls() - length(ghouls), 0)
/datum/antagonist/bloodsucker/proc/frenzy_enter_threshold()
return FRENZY_THRESHOLD_ENTER + (humanity_lost * 10)
@@ -366,7 +366,7 @@
/datum/antagonist/bloodsucker/proc/on_owner_deletion(mob/living/deleted_mob)
SIGNAL_HANDLER
free_all_vassals()
free_all_ghouls()
if(deleted_mob != owner.current)
return
if(is_head(deleted_mob))
@@ -20,7 +20,7 @@
///Called when Sol is near starting.
/datum/antagonist/bloodsucker/proc/sol_near_start(atom/source)
SIGNAL_HANDLER
if(bloodsucker_lair_area && !(locate(/datum/action/cooldown/bloodsucker/gohome) in powers))
if(bloodsucker_haven_area && !(locate(/datum/action/cooldown/bloodsucker/gohome) in powers))
BuyPower(/datum/action/cooldown/bloodsucker/gohome)
///Called when Sol first ends.
@@ -70,7 +70,7 @@
owner.current.updatehealth()
owner.current.add_mood_event("vampsleep", /datum/mood_event/daylight_bad_sleep)
/datum/antagonist/bloodsucker/proc/give_warning(atom/source, danger_level, vampire_warning_message, vassal_warning_message)
/datum/antagonist/bloodsucker/proc/give_warning(atom/source, danger_level, vampire_warning_message, ghoul_warning_message)
SIGNAL_HANDLER
SSsunlight.warn_notify(owner.current, danger_level, vampire_warning_message)
@@ -13,7 +13,7 @@
var/description = "The Caitiff is as basic as you can get with Bloodsuckers. \n\
Entirely without the help of a formal Clan, they are blissfully unaware of who they really are. \n\
No additional abilities is gained, nothing is lost, if you want a plain Bloodsucker, this is it. \n\
The Favorite Vassal will gain the Brawn ability, to help in combat."
The Favorite Ghoul will gain the Brawn ability, to help in combat."
///The clan objective that is required to greentext.
var/datum/objective/bloodsucker/clan_objective
///The icon of the radial icon to join this clan.
@@ -40,11 +40,11 @@
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_ON_LIFETICK, PROC_REF(handle_clan_life))
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_RANK_UP, PROC_REF(on_spend_rank))
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_INTERACT_WITH_VASSAL, PROC_REF(on_interact_with_vassal))
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_MAKE_FAVORITE, PROC_REF(favorite_vassal_gain))
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_LOOSE_FAVORITE, PROC_REF(favorite_vassal_loss))
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_INTERACT_WITH_GHOUL, PROC_REF(on_interact_with_ghoul))
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_MAKE_FAVORITE, PROC_REF(favorite_ghoul_gain))
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_LOOSE_FAVORITE, PROC_REF(favorite_ghoul_loss))
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_MADE_VASSAL, PROC_REF(on_vassal_made))
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_MADE_GHOUL, PROC_REF(on_ghoul_made))
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_EXIT_TORPOR, PROC_REF(on_exit_torpor))
RegisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_FINAL_DEATH, PROC_REF(on_final_death))
@@ -57,9 +57,9 @@
UnregisterSignal(bloodsuckerdatum, list(
COMSIG_BLOODSUCKER_ON_LIFETICK,
COMSIG_BLOODSUCKER_RANK_UP,
COMSIG_BLOODSUCKER_INTERACT_WITH_VASSAL,
COMSIG_BLOODSUCKER_INTERACT_WITH_GHOUL,
COMSIG_BLOODSUCKER_MAKE_FAVORITE,
COMSIG_BLOODSUCKER_MADE_VASSAL,
COMSIG_BLOODSUCKER_MADE_GHOUL,
COMSIG_BLOODSUCKER_EXIT_TORPOR,
COMSIG_BLOODSUCKER_FINAL_DEATH,
COMSIG_BLOODSUCKER_ENTERS_FRENZY,
@@ -125,11 +125,11 @@
SIGNAL_HANDLER
/**
* Called when a Bloodsucker successfully Vassalizes someone.
* Called when a Bloodsucker successfully Ghoulizes someone.
* args:
* bloodsuckerdatum - the antagonist datum of the Bloodsucker running this.
*/
/datum/bloodsucker_clan/proc/on_vassal_made(datum/antagonist/bloodsucker/source, mob/living/user, mob/living/target)
/datum/bloodsucker_clan/proc/on_ghoul_made(datum/antagonist/bloodsucker/source, mob/living/user, mob/living/target)
SIGNAL_HANDLER
user.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, TRUE)
target.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE)
@@ -140,6 +140,7 @@
* Called when a Bloodsucker successfully starts spending their Rank
* args:
* bloodsuckerdatum - the antagonist datum of the Bloodsucker running this.
* target - The Ghoul (if any) we are upgrading.
* cost_rank - TRUE/FALSE on whether this will cost us a rank when we go through with it.
* blood_cost - A number saying how much it costs to rank up.
*/
@@ -233,15 +234,16 @@
bloodsuckerdatum.owner.current.playsound_local(null, 'sound/effects/pope_entry.ogg', 25, TRUE, pressure_affected = FALSE)
bloodsuckerdatum.update_static_data_for_all_viewers()
// unlock vassalizing if we have a vassal slot
if(bloodsuckerdatum.max_vassals() >= 1 && !(/datum/crafting_recipe/vassalrack in bloodsuckerdatum.owner?.learned_recipes))
bloodsuckerdatum.owner.teach_crafting_recipe(/datum/crafting_recipe/vassalrack)
// unlock ghoulizing if we have a ghoul slot
if(bloodsuckerdatum.max_ghouls() >= 1 && !(/datum/crafting_recipe/ghoulrack in bloodsuckerdatum.owner?.learned_recipes))
bloodsuckerdatum.owner.teach_crafting_recipe(/datum/crafting_recipe/ghoulrack)
bloodsuckerdatum.owner.teach_crafting_recipe(/datum/crafting_recipe/candelabrum)
bloodsuckerdatum.owner.teach_crafting_recipe(/datum/crafting_recipe/bloodthrone)
bloodsuckerdatum.owner.teach_crafting_recipe(/datum/crafting_recipe/meatcoffin)
bloodsuckerdatum.owner.current.balloon_alert(bloodsuckerdatum.owner.current, "new recipes learned! Vassalization unlocked!")
bloodsuckerdatum.owner.current.balloon_alert(bloodsuckerdatum.owner.current, "new recipes learned! Ghoulization unlocked!")
return TRUE
/datum/bloodsucker_clan/proc/list_available_powers(already_known = bloodsuckerdatum.powers, powers_list = bloodsuckerdatum.all_bloodsucker_powers)
var/list/options = list()
for(var/datum/action/cooldown/bloodsucker/power as anything in powers_list)
@@ -255,77 +257,77 @@
/datum/bloodsucker_clan/proc/level_up_powers(datum/antagonist/bloodsucker/source)
bloodsuckerdatum.LevelUpPowers()
/**
* Called when we are trying to turn someone into a Favorite Vassal
* Called when we are trying to turn someone into a Favorite Ghoul
* args:
* bloodsuckerdatum - the antagonist datum of the Bloodsucker performing this.
* vassaldatum - the antagonist datum of the Vassal being offered up.
* ghouldatum - the antagonist datum of the Ghoul being offered up.
*/
/datum/bloodsucker_clan/proc/on_interact_with_vassal(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
/datum/bloodsucker_clan/proc/on_interact_with_ghoul(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/ghouldatum)
SIGNAL_HANDLER
INVOKE_ASYNC(src, PROC_REF(interact_with_vassal), bloodsuckerdatum, vassaldatum)
INVOKE_ASYNC(src, PROC_REF(interact_with_ghoul), bloodsuckerdatum, ghouldatum)
/datum/bloodsucker_clan/proc/interact_with_vassal(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
/datum/bloodsucker_clan/proc/interact_with_ghoul(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/ghouldatum)
var/mob/living/carbon/human/master = bloodsuckerdatum.owner.current
var/mob/living/carbon/human/servant = vassaldatum.owner.current
if(vassaldatum.special_type || IS_BLOODSUCKER(servant))
to_chat(master, span_notice("This Vassal was already assigned a special position."))
var/mob/living/carbon/human/servant = ghouldatum.owner.current
if(ghouldatum.special_type || IS_BLOODSUCKER(servant))
to_chat(master, span_notice("This Ghoul was already assigned a special position."))
return FALSE
if(!vassaldatum.owner.can_make_special(creator = bloodsuckerdatum.owner))
to_chat(master, span_notice("This Vassal is unable to gain a Special rank due to innate features."))
if(!ghouldatum.owner.can_make_special(creator = bloodsuckerdatum.owner))
to_chat(master, span_notice("This Ghoul is unable to gain a Special rank due to innate features."))
return FALSE
if(bloodsuckerdatum.GetBloodVolume() < SPECIAL_VASSAL_COST)
to_chat(master, span_notice("You need at least 150 blood to make a Vassal a Favorite Vassal."))
if(bloodsuckerdatum.GetBloodVolume() < SPECIAL_GHOUL_COST)
to_chat(master, span_notice("You need at least 150 blood to make a Ghoul a Favorite Ghoul."))
return FALSE
var/list/options = list()
var/list/radial_display = list()
for(var/datum/antagonist/vassal/vassaldatums as anything in subtypesof(/datum/antagonist/vassal))
var/vassal_type = initial(vassaldatums.special_type)
var/slot = bloodsuckerdatum.special_vassals[vassal_type]
if(vassal_type && slot)
for(var/datum/antagonist/ghoul/ghouldatums as anything in subtypesof(/datum/antagonist/ghoul))
var/ghoul_type = initial(ghouldatums.special_type)
var/slot = bloodsuckerdatum.special_ghouls[ghoul_type]
if(ghoul_type && slot)
continue
options[initial(vassaldatums.name)] = vassaldatums
options[initial(ghouldatums.name)] = ghouldatums
var/datum/radial_menu_choice/option = new
option.image = image(icon = initial(vassaldatums.hud_icon), icon_state = initial(vassaldatums.antag_hud_name), pixel_y = -12, pixel_x = -12)
option.info = "[initial(vassaldatums.name)] - [span_boldnotice(initial(vassaldatums.vassal_description))]"
radial_display[initial(vassaldatums.name)] = option
option.image = image(icon = initial(ghouldatums.hud_icon), icon_state = initial(ghouldatums.antag_hud_name), pixel_y = -12, pixel_x = -12)
option.info = "[initial(ghouldatums.name)] - [span_boldnotice(initial(ghouldatums.ghoul_description))]"
radial_display[initial(ghouldatums.name)] = option
if(!options.len)
master.balloon_alert(master, "Out of Special Vassal slots!")
master.balloon_alert(master, "Out of Special Ghoul slots!")
return FALSE
to_chat(master, span_notice("You can change who this Vassal is, who are they to you? This will cost [SPECIAL_VASSAL_COST] blood."))
var/vassal_response = show_radial_menu(master, servant, radial_display)
if(!vassal_response)
to_chat(master, span_notice("You can change who this Ghoul is, who are they to you? This will cost [SPECIAL_GHOUL_COST] blood."))
var/ghoul_response = show_radial_menu(master, servant, radial_display)
if(!ghoul_response)
return FALSE
var/datum/antagonist/vassal/vassal_type = options[vassal_response]
// let's ask if the vassal themselves actually wants to be a favorite
var/datum/antagonist/ghoul/ghoul_type = options[ghoul_response]
// let's ask if the ghoul themselves actually wants to be a favorite
#ifndef BLOODSUCKER_TESTING
servant.balloon_alert(master, "asking...")
var/vassal_permission = tgui_alert(servant, initial(vassal_type.vassal_description), "Become a Special Vassal?", list("Yes", "No"), 1 MINUTES) == "Yes"
if(!vassal_permission)
var/ghoul_permission = tgui_alert(servant, initial(ghoul_type.ghoul_description), "Become a Special Ghoul?", list("Yes", "No"), 1 MINUTES) == "Yes"
if(!ghoul_permission)
servant.balloon_alert(master, "refused!")
return FALSE
#endif
if(QDELETED(src) || QDELETED(master) || QDELETED(servant) || !vassal_type)
if(QDELETED(src) || QDELETED(master) || QDELETED(servant) || !ghoul_type)
return FALSE
if(bloodsuckerdatum.GetBloodVolume() < SPECIAL_VASSAL_COST)
to_chat(master, span_notice("You took too long to make your vassal, you no longer have enough blood!"))
if(bloodsuckerdatum.GetBloodVolume() < SPECIAL_GHOUL_COST)
to_chat(master, span_notice("You took too long to make your ghoul, you no longer have enough blood!"))
return FALSE
vassaldatum.make_special(vassal_type)
bloodsuckerdatum.AdjustBloodVolume(-SPECIAL_VASSAL_COST)
ghouldatum.make_special(ghoul_type)
bloodsuckerdatum.AdjustBloodVolume(-SPECIAL_GHOUL_COST)
return TRUE
/**
* Called when we are successfully turn a Vassal into a Favorite Vassal
* Called when we are successfully turn a Ghoul into a Favorite Ghoul
* args:
* bloodsuckerdatum - antagonist datum of the Bloodsucker who turned them into a Vassal.
* vassaldatum - the antagonist datum of the Vassal being offered up.
* bloodsuckerdatum - antagonist datum of the Bloodsucker who turned them into a Ghoul.
* ghouldatum - the antagonist datum of the Ghoul being offered up.
*/
/datum/bloodsucker_clan/proc/favorite_vassal_gain(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
/datum/bloodsucker_clan/proc/favorite_ghoul_gain(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/ghouldatum)
SIGNAL_HANDLER
vassaldatum.BuyPower(/datum/action/cooldown/bloodsucker/targeted/brawn)
ghouldatum.BuyPower(/datum/action/cooldown/bloodsucker/targeted/brawn)
/datum/bloodsucker_clan/proc/favorite_vassal_loss(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
/datum/bloodsucker_clan/proc/favorite_ghoul_loss(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/ghouldatum)
SIGNAL_HANDLER
@@ -3,7 +3,7 @@
description = "Closer to Animals than Bloodsuckers, known as Werewolves waiting to happen, \n\
these are the most fearful of True Faith, being the most lethal thing they would ever see the night of. \n\
Full Moons do not seem to have an effect, despite common-told stories. \n\
The Favorite Vassal turns into a Werewolf whenever their Master does."
The Favorite Ghoul turns into a Werewolf whenever their Master does."
joinable_clan = FALSE
blood_drink_type = BLOODSUCKER_DRINK_INHUMANELY
@@ -27,7 +27,7 @@
description = "The most charming Clan of them all, allowing them to very easily disguise among the crew. \n\
More in touch with their morals, they suffer and benefit more strongly from humanity cost or gain of their actions. \n\
Known as 'The most humane kind of vampire', they have an obsession with perfectionism and beauty \n\
The Favorite Vassal gains the Mesmerize ability."
The Favorite Ghoul gains the Mesmerize ability."
joinable_clan = FALSE
blood_drink_type = BLOODSUCKER_DRINK_SNOBBY
@@ -36,7 +36,7 @@
description = "The Brujah Clan has proven to be the strongest in melee combat, boasting a powerful punch. \n\
They also appear to be more calm than the others, entering their 'frenzies' whenever they want, but dont seem affected much by them. \n\
Be wary, as they are fearsome warriors, rebels and anarchists, with an inclination towards Frenzy. \n\
The Favorite Vassal gains brawn and a massive increase in brute damage from punching."
The Favorite Ghoul gains brawn and a massive increase in brute damage from punching."
joinable_clan = FALSE
/datum/bloodsucker_clan/tzimisce
@@ -1,7 +1,7 @@
/datum/bloodsucker_clan/malkavian
name = CLAN_MALKAVIAN
description = "Little is documented about Malkavians. Complete insanity is the most common theme. \n\
The Favorite Vassal will suffer the same fate as the Master, while gaining the ability to tap into the madness when fighting."
The Favorite Ghoul will suffer the same fate as the Master, while gaining the ability to tap into the madness when fighting."
join_icon_state = "malkavian"
join_description = "Completely insane. You gain constant hallucinations, become a prophet with unintelligable rambling, \
and become the enforcer of the Masquerade code."
@@ -56,24 +56,24 @@
var/message = pick(strings("malkavian_revelations.json", "revelations", "modular_zubbers/strings/bloodsuckers"))
INVOKE_ASYNC(source.owner.current, TYPE_PROC_REF(/atom/movable, say), message, forced = CLAN_MALKAVIAN)
/datum/bloodsucker_clan/malkavian/favorite_vassal_gain(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
var/mob/living/carbon/carbonowner = vassaldatum.owner.current
/datum/bloodsucker_clan/malkavian/favorite_ghoul_gain(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/ghouldatum)
var/mob/living/carbon/carbonowner = ghouldatum.owner.current
if(istype(carbonowner))
carbonowner.gain_trauma(/datum/brain_trauma/mild/hallucinations, TRAUMA_RESILIENCE_ABSOLUTE)
carbonowner.gain_trauma(/datum/brain_trauma/special/bluespace_prophet/phobetor, TRAUMA_RESILIENCE_ABSOLUTE)
var/datum/martial_art/psychotic_brawling/psychotic_brawling = new(null)
psychotic_brawling.teach(vassaldatum.owner.current, TRUE)
to_chat(vassaldatum.owner.current, span_notice("Additionally, you now suffer the same fate as your Master, while also gaining the ability to tap into the madness when fighting."))
psychotic_brawling.teach(ghouldatum.owner.current, TRUE)
to_chat(ghouldatum.owner.current, span_notice("Additionally, you now suffer the same fate as your Master, while also gaining the ability to tap into the madness when fighting."))
/datum/bloodsucker_clan/malkavian/favorite_vassal_loss(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
var/mob/living/carbon/carbonowner = vassaldatum.owner.current
/datum/bloodsucker_clan/malkavian/favorite_ghoul_loss(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/ghouldatum)
var/mob/living/carbon/carbonowner = ghouldatum.owner.current
if(istype(carbonowner))
carbonowner.cure_trauma_type(/datum/brain_trauma/mild/hallucinations, TRAUMA_RESILIENCE_ABSOLUTE)
carbonowner.cure_trauma_type(/datum/brain_trauma/special/bluespace_prophet/phobetor, TRAUMA_RESILIENCE_ABSOLUTE)
if(!istype(/datum/martial_art/psychotic_brawling, vassaldatum.owner.martial_art))
if(!istype(/datum/martial_art/psychotic_brawling, ghouldatum.owner.martial_art))
return
var/datum/martial_art/psychotic_brawling/psychotic_brawling = vassaldatum.owner.martial_art
psychotic_brawling.remove(vassaldatum.owner.current)
var/datum/martial_art/psychotic_brawling/psychotic_brawling = ghouldatum.owner.martial_art
psychotic_brawling.remove(ghouldatum.owner.current)
/datum/bloodsucker_clan/malkavian/on_exit_torpor(datum/antagonist/bloodsucker/source)
var/mob/living/carbon/carbonowner = bloodsuckerdatum.owner.martial_art
@@ -3,7 +3,7 @@
description = "The Nosferatu Clan is unable to blend in with the crew, with no abilities such as Masquerade and Veil. \n\
Additionally, has a permanent bad back and looks like a Bloodsucker upon a simple examine, and their face is disfigured \n\
they can fit in the vents regardless of their form and equipment. \n\
The Favorite Vassal is also permanently disfigured, and can also ventcrawl, but only while entirely nude. \n\
The Favorite Ghoul is also permanently disfigured, and can also ventcrawl, but only while entirely nude. \n\
They also have night vision, know what each wire does, and have silent footsteps."
clan_objective = /datum/objective/bloodsucker/kindred
join_icon_state = "nosferatu"
@@ -40,12 +40,12 @@
UnregisterSignal(bloodsuckerdatum, COMSIG_BLOODSUCKER_EXAMINE)
return ..()
/datum/bloodsucker_clan/nosferatu/favorite_vassal_gain(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
/datum/bloodsucker_clan/nosferatu/favorite_ghoul_gain(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/ghouldatum)
var/list/traits_to_add = list(TRAIT_VENTCRAWLER_NUDE, TRAIT_DISFIGURED, TRAIT_TRUE_NIGHT_VISION, TRAIT_KNOW_ENGI_WIRES, TRAIT_SILENT_FOOTSTEPS)
vassaldatum.owner.current.add_traits(traits_to_add, VASSAL_TRAIT)
vassaldatum.traits += traits_to_add
vassaldatum.owner.current.update_sight()
to_chat(vassaldatum.owner.current, span_notice("Additionally, you can now ventcrawl while naked, and are permanently disfigured. You also have night vision, know how which wires to cut, and have silent footsteps."))
ghouldatum.owner.current.add_traits(traits_to_add, GHOUL_TRAIT)
ghouldatum.traits += traits_to_add
ghouldatum.owner.current.update_sight()
to_chat(ghouldatum.owner.current, span_notice("Additionally, you can now ventcrawl while naked, and are permanently disfigured. You also have night vision, know how which wires to cut, and have silent footsteps."))
/datum/bloodsucker_clan/nosferatu/favorite_vassal_loss(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
vassaldatum.owner.current.update_sight()
/datum/bloodsucker_clan/nosferatu/favorite_ghoul_loss(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/ghouldatum)
ghouldatum.owner.current.update_sight()
@@ -2,8 +2,8 @@
name = CLAN_TREMERE
description = "The Tremere Clan is extremely weak to True Faith, and will burn when entering areas considered such, like the Chapel. \n\
Additionally, a whole new moveset is learned, built on Blood magic rather than Blood abilities, which are upgraded overtime. \n\
More ranks can be gained by Vassalizing crewmembers. \n\
The Favorite Vassal gains the Batform spell, being able to morph themselves at will."
More ranks can be gained by Ghoulizing crewmembers. \n\
The Favorite Ghoul gains the Batform spell, being able to morph themselves at will."
clan_objective = /datum/objective/bloodsucker/tremere_power
join_icon_state = "tremere"
join_description = "You will burn if you enter the Chapel, lose all default powers, \
@@ -49,15 +49,15 @@
/datum/bloodsucker_clan/tremere/purchase_choice(datum/antagonist/bloodsucker/source, datum/action/cooldown/bloodsucker/purchased_power)
return purchased_power.upgrade_power()
/datum/bloodsucker_clan/tremere/favorite_vassal_gain(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
var/datum/action/cooldown/spell/shapeshift/bat/batform = new(vassaldatum.owner || vassaldatum.owner.current)
batform.Grant(vassaldatum.owner.current)
/datum/bloodsucker_clan/tremere/favorite_ghoul_gain(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/ghouldatum)
var/datum/action/cooldown/spell/shapeshift/bat/batform = new(ghouldatum.owner || ghouldatum.owner.current)
batform.Grant(ghouldatum.owner.current)
/datum/bloodsucker_clan/tremere/favorite_vassal_loss(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
var/datum/action/cooldown/spell/shapeshift/bat/batform = locate() in vassaldatum.owner.current.actions
batform.Remove(vassaldatum.owner.current)
/datum/bloodsucker_clan/tremere/favorite_ghoul_loss(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/ghouldatum)
var/datum/action/cooldown/spell/shapeshift/bat/batform = locate() in ghouldatum.owner.current.actions
batform.Remove(ghouldatum.owner.current)
/datum/bloodsucker_clan/tremere/on_vassal_made(datum/antagonist/bloodsucker/source, mob/living/user, mob/living/target)
/datum/bloodsucker_clan/tremere/on_ghoul_made(datum/antagonist/bloodsucker/source, mob/living/user, mob/living/target)
. = ..()
to_chat(bloodsuckerdatum.owner.current, span_danger("You have now gained an additional Rank to spend!"))
bloodsuckerdatum.AdjustUnspentRank(1)
@@ -1,16 +1,16 @@
///The maximum level a Ventrue Bloodsucker can be, before they have to level up their vassal instead.
///The maximum level a Ventrue Bloodsucker can be, before they have to level up their ghoul instead.
#define VENTRUE_MAX_POWERS 3
/datum/bloodsucker_clan/ventrue
name = CLAN_VENTRUE
description = "The Ventrue Clan is extremely snobby with their meals, and refuse to drink blood from people without a mind. \n\
You may have up to %MAX_POWERS% powers, anything further will be ranks to spend on their Favorite Vassal through a Persuasion Rack. \n\
The Favorite Vassal will slowly turn more Vampiric this way, until they finally lose their last bits of Humanity. \n\
Once you finish your embracing, the newly sired vampire will become just a vassal, and you'll be able to sire another bloodsucker."
You may have up to %MAX_POWERS% powers, anything further will be ranks to spend on their Favorite Ghoul through a Persuasion Rack. \n\
The Favorite Ghoul will slowly turn more Vampiric this way, until they finally lose their last bits of Humanity. \n\
Once you finish your embracing, the newly sired vampire will become just a ghoul, and you'll be able to sire another bloodsucker."
clan_objective = /datum/objective/bloodsucker/embrace
join_icon_state = "ventrue"
join_description = "Lose the ability to drink from mindless mobs, can't level up or gain new powers, \
instead you raise a vassal into a Bloodsucker."
instead you raise a ghoul into a Bloodsucker."
blood_drink_type = BLOODSUCKER_DRINK_SNOBBY
level_cost = BLOODSUCKER_LEVELUP_PERCENTAGE_VENTRUE
@@ -29,47 +29,47 @@
/datum/bloodsucker_clan/ventrue/spend_rank(datum/antagonist/bloodsucker/source, cost_rank = TRUE, blood_cost)
if(has_enough_abilities())
to_chat(bloodsuckerdatum.owner.current, span_danger("You can only have up to [VENTRUE_MAX_POWERS] powers, anything further must be ranks to spend on your Favorite Vassal through a Persuasion Rack."))
to_chat(bloodsuckerdatum.owner.current, span_danger("You can only have up to [VENTRUE_MAX_POWERS] powers, anything further must be ranks to spend on your Favorite Ghoul through a Persuasion Rack."))
return FALSE
. = ..()
/datum/bloodsucker_clan/ventrue/proc/finish_spend_rank(datum/antagonist/vassal/vassaldatum, cost_rank, blood_cost)
/datum/bloodsucker_clan/ventrue/proc/finish_spend_rank(datum/antagonist/ghoul/ghouldatum, cost_rank, blood_cost)
finalize_spend_rank(bloodsuckerdatum, cost_rank, blood_cost)
vassaldatum.LevelUpPowers()
ghouldatum.LevelUpPowers()
/datum/bloodsucker_clan/ventrue/interact_with_vassal(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/favorite/vassaldatum)
/datum/bloodsucker_clan/ventrue/interact_with_ghoul(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/favorite/ghouldatum)
. = ..()
if(.)
return TRUE
if(!istype(vassaldatum))
if(!istype(ghouldatum))
return FALSE
to_chat(bloodsuckerdatum.owner.current, span_warning("Do you wish to Rank [vassaldatum.owner.current] up?"))
to_chat(bloodsuckerdatum.owner.current, span_warning("Do you wish to Rank [ghouldatum.owner.current] up?"))
to_chat(bloodsuckerdatum.owner.current, span_warning("This will use [bloodsuckerdatum.GetUnspentRank() >= 1 ? "a unspent Rank" : "[bloodsuckerdatum.get_level_cost()] Blood Thickening Points"]!"))
var/static/list/rank_options = list(
"Yes" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_yes"),
"No" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_no"),
)
var/rank_response = show_radial_menu(bloodsuckerdatum.owner.current, vassaldatum.owner.current, rank_options, radius = 36, require_near = TRUE)
var/rank_response = show_radial_menu(bloodsuckerdatum.owner.current, ghouldatum.owner.current, rank_options, radius = 36, require_near = TRUE)
if(rank_response == "Yes")
if(!bloodsuckerdatum.GetUnspentRank() >= 1 && !source.blood_level_gain(FALSE))
to_chat(bloodsuckerdatum.owner.current, span_danger("You don't have any levels or enough blood thickening points to Rank [vassaldatum.owner.current] up with."))
to_chat(bloodsuckerdatum.owner.current, span_danger("You don't have any levels or enough blood thickening points to Rank [ghouldatum.owner.current] up with."))
return FALSE
return vassal_level(vassaldatum)
return ghoul_level(ghouldatum)
return FALSE
/datum/bloodsucker_clan/ventrue/proc/vassal_level(datum/antagonist/vassal/favorite/vassaldatum)
var/list/options = list_available_powers(vassaldatum.bloodsucker_powers)
var/mob/living/carbon/human/target = vassaldatum.owner.current
/datum/bloodsucker_clan/ventrue/proc/ghoul_level(datum/antagonist/ghoul/favorite/ghouldatum)
var/list/options = list_available_powers(ghouldatum.bloodsucker_powers)
var/mob/living/carbon/human/target = ghouldatum.owner.current
var/datum/action/cooldown/bloodsucker/choice = choose_powers(
"You have the opportunity to level up your Favorite Vassal. Select a power you wish them to recieve.",
"You have the opportunity to level up your Favorite Ghoul. Select a power you wish them to recieve.",
"A wise master's hand is neccesary",
options
)
if(!choice)
return FALSE
var/power_name = initial(choice.name)
if(!vassaldatum.BuyPower(choice, vassaldatum.bloodsucker_powers))
if(!ghouldatum.BuyPower(choice, ghouldatum.bloodsucker_powers))
bloodsuckerdatum.owner.current.balloon_alert(bloodsuckerdatum.owner.current, "[target] already knows [power_name]!")
return FALSE
bloodsuckerdatum.owner.current.balloon_alert(bloodsuckerdatum.owner.current, "taught [power_name]!")
@@ -78,14 +78,14 @@
target.balloon_alert(target, "learned [power_name]!")
to_chat(target, span_notice("Your master taught you how to use [power_name]!"))
vassaldatum.vassal_level++
finish_spend_rank(vassaldatum, TRUE, FALSE)
bloodsuckerify(vassaldatum)
ghouldatum.ghoul_level++
finish_spend_rank(ghouldatum, TRUE, FALSE)
bloodsuckerify(ghouldatum)
return TRUE
/datum/bloodsucker_clan/ventrue/proc/bloodsuckerify(datum/antagonist/vassal/favorite/vassaldatum)
var/mob/living/carbon/human/target = vassaldatum.owner.current
var/stage = vassaldatum.vassal_level
/datum/bloodsucker_clan/ventrue/proc/bloodsuckerify(datum/antagonist/ghoul/favorite/ghouldatum)
var/mob/living/carbon/human/target = ghouldatum.owner.current
var/stage = ghouldatum.ghoul_level
var/list/traits_possible = list(
list(TRAIT_COLDBLOODED, TRAIT_NOBREATH, TRAIT_AGEUSIA),
list(TRAIT_NOCRITDAMAGE, TRAIT_NOSOFTCRIT, TRAIT_SLEEPIMMUNE, TRAIT_VIRUSIMMUNE),
@@ -93,6 +93,7 @@
)
var/traits_to_add = length(traits_possible) >= stage ? traits_possible[stage] : list()
switch(stage)
if(1)
to_chat(target, span_notice("Your blood begins to feel cold, and as a mote of ash lands upon your tongue, you stop breathing..."))
@@ -111,14 +112,15 @@
to_chat(target, span_notice("You feel your heart stop pumping for the last time as you begin to thirst for blood, you feel... dead."))
// Unfavorites you, so the ventrue isn't stuck with you forever
var/powers_to_transfer = list()
// Get rid of the favorite datum and replace with a normal vassal datum
if(vassaldatum)
vassaldatum.silent = TRUE
for(var/datum/power as anything in vassaldatum.bloodsucker_powers)
// Get rid of the favorite datum and replace with a normal ghoul datum
if(ghouldatum)
ghouldatum.silent = TRUE
for(var/datum/power as anything in ghouldatum.bloodsucker_powers)
powers_to_transfer += power.type
target.mind.remove_antag_datum(/datum/antagonist/vassal/favorite)
target.mind.remove_antag_datum(/datum/antagonist/ghoul/favorite)
else
target.remove_traits(flatten_list(traits_to_add), VASSAL_TRAIT)
target.remove_traits(flatten_list(traits_to_add), GHOUL_TRAIT)
var/datum/antagonist/bloodsucker/vamp = new()
vamp.ventrue_sired = bloodsuckerdatum
@@ -127,12 +129,14 @@
// Check for the recuperate power and remove it if they have it
bloodsuckerdatum.owner.current.add_mood_event("madevamp", /datum/mood_event/madevamp)
if(vassaldatum && QDELETED(vassaldatum) && length(traits_to_add))
target.add_traits(traits_to_add, VASSAL_TRAIT)
vassaldatum.traits += traits_to_add
/datum/bloodsucker_clan/ventrue/favorite_vassal_gain(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
to_chat(source.owner.current, span_announce("* Bloodsucker Tip: You can now upgrade your Favorite Vassal by buckling them onto a persuasion rack!"))
vassaldatum.BuyPower(/datum/action/cooldown/bloodsucker/distress)
if(ghouldatum && QDELETED(ghouldatum) && length(traits_to_add))
target.add_traits(traits_to_add, GHOUL_TRAIT)
ghouldatum.traits += traits_to_add
/datum/bloodsucker_clan/ventrue/favorite_ghoul_gain(datum/antagonist/bloodsucker/source, datum/antagonist/ghoul/ghouldatum)
to_chat(source.owner.current, span_announce("* Bloodsucker Tip: You can now upgrade your Favorite Ghoul by buckling them onto a persuasion rack!"))
ghouldatum.BuyPower(/datum/action/cooldown/bloodsucker/distress)
#undef VENTRUE_MAX_POWERS
@@ -26,7 +26,7 @@
check_flags = AB_CHECK_INCAPACITATED|AB_CHECK_CONSCIOUS|AB_CHECK_PHASED
var/bloodsucker_check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY
/// Who can purchase the Power
var/purchase_flags = NONE // BLOODSUCKER_CAN_BUY|BLOODSUCKER_DEFAULT_POWER|TREMERE_CAN_BUY|VASSAL_CAN_BUY
var/purchase_flags = NONE // BLOODSUCKER_CAN_BUY|BLOODSUCKER_DEFAULT_POWER|TREMERE_CAN_BUY|GHOUL_CAN_BUY
// VARS //
/// If the Power is currently active, differs from action cooldown because of how powers are handled.
@@ -15,7 +15,7 @@
At level 4, you will be able to run while cloaked."
power_flags = BP_CONTINUOUS_EFFECT
check_flags = AB_CHECK_CONSCIOUS
purchase_flags = BLOODSUCKER_CAN_BUY|VASSAL_CAN_BUY
purchase_flags = BLOODSUCKER_CAN_BUY|GHOUL_CAN_BUY
bloodcost = 5
constant_bloodcost = 0.2
cooldown_time = 5 SECONDS
@@ -32,7 +32,7 @@
continue
if(!can_see(watcher, owner))
continue
if(IS_BLOODSUCKER(watcher) || IS_VASSAL(watcher))
if(IS_BLOODSUCKER(watcher) || IS_GHOUL(watcher))
continue
owner.balloon_alert(owner, "you can only vanish unseen.")
return FALSE
@@ -133,7 +133,7 @@
target_ref = null
return FALSE
if(owner.pulling == feed_target && owner.grab_state >= GRAB_AGGRESSIVE)
if(!IS_BLOODSUCKER(feed_target) && !IS_VASSAL(feed_target) && !IS_MONSTERHUNTER(feed_target))
if(!IS_BLOODSUCKER(feed_target) && !IS_GHOUL(feed_target) && !IS_MONSTERHUNTER(feed_target))
feed_target.Unconscious(get_sleep_time())
if(!feed_target.density)
feed_target.Move(owner.loc)
@@ -159,7 +159,7 @@
continue
if(watchers.is_blind() || watchers.is_nearsighted_currently())
continue
if(IS_BLOODSUCKER(watchers) || IS_VASSAL(watchers) || HAS_TRAIT(watchers.mind, TRAIT_BLOODSUCKER_HUNTER))
if(IS_BLOODSUCKER(watchers) || IS_GHOUL(watchers) || HAS_TRAIT(watchers.mind, TRAIT_BLOODSUCKER_HUNTER))
continue
owner.balloon_alert(owner, "feed noticed!")
bloodsuckerdatum_power.give_masquerade_infraction()
@@ -5,7 +5,7 @@
button_icon_state = "power_fortitude"
power_flags = BP_CONTINUOUS_EFFECT|BP_AM_COSTLESS_UNCONSCIOUS
check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY
purchase_flags = BLOODSUCKER_CAN_BUY|VASSAL_CAN_BUY
purchase_flags = BLOODSUCKER_CAN_BUY|GHOUL_CAN_BUY
cooldown_time = 20 SECONDS
bloodcost = 30
constant_bloodcost = 0.2
@@ -31,7 +31,7 @@
if(level_current >= FORTITUDE_STUN_IMMUNITY_LEVEL)
ADD_TRAIT(owner, TRAIT_STUNIMMUNE, BLOODSUCKER_TRAIT)
var/mob/living/carbon/human/bloodsucker_user = owner
if(IS_BLOODSUCKER(owner) || IS_VASSAL(owner))
if(IS_BLOODSUCKER(owner) || IS_GHOUL(owner))
fortitude_resist = GetFortitudeResist()
bloodsucker_user.physiology.brute_mod *= fortitude_resist
bloodsucker_user.physiology.burn_mod *= GetBurnResist()
@@ -91,7 +91,7 @@
if(!. || !ishuman(owner))
return
var/mob/living/carbon/human/bloodsucker_user = owner
if(IS_BLOODSUCKER(owner) || IS_VASSAL(owner) && fortitude_resist)
if(IS_BLOODSUCKER(owner) || IS_GHOUL(owner) && fortitude_resist)
bloodsucker_user.physiology.brute_mod /= fortitude_resist
bloodsucker_user.physiology.burn_mod /= fortitude_resist + 0.2
bloodsucker_user.physiology.stamina_mod /= fortitude_resist
@@ -10,7 +10,7 @@
*/
/datum/action/cooldown/bloodsucker/gohome
name = "Vanishing Act"
desc = "As dawn aproaches, disperse into mist and return directly to your Lair.<br><b>WARNING:</b> You will drop <b>ALL</b> of your possessions if observed by mortals."
desc = "As dawn aproaches, disperse into mist and return directly to your Haven.<br><b>WARNING:</b> You will drop <b>ALL</b> of your possessions if observed by mortals."
button_icon_state = "power_gohome"
active_background_icon_state = "vamp_power_off_oneshot"
base_background_icon_state = "vamp_power_off_oneshot"
@@ -43,7 +43,7 @@
. = ..()
if(!.)
return FALSE
/// Have No Lair (NOTE: You only got this power if you had a lair, so this means it's destroyed)
/// Have No Haven (NOTE: You only got this power if you had a haven, so this means it's destroyed)
if(!istype(bloodsuckerdatum_power) || !bloodsuckerdatum_power.coffin)
owner.balloon_alert(owner, "coffin was destroyed!")
return FALSE
@@ -105,7 +105,7 @@
continue
if(watchers.is_blind())
continue
if(!IS_BLOODSUCKER(watchers) && !IS_VASSAL(watchers))
if(!IS_BLOODSUCKER(watchers) && !IS_GHOUL(watchers))
drop_item = TRUE
break
// Drop all necessary items (handcuffs, legcuffs, items if seen)
@@ -5,7 +5,7 @@
name = "Brawn"
desc = "Snap restraints, break lockers and doors at higher levels, or deal terrible damage with your bare hands."
button_icon_state = "power_strength"
purchase_flags = BLOODSUCKER_CAN_BUY|VASSAL_CAN_BUY
purchase_flags = BLOODSUCKER_CAN_BUY|GHOUL_CAN_BUY
bloodcost = 10
cooldown_time = 12 SECONDS
target_range = 1
@@ -9,7 +9,7 @@
desc = "Force yourself to stand up if you're down and dash somewhere with supernatural speed. Those nearby may be knocked away, stunned, or left empty-handed."
button_icon_state = "power_speed"
prefire_message = "You prepare to dash!"
purchase_flags = BLOODSUCKER_CAN_BUY|VASSAL_CAN_BUY
purchase_flags = BLOODSUCKER_CAN_BUY|GHOUL_CAN_BUY
bloodcost = 6
cooldown_time = 12 SECONDS
target_range = 5
@@ -6,7 +6,7 @@
desc = "Spring at your target 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"
check_flags = AB_CHECK_CONSCIOUS|AB_CHECK_INCAPACITATED|AB_CHECK_LYING|AB_CHECK_PHASED|AB_CHECK_LYING
purchase_flags = BLOODSUCKER_CAN_BUY|VASSAL_CAN_BUY
purchase_flags = BLOODSUCKER_CAN_BUY|GHOUL_CAN_BUY
bloodcost = 10
cooldown_time = 10 SECONDS
power_activates_immediately = FALSE
@@ -14,7 +14,7 @@
name = "Mesmerize"
button_icon_state = "power_mez"
power_flags = NONE
purchase_flags = BLOODSUCKER_CAN_BUY|VASSAL_CAN_BUY
purchase_flags = BLOODSUCKER_CAN_BUY|GHOUL_CAN_BUY
bloodcost = 30
cooldown_time = 30 SECONDS
target_range = 4
@@ -3,7 +3,7 @@
desc = "Become mist and advance two tiles in one direction. Useful for skipping past doors and barricades."
button_icon_state = "power_tres"
bloodsucker_check_flags = BP_CANT_USE_IN_TORPOR
purchase_flags = BLOODSUCKER_CAN_BUY|VASSAL_CAN_BUY
purchase_flags = BLOODSUCKER_CAN_BUY|GHOUL_CAN_BUY
bloodcost = 10
cooldown_time = 8 SECONDS
prefire_message = "Select a destination."
@@ -100,7 +100,7 @@
new /obj/effect/particle_effect/fluid/smoke/vampsmoke(targeted_turf)
for(var/mob/living/carbon/living_mob in range(1, targeted_turf)-user)
if(IS_BLOODSUCKER(living_mob) || IS_VASSAL(living_mob))
if(IS_BLOODSUCKER(living_mob) || IS_GHOUL(living_mob))
continue
if(level_current >= AUSPEX_BLEED_LEVEL)
var/obj/item/bodypart/bodypart = pick(living_mob.bodyparts)
@@ -4,13 +4,13 @@
* Level 1 - Mesmerizes target
* Level 2 - Mesmerizes and mutes target
* Level 3 - Mesmerizes, blinds and mutes target
* Level 4 - Target (if at least in crit & has a mind) will revive as a Mute/Deaf Vassal for 5 minutes before dying.
* Level 5 - Target (if at least in crit & has a mind) will revive as a Vassal for 8 minutes before dying.
* Level 4 - Target (if at least in crit & has a mind) will revive as a Mute/Deaf Ghoul for 5 minutes before dying.
* Level 5 - Target (if at least in crit & has a mind) will revive as a Ghoul for 8 minutes before dying.
*/
#define TEMP_VASSALIZE_COST 150
#define TEMP_GHOULIZE_COST 150
#define DOMINATE_XRAY_LEVEL 3
#define DOMINATE_NON_MUTE_VASSALIZE_LEVEL 4
#define DOMINATE_NON_MUTE_GHOULIZE_LEVEL 4
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate
name = "Dominate"
button_icon_state = "power_auspex"
@@ -43,8 +43,8 @@
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/get_power_desc_extended()
. = ..()
if(level_current >= DOMINATE_VASSALIZE_LEVEL)
. += "If your target is in critical condition or dead, they will instead be turned into a temporary Vassal. This will cost [TEMP_VASSALIZE_COST] blood. Pre-existing dead vassals will simply be revived."
if(level_current >= DOMINATE_GHOULIZE_LEVEL)
. += "If your target is in critical condition or dead, they will instead be turned into a temporary Ghoul. This will cost [TEMP_GHOULIZE_COST] blood. Pre-existing dead ghouls will simply be revived."
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/get_power_explanation_extended()
. = list()
@@ -53,16 +53,16 @@
. += "A left click will completely immobilize, and blind them for the next [DisplayTimeText(get_power_time())] seconds, and will also mute them for [DisplayTimeText(get_power_time())] seconds."
. += "While this ability is active, you will be able to see additional information about everyone in the room."
. += "At level [DOMINATE_XRAY_LEVEL], you will gain X-Ray vision while this ability is active."
. += "At level [DOMINATE_VASSALIZE_LEVEL], while adjacent to the target, if your target is in critical condition or dead, they will instead be turned into a temporary Vassal. This will cost [TEMP_VASSALIZE_COST] blood."
. += "The victim must have atleast [BLOOD_VOLUME_BAD] blood to be vassalized."
. += "The vassal will be mute and deaf if the level of [src] is not at least [DOMINATE_NON_MUTE_VASSALIZE_LEVEL]"
. += "If you use this on a currently dead normal Vassal, they will will not suddenly cease to live as if a temporary Vassal."
. += "They will have complete loyalty to you, until their death in [DisplayTimeText(get_vassal_duration())] upon use."
. += "Vassalizing or reviving a vassal will make this ability go on cooldown for [DisplayTimeText(get_vassalize_cooldown())]."
. += "At level [DOMINATE_GHOULIZE_LEVEL], while adjacent to the target, if your target is in critical condition or dead, they will instead be turned into a temporary Ghoul. This will cost [TEMP_GHOULIZE_COST] blood."
. += "The victim must have atleast [BLOOD_VOLUME_BAD] blood to be ghoulized."
. += "The ghoul will be mute and deaf if the level of [src] is not at least [DOMINATE_NON_MUTE_GHOULIZE_LEVEL]"
. += "If you use this on a currently dead normal Ghoul, they will will not suddenly cease to live as if a temporary Ghoul."
. += "They will have complete loyalty to you, until their death in [DisplayTimeText(get_ghoul_duration())] upon use."
. += "Ghoulizing or reviving a ghoul will make this ability go on cooldown for [DisplayTimeText(get_ghoulize_cooldown())]."
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/CheckCanTarget(atom/target_atom)
var/mob/living/selected_target = target_atom
if(level_current >= DOMINATE_VASSALIZE_LEVEL && (IS_VASSAL(selected_target) || selected_target.stat >= SOFT_CRIT))
if(level_current >= DOMINATE_GHOULIZE_LEVEL && (IS_GHOUL(selected_target) || selected_target.stat >= SOFT_CRIT))
if(selected_target?.mind && owner.Adjacent(selected_target))
return TRUE
. = ..()
@@ -99,59 +99,59 @@
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/FireTargetedPower(atom/target, params)
var/mob/living/target_mob = target
var/mob/living/user = owner
if(target_mob.stat != CONSCIOUS && level_current >= DOMINATE_VASSALIZE_LEVEL)
if(target_mob.stat != CONSCIOUS && level_current >= DOMINATE_GHOULIZE_LEVEL)
if(user.Adjacent(target))
attempt_vassalize(target, user)
attempt_ghoulize(target, user)
else
if(IS_VASSAL(target_mob))
if(IS_GHOUL(target_mob))
owner.balloon_alert(owner, "too far to revive!")
else
owner.balloon_alert(owner, "too far to vassalize!")
owner.balloon_alert(owner, "too far to ghoulize!")
return TRUE
return ..()
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/proc/attempt_vassalize(mob/living/target, mob/living/user)
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/proc/attempt_ghoulize(mob/living/target, mob/living/user)
owner.face_atom(target)
var/datum/antagonist/vassal/vassal = IS_VASSAL(target)
var/datum/antagonist/ghoul/ghoul = IS_GHOUL(target)
if(!victim_has_blood(target))
return FALSE
if(vassal)
if(ghoul)
owner.balloon_alert(owner, "attempting to revive.")
else
owner.balloon_alert(owner, "attempting to vassalize.")
owner.balloon_alert(owner, "attempting to ghoulize.")
if(!do_after(user, 6 SECONDS, target, NONE, TRUE))
return FALSE
if(!victim_has_blood(target))
return FALSE
if(vassal?.master == bloodsuckerdatum_power)
if(ghoul?.master == bloodsuckerdatum_power)
if(target.stat != DEAD)
owner.balloon_alert(owner, "not dead!")
return FALSE
PowerActivatedSuccesfully(get_vassalize_cooldown())
PowerActivatedSuccesfully(get_ghoulize_cooldown())
to_chat(user, span_warning("We revive [target]!"))
owner.balloon_alert(owner, "successfully revived!")
target.mind?.grab_ghost()
target.revive(ADMIN_HEAL_ALL)
pay_cost(TEMP_VASSALIZE_COST - bloodcost)
log_combat(owner, target, "tremere revived", addition="Revived their vassal using dominate")
pay_cost(TEMP_GHOULIZE_COST - bloodcost)
log_combat(owner, target, "tremere revived", addition="Revived their ghoul using dominate")
return FALSE
if(!bloodsuckerdatum_power.make_vassal(target) )
owner.balloon_alert(owner, "not a valid target for vassalization!.")
if(!bloodsuckerdatum_power.make_ghoul(target) )
owner.balloon_alert(owner, "not a valid target for ghoulization!.")
return
/*if(IS_MONSTERHUNTER(target))
to_chat(target, span_notice("Their body refuses to react..."))
return*/
PowerActivatedSuccesfully(get_vassalize_cooldown())
PowerActivatedSuccesfully(get_ghoulize_cooldown())
to_chat(user, span_warning("We revive [target]!"))
// no escaping at this point
target.mind?.grab_ghost(TRUE)
target.revive(ADMIN_HEAL_ALL)
var/datum/antagonist/vassal/vassaldatum = target.mind.has_antag_datum(/datum/antagonist/vassal)
vassaldatum.special_type = TREMERE_VASSAL //don't turn them into a favorite please
var/living_time = get_vassal_duration()
log_combat(owner, target, "tremere mindslaved", addition="Revived and converted [target] into a temporary tremere vassal for [DisplayTimeText(living_time)].")
if(level_current <= DOMINATE_NON_MUTE_VASSALIZE_LEVEL)
var/datum/antagonist/ghoul/ghouldatum = target.mind.has_antag_datum(/datum/antagonist/ghoul)
ghouldatum.special_type = TREMERE_GHOUL //don't turn them into a favorite please
var/living_time = get_ghoul_duration()
log_combat(owner, target, "tremere mindslaved", addition="Revived and converted [target] into a temporary tremere ghoul for [DisplayTimeText(living_time)].")
if(level_current <= DOMINATE_NON_MUTE_GHOULIZE_LEVEL)
target.add_traits(list(TRAIT_MUTE, TRAIT_DEAF), DOMINATE_TRAIT)
user.balloon_alert(target, "only [DisplayTimeText(living_time)] left to live!")
to_chat(target, span_warning("You will only live for [DisplayTimeText(living_time)]! Obey your master and go out in a blaze of glory!"))
@@ -160,13 +160,13 @@
setup_timer(user, target, living_time, timer_id)
thralls += target
RegisterSignals(target, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING), PROC_REF(end_possession), timer_id)
RegisterSignal(vassaldatum, COMSIG_ANTAGONIST_REMOVED, PROC_REF(on_antag_datum_removal), target, timer_id)
pay_cost(TEMP_VASSALIZE_COST - bloodcost)
RegisterSignal(ghouldatum, COMSIG_ANTAGONIST_REMOVED, PROC_REF(on_antag_datum_removal), target, timer_id)
pay_cost(TEMP_GHOULIZE_COST - bloodcost)
return TRUE
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/proc/victim_has_blood(mob/living/target)
// you can always revive non-temporary vassals
if(IS_VASSAL(target))
// you can always revive non-temporary ghouls
if(IS_GHOUL(target))
return TRUE
if(target.blood_volume < BLOOD_VOLUME_BAD)
owner.balloon_alert(owner, "not enough blood in victim!")
@@ -175,15 +175,15 @@
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/proc/setup_timer(mob/living/user, mob/living/target, living_time, timer_id)
var/list/show_to = list(user, target)
if(bloodsuckerdatum_power && length(bloodsuckerdatum_power.vassals))
for(var/datum/antagonist/vassal in bloodsuckerdatum_power.vassals)
if(!vassal?.owner?.current)
if(bloodsuckerdatum_power && length(bloodsuckerdatum_power.ghouls))
for(var/datum/antagonist/ghoul in bloodsuckerdatum_power.ghouls)
if(!ghoul?.owner?.current)
continue
show_to += vassal.owner.current
show_to += ghoul.owner.current
new /atom/movable/screen/text/screen_timer/attached(null, show_to, timer_id, "Dies in ${timer}", null, null, target)
new /atom/movable/screen/text/screen_timer(null, target, timer_id, "You die in ${timer}")
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/proc/on_antag_datum_removal(datum/antagonist/vassal, mob/living/thrall, timer_id)
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/proc/on_antag_datum_removal(datum/antagonist/ghoul, mob/living/thrall, timer_id)
end_possession(thrall, timer_id)
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/proc/end_possession(mob/living/user, timer_id)
@@ -197,20 +197,20 @@
user.remove_traits(list(TRAIT_MUTE, TRAIT_DEAF), DOMINATE_TRAIT)
if(!HAS_TRAIT(user, TRAIT_NOBLOOD))
user.blood_volume = 0
if(!IS_VASSAL(user))
if(!IS_GHOUL(user))
to_chat(user, span_warning("You feel the blood keeping you alive run out!"))
return
to_chat(user, span_warning("You feel the Blood of your Master run out!"))
user.mind?.remove_antag_datum(/datum/antagonist/vassal)
user.mind?.remove_antag_datum(/datum/antagonist/ghoul)
if(user.stat == DEAD)
return
user.death()
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/proc/get_vassal_duration()
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/proc/get_ghoul_duration()
return 4 MINUTES * max(level_current, 1)
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/proc/get_vassalize_cooldown()
/datum/action/cooldown/bloodsucker/targeted/mesmerize/dominate/proc/get_ghoulize_cooldown()
return cooldown_time * 3
#undef TEMP_VASSALIZE_COST
#undef TEMP_GHOULIZE_COST
#undef DOMINATE_XRAY_LEVEL
@@ -195,8 +195,8 @@
for(var/mob/living/possible_target as anything in orange(1, target))
if(!ismob(possible_target))
continue
var/datum/antagonist/vassal/vassal = IS_VASSAL(possible_target)
if(length(bloodsuckerdatum_power?.vassals) && vassal && (vassal in bloodsuckerdatum_power?.vassals))
var/datum/antagonist/ghoul/ghoul = IS_GHOUL(possible_target)
if(length(bloodsuckerdatum_power?.ghouls) && ghoul && (ghoul in bloodsuckerdatum_power?.ghouls))
continue
targets += possible_target
if(length(targets))
@@ -14,10 +14,10 @@
/datum/action/cooldown/bloodsucker/distress/ActivatePower(trigger_flags)
. = ..()
var/turf/open/floor/target_area = get_area(owner)
var/datum/antagonist/vassal/vassaldatum = owner.mind.has_antag_datum(/datum/antagonist/vassal)
var/datum/antagonist/ghoul/ghouldatum = owner.mind.has_antag_datum(/datum/antagonist/ghoul)
owner.balloon_alert(owner, "you call out for your master!")
to_chat(vassaldatum.master.owner, "<span class='userdanger'>[owner], your loyal Vassal, is desperately calling for aid at [target_area]!</span>")
to_chat(ghouldatum.master.owner, "<span class='userdanger'>[owner], your loyal Ghoul, is desperately calling for aid at [target_area]!</span>")
var/mob/living/user = owner
user.adjustBruteLoss(10)
@@ -1,4 +1,4 @@
/// Used by Vassals
/// Used by Ghouls
/datum/action/cooldown/bloodsucker/recuperate
name = "Sanguine Recuperation"
desc = "Slowly heals you overtime using your master's blood, in exchange for some of your own blood and effort."
@@ -39,12 +39,12 @@
if(!active)
return
var/mob/living/carbon/user = owner
var/datum/antagonist/vassal/vassaldatum = IS_VASSAL(user)
if(!vassaldatum || QDELETED(vassaldatum.master))
var/datum/antagonist/ghoul/ghouldatum = IS_GHOUL(user)
if(!ghouldatum || QDELETED(ghouldatum.master))
to_chat(owner, span_warning("No master to draw blood from!"))
DeactivatePower()
return
vassaldatum.master.AdjustBloodVolume(-1)
ghouldatum.master.AdjustBloodVolume(-1)
user.set_timed_status_effect(5 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE)
user.adjustStaminaLoss(bloodcost * 1.1)
user.adjustBruteLoss(-2.5, updating_health = FALSE)
@@ -1,12 +1,12 @@
/datum/action/cooldown/bloodsucker/vassal_blood
name = "Help Vassal"
desc = "Bring an ex-Vassal back into the fold, or create blood using a bag. RMB: Check Vassal status."
/datum/action/cooldown/bloodsucker/ghoul_blood
name = "Help Ghoul"
desc = "Bring an ex-Ghoul back into the fold, or create blood using a bag. RMB: Check Ghoul status."
button_icon_state = "power_torpor"
power_explanation = "Help Vassal:\n\
Use this power while you have an ex-Vassal grabbed to bring them back into the fold. \
power_explanation = "Help Ghoul:\n\
Use this power while you have an ex-Ghoul grabbed to bring them back into the fold. \
Use this power with a bloodbag in your hand to instead fill it with Vampiric Blood which \
can be used to reset ex-vassal deconversion timers. \
Right-Click will show the status of all Vassals."
can be used to reset ex-ghoul deconversion timers. \
Right-Click will show the status of all Ghouls."
check_flags = NONE
purchase_flags = NONE
bloodcost = 10
@@ -17,25 +17,25 @@
///Weakref to a target we're bringing into the fold.
var/datum/weakref/target_ref
/datum/action/cooldown/bloodsucker/vassal_blood/can_use(mob/living/carbon/user, trigger_flags)
/datum/action/cooldown/bloodsucker/ghoul_blood/can_use(mob/living/carbon/user, trigger_flags)
. = ..()
if(!.)
return FALSE
var/datum/antagonist/vassal/revenge/revenge_vassal = IS_REVENGE_VASSAL(owner)
if(revenge_vassal)
var/datum/antagonist/ghoul/revenge/revenge_ghoul = IS_REVENGE_GHOUL(owner)
if(revenge_ghoul)
return FALSE
if(trigger_flags & TRIGGER_SECONDARY_ACTION)
if(!revenge_vassal.ex_vassals.len)
owner.balloon_alert(owner, "no vassals!")
if(!revenge_ghoul.ex_ghouls.len)
owner.balloon_alert(owner, "no ghouls!")
return FALSE
return TRUE
if(owner.pulling && isliving(owner.pulling))
var/mob/living/pulled_target = owner.pulling
var/datum/antagonist/ex_vassal/former_vassal = IS_EX_VASSAL(pulled_target)
if(!former_vassal)
owner.balloon_alert(owner, "not a former vassal!")
var/datum/antagonist/ex_ghoul/former_ghoul = IS_EX_GHOUL(pulled_target)
if(!former_ghoul)
owner.balloon_alert(owner, "not a former ghoul!")
return FALSE
target_ref = WEAKREF(owner.pulling)
return TRUE
@@ -50,17 +50,17 @@
bloodbag = blood_bag
return TRUE
/datum/action/cooldown/bloodsucker/vassal_blood/ActivatePower(trigger_flags)
/datum/action/cooldown/bloodsucker/ghoul_blood/ActivatePower(trigger_flags)
. = ..()
var/datum/antagonist/vassal/revenge/revenge_vassal = IS_REVENGE_VASSAL(owner)
var/datum/antagonist/ghoul/revenge/revenge_ghoul = IS_REVENGE_GHOUL(owner)
if(trigger_flags & TRIGGER_SECONDARY_ACTION)
for(var/datum/antagonist/ex_vassal/former_vassals as anything in revenge_vassal.ex_vassals)
var/information = "[former_vassals.owner.current]"
information += " - has [round(COOLDOWN_TIMELEFT(former_vassals, blood_timer) / 600)] minutes left of Blood"
for(var/datum/antagonist/ex_ghoul/former_ghouls as anything in revenge_ghoul.ex_ghouls)
var/information = "[former_ghouls.owner.current]"
information += " - has [round(COOLDOWN_TIMELEFT(former_ghouls, blood_timer) / 600)] minutes left of Blood"
var/turf/open/floor/target_area = get_area(owner)
if(target_area)
information += " - currently at [target_area]."
if(former_vassals.owner.current.stat >= DEAD)
if(former_ghouls.owner.current.stat >= DEAD)
information += " - DEAD."
to_chat(owner, "[information]")
@@ -70,12 +70,12 @@
if(target_ref)
var/mob/living/target = target_ref.resolve()
var/datum/antagonist/ex_vassal/former_vassal = IS_EX_VASSAL(target)
if(!former_vassal || former_vassal.revenge_vassal)
var/datum/antagonist/ex_ghoul/former_ghoul = IS_EX_GHOUL(target)
if(!former_ghoul || former_ghoul.revenge_ghoul)
target_ref = null
return
if(do_after(owner, 5 SECONDS, target))
former_vassal.return_to_fold(revenge_vassal)
former_ghoul.return_to_fold(revenge_ghoul)
target_ref = null
DeactivatePower()
return FALSE
@@ -14,11 +14,11 @@
/datum/antagonist/bloodsucker/proc/claim_coffin(obj/structure/closet/crate/claimed, area/current_area)
if(!can_claim_coffin(claimed, current_area))
return FALSE
// This is my Lair
// This is my Haven
coffin = claimed
bloodsucker_lair_area = current_area
to_chat(owner, span_userdanger("You have claimed the [claimed] as your place of immortal rest! Your lair is now [bloodsucker_lair_area]."))
to_chat(owner, span_announce("Bloodsucker Tip: Find new lair recipes in the Structures tab of the <i>Crafting Menu</i>, including the <i>Persuasion Rack</i> for converting crew into Vassals."))
bloodsucker_haven_area = current_area
to_chat(owner, span_userdanger("You have claimed the [claimed] as your place of immortal rest! Your haven is now [bloodsucker_haven_area]."))
to_chat(owner, span_announce("Bloodsucker Tip: Find new haven recipes in the Structures tab of the <i>Crafting Menu</i>, including the <i>Persuasion Rack</i> for converting crew into Ghouls."))
return TRUE
/// From crate.dm
@@ -180,7 +180,7 @@
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(resident)
if(bloodsuckerdatum && bloodsuckerdatum.coffin == src)
bloodsuckerdatum.coffin = null
bloodsuckerdatum.bloodsucker_lair_area = null
bloodsuckerdatum.bloodsucker_haven_area = null
for(var/obj/structure/bloodsucker/bloodsucker_structure in get_area(src))
if(bloodsucker_structure.owner == resident)
bloodsucker_structure.unbolt()
@@ -188,7 +188,7 @@
if(manual)
to_chat(resident, span_cult_italic("You have unclaimed your coffin! This also unclaims all your other Bloodsucker structures!"))
else
to_chat(resident, span_cult_italic("You sense that the link with your coffin and your sacred lair has been broken! You will need to seek another."))
to_chat(resident, span_cult_italic("You sense that the link with your coffin and your sacred haven has been broken! You will need to seek another."))
// Remove resident. Because this object isnt removed from the game immediately (GC?) we need to give them a way to see they don't have a home anymore.
resident = null
@@ -233,7 +233,7 @@
/obj/structure/closet/crate/coffin/proc/prompt_coffin_claim(datum/antagonist/bloodsucker/dracula)
var/area/current_area = get_area(src)
switch(tgui_alert(dracula.owner.current, "Do you wish to claim this as your coffin? [current_area] will be your lair.", "Claim Lair", list("Yes", "No")))
switch(tgui_alert(dracula.owner.current, "Do you wish to claim this as your coffin? [current_area] will be your haven.", "Claim Haven", list("Yes", "No")))
if("Yes")
return claim_coffin(dracula.owner.current, current_area)
return FALSE
@@ -8,7 +8,7 @@
*/
var/ghost_desc
var/vamp_desc
var/vassal_desc
var/ghoul_desc
var/hunter_desc
/obj/structure/bloodsucker/examine(mob/user)
@@ -17,11 +17,11 @@
. += span_cult(ghost_desc)
if(IS_BLOODSUCKER(user) && vamp_desc)
if(!owner)
. += span_cult("It is unsecured. Click on [src] while in your lair to secure it in place to get its full potential.")
. += span_cult("It is unsecured. Click on [src] while in your haven to secure it in place to get its full potential.")
return
. += span_cult(vamp_desc)
if(IS_VASSAL(user) && vassal_desc != "")
. += span_cult(vassal_desc)
if(IS_GHOUL(user) && ghoul_desc != "")
. += span_cult(ghoul_desc)
if(IS_MONSTERHUNTER(user) && hunter_desc != "")
. += span_cult(hunter_desc)
@@ -49,11 +49,11 @@
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(user)
/// Claiming the Rack instead of using it?
if(istype(bloodsuckerdatum) && !owner)
if(!bloodsuckerdatum.bloodsucker_lair_area)
to_chat(user, span_danger("You don't have a lair. Claim a coffin to make that location your lair."))
if(!bloodsuckerdatum.bloodsucker_haven_area)
to_chat(user, span_danger("You don't have a haven. Claim a coffin to make that location your haven."))
return FALSE
if(bloodsuckerdatum.bloodsucker_lair_area != get_area(src))
to_chat(user, span_danger("You may only activate this structure in your lair: [bloodsuckerdatum.bloodsucker_lair_area]."))
if(bloodsuckerdatum.bloodsucker_haven_area != get_area(src))
to_chat(user, span_danger("You may only activate this structure in your haven: [bloodsuckerdatum.bloodsucker_haven_area]."))
return FALSE
/// Radial menu for securing your Persuasion rack in place.
@@ -103,24 +103,24 @@
/obj/item/restraints/legcuffs/beartrap/bloodsucker
*/
/obj/structure/bloodsucker/vassalrack
/obj/structure/bloodsucker/ghoulrack
name = "persuasion rack"
desc = "If this wasn't meant for torture, then someone has some fairly horrifying hobbies."
icon = 'modular_zubbers/icons/obj/structures/vamp_obj.dmi'
icon_state = "vassalrack"
icon_state = "ghoulrack"
anchored = FALSE
density = TRUE
can_buckle = TRUE
buckle_lying = 180
ghost_desc = "This is a Vassal rack, which allows Bloodsuckers to thrall crewmembers into loyal minions."
vamp_desc = "This is the Vassal rack, which allows you to thrall crewmembers into loyal minions in your service.\n\
Simply click and hold on a victim, and then drag their sprite on the vassal rack. Right-click on the vassal rack to unbuckle them.\n\
To convert into a Vassal, repeatedly click on the persuasion rack. The time required scales with the tool in your off hand. This costs Blood to do.\n\
Vassals can be turned into special ones by continuing to torture them once converted."
vassal_desc = "This is the vassal rack, which allows your master to thrall crewmembers into their minions.\n\
ghost_desc = "This is a Ghoul rack, which allows Bloodsuckers to thrall crewmembers into loyal minions."
vamp_desc = "This is the Ghoul rack, which allows you to thrall crewmembers into loyal minions in your service.\n\
Simply click and hold on a victim, and then drag their sprite on the ghoul rack. Right-click on the ghoul rack to unbuckle them.\n\
To convert into a Ghoul, repeatedly click on the persuasion rack. The time required scales with the tool in your off hand. This costs Blood to do.\n\
Ghouls can be turned into special ones by continuing to torture them once converted."
ghoul_desc = "This is the ghoul rack, which allows your master to thrall crewmembers into their minions.\n\
Aid your master in bringing their victims here and keeping them secure.\n\
You can secure victims to the vassal rack by click dragging the victim onto the rack while it is secured."
hunter_desc = "This is the vassal rack, which monsters use to brainwash crewmembers into their loyal slaves.\n\
You can secure victims to the ghoul rack by click dragging the victim onto the rack while it is secured."
hunter_desc = "This is the ghoul rack, which monsters use to brainwash crewmembers into their loyal slaves.\n\
They usually ensure that victims are handcuffed, to prevent them from running away.\n\
Their rituals take time, allowing us to disrupt it."
@@ -131,30 +131,30 @@
/// Prevents popup spam.
var/disloyalty_offered = FALSE
/obj/structure/bloodsucker/vassalrack/examine(mob/user)
/obj/structure/bloodsucker/ghoulrack/examine(mob/user)
. = ..()
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(user)
if(bloodsuckerdatum)
. += span_cult("You can support a total of [convert_integer_to_words(bloodsuckerdatum.max_vassals())] [bloodsuckerdatum.max_vassals() == 1 ? "vassal" : "vassals"], \
with [convert_integer_to_words(bloodsuckerdatum.free_vassal_slots())] [bloodsuckerdatum.free_vassal_slots() == 1 ? "slot" : "slots"] remaining.")
. += span_cult("You can support a total of [convert_integer_to_words(bloodsuckerdatum.max_ghouls())] [bloodsuckerdatum.max_ghouls() == 1 ? "ghoul" : "ghouls"], \
with [convert_integer_to_words(bloodsuckerdatum.free_ghoul_slots())] [bloodsuckerdatum.free_ghoul_slots() == 1 ? "slot" : "slots"] remaining.")
/obj/structure/bloodsucker/vassalrack/atom_deconstruct(disassembled = TRUE)
/obj/structure/bloodsucker/ghoulrack/atom_deconstruct(disassembled = TRUE)
. = ..()
new /obj/item/stack/sheet/iron(src.loc, 4)
new /obj/item/stack/rods(loc, 4)
qdel(src)
/obj/structure/bloodsucker/vassalrack/bolt()
/obj/structure/bloodsucker/ghoulrack/bolt()
. = ..()
density = FALSE
anchored = TRUE
/obj/structure/bloodsucker/vassalrack/unbolt()
/obj/structure/bloodsucker/ghoulrack/unbolt()
. = ..()
density = TRUE
anchored = FALSE
/obj/structure/bloodsucker/vassalrack/mouse_drop_receive(atom/movable/movable_atom, mob/user, params)
/obj/structure/bloodsucker/ghoulrack/mouse_drop_receive(atom/movable/movable_atom, mob/user, params)
var/mob/living/living_target = movable_atom
if(!anchored && IS_BLOODSUCKER(user))
user.balloon_alert(user, "not secured!")
@@ -166,13 +166,13 @@
return
// Don't buckle Silicon to it please.
if(issilicon(living_target))
to_chat(user, span_danger("You realize that this machine cannot be vassalized, therefore it is useless to buckle them."))
to_chat(user, span_danger("You realize that this machine cannot be ghoulized, therefore it is useless to buckle them."))
return
if(do_after(user, 5 SECONDS, living_target))
attach_victim(living_target, user)
/// Attempt Release (Owner vs Non Owner)
/obj/structure/bloodsucker/vassalrack/attack_hand_secondary(mob/user, modifiers)
/obj/structure/bloodsucker/ghoulrack/attack_hand_secondary(mob/user, modifiers)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
@@ -188,9 +188,9 @@
user_unbuckle_mob(buckled_carbons, user)
/**
* Attempts to buckle target into the vassalrack
* Attempts to buckle target into the ghoulrack
*/
/obj/structure/bloodsucker/vassalrack/proc/attach_victim(mob/living/target, mob/living/user)
/obj/structure/bloodsucker/ghoulrack/proc/attach_victim(mob/living/target, mob/living/user)
if(!buckle_mob(target))
return
user.visible_message(
@@ -208,8 +208,8 @@
disloyalty_offered = FALSE
/// Attempt Unbuckle
/obj/structure/bloodsucker/vassalrack/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
if(IS_BLOODSUCKER(user) || IS_VASSAL(user))
/obj/structure/bloodsucker/ghoulrack/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
if(IS_BLOODSUCKER(user) || IS_GHOUL(user))
return ..()
if(buckled_mob == user)
@@ -229,7 +229,7 @@
return ..()
/obj/structure/bloodsucker/vassalrack/unbuckle_mob(mob/living/buckled_mob, force = FALSE, can_fall = TRUE)
/obj/structure/bloodsucker/ghoulrack/unbuckle_mob(mob/living/buckled_mob, force = FALSE, can_fall = TRUE)
. = ..()
if(!.)
return
@@ -238,7 +238,7 @@
buckled_mob.Paralyze(2 SECONDS)
update_appearance(UPDATE_ICON)
/obj/structure/bloodsucker/vassalrack/attack_hand(mob/user, list/modifiers)
/obj/structure/bloodsucker/ghoulrack/attack_hand(mob/user, list/modifiers)
. = ..()
if(!.)
return FALSE
@@ -253,21 +253,21 @@
user_unbuckle_mob(buckled_carbons, user)
return
if(!bloodsuckerdatum.my_clan)
to_chat(user, span_warning("You can't vassalize people until you enter a Clan (Through your Antagonist UI button)"))
to_chat(user, span_warning("You can't ghoulize people until you enter a Clan (Through your Antagonist UI button)"))
user.balloon_alert(user, "join a clan first!")
return
var/datum/antagonist/vassal/vassaldatum = IS_VASSAL(buckled_carbons)
// Are they our Vassal?
if(vassaldatum && (vassaldatum in bloodsuckerdatum.vassals))
SEND_SIGNAL(bloodsuckerdatum, COMSIG_BLOODSUCKER_INTERACT_WITH_VASSAL, vassaldatum)
var/datum/antagonist/ghoul/ghouldatum = IS_GHOUL(buckled_carbons)
// Are they our Ghoul?
if(ghouldatum && (ghouldatum in bloodsuckerdatum.ghouls))
SEND_SIGNAL(bloodsuckerdatum, COMSIG_BLOODSUCKER_INTERACT_WITH_GHOUL, ghouldatum)
return
if(bloodsuckerdatum.free_vassal_slots() < 1)
to_chat(user, span_warning("You can't vassalize more people until you level up more! You are currently at [bloodsuckerdatum.free_vassal_slots()] active / [bloodsuckerdatum.max_vassals()] max vassals."))
user.balloon_alert(user, "not enough vassal slots!")
if(bloodsuckerdatum.free_ghoul_slots() < 1)
to_chat(user, span_warning("You can't ghoulize more people until you level up more! You are currently at [bloodsuckerdatum.free_ghoul_slots()] active / [bloodsuckerdatum.max_ghouls()] max ghouls."))
user.balloon_alert(user, "not enough ghoul slots!")
return
// Not our Vassal, but Alive & We're a Bloodsucker, good to torture!
// Not our Ghoul, but Alive & We're a Bloodsucker, good to torture!
torture_victim(user, buckled_carbons)
/**
@@ -275,20 +275,20 @@
*
* * Tick Down Conversion from 3 to 0
* * Break mindshielding/antag (on approve)
* * Vassalize target
* * Ghoulize target
*/
/obj/structure/bloodsucker/vassalrack/proc/torture_victim(mob/living/user, mob/living/target)
/obj/structure/bloodsucker/ghoulrack/proc/torture_victim(mob/living/user, mob/living/target)
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(user)
if(IS_VASSAL(target))
var/datum/antagonist/vassal/vassaldatum = IS_VASSAL(target)
if(!vassaldatum.master.broke_masquerade)
balloon_alert(user, "someone else's vassal!")
if(IS_GHOUL(target))
var/datum/antagonist/ghoul/ghouldatum = IS_GHOUL(target)
if(!ghouldatum.master.broke_masquerade)
balloon_alert(user, "someone else's ghoul!")
return FALSE
var/disloyalty_requires = RequireDisloyalty(user, target)
if(disloyalty_requires == VASSALIZATION_BANNED)
if(disloyalty_requires == GHOULIZATION_BANNED)
if(target.ckey)
balloon_alert(user, "can't be vassalized!")
balloon_alert(user, "can't be ghoulized!")
else
balloon_alert(user, "target has no mind!")
return FALSE
@@ -304,7 +304,7 @@
target.Paralyze(1 SECONDS)
convert_progress--
// We're done? Let's see if they can be Vassal.
// We're done? Let's see if they can be Ghoul.
if(convert_progress)
balloon_alert(user, "needs more persuasion...")
return
@@ -328,13 +328,13 @@
if(!do_after(user, 5 SECONDS, target))
balloon_alert(user, "interrupted!")
return
// Convert to Vassal!
// Convert to Ghoul!
bloodsuckerdatum.AdjustBloodVolume(-TORTURE_CONVERSION_COST)
if(bloodsuckerdatum.make_vassal(target))
if(bloodsuckerdatum.make_ghoul(target))
remove_loyalties(target)
SEND_SIGNAL(bloodsuckerdatum, COMSIG_BLOODSUCKER_MADE_VASSAL, user, target)
SEND_SIGNAL(bloodsuckerdatum, COMSIG_BLOODSUCKER_MADE_GHOUL, user, target)
/obj/structure/bloodsucker/vassalrack/proc/do_torture(mob/living/user, mob/living/carbon/target, mult = 1)
/obj/structure/bloodsucker/ghoulrack/proc/do_torture(mob/living/user, mob/living/carbon/target, mult = 1)
// Fifteen seconds if you aren't using anything. Shorter with weapons and such.
var/torture_time = 15
var/torture_dmg_brute = 2
@@ -378,7 +378,7 @@
return TRUE
/// Offer them the oppertunity to join now.
/obj/structure/bloodsucker/vassalrack/proc/do_disloyalty(mob/living/user, mob/living/target)
/obj/structure/bloodsucker/ghoulrack/proc/do_disloyalty(mob/living/user, mob/living/target)
if(disloyalty_offered)
return FALSE
// Can't willingly join if you're banned from it. It'll just ghost you anyways.
@@ -399,24 +399,24 @@
if("Accept")
disloyalty_confirm = TRUE
else
target.balloon_alert_to_viewers("stares defiantly", "refused vassalization!")
target.balloon_alert_to_viewers("stares defiantly", "refused ghoulization!")
disloyalty_offered = FALSE
return TRUE
/obj/structure/bloodsucker/vassalrack/proc/RequireDisloyalty(mob/living/user, mob/living/target)
/obj/structure/bloodsucker/ghoulrack/proc/RequireDisloyalty(mob/living/user, mob/living/target)
#ifdef BLOODSUCKER_TESTING
if(!target || !target.mind)
#else
if(!target?.mind || !target?.client)
#endif
return VASSALIZATION_BANNED
return GHOULIZATION_BANNED
if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
return VASSALIZATION_DISLOYAL
return GHOULIZATION_DISLOYAL
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(user)
return bloodsuckerdatum.AmValidAntag(target)
/obj/structure/bloodsucker/vassalrack/proc/remove_loyalties(mob/living/target)
/obj/structure/bloodsucker/ghoulrack/proc/remove_loyalties(mob/living/target)
// Find Mind Implant & Destroy
for(var/obj/item/implant/all_implants as anything in target.implants)
if(all_implants.type == /obj/item/implant/mindshield)
@@ -436,13 +436,13 @@
density = FALSE
can_buckle = TRUE
anchored = FALSE
ghost_desc = "This is a magical candle which drains at the sanity of non Bloodsuckers and Vassals.\n\
Vassals can turn the candle on manually, while Bloodsuckers can do it from a distance."
ghost_desc = "This is a magical candle which drains at the sanity of non Bloodsuckers and Ghouls.\n\
Ghouls can turn the candle on manually, while Bloodsuckers can do it from a distance."
vamp_desc = "This is a magical candle which drains at the sanity of mortals who are not under your command while it is active.\n\
You can right-click on it from any range to turn it on remotely, or simply be next to it and click on it to turn it on and off normally."
vassal_desc = "This is a magical candle which drains at the sanity of the fools who havent yet accepted your master, as long as it is active.\n\
ghoul_desc = "This is a magical candle which drains at the sanity of the fools who havent yet accepted your master, as long as it is active.\n\
You can turn it on and off by clicking on it while you are next to it.\n\
If your Master is part of the Ventrue Clan, they utilize this to upgrade their Favorite Vassal."
If your Master is part of the Ventrue Clan, they utilize this to upgrade their Favorite Ghoul."
hunter_desc = "This is a blue Candelabrum, which causes insanity to those near it while active."
var/lit = FALSE
@@ -470,7 +470,7 @@
. = ..()
if(!.)
return
if(anchored && (IS_VASSAL(user) || IS_BLOODSUCKER(user)))
if(anchored && (IS_GHOUL(user) || IS_BLOODSUCKER(user)))
toggle()
return ..()
@@ -490,13 +490,13 @@
if(!lit)
return
for(var/mob/living/carbon/nearly_people in viewers(7, src))
/// We dont want Bloodsuckers or Vassals affected by this
if(IS_VASSAL(nearly_people) || IS_BLOODSUCKER(nearly_people))
/// We dont want Bloodsuckers or Ghouls affected by this
if(IS_GHOUL(nearly_people) || IS_BLOODSUCKER(nearly_people))
continue
nearly_people.adjust_hallucinations(5 SECONDS)
nearly_people.add_mood_event("vampcandle", /datum/mood_event/vampcandle)
/// Blood Throne - Allows Bloodsuckers to remotely speak with their Vassals. - Code (Mostly) stolen from comfy chairs (armrests) and chairs (layers)
/// Blood Throne - Allows Bloodsuckers to remotely speak with their Ghouls. - Code (Mostly) stolen from comfy chairs (armrests) and chairs (layers)
/obj/structure/bloodsucker/bloodthrone
name = "wicked throne"
desc = "Twisted metal shards jut from the arm rests. Very uncomfortable looking. It would take a masochistic sort to sit on this jagged piece of furniture."
@@ -506,9 +506,9 @@
anchored = FALSE
density = TRUE
can_buckle = TRUE
ghost_desc = "This is a Bloodsucker throne, any Bloodsucker sitting on it can remotely speak to their Vassals by attempting to speak aloud."
vamp_desc = "This is a blood throne, sitting on it will allow you to telepathically speak to your vassals by simply speaking."
vassal_desc = "This is a blood throne, it allows your Master to telepathically speak to you and others like you."
ghost_desc = "This is a Bloodsucker throne, any Bloodsucker sitting on it can remotely speak to their Ghouls by attempting to speak aloud."
vamp_desc = "This is a blood throne, sitting on it will allow you to telepathically speak to your ghouls by simply speaking."
ghoul_desc = "This is a blood throne, it allows your Master to telepathically speak to you and others like you."
hunter_desc = "This is a chair that hurts those that try to buckle themselves onto it, though the Undead have no problem latching on.\n\
While buckled, Monsters can use this to telepathically communicate with eachother."
var/mutable_appearance/armrest
@@ -599,7 +599,7 @@
var/rendered = span_cult_large("<b>[user.real_name]:</b> [capitalize(message)]")
user.log_talk(message, LOG_SAY, tag = ROLE_BLOODSUCKER)
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(user)
for(var/datum/antagonist/vassal/receiver as anything in bloodsuckerdatum.vassals)
for(var/datum/antagonist/ghoul/receiver as anything in bloodsuckerdatum.ghouls)
if(!receiver.owner.current)
continue
var/mob/receiver_mob = receiver.owner.current
@@ -47,14 +47,14 @@
return FALSE
return TRUE
///Bloodbag of Bloodsucker blood (used by Vassals only)
///Bloodbag of Bloodsucker blood (used by Ghouls only)
/obj/item/reagent_containers/blood/o_minus/bloodsucker
name = "blood pack"
unique_blood = /datum/reagent/blood/bloodsucker
/obj/item/reagent_containers/blood/o_minus/bloodsucker/examine(mob/user)
. = ..()
if(user.mind.has_antag_datum(/datum/antagonist/ex_vassal) || user.mind.has_antag_datum(/datum/antagonist/vassal/revenge))
if(user.mind.has_antag_datum(/datum/antagonist/ex_ghoul) || user.mind.has_antag_datum(/datum/antagonist/ghoul/revenge))
. += span_notice("Seems to be just about the same color as your Master's...")
//////////////////////
@@ -248,14 +248,14 @@
* A book that can only be used by Curators.
* When used on a player, after a short timer, will reveal if the player is a Bloodsucker, including their real name and Clan.
* This book should not work on Bloodsuckers using the Masquerade ability.
* If it reveals a Bloodsucker, the Curator will then be able to tell they are a Bloodsucker on examine (Like a Vassal).
* If it reveals a Bloodsucker, the Curator will then be able to tell they are a Bloodsucker on examine (Like a Ghoul).
* Reading it normally will allow Curators to read what each Clan does, with some extra flavor text ones.
*
* Regular Bloodsuckers won't have any negative effects from the book, while everyone else will get burns/eye damage.
*/
/obj/item/book/kindred
name = "\improper Archive of the Kindred"
starting_title = "the Archive of the Kindred"
name = "\improper Book of Nod"
starting_title = "the Book of Nod"
desc = "Cryptic documents explaining hidden truths behind Undead beings. It is said only Curators can decipher what they really mean."
icon = 'modular_zubbers/icons/obj/structures/vamp_obj.dmi'
lefthand_file = 'modular_zubbers/icons/mob/inhands/weapons/bloodsucker_lefthand.dmi'
@@ -1,47 +1,47 @@
#define VASSAL_SCAN_MIN_DISTANCE 5
#define VASSAL_SCAN_MAX_DISTANCE 500
#define GHOUL_SCAN_MIN_DISTANCE 5
#define GHOUL_SCAN_MAX_DISTANCE 500
/// 2s update time.
#define VASSAL_SCAN_PING_TIME 20
#define GHOUL_SCAN_PING_TIME 20
/datum/antagonist/vassal
name = "\improper Vassal"
roundend_category = "vassals"
/datum/antagonist/ghoul
name = "\improper Ghoul"
roundend_category = "ghouls"
antagpanel_category = "Bloodsucker"
job_rank = ROLE_VASSAL
antag_hud_name = "vassal"
antag_hud_name = "ghoul"
show_in_roundend = FALSE
hud_icon = 'modular_zubbers/icons/mob/huds/bloodsucker.dmi'
ui_name = "AntagInfoVassal"
antag_panel_description = "You are a Vassal, a mortal servant of a Bloodsucker."
ui_name = "AntagInfoGhoul"
antag_panel_description = "You are a Ghoul, a mortal servant of a Bloodsucker."
/// The Master Bloodsucker's antag datum.
var/datum/antagonist/bloodsucker/master
/// List of all Purchased Powers, to be cleaned up on antag removal.
var/list/datum/action/powers = list()
///Whether this vassal is already a special type of Vassal.
///Whether this ghoul is already a special type of Ghoul.
var/special_type = FALSE
///Description of what this Vassal does.
/// It's shown to the bloodsucker in the radial for setting vassal type
var/vassal_description
///Description of what this Ghoul does.
/// It's shown to the bloodsucker in the radial for setting ghoul type
var/ghoul_description
/// inherent traits that are removed and addded on antag datum loss and gain
var/list/traits = list()
/datum/antagonist/vassal/antag_panel_data()
/datum/antagonist/ghoul/antag_panel_data()
return "Master : [master?.owner.name ? master.owner.name : "Gone"]"
// todo make this into a shared proc that bloodsuckers and vassals share
/datum/antagonist/vassal/ui_static_data(mob/user)
// todo make this into a shared proc that bloodsuckers and ghouls share
/datum/antagonist/ghoul/ui_static_data(mob/user)
return ability_ui_data(powers) + ..()
/datum/antagonist/vassal/apply_innate_effects(mob/living/mob_override)
/datum/antagonist/ghoul/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)
current_mob.apply_status_effect(/datum/status_effect/agent_pinpointer/ghoul_edition)
add_team_hud(current_mob)
if(length(traits))
current_mob.add_traits(traits, VASSAL_TRAIT)
current_mob.add_traits(traits, GHOUL_TRAIT)
/datum/antagonist/vassal/add_team_hud(mob/target)
/datum/antagonist/ghoul/add_team_hud(mob/target)
QDEL_NULL(team_hud_ref)
team_hud_ref = WEAKREF(target.add_alt_appearance(
@@ -54,8 +54,8 @@
var/list/mob/living/mob_list = list()
mob_list += master.owner.current
for(var/datum/antagonist/vassal/vassal as anything in master.vassals)
mob_list += vassal.owner.current
for(var/datum/antagonist/ghoul/ghoul as anything in master.ghouls)
mob_list += ghoul.owner.current
for (var/datum/atom_hud/alternate_appearance/basic/has_antagonist/antag_hud as anything in GLOB.has_antagonist_huds)
if(!(antag_hud.target in mob_list))
@@ -63,85 +63,85 @@
antag_hud.show_to(target)
hud.show_to(antag_hud.target)
/datum/antagonist/vassal/remove_innate_effects(mob/living/mob_override)
/datum/antagonist/ghoul/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)
current_mob.remove_status_effect(/datum/status_effect/agent_pinpointer/ghoul_edition)
if(length(traits))
current_mob.remove_traits(traits, VASSAL_TRAIT)
current_mob.remove_traits(traits, GHOUL_TRAIT)
/datum/antagonist/vassal/pre_mindshield(mob/implanter, mob/living/mob_override)
/datum/antagonist/ghoul/pre_mindshield(mob/implanter, mob/living/mob_override)
return COMPONENT_MINDSHIELD_PASSED
/// This is called when the antagonist is successfully mindshielded.
/datum/antagonist/vassal/on_mindshield(mob/implanter, mob/living/mob_override)
owner.remove_antag_datum(/datum/antagonist/vassal)
owner.current.log_message("has been deconverted from Vassalization by [implanter]!", LOG_ATTACK, color="#960000")
/datum/antagonist/ghoul/on_mindshield(mob/implanter, mob/living/mob_override)
owner.remove_antag_datum(/datum/antagonist/ghoul)
owner.current.log_message("has been deconverted from Ghoulization by [implanter]!", LOG_ATTACK, color="#960000")
return COMPONENT_MINDSHIELD_DECONVERTED
/datum/antagonist/vassal/proc/on_examined(datum/source, mob/examiner, examine_text)
/datum/antagonist/ghoul/proc/on_examined(datum/source, mob/examiner, examine_text)
SIGNAL_HANDLER
var/vassal_examine = return_vassal_examine(examiner)
if(vassal_examine)
examine_text += vassal_examine
var/ghoul_examine = return_ghoul_examine(examiner)
if(ghoul_examine)
examine_text += ghoul_examine
/datum/antagonist/vassal/on_gain()
/datum/antagonist/ghoul/on_gain()
RegisterSignal(owner.current, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined))
RegisterSignal(SSsunlight, COMSIG_SOL_WARNING_GIVEN, PROC_REF(give_warning))
/// Enslave them to their Master
if(!master || !istype(master, master))
return
if(special_type)
if(!master.special_vassals[special_type])
master.special_vassals[special_type] = list()
master.special_vassals[special_type] |= src
master.vassals += src
if(!master.special_ghouls[special_type])
master.special_ghouls[special_type] = list()
master.special_ghouls[special_type] |= src
master.ghouls += src
owner.enslave_mind_to_creator(master.owner.current)
owner.current.log_message("has been vassalized by [master.owner.current]!", LOG_ATTACK, color="#960000")
owner.current.log_message("has been ghoulized by [master.owner.current]!", LOG_ATTACK, color="#960000")
/// Give Recuperate Power
BuyPower(/datum/action/cooldown/bloodsucker/recuperate)
/// Give Objectives
var/datum/objective/bloodsucker/vassal/vassal_objective = new
vassal_objective.owner = owner
objectives += vassal_objective
var/datum/objective/bloodsucker/ghoul/ghoul_objective = new
ghoul_objective.owner = owner
objectives += ghoul_objective
/// Give Vampire Language & Hud
owner.current.grant_all_languages(FALSE, FALSE, TRUE)
owner.current.grant_language(/datum/language/vampiric, ALL, LANGUAGE_MIND)
return ..()
/datum/antagonist/vassal/on_removal()
/datum/antagonist/ghoul/on_removal()
UnregisterSignal(owner.current, COMSIG_ATOM_EXAMINE)
UnregisterSignal(SSsunlight, COMSIG_SOL_WARNING_GIVEN)
//Free them from their Master
if(master && master.owner)
if(special_type && master.special_vassals[special_type])
master.special_vassals.Remove(special_type)
master.vassals -= src
if(special_type && master.special_ghouls[special_type])
master.special_ghouls.Remove(special_type)
master.ghouls -= src
owner.enslaved_to = null
//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, VASSAL_TRAIT)
REMOVE_TRAIT(owner.current, all_status_traits, GHOUL_TRAIT)
//Remove Recuperate Power
remove_powers(powers)
//Remove Language & Hud
owner.current.remove_language(/datum/language/vampiric, ALL, LANGUAGE_MIND)
return ..()
/datum/antagonist/vassal/proc/remove_powers(list/removing_powers)
/datum/antagonist/ghoul/proc/remove_powers(list/removing_powers)
for(var/datum/action/cooldown/bloodsucker/power as anything in removing_powers)
removing_powers -= power
if(!(power in owner.current.actions))
continue
power.Remove(owner.current)
/datum/antagonist/vassal/on_body_transfer(mob/living/old_body, mob/living/new_body)
/datum/antagonist/ghoul/on_body_transfer(mob/living/old_body, mob/living/new_body)
. = ..()
for(var/datum/action/cooldown/bloodsucker/all_powers as anything in powers)
all_powers.Remove(old_body)
all_powers.Grant(new_body)
/datum/antagonist/vassal/greet()
/datum/antagonist/ghoul/greet()
. = ..()
if(silent)
return
@@ -155,7 +155,7 @@
to_chat(master.owner, span_userdanger("[owner.current] has become addicted to your immortal blood. [capitalize(owner.current.p_they(TRUE))] [owner.current.p_are()] now your mortal servant!"))
master.owner.current.playsound_local(null, 'sound/magic/mutate.ogg', 100, FALSE, pressure_affected = FALSE)
/datum/antagonist/vassal/farewell()
/datum/antagonist/ghoul/farewell()
if(silent)
return
@@ -166,9 +166,9 @@
owner.current.playsound_local(null, 'sound/magic/mutate.ogg', 100, FALSE, pressure_affected = FALSE)
/// Message told to your (former) Master.
if(master && master.owner)
to_chat(master.owner, span_cult_bold("You feel the bond with your vassal [owner.current] has somehow been broken!"))
to_chat(master.owner, span_cult_bold("You feel the bond with your ghoul [owner.current] has somehow been broken!"))
/datum/antagonist/vassal/admin_add(datum/mind/new_owner, mob/admin)
/datum/antagonist/ghoul/admin_add(datum/mind/new_owner, mob/admin)
var/list/datum/mind/possible_vampires = list()
for(var/datum/antagonist/bloodsucker/bloodsuckerdatums in GLOB.antagonists)
var/datum/mind/vamp = bloodsuckerdatums.owner
@@ -180,13 +180,13 @@
continue
possible_vampires += vamp
if(!length(possible_vampires))
message_admins("[key_name_admin(admin)] tried vassalizing [key_name_admin(new_owner)], but there were no bloodsuckers!")
message_admins("[key_name_admin(admin)] tried ghoulizing [key_name_admin(new_owner)], but there were no bloodsuckers!")
return
var/datum/mind/choice = tgui_input_list(admin, "Which bloodsucker should this vassal belong to?", "Bloodsucker", possible_vampires)
var/datum/mind/choice = tgui_input_list(admin, "Which bloodsucker should this ghoul belong to?", "Bloodsucker", possible_vampires)
if(!choice)
return
log_admin("[key_name_admin(admin)] turned [key_name_admin(new_owner)] into a vassal of [key_name_admin(choice)]!")
log_admin("[key_name_admin(admin)] turned [key_name_admin(new_owner)] into a ghoul of [key_name_admin(choice)]!")
var/datum/antagonist/bloodsucker/vampire = IS_BLOODSUCKER(choice.current)
master = vampire
new_owner.add_antag_datum(src)
to_chat(choice, span_notice("Through divine intervention, you've gained a new vassal!"))
to_chat(choice, span_notice("Through divine intervention, you've gained a new ghoul!"))
@@ -1,31 +1,31 @@
/**
* # Vassal Pinpointer
* # Ghoul Pinpointer
*
* Pinpointer that points to their Master's location at all times.
* 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
/atom/movable/screen/alert/status_effect/agent_pinpointer/ghoul_edition
name = "Blood Bond"
desc = "You always know where your master is."
/datum/status_effect/agent_pinpointer/vassal_edition
/datum/status_effect/agent_pinpointer/ghoul_edition
id = "agent_pinpointer"
alert_type = /atom/movable/screen/alert/status_effect/agent_pinpointer/vassal_edition
minimum_range = VASSAL_SCAN_MIN_DISTANCE
tick_interval = VASSAL_SCAN_PING_TIME
alert_type = /atom/movable/screen/alert/status_effect/agent_pinpointer/ghoul_edition
minimum_range = GHOUL_SCAN_MIN_DISTANCE
tick_interval = GHOUL_SCAN_PING_TIME
duration = -1
range_fuzz_factor = 0
/datum/status_effect/agent_pinpointer/vassal_edition/on_creation(mob/living/new_owner, ...)
/datum/status_effect/agent_pinpointer/ghoul_edition/on_creation(mob/living/new_owner, ...)
..()
var/datum/antagonist/vassal/antag_datum = new_owner.mind.has_antag_datum(/datum/antagonist/vassal)
var/datum/antagonist/ghoul/antag_datum = new_owner.mind.has_antag_datum(/datum/antagonist/ghoul)
scan_target = antag_datum?.master?.owner?.current
/datum/status_effect/agent_pinpointer/vassal_edition/scan_for_target()
/datum/status_effect/agent_pinpointer/ghoul_edition/scan_for_target()
return
/datum/status_effect/agent_pinpointer/vassal_edition/Destroy()
/datum/status_effect/agent_pinpointer/ghoul_edition/Destroy()
if(scan_target)
to_chat(owner, span_notice("You've lost your master's trail."))
return ..()
@@ -1,46 +1,46 @@
/datum/antagonist/vassal/proc/give_warning(atom/source, danger_level, vampire_warning_message, vassal_warning_message)
/datum/antagonist/ghoul/proc/give_warning(atom/source, danger_level, vampire_warning_message, ghoul_warning_message)
SIGNAL_HANDLER
if(vassal_warning_message)
to_chat(owner, vassal_warning_message)
if(ghoul_warning_message)
to_chat(owner, ghoul_warning_message)
/**
* Returns a Vassals's examine strings.
* Returns a Ghouls's examine strings.
* Args:
* viewer - The person examining.
*/
/datum/antagonist/vassal/proc/return_vassal_examine(mob/living/viewer)
/datum/antagonist/ghoul/proc/return_ghoul_examine(mob/living/viewer)
if((!viewer.mind && !isobserver(viewer)) || !iscarbon(owner.current))
return FALSE
var/mob/living/carbon/carbon_current = owner.current
// Target must be a Vassal
// Target must be a Ghoul
// Default String
var/returnString = "\[<span class='warning'>"
var/returnIcon = ""
// Vassals and Bloodsuckers recognize eachother, while Monster Hunters can see Vassals.
if(!IS_BLOODSUCKER(viewer) && !IS_VASSAL(viewer) && !IS_MONSTERHUNTER(viewer) && !isobserver(viewer))
// Ghouls and Bloodsuckers recognize eachother, while Monster Hunters can see Ghouls.
if(!IS_BLOODSUCKER(viewer) && !IS_GHOUL(viewer) && !IS_MONSTERHUNTER(viewer) && !isobserver(viewer))
return FALSE
// Am I Viewer's Vassal?
// Am I Viewer's Ghoul?
if(master.owner == viewer.mind)
returnString += "This [carbon_current.dna.species.name] bears YOUR mark!"
returnIcon = "[icon2html('modular_zubbers/icons/misc/language.dmi', world, "vassal")]"
// Am I someone ELSE'S Vassal?
returnIcon = "[icon2html('modular_zubbers/icons/misc/language.dmi', world, "ghoul")]"
// Am I someone ELSE'S Ghoul?
else if(IS_BLOODSUCKER(viewer) || IS_MONSTERHUNTER(viewer) || isobserver(viewer))
returnString += "This [carbon_current.dna.species.name] bears the mark of <span class='boldwarning'>[master.return_full_name()][master.broke_masquerade ? " who has broken the Masquerade" : ""]</span>"
returnIcon = "[icon2html('modular_zubbers/icons/misc/language.dmi', world, "vassal_grey")]"
returnIcon = "[icon2html('modular_zubbers/icons/misc/language.dmi', world, "ghoul_grey")]"
// Are you serving the same master as I am?
else if(viewer.mind.has_antag_datum(/datum/antagonist/vassal) in master.vassals)
else if(viewer.mind.has_antag_datum(/datum/antagonist/ghoul) in master.ghouls)
returnString += "[p_they(TRUE)] bears the mark of your Master"
returnIcon = "[icon2html('modular_zubbers/icons/misc/language.dmi', world, "vassal")]"
returnIcon = "[icon2html('modular_zubbers/icons/misc/language.dmi', world, "ghoul")]"
// You serve a different Master than I do.
else
returnString += "[p_they(TRUE)] bears the mark of another Bloodsucker"
returnIcon = "[icon2html('modular_zubbers/icons/misc/language.dmi', world, "vassal_grey")]"
returnIcon = "[icon2html('modular_zubbers/icons/misc/language.dmi', world, "ghoul_grey")]"
returnString += "</span>\]" // \n" Don't need spacers. Using . += "" in examine.dm does this on its own.
return returnIcon + returnString
/// Used when your Master teaches you a new Power.
/datum/antagonist/vassal/proc/BuyPower(datum/action/cooldown/power, list_to_add_to = powers)
/datum/antagonist/ghoul/proc/BuyPower(datum/action/cooldown/power, list_to_add_to = powers)
for(var/datum/action/current_powers as anything in list_to_add_to)
if(current_powers.type == power.type)
return FALSE
@@ -50,28 +50,28 @@
log_uplink("[key_name(owner.current)] purchased [power].")
return TRUE
/datum/antagonist/vassal/proc/LevelUpPowers()
/datum/antagonist/ghoul/proc/LevelUpPowers()
for(var/datum/action/cooldown/bloodsucker/power in powers)
power.level_current++
/// Called when we are made into the Favorite Vassal
/datum/antagonist/vassal/proc/make_special(datum/antagonist/vassal/vassal_type)
/// Called when we are made into the Favorite Ghoul
/datum/antagonist/ghoul/proc/make_special(datum/antagonist/ghoul/ghoul_type)
//store what we need
var/datum/mind/vassal_owner = owner
var/datum/mind/ghoul_owner = owner
var/datum/antagonist/bloodsucker/bloodsuckerdatum = master
//remove our antag datum
silent = TRUE
vassal_owner.remove_antag_datum(/datum/antagonist/vassal)
ghoul_owner.remove_antag_datum(/datum/antagonist/ghoul)
//give our new one
var/datum/antagonist/vassal/vassaldatum = new vassal_type(vassal_owner)
vassaldatum.master = bloodsuckerdatum
vassaldatum.silent = TRUE
vassal_owner.add_antag_datum(vassaldatum)
vassaldatum.silent = FALSE
var/datum/antagonist/ghoul/ghouldatum = new ghoul_type(ghoul_owner)
ghouldatum.master = bloodsuckerdatum
ghouldatum.silent = TRUE
ghoul_owner.add_antag_datum(ghouldatum)
ghouldatum.silent = FALSE
//send alerts of completion
to_chat(master, span_danger("You have turned [vassal_owner.current] into your [vassaldatum.name]! They will no longer be deconverted upon Mindshielding!"))
to_chat(vassal_owner, span_notice("As Blood drips over your body, you feel closer to your Master... You are now the [vassaldatum.name]!"))
vassal_owner.current.playsound_local(null, 'sound/magic/mutate.ogg', 75, FALSE, pressure_affected = FALSE)
to_chat(master, span_danger("You have turned [ghoul_owner.current] into your [ghouldatum.name]! They will no longer be deconverted upon Mindshielding!"))
to_chat(ghoul_owner, span_notice("As Blood drips over your body, you feel closer to your Master... You are now the [ghouldatum.name]!"))
ghoul_owner.current.playsound_local(null, 'sound/magic/mutate.ogg', 75, FALSE, pressure_affected = FALSE)
@@ -1,42 +1,42 @@
#define BLOOD_TIMER_REQUIREMENT (10 MINUTES)
#define BLOOD_TIMER_HALWAY (BLOOD_TIMER_REQUIREMENT / 2)
/datum/antagonist/ex_vassal
name = "\improper Ex-Vassal"
roundend_category = "vassals"
/datum/antagonist/ex_ghoul
name = "\improper Ex-Ghoul"
roundend_category = "ghouls"
antagpanel_category = "Bloodsucker"
job_rank = ROLE_VASSAL
antag_hud_name = "vassal_grey"
antag_hud_name = "ghoul_grey"
show_in_roundend = FALSE
show_in_antagpanel = FALSE
silent = TRUE
ui_name = FALSE
hud_icon = 'modular_zubbers/icons/mob/huds/bloodsucker.dmi'
///The revenge vassal that brought us into the fold.
var/datum/antagonist/vassal/revenge/revenge_vassal
///The revenge ghoul that brought us into the fold.
var/datum/antagonist/ghoul/revenge/revenge_ghoul
///Timer we have to live
COOLDOWN_DECLARE(blood_timer)
/datum/antagonist/ex_vassal/on_gain()
/datum/antagonist/ex_ghoul/on_gain()
. = ..()
RegisterSignal(owner.current, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
/datum/antagonist/ex_vassal/on_removal()
if(revenge_vassal)
revenge_vassal.ex_vassals -= src
revenge_vassal = null
/datum/antagonist/ex_ghoul/on_removal()
if(revenge_ghoul)
revenge_ghoul.ex_ghouls -= src
revenge_ghoul = null
blood_timer = null
return ..()
/datum/antagonist/ex_vassal/proc/on_examine(datum/source, mob/examiner, examine_text)
/datum/antagonist/ex_ghoul/proc/on_examine(datum/source, mob/examiner, examine_text)
SIGNAL_HANDLER
var/datum/antagonist/vassal/revenge/vassaldatum = IS_REVENGE_VASSAL(examiner)
if(vassaldatum && !revenge_vassal)
examine_text += span_notice("[owner.current] is an ex-vassal!")
var/datum/antagonist/ghoul/revenge/ghouldatum = IS_REVENGE_GHOUL(examiner)
if(ghouldatum && !revenge_ghoul)
examine_text += span_notice("[owner.current] is an ex-ghoul!")
/datum/antagonist/ex_vassal/add_team_hud(mob/target)
/datum/antagonist/ex_ghoul/add_team_hud(mob/target)
QDEL_NULL(team_hud_ref)
team_hud_ref = WEAKREF(target.add_alt_appearance(
@@ -48,9 +48,9 @@
var/datum/atom_hud/alternate_appearance/basic/has_antagonist/hud = team_hud_ref.resolve()
var/list/mob/living/mob_list = list()
mob_list += revenge_vassal.owner.current
for(var/datum/antagonist/ex_vassal/former_vassals as anything in revenge_vassal.ex_vassals)
mob_list += former_vassals.owner.current
mob_list += revenge_ghoul.owner.current
for(var/datum/antagonist/ex_ghoul/former_ghouls as anything in revenge_ghoul.ex_ghouls)
mob_list += former_ghouls.owner.current
for (var/datum/atom_hud/alternate_appearance/basic/has_antagonist/antag_hud as anything in GLOB.has_antagonist_huds)
if(!(antag_hud.target in mob_list))
@@ -61,17 +61,17 @@
/**
* Fold return
*
* Called when a Revenge bloodsucker gets a vassal back into the fold.
* Called when a Revenge bloodsucker gets a ghoul back into the fold.
*/
/datum/antagonist/ex_vassal/proc/return_to_fold(datum/antagonist/vassal/revenge/mike_ehrmantraut)
revenge_vassal = mike_ehrmantraut
mike_ehrmantraut.ex_vassals += src
/datum/antagonist/ex_ghoul/proc/return_to_fold(datum/antagonist/ghoul/revenge/mike_ehrmantraut)
revenge_ghoul = mike_ehrmantraut
mike_ehrmantraut.ex_ghouls += src
COOLDOWN_START(src, blood_timer, BLOOD_TIMER_REQUIREMENT)
add_team_hud(owner.current)
RegisterSignal(src, COMSIG_LIVING_LIFE, PROC_REF(on_life))
/datum/antagonist/ex_vassal/proc/on_life(datum/source, seconds_per_tick, times_fired)
/datum/antagonist/ex_ghoul/proc/on_life(datum/source, seconds_per_tick, times_fired)
SIGNAL_HANDLER
if(COOLDOWN_TIMELEFT(src, blood_timer) <= BLOOD_TIMER_HALWAY + 2 && COOLDOWN_TIMELEFT(src, blood_timer) >= BLOOD_TIMER_HALWAY - 2) //just about halfway
@@ -79,24 +79,24 @@
if(!COOLDOWN_FINISHED(src, blood_timer))
return
to_chat(owner.current, span_cult_bold("You are out of blood!"))
to_chat(revenge_vassal.owner.current, span_cult_bold("[owner.current] has ran out of blood and is no longer in the fold!"))
owner.remove_antag_datum(/datum/antagonist/ex_vassal)
to_chat(revenge_ghoul.owner.current, span_cult_bold("[owner.current] has ran out of blood and is no longer in the fold!"))
owner.remove_antag_datum(/datum/antagonist/ex_ghoul)
/**
* Bloodsucker Blood
*
* Artificially made, this must be fed to ex-vassals to keep them on their high.
* Artificially made, this must be fed to ex-ghouls to keep them on their high.
*/
/datum/reagent/blood/bloodsucker
name = "Blood two"
/datum/reagent/blood/bloodsucker/expose_mob(mob/living/exposed_mob, methods, reac_volume, show_message, touch_protection)
var/datum/antagonist/ex_vassal/former_vassal = exposed_mob.mind.has_antag_datum(/datum/antagonist/ex_vassal)
if(former_vassal)
var/datum/antagonist/ex_ghoul/former_ghoul = exposed_mob.mind.has_antag_datum(/datum/antagonist/ex_ghoul)
if(former_ghoul)
to_chat(exposed_mob, span_cult("You feel the blood restore you... You feel safe."))
COOLDOWN_RESET(former_vassal, blood_timer)
COOLDOWN_START(former_vassal, blood_timer, BLOOD_TIMER_REQUIREMENT)
COOLDOWN_RESET(former_ghoul, blood_timer)
COOLDOWN_START(former_ghoul, blood_timer, BLOOD_TIMER_REQUIREMENT)
return ..()
#undef BLOOD_TIMER_REQUIREMENT
@@ -1,28 +1,28 @@
/**
* Favorite Vassal
* Favorite Ghoul
*
* Gets some cool abilities depending on the Clan.
*/
/datum/antagonist/vassal/favorite
name = "\improper Favorite Vassal"
antag_hud_name = "vassal6"
special_type = FAVORITE_VASSAL
vassal_description = "The Favorite Vassal gets unique abilities over other Vassals depending on the Master's Clan \
and becomes completely immune to Mindshields. If part of Ventrue, this is the Vassal a Bloodsucker will rank up."
/datum/antagonist/ghoul/favorite
name = "\improper Favorite Ghoul"
antag_hud_name = "ghoul6"
special_type = FAVORITE_GHOUL
ghoul_description = "The Favorite Ghoul gets unique abilities over other Ghouls depending on the Master's Clan \
and becomes completely immune to Mindshields. If part of Ventrue, this is the Ghoul a Bloodsucker will rank up."
///Bloodsucker levels, but for Vassals, used by Ventrue. Used for ventrue creating a new bloodsucker.
var/vassal_level
///Bloodsucker levels, but for Ghouls, used by Ventrue. Used for ventrue creating a new bloodsucker.
var/ghoul_level
/// Power's we're going to inherit once we turn into a Bloodsucker
var/list/bloodsucker_powers = list()
/datum/antagonist/vassal/favorite/on_gain()
/datum/antagonist/ghoul/favorite/on_gain()
. = ..()
SEND_SIGNAL(master, COMSIG_BLOODSUCKER_MAKE_FAVORITE, src)
/datum/antagonist/vassal/favorite/on_removal()
/datum/antagonist/ghoul/favorite/on_removal()
SEND_SIGNAL(master, COMSIG_BLOODSUCKER_LOOSE_FAVORITE, src)
remove_powers(bloodsucker_powers)
. = ..()
/datum/antagonist/vassal/favorite/pre_mindshield(mob/implanter, mob/living/mob_override)
/datum/antagonist/ghoul/favorite/pre_mindshield(mob/implanter, mob/living/mob_override)
return COMPONENT_MINDSHIELD_RESISTED
@@ -1,68 +1,68 @@
/**
* Revenge Vassal
* Revenge Ghoul
*
* Has the goal to 'get revenge' when their Master dies.
*/
/datum/antagonist/vassal/revenge
name = "\improper Revenge Vassal"
roundend_category = "abandoned Vassals"
/datum/antagonist/ghoul/revenge
name = "\improper Revenge Ghoul"
roundend_category = "abandoned Ghouls"
show_in_roundend = FALSE
show_in_antagpanel = FALSE
antag_hud_name = "vassal4"
special_type = REVENGE_VASSAL
vassal_description = "The Revenge Vassal will not deconvert on a Bloodsucker's Final Death, \
antag_hud_name = "ghoul4"
special_type = REVENGE_GHOUL
ghoul_description = "The Revenge Ghoul will not deconvert on a Bloodsucker's Final Death, \
instead they will gain all your Powers, and the objective to take revenge for your demise. \
They additionally maintain Vassals their Master's departure, rather than become aimless."
They additionally maintain Ghouls their Master's departure, rather than become aimless."
///all ex-vassals brought back into the fold.
var/list/datum/antagonist/ex_vassal/ex_vassals = list()
///all ex-ghouls brought back into the fold.
var/list/datum/antagonist/ex_ghoul/ex_ghouls = list()
/datum/antagonist/vassal/revenge/roundend_report()
/datum/antagonist/ghoul/revenge/roundend_report()
var/list/report = list()
report += printplayer(owner)
if(objectives.len)
report += printobjectives(objectives)
// Now list their vassals
if(ex_vassals.len)
report += "<span class='header'>The Vassals brought back into the fold were...</span>"
for(var/datum/antagonist/ex_vassal/all_vassals as anything in ex_vassals)
if(!all_vassals.owner)
// Now list their ghouls
if(ex_ghouls.len)
report += "<span class='header'>The Ghouls brought back into the fold were...</span>"
for(var/datum/antagonist/ex_ghoul/all_ghouls as anything in ex_ghouls)
if(!all_ghouls.owner)
continue
report += "<b>[all_vassals.owner.name]</b> the [all_vassals.owner.assigned_role.title]"
report += "<b>[all_ghouls.owner.name]</b> the [all_ghouls.owner.assigned_role.title]"
return report.Join("<br>")
/datum/antagonist/vassal/revenge/on_gain()
/datum/antagonist/ghoul/revenge/on_gain()
. = ..()
RegisterSignal(master, COMSIG_BLOODSUCKER_FINAL_DEATH, PROC_REF(on_master_death))
/datum/antagonist/vassal/revenge/on_removal()
/datum/antagonist/ghoul/revenge/on_removal()
UnregisterSignal(master, COMSIG_BLOODSUCKER_FINAL_DEATH)
return ..()
/datum/antagonist/vassal/revenge/proc/on_master_death(datum/antagonist/bloodsucker/bloodsuckerdatum, mob/living/carbon/master)
/datum/antagonist/ghoul/revenge/proc/on_master_death(datum/antagonist/bloodsucker/bloodsuckerdatum, mob/living/carbon/master)
SIGNAL_HANDLER
show_in_roundend = TRUE
for(var/datum/objective/all_objectives as anything in objectives)
objectives -= all_objectives
BuyPower(/datum/action/cooldown/bloodsucker/vassal_blood)
BuyPower(/datum/action/cooldown/bloodsucker/ghoul_blood)
for(var/datum/action/cooldown/bloodsucker/master_powers as anything in bloodsuckerdatum.powers)
if(master_powers.purchase_flags & BLOODSUCKER_DEFAULT_POWER)
continue
master_powers.Grant(owner.current)
owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer/vassal_edition)
owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer/ghoul_edition)
var/datum/objective/survive/new_objective = new
new_objective.name = "Avenge Bloodsucker"
new_objective.explanation_text = "Avenge your Bloodsucker's death by felling the ones that killed them, and by recruiting their ex-vassals and continuing their operations."
new_objective.name = "Avenge your Master"
new_objective.explanation_text = "Avenge your Master's final death by felling the ones that killed them, recruiting their ex-ghouls and continuing their operations."
new_objective.owner = owner
objectives += new_objective
antag_panel_title = "You are a Vassal tasked with taking revenge for the death of your Master!"
antag_panel_description = "You have gained your Master&#39;s old Powers, and a brand new \
antag_panel_title = "You are a Ghoul tasked with taking revenge for the death of your Master!"
antag_panel_description = "You have gained your Master's old Powers, and a brand new \
power. You will have to survive and maintain your old \
Master&#39;s integrity. Bring their old Vassals back into the \
Master's integrity. Bring their old Ghouls back into the \
fold using your new Ability."
update_static_data_for_all_viewers()
@@ -1,6 +1,6 @@
/datum/language/vampiric
name = "Blah-Sucker"
desc = "The native language of the Bloodsucker elders, learned intuitively by Fledglings as they pass from death into immortality."
name = "Enochian"
desc = "Rumored to be created by the Dark Father, Caine himself as a way to talk to his Childer, the truth, like many things in unlife is uncertain. Spoken by creatures of the night."
key = "L"//Capital L, lowercase l is for ashies.
space_chance = 40
default_priority = 90
@@ -84,7 +84,7 @@
to_chat(quirk_holder, text)
COOLDOWN_START(src, sun_burn, 30 SECONDS)
/datum/quirk/sol_weakness/proc/sun_warning(atom/source, danger_level, vampire_warning_message, vassal_warning_message)
/datum/quirk/sol_weakness/proc/sun_warning(atom/source, danger_level, vampire_warning_message, ghoul_warning_message)
SIGNAL_HANDLER
if(danger_level == DANGER_LEVEL_SOL_ROSE)
vampire_warning_message = span_userdanger("Solar flares bombard the station with deadly UV light! Stay in cover for the next [TIME_BLOODSUCKER_DAY / 60] minutes or risk death!")
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

@@ -14,7 +14,7 @@
"#If I focus on my goals, rather than what I want to do, am I truly happy?",
"#Maybe... in an alternate universe... I could be part of another family. One that cares more about me...",
",LI wonder what other people think of me... Possibly terribly.",
"#...What would happen if I Vassalized a Clown?",
"#...What would happen if I Ghoulized a Clown?",
"#Why can't we just walk? Does anyone walk anymore? Why do we run? What rush are we in?",
"#Medbay is overworking, I wonder why they are always so shortstaffed.",
"#Why do we take a pod instead of the shuttle? Where's the fun in that?",
@@ -30,7 +30,7 @@
",LWhat would happen if a Bloodsucker got their hands on a Power Miner?",
"#There are Aliens, they exist. It isn't a conspiracy. The real question is when they will attack us.",
"#Is Brain damage real, or is it just our brains adapting to reality?",
"#How do we all understand eachother when we speak over eachother on the radio?",
"#How do we all understand each other when we speak over each other on the radio?",
"#Huds are broken again, it seems...",
"#Never make a deal with the devil... worst mistake of my life.",
"#Does plasma still affect the minds of people who can't get poisoned?",
@@ -115,11 +115,11 @@
"#If you wish to defeat me. Train for another 10,000 years.",
"#If i knew you was coming i'd have baked a cake! Wait, who was i talking to?",
"#We'll meet again. I don't know where and i don't know when but i know we'll meet again. Hopefully on a not very sunny day.",
"#Here is my question: When Cain slew Abel and God punished Cain, why did God give him superpowers?",
"#Here is my question: When Caine slew Abel and God punished Caine, why did God give him superpowers?",
"#If i became fully augmented, would i still be a Vampire? Would i need to suck on Borgs and power cells?",
";No security! Don't try it!",
"#What would happen if i wore a Memento Mori and was staked?",
"#Hmm, do i feel like doing my objectives today or going to the dorm rooms?... A better question is why an undead creature like myself has a libido in the first place.",
"#Hmm, do I feel like doing my objectives today or going to the dorm rooms?... A better question is why an undead creature like myself has a libido in the first place.",
"#P-Please don't hurt me! I'm not a bad Vampire!",
"#Why do we sleep in coffins? I'm undead not dead.",
"#Crazy? I was Crazy once. They locked me in a room, a rubber room filled with rats. I drank the blood of the rats. Their ignoble blood made me crazy. Crazy?- ",
@@ -152,6 +152,14 @@
"#The station's intercom is the voice of the cosmic leprechaun who stole my sanity. Now it's broadcasting riddles about the meaning of socks.",
"#The walls told me secrets, but now they're suing me for breach of confidentiality. I didn't sign an NDA with the cosmos, did I?",
"#I challenged the HoS to a dance-off with quantum entanglement moves. Now we're quantumly entangled in a never-ending cosmic boogie.",
"#I found a message in the maintenance pipes. It said, 'The space hamsters know your deepest fears.' Now I'm facing existential dread fueled by rodent prophecy."
"#I found a message in the maintenance pipes. It said, 'The space hamsters know your deepest fears.' Now I'm facing existential dread fueled by rodent prophecy.",
"#I am the sword of Caine, I am the sword of Caine...",
"#The Wisdom Cow is a sign of Gehenna, Lilith is laughing at me.",
";Don't open it.",
"#One hand moves the pieces of the game - the winner keeps his hand on the pawn...",
"#Why's he smiling? The father? Is it the father behind him?",
"#Whether or not you win the game, matters not. It's if you bought it.",
"#In the time of Thin-Blood when his, the Dark Father's blood runs weak...",
"#Is Nanotrasen part of our games of Elders and Antediluvians or are we part of theirs?"
]
}
@@ -29,7 +29,7 @@ export type BloodsuckerProps = {
powers: PowerInfo[];
objectives: Objective[];
};
export type VassalProps = BloodsuckerProps & {
export type GhoulProps = BloodsuckerProps & {
title: string;
description: string;
};
@@ -131,7 +131,7 @@ const BloodsuckerIntro = () => {
<Section fill title="Items">
<Stack vertical>
<Stack.Item>
Rest in a <b>Coffin</b> to claim it, and that area, as your lair.
Rest in a <b>Coffin</b> to claim it, and that area, as your haven.
<br />
Examine your new structures to see how they function!
<br />
@@ -139,9 +139,9 @@ const BloodsuckerIntro = () => {
Masquerade ability will hide your identity to prevent this.
<br />
You will learn how to make persuasion racks once you have enough
levels to support a vassal, which you will learn during torpor
during daytime. Examine the vassal rack to see how many vassals
you can have!
levels to support a ghoul, which you will learn during torpor
during daytime. Examine the ghoul rack to see how many ghouls you
can have!
<br />
You cannot level up until you select a clan. To select a clan,
click the clan tab on the top right of this window.
@@ -1,12 +1,12 @@
import { useBackend } from '../backend';
import { Section, Stack } from '../components';
import { Window } from '../layouts';
import { VassalProps } from './AntagInfoBloodsucker';
import { GhoulProps } from './AntagInfoBloodsucker';
import { ObjectivePrintout } from './common/Objectives';
import { PowerDetails } from './PowerInfo';
export const AntagInfoVassal = (props: any, context: any) => {
const { data } = useBackend<VassalProps>();
export const AntagInfoGhoul = (props: any, context: any) => {
const { data } = useBackend<GhoulProps>();
const { powers } = data;
return (
<Window
@@ -15,14 +15,14 @@ export const AntagInfoVassal = (props: any, context: any) => {
theme="spookyconsole"
>
<Window.Content>
<VassalInfo />
<GhoulInfo />
</Window.Content>
</Window>
);
};
const VassalInfo = () => {
const { data } = useBackend<VassalProps>();
const GhoulInfo = () => {
const { data } = useBackend<GhoulProps>();
const { powers, objectives, title, description } = data;
return (
<Stack vertical fill>
@@ -3,7 +3,7 @@ import { Antagonist, Category } from '../base';
export const VAMPIRE_MECHANICAL_DESCRIPTION = `
After your death, you awaken to see yourself as an undead monster.
Use your Vampiric abilities as best you can.
Scrape by Space Station 13, or take over it, vassalizing your way.
Scrape by Space Station 13, or take over it, ghoulizing your way.
`;
const Bloodsucker: Antagonist = {
@@ -3,7 +3,7 @@ import { Antagonist, Category } from '../base';
export const VAMPIRE_MECHANICAL_DESCRIPTION = `
After your death, you awaken to see yourself as an undead monster.
Use your Vampiric abilities as best you can.
Scrape by Space Station 13, or take over it, vassalizing your way.
Scrape by Space Station 13, or take over it, ghoulizing your way.
`;
const BloodsuckerBreakout: Antagonist = {
@@ -3,7 +3,7 @@ import { Antagonist, Category } from '../base';
export const VAMPIRE_MECHANICAL_DESCRIPTION = `
After your death, you awaken to see yourself as an undead monster.
Use your Vampiric abilities as best you can.
Scrape by Space Station 13, or take over it, vassalizing your way.
Scrape by Space Station 13, or take over it, ghoulizing your way.
`;
const VampiricAccident: Antagonist = {