Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Bloodsucker fixes #2102

Merged
merged 2 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions code/__DEFINES/bloodsuckers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@
*/
/// Source trait for Bloodsuckers-related traits
#define BLOODSUCKER_TRAIT "bloodsucker_trait"
/// Source trait for bloodsuckers in torpor.
#define TORPOR_TRAIT "torpor_trait"
/// Source trait for bloodsucker mesmerization.
#define MESMERIZED_TRAIT "mesmerized_trait"
/// Source trait for Monster Hunter-related traits
#define HUNTER_TRAIT "monsterhunter_trait"
/// Source trait while Feeding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
if(!master || (master == owner.current))
return TRUE
var/datum/antagonist/bloodsucker/bloodsuckerdatum = master.mind.has_antag_datum(/datum/antagonist/bloodsucker)
if(bloodsuckerdatum && bloodsuckerdatum.broke_masquerade)
if(bloodsuckerdatum?.broke_masquerade)
//vassal stealing
return TRUE
to_chat(owner.current, span_danger("[conversion_target]'s mind is overwhelmed with too much external force to put your own!"))
Expand All @@ -52,7 +52,7 @@
* time, ranges from 1 at 20 pop to 4 at 40 pop
*/
/datum/antagonist/bloodsucker/proc/return_current_max_vassals()
var/total_players = GLOB.joined_player_list.len
var/total_players = length(GLOB.joined_player_list)
switch(total_players)
if(1 to 20)
return 1
Expand All @@ -72,8 +72,7 @@
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)
if(IS_VASSAL(conversion_target))
conversion_target.mind.remove_antag_datum(/datum/antagonist/vassal)

var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.has_antag_datum(/datum/antagonist/bloodsucker)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@

// Default Report
var/objectives_complete = TRUE
if(objectives.len)
if(length(objectives))
report += printobjectives(objectives)
for(var/datum/objective/objective in objectives)
if(objective.objective_name == "Optional Objective")
Expand All @@ -351,10 +351,10 @@
break

// Now list their vassals
if(vassals.len)
report += "<span class='header'>Their Vassals were...</span>"
if(length(vassals))
report += span_header("Their Vassals were...")
for(var/datum/antagonist/vassal/all_vassals as anything in vassals)
if(!all_vassals.owner)
if(QDELETED(all_vassals?.owner))
continue
var/list/vassal_report = list()
vassal_report += "<b>[all_vassals.owner.name]</b>"
Expand All @@ -367,7 +367,7 @@
vassal_report += " and was the <b>Revenge Vassal</b>"
report += vassal_report.Join()

if(objectives.len == 0 || objectives_complete)
if(!length(objectives) || objectives_complete)
report += "<span class='greentext big'>The [name] was successful!</span>"
else
report += "<span class='redtext big'>The [name] has failed!</span>"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,21 @@
* person_selecting - Mob override for stuff like Admins selecting someone's clan.
*/
/datum/antagonist/bloodsucker/proc/assign_clan_and_bane(mob/person_selecting)
if(my_clan)
if(my_clan || owner.current.has_status_effect(/datum/status_effect/frenzy))
return
if(owner.current.has_status_effect(/datum/status_effect/frenzy))
return
if(!person_selecting)
person_selecting = owner.current
person_selecting ||= owner.current

var/list/options = list()
var/list/radial_display = list()
for(var/datum/bloodsucker_clan/all_clans as anything in typesof(/datum/bloodsucker_clan))
if(!initial(all_clans.joinable_clan)) //flavortext only
if(!all_clans::joinable_clan) //flavortext only
continue
options[initial(all_clans.name)] = all_clans
options[all_clans::name] = all_clans

var/datum/radial_menu_choice/option = new
option.image = image(icon = initial(all_clans.join_icon), icon_state = initial(all_clans.join_icon_state))
option.info = "[initial(all_clans.name)] - [span_boldnotice(initial(all_clans.join_description))]"
radial_display[initial(all_clans.name)] = option
option.image = image(icon = all_clans::join_icon, icon_state = all_clans::join_icon_state)
option.info = "[all_clans::name] - [span_boldnotice(all_clans::join_description)]"
radial_display[all_clans::name] = option

