Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BloodSuckers port from monkey #941

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 169 additions & 0 deletions code/__DEFINES/bloodsuckers.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
///Uncomment this to enable testing of Bloodsucker features (such as vassalizing people with a mind instead of a client).
//#define BLOODSUCKER_TESTING

/**
* Blood-level defines
*/
/// Determines Bloodsucker regeneration rate
#define BS_BLOOD_VOLUME_MAX_REGEN 700
/// Cost to torture someone halfway, in blood. Called twice for full cost
#define TORTURE_BLOOD_HALF_COST 8
/// Cost to convert someone after successful torture, in blood
#define TORTURE_CONVERSION_COST 50
/// Once blood is this low, will enter Frenzy
#define FRENZY_THRESHOLD_ENTER 25
/// Once blood is this high, will exit Frenzyshak
#define FRENZY_THRESHOLD_EXIT 250

/// Minimum blood required for bloodsucker oozelings to auto-revive
#define OOZELING_MIN_REVIVE_BLOOD_THRESHOLD (FRENZY_THRESHOLD_ENTER * 10)

/**
* Vassal 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

/**
* Cooldown defines
* Used in Cooldowns Bloodsuckers use to prevent spamming
*/
///Spam prevention for healing messages.
#define BLOODSUCKER_SPAM_HEALING (15 SECONDS)
///Span prevention for Sol Masquerade messages.
#define BLOODSUCKER_SPAM_MASQUERADE (60 SECONDS)

///Span prevention for Sol messages.
#define BLOODSUCKER_SPAM_SOL (30 SECONDS)

/**
* Clan defines
*/
#define CLAN_NONE "Caitiff"
#define CLAN_BRUJAH "Brujah Clan"
#define CLAN_TOREADOR "Toreador Clan"
#define CLAN_NOSFERATU "Nosferatu Clan"
#define CLAN_TREMERE "Tremere Clan"
#define CLAN_GANGREL "Gangrel Clan"
#define CLAN_VENTRUE "Ventrue Clan"
#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"

/**
* Power defines
*/
/// This Power can't be used in Torpor
#define BP_CANT_USE_IN_TORPOR (1<<0)
/// This Power can't be used in Frenzy.
#define BP_CANT_USE_IN_FRENZY (1<<1)
/// This Power can't be used with a stake in you
#define BP_CANT_USE_WHILE_STAKED (1<<2)
/// This Power can't be used while incapacitated
#define BP_CANT_USE_WHILE_INCAPACITATED (1<<3)
/// This Power can't be used while unconscious
#define BP_CANT_USE_WHILE_UNCONSCIOUS (1<<4)
/// This Power can't be used during Sol
#define BP_CANT_USE_DURING_SOL (1<<5)

/// This Power can be purchased by Bloodsuckers
#define BLOODSUCKER_CAN_BUY (1<<0)
/// This is a Default Power that all Bloodsuckers get.
#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 is a Toggled Power
#define BP_AM_TOGGLE (1<<0)
/// This Power is a Single-Use Power
#define BP_AM_SINGLEUSE (1<<1)
/// This Power has a Static cooldown
#define BP_AM_STATIC_COOLDOWN (1<<2)
/// This Power doesn't cost bloot to run while unconscious
#define BP_AM_COSTLESS_UNCONSCIOUS (1<<3)

/**
* Bloodsucker Signals
*/
///Called when a Bloodsucker ranks up: (datum/bloodsucker_datum, mob/owner, mob/target)
#define BLOODSUCKER_RANK_UP "bloodsucker_rank_up"
///Called when a Bloodsucker interacts with a Vassal on their persuasion rack.
#define BLOODSUCKER_INTERACT_WITH_VASSAL "bloodsucker_interact_with_vassal"
///Called when a Bloodsucker makes a Vassal into their Favorite Vassal: (datum/vassal_datum, mob/master)
#define BLOODSUCKER_MAKE_FAVORITE "bloodsucker_make_favorite"
///Called when a new Vassal is successfully made: (datum/bloodsucker_datum)
#define BLOODSUCKER_MADE_VASSAL "bloodsucker_made_vassal"
///Called when a Bloodsucker exits Torpor.
#define BLOODSUCKER_EXIT_TORPOR "bloodsucker_exit_torpor"
///Called when a Bloodsucker reaches Final Death.
#define BLOODSUCKER_FINAL_DEATH "bloodsucker_final_death"
///Whether the Bloodsucker should not be dusted when arriving Final Death
#define DONT_DUST (1<<0)
///Called when a Bloodsucker breaks the Masquerade
#define COMSIG_BLOODSUCKER_BROKE_MASQUERADE "comsig_bloodsucker_broke_masquerade"
///Called when a Bloodsucker enters Frenzy
#define BLOODSUCKER_ENTERS_FRENZY "bloodsucker_enters_frenzy"
///Called when a Bloodsucker exits Frenzy
#define BLOODSUCKER_EXITS_FRENZY "bloodsucker_exits_frenzy"

