From e0c0c45a35e12e9a903123d4cd368050869795ea Mon Sep 17 00:00:00 2001 From: Cameron Lennox Date: Thu, 27 Feb 2025 05:06:27 -0500 Subject: [PATCH] Moree unarmed fixes (#17192) * Fixes attacking without arms. - Makes it so you can attack without hands - Also removes an unused attack_paw - Makes the attack_hand code less garbage - Fixes grabbing a buckled entity to cause you to be perma-slowed * Fixes your head from bleeding to death with headbutts --- code/__defines/dcs/signals.dm | 2 - code/_onclick/telekinesis.dm | 2 +- code/game/objects/items/weapons/game_kit.dm | 3 - .../living/carbon/human/human_attackhand.dm | 570 +++++++++--------- .../mob/living/carbon/human/human_organs.dm | 2 +- code/modules/power/antimatter/computer.dm | 3 - code/modules/power/pacman2.dm | 3 - 7 files changed, 301 insertions(+), 284 deletions(-) diff --git a/code/__defines/dcs/signals.dm b/code/__defines/dcs/signals.dm index a8004fff4c5..559c528f36f 100644 --- a/code/__defines/dcs/signals.dm +++ b/code/__defines/dcs/signals.dm @@ -174,8 +174,6 @@ ///from base of atom/attack_hand(): (mob/user) #define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand" ///from base of atom/attack_paw(): (mob/user) -#define COMSIG_ATOM_ATTACK_PAW "atom_attack_paw" - #define COMPONENT_NO_ATTACK_HAND (1<<0) //works on all 3. //This signal return value bitflags can be found in __DEFINES/misc.dm ///called for each movable in a turf contents on /turf/zImpact(): (atom/movable/A, levels) diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm index f6946a353dc..4d7a65d81ef 100644 --- a/code/_onclick/telekinesis.dm +++ b/code/_onclick/telekinesis.dm @@ -12,7 +12,7 @@ var/const/tk_maxrange = 15 */ /atom/proc/attack_tk(mob/user) if(user.stat) return - user.UnarmedAttack(src,0) // attack_hand, attack_paw, etc + user.UnarmedAttack(src,0) return /* diff --git a/code/game/objects/items/weapons/game_kit.dm b/code/game/objects/items/weapons/game_kit.dm index 5e5f21fce11..1e038d316bf 100644 --- a/code/game/objects/items/weapons/game_kit.dm +++ b/code/game/objects/items/weapons/game_kit.dm @@ -7,9 +7,6 @@ THAT STUPID GAME KIT src.board_stat = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" src.selected = "CR" -/obj/item/game_kit/attack_paw(mob/user as mob) - return src.attack_hand(user) - /obj/item/game_kit/MouseDrop(mob/user as mob) if (user == usr && !user.restrained() && !user.stat && (user.contents.Find(src) || in_range(src, user))) if (user.hand) diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 6caf37d0e44..65bec440d28 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -2,7 +2,6 @@ var/datum/unarmed_attack/default_attack /mob/living/carbon/human/proc/get_unarmed_attack(var/mob/living/carbon/human/target, var/hit_zone) - // VOREStation Edit - Begin if(nif && nif.flag_check(NIF_C_HARDCLAWS,NIF_FLAGS_COMBAT)){return unarmed_hardclaws} if(src.default_attack && src.default_attack.is_usable(src, target, hit_zone)) if(pulling_punches) @@ -10,7 +9,6 @@ if(soft_type) return soft_type return src.default_attack - // VOREStation Edit - End if(src.gloves) var/obj/item/clothing/gloves/G = src.gloves if(istype(G) && G.special_attack && G.special_attack.is_usable(src, target, hit_zone)) @@ -37,15 +35,15 @@ /mob/living/carbon/human/attack_hand(mob/living/M as mob) var/datum/gender/TT = gender_datums[M.get_visible_gender()] var/mob/living/carbon/human/H = M + var/has_hands = TRUE if(istype(H)) var/obj/item/organ/external/temp = H.organs_by_name["r_hand"] if(H.hand) temp = H.organs_by_name["l_hand"] if(!temp || !temp.is_usable()) - to_chat(H, span_warning("You can't use your hand.")) - return - - for(var/thing in GetViruses()) + //to_chat(H, span_warning("You can't use your hand.")) + has_hands = FALSE + for(var/thing in GetViruses()) //This is intentionally not having a has_hands check. If you are clicking on someone next to them, you're close enough to sneeze/cough on them! var/datum/disease/D = thing if(D.IsSpreadByTouch()) H.ContractDisease(D) @@ -62,7 +60,7 @@ ..() // Should this all be in Touch()? - if(istype(H)) + if(istype(H) && has_hands) if(H.get_accuracy_penalty() && H != src) //Should only trigger if they're not aiming well var/hit_zone = get_zone_with_miss_chance(H.zone_sel.selecting, src, H.get_accuracy_penalty()) if(!hit_zone) @@ -75,283 +73,313 @@ H.do_attack_animation(src) return FALSE - if(istype(M,/mob/living/carbon)) + if(istype(M,/mob/living/carbon) && has_hands) for(var/datum/disease/D in M.GetViruses()) if(D.spread_flags & CONTACT_HANDS) ContractDisease(D) - switch(M.a_intent) + switch(M.a_intent) //VARS: H = The one doing the attack. || M = The mob we are targeting || TT = gender of what we are targeting. if(I_HELP) - - // VOREStation Edit - Begin - if (istype(H) && attempt_to_scoop(H)) - return 0; - // VOREStation Edit - End - if(istype(H) && health < CONFIG_GET(number/health_threshold_crit)) - if(!H.check_has_mouth()) - to_chat(H, span_danger("You don't have a mouth, you cannot perform CPR!")) - return - if(!check_has_mouth()) - to_chat(H, span_danger("They don't have a mouth, you cannot perform CPR!")) - return - if((H.head && (H.head.body_parts_covered & FACE)) || (H.wear_mask && (H.wear_mask.body_parts_covered & FACE))) - to_chat(H, span_notice("Remove your mask!")) - return 0 - if((head && (head.body_parts_covered & FACE)) || (wear_mask && (wear_mask.body_parts_covered & FACE))) - to_chat(H, span_notice("Remove [src]'s mask!")) - return 0 - - if (!cpr_time) - return 0 - - cpr_time = 0 - spawn(30) - cpr_time = 1 - - H.visible_message(span_danger("\The [H] is trying to perform CPR on \the [src]!")) - - if(!do_after(H, 30)) - return - - H.visible_message(span_danger("\The [H] performs CPR on \the [src]!")) - to_chat(H, span_warning("Repeat at least every 7 seconds.")) - - if(istype(H) && health > CONFIG_GET(number/health_threshold_dead)) - adjustOxyLoss(-(min(getOxyLoss(), 5))) - updatehealth() - to_chat(src, span_notice("You feel a breath of fresh air enter your lungs. It feels good.")) - - else if(!(M == src && apply_pressure(M, M.zone_sel.selecting))) - help_shake_act(M) - return TRUE + attack_hand_help_intent(H, M, TT, has_hands) if(I_GRAB) - if(M == src || anchored) - return 0 - for(var/obj/item/grab/G in src.grabbed_by) - if(G.assailant == M) - to_chat(M, span_notice("You already grabbed [src].")) - return - if(w_uniform) - w_uniform.add_fingerprint(M) - - var/obj/item/grab/G = new /obj/item/grab(M, src) - if(buckled) - to_chat(M, span_notice("You cannot grab [src], [TT.he] is buckled in!")) - return - if(!G) //the grab will delete itself in New if affecting is anchored - return - M.put_in_active_hand(G) - G.synch() - LAssailant = M - - H.do_attack_animation(src) - playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - //VORESTATION EDIT - visible_message(span_warning("[M] has grabbed [src] [(M.zone_sel.selecting == BP_L_HAND || M.zone_sel.selecting == BP_R_HAND)? "by [(gender==FEMALE)? "her" : ((gender==MALE)? "his": "their")] hands": "passively"]!")) - //VORESTATION END END - return TRUE + attack_hand_grab_intent(H, M, TT, has_hands) if(I_HURT) - - if(M.zone_sel.selecting == "mouth" && wear_mask && istype(wear_mask, /obj/item/grenade)) - var/obj/item/grenade/G = wear_mask - if(!G.active) - visible_message(span_danger("\The [M] pulls the pin from \the [src]'s [G.name]!")) - G.activate(M) - update_inv_wear_mask() - else - to_chat(M, span_warning("\The [G] is already primed! Run!")) - return - - if(!istype(H)) - attack_generic(H,rand(1,3),"punched") - return - - var/rand_damage = rand(1, 5) - var/block = 0 - var/accurate = 0 - var/hit_zone = H.zone_sel.selecting - var/obj/item/organ/external/affecting = get_organ(hit_zone) - - if(!affecting || affecting.is_stump()) - to_chat(M, span_danger("They are missing that limb!")) - return TRUE - - switch(src.a_intent) - if(I_HELP) - // We didn't see this coming, so we get the full blow - rand_damage = 5 - accurate = 1 - if(I_HURT, I_GRAB) - // We're in a fighting stance, there's a chance we block - if(src.canmove && src!=H && prob(20)) - block = 1 - - if (M.grabbed_by.len) - // Someone got a good grip on them, they won't be able to do much damage - rand_damage = max(1, rand_damage - 2) - - if(src.grabbed_by.len || src.buckled || !src.canmove || src==H) - accurate = 1 // certain circumstances make it impossible for us to evade punches - rand_damage = 5 - - // Process evasion and blocking - var/miss_type = 0 - var/attack_message - if(!accurate) - /* ~Hubblenaut - This place is kind of convoluted and will need some explaining. - ran_zone() will pick out of 11 zones, thus the chance for hitting - our target where we want to hit them is circa 9.1%. - - Now since we want to statistically hit our target organ a bit more - often than other organs, we add a base chance of 20% for hitting it. - - This leaves us with the following chances: - - If aiming for chest: - 27.3% chance you hit your target organ - 70.5% chance you hit a random other organ - 2.2% chance you miss - - If aiming for something else: - 23.2% chance you hit your target organ - 56.8% chance you hit a random other organ - 15.0% chance you miss - - Note: We don't use get_zone_with_miss_chance() here since the chances - were made for projectiles. - TODO: proc for melee combat miss chances depending on organ? - */ - - if(!hit_zone) - attack_message = "[H] attempted to strike [src], but missed!" - miss_type = 1 - - if(prob(80)) - hit_zone = ran_zone(hit_zone, 70) //70% chance to hit what you're aiming at seems fair? - if(prob(15) && hit_zone != BP_TORSO) // Missed! - if(!src.lying) - attack_message = "[H] attempted to strike [src], but missed!" - else - attack_message = "[H] attempted to strike [src], but [TT.he] rolled out of the way!" - src.set_dir(pick(cardinal)) - miss_type = 1 - - if(!miss_type && block) - attack_message = "[H] went for [src]'s [affecting.name] but was blocked!" - miss_type = 2 - - // See what attack they use - var/datum/unarmed_attack/attack = H.get_unarmed_attack(src, hit_zone) - if(!attack) - return FALSE - - if(attack.unarmed_override(H, src, hit_zone)) - return FALSE - - H.do_attack_animation(src) - if(!attack_message) - attack.show_attack(H, src, hit_zone, rand_damage) - else - H.visible_message(span_danger("[attack_message]")) - - playsound(src, ((miss_type) ? (miss_type == 1 ? attack.miss_sound : 'sound/weapons/thudswoosh.ogg') : attack.attack_sound), 25, 1, -1) - - add_attack_logs(H,src,"Melee attacked with fists (miss/block)") - - if(miss_type) - return FALSE - - var/real_damage = rand_damage - var/hit_dam_type = attack.damage_type - real_damage += attack.get_unarmed_damage(H) - if(H.gloves && attack.is_punch) - if(istype(H.gloves, /obj/item/clothing/gloves)) - var/obj/item/clothing/gloves/G = H.gloves - real_damage += G.punch_force - hit_dam_type = G.punch_damtype - else if(istype(H.gloves, /obj/item/clothing/accessory)) - var/obj/item/clothing/accessory/G = H.gloves - real_damage += G.punch_force - hit_dam_type = G.punch_damtype - if(H.pulling_punches && !attack.sharp && !attack.edge) //SO IT IS DECREED: PULLING PUNCHES WILL PREVENT THE ACTUAL DAMAGE FROM RINGS AND KNUCKLES, BUT NOT THE ADDED PAIN, BUT YOU CAN'T "PULL" A KNIFE - hit_dam_type = HALLOSS - real_damage *= damage_multiplier - rand_damage *= damage_multiplier - if(HULK in H.mutations) - real_damage *= 2 // Hulks do twice the damage - rand_damage *= 2 - real_damage = max(1, real_damage) - - var/armour = run_armor_check(hit_zone, "melee") - var/soaked = get_armor_soak(hit_zone, "melee") - // Apply additional unarmed effects. - attack.apply_effects(H, src, armour, rand_damage, hit_zone) - - // Finally, apply damage to target - apply_damage(real_damage, hit_dam_type, hit_zone, armour, soaked, sharp=attack.sharp, edge=attack.edge) + attack_hand_harm_intent(H, M, TT, has_hands) if(I_DISARM) - add_attack_logs(H,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/list/holding = list(get_active_hand() = 40, get_inactive_hand = 20) - - //See if they have any guns that might go off - for(var/obj/item/gun/W in holding) - if(W && prob(holding[W])) - var/list/turfs = list() - for(var/turf/T in view()) - turfs += T - if(turfs.len) - var/turf/target = pick(turfs) - visible_message(span_danger("[src]'s [W] goes off during the struggle!")) - return W.afterattack(target,src) - - if(last_push_time + 30 > world.time) - visible_message(span_warning("[M] has weakly pushed [src]!")) - return - - var/randn = rand(1, 100) - last_push_time = world.time - // We ARE wearing shoes OR - // We as a species CAN be slipped when barefoot - // And also 1 in 4 because rngesus - if((shoes || !(species.flags & NO_SLIP)) && randn <= 25) - var/armor_check = run_armor_check(affecting, "melee") - apply_effect(3, WEAKEN, armor_check) - playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - if(armor_check < 60) - visible_message(span_danger("[M] has pushed [src]!")) - else - visible_message(span_warning("[M] attempted to push [src]!")) - return - - if(randn <= 60) - //See about breaking grips or pulls - if(break_all_grabs(M)) - playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - return - - //Actually disarm them - for(var/obj/item/I in holding) - if(I) - drop_from_inventory(I) - visible_message(span_danger("[M] has disarmed [src]!")) - playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - return - - playsound(src, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - visible_message(span_filter_combat("[span_red(span_bold("[M] attempted to disarm [src]!"))]")) + attack_hand_disarm_intent(H, M, TT, has_hands) return + +/// THE VARIOUS INTENTS. +/// Theses used to be included in the above proc into a MEGA PROC that was over 300 lines long. +/// This condenses them and makes it less of a cluster. + +///Help Intent +/mob/living/carbon/human/proc/attack_hand_help_intent(var/mob/living/carbon/human/H, var/mob/living/M as mob, var/datum/gender/TT, var/has_hands) + PRIVATE_PROC(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + if(!has_hands) //This is here so if you WANT to do special code for 'if we don't have hands, do stuff' it can be done here! + return FALSE + if (istype(H) && attempt_to_scoop(H)) + return FALSE; + if(istype(H) && health < CONFIG_GET(number/health_threshold_crit)) + if(!H.check_has_mouth()) + to_chat(H, span_danger("You don't have a mouth, you cannot perform CPR!")) + return FALSE + if(!check_has_mouth()) + to_chat(H, span_danger("They don't have a mouth, you cannot perform CPR!")) + return FALSE + if((H.head && (H.head.body_parts_covered & FACE)) || (H.wear_mask && (H.wear_mask.body_parts_covered & FACE))) + to_chat(H, span_notice("Remove your mask!")) + return FALSE + if((head && (head.body_parts_covered & FACE)) || (wear_mask && (wear_mask.body_parts_covered & FACE))) + to_chat(H, span_notice("Remove [src]'s mask!")) + return FALSE + + if (!cpr_time) + return FALSE + + cpr_time = 0 + addtimer(VARSET_CALLBACK(src, cpr_time , 1), 3 SECONDS, TIMER_DELETE_ME) + + H.visible_message(span_danger("\The [H] is trying to perform CPR on \the [src]!")) + + if(!do_after(H, 30)) + return FALSE + + H.visible_message(span_danger("\The [H] performs CPR on \the [src]!")) + to_chat(H, span_warning("Repeat at least every 7 seconds.")) + + if(istype(H) && health > CONFIG_GET(number/health_threshold_dead)) + adjustOxyLoss(-(min(getOxyLoss(), 5))) + updatehealth() + to_chat(src, span_notice("You feel a breath of fresh air enter your lungs. It feels good.")) + + else if(!(M == src && apply_pressure(M, M.zone_sel.selecting))) + help_shake_act(M) + return TRUE + +//Disarm Intent +/mob/living/carbon/human/proc/attack_hand_disarm_intent(var/mob/living/carbon/human/H, var/mob/living/M as mob, var/datum/gender/TT, var/has_hands) + PRIVATE_PROC(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + if(!has_hands) //This is here so if you WANT to do special code for 'if we don't have hands, do stuff' it can be done here! + return + + add_attack_logs(H,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/list/holding = list(get_active_hand() = 40, get_inactive_hand = 20) + + //See if they have any guns that might go off + for(var/obj/item/gun/W in holding) + if(W && prob(holding[W])) + var/list/turfs = list() + for(var/turf/T in view()) + turfs += T + if(turfs.len) + var/turf/target = pick(turfs) + visible_message(span_danger("[src]'s [W] goes off during the struggle!")) + return W.afterattack(target,src) + + if(last_push_time + 30 > world.time) + visible_message(span_warning("[M] has weakly pushed [src]!")) + return + + var/randn = rand(1, 100) + last_push_time = world.time + // We ARE wearing shoes OR + // We as a species CAN be slipped when barefoot + // And also 1 in 4 because rngesus + if((shoes || !(species.flags & NO_SLIP)) && randn <= 25) + var/armor_check = run_armor_check(affecting, "melee") + apply_effect(3, WEAKEN, armor_check) + playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + if(armor_check < 60) + visible_message(span_danger("[M] has pushed [src]!")) + else + visible_message(span_warning("[M] attempted to push [src]!")) + return + + if(randn <= 60) + //See about breaking grips or pulls + if(break_all_grabs(M)) + playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return + + //Actually disarm them + for(var/obj/item/I in holding) + if(I) + drop_from_inventory(I) + visible_message(span_danger("[M] has disarmed [src]!")) + playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return + + playsound(src, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + visible_message(span_filter_combat("[span_red(span_bold("[M] attempted to disarm [src]!"))]")) +//Grab Intent +/mob/living/carbon/human/proc/attack_hand_grab_intent(var/mob/living/carbon/human/H, var/mob/living/M as mob, var/datum/gender/TT, var/has_hands) + PRIVATE_PROC(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + if(!has_hands) //This is here so if you WANT to do special code for 'if we don't have hands, do stuff' it can be done here! + return FALSE + if(M == src || anchored) + return FALSE + for(var/obj/item/grab/G in src.grabbed_by) + if(G.assailant == M) + to_chat(M, span_notice("You already grabbed [src].")) + return + if(w_uniform) + w_uniform.add_fingerprint(M) + + if(buckled) + to_chat(M, span_notice("You cannot grab [src], [TT.he] is buckled in!")) + return + var/obj/item/grab/G = new /obj/item/grab(M, src) //If this is put before the buckled check, the user will be perma-slowed due to a grab existing in nullspace. + if(!G) //the grab will delete itself in New if affecting is anchored + return + M.put_in_active_hand(G) + G.synch() + LAssailant = M + + H.do_attack_animation(src) + playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + visible_message(span_warning("[M] has grabbed [src] [(M.zone_sel.selecting == BP_L_HAND || M.zone_sel.selecting == BP_R_HAND)? "by [(gender==FEMALE)? "her" : ((gender==MALE)? "his": "their")] hands": "passively"]!")) +//Harm Intent +/mob/living/carbon/human/proc/attack_hand_harm_intent(var/mob/living/carbon/human/H, var/mob/living/M as mob, var/datum/gender/TT, var/has_hands) + PRIVATE_PROC(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + //As a note: This intentionally doesn't immediately return if has_hands is false. This is because you can attack with kicks/bites! + if(has_hands && M.zone_sel.selecting == "mouth" && wear_mask && istype(wear_mask, /obj/item/grenade)) + var/obj/item/grenade/G = wear_mask + if(!G.active) + visible_message(span_danger("\The [M] pulls the pin from \the [src]'s [G.name]!")) + G.activate(M) + update_inv_wear_mask() + else + to_chat(M, span_warning("\The [G] is already primed! Run!")) + return + + if(has_hands && !istype(H)) + attack_generic(H,rand(1,3),"punched") + return + + var/rand_damage = rand(1, 5) + var/block = 0 + var/accurate = 0 + var/hit_zone = H.zone_sel.selecting + var/obj/item/organ/external/affecting = get_organ(hit_zone) + + if(!affecting || affecting.is_stump()) + to_chat(M, span_danger("They are missing that limb!")) + return FALSE + + switch(a_intent) + if(I_HELP) + // We didn't see this coming, so we get the full blow + rand_damage = 5 + accurate = 1 + if(I_HURT, I_GRAB) + // We're in a fighting stance, there's a chance we block + if(canmove && src!=H && prob(20)) + block = 1 + + if (M.grabbed_by.len) + // Someone got a good grip on them, they won't be able to do much damage + rand_damage = max(1, rand_damage - 2) + + if(src.grabbed_by.len || src.buckled || !src.canmove || src==H) + accurate = 1 // certain circumstances make it impossible for us to evade punches + rand_damage = 5 + + // Process evasion and blocking + var/miss_type = 0 + var/attack_message + if(!accurate) + /* ~Hubblenaut + This place is kind of convoluted and will need some explaining. + ran_zone() will pick out of 11 zones, thus the chance for hitting + our target where we want to hit them is circa 9.1%. + + Now since we want to statistically hit our target organ a bit more + often than other organs, we add a base chance of 20% for hitting it. + + This leaves us with the following chances: + + If aiming for chest: + 27.3% chance you hit your target organ + 70.5% chance you hit a random other organ + 2.2% chance you miss + + If aiming for something else: + 23.2% chance you hit your target organ + 56.8% chance you hit a random other organ + 15.0% chance you miss + + Note: We don't use get_zone_with_miss_chance() here since the chances + were made for projectiles. + TODO: proc for melee combat miss chances depending on organ? + */ + + if(!hit_zone) + attack_message = "[H] attempted to strike [src], but missed!" + miss_type = 1 + + if(prob(80)) + hit_zone = ran_zone(hit_zone, 70) //70% chance to hit what you're aiming at seems fair? + if(prob(15) && hit_zone != BP_TORSO) // Missed! + if(!src.lying) + attack_message = "[H] attempted to strike [src], but missed!" + else + attack_message = "[H] attempted to strike [src], but [TT.he] rolled out of the way!" + src.set_dir(pick(cardinal)) + miss_type = 1 + + if(!miss_type && block) + attack_message = "[H] went for [src]'s [affecting.name] but was blocked!" + miss_type = 2 + + // See what attack they use + var/datum/unarmed_attack/attack = H.get_unarmed_attack(src, hit_zone) + if(!attack) + return FALSE + + if(attack.unarmed_override(H, src, hit_zone)) + return FALSE + + H.do_attack_animation(src) + if(!attack_message) + attack.show_attack(H, src, hit_zone, rand_damage) + else + H.visible_message(span_danger("[attack_message]")) + + playsound(src, ((miss_type) ? (miss_type == 1 ? attack.miss_sound : 'sound/weapons/thudswoosh.ogg') : attack.attack_sound), 25, 1, -1) + + add_attack_logs(H,src,"Melee attacked with fists (miss/block)") + + if(miss_type) + return FALSE + + var/real_damage = rand_damage + var/hit_dam_type = attack.damage_type + real_damage += attack.get_unarmed_damage(H) + if(H.gloves && attack.is_punch) + if(istype(H.gloves, /obj/item/clothing/gloves)) + var/obj/item/clothing/gloves/G = H.gloves + real_damage += G.punch_force + hit_dam_type = G.punch_damtype + else if(istype(H.gloves, /obj/item/clothing/accessory)) + var/obj/item/clothing/accessory/G = H.gloves + real_damage += G.punch_force + hit_dam_type = G.punch_damtype + if(H.pulling_punches && !attack.sharp && !attack.edge) //SO IT IS DECREED: PULLING PUNCHES WILL PREVENT THE ACTUAL DAMAGE FROM RINGS AND KNUCKLES, BUT NOT THE ADDED PAIN, BUT YOU CAN'T "PULL" A KNIFE + hit_dam_type = HALLOSS + real_damage *= damage_multiplier + rand_damage *= damage_multiplier + if(HULK in H.mutations) + real_damage *= 2 // Hulks do twice the damage + rand_damage *= 2 + real_damage = max(1, real_damage) + + var/armour = run_armor_check(hit_zone, "melee") + var/soaked = get_armor_soak(hit_zone, "melee") + // Apply additional unarmed effects. + attack.apply_effects(H, src, armour, rand_damage, hit_zone) + + // Finally, apply damage to target + apply_damage(real_damage, hit_dam_type, hit_zone, armour, soaked, sharp=attack.sharp, edge=attack.edge) + +/// INTENTS END + + /mob/living/carbon/human/proc/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, inrange, params) return diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm index 1b8251985a0..58d44a1aaba 100644 --- a/code/modules/mob/living/carbon/human/human_organs.dm +++ b/code/modules/mob/living/carbon/human/human_organs.dm @@ -51,7 +51,7 @@ //Moving around with fractured ribs won't do you any good if (prob(10) && !stat && can_feel_pain() && chem_effects[CE_PAINKILLER] < 50 && E.is_broken() && E.internal_organs.len) custom_pain("Pain jolts through your broken [E.encased ? E.encased : E.name], staggering you!", 50) - emote("pain") + emote("scream") drop_item(loc) Stun(2) diff --git a/code/modules/power/antimatter/computer.dm b/code/modules/power/antimatter/computer.dm index 1def5b7b32d..c7c1f720f11 100644 --- a/code/modules/power/antimatter/computer.dm +++ b/code/modules/power/antimatter/computer.dm @@ -59,9 +59,6 @@ /obj/machinery/computer/am_engine/attack_ai(var/mob/user as mob) return src.attack_hand(user) -/obj/machinery/computer/am_engine/attack_paw(var/mob/user as mob) - return src.attack_hand(user) - /obj/machinery/computer/am_engine/attack_hand(var/mob/user as mob) if(..()) return diff --git a/code/modules/power/pacman2.dm b/code/modules/power/pacman2.dm index 44d1d768427..e0c09c5cf74 100644 --- a/code/modules/power/pacman2.dm +++ b/code/modules/power/pacman2.dm @@ -104,9 +104,6 @@ attack_ai(mob/user as mob) interact(user) - attack_paw(mob/user as mob) - interact(user) - proc interact(mob/user) if (get_dist(src, user) > 1 )