diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 31a1681eace..f7eafdda9db 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -153,17 +153,23 @@ if(propelled) var/mob/living/occupant = buckled_mob unbuckle() + + var/def_zone = ran_zone() + var/blocked = occupant.run_armor_check(def_zone, "melee") occupant.throw_at(A, 3, propelled) - occupant.apply_effect(6, STUN, 0) - occupant.apply_effect(6, WEAKEN, 0) - occupant.apply_effect(6, STUTTER, 0) + occupant.apply_effect(6, STUN, blocked) + occupant.apply_effect(6, WEAKEN, blocked) + occupant.apply_effect(6, STUTTER, blocked) + occupant.apply_damage(10, BRUTE, def_zone, blocked) playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) if(istype(A, /mob/living)) var/mob/living/victim = A - victim.apply_effect(6, STUN, 0) - victim.apply_effect(6, WEAKEN, 0) - victim.apply_effect(6, STUTTER, 0) - victim.take_organ_damage(10) + def_zone = ran_zone() + blocked = victim.run_armor_check(def_zone, "melee") + victim.apply_effect(6, STUN, blocked) + victim.apply_effect(6, WEAKEN, blocked) + victim.apply_effect(6, STUTTER, blocked) + victim.apply_damage(10, BRUTE, def_zone, blocked) occupant.visible_message("[occupant] crashed into \the [A]!") /obj/structure/stool/bed/chair/office/light diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm index 9c00ee38963..8e801de6e2d 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -147,16 +147,22 @@ else if (propelled) occupant.throw_at(A, 3, propelled) - occupant.apply_effect(6, STUN, 0) - occupant.apply_effect(6, WEAKEN, 0) - occupant.apply_effect(6, STUTTER, 0) + var/def_zone = ran_zone() + var/blocked = occupant.run_armor_check(def_zone, "melee") + occupant.throw_at(A, 3, propelled) + occupant.apply_effect(6, STUN, blocked) + occupant.apply_effect(6, WEAKEN, blocked) + occupant.apply_effect(6, STUTTER, blocked) + occupant.apply_damage(10, BRUTE, def_zone) playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) if(istype(A, /mob/living)) var/mob/living/victim = A - victim.apply_effect(6, STUN, 0) - victim.apply_effect(6, WEAKEN, 0) - victim.apply_effect(6, STUTTER, 0) - victim.take_organ_damage(10) + def_zone = ran_zone() + blocked = victim.run_armor_check(def_zone, "melee") + victim.apply_effect(6, STUN, blocked) + victim.apply_effect(6, WEAKEN, blocked) + victim.apply_effect(6, STUTTER, blocked) + victim.apply_damage(10, BRUTE, def_zone) if(pulling) occupant.visible_message("[pulling] has thrusted \the [name] into \the [A], throwing \the [occupant] out of it!") diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index 91153fee0fa..e75b3126902 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -102,7 +102,7 @@ w_class = 4//bulky item gas_transfer_coefficient = 0.90 permeability_coefficient = 0.50 - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS|FEET allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency_oxygen,/obj/item/clothing/head/radiation,/obj/item/clothing/mask/gas) slowdown = 1.5 armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index bc6d2832e6a..01caff57e5a 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -165,6 +165,10 @@ hud_updateflag |= 1 << HEALTH_HUD updatehealth() + +/* +In most cases it makes more sense to use apply_damage() instead! And make sure to check armour if applicable. +*/ //Damages ONE external organ, organ gets randomly selected from damagable ones. //It automatically updates damage overlays if necesary //It automatically updates health status diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 407b83c9c34..7406c693b53 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -84,7 +84,7 @@ emp_act /mob/living/carbon/human/getarmor(var/def_zone, var/type) var/armorval = 0 - var/organnum = 0 + var/total = 0 if(def_zone) if(isorgan(def_zone)) @@ -94,10 +94,13 @@ emp_act //If a specific bodypart is targetted, check how that bodypart is protected and return the value. //If you don't specify a bodypart, it checks ALL your bodyparts for protection, and averages out the values - for(var/datum/organ/external/organ in organs) - armorval += getarmor_organ(organ, type) - organnum++ - return (armorval/max(organnum, 1)) + for(var/organ_name in organs_by_name) + if (organ_name in organ_rel_size) + var/datum/organ/external/organ = organs_by_name[organ_name] + var/weight = organ_rel_size[organ_name] + armorval += getarmor_organ(organ, type) * weight + total += weight + return (armorval/max(total, 1)) //this proc returns the Siemens coefficient of electrical resistivity for a particular external organ. /mob/living/carbon/human/proc/get_siemens_coefficient_organ(var/datum/organ/external/def_zone) @@ -117,11 +120,10 @@ emp_act /mob/living/carbon/human/proc/getarmor_organ(var/datum/organ/external/def_zone, var/type) if(!type) return 0 var/protection = 0 - var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform) - for(var/bp in body_parts) - if(!bp) continue - if(bp && istype(bp ,/obj/item/clothing)) - var/obj/item/clothing/C = bp + var/list/protective_gear = list(head, wear_mask, wear_suit, w_uniform) + for(var/gear in protective_gear) + if(gear && istype(gear ,/obj/item/clothing)) + var/obj/item/clothing/C = gear if(C.body_parts_covered & def_zone.body_part) protection += C.armor[type] return protection diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 5431a2775ad..cc76d40c654 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -52,7 +52,8 @@ if(AGONY) halloss += effect // Useful for objects that cause "subdual" damage. PAIN! if(IRRADIATE) - radiation += max((((effect - (effect*(getarmor(null, "rad")/100))))/(blocked+1)),0)//Rads auto check armor + var/rad_protection = getarmor(null, "rad")/100 + radiation += max((1-rad_protection)*effect/(blocked+1),0)//Rads auto check armor if(STUTTER) if(status_flags & CANSTUN) // stun is usually associated with stutter stuttering = max(stuttering,(effect/(blocked+1))) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 388f2bf7a4b..08f80ceaabf 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -119,8 +119,44 @@ proc/hasorgans(A) return ishuman(A) /proc/hsl2rgb(h, s, l) - return + return //TODO: Implement +/* + Miss Chance +*/ + +//TODO: Integrate defence zones and targeting body parts with the actual organ system, move these into organ definitions. + +//The base miss chance for the different defence zones +var/list/global/base_miss_chance = list( + "head" = 40, + "chest" = 10, + "groin" = 20, + "l_leg" = 20, + "r_leg" = 20, + "l_arm" = 20, + "r_arm" = 20, + "l_hand" = 50, + "r_hand" = 50, + "l_foot" = 50, + "r_foot" = 50, +) + +//Used to weight organs when an organ is hit randomly (i.e. not a directed, aimed attack). +//Also used to weight the protection value that armour provides for covering that body part when calculating protection from full-body effects. +var/list/global/organ_rel_size = list( + "head" = 25, + "chest" = 70, + "groin" = 30, + "l_leg" = 25, + "r_leg" = 25, + "l_arm" = 25, + "r_arm" = 25, + "l_hand" = 10, + "r_hand" = 10, + "l_foot" = 10, + "r_foot" = 10, +) /proc/check_zone(zone) if(!zone) return "chest" @@ -131,26 +167,32 @@ proc/hasorgans(A) zone = "head" return zone -// Returns zone with a certain probability. -// If the probability misses, returns "chest" instead. -// If "chest" was passed in as zone, then on a "miss" will return "head", "l_arm", or "r_arm" +// Returns zone with a certain probability. If the probability fails, or no zone is specified, then a random body part is chosen. // Do not use this if someone is intentionally trying to hit a specific body part. // Use get_zone_with_miss_chance() for that. /proc/ran_zone(zone, probability) - zone = check_zone(zone) - if(!probability) probability = 90 - if(probability == 100) return zone + if (zone) + zone = check_zone(zone) + if (prob(probability)) + return zone - if(zone == "chest") - if(prob(probability)) return "chest" - var/t = rand(1, 9) - switch(t) - if(1 to 3) return "head" - if(4 to 6) return "l_arm" - if(7 to 9) return "r_arm" - - if(prob(probability * 0.75)) return zone - return "chest" + var/ran_zone = zone + while (ran_zone == zone) + ran_zone = pick ( + organ_rel_size["head"]; "head", + organ_rel_size["chest"]; "chest", + organ_rel_size["groin"]; "groin", + organ_rel_size["l_arm"]; "l_arm", + organ_rel_size["r_arm"]; "r_arm", + organ_rel_size["l_leg"]; "l_leg", + organ_rel_size["r_leg"]; "r_leg", + organ_rel_size["l_hand"]; "l_hand", + organ_rel_size["r_hand"]; "r_hand", + organ_rel_size["l_foot"]; "l_foot", + organ_rel_size["r_foot"]; "r_foot", + ) + + return ran_zone // Emulates targetting a specific body part, and miss chances // May return null if missed @@ -161,42 +203,13 @@ proc/hasorgans(A) // you can only miss if your target is standing and not restrained if(!target.buckled && !target.lying) var/miss_chance = 10 - switch(zone) - if("head") - miss_chance = 40 - if("l_leg") - miss_chance = 20 - if("r_leg") - miss_chance = 20 - if("l_arm") - miss_chance = 20 - if("r_arm") - miss_chance = 20 - if("l_hand") - miss_chance = 50 - if("r_hand") - miss_chance = 50 - if("l_foot") - miss_chance = 50 - if("r_foot") - miss_chance = 50 + if (zone in base_miss_chance) + miss_chance = base_miss_chance[zone] miss_chance = max(miss_chance + miss_chance_mod, 0) if(prob(miss_chance)) if(prob(70)) return null - else - var/t = rand(1, 10) - switch(t) - if(1) return "head" - if(2) return "l_arm" - if(3) return "r_arm" - if(4) return "chest" - if(5) return "l_foot" - if(6) return "r_foot" - if(7) return "l_hand" - if(8) return "r_hand" - if(9) return "l_leg" - if(10) return "r_leg" + return pick(base_miss_chance) return zone diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm index 35b776af287..9e5dbbb4d4d 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm @@ -49,32 +49,8 @@ var/armor_duration = 0 //The more force the bottle has, the longer the duration. //Calculating duration and calculating damage. - if(ishuman(target)) - - var/mob/living/carbon/human/H = target - var/headarmor = 0 // Target's head armour - armor_block = H.run_armor_check(affecting, "melee") // For normal attack damage - - //If they have a hat/helmet and the user is targeting their head. - if(istype(H.head, /obj/item/clothing/head) && affecting == "head") - - // If their head has an armour value, assign headarmor to it, else give it 0. - if(H.head.armor["melee"]) - headarmor = H.head.armor["melee"] - else - headarmor = 0 - else - headarmor = 0 - - //Calculate the weakening duration for the target. - armor_duration = (duration - headarmor) + force - - else - //Only humans can have armour, right? - armor_block = target.run_armor_check(affecting, "melee") - if(affecting == "head") - armor_duration = duration + force - armor_duration /= 10 + armor_block = target.run_armor_check(affecting, "melee") + armor_duration = duration + force - target.getarmor(affecting, "melee") //Apply the damage! target.apply_damage(force, BRUTE, affecting, armor_block, sharp=0) @@ -88,7 +64,7 @@ else O.show_message(text("\red [target] hit himself with a bottle of [src.name] on the head!"), 1) //Weaken the target for the duration that we calculated and divide it by 5. if(armor_duration) - target.apply_effect(min(armor_duration, 10) , WEAKEN) // Never weaken more than a flash! + target.apply_effect(min(armor_duration, 10) , WEAKEN, armor_block) // Never weaken more than a flash! else //Default attack message and don't weaken the target.