diff --git a/aurorastation.dme b/aurorastation.dme
index 39cc61ad5bc..ed99b98a33e 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -2353,6 +2353,7 @@
#include "code\modules\organs\organ_stump.dm"
#include "code\modules\organs\pain.dm"
#include "code\modules\organs\robolimbs.dm"
+#include "code\modules\organs\tendons.dm"
#include "code\modules\organs\wound.dm"
#include "code\modules\organs\internal\_internal.dm"
#include "code\modules\organs\internal\appendix.dm"
diff --git a/code/__defines/damage_organs.dm b/code/__defines/damage_organs.dm
index d7243e67485..42418f1a6a3 100644
--- a/code/__defines/damage_organs.dm
+++ b/code/__defines/damage_organs.dm
@@ -46,11 +46,10 @@
#define ORGAN_ADV_ROBOT (1<<9)
#define ORGAN_PLANT (1<<10)
#define ORGAN_ARTERY_CUT (1<<11)
-#define ORGAN_TENDON_CUT (1<<12)
-#define ORGAN_LIFELIKE (1<<13) // Robotic, made to appear organic.
+#define ORGAN_LIFELIKE (1<<12) // Robotic, made to appear organic.
// the largest bitflag, in the WORLD
-#define ORGAN_DAMAGE_STATES ORGAN_CUT_AWAY|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_DESTROYED|ORGAN_SPLINTED|ORGAN_DEAD|ORGAN_MUTATED|ORGAN_ARTERY_CUT|ORGAN_TENDON_CUT
+#define ORGAN_DAMAGE_STATES ORGAN_CUT_AWAY|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_DESTROYED|ORGAN_SPLINTED|ORGAN_DEAD|ORGAN_MUTATED|ORGAN_ARTERY_CUT
// Limb behaviour defines.
#define ORGAN_CAN_AMPUTATE (1<<0) //Can this organ be amputated?
diff --git a/code/game/gamemodes/cult/structures/altar.dm b/code/game/gamemodes/cult/structures/altar.dm
index c472aa000f8..6c21b0c34d8 100644
--- a/code/game/gamemodes/cult/structures/altar.dm
+++ b/code/game/gamemodes/cult/structures/altar.dm
@@ -18,10 +18,10 @@
to_chat(H, SPAN_WARNING("Severed artery found in [O.name], repairing..."))
if(do_after(user, 20))
O.status &= ~ORGAN_ARTERY_CUT
- if(O.status & ORGAN_TENDON_CUT)
+ if(istype(O.tendon) && !O.tendon.intact)
to_chat(H, SPAN_WARNING("Severed tendon found in [O.name], repairing..."))
if(do_after(user, 20))
- O.status &= ~ORGAN_TENDON_CUT
+ O.tendon.heal()
if(O.status & ORGAN_BROKEN)
to_chat(H, SPAN_WARNING("Broken bone found in [O.name], repairing..."))
if(do_after(user, 20))
diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm
index d8a5674f4da..eb170594848 100644
--- a/code/game/gamemodes/vampire/vampire_powers.dm
+++ b/code/game/gamemodes/vampire/vampire_powers.dm
@@ -616,8 +616,8 @@
if(E.status & ORGAN_ARTERY_CUT)
E.status &= ~ORGAN_ARTERY_CUT
blood_used += 2
- if(E.status & ORGAN_TENDON_CUT)
- E.status &= ~ORGAN_TENDON_CUT
+ if(istype(E.tendon) && !E.tendon.intact)
+ E.tendon.heal()
blood_used += 2
if(E.status & ORGAN_BROKEN)
E.status &= ~ORGAN_BROKEN
diff --git a/code/game/machinery/body_scanner.dm b/code/game/machinery/body_scanner.dm
index dbd86a1c290..7578b0191b7 100644
--- a/code/game/machinery/body_scanner.dm
+++ b/code/game/machinery/body_scanner.dm
@@ -503,8 +503,8 @@
wounds += "Appears to be composed of inorganic material."
if (O.status & ORGAN_ARTERY_CUT)
wounds += "Severed [O.artery_name]."
- if (O.status & ORGAN_TENDON_CUT)
- wounds += "Severed [O.tendon_name]."
+ if(istype(O.tendon) && !O.tendon.intact)
+ wounds += "Severed [O.tendon.name]."
if (O.status & ORGAN_SPLINTED)
wounds += "Splinted."
if (O.status & ORGAN_BLEEDING)
@@ -714,7 +714,7 @@
if(e.status & ORGAN_ARTERY_CUT)
internal_bleeding = "Arterial bleeding."
- if(e.status & ORGAN_TENDON_CUT)
+ if(istype(e.tendon) && !e.tendon.intact)
severed_tendon = "Severed tendon."
if(istype(e, /obj/item/organ/external/chest) && occ["lung_ruptured"])
lung_ruptured = "Lung ruptured."
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index b152e9e9122..b11b9aeeaa2 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -248,7 +248,7 @@ BREATH ANALYZER
if(!found_bleed && (e.status & ORGAN_ARTERY_CUT))
dat += "Arterial bleeding detected. Advanced scanner required for location."
found_bleed = TRUE
- if(!found_tendon && (e.status & ORGAN_TENDON_CUT))
+ if(!found_tendon && (istype(e.tendon) && !e.tendon.intact))
dat += "Tendon or ligament damage detected. Advanced scanner required for location."
found_tendon = TRUE
if(found_disloc && found_bleed && found_tendon)
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index 97cc4b8c92e..e732d3689a6 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -63,6 +63,12 @@
var/supports_children = TRUE
var/list/internal_organs = list() // Internal organs of this body part
+ var/datum/tendon/tendon
+ var/tendon_path = /datum/tendon
+ var/tendon_name = "tendon" // Name of the limb's tendon. Achilles heel, etc.
+ var/tendon_dt // Damage threshold required to possibly snap a tendon
+ var/list/tendon_msgs = list("tore apart", "ripped away")
+
var/damage_msg = "You feel an intense pain!"
var/broken_description
var/open = 0
@@ -72,7 +78,6 @@
var/encased // Needs to be opened with a saw to access the organs.
var/joint = "joint" // Descriptive string used in dislocation.
var/artery_name = "artery" //Name of the artery. Cartoid, etc.
- var/tendon_name = "tendon" //Name of the limb's tendon. Achilles heel, etc.
var/amputation_point // Descriptive string used in amputation.
var/dislocated = 0 // If you target a joint, you can dislocate the limb, causing temporary damage to the organ.
@@ -227,6 +232,9 @@
get_icon()
+ if((limb_flags & ORGAN_HAS_TENDON) && !BP_IS_ROBOTIC(src))
+ tendon = new tendon_path(src, tendon_name, tendon_dt, tendon_msgs)
+
/obj/item/organ/external/replaced(var/mob/living/carbon/human/target)
..()
if(istype(owner))
@@ -291,8 +299,8 @@
handle_limb_gibbing(used_weapon, brute, burn)
if(brute_dam + brute > min_broken_damage && prob(brute_dam + brute * (1 + blunt)))
- if(damage_flags & DAM_EDGE)
- sever_tendon()
+ if((brute && !blunt) && istype(tendon) && brute_dam + brute > tendon.threshold)
+ tendon.sever()
if(brute_dam > FRACTURE_AND_TENDON_DAM_THRESHOLD)
fracture()
else
@@ -472,14 +480,14 @@ This function completely restores a damaged organ to perfect condition.
//Possibly trigger an internal wound, too.
var/local_damage = brute_dam + burn_dam + damage
if(damage > 15 && !(type in list(BURN, LASER)) && local_damage > 30 && !(status & ORGAN_ROBOT))
- var/internal_damage
if(prob(damage) && sever_artery())
- internal_damage = TRUE
- if(prob(Ceiling(damage / 4)) && type == CUT && sever_tendon())
- internal_damage = TRUE
- if(internal_damage)
owner.custom_pain("You feel something rip in your [name]!", 25)
+ if(istype(tendon) && type == CUT && !(status & ORGAN_ROBOT))
+ var/DT = tendon.threshold
+ if(DT && local_damage > DT && damage > (DT / 2) && prob(damage))
+ tendon.sever()
+
//Burn damage can cause fluid loss due to blistering and cook-off
if((type in list(BURN, LASER)) && (damage > 5 || damage + burn_dam >= 15) && !BP_IS_ROBOTIC(src))
var/fluid_loss_severity
@@ -814,10 +822,7 @@ Note that amputating the affected organ does in fact remove the infection from t
//Bone fractures
if(config.bones_can_break && brute_dam > min_broken_damage * config.organ_health_multiplier && !(status & ORGAN_ROBOT))
- if(cut_dam > brute_dam * 0.5)
- sever_tendon()
- else
- fracture()
+ fracture()
update_damage_ratios()
/obj/item/organ/external/proc/update_damage_ratios()
@@ -1150,9 +1155,9 @@ Note that amputating the affected organ does in fact remove the infection from t
/obj/item/organ/external/is_usable()
if(is_dislocated())
return FALSE
- if(status & ORGAN_TENDON_CUT)
+ if(istype(tendon) && !tendon.intact)
return FALSE
- if(parent && (parent.status & ORGAN_TENDON_CUT))
+ if(parent && (istype(parent.tendon) && !parent.tendon.intact))
return FALSE
if(can_feel_pain() && get_pain() > pain_disability_threshold)
return FALSE
@@ -1356,25 +1361,6 @@ Note that amputating the affected organ does in fact remove the infection from t
status |= ORGAN_ARTERY_CUT
return TRUE
-/obj/item/organ/external/proc/sever_tendon()
- if(!(limb_flags & ORGAN_HAS_TENDON) || (status & ORGAN_ROBOT) || (status & ORGAN_TENDON_CUT))
- return FALSE
-
- . = TRUE
- playsound(src.loc, 'sound/effects/snap.ogg', 40, 1, -2)
- status |= ORGAN_TENDON_CUT
- if(!owner)
- return
-
- var/message = pick("tore apart", "ripped away")
- owner.visible_message(\
- "You hear a loud snapping sound coming from \the [owner]!",\
- "Something feels like it [message] in your [name]!",\
- "You hear a sickening snap!")
- if(owner.species && owner.can_feel_pain())
- owner.emote("scream")
- owner.flash_strong_pain()
-
// Damage procs
/obj/item/organ/external/proc/get_brute_damage()
return brute_dam
diff --git a/code/modules/organs/subtypes/parasite.dm b/code/modules/organs/subtypes/parasite.dm
index 3b45175eb52..da321ba6c94 100644
--- a/code/modules/organs/subtypes/parasite.dm
+++ b/code/modules/organs/subtypes/parasite.dm
@@ -251,8 +251,8 @@
O.status &= ~ORGAN_ARTERY_CUT
owner.visible_message(SPAN_WARNING("The severed artery in \the [owner]'s [O] stitches itself back together..."), SPAN_NOTICE("The severed artery in your [O] stitches itself back together..."))
healed = TRUE
- else if(O.status & ORGAN_TENDON_CUT)
- O.status &= ~ORGAN_TENDON_CUT
+ else if(istype(O.tendon) && !O.tendon.intact)
+ O.tendon.heal()
owner.visible_message(SPAN_WARNING("The severed tendon in \the [owner]'s [O] stitches itself back together..."), SPAN_NOTICE("The severed tendon in your [O] stitches itself back together..."))
healed = TRUE
else if(O.status & ORGAN_BROKEN)
diff --git a/code/modules/organs/subtypes/standard.dm b/code/modules/organs/subtypes/standard.dm
index 5dc6a68eeca..a5cb54c25ab 100644
--- a/code/modules/organs/subtypes/standard.dm
+++ b/code/modules/organs/subtypes/standard.dm
@@ -176,10 +176,6 @@
. = ..()
owner.update_hud_hands()
-/obj/item/organ/external/hand/sever_tendon()
- . = ..()
- owner.update_hud_hands()
-
/obj/item/organ/external/hand/removed()
owner.drop_from_inventory(owner.gloves)
owner.update_hud_hands()
@@ -256,4 +252,4 @@
/obj/item/organ/external/head/droplimb(var/clean, var/disintegrate = DROPLIMB_EDGE, var/ignore_children = null)
if(iszombie(owner))
return ..(disintegrate = DROPLIMB_BLUNT)
- return ..()
\ No newline at end of file
+ return ..()
diff --git a/code/modules/organs/tendons.dm b/code/modules/organs/tendons.dm
new file mode 100644
index 00000000000..443ebceb675
--- /dev/null
+++ b/code/modules/organs/tendons.dm
@@ -0,0 +1,55 @@
+/datum/tendon
+ var/name = "tendon"
+ var/threshold
+ var/intact = TRUE
+
+ var/list/messages
+
+ var/obj/item/organ/external/parent
+
+/datum/tendon/New(var/obj/item/organ/external/E, var/name, var/damage_threshold, var/list/damage_msgs)
+ if(!istype(E))
+ crash_with("Tendon created with invalid parent organ: [E]")
+ qdel(src)
+ return
+
+ parent = E
+
+ if(name)
+ src.name = name
+ if(islist(damage_msgs))
+ messages = damage_msgs
+
+ if(damage_threshold)
+ threshold = damage_threshold
+ else
+ threshold = parent.min_broken_damage
+
+/datum/tendon/proc/heal()
+ if(!parent?.owner || intact)
+ return FALSE
+
+ . = intact = TRUE
+
+/datum/tendon/proc/sever()
+ if(!parent?.owner || !intact)
+ return FALSE
+
+ playsound(parent.owner.loc, 'sound/effects/snap.ogg', 40, 1, -2)
+ intact = FALSE
+
+ if(parent.owner.species && parent.owner.can_feel_pain())
+ parent.owner.emote("scream")
+ parent.owner.flash_strong_pain()
+ parent.owner.custom_pain("You feel something [pick(messages)] in your [parent.owner.name]!", 25)
+ parent.owner.visible_message(SPAN_WARNING("You hear a loud snapping sound coming from [parent.owner]!"),
+ blind_message = "You hear a sickening snap!")
+ else
+ parent.owner.visible_message(SPAN_WARNING("You hear a loud snapping sound coming from [parent.owner]!"),\
+ SPAN_DANGER("Something feels like it [pick(messages)] in your [parent.name]!"),\
+ "You hear a sickening snap!")
+
+ if(istype(parent, /obj/item/organ/external/hand))
+ parent.owner.update_hud_hands()
+
+ return TRUE
diff --git a/code/modules/psionics/complexus/complexus_process.dm b/code/modules/psionics/complexus/complexus_process.dm
index 6945df397c8..0cae991b7e2 100644
--- a/code/modules/psionics/complexus/complexus_process.dm
+++ b/code/modules/psionics/complexus/complexus_process.dm
@@ -190,9 +190,9 @@
E.status &= ~ORGAN_ARTERY_CUT
return
- if(E.status & ORGAN_TENDON_CUT)
+ if(istype(E.tendon) && !E.tendon.intact)
to_chat(H, SPAN_NOTICE("Your autoredactive faculty repairs the severed tendon in your [E.name]."))
- E.status &= ~ORGAN_TENDON_CUT
+ E.tendon.heal()
return TRUE
for(var/datum/wound/W in E.wounds)
diff --git a/code/modules/psionics/faculties/redaction.dm b/code/modules/psionics/faculties/redaction.dm
index 9727426001f..448d1201752 100644
--- a/code/modules/psionics/faculties/redaction.dm
+++ b/code/modules/psionics/faculties/redaction.dm
@@ -83,9 +83,9 @@
to_chat(user, SPAN_NOTICE("You painstakingly mend the torn veins in \the [E], stemming the internal bleeding."))
E.status &= ~ORGAN_ARTERY_CUT
return TRUE
- if(E.status & ORGAN_TENDON_CUT)
+ if(istype(E.tendon) && !E.tendon.intact)
to_chat(user, SPAN_NOTICE("You interleave and repair the severed tendon in \the [E]."))
- E.status &= ~ORGAN_TENDON_CUT
+ E.tendon.heal()
return TRUE
if(E.status & ORGAN_BROKEN)
to_chat(user, SPAN_NOTICE("You coax shattered bones to come together and fuse, mending the break."))
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm
index 1f8b1acff62..7e1c97eab67 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm
@@ -1279,8 +1279,8 @@
var/mob/living/carbon/human/H = M
for (var/A in H.organs)
var/obj/item/organ/external/E = A
- if(E.status & ORGAN_TENDON_CUT)
- E.status &= ~ORGAN_TENDON_CUT
+ if(istype(E.tendon) && !E.tendon.intact)
+ E.tendon.heal()
return 1
if(E.status & ORGAN_ARTERY_CUT)
diff --git a/code/modules/spell_system/spells/spell_list/others/generic/mend.dm b/code/modules/spell_system/spells/spell_list/others/generic/mend.dm
index a68755fd606..b7796b08caa 100644
--- a/code/modules/spell_system/spells/spell_list/others/generic/mend.dm
+++ b/code/modules/spell_system/spells/spell_list/others/generic/mend.dm
@@ -67,9 +67,9 @@
E.stage = 0
return 1
- if(E.status & ORGAN_TENDON_CUT)
+ if(istype(E.tendon) && !E.tendon.intact)
to_chat(user, "You place your hands over [target]'s [E.name], joining the two ends of their [E.tendon_name] in the process.")
- E.status &= ~ORGAN_TENDON_CUT
+ E.tendon.heal()
return 1
for(var/obj/item/organ/I in E.internal_organs)
@@ -79,4 +79,4 @@
return 1
to_chat(user, "You can find nothing within \the [target]'s [E.name] to mend.")
- return 1
\ No newline at end of file
+ return 1
diff --git a/code/modules/surgery/other.dm b/code/modules/surgery/other.dm
index edeec246065..925c7ce5374 100644
--- a/code/modules/surgery/other.dm
+++ b/code/modules/surgery/other.dm
@@ -201,7 +201,7 @@
return FALSE
var/obj/item/organ/external/affected = target.get_organ(target_zone)
- return affected && (affected.status & ORGAN_TENDON_CUT) && affected.open >= ORGAN_OPEN_RETRACTED
+ return affected && istype(affected.tendon) && !affected.tendon.intact && affected.open >= ORGAN_OPEN_RETRACTED
/decl/surgery_step/fix_tendon/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
@@ -214,7 +214,7 @@
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message(SPAN_NOTICE("[user] has reattached the [affected.tendon_name] in [target]'s [affected.name] with \the [tool]."), \
SPAN_NOTICE("You have reattached the [affected.tendon_name] in [target]'s [affected.name] with \the [tool]."))
- affected.status &= ~ORGAN_TENDON_CUT
+ affected.tendon.heal()
affected.update_damages()
/decl/surgery_step/fix_tendon/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)