Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
7 changes: 5 additions & 2 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,12 @@
#define TRAIT_ABILITY_BURROWED "t_ability_burrowed"
/// Xenos with this trait can toggle long sight while resting.
#define TRAIT_ABILITY_SIGHT_IGNORE_REST "t_ability_sight_ignore_rest"
/// Used by shielder to check stance.


// -- specific ability traits --
#define TRAIT_ABILITY_ASSASINATE "t_ability_assasinate"
#define TRAIT_ABILITY_INVIS "t_ability_invis"
#define TRAIT_ABILITY_ENCLOSED_PLATES "t_ability_enclosed_plates"
/// Used by shielder for reflective plates.
#define TRAIT_ABILITY_REFLECTIVE_PLATES "t_ability_reflective_plates"


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
action_type = XENO_ACTION_CLICK
plasma_cost = 20

var/duration = 30 SECONDS // 30 seconds base
var/invis_timer_id = TIMER_ID_NULL
var/alpha_amount = 25
var/speed_buff = 0.20
var/invis_recharge_time = 20 SECONDS
var/invis_start_time = -1 // Special value for when we're not invisible
var/invis_duration = 30 SECONDS

// tightly coupled 'buff next slash' action
/datum/action/xeno_action/onclick/lurker_assassinate
Expand All @@ -35,6 +37,8 @@
plasma_cost = 20

var/buff_duration = 50
var/buffed_slash_damage_ratio = 1.2
var/slash_slow_duration = 35

// VAMP LURKER ABILITIES

Expand Down
166 changes: 74 additions & 92 deletions code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,18 @@
/datum/behavior_delegate/lurker_base
name = "Base Lurker Behavior Delegate"

// Config
var/invis_recharge_time = 20 SECONDS
Comment thread
Venuska1117 marked this conversation as resolved.
var/invis_start_time = -1 // Special value for when we're not invisible
var/invis_duration = 30 SECONDS // so we can display how long the lurker is invisible to it
var/buffed_slash_damage_ratio = 1.2
var/slash_slow_duration = 35

// State
var/next_slash_buffed = FALSE

/datum/behavior_delegate/lurker_base/melee_attack_modify_damage(original_damage, mob/living/carbon/target_carbon)
if (!isxeno_human(target_carbon))
if(!isxeno_human(target_carbon))
return original_damage

if (next_slash_buffed)
if(HAS_TRAIT(bound_xeno, TRAIT_ABILITY_ASSASINATE))
to_chat(bound_xeno, SPAN_XENOHIGHDANGER("We significantly strengthen our attack, slowing [target_carbon]!"))
to_chat(target_carbon, SPAN_XENOHIGHDANGER("You feel a sharp pain as [bound_xeno] slashes you, slowing you down!"))
original_damage *= buffed_slash_damage_ratio
target_carbon.set_effect(get_xeno_stun_duration(target_carbon, 3), SUPERSLOW)
next_slash_buffed = FALSE
var/datum/action/xeno_action/onclick/lurker_assassinate/ability = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_assassinate)
if (ability)
original_damage *= ability.buffed_slash_damage_ratio
target_carbon.set_effect(get_xeno_stun_duration(target_carbon, 3), SUPERSLOW)
REMOVE_TRAIT(bound_xeno, TRAIT_ABILITY_ASSASINATE, TRAIT_SOURCE_ABILITY("assasinate"))
if(ability)
ability.button.icon_state = "template_xeno"

return original_damage
Expand All @@ -103,85 +93,66 @@
if(!isxeno_human(target_carbon))
return

if(next_slash_buffed && target_carbon)
if(HAS_TRAIT(bound_xeno, TRAIT_ABILITY_ASSASINATE) && target_carbon)
return INTENT_HARM

/datum/behavior_delegate/lurker_base/melee_attack_additional_effects_target(mob/living/carbon/target_carbon)
if (!isxeno_human(target_carbon))
if(!isxeno_human(target_carbon))
return

var/datum/action/xeno_action/onclick/lurker_assassinate/lurker_ass = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_assassinate)
if(!lurker_ass)
return

if (HAS_TRAIT(target_carbon, TRAIT_FLOORED))
new /datum/effects/xeno_slow(target_carbon, bound_xeno, null, null, get_xeno_stun_duration(target_carbon, slash_slow_duration))
if(HAS_TRAIT(target_carbon, TRAIT_FLOORED))
new /datum/effects/xeno_slow(target_carbon, bound_xeno, null, null, get_xeno_stun_duration(target_carbon, lurker_ass.slash_slow_duration))

return

/datum/behavior_delegate/lurker_base/melee_attack_additional_effects_self()
..()

var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis_action = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility)
if (lurker_invis_action)
if(lurker_invis_action)
lurker_invis_action.invisibility_off() // Full cooldown

/datum/behavior_delegate/lurker_base/proc/decloak_handler(mob/source)
SIGNAL_HANDLER
var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis_action = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility)
if(istype(lurker_invis_action))
lurker_invis_action.invisibility_off(0.5) // Partial refund of remaining time

