/obj/item/bodypart name = "limb" desc = "Why is it detached..." force = 3 throwforce = 3 icon = 'icons/mob/human_parts.dmi' w_class = WEIGHT_CLASS_SMALL icon_state = "" layer = BELOW_MOB_LAYER //so it isn't hidden behind objects when on the floor var/mob/living/carbon/owner = null var/mob/living/carbon/original_owner = null var/status = BODYPART_ORGANIC var/needs_processing = FALSE var/body_zone //BODY_ZONE_CHEST, BODY_ZONE_L_ARM, etc , used for def_zone var/list/aux_icons // associative list, currently used for hands var/body_part = null //bitflag used to check which clothes cover this bodypart var/use_digitigrade = NOT_DIGITIGRADE //Used for alternate legs, useless elsewhere var/list/embedded_objects = list() var/held_index = 0 //are we a hand? if so, which one! var/is_pseudopart = FALSE //For limbs that don't really exist, eg chainsaws var/disabled = BODYPART_NOT_DISABLED //If disabled, limb is as good as missing var/body_damage_coeff = 1 //Multiplier of the limb's damage that gets applied to the mob var/stam_damage_coeff = 0.75 var/brutestate = 0 var/burnstate = 0 var/brute_dam = 0 var/burn_dam = 0 var/stamina_dam = 0 var/max_stamina_damage = 0 var/incoming_stam_mult = 1 //Multiplier for incoming staminaloss, decreases when taking staminaloss when the limb is disabled, resets back to 1 when limb is no longer disabled. var/max_damage = 0 var/stam_heal_tick = 0 //per Life(). Defaults to 0 due to citadel changes var/brute_reduction = 0 //Subtracted to brute damage taken var/burn_reduction = 0 //Subtracted to burn damage taken //Coloring and proper item icon update var/skin_tone = "" var/body_gender = "" var/species_id = "" var/color_src var/base_bp_icon //Overrides the icon being used for this limb. This is mainly for downstreams, implemented and maintained as a favor in return for implementing synths. And also because should_draw_* for icon overrides was pretty messy. You're welcome. var/should_draw_gender = FALSE var/species_color = "" var/mutation_color = "" var/no_update = 0 var/body_markings = "" //for bodypart markings var/body_markings_icon = 'modular_citadel/icons/mob/mam_markings.dmi' var/list/markings_color = list() var/aux_marking var/digitigrade_type var/animal_origin = null //for nonhuman bodypart (e.g. monkey) var/dismemberable = 1 //whether it can be dismembered with a weapon. var/px_x = 0 var/px_y = 0 var/species_flags_list = list() var/dmg_overlay_type //the type of damage overlay (if any) to use when this bodypart is bruised/burned. //Damage messages used by help_shake_act() var/light_brute_msg = "bruised" var/medium_brute_msg = "battered" var/heavy_brute_msg = "mangled" var/light_burn_msg = "numb" var/medium_burn_msg = "blistered" var/heavy_burn_msg = "peeling away" /// The wounds currently afflicting this body part var/list/wounds /// The scars currently afflicting this body part var/list/scars /// Our current stored wound damage multiplier var/wound_damage_multiplier = 1 /// This number is subtracted from all wound rolls on this bodypart, higher numbers mean more defense, negative means easier to wound var/wound_resistance = 0 /// When this bodypart hits max damage, this number is added to all wound rolls. Obviously only relevant for bodyparts that have damage caps. var/disabled_wound_penalty = 15 /// A hat won't cover your face, but a shirt covering your chest will cover your... you know, chest var/scars_covered_by_clothes = TRUE /// Descriptions for the locations on the limb for scars to be assigned, just cosmetic var/list/specific_locations = list("general area") /// So we know if we need to scream if this limb hits max damage var/last_maxed /// How much generic bleedstacks we have on this bodypart var/generic_bleedstacks /obj/item/bodypart/examine(mob/user) . = ..() if(brute_dam > DAMAGE_PRECISION) . += "This limb has [brute_dam > 30 ? "severe" : "minor"] bruising." if(burn_dam > DAMAGE_PRECISION) . += "This limb has [burn_dam > 30 ? "severe" : "minor"] burns." /obj/item/bodypart/blob_act() take_damage(max_damage) /obj/item/bodypart/Destroy() if(owner) owner.bodyparts -= src owner = null return ..() /obj/item/bodypart/attack(mob/living/carbon/C, mob/user) if(ishuman(C)) var/mob/living/carbon/human/H = C if(HAS_TRAIT(C, TRAIT_LIMBATTACHMENT)) if(!H.get_bodypart(body_zone) && !animal_origin) if(H == user) H.visible_message("[H] jams [src] into [H.p_their()] empty socket!",\ "You force [src] into your empty socket, and it locks into place!") else H.visible_message("[user] jams [src] into [H]'s empty socket!",\ "[user] forces [src] into your empty socket, and it locks into place!") user.temporarilyRemoveItemFromInventory(src, TRUE) attach_limb(C) return ..() /obj/item/bodypart/attackby(obj/item/W, mob/user, params) if(W.sharpness) add_fingerprint(user) if(!contents.len) to_chat(user, "There is nothing left inside [src]!") return playsound(loc, 'sound/weapons/slice.ogg', 50, 1, -1) user.visible_message("[user] begins to cut open [src].",\ "You begin to cut open [src]...") if(do_after(user, 54, target = src)) drop_organs(user) else return ..() /obj/item/bodypart/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) ..() if(status != BODYPART_ROBOTIC) playsound(get_turf(src), 'sound/misc/splort.ogg', 50, 1, -1) pixel_x = rand(-3, 3) pixel_y = rand(-3, 3) //empties the bodypart from its organs and other things inside it /obj/item/bodypart/proc/drop_organs(mob/user) var/turf/T = get_turf(src) if(status != BODYPART_ROBOTIC) playsound(T, 'sound/misc/splort.ogg', 50, 1, -1) for(var/obj/item/I in src) I.forceMove(T) /obj/item/bodypart/proc/consider_processing() if(stamina_dam > DAMAGE_PRECISION) . = TRUE //else if.. else if.. so on. else . = FALSE needs_processing = . //Return TRUE to get whatever mob this is in to update health. /obj/item/bodypart/proc/on_life() if(stam_heal_tick && stamina_dam > DAMAGE_PRECISION) //DO NOT update health here, it'll be done in the carbon's life. if(heal_damage(brute = 0, burn = 0, stamina = (stam_heal_tick * (disabled ? 2 : 1)), only_robotic = FALSE, only_organic = FALSE, updating_health = FALSE)) . |= BODYPART_LIFE_UPDATE_HEALTH //Applies brute and burn damage to the organ. Returns 1 if the damage-icon states changed at all. //Damage will not exceed max_damage using this proc //Cannot apply negative damage /obj/item/bodypart/proc/receive_damage(brute = 0, burn = 0, stamina = 0, blocked = 0, updating_health = TRUE, required_status = null, wound_bonus = 0, bare_wound_bonus = 0, sharpness = FALSE) // maybe separate BRUTE_SHARP and BRUTE_OTHER eventually somehow hmm if(owner && (owner.status_flags & GODMODE)) return FALSE //godmode var/dmg_mlt = CONFIG_GET(number/damage_multiplier) brute = round(max(brute * dmg_mlt, 0),DAMAGE_PRECISION) burn = round(max(burn * dmg_mlt, 0),DAMAGE_PRECISION) stamina = round(max((stamina * dmg_mlt) * incoming_stam_mult, 0),DAMAGE_PRECISION) brute = max(0, brute - brute_reduction) burn = max(0, burn - burn_reduction) //No stamina scaling.. for now.. if(!brute && !burn && !stamina) return FALSE brute *= wound_damage_multiplier burn *= wound_damage_multiplier switch(animal_origin) if(ALIEN_BODYPART,LARVA_BODYPART) //aliens take some additional burn //nothing can burn with so much snowflake code around burn *= 1.2 var/wounding_type = (brute > burn ? WOUND_BRUTE : WOUND_BURN) var/wounding_dmg = max(brute, burn) if(wounding_type == WOUND_BRUTE && sharpness) wounding_type = WOUND_SHARP // i know this is effectively the same check as above but i don't know if those can null the damage by rounding and want to be safe if(owner && wounding_dmg > 4 && wound_bonus != CANT_WOUND) // if you want to make tox wounds or some other type, this will need to be expanded and made more modular // handle all our wounding stuff check_wounding(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus) var/can_inflict = max_damage - get_damage() var/total_damage = brute + burn if(total_damage > can_inflict && total_damage > 0) // TODO: the second part of this check should be removed once disabling is all done brute = round(brute * (max_damage / total_damage),DAMAGE_PRECISION) burn = round(burn * (max_damage / total_damage),DAMAGE_PRECISION) if(can_inflict <= 0) return FALSE for(var/i in wounds) var/datum/wound/W = i W.receive_damage(wounding_type, wounding_dmg, wound_bonus) brute_dam += brute burn_dam += burn //We've dealt the physical damages, if there's room lets apply the stamina damage. var/current_damage = get_damage(TRUE) //This time around, count stamina loss too. var/available_damage = max_damage - current_damage stamina_dam += round(clamp(stamina, 0, min(max_stamina_damage - stamina_dam, available_damage)), DAMAGE_PRECISION) if(disabled && stamina > 10) incoming_stam_mult = max(0.01, incoming_stam_mult/(stamina*0.1)) if(owner && updating_health) owner.updatehealth() if(stamina > DAMAGE_PRECISION) owner.update_stamina() consider_processing() update_disabled() return update_bodypart_damage_state() /** * check_wounding() is where we handle rolling for, selecting, and applying a wound if we meet the criteria * * We generate a "score" for how woundable the attack was based on the damage and other factors discussed in [check_wounding_mods()], then go down the list from most severe to least severe wounds in that category. * We can promote a wound from a lesser to a higher severity this way, but we give up if we have a wound of the given type and fail to roll a higher severity, so no sidegrades/downgrades * * Arguments: * * woundtype- Either WOUND_SHARP, WOUND_BRUTE, or WOUND_BURN based on the attack type. * * damage- How much damage is tied to this attack, since wounding potential scales with damage in an attack (see: WOUND_DAMAGE_EXPONENT) * * wound_bonus- The wound_bonus of an attack * * bare_wound_bonus- The bare_wound_bonus of an attack */ /obj/item/bodypart/proc/check_wounding(woundtype, damage, wound_bonus, bare_wound_bonus) // actually roll wounds if applicable if(HAS_TRAIT(owner, TRAIT_EASYLIMBDISABLE)) damage *= 1.5 var/base_roll = rand(1, round(damage ** WOUND_DAMAGE_EXPONENT)) var/injury_roll = base_roll injury_roll += check_woundings_mods(woundtype, damage, wound_bonus, bare_wound_bonus) var/list/wounds_checking switch(woundtype) if(WOUND_SHARP) wounds_checking = WOUND_LIST_CUT if(WOUND_BRUTE) wounds_checking = WOUND_LIST_BONE if(WOUND_BURN) wounds_checking = WOUND_LIST_BURN //cycle through the wounds of the relevant category from the most severe down for(var/PW in wounds_checking) var/datum/wound/possible_wound = PW var/datum/wound/replaced_wound for(var/i in wounds) var/datum/wound/existing_wound = i if(existing_wound.type in wounds_checking) if(existing_wound.severity >= initial(possible_wound.severity)) return else replaced_wound = existing_wound if(initial(possible_wound.threshold_minimum) < injury_roll) if(replaced_wound) var/datum/wound/new_wound = replaced_wound.replace_wound(possible_wound) log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) else var/datum/wound/new_wound = new possible_wound new_wound.apply_wound(src) log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) return // try forcing a specific wound, but only if there isn't already a wound of that severity or greater for that type on this bodypart /obj/item/bodypart/proc/force_wound_upwards(specific_woundtype, smited = FALSE) var/datum/wound/potential_wound = specific_woundtype for(var/i in wounds) var/datum/wound/existing_wound = i if(existing_wound.type in (initial(potential_wound.wound_type))) if(existing_wound.severity < initial(potential_wound.severity)) // we only try if the existing one is inferior to the one we're trying to force existing_wound.replace_wound(potential_wound, smited) return var/datum/wound/new_wound = new potential_wound new_wound.apply_wound(src, smited = smited) /obj/item/bodypart/proc/check_woundings_mods(wounding_type, damage, wound_bonus, bare_wound_bonus) var/armor_ablation = 0 var/injury_mod = 0 //var/bwb = 0 if(owner && ishuman(owner)) var/mob/living/carbon/human/H = owner var/list/clothing = H.clothingonpart(src) for(var/c in clothing) var/obj/item/clothing/C = c // unlike normal armor checks, we tabluate these piece-by-piece manually so we can also pass on appropriate damage the clothing's limbs if necessary armor_ablation += C.armor.getRating("wound") if(wounding_type == WOUND_SHARP) C.take_damage_zone(body_zone, damage, BRUTE, armour_penetration) else if(wounding_type == WOUND_BURN && damage >= 10) // lazy way to block freezing from shredding clothes without adding another var onto apply_damage() C.take_damage_zone(body_zone, damage, BURN, armour_penetration) if(!armor_ablation) injury_mod += bare_wound_bonus injury_mod -= armor_ablation injury_mod += wound_bonus for(var/thing in wounds) var/datum/wound/W = thing injury_mod += W.threshold_penalty var/part_mod = -wound_resistance if(is_disabled()) part_mod += disabled_wound_penalty injury_mod += part_mod return injury_mod //Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all. //Damage cannot go below zero. //Cannot remove negative damage (i.e. apply damage) /obj/item/bodypart/proc/heal_damage(brute, burn, stamina, only_robotic = FALSE, only_organic = TRUE, updating_health = TRUE) if(only_robotic && status != BODYPART_ROBOTIC) //This makes organic limbs not heal when the proc is in Robotic mode. return if(only_organic && status != BODYPART_ORGANIC) //This makes robolimbs not healable by chems. return brute_dam = round(max(brute_dam - brute, 0), DAMAGE_PRECISION) burn_dam = round(max(burn_dam - burn, 0), DAMAGE_PRECISION) stamina_dam = round(max(stamina_dam - stamina, 0), DAMAGE_PRECISION) if(owner && updating_health) owner.updatehealth() consider_processing() update_disabled() return update_bodypart_damage_state() //Returns total damage. /obj/item/bodypart/proc/get_damage(include_stamina = FALSE) var/total = brute_dam + burn_dam if(include_stamina) total = max(total, stamina_dam) return total //Checks disabled status thresholds //Checks disabled status thresholds /obj/item/bodypart/proc/update_disabled() if(!owner) return set_disabled(is_disabled()) /obj/item/bodypart/proc/is_disabled() if(!owner) return if(HAS_TRAIT(owner, TRAIT_PARALYSIS)) return BODYPART_DISABLED_PARALYSIS for(var/i in wounds) var/datum/wound/W = i if(W.disabling) return BODYPART_DISABLED_WOUND if(can_dismember() && !HAS_TRAIT(owner, TRAIT_NODISMEMBER)) . = disabled //inertia, to avoid limbs healing 0.1 damage and being re-enabled if((get_damage(TRUE) >= max_damage) || (HAS_TRAIT(owner, TRAIT_EASYLIMBDISABLE) && (get_damage(TRUE) >= (max_damage * 0.6)))) //Easy limb disable disables the limb at 40% health instead of 0% if(!last_maxed) owner.emote("scream") last_maxed = TRUE if(!is_organic_limb()) return BODYPART_DISABLED_DAMAGE else if(disabled && (get_damage(TRUE) <= (max_damage * 0.8))) // reenabled at 80% now instead of 50% as of wounds update last_maxed = FALSE return BODYPART_NOT_DISABLED else return BODYPART_NOT_DISABLED /obj/item/bodypart/proc/check_disabled() //This might be depreciated and should be safe to remove. if(!can_dismember() || HAS_TRAIT(owner, TRAIT_NODISMEMBER)) return if(!disabled && (get_damage(TRUE) >= max_damage)) set_disabled(TRUE) else if(disabled && (get_damage(TRUE) <= (max_damage * 0.5))) set_disabled(FALSE) /obj/item/bodypart/proc/set_disabled(new_disabled) if(disabled == new_disabled || !owner) return FALSE disabled = new_disabled if(disabled && owner.get_item_for_held_index(held_index)) owner.dropItemToGround(owner.get_item_for_held_index(held_index)) owner.update_health_hud() //update the healthdoll owner.update_body() owner.update_mobility() if(!disabled) incoming_stam_mult = 1 return TRUE //Updates an organ's brute/burn states for use by update_damage_overlays() //Returns 1 if we need to update overlays. 0 otherwise. /obj/item/bodypart/proc/update_bodypart_damage_state() var/tbrute = round( (brute_dam/max_damage)*3, 1 ) var/tburn = round( (burn_dam/max_damage)*3, 1 ) if((tbrute != brutestate) || (tburn != burnstate)) brutestate = tbrute burnstate = tburn return TRUE return FALSE //Change organ status /obj/item/bodypart/proc/change_bodypart_status(new_limb_status, heal_limb, change_icon_to_default) status = new_limb_status if(heal_limb) burn_dam = 0 brute_dam = 0 brutestate = 0 burnstate = 0 if(change_icon_to_default) if(status == BODYPART_ORGANIC) icon = base_bp_icon || DEFAULT_BODYPART_ICON_ORGANIC else if(status == BODYPART_ROBOTIC) icon = DEFAULT_BODYPART_ICON_ROBOTIC if(owner) owner.updatehealth() owner.update_body() //if our head becomes robotic, we remove the lizard horns and human hair. owner.update_hair() owner.update_damage_overlays() /obj/item/bodypart/proc/is_organic_limb() return (status == BODYPART_ORGANIC) //we inform the bodypart of the changes that happened to the owner, or give it the informations from a source mob. /obj/item/bodypart/proc/update_limb(dropping_limb, mob/living/carbon/source) var/mob/living/carbon/C if(source) C = source if(!original_owner) original_owner = source else if(original_owner && owner != original_owner) //Foreign limb no_update = TRUE else C = owner no_update = FALSE if(HAS_TRAIT(C, TRAIT_HUSK) && is_organic_limb()) species_id = "husk" //overrides species_id dmg_overlay_type = "" //no damage overlay shown when husked should_draw_gender = FALSE color_src = FALSE base_bp_icon = DEFAULT_BODYPART_ICON no_update = TRUE body_markings = "husk" // reeee aux_marking = "husk" if(no_update) return if(!animal_origin) var/mob/living/carbon/human/H = C color_src = FALSE var/datum/species/S = H.dna.species base_bp_icon = S?.icon_limbs || DEFAULT_BODYPART_ICON species_id = S.limbs_id species_flags_list = H.dna.species.species_traits //body marking memes var/list/colorlist = list() colorlist.Cut() colorlist += ReadRGB("[H.dna.features["mcolor"]]00") colorlist += ReadRGB("[H.dna.features["mcolor2"]]00") colorlist += ReadRGB("[H.dna.features["mcolor3"]]00") colorlist += list(0,0,0, S.hair_alpha) for(var/index=1, index<=colorlist.len, index++) colorlist[index] = colorlist[index]/255 if(S.use_skintones) skin_tone = H.skin_tone base_bp_icon = (base_bp_icon == DEFAULT_BODYPART_ICON) ? DEFAULT_BODYPART_ICON_ORGANIC : base_bp_icon else skin_tone = "" body_gender = H.dna.features["body_model"] should_draw_gender = S.sexes var/mut_colors = (MUTCOLORS in S.species_traits) if(mut_colors) if(S.fixed_mut_color) species_color = S.fixed_mut_color else species_color = H.dna.features["mcolor"] base_bp_icon = (base_bp_icon == DEFAULT_BODYPART_ICON) ? DEFAULT_BODYPART_ICON_ORGANIC : base_bp_icon else species_color = "" if(base_bp_icon != DEFAULT_BODYPART_ICON) color_src = mut_colors ? MUTCOLORS : ((H.dna.skin_tone_override && S.use_skintones == USE_SKINTONES_GRAYSCALE_CUSTOM) ? CUSTOM_SKINTONE : SKINTONE) if(S.mutant_bodyparts["legs"]) if(body_zone == BODY_ZONE_L_LEG || body_zone == BODY_ZONE_R_LEG) if(DIGITIGRADE in S.species_traits) digitigrade_type = lowertext(H.dna.features["legs"]) else digitigrade_type = null if(S.mutant_bodyparts["mam_body_markings"]) var/datum/sprite_accessory/Smark Smark = GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]] if(Smark) body_markings_icon = Smark.icon if(H.dna.features["mam_body_markings"] != "None") body_markings = Smark?.icon_state || lowertext(H.dna.features["mam_body_markings"]) aux_marking = Smark?.icon_state || lowertext(H.dna.features["mam_body_markings"]) else body_markings = "plain" aux_marking = "plain" markings_color = list(colorlist) else body_markings = null aux_marking = null if(!dropping_limb && H.dna.check_mutation(HULK)) mutation_color = "00aa00" else mutation_color = "" dmg_overlay_type = S.damage_overlay_type else if(animal_origin == MONKEY_BODYPART) //currently monkeys are the only non human mob to have damage overlays. dmg_overlay_type = animal_origin if(status == BODYPART_ROBOTIC) dmg_overlay_type = "robotic" body_markings = null aux_marking = null if(dropping_limb) no_update = TRUE //when attached, the limb won't be affected by the appearance changes of its mob owner. //to update the bodypart's icon when not attached to a mob /obj/item/bodypart/proc/update_icon_dropped() cut_overlays() var/list/standing = get_limb_icon(1) if(!standing.len) icon_state = initial(icon_state)//no overlays found, we default back to initial icon. return for(var/image/I in standing) I.pixel_x = px_x I.pixel_y = px_y add_overlay(standing) //Gives you a proper icon appearance for the dismembered limb /obj/item/bodypart/proc/get_limb_icon(dropped) cut_overlays() icon_state = "" //to erase the default sprite, we're building the visual aspects of the bodypart through overlays alone. . = list() var/image_dir = 0 var/icon_gender = (body_gender == FEMALE) ? "f" : "m" //gender of the icon, if applicable if(dropped) image_dir = SOUTH if(dmg_overlay_type) if(brutestate) . += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, image_dir) if(burnstate) . += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, image_dir) if(!isnull(body_markings) && status == BODYPART_ORGANIC) if(!use_digitigrade) if(body_zone == BODY_ZONE_CHEST) . += image(body_markings_icon, "[body_markings]_[body_zone]_[icon_gender]", -MARKING_LAYER, image_dir) else . += image(body_markings_icon, "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir) else . += image(body_markings_icon, "[body_markings]_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir) var/list/aux = list() var/image/marking var/list/auxmarking = list() . += limb if(animal_origin) if(is_organic_limb()) limb.icon = 'icons/mob/animal_parts.dmi' if(species_id == "husk") limb.icon_state = "[animal_origin]_husk_[body_zone]" else limb.icon_state = "[animal_origin]_[body_zone]" else limb.icon = 'icons/mob/augmentation/augments.dmi' limb.icon_state = "[animal_origin]_[body_zone]" return if((body_zone != BODY_ZONE_HEAD && body_zone != BODY_ZONE_CHEST)) should_draw_gender = FALSE if(is_organic_limb()) limb.icon = base_bp_icon || 'icons/mob/human_parts.dmi' if(should_draw_gender) limb.icon_state = "[species_id]_[body_zone]_[icon_gender]" else if (use_digitigrade) if(base_bp_icon == DEFAULT_BODYPART_ICON_ORGANIC) //Compatibility hack for the current iconset. limb.icon_state = "[digitigrade_type]_[use_digitigrade]_[body_zone]" else limb.icon_state = "[species_id]_[digitigrade_type]_[use_digitigrade]_[body_zone]" else limb.icon_state = "[species_id]_[body_zone]" // Body markings if(!isnull(body_markings)) if(species_id == "husk") marking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[body_zone]", -MARKING_LAYER, image_dir) else if(species_id == "husk" && use_digitigrade) marking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) else if(!use_digitigrade) if(body_zone == BODY_ZONE_CHEST) marking = image(body_markings_icon, "[body_markings]_[body_zone]_[icon_gender]", -MARKING_LAYER, image_dir) else marking = image(body_markings_icon, "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir) else marking = image(body_markings_icon, "[body_markings]_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) . += marking // Citadel End if(aux_icons) for(var/I in aux_icons) var/aux_layer = aux_icons[I] aux += image(limb.icon, "[species_id]_[I]", -aux_layer, image_dir) if(!isnull(aux_marking)) if(species_id == "husk") auxmarking += image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[I]", -aux_layer, image_dir) else auxmarking += image(body_markings_icon, "[body_markings]_[I]", -aux_layer, image_dir) . += aux . += auxmarking else limb.icon = icon if(should_draw_gender) limb.icon_state = "[body_zone]_[icon_gender]" else limb.icon_state = "[body_zone]" if(aux_icons) for(var/I in aux_icons) var/aux_layer = aux_icons[I] aux += image(limb.icon, "[I]", -aux_layer, image_dir) if(!isnull(aux_marking)) if(species_id == "husk") auxmarking += image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[I]", -aux_layer, image_dir) else auxmarking += image(body_markings_icon, "[body_markings]_[I]", -aux_layer, image_dir) . += auxmarking . += aux if(!isnull(body_markings)) if(species_id == "husk") marking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[body_zone]", -MARKING_LAYER, image_dir) else if(species_id == "husk" && use_digitigrade) marking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) else if(!use_digitigrade) if(body_zone == BODY_ZONE_CHEST) marking = image(body_markings_icon, "[body_markings]_[body_zone]_[icon_gender]", -MARKING_LAYER, image_dir) else marking = image(body_markings_icon, "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir) else marking = image(body_markings_icon, "[body_markings]_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) . += marking return if(color_src) //TODO - add color matrix support for base species limbs var/draw_color = mutation_color || species_color var/grayscale = FALSE if(!draw_color) draw_color = SKINTONE2HEX(skin_tone) grayscale = color_src == CUSTOM_SKINTONE //Cause human limbs have a very pale pink hue by def. else draw_color = "#[draw_color]" if(draw_color) if(grayscale) limb.icon_state += "_g" limb.color = draw_color if(aux_icons) for(var/a in aux) var/image/I = a if(grayscale) I.icon_state += "_g" I.color = draw_color if(!isnull(aux_marking)) for(var/a in auxmarking) var/image/I = a if(species_id == "husk") I.color = "#141414" else I.color = list(markings_color) if(!isnull(body_markings)) if(species_id == "husk") marking.color = "#141414" else marking.color = list(markings_color) /obj/item/bodypart/deconstruct(disassembled = TRUE) drop_organs() qdel(src) /// Get whatever wound of the given type is currently attached to this limb, if any /obj/item/bodypart/proc/get_wound_type(checking_type) if(isnull(wounds)) return for(var/thing in wounds) var/datum/wound/W = thing if(istype(W, checking_type)) return W /// very rough start for updating efficiency and other stats on a body part whenever a wound is gained/lost /obj/item/bodypart/proc/update_wounds() var/dam_mul = 1 //initial(wound_damage_multiplier) // we can only have one wound per type, but remember there's multiple types for(var/datum/wound/W in wounds) dam_mul *= W.damage_mulitplier_penalty wound_damage_multiplier = dam_mul update_disabled() /obj/item/bodypart/proc/get_bleed_rate() if(status != BODYPART_ORGANIC) // maybe in the future we can bleed oil from aug parts, but not now return var/bleed_rate = 0 if(generic_bleedstacks > 0) bleed_rate++ if(brute_dam >= 40) bleed_rate += (brute_dam * 0.008) //We want an accurate reading of .len listclearnulls(embedded_objects) for(var/obj/item/embeddies in embedded_objects) if(!embeddies.isEmbedHarmless()) bleed_rate += 0.5 for(var/thing in wounds) var/datum/wound/W = thing bleed_rate += W.blood_flow return bleed_rate