Merge pull request #11150 from raspyosu/master
Bloodsucker Abilities Tweaks/Rebalances
This commit is contained in:
@@ -101,14 +101,16 @@
|
||||
/datum/status_effect/no_combat_mode/mesmerize/on_creation(mob/living/new_owner, set_duration)
|
||||
. = ..()
|
||||
ADD_TRAIT(owner, TRAIT_MUTE, "mesmerize")
|
||||
owner.add_movespeed_modifier("[STATUS_EFFECT_MESMERIZE]_[id]", TRUE, priority = 64, override = TRUE, multiplicative_slowdown = 5, blacklisted_movetypes = FALSE? NONE : CRAWLING)
|
||||
|
||||
/datum/status_effect/no_combat_mode/mesmerize/on_remove()
|
||||
. = ..()
|
||||
REMOVE_TRAIT(owner, TRAIT_MUTE, "mesmerize")
|
||||
owner.remove_movespeed_modifier("[STATUS_EFFECT_MESMERIZE]_[id]")
|
||||
|
||||
/obj/screen/alert/status_effect/mesmerized
|
||||
name = "Mesmerized"
|
||||
desc = "You cant tear your sight from who is in front of you...Their gaze is simply too enthralling.."
|
||||
desc = "You cant tear your sight from who is in front of you... their gaze is simply too enthralling.."
|
||||
icon = 'icons/mob/actions/bloodsucker.dmi'
|
||||
icon_state = "power_mez"
|
||||
|
||||
|
||||
@@ -2,40 +2,56 @@
|
||||
|
||||
/datum/action/bloodsucker/cloak
|
||||
name = "Cloak of Darkness"
|
||||
desc = "Blend into the shadows and become invisible to the untrained eye."
|
||||
desc = "Blend into the shadows and become invisible to the untrained eye. Movement is slowed in brightly lit areas."
|
||||
button_icon_state = "power_cloak"
|
||||
bloodcost = 5
|
||||
cooldown = 50
|
||||
bloodsucker_can_buy = TRUE
|
||||
amToggle = TRUE
|
||||
warn_constant_cost = TRUE
|
||||
var/was_running
|
||||
|
||||
var/light_min = 0.2 // If lum is above this, no good.
|
||||
var/moveintent_was_run
|
||||
var/walk_threshold = 0.4 // arbitrary number, to be changed. edit in last commit: this is fine after testing on box station for a bit
|
||||
var/lum
|
||||
|
||||
/datum/action/bloodsucker/cloak/CheckCanUse(display_error)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
// Must be Dark
|
||||
var/turf/T = owner.loc
|
||||
if(istype(T) && T.get_lumcount() > light_min)
|
||||
to_chat(owner, "<span class='warning'>This area is not dark enough to blend in</span>")
|
||||
return FALSE
|
||||
|
||||
// must have nobody around to see the cloak
|
||||
var/watchers = viewers(9,get_turf(owner))
|
||||
for(var/mob/living/M in watchers)
|
||||
if(M != owner)
|
||||
to_chat(owner, "<span class='warning'>You may only vanish into the shadows unseen.</span>")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/action/bloodsucker/cloak/ActivatePower()
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
var/mob/living/user = owner
|
||||
was_running = (user.m_intent == MOVE_INTENT_RUN)
|
||||
if(was_running)
|
||||
user.toggle_move_intent()
|
||||
ADD_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
|
||||
|
||||
while(bloodsuckerdatum && ContinueActive(user))
|
||||
// Pay Blood Toll (if awake)
|
||||
owner.alpha = max(20, owner.alpha - min(75, 10 + 5 * level_current))
|
||||
owner.alpha = max(35, owner.alpha - min(75, 10 + 5 * level_current))
|
||||
bloodsuckerdatum.AddBloodVolume(-0.2)
|
||||
sleep(5) // Check every few ticks that we haven't disabled this power
|
||||
|
||||
moveintent_was_run = (user.m_intent == MOVE_INTENT_RUN)
|
||||
var/turf/T = get_turf(user)
|
||||
lum = T.get_lumcount()
|
||||
|
||||
if(istype(owner.loc))
|
||||
if(lum > walk_threshold)
|
||||
if(moveintent_was_run)
|
||||
user.toggle_move_intent()
|
||||
ADD_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
|
||||
|
||||
if(lum < walk_threshold)
|
||||
if(!moveintent_was_run)
|
||||
user.toggle_move_intent()
|
||||
REMOVE_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
|
||||
|
||||
sleep(5) // Check every few ticks
|
||||
|
||||
/datum/action/bloodsucker/cloak/ContinueActive(mob/living/user, mob/living/target)
|
||||
if (!..())
|
||||
@@ -43,15 +59,11 @@
|
||||
if(user.stat == !CONSCIOUS) // Must be CONSCIOUS
|
||||
to_chat(owner, "<span class='warning'>Your cloak failed due to you falling unconcious! </span>")
|
||||
return FALSE
|
||||
var/turf/T = owner.loc // Must be DARK
|
||||
if(istype(T) && T.get_lumcount() > light_min)
|
||||
to_chat(owner, "<span class='warning'>Your cloak failed due to there being too much light!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/bloodsucker/cloak/DeactivatePower(mob/living/user = owner, mob/living/target)
|
||||
..()
|
||||
REMOVE_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
|
||||
user.alpha = 255
|
||||
if(was_running && user.m_intent != MOVE_INTENT_RUN)
|
||||
if(!moveintent_was_run)
|
||||
user.toggle_move_intent()
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
button_icon_state = "power_lunge"
|
||||
bloodcost = 10
|
||||
cooldown = 120
|
||||
target_range = 3
|
||||
target_range = 5
|
||||
power_activates_immediately = TRUE
|
||||
message_Trigger = ""//"Whom will you subvert to your will?"
|
||||
message_Trigger = "Whom will you ensnare within your grasp?"
|
||||
must_be_capacitated = TRUE
|
||||
bloodsucker_can_buy = TRUE
|
||||
|
||||
@@ -58,25 +58,29 @@
|
||||
var/do_knockdown = !is_A_facing_B(target,owner) || owner.alpha <= 0 || istype(owner.loc, /obj/structure/closet)
|
||||
// CAUSES: Target has their back to me, I'm invisible, or I'm in a Closet
|
||||
// Step One: Heatseek toward Target's Turf
|
||||
|
||||
walk_towards(owner, T, 0.1, 10) // NOTE: this runs in the background! to cancel it, you need to use walk(owner.current,0), or give them a new path.
|
||||
addtimer(CALLBACK(owner, .proc/_walk, 0), 2 SECONDS)
|
||||
if(get_turf(owner) != T && !(isliving(target) && target.Adjacent(owner)) && owner.incapacitated() && owner.resting)
|
||||
var/send_dir = get_dir(owner, T)
|
||||
new /datum/forced_movement(owner, get_ranged_target_turf(owner, send_dir, 1), 1, FALSE)
|
||||
owner.spin(10)
|
||||
// Step Two: Check if I'm at/adjectent to Target's CURRENT turf (not original...that was just a destination)
|
||||
sleep(1)
|
||||
if(target.Adjacent(owner))
|
||||
// LEVEL 2: If behind target, mute or unconscious!
|
||||
if(do_knockdown) // && level_current >= 1)
|
||||
target.Knockdown(15 + 10 * level_current,1)
|
||||
target.adjustStaminaLoss(40 + 10 * level_current)
|
||||
// Cancel Walk (we were close enough to contact them)
|
||||
walk(owner, 0)
|
||||
target.Stun(10,1) //Without this the victim can just walk away
|
||||
target.grabbedby(owner) // Taken from mutations.dm under changelings
|
||||
target.grippedby(owner, instant = TRUE) //instant aggro grab
|
||||
target.playsound_local(get_turf(owner), 'sound/bloodsucker/lunge_warn.ogg', 60, FALSE, pressure_affected = FALSE) // target-only telegraphing
|
||||
owner.playsound_local(owner, 'sound/bloodsucker/lunge_warn.ogg', 60, FALSE, pressure_affected = FALSE) // audio feedback to the user
|
||||
if(do_mob(owner, owner, 6, TRUE, TRUE))
|
||||
walk_towards(owner, T, 0.1, 10) // yes i know i shouldn't use this but i don't know how to work in anything better
|
||||
if(get_turf(owner) != T && !(isliving(target) && target.Adjacent(owner)) && owner.incapacitated() && owner.resting)
|
||||
var/send_dir = get_dir(owner, T)
|
||||
new /datum/forced_movement(owner, get_ranged_target_turf(owner, send_dir, 1), 1, FALSE)
|
||||
owner.spin(10)
|
||||
// Step Two: Check if I'm at/adjectent to Target's CURRENT turf (not original...that was just a destination)
|
||||
for(var/i in 1 to 6)
|
||||
if (target.Adjacent(owner))
|
||||
// LEVEL 2: If behind target, mute or unconscious!
|
||||
if(do_knockdown) // && level_current >= 1)
|
||||
target.Knockdown(15 + 10 * level_current,1)
|
||||
target.adjustStaminaLoss(40 + 10 * level_current)
|
||||
// Cancel Walk (we were close enough to contact them)
|
||||
walk(owner, 0)
|
||||
target.Stun(10,1) //Without this the victim can just walk away
|
||||
target.grabbedby(owner) // Taken from mutations.dm under changelings
|
||||
target.grippedby(owner, instant = TRUE) //instant aggro grab
|
||||
break
|
||||
sleep(i*3)
|
||||
|
||||
/datum/action/bloodsucker/targeted/lunge/DeactivatePower(mob/living/user = owner, mob/living/target)
|
||||
..() // activate = FALSE
|
||||
|
||||
@@ -11,24 +11,25 @@
|
||||
button_icon_state = "power_mez"
|
||||
bloodcost = 30
|
||||
cooldown = 300
|
||||
target_range = 1
|
||||
power_activates_immediately = FALSE
|
||||
target_range = 3
|
||||
power_activates_immediately = TRUE
|
||||
message_Trigger = "Whom will you subvert to your will?"
|
||||
must_be_capacitated = TRUE
|
||||
bloodsucker_can_buy = TRUE
|
||||
var/success
|
||||
|
||||
/datum/action/bloodsucker/targeted/mesmerize/CheckCanUse(display_error)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if (!owner.getorganslot(ORGAN_SLOT_EYES))
|
||||
if(!owner.getorganslot(ORGAN_SLOT_EYES))
|
||||
if (display_error)
|
||||
to_chat(owner, "<span class='warning'>You have no eyes with which to mesmerize.</span>")
|
||||
return FALSE
|
||||
// Check: Eyes covered?
|
||||
var/mob/living/L = owner
|
||||
if (istype(L) && L.is_eyes_covered() || !isturf(owner.loc))
|
||||
if (display_error)
|
||||
if(istype(L) && L.is_eyes_covered() || !isturf(owner.loc))
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>Your eyes are concealed from sight.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -38,46 +39,51 @@
|
||||
|
||||
/datum/action/bloodsucker/targeted/mesmerize/CheckCanTarget(atom/A,display_error)
|
||||
// Check: Self
|
||||
if (A == owner)
|
||||
if(A == owner)
|
||||
return FALSE
|
||||
var/mob/living/carbon/target = A // We already know it's carbon due to CheckValidTarget()
|
||||
|
||||
// Bloodsucker
|
||||
if (target.mind && target.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
|
||||
if(target.mind && target.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
|
||||
if (display_error)
|
||||
to_chat(owner, "<span class='warning'>Bloodsuckers are immune to [src].</span>")
|
||||
return FALSE
|
||||
// Dead/Unconscious
|
||||
if (target.stat > CONSCIOUS)
|
||||
if(target.stat > CONSCIOUS)
|
||||
if (display_error)
|
||||
to_chat(owner, "<span class='warning'>Your victim is not [(target.stat == DEAD || HAS_TRAIT(target, TRAIT_FAKEDEATH))?"alive":"conscious"].</span>")
|
||||
return FALSE
|
||||
// Check: Target has eyes?
|
||||
if (!target.getorganslot(ORGAN_SLOT_EYES))
|
||||
if(!target.getorganslot(ORGAN_SLOT_EYES))
|
||||
if (display_error)
|
||||
to_chat(owner, "<span class='warning'>They have no eyes!</span>")
|
||||
return FALSE
|
||||
// Check: Target blind?
|
||||
if (target.eye_blind > 0)
|
||||
if(target.eye_blind > 0)
|
||||
if (display_error)
|
||||
to_chat(owner, "<span class='warning'>Your victim's eyes are glazed over. They cannot perceive you.</span>")
|
||||
return FALSE
|
||||
// Check: Target See Me? (behind wall)
|
||||
if (!(owner in view(target_range, get_turf(target))))
|
||||
if(!(target in view(target_range, get_turf(owner))))
|
||||
// Sub-Check: GET CLOSER
|
||||
//if (!(owner in range(target_range, get_turf(target)))
|
||||
// if (display_error)
|
||||
// to_chat(owner, "<span class='warning'>You're too far from your victim.</span>")
|
||||
if (display_error)
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>You're too far outside your victim's view.</span>")
|
||||
return FALSE
|
||||
|
||||
if(target.has_status_effect(STATUS_EFFECT_MESMERIZE)) // ?
|
||||
return TRUE
|
||||
|
||||
// Check: Facing target?
|
||||
if (!is_A_facing_B(owner,target)) // in unsorted.dm
|
||||
if(!is_A_facing_B(owner,target)) // in unsorted.dm
|
||||
if (display_error)
|
||||
to_chat(owner, "<span class='warning'>You must be facing your victim.</span>")
|
||||
return FALSE
|
||||
// Check: Target facing me?
|
||||
if (!target.resting && !is_A_facing_B(target,owner))
|
||||
if (display_error)
|
||||
if(!target.resting && !is_A_facing_B(target,owner))
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>Your victim must be facing you to see into your eyes.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -88,19 +94,28 @@
|
||||
var/mob/living/user = owner
|
||||
|
||||
if(istype(target))
|
||||
target.Stun(40) //Utterly useless without this, its okay since there are so many checks to go through
|
||||
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 45) //So you cant rotate with combat mode, plus fancy status alert
|
||||
var/power_time = 138 + level_current * 12
|
||||
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
|
||||
user.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
|
||||
if(do_mob(user, target, 30, TRUE, TRUE)) // 3 seconds windup
|
||||
success = CheckCanTarget(target)
|
||||
if(success) // target just has to be out of view when it is fully charged in order to avoid
|
||||
PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y
|
||||
target.face_atom(user)
|
||||
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time) // pretty much purely cosmetic
|
||||
target.Stun(power_time)
|
||||
to_chat(user, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
|
||||
target.next_move = world.time + power_time // <--- Use direct change instead. We want an unmodified delay to their next move // target.changeNext_move(power_time) // check click.dm
|
||||
target.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[target] has escaped your gaze!</span>")
|
||||
DeactivatePower()
|
||||
DeactivateRangedAbility()
|
||||
StartCooldown()
|
||||
// oops! if they knew how they could just spam stun the victim and themselves.
|
||||
|
||||
if(do_mob(user, target, 40, 0, TRUE, extra_checks = CALLBACK(src, .proc/ContinueActive, user, target)))
|
||||
PowerActivatedSuccessfully() // PAY COST! BEGIN COOLDOWN!
|
||||
var/power_time = 90 + level_current * 12
|
||||
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time + 80)
|
||||
to_chat(user, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
|
||||
target.Stun(power_time)
|
||||
target.next_move = world.time + power_time // <--- Use direct change instead. We want an unmodified delay to their next move // target.changeNext_move(power_time) // check click.dm
|
||||
target.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
|
||||
spawn(power_time)
|
||||
if(istype(target))
|
||||
if(istype(target) && success)
|
||||
target.notransform = FALSE
|
||||
// They Woke Up! (Notice if within view)
|
||||
if(istype(user) && target.stat == CONSCIOUS && (target in view(10, get_turf(user))) )
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user