/// Implementation for enabling invisibility.
/datum/behavior_delegate/lurker_base/proc/on_invisibility()
var/datum/action/xeno_action/activable/pounce/lurker/lurker_pounce_action = get_action(bound_xeno, /datum/action/xeno_action/activable/pounce/lurker)
if(lurker_pounce_action)
lurker_pounce_action.knockdown = TRUE // pounce knocks down
lurker_pounce_action.freeze_self = TRUE
ADD_TRAIT(bound_xeno, TRAIT_CLOAKED, TRAIT_SOURCE_ABILITY("cloak"))
RegisterSignal(bound_xeno, COMSIG_MOB_EFFECT_CLOAK_CANCEL, PROC_REF(decloak_handler))
bound_xeno.stealth = TRUE
invis_start_time = world.time

/// Implementation for disabling invisibility.
/datum/behavior_delegate/lurker_base/proc/on_invisibility_off()
var/datum/action/xeno_action/activable/pounce/lurker/lurker_pounce_action = get_action(bound_xeno, /datum/action/xeno_action/activable/pounce/lurker)
if(lurker_pounce_action)
lurker_pounce_action.knockdown = FALSE // pounce no longer knocks down
lurker_pounce_action.freeze_self = FALSE
bound_xeno.stealth = FALSE
REMOVE_TRAIT(bound_xeno, TRAIT_CLOAKED, TRAIT_SOURCE_ABILITY("cloak"))
UnregisterSignal(bound_xeno, COMSIG_MOB_EFFECT_CLOAK_CANCEL)
invis_start_time = -1

/datum/behavior_delegate/lurker_base/append_to_stat()
. = list()

var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_inv = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility)

// Invisible
if(invis_start_time != -1)
var/time_left = (invis_duration-(world.time - invis_start_time)) / 10
if(lurker_inv.invis_start_time != -1)
var/time_left = (lurker_inv.invis_duration-(world.time - lurker_inv.invis_start_time)) / 10
. += "Invisibility Remaining: [time_left] second\s."
return

var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invisibility_action = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility)
if(!lurker_invisibility_action)
if(!lurker_inv)
return

if(!bound_xeno.client?.prefs.show_cooldown_messages)
return

// Recharged
if(lurker_invisibility_action.cooldown_timer_id == TIMER_ID_NULL)
if(lurker_inv.cooldown_timer_id == TIMER_ID_NULL)
. += "Invisibility Recharge: Ready."
return

// Recharging
var/time_left = timeleft(lurker_invisibility_action.cooldown_timer_id) / 10
var/time_left = timeleft(lurker_inv.cooldown_timer_id) / 10
. += "Invisibility Recharge: [time_left] second\s."


/datum/behavior_delegate/lurker_base/on_collide(atom/movable/movable_atom)
. = ..()

if(!ishuman(movable_atom))
return

if(!bound_xeno || !bound_xeno.stealth)
if(!bound_xeno)
return

if(!HAS_TRAIT(bound_xeno, TRAIT_ABILITY_INVIS))
return

var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invisibility_action = get_action(bound_xeno, /datum/action/xeno_action/onclick/lurker_invisibility)
Expand All @@ -195,7 +166,6 @@
to_chat(bound_xeno, SPAN_XENOHIGHDANGER("We bumped into someone and lost our invisibility!"))
lurker_invisibility_action.invisibility_off(0.5) // partial refund of remaining time


/datum/action/xeno_action/activable/pounce/lurker/additional_effects(mob/living/living_mob)
var/mob/living/carbon/xenomorph/xeno = owner
if(!istype(xeno))
Expand Down Expand Up @@ -234,14 +204,12 @@

if(!istype(xeno))
return
if(!action_cooldown_check())
return
if(!check_and_use_plasma_owner())
return

XENO_ACTION_CHECK_USE_PLASMA(xeno)

xeno.deselect_timer = world.time + 5 // Half a second to prevent double clicks

if(xeno.stealth)
if(HAS_TRAIT(xeno, TRAIT_ABILITY_INVIS))
invisibility_off(0.9) // Near full refund of remaining time
return ..()

Expand All @@ -252,14 +220,25 @@
xeno.speed_modifier -= speed_buff
xeno.recalculate_speed()

var/datum/behavior_delegate/lurker_base/behavior = xeno.behavior_delegate
behavior.on_invisibility()
on_invisibility()

// if we go off early, this also works fine.
invis_timer_id = addtimer(CALLBACK(src, PROC_REF(invisibility_off)), duration, TIMER_STOPPABLE)
invis_timer_id = addtimer(CALLBACK(src, PROC_REF(invisibility_off)), invis_duration, TIMER_STOPPABLE)

return ..()

