diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index e36d5c027f5..2df699b92ed 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -34,8 +34,6 @@ SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, M, user) if(flags & (NOBLUDGEON)) return 0 - if(check_martial_counter(M, user)) - return 0 if(can_operate(M)) //Checks if mob is lying down on table for surgery if(istype(src,/obj/item/robot_parts))//popup override for direct attach if(!attempt_initiate_surgery(src, M, user,1)) diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 8e69face174..b8b38b0fb5a 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -769,7 +769,9 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A manual that teaches a single user tactical Close-Quarters Combat before self-destructing. Does not restrict weapon usage, but cannot be used alongside Gloves of the North Star." reference = "CQC" item = /obj/item/CQC_manual - cost = 9 + gamemodes = list(/datum/game_mode/nuclear) + cost = 13 + surplus = 0 /datum/uplink_item/stealthy_weapons/throwingweapons name = "Box of Throwing Weapons" diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index f8798d77c5d..55c87c59bf1 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -562,11 +562,4 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d return TRUE /obj/item/attack_hulk(mob/living/carbon/human/user) - return FALSE - -/obj/item/proc/check_martial_counter(mob/living/carbon/human/target, mob/living/carbon/human/user) //handles block for CQC - if(target.check_block()) - target.visible_message("[target.name] blocks [src] and twists [user]'s arm behind [user.p_their()] back!", - "You block the attack!") - user.Stun(2) - return TRUE \ No newline at end of file + return FALSE \ No newline at end of file diff --git a/code/game/objects/items/weapons/melee/misc.dm b/code/game/objects/items/weapons/melee/misc.dm index a19df11e790..38a38c45edb 100644 --- a/code/game/objects/items/weapons/melee/misc.dm +++ b/code/game/objects/items/weapons/melee/misc.dm @@ -1,6 +1,13 @@ /obj/item/melee needs_permit = 1 +/obj/item/melee/proc/check_martial_counter(mob/living/carbon/human/target, mob/living/carbon/human/user) + if(target.check_block()) + target.visible_message("[target.name] blocks [src] and twists [user]'s arm behind [user.p_their()] back!", + "You block the attack!") + user.Stun(2) + return TRUE + /obj/item/melee/chainofcommand name = "chain of command" desc = "A tool used by great men to placate the frothing masses." diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index f16ca21682f..f27770e8bbc 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -141,6 +141,12 @@ if(isrobot(M)) ..() return + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(check_martial_counter(H, user)) + return + if(!isliving(M)) return @@ -166,8 +172,6 @@ if(ishuman(L)) var/mob/living/carbon/human/H = L - if(check_martial_counter(L, user)) - return if(H.check_shields(0, "[user]'s [name]", src, MELEE_ATTACK)) //No message; check_shields() handles that playsound(L, 'sound/weapons/Genhit.ogg', 50, 1) return diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm index 3fc4b4b7717..d0526ebbcb8 100644 --- a/code/game/objects/items/weapons/swords_axes_etc.dm +++ b/code/game/objects/items/weapons/swords_axes_etc.dm @@ -52,7 +52,9 @@ if(ishuman(target)) var/mob/living/carbon/human/H = target if(H.check_shields(0, "[user]'s [name]", src, MELEE_ATTACK)) - return 0 + return + if(check_martial_counter(H, user)) + return playsound(get_turf(src), 'sound/effects/woodhit.ogg', 75, 1, -1) target.Weaken(3) add_attack_logs(user, target, "Stunned with [src]") diff --git a/code/modules/martial_arts/cqc.dm b/code/modules/martial_arts/cqc.dm index 54f9ac97cd9..bf3c566f2a6 100644 --- a/code/modules/martial_arts/cqc.dm +++ b/code/modules/martial_arts/cqc.dm @@ -1,4 +1,4 @@ -#define SLAM_COMBO "HG" +#define SLAM_COMBO "GH" #define KICK_COMBO "HH" #define RESTRAIN_COMBO "GG" #define PRESSURE_COMBO "DG" @@ -8,15 +8,24 @@ name = "CQC" help_verb = /mob/living/carbon/human/proc/CQC_help block_chance = 75 + var/just_a_cook = FALSE + var/static/list/areas_under_siege = typecacheof(list(/area/crew_quarters/kitchen, + /area/crew_quarters/cafeteria, + /area/crew_quarters/bar)) -/datum/martial_art/cqc/can_use(mob/living/carbon/human/H) - if(istype(H.gloves, /obj/item/clothing/gloves/fingerless/rapid)) - return FALSE - return ..() +/datum/martial_art/cqc/under_siege + name = "Close Quarters Cooking" + just_a_cook = TRUE /datum/martial_art/cqc/proc/drop_restraining() restraining = FALSE +/datum/martial_art/cqc/can_use(mob/living/carbon/human/H) + var/area/A = get_area(H) + if(just_a_cook && !(is_type_in_typecache(A, areas_under_siege))) + return FALSE + return ..() + /datum/martial_art/cqc/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D) if(!can_use(A)) return FALSE @@ -44,17 +53,13 @@ /datum/martial_art/cqc/proc/Slam(mob/living/carbon/human/A, mob/living/carbon/human/D) if(!can_use(A)) return FALSE - if(!D.stat || !D.weakened) + if(!D.weakened || !D.resting || !D.lying) D.visible_message("[A] slams [D] into the ground!", \ "[A] slams you into the ground!") playsound(get_turf(A), 'sound/weapons/slam.ogg', 50, 1, -1) D.apply_damage(10, BRUTE) D.Weaken(6) add_attack_logs(A, D, "Melee attacked with martial-art [src] : Slam", ATKLOG_ALL) - else //if target can't be slammed, do a regular grab attack then clear the streak - streak = "" - grab_act(A, D) - streak = "" return TRUE /datum/martial_art/cqc/proc/Kick(mob/living/carbon/human/A, mob/living/carbon/human/D) @@ -68,17 +73,13 @@ D.throw_at(throw_target, 1, 14, A) D.apply_damage(10, BRUTE) add_attack_logs(A, D, "Melee attacked with martial-art [src] : Kick", ATKLOG_ALL) - if(D.weakened && !D.stat) - D.visible_message("[A] kicks [D]'s head, knocking [D.p_them()] out!", \ - "[A] kicks your head, knocking you out!") - playsound(get_turf(A), 'sound/weapons/genhit1.ogg', 50, 1, -1) - D.SetSleeping(15) - D.adjustBrainLoss(15, 150) - add_attack_logs(A, D, "Knocked out with martial-art [src] : Kick", ATKLOG_ALL) - else //if target can't be kicked, do a regular harm attack then clear the streak - streak = "" - harm_act(A, D) - streak = "" + if(D.weakened && !D.stat) + D.visible_message("[A] kicks [D]'s head, knocking [D.p_them()] out!", \ + "[A] kicks your head, knocking you out!") + playsound(get_turf(A), 'sound/weapons/genhit1.ogg', 50, 1, -1) + D.SetSleeping(15) + D.adjustBrainLoss(15) + add_attack_logs(A, D, "Knocked out with martial-art [src] : Kick", ATKLOG_ALL) return TRUE /datum/martial_art/cqc/proc/Pressure(mob/living/carbon/human/A, mob/living/carbon/human/D) @@ -118,10 +119,6 @@ D.adjustStaminaLoss(50) D.apply_damage(25, BRUTE) add_attack_logs(A, D, "Melee attacked with martial-art [src] : Consecutive", ATKLOG_ALL) - else //if target can't be hit, do a regular harm attack then clear the streak - streak = "" - harm_act(A, D) - streak = "" return TRUE /datum/martial_art/cqc/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D) @@ -133,6 +130,8 @@ var/obj/item/grab/G = D.grabbedby(A, 1) if(G) G.state = GRAB_AGGRESSIVE //Instant aggressive grab + add_attack_logs(A, D, "Melee attacked with martial-art [src] : aggressively grabbed", ATKLOG_ALL) + return TRUE /datum/martial_art/cqc/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) @@ -141,8 +140,9 @@ add_to_streak("H", D) if(check_streak(A, D)) return TRUE + add_attack_logs(A, D, "Melee attacked with martial-art [src]", ATKLOG_ALL) A.do_attack_animation(D) - var/picked_hit_type = pick("CQC'd", "neck chopped", "gut punched") + var/picked_hit_type = pick("CQC'd", "Big Bossed") var/bonus_damage = 13 if(D.weakened || D.resting || D.lying) bonus_damage += 5 @@ -154,7 +154,7 @@ playsound(get_turf(D), 'sound/weapons/cqchit1.ogg', 50, 1, -1) D.visible_message("[A] [picked_hit_type] [D]!", \ "[A] [picked_hit_type] you!") - add_attack_logs(A, D, "Melee attacked with martial-art [src]", ATKLOG_ALL) + add_attack_logs(A, D, "Melee attacked with martial-art [src] : [picked_hit_type]", ATKLOG_ALL) if(A.resting && !D.stat && !D.weakened) D.visible_message("[A] leg sweeps [D]!", \ "[A] leg sweeps you!") @@ -168,21 +168,31 @@ if(!can_use(A)) return FALSE add_to_streak("D", D) + var/obj/item/I = null if(check_streak(A, D)) return TRUE - if(!restraining) - D.visible_message("[A] strikes [D]'s jaw with their hand!", \ - "[A] strikes your jaw, disorienting you!") - playsound(get_turf(D), 'sound/weapons/cqchit1.ogg', 50, 1, -1) - D.Jitter(2) - D.apply_damage(5, BRUTE) - add_attack_logs(A, D, "Melee attacked with martial-art [src] : Disarm", ATKLOG_ALL) - if(restraining) + if(prob(65)) + if(!D.stat || !D.weakened || !restraining) + I = D.get_active_hand() + D.visible_message("[A] strikes [D]'s jaw with their hand!", \ + "[A] strikes your jaw, disorienting you!") + playsound(get_turf(D), 'sound/weapons/cqchit1.ogg', 50, 1, -1) + if(I && D.drop_item()) + A.put_in_hands(I) + D.Jitter(2) + D.apply_damage(5, BRUTE) + else + D.visible_message("[A] attempted to disarm [D]!", "[A] attempted to disarm [D]!") + playsound(D, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + add_attack_logs(A, D, "Melee attacked with martial-art [src] : Disarmed [I ? " grabbing \the [I]" : ""]", ATKLOG_ALL) + var/obj/item/grab/G = A.get_inactive_hand() + if(restraining && istype(G) && G.affecting == D) D.visible_message("[A] puts [D] into a chokehold!", \ "[A] puts you into a chokehold!") D.SetSleeping(20) restraining = FALSE - add_attack_logs(A, D, "Knocked out with martial-art [src] : Choke hold", ATKLOG_ALL) + if(G.state < GRAB_NECK) + G.state = GRAB_NECK else restraining = FALSE return FALSE @@ -194,11 +204,10 @@ set category = "CQC" to_chat(usr, "You try to remember some of the basics of CQC.") - to_chat(usr, "Slam: Harm Grab. Slam opponent into the ground, knocking them down.") - to_chat(usr, "CQC Kick: Harm Harm. Knocks opponent away. Knocks out stunned or knocked down opponents.") - to_chat(usr, "Restrain: Grab Switch Hand Grab. Locks opponent into a restraining position, stunning them.") - to_chat(usr, "Choke Hold: Restrain Disarm. Knocks out an opponent you have restrained.") + to_chat(usr, "Slam: Grab Harm. Slam opponent into the ground, knocking them down.") + to_chat(usr, "CQC Kick: Disarm Harm Harm. Knocks opponent away. Knocks out stunned or knocked down opponents.") + to_chat(usr, "Restrain: Grab Grab. Locks opponents into a restraining position, disarm to knock them out with a choke hold.") to_chat(usr, "Pressure: Disarm Grab. Decent stamina damage.") to_chat(usr, "Consecutive CQC: Disarm Disarm Harm. Mainly offensive move, huge damage and decent stamina damage.") - to_chat(usr, "In addition, by having your throw mode on when being attacked, you enter an active defense mode where you have a chance to block and sometimes even counter melee attacks done to you.") \ No newline at end of file + to_chat(usr, "In addition, by having your throw mode on when being attacked, you enter an active defense mode where you have a chance to block and sometimes even counter attacks done to you.") \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index a7d04c7f0c4..6ff70a348c1 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -156,7 +156,7 @@ emp_act return 1 return 0 -/mob/living/carbon/human/check_block() +/mob/living/carbon/human/proc/check_block() if(martial_art && prob(martial_art.block_chance) && martial_art.can_use(src) && in_throw_mode && !incapacitated(FALSE, TRUE)) return TRUE @@ -219,6 +219,10 @@ emp_act if(check_shields(I.force, "the [I.name]", I, MELEE_ATTACK, I.armour_penetration)) return 0 + if(check_block()) + visible_message("[src] blocks [I]!") + return FALSE + if(istype(I,/obj/item/card/emag)) emag_act(user, affecting) diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index a728c2bbfd8..fd55b2cd76a 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -318,7 +318,7 @@ user.do_cpr(target) /datum/species/proc/grab(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) - if(target.check_block()) //cqc + if(target.check_block()) target.visible_message("[target] blocks [user]'s grab attempt!") return FALSE if(attacker_style && attacker_style.grab_act(user, target)) @@ -347,7 +347,7 @@ add_attack_logs(user, target, "vampirebit") return //end vampire codes - if(target.check_block()) //cqc + if(target.check_block()) target.visible_message("[target] blocks [user]'s attack!") return FALSE if(attacker_style && attacker_style.harm_act(user, target)) @@ -388,7 +388,7 @@ target.forcesay(GLOB.hit_appends) /datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) - if(target.check_block()) //cqc + if(target.check_block()) target.visible_message("[target] blocks [user]'s disarm attempt!") return FALSE if(attacker_style && attacker_style.disarm_act(user, target)) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index f766a1f53ce..da5a3cf96ca 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -336,8 +336,4 @@ return TRUE if(INTENT_DISARM) M.do_attack_animation(src, ATTACK_EFFECT_DISARM) - return TRUE - -//defined here, overridden for humans in human_defense. By default, living mobs don't get to block anything -/mob/living/proc/check_block() - return FALSE \ No newline at end of file + return TRUE \ No newline at end of file