var/chosen_clan = show_radial_menu(person_selecting, owner.current, radial_display)
chosen_clan = options[chosen_clan]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
owner.add_client_colour(/datum/client_colour/cursed_heart_blood)
var/obj/cuffs = user.get_item_by_slot(ITEM_SLOT_HANDCUFFED)
var/obj/legcuffs = user.get_item_by_slot(ITEM_SLOT_LEGCUFFED)
if(user.handcuffed || user.legcuffed)
if(!QDELETED(user.handcuffed) || !QDELETED(user.legcuffed))
user.clear_cuffs(cuffs, TRUE)
user.clear_cuffs(legcuffs, TRUE)
bloodsuckerdatum.frenzied = TRUE
Expand All @@ -90,6 +90,6 @@

/datum/status_effect/frenzy/tick()
var/mob/living/carbon/human/user = owner
if(!bloodsuckerdatum.frenzied)
if(!bloodsuckerdatum?.frenzied)
return
user.adjustFireLoss(1.5 + (bloodsuckerdatum.humanity_lost / 10))
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
if(length(guardians) && !allow_multiple)
balloon_alert(user, "already have one!")
return
if(user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling) && !allow_changeling)
if(user.mind?.has_antag_datum(/datum/antagonist/changeling) && !allow_changeling)
to_chat(user, ling_failure)
return
if(used)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@
else if(bloodsucker_blood_volume > BLOOD_VOLUME_BAD)
valuecolor = "#FFAAAA"

if(blood_display)
blood_display.maptext = FORMAT_BLOODSUCKER_HUD_TEXT(valuecolor, bloodsucker_blood_volume)
blood_display?.maptext = FORMAT_BLOODSUCKER_HUD_TEXT(valuecolor, bloodsucker_blood_volume)

