diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm index b4fba61d51db..c19a1077bac2 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm @@ -223,6 +223,7 @@ var/list/pounce_callbacks = null // Specific callbacks to invoke when a pounce lands on an atom of a specific type // (note that if a collided atom does not match any of the key types, defaults to the appropriate X_launch_collision proc) + var/list/pounce_end_callbacks = null // Callbacks to call when the pounce (throw) ends /datum/action/xeno_action/activable/pounce/New() . = ..() diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm index cf5732741a1e..6dca6af969a9 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm @@ -440,7 +440,8 @@ pre_pounce_effects() X.pounce_distance = get_dist(X, A) - X.throw_atom(A, distance, throw_speed, X, launch_type = LOW_LAUNCH, pass_flags = pounce_pass_flags, collision_callbacks = pounce_callbacks) + var/list/pounce_end_callbacks = list(CALLBACK(src, PROC_REF(on_end_pounce))) + X.throw_atom(A, distance, throw_speed, X, launch_type = LOW_LAUNCH, pass_flags = pounce_pass_flags, end_throw_callbacks = pounce_end_callbacks, collision_callbacks = pounce_callbacks) X.update_icons() additional_effects_always() @@ -448,6 +449,9 @@ return TRUE +/datum/action/xeno_action/activable/pounce/proc/on_end_pounce() + return + // Massive, customizable spray_acid /datum/action/xeno_action/activable/spray_acid/use_ability(atom/A) var/mob/living/carbon/xenomorph/X = owner diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm index d4fb390f14f9..cb9215c81e06 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm @@ -49,7 +49,7 @@ plasma_cost = 0 // Config options - distance = 4 + distance = 5 knockdown = FALSE freeze_self = FALSE @@ -59,7 +59,7 @@ macro_path = /datum/action/xeno_action/verb/verb_flurry ability_primacy = XENO_PRIMARY_ACTION_2 action_type = XENO_ACTION_CLICK - xeno_cooldown = 3 SECONDS + xeno_cooldown = 4 SECONDS /datum/action/xeno_action/activable/tail_jab name = "Tail Jab" @@ -68,6 +68,7 @@ ability_primacy = XENO_PRIMARY_ACTION_3 action_type = XENO_ACTION_CLICK xeno_cooldown = 7 SECONDS + charge_time = 1 SECONDS /datum/action/xeno_action/activable/headbite name = "Headbite" diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm index 3c1d3a04543d..41d5908e0e15 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm @@ -144,9 +144,51 @@ // VAMPIRE LURKER -/datum/action/xeno_action/activable/pounce/rush/additional_effects(mob/living/living_target) //pounce effects +/datum/action/xeno_action/activable/pounce/rush/use_ability(atom/target) + var/mob/living/carbon/xenomorph/xeno = owner + if(!action_cooldown_check()) + return + + if(target == xeno) + return + + if(!isturf(xeno.loc)) + to_chat(xeno, SPAN_XENOWARNING("We can't [action_text] from here!")) + return + + if(!xeno.check_state()) + return + + var/mob/living/carbon/carbon_target = target + if(get_dist(xeno, target) > distance) + to_chat(xeno, SPAN_XENOWARNING("This is too far, find a closer target.")) + return FALSE + if(!iscarbon(target) || carbon_target.stat == DEAD) + for(var/mob/living/carbon/carbon in get_turf(target)) + carbon_target = carbon + if(carbon_target.stat != DEAD) + break + if(!iscarbon(carbon_target) || carbon_target.stat == DEAD) + to_chat(xeno, SPAN_XENOWARNING("We need a target to rush at, hostile or not.")) + return FALSE + + var/datum/behavior_delegate/lurker_vampire/vamp = xeno.behavior_delegate + vamp.rush_target_ref = WEAKREF(carbon_target) + + . = ..(carbon_target) + + if(!.) + vamp.rush_target_ref = null + return + + if(xeno.can_not_harm(carbon_target)) + xeno.emote("needshelp") + +/datum/action/xeno_action/activable/pounce/rush/additional_effects(mob/living/living_target) //rush effects var/mob/living/carbon/target = living_target var/mob/living/carbon/xenomorph/xeno = owner + var/datum/behavior_delegate/lurker_vampire/vamp = xeno.behavior_delegate + vamp.rush_target_ref = null target.sway_jitter(times = 2) xeno.animation_attack_on(target) xeno.flick_attack_overlay(target, "slash") //fake slash to prevent disarm abuse @@ -155,6 +197,22 @@ playsound(get_turf(target), 'sound/weapons/alien_claw_flesh3.ogg', 30, TRUE) shake_camera(target, 2, 1) +/datum/action/xeno_action/activable/pounce/rush/on_end_pounce() + var/mob/living/carbon/xenomorph/xeno = owner + var/datum/behavior_delegate/lurker_vampire/vamp = xeno.behavior_delegate + if(!vamp.rush_target_ref) + return + + var/mob/living/target = vamp.rush_target_ref.resolve() + vamp.rush_target_ref = null + if(!target) + return + if(!xeno.check_state()) + return + if(target.stat == DEAD || xeno.can_not_harm(target) || !xeno.Adjacent(target)) + return + additional_effects(target) + /datum/action/xeno_action/activable/flurry/use_ability(atom/targeted_atom) //flurry ability var/mob/living/carbon/xenomorph/xeno = owner @@ -214,9 +272,10 @@ log_attack("[key_name(xeno)] attacked [key_name(target)] with Flurry") target.apply_armoured_damage(get_xeno_damage_slash(target, xeno.caste.melee_damage_upper), ARMOR_MELEE, BRUTE, rand_zone()) playsound(get_turf(target), 'sound/weapons/alien_claw_flesh4.ogg', 30, TRUE) - xeno.flick_heal_overlay(1 SECONDS, "#00B800") - xeno.gain_health(30) xeno.animation_attack_on(target) + if (!xeno.on_fire) + xeno.flick_heal_overlay(1 SECONDS, "#00B800") + xeno.gain_health(30) xeno.emote("roar") return ..() @@ -236,6 +295,9 @@ if(distance > 2) return + if (world.time <= xeno.next_move) + return + var/list/turf/path = get_line(xeno, targeted_atom, include_start_atom = FALSE) for(var/turf/path_turf as anything in path) if(path_turf.density) @@ -266,11 +328,7 @@ break if(iscarbon(hit_target) && !xeno.can_not_harm(hit_target) && hit_target.stat != DEAD) - if(targeted_atom == hit_target) //reward for a direct hit - to_chat(xeno, SPAN_XENOHIGHDANGER("We attack [hit_target], with our tail, piercing their body!")) - hit_target.apply_armoured_damage(15, ARMOR_MELEE, BRUTE, "chest") - else - to_chat(xeno, SPAN_XENODANGER("We attack [hit_target], slashing them with our tail!")) + to_chat(xeno, SPAN_XENODANGER("We attack [hit_target], slashing them with our tail!")) else xeno.visible_message(SPAN_XENOWARNING("\The [xeno] swipes their tail through the air!"), SPAN_XENOWARNING("We swipe our tail through the air!")) apply_cooldown(cooldown_modifier = 0.2) @@ -290,10 +348,12 @@ hit_target.visible_message(SPAN_DANGER("[hit_target] slams into an obstacle!"), isxeno(hit_target) ? SPAN_XENODANGER("We slam into an obstacle!") : SPAN_HIGHDANGER("You slam into an obstacle!"), null, 4, CHAT_TYPE_TAKING_HIT) hit_target.apply_damage(MELEE_FORCE_TIER_2) - if (hit_target.mob_size < MOB_SIZE_BIG) - hit_target.KnockDown(0.5) - else - hit_target.Slow(0.5) + + if (hit_target.mob_size < MOB_SIZE_BIG) + hit_target.KnockDown(0.5) + else + hit_target.Slow(0.5) + /// To reset the direction if they haven't moved since then in below callback. var/last_dir = xeno.dir @@ -311,6 +371,7 @@ log_attack("[key_name(xeno)] attacked [key_name(hit_target)] with Tail Jab") apply_cooldown() + xeno_attack_delay(xeno) return ..() /datum/action/xeno_action/activable/tail_jab/proc/reset_direction(mob/living/carbon/xenomorph/xeno, last_dir, new_dir) @@ -374,10 +435,11 @@ xeno.animation_attack_on(target_carbon, pixel_offset = 16) target_carbon.apply_armoured_damage(60, ARMOR_MELEE, BRUTE, "head", 5) //DIE target_carbon.death(create_cause_data("headbite execution", xeno), FALSE) - xeno.gain_health(150) - xeno.xeno_jitter(1 SECONDS) - xeno.flick_heal_overlay(3 SECONDS, "#00B800") - xeno.emote("roar") + if (!xeno.on_fire) + xeno.gain_health(150) + xeno.xeno_jitter(1 SECONDS) + xeno.flick_heal_overlay(3 SECONDS, "#00B800") + xeno.emote("roar") log_attack("[key_name(xeno)] was executed by [key_name(target_carbon)] with a headbite!") apply_cooldown() return ..() diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm index 2f383d6e3c3a..2e38b5584b70 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm @@ -264,6 +264,7 @@ if(target.health < 0) target.gain_health(abs(target.health)) // gets them out of crit first + target.ExtinguishMob() target.gain_health(xeno.health * transfer_mod) target.updatehealth() diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm index 820aa662c919..284be1d8f1be 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm @@ -16,6 +16,7 @@ /datum/action/xeno_action/activable/tail_jab, /datum/action/xeno_action/activable/headbite, ) + behavior_delegate_type = /datum/behavior_delegate/lurker_vampire /datum/xeno_strain/vampire/apply_strain(mob/living/carbon/xenomorph/lurker/lurker) lurker.plasmapool_modifier = 0 @@ -30,3 +31,8 @@ lurker.execute_hud = TRUE lurker.recalculate_everything() + +/datum/behavior_delegate/lurker_vampire + name = "Lurker Vampire Behavior Delegate" + + var/datum/weakref/rush_target_ref = null //who are we targeting with the rush ability, used to strike them even if we didn't land exactly on top of them