Files
CHOMPStation2/code/game/objects/items/weapons/material/material_armor.dm
CHOMPStation2 f172e1f5b3 [MIRROR] even more local defines (#8516)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
Co-authored-by: Kashargul <KashL@t-online.de>
2024-06-14 08:28:10 +02:00

415 lines
16 KiB
Plaintext

#define MATERIAL_ARMOR_COEFFICENT 0.05
/*
SEE code/modules/materials/materials.dm FOR DETAILS ON INHERITED DATUM.
This class of armor takes armor and appearance data from a material "datum".
They are also fragile based on material data and many can break/smash apart when hit.
Materials has a var called protectiveness which plays a major factor in how good it is for armor.
With the coefficent being 0.05, this is how strong different levels of protectiveness are (for melee)
For bullets and lasers, material hardness and reflectivity also play a major role, respectively.
Protectiveness | Armor %
0 = 0%
5 = 20%
10 = 33%
15 = 42%
20 = 50%
25 = 55%
30 = 60%
40 = 66%
50 = 71%
60 = 75%
70 = 77%
80 = 80%
*/
// Putting these at /clothing/ level saves a lot of code duplication in armor/helmets/gauntlets/etc
/obj/item/clothing
var/datum/material/material = null // Why isn't this a datum?
var/applies_material_color = TRUE
var/unbreakable = FALSE
var/default_material = null // Set this to something else if you want material attributes on init.
var/material_armor_modifier = 1 // Adjust if you want seperate types of armor made from the same material to have different protectiveness (e.g. makeshift vs real armor)
var/material_slowdown_modifier = 0
var/material_slowdown_multiplier = 0.5
/obj/item/clothing/New(var/newloc, var/material_key)
..(newloc)
if(!material_key)
material_key = default_material
if(material_key) // May still be null if a material was not specified as a default.
set_material(material_key)
/obj/item/clothing/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/clothing/get_material()
return material
// Debating if this should be made an /obj/item/ proc.
/obj/item/clothing/proc/set_material(var/new_material)
material = get_material_by_name(new_material)
if(!material)
qdel(src)
else
name = "[material.display_name] [initial(name)]"
health = round(material.integrity/10)
if(applies_material_color)
color = material.icon_colour
if(material.products_need_process())
START_PROCESSING(SSobj, src)
update_armor()
// This is called when someone wearing the object gets hit in some form (melee, bullet_act(), etc).
// Note that this cannot change if someone gets hurt, as it merely reacts to being hit.
/obj/item/clothing/proc/clothing_impact(var/obj/source, var/damage)
if(material && damage)
material_impact(source, damage)
/obj/item/clothing/proc/material_impact(var/obj/source, var/damage)
if(!material || unbreakable)
return
if(istype(source, /obj/item/projectile))
var/obj/item/projectile/P = source
if(P.pass_flags & PASSGLASS)
if(material.opacity - 0.3 <= 0)
return // Lasers ignore 'fully' transparent material.
if(material.is_brittle())
health = 0
else if(!prob(material.hardness))
health--
if(health <= 0)
shatter()
/obj/item/clothing/proc/shatter()
if(!material)
return
var/turf/T = get_turf(src)
T.visible_message("<span class='danger'>\The [src] [material.destruction_desc]!</span>")
if(istype(loc, /mob/living))
var/mob/living/M = loc
M.drop_from_inventory(src)
if(material.shard_type == SHARD_SHARD) // Wearing glass armor is a bad idea.
var/obj/item/weapon/material/shard/S = material.place_shard(T)
M.embed(S)
playsound(src, "shatter", 70, 1)
qdel(src)
// Might be best to make ablative vests a material armor using a new material to cut down on this copypaste.
/obj/item/clothing/suit/armor/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(!material) // No point checking for reflection.
return ..()
if(material.negation && prob(material.negation)) // Strange and Alien materials, or just really strong materials.
user.visible_message("<span class='danger'>\The [src] completely absorbs [attack_text]!</span>")
return TRUE
if(material.spatial_instability && prob(material.spatial_instability))
user.visible_message("<span class='danger'>\The [src] flashes [user] clear of [attack_text]!</span>")
var/list/turfs = new/list()
for(var/turf/T in orange(round(material.spatial_instability / 10) + 1, user))
if(istype(T,/turf/space)) continue
if(T.density) continue
if(T.x>world.maxx-6 || T.x<6) continue
if(T.y>world.maxy-6 || T.y<6) continue
turfs += T
if(!turfs.len) turfs += pick(/turf in orange(6))
var/turf/picked = pick(turfs)
if(!isturf(picked)) return
var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
spark_system.set_up(5, 0, user.loc)
spark_system.start()
playsound(src, 'sound/effects/teleport.ogg', 50, 1)
user.loc = picked
return PROJECTILE_FORCE_MISS
if(material.reflectivity)
if(istype(damage_source, /obj/item/projectile/energy) || istype(damage_source, /obj/item/projectile/beam))
var/obj/item/projectile/P = damage_source
if(P.reflected) // Can't reflect twice
return ..()
var/reflectchance = (40 * material.reflectivity) - round(damage/3)
reflectchance *= material_armor_modifier
if(!(def_zone in list(BP_TORSO, BP_GROIN)))
reflectchance /= 2
if(P.starting && prob(reflectchance))
visible_message("<span class='danger'>\The [user]'s [src.name] reflects [attack_text]!</span>")
// Find a turf near or on the original location to bounce to
var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/turf/curloc = get_turf(user)
// redirect the projectile
P.redirect(new_x, new_y, curloc, user)
P.reflected = 1
return PROJECTILE_CONTINUE // complete projectile permutation
/proc/calculate_material_armor(amount)
var/result = 1 - MATERIAL_ARMOR_COEFFICENT * amount / (1 + MATERIAL_ARMOR_COEFFICENT * abs(amount))
result = result * 100
result = abs(result - 100)
return round(result)
#undef MATERIAL_ARMOR_COEFFICENT
/obj/item/clothing/proc/update_armor()
if(material)
var/melee_armor = 0, bullet_armor = 0, laser_armor = 0, energy_armor = 0, bomb_armor = 0
melee_armor = calculate_material_armor(material.protectiveness * material_armor_modifier)
bullet_armor = calculate_material_armor((material.protectiveness * (material.hardness / 100) * material_armor_modifier) * 0.7)
laser_armor = calculate_material_armor((material.protectiveness * (material.reflectivity + 1) * material_armor_modifier) * 0.7)
if(material.opacity != 1)
laser_armor *= max(material.opacity - 0.3, 0) // Glass and such has an opacity of 0.3, but lasers should go through glass armor entirely.
energy_armor = calculate_material_armor((material.protectiveness * material_armor_modifier) * 0.4)
bomb_armor = calculate_material_armor((material.protectiveness * material_armor_modifier) * 0.5)
// Makes sure the numbers stay capped.
for(var/number in list(melee_armor, bullet_armor, laser_armor, energy_armor, bomb_armor))
number = between(0, number, 100)
armor["melee"] = melee_armor
armor["bullet"] = bullet_armor
armor["laser"] = laser_armor
armor["energy"] = energy_armor
armor["bomb"] = bomb_armor
if(!isnull(material.conductivity))
siemens_coefficient = between(0, material.conductivity / 10, 10)
var/slowdownModified = between(0, round(material.weight / 10, 0.1), 6)
var/slowdownUncapped = (material_slowdown_multiplier * slowdownModified) - material_slowdown_modifier
slowdown = max(slowdownUncapped, 0)
/obj/item/clothing/suit/armor/material
name = "armor"
default_material = MAT_STEEL
/obj/item/clothing/suit/armor/material/makeshift
name = "sheet armor"
desc = "This appears to be two 'sheets' of a material held together by cable. If the sheets are strong, this could be rather protective."
icon_state = "material_armor_makeshift"
/obj/item/clothing/accessory/material/makeshift/light //Craftable with 4 material sheets, less slowdown, less armour
name = "light armor plate"
desc = "A thin plate of padded material, designed to fit into a plate carrier. Attaches to a plate carrier."
icon = 'icons/obj/clothing/modular_armor.dmi'
icon_state = "armor_light"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
slot = ACCESSORY_SLOT_ARMOR_C
material_armor_modifier = 0.8
material_slowdown_modifier = 0.5 //Subtracted from total slowdown
material_slowdown_multiplier = 0.4 //Multiplied by total slowdown
/obj/item/clothing/accessory/material/makeshift/heavy //Craftable with 8 material sheets, more slowdown, more armour
name = "heavy armor plate"
desc = "A thick plate of padded material, designed to fit into a plate carrier. Attaches to a plate carrier."
icon = 'icons/obj/clothing/modular_armor.dmi'
icon_state = "armor_medium"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
slot = ACCESSORY_SLOT_ARMOR_C
material_armor_modifier = 1.2
material_slowdown_modifier = 0
material_slowdown_multiplier = 0.5
/obj/item/clothing/accessory/material/custom //Not yet craftable, advanced version made with science!
name = "custom armor plate"
desc = "A composite plate of custom machined material, designed to fit into a plate carrier. Attaches to a plate carrier."
icon = 'icons/obj/clothing/modular_armor.dmi'
icon_state = "armor_tactical"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
slot = ACCESSORY_SLOT_ARMOR_C
material_armor_modifier = 1.2
material_slowdown_modifier = 0.5
material_slowdown_multiplier = 0.4
/obj/item/clothing/accessory/material/makeshift/armguards
name = "arm guards"
desc = "A pair of arm pads reinforced with material. Attaches to a plate carrier."
// accessory_icons = list(slot_tie_str = 'icons/mob/modular_armor.dmi', slot_wear_suit_str = 'icons/mob/modular_armor.dmi')
icon = 'icons/obj/clothing/modular_armor.dmi'
icon_override = 'icons/mob/modular_armor.dmi'
icon_state = "armguards_material"
gender = PLURAL
body_parts_covered = ARMS
slot = ACCESSORY_SLOT_ARMOR_A
material_armor_modifier = 0.8
material_slowdown_modifier = 0.8
material_slowdown_multiplier = 0.4
/obj/item/clothing/accessory/material/makeshift/legguards
name = "leg guards"
desc = "A pair of leg guards reinforced with material. Attaches to a plate carrier."
// accessory_icons = list(slot_tie_str = 'icons/mob/modular_armor.dmi', slot_wear_suit_str = 'icons/mob/modular_armor.dmi')
icon = 'icons/obj/clothing/modular_armor.dmi'
icon_override = 'icons/mob/modular_armor.dmi'
icon_state = "legguards_material"
gender = PLURAL
body_parts_covered = LEGS
slot = ACCESSORY_SLOT_ARMOR_L
material_armor_modifier = 0.8
material_slowdown_modifier = 0.8
material_slowdown_multiplier = 0.4
/obj/item/clothing/suit/armor/material/makeshift/durasteel
default_material = "durasteel"
/obj/item/clothing/suit/armor/material/makeshift/glass
default_material = "glass"
// Used to craft sheet armor, and possibly other things in the Future(tm).
/obj/item/weapon/material/armor_plating
name = "armor plating"
desc = "A sheet designed to protect something."
icon = 'icons/obj/items.dmi'
icon_state = "armor_plate"
unbreakable = TRUE
force_divisor = 0.05 // Really bad as a weapon.
thrown_force_divisor = 0.2
var/wired = FALSE
/obj/item/weapon/material/armor_plating/insert
unbreakable = FALSE
name = "plate insert"
desc = "used to craft armor plates for a plate carrier. Trim with a welder for light armor or add a second for heavy armor"
/obj/item/weapon/material/armor_plating/attackby(var/obj/O, mob/user)
if(istype(O, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/S = O
if(wired)
to_chat(user, "<span class='warning'>This already has enough wires on it.</span>")
return
if(S.use(20))
to_chat(user, "<span class='notice'>You attach several wires to \the [src]. Now it needs another plate.</span>")
wired = TRUE
icon_state = "[initial(icon_state)]_wired"
return
else
to_chat(user, "<span class='notice'>You need more wire for that.</span>")
return
if(istype(O, /obj/item/weapon/material/armor_plating))
var/obj/item/weapon/material/armor_plating/second_plate = O
if(!wired && !second_plate.wired)
to_chat(user, "<span class='warning'>You need something to hold the two pieces of plating together.</span>")
return
if(second_plate.material != src.material)
to_chat(user, "<span class='warning'>Both plates need to be the same type of material.</span>")
return
user.drop_from_inventory(src)
user.drop_from_inventory(second_plate)
var/obj/item/clothing/suit/armor/material/makeshift/new_armor = new(null, src.material.name)
user.put_in_hands(new_armor)
qdel(second_plate)
qdel(src)
else
..()
//Make plating inserts for modular armour.
/obj/item/weapon/material/armor_plating/insert/attackby(var/obj/item/O, mob/user)
. = ..()
if(O.has_tool_quality(TOOL_WELDER))
var /obj/item/weapon/weldingtool/S = O.get_welder()
if(S.remove_fuel(0,user))
if(!src || !S.isOn()) return
to_chat(user, "<span class='notice'>You trim down the edges to size.</span>")
user.drop_from_inventory(src)
var/obj/item/clothing/accessory/material/makeshift/light/new_armor = new(null, src.material.name)
user.put_in_hands(new_armor)
qdel(src)
return
if(istype(O, /obj/item/weapon/material/armor_plating/insert))
var/obj/item/weapon/material/armor_plating/insert/second_plate = O
if(second_plate.material != src.material)
to_chat(user, "<span class='warning'>Both plates need to be the same type of material.</span>")
return
to_chat(user, "<span class='notice'>You bond the two plates together.</span>")
user.drop_from_inventory(src)
user.drop_from_inventory(second_plate)
var/obj/item/clothing/accessory/material/makeshift/heavy/new_armor = new(null, src.material.name)
user.put_in_hands(new_armor)
qdel(second_plate)
qdel(src)
return
if(istype(O, /obj/item/weapon/tool/wirecutters))
to_chat(user, "<span class='notice'>You split the plate down the middle, and joint it at the elbow.</span>")
user.drop_from_inventory(src)
var/obj/item/clothing/accessory/material/makeshift/armguards/new_armor = new(null, src.material.name)
user.put_in_hands(new_armor)
qdel(src)
return
if(istype(O, /obj/item/stack/material))
var/obj/item/stack/material/S = O
if(S.material == get_material_by_name("leather"))
if(S.use(2))
to_chat(user, "<span class='notice'>You curve the plate inwards, and add a strap for adjustment.</span>")
user.drop_from_inventory(src)
var/obj/item/clothing/accessory/material/makeshift/legguards/new_armor = new(null, src.material.name)
user.put_in_hands(new_armor)
qdel(src)
return
// Used to craft the makeshift helmet
/obj/item/clothing/head/helmet/bucket
name = "bucket"
desc = "It's a bucket with a large hole cut into it. You could wear it on your head and look really stupid."
flags_inv = HIDEEARS|HIDEEYES|BLOCKHAIR
icon_state = "bucket"
armor = list(melee = 5, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0)
/obj/item/clothing/head/helmet/bucket/wood
name = "wooden bucket"
icon_state = "woodbucket"
/obj/item/clothing/head/helmet/bucket/attackby(var/obj/O, mob/user)
if(istype(O, /obj/item/stack/material))
var/obj/item/stack/material/S = O
if(S.use(2))
to_chat(user, "<span class='notice'>You apply some [S.material.use_name] to \the [src]. Hopefully it'll make the makeshift helmet stronger.</span>")
var/obj/item/clothing/head/helmet/material/makeshift/helmet = new(null, S.material.name)
user.put_in_hands(helmet)
user.drop_from_inventory(src)
qdel(src)
return
else
to_chat(user, "<span class='warning'>You don't have enough material to build a helmet!</span>")
else
..()
/obj/item/clothing/head/helmet/material
name = "helmet"
flags_inv = HIDEEARS|HIDEEYES|BLOCKHAIR
default_material = MAT_STEEL
/obj/item/clothing/head/helmet/material/makeshift
name = "bucket"
desc = "A bucket with plating applied to the outside. Very crude, but could potentially be rather protective, if \
it was plated with something strong."
icon_state = "material_armor_makeshift"
/obj/item/clothing/head/helmet/material/makeshift/durasteel
default_material = "durasteel"