mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-16 03:56:20 +00:00
People can now pet held mothroaches and pugs if they want to, or use items on them, hopefully without causing many issues. After all, it only took about a couple dozen lines of code to make... ...Oh, did the 527 files changed or the 850~ lines added/removed perhaps catch your eye? Made you wonder if I accidentally pushed the wrong branch? or skewed something up big time? Well, nuh uh. I just happen to be fed up with the melee attack chain still using stringized params instead of an array/list. It was frankly revolting to see how I'd have had to otherwise call `list2params` for what I'm trying to accomplish here, and make this PR another tessera to the immense stupidity of our attack chain procs calling `params2list` over and over and over instead of just using that one call instance from `ClickOn` as an argument. It's 2025, honey, wake up! I also tried to replace some of those single letter vars/args but there are just way too many of them. Improving old code. And I want to be able to pet mobroaches while holding them too. 🆑 qol: You can now interact with held mobs in more ways beside wearing them. /🆑
94 lines
4.1 KiB
Plaintext
94 lines
4.1 KiB
Plaintext
/**
|
|
* Kneecapping element replaces the item's secondary attack with an aimed attack at the kneecaps under certain circumstances.
|
|
*
|
|
* Element is incompatible with non-items. Requires the parent item to have a force equal to or greater than WOUND_MINIMUM_DAMAGE.
|
|
* Also requires that the parent can actually get past pre_secondary_attack without the attack chain cancelling.
|
|
*
|
|
* Kneecapping attacks have a wounding bonus between severe and critical+10 wound thresholds. Without some serious wound protecting
|
|
* armour this all but guarantees a wound of some sort. The attack is directed specifically at a limb and the limb takes the damage.
|
|
*
|
|
* Requires the attacker to be aiming for either leg zone, which will be targeted specifically. They will than have a 3-second long
|
|
* do_after before executing the attack.
|
|
*
|
|
* Kneecapping requires the target to either be on the floor, immobilised or buckled to something. And also to have an appropriate leg.
|
|
*
|
|
* Passing all the checks will cancel the entire attack chain.
|
|
*/
|
|
/datum/element/kneecapping
|
|
|
|
/datum/element/kneecapping/Attach(datum/target)
|
|
if(!isitem(target))
|
|
stack_trace("Kneecapping element added to non-item object: \[[target]\]")
|
|
return ELEMENT_INCOMPATIBLE
|
|
|
|
var/obj/item/target_item = target
|
|
|
|
if(target_item.force < WOUND_MINIMUM_DAMAGE)
|
|
stack_trace("Kneecapping element added to item with too little force to wound: \[[target]\]")
|
|
return ELEMENT_INCOMPATIBLE
|
|
|
|
. = ..()
|
|
|
|
if(. == ELEMENT_INCOMPATIBLE)
|
|
return
|
|
|
|
RegisterSignal(target, COMSIG_ITEM_ATTACK_SECONDARY , PROC_REF(try_kneecap_target))
|
|
|
|
/datum/element/kneecapping/Detach(datum/target)
|
|
UnregisterSignal(target, COMSIG_ITEM_ATTACK_SECONDARY)
|
|
|
|
return ..()
|
|
|
|
/**
|
|
* Signal handler for COMSIG_ITEM_ATTACK_SECONDARY. Does checks for pacifism, zones and target state before either returning nothing
|
|
* if the special attack could not be attempted, performing the ordinary attack procs instead - Or cancelling the attack chain if
|
|
* the attack can be started.
|
|
*/
|
|
/datum/element/kneecapping/proc/try_kneecap_target(obj/item/source, mob/living/carbon/target, mob/attacker, list/modifiers)
|
|
SIGNAL_HANDLER
|
|
|
|
if((attacker.zone_selected != BODY_ZONE_L_LEG) && (attacker.zone_selected != BODY_ZONE_R_LEG))
|
|
return
|
|
|
|
if(HAS_TRAIT(attacker, TRAIT_PACIFISM))
|
|
return
|
|
|
|
if(!iscarbon(target))
|
|
return
|
|
|
|
if(!target.buckled && !HAS_TRAIT(target, TRAIT_FLOORED) && !HAS_TRAIT(target, TRAIT_IMMOBILIZED))
|
|
return
|
|
|
|
var/obj/item/bodypart/leg = target.get_bodypart(attacker.zone_selected)
|
|
|
|
if(!leg)
|
|
return
|
|
|
|
. = COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN
|
|
|
|
INVOKE_ASYNC(src, PROC_REF(do_kneecap_target), source, leg, target, attacker)
|
|
|
|
/**
|
|
* After a short do_after, attacker applies damage to the given leg with a significant wounding bonus, applying the weapon's force as damage.
|
|
*/
|
|
/datum/element/kneecapping/proc/do_kneecap_target(obj/item/weapon, obj/item/bodypart/leg, mob/living/carbon/target, mob/attacker)
|
|
if(LAZYACCESS(attacker.do_afters, weapon))
|
|
return
|
|
|
|
attacker.visible_message(span_warning("[attacker] carefully aims [attacker.p_their()] [weapon] for a swing at [target]'s kneecaps!"), span_danger("You carefully aim \the [weapon] for a swing at [target]'s kneecaps!"))
|
|
log_combat(attacker, target, "started aiming a swing to break the kneecaps of", weapon)
|
|
|
|
if(!do_after(attacker, 3 SECONDS, target, interaction_key = weapon))
|
|
return
|
|
|
|
attacker.visible_message(span_warning("[attacker] swings [attacker.p_their()] [weapon] at [target]'s kneecaps!"), span_danger("You swing \the [weapon] at [target]'s kneecaps!"))
|
|
|
|
var/min_wound = leg.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_SEVERE, return_value_if_no_wound = 30, wound_source = weapon)
|
|
var/max_wound = leg.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_CRITICAL, return_value_if_no_wound = 50, wound_source = weapon)
|
|
|
|
target.apply_damage(weapon.force, weapon.damtype, leg, wound_bonus = rand(min_wound, max_wound + 10), attacking_item = weapon)
|
|
target.emote("scream")
|
|
log_combat(attacker, target, "broke the kneecaps of", weapon)
|
|
attacker.do_attack_animation(target, used_item = weapon)
|
|
playsound(source = weapon, soundin = weapon.hitsound, vol = weapon.get_clamped_volume(), vary = TRUE)
|