if(vamprank_display)
if(bloodsucker_level_unspent > 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
if(!owner)
INVOKE_ASYNC(src, PROC_REF(HandleDeath))
return
if(HAS_TRAIT(owner.current, TRAIT_NODEATH))
if(HAS_TRAIT_FROM(owner.current, TRAIT_NODEATH, TORPOR_TRAIT))
check_end_torpor()
// Deduct Blood
if(owner.current.stat == CONSCIOUS && !HAS_TRAIT(owner.current, TRAIT_IMMOBILIZED) && !HAS_TRAIT(owner.current, TRAIT_NODEATH))
if(owner.current.stat == CONSCIOUS && !HAS_TRAIT(owner.current, TRAIT_IMMOBILIZED) && !HAS_TRAIT_FROM(owner.current, TRAIT_NODEATH, TORPOR_TRAIT))
INVOKE_ASYNC(src, PROC_REF(AddBloodVolume), -BLOODSUCKER_PASSIVE_BLOOD_DRAIN) // -.1 currently
if(HandleHealing())
if((COOLDOWN_FINISHED(src, bloodsucker_spam_healing)) && bloodsucker_blood_volume > 0)
Expand Down Expand Up @@ -83,7 +83,7 @@
/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(owner.current, TRAIT_NODEATH, TORPOR_TRAIT)))
return FALSE
owner.current.adjustCloneLoss(-1 * (actual_regen * 4) * mult, 0)
owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * (actual_regen * 4) * mult) //adjustBrainLoss(-1 * (actual_regen * 4) * mult, 0)
Expand All @@ -95,7 +95,7 @@
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(user, TRAIT_NODEATH, TORPOR_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)
Expand All @@ -108,7 +108,7 @@
if(check_limbs(costMult))
return TRUE
// In Torpor, but not in a Coffin? Heal faster anyways.
else if(HAS_TRAIT(user, TRAIT_NODEATH))
else if(HAS_TRAIT_FROM(user, TRAIT_NODEATH, TORPOR_TRAIT))
fireheal = min(user.getFireLoss_nonProsthetic(), actual_regen) / 1.2 // 20% slower than being in a coffin
mult *= 3
// Heal if Damaged
Expand All @@ -123,7 +123,7 @@
var/limb_regen_cost = 50 * -costMult
var/mob/living/carbon/user = owner.current
var/list/missing = user.get_missing_limbs()
if(missing.len && (bloodsucker_blood_volume < limb_regen_cost + 5))
if(length(missing) && (bloodsucker_blood_volume < limb_regen_cost + 5))
return FALSE
for(var/missing_limb in missing) //Find ONE Limb and regenerate it.
user.regenerate_limb(missing_limb, FALSE)
Expand Down Expand Up @@ -155,7 +155,7 @@
organ.set_organ_damage(0)
if(!HAS_TRAIT(bloodsuckeruser, TRAIT_MASQUERADE))
var/obj/item/organ/internal/heart/current_heart = bloodsuckeruser.get_organ_slot(ORGAN_SLOT_HEART)
current_heart.beating = FALSE
current_heart?.beating = FALSE
var/obj/item/organ/internal/eyes/current_eyes = bloodsuckeruser.get_organ_slot(ORGAN_SLOT_EYES)
if(current_eyes)
current_eyes.flash_protect = max(initial(current_eyes.flash_protect) - 1, FLASH_PROTECTION_SENSITIVE)
Expand Down Expand Up @@ -199,7 +199,7 @@
FinalDeath()
return
// Temporary Death? Convert to Torpor.
if(HAS_TRAIT(owner.current, TRAIT_NODEATH))
if(HAS_TRAIT_FROM(owner.current, TRAIT_NODEATH, TORPOR_TRAIT))
return
to_chat(owner.current, span_danger("Your immortal body will not yet relinquish your soul to the abyss. You enter Torpor."))
check_begin_torpor(TRUE)
Expand All @@ -215,7 +215,7 @@
if(bloodsucker_blood_volume >= FRENZY_THRESHOLD_EXIT && frenzied)
owner.current.remove_status_effect(/datum/status_effect/frenzy)
// 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(owner.current, TRAIT_NODEATH, TORPOR_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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,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(owner.current, TRAIT_NODEATH, TORPOR_TRAIT)))
if(power.active)
power.DeactivatePower()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
/// Check Vassals and get their occupations
/datum/objective/bloodsucker/proc/get_vassal_occupations()
var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.has_antag_datum(/datum/antagonist/bloodsucker)
if(!bloodsuckerdatum || !bloodsuckerdatum.vassals.len)
if(!length(bloodsuckerdatum?.vassals))
return FALSE
var/list/all_vassal_jobs = list()
var/vassal_job
Expand Down Expand Up @@ -310,7 +310,7 @@
var/list/datum/mind/monsters = list()
for(var/datum/antagonist/monster in GLOB.antagonists)
var/datum/mind/brain = monster.owner
if(!brain || brain == owner)
if(QDELETED(brain) || brain == owner)
continue
if(brain.current.stat == DEAD)
continue
Expand All @@ -319,7 +319,7 @@
if(brain.has_antag_datum(/datum/antagonist/changeling))
monsters += brain

return completed || !monsters.len
return completed || !length(monsters)



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,8 @@
/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
var/datum/antagonist/bloodsucker/bloodsuckerdatum = mind?.has_antag_datum(/datum/antagonist/bloodsucker)
bloodsuckerdatum?.bloodsucker_blood_volume -= amount

/// Prevents using a Memento Mori
/obj/item/clothing/neck/necklace/memento_mori/memento(mob/living/carbon/human/user)
Expand All @@ -42,10 +38,9 @@

// Used when analyzing a Bloodsucker, Masquerade will hide brain traumas (Unless you're a Beefman)
/mob/living/carbon/get_traumas()
if(!mind)
if(QDELETED(mind))
return ..()
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(src)
if(bloodsuckerdatum && HAS_TRAIT(src, TRAIT_MASQUERADE))
if(IS_BLOODSUCKER(src) && HAS_TRAIT(src, TRAIT_MASQUERADE))
return
return ..()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

