diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 8426edcfcfe..efb94d49631 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -210,13 +210,17 @@
#define O_GBLADDER "gas bladder"
#define O_POLYP "polyp segment"
#define O_ANCHOR "anchoring ligament"
+#define O_REGBRUTE "pneumoregenitor"
+#define O_REGBURN "thermoregenitor"
+#define O_REGOXY "respiroregenitor"
+#define O_REGTOX "toxoregenitor"
#define O_ACID "acid gland"
#define O_EGG "egg sac"
#define O_RESIN "resin spinner"
#define O_AREJECT "immune hub"
#define O_VENTC "morphoplastic node"
#define O_VRLINK "virtual node"
-#define O_ALL list(O_STANDARD, O_MOUTH, O_CELL, O_PLASMA, O_HIVE, O_NUTRIENT, O_STRATA, O_RESPONSE, O_GBLADDER, O_POLYP, O_ANCHOR, O_ACID, O_EGG, O_RESIN, O_AREJECT, O_VENTC, O_VRLINK)
+#define O_ALL list(O_STANDARD, O_MOUTH, O_CELL, O_PLASMA, O_HIVE, O_NUTRIENT, O_STRATA, O_RESPONSE, O_GBLADDER, O_POLYP, O_ANCHOR, O_REGBRUTE, O_REGBURN, O_REGOXY, O_REGTOX, O_ACID, O_EGG, O_RESIN, O_AREJECT, O_VENTC, O_VRLINK)
// External organs, aka limbs
#define BP_L_FOOT "l_foot"
diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm
index 809a5ef8ade..a3c5e654701 100644
--- a/code/modules/mob/living/carbon/human/human_powers.dm
+++ b/code/modules/mob/living/carbon/human/human_powers.dm
@@ -286,8 +286,11 @@
nutrition -= 200
for(var/obj/item/organ/I in internal_organs)
+ if(I.robotic >= ORGAN_ROBOT) // No free robofix.
+ continue
if(I.damage > 0)
I.damage = max(I.damage - 30, 0) //Repair functionally half of a dead internal organ.
+ I.status = 0 // Wipe status, as it's being regenerated from possibly dead.
to_chat(src, "You feel a soothing sensation within your [I.name]...")
// Replace completely missing limbs.
@@ -310,6 +313,15 @@
var/agony_to_apply = round(0.66 * O.max_damage) // 66% of the limb's health is converted into pain.
src.apply_damage(agony_to_apply, HALLOSS)
+ for(var/organtype in species.has_organ) // Replace completely missing internal organs. -After- external ones, so they all should exist.
+ if(!src.internal_organs_by_name[organtype])
+ var/organpath = species.has_organ[organtype]
+ var/obj/item/organ/Int = new organpath(src, TRUE)
+
+ Int.rejuvenate(TRUE)
+
+ handle_organs() // Update everything
+
update_icons_body()
active_regen = FALSE
else
diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
index a14db9d9f50..8c745c056e5 100644
--- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm
+++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
@@ -74,7 +74,13 @@ var/datum/species/shapeshifter/promethean/prometheans
genders = list(MALE, FEMALE, NEUTER, PLURAL)
unarmed_types = list(/datum/unarmed_attack/slime_glomp)
- has_organ = list(O_BRAIN = /obj/item/organ/internal/brain/slime) // Slime core.
+
+ has_organ = list(O_BRAIN = /obj/item/organ/internal/brain/slime,
+ O_HEART = /obj/item/organ/internal/heart/grey/colormatch/slime,
+ O_REGBRUTE = /obj/item/organ/internal/regennetwork,
+ O_REGBURN = /obj/item/organ/internal/regennetwork/burn,
+ O_REGOXY = /obj/item/organ/internal/regennetwork/oxy,
+ O_REGTOX = /obj/item/organ/internal/regennetwork/tox)
dispersed_eyes = TRUE
@@ -197,35 +203,71 @@ var/datum/species/shapeshifter/promethean/prometheans
var/nutrition_cost = 0 // The total amount of nutrition drained every tick, when healing
var/nutrition_debt = 0 // Holder variable used to store previous damage values prior to healing for use in the nutrition_cost equation.
var/starve_mod = 1 // Lowering this lowers healing and increases agony multiplicatively.
- if(H.nutrition <= 150) // This is when the icon goes red
+
+ var/strain_negation = 0 // How much agony is being prevented by the
+
+ if(H.nutrition <= 150) // This is when the icon goes red
starve_mod = 0.75
if(H.nutrition <= 50) // Severe starvation. Damage repaired beyond this point will cause a stunlock if untreated.
starve_mod = 0.5
+ var/to_pay = 0
if(regen_brute)
nutrition_debt = H.getBruteLoss()
H.adjustBruteLoss(-heal_rate * starve_mod)
- nutrition_cost += nutrition_debt - H.getBruteLoss()
+
+ to_pay = nutrition_debt - H.getBruteLoss()
+
+ nutrition_cost += to_pay
+
+ var/obj/item/organ/internal/regennetwork/BrReg = H.internal_organs_by_name[O_REGBRUTE]
+
+ if(BrReg)
+ strain_negation += to_pay * max(0, (1 - BrReg.get_strain_percent()))
if(regen_burn)
nutrition_debt = H.getFireLoss()
H.adjustFireLoss(-heal_rate * starve_mod)
- nutrition_cost += nutrition_debt - H.getFireLoss()
+
+ to_pay = nutrition_debt - H.getFireLoss()
+
+ nutrition_cost += to_pay
+
+ var/obj/item/organ/internal/regennetwork/BuReg = H.internal_organs_by_name[O_REGBURN]
+
+ if(BuReg)
+ strain_negation += to_pay * max(0, (1 - BuReg.get_strain_percent()))
if(regen_oxy)
nutrition_debt = H.getOxyLoss()
H.adjustOxyLoss(-heal_rate * starve_mod)
- nutrition_cost += nutrition_debt - H.getOxyLoss()
+
+ to_pay = nutrition_debt - H.getOxyLoss()
+
+ nutrition_cost += to_pay
+
+ var/obj/item/organ/internal/regennetwork/OxReg = H.internal_organs_by_name[O_REGOXY]
+
+ if(OxReg)
+ strain_negation += to_pay * max(0, (1 - OxReg.get_strain_percent()))
if(regen_tox)
nutrition_debt = H.getToxLoss()
H.adjustToxLoss(-heal_rate * starve_mod)
- nutrition_cost += nutrition_debt - H.getToxLoss()
+
+ to_pay = nutrition_debt - H.getToxLoss()
+
+ nutrition_cost += to_pay
+
+ var/obj/item/organ/internal/regennetwork/ToxReg = H.internal_organs_by_name[O_REGTOX]
+
+ if(ToxReg)
+ strain_negation += to_pay * max(0, (1 - ToxReg.get_strain_percent()))
H.nutrition -= (3 * nutrition_cost) //Costs Nutrition when damage is being repaired, corresponding to the amount of damage being repaired.
H.nutrition = max(0, H.nutrition) //Ensure it's not below 0.
- var/agony_to_apply = ((1 / starve_mod) * nutrition_cost) //Regenerating damage causes minor pain over time. Small injures will be no issue, large ones will cause problems.
+ var/agony_to_apply = ((1 / starve_mod) * (nutrition_cost - strain_negation)) //Regenerating damage causes minor pain over time, if the organs responsible are nonexistant or too high on strain. Small injures will be no issue, large ones will cause problems.
if((starve_mod <= 0.5 && (H.getHalLoss() + agony_to_apply) <= 90) || ((H.getHalLoss() + agony_to_apply) <= 70)) // Will max out at applying halloss at 70, unless they are starving; starvation regeneration will bring them up to a maximum of 120, the same amount of agony a human receives from three taser hits.
H.apply_damage(agony_to_apply, HALLOSS)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index e5dd8bf63ec..e6fde9860fa 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1060,7 +1060,7 @@ default behaviour is:
var/mob/living/carbon/human/H = src
if(!H.isSynthetic())
var/obj/item/organ/internal/liver/L = H.internal_organs_by_name["liver"]
- if(L.is_broken())
+ if(!L || L.is_broken())
blood_vomit = 1
Stun(5)
diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm
index 579e7776b79..215ef65ced8 100644
--- a/code/modules/organs/organ.dm
+++ b/code/modules/organs/organ.dm
@@ -78,6 +78,7 @@ var/list/organ_cache = list()
if(E.internal_organs == null)
E.internal_organs = list()
E.internal_organs |= src
+ H.internal_organs_by_name[organ_tag] = src
if(dna)
if(!blood_DNA)
blood_DNA = list()
diff --git a/code/modules/organs/subtypes/slime.dm b/code/modules/organs/subtypes/slime.dm
index f22b90caea2..5fb54a21b45 100644
--- a/code/modules/organs/subtypes/slime.dm
+++ b/code/modules/organs/subtypes/slime.dm
@@ -56,3 +56,89 @@
max_damage = 30
encased = 0
spread_dam = 1
+
+/*
+ * Internal Slime organs.
+ */
+
+/obj/item/organ/internal/heart/grey/colormatch/slime
+ name = "pneumatic network"
+ desc = "A disgusting sac of goo."
+ icon_state = "sac_slime"
+ dead_icon = null
+ standard_pulse_level = PULSE_NONE
+
+/obj/item/organ/internal/heart/grey/colormatch/slime/process()
+ ..()
+ if(!(QDELETED(src)) && src.loc != owner)
+ visible_message("\The [src] splatters!")
+ var/turf/T = get_turf(src)
+ var/obj/effect/decal/cleanable/blood/B = new (T)
+
+ B.basecolor = src.color
+ B.update_icon()
+ qdel(src)
+
+/obj/item/organ/internal/regennetwork
+ name = "pneumoregenesis network"
+ parent_organ = BP_TORSO
+ organ_tag = O_REGBRUTE
+
+ icon_state = "sac_slime"
+
+ var/strain = 0 // The amount of stress this organ is under. Capped at min_broken_damage, usually half its max damage.
+
+ var/last_strain_increase = 0 // World time of the last increase in strain.
+ var/strain_regen_cooldown = 5 MINUTES
+
+/obj/item/organ/internal/regennetwork/Initialize()
+ ..()
+ var/mob/living/carbon/human/H = null
+ spawn(15)
+ if(ishuman(owner))
+ H = owner
+ color = H.species.get_blood_colour(H)
+
+/obj/item/organ/internal/regennetwork/proc/get_strain_percent(var/cost)
+ adjust_strain(cost)
+
+ if((status & ORGAN_CUT_AWAY) || (status & ORGAN_BROKEN) || (status & ORGAN_DEAD))
+ return 1
+
+ return round((strain / min_broken_damage) * 10) / 10
+
+/obj/item/organ/internal/regennetwork/proc/adjust_strain(var/amount)
+ if(amount < 0 && world.time < (last_strain_increase + strain_regen_cooldown))
+ return
+
+ else if(amount > 0)
+ last_strain_increase = world.time
+
+ strain = CLAMP(strain + amount, 0, min_broken_damage)
+
+/obj/item/organ/internal/regennetwork/process()
+ ..()
+
+ if(!(QDELETED(src)) && src.loc != owner)
+ visible_message("\The [src] splatters!")
+ var/turf/T = get_turf(src)
+ var/obj/effect/decal/cleanable/blood/B = new (T)
+
+ B.basecolor = src.color
+ B.update_icon()
+ qdel(src)
+
+ if(src && !is_bruised())
+ adjust_strain(-0.25 * max(0, (min_broken_damage - damage) / min_broken_damage)) // Decrease the current strain with respect to the current strain level.
+
+/obj/item/organ/internal/regennetwork/burn
+ name = "thermoregenesis network"
+ organ_tag = O_REGBURN
+
+/obj/item/organ/internal/regennetwork/oxy
+ name = "respiroregenesis network"
+ organ_tag = O_REGOXY
+
+/obj/item/organ/internal/regennetwork/tox
+ name = "toxoregenesis network"
+ organ_tag = O_REGTOX
diff --git a/html/changelogs/Mechoid - Promethean Organs.yml b/html/changelogs/Mechoid - Promethean Organs.yml
new file mode 100644
index 00000000000..c579478d5a9
--- /dev/null
+++ b/html/changelogs/Mechoid - Promethean Organs.yml
@@ -0,0 +1,40 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+#################################
+
+# Your name.
+author: Mechoid
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Added multiple new organs for Prometheans. Removing them will cause them to take large amounts of Toxloss untill they are Regenerated using the active regeneration verb."
+ - rscadd: "Organ: pneumatic network, a series of skeletal tubes with high pressure used to move nutrients and waste."
+ - rscadd: "Organs: -regenesis systems, different 'networks' of clumped cellular matter that allow Prometheans to recover rapidly from small injuries. Large or numerous injuries cause un-needed stress, and pain."
+ - bugfix: "Internal organs now properly add themselves to the internal organ-by-name list, the one referenced 99.9% of the time."
+ - tweak: "Active regeneration will now replace internal organs if they are nonexistant, as it does for limbs."
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index 12bededf903..5d28658eed7 100644
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