From 8cd7f3770a4b7ba18391f02d4c9c4bb284cb51cb Mon Sep 17 00:00:00 2001 From: Venuska1117 Date: Sun, 19 Jul 2026 19:06:23 +0200 Subject: [PATCH 1/3] i hope its all --- code/__DEFINES/traits.dm | 15 +- .../mob/living/carbon/xenomorph/Evolution.dm | 4 +- .../living/carbon/xenomorph/XenoAttacks.dm | 3 + .../mob/living/carbon/xenomorph/Xenomorph.dm | 27 +- .../abilities/burrower/burrower_abilities.dm | 20 +- .../abilities/lurker/lurker_abilities.dm | 6 +- .../praetorian/praetorian_abilities.dm | 8 + .../abilities/ravager/ravager_abilities.dm | 3 + .../abilities/runner/runner_abilities.dm | 16 + .../abilities/runner/runner_powers.dm | 249 ----------- .../carbon/xenomorph/abilities/xeno_action.dm | 39 +- .../carbon/xenomorph/castes/Burrower.dm | 378 ++++++++-------- .../living/carbon/xenomorph/castes/Lurker.dm | 183 +++----- .../living/carbon/xenomorph/castes/Spitter.dm | 66 ++- .../carbon/xenomorph/castes/caste_datum.dm | 2 - .../living/carbon/xenomorph/damage_procs.dm | 4 + .../strains/castes/defender/steel_crest.dm | 34 +- .../strains/castes/praetorian/dancer.dm | 353 +++++++-------- .../strains/castes/praetorian/oppressor.dm | 184 ++++---- .../strains/castes/ravager/hedgehog.dm | 111 +++-- .../xenomorph/strains/castes/runner/acider.dm | 406 ++++++++++++++---- .../carbon/xenomorph/strains/xeno_strain.dm | 2 +- code/modules/projectiles/projectile.dm | 3 + 23 files changed, 1024 insertions(+), 1092 deletions(-) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 3df635790a5e..4ea0d29ccdd3 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -258,7 +258,7 @@ /// If the mob won't drop items held in face slot when downed #define TRAIT_IRON_TEETH "t_iron_teeth" -// -- ability traits -- +// -- general ability traits -- /// Xenos with this trait cannot have plasma transferred to them #define TRAIT_ABILITY_NO_PLASMA_TRANSFER "t_ability_no_plasma_transfer" /// Shows that the xeno queen is on ovi @@ -267,9 +267,18 @@ #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_BURROW_DIGGING "t_ability_burrow_digging" +#define TRAIT_ABILITY_BURROW_UNDERGROUND "t_ability_burrow_underground" +#define TRAIT_ABILITY_DODGE "t_ability_dodge" +#define TRAIT_ABILITY_RED_TAG "t_ability_red_tag" +#define TRAIT_ABILITY_YELLOW_TAG "t_ability_yellow_tag" +#define TRAIT_ABILITY_SHED_SPIKES "t_ability_shed_spikes" #define TRAIT_ABILITY_ENCLOSED_PLATES "t_ability_enclosed_plates" -/// Used by shielder for reflective plates. #define TRAIT_ABILITY_REFLECTIVE_PLATES "t_ability_reflective_plates" diff --git a/code/modules/mob/living/carbon/xenomorph/Evolution.dm b/code/modules/mob/living/carbon/xenomorph/Evolution.dm index be3e34808fef..8aa84e3b9a06 100644 --- a/code/modules/mob/living/carbon/xenomorph/Evolution.dm +++ b/code/modules/mob/living/carbon/xenomorph/Evolution.dm @@ -285,7 +285,7 @@ GLOBAL_LIST_EMPTY(deevolved_ckeys) to_chat(src, SPAN_WARNING("We must be at full health to evolve.")) return FALSE - if(agility || fortify || crest_defense || stealth || HAS_TRAIT(src, TRAIT_ABILITY_ENCLOSED_PLATES) || HAS_TRAIT(src, TRAIT_ABILITY_REFLECTIVE_PLATES)) + if(agility || fortify || crest_defense || HAS_TRAIT(src, TRAIT_ABILITY_INVIS) || HAS_TRAIT(src, TRAIT_ABILITY_ENCLOSED_PLATES) || HAS_TRAIT(src, TRAIT_ABILITY_REFLECTIVE_PLATES)) to_chat(src, SPAN_WARNING("We cannot evolve while in this stance.")) return FALSE @@ -324,7 +324,7 @@ GLOBAL_LIST_EMPTY(deevolved_ckeys) if(tier == 0 || tier == 4) to_chat(src, SPAN_XENOWARNING("We can't transmute.")) return - if(agility || fortify || crest_defense || stealth) + if(agility || fortify || crest_defense || HAS_TRAIT(src, TRAIT_ABILITY_INVIS)) to_chat(src, SPAN_XENOWARNING("We can't transmute while in this stance.")) return if(lock_evolve) diff --git a/code/modules/mob/living/carbon/xenomorph/XenoAttacks.dm b/code/modules/mob/living/carbon/xenomorph/XenoAttacks.dm index 816ba1fb8c7f..51bd4e859fef 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoAttacks.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoAttacks.dm @@ -24,6 +24,9 @@ if(..()) return TRUE + if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + return + switch(M.a_intent) if(INTENT_HELP) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index 923d19bb26cc..db86dd20ff42 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -294,9 +294,7 @@ // ////////////////////////////////////////////////////////////////// - var/tunnel = FALSE /// for check on lurker invisibility - var/stealth = FALSE var/fortify = FALSE var/crest_defense = FALSE /// 0/FALSE - upright, 1/TRUE - all fours @@ -365,14 +363,6 @@ // Vars that should be deleted // ////////////////////////////////////////////////////////////////// - var/burrow_timer = 200 - var/tunnel_timer = 20 - - //Burrower Vars - var/used_tremor = 0 - // Burrowers - var/used_burrow = 0 - var/used_tunnel = 0 //Taken from update_icon for all xeno's var/list/overlays_standing[X_TOTAL_LAYERS] @@ -830,7 +820,7 @@ return TRUE playsound(puller.loc, 'sound/weapons/pierce.ogg', 25, 1) puller.visible_message(SPAN_WARNING("[puller] tried to pull [src] but instead gets a tail swipe to the head!")) - if(stealth) + if(HAS_TRAIT(src, TRAIT_ABILITY_INVIS)) puller.apply_effect(caste.tacklestrength_min, WEAKEN) return FALSE puller.apply_effect(rand(caste.tacklestrength_min,caste.tacklestrength_max), WEAKEN) @@ -857,7 +847,22 @@ pulledby.stop_pulling() . = 1 +/mob/living/carbon/xenomorph/proc/rename_tunnel(obj/structure/tunnel/tunnel_target in oview(1)) + set name = "Rename Tunnel" + set desc = "Rename the tunnel." + set category = null + + if(!istype(tunnel_target)) + return + var/new_name = strip_html(input("Change the description of the tunnel:", "Tunnel Description") as text|null) + new_name = replace_non_alphanumeric_plus(new_name) + if(new_name) + new_name = "[new_name] ([get_area_name(tunnel_target)])" + log_admin("[key_name(src)] has renamed the tunnel \"[tunnel_target.tunnel_desc]\" as \"[new_name]\".") + msg_admin_niche("[src]/([key_name(src)]) has renamed the tunnel \"[tunnel_target.tunnel_desc]\" as \"[new_name]\".") + tunnel_target.tunnel_desc = "[new_name]" + return /mob/living/carbon/xenomorph/prepare_huds() ..() diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/burrower/burrower_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/burrower/burrower_abilities.dm index 0ea27be28d18..cceb74d8b38c 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/burrower/burrower_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/burrower/burrower_abilities.dm @@ -8,16 +8,22 @@ action_type = XENO_ACTION_CLICK ability_primacy = XENO_PRIMARY_ACTION_3 -/datum/action/xeno_action/activable/burrow/use_ability(atom/A) - var/mob/living/carbon/xenomorph/xenomorph = owner + var/used_digging = FALSE + var/digging_timer = 2 SECONDS + var/burrow_timer = 20 SECONDS - if(!action_cooldown_check()) - return + var/burrow_cooldown = 2 SECONDS + var/digging_cooldown = 7 SECONDS - if(HAS_TRAIT(xenomorph, TRAIT_ABILITY_BURROWED)) - xenomorph.tunnel(get_turf(A)) +/datum/action/xeno_action/activable/burrow/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + + XENO_ACTION_CHECK(xeno) + + if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) + digging(get_turf(target_atom)) else - xenomorph.burrow() + burrow() return ..() /datum/action/xeno_action/onclick/tremor 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..99f8a67f1723 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 @@ -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 @@ -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 diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_abilities.dm index 5991ac7fde8b..57ffa766ebc7 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_abilities.dm @@ -173,6 +173,9 @@ action_type = XENO_ACTION_CLICK ability_primacy = XENO_TAIL_STAB + var/blunt_damage = 8 // How much damage Harpoon Tail on DISARM mode do. (pierces armor) + var/tail_mode = null // Harpoon Tail mode, used only to display in status. + /datum/action/xeno_action/activable/prae_impale name = "Impale" action_icon_state = "prae_impale" @@ -198,6 +201,11 @@ var/speed_buff_amount = 0.5 var/afterimage_interval = 1 DECISECONDS + var/dodge_start_time = -1 // Used to countdown DANCER_DODGE_TIME. + var/refund_multiplier = 2.0 // How much refund we want to get back? 1.0 is 1s used to 1s cooldown, 2.0 is 1s used 2s cooldown. + var/recharge_time = null // Used in calculation, finalized number will be displayed as cooldown. + var/safe_click_cooldown = 0 // Cooldown after activation to prevent accidental double click. + /datum/action/xeno_action/activable/prae_tail_trip name = "Tail Trip" action_icon_state = "prae_tail_trip" diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_abilities.dm index c676fff61826..e730b656c8db 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_abilities.dm @@ -149,4 +149,7 @@ var/ammo_type = /datum/ammo/xeno/bone_chips/spread var/shrapnel_amount = 40 + var/shard_lock_duration = 15 SECONDS + var/shard_lock_speed_mod = 0.45 + diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_abilities.dm index 528dc9767a13..158cf0a43da4 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_abilities.dm @@ -38,6 +38,7 @@ macro_path = /datum/action/xeno_action/verb/verb_acider_acid ability_primacy = XENO_PRIMARY_ACTION_1 action_type = XENO_ACTION_CLICK + var/acid_cost = 100 /datum/action/xeno_action/activable/acider_for_the_hive @@ -46,4 +47,19 @@ macro_path = /datum/action/xeno_action/verb/verb_acider_sacrifice action_type = XENO_ACTION_CLICK ability_primacy = XENO_PRIMARY_ACTION_2 + var/minimal_acid = 200 + var/caboom_timer = 20 + var/caboom_left = 20 + var/caboom_loop = 1 + + var/caboom_left_display = 20 SECONDS + + var/caboom_trigger + var/caboom_last_proc + var/list/caboom_sound = list('sound/effects/runner_charging_1.ogg','sound/effects/runner_charging_2.ogg') + + var/caboom_acid_ratio = 200 + var/caboom_burn_damage_ratio = 5 + var/caboom_burn_range_ratio = 100 + var/caboom_struct_acid_type = /obj/effect/xenomorph/acid diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_powers.dm index 3cdbe7be7c8c..5e33127aacbb 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_powers.dm @@ -25,252 +25,3 @@ apply_cooldown() return ..() - - -/datum/action/xeno_action/activable/acider_acid/use_ability(atom/affected_atom) - var/mob/living/carbon/xenomorph/xeno = owner - if(!istype(affected_atom, /obj/item) && !istype(affected_atom, /obj/structure/) && !istype(affected_atom, /obj/vehicle/multitile)) - to_chat(xeno, SPAN_XENOHIGHDANGER("Can only melt barricades and items!")) - return - var/datum/behavior_delegate/runner_acider/behavior_delegate = xeno.behavior_delegate - if (!istype(behavior_delegate)) - return - if(behavior_delegate.acid_amount < acid_cost) - to_chat(xeno, SPAN_XENOHIGHDANGER("Not enough acid stored!")) - return - - xeno.corrosive_acid(affected_atom, acid_type, 0) - for(var/obj/item/explosive/plastic/plastic_explosive in affected_atom.contents) - xeno.corrosive_acid(plastic_explosive, acid_type, 0) - return ..() - -/mob/living/carbon/xenomorph/runner/corrosive_acid(atom/affected_atom, acid_type, plasma_cost) - if(!istype(strain, /datum/xeno_strain/acider)) - return ..() - if(!affected_atom.Adjacent(src)) - if(istype(affected_atom,/obj/item/explosive/plastic)) - var/obj/item/explosive/plastic/plastic_explosive = affected_atom - if(plastic_explosive.plant_target && !plastic_explosive.plant_target.Adjacent(src)) - to_chat(src, SPAN_WARNING("We can't reach [affected_atom].")) - return - else - to_chat(src, SPAN_WARNING("[affected_atom] is too far away.")) - return - - if(!isturf(loc) || HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - to_chat(src, SPAN_WARNING("We can't melt [affected_atom] from here!")) - return - - face_atom(affected_atom) - - var/wait_time = 10 - - var/turf/turf = get_turf(affected_atom) - - for(var/obj/effect/xenomorph/acid/acid in turf) - if(acid_type == acid.type && acid.acid_t == affected_atom) - to_chat(src, SPAN_WARNING("[affected_atom] is already drenched in acid.")) - return - - var/obj/object - //OBJ CHECK - if(isobj(affected_atom)) - object = affected_atom - - wait_time = object.get_applying_acid_time() - if(wait_time == -1) - to_chat(src, SPAN_WARNING("We cannot dissolve [object].")) - return - else - to_chat(src, SPAN_WARNING("We cannot dissolve [affected_atom].")) - return - wait_time = wait_time / 4 - if(!do_after(src, wait_time, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) - return - - // AGAIN BECAUSE SOMETHING COULD'VE ACIDED THE PLACE - for(var/obj/effect/xenomorph/acid/acid in turf) - if(acid_type == acid.type && acid.acid_t == affected_atom) - to_chat(src, SPAN_WARNING("[affected_atom] is already drenched in acid.")) - return - - if(!check_state()) - return - - if(!affected_atom || QDELETED(affected_atom)) //Some logic. - return - - if(!affected_atom.Adjacent(src) || (object && !isturf(object.loc)))//not adjacent or inside something - if(istype(affected_atom, /obj/item/explosive/plastic)) - var/obj/item/explosive/plastic/plastic_explosive = affected_atom - if(plastic_explosive.plant_target && !plastic_explosive.plant_target.Adjacent(src)) - to_chat(src, SPAN_WARNING("We can't reach [affected_atom].")) - return - else - to_chat(src, SPAN_WARNING("[affected_atom] is too far away.")) - return - - var/datum/behavior_delegate/runner_acider/behavior_del = behavior_delegate - if (!istype(behavior_del)) - return - if(behavior_del.acid_amount < behavior_del.melt_acid_cost) - to_chat(src, SPAN_XENOHIGHDANGER("Not enough acid stored!")) - return - - behavior_del.modify_acid(-behavior_del.melt_acid_cost) - - var/obj/effect/xenomorph/acid/acid = new acid_type(turf, affected_atom) - - if(istype(affected_atom, /obj/vehicle/multitile)) - var/obj/vehicle/multitile/multitile_vehicle = affected_atom - multitile_vehicle.take_damage_type(20 / acid.acid_delay, "acid", src) - visible_message(SPAN_XENOWARNING("[src] vomits globs of vile stuff at [multitile_vehicle]. It sizzles under the bubbling mess of acid!"), - SPAN_XENOWARNING("We vomit globs of vile stuff at [multitile_vehicle]. It sizzles under the bubbling mess of acid!"), null, 5) - playsound(loc, "sound/bullets/acid_impact1.ogg", 25) - QDEL_IN(acid, 20) - return - - acid.add_hiddenprint(src) - acid.name += " ([affected_atom])" - - visible_message(SPAN_XENOWARNING("[src] vomits globs of vile stuff all over [affected_atom]. It begins to sizzle and melt under the bubbling mess of acid!"), - SPAN_XENOWARNING("We vomit globs of vile stuff all over [affected_atom]. It begins to sizzle and melt under the bubbling mess of acid!"), null, 5) - playsound(loc, "sound/bullets/acid_impact1.ogg", 25) - -#define ACIDER_ACID_LEVEL 3 - -/mob/living/carbon/xenomorph/runner/try_fill_trap(obj/effect/alien/resin/trap/target) - if(!istype(strain, /datum/xeno_strain/acider)) - return ..() - - if(!istype(target)) - return FALSE - - var/datum/behavior_delegate/runner_acider/behavior_del = behavior_delegate - if(!istype(behavior_del)) - return FALSE - - if(behavior_del.acid_amount < behavior_del.fill_acid_cost) - to_chat(src, SPAN_XENOHIGHDANGER("Not enough acid stored!")) - return FALSE - - var/trap_acid_level = 0 - if(target.trap_type >= RESIN_TRAP_ACID1) - trap_acid_level = 1 + target.trap_type - RESIN_TRAP_ACID1 - - if(trap_acid_level >= ACIDER_ACID_LEVEL) // Acid runners apply /obj/effect/xenomorph/acid/strong generally - to_chat(src, SPAN_XENONOTICE("It already has good acid in.")) - return FALSE - - to_chat(src, SPAN_XENONOTICE("You begin charging the resin trap with acid.")) - xeno_attack_delay(src) - if(!do_after(src, 3 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE, src)) - return FALSE - - if(target.trap_type >= RESIN_TRAP_ACID1) - trap_acid_level = 1 + target.trap_type - RESIN_TRAP_ACID1 - - if(trap_acid_level >= ACIDER_ACID_LEVEL) - return FALSE - - if(behavior_del.acid_amount < behavior_del.fill_acid_cost) - to_chat(src, SPAN_XENOHIGHDANGER("Not enough acid stored!")) - return FALSE - - behavior_del.modify_acid(-behavior_del.fill_acid_cost) - - target.cause_data = create_cause_data("resin acid trap", src) - target.setup_tripwires() - target.set_state(RESIN_TRAP_ACID1 + ACIDER_ACID_LEVEL - 1) - - playsound(target, 'sound/effects/refill.ogg', 25, 1) - visible_message(SPAN_XENOWARNING("[src] pressurises the resin trap with acid!"), - SPAN_XENOWARNING("You pressurise the resin trap with acid!"), null, 5) - return TRUE - -#undef ACIDER_ACID_LEVEL - -/datum/action/xeno_action/activable/acider_for_the_hive/use_ability(atom/affected_atom) - var/mob/living/carbon/xenomorph/xeno = owner - - if(!istype(xeno)) - return - - if(!isturf(xeno.loc)) - to_chat(xeno, SPAN_XENOWARNING("It is too cramped in here to activate this!")) - return - - var/area/xeno_area = get_area(xeno) - if(xeno_area.flags_area & AREA_CONTAINMENT) - to_chat(xeno, SPAN_XENOWARNING("We can't activate this here!")) - return - - if(!xeno.check_state()) - return - - if(!action_cooldown_check()) - return - - var/datum/behavior_delegate/runner_acider/behavior_delegate = xeno.behavior_delegate - if(!istype(behavior_delegate)) - return - - if(behavior_delegate.caboom_trigger) - cancel_ability() - return - - if(behavior_delegate.acid_amount < minimal_acid) - to_chat(xeno, SPAN_XENOWARNING("Not enough acid built up for an explosion.")) - return - - notify_ghosts(header = "For the Hive!", message = "[xeno] is going to explode for the Hive!", source = xeno, action = NOTIFY_ORBIT) - - to_chat(xeno, SPAN_XENOWARNING("Our stomach starts turning and twisting, getting ready to compress the built up acid.")) - xeno.color = "#22FF22" - xeno.set_light_color("#22FF22") - xeno.set_light_range(3) - - behavior_delegate.caboom_trigger = TRUE - behavior_delegate.caboom_left = behavior_delegate.caboom_timer - behavior_delegate.caboom_last_proc = 0 - xeno.set_effect(behavior_delegate.caboom_timer*2, SUPERSLOW) - - START_PROCESSING(SSfasteffects, src) - - xeno.say(";FOR THE HIVE!!!") - return ..() - -/datum/action/xeno_action/activable/acider_for_the_hive/proc/cancel_ability() - var/mob/living/carbon/xenomorph/xeno = owner - if(!istype(xeno)) - return - var/datum/behavior_delegate/runner_acider/behavior_delegate = xeno.behavior_delegate - if(!istype(behavior_delegate)) - return - - behavior_delegate.caboom_trigger = FALSE - xeno.color = null - xeno.set_light_range(0) - behavior_delegate.modify_acid(-behavior_delegate.max_acid / 4) - - // Done this way rather than setting to 0 in case something else slowed us - // -Original amount set - (time exploding + timer inaccuracy) * how much gets removed per tick / 2 - xeno.adjust_effect(behavior_delegate.caboom_timer * -2 - (behavior_delegate.caboom_timer - behavior_delegate.caboom_left + 2) * xeno.life_slow_reduction * 0.5, SUPERSLOW) - - to_chat(xeno, SPAN_XENOWARNING("We remove all our explosive acid before it combusted.")) - - STOP_PROCESSING(SSfasteffects, src) - button.set_maptext() - -/datum/action/xeno_action/activable/acider_for_the_hive/process(delta_time) - return update_caboom_maptext() - -/datum/action/xeno_action/activable/acider_for_the_hive/proc/update_caboom_maptext() - var/mob/living/carbon/xenomorph/xeno = owner - var/datum/behavior_delegate/runner_acider/delegate = xeno.behavior_delegate - if(!istype(delegate) || !delegate.caboom_trigger || delegate.caboom_left <= 0) - button.set_maptext() - return PROCESS_KILL - - button.set_maptext(SMALL_FONTS_COLOR(7, delegate.caboom_left, "#e69d00"), 19, 2) - return diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm b/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm index d2cd1e661556..855b4ac468de 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm @@ -13,12 +13,16 @@ var/cooldown_message = null var/no_cooldown_msg = FALSE - var/cooldown_timer_id = TIMER_ID_NULL // holds our timer ID + var/cooldown_timer_id = TIMER_ID_NULL // holds cooldown timer ID // Track state so we can effectively REDUCE xeno_cooldown by removing and replacing timers. var/current_cooldown_start_time = 0 var/current_cooldown_duration = 0 + var/duration_timer_id = TIMER_ID_NULL // holds duration timer ID + var/current_duration_start_time = 0 + var/current_duration_duration = 0 + // Charging /// When set, an ability has to be charged up by being the active ability before it can be used var/charge_time = null @@ -43,6 +47,9 @@ . = ..() /datum/action/xeno_action/process(delta_time) + if(duration_timer_id != TIMER_ID_NULL) + return update_duration_visual() + return update_cooldown_visual() /datum/action/xeno_action/proc/remove_charge() @@ -472,13 +479,39 @@ if(action_start_message) to_chat(owner, SPAN_NOTICE(action_start_message)) +///Use to display duration time of active ability. +/datum/action/xeno_action/proc/start_duration_display(duration) + if(duration_timer_id != TIMER_ID_NULL) + deltimer(duration_timer_id) + + duration_timer_id = addtimer(CALLBACK(src, PROC_REF(end_duration_display)), duration, TIMER_STOPPABLE) + + current_duration_start_time = world.time + current_duration_duration = duration + + START_PROCESSING(SSfasteffects, src) + +///Use to stop display duration time of active ability. +/datum/action/xeno_action/proc/end_duration_display() + duration_timer_id = TIMER_ID_NULL + current_duration_start_time = 0 + current_duration_duration = 0 + + update_button_icon() + +/datum/action/xeno_action/proc/update_duration_visual() + var/time_left = max(current_duration_start_time + current_duration_duration - world.time, 0) + if(!owner || time_left <= 0 || duration_timer_id == TIMER_ID_NULL) + button.set_maptext() + return PROCESS_KILL + button.set_maptext(SMALL_FONTS(7, round(time_left/10, 0.1)), 4, 4) + /datum/action/xeno_action/proc/update_cooldown_visual() var/time_left = max(current_cooldown_start_time + current_cooldown_duration - world.time, 0) if(!owner || time_left <= 0 || cooldown_timer_id == TIMER_ID_NULL) button.set_maptext() return PROCESS_KILL - else - button.set_maptext(SMALL_FONTS(7, round(time_left/10, 0.1)), 4, 4) + button.set_maptext(SMALL_FONTS_COLOR(7, round(time_left/10, 0.1), "#fffb00"), 4, 4) /datum/action/xeno_action/proc/on_select(mob/user) return diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm index f3837947db9f..ff3df8481f5c 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm @@ -28,9 +28,6 @@ tacklestrength_min = 4 tacklestrength_max = 5 - burrow_cooldown = 2 SECONDS - tunnel_cooldown = 7 SECONDS - minimum_evolve_time = 7 MINUTES minimap_icon = "burrower" @@ -85,249 +82,219 @@ skull = /obj/item/skull/burrower pelt = /obj/item/pelt/burrower -/mob/living/carbon/xenomorph/burrower/ex_act(severity, direction, datum/cause_data/cause_data, pierce=0, enviro=FALSE) - if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - return - ..() - -/mob/living/carbon/xenomorph/burrower/attack_hand() - if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - return - ..() - -/mob/living/carbon/xenomorph/burrower/attackby() - if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - return - . = ..() - -/mob/living/carbon/xenomorph/burrower/get_projectile_hit_chance() - . = ..() - if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - return 0 - /datum/behavior_delegate/burrower_base name = "Base Burrower Behavior Delegate" -//Burrower Abilities -/mob/living/carbon/xenomorph/proc/burrow() - if(!check_state()) +/datum/action/xeno_action/activable/burrow/proc/burrow() + var/mob/living/carbon/xenomorph/xeno = owner + + XENO_ACTION_CHECK(xeno) + + if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_UNDERGROUND) || HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING)) return - if(used_burrow || tunnel || is_ventcrawling || action_busy) + if(xeno.is_ventcrawling || xeno.action_busy) return - var/turf/current_turf = get_turf(src) + var/turf/current_turf = get_turf(xeno) if(!current_turf) return var/area/current_area = get_area(current_turf) if(current_area.flags_area & AREA_NOBURROW) - to_chat(src, SPAN_XENOWARNING("There's no way to burrow here.")) + to_chat(xeno, SPAN_XENOWARNING("There's no way to burrow here.")) return if(istype(current_turf, /turf/open/floor/almayer/research/containment) || istype(current_turf, /turf/closed/wall/almayer/research/containment)) - to_chat(src, SPAN_XENOWARNING("We can't escape this cell!")) + to_chat(xeno, SPAN_XENOWARNING("We can't escape this cell!")) return - if(clone) //Prevents burrowing on stairs - to_chat(src, SPAN_XENOWARNING("We can't burrow here!")) + if(xeno.clone) //Prevents burrowing on stairs + to_chat(xeno, SPAN_XENOWARNING("We can't burrow here!")) return - if(caste_type && GLOB.xeno_datum_list[caste_type]) - caste = GLOB.xeno_datum_list[caste_type] + if(xeno.caste_type && GLOB.xeno_datum_list[xeno.caste_type]) + xeno.caste = GLOB.xeno_datum_list[xeno.caste_type] - used_burrow = TRUE + ADD_TRAIT(xeno, TRAIT_ABILITY_BURROW_UNDERGROUND, TRAIT_SOURCE_ABILITY("burrow_underground")) - to_chat(src, SPAN_XENOWARNING("We begin burrowing ourselves into the ground.")) - if(!do_after(src, 1.5 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) - addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), (caste ? caste.burrow_cooldown : 5 SECONDS)) + to_chat(xeno, SPAN_XENOWARNING("We begin burrowing ourselves into the ground.")) + if(!do_after(xeno, 1.5 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) + addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), burrow_cooldown) return // TODO Make immune to all damage here. - to_chat(src, SPAN_XENOWARNING("We burrow ourselves into the ground.")) - QDEL_NULL(observed_atom) - invisibility = 101 - alpha = 100 - anchored = TRUE + to_chat(xeno, SPAN_XENOWARNING("We burrow ourselves into the ground.")) + QDEL_NULL(xeno.observed_atom) + xeno.invisibility = 101 + xeno.alpha = 100 + xeno.anchored = TRUE - var/mob/living/carbon/human/hauled = hauled_mob?.resolve() + var/mob/living/carbon/human/hauled = xeno.hauled_mob?.resolve() if(hauled) - hauled.forceMove(src) + hauled.forceMove(xeno) - add_traits(list(TRAIT_ABILITY_BURROWED, TRAIT_UNDENSE, TRAIT_IMMOBILIZED), TRAIT_SOURCE_ABILITY("Burrow")) - playsound(src.loc, 'sound/effects/burrowing_b.ogg', 25) - update_icons() - addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), (caste ? caste.burrow_cooldown : 5 SECONDS)) + xeno.add_traits(list(TRAIT_ABILITY_BURROWED, TRAIT_UNDENSE, TRAIT_IMMOBILIZED), TRAIT_SOURCE_ABILITY("Burrow")) + playsound(xeno.loc, 'sound/effects/burrowing_b.ogg', 25) + xeno.update_icons() + start_duration_display(10 SECONDS) + addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), burrow_cooldown) burrow_timer = world.time + 90 // How long we can be burrowed process_burrow() -/mob/living/carbon/xenomorph/proc/process_burrow() - if(!HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) +/datum/action/xeno_action/activable/burrow/proc/process_burrow() + var/mob/living/carbon/xenomorph/xeno = owner + + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) return - if(world.time > burrow_timer && !tunnel) + if(world.time > burrow_timer && !HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING)) burrow_off() - if(observed_xeno) - overwatch(observed_xeno, TRUE) - if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + if(xeno.observed_xeno) + xeno.overwatch(xeno.observed_xeno, TRUE) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) addtimer(CALLBACK(src, PROC_REF(process_burrow)), 1 SECONDS) -/mob/living/carbon/xenomorph/proc/burrow_off() - if(caste_type && GLOB.xeno_datum_list[caste_type]) - caste = GLOB.xeno_datum_list[caste_type] - to_chat(src, SPAN_NOTICE("You resurface.")) - remove_traits(list(TRAIT_ABILITY_BURROWED, TRAIT_UNDENSE, TRAIT_IMMOBILIZED), TRAIT_SOURCE_ABILITY("Burrow")) - invisibility = FALSE - alpha = initial(alpha) - anchored = FALSE +/datum/action/xeno_action/activable/burrow/proc/burrow_off() + var/mob/living/carbon/xenomorph/xeno = owner + + to_chat(xeno, SPAN_NOTICE("You resurface.")) + xeno.remove_traits(list(TRAIT_ABILITY_BURROWED, TRAIT_UNDENSE, TRAIT_IMMOBILIZED), TRAIT_SOURCE_ABILITY("Burrow")) + xeno.invisibility = FALSE + xeno.alpha = initial(xeno.alpha) + xeno.anchored = FALSE + end_duration_display() - var/mob/living/carbon/human/hauled = hauled_mob?.resolve() + var/mob/living/carbon/human/hauled = xeno.hauled_mob?.resolve() if(hauled) - hauled.forceMove(loc) + hauled.forceMove(xeno.loc) - playsound(loc, 'sound/effects/burrowoff.ogg', 25) - for(var/mob/living/carbon/mob in loc) - if(!can_not_harm(mob)) + playsound(xeno.loc, 'sound/effects/burrowoff.ogg', 25) + for(var/mob/living/carbon/mob in xeno.loc) + if(!xeno.can_not_harm(mob)) mob.apply_effect(1.5, WEAKEN) - addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), (caste ? caste.burrow_cooldown : 5 SECONDS)) - update_icons() + addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), burrow_cooldown) + xeno.update_icons() -/mob/living/carbon/xenomorph/proc/do_burrow_cooldown() - used_burrow = FALSE - if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - to_chat(src, SPAN_NOTICE("We can now surface.")) - for(var/X in actions) - var/datum/action/act = X - act.update_button_icon() +/datum/action/xeno_action/activable/burrow/proc/do_burrow_cooldown() + var/mob/living/carbon/xenomorph/xeno = owner + + REMOVE_TRAIT(xeno, TRAIT_ABILITY_BURROW_UNDERGROUND, TRAIT_SOURCE_ABILITY("burrow_underground")) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) + to_chat(xeno, SPAN_NOTICE("We can now surface.")) + update_button_icon() -/mob/living/carbon/xenomorph/proc/tunnel(turf/target) - if(!check_state()) - return - if(!HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - to_chat(src, SPAN_NOTICE("We must be burrowed to do this.")) +/datum/action/xeno_action/activable/burrow/proc/digging(turf/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + + XENO_ACTION_CHECK(xeno) + + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) + to_chat(xeno, SPAN_NOTICE("We must be burrowed to do this.")) return - if(tunnel) - tunnel = FALSE - to_chat(src, SPAN_NOTICE("We stop tunneling.")) - used_tunnel = TRUE - addtimer(CALLBACK(src, PROC_REF(do_tunnel_cooldown)), (caste ? caste.tunnel_cooldown : 5 SECONDS)) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING)) + REMOVE_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING, TRAIT_SOURCE_ABILITY("burrow_digging")) + to_chat(xeno, SPAN_NOTICE("We stop tunneling.")) + used_digging = TRUE + addtimer(CALLBACK(src, PROC_REF(do_digging_cooldown)), digging_cooldown) return - if(used_tunnel) - to_chat(src, SPAN_NOTICE("We must wait some time to do this.")) + if(used_digging) + to_chat(xeno, SPAN_NOTICE("We must wait some time to do this.")) return - if(!target) - to_chat(src, SPAN_NOTICE("We can't tunnel there!")) + if(!target_atom) + to_chat(xeno, SPAN_NOTICE("We can't tunnel there!")) return - if(target.density) - to_chat(src, SPAN_XENOWARNING("We can't tunnel into a solid wall!")) + if(target_atom.density) + to_chat(xeno, SPAN_XENOWARNING("We can't tunnel into a solid wall!")) return - if(istype(target, /turf/open/space)) - to_chat(src, SPAN_XENOWARNING("We make tunnels, not wormholes!")) + if(istype(target_atom, /turf/open/space)) + to_chat(xeno, SPAN_XENOWARNING("We make tunnels, not wormholes!")) return - if(clone) //Prevents tunnels in Z transition areas - to_chat(src, SPAN_XENOWARNING("We make tunnels, not wormholes!")) + if(xeno.clone) //Prevents tunnels in Z transition areas + to_chat(xeno, SPAN_XENOWARNING("We make tunnels, not wormholes!")) return - var/area/area_to_get = get_area(target) - if(area_to_get.flags_area & AREA_NOBURROW || get_dist(src, target) > 15) - to_chat(src, SPAN_XENOWARNING("There's no way to tunnel over there.")) + var/area/area_to_get = get_area(target_atom) + if(area_to_get.flags_area & AREA_NOBURROW || get_dist(xeno, target_atom) > 15) + to_chat(xeno, SPAN_XENOWARNING("There's no way to tunnel over there.")) return - for(var/obj/objects_in_turf in target.contents) + for(var/obj/objects_in_turf in target_atom.contents) if(objects_in_turf.density) if(objects_in_turf.flags_atom & ON_BORDER) continue - to_chat(src, SPAN_WARNING("There's something solid there to stop us from emerging.")) + to_chat(xeno, SPAN_WARNING("There's something solid there to stop us from emerging.")) return - if(!target || target.density) - to_chat(src, SPAN_NOTICE("We cannot tunnel to there!")) - tunnel = TRUE - to_chat(src, SPAN_NOTICE("We start tunneling!")) - var/target_distance = max(get_dist(src, target), 1) // Min distance of 1 is to prevent stunlocking - tunnel_timer = (target_distance*10) + world.time - process_tunnel(target) + if(!target_atom || target_atom.density) + to_chat(xeno, SPAN_NOTICE("We cannot tunnel to there!")) + ADD_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING, TRAIT_SOURCE_ABILITY("burrow_digging")) + to_chat(xeno, SPAN_NOTICE("We start tunneling!")) + var/target_distance = max(get_dist(xeno, target_atom), 1) // Min distance of 1 is to prevent stunlocking + digging_timer = (target_distance * 10) + world.time + process_digging(target_atom) +/datum/action/xeno_action/activable/burrow/proc/process_digging(turf/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner -/mob/living/carbon/xenomorph/proc/process_tunnel(turf/target) - if(!tunnel) + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING)) return - if(world.time > tunnel_timer) - tunnel = FALSE - do_tunnel(target) - if(tunnel && target) - addtimer(CALLBACK(src, PROC_REF(process_tunnel), target), 1 SECONDS) + if(world.time > digging_timer) + REMOVE_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING, TRAIT_SOURCE_ABILITY("burrow_digging")) + do_digging(target_atom) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING) && target_atom) + addtimer(CALLBACK(src, PROC_REF(process_digging), target_atom), 1 SECONDS) -/mob/living/carbon/xenomorph/proc/do_tunnel(turf/target) - to_chat(src, SPAN_NOTICE("We tunnel to the destination.")) - anchored = FALSE - forceMove(target) - burrow_off() +/datum/action/xeno_action/activable/burrow/proc/do_digging(turf/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner -/mob/living/carbon/xenomorph/proc/do_tunnel_cooldown() - used_tunnel = FALSE - to_chat(src, SPAN_NOTICE("We can now tunnel while burrowed.")) - for(var/X in actions) - var/datum/action/act = X - act.update_button_icon() + to_chat(xeno, SPAN_NOTICE("We tunnel to the destination.")) + xeno.anchored = FALSE + xeno.forceMove(target_atom) + end_duration_display() + burrow_off() -/mob/living/carbon/xenomorph/proc/rename_tunnel(obj/structure/tunnel/tunnel_target in oview(1)) - set name = "Rename Tunnel" - set desc = "Rename the tunnel." - set category = null +/datum/action/xeno_action/activable/burrow/proc/do_digging_cooldown() + var/mob/living/carbon/xenomorph/xeno = owner - if(!istype(tunnel_target)) - return + used_digging = FALSE + to_chat(xeno, SPAN_NOTICE("We can now tunnel while burrowed.")) + update_button_icon() - var/new_name = strip_html(input("Change the description of the tunnel:", "Tunnel Description") as text|null) - new_name = replace_non_alphanumeric_plus(new_name) - if(new_name) - new_name = "[new_name] ([get_area_name(tunnel_target)])" - log_admin("[key_name(src)] has renamed the tunnel \"[tunnel_target.tunnel_desc]\" as \"[new_name]\".") - msg_admin_niche("[src]/([key_name(src)]) has renamed the tunnel \"[tunnel_target.tunnel_desc]\" as \"[new_name]\".") - tunnel_target.tunnel_desc = "[new_name]" - return -/datum/action/xeno_action/onclick/tremor/use_ability(atom/target) - var/mob/living/carbon/xenomorph/burrower_tremor = owner - if(HAS_TRAIT(burrower_tremor, TRAIT_ABILITY_BURROWED)) - to_chat(burrower_tremor, SPAN_XENOWARNING("We must be above ground to do this.")) - return +/datum/action/xeno_action/onclick/tremor/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner - if(burrower_tremor.is_ventcrawling) - to_chat(burrower_tremor, SPAN_XENOWARNING("We must be above ground to do this.")) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) + to_chat(xeno, SPAN_XENOWARNING("We must be above ground to do this.")) return - if(!action_cooldown_check()) + if(xeno.is_ventcrawling) + to_chat(xeno, SPAN_XENOWARNING("We must be above ground to do this.")) return - if(!burrower_tremor.check_state()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) - if(!check_and_use_plasma_owner()) - return + playsound(xeno, 'sound/effects/alien_footstep_charge3.ogg', 75, 0) + to_chat(xeno, SPAN_XENOWARNING("We dig ourselves into the ground and cause tremors.")) + xeno.create_stomp() - playsound(burrower_tremor, 'sound/effects/alien_footstep_charge3.ogg', 75, 0) - to_chat(burrower_tremor, SPAN_XENOWARNING("We dig ourselves into the ground and cause tremors.")) - burrower_tremor.create_stomp() - - - for(var/mob/living/carbon/carbon_target in range(7, burrower_tremor)) + for(var/mob/living/carbon/carbon_target in range(7, xeno)) to_chat(carbon_target, SPAN_WARNING("You struggle to remain on your feet as the ground shakes beneath your feet!")) shake_camera(carbon_target, 2, 3) - if(get_dist(burrower_tremor, carbon_target) <= 3 && !burrower_tremor.can_not_harm(carbon_target)) + if(get_dist(xeno, carbon_target) <= 3 && !xeno.can_not_harm(carbon_target)) if(carbon_target.mob_size >= MOB_SIZE_BIG) carbon_target.apply_effect(1, SLOW) else @@ -337,96 +304,97 @@ apply_cooldown() return ..() -/datum/action/xeno_action/onclick/build_tunnel/use_ability(atom/A) - var/mob/living/carbon/xenomorph/xenomorph = owner - if(!xenomorph.check_state()) - return - if(xenomorph.action_busy) - to_chat(xenomorph, SPAN_XENOWARNING("We should finish up what we're doing before digging.")) + +/datum/action/xeno_action/onclick/build_tunnel/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + + XENO_ACTION_CHECK(xeno) + + if(xeno.action_busy) + to_chat(xeno, SPAN_XENOWARNING("We should finish up what we're doing before digging.")) return - var/turf/turf = xenomorph.loc + var/turf/turf = xeno.loc if(!istype(turf)) //logic - to_chat(xenomorph, SPAN_XENOWARNING("We can't do that from there.")) + to_chat(xeno, SPAN_XENOWARNING("We can't do that from there.")) return var/area/current_area = get_area(turf) if(!turf.can_dig_xeno_tunnel() || !is_ground_level(turf.z) || current_area.flags_area & AREA_NOTUNNEL) - to_chat(xenomorph, SPAN_XENOWARNING("We scrape around, but we can't seem to dig through that kind of floor.")) + to_chat(xeno, SPAN_XENOWARNING("We scrape around, but we can't seem to dig through that kind of floor.")) return - if(locate(/obj/structure/tunnel) in xenomorph.loc) - to_chat(xenomorph, SPAN_XENOWARNING("There already is a tunnel here.")) + if(locate(/obj/structure/tunnel) in xeno.loc) + to_chat(xeno, SPAN_XENOWARNING("There already is a tunnel here.")) return - if(locate(/obj/structure/machinery/sentry_holder/landing_zone) in xenomorph.loc) - to_chat(xenomorph, SPAN_XENOWARNING("We can't dig a tunnel with this object in the way.")) + if(locate(/obj/structure/machinery/sentry_holder/landing_zone) in xeno.loc) + to_chat(xeno, SPAN_XENOWARNING("We can't dig a tunnel with this object in the way.")) return - if(xenomorph.tunnel_delay) - to_chat(xenomorph, SPAN_XENOWARNING("We are not ready to dig a tunnel again.")) + if(xeno.tunnel_delay) + to_chat(xeno, SPAN_XENOWARNING("We are not ready to dig a tunnel again.")) return - if(xenomorph.get_active_hand()) - to_chat(xenomorph, SPAN_XENOWARNING("We need an empty claw for this!")) + if(xeno.get_active_hand()) + to_chat(xeno, SPAN_XENOWARNING("We need an empty claw for this!")) return - if(!xenomorph.check_plasma(plasma_cost)) + if(!xeno.check_plasma(plasma_cost)) return - var/area/AR = get_area(turf) + var/area/target_area = get_area(turf) - if(isnull(AR) || !(AR.is_resin_allowed)) - if(!AR || AR.flags_area & AREA_UNWEEDABLE) - to_chat(xenomorph, SPAN_XENOWARNING("This area is unsuited to host the hive!")) + if(isnull(target_area) || !(target_area.is_resin_allowed)) + if(!target_area || target_area.flags_area & AREA_UNWEEDABLE) + to_chat(xeno, SPAN_XENOWARNING("This area is unsuited to host the hive!")) return - to_chat(xenomorph, SPAN_XENOWARNING("It's too early to spread the hive this far.")) + to_chat(xeno, SPAN_XENOWARNING("It's too early to spread the hive this far.")) return - xenomorph.visible_message(SPAN_XENONOTICE("[xenomorph] begins digging out a tunnel entrance."), + xeno.visible_message(SPAN_XENONOTICE("[xeno] begins digging out a tunnel entrance."), SPAN_XENONOTICE("We begin digging out a tunnel entrance."), null, 5) - if(!do_after(xenomorph, 10 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) - to_chat(xenomorph, SPAN_WARNING("Our tunnel caves in as we stop digging it.")) + if(!do_after(xeno, 10 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) + to_chat(xeno, SPAN_WARNING("Our tunnel caves in as we stop digging it.")) return - if(!xenomorph.check_plasma(plasma_cost)) + if(!xeno.check_plasma(plasma_cost)) return - xenomorph.visible_message(SPAN_XENONOTICE("\The [xenomorph] digs out a tunnel entrance."), + xeno.visible_message(SPAN_XENONOTICE("\The [xeno] digs out a tunnel entrance."), SPAN_XENONOTICE("We dig out an entrance to the tunnel network."), null, 5) - var/obj/structure/tunnel/tunnelobj = new(turf, xenomorph.hivenumber) - xenomorph.tunnel_delay = 1 - addtimer(CALLBACK(src, PROC_REF(cooldown_end)), 4 MINUTES) + var/obj/structure/tunnel/tunnelobj = new(turf, xeno.hivenumber) + xeno.tunnel_delay = 1 + addtimer(CALLBACK(xeno, PROC_REF(cooldown_end)), 4 MINUTES) var/msg = strip_html(input("Add a description to the tunnel:", "Tunnel Description") as text|null) msg = replace_non_alphanumeric_plus(msg) var/description if(msg) description = msg msg = "[msg] ([get_area_name(tunnelobj)])" - log_admin("[key_name(xenomorph)] has named a new tunnel \"[msg]\".") - msg_admin_niche("[xenomorph]/([key_name(xenomorph)]) has named a new tunnel \"[msg]\".") + log_admin("[key_name(xeno)] has named a new tunnel \"[msg]\".") + msg_admin_niche("[xeno]/([key_name(xeno)]) has named a new tunnel \"[msg]\".") tunnelobj.tunnel_desc = "[msg]" - if(xenomorph.hive.living_xeno_queen || xenomorph.hive.allow_no_queen_actions) - for(var/mob/living/carbon/xenomorph/target_for_message as anything in xenomorph.hive.totalXenos) + if(xeno.hive.living_xeno_queen || xeno.hive.allow_no_queen_actions) + for(var/mob/living/carbon/xenomorph/target_for_message as anything in xeno.hive.totalXenos) var/overwatch_target = XENO_OVERWATCH_TARGET_HREF var/overwatch_src = XENO_OVERWATCH_SRC_HREF - to_chat(target_for_message, SPAN_XENOANNOUNCE("Hive: A new tunnel[description ? " ([description])" : ""] has been created by [xenomorph] (watch) at [get_area_name(tunnelobj)].")) + to_chat(target_for_message, SPAN_XENOANNOUNCE("Hive: A new tunnel[description ? " ([description])" : ""] has been created by [xeno] (watch) at [get_area_name(tunnelobj)].")) - xenomorph.use_plasma(plasma_cost) - to_chat(xenomorph, SPAN_NOTICE("We will be ready to dig a new tunnel in 4 minutes.")) - playsound(xenomorph.loc, 'sound/weapons/pierce.ogg', 25, 1) + xeno.use_plasma(plasma_cost) + to_chat(xeno, SPAN_NOTICE("We will be ready to dig a new tunnel in 4 minutes.")) + playsound(xeno.loc, 'sound/weapons/pierce.ogg', 25, 1) apply_cooldown() return ..() - /datum/action/xeno_action/onclick/build_tunnel/proc/cooldown_end() - var/mob/living/carbon/xenomorph/xenomorph = owner - to_chat(xenomorph, SPAN_NOTICE("We are ready to dig a tunnel again.")) - xenomorph.tunnel_delay = 0 + var/mob/living/carbon/xenomorph/xeno = owner + to_chat(xeno, SPAN_NOTICE("We are ready to dig a tunnel again.")) + xeno.tunnel_delay = 0 -/mob/living/carbon/xenomorph/burrower/try_fill_trap(obj/effect/alien/resin/trap/target) +/mob/living/carbon/xenomorph/burrower/try_fill_trap(obj/effect/alien/resin/trap/target_trap) . = ..() if(.) - target.set_state(RESIN_TRAP_ACID3) + target_trap.set_state(RESIN_TRAP_ACID3) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm index 9bd5e35cb8e3..2fe8a89b80ae 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm @@ -71,28 +71,18 @@ /datum/behavior_delegate/lurker_base name = "Base Lurker Behavior Delegate" - // Config - var/invis_recharge_time = 20 SECONDS - 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 @@ -103,15 +93,19 @@ 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 @@ -119,69 +113,19 @@ ..() 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() - - // Invisible - if(invis_start_time != -1) - var/time_left = (invis_duration-(world.time - 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) - return - - if(!bound_xeno.client?.prefs.show_cooldown_messages) - return - - // Recharged - if(lurker_invisibility_action.cooldown_timer_id == TIMER_ID_NULL) - . += "Invisibility Recharge: Ready." - return - - // Recharging - var/time_left = timeleft(lurker_invisibility_action.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) @@ -195,7 +139,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)) @@ -229,19 +172,17 @@ var/mob/living/carbon/xenomorph/xeno = owner return xeno.deselect_timer < world.time // We clicked the same ability in a very short time -/datum/action/xeno_action/onclick/lurker_invisibility/use_ability(atom/targeted_atom) +/datum/action/xeno_action/onclick/lurker_invisibility/use_ability() var/mob/living/carbon/xenomorph/xeno = owner 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 ..() @@ -252,14 +193,26 @@ 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 + start_duration_display(invis_duration) + /// 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 @@ -268,7 +221,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) @@ -283,39 +240,41 @@ 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 + + apply_cooldown_override(invis_recharge_time) + end_duration_display() + + 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 - behavior.on_invisibility_off() +/datum/action/xeno_action/onclick/lurker_invisibility/proc/decloak_handler() + 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) to_chat(owner, SPAN_XENOHIGHDANGER("We are ready to use our invisibility again!")) ..() -/datum/action/xeno_action/onclick/lurker_assassinate/use_ability(atom/targeted_atom) +/datum/action/xeno_action/onclick/lurker_assassinate/use_ability() 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!")) @@ -327,13 +286,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!")) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm b/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm index 4fe0425c410f..21373622e1e7 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm @@ -68,35 +68,32 @@ skull = /obj/item/skull/spitter pelt = /obj/item/pelt/spitter -/datum/action/xeno_action/onclick/charge_spit/use_ability(atom/A) - var/mob/living/carbon/xenomorph/zenomorf = owner +/datum/action/xeno_action/onclick/charge_spit/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner - if (!action_cooldown_check()) + if(!istype(xeno)) return - if (!istype(zenomorf) || !zenomorf.check_state()) + if(buffs_active) + to_chat(xeno, SPAN_XENOHIGHDANGER("We cannot stack this!")) return - if (buffs_active) - to_chat(zenomorf, SPAN_XENOHIGHDANGER("We cannot stack this!")) - return - - if (!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) - to_chat(zenomorf, SPAN_XENOHIGHDANGER("We accumulate acid in your glands. Our next spit will be stronger but shorter-ranged.")) - to_chat(zenomorf, SPAN_XENOWARNING("Additionally, we are slightly faster and more armored for a small amount of time.")) - zenomorf.create_custom_empower(icolor = "#93ec78", ialpha = 200, small_xeno = TRUE) - zenomorf.balloon_alert(zenomorf, "our next spit will be stronger", text_color = "#93ec78") + to_chat(xeno, SPAN_XENOHIGHDANGER("We accumulate acid in your glands. Our next spit will be stronger but shorter-ranged.")) + to_chat(xeno, SPAN_XENOWARNING("Additionally, we are slightly faster and more armored for a small amount of time.")) + xeno.create_custom_empower(icolor = "#93ec78", ialpha = 200, small_xeno = TRUE) + xeno.balloon_alert(xeno, "our next spit will be stronger", text_color = "#93ec78") buffs_active = TRUE - zenomorf.ammo = GLOB.ammo_list[/datum/ammo/xeno/acid/spatter] // shitcode is my city - zenomorf.speed_modifier -= speed_buff_amount - zenomorf.armor_modifier += armor_buff_amount - zenomorf.recalculate_speed() - zenomorf.recalculate_armor() + xeno.ammo = GLOB.ammo_list[/datum/ammo/xeno/acid/spatter] // shitcode is my city + xeno.speed_modifier -= speed_buff_amount + xeno.armor_modifier += armor_buff_amount + xeno.recalculate_speed() + xeno.recalculate_armor() + start_duration_display(duration) /// Though the ability's other buffs are supposed to last for its duration, it's only supposed to enhance one spit. - RegisterSignal(zenomorf, COMSIG_XENO_POST_SPIT, PROC_REF(disable_spatter)) + RegisterSignal(xeno, COMSIG_XENO_POST_SPIT, PROC_REF(disable_spatter)) addtimer(CALLBACK(src, PROC_REF(remove_effects)), duration) @@ -105,28 +102,29 @@ /datum/action/xeno_action/onclick/charge_spit/proc/disable_spatter() SIGNAL_HANDLER - var/mob/living/carbon/xenomorph/zenomorf = owner - if(zenomorf.ammo == GLOB.ammo_list[/datum/ammo/xeno/acid/spatter]) - to_chat(zenomorf, SPAN_XENOWARNING("Our acid glands empty out and return back to normal. We will once more fire long-ranged weak spits.")) - zenomorf.balloon_alert(zenomorf, "our spits are back to normal", text_color = "#93ec78") - zenomorf.ammo = GLOB.ammo_list[/datum/ammo/xeno/acid] // el codigo de mierda es mi ciudad - UnregisterSignal(zenomorf, COMSIG_XENO_POST_SPIT) + var/mob/living/carbon/xenomorph/xeno = owner + if(xeno.ammo == GLOB.ammo_list[/datum/ammo/xeno/acid/spatter]) + to_chat(xeno, SPAN_XENOWARNING("Our acid glands empty out and return back to normal. We will once more fire long-ranged weak spits.")) + xeno.balloon_alert(xeno, "our spits are back to normal", text_color = "#93ec78") + xeno.ammo = GLOB.ammo_list[/datum/ammo/xeno/acid] // el codigo de mierda es mi ciudad + UnregisterSignal(xeno, COMSIG_XENO_POST_SPIT) + end_duration_display() /datum/action/xeno_action/onclick/charge_spit/proc/remove_effects() - var/mob/living/carbon/xenomorph/zenomorf = owner + var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(zenomorf)) + if(!istype(xeno)) return - zenomorf.speed_modifier += speed_buff_amount - zenomorf.armor_modifier -= armor_buff_amount - zenomorf.recalculate_speed() - zenomorf.recalculate_armor() - to_chat(zenomorf, SPAN_XENOHIGHDANGER("We feel our movement speed slow down!")) + xeno.speed_modifier += speed_buff_amount + xeno.armor_modifier -= armor_buff_amount + xeno.recalculate_speed() + xeno.recalculate_armor() + to_chat(xeno, SPAN_XENOHIGHDANGER("We feel our movement speed slow down!")) disable_spatter() buffs_active = FALSE -/datum/action/xeno_action/activable/tail_stab/spitter/use_ability(atom/A) +/datum/action/xeno_action/activable/tail_stab/spitter/use_ability(atom/target_atom) var/target = ..() if(iscarbon(target)) var/mob/living/carbon/carbon_target = target diff --git a/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm b/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm index f3bcd560ed8b..b9a4facaaa36 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm @@ -103,8 +103,6 @@ /// if fire_immunity is set to be vulnerable, how much will fire damage be multiplied. Defines in xeno.dm var/fire_vulnerability_mult = 0 - var/burrow_cooldown = 5 SECONDS - var/tunnel_cooldown = 10 SECONDS ///whether the xeno heals even outside weeds. var/innate_healing = FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm index d59ad11f8eb0..9c875e53c930 100644 --- a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm +++ b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm @@ -1,4 +1,6 @@ /mob/living/carbon/xenomorph/attackby(obj/item/item, mob/user) + if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + return if(user.a_intent != INTENT_HELP) return ..() if(HAS_TRAIT(item, TRAIT_TOOL_MULTITOOL) && ishuman(user)) @@ -45,6 +47,8 @@ return ..() /mob/living/carbon/xenomorph/ex_act(severity, direction, datum/cause_data/cause_data, pierce=0, enviro=FALSE) + if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + return if(body_position == LYING_DOWN && direction) severity *= EXPLOSION_PRONE_MULTIPLIER diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm index 50957326b920..e5bac1e92e0c 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm @@ -22,7 +22,6 @@ defender.recalculate_stats() - // Steel crest override /datum/action/xeno_action/activable/fortify/steel_crest/apply_modifiers(mob/living/carbon/xenomorph/xeno, fortify_state) if(fortify_state) @@ -37,26 +36,20 @@ xeno.damage_modifier += XENO_DAMAGE_MOD_SMALL -/datum/action/xeno_action/onclick/soak/use_ability(atom/A) - var/mob/living/carbon/xenomorph/steelcrest = owner - - if (!action_cooldown_check()) - return - - if (!steelcrest.check_state()) - return +/datum/action/xeno_action/onclick/soak/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) - RegisterSignal(steelcrest, COMSIG_MOB_TAKE_DAMAGE, PROC_REF(damage_accumulate)) + RegisterSignal(xeno, COMSIG_MOB_TAKE_DAMAGE, PROC_REF(damage_accumulate)) addtimer(CALLBACK(src, PROC_REF(stop_accumulating)), 6 SECONDS) + start_duration_display(6 SECONDS) - steelcrest.balloon_alert(steelcrest, "begins to tank incoming damage!") + xeno.balloon_alert(xeno, "begins to tank incoming damage!") - to_chat(steelcrest, SPAN_XENONOTICE("We begin to tank incoming damage!")) + to_chat(xeno, SPAN_XENONOTICE("We begin to tank incoming damage!")) - steelcrest.add_filter("steelcrest_enraging", 1, list("type" = "outline", "color" = "#421313", "size" = 1)) + xeno.add_filter("steelcrest_enraging", 1, list("type" = "outline", "color" = "#421313", "size" = 1)) apply_cooldown() return ..() @@ -74,23 +67,26 @@ /datum/action/xeno_action/onclick/soak/proc/stop_accumulating() UnregisterSignal(owner, COMSIG_MOB_TAKE_DAMAGE) + end_duration_display() damage_accumulated = 0 to_chat(owner, SPAN_XENONOTICE("We stop taking incoming damage.")) owner.remove_filter("steelcrest_enraging") /datum/action/xeno_action/onclick/soak/proc/enraged() + end_duration_display() owner.remove_filter("steelcrest_enraging") owner.add_filter("steelcrest_enraged", 1, list("type" = "outline", "color" = "#ad1313", "size" = 1)) - owner.visible_message(SPAN_XENOWARNING("[owner] gets enraged after being damaged enough!"), SPAN_XENOWARNING("We feel enraged after taking in oncoming damage! Our tail slam's cooldown is reset and we heal!")) + owner.visible_message(SPAN_XENOWARNING("[owner] gets enraged and their carapace start to rapidly mend!"), SPAN_XENOWARNING("We feel enraged after taking in oncoming damage! Our tail slam's cooldown is reset and our carapace start to rapidly mend!")) + owner.flick_heal_overlay(3 SECONDS, "#00B800") - var/mob/living/carbon/xenomorph/enraged_mob = owner - enraged_mob.gain_health(75) // pretty reasonable amount of health recovered + var/mob/living/carbon/xenomorph/xeno = owner + xeno.gain_health(75) // pretty reasonable amount of health recovered // Check actions list for tail slam and reset it's cooldown if it's there var/datum/action/xeno_action/activable/tail_stab/slam/slam_action = locate() in owner.actions - if (slam_action && !slam_action.action_cooldown_check()) + if(slam_action && !slam_action.action_cooldown_check()) slam_action.end_cooldown() diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm index 616418396fad..46e5455ac9c5 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm @@ -45,28 +45,6 @@ /// How much time is left on timer. (used for status) var/time_left = null - /// Check for slashed target that had yellow tag - var/spread_slash_triggered = FALSE - - /// How many targets got yellow tag. - var/spread_count = 0 - - /// How much damage Harpoon Tail on DISARM mode do. (pierces armor) - var/blunt_damage = 8 - /// Harpoon Tail mode, used only to display in status. - var/tail_mode = null - - /// Is Dodge ability active? - var/dodge_activated = FALSE - /// Used to countdown DANCER_DODGE_TIME. - var/dodge_start_time = -1 - /// How much refund we want to get back? 1.0 is 1s used to 1s cooldown, 2.0 is 1s used 2s cooldown. - var/refund_multiplier = 2.0 - /// Used in calculation, finalized number will be displayed as cooldown. - var/recharge_time = null - /// Cooldown after activation to prevent accidental double click. - var/safe_click_cooldown = 0 - /// Timer to prevent dancer from spreading yellow tags. var/last_dancer_spread_time = 0 @@ -74,23 +52,27 @@ . = list() . += "Guaranteed Dodge every [bound_xeno.dodge_threshold] bullet\s." . += "Yellow Tag Spread Delay: 5 seconds." - intent_detection() - . += "Tail Lance Intent: [tail_mode]" - if(tail_mode == "Blunt") - . += "Damage: [blunt_damage] AP" + + var/datum/action/xeno_action/activable/tail_stab/harpoon_tail/harpoon_action = get_action(bound_xeno, /datum/action/xeno_action/activable/tail_stab/harpoon_tail) + harpoon_action.intent_detection() + . += "Tail Lance Intent: [harpoon_action.tail_mode]" + if(harpoon_action.tail_mode == "Blunt") + . += "Damage: [harpoon_action.blunt_damage] AP" . += "Cooldown: 3 seconds." - if(dodge_start_time != -1) - time_left = (DANCER_DODGE_TIME - (world.time - dodge_start_time)) / 10 + + var/datum/action/xeno_action/onclick/prae_dodge/dodge_action = get_action(bound_xeno, /datum/action/xeno_action/onclick/prae_dodge) + if(dodge_action.dodge_start_time != -1) + time_left = (DANCER_DODGE_TIME - (world.time - dodge_action.dodge_start_time)) / 10 . += "Dodge Remaining: [time_left] second\s." return /datum/behavior_delegate/praetorian_dancer/melee_attack_additional_effects_self() ..() - if(!spread_slash_triggered) + if(!HAS_TRAIT(bound_xeno, TRAIT_ABILITY_YELLOW_TAG)) return - spread_slash_triggered = FALSE + REMOVE_TRAIT(bound_xeno, TRAIT_ABILITY_YELLOW_TAG, TRAIT_SOURCE_ABILITY("yellow_tag")) var/datum/action/xeno_action/activable/prae_impale/impale_action = get_action(bound_xeno, /datum/action/xeno_action/activable/prae_impale) if(!impale_action.action_cooldown_check()) @@ -121,30 +103,30 @@ break if(consumed_spread) - spread_slash_triggered = TRUE + ADD_TRAIT(bound_xeno, TRAIT_ABILITY_YELLOW_TAG, TRAIT_SOURCE_ABILITY("yellow_tag")) if(target_carbon.health <= 0) try_spread_tags_from(target_carbon) -/datum/behavior_delegate/praetorian_dancer/proc/try_spread_tags_from(mob/living/carbon/human/source) - if(!ishuman(source)) +/datum/behavior_delegate/praetorian_dancer/proc/try_spread_tags_from(mob/living/carbon/human/target_human) + if(!ishuman(target_human)) return - var/turf/origin = get_turf(source) + var/turf/origin = get_turf(target_human) if(!origin) return if(world.time < last_dancer_spread_time + DANCER_YELLOW_TAG_SPREAD_DURATION) return - if(world.time < source.last_target_spread_time + DANCER_YELLOW_TAG_SPREAD_CD) + if(world.time < target_human.last_target_spread_time + DANCER_YELLOW_TAG_SPREAD_CD) return - source.last_target_spread_time = world.time + target_human.last_target_spread_time = world.time var/spread_count = 0 for(var/mob/living/carbon/human/human_target in view(DANCER_YELLOW_TAG_SPREAD_DIST)) - if(human_target == source) + if(human_target == target_human) continue if(human_target.stat == DEAD || human_target.stat == UNCONSCIOUS) continue @@ -164,95 +146,92 @@ if(spread_count >= 0) to_chat(bound_xeno, SPAN_XENOHIGHDANGER("Fear spreads among the prey, their weakness fuels your instincts to strike them down!")) -/datum/behavior_delegate/praetorian_dancer/proc/intent_detection() - if(bound_xeno && bound_xeno.a_intent == INTENT_DISARM) - tail_mode = "Blunt" - else - tail_mode = "Normal" -/datum/action/xeno_action/activable/tail_stab/harpoon_tail/ability_act(mob/living/carbon/xenomorph/xeno, mob/living/carbon/target, obj/limb/limb) - if(!istype(xeno) || !istype(target)) - return - var/datum/behavior_delegate/praetorian_dancer/behavior = xeno.behavior_delegate - if(!istype(behavior)) +/datum/action/xeno_action/activable/tail_stab/harpoon_tail/ability_act(mob/living/carbon/xenomorph/xeno, mob/living/carbon/target_carbon, obj/limb/limb) + if(!istype(xeno) || !istype(target_carbon)) return if(xeno.a_intent == INTENT_DISARM) - target.last_damage_data = create_cause_data(initial(xeno.caste_type), xeno) + target_carbon.last_damage_data = create_cause_data(initial(xeno.caste_type), xeno) xeno.visible_message( - SPAN_XENOWARNING("[xeno] smash [target] with flat side of its tail!"), - SPAN_XENOWARNING("We smash [target] with flat side of our tail!") + SPAN_XENOWARNING("[xeno] smash [target_carbon] with flat side of its tail!"), + SPAN_XENOWARNING("We smash [target_carbon] with flat side of our tail!") ) - xeno.animation_attack_on(target) - xeno.flick_attack_overlay(target, "slam") + xeno.animation_attack_on(target_carbon) + xeno.flick_attack_overlay(target_carbon, "slam") if(xeno.behavior_delegate) - xeno.behavior_delegate.melee_attack_additional_effects_target(target) + xeno.behavior_delegate.melee_attack_additional_effects_target(target_carbon) - playsound(target, "punch", 25, TRUE) - target.apply_damage(behavior.blunt_damage, BRUTE, "chest") + playsound(target_carbon, "punch", 25, TRUE) + target_carbon.apply_damage(blunt_damage, BRUTE, "chest") apply_cooldown(cooldown_modifier = 0.3) update_button_icon() - return target + return target_carbon return ..() -/datum/action/xeno_action/activable/prae_impale/use_ability(atom/target_atom) - var/mob/living/carbon/xenomorph/dancer_user = owner +/datum/action/xeno_action/activable/tail_stab/harpoon_tail/proc/intent_detection() + var/mob/living/carbon/xenomorph/xeno = owner + if(xeno && xeno.a_intent == INTENT_DISARM) + tail_mode = "Blunt" + else + tail_mode = "Normal" - if(!action_cooldown_check()) - return - if(!dancer_user.check_state()) - return + + +/datum/action/xeno_action/activable/prae_impale/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + + XENO_ACTION_CHECK(xeno) if(!ismob(target_atom)) apply_cooldown_override(impale_click_miss_cooldown) update_button_icon() return - if(!isxeno_human(target_atom) || dancer_user.can_not_harm(target_atom)) - to_chat(dancer_user, SPAN_XENODANGER("We must target a hostile!")) + if(!isxeno_human(target_atom) || xeno.can_not_harm(target_atom)) + to_chat(xeno, SPAN_XENODANGER("We must target a hostile!")) return var/mob/living/carbon/target_carbon = target_atom if(target_carbon.stat == DEAD) - to_chat(dancer_user, SPAN_XENOWARNING("[target_atom] is dead, why would we want to attack it?")) + to_chat(xeno, SPAN_XENOWARNING("[target_atom] is dead, why would we want to attack it?")) return - var/dist = get_dist(dancer_user, target_carbon) + var/dist = get_dist(xeno, target_carbon) if(dist > range) - to_chat(dancer_user, SPAN_WARNING("[target_carbon] is too far away!")) + to_chat(xeno, SPAN_WARNING("[target_carbon] is too far away!")) return if(dist > 1) - var/turf/target_turf = get_step(dancer_user, get_dir(dancer_user, target_carbon)) + var/turf/target_turf = get_step(xeno, get_dir(xeno, target_carbon)) if(target_turf.density) - to_chat(dancer_user, SPAN_WARNING("We can't attack through [target_turf]!")) + to_chat(xeno, SPAN_WARNING("We can't attack through [target_turf]!")) return else for(var/atom/atom_in_turf in target_turf) if(atom_in_turf.density && !atom_in_turf.throwpass && !istype(atom_in_turf, /obj/structure/barricade) && !istype(atom_in_turf, /mob/living)) - to_chat(dancer_user, SPAN_WARNING("We can't attack through [atom_in_turf]!")) + to_chat(xeno, SPAN_WARNING("We can't attack through [atom_in_turf]!")) return - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) apply_cooldown() - var/buffed = FALSE + REMOVE_TRAIT(xeno, TRAIT_ABILITY_RED_TAG, TRAIT_SOURCE_ABILITY("red_tag")) for(var/datum/effects/dancer_tag/spread/tag_spread in target_carbon.effects_list) - buffed = TRUE + ADD_TRAIT(xeno, TRAIT_ABILITY_RED_TAG, TRAIT_SOURCE_ABILITY("red_tag")) qdel(tag_spread) apply_cooldown_override() break for(var/datum/effects/dancer_tag/normal/dancer_tag_effect in target_carbon.effects_list) - buffed = TRUE + ADD_TRAIT(xeno, TRAIT_ABILITY_RED_TAG, TRAIT_SOURCE_ABILITY("red_tag")) qdel(dancer_tag_effect) break @@ -260,72 +239,64 @@ var/mob/living/carbon/human/human_target = target_carbon human_target.update_xeno_hostile_hud() - // Hmm today visible_message(SPAN_DANGER("\The [dancer_user] violently slices [target_atom] with its tail[buffed?" twice":""]!"), - dancer_user.face_atom(target_atom) - - var/damage = get_xeno_damage_slash(target_carbon, rand(dancer_user.melee_damage_lower, dancer_user.melee_damage_upper)) + // Hmm today visible_message(SPAN_DANGER("\The [xeno] violently slices [target_atom] with its tail[buffed?" twice":""]!"), + xeno.face_atom(target_atom) - dancer_user.visible_message(SPAN_DANGER("\The [dancer_user] violently slices [target_atom] with its tail[buffed?" twice":""]!"), + var/damage = get_xeno_damage_slash(target_carbon, rand(xeno.melee_damage_lower, xeno.melee_damage_upper)) + var/buffed = HAS_TRAIT(xeno, TRAIT_ABILITY_RED_TAG) + xeno.visible_message(SPAN_DANGER("\The [xeno] violently slices [target_atom] with its tail[buffed?" twice":""]!"), SPAN_DANGER("We slice [target_atom] with our tail[buffed?" twice":""]!")) - var/list/attack_data = list( - "attacker" = dancer_user, - "target" = target_carbon, - "damage" = damage - ) - impale_strike(attack_data) + impale_strike(xeno, target_carbon, damage) if(buffed) - dancer_user.emote("roar") // Feedback for the player that we got the magic double impale - addtimer(CALLBACK(src, PROC_REF(impale_strike), attack_data), 4 DECISECONDS) + xeno.emote("roar") // Feedback for the player that we got the magic double impale + addtimer(CALLBACK(src, PROC_REF(impale_strike), xeno, target_carbon, damage), 4 DECISECONDS) return ..() -/datum/action/xeno_action/activable/prae_impale/proc/impale_strike(list/attack_data) - var/mob/living/carbon/xenomorph/attacker = attack_data["attacker"] - var/mob/living/carbon/target = attack_data["target"] - var/damage = attack_data["damage"] - if(!attacker || !target || target.stat == DEAD || QDELETED(attacker) || QDELETED(target)) + +/datum/action/xeno_action/activable/prae_impale/proc/impale_strike(mob/living/carbon/xenomorph/xeno, mob/living/carbon/target_carbon, damage) + if(!xeno || !target_carbon || target_carbon.stat == DEAD || QDELETED(xeno) || QDELETED(target_carbon)) return - attacker.animation_attack_on(target) - attacker.flick_attack_overlay(target, "tail") + xeno.animation_attack_on(target_carbon) + xeno.flick_attack_overlay(target_carbon, "tail") - target.last_damage_data = create_cause_data(initial(attacker.caste_type), attacker) - target.apply_armoured_damage(damage, ARMOR_MELEE, BRUTE, "chest", 10) - playsound(target, 'sound/weapons/alien_tail_attack.ogg', 30, TRUE) + target_carbon.last_damage_data = create_cause_data(initial(xeno.caste_type), xeno) + target_carbon.apply_armoured_damage(damage, ARMOR_MELEE, BRUTE, "chest", 10) + playsound(target_carbon, 'sound/weapons/alien_tail_attack.ogg', 30, TRUE) -/datum/action/xeno_action/onclick/prae_dodge/use_ability(atom/target) - var/mob/living/carbon/xenomorph/dodge_user = owner - if(!istype(dodge_user) || !dodge_user.check_state()) - return - var/datum/behavior_delegate/praetorian_dancer/behavior = dodge_user.behavior_delegate - if(!istype(behavior)) + +/datum/action/xeno_action/onclick/prae_dodge/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(xeno)) return - if(behavior.dodge_activated) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_DODGE)) remove_effects() return - if(!action_cooldown_check()) - return + XENO_ACTION_CHECK(xeno) if(!check_and_use_plasma_owner(200)) return - behavior.dodge_activated = TRUE - behavior.dodge_start_time = world.time - behavior.safe_click_cooldown = world.time + 1 SECONDS + ADD_TRAIT(xeno, TRAIT_ABILITY_DODGE, TRAIT_SOURCE_ABILITY("dodge")) + dodge_start_time = world.time + safe_click_cooldown = world.time + 1 SECONDS button.icon_state = "template_active" - dodge_user.speed_modifier -= speed_buff_amount - dodge_user.dodge_threshold -= 3 - dodge_user.add_temp_pass_flags(PASS_MOB_THRU) - dodge_user.recalculate_speed() - dodge_user.balloon_alert(dodge_user, "we start our evasive stance!", text_color = "#7d32bb", delay = 1 SECONDS) + xeno.speed_modifier -= speed_buff_amount + xeno.dodge_threshold -= 3 + xeno.add_temp_pass_flags(PASS_MOB_THRU) + xeno.recalculate_speed() + xeno.balloon_alert(xeno, "we start our evasive stance!", text_color = "#7d32bb", delay = 1 SECONDS) + + start_duration_display(duration) - INVOKE_ASYNC(src, PROC_REF(create_afterimage_sequence), dodge_user, duration) + INVOKE_ASYNC(src, PROC_REF(create_afterimage_sequence), xeno, duration) if(dodge_timer != TIMER_ID_NULL) deltimer(dodge_timer) @@ -335,51 +306,49 @@ return ..() /datum/action/xeno_action/onclick/prae_dodge/proc/remove_effects() - var/mob/living/carbon/xenomorph/dodge_remove = owner - if(!istype(dodge_remove)) - return - - var/datum/behavior_delegate/praetorian_dancer/behavior = dodge_remove.behavior_delegate - if(!istype(behavior)) + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(xeno)) return - if(!behavior.dodge_activated) + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_DODGE)) return - if(world.time < behavior.safe_click_cooldown) - to_chat(dodge_remove, SPAN_XENOWARNING("We need a moment before breaking our evasive stance!")) + if(world.time < safe_click_cooldown) + to_chat(xeno, SPAN_XENOWARNING("We need a moment before breaking our evasive stance!")) return - behavior.dodge_activated = FALSE + REMOVE_TRAIT(xeno, TRAIT_ABILITY_DODGE, TRAIT_SOURCE_ABILITY("dodge")) button.icon_state = "template_xeno" - dodge_remove.speed_modifier += speed_buff_amount - dodge_remove.dodge_threshold += 3 - dodge_remove.remove_temp_pass_flags(PASS_MOB_THRU) - dodge_remove.recalculate_speed() - dodge_remove.reset_position_to_initial() - dodge_remove.balloon_alert(dodge_remove, "our evasive stance fades", text_color = "#bb5d32", delay = 1 SECONDS) + xeno.speed_modifier += speed_buff_amount + xeno.dodge_threshold += 3 + xeno.remove_temp_pass_flags(PASS_MOB_THRU) + xeno.recalculate_speed() + xeno.reset_position_to_initial() + xeno.balloon_alert(xeno, "our evasive stance fades", text_color = "#bb5d32", delay = 1 SECONDS) + + end_duration_display() if(dodge_timer != TIMER_ID_NULL) deltimer(dodge_timer) dodge_timer = TIMER_ID_NULL - if(behavior.dodge_start_time > 0) - var/used_ratio = round((world.time - behavior.dodge_start_time) / duration, 0.1) - behavior.recharge_time = max(DANCER_DODGE_TIME * used_ratio * behavior.refund_multiplier, 5 SECONDS) + if(dodge_start_time > 0) + var/used_ratio = round((world.time - dodge_start_time) / duration, 0.1) + recharge_time = max(DANCER_DODGE_TIME * used_ratio * refund_multiplier, 5 SECONDS) - behavior.dodge_start_time = -1 - apply_cooldown_override(behavior.recharge_time) + dodge_start_time = -1 + apply_cooldown_override(recharge_time) -/datum/action/xeno_action/onclick/prae_dodge/proc/create_afterimage_sequence(mob/living/carbon/xenomorph/dodge_user, duration) - if(!dodge_user || !dodge_user.loc) +/datum/action/xeno_action/onclick/prae_dodge/proc/create_afterimage_sequence(mob/living/carbon/xenomorph/xeno, duration) + if(!xeno || !xeno.loc) return var/afterimage_count = round(duration / afterimage_interval) var/datum/afterimage_state/state = new - state.owner = dodge_user + state.owner = xeno state.remaining = afterimage_count - state.last_turf = get_turf(dodge_user.loc) + state.last_turf = get_turf(xeno.loc) addtimer(CALLBACK(src, PROC_REF(process_afterimage_tick), state), afterimage_interval) @@ -387,20 +356,19 @@ if(!state || !state.owner || !state.owner.loc) return - var/mob/living/carbon/xenomorph/dodge_user = state.owner - var/datum/behavior_delegate/praetorian_dancer/behavior = dodge_user.behavior_delegate - if(!istype(behavior) || !behavior.dodge_activated) + var/mob/living/carbon/xenomorph/xeno = state.owner + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_DODGE)) return - var/turf/current_position = get_turf(dodge_user.loc) + var/turf/current_position = get_turf(xeno.loc) if(current_position && current_position != state.last_turf) var/random_offset_x = rand(-4, 4) var/random_offset_y = rand(-4, 4) - dodge_user.reset_position_to_initial() - dodge_user.apply_offset(random_offset_x, random_offset_y) + xeno.reset_position_to_initial() + xeno.apply_offset(random_offset_x, random_offset_y) - create_afterimage(dodge_user, random_offset_x, random_offset_y) + create_afterimage(xeno, random_offset_x, random_offset_y) state.last_turf = current_position state.remaining-- @@ -408,20 +376,20 @@ if(state.remaining > 0) addtimer(CALLBACK(src, PROC_REF(process_afterimage_tick), state), afterimage_interval) else - addtimer(CALLBACK(dodge_user, TYPE_PROC_REF(/atom/movable, reset_position_to_initial)), 2 DECISECONDS) + addtimer(CALLBACK(xeno, TYPE_PROC_REF(/atom/movable, reset_position_to_initial)), 2 DECISECONDS) -/datum/action/xeno_action/onclick/prae_dodge/proc/create_afterimage(mob/living/carbon/xenomorph/dodge_user, random_offset_x, random_offset_y) - if(!dodge_user || !dodge_user.loc) +/datum/action/xeno_action/onclick/prae_dodge/proc/create_afterimage(mob/living/carbon/xenomorph/xeno, random_offset_x, random_offset_y) + if(!xeno || !xeno.loc) return - var/turf/afterimage_location = get_turf(dodge_user.loc) + var/turf/afterimage_location = get_turf(xeno.loc) if(!afterimage_location) return var/directional_offset_x = 0 var/directional_offset_y = 0 - switch(dodge_user.dir) + switch(xeno.dir) if(NORTH) directional_offset_y = -16 if(SOUTH) @@ -432,18 +400,20 @@ directional_offset_x = 16 var/obj/effect/overlay/afterimage = new /obj/effect/overlay/afterimage(afterimage_location) - afterimage.icon = dodge_user.icon - afterimage.icon_state = dodge_user.icon_state - afterimage.color = dodge_user.color - afterimage.layer = dodge_user.layer - afterimage.dir = dodge_user.dir + afterimage.icon = xeno.icon + afterimage.icon_state = xeno.icon_state + afterimage.color = xeno.color + afterimage.layer = xeno.layer + afterimage.dir = xeno.dir afterimage.alpha = 200 afterimage.mouse_opacity = MOUSE_OPACITY_TRANSPARENT - afterimage.pixel_x = dodge_user.pixel_x + directional_offset_x - afterimage.pixel_y = dodge_user.pixel_y + directional_offset_y + afterimage.pixel_x = xeno.pixel_x + directional_offset_x + afterimage.pixel_y = xeno.pixel_y + directional_offset_y addtimer(CALLBACK(afterimage, TYPE_PROC_REF(/obj/effect/overlay/afterimage, fade_out_afterimage))) + + /obj/effect/overlay/afterimage/proc/fade_out_afterimage() if(!src) return @@ -484,80 +454,79 @@ var/fade_max_steps = 3 var/fade_delay = 1 DECISECONDS + + /datum/action/xeno_action/activable/prae_tail_trip/use_ability(atom/target_atom) - var/mob/living/carbon/xenomorph/dancer_user = owner + var/mob/living/carbon/xenomorph/xeno = owner - if(!action_cooldown_check()) + if(!istype(xeno)) return - if(!istype(dancer_user) || !dancer_user.check_state()) - return + XENO_ACTION_CHECK(xeno) if(!ismob(target_atom)) apply_cooldown_override(tail_click_miss_cooldown) update_button_icon() return - if(!isxeno_human(target_atom) || dancer_user.can_not_harm(target_atom)) - to_chat(dancer_user, SPAN_XENODANGER("We must target a hostile!")) + if(!isxeno_human(target_atom) || xeno.can_not_harm(target_atom)) + to_chat(xeno, SPAN_XENODANGER("We must target a hostile!")) return var/mob/living/carbon/target_carbon = target_atom if(target_carbon.stat == DEAD) - to_chat(dancer_user, SPAN_XENOWARNING("[target_atom] is dead, why would we want to attack it?")) - return - - if(!check_and_use_plasma_owner()) + to_chat(xeno, SPAN_XENOWARNING("[target_atom] is dead, why would we want to attack it?")) return + XENO_ACTION_CHECK_USE_PLASMA(xeno) if(ishuman(target_carbon)) var/mob/living/carbon/human/target_human = target_carbon target_human.update_xeno_hostile_hud() - var/dist = get_dist(dancer_user, target_carbon) + var/dist = get_dist(xeno, target_carbon) if(dist > range) - to_chat(dancer_user, SPAN_WARNING("[target_carbon] is too far away!")) + to_chat(xeno, SPAN_WARNING("[target_carbon] is too far away!")) return if(dist > 1) - var/turf/target_turf = get_step(dancer_user, get_dir(dancer_user, target_carbon)) + var/turf/target_turf = get_step(xeno, get_dir(xeno, target_carbon)) if(target_turf.density) - to_chat(dancer_user, SPAN_WARNING("We can't attack through [target_turf]!")) + to_chat(xeno, SPAN_WARNING("We can't attack through [target_turf]!")) return else for(var/atom/atom_in_turf in target_turf) if(atom_in_turf.density && !atom_in_turf.throwpass && !istype(atom_in_turf, /obj/structure/barricade) && !istype(atom_in_turf, /mob/living)) - to_chat(dancer_user, SPAN_WARNING("We can't attack through [atom_in_turf]!")) + to_chat(xeno, SPAN_WARNING("We can't attack through [atom_in_turf]!")) return // Hmm today I will kill a marine while looking away from them - dancer_user.face_atom(target_carbon) - dancer_user.flick_attack_overlay(target_carbon, "disarm") + xeno.face_atom(target_carbon) + xeno.flick_attack_overlay(target_carbon, "disarm") - var/buffed = FALSE + REMOVE_TRAIT(xeno, TRAIT_ABILITY_RED_TAG, TRAIT_SOURCE_ABILITY("red_tag")) var/datum/effects/dancer_tag/normal/dancer_tag_effect = locate() in target_carbon.effects_list var/datum/effects/dancer_tag/spread/tag_spread = locate() in target_carbon.effects_list if(tag_spread) - buffed = TRUE + ADD_TRAIT(xeno, TRAIT_ABILITY_RED_TAG, TRAIT_SOURCE_ABILITY("red_tag")) qdel(tag_spread) apply_cooldown_override() if(dancer_tag_effect) - buffed = TRUE + ADD_TRAIT(xeno, TRAIT_ABILITY_RED_TAG, TRAIT_SOURCE_ABILITY("red_tag")) qdel(dancer_tag_effect) - if(!buffed) - new /datum/effects/xeno_slow(target_carbon, dancer_user, null, null, get_xeno_stun_duration(target_carbon, slow_duration)) + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_RED_TAG)) + new /datum/effects/xeno_slow(target_carbon, xeno, null, null, get_xeno_stun_duration(target_carbon, slow_duration)) var/stun_duration = stun_duration_default var/daze_duration = 0 - if(buffed) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_RED_TAG)) stun_duration = stun_duration_buffed daze_duration = daze_duration_buffed @@ -568,20 +537,20 @@ if(Xeno.mob_size >= MOB_SIZE_BIG) xeno_smashed = TRUE shake_camera(Xeno, 10, 1) - dancer_user.visible_message(SPAN_XENODANGER("[dancer_user] smashes [Xeno] with it's tail!"), SPAN_XENODANGER("We smash [Xeno] with your tail!")) - to_chat(Xeno, SPAN_XENOHIGHDANGER("You feel dizzy as [dancer_user] smashes you with their tail!")) - dancer_user.animation_attack_on(Xeno) + xeno.visible_message(SPAN_XENODANGER("[xeno] smashes [Xeno] with it's tail!"), SPAN_XENODANGER("We smash [Xeno] with your tail!")) + to_chat(Xeno, SPAN_XENOHIGHDANGER("You feel dizzy as [xeno] smashes you with their tail!")) + xeno.animation_attack_on(Xeno) if(!xeno_smashed) - if (stun_duration > 0) + if(stun_duration > 0) target_carbon.apply_effect(stun_duration, WEAKEN) - dancer_user.visible_message(SPAN_XENODANGER("[dancer_user] trips [target_atom] with it's tail!"), SPAN_XENODANGER("We trip [target_atom] with our tail!")) - dancer_user.spin_circle() - dancer_user.emote("tail") - to_chat(target_carbon, SPAN_XENOHIGHDANGER("You are swept off your feet by [dancer_user]!")) + xeno.visible_message(SPAN_XENODANGER("[xeno] trips [target_atom] with it's tail!"), SPAN_XENODANGER("We trip [target_atom] with our tail!")) + xeno.spin_circle() + xeno.emote("tail") + to_chat(target_carbon, SPAN_XENOHIGHDANGER("You are swept off your feet by [xeno]!")) if(daze_duration > 0) target_carbon.apply_effect(daze_duration, DAZE) - playsound(dancer_user, 'sound/effects/hit_kick.ogg', 75, 1) + playsound(xeno, 'sound/effects/hit_kick.ogg', 75, 1) apply_cooldown() return ..() diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm index fc04821b63e7..08b55a5c902f 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm @@ -51,17 +51,10 @@ /datum/action/xeno_action/activable/tail_stab/tail_seize/use_ability(atom/targetted_atom) var/mob/living/carbon/xenomorph/stabbing_xeno = owner - if(!action_cooldown_check()) + if(world.time <= stabbing_xeno.next_move) return FALSE - if(!stabbing_xeno.check_state()) - return FALSE - - if (world.time <= stabbing_xeno.next_move) - return FALSE - - if(!check_and_use_plasma_owner()) - return FALSE + XENO_ACTION_CHECK_USE_PLASMA(stabbing_xeno) stabbing_xeno.visible_message(SPAN_XENODANGER("\The [stabbing_xeno] uncoils and wildly throws out its tail!"), SPAN_XENODANGER("We uncoil our tail wildly in front of us!")) @@ -79,27 +72,23 @@ xeno_attack_delay(stabbing_xeno) return ..() -/datum/action/xeno_action/activable/prae_abduct/use_ability(atom/atom) - var/mob/living/carbon/xenomorph/abduct_user = owner +/datum/action/xeno_action/activable/prae_abduct/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner - if(!atom || atom.layer >= FLY_LAYER || !isturf(abduct_user.loc)) + if(!target_atom || target_atom.layer >= FLY_LAYER || !isturf(xeno.loc)) return - if(!action_cooldown_check() || abduct_user.action_busy) + if(xeno.action_busy) return - if(!abduct_user.check_state()) - return - - if(!check_plasma_owner()) - return + XENO_ACTION_CHECK(xeno) // Build our turflist var/list/turf/turflist = list() var/list/telegraph_atom_list = list() - var/facing = get_dir(abduct_user, atom) - var/turf/turf = abduct_user.loc - var/turf/temp = abduct_user.loc + var/facing = get_dir(xeno, target_atom) + var/turf/turf = xeno.loc + var/turf/temp = xeno.loc for(var/distance in 0 to max_distance) temp = get_step(turf, facing) if(facing in GLOB.diagonals) // check if it goes through corners @@ -158,65 +147,72 @@ break turflist += turf - facing = get_dir(turf, atom) + facing = get_dir(turf, target_atom) telegraph_atom_list += new /obj/effect/xenomorph/xeno_telegraph/abduct_hook(turf, windup) if(allow_one_more_step) break if(!length(turflist)) - to_chat(abduct_user, SPAN_XENOWARNING("We don't have any room to do our abduction!")) + to_chat(xeno, SPAN_XENOWARNING("We don't have any room to do our abduction!")) return - abduct_user.visible_message(SPAN_XENODANGER("\The [abduct_user]'s segmented tail starts coiling..."), SPAN_XENODANGER("We begin coiling our tail, aiming towards \the [atom]...")) - abduct_user.emote("roar") + xeno.visible_message(SPAN_XENODANGER("\The [xeno]'s segmented tail starts coiling..."), SPAN_XENODANGER("We begin coiling our tail, aiming towards \the [target_atom]...")) + xeno.emote("roar") - var/throw_target_turf = get_step(abduct_user, facing) + var/throw_target_turf = get_step(xeno, facing) - ADD_TRAIT(abduct_user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Abduct")) - if(!do_after(abduct_user, windup, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE, numticks = 1)) - to_chat(abduct_user, SPAN_XENOWARNING("You relax your tail.")) + ADD_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Abduct")) + start_duration_display(windup) + if(!do_after(xeno, windup, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE, numticks = 1)) + end_duration_display(windup) + to_chat(xeno, SPAN_XENOWARNING("You relax your tail.")) apply_cooldown() - for (var/obj/effect/xenomorph/xeno_telegraph/xenotelegraph in telegraph_atom_list) + for(var/obj/effect/xenomorph/xeno_telegraph/xenotelegraph in telegraph_atom_list) telegraph_atom_list -= xenotelegraph qdel(xenotelegraph) - REMOVE_TRAIT(abduct_user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Abduct")) + REMOVE_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Abduct")) return - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) - REMOVE_TRAIT(abduct_user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Abduct")) + REMOVE_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Abduct")) - playsound(get_turf(abduct_user), 'sound/effects/bang.ogg', 25, 0) - abduct_user.visible_message(SPAN_XENODANGER("\The [abduct_user] suddenly uncoils its tail, firing it towards [atom]!"), SPAN_XENODANGER("We uncoil our tail, sending it out towards \the [atom]!")) + playsound(get_turf(xeno), 'sound/effects/bang.ogg', 25, 0) + xeno.visible_message(SPAN_XENODANGER("\The [xeno] suddenly uncoils its tail, firing it towards [target_atom]!"), SPAN_XENODANGER("We uncoil our tail, sending it out towards \the [target_atom]!")) var/list/targets = list() for(var/turf/target_turf in turflist) for(var/mob/living/carbon/target in target_turf) - if(!isxeno_human(target) || abduct_user.can_not_harm(target) || target.is_dead() || target.is_mob_incapacitated(TRUE) || target.mob_size >= MOB_SIZE_BIG) + if(!isxeno_human(target) || xeno.can_not_harm(target) || target.is_dead() || target.is_mob_incapacitated(TRUE) || target.mob_size >= MOB_SIZE_BIG) continue - targets += target - if(LAZYLEN(targets) == 1) - abduct_user.balloon_alert(abduct_user, "slowed one target", text_color = "#51a16c") - else if(LAZYLEN(targets) == 2) - abduct_user.balloon_alert(abduct_user, "rooted two targets", text_color = "#51a16c") - else if(LAZYLEN(targets) >= 3) - abduct_user.balloon_alert(abduct_user, "stunned [LAZYLEN(targets)] targets", text_color = "#51a16c") + + var/target_count = LAZYLEN(targets) + var/captured_message + + if(target_count == 1) + captured_message = "slowed one target" + else if(target_count == 2) + captured_message = "rooted two targets" + else if(target_count >= 3) + captured_message = "stunned [target_count] targets" + + if(captured_message) + xeno.balloon_alert(xeno, captured_message, text_color = "#51a16c") apply_cooldown() for(var/mob/living/carbon/target in targets) - abduct_user.visible_message(SPAN_XENODANGER("\The [abduct_user]'s hooked tail coils itself around [target]!"), SPAN_XENODANGER("Our hooked tail coils itself around [target]!")) + xeno.visible_message(SPAN_XENODANGER("\The [xeno]'s hooked tail coils itself around [target]!"), SPAN_XENODANGER("Our hooked tail coils itself around [target]!")) target.apply_effect(0.2, WEAKEN) if(LAZYLEN(targets) == 1) - new /datum/effects/xeno_slow(target, abduct_user, null, null, 2.5 SECONDS) + new /datum/effects/xeno_slow(target, xeno, null, null, 2.5 SECONDS) target.apply_effect(1, SLOW) else if(LAZYLEN(targets) == 2) ADD_TRAIT(target, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Abduct")) @@ -224,17 +220,16 @@ var/mob/living/carbon/human/target_human = target target_human.update_xeno_hostile_hud() addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(unroot_human), target, TRAIT_SOURCE_ABILITY("Abduct")), get_xeno_stun_duration(target, 2.5 SECONDS)) - to_chat(target, SPAN_XENOHIGHDANGER("[abduct_user] has pinned you to the ground! You cannot move!")) + to_chat(target, SPAN_XENOHIGHDANGER("[xeno] has pinned you to the ground! You cannot move!")) target.set_effect(2, DAZE) else if(LAZYLEN(targets) >= 3) target.apply_effect(get_xeno_stun_duration(target, 1.3), WEAKEN) - to_chat(target, SPAN_XENOHIGHDANGER("You are slammed into the other victims of [abduct_user]!")) - + to_chat(target, SPAN_XENOHIGHDANGER("You are slammed into the other victims of [xeno]!")) shake_camera(target, 10, 1) - var/obj/effect/beam/tail_beam = abduct_user.beam(target, "oppressor_tail", 'icons/effects/beam.dmi', 0.5 SECONDS, 8) + var/obj/effect/beam/tail_beam = xeno.beam(target, "oppressor_tail", 'icons/effects/beam.dmi', 0.5 SECONDS, 8) var/image/tail_image = image('icons/effects/status_effects.dmi', "hooked") target.overlays += tail_image @@ -249,62 +244,55 @@ overlayed_human.overlays -= tail_image /datum/action/xeno_action/activable/oppressor_punch/use_ability(atom/target_atom) - var/mob/living/carbon/xenomorph/oppressor_user = owner - - if (!action_cooldown_check()) - return + var/mob/living/carbon/xenomorph/xeno = owner - if (!isxeno_human(target_atom) || oppressor_user.can_not_harm(target_atom)) - return - - if (!oppressor_user.check_state() || oppressor_user.agility) + if(!isxeno_human(target_atom) || xeno.can_not_harm(target_atom)) return var/mob/living/carbon/target_carbon = target_atom - if (!oppressor_user.Adjacent(target_carbon)) + if(!xeno.Adjacent(target_carbon)) return if(target_carbon.stat == DEAD) return - var/obj/limb/target_limb = target_carbon.get_limb(check_zone(oppressor_user.zone_selected)) + var/obj/limb/target_limb = target_carbon.get_limb(check_zone(xeno.zone_selected)) - if (ishuman(target_carbon) && (!target_limb || (target_limb.status & LIMB_DESTROYED))) + if(ishuman(target_carbon) && (!target_limb || (target_limb.status & LIMB_DESTROYED))) target_limb = target_carbon.get_limb("chest") - if (!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) - target_carbon.last_damage_data = create_cause_data(oppressor_user.caste_type, oppressor_user) + target_carbon.last_damage_data = create_cause_data(xeno.caste_type, xeno) - oppressor_user.visible_message(SPAN_XENOWARNING("\The [oppressor_user] hits [target_carbon] in the [target_limb? target_limb.display_name : "chest"] with a devastatingly powerful punch!"), + xeno.visible_message(SPAN_XENOWARNING("\The [xeno] hits [target_carbon] in the [target_limb? target_limb.display_name : "chest"] with a devastatingly powerful punch!"), SPAN_XENOWARNING("We hit [target_carbon] in the [target_limb ? target_limb.display_name : "chest"] with a devastatingly powerful punch!")) var/hitsound = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg') playsound(target_carbon,hitsound, 50, 1) - oppressor_user.face_atom(target_carbon) - oppressor_user.animation_attack_on(target_carbon) - oppressor_user.flick_attack_overlay(target_carbon, "punch") + xeno.face_atom(target_carbon) + xeno.animation_attack_on(target_carbon) + xeno.flick_attack_overlay(target_carbon, "punch") - if (!(target_carbon.mobility_flags & MOBILITY_MOVE) || !(target_carbon.mobility_flags & MOBILITY_STAND) || target_carbon.slowed) + if(!(target_carbon.mobility_flags & MOBILITY_MOVE) || !(target_carbon.mobility_flags & MOBILITY_STAND) || target_carbon.slowed) target_carbon.apply_damage(get_xeno_damage_slash(target_carbon, damage), BRUTE, target_limb? target_limb.name : "chest") ADD_TRAIT(target_carbon, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Oppressor Punch")) - if (ishuman(target_carbon)) + if(ishuman(target_carbon)) var/mob/living/carbon/human/human_to_update = target_carbon human_to_update.update_xeno_hostile_hud() addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(unroot_human), target_carbon, TRAIT_SOURCE_ABILITY("Oppressor Punch")), get_xeno_stun_duration(target_carbon, 1.2 SECONDS)) - to_chat(target_carbon, SPAN_XENOHIGHDANGER("[oppressor_user] has pinned you to the ground! You cannot move!")) + to_chat(target_carbon, SPAN_XENOHIGHDANGER("[xeno] has pinned you to the ground! You cannot move!")) else target_carbon.apply_armoured_damage(get_xeno_damage_slash(target_carbon, damage), ARMOR_MELEE, BRUTE, target_limb? target_limb.name : "chest") - step_away(target_carbon, oppressor_user, 2) + step_away(target_carbon, xeno, 2) shake_camera(target_carbon, 2, 1) - var/datum/action/xeno_action/activable/prae_abduct/abduct_action = get_action(oppressor_user, /datum/action/xeno_action/activable/prae_abduct) - var/datum/action/xeno_action/activable/tail_lash/tail_lash_action = get_action(oppressor_user, /datum/action/xeno_action/activable/tail_lash) + var/datum/action/xeno_action/activable/prae_abduct/abduct_action = get_action(xeno, /datum/action/xeno_action/activable/prae_abduct) + var/datum/action/xeno_action/activable/tail_lash/tail_lash_action = get_action(xeno, /datum/action/xeno_action/activable/tail_lash) if(abduct_action && !abduct_action.action_cooldown_check()) abduct_action.reduce_cooldown(5 SECONDS) if(tail_lash_action && !tail_lash_action.action_cooldown_check()) @@ -313,17 +301,16 @@ apply_cooldown() return ..() -/datum/action/xeno_action/activable/tail_lash/use_ability(atom/atoms) - var/mob/living/carbon/xenomorph/lash_user = owner +/datum/action/xeno_action/activable/tail_lash/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(lash_user) || !lash_user.check_state() || !action_cooldown_check()) + if(!istype(xeno) || !target_atom) return - if(!atoms || atoms.layer >= FLY_LAYER || !isturf(lash_user.loc)) + if(target_atom.layer >= FLY_LAYER || !isturf(xeno.loc)) return - if (!check_plasma_owner()) - return + XENO_ACTION_CHECK(xeno) // Transient turf list var/list/target_turfs = list() @@ -331,8 +318,8 @@ var/list/telegraph_atom_list = list() // Code to get a 2x3 area of turfs - var/turf/root = get_turf(lash_user) - var/facing = Get_Compass_Dir(lash_user, atoms) + var/turf/root = get_turf(xeno) + var/facing = Get_Compass_Dir(xeno, target_atom) var/turf/infront = get_step(root, facing) var/turf/left = get_step(root, turn(facing, 90)) var/turf/right = get_step(root, turn(facing, -90)) @@ -345,57 +332,56 @@ temp_turfs += infront_right for(var/turf/turfs_to_check in temp_turfs) - if (!istype(turfs_to_check)) + if(!istype(turfs_to_check)) continue - if (turfs_to_check.density) + if(turfs_to_check.density) continue target_turfs += turfs_to_check telegraph_atom_list += new /obj/effect/xenomorph/xeno_telegraph/lash(turfs_to_check, windup) var/turf/next_turf = get_step(turfs_to_check, facing) - if (!istype(next_turf) || next_turf.density) + if(!istype(next_turf) || next_turf.density) continue target_turfs += next_turf telegraph_atom_list += new /obj/effect/xenomorph/xeno_telegraph/lash(next_turf, windup) if(!length(target_turfs)) - to_chat(lash_user, SPAN_XENOWARNING("We don't have any room to do our tail lash!")) + to_chat(xeno, SPAN_XENOWARNING("We don't have any room to do our tail lash!")) return - if(!do_after(lash_user, windup, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) - to_chat(lash_user, SPAN_XENOWARNING("We cancel our tail lash.")) + if(!do_after(xeno, windup, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + to_chat(xeno, SPAN_XENOWARNING("We cancel our tail lash.")) for(var/obj/effect/xenomorph/xeno_telegraph/tail_telegraph in telegraph_atom_list) telegraph_atom_list -= tail_telegraph qdel(tail_telegraph) return - if(!action_cooldown_check() || !check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) apply_cooldown() - lash_user.visible_message(SPAN_XENODANGER("[lash_user] lashes its tail furiously, hitting everything in front of it!"), SPAN_XENODANGER("We lash our tail furiously, hitting everything in front of us!")) - lash_user.spin_circle() - lash_user.emote("tail") + xeno.visible_message(SPAN_XENODANGER("[xeno] lashes its tail furiously, hitting everything in front of it!"), SPAN_XENODANGER("We lash our tail furiously, hitting everything in front of us!")) + xeno.spin_circle() + xeno.emote("tail") - for (var/turf/targets_in_turf in target_turfs) - for (var/mob/living/carbon/possible_targets in targets_in_turf) - if (possible_targets.stat == DEAD) + for(var/turf/targets_in_turf in target_turfs) + for(var/mob/living/carbon/possible_targets in targets_in_turf) + if(possible_targets.stat == DEAD) continue - if(!isxeno_human(possible_targets) || lash_user.can_not_harm(possible_targets)) + if(!isxeno_human(possible_targets) || xeno.can_not_harm(possible_targets)) continue if(possible_targets.mob_size >= MOB_SIZE_BIG) continue - lash_user.throw_carbon(possible_targets, facing, fling_dist) + xeno.throw_carbon(possible_targets, facing, fling_dist) possible_targets.apply_effect(get_xeno_stun_duration(possible_targets, 0.5), WEAKEN) - new /datum/effects/xeno_slow(possible_targets, lash_user, ttl = get_xeno_stun_duration(possible_targets, 2.5 SECONDS)) + new /datum/effects/xeno_slow(possible_targets, xeno, ttl = get_xeno_stun_duration(possible_targets, 2.5 SECONDS)) return ..() diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm index 8632830e2172..bbc653b739b0 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm @@ -34,12 +34,9 @@ var/shards_per_projectile = 10 var/shards_per_slash = 15 var/armor_buff_per_fifty_shards = 2.50 - var/shard_lock_duration = 150 - var/shard_lock_speed_mod = 0.45 // Shard state var/shards = 0 - var/shards_locked = FALSE //are we locked at 0 shards? // Armor buff state var/times_armor_buffed = 0 @@ -49,46 +46,21 @@ . += "Bone Shards: [shards]/[max_shards]" . += "Shards Armor Bonus: [times_armor_buffed*armor_buff_per_fifty_shards]" -/datum/behavior_delegate/ravager_hedgehog/proc/lock_shards() - - if (!bound_xeno) - return - - to_chat(bound_xeno, SPAN_XENODANGER("You have shed your spikes and cannot gain any more for [shard_lock_duration/10] seconds!")) - - bound_xeno.speed_modifier -= shard_lock_speed_mod - bound_xeno.recalculate_speed() - - shards = 0 - shards_locked = TRUE - addtimer(CALLBACK(src, PROC_REF(unlock_shards)), shard_lock_duration) - -/datum/behavior_delegate/ravager_hedgehog/proc/unlock_shards() - - if (!bound_xeno) - return - - to_chat(bound_xeno, SPAN_XENODANGER("You feel your ability to gather shards return!")) - - bound_xeno.speed_modifier += shard_lock_speed_mod - bound_xeno.recalculate_speed() - shards_locked = FALSE - // Return true if we have enough shards, false otherwise /datum/behavior_delegate/ravager_hedgehog/proc/check_shards(amount) - if (!amount) + if(!amount) return FALSE else return (shards >= amount) /datum/behavior_delegate/ravager_hedgehog/proc/use_shards(amount) - if (!amount) + if(!amount) return shards = max(0, shards - amount) /datum/behavior_delegate/ravager_hedgehog/on_life() - if (!shards_locked) + if(!HAS_TRAIT(bound_xeno, TRAIT_ABILITY_SHED_SPIKES)) shards = min(max_shards, shards + shard_gain_onlife) var/armor_buff_count = shards/50 //0-6 @@ -110,7 +82,6 @@ bound_xeno.small_explosives_stun = TRUE bound_xeno.remove_filter("hedge_unstunnable", 1, list("type" = "outline", "color" = "#421313", "size" = 1)) - return @@ -119,27 +90,23 @@ holder.overlays.Cut() /datum/behavior_delegate/ravager_hedgehog/on_hitby_projectile() - if (!shards_locked) + if(!HAS_TRAIT(bound_xeno, TRAIT_ABILITY_SHED_SPIKES)) shards = min(max_shards, shards + shards_per_projectile) return /datum/behavior_delegate/ravager_hedgehog/melee_attack_additional_effects_self() - if (!shards_locked) + if(!HAS_TRAIT(bound_xeno, TRAIT_ABILITY_SHED_SPIKES)) shards = min(max_shards, shards + shards_per_slash) return -/datum/action/xeno_action/onclick/spike_shield/use_ability(atom/target) +/datum/action/xeno_action/onclick/spike_shield/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if (!action_cooldown_check()) - return - - if (!xeno.check_state()) - return + XENO_ACTION_CHECK(xeno) var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate - if (!behavior.check_shards(shard_cost)) + if(!behavior.check_shards(shard_cost)) to_chat(xeno, SPAN_DANGER("Not enough shards! We need [shard_cost - behavior.shards] more!")) return behavior.use_shards(shard_cost) @@ -148,7 +115,7 @@ // Add our shield var/datum/xeno_shield/hedgehog_shield/shield = xeno.add_xeno_shield(shield_amount, XENO_SHIELD_SOURCE_HEDGE_RAV, /datum/xeno_shield/hedgehog_shield) - if (shield) + if(shield) shield.owner = xeno shield.shrapnel_amount = shield_shrapnel_amount xeno.overlay_shields() @@ -162,7 +129,7 @@ return ..() /datum/action/xeno_action/onclick/spike_shield/action_cooldown_check() - if (shield_active) // If active shield, return FALSE so that this action does not get carried out + if(shield_active) // If active shield, return FALSE so that this action does not get carried out return FALSE else if (cooldown_timer_id == TIMER_ID_NULL) var/mob/living/carbon/xenomorph/xeno = owner @@ -173,14 +140,14 @@ /datum/action/xeno_action/onclick/spike_shield/proc/remove_shield() var/mob/living/carbon/xenomorph/xeno = owner - if (!shield_active) + if(!shield_active) return shield_active = FALSE button.icon_state = "template_xeno" - for (var/datum/xeno_shield/shield in xeno.xeno_shields) - if (shield.shield_source == XENO_SHIELD_SOURCE_HEDGE_RAV) + for(var/datum/xeno_shield/shield in xeno.xeno_shields) + if(shield.shield_source == XENO_SHIELD_SOURCE_HEDGE_RAV) shield.on_removal() qdel(shield) break @@ -192,28 +159,27 @@ /datum/action/xeno_action/activable/rav_spikes/use_ability(atom/affected_atom) var/mob/living/carbon/xenomorph/xeno = owner - if (!action_cooldown_check()) + if(!affected_atom || affected_atom.layer >= FLY_LAYER || !isturf(xeno.loc)) return - if(!affected_atom || affected_atom.layer >= FLY_LAYER || !isturf(xeno.loc) || !xeno.check_state()) - return + XENO_ACTION_CHECK(xeno) var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate - if (!behavior.check_shards(shard_cost)) + if(!behavior.check_shards(shard_cost)) to_chat(xeno, SPAN_DANGER("Not enough shards! We need [shard_cost - behavior.shards] more!")) return behavior.use_shards(shard_cost) xeno.visible_message(SPAN_XENOWARNING("[xeno] fires their spikes at [affected_atom]!"), SPAN_XENOWARNING("We fire our spikes at [affected_atom]!")) - var/turf/target = locate(affected_atom.x, affected_atom.y, affected_atom.z) + var/turf/target_turf = locate(affected_atom.x, affected_atom.y, affected_atom.z) var/obj/projectile/projectile = new /obj/projectile(xeno.loc, create_cause_data(initial(xeno.caste_type), xeno)) var/datum/ammo/ammo_datum = GLOB.ammo_list[ammo_type] projectile.generate_bullet(ammo_datum) - projectile.fire_at(target, xeno, xeno, ammo_datum.max_range, ammo_datum.shell_speed) + projectile.fire_at(target_turf, xeno, xeno, ammo_datum.max_range, ammo_datum.shell_speed) playsound(xeno, 'sound/effects/spike_spray.ogg', 25, 1) apply_cooldown() @@ -222,7 +188,7 @@ /datum/action/xeno_action/activable/rav_spikes/action_cooldown_check() if(!owner) return FALSE - if (cooldown_timer_id == TIMER_ID_NULL) + if(cooldown_timer_id == TIMER_ID_NULL) var/mob/living/carbon/xenomorph/xeno = owner if(!istype(xeno)) return FALSE @@ -234,18 +200,14 @@ /datum/action/xeno_action/onclick/spike_shed/use_ability(atom/affected_atom) var/mob/living/carbon/xenomorph/xeno = owner - if (!action_cooldown_check()) - return - - if (!xeno.check_state()) - return + XENO_ACTION_CHECK(xeno) var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate - if (!behavior.check_shards(shard_cost)) + if(!behavior.check_shards(shard_cost)) to_chat(xeno, SPAN_DANGER("Not enough shards! We need [shard_cost - behavior.shards] more!")) return behavior.use_shards(shard_cost) - behavior.lock_shards() + lock_shards() xeno.visible_message(SPAN_XENOWARNING("[xeno] sheds their spikes, firing them in all directions!"), SPAN_XENOWARNING("We shed our spikes, firing them in all directions!!")) xeno.spin_circle() @@ -256,9 +218,36 @@ return ..() /datum/action/xeno_action/onclick/spike_shed/action_cooldown_check() - if (cooldown_timer_id == TIMER_ID_NULL) + if(cooldown_timer_id == TIMER_ID_NULL) var/mob/living/carbon/xenomorph/xeno = owner var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate return behavior.check_shards(shard_cost) else return FALSE + +/datum/action/xeno_action/onclick/spike_shed/proc/lock_shards() + var/mob/living/carbon/xenomorph/xeno = owner + if(!xeno) + return + + to_chat(xeno, SPAN_XENODANGER("You have shed your spikes and cannot gain any more for [shard_lock_duration/10] seconds!")) + + xeno.speed_modifier -= shard_lock_speed_mod + xeno.recalculate_speed() + + var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate + behavior.shards = 0 + start_duration_display(shard_lock_duration) + ADD_TRAIT(xeno, TRAIT_ABILITY_SHED_SPIKES, TRAIT_SOURCE_ABILITY("shed_spikes")) + addtimer(CALLBACK(src, PROC_REF(unlock_shards)), shard_lock_duration) + +/datum/action/xeno_action/onclick/spike_shed/proc/unlock_shards() + var/mob/living/carbon/xenomorph/xeno = owner + if(!xeno) + return + + to_chat(xeno, SPAN_XENODANGER("You feel your ability to gather shards return!")) + + xeno.speed_modifier += shard_lock_speed_mod + xeno.recalculate_speed() + REMOVE_TRAIT(xeno, TRAIT_ABILITY_SHED_SPIKES, TRAIT_SOURCE_ABILITY("shed_spikes")) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acider.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acider.dm index d6bcb4cbfb5b..ac5b05fc15b8 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acider.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acider.dm @@ -26,12 +26,7 @@ /datum/behavior_delegate/runner_acider var/acid_amount = 0 - var/caboom_left = 20 - var/caboom_trigger - var/caboom_last_proc - var/max_acid = 1000 - var/caboom_timer = 20 var/acid_slash_regen_lying = 8 var/acid_slash_regen_standing = 14 var/acid_passive_regen = 1 @@ -50,14 +45,6 @@ /// How much acid is required to fill a trap var/fill_acid_cost = 75 - var/list/caboom_sound = list('sound/effects/runner_charging_1.ogg','sound/effects/runner_charging_2.ogg') - var/caboom_loop = 1 - - var/caboom_acid_ratio = 200 - var/caboom_burn_damage_ratio = 5 - var/caboom_burn_range_ratio = 100 - var/caboom_struct_acid_type = /obj/effect/xenomorph/acid - var/drool_overlay_active = FALSE var/mutable_appearance/drool_applied_icon var/mutable_appearance/acid_overlays_icon @@ -81,8 +68,6 @@ if(acid_amount >= acid_gen_cap) . += "Passive acid generation cap ([acid_gen_cap]) reached" . += "Battle acid generation: [combat_gen_active ? "Active" : "Inactive"]" - if(caboom_trigger) - . += "FOR THE HIVE!: in [caboom_left] seconds" /datum/behavior_delegate/runner_acider/melee_attack_additional_effects_target(mob/living/carbon/target_mob) if(ishuman(target_mob)) //Will acid be applied to the mob @@ -112,6 +97,7 @@ drool_overlay_active = TRUE //turns the overlay on /datum/behavior_delegate/runner_acider/on_life() + var/datum/action/xeno_action/activable/acider_for_the_hive/acider_fth = get_action(bound_xeno, /datum/action/xeno_action/activable/acider_for_the_hive) if(acid_amount < acid_gen_cap) modify_acid(acid_passive_regen) if(combat_gen_active) @@ -120,19 +106,19 @@ return if(bound_xeno.stat == DEAD) return - if(caboom_trigger) - var/wt = world.time - if(caboom_last_proc) - caboom_left -= (wt - caboom_last_proc)/10 - caboom_last_proc = wt - var/amplitude = 50 + 50 * (caboom_timer - caboom_left) / caboom_timer - playsound(bound_xeno, caboom_sound[caboom_loop], amplitude, FALSE, 10) - caboom_loop++ - if(caboom_loop > length(caboom_sound)) - caboom_loop = 1 - if(caboom_left <= 0) - caboom_trigger = FALSE - do_caboom() + if(acider_fth.caboom_trigger) + var/world_time = world.time + if(acider_fth.caboom_last_proc) + acider_fth.caboom_left -= (world_time - acider_fth.caboom_last_proc)/10 + acider_fth.caboom_last_proc = world_time + var/amplitude = 50 + 50 * (acider_fth.caboom_timer - acider_fth.caboom_left) / acider_fth.caboom_timer + playsound(bound_xeno, acider_fth.caboom_sound[acider_fth.caboom_loop], amplitude, FALSE, 10) + acider_fth.caboom_loop++ + if(acider_fth.caboom_loop > length(acider_fth.caboom_sound)) + acider_fth.caboom_loop = 1 + if(acider_fth.caboom_left <= 0) + acider_fth.caboom_trigger = FALSE + acider_fth.do_caboom() return var/image/holder = bound_xeno.hud_list[SPECIAL_HUD] @@ -144,70 +130,11 @@ if(acid_amount >= acid_gen_cap) holder.overlays += image('icons/mob/hud/hud.dmi', "cap[percentage_acid_cap]") -/datum/behavior_delegate/runner_acider/handle_death(mob/M) +/datum/behavior_delegate/runner_acider/handle_death(mob/target_mob) var/image/holder = bound_xeno.hud_list[SPECIAL_HUD] holder.overlays.Cut() STOP_PROCESSING(SSfasteffects, src) -/datum/behavior_delegate/runner_acider/proc/do_caboom() - if(!bound_xeno) - return - var/acid_range = acid_amount / caboom_acid_ratio - var/max_burn_damage = acid_amount / caboom_burn_damage_ratio - var/burn_range = acid_amount / caboom_burn_range_ratio - - for(var/barricades in dview(acid_range, bound_xeno)) - if(istype(barricades, /obj/structure/barricade)) - new caboom_struct_acid_type(get_turf(barricades), barricades) - continue - if(istype(barricades, /mob)) - new /datum/effects/acid(barricades, bound_xeno, initial(bound_xeno.caste_type)) - continue - var/x = bound_xeno.x - var/y = bound_xeno.y - FOR_DVIEW(var/mob/living/target_living, burn_range, bound_xeno, HIDE_INVISIBLE_OBSERVER) - if (!isxeno_human(target_living) || bound_xeno.can_not_harm(target_living)) - continue - var/dist = 0 - // such cheap, much fast - var/dx = abs(target_living.x - x) - var/dy = abs(target_living.y - y) - if(dx>=dy) - dist = (0.934*dx) + (0.427*dy) - else - dist = (0.427*dx) + (0.934*dy) - var/damage = floor((burn_range - dist) * max_burn_damage / burn_range) - if(isxeno(target_living)) - damage *= XVX_ACID_DAMAGEMULT - - target_living.apply_damage(damage, BURN) - FOR_DVIEW_END - FOR_DVIEW(var/turf/T, acid_range, bound_xeno, HIDE_INVISIBLE_OBSERVER) - new /obj/effect/particle_effect/smoke/acid_runner_harmless(T) - FOR_DVIEW_END - playsound(bound_xeno, 'sound/effects/blobattack.ogg', 75) - if(bound_xeno.client && bound_xeno.hive) - var/datum/hive_status/hive_status = bound_xeno.hive - var/turf/spawning_turf = get_turf(bound_xeno) - if(!hive_status.hive_location) - addtimer(CALLBACK(bound_xeno.hive, TYPE_PROC_REF(/datum/hive_status, respawn_on_turf), bound_xeno.client, spawning_turf), 0.5 SECONDS) - else - addtimer(CALLBACK(bound_xeno.hive, TYPE_PROC_REF(/datum/hive_status, free_respawn), bound_xeno.client), 5 SECONDS) - bound_xeno.gib(create_cause_data("internal acid rupture", src)) - -/mob/living/carbon/xenomorph/runner/ventcrawl_carry() - var/datum/behavior_delegate/runner_acider/behavior_delegates = behavior_delegate - if(istype(behavior_delegates) && behavior_delegates.caboom_trigger) - to_chat(src, SPAN_XENOWARNING("You cannot ventcrawl when you are about to explode!")) - return FALSE - return ..() - -/mob/living/carbon/xenomorph/runner/get_examine_text(mob/user) - . = ..() - var/datum/behavior_delegate/runner_acider/behavior = behavior_delegate - if(istype(behavior) && isxeno(user)) - . += "it has [SPAN_GREEN(behavior.acid_amount)] acid!" - /datum/behavior_delegate/runner_acider/proc/combat_gen_end() //This proc is triggerd once the combat acid timer runs out. combat_gen_active = FALSE //turns combat acid off drool_overlay_active = FALSE @@ -252,9 +179,9 @@ var/perc_index = 0 if(acid_amount > max_acid * 0.8) perc_index = 3 - else if (acid_amount > max_acid * 0.5) + else if(acid_amount > max_acid * 0.5) perc_index = 2 - else if (acid_amount > max_acid * 0.2) + else if(acid_amount > max_acid * 0.2) perc_index = 1 if(perc_index && bound_runner.stat != DEAD) @@ -267,3 +194,302 @@ acid_overlays_icon.overlays += icon('icons/mob/xenos/castes/tier_1/runner_strain_overlays.dmi', "acidsac_[perc_index]") bound_runner.overlays += acid_overlays_icon + + + +/datum/action/xeno_action/activable/acider_acid/use_ability(atom/affected_atom) + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(affected_atom, /obj/item) && !istype(affected_atom, /obj/structure/) && !istype(affected_atom, /obj/vehicle/multitile)) + to_chat(xeno, SPAN_XENOHIGHDANGER("Can only melt barricades and items!")) + return + var/datum/behavior_delegate/runner_acider/behavior_delegate = xeno.behavior_delegate + if(!istype(behavior_delegate)) + return + if(behavior_delegate.acid_amount < acid_cost) + to_chat(xeno, SPAN_XENOHIGHDANGER("Not enough acid stored!")) + return + + xeno.corrosive_acid(affected_atom, acid_type, 0) + for(var/obj/item/explosive/plastic/plastic_explosive in affected_atom.contents) + xeno.corrosive_acid(plastic_explosive, acid_type, 0) + return ..() + + +/datum/action/xeno_action/activable/acider_for_the_hive/use_ability() + var/mob/living/carbon/xenomorph/xeno = owner + + if(!istype(xeno)) + return + + if(!isturf(xeno.loc)) + to_chat(xeno, SPAN_XENOWARNING("It is too cramped in here to activate this!")) + return + + var/area/xeno_area = get_area(xeno) + if(xeno_area.flags_area & AREA_CONTAINMENT) + to_chat(xeno, SPAN_XENOWARNING("We can't activate this here!")) + return + + XENO_ACTION_CHECK(xeno) + + var/datum/behavior_delegate/runner_acider/behavior_delegate = xeno.behavior_delegate + if(!istype(behavior_delegate)) + return + + if(caboom_trigger) + cancel_ability() + return + + if(behavior_delegate.acid_amount < minimal_acid) + to_chat(xeno, SPAN_XENOWARNING("Not enough acid built up for an explosion.")) + return + + notify_ghosts(header = "For the Hive!", message = "[xeno] is going to explode for the Hive!", source = xeno, action = NOTIFY_ORBIT) + + to_chat(xeno, SPAN_XENOWARNING("Our stomach starts turning and twisting, getting ready to compress the built up acid.")) + xeno.color = "#22FF22" + xeno.set_light_color("#22FF22") + xeno.set_light_range(3) + + caboom_trigger = TRUE + caboom_left = caboom_timer + caboom_last_proc = 0 + xeno.set_effect(caboom_timer*2, SUPERSLOW) + + start_duration_display(caboom_left_display) + + xeno.say(";FOR THE HIVE!!!") + return ..() + +/datum/action/xeno_action/activable/acider_for_the_hive/proc/cancel_ability() + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(xeno)) + return + var/datum/behavior_delegate/runner_acider/behavior_delegate = xeno.behavior_delegate + if(!istype(behavior_delegate)) + return + + caboom_trigger = FALSE + xeno.color = null + xeno.set_light_range(0) + behavior_delegate.modify_acid(-behavior_delegate.max_acid / 4) + + // Done this way rather than setting to 0 in case something else slowed us + // -Original amount set - (time exploding + timer inaccuracy) * how much gets removed per tick / 2 + xeno.adjust_effect(caboom_timer * -2 - (caboom_timer - caboom_left + 2) * xeno.life_slow_reduction * 0.5, SUPERSLOW) + + end_duration_display() + to_chat(xeno, SPAN_XENOWARNING("We remove all our explosive acid before it combusted.")) + +/datum/action/xeno_action/activable/acider_for_the_hive/proc/do_caboom() + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(xeno)) + return + + var/datum/behavior_delegate/runner_acider/behavior_delegate = xeno.behavior_delegate + if(!istype(behavior_delegate)) + return + + var/acid_range = behavior_delegate.acid_amount / caboom_acid_ratio + var/max_burn_damage = behavior_delegate.acid_amount / caboom_burn_damage_ratio + var/burn_range = behavior_delegate.acid_amount / caboom_burn_range_ratio + + for(var/barricades in dview(acid_range, xeno)) + if(istype(barricades, /obj/structure/barricade)) + new caboom_struct_acid_type(get_turf(barricades), barricades) + continue + if(istype(barricades, /mob)) + new /datum/effects/acid(barricades, xeno, initial(xeno.caste_type)) + continue + var/x = xeno.x + var/y = xeno.y + FOR_DVIEW(var/mob/living/target_living, burn_range, xeno, HIDE_INVISIBLE_OBSERVER) + if (!isxeno_human(target_living) || xeno.can_not_harm(target_living)) + continue + var/dist = 0 + // such cheap, much fast + var/dx = abs(target_living.x - x) + var/dy = abs(target_living.y - y) + if(dx>=dy) + dist = (0.934*dx) + (0.427*dy) + else + dist = (0.427*dx) + (0.934*dy) + var/damage = floor((burn_range - dist) * max_burn_damage / burn_range) + if(isxeno(target_living)) + damage *= XVX_ACID_DAMAGEMULT + + target_living.apply_damage(damage, BURN) + FOR_DVIEW_END + FOR_DVIEW(var/turf/T, acid_range, xeno, HIDE_INVISIBLE_OBSERVER) + new /obj/effect/particle_effect/smoke/acid_runner_harmless(T) + FOR_DVIEW_END + playsound(xeno, 'sound/effects/blobattack.ogg', 75) + if(xeno.client && xeno.hive) + var/datum/hive_status/hive_status = xeno.hive + var/turf/spawning_turf = get_turf(xeno) + if(!hive_status.hive_location) + addtimer(CALLBACK(xeno.hive, TYPE_PROC_REF(/datum/hive_status, respawn_on_turf), xeno.client, spawning_turf), 0.5 SECONDS) + else + addtimer(CALLBACK(xeno.hive, TYPE_PROC_REF(/datum/hive_status, free_respawn), xeno.client), 5 SECONDS) + xeno.gib(create_cause_data("internal acid rupture", src)) + + + +/mob/living/carbon/xenomorph/runner/get_examine_text(mob/user) + . = ..() + var/datum/behavior_delegate/runner_acider/behavior = behavior_delegate + if(istype(behavior) && isxeno(user)) + . += "it has [SPAN_GREEN(behavior.acid_amount)] acid!" + +/mob/living/carbon/xenomorph/runner/ventcrawl_carry() + var/datum/action/xeno_action/activable/acider_for_the_hive/acider_fth = get_action(src, /datum/action/xeno_action/activable/acider_for_the_hive) + if(acider_fth.caboom_trigger) + to_chat(src, SPAN_XENOWARNING("You cannot ventcrawl when you are about to explode!")) + return FALSE + return ..() + +/mob/living/carbon/xenomorph/runner/corrosive_acid(atom/affected_atom, acid_type, plasma_cost) + if(!istype(strain, /datum/xeno_strain/acider)) + return ..() + if(!affected_atom.Adjacent(src)) + if(istype(affected_atom,/obj/item/explosive/plastic)) + var/obj/item/explosive/plastic/plastic_explosive = affected_atom + if(plastic_explosive.plant_target && !plastic_explosive.plant_target.Adjacent(src)) + to_chat(src, SPAN_WARNING("We can't reach [affected_atom].")) + return + else + to_chat(src, SPAN_WARNING("[affected_atom] is too far away.")) + return + + if(!isturf(loc) || HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + to_chat(src, SPAN_WARNING("We can't melt [affected_atom] from here!")) + return + + face_atom(affected_atom) + + var/wait_time = 10 + + var/turf/turf = get_turf(affected_atom) + + for(var/obj/effect/xenomorph/acid/acid in turf) + if(acid_type == acid.type && acid.acid_t == affected_atom) + to_chat(src, SPAN_WARNING("[affected_atom] is already drenched in acid.")) + return + + var/obj/object + //OBJ CHECK + if(isobj(affected_atom)) + object = affected_atom + + wait_time = object.get_applying_acid_time() + if(wait_time == -1) + to_chat(src, SPAN_WARNING("We cannot dissolve [object].")) + return + else + to_chat(src, SPAN_WARNING("We cannot dissolve [affected_atom].")) + return + wait_time = wait_time / 4 + if(!do_after(src, wait_time, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + return + + // AGAIN BECAUSE SOMETHING COULD'VE ACIDED THE PLACE + for(var/obj/effect/xenomorph/acid/acid in turf) + if(acid_type == acid.type && acid.acid_t == affected_atom) + to_chat(src, SPAN_WARNING("[affected_atom] is already drenched in acid.")) + return + + if(!check_state()) + return + + if(!affected_atom || QDELETED(affected_atom)) //Some logic. + return + + if(!affected_atom.Adjacent(src) || (object && !isturf(object.loc)))//not adjacent or inside something + if(istype(affected_atom, /obj/item/explosive/plastic)) + var/obj/item/explosive/plastic/plastic_explosive = affected_atom + if(plastic_explosive.plant_target && !plastic_explosive.plant_target.Adjacent(src)) + to_chat(src, SPAN_WARNING("We can't reach [affected_atom].")) + return + else + to_chat(src, SPAN_WARNING("[affected_atom] is too far away.")) + return + + var/datum/behavior_delegate/runner_acider/behavior_del = behavior_delegate + if(!istype(behavior_del)) + return + if(behavior_del.acid_amount < behavior_del.melt_acid_cost) + to_chat(src, SPAN_XENOHIGHDANGER("Not enough acid stored!")) + return + + behavior_del.modify_acid(-behavior_del.melt_acid_cost) + + var/obj/effect/xenomorph/acid/acid = new acid_type(turf, affected_atom) + + if(istype(affected_atom, /obj/vehicle/multitile)) + var/obj/vehicle/multitile/multitile_vehicle = affected_atom + multitile_vehicle.take_damage_type(20 / acid.acid_delay, "acid", src) + visible_message(SPAN_XENOWARNING("[src] vomits globs of vile stuff at [multitile_vehicle]. It sizzles under the bubbling mess of acid!"), + SPAN_XENOWARNING("We vomit globs of vile stuff at [multitile_vehicle]. It sizzles under the bubbling mess of acid!"), null, 5) + playsound(loc, "sound/bullets/acid_impact1.ogg", 25) + QDEL_IN(acid, 20) + return + + acid.add_hiddenprint(src) + acid.name += " ([affected_atom])" + + visible_message(SPAN_XENOWARNING("[src] vomits globs of vile stuff all over [affected_atom]. It begins to sizzle and melt under the bubbling mess of acid!"), + SPAN_XENOWARNING("We vomit globs of vile stuff all over [affected_atom]. It begins to sizzle and melt under the bubbling mess of acid!"), null, 5) + playsound(loc, "sound/bullets/acid_impact1.ogg", 25) + +#define ACIDER_ACID_LEVEL 3 + +/mob/living/carbon/xenomorph/runner/try_fill_trap(obj/effect/alien/resin/trap/target) + if(!istype(strain, /datum/xeno_strain/acider)) + return ..() + + if(!istype(target)) + return FALSE + + var/datum/behavior_delegate/runner_acider/behavior_del = behavior_delegate + if(!istype(behavior_del)) + return FALSE + + if(behavior_del.acid_amount < behavior_del.fill_acid_cost) + to_chat(src, SPAN_XENOHIGHDANGER("Not enough acid stored!")) + return FALSE + + var/trap_acid_level = 0 + if(target.trap_type >= RESIN_TRAP_ACID1) + trap_acid_level = 1 + target.trap_type - RESIN_TRAP_ACID1 + + if(trap_acid_level >= ACIDER_ACID_LEVEL) // Acid runners apply /obj/effect/xenomorph/acid/strong generally + to_chat(src, SPAN_XENONOTICE("It already has good acid in.")) + return FALSE + + to_chat(src, SPAN_XENONOTICE("You begin charging the resin trap with acid.")) + xeno_attack_delay(src) + if(!do_after(src, 3 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE, src)) + return FALSE + + if(target.trap_type >= RESIN_TRAP_ACID1) + trap_acid_level = 1 + target.trap_type - RESIN_TRAP_ACID1 + + if(trap_acid_level >= ACIDER_ACID_LEVEL) + return FALSE + + if(behavior_del.acid_amount < behavior_del.fill_acid_cost) + to_chat(src, SPAN_XENOHIGHDANGER("Not enough acid stored!")) + return FALSE + + behavior_del.modify_acid(-behavior_del.fill_acid_cost) + + target.cause_data = create_cause_data("resin acid trap", src) + target.setup_tripwires() + target.set_state(RESIN_TRAP_ACID1 + ACIDER_ACID_LEVEL - 1) + + playsound(target, 'sound/effects/refill.ogg', 25, 1) + visible_message(SPAN_XENOWARNING("[src] pressurises the resin trap with acid!"), + SPAN_XENOWARNING("You pressurise the resin trap with acid!"), null, 5) + return TRUE + +#undef ACIDER_ACID_LEVEL diff --git a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm index b41fa65d6d56..b0fda47ad13e 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -171,7 +171,7 @@ to_chat(src, SPAN_WARNING("We must be at full health to take a strain.")) return FALSE - if(agility || fortify || crest_defense || stealth) + if(agility || fortify || crest_defense || HAS_TRAIT(src, TRAIT_ABILITY_INVIS)) to_chat(src, SPAN_WARNING("We cannot take a strain while in this stance.")) return FALSE diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index f1fa746647e7..cbef42edd2c8 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -952,6 +952,9 @@ if(evasion > 0) . -= evasion + if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + return 0 + /obj/projectile/proc/play_hit_effect(mob/hit_mob) if(ammo.sound_hit) From 801b23b70b5dfa1043d33d59341e659e10d8746d Mon Sep 17 00:00:00 2001 From: Venuska1117 Date: Sat, 25 Jul 2026 01:39:52 +0200 Subject: [PATCH 2/3] eh... not worth the trouble --- code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm index ff3df8481f5c..56930fe7297a 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm @@ -138,7 +138,6 @@ xeno.add_traits(list(TRAIT_ABILITY_BURROWED, TRAIT_UNDENSE, TRAIT_IMMOBILIZED), TRAIT_SOURCE_ABILITY("Burrow")) playsound(xeno.loc, 'sound/effects/burrowing_b.ogg', 25) xeno.update_icons() - start_duration_display(10 SECONDS) addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), burrow_cooldown) burrow_timer = world.time + 90 // How long we can be burrowed process_burrow() @@ -163,7 +162,6 @@ xeno.invisibility = FALSE xeno.alpha = initial(xeno.alpha) xeno.anchored = FALSE - end_duration_display() var/mob/living/carbon/human/hauled = xeno.hauled_mob?.resolve() if(hauled) @@ -185,8 +183,6 @@ to_chat(xeno, SPAN_NOTICE("We can now surface.")) update_button_icon() - - /datum/action/xeno_action/activable/burrow/proc/digging(turf/target_atom) var/mob/living/carbon/xenomorph/xeno = owner @@ -261,7 +257,6 @@ to_chat(xeno, SPAN_NOTICE("We tunnel to the destination.")) xeno.anchored = FALSE xeno.forceMove(target_atom) - end_duration_display() burrow_off() /datum/action/xeno_action/activable/burrow/proc/do_digging_cooldown() From 91db744452be5681ad9b8668f38a119781bfebc1 Mon Sep 17 00:00:00 2001 From: Venuska1117 Date: Sat, 25 Jul 2026 01:54:34 +0200 Subject: [PATCH 3/3] reverting burrower changes --- code/__DEFINES/traits.dm | 4 +- .../living/carbon/xenomorph/XenoAttacks.dm | 3 - .../mob/living/carbon/xenomorph/Xenomorph.dm | 24 +- .../abilities/burrower/burrower_abilities.dm | 20 +- .../carbon/xenomorph/castes/Burrower.dm | 373 ++++++++++-------- .../carbon/xenomorph/castes/caste_datum.dm | 2 + .../living/carbon/xenomorph/damage_procs.dm | 4 - code/modules/projectiles/projectile.dm | 3 - 8 files changed, 225 insertions(+), 208 deletions(-) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 4ea0d29ccdd3..3fa1c1335514 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -272,13 +272,13 @@ // -- specific ability traits -- #define TRAIT_ABILITY_ASSASINATE "t_ability_assasinate" #define TRAIT_ABILITY_INVIS "t_ability_invis" -#define TRAIT_ABILITY_BURROW_DIGGING "t_ability_burrow_digging" -#define TRAIT_ABILITY_BURROW_UNDERGROUND "t_ability_burrow_underground" #define TRAIT_ABILITY_DODGE "t_ability_dodge" #define TRAIT_ABILITY_RED_TAG "t_ability_red_tag" #define TRAIT_ABILITY_YELLOW_TAG "t_ability_yellow_tag" #define TRAIT_ABILITY_SHED_SPIKES "t_ability_shed_spikes" +/// Used by shielder to check stance. #define TRAIT_ABILITY_ENCLOSED_PLATES "t_ability_enclosed_plates" +/// Used by shielder for reflective plates. #define TRAIT_ABILITY_REFLECTIVE_PLATES "t_ability_reflective_plates" diff --git a/code/modules/mob/living/carbon/xenomorph/XenoAttacks.dm b/code/modules/mob/living/carbon/xenomorph/XenoAttacks.dm index 51bd4e859fef..816ba1fb8c7f 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoAttacks.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoAttacks.dm @@ -24,9 +24,6 @@ if(..()) return TRUE - if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - return - switch(M.a_intent) if(INTENT_HELP) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index db86dd20ff42..a80a82256455 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -294,6 +294,7 @@ // ////////////////////////////////////////////////////////////////// + var/tunnel = FALSE /// for check on lurker invisibility var/fortify = FALSE var/crest_defense = FALSE @@ -363,6 +364,14 @@ // Vars that should be deleted // ////////////////////////////////////////////////////////////////// + var/burrow_timer = 200 + var/tunnel_timer = 20 + + //Burrower Vars + var/used_tremor = 0 + // Burrowers + var/used_burrow = 0 + var/used_tunnel = 0 //Taken from update_icon for all xeno's var/list/overlays_standing[X_TOTAL_LAYERS] @@ -847,22 +856,7 @@ pulledby.stop_pulling() . = 1 -/mob/living/carbon/xenomorph/proc/rename_tunnel(obj/structure/tunnel/tunnel_target in oview(1)) - set name = "Rename Tunnel" - set desc = "Rename the tunnel." - set category = null - - if(!istype(tunnel_target)) - return - var/new_name = strip_html(input("Change the description of the tunnel:", "Tunnel Description") as text|null) - new_name = replace_non_alphanumeric_plus(new_name) - if(new_name) - new_name = "[new_name] ([get_area_name(tunnel_target)])" - log_admin("[key_name(src)] has renamed the tunnel \"[tunnel_target.tunnel_desc]\" as \"[new_name]\".") - msg_admin_niche("[src]/([key_name(src)]) has renamed the tunnel \"[tunnel_target.tunnel_desc]\" as \"[new_name]\".") - tunnel_target.tunnel_desc = "[new_name]" - return /mob/living/carbon/xenomorph/prepare_huds() ..() diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/burrower/burrower_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/burrower/burrower_abilities.dm index cceb74d8b38c..0ea27be28d18 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/burrower/burrower_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/burrower/burrower_abilities.dm @@ -8,22 +8,16 @@ action_type = XENO_ACTION_CLICK ability_primacy = XENO_PRIMARY_ACTION_3 - var/used_digging = FALSE - var/digging_timer = 2 SECONDS - var/burrow_timer = 20 SECONDS +/datum/action/xeno_action/activable/burrow/use_ability(atom/A) + var/mob/living/carbon/xenomorph/xenomorph = owner - var/burrow_cooldown = 2 SECONDS - var/digging_cooldown = 7 SECONDS + if(!action_cooldown_check()) + return -/datum/action/xeno_action/activable/burrow/use_ability(atom/target_atom) - var/mob/living/carbon/xenomorph/xeno = owner - - XENO_ACTION_CHECK(xeno) - - if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) - digging(get_turf(target_atom)) + if(HAS_TRAIT(xenomorph, TRAIT_ABILITY_BURROWED)) + xenomorph.tunnel(get_turf(A)) else - burrow() + xenomorph.burrow() return ..() /datum/action/xeno_action/onclick/tremor diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm index 56930fe7297a..f3837947db9f 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm @@ -28,6 +28,9 @@ tacklestrength_min = 4 tacklestrength_max = 5 + burrow_cooldown = 2 SECONDS + tunnel_cooldown = 7 SECONDS + minimum_evolve_time = 7 MINUTES minimap_icon = "burrower" @@ -82,214 +85,249 @@ skull = /obj/item/skull/burrower pelt = /obj/item/pelt/burrower -/datum/behavior_delegate/burrower_base - name = "Base Burrower Behavior Delegate" +/mob/living/carbon/xenomorph/burrower/ex_act(severity, direction, datum/cause_data/cause_data, pierce=0, enviro=FALSE) + if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + return + ..() +/mob/living/carbon/xenomorph/burrower/attack_hand() + if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + return + ..() -/datum/action/xeno_action/activable/burrow/proc/burrow() - var/mob/living/carbon/xenomorph/xeno = owner +/mob/living/carbon/xenomorph/burrower/attackby() + if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + return + . = ..() - XENO_ACTION_CHECK(xeno) +/mob/living/carbon/xenomorph/burrower/get_projectile_hit_chance() + . = ..() + if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + return 0 - if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_UNDERGROUND) || HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING)) +/datum/behavior_delegate/burrower_base + name = "Base Burrower Behavior Delegate" + + +//Burrower Abilities +/mob/living/carbon/xenomorph/proc/burrow() + if(!check_state()) return - if(xeno.is_ventcrawling || xeno.action_busy) + if(used_burrow || tunnel || is_ventcrawling || action_busy) return - var/turf/current_turf = get_turf(xeno) + var/turf/current_turf = get_turf(src) if(!current_turf) return var/area/current_area = get_area(current_turf) if(current_area.flags_area & AREA_NOBURROW) - to_chat(xeno, SPAN_XENOWARNING("There's no way to burrow here.")) + to_chat(src, SPAN_XENOWARNING("There's no way to burrow here.")) return if(istype(current_turf, /turf/open/floor/almayer/research/containment) || istype(current_turf, /turf/closed/wall/almayer/research/containment)) - to_chat(xeno, SPAN_XENOWARNING("We can't escape this cell!")) + to_chat(src, SPAN_XENOWARNING("We can't escape this cell!")) return - if(xeno.clone) //Prevents burrowing on stairs - to_chat(xeno, SPAN_XENOWARNING("We can't burrow here!")) + if(clone) //Prevents burrowing on stairs + to_chat(src, SPAN_XENOWARNING("We can't burrow here!")) return - if(xeno.caste_type && GLOB.xeno_datum_list[xeno.caste_type]) - xeno.caste = GLOB.xeno_datum_list[xeno.caste_type] + if(caste_type && GLOB.xeno_datum_list[caste_type]) + caste = GLOB.xeno_datum_list[caste_type] - ADD_TRAIT(xeno, TRAIT_ABILITY_BURROW_UNDERGROUND, TRAIT_SOURCE_ABILITY("burrow_underground")) + used_burrow = TRUE - to_chat(xeno, SPAN_XENOWARNING("We begin burrowing ourselves into the ground.")) - if(!do_after(xeno, 1.5 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) - addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), burrow_cooldown) + to_chat(src, SPAN_XENOWARNING("We begin burrowing ourselves into the ground.")) + if(!do_after(src, 1.5 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) + addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), (caste ? caste.burrow_cooldown : 5 SECONDS)) return // TODO Make immune to all damage here. - to_chat(xeno, SPAN_XENOWARNING("We burrow ourselves into the ground.")) - QDEL_NULL(xeno.observed_atom) - xeno.invisibility = 101 - xeno.alpha = 100 - xeno.anchored = TRUE + to_chat(src, SPAN_XENOWARNING("We burrow ourselves into the ground.")) + QDEL_NULL(observed_atom) + invisibility = 101 + alpha = 100 + anchored = TRUE - var/mob/living/carbon/human/hauled = xeno.hauled_mob?.resolve() + var/mob/living/carbon/human/hauled = hauled_mob?.resolve() if(hauled) - hauled.forceMove(xeno) + hauled.forceMove(src) - xeno.add_traits(list(TRAIT_ABILITY_BURROWED, TRAIT_UNDENSE, TRAIT_IMMOBILIZED), TRAIT_SOURCE_ABILITY("Burrow")) - playsound(xeno.loc, 'sound/effects/burrowing_b.ogg', 25) - xeno.update_icons() - addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), burrow_cooldown) + add_traits(list(TRAIT_ABILITY_BURROWED, TRAIT_UNDENSE, TRAIT_IMMOBILIZED), TRAIT_SOURCE_ABILITY("Burrow")) + playsound(src.loc, 'sound/effects/burrowing_b.ogg', 25) + update_icons() + addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), (caste ? caste.burrow_cooldown : 5 SECONDS)) burrow_timer = world.time + 90 // How long we can be burrowed process_burrow() -/datum/action/xeno_action/activable/burrow/proc/process_burrow() - var/mob/living/carbon/xenomorph/xeno = owner - - if(!HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) +/mob/living/carbon/xenomorph/proc/process_burrow() + if(!HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) return - if(world.time > burrow_timer && !HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING)) + if(world.time > burrow_timer && !tunnel) burrow_off() - if(xeno.observed_xeno) - xeno.overwatch(xeno.observed_xeno, TRUE) - if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) + if(observed_xeno) + overwatch(observed_xeno, TRUE) + if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) addtimer(CALLBACK(src, PROC_REF(process_burrow)), 1 SECONDS) -/datum/action/xeno_action/activable/burrow/proc/burrow_off() - var/mob/living/carbon/xenomorph/xeno = owner - - to_chat(xeno, SPAN_NOTICE("You resurface.")) - xeno.remove_traits(list(TRAIT_ABILITY_BURROWED, TRAIT_UNDENSE, TRAIT_IMMOBILIZED), TRAIT_SOURCE_ABILITY("Burrow")) - xeno.invisibility = FALSE - xeno.alpha = initial(xeno.alpha) - xeno.anchored = FALSE +/mob/living/carbon/xenomorph/proc/burrow_off() + if(caste_type && GLOB.xeno_datum_list[caste_type]) + caste = GLOB.xeno_datum_list[caste_type] + to_chat(src, SPAN_NOTICE("You resurface.")) + remove_traits(list(TRAIT_ABILITY_BURROWED, TRAIT_UNDENSE, TRAIT_IMMOBILIZED), TRAIT_SOURCE_ABILITY("Burrow")) + invisibility = FALSE + alpha = initial(alpha) + anchored = FALSE - var/mob/living/carbon/human/hauled = xeno.hauled_mob?.resolve() + var/mob/living/carbon/human/hauled = hauled_mob?.resolve() if(hauled) - hauled.forceMove(xeno.loc) + hauled.forceMove(loc) - playsound(xeno.loc, 'sound/effects/burrowoff.ogg', 25) - for(var/mob/living/carbon/mob in xeno.loc) - if(!xeno.can_not_harm(mob)) + playsound(loc, 'sound/effects/burrowoff.ogg', 25) + for(var/mob/living/carbon/mob in loc) + if(!can_not_harm(mob)) mob.apply_effect(1.5, WEAKEN) - addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), burrow_cooldown) - xeno.update_icons() - -/datum/action/xeno_action/activable/burrow/proc/do_burrow_cooldown() - var/mob/living/carbon/xenomorph/xeno = owner + addtimer(CALLBACK(src, PROC_REF(do_burrow_cooldown)), (caste ? caste.burrow_cooldown : 5 SECONDS)) + update_icons() - REMOVE_TRAIT(xeno, TRAIT_ABILITY_BURROW_UNDERGROUND, TRAIT_SOURCE_ABILITY("burrow_underground")) - if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) - to_chat(xeno, SPAN_NOTICE("We can now surface.")) - update_button_icon() +/mob/living/carbon/xenomorph/proc/do_burrow_cooldown() + used_burrow = FALSE + if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + to_chat(src, SPAN_NOTICE("We can now surface.")) + for(var/X in actions) + var/datum/action/act = X + act.update_button_icon() -/datum/action/xeno_action/activable/burrow/proc/digging(turf/target_atom) - var/mob/living/carbon/xenomorph/xeno = owner - XENO_ACTION_CHECK(xeno) +/mob/living/carbon/xenomorph/proc/tunnel(turf/target) + if(!check_state()) + return - if(!HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) - to_chat(xeno, SPAN_NOTICE("We must be burrowed to do this.")) + if(!HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) + to_chat(src, SPAN_NOTICE("We must be burrowed to do this.")) return - if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING)) - REMOVE_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING, TRAIT_SOURCE_ABILITY("burrow_digging")) - to_chat(xeno, SPAN_NOTICE("We stop tunneling.")) - used_digging = TRUE - addtimer(CALLBACK(src, PROC_REF(do_digging_cooldown)), digging_cooldown) + if(tunnel) + tunnel = FALSE + to_chat(src, SPAN_NOTICE("We stop tunneling.")) + used_tunnel = TRUE + addtimer(CALLBACK(src, PROC_REF(do_tunnel_cooldown)), (caste ? caste.tunnel_cooldown : 5 SECONDS)) return - if(used_digging) - to_chat(xeno, SPAN_NOTICE("We must wait some time to do this.")) + if(used_tunnel) + to_chat(src, SPAN_NOTICE("We must wait some time to do this.")) return - if(!target_atom) - to_chat(xeno, SPAN_NOTICE("We can't tunnel there!")) + if(!target) + to_chat(src, SPAN_NOTICE("We can't tunnel there!")) return - if(target_atom.density) - to_chat(xeno, SPAN_XENOWARNING("We can't tunnel into a solid wall!")) + if(target.density) + to_chat(src, SPAN_XENOWARNING("We can't tunnel into a solid wall!")) return - if(istype(target_atom, /turf/open/space)) - to_chat(xeno, SPAN_XENOWARNING("We make tunnels, not wormholes!")) + if(istype(target, /turf/open/space)) + to_chat(src, SPAN_XENOWARNING("We make tunnels, not wormholes!")) return - if(xeno.clone) //Prevents tunnels in Z transition areas - to_chat(xeno, SPAN_XENOWARNING("We make tunnels, not wormholes!")) + if(clone) //Prevents tunnels in Z transition areas + to_chat(src, SPAN_XENOWARNING("We make tunnels, not wormholes!")) return - var/area/area_to_get = get_area(target_atom) - if(area_to_get.flags_area & AREA_NOBURROW || get_dist(xeno, target_atom) > 15) - to_chat(xeno, SPAN_XENOWARNING("There's no way to tunnel over there.")) + var/area/area_to_get = get_area(target) + if(area_to_get.flags_area & AREA_NOBURROW || get_dist(src, target) > 15) + to_chat(src, SPAN_XENOWARNING("There's no way to tunnel over there.")) return - for(var/obj/objects_in_turf in target_atom.contents) + for(var/obj/objects_in_turf in target.contents) if(objects_in_turf.density) if(objects_in_turf.flags_atom & ON_BORDER) continue - to_chat(xeno, SPAN_WARNING("There's something solid there to stop us from emerging.")) + to_chat(src, SPAN_WARNING("There's something solid there to stop us from emerging.")) return - if(!target_atom || target_atom.density) - to_chat(xeno, SPAN_NOTICE("We cannot tunnel to there!")) - ADD_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING, TRAIT_SOURCE_ABILITY("burrow_digging")) - to_chat(xeno, SPAN_NOTICE("We start tunneling!")) - var/target_distance = max(get_dist(xeno, target_atom), 1) // Min distance of 1 is to prevent stunlocking - digging_timer = (target_distance * 10) + world.time - process_digging(target_atom) + if(!target || target.density) + to_chat(src, SPAN_NOTICE("We cannot tunnel to there!")) + tunnel = TRUE + to_chat(src, SPAN_NOTICE("We start tunneling!")) + var/target_distance = max(get_dist(src, target), 1) // Min distance of 1 is to prevent stunlocking + tunnel_timer = (target_distance*10) + world.time + process_tunnel(target) -/datum/action/xeno_action/activable/burrow/proc/process_digging(turf/target_atom) - var/mob/living/carbon/xenomorph/xeno = owner - if(!HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING)) +/mob/living/carbon/xenomorph/proc/process_tunnel(turf/target) + if(!tunnel) return - if(world.time > digging_timer) - REMOVE_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING, TRAIT_SOURCE_ABILITY("burrow_digging")) - do_digging(target_atom) - if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROW_DIGGING) && target_atom) - addtimer(CALLBACK(src, PROC_REF(process_digging), target_atom), 1 SECONDS) - -/datum/action/xeno_action/activable/burrow/proc/do_digging(turf/target_atom) - var/mob/living/carbon/xenomorph/xeno = owner + if(world.time > tunnel_timer) + tunnel = FALSE + do_tunnel(target) + if(tunnel && target) + addtimer(CALLBACK(src, PROC_REF(process_tunnel), target), 1 SECONDS) - to_chat(xeno, SPAN_NOTICE("We tunnel to the destination.")) - xeno.anchored = FALSE - xeno.forceMove(target_atom) +/mob/living/carbon/xenomorph/proc/do_tunnel(turf/target) + to_chat(src, SPAN_NOTICE("We tunnel to the destination.")) + anchored = FALSE + forceMove(target) burrow_off() -/datum/action/xeno_action/activable/burrow/proc/do_digging_cooldown() - var/mob/living/carbon/xenomorph/xeno = owner +/mob/living/carbon/xenomorph/proc/do_tunnel_cooldown() + used_tunnel = FALSE + to_chat(src, SPAN_NOTICE("We can now tunnel while burrowed.")) + for(var/X in actions) + var/datum/action/act = X + act.update_button_icon() - used_digging = FALSE - to_chat(xeno, SPAN_NOTICE("We can now tunnel while burrowed.")) - update_button_icon() +/mob/living/carbon/xenomorph/proc/rename_tunnel(obj/structure/tunnel/tunnel_target in oview(1)) + set name = "Rename Tunnel" + set desc = "Rename the tunnel." + set category = null + + if(!istype(tunnel_target)) + return + var/new_name = strip_html(input("Change the description of the tunnel:", "Tunnel Description") as text|null) + new_name = replace_non_alphanumeric_plus(new_name) + if(new_name) + new_name = "[new_name] ([get_area_name(tunnel_target)])" + log_admin("[key_name(src)] has renamed the tunnel \"[tunnel_target.tunnel_desc]\" as \"[new_name]\".") + msg_admin_niche("[src]/([key_name(src)]) has renamed the tunnel \"[tunnel_target.tunnel_desc]\" as \"[new_name]\".") + tunnel_target.tunnel_desc = "[new_name]" + return +/datum/action/xeno_action/onclick/tremor/use_ability(atom/target) + var/mob/living/carbon/xenomorph/burrower_tremor = owner + + if(HAS_TRAIT(burrower_tremor, TRAIT_ABILITY_BURROWED)) + to_chat(burrower_tremor, SPAN_XENOWARNING("We must be above ground to do this.")) + return + + if(burrower_tremor.is_ventcrawling) + to_chat(burrower_tremor, SPAN_XENOWARNING("We must be above ground to do this.")) + return -/datum/action/xeno_action/onclick/tremor/use_ability(atom/target_atom) - var/mob/living/carbon/xenomorph/xeno = owner + if(!action_cooldown_check()) + return - if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) - to_chat(xeno, SPAN_XENOWARNING("We must be above ground to do this.")) + if(!burrower_tremor.check_state()) return - if(xeno.is_ventcrawling) - to_chat(xeno, SPAN_XENOWARNING("We must be above ground to do this.")) + if(!check_and_use_plasma_owner()) return - XENO_ACTION_CHECK_USE_PLASMA(xeno) + playsound(burrower_tremor, 'sound/effects/alien_footstep_charge3.ogg', 75, 0) + to_chat(burrower_tremor, SPAN_XENOWARNING("We dig ourselves into the ground and cause tremors.")) + burrower_tremor.create_stomp() - playsound(xeno, 'sound/effects/alien_footstep_charge3.ogg', 75, 0) - to_chat(xeno, SPAN_XENOWARNING("We dig ourselves into the ground and cause tremors.")) - xeno.create_stomp() - for(var/mob/living/carbon/carbon_target in range(7, xeno)) + for(var/mob/living/carbon/carbon_target in range(7, burrower_tremor)) to_chat(carbon_target, SPAN_WARNING("You struggle to remain on your feet as the ground shakes beneath your feet!")) shake_camera(carbon_target, 2, 3) - if(get_dist(xeno, carbon_target) <= 3 && !xeno.can_not_harm(carbon_target)) + if(get_dist(burrower_tremor, carbon_target) <= 3 && !burrower_tremor.can_not_harm(carbon_target)) if(carbon_target.mob_size >= MOB_SIZE_BIG) carbon_target.apply_effect(1, SLOW) else @@ -299,97 +337,96 @@ apply_cooldown() return ..() +/datum/action/xeno_action/onclick/build_tunnel/use_ability(atom/A) + var/mob/living/carbon/xenomorph/xenomorph = owner + if(!xenomorph.check_state()) + return - -/datum/action/xeno_action/onclick/build_tunnel/use_ability(atom/target_atom) - var/mob/living/carbon/xenomorph/xeno = owner - - XENO_ACTION_CHECK(xeno) - - if(xeno.action_busy) - to_chat(xeno, SPAN_XENOWARNING("We should finish up what we're doing before digging.")) + if(xenomorph.action_busy) + to_chat(xenomorph, SPAN_XENOWARNING("We should finish up what we're doing before digging.")) return - var/turf/turf = xeno.loc + var/turf/turf = xenomorph.loc if(!istype(turf)) //logic - to_chat(xeno, SPAN_XENOWARNING("We can't do that from there.")) + to_chat(xenomorph, SPAN_XENOWARNING("We can't do that from there.")) return var/area/current_area = get_area(turf) if(!turf.can_dig_xeno_tunnel() || !is_ground_level(turf.z) || current_area.flags_area & AREA_NOTUNNEL) - to_chat(xeno, SPAN_XENOWARNING("We scrape around, but we can't seem to dig through that kind of floor.")) + to_chat(xenomorph, SPAN_XENOWARNING("We scrape around, but we can't seem to dig through that kind of floor.")) return - if(locate(/obj/structure/tunnel) in xeno.loc) - to_chat(xeno, SPAN_XENOWARNING("There already is a tunnel here.")) + if(locate(/obj/structure/tunnel) in xenomorph.loc) + to_chat(xenomorph, SPAN_XENOWARNING("There already is a tunnel here.")) return - if(locate(/obj/structure/machinery/sentry_holder/landing_zone) in xeno.loc) - to_chat(xeno, SPAN_XENOWARNING("We can't dig a tunnel with this object in the way.")) + if(locate(/obj/structure/machinery/sentry_holder/landing_zone) in xenomorph.loc) + to_chat(xenomorph, SPAN_XENOWARNING("We can't dig a tunnel with this object in the way.")) return - if(xeno.tunnel_delay) - to_chat(xeno, SPAN_XENOWARNING("We are not ready to dig a tunnel again.")) + if(xenomorph.tunnel_delay) + to_chat(xenomorph, SPAN_XENOWARNING("We are not ready to dig a tunnel again.")) return - if(xeno.get_active_hand()) - to_chat(xeno, SPAN_XENOWARNING("We need an empty claw for this!")) + if(xenomorph.get_active_hand()) + to_chat(xenomorph, SPAN_XENOWARNING("We need an empty claw for this!")) return - if(!xeno.check_plasma(plasma_cost)) + if(!xenomorph.check_plasma(plasma_cost)) return - var/area/target_area = get_area(turf) + var/area/AR = get_area(turf) - if(isnull(target_area) || !(target_area.is_resin_allowed)) - if(!target_area || target_area.flags_area & AREA_UNWEEDABLE) - to_chat(xeno, SPAN_XENOWARNING("This area is unsuited to host the hive!")) + if(isnull(AR) || !(AR.is_resin_allowed)) + if(!AR || AR.flags_area & AREA_UNWEEDABLE) + to_chat(xenomorph, SPAN_XENOWARNING("This area is unsuited to host the hive!")) return - to_chat(xeno, SPAN_XENOWARNING("It's too early to spread the hive this far.")) + to_chat(xenomorph, SPAN_XENOWARNING("It's too early to spread the hive this far.")) return - xeno.visible_message(SPAN_XENONOTICE("[xeno] begins digging out a tunnel entrance."), + xenomorph.visible_message(SPAN_XENONOTICE("[xenomorph] begins digging out a tunnel entrance."), SPAN_XENONOTICE("We begin digging out a tunnel entrance."), null, 5) - if(!do_after(xeno, 10 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) - to_chat(xeno, SPAN_WARNING("Our tunnel caves in as we stop digging it.")) + if(!do_after(xenomorph, 10 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) + to_chat(xenomorph, SPAN_WARNING("Our tunnel caves in as we stop digging it.")) return - if(!xeno.check_plasma(plasma_cost)) + if(!xenomorph.check_plasma(plasma_cost)) return - xeno.visible_message(SPAN_XENONOTICE("\The [xeno] digs out a tunnel entrance."), + xenomorph.visible_message(SPAN_XENONOTICE("\The [xenomorph] digs out a tunnel entrance."), SPAN_XENONOTICE("We dig out an entrance to the tunnel network."), null, 5) - var/obj/structure/tunnel/tunnelobj = new(turf, xeno.hivenumber) - xeno.tunnel_delay = 1 - addtimer(CALLBACK(xeno, PROC_REF(cooldown_end)), 4 MINUTES) + var/obj/structure/tunnel/tunnelobj = new(turf, xenomorph.hivenumber) + xenomorph.tunnel_delay = 1 + addtimer(CALLBACK(src, PROC_REF(cooldown_end)), 4 MINUTES) var/msg = strip_html(input("Add a description to the tunnel:", "Tunnel Description") as text|null) msg = replace_non_alphanumeric_plus(msg) var/description if(msg) description = msg msg = "[msg] ([get_area_name(tunnelobj)])" - log_admin("[key_name(xeno)] has named a new tunnel \"[msg]\".") - msg_admin_niche("[xeno]/([key_name(xeno)]) has named a new tunnel \"[msg]\".") + log_admin("[key_name(xenomorph)] has named a new tunnel \"[msg]\".") + msg_admin_niche("[xenomorph]/([key_name(xenomorph)]) has named a new tunnel \"[msg]\".") tunnelobj.tunnel_desc = "[msg]" - if(xeno.hive.living_xeno_queen || xeno.hive.allow_no_queen_actions) - for(var/mob/living/carbon/xenomorph/target_for_message as anything in xeno.hive.totalXenos) + if(xenomorph.hive.living_xeno_queen || xenomorph.hive.allow_no_queen_actions) + for(var/mob/living/carbon/xenomorph/target_for_message as anything in xenomorph.hive.totalXenos) var/overwatch_target = XENO_OVERWATCH_TARGET_HREF var/overwatch_src = XENO_OVERWATCH_SRC_HREF - to_chat(target_for_message, SPAN_XENOANNOUNCE("Hive: A new tunnel[description ? " ([description])" : ""] has been created by [xeno] (watch) at [get_area_name(tunnelobj)].")) + to_chat(target_for_message, SPAN_XENOANNOUNCE("Hive: A new tunnel[description ? " ([description])" : ""] has been created by [xenomorph] (watch) at [get_area_name(tunnelobj)].")) - xeno.use_plasma(plasma_cost) - to_chat(xeno, SPAN_NOTICE("We will be ready to dig a new tunnel in 4 minutes.")) - playsound(xeno.loc, 'sound/weapons/pierce.ogg', 25, 1) + xenomorph.use_plasma(plasma_cost) + to_chat(xenomorph, SPAN_NOTICE("We will be ready to dig a new tunnel in 4 minutes.")) + playsound(xenomorph.loc, 'sound/weapons/pierce.ogg', 25, 1) apply_cooldown() return ..() + /datum/action/xeno_action/onclick/build_tunnel/proc/cooldown_end() - var/mob/living/carbon/xenomorph/xeno = owner - to_chat(xeno, SPAN_NOTICE("We are ready to dig a tunnel again.")) - xeno.tunnel_delay = 0 + var/mob/living/carbon/xenomorph/xenomorph = owner + to_chat(xenomorph, SPAN_NOTICE("We are ready to dig a tunnel again.")) + xenomorph.tunnel_delay = 0 -/mob/living/carbon/xenomorph/burrower/try_fill_trap(obj/effect/alien/resin/trap/target_trap) +/mob/living/carbon/xenomorph/burrower/try_fill_trap(obj/effect/alien/resin/trap/target) . = ..() if(.) - target_trap.set_state(RESIN_TRAP_ACID3) + target.set_state(RESIN_TRAP_ACID3) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm b/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm index b9a4facaaa36..f3bcd560ed8b 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm @@ -103,6 +103,8 @@ /// if fire_immunity is set to be vulnerable, how much will fire damage be multiplied. Defines in xeno.dm var/fire_vulnerability_mult = 0 + var/burrow_cooldown = 5 SECONDS + var/tunnel_cooldown = 10 SECONDS ///whether the xeno heals even outside weeds. var/innate_healing = FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm index 9c875e53c930..d59ad11f8eb0 100644 --- a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm +++ b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm @@ -1,6 +1,4 @@ /mob/living/carbon/xenomorph/attackby(obj/item/item, mob/user) - if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - return if(user.a_intent != INTENT_HELP) return ..() if(HAS_TRAIT(item, TRAIT_TOOL_MULTITOOL) && ishuman(user)) @@ -47,8 +45,6 @@ return ..() /mob/living/carbon/xenomorph/ex_act(severity, direction, datum/cause_data/cause_data, pierce=0, enviro=FALSE) - if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - return if(body_position == LYING_DOWN && direction) severity *= EXPLOSION_PRONE_MULTIPLIER diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index cbef42edd2c8..f1fa746647e7 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -952,9 +952,6 @@ if(evasion > 0) . -= evasion - if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - return 0 - /obj/projectile/proc/play_hit_effect(mob/hit_mob) if(ammo.sound_hit)