/**
* Sol signals & Defines
*/
#define COMSIG_SOL_RANKUP_BLOODSUCKERS "comsig_sol_rankup_bloodsuckers"
#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)
#define COMSIG_SOL_WARNING_GIVEN "comsig_sol_warning_given"
///Called on a Bloodsucker's Lifetick.
#define COMSIG_BLOODSUCKER_ON_LIFETICK "comsig_bloodsucker_on_lifetick"

#define DANGER_LEVEL_FIRST_WARNING 1
#define DANGER_LEVEL_SECOND_WARNING 2
#define DANGER_LEVEL_THIRD_WARNING 3
#define DANGER_LEVEL_SOL_ROSE 4
#define DANGER_LEVEL_SOL_ENDED 5

/**
* Clan defines
*
* This is stuff that is used solely by Clans for clan-related activity.
*/
///Drinks blood the normal Bloodsucker way.
#define BLOODSUCKER_DRINK_NORMAL "bloodsucker_drink_normal"
///Drinks blood but is snobby, refusing to drink from mindless
#define BLOODSUCKER_DRINK_SNOBBY "bloodsucker_drink_snobby"
///Drinks blood from disgusting creatures without Humanity consequences.
#define BLOODSUCKER_DRINK_INHUMANELY "bloodsucker_drink_imhumanely"

/**
* Role defines
*/
#define ROLE_BLOODSUCKER "Bloodsucker"
#define ROLE_VAMPIRICACCIDENT "Vampiric Accident"
#define ROLE_BLOODSUCKERBREAKOUT "Bloodsucker Breakout"
#define ROLE_INFILTRATOR "Infiltrator"

/**
* Macros
*/
///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))

