diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm
index f9be57a01d0..677d220cd5e 100644
--- a/code/game/objects/items/stacks/sheets/leather.dm
+++ b/code/game/objects/items/stacks/sheets/leather.dm
@@ -208,6 +208,19 @@ GLOBAL_LIST_INIT(sinew_recipes, list (
use(1)
else
to_chat(user, "You can't improve [D] any further!")
+ else if(isrobot(target))
+ var/mob/living/silicon/robot/R = target
+ if(istype(R.module, /obj/item/robot_module/miner))
+ var/datum/armor/current_armor = R.armor
+ if(current_armor.getRating(MELEE) < 60)
+ R.armor = current_armor.setRating(melee_value = min(current_armor.getRating(MELEE) + 10, 60))
+ to_chat(user, "You strengthen [target], improving its resistance against melee attacks.")
+ use(1)
+ else
+ to_chat(user, "You can't improve [R] any further!")
+ else
+ to_chat(user, "[R]'s armor can not be improved!")
+
/obj/item/stack/sheet/animalhide/ashdrake
name = "ash drake hide"
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 60cdacafe29..31baf65f7dc 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -493,6 +493,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
modtype = selected_module
designation = selected_module
module.add_languages(src)
+ module.add_armor(src)
module.add_subsystems_and_actions(src)
if(!static_radio_channels)
radio.config(module.channels)
@@ -541,6 +542,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
add_language("Robot Talk", TRUE)
if("lava" in weather_immunities) // Remove the lava-immunity effect given by a printable upgrade
weather_immunities -= "lava"
+ armor = getArmor(arglist(initial(armor)))
status_flags |= CANPUSH
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 95e40f14323..b2e234ba5b7 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -5,6 +5,7 @@
w_class = 100
item_state = "electronic"
flags = CONDUCT
+ var/module_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0)
/// Has the AI hacked the borg module, allowing access to the malf AI exclusive item.
var/malfhacked = FALSE
@@ -85,7 +86,9 @@
QDEL_LIST_CONTENTS(special_rechargables)
return ..()
-
+/obj/item/robot_module/Initialize(mapload)
+ . = ..()
+ module_armor = getArmor(arglist(module_armor))
/**
* Searches through the various module lists for the given `item_type`, deletes and removes the item from all supplied lists, if the item is found.
*
@@ -263,6 +266,11 @@
R.add_language("Clownish", 0)
R.add_language("Tkachi", 0)
+///Adds armor to a cyborg. Normaly resets it to 0 across the board, unless the module has an armor defined.
+/obj/item/robot_module/proc/add_armor(mob/living/silicon/robot/R)
+ R.armor = module_armor
+
+
/// Adds anything in `subsystems` to the robot's verbs, and grants any actions that are in `module_actions`.
/obj/item/robot_module/proc/add_subsystems_and_actions(mob/living/silicon/robot/R)
R.verbs |= subsystems
@@ -539,6 +547,7 @@
/obj/item/robot_module/miner
name = "miner robot module"
module_type = "Miner"
+ module_armor = list(MELEE = 20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0)
module_actions = list(/datum/action/innate/robot_sight/meson)
custom_removals = list("KA modkits")
basic_modules = list(
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 398686060a1..81cc4b5ccca 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -6,6 +6,12 @@
weather_immunities = list("ash")
mob_biotypes = MOB_ROBOTIC
flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
+
+ // You can define armor as a list in datum definition (e.g. `armor = list("fire" = 80, "brute" = 10)`),
+ // which would be converted to armor datum during initialization.
+ // Setting `armor` to a list on an *existing* object would inevitably runtime. Use `getArmor()` instead.
+ var/datum/armor/armor
+
var/syndicate = FALSE
var/const/MAIN_CHANNEL = "Main Frequency"
var/lawchannel = MAIN_CHANNEL // Default channel on which to state laws
@@ -49,6 +55,12 @@
diag_hud.add_to_hud(src)
diag_hud_set_status()
diag_hud_set_health()
+ if(islist(armor))
+ armor = getArmor(arglist(armor))
+ else if(!armor)
+ armor = getArmor()
+ else if(!istype(armor, /datum/armor))
+ stack_trace("Invalid type [armor.type] found in .armor during /obj Initialize()")
/mob/living/silicon/med_hud_set_health()
@@ -211,19 +223,39 @@
/mob/living/silicon/bullet_act(obj/item/projectile/Proj)
-
-
if(!Proj.nodamage)
+ var/damage = run_armor(Proj.damage, Proj.damage_type, Proj.flag, 0, Proj.armour_penetration_flat, Proj.armour_penetration_percentage)
switch(Proj.damage_type)
if(BRUTE)
- adjustBruteLoss(Proj.damage)
+ adjustBruteLoss(damage)
if(BURN)
- adjustFireLoss(Proj.damage)
+ adjustFireLoss(damage)
Proj.on_hit(src,2)
return 2
+/mob/living/silicon/attacked_by(obj/item/I, mob/living/user, def_zone)
+ send_item_attack_message(I, user)
+ if(I.force)
+ var/bonus_damage = 0
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ bonus_damage = H.physiology.melee_bonus
+ var/damage = run_armor(I.force + bonus_damage, I.damtype, MELEE, 0, I.armour_penetration_flat, I.armour_penetration_percentage)
+ apply_damage(damage, I.damtype, def_zone)
+
+///returns the damage value of the attack after processing the silicons's various armor protections
+/mob/living/silicon/proc/run_armor(damage_amount, damage_type, damage_flag = 0, attack_dir, armour_penetration_flat = 0, armour_penetration_percentage = 0)
+ if(damage_type != BRUTE && damage_type != BURN)
+ return 0
+ var/armor_protection = 0
+ if(damage_flag)
+ armor_protection = armor.getRating(damage_flag)
+ if(armor_protection) //Only apply weak-against-armor/hollowpoint effects if there actually IS armor.
+ armor_protection = clamp((armor_protection * ((100 - armour_penetration_percentage) / 100)) - armour_penetration_flat, min(armor_protection, 0), 100)
+ return round(damage_amount * (100 - armor_protection) * 0.01, DAMAGE_PRECISION)
+
/mob/living/silicon/apply_effect(effect = 0, effecttype = STUN, blocked = 0)
return FALSE //The only effect that can hit them atm is flashes and they still directly edit so this works for now
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index 36d11b0f2a2..7cf7fec5fd2 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -10,6 +10,7 @@
if(prob(8))
flash_eyes(affect_silicon = 1)
add_attack_logs(M, src, "Alien attacked")
+ damage = run_armor(damage, BRUTE, MELEE)
adjustBruteLoss(damage)
updatehealth()
else
@@ -22,6 +23,7 @@
. = ..()
if(.)
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
+ damage = run_armor(damage, M.melee_damage_type, MELEE, 0, M.armour_penetration_flat, M.armour_penetration_percentage)
switch(M.melee_damage_type)
if(BRUTE)
adjustBruteLoss(damage)
@@ -47,7 +49,7 @@
to_chat(user, "You don't want to hurt [src]!")
return FALSE
..(user, TRUE)
- adjustBruteLoss(rand(10, 15))
+ adjustBruteLoss(run_armor(rand(10, 15), BRUTE, MELEE))
playsound(loc, "punch", 25, 1, -1)
visible_message("[user] has punched [src]!", "[user] has punched [src]!")
return TRUE