diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 0b9b02af75..81ee5c3989 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -201,51 +201,52 @@ /datum/mood_event/vampcandle description = "Something is making your mind feel... loose...\n" - mood_change = -10 + mood_change = -15 timeout = 1 MINUTES /datum/mood_event/drankblood_bad description = "I drank the blood of a lesser creature. Disgusting.\n" mood_change = -4 - timeout = 900 + timeout = 8 MINUTES /datum/mood_event/drankblood_dead description = "I drank dead blood. I am better than this.\n" mood_change = -7 - timeout = 900 + timeout = 10 MINUTES /datum/mood_event/drankblood_synth description = "I drank synthetic blood. What is wrong with me?\n" mood_change = -7 - timeout = 900 + timeout = 15 MINUTES /datum/mood_event/drankkilled description = "I drank from my victim until they died. I feel...less human.\n" mood_change = -12 - timeout = 6000 + timeout = 25 MINUTES /datum/mood_event/madevamp description = "A soul has been cursed to undeath by my own hand.\n" mood_change = -10 - timeout = 10000 + timeout = 30 MINUTES /datum/mood_event/vampatefood description = "Mortal nourishment no longer sustains me. I feel unwell.\n" mood_change = -6 - timeout = 1000 + timeout = 10 MINUTES /datum/mood_event/daylight_1 description = "I slept poorly in a makeshift coffin during the day.\n" mood_change = -3 - timeout = 1000 + timeout = 10 MINUTES -/datum/mood_event/nanite_sadness - description = "+++++++HAPPINESS SUPPRESSION+++++++\n" - mood_change = -7 /datum/mood_event/daylight_2 description = "I have been scorched by the unforgiving rays of the sun.\n" mood_change = -6 - timeout = 1200 + timeout = 15 MINUTES + +/datum/mood_event/nanite_sadness + description = "+++++++HAPPINESS SUPPRESSION+++++++\n" + mood_change = -7 /datum/mood_event/nanite_sadness/add_effects(message) description = "+++++++[message]+++++++\n" diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_life.dm b/code/modules/antagonists/bloodsucker/bloodsucker_life.dm index 10728d0664..f979b48c61 100644 --- a/code/modules/antagonists/bloodsucker/bloodsucker_life.dm +++ b/code/modules/antagonists/bloodsucker/bloodsucker_life.dm @@ -125,7 +125,7 @@ C.adjustFireLoss(-fireheal * mult, forced = TRUE) C.adjustToxLoss(-toxinheal * mult * 2, forced = TRUE) //Toxin healing because vamps arent immune //C.heal_overall_damage(bruteheal * mult, fireheal * mult) // REMOVED: We need to FORCE this, because otherwise, vamps won't heal EVER. Swapped to above. - AddBloodVolume((bruteheal * -0.5 + fireheal * -1) / mult * costMult) // Costs blood to heal + AddBloodVolume((bruteheal * -0.5 + fireheal * -1 + toxinheal * -0.2) / mult * costMult) // Costs blood to heal return TRUE // Healed! Done for this tick. if(amInCoffinWhileTorpor) // Limbs? (And I have no other healing) var/list/missing = owner.current.get_missing_limbs() // Heal Missing @@ -189,7 +189,7 @@ /datum/antagonist/bloodsucker/proc/HandleDeath() // FINAL DEATH // Fire Damage? (above double health) - if(owner.current.getFireLoss_nonProsthetic() >= owner.current.getMaxHealth() * 1.5) + if(owner.current.getFireLoss_nonProsthetic() >= owner.current.maxHealth * 3) FinalDeath() return // Staked while "Temp Death" or Asleep diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm b/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm index dffdeaf7fc..626ad43b10 100644 --- a/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm +++ b/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm @@ -32,11 +32,11 @@ //var/not_bloodsucker = FALSE // This goes to Vassals or Hunters, but NOT bloodsuckers. /datum/action/bloodsucker/New() - if (bloodcost > 0) + if(bloodcost > 0) desc += "

COST: [bloodcost] Blood" // Modify description to add cost. - if (warn_constant_cost) + if(warn_constant_cost) desc += "

Your over-time blood consumption increases while [name] is active." - if (amSingleUse) + if(amSingleUse) desc += "

