mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-25 00:51:55 +00:00
* Fix underlying armor logic and fix bug with constructed ripleys having zero armor (#73319) ## About The Pull Request See title ## Why It's Good For The Game Messed up one of the armor procs; it changed the given values but never carried over existing values. So you would end up with an armor of that one specific value and nothing else. This wasn't actually used anywhere other than mecha, lava burning, and sentient viruses, so the issue isn't that bad. It's still an issue however. ## Changelog 🆑 fix: Mechs no longer have zero armor when built. /🆑 * Fix underlying armor logic and fix bug with constructed ripleys having zero armor --------- Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
234 lines
6.7 KiB
Plaintext
234 lines
6.7 KiB
Plaintext
/// Assosciative list of type -> armor. Used to ensure we always hold a reference to default armor datums
|
|
GLOBAL_LIST_INIT(armor_by_type, generate_armor_type_cache())
|
|
|
|
/proc/generate_armor_type_cache()
|
|
var/list/armor_cache = list()
|
|
for(var/datum/armor/armor_type as anything in subtypesof(/datum/armor))
|
|
armor_type = new armor_type
|
|
armor_cache[armor_type.type] = armor_type
|
|
armor_type.GenerateTag()
|
|
return armor_cache
|
|
|
|
/**
|
|
* Gets an armor type datum using the given type by formatting it into the expected datum tag
|
|
*/
|
|
/proc/get_armor_by_type(armor_type)
|
|
var/armor = locate(replacetext("[armor_type]", "/", "-"))
|
|
if(armor)
|
|
return armor
|
|
if(armor_type == /datum/armor)
|
|
CRASH("Attempted to get the base armor type, you probably meant to use /datum/armor/none")
|
|
CRASH("Attempted to get an armor type that did not exist! '[armor_type]'")
|
|
|
|
/**
|
|
* The armor datum holds information about different types of armor that an atom can have.
|
|
* It also contains logic and helpers for calculating damage and effective damage
|
|
*/
|
|
/datum/armor
|
|
VAR_PROTECTED/acid = 0
|
|
VAR_PROTECTED/bio = 0
|
|
VAR_PROTECTED/bomb = 0
|
|
VAR_PROTECTED/bullet = 0
|
|
VAR_PROTECTED/consume = 0
|
|
VAR_PROTECTED/energy = 0
|
|
VAR_PROTECTED/laser = 0
|
|
VAR_PROTECTED/fire = 0
|
|
VAR_PROTECTED/melee = 0
|
|
VAR_PROTECTED/wound = 0
|
|
|
|
/// A version of armor with no protections
|
|
/datum/armor/none
|
|
|
|
/// A version of armor that cannot be modified and will always return itself when attempted to be modified
|
|
/datum/armor/immune
|
|
|
|
/datum/armor/Destroy(force, ...)
|
|
if(!force && tag)
|
|
return QDEL_HINT_LETMELIVE
|
|
|
|
// something really wants us gone
|
|
datum_flags &= ~DF_USE_TAG
|
|
tag = null
|
|
return ..()
|
|
|
|
/datum/armor/GenerateTag()
|
|
..()
|
|
tag = replacetext("[type]", "/", "-")
|
|
|
|
/datum/armor/vv_edit_var(var_name, var_value)
|
|
return FALSE
|
|
|
|
/datum/armor/can_vv_mark()
|
|
return FALSE
|
|
|
|
/datum/armor/vv_get_dropdown()
|
|
return list("", "MUST MODIFY ARMOR VALUES ON THE PARENT ATOM")
|
|
|
|
/datum/armor/CanProcCall(procname)
|
|
return FALSE
|
|
|
|
/// Generate a brand new armor datum with the modifiers given, if ARMOR_ALL is specified only that modifier is used
|
|
/datum/armor/proc/generate_new_with_modifiers(list/modifiers)
|
|
var/datum/armor/new_armor = new
|
|
|
|
var/all_keys = ARMOR_LIST_ALL()
|
|
if(ARMOR_ALL in modifiers)
|
|
var/modifier_all = modifiers[ARMOR_ALL]
|
|
if(!modifier_all)
|
|
return src
|
|
for(var/mod in all_keys)
|
|
new_armor.vars[mod] = vars[mod] + modifier_all
|
|
return new_armor
|
|
|
|
for(var/modifier in modifiers)
|
|
if(modifier in all_keys)
|
|
new_armor.vars[modifier] = vars[modifier] + modifiers[modifier]
|
|
else
|
|
stack_trace("Attempt to call generate_new_with_modifiers with illegal modifier '[modifier]'! Ignoring it")
|
|
return new_armor
|
|
|
|
/datum/armor/immune/generate_new_with_modifiers(list/modifiers)
|
|
return src
|
|
|
|
/// Generate a brand new armor datum with the multiplier given, if ARMOR_ALL is specified only that modifer is used
|
|
/datum/armor/proc/generate_new_with_multipliers(list/multipliers)
|
|
var/datum/armor/new_armor = new
|
|
|
|
var/all_keys = ARMOR_LIST_ALL()
|
|
if(ARMOR_ALL in multipliers)
|
|
var/multiplier_all = multipliers[ARMOR_ALL]
|
|
if(!multiplier_all)
|
|
return src
|
|
for(var/multiplier in all_keys)
|
|
new_armor.vars[multiplier] = vars[multiplier] * multiplier_all
|
|
return new_armor
|
|
|
|
for(var/multiplier in multipliers)
|
|
if(multiplier in all_keys)
|
|
new_armor.vars[multiplier] = vars[multiplier] * multipliers[multiplier]
|
|
else
|
|
stack_trace("Attempt to call generate_new_with_multipliers with illegal multiplier '[multiplier]'! Ignoring it")
|
|
return new_armor
|
|
|
|
/datum/armor/immune/generate_new_with_multipliers(list/multipliers)
|
|
return src
|
|
|
|
/// Generate a brand new armor datum with the values given, if a value is not present it carries over
|
|
/datum/armor/proc/generate_new_with_specific(list/values)
|
|
var/datum/armor/new_armor = new
|
|
|
|
var/all_keys = ARMOR_LIST_ALL()
|
|
if(ARMOR_ALL in values)
|
|
var/value_all = values[ARMOR_ALL]
|
|
if(!value_all)
|
|
return src
|
|
for(var/mod in all_keys)
|
|
new_armor.vars[mod] = value_all
|
|
return new_armor
|
|
|
|
for(var/armor_rating in all_keys)
|
|
if(armor_rating in values)
|
|
new_armor.vars[armor_rating] = values[armor_rating]
|
|
else
|
|
new_armor.vars[armor_rating] = vars[armor_rating]
|
|
return new_armor
|
|
|
|
/datum/armor/immune/generate_new_with_specific(list/values)
|
|
return src
|
|
|
|
/// Gets the rating of armor for the specified rating
|
|
/datum/armor/proc/get_rating(rating)
|
|
// its not that I dont trust coders, its just that I don't trust coders
|
|
if(!(rating in ARMOR_LIST_ALL()))
|
|
CRASH("Attempted to get a rating '[rating]' that doesnt exist")
|
|
return vars[rating]
|
|
|
|
/datum/armor/immune/get_rating(rating)
|
|
return 100
|
|
|
|
/// Converts all the ratings of the armor into a list, optionally inversed
|
|
/datum/armor/proc/get_rating_list(inverse = FALSE)
|
|
var/ratings = list()
|
|
for(var/rating in ARMOR_LIST_ALL())
|
|
var/value = vars[rating]
|
|
if(inverse)
|
|
value *= -1
|
|
ratings[rating] = value
|
|
return ratings
|
|
|
|
/datum/armor/immune/get_rating_list(inverse)
|
|
var/ratings = ..() // get all ratings
|
|
for(var/rating in ratings)
|
|
ratings[rating] = 100 // and set them to 100
|
|
return ratings
|
|
|
|
/// Returns a new armor datum with the given armor added onto this one
|
|
/datum/armor/proc/add_other_armor(datum/armor/other)
|
|
if(ispath(other))
|
|
other = get_armor_by_type(other)
|
|
return generate_new_with_modifiers(other.get_rating_list())
|
|
|
|
/datum/armor/immune/add_other_armor(datum/armor/other)
|
|
return src
|
|
|
|
/// Returns a new armor datum with the given armor removed from this one
|
|
/datum/armor/proc/subtract_other_armor(datum/armor/other)
|
|
if(ispath(other))
|
|
other = get_armor_by_type(other)
|
|
return generate_new_with_modifiers(other.get_rating_list(inverse = TRUE))
|
|
|
|
/datum/armor/immune/subtract_other_armor(datum/armor/other)
|
|
return src
|
|
|
|
/// Checks if any of the armor values are non-zero, so this technically also counts negative armor!
|
|
/datum/armor/proc/has_any_armor()
|
|
for(var/rating as anything in ARMOR_LIST_ALL())
|
|
if(vars[rating])
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/datum/armor/immune/has_any_armor()
|
|
return TRUE
|
|
|
|
/**
|
|
* Rounds armor_value down to the nearest 10, divides it by 10 and then converts it to Roman numerals.
|
|
*
|
|
* Arguments:
|
|
* * armor_value - Number we're converting
|
|
*/
|
|
/proc/armor_to_protection_class(armor_value)
|
|
if (armor_value < 0)
|
|
. = "-"
|
|
. += "\Roman[round(abs(armor_value), 10) / 10]"
|
|
return .
|
|
|
|
/**
|
|
* Returns the client readable name of an armor type
|
|
*
|
|
* Arguments:
|
|
* * armor_type - The type to convert
|
|
*/
|
|
/proc/armor_to_protection_name(armor_type)
|
|
switch(armor_type)
|
|
if(ACID)
|
|
return "ACID"
|
|
if(BIO)
|
|
return "BIOHAZARD"
|
|
if(BOMB)
|
|
return "EXPLOSIVE"
|
|
if(BULLET)
|
|
return "BULLET"
|
|
if(CONSUME)
|
|
return "CONSUMING"
|
|
if(ENERGY)
|
|
return "ENERGY"
|
|
if(FIRE)
|
|
return "FIRE"
|
|
if(LASER)
|
|
return "LASER"
|
|
if(MELEE)
|
|
return "MELEE"
|
|
if(WOUND)
|
|
return "WOUNDING"
|
|
CRASH("Unknown armor type '[armor_type]'")
|