From a0d0f8a7cd119b5e5ca84dbc28c8c0d020126b67 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 27 Feb 2024 01:59:40 +0100 Subject: [PATCH] [MIRROR] Riot armor and helmets (and similar gear) protect against more melee-based attacks (like RNG punches), bottles aren't near guaranteed knockdowns (#26633) * Riot armor and helmets (and similar gear) protect against more melee-based attacks (like RNG punches), bottles aren't near guaranteed knockdowns (#81365) partially includes Syndicate modsuits and other suits with a module) TRAIT_SHOVE_KNOCKDOWN_BLOCKED is now called TRAIT_BRAWLING_KNOCKDOWN_BLOCKED. This is possessed by riot suits, SWAT suits and now **plate armor**. Not the chaplain variety, because fuck them I guess. (this was apparently deliberate so don't complain to me, okay?) Anyone with this trait is now unable to be knocked down by; - Pure RNG on blunt objects attacks to the chest (Probability is otherwise altered by melee armor already) - Unarmed punches, both RNG and deterministic - Bodies thrown at them. Instead, dealing stamina damage and causing them to become staggered. A new trait called TRAIT_HEAD_INJURY_BLOCKED, which protects from various head injury related effects. This is possessed by riot helmets, SWAT helmets, plate helmets, hardhats and applied to MODsuits with armor boosters activated/the infiltrator suit while active. The trait is also granted to anyone wearing a modsuit with the Head Protection module installed. This can be printed from round start, and comes pre-installed into all the engineering modsuits, security moduits, research modsuit and magnate modsuit. (I had to bump up the security modsuit complexity a bit to put it in iunno if we have a policy about that) Anyone with this trait is protected against: - Bottle smashes to the head. - RNG Blunt force trauma to the head by blunt objects (Probability is otherwise altered by melee armor already) - Partially protects against getting your spine snapped during a bad tackle (this used to be a check ONLY for the riot helmet or hardhat) The bottle smash's chance of a knockdown is based on the force and knockdown duration of the bottle, altered by relevant head melee armor. It's no longer basically guaranteed due to weird math that would determine whether or not you were knocked down only if your armor exceeded certain values or not. Any instance that would check either for riot armor or riot helmets instead checks for the new traits. People weren't particularly happy with the possibility of getting ownzoned by a naked assistant or random toolbox-wielding tider while in dedicated melee protection armor as a result of pure RNG jank. [There was a whole thread here about it](https://tgstation13.org/phpBB/viewtopic.php?f=83&t=35645) with regards to unarmed combat. If you're in riot gear, you should feel like you can confidently combat improvised/blunt weapons at a cost of general protection from the more serious dangers to your wellbeing (AKA lead poisoning or heatstroke. Get it....it's bullets and lasers...) For some reason, bottle smash knockdowns, despite using the values just...conveniently don't get blocked by armor except for extreme values? If at all? I felt like this was really weird for something with such a hefty and fairly powerful knockdown effect, particularly one you can lob at someones head at range. I remember, way back when I first started playing, that this was a feature that used to stun, and one I used a lot to get cheap kills. The amount of bullshit stuns I got on people with it still haunt me to this day. It hasn't improved in the current era, despite being a knockdown, simply because any knockdown still takes several seconds to exit. An arbitrarily low knockdown is still a several second one. It's time to bring this in line with similar equipment. Rather than using flat values that are _clearly_ meant to be only applicable to riot armor the decade ago that the code was written, let's use traits instead. That's way better than relying on magic numbers that may become irrelevant when the code around it changes, which anyone touching that code may not even be aware existed. Since we're using a trait, we can actually allow modsuits to occasionally fill defensive niches that aren't strictly armor values. Handy. :cl: balance: Nanotrasen, in direct response to the increasing danger posed by wannabe martial artists and rioters in the fringes of the Spinward Sector, have upgraded the impact dampeners found in their riot armor. Staff have also started to rediscover the value of medieval armor; it isn't particularly easy to topple a knight in a suit of plate with just your fists. balance: Melee-focused armor is now more able to protect you from various RNG-based knockdowns, such as critical hits from punches (as well as the ones applied through the staggered status), shoves, critical hits with a blunt weapon to the chest, and body throws. balance: Melee-focused helmets also protect you from head injuries, such as bottle smashes, accidentally hitting something dense during a tackle, and critical hits from a blunt weapon to the head. balance: Bottlesmash knockdowns are less reliable in general. add: A new module, the Safety-First Head Protection module, protects you from head trauma! Available in most modsuits expected to take hits to the head often. And from roundstart exofabricators. /:cl: * oh well --------- Co-authored-by: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Co-authored-by: Useroth <37159550+Useroth@users.noreply.github.com> --- code/__DEFINES/traits/declarations.dm | 6 ++++-- code/_globalvars/traits/_traits.dm | 3 ++- code/_onclick/item_attack.dm | 4 ++-- code/datums/components/tackle.dm | 16 ++++++---------- code/modules/clothing/head/hardhat.dm | 5 +++-- code/modules/clothing/head/helmet.dm | 3 +++ code/modules/clothing/suits/armor.dm | 4 ++-- .../mob/living/carbon/alien/adult/queen.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 8 +++++++- .../mob/living/carbon/human/_species.dm | 19 +++++++++---------- .../mob/living/carbon/human/human_defense.dm | 2 +- code/modules/mob/living/living_defense.dm | 2 +- code/modules/mob/living/silicon/silicon.dm | 2 +- code/modules/mod/mod_theme.dm | 2 +- code/modules/mod/mod_types.dm | 7 +++++++ code/modules/mod/modules/modules_antag.dm | 17 ++++++++++++----- .../mod/modules/modules_engineering.dm | 18 ++++++++++++++++++ code/modules/mod/modules/modules_security.dm | 4 ++-- .../reagent_containers/cups/glassbottle.dm | 12 ++++++------ .../designs/mechfabricator_designs.dm | 11 +++++++++++ code/modules/research/techweb/all_nodes.dm | 1 + .../modules/novaya_ert/code/suit.dm | 2 +- 22 files changed, 101 insertions(+), 49 deletions(-) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 648f86ff999..eef432fb2ed 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -211,8 +211,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_BLOOD_DEFICIENCY "blood_deficiency" #define TRAIT_JOLLY "jolly" #define TRAIT_NOCRITDAMAGE "no_crit" -/// Prevents shovies against a dense object from knocking them down. -#define TRAIT_SHOVE_KNOCKDOWN_BLOCKED "shove_knockdown_blocked" +/// Prevents shovies and some strong blows such as unarmed punches and (unreliably) tackles the owner down +#define TRAIT_BRAWLING_KNOCKDOWN_BLOCKED "brawling_knockdown_blocked" +/// Prevents some severe head injuries being sustained from heavy collisions or blunt force injuries. +#define TRAIT_HEAD_INJURY_BLOCKED "head_injury_blocked" /// Prevents staggering. #define TRAIT_NO_STAGGER "no_stagger" /// Getting hit by thrown movables won't push you away diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 35d8b079721..20e592a8448 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -140,6 +140,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BONSAI" = TRAIT_BONSAI, "TRAIT_BOOZE_SLIDER" = TRAIT_BOOZE_SLIDER, "TRAIT_BRAINWASHING" = TRAIT_BRAINWASHING, + "TRAIT_BRAWLING_KNOCKDOWN_BLOCKED" = TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, "TRAIT_BYPASS_EARLY_IRRADIATED_CHECK" = TRAIT_BYPASS_EARLY_IRRADIATED_CHECK, "TRAIT_BYPASS_MEASURES" = TRAIT_BYPASS_MEASURES, "TRAIT_CANNOT_BE_UNBUCKLED" = TRAIT_CANNOT_BE_UNBUCKLED, @@ -237,6 +238,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_HAS_CRANIAL_FISSURE" = TRAIT_HAS_CRANIAL_FISSURE, "TRAIT_HAS_MARKINGS" = TRAIT_HAS_MARKINGS, "TRAIT_HATED_BY_DOGS" = TRAIT_HATED_BY_DOGS, + "TRAIT_HEAD_INJURY_BLOCKED" = TRAIT_HEAD_INJURY_BLOCKED, "TRAIT_HEALS_FROM_CARP_RIFTS" = TRAIT_HEALS_FROM_CARP_RIFTS, "TRAIT_HEALS_FROM_CULT_PYLONS" = TRAIT_HEALS_FROM_CULT_PYLONS, "TRAIT_HEAR_THROUGH_DARKNESS" = TRAIT_HEAR_THROUGH_DARKNESS, @@ -401,7 +403,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_SHAVED" = TRAIT_SHAVED, "TRAIT_SHIFTY_EYES" = TRAIT_SHIFTY_EYES, "TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE, - "TRAIT_SHOVE_KNOCKDOWN_BLOCKED" = TRAIT_SHOVE_KNOCKDOWN_BLOCKED, "TRAIT_SIGN_LANG" = TRAIT_SIGN_LANG, "TRAIT_PAPER_MASTER" = TRAIT_PAPER_MASTER, "TRAIT_SILENT_FOOTSTEPS" = TRAIT_SILENT_FOOTSTEPS, diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 745d63b5b94..174aac2fc62 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -390,7 +390,7 @@ glasses.add_mob_blood(src) update_worn_glasses() - if(!attacking_item.get_sharpness() && armor_block < 50) + if(!attacking_item.get_sharpness() && !HAS_TRAIT(src, TRAIT_HEAD_INJURY_BLOCKED)) if(prob(damage_done)) adjustOrganLoss(ORGAN_SLOT_BRAIN, 20) if(stat == CONSCIOUS) @@ -420,7 +420,7 @@ w_uniform.add_mob_blood(src) update_worn_undersuit() - if(stat == CONSCIOUS && !attacking_item.get_sharpness() && armor_block < 50) + if(stat == CONSCIOUS && !attacking_item.get_sharpness() && !HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) if(prob(damage_done)) visible_message( span_danger("[src] is knocked down!"), diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index acd25fb328b..b6cc4d32c97 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -400,7 +400,7 @@ defense_mod += 2 if(tackle_target.mob_negates_gravity()) defense_mod += 1 - if(HAS_TRAIT(tackle_target, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) // riot armor and such + if(HAS_TRAIT(tackle_target, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) // riot armor and such defense_mod += 5 var/obj/item/organ/external/tail/lizard/el_tail = tackle_target.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL) @@ -451,7 +451,7 @@ attack_mod += 15 human_sacker.adjustStaminaLoss(100) //AHAHAHAHAHAHAHAHA - if(HAS_TRAIT(human_sacker, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) // tackling with riot specialized armor, like riot armor, is effective but tiring + if(HAS_TRAIT(human_sacker, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) // tackling with riot specialized armor, like riot armor, is effective but tiring attack_mod += 2 human_sacker.adjustStaminaLoss(20) @@ -499,14 +499,10 @@ var/danger_zone = (speed - 1) * 13 // for every extra speed we have over 1, take away 13 of the safest chance danger_zone = max(min(danger_zone, 100), 1) - if(ishuman(user)) - var/mob/living/carbon/human/S = user - var/head_slot = S.get_item_by_slot(ITEM_SLOT_HEAD) - var/suit_slot = S.get_item_by_slot(ITEM_SLOT_OCLOTHING) - if(head_slot && (istype(head_slot,/obj/item/clothing/head/helmet) || istype(head_slot,/obj/item/clothing/head/utility/hardhat))) - oopsie_mod -= 6 - if(suit_slot && (istype(suit_slot,/obj/item/clothing/suit/armor/riot))) - oopsie_mod -= 6 + if(HAS_TRAIT(user, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) + oopsie_mod -= 6 + if(HAS_TRAIT(user, TRAIT_HEAD_INJURY_BLOCKED)) + oopsie_mod -= 6 if(HAS_TRAIT(user, TRAIT_CLUMSY)) oopsie_mod += 6 //honk! diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index ce6becd524e..3550690b426 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -23,7 +23,7 @@ var/hat_type = "yellow" ///Whether the headlamp is on or off. var/on = FALSE - + clothing_traits = list(TRAIT_HEAD_INJURY_BLOCKED) /datum/armor/utility_hardhat melee = 15 @@ -224,6 +224,7 @@ light_color = "#fff2bf" worn_y_offset = 1 dog_fashion = /datum/dog_fashion/head/pumpkin/unlit + clothing_traits = list() /obj/item/clothing/head/utility/hardhat/pumpkinhead/set_light_on(new_value) . = ..() @@ -277,6 +278,6 @@ flags_inv = 0 armor_type = /datum/armor/none light_range = 1 //luminosity when on - + clothing_traits = list() dog_fashion = /datum/dog_fashion/head/reindeer diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 2960260255f..7741251f3f5 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -184,6 +184,7 @@ visor_flags_inv = HIDEFACE|HIDESNOUT flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF visor_flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF + clothing_traits = list(TRAIT_HEAD_INJURY_BLOCKED) /datum/armor/toggleable_riot melee = 50 @@ -247,6 +248,7 @@ strip_delay = 80 resistance_flags = FIRE_PROOF | ACID_PROOF dog_fashion = null + clothing_traits = list(TRAIT_HEAD_INJURY_BLOCKED) /datum/armor/helmet_swat melee = 40 @@ -394,6 +396,7 @@ flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH strip_delay = 80 dog_fashion = null + clothing_traits = list(TRAIT_HEAD_INJURY_BLOCKED) /datum/armor/helmet_knight melee = 50 diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index bcfe4776b76..02e6110b3ee 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -306,7 +306,7 @@ armor_type = /datum/armor/armor_riot strip_delay = 80 equip_delay_other = 60 - clothing_traits = list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED) + clothing_traits = list(TRAIT_BRAWLING_KNOCKDOWN_BLOCKED) /datum/armor/armor_riot melee = 50 @@ -410,7 +410,7 @@ max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT slowdown = 0.7 body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - clothing_traits = list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED) + clothing_traits = list(TRAIT_BRAWLING_KNOCKDOWN_BLOCKED) //All of the armor below is mostly unused diff --git a/code/modules/mob/living/carbon/alien/adult/queen.dm b/code/modules/mob/living/carbon/alien/adult/queen.dm index 1a08d2446d2..4387f7db3ec 100644 --- a/code/modules/mob/living/carbon/alien/adult/queen.dm +++ b/code/modules/mob/living/carbon/alien/adult/queen.dm @@ -19,7 +19,7 @@ // as a wise man once wrote: "pull over that ass too fat" REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) // that'd be a too cheeky shield bashing strat - ADD_TRAIT(src, TRAIT_SHOVE_KNOCKDOWN_BLOCKED, INNATE_TRAIT) + ADD_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, INNATE_TRAIT) AddComponent(/datum/component/seethrough_mob) /mob/living/carbon/alien/adult/royal/on_lying_down(new_lying_angle) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index db21a9635ad..7b4f7834377 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -85,12 +85,18 @@ span_userdanger("You violently crash into [victim][extra_speed ? " extra hard" : ""], but [victim] managed to block the worst of it!")) log_combat(src, victim, "crashed into and was blocked by") return + else if(HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) + victim.take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) + victim.apply_damage(10 + 10 * extra_speed, STAMINA) + victim.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS) + visible_message(span_danger("[src] crashes into [victim][extra_speed ? " really hard" : ""], but [victim] was able to stay on their feet!"),\ + span_userdanger("You violently crash into [victim][extra_speed ? " extra hard" : ""], but [victim] managed to stay on their feet!")) else victim.Paralyze(2 SECONDS) victim.take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) visible_message(span_danger("[src] crashes into [victim][extra_speed ? " really hard" : ""], knocking them both over!"),\ span_userdanger("You violently crash into [victim][extra_speed ? " extra hard" : ""]!")) - log_combat(src, victim, "crashed into") + log_combat(src, victim, "crashed into") if(oof_noise) playsound(src,'sound/weapons/punch1.ogg',50,TRUE) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index d6aedcf91d7..f361a3dcfb2 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1229,16 +1229,15 @@ GLOBAL_LIST_EMPTY(features_by_species) log_combat(user, target, "punched") //If we rolled a punch high enough to hit our stun threshold, or our target is staggered and they have at least 40 damage+stamina loss, we knock them down - if((target.stat != DEAD) && prob(limb_accuracy) || (target.stat != DEAD) && staggered && (target.getStaminaLoss() + user.getBruteLoss()) >= 40) - target.visible_message(span_danger("[user] knocks [target] down!"), \ - span_userdanger("You're knocked down by [user]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_danger("You knock [target] down!")) - /* SKYRAT EDIT REMOVAL - Less combat lethality and hard stuns - var/knockdown_duration = 4 SECONDS + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 //50 total damage = 4 second base stun + 4 second stun modifier = 8 second knockdown duration - target.apply_effect(knockdown_duration, EFFECT_KNOCKDOWN, armor_block) - SKYRAT EDIT REMOVAL END */ - target.StaminaKnockdown(20) //SKYRAT EDIT ADDITION - log_combat(user, target, "got a stun punch with their previous punch") + //This does not work against opponents who are knockdown immune, such as from wearing riot armor. + if(!HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) + if((target.stat != DEAD) && prob(limb_accuracy) || (target.stat != DEAD) && staggered && (target.getStaminaLoss() + user.getBruteLoss()) >= 40) + target.visible_message(span_danger("[user] knocks [target] down!"), \ + span_userdanger("You're knocked down by [user]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, user) + to_chat(user, span_danger("You knock [target] down!")) + var/knockdown_duration = 4 SECONDS + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 //50 total damage = 4 second base stun + 4 second stun modifier = 8 second knockdown duration + target.apply_effect(knockdown_duration, EFFECT_KNOCKDOWN, armor_block) + log_combat(user, target, "got a stun punch with their previous punch") /datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) if(user.body_position != STANDING_UP) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 470a72b9d88..62a201cc1a6 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -146,7 +146,7 @@ return if(!(shove_flags & SHOVE_KNOCKDOWN_BLOCKED)) target.Knockdown(SHOVE_KNOCKDOWN_HUMAN) - if(!HAS_TRAIT(src, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) + if(!HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) Knockdown(SHOVE_KNOCKDOWN_COLLATERAL) target.visible_message(span_danger("[shover] shoves [target.name] into [name]!"), span_userdanger("You're shoved into [name] by [shover]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index bb39ab60663..262df8c99b5 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -756,7 +756,7 @@ . |= SHOVE_CAN_MOVE if(!buckled) . |= SHOVE_CAN_HIT_SOMETHING - if(HAS_TRAIT(src, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) + if(HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) . |= SHOVE_KNOCKDOWN_BLOCKED ///Send the chat feedback message for shoving diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 12f9a293b45..14f3bb4ba3d 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -75,7 +75,7 @@ TRAIT_MADNESS_IMMUNE, TRAIT_MARTIAL_ARTS_IMMUNE, TRAIT_NOFIRE_SPREAD, - TRAIT_SHOVE_KNOCKDOWN_BLOCKED, + TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, ) add_traits(traits_to_apply, ROUNDSTART_TRAIT) diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index 3efc26214bf..509cdfc1ed7 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -698,7 +698,7 @@ a few years out of date, leading to an overall lower capacity for modules." default_skin = "security" armor_type = /datum/armor/mod_theme_security - complexity_max = DEFAULT_MAX_COMPLEXITY - 3 + complexity_max = DEFAULT_MAX_COMPLEXITY - 2 slowdown_inactive = 1 slowdown_active = 0.5 allowed_suit_storage = list( diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index 0933c7e8f18..0659dd6208b 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -55,6 +55,7 @@ /obj/item/mod/module/flashlight, /obj/item/mod/module/tether, /obj/item/mod/module/magboot, + /obj/item/mod/module/headprotector, ) default_pins = list( /obj/item/mod/module/magboot, @@ -72,6 +73,7 @@ /obj/item/mod/module/magboot, /obj/item/mod/module/t_ray, /obj/item/mod/module/quick_carry, + /obj/item/mod/module/headprotector, ) default_pins = list( /obj/item/mod/module/magboot, @@ -87,6 +89,7 @@ /obj/item/mod/module/rad_protection, /obj/item/mod/module/flashlight, /obj/item/mod/module/jetpack, + /obj/item/mod/module/headprotector, ) default_pins = list( /obj/item/mod/module/magboot/advanced, @@ -153,6 +156,7 @@ /obj/item/mod/module/flashlight, /obj/item/mod/module/circuit, /obj/item/mod/module/t_ray, + /obj/item/mod/module/headprotector, ) /obj/item/mod/control/pre_equipped/security @@ -165,6 +169,7 @@ /obj/item/mod/module/criminalcapture, /obj/item/mod/module/dispenser/mirage, /obj/item/mod/module/quick_cuff, + /obj/item/mod/module/headprotector, ) /obj/item/mod/control/pre_equipped/safeguard @@ -179,6 +184,7 @@ /obj/item/mod/module/projectile_dampener, /obj/item/mod/module/pepper_shoulders, /obj/item/mod/module/quick_cuff, + /obj/item/mod/module/headprotector, ) default_pins = list( /obj/item/mod/module/jetpack, @@ -194,6 +200,7 @@ /obj/item/mod/module/jetpack/advanced, /obj/item/mod/module/pathfinder, /obj/item/mod/module/quick_cuff, + /obj/item/mod/module/headprotector, ) default_pins = list( /obj/item/mod/module/jetpack/advanced, diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm index cf72f62d6c4..a35e39365b9 100644 --- a/code/modules/mod/modules/modules_antag.dm +++ b/code/modules/mod/modules/modules_antag.dm @@ -11,7 +11,7 @@ module_type = MODULE_TOGGLE active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 removable = FALSE - incompatible_modules = list(/obj/item/mod/module/armor_booster, /obj/item/mod/module/welding) + incompatible_modules = list(/obj/item/mod/module/armor_booster, /obj/item/mod/module/welding, /obj/item/mod/module/headprotector) cooldown_time = 0.5 SECONDS overlay_state_inactive = "module_armorbooster_off" overlay_state_active = "module_armorbooster_on" @@ -26,6 +26,8 @@ var/list/armor_mod = /datum/armor/mod_module_armor_boost /// List of parts of the suit that are spaceproofed, for giving them back the pressure protection. var/list/spaceproofed = list() + /// List of traits added when the mod is activated + var/list/traits_to_add = list(TRAIT_HEAD_INJURY_BLOCKED) /datum/armor/mod_module_armor_boost melee = 25 @@ -50,6 +52,7 @@ actual_speed_added = max(0, min(mod.slowdown_active, speed_added)) mod.slowdown -= actual_speed_added mod.wearer.update_equipment_speed_mods() + mod.wearer.add_traits(traits_to_add, MOD_TRAIT) var/list/parts = mod.mod_parts + mod for(var/obj/item/part as anything in parts) part.set_armor(part.get_armor().add_other_armor(armor_mod)) @@ -69,6 +72,7 @@ balloon_alert(mod.wearer, "armor retracts, EVA ready") mod.slowdown += actual_speed_added mod.wearer.update_equipment_speed_mods() + mod.wearer.remove_traits(traits_to_add, MOD_TRAIT) var/list/parts = mod.mod_parts + mod for(var/obj/item/part as anything in parts) part.set_armor(part.get_armor().subtract_other_armor(armor_mod)) @@ -483,12 +487,15 @@ /obj/item/mod/module/infiltrator name = "MOD infiltration core programs module" desc = "The primary stealth systems operating within the suit. Utilizing electromagnetic signals, \ - the wearer simply cannot be observed closely, or heard clearly by those around them." + the wearer simply cannot be observed closely, or heard clearly by those around them.\ + It also contains some dampening systems to help protect a user from blows to the head." icon_state = "infiltrator" complexity = 0 removable = FALSE idle_power_cost = DEFAULT_CHARGE_DRAIN * 0 - incompatible_modules = list(/obj/item/mod/module/infiltrator, /obj/item/mod/module/armor_booster, /obj/item/mod/module/welding) + incompatible_modules = list(/obj/item/mod/module/infiltrator, /obj/item/mod/module/armor_booster, /obj/item/mod/module/welding, /obj/item/mod/module/headprotector) + /// List of traits added when the suit is activated + var/list/traits_to_add = list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN, TRAIT_HEAD_INJURY_BLOCKED) /obj/item/mod/module/infiltrator/on_install() mod.item_flags |= EXAMINE_SKIP @@ -497,11 +504,11 @@ mod.item_flags &= ~EXAMINE_SKIP /obj/item/mod/module/infiltrator/on_suit_activation() - mod.wearer.add_traits(list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN), MOD_TRAIT) + mod.wearer.add_traits(traits_to_add, MOD_TRAIT) mod.helmet.flash_protect = FLASH_PROTECTION_WELDER /obj/item/mod/module/infiltrator/on_suit_deactivation(deleting = FALSE) - mod.wearer.remove_traits(list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN), MOD_TRAIT) + mod.wearer.remove_traits(traits_to_add, MOD_TRAIT) if(deleting) return mod.helmet.flash_protect = initial(mod.helmet.flash_protect) diff --git a/code/modules/mod/modules/modules_engineering.dm b/code/modules/mod/modules/modules_engineering.dm index 9095bbd2c24..fa746048e82 100644 --- a/code/modules/mod/modules/modules_engineering.dm +++ b/code/modules/mod/modules/modules_engineering.dm @@ -204,6 +204,24 @@ rcd_scan(src, fade_time = 10 SECONDS) drain_power(use_power_cost) +///Safety-First Head Protection - Protects your brain matter from sudden impacts. +/obj/item/mod/module/headprotector + name = "MOD Safety-First Head Protection module" + desc = "A series of dampening plates are installed along the back and upper areas of \ + the helmet. These plates absorb abrupt kinetic shocks delivered to the skull. \ + The bulk of this module prevents it from being installed in any suit that is capable \ + of combat armor adjustments. However, the rudimentry nature of the module makes it \ + relatively easy to install into most other suits." + icon_state = "welding" + complexity = 1 + incompatible_modules = list(/obj/item/mod/module/armor_booster, /obj/item/mod/module/infiltrator) + +/obj/item/mod/module/constructor/on_suit_activation() + ADD_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, MOD_TRAIT) + +/obj/item/mod/module/constructor/on_suit_deactivation(deleting = FALSE) + REMOVE_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, MOD_TRAIT) + ///Mister - Sprays water over an area. /obj/item/mod/module/mister name = "MOD water mister module" diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index 3b8bc8cb3a8..be271ae61e6 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -587,10 +587,10 @@ incompatible_modules = list(/obj/item/mod/module/shove_blocker) /obj/item/mod/module/shove_blocker/on_suit_activation() - mod.wearer.add_traits(list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) + mod.wearer.add_traits(list(TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) /obj/item/mod/module/shove_blocker/on_suit_deactivation(deleting = FALSE) - mod.wearer.remove_traits(list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) + mod.wearer.remove_traits(list(TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) /obj/item/mod/module/shove_blocker/locked name = "superglued MOD bulwark module" diff --git a/code/modules/reagents/reagent_containers/cups/glassbottle.dm b/code/modules/reagents/reagent_containers/cups/glassbottle.dm index 83754dd571f..9deb6582508 100644 --- a/code/modules/reagents/reagent_containers/cups/glassbottle.dm +++ b/code/modules/reagents/reagent_containers/cups/glassbottle.dm @@ -82,7 +82,7 @@ var/obj/item/bodypart/affecting = user.zone_selected //Find what the player is aiming at var/armor_block = 0 //Get the target's armor values for normal attack damage. - var/armor_duration = 0 //The more force the bottle has, the longer the duration. + var/knockdown_effectiveness = 0 //The more force the bottle has, the longer the duration. //Calculating duration and calculating damage. if(ishuman(target)) @@ -95,23 +95,23 @@ if(istype(H.head, /obj/item/clothing/head) && affecting == BODY_ZONE_HEAD) headarmor = H.head.get_armor_rating(MELEE) //Calculate the knockdown duration for the target. - armor_duration = (bottle_knockdown_duration - headarmor) + force + knockdown_effectiveness = (bottle_knockdown_duration - headarmor) + force else //Only humans can have armor, right? armor_block = living_target.run_armor_check(affecting, MELEE) if(affecting == BODY_ZONE_HEAD) - armor_duration = bottle_knockdown_duration + force + knockdown_effectiveness = bottle_knockdown_duration + force //Apply the damage! armor_block = min(90,armor_block) living_target.apply_damage(force, BRUTE, affecting, armor_block) // You are going to knock someone down for longer if they are not wearing a helmet. var/head_attack_message = "" - if(affecting == BODY_ZONE_HEAD && iscarbon(target)) + if(affecting == BODY_ZONE_HEAD && iscarbon(target) && !HAS_TRAIT(target, TRAIT_HEAD_INJURY_BLOCKED)) head_attack_message = " on the head" - if(armor_duration) - living_target.apply_effect(min(armor_duration, 200) , EFFECT_KNOCKDOWN) + if(knockdown_effectiveness && prob(knockdown_effectiveness)) + living_target.apply_effect(min(knockdown_effectiveness, 200) , EFFECT_KNOCKDOWN) //Display an attack message. if(target != user) diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 3ec6604b329..4532ec0d43d 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -2052,6 +2052,17 @@ category = list( RND_CATEGORY_MODSUIT_MODULES + RND_SUBCATEGORY_MODSUIT_MODULES_ENGINEERING ) +/datum/design/module/mod_head_protection + name = "Safety-First Head Protection Module" + id = "mod_safety" + materials = list( + /datum/material/iron =SMALL_MATERIAL_AMOUNT*5, + /datum/material/glass =HALF_SHEET_MATERIAL_AMOUNT, + ) + build_path = /obj/item/mod/module/headprotector + category = list( + RND_CATEGORY_MODSUIT_MODULES + RND_SUBCATEGORY_MODSUIT_MODULES_ENGINEERING + ) /datum/design/module/mod_t_ray name = "T-Ray Scanner Module" id = "mod_t_ray" diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index d45d819b252..4355dbeca71 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -210,6 +210,7 @@ "mod_plating_standard", "mod_storage", "mod_welding", + "mod_safety", "mod_mouthhole", "mod_flashlight", "mod_longfall", diff --git a/modular_skyrat/modules/novaya_ert/code/suit.dm b/modular_skyrat/modules/novaya_ert/code/suit.dm index 3a6542a562d..587f63549aa 100644 --- a/modular_skyrat/modules/novaya_ert/code/suit.dm +++ b/modular_skyrat/modules/novaya_ert/code/suit.dm @@ -23,7 +23,7 @@ actions_types = list(/datum/action/item_action/hev_toggle/nri, /datum/action/item_action/hev_toggle_notifs/nri, /datum/action/item_action/toggle_spacesuit) resistance_flags = FIRE_PROOF|UNACIDABLE|ACID_PROOF|FREEZE_PROOF clothing_flags = STOPSPRESSUREDAMAGE|SNUG_FIT - clothing_traits = list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED) + clothing_traits = list(TRAIT_BRAWLING_KNOCKDOWN_BLOCKED) activation_song = null //No nice song.