/obj/item/soulstone/bloodsucker/get_ghost_to_replace_shade(mob/living/carbon/victim, mob/user)
var/mob/dead/observer/chosen_ghost = victim.get_ghost(FALSE, TRUE)
if(!chosen_ghost || !chosen_ghost.client)
if(QDELETED(chosen_ghost?.client))
victim.dust()
return FALSE
victim.unequip_everything()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
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."))
COOLDOWN_START(src, bloodsucker_spam_sol_burn, BLOODSUCKER_SPAM_SOL) //This should happen twice per Sol
if(!HAS_TRAIT(owner.current, TRAIT_NODEATH))
if(!HAS_TRAIT_FROM(owner.current, TRAIT_NODEATH, TORPOR_TRAIT))
check_begin_torpor(TRUE)
owner.current.add_mood_event("vampsleep", /datum/mood_event/coffinsleep)
return
Expand Down Expand Up @@ -122,7 +122,7 @@
var/total_burn = user.getFireLoss_nonProsthetic()
var/total_damage = total_brute + total_burn
/// 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(!SSsunlight.sunlight_active && total_damage >= 10 && !HAS_TRAIT_FROM(owner.current, TRAIT_NODEATH, TORPOR_TRAIT))
torpor_begin()

/datum/antagonist/bloodsucker/proc/check_end_torpor()
Expand All @@ -147,15 +147,15 @@
// 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.add_traits(list(TRAIT_NODEATH, TRAIT_FAKEDEATH, TRAIT_DEATHCOMA, TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTHIGHPRESSURE), TORPOR_TRAIT)
owner.current.set_timed_status_effect(0 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE)
// 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."))
owner.current.remove_traits(list(TRAIT_NODEATH, TRAIT_FAKEDEATH, TRAIT_DEATHCOMA, TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTHIGHPRESSURE), BLOODSUCKER_TRAIT)
REMOVE_TRAITS_IN(owner.current, TORPOR_TRAIT)
if(!HAS_TRAIT(owner.current, TRAIT_MASQUERADE))
ADD_TRAIT(owner.current, TRAIT_SLEEPIMMUNE, BLOODSUCKER_TRAIT)
heal_vampire_organs()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@

// Delete Next Portal if it's time (it will remove its partner)
var/obj/effect/client_image_holder/phobetor/first_on_the_stack = created_firsts[1]
if(created_firsts.len && world.time >= first_on_the_stack.created_on + first_on_the_stack.exist_length)
if(length(created_firsts) && world.time >= first_on_the_stack.created_on + first_on_the_stack.exist_length)
var/targetGate = first_on_the_stack
created_firsts -= targetGate
qdel(targetGate)
Expand Down
4 changes: 2 additions & 2 deletions monkestation/code/modules/bloodsuckers/clans/_clan_base.dm
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@
if(initial(power.purchase_flags) & BLOODSUCKER_CAN_BUY && !(locate(power) in bloodsuckerdatum.powers))
options[initial(power.name)] = power

if(options.len < 1)
if(length(options) < 1)
to_chat(bloodsuckerdatum.owner.current, span_notice("You grow more ancient by the night!"))
else
// Give them the UI to purchase a power.
Expand Down Expand Up @@ -242,7 +242,7 @@
option.info = "[initial(vassaldatums.name)] - [span_boldnotice(initial(vassaldatums.vassal_description))]"
radial_display[initial(vassaldatums.name)] = option

if(!options.len)
if(!length(options))
return

to_chat(bloodsuckerdatum.owner.current, span_notice("You can change who this Vassal is, who are they to you?"))
Expand Down
2 changes: 1 addition & 1 deletion monkestation/code/modules/bloodsuckers/clans/tremere.dm
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
continue
options[initial(power.name)] = power

if(options.len < 1)
if(length(options) < 1)
to_chat(bloodsuckerdatum.owner.current, span_notice("You grow more ancient by the night!"))
else
// Give them the UI to purchase a power.
Expand Down
2 changes: 1 addition & 1 deletion monkestation/code/modules/bloodsuckers/clans/venture.dm
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
if(initial(power.purchase_flags) & VASSAL_CAN_BUY && !(locate(power) in vassaldatum.powers))
options[initial(power.name)] = power

if(options.len < 1)
if(length(options) < 1)
to_chat(bloodsuckerdatum.owner.current, span_notice("You grow more ancient by the night!"))
else
// Give them the UI to purchase a power.
Expand Down
Loading
Loading