Useable once per night." ..() @@ -47,35 +47,35 @@ /datum/action/bloodsucker/Trigger() // Active? DEACTIVATE AND END! - if (active && CheckCanDeactivate(TRUE)) + if(active && CheckCanDeactivate(TRUE)) DeactivatePower() return - if (!CheckCanPayCost(TRUE) || !CheckCanUse(TRUE)) + if(!CheckCanPayCost(TRUE) || !CheckCanUse(TRUE)) return PayCost() - if (amToggle) + if(amToggle) active = !active UpdateButtonIcon() - if (!amToggle || !active) + if(!amToggle || !active) StartCooldown() // Must come AFTER UpdateButton(), otherwise icon will revert. ActivatePower() // NOTE: ActivatePower() freezes this power in place until it ends. - if (active) // Did we not manually disable? Handle it here. + if(active) // Did we not manually disable? Handle it here. DeactivatePower() - if (amSingleUse) + if(amSingleUse) RemoveAfterUse() /datum/action/bloodsucker/proc/CheckCanPayCost(display_error) if(!owner || !owner.mind) return FALSE // Cooldown? - if (cooldownUntil > world.time) - if (display_error) + if(cooldownUntil > world.time) + if(display_error) to_chat(owner, "[src] is unavailable. Wait [(cooldownUntil - world.time) / 10] seconds.") return FALSE // Have enough blood? var/mob/living/L = owner - if (L.blood_volume < bloodcost) - if (display_error) + if(L.blood_volume < bloodcost) + if(display_error) to_chat(owner, "You need at least [bloodcost] blood to activate [name]") return FALSE return TRUE diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm b/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm index bb6e2a69f9..713699bbc7 100644 --- a/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm +++ b/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm @@ -1,4 +1,3 @@ -#define TIME_BLOODSUCKER_NIGHT 900 // 15 minutes #define TIME_BLOODSUCKER_DAY_WARN 90 // 1.5 minutes #define TIME_BLOODSUCKER_DAY_FINAL_WARN 25 // 25 sec #define TIME_BLOODSUCKER_DAY 60 // 1.5 minutes // 10 is a second, 600 is a minute. @@ -11,6 +10,7 @@ var/cancel_me = FALSE var/amDay = FALSE var/time_til_cycle = 0 + var/nightime_duration = 900 //15 Minutes /obj/effect/sunlight/Initialize() countdown() @@ -21,7 +21,7 @@ while(!cancel_me) - time_til_cycle = TIME_BLOODSUCKER_NIGHT + time_til_cycle = nightime_duration // Part 1: Night (all is well) while(time_til_cycle > TIME_BLOODSUCKER_DAY_WARN) @@ -81,7 +81,9 @@ "The solar flare has ended, and the daylight danger has passed...for now.") amDay = FALSE day_end() // Remove VANISHING ACT power from all vamps who have it! Clear Warnings (sunlight, locker protection) - message_admins("BLOODSUCKER NOTICE: Daylight Ended. Resetting to Night (Lasts for [TIME_BLOODSUCKER_NIGHT / 60] minutes.)") + nightime_duration += 200 //Each day makes the night last 2 or so minutes longer. + message_admins("BLOODSUCKER NOTICE: Daylight Ended. Resetting to Night (Lasts for [nightime_duration / 60] minutes.)") + /obj/effect/sunlight/proc/hud_tick() @@ -97,7 +99,7 @@ sleep(10) time_til_cycle -- -/obj/effect/sunlight/proc/warn_daylight(danger_level=0, vampwarn = "", vassalwarn = "") +/obj/effect/sunlight/proc/warn_daylight(danger_level =0, vampwarn = "", vassalwarn = "") for(var/datum/mind/M in SSticker.mode.bloodsuckers) if(!istype(M)) continue diff --git a/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm b/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm index 844b523135..034904b0bd 100644 --- a/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm +++ b/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm @@ -21,7 +21,7 @@ var/poweron_masquerade = FALSE // STATS var/vamplevel = 0 - var/vamplevel_unspent = 1 + var/vamplevel_unspent = 0 var/regenRate = 0.3 // How many points of Brute do I heal per tick? var/feedAmount = 15 // Amount of blood drawn from a target per tick. var/maxBloodVolume = 600 // Maximum blood a Vamp can hold via feeding. // BLOOD_VOLUME_NORMAL 550 // BLOOD_VOLUME_SAFE 475 //BLOOD_VOLUME_OKAY 336 //BLOOD_VOLUME_BAD 224 // BLOOD_VOLUME_SURVIVE 122 @@ -34,6 +34,7 @@ var/warn_sun_locker = FALSE // So we only get the locker burn message once per day. var/warn_sun_burn = FALSE // So we only get the sun burn message once per day. var/had_toxlover = FALSE + var/level_bloodcost // LISTS var/static/list/defaultTraits = list (TRAIT_STABLEHEART, TRAIT_NOBREATH, TRAIT_SLEEPIMMUNE, TRAIT_NOCRITDAMAGE, TRAIT_RESISTCOLD, TRAIT_RADIMMUNE, TRAIT_NIGHT_VISION, \ TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_AGEUSIA, TRAIT_COLDBLOODED, TRAIT_NONATURALHEAL, TRAIT_NOMARROW, TRAIT_NOPULSE, TRAIT_VIRUSIMMUNE) @@ -261,7 +262,7 @@ owner.hasSoul = TRUE //owner.current.hellbound = FALSE -datum/antagonist/bloodsucker/proc/RankUp() +/datum/antagonist/bloodsucker/proc/RankUp() set waitfor = FALSE if(!owner || !owner.current) return @@ -272,21 +273,23 @@ datum/antagonist/bloodsucker/proc/RankUp() else to_chat(owner, "You have grown more ancient! Sleep in a coffin that you have claimed to thicken your blood and become more powerful.") if(vamplevel_unspent >= 2) - to_chat(owner, "Bloodsucker Tip: If you cannot find or steal a coffin to use, they can be built from wooden planks.
") + to_chat(owner, "Bloodsucker Tip: If you cannot find or steal a coffin to use, you can build one from wooden planks.
") -datum/antagonist/bloodsucker/proc/LevelUpPowers() +/datum/antagonist/bloodsucker/proc/LevelUpPowers() for(var/datum/action/bloodsucker/power in powers) power.level_current ++ -datum/antagonist/bloodsucker/proc/SpendRank() +/datum/antagonist/bloodsucker/proc/SpendRank() set waitfor = FALSE - if (vamplevel_unspent <= 0 || !owner || !owner.current || !owner.current.client) + if(vamplevel_unspent <= 0 || !owner || !owner.current || !owner.current.client || !isliving(owner.current)) return - ///////// - // Powers - //TODO: Make this into a radial + var/mob/living/L = owner.current + level_bloodcost = maxBloodVolume * 0.3 + //If the blood volume of the bloodsucker is lower than the cost to level up, return and inform the bloodsucker + + //TODO: Make this into a radial, or perhaps a tgui next UI // Purchase Power Prompt - var/list/options = list() // Taken from gasmask.dm, for Clown Masks. + var/list/options = list() for(var/pickedpower in typesof(/datum/action/bloodsucker)) var/datum/action/bloodsucker/power = pickedpower // If I don't own it, and I'm allowed to buy it. @@ -295,7 +298,7 @@ datum/antagonist/bloodsucker/proc/SpendRank() options["\[ Not Now \]"] = null // Abort? if(options.len > 1) - var/choice = input(owner.current, "You have the opportunity to grow more ancient. Select a power to advance your Rank.", "Your Blood Thickens...") in options + var/choice = input(owner.current, "You have the opportunity to grow more ancient at the cost of [level_bloodcost] units of blood. Select a power to advance your Rank.", "Your Blood Thickens...") in options // Cheat-Safety: Can't keep opening/closing coffin to spam levels if(vamplevel_unspent <= 0) // Already spent all your points, and tried opening/closing your coffin, pal. return @@ -305,10 +308,14 @@ datum/antagonist/bloodsucker/proc/SpendRank() if(!choice || !options[choice] || (locate(options[choice]) in powers)) // ADDED: Check to see if you already have this power, due to window stacking. to_chat(owner.current, "You prevent your blood from thickening just yet, but you may try again later.") return + if(L.blood_volume < level_bloodcost) + to_chat(owner.current, "You dont have enough blood to thicken your blood, you need [level_bloodcost - L.blood_volume] units more!") + return // Buy New Powers var/datum/action/bloodsucker/P = options[choice] + AddBloodVolume(-level_bloodcost) BuyPower(new P) - to_chat(owner.current, "You have learned [initial(P.name)]!") + to_chat(owner.current, "You have used [level_bloodcost] units of blood and learned [initial(P.name)]!") else to_chat(owner.current, "You grow more ancient by the night!") ///////// @@ -326,7 +333,7 @@ datum/antagonist/bloodsucker/proc/SpendRank() // Vamp Stats regenRate += 0.05 // Points of brute healed (starts at 0.3) feedAmount += 2 // Increase how quickly I munch down vics (15) - maxBloodVolume += 50 // Increase my max blood (600) + maxBloodVolume += 100 // Increase my max blood (600) ///////// vamplevel ++ vamplevel_unspent -- diff --git a/code/modules/antagonists/bloodsucker/datum_vassal.dm b/code/modules/antagonists/bloodsucker/datum_vassal.dm index 716b7ff223..345c6f3c10 100644 --- a/code/modules/antagonists/bloodsucker/datum_vassal.dm +++ b/code/modules/antagonists/bloodsucker/datum_vassal.dm @@ -8,7 +8,7 @@ return SSticker.mode.make_vassal(C,owner) /datum/antagonist/bloodsucker/proc/FreeAllVassals() - for (var/datum/antagonist/vassal/V in vassals) + for(var/datum/antagonist/vassal/V in vassals) SSticker.mode.remove_vassal(V.owner) /datum/antagonist/vassal @@ -22,7 +22,7 @@ /datum/antagonist/vassal/can_be_owned(datum/mind/new_owner) // If we weren't created by a bloodsucker, then we cannot be a vassal (assigned from antag panel) - if (!master) + if(!master) return FALSE return ..() @@ -63,9 +63,9 @@ /datum/antagonist/vassal/on_removal() SSticker.mode.vassals -= owner // Add if not already in here (and you might be, if you were picked at round start) // Mindslave Remove - if (master && master.owner) + if(master && master.owner) master.vassals -= src - if (owner.enslaved_to == master.owner.current) + if(owner.enslaved_to == master.owner.current) owner.enslaved_to = null // Master Pinpointer owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer/vassal_edition) diff --git a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm index f66ce4a208..18758021db 100644 --- a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm +++ b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm @@ -107,7 +107,7 @@ var/convert_progress = 3 // Resets on each new character to be added to the chair. Some effects should lower it... var/disloyalty_confirm = FALSE // Command & Antags need to CONFIRM they are willing to lose their role (and will only do it if the Vassal'ing succeeds) var/disloyalty_offered = FALSE // Has the popup been issued? Don't spam them. - var/convert_cost = 100 + /obj/structure/bloodsucker/vassalrack/deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/metal(src.loc, 4) @@ -116,10 +116,10 @@ /obj/structure/bloodsucker/vassalrack/examine(mob/user) . = ..() - if((user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) || isobserver(user)) + if(isvamp(user) || isobserver(user)) . += {"This is the vassal rack, which allows you to thrall crewmembers into loyal minions in your service."} . += {"You need to first secure the vassal rack by clicking on it while it is in your lair."} - . += {"Simply click and hold on a victim, and then drag their sprite on the vassal rack."} + . += {"Simply click and hold on a victim, and then drag their sprite on the vassal rack. Alt click on the vassal rack to unbuckle them."} . += {"Make sure that the victim is handcuffed, or else they can simply run away or resist, as the process is not instant."} . += {"To convert the victim, simply click on the vassal rack itself. Sharp weapons work faster than other tools."} /* if(user.mind.has_antag_datum(ANTAG_DATUM_VASSAL) @@ -177,7 +177,7 @@ M.pixel_y = -2 //M.get_standard_pixel_y_offset(120)//180) update_icon() // Torture Stuff - convert_progress = 2 // Goes down unless you start over. + convert_progress = 4 // Goes down unless you start over. disloyalty_confirm = FALSE // New guy gets the chance to say NO if he's special. disloyalty_offered = FALSE // Prevents spamming torture window. @@ -190,7 +190,7 @@ else M.visible_message("[user] tries to pull [M] rack!",\ "[user] attempts to release you from the rack!") // For sound if not seen --> "You hear a squishy wet noise.") - if(!do_mob(user, M, 100)) + if(!do_mob(user, M, 200)) return // Did the time. Now try to do it. ..() @@ -248,7 +248,7 @@ // Bloodsucker Owner! Let the boy go. if(C.mind) var/datum/antagonist/vassal/vassaldatum = C.mind.has_antag_datum(ANTAG_DATUM_VASSAL) - if (istype(vassaldatum) && vassaldatum.master == bloodsuckerdatum || C.stat >= DEAD) + if(istype(vassaldatum) && vassaldatum.master == bloodsuckerdatum || C.stat >= DEAD) unbuckle_mob(C) useLock = FALSE // Failsafe return @@ -256,7 +256,9 @@ torture_victim(user, C) /obj/structure/bloodsucker/vassalrack/proc/torture_victim(mob/living/user, mob/living/target) + var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) // Check Bloodmob/living/M, force = FALSE, check_loc = TRUE + var/convert_cost = 200 * bloodsuckerdatum.vassals if(user.blood_volume < convert_cost + 5) to_chat(user, "You don't have enough blood to initiate the Dark Communion with [target].") return @@ -275,7 +277,7 @@ // All done! if(convert_progress <= 0) // FAIL: Can't be Vassal - if(!SSticker.mode.can_make_vassal(target, user, display_warning=FALSE) || HAS_TRAIT(target, TRAIT_MINDSHIELD)) // If I'm an unconvertable Antag ONLY + if(!SSticker.mode.can_make_vassal(target, user, display_warning = FALSE) || HAS_TRAIT(target, TRAIT_MINDSHIELD)) // If I'm an unconvertable Antag ONLY to_chat(user, "[target] doesn't respond to your persuasion. It doesn't appear they can be converted to follow you, they either have a mindshield or their external loyalties are too difficult for you to break.\[ALT+click to release\]") convert_progress ++ // Pop it back up some. Avoids wasting Blood on a lost cause. // SUCCESS: All done! @@ -301,10 +303,9 @@ return // Check: Blood if(user.blood_volume < convert_cost) - to_chat(user, "You don't have enough blood to initiate the Dark Communion with [target].") + to_chat(user, "You don't have enough blood to initiate the Dark Communion with [target], you need [convert_cost - user.blood_volume] units more!") useLock = FALSE return - var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) bloodsuckerdatum.AddBloodVolume(-convert_cost) target.add_mob_blood(user) user.visible_message("[user] marks a bloody smear on [target]'s forehead and puts a wrist up to [target.p_their()] mouth!", \ diff --git a/code/modules/antagonists/bloodsucker/powers/bs_brawn.dm b/code/modules/antagonists/bloodsucker/powers/bs_brawn.dm index 49aada3611..712a15dff9 100644 --- a/code/modules/antagonists/bloodsucker/powers/bs_brawn.dm +++ b/code/modules/antagonists/bloodsucker/powers/bs_brawn.dm @@ -5,7 +5,7 @@ desc = "Snap restraints with ease, or deal terrible damage with your bare hands." button_icon_state = "power_strength" bloodcost = 10 - cooldown = 130 + cooldown = 90 target_range = 1 power_activates_immediately = TRUE message_Trigger = ""//"Whom will you subvert to your will?" @@ -66,16 +66,14 @@ // Target Type: Mob if(isliving(target)) var/mob/living/carbon/user_C = user - var/hitStrength = user_C.dna.species.punchdamagehigh * 1.3 + 5 + var/hitStrength = user_C.dna.species.punchdamagehigh * 1.4 + 15 // Knockdown! var/powerlevel = min(5, 1 + level_current) if(rand(5 + powerlevel) >= 5) target.visible_message("[user] lands a vicious punch, sending [target] away!", \ "[user] has landed a horrifying punch on you, sending you flying!!", null, COMBAT_MESSAGE_RANGE) target.Knockdown(min(5, rand(10, 10 * powerlevel)) ) - // Chance of KO - if(rand(6 + powerlevel) >= 6 && target.stat <= UNCONSCIOUS) - target.Unconscious(40) + // Attack! playsound(get_turf(target), 'sound/weapons/punch4.ogg', 60, 1, -1) user.do_attack_animation(target, ATTACK_EFFECT_SMASH) diff --git a/code/modules/antagonists/bloodsucker/powers/bs_feed.dm b/code/modules/antagonists/bloodsucker/powers/bs_feed.dm index 7c4cf46e3c..2da84b6075 100644 --- a/code/modules/antagonists/bloodsucker/powers/bs_feed.dm +++ b/code/modules/antagonists/bloodsucker/powers/bs_feed.dm @@ -22,12 +22,12 @@ return // Wearing mask var/mob/living/L = owner - if (L.is_mouth_covered()) - if (display_error) + if(L.is_mouth_covered()) + if(display_error) to_chat(owner, "You cannot feed with your mouth covered! Remove your mask.") return FALSE // Find my Target! - if (!FindMyTarget(display_error)) // Sets feed_target within after Validating + if(!FindMyTarget(display_error)) // Sets feed_target within after Validating return FALSE // Not in correct state // DONE! @@ -35,36 +35,36 @@ /datum/action/bloodsucker/feed/proc/ValidateTarget(mob/living/target, display_error) // Called twice: validating a subtle victim, or validating your grapple victim. // Bloodsuckers + Animals MUST be grabbed aggressively! - if (!owner.pulling || target == owner.pulling && owner.grab_state < GRAB_AGGRESSIVE) + if(!owner.pulling || target == owner.pulling && owner.grab_state < GRAB_AGGRESSIVE) // NOTE: It's OKAY that we are checking if(!target) below, AFTER animals here. We want passive check vs animal to warn you first, THEN the standard warning. // Animals: - if (isliving(target) && !iscarbon(target)) - if (display_error) + if(isliving(target) && !iscarbon(target)) + if(display_error) to_chat(owner, "Lesser beings require a tighter grip.") return FALSE // Bloodsuckers: - else if (iscarbon(target) && target.mind && target.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) - if (display_error) + else if(iscarbon(target) && target.mind && target.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) + if(display_error) to_chat(owner, "Other Bloodsuckers will not fall for your subtle approach.") return FALSE // Must have Target - if (!target) // || !ismob(target) - if (display_error) + if(!target) // || !ismob(target) + if(display_error) to_chat(owner, "You must be next to or grabbing a victim to feed from them.") return FALSE // Not even living! - if (!isliving(target) || issilicon(target)) - if (display_error) + if(!isliving(target) || issilicon(target)) + if(display_error) to_chat(owner, "You may only feed from living beings.") return FALSE - if (target.blood_volume <= 0) - if (display_error) + if(target.blood_volume <= 0) + if(display_error) to_chat(owner, "Your victim has no blood to take.") return FALSE - if (ishuman(target)) + if(ishuman(target)) var/mob/living/carbon/human/H = target if(NOBLOOD in H.dna.species.species_traits)// || owner.get_blood_id() != target.get_blood_id()) - if (display_error) + if(display_error) to_chat(owner, "Your victim's blood is not suitable for you to take.") return FALSE return TRUE @@ -75,9 +75,9 @@ feed_target = null target_grappled = FALSE // If you are pulling a mob, that's your target. If you don't like it, then release them. - if (owner.pulling && ismob(owner.pulling)) + if(owner.pulling && ismob(owner.pulling)) // Check grapple target Valid - if (!ValidateTarget(owner.pulling, display_error)) // Grabbed targets display error. + if(!ValidateTarget(owner.pulling, display_error)) // Grabbed targets display error. return FALSE target_grappled = TRUE feed_target = owner.pulling @@ -86,11 +86,11 @@ var/list/mob/living/seen_targets = view(1, owner) var/list/mob/living/seen_mobs = list() for(var/mob/living/M in seen_targets) - if (isliving(M) && M != owner) + if(isliving(M) && M != owner) seen_mobs += M // None Seen! - if (seen_mobs.len == 0) - if (display_error) + if(seen_mobs.len == 0) + if(display_error) to_chat(owner, "You must be next to or grabbing a victim to feed from them.") return FALSE // Check Valids... @@ -98,19 +98,19 @@ var/list/targets_dead = list() for(var/mob/living/M in seen_mobs) // Check adjecent Valid target - if (M != owner && ValidateTarget(M, display_error = FALSE)) // Do NOT display errors. We'll be doing this again in CheckCanUse(), which will rule out grabbed targets. + if(M != owner && ValidateTarget(M, display_error = FALSE)) // Do NOT display errors. We'll be doing this again in CheckCanUse(), which will rule out grabbed targets. // Prioritize living, but remember dead as backup - if (M.stat < DEAD) + if(M.stat < DEAD) targets_valid += M else targets_dead += M // No Living? Try dead. - if (targets_valid.len == 0 && targets_dead.len > 0) + if(targets_valid.len == 0 && targets_dead.len > 0) targets_valid = targets_dead // No Targets - if (targets_valid.len == 0) + if(targets_valid.len == 0) // Did I see targets? Then display at least one error - if (seen_mobs.len > 1) + if(seen_mobs.len > 1) if (display_error) to_chat(owner, "None of these are valid targets to feed from subtly.") else @@ -136,28 +136,28 @@ // Initial Wait var/feed_time = (amSilent ? 45 : 25) - (2.5 * level_current) feed_time = max(15, feed_time) - if (amSilent) + if(amSilent) to_chat(user, "You lean quietly toward [target] and secretly draw out your fangs...") else to_chat(user, "You pull [target] close to you and draw out your fangs...") - if (!do_mob(user, target, feed_time,0,1,extra_checks=CALLBACK(src, .proc/ContinueActive, user, target)))//sleep(10) + if(!do_mob(user, target, feed_time,0,1,extra_checks=CALLBACK(src, .proc/ContinueActive, user, target)))//sleep(10) to_chat(user, "Your feeding was interrupted.") //DeactivatePower(user,target) return // Put target to Sleep (Bloodsuckers are immune to their own bite's sleep effect) - if (!amSilent) + if(!amSilent) ApplyVictimEffects(target) // Sleep, paralysis, immobile, unconscious, and mute if(target.stat <= UNCONSCIOUS) sleep(1) // Wait, then Cancel if Invalid - if (!ContinueActive(user,target)) // Cancel. They're gone. + if(!ContinueActive(user,target)) // Cancel. They're gone. //DeactivatePower(user,target) return // Pull Target Close - if (!target.density) // Pull target to you if they don't take up space. + if(!target.density) // Pull target to you if they don't take up space. target.Move(user.loc) // Broadcast Message - if (amSilent) + if(amSilent) //if (!iscarbon(target)) // user.visible_message("[user] shifts [target] closer to [user.p_their()] mouth.", \ // "You secretly slip your fangs into [target]'s flesh.", \ @@ -173,7 +173,7 @@ if(M != owner && M != target && iscarbon(M) && M.mind && !M.has_unlimited_silicon_privilege && !M.eye_blind && !M.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) was_unnoticed = FALSE break - if (was_unnoticed) + if(was_unnoticed) to_chat(user, "You think no one saw you...") else to_chat(user, "Someone may have noticed...") @@ -197,16 +197,16 @@ // FEEEEEEEEED!!! // bloodsuckerdatum.poweron_feed = TRUE - while (bloodsuckerdatum && target && active) + while(bloodsuckerdatum && target && active) //user.mobility_flags &= ~MOBILITY_MOVE // user.canmove = 0 // Prevents spilling blood accidentally. // Abort? A bloody mistake. - if (!do_mob(user, target, 20, 0, 0, extra_checks=CALLBACK(src, .proc/ContinueActive, user, target))) + if(!do_mob(user, target, 20, 0, 0, extra_checks=CALLBACK(src, .proc/ContinueActive, user, target))) // May have disabled Feed during do_mob - if (!active || !ContinueActive(user, target)) + if(!active || !ContinueActive(user, target)) break - if (amSilent) + if(amSilent) to_chat(user, "Your feeding has been interrupted...but [target.p_they()] didn't seem to notice you.") else to_chat(user, "Your feeding has been interrupted!") @@ -214,11 +214,11 @@ "Your teeth are ripped from [target]'s throat. [target.p_their(TRUE)] blood sprays everywhere!") // Deal Damage to Target (should have been more careful!) - if (iscarbon(target)) + if(iscarbon(target)) var/mob/living/carbon/C = target C.bleed(15) playsound(get_turf(target), 'sound/effects/splat.ogg', 40, 1) - if (ishuman(target)) + if(ishuman(target)) var/mob/living/carbon/human/H = target H.bleed_rate += 5 target.add_splatter_floor(get_turf(target)) @@ -228,7 +228,7 @@ target.emote("scream") // Killed Target? - if (was_alive) + if(was_alive) CheckKilledTarget(user,target) return @@ -237,40 +237,40 @@ // Handle Feeding! User & Victim Effects (per tick) bloodsuckerdatum.HandleFeeding(target, blood_take_mult) amount_taken += amSilent ? 0.3 : 1 - if (!amSilent) + if(!amSilent) ApplyVictimEffects(target) // Sleep, paralysis, immobile, unconscious, and mute - if (amount_taken > 5 && target.stat < DEAD && ishuman(target)) + if(amount_taken > 5 && target.stat < DEAD && ishuman(target)) SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "drankblood", /datum/mood_event/drankblood) // GOOD // in bloodsucker_life.dm /////////////////////////////////////////////////////////// // Not Human? - if (!ishuman(target)) + if(!ishuman(target)) SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "drankblood", /datum/mood_event/drankblood_bad) // BAD // in bloodsucker_life.dm - if (!warning_target_inhuman) + if(!warning_target_inhuman) to_chat(user, "You recoil at the taste of a lesser lifeform.") warning_target_inhuman = TRUE // Dead Blood? - if (target.stat >= DEAD) - if (ishuman(target)) + if(target.stat >= DEAD) + if(ishuman(target)) SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "drankblood", /datum/mood_event/drankblood_dead) // BAD // in bloodsucker_life.dm - if (!warning_target_dead) + if(!warning_target_dead) to_chat(user, "Your victim is dead. [target.p_their(TRUE)] blood barely nourishes you.") warning_target_dead = TRUE // Full? - if (!warning_full && user.blood_volume >= bloodsuckerdatum.maxBloodVolume) + if(!warning_full && user.blood_volume >= bloodsuckerdatum.maxBloodVolume) to_chat(user, "You are full. Further blood will be wasted.") warning_full = TRUE // Blood Remaining? (Carbons/Humans only) - if (iscarbon(target) && !target.AmBloodsucker(1)) - if (target.blood_volume <= BLOOD_VOLUME_BAD && warning_target_bloodvol > BLOOD_VOLUME_BAD) + if(iscarbon(target) && !target.AmBloodsucker(1)) + if(target.blood_volume <= BLOOD_VOLUME_BAD && warning_target_bloodvol > BLOOD_VOLUME_BAD) to_chat(user, "Your victim's blood volume is fatally low!") - else if (target.blood_volume <= BLOOD_VOLUME_OKAY && warning_target_bloodvol > BLOOD_VOLUME_OKAY) + else if(target.blood_volume <= BLOOD_VOLUME_OKAY && warning_target_bloodvol > BLOOD_VOLUME_OKAY) to_chat(user, "Your victim's blood volume is dangerously low.") - else if (target.blood_volume <= BLOOD_VOLUME_SAFE && warning_target_bloodvol > BLOOD_VOLUME_SAFE) + else if(target.blood_volume <= BLOOD_VOLUME_SAFE && warning_target_bloodvol > BLOOD_VOLUME_SAFE) to_chat(user, "Your victim's blood is at an unsafe level.") warning_target_bloodvol = target.blood_volume // If we had a warning to give, it's been given by now. // Done? - if (target.blood_volume <= 0) + if(target.blood_volume <= 0) to_chat(user, "You have bled your victim dry.") break @@ -279,7 +279,7 @@ // DONE! //DeactivatePower(user,target) - if (amSilent) + if(amSilent) to_chat(user, "You slowly release [target]'s wrist." + (target.stat == 0 ? " [target.p_their(TRUE)] face lacks expression, like you've already been forgotten." : "")) else user.visible_message("[user] unclenches their teeth from [target]'s neck.", \ @@ -289,13 +289,13 @@ log_combat(owner, target, "fed on blood", addition="(and took [amount_taken] blood)") // Killed Target? - if (was_alive) + if(was_alive) CheckKilledTarget(user,target) /datum/action/bloodsucker/feed/proc/CheckKilledTarget(mob/living/user, mob/living/target) // Bad Vampire. You shouldn't do that. - if (target && target.stat >= DEAD && ishuman(target)) + if(target && target.stat >= DEAD && ishuman(target)) SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "drankkilled", /datum/mood_event/drankkilled) // BAD // in bloodsucker_life.dm /datum/action/bloodsucker/feed/ContinueActive(mob/living/user, mob/living/target) @@ -304,18 +304,18 @@ /datum/action/bloodsucker/feed/proc/ApplyVictimEffects(mob/living/target) // Bloodsuckers not affected by "the Kiss" of another vampire - if (!target.mind || !target.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) + if(!target.mind || !target.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) target.Unconscious(50,0) target.Knockdown(40 + 5 * level_current,1) // NOTE: THis is based on level of power! - if (ishuman(target)) + if(ishuman(target)) target.adjustStaminaLoss(5, forced = TRUE)// Base Stamina Damage /datum/action/bloodsucker/feed/DeactivatePower(mob/living/user = owner, mob/living/target) ..() // activate = FALSE var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) // No longer Feeding - if (bloodsuckerdatum) + if(bloodsuckerdatum) bloodsuckerdatum.poweron_feed = FALSE feed_target = null // My mouth is no longer full diff --git a/code/modules/antagonists/bloodsucker/powers/bs_fortitude.dm b/code/modules/antagonists/bloodsucker/powers/bs_fortitude.dm index 3305504c15..f0724f8204 100644 --- a/code/modules/antagonists/bloodsucker/powers/bs_fortitude.dm +++ b/code/modules/antagonists/bloodsucker/powers/bs_fortitude.dm @@ -6,7 +6,7 @@ name = "Fortitude"//"Cellular Emporium" desc = "Withstand egregious physical wounds and walk away from attacks that would stun, pierce, and dismember lesser beings. You cannot run while active." button_icon_state = "power_fortitude" - bloodcost = 5 + bloodcost = 30 cooldown = 80 bloodsucker_can_buy = TRUE amToggle = TRUE @@ -23,7 +23,7 @@ ADD_TRAIT(user, TRAIT_NODISMEMBER, "fortitude") ADD_TRAIT(user, TRAIT_STUNIMMUNE, "fortitude") ADD_TRAIT(user, TRAIT_NORUNNING, "fortitude") - if (ishuman(owner)) + if(ishuman(owner)) var/mob/living/carbon/human/H = owner this_resist = max(0.3, 0.7 - level_current * 0.1) H.physiology.brute_mod *= this_resist//0.5 @@ -34,7 +34,7 @@ user.toggle_move_intent() while(bloodsuckerdatum && ContinueActive(user) || user.m_intent == MOVE_INTENT_RUN) // Pay Blood Toll (if awake) - if (user.stat == CONSCIOUS) + if(user.stat == CONSCIOUS) bloodsuckerdatum.AddBloodVolume(-0.5) // Used to be 0.3 blood per 2 seconds, but we're making it more expensive to keep on. sleep(20) // Check every few ticks that we haven't disabled this power // Return to Running (if you were before) @@ -48,7 +48,7 @@ REMOVE_TRAIT(user, TRAIT_NODISMEMBER, "fortitude") REMOVE_TRAIT(user, TRAIT_STUNIMMUNE, "fortitude") REMOVE_TRAIT(user, TRAIT_NORUNNING, "fortitude") - if (ishuman(owner)) + if(ishuman(owner)) var/mob/living/carbon/human/H = owner H.physiology.brute_mod /= this_resist//0.5 H.physiology.burn_mod /= this_resist//0.5 diff --git a/code/modules/antagonists/bloodsucker/powers/bs_gohome.dm b/code/modules/antagonists/bloodsucker/powers/bs_gohome.dm index 0da9ab5ba3..217f3ec221 100644 --- a/code/modules/antagonists/bloodsucker/powers/bs_gohome.dm +++ b/code/modules/antagonists/bloodsucker/powers/bs_gohome.dm @@ -23,11 +23,16 @@ return // Have No Lair (NOTE: You only got this power if you had a lair, so this means it's destroyed) var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) - if (!istype(bloodsuckerdatum) || !bloodsuckerdatum.coffin) - if (display_error) + if(!istype(bloodsuckerdatum) || !bloodsuckerdatum.coffin) + if(display_error) to_chat(owner, "Your coffin has been destroyed!") return FALSE return TRUE + +/datum/action/bloodsucker/gohome/proc/flicker_lights(var/flicker_range, var/beat_volume) + for(var/obj/machinery/light/L in view(flicker_range, get_turf(owner))) + playsound(get_turf(owner), 'sound/effects/singlebeat.ogg', beat_volume, 1) + /datum/action/bloodsucker/gohome/ActivatePower() var/mob/living/carbon/user = owner @@ -35,34 +40,31 @@ // IMPORTANT: Check for lair at every step! It might get destroyed. to_chat(user, "You focus on separating your consciousness from your physical form...") // STEP ONE: Flicker Lights - for(var/obj/machinery/light/L in view(3, get_turf(owner))) // /obj/machinery/light/proc/flicker(var/amount = rand(10, 20)) - L.flicker(5) - playsound(get_turf(owner), 'sound/effects/singlebeat.ogg', 20, 1) + flicker_lights(3, 20) sleep(50) - for(var/obj/machinery/light/L in view(3, get_turf(owner))) // /obj/machinery/light/proc/flicker(var/amount = rand(10, 20)) - L.flicker(5) - playsound(get_turf(owner), 'sound/effects/singlebeat.ogg', 40, 1) + flicker_lights(4, 40) sleep(50) - for(var/obj/machinery/light/L in view(6, get_turf(owner))) // /obj/machinery/light/proc/flicker(var/amount = rand(10, 20)) + flicker_lights(4, 60) + for(var/obj/machinery/light/L in view(6, get_turf(owner))) L.flicker(5) playsound(get_turf(owner), 'sound/effects/singlebeat.ogg', 60, 1) // ( STEP TWO: Lights OFF? ) // CHECK: Still have Coffin? - if (!istype(bloodsuckerdatum) || !bloodsuckerdatum.coffin) + if(!istype(bloodsuckerdatum) || !bloodsuckerdatum.coffin) to_chat(user, "Your coffin has been destroyed! You no longer have a destination.") return FALSE - if (!owner) + if(!owner) return // SEEN?: (effects ONLY if there are witnesses! Otherwise you just POOF) - // NOTE: Stolen directly from statue.dm, thanks guys! + var/am_seen = FALSE // Do Effects (seen by anyone) var/drop_item = FALSE // Drop Stuff (seen by non-vamp) - if (isturf(owner.loc)) // Only check if I'm not in a Locker or something. + if(isturf(owner.loc)) // Only check if I'm not in a Locker or something. // A) Check for Darkness (we can just leave) var/turf/T = get_turf(user) if(T && T.lighting_object && T.get_lumcount()>= 0.1) // B) Check for Viewers - for(var/mob/living/M in viewers(owner)) + for(var/mob/living/M in viewers(get_turf(owner))) if(M != owner && isliving(M) && M.mind && !M.has_unlimited_silicon_privilege && !M.eye_blind) // M.client <--- add this in after testing! am_seen = TRUE if (!M.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) @@ -76,7 +78,7 @@ var/obj/O = user.legcuffed user.dropItemToGround(O) // SEEN! - if (drop_item) + if(drop_item) // DROP: Clothes, held items, and cuffs etc // NOTE: Taken from unequip_everything() in inventory.dm. We need to // *force* all items to drop, so we had to just gut the code out of it. @@ -86,30 +88,28 @@ user.dropItemToGround(I,TRUE) for(var/obj/item/I in owner.held_items) // drop_all_held_items() user.dropItemToGround(I, TRUE) - if (am_seen) + if(am_seen) // POOF EFFECTS playsound(get_turf(owner), 'sound/magic/summon_karp.ogg', 60, 1) var/datum/effect_system/steam_spread/puff = new /datum/effect_system/steam_spread/() puff.effect_type = /obj/effect/particle_effect/smoke/vampsmoke puff.set_up(3, 0, get_turf(owner)) puff.start() + + //STEP FIVE: Create animal at prev location + var/mob/living/simple_animal/SA = pick(/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse, /mob/living/simple_animal/hostile/retaliate/bat) //prob(300) /mob/living/simple_animal/mouse, + new SA (owner.loc) // TELEPORT: Move to Coffin & Close it! - do_teleport(owner, bloodsuckerdatum.coffin, no_effects = TRUE, forced = TRUE, channel = TELEPORT_CHANNEL_QUANTUM) // in teleport.dm? - // SLEEP + do_teleport(owner, bloodsuckerdatum.coffin, no_effects = TRUE, forced = TRUE, channel = TELEPORT_CHANNEL_QUANTUM) user.resting = TRUE - //user.Unconscious(30,0) user.Stun(30,1) // CLOSE LID: If fail, force me in. - if (!bloodsuckerdatum.coffin.close(owner)) + if(!bloodsuckerdatum.coffin.close(owner)) bloodsuckerdatum.coffin.insert(owner) // Puts me inside. - // The following was taken from close() proc in closets.dm - // (but we had to do it this way because there is no way to force entry) playsound(bloodsuckerdatum.coffin.loc, bloodsuckerdatum.coffin.close_sound, 15, 1, -3) bloodsuckerdatum.coffin.opened = FALSE bloodsuckerdatum.coffin.density = TRUE bloodsuckerdatum.coffin.update_icon() // Lock Coffin bloodsuckerdatum.coffin.LockMe(owner) - // ( STEP FIVE: Create animal at prev location? ) - //var/mob/living/simple_animal/SA = /mob/living/simple_animal/hostile/retaliate/bat // pick(/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse, /mob/living/simple_animal/hostile/retaliate/bat) //prob(300) /mob/living/simple_animal/mouse, - //new SA (owner.loc) + diff --git a/code/modules/antagonists/bloodsucker/powers/bs_haste.dm b/code/modules/antagonists/bloodsucker/powers/bs_haste.dm index ee1dd3007c..a1aaf50499 100644 --- a/code/modules/antagonists/bloodsucker/powers/bs_haste.dm +++ b/code/modules/antagonists/bloodsucker/powers/bs_haste.dm @@ -8,7 +8,7 @@ desc = "Dash somewhere with supernatural speed. Those nearby may be knocked away, stunned, or left empty-handed." button_icon_state = "power_speed" bloodcost = 6 - cooldown = 30 + cooldown = 50 target_range = 15 power_activates_immediately = TRUE message_Trigger = ""//"Whom will you subvert to your will?" diff --git a/code/modules/antagonists/bloodsucker/powers/bs_lunge.dm b/code/modules/antagonists/bloodsucker/powers/bs_lunge.dm index 2c1b8d6321..7f180a1f19 100644 --- a/code/modules/antagonists/bloodsucker/powers/bs_lunge.dm +++ b/code/modules/antagonists/bloodsucker/powers/bs_lunge.dm @@ -6,7 +6,7 @@ desc = "Spring at your target and aggressively grapple them without warning. Attacks from concealment or the rear may even knock them down." button_icon_state = "power_lunge" bloodcost = 10 - cooldown = 100 + cooldown = 120 target_range = 3 power_activates_immediately = TRUE message_Trigger = ""//"Whom will you subvert to your will?" @@ -46,6 +46,8 @@ var/mob/living/L = A if(!isturf(L.loc)) return FALSE + if(!ishuman(target)) + return FALSE return TRUE /datum/action/bloodsucker/targeted/lunge/FireTargetedPower(atom/A) diff --git a/code/modules/antagonists/bloodsucker/powers/bs_mesmerize.dm b/code/modules/antagonists/bloodsucker/powers/bs_mesmerize.dm index 2fe7115d98..dc9d1d46a0 100644 --- a/code/modules/antagonists/bloodsucker/powers/bs_mesmerize.dm +++ b/code/modules/antagonists/bloodsucker/powers/bs_mesmerize.dm @@ -10,7 +10,7 @@ desc = "Dominate the mind of a mortal who can see your eyes." button_icon_state = "power_mez" bloodcost = 30 - cooldown = 200 + cooldown = 300 target_range = 1 power_activates_immediately = FALSE message_Trigger = "Whom will you subvert to your will?" diff --git a/code/modules/antagonists/bloodsucker/powers/bs_trespass.dm b/code/modules/antagonists/bloodsucker/powers/bs_trespass.dm index 159c7b20b7..45d1dda3ef 100644 --- a/code/modules/antagonists/bloodsucker/powers/bs_trespass.dm +++ b/code/modules/antagonists/bloodsucker/powers/bs_trespass.dm @@ -6,7 +6,7 @@ button_icon_state = "power_tres" bloodcost = 10 - cooldown = 60 + cooldown = 80 amToggle = FALSE //target_range = 2 diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index 8e5e327f39..6947ab28f8 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -252,7 +252,9 @@ return 0 if(M.getorgan(/obj/item/organ/alien/hivenode)) return 0 - + if(isvamp(M)) + return 0 + if(ismonkey(M)) return 1