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.