mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-12 00:27:31 +01:00
00ccf0c6b5
# Conflicts: # .github/CODEOWNERS # .github/workflows/compile_changelogs.yml # .github/workflows/stale.yml # SQL/database_changelog.md # _maps/map_files/CatwalkStation/CatwalkStation_2023.dmm # code/__DEFINES/atom_hud.dm # code/__DEFINES/inventory.dm # code/__DEFINES/mobs.dm # code/__DEFINES/species_clothing_paths.dm # code/__DEFINES/subsystems.dm # code/__DEFINES/surgery.dm # code/__HELPERS/global_lists.dm # code/_globalvars/lists/maintenance_loot.dm # code/_globalvars/traits/_traits.dm # code/controllers/subsystem/minor_mapping.dm # code/controllers/subsystem/processing/quirks.dm # code/controllers/subsystem/shuttle.dm # code/datums/components/palette.dm # code/datums/components/surgery_initiator.dm # code/datums/diseases/advance/advance.dm # code/datums/hud.dm # code/datums/mood.dm # code/datums/mutations/chameleon.dm # code/datums/quirks/negative_quirks/nyctophobia.dm # code/datums/status_effects/debuffs/debuffs.dm # code/datums/status_effects/debuffs/drunk.dm # code/datums/status_effects/debuffs/slime/slime_leech.dm # code/datums/weather/weather.dm # code/game/data_huds.dm # code/game/objects/items.dm # code/game/objects/items/devices/scanners/health_analyzer.dm # code/game/objects/items/frog_statue.dm # code/game/objects/items/rcd/RLD.dm # code/game/objects/items/robot/items/hypo.dm # code/game/objects/items/stacks/medical.dm # code/game/objects/items/stacks/wrap.dm # code/game/objects/items/storage/garment.dm # code/game/objects/items/tools/medical/defib.dm # code/game/objects/items/weaponry.dm # code/game/objects/items/weaponry/melee/misc.dm # code/game/objects/structures/crates_lockers/closets/secure/security.dm # code/game/objects/structures/curtains.dm # code/game/objects/structures/dresser.dm # code/game/objects/structures/girders.dm # code/game/objects/structures/maintenance.dm # code/game/objects/structures/mirror.dm # code/modules/admin/greyscale_modify_menu.dm # code/modules/admin/verbs/light_debug.dm # code/modules/antagonists/ashwalker/ashwalker.dm # code/modules/antagonists/heretic/knowledge/starting_lore.dm # code/modules/antagonists/ninja/ninjaDrainAct.dm # code/modules/art/paintings.dm # code/modules/client/preferences.dm # code/modules/client/verbs/ooc.dm # code/modules/clothing/head/wig.dm # code/modules/events/disease_outbreak.dm # code/modules/holodeck/holo_effect.dm # code/modules/jobs/job_types/head_of_security.dm # code/modules/jobs/job_types/security_officer.dm # code/modules/library/skill_learning/generic_skillchips/point.dm # code/modules/mining/lavaland/ash_flora.dm # code/modules/mining/lavaland/mining_loot/megafauna/ash_drake.dm # code/modules/mob/dead/new_player/new_player.dm # code/modules/mob/living/basic/guardian/guardian.dm # code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm # code/modules/mob/living/carbon/carbon.dm # code/modules/mob/living/carbon/human/human.dm # code/modules/mob/living/carbon/human/human_defines.dm # code/modules/mob/living/carbon/life.dm # code/modules/mob/living/living.dm # code/modules/mob/living/living_defines.dm # code/modules/mob/mob.dm # code/modules/mob_spawn/ghost_roles/mining_roles.dm # code/modules/mod/mod_control.dm # code/modules/mod/modules/modules_general.dm # code/modules/modular_computers/computers/item/computer_ui.dm # code/modules/paperwork/paper.dm # code/modules/paperwork/paperbin.dm # code/modules/power/lighting/light.dm # code/modules/projectiles/guns/energy/kinetic_accelerator.dm # code/modules/projectiles/projectile.dm # code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm # code/modules/reagents/chemistry/reagents/food_reagents.dm # code/modules/reagents/chemistry/reagents/other_reagents.dm # code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm # code/modules/research/xenobiology/crossbreeding/_clothing.dm # code/modules/research/xenobiology/crossbreeding/prismatic.dm # code/modules/surgery/advanced/brainwashing.dm # code/modules/surgery/advanced/lobotomy.dm # code/modules/surgery/amputation.dm # code/modules/surgery/blood_filter.dm # code/modules/surgery/bodyparts/_bodyparts.dm # code/modules/surgery/brain_surgery.dm # code/modules/surgery/cavity_implant.dm # code/modules/surgery/coronary_bypass.dm # code/modules/surgery/gastrectomy.dm # code/modules/surgery/healing.dm # code/modules/surgery/limb_augmentation.dm # code/modules/surgery/organ_manipulation.dm # code/modules/surgery/revival.dm # code/modules/surgery/sleeper_protocol.dm # code/modules/surgery/surgery_helpers.dm # code/modules/surgery/surgery_step.dm # code/modules/unit_tests/_unit_tests.dm # code/modules/unit_tests/designs.dm # code/modules/unit_tests/icon_state_worn.dm # code/modules/unit_tests/screenshots/screenshot_antag_icons_cultist.png # code/modules/unit_tests/screenshots/screenshot_antag_icons_headrevolutionary.png # code/modules/unit_tests/screenshots/screenshot_antag_icons_provocateur.png # code/modules/unit_tests/screenshots/screenshot_husk_body.png # code/modules/unit_tests/screenshots/screenshot_husk_body_missing_limbs.png # icons/map_icons/clothing/head/_head.dmi # icons/map_icons/clothing/shoes.dmi # icons/map_icons/items/_item.dmi # icons/mob/huds/hud.dmi # icons/mob/inhands/64x64_lefthand.dmi # icons/mob/inhands/64x64_righthand.dmi # icons/obj/machines/computer.dmi # tgui/packages/tgui/interfaces/OperatingComputer.jsx # tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx # tgui/packages/tgui/interfaces/PreferencesMenu/types.ts # tgui/packages/tgui/interfaces/SurgeryInitiator.tsx # tools/icon_cutter/check.py
529 lines
20 KiB
Plaintext
529 lines
20 KiB
Plaintext
/obj/item/organ
|
|
name = "organ"
|
|
icon = 'icons/obj/medical/organs/organs.dmi'
|
|
abstract_type = /obj/item/organ
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
throwforce = 0
|
|
/// The mob that owns this organ.
|
|
var/mob/living/carbon/owner = null
|
|
/// Reference to the limb we're inside of
|
|
var/obj/item/bodypart/bodypart_owner
|
|
/// The cached info about the blood this organ belongs to
|
|
var/list/blood_dna_info // not every organ spawns inside a person
|
|
/// The body zone this organ is supposed to inhabit.
|
|
var/zone = BODY_ZONE_CHEST
|
|
/**
|
|
* The organ slot this organ is supposed to inhabit. This should be unique by type. (Lungs, Appendix, Stomach, etc)
|
|
* Do NOT add slots with matching names to different zones - it will break the organs_slot list!
|
|
*/
|
|
var/slot
|
|
/// Random flags that describe this organ
|
|
var/organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN
|
|
/// Maximum damage the organ can take, ever.
|
|
var/maxHealth = STANDARD_ORGAN_THRESHOLD
|
|
/**
|
|
* Total damage this organ has sustained.
|
|
* Should only ever be modified by apply_organ_damage!
|
|
*/
|
|
var/damage = 0
|
|
/// Healing factor and decay factor function on % of maxhealth, and do not work by applying a static number per tick
|
|
var/healing_factor = 0 //fraction of maxhealth healed per on_life(), set to 0 for generic organs
|
|
var/decay_factor = 0 //same as above but when without a living owner, set to 0 for generic organs
|
|
var/high_threshold = STANDARD_ORGAN_THRESHOLD * 0.45 //when severe organ damage occurs
|
|
var/low_threshold = STANDARD_ORGAN_THRESHOLD * 0.1 //when minor organ damage occurs
|
|
var/severe_cooldown //cooldown for severe effects, used for synthetic organ emp effects.
|
|
|
|
// Organ variables for determining what we alert the owner with when they pass/clear the damage thresholds
|
|
var/prev_damage = 0
|
|
var/low_threshold_passed
|
|
var/high_threshold_passed
|
|
var/now_failing
|
|
var/now_fixed
|
|
var/high_threshold_cleared
|
|
var/low_threshold_cleared
|
|
|
|
/// When set to false, this can't be used in surgeries and such - Honestly a terrible variable.
|
|
var/useable = TRUE
|
|
|
|
/// Food reagents if the organ is edible
|
|
var/list/food_reagents = list(/datum/reagent/consumable/nutriment = 5)
|
|
/// Foodtypes if the organ is edible
|
|
var/foodtype_flags = RAW | MEAT | GORE
|
|
/// Overrides tastes if the organ is edible
|
|
var/food_tastes
|
|
/// The size of the reagent container if the organ is edible
|
|
var/reagent_vol = 10
|
|
|
|
/// Time this organ has failed for
|
|
var/failure_time = 0
|
|
/// Do we affect the appearance of our mob. Used to save time in preference code
|
|
var/visual = TRUE
|
|
/**
|
|
* Traits that are given to the holder of the organ.
|
|
* If you want an effect that changes this, don't add directly to this. Use the add_organ_trait() proc.
|
|
*/
|
|
var/list/organ_traits
|
|
/// Status Effects that are given to the holder of the organ.
|
|
var/list/organ_effects
|
|
/// String displayed when the organ has decayed.
|
|
var/failing_desc = "has decayed for too long, and has turned a sickly color. It probably won't work without repairs."
|
|
/// Assoc list of alternate zones where this can organ be slotted to organ slot for that zone
|
|
var/list/valid_zones = null
|
|
/// The cell line we can spawn on us
|
|
var/cell_line = null
|
|
/// The minimum cells we can spawn
|
|
var/cells_minimum = 0
|
|
/// The maximum cells we can spawn
|
|
var/cells_maximum = 0
|
|
|
|
// Players can look at prefs before atoms SS init, and without this
|
|
// they would not be able to see external organs, such as moth wings.
|
|
// This is also necessary because assets SS is before atoms, and so
|
|
// any nonhumans created in that time would experience the same effect.
|
|
INITIALIZE_IMMEDIATE(/obj/item/organ)
|
|
|
|
/obj/item/organ/Initialize(mapload)
|
|
. = ..()
|
|
blood_dna_info = list("Unknown DNA" = get_blood_type(BLOOD_TYPE_O_PLUS))
|
|
if(organ_flags & ORGAN_EDIBLE)
|
|
AddComponentFrom(
|
|
SOURCE_EDIBLE_INNATE, \
|
|
/datum/component/edible, \
|
|
initial_reagents = food_reagents, \
|
|
foodtypes = foodtype_flags, \
|
|
volume = reagent_vol, \
|
|
tastes = food_tastes, \
|
|
after_eat = CALLBACK(src, PROC_REF(OnEatFrom)), \
|
|
)
|
|
RegisterSignal(src, COMSIG_FOOD_ATTEMPT_EAT, PROC_REF(block_nom))
|
|
|
|
if(bodypart_overlay)
|
|
setup_bodypart_overlay()
|
|
|
|
if(cell_line && (organ_flags & ORGAN_ORGANIC))
|
|
AddElement(/datum/element/swabable, cell_line, cell_line_amount = rand(cells_minimum, cells_maximum))
|
|
|
|
START_PROCESSING(SSobj, src)
|
|
|
|
/obj/item/organ/Destroy()
|
|
if(bodypart_owner && !owner && !QDELETED(bodypart_owner))
|
|
bodypart_remove(bodypart_owner)
|
|
else if(owner && QDESTROYING(owner))
|
|
// The mob is being deleted, don't update the mob
|
|
Remove(owner, special=TRUE)
|
|
else if(owner)
|
|
Remove(owner)
|
|
else
|
|
STOP_PROCESSING(SSobj, src)
|
|
return ..()
|
|
|
|
/// Add a Trait to an organ that it will give its owner.
|
|
/obj/item/organ/proc/add_organ_trait(trait)
|
|
LAZYOR(organ_traits, trait)
|
|
if(isnull(owner))
|
|
return
|
|
ADD_TRAIT(owner, trait, REF(src))
|
|
|
|
/// Removes a Trait from an organ, and by extension, its owner.
|
|
/obj/item/organ/proc/remove_organ_trait(trait)
|
|
LAZYREMOVE(organ_traits, trait)
|
|
if(isnull(owner))
|
|
return
|
|
REMOVE_TRAIT(owner, trait, REF(src))
|
|
|
|
/// Add a Status Effect to an organ that it will give its owner.
|
|
/obj/item/organ/proc/add_organ_status(status)
|
|
LAZYADD(organ_effects, status)
|
|
if(isnull(owner))
|
|
return
|
|
owner.apply_status_effect(status, type)
|
|
|
|
/// Removes a Status Effect from an organ, and by extension, its owner.
|
|
/obj/item/organ/proc/remove_organ_status(status)
|
|
LAZYREMOVE(organ_effects, status)
|
|
if(isnull(owner))
|
|
return
|
|
owner.remove_status_effect(status, type)
|
|
|
|
/obj/item/organ/proc/on_find(mob/living/finder)
|
|
return
|
|
|
|
/obj/item/organ/wash(clean_types)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
// always add the original dna to the organ after it's washed
|
|
if(!IS_ROBOTIC_ORGAN(src) && (clean_types & CLEAN_TYPE_BLOOD))
|
|
add_blood_DNA(blood_dna_info)
|
|
|
|
/obj/item/organ/proc/on_death(seconds_per_tick) //runs decay when outside of a person
|
|
if(organ_flags & (ORGAN_ROBOTIC | ORGAN_FROZEN))
|
|
return
|
|
|
|
if(owner)
|
|
if(owner.bodytemperature > T0C)
|
|
var/air_temperature_factor = min((owner.bodytemperature - T0C) / 20, 1)
|
|
apply_organ_damage(decay_factor * maxHealth * seconds_per_tick * air_temperature_factor)
|
|
else
|
|
var/datum/gas_mixture/exposed_air = return_air()
|
|
if(exposed_air && exposed_air.temperature > T0C)
|
|
var/air_temperature_factor = min((exposed_air.temperature - T0C) / 20, 1)
|
|
apply_organ_damage(decay_factor * maxHealth * seconds_per_tick * air_temperature_factor)
|
|
|
|
/obj/item/organ/proc/on_life(seconds_per_tick) //repair organ damage if the organ is not failing
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
|
|
if(organ_flags & ORGAN_FAILING)
|
|
handle_failing_organs(seconds_per_tick)
|
|
return
|
|
|
|
if(failure_time > 0)
|
|
failure_time--
|
|
|
|
if(organ_flags & ORGAN_EMP) //Synthetic organ has been emped, is now failing.
|
|
apply_organ_damage(decay_factor * maxHealth * seconds_per_tick)
|
|
return
|
|
|
|
if(!damage) // No sense healing if you're not even hurt bro
|
|
return
|
|
|
|
if(IS_ROBOTIC_ORGAN(src)) // Robotic organs don't naturally heal
|
|
return
|
|
|
|
///Damage decrements by a percent of its maxhealth
|
|
var/healing_amount = healing_factor
|
|
///Damage decrements again by a percent of its maxhealth, up to a total of 4 extra times depending on the owner's health
|
|
healing_amount += (owner.satiety > 0) ? (4 * healing_factor * owner.satiety / MAX_SATIETY) : 0
|
|
apply_organ_damage(-healing_amount * maxHealth * seconds_per_tick, damage) // pass curent damage incase we are over cap
|
|
|
|
/obj/item/organ/examine(mob/user)
|
|
. = ..()
|
|
|
|
. += zones_tip()
|
|
|
|
if(HAS_MIND_TRAIT(user, TRAIT_ENTRAILS_READER) || isobserver(user))
|
|
if(HAS_TRAIT(src, TRAIT_CLIENT_STARTING_ORGAN))
|
|
. += span_info("Lived in and homely. Proven to work. This should fetch a high price on the market.")
|
|
|
|
if(organ_flags & ORGAN_FAILING)
|
|
. += span_warning("[src] [failing_desc]")
|
|
return
|
|
|
|
if(damage > high_threshold)
|
|
if(IS_ROBOTIC_ORGAN(src))
|
|
. += span_warning("[src] seems to be malfunctioning.")
|
|
return
|
|
. += span_warning("[src] is starting to look discolored.")
|
|
|
|
/// Returns a line to be displayed regarding valid insertion zones
|
|
/obj/item/organ/proc/zones_tip()
|
|
if (!valid_zones)
|
|
return span_notice("It should be inserted in the [parse_zone(zone)].")
|
|
|
|
var/list/fit_zones = list()
|
|
for (var/valid_zone in valid_zones)
|
|
fit_zones += parse_zone(valid_zone)
|
|
return span_notice("It should be inserted in the [english_list(fit_zones, and_text = " or ")].")
|
|
|
|
///Used as callbacks by object pooling
|
|
/obj/item/organ/proc/exit_wardrobe()
|
|
START_PROCESSING(SSobj, src)
|
|
bodypart_overlay?.imprint_on_next_insertion = TRUE
|
|
|
|
//See above
|
|
/obj/item/organ/proc/enter_wardrobe()
|
|
STOP_PROCESSING(SSobj, src)
|
|
|
|
/obj/item/organ/process(seconds_per_tick)
|
|
on_death(seconds_per_tick) //Kinda hate doing it like this, but I really don't want to call process directly.
|
|
|
|
/obj/item/organ/proc/OnEatFrom(eater, feeder)
|
|
// You can't use it anymore after eating it
|
|
organ_flags |= ORGAN_UNUSABLE
|
|
|
|
/obj/item/organ/item_action_slot_check(slot,mob/user)
|
|
return //so we don't grant the organ's action to mobs who pick up the organ.
|
|
|
|
///Adjusts an organ's damage by the amount "damage_amount", up to a maximum amount, which is by default max damage. Returns the net change in organ damage.
|
|
/obj/item/organ/proc/apply_organ_damage(damage_amount, maximum = maxHealth, required_organ_flag = NONE) //use for damaging effects
|
|
if(!damage_amount) //Micro-optimization.
|
|
return FALSE
|
|
maximum = clamp(maximum, 0, maxHealth) // the logical max is, our max
|
|
if(maximum < damage)
|
|
return FALSE
|
|
if(required_organ_flag && !(organ_flags & required_organ_flag))
|
|
return FALSE
|
|
damage = clamp(damage + damage_amount, 0, maximum)
|
|
SEND_SIGNAL(src, COMSIG_ORGAN_ADJUST_DAMAGE, damage_amount, maximum, required_organ_flag)
|
|
. = (prev_damage - damage) // return net damage
|
|
var/message = check_damage_thresholds()
|
|
prev_damage = damage
|
|
|
|
if(message && owner && owner.stat <= SOFT_CRIT)
|
|
to_chat(owner, message)
|
|
|
|
///SETS an organ's damage to the amount "damage_amount", and in doing so clears or sets the failing flag, good for when you have an effect that should fix an organ if broken
|
|
/obj/item/organ/proc/set_organ_damage(damage_amount, required_organ_flag = NONE) //use mostly for admin heals
|
|
return apply_organ_damage(damage_amount - damage, required_organ_flag = required_organ_flag)
|
|
|
|
/** check_damage_thresholds
|
|
* input: mob/organ_owner (a mob, the owner of the organ we call the proc on)
|
|
* output: returns a message should get displayed.
|
|
* description: By checking our current damage against our previous damage, we can decide whether we've passed an organ threshold.
|
|
* If we have, send the corresponding threshold message to the owner, if such a message exists.
|
|
*/
|
|
/obj/item/organ/proc/check_damage_thresholds()
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
if(damage == prev_damage)
|
|
return
|
|
var/delta = damage - prev_damage
|
|
var/message = ""
|
|
if(delta > 0)
|
|
if(damage > low_threshold && prev_damage <= low_threshold)
|
|
on_low_damage_received()
|
|
message = low_threshold_passed
|
|
if(damage > high_threshold && prev_damage <= high_threshold)
|
|
on_high_damage_received()
|
|
message = high_threshold_passed
|
|
if(damage >= maxHealth)
|
|
organ_flags |= ORGAN_FAILING
|
|
on_begin_failure()
|
|
message = now_failing
|
|
return message
|
|
|
|
if(prev_damage == maxHealth)
|
|
organ_flags &= ~ORGAN_FAILING
|
|
on_failure_recovery()
|
|
message = now_fixed
|
|
if(prev_damage > high_threshold && damage <= high_threshold)
|
|
on_high_damage_healed()
|
|
message = high_threshold_cleared
|
|
if(prev_damage > low_threshold && damage <= low_threshold)
|
|
on_low_damage_healed()
|
|
message = low_threshold_cleared
|
|
return message
|
|
|
|
/**
|
|
* Called when the damage surpasses the low damage threshold.
|
|
*
|
|
* This and other procs like this one merely exist to make it easier to keep a standard on
|
|
* damage thresholds for organs. This doesn't mean you cannot make custom thresholds for various stuff,
|
|
* and you're more than welcome to improve or refactor any portion of the code around these mechanics
|
|
*/
|
|
/obj/item/organ/proc/on_low_damage_received()
|
|
return
|
|
|
|
///Called when the damage goes below the low damage threshold
|
|
/obj/item/organ/proc/on_low_damage_healed()
|
|
return
|
|
|
|
///Called when the damage surpasses the high damage threshold
|
|
/obj/item/organ/proc/on_high_damage_received()
|
|
return
|
|
|
|
///Called when the damage goes below the high damage threshold
|
|
/obj/item/organ/proc/on_high_damage_healed()
|
|
return
|
|
|
|
///Called when the organ enters failing stage
|
|
/obj/item/organ/proc/on_begin_failure()
|
|
return
|
|
|
|
///Called when the organ recovers from failing stage
|
|
/obj/item/organ/proc/on_failure_recovery()
|
|
return
|
|
|
|
//Looking for brains?
|
|
//Try code/modules/mob/living/carbon/brain/brain_item.dm
|
|
|
|
/**
|
|
* Heals all of the mob's organs, and re-adds any missing ones.
|
|
*
|
|
* * regenerate_existing - if TRUE, existing organs will be deleted and replaced with new ones
|
|
*/
|
|
|
|
/mob/living/carbon/proc/regenerate_organs(remove_hazardous = FALSE)
|
|
// Delegate to species if possible.
|
|
if(dna?.species)
|
|
for(var/obj/item/organ/organ as anything in organs)
|
|
if(organ.organ_flags & ORGAN_EMP)
|
|
organ.organ_flags &= ~ORGAN_EMP
|
|
if(remove_hazardous && (organ.organ_flags & ORGAN_HAZARDOUS))
|
|
qdel(organ)
|
|
continue
|
|
// Species regenerate organs doesn't ALWAYS handle healing the organs because it's dumb
|
|
organ.set_organ_damage(0)
|
|
|
|
dna.species.regenerate_organs(src, replace_current = FALSE)
|
|
set_heartattack(FALSE)
|
|
|
|
// Ears have aditional var "deaf", need to update it too
|
|
var/obj/item/organ/ears/ears = get_organ_slot(ORGAN_SLOT_EARS)
|
|
ears.adjust_temporary_deafness(-INFINITY)
|
|
|
|
return
|
|
|
|
// Default organ fixing handling
|
|
// May result in kinda cursed stuff for mobs which don't need these organs
|
|
var/obj/item/organ/lungs/lungs = get_organ_slot(ORGAN_SLOT_LUNGS)
|
|
if(!lungs)
|
|
lungs = new()
|
|
lungs.Insert(src)
|
|
lungs.set_organ_damage(0)
|
|
lungs.received_pressure_mult = lungs::received_pressure_mult
|
|
|
|
var/obj/item/organ/heart/heart = get_organ_slot(ORGAN_SLOT_HEART)
|
|
if(heart)
|
|
set_heartattack(FALSE)
|
|
else
|
|
heart = new()
|
|
heart.Insert(src)
|
|
heart.set_organ_damage(0)
|
|
|
|
var/obj/item/organ/tongue/tongue = get_organ_slot(ORGAN_SLOT_TONGUE)
|
|
if(!tongue)
|
|
tongue = new()
|
|
tongue.Insert(src)
|
|
tongue.set_organ_damage(0)
|
|
|
|
var/obj/item/organ/eyes/eyes = get_organ_slot(ORGAN_SLOT_EYES)
|
|
if(!eyes)
|
|
eyes = new()
|
|
eyes.Insert(src)
|
|
eyes.set_organ_damage(0)
|
|
|
|
var/obj/item/organ/ears/ears = get_organ_slot(ORGAN_SLOT_EARS)
|
|
if(!ears)
|
|
ears = new()
|
|
ears.Insert(src)
|
|
ears.set_organ_damage(0)
|
|
ears.adjust_temporary_deafness(-INFINITY)
|
|
|
|
///Organs don't die instantly, and neither should you when you get fucked up
|
|
/obj/item/organ/proc/handle_failing_organs(seconds_per_tick)
|
|
if(owner.stat == DEAD)
|
|
return
|
|
|
|
failure_time += seconds_per_tick
|
|
organ_failure(seconds_per_tick)
|
|
|
|
|
|
/** organ_failure
|
|
* generic proc for handling dying organs
|
|
*
|
|
* Arguments:
|
|
* seconds_per_tick - seconds since last tick
|
|
*/
|
|
/obj/item/organ/proc/organ_failure(seconds_per_tick)
|
|
return
|
|
|
|
/** get_availability
|
|
* returns whether the species should innately have this organ.
|
|
*
|
|
* regenerate organs works with generic organs, so we need to get whether it can accept certain organs just by what this returns.
|
|
* This is set to return true or false, depending on if a species has a trait that would nulify the purpose of the organ.
|
|
* For example, lungs won't be given if you have NO_BREATH, stomachs check for NO_HUNGER, and livers check for NO_METABOLISM.
|
|
* If you want a carbon to have a trait that normally blocks an organ but still want the organ. Attach the trait to the organ using the organ_traits var
|
|
* Arguments:
|
|
* owner_species - species, needed to return the mutant slot as true or false. stomach set to null means it shouldn't have one.
|
|
* owner_mob - for more specific checks, like nightmares.
|
|
*/
|
|
/obj/item/organ/proc/get_availability(datum/species/owner_species, mob/living/owner_mob)
|
|
return TRUE
|
|
|
|
/// Called before organs are replaced in regenerate_organs with new ones
|
|
/obj/item/organ/proc/before_organ_replacement(obj/item/organ/replacement)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
|
|
SEND_SIGNAL(src, COMSIG_ORGAN_BEING_REPLACED, replacement)
|
|
|
|
// If we're being replace with an identical type we should take organ damage
|
|
if(replacement.type == type)
|
|
replacement.set_organ_damage(damage)
|
|
|
|
/// Called by medical scanners to get a simple summary of how healthy the organ is. Returns an empty string if things are fine.
|
|
/obj/item/organ/proc/get_status_text(advanced, add_tooltips, colored = TRUE)
|
|
if(advanced && (organ_flags & ORGAN_HAZARDOUS))
|
|
return conditional_tooltip("[colored ? "<font color='#cc3333'>" : ""]Harmful Foreign Body[colored ? "</font>" : ""]", "Remove surgically.", add_tooltips)
|
|
|
|
if(organ_flags & ORGAN_EMP)
|
|
return conditional_tooltip("[colored ? "<font color='#cc3333'>" : ""]EMP-Derived Failure[colored ? "</font>" : ""]", "Repair or replace surgically.", add_tooltips)
|
|
|
|
var/tech_text = ""
|
|
if(owner.has_reagent(/datum/reagent/inverse/technetium))
|
|
tech_text = "[round((damage / maxHealth) * 100, 1)]% damaged"
|
|
|
|
if(organ_flags & ORGAN_FAILING)
|
|
return conditional_tooltip("[colored ? "<font color='#cc3333'>" : ""][tech_text || "Non-Functional"][colored ? "</font>" : ""]", "Repair or replace surgically.", add_tooltips)
|
|
|
|
if(damage > high_threshold)
|
|
return conditional_tooltip("[colored ? "<font color='#ff9933'>" : ""][tech_text || "Severely Damaged"][colored ? "</font>" : ""]", "[healing_factor ? "Treat with rest or use specialty medication." : "Repair surgically or use specialty medication."]", add_tooltips && owner.stat != DEAD)
|
|
|
|
if(damage > low_threshold)
|
|
return conditional_tooltip("[colored ? "<font color='#ffcc33'>" : ""][tech_text || "Mildly Damaged"][colored ? "</font>" : ""]", "[healing_factor ? "Treat with rest." : "Use specialty medication."]", add_tooltips && owner.stat != DEAD)
|
|
|
|
if(tech_text)
|
|
return "[colored ? "<font color='#33cc33'>" : ""][tech_text][colored ? "</font>" : ""]"
|
|
|
|
return ""
|
|
|
|
/// Determines if this organ is shown when a user has condensed scans enabled
|
|
/obj/item/organ/proc/show_on_condensed_scans()
|
|
// We don't need to show *most* damaged organs as they have no effects associated
|
|
return (organ_flags & (ORGAN_PROMINENT|ORGAN_HAZARDOUS|ORGAN_FAILING|ORGAN_VITAL))
|
|
|
|
/// Similar to get_status_text, but appends the text after the damage report, for additional status info
|
|
/obj/item/organ/proc/get_status_appendix(advanced, add_tooltips)
|
|
return
|
|
|
|
/**
|
|
* Used when a mob is examining themselves / their limbs
|
|
*
|
|
* Reports how they feel based on how the status of this organ
|
|
*
|
|
* It should be formatted as an extension of the limb:
|
|
* Input is something like "Your chest is bruised. It is bleeding.",
|
|
* you would add something like "It hurts a little, and your stomach cramps."
|
|
*
|
|
* * self_aware - if TRUE, the examiner is more aware of themselves and thus may get more detailed information
|
|
*
|
|
* Return a string, to be concatenated with other organ / limb status strings. Include spans and punctuation.
|
|
*/
|
|
/obj/item/organ/proc/feel_for_damage(self_aware)
|
|
if(organ_flags & ORGAN_EXTERNAL)
|
|
return ""
|
|
if(damage < low_threshold)
|
|
return ""
|
|
if(damage < high_threshold)
|
|
return span_warning("[self_aware ? "[capitalize(slot)]" : "It"] feels a bit off.")
|
|
return span_boldwarning("[self_aware ? "[capitalize(slot)]" : "It"] feels terrible!")
|
|
|
|
/// Tries to replace the existing organ on the passed mob with this one, with special handling for replacing a brain without ghosting target
|
|
/obj/item/organ/proc/replace_into(mob/living/carbon/new_owner)
|
|
// BUBBER EDIT - OR BEGIN
|
|
return Insert(new_owner, special = TRUE, movement_flags = DELETE_IF_REPLACED)
|
|
//Insert(new_owner, special = TRUE, movement_flags = DELETE_IF_REPLACED)
|
|
|
|
/// Signal proc for [COMSIG_FOOD_ATTEMPT_EAT], block feeding an organ to a mob if they are marked as ready to operate - to prevent mistakenly feeding your patient
|
|
/obj/item/organ/proc/block_nom(datum/source, mob/living/carbon/eater, mob/living/carbon/feeder)
|
|
SIGNAL_HANDLER
|
|
if(!HAS_TRAIT(eater, TRAIT_READY_TO_OPERATE))
|
|
return NONE
|
|
if(eater == feeder)
|
|
to_chat(feeder, span_warning("You feel it unwise to eat [source] while you're undergoing surgery."))
|
|
else
|
|
to_chat(feeder, span_warning("The only thing you could think of doing with [source] right now is feeding it to [eater], but that doesn't seem right."))
|
|
return BLOCK_EAT_ATTEMPT
|
|
|
|
/// Get all possible organ slots by checking every organ, and then store it and give it whenever needed
|
|
/proc/get_all_slots()
|
|
var/static/list/all_organ_slots = list()
|
|
|
|
if(!all_organ_slots.len)
|
|
for(var/obj/item/organ/an_organ as anything in subtypesof(/obj/item/organ))
|
|
if(!initial(an_organ.slot))
|
|
continue
|
|
all_organ_slots |= initial(an_organ.slot)
|
|
|
|
return all_organ_slots
|