From 9664d24c133b2910489e0619c6e27c19bdf2ae9a Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Sun, 15 Oct 2023 23:25:19 -0500 Subject: [PATCH] Refactors `UnarmedAttack` so we don't have like 4 Unarmed Attack signals, kills two more snowflake species procs (#78991) ## About The Pull Request - Deletes `spec_unarmedattack` - Deletes `spec_unarmedattacked` - Replaces `COMSIG_HUMAN_EARLY_UNARMED_ATTACK` with `COMSIG_LIVING_EARLY_UNARMED_ATTACK` - Replaces uses of `COMSIG_HUMAN_MELEE_UNARMED_ATTACK` with `COMSIG_LIVING_EARLY_UNARMED_ATTACK` - Fixes(?)(I've never seen this work) / Elementizes Monkey ability to bite while handcuffed - Monkey clever `attack paw` / `attack hand` thing is now handled the same on the human level (via `resolve_unarmed_attack`) ## Why It's Good For The Game Atomized from swing branch. I was really annoyed with these two signals, this kinda unifies the behavior between living and human mobs (they were already quite similar). One thing of note is that this will make dis-coordinated humans use `attack_paw` rather than `attack_hand`, so they'll bite people instead of punching them. I'm not sure if this is what we want, if we wanna tweak that before then I can by all means. ## Changelog :cl: Melbert refactor: Refactored unarmed attacking mechanisms, this means dis-coordinated humans will now bite people like monkeys (like how coordinated monkeys punch people like humans?) refactor: Dis-coordinated humans smashing up machines now use their hands, rather than their paws /:cl: --------- Co-authored-by: san7890 --- .../signals/signals_mob/signals_mob_carbon.dm | 4 - .../signals/signals_mob/signals_mob_living.dm | 6 +- .../signals/signals_mob/signals_mob_simple.dm | 2 +- code/_onclick/click.dm | 5 +- code/_onclick/other_mobs.dm | 82 ++++++++++++------- code/datums/components/butchering.dm | 8 +- code/datums/components/focused_attacker.dm | 4 +- code/datums/components/mob_chain.dm | 3 +- code/datums/components/punchcooldown.dm | 4 +- code/datums/components/riding/riding_mob.dm | 7 +- code/datums/components/shovel_hands.dm | 4 +- code/datums/components/shy.dm | 5 +- code/datums/components/shy_in_room.dm | 4 +- code/datums/components/style/style.dm | 4 +- code/datums/elements/amputating_limbs.dm | 8 +- code/datums/elements/basic_eating.dm | 14 +++- code/datums/elements/dextrous.dm | 4 +- code/datums/elements/door_pryer.dm | 12 +-- code/datums/elements/human_biter.dm | 28 +++++++ code/datums/elements/mob_grabber.dm | 13 +-- code/datums/elements/structure_repair.dm | 6 +- code/datums/elements/wall_smasher.dm | 14 ++-- code/datums/elements/wall_tearer.dm | 6 +- code/datums/mutations/chameleon.dm | 4 +- code/datums/mutations/hulk.dm | 29 +++---- code/datums/wounds/bones.dm | 9 +- code/game/machinery/_machinery.dm | 19 ++++- .../stacks/golem_food/golem_status_effects.dm | 8 +- .../traitor/objectives/hack_comm_console.dm | 2 +- code/modules/clothing/shoes/gunboots.dm | 10 +-- code/modules/mining/lavaland/tendril_loot.dm | 8 +- .../basic/space_fauna/demon/demon_subtypes.dm | 7 +- .../mob/living/carbon/human/_species.dm | 8 -- .../carbon/human/species_types/monkeys.dm | 61 +------------- code/modules/mob/living/living_defense.dm | 6 +- code/modules/mod/modules/modules_ninja.dm | 8 +- code/modules/surgery/bodyparts/parts.dm | 6 ++ .../organs/internal/cyberimp/augments_arms.dm | 16 ++-- code/modules/unit_tests/_unit_tests.dm | 1 + code/modules/unit_tests/hulk.dm | 44 ++++++++++ tgstation.dme | 1 + 41 files changed, 280 insertions(+), 214 deletions(-) create mode 100644 code/datums/elements/human_biter.dm create mode 100644 code/modules/unit_tests/hulk.dm diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index a6e60f1ced8..dd6f6fdccc4 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -132,10 +132,6 @@ #define COMSIG_HUMAN_CORETEMP_CHANGE "human_coretemp_change" ///from /datum/species/handle_fire. Called when the human is set on fire and burning clothes and stuff #define COMSIG_HUMAN_BURNING "human_burning" -///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity, modifiers) -#define COMSIG_HUMAN_EARLY_UNARMED_ATTACK "human_early_unarmed_attack" -///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity, modifiers) -#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" ///from /mob/living/carbon/human/proc/check_shields(): (atom/hit_by, damage, attack_text, attack_type, armour_penetration, damage_type) #define COMSIG_HUMAN_CHECK_SHIELDS "human_check_shields" #define SHIELD_BLOCK (1<<0) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index b70f7f9013d..ceebe7f304b 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -133,7 +133,11 @@ #define COMSIG_LIVING_SLAM_TABLE "living_slam_table" ///from /obj/item/hand_item/slapper/attack(): (source=mob/living/slapper, mob/living/slapped) #define COMSIG_LIVING_SLAP_MOB "living_slap_mob" -///(NOT on humans) from mob/living/*/UnarmedAttack(): (mob/living/source, atom/target, proximity, modifiers) +/// from /mob/living/*/UnarmedAttack(), before sending [COMSIG_LIVING_UNARMED_ATTACK]: (mob/living/source, atom/target, proximity, modifiers) +/// The only reason this exists is so hulk can fire before Fists of the North Star. +/// Note that this is called before [/mob/living/proc/can_unarmed_attack] is called, so be wary of that. +#define COMSIG_LIVING_EARLY_UNARMED_ATTACK "human_pre_attack_hand" +/// from mob/living/*/UnarmedAttack(): (mob/living/source, atom/target, proximity, modifiers) #define COMSIG_LIVING_UNARMED_ATTACK "living_unarmed_attack" ///From base of mob/living/MobBump() (mob/living) #define COMSIG_LIVING_MOB_BUMP "living_mob_bump" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_simple.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_simple.dm index 65d96ea8c4c..8b19c1f0054 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_simple.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_simple.dm @@ -7,7 +7,7 @@ // /mob/living/simple_animal/hostile signals ///before attackingtarget has happened, source is the attacker and target is the attacked #define COMSIG_HOSTILE_PRE_ATTACKINGTARGET "hostile_pre_attackingtarget" - #define COMPONENT_HOSTILE_NO_ATTACK (1<<0) //cancel the attack, only works before attack happens + #define COMPONENT_HOSTILE_NO_ATTACK COMPONENT_CANCEL_ATTACK_CHAIN //cancel the attack, only works before attack happens ///after attackingtarget has happened, source is the attacker and target is the attacked, extra argument for if the attackingtarget was successful #define COMSIG_HOSTILE_POST_ATTACKINGTARGET "hostile_post_attackingtarget" ///from base of mob/living/basic/regal_rat: (mob/living/basic/regal_rat/king) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 0dbc6380233..6418b20abec 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -277,7 +277,10 @@ /** - * Translates into [atom/proc/attack_hand], etc. + * UnarmedAttack: The higest level of mob click chain discounting click itself. + * + * This handles, just "clicking on something" without an item. It translates + * into [atom/proc/attack_hand], [atom/proc/attack_animal] etc. * * Note: proximity_flag here is used to distinguish between normal usage (flag=1), * and usage when clicking on things telekinetically (flag=0). This proc will diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index aeb42361c05..ce281bb4ecf 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -9,33 +9,66 @@ else if (secondary_result != SECONDARY_ATTACK_CALL_NORMAL) CRASH("resolve_right_click_attack (probably attack_hand_secondary) did not return a SECONDARY_ATTACK_* define.") -/* - Humans: - Adds an exception for gloves, to allow special glove types like the ninja ones. +/** + * Checks if this mob is in a valid state to punch someone. + */ +/mob/living/proc/can_unarmed_attack() + return !HAS_TRAIT(src, TRAIT_HANDS_BLOCKED) + +/mob/living/carbon/can_unarmed_attack() + . = ..() + if(!.) + return FALSE - Otherwise pretty standard. -*/ -/mob/living/carbon/human/UnarmedAttack(atom/A, proximity_flag, list/modifiers) - if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED)) - if(src == A) - check_self_for_injuries() - return if(!has_active_hand()) //can't attack without a hand. var/obj/item/bodypart/check_arm = get_active_hand() if(check_arm?.bodypart_disabled) to_chat(src, span_warning("Your [check_arm.name] is in no condition to be used.")) - return + return FALSE to_chat(src, span_notice("You look at your arm and sigh.")) - return + return FALSE - //This signal is needed to prevent gloves of the north star + hulk. - if(SEND_SIGNAL(src, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, A, proximity_flag, modifiers) & COMPONENT_CANCEL_ATTACK_CHAIN) - return - SEND_SIGNAL(src, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, A, proximity_flag, modifiers) + return TRUE - if(!right_click_attack_chain(A, modifiers) && !dna?.species?.spec_unarmedattack(src, A, modifiers)) //Because species like monkeys dont use attack hand - A.attack_hand(src, modifiers) +/mob/living/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) + // The sole reason for this signal needing to exist is making FotNS incompatible with Hulk. + // Note that it is send before [proc/can_unarmed_attack] is called, keep this in mind. + var/sigreturn = SEND_SIGNAL(src, COMSIG_LIVING_EARLY_UNARMED_ATTACK, attack_target, modifiers) + if(sigreturn & COMPONENT_CANCEL_ATTACK_CHAIN) + return TRUE + if(sigreturn & COMPONENT_SKIP_ATTACK) + return FALSE + + if(!can_unarmed_attack(attack_target)) + return FALSE + + sigreturn = SEND_SIGNAL(src, COMSIG_LIVING_UNARMED_ATTACK, attack_target, proximity_flag, modifiers) + if(sigreturn & COMPONENT_CANCEL_ATTACK_CHAIN) + return TRUE + if(sigreturn & COMPONENT_SKIP_ATTACK) + return FALSE + + if(!right_click_attack_chain(attack_target, modifiers)) + resolve_unarmed_attack(attack_target, modifiers) + return TRUE + +/mob/living/carbon/human/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) + // Humans can always check themself regardless of having their hands blocked or w/e + if(src == attack_target) + check_self_for_injuries() + return TRUE + + return ..() + +/mob/living/carbon/resolve_unarmed_attack(atom/attack_target, list/modifiers) + return attack_target.attack_paw(src, modifiers) + +/mob/living/carbon/human/resolve_unarmed_attack(atom/attack_target, list/modifiers) + if(!ISADVANCEDTOOLUSER(src)) + return ..() + + return attack_target.attack_hand(src, modifiers) /mob/living/carbon/human/resolve_right_click_attack(atom/target, list/modifiers) return target.attack_hand_secondary(src, modifiers) @@ -119,17 +152,6 @@ Animals & All Unspecified */ -// If the UnarmedAttack chain is blocked -#define LIVING_UNARMED_ATTACK_BLOCKED(target_atom) (HAS_TRAIT(src, TRAIT_HANDS_BLOCKED) \ - || SEND_SIGNAL(src, COMSIG_LIVING_UNARMED_ATTACK, target_atom, proximity_flag, modifiers) & COMPONENT_CANCEL_ATTACK_CHAIN) - -/mob/living/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) - if(LIVING_UNARMED_ATTACK_BLOCKED(attack_target)) - return FALSE - if(!right_click_attack_chain(attack_target, modifiers)) - resolve_unarmed_attack(attack_target, modifiers) - return TRUE - /** * Called when the unarmed attack hasn't been stopped by the LIVING_UNARMED_ATTACK_BLOCKED macro or the right_click_attack_chain proc. * This will call an attack proc that can vary from mob type to mob type on the target. @@ -295,8 +317,6 @@ GiveTarget(attack_target) INVOKE_ASYNC(src, PROC_REF(AttackingTarget), attack_target) -#undef LIVING_UNARMED_ATTACK_BLOCKED - /* New Players: Have no reason to click on anything at all. diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index 689de30db37..183203ed709 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -257,16 +257,16 @@ if(!(slot & source.slot_flags)) return butchering_enabled = TRUE - RegisterSignal(user, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(butcher_target)) + RegisterSignal(user, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(butcher_target)) ///Same as disable_butchering but for worn items /datum/component/butchering/wearable/proc/worn_disable_butchering(obj/item/source, mob/user) SIGNAL_HANDLER butchering_enabled = FALSE - UnregisterSignal(user, COMSIG_HUMAN_EARLY_UNARMED_ATTACK) + UnregisterSignal(user, COMSIG_LIVING_UNARMED_ATTACK) /datum/component/butchering/wearable/proc/butcher_target(mob/user, atom/target, proximity) SIGNAL_HANDLER if(!isliving(target)) - return - onItemAttack(parent, target, user) + return NONE + return onItemAttack(parent, target, user) diff --git a/code/datums/components/focused_attacker.dm b/code/datums/components/focused_attacker.dm index eda6bd17979..8635973f263 100644 --- a/code/datums/components/focused_attacker.dm +++ b/code/datums/components/focused_attacker.dm @@ -24,12 +24,12 @@ /datum/component/focused_attacker/RegisterWithParent() if (isliving(parent)) - RegisterSignals(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK), PROC_REF(pre_mob_attack)) + RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(pre_mob_attack)) else RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(pre_item_attack)) /datum/component/focused_attacker/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_ITEM_PRE_ATTACK)) + UnregisterSignal(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_ITEM_PRE_ATTACK)) /// Before a mob attacks, try increasing its attack power /datum/component/focused_attacker/proc/pre_mob_attack(mob/living/attacker, atom/target) diff --git a/code/datums/components/mob_chain.dm b/code/datums/components/mob_chain.dm index 8312d9d5504..2ff7c4f1967 100644 --- a/code/datums/components/mob_chain.dm +++ b/code/datums/components/mob_chain.dm @@ -43,7 +43,7 @@ RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(on_deletion)) RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) RegisterSignal(parent, COMSIG_ATOM_CAN_BE_PULLED, PROC_REF(on_pulled)) - RegisterSignals(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, COMSIG_MOB_ATTACK_RANGED), PROC_REF(on_attack)) + RegisterSignals(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_MOB_ATTACK_RANGED), PROC_REF(on_attack)) RegisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, PROC_REF(on_glide_size_changed)) if (vary_icon_state) RegisterSignal(parent, COMSIG_ATOM_UPDATE_ICON_STATE, PROC_REF(on_update_icon_state)) @@ -61,7 +61,6 @@ COMSIG_ATOM_CAN_BE_PULLED, COMSIG_ATOM_UPDATE_ICON_STATE, COMSIG_CARBON_LIMB_DAMAGED, - COMSIG_HUMAN_EARLY_UNARMED_ATTACK, COMSIG_LIVING_ADJUST_BRUTE_DAMAGE, COMSIG_LIVING_ADJUST_BURN_DAMAGE, COMSIG_LIVING_ADJUST_CLONE_DAMAGE, diff --git a/code/datums/components/punchcooldown.dm b/code/datums/components/punchcooldown.dm index 7c2ae1047fe..80a72784c09 100644 --- a/code/datums/components/punchcooldown.dm +++ b/code/datums/components/punchcooldown.dm @@ -1,6 +1,6 @@ ///Your favourite Jojoke. Used for the gloves of the north star. /datum/component/wearertargeting/punchcooldown - signals = list(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_LIVING_SLAP_MOB) + signals = list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_LIVING_SLAP_MOB) mobtype = /mob/living/carbon proctype = PROC_REF(reducecooldown) valid_slots = list(ITEM_SLOT_GLOVES) @@ -13,7 +13,7 @@ return RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(changewarcry)) -///Called on COMSIG_HUMAN_MELEE_UNARMED_ATTACK. Yells the warcry and and reduces punch cooldown. +///Called on COMSIG_LIVING_UNARMED_ATTACK. Yells the warcry and and reduces punch cooldown. /datum/component/wearertargeting/punchcooldown/proc/reducecooldown(mob/living/carbon/M, atom/target) if((M.combat_mode && isliving(target)) || istype(M.get_active_held_item(), /obj/item/hand_item/slapper)) M.changeNext_move(CLICK_CD_RAPID) diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index a546508e505..cf4dad61b5e 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -212,7 +212,7 @@ /datum/component/riding/creature/human/RegisterWithParent() . = ..() - RegisterSignal(parent, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(on_host_unarmed_melee)) + RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_host_unarmed_melee)) RegisterSignal(parent, COMSIG_LIVING_SET_BODY_POSITION, PROC_REF(check_carrier_fall_over)) /datum/component/riding/creature/human/log_riding(mob/living/living_parent, mob/living/rider) @@ -234,12 +234,13 @@ return ..() /// If the carrier shoves the person they're carrying, force the carried mob off -/datum/component/riding/creature/human/proc/on_host_unarmed_melee(mob/living/carbon/human/human_parent, atom/target, proximity, modifiers) +/datum/component/riding/creature/human/proc/on_host_unarmed_melee(mob/living/source, atom/target, proximity, modifiers) SIGNAL_HANDLER - if(LAZYACCESS(modifiers, RIGHT_CLICK) && (target in human_parent.buckled_mobs)) + if(LAZYACCESS(modifiers, RIGHT_CLICK) && (target in source.buckled_mobs)) force_dismount(target) return COMPONENT_CANCEL_ATTACK_CHAIN + return NONE /// If the carrier gets knocked over, force the rider(s) off and see if someone got hurt /datum/component/riding/creature/human/proc/check_carrier_fall_over(mob/living/carbon/human/human_parent) diff --git a/code/datums/components/shovel_hands.dm b/code/datums/components/shovel_hands.dm index e4ee2d644d3..34eaf8a98b6 100644 --- a/code/datums/components/shovel_hands.dm +++ b/code/datums/components/shovel_hands.dm @@ -14,10 +14,10 @@ /datum/component/shovel_hands/RegisterWithParent() . = ..() - RegisterSignals(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET), PROC_REF(dig)) + RegisterSignals(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET), PROC_REF(dig)) /datum/component/shovel_hands/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) + UnregisterSignal(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) return ..() /datum/component/shovel_hands/Destroy(force, silent) diff --git a/code/datums/components/shy.dm b/code/datums/components/shy.dm index 845da7e0f7d..5743322dea1 100644 --- a/code/datums/components/shy.dm +++ b/code/datums/components/shy.dm @@ -46,7 +46,7 @@ /datum/component/shy/RegisterWithParent() RegisterSignal(parent, COMSIG_MOB_CLICKON, PROC_REF(on_clickon)) RegisterSignal(parent, COMSIG_LIVING_TRY_PULL, PROC_REF(on_try_pull)) - RegisterSignals(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_EARLY_UNARMED_ATTACK), PROC_REF(on_unarmed_attack)) + RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack)) RegisterSignal(parent, COMSIG_TRY_STRIP, PROC_REF(on_try_strip)) RegisterSignal(parent, COMSIG_TRY_ALT_ACTION, PROC_REF(on_try_alt_action)) @@ -54,7 +54,7 @@ UnregisterSignal(parent, list( COMSIG_MOB_CLICKON, COMSIG_LIVING_TRY_PULL, - COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, + COMSIG_LIVING_UNARMED_ATTACK, COMSIG_TRY_STRIP, COMSIG_TRY_ALT_ACTION, )) @@ -137,4 +137,3 @@ return is_shy(target) && COMPONENT_CANT_ALT_ACTION #undef SHY_COMPONENT_CACHE_TIME - diff --git a/code/datums/components/shy_in_room.dm b/code/datums/components/shy_in_room.dm index 2413c9abafd..023dbaff719 100644 --- a/code/datums/components/shy_in_room.dm +++ b/code/datums/components/shy_in_room.dm @@ -17,7 +17,7 @@ /datum/component/shy_in_room/RegisterWithParent() RegisterSignal(parent, COMSIG_MOB_CLICKON, PROC_REF(on_clickon)) RegisterSignal(parent, COMSIG_LIVING_TRY_PULL, PROC_REF(on_try_pull)) - RegisterSignals(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_EARLY_UNARMED_ATTACK), PROC_REF(on_unarmed_attack)) + RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack)) RegisterSignal(parent, COMSIG_TRY_STRIP, PROC_REF(on_try_strip)) RegisterSignal(parent, COMSIG_TRY_ALT_ACTION, PROC_REF(on_try_alt_action)) @@ -27,7 +27,6 @@ COMSIG_MOB_CLICKON, COMSIG_LIVING_TRY_PULL, COMSIG_LIVING_UNARMED_ATTACK, - COMSIG_HUMAN_EARLY_UNARMED_ATTACK, COMSIG_TRY_STRIP, COMSIG_TRY_ALT_ACTION, )) @@ -73,4 +72,3 @@ /datum/component/shy_in_room/proc/on_try_alt_action(datum/source, atom/target) SIGNAL_HANDLER return is_shy(target) && COMPONENT_CANT_ALT_ACTION - diff --git a/code/datums/components/style/style.dm b/code/datums/components/style/style.dm index 3894f77311e..abcc99574fe 100644 --- a/code/datums/components/style/style.dm +++ b/code/datums/components/style/style.dm @@ -105,7 +105,7 @@ RegisterSignal(parent, COMSIG_MOB_EMOTED("flip"), PROC_REF(on_flip)) RegisterSignal(parent, COMSIG_MOB_EMOTED("spin"), PROC_REF(on_spin)) RegisterSignal(parent, COMSIG_MOB_ITEM_ATTACK, PROC_REF(on_attack)) - RegisterSignal(parent, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, PROC_REF(on_punch)) + RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_punch)) RegisterSignal(SSdcs, COMSIG_GLOB_MOB_DEATH, PROC_REF(on_death)) RegisterSignal(parent, COMSIG_LIVING_RESONATOR_BURST, PROC_REF(on_resonator_burst)) RegisterSignal(parent, COMSIG_LIVING_PROJECTILE_PARRIED, PROC_REF(on_projectile_parry)) @@ -132,7 +132,7 @@ UnregisterSignal(parent, COMSIG_MOB_MINED) UnregisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE) UnregisterSignal(parent, list(COMSIG_MOB_EMOTED("flip"), COMSIG_MOB_EMOTED("spin"))) - UnregisterSignal(parent, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK)) + UnregisterSignal(parent, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_LIVING_UNARMED_ATTACK)) UnregisterSignal(SSdcs, COMSIG_GLOB_MOB_DEATH) UnregisterSignal(parent, COMSIG_LIVING_RESONATOR_BURST) UnregisterSignal(parent, COMSIG_LIVING_PROJECTILE_PARRIED) diff --git a/code/datums/elements/amputating_limbs.dm b/code/datums/elements/amputating_limbs.dm index 16a99e96f6c..8684a76f47f 100644 --- a/code/datums/elements/amputating_limbs.dm +++ b/code/datums/elements/amputating_limbs.dm @@ -32,16 +32,16 @@ src.minimum_stat = minimum_stat src.snip_chance = snip_chance src.target_zones = target_zones - RegisterSignals(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET), PROC_REF(try_amputate)) + RegisterSignals(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET), PROC_REF(try_amputate)) /datum/element/amputating_limbs/Detach(datum/source) - UnregisterSignal(source, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) + UnregisterSignal(source, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) return ..() /// Called when you click on literally anything with your hands, see if it is an injured carbon and then try to cut it up -/datum/element/amputating_limbs/proc/try_amputate(mob/living/surgeon, atom/victim) +/datum/element/amputating_limbs/proc/try_amputate(mob/living/surgeon, atom/victim, proximity, modifiers) SIGNAL_HANDLER - if (!iscarbon(victim) || HAS_TRAIT(victim, TRAIT_NODISMEMBER) || !prob(snip_chance)) + if (!proximity || !iscarbon(victim) || HAS_TRAIT(victim, TRAIT_NODISMEMBER) || !prob(snip_chance)) return var/mob/living/carbon/limbed_victim = victim diff --git a/code/datums/elements/basic_eating.dm b/code/datums/elements/basic_eating.dm index 86f4be63cac..08c2ed0c192 100644 --- a/code/datums/elements/basic_eating.dm +++ b/code/datums/elements/basic_eating.dm @@ -37,7 +37,12 @@ /datum/element/basic_eating/proc/on_unarm_attack(mob/living/eater, atom/target, proximity, modifiers) SIGNAL_HANDLER - try_eating(eater, target) + if(!proximity) + return NONE + + if(try_eating(eater, target)) + return COMPONENT_CANCEL_ATTACK_CHAIN + return NONE /datum/element/basic_eating/proc/on_pre_attackingtarget(mob/living/eater, atom/target) SIGNAL_HANDLER @@ -45,7 +50,7 @@ /datum/element/basic_eating/proc/try_eating(mob/living/eater, atom/target) if(!is_type_in_list(target, food_types)) - return + return FALSE var/eat_verb = pick("bite","chew","nibble","gnaw","gobble","chomp") if (heal_amt > 0) @@ -54,16 +59,17 @@ eater.heal_overall_damage(heal_amt) eater.visible_message(span_notice("[eater] [eat_verb]s [target]."), span_notice("You [eat_verb] [target][healed ? ", restoring some health" : ""].")) finish_eating(eater, target) - return + return TRUE if (damage_amount > 0 && damage_type) eater.apply_damage(damage_amount, damage_type) eater.visible_message(span_notice("[eater] [eat_verb]s [target], and seems to hurt itself."), span_notice("You [eat_verb] [target], hurting yourself in the process.")) finish_eating(eater, target) - return + return TRUE eater.visible_message(span_notice("[eater] [eat_verb]s [target]."), span_notice("You [eat_verb] [target].")) finish_eating(eater, target) + return TRUE /datum/element/basic_eating/proc/finish_eating(mob/living/eater, atom/target) playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE) diff --git a/code/datums/elements/dextrous.dm b/code/datums/elements/dextrous.dm index 335c7c196d1..526dfa974af 100644 --- a/code/datums/elements/dextrous.dm +++ b/code/datums/elements/dextrous.dm @@ -50,8 +50,10 @@ /// Try picking up items /datum/element/dextrous/proc/on_hand_clicked(mob/living/hand_haver, atom/target, proximity, modifiers) SIGNAL_HANDLER + if(!proximity) + return NONE if (!isitem(target) && hand_haver.combat_mode) - return + return NONE if (LAZYACCESS(modifiers, RIGHT_CLICK)) INVOKE_ASYNC(target, TYPE_PROC_REF(/atom, attack_hand_secondary), hand_haver, modifiers) else diff --git a/code/datums/elements/door_pryer.dm b/code/datums/elements/door_pryer.dm index 5d807434e04..a17687407e3 100644 --- a/code/datums/elements/door_pryer.dm +++ b/code/datums/elements/door_pryer.dm @@ -16,20 +16,20 @@ return ELEMENT_INCOMPATIBLE src.pry_time = pry_time src.interaction_key = interaction_key - RegisterSignals(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK), PROC_REF(on_attack)) + RegisterSignal(target, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_attack)) /datum/element/door_pryer/Detach(datum/source) . = ..() - UnregisterSignal(source, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK)) + UnregisterSignal(source, COMSIG_LIVING_UNARMED_ATTACK) /// If we're targetting an airlock, open it -/datum/element/door_pryer/proc/on_attack(mob/living/basic/attacker, atom/target) +/datum/element/door_pryer/proc/on_attack(mob/living/basic/attacker, atom/target, proximity_flag) SIGNAL_HANDLER - if(!istype(target, /obj/machinery/door/airlock)) - return + if(!proximity_flag || !istype(target, /obj/machinery/door/airlock)) + return NONE var/obj/machinery/door/airlock/airlock_target = target if (!airlock_target.density) - return // It's already open numbnuts + return NONE // It's already open numbnuts if(DOING_INTERACTION_WITH_TARGET(attacker, target) || (!isnull(interaction_key) && DOING_INTERACTION(attacker, interaction_key))) attacker.balloon_alert(attacker, "busy!") diff --git a/code/datums/elements/human_biter.dm b/code/datums/elements/human_biter.dm new file mode 100644 index 00000000000..852dea12320 --- /dev/null +++ b/code/datums/elements/human_biter.dm @@ -0,0 +1,28 @@ +/// Allows carbons with heads to attempt to bite mobs if attacking with cuffed hands / missing arms +/datum/element/human_biter + +/datum/element/human_biter/Attach(datum/target) + . = ..() + if(!iscarbon(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_LIVING_EARLY_UNARMED_ATTACK, PROC_REF(try_bite)) + +/datum/element/human_biter/Detach(datum/source, ...) + . = ..() + UnregisterSignal(source, COMSIG_LIVING_EARLY_UNARMED_ATTACK) + +/datum/element/human_biter/proc/try_bite(mob/living/carbon/human/source, atom/target, proximity_flag, modifiers) + SIGNAL_HANDLER + + if(!proximity_flag || !source.combat_mode || LAZYACCESS(modifiers, RIGHT_CLICK) || !isliving(target)) + return NONE + + // If we can attack like normal, just go ahead and do that + if(source.can_unarmed_attack()) + return NONE + + if(target.attack_paw(source, modifiers)) + return COMPONENT_CANCEL_ATTACK_CHAIN // bite successful! + + return COMPONENT_SKIP_ATTACK // we will fail anyways if we try to attack normally, so skip the rest diff --git a/code/datums/elements/mob_grabber.dm b/code/datums/elements/mob_grabber.dm index a85c5dc48b2..cc766f24887 100644 --- a/code/datums/elements/mob_grabber.dm +++ b/code/datums/elements/mob_grabber.dm @@ -13,18 +13,19 @@ return ELEMENT_INCOMPATIBLE src.minimum_stat = minimum_stat src.steal_from_others = steal_from_others - RegisterSignals(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET), PROC_REF(grab_mob)) + RegisterSignals(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET), PROC_REF(grab_mob)) /datum/element/mob_grabber/Detach(datum/source) - UnregisterSignal(source, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) + UnregisterSignal(source, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) . = ..() /// Try and grab something we attacked -/datum/element/mob_grabber/proc/grab_mob(mob/living/source, mob/living/target) +/datum/element/mob_grabber/proc/grab_mob(mob/living/source, mob/living/target, proximity, modifiers) SIGNAL_HANDLER - if (!isliving(target) || !source.Adjacent(target) || target.stat < minimum_stat) - return + if (!isliving(target) || !proximity || target.stat < minimum_stat) + return NONE var/atom/currently_pulled = target.pulledby if (!isnull(currently_pulled) && (!steal_from_others || currently_pulled == source)) - return + return NONE INVOKE_ASYNC(target, TYPE_PROC_REF(/mob/living, grabbedby), source) + return COMPONENT_CANCEL_ATTACK_CHAIN diff --git a/code/datums/elements/structure_repair.dm b/code/datums/elements/structure_repair.dm index d3b26eed815..1f57a3d1730 100644 --- a/code/datums/elements/structure_repair.dm +++ b/code/datums/elements/structure_repair.dm @@ -25,11 +25,11 @@ return ..() /// If the target is of a valid type, interrupt the attack chain to repair it instead -/datum/element/structure_repair/proc/try_repair(mob/living/fixer, atom/target) +/datum/element/structure_repair/proc/try_repair(mob/living/fixer, atom/target, proximity) SIGNAL_HANDLER - if (!is_type_in_typecache(target, structure_types_typecache)) - return + if (!proximity || !is_type_in_typecache(target, structure_types_typecache)) + return NONE if (target.get_integrity() >= target.max_integrity) target.balloon_alert(fixer, "not damaged!") diff --git a/code/datums/elements/wall_smasher.dm b/code/datums/elements/wall_smasher.dm index 3c6c1d92da7..ba8a689253c 100644 --- a/code/datums/elements/wall_smasher.dm +++ b/code/datums/elements/wall_smasher.dm @@ -17,7 +17,7 @@ return ELEMENT_INCOMPATIBLE src.strength_flag = strength_flag - RegisterSignals(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_EARLY_UNARMED_ATTACK), PROC_REF(on_unarm_attack)) // Players + RegisterSignal(target, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarm_attack)) // Players RegisterSignal(target, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_pre_attackingtarget)) // AI if (isanimal_or_basicmob(target)) @@ -25,7 +25,7 @@ animal_target.environment_smash = strength_flag /datum/element/wall_smasher/Detach(datum/target) - UnregisterSignal(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) + UnregisterSignal(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) if (isanimal_or_basicmob(target)) var/mob/living/simple_animal/animal_target = target animal_target.environment_smash = initial(animal_target.environment_smash) @@ -34,19 +34,19 @@ /datum/element/wall_smasher/proc/on_unarm_attack(mob/living/puncher, atom/target, proximity, modifiers) SIGNAL_HANDLER - try_smashing(puncher, target) + return try_smashing(puncher, target) /datum/element/wall_smasher/proc/on_pre_attackingtarget(mob/living/puncher, atom/target) SIGNAL_HANDLER - try_smashing(puncher, target) + return try_smashing(puncher, target) /datum/element/wall_smasher/proc/try_smashing(mob/living/puncher, atom/target) if (!isturf(target)) - return + return NONE if (isfloorturf(target)) - return + return NONE if (isindestructiblewall(target)) - return + return NONE puncher.changeNext_move(CLICK_CD_MELEE) puncher.do_attack_animation(target) diff --git a/code/datums/elements/wall_tearer.dm b/code/datums/elements/wall_tearer.dm index 8499a161705..e7ca4b3be96 100644 --- a/code/datums/elements/wall_tearer.dm +++ b/code/datums/elements/wall_tearer.dm @@ -28,17 +28,17 @@ src.tear_time = tear_time src.reinforced_multiplier = reinforced_multiplier src.do_after_key = do_after_key - RegisterSignals(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK), PROC_REF(on_attacked_wall)) + RegisterSignal(target, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_attacked_wall)) /datum/element/wall_tearer/Detach(datum/source) . = ..() - UnregisterSignal(source, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK)) + UnregisterSignal(source, COMSIG_LIVING_UNARMED_ATTACK) /// Try to tear up a wall /datum/element/wall_tearer/proc/on_attacked_wall(mob/living/tearer, atom/target, proximity_flag) SIGNAL_HANDLER if (!proximity_flag) - return + return NONE if (DOING_INTERACTION_WITH_TARGET(tearer, target) || (!isnull(do_after_key) && DOING_INTERACTION(tearer, do_after_key))) tearer.balloon_alert(tearer, "busy!") return COMPONENT_HOSTILE_NO_ATTACK diff --git a/code/datums/mutations/chameleon.dm b/code/datums/mutations/chameleon.dm index 9cd155594ec..3de361ba548 100644 --- a/code/datums/mutations/chameleon.dm +++ b/code/datums/mutations/chameleon.dm @@ -14,7 +14,7 @@ return owner.alpha = CHAMELEON_MUTATION_DEFAULT_TRANSPARENCY RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) - RegisterSignal(owner, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(on_attack_hand)) + RegisterSignal(owner, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_attack_hand)) /datum/mutation/human/chameleon/on_life(seconds_per_tick, times_fired) owner.alpha = max(owner.alpha - (12.5 * (GET_MUTATION_POWER(src)) * seconds_per_tick), 0) @@ -54,4 +54,4 @@ if(..()) return owner.alpha = 255 - UnregisterSignal(owner, list(COMSIG_MOVABLE_MOVED, COMSIG_HUMAN_EARLY_UNARMED_ATTACK)) + UnregisterSignal(owner, list(COMSIG_MOVABLE_MOVED, COMSIG_LIVING_UNARMED_ATTACK)) diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm index ba04fc07c54..788b885bbce 100644 --- a/code/datums/mutations/hulk.dm +++ b/code/datums/mutations/hulk.dm @@ -29,26 +29,27 @@ part.variable_color = "#00aa00" owner.update_body_parts() owner.add_mood_event("hulk", /datum/mood_event/hulk) - RegisterSignal(owner, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(on_attack_hand)) + RegisterSignal(owner, COMSIG_LIVING_EARLY_UNARMED_ATTACK, PROC_REF(on_attack_hand)) RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(handle_speech)) RegisterSignal(owner, COMSIG_MOB_CLICKON, PROC_REF(check_swing)) /datum/mutation/human/hulk/proc/on_attack_hand(mob/living/carbon/human/source, atom/target, proximity, modifiers) SIGNAL_HANDLER - if(!proximity) - return - if(!source.combat_mode || LAZYACCESS(modifiers, RIGHT_CLICK)) - return - if(target.attack_hulk(owner)) - if(world.time > (last_scream + scream_delay)) - last_scream = world.time - INVOKE_ASYNC(src, PROC_REF(scream_attack), source) - log_combat(source, target, "punched", "hulk powers") - source.do_attack_animation(target, ATTACK_EFFECT_SMASH) - source.changeNext_move(CLICK_CD_MELEE) - + if(!source.combat_mode || !proximity || LAZYACCESS(modifiers, RIGHT_CLICK)) + return NONE + if(!source.can_unarmed_attack()) return COMPONENT_CANCEL_ATTACK_CHAIN + if(!target.attack_hulk(owner)) + return NONE + + if(world.time > (last_scream + scream_delay)) + last_scream = world.time + INVOKE_ASYNC(src, PROC_REF(scream_attack), source) + log_combat(source, target, "punched", "hulk powers") + source.do_attack_animation(target, ATTACK_EFFECT_SMASH) + source.changeNext_move(CLICK_CD_MELEE) + return COMPONENT_CANCEL_ATTACK_CHAIN /datum/mutation/human/hulk/proc/scream_attack(mob/living/carbon/human/source) source.say("WAAAAAAAAAAAAAAGH!", forced="hulk") @@ -90,7 +91,7 @@ part.variable_color = null owner.update_body_parts() owner.clear_mood_event("hulk") - UnregisterSignal(owner, COMSIG_HUMAN_EARLY_UNARMED_ATTACK) + UnregisterSignal(owner, COMSIG_LIVING_EARLY_UNARMED_ATTACK) UnregisterSignal(owner, COMSIG_MOB_SAY) UnregisterSignal(owner, COMSIG_MOB_CLICKON) diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index 9b8da5177ca..80c1c0a7557 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -61,9 +61,9 @@ /datum/wound/blunt/bone/set_victim(new_victim) if (victim) - UnregisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK) + UnregisterSignal(victim, COMSIG_LIVING_UNARMED_ATTACK) if (new_victim) - RegisterSignal(new_victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(attack_with_hurt_hand)) + RegisterSignal(new_victim, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(attack_with_hurt_hand)) return ..() @@ -114,8 +114,8 @@ /datum/wound/blunt/bone/proc/attack_with_hurt_hand(mob/M, atom/target, proximity) SIGNAL_HANDLER - if(victim.get_active_hand() != limb || !victim.combat_mode || !ismob(target) || severity <= WOUND_SEVERITY_MODERATE) - return + if(victim.get_active_hand() != limb || !proximity || !victim.combat_mode || !ismob(target) || severity <= WOUND_SEVERITY_MODERATE) + return NONE // With a severe or critical wound, you have a 15% or 30% chance to proc pain on hit if(prob((severity - 1) * 15)) @@ -131,6 +131,7 @@ limb.receive_damage(brute=rand(3,7)) return COMPONENT_CANCEL_ATTACK_CHAIN + return NONE /datum/wound/blunt/bone/receive_damage(wounding_type, wounding_dmg, wound_bonus) if(!victim || wounding_dmg < WOUND_MINIMUM_DAMAGE) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index f99b9f3cc94..c3d968dca8a 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -680,10 +680,25 @@ /obj/machinery/attack_paw(mob/living/user, list/modifiers) if(!user.combat_mode) return attack_hand(user) + user.changeNext_move(CLICK_CD_MELEE) user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) - var/damage = take_damage(4, BRUTE, MELEE, 1) - user.visible_message(span_danger("[user] smashes [src] with [user.p_their()] paws[damage ? "." : ", without leaving a mark!"]"), null, null, COMBAT_MESSAGE_RANGE) + var/damage = take_damage(damage_amount = 4, damage_type = BRUTE, damage_flag = MELEE, sound_effect = TRUE, attack_dir = get_dir(user, src)) + + var/hit_with_what_noun = "paws" + var/obj/item/bodypart/arm/arm = user.get_active_hand() + if(!isnull(arm)) + hit_with_what_noun = arm.appendage_noun // hit with "their hand" + if(user.usable_hands > 1) + hit_with_what_noun += plural_s(hit_with_what_noun) // hit with "their hands" + + user.visible_message( + span_danger("[user] smashes [src] with [user.p_their()] [hit_with_what_noun][damage ? "." : ", without leaving a mark!"]"), + span_danger("You smash [src] with your [hit_with_what_noun][damage ? "." : ", without leaving a mark!"]"), + span_hear("You hear a [damage ? "smash" : "thud"]."), + COMBAT_MESSAGE_RANGE, + ) + return TRUE /obj/machinery/attack_hulk(mob/living/carbon/user) . = ..() diff --git a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm index 5ed7fcd4682..e52c5f8034c 100644 --- a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm +++ b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm @@ -343,7 +343,7 @@ if (!.) return FALSE var/mob/living/carbon/human/human_owner = owner - RegisterSignal(human_owner, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, PROC_REF(on_punched)) + RegisterSignal(human_owner, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_punched)) human_owner.physiology.brute_mod *= brute_modifier for (var/obj/item/bodypart/arm/arm in human_owner.bodyparts) if (arm.limb_id != SPECIES_GOLEM) @@ -354,10 +354,10 @@ /datum/status_effect/golem/titanium/proc/on_punched(mob/living/puncher, atom/punchee, proximity) SIGNAL_HANDLER if (!proximity || !isliving(punchee)) - return + return NONE var/mob/living/victim = punchee if (victim.body_position == LYING_DOWN || (!(FACTION_MINING in victim.faction) && !(FACTION_BOSS in victim.faction))) - return + return NONE victim.apply_damage(mining_bonus, BRUTE) /// Make the targeted arm big and strong @@ -370,7 +370,7 @@ /datum/status_effect/golem/titanium/on_remove() var/mob/living/carbon/human/human_owner = owner - UnregisterSignal(human_owner, COMSIG_HUMAN_MELEE_UNARMED_ATTACK) + UnregisterSignal(human_owner, COMSIG_LIVING_UNARMED_ATTACK) human_owner.physiology.brute_mod /= brute_modifier for (var/obj/item/bodypart/arm/arm as anything in modified_arms) debuff_arm(arm) diff --git a/code/modules/antagonists/traitor/objectives/hack_comm_console.dm b/code/modules/antagonists/traitor/objectives/hack_comm_console.dm index 52e0397cc60..93323e4e15f 100644 --- a/code/modules/antagonists/traitor/objectives/hack_comm_console.dm +++ b/code/modules/antagonists/traitor/objectives/hack_comm_console.dm @@ -23,7 +23,7 @@ /datum/traitor_objective/hack_comm_console/generate_objective(datum/mind/generating_for, list/possible_duplicates) AddComponent(/datum/component/traitor_objective_mind_tracker, generating_for, \ - signals = list(COMSIG_HUMAN_EARLY_UNARMED_ATTACK = PROC_REF(on_unarmed_attack))) + signals = list(COMSIG_LIVING_UNARMED_ATTACK = PROC_REF(on_unarmed_attack))) RegisterSignal(SSdcs, COMSIG_GLOB_TRAITOR_OBJECTIVE_COMPLETED, PROC_REF(on_global_obj_completed)) return TRUE diff --git a/code/modules/clothing/shoes/gunboots.dm b/code/modules/clothing/shoes/gunboots.dm index db24b2338cf..d8335b5fcb0 100644 --- a/code/modules/clothing/shoes/gunboots.dm +++ b/code/modules/clothing/shoes/gunboots.dm @@ -18,13 +18,13 @@ /obj/item/clothing/shoes/gunboots/equipped(mob/user, slot) . = ..() if(slot & ITEM_SLOT_FEET) - RegisterSignal(user, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, PROC_REF(check_kick)) + RegisterSignal(user, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(check_kick)) else - UnregisterSignal(user, COMSIG_HUMAN_MELEE_UNARMED_ATTACK) + UnregisterSignal(user, COMSIG_LIVING_UNARMED_ATTACK) /obj/item/clothing/shoes/gunboots/dropped(mob/user) if(user) - UnregisterSignal(user, COMSIG_HUMAN_MELEE_UNARMED_ATTACK) + UnregisterSignal(user, COMSIG_LIVING_UNARMED_ATTACK) return ..() /// After each step, check if we randomly fire a shot @@ -38,8 +38,8 @@ /// Stomping on someone while wearing gunboots shoots them point blank /obj/item/clothing/shoes/gunboots/proc/check_kick(mob/living/carbon/human/kicking_person, atom/attacked_atom, proximity) SIGNAL_HANDLER - if(!isliving(attacked_atom)) - return + if(!proximity || !isliving(attacked_atom)) + return NONE var/mob/living/attacked_living = attacked_atom if(attacked_living.body_position == LYING_DOWN) INVOKE_ASYNC(src, PROC_REF(fire_shot), attacked_living) diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm index d3d4b4b672f..e790a235549 100644 --- a/code/modules/mining/lavaland/tendril_loot.dm +++ b/code/modules/mining/lavaland/tendril_loot.dm @@ -632,7 +632,7 @@ . = ..() if(slot & ITEM_SLOT_GLOVES) tool_behaviour = TOOL_MINING - RegisterSignal(user, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(rocksmash)) + RegisterSignal(user, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(rocksmash)) RegisterSignal(user, COMSIG_MOVABLE_BUMP, PROC_REF(rocksmash)) else stopmining(user) @@ -643,13 +643,15 @@ /obj/item/clothing/gloves/gauntlets/proc/stopmining(mob/user) tool_behaviour = initial(tool_behaviour) - UnregisterSignal(user, COMSIG_HUMAN_EARLY_UNARMED_ATTACK) + UnregisterSignal(user, COMSIG_LIVING_UNARMED_ATTACK) UnregisterSignal(user, COMSIG_MOVABLE_BUMP) /obj/item/clothing/gloves/gauntlets/proc/rocksmash(mob/living/carbon/human/user, atom/rocks, proximity) SIGNAL_HANDLER + if(!proximity) + return NONE if(!ismineralturf(rocks) && !isasteroidturf(rocks)) - return + return NONE rocks.attackby(src, user) return COMPONENT_CANCEL_ATTACK_CHAIN diff --git a/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm b/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm index e52eb09ac0b..ed3c131949d 100644 --- a/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm +++ b/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm @@ -99,16 +99,19 @@ /mob/living/basic/demon/slaughter/proc/on_attack(mob/living/source, atom/attack_target, proximity_flag, list/modifiers) SIGNAL_HANDLER + if(!proximity_flag) + return NONE + if(LAZYACCESS(modifiers, RIGHT_CLICK)) bodyslam(attack_target) return COMPONENT_CANCEL_ATTACK_CHAIN if(!iscarbon(attack_target)) - return + return NONE var/mob/living/carbon/target = attack_target if(target.stat == DEAD || isnull(target.mind) || (current_hitstreak > wound_bonus_hitstreak_max)) - return + return NONE current_hitstreak++ wound_bonus += wound_bonus_per_hit diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 12e2bd7a053..af4f3b9ddf7 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1198,7 +1198,6 @@ GLOBAL_LIST_EMPTY(features_by_species) target.lastattacker = user.real_name target.lastattackerckey = user.ckey - user.dna.species.spec_unarmedattacked(user, target) if(user.limb_destroyer) target.dismembering_strike(user, affecting.body_zone) @@ -1225,9 +1224,6 @@ GLOBAL_LIST_EMPTY(features_by_species) target.apply_effect(knockdown_duration, EFFECT_KNOCKDOWN, armor_block) log_combat(user, target, "got a stun punch with their previous punch") -/datum/species/proc/spec_unarmedattacked(mob/living/carbon/human/user, mob/living/carbon/human/target) - return - /datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) if(target.check_block()) target.visible_message(span_warning("[user]'s shove is blocked by [target]!"), \ @@ -1790,10 +1786,6 @@ GLOBAL_LIST_EMPTY(features_by_species) former_tail_owner.clear_mood_event("tail_balance_lost") former_tail_owner.clear_mood_event("wrong_tail_regained") -///Species override for unarmed attacks because the attack_hand proc was made by a mouth-breathing troglodyte on a tricycle. Also to whoever thought it would be a good idea to make it so the original spec_unarmedattack was not actually linked to unarmed attack needs to be checked by a doctor because they clearly have a vast empty space in their head. -/datum/species/proc/spec_unarmedattack(mob/living/carbon/human/user, atom/target, modifiers) - return FALSE - /// Returns a list of strings representing features this species has. /// Used by the preferences UI to know what buttons to show. /datum/species/proc/get_features() diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index f8aee4d83b1..81861d381a0 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -52,70 +52,13 @@ passtable_on(H, SPECIES_TRAIT) H.dna.add_mutation(/datum/mutation/human/race, MUT_NORMAL) H.dna.activate_mutation(/datum/mutation/human/race) + H.AddElement(/datum/element/human_biter) /datum/species/monkey/on_species_loss(mob/living/carbon/C) . = ..() passtable_off(C, SPECIES_TRAIT) C.dna.remove_mutation(/datum/mutation/human/race) - -/datum/species/monkey/spec_unarmedattack(mob/living/carbon/human/user, atom/target, modifiers) - // If our hands are not blocked, dont try to bite them - if(!HAS_TRAIT(user, TRAIT_HANDS_BLOCKED)) - // if we aren't an advanced tool user, we call attack_paw and cancel the preceeding attack chain - if(!ISADVANCEDTOOLUSER(user)) - target.attack_paw(user, modifiers) - return TRUE - return ..() - - // this shouldn't even be possible, but I'm sure the check was here for a reason - if(!iscarbon(target)) - stack_trace("HEY LISTEN! We are performing a species spec_unarmed attack with a non-carbon user. How did you fuck this up?") - return TRUE - var/mob/living/carbon/victim = target - if(user.is_muzzled()) - return TRUE // cannot bite them if we're muzzled - - var/obj/item/bodypart/affecting - if(ishuman(victim)) - var/mob/living/carbon/human/human_victim = victim - affecting = human_victim.get_bodypart(human_victim.get_random_valid_zone(even_weights = TRUE)) - var/armor = victim.run_armor_check(affecting, MELEE) - - if(prob(MONKEY_SPEC_ATTACK_BITE_MISS_CHANCE)) - victim.visible_message( - span_danger("[user]'s bite misses [victim]!"), - span_danger("You avoid [user]'s bite!"), - span_hear("You hear jaws snapping shut!"), - COMBAT_MESSAGE_RANGE, - user, - ) - to_chat(user, span_danger("Your bite misses [victim]!")) - return TRUE - - var/obj/item/bodypart/head/mouth = user.get_bodypart(BODY_ZONE_HEAD) - if(!mouth) // check for them having a head, ala HARS - return TRUE - - var/damage_roll = rand(mouth.unarmed_damage_low, mouth.unarmed_damage_high) - victim.apply_damage(damage_roll, BRUTE, affecting, armor) - - victim.visible_message( - span_danger("[name] bites [victim]!"), - span_userdanger("[name] bites you!"), - span_hear("You hear a chomp!"), - COMBAT_MESSAGE_RANGE, - name, - ) - to_chat(user, span_danger("You bite [victim]!")) - - if(armor >= 2) // if they have basic armor on the limb we bit, don't spread diseases - return TRUE - for(var/datum/disease/bite_infection as anything in user.diseases) - if(bite_infection.spread_flags & (DISEASE_SPREAD_SPECIAL | DISEASE_SPREAD_NON_CONTAGIOUS)) - continue // ignore diseases that have special spread logic, or are not contagious - victim.ForceContractDisease(bite_infection) - - return TRUE + C.RemoveElement(/datum/element/human_biter) /datum/species/monkey/check_roundstart_eligible() if(check_holidays(MONKEYDAY)) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index f31fd60b131..cfc2208a1bc 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -309,10 +309,6 @@ return martial_result /mob/living/attack_paw(mob/living/carbon/human/user, list/modifiers) - if(isturf(loc) && istype(loc.loc, /area/misc/start)) - to_chat(user, "No attacking people at spawn, you jackass.") - return FALSE - var/martial_result = user.apply_martial_art(src, modifiers) if (martial_result != MARTIAL_ATTACK_INVALID) return martial_result @@ -327,6 +323,8 @@ to_chat(user, span_warning("You don't want to hurt anyone!")) return FALSE + if(!user.get_bodypart(BODY_ZONE_HEAD)) + return FALSE if(user.is_muzzled() || user.is_mouth_covered(ITEM_SLOT_MASK)) to_chat(user, span_warning("You can't bite with your mouth covered!")) return FALSE diff --git a/code/modules/mod/modules/modules_ninja.dm b/code/modules/mod/modules/modules_ninja.dm index 7a38238594d..31db6017609 100644 --- a/code/modules/mod/modules/modules_ninja.dm +++ b/code/modules/mod/modules/modules_ninja.dm @@ -24,7 +24,7 @@ return if(bumpoff) RegisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP, PROC_REF(unstealth)) - RegisterSignal(mod.wearer, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, PROC_REF(on_unarmed_attack)) + RegisterSignal(mod.wearer, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack)) RegisterSignal(mod.wearer, COMSIG_ATOM_BULLET_ACT, PROC_REF(on_bullet_act)) RegisterSignals(mod.wearer, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED), PROC_REF(unstealth)) animate(mod.wearer, alpha = stealth_alpha, time = 1.5 SECONDS) @@ -36,7 +36,7 @@ return if(bumpoff) UnregisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP) - UnregisterSignal(mod.wearer, list(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ITEM_ATTACK, COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_BULLET_ACT, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED)) + UnregisterSignal(mod.wearer, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_MOB_ITEM_ATTACK, COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_BULLET_ACT, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED)) animate(mod.wearer, alpha = 255, time = 1.5 SECONDS) /obj/item/mod/module/stealth/proc/unstealth(datum/source) @@ -143,10 +143,10 @@ var/door_hack_counter = 0 /obj/item/mod/module/hacker/on_suit_activation() - RegisterSignal(mod.wearer, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(hack)) + RegisterSignal(mod.wearer, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(hack)) /obj/item/mod/module/hacker/on_suit_deactivation(deleting = FALSE) - UnregisterSignal(mod.wearer, COMSIG_HUMAN_EARLY_UNARMED_ATTACK) + UnregisterSignal(mod.wearer, COMSIG_LIVING_UNARMED_ATTACK) /obj/item/mod/module/hacker/proc/hack(mob/living/carbon/human/source, atom/target, proximity, modifiers) SIGNAL_HANDLER diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index c3924163784..fc3c259fa92 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -113,6 +113,8 @@ var/datum/worn_feature_offset/worn_glove_offset /// Datum describing how to offset things held in the hands of this arm, the x offset IS functional here var/datum/worn_feature_offset/held_hand_offset + /// The noun to use when referring to this arm's appendage, e.g. "hand" or "paw" + var/appendage_noun = "hand" biological_state = BIO_STANDARD_JOINTED @@ -211,6 +213,7 @@ unarmed_damage_low = 1 /// monkey punches must be really weak, considering they bite people instead and their bites are weak as hell. unarmed_damage_high = 2 unarmed_stun_threshold = 3 + appendage_noun = "paw" /obj/item/bodypart/arm/left/alien icon = 'icons/mob/human/species/alien/bodyparts.dmi' @@ -224,6 +227,7 @@ can_be_disabled = FALSE max_damage = 100 should_draw_greyscale = FALSE + appendage_noun = "scythe-like hand" /obj/item/bodypart/arm/right @@ -314,6 +318,7 @@ unarmed_damage_low = 1 unarmed_damage_high = 2 unarmed_stun_threshold = 3 + appendage_noun = "paw" /obj/item/bodypart/arm/right/alien icon = 'icons/mob/human/species/alien/bodyparts.dmi' @@ -327,6 +332,7 @@ can_be_disabled = FALSE max_damage = 100 should_draw_greyscale = FALSE + appendage_noun = "scythe-like hand" /// Parent Type for legs, should not appear in game. /obj/item/bodypart/leg diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm b/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm index 86cdf855134..142cf8d5143 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm @@ -381,11 +381,11 @@ /obj/item/organ/internal/cyberimp/arm/muscle/Insert(mob/living/carbon/reciever, special = FALSE, drop_if_replaced = TRUE) . = ..() if(ishuman(reciever)) //Sorry, only humans - RegisterSignal(reciever, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(on_attack_hand)) + RegisterSignal(reciever, COMSIG_LIVING_EARLY_UNARMED_ATTACK, PROC_REF(on_attack_hand)) /obj/item/organ/internal/cyberimp/arm/muscle/Remove(mob/living/carbon/implant_owner, special = 0) . = ..() - UnregisterSignal(implant_owner, COMSIG_HUMAN_EARLY_UNARMED_ATTACK) + UnregisterSignal(implant_owner, COMSIG_LIVING_EARLY_UNARMED_ATTACK) /obj/item/organ/internal/cyberimp/arm/muscle/emp_act(severity) . = ..() @@ -402,15 +402,17 @@ /obj/item/organ/internal/cyberimp/arm/muscle/proc/on_attack_hand(mob/living/carbon/human/source, atom/target, proximity, modifiers) SIGNAL_HANDLER - if(source.get_active_hand() != source.get_bodypart(check_zone(zone)) || !proximity) - return + if(source.get_active_hand() != hand || !proximity) + return NONE if(!source.combat_mode || LAZYACCESS(modifiers, RIGHT_CLICK)) - return + return NONE if(!isliving(target)) - return + return NONE var/datum/dna/dna = source.has_dna() if(dna?.check_mutation(/datum/mutation/human/hulk)) //NO HULK - return + return NONE + if(!source.can_unarmed_attack()) + return COMPONENT_CANCEL_ATTACK_CHAIN var/mob/living/living_target = target source.changeNext_move(CLICK_CD_MELEE) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index c6fdecbd29b..3f877d637aa 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -149,6 +149,7 @@ #include "heretic_rituals.dm" #include "high_five.dm" #include "holidays.dm" +#include "hulk.dm" #include "human_through_recycler.dm" #include "hunger_curse.dm" #include "hydroponics_extractor_storage.dm" diff --git a/code/modules/unit_tests/hulk.dm b/code/modules/unit_tests/hulk.dm new file mode 100644 index 00000000000..52706e9ac73 --- /dev/null +++ b/code/modules/unit_tests/hulk.dm @@ -0,0 +1,44 @@ +/// Tests hulk attacking over normal attacking +/datum/unit_test/hulk_attack + var/hulk_hits = 0 + var/hand_hits = 0 + +/datum/unit_test/hulk_attack/Run() + var/mob/living/carbon/human/hulk = allocate(/mob/living/carbon/human/consistent) + var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent) + + + RegisterSignal(dummy, COMSIG_ATOM_HULK_ATTACK, PROC_REF(hulk_sig_fire)) + RegisterSignal(dummy, COMSIG_ATOM_ATTACK_HAND, PROC_REF(hand_sig_fire)) + + hulk.dna.add_mutation(/datum/mutation/human/hulk) + hulk.set_combat_mode(TRUE) + hulk.ClickOn(dummy) + + TEST_ASSERT_EQUAL(hulk_hits, 1, "Hulk should have hit the dummy once.") + TEST_ASSERT_EQUAL(hand_hits, 0, "Hulk should not have hit the dummy with attack_hand.") + TEST_ASSERT(dummy.getBruteLoss(), "Dummy should have taken brute damage from being hulk punched.") + +/datum/unit_test/hulk_attack/proc/hulk_sig_fire() + SIGNAL_HANDLER + hulk_hits += 1 + +/datum/unit_test/hulk_attack/proc/hand_sig_fire() + SIGNAL_HANDLER + hand_hits += 1 + +/// Tests that hulks aren't given rapid attacks from rapid attack gloves +/datum/unit_test/hulk_north_star + +/datum/unit_test/hulk_north_star/Run() + var/mob/living/carbon/human/hulk = allocate(/mob/living/carbon/human/consistent) + var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent) + var/obj/item/clothing/gloves/rapid/fotns = allocate(/obj/item/clothing/gloves/rapid) + + hulk.equip_to_appropriate_slot(fotns) + hulk.dna.add_mutation(/datum/mutation/human/hulk) + hulk.set_combat_mode(TRUE) + hulk.ClickOn(dummy) + + TEST_ASSERT_NOTEQUAL(hulk.next_move, world.time + CLICK_CD_RAPID, "Hulk should not gain the effects of the Fists of the North Star.") + TEST_ASSERT_EQUAL(hulk.next_move, world.time + CLICK_CD_MELEE, "Hulk click cooldown was a value not expected.") diff --git a/tgstation.dme b/tgstation.dme index 366143b7aa0..640bda8c24c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1326,6 +1326,7 @@ #include "code\datums\elements\haunted.dm" #include "code\datums\elements\high_fiver.dm" #include "code\datums\elements\honkspam.dm" +#include "code\datums\elements\human_biter.dm" #include "code\datums\elements\immerse.dm" #include "code\datums\elements\item_fov.dm" #include "code\datums\elements\item_scaling.dm"