//Used in bloodsucker_life.dm
#define MARTIALART_FRENZYGRAB "frenzy grabbing"
3 changes: 3 additions & 0 deletions code/__DEFINES/role_preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ GLOBAL_LIST_INIT(special_roles, list(
ROLE_TRAITOR = 0,
ROLE_WIZARD = 14,
ROLE_SPY = 0,
ROLE_BLOODSUCKER = 0,

// Midround
ROLE_ABDUCTOR = 0,
Expand All @@ -158,12 +159,14 @@ GLOBAL_LIST_INIT(special_roles, list(
ROLE_SPIDER = 0,
ROLE_WIZARD_MIDROUND = 14,
ROLE_VOIDWALKER = 0,
ROLE_VAMPIRICACCIDENT = 0,

// Latejoin
ROLE_HERETIC_SMUGGLER = 0,
ROLE_PROVOCATEUR = 14,
ROLE_SYNDICATE_INFILTRATOR = 0,
ROLE_STOWAWAY_CHANGELING = 0,
ROLE_BLOODSUCKERBREAKOUT = 0,

// I'm not too sure why these are here, but they're not moving.
ROLE_GLITCH = 0,
Expand Down
1 change: 1 addition & 0 deletions code/__DEFINES/traits/sources.dm
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,4 @@

/// Trait aquired from being painted a certain color
#define ATOM_COLOR_TRAIT "atom_color"

4 changes: 4 additions & 0 deletions modular_bandastation/blood_suckers/_blood_suckers.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/datum/modpack/jobs
name = "Blood Sucker"
desc = "Портирование антаганиста бладсакер с монки."
author = "dwasint, Lime-7"
67 changes: 67 additions & 0 deletions modular_bandastation/blood_suckers/_blood_suckers.dme
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "_blood_suckers.dm"

#include "code/bloodsucker/bloodsucker_conversion.dm"
#include "code/bloodsucker/bloodsucker_datum.dm"
#include "code/bloodsucker/bloodsucker_flaws.dm"
#include "code/bloodsucker/bloodsucker_frenzy.dm"
#include "code/bloodsucker/bloodsucker_guardian.dm"
#include "code/bloodsucker/bloodsucker_hud.dm"
#include "code/bloodsucker/bloodsucker_life.dm"
#include "code/bloodsucker/bloodsucker_misc_procs.dm"
#include "code/bloodsucker/bloodsucker_moodlets.dm"
#include "code/bloodsucker/bloodsucker_names.dm"
#include "code/bloodsucker/bloodsucker_objectives.dm"
#include "code/bloodsucker/bloodsucker_overwrites.dm"
#include "code/bloodsucker/bloodsucker_ruleset.dm"
#include "code/bloodsucker/bloodsucker_shaded.dm"
#include "code/bloodsucker/bloodsucker_sol.dm"
#include "code/bloodsucker/bloodsucker_traumas.dm"

#include "code/clans/_clan_base.dm"
#include "code/clans/_clan_flavortext.dm"
#include "code/clans/malkavian.dm"
#include "code/clans/nosferatu.dm"
#include "code/clans/tremere.dm"
#include "code/clans/venture.dm"

#include "code/controllers/sunlight.dm"

#include "code/powers/targeted/_base_targeted.dm"
#include "code/powers/targeted/brawn.dm"
#include "code/powers/targeted/haste.dm"
#include "code/powers/targeted/lunge.dm"
#include "code/powers/targeted/mesmerize.dm"
#include "code/powers/targeted/trespass.dm"

#include "code/powers/tremere/_base_tremere.dm"
#include "code/powers/tremere/auspex.dm"
#include "code/powers/tremere/dominate.dm"
#include "code/powers/tremere/thaumaturgey.dm"

#include "code/powers/vassal/distress.dm"
#include "code/powers/vassal/recuperate.dm"
#include "code/powers/vassal/vassal_fold.dm"

#include "code/powers/_base_power.dm"
#include "code/powers/cloak.dm"
#include "code/powers/feed.dm"
#include "code/powers/fortitude.dm"
#include "code/powers/go_home.dm"
#include "code/powers/masquerade.dm"
#include "code/powers/veil.dm"

#include "code/structures/bloodsucker_coffin.dm"
#include "code/structures/bloodsucker_crypt.dm"
#include "code/structures/bloodsucker_objects.dm"
#include "code/structures/bloodsucker_recipes.dm"

#include "code/vassals/types/favorite.dm"
#include "code/vassals/types/revenge.dm"

#include "code/vassals/batform.dm"
#include "code/vassals/ex_vassal.dm"
#include "code/vassals/vassal_datum.dm"
#include "code/vassals/vassal_misc_procs.dm"
#include "code/vassals/vassal_pinpointer.dm"

#include "code/bloodsucker_assets.dm"
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/**
* Checks if the target has antag datums and, if so,
* are they allowed to be Vassalized, or not, or banned.
* Args:
* target - The person we check for antag datums.
*/
/datum/antagonist/bloodsucker/proc/AmValidAntag(mob/target)
. = VASSALIZATION_ALLOWED
if(!target.mind || HAS_MIND_TRAIT(target, TRAIT_UNCONVERTABLE))
return VASSALIZATION_BANNED

for(var/datum/antagonist/antag_datum as anything in target.mind.antag_datums)
if(antag_datum.type in vassal_banned_antags)
return VASSALIZATION_BANNED
return VASSALIZATION_DISLOYAL
if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
return VASSALIZATION_DISLOYAL


/**
* # can_make_vassal
* 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
* has broken the Masquerade, to steal them.
* Args:
* conversion_target - Person being vassalized
*/
/datum/antagonist/bloodsucker/proc/can_make_vassal(mob/living/conversion_target)
if(!iscarbon(conversion_target))
return FALSE
if(length(vassals) == return_current_max_vassals())
to_chat(owner.current, span_danger("You find that your powers run thin and are unable to dominate their mind with your blood!"))
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."))
return FALSE
if(AmValidAntag(conversion_target) == VASSALIZATION_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()
if(!master || (master == owner.current))
return TRUE
var/datum/antagonist/bloodsucker/bloodsuckerdatum = master.mind.has_antag_datum(/datum/antagonist/bloodsucker)
if(bloodsuckerdatum?.broke_masquerade)
//vassal 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

/**
* This proc is responsible for calculating how many vassals you can have at any given
* time, ranges from 1 at 20 pop to 4 at 40 pop
*/
/datum/antagonist/bloodsucker/proc/return_current_max_vassals()
var/total_players = length(GLOB.joined_player_list)
switch(total_players)
if(1 to 20)
return 1
if(21 to 30)
return 3
else
return 4

/**
* First will check if the target can be turned into a Vassal, 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)
if(!can_make_vassal(conversion_target))
return FALSE

//Check if they used to be a Vassal and was stolen.
if(IS_VASSAL(conversion_target))
conversion_target.mind.remove_antag_datum(/datum/antagonist/vassal)

var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.has_antag_datum(/datum/antagonist/bloodsucker)
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)

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].")
return TRUE

/*
* # can_make_special
*
* MIND Helper proc that ensures the person can be a Special Vassal,
* without actually giving the antag datum to them.
* This is because Special Vassals 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.
*/
/datum/mind/proc/can_make_special(datum/mind/creator)
var/mob/living/user = current
if(!(user.mob_biotypes & MOB_ORGANIC))
if(creator)
to_chat(creator, span_danger("[user]'s DNA isn't compatible!"))
return FALSE
return TRUE

/*
* # make_bloodsucker
*
* MIND Helper proc that turns the person into a Bloodsucker
* Args:
* creator - Person attempting to convert them.
*/
/datum/mind/proc/make_bloodsucker(datum/mind/creator)
var/datum/antagonist/bloodsuckerdatum = add_antag_datum(/datum/antagonist/bloodsucker)
if(bloodsuckerdatum && creator)
message_admins("[src] has become a Bloodsucker, and was created by [creator].")
log_admin("[src] has become a Bloodsucker, and was created by [creator].")
return bloodsuckerdatum
Loading
Loading