diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 3df635790a5e2..c178353ece1cc 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,31 @@ #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. +/// Xenos with this trait cannot spit multiple times. +#define TRAIT_ABILITY_SPITTING "t_ability_charge_spitting" + + +// -- specific ability traits -- +#define TRAIT_ABILITY_POUNCE "t_ability_pounce" +#define TRAIT_ABILITY_ASSASINATE "t_ability_assasinate" +#define TRAIT_ABILITY_INVIS "t_ability_invis" +#define TRAIT_ABILITY_LUNGE "t_ability_lunge" +#define TRAIT_ABILITY_BURROW_DIGGING "t_ability_burrow_digging" +#define TRAIT_ABILITY_BURROW_UNDERGROUND "t_ability_burrow_underground" +#define TRAIT_ABILITY_CREST "t_ability_burrower_crest" +#define TRAIT_ABILITY_FORTIFY "t_ability_fortify" +#define TRAIT_ABILITY_POUNCE_CHARGE "t_ability_pounce_charge" +#define TRAIT_ABILITY_PRE_EMPOWER "t_ability_pre_empower" +#define TRAIT_ABILITY_EMPOWER "t_ability_empower" +#define TRAIT_ABILITY_CATALYZE_EMPOWER "t_ability_catalyze_empower" +#define TRAIT_ABILITY_CLEAVE_ROOT "t_ability_cleave_root" +#define TRAIT_ABILITY_CLEAVE_BUFFED "t_ability_cleave_buffed" +#define TRAIT_ABILITY_PRE_DASH "t_ability_pre_dash" +#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/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 05c0dfc563ff8..ebea5c56e83f0 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -89,6 +89,7 @@ if(!new_maptext) return maptext_overlay = image(null, null, null, layer + 0.1) + maptext_overlay.appearance_flags |= RESET_COLOR maptext_overlay.maptext = new_maptext if(new_maptext_x) maptext_overlay.maptext_x = new_maptext_x diff --git a/code/datums/action.dm b/code/datums/action.dm index ad77899663428..3ab28917e559c 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -663,3 +663,5 @@ if(reload_screen) client.add_to_screen(hud_used.hide_actions_toggle) +#define XENO_ACTION_CHECK(X) if(!X.check_state() || !action_cooldown_check() || !check_plasma_owner(src.plasma_cost)) return +#define XENO_ACTION_CHECK_USE_PLASMA(X) if(!X.check_state() || !action_cooldown_check() || !check_and_use_plasma_owner(src.plasma_cost)) return diff --git a/code/modules/mob/living/carbon/xenomorph/Evolution.dm b/code/modules/mob/living/carbon/xenomorph/Evolution.dm index ff5348756c8ae..4e26134fe77fa 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(fortify || crest_defense || stealth || HAS_TRAIT(src, TRAIT_ABILITY_ENCLOSED_PLATES) || HAS_TRAIT(src, TRAIT_ABILITY_REFLECTIVE_PLATES)) + if(HAS_TRAIT(src, TRAIT_ABILITY_FORTIFY) || HAS_TRAIT(src, TRAIT_ABILITY_CREST) || 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 @@ -326,7 +326,7 @@ GLOBAL_LIST_EMPTY(deevolved_ckeys) if(tier == 0 || tier == 4) to_chat(src, SPAN_XENOWARNING("We can't transmute.")) return - if(fortify || crest_defense || stealth) + if(HAS_TRAIT(src, TRAIT_ABILITY_FORTIFY) || HAS_TRAIT(src, TRAIT_ABILITY_CREST) || HAS_TRAIT(src, TRAIT_ABILITY_INVIS) || HAS_TRAIT(src, TRAIT_ABILITY_ENCLOSED_PLATES) || HAS_TRAIT(src, TRAIT_ABILITY_REFLECTIVE_PLATES)) 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 816ba1fb8c7f4..b8356f5aefdf3 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) @@ -109,7 +112,7 @@ //Hot hot Aliens on Aliens action. //Actually just used for eating people. /mob/living/carbon/xenomorph/attack_alien(mob/living/carbon/xenomorph/xeno) - if(xeno.fortify || HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED) || HAS_TRAIT(xeno, TRAIT_ABILITY_REFLECTIVE_PLATES)) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_FORTIFY) || HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) return XENO_NO_DELAY_ACTION if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index ce4d8f9c4af50..28024c8522f50 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -293,11 +293,6 @@ // ////////////////////////////////////////////////////////////////// - var/tunnel = FALSE - /// for check on lurker invisibility - var/stealth = FALSE - var/fortify = FALSE - var/crest_defense = FALSE /// For drones/hivelords. Extends the maximum build range they have var/extra_build_dist = 0 /// tiles from self you can plant eggs. @@ -362,14 +357,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] @@ -827,7 +814,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) @@ -854,7 +841,6 @@ 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." @@ -872,7 +858,6 @@ tunnel_target.tunnel_desc = "[new_name]" return - /mob/living/carbon/xenomorph/prepare_huds() ..() //updating all the mob's hud images 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 0ea27be28d18d..933bd6effe86c 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,17 +8,12 @@ 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 - - if(HAS_TRAIT(xenomorph, TRAIT_ABILITY_BURROWED)) - xenomorph.tunnel(get_turf(A)) - else - xenomorph.burrow() - return ..() + var/burrow_cooldown = 2 SECONDS + var/digging_cooldown = 7 SECONDS /datum/action/xeno_action/onclick/tremor name = "Tremor (100)" diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_abilities.dm index ed9ad321ce4b0..c4add8fcc7d91 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_abilities.dm @@ -5,12 +5,6 @@ action_type = XENO_ACTION_CLICK ability_primacy = XENO_PRIMARY_ACTION_3 -/datum/action/xeno_action/activable/throw_hugger/action_cooldown_check() - if(owner) - var/mob/living/carbon/xenomorph/carrier/alien = owner - return world.time >= alien.hugger_throw_cooldown // i think - return TRUE //When we first add the ability we still do this check, but owner is null, so a workaround - /datum/action/xeno_action/activable/retrieve_egg name = "Retrieve Egg" action_icon_state = "retrieve_egg" diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_abilities.dm index eae9b09a18551..5bdd9d05646ee 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_abilities.dm @@ -24,14 +24,6 @@ // Object types that don't reduce cooldown when hit var/list/not_reducing_objects = list() - -/datum/action/xeno_action/activable/pounce/crusher_charge/New() - . = ..() - not_reducing_objects = typesof(/obj/structure/barricade) + typesof(/obj/structure/machinery/defenses) - -/datum/action/xeno_action/activable/pounce/crusher_charge/initialize_pounce_pass_flags() - pounce_pass_flags = PASS_CRUSHER_CHARGE - /datum/action/xeno_action/onclick/crusher_stomp name = "Stomp" action_icon_state = "stomp" @@ -119,137 +111,6 @@ var/momentum = 0 -/datum/action/xeno_action/onclick/charger_charge/proc/handle_position_change(mob/living/carbon/xenomorph/xeno, body_position) - SIGNAL_HANDLER - if(body_position == LYING_DOWN) - handle_movement(xeno) - -/datum/action/xeno_action/onclick/charger_charge/proc/handle_movement(mob/living/carbon/xenomorph/Xeno, atom/oldloc, dir, forced) - SIGNAL_HANDLER - if(Xeno.pulling) - if(!momentum) - steps_taken = 0 - return - else - Xeno.stop_pulling() - - if(Xeno.is_mob_incapacitated()) - if(!momentum) - return - var/distance_to_throw = get_ranged_target_turf(Xeno, charge_dir, momentum/2) - INVOKE_ASYNC(Xeno, TYPE_PROC_REF(/atom/movable, throw_atom), distance_to_throw, momentum/2, SPEED_FAST, null, TRUE) - stop_momentum() - return - if(!isturf(Xeno.loc)) - stop_momentum() - return - // Don't build up charge if you move via getting propelled by something - if(Xeno.throwing) - stop_momentum() - return - - var/do_stop_momentum = FALSE - - // Need to be constantly moving in order to maintain charge - if(world.time > last_charge_move + 0.5 SECONDS) - do_stop_momentum = TRUE - if(dir != charge_dir) - charge_dir = dir - do_stop_momentum = TRUE - - if(do_stop_momentum) - stop_momentum() - if(Xeno.plasma_stored <= plasma_per_step) - stop_momentum() - return - last_charge_move = world.time - steps_taken++ - if(steps_taken < steps_to_charge) - return - if(momentum < max_momentum) - momentum++ - ADD_TRAIT(Xeno, TRAIT_CHARGING, TRAIT_SOURCE_XENO_ACTION_CHARGE) - Xeno.update_icons() - if(momentum == max_momentum) - Xeno.emote("roar") - //X.use_plasma(plasma_per_step) // take if you are in toggle charge mode - if(momentum > 0) - Xeno.use_plasma(plasma_per_step) // take plasma when you have momentum - - noise_timer = noise_timer ? --noise_timer : 3 - if(noise_timer == 3) - playsound(Xeno, 'sound/effects/alien_footstep_charge1.ogg', 50) - - for(var/mob/living/carbon/human/Mob in Xeno.loc) - if(Mob.body_position == LYING_DOWN && Mob.stat != DEAD) - Xeno.visible_message(SPAN_DANGER("[Xeno] runs [Mob] over!"), - SPAN_DANGER("We run [Mob] over!") - ) - var/ram_dir = pick(get_perpen_dir(Xeno.dir)) - var/dist = 1 - if(momentum == max_momentum) - dist = momentum * 0.25 - step(Mob, ram_dir, dist) - Mob.take_overall_armored_damage(momentum * 6) - INVOKE_ASYNC(Mob, TYPE_PROC_REF(/mob/living/carbon/human, emote),"pain") - shake_camera(Mob, 7,3) - animation_flash_color(Mob) - - Xeno.recalculate_speed() - -/datum/action/xeno_action/onclick/charger_charge/proc/handle_dir_change(datum/source, old_dir, new_dir) - SIGNAL_HANDLER - if(new_dir != charge_dir) - charge_dir = new_dir - if(momentum) - stop_momentum() - -/datum/action/xeno_action/onclick/charger_charge/proc/handle_river(datum/source, covered) - SIGNAL_HANDLER - if(!covered) - stop_momentum() - -/datum/action/xeno_action/onclick/charger_charge/proc/update_speed(mob/living/carbon/xenomorph/Xeno) - SIGNAL_HANDLER - Xeno.speed += momentum * speed_per_momentum - -/datum/action/xeno_action/onclick/charger_charge/proc/stop_momentum(datum/source) - SIGNAL_HANDLER - var/mob/living/carbon/xenomorph/Xeno = owner - if(momentum == max_momentum) - Xeno.visible_message(SPAN_DANGER("[Xeno] skids to a halt!")) - - REMOVE_TRAIT(Xeno, TRAIT_CHARGING, TRAIT_SOURCE_XENO_ACTION_CHARGE) - steps_taken = 0 - momentum = 0 - Xeno.recalculate_speed() - Xeno.update_icons() - -/datum/action/xeno_action/onclick/charger_charge/proc/lose_momentum(amount) - if(amount >= momentum) - stop_momentum() - else - momentum -= amount - var/mob/living/carbon/xenomorph/Xeno = owner - Xeno.recalculate_speed() - -/datum/action/xeno_action/onclick/charger_charge/proc/handle_collision(mob/living/carbon/xenomorph/Xeno, atom/tar) - SIGNAL_HANDLER - if(!momentum) - stop_momentum() - return - - var/result = tar.handle_charge_collision(Xeno, src) - switch(result) - if(XENO_CHARGE_TRY_MOVE) - if(step(Xeno, charge_dir)) - return COMPONENT_LIVING_COLLIDE_HANDLED - -/datum/action/xeno_action/onclick/charger_charge/proc/start_charging(datum/source) - SIGNAL_HANDLER - steps_taken = steps_to_charge - - /datum/action/xeno_action/activable/tumble name = "Tumble" action_icon_state = "tumble" diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm index 13cacd7929595..e92eccd9393fb 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm @@ -261,6 +261,21 @@ /datum/action/xeno_action/activable/pounce/proc/pre_pounce_effects() return +/** + * Effects to apply before "thrown" xeno to choosen tile. + */ +/datum/action/xeno_action/activable/pounce/proc/start_airbone() + return + +/** + * Effects to apply after xeno is "thrown" to choosen tile. + */ +/datum/action/xeno_action/activable/pounce/proc/end_airbone() + var/mob/living/carbon/xenomorph/xeno = owner + + if(HAS_TRAIT(xeno, TRAIT_ABILITY_POUNCE)) + REMOVE_TRAIT(xeno, TRAIT_ABILITY_POUNCE, TRAIT_SOURCE_ABILITY("pounce")) + /datum/action/xeno_action/activable/pounce/proc/end_pounce_freeze() if(freeze_timer_id == TIMER_ID_NULL) return @@ -461,8 +476,6 @@ no_cooldown_msg = TRUE // Currently [14.6.25], every xeno that uses this save Boiler has a cooldown far too fast for messages to be worth it ability_uses_acid_overlay = TRUE - /// Var that keeps track of in-progress wind-up spits like Bombard to prevent spitting multiple spits at the same time - var/spitting = FALSE var/sound_to_play = "acid_spit" var/aim_turf = FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm index ec981e3d9ce13..170ba0b96150d 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm @@ -3,12 +3,11 @@ // and abilities files hold the object declarations for the abilities // Plant weeds -/datum/action/xeno_action/onclick/plant_weeds/use_ability(atom/atom) +/datum/action/xeno_action/onclick/plant_weeds/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) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) return @@ -70,8 +69,7 @@ to_chat(xeno, SPAN_XENOWARNING("It's too early to spread the hive this far.")) return - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) var/list/to_convert if(node) @@ -98,7 +96,7 @@ to_chat(src, SPAN_WARNING("No time to rest, must KILL!")) return - if(fortify) + if(HAS_TRAIT(src, TRAIT_ABILITY_FORTIFY)) to_chat(src, SPAN_WARNING("We cannot rest while fortified!")) return @@ -106,7 +104,7 @@ to_chat(src, SPAN_WARNING("We cannot rest while burrowed!")) return - if(crest_defense) + if(HAS_TRAIT(src, TRAIT_ABILITY_CREST)) to_chat(src, SPAN_WARNING("We cannot rest while our crest is down!")) return @@ -128,17 +126,16 @@ return ..() -/datum/action/xeno_action/onclick/xeno_resting/use_ability(atom/target) +/datum/action/xeno_action/onclick/xeno_resting/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner xeno.lay_down() button.icon_state = xeno.resting ? "template_active" : "template_xeno" return ..() // Shift spits -/datum/action/xeno_action/onclick/shift_spits/use_ability(atom/atom) +/datum/action/xeno_action/onclick/shift_spits/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if(!xeno.check_state()) - return + XENO_ACTION_CHECK(xeno) for(var/i in 1 to length(xeno.caste.spit_types)) if(xeno.ammo == GLOB.ammo_list[xeno.caste.spit_types[i]]) if(i == length(xeno.caste.spit_types)) @@ -151,10 +148,10 @@ button.overlays += image('icons/mob/hud/actions_xeno.dmi', button, "shift_spit_[xeno.ammo.icon_state]") return ..() -/datum/action/xeno_action/onclick/release_haul/use_ability(atom/atom) +/datum/action/xeno_action/onclick/release_haul/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if(!xeno.check_state()) - return + + XENO_ACTION_CHECK(xeno) if(!isturf(xeno.loc)) to_chat(xeno, SPAN_WARNING("We cannot put them down here.")) @@ -167,11 +164,10 @@ /datum/action/xeno_action/onclick/release_haul/can_use_action() return TRUE //we should always be able to do this -/datum/action/xeno_action/onclick/choose_resin/use_ability(atom/atom) +/datum/action/xeno_action/onclick/choose_resin/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if(!xeno.check_state()) - return + XENO_ACTION_CHECK(xeno) tgui_interact(xeno) return ..() @@ -190,13 +186,13 @@ var/list/constructions = list() for(var/type in xeno.resin_build_order) var/list/entry = list() - var/datum/resin_construction/RC = GLOB.resin_constructions_list[type] + var/datum/resin_construction/resin_const = GLOB.resin_constructions_list[type] - entry["name"] = RC.name - entry["desc"] = RC.desc - entry["image"] = replacetext(RC.construction_name, " ", "-") - entry["plasma_cost"] = RC.cost - entry["max_per_xeno"] = RC.max_per_xeno + entry["name"] = resin_const.name + entry["desc"] = resin_const.desc + entry["image"] = replacetext(resin_const.construction_name, " ", "-") + entry["plasma_cost"] = resin_const.cost + entry["max_per_xeno"] = resin_const.max_per_xeno entry["id"] = "[type]" constructions += list(entry) @@ -257,21 +253,21 @@ button.overlays += image('icons/mob/hud/xeno_building.dmi', button, resin_construction.construction_name) // Resin -/datum/action/xeno_action/activable/secrete_resin/use_ability(atom/target) +/datum/action/xeno_action/activable/secrete_resin/use_ability(atom/target_atom) if(!..()) return FALSE var/mob/living/carbon/xenomorph/xeno_owner = owner - if(isstorage(target.loc)) + if(isstorage(target_atom.loc)) return FALSE - if(xeno_owner.contains(target)) + if(xeno_owner.contains(target_atom)) return FALSE - if(istype(target, /atom/movable/screen)) + if(istype(target_atom, /atom/movable/screen)) return FALSE - if(!SSmapping.same_z_map(target.z, xeno_owner.z)) + if(!SSmapping.same_z_map(target_atom.z, xeno_owner.z)) to_chat(owner, SPAN_XENOWARNING("This area is too far away to affect!")) return apply_cooldown() - switch(xeno_owner.build_resin(target, thick, make_message, plasma_cost != 0, build_speed_mod)) + switch(xeno_owner.build_resin(target_atom, thick, make_message, plasma_cost != 0, build_speed_mod)) if(SECRETE_RESIN_INTERRUPT) if(xeno_cooldown || xeno_cooldown_interrupt_penalty) apply_cooldown_override(xeno_cooldown + xeno_cooldown_interrupt_penalty) @@ -284,27 +280,26 @@ // leader Marker -/datum/action/xeno_action/activable/info_marker/use_ability(atom/atom, mods) +/datum/action/xeno_action/activable/info_marker/use_ability(atom/target_atom, mods) + var/mob/living/carbon/xenomorph/xeno = owner if(!..()) return FALSE if(mods[CLICK_CATCHER]) return - if(!action_cooldown_check()) - return + XENO_ACTION_CHECK(xeno) - var/mob/living/carbon/xenomorph/xeno = owner if(!xeno.check_state(TRUE)) - return FALSE + return - if(ismob(atom)) //anticheese : if they click a mob, it will cancel. + if(ismob(target_atom)) //anticheese : if they click a mob, it will cancel. to_chat(xeno, SPAN_XENOWARNING("We can't place resin markers on living things!")) return FALSE //this is because xenos have thermal vision and can see mobs through walls - which would negate not being able to place them through walls - if(isstorage(atom.loc) || xeno.contains(atom) || istype(atom, /atom/movable/screen)) + if(isstorage(target_atom.loc) || xeno.contains(target_atom) || istype(target_atom, /atom/movable/screen)) return FALSE - var/turf/target_turf = get_turf(atom) + var/turf/target_turf = get_turf(target_atom) if(!SSmapping.same_z_map(xeno.loc.z, target_turf.loc.z)) to_chat(xeno, SPAN_XENOWARNING("Our mind cannot reach that far.")) @@ -316,24 +311,24 @@ var/tally = 0 - for(var/obj/effect/alien/resin/marker/MRK in xeno.hive.resin_marks) - if(MRK.createdby == xeno.nicknumber) + for(var/obj/effect/alien/resin/marker/target_marker in xeno.hive.resin_marks) + if(target_marker.createdby == xeno.nicknumber) tally++ if(tally >= max_markers) to_chat(xeno, SPAN_XENOWARNING("We have reached the maximum number of resin marks.")) var/list/promptlist = list("Yes", "No") - var/obj/effect/alien/resin/marker/Goober = null + var/obj/effect/alien/resin/marker/target_marker = null var/promptuser = null for(var/i=1, i<=length(xeno.hive.resin_marks)) - Goober = xeno.hive.resin_marks[i] - if(Goober.createdby == xeno.nicknumber) - promptuser = tgui_input_list(xeno, "Remove oldest placed mark: '[Goober.mark_meaning.name]!'?", "Mark limit reached.", promptlist, theme="hive_status") + target_marker = xeno.hive.resin_marks[i] + if(target_marker.createdby == xeno.nicknumber) + promptuser = tgui_input_list(xeno, "Remove oldest placed mark: '[target_marker.mark_meaning.name]!'?", "Mark limit reached.", promptlist, theme="hive_status") break i++ if(promptuser == "No") return else if(promptuser == "Yes") - qdel(Goober) + qdel(target_marker) if(xeno.make_marker(target_turf)) apply_cooldown() return TRUE @@ -344,10 +339,10 @@ // Destructive Acid -/datum/action/xeno_action/activable/corrosive_acid/use_ability(atom/target) +/datum/action/xeno_action/activable/corrosive_acid/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - xeno.corrosive_acid(target, acid_type, acid_plasma_cost) - for(var/obj/item/explosive/plastic/explosive in target.contents) + xeno.corrosive_acid(target_atom, acid_type, acid_plasma_cost) + for(var/obj/item/explosive/plastic/explosive in target_atom.contents) xeno.corrosive_acid(explosive,acid_type,acid_plasma_cost) return ..() @@ -357,17 +352,17 @@ /// Attempt to fill the target trap (called when xeno attacks with an empty hand) /// Returns TRUE if the trap was filled -/mob/living/carbon/xenomorph/proc/try_fill_trap(obj/effect/alien/resin/trap/target) - if(!istype(target)) +/mob/living/carbon/xenomorph/proc/try_fill_trap(obj/effect/alien/resin/trap/target_trap) + if(!istype(target_trap)) return FALSE if(!acid_level) - to_chat(src, SPAN_XENONOTICE("You can't secrete any acid into [target].")) + to_chat(src, SPAN_XENONOTICE("You can't secrete any acid into [target_trap].")) 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(target_trap.trap_type >= RESIN_TRAP_ACID1) + trap_acid_level = 1 + target_trap.trap_type - RESIN_TRAP_ACID1 if(trap_acid_level >= acid_level) to_chat(src, SPAN_XENONOTICE("It already has good acid in.")) @@ -388,8 +383,8 @@ 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(target_trap.trap_type >= RESIN_TRAP_ACID1) + trap_acid_level = 1 + target_trap.trap_type - RESIN_TRAP_ACID1 if(trap_acid_level >= acid_level) return FALSE @@ -399,11 +394,11 @@ use_plasma(acid_cost) - target.cause_data = create_cause_data("resin acid trap", src) - target.setup_tripwires() - target.set_state(RESIN_TRAP_ACID1 + acid_level - 1) + target_trap.cause_data = create_cause_data("resin acid trap", src) + target_trap.setup_tripwires() + target_trap.set_state(RESIN_TRAP_ACID1 + acid_level - 1) - playsound(target, 'sound/effects/refill.ogg', 25, 1) + playsound(target_trap, '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 @@ -412,7 +407,7 @@ #undef ACID_COST_LEVEL_2 #undef ACID_COST_LEVEL_3 -/datum/action/xeno_action/onclick/emit_pheromones/use_ability(atom/target) +/datum/action/xeno_action/onclick/emit_pheromones/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner if(!istype(xeno)) return @@ -439,7 +434,7 @@ if(pheromone == "help") to_chat(src, SPAN_NOTICE("
Pheromones provide a buff to all Xenos in range at the cost of some stored plasma every second, as follows:
Frenzy - Increased run speed, damage and chance to knock off headhunter masks.
Warding - While in critical state, increased maximum negative health and slower off weed bleedout.
Recovery - Increased plasma and health regeneration.
")) return - if(!pheromone || pheromone == "cancel" || current_aura || !check_state(1)) //If they are stacking windows, disable all input + if(!pheromone || pheromone == "cancel" || current_aura || !check_state(TRUE)) //If they are stacking windows, disable all input return else var/static/list/phero_selections = list("Help" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_help"), "Frenzy" = image(icon = 'icons/mob/radial.dmi', icon_state = "phero_frenzy"), "Warding" = image(icon = 'icons/mob/radial.dmi', icon_state = "phero_warding"), "Recovery" = image(icon = 'icons/mob/radial.dmi', icon_state = "phero_recov")) @@ -447,7 +442,7 @@ if(pheromone == "help") to_chat(src, SPAN_XENONOTICE("
Pheromones provide a buff to all Xenos in range at the cost of some stored plasma every second, as follows:
Frenzy (Red) - Increased run speed, damage and chance to knock off headhunter masks.
Warding (Green) - While in critical state, increased maximum negative health and slower off weed bleedout.
Recovery (Blue) - Increased plasma and health regeneration.
")) return - if(!pheromone || current_aura || !check_state(1)) //If they are stacking windows, disable all input + if(!pheromone || current_aura || !check_state(TRUE)) //If they are stacking windows, disable all input return if(pheromone) if(pheromone == current_aura) @@ -464,37 +459,35 @@ playsound(loc, "alien_drool", 25) if(isqueen(src) && hive && length(hive.xeno_leader_list) && anchored) - for(var/mob/living/carbon/xenomorph/L in hive.xeno_leader_list) - L.handle_xeno_leader_pheromones() + for(var/mob/living/carbon/xenomorph/leader_xeno in hive.xeno_leader_list) + leader_xeno.handle_xeno_leader_pheromones() -/datum/action/xeno_action/activable/pounce/use_ability(atom/target) +/datum/action/xeno_action/activable/pounce/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if(!action_cooldown_check()) + if(!istype(xeno)) return - if(!target) + XENO_ACTION_CHECK(xeno) + + if(!target_atom) return - while(istype(target, /turf/open_space)) - target = SSmapping.get_turf_below(target) + while(istype(target_atom, /turf/open_space)) + target_atom = SSmapping.get_turf_below(target_atom) - if(target.layer >= FLY_LAYER)//anything above that shouldn't be pounceable (hud stuff) + if(target_atom.layer >= FLY_LAYER)//anything above that shouldn't be pounceable (hud stuff) return if(!isturf(xeno.loc)) to_chat(xeno, SPAN_XENOWARNING("We can't [action_text] from here!")) return - if(!xeno.check_state()) - return - if(xeno.legcuffed) to_chat(xeno, SPAN_XENODANGER("We can't [action_text] with that thing on our leg!")) return - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) if(xeno.layer == XENO_HIDING_LAYER) //Xeno is currently hiding, unhide him var/datum/action/xeno_action/onclick/xenohide/hide = get_action(xeno, /datum/action/xeno_action/onclick/xenohide) @@ -504,13 +497,13 @@ if(isravager(xeno)) xeno.emote("roar") - if (!tracks_target) - target = get_turf(target) + if(!tracks_target) + target_atom = get_turf(target_atom) //everyone gets (extra) timer to pounce up - if(target.z != xeno.z) - var/maximum_z = max(target.z, xeno.z) - var/list/turf/path = get_line(locate(xeno.x, xeno.y, maximum_z), locate(target.x, target.y, maximum_z)) + if(target_atom.z != xeno.z) + var/maximum_z = max(target_atom.z, xeno.z) + var/list/turf/path = get_line(locate(xeno.x, xeno.y, maximum_z), locate(target_atom.x, target_atom.y, maximum_z)) for(var/turf/turf_in_path in path) while(istype(turf_in_path, /turf/open_space)) turf_in_path = SSmapping.get_turf_below(turf_in_path) @@ -524,43 +517,45 @@ to_chat(xeno, SPAN_WARNING("You can't jump over an object in your path.")) return - if (!do_after(xeno, 0.5 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + if(!do_after(xeno, 0.5 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) return - if(target.z != xeno.z && xeno.mob_size >= MOB_SIZE_BIG) - if (!do_after(xeno, 2 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) + if(target_atom.z != xeno.z && xeno.mob_size >= MOB_SIZE_BIG) + if(!do_after(xeno, 2 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) return apply_cooldown() - if (windup) - xeno.set_face_dir(get_cardinal_dir(xeno, target)) - if (!windup_interruptable) + if(windup) + xeno.set_face_dir(get_cardinal_dir(xeno, target_atom)) + if(!windup_interruptable) ADD_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Pounce")) xeno.anchored = TRUE pre_windup_effects() - if (!do_after(xeno, windup_duration, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + if(!do_after(xeno, windup_duration, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) to_chat(xeno, SPAN_XENODANGER("We cancel our [action_text]!")) - if (!windup_interruptable) + if(!windup_interruptable) REMOVE_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Pounce")) xeno.anchored = FALSE post_windup_effects(interrupted = TRUE) return - if (!windup_interruptable) + if(!windup_interruptable) REMOVE_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Pounce")) xeno.anchored = FALSE post_windup_effects() - xeno.visible_message(SPAN_XENOWARNING("[xeno] [action_text][findtext(action_text, "e", -1) || findtext(action_text, "p", -1) ? "s" : "es"] at [target]!"), SPAN_XENOWARNING("We [action_text] at [target]!")) + xeno.visible_message(SPAN_XENOWARNING("[xeno] [action_text][findtext(action_text, "e", -1) || findtext(action_text, "p", -1) ? "s" : "es"] at [target_atom]!"), SPAN_XENOWARNING("We [action_text] at [target_atom]!")) pre_pounce_effects() - xeno.pounce_distance = get_dist(xeno, target) - if(xeno.z != target.z) + xeno.pounce_distance = get_dist(xeno, target_atom) + if(xeno.z != target_atom.z) xeno.pounce_distance += 2 - xeno.throw_atom(target, distance, throw_speed, xeno, launch_type = LOW_LAUNCH, pass_flags = pounce_pass_flags, collision_callbacks = pounce_callbacks, tracking=TRUE) + start_airbone() + xeno.throw_atom(target_atom, distance, throw_speed, xeno, launch_type = LOW_LAUNCH, pass_flags = pounce_pass_flags, collision_callbacks = pounce_callbacks, tracking=TRUE) + end_airbone() xeno.update_icons() additional_effects_always() @@ -569,59 +564,51 @@ return TRUE // Massive, customizable spray_acid -/datum/action/xeno_action/activable/spray_acid/use_ability(atom/atom) +/datum/action/xeno_action/activable/spray_acid/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if(!action_cooldown_check()) - return + XENO_ACTION_CHECK(xeno) - if(!atom) + if(!target_atom) return - if(atom.layer >= FLY_LAYER) + if(target_atom.layer >= FLY_LAYER) return if(!isturf(xeno.loc)) to_chat(xeno, SPAN_XENOWARNING("We can't [action_text] from here!")) return - if(!xeno.check_state() || xeno.action_busy) + if(xeno.action_busy) return - if (activation_delay) + if(activation_delay) if(!do_after(xeno, activation_delay_length, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) to_chat(xeno, SPAN_XENOWARNING("We decide to cancel our acid spray.")) end_cooldown() return - if (!action_cooldown_check()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) apply_cooldown() - if(!check_and_use_plasma_owner()) - return - playsound(get_turf(xeno), 'sound/effects/refill.ogg', 25, 1) xeno.visible_message(SPAN_XENOWARNING("[xeno] vomits a flood of acid!"), SPAN_XENOWARNING("We vomit a flood of acid!"), null, 5) - apply_cooldown() - // Build our list of target turfs based on - if (spray_type == ACID_SPRAY_LINE) - xeno.do_acid_spray_line(get_line(xeno, atom, include_start_atom = FALSE), spray_effect_type, spray_distance) + if(spray_type == ACID_SPRAY_LINE) + xeno.do_acid_spray_line(get_line(xeno, target_atom, include_start_atom = FALSE), spray_effect_type, spray_distance) - else if (spray_type == ACID_SPRAY_CONE) - xeno.do_acid_spray_cone(get_turf(atom), spray_effect_type, spray_distance) + else if(spray_type == ACID_SPRAY_CONE) + xeno.do_acid_spray_cone(get_turf(target_atom), spray_effect_type, spray_distance) return ..() -/datum/action/xeno_action/onclick/xenohide/use_ability(atom/target) +/datum/action/xeno_action/onclick/xenohide/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner if(!xeno.check_state(TRUE)) return - if(!action_cooldown_check()) - return + XENO_ACTION_CHECK(xeno) if(xeno.action_busy) return if(xeno.layer != XENO_HIDING_LAYER) @@ -643,10 +630,9 @@ if(!QDELETED(source) && (new_stat >= UNCONSCIOUS && old_stat <= UNCONSCIOUS)) post_attack() -/datum/action/xeno_action/onclick/place_trap/use_ability(atom/target) +/datum/action/xeno_action/onclick/place_trap/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if(!xeno.check_state()) - return + XENO_ACTION_CHECK(xeno) if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) return @@ -655,6 +641,7 @@ if(!istype(turf)) to_chat(xeno, SPAN_XENOWARNING("We can't do that here.")) return + var/area/area = turf.loc if(!area?.is_resin_allowed) if(!area || area.flags_area & AREA_UNWEEDABLE) @@ -665,13 +652,14 @@ if(istype(area,/area/shuttle/drop1/lz1) || istype(area,/area/shuttle/drop2/lz2) || SSinterior.in_interior(owner)) to_chat(xeno, SPAN_WARNING("We sense this is not a suitable area for creating a resin hole.")) return + var/obj/effect/alien/weeds/alien_weeds = turf.check_xeno_trap_placement(xeno) if(!alien_weeds) return if(istype(alien_weeds, /obj/effect/alien/weeds/node)) to_chat(xeno, SPAN_NOTICE("We start uprooting the node so we can put the resin hole in its place...")) - if(!do_after(xeno, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC, target, INTERRUPT_ALL)) + if(!do_after(xeno, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC, target_atom, INTERRUPT_ALL)) return if(!turf.check_xeno_trap_placement(xeno)) return @@ -745,12 +733,11 @@ return alien_weeds -/datum/action/xeno_action/activable/place_construction/use_ability(atom/target) +/datum/action/xeno_action/activable/place_construction/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if(!xeno.check_state()) - return FALSE + XENO_ACTION_CHECK(xeno) - if(isstorage(target.loc) || xeno.contains(target) || istype(target, /atom/movable/screen)) + if(isstorage(target_atom.loc) || xeno.contains(target_atom) || istype(target_atom, /atom/movable/screen)) return FALSE if(!xeno.hive) @@ -777,7 +764,7 @@ to_chat(xeno, SPAN_DANGER("Something went wrong!")) CRASH("Something went wrong determining hive_pos during place_construction!") - var/turf/target_turf = get_turf(target) + var/turf/target_turf = get_turf(target_atom) var/area/target_area = get_area(target_turf) if(isnull(target_area) || !(target_area.is_resin_allowed)) @@ -787,7 +774,7 @@ to_chat(xeno, SPAN_XENOWARNING("It's too early to spread the hive this far.")) return FALSE - if(!SSmapping.same_z_map(target_turf.z, xeno.z)) + if(target_turf.z != xeno.z) to_chat(xeno, SPAN_XENOWARNING("This area is too far away to affect!")) return FALSE @@ -795,7 +782,6 @@ to_chat(xeno, SPAN_XENOWARNING("It's too tight in here to build.")) return FALSE - if(!xeno.check_alien_construction(target_turf)) return FALSE @@ -814,12 +800,12 @@ message += "[capitalize_first_letters(structure_name)] - [initial(structure_type.description)]
" to_chat(xeno, SPAN_NOTICE(message)) return TRUE - if(!xeno.check_state(TRUE) || !xeno.check_plasma(400)) + XENO_ACTION_CHECK(xeno) + if(!xeno.check_plasma(400)) return FALSE var/structure_type = xeno.hive.hive_structure_types[choice] var/datum/construction_template/xenomorph/structure_template = new structure_type() - if(!spacecheck(xeno, target_turf, structure_template)) // spacecheck already cleans up the template return FALSE @@ -889,74 +875,70 @@ // XSS Spacecheck -/datum/action/xeno_action/activable/place_construction/proc/spacecheck(mob/living/carbon/xenomorph/xeno, turf/turf, datum/construction_template/xenomorph/tem) +/datum/action/xeno_action/activable/place_construction/proc/spacecheck(mob/living/carbon/xenomorph/xeno, turf/target_turf, datum/construction_template/xenomorph/tem) if(tem.block_range) - for(var/turf/TA in range(tem.block_range, turf)) - if(!xeno.check_alien_construction(TA, FALSE, TRUE, ignore_nest = TRUE)) + for(target_turf in range(tem.block_range, target_turf)) + if(!xeno.check_alien_construction(target_turf, FALSE, TRUE, ignore_nest = TRUE)) to_chat(xeno, SPAN_WARNING("We need more open space to build here.")) qdel(tem) return FALSE - if(!xeno.check_alien_construction(turf, ignore_nest = TRUE)) + if(!xeno.check_alien_construction(target_turf, ignore_nest = TRUE)) to_chat(xeno, SPAN_WARNING("We need more open space to build here.")) qdel(tem) return FALSE - var/obj/effect/alien/weeds/alien_weeds = locate() in turf + var/obj/effect/alien/weeds/alien_weeds = locate() in target_turf if(!alien_weeds || alien_weeds.weed_strength < WEED_LEVEL_HIVE || alien_weeds.linked_hive.hivenumber != xeno.hivenumber) to_chat(xeno, SPAN_WARNING("We can only shape on [lowertext(GLOB.hive_datum[xeno.hivenumber].prefix)]hive weeds. We must find a hive node or core before we start building!")) qdel(tem) return FALSE - if(turf.density) + if(target_turf.density) qdel(tem) to_chat(xeno, SPAN_WARNING("We need empty space to build this.")) return FALSE return TRUE -/datum/action/xeno_action/activable/xeno_spit/use_ability(atom/atom) +/datum/action/xeno_action/activable/xeno_spit/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - var/spit_target = aim_turf ? get_turf(atom) : atom - if(!xeno.check_state()) - return + var/spit_target = aim_turf ? get_turf(target_atom) : target_atom - if(spitting) - to_chat(src, SPAN_WARNING("We are already preparing a spit!")) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_SPITTING)) + to_chat(xeno, SPAN_WARNING("We are already preparing a spit!")) return if(!isturf(xeno.loc)) - to_chat(src, SPAN_WARNING("We can't spit from here!")) + to_chat(xeno, SPAN_WARNING("We can't spit from here!")) return if(!action_cooldown_check()) - to_chat(src, SPAN_WARNING("We must wait for our spit glands to refill.")) + to_chat(xeno, SPAN_WARNING("We must wait for our spit glands to refill.")) return var/turf/current_turf = get_turf(xeno) - if(!current_turf) return - if (!check_plasma_owner()) - return + XENO_ACTION_CHECK(xeno) if(xeno.ammo.spit_windup) - spitting = TRUE + ADD_TRAIT(xeno, TRAIT_ABILITY_SPITTING, TRAIT_SOURCE_ABILITY("spitting")) if(xeno.ammo.pre_spit_warn) playsound(xeno.loc,"alien_drool", 55, 1) to_chat(xeno, SPAN_WARNING("We begin to prepare a large spit!")) xeno.visible_message(SPAN_WARNING("[xeno] prepares to spit a massive glob!"), SPAN_WARNING("We begin to spit [xeno.ammo.name]!")) - if (!do_after(xeno, xeno.ammo.spit_windup, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_HOSTILE)) + if(!do_after(xeno, xeno.ammo.spit_windup, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_HOSTILE)) to_chat(xeno, SPAN_XENODANGER("We decide to cancel our spit.")) - spitting = FALSE + REMOVE_TRAIT(xeno, TRAIT_ABILITY_SPITTING, TRAIT_SOURCE_ABILITY("spitting")) return plasma_cost = xeno.ammo.spit_cost if(!check_and_use_plasma_owner()) - spitting = FALSE + REMOVE_TRAIT(xeno, TRAIT_ABILITY_SPITTING, TRAIT_SOURCE_ABILITY("spitting")) return - xeno.visible_message(SPAN_XENOWARNING("[xeno] spits at [atom]!"), + xeno.visible_message(SPAN_XENOWARNING("[xeno] spits at [target_atom]!"), - SPAN_XENOWARNING("We spit [xeno.ammo.name] at [atom]!") ) + SPAN_XENOWARNING("We spit [xeno.ammo.name] at [target_atom]!") ) playsound(xeno.loc, sound_to_play, 25, 1) var/obj/projectile/proj = new (current_turf, create_cause_data(xeno.ammo.name, xeno)) @@ -965,13 +947,13 @@ proj.def_zone = xeno.get_limbzone_target() proj.fire_at(spit_target, xeno, xeno, xeno.ammo.max_range, xeno.ammo.shell_speed) - spitting = FALSE - + REMOVE_TRAIT(xeno, TRAIT_ABILITY_SPITTING, TRAIT_SOURCE_ABILITY("spitting")) SEND_SIGNAL(xeno, COMSIG_XENO_POST_SPIT) apply_cooldown() return ..() + /datum/action/xeno_action/activable/tail_stab/use_ability(atom/targetted_atom) var/mob/living/carbon/xenomorph/stabbing_xeno = owner if(HAS_TRAIT(targetted_atom, TRAIT_HAULED)) @@ -981,7 +963,7 @@ to_chat(stabbing_xeno, SPAN_XENOWARNING("We must be above ground to do this.")) return - if(!stabbing_xeno.check_state() || stabbing_xeno.cannot_slash) + if(stabbing_xeno.cannot_slash) return FALSE var/pre_result = pre_ability_act(stabbing_xeno, targetted_atom) @@ -989,10 +971,9 @@ if(pre_result) return FALSE - if(!action_cooldown_check()) - return FALSE + XENO_ACTION_CHECK(stabbing_xeno) - if (world.time <= stabbing_xeno.next_move) + if(world.time <= stabbing_xeno.next_move) return FALSE if(stabbing_xeno.z != targetted_atom.z) @@ -1045,20 +1026,19 @@ if(stabbing_xeno.can_not_harm(targetted_atom)) return FALSE - var/mob/living/carbon/target = targetted_atom + var/mob/living/carbon/target_carbon = targetted_atom - if(target.stat == DEAD || HAS_TRAIT(target, TRAIT_NESTED)) + if(target_carbon.stat == DEAD || HAS_TRAIT(target_carbon, TRAIT_NESTED)) return FALSE - var/obj/limb/limb = target.get_limb(check_zone(stabbing_xeno.zone_selected)) - if (ishuman(target) && (!limb || (limb.status & LIMB_DESTROYED))) + var/obj/limb/limb = target_carbon.get_limb(check_zone(stabbing_xeno.zone_selected)) + if(ishuman(target_carbon) && (!limb || (limb.status & LIMB_DESTROYED))) to_chat(stabbing_xeno, (SPAN_WARNING("What [limb.display_name]?"))) return FALSE - if(!check_and_use_plasma_owner()) - return FALSE + XENO_ACTION_CHECK_USE_PLASMA(stabbing_xeno) - var/result = ability_act(stabbing_xeno, target, limb) + var/result = ability_act(stabbing_xeno, target_carbon, limb) apply_cooldown() xeno_attack_delay(stabbing_xeno) @@ -1091,45 +1071,45 @@ if(new_dir == dir) setDir(last_dir) -/datum/action/xeno_action/activable/tail_stab/proc/ability_act(mob/living/carbon/xenomorph/stabbing_xeno, mob/living/carbon/target, obj/limb/limb, apply_behavior_delagate = TRUE) +/datum/action/xeno_action/activable/tail_stab/proc/ability_act(mob/living/carbon/xenomorph/stabbing_xeno, mob/living/carbon/target_carbon, obj/limb/limb, apply_behavior_delagate = TRUE) - target.last_damage_data = create_cause_data(initial(stabbing_xeno.caste_type), stabbing_xeno) + target_carbon.last_damage_data = create_cause_data(initial(stabbing_xeno.caste_type), stabbing_xeno) var/stab_overlay if(blunt_stab) - stabbing_xeno.visible_message(SPAN_XENOWARNING("\The [stabbing_xeno] swipes its tail into [target]'s [limb ? limb.display_name : "chest"], bashing it!"), SPAN_XENOWARNING("We swipe our tail into [target]'s [limb? limb.display_name : "chest"], bashing it!")) + stabbing_xeno.visible_message(SPAN_XENOWARNING("\The [stabbing_xeno] swipes its tail into [target_carbon]'s [limb ? limb.display_name : "chest"], bashing it!"), SPAN_XENOWARNING("We swipe our tail into [target_carbon]'s [limb? limb.display_name : "chest"], bashing it!")) if(prob(1)) - playsound(target, 'sound/effects/comical_bonk.ogg', 50, TRUE) + playsound(target_carbon, 'sound/effects/comical_bonk.ogg', 50, TRUE) else - playsound(target, "punch", 50, TRUE) + playsound(target_carbon, "punch", 50, TRUE) stab_overlay = "slam" else - stabbing_xeno.visible_message(SPAN_XENOWARNING("\The [stabbing_xeno] skewers [target] through the [limb ? limb.display_name : "chest"] with its razor sharp tail!"), SPAN_XENOWARNING("We skewer [target] through the [limb? limb.display_name : "chest"] with our razor sharp tail!")) - playsound(target, "alien_bite", 50, TRUE) + stabbing_xeno.visible_message(SPAN_XENOWARNING("\The [stabbing_xeno] skewers [target_carbon] through the [limb ? limb.display_name : "chest"] with its razor sharp tail!"), SPAN_XENOWARNING("We skewer [target_carbon] through the [limb? limb.display_name : "chest"] with our razor sharp tail!")) + playsound(target_carbon, "alien_bite", 50, TRUE) stab_overlay = "tail" - log_attack("[key_name(stabbing_xeno)] tailstabbed [key_name(target)] at [get_area_name(stabbing_xeno)]") - target.attack_log += text("\[[time_stamp()]\] was tailstabbed by [key_name(stabbing_xeno)]") - stabbing_xeno.attack_log += text("\[[time_stamp()]\] tailstabbed [key_name(target)]") + log_attack("[key_name(stabbing_xeno)] tailstabbed [key_name(target_carbon)] at [get_area_name(stabbing_xeno)]") + target_carbon.attack_log += text("\[[time_stamp()]\] was tailstabbed by [key_name(stabbing_xeno)]") + stabbing_xeno.attack_log += text("\[[time_stamp()]\] tailstabbed [key_name(target_carbon)]") - stabbing_xeno.tail_stab_animation(target, blunt_stab) - stabbing_xeno.animation_attack_on(target) - stabbing_xeno.flick_attack_overlay(target, stab_overlay) + stabbing_xeno.tail_stab_animation(target_carbon, blunt_stab) + stabbing_xeno.animation_attack_on(target_carbon) + stabbing_xeno.flick_attack_overlay(target_carbon, stab_overlay) var/damage = (stabbing_xeno.melee_damage_upper + stabbing_xeno.frenzy_aura * FRENZY_DAMAGE_MULTIPLIER) * damage_multiplier if(stabbing_xeno.behavior_delegate && apply_behavior_delagate) - stabbing_xeno.behavior_delegate.melee_attack_additional_effects_target(target) + stabbing_xeno.behavior_delegate.melee_attack_additional_effects_target(target_carbon) stabbing_xeno.behavior_delegate.melee_attack_additional_effects_self() - damage = stabbing_xeno.behavior_delegate.melee_attack_modify_damage(damage, target) + damage = stabbing_xeno.behavior_delegate.melee_attack_modify_damage(damage, target_carbon) - target.apply_armoured_damage(get_xeno_damage_slash(target, damage), ARMOR_MELEE, BRUTE, limb ? limb.name : "chest") + target_carbon.apply_armoured_damage(get_xeno_damage_slash(target_carbon, damage), ARMOR_MELEE, BRUTE, limb ? limb.name : "chest") if(stabbing_xeno.mob_size >= MOB_SIZE_BIG) - target.apply_effect(3, DAZE) + target_carbon.apply_effect(3, DAZE) else if(stabbing_xeno.mob_size == MOB_SIZE_XENO) - target.apply_effect(1, DAZE) - shake_camera(target, 2, 1) + target_carbon.apply_effect(1, DAZE) + shake_camera(target_carbon, 2, 1) - target.handle_blood_splatter(get_dir(owner.loc, target.loc)) - return target + target_carbon.handle_blood_splatter(get_dir(owner.loc, target_carbon.loc)) + return target_carbon 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 d4fb390f14f92..99f8a67f17234 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 282b6f6c52d00..6abdf6d126617 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 @@ -35,8 +35,6 @@ var/buff_duration = 12 var/damage = 40 var/shield_regen_threshold = 1 - - var/activated_once = FALSE var/time_until_timeout = 20 /datum/action/xeno_action/activable/pounce/prae_dash/initialize_pounce_pass_flags() @@ -58,8 +56,6 @@ var/fling_dist_unbuffed = 3 var/fling_dist_buffed = 6 - // Root or do a punch-like-effect. - var/root_toggle = TRUE var/buffed = FALSE // Are we buffed /datum/action/xeno_action/onclick/toggle_cleave @@ -70,39 +66,6 @@ action_type = XENO_ACTION_CLICK ability_primacy = XENO_PRIMARY_ACTION_4 -/datum/action/xeno_action/onclick/toggle_cleave/can_use_action() - var/mob/living/carbon/xenomorph/X = owner - if(X && !X.buckled && !X.is_mob_incapacitated()) - return TRUE - -/datum/action/xeno_action/onclick/toggle_cleave/use_ability(atom/A) - var/mob/living/carbon/xenomorph/X = owner - - if (!istype(X)) - return - - if(!X.check_state(1)) - return - - var/datum/action/xeno_action/activable/cleave/cAction = get_action(X, /datum/action/xeno_action/activable/cleave) - - if (!istype(cAction)) - return - - cAction.root_toggle = !cAction.root_toggle - - var/action_icon_result - if (cAction.root_toggle) - action_icon_result = "prae_cleave_root" - to_chat(X, SPAN_WARNING("We will now root marines with our cleave.")) - else - action_icon_result = "prae_cleave_fling" // TODO: update - to_chat(X, SPAN_WARNING("We will now throw marines with our cleave.")) - - button.overlays.Cut() - button.overlays += image('icons/mob/hud/actions_xeno.dmi', button, action_icon_result) - return ..() - ////////// Oppressor powers /datum/action/xeno_action/activable/tail_stab/tail_seize //no verbmacrohotkey, its just tail stab. @@ -172,6 +135,11 @@ action_type = XENO_ACTION_CLICK ability_primacy = XENO_TAIL_STAB + /// 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 + /datum/action/xeno_action/activable/prae_impale name = "Impale" action_icon_state = "prae_impale" @@ -197,6 +165,15 @@ var/speed_buff_amount = 0.5 var/afterimage_interval = 1 DECISECONDS + /// 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 + /datum/action/xeno_action/activable/prae_tail_trip name = "Tail Trip" action_icon_state = "prae_tail_trip" @@ -249,7 +226,7 @@ plasma_cost = 80 var/activation_delay = 1 SECONDS - var/prime_delay = 1 SECONDS + var/prime_delay = 1.5 SECONDS /datum/action/xeno_action/activable/prae_acid_ball/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/acid_ball_user = owner diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm index 5a181a5b1990f..998da49b5c2eb 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm @@ -156,29 +156,29 @@ var/datum/hive_status/hive var/list/transported_xenos -/datum/action/xeno_action/activable/place_queen_beacon/give_to(mob/living/carbon/xenomorph/queen/Q) +/datum/action/xeno_action/activable/place_queen_beacon/give_to(mob/living/carbon/xenomorph/queen/queen_user) . = ..() - hive = Q.hive - if(!Q.ovipositor) - hide_from(Q) - RegisterSignal(Q, COMSIG_QUEEN_MOUNT_OVIPOSITOR, PROC_REF(handle_mount_ovipositor)) - RegisterSignal(Q, COMSIG_QUEEN_DISMOUNT_OVIPOSITOR, PROC_REF(handle_dismount_ovipositor)) + hive = queen_user.hive + if(!queen_user.ovipositor) + hide_from(queen_user) + RegisterSignal(queen_user, COMSIG_QUEEN_MOUNT_OVIPOSITOR, PROC_REF(handle_mount_ovipositor)) + RegisterSignal(queen_user, COMSIG_QUEEN_DISMOUNT_OVIPOSITOR, PROC_REF(handle_dismount_ovipositor)) -/datum/action/xeno_action/activable/place_queen_beacon/remove_from(mob/living/carbon/xenomorph/X) +/datum/action/xeno_action/activable/place_queen_beacon/remove_from(mob/living/carbon/xenomorph/xeno) . = ..() hive = null - UnregisterSignal(X, list( + UnregisterSignal(xeno, list( COMSIG_QUEEN_MOUNT_OVIPOSITOR, COMSIG_QUEEN_DISMOUNT_OVIPOSITOR, )) -/datum/action/xeno_action/activable/place_queen_beacon/proc/handle_mount_ovipositor(mob/living/carbon/xenomorph/queen/Q) +/datum/action/xeno_action/activable/place_queen_beacon/proc/handle_mount_ovipositor(mob/living/carbon/xenomorph/queen/queen_user) SIGNAL_HANDLER - unhide_from(Q) + unhide_from(queen_user) -/datum/action/xeno_action/activable/place_queen_beacon/proc/handle_dismount_ovipositor(mob/living/carbon/xenomorph/queen/Q) +/datum/action/xeno_action/activable/place_queen_beacon/proc/handle_dismount_ovipositor(mob/living/carbon/xenomorph/queen/queen_user) SIGNAL_HANDLER - hide_from(Q) + hide_from(queen_user) /datum/action/xeno_action/activable/blockade @@ -194,24 +194,24 @@ var/brittle_time = 45 SECONDS var/decay_time = 45 SECONDS -/datum/action/xeno_action/activable/blockade/give_to(mob/living/carbon/xenomorph/queen/Q) +/datum/action/xeno_action/activable/blockade/give_to(mob/living/carbon/xenomorph/queen/queen_user) . = ..() - if(!Q.ovipositor) - hide_from(Q) - RegisterSignal(Q, COMSIG_QUEEN_MOUNT_OVIPOSITOR, PROC_REF(handle_mount_ovipositor)) - RegisterSignal(Q, COMSIG_QUEEN_DISMOUNT_OVIPOSITOR, PROC_REF(handle_dismount_ovipositor)) + if(!queen_user.ovipositor) + hide_from(queen_user) + RegisterSignal(queen_user, COMSIG_QUEEN_MOUNT_OVIPOSITOR, PROC_REF(handle_mount_ovipositor)) + RegisterSignal(queen_user, COMSIG_QUEEN_DISMOUNT_OVIPOSITOR, PROC_REF(handle_dismount_ovipositor)) -/datum/action/xeno_action/activable/blockade/remove_from(mob/living/carbon/xenomorph/X) +/datum/action/xeno_action/activable/blockade/remove_from(mob/living/carbon/xenomorph/xeno) . = ..() - UnregisterSignal(X, list( + UnregisterSignal(xeno, list( COMSIG_QUEEN_MOUNT_OVIPOSITOR, COMSIG_QUEEN_DISMOUNT_OVIPOSITOR, )) -/datum/action/xeno_action/activable/blockade/proc/handle_mount_ovipositor(mob/living/carbon/xenomorph/queen/Q) +/datum/action/xeno_action/activable/blockade/proc/handle_mount_ovipositor(mob/living/carbon/xenomorph/queen/queen_user) SIGNAL_HANDLER - unhide_from(Q) + unhide_from(queen_user) -/datum/action/xeno_action/activable/blockade/proc/handle_dismount_ovipositor(mob/living/carbon/xenomorph/queen/Q) +/datum/action/xeno_action/activable/blockade/proc/handle_dismount_ovipositor(mob/living/carbon/xenomorph/queen/queen_user) SIGNAL_HANDLER - hide_from(Q) + hide_from(queen_user) 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 c676fff618263..3c62418cb3f14 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 @@ -17,6 +17,9 @@ freeze_self = FALSE // Should we freeze ourselves after the lunge? should_destroy_objects = TRUE // Only used for ravager charge + var/knockdown_amount = 1.6 + var/fling_distance = 3 + // Base ravager shield ability /datum/action/xeno_action/onclick/empower name = "Empower" @@ -34,9 +37,8 @@ var/initial_activation_shield = 50 var/shield_per_human = 50 var/time_until_timeout = 6 SECONDS - - // State - var/activated_once = FALSE + var/empower_targets = 0 + var/super_empower_threshold = 3 // Rav "Scissor Cut" /datum/action/xeno_action/activable/scissor_cut @@ -149,4 +151,6 @@ 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 528dc9767a139..158cf0a43da44 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/xeno_action.dm b/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm index d2cd1e6615566..e452ef8a37f3d 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,19 +479,42 @@ 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 /datum/action/xeno_action/proc/on_deselect(mob/user) return - -#define XENO_ACTION_CHECK(X) if(!X.check_state() || !action_cooldown_check() || !check_plasma_owner(src.plasma_cost)) return -#define XENO_ACTION_CHECK_USE_PLASMA(X) if(!X.check_state() || !action_cooldown_check() || !check_and_use_plasma_owner(src.plasma_cost)) return diff --git a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm index 3a2098f14bea3..375dd3ce124f8 100644 --- a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm +++ b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm @@ -9,7 +9,7 @@ // this proc could use refactoring at some point /mob/living/carbon/human/attack_alien(mob/living/carbon/xenomorph/attacking_xeno, dam_bonus, unblockable = FALSE) - if(attacking_xeno.fortify || HAS_TRAIT(attacking_xeno, TRAIT_ABILITY_BURROWED) || HAS_TRAIT(attacking_xeno, TRAIT_ABILITY_REFLECTIVE_PLATES)) + if(HAS_TRAIT(attacking_xeno, TRAIT_ABILITY_FORTIFY) || HAS_TRAIT(attacking_xeno, TRAIT_ABILITY_BURROWED) || HAS_TRAIT(attacking_xeno, TRAIT_ABILITY_REFLECTIVE_PLATES)) return XENO_NO_DELAY_ACTION if(HAS_TRAIT(src, TRAIT_HAULED)) @@ -253,7 +253,7 @@ //Every other type of nonhuman mob /mob/living/attack_alien(mob/living/carbon/xenomorph/xeno) - if(xeno.fortify || HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_FORTIFY) || HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) return XENO_NO_DELAY_ACTION switch(xeno.a_intent) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm index 95483880fa51b..97579461284d5 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm @@ -100,11 +100,11 @@ /datum/action/xeno_action/activable/xeno_spit/bombard/use_ability(atom/affected_atom) . = ..() - var/mob/living/carbon/xenomorph/xeno = owner + var/mob/living/carbon/xenomorph/bombard_user = owner if(!action_cooldown_check()) // activate c/d only if we already spit - for (var/action_type in action_types_to_cd) - var/datum/action/xeno_action/xeno_action = get_action(xeno, action_type) - if (!istype(xeno_action)) + for(var/action_type in action_types_to_cd) + var/datum/action/xeno_action/xeno_action = get_action(bombard_user, action_type) + if(!istype(xeno_action)) continue xeno_action.apply_cooldown_override(cooldown_duration) @@ -113,21 +113,17 @@ /datum/action/xeno_action/onclick/acid_shroud/use_ability(atom/affected_atom) var/datum/effect_system/smoke_spread/xeno_acid/spicy_gas var/mob/living/carbon/xenomorph/xeno = owner - if (!isxeno(owner)) + if(!isxeno(owner)) return - if (!action_cooldown_check()) - return - - if (!xeno.check_state()) - return + XENO_ACTION_CHECK(xeno) if(sound_play) playsound(xeno,"acid_strike", 35, 1) sound_play = FALSE addtimer(VARSET_CALLBACK(src, sound_play, TRUE), 2 SECONDS) - if (!do_after(xeno, xeno.ammo.spit_windup/6.5, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_HOSTILE, numticks = 2)) /// 0.7 seconds + if(!do_after(xeno, xeno.ammo.spit_windup / 6.5, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_HOSTILE, numticks = 2)) /// 0.7 seconds to_chat(xeno, SPAN_XENODANGER("We decide to cancel our gas shroud.")) return @@ -144,9 +140,9 @@ spicy_gas.start() to_chat(xeno, SPAN_XENOHIGHDANGER("We dump our acid through our pores, creating a shroud of gas!")) - for (var/action_type in action_types_to_cd) + for(var/action_type in action_types_to_cd) var/datum/action/xeno_action/xeno_action = get_action(xeno, action_type) - if (!istype(xeno_action)) + if(!istype(xeno_action)) continue xeno_action.apply_cooldown_override(cooldown_duration) @@ -159,21 +155,21 @@ apply_cooldown() /datum/action/xeno_action/activable/tail_stab/boiler/use_ability(atom/affected_atom) - var/mob/living/carbon/xenomorph/stabbing_xeno = owner + var/mob/living/carbon/xenomorph/xeno = owner var/target = ..() if(iscarbon(target)) var/mob/living/carbon/carbon_target = target - if(stabbing_xeno.ammo == GLOB.ammo_list[/datum/ammo/xeno/boiler_gas/acid]) + if(xeno.ammo == GLOB.ammo_list[/datum/ammo/xeno/boiler_gas/acid]) carbon_target.reagents.add_reagent("molecularacid", 6) carbon_target.reagents.set_source_mob(owner, /datum/reagent/toxin/molecular_acid) - else if(stabbing_xeno.ammo == GLOB.ammo_list[/datum/ammo/xeno/boiler_gas]) + else if(xeno.ammo == GLOB.ammo_list[/datum/ammo/xeno/boiler_gas]) var/datum/effects/neurotoxin/neuro_effect = locate() in carbon_target.effects_list if(!neuro_effect) neuro_effect = new(carbon_target, owner) neuro_effect.duration += 20 - to_chat(carbon_target,SPAN_HIGHDANGER("You are injected with something from [stabbing_xeno]'s tailstab!")) + to_chat(carbon_target,SPAN_HIGHDANGER("You are injected with something from [xeno]'s tailstab!")) else - CRASH("Globber has unknown ammo [stabbing_xeno.ammo]! Oh no!") + CRASH("Globber has unknown ammo [xeno.ammo]! Oh no!") return TRUE #define ACID_COST_BOILER 200 // ACID_COST_LEVEL_3 diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm index 574c191d32b35..7b66d6e8ac411 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,232 +82,229 @@ 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 - ..() +/datum/behavior_delegate/burrower_base + name = "Base Burrower Behavior Delegate" -/mob/living/carbon/xenomorph/burrower/attack_hand() - if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) - return - ..() +/datum/action/xeno_action/activable/burrow/use_ability(atom/target_atom) + 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_BURROWED)) + digging(get_turf(target_atom)) + else + burrow() + return ..() -/datum/behavior_delegate/burrower_base - name = "Base Burrower Behavior Delegate" +/datum/action/xeno_action/activable/burrow/proc/burrow() + var/mob/living/carbon/xenomorph/xeno = owner + XENO_ACTION_CHECK(xeno) -//Burrower Abilities -/mob/living/carbon/xenomorph/proc/burrow() - if(!check_state()) + 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) +/datum/action/xeno_action/activable/burrow/proc/do_digging(turf/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + + 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/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() +/datum/action/xeno_action/activable/burrow/proc/do_digging_cooldown() + var/mob/living/carbon/xenomorph/xeno = owner + used_digging = FALSE + to_chat(xeno, SPAN_NOTICE("We can now tunnel while burrowed.")) + update_button_icon() -/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 - if(!action_cooldown_check()) - return +/datum/action/xeno_action/onclick/tremor/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner - if(!burrower_tremor.check_state()) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_BURROWED)) + to_chat(xeno, SPAN_XENOWARNING("We must be above ground to do this.")) return - if(!check_and_use_plasma_owner()) + if(xeno.is_ventcrawling) + to_chat(xeno, SPAN_XENOWARNING("We must be above ground to do this.")) return - 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() + XENO_ACTION_CHECK_USE_PLASMA(xeno) + 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, 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 @@ -320,96 +314,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/Carrier.dm b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm index 8196ea906bbf2..d47a1073161af 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm @@ -247,7 +247,6 @@ else to_chat(src, SPAN_WARNING("We can't carry more facehuggers on you.")) - /mob/living/carbon/xenomorph/carrier/proc/throw_hugger(atom/object) if(!object) return @@ -318,8 +317,8 @@ SPAN_XENOWARNING("We throw a facehugger towards \the [object]!")) addtimer(CALLBACK(src, PROC_REF(update_action_buttons)), caste.hugger_throw_delay) // no idea why hugger_throw_delay is a parent since its only really used by this file but whatever -/mob/living/carbon/xenomorph/carrier/proc/store_egg(obj/item/xeno_egg/E) - if(E.hivenumber != hivenumber) +/mob/living/carbon/xenomorph/carrier/proc/store_egg(obj/item/xeno_egg/target_egg) + if(target_egg.hivenumber != hivenumber) to_chat(src, SPAN_WARNING("That egg is tainted!")) return if(eggs_cur < eggs_max) @@ -327,9 +326,9 @@ eggs_cur++ behavior_delegate?.on_update_icons() to_chat(src, SPAN_NOTICE("We store the egg and carry it for safekeeping. Now sheltering: [eggs_cur] / [eggs_max].")) - qdel(E) + qdel(target_egg) else - to_chat(src, SPAN_WARNING("This [E.name] looks too unhealthy.")) + to_chat(src, SPAN_WARNING("This [target_egg.name] looks too unhealthy.")) else to_chat(src, SPAN_WARNING("We can't carry more eggs on ourselves.")) @@ -342,35 +341,35 @@ //target a hugger on the ground to store it directly if(istype(object, /obj/item/xeno_egg)) - var/obj/item/xeno_egg/E = object - if(isturf(E.loc) && Adjacent(E)) - var/turf/egg_turf = E.loc - store_egg(E) + var/obj/item/xeno_egg/target_egg = object + if(isturf(target_egg.loc) && Adjacent(target_egg)) + var/turf/egg_turf = target_egg.loc + store_egg(target_egg) //Grab all the eggs from the turf if(eggs_cur < eggs_max) - for(E in egg_turf) + for(target_egg in egg_turf) if(eggs_cur < eggs_max) - store_egg(E) + store_egg(target_egg) return if(istype(object, /obj/effect/alien/resin/special/eggmorph)) store_eggs_into_egg_morpher(object) return - var/obj/item/xeno_egg/E = get_active_hand() - if(!E) //empty active hand + var/obj/item/xeno_egg/target_egg = get_active_hand() + if(!target_egg) //empty active hand //if no hugger in active hand, we take one from our storage if(eggs_cur <= 0) to_chat(src, SPAN_WARNING("We don't have any eggs to use!")) return - E = new(src, hivenumber) + target_egg = new(src, hivenumber) eggs_cur-- behavior_delegate?.on_update_icons() - put_in_active_hand(E) + put_in_active_hand(target_egg) to_chat(src, SPAN_XENONOTICE("We grab one of the eggs in our storage. Now sheltering: [eggs_cur] / [eggs_max].")) return - if(!istype(E)) //something else in our hand + if(!istype(target_egg)) //something else in our hand to_chat(src, SPAN_WARNING("We need an empty hand to grab one of our stored eggs!")) return @@ -454,6 +453,12 @@ carrier_owner.throw_hugger(target) return ..() +/datum/action/xeno_action/activable/throw_hugger/action_cooldown_check() + if(owner) + var/mob/living/carbon/xenomorph/carrier/alien = owner + return world.time >= alien.hugger_throw_cooldown // i think + return TRUE //When we first add the ability we still do this check, but owner is null, so a workaround + /datum/action/xeno_action/activable/retrieve_egg/use_ability(atom/target) var/mob/living/carbon/xenomorph/carrier/carrier_owner = owner carrier_owner.retrieve_egg(target) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm index d38205214a601..a828c922c714b 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm @@ -76,140 +76,130 @@ pelt = /obj/item/pelt/crusher // Refactored to handle all of crusher's interactions with object during charge. -/mob/living/carbon/xenomorph/proc/handle_collision(atom/target) - if(!target) +/mob/living/carbon/xenomorph/proc/handle_collision(atom/target_atom) + if(!target_atom) return FALSE - var/handled = FALSE + //Barricade collision + else if(istype(target_atom, /obj/structure/barricade)) + var/obj/structure/barricade/blockade_in_path = target_atom + visible_message(SPAN_DANGER("[src] rams into [blockade_in_path] and skids to a halt!"), SPAN_XENOWARNING("We ram into [blockade_in_path] and skid to a halt!")) - //Check all machinery first - if(istype(target, /obj/structure/machinery)) - if(istype(target, /obj/structure/machinery/m56d_hmg)) - handled = TRUE - var/obj/structure/machinery/m56d_hmg/weapon_in_path = target - visible_message(SPAN_DANGER("[src] rams [weapon_in_path]!"), SPAN_XENODANGER("We ram [weapon_in_path]!")) - playsound(loc, "punch", 25, 1) - weapon_in_path.CrusherImpact() + blockade_in_path.Collided(src) + . = FALSE + + else if(istype(target_atom, /obj/vehicle/multitile)) + var/obj/vehicle/multitile/vehicle_in_path = target_atom + visible_message(SPAN_DANGER("[src] rams into [vehicle_in_path] and skids to a halt!"), SPAN_XENOWARNING("We ram into [vehicle_in_path] and skid to a halt!")) + + vehicle_in_path.Collided(src) + . = FALSE + + else if(istype(target_atom, /obj/structure/machinery/m56d_hmg)) + var/obj/structure/machinery/m56d_hmg/weapon_in_path = target_atom + visible_message(SPAN_DANGER("[src] rams [weapon_in_path]!"), SPAN_XENODANGER("We ram [weapon_in_path]!")) + playsound(loc, "punch", 25, 1) + weapon_in_path.CrusherImpact() + . = FALSE + + else if(istype(target_atom, /obj/structure/window)) + var/obj/structure/window/window_in_path = target_atom + if (window_in_path.unacidable) . = FALSE - else if(istype(target, /obj/structure/machinery/door/airlock)) - handled = TRUE - var/obj/structure/machinery/door/airlock/airlock_in_path = target - if(airlock_in_path.unacidable) - . = FALSE - else - airlock_in_path.deconstruct() - - else if(istype(target, /obj/structure/machinery/defenses)) - handled = TRUE - var/obj/structure/machinery/defenses/defenses_in_path = target - visible_message(SPAN_DANGER("[src] rams [defenses_in_path]!"), SPAN_XENODANGER("We ram [defenses_in_path]!")) - if(!defenses_in_path.unacidable) - playsound(loc, "punch", 25, 1) - defenses_in_path.stat |= DEFENSE_DAMAGED - defenses_in_path.update_health(melee_damage_upper) + else if (istype(target_atom, /obj/structure/machinery/door/airlock)) + var/obj/structure/machinery/door/airlock/airlock_in_path = target_atom + + if(airlock_in_path.unacidable) . = FALSE + else + airlock_in_path.deconstruct() - else if(istype(target, /obj/structure/machinery/vending)) - handled = TRUE - var/obj/structure/machinery/vending/vending_in_path = target - if(vending_in_path.unslashable) - . = FALSE - else - visible_message(SPAN_DANGER("[src] smashes straight into [vending_in_path]!"), SPAN_XENODANGER("We smash straight into [vending_in_path]!")) - playsound(loc, "punch", 25, 1) - vending_in_path.tip_over() - var/turf/turfs_charged_at = get_diagonal_step(vending_in_path, dir) - turfs_charged_at = get_step_away(turfs_charged_at, src) - throw_atom(turfs_charged_at, range=1, speed=2) - . = TRUE + else if(istype(target_atom, /obj/structure/grille)) + var/obj/structure/grille/grille_in_path = target_atom + if(grille_in_path.unacidable) + . = FALSE + else + grille_in_path.health -= 80 //Usually knocks it down. + grille_in_path.healthcheck() + . = TRUE - else if(istype(target, /obj/structure/machinery/cm_vending)) - handled = TRUE - var/obj/structure/machinery/cm_vending/vending_in_path = target - if(vending_in_path.unslashable) - . = FALSE - else - visible_message(SPAN_DANGER("[src] smashes straight into [vending_in_path]!"), SPAN_XENODANGER("We smash straight into [vending_in_path]!")) - playsound(loc, "punch", 25, 1) - vending_in_path.tip_over() - var/turf/turfs_charged_at = get_diagonal_step(vending_in_path, dir) - turfs_charged_at = get_step_away(turfs_charged_at, src) - throw_atom(turfs_charged_at, range=1, speed=2) - . = TRUE + else if(istype(target_atom, /obj/structure/surface/table)) + var/obj/structure/surface/table/table_in_path = target_atom + table_in_path.Crossed(src) + . = TRUE + + else if(istype(target_atom, /obj/structure/machinery/defenses)) + var/obj/structure/machinery/defenses/defenses_in_path = target_atom + visible_message(SPAN_DANGER("[src] rams [defenses_in_path]!"), SPAN_XENODANGER("We ram [defenses_in_path]!")) - else if(istype(target, /obj/structure/machinery/fuelpump)) - handled = TRUE - var/obj/structure/machinery/fuelpump/pump_in_path = target - visible_message(SPAN_DANGER("[src] rams [pump_in_path]!"), SPAN_XENODANGER("We ram [pump_in_path]!")) + if (!defenses_in_path.unacidable) playsound(loc, "punch", 25, 1) - pump_in_path.update_health(melee_damage_upper) - . = FALSE + defenses_in_path.stat = 1 + defenses_in_path.update_icon() + defenses_in_path.update_health(40) - // Check all structures next - else if(istype(target, /obj/structure)) - if(istype(target, /obj/structure/barricade)) - handled = TRUE - var/obj/structure/barricade/blockade_in_path = target - visible_message(SPAN_DANGER("[src] rams into [blockade_in_path] and skids to a halt!"), SPAN_XENOWARNING("We ram into [blockade_in_path] and skid to a halt!")) - blockade_in_path.Collided(src) - . = FALSE + . = FALSE - else if(istype(target, /obj/structure/window)) - handled = TRUE - var/obj/structure/window/window_in_path = target - if (window_in_path.unacidable) - . = FALSE - else - window_in_path.deconstruct(FALSE) - . = TRUE // Continue throw - playsound(loc, 'sound/effects/Glassbr1.ogg') - - else if(istype(target, /obj/structure/grille)) - handled = TRUE - var/obj/structure/grille/grille_in_path = target - if(grille_in_path.unacidable) - . = FALSE - else - grille_in_path.health -= 80 //Usually knocks it down. - grille_in_path.healthcheck() - . = TRUE + else if(istype(target_atom, /obj/structure/machinery/vending)) + var/obj/structure/machinery/vending/vending_in_path = target_atom - else if(istype(target, /obj/structure/surface/table)) - handled = TRUE - var/obj/structure/surface/table/table_in_path = target - table_in_path.Crossed(src) - . = TRUE + if(vending_in_path.unslashable) + . = FALSE + else + visible_message(SPAN_DANGER("[src] smashes straight into [vending_in_path]!"), SPAN_XENODANGER("We smash straight into [vending_in_path]!")) + playsound(loc, "punch", 25, 1) + vending_in_path.tip_over() - else if(istype(target, /obj/structure/fence/electrified)) - handled = TRUE - var/obj/structure/fence/electrified/fence = target - if(fence.cut) - . = FALSE - else - visible_message(SPAN_DANGER("[src] smashes into [fence]!")) - fence.cut_grille() - . = TRUE + var/impact_range = 1 + var/turf/turfs_charged_at = get_diagonal_step(vending_in_path, dir) + turfs_charged_at = get_step_away(turfs_charged_at, src) + var/launch_speed = 2 + launch_towards(turfs_charged_at, impact_range, launch_speed) - // Vehicle? - else if(istype(target, /obj/vehicle/multitile)) - handled = TRUE - var/obj/vehicle/multitile/vehicle_in_path = target - visible_message(SPAN_DANGER("[src] rams into [vehicle_in_path] and skids to a halt!"), SPAN_XENOWARNING("We ram into [vehicle_in_path] and skid to a halt!")) - vehicle_in_path.Collided(src) - . = FALSE + . = TRUE - // Is it atleast an object? - if(!handled && isobj(target)) - var/obj/object_in_path = target - if(object_in_path.unacidable) + else if(istype(target_atom, /obj/structure/machinery/cm_vending)) + var/obj/structure/machinery/cm_vending/vending_in_path = target_atom + if(vending_in_path.unslashable) . = FALSE - else if(object_in_path.anchored) - visible_message(SPAN_DANGER("[src] crushes [object_in_path]!"), SPAN_XENODANGER("We crush [object_in_path]!")) + else + visible_message(SPAN_DANGER("[src] smashes straight into [vending_in_path]!"), SPAN_XENODANGER("We smash straight into [vending_in_path]!")) playsound(loc, "punch", 25, 1) - object_in_path.deconstruct(FALSE) + vending_in_path.tip_over() + + var/impact_range = 1 + var/turf/turfs_charged_at = get_diagonal_step(vending_in_path, dir) + turfs_charged_at = get_step_away(turfs_charged_at, src) + var/launch_speed = 2 + throw_atom(turfs_charged_at, impact_range, launch_speed) + + . = TRUE + + else if(istype(target_atom, /obj/structure/fence/electrified)) + var/obj/structure/fence/electrified/fence = target_atom + if(fence.cut) + . = FALSE + else + src.visible_message(SPAN_DANGER("[src] smashes into [fence]!")) + fence.cut_grille() . = TRUE + // Anything else? + else + if(isobj(target_atom)) + var/obj/objects_in_path = target_atom + if(objects_in_path.unacidable) + . = FALSE + else if(objects_in_path.anchored) + visible_message(SPAN_DANGER("[src] crushes [objects_in_path]!"), SPAN_XENODANGER("We crush [objects_in_path]!")) + if(length(objects_in_path.contents)) //Hopefully won't auto-delete things inside crushed stuff. + var/turf/turf_for_obj = get_turf(src) + for(var/atom/movable/stuff_to_move in turf_for_obj.contents) stuff_to_move.forceMove(turf_for_obj) + + qdel(objects_in_path) + . = TRUE + else if(object_in_path.buckled_mob) object_in_path.unbuckle() @@ -232,25 +222,24 @@ /// Utilized to update charging animation. var/is_charging = FALSE -/datum/behavior_delegate/crusher_base/melee_attack_additional_effects_target(mob/living/carbon/target) - - if (!isxeno_human(target)) +/datum/behavior_delegate/crusher_base/melee_attack_additional_effects_target(mob/living/carbon/target_carbon) + if(!isxeno_human(target_carbon)) return - new /datum/effects/xeno_slow(target, bound_xeno, ttl = 2 SECONDS) + new /datum/effects/xeno_slow(target_carbon, bound_xeno, ttl = 2 SECONDS) var/damage = bound_xeno.melee_damage_upper * aoe_slash_damage_reduction var/base_cdr_amount = 1.5 SECONDS var/cdr_amount = base_cdr_amount - for (var/mob/living/carbon/aoe_targets in orange(1, target)) - if (aoe_targets.stat == DEAD) + for(var/mob/living/carbon/aoe_targets in orange(1, target_carbon)) + if(aoe_targets.stat == DEAD) continue if(!isxeno_human(aoe_targets) || bound_xeno.can_not_harm(aoe_targets)) continue - if (HAS_TRAIT(aoe_targets, TRAIT_NESTED)) + if(HAS_TRAIT(aoe_targets, TRAIT_NESTED)) continue cdr_amount += 0.5 SECONDS @@ -273,19 +262,19 @@ aoe_targets.apply_armoured_damage(get_xeno_damage_slash(aoe_targets, damage), ARMOR_MELEE, BRUTE, bound_xeno.zone_selected) var/datum/action/xeno_action/activable/pounce/crusher_charge/cAction = get_action(bound_xeno, /datum/action/xeno_action/activable/pounce/crusher_charge) - if (!cAction.action_cooldown_check()) + if(!cAction.action_cooldown_check()) cAction.reduce_cooldown(cdr_amount) var/datum/action/xeno_action/onclick/crusher_shield/sAction = get_action(bound_xeno, /datum/action/xeno_action/onclick/crusher_shield) - if (!sAction.action_cooldown_check()) + if(!sAction.action_cooldown_check()) sAction.reduce_cooldown(base_cdr_amount) /datum/behavior_delegate/crusher_base/append_to_stat() . = list() var/shield_total = 0 - for (var/datum/xeno_shield/XS in bound_xeno.xeno_shields) - if (XS.shield_source == XENO_SHIELD_SOURCE_CRUSHER) - shield_total += XS.amount + for(var/datum/xeno_shield/shielded_xeno in bound_xeno.xeno_shields) + if(shielded_xeno.shield_source == XENO_SHIELD_SOURCE_CRUSHER) + shield_total += shielded_xeno.amount . += "Shield: [shield_total]" @@ -294,29 +283,36 @@ bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Crusher Charging" return TRUE +/datum/action/xeno_action/activable/pounce/crusher_charge/New() + . = ..() + not_reducing_objects = typesof(/obj/structure/barricade) + typesof(/obj/structure/machinery/defenses) + +/datum/action/xeno_action/activable/pounce/crusher_charge/initialize_pounce_pass_flags() + pounce_pass_flags = PASS_CRUSHER_CHARGE + /datum/action/xeno_action/activable/pounce/crusher_charge/additional_effects_always() var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) + if(!istype(xeno)) return - for (var/mob/living/carbon/target in orange(1, get_turf(xeno))) - if(xeno.can_not_harm(target)) + for(var/mob/living/carbon/target_carbon in orange(1, get_turf(xeno))) + if(xeno.can_not_harm(target_carbon)) continue - new /datum/effects/xeno_slow(target, xeno, ttl = 3.5 SECONDS) - to_chat(target, SPAN_XENODANGER("You are slowed as the impact of [xeno] shakes the ground!")) + new /datum/effects/xeno_slow(target_carbon, xeno, ttl = 3.5 SECONDS) + to_chat(target_carbon, SPAN_XENODANGER("You are slowed as the impact of [xeno] shakes the ground!")) -/datum/action/xeno_action/activable/pounce/crusher_charge/additional_effects(mob/living/target) +/datum/action/xeno_action/activable/pounce/crusher_charge/additional_effects(mob/living/target_living) var/mob/living/carbon/xenomorph/xeno = owner - var/mob/living/carbon/target_to_check = target - if (!isxeno_human(target)) + var/mob/living/carbon/target_to_check = target_living + if(!isxeno_human(target_living)) return - if (target_to_check.stat == DEAD) + if(target_to_check.stat == DEAD) return xeno.emote("roar") - target.apply_effect(2, WEAKEN) + target_living.apply_effect(2, WEAKEN) xeno.visible_message(SPAN_XENODANGER("[xeno] overruns [target_to_check], brutally trampling them underfoot!"), SPAN_XENODANGER("We brutalize [target_to_check] as we crush them underfoot!")) target_to_check.apply_armoured_damage(get_xeno_damage_slash(target_to_check, direct_hit_damage), ARMOR_MELEE, BRUTE) @@ -326,7 +322,7 @@ return /datum/action/xeno_action/activable/pounce/crusher_charge/pre_windup_effects() - RegisterSignal(owner, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE, PROC_REF(check_directional_armor)) + RegisterSignal(owner, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE, PROC_REF(check_directional_projectile_armor)) var/mob/living/carbon/xenomorph/xeno_owner = owner if(!istype(xeno_owner)) @@ -352,6 +348,7 @@ addtimer(CALLBACK(src, PROC_REF(undo_charging_icon)), 0.5 SECONDS) // let the icon be here for a bit, it looks cool + /datum/action/xeno_action/activable/pounce/crusher_charge/proc/undo_charging_icon() var/mob/living/carbon/xenomorph/xeno_owner = owner if(!istype(xeno_owner)) @@ -364,10 +361,10 @@ crusher_delegate.is_charging = FALSE xeno_owner.update_icons() -/datum/action/xeno_action/activable/pounce/crusher_charge/proc/check_directional_armor(mob/living/carbon/xenomorph/X, list/damagedata) +/datum/action/xeno_action/activable/pounce/crusher_charge/proc/check_directional_projectile_armor(mob/living/carbon/xenomorph/xeno, list/damagedata) SIGNAL_HANDLER var/projectile_direction = damagedata["direction"] - if(X.dir & REVERSE_DIR(projectile_direction)) + if(xeno.dir & REVERSE_DIR(projectile_direction)) // During the charge windup, crusher gets an extra 15 directional armor in the direction its charging damagedata["armor"] += frontal_armor @@ -375,38 +372,31 @@ // This ties the pounce/throwing backend into the old collision backend /mob/living/carbon/xenomorph/crusher/pounced_obj(obj/pounced_object) var/datum/action/xeno_action/activable/pounce/crusher_charge/crusher_charge_action = get_action(src, /datum/action/xeno_action/activable/pounce/crusher_charge) - if (istype(crusher_charge_action) && !crusher_charge_action.action_cooldown_check() && !(pounced_object.type in crusher_charge_action.not_reducing_objects)) + if(istype(crusher_charge_action) && !crusher_charge_action.action_cooldown_check() && !(pounced_object.type in crusher_charge_action.not_reducing_objects)) crusher_charge_action.reduce_cooldown(50) gain_plasma(10) - if (!handle_collision(pounced_object)) // Check old backend + if(!handle_collision(pounced_object)) // Check old backend obj_launch_collision(pounced_object) /mob/living/carbon/xenomorph/crusher/pounced_turf(turf/pounced_turf) pounced_turf.ex_act(EXPLOSION_THRESHOLD_VLOW, , create_cause_data(caste_type, src)) ..(pounced_turf) -/datum/action/xeno_action/onclick/crusher_stomp/use_ability(atom/Atom) +/datum/action/xeno_action/onclick/crusher_stomp/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if (!action_cooldown_check()) - return - - if (!xeno.check_state()) - return - - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) playsound(xeno, 'sound/effects/bang.ogg', 25) xeno.visible_message(SPAN_XENODANGER("[xeno] smashes into the ground!"), SPAN_XENODANGER("We smash into the ground!")) xeno.create_stomp() - for (var/mob/living/carbon/targets in orange(distance, xeno)) + for(var/mob/living/carbon/targets in orange(distance, xeno)) - if (targets.stat == DEAD || xeno.can_not_harm(targets)) + if(targets.stat == DEAD || xeno.can_not_harm(targets)) continue if(targets in get_turf(xeno)) @@ -426,24 +416,17 @@ var/mob/living/carbon/xenomorph/xeno = owner var/mob/living/carbon/stomped_carbon - if (!istype(xeno)) - return - - if (!action_cooldown_check()) + if(!istype(xeno)) return - if (!xeno.check_state()) - return - - if (!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) playsound(get_turf(xeno), 'sound/effects/bang.ogg', 25, 0) xeno.visible_message(SPAN_XENODANGER("[xeno] smashes into the ground!"), SPAN_XENODANGER("We smash into the ground!")) xeno.create_stomp() - for (var/mob/living/carbon/target_to_stomp in get_turf(xeno)) // MOBS ONTOP - if (target_to_stomp.stat == DEAD || xeno.can_not_harm(target_to_stomp)) + for(var/mob/living/carbon/target_to_stomp in get_turf(xeno)) // MOBS ONTOP + if(target_to_stomp.stat == DEAD || xeno.can_not_harm(target_to_stomp)) continue new effect_type_base(target_to_stomp, xeno, null, null, get_xeno_stun_duration(target_to_stomp, effect_duration)) @@ -457,8 +440,8 @@ target_to_stomp.last_damage_data = create_cause_data(xeno.caste_type, xeno) target_to_stomp.emote("pain") target_to_stomp = stomped_carbon - for (var/mob/living/carbon/targets_to_get in orange(distance, get_turf(xeno))) // MOBS AROUND - if (targets_to_get.stat == DEAD || xeno.can_not_harm(targets_to_get)) + for(var/mob/living/carbon/targets_to_get in orange(distance, get_turf(xeno))) // MOBS AROUND + if(targets_to_get.stat == DEAD || xeno.can_not_harm(targets_to_get)) continue if(targets_to_get.client) shake_camera(targets_to_get, 10, 2) @@ -469,20 +452,13 @@ apply_cooldown() return ..() -/datum/action/xeno_action/onclick/crusher_shield/use_ability(atom/Target) +/datum/action/xeno_action/onclick/crusher_shield/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) - return - - if (!action_cooldown_check()) + if(!istype(xeno)) return - if (!xeno.check_state()) - return - - if (!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) xeno.visible_message(SPAN_XENOWARNING("[xeno] hunkers down and bolsters its defenses!"), SPAN_XENOHIGHDANGER("We hunker down and bolster our defenses!")) button.icon_state = "template_active" @@ -503,7 +479,7 @@ /datum/action/xeno_action/onclick/crusher_shield/proc/remove_explosion_immunity() var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) + if(!istype(xeno)) return xeno.explosivearmor_modifier -= 1000 @@ -512,16 +488,16 @@ /datum/action/xeno_action/onclick/crusher_shield/proc/remove_shield() var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) + if(!istype(xeno)) return var/datum/xeno_shield/found - for (var/datum/xeno_shield/shield in xeno.xeno_shields) - if (shield.shield_source == XENO_SHIELD_SOURCE_CRUSHER) + for(var/datum/xeno_shield/shield in xeno.xeno_shields) + if(shield.shield_source == XENO_SHIELD_SOURCE_CRUSHER) found = shield break - if (istype(found)) + if(istype(found)) found.on_removal() qdel(found) to_chat(xeno, SPAN_XENOHIGHDANGER("We feel our enhanced shield end!")) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm index c14045216b4ed..d325fde650445 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm @@ -64,26 +64,50 @@ pelt = /obj/item/pelt/defender /mob/living/carbon/xenomorph/defender/handle_special_state() - if(fortify) + if(HAS_TRAIT(src, TRAIT_ABILITY_FORTIFY)) return TRUE - if(crest_defense) + if(HAS_TRAIT(src, TRAIT_ABILITY_CREST)) return TRUE return FALSE /mob/living/carbon/xenomorph/defender/handle_special_wound_states(severity) . = ..() - if(fortify) + if(HAS_TRAIT(src, TRAIT_ABILITY_FORTIFY)) return "Defender_fortify_[severity]" - if(crest_defense) + if(HAS_TRAIT(src, TRAIT_ABILITY_CREST)) return "Defender_crest_[severity]" /mob/living/carbon/xenomorph/defender/handle_special_backpack_states() . = ..() - if(fortify) + if(HAS_TRAIT(src, TRAIT_ABILITY_FORTIFY)) return " Fortify" - if(crest_defense) + if(HAS_TRAIT(src, TRAIT_ABILITY_CREST)) return " Crest" +/mob/living/carbon/xenomorph/defender/ex_act() + . = ..() + if(HAS_TRAIT(src, TRAIT_INCAPACITATED) && HAS_TRAIT(src, TRAIT_FLOORED)) + if(HAS_TRAIT(src, TRAIT_ABILITY_FORTIFY)) + var/datum/action/xeno_action/activable/fortify/fortify_used = get_action(src, /datum/action/xeno_action/activable/fortify) + fortify_used.stop_fortify() + + if(HAS_TRAIT(src, TRAIT_ABILITY_CREST)) + var/datum/action/xeno_action/onclick/toggle_crest/crest_used = get_action(src, /datum/action/xeno_action/onclick/toggle_crest) + crest_used.stop_crest() + + +/mob/living/carbon/xenomorph/defender/death() + var/datum/action/xeno_action/activable/fortify/fortify_used = get_action(src, /datum/action/xeno_action/activable/fortify) + if(HAS_TRAIT(src, TRAIT_ABILITY_FORTIFY)) + fortify_used.stop_fortify() + + var/datum/action/xeno_action/onclick/toggle_crest/crest_used = get_action(src, /datum/action/xeno_action/onclick/toggle_crest) + if(HAS_TRAIT(src, TRAIT_ABILITY_CREST)) + crest_used.stop_crest() + + return ..() + + /datum/behavior_delegate/defender_base name = "Base Defender Behavior Delegate" @@ -91,159 +115,149 @@ if(bound_xeno.stat == DEAD) return - if(bound_xeno.fortify && bound_xeno.health > 0) - bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Defender Fortify" - return TRUE - if(bound_xeno.crest_defense && bound_xeno.health > 0) - bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Defender Crest" - return TRUE + if(!HAS_TRAIT(bound_xeno, TRAIT_INCAPACITATED) && !HAS_TRAIT(bound_xeno, TRAIT_FLOORED)) + if(HAS_TRAIT(bound_xeno, TRAIT_ABILITY_FORTIFY) && bound_xeno.health > 0) + bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Defender Fortify" + return TRUE + if(HAS_TRAIT(bound_xeno, TRAIT_ABILITY_CREST) && bound_xeno.health > 0) + bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Defender Crest" + return TRUE -/datum/action/xeno_action/onclick/toggle_crest/use_ability(atom/target) - var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) - return + else + bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Defender Knocked Down" - if(xeno.fortify) - to_chat(xeno, SPAN_XENOWARNING("We cannot use abilities while fortified.")) - return - if(!xeno.check_state()) +/datum/action/xeno_action/onclick/toggle_crest/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(xeno)) return - if(!action_cooldown_check()) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_FORTIFY)) + to_chat(xeno, SPAN_XENOWARNING("We cannot use crest while fortified.")) return - if(!xeno.crest_defense) - RegisterSignal(owner, COMSIG_MOB_STATCHANGE, PROC_REF(unconscious_check)) - headcrest_switch(xeno, TRUE) - if(xeno.selected_ability != src) - button.icon_state = "template_active" + XENO_ACTION_CHECK(xeno) + + if(HAS_TRAIT(xeno, TRAIT_ABILITY_CREST)) + stop_crest() else - UnregisterSignal(owner, COMSIG_MOB_STATCHANGE) - headcrest_switch(xeno, FALSE) - if(xeno.selected_ability != src) - button.icon_state = "template_xeno" + start_crest() - apply_cooldown() return ..() -/datum/action/xeno_action/onclick/toggle_crest/proc/headcrest_switch(mob/living/carbon/xenomorph/xeno, crest_state) - if(xeno.crest_defense == crest_state) - return - - if(crest_state) - to_chat(xeno, SPAN_XENOWARNING("We lower our crest.")) +/datum/action/xeno_action/onclick/toggle_crest/proc/start_crest() + var/mob/living/carbon/xenomorph/xeno = owner - xeno.ability_speed_modifier += speed_debuff - xeno.armor_deflection_buff += armor_buff - xeno.crest_defense = TRUE - xeno.mob_size = MOB_SIZE_BIG //knockback immune - button.icon_state = "template_active" - else - to_chat(xeno, SPAN_XENOWARNING("We raise our crest.")) + ADD_TRAIT(xeno, TRAIT_ABILITY_CREST, TRAIT_SOURCE_ABILITY("crest")) + to_chat(xeno, SPAN_XENOWARNING("We lower our crest.")) + xeno.ability_speed_modifier += speed_debuff + xeno.armor_deflection_buff += armor_buff + xeno.mob_size = MOB_SIZE_BIG //knockback immune + button.icon_state = "template_active" + xeno.update_icons() + apply_cooldown() - xeno.ability_speed_modifier -= speed_debuff - xeno.armor_deflection_buff -= armor_buff - xeno.crest_defense = FALSE - xeno.mob_size = MOB_SIZE_XENO //no longer knockback immune - button.icon_state = "template_xeno" +/datum/action/xeno_action/onclick/toggle_crest/proc/stop_crest() + var/mob/living/carbon/xenomorph/xeno = owner + REMOVE_TRAIT(xeno, TRAIT_ABILITY_CREST, TRAIT_SOURCE_ABILITY("crest")) + to_chat(xeno, SPAN_XENOWARNING("We raise our crest.")) + xeno.ability_speed_modifier -= speed_debuff + xeno.armor_deflection_buff -= armor_buff + xeno.mob_size = MOB_SIZE_XENO //no longer knockback immune + button.icon_state = "template_xeno" xeno.update_icons() + apply_cooldown() + + // Defender Headbutt /datum/action/xeno_action/activable/headbutt/use_ability(atom/target_atom) - var/mob/living/carbon/xenomorph/fendy = owner - if(!istype(fendy)) - return - - if(!isxeno_human(target_atom) || fendy.can_not_harm(target_atom)) + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(xeno)) return - if(!fendy.check_state()) + if(!isxeno_human(target_atom) || xeno.can_not_harm(target_atom)) return - if(!action_cooldown_check()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) - if(!check_and_use_plasma_owner()) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_FORTIFY) && !usable_while_fortified) + to_chat(xeno, SPAN_XENOWARNING("We cannot use headbutt while fortified.")) return - if(fendy.fortify && !usable_while_fortified) - to_chat(fendy, SPAN_XENOWARNING("We cannot use headbutt while fortified.")) + var/mob/living/carbon/target_carbon = target_atom + if(target_carbon.stat == DEAD) return - var/mob/living/carbon/carbone = target_atom - if(carbone.stat == DEAD) - return + var/fortify = HAS_TRAIT(xeno, TRAIT_ABILITY_FORTIFY) + var/crest_defense = HAS_TRAIT(xeno, TRAIT_ABILITY_CREST) - var/distance = get_dist(fendy, carbone) + var/distance = get_dist(xeno, target_carbon) - var/max_distance = 3 - (fendy.crest_defense * 2) + var/max_distance = 3 - (crest_defense ? 2 : 0) if(distance > max_distance) return - if(!fendy.crest_defense) + if(!crest_defense) apply_cooldown() - fendy.throw_atom(get_step_towards(carbone, fendy), 3, SPEED_SLOW, fendy, tracking=TRUE) - if(!fendy.Adjacent(carbone)) + xeno.throw_atom(get_step_towards(target_carbon, xeno), 3, SPEED_SLOW, xeno, tracking=TRUE) + if(!xeno.Adjacent(target_carbon)) on_cooldown_end() return - carbone.last_damage_data = create_cause_data(fendy.caste_type, fendy) - fendy.visible_message(SPAN_XENOWARNING("[fendy] rams [carbone] with its armored crest!"), - SPAN_XENOWARNING("We ram [carbone] with our armored crest!")) + target_carbon.last_damage_data = create_cause_data(xeno.caste_type, xeno) + xeno.visible_message(SPAN_XENOWARNING("[xeno] rams [target_carbon] with its armored crest!"), + SPAN_XENOWARNING("We ram [target_carbon] with our armored crest!")) - if(carbone.stat != DEAD && (!(carbone.status_flags & XENO_HOST) || !HAS_TRAIT(carbone, TRAIT_NESTED))) + if(target_carbon.stat != DEAD && (!(target_carbon.status_flags & XENO_HOST) || !HAS_TRAIT(target_carbon, TRAIT_NESTED))) // -10 damage if their crest is down. - var/damage = base_damage - (fendy.crest_defense * 10) - carbone.apply_armoured_damage(get_xeno_damage_slash(carbone, damage), ARMOR_MELEE, BRUTE, "chest", 5) + var/damage = base_damage - (crest_defense ? 10 : 0) + target_carbon.apply_armoured_damage(get_xeno_damage_slash(target_carbon, damage), ARMOR_MELEE, BRUTE, "chest", 5) - var/facing = get_dir(fendy, carbone) - var/headbutt_distance = 1 + (fendy.crest_defense * 2) + (fendy.fortify * 2) + var/facing = get_dir(xeno, target_carbon) + var/headbutt_distance = 1 + (crest_defense ? 2 : 0) + (fortify ? 2 : 0) // Hmm today I will kill a marine while looking away from them - fendy.face_atom(carbone) - fendy.animation_attack_on(carbone) - fendy.flick_attack_overlay(carbone, "punch") - fendy.throw_carbon(carbone, facing, headbutt_distance, SPEED_SLOW, shake_camera = FALSE, immobilize = FALSE) - playsound(carbone,'sound/weapons/alien_claw_block.ogg', 50, 1) + xeno.face_atom(target_carbon) + xeno.animation_attack_on(target_carbon) + xeno.flick_attack_overlay(target_carbon, "punch") + xeno.throw_carbon(target_carbon, facing, headbutt_distance, SPEED_SLOW, shake_camera = FALSE, immobilize = FALSE) + playsound(target_carbon,'sound/weapons/alien_claw_block.ogg', 50, 1) apply_cooldown() return ..() + + // Defender Tail Sweep -/datum/action/xeno_action/onclick/tail_sweep/use_ability(atom/A) +/datum/action/xeno_action/onclick/tail_sweep/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) + if(!istype(xeno)) return - if(!xeno.check_state()) - return - - if (!action_cooldown_check()) - return + XENO_ACTION_CHECK(xeno) - if(xeno.fortify) - to_chat(src, SPAN_XENOWARNING("We cannot use tail swipe while fortified.")) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_FORTIFY)) + to_chat(xeno, SPAN_XENOWARNING("We cannot use tail swipe while fortified.")) return - if(xeno.crest_defense) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_CREST)) xeno.balloon_alert(xeno, "our crest is lowered!", text_color = "#7d32bb", delay = 1 SECONDS) return xeno.visible_message(SPAN_XENOWARNING("[xeno] sweeps its tail in a wide circle!"), SPAN_XENOWARNING("We sweep our tail in a wide circle!")) - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) xeno.spin_circle() xeno.emote("tail") var/sweep_range = 1 for(var/mob/living/carbon/human in orange(sweep_range, get_turf(xeno))) - if (!isxeno_human(human) || xeno.can_not_harm(human)) + if(!isxeno_human(human) || xeno.can_not_harm(human)) continue if(human.stat == DEAD) continue @@ -264,74 +278,66 @@ apply_cooldown() return ..() + + // Defender Fortify -/datum/action/xeno_action/activable/fortify/use_ability(atom/target) +/datum/action/xeno_action/activable/fortify/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) + if(!istype(xeno)) return - if(xeno.crest_defense) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_CREST)) xeno.balloon_alert(xeno, "our crest is lowered!", text_color = "#7d32bb", delay = 1 SECONDS) return - if(!xeno.check_state()) - return - - if (!action_cooldown_check()) - return + XENO_ACTION_CHECK(xeno) playsound(get_turf(xeno), 'sound/effects/stonedoor_openclose.ogg', 30, 1) - if(!xeno.fortify) - RegisterSignal(owner, COMSIG_MOB_STATCHANGE, PROC_REF(unconscious_check)) - fortify_switch(xeno, TRUE) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_FORTIFY)) + stop_fortify() if(xeno.selected_ability != src) - button.icon_state = "template_active" + button.icon_state = "template_xeno" else - UnregisterSignal(owner, COMSIG_MOB_STATCHANGE) - fortify_switch(xeno, FALSE) + start_fortify() if(xeno.selected_ability != src) - button.icon_state = "template_xeno" + button.icon_state = "template_active" + xeno.update_icons() apply_cooldown() return ..() -/datum/action/xeno_action/activable/fortify/action_activate() - . = ..() - ..() +/datum/action/xeno_action/activable/fortify/proc/start_fortify() var/mob/living/carbon/xenomorph/xeno = owner - if(xeno.fortify && xeno.selected_ability != src) - button.icon_state = "template_active" -/datum/action/xeno_action/activable/fortify/action_deselect() - ..() + RegisterSignal(xeno, COMSIG_XENO_ENTER_CRIT, PROC_REF(unconscious_check)) + RegisterSignal(xeno, COMSIG_MOB_DEATH, PROC_REF(unconscious_check)) + RegisterSignal(xeno, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE, PROC_REF(check_directional_projectile_armor)) + + ADD_TRAIT(xeno, TRAIT_ABILITY_FORTIFY, TRAIT_SOURCE_ABILITY("fortify")) + to_chat(xeno, SPAN_XENOWARNING("We tuck ourself into a defensive stance.")) + + apply_modifiers(xeno, TRUE) + xeno.mob_size = MOB_SIZE_IMMOBILE //knockback immune + xeno.mob_flags &= ~SQUEEZE_UNDER_VEHICLES + +/datum/action/xeno_action/activable/fortify/proc/stop_fortify() var/mob/living/carbon/xenomorph/xeno = owner - if(xeno.fortify) - button.icon_state = "template_active" -/datum/action/xeno_action/activable/fortify/proc/fortify_switch(mob/living/carbon/xenomorph/xeno, fortify_state) - if(xeno.fortify == fortify_state) - return + UnregisterSignal(xeno, COMSIG_XENO_ENTER_CRIT) + UnregisterSignal(xeno, COMSIG_MOB_DEATH) + UnregisterSignal(xeno, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE) - if(fortify_state) - to_chat(xeno, SPAN_XENOWARNING("We tuck ourself into a defensive stance.")) - RegisterSignal(owner, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE, PROC_REF(check_directional_armor)) - xeno.mob_size = MOB_SIZE_IMMOBILE //knockback immune - xeno.mob_flags &= ~SQUEEZE_UNDER_VEHICLES - xeno.fortify = TRUE - else - to_chat(xeno, SPAN_XENOWARNING("We resume our normal stance.")) - REMOVE_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Fortify")) - xeno.anchored = FALSE - UnregisterSignal(owner, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE) - xeno.mob_size = MOB_SIZE_XENO //no longer knockback immune - xeno.mob_flags |= SQUEEZE_UNDER_VEHICLES - xeno.fortify = FALSE - - apply_modifiers(xeno, fortify_state) - xeno.update_icons() + REMOVE_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Fortify")) + REMOVE_TRAIT(xeno, TRAIT_ABILITY_FORTIFY, TRAIT_SOURCE_ABILITY("fortify")) + to_chat(xeno, SPAN_XENOWARNING("We resume our normal stance.")) -/datum/action/xeno_action/activable/fortify/proc/apply_modifiers(mob/living/carbon/xenomorph/xeno, fortify_state) + apply_modifiers(xeno, FALSE) + xeno.anchored = FALSE + xeno.mob_size = MOB_SIZE_XENO //no longer knockback immune + xeno.mob_flags |= SQUEEZE_UNDER_VEHICLES + +/datum/action/xeno_action/activable/fortify/proc/apply_modifiers(mob/living/carbon/xenomorph/xeno, fortify_state = FALSE) if(fortify_state) xeno.armor_deflection_buff += 30 xeno.armor_explosive_buff += 60 @@ -343,21 +349,16 @@ xeno.armor_explosive_buff -= 60 xeno.small_explosives_stun = TRUE -/datum/action/xeno_action/activable/fortify/proc/check_directional_armor(mob/living/carbon/xenomorph/defendy, list/damagedata) - SIGNAL_HANDLER - var/projectile_direction = damagedata["direction"] - // If the defender is facing the projectile. - if(defendy.dir & REVERSE_DIR(projectile_direction)) - damagedata["armor"] += frontal_armor - -/datum/action/xeno_action/activable/fortify/proc/unconscious_check() - SIGNAL_HANDLER - - UnregisterSignal(owner, COMSIG_MOB_STATCHANGE) - fortify_switch(owner, FALSE) +/datum/action/xeno_action/activable/fortify/action_activate() + . = ..() + ..() + var/mob/living/carbon/xenomorph/xeno = owner + if(HAS_TRAIT(xeno, TRAIT_ABILITY_FORTIFY) && xeno.selected_ability != src) + button.icon_state = "template_active" -/datum/action/xeno_action/onclick/toggle_crest/proc/unconscious_check() - SIGNAL_HANDLER +/datum/action/xeno_action/activable/fortify/action_deselect() + ..() + var/mob/living/carbon/xenomorph/xeno = owner + if(HAS_TRAIT(xeno, TRAIT_ABILITY_FORTIFY)) + button.icon_state = "template_active" - UnregisterSignal(owner, COMSIG_MOB_STATCHANGE) - headcrest_switch(owner, FALSE) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Despoiler.dm b/code/modules/mob/living/carbon/xenomorph/castes/Despoiler.dm index 8f5f78f493127..26637675c50e3 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Despoiler.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Despoiler.dm @@ -71,7 +71,7 @@ /mob/living/carbon/xenomorph/despoiler/proc/update_hypertension() var/image/holder = hud_list[SPECIAL_HUD] holder.overlays.Cut() - if (stat == DEAD) + if(stat == DEAD) return var/datum/behavior_delegate/despoiler_base/delegate = behavior_delegate @@ -98,7 +98,6 @@ /datum/behavior_delegate/despoiler_base name = "Base Despoiler Behavior Delegate" - var/next_ability_empowered = FALSE var/image/empowered_overlay // State @@ -119,7 +118,7 @@ xeno.update_hypertension() /datum/behavior_delegate/despoiler_base/on_life() - if (last_hypertension_loss_time <= last_combat_time && last_combat_time + hypertension_loss_time <= world.time) + if(last_hypertension_loss_time <= last_combat_time && last_combat_time + hypertension_loss_time <= world.time) hypertension_stacks = max(0, hypertension_stacks - 1) var/mob/living/carbon/xenomorph/despoiler/xeno = bound_xeno xeno.update_hypertension() @@ -129,7 +128,7 @@ last_combat_time = world.time /datum/behavior_delegate/despoiler_base/melee_attack_modify_burn_damage(original_damage, mob/living/carbon/target_carbon) - if (!isxeno_human(target_carbon)) + if(!isxeno_human(target_carbon)) return original_damage increase_hypertension(100) @@ -149,33 +148,32 @@ return original_damage + burn_damage -/datum/action/xeno_action/activable/tail_stab/despoiler/ability_act(mob/living/carbon/xenomorph/stabbing_xeno, mob/living/carbon/target, obj/limb/limb, apply_behavior_delagate = FALSE) +/datum/action/xeno_action/activable/tail_stab/despoiler/ability_act(mob/living/carbon/xenomorph/stabbing_xeno, mob/living/carbon/target_carbon, obj/limb/target_limb, apply_behavior_delagate = FALSE) . = ..() - var/datum/effects/acid/acid_effect = locate() in target.effects_list + var/datum/effects/acid/acid_effect = locate() in target_carbon.effects_list if(!acid_effect) return - target.apply_armoured_damage(acid_effect.acid_level * 15, ARMOR_BIO, BURN, limb ? limb.name : "chest", acid_effect.acid_level * 10) + target_carbon.apply_armoured_damage(acid_effect.acid_level * 15, ARMOR_BIO, BURN, target_limb ? target_limb.name : "chest", acid_effect.acid_level * 10) /datum/action/xeno_action/activable/acid_barrage/on_select(mob/user) RegisterSignal(user, COMSIG_MOB_MOUSEDOWN, PROC_REF(on_mouse_down)) -/datum/action/xeno_action/activable/acid_barrage/proc/on_mouse_down(mob/source, atom/target, turf, skin_ctl, params) +/datum/action/xeno_action/activable/acid_barrage/proc/on_mouse_down(mob/source, atom/target_atom, target_turf, skin_ctl, params) SIGNAL_HANDLER var/list/mods = params2list(params) - source.click(target, mods) + source.click(target_atom, mods) /datum/action/xeno_action/activable/acid_barrage/on_deselect(mob/user) UnregisterSignal(user, COMSIG_MOB_MOUSEDOWN) -/datum/action/xeno_action/activable/acid_barrage/use_ability(atom/target) +/datum/action/xeno_action/activable/acid_barrage/use_ability(atom/target_atom) . = ..() var/mob/living/carbon/xenomorph/despoiler/xeno = owner if(!action_cooldown_check()) to_chat(xeno, SPAN_WARNING("We must wait for our spit glands to refill.")) return - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) // Prevent some mouse down shenangians apply_cooldown() @@ -202,7 +200,7 @@ /datum/action/xeno_action/activable/acid_barrage/proc/notify_max_charge() to_chat(owner, SPAN_XENOHIGHDANGER("Our acid barrage is full!")) -/datum/action/xeno_action/activable/acid_barrage/proc/release_barrage(atom/source, atom/target, turf, skin_ctl, params) +/datum/action/xeno_action/activable/acid_barrage/proc/release_barrage(atom/source, atom/target_atom, turf, skin_ctl, params) SIGNAL_HANDLER // The real cooldown starts here apply_cooldown_override(xeno_cooldown) @@ -220,8 +218,8 @@ var/datum/behavior_delegate/despoiler_base/delegate = xeno.behavior_delegate var/time_charged = min(world.time - start_time, max_charge_time) var/modifier = 0 - if(delegate.next_ability_empowered) - delegate.next_ability_empowered = FALSE + if(HAS_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER)) + REMOVE_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER, TRAIT_SOURCE_ABILITY("catalyze_empower")) modifier += empower_modifier xeno.overlays -= delegate.empowered_overlay @@ -229,7 +227,7 @@ playsound(xeno, "alien_roarhiss", 30, 0, status = 0) playsound(xeno.loc, "acid_spit", 25, 1) for(var/index in 1 to barrage_size) - var/initial_angle = Get_Angle(xeno, target) + var/initial_angle = Get_Angle(xeno, target_atom) var/rand_angle = rand(-scatter, scatter) var/turf/new_target = get_angle_target_turf(xeno, initial_angle + rand_angle, rand(1, 6)) var/obj/projectile/proj = new (get_turf(xeno), create_cause_data(xeno.ammo.name, xeno)) @@ -242,10 +240,11 @@ proj.def_zone = xeno.get_limbzone_target() proj.fire_at(new_target, xeno, xeno, xeno.ammo.max_range, xeno.ammo.shell_speed) -/datum/action/xeno_action/activable/pounce/caustic_embrace/use_ability(atom/target) + + +/datum/action/xeno_action/activable/pounce/caustic_embrace/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/despoiler/xeno = owner - var/datum/behavior_delegate/despoiler_base/delegate = xeno.behavior_delegate - if(delegate.next_ability_empowered) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER)) distance = empowered_distance else distance = initial(distance) @@ -257,46 +256,46 @@ var/datum/behavior_delegate/despoiler_base/delegate = xeno.behavior_delegate xeno.emote("roar") - if(delegate.next_ability_empowered) - delegate.next_ability_empowered = FALSE + if(HAS_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER)) + REMOVE_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER, TRAIT_SOURCE_ABILITY("catalyze_empower")) xeno.overlays -= delegate.empowered_overlay return // Handled in additional_effects() var/list/turfs = orange(1, get_turf(xeno)) - get_step(xeno.loc, REVERSE_DIR(xeno.dir)) - for(var/turf/turf in turfs) - for(var/mob/living/carbon/human/target in turf) - playsound(target.loc, "acid_strike", 25, 1) - var/armor_block_acid = target.getarmor("chest", ARMOR_BIO) + for(var/turf/target_turf in turfs) + for(var/mob/living/carbon/human/target_human in target_turf) + playsound(target_human.loc, "acid_strike", 25, 1) + var/armor_block_acid = target_human.getarmor("chest", ARMOR_BIO) var/n_acid_damage = armor_damage_reduction(GLOB.marine_melee, damage, armor_block_acid) if(n_acid_damage <= 0.34*damage) - to_chat(target, SPAN_WARNING("Your armor absorbs the acid!")) + to_chat(target_human, SPAN_WARNING("Your armor absorbs the acid!")) else if(n_acid_damage <= 0.67*damage) - to_chat(target, SPAN_WARNING("Your armor softens the acid!")) - target.apply_damage(n_acid_damage, BURN, "chest") + to_chat(target_human, SPAN_WARNING("Your armor softens the acid!")) + target_human.apply_damage(n_acid_damage, BURN, "chest") if(prob(30)) - new /obj/effect/lingering_acid(turf, xeno.hivenumber) - new /obj/effect/xenomorph/xeno_telegraph/yellow(turf, 2) + new /obj/effect/lingering_acid(target_turf, xeno.hivenumber) + new /obj/effect/xenomorph/xeno_telegraph/yellow(target_turf, 2) -/datum/action/xeno_action/activable/pounce/caustic_embrace/additional_effects(mob/living/carbon/target) +/datum/action/xeno_action/activable/pounce/caustic_embrace/additional_effects(mob/living/carbon/target_carbon) var/mob/living/carbon/xenomorph/despoiler/xeno = owner - var/datum/behavior_delegate/despoiler_base/delegate = xeno.behavior_delegate - if(!delegate.next_ability_empowered) + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER)) return - xeno.visible_message(SPAN_XENODANGER("[xeno] ravages [target] as it charges at them!"), SPAN_XENODANGER("We ruthlessly ravage [target] as we charge at them!")) - target.apply_effect(weaken_duration, WEAKEN) - target.attack_alien(xeno, rand(xeno.melee_damage_lower, xeno.melee_damage_upper)) - xeno.flick_attack_overlay(target, "embrace_slash") + xeno.visible_message(SPAN_XENODANGER("[xeno] ravages [target_carbon] as it charges at them!"), SPAN_XENODANGER("We ruthlessly ravage [target_carbon] as we charge at them!")) + target_carbon.apply_effect(weaken_duration, WEAKEN) + target_carbon.attack_alien(xeno, rand(xeno.melee_damage_lower, xeno.melee_damage_upper)) + xeno.flick_attack_overlay(target_carbon, "embrace_slash") - var/datum/effects/acid/acid_effect = locate() in target.effects_list + var/datum/effects/acid/acid_effect = locate() in target_carbon.effects_list if(!acid_effect) - acid_effect = new /datum/effects/acid(target) + acid_effect = new /datum/effects/acid(target_carbon) acid_effect.enhance_acid() acid_effect.enhance_acid(TRUE) + /datum/action/xeno_action/onclick/oozing_wounds/use_ability() . = ..() @@ -307,35 +306,35 @@ to_chat(xeno, SPAN_WARNING("We must wait for our acid glands to refill.")) return - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) apply_cooldown() playsound(xeno, "alien_roarhiss", 30, 0, status = 0) var/severity = (xeno.health <= (0.7 * xeno.maxHealth)) + (xeno.health <= (0.3 * xeno.maxHealth)) var/acid_range = severity + 1 - var/empowered = delegate.next_ability_empowered - if(empowered) - delegate.next_ability_empowered = FALSE + if(HAS_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER)) + REMOVE_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER, TRAIT_SOURCE_ABILITY("catalyze_empower")) xeno.overlays -= delegate.empowered_overlay - for(var/turf/turf in orange(acid_range, get_turf(xeno))) - if(get_dist_sqrd(turf, xeno) > acid_range ** 2) + for(var/turf/target_turf in orange(acid_range, get_turf(xeno))) + if(get_dist_sqrd(target_turf, xeno) > acid_range ** 2) continue - addtimer(CALLBACK(src, PROC_REF(spawn_acid), xeno, turf, empowered), 0.2 SECONDS * get_dist(turf, xeno)) + addtimer(CALLBACK(src, PROC_REF(spawn_acid), xeno, target_turf), 0.2 SECONDS * get_dist(target_turf, xeno)) -/datum/action/xeno_action/onclick/oozing_wounds/proc/spawn_acid(mob/living/carbon/xenomorph/xeno, turf/turf, empowered) - if(empowered) - new /obj/effect/xenomorph/spray/despoiler/empowered(turf, create_cause_data(initial(xeno.caste_type), src), xeno.hivenumber) +/datum/action/xeno_action/onclick/oozing_wounds/proc/spawn_acid(mob/living/carbon/xenomorph/xeno, turf/target_turf) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER)) + new /obj/effect/xenomorph/spray/despoiler/empowered(target_turf, create_cause_data(initial(xeno.caste_type), src), xeno.hivenumber) else - new /obj/effect/xenomorph/spray/despoiler(turf, create_cause_data(initial(xeno.caste_type), src), xeno.hivenumber) + new /obj/effect/xenomorph/spray/despoiler(target_turf, create_cause_data(initial(xeno.caste_type), src), xeno.hivenumber) if(prob(20)) - new /obj/effect/lingering_acid(turf, xeno.hivenumber) + new /obj/effect/lingering_acid(target_turf, xeno.hivenumber) + -/datum/action/xeno_action/onclick/catalyze/use_ability(atom/target) + +/datum/action/xeno_action/onclick/catalyze/use_ability(atom/target_atom) . = ..() var/mob/living/carbon/xenomorph/despoiler/xeno = owner var/datum/behavior_delegate/despoiler_base/delegate = xeno.behavior_delegate @@ -344,8 +343,7 @@ to_chat(xeno, SPAN_WARNING("We must wait before empowering an ability again.")) return - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) if(delegate.hypertension_stacks < 1) to_chat(xeno, SPAN_WARNING("We don't enough acid to do that.")) @@ -354,7 +352,7 @@ apply_cooldown() delegate.hypertension_stacks-- - delegate.next_ability_empowered = TRUE + ADD_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER, TRAIT_SOURCE_ABILITY("catalyze_empower")) delegate.empowered_overlay = image('icons/mob/xenos/castes/tier_3/despoiler.dmi', "hypertension") delegate.empowered_overlay.layer = FLY_LAYER delegate.empowered_overlay.plane = ABOVE_GAME_PLANE @@ -366,10 +364,12 @@ /datum/action/xeno_action/onclick/catalyze/proc/debuff_next_ability() var/mob/living/carbon/xenomorph/despoiler/xeno = owner var/datum/behavior_delegate/despoiler_base/delegate = xeno.behavior_delegate - if(delegate.next_ability_empowered) - to_chat(owner, SPAN_XENOHIGHDANGER("We waited too long, our next ability is no longer empowered!")) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER)) + to_chat(xeno, SPAN_XENOHIGHDANGER("We waited too long, our next ability is no longer empowered!")) xeno.overlays -= delegate.empowered_overlay - delegate.next_ability_empowered = FALSE + REMOVE_TRAIT(xeno, TRAIT_ABILITY_CATALYZE_EMPOWER, TRAIT_SOURCE_ABILITY("catalyze_empower")) + + /obj/effect/lingering_acid name = "acid" @@ -393,30 +393,31 @@ /obj/effect/lingering_acid/Initialize(mapload, hive) . = ..() - if (hive) + if(hive) hivenumber = hive var/decay_time = rand(15 SECONDS, 20 SECONDS) animate(src, alpha = 127, time = decay_time) QDEL_IN(src, decay_time) -/obj/effect/lingering_acid/Crossed(atom/movable/movable) +/obj/effect/lingering_acid/Crossed(atom/movable/target_movable) . = ..() - var/mob/living/carbon/carbon = movable - if(!istype(carbon)) + var/mob/living/carbon/target_carbon = target_movable + if(!istype(target_carbon)) return - if(carbon.ally_of_hivenumber(hivenumber)) + if(target_carbon.ally_of_hivenumber(hivenumber)) return - if(HAS_TRAIT(carbon, TRAIT_HAULED)) + if(HAS_TRAIT(target_carbon, TRAIT_HAULED)) return playsound(loc, "sound/bullets/acid_impact1.ogg", 15) - if(!isliving(movable)) + if(!isliving(target_movable)) return - var/mob/living/target_mob = movable + var/mob/living/target_mob = target_movable if(!target_mob.ally_of_hivenumber(hivenumber)) target_mob.next_move_slowdown = max(target_mob.next_move_slowdown, slow_amt) - carbon.apply_armoured_damage(damage, damage_type = BURN, def_zone = pick(target_limbs)) + target_carbon.apply_armoured_damage(damage, damage_type = BURN, def_zone = pick(target_limbs)) + diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm index f9b1ca723478e..498f871497751 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm @@ -93,7 +93,7 @@ /mob/living/carbon/xenomorph/hellhound/initialize_pass_flags(datum/pass_flags_container/PF) ..() - if (PF) + if(PF) PF.flags_pass = PASS_FLAGS_CRAWLER /mob/living/carbon/xenomorph/hellhound/Login() @@ -173,7 +173,7 @@ playsound(hellhound_gorger, "giant_lizard_growl", 30) playsound(carbon, "alien_bite", 30) -/datum/action/xeno_action/onclick/sense_owner/use_ability(atom/layer) +/datum/action/xeno_action/onclick/sense_owner/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/hellhound/xeno = owner var/datum/behavior_delegate/hellhound_base/hound_owner = xeno.behavior_delegate var/direction = -3 diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm index 9bd5e35cb8e34..e68296254a020 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)) @@ -215,6 +158,11 @@ if(lurker_invis) lurker_invis.invisibility_off() // Full cooldown +/datum/action/xeno_action/activable/pounce/lurker/start_airbone() + var/mob/living/carbon/xenomorph/xeno = owner + + ADD_TRAIT(xeno, TRAIT_ABILITY_POUNCE, TRAIT_SOURCE_ABILITY("pounce")) + /datum/action/xeno_action/activable/pounce/lurker/proc/remove_freeze(mob/living/carbon/xenomorph/xeno) SIGNAL_HANDLER @@ -229,19 +177,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 +198,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 +226,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 +245,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 - behavior.on_invisibility_off() + 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 + +/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 +291,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/Praetorian.dm b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm index fac0fcd724f89..4b1af4557d040 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm @@ -107,3 +107,8 @@ bound_xeno.add_xeno_shield(reward_shield, XENO_SHIELD_SOURCE_BASE_PRAE, add_shield_on = TRUE, max_shield = 45) to_chat(bound_xeno, SPAN_NOTICE("Your exoskeleton shimmers for a fraction of a second as the acid coats your target.")) return + +/datum/action/xeno_action/activable/pounce/base_prae_dash/start_airbone() + var/mob/living/carbon/xenomorph/xeno = owner + + ADD_TRAIT(xeno, TRAIT_ABILITY_POUNCE, TRAIT_SOURCE_ABILITY("pounce")) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm b/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm index 262e7c1e1b88b..15352fa40452a 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm @@ -154,7 +154,7 @@ You must still listen to the queen. . = list() . += "Kills: [kills]/[max_kills]" -/datum/behavior_delegate/predalien_base/on_kill_mob(mob/M) +/datum/behavior_delegate/predalien_base/on_kill_mob(mob/target_mob) . = ..() kills = min(kills + 1, max_kills) @@ -184,6 +184,9 @@ You must still listen to the queen. if(isyautja(target_human) && yautja_glove) if(HAS_TRAIT(target_human, TRAIT_CLOAKED)) yautja_glove.decloak(target_human, TRUE, DECLOAK_PREDALIEN) + target_human.add_filter("uncloack", 1, list("type" = "outline", "color" = "#32fff58c", "size" = 1.5)) + addtimer(CALLBACK(src, PROC_REF(disable_filter), target_human), 3 SECONDS) + playsound(target_human.loc, 'sound/effects/pred_force_decloak.ogg', 100, 1, 10) yautja_glove.cloak_timer = xeno_cooldown * 0.1 else if(isxeno(target_carbon) && xeno.can_not_harm(target_carbon)) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm index 462fb168d5dd0..f4d9d1b6cda6b 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm @@ -58,9 +58,9 @@ if(hive.living_xeno_queen) if(hive.living_xeno_queen.hivenumber == hive.hivenumber) continue - for(var/mob/living/carbon/xenomorph/queen/Q in GLOB.living_xeno_list) - if(Q.hivenumber == hive.hivenumber && !should_block_game_interaction(Q)) - hive.living_xeno_queen = Q + for(var/mob/living/carbon/xenomorph/queen/queen_user in GLOB.living_xeno_list) + if(queen_user.hivenumber == hive.hivenumber && !should_block_game_interaction(queen_user)) + hive.living_xeno_queen = queen_user xeno_message(SPAN_XENOANNOUNCE("A new Queen has risen to lead the Hive! Rejoice!"),3,hive.hivenumber) continue outer_loop hive.living_xeno_queen = null @@ -73,7 +73,6 @@ color = "#a800a8" hud_possible = list(XENO_STATUS_HUD) - var/mob/is_watching var/hivenumber = XENO_HIVE_NORMAL @@ -82,40 +81,40 @@ var/point_delay = 1 SECONDS -/mob/hologram/queen/Initialize(mapload, mob/living/carbon/xenomorph/queen/Q) - if(!Q) +/mob/hologram/queen/Initialize(mapload, mob/living/carbon/xenomorph/queen/queen_user) + if(!queen_user) return INITIALIZE_HINT_QDEL - if(!istype(Q)) - stack_trace("Tried to initialize a /mob/hologram/queen on type ([Q.type])") + if(!istype(queen_user)) + stack_trace("Tried to initialize a /mob/hologram/queen on type ([queen_user.type])") return INITIALIZE_HINT_QDEL - if(!Q.ovipositor) + if(!queen_user.ovipositor) return INITIALIZE_HINT_QDEL // Make sure to turn off any previous overwatches - Q.overwatch(stop_overwatch = TRUE) + queen_user.overwatch(stop_overwatch = TRUE) . = ..() - RegisterSignal(Q, COMSIG_MOB_PRE_CLICK, PROC_REF(handle_overwatch)) - RegisterSignal(Q, COMSIG_QUEEN_DISMOUNT_OVIPOSITOR, PROC_REF(exit_hologram)) - RegisterSignal(Q, COMSIG_XENO_OVERWATCH_XENO, PROC_REF(start_watching)) - RegisterSignal(Q, list( + RegisterSignal(queen_user, COMSIG_MOB_PRE_CLICK, PROC_REF(handle_overwatch)) + RegisterSignal(queen_user, COMSIG_QUEEN_DISMOUNT_OVIPOSITOR, PROC_REF(exit_hologram)) + RegisterSignal(queen_user, COMSIG_XENO_OVERWATCH_XENO, PROC_REF(start_watching)) + RegisterSignal(queen_user, list( COMSIG_XENO_STOP_OVERWATCH, COMSIG_XENO_STOP_OVERWATCH_XENO ), PROC_REF(stop_watching)) - RegisterSignal(Q, COMSIG_MOB_REAL_NAME_CHANGED, PROC_REF(on_name_changed)) + RegisterSignal(queen_user, COMSIG_MOB_REAL_NAME_CHANGED, PROC_REF(on_name_changed)) RegisterSignal(src, COMSIG_MOVABLE_TURF_ENTER, PROC_REF(turf_weed_only)) // Default color - if(Q.hive.color) - color = Q.hive.color + if(queen_user.hive.color) + color = queen_user.hive.color - hivenumber = Q.hivenumber + hivenumber = queen_user.hivenumber med_hud_set_status() add_to_all_mob_huds() - Q.sight |= SEE_TURFS|SEE_OBJS + queen_user.sight |= SEE_TURFS|SEE_OBJS /mob/hologram/queen/proc/exit_hologram() SIGNAL_HANDLER @@ -131,43 +130,43 @@ qdel(src) -/mob/hologram/queen/handle_move(mob/living/carbon/xenomorph/X, NewLoc, direct) +/mob/hologram/queen/handle_move(mob/living/carbon/xenomorph/xeno, NewLoc, direct) if(is_watching && (turf_weed_only(src, is_watching.loc) & COMPONENT_TURF_DENY_MOVEMENT)) return COMPONENT_OVERRIDE_MOVE - X.overwatch(stop_overwatch = TRUE) + xeno.overwatch(stop_overwatch = TRUE) return ..() -/mob/hologram/queen/proc/start_watching(mob/living/carbon/xenomorph/X, mob/living/carbon/xenomorph/target) +/mob/hologram/queen/proc/start_watching(mob/living/carbon/xenomorph/xeno, mob/living/carbon/xenomorph/target_xeno) SIGNAL_HANDLER - forceMove(target) - is_watching = target + forceMove(target_xeno) + is_watching = target_xeno - RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(target_watching_qdeleted)) + RegisterSignal(target_xeno, COMSIG_PARENT_QDELETING, PROC_REF(target_watching_qdeleted)) return // able to stop watching here before the loc is set to null -/mob/hologram/queen/proc/target_watching_qdeleted(mob/living/carbon/xenomorph/target) +/mob/hologram/queen/proc/target_watching_qdeleted(mob/living/carbon/xenomorph/target_xeno) SIGNAL_HANDLER - stop_watching(linked_mob, target) + stop_watching(linked_mob, target_xeno) -/mob/hologram/queen/proc/stop_watching(mob/living/carbon/xenomorph/X, mob/living/carbon/xenomorph/target) +/mob/hologram/queen/proc/stop_watching(mob/living/carbon/xenomorph/xeno, mob/living/carbon/xenomorph/target_xeno) SIGNAL_HANDLER - if(target) - if(loc == target) - var/turf/T = get_turf(target) + if(target_xeno) + if(loc == target_xeno) + var/turf/target_turf = get_turf(target_xeno) - if(T) - forceMove(T) - UnregisterSignal(target, COMSIG_PARENT_QDELETING) + if(target_turf) + forceMove(target_turf) + UnregisterSignal(target_xeno, COMSIG_PARENT_QDELETING) if(!isturf(loc) || (turf_weed_only(src, loc) & COMPONENT_TURF_DENY_MOVEMENT)) - forceMove(X.loc) + forceMove(xeno.loc) is_watching = null - X.reset_view() + xeno.reset_view() return /mob/hologram/queen/proc/on_name_changed(mob/parent, old_name, new_name) @@ -196,11 +195,11 @@ return COMPONENT_TURF_DENY_MOVEMENT -/mob/hologram/queen/proc/handle_overwatch(mob/living/carbon/xenomorph/queen/Q, atom/A, mods) +/mob/hologram/queen/proc/handle_overwatch(mob/living/carbon/xenomorph/queen/queen_user, atom/target_atom, mods) SIGNAL_HANDLER - var/turf/T = get_turf(A) - if(!istype(T)) + var/turf/target_turf = get_turf(target_atom) + if(!istype(target_turf)) return if(mods[SHIFT_CLICK] && mods[MIDDLE_CLICK]) @@ -209,15 +208,15 @@ next_point = world.time + point_delay - var/message = SPAN_XENONOTICE("[Q] points at [A].") + var/message = SPAN_XENONOTICE("[queen_user] points at [target_atom].") - to_chat(Q, message) - for(var/mob/living/carbon/xenomorph/X in viewers(7, src)) - if(X == Q) + to_chat(queen_user, message) + for(var/mob/living/carbon/xenomorph/xeno in viewers(7, src)) + if(xeno == queen_user) continue - to_chat(X, message) + to_chat(xeno, message) - var/obj/effect/overlay/temp/point/big/queen/point = new(T, src, A) + var/obj/effect/overlay/temp/point/big/queen/point = new(target_turf, src, target_atom) point.color = color return COMPONENT_INTERRUPT_CLICK @@ -225,36 +224,36 @@ if(!mods[CTRL_CLICK]) return - if(isxeno(A)) - var/mob/living/carbon/xenomorph/X = A - if(X.ally_of_hivenumber(hivenumber)) - Q.overwatch(A) + if(isxeno(target_atom)) + var/mob/living/carbon/xenomorph/xeno = target_atom + if(xeno.ally_of_hivenumber(hivenumber)) + queen_user.overwatch(target_atom) return COMPONENT_INTERRUPT_CLICK - if(!(turf_weed_only(src, T) & COMPONENT_TURF_ALLOW_MOVEMENT)) + if(!(turf_weed_only(src, target_turf) & COMPONENT_TURF_ALLOW_MOVEMENT)) return - forceMove(T) + forceMove(target_turf) if(is_watching) - Q.overwatch(stop_overwatch = TRUE) + queen_user.overwatch(stop_overwatch = TRUE) return COMPONENT_INTERRUPT_CLICK -/mob/hologram/queen/handle_view(mob/M, atom/target) - if(M.client) - M.client.perspective = EYE_PERSPECTIVE +/mob/hologram/queen/handle_view(mob/target_mob, atom/target_atom) + if(target_mob.client) + target_mob.client.perspective = EYE_PERSPECTIVE if(is_watching) - M.client.set_eye(is_watching) + target_mob.client.set_eye(is_watching) else - M.client.set_eye(src) + target_mob.client.set_eye(src) return COMPONENT_OVERRIDE_VIEW /mob/hologram/queen/Destroy() if(linked_mob) - var/mob/living/carbon/xenomorph/queen/Q = linked_mob - if(Q.ovipositor) + var/mob/living/carbon/xenomorph/queen/queen_user = linked_mob + if(queen_user.ovipositor) give_action(linked_mob, /datum/action/xeno_action/onclick/eye) linked_mob.sight &= ~(SEE_TURFS|SEE_OBJS) @@ -643,8 +642,8 @@ egg_amount += 0.07 //one egg approximately every 30 seconds if(egg_amount >= 1) if(isturf(loc)) - var/turf/T = loc - if(length(T.contents) <= 25) //so we don't end up with a million object on that turf. + var/turf/target_turf = loc + if(length(target_turf.contents) <= 25) //so we don't end up with a million object on that turf. egg_amount-- new /obj/item/xeno_egg(loc, hivenumber) overlays -= acid_overlay @@ -679,17 +678,17 @@ /mob/living/carbon/xenomorph/queen/proc/screech_ready() to_chat(src, SPAN_WARNING("You feel your throat muscles vibrate. You are ready to screech again.")) - for(var/Z in actions) - var/datum/action/A = Z - A.update_button_icon() + for(var/xeno_ability in actions) + var/datum/action/target_action = xeno_ability + target_action.update_button_icon() -/mob/living/carbon/xenomorph/queen/proc/queen_gut(atom/target) - if(!iscarbon(target)) +/mob/living/carbon/xenomorph/queen/proc/queen_gut(atom/target_atom) + if(!iscarbon(target_atom)) return FALSE - if(HAS_TRAIT(target, TRAIT_HAULED)) - to_chat(src, SPAN_XENOWARNING("[target] needs to be released first.")) + if(HAS_TRAIT(target_atom, TRAIT_HAULED)) + to_chat(src, SPAN_XENOWARNING("[target_atom] needs to be released first.")) return FALSE - var/mob/living/carbon/victim = target + var/mob/living/carbon/victim = target_atom if(get_dist(src, victim) > 1) return FALSE @@ -873,8 +872,8 @@ break anchored = FALSE - for(var/mob/living/carbon/xenomorph/L in hive.xeno_leader_list) - L.handle_xeno_leader_pheromones() + for(var/mob/living/carbon/xenomorph/xeno_leader in hive.xeno_leader_list) + xeno_leader.handle_xeno_leader_pheromones() if(!instant_dismount) xeno_message(SPAN_XENOANNOUNCE("The Queen has shed her ovipositor, evolution progress paused."), 3, hivenumber) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm index 85472a71a63ad..05f775d4096bd 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm @@ -78,45 +78,44 @@ /datum/behavior_delegate/ravager_base var/shield_decay_time = 15 SECONDS // Time in deciseconds before our shield decays var/slash_charge_cdr = 3 SECONDS // Amount to reduce charge cooldown by per slash - var/knockdown_amount = 1.6 - var/fling_distance = 3 - var/empower_targets = 0 - var/super_empower_threshold = 3 var/dmg_buff_per_target = 2 - var/mid_charge = FALSE -/datum/behavior_delegate/ravager_base/melee_attack_modify_damage(original_damage, mob/living/carbon/carbon) +/datum/behavior_delegate/ravager_base/melee_attack_modify_damage(original_damage) var/damage_plus - if(empower_targets) - damage_plus = dmg_buff_per_target * empower_targets + + var/datum/action/xeno_action/onclick/empower/empower_used = get_action(bound_xeno, /datum/action/xeno_action/onclick/empower) + if(empower_used.empower_targets) + damage_plus = dmg_buff_per_target * empower_used.empower_targets return original_damage + damage_plus /datum/behavior_delegate/ravager_base/melee_attack_additional_effects_self() ..() - var/datum/action/xeno_action/activable/pounce/charge/cAction = get_action(bound_xeno, /datum/action/xeno_action/activable/pounce/charge) - if (!cAction.action_cooldown_check()) - cAction.reduce_cooldown(slash_charge_cdr) + var/datum/action/xeno_action/activable/pounce/charge/charge_used = get_action(bound_xeno, /datum/action/xeno_action/activable/pounce/charge) + if(!charge_used.action_cooldown_check()) + charge_used.reduce_cooldown(slash_charge_cdr) /datum/behavior_delegate/ravager_base/append_to_stat() . = list() var/shield_total = 0 - for (var/datum/xeno_shield/xeno_shield in bound_xeno.xeno_shields) - if (xeno_shield.shield_source == XENO_SHIELD_SOURCE_RAVAGER) + for(var/datum/xeno_shield/xeno_shield in bound_xeno.xeno_shields) + if(xeno_shield.shield_source == XENO_SHIELD_SOURCE_RAVAGER) shield_total += xeno_shield.amount . += "Empower Shield: [shield_total]" - . += "Bonus Slash Damage: [dmg_buff_per_target * empower_targets]" + + var/datum/action/xeno_action/onclick/empower/empower_used = get_action(bound_xeno, /datum/action/xeno_action/onclick/empower) + . += "Bonus Slash Damage: [dmg_buff_per_target * empower_used.empower_targets]" /datum/behavior_delegate/ravager_base/on_life() var/datum/xeno_shield/rav_shield - for (var/datum/xeno_shield/xeno_shield in bound_xeno.xeno_shields) - if (xeno_shield.shield_source == XENO_SHIELD_SOURCE_RAVAGER) + for(var/datum/xeno_shield/xeno_shield in bound_xeno.xeno_shields) + if(xeno_shield.shield_source == XENO_SHIELD_SOURCE_RAVAGER) rav_shield = xeno_shield break - if (rav_shield && ((rav_shield.last_damage_taken + shield_decay_time) < world.time)) + if(rav_shield && ((rav_shield.last_damage_taken + shield_decay_time) < world.time)) QDEL_NULL(rav_shield) to_chat(bound_xeno, SPAN_XENODANGER("We feel our shield decay!")) bound_xeno.overlay_shields() @@ -127,23 +126,26 @@ if(!isxeno_human(target_carbon)) return - if(mid_charge && target_carbon) + if(HAS_TRAIT(bound_xeno, TRAIT_ABILITY_POUNCE_CHARGE) && target_carbon) return INTENT_HARM -/datum/action/xeno_action/onclick/empower/use_ability(atom/target) + +/datum/action/xeno_action/activable/pounce/charge/start_airbone() var/mob/living/carbon/xenomorph/xeno = owner - if(!xeno.check_state()) - return - if(!action_cooldown_check()) - return + ADD_TRAIT(xeno, TRAIT_ABILITY_POUNCE, TRAIT_SOURCE_ABILITY("pounce")) + + +/datum/action/xeno_action/onclick/empower/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + + XENO_ACTION_CHECK(xeno) - if(!activated_once) - if (!check_and_use_plasma_owner()) - return + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_PRE_EMPOWER)) + XENO_ACTION_CHECK_USE_PLASMA(xeno) xeno.visible_message(SPAN_XENODANGER("[xeno] starts empowering!"), SPAN_XENODANGER("We start empowering ourself!")) - activated_once = TRUE + ADD_TRAIT(xeno, TRAIT_ABILITY_PRE_EMPOWER, TRAIT_SOURCE_ABILITY("pre_empower")) button.icon_state = "template_active" get_initial_shield() addtimer(CALLBACK(src, PROC_REF(timeout)), time_until_timeout) @@ -153,10 +155,17 @@ actual_empower(xeno) return TRUE -/datum/action/xeno_action/onclick/empower/proc/actual_empower(mob/living/carbon/xenomorph/xeno) - var/datum/behavior_delegate/ravager_base/behavior = xeno.behavior_delegate +/datum/action/xeno_action/onclick/empower/action_cooldown_check() + var/mob/living/carbon/xenomorph/xeno = owner + if(cooldown_timer_id == TIMER_ID_NULL) + return TRUE + else if(HAS_TRAIT(xeno, TRAIT_ABILITY_PRE_EMPOWER)) + return TRUE + else + return FALSE - activated_once = FALSE +/datum/action/xeno_action/onclick/empower/proc/actual_empower(mob/living/carbon/xenomorph/xeno) + REMOVE_TRAIT(xeno, TRAIT_ABILITY_PRE_EMPOWER, TRAIT_SOURCE_ABILITY("pre_empower")) button.icon_state = "template_xeno" xeno.visible_message(SPAN_XENOWARNING("[xeno] gets empowered by the surrounding enemies!"), SPAN_XENOWARNING("We feel a rush of power from the surrounding enemies!")) xeno.create_empower() @@ -168,7 +177,6 @@ var/accumulative_health = 0 var/list/telegraph_atom_list = list() - var/empower_targets for(var/mob/living/mob in mobs_in_range) if(empower_targets >= max_targets) break @@ -184,26 +192,24 @@ accumulative_health += main_empower_base_shield + ADD_TRAIT(xeno, TRAIT_ABILITY_EMPOWER, TRAIT_SOURCE_ABILITY("empower")) xeno.add_xeno_shield(accumulative_health, XENO_SHIELD_SOURCE_RAVAGER) xeno.overlay_shields() - if(empower_targets >= behavior.super_empower_threshold) //you go in deep you reap the rewards - super_empower(xeno, empower_targets, behavior) + if(empower_targets >= super_empower_threshold) //you go in deep you reap the rewards + super_empower(xeno, empower_targets) -/datum/action/xeno_action/onclick/empower/proc/super_empower(mob/living/carbon/xenomorph/xeno, empower_targets, datum/behavior_delegate/ravager_base/behavior) +/datum/action/xeno_action/onclick/empower/proc/super_empower(mob/living/carbon/xenomorph/xeno, empower_targets) xeno.visible_message(SPAN_DANGER("[xeno] glows an eerie red as it empowers further with the strength of [empower_targets] hostiles!"), SPAN_XENOHIGHDANGER("We begin to glow an eerie red, empowered by the [empower_targets] enemies!")) xeno.emote("roar") - - behavior.empower_targets = empower_targets - var/color = "#FF0000" var/alpha = 70 color += num2text(alpha, 2, 16) xeno.add_filter("empower_rage", 1, list("type" = "outline", "color" = color, "size" = 3)) - addtimer(CALLBACK(src, PROC_REF(weaken_superbuff), xeno, behavior), 5 SECONDS) + addtimer(CALLBACK(src, PROC_REF(weaken_superbuff), xeno), 5 SECONDS) -/datum/action/xeno_action/onclick/empower/proc/weaken_superbuff(mob/living/carbon/xenomorph/xeno, datum/behavior_delegate/ravager_base/behavior) +/datum/action/xeno_action/onclick/empower/proc/weaken_superbuff(mob/living/carbon/xenomorph/xeno) xeno.remove_filter("empower_rage") var/color = "#FF0000" @@ -211,80 +217,63 @@ color += num2text(alpha, 2, 16) xeno.add_filter("empower_rage", 1, list("type" = "outline", "color" = color, "size" = 3)) - addtimer(CALLBACK(src, PROC_REF(remove_superbuff), xeno, behavior), 1.5 SECONDS) + addtimer(CALLBACK(src, PROC_REF(remove_superbuff), xeno), 1.5 SECONDS) -/datum/action/xeno_action/onclick/empower/proc/remove_superbuff(mob/living/carbon/xenomorph/xeno, datum/behavior_delegate/ravager_base/behavior) - behavior.empower_targets = 0 +/datum/action/xeno_action/onclick/empower/proc/remove_superbuff(mob/living/carbon/xenomorph/xeno) + empower_targets = 0 + REMOVE_TRAIT(xeno, TRAIT_ABILITY_EMPOWER, TRAIT_SOURCE_ABILITY("empower")) xeno.visible_message(SPAN_DANGER("[xeno]'s glow slowly dims."), SPAN_XENOHIGHDANGER("Our glow fades away, the power leaving our form!")) xeno.remove_filter("empower_rage") /datum/action/xeno_action/onclick/empower/proc/get_initial_shield() var/mob/living/carbon/xenomorph/xeno = owner - if(!activated_once) + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_PRE_EMPOWER)) return xeno.add_xeno_shield(initial_activation_shield, XENO_SHIELD_SOURCE_RAVAGER) xeno.overlay_shields() /datum/action/xeno_action/onclick/empower/proc/timeout() - if(!activated_once) + var/mob/living/carbon/xenomorph/xeno = owner + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_PRE_EMPOWER)) return - var/mob/living/carbon/xenomorph/xeno = owner actual_empower(xeno) -/datum/action/xeno_action/onclick/empower/action_cooldown_check() - if (cooldown_timer_id == TIMER_ID_NULL) - return TRUE - else if (activated_once) - return TRUE - else - return FALSE - // Supplemental behavior for our charge /datum/action/xeno_action/activable/pounce/charge/additional_effects(mob/living/living) - var/mob/living/carbon/human/human = living var/mob/living/carbon/xenomorph/xeno = owner - var/datum/behavior_delegate/ravager_base/behavior = xeno.behavior_delegate - if(behavior.empower_targets < behavior.super_empower_threshold) + + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_EMPOWER)) return - behavior.mid_charge = TRUE + + ADD_TRAIT(xeno, TRAIT_ABILITY_POUNCE_CHARGE, TRAIT_SOURCE_ABILITY("pounce_charge")) xeno.visible_message(SPAN_XENODANGER("[xeno] uses its shield to bash [human] as it charges at them!"), SPAN_XENODANGER("We use our shield to bash [human] as we charge at them!")) - human.apply_effect(behavior.knockdown_amount, WEAKEN) + human.apply_effect(knockdown_amount, WEAKEN) human.attack_alien(xeno, rand(xeno.melee_damage_lower, xeno.melee_damage_upper), unblockable=TRUE) - behavior.mid_charge = FALSE + REMOVE_TRAIT(xeno, TRAIT_ABILITY_POUNCE_CHARGE, TRAIT_SOURCE_ABILITY("pounce_charge")) var/facing = get_dir(xeno, human) - xeno.throw_carbon(human, facing, behavior.fling_distance, SPEED_VERY_FAST, shake_camera = FALSE, immobilize = TRUE) + xeno.throw_carbon(human, facing, fling_distance, SPEED_VERY_FAST, shake_camera = FALSE, immobilize = TRUE) /datum/action/xeno_action/activable/scissor_cut/use_ability(atom/target_atom) - var/mob/living/carbon/xenomorph/ravager_user = owner - - if (!action_cooldown_check()) - return - - if (!ravager_user.check_state()) - return + var/mob/living/carbon/xenomorph/xeno = owner - // Determine whether or not we should daze here - var/should_sslow = FALSE - var/datum/behavior_delegate/ravager_base/ravager_delegate = ravager_user.behavior_delegate - if(ravager_delegate.empower_targets >= ravager_delegate.super_empower_threshold) - should_sslow = TRUE + XENO_ACTION_CHECK(xeno) // Get line of turfs var/list/turf/target_turfs = list() - var/facing = Get_Compass_Dir(ravager_user, target_atom) - var/turf/turf = ravager_user.loc - var/turf/temp = ravager_user.loc + var/facing = Get_Compass_Dir(xeno, target_atom) + var/turf/turf = xeno.loc + var/turf/temp = xeno.loc var/list/telegraph_atom_list = list() - for (var/step in 0 to 3) + for(var/step in 0 to 3) temp = get_step(turf, facing) if(facing in GLOB.diagonals) // check if it goes through corners var/reverse_face = GLOB.reverse_dir[facing] @@ -319,31 +308,31 @@ telegraph_atom_list += new /obj/effect/xenomorph/xeno_telegraph/red(turf, 0.25 SECONDS) // Extract our 'optimal' turf, if it exists - if (length(target_turfs) >= 2) - ravager_user.animation_attack_on(target_turfs[length(target_turfs)], 15) + if(length(target_turfs) >= 2) + xeno.animation_attack_on(target_turfs[length(target_turfs)], 15) // Hmm today I will kill a marine while looking away from them - ravager_user.face_atom(target_atom) - ravager_user.emote("roar") - ravager_user.visible_message(SPAN_XENODANGER("[ravager_user] sweeps its claws through the area in front of it!"), SPAN_XENODANGER("We sweep our claws through the area in front of us!")) + xeno.face_atom(target_atom) + xeno.emote("roar") + xeno.visible_message(SPAN_XENODANGER("[xeno] sweeps its claws through the area in front of it!"), SPAN_XENODANGER("We sweep our claws through the area in front of us!")) // Loop through our turfs, finding any humans there and dealing damage to them - for (var/turf/target_turf in target_turfs) - for (var/mob/living/carbon/carbon_target in target_turf) - if (carbon_target.stat == DEAD) + for(var/turf/target_turf in target_turfs) + for(var/mob/living/carbon/carbon_target in target_turf) + if(carbon_target.stat == DEAD) continue - if (HAS_TRAIT(carbon_target, TRAIT_NESTED)) + if(HAS_TRAIT(carbon_target, TRAIT_NESTED)) continue - if(ravager_user.can_not_harm(carbon_target)) + if(xeno.can_not_harm(carbon_target)) continue - ravager_user.flick_attack_overlay(carbon_target, "slash") + xeno.flick_attack_overlay(carbon_target, "slash") carbon_target.apply_armoured_damage(damage, ARMOR_MELEE, BRUTE) playsound(get_turf(carbon_target), "alien_claw_flesh", 30, TRUE) - if(should_sslow) - new /datum/effects/xeno_slow/superslow(carbon_target, ravager_user, ttl = superslow_duration) + if(HAS_TRAIT(xeno, TRAIT_ABILITY_EMPOWER)) + new /datum/effects/xeno_slow/superslow(carbon_target, xeno, ttl = superslow_duration) apply_cooldown() return ..() diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm index 2a0e3db43890b..1beadcbdedf76 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm @@ -110,6 +110,11 @@ if(hide) hide.post_attack() +/datum/action/xeno_action/activable/pounce/runner/start_airbone() + var/mob/living/carbon/xenomorph/xeno = owner + + ADD_TRAIT(xeno, TRAIT_ABILITY_POUNCE, TRAIT_SOURCE_ABILITY("pounce")) + /datum/action/xeno_action/activable/runner_skillshot/use_ability(atom/affected_atom) var/mob/living/carbon/xenomorph/xeno = owner if(!istype(xeno)) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm b/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm index 40613db49e62e..cae028674021d 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm @@ -77,37 +77,32 @@ var/increment_amount = 10 /datum/behavior_delegate/sentinel_base/melee_attack_modify_damage(original_damage, mob/living/carbon/carbon_target) - if (!buffed_slashes) + if(!next_slash_buffed) return original_damage - if (!isxeno_human(carbon_target)) + if(!isxeno_human(carbon_target)) return original_damage if(skillcheck(carbon_target, SKILL_ENDURANCE, SKILL_ENDURANCE_MAX )) carbon_target.visible_message(SPAN_DANGER("[carbon_target] withstands the neurotoxin!")) return original_damage //endurance 5 makes you immune to weak neurotoxin if(ishuman(carbon_target)) - var/mob/living/carbon/human/human = carbon_target - if(human.chem_effect_flags & CHEM_EFFECT_RESIST_NEURO || human.species.flags & NO_NEURO) - human.visible_message(SPAN_DANGER("[human] shrugs off the neurotoxin!")) - return original_damage //species like zombies or synths are immune to neurotoxin - if (buffed_slashes) - to_chat(bound_xeno, SPAN_XENOHIGHDANGER("Our slash applied a large amount of neurotoxin!")) - to_chat(carbon_target, SPAN_XENOHIGHDANGER("You feel your muscles, as [bound_xeno] slashes you with its neurotoxin coated claws!")) - var/datum/effects/sentinel_neuro_stacks/sns = null - for (var/datum/effects/sentinel_neuro_stacks/sentinel_neuro_stacks in human.effects_list) - sns = sentinel_neuro_stacks - break - - if (sns == null) - sns = new /datum/effects/sentinel_neuro_stacks(human) - sns.increment_stack_count(increment_amount) - - buffed_slashes -- - if(!buffed_slashes) + var/mob/living/carbon/human/target_human = carbon_target + if(target_human.chem_effect_flags & CHEM_EFFECT_RESIST_NEURO || target_human.species.flags & NO_NEURO) + target_human.visible_message(SPAN_DANGER("[target_human] shrugs off the neurotoxin!")) + next_slash_buffed = FALSE + return //species like zombies or synths are immune to neurotoxin + if(next_slash_buffed) + to_chat(bound_xeno, SPAN_XENOHIGHDANGER("We add neurotoxin into our attack, [carbon_target] is about to fall over paralyzed!")) + to_chat(carbon_target, SPAN_XENOHIGHDANGER("You feel like you're about to fall over, as [bound_xeno] slashes you with its neurotoxin coated claws!")) + carbon_target.sway_jitter(times = 3, steps = floor(NEURO_TOUCH_DELAY/3)) + carbon_target.apply_effect(4, DAZE) + addtimer(CALLBACK(src, PROC_REF(paralyzing_slash), carbon_target), NEURO_TOUCH_DELAY) + next_slash_buffed = FALSE + if(!next_slash_buffed) var/datum/action/xeno_action/onclick/paralyzing_slash/ability = get_action(bound_xeno, /datum/action/xeno_action/onclick/paralyzing_slash) - if (ability && istype(ability)) - ability.button.icon_state = "template_xeno" + if(ability && istype(ability)) + ability.button.icon_state = "template" return original_damage /datum/behavior_delegate/sentinel_base/override_intent(mob/living/carbon/target_carbon) @@ -119,89 +114,84 @@ if(buffed_slashes) return INTENT_HARM +/datum/behavior_delegate/sentinel_base/proc/paralyzing_slash(mob/living/carbon/human/human_target) + human_target.KnockDown(2) + human_target.Stun(2) + to_chat(human_target, SPAN_XENOHIGHDANGER("You fall over, paralyzed by the toxin!")) -/datum/action/xeno_action/activable/slowing_spit/use_ability(atom/target) - var/mob/living/carbon/xenomorph/slowspit_user = owner - if(!slowspit_user.check_state()) - return + +/datum/action/xeno_action/activable/slowing_spit/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner if(!action_cooldown_check()) to_chat(src, SPAN_WARNING("We must wait for our spit glands to refill.")) return - var/turf/current_turf = get_turf(slowspit_user) + var/turf/current_turf = get_turf(xeno) if(!current_turf) return - if (!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) - slowspit_user.visible_message(SPAN_XENOWARNING("[slowspit_user] spits at [target]!"), - SPAN_XENOWARNING("You spit at [target]!") ) + xeno.visible_message(SPAN_XENOWARNING("[xeno] spits at [target_atom]!"), + SPAN_XENOWARNING("You spit at [target_atom]!") ) var/sound_to_play = pick(1, 2) == 1 ? 'sound/voice/alien_spitacid.ogg' : 'sound/voice/alien_spitacid2.ogg' - playsound(slowspit_user.loc, sound_to_play, 25, 1) + playsound(xeno.loc, sound_to_play, 25, 1) - slowspit_user.ammo = GLOB.ammo_list[/datum/ammo/xeno/toxin] - var/obj/projectile/projectile = new /obj/projectile(current_turf, create_cause_data(initial(slowspit_user.caste_type), slowspit_user)) - projectile.generate_bullet(slowspit_user.ammo) - projectile.permutated += slowspit_user - projectile.def_zone = slowspit_user.get_limbzone_target() - projectile.fire_at(target, slowspit_user, slowspit_user, slowspit_user.ammo.max_range, slowspit_user.ammo.shell_speed) + xeno.ammo = GLOB.ammo_list[/datum/ammo/xeno/toxin] + var/obj/projectile/projectile = new /obj/projectile(current_turf, create_cause_data(initial(xeno.caste_type), xeno)) + projectile.generate_bullet(xeno.ammo) + projectile.permutated += xeno + projectile.def_zone = xeno.get_limbzone_target() + projectile.fire_at(target_atom, xeno, xeno, xeno.ammo.max_range, xeno.ammo.shell_speed) apply_cooldown() return ..() -/datum/action/xeno_action/activable/scattered_spit/use_ability(atom/target) - var/mob/living/carbon/xenomorph/scatterspit_user = owner - if(!scatterspit_user.check_state()) - return +/datum/action/xeno_action/activable/scattered_spit/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner if(!action_cooldown_check()) to_chat(src, SPAN_WARNING("We must wait for your spit glands to refill.")) return - var/turf/current_turf = get_turf(scatterspit_user) + var/turf/current_turf = get_turf(xeno) if(!current_turf) return - if (!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) - scatterspit_user.visible_message(SPAN_XENOWARNING("[scatterspit_user] spits at [target]!"), - SPAN_XENOWARNING("You spit at [target]!") ) + xeno.visible_message(SPAN_XENOWARNING("[xeno] spits at [target_atom]!"), + SPAN_XENOWARNING("You spit at [target_atom]!") ) var/sound_to_play = pick(1, 2) == 1 ? 'sound/voice/alien_spitacid.ogg' : 'sound/voice/alien_spitacid2.ogg' - playsound(scatterspit_user.loc, sound_to_play, 25, 1) + playsound(xeno.loc, sound_to_play, 25, 1) - scatterspit_user.ammo = GLOB.ammo_list[/datum/ammo/xeno/toxin/shotgun] - var/obj/projectile/projectile = new /obj/projectile(current_turf, create_cause_data(initial(scatterspit_user.caste_type), scatterspit_user)) - projectile.generate_bullet(scatterspit_user.ammo) - projectile.permutated += scatterspit_user - projectile.def_zone = scatterspit_user.get_limbzone_target() - projectile.fire_at(target, scatterspit_user, scatterspit_user, scatterspit_user.ammo.max_range, scatterspit_user.ammo.shell_speed) + xeno.ammo = GLOB.ammo_list[/datum/ammo/xeno/toxin/shotgun] + var/obj/projectile/projectile = new /obj/projectile(current_turf, create_cause_data(initial(xeno.caste_type), xeno)) + projectile.generate_bullet(xeno.ammo) + projectile.permutated += xeno + projectile.def_zone = xeno.get_limbzone_target() + projectile.fire_at(target_atom, xeno, xeno, xeno.ammo.max_range, xeno.ammo.shell_speed) apply_cooldown() return ..() -/datum/action/xeno_action/onclick/paralyzing_slash/use_ability(atom/target) - var/mob/living/carbon/xenomorph/paraslash_user = owner - - if (!istype(paraslash_user)) - return +/datum/action/xeno_action/onclick/paralyzing_slash/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner - 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/sentinel_base/behavior = paraslash_user.behavior_delegate - if (istype(behavior)) - behavior.buffed_slashes = behavior.max_buffed_slashes + var/datum/behavior_delegate/sentinel_base/behavior = xeno.behavior_delegate + if(istype(behavior)) + behavior.next_slash_buffed = TRUE - to_chat(paraslash_user, SPAN_XENOHIGHDANGER("Our next three slashes will apply neurotoxin!")) + to_chat(xeno, SPAN_XENOHIGHDANGER("Our next slash will apply neurotoxin!")) button.icon_state = "template_active" addtimer(CALLBACK(src, PROC_REF(unbuff_slash)), buff_duration) @@ -210,17 +200,17 @@ return ..() /datum/action/xeno_action/onclick/paralyzing_slash/proc/unbuff_slash() - var/mob/living/carbon/xenomorph/unbuffslash_user = owner - if (!istype(unbuffslash_user)) + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(xeno)) return - var/datum/behavior_delegate/sentinel_base/behavior = unbuffslash_user.behavior_delegate - if (istype(behavior)) + var/datum/behavior_delegate/sentinel_base/behavior = xeno.behavior_delegate + if(istype(behavior)) // In case slash has already landed - if (!behavior.buffed_slashes) + if(!behavior.next_slash_buffed) return behavior.buffed_slashes = 0 - to_chat(unbuffslash_user, SPAN_XENODANGER("We have waited too long, our slash will no longer apply neurotoxin!")) + to_chat(xeno, SPAN_XENODANGER("We have waited too long, our slash will no longer apply neurotoxin!")) button.icon_state = "template_xeno" /datum/action/xeno_action/activable/draining_bite/use_ability(atom/target) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm b/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm index 4fe0425c410f0..21373622e1e70 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/Warrior.dm b/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm index ec3729688f6f6..c8107481cf44c 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm @@ -78,7 +78,6 @@ var/lifesteal_lock_duration = 20 // This will remove the glow effect on warrior after 2 seconds var/color = "#6c6f24" var/emote_cooldown = 0 - var/lunging = FALSE // whether or not the warrior is currently lunging (holding) a target /mob/living/carbon/xenomorph/warrior/handle_special_state() return HAS_TRAIT(src, TRAIT_ABILITY_ENCLOSED_PLATES) @@ -87,20 +86,19 @@ if(HAS_TRAIT(src, TRAIT_ABILITY_ENCLOSED_PLATES)) return "Warrior_plates_[severity]" -/mob/living/carbon/xenomorph/warrior/throw_item(atom/target) +/mob/living/carbon/xenomorph/warrior/throw_item(atom/target_atom) toggle_throw_mode(THROW_MODE_OFF) /mob/living/carbon/xenomorph/warrior/stop_pulling() var/datum/behavior_delegate/warrior_base/warrior_delegate = behavior_delegate - if(isliving(pulling) && istype(warrior_delegate) && warrior_delegate.lunging) - warrior_delegate.lunging = FALSE // To avoid extreme cases of stopping a lunge then quickly pulling and stopping to pull someone else + if(isliving(pulling) && istype(warrior_delegate) && HAS_TRAIT(src, TRAIT_ABILITY_LUNGE)) + REMOVE_TRAIT(src, TRAIT_ABILITY_LUNGE, TRAIT_SOURCE_ABILITY("lunge")) var/mob/living/lunged = pulling lunged.set_effect(0, STUN) lunged.set_effect(0, WEAKEN) return ..() /mob/living/carbon/xenomorph/warrior/start_pulling(atom/movable/movable_atom, lunge) - var/datum/behavior_delegate/warrior_base/warrior_delegate = behavior_delegate if(!check_state()) return FALSE @@ -117,8 +115,8 @@ if(.) //successful pull if(isxeno(living_mob)) - var/mob/living/carbon/xenomorph/xeno = living_mob - if(xeno.tier >= 2) // Tier 2 castes or higher immune to warrior grab stuns + var/mob/living/carbon/xenomorph/target_xeno = living_mob + if(target_xeno.tier >= 2) // Tier 2 castes or higher immune to warrior grab stuns return if(should_neckgrab && living_mob.mob_size < MOB_SIZE_BIG) @@ -130,12 +128,11 @@ return // Grab was broken, probably as Stun side effect (eg. target getting knocked away from a manned M56D) visible_message(SPAN_XENOWARNING("[src] grabs [living_mob] by the throat!"), SPAN_XENOWARNING("We grab [living_mob] by the throat!")) - warrior_delegate.lunging = TRUE + ADD_TRAIT(src, TRAIT_ABILITY_LUNGE, TRAIT_SOURCE_ABILITY("lunge")) addtimer(CALLBACK(src, PROC_REF(stop_lunging)), get_xeno_stun_duration(living_mob, 2) SECONDS + 1 SECONDS) /mob/living/carbon/xenomorph/warrior/proc/stop_lunging(world_time) - var/datum/behavior_delegate/warrior_base/warrior_delegate = behavior_delegate - warrior_delegate.lunging = FALSE + REMOVE_TRAIT(src, TRAIT_ABILITY_LUNGE, TRAIT_SOURCE_ABILITY("lunge")) /mob/living/carbon/xenomorph/warrior/hitby(atom/movable/movable_atom) if(ishuman(movable_atom)) @@ -143,7 +140,7 @@ ..() -/datum/behavior_delegate/warrior_base/melee_attack_additional_effects_target(mob/living/carbon/carbon) +/datum/behavior_delegate/warrior_base/melee_attack_additional_effects_target(mob/living/carbon/target_carbon) ..() if(SEND_SIGNAL(bound_xeno, COMSIG_XENO_PRE_HEAL) & COMPONENT_CANCEL_XENO_HEAL) @@ -152,14 +149,14 @@ var/final_lifesteal = lifesteal_percent var/list/mobs_in_range = oviewers(lifesteal_range, bound_xeno) - for(var/mob/mob as anything in mobs_in_range) + for(var/mob/target_mob as anything in mobs_in_range) if(final_lifesteal >= max_lifesteal) break - if(mob.stat == DEAD || HAS_TRAIT(mob, TRAIT_NESTED)) + if(target_mob.stat == DEAD || HAS_TRAIT(target_mob, TRAIT_NESTED)) continue - if(bound_xeno.can_not_harm(mob)) + if(bound_xeno.can_not_harm(target_mob)) continue final_lifesteal++ @@ -182,8 +179,7 @@ if(!isxeno_human(target_carbon)) return - - if(lunging && target_carbon) + if(HAS_TRAIT(bound_xeno, TRAIT_ABILITY_LUNGE) && target_carbon) return INTENT_HARM @@ -192,101 +188,92 @@ /datum/action/xeno_action/activable/lunge/use_ability(atom/affected_atom) - var/mob/living/carbon/xenomorph/lunge_user = owner + var/mob/living/carbon/xenomorph/xeno = owner if(!action_cooldown_check()) - if(twitch_message_cooldown < world.time ) - lunge_user.visible_message(SPAN_XENOWARNING("[lunge_user]'s claws twitch."), SPAN_XENOWARNING("Our claws twitch as we try to lunge but lack the strength. Wait a moment to try again.")) + if(twitch_message_cooldown < world.time) + xeno.visible_message(SPAN_XENOWARNING("[xeno]'s claws twitch."), SPAN_XENOWARNING("Our claws twitch as we try to lunge but lack the strength. Wait a moment to try again.")) twitch_message_cooldown = world.time + 5 SECONDS return //this gives a little feedback on why your lunge didn't hit other than the lunge button going grey. Plus, it might spook marines that almost got lunged if they know why the message appeared, and extra spookiness is always good. if(!affected_atom) return - if(!isturf(lunge_user.loc)) - to_chat(lunge_user, SPAN_XENOWARNING("We can't lunge from here!")) - return - - if(!lunge_user.check_state()) + if(!isturf(xeno.loc)) + to_chat(xeno, SPAN_XENOWARNING("We can't lunge from here!")) return - if(lunge_user.can_not_harm(affected_atom) || !ismob(affected_atom)) + if(xeno.can_not_harm(affected_atom) || !ismob(affected_atom)) apply_cooldown_override(click_miss_cooldown) return - var/mob/living/carbon/carbon = affected_atom - if(carbon.stat == DEAD) + var/mob/living/carbon/target_carbon = affected_atom + if(target_carbon.stat == DEAD) return - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) apply_cooldown() ..() - lunge_user.visible_message(SPAN_XENOWARNING("[lunge_user] lunges towards [carbon]!"), SPAN_XENOWARNING("We lunge at [carbon]!")) + xeno.visible_message(SPAN_XENOWARNING("[xeno] lunges towards [target_carbon]!"), SPAN_XENOWARNING("We lunge at [target_carbon]!")) - lunge_user.throw_atom(get_step_towards(affected_atom, lunge_user), grab_range, SPEED_FAST, lunge_user, tracking=TRUE) + xeno.throw_atom(get_step_towards(affected_atom, xeno), grab_range, SPEED_FAST, xeno, tracking=TRUE) - if(lunge_user.Adjacent(carbon)) - lunge_user.start_pulling(carbon,1) - if(ishuman(carbon)) - INVOKE_ASYNC(carbon, TYPE_PROC_REF(/mob, emote), "scream") + if(xeno.Adjacent(target_carbon)) + xeno.start_pulling(target_carbon,1) + if(ishuman(target_carbon)) + INVOKE_ASYNC(target_carbon, TYPE_PROC_REF(/mob, emote), "scream") else - lunge_user.visible_message(SPAN_XENOWARNING("[lunge_user]'s claws twitch."), SPAN_XENOWARNING("Our claws twitch as we lunge but are unable to grab onto our target. Wait a moment to try again.")) + xeno.visible_message(SPAN_XENOWARNING("[xeno]'s claws twitch."), SPAN_XENOWARNING("Our claws twitch as we lunge but are unable to grab onto our target. Wait a moment to try again.")) return TRUE /datum/action/xeno_action/activable/fling/use_ability(atom/affected_atom) - var/mob/living/carbon/xenomorph/fling_user = owner + var/mob/living/carbon/xenomorph/xeno = owner - if(!action_cooldown_check()) + if(!isxeno_human(affected_atom) || xeno.can_not_harm(affected_atom)) return - if(!isxeno_human(affected_atom) || fling_user.can_not_harm(affected_atom)) - return + XENO_ACTION_CHECK(xeno) - if(!fling_user.check_state()) + if(!xeno.Adjacent(affected_atom)) return - if(!fling_user.Adjacent(affected_atom)) + var/mob/living/carbon/target_carbon = affected_atom + if(target_carbon.stat == DEAD) return - var/mob/living/carbon/carbon = affected_atom - if(carbon.stat == DEAD) + if(HAS_TRAIT(target_carbon, TRAIT_NESTED)) return - if(HAS_TRAIT(carbon, TRAIT_NESTED)) - return + if(target_carbon == xeno.pulling) + xeno.stop_pulling() - if(carbon == fling_user.pulling) - fling_user.stop_pulling() - - if(carbon.mob_size >= MOB_SIZE_BIG) - to_chat(fling_user, SPAN_XENOWARNING("[carbon] is too big for us to fling!")) + if(target_carbon.mob_size >= MOB_SIZE_BIG) + to_chat(xeno, SPAN_XENOWARNING("[target_carbon] is too big for us to fling!")) return - if(!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) - fling_user.visible_message(SPAN_XENOWARNING("[fling_user] effortlessly flings [carbon] to the side!"), SPAN_XENOWARNING("We effortlessly fling [carbon] to the side!")) - playsound(carbon,'sound/weapons/alien_claw_block.ogg', 75, 1) + xeno.visible_message(SPAN_XENOWARNING("[xeno] effortlessly flings [target_carbon] to the side!"), SPAN_XENOWARNING("We effortlessly fling [target_carbon] to the side!")) + playsound(target_carbon,'sound/weapons/alien_claw_block.ogg', 75, 1) if(stun_power) - carbon.Stun(get_xeno_stun_duration(carbon, stun_power)) + target_carbon.Stun(get_xeno_stun_duration(target_carbon, stun_power)) if(weaken_power) - carbon.KnockDown(get_xeno_stun_duration(carbon, weaken_power)) + target_carbon.KnockDown(get_xeno_stun_duration(target_carbon, weaken_power)) if(slowdown) - if(carbon.slowed < slowdown) - carbon.apply_effect(slowdown, SLOW) - carbon.last_damage_data = create_cause_data(initial(fling_user.caste_type), fling_user) + if(target_carbon.slowed < slowdown) + target_carbon.apply_effect(slowdown, SLOW) + target_carbon.last_damage_data = create_cause_data(initial(xeno.caste_type), xeno) - var/facing = get_dir(fling_user, carbon) + var/facing = get_dir(xeno, target_carbon) // Hmm today I will kill a marine while looking away from them - fling_user.face_atom(carbon) - fling_user.animation_attack_on(carbon) - fling_user.flick_attack_overlay(carbon, "disarm") - fling_user.throw_carbon(carbon, facing, fling_distance, SPEED_VERY_FAST, shake_camera = TRUE, immobilize = TRUE) + xeno.face_atom(target_carbon) + xeno.animation_attack_on(target_carbon) + xeno.flick_attack_overlay(target_carbon, "disarm") + xeno.throw_carbon(target_carbon, facing, fling_distance, SPEED_VERY_FAST, shake_camera = TRUE, immobilize = TRUE) apply_cooldown() return ..() @@ -294,73 +281,68 @@ /datum/action/xeno_action/activable/warrior_punch/use_ability(atom/affected_atom) var/mob/living/carbon/xenomorph/punch_user = owner - if(!action_cooldown_check()) - return + XENO_ACTION_CHECK(punch_user) if(!isxeno_human(affected_atom) || punch_user.can_not_harm(affected_atom)) return - if(!punch_user.check_state()) - return - var/distance = get_dist(punch_user, affected_atom) if(distance > 2) return - var/mob/living/carbon/carbon = affected_atom + var/mob/living/carbon/target_carbon = affected_atom - if(!punch_user.Adjacent(carbon)) + if(!punch_user.Adjacent(target_carbon)) return - if(carbon.stat == DEAD) + if(target_carbon.stat == DEAD) return - if(HAS_TRAIT(carbon, TRAIT_NESTED)) + if(HAS_TRAIT(target_carbon, TRAIT_NESTED)) return - var/obj/limb/target_limb = carbon.get_limb(check_zone(punch_user.zone_selected)) + var/obj/limb/target_limb = target_carbon.get_limb(check_zone(punch_user.zone_selected)) - if(ishuman(carbon) && (!target_limb || (target_limb.status & LIMB_DESTROYED))) - target_limb = carbon.get_limb("chest") + 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(punch_user) - carbon.last_damage_data = create_cause_data(initial(punch_user.caste_type), punch_user) + target_carbon.last_damage_data = create_cause_data(initial(punch_user.caste_type), punch_user) - punch_user.visible_message(SPAN_XENOWARNING("[punch_user] hits [carbon] in the [target_limb ? target_limb.display_name : "chest"] with a devastatingly powerful punch!"), - SPAN_XENOWARNING("We hit [carbon] in the [target_limb ? target_limb.display_name : "chest"] with a devastatingly powerful punch!")) + punch_user.visible_message(SPAN_XENOWARNING("[punch_user] 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/sound = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg',) - playsound(carbon, sound, 50, 1) - do_base_warrior_punch(carbon, target_limb) + playsound(target_carbon, sound, 50, 1) + do_base_warrior_punch(target_carbon, target_limb) apply_cooldown() return ..() -/datum/action/xeno_action/activable/warrior_punch/proc/do_base_warrior_punch(mob/living/carbon/carbon, obj/limb/target_limb) - var/mob/living/carbon/xenomorph/warrior = owner +/datum/action/xeno_action/activable/warrior_punch/proc/do_base_warrior_punch(mob/living/carbon/target_carbon, obj/limb/target_limb) + var/mob/living/carbon/xenomorph/punch_user = owner var/damage = rand(base_damage, base_damage + damage_variance) - if(ishuman(carbon)) + if(ishuman(target_carbon)) if((target_limb.status & LIMB_SPLINTED) && !(target_limb.status & LIMB_SPLINTED_INDESTRUCTIBLE)) //If they have it splinted, the splint won't hold. target_limb.status &= ~LIMB_SPLINTED - playsound(get_turf(carbon), 'sound/items/splintbreaks.ogg', 20) - to_chat(carbon, SPAN_DANGER("The splint on your [target_limb.display_name] comes apart!")) - carbon.pain.apply_pain(PAIN_BONE_BREAK_SPLINTED) + playsound(get_turf(target_carbon), 'sound/items/splintbreaks.ogg', 20) + to_chat(target_carbon, SPAN_DANGER("The splint on your [target_limb.display_name] comes apart!")) + target_carbon.pain.apply_pain(PAIN_BONE_BREAK_SPLINTED) - if(ishuman_strict(carbon)) - carbon.apply_effect(3, SLOW) + if(ishuman_strict(target_carbon)) + target_carbon.apply_effect(3, SLOW) - if(isyautja(carbon)) + if(isyautja(target_carbon)) damage = rand(base_punch_damage_pred, base_punch_damage_pred + damage_variance) else if(target_limb.status & (LIMB_ROBOT|LIMB_SYNTHSKIN)) damage = rand(base_punch_damage_synth, base_punch_damage_synth + damage_variance) - carbon.apply_armoured_damage(get_xeno_damage_slash(carbon, damage), ARMOR_MELEE, BRUTE, target_limb ? target_limb.name : "chest") + target_carbon.apply_armoured_damage(get_xeno_damage_slash(target_carbon, damage), ARMOR_MELEE, BRUTE, target_limb ? target_limb.name : "chest") // Hmm today I will kill a marine while looking away from them - warrior.face_atom(carbon) - warrior.animation_attack_on(carbon) - warrior.flick_attack_overlay(carbon, "punch") - shake_camera(carbon, 2, 1) - step_away(carbon, warrior, 2) + punch_user.face_atom(target_carbon) + punch_user.animation_attack_on(target_carbon) + punch_user.flick_attack_overlay(target_carbon, "punch") + shake_camera(target_carbon, 2, 1) + step_away(target_carbon, punch_user, 2) 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 f3bcd560ed8b7..b9a4facaaa362 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 97c25f0430a4f..39ce178ee55b8 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 > 0) severity *= EXPLOSION_PRONE_MULTIPLIER @@ -327,4 +331,8 @@ fire.set_on_fire(src) //Deals an extra proc of fire when you're crossing it. 30 damage per tile crossed, plus 15 per Process(). next_move_slowdown = next_move_slowdown + (SLOWDOWN_AMT_GREENFIRE * resist_modifier) if(resist_modifier > 0) - to_chat(src, SPAN_DANGER("We feel pieces of our exoskeleton fusing with the viscous fluid below and tearing off as we struggle to move through the flames!")) + if(!HAS_TRAIT(src, TRAIT_ABILITY_POUNCE)) + to_chat(src, SPAN_DANGER("We feel pieces of our exoskeleton fusing with the viscous fluid below and tearing off as we struggle to move through the flames!")) + else + if(!prob(75)) + to_chat(src, SPAN_DANGER("We feel searing heat full of chemicals from below us, melting our exoskeleton as we pass above the flames!")) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm index 26d36331587b2..cf4194182e71b 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm @@ -56,31 +56,31 @@ . += "Insight Amount: [trap_ability.empowering_charge_counter]/[trap_ability.empower_charge_max]" /datum/behavior_delegate/boiler_trapper/on_hitby_projectile(ammo) - if (temp_movespeed_usable) + if(temp_movespeed_usable) temp_movespeed_time_used = world.time temp_movespeed_usable = FALSE - if (isxeno(bound_xeno)) + if(isxeno(bound_xeno)) var/mob/living/carbon/xenomorph/xeno = bound_xeno xeno.speed_modifier -= temp_movespeed_amount xeno.recalculate_speed() addtimer(CALLBACK(src, PROC_REF(remove_speed_buff)), temp_movespeed_duration) /datum/behavior_delegate/boiler_trapper/ranged_attack_additional_effects_target(atom/target_atom) - if (!ishuman(target_atom)) + if(!ishuman(target_atom)) return - if (!istype(bound_xeno)) + if(!istype(bound_xeno)) return var/mob/living/carbon/human/target_human = target_atom var/datum/effects/boiler_trap/found = null - for (var/datum/effects/boiler_trap/trap in target_human.effects_list) - if (trap.cause_data?.resolve_mob() == bound_xeno) + for(var/datum/effects/boiler_trap/trap in target_human.effects_list) + if(trap.cause_data?.resolve_mob() == bound_xeno) found = trap break var/datum/action/xeno_action/activable/boiler_trap/trap_ability = get_action(bound_xeno, /datum/action/xeno_action/activable/boiler_trap) - if (found) + if(found) target_human.apply_armoured_damage(bonus_damage_shotgun_trapped, ARMOR_BIO, BURN) trap_ability.empowering_charge_counter = trap_ability.empower_charge_max else @@ -96,15 +96,15 @@ trap_ability.empowering_charge_counter = trap_ability.empower_charge_max /datum/behavior_delegate/boiler_trapper/on_life() - if ((temp_movespeed_time_used + temp_movespeed_cooldown) < world.time) - if (!temp_movespeed_messaged) + if((temp_movespeed_time_used + temp_movespeed_cooldown) < world.time) + if(!temp_movespeed_messaged) to_chat(bound_xeno, SPAN_XENODANGER("You feel your adrenaline glands refill! Your speedboost will activate again.")) temp_movespeed_messaged = TRUE temp_movespeed_usable = TRUE return /datum/behavior_delegate/boiler_trapper/proc/remove_speed_buff() - if (isxeno(bound_xeno)) + if(isxeno(bound_xeno)) var/mob/living/carbon/xenomorph/xeno = bound_xeno xeno.speed_modifier += temp_movespeed_amount xeno.recalculate_speed() @@ -113,21 +113,14 @@ /datum/action/xeno_action/activable/boiler_trap/use_ability(atom/affected_atom) var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) + if(!istype(xeno)) return - if (!action_cooldown_check()) - return - - if (!xeno.check_state()) - return - - if (!can_see(xeno, affected_atom, TRAPPER_VIEWRANGE)) + if(!can_see(xeno, affected_atom, TRAPPER_VIEWRANGE)) to_chat(xeno, SPAN_XENODANGER("We cannot see that location!")) return - if (!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) // 5-long line of turfs orthogonal to the line between us and our target as precisely as we can figure it var/dir_between = Get_Compass_Dir(xeno, affected_atom) @@ -141,16 +134,16 @@ target_turfs += get_step(left_turf, turn(dir_between, -90)) target_turfs += get_step(right_turf, turn(dir_between, 90)) - for (var/turf/turf in target_turfs) - if (!istype(turf) || turf.density) + for(var/turf/turf in target_turfs) + if(!istype(turf) || turf.density) continue var/trap_found = FALSE - for (var/obj/effect/alien/resin/boilertrap/boiler_trap in turf) + for(var/obj/effect/alien/resin/boilertrap/boiler_trap in turf) trap_found = TRUE break - if (trap_found) + if(trap_found) continue var/obj/effect/alien/resin/boilertrap/boiler_trap @@ -176,13 +169,7 @@ /datum/action/xeno_action/activable/acid_mine/use_ability(atom/affected_atom) var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) - return - - if (!xeno.check_state()) - return - - if (!action_cooldown_check()) + if(!istype(xeno)) return if(!affected_atom || affected_atom.layer >= FLY_LAYER || !isturf(xeno.loc)) @@ -192,8 +179,7 @@ to_chat(xeno, SPAN_XENOWARNING("Something is in the way!")) return - if (!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) var/turf/turf = get_turf(affected_atom) var/acid_bolt_message = "a bolt of acid" @@ -203,7 +189,7 @@ xeno.visible_message(SPAN_XENODANGER("[xeno] fires " + acid_bolt_message + " at [affected_atom]!"), SPAN_XENODANGER("We fire " + acid_bolt_message + " at [affected_atom]!")) new /obj/effect/xenomorph/acid_damage_delay/boiler_landmine(turf, damage, delay, empowered, "You are blasted with " + acid_bolt_message + "!", xeno) - for (var/turf/target_turf in orange(1, turf)) + for(var/turf/target_turf in orange(1, turf)) new /obj/effect/xenomorph/acid_damage_delay/boiler_landmine(target_turf, damage, delay, empowered, "You are blasted with a " + acid_bolt_message + "!", xeno) if(empowered) @@ -215,13 +201,12 @@ /datum/action/xeno_action/activable/acid_shotgun/use_ability(atom/affected_atom) var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) + if(!istype(xeno)) return - if (!action_cooldown_check()) - return + XENO_ACTION_CHECK(xeno) - if(!affected_atom || affected_atom.layer >= FLY_LAYER || !isturf(xeno.loc) || !xeno.check_state()) + if(!affected_atom || affected_atom.layer >= FLY_LAYER || !isturf(xeno.loc)) return xeno.visible_message(SPAN_XENOWARNING("[xeno] fires a blast of acid at [affected_atom]!"), SPAN_XENOWARNING("We fire a blast of acid at [affected_atom]!")) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm index 67567161b1da4..b75b9286a62d8 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm @@ -50,7 +50,7 @@ /datum/behavior_delegate/crusher_charger/add_to_xeno() RegisterSignal(bound_xeno, COMSIG_MOB_SET_FACE_DIR, PROC_REF(cancel_dir_lock)) - RegisterSignal(bound_xeno, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE, PROC_REF(apply_directional_armor)) + RegisterSignal(bound_xeno, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE, PROC_REF(apply_directional_projectile_armor)) my_action = get_action(bound_xeno, /datum/action/xeno_action/onclick/charger_charge) if(my_action == null) @@ -63,7 +63,7 @@ SIGNAL_HANDLER return COMPONENT_CANCEL_SET_FACE_DIR -/datum/behavior_delegate/crusher_charger/proc/apply_directional_armor(mob/living/carbon/xenomorph/xeno, list/damagedata) +/datum/behavior_delegate/crusher_charger/proc/apply_directional_projectile_armor(mob/living/carbon/xenomorph/xeno, list/damagedata) SIGNAL_HANDLER var/projectile_direction = damagedata["direction"] if(xeno.dir & REVERSE_DIR(projectile_direction)) @@ -118,6 +118,136 @@ return ..() +/datum/action/xeno_action/onclick/charger_charge/proc/handle_position_change(mob/living/carbon/xenomorph/xeno, body_position) + SIGNAL_HANDLER + if(body_position == LYING_DOWN) + handle_movement(xeno) + +/datum/action/xeno_action/onclick/charger_charge/proc/handle_movement(mob/living/carbon/xenomorph/xeno, atom/oldloc, dir, forced) + SIGNAL_HANDLER + if(xeno.pulling) + if(!momentum) + steps_taken = 0 + return + else + xeno.stop_pulling() + + if(xeno.is_mob_incapacitated()) + if(!momentum) + return + var/distance_to_throw = get_ranged_target_turf(xeno, charge_dir, momentum/2) + INVOKE_ASYNC(xeno, TYPE_PROC_REF(/atom/movable, throw_atom), distance_to_throw, momentum/2, SPEED_FAST, null, TRUE) + stop_momentum() + return + if(!isturf(xeno.loc)) + stop_momentum() + return + // Don't build up charge if you move via getting propelled by something + if(xeno.throwing) + stop_momentum() + return + + var/do_stop_momentum = FALSE + + // Need to be constantly moving in order to maintain charge + if(world.time > last_charge_move + 0.5 SECONDS) + do_stop_momentum = TRUE + if(dir != charge_dir) + charge_dir = dir + do_stop_momentum = TRUE + + if(do_stop_momentum) + stop_momentum() + if(xeno.plasma_stored <= plasma_per_step) + stop_momentum() + return + last_charge_move = world.time + steps_taken++ + if(steps_taken < steps_to_charge) + return + if(momentum < max_momentum) + momentum++ + ADD_TRAIT(xeno, TRAIT_CHARGING, TRAIT_SOURCE_XENO_ACTION_CHARGE) + xeno.update_icons() + if(momentum == max_momentum) + xeno.emote("roar") + //X.use_plasma(plasma_per_step) // take if you are in toggle charge mode + if(momentum > 0) + xeno.use_plasma(plasma_per_step) // take plasma when you have momentum + + noise_timer = noise_timer ? --noise_timer : 3 + if(noise_timer == 3) + playsound(xeno, 'sound/effects/alien_footstep_charge1.ogg', 50) + + for(var/mob/living/carbon/human/Mob in xeno.loc) + if(Mob.body_position == LYING_DOWN && Mob.stat != DEAD) + xeno.visible_message(SPAN_DANGER("[xeno] runs [Mob] over!"), + SPAN_DANGER("We run [Mob] over!") + ) + var/ram_dir = pick(get_perpen_dir(xeno.dir)) + var/dist = 1 + if(momentum == max_momentum) + dist = momentum * 0.25 + step(Mob, ram_dir, dist) + Mob.take_overall_armored_damage(momentum * 6) + INVOKE_ASYNC(Mob, TYPE_PROC_REF(/mob/living/carbon/human, emote),"pain") + shake_camera(Mob, 7,3) + animation_flash_color(Mob) + + xeno.recalculate_speed() + +/datum/action/xeno_action/onclick/charger_charge/proc/handle_dir_change(datum/source, old_dir, new_dir) + SIGNAL_HANDLER + if(new_dir != charge_dir) + charge_dir = new_dir + if(momentum) + stop_momentum() + +/datum/action/xeno_action/onclick/charger_charge/proc/handle_river(datum/source, covered) + SIGNAL_HANDLER + if(!covered) + stop_momentum() + +/datum/action/xeno_action/onclick/charger_charge/proc/update_speed(mob/living/carbon/xenomorph/xeno) + SIGNAL_HANDLER + xeno.speed += momentum * speed_per_momentum + +/datum/action/xeno_action/onclick/charger_charge/proc/stop_momentum(datum/source) + SIGNAL_HANDLER + var/mob/living/carbon/xenomorph/xeno = owner + if(momentum == max_momentum) + xeno.visible_message(SPAN_DANGER("[xeno] skids to a halt!")) + + REMOVE_TRAIT(xeno, TRAIT_CHARGING, TRAIT_SOURCE_XENO_ACTION_CHARGE) + steps_taken = 0 + momentum = 0 + xeno.recalculate_speed() + xeno.update_icons() + +/datum/action/xeno_action/onclick/charger_charge/proc/lose_momentum(amount) + if(amount >= momentum) + stop_momentum() + else + momentum -= amount + var/mob/living/carbon/xenomorph/xeno = owner + xeno.recalculate_speed() + +/datum/action/xeno_action/onclick/charger_charge/proc/handle_collision(mob/living/carbon/xenomorph/xeno, atom/tar) + SIGNAL_HANDLER + if(!momentum) + stop_momentum() + return + + var/result = tar.handle_charge_collision(xeno, src) + switch(result) + if(XENO_CHARGE_TRY_MOVE) + if(step(xeno, charge_dir)) + return COMPONENT_LIVING_COLLIDE_HANDLED + +/datum/action/xeno_action/onclick/charger_charge/proc/start_charging(datum/source) + SIGNAL_HANDLER + steps_taken = steps_to_charge + /datum/action/xeno_action/activable/tumble/use_ability(atom/Target) if(!action_cooldown_check()) 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 50957326b920d..5aa96e538c864 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 @@ -17,12 +17,11 @@ /datum/xeno_strain/steel_crest/apply_strain(mob/living/carbon/xenomorph/defender/defender) defender.damage_modifier -= XENO_DAMAGE_MOD_VERY_SMALL - if(defender.fortify) + if(HAS_TRAIT(defender, TRAIT_ABILITY_FORTIFY)) defender.ability_speed_modifier += 2.5 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) @@ -36,27 +35,36 @@ xeno.ability_speed_modifier -= 3 xeno.damage_modifier += XENO_DAMAGE_MOD_SMALL +/datum/action/xeno_action/activable/fortify/proc/check_directional_projectile_armor(mob/living/carbon/xenomorph/defendy, list/damagedata) + SIGNAL_HANDLER + var/projectile_direction = damagedata["direction"] + // If the defender is facing the projectile. + if(defendy.dir & REVERSE_DIR(projectile_direction)) + damagedata["armor"] += frontal_armor -/datum/action/xeno_action/onclick/soak/use_ability(atom/A) - var/mob/living/carbon/xenomorph/steelcrest = owner +/datum/action/xeno_action/activable/fortify/proc/unconscious_check() + SIGNAL_HANDLER - if (!action_cooldown_check()) + if(QDELETED(owner)) return - if (!steelcrest.check_state()) - return + UnregisterSignal(owner, COMSIG_XENO_ENTER_CRIT) + UnregisterSignal(owner, COMSIG_MOB_DEATH) - if(!check_and_use_plasma_owner()) - return +/datum/action/xeno_action/onclick/soak/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + + 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 +82,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 + new /datum/effects/heal_over_time(xeno, healing_time = 3, heal_amount = 75) // pretty reasonable amount of health recovered over time. // 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/lurker/vampire.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm index 1d5c0931116eb..ad2d8b5e94e69 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm @@ -31,6 +31,13 @@ lurker.recalculate_everything() + +/datum/action/xeno_action/activable/pounce/rush/start_airbone() + var/mob/living/carbon/xenomorph/xeno = owner + + ADD_TRAIT(xeno, TRAIT_ABILITY_POUNCE, TRAIT_SOURCE_ABILITY("pounce")) + + /datum/action/xeno_action/activable/pounce/rush/additional_effects(mob/living/living_target) //pounce effects var/mob/living/carbon/target = living_target var/mob/living/carbon/xenomorph/xeno = owner @@ -47,10 +54,8 @@ if(!istype(xeno)) return - if(!xeno.check_state()) - return - if(!action_cooldown_check()) - return + + XENO_ACTION_CHECK(xeno) xeno.visible_message(SPAN_DANGER("[xeno] drags its claws in a wide area in front of it!"), SPAN_XENOWARNING("We unleash a barrage of slashes!")) @@ -106,23 +111,18 @@ playsound(get_turf(target), 'sound/weapons/alien_claw_flesh4.ogg', 30, TRUE) if(!xeno.on_fire) xeno.flick_heal_overlay(1 SECONDS, "#00B800") - xeno.gain_health(30) + new /datum/effects/heal_over_time(xeno, healing_time = 2, heal_amount = 30) xeno.animation_attack_on(target) xeno.emote("roar") return ..() /datum/action/xeno_action/activable/tail_jab/use_ability(atom/targeted_atom) - var/mob/living/carbon/xenomorph/xeno = owner var/mob/living/carbon/hit_target = targeted_atom var/distance = get_dist(xeno, hit_target) - if(!action_cooldown_check()) - return - - if(!xeno.check_state()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) if(distance > 2) return @@ -220,6 +220,10 @@ if(xeno.can_not_harm(target_carbon)) return + if(target_carbon.stat == DEAD) + to_chat(xeno, SPAN_XENODANGER("They are already dead!")) + return + if(!(HAS_TRAIT(target_carbon, TRAIT_KNOCKEDOUT) || target_carbon.stat == UNCONSCIOUS)) //called knocked out because for some reason .stat seems to have a delay . to_chat(xeno, SPAN_XENOHIGHDANGER("We can only headbite an unconscious, adjacent target!")) return @@ -228,10 +232,7 @@ to_chat(xeno, SPAN_XENOHIGHDANGER("We can only headbite an unconscious, adjacent target!")) return - if(xeno.stat == UNCONSCIOUS) - return - - if(xeno.stat == DEAD) + if(xeno.stat == UNCONSCIOUS || xeno.stat == DEAD) return if(xeno.action_busy) @@ -243,6 +244,8 @@ to_chat(xeno, SPAN_WARNING("We should not harm this host! It has a sister inside.")) return + XENO_ACTION_CHECK(xeno) + xeno.visible_message(SPAN_DANGER("[xeno] grabs [target_carbon]’s head aggressively."), SPAN_XENOWARNING("We grab [target_carbon]’s head aggressively.")) @@ -266,7 +269,7 @@ target_carbon.apply_armoured_damage(60, ARMOR_MELEE, BRUTE, "head", 5) //DIE target_carbon.death(create_cause_data("headbite execution", xeno), FALSE) if(!xeno.on_fire) - xeno.gain_health(150) + new /datum/effects/heal_over_time(xeno, healing_time = 3, heal_amount = 150) xeno.xeno_jitter(1 SECONDS) xeno.flick_heal_overlay(3 SECONDS, "#00B800") xeno.emote("roar") 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 616418396fadc..46e5455ac9c5f 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 d3843ebbef424..08b55a5c902f3 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()) + 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/praetorian/vanguard.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm index a30a02a97c649..93f0b1f5fb918 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm @@ -1,6 +1,6 @@ /datum/xeno_strain/vanguard name = PRAETORIAN_VANGUARD - description = "You forfeit all of your acid-based abilities and some health for some extra speed and a rechargable shield that can block one attack. Use your Pierce from up to three paces away to stab through talls, while stabbing through two or more will completely recharge your shield. Use your charge to plow through enemies and use it again to unleash a powerful AoE slash that reaches up to three paces. You also have a Cleave ability, amplified by your shield, which you can toggle to either immobilize or fling a target away." + description = "You forfeit all of your acid-based abilities and some health for some extra speed and a rechargeable shield that begins rapidly decaying after taking a hit. Use your Pierce from up to three paces away to stab through talls, while stabbing through two or more will completely recharge your shield. Use your charge to plow through enemies and use it again to unleash a powerful AoE slash that reaches up to three paces. You also have a Cleave ability, amplified by your shield, which you can toggle to either immobilize or fling a target away." flavor_description = "Fearless you are born, fearless you serve, fearless you die. This one will become my Vanguard" icon_state_prefix = "Vanguard" @@ -40,7 +40,7 @@ var/last_shield_regen_time = 0 /datum/behavior_delegate/praetorian_vanguard/on_life() - if (last_shield_regen_time <= last_combat_time && last_combat_time + shield_recharge_time <= world.time) + if(last_shield_regen_time <= last_combat_time && last_combat_time + shield_recharge_time <= world.time) regen_shield() @@ -54,46 +54,39 @@ last_combat_time = world.time /datum/behavior_delegate/praetorian_vanguard/proc/regen_shield() - var/mob/living/carbon/xenomorph/praetorian = bound_xeno var/datum/xeno_shield/vanguard/found_shield = null - last_shield_regen_time = world.time - for (var/datum/xeno_shield/vanguard/vanguard_shield in praetorian.xeno_shields) - if (vanguard_shield.shield_source == XENO_SHIELD_SOURCE_VANGUARD_PRAE) + for(var/datum/xeno_shield/vanguard/vanguard_shield in bound_xeno.xeno_shields) + if(vanguard_shield.shield_source == XENO_SHIELD_SOURCE_VANGUARD_PRAE) found_shield = vanguard_shield break + if(bound_xeno.stat == UNCONSCIOUS || (HAS_TRAIT(bound_xeno, TRAIT_INCAPACITATED) && HAS_TRAIT(bound_xeno, TRAIT_FLOORED))) + return + + last_shield_regen_time = world.time + if(found_shield) - praetorian.add_xeno_shield(800, XENO_SHIELD_SOURCE_VANGUARD_PRAE, /datum/xeno_shield/vanguard) + bound_xeno.add_xeno_shield(800, XENO_SHIELD_SOURCE_VANGUARD_PRAE, /datum/xeno_shield/vanguard) else - var/datum/xeno_shield/vanguard/new_shield = praetorian.add_xeno_shield(800, XENO_SHIELD_SOURCE_VANGUARD_PRAE, /datum/xeno_shield/vanguard) - bound_xeno.explosivearmor_modifier += 1.5*XENO_EXPOSIVEARMOR_MOD_VERY_LARGE + var/datum/xeno_shield/vanguard/new_shield = bound_xeno.add_xeno_shield(800, XENO_SHIELD_SOURCE_VANGUARD_PRAE, /datum/xeno_shield/vanguard) + bound_xeno.explosivearmor_modifier += 1.5 * XENO_EXPOSIVEARMOR_MOD_VERY_LARGE bound_xeno.recalculate_armor() - new_shield.explosive_armor_amount = 1.5*XENO_EXPOSIVEARMOR_MOD_VERY_LARGE - to_chat(praetorian, SPAN_XENOHIGHDANGER("We feel our defensive shell regenerate! It will block one hit!")) + new_shield.explosive_armor_amount = 1.5 * XENO_EXPOSIVEARMOR_MOD_VERY_LARGE + to_chat(bound_xeno, SPAN_XENOHIGHDANGER("We feel our defensive shell regenerate! It will block one hit!")) + ADD_TRAIT(bound_xeno, TRAIT_ABILITY_CLEAVE_BUFFED, TRAIT_SOURCE_ABILITY("cleave_buffed")) - var/datum/action/xeno_action/activable/cleave/caction = get_action(bound_xeno, /datum/action/xeno_action/activable/cleave) - if(istype(caction)) - caction.buffed = TRUE /datum/action/xeno_action/activable/pierce/use_ability(atom/targetted_atom) - var/mob/living/carbon/xenomorph/pierce_user = owner + var/mob/living/carbon/xenomorph/xeno = owner var/pierce_sounds = pick('sound/effects/pierce1.ogg', 'sound/effects/pierce2.ogg', 'sound/effects/pierce3.ogg') - if (!action_cooldown_check()) + if(!targetted_atom || targetted_atom.layer >= FLY_LAYER || !isturf(xeno.loc)) return - if (!pierce_user.check_state()) - return - - if(!targetted_atom || targetted_atom.layer >= FLY_LAYER || !isturf(pierce_user.loc)) - return - - if (!check_and_use_plasma_owner()) - return + XENO_ACTION_CHECK_USE_PLASMA(xeno) - //X = xeno user, A = target atom - var/list/turf/target_turfs = get_line(pierce_user, targetted_atom, include_start_atom = FALSE) + var/list/turf/target_turfs = get_line(xeno, targetted_atom, include_start_atom = FALSE) var/length_of_line = LAZYLEN(target_turfs) if(length_of_line > 3) target_turfs = target_turfs.Copy(1, 4) @@ -126,158 +119,190 @@ //Check for mobs and add them to our target list for damage if(iscarbon(path_content)) var/mob/living/carbon/mob_to_act = path_content - if(!isxeno_human(mob_to_act) || pierce_user.can_not_harm(mob_to_act)) + if(!isxeno_human(mob_to_act) || xeno.can_not_harm(mob_to_act)) continue if(!(mob_to_act in target_mobs)) target_mobs += mob_to_act - pierce_user.visible_message(SPAN_XENODANGER("[pierce_user] slashes its claws through the area in front of it!"), SPAN_XENODANGER("We slash our claws through the area in front of us!")) - pierce_user.animation_attack_on(targetted_atom, 15) + xeno.visible_message(SPAN_XENODANGER("[xeno] slashes its claws through the area in front of it!"), SPAN_XENODANGER("We slash our claws through the area in front of us!")) + xeno.animation_attack_on(targetted_atom, 15) - pierce_user.emote("roar") + xeno.emote("roar") // Loop through our mob list, finding any humans there and dealing damage to them - for (var/mob/living/carbon/current_mob in target_mobs) - if (!isxeno_human(current_mob) || pierce_user.can_not_harm(current_mob)) + for(var/mob/living/carbon/current_mob in target_mobs) + if(!isxeno_human(current_mob) || xeno.can_not_harm(current_mob)) continue - if (current_mob.stat == DEAD) + if(current_mob.stat == DEAD) continue - if (HAS_TRAIT(current_mob, TRAIT_NESTED)) + if(HAS_TRAIT(current_mob, TRAIT_NESTED)) continue current_mob.flick_attack_overlay(current_mob, "slash") current_mob.apply_armoured_damage(get_xeno_damage_slash(current_mob, damage), ARMOR_MELEE, BRUTE, null, 20) playsound(current_mob, pierce_sounds, 30, 1) - if (length(target_mobs) >= shield_regen_threshold) - var/datum/behavior_delegate/praetorian_vanguard/behavior = pierce_user.behavior_delegate - if (istype(behavior)) + if(length(target_mobs) >= shield_regen_threshold) + var/datum/behavior_delegate/praetorian_vanguard/behavior = xeno.behavior_delegate + if(istype(behavior)) behavior.regen_shield() apply_cooldown() return ..() -/datum/action/xeno_action/activable/pounce/prae_dash/use_ability(atom/A) - if(!activated_once && !action_cooldown_check() || owner.throwing) + + +/datum/action/xeno_action/activable/pounce/prae_dash/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_PRE_DASH) && !action_cooldown_check() || owner.throwing) return - if(!activated_once) + if(!HAS_TRAIT(xeno, TRAIT_ABILITY_PRE_DASH)) . = ..() if(.) - activated_once = TRUE + ADD_TRAIT(xeno, TRAIT_ABILITY_PRE_DASH, TRAIT_SOURCE_ABILITY("pre_dash")) button.icon_state = "template_active" addtimer(CALLBACK(src, PROC_REF(timeout)), time_until_timeout) else damage_nearby_targets() return TRUE -/datum/action/xeno_action/activable/pounce/prae_dash/proc/timeout() - if (activated_once) - activated_once = FALSE - damage_nearby_targets() - /datum/action/xeno_action/activable/pounce/prae_dash/ability_cooldown_over() update_button_icon() return +/datum/action/xeno_action/activable/pounce/prae_dash/proc/timeout() + var/mob/living/carbon/xenomorph/xeno = owner + if(HAS_TRAIT(xeno, TRAIT_ABILITY_PRE_DASH)) + REMOVE_TRAIT(xeno, TRAIT_ABILITY_PRE_DASH, TRAIT_SOURCE_ABILITY("pre_dash")) + damage_nearby_targets() + /datum/action/xeno_action/activable/pounce/prae_dash/proc/damage_nearby_targets() - var/mob/living/carbon/xenomorph/dash_user = owner + var/mob/living/carbon/xenomorph/xeno = owner - if (QDELETED(dash_user) || !dash_user.check_state()) + if(QDELETED(xeno) || !xeno.check_state()) return - activated_once = FALSE - button.icon_state = dash_user.selected_ability == src ? "template_on" : "template_xeno" + REMOVE_TRAIT(xeno, TRAIT_ABILITY_PRE_DASH, TRAIT_SOURCE_ABILITY("pre_dash")) + button.icon_state = xeno.selected_ability == src ? "template_on" : "template_xeno" var/list/target_mobs = list() - var/list/list_of_targets = orange(1, dash_user) - for (var/mob/living/carbon/targets_in_range in list_of_targets) - if (!isxeno_human(targets_in_range) || dash_user.can_not_harm(targets_in_range)) + var/list/list_of_targets = orange(1, xeno) + for(var/mob/living/carbon/targets_in_range in list_of_targets) + if(!isxeno_human(targets_in_range) || xeno.can_not_harm(targets_in_range)) continue - if (!(targets_in_range in target_mobs)) + if(!(targets_in_range in target_mobs)) target_mobs += targets_in_range - if (targets_in_range.stat) + if(targets_in_range.stat) continue - if (HAS_TRAIT(targets_in_range, TRAIT_NESTED)) + if(HAS_TRAIT(targets_in_range, TRAIT_NESTED)) continue - if (!isxeno_human(targets_in_range) || dash_user.can_not_harm(targets_in_range)) + if(!isxeno_human(targets_in_range) || xeno.can_not_harm(targets_in_range)) continue - dash_user.flick_attack_overlay(targets_in_range, "slash") + xeno.flick_attack_overlay(targets_in_range, "slash") targets_in_range.apply_armoured_damage(get_xeno_damage_slash(targets_in_range, damage), ARMOR_MELEE, BRUTE) playsound(get_turf(targets_in_range), "alien_claw_flesh", 30, 1) - dash_user.visible_message(SPAN_XENODANGER("[dash_user] slashes its claws through the area around it!"), SPAN_XENODANGER("We slash our claws through the area around us!")) - dash_user.spin_circle() + xeno.visible_message(SPAN_XENODANGER("[xeno] slashes its claws through the area around it!"), SPAN_XENODANGER("We slash our claws through the area around us!")) + xeno.spin_circle() - if (length(target_mobs) >= shield_regen_threshold) - var/datum/behavior_delegate/praetorian_vanguard/behavior = dash_user.behavior_delegate - if (istype(behavior)) + if(length(target_mobs) >= shield_regen_threshold) + var/datum/behavior_delegate/praetorian_vanguard/behavior = xeno.behavior_delegate + if(istype(behavior)) behavior.regen_shield() -/datum/action/xeno_action/activable/cleave/use_ability(atom/target_atom) - var/mob/living/carbon/xenomorph/cleave_user = owner - if (!action_cooldown_check()) - return - if (!cleave_user.check_state()) - return - if (!check_and_use_plasma_owner()) - return +/datum/action/xeno_action/activable/cleave/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + + XENO_ACTION_CHECK_USE_PLASMA(xeno) - if (!isxeno_human(target_atom) || cleave_user.can_not_harm(target_atom)) - to_chat(cleave_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 (!cleave_user.Adjacent(target_carbon)) - to_chat(cleave_user, SPAN_XENOWARNING("We must be adjacent to our target!")) + if(!xeno.Adjacent(target_carbon)) + to_chat(xeno, SPAN_XENOWARNING("We must be adjacent to our target!")) return - if (target_carbon.stat == DEAD) - to_chat(cleave_user, SPAN_XENODANGER("[target_carbon] is dead, why would we want to touch it?")) + if(target_carbon.stat == DEAD) + to_chat(xeno, SPAN_XENODANGER("[target_carbon] is dead, why would we want to touch it?")) return // Flick overlay and play sound - cleave_user.face_atom(target_carbon) - cleave_user.animation_attack_on(target_atom, 10) + xeno.face_atom(target_carbon) + xeno.animation_attack_on(target_atom, 10) var/hitsound = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg') playsound(target_carbon, hitsound, 75, 1) - if (root_toggle) + var/buffed = HAS_TRAIT(xeno, TRAIT_ABILITY_CLEAVE_ROOT) + + if(HAS_TRAIT(xeno, TRAIT_ABILITY_CLEAVE_ROOT)) var/root_duration = buffed ? root_duration_buffed : root_duration_unbuffed - cleave_user.visible_message(SPAN_XENODANGER("[cleave_user] slams [target_atom] into the ground!"), SPAN_XENOHIGHDANGER("We slam [target_atom] into the ground!")) + xeno.visible_message(SPAN_XENODANGER("[xeno] slams [target_atom] into the ground!"), SPAN_XENOHIGHDANGER("We slam [target_atom] into the ground!")) ADD_TRAIT(target_carbon, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Cleave")) - if (ishuman(target_carbon)) - var/mob/living/carbon/human/Hu = target_carbon - Hu.update_xeno_hostile_hud() + if(ishuman(target_carbon)) + var/mob/living/carbon/human/target_human = target_carbon + target_human.update_xeno_hostile_hud() addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(unroot_human), target_carbon, TRAIT_SOURCE_ABILITY("Cleave")), get_xeno_stun_duration(target_carbon, root_duration)) - to_chat(target_carbon, SPAN_XENOHIGHDANGER("[cleave_user] has pinned you to the ground! You cannot move!")) - cleave_user.flick_attack_overlay(target_carbon, "punch") + to_chat(target_carbon, SPAN_XENOHIGHDANGER("[xeno] has pinned you to the ground! You cannot move!")) + xeno.flick_attack_overlay(target_carbon, "punch") else var/fling_distance = buffed ? fling_dist_buffed : fling_dist_unbuffed if(target_carbon.mob_size >= MOB_SIZE_BIG) fling_distance *= 0.1 - cleave_user.visible_message(SPAN_XENODANGER("[cleave_user] deals [target_atom] a massive blow, sending them flying!"), SPAN_XENOHIGHDANGER("We deal [target_atom] a massive blow, sending them flying!")) - cleave_user.flick_attack_overlay(target_carbon, "slam") - cleave_user.throw_carbon(target_atom, null, fling_distance) + xeno.visible_message(SPAN_XENODANGER("[xeno] deals [target_atom] a massive blow, sending them flying!"), SPAN_XENOHIGHDANGER("We deal [target_atom] a massive blow, sending them flying!")) + xeno.flick_attack_overlay(target_carbon, "slam") + xeno.throw_carbon(target_atom, null, fling_distance) apply_cooldown() return ..() /datum/action/xeno_action/activable/cleave/proc/remove_buff() - buffed = FALSE + var/mob/living/carbon/xenomorph/xeno = owner + REMOVE_TRAIT(xeno, TRAIT_ABILITY_CLEAVE_BUFFED, TRAIT_SOURCE_ABILITY("cleave_buffed")) + + + +/datum/action/xeno_action/onclick/toggle_cleave/can_use_action() + var/mob/living/carbon/xenomorph/xeno = owner + if(xeno && !xeno.buckled && !xeno.is_mob_incapacitated()) + return TRUE + +/datum/action/xeno_action/onclick/toggle_cleave/use_ability(atom/target_atom) + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(xeno)) + return + + if(!xeno.check_state(TRUE)) + return + + var/action_icon_result + if(HAS_TRAIT(xeno, TRAIT_ABILITY_CLEAVE_ROOT)) + REMOVE_TRAIT(xeno, TRAIT_ABILITY_CLEAVE_ROOT, TRAIT_SOURCE_ABILITY("cleave_root")) + action_icon_result = "prae_cleave_root" + to_chat(xeno, SPAN_WARNING("We will now root marines with our cleave.")) + else + ADD_TRAIT(xeno, TRAIT_ABILITY_CLEAVE_ROOT, TRAIT_SOURCE_ABILITY("cleave_root")) + action_icon_result = "prae_cleave_fling" // TODO: update + to_chat(xeno, SPAN_WARNING("We will now throw marines with our cleave.")) + + button.overlays.Cut() + button.overlays += image('icons/mob/hud/actions_xeno.dmi', button, action_icon_result) + 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 8632830e2172e..bbc653b739b0c 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 448b5f426e2f0..9778691181a9f 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() 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) @@ -276,7 +203,7 @@ 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)) + if(!istype(behavior_delegate)) return if(behavior_delegate.acid_amount < acid_cost) to_chat(xeno, SPAN_XENOHIGHDANGER("Not enough acid stored!")) @@ -288,7 +215,7 @@ return ..() -/datum/action/xeno_action/activable/acider_for_the_hive/use_ability(atom/affected_atom) +/datum/action/xeno_action/activable/acider_for_the_hive/use_ability() var/mob/living/carbon/xenomorph/xeno = owner if(!istype(xeno)) @@ -303,17 +230,13 @@ to_chat(xeno, SPAN_XENOWARNING("We can't activate this here!")) return - if(!xeno.check_state()) - return - - if(!action_cooldown_check()) - return + XENO_ACTION_CHECK(xeno) var/datum/behavior_delegate/runner_acider/behavior_delegate = xeno.behavior_delegate if(!istype(behavior_delegate)) return - if(behavior_delegate.caboom_trigger) + if(caboom_trigger) cancel_ability() return @@ -328,12 +251,12 @@ 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) + caboom_trigger = TRUE + caboom_left = caboom_timer + caboom_last_proc = 0 + xeno.set_effect(caboom_timer*2, SUPERSLOW) - START_PROCESSING(SSfasteffects, src) + start_duration_display(caboom_left_display) xeno.say(";FOR THE HIVE!!!") return ..() @@ -346,35 +269,85 @@ if(!istype(behavior_delegate)) return - behavior_delegate.caboom_trigger = FALSE + 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) + 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.")) - STOP_PROCESSING(SSfasteffects, src) - button.set_maptext() +/datum/action/xeno_action/activable/acider_for_the_hive/proc/do_caboom() + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(xeno)) + return -/datum/action/xeno_action/activable/acider_for_the_hive/process(delta_time) - return update_caboom_maptext() + var/datum/behavior_delegate/runner_acider/behavior_delegate = xeno.behavior_delegate + if(!istype(behavior_delegate)) + return -/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 + 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 - button.set_maptext(SMALL_FONTS_COLOR(7, delegate.caboom_left, "#e69d00"), 19, 2) - return + 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/target_turf, acid_range, xeno, HIDE_INVISIBLE_OBSERVER) + new /obj/effect/particle_effect/smoke/acid_runner_harmless(target_turf) + 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 ..() 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 8b73f42710425..5970fe150d8f5 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(fortify || crest_defense || stealth || HAS_TRAIT(src, TRAIT_ABILITY_ENCLOSED_PLATES) || HAS_TRAIT(src, TRAIT_ABILITY_REFLECTIVE_PLATES)) + if(HAS_TRAIT(src, TRAIT_ABILITY_FORTIFY) || HAS_TRAIT(src, TRAIT_ABILITY_CREST) || 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 take a strain while in this stance.")) return FALSE diff --git a/code/modules/projectiles/guns/flamer/flamer.dm b/code/modules/projectiles/guns/flamer/flamer.dm index bc55c7300c256..708e507a91cb6 100644 --- a/code/modules/projectiles/guns/flamer/flamer.dm +++ b/code/modules/projectiles/guns/flamer/flamer.dm @@ -727,7 +727,7 @@ GLOBAL_LIST_EMPTY(flamer_particles) var/sig_result = SEND_SIGNAL(ignited_morb, COMSIG_LIVING_FLAMER_FLAMED, tied_reagent) - if(!(sig_result & COMPONENT_NO_IGNITE)) + if(!(sig_result & COMPONENT_NO_IGNITE) && !HAS_TRAIT(ignited_morb, TRAIT_ABILITY_POUNCE)) switch(fire_variant) if(FIRE_VARIANT_TYPE_B) //Armor Shredding Greenfire, super easy to pat out. 50 duration -> 10 stacks (1 pat/resist) ignited_morb.TryIgniteMob(floor(tied_reagent.durationfire / 5), tied_reagent) @@ -815,7 +815,7 @@ GLOBAL_LIST_EMPTY(flamer_particles) xeno_target.emote("roar") xeno_target.plasma_stored = xeno_target.plasma_max - if(!(sig_result & COMPONENT_NO_IGNITE) && burn_damage) + if(!(sig_result & COMPONENT_NO_IGNITE) && !HAS_TRAIT(target, TRAIT_ABILITY_POUNCE) && burn_damage) switch(fire_variant) if(FIRE_VARIANT_TYPE_B) //Armor Shredding Greenfire, super easy to pat out. 50 duration -> 10 stacks (1 pat/resist) target.TryIgniteMob(floor(tied_reagent.durationfire / 5), tied_reagent) @@ -841,8 +841,13 @@ GLOBAL_LIST_EMPTY(flamer_particles) if(FIRE_VARIANT_TYPE_B) if(isxeno(target)) var/mob/living/carbon/xenomorph/xeno_target = target - xeno_target.armor_deflection?(variant_burn_msg=" We feel the flames weakening our exoskeleton!"):(variant_burn_msg=" You feel the flaming chemicals eating into your body!") - to_chat(target, SPAN_DANGER("You are burned![variant_burn_msg?"[variant_burn_msg]":""]")) + if(!HAS_TRAIT(target, TRAIT_ABILITY_POUNCE)) + xeno_target.armor_deflection?(variant_burn_msg=" We feel the flames weakening our exoskeleton!"):(variant_burn_msg=" You feel the flaming chemicals eating into your body!") + if(!HAS_TRAIT(target, TRAIT_ABILITY_POUNCE)) + to_chat(target, SPAN_DANGER("You are burned![variant_burn_msg?"[variant_burn_msg]":""]")) + else + if(!prob(75)) // It spam like crazy, it even can lag client. + to_chat(target, SPAN_DANGER("We got burned from flames below!")) target.updatehealth() /obj/flamer_fire/proc/update_flame() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index c7b0c94feba55..4efda2b34057e 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -989,6 +989,8 @@ 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) @@ -1476,3 +1478,4 @@ #undef DEBUG_HIT_CHANCE #undef DEBUG_HUMAN_DEFENSE #undef DEBUG_XENO_DEFENSE + diff --git a/code/modules/vehicles/multitile/multitile_bump.dm b/code/modules/vehicles/multitile/multitile_bump.dm index e81097de0f75e..ae8f21ac23713 100644 --- a/code/modules/vehicles/multitile/multitile_bump.dm +++ b/code/modules/vehicles/multitile/multitile_bump.dm @@ -773,7 +773,7 @@ //DEFENDER /mob/living/carbon/xenomorph/defender/handle_vehicle_bump(obj/vehicle/multitile/V) - if(fortify) + if(HAS_TRAIT(src, TRAIT_ABILITY_FORTIFY)) if(V.vehicle_flags & VEHICLE_CLASS_WEAK) //defenders being able to completely block armored vehicles by crawling into a boulder is ridiculous visible_message(SPAN_DANGER("[src] digs its claws into the ground, anchoring itself in place and halting [V] in its tracks!"), SPAN_DANGER("You dig your claws into the ground, stopping [V] in its tracks!")) diff --git a/sound/effects/pred_force_decloak.ogg b/sound/effects/pred_force_decloak.ogg new file mode 100644 index 0000000000000..672a5314a3b2f Binary files /dev/null and b/sound/effects/pred_force_decloak.ogg differ