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

🆑 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
/🆑

---------

Co-authored-by: san7890 <the@san7890.com>
This commit is contained in:
MrMelbert
2023-10-15 22:25:19 -06:00
committed by GitHub
co-authored by san7890
parent 75da480997
commit 9664d24c13
41 changed files with 280 additions and 214 deletions
@@ -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)
@@ -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"
@@ -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)
+4 -1
View File
@@ -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
+51 -31
View File
@@ -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.
+4 -4
View File
@@ -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)
+2 -2
View File
@@ -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)
+1 -2
View File
@@ -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,
+2 -2
View File
@@ -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)
+4 -3
View File
@@ -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)
+2 -2
View File
@@ -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)
+2 -3
View File
@@ -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
+1 -3
View File
@@ -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
+2 -2
View File
@@ -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)
+4 -4
View File
@@ -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
+10 -4
View File
@@ -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)
+3 -1
View File
@@ -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
+6 -6
View File
@@ -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!")
+28
View File
@@ -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
+7 -6
View File
@@ -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
+3 -3
View File
@@ -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!")
+7 -7
View File
@@ -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)
+3 -3
View File
@@ -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
+2 -2
View File
@@ -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))
+15 -14
View File
@@ -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)
+5 -4
View File
@@ -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)
+17 -2
View File
@@ -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)
. = ..()
@@ -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)
@@ -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
+5 -5
View File
@@ -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)
+5 -3
View File
@@ -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
@@ -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
@@ -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()
@@ -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))
+2 -4
View File
@@ -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
+4 -4
View File
@@ -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
+6
View File
@@ -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
@@ -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)
+1
View File
@@ -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"
+44
View File
@@ -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.")
+1
View File
@@ -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"