Files
CHOMPStation2/code/modules/mob/living/carbon/human/update_icons.dm
CHOMPStation2 f172e1f5b3 [MIRROR] even more local defines (#8516)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
Co-authored-by: Kashargul <KashL@t-online.de>
2024-06-14 08:28:10 +02:00

1492 lines
56 KiB
Plaintext

/*
Global associative list for caching humanoid icons.
Index format m or f, followed by a string of 0 and 1 to represent bodyparts followed by husk fat hulk skeleton 1 or 0.
*/
//ChompEDIT START - change to managed GLOB
GLOBAL_LIST_EMPTY(human_icon_cache) //key is incredibly complex, see update_icons_body()
GLOBAL_LIST_EMPTY(tail_icon_cache) //key is [species.race_key][r_skin][g_skin][b_skin]
GLOBAL_LIST_EMPTY(wing_icon_cache) // See tail.
GLOBAL_LIST_EMPTY(light_overlay_cache) //see make_worn_icon() on helmets
GLOBAL_LIST_EMPTY(damage_icon_parts) //see UpdateDamageIcon()
//ChompEDIT END
////////////////////////////////////////////////////////////////////////////////////////////////
// # Human Icon Updating System
//
// This system takes care of the "icon" for human mobs. Of course humans don't just have a single
// icon+icon_state, but a combination of dozens of little sprites including including the body,
// clothing, equipment, in-universe HUD images, etc.
//
// # Basic Operation
// Whenever you do something that should update the on-mob appearance of a worn or held item, You
// will need to call the relevant update_inv_* proc. All of these are named after the variable they
// update from. They are defined at the /mob level so you don't even need to cast to carbon/human.
//
// The new system leverages SSoverlays to actually add/remove the overlays from mob.overlays
// Since SSoverlays already manages batching updates to reduce apperance churn etc, we don't need
// to worry about that. (In short, you can call add/cut overlay as many times as you want, it will
// only get assigned to the mob once per tick.)
// As a corrolary, this means users of this system do NOT need to tell the system when you're done
// making changes.
//
// There are also these special cases:
// update_icons_body() //Handles updating your mob's icon to reflect their gender/race/complexion etc
// UpdateDamageIcon() //Handles damage overlays for brute/burn damage //(will rename this when I geta round to it) ~Carn
// update_skin() //Handles updating skin for species that have a skin overlay.
// update_bloodied() //Handles adding/clearing the blood overlays for hands & feet. Call when bloodied or cleaned.
// update_underwear() //Handles updating the sprite for underwear.
// update_hair() //Handles updating your hair and eyes overlay
// update_mutations() //Handles updating your appearance for certain mutations. e.g TK head-glows
// update_fire() //Handles overlay from being on fire.
// update_water() //Handles overlay from being submerged.
// update_surgery() //Handles overlays from open external organs.
//
// # History (i.e. I'm used to the old way, what is different?)
// You used to have to call update_icons(FALSE) if you planned to make more changes, and call update_icons(TRUE)
// on the final update. All that is gone, just call update_inv_whatever() and it handles the rest.
//
////////////////////////////////////////////////////////////////////////////////////////////////
//Add an entry to overlays, assuming it exists
/mob/living/carbon/human/proc/apply_layer(cache_index)
if((. = overlays_standing[cache_index]))
add_overlay(.)
//Remove an entry from overlays, and from the list
/mob/living/carbon/human/proc/remove_layer(cache_index)
var/I = overlays_standing[cache_index]
if(I)
cut_overlay(I)
overlays_standing[cache_index] = null
// These are used as the layers for the icons, as well as indexes in a list that holds onto them.
// Technically the layers used are all -100+layer to make them FLOAT_LAYER overlays.
//CHOMPEDIT: edit the file human/update_icons.dm in the modular_chomp folder as well, if you update these (and clothing/clothing.dm line 789, the hardcoded layer there in /obj/item/clothing/suit/make_worn_icon)
/*CHOMPRemove Start: Global here!
//Human Overlays Indexes/////////
#define MUTATIONS_LAYER 1 //Mutations like fat, and lasereyes
#define TAIL_LOWER_LAYER 2 //Tail as viewed from the south //CHOMPStation edit - underneath bodyparts
#define WING_LOWER_LAYER 3 //Wings as viewed from the south //CHOMPStation edit - underneath bodyparts
#define BODYPARTS_LAYER 4 //Bodyparts layer - CHOMPStation edit
#define SKIN_LAYER 5 //Skin things added by a call on species
#define BLOOD_LAYER 6 //Bloodied hands/feet/anything else
#define MOB_DAM_LAYER 7 //Injury overlay sprites like open wounds
#define SURGERY_LAYER 8 //Overlays for open surgical sites
#define UNDERWEAR_LAYER 9 //Underwear/bras/etc
#define SHOES_LAYER_ALT 10 //Shoe-slot item (when set to be under uniform via verb)
#define UNIFORM_LAYER 11 //Uniform-slot item
#define ID_LAYER 12 //ID-slot item
#define SHOES_LAYER 13 //Shoe-slot item
#define GLOVES_LAYER 14 //Glove-slot item
#define BELT_LAYER 15 //Belt-slot item
#define SUIT_LAYER 16 //Suit-slot item
#define TAIL_UPPER_LAYER 17 //Some species have tails to render (As viewed from the N, E, or W)
#define GLASSES_LAYER 18 //Eye-slot item
#define BELT_LAYER_ALT 19 //Belt-slot item (when set to be above suit via verb)
#define SUIT_STORE_LAYER 20 //Suit storage-slot item
#define BACK_LAYER 21 //Back-slot item
#define HAIR_LAYER 22 //The human's hair
#define HAIR_ACCESSORY_LAYER 23 //VOREStation edit. Simply move this up a number if things are added.
#define EARS_LAYER 24 //Both ear-slot items (combined image)
#define EYES_LAYER 25 //Mob's eyes (used for glowing eyes)
#define FACEMASK_LAYER 26 //Mask-slot item
#define GLASSES_LAYER_ALT 27 //So some glasses can appear on top of hair and things
#define HEAD_LAYER 28 //Head-slot item
#define HANDCUFF_LAYER 29 //Handcuffs, if the human is handcuffed, in a secret inv slot
#define LEGCUFF_LAYER 30 //Same as handcuffs, for legcuffs
#define L_HAND_LAYER 31 //Left-hand item
#define R_HAND_LAYER 32 //Right-hand item
#define WING_LAYER 33 //Wings or protrusions over the suit.
#define VORE_BELLY_LAYER 34 //CHOMPStation edit - Move this and everything after up if things are added.
#define VORE_TAIL_LAYER 35 //CHOMPStation edit - Move this and everything after up if things are added.
#define TAIL_UPPER_LAYER_ALT 36 //Modified tail-sprite layer. Tend to be larger.
#define MODIFIER_EFFECTS_LAYER 37 //Effects drawn by modifiers
#define FIRE_LAYER 38 //'Mob on fire' overlay layer
#define MOB_WATER_LAYER 39 //'Mob submerged' overlay layer
#define TARGETED_LAYER 40 //'Aimed at' overlay layer
#define TOTAL_LAYERS 40 //CHOMPStation edit. <---- KEEP THIS UPDATED, should always equal the highest number here, used to initialize a list.
//////////////////////////////////
*///CHOMPRemove End
//These two are only used for gargoyles currently
#define HUMAN_BODY_LAYERS list(MUTATIONS_LAYER, TAIL_LOWER_LAYER, WING_LOWER_LAYER, BODYPARTS_LAYER, SKIN_LAYER, BLOOD_LAYER, MOB_DAM_LAYER, TAIL_UPPER_LAYER, HAIR_LAYER, HAIR_ACCESSORY_LAYER, EYES_LAYER, WING_LAYER, VORE_BELLY_LAYER, VORE_TAIL_LAYER, TAIL_UPPER_LAYER_ALT)
#define HUMAN_OTHER_LAYERS list(MODIFIER_EFFECTS_LAYER, FIRE_LAYER, MOB_WATER_LAYER, TARGETED_LAYER)
/mob/living/carbon/human
var/list/overlays_standing[TOTAL_LAYERS]
var/previous_damage_appearance // store what the body last looked like, so we only have to update it if something changed
//UPDATES OVERLAYS FROM OVERLAYS_LYING/OVERLAYS_STANDING
//I'll work on removing that stuff by rewriting some of the cloaking stuff at a later date.
/mob/living/carbon/human/update_icons()
if(QDESTROYING(src))
return
stack_trace("CANARY: Old human update_icons was called.")
update_hud() //TODO: remove the need for this
//Do any species specific layering updates, such as when hiding.
update_icon_special()
/mob/living/carbon/human/update_transform(var/instant = FALSE)
/* VOREStation Edit START
// First, get the correct size.
var/desired_scale_x = icon_scale_x
var/desired_scale_y = icon_scale_y
desired_scale_x *= species.icon_scale_x
desired_scale_y *= species.icon_scale_y
for(var/datum/modifier/M in modifiers)
if(!isnull(M.icon_scale_x_percent))
desired_scale_x *= M.icon_scale_x_percent
if(!isnull(M.icon_scale_y_percent))
desired_scale_y *= M.icon_scale_y_percent
*/
var/desired_scale_x = size_multiplier * icon_scale_x
var/desired_scale_y = size_multiplier * icon_scale_y
desired_scale_x *= species.icon_scale_x
desired_scale_y *= species.icon_scale_y
var/cent_offset = species.center_offset
if(fuzzy || offset_override || dir == EAST || dir == WEST)
cent_offset = 0
vis_height = species.icon_height
appearance_flags |= PIXEL_SCALE
if(fuzzy)
appearance_flags &= ~PIXEL_SCALE
center_offset = 0 //CHOMPEdit
//VOREStation Edit End
// Regular stuff again.
var/matrix/M = matrix()
var/anim_time = 3
//Due to some involuntary means, you're laying now
if(lying && !resting && !sleeping)
anim_time = 1 //Thud
if(lying && !species.prone_icon) //Only rotate them if we're not drawing a specific icon for being prone.
// CHOMPEdit Start Loafy Time
if(tail_style?.can_loaf && resting) // Only call these if we're resting?
update_tail_showing()
M.Scale(desired_scale_x, desired_scale_y)
M.Translate(cent_offset * desired_scale_x, (vis_height/2)*(desired_scale_y-1)) //CHOMPEdit
else
M.Scale(desired_scale_x, desired_scale_y)
if(isnull(resting_dir))
resting_dir = pick(FALSE, TRUE)
if(resting_dir)
M.Translate((1 / desired_scale_x * -4) + (desired_scale_x * cent_offset), 0)
M.Turn(-90)
else
M.Translate((1 / desired_scale_x * 4) - (desired_scale_x * cent_offset), 0)
M.Turn(90)
// CHOMPEdit End
layer = MOB_LAYER -0.01 // Fix for a byond bug where turf entry order no longer matters
else
M.Scale(desired_scale_x, desired_scale_y)//VOREStation Edit
M.Translate(cent_offset * desired_scale_x, (vis_height/2)*(desired_scale_y-1))
if(tail_style?.can_loaf) // VOREStation Edit: Taur Loafing
update_tail_showing() // VOREStation Edit: Taur Loafing
layer = MOB_LAYER // Fix for a byond bug where turf entry order no longer matters
if(instant)
transform = M
else
animate(src, transform = M, time = anim_time)
update_icon_special() //May contain transform-altering things
//DAMAGE OVERLAYS
//constructs damage icon for each organ from mask * damage field and saves it in our overlays_ lists
/mob/living/carbon/human/UpdateDamageIcon()
if(QDESTROYING(src))
return
remove_layer(MOB_DAM_LAYER)
// first check whether something actually changed about damage appearance
var/damage_appearance = ""
for(var/obj/item/organ/external/O in organs)
if(isnull(O) || O.is_stump())
continue
damage_appearance += O.damage_state
if(damage_appearance == previous_damage_appearance)
// nothing to do here
return
previous_damage_appearance = damage_appearance
var/image/standing_image = image(icon = species.damage_overlays, icon_state = "00", layer = BODY_LAYER+MOB_DAM_LAYER)
// blend the individual damage states with our icons
for(var/obj/item/organ/external/O in organs)
if(isnull(O) || O.is_stump() || O.is_hidden_by_sprite_accessory())
continue
O.update_icon()
if(O.damage_state == "00") continue
var/icon/DI
var/cache_index = "[O.damage_state]/[O.icon_name]/[species.get_blood_colour(src)]/[species.get_bodytype(src)]"
if(GLOB.damage_icon_parts[cache_index] == null) //ChompEDIT Managed GLOB
DI = icon(species.get_damage_overlays(src), O.damage_state) // the damage icon for whole human
DI.Blend(icon(species.get_damage_mask(src), O.icon_name), ICON_MULTIPLY) // mask with this organ's pixels
DI.Blend(species.get_blood_colour(src), ICON_MULTIPLY)
GLOB.damage_icon_parts[cache_index] = DI //ChompEDIT Managed GLOB
else
DI = GLOB.damage_icon_parts[cache_index] //ChompEDIT Managed GLOB
standing_image.add_overlay(DI)
overlays_standing[MOB_DAM_LAYER] = standing_image
apply_layer(MOB_DAM_LAYER)
//BASE MOB SPRITE
/mob/living/carbon/human/update_icons_body()
if(QDESTROYING(src))
return
remove_layer(BODYPARTS_LAYER)
var/husk_color_mod = rgb(96,88,80)
var/hulk_color_mod = rgb(48,224,40)
var/husk = (HUSK in src.mutations)
var/fat = (FAT in src.mutations)
var/hulk = (HULK in src.mutations)
var/skeleton = (SKELETON in src.mutations)
robolimb_count = 0 //TODO, here, really tho?
robobody_count = 0
//CACHING: Generate an index key from visible bodyparts.
//0 = destroyed, 1 = normal, 2 = robotic, 3 = necrotic.
//Create a new, blank icon for our mob to use.
var/icon/stand_icon = new(species.icon_template ? species.icon_template : 'icons/mob/human.dmi', icon_state = "blank")
var/g = (gender == MALE ? "male" : "female")
var/icon_key = "[species.get_race_key(src)][g][s_tone][r_skin][g_skin][b_skin]"
if(lip_style)
icon_key += "[lip_style]"
else
icon_key += "nolips"
var/obj/item/organ/internal/eyes/eyes = internal_organs_by_name[O_EYES]
if(eyes)
icon_key += "[rgb(eyes.eye_colour[1], eyes.eye_colour[2], eyes.eye_colour[3])]"
else
icon_key += "[r_eyes], [g_eyes], [b_eyes]"
var/obj/item/organ/external/head/head = organs_by_name[BP_HEAD]
if(head)
if(!istype(head, /obj/item/organ/external/stump))
if (species.selects_bodytype != SELECTS_BODYTYPE_FALSE)
var/headtype = GLOB.all_species[species.base_species]?.has_limbs[BP_HEAD]
var/obj/item/organ/external/head/headtypepath = headtype["path"]
if (headtypepath && !head.eye_icon_override)
head.eye_icon = initial(headtypepath.eye_icon)
head.eye_icon_location = initial(headtypepath.eye_icon_location)
icon_key += "[head.eye_icon]"
var/wholeicontransparent = TRUE
for(var/organ_tag in species.has_limbs)
var/obj/item/organ/external/part = organs_by_name[organ_tag]
if(isnull(part) || part.is_stump() || part.is_hidden_by_sprite_accessory()) //VOREStation Edit allowing tails to prevent bodyparts rendering, granting more spriter freedom for taur/digitigrade stuff.
icon_key += "0"
continue
if(part)
wholeicontransparent &&= part.transparent //VORESTATION EDIT: transparent instead of nonsolid
icon_key += "[part.species.get_race_key(part.owner)]"
icon_key += "[part.dna.GetUIState(DNA_UI_GENDER)]"
icon_key += "[part.s_tone]"
if(part.s_col && part.s_col.len >= 3)
icon_key += "[rgb(part.s_col[1],part.s_col[2],part.s_col[3])]"
if(part.body_hair && part.h_col && part.h_col.len >= 3)
icon_key += "[rgb(part.h_col[1],part.h_col[2],part.h_col[3])]"
if(species.color_mult)
icon_key += "[ICON_MULTIPLY]"
else
icon_key += "[ICON_ADD]"
else
icon_key += "#000000"
for(var/M in part.markings)
if (part.markings[M]["on"])
icon_key += "[M][part.markings[M]["color"]]"
// VOREStation Edit Start
if(part.nail_polish)
icon_key += "_[part.nail_polish.icon]_[part.nail_polish.icon_state]_[part.nail_polish.color]"
// VOREStation Edit End
if(part.robotic >= ORGAN_ROBOT)
icon_key += "2[part.model ? "-[part.model]": ""]"
robolimb_count++
if((part.robotic == ORGAN_ROBOT || part.robotic == ORGAN_LIFELIKE) && (part.organ_tag == BP_HEAD || part.organ_tag == BP_TORSO || part.organ_tag == BP_GROIN))
robobody_count ++
else if(part.status & ORGAN_DEAD)
icon_key += "3"
else
icon_key += "1"
if(part.transparent) //VOREStation Edit. For better slime limbs. Avoids using solid var due to limb dropping.
icon_key += "_t" //VOREStation Edit.
if(istype(tail_style, /datum/sprite_accessory/tail/taur))
if(tail_style.clip_mask) //VOREStation Edit.
icon_key += tail_style.clip_mask_state
if(digitigrade && (part.organ_tag == BP_R_LEG || part.organ_tag == BP_L_LEG || part.organ_tag == BP_R_FOOT || part.organ_tag == BP_L_FOOT))
icon_key += "_digi"
if(tail_style)
pixel_x = tail_style.mob_offset_x
pixel_y = tail_style.mob_offset_y
default_pixel_x = tail_style.mob_offset_x
default_pixel_y = tail_style.mob_offset_y
//ChompEDIT START
//icon_key addition for digitigrade switch
if(digitigrade && (part.organ_tag == BP_R_LEG || part.organ_tag == BP_L_LEG || part.organ_tag == BP_R_FOOT || part.organ_tag == BP_L_FOOT))
icon_key += "_digi"
//ChompEDIT END
icon_key = "[icon_key][husk ? 1 : 0][fat ? 1 : 0][hulk ? 1 : 0][skeleton ? 1 : 0]"
var/icon/base_icon
if(GLOB.human_icon_cache[icon_key])
base_icon = GLOB.human_icon_cache[icon_key]
else
//BEGIN CACHED ICON GENERATION.
var/obj/item/organ/external/chest = get_organ(BP_TORSO)
base_icon = new(chest?.get_icon(skeleton, !wholeicontransparent)) //ChompEDIT NEW icon, not referencing original
var/apply_extra_transparency_leg = organs_by_name[BP_L_LEG] && organs_by_name[BP_R_LEG]
var/apply_extra_transparency_foot = organs_by_name[BP_L_FOOT] && organs_by_name[BP_R_FOOT]
var/icon/Cutter = null
var/icon_x_offset = 0
var/icon_y_offset = 0
if(istype(tail_style, /datum/sprite_accessory/tail/taur)) // Tail icon 'cookie cutters' are filled in where icons are preserved. We need to invert that.
if(tail_style.clip_mask) //VOREStation Edit.
Cutter = new(icon = (tail_style.clip_mask_icon ? tail_style.clip_mask_icon : tail_style.icon), icon_state = tail_style.clip_mask_state)
Cutter.Blend("#000000", ICON_MULTIPLY) // Make it all black.
Cutter.SwapColor("#00000000", "#FFFFFFFF") // Everywhere empty, make white.
Cutter.SwapColor("#000000FF", "#00000000") // Everywhere black, make empty.
Cutter.Blend("#000000", ICON_MULTIPLY) // Black again.
icon_x_offset = tail_style.offset_x
icon_y_offset = tail_style.offset_y
for(var/obj/item/organ/external/part in organs)
if(isnull(part) || part.is_stump() || part == chest || part.is_hidden_by_sprite_accessory()) //VOREStation Edit allowing tails to prevent bodyparts rendering, granting more spriter freedom for taur/digitigrade stuff.
continue
var/icon/temp = new(part.get_icon(skeleton, !wholeicontransparent)) //ChompEDIT NEW icon, not referencing original
if((part.organ_tag in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)) && Cutter)
temp.Blend(Cutter, ICON_AND, x = icon_x_offset, y = icon_y_offset)
//That part makes left and right legs drawn topmost and lowermost when human looks WEST or EAST
//And no change in rendering for other parts (they icon_position is 0, so goes to 'else' part)
if(part.icon_position & (LEFT | RIGHT))
var/icon/temp2 = new(species.icon_template ? species.icon_template : 'icons/mob/human.dmi', icon_state = "blank")
temp2.Insert(new/icon(temp,dir=NORTH),dir=NORTH)
temp2.Insert(new/icon(temp,dir=SOUTH),dir=SOUTH)
if(!(part.icon_position & LEFT))
temp2.Insert(new/icon(temp,dir=EAST),dir=EAST)
if(!(part.icon_position & RIGHT))
temp2.Insert(new/icon(temp,dir=WEST),dir=WEST)
base_icon.Blend(temp2, ICON_OVERLAY)
/* //ChompEDIT START - icon crashes
temp2.Insert(temp2,"blank",dir=NORTH) //faaaaairly certain this is more efficient than reloading temp2, doing this so we don't blend the icons twice (it matters more in transparent limbs)
temp2.Insert(temp2,"blank",dir=SOUTH)
temp2.Insert(temp2,"blank",dir=EAST)
temp2.Insert(temp2,"blank",dir=WEST)
*/
temp2 = new(species.icon_template ? species.icon_template : 'icons/mob/human.dmi', icon_state = "blank")
//ChompEDIT END
if(part.icon_position & LEFT)
temp2.Insert(new/icon(temp,dir=EAST),dir=EAST)
if(part.icon_position & RIGHT)
temp2.Insert(new/icon(temp,dir=WEST),dir=WEST)
if (part.transparent && !wholeicontransparent) //apply a little (a lot) extra transparency to make it look better //VORESTATION EDIT: transparent instead of nonsolid
if ((istype(part, /obj/item/organ/external/leg) && apply_extra_transparency_leg) || (istype(part, /obj/item/organ/external/foot) && apply_extra_transparency_foot)) //maybe
temp2 += rgb(,,,30)
base_icon.Blend(temp2, ICON_UNDERLAY)
else if(part.icon_position & UNDER)
base_icon.Blend(temp, ICON_UNDERLAY)
else
base_icon.Blend(temp, ICON_OVERLAY)
if (wholeicontransparent) //because, I mean. It's basically never gonna happen that you'll have just one non-transparent limb but if you do your icon will look meh. Still good but meh, will have some areas with higher transparencies unless you're literally just a torso and a head
base_icon += rgb(,,,180)
if(!skeleton)
if(husk)
base_icon.ColorTone(husk_color_mod)
else if(hulk)
var/list/tone = rgb2num(hulk_color_mod)
base_icon.MapColors(rgb(tone[1],0,0),rgb(0,tone[2],0),rgb(0,0,tone[3]))
//Handle husk overlay.
if(husk && ("overlay_husk" in cached_icon_states(species.icobase)))
var/icon/mask = new(base_icon)
var/icon/husk_over = new(species.icobase,"overlay_husk")
mask.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0)
husk_over.Blend(mask, ICON_ADD)
base_icon.Blend(husk_over, ICON_OVERLAY)
GLOB.human_icon_cache[icon_key] = base_icon
//END CACHED ICON GENERATION. //ChompEDIT END
stand_icon.Blend(base_icon,ICON_OVERLAY)
var/image/body = image(stand_icon)
if (body)
body.layer = BODY_LAYER + BODYPARTS_LAYER
overlays_standing[BODYPARTS_LAYER] = body
apply_layer(BODYPARTS_LAYER)
icon = stand_icon
//tail
update_tail_showing()
update_wing_showing()
update_vore_belly_sprite()
update_vore_tail_sprite()
/mob/living/carbon/human/proc/update_skin()
if(QDESTROYING(src))
return
remove_layer(SKIN_LAYER)
var/image/skin = species.update_skin(src)
if(skin)
skin.layer = BODY_LAYER+SKIN_LAYER
overlays_standing[SKIN_LAYER] = skin
apply_layer(SKIN_LAYER)
/mob/living/carbon/human/proc/update_bloodied()
if(QDESTROYING(src))
return
remove_layer(BLOOD_LAYER)
if(!blood_DNA && !feet_blood_DNA)
return
var/image/both = image(icon = 'icons/effects/effects.dmi', icon_state = "nothing", layer = BODY_LAYER+BLOOD_LAYER)
//Bloody hands
if(blood_DNA)
var/image/bloodsies = image(icon = species.get_blood_mask(src), icon_state = "bloodyhands", layer = BODY_LAYER+BLOOD_LAYER)
bloodsies.color = hand_blood_color
both.add_overlay(bloodsies)
//Bloody feet
if(feet_blood_DNA)
var/image/bloodsies = image(icon = digitigrade ? 'icons/mob/human_races/masks/blood_digitigrade.dmi' : species.get_blood_mask(src), icon_state = "shoeblood", layer = BODY_LAYER+BLOOD_LAYER) //CHOMPEdit: digitigrade feeties
bloodsies.color = feet_blood_color
both.add_overlay(bloodsies)
overlays_standing[BLOOD_LAYER] = both
apply_layer(BLOOD_LAYER)
//UNDERWEAR OVERLAY
/mob/living/carbon/human/proc/update_underwear()
if(QDESTROYING(src))
return
remove_layer(UNDERWEAR_LAYER)
if(species.appearance_flags & HAS_UNDERWEAR)
overlays_standing[UNDERWEAR_LAYER] = list()
for(var/category in all_underwear)
if(hide_underwear[category])
continue
var/datum/category_item/underwear/UWI = all_underwear[category]
var/image/wear = UWI.generate_image(all_underwear_metadata[category], layer = BODY_LAYER+UNDERWEAR_LAYER, digitigrade = digitigrade) //CHOMPEdit
overlays_standing[UNDERWEAR_LAYER] += wear
apply_layer(UNDERWEAR_LAYER)
//HAIR OVERLAY
/mob/living/carbon/human/proc/update_hair()
if(QDESTROYING(src))
return
//Reset our hair
remove_layer(HAIR_LAYER)
remove_layer(HAIR_ACCESSORY_LAYER) //VOREStation Edit
update_eyes() //Pirated out of here, for glowing eyes.
var/obj/item/organ/external/head/head_organ = get_organ(BP_HEAD)
if(!head_organ || head_organ.is_stump() )
return
//masks and helmets can obscure our hair.
if( (head && (head.flags_inv & BLOCKHAIR)) || (wear_mask && (wear_mask.flags_inv & BLOCKHAIR)))
return
//base icons
var/icon/face_standing = icon(icon = 'icons/mob/human_face.dmi', icon_state = "bald_s")
if(f_style)
var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style]
if(facial_hair_style && facial_hair_style.species_allowed && (src.species.get_bodytype(src) in facial_hair_style.species_allowed))
var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s")
if(facial_hair_style.do_colouration)
facial_s.Blend(rgb(r_facial, g_facial, b_facial), facial_hair_style.color_blend_mode)
face_standing.Blend(facial_s, ICON_OVERLAY)
if(h_style)
var/datum/sprite_accessory/hair/hair_style = hair_styles_list[h_style]
if(head && (head.flags_inv & BLOCKHEADHAIR))
if(!(hair_style.flags & HAIR_VERY_SHORT))
hair_style = hair_styles_list["Short Hair"]
if(hair_style && (src.species.get_bodytype(src) in hair_style.species_allowed))
var/icon/grad_s = null
var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
var/icon/hair_s_add = new/icon("icon" = hair_style.icon_add, "icon_state" = "[hair_style.icon_state]_s")
if(hair_style.do_colouration)
if(grad_style)
grad_s = new/icon("icon" = 'icons/mob/hair_gradients.dmi', "icon_state" = GLOB.hair_gradients[grad_style])
grad_s.Blend(hair_s, ICON_AND)
grad_s.Blend(rgb(r_grad, g_grad, b_grad), ICON_MULTIPLY)
hair_s.Blend(rgb(r_hair, g_hair, b_hair), ICON_MULTIPLY)
hair_s.Blend(hair_s_add, ICON_ADD)
if(!isnull(grad_s))
hair_s.Blend(grad_s, ICON_OVERLAY)
face_standing.Blend(hair_s, ICON_OVERLAY)
var/icon/ears_s = get_ears_overlay()
if(head_organ.transparent) //VORESTATION EDIT: transparent instead of nonsolid
face_standing += rgb(,,,120)
if (ears_s)
ears_s += rgb(,,,180)
var/image/em_block_ears
if(ears_s)
if(ears_s.Height() > face_standing.Height()) // Tol ears
face_standing.Crop(1, 1, face_standing.Width(), ears_s.Height())
face_standing.Blend(ears_s, ICON_OVERLAY)
if(ear_style?.em_block)
em_block_ears = em_block_image_generic(image(ears_s))
var/image/semifinal = image(face_standing, layer = BODY_LAYER+HAIR_LAYER, "pixel_y" = head_organ.head_offset)
if(em_block_ears)
semifinal.overlays += em_block_ears // Leaving this as overlays +=
overlays_standing[HAIR_LAYER] = semifinal
apply_layer(HAIR_LAYER)
//return //VOREStation Edit
// VOREStation Edit - START
var/icon/hair_acc_s = get_hair_accessory_overlay()
var/image/hair_acc_s_image = null
if(hair_acc_s)
if(hair_accessory_style.ignores_lighting)
hair_acc_s_image = image(hair_acc_s)
hair_acc_s_image.plane = PLANE_LIGHTING_ABOVE
hair_acc_s_image.appearance_flags = appearance_flags
if (hair_acc_s_image)
overlays_standing[HAIR_ACCESSORY_LAYER] = hair_acc_s_image
apply_layer(HAIR_ACCESSORY_LAYER)
return
overlays_standing[HAIR_ACCESSORY_LAYER] = image(hair_acc_s, layer = BODY_LAYER+HAIR_ACCESSORY_LAYER)
apply_layer(HAIR_ACCESSORY_LAYER)
// VOREStation Edit - END
/mob/living/carbon/human/update_eyes()
if(QDESTROYING(src))
return
//Reset our eyes
remove_layer(EYES_LAYER)
//TODO: Probably redo this. I know I wrote it, but...
//This is ONLY for glowing eyes for now. Boring flat eyes are done by the head's own proc.
if(!species.has_glowing_eyes)
return
//Our glowy eyes should be hidden if some equipment hides them.
if(!should_have_organ(O_EYES) || (head && (head.flags_inv & BLOCKHAIR)) || (wear_mask && (wear_mask.flags_inv & BLOCKHAIR)))
return
//Get the head, we'll need it later.
var/obj/item/organ/external/head/head_organ = get_organ(BP_HEAD)
if(!head_organ || head_organ.is_stump() )
return
//The eyes store the color themselves, funny enough.
var/obj/item/organ/internal/eyes/eyes = internal_organs_by_name[O_EYES]
if(!head_organ.eye_icon)
return
var/icon/eyes_icon = new/icon(head_organ.eye_icon_location, head_organ.eye_icon) //VOREStation Edit
if(eyes)
eyes_icon.Blend(rgb(eyes.eye_colour[1], eyes.eye_colour[2], eyes.eye_colour[3]), ICON_ADD)
else
eyes_icon.Blend(rgb(128,0,0), ICON_ADD)
// Convert to emissive at some point
if (head_organ.transparent) //VOREStation Edit: transparent instead of nonsolid
eyes_icon += rgb(,,,180)
var/image/eyes_image = image(eyes_icon)
eyes_image.plane = PLANE_LIGHTING_ABOVE
eyes_image.appearance_flags = appearance_flags
overlays_standing[EYES_LAYER] = eyes_image
apply_layer(EYES_LAYER)
/mob/living/carbon/human/update_mutations()
if(QDESTROYING(src))
return
remove_layer(MUTATIONS_LAYER)
if(!LAZYLEN(mutations))
return //No mutations, no icons.
//TODO: THIS PROC???
var/fat
if(FAT in mutations)
fat = "fat"
var/image/standing = image(icon = 'icons/effects/genetics.dmi', layer = BODY_LAYER+MUTATIONS_LAYER)
var/g = gender == FEMALE ? "f" : "m"
for(var/datum/dna/gene/gene in dna_genes)
if(!gene.block)
continue
if(gene.is_active(src))
var/underlay = gene.OnDrawUnderlays(src,g,fat)
if(underlay)
standing.underlays += underlay
for(var/mut in mutations)
if(mut == LASER)
standing.overlays += "lasereyes_s" // Leaving this as overlays +=
overlays_standing[MUTATIONS_LAYER] = standing
apply_layer(MUTATIONS_LAYER)
/* --------------------------------------- */
//Recomputes every icon on the mob. Expensive.
//Useful if the species changed, or there's some
//other drastic body-shape change, but otherwise avoid.
/mob/living/carbon/human/regenerate_icons()
..()
if(transforming || QDELETED(src))
return
update_icons_body()
UpdateDamageIcon()
update_mutations()
update_skin()
update_underwear()
update_hair()
update_inv_w_uniform()
update_inv_wear_id()
update_inv_gloves()
update_inv_glasses()
update_inv_ears()
update_inv_shoes()
update_inv_s_store()
update_inv_wear_mask()
update_inv_head()
update_inv_belt()
update_inv_back()
update_inv_wear_suit()
update_inv_r_hand()
update_inv_l_hand()
update_inv_handcuffed()
update_inv_legcuffed()
//update_inv_pockets() //Doesn't do anything
update_fire()
update_water()
update_surgery()
/* --------------------------------------- */
//vvvvvv UPDATE_INV PROCS vvvvvv
/mob/living/carbon/human/update_inv_w_uniform()
if(QDESTROYING(src))
return
remove_layer(UNIFORM_LAYER)
//Shoes can be affected by uniform being drawn onto them
update_inv_shoes()
if(!w_uniform)
return
if(wear_suit && (wear_suit.flags_inv & HIDEJUMPSUIT) && !istype(wear_suit, /obj/item/clothing/suit/space/rig))
return //Wearing a suit that prevents uniform rendering
var/obj/item/clothing/under/under = w_uniform
var/uniform_sprite
if(istype(under) && !isnull(under.update_icon_define))
uniform_sprite = under.update_icon_define
else
uniform_sprite = INV_W_UNIFORM_DEF_ICON
//Build a uniform sprite
var/icon/c_mask = tail_style?.clip_mask
if(c_mask)
var/obj/item/clothing/suit/S = wear_suit
if((wear_suit?.flags_inv & HIDETAIL) || (istype(S) && S.taurized)) // Reasons to not mask: 1. If you're wearing a suit that hides the tail or if you're wearing a taurized suit.
c_mask = null
overlays_standing[UNIFORM_LAYER] = w_uniform.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_w_uniform_str, default_icon = uniform_sprite, default_layer = UNIFORM_LAYER, clip_mask = c_mask)
apply_layer(UNIFORM_LAYER)
/mob/living/carbon/human/update_inv_wear_id()
if(QDESTROYING(src))
return
remove_layer(ID_LAYER)
if(!wear_id)
return //Not wearing an ID
//Only draw the ID on the mob if the uniform allows for it
if(w_uniform && istype(w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/U = w_uniform
if(U.displays_id)
overlays_standing[ID_LAYER] = wear_id.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_wear_id_str, default_icon = INV_WEAR_ID_DEF_ICON, default_layer = ID_LAYER)
apply_layer(ID_LAYER)
/mob/living/carbon/human/update_inv_gloves()
if(QDESTROYING(src))
return
remove_layer(GLOVES_LAYER)
if(!gloves)
return //No gloves, no reason to be here.
overlays_standing[GLOVES_LAYER] = gloves.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_gloves_str, default_icon = INV_GLOVES_DEF_ICON, default_layer = GLOVES_LAYER)
apply_layer(GLOVES_LAYER)
/mob/living/carbon/human/update_inv_glasses()
if(QDESTROYING(src))
return
remove_layer(GLASSES_LAYER)
remove_layer(GLASSES_LAYER_ALT)
if(!glasses || hide_glasses) // CHOMPEdit - Add "|| hide_glasses" for glasses hiding
return //Not wearing glasses, no need to update anything.
var/glasses_layer = GLASSES_LAYER
if(istype(glasses, /obj/item/clothing/glasses))
var/obj/item/clothing/glasses/our_glasses = glasses
if(our_glasses.glasses_layer_above)
glasses_layer = GLASSES_LAYER_ALT
overlays_standing[glasses_layer] = glasses.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_gloves_str, default_icon = INV_EYES_DEF_ICON, default_layer = glasses_layer)
apply_layer(glasses_layer)
/mob/living/carbon/human/update_inv_ears()
if(QDESTROYING(src))
return
remove_layer(EARS_LAYER)
if((head && head.flags_inv & (BLOCKHAIR | BLOCKHEADHAIR)) || (wear_mask && wear_mask.flags_inv & (BLOCKHAIR | BLOCKHEADHAIR)))
return //Ears are blocked (by hair being blocked, overloaded)
if(!l_ear && !r_ear)
return //Why bother, if no ear sprites
if(hide_headset) //CHOMPEdit Start
if(l_ear && istype(l_ear, /obj/item/device/radio/headset)) //No need to generate blank images if only headsets are present.
if(!r_ear || istype(r_ear, /obj/item/device/radio/headset))
return
if(r_ear && istype(r_ear, /obj/item/device/radio/headset))
if(!l_ear || istype(l_ear, /obj/item/device/radio/headset))
return
// Blank image upon which to layer left & right overlays.
var/image/both = image(icon = 'icons/effects/effects.dmi', icon_state = "nothing", layer = BODY_LAYER+EARS_LAYER)
if(l_ear)
if(istype(l_ear, /obj/item/device/radio/headset))
if(!hide_headset)
var/image/standing = l_ear.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_l_ear_str, default_icon = INV_EARS_DEF_ICON, default_layer = EARS_LAYER)
both.add_overlay(standing)
else
var/image/standing = l_ear.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_l_ear_str, default_icon = INV_EARS_DEF_ICON, default_layer = EARS_LAYER)
both.add_overlay(standing)
if(r_ear)
if(istype(r_ear, /obj/item/device/radio/headset))
if(!hide_headset)
var/image/standing = r_ear.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_r_ear_str, default_icon = INV_EARS_DEF_ICON, default_layer = EARS_LAYER)
both.add_overlay(standing)
else
var/image/standing = r_ear.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_r_ear_str, default_icon = INV_EARS_DEF_ICON, default_layer = EARS_LAYER)
both.add_overlay(standing) //CHOMPEdit End
overlays_standing[EARS_LAYER] = both
apply_layer(EARS_LAYER)
/mob/living/carbon/human/update_inv_shoes()
if(QDESTROYING(src))
return
remove_layer(SHOES_LAYER)
remove_layer(SHOES_LAYER_ALT) //Dumb alternate layer for shoes being under the uniform.
if(!shoes || (wear_suit && wear_suit.flags_inv & HIDESHOES) || (w_uniform && w_uniform.flags_inv & HIDESHOES))
return //Either nothing to draw, or it'd be hidden.
for(var/f in list(BP_L_FOOT, BP_R_FOOT))
var/obj/item/organ/external/foot/foot = get_organ(f)
if(istype(foot) && foot.is_hidden_by_sprite_accessory(clothing_only = TRUE)) //If either foot is hidden by the tail, don't render footwear.
return
var/obj/item/clothing/shoes/shoe = shoes
var/shoe_sprite
if(istype(shoe) && !isnull(shoe.update_icon_define))
shoe_sprite = shoe.update_icon_define
else
shoe_sprite = INV_FEET_DEF_ICON
//Allow for shoe layer toggle nonsense
var/shoe_layer = SHOES_LAYER
if(istype(shoes, /obj/item/clothing/shoes))
var/obj/item/clothing/shoes/ushoes = shoes
if(ushoes.shoes_under_pants == 1)
shoe_layer = SHOES_LAYER_ALT
//NB: the use of a var for the layer on this one
overlays_standing[shoe_layer] = shoes.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_shoes_str, default_icon = shoe_sprite, default_layer = shoe_layer)
apply_layer(SHOES_LAYER)
apply_layer(SHOES_LAYER_ALT)
/mob/living/carbon/human/update_inv_s_store()
if(QDESTROYING(src))
return
remove_layer(SUIT_STORE_LAYER)
if(!s_store)
return //Why bother, nothing there.
//TODO, this is unlike the rest of the things
//Basically has no variety in slot icon choices at all. WHY SPECIES ONLY??
var/t_state = s_store.item_state
if(!t_state)
t_state = s_store.icon_state
overlays_standing[SUIT_STORE_LAYER] = image(icon = species.suit_storage_icon, icon_state = t_state, layer = BODY_LAYER+SUIT_STORE_LAYER)
apply_layer(SUIT_STORE_LAYER)
/mob/living/carbon/human/update_inv_head()
if(QDESTROYING(src))
return
remove_layer(HEAD_LAYER)
if(!head)
return //No head item, why bother.
overlays_standing[HEAD_LAYER] = head.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_head_str, default_icon = INV_HEAD_DEF_ICON, default_layer = HEAD_LAYER)
apply_layer(HEAD_LAYER)
/mob/living/carbon/human/update_inv_belt()
if(QDESTROYING(src))
return
remove_layer(BELT_LAYER)
remove_layer(BELT_LAYER_ALT) //Because you can toggle belt layer with a verb
if(!belt)
return //No belt, why bother.
//Toggle for belt layering with uniform
var/belt_layer = BELT_LAYER
if(istype(belt, /obj/item/weapon/storage/belt))
var/obj/item/weapon/storage/belt/ubelt = belt
if(ubelt.show_above_suit)
belt_layer = BELT_LAYER_ALT
var/icon/c_mask = tail_style?.clip_mask
//NB: this uses a var from above
overlays_standing[belt_layer] = belt.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_belt_str, default_icon = INV_BELT_DEF_ICON, default_layer = belt_layer, clip_mask = c_mask)
apply_layer(belt_layer)
/mob/living/carbon/human/update_inv_wear_suit()
if(QDESTROYING(src))
return
remove_layer(SUIT_LAYER)
//Hide/show other layers if necessary
update_inv_w_uniform()
update_inv_shoes()
update_tail_showing()
update_wing_showing()
if(!wear_suit)
return //No point, no suit.
var/obj/item/clothing/suit/suit = wear_suit
var/suit_sprite
if(istype(suit) && !isnull(suit.update_icon_define))
suit_sprite = suit.update_icon_define
else
suit_sprite = INV_SUIT_DEF_ICON
var/icon/c_mask = null
var/tail_is_rendered = (overlays_standing[TAIL_UPPER_LAYER] || overlays_standing[TAIL_UPPER_LAYER_ALT] || overlays_standing[TAIL_LOWER_LAYER])
var/valid_clip_mask = tail_style?.clip_mask
if(tail_is_rendered && valid_clip_mask && !(istype(suit) && suit.taurized)) //Clip the lower half of the suit off using the tail's clip mask for taurs since taur bodies aren't hidden.
c_mask = valid_clip_mask
overlays_standing[SUIT_LAYER] = wear_suit.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_wear_suit_str, default_icon = suit_sprite, default_layer = SUIT_LAYER, clip_mask = c_mask)
apply_layer(SUIT_LAYER)
/mob/living/carbon/human/update_inv_pockets()
stack_trace("Someone called update_inv_pockets even though it's dumb")
/mob/living/carbon/human/update_inv_wear_mask()
if(QDESTROYING(src))
return
remove_layer(FACEMASK_LAYER)
if(!wear_mask || (head && head.flags_inv & HIDEMASK))
return //Why bother, nothing in mask slot.
overlays_standing[FACEMASK_LAYER] = wear_mask.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_wear_mask_str, default_icon = INV_MASK_DEF_ICON, default_layer = FACEMASK_LAYER)
apply_layer(FACEMASK_LAYER)
/mob/living/carbon/human/update_inv_back()
if(QDESTROYING(src))
return
remove_layer(BACK_LAYER)
if(!back)
return //Why do anything
var/icon/c_mask = tail_style?.clip_mask
if(c_mask)
if(istype(back, /obj/item/weapon/storage/backpack/saddlebag) || istype(back, /obj/item/weapon/storage/backpack/saddlebag_common))
c_mask = null
overlays_standing[BACK_LAYER] = back.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_back_str, default_icon = INV_BACK_DEF_ICON, default_layer = BACK_LAYER, clip_mask = c_mask)
apply_layer(BACK_LAYER)
//TODO: Carbon procs in my human update_icons??
/mob/living/carbon/human/update_hud() //TODO: do away with this if possible
if(QDESTROYING(src))
return
if(client)
client.screen |= contents
if(hud_used)
hud_used.hidden_inventory_update() //Updates the screenloc of the items on the 'other' inventory bar
//update whether handcuffs appears on our hud.
/mob/living/carbon/proc/update_hud_handcuffed()
if(QDESTROYING(src))
return
if(hud_used && hud_used.l_hand_hud_object && hud_used.r_hand_hud_object)
hud_used.l_hand_hud_object.update_icon()
hud_used.r_hand_hud_object.update_icon()
/mob/living/carbon/human/update_inv_handcuffed()
if(QDESTROYING(src))
return
remove_layer(HANDCUFF_LAYER)
update_hud_handcuffed() //TODO
if(!handcuffed)
return //Not cuffed, why bother
overlays_standing[HANDCUFF_LAYER] = handcuffed.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_handcuffed_str, default_icon = INV_HCUFF_DEF_ICON, default_layer = HANDCUFF_LAYER)
apply_layer(HANDCUFF_LAYER)
/mob/living/carbon/human/update_inv_legcuffed()
if(QDESTROYING(src))
return
clear_alert("legcuffed")
remove_layer(LEGCUFF_LAYER)
if(!legcuffed)
return //Not legcuffed, why bother.
throw_alert("legcuffed", /obj/screen/alert/restrained/legcuffed, new_master = legcuffed)
overlays_standing[LEGCUFF_LAYER] = legcuffed.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_legcuffed_str, default_icon = INV_LCUFF_DEF_ICON, default_layer = LEGCUFF_LAYER)
apply_layer(LEGCUFF_LAYER)
/mob/living/carbon/human/update_inv_r_hand()
if(QDESTROYING(src))
return
remove_layer(R_HAND_LAYER)
if(!r_hand)
return //No hand, no bother.
overlays_standing[R_HAND_LAYER] = r_hand.make_worn_icon(body_type = species.get_bodytype(src), inhands = TRUE, slot_name = slot_r_hand_str, default_icon = INV_R_HAND_DEF_ICON, default_layer = R_HAND_LAYER)
apply_layer(R_HAND_LAYER)
/mob/living/carbon/human/update_inv_l_hand()
if(QDESTROYING(src))
return
remove_layer(L_HAND_LAYER)
if(!l_hand)
return //No hand, no bother.
overlays_standing[L_HAND_LAYER] = l_hand.make_worn_icon(body_type = species.get_bodytype(src), inhands = TRUE, slot_name = slot_l_hand_str, default_icon = INV_L_HAND_DEF_ICON, default_layer = L_HAND_LAYER)
apply_layer(L_HAND_LAYER)
/mob/living/carbon/human/proc/get_tail_layer()
var/list/lower_layer_dirs = list(SOUTH, EAST, WEST) //ChompEDIT - Tail below clothing on side views too.
if(tail_style)
lower_layer_dirs = tail_style.lower_layer_dirs.Copy()
if(dir in lower_layer_dirs)
return TAIL_LOWER_LAYER
else
return TAIL_UPPER_LAYER
/mob/living/carbon/human/proc/update_tail_showing()
if(QDESTROYING(src))
return
remove_layer(TAIL_UPPER_LAYER)
remove_layer(TAIL_UPPER_LAYER_ALT)
remove_layer(TAIL_LOWER_LAYER)
var/tail_layer = get_tail_layer()
if(src.tail_style && src.tail_style.clip_mask_state)
tail_layer = TAIL_UPPER_LAYER // Use default, let clip mask handle everything
if(tail_alt && tail_layer == TAIL_UPPER_LAYER)
tail_layer = TAIL_UPPER_LAYER_ALT
var/obj/item/organ/external/chest = organs_by_name[BP_TORSO]
var/image/tail_image = get_tail_image()
if(tail_image)
tail_image.layer = BODY_LAYER+tail_layer
tail_image.alpha = chest?.transparent ? 180 : 255 //VORESTATION EDIT: transparent instead of nonsolid
overlays_standing[tail_layer] = tail_image
apply_layer(tail_layer)
return
var/species_tail = species.get_tail(src) // Species tail icon_state prefix.
//This one is actually not that bad I guess.
if(species_tail && !(wear_suit && wear_suit.flags_inv & HIDETAIL))
var/icon/tail_s = get_tail_icon()
tail_image = image(icon = tail_s, icon_state = "[species_tail]_s", layer = BODY_LAYER+tail_layer)
tail_image.alpha = chest?.transparent ? 180 : 255 //VORESTATION EDIT: transparent instead of nonsolid
overlays_standing[tail_layer] = tail_image
animate_tail_reset()
//TODO: Is this the appropriate place for this, and not on species...?
/mob/living/carbon/human/proc/get_tail_icon()
var/icon_key = "[species.get_race_key(src)][r_skin][g_skin][b_skin][r_hair][g_hair][b_hair]"
var/icon/tail_icon = GLOB.tail_icon_cache[icon_key] //ChompEDIT Managed GLOB
if(!tail_icon)
//generate a new one
var/species_tail_anim = species.get_tail_animation(src)
if(!species_tail_anim && species.icobase_tail) species_tail_anim = species.icobase //Allow override of file for non-animated tails
if(!species_tail_anim) species_tail_anim = 'icons/effects/species.dmi'
tail_icon = new/icon(species_tail_anim)
tail_icon.Blend(rgb(r_skin, g_skin, b_skin), species.color_mult ? ICON_MULTIPLY : ICON_ADD)
// The following will not work with animated tails.
var/use_species_tail = species.get_tail_hair(src)
if(use_species_tail)
var/icon/hair_icon = icon('icons/effects/species.dmi', "[species.get_tail(src)]_[use_species_tail]")
hair_icon.Blend(rgb(r_hair, g_hair, b_hair), species.color_mult ? ICON_MULTIPLY : ICON_ADD) //Check for species color_mult
tail_icon.Blend(hair_icon, ICON_OVERLAY)
GLOB.tail_icon_cache[icon_key] = tail_icon //ChompEDIT Managed GLOB
return tail_icon
/mob/living/carbon/human/proc/set_tail_state(var/t_state)
var/tail_layer = get_tail_layer()
if(src.tail_style && src.tail_style.clip_mask_state)
tail_layer = TAIL_UPPER_LAYER // Use default, let clip mask handle everything
if(tail_alt && tail_layer == TAIL_UPPER_LAYER)
tail_layer = TAIL_UPPER_LAYER_ALT
var/image/tail_overlay = overlays_standing[tail_layer]
remove_layer(TAIL_UPPER_LAYER)
remove_layer(TAIL_UPPER_LAYER_ALT)
remove_layer(TAIL_LOWER_LAYER)
if(tail_overlay)
overlays_standing[tail_layer] = tail_overlay
if(species.get_tail_animation(src))
tail_overlay.icon_state = t_state
. = tail_overlay
apply_layer(tail_layer)
//Not really once, since BYOND can't do that.
//Update this if the ability to flick() images or make looping animation start at the first frame is ever added.
//You can sort of flick images now with flick_overlay -Aro
/mob/living/carbon/human/proc/animate_tail_once()
if(QDESTROYING(src))
return
var/t_state = "[species.get_tail(src)]_once"
var/tail_layer = get_tail_layer()
if(src.tail_style && src.tail_style.clip_mask_state)
tail_layer = TAIL_UPPER_LAYER // Use default, let clip mask handle everything
var/image/tail_overlay = overlays_standing[tail_layer]
if(tail_overlay && tail_overlay.icon_state == t_state)
return //let the existing animation finish
tail_overlay = set_tail_state(t_state) // Calls remove_layer & apply_layer
if(tail_overlay)
spawn(20)
//check that the animation hasn't changed in the meantime
if(overlays_standing[tail_layer] == tail_overlay && tail_overlay.icon_state == t_state)
animate_tail_stop()
/mob/living/carbon/human/proc/animate_tail_start()
if(QDESTROYING(src))
return
set_tail_state("[species.get_tail(src)]_slow[rand(0,9)]")
/mob/living/carbon/human/proc/animate_tail_fast()
if(QDESTROYING(src))
return
set_tail_state("[species.get_tail(src)]_loop[rand(0,9)]")
/mob/living/carbon/human/proc/animate_tail_reset()
if(QDESTROYING(src))
return
if(stat != DEAD)
set_tail_state("[species.get_tail(src)]_idle[rand(0,9)]")
else
set_tail_state("[species.get_tail(src)]_static")
toggle_tail(FALSE) //So tails stop when someone dies. TODO - Fix this hack ~Leshana
/mob/living/carbon/human/proc/animate_tail_stop()
if(QDESTROYING(src))
return
set_tail_state("[species.get_tail(src)]_static")
/mob/living/carbon/human/proc/update_wing_showing()
if(QDESTROYING(src))
return
remove_layer(WING_LAYER)
remove_layer(WING_LOWER_LAYER)
var/image/wing_image = get_wing_image(FALSE)
var/obj/item/organ/external/chest = organs_by_name[BP_TORSO]
if(wing_image)
wing_image.layer = BODY_LAYER+WING_LAYER
wing_image.alpha = chest?.transparent ? 180 : 255 //VORESTATION EDIT: transparent instead of nonsolid
overlays_standing[WING_LAYER] = wing_image
if(wing_style && wing_style.multi_dir)
wing_image = get_wing_image(TRUE)
if(wing_image)
wing_image.layer = BODY_LAYER+WING_LOWER_LAYER
overlays_standing[WING_LOWER_LAYER] = wing_image
apply_layer(WING_LAYER)
apply_layer(WING_LOWER_LAYER)
/mob/living/carbon/human/update_modifier_visuals()
if(QDESTROYING(src))
return
remove_layer(MODIFIER_EFFECTS_LAYER)
if(!LAZYLEN(modifiers))
return //No modifiers, no effects.
var/image/effects = new()
for(var/datum/modifier/M in modifiers)
if(M.mob_overlay_state)
if(M.icon_override) //VOREStation Edit. Override for the modifer icon.
var/image/I = image(icon = 'icons/mob/modifier_effects_vr.dmi', icon_state = M.mob_overlay_state)
I.color = M.effect_color
effects.overlays += I // Leaving this as overlays +=
else
var/image/I = image(icon = 'icons/mob/modifier_effects.dmi', icon_state = M.mob_overlay_state)
I.color = M.effect_color
effects.overlays += I // Leaving this as overlays +=
overlays_standing[MODIFIER_EFFECTS_LAYER] = effects
apply_layer(MODIFIER_EFFECTS_LAYER)
/mob/living/carbon/human/update_fire()
if(QDESTROYING(src))
return
remove_layer(FIRE_LAYER)
if(!on_fire)
return
overlays_standing[FIRE_LAYER] = image(icon = 'icons/mob/OnFire.dmi', icon_state = get_fire_icon_state(), layer = BODY_LAYER+FIRE_LAYER)
apply_layer(FIRE_LAYER)
/mob/living/carbon/human/update_water()
if(QDESTROYING(src))
return
remove_layer(MOB_WATER_LAYER)
var/depth = check_submerged()
if(!depth || lying)
return
var/atom/A = loc // We'd better be swimming and on a turf
var/image/I = image(icon = 'icons/mob/submerged.dmi', icon_state = "human_swimming_[depth]", layer = BODY_LAYER+MOB_WATER_LAYER) //TODO: Improve
I.color = A.color
overlays_standing[MOB_WATER_LAYER] = I
apply_layer(MOB_WATER_LAYER)
/mob/living/carbon/human/proc/update_surgery()
if(QDESTROYING(src))
return
remove_layer(SURGERY_LAYER)
var/image/total = new
for(var/obj/item/organ/external/E in organs)
if(E.open)
var/image/I = image(icon = 'icons/mob/surgery.dmi', icon_state = "[E.icon_name][round(E.open)]", layer = BODY_LAYER+SURGERY_LAYER)
total.overlays += I // Leaving this as overlays +=
if(total.overlays.len)
overlays_standing[SURGERY_LAYER] = total
apply_layer(SURGERY_LAYER)
/mob/living/carbon/human/proc/get_wing_image(var/under_layer)
if(QDESTROYING(src))
return
//If you are FBP with wing style and didn't set a custom one
if(synthetic && synthetic.includes_wing && !wing_style && !wings_hidden) //VOREStation Edit
var/icon/wing_s = new/icon("icon" = synthetic.icon, "icon_state" = "wing") //I dunno. If synths have some custom wing?
wing_s.Blend(rgb(src.r_skin, src.g_skin, src.b_skin), species.color_mult ? ICON_MULTIPLY : ICON_ADD)
var/image/working = image(wing_s)
working.overlays += em_block_image_generic(working) // Leaving this as overlays +=
return working
//If you have custom wings selected
if(wing_style && !(wear_suit && wear_suit.flags_inv & HIDETAIL) && !wings_hidden) //VOREStation Edit
var/wing_state = (flapping && wing_style.ani_state) ? wing_style.ani_state : wing_style.icon_state
if(wing_style.multi_dir)
wing_state += "_[under_layer ? "back" : "front"]"
var/icon/wing_s = new/icon("icon" = wing_style.icon, "icon_state" = wing_state)
if(wing_style.do_colouration)
wing_s.Blend(rgb(src.r_wing, src.g_wing, src.b_wing), wing_style.color_blend_mode)
if(wing_style.extra_overlay)
var/icon/overlay = new/icon("icon" = wing_style.icon, "icon_state" = wing_style.extra_overlay)
overlay.Blend(rgb(src.r_wing2, src.g_wing2, src.b_wing2), wing_style.color_blend_mode)
wing_s.Blend(overlay, ICON_OVERLAY)
qdel(overlay)
if(wing_style.extra_overlay2)
var/icon/overlay = new/icon("icon" = wing_style.icon, "icon_state" = wing_style.extra_overlay2)
if(wing_style.ani_state)
overlay = new/icon("icon" = wing_style.icon, "icon_state" = wing_style.extra_overlay2_w)
overlay.Blend(rgb(src.r_wing3, src.g_wing3, src.b_wing3), wing_style.color_blend_mode)
wing_s.Blend(overlay, ICON_OVERLAY)
qdel(overlay)
else
overlay.Blend(rgb(src.r_wing3, src.g_wing3, src.b_wing3), wing_style.color_blend_mode)
wing_s.Blend(overlay, ICON_OVERLAY)
qdel(overlay)
var/image/working = image(wing_s)
if(wing_style.em_block)
working.overlays += em_block_image_generic(working) // Leaving this as overlays +=
working.pixel_x -= wing_style.wing_offset
return working
/mob/living/carbon/human/proc/get_ears_overlay()
//If you are FBP with ear style and didn't set a custom one
var/datum/robolimb/model = isSynthetic()
if(istype(model) && model.includes_ears && !ear_style)
var/icon/ears_s = new/icon("icon" = synthetic.icon, "icon_state" = "ears")
ears_s.Blend(rgb(src.r_ears, src.g_ears, src.b_ears), species.color_mult ? ICON_MULTIPLY : ICON_ADD)
return ears_s
if(ear_style && !(head && (head.flags_inv & BLOCKHEADHAIR)))
var/icon/ears_s = new/icon("icon" = ear_style.icon, "icon_state" = ear_style.icon_state)
if(ear_style.do_colouration)
ears_s.Blend(rgb(src.r_ears, src.g_ears, src.b_ears), ear_style.color_blend_mode)
if(ear_style.extra_overlay)
var/icon/overlay = new/icon("icon" = ear_style.icon, "icon_state" = ear_style.extra_overlay)
overlay.Blend(rgb(src.r_ears2, src.g_ears2, src.b_ears2), ear_style.color_blend_mode)
ears_s.Blend(overlay, ICON_OVERLAY)
qdel(overlay)
if(ear_style.extra_overlay2) //MORE COLOURS IS BETTERER
var/icon/overlay = new/icon("icon" = ear_style.icon, "icon_state" = ear_style.extra_overlay2)
overlay.Blend(rgb(src.r_ears3, src.g_ears3, src.b_ears3), ear_style.color_blend_mode)
ears_s.Blend(overlay, ICON_OVERLAY)
qdel(overlay)
return ears_s
return null
/mob/living/carbon/human/proc/get_tail_image()
//If you are FBP with tail style and didn't set a custom one
var/datum/robolimb/model = isSynthetic()
if(istype(model) && model.includes_tail && !tail_style && !tail_hidden)
var/icon/tail_s = new/icon("icon" = synthetic.icon, "icon_state" = "tail")
tail_s.Blend(rgb(src.r_skin, src.g_skin, src.b_skin), species.color_mult ? ICON_MULTIPLY : ICON_ADD)
return image(tail_s)
//If you have a custom tail selected
if(tail_style && !(wear_suit && wear_suit.flags_inv & HIDETAIL && !istaurtail(tail_style)) && !tail_hidden)
var/icon/tail_s = new/icon("icon" = (tail_style.can_loaf && resting) ? tail_style.icon_loaf : tail_style.icon, "icon_state" = (wagging && tail_style.ani_state ? tail_style.ani_state : tail_style.icon_state)) //CHOMPEdit
if(tail_style.can_loaf && !is_shifted)
pixel_y = (resting) ? -tail_style.loaf_offset*size_multiplier : default_pixel_y //move player down, then taur up, to fit the overlays correctly // VOREStation Edit: Taur Loafing
if(tail_style.do_colouration)
tail_s.Blend(rgb(src.r_tail, src.g_tail, src.b_tail), tail_style.color_blend_mode)
if(tail_style.extra_overlay)
var/icon/overlay = new/icon("icon" = (tail_style?.can_loaf && resting) ? tail_style.icon_loaf : tail_style.icon, "icon_state" = tail_style.extra_overlay) //CHOMPEdit
if(wagging && tail_style.ani_state)
overlay = new/icon("icon" = tail_style.icon, "icon_state" = tail_style.extra_overlay_w)
overlay.Blend(rgb(src.r_tail2, src.g_tail2, src.b_tail2), tail_style.color_blend_mode)
tail_s.Blend(overlay, ICON_OVERLAY)
qdel(overlay)
else
overlay.Blend(rgb(src.r_tail2, src.g_tail2, src.b_tail2), tail_style.color_blend_mode)
tail_s.Blend(overlay, ICON_OVERLAY)
qdel(overlay)
if(tail_style.extra_overlay2)
var/icon/overlay = new/icon("icon" = (tail_style?.can_loaf && resting) ? tail_style.icon_loaf : tail_style.icon, "icon_state" = tail_style.extra_overlay2) //CHOMPEdit
if(wagging && tail_style.ani_state)
overlay = new/icon("icon" = tail_style.icon, "icon_state" = tail_style.extra_overlay2_w)
overlay.Blend(rgb(src.r_tail3, src.g_tail3, src.b_tail3), tail_style.color_blend_mode)
tail_s.Blend(overlay, ICON_OVERLAY)
qdel(overlay)
else
overlay.Blend(rgb(src.r_tail3, src.g_tail3, src.b_tail3), tail_style.color_blend_mode)
tail_s.Blend(overlay, ICON_OVERLAY)
qdel(overlay)
var/image/working = image(tail_s)
if(tail_style.em_block)
working.overlays += em_block_image_generic(working) // Leaving this as overlays +=
if(istaurtail(tail_style))
var/datum/sprite_accessory/tail/taur/taurtype = tail_style
working.pixel_x = tail_style.offset_x
working.pixel_y = tail_style.offset_y
if(taurtype.can_ride && !riding_datum)
riding_datum = new /datum/riding/taur(src)
add_verb(src,/mob/living/carbon/human/proc/taur_mount) //CHOMPEdit TGPanel
add_verb(src,/mob/living/proc/toggle_rider_reins) //CHOMPEdit TGPanel
else if(islongtail(tail_style))
working.pixel_x = tail_style.offset_x
working.pixel_y = tail_style.offset_y
return working
return null
// TODO - Move this to where it should go ~Leshana
/mob/living/proc/stop_flying()
if(QDESTROYING(src))
return
flying = FALSE
return 1
/mob/living/carbon/human/stop_flying()
if((. = ..()))
update_wing_showing()
//Human Overlays Indexes/////////
/* CHOMPEdit - why are these undefined??
# undef MUTATIONS_LAYER
# undef SKIN_LAYER
# undef BLOOD_LAYER
# undef MOB_DAM_LAYER
# undef SURGERY_LAYER
# undef UNDERWEAR_LAYER
# undef SHOES_LAYER_ALT
# undef UNIFORM_LAYER
# undef ID_LAYER
# undef SHOES_LAYER
# undef GLOVES_LAYER
# undef BELT_LAYER
# undef SUIT_LAYER
# undef TAIL_UPPER_LAYER
# undef TAIL_LOWER_LAYER
# undef WING_LOWER_LAYER
# undef GLASSES_LAYER
# undef BELT_LAYER_ALT
# undef SUIT_STORE_LAYER
# undef BACK_LAYER
# undef HAIR_LAYER
# undef HAIR_ACCESSORY_LAYER
# undef EARS_LAYER
# undef EYES_LAYER
# undef FACEMASK_LAYER
# undef GLASSES_LAYER_ALT
# undef HEAD_LAYER
# undef HANDCUFF_LAYER
# undef LEGCUFF_LAYER
# undef L_HAND_LAYER
# undef R_HAND_LAYER
# undef VORE_BELLY_LAYER
# undef WING_LAYER
# undef TAIL_UPPER_LAYER_ALT
# undef MODIFIER_EFFECTS_LAYER
# undef FIRE_LAYER
# undef WATER_LAYER
# undef TARGETED_LAYER
# undef TOTAL_LAYERS
*/