diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 140e868dddf..7e6f427e069 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -38,6 +38,12 @@
var/datum/disease/D = thing
if(D.IsSpreadByTouch())
ContractDisease(D)
+
+ if(lying && surgeries.len)
+ if(user.a_intent == INTENT_HELP)
+ for(var/datum/surgery/S in surgeries)
+ if(S.next_step(user, user.a_intent))
+ return 1
return 0
/mob/living/carbon/attack_slime(mob/living/carbon/slime/M)
diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm
deleted file mode 100644
index eedc6c1ea0c..00000000000
--- a/code/modules/mob/living/carbon/human/human_attackhand.dm
+++ /dev/null
@@ -1,197 +0,0 @@
-/mob/living/carbon/human/attack_hand(mob/living/carbon/human/M)
- if(frozen)
- to_chat(M, "Do not touch Admin-Frozen people.")
- return
-
- var/mob/living/carbon/human/H = M
- if(istype(H))
- var/obj/item/organ/external/temp = H.bodyparts_by_name["r_hand"]
- if(H.hand)
- temp = H.bodyparts_by_name["l_hand"]
- if(!temp || !temp.is_usable())
- to_chat(H, "You can't use your hand.")
- return
-
- ..()
-
- if((M != src) && M.a_intent != INTENT_HELP && check_shields(0, M.name, attack_type = UNARMED_ATTACK))
- add_attack_logs(M, src, "Melee attacked with fists (miss/block)")
- visible_message("[M] attempted to touch [src]!")
- return 0
-
- var/datum/martial_art/attacker_style = M.martial_art
-
- species.handle_attack_hand(src, M)
-
- switch(M.a_intent)
- if(INTENT_HELP)
- if(attacker_style && attacker_style.help_act(H, src))//adminfu only...
- return 1
- if(can_operate(src))
- if(health >= config.health_threshold_crit)
- if(src.surgeries.len)
- for(var/datum/surgery/S in src.surgeries)
- if(S.next_step(M, src))
- return 1
- help_shake_act(M)
- add_attack_logs(M, src, "Shaked")
- return 1
- if(health >= config.health_threshold_crit)
- help_shake_act(M)
- add_attack_logs(M, src, "Shaked")
- return 1
- if(!H.check_has_mouth())
- to_chat(H, "You don't have a mouth, you cannot perform CPR!")
- return
- if(!check_has_mouth())
- to_chat(H, "They don't have a mouth, you cannot perform CPR!")
- return
- if((M.head && (M.head.flags_cover & HEADCOVERSMOUTH)) || (M.wear_mask && (M.wear_mask.flags_cover & MASKCOVERSMOUTH) && !M.wear_mask.mask_adjusted))
- to_chat(M, "Remove your mask!")
- return 0
- if((head && (head.flags_cover & HEADCOVERSMOUTH)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && !wear_mask.mask_adjusted))
- to_chat(M, "Remove his mask!")
- return 0
-
- M.visible_message("\The [M] is trying to perform CPR on \the [src]!", \
- "You try to perform CPR on \the [src]!")
- if(do_mob(M, src, 40))
- if(health > config.health_threshold_dead && health <= config.health_threshold_crit)
- var/suff = min(getOxyLoss(), 7)
- adjustOxyLoss(-suff)
- updatehealth()
- M.visible_message("\The [M] performs CPR on \the [src]!", \
- "You perform CPR on \the [src].")
-
- to_chat(src, "You feel a breath of fresh air enter your lungs. It feels good.")
- to_chat(M, "Repeat at least every 7 seconds.")
- add_attack_logs(M, src, "CPRed", FALSE)
- return 1
- else
- to_chat(M, "You need to stay still while performing CPR!")
-
- if(INTENT_GRAB)
- if(attacker_style && attacker_style.grab_act(H, src))
- return 1
- else
- grabbedby(M)
- return 1
-
- if(INTENT_HARM)
- //Vampire code
- if(M.mind && M.mind.vampire && (M.mind in ticker.mode.vampires) && !M.mind.vampire.draining && M.zone_sel && M.zone_sel.selecting == "head" && src != M)
- if((NO_BLOOD in species.species_traits) || species.exotic_blood || !blood_volume)
- to_chat(M, "They have no blood!")
- return
- if(mind && mind.vampire && (mind in ticker.mode.vampires))
- to_chat(M, "Your fangs fail to pierce [name]'s cold flesh")
- return
- if(SKELETON in mutations)
- to_chat(M, "There is no blood in a skeleton!")
- return
- if(issmall(src) && !ckey) //Monkeyized humans are okay, humanized monkeys are okay, NPC monkeys are not.
- to_chat(M, "Blood from a monkey is useless!")
- return
- //we're good to suck the blood, blaah
- M.mind.vampire.handle_bloodsucking(src)
- add_attack_logs(M, src, "vampirebit")
- return
- //end vampire codes
- if(attacker_style && attacker_style.harm_act(H, src))
- return 1
- else
- var/datum/unarmed_attack/attack = M.species.unarmed
-
- M.do_attack_animation(src)
- add_attack_logs(M, src, "Melee attacked with fists")
-
- if(!iscarbon(M))
- LAssailant = null
- else
- LAssailant = M
-
- var/damage = rand(M.species.punchdamagelow, M.species.punchdamagehigh)
- damage += attack.damage
- if(!damage)
- playsound(loc, attack.miss_sound, 25, 1, -1)
- visible_message("[M] tried to [pick(attack.attack_verb)] [src]!")
- return 0
-
-
- var/obj/item/organ/external/affecting = get_organ(ran_zone(M.zone_sel.selecting))
- var/armor_block = run_armor_check(affecting, "melee")
-
- if(HULK in M.mutations)
- adjustBruteLoss(15)
-
- playsound(loc, attack.attack_sound, 25, 1, -1)
-
- visible_message("[M] [pick(attack.attack_verb)]ed [src]!")
-
- apply_damage(damage, BRUTE, affecting, armor_block, sharp = attack.sharp) //moving this back here means Armalis are going to knock you down 70% of the time, but they're pure adminbus anyway.
- if((stat != DEAD) && damage >= M.species.punchstunthreshold)
- visible_message("[M] has weakened [src]!", \
- "[M] has weakened [src]!")
- apply_effect(4, WEAKEN, armor_block)
- forcesay(hit_appends)
- else if(lying)
- forcesay(hit_appends)
-
-
- if(INTENT_DISARM)
- if(attacker_style && attacker_style.disarm_act(H, src))
- return 1
- else
- add_attack_logs(M, src, "Disarmed")
- M.do_attack_animation(src)
- if(w_uniform)
- w_uniform.add_fingerprint(M)
- var/obj/item/organ/external/affecting = get_organ(ran_zone(M.zone_sel.selecting))
- var/randn = rand(1, 100)
- if(randn <= 25)
- apply_effect(2, WEAKEN, run_armor_check(affecting, "melee"))
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- visible_message("[M] has pushed [src]!")
- add_attack_logs(M, src, "Pushed over")
- if(!iscarbon(M))
- LAssailant = null
- else
- LAssailant = M
- return
-
- var/talked = 0 // BubbleWrap
-
- if(randn <= 60)
- //BubbleWrap: Disarming breaks a pull
- if(pulling)
- visible_message("[M] has broken [src]'s grip on [pulling]!")
- talked = 1
- stop_pulling()
-
- //BubbleWrap: Disarming also breaks a grab - this will also stop someone being choked, won't it?
- if(istype(l_hand, /obj/item/grab))
- var/obj/item/grab/lgrab = l_hand
- if(lgrab.affecting)
- visible_message("[M] has broken [src]'s grip on [lgrab.affecting]!")
- talked = 1
- spawn(1)
- qdel(lgrab)
- if(istype(r_hand, /obj/item/grab))
- var/obj/item/grab/rgrab = r_hand
- if(rgrab.affecting)
- visible_message("[M] has broken [src]'s grip on [rgrab.affecting]!")
- talked = 1
- spawn(1)
- qdel(rgrab)
- //End BubbleWrap
-
- if(!talked) //BubbleWrap
- if(drop_item())
- visible_message("[M] has disarmed [src]!")
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- return
-
-
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- visible_message("[M] attempted to disarm [src]!")
- return
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 1d4dc544667..d6545d9bff6 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -348,6 +348,13 @@ emp_act
if(penetrated_dam) SS.create_breaches(damtype, penetrated_dam)
+/mob/living/carbon/human/attack_hand(mob/user)
+ if(..()) //to allow surgery to return properly.
+ return
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ species.spec_attack_hand(H, src)
+
/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L)
if(..()) //successful larva bite.
var/damage = rand(1, 3)
diff --git a/code/modules/mob/living/carbon/human/species/apollo.dm b/code/modules/mob/living/carbon/human/species/apollo.dm
index f1ca3294017..0b38b57c786 100644
--- a/code/modules/mob/living/carbon/human/species/apollo.dm
+++ b/code/modules/mob/living/carbon/human/species/apollo.dm
@@ -56,30 +56,29 @@
to_chat(C, "Your antennae tingle as you are overcome with pain...")
to_chat(C, "It feels like part of you has died.")
-/datum/species/wryn/handle_attack_hand(var/mob/living/carbon/human/H, var/mob/living/carbon/human/M)
- var/obj/item/organ/external/head/head_organ = H.get_organ("head")
- if(M.a_intent == INTENT_HARM)
- if(H.handcuffed)
- if(!H.get_int_organ(/obj/item/organ/internal/wryn/hivenode)) return
- var/turf/p_loc = M.loc
- var/turf/p_loc_m = H.loc
+/datum/species/wryn/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
+ if(target.handcuffed)
+ if(!target.get_int_organ(/obj/item/organ/internal/wryn/hivenode))
+ return
- M.visible_message("[M] begins to violently pull off [H]'s antennae.")
- to_chat(H, "[M] grips your antennae and starts violently pulling!")
- if(do_after(H, 250, target = src))
- if(p_loc == M.loc && p_loc_m == H.loc)
- var/obj/item/organ/internal/wryn/hivenode/node = new /obj/item/organ/internal/wryn/hivenode
- H.remove_language("Wryn Hivemind")
- node.remove(H)
- node.loc = M.loc
- to_chat(M, "You hear a loud crunch as you mercilessly pull off [H]'s antennae.")
- to_chat(H, "You hear a loud crunch as your antennae is ripped off your head by [M].")
- to_chat(H, "It's so quiet...")
- head_organ.h_style = "Bald"
- H.update_hair()
+ user.visible_message("[user] begins to violently pull off [target]'s antennae.")
+ to_chat(target, "[user] grips your antennae and starts violently pulling!")
+ if(do_mob(user, target, 250))
+ var/obj/item/organ/internal/wryn/hivenode/node = new /obj/item/organ/internal/wryn/hivenode
+ target.remove_language("Wryn Hivemind")
+ node.remove(target)
+ node.forceMove(user.loc)
+ to_chat(user, "You hear a loud crunch as you mercilessly pull off [target]'s antennae.")
+ to_chat(target, "You hear a loud crunch as your antennae is ripped off your head by [user].")
+ to_chat(target, "It's so quiet...")
+ var/obj/item/organ/external/head/head_organ = target.get_organ("head")
+ head_organ.h_style = "Bald"
+ target.update_hair()
- add_attack_logs(M, H, "Antennae removed")
- return 0
+ add_attack_logs(user, target, "Antennae removed")
+ return 0
+ else
+ ..()
/datum/species/nucleation
name = "Nucleation"
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index 901d221a8b3..8bc5ccfd6b4 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -315,8 +315,199 @@
/datum/species/proc/handle_death(var/mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns).
return
-/datum/species/proc/handle_attack_hand(var/mob/living/carbon/human/H, var/mob/living/carbon/human/M) //Handles any species-specific attackhand events.
- return
+/datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
+ if(attacker_style && attacker_style.help_act(user, target))//adminfu only...
+ return 1
+ if(target.health >= config.health_threshold_crit)
+ target.help_shake_act(user)
+ add_attack_logs(user, target, "Shaked")
+ return 1
+ if(!user.check_has_mouth())
+ to_chat(user, "You don't have a mouth, you cannot perform CPR!")
+ return
+ if(!target.check_has_mouth())
+ to_chat(user, "They don't have a mouth, you cannot perform CPR!")
+ return
+ if((user.head && (user.head.flags_cover & HEADCOVERSMOUTH)) || (user.wear_mask && (user.wear_mask.flags_cover & MASKCOVERSMOUTH) && !user.wear_mask.mask_adjusted))
+ to_chat(user, "Remove your mask!")
+ return 0
+ if((target.head && (target.head.flags_cover & HEADCOVERSMOUTH)) || (target.wear_mask && (target.wear_mask.flags_cover & MASKCOVERSMOUTH) && !target.wear_mask.mask_adjusted))
+ to_chat(user, "Remove his mask!")
+ return 0
+
+ user.visible_message("\The [user] is trying to perform CPR on \the [target]!", \
+ "You try to perform CPR on \the [target]!")
+ if(do_mob(user, target, 40))
+ if(target.health > config.health_threshold_dead && target.health <= config.health_threshold_crit)
+ var/suff = min(target.getOxyLoss(), 7)
+ target.adjustOxyLoss(-suff)
+ target.updatehealth()
+ user.visible_message("\The [user] performs CPR on \the [target]!", \
+ "You perform CPR on \the [target].")
+
+ to_chat(target, "You feel a breath of fresh air enter your lungs. It feels good.")
+ to_chat(user, "Repeat at least every 7 seconds.")
+ add_attack_logs(user, target, "CPRed", FALSE)
+ return 1
+ else
+ to_chat(user, "You need to stay still while performing CPR!")
+
+/datum/species/proc/grab(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
+ if(attacker_style && attacker_style.grab_act(user, target))
+ return 1
+ else
+ target.grabbedby(user)
+ return 1
+
+/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
+ //Vampire code
+ if(user.mind && user.mind.vampire && (user.mind in ticker.mode.vampires) && !user.mind.vampire.draining && user.zone_sel && user.zone_sel.selecting == "head" && target != user)
+ if((NO_BLOOD in target.species.species_traits) || target.species.exotic_blood || !target.blood_volume)
+ to_chat(user, "They have no blood!")
+ return
+ if(target.mind && target.mind.vampire && (target.mind in ticker.mode.vampires))
+ to_chat(user, "Your fangs fail to pierce [target.name]'s cold flesh")
+ return
+ if(SKELETON in target.mutations)
+ to_chat(user, "There is no blood in a skeleton!")
+ return
+ if(issmall(target) && !target.ckey) //Monkeyized humans are okay, humanized monkeys are okay, NPC monkeys are not.
+ to_chat(user, "Blood from a monkey is useless!")
+ return
+ //we're good to suck the blood, blaah
+ user.mind.vampire.handle_bloodsucking(target)
+ add_attack_logs(user, target, "vampirebit")
+ return
+ //end vampire codes
+ if(attacker_style && attacker_style.harm_act(user, target))
+ return 1
+ else
+ var/datum/unarmed_attack/attack = user.species.unarmed
+
+ user.do_attack_animation(target)
+ add_attack_logs(user, target, "Melee attacked with fists")
+
+ if(!iscarbon(user))
+ target.LAssailant = null
+ else
+ target.LAssailant = user
+
+ var/damage = rand(user.species.punchdamagelow, user.species.punchdamagehigh)
+ damage += attack.damage
+ if(!damage)
+ playsound(target.loc, attack.miss_sound, 25, 1, -1)
+ target.visible_message("[user] tried to [pick(attack.attack_verb)] [target]!")
+ return 0
+
+
+ var/obj/item/organ/external/affecting = target.get_organ(ran_zone(user.zone_sel.selecting))
+ var/armor_block = target.run_armor_check(affecting, "melee")
+
+ if(HULK in user.mutations)
+ target.adjustBruteLoss(15)
+
+ playsound(target.loc, attack.attack_sound, 25, 1, -1)
+
+ target.visible_message("[user] [pick(attack.attack_verb)]ed [target]!")
+
+ target.apply_damage(damage, BRUTE, affecting, armor_block, sharp = attack.sharp) //moving this back here means Armalis are going to knock you down 70% of the time, but they're pure adminbus anyway.
+ if((target.stat != DEAD) && damage >= user.species.punchstunthreshold)
+ target.visible_message("[user] has weakened [target]!", \
+ "[user] has weakened [target]!")
+ target.apply_effect(4, WEAKEN, armor_block)
+ target.forcesay(hit_appends)
+ else if(target.lying)
+ target.forcesay(hit_appends)
+
+/datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
+ if(attacker_style && attacker_style.disarm_act(user, target))
+ return 1
+ else
+ add_attack_logs(user, target, "Disarmed")
+ user.do_attack_animation(target)
+ if(target.w_uniform)
+ target.w_uniform.add_fingerprint(user)
+ var/obj/item/organ/external/affecting = target.get_organ(ran_zone(user.zone_sel.selecting))
+ var/randn = rand(1, 100)
+ if(randn <= 25)
+ target.apply_effect(2, WEAKEN, target.run_armor_check(affecting, "melee"))
+ playsound(target.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ target.visible_message("[user] has pushed [target]!")
+ add_attack_logs(user, target, "Pushed over")
+ if(!iscarbon(user))
+ target.LAssailant = null
+ else
+ target.LAssailant = user
+ return
+
+ var/talked = 0 // BubbleWrap
+
+ if(randn <= 60)
+ //BubbleWrap: Disarming breaks a pull
+ if(target.pulling)
+ target.visible_message("[user] has broken [target]'s grip on [target.pulling]!")
+ talked = 1
+ target.stop_pulling()
+
+ //BubbleWrap: Disarming also breaks a grab - this will also stop someone being choked, won't it?
+ if(istype(target.l_hand, /obj/item/weapon/grab))
+ var/obj/item/weapon/grab/lgrab = target.l_hand
+ if(lgrab.affecting)
+ target.visible_message("[user] has broken [target]'s grip on [lgrab.affecting]!")
+ talked = 1
+ spawn(1)
+ qdel(lgrab)
+ if(istype(target.r_hand, /obj/item/weapon/grab))
+ var/obj/item/weapon/grab/rgrab = target.r_hand
+ if(rgrab.affecting)
+ target.visible_message("[user] has broken [target]'s grip on [rgrab.affecting]!")
+ talked = 1
+ spawn(1)
+ qdel(rgrab)
+ //End BubbleWrap
+
+ if(!talked) //BubbleWrap
+ if(target.drop_item())
+ target.visible_message("[user] has disarmed [target]!")
+ playsound(target.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ return
+
+
+ playsound(target.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ target.visible_message("[user] attempted to disarm [target]!")
+
+/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style = M.martial_art) //Handles any species-specific attackhand events.
+ if(!istype(M))
+ return
+ if(H.frozen)
+ to_chat(M, "Do not touch Admin-Frozen people.")
+ return
+
+ if(istype(M))
+ var/obj/item/organ/external/temp = M.bodyparts_by_name["r_hand"]
+ if(M.hand)
+ temp = M.bodyparts_by_name["l_hand"]
+ if(!temp || !temp.is_usable())
+ to_chat(M, "You can't use your hand.")
+ return
+
+ if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(0, M.name, attack_type = UNARMED_ATTACK))
+ add_attack_logs(M, H, "Melee attacked with fists (miss/block)")
+ H.visible_message("[M] attempted to touch [H]!")
+ return 0
+
+ switch(M.a_intent)
+ if(INTENT_HELP)
+ help(M, H, attacker_style)
+
+ if(INTENT_GRAB)
+ grab(M, H, attacker_style)
+
+ if(INTENT_HARM)
+ harm(M, H, attacker_style)
+
+ if(INTENT_DISARM)
+ disarm(M, H, attacker_style)
/datum/species/proc/say_filter(mob/M, message, datum/language/speaking)
return message
diff --git a/paradise.dme b/paradise.dme
index 1d329f9aec5..716baebdf05 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1622,7 +1622,6 @@
#include "code\modules\mob\living\carbon\human\emote.dm"
#include "code\modules\mob\living\carbon\human\examine.dm"
#include "code\modules\mob\living\carbon\human\human.dm"
-#include "code\modules\mob\living\carbon\human\human_attackhand.dm"
#include "code\modules\mob\living\carbon\human\human_damage.dm"
#include "code\modules\mob\living\carbon\human\human_defense.dm"
#include "code\modules\mob\living\carbon\human\human_defines.dm"