mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 21:18:37 +01:00
[DONE] A bunch of bloodsucker changes (#1061)
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may not be viewable. --> <!-- You can view Contributing.MD for a detailed description of the pull request process. --> ## About The Pull Request This adds a bunch of things as a addition to my original bloodsucker PR, there's still one PR in the plans to refactor bloodsucker abilities. #What this adds: - Bloodsuckers loosing the heart or brain is lethal, before you could simply walk around without a heart. Does not however cause a final death - bloodsucker vampire bats will no longer /list you when attacking, and are also just as fast as human runspeed - Blood cost for vassalizing was almost completely removed, now only taking tiny amounts of blood to do so. - Dullahans can't be bloodsuckers since... their head isn't attached. - ....buuuut bloodsuckers now kinda become helpless dullahans just with no body if they get decapicated! Funny talking head go! - Level up cost is now 15% of max blood, down from 20% - The stat bar will show you the threshold for exiting frenzy now too when you are frenzying. - Maximum blood volume is shown in the stat menu as well - Hopefully fixes some torpor loops related to frenzy - Tremere now also get informed of how much blood they need to pay for level ups. - Fortitude now gives you burn resistance, just 20% less than brute resistance - Bloodsucker abilities now will show their level when you hover over them. Trust me, this was really neccessary. - Hopefully fixes cryoing or deleted bloodsuckers not removing vassals. - Can longer use veil while unconcious or dead - Caps humanity lost to 50, this means a maximum of 500 blood to enter frenzy/ 10 fully drained people with clients, at this point you also loose the masquerade ability. - Admins can now ban bloodsuckers and vassals. - Bloodsuckers can now mesmerize mimes - Fat bloodsuckers are no longer unable to enter coffins. Now they resize their lair's coffin. Very obviously. - Lizards are no longer fucked if they are on fire, they are no longer forever too hot to survive - Going into torpor in a coffin will extinguish and set your temperature to normal - bloodsuckers will no longer accrue toxin damage from not having a liver or having a failing one, even though they had the toxin immune trait - synths will now heal their prosthetic limbs - torpor start now checks for oxygen and toxin damage, and heals both completely on it's end - Haste will remove stuns at level 3, and do a non-stunning dash - Tremere dominate vassalizing now actually works! - Fixes ventrue objectives not succeeding properly - Refactors the heart thief objective and improves it by requiring it to be non-monkey hearts and letting bloodsuckers examine hearts to see if they are valid, even uses the same logic, too! - Ventrue favorite vassal batform now has night vision, and it's spawned bats despawn once the cooldown refreshes, and halves it's cooldown to 1 minute - Traits added to vassals get removed once they loose their antag datum, ie favorite vassal traits, or the ones gained in the process of ventrue sire-ing. - Favorite vassals now clean up propertly when the antag datum is removed, tremere, and malkavian clean up their related additions. - Refactors how the blood display updates, instead it now updates every time your blood level is changed, making it update far faster and only when it's needed. - Stakes now have different properties, the normal stake is fast to stick in someone, but can fall out on it's own, the burnt one takes longer to be put in, but doesn't fall out, the silver stake is the slowest to be stuffed in someone's heart, and is the only stake to be able to cause a Final Death to a sleeping or dead bloodsucker <!-- Describe The Pull Request. Please be sure every change is documented or this can delay review and even discourage maintainers from merging your PR! --> closes #1180, closes #1208 <!-- Please make sure to actually test your PRs. If you have not tested your PR mention it. --> ## Why It's Good For The Game <!-- Argue for the merits of your changes and how they benefit the game, especially if they are controversial and/or far reaching. If you can't actually explain WHY what you are doing will improve the game, then it probably isn't good for the game in the first place. --> ## Proof Of Testing The way I develop is always run a local server and test the changes that I do, takes awhile but won't have as many bugs as a result <!-- Compile and run your code locally. Make sure it works. This is the place to show off your changes! We are not responsible for testing your features. --> ## Changelog <!-- If your PR modifies aspects of the game that can be concretely observed by players or admins you should add a changelog. If your change does NOT meet this description, remove this section. Be sure to properly mark your PRs to prevent unnecessary GBP loss. You can read up on GBP and it's effects on PRs in the tgstation guides for contributors. Please note that maintainers freely reserve the right to remove and add tags should they deem it appropriate. You can attempt to finagle the system all you want, but it's best to shoot for clear communication right off the bat. --> 🆑 add: Decapacitated bloodsuckers can now talk! add: The stat bar will show you the threshold for exiting frenzy now too when you are frenzying. add: Bloodsucker abilities now will show their level when you hover over them. Trust me, this was really neccessary. add: Tremere now also get informed of how much blood they need to pay for level ups. add: At level 3, haste will now remove stuns and do a non-stunning dash add: Bloodsucker blood display now always updates when a bloodsucker's blood level is changed add: Bloodsuckers can now examine hearts to see if they are valid for the heart thief objective add: Bloodsucker vassals now clean up any traits gained from their tenure as a vampire's minion. add: Favorite vassals now properly clean up their effects once the antag datum is lost. add: Bloodsucker synths will be able to heal their prosthetic limbs, but normal bloodsuckers still cannot. add: When you exiit torpor as a bloodsucker, you will completely heal any toxin and oxygen damage, as you should already be immune to it. This is a safety feature. add: Entering a coffin will normalize your temperature and extinguish you if you're on fire, if you are a bloodsucker. fix: bloodsucker vampire bats will no longer /list you when attacking fix: Hopefully fixes some torpor loops related to frenzy fix: Hopefully fixes bloodsuckers cryoing not removing vassal datums fix: Bloodsuckers can no longer use veil of many faces while unconcious fix: lizard bloodsuckers will no longer suffer from heat for a long time fix: The ventrue objective now properly succeeds if you have sired a vampire fix: Livers are no longer required for bloodsuckers to live, as it caused them toxin damage which overrode the trait that made them immune to toxins. fix: Entering torpor now accounts for all damage types, even when you should be immune to them. This is to ensure you enter torpor to heal those damage types in the case of odd behaviour. balance: coffins should now set your temperature to normal and extinguish you. balance: bloodsucker level up cost is now 15% of max blood, down from 20% balance: Caps humantiy loss at 50 humanity/500 blood to frenzy, and makes it remove your masquerade ability. balance: Bloodsucker bats now have human runspeed balance: Blood cost for vassalizing was almost completely removed, now only taking tiny amounts of blood to do so. balance: Fortitude now gives you burn resistance, just 20% less than brute resistance balance: Can no longer gut bloodsuckers balance: Bloodsuckers loosing their heart will make the vampire unable to use their abilities or even regenerateor revive via torpor, you can however regain your heart if you sleep in a coffin with a heart. balance: Stakes now have different properties, the normal stake is fast to stick in someone, but can fall out on it's own, the burnt one takes longer to be put in, but doesn't fall out, the silver stake is the slowest to be stuffed in someone's heart, and is the only stake to be able to cause a Final Death to a sleeping or dead bloodsucker del: Dullahans can't be bloodsuckers since... their head isn't attached admin: Bloodsuckers and vassals can now be banned like other antags. /🆑 <!-- Both 🆑's are required for the changelog to work! You can put your name to the right of the first 🆑 if you want to overwrite your GitHub username as author ingame. --> <!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. --> <!-- By opening a pull request. You have read and understood the repository rules located on the main README.md on this project. --> --------- Co-authored-by: Waterpig <49160555+Majkl-J@users.noreply.github.com>
This commit is contained in:
@@ -137,6 +137,7 @@
|
||||
#define ROLE_VAMPIRICACCIDENT "Bloodsucker (Midround)"
|
||||
#define ROLE_BLOODSUCKERBREAKOUT "Bloodsucker (Latejoin)"
|
||||
#define ROLE_MONSTERHUNTER "Monster Hunter"
|
||||
#define ROLE_VASSAL "Vassal"
|
||||
//BUBBER EDIT END
|
||||
|
||||
/// This defines the antagonists you can operate with in the settings.
|
||||
|
||||
@@ -433,6 +433,8 @@
|
||||
ROLE_WIZARD,
|
||||
ROLE_BORER, //SKYRAT EDIT
|
||||
ROLE_ASSAULT_OPERATIVE, //SKYRAT EDIT
|
||||
ROLE_BLOODSUCKER,// BUBBER EDIT,
|
||||
ROLE_VASSAL, // BUBBER EDIT
|
||||
),
|
||||
"Skyrat Ban Options" = list(
|
||||
BAN_PACIFICATION,
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
/mob/living/brain/say(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null, filterpoof = null, message_range = 7, datum/saymode/saymode = null)
|
||||
// BUBBER CHANGE: funny talking head
|
||||
if(stat == DEAD) // lets you talk in deadchat
|
||||
return ..()
|
||||
var/datum/antagonist/bloodsucker/spooky_vampire_head = mind?.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
if(!container && spooky_vampire_head)
|
||||
var/obj/head = spooky_vampire_head.is_head(src)
|
||||
if(!head)
|
||||
return
|
||||
var/animation_time = max(2, length_char(message) * 0.5)
|
||||
head.Shake(duration = animation_time)
|
||||
..()
|
||||
// BUBBER CHANGE END
|
||||
if(!(container && istype(container, /obj/item/mmi)))
|
||||
return //No MMI, can't speak, bucko./N
|
||||
else
|
||||
|
||||
+30
-4
@@ -4,22 +4,29 @@
|
||||
/// You have special interactions with Bloodsuckers
|
||||
#define TRAIT_BLOODSUCKER_HUNTER "bloodsucker_hunter"
|
||||
|
||||
// how much to multiply the coffin size by mob_size
|
||||
#define COFFIN_ENLARGE_MULT 0.5
|
||||
/**
|
||||
* 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
|
||||
#define TORTURE_BLOOD_HALF_COST 4
|
||||
/// Cost to convert someone after successful torture, in blood
|
||||
#define TORTURE_CONVERSION_COST 50
|
||||
#define TORTURE_CONVERSION_COST 10
|
||||
/// How much blood it costs you to make a vassal into a special vassal
|
||||
#define SPECIAL_VASSAL_COST 150
|
||||
/// Once blood is this low, will enter Frenzy
|
||||
#define FRENZY_THRESHOLD_ENTER 25
|
||||
/// Once blood is this high, will exit Frenzy
|
||||
#define FRENZY_THRESHOLD_EXIT 250
|
||||
|
||||
/// a bloodsucker can't loose more humanity than this, and looses the masquerade ability when reaching it
|
||||
#define HUMANITY_LOST_MAXIMUM 50
|
||||
|
||||
/// Level up blood cost define, max_blood * this = blood cost
|
||||
#define BLOODSUCKER_LEVELUP_PERCENTAGE 0.2
|
||||
#define BLOODSUCKER_LEVELUP_PERCENTAGE 0.15
|
||||
|
||||
///The level when at a bloodsucker becomes snobby about who they drink from and gain their non-fledling reputation
|
||||
#define BLOODSUCKER_HIGH_LEVEL 4
|
||||
@@ -73,7 +80,7 @@
|
||||
/// This Power can't be used in Frenzy.
|
||||
#define BP_CANT_USE_IN_FRENZY (1<<2)
|
||||
/// This Power can't be used with a stake in you
|
||||
#define BP_CANT_USE_WHILE_STAKED (1<<3)
|
||||
#define BP_CAN_USE_WHILE_STAKED (1<<3)
|
||||
/// This Power can't be used while incapacitated
|
||||
#define BP_CANT_USE_WHILE_INCAPACITATED (1<<4)
|
||||
/// This Power can't be used while unconscious
|
||||
@@ -97,6 +104,13 @@
|
||||
/// This Power doesn't cost bloot to run while unconscious
|
||||
#define BP_AM_COSTLESS_UNCONSCIOUS (1<<3)
|
||||
|
||||
/**
|
||||
* Torpor check bitflags
|
||||
*/
|
||||
#define TORPOR_SKIP_CHECK_ALL (1<<0)
|
||||
#define TORPOR_SKIP_CHECK_FRENZY (1<<1)
|
||||
#define TORPOR_SKIP_CHECK_DAMAGE (1<<2)
|
||||
|
||||
/**
|
||||
* Bloodsucker Signals
|
||||
*/
|
||||
@@ -106,6 +120,8 @@
|
||||
#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 bloodsucker looses their favorite vassal, cleaning up whatever they gained
|
||||
#define BLOODSUCKER_LOOSE_FAVORITE "bloodsucker_loose_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.
|
||||
@@ -120,6 +136,8 @@
|
||||
#define BLOODSUCKER_ENTERS_FRENZY "bloodsucker_enters_frenzy"
|
||||
///Called when a Bloodsucker exits Frenzy
|
||||
#define BLOODSUCKER_EXITS_FRENZY "bloodsucker_exits_frenzy"
|
||||
// Called when anyone enters the coffin
|
||||
#define COMSIG_ENTER_COFFIN "comsig_enter_coffin"
|
||||
|
||||
/**
|
||||
* Sol signals & Defines
|
||||
@@ -164,6 +182,12 @@
|
||||
*/
|
||||
/// Source trait for Bloodsuckers-related traits
|
||||
#define BLOODSUCKER_TRAIT "bloodsucker_trait"
|
||||
|
||||
#define VASSAL_TRAIT "vassal_trait"
|
||||
|
||||
/// Source trait for dominate related traits
|
||||
#define DOMINATE_TRAIT "dominate_trait"
|
||||
|
||||
/// Source trait for Monster Hunter-related traits
|
||||
#define HUNTER_TRAIT "monsterhunter_trait"
|
||||
/// Source trait while Feeding
|
||||
@@ -186,6 +210,7 @@
|
||||
#define IS_MONSTERHUNTER(mob) (FALSE)
|
||||
|
||||
#define BLOODSUCKER_SIGHT_COLOR_CUTOFF list(25, 8, 5)
|
||||
#define POLL_IGNORE_VASSAL "vassal"
|
||||
|
||||
// Why waste memory on a dynamic global list if we can just bake it in on compile time?
|
||||
#define BLOODSUCKER_PROTECTED_ROLES list( \
|
||||
@@ -214,4 +239,5 @@
|
||||
/datum/species/skeleton, \
|
||||
/datum/species/zombie, \
|
||||
/datum/species/mutant, \
|
||||
/datum/species/dullahan \
|
||||
) \
|
||||
@@ -1 +1,3 @@
|
||||
#define TRAIT_MONOPHOBIA "monophobia"
|
||||
|
||||
#define TRAIT_COFFIN_ENLARGED "coffin_enlarged"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
/datum/action
|
||||
/// Extended description of the action, usually shown in an antag UI.
|
||||
var/power_explanation = ""
|
||||
@@ -38,6 +38,8 @@
|
||||
/datum/dynamic_ruleset/roundstart/bloodsucker/execute()
|
||||
for(var/datum/mind/candidate_minds as anything in assigned)
|
||||
if(!candidate_minds.make_bloodsucker())
|
||||
candidate_minds.special_role = null
|
||||
candidate_minds.restricted_roles = null
|
||||
message_admins("[ADMIN_LOOKUPFLW(candidate_minds)] was selected by the [name] ruleset, but couldn't be made into a Bloodsucker.")
|
||||
assigned -= candidate_minds
|
||||
continue
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
/datum/antagonist
|
||||
var/antag_panel_title = "Antagonist Panel"
|
||||
var/antag_panel_description = "This is the antagonist panel. It contains all the abilities you have access to as an antagonist. Use them wisely."
|
||||
|
||||
/datum/antagonist/proc/ability_ui_data(actions = list())
|
||||
var/list/data = list()
|
||||
data["title"] = "[antag_panel_title]\n[antag_panel_data()]"
|
||||
data["description"] = antag_panel_description
|
||||
for(var/datum/action/cooldown/power as anything in actions)
|
||||
var/list/power_data = list()
|
||||
|
||||
power_data["power_name"] = power.name
|
||||
power_data["power_explanation"] = power?.power_explanation
|
||||
power_data["power_icon"] = power.button_icon_state
|
||||
|
||||
data["powers"] += list(power_data)
|
||||
return data
|
||||
@@ -24,6 +24,8 @@
|
||||
COOLDOWN_DECLARE(bloodsucker_spam_sol_burn)
|
||||
///Timer between alerts for Healing messages
|
||||
COOLDOWN_DECLARE(bloodsucker_spam_healing)
|
||||
/// Timer between exiting torpor
|
||||
COOLDOWN_DECLARE(bloodsucker_spam_torpor)
|
||||
|
||||
///Used for assigning your name
|
||||
var/bloodsucker_name
|
||||
@@ -38,10 +40,10 @@
|
||||
var/broke_masquerade = FALSE
|
||||
///How many Masquerade Infractions do we have?
|
||||
var/masquerade_infractions = 0
|
||||
///Blood required to enter Frenzy
|
||||
var/frenzy_threshold = FRENZY_THRESHOLD_ENTER
|
||||
///If we are currently in a Frenzy
|
||||
var/frenzied = FALSE
|
||||
/// sired by a ventrue
|
||||
var/ventrue_sired
|
||||
|
||||
///ALL Powers currently owned
|
||||
var/list/datum/action/cooldown/bloodsucker/powers = list()
|
||||
@@ -91,12 +93,18 @@
|
||||
TRAIT_AGEUSIA,
|
||||
TRAIT_COLDBLOODED,
|
||||
TRAIT_VIRUSIMMUNE,
|
||||
TRAIT_TOXIMMUNE,
|
||||
TRAIT_HARDLY_WOUNDED,
|
||||
TRAIT_NO_MIRROR_REFLECTION,
|
||||
TRAIT_DRINKS_BLOOD
|
||||
TRAIT_DRINKS_BLOOD,
|
||||
TRAIT_TOXIMMUNE,
|
||||
// Fun fact, toxins can still be applied to you if you loose your liver even with TOXIMMUNE
|
||||
TRAIT_STABLELIVER
|
||||
)
|
||||
var/biotype = MOB_VAMPIRIC
|
||||
var/static/biotype = MOB_VAMPIRIC
|
||||
/// Weakref to the owner mob's heart, without bloodsucker_life stops and they die. Handled via signals due to the fact that
|
||||
/// Bloodsuckers don't take damage from lacking a heart due to TRAIT_NOBREATH
|
||||
/// Saved here so we can keep a track of it and remove signals properly
|
||||
var/datum/weakref/heart
|
||||
|
||||
/**
|
||||
* Apply innate effects is everything given to the mob
|
||||
@@ -110,6 +118,9 @@
|
||||
RegisterSignal(current_mob, COMSIG_LIVING_LIFE, PROC_REF(LifeTick))
|
||||
RegisterSignal(current_mob, COMSIG_LIVING_DEATH, PROC_REF(on_death))
|
||||
RegisterSignal(current_mob, COMSIG_SPECIES_GAIN, PROC_REF(on_species_gain))
|
||||
RegisterSignal(current_mob, COMSIG_QDELETING, PROC_REF(on_removal))
|
||||
RegisterSignal(current_mob, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(on_organ_gain))
|
||||
talking_head()
|
||||
handle_clown_mutation(current_mob, mob_override ? null : "As a vampiric clown, you are no longer a danger to yourself. Your clownish nature has been subdued by your thirst for blood.")
|
||||
add_team_hud(current_mob)
|
||||
|
||||
@@ -117,7 +128,9 @@
|
||||
on_hud_created()
|
||||
else
|
||||
RegisterSignal(current_mob, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created))
|
||||
current_mob?.dna?.species.on_bloodsucker_gain(current_mob)
|
||||
if(ishuman(current_mob))
|
||||
current_mob?.dna?.species.on_bloodsucker_gain(current_mob)
|
||||
add_signals_to_heart(current_mob)
|
||||
#ifdef BLOODSUCKER_TESTING
|
||||
var/turf/user_loc = get_turf(current_mob)
|
||||
new /obj/structure/closet/crate/coffin(user_loc)
|
||||
@@ -126,13 +139,14 @@
|
||||
|
||||
/**
|
||||
* Remove innate effects is everything given to the mob
|
||||
* When a body is tranferred, this is called on the old mob.
|
||||
* When a body is transferred, this is called on the old mob.
|
||||
* while on_removal is called ONCE per ANTAG, this is called ONCE per BODY.
|
||||
*/
|
||||
/datum/antagonist/bloodsucker/remove_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
var/mob/living/carbon/current_mob = mob_override || owner.current
|
||||
UnregisterSignal(current_mob, list(COMSIG_LIVING_LIFE, COMSIG_ATOM_EXAMINE, COMSIG_LIVING_DEATH, COMSIG_SPECIES_GAIN))
|
||||
remove_signals_from_heart(current_mob)
|
||||
UnregisterSignal(current_mob, list(COMSIG_LIVING_LIFE, COMSIG_ATOM_EXAMINE, COMSIG_LIVING_DEATH, COMSIG_SPECIES_GAIN, COMSIG_QDELETING))
|
||||
handle_clown_mutation(current_mob, removing = FALSE)
|
||||
|
||||
if(current_mob.hud_used)
|
||||
@@ -160,17 +174,21 @@
|
||||
|
||||
bloodsucker_hud.show_hud(bloodsucker_hud.hud_version)
|
||||
UnregisterSignal(owner.current, COMSIG_MOB_HUD_CREATED)
|
||||
update_hud()
|
||||
update_blood_hud()
|
||||
|
||||
/// Override some properties of incompatible species
|
||||
/datum/antagonist/bloodsucker/proc/on_species_gain(mob/living/carbon/human/target, datum/species/current_species, datum/species/old_species)
|
||||
SIGNAL_HANDLER
|
||||
if(!ishuman(owner.current))
|
||||
return
|
||||
add_signals_to_heart(target)
|
||||
var/mob/living/carbon/human/user = owner.current
|
||||
user?.dna?.species.on_bloodsucker_gain(target)
|
||||
|
||||
/datum/antagonist/bloodsucker/get_admin_commands()
|
||||
. = ..()
|
||||
.["Set blood level"] = CALLBACK(src, PROC_REF(admin_set_blood))
|
||||
.["Give Level"] = CALLBACK(src, PROC_REF(RankUp), TRUE)
|
||||
if(bloodsucker_level_unspent >= 1)
|
||||
.["Remove Level"] = CALLBACK(src, PROC_REF(RankDown))
|
||||
@@ -187,13 +205,14 @@
|
||||
|
||||
///Called when you get the antag datum, called only ONCE per antagonist.
|
||||
/datum/antagonist/bloodsucker/on_gain()
|
||||
if(!owner?.current)
|
||||
return ..()
|
||||
RegisterSignal(SSsunlight, COMSIG_SOL_RANKUP_BLOODSUCKERS, PROC_REF(sol_rank_up))
|
||||
RegisterSignal(SSsunlight, COMSIG_SOL_NEAR_START, PROC_REF(sol_near_start))
|
||||
RegisterSignal(SSsunlight, COMSIG_SOL_END, PROC_REF(on_sol_end))
|
||||
RegisterSignal(SSsunlight, COMSIG_SOL_RISE_TICK, PROC_REF(handle_sol))
|
||||
RegisterSignal(SSsunlight, COMSIG_SOL_WARNING_GIVEN, PROC_REF(give_warning))
|
||||
|
||||
if(IS_VASSAL(owner.current)) // Vassals shouldnt be getting the same benefits as Bloodsuckers.
|
||||
if(ventrue_sired) // sired bloodsuckers shouldnt be getting the same benefits as Bloodsuckers.
|
||||
bloodsucker_level_unspent = 0
|
||||
show_in_roundend = FALSE
|
||||
else
|
||||
@@ -213,13 +232,16 @@
|
||||
|
||||
/// 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()
|
||||
UnregisterSignal(SSsunlight, list(COMSIG_SOL_RANKUP_BLOODSUCKERS, COMSIG_SOL_NEAR_START, COMSIG_SOL_END, COMSIG_SOL_RISE_TICK, COMSIG_SOL_WARNING_GIVEN, COMSIG_QDELETING))
|
||||
free_all_vassals()
|
||||
check_cancel_sunlight() //check if sunlight should end
|
||||
if(!owner?.current)
|
||||
return
|
||||
if(ishuman(owner.current))
|
||||
var/mob/living/carbon/human/user = owner.current
|
||||
user?.dna?.species.regenerate_organs(user, null, TRUE)
|
||||
UnregisterSignal(SSsunlight, list(COMSIG_SOL_RANKUP_BLOODSUCKERS, COMSIG_SOL_NEAR_START, COMSIG_SOL_END, COMSIG_SOL_RISE_TICK, COMSIG_SOL_WARNING_GIVEN))
|
||||
clear_powers_and_stats()
|
||||
check_cancel_sunlight() //check if sunlight should end
|
||||
free_all_vassals()
|
||||
ventrue_sired = null
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/bloodsucker/on_body_transfer(mob/living/old_body, mob/living/new_body)
|
||||
@@ -306,7 +328,7 @@
|
||||
return finish_preview_icon(final_icon)
|
||||
|
||||
/datum/antagonist/bloodsucker/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
var/list/data = ability_ui_data(powers)
|
||||
//we don't need to update this that much.
|
||||
data["in_clan"] = !!my_clan
|
||||
var/list/clan_data = list()
|
||||
@@ -317,15 +339,6 @@
|
||||
|
||||
data["clan"] += list(clan_data)
|
||||
|
||||
for(var/datum/action/cooldown/bloodsucker/power as anything in powers)
|
||||
var/list/power_data = list()
|
||||
|
||||
power_data["power_name"] = power.name
|
||||
power_data["power_explanation"] = power.power_explanation
|
||||
power_data["power_icon"] = power.button_icon_state
|
||||
|
||||
data["powers"] += list(power_data)
|
||||
|
||||
return data + ..()
|
||||
|
||||
/datum/antagonist/bloodsucker/ui_assets(mob/user)
|
||||
@@ -343,8 +356,9 @@
|
||||
if(my_clan)
|
||||
return
|
||||
assign_clan_and_bane()
|
||||
if(ui.closing)
|
||||
return
|
||||
ui.send_full_update(force = TRUE)
|
||||
return
|
||||
|
||||
/datum/antagonist/bloodsucker/roundend_report()
|
||||
var/list/report = list()
|
||||
@@ -403,10 +417,10 @@
|
||||
var/obj/item/bodypart/user_left_arm = user.get_bodypart(BODY_ZONE_L_ARM)
|
||||
var/obj/item/bodypart/user_right_arm = user.get_bodypart(BODY_ZONE_R_ARM)
|
||||
user.dna?.remove_all_mutations()
|
||||
user_left_arm.unarmed_damage_low += 1 //lowest possible punch damage - 0
|
||||
user_left_arm.unarmed_damage_high += 1 //highest possible punch damage - 9
|
||||
user_right_arm.unarmed_damage_low += 1 //lowest possible punch damage - 0
|
||||
user_right_arm.unarmed_damage_high += 1 //highest possible punch damage - 9
|
||||
user_left_arm.unarmed_damage_low += 1 //lowest possible punch damage - 6 now
|
||||
user_left_arm.unarmed_damage_high += 1 //highest possible punch damage - 11
|
||||
user_right_arm.unarmed_damage_low += 1 //lowest possible punch damage - 6
|
||||
user_right_arm.unarmed_damage_high += 1 //highest possible punch damage - 11
|
||||
user.mob_biotypes |= biotype
|
||||
//Give Bloodsucker Traits
|
||||
owner.current.add_traits(bloodsucker_traits, BLOODSUCKER_TRAIT)
|
||||
@@ -417,7 +431,7 @@
|
||||
if(HAS_TRAIT(owner.current, TRAIT_SKITTISH))
|
||||
REMOVE_TRAIT(owner.current, TRAIT_SKITTISH, ROUNDSTART_TRAIT)
|
||||
// Tongue & Language
|
||||
owner.current.grant_language(/datum/language/vampiric, LANGUAGE_SPOKEN, LANGUAGE_MIND)
|
||||
owner.current.grant_language(/datum/language/vampiric, ALL, LANGUAGE_MIND)
|
||||
/// Clear Disabilities & Organs
|
||||
heal_vampire_organs()
|
||||
|
||||
@@ -439,6 +453,8 @@
|
||||
// Powers
|
||||
for(var/datum/action/cooldown/bloodsucker/all_powers as anything in powers)
|
||||
RemovePower(all_powers)
|
||||
if(QDELETED(owner.current))
|
||||
return
|
||||
/// Stats
|
||||
if(ishuman(owner.current))
|
||||
var/mob/living/carbon/human/user = owner.current
|
||||
@@ -451,6 +467,9 @@
|
||||
if(right_arm)
|
||||
right_arm.unarmed_damage_low = initial(right_arm.unarmed_damage_low)
|
||||
right_arm.unarmed_damage_high = initial(right_arm.unarmed_damage_high)
|
||||
var/obj/item/bodypart/chest/target_chest = owner.current.get_bodypart(BODY_ZONE_CHEST)
|
||||
if(target_chest && target_chest.bodypart_flags & BODYPART_UNREMOVABLE)
|
||||
target_chest.bodypart_flags &= ~BODYPART_UNREMOVABLE
|
||||
// Remove all bloodsucker traits
|
||||
owner.current.remove_traits(bloodsucker_traits, BLOODSUCKER_TRAIT)
|
||||
// Language
|
||||
@@ -497,7 +516,7 @@
|
||||
conversion_objective.objective_name = "Optional Objective"
|
||||
objectives += conversion_objective
|
||||
if(2) // Heart Thief Objective
|
||||
var/datum/objective/bloodsucker/heartthief/heartthief_objective = new
|
||||
var/datum/objective/steal_n_of_type/hearts/heartthief_objective = new
|
||||
heartthief_objective.owner = owner
|
||||
heartthief_objective.objective_name = "Optional Objective"
|
||||
objectives += heartthief_objective
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* conversion_target - Person being vassalized
|
||||
*/
|
||||
/datum/antagonist/bloodsucker/proc/can_make_vassal(mob/living/conversion_target)
|
||||
if(!iscarbon(conversion_target) || conversion_target.stat > UNCONSCIOUS)
|
||||
if(!iscarbon(conversion_target) || (conversion_target.stat < CONSCIOUS))
|
||||
return FALSE
|
||||
// No Mind!
|
||||
if(!conversion_target.mind)
|
||||
@@ -53,7 +53,6 @@
|
||||
/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.
|
||||
var/datum/antagonist/vassal/old_vassal = conversion_target.mind.has_antag_datum(/datum/antagonist/vassal)
|
||||
if(old_vassal)
|
||||
|
||||
@@ -37,45 +37,49 @@
|
||||
|
||||
/// Update Blood Counter + Rank Counter
|
||||
/datum/antagonist/bloodsucker/proc/update_hud()
|
||||
var/valuecolor
|
||||
if(bloodsucker_blood_volume > BLOOD_VOLUME_SAFE)
|
||||
valuecolor = "#FFDDDD"
|
||||
else if(bloodsucker_blood_volume > BLOOD_VOLUME_BAD)
|
||||
valuecolor = "#FFAAAA"
|
||||
|
||||
if(blood_display)
|
||||
blood_display.maptext = FORMAT_BLOODSUCKER_HUD_TEXT(valuecolor, bloodsucker_blood_volume)
|
||||
|
||||
if(vamprank_display)
|
||||
if(bloodsucker_level_unspent > 0)
|
||||
vamprank_display.icon_state = "[initial(vamprank_display.icon_state)]_up"
|
||||
else
|
||||
vamprank_display.icon_state = initial(vamprank_display.icon_state)
|
||||
vamprank_display.maptext = FORMAT_BLOODSUCKER_HUD_TEXT(valuecolor, bloodsucker_level)
|
||||
vamprank_display.maptext = FORMAT_BLOODSUCKER_HUD_TEXT(hud_text_color(), bloodsucker_level)
|
||||
|
||||
if(sunlight_display)
|
||||
if(SSsunlight.sunlight_active)
|
||||
valuecolor = "#FF5555"
|
||||
sunlight_display.icon_state = "[initial(sunlight_display.icon_state)]_day"
|
||||
else
|
||||
switch(round(SSsunlight.time_til_cycle, 1))
|
||||
if(0 to 30)
|
||||
sunlight_display.icon_state = "[initial(sunlight_display.icon_state)]_30"
|
||||
valuecolor = "#FFCCCC"
|
||||
if(31 to 60)
|
||||
sunlight_display.icon_state = "[initial(sunlight_display.icon_state)]_60"
|
||||
valuecolor = "#FFE6CC"
|
||||
if(61 to 90)
|
||||
sunlight_display.icon_state = "[initial(sunlight_display.icon_state)]_90"
|
||||
valuecolor = "#FFFFCC"
|
||||
else
|
||||
sunlight_display.icon_state = "[initial(sunlight_display.icon_state)]_night"
|
||||
valuecolor = "#FFFFFF"
|
||||
sunlight_display.maptext = FORMAT_BLOODSUCKER_SUNLIGHT_TEXT( \
|
||||
valuecolor, \
|
||||
(SSsunlight.time_til_cycle >= 60) ? "[round(SSsunlight.time_til_cycle / 60, 1)] m" : "[round(SSsunlight.time_til_cycle, 1)] s" \
|
||||
)
|
||||
update_sol_hud()
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/hud_text_color()
|
||||
return bloodsucker_blood_volume > BLOOD_VOLUME_SAFE ? "#FFDDDD" : "#FFAAAA"
|
||||
|
||||
/// Updated every time blood is changed by either
|
||||
/datum/antagonist/bloodsucker/proc/update_blood_hud()
|
||||
if(!blood_display)
|
||||
return
|
||||
blood_display.maptext = FORMAT_BLOODSUCKER_HUD_TEXT(hud_text_color(), bloodsucker_blood_volume)
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/update_sol_hud()
|
||||
var/valuecolor = hud_text_color()
|
||||
if(!sunlight_display)
|
||||
return
|
||||
if(SSsunlight.sunlight_active)
|
||||
valuecolor = "#FF5555"
|
||||
sunlight_display.icon_state = "[initial(sunlight_display.icon_state)]_day"
|
||||
else
|
||||
switch(round(SSsunlight.time_til_cycle, 1))
|
||||
if(0 to 30)
|
||||
sunlight_display.icon_state = "[initial(sunlight_display.icon_state)]_30"
|
||||
valuecolor = "#FFCCCC"
|
||||
if(31 to 60)
|
||||
sunlight_display.icon_state = "[initial(sunlight_display.icon_state)]_60"
|
||||
valuecolor = "#FFE6CC"
|
||||
if(61 to 90)
|
||||
sunlight_display.icon_state = "[initial(sunlight_display.icon_state)]_90"
|
||||
valuecolor = "#FFFFCC"
|
||||
else
|
||||
sunlight_display.icon_state = "[initial(sunlight_display.icon_state)]_night"
|
||||
valuecolor = "#FFFFFF"
|
||||
sunlight_display.maptext = FORMAT_BLOODSUCKER_SUNLIGHT_TEXT( \
|
||||
valuecolor, \
|
||||
(SSsunlight.time_til_cycle >= 60) ? "[round(SSsunlight.time_til_cycle / 60, 1)] m" : "[round(SSsunlight.time_til_cycle, 1)] s" \
|
||||
)
|
||||
/// 1 tile down
|
||||
#undef UI_BLOOD_DISPLAY
|
||||
/// 2 tiles down
|
||||
|
||||
@@ -8,20 +8,21 @@
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(exposed_mob)
|
||||
if(!bloodsuckerdatum)
|
||||
return ..()
|
||||
bloodsuckerdatum.bloodsucker_blood_volume = min(bloodsuckerdatum.bloodsucker_blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM)
|
||||
|
||||
if(bloodsuckerdatum.bloodsucker_blood_volume > BLOOD_VOLUME_NORMAL)
|
||||
return
|
||||
bloodsuckerdatum.AdjustBloodVolume(round(reac_volume, 0.1))
|
||||
|
||||
/mob/living/carbon/transfer_blood_to(atom/movable/AM, amount, forced)
|
||||
. = ..()
|
||||
|
||||
if(!mind)
|
||||
return
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = mind.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
if(!bloodsuckerdatum)
|
||||
return
|
||||
bloodsuckerdatum.bloodsucker_blood_volume -= amount
|
||||
bloodsuckerdatum.AdjustBloodVolume(-amount)
|
||||
|
||||
/// Prevents using a Memento Mori
|
||||
// Prevents using a Memento Mori
|
||||
// todo move this to it's own trait
|
||||
/obj/item/clothing/neck/necklace/memento_mori/memento(mob/living/carbon/human/user)
|
||||
if(IS_BLOODSUCKER(user))
|
||||
to_chat(user, span_warning("The Memento notices your undead soul, and refuses to react.."))
|
||||
@@ -35,6 +36,7 @@
|
||||
return ..()
|
||||
|
||||
// Used when analyzing a Bloodsucker, Masquerade will hide brain traumas (Unless you're a Beefman)
|
||||
/// todo move this to it's own trait or something
|
||||
/mob/living/carbon/get_traumas()
|
||||
if(!mind)
|
||||
return ..()
|
||||
@@ -52,7 +54,11 @@
|
||||
if(bloodsuckerdatum)
|
||||
. += ""
|
||||
. += "Blood Drank: [bloodsuckerdatum.total_blood_drank]"
|
||||
. += "Frenzy blood threshold: [bloodsuckerdatum.frenzy_enter_threshold()]"
|
||||
. += "Maximum blood: [bloodsuckerdatum.max_blood_volume]"
|
||||
if(bloodsuckerdatum.frenzied)
|
||||
. += "Frenzy exit blood threshold: [bloodsuckerdatum.frenzy_exit_threshold()]"
|
||||
else
|
||||
. += "Frenzy blood threshold: [bloodsuckerdatum.frenzy_enter_threshold()]"
|
||||
|
||||
/datum/outfit/bloodsucker_outfit
|
||||
name = "Bloodsucker outfit (Preview only)"
|
||||
@@ -96,3 +102,16 @@
|
||||
continue
|
||||
amount += chosen_bodypart.burn_dam
|
||||
return amount
|
||||
|
||||
/mob/living/brain/can_be_revived()
|
||||
if(health <= HEALTH_THRESHOLD_DEAD)
|
||||
return FALSE
|
||||
if(IS_BLOODSUCKER(src))
|
||||
return TRUE
|
||||
. =..()
|
||||
|
||||
// prevents players being trapped in their brain, alive, yet limbless and voiceless
|
||||
/obj/item/bodypart/head/drop_organs(mob/user, violent_removal)
|
||||
var/obj/item/organ/internal/brain/brain = locate(/obj/item/organ/internal/brain) in src
|
||||
brain.brainmob.death()
|
||||
. = ..()
|
||||
|
||||
@@ -4,27 +4,27 @@
|
||||
/// Runs from COMSIG_LIVING_LIFE, handles Bloodsucker constant proccesses.
|
||||
/datum/antagonist/bloodsucker/proc/LifeTick(mob/living/source, seconds_per_tick, times_fired)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(isbrain(owner.current))
|
||||
return
|
||||
if(!owner)
|
||||
INVOKE_ASYNC(src, PROC_REF(HandleDeath))
|
||||
return
|
||||
if(HAS_TRAIT(owner.current, TRAIT_NODEATH))
|
||||
if(isbrain(owner.current))
|
||||
INVOKE_ASYNC(src, PROC_REF(update_hud))
|
||||
return
|
||||
if(HAS_TRAIT_FROM_ONLY(owner.current, TRAIT_NODEATH, BLOODSUCKER_TRAIT))
|
||||
check_end_torpor()
|
||||
// Deduct Blood
|
||||
if(owner.current.stat == CONSCIOUS && !HAS_TRAIT(owner.current, TRAIT_IMMOBILIZED) && !HAS_TRAIT(owner.current, TRAIT_NODEATH))
|
||||
INVOKE_ASYNC(src, PROC_REF(AddBloodVolume), -BLOODSUCKER_PASSIVE_BLOOD_DRAIN) // -.1 currently
|
||||
if(owner.current.stat == CONSCIOUS && !HAS_TRAIT(owner.current, TRAIT_IMMOBILIZED) && !HAS_TRAIT_FROM_ONLY(owner.current, TRAIT_NODEATH, BLOODSUCKER_TRAIT))
|
||||
INVOKE_ASYNC(src, PROC_REF(AdjustBloodVolume), -BLOODSUCKER_PASSIVE_BLOOD_DRAIN) // -.1 currently
|
||||
if(HandleHealing())
|
||||
if((COOLDOWN_FINISHED(src, bloodsucker_spam_healing)) && bloodsucker_blood_volume > 0)
|
||||
to_chat(owner.current, span_notice("The power of your blood begins knitting your wounds..."))
|
||||
COOLDOWN_START(src, bloodsucker_spam_healing, BLOODSUCKER_SPAM_HEALING)
|
||||
// Standard Updates
|
||||
SEND_SIGNAL(src, COMSIG_BLOODSUCKER_ON_LIFETICK)
|
||||
INVOKE_ASYNC(src, PROC_REF(HandleStarving))
|
||||
INVOKE_ASYNC(src, PROC_REF(update_blood))
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(update_hud))
|
||||
SEND_SIGNAL(src, COMSIG_BLOODSUCKER_ON_LIFETICK)
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/on_death(mob/living/source, gibbed)
|
||||
SIGNAL_HANDLER
|
||||
@@ -39,16 +39,33 @@
|
||||
/**
|
||||
* ## BLOOD STUFF
|
||||
*/
|
||||
/datum/antagonist/bloodsucker/proc/AddBloodVolume(value)
|
||||
/datum/antagonist/bloodsucker/proc/AdjustBloodVolume(value)
|
||||
bloodsucker_blood_volume = clamp(bloodsucker_blood_volume + value, 0, max_blood_volume)
|
||||
update_blood_hud()
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/SetBloodVolume(value)
|
||||
bloodsucker_blood_volume = clamp(value, 0, max_blood_volume)
|
||||
update_blood_hud()
|
||||
|
||||
#define MASQUERADE /datum/action/cooldown/bloodsucker/masquerade
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/AddHumanityLost(value)
|
||||
// 100 humanity lost already causes you to frenzy at 25 + 100 * 10 = 1025 blood and deal 1 + 100 / 10 = 11 burn per second due to frenzy
|
||||
if(humanity_lost >= 100)
|
||||
to_chat(owner.current, span_warning("You hit the maximum amount of lost Humanty, you are far from Human."))
|
||||
if(value == 0)
|
||||
return
|
||||
humanity_lost += value
|
||||
to_chat(owner.current, span_warning("You feel as if you lost some of your humanity, you will now enter Frenzy at [FRENZY_THRESHOLD_ENTER + (humanity_lost * 10)] Blood."))
|
||||
var/has_masq = is_path_in_list(MASQUERADE, powers)
|
||||
if(value + humanity_lost >= HUMANITY_LOST_MAXIMUM)
|
||||
if(has_masq)
|
||||
RemovePowerByPath(MASQUERADE)
|
||||
to_chat(owner.current, span_warning("You hit the maximum amount of lost Humanty, you are far from Human. You've forgotten how to pretend to be like your prey..."))
|
||||
else
|
||||
to_chat(owner.current, span_hypnophrase("The Beast, it yearns for Blood..."))
|
||||
else if(!has_masq)
|
||||
BuyPower(MASQUERADE)
|
||||
to_chat(owner.current, span_hypnophrase("You've remembered, yet again, how it feels to live again."))
|
||||
humanity_lost = clamp(value, 0, HUMANITY_LOST_MAXIMUM)
|
||||
to_chat(owner.current, span_warning("You feel as if you [value < 0 ? "gained" : "lost" ] some of your humanity, you will now enter Frenzy at [FRENZY_THRESHOLD_ENTER + (humanity_lost * 10)] Blood."))
|
||||
|
||||
#undef MASQUERADE
|
||||
|
||||
/// mult: SILENT feed is 1/3 the amount
|
||||
/datum/antagonist/bloodsucker/proc/handle_feeding(mob/living/carbon/target, mult=1, power_level)
|
||||
@@ -74,7 +91,7 @@
|
||||
blood_taken /= 2
|
||||
//if (!iscarbon(target)) // Penalty for Animals (they're junk food)
|
||||
// Apply to Volume
|
||||
AddBloodVolume(blood_taken)
|
||||
AdjustBloodVolume(blood_taken)
|
||||
// Reagents (NOT Blood!)
|
||||
if(target.reagents && target.reagents.total_volume)
|
||||
target.reagents.trans_to(owner.current, INGEST, 1) // Run transfer of 1 unit of reagent from them to me.
|
||||
@@ -90,42 +107,49 @@
|
||||
/datum/antagonist/bloodsucker/proc/HandleHealing(mult = 1)
|
||||
var/actual_regen = bloodsucker_regen_rate + additional_regen
|
||||
// Don't heal if I'm staked or on Masquerade (+ not in a Coffin). Masqueraded Bloodsuckers in a Coffin however, will heal.
|
||||
if(owner.current.am_staked() || (HAS_TRAIT(owner.current, TRAIT_MASQUERADE) && !HAS_TRAIT(owner.current, TRAIT_NODEATH)))
|
||||
if(owner.current.am_staked() || (HAS_TRAIT(owner.current, TRAIT_MASQUERADE) && !HAS_TRAIT_FROM_ONLY(owner.current, TRAIT_NODEATH, BLOODSUCKER_TRAIT)))
|
||||
return FALSE
|
||||
// Garlic in you? No healing for you!
|
||||
if(HAS_TRAIT(owner.current, TRAIT_GARLIC_REAGENT))
|
||||
return FALSE
|
||||
owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * (actual_regen * 4) * mult) //adjustBrainLoss(-1 * (actual_regen * 4) * mult, 0)
|
||||
owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * actual_regen * mult) //adjustBrainLoss(-1 * (actual_regen * 4) * mult, 0)
|
||||
if(!iscarbon(owner.current)) // Damage Heal: Do I have damage to ANY bodypart?
|
||||
return FALSE
|
||||
var/mob/living/carbon/user = owner.current
|
||||
var/costMult = 1 // Coffin makes it cheaper
|
||||
var/bruteheal = min(user.getBruteLoss_nonProsthetic(), actual_regen) // BRUTE: Always Heal
|
||||
// If you're a synth, you heal prosthetic damage.
|
||||
var/bruteLoss = getBruteLoss()
|
||||
var/bruteheal = min(bruteLoss, actual_regen) // BRUTE: Always Heal
|
||||
var/fireheal = 0 // BURN: Heal in Coffin while Fakedeath, or when damage above maxhealth (you can never fully heal fire)
|
||||
// Checks if you're in a coffin here, additionally checks for Torpor right below it.
|
||||
var/amInCoffin = istype(user.loc, /obj/structure/closet/crate/coffin)
|
||||
if(amInCoffin && HAS_TRAIT(user, TRAIT_NODEATH))
|
||||
if(amInCoffin && HAS_TRAIT_FROM_ONLY(owner.current, TRAIT_NODEATH, BLOODSUCKER_TRAIT))
|
||||
if(HAS_TRAIT(owner.current, TRAIT_MASQUERADE) && (COOLDOWN_FINISHED(src, bloodsucker_spam_healing)))
|
||||
to_chat(user, span_alert("You do not heal while your Masquerade ability is active."))
|
||||
COOLDOWN_START(src, bloodsucker_spam_healing, BLOODSUCKER_SPAM_MASQUERADE)
|
||||
return FALSE
|
||||
fireheal = min(user.getFireLoss_nonProsthetic(), actual_regen)
|
||||
fireheal = min(getFireLoss(), actual_regen)
|
||||
mult *= 5 // Increase multiplier if we're sleeping in a coffin.
|
||||
costMult /= 2 // Decrease cost if we're sleeping in a coffin.
|
||||
user.extinguish_mob()
|
||||
user.bodytemperature = user.get_body_temp_normal()
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/humie = user
|
||||
humie.set_coretemperature(humie.get_body_temp_normal(apply_change = FALSE))
|
||||
user.remove_all_embedded_objects() // Remove Embedded!
|
||||
if(check_limbs(costMult))
|
||||
return TRUE
|
||||
// In Torpor, but not in a Coffin? Heal faster anyways.
|
||||
else if(HAS_TRAIT(user, TRAIT_NODEATH))
|
||||
fireheal = min(user.getFireLoss_nonProsthetic(), actual_regen) / 1.2 // 20% slower than being in a coffin
|
||||
else if(HAS_TRAIT_FROM_ONLY(owner.current, TRAIT_NODEATH, BLOODSUCKER_TRAIT))
|
||||
var/fireloss = getFireLoss()
|
||||
fireheal = min(fireloss, actual_regen) / 1.2 // 20% slower than being in a coffin
|
||||
mult *= 3
|
||||
// Heal if Damaged
|
||||
if((bruteheal + fireheal > 0) && mult != 0) // Just a check? Don't heal/spend, and return.
|
||||
if((bruteheal + fireheal) && mult != 0) // Just a check? Don't heal/spend, and return.
|
||||
// We have damage. Let's heal (one time)
|
||||
user.adjustBruteLoss(-bruteheal * mult, forced=TRUE) // Heal BRUTE / BURN in random portions throughout the body.
|
||||
user.adjustFireLoss(-fireheal * mult, forced=TRUE)
|
||||
AddBloodVolume(((bruteheal * -0.5) + (fireheal * -1)) * costMult * mult) // Costs blood to heal
|
||||
user.adjustBruteLoss(-bruteheal * mult) // Heal BRUTE / BURN in random portions throughout the body.
|
||||
user.adjustFireLoss(-fireheal * mult)
|
||||
AdjustBloodVolume(((bruteheal * -0.5) + (fireheal * -1)) * costMult * mult) // Costs blood to heal
|
||||
return TRUE
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/check_limbs(costMult = 1)
|
||||
@@ -136,9 +160,9 @@
|
||||
return FALSE
|
||||
for(var/missing_limb in missing) //Find ONE Limb and regenerate it.
|
||||
user.regenerate_limb(missing_limb, FALSE)
|
||||
AddBloodVolume(-limb_regen_cost)
|
||||
AdjustBloodVolume(-limb_regen_cost)
|
||||
var/obj/item/bodypart/missing_bodypart = user.get_bodypart(missing_limb) // 2) Limb returns Damaged
|
||||
missing_bodypart.brute_dam = 60
|
||||
missing_bodypart.brute_dam = missing_bodypart.max_damage
|
||||
to_chat(user, span_notice("Your flesh knits as it regrows your [missing_bodypart]!"))
|
||||
playsound(user, 'sound/magic/demon_consume.ogg', 50, TRUE)
|
||||
return TRUE
|
||||
@@ -153,18 +177,22 @@
|
||||
*
|
||||
* This is called on Bloodsucker's Assign, and when they end Torpor.
|
||||
*/
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/heal_vampire_organs()
|
||||
/// TODO: Separate this into smaller functions
|
||||
/datum/antagonist/bloodsucker/proc/heal_vampire_organs(regenerate_heart = FALSE)
|
||||
var/mob/living/carbon/bloodsuckeruser = owner.current
|
||||
|
||||
// please don't poison or asphyxiate the immune
|
||||
bloodsuckeruser.setToxLoss(0, forced = TRUE)
|
||||
bloodsuckeruser.setOxyLoss(0, forced = TRUE)
|
||||
if(!bloodsuckeruser)
|
||||
return
|
||||
|
||||
if(HAS_TRAIT_FROM_ONLY(bloodsuckeruser, TRAIT_HUSK, CHANGELING_DRAIN) || bloodsuckeruser.has_status_effect(/datum/status_effect/gutted))
|
||||
to_chat(bloodsuckeruser, span_danger("Your immortal blood has healed your body from near-irrecoverable damage, but has used nearly all of your blood in doing so!"))
|
||||
AddHumanityLost(2)
|
||||
SetBloodVolume(min(bloodsucker_blood_volume, frenzy_enter_threshold() * 2))
|
||||
bloodsuckeruser.cure_husk(CHANGELING_DRAIN)
|
||||
bloodsuckeruser.cure_husk(BURN)
|
||||
bloodsuckeruser.regenerate_organs(regenerate_existing = FALSE)
|
||||
|
||||
for(var/obj/item/organ/organ as anything in bloodsuckeruser.organs)
|
||||
organ.set_organ_damage(0)
|
||||
if(regenerate_heart || bloodsuckeruser.get_organ_slot(ORGAN_SLOT_HEART))
|
||||
bloodsuckeruser.regenerate_organs(regenerate_existing = FALSE)
|
||||
if(!HAS_TRAIT(bloodsuckeruser, TRAIT_MASQUERADE))
|
||||
var/obj/item/organ/internal/heart/current_heart = bloodsuckeruser.get_organ_slot(ORGAN_SLOT_HEART)
|
||||
current_heart.Stop()
|
||||
@@ -174,6 +202,10 @@
|
||||
current_eyes.color_cutoffs = BLOODSUCKER_SIGHT_COLOR_CUTOFF
|
||||
current_eyes.sight_flags = SEE_MOBS
|
||||
bloodsuckeruser.update_sight()
|
||||
/// Disable gutting for the chest
|
||||
var/obj/item/bodypart/chest/target_chest = bloodsuckeruser.get_bodypart(BODY_ZONE_CHEST)
|
||||
if(target_chest && !(target_chest.bodypart_flags & BODYPART_UNREMOVABLE))
|
||||
target_chest.bodypart_flags |= BODYPART_UNREMOVABLE
|
||||
// Sometimes bloodsuckers can get into a loop of reviving and dying, if they somehow get a new body without being revived.
|
||||
if(_listen_lookup?[COMSIG_BLOODSUCKER_ON_LIFETICK] || bloodsuckeruser._listen_lookup?[COMSIG_LIVING_REVIVE])
|
||||
on_revive()
|
||||
@@ -184,7 +216,8 @@
|
||||
// From [powers/panacea.dm]
|
||||
var/list/bad_organs = list(
|
||||
bloodsuckeruser.get_organ_by_type(/obj/item/organ/internal/body_egg),
|
||||
bloodsuckeruser.get_organ_by_type(/obj/item/organ/internal/zombie_infection))
|
||||
bloodsuckeruser.get_organ_by_type(/obj/item/organ/internal/zombie_infection)
|
||||
)
|
||||
for(var/tumors in bad_organs)
|
||||
var/obj/item/organ/yucky_organs = tumors
|
||||
if(!istype(yucky_organs))
|
||||
@@ -214,9 +247,14 @@
|
||||
FinalDeath()
|
||||
return
|
||||
// Temporary Death? Convert to Torpor.
|
||||
if(HAS_TRAIT(owner.current, TRAIT_NODEATH))
|
||||
if(HAS_TRAIT_FROM_ONLY(owner.current, TRAIT_NODEATH, BLOODSUCKER_TRAIT) || isbrain(owner.current))
|
||||
return
|
||||
check_begin_torpor(TRUE)
|
||||
// Won't torpor without vital organs, as this means they'd revive without a heart
|
||||
if(ishuman(owner.current))
|
||||
var/mob/living/carbon/human/humie = owner.current
|
||||
if(humie.dna.species.mutantheart && !owner.current.get_organ_slot(ORGAN_SLOT_HEART))
|
||||
return
|
||||
check_begin_torpor(TORPOR_SKIP_CHECK_ALL)
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/HandleStarving() // I am thirsty for blood!
|
||||
// Nutrition - The amount of blood is how full we are.
|
||||
@@ -226,11 +264,11 @@
|
||||
// handled in bloodsucker_integration.dm
|
||||
// BLOOD_VOLUME_EXIT: [250] - Exit Frenzy (If in one) This is high because we want enough to kill the poor soul they feed off of.
|
||||
var/datum/status_effect/frenzy/status_effect = owner.current.has_status_effect(/datum/status_effect/frenzy)
|
||||
if(bloodsucker_blood_volume >= frenzy_exit_threshold() && frenzied && status_effect.duration == -1)
|
||||
if(bloodsucker_blood_volume >= frenzy_exit_threshold() && frenzied && status_effect?.duration == -1)
|
||||
status_effect.duration = world.time + 10 SECONDS
|
||||
owner.current.balloon_alert(owner.current, "Frenzy ends in 10 seconds!")
|
||||
// BLOOD_VOLUME_BAD: [224] - Jitter
|
||||
if(bloodsucker_blood_volume < BLOOD_VOLUME_BAD && prob(0.5) && !HAS_TRAIT(owner.current, TRAIT_NODEATH) && !HAS_TRAIT(owner.current, TRAIT_MASQUERADE))
|
||||
if(bloodsucker_blood_volume < BLOOD_VOLUME_BAD && prob(0.5) && !HAS_TRAIT_FROM_ONLY(owner.current, TRAIT_NODEATH, BLOODSUCKER_TRAIT) && !HAS_TRAIT(owner.current, TRAIT_MASQUERADE))
|
||||
owner.current.set_timed_status_effect(3 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE)
|
||||
// BLOOD_VOLUME_SURVIVE: [122] - Blur Vision
|
||||
if(bloodsucker_blood_volume < BLOOD_VOLUME_SURVIVE)
|
||||
@@ -267,10 +305,25 @@
|
||||
|
||||
owner.current.blood_volume = bloodsucker_blood_volume
|
||||
|
||||
/// Turns the bloodsucker into a wacky talking head.
|
||||
/datum/antagonist/bloodsucker/proc/talking_head()
|
||||
var/mob/living/poor_fucker = owner.current
|
||||
// Don't do anything if we're not actually inside a brain and a head
|
||||
if(!is_head(poor_fucker) || poor_fucker.stat != DEAD || !poor_fucker.can_be_revived())
|
||||
return
|
||||
// Ensure that the HUD updates (We might have lost the heart at some point)
|
||||
RegisterSignal(poor_fucker, COMSIG_LIVING_LIFE, PROC_REF(LifeTick), TRUE)
|
||||
poor_fucker.revive()
|
||||
poor_fucker.stat = CONSCIOUS
|
||||
to_chat(poor_fucker, span_warning("Your immortal [pick(list("blood", "curse"))] keeps your head alive! Though... what will you do now?"))
|
||||
// No lungs to speak, let's make it spooky
|
||||
poor_fucker.speech_span = SPAN_PAPYRUS
|
||||
|
||||
/// Gibs the Bloodsucker, roundremoving them.
|
||||
/datum/antagonist/bloodsucker/proc/FinalDeath()
|
||||
/datum/antagonist/bloodsucker/proc/FinalDeath(check_organs = FALSE)
|
||||
SIGNAL_HANDLER
|
||||
// If we have no body, end here.
|
||||
if(!owner.current)
|
||||
if(!owner.current || isbrain(owner.current))
|
||||
return
|
||||
UnregisterSignal(src, list(
|
||||
COMSIG_BLOODSUCKER_ON_LIFETICK,
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
)
|
||||
|
||||
///Returns a Title for the Bloodsucker.
|
||||
/datum/antagonist/bloodsucker/proc/SelectTitle(am_fledgling = 0, forced = FALSE)
|
||||
/datum/antagonist/bloodsucker/proc/SelectTitle(am_fledgling = FALSE, forced = FALSE)
|
||||
// Already have Title
|
||||
if(!forced && bloodsucker_title != null)
|
||||
return
|
||||
|
||||
@@ -165,35 +165,23 @@
|
||||
|
||||
// NOTE: Look up /steal in objective.dm for inspiration.
|
||||
/// Steal hearts. You just really wanna have some hearts.
|
||||
/datum/objective/bloodsucker/heartthief
|
||||
/datum/objective/steal_n_of_type/hearts
|
||||
martyr_compatible = TRUE
|
||||
name = "heartthief"
|
||||
wanted_items = (/obj/item/organ/internal/heart)
|
||||
|
||||
// GENERATE!
|
||||
/datum/objective/bloodsucker/heartthief/New()
|
||||
target_amount = rand(2,3)
|
||||
/datum/objective/steal_n_of_type/hearts/New()
|
||||
amount = rand(2, 3)
|
||||
explanation_text = "Steal and keep [amount] organic hearts. Must be obtained from non-monkeys. Examine hearts thoroughly to see if they are valid."
|
||||
update_explanation_text()
|
||||
..()
|
||||
|
||||
// EXPLANATION
|
||||
/datum/objective/bloodsucker/heartthief/update_explanation_text()
|
||||
/datum/objective/steal_n_of_type/hearts/check_if_valid_item(obj/item/organ/internal/heart/current_item)
|
||||
. = ..()
|
||||
explanation_text = "Steal and keep [target_amount] organic heart\s."
|
||||
|
||||
// WIN CONDITIONS?
|
||||
/datum/objective/bloodsucker/heartthief/check_completion()
|
||||
if(!owner.current)
|
||||
if(current_item.type == /obj/item/organ/internal/heart/monkey || IS_ROBOTIC_ORGAN(current_item))
|
||||
return FALSE
|
||||
|
||||
var/list/all_items = owner.current.get_all_contents()
|
||||
var/heart_count = 0
|
||||
for(var/obj/item/organ/internal/heart/current_hearts in all_items)
|
||||
if(IS_ROBOTIC_ORGAN(current_hearts)) // No robo-hearts allowed
|
||||
continue
|
||||
heart_count++
|
||||
|
||||
if(heart_count >= target_amount)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///Eat blood from a lot of people
|
||||
@@ -202,7 +190,7 @@
|
||||
|
||||
// GENERATE!
|
||||
/datum/objective/bloodsucker/gourmand/New()
|
||||
target_amount = rand(450,650)
|
||||
target_amount = rand(800, 3 * BLOOD_VOLUME_NORMAL)
|
||||
..()
|
||||
|
||||
// EXPLANATION
|
||||
@@ -285,10 +273,9 @@
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.current.mind.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
if(!bloodsuckerdatum)
|
||||
return FALSE
|
||||
for(var/datum/antagonist/vassal/vassaldatum in bloodsuckerdatum.vassals)
|
||||
if(IS_FAVORITE_VASSAL(vassaldatum.owner.current))
|
||||
if(vassaldatum.owner.has_antag_datum(/datum/antagonist/bloodsucker))
|
||||
return TRUE
|
||||
for(var/datum/antagonist/bloodsucker/sired_vamp in GLOB.antagonists)
|
||||
if(sired_vamp.ventrue_sired == bloodsuckerdatum)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
if(vamp_examine)
|
||||
examine_text += vamp_examine
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/BuyPowers(powers = list())
|
||||
for(var/datum/action/cooldown/bloodsucker/power as anything in powers)
|
||||
BuyPower(power)
|
||||
|
||||
///Called when a Bloodsucker buys a power: (power)
|
||||
/datum/antagonist/bloodsucker/proc/BuyPower(datum/action/cooldown/bloodsucker/power)
|
||||
for(var/datum/action/cooldown/bloodsucker/current_powers as anything in powers)
|
||||
@@ -25,6 +29,11 @@
|
||||
powers -= power
|
||||
power.Remove(owner.current)
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/RemovePowerByPath(datum/action/cooldown/bloodsucker/power_to_remove)
|
||||
for(var/datum/action/cooldown/bloodsucker/power as anything in powers)
|
||||
if(power?.type == power_to_remove)
|
||||
RemovePower(power)
|
||||
|
||||
///When a Bloodsucker breaks the Masquerade, they get their HUD icon changed, and Malkavian Bloodsuckers get alerted.
|
||||
/datum/antagonist/bloodsucker/proc/break_masquerade(mob/admin)
|
||||
if(broke_masquerade)
|
||||
@@ -43,6 +52,8 @@
|
||||
return
|
||||
to_chat(owner.current, span_cultboldtalic("You have re-entered the Masquerade."))
|
||||
broke_masquerade = FALSE
|
||||
antag_hud_name = "bloodsucker"
|
||||
add_team_hud(owner.current)
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/give_masquerade_infraction()
|
||||
if(broke_masquerade)
|
||||
@@ -66,12 +77,6 @@
|
||||
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
|
||||
if(max_vassals() >= 1 && !(/datum/crafting_recipe/vassalrack in owner?.learned_recipes))
|
||||
owner.teach_crafting_recipe(/datum/crafting_recipe/vassalrack)
|
||||
owner.teach_crafting_recipe(/datum/crafting_recipe/candelabrum)
|
||||
owner.teach_crafting_recipe(/datum/crafting_recipe/bloodthrone)
|
||||
owner.teach_crafting_recipe(/datum/crafting_recipe/meatcoffin)
|
||||
owner.current.balloon_alert(owner.current, "new recipes learned! Vassalization unlocked!")
|
||||
SpendRank()
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/RankDown()
|
||||
@@ -94,7 +99,7 @@
|
||||
///Disables all powers, accounting for torpor
|
||||
/datum/antagonist/bloodsucker/proc/DisableAllPowers(forced = FALSE)
|
||||
for(var/datum/action/cooldown/bloodsucker/power as anything in powers)
|
||||
if(forced || ((power.check_flags & BP_CANT_USE_IN_TORPOR) && HAS_TRAIT(owner.current, TRAIT_NODEATH)))
|
||||
if(forced || ((power.check_flags & BP_CANT_USE_IN_TORPOR) && HAS_TRAIT_FROM_ONLY(owner.current, TRAIT_NODEATH, BLOODSUCKER_TRAIT)))
|
||||
if(power.active)
|
||||
power.DeactivatePower()
|
||||
|
||||
@@ -124,16 +129,16 @@
|
||||
* viewer - The person examining.
|
||||
*/
|
||||
/datum/antagonist/bloodsucker/proc/return_vamp_examine(mob/living/viewer)
|
||||
if(!viewer.mind)
|
||||
if(!viewer.mind && !isobserver(viewer))
|
||||
return FALSE
|
||||
// Viewer is Target's Vassal?
|
||||
if(viewer.mind.has_antag_datum(/datum/antagonist/vassal) in vassals)
|
||||
if(!isobserver(viewer) && (viewer.mind.has_antag_datum(/datum/antagonist/vassal) in vassals))
|
||||
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(!viewer.mind.has_antag_datum((/datum/antagonist/bloodsucker)) && !(viewer in vassals))
|
||||
if(!isobserver(viewer) && !viewer.mind.has_antag_datum((/datum/antagonist/bloodsucker)) && !(viewer in vassals))
|
||||
if(!(HAS_TRAIT(viewer.mind, TRAIT_BLOODSUCKER_HUNTER) && broke_masquerade))
|
||||
return FALSE
|
||||
// Default String
|
||||
@@ -159,3 +164,88 @@
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/frenzy_exit_threshold()
|
||||
return FRENZY_THRESHOLD_EXIT + (humanity_lost * 10)
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/add_signals_to_heart(mob/living/carbon/human/current_mob)
|
||||
if(heart?.resolve())
|
||||
remove_signals_from_heart(current_mob)
|
||||
var/organ = current_mob.get_organ_slot(ORGAN_SLOT_HEART)
|
||||
heart = WEAKREF(organ)
|
||||
RegisterSignal(organ, COMSIG_ORGAN_REMOVED, PROC_REF(on_organ_removal))
|
||||
RegisterSignal(organ, COMSIG_ORGAN_BEING_REPLACED, PROC_REF(before_organ_replace))
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/remove_signals_from_heart(mob/living/carbon/human/current_mob)
|
||||
var/organ = heart.resolve()
|
||||
if(!organ)
|
||||
return
|
||||
UnregisterSignal(organ, COMSIG_ORGAN_REMOVED)
|
||||
UnregisterSignal(organ, COMSIG_ORGAN_BEING_REPLACED)
|
||||
organ = null
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/on_organ_removal(obj/item/organ/organ, mob/living/carbon/old_owner)
|
||||
SIGNAL_HANDLER
|
||||
if(old_owner.get_organ_slot(ORGAN_SLOT_HEART) || organ.slot != ORGAN_SLOT_HEART || !old_owner.dna.species.mutantheart)
|
||||
return
|
||||
remove_signals_from_heart(old_owner)
|
||||
// You don't run bloodsucker life without a heart or brain
|
||||
RegisterSignal(old_owner, COMSIG_ENTER_COFFIN, PROC_REF(regain_heart))
|
||||
UnregisterSignal(old_owner, COMSIG_LIVING_LIFE)
|
||||
DisableAllPowers(TRUE)
|
||||
if(HAS_TRAIT_FROM_ONLY(old_owner, TRAIT_NODEATH, BLOODSUCKER_TRAIT))
|
||||
torpor_end(TRUE)
|
||||
to_chat(old_owner, span_userdanger("You have lost your [organ.slot]!"))
|
||||
to_chat(old_owner, span_warning("This means you will no longer enter torpor nor revive from death, and you will no longer heal any damage, nor can you use your abilities."))
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/on_organ_gain(mob/living/carbon/human/current_mob, obj/item/organ/replacement)
|
||||
SIGNAL_HANDLER
|
||||
if(replacement.slot != ORGAN_SLOT_HEART)
|
||||
return
|
||||
// Shit might get really fucked up. Let's try to fix things if it does
|
||||
if(current_mob != owner.current)
|
||||
UnregisterSignal(current_mob, COMSIG_CARBON_GAIN_ORGAN)
|
||||
RegisterSignal(owner.current, COMSIG_CARBON_GAIN_ORGAN)
|
||||
add_signals_to_heart(owner.current)
|
||||
RegisterSignal(owner.current, COMSIG_LIVING_LIFE, PROC_REF(LifeTick), TRUE)
|
||||
CRASH("What the fuck, somehow called on_organ_gain signal on [src] without current_mob being the antag datum's owner?")
|
||||
UnregisterSignal(current_mob, COMSIG_ENTER_COFFIN)
|
||||
RegisterSignal(current_mob, COMSIG_LIVING_LIFE, PROC_REF(LifeTick))
|
||||
add_signals_to_heart(current_mob)
|
||||
|
||||
/// This handles regen_organs replacing organs, without this the bloodsucker would die for a moment due to their heart being removed for a moment
|
||||
/datum/antagonist/bloodsucker/proc/before_organ_replace(obj/item/organ/old_organ, obj/item/organ/new_organ)
|
||||
SIGNAL_HANDLER
|
||||
if(new_organ.slot != ORGAN_SLOT_HEART)
|
||||
return
|
||||
remove_signals_from_heart(owner.current)
|
||||
|
||||
/// checks if we're a brainmob inside a brain & the brain is inside a head
|
||||
/datum/antagonist/bloodsucker/proc/is_head(mob/living/poor_fucker)
|
||||
if(!istype(poor_fucker?.loc, /obj/item/organ/internal/brain))
|
||||
return
|
||||
var/obj/brain = poor_fucker.loc
|
||||
if(!istype(brain?.loc, /obj/item/bodypart/head))
|
||||
return
|
||||
return brain.loc
|
||||
|
||||
// helper procs for damage checking, just in case a synth becomes one, let's them heal thesmelves
|
||||
/datum/antagonist/bloodsucker/proc/getBruteLoss()
|
||||
var/mob/living/carbon/human/humie = owner.current
|
||||
return issynthetic(humie) ? humie.getBruteLoss() : humie.getBruteLoss_nonProsthetic()
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/getFireLoss()
|
||||
var/mob/living/carbon/human/humie = owner.current
|
||||
return issynthetic(humie) ? humie.getFireLoss() : humie.getFireLoss_nonProsthetic()
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/admin_set_blood(mob/admin)
|
||||
var/blood = tgui_input_number(admin, "What blood level to set [owner.current]'s to?", "Blood is life.", floor(bloodsucker_blood_volume), max_blood_volume, 0)
|
||||
// 0 input is falsey
|
||||
if(blood == null)
|
||||
return
|
||||
SetBloodVolume(blood)
|
||||
update_hud()
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/regain_heart(mob/coffin_dweller, obj/structure/closet/crate/coffin/coffin, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
var/obj/item/organ/heart = locate(/obj/item/organ/internal/heart) in coffin.contents
|
||||
if(heart && !coffin_dweller.get_organ_slot(ORGAN_SLOT_HEART))
|
||||
to_chat(span_warning("You have regained your heart!"))
|
||||
heart.Insert(coffin_dweller)
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
/// Cycle through all vamp antags and check if they're inside a closet.
|
||||
/datum/antagonist/bloodsucker/proc/handle_sol()
|
||||
SIGNAL_HANDLER
|
||||
if(!owner || !owner.current)
|
||||
if(!owner || !owner.current || isbrain(owner.current))
|
||||
return
|
||||
|
||||
if(!istype(owner.current.loc, /obj/structure))
|
||||
@@ -64,10 +64,10 @@
|
||||
|
||||
if(istype(owner.current.loc, /obj/structure/closet/crate/coffin)) // Coffins offer the BEST protection
|
||||
if(owner.current.am_staked() && COOLDOWN_FINISHED(src, bloodsucker_spam_sol_burn))
|
||||
to_chat(owner.current, span_userdanger("You are staked! Remove the offending weapon from your heart before sleeping."))
|
||||
to_chat(owner.current, span_userdanger("You are staked you will keep burning until it is removed! Remove the offending weapon from your heart before sleeping."))
|
||||
COOLDOWN_START(src, bloodsucker_spam_sol_burn, BLOODSUCKER_SPAM_SOL) //This should happen twice per Sol
|
||||
if(!HAS_TRAIT(owner.current, TRAIT_NODEATH))
|
||||
check_begin_torpor(TRUE)
|
||||
if(!HAS_TRAIT_FROM_ONLY(owner.current, TRAIT_NODEATH, BLOODSUCKER_TRAIT))
|
||||
check_begin_torpor(TORPOR_SKIP_CHECK_ALL)
|
||||
owner.current.add_mood_event("vampsleep", /datum/mood_event/coffinsleep)
|
||||
return
|
||||
|
||||
@@ -112,58 +112,68 @@
|
||||
* - Having less than 10 Brute & Burn Combined while INSIDE of your Coffin while it isnt Sol.
|
||||
* - Sol being over, dealt with by /sunlight/process() [bloodsucker_daylight.dm]
|
||||
*/
|
||||
/datum/antagonist/bloodsucker/proc/check_begin_torpor(SkipChecks = FALSE)
|
||||
/datum/antagonist/bloodsucker/proc/check_begin_torpor(SkipChecks = NONE)
|
||||
var/mob/living/carbon/user = owner.current
|
||||
/// Are we entering Torpor via Sol/Death? Then entering it isnt optional!
|
||||
if(SkipChecks)
|
||||
to_chat(user, span_danger("Your immortal body will not yet relinquish your soul to the abyss. You enter Torpor."))
|
||||
torpor_begin()
|
||||
if(SkipChecks & TORPOR_SKIP_CHECK_ALL)
|
||||
if(COOLDOWN_FINISHED(src, bloodsucker_spam_torpor))
|
||||
to_chat(user, span_danger("Your immortal body will not yet relinquish your soul to the abyss. You enter Torpor."))
|
||||
torpor_begin(TRUE)
|
||||
return
|
||||
/// Prevent Torpor whilst frenzied.
|
||||
if(frenzied || (IS_DEAD_OR_INCAP(user) && bloodsucker_blood_volume == 0))
|
||||
if(!(SkipChecks & TORPOR_SKIP_CHECK_FRENZY) && (frenzied || (IS_DEAD_OR_INCAP(user) && bloodsucker_blood_volume == 0)))
|
||||
to_chat(user, span_userdanger("Your frenzy prevents you from entering torpor!"))
|
||||
return
|
||||
var/total_brute = user.getBruteLoss_nonProsthetic()
|
||||
var/total_burn = user.getFireLoss_nonProsthetic()
|
||||
var/total_damage = total_brute + total_burn
|
||||
// sometimes you might incur these damage types when you really, should not, important to check for it here so we can heal it later
|
||||
var/total_damage = getBruteLoss() + getFireLoss() + user.getToxLoss() + user.getOxyLoss()
|
||||
/// Checks - Not daylight & Has more than 10 Brute/Burn & not already in Torpor
|
||||
if(!SSsunlight.sunlight_active && total_damage >= 10 && !HAS_TRAIT(owner.current, TRAIT_NODEATH))
|
||||
if(SkipChecks & TORPOR_SKIP_CHECK_DAMAGE || !SSsunlight.sunlight_active && total_damage >= 10 && !HAS_TRAIT_FROM_ONLY(owner.current, TRAIT_NODEATH, BLOODSUCKER_TRAIT))
|
||||
torpor_begin()
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/check_end_torpor()
|
||||
var/mob/living/carbon/user = owner.current
|
||||
var/total_brute = user.getBruteLoss_nonProsthetic()
|
||||
var/total_burn = user.getFireLoss_nonProsthetic()
|
||||
var/total_brute = getBruteLoss()
|
||||
var/total_burn = getFireLoss()
|
||||
// for waking up we ignore all other damage types so we don't get stuck
|
||||
var/total_damage = total_brute + total_burn
|
||||
if(bloodsucker_blood_volume == 0 || owner.current.am_staked() || HAS_TRAIT(owner.current, TRAIT_GARLIC_REAGENT))
|
||||
torpor_end()
|
||||
if(total_burn >= user.maxHealth * 2)
|
||||
return FALSE
|
||||
if(SSsunlight.sunlight_active)
|
||||
return FALSE
|
||||
if(bloodsucker_blood_volume == 0 || owner.current.am_staked() || HAS_TRAIT(owner.current, TRAIT_GARLIC_REAGENT))
|
||||
// If you're frenzying, you need a bit more health to actually have a chance to do something
|
||||
if(frenzied && total_damage >= user.maxHealth)
|
||||
return FALSE
|
||||
torpor_end()
|
||||
// You are in a Coffin, so instead we'll check TOTAL damage, here.
|
||||
if(istype(user.loc, /obj/structure/closet/crate/coffin))
|
||||
if(total_damage <= 10)
|
||||
torpor_end()
|
||||
else
|
||||
if(total_brute <= 10)
|
||||
if(total_damage <= 10)
|
||||
torpor_end()
|
||||
return TRUE
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/torpor_begin()
|
||||
to_chat(owner.current, span_notice("You enter the horrible slumber of deathless Torpor. You will heal until you are renewed."))
|
||||
/datum/antagonist/bloodsucker/proc/torpor_begin(silent = FALSE)
|
||||
// slow down bucko
|
||||
if(!COOLDOWN_FINISHED(src, bloodsucker_spam_torpor))
|
||||
return
|
||||
if(!silent)
|
||||
to_chat(owner.current, span_notice("You enter the horrible slumber of deathless Torpor. You will heal until you are renewed."))
|
||||
// Force them to go to sleep
|
||||
REMOVE_TRAIT(owner.current, TRAIT_SLEEPIMMUNE, BLOODSUCKER_TRAIT)
|
||||
// Without this, you'll just keep dying while you recover.
|
||||
owner.current.add_traits(list(TRAIT_NODEATH, TRAIT_FAKEDEATH, TRAIT_DEATHCOMA, TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTHIGHPRESSURE), BLOODSUCKER_TRAIT)
|
||||
owner.current.set_timed_status_effect(0 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE)
|
||||
owner.current.do_jitter_animation(2)
|
||||
// Disable ALL Powers
|
||||
DisableAllPowers()
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/torpor_end()
|
||||
owner.current.grab_ghost()
|
||||
to_chat(owner.current, span_warning("You have recovered from Torpor."))
|
||||
/datum/antagonist/bloodsucker/proc/torpor_end(quiet = FALSE)
|
||||
if(quiet)
|
||||
owner.current.grab_ghost()
|
||||
to_chat(owner.current, span_warning("You have recovered from Torpor."))
|
||||
owner.current.remove_traits(list(TRAIT_NODEATH, TRAIT_FAKEDEATH, TRAIT_DEATHCOMA, TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTHIGHPRESSURE), BLOODSUCKER_TRAIT)
|
||||
if(!HAS_TRAIT(owner.current, TRAIT_MASQUERADE))
|
||||
if(!HAS_TRAIT_FROM_ONLY(owner.current, TRAIT_MASQUERADE, BLOODSUCKER_TRAIT))
|
||||
ADD_TRAIT(owner.current, TRAIT_SLEEPIMMUNE, BLOODSUCKER_TRAIT)
|
||||
heal_vampire_organs()
|
||||
SEND_SIGNAL(src, BLOODSUCKER_EXIT_TORPOR)
|
||||
|
||||
@@ -38,7 +38,8 @@
|
||||
RegisterSignal(bloodsuckerdatum, BLOODSUCKER_RANK_UP, PROC_REF(on_spend_rank))
|
||||
|
||||
RegisterSignal(bloodsuckerdatum, BLOODSUCKER_INTERACT_WITH_VASSAL, PROC_REF(on_interact_with_vassal))
|
||||
RegisterSignal(bloodsuckerdatum, BLOODSUCKER_MAKE_FAVORITE, PROC_REF(on_favorite_vassal))
|
||||
RegisterSignal(bloodsuckerdatum, BLOODSUCKER_MAKE_FAVORITE, PROC_REF(favorite_vassal_gain))
|
||||
RegisterSignal(bloodsuckerdatum, BLOODSUCKER_LOOSE_FAVORITE, PROC_REF(favorite_vassal_loss))
|
||||
|
||||
RegisterSignal(bloodsuckerdatum, BLOODSUCKER_MADE_VASSAL, PROC_REF(on_vassal_made))
|
||||
RegisterSignal(bloodsuckerdatum, BLOODSUCKER_EXIT_TORPOR, PROC_REF(on_exit_torpor))
|
||||
@@ -205,7 +206,7 @@
|
||||
if(cost_rank)
|
||||
bloodsuckerdatum.bloodsucker_level_unspent--
|
||||
if(blood_cost)
|
||||
bloodsuckerdatum.AddBloodVolume(-blood_cost)
|
||||
bloodsuckerdatum.AdjustBloodVolume(-blood_cost)
|
||||
|
||||
// Ranked up enough to get your true Reputation?
|
||||
if(bloodsuckerdatum.bloodsucker_level == BLOODSUCKER_HIGH_LEVEL)
|
||||
@@ -214,10 +215,19 @@
|
||||
|
||||
|
||||
to_chat(bloodsuckerdatum.owner.current, span_notice("You are now a rank [bloodsuckerdatum.bloodsucker_level] Bloodsucker. \
|
||||
Your strength, health, feed rate, regen rate, and maximum blood capacity have all increased! \n\
|
||||
Your strength, feed rate, regen rate, and maximum blood capacity have all increased! \n\
|
||||
* Your existing powers have all ranked up as well!"))
|
||||
bloodsuckerdatum.owner.current.playsound_local(null, 'sound/effects/pope_entry.ogg', 25, TRUE, pressure_affected = FALSE)
|
||||
bloodsuckerdatum.update_hud()
|
||||
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)
|
||||
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!")
|
||||
|
||||
/**
|
||||
* Called when we are trying to turn someone into a Favorite Vassal
|
||||
@@ -258,7 +268,7 @@
|
||||
bloodsuckerdatum.owner.current.balloon_alert(bloodsuckerdatum.owner.current, "Out of Special Vassal slots!")
|
||||
return
|
||||
|
||||
to_chat(bloodsuckerdatum.owner.current, span_notice("You can change who this Vassal is, who are they to you?"))
|
||||
to_chat(bloodsuckerdatum.owner.current, 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(bloodsuckerdatum.owner.current, vassaldatum.owner.current, radial_display)
|
||||
if(!vassal_response)
|
||||
return
|
||||
@@ -266,7 +276,7 @@
|
||||
if(QDELETED(src) || QDELETED(bloodsuckerdatum.owner.current) || QDELETED(vassaldatum.owner.current))
|
||||
return FALSE
|
||||
vassaldatum.make_special(vassal_response)
|
||||
bloodsuckerdatum.bloodsucker_blood_volume -= 150
|
||||
bloodsuckerdatum.AdjustBloodVolume(-SPECIAL_VASSAL_COST)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
@@ -275,6 +285,9 @@
|
||||
* bloodsuckerdatum - antagonist datum of the Bloodsucker who turned them into a Vassal.
|
||||
* vassaldatum - the antagonist datum of the Vassal being offered up.
|
||||
*/
|
||||
/datum/bloodsucker_clan/proc/on_favorite_vassal(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
|
||||
/datum/bloodsucker_clan/proc/favorite_vassal_gain(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
|
||||
SIGNAL_HANDLER
|
||||
vassaldatum.BuyPower(/datum/action/cooldown/bloodsucker/targeted/brawn)
|
||||
|
||||
/datum/bloodsucker_clan/proc/favorite_vassal_loss(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
var/message = pick(strings("malkavian_revelations.json", "revelations", "modular_zubbers/strings/bloodsuckers"))
|
||||
INVOKE_ASYNC(bloodsuckerdatum.owner.current, TYPE_PROC_REF(/atom/movable, say), message, forced = CLAN_MALKAVIAN)
|
||||
|
||||
/datum/bloodsucker_clan/malkavian/on_favorite_vassal(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
|
||||
/datum/bloodsucker_clan/malkavian/favorite_vassal_gain(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
|
||||
var/mob/living/carbon/carbonowner = vassaldatum.owner.current
|
||||
if(istype(carbonowner))
|
||||
carbonowner.gain_trauma(/datum/brain_trauma/mild/hallucinations, TRAUMA_RESILIENCE_ABSOLUTE)
|
||||
@@ -61,8 +61,18 @@
|
||||
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."))
|
||||
|
||||
/datum/bloodsucker_clan/malkavian/favorite_vassal_loss(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
|
||||
var/mob/living/carbon/carbonowner = vassaldatum.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))
|
||||
return
|
||||
var/datum/martial_art/psychotic_brawling/psychotic_brawling = vassaldatum.owner.martial_art
|
||||
psychotic_brawling.remove(vassaldatum.owner.current)
|
||||
|
||||
/datum/bloodsucker_clan/malkavian/on_exit_torpor(datum/antagonist/bloodsucker/source)
|
||||
var/mob/living/carbon/carbonowner = bloodsuckerdatum.owner.current
|
||||
var/mob/living/carbon/carbonowner = bloodsuckerdatum.owner.martial_art
|
||||
if(istype(carbonowner))
|
||||
carbonowner.gain_trauma(/datum/brain_trauma/mild/hallucinations, TRAUMA_RESILIENCE_ABSOLUTE)
|
||||
carbonowner.gain_trauma(/datum/brain_trauma/special/bluespace_prophet, TRAUMA_RESILIENCE_ABSOLUTE)
|
||||
|
||||
@@ -33,6 +33,12 @@
|
||||
if(!HAS_TRAIT(bloodsuckerdatum.owner.current, TRAIT_NOBLOOD))
|
||||
bloodsuckerdatum.owner.current.blood_volume = BLOOD_VOLUME_SURVIVE
|
||||
|
||||
/datum/bloodsucker_clan/nosferatu/on_favorite_vassal(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
|
||||
vassaldatum.owner.current.add_traits(list(TRAIT_VENTCRAWLER_NUDE, TRAIT_DISFIGURED, TRAIT_TRUE_NIGHT_VISION, TRAIT_KNOW_ENGI_WIRES, TRAIT_SILENT_FOOTSTEPS), BLOODSUCKER_TRAIT)
|
||||
/datum/bloodsucker_clan/nosferatu/favorite_vassal_gain(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
|
||||
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."))
|
||||
|
||||
/datum/bloodsucker_clan/nosferatu/favorite_vassal_loss(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
|
||||
vassaldatum.owner.current.update_sight()
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
to_chat(bloodsuckerdatum.owner.current, span_notice("You grow more ancient by the night!"))
|
||||
else
|
||||
// Give them the UI to purchase a power.
|
||||
var/choice = tgui_input_list(bloodsuckerdatum.owner.current, "You have the opportunity to grow more ancient. Select a power you wish to upgrade.", "Your Blood Thickens...", options)
|
||||
var/choice = tgui_input_list(bloodsuckerdatum.owner.current, "You have the opportunity to grow more ancient. Spend [round(blood_cost, 1)] blood to upgrade a power.", "Your Blood Thickens...", options)
|
||||
// Prevent Bloodsuckers from closing/reopning their coffin to spam Levels.
|
||||
if(cost_rank && bloodsuckerdatum.bloodsucker_level_unspent <= 0)
|
||||
return
|
||||
@@ -72,10 +72,14 @@
|
||||
|
||||
finalize_spend_rank(bloodsuckerdatum, cost_rank, blood_cost)
|
||||
|
||||
/datum/bloodsucker_clan/tremere/on_favorite_vassal(datum/antagonist/bloodsucker/source, datum/antagonist/vassal/vassaldatum)
|
||||
/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_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/on_vassal_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!"))
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
///The maximum level a Ventrue Bloodsucker can be, before they have to level up their vassal instead.
|
||||
#define VENTRUE_MAX_LEVEL 3
|
||||
#define VENTRUE_MAX_POWERS 3
|
||||
///How much it costs for a Ventrue to rank up without a spare rank to spend.
|
||||
#define BLOODSUCKER_BLOOD_RANKUP_COST (550)
|
||||
|
||||
/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 only level yourself up to Level %MAX_LEVEL%, anything further will be ranks to spend on their Favorite Vassal through a Persuasion Rack. \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."
|
||||
clan_objective = /datum/objective/bloodsucker/embrace
|
||||
@@ -17,19 +17,31 @@
|
||||
|
||||
/datum/bloodsucker_clan/ventrue/New(datum/antagonist/bloodsucker/owner_datum)
|
||||
. = ..()
|
||||
description = replacetext(description, "%MAX_LEVEL%", VENTRUE_MAX_LEVEL)
|
||||
description = replacetext(description, "%MAX_POWERS%", VENTRUE_MAX_POWERS)
|
||||
|
||||
/datum/bloodsucker_clan/ventrue/proc/has_enough_abilities()
|
||||
var/power_count = 0
|
||||
for(var/datum/action/cooldown/bloodsucker/power in bloodsuckerdatum.powers)
|
||||
if(!(power.purchase_flags & BLOODSUCKER_DEFAULT_POWER))
|
||||
power_count++
|
||||
if(power_count >= VENTRUE_MAX_POWERS)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/bloodsucker_clan/ventrue/spend_rank(datum/antagonist/bloodsucker/source, mob/living/carbon/target, cost_rank = TRUE, blood_cost)
|
||||
if(bloodsuckerdatum.bloodsucker_level < VENTRUE_MAX_LEVEL)
|
||||
if(!target && !has_enough_abilities())
|
||||
return ..()
|
||||
else if(!target)
|
||||
to_chat(bloodsuckerdatum.owner.current, span_danger("You can only level up to Level [VENTRUE_MAX_LEVEL], anything further will 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 will be ranks to spend on your Favorite Vassal through a Persuasion Rack."))
|
||||
return FALSE
|
||||
var/datum/antagonist/vassal/favorite/vassaldatum = target.mind.has_antag_datum(/datum/antagonist/vassal/favorite)
|
||||
var/datum/antagonist/vassal/non_favorite = target.mind.has_antag_datum(/datum/antagonist/vassal)
|
||||
if(!vassaldatum && vassaldatum.master != bloodsuckerdatum.owner.current || !IS_BLOODSUCKER(target) && !non_favorite && vassaldatum.master != bloodsuckerdatum.owner.current)
|
||||
target.balloon_alert(target, "is not a sired bloodsucker nor your favorite vassal!")
|
||||
return FALSE
|
||||
if(!vassaldatum.owner.current.mind)
|
||||
target.balloon_alert(target, "vassal must be awake!")
|
||||
return FALSE
|
||||
// Purchase Power Prompt
|
||||
var/list/options = list()
|
||||
for(var/datum/action/cooldown/bloodsucker/power as anything in bloodsuckerdatum.all_bloodsucker_powers)
|
||||
@@ -67,18 +79,19 @@
|
||||
return
|
||||
vassaldatum.vassal_level++
|
||||
finish_spend_rank(vassaldatum, cost_rank, blood_cost)
|
||||
var/traits_to_add = list()
|
||||
switch(vassaldatum.vassal_level)
|
||||
if(1)
|
||||
target.add_traits(list(TRAIT_COLDBLOODED, TRAIT_NOBREATH, TRAIT_AGEUSIA), BLOODSUCKER_TRAIT)
|
||||
traits_to_add = list(TRAIT_COLDBLOODED, TRAIT_NOBREATH, TRAIT_AGEUSIA)
|
||||
to_chat(target, span_notice("Your blood begins to feel cold, and as a mote of ash lands upon your tongue, you stop breathing..."))
|
||||
if(2)
|
||||
target.add_traits(list(TRAIT_NOCRITDAMAGE, TRAIT_NOSOFTCRIT, TRAIT_SLEEPIMMUNE, TRAIT_VIRUSIMMUNE), BLOODSUCKER_TRAIT)
|
||||
traits_to_add = list(TRAIT_NOCRITDAMAGE, TRAIT_NOSOFTCRIT, TRAIT_SLEEPIMMUNE, TRAIT_VIRUSIMMUNE)
|
||||
to_chat(target, span_notice("You feel your Master's blood reinforce you, strengthening you up."))
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/human_target = target
|
||||
human_target.skin_tone = "albino"
|
||||
if(3)
|
||||
target.add_traits(list(TRAIT_NOHARDCRIT, TRAIT_HARDLY_WOUNDED), BLOODSUCKER_TRAIT)
|
||||
traits_to_add = list(TRAIT_NOHARDCRIT, TRAIT_HARDLY_WOUNDED)
|
||||
to_chat(target, span_notice("You feel yourself able to take cuts and stabbings like it's nothing."))
|
||||
if(4 to INFINITY)
|
||||
var/datum/antagonist/bloodsucker/bloodsucker_target = target.mind.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
@@ -89,18 +102,18 @@
|
||||
var/powers_to_transfer = list()
|
||||
// Get rid of the favorite datum and replace with a normal vassal datum
|
||||
if(target.mind.has_antag_datum(/datum/antagonist/vassal/favorite))
|
||||
var/datum/antagonist/vassal/new_antag_datum = new(target.mind)
|
||||
powers_to_transfer = vassaldatum.bloodsucker_powers.Copy()
|
||||
vassaldatum.bloodsucker_powers.Cut(powers_to_transfer)
|
||||
for(var/datum/power as anything in vassaldatum.bloodsucker_powers)
|
||||
powers_to_transfer += power.type
|
||||
target.mind.remove_antag_datum(/datum/antagonist/vassal/favorite)
|
||||
new_antag_datum.master = vassaldatum.master
|
||||
new_antag_datum.silent = TRUE
|
||||
target.mind.add_antag_datum(new_antag_datum)
|
||||
new_antag_datum.remove_powers(new_antag_datum.powers)
|
||||
bloodsucker_target = target.mind.add_antag_datum(/datum/antagonist/bloodsucker)
|
||||
bloodsucker_target?.powers += powers_to_transfer
|
||||
var/datum/antagonist/bloodsucker/vamp = new()
|
||||
vamp.ventrue_sired = bloodsuckerdatum
|
||||
bloodsucker_target = target.mind.add_antag_datum(vamp)
|
||||
bloodsucker_target.BuyPowers(powers_to_transfer)
|
||||
// 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/proc/finish_spend_rank(datum/antagonist/vassal/vassaldatum, cost_rank, blood_cost)
|
||||
finalize_spend_rank(bloodsuckerdatum, cost_rank, blood_cost)
|
||||
@@ -112,9 +125,6 @@
|
||||
return TRUE
|
||||
if(!istype(vassaldatum))
|
||||
return FALSE
|
||||
if(bloodsuckerdatum.bloodsucker_level < VENTRUE_MAX_LEVEL)
|
||||
to_chat(bloodsuckerdatum.owner.current, span_danger("You are too low level to Rank up [vassaldatum.owner.current] You must at least be level [VENTRUE_MAX_LEVEL]."))
|
||||
return FALSE
|
||||
if(!bloodsuckerdatum.bloodsucker_level_unspent <= 0)
|
||||
bloodsuckerdatum.SpendRank(vassaldatum.owner.current)
|
||||
return TRUE
|
||||
@@ -132,9 +142,9 @@
|
||||
to_chat(bloodsuckerdatum.owner.current, span_danger("You don't have any levels or enough Blood to Rank [vassaldatum.owner.current] up with."))
|
||||
return TRUE
|
||||
|
||||
/datum/bloodsucker_clan/ventrue/on_favorite_vassal(datum/source, datum/antagonist/vassal/vassaldatum, mob/living/bloodsucker)
|
||||
to_chat(bloodsucker, span_announce("* Bloodsucker Tip: You can now upgrade your Favorite Vassal by buckling them onto a persuasion rack!"))
|
||||
/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)
|
||||
|
||||
#undef BLOODSUCKER_BLOOD_RANKUP_COST
|
||||
#undef VENTRUE_MAX_LEVEL
|
||||
#undef VENTRUE_MAX_POWERS
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
base_background_icon_state = "vamp_power_off"
|
||||
|
||||
/// The text that appears when using the help verb, meant to explain how the Power changes when ranking up.
|
||||
var/power_explanation = ""
|
||||
///The owner's stored Bloodsucker datum
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum_power
|
||||
|
||||
@@ -25,14 +24,14 @@
|
||||
/// The effects on this Power (Toggled/Single Use/Static Cooldown)
|
||||
var/power_flags = BP_AM_TOGGLE|BP_AM_SINGLEUSE|BP_AM_STATIC_COOLDOWN|BP_AM_COSTLESS_UNCONSCIOUS
|
||||
/// Requirement flags for checks
|
||||
check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_CANT_USE_WHILE_STAKED|BP_CANT_USE_WHILE_INCAPACITATED|BP_CANT_USE_WHILE_UNCONSCIOUS
|
||||
check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_CANT_USE_WHILE_INCAPACITATED|BP_CANT_USE_WHILE_UNCONSCIOUS
|
||||
/// Who can purchase the Power
|
||||
var/purchase_flags = NONE // BLOODSUCKER_CAN_BUY|BLOODSUCKER_DEFAULT_POWER|TREMERE_CAN_BUY|VASSAL_CAN_BUY
|
||||
|
||||
// VARS //
|
||||
/// If the Power is currently active, differs from action cooldown because of how powers are handled.
|
||||
var/active = FALSE
|
||||
///Can increase to yield new abilities - Each Power ranks up each Rank
|
||||
///Can increase to yield new capabilities - Each Power ranks up each Rank, with the oldest power being the highest rank.
|
||||
var/level_current = 0
|
||||
///The cost to ACTIVATE this Power
|
||||
var/bloodcost = 0
|
||||
@@ -102,6 +101,13 @@
|
||||
///Called when the Power is upgraded.
|
||||
/datum/action/cooldown/bloodsucker/proc/upgrade_power()
|
||||
level_current++
|
||||
build_all_button_icons(UPDATE_BUTTON_NAME)
|
||||
|
||||
// Put desc that you want to update every time build_all_button_icons is called here
|
||||
/datum/action/cooldown/bloodsucker/update_button_name(atom/movable/screen/movable/action_button/button, force)
|
||||
. = ..()
|
||||
if((purchase_flags & BLOODSUCKER_CAN_BUY) || (purchase_flags & TREMERE_CAN_BUY))
|
||||
button.desc += "<br><br><b>LEVEL:</b> [level_current]"
|
||||
|
||||
///Checks if the Power is available to use.
|
||||
/datum/action/cooldown/bloodsucker/proc/can_use(mob/living/carbon/user, trigger_flags)
|
||||
@@ -109,6 +115,12 @@
|
||||
return FALSE
|
||||
if(!isliving(user))
|
||||
return FALSE
|
||||
if(bloodsuckerdatum_power && !bloodsuckerdatum_power.heart?.resolve())
|
||||
to_chat(user, span_warning("To channel your powers you need a heart!"))
|
||||
return FALSE
|
||||
if(isbrain(user))
|
||||
to_chat(user, span_warning("What are you going to do, jump on someone and suck their blood? You're just a head."))
|
||||
return FALSE
|
||||
// Torpor?
|
||||
if((check_flags & BP_CANT_USE_IN_TORPOR) && HAS_TRAIT(user, TRAIT_NODEATH))
|
||||
to_chat(user, span_warning("Not while you're in Torpor."))
|
||||
@@ -121,11 +133,11 @@
|
||||
to_chat(user, span_warning("You cannot use powers while in a Frenzy!"))
|
||||
return FALSE
|
||||
// Stake?
|
||||
if((check_flags & BP_CANT_USE_WHILE_STAKED) && user.am_staked())
|
||||
if(!(check_flags & BP_CAN_USE_WHILE_STAKED) && user.am_staked())
|
||||
to_chat(user, span_warning("You have a stake in your chest! Your powers are useless."))
|
||||
return FALSE
|
||||
// Conscious? -- We use our own (AB_CHECK_CONSCIOUS) here so we can control it more, like the error message.
|
||||
if((check_flags & BP_CANT_USE_WHILE_UNCONSCIOUS) && user.stat != CONSCIOUS)
|
||||
if((check_flags & BP_CANT_USE_WHILE_UNCONSCIOUS) && user.stat >= UNCONSCIOUS)
|
||||
to_chat(user, span_warning("You can't do this while you are unconcious!"))
|
||||
return FALSE
|
||||
// Incapacitated?
|
||||
@@ -133,13 +145,16 @@
|
||||
to_chat(user, span_warning("Not while you're incapacitated!"))
|
||||
return FALSE
|
||||
// Constant Cost (out of blood)
|
||||
if(constant_bloodcost > 0 && bloodsuckerdatum_power?.bloodsucker_blood_volume <= 0)
|
||||
if(constant_bloodcost > 0 && !can_pay_blood(user))
|
||||
to_chat(user, span_warning("You don't have the blood to upkeep [src]."))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// NOTE: With this formula, you'll hit half cooldown at level 8 for that power.
|
||||
/datum/action/cooldown/bloodsucker/StartCooldown()
|
||||
/datum/action/cooldown/bloodsucker/StartCooldown(override_cooldown_time, override_melee_cooldown_time)
|
||||
// don't re-set the cooldown if we don't have a override time and there's already a cooldown ongoing
|
||||
if(!override_cooldown_time && next_use_time > world.time)
|
||||
return
|
||||
// Calculate Cooldown (by power's level)
|
||||
if(power_flags & BP_AM_STATIC_COOLDOWN)
|
||||
cooldown_time = initial(cooldown_time)
|
||||
@@ -148,6 +163,9 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/action/cooldown/bloodsucker/proc/can_pay_blood(mob/living/carbon/user)
|
||||
return bloodsuckerdatum_power ? bloodsuckerdatum_power?.bloodsucker_blood_volume >= 0 : user.blood_volume >= 0
|
||||
|
||||
/datum/action/cooldown/bloodsucker/proc/can_deactivate()
|
||||
return TRUE
|
||||
|
||||
@@ -164,8 +182,7 @@
|
||||
// Bloodsuckers in a Frenzy don't have enough Blood to pay it, so just don't.
|
||||
if(bloodsuckerdatum_power.frenzied)
|
||||
return
|
||||
bloodsuckerdatum_power.bloodsucker_blood_volume -= bloodcost
|
||||
bloodsuckerdatum_power.update_hud()
|
||||
bloodsuckerdatum_power.AdjustBloodVolume(-bloodcost)
|
||||
|
||||
/datum/action/cooldown/bloodsucker/proc/ActivatePower(trigger_flags)
|
||||
active = TRUE
|
||||
@@ -200,7 +217,7 @@
|
||||
if(power_flags & BP_AM_COSTLESS_UNCONSCIOUS && owner.stat != CONSCIOUS)
|
||||
return TRUE
|
||||
if(bloodsuckerdatum_power)
|
||||
bloodsuckerdatum_power.AddBloodVolume(-constant_bloodcost * seconds_per_tick)
|
||||
bloodsuckerdatum_power.AdjustBloodVolume(-constant_bloodcost * seconds_per_tick)
|
||||
else
|
||||
var/mob/living/living_owner = owner
|
||||
if(!HAS_TRAIT(living_owner, TRAIT_NOBLOOD))
|
||||
@@ -211,7 +228,7 @@
|
||||
/datum/action/cooldown/bloodsucker/proc/ContinueActive(mob/living/user, mob/living/target)
|
||||
if(!user)
|
||||
return FALSE
|
||||
if(!constant_bloodcost > 0 || bloodsuckerdatum_power.bloodsucker_blood_volume > 0)
|
||||
if(!constant_bloodcost > 0 || can_pay_blood(user))
|
||||
return TRUE
|
||||
|
||||
/// Used to unlearn Single-Use Powers
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
If you are in desperate need of blood, mice can be fed off of, at a cost.\n\
|
||||
You must use the ability again to stop sucking blood."
|
||||
power_flags = BP_AM_TOGGLE|BP_AM_STATIC_COOLDOWN
|
||||
check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_WHILE_STAKED|BP_CANT_USE_WHILE_INCAPACITATED|BP_CANT_USE_WHILE_UNCONSCIOUS
|
||||
purchase_flags = BLOODSUCKER_CAN_BUY|BLOODSUCKER_DEFAULT_POWER
|
||||
check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_WHILE_INCAPACITATED|BP_CANT_USE_WHILE_UNCONSCIOUS|BP_CAN_USE_WHILE_STAKED
|
||||
purchase_flags = BLOODSUCKER_DEFAULT_POWER
|
||||
bloodcost = 0
|
||||
cooldown_time = 15 SECONDS
|
||||
|
||||
@@ -69,8 +69,8 @@
|
||||
bloodsuckerdatum_power.AddHumanityLost(5)
|
||||
|
||||
target_ref = null
|
||||
warning_target_bloodvol = BLOOD_VOLUME_MAX_LETHAL
|
||||
blood_taken = 0
|
||||
warning_target_bloodvol = initial(warning_target_bloodvol)
|
||||
blood_taken = initial(blood_taken)
|
||||
REMOVE_TRAIT(user, TRAIT_IMMOBILIZED, FEED_TRAIT)
|
||||
REMOVE_TRAIT(user, TRAIT_MUTE, FEED_TRAIT)
|
||||
return ..()
|
||||
@@ -84,7 +84,7 @@
|
||||
var/mob/living/user = owner
|
||||
user.add_mood_event("drankblood", /datum/mood_event/drankblood_bad)
|
||||
bloodsuckerdatum_power.AddHumanityLost(1)
|
||||
bloodsuckerdatum_power.AddBloodVolume(25)
|
||||
bloodsuckerdatum_power.AdjustBloodVolume(25)
|
||||
DeactivatePower()
|
||||
feed_target.death()
|
||||
return
|
||||
@@ -111,7 +111,7 @@
|
||||
// Only people who AREN'T the target will notice this action.
|
||||
var/dead_message = feed_target.stat != DEAD ? " <i>[feed_target.p_they(TRUE)] looks dazed, and will not remember this.</i>" : ""
|
||||
owner.visible_message(
|
||||
span_notice("[owner] puts [feed_target]'s wrist up to [owner.p_their()] mouth."), \
|
||||
span_warning("[owner] puts [feed_target]'s wrist up to [owner.p_their()] mouth."), \
|
||||
span_notice("You slip your fangs into [feed_target]'s wrist.[dead_message]"), \
|
||||
vision_distance = FEED_NOTICE_RANGE, ignored_mobs = feed_target)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
button_icon_state = "power_fortitude"
|
||||
power_explanation = "Fortitude:\n\
|
||||
Activating Fortitude will provide pierce, stun and dismember immunity.\n\
|
||||
You will additionally gain resistance to Brute and Stamina damge, scaling with level.\n\
|
||||
You will additionally gain resistance to both physical and stamina damage, scaling with level.\n\
|
||||
While using Fortitude, attempting to run will crush you.\n\
|
||||
At level 4, you gain complete stun immunity.\n\
|
||||
Higher levels will increase Brute and Stamina resistance."
|
||||
@@ -29,6 +29,7 @@
|
||||
if(IS_BLOODSUCKER(owner) || IS_VASSAL(owner))
|
||||
fortitude_resist = max(0.3, 0.7 - level_current * 0.1)
|
||||
bloodsucker_user.physiology.brute_mod *= fortitude_resist
|
||||
bloodsucker_user.physiology.burn_mod *= fortitude_resist + 0.2
|
||||
bloodsucker_user.physiology.stamina_mod *= fortitude_resist
|
||||
|
||||
was_running = (bloodsucker_user.move_intent == MOVE_INTENT_RUN)
|
||||
@@ -58,8 +59,8 @@
|
||||
var/mob/living/carbon/human/bloodsucker_user = owner
|
||||
if(IS_BLOODSUCKER(owner) || IS_VASSAL(owner))
|
||||
bloodsucker_user.physiology.brute_mod /= fortitude_resist
|
||||
if(!HAS_TRAIT_FROM(bloodsucker_user, TRAIT_STUNIMMUNE, BLOODSUCKER_TRAIT))
|
||||
bloodsucker_user.physiology.stamina_mod /= fortitude_resist
|
||||
bloodsucker_user.physiology.burn_mod /= fortitude_resist + 0.2
|
||||
bloodsucker_user.physiology.stamina_mod /= fortitude_resist
|
||||
// Remove Traits & Effects
|
||||
owner.remove_traits(list(TRAIT_PIERCEIMMUNE, TRAIT_NODISMEMBER, TRAIT_PUSHIMMUNE, TRAIT_STUNIMMUNE), BLOODSUCKER_TRAIT)
|
||||
|
||||
|
||||
@@ -20,11 +20,12 @@
|
||||
Immediately after activating, lights around the user will begin to flicker. \n\
|
||||
Once the user teleports to their coffin, in their place will be a Rat or Bat."
|
||||
power_flags = BP_AM_TOGGLE|BP_AM_SINGLEUSE|BP_AM_STATIC_COOLDOWN
|
||||
check_flags = BP_CANT_USE_IN_FRENZY|BP_CANT_USE_WHILE_STAKED
|
||||
check_flags = BP_CANT_USE_IN_FRENZY
|
||||
purchase_flags = NONE
|
||||
bloodcost = 100
|
||||
constant_bloodcost = 2
|
||||
cooldown_time = 100 SECONDS
|
||||
|
||||
///What stage of the teleportation are we in
|
||||
var/teleporting_stage = GOHOME_START
|
||||
///The types of mobs that will drop post-teleportation.
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
button_icon_state = "power_human"
|
||||
power_explanation = "Masquerade:\n\
|
||||
Activating Masquerade will forge your identity to be practically identical to that of a human;\n\
|
||||
- You lose nearly all Bloodsucker benefits, including healing, sleep, radiation, crit, virus and cold immunity.\n\
|
||||
- You lose nearly all Bloodsucker benefits, including healing, sleep, radiation, crit, virus, gutting and cold immunity.\n\
|
||||
- Your eyes turn to that of a regular human as your heart begins to beat.\n\
|
||||
- You gain a Genetic sequence, and appear to have 100% blood when scanned by a Health Analyzer.\n\
|
||||
- You will not appear as Pale when examined. Anything further than Pale, however, will not be hidden.\n\
|
||||
At the end of a Masquerade, you will re-gain your Vampiric abilities, as well as lose any Disease & Gene you might have."
|
||||
At the end of a Masquerade, you will re-gain your Vampiric abilities, as well as lose any diseases you might have."
|
||||
power_flags = BP_AM_TOGGLE|BP_AM_STATIC_COOLDOWN|BP_AM_COSTLESS_UNCONSCIOUS
|
||||
check_flags = BP_CANT_USE_IN_FRENZY
|
||||
purchase_flags = BLOODSUCKER_CAN_BUY|BLOODSUCKER_DEFAULT_POWER
|
||||
purchase_flags = BLOODSUCKER_DEFAULT_POWER
|
||||
bloodcost = 10
|
||||
cooldown_time = 5 SECONDS
|
||||
constant_bloodcost = 0.1
|
||||
@@ -40,7 +40,11 @@
|
||||
|
||||
// Handle Traits
|
||||
user.remove_traits(bloodsuckerdatum_power.bloodsucker_traits, BLOODSUCKER_TRAIT)
|
||||
|
||||
ADD_TRAIT(user, TRAIT_MASQUERADE, BLOODSUCKER_TRAIT)
|
||||
var/obj/item/bodypart/chest/target_chest = user.get_bodypart(BODY_ZONE_CHEST)
|
||||
if(target_chest)
|
||||
target_chest.bodypart_flags &= ~BODYPART_UNREMOVABLE
|
||||
// Handle organs
|
||||
var/obj/item/organ/internal/heart/vampheart = user.get_organ_slot(ORGAN_SLOT_HEART)
|
||||
if(vampheart)
|
||||
@@ -52,6 +56,7 @@
|
||||
eyes.sight_flags = initial(eyes.sight_flags)
|
||||
user.update_sight()
|
||||
|
||||
/// todo, make bloodsuckerification into it's own proc, ie, eyes, traits, and such
|
||||
/datum/action/cooldown/bloodsucker/masquerade/DeactivatePower()
|
||||
. = ..() // activate = FALSE
|
||||
var/mob/living/carbon/user = owner
|
||||
@@ -59,14 +64,15 @@
|
||||
|
||||
// Remove status effect, mutations & diseases that you got while on masq.
|
||||
user.remove_status_effect(/datum/status_effect/masquerade)
|
||||
user.dna.remove_all_mutations()
|
||||
for(var/datum/disease/diseases as anything in user.diseases)
|
||||
diseases.cure()
|
||||
|
||||
// Handle Traits
|
||||
user.add_traits(bloodsuckerdatum_power.bloodsucker_traits, BLOODSUCKER_TRAIT)
|
||||
REMOVE_TRAIT(user, TRAIT_MASQUERADE, BLOODSUCKER_TRAIT)
|
||||
|
||||
var/obj/item/bodypart/chest/target_chest = user.get_bodypart(BODY_ZONE_CHEST)
|
||||
if(target_chest)
|
||||
target_chest.bodypart_flags |= BODYPART_UNREMOVABLE
|
||||
// Handle organs
|
||||
var/obj/item/organ/internal/heart/vampheart = user.get_organ_slot(ORGAN_SLOT_HEART)
|
||||
if(vampheart)
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
|
||||
/datum/action/cooldown/bloodsucker/targeted/haste
|
||||
name = "Immortal Haste"
|
||||
desc = "Dash somewhere with supernatural speed. Those nearby may be knocked away, stunned, or left empty-handed."
|
||||
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"
|
||||
power_explanation = "Immortal Haste:\n\
|
||||
Click anywhere to immediately dash towards that location.\n\
|
||||
At level 3, if you are lying down, you will get up and regain your stamina, but the resulting dash will not knock down those nearby.\n\
|
||||
The Power will not work if you are lying down, in no gravity, or are aggressively grabbed.\n\
|
||||
Anyone in your way during your Haste will be knocked down.\n\
|
||||
Higher levels will increase the knockdown dealt to enemies.\n\
|
||||
@@ -34,8 +35,8 @@
|
||||
if(!user.has_gravity(user.loc)) //We dont want people to be able to use this to fly around in space
|
||||
user.balloon_alert(user, "you cannot dash while floating!")
|
||||
return FALSE
|
||||
if(user.body_position == LYING_DOWN)
|
||||
user.balloon_alert(user, "you must be standing to tackle!")
|
||||
if(level_current < 3 && user.body_position == LYING_DOWN)
|
||||
user.balloon_alert(user, "you must be standing to dash!")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -49,8 +50,17 @@
|
||||
/// This is a non-async proc to make sure the power is "locked" until this finishes.
|
||||
/datum/action/cooldown/bloodsucker/targeted/haste/FireTargetedPower(atom/target_atom)
|
||||
. = ..()
|
||||
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
|
||||
var/mob/living/user = owner
|
||||
var/stuns_mobs = TRUE
|
||||
if(level_current >= 3 && user.body_position == LYING_DOWN)
|
||||
to_chat(user, span_danger("Your heart takes a beat, and you force yourself to stand up!"))
|
||||
user.SetKnockdown(0)
|
||||
user.setStaminaLoss(0)
|
||||
user.set_resting(FALSE, FALSE, TRUE)
|
||||
stuns_mobs = FALSE
|
||||
StartCooldown(cooldown_time * 3)
|
||||
if(stuns_mobs)
|
||||
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
|
||||
var/turf/targeted_turf = isturf(target_atom) ? target_atom : get_turf(target_atom)
|
||||
// Pulled? Not anymore.
|
||||
user.pulledby?.stop_pulling()
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
/*if(IS_MONSTERHUNTER(mesmerized_target))
|
||||
to_chat(mesmerized_target, span_notice("You feel your eyes burn for a while, but it passes."))
|
||||
return*/
|
||||
if(HAS_TRAIT_FROM(mesmerized_target, TRAIT_MUTE, BLOODSUCKER_TRAIT))
|
||||
if(HAS_TRAIT_FROM_ONLY(mesmerized_target, TRAIT_MUTE, BLOODSUCKER_TRAIT))
|
||||
owner.balloon_alert(owner, "[mesmerized_target] is already in a hypnotic gaze.")
|
||||
return
|
||||
if(iscarbon(mesmerized_target))
|
||||
|
||||
@@ -68,12 +68,12 @@
|
||||
name = "Level 4: Possession"
|
||||
upgraded_power = /datum/action/cooldown/bloodsucker/targeted/tremere/dominate/advanced/two
|
||||
level_current = 4
|
||||
desc = "Mesmerize, mute and blind any foe who stands still long enough, or convert the damaged to temporary Vassals."
|
||||
desc = "Mesmerize, mute and blind any foe who stands still long enough, or convert the damaged or dead to temporary Vassals."
|
||||
power_explanation = "Level 4: Possession:\n\
|
||||
Click any person to, after a 4 second timer, Mesmerize them.\n\
|
||||
This will completely immobilize, mute, and blind them for the next 13.5 seconds.\n\
|
||||
However, while adjacent to the target, if your target is in critical condition or dead, they will instead be turned into a temporary Vassal.\n\
|
||||
If you use this on a currently dead normal Vassal, you will instead revive them normally.\n\
|
||||
If you use this on a currently dead normal Vassal, they will will not suddenly cease to live as if a temporary Vassal.\n\
|
||||
Despite being Mute and Deaf, they will still have complete loyalty to you, until their death in 5 minutes upon use."
|
||||
background_icon_state = "tremere_power_gold_off"
|
||||
active_background_icon_state = "tremere_power_gold_on"
|
||||
@@ -83,14 +83,14 @@
|
||||
|
||||
/datum/action/cooldown/bloodsucker/targeted/tremere/dominate/advanced/two
|
||||
name = "Level 5: Possession"
|
||||
desc = "Mesmerize, mute and blind any foe who stands still long enough, or convert the damaged to temporary Vassals."
|
||||
desc = "Mesmerize, mute and blind any foe who stands still long enough, or convert the damaged or dead to temporary Vassals."
|
||||
level_current = 5
|
||||
upgraded_power = null
|
||||
power_explanation = "Level 5: Possession:\n\
|
||||
Click any person to, after a 4 second timer, Mesmerize them.\n\
|
||||
This will completely immobilize, mute, and blind them for the next 13.5 seconds.\n\
|
||||
However, while adjacent to the target, if your target is in critical condition or dead, they will instead be turned into a temporary Vassal.\n\
|
||||
If you use this on a currently dead normal Vassal, you will instead revive them normally.\n\
|
||||
If you use this on a currently dead normal Vassal, they will will not suddenly cease to live as if a temporary Vassal.\n\
|
||||
They will have complete loyalty to you, until their death in 8 minutes upon use."
|
||||
bloodcost = 100
|
||||
cooldown_time = 2 MINUTES
|
||||
@@ -110,8 +110,11 @@
|
||||
. = ..()
|
||||
var/mob/living/target = target_atom
|
||||
var/mob/living/user = owner
|
||||
if(target.stat >= SOFT_CRIT && user.Adjacent(target) && level_current >= 4)
|
||||
attempt_vassalize(target, user)
|
||||
if(target.stat != CONSCIOUS && level_current >= 4)
|
||||
if(user.Adjacent(target))
|
||||
attempt_vassalize(target, user)
|
||||
else
|
||||
owner.balloon_alert(owner, "too far to vassalize!")
|
||||
return
|
||||
else if(IS_VASSAL(target))
|
||||
owner.balloon_alert(owner, "vassal cant be revived")
|
||||
@@ -128,7 +131,8 @@
|
||||
/*if(IS_MONSTERHUNTER(target))
|
||||
to_chat(target, span_notice("You feel you something crawling under your skin, but it passes."))
|
||||
return*/
|
||||
if(HAS_TRAIT_FROM(target, TRAIT_MUTE, BLOODSUCKER_TRAIT))
|
||||
// todo replace with status effect so we don't only check chainstunning above lvl 2
|
||||
if(HAS_TRAIT_FROM_ONLY(target, TRAIT_MUTE, BLOODSUCKER_TRAIT))
|
||||
owner.balloon_alert(owner, "[target] is already in some form of hypnotic gaze.")
|
||||
return
|
||||
if(iscarbon(target))
|
||||
@@ -155,37 +159,50 @@
|
||||
owner.balloon_alert(owner, "[target] snapped out of their trance.")
|
||||
|
||||
/datum/action/cooldown/bloodsucker/targeted/tremere/dominate/proc/attempt_vassalize(mob/living/target, mob/living/user)
|
||||
var/datum/antagonist/vassal/is_vassal = IS_VASSAL(target)
|
||||
if(!bloodsuckerdatum_power.can_make_vassal(target))
|
||||
owner.balloon_alert(owner, "not a valid target for vassalization!.")
|
||||
return FALSE
|
||||
|
||||
owner.balloon_alert(owner, "attempting to vassalize.")
|
||||
if(!do_after(user, 6 SECONDS, target, NONE, TRUE))
|
||||
return
|
||||
return FALSE
|
||||
|
||||
if(IS_VASSAL(target))
|
||||
if(is_vassal?.master == bloodsuckerdatum_power)
|
||||
if(target.stat != DEAD)
|
||||
owner.balloon_alert(owner, "not dead!")
|
||||
return FALSE
|
||||
power_activated_sucessfully()
|
||||
to_chat(user, span_warning("We revive [target]!"))
|
||||
owner.balloon_alert(owner, "successfully revived!")
|
||||
target.mind.grab_ghost()
|
||||
target.revive(ADMIN_HEAL_ALL)
|
||||
return FALSE
|
||||
|
||||
if(!bloodsuckerdatum_power.make_vassal(target))
|
||||
owner.balloon_alert(owner, "not a valid target for vassalization!.")
|
||||
return
|
||||
|
||||
/*if(IS_MONSTERHUNTER(target))
|
||||
to_chat(target, span_notice("Their body refuses to react..."))
|
||||
return*/
|
||||
if(!bloodsuckerdatum_power.make_vassal(target))
|
||||
return
|
||||
power_activated_sucessfully()
|
||||
to_chat(user, span_warning("We revive [target]!"))
|
||||
target.mind.grab_ghost()
|
||||
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
|
||||
if(level_current == 4)
|
||||
living_time = 5 MINUTES
|
||||
target.add_traits(list(TRAIT_MUTE, TRAIT_DEAF), BLOODSUCKER_TRAIT)
|
||||
else if(level_current == 5)
|
||||
living_time = 8 MINUTES
|
||||
var/living_time = (1 MINUTES) * level_current
|
||||
if(level_current <= 4)
|
||||
target.add_traits(list(TRAIT_MUTE, TRAIT_DEAF), DOMINATE_TRAIT)
|
||||
addtimer(CALLBACK(src, PROC_REF(end_possession), target), living_time)
|
||||
RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(end_possession))
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/bloodsucker/targeted/tremere/proc/end_possession(mob/living/user)
|
||||
user.remove_traits(list(TRAIT_MUTE, TRAIT_DEAF), BLOODSUCKER_TRAIT)
|
||||
if(!IS_VASSAL(user) && !HAS_TRAIT_FROM_ONLY(user, TRAIT_MUTE, DOMINATE_TRAIT) && !HAS_TRAIT_FROM_ONLY(user, TRAIT_MUTE, DOMINATE_TRAIT))
|
||||
return
|
||||
user.remove_traits(list(TRAIT_MUTE, TRAIT_DEAF), DOMINATE_TRAIT)
|
||||
user.mind.remove_antag_datum(/datum/antagonist/vassal)
|
||||
to_chat(user, span_warning("You feel the Blood of your Master run out!"))
|
||||
user.death()
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
if(bloodsucker_power.level_current >= 5)
|
||||
var/mob/living/person_hit = target
|
||||
person_hit.blood_volume -= 60
|
||||
bloodsucker_power.bloodsuckerdatum_power.AddBloodVolume(60)
|
||||
bloodsucker_power.bloodsuckerdatum_power.AdjustBloodVolume(60)
|
||||
qdel(src)
|
||||
return BULLET_ACT_HIT
|
||||
. = ..()
|
||||
@@ -182,5 +182,5 @@
|
||||
/obj/item/shield/bloodsucker/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.mind.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
if(bloodsuckerdatum)
|
||||
bloodsuckerdatum.AddBloodVolume(-15)
|
||||
bloodsuckerdatum.AdjustBloodVolume(-15)
|
||||
return ..()
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
Activating this Power will begin to heal your wounds.\n\
|
||||
You will heal Brute and Toxin damage, at the cost of Stamina damage, and blood from both you and your Master.\n\
|
||||
If you aren't a bloodless race, you will additionally heal Burn damage.\n\
|
||||
The power will cancel out if you are incapacitated or dead."
|
||||
The power will cancel out if you are dead or unconcious."
|
||||
power_flags = BP_AM_TOGGLE
|
||||
check_flags = BP_CANT_USE_WHILE_INCAPACITATED|BP_CANT_USE_WHILE_UNCONSCIOUS
|
||||
check_flags = BP_CANT_USE_WHILE_UNCONSCIOUS
|
||||
purchase_flags = NONE
|
||||
bloodcost = 1.5
|
||||
cooldown_time = 10 SECONDS
|
||||
@@ -38,7 +38,7 @@
|
||||
return
|
||||
var/mob/living/carbon/user = owner
|
||||
var/datum/antagonist/vassal/vassaldatum = IS_VASSAL(user)
|
||||
vassaldatum.master.AddBloodVolume(-1)
|
||||
vassaldatum.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)
|
||||
@@ -55,7 +55,7 @@
|
||||
/datum/action/cooldown/bloodsucker/recuperate/ContinueActive(mob/living/user, mob/living/target)
|
||||
if(user.stat >= DEAD)
|
||||
return FALSE
|
||||
if(user.incapacitated())
|
||||
if(user.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB))
|
||||
owner.balloon_alert(owner, "too exhausted...")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Your name and appearance will be completely randomized, and turning the ability off again will undo it all.\n\
|
||||
Clothes, gear, and Security/Medical HUD status is kept the same while this power is active."
|
||||
power_flags = BP_AM_TOGGLE
|
||||
check_flags = BP_CANT_USE_IN_FRENZY
|
||||
check_flags = BP_CANT_USE_IN_FRENZY|BP_CANT_USE_WHILE_UNCONSCIOUS
|
||||
purchase_flags = BLOODSUCKER_DEFAULT_POWER
|
||||
bloodcost = 15
|
||||
constant_bloodcost = 0.1
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
if(user == resident)
|
||||
. += span_cult("This is your Claimed Coffin.")
|
||||
. += span_cult("Rest in it while injured to enter Torpor. Entering it with unspent Ranks will allow you to spend one.")
|
||||
. += span_cult("Going inside while it contains a heart will put it in your chest, letting you regain your might.")
|
||||
. += span_cult("Alt-Click while inside the Coffin to Lock/Unlock.")
|
||||
. += span_cult("Alt-Click while outside of your Coffin to Unclaim it, unwrenching it and all your other structures as a result.")
|
||||
|
||||
@@ -133,6 +134,8 @@
|
||||
resident = claimant
|
||||
anchored = TRUE
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/structure/closet/crate/coffin/Destroy()
|
||||
unclaim_coffin()
|
||||
@@ -168,6 +171,7 @@
|
||||
anchored = FALSE
|
||||
if(!resident || !resident.mind)
|
||||
return
|
||||
un_enlarge(resident)
|
||||
// Unclaiming
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = resident.mind.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
if(bloodsuckerdatum && bloodsuckerdatum.coffin == src)
|
||||
@@ -198,33 +202,61 @@
|
||||
|
||||
|
||||
/obj/structure/closet/crate/coffin/close(mob/living/user)
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = user?.mind?.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
if(bloodsuckerdatum && user.mob_size > max_mob_size)
|
||||
if(!HAS_TRAIT_FROM_ONLY(src, TRAIT_COFFIN_ENLARGED, "bloodsucker_coffin"))
|
||||
if(prompt_coffin_claim(bloodsuckerdatum))
|
||||
enlarge(user)
|
||||
else
|
||||
user.balloon_alert(user, "already claimed by another!")
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
for(var/atom/thing as anything in contents)
|
||||
SEND_SIGNAL(thing, COMSIG_ENTER_COFFIN, src, user)
|
||||
// Only the User can put themself into Torpor. If already in it, you'll start to heal.
|
||||
if(user in src)
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
if(!bloodsuckerdatum)
|
||||
if(!resident && !prompt_coffin_claim(bloodsuckerdatum))
|
||||
return FALSE
|
||||
var/area/current_area = get_area(src)
|
||||
if(!bloodsuckerdatum.coffin && !resident)
|
||||
switch(tgui_alert(user, "Do you wish to claim this as your coffin? [current_area] will be your lair.", "Claim Lair", list("Yes", "No")))
|
||||
if("Yes")
|
||||
claim_coffin(user, current_area)
|
||||
if("No")
|
||||
return
|
||||
LockMe(user)
|
||||
//Level up if possible.
|
||||
if(!bloodsuckerdatum.my_clan)
|
||||
user.balloon_alert("enter a clan!")
|
||||
to_chat(user, span_notice("You must enter a Clan to rank up. Do it in the antag menu, which you can see by pressing the action button in the top left."))
|
||||
else
|
||||
// Level ups cost 30% of your max blood volume, which scales with your rank.
|
||||
bloodsuckerdatum.SpendRank(blood_cost = bloodsuckerdatum.max_blood_volume * BLOODSUCKER_LEVELUP_PERCENTAGE)
|
||||
// You're in a Coffin, everything else is done, you're likely here to heal. Let's offer them the oppertunity to do so.
|
||||
bloodsuckerdatum.check_begin_torpor()
|
||||
if(!bloodsuckerdatum.frenzied)
|
||||
bloodsuckerdatum.SpendRank(blood_cost = bloodsuckerdatum.max_blood_volume * BLOODSUCKER_LEVELUP_PERCENTAGE)
|
||||
// You're in a Coffin, everything else is done, you're likely here to heal. Let's offer them the opportunity to do so.
|
||||
bloodsuckerdatum.check_begin_torpor(TORPOR_SKIP_CHECK_DAMAGE)
|
||||
return TRUE
|
||||
|
||||
#undef BLOODSUCKER_LEVELUP_PERCENTAGE
|
||||
/obj/structure/closet/crate/coffin/proc/prompt_coffin_claim(datum/antagonist/bloodsucker/dracula)
|
||||
if(!dracula)
|
||||
return FALSE
|
||||
var/area/current_area = get_area(src)
|
||||
if(!dracula.coffin && !resident)
|
||||
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")))
|
||||
if("Yes")
|
||||
return claim_coffin(dracula.owner.current, current_area)
|
||||
return FALSE
|
||||
|
||||
// some fatass bloodsucker is trying to fit in a too-small coffin, how about we make some room?
|
||||
/obj/structure/closet/crate/proc/enlarge(mob/living/user)
|
||||
ADD_TRAIT(src, TRAIT_COFFIN_ENLARGED, "bloodsucker_coffin")
|
||||
max_mob_size = user.mob_size
|
||||
to_chat(user, span_warning("The coffin creaks and squeaks as you try to squeeze into it. It's a tight fit but you manage it make it fit you."))
|
||||
playsound(src, 'modular_skyrat/modules/aesthetics/airlock/sound/creaking.ogg')
|
||||
animate(src, 1 SECONDS, FALSE, BOUNCE_EASING, transform = transform.Scale(user.mob_size * COFFIN_ENLARGE_MULT))
|
||||
|
||||
/obj/structure/closet/crate/proc/un_enlarge(mob/living/user)
|
||||
if(!HAS_TRAIT_FROM_ONLY(src, TRAIT_COFFIN_ENLARGED, "bloodsucker_coffin"))
|
||||
return
|
||||
REMOVE_TRAIT(src, TRAIT_COFFIN_ENLARGED, "bloodsucker_coffin")
|
||||
max_mob_size = initial(max_mob_size)
|
||||
var/matrix/normal
|
||||
// transform.Scale(user.mob_size * (COFFIN_ENLARGE_MULT + 1)
|
||||
animate(src, 1 SECONDS, FALSE, transform = normal)
|
||||
|
||||
/// You cannot weld or deconstruct an owned coffin. Only the owner can destroy their own coffin.
|
||||
/obj/structure/closet/crate/coffin/attackby(obj/item/item, mob/user, params)
|
||||
|
||||
@@ -296,10 +296,10 @@
|
||||
// Conversion Process
|
||||
if(convert_progress)
|
||||
balloon_alert(user, "spilling blood...")
|
||||
bloodsuckerdatum.AddBloodVolume(-TORTURE_BLOOD_HALF_COST)
|
||||
bloodsuckerdatum.AdjustBloodVolume(-TORTURE_BLOOD_HALF_COST)
|
||||
if(!do_torture(user, target))
|
||||
return FALSE
|
||||
bloodsuckerdatum.AddBloodVolume(-TORTURE_BLOOD_HALF_COST)
|
||||
bloodsuckerdatum.AdjustBloodVolume(-TORTURE_BLOOD_HALF_COST)
|
||||
// Prevent them from unbuckling themselves as long as we're torturing.
|
||||
target.Paralyze(1 SECONDS)
|
||||
convert_progress--
|
||||
@@ -329,7 +329,7 @@
|
||||
balloon_alert(user, "interrupted!")
|
||||
return
|
||||
// Convert to Vassal!
|
||||
bloodsuckerdatum.AddBloodVolume(-TORTURE_CONVERSION_COST)
|
||||
bloodsuckerdatum.AdjustBloodVolume(-TORTURE_CONVERSION_COST)
|
||||
if(bloodsuckerdatum.make_vassal(target))
|
||||
remove_loyalties(target)
|
||||
SEND_SIGNAL(bloodsuckerdatum, BLOODSUCKER_MADE_VASSAL, user, target)
|
||||
@@ -381,7 +381,9 @@
|
||||
/obj/structure/bloodsucker/vassalrack/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.
|
||||
if(is_banned_from(target.ckey, ROLE_BLOODSUCKER))
|
||||
return TRUE
|
||||
disloyalty_offered = TRUE
|
||||
to_chat(user, span_notice("[target] has been given the opportunity for servitude. You await their decision..."))
|
||||
var/alert_response = tgui_alert(
|
||||
|
||||
@@ -124,9 +124,15 @@
|
||||
custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 3)
|
||||
|
||||
///Time it takes to embed the stake into someone's chest.
|
||||
var/staketime = 12 SECONDS
|
||||
var/staketime = 5 SECONDS
|
||||
var/kills_blodsuckers = FALSE
|
||||
|
||||
/obj/item/stake/examine_more(mob/user)
|
||||
. = ..()
|
||||
. += span_notice("You can use [src] to stake someone in the chest, if they are laying down or grabbed by the neck.")
|
||||
if(IS_BLOODSUCKER(user))
|
||||
. += span_warning("You feel a sense of dread as you look at the [src]...")
|
||||
|
||||
/obj/item/stake/attack(mob/living/target, mob/living/user, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
@@ -161,7 +167,7 @@
|
||||
return
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = target.mind.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
if(bloodsuckerdatum)
|
||||
// If DEAD or TORPID... Kill Bloodsucker!
|
||||
// If silver stake and DEAD or TORPOR... Kill the Bloodsucker!
|
||||
if(target.StakeCanKillMe())
|
||||
bloodsuckerdatum.FinalDeath()
|
||||
else
|
||||
@@ -173,7 +179,7 @@
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/can_be_staked()
|
||||
if(!(mobility_flags & MOBILITY_MOVE))
|
||||
if(body_position == LYING_DOWN)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -185,8 +191,12 @@
|
||||
force = 8
|
||||
throwforce = 12
|
||||
armour_penetration = 10
|
||||
embedding = list("embed_chance" = 35)
|
||||
staketime = 10 SECONDS
|
||||
embedding = list("embed_chance" = 35, "fall_chance" = 0)
|
||||
staketime = 12 SECONDS
|
||||
|
||||
/obj/item/stake/hardened/examine_more(mob/user)
|
||||
. = ..()
|
||||
. += span_notice("The [src] won't fall out by itself, if embedded in someone.")
|
||||
|
||||
/obj/item/stake/hardened/silver
|
||||
name = "silver stake"
|
||||
@@ -197,10 +207,15 @@
|
||||
force = 9
|
||||
armour_penetration = 25
|
||||
custom_materials = list(/datum/material/silver = SHEET_MATERIAL_AMOUNT)
|
||||
embedding = list("embed_chance" = 65)
|
||||
staketime = 8 SECONDS
|
||||
embedding = list("embed_chance" = 65, "fall_chance" = 0)
|
||||
staketime = 15 SECONDS
|
||||
kills_blodsuckers = TRUE
|
||||
|
||||
/obj/item/stake/hardened/silver/examine_more(mob/user)
|
||||
. = ..()
|
||||
if(HAS_TRAIT(user.mind, TRAIT_BLOODSUCKER_HUNTER))
|
||||
. += span_notice("You know that the [src] can cause a Final Death to a vile Bloodsucker if they are asleep or dead.")
|
||||
|
||||
//////////////////////
|
||||
// ARCHIVES //
|
||||
//////////////////////
|
||||
@@ -233,13 +248,6 @@
|
||||
COOLDOWN_DECLARE(bloodsucker_check_cooldown)
|
||||
var/cooldown_time = 1 MINUTES
|
||||
|
||||
/obj/item/book/kindred/station_loving
|
||||
|
||||
/obj/item/book/kindred/station_loving/Initialize()
|
||||
. = ..()
|
||||
SSpoints_of_interest.make_point_of_interest(src)
|
||||
AddComponent(/datum/component/stationloving, FALSE, TRUE)
|
||||
|
||||
/obj/item/book/kindred/try_carve(obj/item/carving_item, mob/living/user, params)
|
||||
to_chat(user, span_notice("You feel the gentle whispers of a Librarian telling you not to cut [starting_title]."))
|
||||
return FALSE
|
||||
@@ -304,5 +312,22 @@
|
||||
|
||||
/obj/structure/displaycase/curator
|
||||
desc = "This book was found inside a coffin of a long dead Curator. It is said to be able to reveal the true nature of those who feed upon mankind."
|
||||
start_showpiece_type = /obj/item/book/kindred/station_loving
|
||||
start_showpiece_type = /obj/item/book/kindred
|
||||
req_access = list(ACCESS_LIBRARY)
|
||||
|
||||
|
||||
/// just a typepath to specify that it's monkey-owned, used for the heart thief objective
|
||||
/obj/item/organ/internal/heart/monkey
|
||||
|
||||
/obj/item/organ/internal/heart/examine_more(mob/user)
|
||||
. = ..()
|
||||
var/datum/antagonist/bloodsucker/vampire = IS_BLOODSUCKER(user)
|
||||
if(!vampire)
|
||||
return
|
||||
var/datum/objective/steal_n_of_type/heart_thief = locate() in vampire?.objectives
|
||||
if(!heart_thief)
|
||||
return
|
||||
if(heart_thief.check_if_valid_item(src))
|
||||
. += span_notice("This [src.name] will do for your purposes...")
|
||||
else
|
||||
. += span_notice("This [src.name] is of lesser quality, it won't do...")
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
/datum/action/cooldown/spell/shapeshift/bat
|
||||
name = "Bat Form"
|
||||
desc = "Take on the shape of a space bat. You can fly and see in the dark, and you heal from doing melee attacks."
|
||||
power_explanation = "You can fly and see in the dark, and you heal from doing melee attacks."
|
||||
invocation = "Master, grant me your might, BAT FORM!!"
|
||||
invocation_type = INVOCATION_SHOUT
|
||||
spell_requirements = NONE
|
||||
convert_damage = TRUE
|
||||
cooldown_time = 2 MINUTES
|
||||
cooldown_time = 1 MINUTES
|
||||
possible_shapes = list(/mob/living/basic/bat/bloodsucker)
|
||||
var/bats_to_spawn = 3
|
||||
var/powers_stored
|
||||
|
||||
/datum/action/cooldown/spell/shapeshift/bat/cast(mob/living/cast_on)
|
||||
. = ..()
|
||||
@@ -22,6 +22,7 @@
|
||||
return
|
||||
for(var/i in 1 to bats_to_spawn)
|
||||
var/mob/living/basic/bat/bat = new(get_turf(cast_on))
|
||||
QDEL_IN(bat, cooldown_time)
|
||||
random_step(bat, 2, 50)
|
||||
|
||||
/mob/living/basic/bat/bloodsucker
|
||||
@@ -29,20 +30,24 @@
|
||||
desc = "A bat with a thirst for blood."
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
speed = 0
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 15
|
||||
wound_bonus = 10
|
||||
obj_damage = 10
|
||||
speed = -0.1
|
||||
lighting_cutoff_red = 25
|
||||
lighting_cutoff_green = 8
|
||||
lighting_cutoff_blue = 5
|
||||
melee_attack_cooldown = CLICK_CD_MELEE
|
||||
basic_mob_flags = FLAMMABLE_MOB
|
||||
lighting_color_cutoffs = BLOODSUCKER_SIGHT_COLOR_CUTOFF
|
||||
damage_coeff = list(BRUTE = 0.9, BURN = 1.25, TOX = 1, STAMINA = 1, OXY = 1)
|
||||
attack_verb_simple = list("bite", "drain", "drain blood", "nip")
|
||||
attack_verb_continuous = list("bites", "drains", "drains blood", "nips")
|
||||
attack_verb_simple = "drain blood from"
|
||||
attack_verb_continuous = "drains blood from"
|
||||
|
||||
/mob/living/basic/bat/bloodsucker/Initialize(mapload)
|
||||
. = ..()
|
||||
// Go as fast as people can run
|
||||
AddElement(/datum/element/lifesteal, melee_damage_lower)
|
||||
// Too fat to fit through vents
|
||||
REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
|
||||
|
||||
@@ -7,48 +7,39 @@
|
||||
name = "\improper Vassal"
|
||||
roundend_category = "vassals"
|
||||
antagpanel_category = "Bloodsucker"
|
||||
job_rank = ROLE_BLOODSUCKER
|
||||
job_rank = ROLE_VASSAL
|
||||
antag_hud_name = "vassal"
|
||||
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."
|
||||
|
||||
/// The Master Bloodsucker's antag datum.
|
||||
var/datum/antagonist/bloodsucker/master
|
||||
/// List of all Purchased Powers, like Bloodsuckers.
|
||||
/// 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.
|
||||
var/special_type = FALSE
|
||||
/// The first textblock text in the antag panel.
|
||||
var/antag_panel_title
|
||||
var/antag_panel_description
|
||||
///Description of what this Vassal does.
|
||||
/// It's shown to the bloodsucker in the radial for setting vassal type
|
||||
var/vassal_description
|
||||
/// inherent traits that are removed and addded on antag datum loss and gain
|
||||
var/list/traits = list()
|
||||
|
||||
/datum/antagonist/vassal/antag_panel_data()
|
||||
return "Master : [master.owner.name]"
|
||||
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)
|
||||
var/list/data = list()
|
||||
data["title"] = "[antag_panel_title]\n[antag_panel_data()]"
|
||||
data["description"] = antag_panel_description
|
||||
for(var/datum/action/cooldown/bloodsucker/power as anything in powers)
|
||||
var/list/power_data = list()
|
||||
|
||||
power_data["power_name"] = power.name
|
||||
power_data["power_explanation"] = power.power_explanation
|
||||
power_data["power_icon"] = power.button_icon_state
|
||||
|
||||
data["powers"] += list(power_data)
|
||||
|
||||
return data + ..()
|
||||
return ability_ui_data(powers) + ..()
|
||||
|
||||
/datum/antagonist/vassal/apply_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
var/mob/living/current_mob = mob_override || owner.current
|
||||
current_mob.apply_status_effect(/datum/status_effect/agent_pinpointer/vassal_edition)
|
||||
add_team_hud(current_mob)
|
||||
if(length(traits))
|
||||
current_mob.add_traits(traits, VASSAL_TRAIT)
|
||||
|
||||
/datum/antagonist/vassal/add_team_hud(mob/target)
|
||||
QDEL_NULL(team_hud_ref)
|
||||
@@ -76,6 +67,8 @@
|
||||
. = ..()
|
||||
var/mob/living/current_mob = mob_override || owner.current
|
||||
current_mob.remove_status_effect(/datum/status_effect/agent_pinpointer/vassal_edition)
|
||||
if(length(traits))
|
||||
current_mob.remove_traits(traits, VASSAL_TRAIT)
|
||||
|
||||
/datum/antagonist/vassal/pre_mindshield(mob/implanter, mob/living/mob_override)
|
||||
return COMPONENT_MINDSHIELD_PASSED
|
||||
@@ -114,7 +107,7 @@
|
||||
objectives += vassal_objective
|
||||
/// Give Vampire Language & Hud
|
||||
owner.current.grant_all_languages(FALSE, FALSE, TRUE)
|
||||
owner.current.grant_language(/datum/language/vampiric, LANGUAGE_SPOKEN, LANGUAGE_MIND)
|
||||
owner.current.grant_language(/datum/language/vampiric, ALL, LANGUAGE_MIND)
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/vassal/on_removal()
|
||||
@@ -128,14 +121,14 @@
|
||||
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, BLOODSUCKER_TRAIT)
|
||||
REMOVE_TRAIT(owner.current, all_status_traits, VASSAL_TRAIT)
|
||||
//Remove Recuperate Power
|
||||
remove_powers(powers)
|
||||
//Remove Language & Hud
|
||||
owner.current.remove_language(/datum/language/vampiric, LANGUAGE_SPOKEN, LANGUAGE_MIND)
|
||||
owner.current.remove_language(/datum/language/vampiric, ALL, LANGUAGE_MIND)
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/vassal/proc/remove_powers(var/list/removing_powers)
|
||||
/datum/antagonist/vassal/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))
|
||||
@@ -187,12 +180,12 @@
|
||||
continue
|
||||
possible_vampires += vamp
|
||||
if(!length(possible_vampires))
|
||||
message_admins("[key_name_admin(usr)] tried vassalizing [key_name_admin(new_owner)], but there were no bloodsuckers!")
|
||||
message_admins("[key_name_admin(admin)] tried vassalizing [key_name_admin(new_owner)], but there were no bloodsuckers!")
|
||||
return
|
||||
var/datum/mind/choice = input("Which bloodsucker should this vassal belong to?", "Bloodsucker") in possible_vampires
|
||||
var/datum/mind/choice = tgui_input_list(admin, "Which bloodsucker should this vassal belong to?", "Bloodsucker", possible_vampires)
|
||||
if(!choice)
|
||||
return
|
||||
log_admin("[key_name_admin(usr)] 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 vassal of [key_name_admin(choice)]!")
|
||||
var/datum/antagonist/bloodsucker/vampire = choice.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
master = vampire
|
||||
new_owner.add_antag_datum(src)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* viewer - The person examining.
|
||||
*/
|
||||
/datum/antagonist/vassal/proc/return_vassal_examine(mob/living/viewer)
|
||||
if(!viewer.mind || !iscarbon(owner.current))
|
||||
if((!viewer.mind && !isobserver(viewer)) || !iscarbon(owner.current))
|
||||
return FALSE
|
||||
var/mob/living/carbon/carbon_current = owner.current
|
||||
// Target must be a Vassal
|
||||
@@ -17,14 +17,14 @@
|
||||
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))
|
||||
if(!IS_BLOODSUCKER(viewer) && !IS_VASSAL(viewer) && !IS_MONSTERHUNTER(viewer) && !isobserver(viewer))
|
||||
return FALSE
|
||||
// Am I Viewer's Vassal?
|
||||
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?
|
||||
else if(IS_BLOODSUCKER(viewer) || IS_MONSTERHUNTER(viewer))
|
||||
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")]"
|
||||
// Are you serving the same master as I am?
|
||||
@@ -40,7 +40,7 @@
|
||||
return returnIcon + returnString
|
||||
|
||||
/// Used when your Master teaches you a new Power.
|
||||
/datum/antagonist/vassal/proc/BuyPower(datum/action/cooldown/bloodsucker/power, list_to_add_to = powers)
|
||||
/datum/antagonist/vassal/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
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
name = "\improper Ex-Vassal"
|
||||
roundend_category = "vassals"
|
||||
antagpanel_category = "Bloodsucker"
|
||||
job_rank = ROLE_BLOODSUCKER
|
||||
job_rank = ROLE_VASSAL
|
||||
antag_hud_name = "vassal_grey"
|
||||
show_in_roundend = FALSE
|
||||
show_in_antagpanel = FALSE
|
||||
|
||||
+1
-2
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
/datum/antagonist/vassal/favorite
|
||||
name = "\improper Favorite Vassal"
|
||||
show_in_antagpanel = FALSE
|
||||
antag_hud_name = "vassal6"
|
||||
special_type = FAVORITE_VASSAL
|
||||
vassal_description = "The Favorite Vassal gets unique abilities over other Vassals depending on your Clan \
|
||||
@@ -21,7 +20,7 @@
|
||||
SEND_SIGNAL(master, BLOODSUCKER_MAKE_FAVORITE, src)
|
||||
|
||||
/datum/antagonist/vassal/favorite/on_removal()
|
||||
remove_powers(bloodsucker_powers)
|
||||
SEND_SIGNAL(master, BLOODSUCKER_LOOSE_FAVORITE, src)
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/vassal/favorite/pre_mindshield(mob/implanter, mob/living/mob_override)
|
||||
|
||||
@@ -6,28 +6,29 @@
|
||||
return null
|
||||
|
||||
/// Replaces a couple organs to normal variants to not cause issues. Not super happy with this, alternative is disallowing vampiric races from being bloodsuckers
|
||||
/datum/species/proc/humanize_organs(mob/living/carbon/human/target)
|
||||
var/list/organs_to_handle = list(
|
||||
ORGAN_SLOT_HEART = /obj/item/organ/internal/heart,
|
||||
ORGAN_SLOT_LIVER = /obj/item/organ/internal/liver,
|
||||
ORGAN_SLOT_STOMACH = /obj/item/organ/internal/stomach,
|
||||
ORGAN_SLOT_TONGUE = /obj/item/organ/internal/tongue,
|
||||
)
|
||||
mutantheart = organs_to_handle[ORGAN_SLOT_HEART]
|
||||
mutantliver = organs_to_handle[ORGAN_SLOT_LIVER]
|
||||
mutantstomach = organs_to_handle[ORGAN_SLOT_STOMACH]
|
||||
mutanttongue = organs_to_handle[ORGAN_SLOT_TONGUE]
|
||||
for(var/organ_slot in organs_to_handle)
|
||||
/datum/species/proc/humanize_organs(mob/living/carbon/human/target, organs = list())
|
||||
if(!organs || !length(organs))
|
||||
organs = list(
|
||||
ORGAN_SLOT_HEART = /obj/item/organ/internal/heart,
|
||||
ORGAN_SLOT_LIVER = /obj/item/organ/internal/liver,
|
||||
ORGAN_SLOT_STOMACH = /obj/item/organ/internal/stomach,
|
||||
ORGAN_SLOT_TONGUE = /obj/item/organ/internal/tongue,
|
||||
)
|
||||
mutantheart = organs[ORGAN_SLOT_HEART]
|
||||
mutantliver = organs[ORGAN_SLOT_LIVER]
|
||||
mutantstomach = organs[ORGAN_SLOT_STOMACH]
|
||||
mutanttongue = organs[ORGAN_SLOT_TONGUE]
|
||||
for(var/organ_slot in organs)
|
||||
var/obj/item/organ/old_organ = target.get_organ_slot(organ_slot)
|
||||
var/organ_path = organs_to_handle[organ_slot]
|
||||
var/organ_path = organs[organ_slot]
|
||||
if(old_organ?.type == organ_path)
|
||||
continue
|
||||
var/obj/item/organ/new_organ = SSwardrobe.provide_type(organ_path)
|
||||
new_organ.Insert(target, FALSE, FALSE)
|
||||
new_organ.Insert(target, FALSE, DELETE_IF_REPLACED)
|
||||
|
||||
/datum/species/proc/normalize_organs(mob/living/carbon/human/target)
|
||||
mutantheart = initial(mutantheart)
|
||||
mutantliver = initial(mutantliver)
|
||||
mutantstomach = initial(mutantstomach)
|
||||
mutanttongue = initial(mutanttongue)
|
||||
regenerate_organs(target)
|
||||
regenerate_organs(target, replace_current = TRUE)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
/datum/species/jelly/on_bloodsucker_gain(mob/living/carbon/human/target)
|
||||
humanize_organs(target)
|
||||
|
||||
/datum/species/jelly/on_bloodsucker_loss(mob/living/carbon/human/target)
|
||||
// regenerate_organs with replace doesn't seem to automatically remove invalid organs unfortunately
|
||||
normalize_organs()
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
/datum/species/lizard/on_bloodsucker_gain(mob/living/carbon/human/target, datum/species/current_species)
|
||||
bodytemp_heat_damage_limit = BODYTEMP_HEAT_DAMAGE_LIMIT
|
||||
bodytemp_cold_damage_limit = BODYTEMP_COLD_DAMAGE_LIMIT
|
||||
|
||||
/datum/species/lizard/on_bloodsucker_loss(mob/living/carbon/human/target)
|
||||
bodytemp_heat_damage_limit = initial(bodytemp_heat_damage_limit)
|
||||
bodytemp_cold_damage_limit = initial(bodytemp_cold_damage_limit)
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
/datum/species/monkey
|
||||
mutantheart = /obj/item/organ/internal/heart/monkey
|
||||
+6
-1
@@ -8148,7 +8148,7 @@
|
||||
#include "modular_skyrat\modules\xenos_skyrat_redo\code\xeno_types\sentinel.dm"
|
||||
#include "modular_skyrat\modules\xenos_skyrat_redo\code\xeno_types\spitter.dm"
|
||||
#include "modular_skyrat\modules\xenos_skyrat_redo\code\xeno_types\warrior.dm"
|
||||
#include "modular_zubbers\code\__DEFINES\bloodsucker.dm"
|
||||
#include "modular_zubbers\code\__DEFINES\bloodsucker_defines.dm"
|
||||
#include "modular_zubbers\code\__DEFINES\moonstation_defines.dm"
|
||||
#include "modular_zubbers\code\__DEFINES\send2relay.dm"
|
||||
#include "modular_zubbers\code\__DEFINES\traits.dm"
|
||||
@@ -8162,6 +8162,7 @@
|
||||
#include "modular_zubbers\code\_globalvars\lists\~maintenance_loot.dm"
|
||||
#include "modular_zubbers\code\controllers\subsystem\air.dm"
|
||||
#include "modular_zubbers\code\controllers\subsystem\sol_subsystem.dm"
|
||||
#include "modular_zubbers\code\datums\action.dm"
|
||||
#include "modular_zubbers\code\datums\armor_overrides.dm"
|
||||
#include "modular_zubbers\code\datums\department_security.dm"
|
||||
#include "modular_zubbers\code\datums\ert.dm"
|
||||
@@ -8270,6 +8271,7 @@
|
||||
#include "modular_zubbers\code\modules\_defines.dm"
|
||||
#include "modular_zubbers\code\modules\admin\verbs\debug.dm"
|
||||
#include "modular_zubbers\code\modules\alternative_job_titles\code\alt_job_titles.dm"
|
||||
#include "modular_zubbers\code\modules\antagonists\_common\antag_datum.dm"
|
||||
#include "modular_zubbers\code\modules\antagonists\ashwalker\ashwalker.dm"
|
||||
#include "modular_zubbers\code\modules\antagonists\bloodsucker\bloodsuckers\assets.dm"
|
||||
#include "modular_zubbers\code\modules\antagonists\bloodsucker\bloodsuckers\bloodsucker.dm"
|
||||
@@ -8439,6 +8441,9 @@
|
||||
#include "modular_zubbers\code\modules\mob\living\carbon\human\_species.dm"
|
||||
#include "modular_zubbers\code\modules\mob\living\carbon\human\human.dm"
|
||||
#include "modular_zubbers\code\modules\mob\living\carbon\human\species_types\abductor.dm"
|
||||
#include "modular_zubbers\code\modules\mob\living\carbon\human\species_types\jellypeople.dm"
|
||||
#include "modular_zubbers\code\modules\mob\living\carbon\human\species_types\lizardpeople.dm"
|
||||
#include "modular_zubbers\code\modules\mob\living\carbon\human\species_types\monkeys.dm"
|
||||
#include "modular_zubbers\code\modules\mob\living\carbon\human\species_types\shadekin.dm"
|
||||
#include "modular_zubbers\code\modules\mob\living\carbon\human\species_types\snail.dm"
|
||||
#include "modular_zubbers\code\modules\mob\living\carbon\human\species_types\vampire.dm"
|
||||
|
||||
Reference in New Issue
Block a user