/// Implementation for enabling invisibility.
/datum/action/xeno_action/onclick/lurker_invisibility/proc/on_invisibility()
var/mob/living/carbon/xenomorph/xeno = owner
var/datum/action/xeno_action/activable/pounce/lurker/lurker_pounce_action = get_action(xeno, /datum/action/xeno_action/activable/pounce/lurker)
if(lurker_pounce_action)
lurker_pounce_action.knockdown = TRUE // pounce knocks down
lurker_pounce_action.freeze_self = TRUE
ADD_TRAIT(xeno, TRAIT_CLOAKED, TRAIT_SOURCE_ABILITY("cloak"))
ADD_TRAIT(xeno, TRAIT_ABILITY_INVIS, TRAIT_SOURCE_ABILITY("invis"))
RegisterSignal(xeno, COMSIG_MOB_EFFECT_CLOAK_CANCEL, PROC_REF(decloak_handler))
invis_start_time = world.time

/// Implementation for disabling invisibility.
/// (refund_multiplier) indicates how much cooldown to refund based on time remaining
/// 0 indicates full cooldown; 0.5 indicates 50% of remaining time is refunded
Expand All @@ -268,7 +247,11 @@

if(!istype(xeno))
return
if(owner.alpha == initial(owner.alpha) && !xeno.stealth)

if(owner.alpha == initial(owner.alpha))
return

if(!HAS_TRAIT(xeno, TRAIT_ABILITY_INVIS))
return

if(invis_timer_id != TIMER_ID_NULL)
Expand All @@ -283,18 +266,25 @@
xeno.speed_modifier += speed_buff
xeno.recalculate_speed()

var/datum/behavior_delegate/lurker_base/behavior = xeno.behavior_delegate
if(!istype(behavior))
CRASH("lurker_base behavior_delegate missing/invalid for [xeno]!")

var/recharge_time = behavior.invis_recharge_time
if(behavior.invis_start_time > 0) // Sanity
if(invis_start_time > 0) // Sanity
refund_multiplier = clamp(refund_multiplier, 0, 1)
var/remaining = 1 - (world.time - behavior.invis_start_time) / behavior.invis_duration
recharge_time = behavior.invis_recharge_time - remaining * refund_multiplier * behavior.invis_recharge_time
apply_cooldown_override(recharge_time)
var/remaining = 1 - (world.time - invis_start_time) / invis_duration
invis_recharge_time = invis_recharge_time - remaining * refund_multiplier * invis_recharge_time

behavior.on_invisibility_off()
apply_cooldown_override(invis_recharge_time)

var/datum/action/xeno_action/activable/pounce/lurker/lurker_pounce_action = get_action(xeno, /datum/action/xeno_action/activable/pounce/lurker)
if(lurker_pounce_action)
lurker_pounce_action.knockdown = FALSE // pounce no longer knocks down
lurker_pounce_action.freeze_self = FALSE
REMOVE_TRAIT(xeno, TRAIT_CLOAKED, TRAIT_SOURCE_ABILITY("cloak"))
REMOVE_TRAIT(xeno, TRAIT_ABILITY_INVIS, TRAIT_SOURCE_ABILITY("invis"))
UnregisterSignal(xeno, COMSIG_MOB_EFFECT_CLOAK_CANCEL)
invis_start_time = -1

/datum/action/xeno_action/onclick/lurker_invisibility/proc/decloak_handler(mob/source)
SIGNAL_HANDLER
invisibility_off(0.5) // Partial refund of remaining time

/datum/action/xeno_action/onclick/lurker_invisibility/ability_cooldown_over()
if(owner.client?.prefs.show_cooldown_messages)
Expand All @@ -304,18 +294,12 @@
/datum/action/xeno_action/onclick/lurker_assassinate/use_ability(atom/targeted_atom)
var/mob/living/carbon/xenomorph/xeno = owner

if (!istype(xeno))
return

if (!action_cooldown_check())
if(!istype(xeno))
return

if (!check_and_use_plasma_owner())
return
XENO_ACTION_CHECK_USE_PLASMA(xeno)

var/datum/behavior_delegate/lurker_base/behavior = xeno.behavior_delegate
if (istype(behavior))
behavior.next_slash_buffed = TRUE
ADD_TRAIT(xeno, TRAIT_ABILITY_ASSASINATE, TRAIT_SOURCE_ABILITY("assasinate"))

to_chat(xeno, SPAN_XENOHIGHDANGER("Our next slash will deal increased damage!"))

Expand All @@ -327,13 +311,11 @@

/datum/action/xeno_action/onclick/lurker_assassinate/proc/unbuff_slash()
var/mob/living/carbon/xenomorph/xeno = owner
if (!istype(xeno))
if(!istype(xeno))
return

if(!HAS_TRAIT(xeno, TRAIT_ABILITY_ASSASINATE))
return
var/datum/behavior_delegate/lurker_base/behavior = xeno.behavior_delegate
if (istype(behavior))
// In case slash has already landed
if (!behavior.next_slash_buffed)
return
behavior.next_slash_buffed = FALSE
REMOVE_TRAIT(xeno, TRAIT_ABILITY_ASSASINATE, TRAIT_SOURCE_ABILITY("assasinate"))

to_chat(xeno, SPAN_XENODANGER("We have waited too long, our slash will no longer deal increased damage!"))