diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index af1043f22e..15e8048926 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -97,6 +97,20 @@ //the define for visible message range in combat #define COMBAT_MESSAGE_RANGE 3 +//Shove knockdown lengths (deciseconds) +#define SHOVE_KNOCKDOWN_SOLID 30 +#define SHOVE_KNOCKDOWN_HUMAN 30 +#define SHOVE_KNOCKDOWN_TABLE 30 +#define SHOVE_KNOCKDOWN_COLLATERAL 10 +//Shove slowdown +#define SHOVE_SLOWDOWN_ID "shove_slowdown" +#define SHOVE_SLOWDOWN_LENGTH 30 +#define SHOVE_SLOWDOWN_STRENGTH 0.85 //multiplier +//Shove disarming item list +GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( + /obj/item/gun))) + + //Combat object defines //Embedded objects diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 1e65c6ca3f..746d5da60d 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -24,6 +24,8 @@ var/can_flashlight = 0 var/scan_reagents = 0 //Can the wearer see reagents while it's equipped? + var/blocks_shove_knockdown = FALSE //Whether wearing the clothing item blocks the ability for shove to knock down. + var/clothing_flags = NONE //Var modification - PLEASE be careful with this I know who you are and where you live diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 97c9da289b..b10bf39729 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -110,13 +110,14 @@ /obj/item/clothing/suit/armor/riot name = "riot suit" - desc = "A suit of semi-flexible polycarbonate body armor with heavy padding to protect against melee attacks." + desc = "A suit of semi-flexible polycarbonate body armor with heavy padding to protect against melee attacks. Helps the wearer resist shoving in close quarters." icon_state = "riot" item_state = "swat_suit" body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS armor = list("melee" = 50, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80) + blocks_shove_knockdown = TRUE strip_delay = 80 equip_delay_other = 60 diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 7909b5e71a..2dfd414e85 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -892,6 +892,21 @@ . = ..(M,force,check_loc) stop_pulling() +/mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this + var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor) + for(var/bp in body_parts) + if(istype(bp, /obj/item/clothing)) + var/obj/item/clothing/C = bp + if(C.blocks_shove_knockdown) + return TRUE + return FALSE + +/mob/living/carbon/human/proc/clear_shove_slowdown() + remove_movespeed_modifier(SHOVE_SLOWDOWN_ID) + var/active_item = get_active_held_item() + if(is_type_in_typecache(active_item, GLOB.shove_disarming_types)) + visible_message("[src.name] regains their grip on \the [active_item]!", "You regain your grip on \the [active_item]", null, COMBAT_MESSAGE_RANGE) + /mob/living/carbon/human/do_after_coefficent() . = ..() . *= physiology.do_after_speed diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 7c0eaacf26..0e67ce7510 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -170,6 +170,9 @@ var/mob/living/L = M if(L.has_trait(TRAIT_PUSHIMMUNE)) return 1 + //If they're a human, and they're not in help intent, block pushing + if(ishuman(M) && (M.a_intent != INTENT_HELP)) + return TRUE //anti-riot equipment is also anti-push for(var/obj/item/I in M.held_items) if(!istype(M, /obj/item/clothing)) diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species.dm b/modular_citadel/code/modules/mob/living/carbon/human/species.dm index 73a50dccf0..d468f34653 100644 --- a/modular_citadel/code/modules/mob/living/carbon/human/species.dm +++ b/modular_citadel/code/modules/mob/living/carbon/human/species.dm @@ -44,37 +44,105 @@ if(user.getStaminaLoss() >= STAMINA_SOFTCRIT) to_chat(user, "You're too exhausted.") return FALSE - else if(target.check_block()) - target.visible_message("[target] blocks [user]'s disarm attempt!") - return 0 + if(target.check_block()) + target.visible_message("[target] blocks [user]'s shoving attempt!") + return FALSE if(attacker_style && attacker_style.disarm_act(user,target)) - return 1 + return TRUE + if(user.resting) + return FALSE else + if(user == target) + return user.do_attack_animation(target, ATTACK_EFFECT_DISARM) - - user.adjustStaminaLossBuffered(4) //CITADEL CHANGE - makes disarmspam cause staminaloss + user.adjustStaminaLossBuffered(4) + playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) if(target.w_uniform) target.w_uniform.add_fingerprint(user) - var/randomized_zone = ran_zone(user.zone_selected) SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected) - var/obj/item/bodypart/affecting = target.get_bodypart(randomized_zone) - if((!target.combatmode && user.combatmode || prob(target.getStaminaLoss()*(user.resting ? 0.25 : 1)*(user.combatmode ? 1 : 0.05))) && !target.resting) //probability depends on staminaloss. it's plausible, but unlikely that you'll be able to push someone over while resting, and pretty rare to successfully push someone outside of combat mode. The few people that even know how to right-click outside of combat mode are a rarity but let's take that into account regardless. - playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - target.visible_message("[user] [user.combatmode ? "has" : "gently"] pushed [target]!", - "[user] has pushed [target]!", null, COMBAT_MESSAGE_RANGE) - target.apply_effect(40, EFFECT_KNOCKDOWN, target.run_armor_check(affecting, "melee", "Your armor prevents your fall!", "Your armor softens your fall!")) - target.forcesay(GLOB.hit_appends) - log_combat(user, target, "disarmed", " pushing them to the ground") - return + if(!target.resting) + target.adjustStaminaLoss(5) + + + var/turf/target_oldturf = target.loc + var/shove_dir = get_dir(user.loc, target_oldturf) + var/turf/target_shove_turf = get_step(target.loc, shove_dir) + var/mob/living/carbon/human/target_collateral_human + var/obj/structure/table/target_table + var/shove_blocked = FALSE //Used to check if a shove is blocked so that if it is knockdown logic can be applied + + //Thank you based whoneedsspace + target_collateral_human = locate(/mob/living/carbon/human) in target_shove_turf.contents + if(target_collateral_human) + shove_blocked = TRUE + else + target.Move(target_shove_turf, shove_dir) + if(get_turf(target) == target_oldturf) + target_table = locate(/obj/structure/table) in target_shove_turf.contents + shove_blocked = TRUE + + if(shove_blocked && !target.is_shove_knockdown_blocked()) + var/directional_blocked = FALSE + if(shove_dir in GLOB.cardinals) //Directional checks to make sure that we're not shoving through a windoor or something like that + var/target_turf = get_turf(target) + for(var/obj/O in target_turf) + if(O.flags_1 & ON_BORDER_1 && O.dir == shove_dir && O.density) + directional_blocked = TRUE + break + if(target_turf != target_shove_turf) //Make sure that we don't run the exact same check twice on the same tile + for(var/obj/O in target_shove_turf) + if(O.flags_1 & ON_BORDER_1 && O.dir == turn(shove_dir, 180) && O.density) + directional_blocked = TRUE + break + var/targetatrest = target.resting + if(((!target_table && !target_collateral_human) || directional_blocked) && !targetatrest) + target.Knockdown(SHOVE_KNOCKDOWN_SOLID) + user.visible_message("[user.name] shoves [target.name], knocking them down!", + "You shove [target.name], knocking them down!", null, COMBAT_MESSAGE_RANGE) + log_combat(user, target, "shoved", "knocking them down") + else if(target_table) + if(!targetatrest) + target.Knockdown(SHOVE_KNOCKDOWN_TABLE) + user.visible_message("[user.name] shoves [target.name] onto \the [target_table]!", + "You shove [target.name] onto \the [target_table]!", null, COMBAT_MESSAGE_RANGE) + target.forceMove(target_shove_turf) + log_combat(user, target, "shoved", "onto [target_table]") + else if(target_collateral_human && !targetatrest) + target.Knockdown(SHOVE_KNOCKDOWN_HUMAN) + if(!target_collateral_human.resting) + target_collateral_human.Knockdown(SHOVE_KNOCKDOWN_COLLATERAL) + user.visible_message("[user.name] shoves [target.name] into [target_collateral_human.name]!", + "You shove [target.name] into [target_collateral_human.name]!", null, COMBAT_MESSAGE_RANGE) + log_combat(user, target, "shoved", "into [target_collateral_human.name]") + + else + user.visible_message("[user.name] shoves [target.name]!", + "You shove [target.name]!", null, COMBAT_MESSAGE_RANGE) + var/target_held_item = target.get_active_held_item() + var/knocked_item = FALSE + if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types)) + target_held_item = null + if(!target.has_movespeed_modifier(SHOVE_SLOWDOWN_ID)) + target.add_movespeed_modifier(SHOVE_SLOWDOWN_ID, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH) + if(target_held_item) + target.visible_message("[target.name]'s grip on \the [target_held_item] loosens!", + "Your grip on \the [target_held_item] loosens!", null, COMBAT_MESSAGE_RANGE) + addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH) + else if(target_held_item) + target.dropItemToGround(target_held_item) + knocked_item = TRUE + target.visible_message("[target.name] drops \the [target_held_item]!!", + "You drop \the [target_held_item]!!", null, COMBAT_MESSAGE_RANGE) + var/append_message = "" + if(target_held_item) + if(knocked_item) + append_message = "causing them to drop [target_held_item]" + else + append_message = "loosening their grip on [target_held_item]" + log_combat(user, target, "shoved", append_message) - playsound(target, 'sound/weapons/thudswoosh.ogg', 25, 1, -1) - target.visible_message("[user] [user.combatmode ? "attempted to push" : "tries to gently push"] [target] over!", \ - "[user] [user.combatmode ? "attempted to push" : "tries to gently push"] [target] over!", null, COMBAT_MESSAGE_RANGE) - if(!target.resting && !user.resting && user.combatmode) - target.adjustStaminaLoss(rand(1,5)) //This is the absolute most inefficient way to get someone into soft stamcrit, but if you've got a crowd trying to shove you over, you've no option but to get knocked down and accept fate - log_combat(user, target, "attempted to disarm push") //////////////////// /////BODYPARTS/////