From 7cf446400503e91e0684dd6b6d36f2e19edd1ebd Mon Sep 17 00:00:00 2001 From: fira Date: Wed, 13 Dec 2023 09:19:41 +0100 Subject: [PATCH] Xeno Throwing Refactor, prevents canceling mob throws by moving (#5175) # About the pull request This refactors xeno throw procs to be less of a pain to work with, and introduces automatic immobilizing during some xeno throws. They end after the throw using throw callbacks. This is important because if you are not immobilized during the throw, you can just move and step from your current location, canceling it - mostly visible on flings and vanguard cleave Xeno throws that apply a stun would already prevent moving. Because they were only used by Xeno Pounce and Crusher Tumble, i don't know how robust the callbacks are. It's worth Testmerging. # Explain why it's good for the game More reliable throws, throw procs which are easier to work with for new contributors by baking in the immobilization # Testing Photographs and Procedure Done baseline testing with things such as Runner Pounce and Vanguard Cleave. Not all abiltiies are affected because they used different handlers, such as Warrior Fling. # Changelog :cl: fix: Some Xeno throws now immobilize their targets, ensuring they do not walk out of the toss mid-flight. /:cl: --- code/__DEFINES/traits.dm | 2 ++ .../mob/living/carbon/xenomorph/XenoProcs.dm | 29 +++++++++++++++++++ .../abilities/ability_helper_procs.dm | 17 ----------- .../abilities/crusher/crusher_abilities.dm | 2 +- .../abilities/crusher/crusher_powers.dm | 18 ++++-------- .../xenomorph/abilities/general_powers.dm | 13 +-------- .../abilities/praetorian/praetorian_powers.dm | 4 +-- code/modules/movement/launching/launching.dm | 6 +++- 8 files changed, 46 insertions(+), 45 deletions(-) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 8962230946c8..d37c9185fa6d 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -415,6 +415,8 @@ GLOBAL_LIST(trait_name_map) #define TRAIT_SOURCE_XENO_ACTION_CHARGE "t_s_xeno_action_charge" ///Status trait coming from a xeno nest #define XENO_NEST_TRAIT "xeno_nest" +///Status trait from a generic throw by xeno abilities +#define XENO_THROW_TRAIT "xeno_throw_trait" //-- structure traits -- ///Status trait coming from being flipped or unflipped. #define TRAIT_SOURCE_FLIP_TABLE "t_s_flip_table" diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm index b5848786c698..289dd6952cda 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -712,3 +712,32 @@ /mob/living/carbon/xenomorph/lying_angle_on_lying_down(new_lying_angle) return // Do not rotate xenos around on the floor, their sprite is already top-down'ish + +/** + * Helper procedure for throwing other carbon based mobs around + * Pretty much a wrapper to [/atom/movable/proc/throw_atom] with extra handling + * + * * target - the target carbon mob that will be thrown + * * direction - the direction the target will be thrown toward, or if null, infered from relative position with target + * * distance - the total distance the throw will be made for + * * speed - throw_atom relative speed of the throw, check [SPEED_AVERAGE] for details + * * shake_camera - whether to shake the thrown mob camera on throw + * * immobilize - if TRUE the mob will be immobilized during the throw, ensuring it doesn't move and break it + */ +/mob/living/carbon/xenomorph/proc/throw_carbon(mob/living/carbon/target, direction, distance, speed = SPEED_VERY_FAST, shake_camera = TRUE, immobilize = TRUE) + if(!direction) + direction = get_dir(src, target) + var/turf/target_destination = get_ranged_target_turf(target, direction, distance) + + var/list/end_throw_callbacks + if(immobilize) + end_throw_callbacks = list(CALLBACK(src, PROC_REF(throw_carbon_end), target)) + ADD_TRAIT(target, TRAIT_IMMOBILIZED, XENO_THROW_TRAIT) + + target.throw_atom(target_destination, distance, speed, src, spin = TRUE, end_throw_callbacks = end_throw_callbacks) + if(shake_camera) + shake_camera(target, 10, 1) + +/// Handler callback to reset immobilization status after a successful [/mob/living/carbon/xenomorph/proc/throw_carbon] +/mob/living/carbon/xenomorph/proc/throw_carbon_end(mob/living/carbon/target) + REMOVE_TRAIT(target, TRAIT_IMMOBILIZED, XENO_THROW_TRAIT) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/ability_helper_procs.dm b/code/modules/mob/living/carbon/xenomorph/abilities/ability_helper_procs.dm index 35024d7304af..b05000cc4588 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/ability_helper_procs.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/ability_helper_procs.dm @@ -171,23 +171,6 @@ T.update_xeno_hostile_hud() to_chat(H, SPAN_XENOHIGHDANGER("You can move again!")) -/proc/xeno_throw_human(mob/living/carbon/H, mob/living/carbon/xenomorph/X, direction, distance, shake_camera = TRUE) - if (!istype(H) || !istype(X) || !direction || !distance) - return - - var/turf/T = get_turf(H) - var/turf/temp = get_turf(H) - for (var/x in 0 to distance) - temp = get_step(T, direction) - if (!temp) - break - T = temp - - H.throw_atom(T, distance, SPEED_VERY_FAST, X, TRUE) - if(!shake_camera) - return - shake_camera(H, 10, 1) - /mob/living/carbon/xenomorph/proc/zoom_in() if(stat || resting) if(is_zoomed) 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 63051a94efa9..73ce0fc41b63 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 @@ -277,7 +277,7 @@ Mob.apply_damage(15,BRUTE) if(ishuman(Mob)) var/mob/living/carbon/human/Human = Mob - xeno_throw_human(Human, Xeno, get_dir(Xeno, Human), 1) + Xeno.throw_carbon(Human, distance = 1) Human.apply_effect(1, WEAKEN) else Mob.apply_effect(1, WEAKEN) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm index 34a9a4833fec..67c92a0efda7 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm @@ -28,7 +28,7 @@ X.visible_message(SPAN_XENODANGER("[X] overruns [H], brutally trampling them underfoot!"), SPAN_XENODANGER("You brutalize [H] as you crush them underfoot!")) H.apply_armoured_damage(get_xeno_damage_slash(H, direct_hit_damage), ARMOR_MELEE, BRUTE) - xeno_throw_human(H, X, X.dir, 3) + X.throw_carbon(H, X.dir, 3) H.last_damage_data = create_cause_data(X.caste_type, X) return @@ -302,17 +302,11 @@ playsound(Xeno,"alien_tail_swipe", 50, 1) Xeno.use_plasma(plasma_cost) - var/datum/launch_metadata/LM = new() - LM.target = get_step(get_step(Xeno, target_dir), target_dir) - LM.range = target_dist - LM.speed = SPEED_FAST - LM.thrower = Xeno - LM.spin = FALSE - LM.pass_flags = PASS_CRUSHER_CHARGE - LM.collision_callbacks = list(/mob/living/carbon/human = CALLBACK(src, PROC_REF(handle_mob_collision))) - LM.end_throw_callbacks = list(CALLBACK(src, PROC_REF(on_end_throw), start_charging)) - - Xeno.launch_towards(LM) + + var/target = get_step(get_step(Xeno, target_dir), target_dir) + var/list/collision_callbacks = list(/mob/living/carbon/human = CALLBACK(src, PROC_REF(handle_mob_collision))) + var/list/end_throw_callbacks = list(CALLBACK(src, PROC_REF(on_end_throw), start_charging)) + Xeno.throw_atom(target, target_dist, SPEED_FAST, pass_flags = PASS_CRUSHER_CHARGE, end_throw_callbacks = end_throw_callbacks, collision_callbacks = collision_callbacks) apply_cooldown() return ..() 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 74a46a30e9ba..fa60187b6fab 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm @@ -433,18 +433,7 @@ pre_pounce_effects() X.pounce_distance = get_dist(X, A) - - var/datum/launch_metadata/LM = new() - LM.target = A - LM.range = distance - LM.speed = throw_speed - LM.thrower = X - LM.spin = FALSE - LM.pass_flags = pounce_pass_flags - LM.collision_callbacks = pounce_callbacks - - X.launch_towards(LM) - + X.throw_atom(A, distance, throw_speed, X, pass_flags = pounce_pass_flags, collision_callbacks = pounce_callbacks) X.update_icons() additional_effects_always() diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm index e7aa02bef824..9a6a22288a31 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm @@ -192,7 +192,7 @@ fling_distance *= 0.1 vanguard_user.visible_message(SPAN_XENODANGER("[vanguard_user] deals [target_atom] a massive blow, sending them flying!"), SPAN_XENOHIGHDANGER("You deal [target_atom] a massive blow, sending them flying!")) vanguard_user.flick_attack_overlay(target_carbon, "slam") - xeno_throw_human(target_carbon, vanguard_user, get_dir(vanguard_user, target_atom), fling_distance) + vanguard_user.throw_carbon(target_atom, null, fling_distance) apply_cooldown() return ..() @@ -509,7 +509,7 @@ if(H.mob_size >= MOB_SIZE_BIG) continue - xeno_throw_human(H, X, facing, fling_dist) + X.throw_carbon(H, facing, fling_dist) H.apply_effect(get_xeno_stun_duration(H, 0.5), WEAKEN) new /datum/effects/xeno_slow(H, X, ttl = get_xeno_stun_duration(H, 25)) diff --git a/code/modules/movement/launching/launching.dm b/code/modules/movement/launching/launching.dm index 96db667fe2ff..f72a7c773490 100644 --- a/code/modules/movement/launching/launching.dm +++ b/code/modules/movement/launching/launching.dm @@ -120,7 +120,7 @@ return TRUE // Proc for throwing items (should only really be used for throw) -/atom/movable/proc/throw_atom(atom/target, range, speed = 0, atom/thrower, spin, launch_type = NORMAL_LAUNCH, pass_flags = NO_FLAGS) +/atom/movable/proc/throw_atom(atom/target, range, speed = 0, atom/thrower, spin, launch_type = NORMAL_LAUNCH, pass_flags = NO_FLAGS, list/end_throw_callbacks, list/collision_callbacks) var/temp_pass_flags = pass_flags switch (launch_type) if (NORMAL_LAUNCH) @@ -135,6 +135,10 @@ LM.speed = speed LM.thrower = thrower LM.spin = spin + if(end_throw_callbacks) + LM.end_throw_callbacks = end_throw_callbacks + if(collision_callbacks) + LM.collision_callbacks = collision_callbacks if(SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_LAUNCH, LM) & COMPONENT_LAUNCH_CANCEL) return