Skip to content
Open
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
5 changes: 5 additions & 0 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,11 @@
#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"


// -- specific ability traits --
#define TRAIT_ABILITY_ASSASSINATE "t_ability_assassinate"
#define TRAIT_ABILITY_INVIS "t_ability_invis"
/// Used by shielder to check stance.
#define TRAIT_ABILITY_ENCLOSED_PLATES "t_ability_enclosed_plates"
/// Used by shielder for 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_ASSASSINATE))
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_ASSASSINATE, TRAIT_SOURCE_ABILITY("assassinate"))
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_ASSASSINATE) && 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_ASSASSINATE, TRAIT_SOURCE_ABILITY("assassinate"))

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_ASSASSINATE))
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_ASSASSINATE, TRAIT_SOURCE_ABILITY("assassinate"))

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