mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
Adds Modifier Armor (#7416)
This commit is contained in:
@@ -55,6 +55,14 @@
|
||||
var/emp_modifier // Added to the EMP strength, which is an inverse scale from 1 to 4, with 1 being the strongest EMP. 5 is a nullification.
|
||||
var/explosion_modifier // Added to the bomb strength, which is an inverse scale from 1 to 3, with 1 being gibstrength. 4 is a nullification.
|
||||
|
||||
// Note that these are combined with the mob's real armor values additatively. You can also omit specific armor types.
|
||||
var/list/armor_percent = null // List of armor values to add to the holder when doing armor calculations. This is for percentage based armor. E.g. 50 = half damage.
|
||||
var/list/armor_flat = null // Same as above but only for flat armor calculations. E.g. 5 = 5 less damage (this comes after percentage).
|
||||
// Unlike armor, this is multiplicative. Two 50% protection modifiers will be combined into 75% protection (assuming no base protection on the mob).
|
||||
var/heat_protection = null // Modifies how 'heat' protection is calculated, like wearing a firesuit. 1 = full protection.
|
||||
var/cold_protection = null // Ditto, but for cold, like wearing a winter coat.
|
||||
var/siemens_coefficient = null // Similar to above two vars but 0 = full protection, to be consistant with siemens numbers everywhere else.
|
||||
|
||||
var/vision_flags // Vision flags to add to the mob. SEE_MOB, SEE_OBJ, etc.
|
||||
|
||||
/datum/modifier/New(var/new_holder, var/new_origin)
|
||||
@@ -186,10 +194,14 @@
|
||||
|
||||
// Checks if the mob has a modifier type.
|
||||
/mob/living/proc/has_modifier_of_type(var/modifier_type)
|
||||
return get_modifier_of_type(modifier_type) ? TRUE : FALSE
|
||||
|
||||
// Gets the first instance of a specific modifier type or subtype.
|
||||
/mob/living/proc/get_modifier_of_type(var/modifier_type)
|
||||
for(var/datum/modifier/M in modifiers)
|
||||
if(istype(M, modifier_type))
|
||||
return TRUE
|
||||
return FALSE
|
||||
return M
|
||||
return null
|
||||
|
||||
// This displays the actual 'numbers' that a modifier is doing. Should only be shown in OOC contexts.
|
||||
// When adding new effects, be sure to update this as well.
|
||||
|
||||
@@ -398,3 +398,32 @@ the artifact triggers the rage.
|
||||
/datum/modifier/outline_test/tick()
|
||||
animate(filter_instance, size = 3, time = 0.25 SECONDS)
|
||||
animate(size = 1, 0.25 SECONDS)
|
||||
|
||||
|
||||
// Acts as a psuedo-godmode, yet probably is more reliable than the actual var for it nowdays.
|
||||
// Can't protect from instantly killing things like singulos.
|
||||
/datum/modifier/invulnerable
|
||||
name = "invulnerable"
|
||||
desc = "You are almost immune to harm, for a little while at least."
|
||||
stacks = MODIFIER_STACK_EXTEND
|
||||
|
||||
disable_duration_percent = 0
|
||||
incoming_damage_percent = 0
|
||||
// bleeding_rate_percent = 0
|
||||
pain_immunity = TRUE
|
||||
armor_percent = list("melee" = 2000, "bullet" = 2000, "laser" = 2000, "bomb" = 2000, "energy" = 2000, "bio" = 2000, "rad" = 2000)
|
||||
heat_protection = 1.0
|
||||
cold_protection = 1.0
|
||||
siemens_coefficient = 0.0
|
||||
|
||||
// Reduces resistance to "elements".
|
||||
// Note that most things that do give resistance gives 100% protection,
|
||||
// and due to multiplicitive stacking, this modifier won't do anything to change that.
|
||||
/datum/modifier/elemental_vulnerability
|
||||
name = "elemental vulnerability"
|
||||
desc = "You're more vulnerable to extreme temperatures and electricity."
|
||||
stacks = MODIFIER_STACK_EXTEND
|
||||
|
||||
heat_protection = -0.5
|
||||
cold_protection = -0.5
|
||||
siemens_coefficient = 1.5
|
||||
@@ -133,6 +133,12 @@ emp_act
|
||||
if(istype(C) && (C.body_parts_covered & def_zone.body_part)) // Is that body part being targeted covered?
|
||||
siemens_coefficient *= C.siemens_coefficient
|
||||
|
||||
// Modifiers.
|
||||
for(var/thing in modifiers)
|
||||
var/datum/modifier/M = thing
|
||||
if(!isnull(M.siemens_coefficient))
|
||||
siemens_coefficient *= M.siemens_coefficient
|
||||
|
||||
return siemens_coefficient
|
||||
|
||||
// Similar to above but is for the mob's overall protection, being the average of all slots.
|
||||
@@ -150,11 +156,11 @@ emp_act
|
||||
if(fire_stacks < 0) // Water makes you more conductive.
|
||||
siemens_value *= 1.5
|
||||
|
||||
return (siemens_value/max(total, 1))
|
||||
return (siemens_value / max(total, 1))
|
||||
|
||||
// Returns a number between 0 to 1, with 1 being total protection.
|
||||
/mob/living/carbon/human/get_shock_protection()
|
||||
return between(0, 1-get_siemens_coefficient_average(), 1)
|
||||
return min(1 - get_siemens_coefficient_average(), 1) // Don't go above 1, but negatives are fine.
|
||||
|
||||
// Returns a list of clothing that is currently covering def_zone.
|
||||
/mob/living/carbon/human/proc/get_clothing_list_organ(var/obj/item/organ/external/def_zone, var/type)
|
||||
@@ -173,6 +179,13 @@ emp_act
|
||||
var/list/protective_gear = def_zone.get_covering_clothing()
|
||||
for(var/obj/item/clothing/gear in protective_gear)
|
||||
protection += gear.armor[type]
|
||||
|
||||
for(var/thing in modifiers)
|
||||
var/datum/modifier/M = thing
|
||||
var/modifier_armor = LAZYACCESS(M.armor_percent, type)
|
||||
if(modifier_armor)
|
||||
protection += modifier_armor
|
||||
|
||||
return protection
|
||||
|
||||
/mob/living/carbon/human/proc/getsoak_organ(var/obj/item/organ/external/def_zone, var/type)
|
||||
@@ -182,6 +195,13 @@ emp_act
|
||||
var/list/protective_gear = def_zone.get_covering_clothing()
|
||||
for(var/obj/item/clothing/gear in protective_gear)
|
||||
soaked += gear.armorsoak[type]
|
||||
|
||||
for(var/thing in modifiers)
|
||||
var/datum/modifier/M = thing
|
||||
var/modifier_armor = LAZYACCESS(M.armor_flat, type)
|
||||
if(modifier_armor)
|
||||
soaked += modifier_armor
|
||||
|
||||
return soaked
|
||||
|
||||
// Checked in borer code
|
||||
|
||||
@@ -836,7 +836,19 @@
|
||||
|
||||
/mob/living/carbon/human/get_heat_protection(temperature) //Temperature is the temperature you're being exposed to.
|
||||
var/thermal_protection_flags = get_heat_protection_flags(temperature)
|
||||
return get_thermal_protection(thermal_protection_flags)
|
||||
|
||||
. = get_thermal_protection(thermal_protection_flags)
|
||||
. = 1 - . // Invert from 1 = immunity to 0 = immunity.
|
||||
|
||||
// Doing it this way makes multiplicative stacking not get out of hand, so two modifiers that give 0.5 protection will be combined to 0.75 in the end.
|
||||
for(var/thing in modifiers)
|
||||
var/datum/modifier/M = thing
|
||||
if(!isnull(M.heat_protection))
|
||||
. *= 1 - M.heat_protection
|
||||
|
||||
// Code that calls this expects 1 = immunity so we need to invert again.
|
||||
. = 1 - .
|
||||
. = min(., 1.0)
|
||||
|
||||
/mob/living/carbon/human/get_cold_protection(temperature)
|
||||
if(COLD_RESISTANCE in mutations)
|
||||
@@ -844,7 +856,20 @@
|
||||
|
||||
temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K.
|
||||
var/thermal_protection_flags = get_cold_protection_flags(temperature)
|
||||
return get_thermal_protection(thermal_protection_flags)
|
||||
|
||||
. = get_thermal_protection(thermal_protection_flags)
|
||||
. = 1 - . // Invert from 1 = immunity to 0 = immunity.
|
||||
|
||||
// Doing it this way makes multiplicative stacking not get out of hand, so two modifiers that give 0.5 protection will be combined to 0.75 in the end.
|
||||
for(var/thing in modifiers)
|
||||
var/datum/modifier/M = thing
|
||||
if(!isnull(M.cold_protection))
|
||||
// Invert the modifier values so they align with the current working value.
|
||||
. *= 1 - M.cold_protection
|
||||
|
||||
// Code that calls this expects 1 = immunity so we need to invert again.
|
||||
. = 1 - .
|
||||
. = min(., 1.0)
|
||||
|
||||
/mob/living/carbon/human/proc/get_thermal_protection(var/flags)
|
||||
.=0
|
||||
|
||||
@@ -140,7 +140,18 @@
|
||||
|
||||
// Cold stuff.
|
||||
/mob/living/simple_mob/get_cold_protection()
|
||||
return cold_resist
|
||||
. = cold_resist
|
||||
. = 1 - . // Invert from 1 = immunity to 0 = immunity.
|
||||
|
||||
// Doing it this way makes multiplicative stacking not get out of hand, so two modifiers that give 0.5 protection will be combined to 0.75 in the end.
|
||||
for(var/thing in modifiers)
|
||||
var/datum/modifier/M = thing
|
||||
if(!isnull(M.cold_protection))
|
||||
. *= 1 - M.cold_protection
|
||||
|
||||
// Code that calls this expects 1 = immunity so we need to invert again.
|
||||
. = 1 - .
|
||||
. = min(., 1.0)
|
||||
|
||||
|
||||
// Fire stuff. Not really exciting at the moment.
|
||||
@@ -154,7 +165,18 @@
|
||||
return
|
||||
|
||||
/mob/living/simple_mob/get_heat_protection()
|
||||
return heat_resist
|
||||
. = heat_resist
|
||||
. = 1 - . // Invert from 1 = immunity to 0 = immunity.
|
||||
|
||||
// Doing it this way makes multiplicative stacking not get out of hand, so two modifiers that give 0.5 protection will be combined to 0.75 in the end.
|
||||
for(var/thing in modifiers)
|
||||
var/datum/modifier/M = thing
|
||||
if(!isnull(M.heat_protection))
|
||||
. *= 1 - M.heat_protection
|
||||
|
||||
// Code that calls this expects 1 = immunity so we need to invert again.
|
||||
. = 1 - .
|
||||
. = min(., 1.0)
|
||||
|
||||
// Electricity
|
||||
/mob/living/simple_mob/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null)
|
||||
@@ -170,7 +192,18 @@
|
||||
s.start()
|
||||
|
||||
/mob/living/simple_mob/get_shock_protection()
|
||||
return shock_resist
|
||||
. = shock_resist
|
||||
. = 1 - . // Invert from 1 = immunity to 0 = immunity.
|
||||
|
||||
// Doing it this way makes multiplicative stacking not get out of hand, so two modifiers that give 0.5 protection will be combined to 0.75 in the end.
|
||||
for(var/thing in modifiers)
|
||||
var/datum/modifier/M = thing
|
||||
if(!isnull(M.siemens_coefficient))
|
||||
. *= M.siemens_coefficient
|
||||
|
||||
// Code that calls this expects 1 = immunity so we need to invert again.
|
||||
. = 1 - .
|
||||
. = min(., 1.0)
|
||||
|
||||
// Shot with taser/stunvolver
|
||||
/mob/living/simple_mob/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null)
|
||||
@@ -218,16 +251,28 @@
|
||||
// Armor
|
||||
/mob/living/simple_mob/getarmor(def_zone, attack_flag)
|
||||
var/armorval = armor[attack_flag]
|
||||
if(!armorval)
|
||||
return 0
|
||||
else
|
||||
if(isnull(armorval))
|
||||
armorval = 0
|
||||
|
||||
for(var/thing in modifiers)
|
||||
var/datum/modifier/M = thing
|
||||
var/modifier_armor = LAZYACCESS(M.armor_percent, attack_flag)
|
||||
if(modifier_armor)
|
||||
armorval += modifier_armor
|
||||
|
||||
return armorval
|
||||
|
||||
/mob/living/simple_mob/getsoak(def_zone, attack_flag)
|
||||
var/armorval = armor_soak[attack_flag]
|
||||
if(!armorval)
|
||||
return 0
|
||||
else
|
||||
if(isnull(armorval))
|
||||
armorval = 0
|
||||
|
||||
for(var/thing in modifiers)
|
||||
var/datum/modifier/M = thing
|
||||
var/modifier_armor = LAZYACCESS(M.armor_flat, attack_flag)
|
||||
if(modifier_armor)
|
||||
armorval += modifier_armor
|
||||
|
||||
return armorval
|
||||
|
||||
// Lightning
|
||||
|
||||
@@ -27,3 +27,120 @@
|
||||
|
||||
qdel(H)
|
||||
return 1
|
||||
|
||||
|
||||
/datum/modifier/unit_test
|
||||
|
||||
/datum/unit_test/modifier
|
||||
name = "modifier test template"
|
||||
var/mob/living/subject = null
|
||||
var/subject_type = /mob/living/carbon/human
|
||||
var/list/inputs = list(1.00, 0.75, 0.50, 0.25, 0.00, -0.50, -1.0, -2.0)
|
||||
var/list/expected_outputs = list(1.00, 0.75, 0.50, 0.25, 0.00, -0.50, -1.0, -2.0)
|
||||
var/datum/modifier/test_modifier = null
|
||||
var/issues = 0
|
||||
|
||||
/datum/unit_test/modifier/start_test()
|
||||
// Arrange.
|
||||
subject = new subject_type(get_standard_turf())
|
||||
subject.add_modifier(/datum/modifier/unit_test)
|
||||
test_modifier = subject.get_modifier_of_type(/datum/modifier/unit_test)
|
||||
|
||||
// Act,
|
||||
for(var/i = 1 to inputs.len)
|
||||
set_tested_variable(test_modifier, inputs[i])
|
||||
var/actual = round(get_test_value(subject), 0.01) // Rounding because floating point schannigans.
|
||||
if(actual != expected_outputs[i])
|
||||
issues++
|
||||
log_bad("Input '[inputs[i]]' did not match expected output '[expected_outputs[i]]', but was instead '[actual]'.")
|
||||
|
||||
// Assert.
|
||||
if(issues)
|
||||
fail("[issues] issues were found.")
|
||||
else
|
||||
pass("No issues found.")
|
||||
qdel(subject)
|
||||
return TRUE
|
||||
|
||||
// Override for subtypes.
|
||||
/datum/unit_test/modifier/proc/set_tested_variable(datum/modifier/M, new_value)
|
||||
return
|
||||
|
||||
/datum/unit_test/modifier/proc/get_test_value(mob/living/L)
|
||||
return
|
||||
|
||||
|
||||
/datum/unit_test/modifier/heat_protection
|
||||
name = "MOB: human mob heat protection is calculated correctly"
|
||||
|
||||
/datum/unit_test/modifier/heat_protection/set_tested_variable(datum/modifier/M, new_value)
|
||||
M.heat_protection = new_value
|
||||
|
||||
/datum/unit_test/modifier/heat_protection/get_test_value(mob/living/L)
|
||||
return L.get_heat_protection(1000)
|
||||
|
||||
/datum/unit_test/modifier/heat_protection/simple_mob
|
||||
name = "MOB: simple mob heat protection is calculated correctly"
|
||||
subject_type = /mob/living/simple_mob
|
||||
|
||||
|
||||
/datum/unit_test/modifier/cold_protection
|
||||
name = "MOB: human mob cold protection is calculated correctly"
|
||||
|
||||
/datum/unit_test/modifier/cold_protection/set_tested_variable(datum/modifier/M, new_value)
|
||||
M.cold_protection = new_value
|
||||
|
||||
/datum/unit_test/modifier/cold_protection/get_test_value(mob/living/L)
|
||||
return L.get_cold_protection(50)
|
||||
|
||||
/datum/unit_test/modifier/cold_protection/simple_mob
|
||||
name = "MOB: simple mob cold protection is calculated correctly"
|
||||
subject_type = /mob/living/simple_mob
|
||||
|
||||
|
||||
/datum/unit_test/modifier/shock_protection
|
||||
name = "MOB: human mob shock protection is calculated correctly"
|
||||
inputs = list(3.00, 2.00, 1.50, 1.00, 0.75, 0.50, 0.25, 0.00)
|
||||
expected_outputs = list(-2.00, -1.00, -0.50, 0.00, 0.25, 0.50, 0.75, 1.00)
|
||||
|
||||
/datum/unit_test/modifier/shock_protection/set_tested_variable(datum/modifier/M, new_value)
|
||||
M.siemens_coefficient = new_value
|
||||
|
||||
/datum/unit_test/modifier/shock_protection/get_test_value(mob/living/L)
|
||||
return L.get_shock_protection()
|
||||
|
||||
/datum/unit_test/modifier/shock_protection/simple_mob
|
||||
name = "MOB: simple mob shock protection is calculated correctly"
|
||||
subject_type = /mob/living/simple_mob
|
||||
|
||||
|
||||
/datum/unit_test/modifier/percentage_armor
|
||||
name = "MOB: human mob percentage armor is calculated correctly"
|
||||
inputs = list(100, 75, 50, 25, 0)
|
||||
expected_outputs = list(100, 75, 50, 25, 0)
|
||||
|
||||
/datum/unit_test/modifier/percentage_armor/set_tested_variable(datum/modifier/M, new_value)
|
||||
M.armor_percent = list("melee" = new_value)
|
||||
|
||||
/datum/unit_test/modifier/percentage_armor/get_test_value(mob/living/L)
|
||||
return L.getarmor(null, "melee")
|
||||
|
||||
/datum/unit_test/modifier/percentage_armor/simple_mob
|
||||
name = "MOB: simple mob percentage armor is calculated correctly"
|
||||
subject_type = /mob/living/simple_mob
|
||||
|
||||
|
||||
/datum/unit_test/modifier/percentage_flat
|
||||
name = "MOB: human mob flat armor is calculated correctly"
|
||||
inputs = list(100, 75, 50, 25, 0)
|
||||
expected_outputs = list(100, 75, 50, 25, 0)
|
||||
|
||||
/datum/unit_test/modifier/percentage_flat/set_tested_variable(datum/modifier/M, new_value)
|
||||
M.armor_flat = list("melee" = new_value)
|
||||
|
||||
/datum/unit_test/modifier/percentage_flat/get_test_value(mob/living/L)
|
||||
return L.getsoak(null, "melee")
|
||||
|
||||
/datum/unit_test/modifier/percentage_flat/simple_mob
|
||||
name = "MOB: simple mob flat armor is calculated correctly"
|
||||
subject_type = /mob/living/simple_mob
|
||||
|
||||
Reference in New Issue
Block a user