/**************************************************** EXTERNAL ORGANS ****************************************************/ //These control the damage thresholds for the various ways of removing limbs #define DROPLIMB_THRESHOLD_EDGE 5 #define DROPLIMB_THRESHOLD_TEAROFF 2 #define DROPLIMB_THRESHOLD_DESTROY 1 /obj/item/organ/external name = "external" min_broken_damage = 60 // CHOMPEdit: Flat doubling of all min_broken_damage max_damage = 0 dir = SOUTH organ_tag = "limb" var/brokenpain = 50 //CHOMPEdit // Strings var/broken_description // fracture string if any. var/damage_state = "00" // Modifier used for generating the on-mob damage overlay for this limb. // Damage vars. var/brute_mod = 1 // Multiplier for incoming brute damage. var/burn_mod = 1 // As above for burn. var/brute_dam = 0 // Actual current brute damage. var/burn_dam = 0 // Actual current burn damage. var/last_dam = -1 // used in healing/processing calculations. var/spread_dam = 0 var/thick_skin = 0 // If a needle has a chance to fail to penetrate. // Appearance vars. var/nonsolid // Snowflake warning, reee. Used for slime limbs. var/transparent // As above, so below. Used for transparent limbs. var/icon_name = null // Icon state base. var/body_part = null // Part flag var/icon_position = 0 // Used in mob overlay layering calculations. var/model // Used when caching robolimb icons. var/force_icon // Used to force override of species-specific limb icons (for prosthetics). Also used for any limbs chopped from a simple mob, and then attached to humans. var/force_icon_key // Used to force the override of the icon-key generated using the species. Must be used in tandem with the above. var/icon/mob_icon // Cached icon for use in mob overlays. var/gendered_icon = 0 // Whether or not the icon state appends a gender. var/s_tone // Skin tone. var/list/s_col // skin colour var/s_col_blend = ICON_ADD // How the skin colour is applied. var/list/h_col // hair colour var/body_hair // Icon blend for body hair if any. var/mob/living/applied_pressure var/list/markings = list() // Markings (body_markings) to apply to the icon var/skip_robo_icon = FALSE //to force it to use the normal species icon var/digi_prosthetic = FALSE //is it a prosthetic that can be digitigrade // Wound and structural data. var/wound_update_accuracy = 1 // how often wounds should be updated, a higher number means less often var/list/wounds = list() // wound datum list. var/number_wounds = 0 // number of wounds, which is NOT wounds.len! var/obj/item/organ/external/parent // Master-limb. var/list/children = list() // Sub-limbs. var/list/internal_organs = list() // Internal organs of this body part var/sabotaged = 0 // If a prosthetic limb is emagged, it will detonate when it fails. var/list/implants = list() // Currently implanted objects. var/organ_rel_size = 25 // Relative size of the organ. var/base_miss_chance = 20 // Chance of missing. var/atom/movable/splinted // Joint/state stuff. var/can_grasp // It would be more appropriate if these two were named "affects_grasp" and "affects_stand" at this point var/can_stand // Modifies stance tally/ability to stand. var/disfigured = 0 // Scarred/burned beyond recognition. var/cannot_amputate // Impossible to amputate. var/cannot_break // Impossible to fracture. var/cannot_gib // Impossible to gib, distinct from amputation. var/joint = "joint" // Descriptive string used in dislocation. var/amputation_point // Descriptive string used in amputation. var/dislocated = 0 // If you target a joint, you can dislocate the limb, impairing it's usefulness and causing pain var/encased // Needs to be opened with a saw to access the organs. // Surgery vars. var/open = 0 var/stage = 0 var/cavity = 0 var/burn_stage = 0 //Surgical repair stage for burn. var/brute_stage = 0 //Surgical repair stage for brute. // HUD element variable, see organ_icon.dm get_damage_hud_image() var/image/hud_damage_image /obj/item/organ/external/Destroy() if(parent && parent.children) parent.children -= src parent = null if(children) for(var/obj/item/organ/external/C in children) children -= C C.parent = null qdel(C) if(internal_organs) for(var/obj/item/organ/O in internal_organs) internal_organs -= O qdel(O) if(splinted && splinted.loc == src) splinted.loc = null qdel(splinted) splinted = null if(istype(owner)) owner.organs -= src owner.organs_by_name[organ_tag] = null owner.organs_by_name -= organ_tag while(null in owner.organs) owner.organs -= null for(var/obj/item/weapon/implant/I as anything in implants) if(!istype(I)) continue I.imp_in = I.part = null implants.Cut() return ..() /obj/item/organ/external/emp_act(severity) for(var/obj/O as anything in src.contents) O.emp_act(severity) if(!(robotic >= ORGAN_ROBOT) || robotic == ORGAN_NANOFORM) //CHOMPEdit - Proteans handle EMP's differently return var/burn_damage = 0 for(var/i = 1; i <= robotic; i++) switch (severity) if (1) burn_damage += rand(5, 8) if (2) burn_damage += rand(4, 6) if(3) burn_damage += rand(2, 5) if(4) burn_damage += rand(1, 3) if(burn_damage) take_damage(0, burn_damage) /obj/item/organ/external/attack_self(var/mob/living/user) if(!contents.len) return ..() var/list/removable_objects = list() for(var/obj/item/organ/external/E in (contents + src)) if(!istype(E)) continue for(var/obj/item/I in E.contents) if(istype(I,/obj/item/organ)) continue removable_objects |= I if(removable_objects.len) var/obj/item/I = pick(removable_objects) I.loc = get_turf(user) //just in case something was embedded that is not an item if(istype(I)) user.put_in_hands(I) user.visible_message("\The [user] rips \the [I] out of \the [src]!") return //no eating the limb until everything's been removed return ..() /obj/item/organ/external/examine() . = ..() if(in_range(usr, src) || istype(usr, /mob/observer/dead)) for(var/obj/item/I in contents) if(istype(I, /obj/item/organ)) continue . += "There is \a [I] sticking out of it." /obj/item/organ/external/attackby(obj/item/weapon/W as obj, mob/living/user as mob) switch(stage) if(0) if(istype(W,/obj/item/weapon/surgical/scalpel)) user.visible_message("[user] cuts [src] open with [W]!") stage++ return if(1) if(istype(W,/obj/item/weapon/surgical/retractor)) user.visible_message("[user] cracks [src] open like an egg with [W]!") stage++ return if(2) if(istype(W,/obj/item/weapon/surgical/hemostat)) if(contents.len) var/obj/item/removing = pick(contents) removing.loc = get_turf(user.loc) user.put_in_hands(removing) user.visible_message("[user] extracts [removing] from [src] with [W]!") else user.visible_message("[user] fishes around fruitlessly in [src] with [W].") return ..() /obj/item/organ/external/proc/is_dislocated() if(dislocated > 0) return 1 if(is_parent_dislocated()) return 1//if any parent is dislocated, we are considered dislocated as well return 0 /obj/item/organ/external/proc/is_parent_dislocated() var/obj/item/organ/external/O = parent while(O && O.dislocated != -1) if(O.dislocated == 1) return 1 O = O.parent return 0 //new function to check for markings /obj/item/organ/external/proc/is_hidden_by_markings() for(var/M in markings) var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"] if(istype(mark_style,/datum/sprite_accessory/marking) && (organ_tag in mark_style.hide_body_parts)) return 1 /obj/item/organ/external/proc/dislocate() if(dislocated == -1) return dislocated = 1 if(istype(owner)) add_verb(owner,/mob/living/carbon/human/proc/relocate) //CHOMPEdit TGPanel /obj/item/organ/external/proc/relocate() if(dislocated == -1) return dislocated = 0 if(istype(owner)) owner.shock_stage += 20 //check to see if we still need the verb for(var/obj/item/organ/external/limb in owner.organs) if(limb.dislocated == 1) return remove_verb(owner,/mob/living/carbon/human/proc/relocate) //CHOMPEdit /obj/item/organ/external/update_health() damage = min(max_damage, (brute_dam + burn_dam)) /obj/item/organ/external/New(var/mob/living/carbon/holder) ..(holder, 0) if(istype(owner)) replaced(owner) sync_colour_to_human(owner) spawn(1) get_icon() /obj/item/organ/external/replaced(var/mob/living/carbon/human/target) owner = target forceMove(owner) if(istype(owner)) owner.organs_by_name[organ_tag] = src owner.organs |= src for(var/obj/item/organ/organ in src) organ.replaced(owner,src) owner.refresh_modular_limb_verbs() if(parent_organ) parent = owner.organs_by_name[src.parent_organ] if(parent) if(!parent.children) parent.children = list() parent.children.Add(src) //Remove all stump wounds since limb is not missing anymore for(var/datum/wound/lost_limb/W in parent.wounds) parent.wounds -= W qdel(W) break parent.update_damages() /**************************************************** DAMAGE PROCS ****************************************************/ /obj/item/organ/external/proc/is_damageable(var/additional_damage = 0) //Continued damage to vital organs can kill you, and robot organs don't count towards total damage so no need to cap them. return (vital || (robotic >= ORGAN_ROBOT) || brute_dam + burn_dam + additional_damage < max_damage) /obj/item/organ/external/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list(), permutation = 0) brute = round(brute * brute_mod, 0.1) burn = round(burn * burn_mod, 0.1) if((brute <= 0) && (burn <= 0)) return 0 // High brute damage or sharp objects may damage internal organs if(internal_organs && (brute_dam >= max_damage || (((sharp && brute >= 5) || brute >= 10) && prob(5)))) // Damage an internal organ if(internal_organs && internal_organs.len) var/obj/item/organ/I = pick(internal_organs) brute *= 0.5 I.take_damage(brute) if(status & ORGAN_BROKEN && brute) jostle_bone(brute) if(organ_can_feel_pain() && prob(40) && !isbelly(owner.loc) && !istype(owner.loc, /obj/item/device/dogborg/sleeper)) //VOREStation Edit owner.emote("scream") //getting hit on broken hand hurts if(used_weapon) add_autopsy_data("[used_weapon]", brute + burn) var/can_cut = (sharp) && (robotic < ORGAN_ROBOT) // If the limbs can break, make sure we don't exceed the maximum damage a limb can take before breaking // Non-vital organs are limited to max_damage. You can't kill someone by bludeonging their arm all the way to 200 -- you can // push them faster into paincrit though, as the additional damage is converted into shock. var/brute_overflow = 0 var/burn_overflow = 0 if(is_damageable(brute + burn) || !CONFIG_GET(flag/limbs_can_break)) // CHOMPedit if(brute) if(can_cut) if(sharp && !edge) createwound( PIERCE, brute ) else createwound( CUT, brute ) else createwound( BRUISE, brute ) if(burn) createwound( BURN, burn ) else //If we can't inflict the full amount of damage, spread the damage in other ways //How much damage can we actually cause? var/can_inflict = max_damage * CONFIG_GET(number/organ_health_multiplier) - (brute_dam + burn_dam) // CHOMPEdit var/spillover = 0 if(can_inflict) if (brute > 0) //Inflict all burte damage we can if(can_cut) if(sharp && !edge) createwound( PIERCE, min(brute,can_inflict) ) else createwound( CUT, min(brute,can_inflict) ) else createwound( BRUISE, min(brute,can_inflict) ) //How much more damage can we inflict brute_overflow = max(0, brute - can_inflict) //How much brute damage is left to inflict spillover += max(0, brute - can_inflict) can_inflict = max_damage * CONFIG_GET(number/organ_health_multiplier) - (brute_dam + burn_dam) //Refresh the can_inflict var, so burn doesn't overload the limb if it is set to take both. // CHOMPEdit if (burn > 0 && can_inflict) //Inflict all burn damage we can createwound(BURN, min(burn,can_inflict)) //How much burn damage is left to inflict burn_overflow = max(0, burn - can_inflict) spillover += burn_overflow //If there is pain to dispense. if(spillover) owner.shock_stage += spillover * CONFIG_GET(number/organ_damage_spillover_multiplier) // CHOMPEdit // sync the organ's damage with its wounds src.update_damages() if(owner) owner.updatehealth() //droplimb will call updatehealth() again if it does end up being called //If limb took enough damage, try to cut or tear it off if(owner && loc == owner && !is_stump()) if(!cannot_amputate && CONFIG_GET(flag/limbs_can_break) && (brute_dam + burn_dam) >= (max_damage * CONFIG_GET(number/organ_health_multiplier))) // CHOMPEdit //organs can come off in three cases //1. If the damage source is edge_eligible and the brute damage dealt exceeds the edge threshold, then the organ is cut off. //2. If the damage amount dealt exceeds the disintegrate threshold, the organ is completely obliterated. //3. If the organ has already reached or would be put over it's max damage amount (currently redundant), // and the brute damage dealt exceeds the tearoff threshold, the organ is torn off. //Check edge eligibility var/edge_eligible = 0 if(edge) if(istype(used_weapon,/obj/item)) var/obj/item/W = used_weapon if(W.w_class >= w_class) edge_eligible = 1 else edge_eligible = 1 //VOREStation Add if(nonsolid && damage >= max_damage) droplimb(TRUE, DROPLIMB_EDGE) else if (robotic >= ORGAN_NANOFORM && damage >= max_damage) droplimb(TRUE, DROPLIMB_BURN) //VOREStation Add End //VOREStation Edit - We have special droplimb handling for prom/proteans else if(edge_eligible && brute >= max_damage / DROPLIMB_THRESHOLD_EDGE && prob(brute)) droplimb(0, DROPLIMB_EDGE) else if((burn >= max_damage / DROPLIMB_THRESHOLD_DESTROY) && prob(burn*0.33)) droplimb(0, DROPLIMB_BURN) else if((brute >= max_damage / DROPLIMB_THRESHOLD_DESTROY && prob(brute))) droplimb(0, DROPLIMB_BLUNT) //VOREStation Edit End else if(brute >= max_damage / DROPLIMB_THRESHOLD_TEAROFF && prob(brute*0.33)) droplimb(0, DROPLIMB_EDGE) else if(spread_dam && owner && parent && (brute_overflow || burn_overflow) && (brute_overflow >= 5 || burn_overflow >= 5) && !permutation) //No infinite damage loops. var/brute_third = brute_overflow * 0.33 var/burn_third = burn_overflow * 0.33 if(children && children.len) var/brute_on_children = brute_third / children.len var/burn_on_children = burn_third / children.len spawn() for(var/obj/item/organ/external/C in children) if(!C.is_stump()) C.take_damage(brute_on_children, burn_on_children, 0, 0, null, forbidden_limbs, 1) //Splits the damage to each individual 'child', incase multiple exist. parent.take_damage(brute_third, burn_third, 0, 0, null, forbidden_limbs, 1) return update_icon() /obj/item/organ/external/proc/heal_damage(brute, burn, internal = 0, robo_repair = 0) if(robotic >= ORGAN_ROBOT && !robo_repair) return //Heal damage on the individual wounds for(var/datum/wound/W in wounds) if(brute == 0 && burn == 0) break // heal brute damage if(W.damage_type == BURN) burn = W.heal_damage(burn) else brute = W.heal_damage(brute) if(internal) status &= ~ORGAN_BROKEN //Sync the organ's damage with its wounds src.update_damages() src.update_wounds() owner.updatehealth() var/result = update_icon() return result //Helper proc used by various tools for repairing robot limbs /obj/item/organ/external/proc/robo_repair(var/repair_amount, var/damage_type, var/damage_desc, obj/item/tool, mob/living/user) if((src.robotic < ORGAN_ROBOT)) return 0 var/damage_amount switch(damage_type) if(BRUTE) damage_amount = brute_dam if(BURN) damage_amount = burn_dam if("omni") damage_amount = max(brute_dam,burn_dam) else return 0 if(!damage_amount) to_chat(user, "Nothing to fix!") return 0 if(brute_dam + burn_dam >= min_broken_damage) //VOREStation Edit - Makes robotic limb damage scalable to_chat(user, "The damage is far too severe to patch over externally.") return 0 if(user == src.owner) var/grasp if(user.l_hand == tool && (src.body_part & (ARM_LEFT|HAND_LEFT))) grasp = "l_hand" else if(user.r_hand == tool && (src.body_part & (ARM_RIGHT|HAND_RIGHT))) grasp = "r_hand" if(grasp) to_chat(user, "You can't reach your [src.name] while holding [tool] in your [owner.get_bodypart_name(grasp)].") return 0 user.setClickCooldown(user.get_attack_speed(tool)) if(!do_mob(user, owner, 10)) to_chat(user, "You must stand still to do that.") return 0 switch(damage_type) if(BRUTE) src.heal_damage(repair_amount, 0, 0, 1) if(BURN) src.heal_damage(0, repair_amount, 0, 1) if("omni")src.heal_damage(repair_amount, repair_amount, 0, 1) if(damage_desc) var/fix_verb = (damage_amount > repair_amount) ? "patches" : "finishes patching" if(user == src.owner) var/datum/gender/T = gender_datums[user.get_visible_gender()] user.visible_message("\The [user] [fix_verb] [damage_desc] on [T.his] [src.name] with [tool].") else user.visible_message("\The [user] [fix_verb] [damage_desc] on [owner]'s [src.name] with [tool].") return 1 /* This function completely restores a damaged organ to perfect condition. */ /obj/item/organ/external/rejuvenate(var/ignore_prosthetic_prefs) damage_state = "00" status = 0 brute_dam = 0 burn_dam = 0 germ_level = 0 wounds.Cut() number_wounds = 0 // handle internal organs for(var/obj/item/organ/current_organ in internal_organs) current_organ.rejuvenate(ignore_prosthetic_prefs) // remove embedded objects and drop them on the floor for(var/obj/implanted_object in implants) if(istype(implanted_object,/obj/item/weapon/implant) || istype(implanted_object,/obj/item/device/nif)) // We don't want to remove REAL implants. Just shrapnel etc. //VOREStation Edit - NIFs pls continue implanted_object.loc = get_turf(src) implants -= implanted_object if(!owner.has_embedded_objects()) owner.clear_alert("embeddedobject") if(owner && !ignore_prosthetic_prefs) if(owner.client && owner.client.prefs && owner.client.prefs.real_name == owner.real_name) var/status = owner.client.prefs.organ_data[organ_tag] if(status == "amputated") remove_rejuv() else if(status == "cyborg") var/robodata = owner.client.prefs.rlimb_data[organ_tag] if(robodata) robotize(robodata) else robotize() owner.updatehealth() /obj/item/organ/external/remove_rejuv() if(owner) owner.organs -= src owner.organs_by_name[organ_tag] = null owner.organs_by_name -= organ_tag while(null in owner.organs) owner.organs -= null if(children && children.len) for(var/obj/item/organ/external/E in children) E.remove_rejuv() children.Cut() for(var/obj/item/organ/internal/I in internal_organs) I.remove_rejuv() ..() /obj/item/organ/external/proc/createwound(var/type = CUT, var/damage) if(damage == 0) return //moved this before the open_wound check so that having many small wounds for example doesn't somehow protect you from taking internal damage (because of the return) //Possibly trigger an internal wound, too. var/local_damage = brute_dam + burn_dam + damage if((damage > 15) && (type != BURN) && (local_damage > 30) && prob(damage) && (robotic < ORGAN_ROBOT) && !(species.flags & NO_BLOOD)) var/datum/wound/internal_bleeding/I = new (min(damage - 15, 15)) wounds += I owner.custom_pain("You feel something rip in your [name]!", 50) //Burn damage can cause fluid loss due to blistering and cook-off if((damage > 5 || damage + burn_dam >= 15) && type == BURN && (robotic < ORGAN_ROBOT) && !(species.flags & NO_BLOOD)) var/fluid_loss = 0.4 * (damage/(owner.getMaxHealth() - CONFIG_GET(number/health_threshold_dead))) * owner.species.blood_volume*(1 - owner.species.blood_level_fatal) // CHOMPEdit owner.remove_blood(fluid_loss) // first check whether we can widen an existing wound if(wounds.len > 0 && prob(max(50+(number_wounds-1)*10,90))) if((type == CUT || type == BRUISE) && damage >= 5) //we need to make sure that the wound we are going to worsen is compatible with the type of damage... var/list/compatible_wounds = list() for (var/datum/wound/W in wounds) if (W.can_worsen(type, damage)) compatible_wounds += W if(compatible_wounds.len) var/datum/wound/W = pick(compatible_wounds) W.open_wound(damage) if(prob(25)) if(robotic >= ORGAN_ROBOT) owner.visible_message("The damage to [owner.name]'s [name] worsens.",\ "The damage to your [name] worsens.",\ "You hear the screech of abused metal.") else owner.visible_message("The wound on [owner.name]'s [name] widens with a nasty ripping noise.",\ "The wound on your [name] widens with a nasty ripping noise.",\ "You hear a nasty ripping noise, as if flesh is being torn apart.") return //Creating wound var/wound_type = get_wound_type(type, damage) if(wound_type) var/datum/wound/W = new wound_type(damage) //Check whether we can add the wound to an existing wound for(var/datum/wound/other in wounds) if(other.can_merge(W)) other.merge_wound(W) W = null // to signify that the wound was added break if(W) wounds += W /**************************************************** PROCESSING & UPDATING ****************************************************/ //external organs handle brokenness a bit differently when it comes to damage. Instead brute_dam is checked inside process() //this also ensures that an external organ cannot be "broken" without broken_description being set. /obj/item/organ/external/is_broken() return ((status & ORGAN_CUT_AWAY) || (status & ORGAN_BROKEN) && (!splinted || (splinted && (splinted in src.contents) && prob(30)))) //Determines if we even need to process this organ. /obj/item/organ/external/proc/need_process() if(status & (ORGAN_CUT_AWAY|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_DESTROYED|ORGAN_DEAD|ORGAN_MUTATED)) return 1 if(brute_dam || burn_dam)//VOREStation Edit - But they do for medichines! ---&& (robotic < ORGAN_ROBOT)) //Robot limbs don't autoheal and thus don't need to process when damaged return 1 if(last_dam != brute_dam + burn_dam) // Process when we are fully healed up. last_dam = brute_dam + burn_dam return 1 else last_dam = brute_dam + burn_dam if(germ_level) return 1 return 0 /obj/item/organ/external/process() if(owner) //Dismemberment //if(parent && parent.is_stump()) //should never happen // warning("\The [src] ([src.type]) belonging to [owner] ([owner.type]) was attached to a stump") // remove() // return // Process wounds, doing healing etc. Only do this every few ticks to save processing power if(owner.life_tick % wound_update_accuracy == 0) update_wounds() //Chem traces slowly vanish if(owner.life_tick % 10 == 0) for(var/chemID in trace_chemicals) trace_chemicals[chemID] = trace_chemicals[chemID] - 1 if(trace_chemicals[chemID] <= 0) trace_chemicals.Remove(chemID) //Infections update_germs() else ..() //Updating germ levels. Handles organ germ levels and necrosis. /* The INFECTION_LEVEL values defined in setup.dm control the time it takes to reach the different infection levels. Since infection growth is exponential, you can adjust the time it takes to get from one germ_level to another using the rough formula: desired_germ_level = initial_germ_level*e^(desired_time_in_seconds/1000) So if I wanted it to take an average of 15 minutes to get from level one (100) to level two I would set INFECTION_LEVEL_TWO to 100*e^(15*60/1000) = 245. Note that this is the average time, the actual time is dependent on RNG. INFECTION_LEVEL_ONE below this germ level nothing happens, and the infection doesn't grow INFECTION_LEVEL_TWO above this germ level the infection will start to spread to internal and adjacent organs INFECTION_LEVEL_THREE above this germ level the player will take additional toxin damage per second, and will die in minutes without antitox. also, above this germ level you will need to overdose on spaceacillin to reduce the germ_level. Note that amputating the affected organ does in fact remove the infection from the player's body. */ /obj/item/organ/external/proc/update_germs() if(robotic >= ORGAN_ROBOT || (owner.species && (owner.species.flags & IS_PLANT || (owner.species.flags & NO_INFECT)))) //Robotic limbs shouldn't be infected, nor should nonexistant limbs. germ_level = 0 return if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs //** Syncing germ levels with external wounds handle_germ_sync() //** Handle antibiotics and curing infections handle_antibiotics() //** Handle the effects of infections handle_germ_effects() /obj/item/organ/external/proc/handle_germ_sync() var/antibiotics = owner.chem_effects[CE_ANTIBIOTIC] for(var/datum/wound/W in wounds) //Open wounds can become infected if (owner.germ_level > W.germ_level && W.infection_check()) W.germ_level++ if (antibiotics < ANTIBIO_NORM) for(var/datum/wound/W in wounds) //Infected wounds raise the organ's germ level if (W.germ_level > germ_level) germ_level++ break //limit increase to a maximum of one per second /obj/item/organ/external/handle_germ_effects() . = ..() //May be null or an infection level, if null then no specific processing needed here if(!.) return var/antibiotics = owner.chem_effects[CE_ANTIBIOTIC] if(. >= 2 && antibiotics < ANTIBIO_NORM) //INFECTION_LEVEL_TWO //spread the infection to internal organs var/obj/item/organ/target_organ = null //make internal organs become infected one at a time instead of all at once for (var/obj/item/organ/I in internal_organs) if (I.germ_level > 0 && I.germ_level < min(germ_level, INFECTION_LEVEL_TWO)) //once the organ reaches whatever we can give it, or level two, switch to a different one if (!target_organ || I.germ_level > target_organ.germ_level) //choose the organ with the highest germ_level target_organ = I if (!target_organ) //figure out which organs we can spread germs to and pick one at random var/list/candidate_organs = list() for (var/obj/item/organ/I in internal_organs) if (I.germ_level < germ_level) candidate_organs |= I if (candidate_organs.len) target_organ = pick(candidate_organs) if (target_organ) target_organ.germ_level++ //spread the infection to child and parent organs if (children) for (var/obj/item/organ/external/child in children) if (child.germ_level < germ_level && (child.robotic < ORGAN_ROBOT)) if (child.germ_level < INFECTION_LEVEL_ONE*2 || prob(30)) child.germ_level++ if (parent) if (parent.germ_level < germ_level && (parent.robotic < ORGAN_ROBOT)) if (parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(30)) parent.germ_level++ if(. >= 3 && antibiotics < ANTIBIO_OD) //INFECTION_LEVEL_THREE if (!(status & ORGAN_DEAD)) status |= ORGAN_DEAD to_chat(owner, "You can't feel your [name] anymore...") owner.update_icons_body() for (var/obj/item/organ/external/child in children) child.germ_level += 110 //Burst of infection from a parent organ becoming necrotic //Updating wounds. Handles wound natural I had some free spachealing, internal bleedings and infections /obj/item/organ/external/proc/update_wounds() if((robotic >= ORGAN_ROBOT) || (species.flags & UNDEAD)) //Robotic and dead limbs don't heal or get worse. for(var/datum/wound/W in wounds) //Repaired wounds disappear though if(W.damage <= 0) //and they disappear right away wounds -= W //TODO: robot wounds for robot limbs src.update_damages() if (update_icon()) owner.UpdateDamageIcon(1) return for(var/datum/wound/W in wounds) // wounds can disappear after 10 minutes at the earliest if(W.damage <= 0 && W.created + 10 MINUTES <= world.time) wounds -= W continue // let the GC handle the deletion of the wound // Internal wounds get worse over time. Low temperatures (cryo) stop them. if(W.internal && owner.bodytemperature >= 170) var/bicardose = owner.reagents.get_reagent_amount("bicaridine") var/inaprovaline = owner.reagents.get_reagent_amount("inaprovaline") var/myeldose = owner.reagents.get_reagent_amount("myelamine") if(!(W.can_autoheal() || (bicardose && inaprovaline) || myeldose)) //bicaridine and inaprovaline stop internal wounds from growing bigger with time, unless it is so small that it is already healing W.open_wound(0.1 * wound_update_accuracy) owner.remove_blood( wound_update_accuracy * W.damage/40) //line should possibly be moved to handle_blood, so all the bleeding stuff is in one place. if(prob(1 * wound_update_accuracy)) owner.custom_pain("You feel a stabbing pain in your [name]!", 50) // slow healing var/heal_amt = 0 // if damage >= 50 AFTER treatment then it's probably too severe to heal within the timeframe of a round. if (W.can_autoheal() && W.wound_damage() < 50) heal_amt += 0.5 //we only update wounds once in [wound_update_accuracy] ticks so have to emulate realtime heal_amt = heal_amt * wound_update_accuracy //configurable regen speed woo, no-regen hardcore or instaheal hugbox, choose your destiny heal_amt = heal_amt * CONFIG_GET(number/organ_regeneration_multiplier) // CHOMPEdit // amount of healing is spread over all the wounds heal_amt = heal_amt / (wounds.len + 1) // making it look prettier on scanners heal_amt = round(heal_amt,0.1) W.heal_damage(heal_amt) // Salving also helps against infection if(W.germ_level > 0 && W.salved && prob(2)) W.disinfected = 1 W.germ_level = 0 // sync the organ's damage with its wounds src.update_damages() if (update_icon()) owner.UpdateDamageIcon(1) //Updates brute_damn and burn_damn from wound damages. Updates BLEEDING status. /obj/item/organ/external/proc/update_damages() number_wounds = 0 brute_dam = 0 burn_dam = 0 status &= ~ORGAN_BLEEDING var/clamped = 0 var/mob/living/carbon/human/H if(istype(owner,/mob/living/carbon/human)) H = owner //update damage counts for(var/datum/wound/W in wounds) if(!W.internal) //so IB doesn't count towards crit/paincrit if(W.damage_type == BURN) burn_dam += W.damage else brute_dam += W.damage if(!(robotic >= ORGAN_ROBOT) && W.bleeding() && (H && H.should_have_organ(O_HEART)) && !(H.species.flags & NO_BLOOD)) W.bleed_timer-- status |= ORGAN_BLEEDING clamped |= W.clamped number_wounds += W.amount //things tend to bleed if they are CUT OPEN if (open && !clamped && (H && H.should_have_organ(O_HEART))) status |= ORGAN_BLEEDING //Bone fractures if(CONFIG_GET(flag/bones_can_break) && brute_dam > min_broken_damage * CONFIG_GET(number/organ_health_multiplier) && !(robotic >= ORGAN_ROBOT)) // CHOMPEdit src.fracture() update_health() // new damage icon system // adjusted to set damage_state to brute/burn code only (without r_name0 as before) /obj/item/organ/external/update_icon() var/n_is = damage_state_text() if (n_is != damage_state) damage_state = n_is return 1 return 0 // new damage icon system // returns just the brute/burn damage code /obj/item/organ/external/proc/damage_state_text() var/tburn = 0 var/tbrute = 0 if(burn_dam ==0) tburn =0 else if (burn_dam < (max_damage * 0.25 / 2)) tburn = 1 else if (burn_dam < (max_damage * 0.75 / 2)) tburn = 2 else tburn = 3 if (brute_dam == 0) tbrute = 0 else if (brute_dam < (max_damage * 0.25 / 2)) tbrute = 1 else if (brute_dam < (max_damage * 0.75 / 2)) tbrute = 2 else tbrute = 3 return "[tbrute][tburn]" /**************************************************** DISMEMBERMENT ****************************************************/ //Handles dismemberment /obj/item/organ/external/proc/droplimb(var/clean, var/disintegrate = DROPLIMB_EDGE, var/ignore_children = null) if(cannot_amputate || !owner) return //VOREStation Add if(robotic >= ORGAN_NANOFORM) disintegrate = DROPLIMB_BURN //Ashes will be fine else if(disintegrate == DROPLIMB_EDGE && nonsolid) //VOREStation Add End disintegrate = DROPLIMB_BLUNT //splut GLOB.lost_limbs_shift_roundstat++ switch(disintegrate) if(DROPLIMB_EDGE) if(!clean) var/gore_sound = "[(robotic >= ORGAN_ROBOT) ? "tortured metal" : "ripping tendons and flesh"]" owner.visible_message( "\The [owner]'s [src.name] flies off in an arc!",\ "Your [src.name] goes flying off!",\ "You hear a terrible sound of [gore_sound].") if(DROPLIMB_BURN) if(cannot_gib) return var/gore = "[(robotic >= ORGAN_ROBOT) ? "": " of burning flesh"]" owner.visible_message( "\The [owner]'s [src.name] flashes away into ashes!",\ "Your [src.name] flashes away into ashes!",\ "You hear a crackling sound[gore].") if(DROPLIMB_BLUNT) if(cannot_gib) return var/gore = "[(robotic >= ORGAN_ROBOT) ? "": " in shower of gore"]" var/gore_sound = "[(status >= ORGAN_ROBOT) ? "rending sound of tortured metal" : "sickening splatter of gore"]" owner.visible_message( "\The [owner]'s [src.name] explodes[gore]!",\ "Your [src.name] explodes[gore]!",\ "You hear the [gore_sound].") var/mob/living/carbon/human/victim = owner //Keep a reference for post-removed(). var/obj/item/organ/external/parent_organ = parent var/use_flesh_colour = species?.get_flesh_colour(owner) ? species.get_flesh_colour(owner) : "#C80000" var/use_blood_colour = species?.get_blood_colour(owner) ? species.get_blood_colour(owner) : "#C80000" removed(null, ignore_children) victim?.traumatic_shock += 60 if(parent_organ) var/datum/wound/lost_limb/W = new (src, disintegrate, clean) if(clean) parent_organ.wounds |= W parent_organ.update_damages() else var/obj/item/organ/external/stump/stump = new (victim, 0, src) if(robotic >= ORGAN_ROBOT) stump.robotize() stump.wounds |= W victim.organs |= stump stump.update_damages() spawn(1) if(istype(victim)) victim.updatehealth() victim.UpdateDamageIcon() victim.update_icons_body() else victim.update_icons() dir = 2 var/atom/droploc = victim.drop_location() switch(disintegrate) if(DROPLIMB_EDGE) appearance_flags &= ~PIXEL_SCALE compile_icon() add_blood(victim) var/matrix/M = matrix() M.Turn(rand(180)) src.transform = M if(!clean) // Throw limb around. if(src && istype(loc,/turf)) throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5) dir = 2 if(DROPLIMB_BURN) new /obj/effect/decal/cleanable/ash(droploc) for(var/obj/item/I in src) if(I.w_class > ITEMSIZE_SMALL && !istype(I,/obj/item/organ)) I.forceMove(droploc) qdel(src) if(DROPLIMB_BLUNT) var/obj/effect/decal/cleanable/blood/gibs/gore if(robotic >= ORGAN_ROBOT) gore = new /obj/effect/decal/cleanable/blood/gibs/robot(droploc) else gore = new /obj/effect/decal/cleanable/blood/gibs(droploc) if(species) gore.fleshcolor = use_flesh_colour gore.basecolor = use_blood_colour gore.update_icon() gore.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5) for(var/obj/item/organ/I in internal_organs) I.removed() if(istype(loc,/turf)) I.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5) for(var/obj/item/I in src) if(I.w_class <= ITEMSIZE_SMALL) qdel(I) continue I.forceMove(droploc) I.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5) qdel(src) if(victim.l_hand) if(istype(victim.l_hand,/obj/item/weapon/material/twohanded)) //if they're holding a two-handed weapon, drop it now they've lost a hand victim.l_hand.update_held_icon() if(victim.r_hand) if(istype(victim.r_hand,/obj/item/weapon/material/twohanded)) victim.r_hand.update_held_icon() /**************************************************** HELPERS ****************************************************/ /obj/item/organ/external/proc/is_stump() return 0 /obj/item/organ/external/proc/release_restraints(var/mob/living/carbon/human/holder) if(!holder) holder = owner if(!holder) return if (holder.handcuffed && (body_part in list(ARM_LEFT, ARM_RIGHT, HAND_LEFT, HAND_RIGHT))) holder.visible_message(\ "\The [holder.handcuffed.name] falls off of [holder.name].",\ "\The [holder.handcuffed.name] falls off you.") holder.drop_from_inventory(holder.handcuffed) if (holder.legcuffed && (body_part in list(FOOT_LEFT, FOOT_RIGHT, LEG_LEFT, LEG_RIGHT))) holder.visible_message(\ "\The [holder.legcuffed.name] falls off of [holder.name].",\ "\The [holder.legcuffed.name] falls off you.") holder.drop_from_inventory(holder.legcuffed) // checks if all wounds on the organ are bandaged /obj/item/organ/external/proc/is_bandaged() for(var/datum/wound/W in wounds) if(W.internal) continue if(!W.bandaged) return 0 return 1 // checks if all wounds on the organ are salved /obj/item/organ/external/proc/is_salved() for(var/datum/wound/W in wounds) if(W.internal) continue if(!W.salved) return 0 return 1 // checks if all wounds on the organ are disinfected /obj/item/organ/external/proc/is_disinfected() for(var/datum/wound/W in wounds) if(W.internal) continue if(!W.disinfected) return 0 return 1 /obj/item/organ/external/proc/bandage() var/rval = 0 status &= ~ORGAN_BLEEDING for(var/datum/wound/W in wounds) if(W.internal) continue rval |= !W.bandaged W.bandaged = 1 return rval /obj/item/organ/external/proc/salve() var/rval = 0 for(var/datum/wound/W in wounds) rval |= !W.salved W.salved = 1 return rval /obj/item/organ/external/proc/disinfect() var/rval = 0 for(var/datum/wound/W in wounds) if(W.internal) continue rval |= !W.disinfected W.disinfected = 1 W.germ_level = 0 return rval /obj/item/organ/external/proc/organ_clamp() var/rval = 0 src.status &= ~ORGAN_BLEEDING for(var/datum/wound/W in wounds) if(W.internal) continue rval |= !W.clamped W.clamped = 1 return rval /obj/item/organ/external/proc/fracture() if(robotic >= ORGAN_ROBOT) return //ORGAN_BROKEN doesn't have the same meaning for robot limbs if((status & ORGAN_BROKEN) || cannot_break) return if(owner) if(organ_can_feel_pain() && !isbelly(owner.loc) && !isliving(owner.loc)) //CHOMPEdit Begin owner.custom_pain(pick(\ "You hear a loud cracking sound coming from \the [owner].",\ "Something feels like it shattered in your [name]!",\ "You hear a sickening crack."),brokenpain) //CHOMPEdit End owner.emote("scream") jostle_bone() //VOREStation Edit End playsound(src, "fracture", 90, 1, -2) // CHOMPedit: Much more audible bonebreaks. status |= ORGAN_BROKEN broken_description = pick("broken","fracture","hairline fracture") // Fractures have a chance of getting you out of restraints if (prob(25)) release_restraints() // This is mostly for the ninja suit to stop ninja being so crippled by breaks. // TODO: consider moving this to a suit proc or process() or something during // hardsuit rewrite. if(!(splinted) && owner && istype(owner.wear_suit, /obj/item/clothing/suit/space)) var/obj/item/clothing/suit/space/suit = owner.wear_suit suit.handle_fracture(owner, src) return 1 /obj/item/organ/external/proc/mend_fracture() if(robotic >= ORGAN_ROBOT) return 0 //ORGAN_BROKEN doesn't have the same meaning for robot limbs if(brute_dam > min_broken_damage * CONFIG_GET(number/organ_health_multiplier)) // CHOMPEdit return 0 //will just immediately fracture again status &= ~ORGAN_BROKEN return 1 /obj/item/organ/external/proc/apply_splint(var/atom/movable/splint) if(!splinted) splinted = splint if(!applied_pressure) applied_pressure = splint return 1 return 0 /obj/item/organ/external/proc/remove_splint() if(splinted) if(splinted.loc == src) splinted.dropInto(owner? owner.loc : src.loc) if(applied_pressure == splinted) applied_pressure = null splinted = null return 1 return 0 /obj/item/organ/external/robotize(var/company, var/skip_prosthetics = 0, var/keep_organs = 0) if(robotic >= ORGAN_ROBOT) return ..() if(company) model = company var/datum/robolimb/R = all_robolimbs[company] if(!R || (species && (species.name in R.species_cannot_use))) R = basic_robolimb if(R) force_icon = R.icon brute_mod *= R.robo_brute_mod burn_mod *= R.robo_burn_mod skip_robo_icon = R.no_icon //CHOMPStation edit digi_prosthetic = R.can_be_digitigrade //CHOMPStation edit if(R.lifelike) robotic = ORGAN_LIFELIKE name = "[initial(name)]" else if(R.modular_bodyparts == MODULAR_BODYPART_PROSTHETIC) name = "prosthetic [initial(name)]" else name = "robotic [initial(name)]" desc = "[R.desc] It looks like it was produced by [R.company]." dislocated = -1 cannot_break = 1 min_broken_damage = ROBOLIMB_REPAIR_CAP //VOREStation Addition - Makes robotic limb damage scalable remove_splint() get_icon() unmutate() drop_sound = 'sound/items/drop/weldingtool.ogg' pickup_sound = 'sound/items/pickup/weldingtool.ogg' for(var/obj/item/organ/external/T in children) T.robotize(company, keep_organs = keep_organs) if(owner) if(!keep_organs) for(var/obj/item/organ/thing in internal_organs) if(istype(thing)) if(thing.vital) continue internal_organs -= thing owner.internal_organs_by_name[thing.organ_tag] = null owner.internal_organs_by_name -= thing.organ_tag owner.internal_organs.Remove(thing) qdel(thing) while(null in owner.internal_organs) owner.internal_organs -= null owner.refresh_modular_limb_verbs() return 1 /obj/item/organ/external/proc/mutate() if(src.robotic >= ORGAN_ROBOT) return src.status |= ORGAN_MUTATED if(owner) owner.update_icons_body() /obj/item/organ/external/proc/unmutate() src.status &= ~ORGAN_MUTATED if(owner) owner.update_icons_body() /obj/item/organ/external/proc/get_damage() //returns total damage return (brute_dam+burn_dam) //could use max_damage? /obj/item/organ/external/proc/has_infected_wound() for(var/datum/wound/W in wounds) if(W.germ_level > INFECTION_LEVEL_ONE) return 1 return 0 /obj/item/organ/external/proc/is_usable() return !(status & (ORGAN_MUTATED|ORGAN_DEAD)) /obj/item/organ/external/proc/is_malfunctioning() return ((robotic >= ORGAN_ROBOT) && (brute_dam + burn_dam) >= min_broken_damage*0.83 && prob(brute_dam + burn_dam)) //VOREStation Edit - Makes robotic limb damage scalable /obj/item/organ/external/proc/embed(var/obj/item/weapon/W, var/silent = 0) if(!owner || loc != owner) return if(!silent) owner.visible_message("\The [W] sticks in the wound!") implants += W owner.embedded_flag = 1 add_verb(owner,/mob/proc/yank_out_object) //CHOMPEdit owner.throw_alert("embeddedobject", /obj/screen/alert/embeddedobject) W.add_blood(owner) if(ismob(W.loc)) var/mob/living/H = W.loc H.drop_from_inventory(W) W.loc = owner /obj/item/organ/external/removed(var/mob/living/user, var/ignore_children = 0) if(!owner) return var/is_robotic = robotic >= ORGAN_ROBOT var/mob/living/carbon/human/victim = owner ..() victim.bad_external_organs -= src for(var/atom/movable/implant in implants) //large items and non-item objs fall to the floor, everything else stays var/obj/item/I = implant if(istype(I) && I.w_class < ITEMSIZE_NORMAL) implant.loc = get_turf(victim.loc) else implant.loc = src implants.Cut() // Attached organs also fly off. if(!ignore_children) for(var/obj/item/organ/external/O in children) O.removed() if(O) O.loc = src for(var/obj/item/I in O.contents) I.loc = src // Grab all the internal giblets too. for(var/obj/item/organ/organ in internal_organs) organ.removed() organ.loc = src // Remove parent references parent?.children -= src parent = null release_restraints(victim) victim.organs -= src victim.organs_by_name[organ_tag] = null // Remove from owner's vars. status |= ORGAN_CUT_AWAY //Checked during surgeries to reattach it //Robotic limbs explode if sabotaged. if(is_robotic && sabotaged) victim.visible_message( "\The [victim]'s [src.name] explodes violently!",\ "Your [src.name] explodes!",\ "You hear an explosion!") explosion(get_turf(owner),-1,-1,2,3) var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() spark_system.set_up(5, 0, victim) spark_system.attach(owner) spark_system.start() spawn(10) qdel(spark_system) qdel(src) victim.refresh_modular_limb_verbs() victim.update_icons_body() /obj/item/organ/external/proc/disfigure(var/type = "brute") if (disfigured) return if(owner) if(type == "brute") owner.visible_message("You hear a sickening cracking sound coming from \the [owner]'s [name].", \ "Your [name] becomes a mangled mess!", \ "You hear a sickening crack.") else owner.visible_message("\The [owner]'s [name] melts away, turning into mangled mess!", \ "Your [name] melts away!", \ "You hear a sickening sizzle.") disfigured = 1 /obj/item/organ/external/proc/jostle_bone(force) if(!(status & ORGAN_BROKEN)) //intact bones stay still return if(brute_dam + force < min_broken_damage/5) //no papercuts moving bones return if(internal_organs.len && prob(brute_dam + force)) owner.custom_pain("A piece of bone in your [encased ? encased : name] moves painfully!", 50) var/obj/item/organ/I = pick(internal_organs) I.take_damage(rand(3,5)) /obj/item/organ/external/proc/get_wounds_desc() . = "" if(status & ORGAN_DESTROYED && !is_stump()) . += "tear at [amputation_point] so severe that it hangs by a scrap of flesh" //Handle robotic and synthetic organ damage if(robotic >= ORGAN_ROBOT) var/LL //Life-Like, aka only show that it's robotic in heavy damage if(robotic >= ORGAN_LIFELIKE) LL = 1 if(brute_dam) switch(brute_dam) if(0 to 20) . += "some [LL ? "cuts" : "dents"]" if(21 to INFINITY) . += "[LL ? pick("exposed wiring","torn-back synthflesh") : pick("a lot of dents","severe denting")]" if(brute_dam && burn_dam) . += " and " if(burn_dam) switch(burn_dam) if(0 to 20) . += "some burns" if(21 to INFINITY) . += "[LL ? pick("roasted synth-flesh","melted internal wiring") : pick("many burns","scorched metal")]" if(open) if(brute_dam || burn_dam) . += " and " if(open == 1) . += "some exposed screws" else . += "an open panel" return //Normal organic organ damage var/list/wound_descriptors = list() if(open > 1) wound_descriptors["an open incision"] = 1 else if (open) wound_descriptors["an incision"] = 1 for(var/datum/wound/W in wounds) if(W.internal && !open) continue // can't see internal wounds var/this_wound_desc = W.desc if(W.damage_type == BURN && W.salved) this_wound_desc = "salved [this_wound_desc]" if(W.bleeding()) this_wound_desc = "bleeding [this_wound_desc]" else if(W.bandaged) this_wound_desc = "bandaged [this_wound_desc]" if(W.germ_level > 600) this_wound_desc = "badly infected [this_wound_desc]" else if(W.germ_level > 330) this_wound_desc = "lightly infected [this_wound_desc]" if(wound_descriptors[this_wound_desc]) wound_descriptors[this_wound_desc] += W.amount else wound_descriptors[this_wound_desc] = W.amount if(wound_descriptors.len) var/list/flavor_text = list() var/list/no_exclude = list("gaping wound", "big gaping wound", "massive wound", "large bruise",\ "huge bruise", "massive bruise", "severe burn", "large burn", "deep burn", "carbonised area") //note to self make this more robust for(var/wound in wound_descriptors) switch(wound_descriptors[wound]) if(1) flavor_text += "[prob(10) && !(wound in no_exclude) ? "what might be " : ""]a [wound]" if(2) flavor_text += "[prob(10) && !(wound in no_exclude) ? "what might be " : ""]a pair of [wound]s" if(3 to 5) flavor_text += "several [wound]s" if(6 to INFINITY) flavor_text += "a ton of [wound]\s" return english_list(flavor_text) // Returns a list of the clothing (not glasses) that are covering this part /obj/item/organ/external/proc/get_covering_clothing(var/target_covering) // target_covering checks for mouth/eye coverage var/list/covering_clothing = list() if(!target_covering) target_covering = src.body_part if(owner) var/list/protective_gear = list(owner.head, owner.wear_mask, owner.wear_suit, owner.w_uniform, owner.gloves, owner.shoes, owner.glasses) for(var/obj/item/clothing/gear in protective_gear) if(gear.body_parts_covered & target_covering) covering_clothing |= gear if(LAZYLEN(gear.accessories)) for(var/obj/item/clothing/accessory/bling in gear.accessories) if(bling.body_parts_covered & src.body_part) covering_clothing |= bling return covering_clothing /mob/living/carbon/human/proc/has_embedded_objects() . = 0 for(var/obj/item/organ/external/L in organs) for(var/obj/item/I in L.implants) if(!istype(I,/obj/item/weapon/implant) && !istype(I,/obj/item/device/nif)) //VOREStation Add - NIFs return 1 /obj/item/organ/external/proc/is_hidden_by_sprite_accessory(var/clothing_only = FALSE) // Clothing only will mean the check should only be used in places where we want to hide clothing icon, not organ itself. if(owner && owner.tail_style && owner.tail_style.hide_body_parts && (organ_tag in owner.tail_style.hide_body_parts)) return 1 if(clothing_only && markings.len) for(var/M in markings) var/datum/sprite_accessory/marking/mark = markings[M]["datum"] if(mark.hide_body_parts && (organ_tag in mark.hide_body_parts)) return 1